[fix] [minor] merged with master
diff --git a/accounts/doctype/sales_invoice/pos.js b/accounts/doctype/sales_invoice/pos.js
index 5045530..1bd6de1 100644
--- a/accounts/doctype/sales_invoice/pos.js
+++ b/accounts/doctype/sales_invoice/pos.js
@@ -5,10 +5,73 @@
init: function(wrapper, frm) {
this.wrapper = wrapper;
this.frm = frm;
- this.wrapper.html('<div class="customer-area"></div>\
- <div class="item-area"></div>\
- <div><button class="btn btn-default btn-add">Add</button>');
-
+ this.wrapper.html('<div class="container">\
+ <div class="row">\
+ <div class="customer-area col-sm-3 col-xs-6"></div>\
+ <div class="barcode-area col-sm-3 col-xs-6"></div>\
+ <div class="search-area col-sm-3 col-xs-6"></div>\
+ <div class="item-group-area col-sm-3 col-xs-6"></div>\
+ </div>\
+ <div class="row">\
+ <div class="col-sm-6">\
+ <div class="pos-bill">\
+ <div class="item-cart">\
+ <table class="table table-condensed table-hover" id="cart" style="table-layout: fixed;">\
+ <thead>\
+ <tr>\
+ <th style="width: 50%">Item</th>\
+ <th style="width: 25%; text-align: right;">Qty</th>\
+ <th style="width: 25%; text-align: right;">Rate</th>\
+ </tr>\
+ </thead>\
+ <tbody>\
+ </tbody>\
+ </table>\
+ </div>\
+ <br>\
+ <div class="net-total-area" style="margin-left: 40%;">\
+ <table class="table table-condensed">\
+ <tr>\
+ <td><b>Net Total</b></td>\
+ <td style="text-align: right;" class="net-total"></td>\
+ </tr>\
+ </table>\
+ <div class="tax-table" style="display: none;">\
+ <table class="table table-condensed">\
+ <thead>\
+ <tr>\
+ <th style="width: 60%">Taxes</th>\
+ <th style="width: 40%; text-align: right;"></th>\
+ </tr>\
+ </thead>\
+ <tbody>\
+ </tbody>\
+ </table>\
+ </div>\
+ <table class="table table-condensed">\
+ <tr>\
+ <td style="vertical-align: middle;"><b>Grand Total</b></td>\
+ <td style="text-align: right; font-size: 200%; \
+ font-size: bold;" class="grand-total"></td>\
+ </tr>\
+ </table>\
+ </div>\
+ </div>\
+ <br><br>\
+ <button class="btn btn-success btn-lg make-payment">\
+ <i class="icon-money"></i> Make Payment</button>\
+ <button class="btn btn-default btn-lg delete-items pull-right" style="display: none;">\
+ <i class="icon-trash"></i> Del</button>\
+ <br><br>\
+ </div>\
+ <div class="col-sm-6">\
+ <div class="item-list-area">\
+ <div class="col-sm-12">\
+ <div class="row item-list"></div></div>\
+ </div>\
+ </div>\
+ </div></div>');
+
this.make();
var me = this;
@@ -16,10 +79,20 @@
me.refresh();
});
+ this.wrapper.find(".delete-items").on("click", function() {
+ me.remove_selected_item();
+ });
+
+ this.wrapper.find(".make-payment").on("click", function() {
+ me.make_payment();
+ });
},
make: function() {
this.make_customer();
- this.make_items();
+ this.make_item_group();
+ this.make_search();
+ this.make_barcode();
+ this.make_item_list();
},
make_customer: function() {
var me = this;
@@ -28,7 +101,8 @@
"fieldtype": "Link",
"options": "Customer",
"label": "Customer",
- "fieldname": "pos_customer"
+ "fieldname": "pos_customer",
+ "placeholder": "Customer"
},
parent: this.wrapper.find(".customer-area")
});
@@ -36,25 +110,302 @@
this.customer.$input.on("change", function() {
if(!me.customer.autocomplete_open)
wn.model.set_value("Sales Invoice", me.frm.docname, "customer", this.value);
- });
- },
- make_items: function() {
- var me = this;
- this.wrapper.find(".btn-add").click(function() {
- var child = wn.model.add_child(me.frm.doc, "Sales Invoice Item", "entries");
- child.item_code = "Test Item";
- me.frm.cscript.item_code(me.frm.doc, child.doctype, child.name);
});
},
+ make_item_group: function() {
+ var me = this;
+ this.item_group = wn.ui.form.make_control({
+ df: {
+ "fieldtype": "Link",
+ "options": "Item Group",
+ "label": "Item Group",
+ "fieldname": "pos_item_group",
+ "placeholder": "Filter by Item Group"
+ },
+ parent: this.wrapper.find(".item-group-area")
+ });
+ this.item_group.make_input();
+ this.item_group.$input.on("change", function() {
+ if(!me.item_group.autocomplete_open)
+ me.make_item_list();
+ });
+ },
+ make_search: function() {
+ var me = this;
+ this.search = wn.ui.form.make_control({
+ df: {
+ "fieldtype": "Link",
+ "options": "Item",
+ "label": "Item",
+ "fieldname": "pos_item",
+ "placeholder": "Select Item"
+ },
+ parent: this.wrapper.find(".search-area")
+ });
+ this.search.make_input();
+ this.search.$input.on("change", function() {
+ if(!me.search.autocomplete_open)
+ me.make_item_list();
+ });
+ },
+ make_barcode: function() {
+ var me = this;
+ this.barcode = wn.ui.form.make_control({
+ df: {
+ "fieldtype": "Data",
+ "label": "Barcode",
+ "fieldname": "pos_barcode",
+ "placeholder": "Select Barcode"
+ },
+ parent: this.wrapper.find(".barcode-area")
+ });
+ this.barcode.make_input();
+ this.barcode.$input.on("change", function() {
+ me.add_item_thru_barcode();
+ });
+ },
+ make_item_list: function() {
+ var me = this;
+ wn.call({
+ method: 'accounts.doctype.sales_invoice.pos.get_items',
+ args: {
+ price_list: cur_frm.doc.selling_price_list,
+ item_group: this.item_group.$input.val(),
+ item: this.search.$input.val()
+ },
+ callback: function(r) {
+ var $wrap = me.wrapper.find(".item-list");
+ me.wrapper.find(".item-list").empty();
+ $.each(r.message, function(index, obj) {
+ if (obj.image)
+ image = "<img src='" + obj.image + "' class='img-responsive'>";
+ else
+ image = '<div class="missing-image"><i class="icon-camera"></i></div>';
+
+ $(repl('<div class="col-xs-3 pos-item" data-item_code="%(item_code)s">\
+ %(item_image)s\
+ <div class="small">%(item_code)s</div>\
+ <div class="small">%(item_name)s</div>\
+ <div class="small">%(item_price)s</div>\
+ </div>',
+ {
+ item_code: obj.name,
+ item_price: format_currency(obj.ref_rate, obj.ref_currency),
+ item_name: obj.name===obj.item_name ? "" : obj.item_name,
+ item_image: image
+ })).appendTo($wrap);
+ });
+
+ $("div.pos-item").on("click", function() {
+ if(!cur_frm.doc.customer) {
+ msgprint("Please select customer first.");
+ return;
+ }
+ me.add_to_cart($(this).attr("data-item_code"));
+ });
+ }
+ });
+ },
+ add_to_cart: function(item_code) {
+ var me = this;
+ var caught = false;
+
+ // get no_of_items
+ no_of_items = me.wrapper.find("#cart tbody").length;
+
+ // check whether the item is already added
+ if (no_of_items != 0) {
+ $.each(wn.model.get_children("Sales Invoice Item", this.frm.doc.name, "entries",
+ "Sales Invoice"), function(i, d) {
+ if (d.item_code == item_code)
+ caught = true;
+ });
+ }
+
+ // if duplicate row then append the qty
+ if (caught) {
+ me.update_qty(item_code, 1);
+ }
+ else {
+ var child = wn.model.add_child(me.frm.doc, "Sales Invoice Item", "entries");
+ child.item_code = item_code;
+ me.frm.cscript.item_code(me.frm.doc, child.doctype, child.name);
+ //me.refresh();
+ }
+ },
+ update_qty: function(item_code, qty) {
+ var me = this;
+ $.each(wn.model.get_children("Sales Invoice Item", this.frm.doc.name, "entries",
+ "Sales Invoice"), function(i, d) {
+ if (d.item_code == item_code) {
+ if (qty == 1)
+ d.qty += 1;
+ else
+ d.qty = qty;
+
+ me.frm.cscript.qty(me.frm.doc, d.doctype, d.name);
+ }
+ });
+ me.refresh();
+ },
refresh: function() {
var me = this;
this.customer.set_input(this.frm.doc.customer);
-
+ this.barcode.set_input("");
+
// add items
- var $items = me.wrapper.find(".item-area").empty();
+ var $items = me.wrapper.find("#cart tbody").empty();
+
$.each(wn.model.get_children("Sales Invoice Item", this.frm.doc.name, "entries",
"Sales Invoice"), function(i, d) {
- $(repl("<div>%(item_code)s</div>", d)).appendTo($items);
+ $(repl('<tr id="%(item_code)s" data-selected="false">\
+ <td>%(item_code)s%(item_name)s</td>\
+ <td><input type="text" value="%(qty)s" \
+ class="form-control qty" style="text-align: right;"></td>\
+ <td style="text-align: right;">%(rate)s<br><b>%(amount)s</b></td>\
+ </tr>',
+ {
+ item_code: d.item_code,
+ item_name: d.item_name===d.item_code ? "" : ("<br>" + d.item_name),
+ qty: d.qty,
+ rate: format_currency(d.ref_rate, cur_frm.doc.price_list_currency),
+ amount: format_currency(d.export_amount, cur_frm.doc.price_list_currency)
+ }
+ )).appendTo($items);
+ });
+
+ // taxes
+ var taxes = wn.model.get_children("Sales Taxes and Charges", this.frm.doc.name, "other_charges",
+ "Sales Invoice");
+ $(".tax-table")
+ .toggle((taxes && taxes.length) ? true : false)
+ .find("tbody").empty();
+
+ $.each(taxes, function(i, d) {
+ $(repl('<tr>\
+ <td>%(description)s</td>\
+ <td style="text-align: right;">%(tax_amount)s</td>\
+ <tr>', {
+ description: d.description,
+ tax_amount: format_currency(d.tax_amount, me.frm.doc.price_list_currency)
+ })).appendTo(".tax-table tbody");
+ });
+
+ // set totals
+ this.wrapper.find(".net-total").text(format_currency(this.frm.doc.net_total_export,
+ cur_frm.doc.price_list_currency));
+ this.wrapper.find(".grand-total").text(format_currency(this.frm.doc.grand_total_export,
+ cur_frm.doc.price_list_currency));
+
+ // append quantity to the respective item after change from input box
+ $("input.qty").on("change", function() {
+ var item_code = $(this).closest("tr")[0].id;
+ me.update_qty(item_code, $(this).val());
+ });
+
+ // on td click highlight the respective row
+ $("td").on("click", function() {
+ var row = $(this).closest("tr");
+ if (row.attr("data-selected") == "false") {
+ row.attr("class", "warning");
+ row.attr("data-selected", "true");
+ }
+ else {
+ row.prop("class", null);
+ row.attr("data-selected", "false");
+ }
+ me.refresh_delete_btn();
+
+ });
+
+ me.refresh_delete_btn();
+ },
+ refresh_delete_btn: function() {
+ $(".delete-items").toggle($(".item-cart .warning").length ? true : false);
+ },
+ add_item_thru_barcode: function() {
+ var me = this;
+ wn.call({
+ method: 'accounts.doctype.sales_invoice.pos.get_item_from_barcode',
+ args: {barcode: this.barcode.$input.val()},
+ callback: function(r) {
+ if (r.message) {
+ me.add_to_cart(r.message[0].name);
+ me.refresh();
+ }
+ else
+ msgprint(wn._("Invalid Barcode"));
+ }
+ });
+ },
+ remove_selected_item: function() {
+ var me = this;
+ var selected_items = [];
+ var no_of_items = $("#cart tbody tr").length;
+ for(var x=0; x<=no_of_items - 1; x++) {
+ var row = $("#cart tbody tr:eq(" + x + ")");
+ if(row.attr("data-selected") == "true") {
+ selected_items.push(row.attr("id"));
+ }
+ }
+
+ if (!selected_items[0])
+ msgprint(wn._("Please select any item to remove it"));
+
+ var child = wn.model.get_children("Sales Invoice Item", this.frm.doc.name, "entries",
+ "Sales Invoice");
+ $.each(child, function(i, d) {
+ for (var i in selected_items) {
+ if (d.item_code == selected_items[i]) {
+ wn.model.clear_doc(d.doctype, d.name);
+ }
+ }
+ });
+ cur_frm.fields_dict["entries"].grid.refresh();
+ me.refresh();
+ },
+ make_payment: function() {
+ var me = this;
+ var no_of_items = $("#cart tbody tr").length;
+ var mode_of_payment = [];
+
+ if (no_of_items == 0)
+ msgprint(wn._("Payment cannot be made for empty cart"));
+ else {
+ wn.call({
+ method: 'accounts.doctype.sales_invoice.pos.get_mode_of_payment',
+ callback: function(r) {
+ for (x=0; x<=r.message.length - 1; x++) {
+ mode_of_payment.push(r.message[x].name);
+ }
+
+ // show payment wizard
+ var dialog = new wn.ui.Dialog({
+ width: 400,
+ title: 'Payment',
+ fields: [
+ {fieldtype:'Data', fieldname:'total_amount', label:'Total Amount', read_only:1},
+ {fieldtype:'Select', fieldname:'mode_of_payment', label:'Mode of Payment',
+ options:mode_of_payment.join('\n'), reqd: 1},
+ {fieldtype:'Button', fieldname:'pay', label:'Pay'}
+ ]
+ });
+ dialog.set_values({
+ "total_amount": $(".grand-total").text()
+ });
+ dialog.show();
+
+ dialog.get_input("total_amount").attr("disabled", "disabled");
+
+ dialog.fields_dict.pay.input.onclick = function() {
+ cur_frm.set_value("mode_of_payment", dialog.get_values().mode_of_payment);
+ cur_frm.set_value("paid_amount", dialog.get_values().total_amount);
+ cur_frm.save();
+ dialog.hide();
+ me.refresh();
+ };
+ }
});
- }
-})
\ No newline at end of file
+ }
+ },
+});
\ No newline at end of file
diff --git a/accounts/doctype/sales_invoice/pos.py b/accounts/doctype/sales_invoice/pos.py
new file mode 100644
index 0000000..2f2ad6a
--- /dev/null
+++ b/accounts/doctype/sales_invoice/pos.py
@@ -0,0 +1,32 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import webnotes
+
+@webnotes.whitelist()
+def get_items(price_list, item=None, item_group=None):
+ condition = ""
+
+ if item_group and item_group != "All Item Groups":
+ condition = "and i.item_group='%s'" % item_group
+
+ if item:
+ condition = "and i.name='%s'" % item
+
+ return webnotes.conn.sql("""select
+ i.name, i.item_name, i.image, ip.ref_rate, ip.ref_currency
+ from `tabItem` i LEFT JOIN `tabItem Price` ip
+ ON ip.parent=i.name
+ and ip.price_list=%s
+ where
+ i.is_sales_item='Yes'%s""" % ('%s', condition), (price_list), as_dict=1)
+
+@webnotes.whitelist()
+def get_item_from_barcode(barcode):
+ return webnotes.conn.sql("""select name from `tabItem` where barcode=%s""",
+ (barcode), as_dict=1)
+
+@webnotes.whitelist()
+def get_mode_of_payment():
+ return webnotes.conn.sql("""select name from `tabMode of Payment`""", as_dict=1)
\ No newline at end of file
diff --git a/accounts/doctype/sales_invoice/sales_invoice.css b/accounts/doctype/sales_invoice/sales_invoice.css
new file mode 100644
index 0000000..e4b61b6
--- /dev/null
+++ b/accounts/doctype/sales_invoice/sales_invoice.css
@@ -0,0 +1,15 @@
+.pos-item {
+ height: 200px;
+ overflow: hidden;
+ cursor: pointer;
+ padding-left: 5px !important;
+ padding-right: 5px !important;
+}
+
+.pos-bill {
+ padding: 20px 5px;
+ font-family: Monospace;
+ border: 1px solid #eee;
+ -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
+ box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
+}
\ No newline at end of file
diff --git a/accounts/doctype/sales_invoice/sales_invoice.js b/accounts/doctype/sales_invoice/sales_invoice.js
index 4001bea..7e7f7d4 100644
--- a/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/accounts/doctype/sales_invoice/sales_invoice.js
@@ -12,7 +12,7 @@
wn.require('app/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.js');
wn.require('app/utilities/doctype/sms_control/sms_control.js');
wn.require('app/selling/doctype/sales_common/sales_common.js');
-// wn.require('app/accounts/doctype/sales_invoice/pos.js');
+wn.require('app/accounts/doctype/sales_invoice/pos.js');
wn.provide("erpnext.accounts");
erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.extend({
@@ -25,9 +25,8 @@
this.frm.set_df_property("debit_to", "print_hide", 0);
}
}
- // if(this.frm.doc.is_pos && this.frm.doc.docstatus===0) {
- // cur_frm.cscript.toggle_pos(true);
- // }
+
+ cur_frm.cscript.toggle_pos(true);
},
refresh: function(doc, dt, dn) {
@@ -58,7 +57,7 @@
cur_frm.add_custom_button('Make Payment Entry', cur_frm.cscript.make_bank_voucher);
}
- if (this.frm.doc.docstatus===0) {
+ if (doc.docstatus===0) {
cur_frm.add_custom_button(wn._('From Sales Order'),
function() {
wn.model.map_current_doc({
@@ -92,32 +91,62 @@
}
});
});
+
+ if(cint(sys_defaults.fs_pos_view)===1)
+ cur_frm.cscript.pos_btn();
- // cur_frm.add_custom_button(wn._("POS View"), function() {
- // cur_frm.cscript.toggle_pos();
- // }, 'icon-desktop');
-
+ // setTimeout(function() { cur_frm.$pos_btn.click(); }, 1000);
+
+ } else {
+ // hide shown pos for submitted records
+ if(cur_frm.pos_active) cur_frm.cscript.toggle_pos(false);
}
},
+ pos_btn: function() {
+ if(cur_frm.$pos_btn)
+ cur_frm.$pos_btn.remove();
+
+ if(!cur_frm.pos_active) {
+ var btn_label = wn._("POS View"),
+ icon = "icon-desktop";
+ } else {
+ var btn_label = wn._("Invoice View"),
+ icon = "icon-file-text";
+ }
+
+ cur_frm.$pos_btn = cur_frm.add_custom_button(btn_label, function() {
+ cur_frm.cscript.toggle_pos();
+ cur_frm.cscript.pos_btn();
+ }, icon);
+
+ },
+
toggle_pos: function(show) {
- if((show===true && cur_frm.pos_active) || (show===false && !cur_frm.pos_active)) return;
+ if(cint(sys_defaults.fs_pos_view)===0) return;
+ if(!(this.frm.doc.is_pos && this.frm.doc.docstatus===0)) return;
- // make pos
- if(!cur_frm.pos) {
- cur_frm.layout.add_view("pos");
- cur_frm.pos = new erpnext.POS(cur_frm.layout.views.pos, cur_frm);
+ if (!this.frm.doc.selling_price_list)
+ msgprint(wn._("Please select Price List"))
+ else {
+ if((show===true && cur_frm.pos_active) || (show===false && !cur_frm.pos_active)) return;
+
+ // make pos
+ if(!cur_frm.pos) {
+ cur_frm.layout.add_view("pos");
+ cur_frm.pos = new erpnext.POS(cur_frm.layout.views.pos, cur_frm);
+ }
+
+ // toggle view
+ cur_frm.layout.set_view(cur_frm.pos_active ? "" : "pos");
+ cur_frm.pos_active = !cur_frm.pos_active;
+
+ // refresh
+ if(cur_frm.pos_active)
+ cur_frm.pos.refresh();
}
-
- // toggle view
- cur_frm.layout.set_view(cur_frm.pos_active ? "" : "pos");
- cur_frm.pos_active = !cur_frm.pos_active;
-
- // refresh
- if(cur_frm.pos_active)
- cur_frm.pos.refresh();
-
},
+
tc_name: function() {
this.get_terms();
},
diff --git a/config.json b/config.json
index c9d1aa7..5412b01 100644
--- a/config.json
+++ b/config.json
@@ -1,4 +1,5 @@
{
+ "app_name": "ERPNext",
"modules": {
"Selling": {
"link": "selling-home",
diff --git a/patches/may_2013/p06_make_notes.py b/patches/may_2013/p06_make_notes.py
index b60642c..29bfe25 100644
--- a/patches/may_2013/p06_make_notes.py
+++ b/patches/may_2013/p06_make_notes.py
@@ -13,17 +13,27 @@
name = question.question[:180]
if webnotes.conn.exists("Note", name):
webnotes.delete_doc("Note", name)
- note = webnotes.bean({
+
+ similar_questions = webnotes.conn.sql_list("""select name from `tabQuestion`
+ where question like %s""", "%s%%" % name)
+ answers = [markdown2.markdown(c) for c in webnotes.conn.sql_list("""
+ select answer from tabAnswer where question in (%s)""" % \
+ ", ".join(["%s"]*len(similar_questions)), similar_questions)]
+
+ webnotes.bean({
"doctype":"Note",
"title": name,
- "content": "<hr>".join([markdown2.markdown(c) for c in webnotes.conn.sql_list("""
- select answer from tabAnswer where question=%s""", question.name)]),
+ "content": "<hr>".join(answers),
"owner": question.owner,
"creation": question.creation,
"public": 1
}).insert()
+
except NameError:
pass
+ except Exception, e:
+ if e.args[0] != 1062:
+ raise e
webnotes.delete_doc("DocType", "Question")
webnotes.delete_doc("DocType", "Answer")
diff --git a/public/js/transaction.js b/public/js/transaction.js
index 118594c..1d06a9f 100644
--- a/public/js/transaction.js
+++ b/public/js/transaction.js
@@ -6,9 +6,9 @@
erpnext.TransactionController = erpnext.stock.StockController.extend({
onload: function() {
+ var me = this;
if(this.frm.doc.__islocal) {
- var me = this,
- today = get_today(),
+ var today = get_today(),
currency = wn.defaults.get_default("currency");
$.each({
@@ -30,6 +30,14 @@
me.frm.script_manager.trigger("company");
}
+
+ if(this.other_fname) {
+ this[this.other_fname + "_remove"] = this.calculate_taxes_and_totals;
+ }
+
+ if(this.fname) {
+ this[this.fname + "_remove"] = this.calculate_taxes_and_totals;
+ }
},
onload_post_render: function() {
@@ -311,9 +319,14 @@
function(item_code, tax_data) {
if(!item_tax[item_code]) item_tax[item_code] = {};
if($.isArray(tax_data)) {
- var tax_rate = tax_data[0] == null ? "" : (flt(tax_data[0], tax_rate_precision) + "%"),
- tax_amount = format_currency(flt(tax_data[1], tax_amount_precision), company_currency,
- tax_amount_precision);
+ var tax_rate = "";
+ if(tax_data[0] != null) {
+ tax_rate = (tax.charge_type === "Actual") ?
+ format_currency(flt(tax_data[0], tax_amount_precision), company_currency, tax_amount_precision) :
+ (flt(tax_data[0], tax_rate_precision) + "%");
+ }
+ var tax_amount = format_currency(flt(tax_data[1], tax_amount_precision), company_currency,
+ tax_amount_precision);
item_tax[item_code][tax.name] = [tax_rate, tax_amount];
} else {
diff --git a/selling/doctype/sales_bom/sales_bom.py b/selling/doctype/sales_bom/sales_bom.py
index 8bcac17..15d8fd1 100644
--- a/selling/doctype/sales_bom/sales_bom.py
+++ b/selling/doctype/sales_bom/sales_bom.py
@@ -76,8 +76,8 @@
def get_new_item_code(doctype, txt, searchfield, start, page_len, filters):
from controllers.queries import get_match_cond
-
- return webnotes.conn.sql("""select name, description from tabItem
+
+ return webnotes.conn.sql("""select name, item_name, description from tabItem
where is_stock_item="No" and is_sales_item="Yes"
and name not in (select name from `tabSales BOM`) and %s like %s
%s limit %s, %s""" % (searchfield, "%s",
diff --git a/selling/doctype/sales_order_item/sales_order_item.txt b/selling/doctype/sales_order_item/sales_order_item.txt
index 9cf2a03..47b4d6b 100644
--- a/selling/doctype/sales_order_item/sales_order_item.txt
+++ b/selling/doctype/sales_order_item/sales_order_item.txt
@@ -2,7 +2,7 @@
{
"creation": "2013-03-07 11:42:58",
"docstatus": 0,
- "modified": "2013-08-22 15:21:56",
+ "modified": "2013-08-22 15:43:07",
"modified_by": "Administrator",
"owner": "Administrator"
},
diff --git a/setup/doctype/features_setup/features_setup.txt b/setup/doctype/features_setup/features_setup.txt
index e1a4c08..89c9dd3 100644
--- a/setup/doctype/features_setup/features_setup.txt
+++ b/setup/doctype/features_setup/features_setup.txt
@@ -2,7 +2,7 @@
{
"creation": "2012-12-20 12:50:49",
"docstatus": 0,
- "modified": "2013-07-05 14:37:59",
+ "modified": "2013-08-22 15:36:43",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -185,6 +185,13 @@
"label": "Point of Sale"
},
{
+ "description": "To enable <b>Point of Sale</b> view",
+ "doctype": "DocField",
+ "fieldname": "fs_pos_view",
+ "fieldtype": "Check",
+ "label": "POS View"
+ },
+ {
"doctype": "DocField",
"fieldname": "production",
"fieldtype": "Section Break",
diff --git a/startup/install.py b/startup/install.py
index 7e9273c..ea281b8 100644
--- a/startup/install.py
+++ b/startup/install.py
@@ -72,7 +72,7 @@
'fs_exports', 'fs_imports', 'fs_discounts', 'fs_purchase_discounts',
'fs_after_sales_installations', 'fs_projects', 'fs_sales_extras',
'fs_recurring_invoice', 'fs_pos', 'fs_manufacturing', 'fs_quality',
- 'fs_page_break', 'fs_more_info'
+ 'fs_page_break', 'fs_more_info', 'fs_pos_view'
]
doc.fields.update(dict(zip(flds, [1]*len(flds))))
doc.save()
diff --git a/stock/doctype/purchase_receipt/purchase_receipt_list.js b/stock/doctype/purchase_receipt/purchase_receipt_list.js
deleted file mode 100644
index bc0c9f6..0000000
--- a/stock/doctype/purchase_receipt/purchase_receipt_list.js
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
-// License: GNU General Public License v3. See license.txt
-
-// render
-wn.listview_settings['Purchase Receipt'] = {
- add_fields: ["group_concat(`tabPurchase Receipt Item`.prevdoc_docname) \
- as purchase_order_no"],
- add_columns: [{"content":"purchase_order_no", width:"30%"}],
- group_by: "`tabPurchase Receipt`.name",
- prepare_data: function(data) {
- if(data.purchase_order_no) {
- data.purchase_order_no = $.unique(data.purchase_order_no.split(","));
- var po_list = [];
- $.each(data.purchase_order_no, function(i, v){
- if(po_list.indexOf(v)==-1) po_list.push(
- repl("<a href=\"#Form/Purchase Order/%(name)s\">%(name)s</a>",
- {name: v}));
- });
- data.purchase_order_no = po_list.join(", ");
- }
- }
-};
diff --git a/stock/utils.py b/stock/utils.py
index b071d75..f0e9481 100644
--- a/stock/utils.py
+++ b/stock/utils.py
@@ -248,8 +248,7 @@
and exists (select name from `tabItem`
where `tabItem`.name = `tabBin`.item_code and
is_stock_item='Yes' and (is_purchase_item='Yes' or is_sub_contracted_item='Yes') and
- (ifnull(end_of_life, '')='') or end_of_life > now())""",
- as_dict=True)
+ (ifnull(end_of_life, '')='' or end_of_life > now()))""", as_dict=True)
for bin in bin_list:
#check if re-order is required
item_reorder = webnotes.conn.get("Item Reorder",
@@ -389,4 +388,4 @@
"""
from webnotes.model.code import get_obj
for wh in webnotes.conn.sql("select name from tabWarehouse"):
- get_obj('Warehouse', wh[0]).repost_stock()
\ No newline at end of file
+ get_obj('Warehouse', wh[0]).repost_stock()
diff --git a/utilities/demo/__init__.py b/utilities/demo/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/utilities/demo/__init__.py
diff --git a/utilities/demo/demo-login.css b/utilities/demo/demo-login.css
new file mode 100644
index 0000000..f3464a3
--- /dev/null
+++ b/utilities/demo/demo-login.css
@@ -0,0 +1,3 @@
+body, #container, .outer {
+ background-color: #888 !important;
+}
\ No newline at end of file
diff --git a/utilities/demo/demo-login.html b/utilities/demo/demo-login.html
new file mode 100644
index 0000000..ef24678
--- /dev/null
+++ b/utilities/demo/demo-login.html
@@ -0,0 +1,25 @@
+<div class="container">
+ <div class="row" style="margin-top: 100px;">
+ <div class="col-sm-offset-3 col-sm-6">
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ Start ERPNext Demo
+ </div>
+ <div class="panel-body">
+ <p>
+ <input id="lead-email" type="email"
+ class="form-control" placeholder="Your Email Id">
+ </p>
+ <p>
+ <button type="submit" id="login_btn"
+ class="btn btn-primary btn-large">Launch Demo</button>
+ </p>
+ <hr>
+ <p class="text-muted small">Some functionality is disabled for the demo app. The demo data will be cleared regulary. To start your own ERPNext Trial, <a href="https://erpnext.com/pricing-and-signup">click here</a></p>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="row">
+ </div>
+</div>
diff --git a/utilities/demo/demo-login.js b/utilities/demo/demo-login.js
new file mode 100644
index 0000000..229d169
--- /dev/null
+++ b/utilities/demo/demo-login.js
@@ -0,0 +1,27 @@
+$(document).ready(function() {
+ $(".navbar, footer, .banner, #user-tools").toggle(false);
+
+ $("#login_btn").click(function() {
+ var me = this;
+ $(this).html("Logging In...").attr("disabled", "disabled");
+ wn.call({
+ "method": "login",
+ args: {
+ usr: "demo@erpnext.com",
+ pwd: "demo",
+ lead_email: $("#lead-email").val(),
+ },
+ callback: function(r) {
+ $(me).attr("disabled", false);
+ if(r.exc) {
+ alert("Error, please contact support@erpnext.com");
+ } else {
+ console.log("Logged In");
+ window.location.href = "app.html";
+ }
+ }
+ })
+ return false;
+ })
+ .attr("disabled", false);
+})
\ No newline at end of file
diff --git a/utilities/demo/demo_control_panel.py b/utilities/demo/demo_control_panel.py
new file mode 100644
index 0000000..c70913e
--- /dev/null
+++ b/utilities/demo/demo_control_panel.py
@@ -0,0 +1,13 @@
+
+ def on_login(self):
+ from webnotes.utils import validate_email_add
+ import conf
+ if hasattr(conf, "demo_notify_url"):
+ if webnotes.form_dict.lead_email and validate_email_add(webnotes.form_dict.lead_email):
+ import requests
+ response = requests.post(conf.demo_notify_url, data={
+ "cmd":"website.helpers.contact.send_message",
+ "subject":"Logged into Demo",
+ "sender": webnotes.form_dict.lead_email,
+ "message": "via demo.erpnext.com"
+ })
diff --git a/utilities/demo_docs/Address.csv b/utilities/demo/demo_docs/Address.csv
similarity index 100%
rename from utilities/demo_docs/Address.csv
rename to utilities/demo/demo_docs/Address.csv
diff --git a/utilities/demo_docs/BOM.csv b/utilities/demo/demo_docs/BOM.csv
similarity index 100%
rename from utilities/demo_docs/BOM.csv
rename to utilities/demo/demo_docs/BOM.csv
diff --git a/utilities/demo_docs/Contact.csv b/utilities/demo/demo_docs/Contact.csv
similarity index 100%
rename from utilities/demo_docs/Contact.csv
rename to utilities/demo/demo_docs/Contact.csv
diff --git a/utilities/demo_docs/Customer.csv b/utilities/demo/demo_docs/Customer.csv
similarity index 100%
rename from utilities/demo_docs/Customer.csv
rename to utilities/demo/demo_docs/Customer.csv
diff --git a/utilities/demo_docs/Employee.csv b/utilities/demo/demo_docs/Employee.csv
similarity index 100%
rename from utilities/demo_docs/Employee.csv
rename to utilities/demo/demo_docs/Employee.csv
diff --git a/utilities/demo_docs/Fiscal_Year.csv b/utilities/demo/demo_docs/Fiscal_Year.csv
similarity index 100%
rename from utilities/demo_docs/Fiscal_Year.csv
rename to utilities/demo/demo_docs/Fiscal_Year.csv
diff --git a/utilities/demo_docs/Item.csv b/utilities/demo/demo_docs/Item.csv
similarity index 100%
rename from utilities/demo_docs/Item.csv
rename to utilities/demo/demo_docs/Item.csv
diff --git a/utilities/demo_docs/Item_Price.csv b/utilities/demo/demo_docs/Item_Price.csv
similarity index 100%
rename from utilities/demo_docs/Item_Price.csv
rename to utilities/demo/demo_docs/Item_Price.csv
diff --git a/utilities/demo_docs/Lead.csv b/utilities/demo/demo_docs/Lead.csv
similarity index 100%
rename from utilities/demo_docs/Lead.csv
rename to utilities/demo/demo_docs/Lead.csv
diff --git a/utilities/demo_docs/Profile.csv b/utilities/demo/demo_docs/Profile.csv
similarity index 100%
rename from utilities/demo_docs/Profile.csv
rename to utilities/demo/demo_docs/Profile.csv
diff --git a/utilities/demo_docs/Salary_Structure.csv b/utilities/demo/demo_docs/Salary_Structure.csv
similarity index 100%
rename from utilities/demo_docs/Salary_Structure.csv
rename to utilities/demo/demo_docs/Salary_Structure.csv
diff --git a/utilities/demo_docs/Stock Reconcilation Template.csv b/utilities/demo/demo_docs/Stock Reconcilation Template.csv
similarity index 100%
rename from utilities/demo_docs/Stock Reconcilation Template.csv
rename to utilities/demo/demo_docs/Stock Reconcilation Template.csv
diff --git a/utilities/demo_docs/Supplier.csv b/utilities/demo/demo_docs/Supplier.csv
similarity index 100%
rename from utilities/demo_docs/Supplier.csv
rename to utilities/demo/demo_docs/Supplier.csv
diff --git a/utilities/demo_docs/bearing-block.png b/utilities/demo/demo_docs/bearing-block.png
similarity index 100%
rename from utilities/demo_docs/bearing-block.png
rename to utilities/demo/demo_docs/bearing-block.png
Binary files differ
diff --git a/utilities/demo_docs/wind-turbine.png b/utilities/demo/demo_docs/wind-turbine.png
similarity index 100%
rename from utilities/demo_docs/wind-turbine.png
rename to utilities/demo/demo_docs/wind-turbine.png
Binary files differ
diff --git a/utilities/make_demo.py b/utilities/demo/make_demo.py
similarity index 92%
rename from utilities/make_demo.py
rename to utilities/demo/make_demo.py
index 809a12b..fc07767 100644
--- a/utilities/make_demo.py
+++ b/utilities/demo/make_demo.py
@@ -19,18 +19,19 @@
country = "United States"
currency = "USD"
time_zone = "America/New York"
-start_date = '2010-01-01'
+start_date = '2013-01-01'
bank_name = "Citibank"
-runs_for = 20
+runs_for = None
prob = {
"default": { "make": 0.6, "qty": (1,5) },
+ "Sales Order": { "make": 0.4, "qty": (1,3) },
"Purchase Order": { "make": 0.7, "qty": (1,15) },
"Purchase Receipt": { "make": 0.7, "qty": (1,15) },
}
def make(reset=False):
webnotes.connect()
- webnotes.print_messages = True
+ #webnotes.print_messages = True
webnotes.mute_emails = True
webnotes.rollback_on_exception = True
@@ -49,21 +50,24 @@
# make_opening_accounts()
def simulate():
- current_date = None
- for i in xrange(runs_for):
- if not current_date:
- # get last stock ledger posting date or use default
- last_posting = webnotes.conn.sql("""select max(posting_date) from `tabStock Ledger Entry`""")
- if last_posting[0][0]:
- current_date = webnotes.utils.add_days(last_posting[0][0], 1)
- else:
- current_date = webnotes.utils.getdate(start_date)
- else:
- current_date = webnotes.utils.add_days(current_date, 1)
-
+ global runs_for
+ current_date = webnotes.utils.getdate(start_date)
+
+ # continue?
+ last_posting = webnotes.conn.sql("""select max(posting_date) from `tabStock Ledger Entry`""")
+ if last_posting[0][0]:
+ current_date = webnotes.utils.add_days(last_posting[0][0], 1)
+
+ # run till today
+ if not runs_for:
+ runs_for = webnotes.utils.date_diff(webnotes.utils.nowdate(), current_date)
+
+ for i in xrange(runs_for):
print current_date.strftime("%Y-%m-%d")
+ webnotes.utils.current_date = current_date
if current_date.weekday() in (5, 6):
+ current_date = webnotes.utils.add_days(current_date, 1)
continue
run_sales(current_date)
@@ -71,6 +75,8 @@
run_manufacturing(current_date)
run_stock(current_date)
run_accounts(current_date)
+
+ current_date = webnotes.utils.add_days(current_date, 1)
def run_sales(current_date):
if can_make("Quotation"):
@@ -135,7 +141,7 @@
for po in list(set([r[0] for r in query_report.run(report)["result"] if r[0]!="Total"]))[:how_many("Purchase Receipt")]:
pr = webnotes.bean(make_purchase_receipt(po))
pr.doc.posting_date = current_date
- pr.doc.fiscal_year = "2010"
+ pr.doc.fiscal_year = "2013"
pr.insert()
pr.submit()
webnotes.conn.commit()
@@ -149,7 +155,7 @@
for so in list(set([r[0] for r in query_report.run(report)["result"] if r[0]!="Total"]))[:how_many("Delivery Note")]:
dn = webnotes.bean(make_delivery_note(so))
dn.doc.posting_date = current_date
- dn.doc.fiscal_year = "2010"
+ dn.doc.fiscal_year = "2013"
dn.insert()
try:
dn.submit()
@@ -172,7 +178,7 @@
mr = webnotes.new_bean("Material Request")
mr.doc.material_request_type = "Purchase"
mr.doc.transaction_date = current_date
- mr.doc.fiscal_year = "2010"
+ mr.doc.fiscal_year = "2013"
mr.doclist.append({
"doctype": "Material Request Item",
"parentfield": "indent_details",
@@ -191,7 +197,7 @@
if row[0] != "Total":
sq = webnotes.bean(make_supplier_quotation(row[0]))
sq.doc.transaction_date = current_date
- sq.doc.fiscal_year = "2010"
+ sq.doc.fiscal_year = "2013"
sq.insert()
sq.submit()
webnotes.conn.commit()
@@ -204,7 +210,7 @@
if row[0] != "Total":
po = webnotes.bean(make_purchase_order(row[0]))
po.doc.transaction_date = current_date
- po.doc.fiscal_year = "2010"
+ po.doc.fiscal_year = "2013"
po.insert()
po.submit()
webnotes.conn.commit()
@@ -262,7 +268,7 @@
st = webnotes.bean(make_stock_entry(pro_id, purpose))
st.doc.posting_date = current_date
- st.doc.fiscal_year = "2010"
+ st.doc.fiscal_year = "2013"
st.doc.expense_adjustment_account = "Stock in Hand - WP"
try:
st.insert()
@@ -281,7 +287,7 @@
"customer": get_random("Customer"),
"order_type": "Sales",
"transaction_date": current_date,
- "fiscal_year": "2010"
+ "fiscal_year": "2013"
}])
add_random_children(b, {
@@ -348,8 +354,9 @@
def install():
print "Creating Fresh Database..."
from webnotes.install_lib.install import Installer
+ import conf
inst = Installer('root')
- inst.import_from_db("demo", verbose = 1)
+ inst.import_from_db(conf.demo_db_name, verbose = 1)
def complete_setup():
print "Complete Setup..."
@@ -391,6 +398,7 @@
}).insert()
webnotes.set_value("Company", company, "default_bank_account", ba.doc.name)
+ webnotes.conn.commit()
def import_data(dt, submit=False):
if not isinstance(dt, (tuple, list)):
diff --git a/utilities/demo/make_erpnext_demo.py b/utilities/demo/make_erpnext_demo.py
new file mode 100644
index 0000000..0a8a935
--- /dev/null
+++ b/utilities/demo/make_erpnext_demo.py
@@ -0,0 +1,81 @@
+if __name__=="__main__":
+ import sys
+ sys.path.extend([".", "lib", "app"])
+
+import webnotes, os
+
+def make_demo_app():
+ import utilities.demo.make_demo
+ utilities.demo.make_demo.make(reset=True)
+
+def make_demo_user():
+ if webnotes.conn.exists("Profile", "demo@erpnext.com"):
+ webnotes.delete_doc("Profile", "demo@erpnext.com")
+
+ p = webnotes.new_bean("Profile")
+ p.doc.email = "demo@erpnext.com"
+ p.doc.first_name = "Demo"
+ p.doc.last_name = "User"
+ p.doc.enabled = 1
+ p.doc.user_type = "ERPNext Demo"
+ p.doc.send_invite_email = 0
+ p.doc.new_password = "demo"
+ p.insert()
+
+ for role in ("Accounts Manager", "Analytics", "Expense Approver", "Accounts User",
+ "Leave Approver", "Blogger", "Customer", "Sales Manager", "Employee", "Support Manager",
+ "HR Manager", "HR User", "Maintenance Manager", "Maintenance User", "Material Manager",
+ "Material Master Manager", "Material User", "Partner", "Manufacturing Manager",
+ "Manufacturing User", "Projects User", "Purchase Manager", "Purchase Master Manager",
+ "Purchase User", "Quality Manager", "Report Manager", "Sales Master Manager", "Sales User",
+ "Supplier", "Support Team"):
+ p.doclist.append({
+ "doctype": "UserRole",
+ "parentfield": "user_roles",
+ "role": role
+ })
+
+ p.save()
+ webnotes.conn.commit()
+
+def make_demo_login_page():
+ webnotes.conn.set_value("Website Settings", None, "home_page", "")
+
+ webnotes.conn.sql("""delete from `tabWeb Page` where name='demo-login'""")
+ p = webnotes.new_bean("Web Page")
+ p.doc.title = "Demo Login"
+ p.doc.published = 1
+ p.doc.description = "ERPNext Demo Login"
+
+ with open(os.path.join(os.path.dirname(__file__), "demo-login.html"), "r") as dfile:
+ p.doc.main_section = dfile.read()
+
+ p.doc.insert_code = 1
+ with open(os.path.join(os.path.dirname(__file__), "demo-login.js"), "r") as dfile:
+ p.doc.javascript = dfile.read()
+
+ p.doc.insert_style = 1
+ with open(os.path.join(os.path.dirname(__file__), "demo-login.css"), "r") as dfile:
+ p.doc.css = dfile.read()
+
+ p.insert()
+
+ webnotes.conn.set_value("Website Settings", None, "home_page", "demo-login")
+
+ webnotes.conn.commit()
+
+def make_demo_on_login_script():
+ webnotes.conn.sql("""delete from `tabCustom Script` where dt='Control Panel'""")
+ s = webnotes.new_bean("Custom Script")
+ s.doc.dt = "Control Panel"
+ s.doc.script_type = "Server"
+ with open(os.path.join(os.path.dirname(__file__), "demo_control_panel.py"), "r") as dfile:
+ s.doc.script = dfile.read()
+
+if __name__=="__main__":
+ webnotes.connect()
+ webnotes.mute_emails = 1
+ make_demo_app()
+ make_demo_user()
+ make_demo_login_page()
+ make_demo_on_login_script()
\ No newline at end of file
diff --git a/website/doctype/website_settings/website_settings.js b/website/doctype/website_settings/website_settings.js
index 0d0dab6..21b55be 100644
--- a/website/doctype/website_settings/website_settings.js
+++ b/website/doctype/website_settings/website_settings.js
@@ -4,6 +4,14 @@
// update parent select
$.extend(cur_frm.cscript, {
+ refresh: function(doc) {
+ cur_frm.add_custom_button("Auto Build Website", function() {
+ cur_frm.call({
+ doc: cur_frm.doc,
+ method: "make_website"
+ })
+ }, 'icon-magic')
+ },
onload_post_render: function(doc) {
this.set_parent_label_options();
},
diff --git a/website/doctype/website_settings/website_settings.py b/website/doctype/website_settings/website_settings.py
index 3b27c7c..5d6c874 100644
--- a/website/doctype/website_settings/website_settings.py
+++ b/website/doctype/website_settings/website_settings.py
@@ -13,6 +13,26 @@
self.set_home_page()
self.validate_top_bar_items()
self.validate_footer_items()
+
+ def make_website(self):
+ # set item pages
+ for name in webnotes.conn.sql_list("""select name from tabItem where
+ ifnull(show_in_website, 0)=0 and is_sales_item ='Yes' """):
+ webnotes.msgprint("Setting 'Show in Website' for:" + name)
+ item = webnotes.bean("Item", name)
+ item.doc.show_in_website = 1
+ item.doc.website_warehouse = item.doc.default_warehouse
+ item.doc.website_image = item.doc.image
+ item.save()
+
+ # set item group pages
+ for name in webnotes.conn.sql_list("""select name from `tabItem Group` where
+ ifnull(show_in_website, 0)=0 and exists (select name from tabItem where
+ ifnull(show_in_website, 0)=1)"""):
+ webnotes.msgprint("Setting 'Show in Website' for:" + name)
+ item_group = webnotes.bean("Item Group", name)
+ item_group.doc.show_in_website = 1
+ item_group.save()
def validate_top_bar_items(self):
"""validate url in top bar items"""