[conflicts] [merged]

This commit is contained in:
Rushabh Mehta 2013-05-02 16:02:59 +05:30
commit d3e00995db
71 changed files with 1249 additions and 360 deletions

View File

@ -81,7 +81,7 @@ class DocType(DocTypeNestedSet):
"""
Cost Center name must be unique
"""
if (self.doc.__islocal or not self.doc.name) and webnotes.conn.sql("select name from `tabCost Center` where cost_center_name = %s and company_name=%s", (self.doc.cost_center_name, self.doc.company_name)):
if (self.doc.fields.get("__islocal") or not self.doc.name) and webnotes.conn.sql("select name from `tabCost Center` where cost_center_name = %s and company_name=%s", (self.doc.cost_center_name, self.doc.company_name)):
msgprint("Cost Center Name already exists, please rename", raise_exception=1)
self.validate_mandatory()

View File

@ -108,8 +108,8 @@ class DocType:
and not 'Accounts Manager' in webnotes.user.get_roles():
msgprint(_("Account") + ": " + self.doc.account + _(" has been freezed. \
Only Accounts Manager can do transaction against this account"), raise_exception=1)
if ret and ret[0]["company"] != self.doc.company:
if self.doc.is_cancelled in ("No", None) and ret and ret[0]["company"] != self.doc.company:
msgprint(_("Account") + ": " + self.doc.account + _(" does not belong to the company") \
+ ": " + self.doc.company, raise_exception=1)
@ -124,9 +124,10 @@ class DocType:
return self.cost_center_company[self.doc.cost_center]
if self.doc.cost_center and _get_cost_center_company() != self.doc.company:
msgprint(_("Cost Center") + ": " + self.doc.cost_center \
+ _(" does not belong to the company") + ": " + self.doc.company, raise_exception=True)
if self.doc.is_cancelled in ("No", None) and \
self.doc.cost_center and _get_cost_center_company() != self.doc.company:
msgprint(_("Cost Center") + ": " + self.doc.cost_center \
+ _(" does not belong to the company") + ": " + self.doc.company, raise_exception=True)
def check_freezing_date(self, adv_adj):
"""

View File

@ -1283,18 +1283,6 @@
"read_only": 0,
"report_hide": 1
},
{
"amend": 0,
"cancel": 0,
"create": 0,
"doctype": "DocPerm",
"match": "",
"permlevel": 1,
"report": 0,
"role": "Accounts Manager",
"submit": 0,
"write": 0
},
{
"amend": 1,
"cancel": 1,
@ -1302,33 +1290,10 @@
"doctype": "DocPerm",
"permlevel": 0,
"report": 1,
"role": "Accounts Manager",
"submit": 1,
"write": 1
},
{
"amend": 1,
"cancel": 0,
"create": 1,
"doctype": "DocPerm",
"permlevel": 0,
"report": 1,
"role": "Accounts User",
"submit": 1,
"write": 1
},
{
"amend": 0,
"cancel": 0,
"create": 0,
"doctype": "DocPerm",
"match": "",
"permlevel": 1,
"report": 0,
"role": "Accounts User",
"submit": 0,
"write": 0
},
{
"doctype": "DocPerm",
"match": "customer",
@ -1336,9 +1301,4 @@
"report": 1,
"role": "Customer"
},
{
"doctype": "DocPerm",
"permlevel": 0,
"role": "Retail User"
}
]

View File

@ -154,6 +154,11 @@ wn.module_page["Accounts"] = [
route: "query-report/Sales Register",
doctype: "Sales Invoice"
},
{
"label":wn._("Purchase Register"),
route: "query-report/Purchase Register",
doctype: "Purchase Invoice"
},
]
},
{
@ -182,6 +187,11 @@ wn.module_page["Accounts"] = [
right: true,
icon: "icon-list",
items: [
{
"label":wn._("Bank Reconciliation Statement"),
route: "query-report/Bank Reconciliation Statement",
doctype: "Journal Voucher"
},
{
"label":wn._("Delivered Items To Be Billed"),
route: "query-report/Delivered Items To Be Billed",
@ -192,6 +202,21 @@ wn.module_page["Accounts"] = [
route: "query-report/Ordered Items To Be Billed",
doctype: "Sales Invoice"
},
{
"label":wn._("Bank Clearance Summary"),
route: "query-report/Bank Clearance Summary",
doctype: "Journal Voucher"
},
{
"label":wn._("Payment Collection With Ageing"),
route: "query-report/Payment Collection With Ageing",
doctype: "Journal Voucher"
},
{
"label":wn._("Payment Made With Ageing"),
route: "query-report/Payment Made With Ageing",
doctype: "Journal Voucher"
},
]
}
]

View File

@ -186,7 +186,6 @@ erpnext.GeneralLedger = wn.views.GridReport.extend({
var totals = this.make_summary_row("Totals", this.account);
var grouped_ledgers = {};
$.each(data, function(i, item) {
if((me.is_default("company") ? true : me.apply_filter(item, "company")) &&
(me.account ? me.is_child_account(me.account, item.account)
@ -217,8 +216,7 @@ erpnext.GeneralLedger = wn.views.GridReport.extend({
grouped_ledgers[item.account].totals.debit += item.debit;
grouped_ledgers[item.account].totals.credit += item.credit;
}
if(me.account) {
if(item.account) {
item.against_account = me.voucher_accounts[item.voucher_type + ":"
+ item.voucher_no][(item.debit > 0 ? "credits" : "debits")].join(", ");
}

View File

@ -1,6 +1,8 @@
from __future__ import unicode_literals
import webnotes
from webnotes.utils import getdate, nowdate, flt, cstr
from webnotes import msgprint, _
from accounts.report.accounts_receivable.accounts_receivable import get_ageing_data
def execute(filters=None):
if not filters: filters = {}
@ -19,7 +21,6 @@ def execute(filters=None):
and nowdate() or filters.get("report_date")
data = []
total_invoiced_amount = total_paid = total_outstanding = 0
for gle in entries:
if cstr(gle.against_voucher) == gle.voucher_no or not gle.against_voucher \
or [gle.against_voucher_type, gle.against_voucher] in entries_after_report_date:
@ -36,7 +37,7 @@ def execute(filters=None):
paid_amount = get_paid_amount(gle, filters.get("report_date") or nowdate(),
entries_after_report_date)
outstanding_amount = invoiced_amount - paid_amount
if abs(flt(outstanding_amount)) > 0.01:
row = [gle.posting_date, gle.account, gle.voucher_type, gle.voucher_no,
gle.remarks, account_supplier_type_map.get(gle.account), due_date, bill_no,
@ -47,16 +48,9 @@ def execute(filters=None):
ageing_based_on_date = due_date
else:
ageing_based_on_date = gle.posting_date
row += get_ageing_data(ageing_based_on_date, age_on, outstanding_amount)
# Add to total
total_invoiced_amount += flt(invoiced_amount)
total_paid += flt(paid_amount)
total_outstanding += flt(outstanding_amount)
data.append(row)
if data:
data.append(["", "", "", "", "", "", "", "Total", "", total_invoiced_amount, total_paid,
total_outstanding, "", "", "", ""])
return columns, data
@ -75,8 +69,7 @@ def get_gl_entries(filters, before_report_date=True):
gl_entries = []
gl_entries = webnotes.conn.sql("""select * from `tabGL Entry`
where ifnull(is_cancelled, 'No') = 'No' %s order by posting_date, account""" %
(conditions) % (", ".join(['%s']*len(supplier_accounts))),
tuple(supplier_accounts), as_dict=1)
(conditions), tuple(supplier_accounts), as_dict=1)
return gl_entries
def get_conditions(filters, before_report_date=True):
@ -87,13 +80,16 @@ def get_conditions(filters, before_report_date=True):
supplier_accounts = []
if filters.get("account"):
supplier_accounts = [filters["account"]]
elif filters.get("company"):
else:
supplier_accounts = webnotes.conn.sql_list("""select name from `tabAccount`
where ifnull(master_type, '') = 'Supplier' and docstatus < 2 %s""" %
conditions, filters)
if supplier_accounts:
conditions += " and account in (%s)"
conditions += " and account in (%s)" % (", ".join(['%s']*len(supplier_accounts)))
else:
msgprint(_("No Supplier Accounts found. Supplier Accounts are identified based on \
'Master Type' value in account record."), raise_exception=1)
if filters.get("report_date"):
if before_report_date:
@ -133,20 +129,4 @@ def get_paid_amount(gle, report_date, entries_after_report_date):
and against_voucher = %s and name != %s and ifnull(is_cancelled, 'No') = 'No'""",
(gle.account, report_date, gle.voucher_type, gle.voucher_no, gle.name))[0][0]
return flt(paid_amount)
def get_ageing_data(ageing_based_on_date, age_on, outstanding_amount):
val1 = val2 = val3 = val4 = diff = 0
diff = age_on and ageing_based_on_date \
and (getdate(age_on) - getdate(ageing_based_on_date)).days or 0
if diff <= 30:
val1 = outstanding_amount
elif 30 < diff <= 60:
val2 = outstanding_amount
elif 60 < diff <= 90:
val3 = outstanding_amount
elif diff > 90:
val4 = outstanding_amount
return [diff, val1, val2, val3, val4]
return flt(paid_amount)

View File

@ -2,11 +2,12 @@
{
"creation": "2013-04-22 16:16:03",
"docstatus": 0,
"modified": "2013-04-23 14:54:27",
"modified": "2013-04-30 17:55:54",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"add_total_row": 1,
"doctype": "Report",
"is_standard": "Yes",
"name": "__common__",

View File

@ -1,5 +1,6 @@
from __future__ import unicode_literals
import webnotes
from webnotes import msgprint, _
from webnotes.utils import getdate, nowdate, flt, cstr
def execute(filters=None):
@ -18,7 +19,6 @@ def execute(filters=None):
and nowdate() or filters.get("report_date")
data = []
total_invoiced_amount = total_payment = total_outstanding = 0
for gle in entries:
if cstr(gle.against_voucher) == gle.voucher_no or not gle.against_voucher \
or [gle.against_voucher_type, gle.against_voucher] in entries_after_report_date:
@ -41,17 +41,9 @@ def execute(filters=None):
else:
ageing_based_on_date = gle.posting_date
row += get_ageing_data(ageing_based_on_date, age_on, outstanding_amount)
# Add to total
total_invoiced_amount += flt(invoiced_amount)
total_payment += flt(payment_amount)
total_outstanding += flt(outstanding_amount)
data.append(row)
if data:
data.append(["", "", "", "", "", "", "Total", total_invoiced_amount, total_payment,
total_outstanding, "", "", "", ""])
return columns, data
def get_columns():
@ -67,8 +59,7 @@ def get_gl_entries(filters, upto_report_date=True):
conditions, customer_accounts = get_conditions(filters, upto_report_date)
return webnotes.conn.sql("""select * from `tabGL Entry`
where ifnull(is_cancelled, 'No') = 'No' %s order by posting_date, account""" %
(conditions) % (", ".join(['%s']*len(customer_accounts))),
tuple(customer_accounts), as_dict=1)
(conditions), tuple(customer_accounts), as_dict=1)
def get_conditions(filters, upto_report_date=True):
conditions = ""
@ -78,13 +69,16 @@ def get_conditions(filters, upto_report_date=True):
customer_accounts = []
if filters.get("account"):
customer_accounts = [filters["account"]]
elif filters.get("company"):
else:
customer_accounts = webnotes.conn.sql_list("""select name from `tabAccount`
where ifnull(master_type, '') = 'Customer' and docstatus < 2 %s""" %
conditions, filters)
if customer_accounts:
conditions += " and account in (%s)"
conditions += " and account in (%s)" % (", ".join(['%s']*len(customer_accounts)))
else:
msgprint(_("No Customer Accounts found. Customer Accounts are identified based on \
'Master Type' value in account record."), raise_exception=1)
if filters.get("report_date"):
if upto_report_date:
@ -105,7 +99,7 @@ def get_account_territory_map():
def get_si_due_date_map():
""" get due_date from sales invoice """
si_due_date_map = {}
for t in webnotes.conn.sql("""select name, due_date from `tabSales Invoice` group by name"""):
for t in webnotes.conn.sql("""select name, due_date from `tabSales Invoice`"""):
si_due_date_map[t[0]] = t[1]
return si_due_date_map

View File

@ -2,11 +2,12 @@
{
"creation": "2013-04-16 11:31:13",
"docstatus": 0,
"modified": "2013-04-16 11:31:13",
"modified": "2013-04-30 17:54:47",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"add_total_row": 1,
"doctype": "Report",
"is_standard": "Yes",
"name": "__common__",

View File

@ -0,0 +1,32 @@
wn.query_reports["Bank Clearance Summary"] = {
"filters": [
{
"fieldname":"from_date",
"label": "From Date",
"fieldtype": "Date",
"default": wn.defaults.get_user_default("year_start_date"),
"width": "80"
},
{
"fieldname":"to_date",
"label": "To Date",
"fieldtype": "Date",
"default": get_today()
},
{
"fieldname":"account",
"label": "Bank Account",
"fieldtype": "Link",
"options": "Account",
"get_query": function() {
return {
"query": "accounts.utils.get_account_list",
"filters": {
"is_pl_account": "No",
"account_type": "Bank or Cash"
}
}
}
},
]
}

View File

@ -0,0 +1,54 @@
# ERPNext - web based ERP (http://erpnext.com)
# Copyright (C) 2012 Web Notes Technologies Pvt Ltd
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from __future__ import unicode_literals
import webnotes
from webnotes import _, msgprint
def execute(filters=None):
if not filters: filters = {}
columns = get_columns()
data = get_entries(filters)
return columns, data
def get_columns():
return ["Journal Voucher:Link/Journal Voucher:140", "Account:Link/Account:140",
"Posting Date:Date:100", "Clearance Date:Date:110", "Against Account:Link/Account:200",
"Debit:Currency:120", "Credit:Currency:120"
]
def get_conditions(filters):
conditions = ""
if not filters.get("account"):
msgprint(_("Please select Bank Account"), raise_exception=1)
else:
conditions += " and jvd.account = %(account)s"
if filters.get("from_date"): conditions += " and jv.posting_date>=%(from_date)s"
if filters.get("to_date"): conditions += " and jv.posting_date<=%(to_date)s"
return conditions
def get_entries(filters):
conditions = get_conditions(filters)
entries = webnotes.conn.sql("""select jv.name, jvd.account, jv.posting_date,
jv.clearance_date, jvd.against_account, jvd.debit, jvd.credit
from `tabJournal Voucher Detail` jvd, `tabJournal Voucher` jv
where jvd.parent = jv.name and jv.docstatus=1 %s
order by jv.name DESC""" % conditions, filters, as_list=1)
return entries

View File

@ -0,0 +1,21 @@
[
{
"creation": "2013-05-01 12:13:25",
"docstatus": 0,
"modified": "2013-05-01 12:13:25",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"doctype": "Report",
"is_standard": "Yes",
"name": "__common__",
"ref_doctype": "Journal Voucher",
"report_name": "Bank Clearance Summary",
"report_type": "Script Report"
},
{
"doctype": "Report",
"name": "Bank Clearance Summary"
}
]

View File

@ -0,0 +1,25 @@
wn.query_reports["Bank Reconciliation Statement"] = {
"filters": [
{
"fieldname":"account",
"label": "Bank Account",
"fieldtype": "Link",
"options": "Account",
"get_query": function() {
return {
"query": "accounts.utils.get_account_list",
"filters": {
"is_pl_account": "No",
"account_type": "Bank or Cash"
}
}
}
},
{
"fieldname":"report_date",
"label": "Date",
"fieldtype": "Date",
"default": get_today()
},
]
}

View File

@ -0,0 +1,79 @@
# ERPNext - web based ERP (http://erpnext.com)
# Copyright (C) 2012 Web Notes Technologies Pvt Ltd
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from __future__ import unicode_literals
import webnotes
from webnotes import _, msgprint
from webnotes.utils import flt
def execute(filters=None):
if not filters: filters = {}
columns = get_columns()
data = get_entries(filters)
from accounts.utils import get_balance_on
balance_as_per_company = get_balance_on(filters["account"], filters["report_date"])
total_debit, total_credit = 0,0
for d in data:
total_debit += flt(d[4])
total_credit += flt(d[5])
if webnotes.conn.get_value("Account", filters["account"], "debit_or_credit") == 'Debit':
bank_bal = flt(balance_as_per_company) - flt(total_debit) + flt(total_credit)
else:
bank_bal = flt(balance_as_per_company) + flt(total_debit) - flt(total_credit)
data += [
["", "", "", "Balance as per company books", balance_as_per_company, ""],
["", "", "", "Amounts not reflected in bank", total_debit, total_credit],
["", "", "", "Balance as per bank", bank_bal, ""]
]
return columns, data
def get_columns():
return ["Journal Voucher:Link/Journal Voucher:140", "Posting Date:Date:100",
"Clearance Date:Date:110", "Against Account:Link/Account:200",
"Debit:Currency:120", "Credit:Currency:120"
]
def get_conditions(filters):
conditions = ""
if not filters.get("account"):
msgprint(_("Please select Bank Account"), raise_exception=1)
else:
conditions += " and jvd.account = %(account)s"
if not filters.get("report_date"):
msgprint(_("Please select Date on which you want to run the report"), raise_exception=1)
else:
conditions += """ and jv.posting_date <= %(report_date)s
and ifnull(jv.clearance_date, '4000-01-01') > %(report_date)s"""
return conditions
def get_entries(filters):
conditions = get_conditions(filters)
entries = webnotes.conn.sql("""select jv.name, jv.posting_date, jv.clearance_date,
jvd.against_account, jvd.debit, jvd.credit
from `tabJournal Voucher Detail` jvd, `tabJournal Voucher` jv
where jvd.parent = jv.name and jv.docstatus=1 and ifnull(jv.cheque_no, '')!= '' %s
order by jv.name DESC""" % conditions, filters, as_list=1)
return entries

View File

@ -0,0 +1,22 @@
[
{
"creation": "2013-04-30 18:30:21",
"docstatus": 0,
"modified": "2013-05-01 10:53:12",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"add_total_row": 0,
"doctype": "Report",
"is_standard": "Yes",
"name": "__common__",
"ref_doctype": "Journal Voucher",
"report_name": "Bank Reconciliation Statement",
"report_type": "Script Report"
},
{
"doctype": "Report",
"name": "Bank Reconciliation Statement"
}
]

View File

@ -1,8 +1,8 @@
[
{
"creation": "2013-02-22 17:55:23",
"creation": "2013-02-25 10:38:57",
"docstatus": 0,
"modified": "2013-02-23 14:35:28",
"modified": "2013-05-01 11:56:43",
"modified_by": "Administrator",
"owner": "Administrator"
},

View File

@ -0,0 +1,42 @@
wn.query_reports["Payment Collection With Ageing"] = {
"filters": [
{
"fieldname": "from_date",
"label": "From Date",
"fieldtype": "Date",
"default": wn.defaults.get_user_default("year_start_date"),
"width": "80"
},
{
"fieldname":"to_date",
"label": "To Date",
"fieldtype": "Date",
"default": get_today()
},
{
"fieldname":"account",
"label": "Customer Account",
"fieldtype": "Link",
"options": "Account",
"get_query": function() {
var company = wn.query_report.filters_by_name.company.get_value();
return {
"query": "accounts.utils.get_account_list",
"filters": {
"is_pl_account": "No",
"debit_or_credit": "Debit",
"company": company,
"master_type": "Customer"
}
}
}
},
{
"fieldname":"company",
"label": "Company",
"fieldtype": "Link",
"options": "Company",
"default": sys_defaults.company
},
]
}

View File

@ -0,0 +1,90 @@
# ERPNext - web based ERP (http://erpnext.com)
# Copyright (C) 2012 Web Notes Technologies Pvt Ltd
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from __future__ import unicode_literals
import webnotes
from webnotes import msgprint, _
from accounts.report.accounts_receivable.accounts_receivable import get_ageing_data
def execute(filters=None):
if not filters: filters = {}
columns = get_columns()
entries = get_entries(filters)
si_posting_date_map = get_si_posting_date_map()
data = []
for d in entries:
against_invoice_date = d.against_invoice and si_posting_date_map[d.against_invoice] or ""
row = [d.name, d.account, d.posting_date, d.against_invoice, against_invoice_date,
d.debit, d.credit, d.cheque_no, d.cheque_date, d.remark]
if d.against_invoice:
row += get_ageing_data(against_invoice_date, d.posting_date, d.credit or -1*d.debit)
else:
row += ["", "", "", "", ""]
data.append(row)
return columns, data
def get_columns():
return ["Journal Voucher:Link/Journal Voucher:140", "Account:Link/Account:140",
"Posting Date:Date:100", "Against Invoice:Link/Sales Invoice:130",
"Against Invoice Posting Date:Date:130", "Debit:Currency:120", "Credit:Currency:120",
"Reference No::100", "Reference Date:Date:100", "Remarks::150", "Age:Int:40",
"0-30:Currency:100", "30-60:Currency:100", "60-90:Currency:100", "90-Above:Currency:100"
]
def get_conditions(filters):
conditions = ""
customer_accounts = []
if filters.get("account"):
customer_accounts = [filters["account"]]
else:
cond = filters.get("company") and (" and company = '%s'" % filters["company"]) or ""
customer_accounts = webnotes.conn.sql_list("""select name from `tabAccount`
where ifnull(master_type, '') = 'Customer' and docstatus < 2 %s""" % cond)
if customer_accounts:
conditions += " and jvd.account in (%s)" % (", ".join(['%s']*len(customer_accounts)))
else:
msgprint(_("No Customer Accounts found. Customer Accounts are identified based on \
'Master Type' value in account record."), raise_exception=1)
if filters.get("from_date"): conditions += " and jv.posting_date >= '%s'" % filters["from_date"]
if filters.get("to_date"): conditions += " and jv.posting_date <= '%s'" % filters["to_date"]
return conditions, customer_accounts
def get_entries(filters):
conditions, customer_accounts = get_conditions(filters)
entries = webnotes.conn.sql("""select jv.name, jvd.account, jv.posting_date,
jvd.against_invoice, jvd.debit, jvd.credit, jv.cheque_no, jv.cheque_date, jv.remark
from `tabJournal Voucher Detail` jvd, `tabJournal Voucher` jv
where jvd.parent = jv.name and jv.docstatus=1 %s order by jv.name DESC""" %
(conditions), tuple(customer_accounts), as_dict=1)
return entries
def get_si_posting_date_map():
si_posting_date_map = {}
for t in webnotes.conn.sql("""select name, posting_date from `tabSales Invoice`"""):
si_posting_date_map[t[0]] = t[1]
return si_posting_date_map

View File

@ -0,0 +1,22 @@
[
{
"creation": "2013-05-02 12:09:51",
"docstatus": 0,
"modified": "2013-05-02 12:09:51",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"add_total_row": 1,
"doctype": "Report",
"is_standard": "Yes",
"name": "__common__",
"ref_doctype": "Journal Voucher",
"report_name": "Payment Collection With Ageing",
"report_type": "Script Report"
},
{
"doctype": "Report",
"name": "Payment Collection With Ageing"
}
]

View File

@ -0,0 +1,40 @@
wn.query_reports["Payment Made With Ageing"] = {
"filters": [
{
fieldname: "from_date",
label: "From Date",
fieldtype: "Date",
default: wn.defaults.get_user_default("year_start_date"),
},
{
fieldname:"to_date",
label: "To Date",
fieldtype: "Date",
default: get_today()
},
{
fieldname:"account",
label: "Supplier Account",
fieldtype: "Link",
options: "Account",
get_query: function() {
return {
query: "accounts.utils.get_account_list",
filters: {
is_pl_account: "No",
debit_or_credit: "Credit",
company: wn.query_report.filters_by_name.company.get_value(),
master_type: "Supplier"
}
}
}
},
{
fieldname:"company",
label: "Company",
fieldtype: "Link",
options: "Company",
default: sys_defaults.company
},
]
}

View File

@ -0,0 +1,89 @@
# ERPNext - web based ERP (http://erpnext.com)
# Copyright (C) 2012 Web Notes Technologies Pvt Ltd
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from __future__ import unicode_literals
import webnotes
from webnotes import msgprint, _
from accounts.report.accounts_receivable.accounts_receivable import get_ageing_data
def execute(filters=None):
if not filters: filters = {}
columns = get_columns()
entries = get_entries(filters)
pi_posting_date_map = get_pi_posting_date_map()
data = []
for d in entries:
against_voucher_date = d.against_voucher and pi_posting_date_map[d.against_voucher] or ""
row = [d.name, d.account, d.posting_date, d.against_voucher, against_voucher_date,
d.debit, d.credit, d.cheque_no, d.cheque_date, d.remark]
if d.against_voucher:
row += get_ageing_data(against_voucher_date, d.posting_date, d.debit or -1*d.credit)
else:
row += ["", "", "", "", ""]
data.append(row)
return columns, data
def get_columns():
return ["Journal Voucher:Link/Journal Voucher:140", "Account:Link/Account:140",
"Posting Date:Date:100", "Against Invoice:Link/Purchase Invoice:130",
"Against Invoice Posting Date:Date:130", "Debit:Currency:120", "Credit:Currency:120",
"Reference No::100", "Reference Date:Date:100", "Remarks::150", "Age:Int:40",
"0-30:Currency:100", "30-60:Currency:100", "60-90:Currency:100", "90-Above:Currency:100"
]
def get_conditions(filters):
conditions = ""
supplier_accounts = []
if filters.get("account"):
supplier_accounts = [filters["account"]]
else:
cond = filters.get("company") and (" and company = '%s'" % filters["company"]) or ""
supplier_accounts = webnotes.conn.sql_list("""select name from `tabAccount`
where ifnull(master_type, '') = 'Supplier' and docstatus < 2 %s""" % cond)
if supplier_accounts:
conditions += " and jvd.account in (%s)" % (", ".join(['%s']*len(supplier_accounts)))
else:
msgprint(_("No Supplier Accounts found. Supplier Accounts are identified based on \
'Master Type' value in account record."), raise_exception=1)
if filters.get("from_date"): conditions += " and jv.posting_date >= '%s'" % filters["from_date"]
if filters.get("to_date"): conditions += " and jv.posting_date <= '%s'" % filters["to_date"]
return conditions, supplier_accounts
def get_entries(filters):
conditions, supplier_accounts = get_conditions(filters)
entries = webnotes.conn.sql("""select jv.name, jvd.account, jv.posting_date,
jvd.against_voucher, jvd.debit, jvd.credit, jv.cheque_no, jv.cheque_date, jv.remark
from `tabJournal Voucher Detail` jvd, `tabJournal Voucher` jv
where jvd.parent = jv.name and jv.docstatus=1 %s order by jv.name DESC""" %
(conditions), tuple(supplier_accounts), as_dict=1)
return entries
def get_pi_posting_date_map():
pi_posting_date_map = {}
for t in webnotes.conn.sql("""select name, posting_date from `tabPurchase Invoice`"""):
pi_posting_date_map[t[0]] = t[1]
return pi_posting_date_map

View File

@ -0,0 +1,22 @@
[
{
"creation": "2013-05-02 12:10:21",
"docstatus": 0,
"modified": "2013-05-02 12:10:21",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"add_total_row": 1,
"doctype": "Report",
"is_standard": "Yes",
"name": "__common__",
"ref_doctype": "Journal Voucher",
"report_name": "Payment Made With Ageing",
"report_type": "Script Report"
},
{
"doctype": "Report",
"name": "Payment Made With Ageing"
}
]

View File

@ -0,0 +1,42 @@
wn.query_reports["Purchase Register"] = {
"filters": [
{
"fieldname":"from_date",
"label": "From Date",
"fieldtype": "Date",
"default": wn.defaults.get_user_default("year_start_date"),
"width": "80"
},
{
"fieldname":"to_date",
"label": "To Date",
"fieldtype": "Date",
"default": get_today()
},
{
"fieldname":"account",
"label": "Account",
"fieldtype": "Link",
"options": "Account",
"get_query": function() {
var company = wn.query_report.filters_by_name.company.get_value();
return {
"query": "accounts.utils.get_account_list",
"filters": {
"is_pl_account": "No",
"debit_or_credit": "Credit",
"company": company,
"master_type": "Supplier"
}
}
}
},
{
"fieldname":"company",
"label": "Company",
"fieldtype": "Link",
"options": "Company",
"default": sys_defaults.company
}
]
}

View File

@ -0,0 +1,146 @@
# ERPNext - web based ERP (http://erpnext.com)
# Copyright (C) 2012 Web Notes Technologies Pvt Ltd
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from __future__ import unicode_literals
import webnotes
from webnotes.utils import flt
def execute(filters=None):
if not filters: filters = {}
columns, expense_accounts, tax_accounts = get_columns()
invoice_list = get_invoices(filters)
invoice_expense_map = get_invoice_expense_map(invoice_list)
invoice_tax_map = get_invoice_tax_map(invoice_list)
invoice_po_pr_map = get_invoice_po_pr_map(invoice_list)
account_map = get_account_details(invoice_list)
data = []
for inv in invoice_list:
# invoice details
purchase_order = ", ".join(invoice_po_pr_map.get(inv.name, {}).get("purchase_order", []))
purchase_receipt = ", ".join(invoice_po_pr_map.get(inv.name, {}).get("purchase_receipt", []))
row = [inv.name, inv.posting_date, inv.supplier, inv.credit_to,
account_map.get(inv.credit_to), inv.project_name, inv.bill_no, inv.bill_date,
inv.remarks, purchase_order, purchase_receipt]
# map expense values
for expense_acc in expense_accounts:
row.append(invoice_expense_map.get(inv.name, {}).get(expense_acc))
# net total
row.append(inv.net_total)
# tax account
for tax_acc in tax_accounts:
row.append(invoice_tax_map.get(inv.name, {}).get(tax_acc))
# total tax, grand total
row += [inv.total_tax, inv.grand_total]
data.append(row)
return columns, data
def get_columns():
"""return columns based on filters"""
columns = [
"Invoice:Link/Purchase Invoice:120", "Posting Date:Date:80", "Supplier:Link/Supplier:120",
"Supplier Account:Link/Account:120", "Account Group:LInk/Account:120",
"Project:Link/Project:80", "Bill No::120", "Bill Date:Date:80", "Remarks::150",
"Purchase Order:Link/Purchase Order:100", "Purchase Receipt:Link/Purchase Receipt:100"
]
expense_accounts = webnotes.conn.sql_list("""select distinct expense_head
from `tabPurchase Invoice Item` where docstatus = 1 and ifnull(expense_head, '') != ''
order by expense_head""")
tax_accounts = webnotes.conn.sql_list("""select distinct account_head
from `tabPurchase Taxes and Charges` where parenttype = 'Purchase Invoice'
and docstatus = 1 and ifnull(account_head, '') != '' order by account_head""")
columns = columns + [(account + ":Currency:120") for account in expense_accounts] + \
["Net Total:Currency:120"] + [(account + ":Currency:120") for account in tax_accounts] + \
["Total Tax:Currency:120"] + ["Grand Total:Currency:120"]
return columns, expense_accounts, tax_accounts
def get_conditions(filters):
conditions = ""
if filters.get("company"): conditions += " and company=%(company)s"
if filters.get("account"): conditions += " and account = %(account)s"
if filters.get("from_date"): conditions += " and posting_date>=%(from_date)s"
if filters.get("to_date"): conditions += " and posting_date<=%(to_date)s"
return conditions
def get_invoices(filters):
conditions = get_conditions(filters)
return webnotes.conn.sql("""select name, posting_date, credit_to, project_name, supplier,
bill_no, bill_date, remarks, net_total, total_tax, grand_total
from `tabPurchase Invoice` where docstatus = 1 %s
order by posting_date desc, name desc""" % conditions, filters, as_dict=1)
def get_invoice_expense_map(invoice_list):
expense_details = webnotes.conn.sql("""select parent, expense_head, sum(amount) as amount
from `tabPurchase Invoice Item` where parent in (%s) group by parent, expense_head""" %
', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]), as_dict=1)
invoice_expense_map = {}
for d in expense_details:
invoice_expense_map.setdefault(d.parent, webnotes._dict()).setdefault(d.expense_head, [])
invoice_expense_map[d.parent][d.expense_head] = flt(d.amount)
return invoice_expense_map
def get_invoice_tax_map(invoice_list):
tax_details = webnotes.conn.sql("""select parent, account_head, sum(tax_amount) as tax_amount
from `tabPurchase Taxes and Charges` where parent in (%s) group by parent, account_head""" %
', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]), as_dict=1)
invoice_tax_map = {}
for d in tax_details:
invoice_tax_map.setdefault(d.parent, webnotes._dict()).setdefault(d.account_head, [])
invoice_tax_map[d.parent][d.account_head] = flt(d.tax_amount)
return invoice_tax_map
def get_invoice_po_pr_map(invoice_list):
pi_items = webnotes.conn.sql("""select parent, purchase_order, purchase_receipt
from `tabPurchase Invoice Item` where parent in (%s)
and (ifnull(purchase_order, '') != '' or ifnull(purchase_receipt, '') != '')""" %
', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]), as_dict=1)
invoice_po_pr_map = {}
for d in pi_items:
if d.purchase_order:
invoice_po_pr_map.setdefault(d.parent, webnotes._dict()).setdefault(
"purchase_order", []).append(d.purchase_order)
if d.purchase_receipt:
invoice_po_pr_map.setdefault(d.parent, webnotes._dict()).setdefault(
"purchase_receipt", []).append(d.purchase_receipt)
return invoice_po_pr_map
def get_account_details(invoice_list):
account_map = {}
accounts = list(set([inv.credit_to for inv in invoice_list]))
for acc in webnotes.conn.sql("""select name, parent_account from tabAccount
where name in (%s)""" % ", ".join(["%s"]*len(accounts)), tuple(accounts), as_dict=1):
account_map[acc.name] = acc.parent_account
return account_map

View File

@ -0,0 +1,22 @@
[
{
"creation": "2013-04-29 16:13:11",
"docstatus": 0,
"modified": "2013-04-30 17:51:19",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"add_total_row": 1,
"doctype": "Report",
"is_standard": "Yes",
"name": "__common__",
"ref_doctype": "Purchase Invoice",
"report_name": "Purchase Register",
"report_type": "Script Report"
},
{
"doctype": "Report",
"name": "Purchase Register"
}
]

View File

@ -94,8 +94,8 @@ def get_conditions(filters):
def get_invoices(filters):
conditions = get_conditions(filters)
return webnotes.conn.sql("""select name, posting_date, territory, debit_to, territory,
project_name, customer, remarks, net_total, other_charges_total, grand_total
return webnotes.conn.sql("""select name, posting_date, debit_to, project_name, customer,
remarks, net_total, other_charges_total, grand_total
from `tabSales Invoice` where docstatus = 1 %s
order by posting_date desc, name desc""" % conditions, filters, as_dict=1)
@ -145,7 +145,6 @@ def get_customer_deatils(invoice_list):
customers = list(set([inv.customer for inv in invoice_list]))
for cust in webnotes.conn.sql("""select name, territory from `tabCustomer`
where name in (%s)""" % ", ".join(["%s"]*len(customers)), tuple(customers), as_dict=1):
customer_map.setdefault(cust.name, "")
customer_map[cust.name] = cust.territory
return customer_map
@ -155,7 +154,6 @@ def get_account_details(invoice_list):
accounts = list(set([inv.debit_to for inv in invoice_list]))
for acc in webnotes.conn.sql("""select name, parent_account from tabAccount
where name in (%s)""" % ", ".join(["%s"]*len(accounts)), tuple(accounts), as_dict=1):
account_map.setdefault(acc.name, "")
account_map[acc.name] = acc.parent_account
return account_map

View File

@ -2,11 +2,12 @@
{
"creation": "2013-04-23 18:15:29",
"docstatus": 0,
"modified": "2013-04-23 18:15:29",
"modified": "2013-04-30 17:53:10",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"add_total_row": 1,
"doctype": "Report",
"is_standard": "Yes",
"name": "__common__",

View File

@ -1,29 +1,32 @@
[
{
"owner": "Administrator",
"creation": "2012-05-14 18:05:41",
"docstatus": 0,
"creation": "2012-04-03 12:49:50",
"modified": "2013-04-30 14:49:06",
"modified_by": "Administrator",
"modified": "2012-04-03 12:49:50"
"owner": "Administrator"
},
{
"description": "Bank Clearance report",
"parent_doc_type": "Journal Voucher",
"module": "Accounts",
"standard": "Yes",
"sort_order": "DESC",
"filters": "{'Journal Voucher\u0001Submitted':1,'Journal Voucher\u0001Voucher Type':'','Journal Voucher\u0001Is Opening':'','Journal Voucher\u0001Fiscal Year':'','Journal Voucher\u0001Company':'','Journal Voucher\u0001TDS Applicable':'','Journal Voucher\u0001TDS Category':''}",
"dis_filters": "fiscal_year",
"doc_type": "Journal Voucher Detail",
"name": "__common__",
"doctype": "Search Criteria",
"sort_by": "ID",
"page_len": 50,
"columns": "Journal Voucher\u0001ID,Journal Voucher Detail\u0001Account,Journal Voucher Detail\u0001Debit,Journal Voucher Detail\u0001Credit,Journal Voucher\u0001Clearance Date,Journal Voucher\u0001Cheque No,Journal Voucher\u0001Cheque Date,Journal Voucher\u0001Voucher Date,Journal Voucher\u0001Posting Date,Journal Voucher Detail\u0001Against Payable,Journal Voucher Detail\u0001Against Receivable",
"criteria_name": "Bank Clearance report",
"columns": "Journal Voucher\u0001ID,Journal Voucher Detail\u0001Account,Journal Voucher Detail\u0001Debit,Journal Voucher Detail\u0001Credit,Journal Voucher\u0001Clearance Date,Journal Voucher\u0001Cheque No,Journal Voucher\u0001Cheque Date,Journal Voucher\u0001Voucher Date,Journal Voucher\u0001Posting Date,Journal Voucher Detail\u0001Against Payable,Journal Voucher Detail\u0001Against Receivable"
"custom_query": "",
"description": "Bank Clearance report",
"dis_filters": "fiscal_year",
"disabled": 0,
"doc_type": "Journal Voucher Detail",
"doctype": "Search Criteria",
"filters": "{'Journal Voucher\u0001Submitted':1,'Journal Voucher\u0001Voucher Type':'','Journal Voucher\u0001Is Opening':'','Journal Voucher\u0001Fiscal Year':'','Journal Voucher\u0001Company':'','Journal Voucher\u0001TDS Applicable':'','Journal Voucher\u0001TDS Category':''}",
"module": "Accounts",
"name": "__common__",
"page_len": 50,
"parent_doc_type": "Journal Voucher",
"report_script": null,
"sort_by": "ID",
"sort_order": "DESC",
"standard": "Yes"
},
{
"name": "bank_clearance_report",
"doctype": "Search Criteria"
"doctype": "Search Criteria",
"name": "bank_clearance_report"
}
]

View File

@ -27,6 +27,12 @@ class TestPurchaseOrder(unittest.TestCase):
po.insert()
self.assertEquals(len(po.doclist.get({"parentfield": "po_raw_material_details"})), 2)
def test_warehouse_company_validation(self):
from controllers.buying_controller import WrongWarehouseCompany
po = webnotes.bean(copy=test_records[0])
po.doc.company = "_Test Company 1"
self.assertRaises(WrongWarehouseCompany, po.insert)
test_dependencies = ["BOM"]

View File

@ -47,7 +47,7 @@ cur_frm.cscript.make_address = function() {
if(!cur_frm.address_list) {
cur_frm.address_list = new wn.ui.Listing({
parent: cur_frm.fields_dict['address_html'].wrapper,
page_length: 2,
page_length: 5,
new_doctype: "Address",
custom_new_doc: function(doctype) {
var address = wn.model.make_new_doc_and_get_name('Address');
@ -78,7 +78,7 @@ cur_frm.cscript.make_contact = function() {
if(!cur_frm.contact_list) {
cur_frm.contact_list = new wn.ui.Listing({
parent: cur_frm.fields_dict['contact_html'].wrapper,
page_length: 2,
page_length: 5,
new_doctype: "Contact",
custom_new_doc: function(doctype) {
var contact = wn.model.make_new_doc_and_get_name('Contact');

View File

@ -26,10 +26,13 @@ from webnotes.model.utils import round_floats_in_doc
from controllers.stock_controller import StockController
class WrongWarehouseCompany(Exception): pass
class BuyingController(StockController):
def validate(self):
super(BuyingController, self).validate()
self.validate_stock_or_nonstock_items()
self.validate_warehouse_belongs_to_company()
if self.meta.get_field("currency"):
self.company_currency = get_company_currency(self.doc.company)
self.validate_conversion_rate("currency", "conversion_rate")
@ -42,15 +45,24 @@ class BuyingController(StockController):
# set total in words
self.set_total_in_words()
def validate_warehouse_belongs_to_company(self):
for warehouse, company in webnotes.conn.get_values("Warehouse",
self.doclist.get_distinct_values("warehouse"), "company").items():
if company and company != self.doc.company:
webnotes.msgprint(_("Warehouse must belong to company") + \
(": %s (%s, %s)" % (warehouse, company, self.doc.company)),
raise_exception=WrongWarehouseCompany)
def validate_stock_or_nonstock_items(self):
items = [d.item_code for d in self.doclist.get({"parentfield": self.fname})]
if self.stock_items and len(items) > len(self.stock_items):
if self.stock_items:
nonstock_items = list(set(items) - set(self.stock_items))
webnotes.msgprint(_("Stock and non-stock items can not be entered at the same ") +
self.doc.doctype + _(""". You should make separate documents for them.
Stock Items: """) + ", ".join(self.stock_items) + _("""
Non-stock Items: """) + ", ".join(nonstock_items), raise_exception=1)
if nonstock_items:
webnotes.msgprint(_("Stock and non-stock items can not be entered in the same ") +
self.doc.doctype + _(""". You should make separate documents for them.
Stock Items: """) + ", ".join(self.stock_items) + _("""
Non-stock Items: """) + ", ".join(nonstock_items), raise_exception=1)
elif items and not self.stock_items:
tax_for_valuation = [d.account_head for d in

View File

@ -1,6 +1,12 @@
erpnext.updates = [
["2nd May", ["Buying: Warehouse must belong to same company as transaction",
"Price List: Added Currency Field. One price list can have only one currency",
"Item: Naming can now be by series or item code",
"Naming Series: Set number of digits in series (optionally)"]],
["18th April", ["Cost Center: Set a default Cost Center for a Company"]],
["12th April", ["Employee: List of Leave Approvers who can approve the Employee's Leave Applications"]],
["10th April", ["Redesigned File Uploads and added File Manager in Setup"]],
["3rd April", ["Update Manager: Open source users can update their ERPNext instance from Setup > Update Manager"]],
["27th March", ["Rename multiple items together. Go to Setup > Rename Tool"]],
["26th March", ["Added project to Stock Ledger and Balance",
"Added Default Cash Account in Company."]],

View File

@ -1,12 +1,13 @@
[
{
"creation": "2013-01-10 16:34:13",
"creation": "2013-01-22 16:50:30",
"docstatus": 0,
"modified": "2013-01-22 14:25:38",
"modified": "2013-05-02 11:22:59",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"allow_rename": 1,
"autoname": "field:deduction_name",
"doctype": "DocType",
"document_type": "Master",

View File

@ -1,12 +1,13 @@
[
{
"creation": "2013-01-10 16:34:13",
"creation": "2013-01-24 11:03:32",
"docstatus": 0,
"modified": "2013-01-23 16:32:07",
"modified": "2013-05-02 11:22:48",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"allow_rename": 1,
"autoname": "field:earning_name",
"doctype": "DocType",
"document_type": "Master",

View File

@ -59,27 +59,22 @@ cur_frm.fields_dict["bom_operations"].grid.on_row_delete = function(cdt, cdn){
set_operation_no(doc);
}
cur_frm.cscript.item = function(doc, dt, dn) {
if (doc.item) {
get_server_fields('get_item_details', doc.item, '', doc, dt, dn, 1);
}
}
cur_frm.add_fetch("item", "description", "description");
cur_frm.add_fetch("item", "stock_uom", "uom");
cur_frm.cscript.workstation = function(doc,dt,dn) {
var d = locals[dt][dn];
if (d.workstation) {
var callback = function(r, rt) {
calculate_op_cost(doc, dt, dn);
calculate_total(doc);
}
get_server_fields('get_workstation_details', d.workstation,
'bom_operations', doc, dt, dn, 1, callback);
}
wn.model.with_doc("Workstation", d.workstation, function(i, v) {
d.hour_rate = v.hour_rate;
refresh_field("hour_rate");
calculate_op_cost(doc);
calculate_total(doc);
});
}
cur_frm.cscript.hour_rate = function(doc, dt, dn) {
calculate_op_cost(doc, dt, dn);
calculate_op_cost(doc);
calculate_total(doc);
}
@ -114,7 +109,7 @@ var get_bom_material_detail= function(doc, cdt, cdn) {
$.extend(d, r.message);
refresh_field("bom_materials");
doc = locals[doc.doctype][doc.name];
calculate_rm_cost(doc, cdt, cdn);
calculate_rm_cost(doc);
calculate_total(doc);
},
freeze: true
@ -124,7 +119,7 @@ var get_bom_material_detail= function(doc, cdt, cdn) {
cur_frm.cscript.qty = function(doc, cdt, cdn) {
calculate_rm_cost(doc, cdt, cdn);
calculate_rm_cost(doc);
calculate_total(doc);
}
@ -134,12 +129,12 @@ cur_frm.cscript.rate = function(doc, cdt, cdn) {
msgprint("You can not change rate if BOM mentioned agianst any item");
get_bom_material_detail(doc, cdt, cdn);
} else {
calculate_rm_cost(doc, cdt, cdn);
calculate_rm_cost(doc);
calculate_total(doc);
}
}
var calculate_op_cost = function(doc, dt, dn) {
var calculate_op_cost = function(doc) {
var op = getchildren('BOM Operation', doc.name, 'bom_operations');
total_op_cost = 0;
for(var i=0;i<op.length;i++) {
@ -151,7 +146,7 @@ var calculate_op_cost = function(doc, dt, dn) {
refresh_field('operating_cost');
}
var calculate_rm_cost = function(doc, dt, dn) {
var calculate_rm_cost = function(doc) {
var rm = getchildren('BOM Item', doc.name, 'bom_materials');
total_rm_cost = 0;
for(var i=0;i<rm.length;i++) {
@ -201,7 +196,7 @@ cur_frm.fields_dict['bom_materials'].grid.get_field('bom_no').get_query = functi
}
cur_frm.cscript.validate = function(doc, dt, dn) {
calculate_op_cost(doc, dt, dn);
calculate_rm_cost(doc, dt, dn);
calculate_op_cost(doc);
calculate_rm_cost(doc);
calculate_total(doc);
}

View File

@ -44,10 +44,11 @@ class DocType:
self.validate_main_item()
self.validate_operations()
self.validate_materials()
self.set_bom_material_details()
self.calculate_cost()
def on_update(self):
self.check_recursion()
self.calculate_cost()
self.update_exploded_items()
self.doc.save()
@ -73,15 +74,7 @@ class DocType:
from `tabItem` where name=%s""", item_code, as_dict = 1)
return item
def get_item_details(self, item_code):
res = webnotes.conn.sql("""select description, stock_uom as uom
from `tabItem` where name=%s""", item_code, as_dict = 1)
return res and res[0] or {}
def get_workstation_details(self,workstation):
return {'hour_rate': webnotes.conn.get_value("Workstation", workstation, "hour_rate")}
def validate_rm_item(self, item):
if item[0]['name'] == self.doc.item:
msgprint("Item_code: %s in materials tab cannot be same as FG Item",
@ -89,32 +82,42 @@ class DocType:
if not item or item[0]['docstatus'] == 2:
msgprint("Item %s does not exist in system" % item[0]['item_code'], raise_exception = 1)
def get_bom_material_detail(self):
def set_bom_material_details(self):
for item in self.doclist.get({"parentfield": "bom_materials"}):
ret = self.get_bom_material_detail({ "item_code": item.item_code, "bom_no": item.bom_no,
"qty": item.qty })
for r in ret:
if not item.fields.get(r):
item.fields[r] = ret[r]
def get_bom_material_detail(self, args=None):
""" Get raw material details like uom, desc and rate"""
arg = webnotes.form_dict.get('args')
import json
arg = json.loads(arg)
item = self.get_item_det(arg['item_code'])
if not args:
args = webnotes.form_dict.get('args')
import json
args = json.loads(args)
item = self.get_item_det(args['item_code'])
self.validate_rm_item(item)
arg['bom_no'] = arg['bom_no'] or item and cstr(item[0]['default_bom']) or ''
arg.update(item[0])
args['bom_no'] = args['bom_no'] or item and cstr(item[0]['default_bom']) or ''
args.update(item[0])
rate = self.get_rm_rate(arg)
rate = self.get_rm_rate(args)
ret_item = {
'description' : item and arg['description'] or '',
'stock_uom' : item and arg['stock_uom'] or '',
'bom_no' : arg['bom_no'],
'description' : item and args['description'] or '',
'stock_uom' : item and args['stock_uom'] or '',
'bom_no' : args['bom_no'],
'rate' : rate
}
return ret_item
def get_rm_rate(self, arg):
""" Get raw material rate as per selected method, if bom exists takes bom cost """
rate = 0
if arg['bom_no']:
rate = self.get_bom_unitcost(arg['bom_no'])
elif arg and (arg['is_purchase_item'] == 'Yes' or arg['is_sub_contracted_item'] == 'Yes'):
@ -183,11 +186,14 @@ class DocType:
if not item:
msgprint("Item %s does not exists in the system or expired." %
self.doc.item, raise_exception = 1)
elif item[0]['is_manufactured_item'] != 'Yes' \
and item[0]['is_sub_contracted_item'] != 'Yes':
msgprint("""As Item: %s is not a manufactured / sub-contracted item, \
you can not make BOM for it""" % self.doc.item, raise_exception = 1)
else:
ret = webnotes.conn.get_value("Item", self.doc.item, ["description", "stock_uom"])
self.doc.description = ret[0]
self.doc.uom = ret[1]
def validate_operations(self):
""" Check duplicate operation no"""
@ -293,9 +299,10 @@ class DocType:
"""Update workstation rate and calculates totals"""
total_op_cost = 0
for d in getlist(self.doclist, 'bom_operations'):
if d.workstation and not d.hour_rate:
d.hour_rate = webnotes.conn.get_value("Workstation", d.workstation, "hour_rate")
if d.hour_rate and d.time_in_mins:
d.operating_cost = flt(d.hour_rate) * flt(d.time_in_mins) / 60.0
d.save()
total_op_cost += flt(d.operating_cost)
self.doc.operating_cost = total_op_cost
@ -307,7 +314,6 @@ class DocType:
d.rate = self.get_bom_unitcost(d.bom_no)
d.amount = flt(d.rate) * flt(d.qty)
d.qty_consumed_per_unit = flt(d.qty) / flt(self.doc.quantity)
d.save()
total_rm_cost += d.amount
self.doc.raw_material_cost = total_rm_cost

View File

@ -5,28 +5,38 @@ def execute():
webnotes.reload_doc("core", "doctype", "file_data")
webnotes.reset_perms("File Data")
singles = webnotes.conn.sql_list("""select name from tabDocType
where ifnull(issingle,0)=1""")
singles = get_single_doctypes()
for doctype in webnotes.conn.sql_list("""select parent from tabDocField where
fieldname='file_list' and fieldtype='Text'"""):
if doctype in singles:
doc = webnotes.doc(doctype, doctype)
if doc.file_list:
update_for_doc(doctype, doc)
webnotes.conn.set_value(doctype, None, "file_list", None)
else:
try:
for doc in webnotes.conn.sql("""select name, file_list from `tab%s` where
ifnull(file_list, '')!=''""" % doctype, as_dict=True):
update_for_doc(doctype, doc)
webnotes.conn.commit()
webnotes.conn.sql("""alter table `tab%s` drop column file_list""" % doctype)
except Exception, e:
if e.args[0]!=1054: raise e
fieldname='file_list'"""):
update_file_list(doctype, singles)
webnotes.conn.sql("""delete from tabDocField where fieldname='file_list'
and parent=%s""", doctype)
export_to_files([["DocType", doctype]])
# export_to_files([["DocType", doctype]])
def get_single_doctypes():
return webnotes.conn.sql_list("""select name from tabDocType
where ifnull(issingle,0)=1""")
def update_file_list(doctype, singles):
if doctype in singles:
doc = webnotes.doc(doctype, doctype)
if doc.file_list:
update_for_doc(doctype, doc)
webnotes.conn.set_value(doctype, None, "file_list", None)
else:
try:
for doc in webnotes.conn.sql("""select name, file_list from `tab%s` where
ifnull(file_list, '')!=''""" % doctype, as_dict=True):
update_for_doc(doctype, doc)
webnotes.conn.commit()
webnotes.conn.sql("""alter table `tab%s` drop column `file_list`""" % doctype)
except Exception, e:
print webnotes.getTraceback()
if (e.args and e.args[0]!=1054) or not e.args:
raise e
def update_for_doc(doctype, doc):
for filedata in doc.file_list.split("\n"):
@ -45,10 +55,21 @@ def update_for_doc(doctype, doc):
exists = False
if exists:
webnotes.conn.sql("""update `tabFile Data`
set attached_to_doctype=%s, attached_to_name=%s
where name=%s""", (doctype, doc.name, fileid))
if webnotes.conn.exists("File Data", fileid):
try:
fd = webnotes.bean("File Data", fileid)
if not (fd.doc.attached_to_doctype and fd.doc.attached_to_name):
fd.doc.attached_to_doctype = doctype
fd.doc.attached_to_name = doc.name
fd.save()
else:
fd = webnotes.bean("File Data", copy=fd.doclist)
fd.doc.attached_to_doctype = doctype
fd.doc.attached_to_name = doc.name
fd.doc.name = None
fd.insert()
except webnotes.DuplicateEntryError:
pass
else:
webnotes.conn.sql("""delete from `tabFile Data` where name=%s""",
fileid)
fileid)

View File

@ -0,0 +1,18 @@
import webnotes
def execute():
from patches.april_2013.p05_update_file_data import update_file_list, get_single_doctypes
singles = get_single_doctypes()
for doctype in webnotes.conn.sql_list("""select table_name from `information_schema`.`columns`
where table_schema=%s and column_name='file_list'""", webnotes.conn.cur_db_name):
doctype = doctype[3:]
if not webnotes.conn.exists("DocType", doctype): continue
update_file_list(doctype, singles)
webnotes.conn.sql("""delete from `tabCustom Field` where fieldname='file_list'
and parent=%s""", doctype)
webnotes.conn.sql("""delete from `tabDocField` where fieldname='file_list'
and parent=%s""", doctype)

View File

@ -0,0 +1,4 @@
import webnotes
def execute():
from patches.january_2013 import rebuild_tree
rebuild_tree.execute()

View File

@ -246,4 +246,7 @@ patch_list = [
"execute:webnotes.delete_doc('DocType Mapper', 'Delivery Note-Packing Slip')",
"execute:webnotes.reload_doc('Stock', 'DocType', 'Delivery Note Item')",
"patches.april_2013.p06_default_cost_center",
"execute:webnotes.reset_perms('File Data')",
"patches.april_2013.p07_update_file_data_2",
"patches.april_2013.rebuild_sales_browser",
]

View File

@ -5,4 +5,4 @@ import webnotes
@webnotes.whitelist()
def get_time_log_list(doctype, txt, searchfield, start, page_len, filters):
return webnotes.conn.get_values("Time Log", filters, ["name", "activity_type", "owner"], debug=True)
return webnotes.conn.get_values("Time Log", filters, ["name", "activity_type", "owner"])

View File

@ -57,7 +57,7 @@ cur_frm.cscript.make_address = function() {
if(!cur_frm.address_list) {
cur_frm.address_list = new wn.ui.Listing({
parent: cur_frm.fields_dict['address_html'].wrapper,
page_length: 2,
page_length: 5,
new_doctype: "Address",
custom_new_doc: function(doctype) {
var address = wn.model.make_new_doc_and_get_name('Address');
@ -88,7 +88,7 @@ cur_frm.cscript.make_contact = function() {
if(!cur_frm.contact_list) {
cur_frm.contact_list = new wn.ui.Listing({
parent: cur_frm.fields_dict['contact_html'].wrapper,
page_length: 2,
page_length: 5,
custom_new_doc: function(doctype) {
var contact = wn.model.make_new_doc_and_get_name('Contact');
contact = locals['Contact'][contact];

View File

@ -85,6 +85,7 @@ def backup_to_dropbox():
os.path.basename(backup.backup_path_db))
upload_file_to_dropbox(filename, "/database", dropbox_client)
webnotes.conn.close()
response = dropbox_client.metadata("/files")
# upload files to files folder
@ -108,6 +109,7 @@ def backup_to_dropbox():
did_not_upload.append(filename)
error_log.append(cstr(e))
webnotes.connect()
return did_not_upload, list(set(error_log))
def get_dropbox_session():

View File

@ -34,7 +34,6 @@ def get_gdrive_authorize_url():
"authorize_url": authorize_url,
}
@webnotes.whitelist()
def upload_files(name, mimetype, service, folder_id):
if not webnotes.conn:
webnotes.connect()
@ -78,6 +77,9 @@ def backup_to_gdrive():
did_not_upload = []
error_log = []
files_folder_id = webnotes.conn.get_value("Backup Manager", None, "files_folder_id")
webnotes.conn.close()
path = os.path.join(get_base_path(), "public", "files")
for filename in os.listdir(path):
found = False
@ -90,10 +92,7 @@ def backup_to_gdrive():
mimetype = mimetypes.types_map.get("." + ext) or "application/octet-stream"
#Compare Local File with Server File
param = {}
children = drive_service.children().list(
folderId=webnotes.conn.get_value("Backup Manager", None, "files_folder_id"),
**param).execute()
children = drive_service.children().list(folderId=files_folder_id).execute()
for child in children.get('items', []):
file = drive_service.files().get(fileId=child['id']).execute()
if filename == file['title'] and size == int(file['fileSize']):
@ -101,12 +100,12 @@ def backup_to_gdrive():
break
if not found:
try:
upload_files(filepath, mimetype, drive_service,
webnotes.conn.get_value("Backup Manager", None, "files_folder_id"))
upload_files(filepath, mimetype, drive_service, files_folder_id)
except Exception, e:
did_not_upload.append(filename)
error_log.append(cstr(e))
webnotes.connect()
return did_not_upload, list(set(error_log))
def get_gdrive_flow():

View File

@ -1,67 +1,90 @@
cur_frm.cscript.refresh = function(doc) {
cur_frm.disable_save();
}
//dropbox
cur_frm.cscript.allow_dropbox_access = function(doc) {
if (doc.send_notifications_to == '') {
msgprint("Please enter email address.")
}
else {
wn.call({
method: "setup.doctype.backup_manager.backup_dropbox.get_dropbox_authorize_url",
callback: function(r) {
if(!r.exc) {
cur_frm.set_value("dropbox_access_secret", r.message.secret);
cur_frm.set_value("dropbox_access_key", r.message.key);
cur_frm.save(null, function() {
window.open(r.message.url);
});
}
$.extend(cur_frm.cscript, {
refresh: function() {
cur_frm.disable_save();
if(!(cint(cur_frm.doc.dropbox_access_allowed) ||
cint(cur_frm.doc.gdrive_access_allowed))) {
cur_frm.set_intro(wn._("You can start by selecting backup frequency and \
granting access for sync"));
} else {
var services = {
"dropbox": wn._("Dropbox"),
"gdrive": wn._("Google Drive")
}
var active_services = [];
$.each(services, function(service, label) {
var access_allowed = cint(cur_frm.doc[service + "_access_allowed"]);
var frequency = cur_frm.doc["upload_backups_to_" + service];
if(access_allowed && frequency && frequency !== "Never") {
active_services.push(label + " [" + frequency + "]");
}
});
if(active_services.length > 0) {
cur_frm.set_intro(wn._("Backups will be uploaded to") + ": " +
wn.utils.comma_and(active_services));
} else {
cur_frm.set_intro("");
}
})
}
}
cur_frm.cscript.backup_right_now = function(doc) {
msgprint("Backing up and uploading. This may take a few minutes.")
wn.call({
method: "setup.doctype.backup_manager.backup_manager.take_backups_dropbox",
callback: function(r) {
msgprint("Backups taken. Please check your email for the response.")
}
})
}
//gdrive
cur_frm.cscript.allow_gdrive_access = function(doc) {
if (doc.send_notifications_to == '') {
msgprint("Please enter email address.")
}
else {
wn.call({
method: "setup.doctype.backup_manager.backup_googledrive.get_gdrive_authorize_url",
callback: function(r) {
if(!r.exc) {
window.open(r.message.authorize_url);
},
validate_send_notifications_to: function() {
if(!cur_frm.doc.send_notifications_to) {
msgprint(wn._("Please specify") + ": " +
wn._(wn.meta.get_label(cur_frm.doctype, "send_notifications_to")));
return false;
}
return true;
},
allow_dropbox_access: function() {
if(cur_frm.cscript.validate_send_notifications_to()) {
wn.call({
method: "setup.doctype.backup_manager.backup_dropbox.get_dropbox_authorize_url",
callback: function(r) {
if(!r.exc) {
cur_frm.set_value("dropbox_access_secret", r.message.secret);
cur_frm.set_value("dropbox_access_key", r.message.key);
cur_frm.save(null, function() {
window.open(r.message.url);
});
}
}
}
})
}
}
cur_frm.cscript.validate_gdrive = function(doc) {
wn.call({
method: "setup.doctype.backup_manager.backup_googledrive.gdrive_callback",
args: {
verification_code: doc.verification_code
},
});
}
cur_frm.cscript.upload_backups_to_dropbox = function(doc) {
cur_frm.save()
}
cur_frm.cscript.upload_backups_to_gdrive = function(doc) {
cur_frm.save()
}
});
}
},
allow_gdrive_access: function() {
if(cur_frm.cscript.validate_send_notifications_to()) {
wn.call({
method: "setup.doctype.backup_manager.backup_googledrive.get_gdrive_authorize_url",
callback: function(r) {
if(!r.exc) {
window.open(r.message.authorize_url);
}
}
});
}
},
validate_gdrive: function() {
wn.call({
method: "setup.doctype.backup_manager.backup_googledrive.gdrive_callback",
args: {
verification_code: cur_frm.doc.verification_code
},
});
},
upload_backups_to_dropbox: function() {
cur_frm.save();
},
upload_backups_to_gdrive: function() {
cur_frm.save();
},
});

View File

@ -20,8 +20,8 @@ def take_backups_if(freq):
if webnotes.conn.get_value("Backup Manager", None, "upload_backups_to_dropbox")==freq:
take_backups_dropbox()
if webnotes.conn.get_value("Backup Manager", None, "upload_backups_to_gdrive")==freq:
take_backups_gdrive()
# if webnotes.conn.get_value("Backup Manager", None, "upload_backups_to_gdrive")==freq:
# take_backups_gdrive()
@webnotes.whitelist()
def take_backups_dropbox():
@ -35,7 +35,7 @@ def take_backups_dropbox():
except Exception:
file_and_error = [" - ".join(f) for f in zip(did_not_upload, error_log)]
error_message = ("\n".join(file_and_error) + "\n" + webnotes.getTraceback())
print error_message
webnotes.errprint(error_message)
send_email(False, "Dropbox", error_message)
#backup to gdrive
@ -51,7 +51,7 @@ def take_backups_gdrive():
except Exception:
file_and_error = [" - ".join(f) for f in zip(did_not_upload, error_log)]
error_message = ("\n".join(file_and_error) + "\n" + webnotes.getTraceback())
print error_message
webnotes.errprint(error_message)
send_email(False, "Google Drive", error_message)
def send_email(success, service_name, error_status=None):

View File

@ -1,8 +1,8 @@
[
{
"creation": "2013-03-15 11:06:59",
"creation": "2013-04-30 12:58:38",
"docstatus": 0,
"modified": "2013-03-15 17:27:33",
"modified": "2013-05-02 11:42:08",
"modified_by": "Administrator",
"owner": "Administrator"
},
@ -109,6 +109,7 @@
"doctype": "DocField",
"fieldname": "sync_with_gdrive",
"fieldtype": "Section Break",
"hidden": 1,
"label": "Sync with Google Drive"
},
{

View File

@ -31,6 +31,7 @@ keydict = {
'item_group': 'default_item_group',
'customer_group': 'default_customer_group',
'cust_master_name': 'cust_master_name',
"item_naming_by": "item_naming_by",
'supplier_type': 'default_supplier_type',
'supp_master_name': 'supp_master_name',
'territory': 'default_territory',

View File

@ -1,8 +1,8 @@
[
{
"creation": "2013-03-25 11:08:14",
"creation": "2013-04-01 15:05:24",
"docstatus": 0,
"modified": "2013-03-28 15:41:03",
"modified": "2013-05-02 15:05:21",
"modified_by": "Administrator",
"owner": "Administrator"
},
@ -27,8 +27,6 @@
"permlevel": 0
},
{
"amend": 0,
"cancel": 0,
"create": 1,
"doctype": "DocPerm",
"name": "__common__",
@ -167,6 +165,13 @@
"read_only": 0,
"width": "50%"
},
{
"doctype": "DocField",
"fieldname": "item_naming_by",
"fieldtype": "Select",
"label": "Item Naming By",
"options": "Item Code\nNaming Series"
},
{
"doctype": "DocField",
"fieldname": "default_item_group",
@ -502,6 +507,11 @@
"label": "SMS Sender Name",
"read_only": 0
},
{
"amend": 0,
"cancel": 0,
"doctype": "DocPerm"
},
{
"doctype": "DocPerm"
}

View File

@ -123,7 +123,14 @@ class DocType:
def validate_series_name(self, n):
import re
if not re.match('[a-zA-Z0-9]+(([-/][a-zA-Z0-9])?[-/][a-zA-Z0-9]*)*',n):
if "." in n:
parts = n.split(".")
if len(parts) > 2:
msgprint("Only one dot (.) allowed in " + n, raise_exception=1)
if not re.match("#+$", parts[-1]):
msgprint("Numbering series must be in hashes (e.g. ####)", raise_exception=1)
n = n[0]
if not re.match("^[a-zA-Z0-9-/]*$", n):
msgprint('Special Characters except "-" and "/" not allowed in naming series')
raise Exception

View File

@ -1,8 +1,8 @@
[
{
"creation": "2013-01-10 16:34:23",
"creation": "2013-01-25 11:35:08",
"docstatus": 0,
"modified": "2013-01-22 14:56:34",
"modified": "2013-05-02 15:34:41",
"modified_by": "Administrator",
"owner": "Administrator"
},
@ -25,8 +25,6 @@
"permlevel": 0
},
{
"amend": 0,
"cancel": 0,
"create": 1,
"doctype": "DocPerm",
"name": "__common__",
@ -62,7 +60,7 @@
"fieldname": "help_html",
"fieldtype": "HTML",
"label": "Help HTML",
"options": "<div class=\"help-box\">\nEdit list of Series in the box below. Each Series Prefix on a new line.<br><br>\nAllowed special characters are \"/\" and \"-\"<br>\nExamples:<br>\nINV-<br>\nINV-10-<br>\nINVK-<br>\n</div>"
"options": "<div class=\"well\">\nEdit list of Series in the box below. Rules:\n<ul>\n<li>Each Series Prefix on a new line.</li>\n<li>Allowed special characters are \"/\" and \"-\"</li>\n<li>Optionally, set the number of digits in the series using dot (.) followed by hashes (#). For example, \".####\" means that the series will have four digits. Default is five digits.</li>\n</ul>\nExamples:<br>\nINV-<br>\nINV-10-<br>\nINVK-<br>\nINV-.####<br>\n</div>"
},
{
"doctype": "DocField",

View File

@ -2,7 +2,7 @@
{
"creation": "2013-01-25 11:35:09",
"docstatus": 0,
"modified": "2013-01-22 14:56:41",
"modified": "2013-05-02 14:44:24",
"modified_by": "Administrator",
"owner": "Administrator"
},
@ -52,13 +52,21 @@
"oldfieldtype": "Data",
"reqd": 1
},
{
"doctype": "DocField",
"fieldname": "currency",
"fieldtype": "Link",
"label": "Currency",
"options": "Currency",
"reqd": 1
},
{
"depends_on": "price_list_name",
"doctype": "DocField",
"fieldname": "how_to_upload",
"fieldtype": "HTML",
"label": "How to upload",
"options": "<div class=\"help\">Use the <a href=\"#data-import-tool\">Data Import Tool</a> to upload, update Item Prices in bulk:\n<ol> \n<li>Go to Data Import Tool.\n<li>Select \"Item\"\n<li>Check on \"With Data\"\n<li>Download \"Item Price\" from Child Tables.\n<li>Update the prices required and add new rows if required.\n<li>Check on \"Overwrite\"\n<li>Upload the modified sheet.\n</div>\n"
"options": "<div class=\"well\">Use the <a href=\"#data-import-tool\">Data Import Tool</a> to upload, update Item Prices in bulk:\n<ol> \n<li>Go to Data Import Tool.\n<li>Select \"Item\"\n<li>Check on \"With Data\"\n<li>Download \"Item Price\" from Child Tables.\n<li>Update the prices required and add new rows if required.\n<li>Check on \"Overwrite\"\n<li>Upload the modified sheet.\n</div>\n"
},
{
"cancel": 0,
@ -78,7 +86,6 @@
"cancel": 1,
"create": 1,
"doctype": "DocPerm",
"match": "",
"role": "Sales Master Manager",
"write": 1
}

View File

@ -1,6 +1,7 @@
test_records = [
[{
"doctype": "Price List",
"price_list_name": "_Test Price List"
"price_list_name": "_Test Price List",
"currency": "INR"
}]
]

View File

@ -1,8 +1,8 @@
[
{
"creation": "2013-03-01 19:09:43",
"creation": "2013-03-05 14:50:38",
"docstatus": 0,
"modified": "2013-03-01 08:22:16",
"modified": "2013-05-01 15:49:47",
"modified_by": "Administrator",
"owner": "harshada@webnotestech.com"
},
@ -24,14 +24,19 @@
"permlevel": 0
},
{
"cancel": 1,
"create": 1,
"doctype": "DocPerm",
"name": "__common__",
"parent": "Batch",
"parentfield": "permissions",
"parenttype": "DocType",
"permlevel": 0,
"read": 1,
"report": 1,
"role": "Material Master Manager",
"submit": 0
"submit": 0,
"write": 1
},
{
"doctype": "DocType",
@ -94,28 +99,6 @@
"oldfieldtype": "Date"
},
{
"doctype": "DocField",
"fieldname": "trash_reason",
"fieldtype": "Small Text",
"label": "Trash Reason",
"oldfieldname": "trash_reason",
"oldfieldtype": "Small Text",
"read_only": 1
},
{
"cancel": 1,
"create": 1,
"doctype": "DocPerm",
"permlevel": 0,
"report": 1,
"write": 1
},
{
"amend": 0,
"cancel": 0,
"create": 0,
"doctype": "DocPerm",
"match": "",
"permlevel": 1
"doctype": "DocPerm"
}
]

View File

@ -326,6 +326,17 @@ if (sys_defaults.auto_inventory_accounting) {
}
// cost center
cur_frm.cscript.cost_center = function(doc, cdt, cdn){
var d = locals[cdt][cdn];
if(d.cost_center) {
var cl = getchildren('Delivery Note Item', doc.name, cur_frm.cscript.fname, doc.doctype);
for(var i = 0; i < cl.length; i++){
if(!cl[i].cost_center) cl[i].cost_center = d.cost_center;
}
}
refresh_field(cur_frm.cscript.fname);
}
cur_frm.fields_dict.delivery_note_details.grid.get_field("cost_center").get_query = function(doc) {
return {
query: "accounts.utils.get_cost_center_list",

View File

@ -14,11 +14,17 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
cur_frm.add_fetch("price_list_name", "currency", "ref_currency")
cur_frm.cscript.refresh = function(doc) {
// make sensitive fields(has_serial_no, is_stock_item, valuation_method)
// read only if any stock ledger entry exists
cur_frm.toggle_enable("item_code", doc.__islocal);
cur_frm.toggle_display("naming_series", sys_defaults.item_naming_by=="Naming Series"
&& doc.__islocal)
cur_frm.toggle_display("item_code", sys_defaults.item_naming_by!="Naming Series"
&& doc.__islocal)
if ((!doc.__islocal) && (doc.is_stock_item == 'Yes')) {
var callback = function(r, rt) {

View File

@ -23,7 +23,17 @@ from webnotes.model.bean import getlist
from webnotes import msgprint, _
from webnotes.model.controller import DocListController
class PriceListCurrencyMismatch(Exception): pass
class DocType(DocListController):
def autoname(self):
if webnotes.conn.get_default("item_naming_by")=="Naming Series":
from webnotes.model.doc import make_autoname
self.doc.item_code = make_autoname(self.doc.naming_series+'.#####')
self.doc.name = self.doc.item_code
def validate(self):
if not self.doc.stock_uom:
msgprint(_("Please enter Default Unit of Measure"), raise_exception=1)
@ -33,7 +43,7 @@ class DocType(DocListController):
self.add_default_uom_in_conversion_factor_table()
self.valiadte_item_type()
self.check_for_active_boms()
self.check_ref_rate_detail()
self.validate_price_lists()
self.fill_customer_code()
self.check_item_tax()
self.validate_barcode()
@ -55,12 +65,13 @@ class DocType(DocListController):
ch.conversion_factor = 1
def check_stock_uom_with_bin(self):
bin = webnotes.conn.sql("select stock_uom from `tabBin` where item_code = %s",
self.doc.item_code)
if self.doc.stock_uom and bin and cstr(bin[0][0]) \
and cstr(bin[0][0]) != cstr(self.doc.stock_uom):
msgprint(_("Please Update Stock UOM with the help of Stock UOM Replace Utility."),
raise_exception=1)
if not self.doc.fields.get("__islocal"):
bin = webnotes.conn.sql("select stock_uom from `tabBin` where item_code = %s",
self.doc.name)
if self.doc.stock_uom and bin and cstr(bin[0][0]) \
and cstr(bin[0][0]) != cstr(self.doc.stock_uom):
msgprint(_("Please Update Stock UOM with the help of Stock UOM Replace Utility."),
raise_exception=1)
def validate_conversion_factor(self):
check_list = []
@ -120,16 +131,21 @@ class DocType(DocListController):
if cstr(self.doc.fields.get(d)) != 'Yes':
_check_for_active_boms(fl[d])
def check_ref_rate_detail(self):
check_list=[]
def validate_price_lists(self):
price_lists=[]
for d in getlist(self.doclist,'ref_rate_details'):
if [cstr(d.price_list_name), cstr(d.ref_currency),
cint(d.selling), cint(d.buying)] in check_list:
msgprint("Ref Rate is entered twice for Price List : '%s' and Currency : '%s'." %
(d.price_list_name,d.ref_currency), raise_exception=1)
if d.price_list_name in price_lists:
msgprint(_("Cannot have two prices for same Price List") + ": " + d.price_list_name,
raise_exception= webnotes.DuplicateEntryError)
else:
check_list.append([cstr(d.price_list_name),cstr(d.ref_currency)])
price_list_currency = webnotes.conn.get_value("Price List", d.price_list_name, "currency")
if price_list_currency and d.ref_currency != price_list_currency:
msgprint(_("Currency does not match Price List Currency for Price List") \
+ ": " + d.price_list_name, raise_exception=PriceListCurrencyMismatch)
price_lists.append(d.price_list_name)
def fill_customer_code(self):
""" Append all the customer codes and insert into "customer_code" field of item table """
cust_code=[]
@ -154,13 +170,14 @@ class DocType(DocListController):
def validate_barcode(self):
if self.doc.barcode:
duplicate = webnotes.conn.sql("select name from tabItem where barcode = %s and name != %s", (self.doc.barcode, self.doc.name))
duplicate = webnotes.conn.sql("""select name from tabItem where barcode = %s
and name != %s""", (self.doc.barcode, self.doc.name))
if duplicate:
msgprint("Barcode: %s already used in item: %s" %
(self.doc.barcode, cstr(duplicate[0][0])), raise_exception = 1)
def check_non_asset_warehouse(self):
if self.doc.is_asset_item == "Yes":
if not self.doc.__islocal and self.doc.is_asset_item == "Yes":
existing_qty = webnotes.conn.sql("select t1.warehouse, t1.actual_qty from tabBin t1, tabWarehouse t2 where t1.item_code=%s and (t2.warehouse_type!='Fixed Asset' or t2.warehouse_type is null) and t1.warehouse=t2.name and t1.actual_qty > 0", self.doc.name)
for e in existing_qty:
msgprint("%s Units exist in Warehouse %s, which is not an Asset Warehouse." %

View File

@ -2,7 +2,7 @@
{
"creation": "2013-03-28 10:35:28",
"docstatus": 0,
"modified": "2013-04-23 11:44:39",
"modified": "2013-05-02 15:10:53",
"modified_by": "Administrator",
"owner": "Administrator"
},
@ -34,7 +34,6 @@
"parent": "Item",
"parentfield": "permissions",
"parenttype": "DocType",
"permlevel": 0,
"read": 1,
"submit": 0
},
@ -51,6 +50,13 @@
"oldfieldtype": "Section Break",
"read_only": 0
},
{
"doctype": "DocField",
"fieldname": "naming_series",
"fieldtype": "Select",
"label": "Naming Series",
"options": "\nITEM"
},
{
"description": "Item will be saved by this name in the data base.",
"doctype": "DocField",

View File

@ -20,6 +20,22 @@ import webnotes
test_ignore = ["BOM"]
class TestItem(unittest.TestCase):
def test_duplicate_price_list(self):
item = webnotes.bean(copy=test_records[0])
item.doc.item_code = "_Test Item 10"
item_price = item.doclist.get({"doctype": "Item Price"})[0]
item.doclist.append(webnotes.doc(item_price.fields.copy()))
self.assertRaises(webnotes.DuplicateEntryError, item.insert)
def test_price_list_mismatch(self):
from stock.doctype.item.item import PriceListCurrencyMismatch
item = webnotes.bean(copy=test_records[0])
item.doc.item_code = "_Test Item 11"
item_price = item.doclist.get({"doctype": "Item Price"})[0].ref_currency="USD"
self.assertRaises(PriceListCurrencyMismatch, item.insert)
test_records = [
[{
"doctype": "Item",
@ -45,7 +61,14 @@ test_records = [
"warehouse": "_Test Warehouse",
"warehouse_reorder_level": 20,
"warehouse_reorder_qty": 20
}],
}, {
"doctype": "Item Price",
"parentfield": "ref_rate_details",
"price_list_name": "_Test Price List",
"ref_rate": 100,
"ref_currency": "INR"
}
],
[{
"doctype": "Item",
"item_code": "_Test Item Home Desktop 100",

View File

@ -263,6 +263,12 @@ class TestMaterialRequest(unittest.TestCase):
se = webnotes.bean(copy=se_doclist)
self.assertRaises(webnotes.MappingMismatchError, se.insert)
def test_warehouse_company_validation(self):
from controllers.buying_controller import WrongWarehouseCompany
mr = webnotes.bean(copy=test_records[0])
mr.doc.company = "_Test Company 1"
self.assertRaises(WrongWarehouseCompany, mr.insert)
test_records = [
[
{

View File

@ -114,7 +114,8 @@ class DocType:
def update_serial_purchase_details(self, obj, d, serial_no, is_submit, purpose = '', rejected=None):
exists = webnotes.conn.sql("select name, status, docstatus from `tabSerial No` where name = '%s'" % (serial_no))
if is_submit:
if exists and exists[0][2] != 2 and purpose not in ['Material Transfer', 'Sales Return']:
if exists and exists[0][2] != 2 and \
purpose not in ['Material Transfer', "Material Receipt", 'Sales Return']:
msgprint("Serial No: %s already %s" % (serial_no, exists and exists[0][1]), raise_exception = 1)
elif exists:
s = Document('Serial No', exists and exists[0][0])

View File

@ -2,7 +2,8 @@ test_records = [
[{
"doctype": "Warehouse",
"warehouse_name": "_Test Warehouse",
"warehouse_type": "_Test Warehouse Type"
"warehouse_type": "_Test Warehouse Type",
"company": "_Test Company"
}],
[{
"doctype": "Warehouse",

View File

@ -95,6 +95,8 @@ erpnext.StockAgeing = erpnext.StockGridReport.extend({
this.data = [].concat(this._data);
this.serialized_buying_rates = this.get_serialized_buying_rates();
$.each(this.data, function(i, d) {
me.reset_item_values(d);
});

View File

@ -29,17 +29,13 @@ $.extend(cur_frm.cscript, {
erpnext.hide_naming_series();
cur_frm.cscript.make_listing(doc);
if(!doc.__islocal) {
if(in_list(user_roles,'System Manager')) {
if(doc.status!='Closed') cur_frm.add_custom_button('Close Ticket', cur_frm.cscript['Close Ticket']);
if(doc.status=='Closed') cur_frm.add_custom_button('Re-Open Ticket', cur_frm.cscript['Re-Open Ticket']);
}else if(doc.allocated_to) {
cur_frm.set_df_property('status','read_only', 1);
if(user==doc.allocated_to && doc.status!='Closed') cur_frm.add_custom_button('Close Ticket', cur_frm.cscript['Close Ticket']);
if(user_roles.indexOf("Support Manager")!==-1) {
if(doc.status!='Closed') cur_frm.add_custom_button('Close Ticket', cur_frm.cscript['Close Ticket']);
if(doc.status=='Closed') cur_frm.add_custom_button('Re-Open Ticket', cur_frm.cscript['Re-Open Ticket']);
}
cur_frm.set_df_property('subject','read_only', 1);
cur_frm.set_df_property('description','hidden', 1);
cur_frm.set_df_property('raised_by','read_only', 1);
cur_frm.toggle_enable(["subject", "raised_by"], false);
cur_frm.toggle_display("description", false);
}
refresh_field('status');
},

View File

@ -45,6 +45,10 @@ class DocType(TransactionBase):
def validate(self):
self.update_status()
if self.doc.status == "Closed":
from webnotes.widgets.form.assign_to import clear
clear(self.doc.doctype, self.doc.name)
def on_communication_sent(self, comm):
webnotes.conn.set(self.doc, 'status', 'Waiting for Customer')
if comm.lead and not self.doc.lead:

View File

@ -34,7 +34,8 @@ def upload(select_doctype=None, rows=None):
rename_log = []
for row in rows:
if len(row) > 2:
# if row has some content
if len(row) > 1 and row[0] and row[1]:
try:
if rename_doc(select_doctype, row[0], row[1]):
rename_log.append(_("Successful: ") + row[0] + " -> " + row[1])
@ -45,5 +46,5 @@ def upload(select_doctype=None, rows=None):
rename_log.append("<span style='color: RED'>" + \
_("Failed: ") + row[0] + " -> " + row[1] + "</span>")
rename_log.append("<span style='margin-left: 20px;'>" + repr(e) + "</span>")
return rename_log