Merge with 3.3.8
diff --git a/erpnext/accounts/doctype/account/account.js b/erpnext/accounts/doctype/account/account.js
index b6986cf..8837586 100644
--- a/erpnext/accounts/doctype/account/account.js
+++ b/erpnext/accounts/doctype/account/account.js
@@ -95,9 +95,10 @@
wn.route_options = {
"account": doc.name,
"from_date": sys_defaults.year_start_date,
- "to_date": sys_defaults.year_end_date
+ "to_date": sys_defaults.year_end_date,
+ "company": doc.company
};
- wn.set_route("general-ledger");
+ wn.set_route("query-report", "General Ledger");
}, "icon-table");
}
}
diff --git a/erpnext/accounts/doctype/account/account.py b/erpnext/accounts/doctype/account/account.py
index eccbb47..99d4f24 100644
--- a/erpnext/accounts/doctype/account/account.py
+++ b/erpnext/accounts/doctype/account/account.py
@@ -211,6 +211,9 @@
# Validate properties before merging
if merge:
+ if not webnotes.conn.exists("Account", new):
+ webnotes.throw(_("Account ") + new +_(" does not exists"))
+
val = list(webnotes.conn.get_value("Account", new_account,
["group_or_ledger", "debit_or_credit", "is_pl_account"]))
diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.py b/erpnext/accounts/doctype/accounts_settings/accounts_settings.py
index d55b022..a6e9938 100644
--- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.py
+++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.py
@@ -5,8 +5,7 @@
from __future__ import unicode_literals
import webnotes
-from webnotes.utils import cint, cstr
-from webnotes import msgprint, _
+from webnotes import _
class DocType:
def __init__(self, d, dl):
@@ -16,6 +15,11 @@
webnotes.conn.set_default("auto_accounting_for_stock", self.doc.auto_accounting_for_stock)
if self.doc.auto_accounting_for_stock:
- for wh in webnotes.conn.sql("select name from `tabWarehouse`"):
- wh_bean = webnotes.bean("Warehouse", wh[0])
+ warehouse_list = webnotes.conn.sql("select name, company from tabWarehouse", as_dict=1)
+ warehouse_with_no_company = [d.name for d in warehouse_list if not d.company]
+ if warehouse_with_no_company:
+ webnotes.throw(_("Company is missing in following warehouses") + ": \n" +
+ "\n".join(warehouse_with_no_company))
+ for wh in warehouse_list:
+ wh_bean = webnotes.bean("Warehouse", wh.name)
wh_bean.save()
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.py b/erpnext/accounts/doctype/gl_entry/gl_entry.py
index 8286c8f..ff44d55 100644
--- a/erpnext/accounts/doctype/gl_entry/gl_entry.py
+++ b/erpnext/accounts/doctype/gl_entry/gl_entry.py
@@ -5,8 +5,7 @@
import webnotes
from webnotes.utils import flt, fmt_money, getdate
-from webnotes.model.code import get_obj
-from webnotes import msgprint, _
+from webnotes import _
class DocType:
def __init__(self,d,dl):
@@ -130,11 +129,12 @@
against_voucher_amount = flt(webnotes.conn.sql("""
select sum(ifnull(debit, 0)) - sum(ifnull(credit, 0))
from `tabGL Entry` where voucher_type = 'Journal Voucher' and voucher_no = %s
- and account = %s""", (against_voucher, account))[0][0])
+ and account = %s and ifnull(against_voucher, '') = ''""",
+ (against_voucher, account))[0][0])
bal = against_voucher_amount + bal
if against_voucher_amount < 0:
bal = -bal
-
+
# Validation : Outstanding can not be negative
if bal < 0 and not on_cancel:
webnotes.throw(_("Outstanding for Voucher ") + against_voucher + _(" will become ") +
diff --git a/erpnext/accounts/doctype/journal_voucher/journal_voucher.js b/erpnext/accounts/doctype/journal_voucher/journal_voucher.js
index f1b6959..1eb8b1d 100644
--- a/erpnext/accounts/doctype/journal_voucher/journal_voucher.js
+++ b/erpnext/accounts/doctype/journal_voucher/journal_voucher.js
@@ -120,8 +120,9 @@
"voucher_no": doc.name,
"from_date": doc.posting_date,
"to_date": doc.posting_date,
+ "company": doc.company
};
- wn.set_route("general-ledger");
+ wn.set_route("query-report", "General Ledger");
}, "icon-table");
}
}
diff --git a/erpnext/accounts/doctype/payment_to_invoice_matching_tool/payment_to_invoice_matching_tool.py b/erpnext/accounts/doctype/payment_to_invoice_matching_tool/payment_to_invoice_matching_tool.py
index efd2e91..0c6cdb6 100644
--- a/erpnext/accounts/doctype/payment_to_invoice_matching_tool/payment_to_invoice_matching_tool.py
+++ b/erpnext/accounts/doctype/payment_to_invoice_matching_tool/payment_to_invoice_matching_tool.py
@@ -145,6 +145,8 @@
and voucher_no != gle.voucher_no)
!= abs(ifnull(gle.debit, 0) - ifnull(gle.credit, 0)
)
+ and if(gle.voucher_type='Sales Invoice', (select is_pos from `tabSales Invoice`
+ where name=gle.voucher_no), 0)=0
%(mcond)s
ORDER BY gle.posting_date desc, gle.voucher_no desc
limit %(start)s, %(page_len)s""" % {
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
index 23a55d3..aa3b45f 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
@@ -35,8 +35,9 @@
"voucher_no": doc.name,
"from_date": doc.posting_date,
"to_date": doc.posting_date,
+ "company": doc.company
};
- wn.set_route("general-ledger");
+ wn.set_route("query-report", "General Ledger");
}, "icon-table");
}
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index ddc68e7..f6b6ef4 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -350,7 +350,7 @@
# item gl entries
stock_item_and_auto_accounting_for_stock = False
stock_items = self.get_stock_items()
- rounding_diff = 0.0
+ # rounding_diff = 0.0
for item in self.doclist.get({"parentfield": "entries"}):
if auto_accounting_for_stock and item.item_code in stock_items:
if flt(item.valuation_rate):
@@ -359,13 +359,12 @@
# expense will be booked in sales invoice
stock_item_and_auto_accounting_for_stock = True
- valuation_amt = flt(flt(item.valuation_rate) * flt(item.qty) * \
- flt(item.conversion_factor), self.precision("valuation_rate", item))
+ valuation_amt = item.amount + item.item_tax_amount + item.rm_supp_cost
- rounding_diff += (flt(item.amount, self.precision("amount", item)) +
- flt(item.item_tax_amount, self.precision("item_tax_amount", item)) +
- flt(item.rm_supp_cost, self.precision("rm_supp_cost", item)) -
- valuation_amt)
+ # rounding_diff += (flt(item.amount, self.precision("amount", item)) +
+ # flt(item.item_tax_amount, self.precision("item_tax_amount", item)) +
+ # flt(item.rm_supp_cost, self.precision("rm_supp_cost", item)) -
+ # valuation_amt)
gl_entries.append(
self.get_gl_dict({
@@ -394,11 +393,11 @@
expenses_included_in_valuation = \
self.get_company_default("expenses_included_in_valuation")
- if rounding_diff:
- import operator
- cost_center_with_max_value = max(valuation_tax.iteritems(),
- key=operator.itemgetter(1))[0]
- valuation_tax[cost_center_with_max_value] -= flt(rounding_diff)
+ # if rounding_diff:
+ # import operator
+ # cost_center_with_max_value = max(valuation_tax.iteritems(),
+ # key=operator.itemgetter(1))[0]
+ # valuation_tax[cost_center_with_max_value] -= flt(rounding_diff)
for cost_center, amount in valuation_tax.items():
gl_entries.append(
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index 630dfe2..9c6a9b2 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -54,8 +54,9 @@
"voucher_no": doc.name,
"from_date": doc.posting_date,
"to_date": doc.posting_date,
+ "company": doc.company
};
- wn.set_route("general-ledger");
+ wn.set_route("query-report", "General Ledger");
}, "icon-table");
var percent_paid = cint(flt(doc.grand_total - doc.outstanding_amount) / flt(doc.grand_total) * 100);
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index f49541b..f77abfe 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -399,9 +399,10 @@
if not self.doc.cash_bank_account and flt(self.doc.paid_amount):
msgprint("Cash/Bank Account is mandatory for POS, for making payment entry")
raise Exception
- if (flt(self.doc.paid_amount) + flt(self.doc.write_off_amount) - round(flt(self.doc.grand_total), 2))>0.001:
- msgprint("(Paid amount + Write Off Amount) can not be greater than Grand Total")
- raise Exception
+ if flt(self.doc.paid_amount) + flt(self.doc.write_off_amount) \
+ - flt(self.doc.grand_total) > 1/(10**(self.precision("grand_total") + 1)):
+ webnotes.throw(_("""(Paid amount + Write Off Amount) can not be \
+ greater than Grand Total"""))
def validate_item_code(self):
diff --git a/erpnext/accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.txt b/erpnext/accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.txt
index fbba643..b006c1d 100644
--- a/erpnext/accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.txt
+++ b/erpnext/accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.txt
@@ -2,7 +2,7 @@
{
"creation": "2013-04-24 11:39:32",
"docstatus": 0,
- "modified": "2013-07-10 14:54:21",
+ "modified": "2013-12-17 12:38:08",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -39,9 +39,18 @@
},
{
"doctype": "DocField",
+ "fieldname": "row_id",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "label": "Enter Row",
+ "oldfieldname": "row_id",
+ "oldfieldtype": "Data"
+ },
+ {
+ "doctype": "DocField",
"fieldname": "account_head",
"fieldtype": "Link",
- "in_list_view": 1,
+ "in_list_view": 0,
"label": "Account Head",
"oldfieldname": "account_head",
"oldfieldtype": "Link",
@@ -54,7 +63,7 @@
"doctype": "DocField",
"fieldname": "cost_center",
"fieldtype": "Link",
- "in_list_view": 1,
+ "in_list_view": 0,
"label": "Cost Center",
"oldfieldname": "cost_center_other_charges",
"oldfieldtype": "Link",
@@ -73,6 +82,24 @@
"width": "300px"
},
{
+ "allow_on_submit": 0,
+ "description": "If checked, the tax amount will be considered as already included in the Print Rate / Print Amount",
+ "doctype": "DocField",
+ "fieldname": "included_in_print_rate",
+ "fieldtype": "Check",
+ "label": "Is this Tax included in Basic Rate?",
+ "no_copy": 0,
+ "print_hide": 1,
+ "print_width": "150px",
+ "report_hide": 1,
+ "width": "150px"
+ },
+ {
+ "doctype": "DocField",
+ "fieldname": "section_break_6",
+ "fieldtype": "Section Break"
+ },
+ {
"doctype": "DocField",
"fieldname": "rate",
"fieldtype": "Float",
@@ -80,7 +107,7 @@
"label": "Rate",
"oldfieldname": "rate",
"oldfieldtype": "Currency",
- "reqd": 0
+ "reqd": 1
},
{
"doctype": "DocField",
@@ -106,15 +133,6 @@
},
{
"doctype": "DocField",
- "fieldname": "row_id",
- "fieldtype": "Data",
- "hidden": 0,
- "label": "Enter Row",
- "oldfieldname": "row_id",
- "oldfieldtype": "Data"
- },
- {
- "doctype": "DocField",
"fieldname": "item_wise_tax_detail",
"fieldtype": "Small Text",
"hidden": 1,
@@ -134,18 +152,5 @@
"oldfieldtype": "Data",
"print_hide": 1,
"search_index": 1
- },
- {
- "allow_on_submit": 0,
- "description": "If checked, the tax amount will be considered as already included in the Print Rate / Print Amount",
- "doctype": "DocField",
- "fieldname": "included_in_print_rate",
- "fieldtype": "Check",
- "label": "Is this Tax included in Basic Rate?",
- "no_copy": 0,
- "print_hide": 1,
- "print_width": "150px",
- "report_hide": 1,
- "width": "150px"
}
]
\ No newline at end of file
diff --git a/erpnext/accounts/general_ledger.py b/erpnext/accounts/general_ledger.py
index b638e6c..5451642 100644
--- a/erpnext/accounts/general_ledger.py
+++ b/erpnext/accounts/general_ledger.py
@@ -24,10 +24,6 @@
gl_map = merge_similar_entries(gl_map)
for entry in gl_map:
- # round off upto 2 decimal
- entry.debit = flt(entry.debit, 2)
- entry.credit = flt(entry.credit, 2)
-
# toggle debit, credit if negative entry
if flt(entry.debit) < 0:
entry.credit = flt(entry.credit) - flt(entry.debit)
@@ -49,7 +45,7 @@
same_head.credit = flt(same_head.credit) + flt(entry.credit)
else:
merged_gl_map.append(entry)
-
+
# filter zero debit and credit entries
merged_gl_map = filter(lambda x: flt(x.debit)!=0 or flt(x.credit)!=0, merged_gl_map)
return merged_gl_map
diff --git a/erpnext/accounts/page/accounts_browser/accounts_browser.js b/erpnext/accounts/page/accounts_browser/accounts_browser.js
index 4623fdd..fe7f06c 100644
--- a/erpnext/accounts/page/accounts_browser/accounts_browser.js
+++ b/erpnext/accounts/page/accounts_browser/accounts_browser.js
@@ -175,9 +175,10 @@
wn.route_options = {
"account": node.data('label'),
"from_date": sys_defaults.year_start_date,
- "to_date": sys_defaults.year_end_date
+ "to_date": sys_defaults.year_end_date,
+ "company": me.company
};
- wn.set_route("general-ledger");
+ wn.set_route("query-report", "General Ledger");
},
rename: function() {
var node = this.selected_node();
diff --git a/erpnext/accounts/page/accounts_home/accounts_home.js b/erpnext/accounts/page/accounts_home/accounts_home.js
index 69c7da1..db7a20c 100644
--- a/erpnext/accounts/page/accounts_home/accounts_home.js
+++ b/erpnext/accounts/page/accounts_home/accounts_home.js
@@ -157,7 +157,8 @@
items: [
{
"label":wn._("General Ledger"),
- page: "general-ledger"
+ doctype: "GL Entry",
+ route: "query-report/General Ledger"
},
{
"label":wn._("Trial Balance"),
diff --git a/erpnext/accounts/page/general_ledger/README.md b/erpnext/accounts/page/general_ledger/README.md
deleted file mode 100644
index 8c51e91..0000000
--- a/erpnext/accounts/page/general_ledger/README.md
+++ /dev/null
@@ -1 +0,0 @@
-General Ledger report (for all transactions and accounts).
\ No newline at end of file
diff --git a/erpnext/accounts/page/general_ledger/__init__.py b/erpnext/accounts/page/general_ledger/__init__.py
deleted file mode 100644
index baffc48..0000000
--- a/erpnext/accounts/page/general_ledger/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-from __future__ import unicode_literals
diff --git a/erpnext/accounts/page/general_ledger/general_ledger.css b/erpnext/accounts/page/general_ledger/general_ledger.css
deleted file mode 100644
index e69de29..0000000
--- a/erpnext/accounts/page/general_ledger/general_ledger.css
+++ /dev/null
diff --git a/erpnext/accounts/page/general_ledger/general_ledger.html b/erpnext/accounts/page/general_ledger/general_ledger.html
deleted file mode 100644
index e69de29..0000000
--- a/erpnext/accounts/page/general_ledger/general_ledger.html
+++ /dev/null
diff --git a/erpnext/accounts/page/general_ledger/general_ledger.js b/erpnext/accounts/page/general_ledger/general_ledger.js
deleted file mode 100644
index 7eeab58..0000000
--- a/erpnext/accounts/page/general_ledger/general_ledger.js
+++ /dev/null
@@ -1,396 +0,0 @@
-// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
-// License: GNU General Public License v3. See license.txt
-
-wn.pages['general-ledger'].onload = function(wrapper) {
- wn.ui.make_app_page({
- parent: wrapper,
- title: wn._('General Ledger'),
- single_column: true
- });
-
- erpnext.general_ledger = new erpnext.GeneralLedger(wrapper);
- wrapper.appframe.add_module_icon("Accounts")
-
-}
-
-erpnext.GeneralLedger = wn.views.GridReport.extend({
- init: function(wrapper) {
- this._super({
- title: wn._("General Ledger"),
- page: wrapper,
- parent: $(wrapper).find('.layout-main'),
- appframe: wrapper.appframe,
- doctypes: ["Company", "Account", "GL Entry", "Cost Center"],
- });
- },
- setup_columns: function() {
- this.columns = [
- {id: "posting_date", name: wn._("Posting Date"), field: "posting_date", width: 100,
- formatter: this.date_formatter},
- {id: "account", name: wn._("Account"), field: "account", width: 240,
- link_formatter: {
- filter_input: "account",
- open_btn: true,
- doctype: "'Account'"
- }},
- {id: "against_account", name: wn._("Against Account"), field: "against_account",
- width: 240, hidden: !this.account},
-
- {id: "debit", name: wn._("Debit"), field: "debit", width: 100,
- formatter: this.currency_formatter},
- {id: "credit", name: wn._("Credit"), field: "credit", width: 100,
- formatter: this.currency_formatter},
- {id: "voucher_type", name: wn._("Voucher Type"), field: "voucher_type", width: 120},
- {id: "voucher_no", name: wn._("Voucher No"), field: "voucher_no", width: 160,
- link_formatter: {
- filter_input: "voucher_no",
- open_btn: true,
- doctype: "dataContext.voucher_type"
- }},
- {id: "remarks", name: wn._("Remarks"), field: "remarks", width: 200,
- formatter: this.text_formatter},
-
- ];
- },
-
- filters: [
- {fieldtype:"Select", label: wn._("Company"), link:"Company", default_value: wn._("Select Company..."),
- filter: function(val, item, opts) {
- return item.company == val || val == opts.default_value;
- }},
- {fieldtype:"Link", label: wn._("Account"), link:"Account",
- filter: function(val, item, opts, me) {
- if(!val) {
- return true;
- } else {
- // true if GL Entry belongs to selected
- // account ledger or group
- return me.is_child_account(val, item.account);
- }
- }},
- {fieldtype:"Data", label: wn._("Voucher No"),
- filter: function(val, item, opts) {
- if(!val) return true;
- return (item.voucher_no && item.voucher_no.indexOf(val)!=-1);
- }},
- {fieldtype:"Date", label: wn._("From Date"), filter: function(val, item) {
- return dateutil.str_to_obj(val) <= dateutil.str_to_obj(item.posting_date);
- }},
- {fieldtype:"Label", label: wn._("To")},
- {fieldtype:"Date", label: wn._("To Date"), filter: function(val, item) {
- return dateutil.str_to_obj(val) >= dateutil.str_to_obj(item.posting_date);
- }},
- {fieldtype: "Check", label: wn._("Group by Ledger")},
- {fieldtype: "Check", label: wn._("Group by Voucher")},
- {fieldtype:"Button", label: wn._("Refresh"), icon:"icon-refresh icon-white"},
- {fieldtype:"Button", label: wn._("Reset Filters")}
- ],
- setup_filters: function() {
- this._super();
- var me = this;
-
- this.accounts_by_company = this.make_accounts_by_company();
-
- // filter accounts options by company
- this.filter_inputs.company.on("change", function() {
- me.setup_account_filter(this);
- me.refresh();
- });
-
- this.trigger_refresh_on_change(["group_by_ledger", "group_by_voucher"]);
- },
- setup_account_filter: function(company_filter) {
- var me = this;
-
- var $account = me.filter_inputs.account;
- var company = $(company_filter).val();
- var default_company = this.filter_inputs.company.get(0).opts.default_value;
- var opts = $account.get(0).opts;
- opts.list = $.map(wn.report_dump.data["Account"], function(ac) {
- return (company===default_company ||
- me.accounts_by_company[company].indexOf(ac.name)!=-1) ?
- ac.name : null;
- });
-
- this.set_autocomplete($account, opts.list);
-
- },
- init_filter_values: function() {
- this._super();
- this.toggle_group_by_checks();
- this.filter_inputs.company.trigger("change");
- },
- apply_filters_from_route: function() {
- this._super();
- this.toggle_group_by_checks();
- },
- make_accounts_by_company: function() {
- var accounts_by_company = {};
- var me = this;
- $.each(wn.report_dump.data["Account"], function(i, ac) {
- if(!accounts_by_company[ac.company]) accounts_by_company[ac.company] = [];
- accounts_by_company[ac.company].push(ac.name);
- });
- return accounts_by_company;
- },
- is_child_account: function(account, item_account) {
- account = this.account_by_name[account];
- item_account = this.account_by_name[item_account];
- return ((item_account.lft >= account.lft) && (item_account.rgt <= account.rgt));
- },
- toggle_group_by_checks: function() {
- this.make_account_by_name();
-
- // this.filter_inputs.group_by_ledger
- // .parent().toggle(!!(this.account_by_name[this.account]
- // && this.account_by_name[this.account].group_or_ledger==="Group"));
- //
- // this.filter_inputs.group_by_voucher
- // .parent().toggle(!!(this.account_by_name[this.account]
- // && this.account_by_name[this.account].group_or_ledger==="Ledger"));
- },
- prepare_data: function() {
- var me = this;
- var data = wn.report_dump.data["GL Entry"];
- var out = [];
-
- this.toggle_group_by_checks();
-
- var from_date = dateutil.str_to_obj(this.from_date);
- var to_date = dateutil.str_to_obj(this.to_date);
-
- if(to_date < from_date) {
- msgprint(wn._("From Date must be before To Date"));
- return;
- }
-
- // add Opening, Closing, Totals rows
- // if filtered by account and / or voucher
- var opening = this.make_summary_row("Opening", this.account);
- var totals = this.make_summary_row("Totals", this.account);
-
- var grouped_ledgers = {};
- $.each(data, function(i, item) {
- if(me.apply_filter(item, "company") &&
- (me.account ? me.is_child_account(me.account, item.account)
- : true) && (me.voucher_no ? item.voucher_no==me.voucher_no : true)) {
- var date = dateutil.str_to_obj(item.posting_date);
-
- // create grouping by ledger
- if(!grouped_ledgers[item.account]) {
- grouped_ledgers[item.account] = {
- entries: [],
- entries_group_by_voucher: {},
- opening: me.make_summary_row("Opening", item.account),
- totals: me.make_summary_row("Totals", item.account),
- closing: me.make_summary_row("Closing (Opening + Totals)",
- item.account)
- };
- }
-
- if(!grouped_ledgers[item.account].entries_group_by_voucher[item.voucher_no]) {
- grouped_ledgers[item.account].entries_group_by_voucher[item.voucher_no] = {
- row: {},
- totals: {"debit": 0, "credit": 0}
- }
- }
-
- if(!me.voucher_no && (date < from_date || item.is_opening=="Yes")) {
- opening.debit += item.debit;
- opening.credit += item.credit;
-
- grouped_ledgers[item.account].opening.debit += item.debit;
- grouped_ledgers[item.account].opening.credit += item.credit;
-
- } else if(date <= to_date) {
-
- totals.debit += item.debit;
- totals.credit += item.credit;
-
- grouped_ledgers[item.account].totals.debit += item.debit;
- grouped_ledgers[item.account].totals.credit += item.credit;
- grouped_ledgers[item.account].entries_group_by_voucher[item.voucher_no]
- .totals.debit += item.debit;
- grouped_ledgers[item.account].entries_group_by_voucher[item.voucher_no]
- .totals.credit += item.credit;
- }
- if(item.account) {
- item.against_account = me.voucher_accounts[item.voucher_type + ":"
- + item.voucher_no][(item.debit > 0 ? "credits" : "debits")].join(", ");
- }
-
- if(me.apply_filters(item) && (me.voucher_no || item.is_opening=="No")) {
- out.push(item);
- grouped_ledgers[item.account].entries.push(item);
-
- if(grouped_ledgers[item.account].entries_group_by_voucher[item.voucher_no].row){
- grouped_ledgers[item.account].entries_group_by_voucher[item.voucher_no]
- .row = $.extend({}, item);
- }
- }
- }
- });
-
- var closing = this.make_summary_row("Closing (Opening + Totals)", this.account);
- closing.debit = opening.debit + totals.debit;
- closing.credit = opening.credit + totals.credit;
-
- if(me.account) {
- me.appframe.set_title(wn._("General Ledger: ") + me.account);
-
- // group by ledgers
- if(this.account_by_name[this.account].group_or_ledger==="Group"
- && this.group_by_ledger) {
- out = this.group_data_by_ledger(grouped_ledgers);
- }
-
- if(this.account_by_name[this.account].group_or_ledger==="Ledger"
- && this.group_by_voucher) {
- out = this.group_data_by_voucher(grouped_ledgers);
- }
-
- opening = me.get_balance(me.account_by_name[me.account].debit_or_credit, opening)
- closing = me.get_balance(me.account_by_name[me.account].debit_or_credit, closing)
-
- out = [opening].concat(out).concat([totals, closing]);
- } else {
- me.appframe.set_title(wn._("General Ledger"));
- out = out.concat([totals]);
- }
-
- this.data = out;
- },
-
- group_data_by_ledger: function(grouped_ledgers) {
- var me = this;
- var out = []
- $.each(Object.keys(grouped_ledgers).sort(), function(i, account) {
- if(grouped_ledgers[account].entries.length) {
- grouped_ledgers[account].closing.debit =
- grouped_ledgers[account].opening.debit
- + grouped_ledgers[account].totals.debit;
-
- grouped_ledgers[account].closing.credit =
- grouped_ledgers[account].opening.credit
- + grouped_ledgers[account].totals.credit;
-
- grouped_ledgers[account].opening =
- me.get_balance(me.account_by_name[me.account].debit_or_credit,
- grouped_ledgers[account].opening)
- grouped_ledgers[account].closing =
- me.get_balance(me.account_by_name[me.account].debit_or_credit,
- grouped_ledgers[account].closing)
-
- out = out.concat([grouped_ledgers[account].opening])
- .concat(grouped_ledgers[account].entries)
- .concat([grouped_ledgers[account].totals,
- grouped_ledgers[account].closing,
- {id: "_blank" + i, debit: "", credit: ""}]);
- }
- });
- return [{id: "_blank_first", debit: "", credit: ""}].concat(out);
- },
-
- group_data_by_voucher: function(grouped_ledgers) {
- var me = this;
- var out = []
- $.each(Object.keys(grouped_ledgers).sort(), function(i, account) {
- if(grouped_ledgers[account].entries.length) {
- $.each(Object.keys(grouped_ledgers[account].entries_group_by_voucher),
- function(j, voucher) {
- voucher_dict = grouped_ledgers[account].entries_group_by_voucher[voucher];
- if(voucher_dict &&
- (voucher_dict.totals.debit || voucher_dict.totals.credit)) {
- voucher_dict.row.debit = voucher_dict.totals.debit;
- voucher_dict.row.credit = voucher_dict.totals.credit;
- voucher_dict.row.id = "entry_grouped_by_" + voucher
- out = out.concat(voucher_dict.row);
- }
- });
- }
- });
- return out;
- },
-
- get_balance: function(debit_or_credit, balance) {
- if(debit_or_credit == "Debit") {
- balance.debit -= balance.credit; balance.credit = 0;
- } else {
- balance.credit -= balance.debit; balance.debit = 0;
- }
- return balance
- },
-
- make_summary_row: function(label, item_account) {
- return {
- account: label,
- debit: 0.0,
- credit: 0.0,
- id: ["", label, item_account].join("_").replace(" ", "_").toLowerCase(),
- _show: true,
- _style: "font-weight: bold"
- }
- },
-
- make_account_by_name: function() {
- this.account_by_name = this.make_name_map(wn.report_dump.data["Account"]);
- this.make_voucher_accounts_map();
- },
-
- make_voucher_accounts_map: function() {
- this.voucher_accounts = {};
- var data = wn.report_dump.data["GL Entry"];
- for(var i=0, j=data.length; i<j; i++) {
- var gl = data[i];
-
- if(!this.voucher_accounts[gl.voucher_type + ":" + gl.voucher_no])
- this.voucher_accounts[gl.voucher_type + ":" + gl.voucher_no] = {
- debits: [],
- credits: []
- }
-
- var va = this.voucher_accounts[gl.voucher_type + ":" + gl.voucher_no];
- if(gl.debit > 0) {
- va.debits.push(gl.account);
- } else {
- va.credits.push(gl.account);
- }
- }
- },
-
- get_plot_data: function() {
- var data = [];
- var me = this;
- if(!me.account || me.voucher_no) return false;
- var debit_or_credit = me.account_by_name[me.account].debit_or_credit;
- var balance = debit_or_credit=="Debit" ? me.data[0].debit : me.data[0].credit;
- data.push({
- label: me.account,
- data: [[dateutil.str_to_obj(me.from_date).getTime(), balance]]
- .concat($.map(me.data, function(col, idx) {
- if (col.posting_date) {
- var diff = (debit_or_credit == "Debit" ? 1 : -1) * (flt(col.debit) - flt(col.credit));
- balance += diff;
- return [[dateutil.str_to_obj(col.posting_date).getTime(), balance - diff],
- [dateutil.str_to_obj(col.posting_date).getTime(), balance]]
- }
- return null;
- })).concat([
- // closing
- [dateutil.str_to_obj(me.to_date).getTime(), balance]
- ]),
- points: {show: true},
- lines: {show: true, fill: true},
- });
- return data;
- },
- get_plot_options: function() {
- return {
- grid: { hoverable: true, clickable: true },
- xaxis: { mode: "time",
- min: dateutil.str_to_obj(this.from_date).getTime(),
- max: dateutil.str_to_obj(this.to_date).getTime() },
- series: { downsample: { threshold: 1000 } }
- }
- },
-});
\ No newline at end of file
diff --git a/erpnext/accounts/page/general_ledger/general_ledger.txt b/erpnext/accounts/page/general_ledger/general_ledger.txt
deleted file mode 100644
index 2cc8a60..0000000
--- a/erpnext/accounts/page/general_ledger/general_ledger.txt
+++ /dev/null
@@ -1,41 +0,0 @@
-[
- {
- "creation": "2012-09-14 11:25:48",
- "docstatus": 0,
- "modified": "2013-07-11 14:42:21",
- "modified_by": "Administrator",
- "owner": "Administrator"
- },
- {
- "doctype": "Page",
- "icon": "icon-table",
- "module": "Accounts",
- "name": "__common__",
- "page_name": "general-ledger",
- "standard": "Yes",
- "title": "General Ledger"
- },
- {
- "doctype": "Page Role",
- "name": "__common__",
- "parent": "general-ledger",
- "parentfield": "roles",
- "parenttype": "Page"
- },
- {
- "doctype": "Page",
- "name": "general-ledger"
- },
- {
- "doctype": "Page Role",
- "role": "Analytics"
- },
- {
- "doctype": "Page Role",
- "role": "Accounts Manager"
- },
- {
- "doctype": "Page Role",
- "role": "Accounts User"
- }
-]
\ No newline at end of file
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
index ad0d925..945bae4 100644
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
@@ -85,7 +85,7 @@
def get_account_map(self):
if not hasattr(self, "account_map"):
self.account_map = dict(((r.name, r) for r in webnotes.conn.sql("""select
- account.name, customer.customer_name, customer.territory
+ account.name, customer.name as customer_name, customer.territory
from `tabAccount` account, `tabCustomer` customer
where account.master_type="Customer"
and customer.name=account.master_name""", as_dict=True)))
diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py
index 2b7c06f..6d74abd 100644
--- a/erpnext/accounts/utils.py
+++ b/erpnext/accounts/utils.py
@@ -16,7 +16,7 @@
def get_fiscal_year(date=None, fiscal_year=None, label="Date", verbose=1):
- return get_fiscal_years(date, fiscal_year, label, verbose=1)[0]
+ return get_fiscal_years(date, fiscal_year, label, verbose)[0]
def get_fiscal_years(date=None, fiscal_year=None, label="Date", verbose=1):
# if year start date is 2012-04-01, year end date should be 2013-03-31 (hence subdate)
diff --git a/erpnext/buying/doctype/purchase_common/purchase_common.py b/erpnext/buying/doctype/purchase_common/purchase_common.py
index b2e59b0..d967b24 100644
--- a/erpnext/buying/doctype/purchase_common/purchase_common.py
+++ b/erpnext/buying/doctype/purchase_common/purchase_common.py
@@ -9,9 +9,8 @@
from webnotes import msgprint, _
from erpnext.buying.utils import get_last_purchase_details
-
-
from erpnext.controllers.buying_controller import BuyingController
+
class DocType(BuyingController):
def __init__(self, doc, doclist=None):
self.doc = doc
@@ -38,13 +37,13 @@
if flt(d.conversion_factor):
last_purchase_rate = flt(d.purchase_rate) / flt(d.conversion_factor)
else:
- msgprint(_("Row ") + cstr(d.idx) + ": " +
- _("UOM Conversion Factor is mandatory"), raise_exception=1)
+ webnotes.throw(_("Row ") + cstr(d.idx) + ": " +
+ _("UOM Conversion Factor is mandatory"))
# update last purchsae rate
if last_purchase_rate:
- webnotes.conn.sql("update `tabItem` set last_purchase_rate = %s where name = %s",
- (flt(last_purchase_rate),d.item_code))
+ 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):
"""get last purchase rates for all items"""
@@ -76,11 +75,11 @@
for d in getlist( obj.doclist, obj.fname):
# validation for valid qty
if flt(d.qty) < 0 or (d.parenttype != 'Purchase Receipt' and not flt(d.qty)):
- msgprint("Please enter valid qty for item %s" % cstr(d.item_code))
- raise Exception
+ webnotes.throw("Please enter valid qty for item %s" % cstr(d.item_code))
# udpate with latest quantities
- bin = webnotes.conn.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':
@@ -89,48 +88,50 @@
if d.fields.has_key(x):
d.fields[x] = f_lst[x]
- 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)
+ 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)
+ webnotes.throw("Item %s does not exist in Item Master." % cstr(d.item_code))
from erpnext.stock.utils import validate_end_of_life
validate_end_of_life(d.item_code, item[0][3])
# validate stock item
if item[0][0]=='Yes' and d.qty and not d.warehouse:
- msgprint("Warehouse is mandatory for %s, since it is a stock item" %
- d.item_code, raise_exception=1)
+ webnotes.throw("Warehouse is mandatory for %s, since it is a stock item" % d.item_code)
# validate purchase item
if item[0][1] != 'Yes' and item[0][2] != 'Yes':
- msgprint("Item %s is not a purchase item or sub-contracted item. Please check" % (d.item_code), raise_exception=True)
+ webnotes.throw("Item %s is not a purchase item or sub-contracted item. Please check" % (d.item_code))
# list criteria that should not repeat if item is stock item
- e = [d.schedule_date, d.item_code, d.description, d.warehouse, d.uom, d.fields.has_key('prevdoc_docname') and d.prevdoc_docname or '', d.fields.has_key('prevdoc_detail_docname') and d.prevdoc_detail_docname or '', d.fields.has_key('batch_no') and d.batch_no or '']
+ e = [d.schedule_date, d.item_code, d.description, d.warehouse, d.uom,
+ d.fields.has_key('prevdoc_docname') and d.prevdoc_docname or d.fields.has_key('sales_order_no') and d.sales_order_no or '',
+ d.fields.has_key('prevdoc_detail_docname') and d.prevdoc_detail_docname or '',
+ d.fields.has_key('batch_no') and d.batch_no or '']
# if is not stock item
f = [d.schedule_date, d.item_code, d.description]
- ch = webnotes.conn.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
if e in check_list:
- msgprint("""Item %s has been entered more than once with same description, schedule date, warehouse and uom.\n
- Please change any of the field value to enter the item twice""" % d.item_code, raise_exception = 1)
+ webnotes.throw("""Item %s has been entered more than once with same description, schedule date, warehouse and uom.\n
+ Please change any of the field value to enter the item twice""" % d.item_code)
else:
check_list.append(e)
elif ch and ch[0][0] == 'No':
# check for same items
if f in chk_dupl_itm:
- msgprint("""Item %s has been entered more than once with same description, schedule date.\n
- Please change any of the field value to enter the item twice.""" % d.item_code, raise_exception = 1)
+ webnotes.throw("""Item %s has been entered more than once with same description, schedule date.\n
+ Please change any of the field value to enter the item twice.""" % d.item_code)
else:
chk_dupl_itm.append(f)
- def get_qty(self,curr_doctype,ref_tab_fname,ref_tab_dn,ref_doc_tname, transaction, curr_parent_name):
+ def get_qty(self, curr_doctype, ref_tab_fname, ref_tab_dn, ref_doc_tname, transaction, curr_parent_name):
# Get total Quantities of current doctype (eg. PR) except for qty of this transaction
#------------------------------
# please check as UOM changes from Material Request - Purchase Order ,so doing following else uom should be same .
@@ -138,35 +139,37 @@
# 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 = 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 = 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, '%s', '%s'),
+ (ref_tab_dn, curr_parent_name))
qty = qty and flt(qty[0][0]) or 0
# get total qty of ref doctype
#--------------------
- max_qty = webnotes.conn.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, '%s'), 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 = webnotes.conn.sql("select name from `tab%s` where name = '%s' and status = 'Stopped'" %
- ( doctype, docname))
+ stopped = webnotes.conn.sql("""select name from `tab%s` where name = %s and
+ status = 'Stopped'""" % (doctype, '%s'), docname)
if stopped:
- msgprint("One cannot do any transaction against %s : %s, it's status is 'Stopped'" %
- ( doctype, docname), raise_exception=1)
+ webnotes.throw("One cannot do any transaction against %s : %s, it's status is 'Stopped'" %
+ (doctype, docname))
- def check_docstatus(self, check, doctype, docname , detail_doctype = ''):
+ def check_docstatus(self, check, doctype, docname, detail_doctype = ''):
if check == 'Next':
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:
- msgprint(cstr(doctype) + ": " + cstr(submitted[0][0])
- + _(" has already been submitted."), raise_exception=1)
+ webnotes.throw(cstr(doctype) + ": " + cstr(submitted[0][0])
+ + _("has already been submitted."))
if check == 'Previous':
submitted = webnotes.conn.sql("""select name from `tab%s`
- where docstatus = 1 and name = %s"""% (doctype, '%s'), docname)
+ where docstatus = 1 and name = %s""" % (doctype, '%s'), docname)
if not submitted:
- msgprint(cstr(doctype) + ": " + cstr(submitted[0][0])
- + _(" not submitted"), raise_exception=1)
+ webnotes.throw(cstr(doctype) + ": " + cstr(submitted[0][0]) + _("not submitted"))
diff --git a/erpnext/buying/doctype/supplier/supplier.py b/erpnext/buying/doctype/supplier/supplier.py
index ace1d12..00eaf90 100644
--- a/erpnext/buying/doctype/supplier/supplier.py
+++ b/erpnext/buying/doctype/supplier/supplier.py
@@ -27,6 +27,14 @@
else:
self.doc.name = make_autoname(self.doc.naming_series + '.#####')
+ def update_address(self):
+ webnotes.conn.sql("""update `tabAddress` set supplier_name=%s, modified=NOW()
+ where supplier=%s""", (self.doc.supplier_name, self.doc.name))
+
+ def update_contact(self):
+ webnotes.conn.sql("""update `tabContact` set supplier_name=%s, modified=NOW()
+ where supplier=%s""", (self.doc.supplier_name, self.doc.name))
+
def update_credit_days_limit(self):
webnotes.conn.sql("""update tabAccount set credit_days = %s where name = %s""",
(cint(self.doc.credit_days), self.doc.name + " - " + self.get_company_abbr()))
@@ -35,6 +43,9 @@
if not self.doc.naming_series:
self.doc.naming_series = ''
+ self.update_address()
+ self.update_contact()
+
# create account head
self.create_account_head()
@@ -151,10 +162,19 @@
def before_rename(self, olddn, newdn, merge=False):
from erpnext.accounts.utils import rename_account_for
rename_account_for("Supplier", olddn, newdn, merge)
-
+
def after_rename(self, olddn, newdn, merge=False):
+ set_field = ''
if webnotes.defaults.get_global_default('supp_master_name') == 'Supplier Name':
webnotes.conn.set(self.doc, "supplier_name", newdn)
+ self.update_contact()
+ set_field = ", supplier_name=%(newdn)s"
+ self.update_supplier_address(newdn, set_field)
+
+ def update_supplier_address(self, newdn, set_field):
+ webnotes.conn.sql("""update `tabAddress` set address_title=%(newdn)s
+ {set_field} where supplier=%(newdn)s"""\
+ .format(set_field=set_field), ({"newdn": newdn}))
@webnotes.whitelist()
def get_dashboard_info(supplier):
diff --git a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.txt b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.txt
index cf62a9f..e532aa6 100644
--- a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.txt
+++ b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.txt
@@ -2,7 +2,7 @@
{
"creation": "2013-05-21 16:16:45",
"docstatus": 0,
- "modified": "2013-11-22 17:16:16",
+ "modified": "2013-12-14 17:27:47",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -632,6 +632,7 @@
"cancel": 0,
"create": 0,
"doctype": "DocPerm",
+ "match": "supplier",
"role": "Supplier",
"submit": 0,
"write": 0
diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py
index b1d32bd..6382e0d 100644
--- a/erpnext/controllers/buying_controller.py
+++ b/erpnext/controllers/buying_controller.py
@@ -107,10 +107,11 @@
item.import_amount = flt(item.import_rate * item.qty,
self.precision("import_amount", item))
item.item_tax_amount = 0.0;
-
+
+ self._set_in_company_currency(item, "import_amount", "amount")
self._set_in_company_currency(item, "import_ref_rate", "purchase_ref_rate")
self._set_in_company_currency(item, "import_rate", "rate")
- self._set_in_company_currency(item, "import_amount", "amount")
+
def calculate_net_total(self):
self.doc.net_total = self.doc.net_total_import = 0.0
@@ -182,14 +183,12 @@
if item.item_code and item.qty:
self.round_floats_in(item)
-
- purchase_rate = item.rate if self.doc.doctype == "Purchase Invoice" else item.purchase_rate
-
+
# if no item code, which is sometimes the case in purchase invoice,
# then it is not possible to track valuation against it
- item.valuation_rate = flt((purchase_rate +
- (item.item_tax_amount + item.rm_supp_cost) / item.qty) / item.conversion_factor,
- self.precision("valuation_rate", item))
+ qty_in_stock_uom = flt(item.qty * item.conversion_factor)
+ item.valuation_rate = ((item.amount + item.item_tax_amount + item.rm_supp_cost)
+ / qty_in_stock_uom)
else:
item.valuation_rate = 0.0
diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py
index 61db756..f950f28 100644
--- a/erpnext/controllers/selling_controller.py
+++ b/erpnext/controllers/selling_controller.py
@@ -205,8 +205,8 @@
self.round_floats_in(self.doc, ["grand_total", "total_advance", "write_off_amount",
"paid_amount"])
total_amount_to_pay = self.doc.grand_total - self.doc.write_off_amount
- self.doc.outstanding_amount = flt(total_amount_to_pay - self.doc.total_advance - self.doc.paid_amount,
- self.precision("outstanding_amount"))
+ self.doc.outstanding_amount = flt(total_amount_to_pay - self.doc.total_advance \
+ - self.doc.paid_amount, self.precision("outstanding_amount"))
def calculate_commission(self):
if self.meta.get_field("commission_rate"):
diff --git a/erpnext/hooks.txt b/erpnext/hooks.txt
index 40bac96..af11df9 100644
--- a/erpnext/hooks.txt
+++ b/erpnext/hooks.txt
@@ -52,13 +52,12 @@
#### Daily
scheduler_event daily:webnotes.core.doctype.event.event.send_event_digest
-scheduler_event daily:erpnext.setup.doctype.email_digest.email_digest.send
scheduler_event daily:webnotes.core.doctype.notification_count.notification_count.delete_event_notification_count
scheduler_event daily:webnotes.utils.email_lib.bulk.clear_outbox
scheduler_event daily:erpnext.accounts.doctype.sales_invoice.sales_invoice.manage_recurring_invoices
scheduler_event daily:erpnext.setup.doctype.backup_manager.backup_manager.take_backups_daily
scheduler_event daily:erpnext.stock.utils.reorder_item
-scheduler_event daily:webnotes.scheduler.report_errors
+scheduler_event daily:erpnext.setup.doctype.email_digest.email_digest.send
#### Weekly
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.txt b/erpnext/hr/doctype/leave_allocation/leave_allocation.txt
index a24823a..38e3eb5 100644
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.txt
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.txt
@@ -2,7 +2,7 @@
{
"creation": "2013-02-20 19:10:38",
"docstatus": 0,
- "modified": "2013-07-05 14:44:19",
+ "modified": "2013-12-12 17:41:52",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -131,10 +131,12 @@
"label": "Carry Forward"
},
{
+ "depends_on": "carry_forward",
"doctype": "DocField",
"fieldname": "carry_forwarded_leaves",
"fieldtype": "Float",
- "label": "Carry Forwarded Leaves"
+ "label": "Carry Forwarded Leaves",
+ "read_only": 1
},
{
"allow_on_submit": 1,
diff --git a/erpnext/hr/doctype/salary_manager/salary_manager.py b/erpnext/hr/doctype/salary_manager/salary_manager.py
index 29b13ae..37a8c5d 100644
--- a/erpnext/hr/doctype/salary_manager/salary_manager.py
+++ b/erpnext/hr/doctype/salary_manager/salary_manager.py
@@ -12,7 +12,6 @@
self.doc = doc
self.doclist = doclist
-
def get_emp_list(self):
"""
Returns list of active employees based on selected criteria
diff --git a/erpnext/hr/doctype/salary_slip/salary_slip.py b/erpnext/hr/doctype/salary_slip/salary_slip.py
index 946106d..f799592 100644
--- a/erpnext/hr/doctype/salary_slip/salary_slip.py
+++ b/erpnext/hr/doctype/salary_slip/salary_slip.py
@@ -29,18 +29,17 @@
if struct:
self.pull_sal_struct(struct)
-
def check_sal_struct(self):
- struct = webnotes.conn.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 = ''
+ msgprint("Please create Salary Structure for employee '%s'" % self.doc.employee)
+ self.doc.employee = None
return struct and struct[0][0] or ''
-
def pull_sal_struct(self, struct):
- from erpnext.hr.doctype.salary_structure.salary_structure import make_salary_slip
- self.doclist = make_salary_slip(struct, self.doclist)
+ from erpnext.hr.doctype.salary_structure.salary_structure import get_mapped_doclist
+ self.doclist = get_mapped_doclist(struct, self.doclist)
def pull_emp_details(self):
emp = webnotes.conn.get_value("Employee", self.doc.employee,
diff --git a/erpnext/hr/doctype/salary_structure/salary_structure.py b/erpnext/hr/doctype/salary_structure/salary_structure.py
index de088e7..67771e6 100644
--- a/erpnext/hr/doctype/salary_structure/salary_structure.py
+++ b/erpnext/hr/doctype/salary_structure/salary_structure.py
@@ -73,6 +73,9 @@
@webnotes.whitelist()
def make_salary_slip(source_name, target_doclist=None):
+ return [d.fields for d in get_mapped_doclist(source_name, target_doclist)]
+
+def get_mapped_doclist(source_name, target_doclist=None):
from webnotes.model.mapper import get_mapped_doclist
def postprocess(source, target):
@@ -108,4 +111,4 @@
}
}, target_doclist, postprocess)
- return [d.fields for d in doclist]
\ No newline at end of file
+ return doclist
diff --git a/erpnext/manufacturing/doctype/production_order/production_order.js b/erpnext/manufacturing/doctype/production_order/production_order.js
index 1ace97b..480f1a6 100644
--- a/erpnext/manufacturing/doctype/production_order/production_order.js
+++ b/erpnext/manufacturing/doctype/production_order/production_order.js
@@ -1,28 +1,56 @@
// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
-cur_frm.cscript.onload = function(doc, dt, dn) {
- if (!doc.status) doc.status = 'Draft';
- cfn_set_fields(doc, dt, dn);
-}
+$.extend(cur_frm.cscript, {
+ onload: function (doc, dt, dn) {
-cur_frm.cscript.refresh = function(doc, dt, dn) {
- cur_frm.dashboard.reset();
- erpnext.hide_naming_series();
- cur_frm.set_intro("");
- cfn_set_fields(doc, dt, dn);
+ if (!doc.status) doc.status = 'Draft';
+ cfn_set_fields(doc, dt, dn);
- if(doc.docstatus===0 && !doc.__islocal) {
- cur_frm.set_intro(wn._("Submit this Production Order for further processing."));
- } else if(doc.docstatus===1) {
- var percent = flt(doc.produced_qty) / flt(doc.qty) * 100;
- cur_frm.dashboard.add_progress(cint(percent) + "% " + wn._("Complete"), percent);
+ this.frm.add_fetch("sales_order", "delivery_date", "expected_delivery_date");
+ },
- if(doc.status === "Stopped") {
- cur_frm.dashboard.set_headline_alert(wn._("Stopped"), "alert-danger", "icon-stop");
+ refresh: function(doc, dt, dn) {
+ this.frm.dashboard.reset();
+ erpnext.hide_naming_series();
+ this.frm.set_intro("");
+ cfn_set_fields(doc, dt, dn);
+
+ if (doc.docstatus === 0 && !doc.__islocal) {
+ this.frm.set_intro(wn._("Submit this Production Order for further processing."));
+ } else if (doc.docstatus === 1) {
+ var percent = flt(doc.produced_qty) / flt(doc.qty) * 100;
+ this.frm.dashboard.add_progress(cint(percent) + "% " + wn._("Complete"), percent);
+
+ if(doc.status === "Stopped") {
+ this.frm.dashboard.set_headline_alert(wn._("Stopped"), "alert-danger", "icon-stop");
+ }
}
+ },
+
+ production_item: function(doc) {
+ return this.frm.call({
+ method: "get_item_details",
+ args: { item: doc.production_item }
+ });
+ },
+
+ make_se: function(purpose) {
+ var me = this;
+
+ wn.call({
+ method:"erpnext.manufacturing.doctype.production_order.production_order.make_stock_entry",
+ args: {
+ "production_order_id": me.frm.doc.name,
+ "purpose": purpose
+ },
+ callback: function(r) {
+ var doclist = wn.model.sync(r.message);
+ wn.set_route("Form", doclist[0].doctype, doclist[0].name);
+ }
+ });
}
-}
+});
var cfn_set_fields = function(doc, dt, dn) {
if (doc.docstatus == 1) {
@@ -38,13 +66,6 @@
}
}
-cur_frm.cscript.production_item = function(doc) {
- return cur_frm.call({
- method: "get_item_details",
- args: { item: doc.production_item }
- });
-}
-
cur_frm.cscript['Stop Production Order'] = function() {
var doc = cur_frm.doc;
var check = confirm(wn._("Do you really want to stop production order: " + doc.name));
@@ -57,7 +78,7 @@
var doc = cur_frm.doc;
var check = confirm(wn._("Do really want to unstop production order: " + doc.name));
if (check)
- return $c_obj(make_doclist(doc.doctype, doc.name), 'stop_unstop', 'Unstopped', function(r, rt) {cur_frm.refresh();});
+ return $c_obj(make_doclist(doc.doctype, doc.name), 'stop_unstop', 'Unstopped', function(r, rt) {cur_frm.refresh();});
}
cur_frm.cscript['Transfer Raw Materials'] = function() {
@@ -68,20 +89,6 @@
cur_frm.cscript.make_se('Manufacture/Repack');
}
-cur_frm.cscript.make_se = function(purpose) {
- wn.call({
- method: "erpnext.manufacturing.doctype.production_order.production_order.make_stock_entry",
- args: {
- "production_order_id": cur_frm.doc.name,
- "purpose": purpose
- },
- callback: function(r) {
- var doclist = wn.model.sync(r.message);
- wn.set_route("Form", doclist[0].doctype, doclist[0].name);
- }
- })
-}
-
cur_frm.fields_dict['production_item'].get_query = function(doc) {
return {
filters:[
@@ -98,7 +105,6 @@
}
}
-
cur_frm.set_query("bom_no", function(doc) {
if (doc.production_item) {
return{
diff --git a/erpnext/manufacturing/doctype/production_order/production_order.py b/erpnext/manufacturing/doctype/production_order/production_order.py
index a6e219a..8d0223e 100644
--- a/erpnext/manufacturing/doctype/production_order/production_order.py
+++ b/erpnext/manufacturing/doctype/production_order/production_order.py
@@ -8,7 +8,6 @@
from webnotes.model.code import get_obj
from webnotes import msgprint, _
-
class OverProductionError(webnotes.ValidationError): pass
class DocType:
@@ -37,15 +36,20 @@
and is_active=1 and item=%s"""
, (self.doc.bom_no, self.doc.production_item), as_dict =1)
if not bom:
- msgprint("""Incorrect BOM: %s entered.
+ webnotes.throw("""Incorrect BOM: %s entered.
May be BOM not exists or inactive or not submitted
- or for some other item.""" % cstr(self.doc.bom_no), raise_exception=1)
+ or for some other item.""" % cstr(self.doc.bom_no))
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)
+ so = webnotes.conn.sql("""select name, delivery_date from `tabSales Order`
+ where name=%s and docstatus = 1""", self.doc.sales_order, as_dict=1)[0]
+
+ if not so.name:
+ webnotes.throw("Sales Order: %s is not valid" % self.doc.sales_order)
+
+ if not self.doc.expected_delivery_date:
+ self.doc.expected_delivery_date = so.delivery_date
self.validate_production_order_against_so()
@@ -76,11 +80,11 @@
so_qty = flt(so_item_qty) + flt(dnpi_qty)
if total_qty > so_qty:
- webnotes.msgprint(_("Total production order qty for item") + ": " +
+ webnotes.throw(_("Total production order qty for item") + ": " +
cstr(self.doc.production_item) + _(" against sales order") + ": " +
cstr(self.doc.sales_order) + _(" will be ") + cstr(total_qty) + ", " +
_("which is greater than sales order qty ") + "(" + cstr(so_qty) + ")" +
- _("Please reduce qty."), raise_exception=OverProductionError)
+ _("Please reduce qty."), exc=OverProductionError)
def stop_unstop(self, status):
""" Called from client side on Stop/Unstop event"""
@@ -114,8 +118,8 @@
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.
- Hence can not be cancelled.""" % stock_entry[0][0], raise_exception=1)
+ webnotes.throw("""Submitted Stock Entry %s exists against this production order.
+ Hence can not be cancelled.""" % stock_entry[0][0])
webnotes.conn.set(self.doc,'status', 'Cancelled')
self.update_planned_qty(-self.doc.qty)
diff --git a/erpnext/manufacturing/doctype/production_order/production_order.txt b/erpnext/manufacturing/doctype/production_order/production_order.txt
index 85c7c83..5e76c0e 100644
--- a/erpnext/manufacturing/doctype/production_order/production_order.txt
+++ b/erpnext/manufacturing/doctype/production_order/production_order.txt
@@ -2,7 +2,7 @@
{
"creation": "2013-01-10 16:34:16",
"docstatus": 0,
- "modified": "2013-11-02 14:05:44",
+ "modified": "2013-12-18 13:22:14",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -137,6 +137,14 @@
"read_only": 1
},
{
+ "depends_on": "sales_order",
+ "doctype": "DocField",
+ "fieldname": "expected_delivery_date",
+ "fieldtype": "Date",
+ "label": "Expected Delivery Date",
+ "read_only": 1
+ },
+ {
"doctype": "DocField",
"fieldname": "warehouses",
"fieldtype": "Section Break",
diff --git a/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.py b/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.py
index cb611ba..3b529cb 100644
--- a/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.py
+++ b/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.py
@@ -9,7 +9,6 @@
from webnotes.model.code import get_obj
from webnotes import msgprint, _
-
class DocType:
def __init__(self, doc, doclist=[]):
self.doc = doc
@@ -47,7 +46,7 @@
def validate_company(self):
if not self.doc.company:
- msgprint("Please enter Company", raise_exception=1)
+ webnotes.throw(_("Please enter Company"))
def get_open_sales_orders(self):
""" Pull sales orders which are pending to deliver based on criteria selected"""
@@ -72,9 +71,9 @@
and (exists (select name from `tabItem` item where item.name=so_item.item_code
and (ifnull(item.is_pro_applicable, 'No') = 'Yes'
or ifnull(item.is_sub_contracted_item, 'No') = 'Yes') %s)
- or exists (select name from `tabPacked Item` dnpi
- where dnpi.parent = so.name and dnpi.parent_item = so_item.item_code
- and exists (select name from `tabItem` item where item.name=dnpi.item_code
+ or exists (select name from `tabPacked Item` pi
+ where pi.parent = so.name and pi.parent_item = so_item.item_code
+ and exists (select name from `tabItem` item where item.name=pi.item_code
and (ifnull(item.is_pro_applicable, 'No') = 'Yes'
or ifnull(item.is_sub_contracted_item, 'No') = 'Yes') %s)))
""" % ('%s', so_filter, item_filter, item_filter), self.doc.company, as_dict=1)
@@ -83,6 +82,8 @@
def add_so_in_table(self, open_so):
""" Add sales orders in the table"""
+ self.clear_so_table()
+
so_list = [d.sales_order for d in getlist(self.doclist, 'pp_so_details')]
for r in open_so:
if cstr(r['name']) not in so_list:
@@ -104,7 +105,7 @@
def get_items(self):
so_list = filter(None, [d.sales_order for d in getlist(self.doclist, 'pp_so_details')])
if not so_list:
- msgprint("Please enter sales order in the above table")
+ msgprint(_("Please enter sales order in the above table"))
return []
items = webnotes.conn.sql("""select distinct parent, item_code, reserved_warehouse,
@@ -116,19 +117,19 @@
or ifnull(item.is_sub_contracted_item, 'No') = 'Yes'))""" % \
(", ".join(["%s"] * len(so_list))), tuple(so_list), as_dict=1)
- 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)
+ packed_items = webnotes.conn.sql("""select distinct pi.parent, pi.item_code, pi.warehouse as reserved_warhouse,
+ (((so_item.qty - ifnull(so_item.delivered_qty, 0)) * pi.qty) / so_item.qty)
as pending_qty
- from `tabSales Order Item` so_item, `tabPacked Item` dnpi
- where so_item.parent = dnpi.parent and so_item.docstatus = 1
- and dnpi.parent_item = so_item.item_code
+ from `tabSales Order Item` so_item, `tabPacked Item` pi
+ where so_item.parent = pi.parent and so_item.docstatus = 1
+ and pi.parent_item = so_item.item_code
and so_item.parent in (%s) and ifnull(so_item.qty, 0) > ifnull(so_item.delivered_qty, 0)
- and exists (select * from `tabItem` item where item.name=dnpi.item_code
+ and exists (select * from `tabItem` item where item.name=pi.item_code
and (ifnull(item.is_pro_applicable, 'No') = 'Yes'
or ifnull(item.is_sub_contracted_item, 'No') = 'Yes'))""" % \
(", ".join(["%s"] * len(so_list))), tuple(so_list), as_dict=1)
- return items + dnpi_items
+ return items + packed_items
def add_items(self, items):
@@ -153,21 +154,21 @@
for d in getlist(self.doclist, 'pp_details'):
self.validate_bom_no(d)
if not flt(d.planned_qty):
- msgprint("Please Enter Planned Qty for item: %s at row no: %s" %
- (d.item_code, d.idx), raise_exception=1)
+ webnotes.throw("Please Enter Planned Qty for item: %s at row no: %s" %
+ (d.item_code, d.idx))
def validate_bom_no(self, d):
if not d.bom_no:
- msgprint("Please enter bom no for item: %s at row no: %s" %
- (d.item_code, d.idx), raise_exception=1)
+ webnotes.throw("Please enter bom no for item: %s at row no: %s" %
+ (d.item_code, d.idx))
else:
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:
- msgprint("""Incorrect BOM No: %s entered for item: %s at row no: %s
+ webnotes.throw("""Incorrect BOM No: %s entered for item: %s at row no: %s
May be BOM is inactive or for other item or does not exists in the system""" %
- (d.bom_no, d.item_doce, d.idx), raise_exception=1)
+ (d.bom_no, d.item_doce, d.idx))
def raise_production_order(self):
"""It will raise production order (Draft) for all distinct FG items"""
@@ -181,16 +182,19 @@
if pro:
pro = ["""<a href="#Form/Production Order/%s" target="_blank">%s</a>""" % \
(p, p) for p in pro]
- msgprint("Production Order(s) created:\n\n" + '\n'.join(pro))
+ msgprint(_("Production Order(s) created:\n\n") + '\n'.join(pro))
else :
- msgprint("No Production Order created.")
-
+ msgprint(_("No Production Order created."))
def get_distinct_items_and_boms(self):
- """ Club similar BOM and item for processing"""
+ """ Club similar BOM and item for processing
+ bom_dict {
+ bom_no: ['sales_order', 'qty']
+ }
+ """
item_dict, bom_dict = {}, {}
for d in self.doclist.get({"parentfield": "pp_details"}):
- bom_dict[d.bom_no] = bom_dict.get(d.bom_no, 0) + flt(d.planned_qty)
+ bom_dict.setdefault(d.bom_no, []).append([d.sales_order, flt(d.planned_qty)])
item_dict[(d.item_code, d.sales_order, d.warehouse)] = {
"production_item" : d.item_code,
"sales_order" : d.sales_order,
@@ -239,48 +243,60 @@
"item_code": [qty_required, description, stock_uom, min_order_qty]
}
"""
- for bom in bom_dict:
+ bom_wise_item_details = {}
+ item_list = []
+
+ for bom, so_wise_qty in bom_dict.items():
if self.doc.use_multi_level_bom:
# get all raw materials with sub assembly childs
- fl_bom_items = webnotes.conn.sql("""select fb.item_code,
- ifnull(sum(fb.qty_consumed_per_unit), 0)*%s as qty,
+ for d in webnotes.conn.sql("""select fb.item_code,
+ ifnull(sum(fb.qty_consumed_per_unit), 0) as qty,
fb.description, fb.stock_uom, it.min_order_qty
from `tabBOM Explosion Item` fb,`tabItem` it
- where it.name = fb.item_code and ifnull(it.is_pro_applicable, 'No') = 'No'
+ where it.name = fb.item_code and ifnull(it.is_pro_applicable, 'No') = 'No'
and ifnull(it.is_sub_contracted_item, 'No') = 'No'
- and fb.docstatus<2 and fb.parent=%s
- group by item_code, stock_uom""", (flt(bom_dict[bom]), bom))
+ and fb.docstatus<2 and fb.parent=%s
+ group by item_code, stock_uom""", bom, as_dict=1):
+ bom_wise_item_details.setdefault(d.item_code, d)
else:
# Get all raw materials considering SA items as raw materials,
# so no childs of SA items
- 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
+ for d in webnotes.conn.sql("""select bom_item.item_code,
+ ifnull(sum(bom_item.qty_consumed_per_unit), 0) as qty,
+ bom_item.description, bom_item.stock_uom, item.min_order_qty
+ from `tabBOM Item` bom_item, tabItem item
where bom_item.parent = %s and bom_item.docstatus < 2
and bom_item.item_code = item.name
- group by item_code""", (flt(bom_dict[bom]), bom))
- self.make_items_dict(fl_bom_items)
+ group by item_code""", bom, as_dict=1):
+ bom_wise_item_details.setdefault(d.item_code, d)
+
+ for item, item_details in bom_wise_item_details.items():
+ for so_qty in so_wise_qty:
+ item_list.append([item, flt(item_details.qty) * so_qty[1], item_details.description,
+ item_details.stock_uom, item_details.min_order_qty, so_qty[0]])
+
+ self.make_items_dict(item_list)
def make_items_dict(self, item_list):
for i in item_list:
- self.item_dict[i[0]] = [(flt(self.item_dict.get(i[0], [0])[0]) + flt(i[1])),
- i[2], i[3], i[4]]
-
+ self.item_dict.setdefault(i[0], []).append([flt(i[1]), i[2], i[3], i[4], i[5]])
def get_csv(self):
item_list = [['Item Code', 'Description', 'Stock UOM', 'Required Qty', 'Warehouse',
'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= 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:
- i_qty, o_qty, a_qty = i_qty + flt(w[1]), o_qty + flt(w[2]), a_qty + flt(w[3])
- item_list.append(['', '', '', '', w[0], flt(w[1]), flt(w[2]), flt(w[3])])
- if item_qty:
- item_list.append(['', '', '', '', 'Total', i_qty, o_qty, a_qty])
+ for item in self.item_dict:
+ total_qty = sum([flt(d[0]) for d in self.item_dict[item]])
+ for item_details in self.item_dict[item]:
+ item_list.append([item, item_details[1], item_details[2], item_details[0]])
+ item_qty = webnotes.conn.sql("""select warehouse, indented_qty, ordered_qty, actual_qty
+ from `tabBin` where item_code = %s""", item, as_dict=1)
+ i_qty, o_qty, a_qty = 0, 0, 0
+ for w in item_qty:
+ i_qty, o_qty, a_qty = i_qty + flt(w.indented_qty), o_qty + flt(w.ordered_qty), a_qty + flt(w.actual_qty)
+ item_list.append(['', '', '', '', w.warehouse, flt(w.indented_qty),
+ flt(w.ordered_qty), flt(w.actual_qty)])
+ if item_qty:
+ item_list.append(['', '', '', '', 'Total', i_qty, o_qty, a_qty])
return item_list
@@ -291,31 +307,49 @@
"""
self.validate_data()
if not self.doc.purchase_request_for_warehouse:
- webnotes.msgprint("Please enter Warehouse for which Material Request will be raised",
- raise_exception=1)
+ webnotes.throw(_("Please enter Warehouse for which Material Request will be raised"))
bom_dict = self.get_distinct_items_and_boms()[0]
self.get_raw_materials(bom_dict)
- if not self.item_dict:
- return
-
+ if self.item_dict:
+ self.insert_purchase_request()
+
+ def get_requested_items(self):
item_projected_qty = self.get_projected_qty()
-
- from erpnext.accounts.utils import get_fiscal_year
- fiscal_year = get_fiscal_year(nowdate())[0]
-
items_to_be_requested = webnotes._dict()
- for item in self.item_dict:
- if flt(self.item_dict[item][0]) > item_projected_qty.get(item, 0):
+
+ for item, so_item_qty in self.item_dict.items():
+ requested_qty = 0
+ total_qty = sum([flt(d[0]) for d in so_item_qty])
+ if total_qty > item_projected_qty.get(item, 0):
# shortage
- requested_qty = flt(self.item_dict[item][0]) - item_projected_qty.get(item, 0)
- # comsider minimum order qty
- requested_qty = requested_qty > flt(self.item_dict[item][3]) and \
- requested_qty or flt(self.item_dict[item][3])
- items_to_be_requested[item] = requested_qty
-
- self.insert_purchase_request(items_to_be_requested, fiscal_year)
+ requested_qty = total_qty - item_projected_qty.get(item, 0)
+ # consider minimum order qty
+ requested_qty = requested_qty > flt(so_item_qty[0][3]) and \
+ requested_qty or flt(so_item_qty[0][3])
+
+ # distribute requested qty SO wise
+ for item_details in so_item_qty:
+ if requested_qty:
+ sales_order = item_details[4] or "No Sales Order"
+ if requested_qty <= item_details[0]:
+ adjusted_qty = requested_qty
+ else:
+ adjusted_qty = item_details[0]
+
+ items_to_be_requested.setdefault(item, {}).setdefault(sales_order, 0)
+ items_to_be_requested[item][sales_order] += adjusted_qty
+ requested_qty -= adjusted_qty
+ else:
+ break
+
+ # requested qty >= total so qty, due to minimum order qty
+ if requested_qty:
+ items_to_be_requested.setdefault(item, {}).setdefault("No Sales Order", 0)
+ items_to_be_requested[item]["No Sales Order"] += requested_qty
+
+ return items_to_be_requested
def get_projected_qty(self):
items = self.item_dict.keys()
@@ -325,24 +359,29 @@
return dict(item_projected_qty)
- def insert_purchase_request(self, items_to_be_requested, fiscal_year):
+ def insert_purchase_request(self):
+ items_to_be_requested = self.get_requested_items()
+
+ from erpnext.accounts.utils import get_fiscal_year
+ fiscal_year = get_fiscal_year(nowdate())[0]
+
purchase_request_list = []
if items_to_be_requested:
for item in items_to_be_requested:
item_wrapper = webnotes.bean("Item", item)
- pr_doclist = [
- {
- "doctype": "Material Request",
- "__islocal": 1,
- "naming_series": "IDT",
- "transaction_date": nowdate(),
- "status": "Draft",
- "company": self.doc.company,
- "fiscal_year": fiscal_year,
- "requested_by": webnotes.session.user,
- "material_request_type": "Purchase"
- },
- {
+ pr_doclist = [{
+ "doctype": "Material Request",
+ "__islocal": 1,
+ "naming_series": "IDT",
+ "transaction_date": nowdate(),
+ "status": "Draft",
+ "company": self.doc.company,
+ "fiscal_year": fiscal_year,
+ "requested_by": webnotes.session.user,
+ "material_request_type": "Purchase"
+ }]
+ for sales_order, requested_qty in items_to_be_requested[item].items():
+ pr_doclist.append({
"doctype": "Material Request Item",
"__islocal": 1,
"parentfield": "indent_details",
@@ -352,11 +391,12 @@
"uom": item_wrapper.doc.stock_uom,
"item_group": item_wrapper.doc.item_group,
"brand": item_wrapper.doc.brand,
- "qty": items_to_be_requested[item],
+ "qty": requested_qty,
"schedule_date": add_days(nowdate(), cint(item_wrapper.doc.lead_time_days)),
- "warehouse": self.doc.purchase_request_for_warehouse
- }
- ]
+ "warehouse": self.doc.purchase_request_for_warehouse,
+ "sales_order_no": sales_order if sales_order!="No Sales Order" else None
+ })
+
pr_wrapper = webnotes.bean(pr_doclist)
pr_wrapper.ignore_permissions = 1
pr_wrapper.submit()
@@ -365,7 +405,7 @@
if purchase_request_list:
pur_req = ["""<a href="#Form/Material Request/%s" target="_blank">%s</a>""" % \
(p, p) for p in purchase_request_list]
- webnotes.msgprint("Material Request(s) created: \n%s" %
+ msgprint("Material Request(s) created: \n%s" %
"\n".join(pur_req))
else:
- webnotes.msgprint("Nothing to request")
+ msgprint(_("Nothing to request"))
diff --git a/erpnext/patches/july_2013/p07_repost_billed_amt_in_sales_cycle.py b/erpnext/patches/july_2013/p07_repost_billed_amt_in_sales_cycle.py
index 6419315..95004c0 100644
--- a/erpnext/patches/july_2013/p07_repost_billed_amt_in_sales_cycle.py
+++ b/erpnext/patches/july_2013/p07_repost_billed_amt_in_sales_cycle.py
@@ -5,7 +5,8 @@
def execute():
import webnotes
+ webnotes.reload_doc('stock', 'doctype', 'packed_item')
for si in webnotes.conn.sql("""select name from `tabSales Invoice` where docstatus = 1"""):
webnotes.get_obj("Sales Invoice", si[0],
with_children=1).update_qty(change_modified=False)
- webnotes.conn.commit()
\ No newline at end of file
+ webnotes.conn.commit()
diff --git a/erpnext/patches/patch_list.py b/erpnext/patches/patch_list.py
index 9400e08..608ba77 100644
--- a/erpnext/patches/patch_list.py
+++ b/erpnext/patches/patch_list.py
@@ -256,6 +256,11 @@
"patches.1311.p06_fix_report_columns",
"execute:webnotes.delete_doc('DocType', 'Documentation Tool')",
"execute:webnotes.delete_doc('Report', 'Stock Ledger') #2013-11-29",
+ "patches.1312.p01_delete_old_stock_reports",
"execute:webnotes.delete_doc('Report', 'Payment Collection With Ageing')",
"execute:webnotes.delete_doc('Report', 'Payment Made With Ageing')",
+ "patches.1311.p07_scheduler_errors_digest",
+ "patches.1311.p08_email_digest_recipients",
+ "execute:webnotes.delete_doc('DocType', 'Warehouse Type')",
+ "patches.1312.p02_update_item_details_in_item_price",
]
\ No newline at end of file
diff --git a/erpnext/public/js/account_tree_grid.js b/erpnext/public/js/account_tree_grid.js
index 44bef57..1cd9aa6 100644
--- a/erpnext/public/js/account_tree_grid.js
+++ b/erpnext/public/js/account_tree_grid.js
@@ -26,9 +26,10 @@
show: true,
parent_field: "parent_account",
formatter: function(item) {
- return repl('<a href="#general-ledger/account=%(enc_value)s">%(value)s</a>', {
+ return repl("<a \
+ onclick='wn.cur_grid_report.show_general_ledger(\"%(value)s\")'>\
+ %(value)s</a>", {
value: item.name,
- enc_value: encodeURIComponent(item.name)
});
}
},
@@ -211,4 +212,14 @@
return;
}
},
+
+ show_general_ledger: function(account) {
+ wn.route_options = {
+ account: account,
+ company: this.company,
+ from_date: this.from_date,
+ to_date: this.to_date
+ };
+ wn.set_route("query-report", "General Ledger");
+ }
});
\ No newline at end of file
diff --git a/erpnext/public/js/controllers/stock_controller.js b/erpnext/public/js/controllers/stock_controller.js
index ee5c497..d2fb904 100644
--- a/erpnext/public/js/controllers/stock_controller.js
+++ b/erpnext/public/js/controllers/stock_controller.js
@@ -11,9 +11,10 @@
wn.route_options = {
voucher_no: me.frm.doc.name,
from_date: me.frm.doc.posting_date,
- to_date: me.frm.doc.posting_date
+ to_date: me.frm.doc.posting_date,
+ company: me.frm.doc.company
};
- wn.set_route('stock-ledger');
+ wn.set_route("query-report", "Stock Ledger");
}, "icon-bar-chart");
}
@@ -24,11 +25,12 @@
if(this.frm.doc.docstatus===1 && cint(wn.defaults.get_default("auto_accounting_for_stock"))) {
cur_frm.appframe.add_button(wn._('Accounting Ledger'), function() {
wn.route_options = {
- "voucher_no": me.frm.doc.name,
- "from_date": me.frm.doc.posting_date,
- "to_date": me.frm.doc.posting_date,
+ voucher_no: me.frm.doc.name,
+ from_date: me.frm.doc.posting_date,
+ to_date: me.frm.doc.posting_date,
+ company: me.frm.doc.company
};
- wn.set_route("general-ledger");
+ wn.set_route("query-report", "General Ledger");
}, "icon-table");
}
},
diff --git a/erpnext/public/js/stock_analytics.js b/erpnext/public/js/stock_analytics.js
index ba41318..48deeb4 100644
--- a/erpnext/public/js/stock_analytics.js
+++ b/erpnext/public/js/stock_analytics.js
@@ -17,10 +17,10 @@
parent_field: "parent_item_group",
formatter: function(item) {
if(!item.is_group) {
- return repl('<a href="#stock-ledger/item_code=%(enc_value)s">%(value)s</a>',
- {
+ return repl("<a \
+ onclick='wn.cur_grid_report.show_stock_ledger(\"%(value)s\")'>\
+ %(value)s</a>", {
value: item.name,
- enc_value: encodeURIComponent(item.name)
});
} else {
return item.name;
@@ -183,5 +183,13 @@
},
get_plot_points: function(item, col, idx) {
return [[dateutil.user_to_obj(col.name).getTime(), item[col.field]]]
+ },
+ show_stock_ledger: function(item_code) {
+ wn.route_options = {
+ item_code: item_code,
+ from_date: this.from_date,
+ to_date: this.to_date
+ };
+ wn.set_route("query-report", "Stock Ledger");
}
});
\ No newline at end of file
diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py
index 185c74b..a54f23d 100644
--- a/erpnext/selling/doctype/customer/customer.py
+++ b/erpnext/selling/doctype/customer/customer.py
@@ -47,6 +47,14 @@
if self.doc.lead_name:
webnotes.conn.sql("update `tabLead` set status='Converted' where name = %s", self.doc.lead_name)
+ def update_address(self):
+ webnotes.conn.sql("""update `tabAddress` set customer_name=%s, modified=NOW()
+ where customer=%s""", (self.doc.customer_name, self.doc.name))
+
+ def update_contact(self):
+ webnotes.conn.sql("""update `tabContact` set customer_name=%s, modified=NOW()
+ where customer=%s""", (self.doc.customer_name, self.doc.name))
+
def create_account_head(self):
if self.doc.company :
abbr = self.get_company_abbr()
@@ -99,6 +107,9 @@
self.validate_name_with_customer_group()
self.update_lead_status()
+ self.update_address()
+ self.update_contact()
+
# create account head
self.create_account_head()
# update credit days and limit in account
@@ -146,10 +157,19 @@
def before_rename(self, olddn, newdn, merge=False):
from erpnext.accounts.utils import rename_account_for
rename_account_for("Customer", olddn, newdn, merge)
-
+
def after_rename(self, olddn, newdn, merge=False):
+ set_field = ''
if webnotes.defaults.get_global_default('cust_master_name') == 'Customer Name':
webnotes.conn.set(self.doc, "customer_name", newdn)
+ self.update_contact()
+ set_field = ", customer_name=%(newdn)s"
+ self.update_customer_address(newdn, set_field)
+
+ def update_customer_address(self, newdn, set_field):
+ webnotes.conn.sql("""update `tabAddress` set address_title=%(newdn)s
+ {set_field} where customer=%(newdn)s"""\
+ .format(set_field=set_field), ({"newdn": newdn}))
@webnotes.whitelist()
def get_dashboard_info(customer):
diff --git a/erpnext/selling/doctype/customer/customer.txt b/erpnext/selling/doctype/customer/customer.txt
index 7a24531..43a3977 100644
--- a/erpnext/selling/doctype/customer/customer.txt
+++ b/erpnext/selling/doctype/customer/customer.txt
@@ -2,7 +2,7 @@
{
"creation": "2013-06-11 14:26:44",
"docstatus": 0,
- "modified": "2013-11-03 14:01:33",
+ "modified": "2013-12-25 11:15:05",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -16,7 +16,7 @@
"icon": "icon-user",
"module": "Selling",
"name": "__common__",
- "search_fields": "customer_name,customer_group,country,territory"
+ "search_fields": "customer_name,customer_group,territory"
},
{
"doctype": "DocField",
diff --git a/erpnext/selling/doctype/quotation/quotation.txt b/erpnext/selling/doctype/quotation/quotation.txt
index dc34272..93346d3 100644
--- a/erpnext/selling/doctype/quotation/quotation.txt
+++ b/erpnext/selling/doctype/quotation/quotation.txt
@@ -2,7 +2,7 @@
{
"creation": "2013-05-24 19:29:08",
"docstatus": 0,
- "modified": "2013-11-27 17:57:19",
+ "modified": "2013-12-14 17:25:46",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -863,6 +863,7 @@
"cancel": 0,
"create": 0,
"doctype": "DocPerm",
+ "match": "customer",
"role": "Customer",
"submit": 0,
"write": 0
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index aa5f214..4527574 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -112,10 +112,11 @@
self.validate_warehouse()
from erpnext.stock.doctype.packed_item.packed_item import make_packing_list
- self.doclist = make_packing_list(self,'sales_order_details')
+ self.doclist = make_packing_list(self,'sales_order_details')
+
self.validate_with_previous_doc()
-
+
if not self.doc.status:
self.doc.status = "Draft"
@@ -124,8 +125,7 @@
"Cancelled"])
if not self.doc.billing_status: self.doc.billing_status = 'Not Billed'
- if not self.doc.delivery_status: self.doc.delivery_status = 'Not Delivered'
-
+ if not self.doc.delivery_status: self.doc.delivery_status = 'Not Delivered'
def validate_warehouse(self):
from erpnext.stock.utils import validate_warehouse_user, validate_warehouse_company
diff --git a/erpnext/selling/sales_common.js b/erpnext/selling/sales_common.js
index ae16413..1c8aed3 100644
--- a/erpnext/selling/sales_common.js
+++ b/erpnext/selling/sales_common.js
@@ -515,7 +515,6 @@
}
});
};
-
setup_field_label_map(["net_total", "other_charges_total", "grand_total",
"rounded_total", "in_words",
"outstanding_amount", "total_advance", "paid_amount", "write_off_amount"],
diff --git a/erpnext/setup/doctype/backup_manager/backup_dropbox.py b/erpnext/setup/doctype/backup_manager/backup_dropbox.py
index 8659b5a..9c1decf 100644
--- a/erpnext/setup/doctype/backup_manager/backup_dropbox.py
+++ b/erpnext/setup/doctype/backup_manager/backup_dropbox.py
@@ -16,8 +16,6 @@
from webnotes.utils import get_request_site_address, cstr
from webnotes import _
-from backup_manager import ignore_list
-
@webnotes.whitelist()
def get_dropbox_authorize_url():
sess = get_dropbox_session()
@@ -100,9 +98,7 @@
path = get_files_path()
for filename in os.listdir(path):
filename = cstr(filename)
- if filename in ignore_list:
- continue
-
+
found = False
filepath = os.path.join(path, filename)
for file_metadata in response["contents"]:
diff --git a/erpnext/setup/doctype/backup_manager/backup_manager.js b/erpnext/setup/doctype/backup_manager/backup_manager.js
index e94a316..dfe6bd5 100644
--- a/erpnext/setup/doctype/backup_manager/backup_manager.js
+++ b/erpnext/setup/doctype/backup_manager/backup_manager.js
@@ -87,7 +87,7 @@
cur_frm.save();
},
- upload_backups_to_gdrive: function() {
- cur_frm.save();
- },
+ // upload_backups_to_gdrive: function() {
+ // cur_frm.save();
+ // },
});
\ No newline at end of file
diff --git a/erpnext/setup/doctype/backup_manager/backup_manager.py b/erpnext/setup/doctype/backup_manager/backup_manager.py
index 339038f..b6a5ace 100644
--- a/erpnext/setup/doctype/backup_manager/backup_manager.py
+++ b/erpnext/setup/doctype/backup_manager/backup_manager.py
@@ -7,8 +7,6 @@
import webnotes
from webnotes import _
-ignore_list = []
-
class DocType:
def __init__(self, d, dl):
self.doc, self.doclist = d, dl
@@ -39,10 +37,6 @@
file_and_error = [" - ".join(f) for f in zip(did_not_upload, error_log)]
error_message = ("\n".join(file_and_error) + "\n" + webnotes.get_traceback())
webnotes.errprint(error_message)
-
- if not webnotes.conn:
- webnotes.connect()
-
send_email(False, "Dropbox", error_message)
#backup to gdrive
@@ -62,6 +56,7 @@
send_email(False, "Google Drive", error_message)
def send_email(success, service_name, error_status=None):
+ from webnotes.utils.email_lib import sendmail
if success:
subject = "Backup Upload Successful"
message ="""<h3>Backup Uploaded Successfully</h3><p>Hi there, this is just to inform you
@@ -76,7 +71,8 @@
<p>Please contact your system manager for more information.</p>
""" % (service_name, error_status)
- # email system managers
- from webnotes.utils.email_lib import sendmail
- sendmail(webnotes.conn.get_value("Backup Manager", None, "send_notifications_to").split(","),
- subject=subject, msg=message)
+ if not webnotes.conn:
+ webnotes.connect()
+
+ recipients = webnotes.conn.get_value("Backup Manager", None, "send_notifications_to").split(",")
+ sendmail(recipients, subject=subject, msg=message)
diff --git a/erpnext/setup/doctype/email_digest/email_digest.js b/erpnext/setup/doctype/email_digest/email_digest.js
index 3367a72..79cc681 100644
--- a/erpnext/setup/doctype/email_digest/email_digest.js
+++ b/erpnext/setup/doctype/email_digest/email_digest.js
@@ -70,8 +70,10 @@
check.checked = 1;
add_or_update = 'Update';
}
+ var fullname = wn.user.full_name(v.name);
+ if(fullname !== v.name) v.name = fullname + " <" + v.name + ">";
if(v.enabled==0) {
- v.name = "<span style='color: red'>" + v.name + " (disabled user)</span>"
+ v.name = repl("<span style='color: red'> %(name)s (disabled user)</span>", {name: v.name});
}
var profile = $a($td(tab, i+1, 1), 'span', '', '', v.name);
//profile.onclick = function() { check.checked = !check.checked; }
diff --git a/erpnext/setup/doctype/email_digest/email_digest.py b/erpnext/setup/doctype/email_digest/email_digest.py
index 15bb67a..b9125c9 100644
--- a/erpnext/setup/doctype/email_digest/email_digest.py
+++ b/erpnext/setup/doctype/email_digest/email_digest.py
@@ -9,6 +9,7 @@
from webnotes.utils.dateutils import datetime_in_user_format
from datetime import timedelta
from dateutil.relativedelta import relativedelta
+from webnotes.utils.email_lib import sendmail
content_sequence = [
["Income / Expenses", ["income_year_to_date", "bank_balance",
@@ -19,16 +20,16 @@
["Selling", ["new_leads", "new_enquiries", "new_quotations", "new_sales_orders"]],
["Stock", ["new_delivery_notes", "new_purchase_receipts", "new_stock_entries"]],
["Support", ["new_communications", "new_support_tickets", "open_tickets"]],
- ["Projects", ["new_projects"]]
+ ["Projects", ["new_projects"]],
+ ["System", ["scheduler_errors"]],
]
user_specific_content = ["calendar_events", "todo_list"]
-digest_template = """\
-<style>p.ed-indent { margin-right: 17px; }</style>
-<h2>%(digest)s</h2>
-<p style='color: grey'>%(date)s</p>
+digest_template = """<style>p.ed-indent { margin-right: 17px; }</style>
+<h2>%(name)s</h2>
<h4>%(company)s</h4>
+<p style='color: grey'>%(date)s</p>
<hr>
%(with_value)s
%(no_value)s
@@ -53,10 +54,10 @@
def get_profiles(self):
"""get list of profiles"""
- import webnotes
profile_list = webnotes.conn.sql("""
select name, enabled from tabProfile
where docstatus=0 and name not in ('Administrator', 'Guest')
+ and user_type = "System User"
order by enabled desc, name asc""", as_dict=1)
if self.doc.recipient_list:
@@ -80,13 +81,15 @@
for user_id in recipients:
msg_for_this_receipient = self.get_msg_html(self.get_user_specific_content(user_id) + \
common_msg)
- from webnotes.utils.email_lib import sendmail
- sendmail(recipients=user_id, subject="[ERPNext] " + (self.doc.frequency + " Digest"),
- msg=msg_for_this_receipient)
+ if msg_for_this_receipient:
+ sendmail(recipients=user_id,
+ subject="[ERPNext] [{frequency} Digest] {name}".format(
+ frequency=self.doc.frequency, name=self.doc.name),
+ msg=msg_for_this_receipient)
def get_digest_msg(self):
return self.get_msg_html(self.get_user_specific_content(webnotes.session.user) + \
- self.get_common_content())
+ self.get_common_content(), send_only_if_updates=False)
def get_common_content(self):
out = []
@@ -117,14 +120,19 @@
return out
- def get_msg_html(self, out):
+ def get_msg_html(self, out, send_only_if_updates=True):
with_value = [o[1] for o in out if o[0]]
if with_value:
+ has_updates = True
with_value = "\n".join(with_value)
else:
- with_value = "<p>There were no updates in the items selected for this digest.</p>"
+ has_updates = False
+ with_value = "<p>There were no updates in the items selected for this digest.</p><hr>"
+ if not has_updates and send_only_if_updates:
+ return
+
# seperate out no value items
no_value = [o[1] for o in out if not o[0]]
if no_value:
@@ -138,7 +146,8 @@
"date": date,
"company": self.doc.company,
"with_value": with_value,
- "no_value": no_value or ""
+ "no_value": no_value or "",
+ "name": self.doc.name
}
return msg
@@ -241,7 +250,7 @@
return self.get_new_count("Lead", self.meta.get_label("new_leads"))
def get_new_enquiries(self):
- return self.get_new_count("Opportunity", self.meta.get_label("new_enquiries"))
+ return self.get_new_count("Opportunity", self.meta.get_label("new_enquiries"), docstatus=1)
def get_new_quotations(self):
return self.get_new_sum("Quotation", self.meta.get_label("new_quotations"), "grand_total")
@@ -253,7 +262,8 @@
return self.get_new_sum("Delivery Note", self.meta.get_label("new_delivery_notes"), "grand_total")
def get_new_purchase_requests(self):
- return self.get_new_count("Material Request", self.meta.get_label("new_purchase_requests"))
+ return self.get_new_count("Material Request",
+ self.meta.get_label("new_purchase_requests"), docstatus=1)
def get_new_supplier_quotations(self):
return self.get_new_sum("Supplier Quotation", self.meta.get_label("new_supplier_quotations"),
@@ -271,13 +281,16 @@
return self.get_new_sum("Stock Entry", self.meta.get_label("new_stock_entries"), "total_amount")
def get_new_support_tickets(self):
- return self.get_new_count("Support Ticket", self.meta.get_label("new_support_tickets"), False)
+ return self.get_new_count("Support Ticket", self.meta.get_label("new_support_tickets"),
+ filter_by_company=False)
def get_new_communications(self):
- return self.get_new_count("Communication", self.meta.get_label("new_communications"), False)
+ return self.get_new_count("Communication", self.meta.get_label("new_communications"),
+ filter_by_company=False)
def get_new_projects(self):
- return self.get_new_count("Project", self.meta.get_label("new_projects"), False)
+ return self.get_new_count("Project", self.meta.get_label("new_projects"),
+ filter_by_company=False)
def get_calendar_events(self, user_id):
from webnotes.core.doctype.event.event import get_events
@@ -321,22 +334,22 @@
else:
return 0, "<p>To Do</p>"
- def get_new_count(self, doctype, label, filter_by_company=True):
+ def get_new_count(self, doctype, label, docstatus=0, filter_by_company=True):
if filter_by_company:
company = """and company="%s" """ % self.doc.company
else:
company = ""
count = webnotes.conn.sql("""select count(*) from `tab%s`
- where docstatus < 2 %s and
- date(creation)>=%s and date(creation)<=%s""" % (doctype, company, "%s", "%s"),
- (self.from_date, self.to_date))
+ where docstatus=%s %s and
+ date(creation)>=%s and date(creation)<=%s""" %
+ (doctype, docstatus, company, "%s", "%s"), (self.from_date, self.to_date))
count = count and count[0][0] or 0
return count, self.get_html(label, None, count)
def get_new_sum(self, doctype, label, sum_field):
count_sum = webnotes.conn.sql("""select count(*), sum(ifnull(`%s`, 0))
- from `tab%s` where docstatus < 2 and company = %s and
+ from `tab%s` where docstatus=1 and company = %s and
date(creation)>=%s and date(creation)<=%s""" % (sum_field, doctype, "%s",
"%s", "%s"), (self.doc.company, self.from_date, self.to_date))
count, total = count_sum and count_sum[0] or (0, 0)
@@ -448,6 +461,10 @@
t for t in open_tickets])
else:
return 0, "No Open Tickets!"
+
+ def get_scheduler_errors(self):
+ import webnotes.utils.scheduler
+ return webnotes.utils.scheduler.get_error_report(self.from_date, self.to_date)
def onload(self):
self.get_next_sending()
diff --git a/erpnext/setup/doctype/email_digest/email_digest.txt b/erpnext/setup/doctype/email_digest/email_digest.txt
index f71d82a..b04885a 100644
--- a/erpnext/setup/doctype/email_digest/email_digest.txt
+++ b/erpnext/setup/doctype/email_digest/email_digest.txt
@@ -2,7 +2,7 @@
{
"creation": "2013-02-21 14:15:31",
"docstatus": 0,
- "modified": "2013-07-05 14:36:13",
+ "modified": "2013-12-16 12:37:43",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -100,11 +100,10 @@
"label": "Add/Remove Recipients"
},
{
- "description": "Check all the items below that you want to send in this digest.",
"doctype": "DocField",
- "fieldname": "select_digest_content",
+ "fieldname": "accounts",
"fieldtype": "Section Break",
- "label": "Select Digest Content"
+ "label": "Accounts"
},
{
"doctype": "DocField",
@@ -178,7 +177,7 @@
"doctype": "DocField",
"fieldname": "section_break_20",
"fieldtype": "Section Break",
- "options": "Simple"
+ "label": "Buying & Selling"
},
{
"doctype": "DocField",
@@ -236,6 +235,12 @@
},
{
"doctype": "DocField",
+ "fieldname": "section_break_34",
+ "fieldtype": "Section Break",
+ "label": "Inventory & Support"
+ },
+ {
+ "doctype": "DocField",
"fieldname": "stock_module",
"fieldtype": "Column Break",
"label": "Stock"
@@ -260,12 +265,6 @@
},
{
"doctype": "DocField",
- "fieldname": "section_break_34",
- "fieldtype": "Section Break",
- "options": "Simple"
- },
- {
- "doctype": "DocField",
"fieldname": "support_module",
"fieldtype": "Column Break",
"label": "Support"
@@ -290,6 +289,12 @@
},
{
"doctype": "DocField",
+ "fieldname": "section_break_40",
+ "fieldtype": "Section Break",
+ "label": "Projects & System"
+ },
+ {
+ "doctype": "DocField",
"fieldname": "projects_module",
"fieldtype": "Column Break",
"label": "Projects"
@@ -302,7 +307,25 @@
},
{
"doctype": "DocField",
- "fieldname": "utilities_module",
+ "fieldname": "core_module",
+ "fieldtype": "Column Break",
+ "label": "System"
+ },
+ {
+ "doctype": "DocField",
+ "fieldname": "scheduler_errors",
+ "fieldtype": "Check",
+ "label": "Scheduler Failed Events"
+ },
+ {
+ "doctype": "DocField",
+ "fieldname": "user_specific",
+ "fieldtype": "Section Break",
+ "label": "User Specific"
+ },
+ {
+ "doctype": "DocField",
+ "fieldname": "general",
"fieldtype": "Column Break",
"label": "General"
},
@@ -319,6 +342,12 @@
"label": "To Do List"
},
{
+ "doctype": "DocField",
+ "fieldname": "stub",
+ "fieldtype": "Column Break",
+ "label": "Stub"
+ },
+ {
"cancel": 1,
"create": 1,
"doctype": "DocPerm",
diff --git a/erpnext/setup/doctype/email_settings/email_settings.txt b/erpnext/setup/doctype/email_settings/email_settings.txt
index 3689718..6b28f10 100644
--- a/erpnext/setup/doctype/email_settings/email_settings.txt
+++ b/erpnext/setup/doctype/email_settings/email_settings.txt
@@ -2,7 +2,7 @@
{
"creation": "2013-03-25 17:53:21",
"docstatus": 0,
- "modified": "2013-11-28 11:54:42",
+ "modified": "2013-12-06 13:12:25",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -103,6 +103,7 @@
"label": "Auto Email Id"
},
{
+ "default": "1",
"description": "If checked, an email with an attached HTML format will be added to part of the EMail body as well as attachment. To only send as attachment, uncheck this.",
"doctype": "DocField",
"fieldname": "send_print_in_body_and_attachment",
diff --git a/erpnext/setup/doctype/features_setup/features_setup.txt b/erpnext/setup/doctype/features_setup/features_setup.txt
index 3f73ee2..d68f489 100644
--- a/erpnext/setup/doctype/features_setup/features_setup.txt
+++ b/erpnext/setup/doctype/features_setup/features_setup.txt
@@ -2,7 +2,7 @@
{
"creation": "2012-12-20 12:50:49",
"docstatus": 0,
- "modified": "2013-11-03 14:20:18",
+ "modified": "2013-12-24 11:40:19",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -90,7 +90,7 @@
"doctype": "DocField",
"fieldname": "fs_packing_details",
"fieldtype": "Check",
- "label": "Packing Detials"
+ "label": "Packing Details"
},
{
"description": "To get Item Group in details table",
diff --git a/erpnext/setup/doctype/naming_series/naming_series.py b/erpnext/setup/doctype/naming_series/naming_series.py
index f825e21..092de20 100644
--- a/erpnext/setup/doctype/naming_series/naming_series.py
+++ b/erpnext/setup/doctype/naming_series/naming_series.py
@@ -22,7 +22,7 @@
where fieldname='naming_series'""")
)))),
"prefixes": "\n".join([''] + [i[0] for i in
- webnotes.conn.sql("""select name from tabSeries""")])
+ webnotes.conn.sql("""select name from tabSeries order by name""")])
}
def scrub_options_list(self, ol):
@@ -38,7 +38,7 @@
self.set_series_for(self.doc.select_doc_for_series, series_list)
# create series
- map(self.insert_series, series_list)
+ map(self.insert_series, [d.split('.')[0] for d in series_list])
msgprint('Series Updated')
@@ -103,7 +103,8 @@
dt.validate_series(series, self.doc.select_doc_for_series)
for i in sr:
if i[0]:
- if series in i[0].split("\n"):
+ existing_series = [d.split('.')[0] for d in i[0].split("\n")]
+ if series.split(".")[0] in existing_series:
msgprint("Oops! Series name %s is already in use in %s. \
Please select a new one" % (series, i[1]), raise_exception=1)
@@ -120,17 +121,21 @@
def get_current(self, arg=None):
"""get series current"""
- self.doc.current_value = webnotes.conn.get_value("Series", self.doc.prefix, "current")
+ self.doc.current_value = webnotes.conn.get_value("Series",
+ self.doc.prefix.split('.')[0], "current")
def insert_series(self, series):
"""insert series if missing"""
if not webnotes.conn.exists('Series', series):
- webnotes.conn.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)
- webnotes.conn.sql("update `tabSeries` set current = '%s' where name = '%s'" % (self.doc.current_value,self.doc.prefix))
+ prefix = self.doc.prefix.split('.')[0]
+ self.insert_series(prefix)
+ webnotes.conn.sql("update `tabSeries` set current = %s where name = %s",
+ (self.doc.current_value, prefix))
msgprint("Series Updated Successfully")
else:
msgprint("Please select prefix first")
diff --git a/erpnext/setup/page/setup/setup.py b/erpnext/setup/page/setup/setup.py
index 4418f85..11025c9 100644
--- a/erpnext/setup/page/setup/setup.py
+++ b/erpnext/setup/page/setup/setup.py
@@ -233,8 +233,9 @@
"route": "Report/Scheduler Log", "type": "Link", "icon": "icon-exclamation-sign" },
]
-@webnotes.whitelist(allow_roles=["System Manager"])
+@webnotes.whitelist()
def get():
+ webnotes.only_for("System Manager")
for item in items:
if item.get("type")=="Section":
continue
diff --git a/erpnext/setup/page/setup_wizard/setup_wizard.py b/erpnext/setup/page/setup_wizard/setup_wizard.py
index 3258db3..6298973 100644
--- a/erpnext/setup/page/setup_wizard/setup_wizard.py
+++ b/erpnext/setup/page/setup_wizard/setup_wizard.py
@@ -158,6 +158,10 @@
hr_settings.doc.emp_created_by = "Naming Series"
hr_settings.save()
+ email_settings = webnotes.bean("Email Settings")
+ email_settings.doc.send_print_in_body_and_attachment = 1
+ email_settings.save()
+
# control panel
cp = webnotes.doc("Control Panel", "Control Panel")
cp.company_name = args["company_name"]
@@ -171,11 +175,12 @@
def create_email_digest():
from webnotes.profile import get_system_managers
- system_managers = get_system_managers()
+ system_managers = get_system_managers(only_name=True)
if not system_managers:
return
- for company in webnotes.conn.sql_list("select name FROM `tabCompany`"):
+ companies = webnotes.conn.sql_list("select name FROM `tabCompany`")
+ for company in companies:
if not webnotes.conn.exists("Email Digest", "Default Weekly Digest - " + company):
edigest = webnotes.bean({
"doctype": "Email Digest",
@@ -186,10 +191,24 @@
})
for fieldname in edigest.meta.get_fieldnames({"fieldtype": "Check"}):
- edigest.doc.fields[fieldname] = 1
+ if fieldname != "scheduler_errors":
+ edigest.doc.fields[fieldname] = 1
edigest.insert()
-
+
+ # scheduler errors digest
+ if companies:
+ edigest = webnotes.new_bean("Email Digest")
+ edigest.doc.fields.update({
+ "name": "Scheduler Errors",
+ "company": companies[0],
+ "frequency": "Daily",
+ "recipient_list": "\n".join(system_managers),
+ "scheduler_errors": 1,
+ "enabled": 1
+ })
+ edigest.insert()
+
def get_fy_details(fy_start_date, fy_end_date):
start_year = getdate(fy_start_date).year
if start_year == getdate(fy_end_date).year:
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py
index de76bb9..be0b95f 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.py
@@ -73,6 +73,9 @@
self.update_current_stock()
self.validate_with_previous_doc()
+ from erpnext.stock.doctype.packed_item.packed_item import make_packing_list
+ self.doclist = make_packing_list(self, 'delivery_note_details')
+
self.doc.status = 'Draft'
if not self.doc.installation_status: self.doc.installation_status = 'Not Installed'
@@ -142,10 +145,6 @@
bin = webnotes.conn.sql("select actual_qty, projected_qty from `tabBin` where item_code = %s and warehouse = %s", (d.item_code, d.warehouse), as_dict = 1)
d.actual_qty = bin and flt(bin[0]['actual_qty']) or 0
d.projected_qty = bin and flt(bin[0]['projected_qty']) or 0
-
- def on_update(self):
- from erpnext.stock.doctype.packed_item.packed_item import make_packing_list
- self.doclist = make_packing_list(self, 'delivery_note_details')
def on_submit(self):
self.validate_packed_qty()
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.txt b/erpnext/stock/doctype/delivery_note/delivery_note.txt
index 1dc3cd3..480d45d 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.txt
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.txt
@@ -2,7 +2,7 @@
{
"creation": "2013-05-24 19:29:09",
"docstatus": 0,
- "modified": "2013-12-09 16:24:08",
+ "modified": "2013-12-14 17:26:12",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -1058,7 +1058,7 @@
},
{
"doctype": "DocPerm",
- "match": "customer_name",
+ "match": "customer",
"role": "Customer"
}
]
\ No newline at end of file
diff --git a/erpnext/stock/doctype/delivery_note/test_delivery_note.py b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
index 7b6b0ad..4213d19 100644
--- a/erpnext/stock/doctype/delivery_note/test_delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
@@ -58,11 +58,6 @@
self.assertEqual(stock_value, 0)
self.assertEqual(stock_value_difference, -375)
-
- gl_entries = webnotes.conn.sql("""select account, debit, credit
- from `tabGL Entry` where voucher_type='Delivery Note' and voucher_no=%s
- order by account desc""", dn.doc.name, as_dict=1)
-
self.assertFalse(get_gl_entries("Delivery Note", dn.doc.name))
def test_delivery_note_gl_entry(self):
@@ -111,8 +106,8 @@
gl_entries = get_gl_entries("Delivery Note", dn.doc.name)
self.assertTrue(gl_entries)
expected_values = {
- stock_in_hand_account: [0.0, 666.65],
- "Cost of Goods Sold - _TC": [666.65, 0.0]
+ stock_in_hand_account: [0.0, 666.67],
+ "Cost of Goods Sold - _TC": [666.67, 0.0]
}
for i, gle in enumerate(gl_entries):
self.assertEquals([gle.debit, gle.credit], expected_values.get(gle.account))
diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py
index 637d1cd..f9763cd 100644
--- a/erpnext/stock/doctype/item/item.py
+++ b/erpnext/stock/doctype/item/item.py
@@ -4,7 +4,7 @@
from __future__ import unicode_literals
import webnotes
-from webnotes.utils import cstr, flt, cint
+from webnotes.utils import cstr, flt
from webnotes.model.doc import addchild
from webnotes.model.bean import getlist
from webnotes import msgprint, _
@@ -49,6 +49,7 @@
def on_update(self):
self.validate_name_with_item_group()
self.update_website()
+ self.update_item_price()
def check_warehouse_is_set_for_stock_item(self):
if self.doc.is_stock_item=="Yes" and not self.doc.default_warehouse:
@@ -112,40 +113,29 @@
self.doc.is_pro_applicable = "No"
if self.doc.is_pro_applicable == 'Yes' and self.doc.is_stock_item == 'No':
- msgprint("As Production Order can be made for this Item, then Is Stock Item Should be 'Yes' as we maintain it's stock. Refer Manufacturing and Inventory section.", raise_exception=1)
+ webnotes.throw(_("As Production Order can be made for this item, \
+ it must be a stock item."))
if self.doc.has_serial_no == 'Yes' and self.doc.is_stock_item == 'No':
msgprint("'Has Serial No' can not be 'Yes' for non-stock item", raise_exception=1)
def check_for_active_boms(self):
- def _check_for_active_boms(field_label):
- if field_label in ['Is Active', 'Is Purchase Item']:
- bom_mat = webnotes.conn.sql("""select distinct t1.parent
- from `tabBOM Item` t1, `tabBOM` t2 where t2.name = t1.parent
- and t1.item_code =%s and ifnull(t1.bom_no, '') = '' and t2.is_active = 1
- and t2.docstatus = 1 and t1.docstatus =1 """, self.doc.name)
- if bom_mat and bom_mat[0][0]:
- msgprint(_(field_label) + _(" should be 'Yes'. As Item: ") + self.doc.name +
- _(" is present in one or many Active BOMs"), raise_exception=1)
-
- if ((field_label == 'Allow Production Order'
- and self.doc.is_sub_contracted_item != 'Yes')
- or (field_label == 'Is Sub Contracted Item'
- and self.doc.is_manufactured_item != 'Yes')):
- bom = webnotes.conn.sql("""select name from `tabBOM` where item = %s
- and is_active = 1""", (self.doc.name,))
- if bom and bom[0][0]:
- msgprint(_(field_label) + _(" should be 'Yes'. As Item: ") + self.doc.name +
- _(" is present in one or many Active BOMs"), raise_exception=1)
-
- if not cint(self.doc.fields.get("__islocal")):
- fl = {'is_manufactured_item' :'Allow Bill of Materials',
- 'is_sub_contracted_item':'Is Sub Contracted Item',
- 'is_purchase_item' :'Is Purchase Item',
- 'is_pro_applicable' :'Allow Production Order'}
- for d in fl:
- if cstr(self.doc.fields.get(d)) != 'Yes':
- _check_for_active_boms(fl[d])
+ if self.doc.is_purchase_item != "Yes":
+ bom_mat = webnotes.conn.sql("""select distinct t1.parent
+ from `tabBOM Item` t1, `tabBOM` t2 where t2.name = t1.parent
+ and t1.item_code =%s and ifnull(t1.bom_no, '') = '' and t2.is_active = 1
+ and t2.docstatus = 1 and t1.docstatus =1 """, self.doc.name)
+
+ if bom_mat and bom_mat[0][0]:
+ webnotes.throw(_("Item must be a purchase item, \
+ as it is present in one or many Active BOMs"))
+
+ if self.doc.is_manufactured_item != "Yes":
+ bom = webnotes.conn.sql("""select name from `tabBOM` where item = %s
+ and is_active = 1""", (self.doc.name,))
+ if bom and bom[0][0]:
+ webnotes.throw(_("""Allow Bill of Materials should be 'Yes'. Because one or many \
+ active BOMs present for this item"""))
def fill_customer_code(self):
""" Append all the customer codes and insert into "customer_code" field of item table """
@@ -215,6 +205,11 @@
WebsiteGenerator.on_update(self)
+ def update_item_price(self):
+ webnotes.conn.sql("""update `tabItem Price` set item_name=%s,
+ item_description=%s, modified=NOW() where item_code=%s""",
+ (self.doc.item_name, self.doc.description, self.doc.name))
+
def get_page_title(self):
if self.doc.name==self.doc.item_name:
page_name_from = self.doc.name
@@ -251,6 +246,9 @@
def before_rename(self, olddn, newdn, merge=False):
if merge:
# Validate properties before merging
+ if not webnotes.conn.exists("Item", newdn):
+ webnotes.throw(_("Item ") + newdn +_(" does not exists"))
+
field_list = ["stock_uom", "is_stock_item", "has_serial_no", "has_batch_no"]
new_properties = [cstr(d) for d in webnotes.conn.get_value("Item", newdn, field_list)]
if new_properties != [cstr(self.doc.fields[fld]) for fld in field_list]:
diff --git a/erpnext/stock/doctype/material_request/material_request.py b/erpnext/stock/doctype/material_request/material_request.py
index 2f0fcb7..28ec508 100644
--- a/erpnext/stock/doctype/material_request/material_request.py
+++ b/erpnext/stock/doctype/material_request/material_request.py
@@ -37,20 +37,25 @@
for so_no in so_items.keys():
for item in so_items[so_no].keys():
- already_indented = webnotes.conn.sql("select sum(qty) from `tabMaterial Request Item` where item_code = '%s' and sales_order_no = '%s' and docstatus = 1 and parent != '%s'" % (item, so_no, self.doc.name))
+ already_indented = webnotes.conn.sql("""select sum(qty) from `tabMaterial Request Item`
+ where item_code = %s and sales_order_no = %s and
+ docstatus = 1 and parent != %s""", (item, so_no, self.doc.name))
already_indented = already_indented and flt(already_indented[0][0]) or 0
- actual_so_qty = webnotes.conn.sql("select sum(qty) from `tabSales Order Item` where parent = '%s' and item_code = '%s' and docstatus = 1 group by parent" % (so_no, item))
+ actual_so_qty = webnotes.conn.sql("""select sum(qty) from `tabSales Order Item`
+ where parent = %s and item_code = %s and docstatus = 1
+ group by parent""", (so_no, item))
actual_so_qty = actual_so_qty and flt(actual_so_qty[0][0]) or 0
- if flt(so_items[so_no][item]) + already_indented > actual_so_qty:
- msgprint("You can raise indent of maximum qty: %s for item: %s against sales order: %s\n Anyway, you can add more qty in new row for the same item." % (actual_so_qty - already_indented, item, so_no), raise_exception=1)
+ if actual_so_qty and (flt(so_items[so_no][item]) + already_indented > actual_so_qty):
+ webnotes.throw("You can raise indent of maximum qty: %s for item: %s against sales order: %s\
+ \n Anyway, you can add more qty in new row for the same item."
+ % (actual_so_qty - already_indented, item, so_no))
def validate_schedule_date(self):
for d in getlist(self.doclist, 'indent_details'):
if d.schedule_date < self.doc.transaction_date:
- msgprint("Expected Date cannot be before Material Request Date")
- raise Exception
+ webnotes.throw(_("Expected Date cannot be before Material Request Date"))
# Validate
# ---------------------
@@ -80,8 +85,8 @@
for d in getlist(self.doclist, 'indent_details'):
if webnotes.conn.get_value("Item", d.item_code, "is_stock_item") == "Yes":
if not d.warehouse:
- msgprint("Please Enter Warehouse for Item %s as it is stock item"
- % cstr(d.item_code), raise_exception=1)
+ webnotes.throw("Please Enter Warehouse for Item %s as it is stock item"
+ % cstr(d.item_code))
qty =flt(d.qty)
if is_stopped:
@@ -96,16 +101,17 @@
update_bin(args)
def on_submit(self):
- webnotes.conn.set(self.doc,'status','Submitted')
+ webnotes.conn.set(self.doc, 'status', 'Submitted')
self.update_bin(is_submit = 1, is_stopped = 0)
def check_modified_date(self):
- mod_db = webnotes.conn.sql("select modified from `tabMaterial Request` where name = '%s'" % self.doc.name)
- date_diff = webnotes.conn.sql("select TIMEDIFF('%s', '%s')" % ( mod_db[0][0],cstr(self.doc.modified)))
+ mod_db = webnotes.conn.sql("""select modified from `tabMaterial Request` 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. ")
- raise Exception
+ webnotes.throw(cstr(self.doc.doctype) + " => " + cstr(self.doc.name) + " has been modified. Please Refresh.")
def update_status(self, status):
self.check_modified_date()
@@ -113,10 +119,10 @@
self.update_bin(is_submit = (status == 'Submitted') and 1 or 0, is_stopped = 1)
# Step 2:=> Set status
- webnotes.conn.set(self.doc,'status',cstr(status))
+ webnotes.conn.set(self.doc, 'status', cstr(status))
# Step 3:=> Acknowledge User
- msgprint(self.doc.doctype + ": " + self.doc.name + " has been %s." % ((status == 'Submitted') and 'Unstopped' or cstr(status)) )
+ msgprint(self.doc.doctype + ": " + self.doc.name + " has been %s." % ((status == 'Submitted') and 'Unstopped' or cstr(status)))
def on_cancel(self):
@@ -177,9 +183,9 @@
mr_doctype = webnotes.get_doctype("Material Request")
if mr_obj.doc.status in ["Stopped", "Cancelled"]:
- msgprint(_("Material Request") + ": %s, " % mr_obj.doc.name
+ webnotes.throw(_("Material Request") + ": %s, " % mr_obj.doc.name
+ _(mr_doctype.get_label("status")) + " = %s. " % _(mr_obj.doc.status)
- + _("Cannot continue."), raise_exception=webnotes.InvalidStatusError)
+ + _("Cannot continue."), exc=webnotes.InvalidStatusError)
_update_requested_qty(controller, mr_obj, mr_items)
diff --git a/erpnext/stock/doctype/material_request_item/material_request_item.txt b/erpnext/stock/doctype/material_request_item/material_request_item.txt
index 15884a3..e0b9330 100644
--- a/erpnext/stock/doctype/material_request_item/material_request_item.txt
+++ b/erpnext/stock/doctype/material_request_item/material_request_item.txt
@@ -2,7 +2,7 @@
{
"creation": "2013-02-22 01:28:02",
"docstatus": 0,
- "modified": "2013-11-03 20:36:45",
+ "modified": "2013-12-18 14:52:02",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -219,7 +219,7 @@
"fieldname": "sales_order_no",
"fieldtype": "Link",
"label": "Sales Order No",
- "no_copy": 1,
+ "no_copy": 0,
"options": "Sales Order",
"print_hide": 1,
"read_only": 1
diff --git a/erpnext/stock/doctype/packed_item/packed_item.py b/erpnext/stock/doctype/packed_item/packed_item.py
index a58444d..ba3cb30 100644
--- a/erpnext/stock/doctype/packed_item/packed_item.py
+++ b/erpnext/stock/doctype/packed_item/packed_item.py
@@ -56,9 +56,6 @@
pi.batch_no = cstr(line.batch_no)
pi.idx = packing_list_idx
- # saved, since this function is called on_update of delivery note
- pi.save()
-
packing_list_idx += 1
@@ -87,19 +84,13 @@
for d in obj.doclist.get({"parentfield": "packing_details"}):
if [d.parent_item, d.parent_detail_docname] not in parent_items:
# mark for deletion from doclist
- delete_list.append(d.name)
+ delete_list.append([d.parent_item, d.parent_detail_docname])
if not delete_list:
return obj.doclist
# delete from doclist
- obj.doclist = webnotes.doclist(filter(lambda d: d.name not in delete_list, obj.doclist))
-
- # delete from db
- webnotes.conn.sql("""\
- delete from `tabPacked Item`
- where name in (%s)"""
- % (", ".join(["%s"] * len(delete_list))),
- tuple(delete_list))
+ obj.doclist = webnotes.doclist(filter(lambda d: [d.parent_item, d.parent_detail_docname]
+ not in delete_list, obj.doclist))
return obj.doclist
\ No newline at end of file
diff --git a/erpnext/stock/doctype/price_list/price_list.py b/erpnext/stock/doctype/price_list/price_list.py
index 226b9da..d0e5d2b 100644
--- a/erpnext/stock/doctype/price_list/price_list.py
+++ b/erpnext/stock/doctype/price_list/price_list.py
@@ -44,5 +44,5 @@
def update_item_price(self):
webnotes.conn.sql("""update `tabItem Price` set currency=%s,
- buying_or_selling=%s where price_list=%s""",
+ buying_or_selling=%s, modified=NOW() where price_list=%s""",
(self.doc.currency, self.doc.buying_or_selling, self.doc.name))
\ No newline at end of file
diff --git a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.txt b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.txt
index 22ded6d..9a641c2 100755
--- a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.txt
+++ b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.txt
@@ -2,7 +2,7 @@
{
"creation": "2013-05-24 19:29:10",
"docstatus": 0,
- "modified": "2013-11-02 19:41:45",
+ "modified": "2013-12-18 10:38:39",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -326,7 +326,7 @@
"fieldname": "schedule_date",
"fieldtype": "Date",
"label": "Required By",
- "no_copy": 1,
+ "no_copy": 0,
"oldfieldname": "schedule_date",
"oldfieldtype": "Date",
"print_hide": 1,
diff --git a/erpnext/stock/doctype/serial_no/serial_no.py b/erpnext/stock/doctype/serial_no/serial_no.py
index 1690cad..9c1da65 100644
--- a/erpnext/stock/doctype/serial_no/serial_no.py
+++ b/erpnext/stock/doctype/serial_no/serial_no.py
@@ -150,7 +150,7 @@
where serial_no like %s and item_code=%s and ifnull(is_cancelled, 'No')='No'
order by posting_date desc, posting_time desc, name desc""",
("%%%s%%" % self.doc.name, self.doc.item_code), as_dict=1):
- if self.doc.name in get_serial_nos(sle.serial_no):
+ if self.doc.name.upper() in get_serial_nos(sle.serial_no):
if sle.actual_qty > 0:
sle_dict.setdefault("incoming", []).append(sle)
else:
@@ -268,7 +268,8 @@
from tabItem where name=%s""", item_code, as_dict=True)[0]
def get_serial_nos(serial_no):
- return [s.strip() for s in cstr(serial_no).strip().replace(',', '\n').split('\n') if s.strip()]
+ return [s.strip() for s in cstr(serial_no).strip().upper().replace(',', '\n').split('\n')
+ if s.strip()]
def make_serial_no(serial_no, sle):
sr = webnotes.new_bean("Serial No")
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js
index 1596039..ec46685 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.js
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.js
@@ -243,7 +243,7 @@
cur_frm.cscript.toggle_related_fields = function(doc) {
disable_from_warehouse = inList(["Material Receipt", "Sales Return"], doc.purpose);
- disable_to_warehouse = inList(["Material Issue", "Purchase Return"], doc.purpose)
+ disable_to_warehouse = inList(["Material Issue", "Purchase Return"], doc.purpose);
cur_frm.toggle_enable("from_warehouse", !disable_from_warehouse);
cur_frm.toggle_enable("to_warehouse", !disable_to_warehouse);
@@ -301,7 +301,7 @@
}
cur_frm.cscript.purpose = function(doc, cdt, cdn) {
- cur_frm.cscript.toggle_related_fields(doc, cdt, cdn);
+ cur_frm.cscript.toggle_related_fields(doc);
}
// Overloaded query for link batch_no
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index 6001220..3ba0deb 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -285,9 +285,15 @@
# validate quantity <= ref item's qty - qty already returned
ref_item = ref.doclist.getone({"item_code": item.item_code})
returnable_qty = ref_item.qty - flt(already_returned_item_qty.get(item.item_code))
- self.validate_value("transfer_qty", "<=", returnable_qty, item,
- raise_exception=StockOverReturnError)
-
+ if not returnable_qty:
+ webnotes.throw("{item}: {item_code} {returned}".format(
+ item=_("Item"), item_code=item.item_code,
+ returned=_("already returned though some other documents")))
+ elif item.transfer_qty > returnable_qty:
+ webnotes.throw("{item}: {item_code}, {returned}: {qty}".format(
+ item=_("Item"), item_code=item.item_code,
+ returned=_("Max Returnable Qty"), qty=returnable_qty))
+
def get_already_returned_item_qty(self, ref_fieldname):
return dict(webnotes.conn.sql("""select item_code, sum(transfer_qty) as qty
from `tabStock Entry Detail` where parent in (
diff --git a/erpnext/stock/doctype/warehouse/warehouse.py b/erpnext/stock/doctype/warehouse/warehouse.py
index 2b7473c..7729b2e 100644
--- a/erpnext/stock/doctype/warehouse/warehouse.py
+++ b/erpnext/stock/doctype/warehouse/warehouse.py
@@ -20,6 +20,19 @@
if self.doc.email_id and not validate_email_add(self.doc.email_id):
msgprint("Please enter valid Email Id", raise_exception=1)
+ self.update_parent_account()
+
+ def update_parent_account(self):
+ if not self.doc.__islocal and (self.doc.create_account_under !=
+ webnotes.conn.get_value("Warehouse", self.doc.name, "create_account_under")):
+ warehouse_account = webnotes.conn.get_value("Account",
+ {"account_type": "Warehouse", "company": self.doc.company,
+ "master_name": self.doc.name}, ["name", "parent_account"])
+ if warehouse_account and warehouse_account[1] != self.doc.create_account_under:
+ acc_bean = webnotes.bean("Account", warehouse_account[0])
+ acc_bean.doc.parent_account = self.doc.create_account_under
+ acc_bean.save()
+
def on_update(self):
self.create_account_head()
@@ -84,6 +97,9 @@
new_warehouse = get_name_with_abbr(newdn, self.doc.company)
if merge:
+ if not webnotes.conn.exists("Warehouse", newdn):
+ webnotes.throw(_("Warehouse ") + newdn +_(" does not exists"))
+
if self.doc.company != webnotes.conn.get_value("Warehouse", new_warehouse, "company"):
webnotes.throw(_("Both Warehouse must belong to same Company"))
diff --git a/erpnext/stock/page/stock_home/stock_home.js b/erpnext/stock/page/stock_home/stock_home.js
index 4be5a46..3b6fd4c 100644
--- a/erpnext/stock/page/stock_home/stock_home.js
+++ b/erpnext/stock/page/stock_home/stock_home.js
@@ -138,7 +138,7 @@
items: [
{
"label":wn._("Stock Ledger"),
- doctype: "Delivery Note",
+ doctype: "Item",
route: "query-report/Stock Ledger"
},
{
@@ -146,12 +146,14 @@
page: "stock-balance"
},
{
- "page":"stock-level",
- "label": wn._("Stock Level")
+ "label":wn._("Stock Projected Qty"),
+ doctype: "Item",
+ route: "query-report/Stock Projected Qty"
},
{
- "page":"stock-ageing",
- "label": wn._("Stock Ageing")
+ "label":wn._("Stock Ageing"),
+ doctype: "Item",
+ route: "query-report/Stock Ageing"
},
]
},
diff --git a/erpnext/stock/report/item_prices/item_prices.py b/erpnext/stock/report/item_prices/item_prices.py
index 9a25c13..da8b500 100644
--- a/erpnext/stock/report/item_prices/item_prices.py
+++ b/erpnext/stock/report/item_prices/item_prices.py
@@ -15,8 +15,8 @@
bom_rate = get_item_bom_rate()
val_rate_map = get_valuation_rate()
- precision = webnotes.conn.get_value("Global Defaults", None, "float_precision") or 2
-
+ precision = get_currency_precision or 2
+
data = []
for item in sorted(item_map):
data.append([item, item_map[item]["item_name"],
@@ -30,6 +30,14 @@
])
return columns, data
+
+def get_currency_precision():
+ company_currency = webnotes.conn.get_value("Company",
+ webnotes.conn.get_default("company"), "default_currency")
+ currency_format = webnotes.conn.get_value("Currency", company_currency, "number_format")
+
+ from webnotes.utils import get_number_format_info
+ return get_number_format_info(currency_format)[2]
def get_columns(filters):
"""return columns based on filters"""
diff --git a/erpnext/stock/report/stock_ledger/stock_ledger.py b/erpnext/stock/report/stock_ledger/stock_ledger.py
index ea1a60f..38308c2 100644
--- a/erpnext/stock/report/stock_ledger/stock_ledger.py
+++ b/erpnext/stock/report/stock_ledger/stock_ledger.py
@@ -3,7 +3,6 @@
from __future__ import unicode_literals
import webnotes
-from webnotes import _
def execute(filters=None):
columns = get_columns()
@@ -13,10 +12,14 @@
data = []
for sle in sl_entries:
item_detail = item_details[sle.item_code]
+ voucher_link_icon = """<a href="%s"><i class="icon icon-share"
+ style="cursor: pointer;"></i></a>""" \
+ % ("/".join(["#Form", sle.voucher_type, sle.voucher_no]),)
+
data.append([sle.date, sle.item_code, item_detail.item_name, item_detail.item_group,
item_detail.brand, item_detail.description, sle.warehouse, item_detail.stock_uom,
sle.actual_qty, sle.qty_after_transaction, sle.stock_value, sle.voucher_type,
- sle.voucher_no, sle.batch_no, sle.serial_no, sle.company])
+ sle.voucher_no, voucher_link_icon, sle.batch_no, sle.serial_no, sle.company])
return columns, data
@@ -25,17 +28,10 @@
"Item Group:Link/Item Group:100", "Brand:Link/Brand:100",
"Description::200", "Warehouse:Link/Warehouse:100",
"Stock UOM:Link/UOM:100", "Qty:Float:50", "Balance Qty:Float:80",
- "Balance Value:Currency:100", "Voucher Type::100", "Voucher #::100",
+ "Balance Value:Currency:100", "Voucher Type::100", "Voucher #::100", "Link::30",
"Batch:Link/Batch:100", "Serial #:Link/Serial No:100", "Company:Link/Company:100"]
def get_stock_ledger_entries(filters):
- if not filters.get("company"):
- webnotes.throw(_("Company is mandatory"))
- if not filters.get("from_date"):
- webnotes.throw(_("From Date is mandatory"))
- if not filters.get("to_date"):
- webnotes.throw(_("To Date is mandatory"))
-
return webnotes.conn.sql("""select concat_ws(" ", posting_date, posting_time) as date,
item_code, warehouse, actual_qty, qty_after_transaction,
stock_value, voucher_type, voucher_no, batch_no, serial_no, company
@@ -66,6 +62,10 @@
def get_sle_conditions(filters):
conditions = []
+ item_conditions=get_item_conditions(filters)
+ if item_conditions:
+ conditions.append("""item_code in (select name from tabItem
+ {item_conditions})""".format(item_conditions=item_conditions))
if filters.get("warehouse"):
conditions.append("warehouse=%(warehouse)s")
if filters.get("voucher_no"):
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index e6a402c..860bb76 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -113,7 +113,14 @@
(qty_after_transaction * valuation_rate) or 0
else:
stock_value = sum((flt(batch[0]) * flt(batch[1]) for batch in stock_queue))
-
+
+ # rounding as per precision
+ from webnotes.model.meta import get_field_precision
+ meta = webnotes.get_doctype("Stock Ledger Entry")
+
+ stock_value = flt(stock_value, get_field_precision(meta.get_field("stock_value"),
+ webnotes._dict({"fields": sle})))
+
stock_value_difference = stock_value - prev_stock_value
prev_stock_value = stock_value
diff --git a/erpnext/support/doctype/support_ticket/support_ticket.txt b/erpnext/support/doctype/support_ticket/support_ticket.txt
index 684c809..4fa4874 100644
--- a/erpnext/support/doctype/support_ticket/support_ticket.txt
+++ b/erpnext/support/doctype/support_ticket/support_ticket.txt
@@ -2,7 +2,7 @@
{
"creation": "2013-02-01 10:36:25",
"docstatus": 0,
- "modified": "2013-11-02 14:06:26",
+ "modified": "2013-12-14 17:27:02",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -278,6 +278,7 @@
{
"cancel": 0,
"doctype": "DocPerm",
+ "match": "customer",
"role": "Customer"
},
{
diff --git a/erpnext/utilities/doctype/address/address.txt b/erpnext/utilities/doctype/address/address.txt
index 09be67e..5b4ada9 100644
--- a/erpnext/utilities/doctype/address/address.txt
+++ b/erpnext/utilities/doctype/address/address.txt
@@ -2,11 +2,12 @@
{
"creation": "2013-01-10 16:34:32",
"docstatus": 0,
- "modified": "2013-07-11 17:02:12",
+ "modified": "2013-12-12 12:17:46",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
+ "allow_rename": 1,
"doctype": "DocType",
"document_type": "Master",
"icon": "icon-map-marker",
diff --git a/erpnext/utilities/doctype/contact/contact.txt b/erpnext/utilities/doctype/contact/contact.txt
index 199aaea..1c8a5cf 100644
--- a/erpnext/utilities/doctype/contact/contact.txt
+++ b/erpnext/utilities/doctype/contact/contact.txt
@@ -2,11 +2,12 @@
{
"creation": "2013-01-10 16:34:32",
"docstatus": 0,
- "modified": "2013-10-08 16:48:50",
+ "modified": "2013-12-12 12:18:19",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
+ "allow_rename": 1,
"doctype": "DocType",
"document_type": "Master",
"icon": "icon-user",