[conflicts] [merged]

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

View File

@@ -81,7 +81,7 @@ class DocType(DocTypeNestedSet):
""" """
Cost Center name must be unique 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) msgprint("Cost Center Name already exists, please rename", raise_exception=1)
self.validate_mandatory() self.validate_mandatory()

View File

@@ -109,7 +109,7 @@ class DocType:
msgprint(_("Account") + ": " + self.doc.account + _(" has been freezed. \ msgprint(_("Account") + ": " + self.doc.account + _(" has been freezed. \
Only Accounts Manager can do transaction against this account"), raise_exception=1) 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") \ msgprint(_("Account") + ": " + self.doc.account + _(" does not belong to the company") \
+ ": " + self.doc.company, raise_exception=1) + ": " + self.doc.company, raise_exception=1)
@@ -124,7 +124,8 @@ class DocType:
return self.cost_center_company[self.doc.cost_center] return self.cost_center_company[self.doc.cost_center]
if self.doc.cost_center and _get_cost_center_company() != self.doc.company: 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 \ msgprint(_("Cost Center") + ": " + self.doc.cost_center \
+ _(" does not belong to the company") + ": " + self.doc.company, raise_exception=True) + _(" does not belong to the company") + ": " + self.doc.company, raise_exception=True)

View File

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

View File

@@ -154,6 +154,11 @@ wn.module_page["Accounts"] = [
route: "query-report/Sales Register", route: "query-report/Sales Register",
doctype: "Sales Invoice" 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, right: true,
icon: "icon-list", icon: "icon-list",
items: [ items: [
{
"label":wn._("Bank Reconciliation Statement"),
route: "query-report/Bank Reconciliation Statement",
doctype: "Journal Voucher"
},
{ {
"label":wn._("Delivered Items To Be Billed"), "label":wn._("Delivered Items To Be Billed"),
route: "query-report/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", route: "query-report/Ordered Items To Be Billed",
doctype: "Sales Invoice" 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 totals = this.make_summary_row("Totals", this.account);
var grouped_ledgers = {}; var grouped_ledgers = {};
$.each(data, function(i, item) { $.each(data, function(i, item) {
if((me.is_default("company") ? true : me.apply_filter(item, "company")) && if((me.is_default("company") ? true : me.apply_filter(item, "company")) &&
(me.account ? me.is_child_account(me.account, item.account) (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.debit += item.debit;
grouped_ledgers[item.account].totals.credit += item.credit; grouped_ledgers[item.account].totals.credit += item.credit;
} }
if(item.account) {
if(me.account) {
item.against_account = me.voucher_accounts[item.voucher_type + ":" item.against_account = me.voucher_accounts[item.voucher_type + ":"
+ item.voucher_no][(item.debit > 0 ? "credits" : "debits")].join(", "); + item.voucher_no][(item.debit > 0 ? "credits" : "debits")].join(", ");
} }

View File

@@ -1,6 +1,8 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import webnotes import webnotes
from webnotes.utils import getdate, nowdate, flt, cstr 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): def execute(filters=None):
if not filters: filters = {} if not filters: filters = {}
@@ -19,7 +21,6 @@ def execute(filters=None):
and nowdate() or filters.get("report_date") and nowdate() or filters.get("report_date")
data = [] data = []
total_invoiced_amount = total_paid = total_outstanding = 0
for gle in entries: for gle in entries:
if cstr(gle.against_voucher) == gle.voucher_no or not gle.against_voucher \ 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: or [gle.against_voucher_type, gle.against_voucher] in entries_after_report_date:
@@ -47,16 +48,9 @@ def execute(filters=None):
ageing_based_on_date = due_date ageing_based_on_date = due_date
else: else:
ageing_based_on_date = gle.posting_date ageing_based_on_date = gle.posting_date
row += get_ageing_data(ageing_based_on_date, age_on, outstanding_amount)
# Add to total row += get_ageing_data(ageing_based_on_date, age_on, outstanding_amount)
total_invoiced_amount += flt(invoiced_amount)
total_paid += flt(paid_amount)
total_outstanding += flt(outstanding_amount)
data.append(row) data.append(row)
if data:
data.append(["", "", "", "", "", "", "", "Total", "", total_invoiced_amount, total_paid,
total_outstanding, "", "", "", ""])
return columns, data return columns, data
@@ -75,8 +69,7 @@ def get_gl_entries(filters, before_report_date=True):
gl_entries = [] gl_entries = []
gl_entries = webnotes.conn.sql("""select * from `tabGL Entry` gl_entries = webnotes.conn.sql("""select * from `tabGL Entry`
where ifnull(is_cancelled, 'No') = 'No' %s order by posting_date, account""" % where ifnull(is_cancelled, 'No') = 'No' %s order by posting_date, account""" %
(conditions) % (", ".join(['%s']*len(supplier_accounts))), (conditions), tuple(supplier_accounts), as_dict=1)
tuple(supplier_accounts), as_dict=1)
return gl_entries return gl_entries
def get_conditions(filters, before_report_date=True): def get_conditions(filters, before_report_date=True):
@@ -87,13 +80,16 @@ def get_conditions(filters, before_report_date=True):
supplier_accounts = [] supplier_accounts = []
if filters.get("account"): if filters.get("account"):
supplier_accounts = [filters["account"]] supplier_accounts = [filters["account"]]
elif filters.get("company"): else:
supplier_accounts = webnotes.conn.sql_list("""select name from `tabAccount` supplier_accounts = webnotes.conn.sql_list("""select name from `tabAccount`
where ifnull(master_type, '') = 'Supplier' and docstatus < 2 %s""" % where ifnull(master_type, '') = 'Supplier' and docstatus < 2 %s""" %
conditions, filters) conditions, filters)
if supplier_accounts: 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 filters.get("report_date"):
if before_report_date: if before_report_date:
@@ -134,19 +130,3 @@ def get_paid_amount(gle, report_date, entries_after_report_date):
(gle.account, report_date, gle.voucher_type, gle.voucher_no, gle.name))[0][0] (gle.account, report_date, gle.voucher_type, gle.voucher_no, gle.name))[0][0]
return flt(paid_amount) 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]

View File

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

View File

@@ -1,5 +1,6 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import webnotes import webnotes
from webnotes import msgprint, _
from webnotes.utils import getdate, nowdate, flt, cstr from webnotes.utils import getdate, nowdate, flt, cstr
def execute(filters=None): def execute(filters=None):
@@ -18,7 +19,6 @@ def execute(filters=None):
and nowdate() or filters.get("report_date") and nowdate() or filters.get("report_date")
data = [] data = []
total_invoiced_amount = total_payment = total_outstanding = 0
for gle in entries: for gle in entries:
if cstr(gle.against_voucher) == gle.voucher_no or not gle.against_voucher \ 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: or [gle.against_voucher_type, gle.against_voucher] in entries_after_report_date:
@@ -42,15 +42,7 @@ def execute(filters=None):
ageing_based_on_date = gle.posting_date ageing_based_on_date = gle.posting_date
row += get_ageing_data(ageing_based_on_date, age_on, outstanding_amount) 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) data.append(row)
if data:
data.append(["", "", "", "", "", "", "Total", total_invoiced_amount, total_payment,
total_outstanding, "", "", "", ""])
return columns, data return columns, data
@@ -67,8 +59,7 @@ def get_gl_entries(filters, upto_report_date=True):
conditions, customer_accounts = get_conditions(filters, upto_report_date) conditions, customer_accounts = get_conditions(filters, upto_report_date)
return webnotes.conn.sql("""select * from `tabGL Entry` return webnotes.conn.sql("""select * from `tabGL Entry`
where ifnull(is_cancelled, 'No') = 'No' %s order by posting_date, account""" % where ifnull(is_cancelled, 'No') = 'No' %s order by posting_date, account""" %
(conditions) % (", ".join(['%s']*len(customer_accounts))), (conditions), tuple(customer_accounts), as_dict=1)
tuple(customer_accounts), as_dict=1)
def get_conditions(filters, upto_report_date=True): def get_conditions(filters, upto_report_date=True):
conditions = "" conditions = ""
@@ -78,13 +69,16 @@ def get_conditions(filters, upto_report_date=True):
customer_accounts = [] customer_accounts = []
if filters.get("account"): if filters.get("account"):
customer_accounts = [filters["account"]] customer_accounts = [filters["account"]]
elif filters.get("company"): else:
customer_accounts = webnotes.conn.sql_list("""select name from `tabAccount` customer_accounts = webnotes.conn.sql_list("""select name from `tabAccount`
where ifnull(master_type, '') = 'Customer' and docstatus < 2 %s""" % where ifnull(master_type, '') = 'Customer' and docstatus < 2 %s""" %
conditions, filters) conditions, filters)
if customer_accounts: 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 filters.get("report_date"):
if upto_report_date: if upto_report_date:
@@ -105,7 +99,7 @@ def get_account_territory_map():
def get_si_due_date_map(): def get_si_due_date_map():
""" get due_date from sales invoice """ """ get due_date from sales invoice """
si_due_date_map = {} 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] si_due_date_map[t[0]] = t[1]
return si_due_date_map return si_due_date_map

View File

@@ -2,11 +2,12 @@
{ {
"creation": "2013-04-16 11:31:13", "creation": "2013-04-16 11:31:13",
"docstatus": 0, "docstatus": 0,
"modified": "2013-04-16 11:31:13", "modified": "2013-04-30 17:54:47",
"modified_by": "Administrator", "modified_by": "Administrator",
"owner": "Administrator" "owner": "Administrator"
}, },
{ {
"add_total_row": 1,
"doctype": "Report", "doctype": "Report",
"is_standard": "Yes", "is_standard": "Yes",
"name": "__common__", "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, "docstatus": 0,
"modified": "2013-02-23 14:35:28", "modified": "2013-05-01 11:56:43",
"modified_by": "Administrator", "modified_by": "Administrator",
"owner": "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): def get_invoices(filters):
conditions = get_conditions(filters) conditions = get_conditions(filters)
return webnotes.conn.sql("""select name, posting_date, territory, debit_to, territory, return webnotes.conn.sql("""select name, posting_date, debit_to, project_name, customer,
project_name, customer, remarks, net_total, other_charges_total, grand_total remarks, net_total, other_charges_total, grand_total
from `tabSales Invoice` where docstatus = 1 %s from `tabSales Invoice` where docstatus = 1 %s
order by posting_date desc, name desc""" % conditions, filters, as_dict=1) 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])) customers = list(set([inv.customer for inv in invoice_list]))
for cust in webnotes.conn.sql("""select name, territory from `tabCustomer` for cust in webnotes.conn.sql("""select name, territory from `tabCustomer`
where name in (%s)""" % ", ".join(["%s"]*len(customers)), tuple(customers), as_dict=1): where name in (%s)""" % ", ".join(["%s"]*len(customers)), tuple(customers), as_dict=1):
customer_map.setdefault(cust.name, "")
customer_map[cust.name] = cust.territory customer_map[cust.name] = cust.territory
return customer_map return customer_map
@@ -155,7 +154,6 @@ def get_account_details(invoice_list):
accounts = list(set([inv.debit_to for inv in 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 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): 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 account_map[acc.name] = acc.parent_account
return account_map return account_map

View File

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

View File

@@ -1,29 +1,32 @@
[ [
{ {
"owner": "Administrator", "creation": "2012-05-14 18:05:41",
"docstatus": 0, "docstatus": 0,
"creation": "2012-04-03 12:49:50", "modified": "2013-04-30 14:49:06",
"modified_by": "Administrator", "modified_by": "Administrator",
"modified": "2012-04-03 12:49:50" "owner": "Administrator"
}, },
{ {
"description": "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",
"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,
"criteria_name": "Bank Clearance report", "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() po.insert()
self.assertEquals(len(po.doclist.get({"parentfield": "po_raw_material_details"})), 2) 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"] test_dependencies = ["BOM"]

View File

@@ -47,7 +47,7 @@ cur_frm.cscript.make_address = function() {
if(!cur_frm.address_list) { if(!cur_frm.address_list) {
cur_frm.address_list = new wn.ui.Listing({ cur_frm.address_list = new wn.ui.Listing({
parent: cur_frm.fields_dict['address_html'].wrapper, parent: cur_frm.fields_dict['address_html'].wrapper,
page_length: 2, page_length: 5,
new_doctype: "Address", new_doctype: "Address",
custom_new_doc: function(doctype) { custom_new_doc: function(doctype) {
var address = wn.model.make_new_doc_and_get_name('Address'); 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) { if(!cur_frm.contact_list) {
cur_frm.contact_list = new wn.ui.Listing({ cur_frm.contact_list = new wn.ui.Listing({
parent: cur_frm.fields_dict['contact_html'].wrapper, parent: cur_frm.fields_dict['contact_html'].wrapper,
page_length: 2, page_length: 5,
new_doctype: "Contact", new_doctype: "Contact",
custom_new_doc: function(doctype) { custom_new_doc: function(doctype) {
var contact = wn.model.make_new_doc_and_get_name('Contact'); 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 from controllers.stock_controller import StockController
class WrongWarehouseCompany(Exception): pass
class BuyingController(StockController): class BuyingController(StockController):
def validate(self): def validate(self):
super(BuyingController, self).validate() super(BuyingController, self).validate()
self.validate_stock_or_nonstock_items() self.validate_stock_or_nonstock_items()
self.validate_warehouse_belongs_to_company()
if self.meta.get_field("currency"): if self.meta.get_field("currency"):
self.company_currency = get_company_currency(self.doc.company) self.company_currency = get_company_currency(self.doc.company)
self.validate_conversion_rate("currency", "conversion_rate") self.validate_conversion_rate("currency", "conversion_rate")
@@ -43,11 +46,20 @@ class BuyingController(StockController):
# set total in words # set total in words
self.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): def validate_stock_or_nonstock_items(self):
items = [d.item_code for d in self.doclist.get({"parentfield": self.fname})] 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)) nonstock_items = list(set(items) - set(self.stock_items))
webnotes.msgprint(_("Stock and non-stock items can not be entered at the same ") + 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. self.doc.doctype + _(""". You should make separate documents for them.
Stock Items: """) + ", ".join(self.stock_items) + _(""" Stock Items: """) + ", ".join(self.stock_items) + _("""
Non-stock Items: """) + ", ".join(nonstock_items), raise_exception=1) Non-stock Items: """) + ", ".join(nonstock_items), raise_exception=1)

View File

@@ -1,6 +1,12 @@
erpnext.updates = [ 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"]], ["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"]], ["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"]], ["27th March", ["Rename multiple items together. Go to Setup > Rename Tool"]],
["26th March", ["Added project to Stock Ledger and Balance", ["26th March", ["Added project to Stock Ledger and Balance",
"Added Default Cash Account in Company."]], "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, "docstatus": 0,
"modified": "2013-01-22 14:25:38", "modified": "2013-05-02 11:22:59",
"modified_by": "Administrator", "modified_by": "Administrator",
"owner": "Administrator" "owner": "Administrator"
}, },
{ {
"allow_rename": 1,
"autoname": "field:deduction_name", "autoname": "field:deduction_name",
"doctype": "DocType", "doctype": "DocType",
"document_type": "Master", "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, "docstatus": 0,
"modified": "2013-01-23 16:32:07", "modified": "2013-05-02 11:22:48",
"modified_by": "Administrator", "modified_by": "Administrator",
"owner": "Administrator" "owner": "Administrator"
}, },
{ {
"allow_rename": 1,
"autoname": "field:earning_name", "autoname": "field:earning_name",
"doctype": "DocType", "doctype": "DocType",
"document_type": "Master", "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); set_operation_no(doc);
} }
cur_frm.cscript.item = function(doc, dt, dn) { cur_frm.add_fetch("item", "description", "description");
if (doc.item) { cur_frm.add_fetch("item", "stock_uom", "uom");
get_server_fields('get_item_details', doc.item, '', doc, dt, dn, 1);
}
}
cur_frm.cscript.workstation = function(doc,dt,dn) { cur_frm.cscript.workstation = function(doc,dt,dn) {
var d = locals[dt][dn]; var d = locals[dt][dn];
if (d.workstation) { wn.model.with_doc("Workstation", d.workstation, function(i, v) {
var callback = function(r, rt) { d.hour_rate = v.hour_rate;
calculate_op_cost(doc, dt, dn); refresh_field("hour_rate");
calculate_op_cost(doc);
calculate_total(doc); calculate_total(doc);
} });
get_server_fields('get_workstation_details', d.workstation,
'bom_operations', doc, dt, dn, 1, callback);
}
} }
cur_frm.cscript.hour_rate = function(doc, dt, dn) { cur_frm.cscript.hour_rate = function(doc, dt, dn) {
calculate_op_cost(doc, dt, dn); calculate_op_cost(doc);
calculate_total(doc); calculate_total(doc);
} }
@@ -114,7 +109,7 @@ var get_bom_material_detail= function(doc, cdt, cdn) {
$.extend(d, r.message); $.extend(d, r.message);
refresh_field("bom_materials"); refresh_field("bom_materials");
doc = locals[doc.doctype][doc.name]; doc = locals[doc.doctype][doc.name];
calculate_rm_cost(doc, cdt, cdn); calculate_rm_cost(doc);
calculate_total(doc); calculate_total(doc);
}, },
freeze: true freeze: true
@@ -124,7 +119,7 @@ var get_bom_material_detail= function(doc, cdt, cdn) {
cur_frm.cscript.qty = 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); 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"); msgprint("You can not change rate if BOM mentioned agianst any item");
get_bom_material_detail(doc, cdt, cdn); get_bom_material_detail(doc, cdt, cdn);
} else { } else {
calculate_rm_cost(doc, cdt, cdn); calculate_rm_cost(doc);
calculate_total(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'); var op = getchildren('BOM Operation', doc.name, 'bom_operations');
total_op_cost = 0; total_op_cost = 0;
for(var i=0;i<op.length;i++) { for(var i=0;i<op.length;i++) {
@@ -151,7 +146,7 @@ var calculate_op_cost = function(doc, dt, dn) {
refresh_field('operating_cost'); 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'); var rm = getchildren('BOM Item', doc.name, 'bom_materials');
total_rm_cost = 0; total_rm_cost = 0;
for(var i=0;i<rm.length;i++) { 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) { cur_frm.cscript.validate = function(doc, dt, dn) {
calculate_op_cost(doc, dt, dn); calculate_op_cost(doc);
calculate_rm_cost(doc, dt, dn); calculate_rm_cost(doc);
calculate_total(doc); calculate_total(doc);
} }

View File

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

View File

@@ -5,10 +5,22 @@ def execute():
webnotes.reload_doc("core", "doctype", "file_data") webnotes.reload_doc("core", "doctype", "file_data")
webnotes.reset_perms("File Data") webnotes.reset_perms("File Data")
singles = webnotes.conn.sql_list("""select name from tabDocType singles = get_single_doctypes()
where ifnull(issingle,0)=1""")
for doctype in webnotes.conn.sql_list("""select parent from tabDocField where for doctype in webnotes.conn.sql_list("""select parent from tabDocField where
fieldname='file_list' and fieldtype='Text'"""): 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]])
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: if doctype in singles:
doc = webnotes.doc(doctype, doctype) doc = webnotes.doc(doctype, doctype)
if doc.file_list: if doc.file_list:
@@ -20,13 +32,11 @@ def execute():
ifnull(file_list, '')!=''""" % doctype, as_dict=True): ifnull(file_list, '')!=''""" % doctype, as_dict=True):
update_for_doc(doctype, doc) update_for_doc(doctype, doc)
webnotes.conn.commit() webnotes.conn.commit()
webnotes.conn.sql("""alter table `tab%s` drop column file_list""" % doctype) webnotes.conn.sql("""alter table `tab%s` drop column `file_list`""" % doctype)
except Exception, e: except Exception, e:
if e.args[0]!=1054: raise e print webnotes.getTraceback()
if (e.args and e.args[0]!=1054) or not e.args:
webnotes.conn.sql("""delete from tabDocField where fieldname='file_list' raise e
and parent=%s""", doctype)
export_to_files([["DocType", doctype]])
def update_for_doc(doctype, doc): def update_for_doc(doctype, doc):
for filedata in doc.file_list.split("\n"): for filedata in doc.file_list.split("\n"):
@@ -45,10 +55,21 @@ def update_for_doc(doctype, doc):
exists = False exists = False
if exists: if exists:
webnotes.conn.sql("""update `tabFile Data` if webnotes.conn.exists("File Data", fileid):
set attached_to_doctype=%s, attached_to_name=%s try:
where name=%s""", (doctype, doc.name, fileid)) 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: else:
webnotes.conn.sql("""delete from `tabFile Data` where name=%s""", 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.delete_doc('DocType Mapper', 'Delivery Note-Packing Slip')",
"execute:webnotes.reload_doc('Stock', 'DocType', 'Delivery Note Item')", "execute:webnotes.reload_doc('Stock', 'DocType', 'Delivery Note Item')",
"patches.april_2013.p06_default_cost_center", "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() @webnotes.whitelist()
def get_time_log_list(doctype, txt, searchfield, start, page_len, filters): 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) { if(!cur_frm.address_list) {
cur_frm.address_list = new wn.ui.Listing({ cur_frm.address_list = new wn.ui.Listing({
parent: cur_frm.fields_dict['address_html'].wrapper, parent: cur_frm.fields_dict['address_html'].wrapper,
page_length: 2, page_length: 5,
new_doctype: "Address", new_doctype: "Address",
custom_new_doc: function(doctype) { custom_new_doc: function(doctype) {
var address = wn.model.make_new_doc_and_get_name('Address'); 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) { if(!cur_frm.contact_list) {
cur_frm.contact_list = new wn.ui.Listing({ cur_frm.contact_list = new wn.ui.Listing({
parent: cur_frm.fields_dict['contact_html'].wrapper, parent: cur_frm.fields_dict['contact_html'].wrapper,
page_length: 2, page_length: 5,
custom_new_doc: function(doctype) { custom_new_doc: function(doctype) {
var contact = wn.model.make_new_doc_and_get_name('Contact'); var contact = wn.model.make_new_doc_and_get_name('Contact');
contact = locals['Contact'][contact]; contact = locals['Contact'][contact];

View File

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

View File

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

View File

@@ -1,13 +1,48 @@
cur_frm.cscript.refresh = function(doc) { $.extend(cur_frm.cscript, {
refresh: function() {
cur_frm.disable_save(); cur_frm.disable_save();
}
//dropbox if(!(cint(cur_frm.doc.dropbox_access_allowed) ||
cur_frm.cscript.allow_dropbox_access = function(doc) { cint(cur_frm.doc.gdrive_access_allowed))) {
if (doc.send_notifications_to == '') { cur_frm.set_intro(wn._("You can start by selecting backup frequency and \
msgprint("Please enter email address.") granting access for sync"));
} else {
var services = {
"dropbox": wn._("Dropbox"),
"gdrive": wn._("Google Drive")
} }
else { 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("");
}
}
},
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({ wn.call({
method: "setup.doctype.backup_manager.backup_dropbox.get_dropbox_authorize_url", method: "setup.doctype.backup_manager.backup_dropbox.get_dropbox_authorize_url",
callback: function(r) { callback: function(r) {
@@ -19,25 +54,12 @@ cur_frm.cscript.allow_dropbox_access = function(doc) {
}); });
} }
} }
}) });
} }
} },
cur_frm.cscript.backup_right_now = function(doc) { allow_gdrive_access: function() {
msgprint("Backing up and uploading. This may take a few minutes.") if(cur_frm.cscript.validate_send_notifications_to()) {
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({ wn.call({
method: "setup.doctype.backup_manager.backup_googledrive.get_gdrive_authorize_url", method: "setup.doctype.backup_manager.backup_googledrive.get_gdrive_authorize_url",
callback: function(r) { callback: function(r) {
@@ -45,23 +67,24 @@ cur_frm.cscript.allow_gdrive_access = function(doc) {
window.open(r.message.authorize_url); window.open(r.message.authorize_url);
} }
} }
}) });
} }
} },
cur_frm.cscript.validate_gdrive = function(doc) { validate_gdrive: function() {
wn.call({ wn.call({
method: "setup.doctype.backup_manager.backup_googledrive.gdrive_callback", method: "setup.doctype.backup_manager.backup_googledrive.gdrive_callback",
args: { args: {
verification_code: doc.verification_code verification_code: cur_frm.doc.verification_code
}, },
}); });
} },
cur_frm.cscript.upload_backups_to_dropbox = function(doc) { upload_backups_to_dropbox: function() {
cur_frm.save() cur_frm.save();
} },
cur_frm.cscript.upload_backups_to_gdrive = function(doc) { upload_backups_to_gdrive: function() {
cur_frm.save() 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: if webnotes.conn.get_value("Backup Manager", None, "upload_backups_to_dropbox")==freq:
take_backups_dropbox() take_backups_dropbox()
if webnotes.conn.get_value("Backup Manager", None, "upload_backups_to_gdrive")==freq: # if webnotes.conn.get_value("Backup Manager", None, "upload_backups_to_gdrive")==freq:
take_backups_gdrive() # take_backups_gdrive()
@webnotes.whitelist() @webnotes.whitelist()
def take_backups_dropbox(): def take_backups_dropbox():
@@ -35,7 +35,7 @@ def take_backups_dropbox():
except Exception: except Exception:
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.getTraceback()) error_message = ("\n".join(file_and_error) + "\n" + webnotes.getTraceback())
print error_message webnotes.errprint(error_message)
send_email(False, "Dropbox", error_message) send_email(False, "Dropbox", error_message)
#backup to gdrive #backup to gdrive
@@ -51,7 +51,7 @@ def take_backups_gdrive():
except Exception: except Exception:
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.getTraceback()) error_message = ("\n".join(file_and_error) + "\n" + webnotes.getTraceback())
print error_message webnotes.errprint(error_message)
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):

View File

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

View File

@@ -31,6 +31,7 @@ keydict = {
'item_group': 'default_item_group', 'item_group': 'default_item_group',
'customer_group': 'default_customer_group', 'customer_group': 'default_customer_group',
'cust_master_name': 'cust_master_name', 'cust_master_name': 'cust_master_name',
"item_naming_by": "item_naming_by",
'supplier_type': 'default_supplier_type', 'supplier_type': 'default_supplier_type',
'supp_master_name': 'supp_master_name', 'supp_master_name': 'supp_master_name',
'territory': 'default_territory', '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, "docstatus": 0,
"modified": "2013-03-28 15:41:03", "modified": "2013-05-02 15:05:21",
"modified_by": "Administrator", "modified_by": "Administrator",
"owner": "Administrator" "owner": "Administrator"
}, },
@@ -27,8 +27,6 @@
"permlevel": 0 "permlevel": 0
}, },
{ {
"amend": 0,
"cancel": 0,
"create": 1, "create": 1,
"doctype": "DocPerm", "doctype": "DocPerm",
"name": "__common__", "name": "__common__",
@@ -167,6 +165,13 @@
"read_only": 0, "read_only": 0,
"width": "50%" "width": "50%"
}, },
{
"doctype": "DocField",
"fieldname": "item_naming_by",
"fieldtype": "Select",
"label": "Item Naming By",
"options": "Item Code\nNaming Series"
},
{ {
"doctype": "DocField", "doctype": "DocField",
"fieldname": "default_item_group", "fieldname": "default_item_group",
@@ -502,6 +507,11 @@
"label": "SMS Sender Name", "label": "SMS Sender Name",
"read_only": 0 "read_only": 0
}, },
{
"amend": 0,
"cancel": 0,
"doctype": "DocPerm"
},
{ {
"doctype": "DocPerm" "doctype": "DocPerm"
} }

View File

@@ -123,7 +123,14 @@ class DocType:
def validate_series_name(self, n): def validate_series_name(self, n):
import re 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') msgprint('Special Characters except "-" and "/" not allowed in naming series')
raise Exception raise Exception

View File

@@ -1,8 +1,8 @@
[ [
{ {
"creation": "2013-01-10 16:34:23", "creation": "2013-01-25 11:35:08",
"docstatus": 0, "docstatus": 0,
"modified": "2013-01-22 14:56:34", "modified": "2013-05-02 15:34:41",
"modified_by": "Administrator", "modified_by": "Administrator",
"owner": "Administrator" "owner": "Administrator"
}, },
@@ -25,8 +25,6 @@
"permlevel": 0 "permlevel": 0
}, },
{ {
"amend": 0,
"cancel": 0,
"create": 1, "create": 1,
"doctype": "DocPerm", "doctype": "DocPerm",
"name": "__common__", "name": "__common__",
@@ -62,7 +60,7 @@
"fieldname": "help_html", "fieldname": "help_html",
"fieldtype": "HTML", "fieldtype": "HTML",
"label": "Help 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", "doctype": "DocField",

View File

@@ -2,7 +2,7 @@
{ {
"creation": "2013-01-25 11:35:09", "creation": "2013-01-25 11:35:09",
"docstatus": 0, "docstatus": 0,
"modified": "2013-01-22 14:56:41", "modified": "2013-05-02 14:44:24",
"modified_by": "Administrator", "modified_by": "Administrator",
"owner": "Administrator" "owner": "Administrator"
}, },
@@ -52,13 +52,21 @@
"oldfieldtype": "Data", "oldfieldtype": "Data",
"reqd": 1 "reqd": 1
}, },
{
"doctype": "DocField",
"fieldname": "currency",
"fieldtype": "Link",
"label": "Currency",
"options": "Currency",
"reqd": 1
},
{ {
"depends_on": "price_list_name", "depends_on": "price_list_name",
"doctype": "DocField", "doctype": "DocField",
"fieldname": "how_to_upload", "fieldname": "how_to_upload",
"fieldtype": "HTML", "fieldtype": "HTML",
"label": "How to upload", "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, "cancel": 0,
@@ -78,7 +86,6 @@
"cancel": 1, "cancel": 1,
"create": 1, "create": 1,
"doctype": "DocPerm", "doctype": "DocPerm",
"match": "",
"role": "Sales Master Manager", "role": "Sales Master Manager",
"write": 1 "write": 1
} }

View File

@@ -1,6 +1,7 @@
test_records = [ test_records = [
[{ [{
"doctype": "Price List", "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, "docstatus": 0,
"modified": "2013-03-01 08:22:16", "modified": "2013-05-01 15:49:47",
"modified_by": "Administrator", "modified_by": "Administrator",
"owner": "harshada@webnotestech.com" "owner": "harshada@webnotestech.com"
}, },
@@ -24,14 +24,19 @@
"permlevel": 0 "permlevel": 0
}, },
{ {
"cancel": 1,
"create": 1,
"doctype": "DocPerm", "doctype": "DocPerm",
"name": "__common__", "name": "__common__",
"parent": "Batch", "parent": "Batch",
"parentfield": "permissions", "parentfield": "permissions",
"parenttype": "DocType", "parenttype": "DocType",
"permlevel": 0,
"read": 1, "read": 1,
"report": 1,
"role": "Material Master Manager", "role": "Material Master Manager",
"submit": 0 "submit": 0,
"write": 1
}, },
{ {
"doctype": "DocType", "doctype": "DocType",
@@ -94,28 +99,6 @@
"oldfieldtype": "Date" "oldfieldtype": "Date"
}, },
{ {
"doctype": "DocField", "doctype": "DocPerm"
"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
} }
] ]

View File

@@ -326,6 +326,17 @@ if (sys_defaults.auto_inventory_accounting) {
} }
// cost center // 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) { cur_frm.fields_dict.delivery_note_details.grid.get_field("cost_center").get_query = function(doc) {
return { return {
query: "accounts.utils.get_cost_center_list", 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 // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>. // 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) { cur_frm.cscript.refresh = function(doc) {
// make sensitive fields(has_serial_no, is_stock_item, valuation_method) // make sensitive fields(has_serial_no, is_stock_item, valuation_method)
// read only if any stock ledger entry exists // 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')) { if ((!doc.__islocal) && (doc.is_stock_item == 'Yes')) {
var callback = function(r, rt) { var callback = function(r, rt) {

View File

@@ -23,7 +23,17 @@ from webnotes.model.bean import getlist
from webnotes import msgprint, _ from webnotes import msgprint, _
from webnotes.model.controller import DocListController from webnotes.model.controller import DocListController
class PriceListCurrencyMismatch(Exception): pass
class DocType(DocListController): 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): def validate(self):
if not self.doc.stock_uom: if not self.doc.stock_uom:
msgprint(_("Please enter Default Unit of Measure"), raise_exception=1) 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.add_default_uom_in_conversion_factor_table()
self.valiadte_item_type() self.valiadte_item_type()
self.check_for_active_boms() self.check_for_active_boms()
self.check_ref_rate_detail() self.validate_price_lists()
self.fill_customer_code() self.fill_customer_code()
self.check_item_tax() self.check_item_tax()
self.validate_barcode() self.validate_barcode()
@@ -55,8 +65,9 @@ class DocType(DocListController):
ch.conversion_factor = 1 ch.conversion_factor = 1
def check_stock_uom_with_bin(self): def check_stock_uom_with_bin(self):
if not self.doc.fields.get("__islocal"):
bin = webnotes.conn.sql("select stock_uom from `tabBin` where item_code = %s", bin = webnotes.conn.sql("select stock_uom from `tabBin` where item_code = %s",
self.doc.item_code) self.doc.name)
if self.doc.stock_uom and bin and cstr(bin[0][0]) \ if self.doc.stock_uom and bin and cstr(bin[0][0]) \
and cstr(bin[0][0]) != cstr(self.doc.stock_uom): and cstr(bin[0][0]) != cstr(self.doc.stock_uom):
msgprint(_("Please Update Stock UOM with the help of Stock UOM Replace Utility."), msgprint(_("Please Update Stock UOM with the help of Stock UOM Replace Utility."),
@@ -120,15 +131,20 @@ class DocType(DocListController):
if cstr(self.doc.fields.get(d)) != 'Yes': if cstr(self.doc.fields.get(d)) != 'Yes':
_check_for_active_boms(fl[d]) _check_for_active_boms(fl[d])
def check_ref_rate_detail(self): def validate_price_lists(self):
check_list=[] price_lists=[]
for d in getlist(self.doclist,'ref_rate_details'): for d in getlist(self.doclist,'ref_rate_details'):
if [cstr(d.price_list_name), cstr(d.ref_currency), if d.price_list_name in price_lists:
cint(d.selling), cint(d.buying)] in check_list: msgprint(_("Cannot have two prices for same Price List") + ": " + d.price_list_name,
msgprint("Ref Rate is entered twice for Price List : '%s' and Currency : '%s'." % raise_exception= webnotes.DuplicateEntryError)
(d.price_list_name,d.ref_currency), raise_exception=1)
else: 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): 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 """
@@ -154,13 +170,14 @@ class DocType(DocListController):
def validate_barcode(self): def validate_barcode(self):
if self.doc.barcode: 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: if duplicate:
msgprint("Barcode: %s already used in item: %s" % msgprint("Barcode: %s already used in item: %s" %
(self.doc.barcode, cstr(duplicate[0][0])), raise_exception = 1) (self.doc.barcode, cstr(duplicate[0][0])), raise_exception = 1)
def check_non_asset_warehouse(self): 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) 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: for e in existing_qty:
msgprint("%s Units exist in Warehouse %s, which is not an Asset Warehouse." % 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", "creation": "2013-03-28 10:35:28",
"docstatus": 0, "docstatus": 0,
"modified": "2013-04-23 11:44:39", "modified": "2013-05-02 15:10:53",
"modified_by": "Administrator", "modified_by": "Administrator",
"owner": "Administrator" "owner": "Administrator"
}, },
@@ -34,7 +34,6 @@
"parent": "Item", "parent": "Item",
"parentfield": "permissions", "parentfield": "permissions",
"parenttype": "DocType", "parenttype": "DocType",
"permlevel": 0,
"read": 1, "read": 1,
"submit": 0 "submit": 0
}, },
@@ -51,6 +50,13 @@
"oldfieldtype": "Section Break", "oldfieldtype": "Section Break",
"read_only": 0 "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.", "description": "Item will be saved by this name in the data base.",
"doctype": "DocField", "doctype": "DocField",

View File

@@ -20,6 +20,22 @@ import webnotes
test_ignore = ["BOM"] 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 = [ test_records = [
[{ [{
"doctype": "Item", "doctype": "Item",
@@ -45,7 +61,14 @@ test_records = [
"warehouse": "_Test Warehouse", "warehouse": "_Test Warehouse",
"warehouse_reorder_level": 20, "warehouse_reorder_level": 20,
"warehouse_reorder_qty": 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", "doctype": "Item",
"item_code": "_Test Item Home Desktop 100", "item_code": "_Test Item Home Desktop 100",

View File

@@ -263,6 +263,12 @@ class TestMaterialRequest(unittest.TestCase):
se = webnotes.bean(copy=se_doclist) se = webnotes.bean(copy=se_doclist)
self.assertRaises(webnotes.MappingMismatchError, se.insert) 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 = [ 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): 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)) exists = webnotes.conn.sql("select name, status, docstatus from `tabSerial No` where name = '%s'" % (serial_no))
if is_submit: 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) msgprint("Serial No: %s already %s" % (serial_no, exists and exists[0][1]), raise_exception = 1)
elif exists: elif exists:
s = Document('Serial No', exists and exists[0][0]) s = Document('Serial No', exists and exists[0][0])

View File

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

View File

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

View File

@@ -29,17 +29,13 @@ $.extend(cur_frm.cscript, {
erpnext.hide_naming_series(); erpnext.hide_naming_series();
cur_frm.cscript.make_listing(doc); cur_frm.cscript.make_listing(doc);
if(!doc.__islocal) { if(!doc.__islocal) {
if(in_list(user_roles,'System Manager')) { 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('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']); 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']);
} }
cur_frm.set_df_property('subject','read_only', 1); cur_frm.toggle_enable(["subject", "raised_by"], false);
cur_frm.set_df_property('description','hidden', 1); cur_frm.toggle_display("description", false);
cur_frm.set_df_property('raised_by','read_only', 1);
} }
refresh_field('status'); refresh_field('status');
}, },

View File

@@ -45,6 +45,10 @@ class DocType(TransactionBase):
def validate(self): def validate(self):
self.update_status() 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): def on_communication_sent(self, comm):
webnotes.conn.set(self.doc, 'status', 'Waiting for Customer') webnotes.conn.set(self.doc, 'status', 'Waiting for Customer')
if comm.lead and not self.doc.lead: if comm.lead and not self.doc.lead:

View File

@@ -34,7 +34,8 @@ def upload(select_doctype=None, rows=None):
rename_log = [] rename_log = []
for row in rows: for row in rows:
if len(row) > 2: # if row has some content
if len(row) > 1 and row[0] and row[1]:
try: try:
if rename_doc(select_doctype, row[0], row[1]): if rename_doc(select_doctype, row[0], row[1]):
rename_log.append(_("Successful: ") + row[0] + " -> " + row[1]) rename_log.append(_("Successful: ") + row[0] + " -> " + row[1])