Merge with 3.3.8

This commit is contained in:
Rushabh Mehta 2013-12-26 11:07:46 +05:30
commit 54047780fc
77 changed files with 700 additions and 895 deletions

View File

@ -95,9 +95,10 @@ cur_frm.cscript.add_toolbar_buttons = function(doc) {
wn.route_options = { wn.route_options = {
"account": doc.name, "account": doc.name,
"from_date": sys_defaults.year_start_date, "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"); }, "icon-table");
} }
} }

View File

@ -211,6 +211,9 @@ class DocType:
# Validate properties before merging # Validate properties before merging
if merge: 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, val = list(webnotes.conn.get_value("Account", new_account,
["group_or_ledger", "debit_or_credit", "is_pl_account"])) ["group_or_ledger", "debit_or_credit", "is_pl_account"]))

View File

@ -5,8 +5,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import webnotes import webnotes
from webnotes.utils import cint, cstr from webnotes import _
from webnotes import msgprint, _
class DocType: class DocType:
def __init__(self, d, dl): def __init__(self, d, dl):
@ -16,6 +15,11 @@ class DocType:
webnotes.conn.set_default("auto_accounting_for_stock", self.doc.auto_accounting_for_stock) webnotes.conn.set_default("auto_accounting_for_stock", self.doc.auto_accounting_for_stock)
if self.doc.auto_accounting_for_stock: if self.doc.auto_accounting_for_stock:
for wh in webnotes.conn.sql("select name from `tabWarehouse`"): warehouse_list = webnotes.conn.sql("select name, company from tabWarehouse", as_dict=1)
wh_bean = webnotes.bean("Warehouse", wh[0]) 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() wh_bean.save()

View File

@ -5,8 +5,7 @@ from __future__ import unicode_literals
import webnotes import webnotes
from webnotes.utils import flt, fmt_money, getdate from webnotes.utils import flt, fmt_money, getdate
from webnotes.model.code import get_obj from webnotes import _
from webnotes import msgprint, _
class DocType: class DocType:
def __init__(self,d,dl): def __init__(self,d,dl):
@ -130,7 +129,8 @@ def update_outstanding_amt(account, against_voucher_type, against_voucher, on_ca
against_voucher_amount = flt(webnotes.conn.sql(""" against_voucher_amount = flt(webnotes.conn.sql("""
select sum(ifnull(debit, 0)) - sum(ifnull(credit, 0)) select sum(ifnull(debit, 0)) - sum(ifnull(credit, 0))
from `tabGL Entry` where voucher_type = 'Journal Voucher' and voucher_no = %s 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 bal = against_voucher_amount + bal
if against_voucher_amount < 0: if against_voucher_amount < 0:
bal = -bal bal = -bal

View File

@ -120,8 +120,9 @@ cur_frm.cscript.refresh = function(doc) {
"voucher_no": doc.name, "voucher_no": doc.name,
"from_date": doc.posting_date, "from_date": doc.posting_date,
"to_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"); }, "icon-table");
} }
} }

View File

@ -145,6 +145,8 @@ def gl_entry_details(doctype, txt, searchfield, start, page_len, filters):
and voucher_no != gle.voucher_no) and voucher_no != gle.voucher_no)
!= abs(ifnull(gle.debit, 0) - ifnull(gle.credit, 0) != 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 %(mcond)s
ORDER BY gle.posting_date desc, gle.voucher_no desc ORDER BY gle.posting_date desc, gle.voucher_no desc
limit %(start)s, %(page_len)s""" % { limit %(start)s, %(page_len)s""" % {

View File

@ -35,8 +35,9 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
"voucher_no": doc.name, "voucher_no": doc.name,
"from_date": doc.posting_date, "from_date": doc.posting_date,
"to_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"); }, "icon-table");
} }

View File

@ -350,7 +350,7 @@ class DocType(BuyingController):
# item gl entries # item gl entries
stock_item_and_auto_accounting_for_stock = False stock_item_and_auto_accounting_for_stock = False
stock_items = self.get_stock_items() stock_items = self.get_stock_items()
rounding_diff = 0.0 # rounding_diff = 0.0
for item in self.doclist.get({"parentfield": "entries"}): for item in self.doclist.get({"parentfield": "entries"}):
if auto_accounting_for_stock and item.item_code in stock_items: if auto_accounting_for_stock and item.item_code in stock_items:
if flt(item.valuation_rate): if flt(item.valuation_rate):
@ -359,13 +359,12 @@ class DocType(BuyingController):
# expense will be booked in sales invoice # expense will be booked in sales invoice
stock_item_and_auto_accounting_for_stock = True stock_item_and_auto_accounting_for_stock = True
valuation_amt = flt(flt(item.valuation_rate) * flt(item.qty) * \ valuation_amt = item.amount + item.item_tax_amount + item.rm_supp_cost
flt(item.conversion_factor), self.precision("valuation_rate", item))
rounding_diff += (flt(item.amount, self.precision("amount", item)) + # rounding_diff += (flt(item.amount, self.precision("amount", item)) +
flt(item.item_tax_amount, self.precision("item_tax_amount", item)) + # flt(item.item_tax_amount, self.precision("item_tax_amount", item)) +
flt(item.rm_supp_cost, self.precision("rm_supp_cost", item)) - # flt(item.rm_supp_cost, self.precision("rm_supp_cost", item)) -
valuation_amt) # valuation_amt)
gl_entries.append( gl_entries.append(
self.get_gl_dict({ self.get_gl_dict({
@ -394,11 +393,11 @@ class DocType(BuyingController):
expenses_included_in_valuation = \ expenses_included_in_valuation = \
self.get_company_default("expenses_included_in_valuation") self.get_company_default("expenses_included_in_valuation")
if rounding_diff: # if rounding_diff:
import operator # import operator
cost_center_with_max_value = max(valuation_tax.iteritems(), # cost_center_with_max_value = max(valuation_tax.iteritems(),
key=operator.itemgetter(1))[0] # key=operator.itemgetter(1))[0]
valuation_tax[cost_center_with_max_value] -= flt(rounding_diff) # valuation_tax[cost_center_with_max_value] -= flt(rounding_diff)
for cost_center, amount in valuation_tax.items(): for cost_center, amount in valuation_tax.items():
gl_entries.append( gl_entries.append(

View File

@ -54,8 +54,9 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
"voucher_no": doc.name, "voucher_no": doc.name,
"from_date": doc.posting_date, "from_date": doc.posting_date,
"to_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"); }, "icon-table");
var percent_paid = cint(flt(doc.grand_total - doc.outstanding_amount) / flt(doc.grand_total) * 100); var percent_paid = cint(flt(doc.grand_total - doc.outstanding_amount) / flt(doc.grand_total) * 100);

View File

@ -399,9 +399,10 @@ class DocType(SellingController):
if not self.doc.cash_bank_account and flt(self.doc.paid_amount): 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") msgprint("Cash/Bank Account is mandatory for POS, for making payment entry")
raise Exception raise Exception
if (flt(self.doc.paid_amount) + flt(self.doc.write_off_amount) - round(flt(self.doc.grand_total), 2))>0.001: if flt(self.doc.paid_amount) + flt(self.doc.write_off_amount) \
msgprint("(Paid amount + Write Off Amount) can not be greater than Grand Total") - flt(self.doc.grand_total) > 1/(10**(self.precision("grand_total") + 1)):
raise Exception webnotes.throw(_("""(Paid amount + Write Off Amount) can not be \
greater than Grand Total"""))
def validate_item_code(self): def validate_item_code(self):

View File

@ -2,7 +2,7 @@
{ {
"creation": "2013-04-24 11:39:32", "creation": "2013-04-24 11:39:32",
"docstatus": 0, "docstatus": 0,
"modified": "2013-07-10 14:54:21", "modified": "2013-12-17 12:38:08",
"modified_by": "Administrator", "modified_by": "Administrator",
"owner": "Administrator" "owner": "Administrator"
}, },
@ -37,11 +37,20 @@
"options": "\nActual\nOn Net Total\nOn Previous Row Amount\nOn Previous Row Total", "options": "\nActual\nOn Net Total\nOn Previous Row Amount\nOn Previous Row Total",
"reqd": 1 "reqd": 1
}, },
{
"doctype": "DocField",
"fieldname": "row_id",
"fieldtype": "Data",
"hidden": 0,
"label": "Enter Row",
"oldfieldname": "row_id",
"oldfieldtype": "Data"
},
{ {
"doctype": "DocField", "doctype": "DocField",
"fieldname": "account_head", "fieldname": "account_head",
"fieldtype": "Link", "fieldtype": "Link",
"in_list_view": 1, "in_list_view": 0,
"label": "Account Head", "label": "Account Head",
"oldfieldname": "account_head", "oldfieldname": "account_head",
"oldfieldtype": "Link", "oldfieldtype": "Link",
@ -54,7 +63,7 @@
"doctype": "DocField", "doctype": "DocField",
"fieldname": "cost_center", "fieldname": "cost_center",
"fieldtype": "Link", "fieldtype": "Link",
"in_list_view": 1, "in_list_view": 0,
"label": "Cost Center", "label": "Cost Center",
"oldfieldname": "cost_center_other_charges", "oldfieldname": "cost_center_other_charges",
"oldfieldtype": "Link", "oldfieldtype": "Link",
@ -72,6 +81,24 @@
"reqd": 1, "reqd": 1,
"width": "300px" "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", "doctype": "DocField",
"fieldname": "rate", "fieldname": "rate",
@ -80,7 +107,7 @@
"label": "Rate", "label": "Rate",
"oldfieldname": "rate", "oldfieldname": "rate",
"oldfieldtype": "Currency", "oldfieldtype": "Currency",
"reqd": 0 "reqd": 1
}, },
{ {
"doctype": "DocField", "doctype": "DocField",
@ -104,15 +131,6 @@
"options": "Company:company:default_currency", "options": "Company:company:default_currency",
"read_only": 1 "read_only": 1
}, },
{
"doctype": "DocField",
"fieldname": "row_id",
"fieldtype": "Data",
"hidden": 0,
"label": "Enter Row",
"oldfieldname": "row_id",
"oldfieldtype": "Data"
},
{ {
"doctype": "DocField", "doctype": "DocField",
"fieldname": "item_wise_tax_detail", "fieldname": "item_wise_tax_detail",
@ -134,18 +152,5 @@
"oldfieldtype": "Data", "oldfieldtype": "Data",
"print_hide": 1, "print_hide": 1,
"search_index": 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"
} }
] ]

View File

@ -24,10 +24,6 @@ def process_gl_map(gl_map, merge_entries=True):
gl_map = merge_similar_entries(gl_map) gl_map = merge_similar_entries(gl_map)
for entry in 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 # toggle debit, credit if negative entry
if flt(entry.debit) < 0: if flt(entry.debit) < 0:
entry.credit = flt(entry.credit) - flt(entry.debit) entry.credit = flt(entry.credit) - flt(entry.debit)

View File

@ -175,9 +175,10 @@ erpnext.AccountsChart = Class.extend({
wn.route_options = { wn.route_options = {
"account": node.data('label'), "account": node.data('label'),
"from_date": sys_defaults.year_start_date, "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() { rename: function() {
var node = this.selected_node(); var node = this.selected_node();

View File

@ -157,7 +157,8 @@ wn.module_page["Accounts"] = [
items: [ items: [
{ {
"label":wn._("General Ledger"), "label":wn._("General Ledger"),
page: "general-ledger" doctype: "GL Entry",
route: "query-report/General Ledger"
}, },
{ {
"label":wn._("Trial Balance"), "label":wn._("Trial Balance"),

View File

@ -1 +0,0 @@
General Ledger report (for all transactions and accounts).

View File

@ -1 +0,0 @@
from __future__ import unicode_literals

View File

@ -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 } }
}
},
});

View File

@ -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"
}
]

View File

@ -85,7 +85,7 @@ class AccountsReceivableReport(object):
def get_account_map(self): def get_account_map(self):
if not hasattr(self, "account_map"): if not hasattr(self, "account_map"):
self.account_map = dict(((r.name, r) for r in webnotes.conn.sql("""select 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 from `tabAccount` account, `tabCustomer` customer
where account.master_type="Customer" where account.master_type="Customer"
and customer.name=account.master_name""", as_dict=True))) and customer.name=account.master_name""", as_dict=True)))

View File

@ -16,7 +16,7 @@ class BudgetError(webnotes.ValidationError): pass
def get_fiscal_year(date=None, fiscal_year=None, label="Date", verbose=1): 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): 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) # if year start date is 2012-04-01, year end date should be 2013-03-31 (hence subdate)

View File

@ -9,9 +9,8 @@ from webnotes.model.utils import getlist
from webnotes import msgprint, _ from webnotes import msgprint, _
from erpnext.buying.utils import get_last_purchase_details from erpnext.buying.utils import get_last_purchase_details
from erpnext.controllers.buying_controller import BuyingController from erpnext.controllers.buying_controller import BuyingController
class DocType(BuyingController): class DocType(BuyingController):
def __init__(self, doc, doclist=None): def __init__(self, doc, doclist=None):
self.doc = doc self.doc = doc
@ -38,12 +37,12 @@ class DocType(BuyingController):
if flt(d.conversion_factor): if flt(d.conversion_factor):
last_purchase_rate = flt(d.purchase_rate) / flt(d.conversion_factor) last_purchase_rate = flt(d.purchase_rate) / flt(d.conversion_factor)
else: else:
msgprint(_("Row ") + cstr(d.idx) + ": " + webnotes.throw(_("Row ") + cstr(d.idx) + ": " +
_("UOM Conversion Factor is mandatory"), raise_exception=1) _("UOM Conversion Factor is mandatory"))
# update last purchsae rate # update last purchsae rate
if last_purchase_rate: if last_purchase_rate:
webnotes.conn.sql("update `tabItem` set last_purchase_rate = %s where name = %s", webnotes.conn.sql("""update `tabItem` set last_purchase_rate = %s where name = %s""",
(flt(last_purchase_rate), d.item_code)) (flt(last_purchase_rate), d.item_code))
def get_last_purchase_rate(self, obj): def get_last_purchase_rate(self, obj):
@ -76,11 +75,11 @@ class DocType(BuyingController):
for d in getlist( obj.doclist, obj.fname): for d in getlist( obj.doclist, obj.fname):
# validation for valid qty # validation for valid qty
if flt(d.qty) < 0 or (d.parenttype != 'Purchase Receipt' and not flt(d.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)) webnotes.throw("Please enter valid qty for item %s" % cstr(d.item_code))
raise Exception
# udpate with latest quantities # 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} 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': if d.doctype == 'Purchase Receipt Item':
@ -89,44 +88,46 @@ class DocType(BuyingController):
if d.fields.has_key(x): if d.fields.has_key(x):
d.fields[x] = f_lst[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", item = webnotes.conn.sql("""select is_stock_item, is_purchase_item,
d.item_code) is_sub_contracted_item, end_of_life from `tabItem` where name=%s""", d.item_code)
if not item: 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 from erpnext.stock.utils import validate_end_of_life
validate_end_of_life(d.item_code, item[0][3]) validate_end_of_life(d.item_code, item[0][3])
# validate stock item # validate stock item
if item[0][0]=='Yes' and d.qty and not d.warehouse: if item[0][0]=='Yes' and d.qty and not d.warehouse:
msgprint("Warehouse is mandatory for %s, since it is a stock item" % webnotes.throw("Warehouse is mandatory for %s, since it is a stock item" % d.item_code)
d.item_code, raise_exception=1)
# validate purchase item # validate purchase item
if item[0][1] != 'Yes' and item[0][2] != 'Yes': 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 # 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 # if is not stock item
f = [d.schedule_date, d.item_code, d.description] 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': if ch and ch[0][0] == 'Yes':
# check for same items # check for same items
if e in check_list: if e in check_list:
msgprint("""Item %s has been entered more than once with same description, schedule date, warehouse and uom.\n 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, raise_exception = 1) Please change any of the field value to enter the item twice""" % d.item_code)
else: else:
check_list.append(e) check_list.append(e)
elif ch and ch[0][0] == 'No': elif ch and ch[0][0] == 'No':
# check for same items # check for same items
if f in chk_dupl_itm: if f in chk_dupl_itm:
msgprint("""Item %s has been entered more than once with same description, schedule date.\n 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, raise_exception = 1) Please change any of the field value to enter the item twice.""" % d.item_code)
else: else:
chk_dupl_itm.append(f) chk_dupl_itm.append(f)
@ -138,22 +139,25 @@ class DocType(BuyingController):
# but if in Material Request uom KG it can change in PO # 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' 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 qty = qty and flt(qty[0][0]) or 0
# get total qty of ref doctype # 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 max_qty = max_qty and flt(max_qty[0][0]) or 0
return cstr(qty)+'~~~'+cstr(max_qty) return cstr(qty)+'~~~'+cstr(max_qty)
def check_for_stopped_status(self, doctype, docname): def check_for_stopped_status(self, doctype, docname):
stopped = webnotes.conn.sql("select name from `tab%s` where name = '%s' and status = 'Stopped'" % stopped = webnotes.conn.sql("""select name from `tab%s` where name = %s and
( doctype, docname)) status = 'Stopped'""" % (doctype, '%s'), docname)
if stopped: if stopped:
msgprint("One cannot do any transaction against %s : %s, it's status is 'Stopped'" % webnotes.throw("One cannot do any transaction against %s : %s, it's status is 'Stopped'" %
( doctype, docname), raise_exception=1) (doctype, docname))
def check_docstatus(self, check, doctype, docname, detail_doctype = ''): def check_docstatus(self, check, doctype, docname, detail_doctype = ''):
if check == 'Next': if check == 'Next':
@ -161,12 +165,11 @@ class DocType(BuyingController):
where t1.name = t2.parent and t2.prevdoc_docname = %s and t1.docstatus = 1""" where t1.name = t2.parent and t2.prevdoc_docname = %s and t1.docstatus = 1"""
% (doctype, detail_doctype, '%s'), docname) % (doctype, detail_doctype, '%s'), docname)
if submitted: if submitted:
msgprint(cstr(doctype) + ": " + cstr(submitted[0][0]) webnotes.throw(cstr(doctype) + ": " + cstr(submitted[0][0])
+ _(" has already been submitted."), raise_exception=1) + _("has already been submitted."))
if check == 'Previous': if check == 'Previous':
submitted = webnotes.conn.sql("""select name from `tab%s` 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: if not submitted:
msgprint(cstr(doctype) + ": " + cstr(submitted[0][0]) webnotes.throw(cstr(doctype) + ": " + cstr(submitted[0][0]) + _("not submitted"))
+ _(" not submitted"), raise_exception=1)

View File

@ -27,6 +27,14 @@ class DocType(TransactionBase):
else: else:
self.doc.name = make_autoname(self.doc.naming_series + '.#####') 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): def update_credit_days_limit(self):
webnotes.conn.sql("""update tabAccount set credit_days = %s where name = %s""", webnotes.conn.sql("""update tabAccount set credit_days = %s where name = %s""",
(cint(self.doc.credit_days), self.doc.name + " - " + self.get_company_abbr())) (cint(self.doc.credit_days), self.doc.name + " - " + self.get_company_abbr()))
@ -35,6 +43,9 @@ class DocType(TransactionBase):
if not self.doc.naming_series: if not self.doc.naming_series:
self.doc.naming_series = '' self.doc.naming_series = ''
self.update_address()
self.update_contact()
# create account head # create account head
self.create_account_head() self.create_account_head()
@ -153,8 +164,17 @@ class DocType(TransactionBase):
rename_account_for("Supplier", olddn, newdn, merge) rename_account_for("Supplier", olddn, newdn, merge)
def after_rename(self, olddn, newdn, merge=False): def after_rename(self, olddn, newdn, merge=False):
set_field = ''
if webnotes.defaults.get_global_default('supp_master_name') == 'Supplier Name': if webnotes.defaults.get_global_default('supp_master_name') == 'Supplier Name':
webnotes.conn.set(self.doc, "supplier_name", newdn) 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() @webnotes.whitelist()
def get_dashboard_info(supplier): def get_dashboard_info(supplier):

View File

@ -2,7 +2,7 @@
{ {
"creation": "2013-05-21 16:16:45", "creation": "2013-05-21 16:16:45",
"docstatus": 0, "docstatus": 0,
"modified": "2013-11-22 17:16:16", "modified": "2013-12-14 17:27:47",
"modified_by": "Administrator", "modified_by": "Administrator",
"owner": "Administrator" "owner": "Administrator"
}, },
@ -632,6 +632,7 @@
"cancel": 0, "cancel": 0,
"create": 0, "create": 0,
"doctype": "DocPerm", "doctype": "DocPerm",
"match": "supplier",
"role": "Supplier", "role": "Supplier",
"submit": 0, "submit": 0,
"write": 0 "write": 0

View File

@ -108,9 +108,10 @@ class BuyingController(StockController):
self.precision("import_amount", item)) self.precision("import_amount", item))
item.item_tax_amount = 0.0; 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_ref_rate", "purchase_ref_rate")
self._set_in_company_currency(item, "import_rate", "rate") self._set_in_company_currency(item, "import_rate", "rate")
self._set_in_company_currency(item, "import_amount", "amount")
def calculate_net_total(self): def calculate_net_total(self):
self.doc.net_total = self.doc.net_total_import = 0.0 self.doc.net_total = self.doc.net_total_import = 0.0
@ -183,13 +184,11 @@ class BuyingController(StockController):
if item.item_code and item.qty: if item.item_code and item.qty:
self.round_floats_in(item) 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, # if no item code, which is sometimes the case in purchase invoice,
# then it is not possible to track valuation against it # then it is not possible to track valuation against it
item.valuation_rate = flt((purchase_rate + qty_in_stock_uom = flt(item.qty * item.conversion_factor)
(item.item_tax_amount + item.rm_supp_cost) / item.qty) / item.conversion_factor, item.valuation_rate = ((item.amount + item.item_tax_amount + item.rm_supp_cost)
self.precision("valuation_rate", item)) / qty_in_stock_uom)
else: else:
item.valuation_rate = 0.0 item.valuation_rate = 0.0

View File

@ -205,8 +205,8 @@ class SellingController(StockController):
self.round_floats_in(self.doc, ["grand_total", "total_advance", "write_off_amount", self.round_floats_in(self.doc, ["grand_total", "total_advance", "write_off_amount",
"paid_amount"]) "paid_amount"])
total_amount_to_pay = self.doc.grand_total - self.doc.write_off_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.doc.outstanding_amount = flt(total_amount_to_pay - self.doc.total_advance \
self.precision("outstanding_amount")) - self.doc.paid_amount, self.precision("outstanding_amount"))
def calculate_commission(self): def calculate_commission(self):
if self.meta.get_field("commission_rate"): if self.meta.get_field("commission_rate"):

View File

@ -52,13 +52,12 @@ scheduler_event all:webnotes.utils.email_lib.bulk.flush
#### Daily #### Daily
scheduler_event daily:webnotes.core.doctype.event.event.send_event_digest 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.core.doctype.notification_count.notification_count.delete_event_notification_count
scheduler_event daily:webnotes.utils.email_lib.bulk.clear_outbox 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.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.setup.doctype.backup_manager.backup_manager.take_backups_daily
scheduler_event daily:erpnext.stock.utils.reorder_item 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 #### Weekly

View File

@ -2,7 +2,7 @@
{ {
"creation": "2013-02-20 19:10:38", "creation": "2013-02-20 19:10:38",
"docstatus": 0, "docstatus": 0,
"modified": "2013-07-05 14:44:19", "modified": "2013-12-12 17:41:52",
"modified_by": "Administrator", "modified_by": "Administrator",
"owner": "Administrator" "owner": "Administrator"
}, },
@ -131,10 +131,12 @@
"label": "Carry Forward" "label": "Carry Forward"
}, },
{ {
"depends_on": "carry_forward",
"doctype": "DocField", "doctype": "DocField",
"fieldname": "carry_forwarded_leaves", "fieldname": "carry_forwarded_leaves",
"fieldtype": "Float", "fieldtype": "Float",
"label": "Carry Forwarded Leaves" "label": "Carry Forwarded Leaves",
"read_only": 1
}, },
{ {
"allow_on_submit": 1, "allow_on_submit": 1,

View File

@ -12,7 +12,6 @@ class DocType:
self.doc = doc self.doc = doc
self.doclist = doclist self.doclist = doclist
def get_emp_list(self): def get_emp_list(self):
""" """
Returns list of active employees based on selected criteria Returns list of active employees based on selected criteria

View File

@ -29,18 +29,17 @@ class DocType(TransactionBase):
if struct: if struct:
self.pull_sal_struct(struct) self.pull_sal_struct(struct)
def check_sal_struct(self): 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: if not struct:
msgprint("Please create Salary Structure for employee '%s'" % self.doc.employee) msgprint("Please create Salary Structure for employee '%s'" % self.doc.employee)
self.doc.employee = '' self.doc.employee = None
return struct and struct[0][0] or '' return struct and struct[0][0] or ''
def pull_sal_struct(self, struct): def pull_sal_struct(self, struct):
from erpnext.hr.doctype.salary_structure.salary_structure import make_salary_slip from erpnext.hr.doctype.salary_structure.salary_structure import get_mapped_doclist
self.doclist = make_salary_slip(struct, self.doclist) self.doclist = get_mapped_doclist(struct, self.doclist)
def pull_emp_details(self): def pull_emp_details(self):
emp = webnotes.conn.get_value("Employee", self.doc.employee, emp = webnotes.conn.get_value("Employee", self.doc.employee,

View File

@ -73,6 +73,9 @@ class DocType:
@webnotes.whitelist() @webnotes.whitelist()
def make_salary_slip(source_name, target_doclist=None): 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 from webnotes.model.mapper import get_mapped_doclist
def postprocess(source, target): def postprocess(source, target):
@ -108,4 +111,4 @@ def make_salary_slip(source_name, target_doclist=None):
} }
}, target_doclist, postprocess) }, target_doclist, postprocess)
return [d.fields for d in doclist] return doclist

View File

@ -1,28 +1,56 @@
// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors // Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt // License: GNU General Public License v3. See license.txt
cur_frm.cscript.onload = function(doc, dt, dn) { $.extend(cur_frm.cscript, {
onload: function (doc, dt, dn) {
if (!doc.status) doc.status = 'Draft'; if (!doc.status) doc.status = 'Draft';
cfn_set_fields(doc, dt, dn); cfn_set_fields(doc, dt, dn);
}
cur_frm.cscript.refresh = function(doc, dt, dn) { this.frm.add_fetch("sales_order", "delivery_date", "expected_delivery_date");
cur_frm.dashboard.reset(); },
refresh: function(doc, dt, dn) {
this.frm.dashboard.reset();
erpnext.hide_naming_series(); erpnext.hide_naming_series();
cur_frm.set_intro(""); this.frm.set_intro("");
cfn_set_fields(doc, dt, dn); cfn_set_fields(doc, dt, dn);
if (doc.docstatus === 0 && !doc.__islocal) { if (doc.docstatus === 0 && !doc.__islocal) {
cur_frm.set_intro(wn._("Submit this Production Order for further processing.")); this.frm.set_intro(wn._("Submit this Production Order for further processing."));
} else if (doc.docstatus === 1) { } else if (doc.docstatus === 1) {
var percent = flt(doc.produced_qty) / flt(doc.qty) * 100; var percent = flt(doc.produced_qty) / flt(doc.qty) * 100;
cur_frm.dashboard.add_progress(cint(percent) + "% " + wn._("Complete"), percent); this.frm.dashboard.add_progress(cint(percent) + "% " + wn._("Complete"), percent);
if(doc.status === "Stopped") { if(doc.status === "Stopped") {
cur_frm.dashboard.set_headline_alert(wn._("Stopped"), "alert-danger", "icon-stop"); 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) { var cfn_set_fields = function(doc, dt, dn) {
if (doc.docstatus == 1) { if (doc.docstatus == 1) {
@ -38,13 +66,6 @@ var cfn_set_fields = function(doc, dt, dn) {
} }
} }
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() { cur_frm.cscript['Stop Production Order'] = function() {
var doc = cur_frm.doc; var doc = cur_frm.doc;
var check = confirm(wn._("Do you really want to stop production order: " + doc.name)); var check = confirm(wn._("Do you really want to stop production order: " + doc.name));
@ -68,20 +89,6 @@ cur_frm.cscript['Update Finished Goods'] = function() {
cur_frm.cscript.make_se('Manufacture/Repack'); 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) { cur_frm.fields_dict['production_item'].get_query = function(doc) {
return { return {
filters:[ filters:[
@ -98,7 +105,6 @@ cur_frm.fields_dict['project_name'].get_query = function(doc, dt, dn) {
} }
} }
cur_frm.set_query("bom_no", function(doc) { cur_frm.set_query("bom_no", function(doc) {
if (doc.production_item) { if (doc.production_item) {
return{ return{

View File

@ -8,7 +8,6 @@ from webnotes.utils import cstr, flt, nowdate
from webnotes.model.code import get_obj from webnotes.model.code import get_obj
from webnotes import msgprint, _ from webnotes import msgprint, _
class OverProductionError(webnotes.ValidationError): pass class OverProductionError(webnotes.ValidationError): pass
class DocType: class DocType:
@ -37,15 +36,20 @@ class DocType:
and is_active=1 and item=%s""" and is_active=1 and item=%s"""
, (self.doc.bom_no, self.doc.production_item), as_dict =1) , (self.doc.bom_no, self.doc.production_item), as_dict =1)
if not bom: if not bom:
msgprint("""Incorrect BOM: %s entered. webnotes.throw("""Incorrect BOM: %s entered.
May be BOM not exists or inactive or not submitted 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): def validate_sales_order(self):
if self.doc.sales_order: if self.doc.sales_order:
if not webnotes.conn.sql("""select name from `tabSales Order` so = webnotes.conn.sql("""select name, delivery_date from `tabSales Order`
where name=%s and docstatus = 1""", self.doc.sales_order): where name=%s and docstatus = 1""", self.doc.sales_order, as_dict=1)[0]
msgprint("Sales Order: %s is not valid" % self.doc.sales_order, raise_exception=1)
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() self.validate_production_order_against_so()
@ -76,11 +80,11 @@ class DocType:
so_qty = flt(so_item_qty) + flt(dnpi_qty) so_qty = flt(so_item_qty) + flt(dnpi_qty)
if total_qty > so_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.production_item) + _(" against sales order") + ": " +
cstr(self.doc.sales_order) + _(" will be ") + cstr(total_qty) + ", " + cstr(self.doc.sales_order) + _(" will be ") + cstr(total_qty) + ", " +
_("which is greater than sales order qty ") + "(" + cstr(so_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): def stop_unstop(self, status):
""" Called from client side on Stop/Unstop event""" """ Called from client side on Stop/Unstop event"""
@ -114,8 +118,8 @@ class DocType:
stock_entry = webnotes.conn.sql("""select name from `tabStock Entry` stock_entry = webnotes.conn.sql("""select name from `tabStock Entry`
where production_order = %s and docstatus = 1""", self.doc.name) where production_order = %s and docstatus = 1""", self.doc.name)
if stock_entry: if stock_entry:
msgprint("""Submitted Stock Entry %s exists against this production order. webnotes.throw("""Submitted Stock Entry %s exists against this production order.
Hence can not be cancelled.""" % stock_entry[0][0], raise_exception=1) Hence can not be cancelled.""" % stock_entry[0][0])
webnotes.conn.set(self.doc,'status', 'Cancelled') webnotes.conn.set(self.doc,'status', 'Cancelled')
self.update_planned_qty(-self.doc.qty) self.update_planned_qty(-self.doc.qty)

View File

@ -2,7 +2,7 @@
{ {
"creation": "2013-01-10 16:34:16", "creation": "2013-01-10 16:34:16",
"docstatus": 0, "docstatus": 0,
"modified": "2013-11-02 14:05:44", "modified": "2013-12-18 13:22:14",
"modified_by": "Administrator", "modified_by": "Administrator",
"owner": "Administrator" "owner": "Administrator"
}, },
@ -136,6 +136,14 @@
"oldfieldtype": "Currency", "oldfieldtype": "Currency",
"read_only": 1 "read_only": 1
}, },
{
"depends_on": "sales_order",
"doctype": "DocField",
"fieldname": "expected_delivery_date",
"fieldtype": "Date",
"label": "Expected Delivery Date",
"read_only": 1
},
{ {
"doctype": "DocField", "doctype": "DocField",
"fieldname": "warehouses", "fieldname": "warehouses",

View File

@ -9,7 +9,6 @@ from webnotes.model.bean import getlist
from webnotes.model.code import get_obj from webnotes.model.code import get_obj
from webnotes import msgprint, _ from webnotes import msgprint, _
class DocType: class DocType:
def __init__(self, doc, doclist=[]): def __init__(self, doc, doclist=[]):
self.doc = doc self.doc = doc
@ -47,7 +46,7 @@ class DocType:
def validate_company(self): def validate_company(self):
if not self.doc.company: if not self.doc.company:
msgprint("Please enter Company", raise_exception=1) webnotes.throw(_("Please enter Company"))
def get_open_sales_orders(self): def get_open_sales_orders(self):
""" Pull sales orders which are pending to deliver based on criteria selected""" """ Pull sales orders which are pending to deliver based on criteria selected"""
@ -72,9 +71,9 @@ class DocType:
and (exists (select name from `tabItem` item where item.name=so_item.item_code and (exists (select name from `tabItem` item where item.name=so_item.item_code
and (ifnull(item.is_pro_applicable, 'No') = 'Yes' and (ifnull(item.is_pro_applicable, 'No') = 'Yes'
or ifnull(item.is_sub_contracted_item, 'No') = 'Yes') %s) or ifnull(item.is_sub_contracted_item, 'No') = 'Yes') %s)
or exists (select name from `tabPacked Item` dnpi or exists (select name from `tabPacked Item` pi
where dnpi.parent = so.name and dnpi.parent_item = so_item.item_code where pi.parent = so.name and pi.parent_item = so_item.item_code
and exists (select name from `tabItem` item where item.name=dnpi.item_code and exists (select name from `tabItem` item where item.name=pi.item_code
and (ifnull(item.is_pro_applicable, 'No') = 'Yes' and (ifnull(item.is_pro_applicable, 'No') = 'Yes'
or ifnull(item.is_sub_contracted_item, 'No') = 'Yes') %s))) or ifnull(item.is_sub_contracted_item, 'No') = 'Yes') %s)))
""" % ('%s', so_filter, item_filter, item_filter), self.doc.company, as_dict=1) """ % ('%s', so_filter, item_filter, item_filter), self.doc.company, as_dict=1)
@ -83,6 +82,8 @@ class DocType:
def add_so_in_table(self, open_so): def add_so_in_table(self, open_so):
""" Add sales orders in the table""" """ Add sales orders in the table"""
self.clear_so_table()
so_list = [d.sales_order for d in getlist(self.doclist, 'pp_so_details')] so_list = [d.sales_order for d in getlist(self.doclist, 'pp_so_details')]
for r in open_so: for r in open_so:
if cstr(r['name']) not in so_list: if cstr(r['name']) not in so_list:
@ -104,7 +105,7 @@ class DocType:
def get_items(self): def get_items(self):
so_list = filter(None, [d.sales_order for d in getlist(self.doclist, 'pp_so_details')]) so_list = filter(None, [d.sales_order for d in getlist(self.doclist, 'pp_so_details')])
if not so_list: if not so_list:
msgprint("Please enter sales order in the above table") msgprint(_("Please enter sales order in the above table"))
return [] return []
items = webnotes.conn.sql("""select distinct parent, item_code, reserved_warehouse, items = webnotes.conn.sql("""select distinct parent, item_code, reserved_warehouse,
@ -116,19 +117,19 @@ class DocType:
or ifnull(item.is_sub_contracted_item, 'No') = 'Yes'))""" % \ or ifnull(item.is_sub_contracted_item, 'No') = 'Yes'))""" % \
(", ".join(["%s"] * len(so_list))), tuple(so_list), as_dict=1) (", ".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, 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)) * dnpi.qty) / so_item.qty) (((so_item.qty - ifnull(so_item.delivered_qty, 0)) * pi.qty) / so_item.qty)
as pending_qty as pending_qty
from `tabSales Order Item` so_item, `tabPacked Item` dnpi from `tabSales Order Item` so_item, `tabPacked Item` pi
where so_item.parent = dnpi.parent and so_item.docstatus = 1 where so_item.parent = pi.parent and so_item.docstatus = 1
and dnpi.parent_item = so_item.item_code 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 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' and (ifnull(item.is_pro_applicable, 'No') = 'Yes'
or ifnull(item.is_sub_contracted_item, 'No') = 'Yes'))""" % \ or ifnull(item.is_sub_contracted_item, 'No') = 'Yes'))""" % \
(", ".join(["%s"] * len(so_list))), tuple(so_list), as_dict=1) (", ".join(["%s"] * len(so_list))), tuple(so_list), as_dict=1)
return items + dnpi_items return items + packed_items
def add_items(self, items): def add_items(self, items):
@ -153,21 +154,21 @@ class DocType:
for d in getlist(self.doclist, 'pp_details'): for d in getlist(self.doclist, 'pp_details'):
self.validate_bom_no(d) self.validate_bom_no(d)
if not flt(d.planned_qty): if not flt(d.planned_qty):
msgprint("Please Enter Planned Qty for item: %s at row no: %s" % webnotes.throw("Please Enter Planned Qty for item: %s at row no: %s" %
(d.item_code, d.idx), raise_exception=1) (d.item_code, d.idx))
def validate_bom_no(self, d): def validate_bom_no(self, d):
if not d.bom_no: if not d.bom_no:
msgprint("Please enter bom no for item: %s at row no: %s" % webnotes.throw("Please enter bom no for item: %s at row no: %s" %
(d.item_code, d.idx), raise_exception=1) (d.item_code, d.idx))
else: else:
bom = webnotes.conn.sql("""select name from `tabBOM` where name = %s and item = %s bom = webnotes.conn.sql("""select name from `tabBOM` where name = %s and item = %s
and docstatus = 1 and is_active = 1""", and docstatus = 1 and is_active = 1""",
(d.bom_no, d.item_code), as_dict = 1) (d.bom_no, d.item_code), as_dict = 1)
if not bom: 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""" % 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): def raise_production_order(self):
"""It will raise production order (Draft) for all distinct FG items""" """It will raise production order (Draft) for all distinct FG items"""
@ -181,16 +182,19 @@ class DocType:
if pro: if pro:
pro = ["""<a href="#Form/Production Order/%s" target="_blank">%s</a>""" % \ pro = ["""<a href="#Form/Production Order/%s" target="_blank">%s</a>""" % \
(p, p) for p in pro] (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 : else :
msgprint("No Production Order created.") msgprint(_("No Production Order created."))
def get_distinct_items_and_boms(self): 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 = {}, {} item_dict, bom_dict = {}, {}
for d in self.doclist.get({"parentfield": "pp_details"}): 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)] = { item_dict[(d.item_code, d.sales_order, d.warehouse)] = {
"production_item" : d.item_code, "production_item" : d.item_code,
"sales_order" : d.sales_order, "sales_order" : d.sales_order,
@ -239,46 +243,58 @@ class DocType:
"item_code": [qty_required, description, stock_uom, min_order_qty] "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: if self.doc.use_multi_level_bom:
# get all raw materials with sub assembly childs # get all raw materials with sub assembly childs
fl_bom_items = webnotes.conn.sql("""select fb.item_code, for d in webnotes.conn.sql("""select fb.item_code,
ifnull(sum(fb.qty_consumed_per_unit), 0)*%s as qty, ifnull(sum(fb.qty_consumed_per_unit), 0) as qty,
fb.description, fb.stock_uom, it.min_order_qty fb.description, fb.stock_uom, it.min_order_qty
from `tabBOM Explosion Item` fb,`tabItem` it 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 ifnull(it.is_sub_contracted_item, 'No') = 'No'
and fb.docstatus<2 and fb.parent=%s and fb.docstatus<2 and fb.parent=%s
group by item_code, stock_uom""", (flt(bom_dict[bom]), bom)) group by item_code, stock_uom""", bom, as_dict=1):
bom_wise_item_details.setdefault(d.item_code, d)
else: else:
# Get all raw materials considering SA items as raw materials, # Get all raw materials considering SA items as raw materials,
# so no childs of SA items # so no childs of SA items
fl_bom_items = webnotes.conn.sql("""select bom_item.item_code, for d in webnotes.conn.sql("""select bom_item.item_code,
ifnull(sum(bom_item.qty_consumed_per_unit), 0) * %s, ifnull(sum(bom_item.qty_consumed_per_unit), 0) as qty,
bom_item.description, bom_item.stock_uom, item.min_order_qty bom_item.description, bom_item.stock_uom, item.min_order_qty
from `tabBOM Item` bom_item, tabItem item from `tabBOM Item` bom_item, tabItem item
where bom_item.parent = %s and bom_item.docstatus < 2 where bom_item.parent = %s and bom_item.docstatus < 2
and bom_item.item_code = item.name and bom_item.item_code = item.name
group by item_code""", (flt(bom_dict[bom]), bom)) group by item_code""", bom, as_dict=1):
self.make_items_dict(fl_bom_items) 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): def make_items_dict(self, item_list):
for i in item_list: for i in item_list:
self.item_dict[i[0]] = [(flt(self.item_dict.get(i[0], [0])[0]) + flt(i[1])), self.item_dict.setdefault(i[0], []).append([flt(i[1]), i[2], i[3], i[4], i[5]])
i[2], i[3], i[4]]
def get_csv(self): def get_csv(self):
item_list = [['Item Code', 'Description', 'Stock UOM', 'Required Qty', 'Warehouse', item_list = [['Item Code', 'Description', 'Stock UOM', 'Required Qty', 'Warehouse',
'Quantity Requested for Purchase', 'Ordered Qty', 'Actual Qty']] 'Quantity Requested for Purchase', 'Ordered Qty', 'Actual Qty']]
for d in self.item_dict: for item in self.item_dict:
item_list.append([d, self.item_dict[d][1], self.item_dict[d][2], self.item_dict[d][0]]) 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 item_qty = webnotes.conn.sql("""select warehouse, indented_qty, ordered_qty, actual_qty
from `tabBin` where item_code = %s""", d) from `tabBin` where item_code = %s""", item, as_dict=1)
i_qty, o_qty, a_qty = 0, 0, 0 i_qty, o_qty, a_qty = 0, 0, 0
for w in item_qty: 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]) 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[0], flt(w[1]), flt(w[2]), flt(w[3])]) item_list.append(['', '', '', '', w.warehouse, flt(w.indented_qty),
flt(w.ordered_qty), flt(w.actual_qty)])
if item_qty: if item_qty:
item_list.append(['', '', '', '', 'Total', i_qty, o_qty, a_qty]) item_list.append(['', '', '', '', 'Total', i_qty, o_qty, a_qty])
@ -291,31 +307,49 @@ class DocType:
""" """
self.validate_data() self.validate_data()
if not self.doc.purchase_request_for_warehouse: if not self.doc.purchase_request_for_warehouse:
webnotes.msgprint("Please enter Warehouse for which Material Request will be raised", webnotes.throw(_("Please enter Warehouse for which Material Request will be raised"))
raise_exception=1)
bom_dict = self.get_distinct_items_and_boms()[0] bom_dict = self.get_distinct_items_and_boms()[0]
self.get_raw_materials(bom_dict) self.get_raw_materials(bom_dict)
if not self.item_dict: if self.item_dict:
return self.insert_purchase_request()
def get_requested_items(self):
item_projected_qty = self.get_projected_qty() 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() 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):
# 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) 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 = 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): def get_projected_qty(self):
items = self.item_dict.keys() items = self.item_dict.keys()
@ -325,13 +359,17 @@ class DocType:
return dict(item_projected_qty) 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 = [] purchase_request_list = []
if items_to_be_requested: if items_to_be_requested:
for item in items_to_be_requested: for item in items_to_be_requested:
item_wrapper = webnotes.bean("Item", item) item_wrapper = webnotes.bean("Item", item)
pr_doclist = [ pr_doclist = [{
{
"doctype": "Material Request", "doctype": "Material Request",
"__islocal": 1, "__islocal": 1,
"naming_series": "IDT", "naming_series": "IDT",
@ -341,8 +379,9 @@ class DocType:
"fiscal_year": fiscal_year, "fiscal_year": fiscal_year,
"requested_by": webnotes.session.user, "requested_by": webnotes.session.user,
"material_request_type": "Purchase" "material_request_type": "Purchase"
}, }]
{ for sales_order, requested_qty in items_to_be_requested[item].items():
pr_doclist.append({
"doctype": "Material Request Item", "doctype": "Material Request Item",
"__islocal": 1, "__islocal": 1,
"parentfield": "indent_details", "parentfield": "indent_details",
@ -352,11 +391,12 @@ class DocType:
"uom": item_wrapper.doc.stock_uom, "uom": item_wrapper.doc.stock_uom,
"item_group": item_wrapper.doc.item_group, "item_group": item_wrapper.doc.item_group,
"brand": item_wrapper.doc.brand, "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)), "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 = webnotes.bean(pr_doclist)
pr_wrapper.ignore_permissions = 1 pr_wrapper.ignore_permissions = 1
pr_wrapper.submit() pr_wrapper.submit()
@ -365,7 +405,7 @@ class DocType:
if purchase_request_list: if purchase_request_list:
pur_req = ["""<a href="#Form/Material Request/%s" target="_blank">%s</a>""" % \ pur_req = ["""<a href="#Form/Material Request/%s" target="_blank">%s</a>""" % \
(p, p) for p in purchase_request_list] (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)) "\n".join(pur_req))
else: else:
webnotes.msgprint("Nothing to request") msgprint(_("Nothing to request"))

View File

@ -5,6 +5,7 @@ from __future__ import unicode_literals
def execute(): def execute():
import webnotes import webnotes
webnotes.reload_doc('stock', 'doctype', 'packed_item')
for si in webnotes.conn.sql("""select name from `tabSales Invoice` where docstatus = 1"""): for si in webnotes.conn.sql("""select name from `tabSales Invoice` where docstatus = 1"""):
webnotes.get_obj("Sales Invoice", si[0], webnotes.get_obj("Sales Invoice", si[0],
with_children=1).update_qty(change_modified=False) with_children=1).update_qty(change_modified=False)

View File

@ -256,6 +256,11 @@ patch_list = [
"patches.1311.p06_fix_report_columns", "patches.1311.p06_fix_report_columns",
"execute:webnotes.delete_doc('DocType', 'Documentation Tool')", "execute:webnotes.delete_doc('DocType', 'Documentation Tool')",
"execute:webnotes.delete_doc('Report', 'Stock Ledger') #2013-11-29", "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 Collection With Ageing')",
"execute:webnotes.delete_doc('Report', 'Payment Made 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",
] ]

View File

@ -26,9 +26,10 @@ erpnext.AccountTreeGrid = wn.views.TreeGridReport.extend({
show: true, show: true,
parent_field: "parent_account", parent_field: "parent_account",
formatter: function(item) { 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, value: item.name,
enc_value: encodeURIComponent(item.name)
}); });
} }
}, },
@ -211,4 +212,14 @@ erpnext.AccountTreeGrid = wn.views.TreeGridReport.extend({
return; 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");
}
}); });

View File

@ -11,9 +11,10 @@ erpnext.stock.StockController = wn.ui.form.Controller.extend({
wn.route_options = { wn.route_options = {
voucher_no: me.frm.doc.name, voucher_no: me.frm.doc.name,
from_date: me.frm.doc.posting_date, 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"); }, "icon-bar-chart");
} }
@ -24,11 +25,12 @@ erpnext.stock.StockController = wn.ui.form.Controller.extend({
if(this.frm.doc.docstatus===1 && cint(wn.defaults.get_default("auto_accounting_for_stock"))) { if(this.frm.doc.docstatus===1 && cint(wn.defaults.get_default("auto_accounting_for_stock"))) {
cur_frm.appframe.add_button(wn._('Accounting Ledger'), function() { cur_frm.appframe.add_button(wn._('Accounting Ledger'), function() {
wn.route_options = { wn.route_options = {
"voucher_no": me.frm.doc.name, voucher_no: me.frm.doc.name,
"from_date": me.frm.doc.posting_date, 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("general-ledger"); wn.set_route("query-report", "General Ledger");
}, "icon-table"); }, "icon-table");
} }
}, },

View File

@ -17,10 +17,10 @@ erpnext.StockAnalytics = erpnext.StockGridReport.extend({
parent_field: "parent_item_group", parent_field: "parent_item_group",
formatter: function(item) { formatter: function(item) {
if(!item.is_group) { 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, value: item.name,
enc_value: encodeURIComponent(item.name)
}); });
} else { } else {
return item.name; return item.name;
@ -183,5 +183,13 @@ erpnext.StockAnalytics = erpnext.StockGridReport.extend({
}, },
get_plot_points: function(item, col, idx) { get_plot_points: function(item, col, idx) {
return [[dateutil.user_to_obj(col.name).getTime(), item[col.field]]] 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");
} }
}); });

View File

@ -47,6 +47,14 @@ class DocType(TransactionBase):
if self.doc.lead_name: if self.doc.lead_name:
webnotes.conn.sql("update `tabLead` set status='Converted' where name = %s", self.doc.lead_name) webnotes.conn.sql("update `tabLead` set status='Converted' where name = %s", self.doc.lead_name)
def 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): def create_account_head(self):
if self.doc.company : if self.doc.company :
abbr = self.get_company_abbr() abbr = self.get_company_abbr()
@ -99,6 +107,9 @@ class DocType(TransactionBase):
self.validate_name_with_customer_group() self.validate_name_with_customer_group()
self.update_lead_status() self.update_lead_status()
self.update_address()
self.update_contact()
# create account head # create account head
self.create_account_head() self.create_account_head()
# update credit days and limit in account # update credit days and limit in account
@ -148,8 +159,17 @@ class DocType(TransactionBase):
rename_account_for("Customer", olddn, newdn, merge) rename_account_for("Customer", olddn, newdn, merge)
def after_rename(self, olddn, newdn, merge=False): def after_rename(self, olddn, newdn, merge=False):
set_field = ''
if webnotes.defaults.get_global_default('cust_master_name') == 'Customer Name': if webnotes.defaults.get_global_default('cust_master_name') == 'Customer Name':
webnotes.conn.set(self.doc, "customer_name", newdn) 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() @webnotes.whitelist()
def get_dashboard_info(customer): def get_dashboard_info(customer):

View File

@ -2,7 +2,7 @@
{ {
"creation": "2013-06-11 14:26:44", "creation": "2013-06-11 14:26:44",
"docstatus": 0, "docstatus": 0,
"modified": "2013-11-03 14:01:33", "modified": "2013-12-25 11:15:05",
"modified_by": "Administrator", "modified_by": "Administrator",
"owner": "Administrator" "owner": "Administrator"
}, },
@ -16,7 +16,7 @@
"icon": "icon-user", "icon": "icon-user",
"module": "Selling", "module": "Selling",
"name": "__common__", "name": "__common__",
"search_fields": "customer_name,customer_group,country,territory" "search_fields": "customer_name,customer_group,territory"
}, },
{ {
"doctype": "DocField", "doctype": "DocField",

View File

@ -2,7 +2,7 @@
{ {
"creation": "2013-05-24 19:29:08", "creation": "2013-05-24 19:29:08",
"docstatus": 0, "docstatus": 0,
"modified": "2013-11-27 17:57:19", "modified": "2013-12-14 17:25:46",
"modified_by": "Administrator", "modified_by": "Administrator",
"owner": "Administrator" "owner": "Administrator"
}, },
@ -863,6 +863,7 @@
"cancel": 0, "cancel": 0,
"create": 0, "create": 0,
"doctype": "DocPerm", "doctype": "DocPerm",
"match": "customer",
"role": "Customer", "role": "Customer",
"submit": 0, "submit": 0,
"write": 0 "write": 0

View File

@ -112,6 +112,7 @@ class DocType(SellingController):
self.validate_warehouse() self.validate_warehouse()
from erpnext.stock.doctype.packed_item.packed_item import make_packing_list 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() self.validate_with_previous_doc()
@ -126,7 +127,6 @@ class DocType(SellingController):
if not self.doc.billing_status: self.doc.billing_status = 'Not Billed' 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): def validate_warehouse(self):
from erpnext.stock.utils import validate_warehouse_user, validate_warehouse_company from erpnext.stock.utils import validate_warehouse_user, validate_warehouse_company

View File

@ -515,7 +515,6 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
} }
}); });
}; };
setup_field_label_map(["net_total", "other_charges_total", "grand_total", setup_field_label_map(["net_total", "other_charges_total", "grand_total",
"rounded_total", "in_words", "rounded_total", "in_words",
"outstanding_amount", "total_advance", "paid_amount", "write_off_amount"], "outstanding_amount", "total_advance", "paid_amount", "write_off_amount"],

View File

@ -16,8 +16,6 @@ import webnotes
from webnotes.utils import get_request_site_address, cstr from webnotes.utils import get_request_site_address, cstr
from webnotes import _ from webnotes import _
from backup_manager import ignore_list
@webnotes.whitelist() @webnotes.whitelist()
def get_dropbox_authorize_url(): def get_dropbox_authorize_url():
sess = get_dropbox_session() sess = get_dropbox_session()
@ -100,8 +98,6 @@ def backup_to_dropbox():
path = get_files_path() path = get_files_path()
for filename in os.listdir(path): for filename in os.listdir(path):
filename = cstr(filename) filename = cstr(filename)
if filename in ignore_list:
continue
found = False found = False
filepath = os.path.join(path, filename) filepath = os.path.join(path, filename)

View File

@ -87,7 +87,7 @@ $.extend(cur_frm.cscript, {
cur_frm.save(); cur_frm.save();
}, },
upload_backups_to_gdrive: function() { // upload_backups_to_gdrive: function() {
cur_frm.save(); // cur_frm.save();
}, // },
}); });

View File

@ -7,8 +7,6 @@ from __future__ import unicode_literals
import webnotes import webnotes
from webnotes import _ from webnotes import _
ignore_list = []
class DocType: class DocType:
def __init__(self, d, dl): def __init__(self, d, dl):
self.doc, self.doclist = d, dl self.doc, self.doclist = d, dl
@ -39,10 +37,6 @@ def take_backups_dropbox():
file_and_error = [" - ".join(f) for f in zip(did_not_upload, error_log)] 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()) error_message = ("\n".join(file_and_error) + "\n" + webnotes.get_traceback())
webnotes.errprint(error_message) webnotes.errprint(error_message)
if not webnotes.conn:
webnotes.connect()
send_email(False, "Dropbox", error_message) send_email(False, "Dropbox", error_message)
#backup to gdrive #backup to gdrive
@ -62,6 +56,7 @@ def take_backups_gdrive():
send_email(False, "Google Drive", error_message) send_email(False, "Google Drive", error_message)
def send_email(success, service_name, error_status=None): def send_email(success, service_name, error_status=None):
from webnotes.utils.email_lib import sendmail
if success: if success:
subject = "Backup Upload Successful" subject = "Backup Upload Successful"
message ="""<h3>Backup Uploaded Successfully</h3><p>Hi there, this is just to inform you message ="""<h3>Backup Uploaded Successfully</h3><p>Hi there, this is just to inform you
@ -76,7 +71,8 @@ def send_email(success, service_name, error_status=None):
<p>Please contact your system manager for more information.</p> <p>Please contact your system manager for more information.</p>
""" % (service_name, error_status) """ % (service_name, error_status)
# email system managers if not webnotes.conn:
from webnotes.utils.email_lib import sendmail webnotes.connect()
sendmail(webnotes.conn.get_value("Backup Manager", None, "send_notifications_to").split(","),
subject=subject, msg=message) recipients = webnotes.conn.get_value("Backup Manager", None, "send_notifications_to").split(",")
sendmail(recipients, subject=subject, msg=message)

View File

@ -70,8 +70,10 @@ cur_frm.cscript.addremove_recipients = function(doc, dt, dn) {
check.checked = 1; check.checked = 1;
add_or_update = 'Update'; add_or_update = 'Update';
} }
var fullname = wn.user.full_name(v.name);
if(fullname !== v.name) v.name = fullname + " &lt;" + v.name + "&gt;";
if(v.enabled==0) { 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); var profile = $a($td(tab, i+1, 1), 'span', '', '', v.name);
//profile.onclick = function() { check.checked = !check.checked; } //profile.onclick = function() { check.checked = !check.checked; }

View File

@ -9,6 +9,7 @@ from webnotes.utils import fmt_money, formatdate, now_datetime, cstr, esc, \
from webnotes.utils.dateutils import datetime_in_user_format from webnotes.utils.dateutils import datetime_in_user_format
from datetime import timedelta from datetime import timedelta
from dateutil.relativedelta import relativedelta from dateutil.relativedelta import relativedelta
from webnotes.utils.email_lib import sendmail
content_sequence = [ content_sequence = [
["Income / Expenses", ["income_year_to_date", "bank_balance", ["Income / Expenses", ["income_year_to_date", "bank_balance",
@ -19,16 +20,16 @@ content_sequence = [
["Selling", ["new_leads", "new_enquiries", "new_quotations", "new_sales_orders"]], ["Selling", ["new_leads", "new_enquiries", "new_quotations", "new_sales_orders"]],
["Stock", ["new_delivery_notes", "new_purchase_receipts", "new_stock_entries"]], ["Stock", ["new_delivery_notes", "new_purchase_receipts", "new_stock_entries"]],
["Support", ["new_communications", "new_support_tickets", "open_tickets"]], ["Support", ["new_communications", "new_support_tickets", "open_tickets"]],
["Projects", ["new_projects"]] ["Projects", ["new_projects"]],
["System", ["scheduler_errors"]],
] ]
user_specific_content = ["calendar_events", "todo_list"] user_specific_content = ["calendar_events", "todo_list"]
digest_template = """\ digest_template = """<style>p.ed-indent { margin-right: 17px; }</style>
<style>p.ed-indent { margin-right: 17px; }</style> <h2>%(name)s</h2>
<h2>%(digest)s</h2>
<p style='color: grey'>%(date)s</p>
<h4>%(company)s</h4> <h4>%(company)s</h4>
<p style='color: grey'>%(date)s</p>
<hr> <hr>
%(with_value)s %(with_value)s
%(no_value)s %(no_value)s
@ -53,10 +54,10 @@ class DocType(DocListController):
def get_profiles(self): def get_profiles(self):
"""get list of profiles""" """get list of profiles"""
import webnotes
profile_list = webnotes.conn.sql(""" profile_list = webnotes.conn.sql("""
select name, enabled from tabProfile select name, enabled from tabProfile
where docstatus=0 and name not in ('Administrator', 'Guest') where docstatus=0 and name not in ('Administrator', 'Guest')
and user_type = "System User"
order by enabled desc, name asc""", as_dict=1) order by enabled desc, name asc""", as_dict=1)
if self.doc.recipient_list: if self.doc.recipient_list:
@ -80,13 +81,15 @@ class DocType(DocListController):
for user_id in recipients: for user_id in recipients:
msg_for_this_receipient = self.get_msg_html(self.get_user_specific_content(user_id) + \ msg_for_this_receipient = self.get_msg_html(self.get_user_specific_content(user_id) + \
common_msg) common_msg)
from webnotes.utils.email_lib import sendmail if msg_for_this_receipient:
sendmail(recipients=user_id, subject="[ERPNext] " + (self.doc.frequency + " Digest"), sendmail(recipients=user_id,
subject="[ERPNext] [{frequency} Digest] {name}".format(
frequency=self.doc.frequency, name=self.doc.name),
msg=msg_for_this_receipient) msg=msg_for_this_receipient)
def get_digest_msg(self): def get_digest_msg(self):
return self.get_msg_html(self.get_user_specific_content(webnotes.session.user) + \ 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): def get_common_content(self):
out = [] out = []
@ -117,13 +120,18 @@ class DocType(DocListController):
return out 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]] with_value = [o[1] for o in out if o[0]]
if with_value: if with_value:
has_updates = True
with_value = "\n".join(with_value) with_value = "\n".join(with_value)
else: 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 # seperate out no value items
no_value = [o[1] for o in out if not o[0]] no_value = [o[1] for o in out if not o[0]]
@ -138,7 +146,8 @@ class DocType(DocListController):
"date": date, "date": date,
"company": self.doc.company, "company": self.doc.company,
"with_value": with_value, "with_value": with_value,
"no_value": no_value or "" "no_value": no_value or "",
"name": self.doc.name
} }
return msg return msg
@ -241,7 +250,7 @@ class DocType(DocListController):
return self.get_new_count("Lead", self.meta.get_label("new_leads")) return self.get_new_count("Lead", self.meta.get_label("new_leads"))
def get_new_enquiries(self): 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): def get_new_quotations(self):
return self.get_new_sum("Quotation", self.meta.get_label("new_quotations"), "grand_total") return self.get_new_sum("Quotation", self.meta.get_label("new_quotations"), "grand_total")
@ -253,7 +262,8 @@ class DocType(DocListController):
return self.get_new_sum("Delivery Note", self.meta.get_label("new_delivery_notes"), "grand_total") return self.get_new_sum("Delivery Note", self.meta.get_label("new_delivery_notes"), "grand_total")
def get_new_purchase_requests(self): 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): def get_new_supplier_quotations(self):
return self.get_new_sum("Supplier Quotation", self.meta.get_label("new_supplier_quotations"), return self.get_new_sum("Supplier Quotation", self.meta.get_label("new_supplier_quotations"),
@ -271,13 +281,16 @@ class DocType(DocListController):
return self.get_new_sum("Stock Entry", self.meta.get_label("new_stock_entries"), "total_amount") return self.get_new_sum("Stock Entry", self.meta.get_label("new_stock_entries"), "total_amount")
def get_new_support_tickets(self): 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): 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): 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): def get_calendar_events(self, user_id):
from webnotes.core.doctype.event.event import get_events from webnotes.core.doctype.event.event import get_events
@ -321,22 +334,22 @@ class DocType(DocListController):
else: else:
return 0, "<p>To Do</p>" 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: if filter_by_company:
company = """and company="%s" """ % self.doc.company company = """and company="%s" """ % self.doc.company
else: else:
company = "" company = ""
count = webnotes.conn.sql("""select count(*) from `tab%s` count = webnotes.conn.sql("""select count(*) from `tab%s`
where docstatus < 2 %s and where docstatus=%s %s and
date(creation)>=%s and date(creation)<=%s""" % (doctype, company, "%s", "%s"), date(creation)>=%s and date(creation)<=%s""" %
(self.from_date, self.to_date)) (doctype, docstatus, company, "%s", "%s"), (self.from_date, self.to_date))
count = count and count[0][0] or 0 count = count and count[0][0] or 0
return count, self.get_html(label, None, count) return count, self.get_html(label, None, count)
def get_new_sum(self, doctype, label, sum_field): def get_new_sum(self, doctype, label, sum_field):
count_sum = webnotes.conn.sql("""select count(*), sum(ifnull(`%s`, 0)) 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", date(creation)>=%s and date(creation)<=%s""" % (sum_field, doctype, "%s",
"%s", "%s"), (self.doc.company, self.from_date, self.to_date)) "%s", "%s"), (self.doc.company, self.from_date, self.to_date))
count, total = count_sum and count_sum[0] or (0, 0) count, total = count_sum and count_sum[0] or (0, 0)
@ -449,6 +462,10 @@ class DocType(DocListController):
else: else:
return 0, "No Open Tickets!" 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): def onload(self):
self.get_next_sending() self.get_next_sending()

View File

@ -2,7 +2,7 @@
{ {
"creation": "2013-02-21 14:15:31", "creation": "2013-02-21 14:15:31",
"docstatus": 0, "docstatus": 0,
"modified": "2013-07-05 14:36:13", "modified": "2013-12-16 12:37:43",
"modified_by": "Administrator", "modified_by": "Administrator",
"owner": "Administrator" "owner": "Administrator"
}, },
@ -100,11 +100,10 @@
"label": "Add/Remove Recipients" "label": "Add/Remove Recipients"
}, },
{ {
"description": "Check all the items below that you want to send in this digest.",
"doctype": "DocField", "doctype": "DocField",
"fieldname": "select_digest_content", "fieldname": "accounts",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"label": "Select Digest Content" "label": "Accounts"
}, },
{ {
"doctype": "DocField", "doctype": "DocField",
@ -178,7 +177,7 @@
"doctype": "DocField", "doctype": "DocField",
"fieldname": "section_break_20", "fieldname": "section_break_20",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"options": "Simple" "label": "Buying & Selling"
}, },
{ {
"doctype": "DocField", "doctype": "DocField",
@ -234,6 +233,12 @@
"fieldtype": "Check", "fieldtype": "Check",
"label": "New Sales Orders" "label": "New Sales Orders"
}, },
{
"doctype": "DocField",
"fieldname": "section_break_34",
"fieldtype": "Section Break",
"label": "Inventory & Support"
},
{ {
"doctype": "DocField", "doctype": "DocField",
"fieldname": "stock_module", "fieldname": "stock_module",
@ -258,12 +263,6 @@
"fieldtype": "Check", "fieldtype": "Check",
"label": "New Stock Entries" "label": "New Stock Entries"
}, },
{
"doctype": "DocField",
"fieldname": "section_break_34",
"fieldtype": "Section Break",
"options": "Simple"
},
{ {
"doctype": "DocField", "doctype": "DocField",
"fieldname": "support_module", "fieldname": "support_module",
@ -288,6 +287,12 @@
"fieldtype": "Check", "fieldtype": "Check",
"label": "New Communications" "label": "New Communications"
}, },
{
"doctype": "DocField",
"fieldname": "section_break_40",
"fieldtype": "Section Break",
"label": "Projects & System"
},
{ {
"doctype": "DocField", "doctype": "DocField",
"fieldname": "projects_module", "fieldname": "projects_module",
@ -302,7 +307,25 @@
}, },
{ {
"doctype": "DocField", "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", "fieldtype": "Column Break",
"label": "General" "label": "General"
}, },
@ -318,6 +341,12 @@
"fieldtype": "Check", "fieldtype": "Check",
"label": "To Do List" "label": "To Do List"
}, },
{
"doctype": "DocField",
"fieldname": "stub",
"fieldtype": "Column Break",
"label": "Stub"
},
{ {
"cancel": 1, "cancel": 1,
"create": 1, "create": 1,

View File

@ -2,7 +2,7 @@
{ {
"creation": "2013-03-25 17:53:21", "creation": "2013-03-25 17:53:21",
"docstatus": 0, "docstatus": 0,
"modified": "2013-11-28 11:54:42", "modified": "2013-12-06 13:12:25",
"modified_by": "Administrator", "modified_by": "Administrator",
"owner": "Administrator" "owner": "Administrator"
}, },
@ -103,6 +103,7 @@
"label": "Auto Email Id" "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.", "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", "doctype": "DocField",
"fieldname": "send_print_in_body_and_attachment", "fieldname": "send_print_in_body_and_attachment",

View File

@ -2,7 +2,7 @@
{ {
"creation": "2012-12-20 12:50:49", "creation": "2012-12-20 12:50:49",
"docstatus": 0, "docstatus": 0,
"modified": "2013-11-03 14:20:18", "modified": "2013-12-24 11:40:19",
"modified_by": "Administrator", "modified_by": "Administrator",
"owner": "Administrator" "owner": "Administrator"
}, },
@ -90,7 +90,7 @@
"doctype": "DocField", "doctype": "DocField",
"fieldname": "fs_packing_details", "fieldname": "fs_packing_details",
"fieldtype": "Check", "fieldtype": "Check",
"label": "Packing Detials" "label": "Packing Details"
}, },
{ {
"description": "To get Item Group in details table", "description": "To get Item Group in details table",

View File

@ -22,7 +22,7 @@ class DocType:
where fieldname='naming_series'""") where fieldname='naming_series'""")
)))), )))),
"prefixes": "\n".join([''] + [i[0] for i in "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): def scrub_options_list(self, ol):
@ -38,7 +38,7 @@ class DocType:
self.set_series_for(self.doc.select_doc_for_series, series_list) self.set_series_for(self.doc.select_doc_for_series, series_list)
# create series # create series
map(self.insert_series, series_list) map(self.insert_series, [d.split('.')[0] for d in series_list])
msgprint('Series Updated') msgprint('Series Updated')
@ -103,7 +103,8 @@ class DocType:
dt.validate_series(series, self.doc.select_doc_for_series) dt.validate_series(series, self.doc.select_doc_for_series)
for i in sr: for i in sr:
if i[0]: 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. \ msgprint("Oops! Series name %s is already in use in %s. \
Please select a new one" % (series, i[1]), raise_exception=1) Please select a new one" % (series, i[1]), raise_exception=1)
@ -120,17 +121,21 @@ class DocType:
def get_current(self, arg=None): def get_current(self, arg=None):
"""get series current""" """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): def insert_series(self, series):
"""insert series if missing""" """insert series if missing"""
if not webnotes.conn.exists('Series', series): 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): def update_series_start(self):
if self.doc.prefix: if self.doc.prefix:
self.insert_series(self.doc.prefix) prefix = self.doc.prefix.split('.')[0]
webnotes.conn.sql("update `tabSeries` set current = '%s' where name = '%s'" % (self.doc.current_value,self.doc.prefix)) self.insert_series(prefix)
webnotes.conn.sql("update `tabSeries` set current = %s where name = %s",
(self.doc.current_value, prefix))
msgprint("Series Updated Successfully") msgprint("Series Updated Successfully")
else: else:
msgprint("Please select prefix first") msgprint("Please select prefix first")

View File

@ -233,8 +233,9 @@ items = [
"route": "Report/Scheduler Log", "type": "Link", "icon": "icon-exclamation-sign" }, "route": "Report/Scheduler Log", "type": "Link", "icon": "icon-exclamation-sign" },
] ]
@webnotes.whitelist(allow_roles=["System Manager"]) @webnotes.whitelist()
def get(): def get():
webnotes.only_for("System Manager")
for item in items: for item in items:
if item.get("type")=="Section": if item.get("type")=="Section":
continue continue

View File

@ -158,6 +158,10 @@ def set_defaults(args):
hr_settings.doc.emp_created_by = "Naming Series" hr_settings.doc.emp_created_by = "Naming Series"
hr_settings.save() hr_settings.save()
email_settings = webnotes.bean("Email Settings")
email_settings.doc.send_print_in_body_and_attachment = 1
email_settings.save()
# control panel # control panel
cp = webnotes.doc("Control Panel", "Control Panel") cp = webnotes.doc("Control Panel", "Control Panel")
cp.company_name = args["company_name"] cp.company_name = args["company_name"]
@ -171,11 +175,12 @@ def create_feed_and_todo():
def create_email_digest(): def create_email_digest():
from webnotes.profile import get_system_managers from webnotes.profile import get_system_managers
system_managers = get_system_managers() system_managers = get_system_managers(only_name=True)
if not system_managers: if not system_managers:
return 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): if not webnotes.conn.exists("Email Digest", "Default Weekly Digest - " + company):
edigest = webnotes.bean({ edigest = webnotes.bean({
"doctype": "Email Digest", "doctype": "Email Digest",
@ -186,10 +191,24 @@ def create_email_digest():
}) })
for fieldname in edigest.meta.get_fieldnames({"fieldtype": "Check"}): for fieldname in edigest.meta.get_fieldnames({"fieldtype": "Check"}):
if fieldname != "scheduler_errors":
edigest.doc.fields[fieldname] = 1 edigest.doc.fields[fieldname] = 1
edigest.insert() 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): def get_fy_details(fy_start_date, fy_end_date):
start_year = getdate(fy_start_date).year start_year = getdate(fy_start_date).year
if start_year == getdate(fy_end_date).year: if start_year == getdate(fy_end_date).year:

View File

@ -73,6 +73,9 @@ class DocType(SellingController):
self.update_current_stock() self.update_current_stock()
self.validate_with_previous_doc() 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' self.doc.status = 'Draft'
if not self.doc.installation_status: self.doc.installation_status = 'Not Installed' if not self.doc.installation_status: self.doc.installation_status = 'Not Installed'
@ -143,10 +146,6 @@ class DocType(SellingController):
d.actual_qty = bin and flt(bin[0]['actual_qty']) or 0 d.actual_qty = bin and flt(bin[0]['actual_qty']) or 0
d.projected_qty = bin and flt(bin[0]['projected_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): def on_submit(self):
self.validate_packed_qty() self.validate_packed_qty()

View File

@ -2,7 +2,7 @@
{ {
"creation": "2013-05-24 19:29:09", "creation": "2013-05-24 19:29:09",
"docstatus": 0, "docstatus": 0,
"modified": "2013-12-09 16:24:08", "modified": "2013-12-14 17:26:12",
"modified_by": "Administrator", "modified_by": "Administrator",
"owner": "Administrator" "owner": "Administrator"
}, },
@ -1058,7 +1058,7 @@
}, },
{ {
"doctype": "DocPerm", "doctype": "DocPerm",
"match": "customer_name", "match": "customer",
"role": "Customer" "role": "Customer"
} }
] ]

View File

@ -58,11 +58,6 @@ class TestDeliveryNote(unittest.TestCase):
self.assertEqual(stock_value, 0) self.assertEqual(stock_value, 0)
self.assertEqual(stock_value_difference, -375) 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)) self.assertFalse(get_gl_entries("Delivery Note", dn.doc.name))
def test_delivery_note_gl_entry(self): def test_delivery_note_gl_entry(self):
@ -111,8 +106,8 @@ class TestDeliveryNote(unittest.TestCase):
gl_entries = get_gl_entries("Delivery Note", dn.doc.name) gl_entries = get_gl_entries("Delivery Note", dn.doc.name)
self.assertTrue(gl_entries) self.assertTrue(gl_entries)
expected_values = { expected_values = {
stock_in_hand_account: [0.0, 666.65], stock_in_hand_account: [0.0, 666.67],
"Cost of Goods Sold - _TC": [666.65, 0.0] "Cost of Goods Sold - _TC": [666.67, 0.0]
} }
for i, gle in enumerate(gl_entries): for i, gle in enumerate(gl_entries):
self.assertEquals([gle.debit, gle.credit], expected_values.get(gle.account)) self.assertEquals([gle.debit, gle.credit], expected_values.get(gle.account))

View File

@ -4,7 +4,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import webnotes import webnotes
from webnotes.utils import cstr, flt, cint from webnotes.utils import cstr, flt
from webnotes.model.doc import addchild from webnotes.model.doc import addchild
from webnotes.model.bean import getlist from webnotes.model.bean import getlist
from webnotes import msgprint, _ from webnotes import msgprint, _
@ -49,6 +49,7 @@ class DocType(DocListController, WebsiteGenerator):
def on_update(self): def on_update(self):
self.validate_name_with_item_group() self.validate_name_with_item_group()
self.update_website() self.update_website()
self.update_item_price()
def check_warehouse_is_set_for_stock_item(self): def check_warehouse_is_set_for_stock_item(self):
if self.doc.is_stock_item=="Yes" and not self.doc.default_warehouse: if self.doc.is_stock_item=="Yes" and not self.doc.default_warehouse:
@ -112,40 +113,29 @@ class DocType(DocListController, WebsiteGenerator):
self.doc.is_pro_applicable = "No" self.doc.is_pro_applicable = "No"
if self.doc.is_pro_applicable == 'Yes' and self.doc.is_stock_item == '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': 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) 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(self):
def _check_for_active_boms(field_label): if self.doc.is_purchase_item != "Yes":
if field_label in ['Is Active', 'Is Purchase Item']:
bom_mat = webnotes.conn.sql("""select distinct t1.parent bom_mat = webnotes.conn.sql("""select distinct t1.parent
from `tabBOM Item` t1, `tabBOM` t2 where t2.name = 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 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) 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' if bom_mat and bom_mat[0][0]:
and self.doc.is_sub_contracted_item != 'Yes') webnotes.throw(_("Item must be a purchase item, \
or (field_label == 'Is Sub Contracted Item' as it is present in one or many Active BOMs"))
and self.doc.is_manufactured_item != 'Yes')):
if self.doc.is_manufactured_item != "Yes":
bom = webnotes.conn.sql("""select name from `tabBOM` where item = %s bom = webnotes.conn.sql("""select name from `tabBOM` where item = %s
and is_active = 1""", (self.doc.name,)) and is_active = 1""", (self.doc.name,))
if bom and bom[0][0]: if bom and bom[0][0]:
msgprint(_(field_label) + _(" should be 'Yes'. As Item: ") + self.doc.name + webnotes.throw(_("""Allow Bill of Materials should be 'Yes'. Because one or many \
_(" is present in one or many Active BOMs"), raise_exception=1) active BOMs present for this item"""))
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])
def fill_customer_code(self): def fill_customer_code(self):
""" Append all the customer codes and insert into "customer_code" field of item table """ """ Append all the customer codes and insert into "customer_code" field of item table """
@ -215,6 +205,11 @@ class DocType(DocListController, WebsiteGenerator):
WebsiteGenerator.on_update(self) 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): def get_page_title(self):
if self.doc.name==self.doc.item_name: if self.doc.name==self.doc.item_name:
page_name_from = self.doc.name page_name_from = self.doc.name
@ -251,6 +246,9 @@ class DocType(DocListController, WebsiteGenerator):
def before_rename(self, olddn, newdn, merge=False): def before_rename(self, olddn, newdn, merge=False):
if merge: if merge:
# Validate properties before merging # 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"] 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)] 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]: if new_properties != [cstr(self.doc.fields[fld]) for fld in field_list]:

View File

@ -37,20 +37,25 @@ class DocType(BuyingController):
for so_no in so_items.keys(): for so_no in so_items.keys():
for item in so_items[so_no].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 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 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: if actual_so_qty and (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) 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): def validate_schedule_date(self):
for d in getlist(self.doclist, 'indent_details'): for d in getlist(self.doclist, 'indent_details'):
if d.schedule_date < self.doc.transaction_date: if d.schedule_date < self.doc.transaction_date:
msgprint("Expected Date cannot be before Material Request Date") webnotes.throw(_("Expected Date cannot be before Material Request Date"))
raise Exception
# Validate # Validate
# --------------------- # ---------------------
@ -80,8 +85,8 @@ class DocType(BuyingController):
for d in getlist(self.doclist, 'indent_details'): for d in getlist(self.doclist, 'indent_details'):
if webnotes.conn.get_value("Item", d.item_code, "is_stock_item") == "Yes": if webnotes.conn.get_value("Item", d.item_code, "is_stock_item") == "Yes":
if not d.warehouse: if not d.warehouse:
msgprint("Please Enter Warehouse for Item %s as it is stock item" webnotes.throw("Please Enter Warehouse for Item %s as it is stock item"
% cstr(d.item_code), raise_exception=1) % cstr(d.item_code))
qty =flt(d.qty) qty =flt(d.qty)
if is_stopped: if is_stopped:
@ -100,12 +105,13 @@ class DocType(BuyingController):
self.update_bin(is_submit = 1, is_stopped = 0) self.update_bin(is_submit = 1, is_stopped = 0)
def check_modified_date(self): def check_modified_date(self):
mod_db = webnotes.conn.sql("select modified from `tabMaterial Request` where name = '%s'" % self.doc.name) mod_db = webnotes.conn.sql("""select modified from `tabMaterial Request` where name = %s""",
date_diff = webnotes.conn.sql("select TIMEDIFF('%s', '%s')" % ( mod_db[0][0],cstr(self.doc.modified))) 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]: if date_diff and date_diff[0][0]:
msgprint(cstr(self.doc.doctype) +" => "+ cstr(self.doc.name) +" has been modified. Please Refresh. ") webnotes.throw(cstr(self.doc.doctype) + " => " + cstr(self.doc.name) + " has been modified. Please Refresh.")
raise Exception
def update_status(self, status): def update_status(self, status):
self.check_modified_date() self.check_modified_date()
@ -177,9 +183,9 @@ def update_completed_qty(controller, caller_method):
mr_doctype = webnotes.get_doctype("Material Request") mr_doctype = webnotes.get_doctype("Material Request")
if mr_obj.doc.status in ["Stopped", "Cancelled"]: 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) + _(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) _update_requested_qty(controller, mr_obj, mr_items)

View File

@ -2,7 +2,7 @@
{ {
"creation": "2013-02-22 01:28:02", "creation": "2013-02-22 01:28:02",
"docstatus": 0, "docstatus": 0,
"modified": "2013-11-03 20:36:45", "modified": "2013-12-18 14:52:02",
"modified_by": "Administrator", "modified_by": "Administrator",
"owner": "Administrator" "owner": "Administrator"
}, },
@ -219,7 +219,7 @@
"fieldname": "sales_order_no", "fieldname": "sales_order_no",
"fieldtype": "Link", "fieldtype": "Link",
"label": "Sales Order No", "label": "Sales Order No",
"no_copy": 1, "no_copy": 0,
"options": "Sales Order", "options": "Sales Order",
"print_hide": 1, "print_hide": 1,
"read_only": 1 "read_only": 1

View File

@ -56,9 +56,6 @@ def update_packing_list_item(obj, packing_item_code, qty, warehouse, line, packi
pi.batch_no = cstr(line.batch_no) pi.batch_no = cstr(line.batch_no)
pi.idx = packing_list_idx pi.idx = packing_list_idx
# saved, since this function is called on_update of delivery note
pi.save()
packing_list_idx += 1 packing_list_idx += 1
@ -87,19 +84,13 @@ def cleanup_packing_list(obj, parent_items):
for d in obj.doclist.get({"parentfield": "packing_details"}): for d in obj.doclist.get({"parentfield": "packing_details"}):
if [d.parent_item, d.parent_detail_docname] not in parent_items: if [d.parent_item, d.parent_detail_docname] not in parent_items:
# mark for deletion from doclist # mark for deletion from doclist
delete_list.append(d.name) delete_list.append([d.parent_item, d.parent_detail_docname])
if not delete_list: if not delete_list:
return obj.doclist return obj.doclist
# delete from doclist # delete from doclist
obj.doclist = webnotes.doclist(filter(lambda d: d.name not in delete_list, obj.doclist)) obj.doclist = webnotes.doclist(filter(lambda d: [d.parent_item, d.parent_detail_docname]
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))
return obj.doclist return obj.doclist

View File

@ -44,5 +44,5 @@ class DocType(DocListController):
def update_item_price(self): def update_item_price(self):
webnotes.conn.sql("""update `tabItem Price` set currency=%s, 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)) (self.doc.currency, self.doc.buying_or_selling, self.doc.name))

View File

@ -2,7 +2,7 @@
{ {
"creation": "2013-05-24 19:29:10", "creation": "2013-05-24 19:29:10",
"docstatus": 0, "docstatus": 0,
"modified": "2013-11-02 19:41:45", "modified": "2013-12-18 10:38:39",
"modified_by": "Administrator", "modified_by": "Administrator",
"owner": "Administrator" "owner": "Administrator"
}, },
@ -326,7 +326,7 @@
"fieldname": "schedule_date", "fieldname": "schedule_date",
"fieldtype": "Date", "fieldtype": "Date",
"label": "Required By", "label": "Required By",
"no_copy": 1, "no_copy": 0,
"oldfieldname": "schedule_date", "oldfieldname": "schedule_date",
"oldfieldtype": "Date", "oldfieldtype": "Date",
"print_hide": 1, "print_hide": 1,

View File

@ -150,7 +150,7 @@ class DocType(StockController):
where serial_no like %s and item_code=%s and ifnull(is_cancelled, 'No')='No' 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""", order by posting_date desc, posting_time desc, name desc""",
("%%%s%%" % self.doc.name, self.doc.item_code), as_dict=1): ("%%%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: if sle.actual_qty > 0:
sle_dict.setdefault("incoming", []).append(sle) sle_dict.setdefault("incoming", []).append(sle)
else: else:
@ -268,7 +268,8 @@ def get_item_details(item_code):
from tabItem where name=%s""", item_code, as_dict=True)[0] from tabItem where name=%s""", item_code, as_dict=True)[0]
def get_serial_nos(serial_no): 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): def make_serial_no(serial_no, sle):
sr = webnotes.new_bean("Serial No") sr = webnotes.new_bean("Serial No")

View File

@ -243,7 +243,7 @@ cur_frm.script_manager.make(erpnext.stock.StockEntry);
cur_frm.cscript.toggle_related_fields = function(doc) { cur_frm.cscript.toggle_related_fields = function(doc) {
disable_from_warehouse = inList(["Material Receipt", "Sales Return"], doc.purpose); 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("from_warehouse", !disable_from_warehouse);
cur_frm.toggle_enable("to_warehouse", !disable_to_warehouse); cur_frm.toggle_enable("to_warehouse", !disable_to_warehouse);
@ -301,7 +301,7 @@ cur_frm.fields_dict['production_order'].get_query = function(doc) {
} }
cur_frm.cscript.purpose = function(doc, cdt, cdn) { 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 // Overloaded query for link batch_no

View File

@ -285,8 +285,14 @@ class DocType(StockController):
# validate quantity <= ref item's qty - qty already returned # validate quantity <= ref item's qty - qty already returned
ref_item = ref.doclist.getone({"item_code": item.item_code}) ref_item = ref.doclist.getone({"item_code": item.item_code})
returnable_qty = ref_item.qty - flt(already_returned_item_qty.get(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, if not returnable_qty:
raise_exception=StockOverReturnError) 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): def get_already_returned_item_qty(self, ref_fieldname):
return dict(webnotes.conn.sql("""select item_code, sum(transfer_qty) as qty return dict(webnotes.conn.sql("""select item_code, sum(transfer_qty) as qty

View File

@ -20,6 +20,19 @@ class DocType:
if self.doc.email_id and not validate_email_add(self.doc.email_id): if self.doc.email_id and not validate_email_add(self.doc.email_id):
msgprint("Please enter valid Email Id", raise_exception=1) 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): def on_update(self):
self.create_account_head() self.create_account_head()
@ -84,6 +97,9 @@ class DocType:
new_warehouse = get_name_with_abbr(newdn, self.doc.company) new_warehouse = get_name_with_abbr(newdn, self.doc.company)
if merge: 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"): if self.doc.company != webnotes.conn.get_value("Warehouse", new_warehouse, "company"):
webnotes.throw(_("Both Warehouse must belong to same Company")) webnotes.throw(_("Both Warehouse must belong to same Company"))

View File

@ -138,7 +138,7 @@ wn.module_page["Stock"] = [
items: [ items: [
{ {
"label":wn._("Stock Ledger"), "label":wn._("Stock Ledger"),
doctype: "Delivery Note", doctype: "Item",
route: "query-report/Stock Ledger" route: "query-report/Stock Ledger"
}, },
{ {
@ -146,12 +146,14 @@ wn.module_page["Stock"] = [
page: "stock-balance" page: "stock-balance"
}, },
{ {
"page":"stock-level", "label":wn._("Stock Projected Qty"),
"label": wn._("Stock Level") 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"
}, },
] ]
}, },

View File

@ -15,7 +15,7 @@ def execute(filters=None):
bom_rate = get_item_bom_rate() bom_rate = get_item_bom_rate()
val_rate_map = get_valuation_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 = [] data = []
for item in sorted(item_map): for item in sorted(item_map):
@ -31,6 +31,14 @@ def execute(filters=None):
return columns, data 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): def get_columns(filters):
"""return columns based on filters""" """return columns based on filters"""

View File

@ -3,7 +3,6 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import webnotes import webnotes
from webnotes import _
def execute(filters=None): def execute(filters=None):
columns = get_columns() columns = get_columns()
@ -13,10 +12,14 @@ def execute(filters=None):
data = [] data = []
for sle in sl_entries: for sle in sl_entries:
item_detail = item_details[sle.item_code] 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, 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, 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.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 return columns, data
@ -25,17 +28,10 @@ def get_columns():
"Item Group:Link/Item Group:100", "Brand:Link/Brand:100", "Item Group:Link/Item Group:100", "Brand:Link/Brand:100",
"Description::200", "Warehouse:Link/Warehouse:100", "Description::200", "Warehouse:Link/Warehouse:100",
"Stock UOM:Link/UOM:100", "Qty:Float:50", "Balance Qty:Float:80", "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"] "Batch:Link/Batch:100", "Serial #:Link/Serial No:100", "Company:Link/Company:100"]
def get_stock_ledger_entries(filters): 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, return webnotes.conn.sql("""select concat_ws(" ", posting_date, posting_time) as date,
item_code, warehouse, actual_qty, qty_after_transaction, item_code, warehouse, actual_qty, qty_after_transaction,
stock_value, voucher_type, voucher_no, batch_no, serial_no, company stock_value, voucher_type, voucher_no, batch_no, serial_no, company
@ -66,6 +62,10 @@ def get_item_conditions(filters):
def get_sle_conditions(filters): def get_sle_conditions(filters):
conditions = [] 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"): if filters.get("warehouse"):
conditions.append("warehouse=%(warehouse)s") conditions.append("warehouse=%(warehouse)s")
if filters.get("voucher_no"): if filters.get("voucher_no"):

View File

@ -114,6 +114,13 @@ def update_entries_after(args, verbose=1):
else: else:
stock_value = sum((flt(batch[0]) * flt(batch[1]) for batch in stock_queue)) 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 stock_value_difference = stock_value - prev_stock_value
prev_stock_value = stock_value prev_stock_value = stock_value

View File

@ -2,7 +2,7 @@
{ {
"creation": "2013-02-01 10:36:25", "creation": "2013-02-01 10:36:25",
"docstatus": 0, "docstatus": 0,
"modified": "2013-11-02 14:06:26", "modified": "2013-12-14 17:27:02",
"modified_by": "Administrator", "modified_by": "Administrator",
"owner": "Administrator" "owner": "Administrator"
}, },
@ -278,6 +278,7 @@
{ {
"cancel": 0, "cancel": 0,
"doctype": "DocPerm", "doctype": "DocPerm",
"match": "customer",
"role": "Customer" "role": "Customer"
}, },
{ {

View File

@ -2,11 +2,12 @@
{ {
"creation": "2013-01-10 16:34:32", "creation": "2013-01-10 16:34:32",
"docstatus": 0, "docstatus": 0,
"modified": "2013-07-11 17:02:12", "modified": "2013-12-12 12:17:46",
"modified_by": "Administrator", "modified_by": "Administrator",
"owner": "Administrator" "owner": "Administrator"
}, },
{ {
"allow_rename": 1,
"doctype": "DocType", "doctype": "DocType",
"document_type": "Master", "document_type": "Master",
"icon": "icon-map-marker", "icon": "icon-map-marker",

View File

@ -2,11 +2,12 @@
{ {
"creation": "2013-01-10 16:34:32", "creation": "2013-01-10 16:34:32",
"docstatus": 0, "docstatus": 0,
"modified": "2013-10-08 16:48:50", "modified": "2013-12-12 12:18:19",
"modified_by": "Administrator", "modified_by": "Administrator",
"owner": "Administrator" "owner": "Administrator"
}, },
{ {
"allow_rename": 1,
"doctype": "DocType", "doctype": "DocType",
"document_type": "Master", "document_type": "Master",
"icon": "icon-user", "icon": "icon-user",