', {
description: d.description,
rate: d.rate,
- tax_amount: format_currency(d.tax_amount, me.frm.doc.price_list_currency)
+ tax_amount: format_currency(flt(d.tax_amount)/flt(me.frm.doc.conversion_rate),
+ me.frm.doc.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));
+ if (this.sales_or_purchase == "Sales") {
+ this.wrapper.find(".net-total").text(format_currency(this.frm.doc.net_total_export,
+ me.frm.doc.currency));
+ this.wrapper.find(".grand-total").text(format_currency(this.frm.doc.grand_total_export,
+ me.frm.doc.currency));
+ }
+ else {
+ this.wrapper.find(".net-total").text(format_currency(this.frm.doc.net_total_import,
+ me.frm.doc.currency));
+ this.wrapper.find(".grand-total").text(format_currency(this.frm.doc.grand_total_import,
+ me.frm.doc.currency));
+ }
// if form is local then only run all these functions
- if (cur_frm.doc.docstatus===0) {
- $("input.qty").on("focus", function() {
+ if (this.frm.doc.docstatus===0) {
+ $(this.wrapper).find("input.qty").on("focus", function() {
$(this).select();
});
// append quantity to the respective item after change from input box
- $("input.qty").on("change", function() {
+ $(this.wrapper).find("input.qty").on("change", function() {
var item_code = $(this).closest("tr")[0].id;
me.update_qty(item_code, $(this).val(), true);
});
// on td click toggle the highlighting of row
- $("#cart tbody tr td").on("click", function() {
+ $(this.wrapper).find("#cart tbody tr td").on("click", function() {
var row = $(this).closest("tr");
if (row.attr("data-selected") == "false") {
row.attr("class", "warning");
@@ -335,20 +371,37 @@ erpnext.POS = Class.extend({
});
me.refresh_delete_btn();
- cur_frm.pos.barcode.$input.focus();
+ this.barcode.$input.focus();
}
// if form is submitted & cancelled then disable all input box & buttons
- if (cur_frm.doc.docstatus>=1 && cint(cur_frm.doc.is_pos)) {
- me.wrapper.find('input, button').each(function () {
+ if (this.frm.doc.docstatus>=1) {
+ $(this.wrapper).find('input, button').each(function () {
$(this).prop('disabled', true);
});
- $(".delete-items").hide();
- $(".make-payment").hide();
+ $(this.wrapper).find(".delete-items").hide();
+ $(this.wrapper).find(".make-payment").hide();
+ }
+ else {
+ $(this.wrapper).find('input, button').each(function () {
+ $(this).prop('disabled', false);
+ });
+ $(this.wrapper).find(".make-payment").show();
+ }
+
+ // Show Make Payment button only in Sales Invoice
+ if (this.frm.doctype != "Sales Invoice")
+ $(this.wrapper).find(".make-payment").hide();
+
+ // If quotation to is not Customer then remove party
+ if (this.frm.doctype == "Quotation") {
+ this.party_field.$wrapper.remove();
+ if (this.frm.doc.quotation_to == "Customer")
+ this.make_party();
}
},
refresh_delete_btn: function() {
- $(".delete-items").toggle($(".item-cart .warning").length ? true : false);
+ $(this.wrapper).find(".delete-items").toggle($(".item-cart .warning").length ? true : false);
},
add_item_thru_barcode: function() {
var me = this;
@@ -370,32 +423,32 @@ erpnext.POS = Class.extend({
remove_selected_item: function() {
var me = this;
var selected_items = [];
- var no_of_items = $("#cart tbody tr").length;
+ var no_of_items = $(this.wrapper).find("#cart tbody tr").length;
for(var x=0; x<=no_of_items - 1; x++) {
- var row = $("#cart tbody tr:eq(" + 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 = wn.model.get_children("Sales Invoice Item", this.frm.doc.name, "entries",
- "Sales Invoice");
+
+ var child = wn.model.get_children(this.frm.doctype + " Item", this.frm.doc.name,
+ this.frm.cscript.fname, this.frm.doctype);
+
$.each(child, function(i, d) {
for (var i in selected_items) {
if (d.item_code == selected_items[i]) {
- // cur_frm.fields_dict["entries"].grid.grid_rows[d.idx].remove();
wn.model.clear_doc(d.doctype, d.name);
}
}
});
- cur_frm.fields_dict["entries"].grid.refresh();
- cur_frm.script_manager.trigger("calculate_taxes_and_totals");
+ this.frm.fields_dict[this.frm.cscript.fname].grid.refresh();
+ this.frm.script_manager.trigger("calculate_taxes_and_totals");
me.frm.dirty();
me.refresh();
},
make_payment: function() {
var me = this;
- var no_of_items = $("#cart tbody tr").length;
+ var no_of_items = $(this.wrapper).find("#cart tbody tr").length;
var mode_of_payment = [];
if (no_of_items == 0)
@@ -423,15 +476,15 @@ erpnext.POS = Class.extend({
"total_amount": $(".grand-total").text()
});
dialog.show();
- cur_frm.pos.barcode.$input.focus();
+ me.barcode.$input.focus();
dialog.get_input("total_amount").prop("disabled", true);
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.cscript.mode_of_payment(cur_frm.doc);
- cur_frm.save();
+ me.frm.set_value("mode_of_payment", dialog.get_values().mode_of_payment);
+ me.frm.set_value("paid_amount", dialog.get_values().total_amount);
+ me.frm.cscript.mode_of_payment(me.frm.doc);
+ me.frm.save();
dialog.hide();
me.refresh();
};
diff --git a/accounts/doctype/sales_invoice/pos.py b/accounts/doctype/sales_invoice/pos.py
index 08340f76c5e..44fe40d8de9 100644
--- a/accounts/doctype/sales_invoice/pos.py
+++ b/accounts/doctype/sales_invoice/pos.py
@@ -3,17 +3,21 @@
from __future__ import unicode_literals
import webnotes
-from webnotes import msgprint
@webnotes.whitelist()
-def get_items(price_list, item=None, item_group=None):
+def get_items(price_list, sales_or_purchase, item=None, item_group=None):
condition = ""
+ if sales_or_purchase == "Sales":
+ condition = "i.is_sales_item='Yes'"
+ else:
+ condition = "i.is_purchase_item='Yes'"
+
if item_group and item_group != "All Item Groups":
- condition = "and i.item_group='%s'" % item_group
+ condition += " and i.item_group='%s'" % item_group
if item:
- condition = "and i.name='%s'" % item
+ condition += " and i.name='%s'" % item
return webnotes.conn.sql("""select i.name, i.item_name, i.image,
pl_items.ref_rate, pl_items.currency
@@ -24,13 +28,18 @@ def get_items(price_list, item=None, item_group=None):
ON
pl_items.item_code=i.name
where
- i.is_sales_item='Yes'%s""" % ('%s', condition), (price_list), as_dict=1)
+ %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_item_from_serial_no(serial_no):
+ return webnotes.conn.sql("""select name, item_code from `tabSerial No` where
+ name=%s""", (serial_no), 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
deleted file mode 100644
index e4b61b66ca8..00000000000
--- a/accounts/doctype/sales_invoice/sales_invoice.css
+++ /dev/null
@@ -1,15 +0,0 @@
-.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 b87f6efe4dc..a926e31f546 100644
--- a/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/accounts/doctype/sales_invoice/sales_invoice.js
@@ -29,9 +29,10 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
// toggle to pos view if is_pos is 1 in user_defaults
if ((cint(wn.defaults.get_user_defaults("is_pos"))===1 || cur_frm.doc.is_pos) &&
cint(wn.defaults.get_user_defaults("fs_pos_view"))===1) {
- this.frm.set_value("is_pos", 1);
- this.is_pos();
- cur_frm.cscript.toggle_pos(true);
+ if(this.frm.doc.__islocal && !this.frm.doc.amended_from) {
+ this.frm.set_value("is_pos", 1);
+ this.is_pos(function() {cur_frm.cscript.toggle_pos(true);});
+ }
}
// if document is POS then change default print format to "POS Invoice"
@@ -78,14 +79,11 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
cur_frm.add_custom_button(wn._('Make Payment Entry'), cur_frm.cscript.make_bank_voucher);
}
- if (doc.docstatus===0) {
+ // Show buttons only when pos view is active
+ if (doc.docstatus===0 && !this.pos_active) {
cur_frm.cscript.sales_order_btn();
cur_frm.cscript.delivery_note_btn();
}
-
- // Show POS button only if it enabled from features setup
- if(cint(sys_defaults.fs_pos_view)===1)
- cur_frm.cscript.pos_btn();
},
sales_order_btn: function() {
@@ -124,62 +122,13 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
});
});
},
-
- 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";
-
- cur_frm.cscript.sales_order_btn();
- cur_frm.cscript.delivery_note_btn();
- } else {
- var btn_label = wn._("Invoice View"),
- icon = "icon-file-text";
-
- if (cur_frm.doc.docstatus===0) {
- this.$delivery_note_btn.remove();
- this.$sales_order_btn.remove();
- }
- }
-
- 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 (!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();
- }
- },
tc_name: function() {
this.get_terms();
},
- is_pos: function() {
+ is_pos: function(callback_fn) {
cur_frm.cscript.hide_fields(this.frm.doc);
-
if(cint(this.frm.doc.is_pos)) {
if(!this.frm.doc.company) {
this.frm.set_value("is_pos", 0);
@@ -192,6 +141,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
callback: function(r) {
if(!r.exc) {
me.frm.script_manager.trigger("update_stock");
+ if(callback_fn) callback_fn()
}
}
});
@@ -256,7 +206,6 @@ cur_frm.cscript.hide_fields = function(doc) {
'total_commission', 'advances'];
item_flds_normal = ['sales_order', 'delivery_note']
- item_flds_pos = ['serial_no', 'batch_no', 'actual_qty', 'expense_account']
if(cint(doc.is_pos) == 1) {
hide_field(par_flds);
@@ -271,7 +220,9 @@ cur_frm.cscript.hide_fields = function(doc) {
cur_frm.fields_dict['entries'].grid.set_column_disp(item_flds_normal, true);
}
- cur_frm.fields_dict['entries'].grid.set_column_disp(item_flds_pos, (cint(doc.update_stock)==1?true:false));
+ item_flds_stock = ['serial_no', 'batch_no', 'actual_qty', 'expense_account', 'warehouse']
+ cur_frm.fields_dict['entries'].grid.set_column_disp(item_flds_stock,
+ (cint(doc.update_stock)==1 ? true : false));
// India related fields
var cp = wn.control_panel;
diff --git a/accounts/doctype/sales_invoice/sales_invoice.py b/accounts/doctype/sales_invoice/sales_invoice.py
index 12deed73a87..92c168008a1 100644
--- a/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/accounts/doctype/sales_invoice/sales_invoice.py
@@ -83,7 +83,6 @@ class DocType(SellingController):
def on_submit(self):
if cint(self.doc.update_stock) == 1:
self.update_stock_ledger()
- self.update_serial_nos()
else:
# Check for Approving Authority
if not self.doc.recurring_id:
@@ -111,7 +110,6 @@ class DocType(SellingController):
def on_cancel(self):
if cint(self.doc.update_stock) == 1:
self.update_stock_ledger()
- self.update_serial_nos(cancel = True)
sales_com_obj = get_obj(dt = 'Sales Common')
sales_com_obj.check_stop_sales_order(self)
@@ -195,7 +193,7 @@ class DocType(SellingController):
pos = get_pos_settings(self.doc.company)
if pos:
- if not for_validate:
+ if not for_validate and not self.doc.customer:
self.doc.customer = pos.customer
self.set_customer_defaults()
@@ -266,13 +264,7 @@ class DocType(SellingController):
def get_adj_percent(self, arg=''):
"""Fetch ref rate from item master as per selected price list"""
- get_obj('Sales Common').get_adj_percent(self)
-
-
- def get_rate(self,arg):
- """Get tax rate if account type is tax"""
- get_obj('Sales Common').get_rate(arg)
-
+ get_obj('Sales Common').get_adj_percent(self)
def get_comm_rate(self, sales_partner):
"""Get Commission rate of Sales Partner"""
@@ -965,8 +957,7 @@ def make_delivery_note(source_name, target_doclist=None):
"doctype": "Delivery Note Item",
"field_map": {
"name": "prevdoc_detail_docname",
- "parent": "prevdoc_docname",
- "parenttype": "prevdoc_doctype",
+ "parent": "against_sales_invoice",
"serial_no": "serial_no"
},
"postprocess": update_item
diff --git a/accounts/doctype/sales_invoice/sales_invoice.txt b/accounts/doctype/sales_invoice/sales_invoice.txt
index f921f242234..331a503b28d 100644
--- a/accounts/doctype/sales_invoice/sales_invoice.txt
+++ b/accounts/doctype/sales_invoice/sales_invoice.txt
@@ -2,12 +2,13 @@
{
"creation": "2013-05-24 19:29:05",
"docstatus": 0,
- "modified": "2013-09-01 05:26:13",
+ "modified": "2013-10-11 13:12:38",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"allow_attach": 1,
+ "allow_import": 1,
"autoname": "naming_series:",
"default_print_format": "Standard",
"doctype": "DocType",
@@ -225,7 +226,6 @@
"reqd": 1
},
{
- "default": "1.00",
"description": "Rate at which Customer Currency is converted to customer's base currency",
"doctype": "DocField",
"fieldname": "conversion_rate",
@@ -411,7 +411,7 @@
"doctype": "DocField",
"fieldname": "other_charges",
"fieldtype": "Table",
- "label": "Taxes and Charges1",
+ "label": "Sales Taxes and Charges",
"oldfieldname": "other_charges",
"oldfieldtype": "Table",
"options": "Sales Taxes and Charges",
diff --git a/accounts/doctype/sales_invoice/test_sales_invoice.py b/accounts/doctype/sales_invoice/test_sales_invoice.py
index dee098a3e4f..9f5b95cd79c 100644
--- a/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -641,8 +641,8 @@ class TestSalesInvoice(unittest.TestCase):
return new_si
- # if yearly, test 3 repetitions, else test 13 repetitions
- count = 3 if no_of_months == 12 else 13
+ # if yearly, test 1 repetition, else test 5 repetitions
+ count = 1 if (no_of_months == 12) else 5
for i in xrange(count):
base_si = _test(i)
@@ -653,7 +653,7 @@ class TestSalesInvoice(unittest.TestCase):
def test_serialized(self):
from stock.doctype.stock_entry.test_stock_entry import make_serialized_item
- from stock.doctype.stock_ledger_entry.stock_ledger_entry import get_serial_nos
+ from stock.doctype.serial_no.serial_no import get_serial_nos
se = make_serialized_item()
serial_nos = get_serial_nos(se.doclist[1].serial_no)
@@ -674,7 +674,7 @@ class TestSalesInvoice(unittest.TestCase):
return si
def test_serialized_cancel(self):
- from stock.doctype.stock_ledger_entry.stock_ledger_entry import get_serial_nos
+ from stock.doctype.serial_no.serial_no import get_serial_nos
si = self.test_serialized()
si.cancel()
@@ -686,7 +686,7 @@ class TestSalesInvoice(unittest.TestCase):
"delivery_document_no"))
def test_serialize_status(self):
- from stock.doctype.stock_ledger_entry.stock_ledger_entry import SerialNoStatusError, get_serial_nos
+ from stock.doctype.serial_no.serial_no import SerialNoStatusError, get_serial_nos
from stock.doctype.stock_entry.test_stock_entry import make_serialized_item
se = make_serialized_item()
diff --git a/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.js b/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.js
index 56e64bc1830..0e623a1dc7e 100644
--- a/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.js
+++ b/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.js
@@ -2,6 +2,9 @@
// License: GNU General Public License v3. See license.txt
//--------- ONLOAD -------------
+
+wn.require("app/js/controllers/accounts.js");
+
cur_frm.cscript.onload = function(doc, cdt, cdn) {
if(doc.doctype === "Sales Taxes and Charges Master")
erpnext.add_for_territory();
@@ -142,6 +145,7 @@ cur_frm.fields_dict['other_charges'].grid.get_field("cost_center").get_query = f
}
}
+<<<<<<< HEAD
cur_frm.cscript.account_head = function(doc, cdt, cdn) {
var d = locals[cdt][cdn];
@@ -157,6 +161,8 @@ cur_frm.cscript.account_head = function(doc, cdt, cdn) {
refresh_field('account_head',d.name,'other_charges');
}
+=======
+>>>>>>> f146e8b7f52a3e46e335c0fefd92c347717b370b
cur_frm.cscript.rate = function(doc, cdt, cdn) {
var d = locals[cdt][cdn];
if(!d.charge_type && d.rate) {
diff --git a/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.py b/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.py
index 019edcb31b1..67ba9cb8add 100644
--- a/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.py
+++ b/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.py
@@ -6,11 +6,7 @@ import webnotes
from webnotes.utils import cint
from webnotes.model.controller import DocListController
-class DocType(DocListController):
- def get_rate(self, arg):
- from webnotes.model.code import get_obj
- return get_obj('Sales Common').get_rate(arg)
-
+class DocType(DocListController):
def validate(self):
if self.doc.is_default == 1:
webnotes.conn.sql("""update `tabSales Taxes and Charges Master` set is_default = 0
diff --git a/accounts/page/accounts_browser/accounts_browser.py b/accounts/page/accounts_browser/accounts_browser.py
index 61f4bfc521b..7bc95494128 100644
--- a/accounts/page/accounts_browser/accounts_browser.py
+++ b/accounts/page/accounts_browser/accounts_browser.py
@@ -15,7 +15,7 @@ def get_companies():
@webnotes.whitelist()
def get_children():
- args = webnotes.form_dict
+ args = webnotes.local.form_dict
ctype, company = args['ctype'], args['comp']
# root
diff --git a/accounts/page/voucher_import_tool/voucher_import_tool.py b/accounts/page/voucher_import_tool/voucher_import_tool.py
index 9425afc7d0f..14e30be7a9e 100644
--- a/accounts/page/voucher_import_tool/voucher_import_tool.py
+++ b/accounts/page/voucher_import_tool/voucher_import_tool.py
@@ -64,10 +64,10 @@ def upload():
data, start_idx = get_data(rows, company_abbr, rows[0][0])
except Exception, e:
- err_msg = webnotes.message_log and " ".join(webnotes.message_log) or cstr(e)
+ err_msg = webnotes.local.message_log and " ".join(webnotes.local.message_log) or cstr(e)
messages.append("""
%s
""" % (err_msg or "No message"))
webnotes.errprint(webnotes.getTraceback())
- webnotes.message_log = []
+ webnotes.local.message_log = []
return messages
return import_vouchers(common_values, data, start_idx, rows[0][0])
@@ -117,11 +117,11 @@ def import_vouchers(common_values, data, start_idx, import_type):
d = data[i][0]
if import_type == "Voucher Import: Two Accounts" and flt(d.get("amount")) == 0:
- webnotes.message_log = ["Amount not specified"]
+ webnotes.local.message_log = ["Amount not specified"]
raise Exception
elif import_type == "Voucher Import: Multiple Accounts" and \
(flt(d.get("total_debit")) == 0 or flt(d.get("total_credit")) == 0):
- webnotes.message_log = ["Total Debit and Total Credit amount can not be zero"]
+ webnotes.local.message_log = ["Total Debit and Total Credit amount can not be zero"]
raise Exception
else:
d.posting_date = parse_date(d.posting_date)
@@ -174,7 +174,7 @@ def import_vouchers(common_values, data, start_idx, import_type):
details.append(detail)
if not details:
- webnotes.message_log = ["""No accounts found.
+ webnotes.local.message_log = ["""No accounts found.
If you entered accounts correctly, please check template once"""]
raise Exception
@@ -193,12 +193,12 @@ def import_vouchers(common_values, data, start_idx, import_type):
webnotes.conn.commit()
except Exception, e:
webnotes.conn.rollback()
- err_msg = webnotes.message_log and " ".join(webnotes.message_log) or cstr(e)
+ err_msg = webnotes.local.message_log and " ".join(webnotes.local.message_log) or cstr(e)
messages.append("""
[row #%s] %s failed: %s
"""
% ((start_idx + 1) + i, jv.name or "", err_msg or "No message"))
messages.append("
All transactions rolled back
")
webnotes.errprint(webnotes.getTraceback())
- webnotes.message_log = []
+ webnotes.local.message_log = []
return messages
diff --git a/accounts/report/gross_profit/gross_profit.py b/accounts/report/gross_profit/gross_profit.py
index d9c20d5ccc7..9917b69697f 100644
--- a/accounts/report/gross_profit/gross_profit.py
+++ b/accounts/report/gross_profit/gross_profit.py
@@ -55,7 +55,7 @@ def get_stock_ledger_entries(filters):
from `tabStock Ledger Entry`"""
if filters.get("company"):
- query += """ and company=%(company)s"""
+ query += """ where company=%(company)s"""
query += " order by item_code desc, warehouse desc, posting_date desc, posting_time desc, name desc"
diff --git a/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py b/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py
index bd0726e37d9..1c3cef3115d 100644
--- a/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py
+++ b/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py
@@ -81,12 +81,12 @@ def get_tax_accounts(item_list, columns):
if account_head not in tax_accounts:
tax_accounts.append(account_head)
- invoice = item_tax.setdefault(parent, {})
if item_wise_tax_detail:
try:
item_wise_tax_detail = json.loads(item_wise_tax_detail)
for item, tax_amount in item_wise_tax_detail.items():
- invoice.setdefault(item, {})[account_head] = flt(tax_amount)
+ item_tax.setdefault(parent, {}).setdefault(item, {})[account_head] = \
+ flt(tax_amount[1])
except ValueError:
continue
diff --git a/accounts/report/item_wise_sales_register/item_wise_sales_register.py b/accounts/report/item_wise_sales_register/item_wise_sales_register.py
index 77fb6f25e6d..48bc463f14f 100644
--- a/accounts/report/item_wise_sales_register/item_wise_sales_register.py
+++ b/accounts/report/item_wise_sales_register/item_wise_sales_register.py
@@ -9,7 +9,7 @@ def execute(filters=None):
if not filters: filters = {}
columns = get_columns()
last_col = len(columns)
-
+
item_list = get_items(filters)
item_tax, tax_accounts = get_tax_accounts(item_list, columns)
@@ -21,7 +21,7 @@ def execute(filters=None):
for tax in tax_accounts:
row.append(item_tax.get(d.parent, {}).get(d.item_code, {}).get(tax, 0))
-
+
total_tax = sum(row[last_col:])
row += [total_tax, d.amount + total_tax]
@@ -71,19 +71,19 @@ def get_tax_accounts(item_list, columns):
tax_details = webnotes.conn.sql("""select parent, account_head, item_wise_tax_detail
from `tabSales Taxes and Charges` where parenttype = 'Sales Invoice'
and docstatus = 1 and ifnull(account_head, '') != ''
- and parent in (%s)""" % ', '.join(['%s']*len(item_list)), tuple([item.parent for item in item_list]))
+ and parent in (%s)""" % ', '.join(['%s']*len(item_list)),
+ tuple([item.parent for item in item_list]))
for parent, account_head, item_wise_tax_detail in tax_details:
if account_head not in tax_accounts:
tax_accounts.append(account_head)
-
- invoice = item_tax.setdefault(parent, {})
+
if item_wise_tax_detail:
try:
item_wise_tax_detail = json.loads(item_wise_tax_detail)
for item, tax_amount in item_wise_tax_detail.items():
- invoice.setdefault(item, {})[account_head] = flt(tax_amount)
-
+ item_tax.setdefault(parent, {}).setdefault(item, {})[account_head] = \
+ flt(tax_amount[1])
except ValueError:
continue
diff --git a/accounts/utils.py b/accounts/utils.py
index 5c6c16b76a9..ac823129d66 100644
--- a/accounts/utils.py
+++ b/accounts/utils.py
@@ -108,7 +108,7 @@ def get_balance_on(account=None, date=None):
@webnotes.whitelist()
def add_ac(args=None):
if not args:
- args = webnotes.form_dict
+ args = webnotes.local.form_dict
args.pop("cmd")
ac = webnotes.bean(args)
@@ -121,7 +121,7 @@ def add_ac(args=None):
@webnotes.whitelist()
def add_cc(args=None):
if not args:
- args = webnotes.form_dict
+ args = webnotes.local.form_dict
args.pop("cmd")
cc = webnotes.bean(args)
diff --git a/buying/doctype/purchase_common/purchase_common.js b/buying/doctype/purchase_common/purchase_common.js
index 2dfe65515a8..023c7f3a631 100644
--- a/buying/doctype/purchase_common/purchase_common.js
+++ b/buying/doctype/purchase_common/purchase_common.js
@@ -8,6 +8,7 @@
wn.provide("erpnext.buying");
wn.require("app/js/transaction.js");
+wn.require("app/js/controllers/accounts.js");
erpnext.buying.BuyingController = erpnext.TransactionController.extend({
onload: function() {
@@ -108,8 +109,7 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
var item = wn.model.get_doc(cdt, cdn);
if(item.item_code) {
if(!this.validate_company_and_party("supplier")) {
- item.item_code = null;
- refresh_field("item_code", item.name, item.parentfield);
+ cur_frm.fields_dict[me.frm.cscript.fname].grid.grid_rows[item.idx - 1].remove();
} else {
return this.frm.call({
method: "buying.utils.get_item_details",
diff --git a/buying/doctype/purchase_common/purchase_common.py b/buying/doctype/purchase_common/purchase_common.py
index 9b6dc6c9ab7..8637e5fb43a 100644
--- a/buying/doctype/purchase_common/purchase_common.py
+++ b/buying/doctype/purchase_common/purchase_common.py
@@ -10,7 +10,6 @@ from webnotes import msgprint, _
from buying.utils import get_last_purchase_details
-sql = webnotes.conn.sql
from controllers.buying_controller import BuyingController
class DocType(BuyingController):
@@ -23,27 +22,20 @@ class DocType(BuyingController):
msgprint(_("You need to put at least one item in the item table."), raise_exception=True)
def get_supplier_details(self, name = ''):
- details = sql("select supplier_name,address from `tabSupplier` where name = '%s' and docstatus != 2" %(name), as_dict = 1)
+ details = webnotes.conn.sql("select supplier_name,address from `tabSupplier` where name = '%s' and docstatus != 2" %(name), as_dict = 1)
if details:
ret = {
'supplier_name' : details and details[0]['supplier_name'] or '',
'supplier_address' : details and details[0]['address'] or ''
}
# ********** get primary contact details (this is done separately coz. , in case there is no primary contact thn it would not be able to fetch customer details in case of join query)
- contact_det = sql("select contact_name, contact_no, email_id from `tabContact` where supplier = '%s' and is_supplier = 1 and is_primary_contact = 'Yes' and docstatus != 2" %(name), as_dict = 1)
+ contact_det = webnotes.conn.sql("select contact_name, contact_no, email_id from `tabContact` where supplier = '%s' and is_supplier = 1 and is_primary_contact = 'Yes' and docstatus != 2" %(name), as_dict = 1)
ret['contact_person'] = contact_det and contact_det[0]['contact_name'] or ''
return ret
else:
msgprint("Supplier : %s does not exists" % (name))
raise Exception
- # Get Available Qty at Warehouse
- def get_bin_details( self, arg = ''):
- arg = eval(arg)
- bin = sql("select projected_qty from `tabBin` where item_code = %s and warehouse = %s", (arg['item_code'], arg['warehouse']), as_dict=1)
- ret = { 'projected_qty' : bin and flt(bin[0]['projected_qty']) or 0 }
- return ret
-
def update_last_purchase_rate(self, obj, is_submit):
"""updates last_purchase_rate in item table for each item"""
@@ -70,7 +62,7 @@ class DocType(BuyingController):
# update last purchsae rate
if last_purchase_rate:
- sql("update `tabItem` set last_purchase_rate = %s where name = %s",
+ webnotes.conn.sql("update `tabItem` set last_purchase_rate = %s where name = %s",
(flt(last_purchase_rate),d.item_code))
def get_last_purchase_rate(self, obj):
@@ -107,7 +99,7 @@ class DocType(BuyingController):
raise Exception
# udpate with latest quantities
- bin = sql("select projected_qty from `tabBin` where item_code = %s and warehouse = %s", (d.item_code, d.warehouse), as_dict = 1)
+ bin = webnotes.conn.sql("select projected_qty from `tabBin` where item_code = %s and warehouse = %s", (d.item_code, d.warehouse), as_dict = 1)
f_lst ={'projected_qty': bin and flt(bin[0]['projected_qty']) or 0, 'ordered_qty': 0, 'received_qty' : 0}
if d.doctype == 'Purchase Receipt Item':
@@ -116,7 +108,7 @@ class DocType(BuyingController):
if d.fields.has_key(x):
d.fields[x] = f_lst[x]
- item = sql("select is_stock_item, is_purchase_item, is_sub_contracted_item, end_of_life from tabItem where name=%s",
+ item = webnotes.conn.sql("select is_stock_item, is_purchase_item, is_sub_contracted_item, end_of_life from tabItem where name=%s",
d.item_code)
if not item:
msgprint("Item %s does not exist in Item Master." % cstr(d.item_code), raise_exception=True)
@@ -139,7 +131,7 @@ class DocType(BuyingController):
# if is not stock item
f = [d.schedule_date, d.item_code, d.description]
- ch = sql("select is_stock_item from `tabItem` where name = '%s'"%d.item_code)
+ ch = webnotes.conn.sql("select is_stock_item from `tabItem` where name = '%s'"%d.item_code)
if ch and ch[0][0] == 'Yes':
# check for same items
@@ -165,18 +157,18 @@ class DocType(BuyingController):
# but if in Material Request uom KG it can change in PO
get_qty = (transaction == 'Material Request - Purchase Order') and 'qty * conversion_factor' or 'qty'
- qty = sql("select sum(%s) from `tab%s` where %s = '%s' and docstatus = 1 and parent != '%s'"% ( get_qty, curr_doctype, ref_tab_fname, ref_tab_dn, curr_parent_name))
+ qty = webnotes.conn.sql("select sum(%s) from `tab%s` where %s = '%s' and docstatus = 1 and parent != '%s'"% ( get_qty, curr_doctype, ref_tab_fname, ref_tab_dn, curr_parent_name))
qty = qty and flt(qty[0][0]) or 0
# get total qty of ref doctype
#--------------------
- max_qty = sql("select qty from `tab%s` where name = '%s' and docstatus = 1"% (ref_doc_tname, ref_tab_dn))
+ max_qty = webnotes.conn.sql("select qty from `tab%s` where name = '%s' and docstatus = 1"% (ref_doc_tname, ref_tab_dn))
max_qty = max_qty and flt(max_qty[0][0]) or 0
return cstr(qty)+'~~~'+cstr(max_qty)
def check_for_stopped_status(self, doctype, docname):
- stopped = sql("select name from `tab%s` where name = '%s' and status = 'Stopped'" %
+ stopped = webnotes.conn.sql("select name from `tab%s` where name = '%s' and status = 'Stopped'" %
( doctype, docname))
if stopped:
msgprint("One cannot do any transaction against %s : %s, it's status is 'Stopped'" %
@@ -184,7 +176,7 @@ class DocType(BuyingController):
def check_docstatus(self, check, doctype, docname , detail_doctype = ''):
if check == 'Next':
- submitted = sql("""select t1.name from `tab%s` t1,`tab%s` t2
+ submitted = webnotes.conn.sql("""select t1.name from `tab%s` t1,`tab%s` t2
where t1.name = t2.parent and t2.prevdoc_docname = %s and t1.docstatus = 1"""
% (doctype, detail_doctype, '%s'), docname)
if submitted:
@@ -192,23 +184,8 @@ class DocType(BuyingController):
+ _(" has already been submitted."), raise_exception=1)
if check == 'Previous':
- submitted = sql("""select name from `tab%s`
+ submitted = webnotes.conn.sql("""select name from `tab%s`
where docstatus = 1 and name = %s"""% (doctype, '%s'), docname)
if not submitted:
msgprint(cstr(doctype) + ": " + cstr(submitted[0][0])
+ _(" not submitted"), raise_exception=1)
-
- def get_rate(self, arg, obj):
- arg = eval(arg)
- rate = sql("select account_type, tax_rate from `tabAccount` where name = %s"
- , (arg['account_head']), as_dict=1)
-
- return {'rate': rate and (rate[0]['account_type'] == 'Tax' \
- and not arg['charge_type'] == 'Actual') and flt(rate[0]['tax_rate']) or 0 }
-
- def get_prevdoc_date(self, obj):
- for d in getlist(obj.doclist, obj.fname):
- if d.prevdoc_doctype and d.prevdoc_docname:
- dt = sql("select transaction_date from `tab%s` where name = %s"
- % (d.prevdoc_doctype, '%s'), (d.prevdoc_docname))
- d.prevdoc_date = dt and dt[0][0].strftime('%Y-%m-%d') or ''
\ No newline at end of file
diff --git a/buying/doctype/purchase_order/purchase_order.js b/buying/doctype/purchase_order/purchase_order.js
index fb452033c73..c1342232bb8 100644
--- a/buying/doctype/purchase_order/purchase_order.js
+++ b/buying/doctype/purchase_order/purchase_order.js
@@ -10,6 +10,7 @@ cur_frm.cscript.other_fname = "purchase_tax_details";
wn.require('app/accounts/doctype/purchase_taxes_and_charges_master/purchase_taxes_and_charges_master.js');
wn.require('app/utilities/doctype/sms_control/sms_control.js');
wn.require('app/buying/doctype/purchase_common/purchase_common.js');
+wn.require('app/accounts/doctype/sales_invoice/pos.js');
erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend({
refresh: function(doc, cdt, cdn) {
@@ -184,9 +185,9 @@ cur_frm.pformat.indent_no = function(doc, cdt, cdn){
if(cl[i].prevdoc_doctype == 'Material Request' && cl[i].prevdoc_docname && prevdoc_list.indexOf(cl[i].prevdoc_docname) == -1) {
prevdoc_list.push(cl[i].prevdoc_docname);
if(prevdoc_list.length ==1)
- out += make_row(cl[i].prevdoc_doctype, cl[i].prevdoc_docname, cl[i].prevdoc_date,0);
+ out += make_row(cl[i].prevdoc_doctype, cl[i].prevdoc_docname, null,0);
else
- out += make_row('', cl[i].prevdoc_docname, cl[i].prevdoc_date,0);
+ out += make_row('', cl[i].prevdoc_docname,null,0);
}
}
}
diff --git a/buying/doctype/purchase_order/purchase_order.py b/buying/doctype/purchase_order/purchase_order.py
index 64f89e32ffe..cf207bb7477 100644
--- a/buying/doctype/purchase_order/purchase_order.py
+++ b/buying/doctype/purchase_order/purchase_order.py
@@ -9,7 +9,6 @@ from webnotes.model.bean import getlist
from webnotes.model.code import get_obj
from webnotes import msgprint
-sql = webnotes.conn.sql
from controllers.buying_controller import BuyingController
class DocType(BuyingController):
@@ -42,7 +41,6 @@ class DocType(BuyingController):
pc_obj = get_obj(dt='Purchase Common')
pc_obj.validate_for_items(self)
- pc_obj.get_prevdoc_date(self)
self.check_for_stopped_status(pc_obj)
self.validate_uom_is_integer("uom", "qty")
@@ -66,10 +64,6 @@ class DocType(BuyingController):
}
})
- # get available qty at warehouse
- def get_bin_details(self, arg = ''):
- return get_obj(dt='Purchase Common').get_bin_details(arg)
-
def get_schedule_dates(self):
for d in getlist(self.doclist, 'po_details'):
if d.prevdoc_detail_docname and not d.schedule_date:
@@ -133,8 +127,8 @@ class DocType(BuyingController):
update_bin(args)
def check_modified_date(self):
- mod_db = sql("select modified from `tabPurchase Order` where name = '%s'" % self.doc.name)
- date_diff = sql("select TIMEDIFF('%s', '%s')" % ( mod_db[0][0],cstr(self.doc.modified)))
+ mod_db = webnotes.conn.sql("select modified from `tabPurchase Order` where name = '%s'" % self.doc.name)
+ date_diff = webnotes.conn.sql("select TIMEDIFF('%s', '%s')" % ( mod_db[0][0],cstr(self.doc.modified)))
if date_diff and date_diff[0][0]:
msgprint(cstr(self.doc.doctype) +" => "+ cstr(self.doc.name) +" has been modified. Please Refresh. ")
@@ -173,7 +167,7 @@ class DocType(BuyingController):
pc_obj.check_docstatus(check = 'Next', doctype = 'Purchase Receipt', docname = self.doc.name, detail_doctype = 'Purchase Receipt Item')
# Check if Purchase Invoice has been submitted against current Purchase Order
- submitted = sql("select t1.name from `tabPurchase Invoice` t1,`tabPurchase Invoice Item` t2 where t1.name = t2.parent and t2.purchase_order = '%s' and t1.docstatus = 1" % self.doc.name)
+ submitted = webnotes.conn.sql("select t1.name from `tabPurchase Invoice` t1,`tabPurchase Invoice Item` t2 where t1.name = t2.parent and t2.purchase_order = '%s' and t1.docstatus = 1" % self.doc.name)
if submitted:
msgprint("Purchase Invoice : " + cstr(submitted[0][0]) + " has already been submitted !")
raise Exception
@@ -186,9 +180,6 @@ class DocType(BuyingController):
def on_update(self):
pass
- def get_rate(self,arg):
- return get_obj('Purchase Common').get_rate(arg,self)
-
@webnotes.whitelist()
def make_purchase_receipt(source_name, target_doclist=None):
from webnotes.model.mapper import get_mapped_doclist
diff --git a/buying/doctype/purchase_order/purchase_order.txt b/buying/doctype/purchase_order/purchase_order.txt
index d3c1620b51d..7169aaf3906 100644
--- a/buying/doctype/purchase_order/purchase_order.txt
+++ b/buying/doctype/purchase_order/purchase_order.txt
@@ -2,12 +2,13 @@
{
"creation": "2013-05-21 16:16:39",
"docstatus": 0,
- "modified": "2013-09-12 18:34:54",
+ "modified": "2013-10-02 14:24:49",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"allow_attach": 1,
+ "allow_import": 1,
"autoname": "naming_series:",
"doctype": "DocType",
"document_type": "Transaction",
@@ -132,7 +133,6 @@
"fieldtype": "Date",
"in_filter": 1,
"label": "Purchase Order Date",
- "no_copy": 1,
"oldfieldname": "transaction_date",
"oldfieldtype": "Date",
"reqd": 1,
diff --git a/buying/doctype/purchase_order/test_purchase_order.py b/buying/doctype/purchase_order/test_purchase_order.py
index cef5e4a207b..bd5f410f6e1 100644
--- a/buying/doctype/purchase_order/test_purchase_order.py
+++ b/buying/doctype/purchase_order/test_purchase_order.py
@@ -98,11 +98,11 @@ class TestPurchaseOrder(unittest.TestCase):
self.assertEquals(len(po.doclist.get({"parentfield": "po_raw_material_details"})), 2)
def test_warehouse_company_validation(self):
- from controllers.buying_controller import WrongWarehouseCompany
+ from stock.utils import InvalidWarehouseCompany
po = webnotes.bean(copy=test_records[0])
po.doc.company = "_Test Company 1"
po.doc.conversion_rate = 0.0167
- self.assertRaises(WrongWarehouseCompany, po.insert)
+ self.assertRaises(InvalidWarehouseCompany, po.insert)
def test_uom_integer_validation(self):
from utilities.transaction_base import UOMMustBeIntegerError
diff --git a/buying/doctype/purchase_order_item/purchase_order_item.txt b/buying/doctype/purchase_order_item/purchase_order_item.txt
index 36b81d2c1fc..fade98fa980 100755
--- a/buying/doctype/purchase_order_item/purchase_order_item.txt
+++ b/buying/doctype/purchase_order_item/purchase_order_item.txt
@@ -2,7 +2,7 @@
{
"creation": "2013-05-24 19:29:06",
"docstatus": 0,
- "modified": "2013-08-07 14:44:12",
+ "modified": "2013-10-10 17:01:57",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -306,21 +306,6 @@
"search_index": 1,
"width": "120px"
},
- {
- "doctype": "DocField",
- "fieldname": "prevdoc_date",
- "fieldtype": "Date",
- "hidden": 1,
- "in_filter": 1,
- "in_list_view": 0,
- "label": "Material Request Date",
- "no_copy": 1,
- "oldfieldname": "prevdoc_date",
- "oldfieldtype": "Date",
- "print_hide": 1,
- "read_only": 1,
- "search_index": 0
- },
{
"doctype": "DocField",
"fieldname": "prevdoc_detail_docname",
diff --git a/buying/doctype/supplier/supplier.py b/buying/doctype/supplier/supplier.py
index 15e1d625f9a..3c0163367be 100644
--- a/buying/doctype/supplier/supplier.py
+++ b/buying/doctype/supplier/supplier.py
@@ -9,7 +9,6 @@ from webnotes.utils import cint
from webnotes import msgprint, _
from webnotes.model.doc import make_autoname
-sql = webnotes.conn.sql
from utilities.transaction_base import TransactionBase
@@ -29,7 +28,7 @@ class DocType(TransactionBase):
self.doc.name = make_autoname(self.doc.naming_series + '.#####')
def update_credit_days_limit(self):
- sql("""update tabAccount set credit_days = %s where name = %s""",
+ webnotes.conn.sql("""update tabAccount set credit_days = %s where name = %s""",
(cint(self.doc.credit_days), self.doc.name + " - " + self.get_company_abbr()))
def on_update(self):
@@ -43,7 +42,7 @@ class DocType(TransactionBase):
self.update_credit_days_limit()
def get_payables_group(self):
- g = sql("select payables_group from tabCompany where name=%s", self.doc.company)
+ g = webnotes.conn.sql("select payables_group from tabCompany where name=%s", self.doc.company)
g = g and g[0][0] or ''
if not g:
msgprint("Update Company master, assign a default group for Payables")
@@ -65,14 +64,14 @@ class DocType(TransactionBase):
msgprint(_("Created Group ") + ac)
def get_company_abbr(self):
- return sql("select abbr from tabCompany where name=%s", self.doc.company)[0][0]
+ return webnotes.conn.sql("select abbr from tabCompany where name=%s", self.doc.company)[0][0]
def get_parent_account(self, abbr):
if (not self.doc.supplier_type):
msgprint("Supplier Type is mandatory")
raise Exception
- if not sql("select name from tabAccount where name=%s and debit_or_credit = 'Credit' and ifnull(is_pl_account, 'No') = 'No'", (self.doc.supplier_type + " - " + abbr)):
+ if not webnotes.conn.sql("select name from tabAccount where name=%s and debit_or_credit = 'Credit' and ifnull(is_pl_account, 'No') = 'No'", (self.doc.supplier_type + " - " + abbr)):
# if not group created , create it
self.add_account(self.doc.supplier_type, self.get_payables_group(), abbr)
@@ -90,7 +89,7 @@ class DocType(TransactionBase):
abbr = self.get_company_abbr()
parent_account = self.get_parent_account(abbr)
- if not sql("select name from tabAccount where name=%s", (self.doc.name + " - " + abbr)):
+ if not webnotes.conn.sql("select name from tabAccount where name=%s", (self.doc.name + " - " + abbr)):
ac_bean = webnotes.bean({
"doctype": "Account",
'account_name': self.doc.name,
@@ -121,15 +120,15 @@ class DocType(TransactionBase):
def get_contacts(self,nm):
if nm:
- contact_details =webnotes.conn.convert_to_lists(sql("select name, CONCAT(IFNULL(first_name,''),' ',IFNULL(last_name,'')),contact_no,email_id from `tabContact` where supplier = '%s'"%nm))
+ contact_details =webnotes.conn.convert_to_lists(webnotes.conn.sql("select name, CONCAT(IFNULL(first_name,''),' ',IFNULL(last_name,'')),contact_no,email_id from `tabContact` where supplier = '%s'"%nm))
return contact_details
else:
return ''
def delete_supplier_address(self):
- for rec in sql("select * from `tabAddress` where supplier=%s", (self.doc.name,), as_dict=1):
- sql("delete from `tabAddress` where name=%s",(rec['name']))
+ for rec in webnotes.conn.sql("select * from `tabAddress` where supplier=%s", (self.doc.name,), as_dict=1):
+ webnotes.conn.sql("delete from `tabAddress` where name=%s",(rec['name']))
def delete_supplier_contact(self):
for contact in webnotes.conn.sql_list("""select name from `tabContact`
@@ -138,7 +137,7 @@ class DocType(TransactionBase):
def delete_supplier_account(self):
"""delete supplier's ledger if exist and check balance before deletion"""
- acc = sql("select name from `tabAccount` where master_type = 'Supplier' \
+ acc = webnotes.conn.sql("select name from `tabAccount` where master_type = 'Supplier' \
and master_name = %s and docstatus < 2", self.doc.name)
if acc:
from webnotes.model import delete_doc
@@ -161,7 +160,7 @@ class DocType(TransactionBase):
('Purchase Receipt', 'supplier'),
('Serial No', 'supplier')]
for rec in update_fields:
- sql("update `tab%s` set supplier_name = %s where `%s` = %s" % \
+ webnotes.conn.sql("update `tab%s` set supplier_name = %s where `%s` = %s" % \
(rec[0], '%s', rec[1], '%s'), (new, old))
for account in webnotes.conn.sql("""select name, account_name from
diff --git a/buying/doctype/supplier_quotation/supplier_quotation.js b/buying/doctype/supplier_quotation/supplier_quotation.js
index ccb903e5999..4e017828019 100644
--- a/buying/doctype/supplier_quotation/supplier_quotation.js
+++ b/buying/doctype/supplier_quotation/supplier_quotation.js
@@ -9,6 +9,7 @@ cur_frm.cscript.other_fname = "purchase_tax_details";
// attach required files
wn.require('app/accounts/doctype/purchase_taxes_and_charges_master/purchase_taxes_and_charges_master.js');
wn.require('app/buying/doctype/purchase_common/purchase_common.js');
+wn.require('app/accounts/doctype/sales_invoice/pos.js');
erpnext.buying.SupplierQuotationController = erpnext.buying.BuyingController.extend({
refresh: function() {
diff --git a/buying/doctype/supplier_quotation/supplier_quotation.py b/buying/doctype/supplier_quotation/supplier_quotation.py
index c3d2f78451a..8c5224e30ac 100644
--- a/buying/doctype/supplier_quotation/supplier_quotation.py
+++ b/buying/doctype/supplier_quotation/supplier_quotation.py
@@ -54,7 +54,6 @@ class DocType(BuyingController):
def validate_common(self):
pc = get_obj('Purchase Common')
pc.validate_for_items(self)
- pc.get_prevdoc_date(self)
@webnotes.whitelist()
def make_purchase_order(source_name, target_doclist=None):
diff --git a/buying/doctype/supplier_quotation/supplier_quotation.txt b/buying/doctype/supplier_quotation/supplier_quotation.txt
index 36747d345a8..ddd17307dcf 100644
--- a/buying/doctype/supplier_quotation/supplier_quotation.txt
+++ b/buying/doctype/supplier_quotation/supplier_quotation.txt
@@ -2,12 +2,13 @@
{
"creation": "2013-05-21 16:16:45",
"docstatus": 0,
- "modified": "2013-08-09 14:45:58",
+ "modified": "2013-10-02 14:24:44",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"allow_attach": 1,
+ "allow_import": 1,
"autoname": "naming_series:",
"doctype": "DocType",
"document_type": "Transaction",
diff --git a/buying/doctype/supplier_quotation_item/supplier_quotation_item.txt b/buying/doctype/supplier_quotation_item/supplier_quotation_item.txt
index 1d162915ef4..515cdb2a34f 100644
--- a/buying/doctype/supplier_quotation_item/supplier_quotation_item.txt
+++ b/buying/doctype/supplier_quotation_item/supplier_quotation_item.txt
@@ -2,7 +2,7 @@
{
"creation": "2013-05-22 12:43:10",
"docstatus": 0,
- "modified": "2013-08-07 14:44:18",
+ "modified": "2013-10-10 17:02:11",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -259,21 +259,6 @@
"search_index": 1,
"width": "120px"
},
- {
- "doctype": "DocField",
- "fieldname": "prevdoc_date",
- "fieldtype": "Date",
- "hidden": 1,
- "in_filter": 1,
- "in_list_view": 0,
- "label": "Material Request Date",
- "no_copy": 1,
- "oldfieldname": "prevdoc_date",
- "oldfieldtype": "Date",
- "print_hide": 1,
- "read_only": 1,
- "search_index": 0
- },
{
"doctype": "DocField",
"fieldname": "prevdoc_detail_docname",
diff --git a/buying/page/buying_home/buying_home.js b/buying/page/buying_home/buying_home.js
index 1e08a3bbf33..f41f619b644 100644
--- a/buying/page/buying_home/buying_home.js
+++ b/buying/page/buying_home/buying_home.js
@@ -145,6 +145,11 @@ wn.module_page["Buying"] = [
route: "query-report/Purchase Order Trends",
doctype: "Purchase Order"
},
+ {
+ "label":wn._("Supplier Addresses And Contacts"),
+ route: "query-report/Supplier Addresses and Contacts",
+ doctype: "Supplier"
+ },
]
}
]
diff --git a/buying/report/supplier_addresses_and_contacts/__init__.py b/buying/report/supplier_addresses_and_contacts/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/buying/report/supplier_addresses_and_contacts/supplier_addresses_and_contacts.txt b/buying/report/supplier_addresses_and_contacts/supplier_addresses_and_contacts.txt
new file mode 100644
index 00000000000..fac1e9e929c
--- /dev/null
+++ b/buying/report/supplier_addresses_and_contacts/supplier_addresses_and_contacts.txt
@@ -0,0 +1,22 @@
+[
+ {
+ "creation": "2013-10-09 10:38:40",
+ "docstatus": 0,
+ "modified": "2013-10-09 10:53:52",
+ "modified_by": "Administrator",
+ "owner": "Administrator"
+ },
+ {
+ "doctype": "Report",
+ "is_standard": "Yes",
+ "name": "__common__",
+ "query": "SELECT\n `tabSupplier`.name as \"Supplier:Link/Supplier:120\",\n\t`tabSupplier`.supplier_name as \"Supplier Name::120\",\n\t`tabSupplier`.supplier_type as \"Supplier Type:Link/Supplier Type:120\",\n\tconcat_ws(', ', \n\t\ttrim(',' from `tabAddress`.address_line1), \n\t\ttrim(',' from tabAddress.address_line2), \n\t\ttabAddress.state, tabAddress.pincode, tabAddress.country\n\t) as 'Address::180',\n concat_ws(', ', `tabContact`.first_name, `tabContact`.last_name) as 'Contact Name::180',\n\t`tabContact`.phone as \"Phone\",\n\t`tabContact`.mobile_no as \"Mobile No\",\n\t`tabContact`.email_id as \"Email Id::120\",\n\t`tabContact`.is_primary_contact as \"Is Primary Contact::120\"\nFROM\n\t`tabSupplier`\n\tleft join `tabAddress` on (\n\t\t`tabAddress`.supplier=`tabSupplier`.name\n\t)\n\tleft join `tabContact` on (\n\t\t`tabContact`.supplier=`tabSupplier`.name\n\t)\nWHERE\n\t`tabSupplier`.docstatus<2\nORDER BY\n\t`tabSupplier`.name asc",
+ "ref_doctype": "Supplier",
+ "report_name": "Supplier Addresses and Contacts",
+ "report_type": "Query Report"
+ },
+ {
+ "doctype": "Report",
+ "name": "Supplier Addresses and Contacts"
+ }
+]
\ No newline at end of file
diff --git a/buying/utils.py b/buying/utils.py
index ce81b6bd67b..115b023962e 100644
--- a/buying/utils.py
+++ b/buying/utils.py
@@ -65,7 +65,7 @@ def _get_basic_details(args, item_bean):
out = webnotes._dict({
"description": item.description_html or item.description,
- "qty": 0.0,
+ "qty": 1.0,
"uom": item.stock_uom,
"conversion_factor": 1.0,
"warehouse": args.warehouse or item.default_warehouse,
diff --git a/controllers/accounts_controller.py b/controllers/accounts_controller.py
index 927b24980ff..5121d69f6a5 100644
--- a/controllers/accounts_controller.py
+++ b/controllers/accounts_controller.py
@@ -52,7 +52,7 @@ class AccountsController(TransactionBase):
msgprint(_("Account for this ") + fieldname + _(" has been freezed. ") +
self.doc.doctype + _(" can not be made."), raise_exception=1)
- def set_price_list_currency(self, buying_or_selling):
+ def set_price_list_currency(self, buying_or_selling, for_validate=False):
if self.meta.get_field("currency"):
company_currency = get_company_currency(self.doc.company)
@@ -60,14 +60,13 @@ class AccountsController(TransactionBase):
fieldname = "selling_price_list" if buying_or_selling.lower() == "selling" \
else "buying_price_list"
if self.meta.get_field(fieldname) and self.doc.fields.get(fieldname):
- if not self.doc.price_list_currency:
- self.doc.price_list_currency = webnotes.conn.get_value("Price List",
- self.doc.fields.get(fieldname), "currency")
+ self.doc.price_list_currency = webnotes.conn.get_value("Price List",
+ self.doc.fields.get(fieldname), "currency")
if self.doc.price_list_currency == company_currency:
self.doc.plc_conversion_rate = 1.0
- elif not self.doc.plc_conversion_rate:
+ elif not self.doc.plc_conversion_rate or not for_validate:
self.doc.plc_conversion_rate = self.get_exchange_rate(
self.doc.price_list_currency, company_currency)
@@ -77,7 +76,7 @@ class AccountsController(TransactionBase):
self.doc.conversion_rate = self.doc.plc_conversion_rate
elif self.doc.currency == company_currency:
self.doc.conversion_rate = 1.0
- elif not self.doc.conversion_rate:
+ elif not self.doc.conversion_rate or not for_validate:
self.doc.conversion_rate = self.get_exchange_rate(self.doc.currency,
company_currency)
@@ -423,3 +422,7 @@ class AccountsController(TransactionBase):
self._abbr = webnotes.conn.get_value("Company", self.doc.company, "abbr")
return self._abbr
+
+@webnotes.whitelist()
+def get_tax_rate(account_head):
+ return webnotes.conn.get_value("Account", account_head, "tax_rate")
diff --git a/controllers/buying_controller.py b/controllers/buying_controller.py
index 7e49e60f8a1..5176b1612a7 100644
--- a/controllers/buying_controller.py
+++ b/controllers/buying_controller.py
@@ -2,7 +2,7 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import webnotes
+import webnotes, json
from webnotes import _, msgprint
from webnotes.utils import flt, _round
@@ -11,9 +11,8 @@ from setup.utils import get_company_currency
from controllers.stock_controller import StockController
-class WrongWarehouseCompany(Exception): pass
-
class BuyingController(StockController):
+
def onload_post_render(self):
# contact, address, item details
self.set_missing_values()
@@ -24,13 +23,13 @@ class BuyingController(StockController):
self.doc.supplier_name = webnotes.conn.get_value("Supplier",
self.doc.supplier, "supplier_name")
self.validate_stock_or_nonstock_items()
- self.validate_warehouse_belongs_to_company()
+ self.validate_warehouse()
def set_missing_values(self, for_validate=False):
super(BuyingController, self).set_missing_values(for_validate)
self.set_supplier_from_item_default()
- self.set_price_list_currency("Buying")
+ self.set_price_list_currency("Buying", for_validate)
# set contact and address details for supplier, if they are not mentioned
if self.doc.supplier and not (self.doc.contact_person and self.doc.supplier_address):
@@ -49,17 +48,20 @@ class BuyingController(StockController):
if supplier:
self.doc.supplier = supplier
break
+
+ def validate_warehouse(self):
+ from stock.utils import validate_warehouse_user, validate_warehouse_company
+
+ warehouses = list(set([d.warehouse for d in
+ self.doclist.get({"doctype": self.tname}) if d.warehouse]))
+
+ for w in warehouses:
+ validate_warehouse_user(w)
+ validate_warehouse_company(w, self.doc.company)
def get_purchase_tax_details(self):
self.doclist = self.doc.clear_table(self.doclist, "purchase_tax_details")
self.set_taxes("purchase_tax_details", "purchase_other_charges")
-
- def validate_warehouse_belongs_to_company(self):
- for warehouse, company in webnotes.conn.get_values("Warehouse",
- self.doclist.get_distinct_values("warehouse"), "company").items():
- if company and company != self.doc.company:
- webnotes.msgprint(_("Company mismatch for Warehouse") + (": %s" % (warehouse,)),
- raise_exception=WrongWarehouseCompany)
def validate_stock_or_nonstock_items(self):
if not self.get_stock_items():
diff --git a/controllers/selling_controller.py b/controllers/selling_controller.py
index f1117ed177b..5c7b66c82ec 100644
--- a/controllers/selling_controller.py
+++ b/controllers/selling_controller.py
@@ -14,13 +14,16 @@ class SellingController(StockController):
def onload_post_render(self):
# contact, address, item details and pos details (if applicable)
self.set_missing_values()
-
+
+ def get_sender(self, comm):
+ return webnotes.conn.get_value('Sales Email Settings', None, 'email_id')
+
def set_missing_values(self, for_validate=False):
super(SellingController, self).set_missing_values(for_validate)
# set contact and address details for customer, if they are not mentioned
self.set_missing_lead_customer_details()
- self.set_price_list_and_item_details()
+ self.set_price_list_and_item_details(for_validate)
if self.doc.fields.get("__islocal"):
self.set_taxes("other_charges", "charge")
@@ -38,8 +41,8 @@ class SellingController(StockController):
if not self.doc.fields.get(fieldname) and self.meta.get_field(fieldname):
self.doc.fields[fieldname] = val
- def set_price_list_and_item_details(self):
- self.set_price_list_currency("Selling")
+ def set_price_list_and_item_details(self, for_validate=False):
+ self.set_price_list_currency("Selling", for_validate)
self.set_missing_item_details(get_item_details)
def get_other_charges(self):
@@ -233,34 +236,4 @@ class SellingController(StockController):
self.doc.order_type = "Sales"
elif self.doc.order_type not in valid_types:
msgprint(_(self.meta.get_label("order_type")) + " " +
- _("must be one of") + ": " + comma_or(valid_types),
- raise_exception=True)
-
- def update_serial_nos(self, cancel=False):
- from stock.doctype.stock_ledger_entry.stock_ledger_entry import update_serial_nos_after_submit, get_serial_nos
- update_serial_nos_after_submit(self, self.doc.doctype, self.fname)
- update_serial_nos_after_submit(self, self.doc.doctype, "packing_details")
-
- for table_fieldname in (self.fname, "packing_details"):
- for d in self.doclist.get({"parentfield": table_fieldname}):
- for serial_no in get_serial_nos(d.serial_no):
- sr = webnotes.bean("Serial No", serial_no)
- if cancel:
- sr.doc.status = "Available"
- for fieldname in ("warranty_expiry_date", "delivery_document_type",
- "delivery_document_no", "delivery_date", "delivery_time", "customer",
- "customer_name"):
- sr.doc.fields[fieldname] = None
- else:
- sr.doc.delivery_document_type = self.doc.doctype
- sr.doc.delivery_document_no = self.doc.name
- sr.doc.delivery_date = self.doc.posting_date
- sr.doc.delivery_time = self.doc.posting_time
- sr.doc.customer = self.doc.customer
- sr.doc.customer_name = self.doc.customer_name
- if sr.doc.warranty_period:
- sr.doc.warranty_expiry_date = add_days(cstr(self.doc.posting_date),
- cint(sr.doc.warranty_period))
- sr.doc.status = 'Delivered'
-
- sr.save()
+ _("must be one of") + ": " + comma_or(valid_types), raise_exception=True)
diff --git a/controllers/status_updater.py b/controllers/status_updater.py
index 070f2002764..b2a0e17a258 100644
--- a/controllers/status_updater.py
+++ b/controllers/status_updater.py
@@ -8,6 +8,51 @@ from webnotes import msgprint
from webnotes.model.controller import DocListController
+status_map = {
+ "Contact": [
+ ["Replied", "communication_sent"],
+ ["Open", "communication_received"]
+ ],
+ "Job Applicant": [
+ ["Replied", "communication_sent"],
+ ["Open", "communication_received"]
+ ],
+ "Lead": [
+ ["Replied", "communication_sent"],
+ ["Converted", "has_customer"],
+ ["Opportunity", "has_opportunity"],
+ ["Open", "communication_received"],
+ ],
+ "Opportunity": [
+ ["Draft", None],
+ ["Submitted", "eval:self.doc.docstatus==1"],
+ ["Lost", "eval:self.doc.status=='Lost'"],
+ ["Quotation", "has_quotation"],
+ ["Replied", "communication_sent"],
+ ["Cancelled", "eval:self.doc.docstatus==2"],
+ ["Open", "communication_received"],
+ ],
+ "Quotation": [
+ ["Draft", None],
+ ["Submitted", "eval:self.doc.docstatus==1"],
+ ["Lost", "eval:self.doc.status=='Lost'"],
+ ["Ordered", "has_sales_order"],
+ ["Replied", "communication_sent"],
+ ["Cancelled", "eval:self.doc.docstatus==2"],
+ ["Open", "communication_received"],
+ ],
+ "Sales Order": [
+ ["Draft", None],
+ ["Submitted", "eval:self.doc.docstatus==1"],
+ ["Stopped", "eval:self.doc.status=='Stopped'"],
+ ["Cancelled", "eval:self.doc.docstatus==2"],
+ ],
+ "Support Ticket": [
+ ["Replied", "communication_sent"],
+ ["Open", "communication_received"]
+ ],
+}
+
class StatusUpdater(DocListController):
"""
Updates the status of the calling records
@@ -20,6 +65,45 @@ class StatusUpdater(DocListController):
self.update_qty()
self.validate_qty()
+ def set_status(self, update=False):
+ if self.doc.get("__islocal"):
+ return
+
+ if self.doc.doctype in status_map:
+ sl = status_map[self.doc.doctype][:]
+ sl.reverse()
+ for s in sl:
+ if not s[1]:
+ self.doc.status = s[0]
+ break
+ elif s[1].startswith("eval:"):
+ if eval(s[1][5:]):
+ self.doc.status = s[0]
+ break
+ elif getattr(self, s[1])():
+ self.doc.status = s[0]
+ break
+
+ if update:
+ webnotes.conn.set_value(self.doc.doctype, self.doc.name, "status", self.doc.status)
+
+ def on_communication(self):
+ self.communication_set = True
+ self.set_status(update=True)
+ del self.communication_set
+
+ def communication_received(self):
+ if getattr(self, "communication_set", False):
+ last_comm = self.doclist.get({"doctype":"Communication"})
+ if last_comm:
+ return last_comm[-1].sent_or_received == "Received"
+
+ def communication_sent(self):
+ if getattr(self, "communication_set", False):
+ last_comm = self.doclist.get({"doctype":"Communication"})
+ if last_comm:
+ return last_comm[-1].sent_or_received == "Sent"
+
def validate_qty(self):
"""
Validates qty at row level
diff --git a/docs/user/accounts/docs.user.accounts.pos.md b/docs/user/accounts/docs.user.accounts.pos.md
index 654a5d6dfab..7bd668ef720 100644
--- a/docs/user/accounts/docs.user.accounts.pos.md
+++ b/docs/user/accounts/docs.user.accounts.pos.md
@@ -13,33 +13,34 @@ You can make a Sales Invoice of type POS by checking on “Is POS”. When you c
- Update Stock: If this is checked, Stock Ledger Entries will be made when you “Submit” this Sales Invoice thereby eliminating the need for a separate Delivery Note.
- In your Items table, update inventory information like Warehouse (saved as default), Serial Number, or Batch Number if applicable.
-- Update Payment Details like your Bank / Cash Account, paid amount etc.
+- Update Payment Details like your Bank / Cash Account, Paid amount etc.
- If you are writing off certain amount. For example when you receive extra cash as a result of not having exact denomination of change, check on ‘Write off Outstanding Amount’ and set the Account.
-Setup [POS Setting](docs.user.setup.pos_setting.html)
#### Enable POS View
-Sales Invoice has 2 different interfaces, Invoice View and POS View. The current view used by most users is the Invoice View. This view is preferred by non-retailing companies.The POS view is used by retailing companies. For retailers it is very important to provide bill or sales invoice at the point of sale. Their customers cannot wait to receive the bill by post. The customers want an immediate bill for the payment which they make. In such cases, the POS View is preferred.
+- Every Sales & Purchase documents has 2 different interfaces, Invoice View and POS View. The current view used by most users is the Invoice View. This view is preferred by non-retailing companies.The POS view is used by retailing companies. For retailers it is very important to provide bill or sales invoice at the point of sale. Their customers cannot wait to receive the bill by post. The customers want an immediate bill for the payment which they make. In such cases, the POS View is preferred.
> Setup > Show/Hide Features

+- Setup [POS Setting](docs.user.setup.pos_setting.html)
+
### Adding an Item
-At the billing counter, the retailer needs to select Items which the consumer buys. In the POS interface you can select an Item by two methods. One, is by clicking on the Item image and the other, is through the Barcode.
+At the billing counter, the retailer needs to select Items which the consumer buys. In the POS interface you can select an Item by two methods. One, is by clicking on the Item image and the other, is through the Barcode / Serial No.
**Select Item** - To select a product click on the Item image and add it into the cart. A cart is an area that prepares a customer for checkout by allowing to edit product information, adjust taxes and add discounts.
-**Barcode** - A Barcode is an optical machine-readable representation of data relating to the object to which it is attached. Enter Barcode in the barcode box and pause for a second. The Item will be automatically added to the cart.
+**Barcode / Serial No** - A Barcode / Serial No is an optical machine-readable representation of data relating to the object to which it is attached. Enter Barcode / Serial No in the box as shown in the image below and pause for a second, the item will be automatically added to the cart.

> Tip: To change the quantity of an Item, enter your desired quantity in the quantity box. These are mostly used if the same Item is purchased in bulk.
-If your product list is very long use the universal search field, to type the product name and select faster.
+If your product list is very long use the Search field, type the product name in Search box.
### Removing an Item
@@ -48,7 +49,7 @@ There are two ways to remove an Item.
- Select an Item by clicking on the row of that Item from Item cart. Then click on “Del” button. OR
-- Type 0 in the ‘select quantity’ field to delete the record.
+- Enter 0(zero) quantity of any item to delete that item.
To remove multiple Items together, select multiple rows & click on “Del” button.
@@ -62,11 +63,11 @@ After all the Items and their quantities are added into the cart, you are ready
1. Click on “Make Payment” to get the Payment window.
1. Select your “Mode of Payment”.
-1. Click on “Pay” button to Save the Sales Invoice.
+1. Click on “Pay” button to Save the document.

-Submit the document to finalise the record. After the Invoice is submitted, you can either print an invoice or email it directly to the customer.
+Submit the document to finalise the record. After the document is submitted, you can either print or email it directly to the customer.
#### Accounting entries (GL Entry) for a Point of Sale:
diff --git a/docs/user/buying/docs.user.buying.supplier.md b/docs/user/buying/docs.user.buying.supplier.md
index e477fa2beda..3707fbe8523 100644
--- a/docs/user/buying/docs.user.buying.supplier.md
+++ b/docs/user/buying/docs.user.buying.supplier.md
@@ -20,7 +20,15 @@ You can create a new Supplier via:
> Tip: When you select a Supplier in any transaction, one Contact and Address gets pre-selected. This is the “Default Contact or Address”. So make sure you set your defaults correctly!
+### Integration with Accounts
+In ERPNext, there is a separate Account record for each Supplier, of Each company.
+
+When you create a new Supplier, ERPNext will automatically create an Account Ledger for the Supplier under “Accounts Receivable” in the Company set in the Supplier record.
+
+> Advanced Tip: If you want to change the Account Group under which the Supplier Account is created, you can set it in the Company master.
+
+If you want to create an Account in another Company, just change the Company value and “Save” the Supplier again.
> Buying > Contact > New Contact
diff --git a/docs/user/buying/docs.user.buying.supplier_type.md b/docs/user/buying/docs.user.buying.supplier_type.md
index deaf01fcfcd..3871991d638 100644
--- a/docs/user/buying/docs.user.buying.supplier_type.md
+++ b/docs/user/buying/docs.user.buying.supplier_type.md
@@ -3,9 +3,11 @@
"_label": "Supplier Type"
}
---
+A supplier may be distinguished from a contractor or subcontractor, who commonly adds specialized input to deliverables. A supplier is also known as a vendor. There are different types of suppliers based on their goods and products.
-Based on what the suppliers supply, they are classified into different categories called Supplier Type.
-There can be different types of suppliers. You can create your own category of Supplier Type.
+ERPNext allows you to create your own categories of suppliers. These categories are known as Supplier Type. For Example, if your suppliers are mainly pharmaceutical companies and FMCG distributors, You can create a new Type for them and name them accordingly.
+
+Based on what the suppliers supply, they are classified into different categories called Supplier Type. There can be different types of suppliers. You can create your own category of Supplier Type.
> Buying > Supplier Type > New Supplier Type
diff --git a/docs/user/docs.user.md b/docs/user/docs.user.md
index d9e7f2aac00..5c6588272e3 100644
--- a/docs/user/docs.user.md
+++ b/docs/user/docs.user.md
@@ -3,6 +3,7 @@
"_label": "User Guide",
"_toc": [
"docs.user.intro",
+ "docs.user.five_day_setup",
"docs.user.implement",
"docs.user.setup",
"docs.user.selling",
@@ -17,7 +18,7 @@
"docs.user.tools",
"docs.user.customize",
"docs.user.knowledge"
- ],
+ ],
"_no_toc": 1
}
---
@@ -29,6 +30,12 @@ Contents
1. [Open Source](docs.user.intro.open_source.html)
1. [Ways to get started](docs.user.intro.try.html)
1. [Getting Help](docs.user.help.html)
+1. [Five-Day-Setup](docs.user.five_day_setup.html)
+ 1. [Day-1: Setup Customer,Item, and Supplier](docs.user.five_day_setup.day_1.html)
+ 1. [Day-2: Setup Chart of Accounts, Opening Accounts, and HR](docs.user.five_day_setup.day_2.html)
+ 1. [Day-3: Sales Cycle and Purchase Cycle](docs.user.five_day_setup.day_3.html)
+ 1. [Day-4: Manufacturing Cycle and Accounting Reports](docs.user.five_day_setup.day_4.html)
+ 1. [Day-5: Projects, Calendar, and Website](docs.user.five_day_setup.day_5.html)
1. [Implementation](docs.user.implement.html)
1. [Implementation Strategy](docs.user.implement.strategy.html)
1. [Concepts](docs.user.implement.concepts.html)
@@ -151,3 +158,6 @@ Contents
1. [Fiscal Year](docs.user.knowledge.fiscal_year.html)
1. [Accounting Knowledge](docs.user.knowledge.accounting.html)
1. [Accounting Entries](docs.user.knowledge.accounting_entries.html)
+ 1. [DocType Definitions](docs.user.knowledge.doctype.html)
+ 1. [Attachment and CSV Files](docs.user.knowledge.attachment_csv.html)
+ 1. [Format using Markdown](docs.user.knowledge.markdown.html)
diff --git a/docs/user/five_day_setup/docs.user.five_day_setup.day_1.md b/docs/user/five_day_setup/docs.user.five_day_setup.day_1.md
new file mode 100644
index 00000000000..bbb8b86e34d
--- /dev/null
+++ b/docs/user/five_day_setup/docs.user.five_day_setup.day_1.md
@@ -0,0 +1,81 @@
+---
+{
+ "_label": "Day-1: Setup Customer, Item, and Supplier"
+}
+---
+Login to your ERPNext account with the User ID and Password sent through the mail.
+
+After logging into your account you will receive a pop-up form to fill. Please fill this form. Select the abbreviation you would wish to have for your company. The abbreviation selected here will be used in naming most of the business documents.
+
+#### Form Part I
+
+
+
+#### Form Part II
+To understand about Company Financial Year or Fiscal Year visit [Fiscal Year](docs.user.knowledge.fiscal_year.html)
+
+
+
+
+After filling this form, you will get a pop-up message for completing the set-up process. Click on the Setup button. The Setup page will appear.
+
+
+#### Setup Page - Customer
+
+The Organisation details are updated in ERPNext, after filling the first form. Go directly to the Customer Icon.
+
+
+
+
+
+After clicking on Customer, a new form will appear.
+
+
+
+
+To see how customer details are added, visit [Customer](docs.user.selling.customer.html). Create 5 new customer records in the system.
+
+Now proceed to make an Item. To go to the main menu, click on erpnext icon which is on the left hand corner of the page. On the main menu page, click on Setup
+
+
+
+
+
+#### Setup Page - Item
+
+On the setup page go to Item.
+
+
+
+
+
+Create a new Item. An Item is your company's product or a service.The term Item is applicable to your core products as well as your raw materials. It can be a product or service that you buy/sell from your customers/ suppliers.
+
+Filling Item details is an important step in ERPNext. Do not postpone this step. After clicking on Item, make a new Item.
+
+
+
+To understand how to fill an Item in detail, visit [Item](docs.user.stock.item.html). Add 5 item records to ERPnext. After adding these records, go back to the Setup Page and add Suppliers.
+
+
+#### Setup Page - Suppliers
+On the Setup page go to Supplier.
+
+
+
+
+Suppliers are companies or individuals who provide you with products or services. They are treated in exactly the same manner as Customers in ERPNext. Create a new Supplier record.
+
+
+
+
+To understand how to fill Supplier details, visit [Supplier](docs.user.buying.supplier.html).
+
+If you wish to import your list of customers and suppliers directly to ERPNext, you can do that via the Data Import Tool.
+
+To upload Customers or suppliers in bulk, go to the Data Import Tool.
+
+> Note: The data import format is case-sensitive. The file will not be processed if there are any spelling mistakes or deviations from the default values.
+
+To understand how to import data, visit [Importing Data](docs.user.setup.data_import.html).
+
diff --git a/docs/user/five_day_setup/docs.user.five_day_setup.day_2.md b/docs/user/five_day_setup/docs.user.five_day_setup.day_2.md
new file mode 100644
index 00000000000..f01662319b3
--- /dev/null
+++ b/docs/user/five_day_setup/docs.user.five_day_setup.day_2.md
@@ -0,0 +1,54 @@
+---
+{
+ "_label": "Day-2: Setup Chart of Accounts, Opening Accounts, and HR"
+}
+---
+
+#### Setup Page - Accounts
+
+Go to the Accounts icon and make ledgers under Chart of Accounts.
+
+
+
+
+
+
+Create acccounting ledgers.
+
+
+
+
+
+To begin Opening Entries, go to 'Opening Accounts and Stock' on the Setup Page.
+
+
+
+
+
+
+To understand how to create opening entries in detail visit [Opening Entry](docs.user.setup.opening.html).
+
+
+
+#### Opening Stock
+
+You can upload your opening stock in the system using Stock Reconciliation. Stock Reconciliation will update your stock for any given Item.
+
+
+
+
+
+To understand Stock Opening in detail visit [Opening Stock](docs.user.accounts.opening_stock.html).
+
+
+
+#### Setup Page - HR Setup
+
+To setup HR, begin by creating individual employee records.
+
+
+
+
+To fill the Employee Form, refer to [Employee](docs.user.hr.employee.html)
+
+To complete the remaining HR-Setup, see [Human Resources](docs.user.hr.html)
\ No newline at end of file
diff --git a/docs/user/five_day_setup/docs.user.five_day_setup.day_3.md b/docs/user/five_day_setup/docs.user.five_day_setup.day_3.md
new file mode 100644
index 00000000000..e0c4114c06d
--- /dev/null
+++ b/docs/user/five_day_setup/docs.user.five_day_setup.day_3.md
@@ -0,0 +1,139 @@
+---
+{
+ "_label": "Day-3: Sales Cycle and Purchase Cycle"
+}
+---
+After completing the set-up and account opening process, it is advisable to complete a few cycles of sales, purchase, and manufacturing process.
+
+
+### Sales Cycle
+
+Complete a standard Sales Cycle.
+> Lead > Opportunity > Quotation > Sales Order > Delivery Note > Sales Invoice > Payment (Journal Voucher)
+
+
+#### Lead
+
+To begin the sales cycle, go to the Selling Icon. On the selling page, click on Lead.
+
+
+
+Fill the Lead form.
+
+> To understand Lead in detail, visit [Lead](docs.user.selling.lead.html)
+
+
+#### Opportunity
+
+After completing the Lead form, assume that, this same lead is getting converted into an Opportunity. Thus, to create an Opportunity from the existing lead, click on Create Opportunity, on the Lead page.
+
+##### Step 1: Go to 'Lead List' Page and open the Lead that shows interested status.
+
+
+
+
+
+##### Step 2: Generate Opportunity from the selected Lead
+
+
+
+You can also generate an Opportunity directly from the Selling Page.
+
+> To understand Opportunity in detail visit [Opportunity](docs.user.selling.opportunity.html).
+
+
+#### Quotation
+
+Imagine that your Opportunity has shown interest and asked for a Quotation. To generate a Quotation from the same Opportunity, open the submitted Opportunity and click on Create Quotation.
+
+
+
+You can also generate a Quotation directly from the Selling Page.
+
+> To understand Quotation in detail visit [Quotation](docs.user.selling.quotation.html)
+
+
+#### Sales Order
+
+Imagine that the Quotation which you sent was accepted by the prospect. You are now reequired to send him a Sales Order. To make a sales order from this same Quotation, go to that Quotation page and click on Make Sales Order.
+
+
+
+You can also generate a Sales Order directly from the Selling Page.
+
+> To understand Sales Order in detail visit [Sales Order](docs.user.selling.sales_order.html).
+
+
+#### Delivery Note
+
+If your organisation has the practice of sending Delivery Note, this section will be helpful. To create a Delivery Note from the a Sales Order, go to that Sales Order and click on Make Delivery.
+
+
+
+
+> To understand Delivery Note in detail, visit [Delivery Note](docs.user.stock.delivery_note.html)
+
+
+#### Sales Invoice
+
+Save and Submit your Delivery Note to generate a Sales Invoice. You can also generate an Invoice from Sales Order.
+
+
+
+
+
+#### Payment (Journal Voucher)
+
+
+A Journal Voucher or a payment entry can be generated directly from the Sales Invoice.
+
+
+
+> To understand a Journal Voucher in detail, visit [Journal Voucher](docs.user.accounts.journal_voucher.html)
+
+
+
+### Purchase Cycle
+
+Complete a standard Purchase Cycle.
+> Material Request > Purchase Order > Purchase Receipt > Payment (Journal Voucher).
+
+
+#### Material Request
+
+To create a Material Request, go to Stock/Buying and Click on Material Request.
+
+
+
+> To understand Material Request in detail, visit [Material Request](docs.user.buying.material_request.html)
+
+
+#### Purchase Order
+
+To create a Purchase Order go to Buying and click on Purchase Order
+
+
+
+> To understand Purchase Order in detail, visit [Purchase Order](docs.user.buying.purchase_order.html)
+
+
+#### Purchase Receipt
+
+To create a Purchase Receipt from an existing Purchase Order, open that purchase order and click on Make Purchase Receipt.
+
+
+
+
+>To understand Purchase Receipt in detail, visit [Purchase Receipt](docs.user.stock.purchase_receipt.html)
+
+
+
+#### Payment (Journal Voucher)
+
+Payments made against Sales Invoices or Purchase Invoices can be made by clicking on “Make Payment Entry” button on “Submitted” invoices.
+
+
+
+
+
+> To understand Payment Entry in detail, visit [Payment Entry](docs.user.accounts.payments.html).
diff --git a/docs/user/five_day_setup/docs.user.five_day_setup.day_4.md b/docs/user/five_day_setup/docs.user.five_day_setup.day_4.md
new file mode 100644
index 00000000000..af6e6365542
--- /dev/null
+++ b/docs/user/five_day_setup/docs.user.five_day_setup.day_4.md
@@ -0,0 +1,86 @@
+---
+{
+ "_label": "Day-4: Manufacturing Cycle and Accounting Reports"
+}
+---
+
+### Manufacturing Cycle
+
+Complete a manufacturing cycle (if applicable).
+> BOM > Production Planning Tool > Production Order > Stock Entry (Material Issue) > Stock Entry (Sales Return)
+
+
+#### Bill of Materials
+
+To go to Bill of Materials, Click on Manufacturing. On the Manufacturing page, click on Bill of Materials.
+
+
+
+> To understand BOM in detail, visit [Bill of Materials](docs.user.mfg.bom.html)
+
+
+#### Production Planning Tool
+
+To go to Production Planning Tool, click on the Manufacturing Icon. On the Manufacturing Page, click on Production Planning Tool to go to that page.
+
+
+
+> To understand Production Planning Tool in detail, visit [Production Planning](docs.user.mfg.planning.html)
+
+
+#### Production Order
+
+To go to Production Order click on the Manufacturing Icon. On the Manufacturing Page, click on Production Order.
+
+
+
+> To understand Production Order in detail, visit [Production Order](docs.user.mfg.production_order.html)
+
+
+#### Stock Entry
+
+To go to Stock Entry, click on the Stock Icon and go to Stock Entry.
+
+
+
+> To understand Material Issue, visit [Material Issue](docs.user.stock.material_issue.html).
+
+> To understand Sales Return, visit [Sales Return](docs.user.stock.sales_return.html).
+
+
+#### Delivery Note
+
+To go to Delivery Note, click on Stock. On the Stock Page, click on Delivery Note.
+
+
+
+> To understand Delivery Note in detail, visit [Delivery Note](docs.user.stock.delivery_note.html)
+
+
+#### Warehouse
+
+To go to Warehouse, Click on Stock. On the Stock Page, go to Warehouse.
+
+
+
+> To understand Warehouse in detail, visit [Warehouse](docs.user.stock.warehouse.html)
+
+
+#### Accounts
+
+Make a few Journal Vouchers. Generate some Accounting Reports.
+
+#### Journal Voucher
+
+To go to a Journal Voucher, click on Accounts. On the Accounts page, click on Journal Voucher.
+
+
+
+> To understand Journal Voucher in detail, visit [Journal Voucher](docs.user.accounts.journal_voucher.html)
+
+
+### Accounting Reports
+
+Some of the major Accounting Reports are General Ledger, Trial Balance, Accounts Payable and Accounts Receivables, and Sales and Purchase Register.
+
+> To be able to generate these accounts, visti [Accounting Reports](docs.user.accounts.report.html)
diff --git a/docs/user/five_day_setup/docs.user.five_day_setup.day_5.md b/docs/user/five_day_setup/docs.user.five_day_setup.day_5.md
new file mode 100644
index 00000000000..db386a0a3e5
--- /dev/null
+++ b/docs/user/five_day_setup/docs.user.five_day_setup.day_5.md
@@ -0,0 +1,32 @@
+---
+{
+ "_label": "Day-5: Projects, Calendar, and Website"
+}
+---
+
+#### Projects
+
+ERPNext helps you to manage your Projects by breaking them into Tasks and allocating them to different people.
+
+
+#### Tasks
+
+Project is divided into Tasks and each Task is allocated to a resource. In ERPNext, you can also create and allocate a Task independently of a Project.
+
+To create a Task, go to Project and click on Task.
+
+
+
+> To understand Projects in detail, visit [Projects](docs.user.projects.html).
+
+> To understand Task in detail, visit [Tasks](docs.user.projects.tasks.html)
+
+
+#### Calendar
+
+> To understand Calendar in detail, visit [Calendar](docs.user.tools.calendar.html)
+
+
+#### Website
+
+> To understand Website in detail, visit [Website](docs.user.website.html)
diff --git a/docs/user/five_day_setup/docs.user.five_day_setup.md b/docs/user/five_day_setup/docs.user.five_day_setup.md
new file mode 100644
index 00000000000..90aeb56c22b
--- /dev/null
+++ b/docs/user/five_day_setup/docs.user.five_day_setup.md
@@ -0,0 +1,48 @@
+---
+{
+ "_label": "Five-Day Setup",
+ "_toc": [
+ "docs.user.five_day_setup.day_1",
+ "docs.user.five_day_setup.day_2",
+ "docs.user.five_day_setup.day_3",
+ "docs.user.five_day_setup.day_4",
+ "docs.user.five_day_setup.day_5"
+
+ ]
+}
+---
+Welcome to ERPNext. To be able to setup ERPNext account successfully, a five-day-setup process is recommended. Perform the 5-days-setup instructions and sail through the ERPNext implementation.
+
+The setup help is divided into day-wise instructions for 5 consecutive days.
+
+#### Day 1
+
+- Company Setup
+- Customer Setup
+- Item Setup
+- Supplier Setup
+- Data Import Tool
+
+#### Day 2
+
+- Opening Accounts
+- Opening Stock
+- HR Setup
+
+#### Day 3
+
+- Sales Cycle
+- Purchase Cycle
+
+
+#### Day 4
+
+- Manufacturing Cycle
+- Delivery Note and Warehouse
+- Accounts
+
+#### Day 5
+
+- Projects
+- Calendar
+- Website
\ No newline at end of file
diff --git a/docs/user/intro/docs.user.implement.strategy.md b/docs/user/intro/docs.user.implement.strategy.md
index 9ec58e8874c..e077a90e562 100644
--- a/docs/user/intro/docs.user.implement.strategy.md
+++ b/docs/user/intro/docs.user.implement.strategy.md
@@ -10,11 +10,12 @@ Before you start managing your Operations in EPRNext, you must first become fami
### Test Phase
- Read the Manual
+- Follow the Five-Day-Setup Module or the instructions given below.
- Create your first Customer, Supplier and Item. Add a few more so you get familiar with them.
- Create Customer Groups, Item Groups, Warehouses, Supplier Groups, so that you can classify your Items.
- Complete a standard sales cycle - Lead > Opportunity > Quotation > Sales Order > Delivery Note > Sales Invoice > Payment (Journal Voucher)
-- Complete a standard purchase cycle - Purchase Request > Purchase Order > Purchase Receipt > Payment (Journal Voucher).
-- Complete a manufacturing cycle (if applicable) - BOM > Production Planning Tool > Production Order > Stock Entry (issue) > Stock Entry (back-flush)
+- Complete a standard purchase cycle - Material Request > Purchase Order > Purchase Receipt > Payment (Journal Voucher).
+- Complete a manufacturing cycle (if applicable) - BOM > Production Planning Tool > Production Order > Material Issue > Sales Return
> Tip: Use the 30-day free trial at [erpnext.com](https://erpnext.com) to take your test drive.
diff --git a/docs/user/knowledge/docs.user.knowledge.accounting.md b/docs/user/knowledge/docs.user.knowledge.accounting.md
index 17304984cb0..995d38cfe97 100644
--- a/docs/user/knowledge/docs.user.knowledge.accounting.md
+++ b/docs/user/knowledge/docs.user.knowledge.accounting.md
@@ -22,34 +22,34 @@ Accounting Entries
The balance of account can be increased / decreased, depending on account type and transaction type.
-
+
-
Account Type
-
Transaction Type
-
Effect on account balance
+
Account Type
+
Transaction Type
+
Effect on account balance
-
Debit
-
Debit
-
Increases
+
Debit
+
Debit
+
Increases
-
Debit
-
Credit
-
Decreases
+
Debit
+
Credit
+
Decreases
-
Credit
-
Credit
-
Increases
+
Credit
+
Credit
+
Increases
-
Credit
-
Debit
-
Decreases
+
Credit
+
Debit
+
Decreases
@@ -62,48 +62,48 @@ This means that every accounting entry has two parts, one debit and one credit a
As the company will receive a payment from customer, the customer is considered as an asset account. For booking income, company maintains an account called "Sales of Laptop". So, entries will be done in the following manner:
-
+
-
Account
-
Debit
-
Credit
+
Account
+
Debit
+
Credit
-
Customer A
-
50000
-
+
Customer A
+
50000
+
-
Sales of Laptop
-
-
50000
+
Sales of Laptop
+
+
50000
Customer A has made the payment, so customer balance should decreased based on the paid amount, which will increase "Cash" balance.
-
+
-
Account
-
Debit
-
Credit
+
Account
+
Debit
+
Credit
-
Customer A
-
-
50000
+
Customer A
+
+
50000
-
Cash
-
50000
-
+
Cash
+
50000
+
diff --git a/docs/user/knowledge/docs.user.knowledge.attachment_csv.md b/docs/user/knowledge/docs.user.knowledge.attachment_csv.md
new file mode 100644
index 00000000000..eecc42ddcf9
--- /dev/null
+++ b/docs/user/knowledge/docs.user.knowledge.attachment_csv.md
@@ -0,0 +1,16 @@
+---
+{
+ "_label": "Attachment and CSV files"
+}
+---
+
+#### How to Attach files?
+
+When you open a form, on the right sidebar, you will see a section to attach files. Click on “Add” and select the file you want to attach. Click on “Upload” and you are set.
+
+#### What is a CSV file?
+
+A CSV (Comma Separated Value) file is a data file that you can upload into ERPNext to update various data. Any spreadsheet file from popular spreadsheet applications like MS Excel or Open Office Spreadsheet can be saved as a CSV file.
+
+If you are using Microsoft Excel and using non-English characters, make sure to save your file encoded as UTF-8. For older versions of Excel, there is no clear way of saving as UTF-8. So save your file as a CSV, then open it in Notepad, and save as “UTF-8”. (Sorry blame Microsoft for this!)
+
diff --git a/docs/user/knowledge/docs.user.knowledge.doctype.md b/docs/user/knowledge/docs.user.knowledge.doctype.md
new file mode 100644
index 00000000000..a2550d4f95f
--- /dev/null
+++ b/docs/user/knowledge/docs.user.knowledge.doctype.md
@@ -0,0 +1,267 @@
+---
+{
+ "_label": "DocType"
+}
+---
+
+
+
+ERPNext is a based on a “metadata” (data about data) framework that helps define all the different types of documents in the system. The basic building block of ERPNext is a DocType.
+
+A DocType represents both a table in the database and a form from which a user can enter data.
+
+Many DocTypes are single tables, but some work in groups. For example, Quotation has a “Quotation” DocType and a “Quotation Item” doctype for the Items table, among others. DocTypes contain a collection of fields called DocFields that form the basis of the columns in the database and the layout of the form.
+
+
+
+
+
Column
+
Description
+
+
+
+
+
Name
+
Name of the record
+
+
+
+
Owner
+
Creator and Owner of the record
+
+
+
+
Created on
+
Date and Time of Creation
+
+
+
+
Modified On
+
Date and Time of Modification
+
+
+
Docstatus
+
Status of the record
+ 0 = Saved/Draft
+ 1 = Submitted
+ 2 = Cancelled/Deleted
+
+
+
+
Parent
+
Name of the Parent
+
+
+
Parent Type
+
Type of Parent
+
+
+
Parent Field
+
Specifying the relationship with the parent (there can be multiple child relationships with the same DocType).
+
+
+
Index(idx)
+
Index (sequence) of the record in the child table.
+
+
+
+
+
+#### Single DocType
+
+There are a certain type of DocTypes that are “Single”, i.e. they have no table associated and have only one record of its fields. DocTypes such as Global Defaults, Production Planning Tool are “Single” DocTypes.
+
+#### Field Columns
+
+In the fields table, there are many columns, here is an explanation of the columns of the field table.
+
+
+
+
+
Column
+
Description
+
+
+
+
+
Label
+
Field Label (that appears in the form).
+
+
+
Type
+
Field Type
+
+
+
Name
+
Column name in the database, must be code friendly with no white spaces, special characters and capital letters.
+
+
+
options
+
Field settings:
+ For Select: List of options (each on a new line).
+ For Link: DocType that is “linked”.
+ For HTML: HTML Content
+
+
+
Perm Level
+
Permission level (number) of the field. You can group fields by numbers, called levels, and apply rules on the levels.
+
+
+
Width
+
Width of the field (in pixels) - useful for “Table” types.
+
+
+
Reqd
+
Checked if field is mandatory (required).
+
+
+
In Filter
+
Checked if field appears as a standard filter in old style reports.
+
+
+
Hidden
+
Checked if field is hidden.
+
+
+
Print Hide
+
Checked if field is hidden in Print Formats.
+
+
+
Report Hide
+
Checked if field is hidden in old style reports.
+
+
+
Allow on Submit
+
Checked if this field can be edited after the document is “Submitted”.
+
+
+
Depends On
+
The fieldname of the field that will decide whether this field will be shown or hidden. It is useful to hide un-necessary fields.
+
+
+
Description
+
Description of the field
+
+
+
Default
+
Default value when a new record is created.
+ Note: “user” will set the current user as default and “today” will set today’s date (if the field is a Date field).
+
+
+
+
+#### Field Types and Options
+
+Here is a list of the different types of fields used to make / customize forms in ERPNext.
+
+
+
+
+
Type
+
Description
+
Options/Setting
+
+
+
+
+
Data
+
Single line text field with 180 characters
+
+
+
+
Select
+
Select from a pre-determined items in a drop-down.
+
The “Options” contains the drop-down items, each on a new row
+
+
+
Link
+
Link an existing document / record
+
Options contains the name of the type of document (DocType)
+
+
+
Currency
+
Number with 2 decimal places, that will be shown separated by commas for thousands etc. in Print.
+
e.g. 1,000,000.00
+
+
+
Float
+
Number with 6 decimal places.
+
e.g. 3.141593
+
+
+
Int
+
Integer (no decimals)
+
e.g. 100
+
+
+
Date
+
Date
+
Format can be selected in Global Defaults
+
+
+
Time
+
Time
+
+
+
+
Text
+
+
+
Text
+
Multi-line text box without formatting features
+
+
+
+
Text editor
+
Multi-line text box with formatting toolbar etc
+
+
+
+
Code
+
Code Editor
+
Options can include the type of language for syntax formatting.
+ Eg JS / Python / HTML
+
+
+
Table (Grid)
+
+
+
Table
+
Table of child items linked to the record.
+
Options contains the name of the DocType of the child table. For example “Sales Invoice Item” for “Sales Invoice”
+
+
+
Layout
+
+
+
Section Break
+
Break into a new horizontal section.
+
The layout in ERPNext is evaluated from top to bottom.
+
+
+
Column Break
+
Break into a new vertical column.
+
+
+
+
HTML
+
Add a static text / help / link etc in HTML
+
Options contains the HTML.
+
+
+
Action
+
+
+
Button
+
Button
+
[for developers only]
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/user/knowledge/docs.user.knowledge.markdown.md b/docs/user/knowledge/docs.user.knowledge.markdown.md
new file mode 100644
index 00000000000..b2f76be5831
--- /dev/null
+++ b/docs/user/knowledge/docs.user.knowledge.markdown.md
@@ -0,0 +1,84 @@
+---
+{
+ "_label": "Format Using Markdown"
+}
+---
+
+Markdown is a simple way of writing text to format your content. Markdown allows you easy ways to format.
+
+1. Headings (h1 (largest), h2, h3, h4 and so on)
+1. Paragraphs
+1. Lists (numbered or bulleted)
+1. Hyper links (links to other pages)
+1. Images
+1. Code
+1. Embed HTML (HTML tags within your text)
+
+#### Headings
+
+Headings are specified by adding a `#` (hash) at the beginning of the line. The more the number of hashes, the smaller the heading:
+
+ # This is a large heading.
+
+ ### This is a smaller heading.
+
+#### Paragraphs
+
+To start a new paragraph, just make sure that there is an empty line at the beginning and end of the paragraph.
+
+To format text as **bold** or with _italics_ format as follows:
+
+ **This text** is **bold** and _this one_ is with _italics_
+
+#### Lists
+
+To define numbered lists, start your link with a number and a dot (.) and ensure there is a blank line before and after the list. The numbers are automatically generated so it does not matter what number you put:
+
+ 1. list 1st item
+ 1. second item
+ 1. and so on
+ 1. and so forth
+
+To define bulleted lists, start your items with a hyphen (-)
+
+ - item 1
+ - item 2
+ - item 3
+
+To nest lists within one another, put four spaces to indent your inner list as follows:
+
+ 1. item 1
+ 1. item 2
+ - sub item 1
+ - sub item 2
+ 1. item 3
+
+#### Links (to other pages)
+
+Links to other pages can be defined by adding your text in box brackets [] followed by the link in round brackets ()
+
+ [This is an external link](http://example.com)
+ [A link within the site](my-page.html)
+
+#### Images
+
+Images can be added by adding an exclamation ! before the link.
+
+ 
+
+
+#### Code
+
+To add a code block, just leave a blank line before and after the block and make sure all code line are indented by four spaces:
+
+ This is normal text
+
+ This is a code block
+
+#### HTML
+
+You can embed any kind of HTML tags within your code. Any content written within HTML tags will not be formatted.
+
+[Detailed description of the markdown format](http://daringfireball.net/projects/markdown/syntax)
+
+
diff --git a/docs/user/knowledge/docs.user.knowledge.md b/docs/user/knowledge/docs.user.knowledge.md
index 5d98cdd4596..11dc9957ac1 100644
--- a/docs/user/knowledge/docs.user.knowledge.md
+++ b/docs/user/knowledge/docs.user.knowledge.md
@@ -4,8 +4,12 @@
"_toc": [
"docs.user.knowledge.fiscal_year",
"docs.user.knowledge.accounting",
- "docs.user.knowledge.accounting_entries"
+ "docs.user.knowledge.accounting_entries",
+ "docs.user.knowledge.doctype",
+ "docs.user.knowledge.attachment_csv",
+ "docs.user.knowledge.markdown"
]
}
---
-Knowledge Library contains definitions and explanations of various management concepts. This page is created for users who wish to elaborate their conceptual knowledge.
\ No newline at end of file
+Knowledge Library contains definitions and explanations of various management concepts. This page is created for users who wish to elaborate their conceptual knowledge.
+
diff --git a/docs/user/selling/docs.user.selling.customer.md b/docs/user/selling/docs.user.selling.customer.md
index 108f20da831..5336ac61a11 100644
--- a/docs/user/selling/docs.user.selling.customer.md
+++ b/docs/user/selling/docs.user.selling.customer.md
@@ -4,7 +4,9 @@
"_title_image": "img/customers.png"
}
---
-You can either directly create your Customers via
+A customer, who is sometimes known as a client, buyer, or purchaser is the one who receives goods, services, products, or ideas, from a seller for a monetary consideration. A customer can also receive goods or services from a vendor or a supplier for other valuable considerations.
+
+ You can either directly create your Customers via
> Selling > Customer
diff --git a/docs/user/setup/docs.user.setup.cost_centers.md b/docs/user/setup/docs.user.setup.cost_centers.md
index 3df26e16a0b..d666e4157f1 100644
--- a/docs/user/setup/docs.user.setup.cost_centers.md
+++ b/docs/user/setup/docs.user.setup.cost_centers.md
@@ -45,6 +45,14 @@ ERPNext will help you set and manage budgets on your Cost Centers. This is usefu
Budgets are also great for planning purposes. When you are making plans for the next financial year, you would typically target a revenue based on which you would set your expenses. Setting a budget will ensure that your expenses do not get out of hand, at any point, as per your plans.
You can define it in the Cost Center. If you have seasonal sales you can also define a budget distribution that the budget will follow.
+
+> Accounts > Budget Distribution > New Budget Distribution
+
+
+
+
+
+

#### Budget Actions
diff --git a/docs/user/setup/docs.user.setup.data_import.md b/docs/user/setup/docs.user.setup.data_import.md
index eec6b65e453..b40573ed43a 100644
--- a/docs/user/setup/docs.user.setup.data_import.md
+++ b/docs/user/setup/docs.user.setup.data_import.md
@@ -3,7 +3,7 @@
"_label": "Data Import Tool"
}
---
-The Data Import Tool is a great way to upload (or edit) bulk data, specially master data, into the system. To start the tool go to:
+The Data Import Tool is a great way to upload (or edit) bulk data, specially master data, into the system.
To Open the data import tool, you either go to Setup or go to the Transaction you want to Import. If Data Import is allowed, you will see an Import Button:
@@ -15,7 +15,7 @@ The tool has two sections, one to download a template and the second to upload t
### 1. Downloading The Template
-Data in ERPNext is stored in tables, much like a spreadsheet with columns and rows of data. Each entity in ERPNext can have multiple child tables associated with it too. The child tables are linked to the parent tables and are implemented where are multiple values for any property. For example an Item can have multiple prices, An Invoice has multiple Items and so on.
+Data in ERPNext is stored in tables, much like a spreadsheet with columns and rows of data. Each entity in ERPNext can have multiple child tables associated with it too. The child tables are linked to the parent tables and are implemented where there are multiple values for any property. For example an Item can have multiple prices, An Invoice has multiple Items and so on.
You can import each table separately, or all at a time. In the child table, you must mention the parent of the row in the “parent” column so that ERPNext knows which Item’s price or tax you are trying to set if you are importing separately.
@@ -36,7 +36,7 @@ Then export your template or save it as a **Comma Separated Values** (CSV) file.
### 3. Upload the .csv File
-Finally attach the .csv file in the section section click on the "Upload and Import" button.
+Finally attach the .csv file in the section. Click on the "Upload and Import" button.

diff --git a/docs/user/setup/docs.user.setup.md b/docs/user/setup/docs.user.setup.md
index fa9680a0629..585811f66eb 100644
--- a/docs/user/setup/docs.user.setup.md
+++ b/docs/user/setup/docs.user.setup.md
@@ -18,7 +18,7 @@
"docs.user.setup.email",
"docs.user.setup.sms",
"docs.user.setup.taxes",
- "docs.user.setup.price_lists",
+ "docs.user.setup.price_list",
"docs.user.setup.opening",
"docs.user.setup.pos_setting",
"docs.user.setup.third_party_backups"
diff --git a/docs/user/setup/docs.user.setup.price_list.md b/docs/user/setup/docs.user.setup.price_list.md
index 021df090419..7214fff5143 100644
--- a/docs/user/setup/docs.user.setup.price_list.md
+++ b/docs/user/setup/docs.user.setup.price_list.md
@@ -7,7 +7,7 @@ A Price List is a place where different rate plans can be stored. It’s a name
An Item can have multiple prices based on customer, currency, region, shipping cost etc, which can be stored as different rate plans. In ERPNext, you are required to store all the lists seperately. Buying Price List is different from Selling Price List and thus is stored separately.
-> Selling > Price List
+> Setup > Price List

@@ -15,7 +15,14 @@ An Item can have multiple prices based on customer, currency, region, shipping c
> For multiple currencies, maintain multiple Price Lists.
+
+### Add Item in Price List
-To add a new Item to the Price List, add the Item Code and its rate in the Item Prices table.
+> Setup > Item Price
-You can also import Item Prices via [Data Import Tool](docs.user.setup.data_import.html)
\ No newline at end of file
+- Enter Price List and Item Code, Valid for Buying or Selling, Item Name & Item Description will be automatically fetched.
+- Enter Rate and save the document.
+
+
+
+For bulk upload of Item Prices, use [Data Import Tool](docs.user.setup.data_import.html)
\ No newline at end of file
diff --git a/docs/user/setup/docs.user.setup.users.md b/docs/user/setup/docs.user.setup.users.md
index 82d79d3d093..06ac9108ec2 100644
--- a/docs/user/setup/docs.user.setup.users.md
+++ b/docs/user/setup/docs.user.setup.users.md
@@ -6,7 +6,7 @@
ERPNext has a role-based permission system, which means that you can assign Roles to Users, and permissions on Roles.Each ERPNext user has a Profile. The Profile contains the user’s email and authentication and can be set from:
-> Setup > Users and Permissions > Users
+> Setup > Profile
#### Step 1: Adding a new User
diff --git a/docs/user/stock/docs.user.stock.item.md b/docs/user/stock/docs.user.stock.item.md
index c98afd29dd8..f7746c48423 100644
--- a/docs/user/stock/docs.user.stock.item.md
+++ b/docs/user/stock/docs.user.stock.item.md
@@ -15,7 +15,7 @@ ERPNext is optimized for itemized management of your sales and purchase. If you
- **Item Name:** Item name is the actual name of your product or service.
- **Item Code:** Item Code is a short-form to denote your Item. If you have very few Items, it is advisable to keep the Item Name and the Item Code same. This helps new users to recognise and update Item details in all transactions. In case you have lot of Items with long names and the list runs in hundreds, it is advisable to code. To understand naming Item codes see [Item Codification](docs.user.setup.codification.html)
-- **Item Group:** Item Group is used to categorize an Item under various criterias like products, raw materials, services, sub-assemblies, consumables or all Item groups. Create your default Item Group list under Setup> Item Group and pre-select the option while filling your New Item details under Item Group.
+- **Item Group:** Item Group is used to categorize an Item under various criterias like products, raw materials, services, sub-assemblies, consumables or all Item groups. Create your default Item Group list under Setup> Item Group and pre-select the option while filling your New Item details under [Item Group](docs.user.stock.item_group.html)
- **Default Unit of Measure:** This is the default measuring unit that you will use for your product. It could be in nos, kgs, meters, etc. You can store all the UOM’s that your product will require under Set Up> Master Data > UOM. These can be preselected while filling New Item by using % sign to get a pop up of the UOM list.
- **Brand:** If you have more than one brand save them under Set Up> Master Data> Brand and pre-select them while filling a New Item.
@@ -27,11 +27,7 @@ To upload an image for your icon that will appear in all transactions, save the

-### Item Pricing
-
-Item Price and Price Lists: ERPNext lets you maintain multiple selling prices for an Item using Price Lists. A Price List is a place where different rate plans can be stored. It’s a name you can give to a set of Item prices. In case you have different zones (based on the shipping costs), for different currencies etc, you can maintain different Price Lists. A Price List is formed when you create different Item Prices. To import Item Price see [Importing Data](docs.user.data_import.md).
-
-## Inventory : Warehouse and Stock Setting
+### Inventory : Warehouse and Stock Setting
In ERPNext, you can select different type of Warehouses to stock your different Items. This can be selected based on Item types. It could be Fixed Asset Item, Stock Item or even Manufacturing Item.
@@ -95,3 +91,59 @@ Inspection Criteria: If a Quality Inspection is prepared for this Item, then thi
Visit [Manufacturing](docs.user.mfg.html) and [Website](docs.user.website.html) to understand these topics in detail.
+
+### Listing Item on Website
+
+To list your Item on the Website, fill the Item details and save the file. Once the file is saved, a plus (+) button will appear next to the Image icon. Click on the plus button and add your Item image. The html code will be generated automatically.
+
+##### Step 1: Save Image
+
+
+
+
+
+##### Step 2: Check the 'Show in Website' box.
+
+Under the Website section, please check the box that says 'show in Website'. Once the box is checked, the page will display other fields for entering information.
+
+
+
+
+
+
+##### Step 3: Enter Website Details
+
+
+
+
+The page name will be generated automatically. Mention the Item-Group under which the Item will be displayed.
+
+#### Item Groups
+
+Mention the Item Group under this column. If you wish to list your Item under the broad category products, name your Item Group as Products. In case you have various varieties of Item and want to classify them under different names, make Item Groups with those names and check the box that says 'show in Website'. For Example, if you wish to create a category called 'Bags', create a Item Group named Bags.
+
+
+
+
+Once the Item Group is created go to the Website Settings page under Website. Enter the Label, Url, and Parent Label.
+
+
+
+
+
+
+#### Webpage labels
+
+
+
+Add more Items under a particular Item Group.
+
+To add more Items under a certain Label, mention the Item Group on the Item Page. The Items will be added automatically on the Webpage, under the Item Group Label. For Example, To add Item-Kiddies Bag and Butterfly Print Bag, check the 'Show in Website'box. The Items will be placed under the Label Bags on the Webpage.
+
+
+
+
+
+Item Group Display
+
+
\ No newline at end of file
diff --git a/docs/user/website/docs.user.website.blog.md b/docs/user/website/docs.user.website.blog.md
index ec035a03440..b71836e016a 100644
--- a/docs/user/website/docs.user.website.blog.md
+++ b/docs/user/website/docs.user.website.blog.md
@@ -15,6 +15,11 @@ To create a new blog, just create a new Blog from:

-You can format the blog using the same Markdown format
+You can format a blog using the Markdown format.You can also access your blog by going to the page “blog.html”.
+
+
+#### A sample blog-page.
+
+
+
-You can access your blog by going to the page “blog.html”
diff --git a/docs/user/website/docs.user.website.setup.md b/docs/user/website/docs.user.website.setup.md
index 3249637c2d3..4d1d7c7c070 100644
--- a/docs/user/website/docs.user.website.setup.md
+++ b/docs/user/website/docs.user.website.setup.md
@@ -29,11 +29,36 @@ To define the Top Bar Menus, Brand, Footers and Home Page, go to:
> Website > Website Settings
+#### Step 1: Landing Page Details

+#### Step 2: Banner Details
+
+
+
+
+
+#### Step 3: Top Bar Labels
+
+
+
+> Note: Create seperate web pages which will be linked to the main web-icons like company, contact, products etc.
+
+
+#### Step 4: Footer Details
+
+
+
+A website can be generated once all the settings and style requirements are added.
+
+A sample website generated by ERPNext would look like this.
+
+
+
+
#### Top Menu
diff --git a/home/doctype/feed/feed.py b/home/doctype/feed/feed.py
index 25abf5798a0..ebee5c4ce75 100644
--- a/home/doctype/feed/feed.py
+++ b/home/doctype/feed/feed.py
@@ -7,7 +7,6 @@ import webnotes
from webnotes.model import db_exists
from webnotes.model.bean import copy_doclist
-sql = webnotes.conn.sql
diff --git a/hr/doctype/attendance/attendance.py b/hr/doctype/attendance/attendance.py
index 7b82bc524b0..6d52b5723d9 100644
--- a/hr/doctype/attendance/attendance.py
+++ b/hr/doctype/attendance/attendance.py
@@ -7,7 +7,6 @@ import webnotes
from webnotes.utils import getdate, nowdate
from webnotes import msgprint, _
-sql = webnotes.conn.sql
class DocType:
def __init__(self, doc, doclist=[]):
@@ -15,7 +14,7 @@ class DocType:
self.doclist = doclist
def validate_duplicate_record(self):
- res = sql("""select name from `tabAttendance` where employee = %s and att_date = %s
+ res = webnotes.conn.sql("""select name from `tabAttendance` where employee = %s and att_date = %s
and name != %s and docstatus = 1""",
(self.doc.employee, self.doc.att_date, self.doc.name))
if res:
@@ -24,7 +23,7 @@ class DocType:
def check_leave_record(self):
if self.doc.status == 'Present':
- leave = sql("""select name from `tabLeave Application`
+ leave = webnotes.conn.sql("""select name from `tabLeave Application`
where employee = %s and %s between from_date and to_date and status = 'Approved'
and docstatus = 1""", (self.doc.employee, self.doc.att_date))
@@ -42,7 +41,7 @@ class DocType:
msgprint(_("Attendance can not be marked for future dates"), raise_exception=1)
def validate_employee(self):
- emp = sql("select name from `tabEmployee` where name = %s and status = 'Active'",
+ emp = webnotes.conn.sql("select name from `tabEmployee` where name = %s and status = 'Active'",
self.doc.employee)
if not emp:
msgprint(_("Employee: ") + self.doc.employee +
diff --git a/hr/doctype/employee/employee.js b/hr/doctype/employee/employee.js
index cfedfc61112..3814dd9c11f 100644
--- a/hr/doctype/employee/employee.js
+++ b/hr/doctype/employee/employee.js
@@ -4,7 +4,6 @@
wn.provide("erpnext.hr");
erpnext.hr.EmployeeController = wn.ui.form.Controller.extend({
setup: function() {
- this.setup_leave_approver_select();
this.frm.fields_dict.user_id.get_query = function(doc,cdt,cdn) {
return { query:"core.doctype.profile.profile.profile_query"} }
this.frm.fields_dict.reports_to.get_query = function(doc,cdt,cdn) {
@@ -12,6 +11,7 @@ erpnext.hr.EmployeeController = wn.ui.form.Controller.extend({
},
onload: function() {
+ this.setup_leave_approver_select();
this.frm.toggle_display(["esic_card_no", "gratuity_lic_id", "pan_number", "pf_number"],
wn.control_panel.country==="India");
if(this.frm.doc.__islocal) this.frm.set_value("employee_name", "");
diff --git a/hr/doctype/employee/employee.py b/hr/doctype/employee/employee.py
index e28e02d81bb..b46123a6d1f 100644
--- a/hr/doctype/employee/employee.py
+++ b/hr/doctype/employee/employee.py
@@ -4,11 +4,10 @@
from __future__ import unicode_literals
import webnotes
-from webnotes.utils import getdate, validate_email_add, cstr
+from webnotes.utils import getdate, validate_email_add, cstr, cint
from webnotes.model.doc import make_autoname
from webnotes import msgprint, _
-sql = webnotes.conn.sql
class DocType:
def __init__(self,doc,doclist=[]):
@@ -40,12 +39,12 @@ class DocType:
self.validate_email()
self.validate_status()
self.validate_employee_leave_approver()
+ self.update_dob_event()
def on_update(self):
if self.doc.user_id:
self.update_user_default()
self.update_profile()
- self.update_dob_event()
def update_user_default(self):
webnotes.conn.set_default("employee", self.doc.name, self.doc.user_id)
@@ -156,10 +155,11 @@ class DocType:
raise_exception=InvalidLeaveApproverError)
def update_dob_event(self):
- if self.doc.status == "Active" and self.doc.date_of_birth:
+ if self.doc.status == "Active" and self.doc.date_of_birth \
+ and not cint(webnotes.conn.get_value("HR Settings", None, "stop_birthday_reminders")):
birthday_event = webnotes.conn.sql("""select name from `tabEvent` where repeat_on='Every Year'
and ref_type='Employee' and ref_name=%s""", self.doc.name)
-
+
starts_on = self.doc.date_of_birth + " 00:00:00"
ends_on = self.doc.date_of_birth + " 00:15:00"
diff --git a/hr/doctype/employee/employee.txt b/hr/doctype/employee/employee.txt
index bbe87ad8801..4ed873275ab 100644
--- a/hr/doctype/employee/employee.txt
+++ b/hr/doctype/employee/employee.txt
@@ -2,12 +2,13 @@
{
"creation": "2013-03-07 09:04:18",
"docstatus": 0,
- "modified": "2013-08-08 14:22:11",
+ "modified": "2013-10-11 10:52:53",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"allow_attach": 1,
+ "allow_rename": 1,
"autoname": "naming_series:",
"doctype": "DocType",
"document_type": "Master",
diff --git a/hr/doctype/holiday_list/holiday_list.py b/hr/doctype/holiday_list/holiday_list.py
index 81d18f336e1..100c1403fad 100644
--- a/hr/doctype/holiday_list/holiday_list.py
+++ b/hr/doctype/holiday_list/holiday_list.py
@@ -10,7 +10,6 @@ from webnotes.model.doc import addchild, make_autoname
from webnotes.model.bean import copy_doclist
from webnotes import msgprint
-sql = webnotes.conn.sql
import datetime
diff --git a/hr/doctype/hr_settings/hr_settings.py b/hr/doctype/hr_settings/hr_settings.py
index 784339de7db..101905c57b4 100644
--- a/hr/doctype/hr_settings/hr_settings.py
+++ b/hr/doctype/hr_settings/hr_settings.py
@@ -6,6 +6,24 @@
from __future__ import unicode_literals
import webnotes
+from webnotes.utils import cint
+
class DocType:
def __init__(self, d, dl):
- self.doc, self.doclist = d, dl
\ No newline at end of file
+ self.doc, self.doclist = d, dl
+
+ def validate(self):
+ self.original_stop_birthday_reminders = cint(webnotes.conn.get_value("HR Settings",
+ None, "stop_birthday_reminders"))
+
+ def on_update(self):
+ # reset birthday reminders
+ if cint(self.doc.stop_birthday_reminders) != self.original_stop_birthday_reminders:
+ webnotes.conn.sql("""delete from `tabEvent` where repeat_on='Every Year' and ref_type='Employee'""")
+
+ if not self.doc.stop_birthday_reminders:
+ for employee in webnotes.conn.sql_list("""select name from `tabEmployee` where status='Active' and
+ ifnull(date_of_birth, '')!=''"""):
+ webnotes.get_obj("Employee", employee).update_dob_event()
+
+ webnotes.msgprint(webnotes._("Updated Birthday Reminders"))
\ No newline at end of file
diff --git a/hr/doctype/hr_settings/hr_settings.txt b/hr/doctype/hr_settings/hr_settings.txt
index e3694d05727..bf4b0119aaf 100644
--- a/hr/doctype/hr_settings/hr_settings.txt
+++ b/hr/doctype/hr_settings/hr_settings.txt
@@ -2,7 +2,7 @@
{
"creation": "2013-08-02 13:45:23",
"docstatus": 0,
- "modified": "2013-08-02 14:22:26",
+ "modified": "2013-10-02 15:44:38",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -38,6 +38,12 @@
"doctype": "DocType",
"name": "HR Settings"
},
+ {
+ "doctype": "DocField",
+ "fieldname": "employee_settings",
+ "fieldtype": "Section Break",
+ "label": "Employee Settings"
+ },
{
"description": "Employee record is created using selected field. ",
"doctype": "DocField",
@@ -46,6 +52,19 @@
"label": "Employee Records to be created by",
"options": "Naming Series\nEmployee Number"
},
+ {
+ "description": "Don't send Employee Birthday Reminders",
+ "doctype": "DocField",
+ "fieldname": "stop_birthday_reminders",
+ "fieldtype": "Check",
+ "label": "Stop Birthday Reminders"
+ },
+ {
+ "doctype": "DocField",
+ "fieldname": "payroll_settings",
+ "fieldtype": "Section Break",
+ "label": "Payroll Settings"
+ },
{
"description": "If checked, Total no. of Working Days will include holidays, and this will reduce the value of Salary Per Day",
"doctype": "DocField",
diff --git a/hr/doctype/job_applicant/get_job_applications.py b/hr/doctype/job_applicant/get_job_applications.py
index 2e013289159..a9297810193 100644
--- a/hr/doctype/job_applicant/get_job_applications.py
+++ b/hr/doctype/job_applicant/get_job_applications.py
@@ -37,7 +37,7 @@ class JobsMailbox(POP3Mailbox):
mail.save_attachments_in_doc(applicant.doc)
make(content=mail.content, sender=mail.from_email,
- doctype="Job Applicant", name=applicant.doc.name)
+ doctype="Job Applicant", name=applicant.doc.name, sent_or_received="Received")
def get_job_applications():
if cint(webnotes.conn.get_value('Jobs Email Settings', None, 'extract_emails')):
diff --git a/hr/doctype/job_applicant/job_applicant.py b/hr/doctype/job_applicant/job_applicant.py
index 9bf1b967e7d..0ab4ba86128 100644
--- a/hr/doctype/job_applicant/job_applicant.py
+++ b/hr/doctype/job_applicant/job_applicant.py
@@ -11,14 +11,9 @@ from webnotes.utils import extract_email_id
class DocType(TransactionBase):
def __init__(self, d, dl):
self.doc, self.doclist = d, dl
-
+
def get_sender(self, comm):
- return webnotes.conn.get_value('Jobs Email Settings',None,'email_id')
-
- def on_communication(self, comm):
- if webnotes.conn.get_value("Profile", extract_email_id(comm.sender), "user_type")=="System User":
- status = "Replied"
- else:
- status = "Open"
-
- webnotes.conn.set(self.doc, 'status', status)
\ No newline at end of file
+ return webnotes.conn.get_value('Jobs Email Settings',None,'email_id')
+
+ def validate(self):
+ self.set_status()
\ No newline at end of file
diff --git a/hr/doctype/leave_allocation/leave_allocation.py b/hr/doctype/leave_allocation/leave_allocation.py
index 1c856fa3352..a058e1db778 100755
--- a/hr/doctype/leave_allocation/leave_allocation.py
+++ b/hr/doctype/leave_allocation/leave_allocation.py
@@ -5,7 +5,6 @@ from __future__ import unicode_literals
import webnotes
from webnotes.utils import cint, flt
from webnotes import msgprint
-sql = webnotes.conn.sql
class DocType:
def __init__(self, doc, doclist):
@@ -37,7 +36,7 @@ class DocType:
def check_existing_leave_allocation(self):
"""check whether leave for same type is already allocated or not"""
- leave_allocation = sql("""select name from `tabLeave Allocation`
+ leave_allocation = webnotes.conn.sql("""select name from `tabLeave Allocation`
where employee=%s and leave_type=%s and fiscal_year=%s and docstatus=1""",
(self.doc.employee, self.doc.leave_type, self.doc.fiscal_year))
if leave_allocation:
@@ -64,14 +63,14 @@ class DocType:
return self.get_leaves_allocated(prev_fyear) - self.get_leaves_applied(prev_fyear)
def get_leaves_applied(self, fiscal_year):
- leaves_applied = sql("""select SUM(ifnull(total_leave_days, 0))
+ leaves_applied = webnotes.conn.sql("""select SUM(ifnull(total_leave_days, 0))
from `tabLeave Application` where employee=%s and leave_type=%s
and fiscal_year=%s and docstatus=1""",
(self.doc.employee, self.doc.leave_type, fiscal_year))
return leaves_applied and flt(leaves_applied[0][0]) or 0
def get_leaves_allocated(self, fiscal_year):
- leaves_allocated = sql("""select SUM(ifnull(total_leaves_allocated, 0))
+ leaves_allocated = webnotes.conn.sql("""select SUM(ifnull(total_leaves_allocated, 0))
from `tabLeave Allocation` where employee=%s and leave_type=%s
and fiscal_year=%s and docstatus=1 and name!=%s""",
(self.doc.employee, self.doc.leave_type, fiscal_year, self.doc.name))
@@ -79,7 +78,7 @@ class DocType:
def allow_carry_forward(self):
"""check whether carry forward is allowed or not for this leave type"""
- cf = sql("""select is_carry_forward from `tabLeave Type` where name = %s""",
+ cf = webnotes.conn.sql("""select is_carry_forward from `tabLeave Type` where name = %s""",
self.doc.leave_type)
cf = cf and cint(cf[0][0]) or 0
if not cf:
@@ -110,7 +109,7 @@ class DocType:
webnotes.conn.set(self.doc,'total_leaves_allocated',flt(leave_det['total_leaves_allocated']))
def check_for_leave_application(self):
- exists = sql("""select name from `tabLeave Application`
+ exists = webnotes.conn.sql("""select name from `tabLeave Application`
where employee=%s and leave_type=%s and fiscal_year=%s and docstatus=1""",
(self.doc.employee, self.doc.leave_type, self.doc.fiscal_year))
if exists:
diff --git a/hr/doctype/leave_application/test_leave_application.py b/hr/doctype/leave_application/test_leave_application.py
index c89f7c4537c..7a900e3bfee 100644
--- a/hr/doctype/leave_application/test_leave_application.py
+++ b/hr/doctype/leave_application/test_leave_application.py
@@ -7,6 +7,9 @@ import unittest
from hr.doctype.leave_application.leave_application import LeaveDayBlockedError, OverlapError
class TestLeaveApplication(unittest.TestCase):
+ def tearDown(self):
+ webnotes.session.user = "Administrator"
+
def _clear_roles(self):
webnotes.conn.sql("""delete from `tabUserRole` where parent in
("test@example.com", "test1@example.com", "test2@example.com")""")
@@ -15,6 +18,7 @@ class TestLeaveApplication(unittest.TestCase):
webnotes.conn.sql("""delete from `tabLeave Application`""")
def _add_employee_leave_approver(self, employee, leave_approver):
+ temp_session_user = webnotes.session.user
webnotes.session.user = "Administrator"
employee = webnotes.bean("Employee", employee)
employee.doclist.append({
@@ -23,6 +27,7 @@ class TestLeaveApplication(unittest.TestCase):
"leave_approver": leave_approver
})
employee.save()
+ webnotes.session.user = temp_session_user
def get_application(self, doclist):
application = webnotes.bean(copy=doclist)
@@ -31,7 +36,6 @@ class TestLeaveApplication(unittest.TestCase):
return application
def test_block_list(self):
- webnotes.session.user = "Administrator"
self._clear_roles()
from webnotes.profile import add_role
@@ -54,7 +58,6 @@ class TestLeaveApplication(unittest.TestCase):
self.assertTrue(application.insert())
def test_overlap(self):
- webnotes.session.user = "Administrator"
self._clear_roles()
self._clear_applications()
@@ -72,7 +75,6 @@ class TestLeaveApplication(unittest.TestCase):
self.assertRaises(OverlapError, application.insert)
def test_global_block_list(self):
- webnotes.session.user = "Administrator"
self._clear_roles()
from webnotes.profile import add_role
@@ -98,7 +100,6 @@ class TestLeaveApplication(unittest.TestCase):
"applies_to_all_departments", 0)
def test_leave_approval(self):
- webnotes.session.user = "Administrator"
self._clear_roles()
from webnotes.profile import add_role
diff --git a/hr/doctype/leave_block_list/test_leave_block_list.py b/hr/doctype/leave_block_list/test_leave_block_list.py
index e266cd84d67..34814d9380b 100644
--- a/hr/doctype/leave_block_list/test_leave_block_list.py
+++ b/hr/doctype/leave_block_list/test_leave_block_list.py
@@ -7,6 +7,9 @@ import unittest
from hr.doctype.leave_block_list.leave_block_list import get_applicable_block_dates
class TestLeaveBlockList(unittest.TestCase):
+ def tearDown(self):
+ webnotes.session.user = "Administrator"
+
def test_get_applicable_block_dates(self):
webnotes.session.user = "test@example.com"
webnotes.conn.set_value("Department", "_Test Department", "leave_block_list",
diff --git a/hr/doctype/leave_control_panel/leave_control_panel.py b/hr/doctype/leave_control_panel/leave_control_panel.py
index 30b52ba8898..294701c004b 100644
--- a/hr/doctype/leave_control_panel/leave_control_panel.py
+++ b/hr/doctype/leave_control_panel/leave_control_panel.py
@@ -9,7 +9,6 @@ from webnotes.model.doc import Document
from webnotes.model.code import get_obj
from webnotes import msgprint
-sql = webnotes.conn.sql
@@ -34,7 +33,7 @@ class DocType:
emp_query = "select name from `tabEmployee` "
if flag == 1:
emp_query += condition
- e = sql(emp_query)
+ e = webnotes.conn.sql(emp_query)
return e
# ----------------
diff --git a/hr/doctype/salary_manager/salary_manager.py b/hr/doctype/salary_manager/salary_manager.py
index 0eadca14c42..48dcab18084 100644
--- a/hr/doctype/salary_manager/salary_manager.py
+++ b/hr/doctype/salary_manager/salary_manager.py
@@ -11,7 +11,6 @@ from webnotes.model.bean import getlist, copy_doclist
from webnotes.model.code import get_obj
from webnotes import msgprint
-sql = webnotes.conn.sql
@@ -30,7 +29,7 @@ class DocType:
cond = self.get_filter_condition()
cond += self.get_joining_releiving_condition()
- emp_list = sql("""
+ emp_list = webnotes.conn.sql("""
select t1.name
from `tabEmployee` t1, `tabSalary Structure` t2
where t1.docstatus!=2 and t2.docstatus != 2
@@ -68,7 +67,7 @@ class DocType:
def get_month_details(self, year, month):
- ysd = sql("select year_start_date from `tabFiscal Year` where name ='%s'"%year)[0][0]
+ ysd = webnotes.conn.sql("select year_start_date from `tabFiscal Year` where name ='%s'"%year)[0][0]
if ysd:
from dateutil.relativedelta import relativedelta
import calendar, datetime
@@ -96,7 +95,7 @@ class DocType:
emp_list = self.get_emp_list()
ss_list = []
for emp in emp_list:
- if not sql("""select name from `tabSalary Slip`
+ if not webnotes.conn.sql("""select name from `tabSalary Slip`
where docstatus!= 2 and employee = %s and month = %s and fiscal_year = %s and company = %s
""", (emp[0], self.doc.month, self.doc.fiscal_year, self.doc.company)):
ss = webnotes.bean({
@@ -127,7 +126,7 @@ class DocType:
which are not submitted
"""
cond = self.get_filter_condition()
- ss_list = sql("""
+ ss_list = webnotes.conn.sql("""
select t1.name from `tabSalary Slip` t1
where t1.docstatus = 0 and month = '%s' and fiscal_year = '%s' %s
""" % (self.doc.month, self.doc.fiscal_year, cond))
@@ -189,7 +188,7 @@ class DocType:
Get total salary amount from submitted salary slip based on selected criteria
"""
cond = self.get_filter_condition()
- tot = sql("""
+ tot = webnotes.conn.sql("""
select sum(rounded_total) from `tabSalary Slip` t1
where t1.docstatus = 1 and month = '%s' and fiscal_year = '%s' %s
""" % (self.doc.month, self.doc.fiscal_year, cond))
@@ -202,7 +201,7 @@ class DocType:
get default bank account,default salary acount from company
"""
amt = self.get_total_salary()
- com = sql("select default_bank_account from `tabCompany` where name = '%s'" % self.doc.company)
+ com = webnotes.conn.sql("select default_bank_account from `tabCompany` where name = '%s'" % self.doc.company)
if not com[0][0] or not com[0][1]:
msgprint("You can set Default Bank Account in Company master.")
diff --git a/hr/doctype/salary_manager/test_salary_manager.py b/hr/doctype/salary_manager/test_salary_manager.py
index 04000f06701..13815db52be 100644
--- a/hr/doctype/salary_manager/test_salary_manager.py
+++ b/hr/doctype/salary_manager/test_salary_manager.py
@@ -9,7 +9,7 @@ test_records = []
# from webnotes.model.doc import Document
# from webnotes.model.code import get_obj
-# sql = webnotes.conn.sql
+# webnotes.conn.sql = webnotes.conn.sql
#
# class TestSalaryManager(unittest.TestCase):
# def setUp(self):
@@ -20,15 +20,15 @@ test_records = []
# ss1[0].employee = emp1.name
# for s in ss1: s.save(1)
# for s in ss1[1:]:
-# sql("update `tabSalary Structure Earning` set parent = '%s' where name = '%s'" % (ss1[0].name, s.name))
-# sql("update `tabSalary Structure Deduction` set parent = '%s' where name = '%s'" % (ss1[0].name, s.name))
+# webnotes.conn.sql("update `tabSalary Structure Earning` set parent = '%s' where name = '%s'" % (ss1[0].name, s.name))
+# webnotes.conn.sql("update `tabSalary Structure Deduction` set parent = '%s' where name = '%s'" % (ss1[0].name, s.name))
#
#
# ss2[0].employee = emp2.name
# for s in ss2: s.save(1)
# for s in ss2[1:]:
-# sql("update `tabSalary Structure Earning` set parent = '%s' where name = '%s'" % (ss2[0].name, s.name))
-# sql("update `tabSalary Structure Deduction` set parent = '%s' where name = '%s'" % (ss2[0].name, s.name))
+# webnotes.conn.sql("update `tabSalary Structure Earning` set parent = '%s' where name = '%s'" % (ss2[0].name, s.name))
+# webnotes.conn.sql("update `tabSalary Structure Deduction` set parent = '%s' where name = '%s'" % (ss2[0].name, s.name))
#
# sman.save()
# self.sm = get_obj('Salary Manager')
@@ -36,7 +36,7 @@ test_records = []
# self.sm.create_sal_slip()
#
# def test_creation(self):
-# ssid = sql("""
+# ssid = webnotes.conn.sql("""
# select name, department
# from `tabSalary Slip`
# where month = '08' and fiscal_year='2011-2012'""")
@@ -46,7 +46,7 @@ test_records = []
#
#
# def test_lwp_calc(self):
-# ss = sql("""
+# ss = webnotes.conn.sql("""
# select payment_days
# from `tabSalary Slip`
# where month = '08' and fiscal_year='2011-2012' and employee = '%s'
diff --git a/hr/doctype/salary_slip/salary_slip.py b/hr/doctype/salary_slip/salary_slip.py
index 36d7ceba84e..dab026e3645 100644
--- a/hr/doctype/salary_slip/salary_slip.py
+++ b/hr/doctype/salary_slip/salary_slip.py
@@ -11,7 +11,6 @@ from webnotes.model.code import get_obj
from webnotes import msgprint, _
from setup.utils import get_company_currency
-sql = webnotes.conn.sql
from utilities.transaction_base import TransactionBase
@@ -32,7 +31,7 @@ class DocType(TransactionBase):
def check_sal_struct(self):
- struct = sql("select name from `tabSalary Structure` where employee ='%s' and is_active = 'Yes' "%self.doc.employee)
+ struct = webnotes.conn.sql("select name from `tabSalary Structure` where employee ='%s' and is_active = 'Yes' "%self.doc.employee)
if not struct:
msgprint("Please create Salary Structure for employee '%s'"%self.doc.employee)
self.doc.employee = ''
@@ -100,13 +99,13 @@ class DocType(TransactionBase):
return payment_days
def get_holidays_for_employee(self, m):
- holidays = sql("""select t1.holiday_date
+ holidays = webnotes.conn.sql("""select t1.holiday_date
from `tabHoliday` t1, tabEmployee t2
where t1.parent = t2.holiday_list and t2.name = %s
and t1.holiday_date between %s and %s""",
(self.doc.employee, m['month_start_date'], m['month_end_date']))
if not holidays:
- holidays = sql("""select t1.holiday_date
+ holidays = webnotes.conn.sql("""select t1.holiday_date
from `tabHoliday` t1, `tabHoliday List` t2
where t1.parent = t2.name and ifnull(t2.is_default, 0) = 1
and t2.fiscal_year = %s
@@ -120,7 +119,7 @@ class DocType(TransactionBase):
for d in range(m['month_days']):
dt = add_days(cstr(m['month_start_date']), d)
if dt not in holidays:
- leave = sql("""
+ leave = webnotes.conn.sql("""
select t1.name, t1.half_day
from `tabLeave Application` t1, `tabLeave Type` t2
where t2.name = t1.leave_type
@@ -134,7 +133,7 @@ class DocType(TransactionBase):
return lwp
def check_existing(self):
- ret_exist = sql("""select name from `tabSalary Slip`
+ ret_exist = webnotes.conn.sql("""select name from `tabSalary Slip`
where month = %s and fiscal_year = %s and docstatus != 2
and employee = %s and name != %s""",
(self.doc.month, self.doc.fiscal_year, self.doc.employee, self.doc.name))
@@ -201,9 +200,9 @@ class DocType(TransactionBase):
receiver = webnotes.conn.get_value("Employee", self.doc.employee, "company_email")
if receiver:
subj = 'Salary Slip - ' + cstr(self.doc.month) +'/'+cstr(self.doc.fiscal_year)
- earn_ret=sql("""select e_type, e_modified_amount from `tabSalary Slip Earning`
+ earn_ret=webnotes.conn.sql("""select e_type, e_modified_amount from `tabSalary Slip Earning`
where parent = %s""", self.doc.name)
- ded_ret=sql("""select d_type, d_modified_amount from `tabSalary Slip Deduction`
+ ded_ret=webnotes.conn.sql("""select d_type, d_modified_amount from `tabSalary Slip Deduction`
where parent = %s""", self.doc.name)
earn_table = ''
diff --git a/hr/doctype/salary_structure/salary_structure.py b/hr/doctype/salary_structure/salary_structure.py
index 50b0160d9ae..bfa7850d51d 100644
--- a/hr/doctype/salary_structure/salary_structure.py
+++ b/hr/doctype/salary_structure/salary_structure.py
@@ -8,7 +8,6 @@ from webnotes.utils import cstr, flt
from webnotes.model.doc import addchild, make_autoname
from webnotes import msgprint, _
-sql = webnotes.conn.sql
class DocType:
def __init__(self,doc,doclist=[]):
@@ -20,7 +19,7 @@ class DocType:
def get_employee_details(self):
ret = {}
- det = sql("""select employee_name, branch, designation, department, grade
+ det = webnotes.conn.sql("""select employee_name, branch, designation, department, grade
from `tabEmployee` where name = %s""", self.doc.employee)
if det:
ret = {
@@ -34,7 +33,7 @@ class DocType:
return ret
def get_ss_values(self,employee):
- basic_info = sql("""select bank_name, bank_ac_no, esic_card_no, pf_number
+ basic_info = webnotes.conn.sql("""select bank_name, bank_ac_no, esic_card_no, pf_number
from `tabEmployee` where name =%s""", employee)
ret = {'bank_name': basic_info and basic_info[0][0] or '',
'bank_ac_no': basic_info and basic_info[0][1] or '',
@@ -43,7 +42,7 @@ class DocType:
return ret
def make_table(self, doct_name, tab_fname, tab_name):
- list1 = sql("select name from `tab%s` where docstatus != 2" % doct_name)
+ list1 = webnotes.conn.sql("select name from `tab%s` where docstatus != 2" % doct_name)
for li in list1:
child = addchild(self.doc, tab_fname, tab_name, self.doclist)
if(tab_fname == 'earning_details'):
@@ -58,7 +57,7 @@ class DocType:
self.make_table('Deduction Type','deduction_details', 'Salary Structure Deduction')
def check_existing(self):
- ret = sql("""select name from `tabSalary Structure` where is_active = 'Yes'
+ ret = webnotes.conn.sql("""select name from `tabSalary Structure` where is_active = 'Yes'
and employee = %s and name!=%s""", (self.doc.employee,self.doc.name))
if ret and self.doc.is_active=='Yes':
msgprint(_("""Another Salary Structure '%s' is active for employee '%s'.
diff --git a/hr/doctype/upload_attendance/upload_attendance.py b/hr/doctype/upload_attendance/upload_attendance.py
index c1344b90e41..56c8eedcc75 100644
--- a/hr/doctype/upload_attendance/upload_attendance.py
+++ b/hr/doctype/upload_attendance/upload_attendance.py
@@ -9,7 +9,8 @@ from webnotes.utils import cstr, add_days, date_diff
from webnotes import msgprint, _
from webnotes.utils.datautils import UnicodeWriter
-doclist = None
+# doclist = None
+doclist = webnotes.local('uploadattendance_doclist')
class DocType():
def __init__(self, doc, doclist=[]):
@@ -21,9 +22,8 @@ def get_template():
if not webnotes.has_permission("Attendance", "create"):
raise webnotes.PermissionError
- args = webnotes.form_dict
- global doclist
- doclist = webnotes.model.doctype.get("Attendance")
+ args = webnotes.local.form_dict
+ webnotes.local.uploadattendance_doclist = webnotes.model.doctype.get("Attendance")
w = UnicodeWriter()
w = add_header(w)
@@ -144,4 +144,4 @@ def upload():
webnotes.conn.rollback()
else:
webnotes.conn.commit()
- return {"messages": ret, "error": error}
\ No newline at end of file
+ return {"messages": ret, "error": error}
diff --git a/manufacturing/doctype/bom/bom.py b/manufacturing/doctype/bom/bom.py
index 9a566123c78..97a2f96c6e0 100644
--- a/manufacturing/doctype/bom/bom.py
+++ b/manufacturing/doctype/bom/bom.py
@@ -9,7 +9,6 @@ from webnotes.model.bean import getlist
from webnotes.model.code import get_obj
from webnotes import msgprint, _
-sql = webnotes.conn.sql
class DocType:
@@ -18,7 +17,7 @@ class DocType:
self.doclist = doclist
def autoname(self):
- last_name = sql("""select max(name) from `tabBOM`
+ last_name = webnotes.conn.sql("""select max(name) from `tabBOM`
where name like "BOM/%s/%%" """ % cstr(self.doc.item).replace('"', '\\"'))
if last_name:
idx = cint(cstr(last_name[0][0]).split('/')[-1].split('-')[0]) + 1
@@ -144,7 +143,7 @@ class DocType:
webnotes.bean(self.doclist).update_after_submit()
def get_bom_unitcost(self, bom_no):
- bom = sql("""select name, total_cost/quantity as unit_cost from `tabBOM`
+ bom = webnotes.conn.sql("""select name, total_cost/quantity as unit_cost from `tabBOM`
where is_active = 1 and name = %s""", bom_no, as_dict=1)
return bom and bom[0]['unit_cost'] or 0
@@ -156,7 +155,7 @@ class DocType:
from stock.utils import get_incoming_rate
dt = self.doc.costing_date or nowdate()
time = self.doc.costing_date == nowdate() and now().split()[1] or '23:59'
- warehouse = sql("select warehouse from `tabBin` where item_code = %s", args['item_code'])
+ warehouse = webnotes.conn.sql("select warehouse from `tabBin` where item_code = %s", args['item_code'])
rate = []
for wh in warehouse:
r = get_incoming_rate({
@@ -184,7 +183,7 @@ class DocType:
if not self.doc.is_active:
webnotes.conn.set(self.doc, "is_default", 0)
- sql("update `tabItem` set default_bom = null where name = %s and default_bom = %s",
+ webnotes.conn.sql("update `tabItem` set default_bom = null where name = %s and default_bom = %s",
(self.doc.item, self.doc.name))
def clear_operations(self):
@@ -250,7 +249,7 @@ class DocType:
def validate_bom_no(self, item, bom_no, idx):
"""Validate BOM No of sub-contracted items"""
- bom = sql("""select name from `tabBOM` where name = %s and item = %s
+ bom = webnotes.conn.sql("""select name from `tabBOM` where name = %s and item = %s
and is_active=1 and docstatus=1""",
(bom_no, item), as_dict =1)
if not bom:
@@ -272,7 +271,7 @@ class DocType:
for d in check_list:
bom_list, count = [self.doc.name], 0
while (len(bom_list) > count ):
- boms = sql(" select %s from `tabBOM Item` where %s = '%s' " %
+ boms = webnotes.conn.sql(" select %s from `tabBOM Item` where %s = '%s' " %
(d[0], d[1], cstr(bom_list[count])))
count = count + 1
for b in boms:
@@ -333,6 +332,7 @@ class DocType:
d.amount = flt(d.rate) * flt(d.qty)
d.qty_consumed_per_unit = flt(d.qty) / flt(self.doc.quantity)
total_rm_cost += d.amount
+
self.doc.raw_material_cost = total_rm_cost
def update_exploded_items(self):
@@ -364,7 +364,7 @@ class DocType:
def get_child_exploded_items(self, bom_no, qty):
""" Add all items from Flat BOM of child BOM"""
- child_fb_items = sql("""select item_code, description, stock_uom, qty, rate,
+ child_fb_items = webnotes.conn.sql("""select item_code, description, stock_uom, qty, rate,
qty_consumed_per_unit from `tabBOM Explosion Item`
where parent = %s and docstatus = 1""", bom_no, as_dict = 1)
@@ -390,12 +390,12 @@ class DocType:
ch.save(1)
def get_parent_bom_list(self, bom_no):
- p_bom = sql("select parent from `tabBOM Item` where bom_no = '%s'" % bom_no)
+ p_bom = webnotes.conn.sql("select parent from `tabBOM Item` where bom_no = '%s'" % bom_no)
return p_bom and [i[0] for i in p_bom] or []
def validate_bom_links(self):
if not self.doc.is_active:
- act_pbom = sql("""select distinct bom_item.parent from `tabBOM Item` bom_item
+ act_pbom = webnotes.conn.sql("""select distinct bom_item.parent from `tabBOM Item` bom_item
where bom_item.bom_no = %s and bom_item.docstatus = 1
and exists (select * from `tabBOM` where name = bom_item.parent
and docstatus = 1 and is_active = 1)""", self.doc.name)
@@ -403,4 +403,53 @@ class DocType:
if act_pbom and act_pbom[0][0]:
action = self.doc.docstatus < 2 and _("deactivate") or _("cancel")
msgprint(_("Cannot ") + action + _(": It is linked to other active BOM(s)"),
- raise_exception=1)
\ No newline at end of file
+ raise_exception=1)
+
+def get_bom_items_as_dict(bom, qty=1, fetch_exploded=1):
+ item_dict = {}
+
+ query = """select
+ bom_item.item_code,
+ ifnull(sum(bom_item.qty_consumed_per_unit),0) * %(qty)s as qty,
+ item.description,
+ item.stock_uom,
+ item.default_warehouse
+ from
+ `tab%(table)s` bom_item, `tabItem` item
+ where
+ bom_item.docstatus < 2
+ and bom_item.parent = "%(bom)s"
+ and item.name = bom_item.item_code
+ %(conditions)s
+ group by item_code, stock_uom"""
+
+ if fetch_exploded:
+ items = webnotes.conn.sql(query % {
+ "qty": qty,
+ "table": "BOM Explosion Item",
+ "bom": bom,
+ "conditions": """and ifnull(item.is_pro_applicable, 'No') = 'No'
+ and ifnull(item.is_sub_contracted_item, 'No') = 'No' """
+ }, as_dict=True)
+ else:
+ items = webnotes.conn.sql(query % {
+ "qty": qty,
+ "table": "BOM Item",
+ "bom": bom,
+ "conditions": ""
+ }, as_dict=True)
+
+ # make unique
+ for item in items:
+ if item_dict.has_key(item.item_code):
+ item_dict[item.item_code]["qty"] += flt(item.qty)
+ else:
+ item_dict[item.item_code] = item
+
+ return item_dict
+
+@webnotes.whitelist()
+def get_bom_items(bom, qty=1, fetch_exploded=1):
+ items = get_bom_items_as_dict(bom, qty, fetch_exploded).values()
+ items.sort(lambda a, b: a.item_code > b.item_code and 1 or -1)
+ return items
\ No newline at end of file
diff --git a/manufacturing/doctype/bom/test_bom.py b/manufacturing/doctype/bom/test_bom.py
index d0b394a1f89..2f4424eb978 100644
--- a/manufacturing/doctype/bom/test_bom.py
+++ b/manufacturing/doctype/bom/test_bom.py
@@ -7,6 +7,35 @@ import unittest
import webnotes
test_records = [
+ [
+ {
+ "doctype": "BOM",
+ "item": "_Test Item Home Desktop Manufactured",
+ "quantity": 1.0,
+ "is_active": 1,
+ "is_default": 1,
+ "docstatus": 1
+ },
+ {
+ "doctype": "BOM Item",
+ "item_code": "_Test Serialized Item With Series",
+ "parentfield": "bom_materials",
+ "qty": 1.0,
+ "rate": 5000.0,
+ "amount": 5000.0,
+ "stock_uom": "_Test UOM"
+ },
+ {
+ "doctype": "BOM Item",
+ "item_code": "_Test Item 2",
+ "parentfield": "bom_materials",
+ "qty": 2.0,
+ "rate": 1000.0,
+ "amount": 2000.0,
+ "stock_uom": "_Test UOM"
+ }
+ ],
+
[
{
"doctype": "BOM",
@@ -34,5 +63,57 @@ test_records = [
"amount": 2000.0,
"stock_uom": "_Test UOM"
}
- ]
-]
\ No newline at end of file
+ ],
+
+ [
+ {
+ "doctype": "BOM",
+ "item": "_Test FG Item 2",
+ "quantity": 1.0,
+ "is_active": 1,
+ "is_default": 1,
+ "docstatus": 1
+ },
+ {
+ "doctype": "BOM Item",
+ "item_code": "_Test Item",
+ "parentfield": "bom_materials",
+ "qty": 1.0,
+ "rate": 5000.0,
+ "amount": 5000.0,
+ "stock_uom": "_Test UOM"
+ },
+ {
+ "doctype": "BOM Item",
+ "item_code": "_Test Item Home Desktop Manufactured",
+ "bom_no": "BOM/_Test Item Home Desktop Manufactured/001",
+ "parentfield": "bom_materials",
+ "qty": 2.0,
+ "rate": 1000.0,
+ "amount": 2000.0,
+ "stock_uom": "_Test UOM"
+ }
+ ],
+]
+
+class TestBOM(unittest.TestCase):
+ def test_get_items(self):
+ from manufacturing.doctype.bom.bom import get_bom_items_as_dict
+ items_dict = get_bom_items_as_dict(bom="BOM/_Test FG Item 2/001", qty=1, fetch_exploded=0)
+ self.assertTrue(test_records[2][1]["item_code"] in items_dict)
+ self.assertTrue(test_records[2][2]["item_code"] in items_dict)
+ self.assertEquals(len(items_dict.values()), 2)
+
+ def test_get_items_exploded(self):
+ from manufacturing.doctype.bom.bom import get_bom_items_as_dict
+ items_dict = get_bom_items_as_dict(bom="BOM/_Test FG Item 2/001", qty=1, fetch_exploded=1)
+ self.assertTrue(test_records[2][1]["item_code"] in items_dict)
+ self.assertFalse(test_records[2][2]["item_code"] in items_dict)
+ self.assertTrue(test_records[0][1]["item_code"] in items_dict)
+ self.assertTrue(test_records[0][2]["item_code"] in items_dict)
+ self.assertEquals(len(items_dict.values()), 3)
+
+ def test_get_items_list(self):
+ from manufacturing.doctype.bom.bom import get_bom_items
+ self.assertEquals(len(get_bom_items(bom="BOM/_Test FG Item 2/001", qty=1, fetch_exploded=1)), 3)
+
diff --git a/manufacturing/doctype/production_order/production_order.py b/manufacturing/doctype/production_order/production_order.py
index 6447c0aa120..36cbc646987 100644
--- a/manufacturing/doctype/production_order/production_order.py
+++ b/manufacturing/doctype/production_order/production_order.py
@@ -8,7 +8,6 @@ from webnotes.utils import cstr, flt, nowdate
from webnotes.model.code import get_obj
from webnotes import msgprint, _
-sql = webnotes.conn.sql
class OverProductionError(webnotes.ValidationError): pass
@@ -18,19 +17,23 @@ class DocType:
self.doclist = doclist
def validate(self):
+ if self.doc.docstatus == 0:
+ self.doc.status = "Draft"
+
import utilities
utilities.validate_status(self.doc.status, ["Draft", "Submitted", "Stopped",
"In Process", "Completed", "Cancelled"])
- if self.doc.production_item :
- item_detail = sql("select name from `tabItem` where name = '%s' and docstatus != 2"
- % self.doc.production_item, as_dict = 1)
- if not item_detail:
- msgprint("Item '%s' does not exist or cancelled in the system."
- % cstr(self.doc.production_item), raise_exception=1)
-
+ self.validate_bom_no()
+ self.validate_sales_order()
+ self.validate_warehouse()
+
+ from utilities.transaction_base import validate_uom_is_integer
+ validate_uom_is_integer(self.doclist, "stock_uom", ["qty", "produced_qty"])
+
+ def validate_bom_no(self):
if self.doc.bom_no:
- bom = sql("""select name from `tabBOM` where name=%s and docstatus=1
+ bom = webnotes.conn.sql("""select name from `tabBOM` where name=%s and docstatus=1
and is_active=1 and item=%s"""
, (self.doc.bom_no, self.doc.production_item), as_dict =1)
if not bom:
@@ -38,16 +41,20 @@ class DocType:
May be BOM not exists or inactive or not submitted
or for some other item.""" % cstr(self.doc.bom_no), raise_exception=1)
+ def validate_sales_order(self):
if self.doc.sales_order:
if not webnotes.conn.sql("""select name from `tabSales Order`
where name=%s and docstatus = 1""", self.doc.sales_order):
msgprint("Sales Order: %s is not valid" % self.doc.sales_order, raise_exception=1)
-
+
self.validate_production_order_against_so()
-
- from utilities.transaction_base import validate_uom_is_integer
- validate_uom_is_integer(self.doclist, "stock_uom", ["qty", "produced_qty"])
-
+
+ def validate_warehouse(self):
+ from stock.utils import validate_warehouse_user, validate_warehouse_company
+
+ for w in [self.doc.fg_warehouse, self.doc.wip_warehouse]:
+ validate_warehouse_user(w)
+ validate_warehouse_company(w, self.doc.company)
def validate_production_order_against_so(self):
# already ordered qty
@@ -104,7 +111,7 @@ class DocType:
def on_cancel(self):
# Check whether any stock entry exists against this Production Order
- stock_entry = sql("""select name from `tabStock Entry`
+ stock_entry = webnotes.conn.sql("""select name from `tabStock Entry`
where production_order = %s and docstatus = 1""", self.doc.name)
if stock_entry:
msgprint("""Submitted Stock Entry %s exists against this production order.
@@ -144,12 +151,6 @@ def get_item_details(item):
@webnotes.whitelist()
def make_stock_entry(production_order_id, purpose):
production_order = webnotes.bean("Production Order", production_order_id)
-
- # validate already existing
- ste = webnotes.conn.get_value("Stock Entry", {
- "production_order":production_order_id,
- "purpose": purpose
- }, "name")
stock_entry = webnotes.new_bean("Stock Entry")
stock_entry.doc.purpose = purpose
diff --git a/manufacturing/doctype/production_order/production_order.txt b/manufacturing/doctype/production_order/production_order.txt
index 782c99f0363..81821f6c45c 100644
--- a/manufacturing/doctype/production_order/production_order.txt
+++ b/manufacturing/doctype/production_order/production_order.txt
@@ -2,11 +2,12 @@
{
"creation": "2013-01-10 16:34:16",
"docstatus": 0,
- "modified": "2013-08-08 14:22:12",
+ "modified": "2013-10-02 14:25:03",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
+ "allow_import": 1,
"autoname": "naming_series:",
"doctype": "DocType",
"icon": "icon-cogs",
diff --git a/manufacturing/doctype/production_order/test_production_order.py b/manufacturing/doctype/production_order/test_production_order.py
new file mode 100644
index 00000000000..9a75762ba47
--- /dev/null
+++ b/manufacturing/doctype/production_order/test_production_order.py
@@ -0,0 +1,75 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
+# License: GNU General Public License v3. See license.txt
+
+
+from __future__ import unicode_literals
+import unittest
+import webnotes
+from stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory
+from manufacturing.doctype.production_order.production_order import make_stock_entry
+
+
+class TestProductionOrder(unittest.TestCase):
+ def test_planned_qty(self):
+ set_perpetual_inventory(0)
+ webnotes.conn.sql("delete from `tabStock Ledger Entry`")
+ webnotes.conn.sql("""delete from `tabBin`""")
+ webnotes.conn.sql("""delete from `tabGL Entry`""")
+
+ pro_bean = webnotes.bean(copy = test_records[0])
+ pro_bean.insert()
+ pro_bean.submit()
+
+ from stock.doctype.stock_entry.test_stock_entry import test_records as se_test_records
+ mr1 = webnotes.bean(copy = se_test_records[0])
+ mr1.insert()
+ mr1.submit()
+
+ mr2 = webnotes.bean(copy = se_test_records[0])
+ mr2.doclist[1].item_code = "_Test Item Home Desktop 100"
+ mr2.insert()
+ mr2.submit()
+
+ stock_entry = make_stock_entry(pro_bean.doc.name, "Manufacture/Repack")
+ stock_entry = webnotes.bean(stock_entry)
+
+ stock_entry.doc.fg_completed_qty = 4
+ stock_entry.run_method("get_items")
+ stock_entry.submit()
+
+ self.assertEqual(webnotes.conn.get_value("Production Order", pro_bean.doc.name,
+ "produced_qty"), 4)
+ self.assertEqual(webnotes.conn.get_value("Bin", {"item_code": "_Test FG Item",
+ "warehouse": "_Test Warehouse 1 - _TC"}, "planned_qty"), 6)
+
+ return pro_bean.doc.name
+
+ def test_over_production(self):
+ from stock.doctype.stock_entry.stock_entry import StockOverProductionError
+ pro_order = self.test_planned_qty()
+
+ stock_entry = make_stock_entry(pro_order, "Manufacture/Repack")
+ stock_entry = webnotes.bean(stock_entry)
+
+ stock_entry.doc.fg_completed_qty = 15
+ stock_entry.run_method("get_items")
+ stock_entry.insert()
+
+ self.assertRaises(StockOverProductionError, stock_entry.submit)
+
+
+
+test_records = [
+ [
+ {
+ "bom_no": "BOM/_Test FG Item/001",
+ "company": "_Test Company",
+ "doctype": "Production Order",
+ "production_item": "_Test FG Item",
+ "qty": 10.0,
+ "fg_warehouse": "_Test Warehouse 1 - _TC",
+ "wip_warehouse": "_Test Warehouse - _TC",
+ "stock_uom": "Nos"
+ }
+ ]
+]
\ No newline at end of file
diff --git a/manufacturing/doctype/production_planning_tool/production_planning_tool.py b/manufacturing/doctype/production_planning_tool/production_planning_tool.py
index 766f2ac233c..6f15d4c9f10 100644
--- a/manufacturing/doctype/production_planning_tool/production_planning_tool.py
+++ b/manufacturing/doctype/production_planning_tool/production_planning_tool.py
@@ -9,7 +9,6 @@ from webnotes.model.bean import getlist
from webnotes.model.code import get_obj
from webnotes import msgprint, _
-sql = webnotes.conn.sql
class DocType:
def __init__(self, doc, doclist=[]):
@@ -19,7 +18,7 @@ class DocType:
def get_so_details(self, so):
"""Pull other details from so"""
- so = sql("""select transaction_date, customer, grand_total
+ so = webnotes.conn.sql("""select transaction_date, customer, grand_total
from `tabSales Order` where name = %s""", so, as_dict = 1)
ret = {
'sales_order_date': so and so[0]['transaction_date'] or '',
@@ -31,7 +30,7 @@ class DocType:
def get_item_details(self, item_code):
""" Pull other item details from item master"""
- item = sql("""select description, stock_uom, default_bom
+ item = webnotes.conn.sql("""select description, stock_uom, default_bom
from `tabItem` where name = %s""", item_code, as_dict =1)
ret = {
'description' : item and item[0]['description'],
@@ -63,7 +62,7 @@ class DocType:
if self.doc.fg_item:
item_filter += ' and item.name = "' + self.doc.fg_item + '"'
- open_so = sql("""
+ open_so = webnotes.conn.sql("""
select distinct so.name, so.transaction_date, so.customer, so.grand_total
from `tabSales Order` so, `tabSales Order Item` so_item
where so_item.parent = so.name
@@ -108,7 +107,7 @@ class DocType:
msgprint("Please enter sales order in the above table")
return []
- items = sql("""select distinct parent, item_code, reserved_warehouse,
+ items = webnotes.conn.sql("""select distinct parent, item_code, reserved_warehouse,
(qty - ifnull(delivered_qty, 0)) as pending_qty
from `tabSales Order Item` so_item
where parent in (%s) and docstatus = 1 and ifnull(qty, 0) > ifnull(delivered_qty, 0)
@@ -117,7 +116,7 @@ class DocType:
or ifnull(item.is_sub_contracted_item, 'No') = 'Yes'))""" % \
(", ".join(["%s"] * len(so_list))), tuple(so_list), as_dict=1)
- dnpi_items = sql("""select distinct dnpi.parent, dnpi.item_code, dnpi.warehouse as reserved_warhouse,
+ dnpi_items = webnotes.conn.sql("""select distinct dnpi.parent, dnpi.item_code, dnpi.warehouse as reserved_warhouse,
(((so_item.qty - ifnull(so_item.delivered_qty, 0)) * dnpi.qty) / so_item.qty)
as pending_qty
from `tabSales Order Item` so_item, `tabDelivery Note Packing Item` dnpi
@@ -136,7 +135,7 @@ class DocType:
self.clear_item_table()
for p in items:
- item_details = sql("""select description, stock_uom, default_bom
+ item_details = webnotes.conn.sql("""select description, stock_uom, default_bom
from tabItem where name=%s""", p['item_code'])
pi = addchild(self.doc, 'pp_details', 'Production Plan Item', self.doclist)
pi.sales_order = p['parent']
@@ -162,7 +161,7 @@ class DocType:
msgprint("Please enter bom no for item: %s at row no: %s" %
(d.item_code, d.idx), raise_exception=1)
else:
- bom = sql("""select name from `tabBOM` where name = %s and item = %s
+ bom = webnotes.conn.sql("""select name from `tabBOM` where name = %s and item = %s
and docstatus = 1 and is_active = 1""",
(d.bom_no, d.item_code), as_dict = 1)
if not bom:
@@ -216,14 +215,14 @@ class DocType:
pro = webnotes.new_bean("Production Order")
pro.doc.fields.update(items[key])
- webnotes.mute_messages = True
+ webnotes.flags.mute_messages = True
try:
pro.insert()
pro_list.append(pro.doc.name)
except OverProductionError, e:
pass
- webnotes.mute_messages = False
+ webnotes.flags.mute_messages = False
return pro_list
@@ -243,7 +242,7 @@ class DocType:
for bom in bom_dict:
if self.doc.use_multi_level_bom:
# get all raw materials with sub assembly childs
- fl_bom_items = sql("""select fb.item_code,
+ fl_bom_items = webnotes.conn.sql("""select fb.item_code,
ifnull(sum(fb.qty_consumed_per_unit), 0)*%s as qty,
fb.description, fb.stock_uom, it.min_order_qty
from `tabBOM Explosion Item` fb,`tabItem` it
@@ -254,7 +253,7 @@ class DocType:
else:
# Get all raw materials considering SA items as raw materials,
# so no childs of SA items
- fl_bom_items = sql("""select bom_item.item_code,
+ fl_bom_items = webnotes.conn.sql("""select bom_item.item_code,
ifnull(sum(bom_item.qty_consumed_per_unit), 0) * %s,
bom_item.description, bom_item.stock_uom, item.min_order_qty
from `tabBOM Item` bom_item, tabItem item
@@ -274,7 +273,7 @@ class DocType:
'Quantity Requested for Purchase', 'Ordered Qty', 'Actual Qty']]
for d in self.item_dict:
item_list.append([d, self.item_dict[d][1], self.item_dict[d][2], self.item_dict[d][0]])
- item_qty= sql("""select warehouse, indented_qty, ordered_qty, actual_qty
+ item_qty= webnotes.conn.sql("""select warehouse, indented_qty, ordered_qty, actual_qty
from `tabBin` where item_code = %s""", d)
i_qty, o_qty, a_qty = 0, 0, 0
for w in item_qty:
diff --git a/manufacturing/doctype/workstation/workstation.py b/manufacturing/doctype/workstation/workstation.py
index 35e2c1f06b2..cc129340e4a 100644
--- a/manufacturing/doctype/workstation/workstation.py
+++ b/manufacturing/doctype/workstation/workstation.py
@@ -8,7 +8,6 @@ from webnotes.utils import flt
from webnotes.model import db_exists
from webnotes.model.bean import copy_doclist
-sql = webnotes.conn.sql
@@ -18,9 +17,9 @@ class DocType:
self.doclist = doclist
def update_bom_operation(self):
- bom_list = sql(" select DISTINCT parent from `tabBOM Operation` where workstation = '%s'" % self.doc.name)
+ bom_list = webnotes.conn.sql(" select DISTINCT parent from `tabBOM Operation` where workstation = '%s'" % self.doc.name)
for bom_no in bom_list:
- sql("update `tabBOM Operation` set hour_rate = '%s' where parent = '%s' and workstation = '%s'"%( self.doc.hour_rate, bom_no[0], self.doc.name))
+ webnotes.conn.sql("update `tabBOM Operation` set hour_rate = '%s' where parent = '%s' and workstation = '%s'"%( self.doc.hour_rate, bom_no[0], self.doc.name))
def on_update(self):
webnotes.conn.set(self.doc, 'overhead', flt(self.doc.hour_rate_electricity) + flt(self.doc.hour_rate_consumable) + flt(self.doc.hour_rate_rent))
diff --git a/patches/april_2013/p05_update_file_data.py b/patches/april_2013/p05_update_file_data.py
index e03abc6b65c..47d6de9186b 100644
--- a/patches/april_2013/p05_update_file_data.py
+++ b/patches/april_2013/p05_update_file_data.py
@@ -52,7 +52,7 @@ def update_for_doc(doctype, doc):
exists = True
if not (filename.startswith("http://") or filename.startswith("https://")):
- if not os.path.exists(webnotes.utils.get_path("public", "files", filename)):
+ if not os.path.exists(webnotes.utils.get_site_path(webnotes.conf.files_path, filename)):
exists = False
if exists:
diff --git a/patches/april_2013/p06_update_file_size.py b/patches/april_2013/p06_update_file_size.py
index 6879625ad9d..973cea94d7e 100644
--- a/patches/april_2013/p06_update_file_size.py
+++ b/patches/april_2013/p06_update_file_size.py
@@ -4,7 +4,7 @@
import webnotes, os, webnotes.utils
def execute():
- files_path = webnotes.utils.get_path("public", "files")
+ files_path = webnotes.utils.get_site_path(webnotes.conf.files_path)
webnotes.conn.auto_commit_on_many_writes = 1
for f in webnotes.conn.sql("""select name, file_name from
@@ -14,4 +14,4 @@ def execute():
if os.path.exists(filepath):
webnotes.conn.set_value("File Data", f.name, "file_size", os.stat(filepath).st_size)
- webnotes.conn.auto_commit_on_many_writes = 0
\ No newline at end of file
+ webnotes.conn.auto_commit_on_many_writes = 0
diff --git a/patches/august_2013/p02_rename_price_list.py b/patches/august_2013/p02_rename_price_list.py
index 41efb273069..0a1929925ba 100644
--- a/patches/august_2013/p02_rename_price_list.py
+++ b/patches/august_2013/p02_rename_price_list.py
@@ -6,6 +6,7 @@ import webnotes
def execute():
webnotes.reload_doc("selling", "doctype", "shopping_cart_price_list")
+ webnotes.reload_doc("setup", "doctype", "item_price")
for t in [
("Supplier Quotation", "price_list_name", "buying_price_list"),
diff --git a/patches/august_2013/p06_fix_sle_against_stock_entry.py b/patches/august_2013/p06_fix_sle_against_stock_entry.py
index 02588bec6d6..2e6c383ebd6 100644
--- a/patches/august_2013/p06_fix_sle_against_stock_entry.py
+++ b/patches/august_2013/p06_fix_sle_against_stock_entry.py
@@ -1,10 +1,9 @@
import webnotes
-cancelled = []
-uncancelled = []
-
def execute():
- global cancelled, uncancelled
+ cancelled = []
+ uncancelled = []
+
stock_entries = webnotes.conn.sql("""select * from `tabStock Entry`
where docstatus >= 1 and date(modified) >= "2013-08-16"
and ifnull(production_order, '') != '' and ifnull(bom_no, '') != ''
@@ -17,14 +16,12 @@ def execute():
where voucher_type='Stock Entry' and voucher_no=%s
and is_cancelled='No'""", entry.name, as_dict=True)
if res:
- make_stock_entry_detail(entry, res)
+ make_stock_entry_detail(entry, res, cancelled, uncancelled)
if cancelled or uncancelled:
- send_email()
+ send_email(cancelled, uncancelled)
-def make_stock_entry_detail(entry, res):
- global cancelled, uncancelled
-
+def make_stock_entry_detail(entry, res, cancelled, uncancelled):
fg_item = webnotes.conn.get_value("Production Order", entry.production_order,
"production_item")
voucher_detail_entries_map = {}
@@ -87,9 +84,8 @@ def make_stock_entry_detail(entry, res):
uncancelled.append(se.doc.name)
-def send_email():
+def send_email(cancelled, uncancelled):
from webnotes.utils.email_lib import sendmail_to_system_managers
- global cancelled, uncancelled
uncancelled = "we have undone the cancellation of the following Stock Entries through a patch:\n" + \
"\n".join(uncancelled) if uncancelled else ""
cancelled = "and cancelled the following Stock Entries:\n" + "\n".join(cancelled) \
diff --git a/patches/december_2012/repost_ordered_qty.py b/patches/december_2012/repost_ordered_qty.py
index 2e3c690adfb..4c1d11d39bc 100644
--- a/patches/december_2012/repost_ordered_qty.py
+++ b/patches/december_2012/repost_ordered_qty.py
@@ -3,16 +3,9 @@
def execute():
import webnotes
- from webnotes.utils import flt
- bins = webnotes.conn.sql("select item_code, warehouse, name, ordered_qty from `tabBin`")
- for d in bins:
- ordered_qty = webnotes.conn.sql("""
- select sum(ifnull(po_item.qty, 0) - ifnull(po_item.received_qty, 0))
- from `tabPurchase Order Item` po_item, `tabPurchase Order` po
- where po_item.parent = po.name and po.docstatus = 1 and po.status != 'Stopped'
- and po_item.item_code = %s and po_item.warehouse = %s
- """, (d[0], d[1]))
-
- if flt(d[3]) != flt(ordered_qty[0][0]):
- webnotes.conn.sql("""update `tabBin` set ordered_qty = %s where name = %s""",
- (ordered_qty and ordered_qty[0][0] or 0, d[2]))
\ No newline at end of file
+ from utilities.repost_stock import get_ordered_qty, update_bin
+
+ for d in webnotes.conn.sql("select item_code, warehouse from tabBin"):
+ update_bin(d[0], d[1], {
+ "ordered_qty": get_ordered_qty(d[0], d[1])
+ })
\ No newline at end of file
diff --git a/patches/february_2013/repost_reserved_qty.py b/patches/february_2013/repost_reserved_qty.py
index 3a3353f9182..5c41266c2aa 100644
--- a/patches/february_2013/repost_reserved_qty.py
+++ b/patches/february_2013/repost_reserved_qty.py
@@ -4,54 +4,10 @@
import webnotes
def execute():
webnotes.conn.auto_commit_on_many_writes = 1
- repost_reserved_qty()
- webnotes.conn.auto_commit_on_many_writes = 0
+ from utilities.repost_stock import get_reserved_qty, update_bin
-def repost_reserved_qty():
- from webnotes.utils import flt
- bins = webnotes.conn.sql("select item_code, warehouse, name, reserved_qty from `tabBin`")
- i = 0
- for d in bins:
- i += 1
- reserved_qty = webnotes.conn.sql("""
- select
- sum((dnpi_qty / so_item_qty) * (so_item_qty - so_item_delivered_qty))
- from
- (
- (select
- qty as dnpi_qty,
- (
- select qty from `tabSales Order Item`
- where name = dnpi.parent_detail_docname
- ) as so_item_qty,
- (
- select ifnull(delivered_qty, 0) from `tabSales Order Item`
- where name = dnpi.parent_detail_docname
- ) as so_item_delivered_qty,
- parent, name
- from
- (
- select qty, parent_detail_docname, parent, name
- from `tabDelivery Note Packing Item` dnpi_in
- where item_code = %s and warehouse = %s
- and parenttype="Sales Order"
- and item_code != parent_item
- and exists (select * from `tabSales Order` so
- where name = dnpi_in.parent and docstatus = 1 and status != 'Stopped')
- ) dnpi)
- union
- (select qty as dnpi_qty, qty as so_item_qty,
- ifnull(delivered_qty, 0) as so_item_delivered_qty, parent, name
- from `tabSales Order Item` so_item
- where item_code = %s and reserved_warehouse = %s
- and exists(select * from `tabSales Order` so
- where so.name = so_item.parent and so.docstatus = 1
- and so.status != 'Stopped'))
- ) tab
- where
- so_item_qty >= so_item_delivered_qty
- """, (d[0], d[1], d[0], d[1]))
-
- if flt(d[3]) != flt(reserved_qty[0][0]):
- webnotes.conn.sql("""update `tabBin` set reserved_qty = %s where name = %s""",
- (reserved_qty and reserved_qty[0][0] or 0, d[2]))
\ No newline at end of file
+ for d in webnotes.conn.sql("select item_code, warehouse from tabBin"):
+ update_bin(d[0], d[1], {
+ "reserved_qty": get_reserved_qty(d[0], d[1])
+ })
+ webnotes.conn.auto_commit_on_many_writes = 0
\ No newline at end of file
diff --git a/patches/june_2013/p08_shopping_cart_settings.py b/patches/june_2013/p08_shopping_cart_settings.py
index 479a6961e26..677b62a5e3e 100644
--- a/patches/june_2013/p08_shopping_cart_settings.py
+++ b/patches/june_2013/p08_shopping_cart_settings.py
@@ -7,7 +7,7 @@ def execute():
webnotes.reload_doc("selling", "doctype", "shopping_cart_settings")
# create two default territories, one for home country and one named Rest of the World
- from setup.doctype.setup_control.setup_control import create_territories
+ from setup.page.setup_wizard.setup_wizard import create_territories
create_territories()
webnotes.conn.set_value("Shopping Cart Settings", None, "default_territory", "Rest of the World")
diff --git a/patches/october_2013/__init__.py b/patches/october_2013/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/patches/october_2013/fix_is_cancelled_in_sle.py b/patches/october_2013/fix_is_cancelled_in_sle.py
new file mode 100644
index 00000000000..cb51b5d7ca1
--- /dev/null
+++ b/patches/october_2013/fix_is_cancelled_in_sle.py
@@ -0,0 +1,13 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import webnotes
+
+def execute():
+ webnotes.conn.sql("""update `tabStock Ledger Entry` set is_cancelled = 'No'
+ where ifnull(is_cancelled, '') = ''""")
+
+ webnotes.conn.sql("""update tabBin b set b.stock_uom =
+ (select i.stock_uom from tabItem i where i.name = b.item_code)
+ where b.creation>='2013-09-01'""")
\ No newline at end of file
diff --git a/patches/october_2013/p01_fix_serial_no_status.py b/patches/october_2013/p01_fix_serial_no_status.py
new file mode 100644
index 00000000000..0bfc400a8e9
--- /dev/null
+++ b/patches/october_2013/p01_fix_serial_no_status.py
@@ -0,0 +1,18 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import webnotes
+from webnotes.utils import flt
+
+def execute():
+ serial_nos = webnotes.conn.sql("""select name from `tabSerial No` where status!='Not in Use'
+ and docstatus=0""")
+ for sr in serial_nos:
+ sr_bean = webnotes.bean("Serial No", sr[0])
+ sr_bean.make_controller().via_stock_ledger = True
+ sr_bean.run_method("validate")
+ sr_bean.save()
+
+ webnotes.conn.sql("""update `tabSerial No` set warehouse='' where status in
+ ('Delivered', 'Purchase Returned')""")
\ No newline at end of file
diff --git a/patches/october_2013/p01_update_delivery_note_prevdocs.py b/patches/october_2013/p01_update_delivery_note_prevdocs.py
new file mode 100644
index 00000000000..75ac53f9837
--- /dev/null
+++ b/patches/october_2013/p01_update_delivery_note_prevdocs.py
@@ -0,0 +1,13 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import webnotes
+
+def execute():
+ webnotes.reload_doc("stock", "doctype", "delivery_note_item")
+ webnotes.conn.sql("""update `tabDelivery Note Item` set against_sales_order=prevdoc_docname
+ where prevdoc_doctype='Sales Order' """)
+
+ webnotes.conn.sql("""update `tabDelivery Note Item` set against_sales_invoice=prevdoc_docname
+ where prevdoc_doctype='Sales Invoice' """)
\ No newline at end of file
diff --git a/patches/october_2013/p02_set_communication_status.py b/patches/october_2013/p02_set_communication_status.py
new file mode 100644
index 00000000000..d67d08dbe0a
--- /dev/null
+++ b/patches/october_2013/p02_set_communication_status.py
@@ -0,0 +1,11 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import webnotes
+
+def execute():
+ webnotes.reload_doc("core", "doctype", "communication")
+
+ webnotes.conn.sql("""update tabCommunication
+ set sent_or_received= if(ifnull(recipients, '')='', "Received", "Sent")""")
\ No newline at end of file
diff --git a/patches/october_2013/p03_crm_update_status.py b/patches/october_2013/p03_crm_update_status.py
new file mode 100644
index 00000000000..07a70c642a9
--- /dev/null
+++ b/patches/october_2013/p03_crm_update_status.py
@@ -0,0 +1,47 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import webnotes
+
+# reason field
+
+def execute():
+ change_map = {
+ "Lead": [
+ ["Lead Lost", "Lead"],
+ ["Not interested", "Do Not Contact"],
+ ["Opportunity Made", "Opportunity"],
+ ["Contacted", "Replied"],
+ ["Attempted to Contact", "Replied"],
+ ["Contact in Future", "Interested"],
+ ],
+ "Opportunity": [
+ ["Quotation Sent", "Quotation"],
+ ["Order Confirmed", "Quotation"],
+ ["Opportunity Lost", "Lost"],
+ ],
+ "Quotation": [
+ ["Order Confirmed", "Ordered"],
+ ["Order Lost", "Lost"]
+ ],
+ "Support Ticket": [
+ ["Waiting for Customer", "Replied"],
+ ["To Reply", "Open"],
+ ]
+ }
+
+ for dt, opts in change_map.items():
+ for status in opts:
+ webnotes.conn.sql("""update `tab%s` set status=%s where status=%s""" % \
+ (dt, "%s", "%s"), (status[1], status[0]))
+
+ for dt in ["Lead", "Opportunity"]:
+ for name in webnotes.conn.sql_list("""select name from `tab%s`""" % dt):
+ bean = webnotes.bean(dt, name)
+ before_status = bean.doc.status
+ bean.get_controller().set_status()
+
+ if bean.doc.status != before_status:
+ webnotes.conn.sql("""update `tab%s` set status=%s where name=%s""" % (dt, "%s", "%s"),
+ (bean.doc.status, name))
diff --git a/patches/october_2013/p04_wsgi_migration.py b/patches/october_2013/p04_wsgi_migration.py
new file mode 100644
index 00000000000..ca73516c25a
--- /dev/null
+++ b/patches/october_2013/p04_wsgi_migration.py
@@ -0,0 +1,30 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import webnotes
+import webnotes.utils
+import os
+
+def execute():
+ base_path = webnotes.utils.get_base_path()
+
+ # Remove symlinks from public folder:
+ # - server.py
+ # - web.py
+ # - unsupported.html
+ # - blank.html
+ # - rss.xml
+ # - sitemap.xml
+ for file in ("server.py", "web.py", "unsupported.html", "blank.html", "rss.xml", "sitemap.xml"):
+ file_path = os.path.join(base_path, "public", file)
+ if os.path.exists(file_path):
+ os.remove(file_path)
+
+ # Remove wn-web files
+ # - js/wn-web.js
+ # - css/wn-web.css
+ for file_path in (("js", "wn-web.js"), ("css", "wn-web.css")):
+ file_path = os.path.join(base_path, "public", *file_path)
+ if os.path.exists(file_path):
+ os.remove(file_path)
\ No newline at end of file
diff --git a/patches/october_2013/p05_server_custom_script_to_file.py b/patches/october_2013/p05_server_custom_script_to_file.py
new file mode 100644
index 00000000000..3a7e7702652
--- /dev/null
+++ b/patches/october_2013/p05_server_custom_script_to_file.py
@@ -0,0 +1,36 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import webnotes
+
+def execute():
+ """
+ Assuming that some kind of indentation exists:
+ - Find indentation of server custom script
+ - replace indentation with tabs
+ - Add line:
+ class CustomDocType(DocType):
+ - Add tab indented code after this line
+ - Write to file
+ - Delete custom script record
+ """
+ import os
+ from webnotes.utils import get_site_base_path
+ from core.doctype.custom_script.custom_script import make_custom_server_script_file
+ for name, dt, script in webnotes.conn.sql("""select name, dt, script from `tabCustom Script`
+ where script_type='Server'"""):
+ if script.strip():
+ script = indent_using_tabs(script)
+ make_custom_server_script_file(dt, script)
+
+def indent_using_tabs(script):
+ for line in script.split("\n"):
+ try:
+ indentation_used = line[:line.index("def ")]
+ script = script.replace(indentation_used, "\t")
+ break
+ except ValueError:
+ pass
+
+ return script
\ No newline at end of file
diff --git a/patches/october_2013/perpetual_inventory_stock_transfer_utility.py b/patches/october_2013/perpetual_inventory_stock_transfer_utility.py
new file mode 100644
index 00000000000..d8cade78eb7
--- /dev/null
+++ b/patches/october_2013/perpetual_inventory_stock_transfer_utility.py
@@ -0,0 +1,86 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import webnotes
+from webnotes.utils import nowdate, nowtime, cstr
+from accounts.utils import get_fiscal_year
+
+def execute():
+ item_map = {}
+ for item in webnotes.conn.sql("""select * from tabItem""", as_dict=1):
+ item_map.setdefault(item.name, item)
+
+ warehouse_map = get_warehosue_map()
+ naming_series = "STE/13/"
+
+ for company in webnotes.conn.sql("select name from tabCompany"):
+ stock_entry = [{
+ "doctype": "Stock Entry",
+ "naming_series": naming_series,
+ "posting_date": nowdate(),
+ "posting_time": nowtime(),
+ "purpose": "Material Transfer",
+ "company": company[0],
+ "remarks": "Material Transfer to activate perpetual inventory",
+ "fiscal_year": get_fiscal_year(nowdate())[0]
+ }]
+ expense_account = "Cost of Goods Sold - NISL"
+ cost_center = "Default CC Ledger - NISL"
+
+ for bin in webnotes.conn.sql("""select * from tabBin bin where ifnull(item_code, '')!=''
+ and ifnull(warehouse, '') in (%s) and ifnull(actual_qty, 0) != 0
+ and (select company from tabWarehouse where name=bin.warehouse)=%s""" %
+ (', '.join(['%s']*len(warehouse_map)), '%s'),
+ (warehouse_map.keys() + [company[0]]), as_dict=1):
+ item_details = item_map[bin.item_code]
+ new_warehouse = warehouse_map[bin.warehouse].get("fixed_asset_warehouse") \
+ if cstr(item_details.is_asset_item) == "Yes" \
+ else warehouse_map[bin.warehouse].get("current_asset_warehouse")
+
+ if item_details.has_serial_no == "Yes":
+ serial_no = "\n".join([d[0] for d in webnotes.conn.sql("""select name
+ from `tabSerial No` where item_code = %s and warehouse = %s
+ and status in ('Available', 'Sales Returned')""",
+ (bin.item_code, bin.warehouse))])
+ else:
+ serial_no = None
+
+ stock_entry.append({
+ "doctype": "Stock Entry Detail",
+ "parentfield": "mtn_details",
+ "s_warehouse": bin.warehouse,
+ "t_warehouse": new_warehouse,
+ "item_code": bin.item_code,
+ "description": item_details.description,
+ "qty": bin.actual_qty,
+ "transfer_qty": bin.actual_qty,
+ "uom": item_details.stock_uom,
+ "stock_uom": item_details.stock_uom,
+ "conversion_factor": 1,
+ "expense_account": expense_account,
+ "cost_center": cost_center,
+ "serial_no": serial_no
+ })
+
+ webnotes.bean(stock_entry).insert()
+
+def get_warehosue_map():
+ return {
+ "MAHAPE": {
+ "current_asset_warehouse": "Mahape-New - NISL",
+ "fixed_asset_warehouse": ""
+ },
+ "DROP SHIPMENT": {
+ "current_asset_warehouse": "Drop Shipment-New - NISL",
+ "fixed_asset_warehouse": ""
+ },
+ "TRANSIT": {
+ "current_asset_warehouse": "Transit-New - NISL",
+ "fixed_asset_warehouse": ""
+ },
+ "ASSET - MAHAPE": {
+ "current_asset_warehouse": "",
+ "fixed_asset_warehouse": "Assets-New - NISL"
+ }
+ }
\ No newline at end of file
diff --git a/patches/october_2013/repost_ordered_qty.py b/patches/october_2013/repost_ordered_qty.py
new file mode 100644
index 00000000000..55827941b0f
--- /dev/null
+++ b/patches/october_2013/repost_ordered_qty.py
@@ -0,0 +1,6 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
+# License: GNU General Public License v3. See license.txt
+
+def execute():
+ from patches.december_2012 import repost_ordered_qty
+ repost_ordered_qty.execute()
\ No newline at end of file
diff --git a/patches/october_2013/repost_planned_qty.py b/patches/october_2013/repost_planned_qty.py
new file mode 100644
index 00000000000..cfe47ca1155
--- /dev/null
+++ b/patches/october_2013/repost_planned_qty.py
@@ -0,0 +1,11 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
+# License: GNU General Public License v3. See license.txt
+
+def execute():
+ import webnotes
+ from utilities.repost_stock import get_planned_qty, update_bin
+
+ for d in webnotes.conn.sql("select item_code, warehouse from tabBin"):
+ update_bin(d[0], d[1], {
+ "planned_qty": get_planned_qty(d[0], d[1])
+ })
\ No newline at end of file
diff --git a/patches/october_2013/set_stock_value_diff_in_sle.py b/patches/october_2013/set_stock_value_diff_in_sle.py
new file mode 100644
index 00000000000..25f95e0e6da
--- /dev/null
+++ b/patches/october_2013/set_stock_value_diff_in_sle.py
@@ -0,0 +1,10 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import webnotes
+from webnotes.utils import cint
+
+def execute():
+ from patches.september_2012 import repost_stock
+ repost_stock.execute()
\ No newline at end of file
diff --git a/patches/patch_list.py b/patches/patch_list.py
index 7041ba88585..9851986415b 100644
--- a/patches/patch_list.py
+++ b/patches/patch_list.py
@@ -3,10 +3,8 @@
from __future__ import unicode_literals
patch_list = [
- "execute:webnotes.reload_doc('core', 'doctype', 'doctype', force=True) #2013-07-15",
- "execute:webnotes.reload_doc('core', 'doctype', 'docfield', force=True) #2013-07-15",
- "execute:webnotes.reload_doc('core', 'doctype', 'doctype', force=True) #2013-07-16",
- "execute:webnotes.reload_doc('core', 'doctype', 'docfield', force=True) #2013-07-16",
+ "execute:webnotes.reload_doc('core', 'doctype', 'doctype', force=True) #2013-10-15",
+ "execute:webnotes.reload_doc('core', 'doctype', 'docfield', force=True) #2013-10-15",
"execute:webnotes.reload_doc('core', 'doctype', 'docperm') #2013-07-16",
"execute:webnotes.reload_doc('core', 'doctype', 'page') #2013-07-16",
"execute:webnotes.reload_doc('core', 'doctype', 'report') #2013-07-16",
@@ -218,4 +216,14 @@ patch_list = [
"execute:webnotes.bean('Style Settings').save() #2013-09-19",
"execute:webnotes.conn.set_value('Accounts Settings', None, 'frozen_accounts_modifier', 'Accounts Manager') # 2013-09-24",
"patches.september_2013.p04_unsubmit_serial_nos",
+ "patches.september_2013.p05_fix_customer_in_pos",
+ "patches.october_2013.fix_is_cancelled_in_sle",
+ "patches.october_2013.p01_update_delivery_note_prevdocs",
+ "patches.october_2013.p02_set_communication_status",
+ "patches.october_2013.p03_crm_update_status",
+ "execute:webnotes.delete_doc('DocType', 'Setup Control')",
+ "patches.october_2013.p04_wsgi_migration",
+ "patches.october_2013.p05_server_custom_script_to_file",
+ "patches.october_2013.repost_ordered_qty",
+ "patches.october_2013.repost_planned_qty",
]
\ No newline at end of file
diff --git a/patches/september_2013/p05_fix_customer_in_pos.py b/patches/september_2013/p05_fix_customer_in_pos.py
new file mode 100644
index 00000000000..60210dab24e
--- /dev/null
+++ b/patches/september_2013/p05_fix_customer_in_pos.py
@@ -0,0 +1,22 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import webnotes
+def execute():
+ si_list = webnotes.conn.sql("""select name, debit_to from `tabSales Invoice`
+ where ifnull(is_pos, 1)=1 and docstatus=1 and modified > '2013-09-03'""", as_dict=1)
+
+ for si in si_list:
+ if not webnotes.conn.get_value("GL Entry", {"voucher_type": "Sales Invoice",
+ "voucher_no": si.name, "account": si.debit_to}):
+ debit_to = webnotes.conn.sql("""select account from `tabGL Entry` gle
+ where voucher_type='Sales Invoice' and voucher_no=%s
+ and (select master_type from tabAccount where name=gle.account)='Customer'
+ """, si.name)
+ if debit_to:
+ si_bean = webnotes.bean("Sales Invoice", si.name)
+ si_bean.doc.debit_to = debit_to[0][0]
+ si_bean.doc.customer = None
+ si_bean.run_method("set_customer_defaults")
+ si_bean.update_after_submit()
\ No newline at end of file
diff --git a/portal/templates/pages/cart.py b/portal/templates/pages/cart.py
index 24b474a55c3..ecf3163f0ad 100644
--- a/portal/templates/pages/cart.py
+++ b/portal/templates/pages/cart.py
@@ -3,4 +3,5 @@
from __future__ import unicode_literals
-no_cache = True
\ No newline at end of file
+no_cache = True
+no_sitemap = True
\ No newline at end of file
diff --git a/portal/templates/pages/profile.py b/portal/templates/pages/profile.py
index 8edd830d471..3a75cfb0823 100644
--- a/portal/templates/pages/profile.py
+++ b/portal/templates/pages/profile.py
@@ -7,6 +7,7 @@ from webnotes import _
from webnotes.utils import cstr
no_cache = True
+no_sitemap = True
def get_context():
from selling.utils.cart import get_lead_or_customer
@@ -33,7 +34,7 @@ def update_profile(fullname, password=None, company_name=None, mobile_no=None, p
return _("Name is required")
webnotes.conn.set_value("Profile", webnotes.session.user, "first_name", fullname)
- webnotes.add_cookies["full_name"] = fullname
+ webnotes._response.set_cookie("full_name", fullname)
return _("Updated")
\ No newline at end of file
diff --git a/projects/doctype/project/project.txt b/projects/doctype/project/project.txt
index 91dcfa16816..fc8accf1ee1 100644
--- a/projects/doctype/project/project.txt
+++ b/projects/doctype/project/project.txt
@@ -2,12 +2,13 @@
{
"creation": "2013-03-07 11:55:07",
"docstatus": 0,
- "modified": "2013-07-05 14:51:41",
+ "modified": "2013-10-02 14:25:02",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"allow_attach": 1,
+ "allow_import": 1,
"autoname": "field:project_name",
"doctype": "DocType",
"document_type": "Master",
diff --git a/projects/doctype/task/task.py b/projects/doctype/task/task.py
index 6cd1ba8636e..fb9b6ab6a67 100644
--- a/projects/doctype/task/task.py
+++ b/projects/doctype/task/task.py
@@ -9,7 +9,6 @@ from webnotes.model import db_exists
from webnotes.model.bean import copy_doclist
from webnotes import msgprint
-sql = webnotes.conn.sql
class DocType:
def __init__(self,doc,doclist=[]):
@@ -17,13 +16,13 @@ class DocType:
self.doclist = doclist
def get_project_details(self):
- cust = sql("select customer, customer_name from `tabProject` where name = %s", self.doc.project)
+ cust = webnotes.conn.sql("select customer, customer_name from `tabProject` where name = %s", self.doc.project)
if cust:
ret = {'customer': cust and cust[0][0] or '', 'customer_name': cust and cust[0][1] or ''}
return ret
def get_customer_details(self):
- cust = sql("select customer_name from `tabCustomer` where name=%s", self.doc.customer)
+ cust = webnotes.conn.sql("select customer_name from `tabCustomer` where name=%s", self.doc.customer)
if cust:
ret = {'customer_name': cust and cust[0][0] or ''}
return ret
diff --git a/projects/doctype/task/task.txt b/projects/doctype/task/task.txt
index d890bd67b94..1c12c8a534f 100644
--- a/projects/doctype/task/task.txt
+++ b/projects/doctype/task/task.txt
@@ -2,12 +2,13 @@
{
"creation": "2013-01-29 19:25:50",
"docstatus": 0,
- "modified": "2013-07-05 14:57:57",
+ "modified": "2013-10-02 14:25:00",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"allow_attach": 1,
+ "allow_import": 1,
"autoname": "TASK.#####",
"doctype": "DocType",
"document_type": "Master",
diff --git a/projects/doctype/time_log_batch/test_time_log_batch.py b/projects/doctype/time_log_batch/test_time_log_batch.py
index 34a0cc06c9f..4976dfe46da 100644
--- a/projects/doctype/time_log_batch/test_time_log_batch.py
+++ b/projects/doctype/time_log_batch/test_time_log_batch.py
@@ -5,15 +5,31 @@ import webnotes, unittest
class TimeLogBatchTest(unittest.TestCase):
def test_time_log_status(self):
- self.assertEquals(webnotes.conn.get_value("Time Log", "_T-Time Log-00001", "status"), "Submitted")
- tlb = webnotes.bean("Time Log Batch", "_T-Time Log Batch-00001")
+ from projects.doctype.time_log.test_time_log import test_records as time_log_records
+ time_log = webnotes.bean(copy=time_log_records[0])
+ time_log.doc.fields.update({
+ "from_time": "2013-01-02 10:00:00",
+ "to_time": "2013-01-02 11:00:00",
+ "docstatus": 0
+ })
+ time_log.insert()
+ time_log.submit()
+
+ self.assertEquals(webnotes.conn.get_value("Time Log", time_log.doc.name, "status"), "Submitted")
+ tlb = webnotes.bean(copy=test_records[0])
+ tlb.doclist[1].time_log = time_log.doc.name
+ tlb.insert()
tlb.submit()
- self.assertEquals(webnotes.conn.get_value("Time Log", "_T-Time Log-00001", "status"), "Batched for Billing")
+
+ self.assertEquals(webnotes.conn.get_value("Time Log", time_log.doc.name, "status"), "Batched for Billing")
tlb.cancel()
- self.assertEquals(webnotes.conn.get_value("Time Log", "_T-Time Log-00001", "status"), "Submitted")
+ self.assertEquals(webnotes.conn.get_value("Time Log", time_log.doc.name, "status"), "Submitted")
test_records = [[
- {"rate": "500"},
+ {
+ "doctype": "Time Log Batch",
+ "rate": "500"
+ },
{
"doctype": "Time Log Batch Detail",
"parenttype": "Time Log Batch",
diff --git a/public/js/complete_setup.js b/public/js/complete_setup.js
deleted file mode 100644
index eeb39d60d59..00000000000
--- a/public/js/complete_setup.js
+++ /dev/null
@@ -1,126 +0,0 @@
-// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
-// License: GNU General Public License v3. See license.txt
-
-// complete my company registration
-// --------------------------------
-wn.provide('erpnext.complete_setup');
-
-$.extend(erpnext.complete_setup, {
- show: function() {
- d = erpnext.complete_setup.prepare_dialog();
- d.show();
- },
-
- prepare_dialog: function() {
- var d = new wn.ui.Dialog({
- title: "Setup",
- fields: [
- {fieldname:'first_name', label:wn._('Your First Name'), fieldtype:'Data', reqd: 1},
- {fieldname:'last_name', label: wn._('Your Last Name'), fieldtype:'Data'},
- {fieldname:'company_name', label:wn._('Company Name'), fieldtype:'Data', reqd:1,
- description: wn._('e.g. "My Company LLC"')},
- {fieldname:'company_abbr', label:wn._('Company Abbreviation'), fieldtype:'Data',
- description:wn._('e.g. "MC"'),reqd:1},
- {fieldname:'fy_start', label:wn._('Financial Year Start Date'), fieldtype:'Select',
- description:wn._('Your financial year begins on"'), reqd:1,
- options: erpnext.complete_setup.fy_start_list.join('\n')},
- {fieldname:'country', label: wn._('Country'), reqd:1,
- options: "", fieldtype: 'Select'},
- {fieldname:'currency', label: wn._('Default Currency'), reqd:1,
- options: "", fieldtype: 'Select'},
- {fieldname:'timezone', label: wn._('Time Zone'), reqd:1,
- options: "", fieldtype: 'Select'},
- {fieldname:'industry', label: wn._('Industry'), reqd:1,
- options: erpnext.complete_setup.domains.join('\n'), fieldtype: 'Select'},
- {fieldname:'update', label:wn._('Setup'),fieldtype:'Button'},
- ],
- });
-
- if(user != 'Administrator'){
- d.$wrapper.find('.close').toggle(false); // Hide close image
- $('header').toggle(false); // hide toolbar
- }
-
- wn.call({
- method:"webnotes.country_info.get_country_timezone_info",
- callback: function(data) {
- erpnext.country_info = data.message.country_info;
- erpnext.all_timezones = data.message.all_timezones;
- d.get_input("country").empty()
- .add_options([""].concat(keys(erpnext.country_info).sort()));
- d.get_input("currency").empty()
- .add_options(wn.utils.unique([""].concat($.map(erpnext.country_info,
- function(opts, country) { return opts.currency; }))).sort());
- d.get_input("timezone").empty()
- .add_options([""].concat(erpnext.all_timezones));
- }
- })
-
- // on clicking update
- d.fields_dict.update.input.onclick = function() {
- var data = d.get_values();
- if(!data) return;
- $(this).set_working();
- return $c_obj('Setup Control','setup_account',data,function(r, rt){
- $(this).done_working();
- if(!r.exc) {
- sys_defaults = r.message;
- user_fullname = r.message.user_fullname;
- wn.boot.user_info[user].fullname = user_fullname;
- d.hide();
- $('header').toggle(true);
- wn.container.wntoolbar.set_user_name();
-
- setTimeout(function() { window.location.reload(); }, 3000);
- }
- });
- };
-
- d.fields_dict.company_name.input.onchange = function() {
- var parts = d.get_input("company_name").val().split(" ");
- var abbr = $.map(parts, function(p) { return p ? p.substr(0,1) : null }).join("");
- d.get_input("company_abbr").val(abbr.toUpperCase());
- }
-
- d.fields_dict.country.input.onchange = function() {
- var country = d.fields_dict.country.input.value;
- var $timezone = $(d.fields_dict.timezone.input);
- $timezone.empty();
- // add country specific timezones first
- if(country){
- var timezone_list = erpnext.country_info[country].timezones || [];
- $timezone.add_options(timezone_list.sort());
-
- d.get_input("currency").val(erpnext.country_info[country].currency);
- }
- // add all timezones at the end, so that user has the option to change it to any timezone
- $timezone.add_options([""].concat(erpnext.all_timezones));
-
- };
-
- // company name already set
- if(wn.control_panel.company_name) {
- var inp = d.fields_dict.company_name.input;
- inp.value = wn.control_panel.company_name;
- inp.disabled = true;
- d.fields_dict.company_name.$input.trigger("change");
- }
-
- // set first name, last name
- if(user_fullname) {
- u = user_fullname.split(' ');
- if(u[0]) {
- d.fields_dict.first_name.input.value = u[0];
- }
- if(u[1]) {
- d.fields_dict.last_name.input.value = u[1];
- }
- }
-
- return d;
- },
-
- fy_start_list: ['', '1st Jan', '1st Apr', '1st Jul', '1st Oct'],
-
- domains: ['', "Manufacturing", "Retail", "Distribution", "Services", "Other"],
-});
\ No newline at end of file
diff --git a/public/js/controllers/accounts.js b/public/js/controllers/accounts.js
new file mode 100644
index 00000000000..201c47e2bb5
--- /dev/null
+++ b/public/js/controllers/accounts.js
@@ -0,0 +1,18 @@
+
+// get tax rate
+cur_frm.cscript.account_head = function(doc, cdt, cdn) {
+ var d = locals[cdt][cdn];
+ if(!d.charge_type && d.account_head){
+ msgprint("Please select Charge Type first");
+ wn.model.set_value(cdt, cdn, "account_head", "");
+ } else if(d.account_head && d.charge_type!=="Actual") {
+ wn.call({
+ type:"GET",
+ method: "controllers.accounts_controller.get_tax_rate",
+ args: {"account_head":d.account_head},
+ callback: function(r) {
+ wn.model.set_value(cdt, cdn, "rate", r.message || 0);
+ }
+ })
+ }
+}
diff --git a/public/js/startup.css b/public/js/startup.css
index ab70ee44147..c3b7276de4e 100644
--- a/public/js/startup.css
+++ b/public/js/startup.css
@@ -29,4 +29,21 @@ span, div, td, input, textarea, button, select {
width: 32px;
height: 32px;
margin: -10px auto;
+}
+
+/* pos */
+.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/public/js/startup.js b/public/js/startup.js
index 7d5792afb5f..76b77148877 100644
--- a/public/js/startup.js
+++ b/public/js/startup.js
@@ -9,25 +9,10 @@ erpnext.startup.start = function() {
console.log(wn._('Starting up...'));
$('#startup_div').html('Starting up...').toggle(true);
- if(user != 'Guest'){
- // setup toolbar
- erpnext.toolbar.setup();
-
- // complete registration
- if(in_list(user_roles,'System Manager') && (wn.boot.setup_complete==='No')) {
- wn.require("app/js/complete_setup.js");
- erpnext.complete_setup.show();
- } else if(!wn.boot.customer_count) {
- if(wn.get_route()[0]!=="Setup") {
- msgprint(""
- + wn._("Proceed to Setup") + "\
-
"+
- wn._("This message goes away after you create your first customer.")+
- "
", wn._("Welcome"));
- }
- } else if(wn.boot.expires_on && in_list(user_roles, 'System Manager')) {
- erpnext.startup.show_expiry_banner();
- }
+ erpnext.toolbar.setup();
+
+ if(wn.boot.expires_on && in_list(user_roles, 'System Manager')) {
+ erpnext.startup.show_expiry_banner();
}
}
diff --git a/public/js/stock_grid_report.js b/public/js/stock_grid_report.js
index 8b79b5e1eea..495ea43e405 100644
--- a/public/js/stock_grid_report.js
+++ b/public/js/stock_grid_report.js
@@ -28,7 +28,7 @@ erpnext.StockGridReport = wn.views.TreeGridReport.extend({
var value_diff = (rate * add_qty);
if(add_qty)
- wh.fifo_stack.push([add_qty, sl.incoming_rate, sl.posting_date]);
+ wh.fifo_stack.push([add_qty, sl.incoming_rate, sl.posting_date]);
} else {
// outgoing
if(sl.serial_no) {
@@ -98,7 +98,7 @@ erpnext.StockGridReport = wn.views.TreeGridReport.extend({
$.each(sl.serial_no.trim().split("\n"), function(i, sr) {
if(sr) {
- value_diff += flt(me.serialized_buying_rates[sr.trim()]);
+ value_diff += flt(me.serialized_buying_rates[sr.trim().toLowerCase()]);
}
});
@@ -111,8 +111,9 @@ erpnext.StockGridReport = wn.views.TreeGridReport.extend({
$.each(wn.report_dump.data["Stock Ledger Entry"], function(i, sle) {
if(sle.qty > 0 && sle.serial_no) {
$.each(sle.serial_no.trim().split("\n"), function(i, sr) {
- if(sr && sle.incoming_rate !== undefined) {
- serialized_buying_rates[sr.trim()] = flt(sle.incoming_rate);
+ if(sr && sle.incoming_rate !== undefined
+ && !serialized_buying_rates[sr.trim().toLowerCase()]) {
+ serialized_buying_rates[sr.trim().toLowerCase()] = flt(sle.incoming_rate);
}
});
}
diff --git a/public/js/transaction.js b/public/js/transaction.js
index 3080ba17210..db93e9fde60 100644
--- a/public/js/transaction.js
+++ b/public/js/transaction.js
@@ -21,8 +21,6 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
company: wn.defaults.get_default("company"),
fiscal_year: wn.defaults.get_default("fiscal_year"),
is_subcontracted: "No",
- conversion_rate: 1.0,
- plc_conversion_rate: 1.0
}, function(fieldname, value) {
if(me.frm.fields_dict[fieldname] && !me.frm.doc[fieldname])
me.frm.set_value(fieldname, value);
@@ -41,18 +39,19 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
},
onload_post_render: function() {
- if(this.frm.doc.__islocal && this.frm.doc.company && !this.frm.doc.customer) {
- var me = this;
- return this.frm.call({
- doc: this.frm.doc,
- method: "onload_post_render",
- freeze: true,
- callback: function(r) {
- // remove this call when using client side mapper
- me.set_default_values();
- me.set_dynamic_labels();
- }
- });
+ if(this.frm.doc.__islocal && this.frm.doc.company &&
+ !this.frm.doc.customer && !this.frm.doc.is_pos) {
+ var me = this;
+ return this.frm.call({
+ doc: this.frm.doc,
+ method: "onload_post_render",
+ freeze: true,
+ callback: function(r) {
+ // remove this call when using client side mapper
+ me.set_default_values();
+ me.set_dynamic_labels();
+ }
+ });
}
},
@@ -62,6 +61,56 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
erpnext.hide_company();
this.show_item_wise_taxes();
this.set_dynamic_labels();
+
+ // Show POS button only if it is enabled from features setup
+ if(cint(sys_defaults.fs_pos_view)===1 && this.frm.doctype!="Material Request")
+ this.pos_btn();
+ },
+
+ pos_btn: function() {
+ if(this.$pos_btn)
+ this.$pos_btn.remove();
+
+ if(!this.pos_active) {
+ var btn_label = wn._("POS View"),
+ icon = "icon-desktop";
+ } else {
+ var btn_label = wn._(this.frm.doctype) + wn._(" View"),
+ icon = "icon-file-text";
+ }
+ var me = this;
+
+ this.$pos_btn = this.frm.add_custom_button(btn_label, function() {
+ me.toggle_pos();
+ me.pos_btn();
+ }, icon);
+ },
+
+ toggle_pos: function(show) {
+ // Check whether it is Selling or Buying cycle
+ var price_list = wn.meta.has_field(cur_frm.doc.doctype, "selling_price_list") ?
+ this.frm.doc.selling_price_list : this.frm.doc.buying_price_list;
+
+ if (!price_list)
+ msgprint(wn._("Please select Price List"))
+ else {
+ if((show===true && this.pos_active) || (show===false && !this.pos_active)) return;
+
+ // make pos
+ if(!this.frm.pos) {
+ this.frm.layout.add_view("pos");
+ this.frm.pos = new erpnext.POS(this.frm.layout.views.pos, this.frm);
+ }
+
+ // toggle view
+ this.frm.layout.set_view(this.pos_active ? "" : "pos");
+ this.pos_active = !this.pos_active;
+
+ // refresh
+ if(this.pos_active)
+ this.frm.pos.refresh();
+ this.frm.refresh();
+ }
},
validate: function() {
@@ -81,10 +130,18 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
company: function() {
if(this.frm.doc.company && this.frm.fields_dict.currency) {
- if(!this.frm.doc.currency) {
- this.frm.set_value("currency", this.get_company_currency());
+ var company_currency = this.get_company_currency();
+ if (!this.frm.doc.currency) {
+ this.frm.set_value("currency", company_currency);
}
+ if (this.frm.doc.currency == company_currency) {
+ this.frm.set_value("conversion_rate", 1.0);
+ }
+ if (this.frm.doc.price_list_currency == company_currency) {
+ this.frm.set_value('plc_conversion_rate', 1.0);
+ }
+
this.frm.script_manager.trigger("currency");
}
},
@@ -96,15 +153,13 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
currency: function() {
var me = this;
this.set_dynamic_labels();
-
+
var company_currency = this.get_company_currency();
if(this.frm.doc.currency !== company_currency) {
this.get_exchange_rate(this.frm.doc.currency, company_currency,
function(exchange_rate) {
- if(exchange_rate) {
- me.frm.set_value("conversion_rate", exchange_rate);
- me.conversion_rate();
- }
+ me.frm.set_value("conversion_rate", exchange_rate);
+ me.conversion_rate();
});
} else {
this.conversion_rate();
@@ -118,7 +173,7 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
this.frm.doc.plc_conversion_rate !== this.frm.doc.conversion_rate) {
this.frm.set_value("plc_conversion_rate", this.frm.doc.conversion_rate);
}
-
+
this.calculate_taxes_and_totals();
},
@@ -182,7 +237,7 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
tax_rate: function(doc, cdt, cdn) {
this.calculate_taxes_and_totals();
},
-
+
row_id: function(doc, cdt, cdn) {
var tax = wn.model.get_doc(cdt, cdn);
try {
@@ -413,15 +468,11 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
}
var company_currency = this.get_company_currency();
- var valid_conversion_rate = this.frm.doc.conversion_rate ?
- ((this.frm.doc.currency == company_currency && this.frm.doc.conversion_rate == 1.0) ||
- (this.frm.doc.currency != company_currency && this.frm.doc.conversion_rate != 1.0)) :
- false;
- // if(!valid_conversion_rate) {
- // wn.throw(wn._("Please enter valid") + " " + wn._(conversion_rate_label) +
- // " 1 " + this.frm.doc.currency + " = [?] " + company_currency);
- // }
+ if(!this.frm.doc.conversion_rate) {
+ wn.throw(wn._("Please enter valid") + " " + wn._(conversion_rate_label) +
+ " 1 " + this.frm.doc.currency + " = [?] " + company_currency);
+ }
},
calculate_taxes_and_totals: function() {
diff --git a/public/js/utils.js b/public/js/utils.js
index a8df11e9337..e14a54c4a82 100644
--- a/public/js/utils.js
+++ b/public/js/utils.js
@@ -20,7 +20,7 @@ $.extend(erpnext, {
hide_company: function() {
if(cur_frm.fields_dict.company) {
- var companies = Object.keys(locals[":Company"]);
+ var companies = Object.keys(locals[":Company"] || {});
if(companies.length === 1) {
if(!cur_frm.doc.company) cur_frm.set_value("company", companies[0]);
cur_frm.toggle_display("company", false);
diff --git a/selling/doctype/customer/customer.js b/selling/doctype/customer/customer.js
index 2b0e877360a..ef02d4668d5 100644
--- a/selling/doctype/customer/customer.js
+++ b/selling/doctype/customer/customer.js
@@ -34,7 +34,6 @@ cur_frm.cscript.refresh = function(doc,dt,dn) {
cur_frm.cscript.make_contact(doc,dt,dn);
cur_frm.communication_view = new wn.views.CommunicationList({
- list: wn.model.get("Communication", {"customer": doc.name}),
parent: cur_frm.fields_dict.communication_html.wrapper,
doc: doc,
});
@@ -45,7 +44,7 @@ cur_frm.cscript.setup_dashboard = function(doc) {
cur_frm.dashboard.reset(doc);
if(doc.__islocal)
return;
- cur_frm.dashboard.set_headline('Loading...')
+ cur_frm.dashboard.set_headline(''+ wn._('Loading...')+ '')
cur_frm.dashboard.add_doctype_badge("Opportunity", "customer");
cur_frm.dashboard.add_doctype_badge("Quotation", "customer");
@@ -119,4 +118,4 @@ cur_frm.fields_dict.lead_name.get_query = function(doc,cdt,cdn) {
return{
query:"controllers.queries.lead_query"
}
-}
\ No newline at end of file
+}
diff --git a/selling/doctype/customer/customer.py b/selling/doctype/customer/customer.py
index 2b57da972c8..18c8a34d8cd 100644
--- a/selling/doctype/customer/customer.py
+++ b/selling/doctype/customer/customer.py
@@ -9,7 +9,6 @@ from webnotes.model.doc import Document, make_autoname
from webnotes import msgprint, _
import webnotes.defaults
-sql = webnotes.conn.sql
from utilities.transaction_base import TransactionBase
@@ -31,7 +30,7 @@ class DocType(TransactionBase):
return webnotes.conn.get_value('Company', self.doc.company, 'abbr')
def get_receivables_group(self):
- g = sql("select receivables_group from tabCompany where name=%s", self.doc.company)
+ g = webnotes.conn.sql("select receivables_group from tabCompany where name=%s", self.doc.company)
g = g and g[0][0] or ''
if not g:
msgprint("Update Company master, assign a default group for Receivables")
@@ -47,7 +46,7 @@ class DocType(TransactionBase):
def update_lead_status(self):
if self.doc.lead_name:
- sql("update `tabLead` set status='Converted' where name = %s", self.doc.lead_name)
+ webnotes.conn.sql("update `tabLead` set status='Converted' where name = %s", self.doc.lead_name)
def create_account_head(self):
if self.doc.company :
@@ -132,7 +131,7 @@ class DocType(TransactionBase):
def delete_customer_account(self):
"""delete customer's ledger if exist and check balance before deletion"""
- acc = sql("select name from `tabAccount` where master_type = 'Customer' \
+ acc = webnotes.conn.sql("select name from `tabAccount` where master_type = 'Customer' \
and master_name = %s and docstatus < 2", self.doc.name)
if acc:
from webnotes.model import delete_doc
@@ -143,7 +142,7 @@ class DocType(TransactionBase):
self.delete_customer_contact()
self.delete_customer_account()
if self.doc.lead_name:
- sql("update `tabLead` set status='Interested' where name=%s",self.doc.lead_name)
+ webnotes.conn.sql("update `tabLead` set status='Interested' where name=%s",self.doc.lead_name)
def on_rename(self, new, old, merge=False):
#update customer_name if not naming series
diff --git a/selling/doctype/customer/test_customer.py b/selling/doctype/customer/test_customer.py
index 7c90f6a1a8f..adc5a549ef9 100644
--- a/selling/doctype/customer/test_customer.py
+++ b/selling/doctype/customer/test_customer.py
@@ -17,6 +17,8 @@ class TestCustomer(unittest.TestCase):
(("_Test Customer 1 Renamed",),))
self.assertEqual(webnotes.conn.exists("Customer", "_Test Customer 1"), ())
+ webnotes.rename_doc("Customer", "_Test Customer 1 Renamed", "_Test Customer 1")
+
def test_merge(self):
from webnotes.test_runner import make_test_records
make_test_records("Sales Invoice")
@@ -57,6 +59,9 @@ class TestCustomer(unittest.TestCase):
# check that old name doesn't exist
self.assertEqual(webnotes.conn.exists("Customer", "_Test Customer"), ())
self.assertEqual(webnotes.conn.exists("Account", "_Test Customer - _TC"), ())
+
+ # create back _Test Customer
+ webnotes.bean(copy=test_records[0]).insert()
test_ignore = ["Price List"]
diff --git a/selling/doctype/installation_note/installation_note.py b/selling/doctype/installation_note/installation_note.py
index ca47043e28c..02b724719c1 100644
--- a/selling/doctype/installation_note/installation_note.py
+++ b/selling/doctype/installation_note/installation_note.py
@@ -38,7 +38,6 @@ class DocType(TransactionBase):
self.check_item_table()
sales_com_obj = get_obj(dt = 'Sales Common')
sales_com_obj.check_active_sales_items(self)
- sales_com_obj.get_prevdoc_date(self)
def validate_fiscal_year(self):
from accounts.utils import validate_fiscal_year
diff --git a/selling/doctype/installation_note_item/installation_note_item.txt b/selling/doctype/installation_note_item/installation_note_item.txt
index 02871ad7343..7435d461b41 100644
--- a/selling/doctype/installation_note_item/installation_note_item.txt
+++ b/selling/doctype/installation_note_item/installation_note_item.txt
@@ -2,7 +2,7 @@
{
"creation": "2013-02-22 01:27:51",
"docstatus": 0,
- "modified": "2013-07-10 14:54:09",
+ "modified": "2013-10-10 17:02:31",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -48,18 +48,6 @@
"read_only": 1,
"width": "300px"
},
- {
- "doctype": "DocField",
- "fieldname": "prevdoc_date",
- "fieldtype": "Date",
- "hidden": 0,
- "in_list_view": 1,
- "label": "Delivery Date",
- "oldfieldname": "prevdoc_date",
- "oldfieldtype": "Date",
- "print_hide": 0,
- "read_only": 1
- },
{
"doctype": "DocField",
"fieldname": "serial_no",
diff --git a/selling/doctype/lead/get_leads.py b/selling/doctype/lead/get_leads.py
index 3305a3b9f6e..eaf837bb5be 100644
--- a/selling/doctype/lead/get_leads.py
+++ b/selling/doctype/lead/get_leads.py
@@ -29,7 +29,7 @@ def add_sales_communication(subject, content, sender, real_name, mail=None,
parent_name = contact_name or lead_name
message = make(content=content, sender=sender, subject=subject,
- doctype = parent_doctype, name = parent_name, date=date)
+ doctype = parent_doctype, name = parent_name, date=date, sent_or_received="Received")
if mail:
# save attachments to parent if from mail
diff --git a/selling/doctype/lead/lead.js b/selling/doctype/lead/lead.js
index 8f5057d2853..9f6412cfd17 100644
--- a/selling/doctype/lead/lead.js
+++ b/selling/doctype/lead/lead.js
@@ -33,7 +33,7 @@ erpnext.LeadController = wn.ui.form.Controller.extend({
var doc = this.frm.doc;
erpnext.hide_naming_series();
this.frm.clear_custom_buttons();
-
+
this.frm.__is_customer = this.frm.__is_customer || this.frm.doc.__is_customer;
if(!this.frm.doc.__islocal && !this.frm.__is_customer) {
this.frm.add_custom_button(wn._("Create Customer"), this.create_customer);
diff --git a/selling/doctype/lead/lead.py b/selling/doctype/lead/lead.py
index 316481cbaa7..a33ae3587fe 100644
--- a/selling/doctype/lead/lead.py
+++ b/selling/doctype/lead/lead.py
@@ -7,7 +7,6 @@ from webnotes import _
from webnotes.utils import cstr, validate_email_add, cint, extract_email_id
from webnotes import session, msgprint
-sql = webnotes.conn.sql
from controllers.selling_controller import SellingController
@@ -27,24 +26,9 @@ class DocType(SellingController):
customer = webnotes.conn.get_value("Customer", {"lead_name": self.doc.name})
if customer:
self.doc.fields["__is_customer"] = customer
-
- def on_communication(self, comm):
- if comm.sender == self.get_sender(comm) or \
- webnotes.conn.get_value("Profile", extract_email_id(comm.sender), "user_type")=="System User":
- status = "Replied"
- else:
- status = "Open"
-
- webnotes.conn.set(self.doc, 'status', status)
-
- def check_status(self):
- chk = sql("select status from `tabLead` where name=%s", self.doc.name)
- chk = chk and chk[0][0] or ''
- return cstr(chk)
def validate(self):
- if self.doc.status == 'Lead Lost' and not self.doc.order_lost_reason:
- webnotes.throw("Please Enter Lost Reason under More Info section")
+ self.set_status()
if self.doc.source == 'Campaign' and not self.doc.campaign_name and session['user'] != 'Guest':
webnotes.throw("Please specify campaign name")
@@ -76,14 +60,18 @@ class DocType(SellingController):
webnotes.msgprint(_("""Email Id must be unique, already exists for: """) + \
", ".join(items), raise_exception=True)
- def get_sender(self, comm):
- return webnotes.conn.get_value('Sales Email Settings',None,'email_id')
-
def on_trash(self):
webnotes.conn.sql("""update `tabSupport Ticket` set lead='' where lead=%s""",
self.doc.name)
self.delete_events()
+
+ def has_customer(self):
+ return webnotes.conn.get_value("Customer", {"lead_name": self.doc.name})
+
+ def has_opportunity(self):
+ return webnotes.conn.get_value("Opportunity", {"lead": self.doc.name, "docstatus": 1,
+ "status": ["!=", "Lost"]})
@webnotes.whitelist()
def make_customer(source_name, target_doclist=None):
@@ -133,4 +121,4 @@ def make_opportunity(source_name, target_doclist=None):
}
}}, target_doclist)
- return [d.fields for d in doclist]
\ No newline at end of file
+ return [d if isinstance(d, dict) else d.fields for d in doclist]
\ No newline at end of file
diff --git a/selling/doctype/lead/lead.txt b/selling/doctype/lead/lead.txt
index 408ad451250..b700a2e1464 100644
--- a/selling/doctype/lead/lead.txt
+++ b/selling/doctype/lead/lead.txt
@@ -2,11 +2,12 @@
{
"creation": "2013-04-10 11:45:37",
"docstatus": 0,
- "modified": "2013-09-26 16:30:36",
+ "modified": "2013-10-09 15:27:54",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
+ "allow_import": 1,
"autoname": "naming_series:",
"doctype": "DocType",
"document_type": "Master",
@@ -101,7 +102,7 @@
"fieldtype": "Column Break"
},
{
- "default": "Open",
+ "default": "Lead",
"doctype": "DocField",
"fieldname": "status",
"fieldtype": "Select",
@@ -111,7 +112,7 @@
"no_copy": 1,
"oldfieldname": "status",
"oldfieldtype": "Select",
- "options": "\nOpen\nReplied\nAttempted to Contact\nContact in Future\nContacted\nOpportunity Made\nInterested\nNot interested\nLead Lost\nConverted\nPassive",
+ "options": "Lead\nOpen\nReplied\nOpportunity\nInterested\nConverted\nDo Not Contact",
"reqd": 1,
"search_index": 1
},
@@ -174,19 +175,6 @@
"options": "Profile",
"search_index": 1
},
- {
- "depends_on": "eval:!doc.__islocal",
- "description": "Date on which the lead was last contacted",
- "doctype": "DocField",
- "fieldname": "last_contact_date",
- "fieldtype": "Date",
- "label": "Last Contact Date",
- "no_copy": 1,
- "oldfieldname": "last_contact_date",
- "oldfieldtype": "Date",
- "print_hide": 1,
- "read_only": 1
- },
{
"doctype": "DocField",
"fieldname": "col_break123",
@@ -236,8 +224,7 @@
"fieldtype": "HTML",
"label": "Communication HTML",
"oldfieldname": "follow_up",
- "oldfieldtype": "Table",
- "print_hide": 1
+ "oldfieldtype": "Table"
},
{
"doctype": "DocField",
@@ -390,18 +377,6 @@
"oldfieldtype": "Column Break",
"width": "50%"
},
- {
- "allow_on_submit": 0,
- "depends_on": "eval:doc.status == 'Lead Lost'",
- "doctype": "DocField",
- "fieldname": "order_lost_reason",
- "fieldtype": "Link",
- "hidden": 0,
- "label": "Lost Reason",
- "oldfieldname": "order_lost_reason",
- "oldfieldtype": "Link",
- "options": "Quotation Lost Reason"
- },
{
"doctype": "DocField",
"fieldname": "company",
@@ -430,8 +405,7 @@
"fieldtype": "Table",
"hidden": 1,
"label": "Communications",
- "options": "Communication",
- "print_hide": 1
+ "options": "Communication"
},
{
"cancel": 1,
diff --git a/selling/doctype/opportunity/opportunity.js b/selling/doctype/opportunity/opportunity.js
index 8b8fbf3866a..e65ef509510 100644
--- a/selling/doctype/opportunity/opportunity.js
+++ b/selling/doctype/opportunity/opportunity.js
@@ -101,21 +101,21 @@ $.extend(cur_frm.cscript, new erpnext.selling.Opportunity({frm: cur_frm}));
cur_frm.cscript.refresh = function(doc, cdt, cdn){
erpnext.hide_naming_series();
-
- cur_frm.dashboard.reset(doc);
- if(!doc.__islocal) {
- if(doc.status=="Converted" || doc.status=="Order Confirmed") {
- cur_frm.dashboard.set_headline_alert(wn._(doc.status), "alert-success", "icon-ok-sign");
- } else if(doc.status=="Opportunity Lost") {
- cur_frm.dashboard.set_headline_alert(wn._(doc.status), "alert-danger", "icon-exclamation-sign");
- }
- }
cur_frm.clear_custom_buttons();
+<<<<<<< HEAD
if(doc.docstatus === 1 && doc.status!=="Opportunity Lost") {
cur_frm.add_custom_button( wn._('Create Quotation'), cur_frm.cscript.create_quotation);
cur_frm.add_custom_button(wn._('Opportunity Lost'), cur_frm.cscript['Declare Opportunity Lost']);
cur_frm.add_custom_button(wn._('Send SMS'), cur_frm.cscript.send_sms);
+=======
+ if(doc.docstatus === 1 && doc.status!=="Lost") {
+ cur_frm.add_custom_button('Create Quotation', cur_frm.cscript.create_quotation);
+ if(doc.status!=="Quotation") {
+ cur_frm.add_custom_button('Opportunity Lost', cur_frm.cscript['Declare Opportunity Lost']);
+ }
+ cur_frm.add_custom_button('Send SMS', cur_frm.cscript.send_sms);
+>>>>>>> f146e8b7f52a3e46e335c0fefd92c347717b370b
}
cur_frm.toggle_display("contact_info", doc.customer || doc.lead);
diff --git a/selling/doctype/opportunity/opportunity.py b/selling/doctype/opportunity/opportunity.py
index c8c41e3f39d..37672f2afb2 100644
--- a/selling/doctype/opportunity/opportunity.py
+++ b/selling/doctype/opportunity/opportunity.py
@@ -4,11 +4,10 @@
from __future__ import unicode_literals
import webnotes
-from webnotes.utils import cstr, getdate, cint
+from webnotes.utils import cstr, cint
from webnotes.model.bean import getlist
-from webnotes import msgprint
+from webnotes import msgprint, _
-sql = webnotes.conn.sql
from utilities.transaction_base import TransactionBase
@@ -18,7 +17,7 @@ class DocType(TransactionBase):
self.doclist = doclist
self.fname = 'enq_details'
self.tname = 'Opportunity Item'
-
+
self._prev = webnotes._dict({
"contact_date": webnotes.conn.get_value("Opportunity", self.doc.name, "contact_date") if \
(not cint(self.doc.fields.get("__islocal"))) else None,
@@ -27,7 +26,7 @@ class DocType(TransactionBase):
})
def get_item_details(self, item_code):
- item = sql("""select item_name, stock_uom, description_html, description, item_group, brand
+ item = webnotes.conn.sql("""select item_name, stock_uom, description_html, description, item_group, brand
from `tabItem` where name = %s""", item_code, as_dict=1)
ret = {
'item_name': item and item[0]['item_name'] or '',
@@ -39,7 +38,7 @@ class DocType(TransactionBase):
return ret
def get_cust_address(self,name):
- details = sql("select customer_name, address, territory, customer_group from `tabCustomer` where name = '%s' and docstatus != 2" %(name), as_dict = 1)
+ details = webnotes.conn.sql("select customer_name, address, territory, customer_group from `tabCustomer` where name = '%s' and docstatus != 2" %(name), as_dict = 1)
if details:
ret = {
'customer_name': details and details[0]['customer_name'] or '',
@@ -49,7 +48,7 @@ class DocType(TransactionBase):
}
# ********** get primary contact details (this is done separately coz. , in case there is no primary contact thn it would not be able to fetch customer details in case of join query)
- contact_det = sql("select contact_name, contact_no, email_id from `tabContact` where customer = '%s' and is_customer = 1 and is_primary_contact = 'Yes' and docstatus != 2" %(name), as_dict = 1)
+ contact_det = webnotes.conn.sql("select contact_name, contact_no, email_id from `tabContact` where customer = '%s' and is_customer = 1 and is_primary_contact = 'Yes' and docstatus != 2" %(name), as_dict = 1)
ret['contact_person'] = contact_det and contact_det[0]['contact_name'] or ''
ret['contact_no'] = contact_det and contact_det[0]['contact_no'] or ''
@@ -62,18 +61,15 @@ class DocType(TransactionBase):
def get_contact_details(self, arg):
arg = eval(arg)
- contact = sql("select contact_no, email_id from `tabContact` where contact_name = '%s' and customer_name = '%s'" %(arg['contact_person'],arg['customer']), as_dict = 1)
+ contact = webnotes.conn.sql("select contact_no, email_id from `tabContact` where contact_name = '%s' and customer_name = '%s'" %(arg['contact_person'],arg['customer']), as_dict = 1)
ret = {
'contact_no' : contact and contact[0]['contact_no'] or '',
'email_id' : contact and contact[0]['email_id'] or ''
}
return ret
-
+
+
def on_update(self):
- # Add to calendar
- if self.doc.contact_date and self.doc.contact_date_ref != self.doc.contact_date:
- webnotes.conn.set(self.doc, 'contact_date_ref',self.doc.contact_date)
-
self.add_calendar_event()
def add_calendar_event(self, opts=None, force=False):
@@ -101,14 +97,6 @@ class DocType(TransactionBase):
super(DocType, self).add_calendar_event(opts, force)
- def set_last_contact_date(self):
- if self.doc.contact_date_ref and self.doc.contact_date_ref != self.doc.contact_date:
- if getdate(self.doc.contact_date_ref) < getdate(self.doc.contact_date):
- self.doc.last_contact_date=self.doc.contact_date_ref
- else:
- msgprint("Contact Date Cannot be before Last Contact Date")
- raise Exception
-
def validate_item_details(self):
if not getlist(self.doclist, 'enquiry_details'):
msgprint("Please select items for which enquiry needs to be made")
@@ -121,49 +109,36 @@ class DocType(TransactionBase):
msgprint("Customer is mandatory if 'Opportunity From' is selected as Customer", raise_exception=1)
def validate(self):
- self.set_last_contact_date()
+ self.set_status()
self.validate_item_details()
self.validate_uom_is_integer("uom", "qty")
self.validate_lead_cust()
from accounts.utils import validate_fiscal_year
validate_fiscal_year(self.doc.transaction_date, self.doc.fiscal_year, "Opportunity Date")
- self.doc.status = "Draft"
def on_submit(self):
- webnotes.conn.set(self.doc, 'status', 'Submitted')
- if self.doc.lead and webnotes.conn.get_value("Lead", self.doc.lead, "status")!="Converted":
- webnotes.conn.set_value("Lead", self.doc.lead, "status", "Opportunity Made")
+ if self.doc.lead:
+ webnotes.bean("Lead", self.doc.lead).get_controller().set_status(update=True)
def on_cancel(self):
- chk = sql("select t1.name from `tabQuotation` t1, `tabQuotation Item` t2 where t2.parent = t1.name and t1.docstatus=1 and (t1.status!='Order Lost' and t1.status!='Cancelled') and t2.prevdoc_docname = %s",self.doc.name)
- if chk:
- msgprint("Quotation No. "+cstr(chk[0][0])+" is submitted against this Opportunity. Thus can not be cancelled.")
- raise Exception
- else:
- webnotes.conn.set(self.doc, 'status', 'Cancelled')
- if self.doc.lead and webnotes.conn.get_value("Lead", self.doc.lead,
- "status")!="Converted":
- if webnotes.conn.get_value("Communication", {"parent": self.doc.lead}):
- status = "Contacted"
- else:
- status = "Open"
-
- webnotes.conn.set_value("Lead", self.doc.lead, "status", status)
+ if self.has_quotation():
+ webnotes.throw(_("Cannot Cancel Opportunity as Quotation Exists"))
+ self.set_status(update=True)
def declare_enquiry_lost(self,arg):
- chk = sql("select t1.name from `tabQuotation` t1, `tabQuotation Item` t2 where t2.parent = t1.name and t1.docstatus=1 and (t1.status!='Order Lost' and t1.status!='Cancelled') and t2.prevdoc_docname = %s",self.doc.name)
- if chk:
- msgprint("Quotation No. "+cstr(chk[0][0])+" is submitted against this Opportunity. Thus 'Opportunity Lost' can not be declared against it.")
- raise Exception
- else:
- webnotes.conn.set(self.doc, 'status', 'Opportunity Lost')
+ if not self.has_quotation():
+ webnotes.conn.set(self.doc, 'status', 'Lost')
webnotes.conn.set(self.doc, 'order_lost_reason', arg)
- return 'true'
+ else:
+ webnotes.throw(_("Cannot declare as lost, because Quotation has been made."))
def on_trash(self):
self.delete_events()
+ def has_quotation(self):
+ return webnotes.conn.get_value("Quotation Item", {"prevdoc_docname": self.doc.name, "docstatus": 1})
+
@webnotes.whitelist()
def make_quotation(source_name, target_doclist=None):
from webnotes.model.mapper import get_mapped_doclist
diff --git a/selling/doctype/opportunity/opportunity.txt b/selling/doctype/opportunity/opportunity.txt
index aeedd08bb80..3c860ade845 100644
--- a/selling/doctype/opportunity/opportunity.txt
+++ b/selling/doctype/opportunity/opportunity.txt
@@ -2,11 +2,12 @@
{
"creation": "2013-03-07 18:50:30",
"docstatus": 0,
- "modified": "2013-09-25 19:32:29",
+ "modified": "2013-10-09 15:26:29",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
+ "allow_import": 1,
"autoname": "naming_series:",
"description": "Potential Sales Deal",
"doctype": "DocType",
@@ -125,7 +126,7 @@
"no_copy": 1,
"oldfieldname": "status",
"oldfieldtype": "Select",
- "options": "\nDraft\nSubmitted\nQuotation Sent\nOrder Confirmed\nOpportunity Lost\nCancelled",
+ "options": "Draft\nSubmitted\nQuotation\nLost\nCancelled\nReplied\nOpen",
"read_only": 1,
"reqd": 1
},
@@ -168,7 +169,6 @@
"label": "Communication History",
"oldfieldtype": "Section Break",
"options": "icon-comments",
- "print_hide": 1,
"read_only": 0
},
{
@@ -179,7 +179,6 @@
"label": "Communication HTML",
"oldfieldname": "follow_up",
"oldfieldtype": "Table",
- "print_hide": 1,
"read_only": 0
},
{
@@ -351,18 +350,6 @@
"options": "Campaign",
"read_only": 0
},
- {
- "depends_on": "eval:!doc.__islocal",
- "doctype": "DocField",
- "fieldname": "order_lost_reason",
- "fieldtype": "Small Text",
- "label": "Quotation Lost Reason",
- "no_copy": 1,
- "oldfieldname": "order_lost_reason",
- "oldfieldtype": "Small Text",
- "read_only": 1,
- "report_hide": 0
- },
{
"doctype": "DocField",
"fieldname": "company",
@@ -377,6 +364,15 @@
"reqd": 1,
"search_index": 1
},
+ {
+ "depends_on": "eval:!doc.__islocal",
+ "doctype": "DocField",
+ "fieldname": "order_lost_reason",
+ "fieldtype": "Text",
+ "label": "Lost Reason",
+ "no_copy": 1,
+ "read_only": 1
+ },
{
"doctype": "DocField",
"fieldname": "column_break2",
@@ -408,20 +404,6 @@
"oldfieldtype": "Date",
"read_only": 0
},
- {
- "allow_on_submit": 0,
- "depends_on": "eval:!doc.__islocal",
- "description": "Date on which the lead was last contacted",
- "doctype": "DocField",
- "fieldname": "last_contact_date",
- "fieldtype": "Date",
- "label": "Last Contact Date",
- "no_copy": 1,
- "oldfieldname": "last_contact_date",
- "oldfieldtype": "Date",
- "print_hide": 1,
- "read_only": 1
- },
{
"doctype": "DocField",
"fieldname": "to_discuss",
@@ -450,8 +432,7 @@
"fieldtype": "Table",
"hidden": 1,
"label": "Communications",
- "options": "Communication",
- "print_hide": 1
+ "options": "Communication"
},
{
"doctype": "DocPerm",
diff --git a/selling/doctype/quotation/quotation.js b/selling/doctype/quotation/quotation.js
index 90be81a257f..a104f34e80d 100644
--- a/selling/doctype/quotation/quotation.js
+++ b/selling/doctype/quotation/quotation.js
@@ -11,6 +11,7 @@ cur_frm.cscript.sales_team_fname = "sales_team";
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');
erpnext.selling.QuotationController = erpnext.selling.SellingController.extend({
onload: function(doc, dt, dn) {
@@ -23,20 +24,18 @@ erpnext.selling.QuotationController = erpnext.selling.SellingController.extend({
},
refresh: function(doc, dt, dn) {
this._super(doc, dt, dn);
-
- cur_frm.dashboard.reset(doc);
- if(!doc.__islocal) {
- if(doc.status=="Converted" || doc.status=="Order Confirmed") {
- cur_frm.dashboard.set_headline_alert(wn._(doc.status), "alert-success", "icon-ok-sign");
- } else if(doc.status==="Order Lost") {
- cur_frm.dashboard.set_headline_alert(wn._(doc.status), "alert-danger", "icon-exclamation-sign");
- }
- }
+<<<<<<< HEAD
if(doc.docstatus == 1 && doc.status!=='Order Lost') {
cur_frm.add_custom_button(wn._('Make Sales Order'), cur_frm.cscript['Make Sales Order']);
if(doc.status!=="Order Confirmed") {
cur_frm.add_custom_button(wn._('Set as Lost'), cur_frm.cscript['Declare Order Lost']);
+=======
+ if(doc.docstatus == 1 && doc.status!=='Lost') {
+ cur_frm.add_custom_button('Make Sales Order', cur_frm.cscript['Make Sales Order']);
+ if(doc.status!=="Ordered") {
+ cur_frm.add_custom_button('Set as Lost', cur_frm.cscript['Declare Order Lost']);
+>>>>>>> f146e8b7f52a3e46e335c0fefd92c347717b370b
}
cur_frm.add_custom_button(wn._('Send SMS'), cur_frm.cscript.send_sms);
}
@@ -82,12 +81,12 @@ erpnext.selling.QuotationController = erpnext.selling.SellingController.extend({
},
validate_company_and_party: function(party_field) {
- if(this.frm.doc.quotation_to == "Lead") {
- return true;
- } else if(!this.frm.doc.quotation_to) {
+ if(!this.frm.doc.quotation_to) {
msgprint(wn._("Please select a value for" + " " + wn.meta.get_label(this.frm.doc.doctype,
"quotation_to", this.frm.doc.name)));
return false;
+ } else if (this.frm.doc.quotation_to == "Lead") {
+ return true;
} else {
return this._super(party_field);
}
diff --git a/selling/doctype/quotation/quotation.py b/selling/doctype/quotation/quotation.py
index 44a67fa45cd..78afb97404e 100644
--- a/selling/doctype/quotation/quotation.py
+++ b/selling/doctype/quotation/quotation.py
@@ -4,12 +4,11 @@
from __future__ import unicode_literals
import webnotes
-from webnotes.utils import cstr, getdate
+from webnotes.utils import cstr
from webnotes.model.bean import getlist
from webnotes.model.code import get_obj
from webnotes import _, msgprint
-sql = webnotes.conn.sql
from controllers.selling_controller import SellingController
@@ -48,17 +47,16 @@ class DocType(SellingController):
if not doc.fields.get(r):
doc.fields[r] = res[r]
+
+ def has_sales_order(self):
+ return webnotes.conn.get_value("Sales Order Item", {"prevdoc_docname": self.doc.name, "docstatus": 1})
+
+
# Re-calculates Basic Rate & amount based on Price List Selected
# --------------------------------------------------------------
def get_adj_percent(self, arg=''):
get_obj('Sales Common').get_adj_percent(self)
-
- # Get Tax rate if account type is TAX
- # -----------------------------------
- def get_rate(self,arg):
- return get_obj('Sales Common').get_rate(arg)
-
# Does not allow same item code to be entered twice
# -------------------------------------------------
def validate_for_items(self):
@@ -78,7 +76,7 @@ class DocType(SellingController):
if self.doc.order_type in ['Maintenance', 'Service']:
for d in getlist(self.doclist, 'quotation_details'):
- is_service_item = sql("select is_service_item from `tabItem` where name=%s", d.item_code)
+ is_service_item = webnotes.conn.sql("select is_service_item from `tabItem` where name=%s", d.item_code)
is_service_item = is_service_item and is_service_item[0][0] or 'No'
if is_service_item == 'No':
@@ -86,37 +84,16 @@ class DocType(SellingController):
raise Exception
else:
for d in getlist(self.doclist, 'quotation_details'):
- is_sales_item = sql("select is_sales_item from `tabItem` where name=%s", d.item_code)
+ is_sales_item = webnotes.conn.sql("select is_sales_item from `tabItem` where name=%s", d.item_code)
is_sales_item = is_sales_item and is_sales_item[0][0] or 'No'
if is_sales_item == 'No':
msgprint("You can not select non sales item "+d.item_code+" in Sales Quotation")
raise Exception
- #--------------Validation For Last Contact Date-----------------
- # ====================================================================================================================
- def set_last_contact_date(self):
- #if not self.doc.contact_date_ref:
- #self.doc.contact_date_ref=self.doc.contact_date
- #self.doc.last_contact_date=self.doc.contact_date_ref
- if self.doc.contact_date_ref and self.doc.contact_date_ref != self.doc.contact_date:
- if getdate(self.doc.contact_date_ref) < getdate(self.doc.contact_date):
- self.doc.last_contact_date=self.doc.contact_date_ref
- else:
- msgprint("Contact Date Cannot be before Last Contact Date")
- raise Exception
-
def validate(self):
super(DocType, self).validate()
-
- import utilities
- if not self.doc.status:
- self.doc.status = "Draft"
- else:
- utilities.validate_status(self.doc.status, ["Draft", "Submitted",
- "Order Confirmed", "Order Lost", "Cancelled"])
-
- self.set_last_contact_date()
+ self.set_status()
self.validate_order_type()
self.validate_for_items()
@@ -126,42 +103,22 @@ class DocType(SellingController):
sales_com_obj.check_active_sales_items(self)
sales_com_obj.validate_max_discount(self,'quotation_details')
sales_com_obj.check_conversion_rate(self)
-
-
- def on_update(self):
- # Set Quotation Status
- webnotes.conn.set(self.doc, 'status', 'Draft')
-
+
#update enquiry
#------------------
- def update_enquiry(self, flag):
- prevdoc=''
- for d in getlist(self.doclist, 'quotation_details'):
- if d.prevdoc_docname:
- prevdoc = d.prevdoc_docname
-
- if prevdoc:
- if flag == 'submit': #on submit
- sql("update `tabOpportunity` set status = 'Quotation Sent' where name = %s", prevdoc)
- elif flag == 'cancel': #on cancel
- sql("update `tabOpportunity` set status = 'Open' where name = %s", prevdoc)
- elif flag == 'order lost': #order lost
- sql("update `tabOpportunity` set status = 'Opportunity Lost' where name=%s", prevdoc)
- elif flag == 'order confirm': #order confirm
- sql("update `tabOpportunity` set status='Order Confirmed' where name=%s", prevdoc)
+ def update_opportunity(self):
+ for opportunity in self.doclist.get_distinct_values("prevdoc_docname"):
+ webnotes.bean("Opportunity", opportunity).get_controller().set_status(update=True)
# declare as order lost
#-------------------------
def declare_order_lost(self, arg):
- chk = sql("select t1.name from `tabSales Order` t1, `tabSales Order Item` t2 where t2.parent = t1.name and t1.docstatus=1 and t2.prevdoc_docname = %s",self.doc.name)
- if chk:
- msgprint("Sales Order No. "+cstr(chk[0][0])+" is submitted against this Quotation. Thus 'Order Lost' can not be declared against it.")
- raise Exception
- else:
- webnotes.conn.set(self.doc, 'status', 'Order Lost')
+ if not self.has_sales_order():
+ webnotes.conn.set(self.doc, 'status', 'Lost')
webnotes.conn.set(self.doc, 'order_lost_reason', arg)
- self.update_enquiry('order lost')
- return 'true'
+ self.update_opportunity()
+ else:
+ webnotes.throw(_("Cannot set as Lost as Sales Order is made."))
#check if value entered in item table
#--------------------------------------
@@ -177,21 +134,17 @@ class DocType(SellingController):
# Check for Approving Authority
get_obj('Authorization Control').validate_approving_authority(self.doc.doctype, self.doc.company, self.doc.grand_total, self)
-
- # Set Quotation Status
- webnotes.conn.set(self.doc, 'status', 'Submitted')
-
+
#update enquiry status
- self.update_enquiry('submit')
+ self.update_opportunity()
# ON CANCEL
# ==========================================================================
def on_cancel(self):
#update enquiry status
- self.update_enquiry('cancel')
-
- webnotes.conn.set(self.doc,'status','Cancelled')
+ self.set_status()
+ self.update_opportunity()
# Print other charges
# ===========================================================================
@@ -203,6 +156,7 @@ class DocType(SellingController):
lst1.append(d.total)
print_lst.append(lst1)
return print_lst
+
@webnotes.whitelist()
def make_sales_order(source_name, target_doclist=None):
diff --git a/selling/doctype/quotation/quotation.txt b/selling/doctype/quotation/quotation.txt
index 3f97c980bc4..1620d915e92 100644
--- a/selling/doctype/quotation/quotation.txt
+++ b/selling/doctype/quotation/quotation.txt
@@ -2,13 +2,14 @@
{
"creation": "2013-05-24 19:29:08",
"docstatus": 0,
- "modified": "2013-09-10 10:46:33",
+ "modified": "2013-10-11 13:21:07",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"allow_attach": 1,
"allow_email": 0,
+ "allow_import": 1,
"autoname": "naming_series:",
"doctype": "DocType",
"document_type": "Transaction",
@@ -257,7 +258,6 @@
"width": "100px"
},
{
- "default": "1.00",
"description": "Rate at which customer's currency is converted to company's base currency",
"doctype": "DocField",
"fieldname": "conversion_rate",
@@ -733,7 +733,7 @@
"no_copy": 1,
"oldfieldname": "status",
"oldfieldtype": "Select",
- "options": "\nDraft\nSubmitted\nOrder Confirmed\nOrder Lost\nCancelled",
+ "options": "Draft\nSubmitted\nOrdered\nLost\nCancelled",
"print_hide": 1,
"read_only": 1,
"reqd": 1,
@@ -841,8 +841,7 @@
"fieldtype": "Table",
"hidden": 1,
"label": "Communications",
- "options": "Communication",
- "print_hide": 1
+ "options": "Communication"
},
{
"amend": 1,
diff --git a/selling/doctype/quotation/test_quotation.py b/selling/doctype/quotation/test_quotation.py
index cf3881d0c3f..366035ef1a5 100644
--- a/selling/doctype/quotation/test_quotation.py
+++ b/selling/doctype/quotation/test_quotation.py
@@ -11,17 +11,19 @@ class TestQuotation(unittest.TestCase):
def test_make_sales_order(self):
from selling.doctype.quotation.quotation import make_sales_order
- self.assertRaises(webnotes.ValidationError, make_sales_order, "_T-Quotation-00001")
+ quotation = webnotes.bean(copy=test_records[0])
+ quotation.insert()
+
+ self.assertRaises(webnotes.ValidationError, make_sales_order, quotation.doc.name)
- quotation = webnotes.bean("Quotation","_T-Quotation-00001")
quotation.submit()
- sales_order = make_sales_order("_T-Quotation-00001")
+ sales_order = make_sales_order(quotation.doc.name)
self.assertEquals(sales_order[0]["doctype"], "Sales Order")
self.assertEquals(len(sales_order), 2)
self.assertEquals(sales_order[1]["doctype"], "Sales Order Item")
- self.assertEquals(sales_order[1]["prevdoc_docname"], "_T-Quotation-00001")
+ self.assertEquals(sales_order[1]["prevdoc_docname"], quotation.doc.name)
self.assertEquals(sales_order[0]["customer"], "_Test Customer")
sales_order[0]["delivery_date"] = "2014-01-01"
diff --git a/selling/doctype/sales_common/sales_common.js b/selling/doctype/sales_common/sales_common.js
index 20ba92a885a..6a4b2283268 100644
--- a/selling/doctype/sales_common/sales_common.js
+++ b/selling/doctype/sales_common/sales_common.js
@@ -10,6 +10,7 @@
wn.provide("erpnext.selling");
wn.require("app/js/transaction.js");
+wn.require("app/js/controllers/accounts.js");
erpnext.selling.SellingController = erpnext.TransactionController.extend({
onload: function() {
@@ -162,8 +163,7 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
var item = wn.model.get_doc(cdt, cdn);
if(item.item_code || item.barcode) {
if(!this.validate_company_and_party("customer")) {
- item.item_code = null;
- refresh_field("item_code", item.name, item.parentfield);
+ cur_frm.fields_dict[me.frm.cscript.fname].grid.grid_rows[item.idx - 1].remove();
} else {
return this.frm.call({
method: "selling.utils.get_item_details",
diff --git a/selling/doctype/sales_common/sales_common.py b/selling/doctype/sales_common/sales_common.py
index 8271c828740..01718dd3f0b 100644
--- a/selling/doctype/sales_common/sales_common.py
+++ b/selling/doctype/sales_common/sales_common.py
@@ -86,26 +86,6 @@ class DocType(TransactionBase):
if (obj.doc.price_list_currency == default_currency and flt(obj.doc.plc_conversion_rate) != 1.00) or not obj.doc.plc_conversion_rate or (obj.doc.price_list_currency != default_currency and flt(obj.doc.plc_conversion_rate) == 1.00):
msgprint("Please Enter Appropriate Conversion Rate for Price List Currency to Base Currency (%s --> %s)" % (obj.doc.price_list_currency, default_currency), raise_exception = 1)
-
-
-
- # Get Tax rate if account type is TAX
- # =========================================================================
- def get_rate(self, arg):
- arg = eval(arg)
- rate = webnotes.conn.sql("select account_type, tax_rate from `tabAccount` where name = '%s' and docstatus != 2" %(arg['account_head']), as_dict=1)
- ret = {'rate' : 0}
- if arg['charge_type'] == 'Actual' and rate[0]['account_type'] == 'Tax':
- msgprint("You cannot select ACCOUNT HEAD of type TAX as your CHARGE TYPE is 'ACTUAL'")
- ret = {
- 'account_head' : ''
- }
- elif rate[0]['account_type'] in ['Tax', 'Chargeable'] and not arg['charge_type'] == 'Actual':
- ret = {
- 'rate' : rate and flt(rate[0]['tax_rate']) or 0
- }
- return ret
-
def get_item_list(self, obj, is_stopped=0):
"""get item list"""
@@ -123,12 +103,12 @@ class DocType(TransactionBase):
if flt(d.qty) > flt(d.delivered_qty):
reserved_qty_for_main_item = flt(d.qty) - flt(d.delivered_qty)
- if obj.doc.doctype == "Delivery Note" and d.prevdoc_doctype == 'Sales Order':
+ if obj.doc.doctype == "Delivery Note" and d.against_sales_order:
# if SO qty is 10 and there is tolerance of 20%, then it will allow DN of 12.
# But in this case reserved qty should only be reduced by 10 and not 12
already_delivered_qty = self.get_already_delivered_qty(obj.doc.name,
- d.prevdoc_docname, d.prevdoc_detail_docname)
+ d.against_sales_order, d.prevdoc_detail_docname)
so_qty, reserved_warehouse = self.get_so_qty_and_warehouse(d.prevdoc_detail_docname)
if already_delivered_qty + d.qty > so_qty:
@@ -168,7 +148,7 @@ class DocType(TransactionBase):
def get_already_delivered_qty(self, dn, so, so_detail):
qty = webnotes.conn.sql("""select sum(qty) from `tabDelivery Note Item`
where prevdoc_detail_docname = %s and docstatus = 1
- and prevdoc_doctype = 'Sales Order' and prevdoc_docname = %s
+ and against_sales_order = %s
and parent != %s""", (so_detail, so, dn))
return qty and flt(qty[0][0]) or 0.0
@@ -218,7 +198,6 @@ class DocType(TransactionBase):
pi.qty = flt(qty)
pi.actual_qty = bin and flt(bin['actual_qty']) or 0
pi.projected_qty = bin and flt(bin['projected_qty']) or 0
- pi.prevdoc_doctype = line.prevdoc_doctype
if not pi.warehouse:
pi.warehouse = warehouse
if not pi.batch_no:
@@ -283,8 +262,8 @@ class DocType(TransactionBase):
def check_stop_sales_order(self,obj):
for d in getlist(obj.doclist,obj.fname):
ref_doc_name = ''
- if d.fields.has_key('prevdoc_docname') and d.prevdoc_docname and d.prevdoc_doctype == 'Sales Order':
- ref_doc_name = d.prevdoc_docname
+ if d.fields.has_key('against_sales_order') and d.against_sales_order:
+ ref_doc_name = d.against_sales_order
elif d.fields.has_key('sales_order') and d.sales_order and not d.delivery_note:
ref_doc_name = d.sales_order
if ref_doc_name:
@@ -319,17 +298,6 @@ class DocType(TransactionBase):
exact_outstanding = flt(tot_outstanding) + flt(grand_total)
get_obj('Account',acc_head[0][0]).check_credit_limit(acc_head[0][0], obj.doc.company, exact_outstanding)
- def get_prevdoc_date(self, obj):
- for d in getlist(obj.doclist, obj.fname):
- if d.prevdoc_doctype and d.prevdoc_docname:
- if d.prevdoc_doctype in ["Sales Invoice", "Delivery Note"]:
- date_field = "posting_date"
- else:
- date_field = "transaction_date"
-
- d.prevdoc_date = webnotes.conn.get_value(d.prevdoc_doctype,
- d.prevdoc_docname, date_field)
-
def get_batch_no(doctype, txt, searchfield, start, page_len, filters):
from controllers.queries import get_match_cond
diff --git a/selling/doctype/sales_order/sales_order.js b/selling/doctype/sales_order/sales_order.js
index b121f1503b3..bf23b9cb9df 100644
--- a/selling/doctype/sales_order/sales_order.js
+++ b/selling/doctype/sales_order/sales_order.js
@@ -12,6 +12,7 @@ cur_frm.cscript.sales_team_fname = "sales_team";
wn.require('app/selling/doctype/sales_common/sales_common.js');
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/accounts/doctype/sales_invoice/pos.js');
erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend({
refresh: function(doc, dt, dn) {
@@ -65,7 +66,7 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
source_doctype: "Quotation",
get_query_filters: {
docstatus: 1,
- status: ["!=", "Order Lost"],
+ status: ["!=", "Lost"],
order_type: cur_frm.doc.order_type,
customer: cur_frm.doc.customer || undefined,
company: cur_frm.doc.company
@@ -188,4 +189,4 @@ cur_frm.cscript.on_submit = function(doc, cdt, cdn) {
if(cint(wn.boot.notification_settings.sales_order)) {
cur_frm.email_doc(wn.boot.notification_settings.sales_order_message);
}
-};
\ No newline at end of file
+};
diff --git a/selling/doctype/sales_order/sales_order.py b/selling/doctype/sales_order/sales_order.py
index 1ccccdd2ebe..1c22c08a3b6 100644
--- a/selling/doctype/sales_order/sales_order.py
+++ b/selling/doctype/sales_order/sales_order.py
@@ -11,7 +11,6 @@ from webnotes.model.code import get_obj
from webnotes import msgprint
from webnotes.model.mapper import get_mapped_doclist
-sql = webnotes.conn.sql
from controllers.selling_controller import SellingController
@@ -39,9 +38,6 @@ class DocType(SellingController):
def get_available_qty(self,args):
return get_obj('Sales Common').get_available_qty(eval(args))
- def get_rate(self,arg):
- return get_obj('Sales Common').get_rate(arg)
-
def validate_mandatory(self):
# validate transaction date v/s delivery date
if self.doc.delivery_date:
@@ -88,14 +84,14 @@ class DocType(SellingController):
# used for production plan
d.transaction_date = self.doc.transaction_date
- tot_avail_qty = sql("select projected_qty from `tabBin` \
+ tot_avail_qty = webnotes.conn.sql("select projected_qty from `tabBin` \
where item_code = '%s' and warehouse = '%s'" % (d.item_code,d.reserved_warehouse))
d.projected_qty = tot_avail_qty and flt(tot_avail_qty[0][0]) or 0
def validate_sales_mntc_quotation(self):
for d in getlist(self.doclist, 'sales_order_details'):
if d.prevdoc_docname:
- res = sql("select name from `tabQuotation` where name=%s and order_type = %s", (d.prevdoc_docname, self.doc.order_type))
+ res = webnotes.conn.sql("select name from `tabQuotation` where name=%s and order_type = %s", (d.prevdoc_docname, self.doc.order_type))
if not res:
msgprint("""Order Type (%s) should be same in Quotation: %s \
and current Sales Order""" % (self.doc.order_type, d.prevdoc_docname))
@@ -112,7 +108,7 @@ class DocType(SellingController):
def validate_proj_cust(self):
if self.doc.project_name and self.doc.customer_name:
- res = sql("select name from `tabProject` where name = '%s' and (customer = '%s' or ifnull(customer,'')='')"%(self.doc.project_name, self.doc.customer))
+ res = webnotes.conn.sql("select name from `tabProject` where name = '%s' and (customer = '%s' or ifnull(customer,'')='')"%(self.doc.project_name, self.doc.customer))
if not res:
msgprint("Customer - %s does not belong to project - %s. \n\nIf you want to use project for multiple customers then please make customer details blank in project - %s."%(self.doc.customer,self.doc.project_name,self.doc.project_name))
raise Exception
@@ -127,7 +123,7 @@ class DocType(SellingController):
self.validate_po()
self.validate_uom_is_integer("stock_uom", "qty")
self.validate_for_items()
- self.validate_warehouse_user()
+ self.validate_warehouse()
sales_com_obj = get_obj(dt = 'Sales Common')
sales_com_obj.check_active_sales_items(self)
sales_com_obj.check_conversion_rate(self)
@@ -148,14 +144,15 @@ class DocType(SellingController):
if not self.doc.delivery_status: self.doc.delivery_status = 'Not Delivered'
- def validate_warehouse_user(self):
- from stock.utils import validate_warehouse_user
+ def validate_warehouse(self):
+ from stock.utils import validate_warehouse_user, validate_warehouse_company
warehouses = list(set([d.reserved_warehouse for d in
self.doclist.get({"doctype": self.tname}) if d.reserved_warehouse]))
for w in warehouses:
validate_warehouse_user(w)
+ validate_warehouse_company(w, self.doc.company)
def validate_with_previous_doc(self):
super(DocType, self).validate_with_previous_doc(self.tname, {
@@ -166,36 +163,20 @@ class DocType(SellingController):
})
- def check_prev_docstatus(self):
- for d in getlist(self.doclist, 'sales_order_details'):
- cancel_quo = sql("select name from `tabQuotation` where docstatus = 2 and name = '%s'" % d.prevdoc_docname)
- if cancel_quo:
- msgprint("Quotation :" + cstr(cancel_quo[0][0]) + " is already cancelled !")
- raise Exception , "Validation Error. "
-
def update_enquiry_status(self, prevdoc, flag):
- enq = sql("select t2.prevdoc_docname from `tabQuotation` t1, `tabQuotation Item` t2 where t2.parent = t1.name and t1.name=%s", prevdoc)
+ enq = webnotes.conn.sql("select t2.prevdoc_docname from `tabQuotation` t1, `tabQuotation Item` t2 where t2.parent = t1.name and t1.name=%s", prevdoc)
if enq:
- sql("update `tabOpportunity` set status = %s where name=%s",(flag,enq[0][0]))
+ webnotes.conn.sql("update `tabOpportunity` set status = %s where name=%s",(flag,enq[0][0]))
- def update_prevdoc_status(self, flag):
- for d in getlist(self.doclist, 'sales_order_details'):
- if d.prevdoc_docname:
- if flag=='submit':
- sql("update `tabQuotation` set status = 'Order Confirmed' where name=%s",d.prevdoc_docname)
-
- #update enquiry
- self.update_enquiry_status(d.prevdoc_docname, 'Order Confirmed')
- elif flag == 'cancel':
- chk = sql("select t1.name from `tabSales Order` t1, `tabSales Order Item` t2 where t2.parent = t1.name and t2.prevdoc_docname=%s and t1.name!=%s and t1.docstatus=1", (d.prevdoc_docname,self.doc.name))
- if not chk:
- sql("update `tabQuotation` set status = 'Submitted' where name=%s",d.prevdoc_docname)
-
- #update enquiry
- self.update_enquiry_status(d.prevdoc_docname, 'Quotation Sent')
+ def update_prevdoc_status(self, flag):
+ for quotation in self.doclist.get_distinct_values("prevdoc_docname"):
+ bean = webnotes.bean("Quotation", quotation)
+ if bean.doc.docstatus==2:
+ webnotes.throw(d.prevdoc_docname + ": " + webnotes._("Quotation is cancelled."))
+
+ bean.get_controller().set_status(update=True)
def on_submit(self):
- self.check_prev_docstatus()
self.update_stock_ledger(update_stock = 1)
get_obj('Sales Common').check_credit(self,self.doc.grand_total)
@@ -219,35 +200,35 @@ class DocType(SellingController):
def check_nextdoc_docstatus(self):
# Checks Delivery Note
- submit_dn = sql("select t1.name from `tabDelivery Note` t1,`tabDelivery Note Item` t2 where t1.name = t2.parent and t2.prevdoc_docname = '%s' and t1.docstatus = 1" % (self.doc.name))
+ submit_dn = webnotes.conn.sql("select t1.name from `tabDelivery Note` t1,`tabDelivery Note Item` t2 where t1.name = t2.parent and t2.against_sales_order = %s and t1.docstatus = 1", self.doc.name)
if submit_dn:
msgprint("Delivery Note : " + cstr(submit_dn[0][0]) + " has been submitted against " + cstr(self.doc.doctype) + ". Please cancel Delivery Note : " + cstr(submit_dn[0][0]) + " first and then cancel "+ cstr(self.doc.doctype), raise_exception = 1)
# Checks Sales Invoice
- submit_rv = sql("select t1.name from `tabSales Invoice` t1,`tabSales Invoice Item` t2 where t1.name = t2.parent and t2.sales_order = '%s' and t1.docstatus = 1" % (self.doc.name))
+ submit_rv = webnotes.conn.sql("select t1.name from `tabSales Invoice` t1,`tabSales Invoice Item` t2 where t1.name = t2.parent and t2.sales_order = '%s' and t1.docstatus = 1" % (self.doc.name))
if submit_rv:
msgprint("Sales Invoice : " + cstr(submit_rv[0][0]) + " has already been submitted against " +cstr(self.doc.doctype)+ ". Please cancel Sales Invoice : "+ cstr(submit_rv[0][0]) + " first and then cancel "+ cstr(self.doc.doctype), raise_exception = 1)
#check maintenance schedule
- submit_ms = sql("select t1.name from `tabMaintenance Schedule` t1, `tabMaintenance Schedule Item` t2 where t2.parent=t1.name and t2.prevdoc_docname = %s and t1.docstatus = 1",self.doc.name)
+ submit_ms = webnotes.conn.sql("select t1.name from `tabMaintenance Schedule` t1, `tabMaintenance Schedule Item` t2 where t2.parent=t1.name and t2.prevdoc_docname = %s and t1.docstatus = 1",self.doc.name)
if submit_ms:
msgprint("Maintenance Schedule : " + cstr(submit_ms[0][0]) + " has already been submitted against " +cstr(self.doc.doctype)+ ". Please cancel Maintenance Schedule : "+ cstr(submit_ms[0][0]) + " first and then cancel "+ cstr(self.doc.doctype), raise_exception = 1)
# check maintenance visit
- submit_mv = sql("select t1.name from `tabMaintenance Visit` t1, `tabMaintenance Visit Purpose` t2 where t2.parent=t1.name and t2.prevdoc_docname = %s and t1.docstatus = 1",self.doc.name)
+ submit_mv = webnotes.conn.sql("select t1.name from `tabMaintenance Visit` t1, `tabMaintenance Visit Purpose` t2 where t2.parent=t1.name and t2.prevdoc_docname = %s and t1.docstatus = 1",self.doc.name)
if submit_mv:
msgprint("Maintenance Visit : " + cstr(submit_mv[0][0]) + " has already been submitted against " +cstr(self.doc.doctype)+ ". Please cancel Maintenance Visit : " + cstr(submit_mv[0][0]) + " first and then cancel "+ cstr(self.doc.doctype), raise_exception = 1)
# check production order
- pro_order = sql("""select name from `tabProduction Order` where sales_order = %s and docstatus = 1""", self.doc.name)
+ pro_order = webnotes.conn.sql("""select name from `tabProduction Order` where sales_order = %s and docstatus = 1""", self.doc.name)
if pro_order:
msgprint("""Production Order: %s exists against this sales order.
Please cancel production order first and then cancel this sales order""" %
pro_order[0][0], raise_exception=1)
def check_modified_date(self):
- mod_db = sql("select modified from `tabSales Order` where name = '%s'" % self.doc.name)
- date_diff = sql("select TIMEDIFF('%s', '%s')" % ( mod_db[0][0],cstr(self.doc.modified)))
+ mod_db = webnotes.conn.sql("select modified from `tabSales Order` where name = '%s'" % self.doc.name)
+ date_diff = webnotes.conn.sql("select TIMEDIFF('%s', '%s')" % ( mod_db[0][0],cstr(self.doc.modified)))
if date_diff and date_diff[0][0]:
msgprint("%s: %s has been modified after you have opened. Please Refresh"
% (self.doc.doctype, self.doc.name), raise_exception=1)
@@ -342,8 +323,7 @@ def make_delivery_note(source_name, target_doclist=None):
"field_map": {
"export_rate": "export_rate",
"name": "prevdoc_detail_docname",
- "parent": "prevdoc_docname",
- "parenttype": "prevdoc_doctype",
+ "parent": "against_sales_order",
"reserved_warehouse": "warehouse"
},
"postprocess": update_item,
diff --git a/selling/doctype/sales_order/sales_order.txt b/selling/doctype/sales_order/sales_order.txt
index 94e63888e3b..c27f8ffa9de 100644
--- a/selling/doctype/sales_order/sales_order.txt
+++ b/selling/doctype/sales_order/sales_order.txt
@@ -2,12 +2,13 @@
{
"creation": "2013-06-18 12:39:59",
"docstatus": 0,
- "modified": "2013-08-09 14:46:17",
+ "modified": "2013-10-11 13:18:47",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"allow_attach": 1,
+ "allow_import": 1,
"autoname": "naming_series:",
"doctype": "DocType",
"document_type": "Transaction",
@@ -272,7 +273,6 @@
"width": "100px"
},
{
- "default": "1.00",
"description": "Rate at which customer's currency is converted to company's base currency",
"doctype": "DocField",
"fieldname": "conversion_rate",
diff --git a/selling/doctype/sales_order/test_sales_order.py b/selling/doctype/sales_order/test_sales_order.py
index 7b72271bec9..0ee58a7fd27 100644
--- a/selling/doctype/sales_order/test_sales_order.py
+++ b/selling/doctype/sales_order/test_sales_order.py
@@ -72,10 +72,13 @@ class TestSalesOrder(unittest.TestCase):
def create_dn_against_so(self, so, delivered_qty=0):
from stock.doctype.delivery_note.test_delivery_note import test_records as dn_test_records
+ from stock.doctype.delivery_note.test_delivery_note import _insert_purchase_receipt
+
+ _insert_purchase_receipt(so.doclist[1].item_code)
+
dn = webnotes.bean(webnotes.copy_doclist(dn_test_records[0]))
dn.doclist[1].item_code = so.doclist[1].item_code
- dn.doclist[1].prevdoc_doctype = "Sales Order"
- dn.doclist[1].prevdoc_docname = so.doc.name
+ dn.doclist[1].against_sales_order = so.doc.name
dn.doclist[1].prevdoc_detail_docname = so.doclist[1].name
if delivered_qty:
dn.doclist[1].qty = delivered_qty
@@ -273,14 +276,13 @@ class TestSalesOrder(unittest.TestCase):
so.doclist[1].reserved_warehouse, 20.0)
def test_warehouse_user(self):
- webnotes.session.user = "test@example.com"
-
webnotes.bean("Profile", "test@example.com").get_controller()\
.add_roles("Sales User", "Sales Manager", "Material User", "Material Manager")
webnotes.bean("Profile", "test2@example.com").get_controller()\
.add_roles("Sales User", "Sales Manager", "Material User", "Material Manager")
-
+
+ webnotes.session.user = "test@example.com"
from stock.utils import UserNotAllowedForWarehouse
so = webnotes.bean(copy = test_records[0])
diff --git a/selling/doctype/sms_center/sms_center.py b/selling/doctype/sms_center/sms_center.py
index 29e793c04e8..eb331c206eb 100644
--- a/selling/doctype/sms_center/sms_center.py
+++ b/selling/doctype/sms_center/sms_center.py
@@ -10,7 +10,6 @@ from webnotes.model.bean import copy_doclist
from webnotes.model.code import get_obj
from webnotes import msgprint
-sql = webnotes.conn.sql
# ----------
@@ -29,15 +28,15 @@ class DocType:
where_clause = self.doc.sales_partner and " and ifnull(is_sales_partner, 0) = 1 and sales_partner = '%s'" % self.doc.sales_partner or " and ifnull(sales_partner, '') != ''"
if self.doc.send_to in ['All Contact', 'All Customer Contact', 'All Supplier Contact', 'All Sales Partner Contact']:
- rec = sql("select CONCAT(ifnull(first_name,''),'',ifnull(last_name,'')), mobile_no from `tabContact` where ifnull(mobile_no,'')!='' and docstatus != 2 %s" % where_clause)
+ rec = webnotes.conn.sql("select CONCAT(ifnull(first_name,''),'',ifnull(last_name,'')), mobile_no from `tabContact` where ifnull(mobile_no,'')!='' and docstatus != 2 %s" % where_clause)
elif self.doc.send_to == 'All Lead (Open)':
- rec = sql("select lead_name, mobile_no from tabLead where ifnull(mobile_no,'')!='' and docstatus != 2 and status = 'Open'")
+ rec = webnotes.conn.sql("select lead_name, mobile_no from tabLead where ifnull(mobile_no,'')!='' and docstatus != 2 and status = 'Open'")
elif self.doc.send_to == 'All Employee (Active)':
where_clause = self.doc.department and " and department = '%s'" % self.doc.department or ""
where_clause += self.doc.branch and " and branch = '%s'" % self.doc.branch or ""
- rec = sql("select employee_name, cell_number from `tabEmployee` where status = 'Active' and docstatus < 2 and ifnull(cell_number,'')!='' %s" % where_clause)
+ rec = webnotes.conn.sql("select employee_name, cell_number from `tabEmployee` where status = 'Active' and docstatus < 2 and ifnull(cell_number,'')!='' %s" % where_clause)
elif self.doc.send_to == 'All Sales Person':
- rec = sql("select sales_person_name, mobile_no from `tabSales Person` where docstatus != 2 and ifnull(mobile_no,'')!=''")
+ rec = webnotes.conn.sql("select sales_person_name, mobile_no from `tabSales Person` where docstatus != 2 and ifnull(mobile_no,'')!=''")
rec_list = ''
for d in rec:
rec_list += d[0] + ' - ' + d[1] + '\n'
diff --git a/selling/page/sales_funnel/__init__.py b/selling/page/sales_funnel/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/selling/page/sales_funnel/sales_funnel.css b/selling/page/sales_funnel/sales_funnel.css
new file mode 100644
index 00000000000..89e904fcfc9
--- /dev/null
+++ b/selling/page/sales_funnel/sales_funnel.css
@@ -0,0 +1,3 @@
+.funnel-wrapper {
+ margin: 15px;
+}
\ No newline at end of file
diff --git a/selling/page/sales_funnel/sales_funnel.js b/selling/page/sales_funnel/sales_funnel.js
new file mode 100644
index 00000000000..e2c3a98bf59
--- /dev/null
+++ b/selling/page/sales_funnel/sales_funnel.js
@@ -0,0 +1,189 @@
+// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
+// License: GNU General Public License v3. See license.txt
+
+wn.pages['sales-funnel'].onload = function(wrapper) {
+ wn.ui.make_app_page({
+ parent: wrapper,
+ title: 'Sales Funnel',
+ single_column: true
+ });
+
+ wrapper.crm_funnel = new erpnext.CRMFunnel(wrapper);
+
+ wrapper.appframe.add_module_icon("Selling", "sales-funnel", function() {
+ wn.set_route("selling-home");
+ });
+}
+
+erpnext.CRMFunnel = Class.extend({
+ init: function(wrapper) {
+ var me = this;
+ // 0 setTimeout hack - this gives time for canvas to get width and height
+ setTimeout(function() {
+ me.setup(wrapper);
+ me.get_data();
+ }, 0);
+ },
+
+ setup: function(wrapper) {
+ var me = this;
+
+ this.elements = {
+ layout: $(wrapper).find(".layout-main"),
+ from_date: wrapper.appframe.add_date("From Date"),
+ to_date: wrapper.appframe.add_date("To Date"),
+ refresh_btn: wrapper.appframe.add_button("Refresh",
+ function() { me.get_data(); }, "icon-refresh"),
+ };
+
+ this.elements.no_data = $('
No Data
')
+ .toggle(false)
+ .appendTo(this.elements.layout);
+
+ this.elements.funnel_wrapper = $('')
+ .appendTo(this.elements.layout);
+
+ this.options = {
+ from_date: wn.datetime.add_months(wn.datetime.get_today(), -1),
+ to_date: wn.datetime.get_today()
+ };
+
+ // set defaults and bind on change
+ $.each(this.options, function(k, v) {
+ me.elements[k].val(wn.datetime.str_to_user(v));
+ me.elements[k].on("change", function() {
+ me.options[k] = wn.datetime.user_to_str($(this).val());
+ me.get_data();
+ });
+ });
+
+ // bind refresh
+ this.elements.refresh_btn.on("click", function() {
+ me.get_data(this);
+ });
+
+ // bind resize
+ $(window).resize(function() {
+ me.render();
+ });
+ },
+
+ get_data: function(btn) {
+ var me = this;
+ wn.call({
+ module: "selling",
+ page: "crm_funnel",
+ method: "get_funnel_data",
+ args: {
+ from_date: this.options.from_date,
+ to_date: this.options.to_date
+ },
+ btn: btn,
+ callback: function(r) {
+ if(!r.exc) {
+ me.options.data = r.message;
+ me.render();
+ }
+ }
+ });
+ },
+
+ render: function() {
+ var me = this;
+ this.prepare();
+
+ var context = this.elements.context,
+ x_start = 0.0,
+ x_end = this.options.width,
+ x_mid = (x_end - x_start) / 2.0,
+ y = 0,
+ y_old = 0.0;
+
+ if(this.options.total_value === 0) {
+ this.elements.no_data.toggle(true);
+ return;
+ }
+
+ this.options.data.forEach(function(d) {
+ context.fillStyle = d.color;
+ context.strokeStyle = d.color;
+ me.draw_triangle(x_start, x_mid, x_end, y, me.options.height);
+
+ y_old = y;
+
+ // new y
+ y = y + d.height;
+
+ // new x
+ var half_side = (me.options.height - y) / Math.sqrt(3);
+ x_start = x_mid - half_side;
+ x_end = x_mid + half_side;
+
+ var y_mid = y_old + (y - y_old) / 2.0;
+
+ me.draw_legend(x_mid, y_mid, me.options.width, me.options.height, d.value + " - " + d.title);
+ });
+ },
+
+ prepare: function() {
+ var me = this;
+
+ this.elements.no_data.toggle(false);
+
+ // calculate width and height options
+ this.options.width = $(this.elements.funnel_wrapper).width() * 2.0 / 3.0;
+ this.options.height = (Math.sqrt(3) * this.options.width) / 2.0;
+
+ // calculate total weightage
+ // as height decreases, area decreases by the square of the reduction
+ // hence, compensating by squaring the index value
+ this.options.total_weightage = this.options.data.reduce(
+ function(prev, curr, i) { return prev + Math.pow(i+1, 2) * curr.value; }, 0.0);
+
+ // calculate height for each data
+ $.each(this.options.data, function(i, d) {
+ d.height = me.options.height * d.value * Math.pow(i+1, 2) / me.options.total_weightage;
+ });
+
+ this.elements.canvas = $('')
+ .appendTo(this.elements.funnel_wrapper.empty())
+ .attr("width", $(this.elements.funnel_wrapper).width())
+ .attr("height", this.options.height);
+
+ this.elements.context = this.elements.canvas.get(0).getContext("2d");
+ },
+
+ draw_triangle: function(x_start, x_mid, x_end, y, height) {
+ var context = this.elements.context;
+ context.beginPath();
+ context.moveTo(x_start, y);
+ context.lineTo(x_end, y);
+ context.lineTo(x_mid, height);
+ context.lineTo(x_start, y);
+ context.closePath();
+ context.fill();
+ },
+
+ draw_legend: function(x_mid, y_mid, width, height, title) {
+ var context = this.elements.context;
+
+ // draw line
+ context.beginPath();
+ context.moveTo(x_mid, y_mid);
+ context.lineTo(width, y_mid);
+ context.closePath();
+ context.stroke();
+
+ // draw circle
+ context.beginPath();
+ context.arc(width, y_mid, 5, 0, Math.PI * 2, false);
+ context.closePath();
+ context.fill();
+
+ // draw text
+ context.fillStyle = "black";
+ context.textBaseline = "middle";
+ context.font = "1.1em sans-serif";
+ context.fillText(title, width + 20, y_mid);
+ }
+});
\ No newline at end of file
diff --git a/selling/page/sales_funnel/sales_funnel.py b/selling/page/sales_funnel/sales_funnel.py
new file mode 100644
index 00000000000..be0aebe7bb8
--- /dev/null
+++ b/selling/page/sales_funnel/sales_funnel.py
@@ -0,0 +1,33 @@
+# 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_funnel_data(from_date, to_date):
+ active_leads = webnotes.conn.sql("""select count(*) from `tabLead`
+ where (`modified` between %s and %s)
+ and status != "Do Not Contact" """, (from_date, to_date))[0][0]
+
+ active_leads += webnotes.conn.sql("""select count(distinct customer) from `tabContact`
+ where (`modified` between %s and %s)
+ and status != "Passive" """, (from_date, to_date))[0][0]
+
+ opportunities = webnotes.conn.sql("""select count(*) from `tabOpportunity`
+ where docstatus = 1 and (`modified` between %s and %s)
+ and status != "Lost" """, (from_date, to_date))[0][0]
+
+ quotations = webnotes.conn.sql("""select count(*) from `tabQuotation`
+ where docstatus = 1 and (`modified` between %s and %s)
+ and status != "Lost" """, (from_date, to_date))[0][0]
+
+ sales_orders = webnotes.conn.sql("""select count(*) from `tabQuotation`
+ where docstatus = 1 and (`modified` between %s and %s)""", (from_date, to_date))[0][0]
+
+ return [
+ { "title": "Active Leads / Customers", "value": active_leads, "color": "#B03B46" },
+ { "title": "Opportunities", "value": opportunities, "color": "#F09C00" },
+ { "title": "Quotations", "value": quotations, "color": "#006685" },
+ { "title": "Sales Orders", "value": sales_orders, "color": "#00AD65" }
+ ]
diff --git a/selling/page/sales_funnel/sales_funnel.txt b/selling/page/sales_funnel/sales_funnel.txt
new file mode 100644
index 00000000000..b841f20fdcc
--- /dev/null
+++ b/selling/page/sales_funnel/sales_funnel.txt
@@ -0,0 +1,33 @@
+[
+ {
+ "creation": "2013-10-04 13:17:18",
+ "docstatus": 0,
+ "modified": "2013-10-04 13:17:18",
+ "modified_by": "Administrator",
+ "owner": "Administrator"
+ },
+ {
+ "doctype": "Page",
+ "icon": "icon-filter",
+ "module": "Selling",
+ "name": "__common__",
+ "page_name": "sales-funnel",
+ "standard": "Yes",
+ "title": "Sales Funnel"
+ },
+ {
+ "doctype": "Page Role",
+ "name": "__common__",
+ "parent": "sales-funnel",
+ "parentfield": "roles",
+ "parenttype": "Page",
+ "role": "Sales Manager"
+ },
+ {
+ "doctype": "Page",
+ "name": "sales-funnel"
+ },
+ {
+ "doctype": "Page Role"
+ }
+]
\ No newline at end of file
diff --git a/selling/page/selling_home/selling_home.js b/selling/page/selling_home/selling_home.js
index b4e93054ccd..6e6283d6e7e 100644
--- a/selling/page/selling_home/selling_home.js
+++ b/selling/page/selling_home/selling_home.js
@@ -155,6 +155,10 @@ wn.module_page["Selling"] = [
"label":wn._("Sales Analytics"),
page: "sales-analytics"
},
+ {
+ "label":wn._("Sales Funnel"),
+ page: "sales-funnel"
+ },
]
},
{
diff --git a/selling/utils/__init__.py b/selling/utils/__init__.py
index 224944dd884..6e74ac48695 100644
--- a/selling/utils/__init__.py
+++ b/selling/utils/__init__.py
@@ -34,6 +34,7 @@ def get_item_details(args):
"plc_conversion_rate": 1.0
}
"""
+
if isinstance(args, basestring):
args = json.loads(args)
args = webnotes._dict(args)
@@ -73,7 +74,7 @@ def get_item_details(args):
out.update(apply_pos_settings(pos_settings, out))
if args.doctype in ("Sales Invoice", "Delivery Note"):
- if item_bean.doc.has_serial_no and not args.serial_no:
+ if item_bean.doc.has_serial_no == "Yes" and not args.serial_no:
out.serial_no = _get_serial_nos_by_fifo(args, item_bean)
return out
diff --git a/selling/utils/cart.py b/selling/utils/cart.py
index 7e7fb2e1035..e48059d50e3 100644
--- a/selling/utils/cart.py
+++ b/selling/utils/cart.py
@@ -12,8 +12,8 @@ class WebsitePriceListMissingError(webnotes.ValidationError): pass
def set_cart_count(quotation=None):
if not quotation:
quotation = _get_cart_quotation()
- webnotes.add_cookies["cart_count"] = cstr(len(quotation.doclist.get(
- {"parentfield": "quotation_details"})) or "")
+ cart_count = cstr(len(quotation.doclist.get({"parentfield": "quotation_details"})))
+ webnotes._response.set_cookie("cart_count", cart_count)
@webnotes.whitelist()
def get_cart_quotation(doclist=None):
@@ -47,7 +47,7 @@ def place_order():
sales_order.ignore_permissions = True
sales_order.insert()
sales_order.submit()
- webnotes.add_cookies["cart_count"] = ""
+ webnotes._response.set_cookie("cart_count", "")
return sales_order.doc.name
diff --git a/setup/doctype/authorization_control/authorization_control.py b/setup/doctype/authorization_control/authorization_control.py
index ddf0791bde1..533f3988e32 100644
--- a/setup/doctype/authorization_control/authorization_control.py
+++ b/setup/doctype/authorization_control/authorization_control.py
@@ -9,7 +9,6 @@ from webnotes.model.bean import getlist
from webnotes import session, msgprint
from setup.utils import get_company_currency
-sql = webnotes.conn.sql
from utilities.transaction_base import TransactionBase
@@ -28,10 +27,10 @@ class DocType(TransactionBase):
amt_list.append(flt(x[0]))
max_amount = max(amt_list)
- app_dtl = sql("select approving_user, approving_role from `tabAuthorization Rule` where transaction = %s and (value = %s or value > %s) and docstatus != 2 and based_on = %s and company = %s %s" % ('%s', '%s', '%s', '%s', '%s', condition), (doctype_name, flt(max_amount), total, based_on, company))
+ app_dtl = webnotes.conn.sql("select approving_user, approving_role from `tabAuthorization Rule` where transaction = %s and (value = %s or value > %s) and docstatus != 2 and based_on = %s and company = %s %s" % ('%s', '%s', '%s', '%s', '%s', condition), (doctype_name, flt(max_amount), total, based_on, company))
if not app_dtl:
- app_dtl = sql("select approving_user, approving_role from `tabAuthorization Rule` where transaction = %s and (value = %s or value > %s) and docstatus != 2 and based_on = %s and ifnull(company,'') = '' %s" % ('%s', '%s', '%s', '%s', condition), (doctype_name, flt(max_amount), total, based_on))
+ app_dtl = webnotes.conn.sql("select approving_user, approving_role from `tabAuthorization Rule` where transaction = %s and (value = %s or value > %s) and docstatus != 2 and based_on = %s and ifnull(company,'') = '' %s" % ('%s', '%s', '%s', '%s', condition), (doctype_name, flt(max_amount), total, based_on))
for d in app_dtl:
if(d[0]): appr_users.append(d[0])
if(d[1]): appr_roles.append(d[1])
@@ -58,18 +57,18 @@ class DocType(TransactionBase):
add_cond1,add_cond2 = '',''
if based_on == 'Itemwise Discount':
add_cond1 += " and master_name = '"+cstr(item)+"'"
- itemwise_exists = sql("select value from `tabAuthorization Rule` where transaction = %s and value <= %s and based_on = %s and company = %s and docstatus != 2 %s %s" % ('%s', '%s', '%s', '%s', cond, add_cond1), (doctype_name, total, based_on, company))
+ itemwise_exists = webnotes.conn.sql("select value from `tabAuthorization Rule` where transaction = %s and value <= %s and based_on = %s and company = %s and docstatus != 2 %s %s" % ('%s', '%s', '%s', '%s', cond, add_cond1), (doctype_name, total, based_on, company))
if not itemwise_exists:
- itemwise_exists = sql("select value from `tabAuthorization Rule` where transaction = %s and value <= %s and based_on = %s and ifnull(company,'') = '' and docstatus != 2 %s %s" % ('%s', '%s', '%s', cond, add_cond1), (doctype_name, total, based_on))
+ itemwise_exists = webnotes.conn.sql("select value from `tabAuthorization Rule` where transaction = %s and value <= %s and based_on = %s and ifnull(company,'') = '' and docstatus != 2 %s %s" % ('%s', '%s', '%s', cond, add_cond1), (doctype_name, total, based_on))
if itemwise_exists:
self.get_appr_user_role(itemwise_exists, doctype_name, total, based_on, cond+add_cond1, item,company)
chk = 0
if chk == 1:
if based_on == 'Itemwise Discount': add_cond2 += " and ifnull(master_name,'') = ''"
- appr = sql("select value from `tabAuthorization Rule` where transaction = %s and value <= %s and based_on = %s and company = %s and docstatus != 2 %s %s" % ('%s', '%s', '%s', '%s', cond, add_cond2), (doctype_name, total, based_on, company))
+ appr = webnotes.conn.sql("select value from `tabAuthorization Rule` where transaction = %s and value <= %s and based_on = %s and company = %s and docstatus != 2 %s %s" % ('%s', '%s', '%s', '%s', cond, add_cond2), (doctype_name, total, based_on, company))
if not appr:
- appr = sql("select value from `tabAuthorization Rule` where transaction = %s and value <= %s and based_on = %s and ifnull(company,'') = '' and docstatus != 2 %s %s"% ('%s', '%s', '%s', cond, add_cond2), (doctype_name, total, based_on))
+ appr = webnotes.conn.sql("select value from `tabAuthorization Rule` where transaction = %s and value <= %s and based_on = %s and ifnull(company,'') = '' and docstatus != 2 %s %s"% ('%s', '%s', '%s', cond, add_cond2), (doctype_name, total, based_on))
self.get_appr_user_role(appr, doctype_name, total, based_on, cond+add_cond2, item, company)
@@ -112,7 +111,7 @@ class DocType(TransactionBase):
# ================
# Check for authorization set for individual user
- based_on = [x[0] for x in sql("select distinct based_on from `tabAuthorization Rule` where transaction = %s and system_user = %s and (company = %s or ifnull(company,'')='') and docstatus != 2", (doctype_name, session['user'], company))]
+ based_on = [x[0] for x in webnotes.conn.sql("select distinct based_on from `tabAuthorization Rule` where transaction = %s and system_user = %s and (company = %s or ifnull(company,'')='') and docstatus != 2", (doctype_name, session['user'], company))]
for d in based_on:
self.bifurcate_based_on_type(doctype_name, total, av_dis, d, doc_obj, 1, company)
@@ -124,7 +123,7 @@ class DocType(TransactionBase):
# Specific Role
# ===============
# Check for authorization set on particular roles
- based_on = [x[0] for x in sql("""select based_on
+ based_on = [x[0] for x in webnotes.conn.sql("""select based_on
from `tabAuthorization Rule`
where transaction = %s and system_role IN (%s) and based_on IN (%s)
and (company = %s or ifnull(company,'')='')
@@ -148,9 +147,9 @@ class DocType(TransactionBase):
# payroll related check
def get_value_based_rule(self,doctype_name,employee,total_claimed_amount,company):
val_lst =[]
- val = sql("select value from `tabAuthorization Rule` where transaction=%s and (to_emp=%s or to_designation IN (select designation from `tabEmployee` where name=%s)) and ifnull(value,0)< %s and company = %s and docstatus!=2",(doctype_name,employee,employee,total_claimed_amount,company))
+ val = webnotes.conn.sql("select value from `tabAuthorization Rule` where transaction=%s and (to_emp=%s or to_designation IN (select designation from `tabEmployee` where name=%s)) and ifnull(value,0)< %s and company = %s and docstatus!=2",(doctype_name,employee,employee,total_claimed_amount,company))
if not val:
- val = sql("select value from `tabAuthorization Rule` where transaction=%s and (to_emp=%s or to_designation IN (select designation from `tabEmployee` where name=%s)) and ifnull(value,0)< %s and ifnull(company,'') = '' and docstatus!=2",(doctype_name, employee, employee, total_claimed_amount))
+ val = webnotes.conn.sql("select value from `tabAuthorization Rule` where transaction=%s and (to_emp=%s or to_designation IN (select designation from `tabEmployee` where name=%s)) and ifnull(value,0)< %s and ifnull(company,'') = '' and docstatus!=2",(doctype_name, employee, employee, total_claimed_amount))
if val:
val_lst = [y[0] for y in val]
@@ -158,9 +157,9 @@ class DocType(TransactionBase):
val_lst.append(0)
max_val = max(val_lst)
- rule = sql("select name, to_emp, to_designation, approving_role, approving_user from `tabAuthorization Rule` where transaction=%s and company = %s and (to_emp=%s or to_designation IN (select designation from `tabEmployee` where name=%s)) and ifnull(value,0)= %s and docstatus!=2",(doctype_name,company,employee,employee,flt(max_val)), as_dict=1)
+ rule = webnotes.conn.sql("select name, to_emp, to_designation, approving_role, approving_user from `tabAuthorization Rule` where transaction=%s and company = %s and (to_emp=%s or to_designation IN (select designation from `tabEmployee` where name=%s)) and ifnull(value,0)= %s and docstatus!=2",(doctype_name,company,employee,employee,flt(max_val)), as_dict=1)
if not rule:
- rule = sql("select name, to_emp, to_designation, approving_role, approving_user from `tabAuthorization Rule` where transaction=%s and ifnull(company,'') = '' and (to_emp=%s or to_designation IN (select designation from `tabEmployee` where name=%s)) and ifnull(value,0)= %s and docstatus!=2",(doctype_name,employee,employee,flt(max_val)), as_dict=1)
+ rule = webnotes.conn.sql("select name, to_emp, to_designation, approving_role, approving_user from `tabAuthorization Rule` where transaction=%s and ifnull(company,'') = '' and (to_emp=%s or to_designation IN (select designation from `tabEmployee` where name=%s)) and ifnull(value,0)= %s and docstatus!=2",(doctype_name,employee,employee,flt(max_val)), as_dict=1)
return rule
@@ -175,9 +174,9 @@ class DocType(TransactionBase):
if doctype_name == 'Expense Claim':
rule = self.get_value_based_rule(doctype_name,doc_obj.doc.employee,doc_obj.doc.total_claimed_amount, doc_obj.doc.company)
elif doctype_name == 'Appraisal':
- rule = sql("select name, to_emp, to_designation, approving_role, approving_user from `tabAuthorization Rule` where transaction=%s and (to_emp=%s or to_designation IN (select designation from `tabEmployee` where name=%s)) and company = %s and docstatus!=2",(doctype_name,doc_obj.doc.employee, doc_obj.doc.employee, doc_obj.doc.company),as_dict=1)
+ rule = webnotes.conn.sql("select name, to_emp, to_designation, approving_role, approving_user from `tabAuthorization Rule` where transaction=%s and (to_emp=%s or to_designation IN (select designation from `tabEmployee` where name=%s)) and company = %s and docstatus!=2",(doctype_name,doc_obj.doc.employee, doc_obj.doc.employee, doc_obj.doc.company),as_dict=1)
if not rule:
- rule = sql("select name, to_emp, to_designation, approving_role, approving_user from `tabAuthorization Rule` where transaction=%s and (to_emp=%s or to_designation IN (select designation from `tabEmployee` where name=%s)) and ifnull(company,'') = '' and docstatus!=2",(doctype_name,doc_obj.doc.employee, doc_obj.doc.employee),as_dict=1)
+ rule = webnotes.conn.sql("select name, to_emp, to_designation, approving_role, approving_user from `tabAuthorization Rule` where transaction=%s and (to_emp=%s or to_designation IN (select designation from `tabEmployee` where name=%s)) and ifnull(company,'') = '' and docstatus!=2",(doctype_name,doc_obj.doc.employee, doc_obj.doc.employee),as_dict=1)
if rule:
for m in rule:
@@ -185,7 +184,7 @@ class DocType(TransactionBase):
if m['approving_user']:
app_specific_user.append(m['approving_user'])
elif m['approving_role']:
- user_lst = [z[0] for z in sql("select distinct t1.name from `tabProfile` t1, `tabUserRole` t2 where t2.role=%s and t2.parent=t1.name and t1.name !='Administrator' and t1.name != 'Guest' and t1.docstatus !=2",m['approving_role'])]
+ user_lst = [z[0] for z in webnotes.conn.sql("select distinct t1.name from `tabProfile` t1, `tabUserRole` t2 where t2.role=%s and t2.parent=t1.name and t1.name !='Administrator' and t1.name != 'Guest' and t1.docstatus !=2",m['approving_role'])]
for x in user_lst:
if not x in app_user:
app_user.append(x)
diff --git a/setup/doctype/authorization_rule/authorization_rule.py b/setup/doctype/authorization_rule/authorization_rule.py
index 3d2de4776d6..ea22b154b91 100644
--- a/setup/doctype/authorization_rule/authorization_rule.py
+++ b/setup/doctype/authorization_rule/authorization_rule.py
@@ -9,7 +9,6 @@ from webnotes.model import db_exists
from webnotes.model.bean import copy_doclist
from webnotes import msgprint
-sql = webnotes.conn.sql
@@ -19,7 +18,7 @@ class DocType:
def check_duplicate_entry(self):
- exists = sql("""select name, docstatus from `tabAuthorization Rule`
+ exists = webnotes.conn.sql("""select name, docstatus from `tabAuthorization Rule`
where transaction = %s and based_on = %s and system_user = %s
and system_role = %s and approving_user = %s and approving_role = %s
and to_emp =%s and to_designation=%s and name != %s""",
@@ -39,12 +38,12 @@ class DocType:
def validate_master_name(self):
if self.doc.based_on == 'Customerwise Discount' and \
- not sql("select name from tabCustomer where name = '%s' and docstatus != 2" % \
+ not webnotes.conn.sql("select name from tabCustomer where name = '%s' and docstatus != 2" % \
(self.doc.master_name)):
msgprint("Please select valid Customer Name for Customerwise Discount",
raise_exception=1)
elif self.doc.based_on == 'Itemwise Discount' and \
- not sql("select name from tabItem where name = '%s' and docstatus != 2" % \
+ not webnotes.conn.sql("select name from tabItem where name = '%s' and docstatus != 2" % \
(self.doc.master_name)):
msgprint("Please select valid Item Name for Itemwise Discount", raise_exception=1)
elif (self.doc.based_on == 'Grand Total' or \
@@ -65,7 +64,7 @@ class DocType:
Applicable To (Role).", raise_exception=1)
elif self.doc.system_user and self.doc.approving_role and \
has_common([self.doc.approving_role], [x[0] for x in \
- sql("select role from `tabUserRole` where parent = '%s'" % \
+ webnotes.conn.sql("select role from `tabUserRole` where parent = '%s'" % \
(self.doc.system_user))]):
msgprint("System User : %s is assigned role : %s. So rule does not make sense" %
(self.doc.system_user,self.doc.approving_role), raise_exception=1)
diff --git a/setup/doctype/backup_manager/backup_dropbox.py b/setup/doctype/backup_manager/backup_dropbox.py
index 8d163539522..3d3f428260a 100644
--- a/setup/doctype/backup_manager/backup_dropbox.py
+++ b/setup/doctype/backup_manager/backup_dropbox.py
@@ -61,8 +61,8 @@ def dropbox_callback(oauth_token=None, not_approved=False):
allowed = 0
message = "Dropbox Access not approved."
- webnotes.message_title = "Dropbox Approval"
- webnotes.message = "
" % message
webnotes.conn.commit()
webnotes.response['type'] = 'page'
@@ -96,6 +96,7 @@ def backup_to_dropbox():
error_log = []
path = os.path.join(get_base_path(), "public", "files")
for filename in os.listdir(path):
+ filename = cstr(filename)
if filename in ignore_list:
continue
diff --git a/setup/doctype/backup_manager/backup_googledrive.py b/setup/doctype/backup_manager/backup_googledrive.py
index 5d7b6ad0fa1..c72295ae627 100644
--- a/setup/doctype/backup_manager/backup_googledrive.py
+++ b/setup/doctype/backup_manager/backup_googledrive.py
@@ -85,6 +85,7 @@ def backup_to_gdrive():
webnotes.conn.close()
path = os.path.join(get_base_path(), "public", "files")
for filename in os.listdir(path):
+ filename = cstr(filename)
found = False
filepath = os.path.join(path, filename)
ext = filename.split('.')[-1]
@@ -113,9 +114,9 @@ def backup_to_gdrive():
def get_gdrive_flow():
from oauth2client.client import OAuth2WebServerFlow
- import conf
+ from webnotes import conf
- if not hasattr(conf, "gdrive_client_id"):
+ if not "gdrive_client_id" in conf:
webnotes.msgprint(_("Please set Google Drive access keys in") + " conf.py",
raise_exception=True)
@@ -169,4 +170,4 @@ def create_folder(name, service, folder_id):
return database['id']
if __name__=="__main__":
- backup_to_gdrive()
\ No newline at end of file
+ backup_to_gdrive()
diff --git a/setup/doctype/company/charts/import_from_openerp.py b/setup/doctype/company/charts/import_from_openerp.py
index 894c2d739d8..ef800086c94 100644
--- a/setup/doctype/company/charts/import_from_openerp.py
+++ b/setup/doctype/company/charts/import_from_openerp.py
@@ -9,6 +9,7 @@ from __future__ import unicode_literals
import os, json
from xml.etree import ElementTree as ET
from webnotes.utils.datautils import read_csv_content
+from webnotes.utils import cstr
path = "/Users/rmehta/Downloads/openerp/openerp/addons"
chart_roots = []
@@ -108,6 +109,7 @@ def find_charts():
basename = os.path.basename(basepath)
if basename.startswith("l10n"):
for fname in files:
+ fname = cstr(fname)
filepath = os.path.join(basepath, fname)
if fname.endswith(".xml"):
tree = ET.parse(filepath)
diff --git a/setup/doctype/company/company.py b/setup/doctype/company/company.py
index 9746eb240ba..da220cc6bee 100644
--- a/setup/doctype/company/company.py
+++ b/setup/doctype/company/company.py
@@ -10,7 +10,6 @@ from webnotes.model.doc import Document
from webnotes.model.code import get_obj
import webnotes.defaults
-sql = webnotes.conn.sql
class DocType:
def __init__(self,d,dl):
diff --git a/setup/doctype/company/company.txt b/setup/doctype/company/company.txt
index 1ba1dde4811..eb6b9ad35f4 100644
--- a/setup/doctype/company/company.txt
+++ b/setup/doctype/company/company.txt
@@ -2,7 +2,7 @@
{
"creation": "2013-04-10 08:35:39",
"docstatus": 0,
- "modified": "2013-08-28 19:15:04",
+ "modified": "2013-10-08 15:18:34",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -80,7 +80,7 @@
"fieldtype": "Select",
"label": "Domain",
"options": "Distribution\nManufacturing\nRetail\nServices",
- "reqd": 1
+ "reqd": 0
},
{
"doctype": "DocField",
diff --git a/setup/doctype/customer_group/customer_group.py b/setup/doctype/customer_group/customer_group.py
index 0940e1f0b3c..1264c1b3ece 100644
--- a/setup/doctype/customer_group/customer_group.py
+++ b/setup/doctype/customer_group/customer_group.py
@@ -5,7 +5,6 @@ from __future__ import unicode_literals
import webnotes
from webnotes import msgprint
-sql = webnotes.conn.sql
from webnotes.utils.nestedset import DocTypeNestedSet
class DocType(DocTypeNestedSet):
@@ -15,7 +14,7 @@ class DocType(DocTypeNestedSet):
self.nsm_parent_field = 'parent_customer_group';
def validate(self):
- if sql("select name from `tabCustomer Group` where name = %s and docstatus = 2",
+ if webnotes.conn.sql("select name from `tabCustomer Group` where name = %s and docstatus = 2",
(self.doc.customer_group_name)):
msgprint("""Another %s record is trashed.
To untrash please go to Setup -> Recycle Bin.""" %
@@ -33,7 +32,7 @@ class DocType(DocTypeNestedSet):
self.doc.name, raise_exception=1)
def on_trash(self):
- cust = sql("select name from `tabCustomer` where ifnull(customer_group, '') = %s",
+ cust = webnotes.conn.sql("select name from `tabCustomer` where ifnull(customer_group, '') = %s",
self.doc.name)
cust = [d[0] for d in cust]
if cust:
@@ -42,7 +41,7 @@ class DocType(DocTypeNestedSet):
To trash/delete this, remove/change customer group in customer master""" %
(self.doc.name, cust or ''), raise_exception=1)
- if sql("select name from `tabCustomer Group` where parent_customer_group = %s \
+ if webnotes.conn.sql("select name from `tabCustomer Group` where parent_customer_group = %s \
and docstatus != 2", self.doc.name):
msgprint("Child customer group exists for this customer group. \
You can not trash/cancel/delete this customer group.", raise_exception=1)
diff --git a/setup/doctype/email_digest/email_digest.py b/setup/doctype/email_digest/email_digest.py
index 07efd16ec8b..9a00723110f 100644
--- a/setup/doctype/email_digest/email_digest.py
+++ b/setup/doctype/email_digest/email_digest.py
@@ -457,8 +457,8 @@ def send():
from webnotes.utils import getdate
now_date = now_datetime().date()
- import conf
- if hasattr(conf, "expires_on") and now_date > getdate(conf.expires_on):
+ from webnotes import conf
+ if "expires_on" in conf and now_date > getdate(conf.expires_on):
# do not send email digests to expired accounts
return
diff --git a/setup/doctype/email_settings/email_settings.py b/setup/doctype/email_settings/email_settings.py
index 219501eb13f..aa511eefcdd 100644
--- a/setup/doctype/email_settings/email_settings.py
+++ b/setup/doctype/email_settings/email_settings.py
@@ -3,7 +3,6 @@
from __future__ import unicode_literals
import webnotes
-sql = webnotes.conn.sql
from webnotes.utils import cint
diff --git a/setup/doctype/item_group/item_group.js b/setup/doctype/item_group/item_group.js
index c5a08d4daee..6dbb0d273bf 100644
--- a/setup/doctype/item_group/item_group.js
+++ b/setup/doctype/item_group/item_group.js
@@ -7,6 +7,12 @@ cur_frm.cscript.refresh = function(doc, cdt, cdn) {
cur_frm.add_custom_button(wn._("Item Group Tree"), function() {
wn.set_route("Sales Browser", "Item Group");
})
+
+ if(!doc.__islocal && doc.show_in_website) {
+ cur_frm.add_custom_button("View In Website", function() {
+ window.open(doc.page_name);
+ }, "icon-globe");
+ }
}
cur_frm.cscript.set_root_readonly = function(doc) {
diff --git a/setup/doctype/naming_series/naming_series.py b/setup/doctype/naming_series/naming_series.py
index 9cc4de294b8..4e85b15f6d9 100644
--- a/setup/doctype/naming_series/naming_series.py
+++ b/setup/doctype/naming_series/naming_series.py
@@ -8,7 +8,6 @@ from webnotes.utils import cstr
from webnotes import msgprint
import webnotes.model.doctype
-sql = webnotes.conn.sql
class DocType:
def __init__(self, d, dl):
@@ -23,7 +22,7 @@ class DocType:
where fieldname='naming_series'""")
)))),
"prefixes": "\n".join([''] + [i[0] for i in
- sql("""select name from tabSeries""")])
+ webnotes.conn.sql("""select name from tabSeries""")])
}
def scrub_options_list(self, ol):
@@ -126,12 +125,12 @@ class DocType:
def insert_series(self, series):
"""insert series if missing"""
if not webnotes.conn.exists('Series', series):
- sql("insert into tabSeries (name, current) values (%s,0)", (series))
+ webnotes.conn.sql("insert into tabSeries (name, current) values (%s,0)", (series))
def update_series_start(self):
if self.doc.prefix:
self.insert_series(self.doc.prefix)
- sql("update `tabSeries` set current = '%s' where name = '%s'" % (self.doc.current_value,self.doc.prefix))
+ webnotes.conn.sql("update `tabSeries` set current = '%s' where name = '%s'" % (self.doc.current_value,self.doc.prefix))
msgprint("Series Updated Successfully")
else:
msgprint("Please select prefix first")
diff --git a/setup/doctype/notification_control/notification_control.py b/setup/doctype/notification_control/notification_control.py
index 6133d9b7019..0a151152d6e 100644
--- a/setup/doctype/notification_control/notification_control.py
+++ b/setup/doctype/notification_control/notification_control.py
@@ -6,7 +6,6 @@ import webnotes
from webnotes import msgprint
-sql = webnotes.conn.sql
class DocType:
def __init__(self,d,dl):
@@ -14,7 +13,7 @@ class DocType:
def get_message(self, arg):
fn = arg.lower().replace(' ', '_') + '_message'
- v = sql("select value from tabSingles where field=%s and doctype=%s", (fn, 'Notification Control'))
+ v = webnotes.conn.sql("select value from tabSingles where field=%s and doctype=%s", (fn, 'Notification Control'))
return v and v[0][0] or ''
def set_message(self, arg = ''):
diff --git a/setup/doctype/price_list/price_list.css b/setup/doctype/price_list/price_list.css
new file mode 100644
index 00000000000..61b069442f8
--- /dev/null
+++ b/setup/doctype/price_list/price_list.css
@@ -0,0 +1,7 @@
+.table-grid tbody tr {
+ cursor: pointer;
+}
+
+.table-grid thead tr {
+ height: 50px;
+}
\ No newline at end of file
diff --git a/setup/doctype/price_list/price_list.js b/setup/doctype/price_list/price_list.js
index f3adc727579..67090bcbc16 100644
--- a/setup/doctype/price_list/price_list.js
+++ b/setup/doctype/price_list/price_list.js
@@ -5,4 +5,253 @@ $.extend(cur_frm.cscript, {
onload: function() {
erpnext.add_for_territory();
},
+});
+
+cur_frm.cscript.refresh = function(doc, cdt, cdn) {
+ cur_frm.cscript.show_item_prices();
+}
+
+cur_frm.cscript.show_item_prices = function() {
+ var item_price = wn.model.get("Item Price", {parent: cur_frm.doc.name});
+
+ $(cur_frm.fields_dict.item_prices_html.wrapper).empty();
+
+ new wn.ui.form.TableGrid({
+ parent: cur_frm.fields_dict.item_prices_html.wrapper,
+ frm: cur_frm,
+ table_field: wn.meta.get_docfield("Price List", "item_prices", cur_frm.doc.name)
+ });
+}
+
+wn.ui.form.TableGrid = Class.extend({
+ init: function(opts) {
+ $.extend(this, opts);
+ this.fields = wn.meta.get_docfields("Item Price", cur_frm.doc.name);
+ this.make_table();
+ },
+ make_table: function() {
+ var me = this;
+ // Creating table & assigning attributes
+ var grid_table = document.createElement("table");
+ grid_table.className = "table table-hover table-bordered table-grid";
+
+ // Appending header & rows to table
+ grid_table.appendChild(this.make_table_headers());
+ grid_table.appendChild(this.make_table_rows());
+
+ // Creating button to add new row
+ var btn_div = document.createElement("div");
+ var new_row_btn = document.createElement("button");
+ new_row_btn.className = "btn btn-success table-new-row";
+ new_row_btn.title = "Add new row";
+
+ var btn_icon = document.createElement("i");
+ btn_icon.className = "icon-plus";
+ new_row_btn.appendChild(btn_icon);
+ new_row_btn.innerHTML += " Add new row";
+ btn_div.appendChild(new_row_btn);
+
+ // Appending table & button to parent
+ var $grid_table = $(grid_table).appendTo($(this.parent));
+ var $btn_div = $(btn_div).appendTo($(this.parent));
+
+ $btn_div.on("click", ".table-new-row", function() {
+ me.make_dialog();
+ return false;
+ });
+
+ $grid_table.on("click", ".table-row", function() {
+ me.make_dialog(this);
+ return false;
+ });
+ },
+ make_table_headers: function() {
+ var me = this;
+ var header = document.createElement("thead");
+
+ // Creating header row
+ var row = document.createElement("tr");
+ row.className = "active";
+
+ // Creating head first cell
+ var th = document.createElement("th");
+ th.width = "8%";
+ th.className = "text-center";
+ th.innerHTML = "#";
+ row.appendChild(th);
+
+ // Make other headers with label as heading
+ for(var i=0, l=this.fields.length; iDelete';
+
+ return buttons;
+ },
+ update_row: function(row) {
+ var me = this;
+
+ if (!row) {
+ var d = wn.model.add_child(this.frm.doc, this.table_field.options,
+ this.table_field.fieldname);
+ refresh_field(this.table_field.fieldname);
+ this.update_item_price(d.name);
+ var tr = this.add_new_row(d);
+ this.table_body.appendChild(tr);
+ }
+ else {
+ this.update_item_price(null, row);
+ }
+
+ this.dialog.hide();
+ },
+
+ update_item_price: function(docname, row) {
+ var me = this;
+ if(!docname && row) docname = $(row).attr("data-docname");
+ $.each(me.fields, function(i, df) {
+ var val = me.dialog.get_values()[df.fieldname];
+
+ if(["Currency", "Float"].indexOf(df.fieldtype)!==-1) {
+ val = flt(val);
+ } else if(["Int", "Check"].indexOf(df.fieldtype)!==-1) {
+ val = cint(val);
+ }
+
+ wn.model.set_value(me.table_field.options, docname,
+ df.fieldname, val);
+
+ if(row) {
+ var $td = $(row).find('td[data-fieldname="'+ df.fieldname +'"]');
+ $td.attr('data-fieldvalue', val);
+ // If field type is currency the update with format currency
+ $td.html(wn.format(val, df));
+ }
+ });
+ },
+
+ delete_row: function(row) {
+ var me = this;
+ var docname = $(row).find('td:last').attr('data-docname');
+ wn.model.clear_doc(me.table_field.options, docname);
+ $(row).remove();
+
+ // Re-assign idx
+ $.each($(this.parent).find("tbody tr"), function(idx, data) {
+ var $td = $(data).find('td:first');
+ $td.html(idx + 1);
+ });
+ this.dialog.hide();
+ },
+
+ add_new_row: function(d) {
+ var tr = document.createElement("tr");
+ tr.className = "table-row";
+ tr.setAttribute("data-docname", d.name);
+
+ // Creating table data & appending to row
+ var td = document.createElement("td");
+ td.className = "text-center";
+ td.innerHTML = d.idx;
+ tr.appendChild(td);
+
+ for(var f=0, lf=this.fields.length; f"' + 'Setup Complete. Please check your \
- To Do List' + '"', '#6B24B3')
-
- d = Document('ToDo')
- d.description = 'Complete ERPNext Setup'
- d.priority = 'High'
- d.date = nowdate()
- d.save(1)
-
- def create_email_digest(self):
- """
- create a default weekly email digest
- * Weekly Digest
- * For all companies
- * Recipients: System Managers
- * Full content
- * Enabled by default
- """
- import webnotes
- companies_list = webnotes.conn.sql("SELECT company_name FROM `tabCompany`", as_list=1)
-
- from webnotes.profile import get_system_managers
- system_managers = get_system_managers()
- if not system_managers: return
-
- from webnotes.model.doc import Document
- for company in companies_list:
- if company and company[0]:
- edigest = webnotes.bean({
- "doctype": "Email Digest",
- "name": "Default Weekly Digest - " + company[0],
- "company": company[0],
- "frequency": "Weekly",
- "recipient_list": "\n".join(system_managers)
- })
-
- if webnotes.conn.sql("""select name from `tabEmail Digest` where name=%s""", edigest.doc.name):
- continue
-
- for fieldname in edigest.meta.get_fieldnames({"fieldtype": "Check"}):
- edigest.doc.fields[fieldname] = 1
-
- edigest.insert()
-
- # Get Fiscal year Details
- # ------------------------
- def get_fy_details(self, fy_start, last_year=False):
- st = {'1st Jan':'01-01','1st Apr':'04-01','1st Jul':'07-01', '1st Oct': '10-01'}
- if cint(getdate(nowdate()).month) < cint((st[fy_start].split('-'))[0]):
- curr_year = getdate(nowdate()).year - 1
- else:
- curr_year = getdate(nowdate()).year
-
- if last_year:
- curr_year = curr_year - 1
-
- stdt = cstr(curr_year)+'-'+cstr(st[fy_start])
-
- if(fy_start == '1st Jan'):
- fy = cstr(curr_year)
- abbr = cstr(fy)[-2:]
- else:
- fy = cstr(curr_year) + '-' + cstr(curr_year+1)
- abbr = cstr(curr_year)[-2:] + '-' + cstr(curr_year+1)[-2:]
- return fy, stdt, abbr
-
- def create_profile(self, user_email, user_fname, user_lname, pwd=None):
- pr = Document('Profile')
- pr.first_name = user_fname
- pr.last_name = user_lname
- pr.name = pr.email = user_email
- pr.enabled = 1
- pr.save(1)
- if pwd:
- webnotes.conn.sql("""insert into __Auth (user, `password`)
- values (%s, password(%s))
- on duplicate key update `password`=password(%s)""",
- (user_email, pwd, pwd))
-
- add_all_roles_to(pr.name)
-
-def add_all_roles_to(name):
- profile = webnotes.doc("Profile", name)
- for role in webnotes.conn.sql("""select name from tabRole"""):
- if role[0] not in ["Administrator", "Guest", "All", "Customer", "Supplier", "Partner"]:
- d = profile.addchild("user_roles", "UserRole")
- d.role = role[0]
- d.insert()
-
-def create_territories():
- """create two default territories, one for home country and one named Rest of the World"""
- from setup.utils import get_root_of
- country = webnotes.conn.get_value("Control Panel", None, "country")
- root_territory = get_root_of("Territory")
- for name in (country, "Rest Of The World"):
- if name and not webnotes.conn.exists("Territory", name):
- webnotes.bean({
- "doctype": "Territory",
- "territory_name": name.replace("'", ""),
- "parent_territory": root_territory,
- "is_group": "No"
- }).insert()
-
diff --git a/setup/doctype/setup_control/setup_control.txt b/setup/doctype/setup_control/setup_control.txt
deleted file mode 100644
index 7ebed3e4a13..00000000000
--- a/setup/doctype/setup_control/setup_control.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-[
- {
- "creation": "2012-03-27 14:36:25",
- "docstatus": 0,
- "modified": "2012-03-27 14:36:25",
- "modified_by": "Administrator",
- "owner": "Administrator"
- },
- {
- "doctype": "DocType",
- "in_create": 1,
- "issingle": 1,
- "istable": 0,
- "module": "Setup",
- "name": "__common__",
- "read_only": 1,
- "section_style": "Simple",
- "version": 73
- },
- {
- "doctype": "DocType",
- "name": "Setup Control"
- }
-]
\ No newline at end of file
diff --git a/setup/doctype/uom/uom.txt b/setup/doctype/uom/uom.txt
index 6577f6c0058..51d98067552 100644
--- a/setup/doctype/uom/uom.txt
+++ b/setup/doctype/uom/uom.txt
@@ -2,7 +2,7 @@
{
"creation": "2013-01-10 16:34:24",
"docstatus": 0,
- "modified": "2013-07-25 16:18:17",
+ "modified": "2013-10-10 15:06:53",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -38,22 +38,6 @@
"doctype": "DocType",
"name": "UOM"
},
- {
- "doctype": "DocField",
- "fieldname": "trash_reason",
- "fieldtype": "Small Text",
- "label": "Trash Reason",
- "oldfieldname": "trash_reason",
- "oldfieldtype": "Small Text",
- "read_only": 1
- },
- {
- "doctype": "DocField",
- "fieldname": "uom_details",
- "fieldtype": "Section Break",
- "label": "UOM Details",
- "oldfieldtype": "Section Break"
- },
{
"doctype": "DocField",
"fieldname": "uom_name",
diff --git a/setup/page/setup_wizard/__init__.py b/setup/page/setup_wizard/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/setup/page/setup_wizard/setup_wizard.css b/setup/page/setup_wizard/setup_wizard.css
new file mode 100644
index 00000000000..ad49ef0c049
--- /dev/null
+++ b/setup/page/setup_wizard/setup_wizard.css
@@ -0,0 +1,8 @@
+#page-setup-wizard .panel {
+ -webkit-box-shadow: 0px 1px 8px rgba(0,0,0,0.6);
+ box-shadow: 0px 1px 8px rgba(0,0,0,0.6);
+}
+
+#page-setup-wizard .col-md-6 .control-input .btn {
+ width: 100%;
+}
diff --git a/setup/page/setup_wizard/setup_wizard.js b/setup/page/setup_wizard/setup_wizard.js
new file mode 100644
index 00000000000..648958e6267
--- /dev/null
+++ b/setup/page/setup_wizard/setup_wizard.js
@@ -0,0 +1,499 @@
+wn.pages['setup-wizard'].onload = function(wrapper) {
+ if(sys_defaults.company) {
+ wn.set_route("desktop");
+ return;
+ }
+ $(".navbar:first").toggle(false);
+ $("body").css({"padding-top":"30px"});
+
+ erpnext.wiz = new wn.wiz.Wizard({
+ page_name: "setup-wizard",
+ parent: wrapper,
+ on_complete: function(wiz) {
+ var values = wiz.get_values();
+ wiz.show_working();
+ wn.call({
+ method: "setup.page.setup_wizard.setup_wizard.setup_account",
+ args: values,
+ callback: function(r) {
+ if(r.exc) {
+ var d = msgprint(wn._("There were errors."));
+ d.custom_onhide = function() {
+ wn.set_route(erpnext.wiz.page_name, "0");
+ }
+ } else {
+ wiz.show_complete();
+ setTimeout(function() {
+ if(user==="Administrator") {
+ msgprint(wn._("Login with your new User ID") + ":" + values.email);
+ setTimeout(function() {
+ wn.app.logout();
+ }, 2000);
+ } else {
+ window.location = "app.html";
+ }
+ }, 2000);
+ }
+ }
+ })
+ },
+ title: wn._("ERPNext Setup Guide"),
+ welcome_html: '
\
+
'+wn._('ERPNext Setup')+'
\
+
' +
+ wn._('Welcome to ERPNext. Over the next few minutes we will help you setup your ERPNext account. Try and fill in as much information as you have even if it takes a bit longer. It will save you a lot of time later. Good Luck!') +
+ '
',
+ working_html: '
\
+
'+wn._('Setting up...')+'
\
+
' +
+ wn._('Sit tight while your system is being setup. This may take a few moments.') +
+ '