Merge branch 'master' into slow

This commit is contained in:
Nabin Hait 2013-04-18 15:46:06 +05:30
commit 265f2f2dea
47 changed files with 653 additions and 474 deletions

View File

@ -69,11 +69,13 @@ class DocType:
raise_exception=1) raise_exception=1)
def validate_duplicate_account(self): def validate_duplicate_account(self):
if (self.doc.fields.get('__islocal') or not self.doc.name) and \
sql("""select name from tabAccount where account_name=%s and company=%s""", if self.doc.fields.get('__islocal') or not self.doc.name:
(self.doc.account_name, self.doc.company)): company_abbr = webnotes.conn.get_value("Company", self.doc.company, "abbr")
msgprint("Account Name: %s already exists, please rename" if sql("""select name from tabAccount where name=%s""",
% self.doc.account_name, raise_exception=1) (self.doc.account_name + " - " + company_abbr)):
msgprint("Account Name: %s already exists, please rename"
% self.doc.account_name, raise_exception=1)
def validate_root_details(self): def validate_root_details(self):
#does not exists parent #does not exists parent

View File

@ -306,13 +306,11 @@ erpnext.GeneralLedger = wn.views.GridReport.extend({
}, },
make_account_by_name: function() { make_account_by_name: function() {
if(!this.account_by_name) { this.account_by_name = this.make_name_map(wn.report_dump.data["Account"]);
this.account_by_name = this.make_name_map(wn.report_dump.data["Account"]); this.make_voucher_accounts_map();
this.make_voucher_acconuts_map();
}
}, },
make_voucher_acconuts_map: function() { make_voucher_accounts_map: function() {
this.voucher_accounts = {}; this.voucher_accounts = {};
var data = wn.report_dump.data["GL Entry"]; var data = wn.report_dump.data["GL Entry"];
for(var i=0, j=data.length; i<j; i++) { for(var i=0, j=data.length; i<j; i++) {

View File

@ -1,4 +1,5 @@
erpnext.updates = [ erpnext.updates = [
["12th April", ["Employee: List of Leave Approvers who can approve the Employee's Leave Applications"]],
["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

@ -14,62 +14,95 @@
// 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.cscript.onload = function(doc) { wn.provide("erpnext.hr");
// bc erpnext.hr.EmployeeController = wn.ui.form.Controller.extend({
var india_specific = ["esic_card_no", "gratuity_lic_id", "pan_number", "pf_number"] setup: function() {
if(wn.control_panel.country!="India") { this.setup_leave_approver_select();
hide_field(india_specific); this.frm.fields_dict.user_id.get_query = erpnext.utils.profile_query;
} this.frm.fields_dict.reports_to.get_query = erpnext.utils.employee_query;
} },
cur_frm.cscript.refresh = function(doc) { onload: function() {
if(!doc.__islocal) { this.frm.toggle_display(["esic_card_no", "gratuity_lic_id", "pan_number", "pf_number"],
hide_field("naming_series"); wn.control_panel.country==="India");
cur_frm.add_custom_button('Make Salary Structure', },
cur_frm.cscript['Make Salary Structure']);
} refresh: function() {
} var me = this;
erpnext.hide_naming_series();
cur_frm.cscript.date_of_birth = function(doc, dt, dn) { if(!this.frm.doc.__islocal) {
get_server_fields('get_retirement_date','','',doc,dt,dn,1); cur_frm.add_custom_button('View Active Salary Structure', function() {
} me.view_active_salary_structure(this); });
cur_frm.cscript.salutation = function(doc,dt,dn) { cur_frm.add_custom_button('Make Salary Structure', function() {
if(doc.salutation){ me.make_salary_structure(this); });
if(doc.salutation=='Mr')
doc.gender='Male';
else if(doc.salutation=='Ms')
doc.gender='Female';
refresh_field('gender');
}
}
cur_frm.cscript['Make Salary Structure']=function(){
$c_obj(make_doclist (cur_frm.doc.doctype, cur_frm.doc.name), 'check_sal_structure',
cur_frm.doc.name, function(r, rt) {
if(r.message)
msgprint("You have already created Active salary structure.\n \
If you want to create new one, please ensure that no active salary structure \
exist.\nTo inactive salary structure select 'Is Active' as 'No'.");
else
cur_frm.cscript.make_salary_structure(cur_frm.doc);
} }
); },
}
setup_leave_approver_select: function() {
cur_frm.cscript.make_salary_structure = function(doc, dt, dn, det){ var me = this;
var st = wn.model.make_new_doc_and_get_name('Salary Structure'); this.frm.call({
st = locals['Salary Structure'][st]; method:"hr.utils.get_leave_approver_list",
st.employee = doc.name; callback: function(r) {
st.employee_name = doc.employee_name; me.frm.fields_dict.employee_leave_approvers.grid.get_field("leave_approver").df.options =
st.branch=doc.branch; $.map(r.message, function(profile) {
st.designation=doc.designation; return {value: profile, label: wn.user_info(profile).fullname};
st.department=doc.department; });
st.fiscal_year = doc.fiscal_year }
st.grade=doc.grade; });
loaddoc('Salary Structure', st.name); },
}
date_of_birth: function() {
cur_frm.fields_dict.user_id.get_query = erpnext.utils.profile_query; cur_frm.call({
method: "get_retirement_date",
cur_frm.fields_dict.reports_to.get_query = erpnext.utils.employee_query; args: {date_of_birth: this.frm.doc.date_of_birth}
});
},
salutation: function() {
if(this.frm.doc.salutation) {
this.frm.set_value("gender", {
"Mr": "Male",
"Ms": "Female"
}[this.frm.doc.salutation]);
}
},
make_salary_structure: function(btn) {
var me = this;
this.validate_salary_structure(btn, function(r) {
if(r.message) {
msgprint(wn._("Employee") + ' "' + me.frm.doc.name + '": '
+ wn._("An active Salary Structure already exists. \
If you want to create new one, please ensure that no active Salary Structure \
exists for this Employee. Go to the active Salary Structure and set \
\"Is Active\" = \"No\""));
} else if(!r.exc) {
wn.model.map({
source: wn.model.get_doclist(me.frm.doc.doctype, me.frm.doc.name),
target: "Salary Structure"
});
}
});
},
validate_salary_structure: function(btn, callback) {
var me = this;
this.frm.call({
btn: btn,
method: "webnotes.client.get_value",
args: {
doctype: "Salary Structure",
fieldname: "name",
filters: {
employee: me.frm.doc.name,
is_active: "Yes",
docstatus: ["!=", 2]
},
},
callback: callback
});
},
});
cur_frm.cscript = new erpnext.hr.EmployeeController({frm: cur_frm});

View File

@ -27,7 +27,7 @@ class DocType:
def __init__(self,doc,doclist=[]): def __init__(self,doc,doclist=[]):
self.doc = doc self.doc = doc
self.doclist = doclist self.doclist = doclist
def autoname(self): def autoname(self):
ret = sql("select value from `tabSingles` where doctype = 'Global Defaults' and field = 'emp_created_by'") ret = sql("select value from `tabSingles` where doctype = 'Global Defaults' and field = 'emp_created_by'")
if not ret: if not ret:
@ -49,30 +49,31 @@ class DocType:
self.validate_email() self.validate_email()
self.validate_name() self.validate_name()
self.validate_status() self.validate_status()
self.validate_employee_leave_approver()
def get_retirement_date(self):
import datetime
ret = {}
if self.doc.date_of_birth:
dt = getdate(self.doc.date_of_birth) + datetime.timedelta(21915)
ret = {'date_of_retirement': dt.strftime('%Y-%m-%d')}
return ret
def check_sal_structure(self, nm):
ret_sal_struct=sql("select name from `tabSalary Structure` where employee='%s' and is_active = 'Yes' and docstatus!= 2"%nm)
return ret_sal_struct and ret_sal_struct[0][0] or ''
def on_update(self): def on_update(self):
if self.doc.user_id: if self.doc.user_id:
self.update_user_default() self.update_user_default()
self.update_profile() self.update_profile()
def update_user_default(self): def update_user_default(self):
webnotes.conn.set_default("employee", self.doc.name, self.doc.user_id) webnotes.conn.set_default("employee", self.doc.name, self.doc.user_id)
webnotes.conn.set_default("employee_name", self.doc.employee_name, self.doc.user_id) webnotes.conn.set_default("employee_name", self.doc.employee_name, self.doc.user_id)
webnotes.conn.set_default("company", self.doc.company, self.doc.user_id) webnotes.conn.set_default("company", self.doc.company, self.doc.user_id)
if self.doc.reports_to: self.set_default_leave_approver()
webnotes.conn.set_default("leave_approver", webnotes.conn.get_value("Employee", self.doc.reports_to, "user_id"), self.doc.user_id)
def set_default_leave_approver(self):
employee_leave_approvers = self.doclist.get({"parentfield": "employee_leave_approvers"})
if len(employee_leave_approvers):
webnotes.conn.set_default("leave_approver", employee_leave_approvers[0].leave_approver,
self.doc.user_id)
elif self.doc.reports_to:
from webnotes.profile import Profile
reports_to_user = webnotes.conn.get_value("Employee", self.doc.reports_to, "user_id")
if "Leave Approver" in Profile(reports_to_user).get_roles():
webnotes.conn.set_default("leave_approver", reports_to_user, self.doc.user_id)
def update_profile(self): def update_profile(self):
# add employee role if missing # add employee role if missing
@ -116,7 +117,6 @@ class DocType:
profile_wrapper.save() profile_wrapper.save()
def validate_date(self): def validate_date(self):
import datetime
if self.doc.date_of_birth and self.doc.date_of_joining and getdate(self.doc.date_of_birth) >= getdate(self.doc.date_of_joining): if self.doc.date_of_birth and self.doc.date_of_joining and getdate(self.doc.date_of_birth) >= getdate(self.doc.date_of_joining):
msgprint('Date of Joining must be greater than Date of Birth') msgprint('Date of Joining must be greater than Date of Birth')
raise Exception raise Exception
@ -167,3 +167,21 @@ class DocType:
if self.doc.status == 'Left' and not self.doc.relieving_date: if self.doc.status == 'Left' and not self.doc.relieving_date:
msgprint("Please enter relieving date.") msgprint("Please enter relieving date.")
raise Exception raise Exception
def validate_employee_leave_approver(self):
from webnotes.profile import Profile
from hr.doctype.leave_application.leave_application import InvalidLeaveApproverError
for l in self.doclist.get({"parentfield": "employee_leave_approvers"}):
if "Leave Approver" not in Profile(l.leave_approver).get_roles():
msgprint(_("Invalid Leave Approver") + ": \"" + l.leave_approver + "\"",
raise_exception=InvalidLeaveApproverError)
@webnotes.whitelist()
def get_retirement_date(date_of_birth=None):
import datetime
ret = {}
if date_of_birth:
dt = getdate(date_of_birth) + datetime.timedelta(21915)
ret = {'date_of_retirement': dt.strftime('%Y-%m-%d')}
return ret

View File

@ -1,8 +1,8 @@
[ [
{ {
"creation": "2013-01-23 19:57:17", "creation": "2013-03-07 09:04:18",
"docstatus": 0, "docstatus": 0,
"modified": "2013-02-08 13:07:25", "modified": "2013-04-12 07:16:42",
"modified_by": "Administrator", "modified_by": "Administrator",
"owner": "Administrator" "owner": "Administrator"
}, },
@ -322,15 +322,6 @@
"options": "Grade", "options": "Grade",
"reqd": 0 "reqd": 0
}, },
{
"doctype": "DocField",
"fieldname": "reports_to",
"fieldtype": "Link",
"label": "Reports to",
"oldfieldname": "reports_to",
"oldfieldtype": "Link",
"options": "Employee"
},
{ {
"description": "Provide email id registered in company", "description": "Provide email id registered in company",
"doctype": "DocField", "doctype": "DocField",
@ -342,6 +333,14 @@
"oldfieldtype": "Data", "oldfieldtype": "Data",
"reqd": 0 "reqd": 0
}, },
{
"doctype": "DocField",
"fieldname": "notice_number_of_days",
"fieldtype": "Int",
"label": "Notice - Number of Days",
"oldfieldname": "notice_number_of_days",
"oldfieldtype": "Int"
},
{ {
"doctype": "DocField", "doctype": "DocField",
"fieldname": "salary_information", "fieldname": "salary_information",
@ -405,6 +404,29 @@
"oldfieldname": "gratuity_lic_id", "oldfieldname": "gratuity_lic_id",
"oldfieldtype": "Data" "oldfieldtype": "Data"
}, },
{
"doctype": "DocField",
"fieldname": "organization_profile",
"fieldtype": "Section Break",
"label": "Organization Profile"
},
{
"doctype": "DocField",
"fieldname": "reports_to",
"fieldtype": "Link",
"label": "Reports to",
"oldfieldname": "reports_to",
"oldfieldtype": "Link",
"options": "Employee"
},
{
"description": "The first Leave Approver in the list will be set as the default Leave Approver",
"doctype": "DocField",
"fieldname": "employee_leave_approvers",
"fieldtype": "Table",
"label": "Leave Approvers",
"options": "Employee Leave Approver"
},
{ {
"doctype": "DocField", "doctype": "DocField",
"fieldname": "contact_details", "fieldname": "contact_details",
@ -429,14 +451,6 @@
"fieldtype": "Data", "fieldtype": "Data",
"label": "Personal Email" "label": "Personal Email"
}, },
{
"doctype": "DocField",
"fieldname": "notice_number_of_days",
"fieldtype": "Int",
"label": "Notice - Number of Days",
"oldfieldname": "notice_number_of_days",
"oldfieldtype": "Int"
},
{ {
"doctype": "DocField", "doctype": "DocField",
"fieldname": "emergency_contact_details", "fieldname": "emergency_contact_details",
@ -767,4 +781,4 @@
"role": "HR Manager", "role": "HR Manager",
"write": 1 "write": 1
} }
] ]

View File

@ -0,0 +1,8 @@
# For license information, please see license.txt
from __future__ import unicode_literals
import webnotes
class DocType:
def __init__(self, d, dl):
self.doc, self.doclist = d, dl

View File

@ -0,0 +1,39 @@
[
{
"creation": "2013-04-12 06:56:15",
"docstatus": 0,
"modified": "2013-04-12 07:53:33",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"allow_import": 0,
"autoname": "LAPPR-/.#####",
"description": "Users who can approve a specific employee's leave applications",
"doctype": "DocType",
"istable": 1,
"module": "HR",
"name": "__common__"
},
{
"doctype": "DocField",
"fieldname": "leave_approver",
"fieldtype": "Select",
"label": "Leave Approver",
"name": "__common__",
"parent": "Employee Leave Approver",
"parentfield": "fields",
"parenttype": "DocType",
"permlevel": 0,
"print_hide": 1,
"reqd": 1,
"width": "200"
},
{
"doctype": "DocType",
"name": "Employee Leave Approver"
},
{
"doctype": "DocField"
}
]

View File

@ -29,7 +29,7 @@ cur_frm.cscript.onload = function(doc,cdt,cdn){
} }
cur_frm.call({ cur_frm.call({
method:"get_approver_list", method:"hr.utils.get_expense_approver_list",
callback: function(r) { callback: function(r) {
cur_frm.set_df_property("exp_approver", "options", r.message); cur_frm.set_df_property("exp_approver", "options", r.message);
} }

View File

@ -52,12 +52,3 @@ class DocType:
if not getlist(self.doclist, 'expense_voucher_details'): if not getlist(self.doclist, 'expense_voucher_details'):
msgprint("Please add expense voucher details") msgprint("Please add expense voucher details")
raise Exception raise Exception
@webnotes.whitelist()
def get_approver_list():
roles = [r[0] for r in webnotes.conn.sql("""select distinct parent from `tabUserRole`
where role='Expense Approver'""")]
if not roles:
webnotes.msgprint("No Expense Approvers. Please assign 'Expense Approver' \
Role to atleast one user.")
return roles

View File

@ -26,7 +26,7 @@ cur_frm.cscript.onload = function(doc, dt, dn) {
} }
cur_frm.set_df_property("leave_approver", "options", ""); cur_frm.set_df_property("leave_approver", "options", "");
cur_frm.call({ cur_frm.call({
method:"get_approver_list", method:"hr.utils.get_leave_approver_list",
callback: function(r) { callback: function(r) {
cur_frm.set_df_property("leave_approver", "options", $.map(r.message, cur_frm.set_df_property("leave_approver", "options", $.map(r.message,
function(profile) { function(profile) {

View File

@ -18,11 +18,13 @@ from __future__ import unicode_literals
import webnotes import webnotes
from webnotes import _ from webnotes import _
from webnotes.utils import cint, cstr, date_diff, flt, formatdate, getdate, get_url_to_form from webnotes.utils import cint, cstr, date_diff, flt, formatdate, getdate, get_url_to_form, \
comma_or, get_fullname
from webnotes import msgprint from webnotes import msgprint
class LeaveDayBlockedError(Exception): pass class LeaveDayBlockedError(webnotes.ValidationError): pass
class OverlapError(Exception): pass class OverlapError(webnotes.ValidationError): pass
class InvalidLeaveApproverError(webnotes.ValidationError): pass
from webnotes.model.controller import DocListController from webnotes.model.controller import DocListController
class DocType(DocListController): class DocType(DocListController):
@ -39,6 +41,7 @@ class DocType(DocListController):
self.validate_max_days() self.validate_max_days()
self.show_block_day_warning() self.show_block_day_warning()
self.validate_block_days() self.validate_block_days()
self.validate_leave_approver()
def on_update(self): def on_update(self):
if (not self.previous_doc and self.doc.leave_approver) or (self.previous_doc and \ if (not self.previous_doc and self.doc.leave_approver) or (self.previous_doc and \
@ -156,6 +159,21 @@ class DocType(DocListController):
msgprint("Sorry ! You cannot apply for %s for more than %s days" % (self.doc.leave_type, max_days)) msgprint("Sorry ! You cannot apply for %s for more than %s days" % (self.doc.leave_type, max_days))
raise Exception raise Exception
def validate_leave_approver(self):
employee = webnotes.bean("Employee", self.doc.employee)
leave_approvers = [l.leave_approver for l in
employee.doclist.get({"parentfield": "employee_leave_approvers"})]
if len(leave_approvers) and self.doc.leave_approver not in leave_approvers:
msgprint(("[" + _("For Employee") + ' "' + self.doc.employee + '"] '
+ _("Leave Approver can be one of") + ": "
+ comma_or(leave_approvers)), raise_exception=InvalidLeaveApproverError)
elif self.doc.leave_approver and not webnotes.conn.sql("""select name from `tabUserRole`
where parent=%s and role='Leave Approver'""", self.doc.leave_approver):
msgprint(get_fullname(self.doc.leave_approver) + ": " \
+ _("does not have role 'Leave Approver'"), raise_exception=InvalidLeaveApproverError)
def notify_employee(self, status): def notify_employee(self, status):
employee = webnotes.doc("Employee", self.doc.employee) employee = webnotes.doc("Employee", self.doc.employee)
if not employee.user_id: if not employee.user_id:
@ -221,15 +239,6 @@ def get_leave_balance(employee, leave_type, fiscal_year):
ret = {'leave_balance': leave_all - leave_app} ret = {'leave_balance': leave_all - leave_app}
return ret return ret
@webnotes.whitelist()
def get_approver_list():
roles = [r[0] for r in webnotes.conn.sql("""select distinct parent from `tabUserRole`
where role='Leave Approver'""")]
if not roles:
webnotes.msgprint("No Leave Approvers. Please assign 'Leave Approver' Role to atleast one user.")
return roles
def is_lwp(leave_type): def is_lwp(leave_type):
lwp = webnotes.conn.sql("select is_lwp from `tabLeave Type` where name = %s", leave_type) lwp = webnotes.conn.sql("select is_lwp from `tabLeave Type` where name = %s", leave_type)
return lwp and cint(lwp[0][0]) or 0 return lwp and cint(lwp[0][0]) or 0

View File

@ -4,6 +4,23 @@ import unittest
from hr.doctype.leave_application.leave_application import LeaveDayBlockedError, OverlapError from hr.doctype.leave_application.leave_application import LeaveDayBlockedError, OverlapError
class TestLeaveApplication(unittest.TestCase): class TestLeaveApplication(unittest.TestCase):
def _clear_roles(self):
webnotes.conn.sql("""delete from `tabUserRole` where parent in
("test@example.com", "test1@example.com", "test2@example.com")""")
def _clear_applications(self):
webnotes.conn.sql("""delete from `tabLeave Application`""")
def _add_employee_leave_approver(self, employee, leave_approver):
webnotes.session.user = "Administrator"
employee = webnotes.bean("Employee", employee)
employee.doclist.append({
"doctype": "Employee Leave Approver",
"parentfield": "employee_leave_approvers",
"leave_approver": leave_approver
})
employee.save()
def get_application(self, doclist): def get_application(self, doclist):
application = webnotes.bean(copy=doclist) application = webnotes.bean(copy=doclist)
application.doc.from_date = "2013-01-01" application.doc.from_date = "2013-01-01"
@ -11,8 +28,14 @@ class TestLeaveApplication(unittest.TestCase):
return application return application
def test_block_list(self): def test_block_list(self):
import webnotes webnotes.session.user = "Administrator"
webnotes.conn.set_value("Department", "_Test Department", "leave_block_list", "_Test Leave Block List") self._clear_roles()
from webnotes.profile import add_role
add_role("test1@example.com", "HR User")
webnotes.conn.set_value("Department", "_Test Department",
"leave_block_list", "_Test Leave Block List")
application = self.get_application(test_records[1]) application = self.get_application(test_records[1])
application.insert() application.insert()
@ -20,9 +43,6 @@ class TestLeaveApplication(unittest.TestCase):
self.assertRaises(LeaveDayBlockedError, application.submit) self.assertRaises(LeaveDayBlockedError, application.submit)
webnotes.session.user = "test1@example.com" webnotes.session.user = "test1@example.com"
from webnotes.profile import add_role
add_role("test1@example.com", "HR User")
# clear other applications # clear other applications
webnotes.conn.sql("delete from `tabLeave Application`") webnotes.conn.sql("delete from `tabLeave Application`")
@ -31,11 +51,31 @@ class TestLeaveApplication(unittest.TestCase):
self.assertTrue(application.insert()) self.assertTrue(application.insert())
def test_overlap(self): def test_overlap(self):
webnotes.session.user = "Administrator"
self._clear_roles()
self._clear_applications()
from webnotes.profile import add_role
add_role("test@example.com", "Employee")
add_role("test2@example.com", "Leave Approver")
webnotes.session.user = "test@example.com"
application = self.get_application(test_records[1]) application = self.get_application(test_records[1])
application.doc.leave_approver = "test2@example.com"
application.insert()
application = self.get_application(test_records[1])
application.doc.leave_approver = "test2@example.com"
self.assertRaises(OverlapError, application.insert) self.assertRaises(OverlapError, application.insert)
def test_global_block_list(self): def test_global_block_list(self):
webnotes.session.user = "Administrator"
self._clear_roles()
from webnotes.profile import add_role
add_role("test1@example.com", "Employee")
add_role("test@example.com", "Leave Approver")
application = self.get_application(test_records[3]) application = self.get_application(test_records[3])
application.doc.leave_approver = "test@example.com" application.doc.leave_approver = "test@example.com"
@ -44,19 +84,120 @@ class TestLeaveApplication(unittest.TestCase):
webnotes.conn.set_value("Employee", "_T-Employee-0002", "department", webnotes.conn.set_value("Employee", "_T-Employee-0002", "department",
"_Test Department") "_Test Department")
webnotes.session.user = "test2@example.com" webnotes.session.user = "test1@example.com"
from webnotes.profile import add_role
add_role("test2@example.com", "Employee")
application.insert() application.insert()
webnotes.session.user = "test@example.com" webnotes.session.user = "test@example.com"
from webnotes.profile import add_role
add_role("test@example.com", "Leave Approver")
application.doc.status = "Approved" application.doc.status = "Approved"
self.assertRaises(LeaveDayBlockedError, application.submit) self.assertRaises(LeaveDayBlockedError, application.submit)
webnotes.conn.set_value("Leave Block List", "_Test Leave Block List",
"applies_to_all_departments", 0)
def test_leave_approval(self):
webnotes.session.user = "Administrator"
self._clear_roles()
from webnotes.profile import add_role
add_role("test@example.com", "Employee")
add_role("test1@example.com", "Leave Approver")
add_role("test2@example.com", "Leave Approver")
self._test_leave_approval_basic_case_1()
self._test_leave_approval_basic_case_2()
self._test_leave_approval_invalid_leave_approver_insert()
self._test_leave_approval_invalid_leave_approver_submit()
self._test_leave_approval_valid_leave_approver_insert()
def _test_leave_approval_basic_case_1(self):
self._clear_applications()
# create leave application as Employee
webnotes.session.user = "test@example.com"
application = self.get_application(test_records[1])
application.doc.leave_approver = "test1@example.com"
application.insert()
# submit leave application by Leave Approver
webnotes.session.user = "test1@example.com"
application.doc.status = "Approved"
application.submit()
self.assertEqual(webnotes.conn.get_value("Leave Application", application.doc.name,
"docstatus"), 1)
def _test_leave_approval_basic_case_2(self):
self._clear_applications()
# create leave application by any leave approver,
# when no leave approver specified in employee's leave approvers list
application = self.get_application(test_records[1])
application.doc.leave_approver = "test1@example.com"
application.insert()
application.doc.status = "Approved"
application.submit()
self.assertEqual(webnotes.conn.get_value("Leave Application", application.doc.name,
"docstatus"), 1)
def _test_leave_approval_invalid_leave_approver_insert(self):
from hr.doctype.leave_application.leave_application import InvalidLeaveApproverError
self._clear_applications()
# add a different leave approver in the employee's list
# should raise exception if not a valid leave approver
self._add_employee_leave_approver("_T-Employee-0001", "test2@example.com")
# TODO - add test2@example.com leave approver in employee's leave approvers list
application = self.get_application(test_records[1])
webnotes.session.user = "test@example.com"
application.doc.leave_approver = "test1@example.com"
self.assertRaises(InvalidLeaveApproverError, application.insert)
webnotes.conn.sql("""delete from `tabEmployee Leave Approver` where parent=%s""",
"_T-Employee-0001")
def _test_leave_approval_invalid_leave_approver_submit(self):
self._clear_applications()
self._add_employee_leave_approver("_T-Employee-0001", "test2@example.com")
# create leave application as employee
# but submit as invalid leave approver - should raise exception
webnotes.session.user = "test@example.com"
application = self.get_application(test_records[1])
application.doc.leave_approver = "test2@example.com"
application.insert()
webnotes.session.user = "test1@example.com"
application.doc.status = "Approved"
from webnotes.model.bean import BeanPermissionError
self.assertRaises(BeanPermissionError, application.submit)
webnotes.conn.sql("""delete from `tabEmployee Leave Approver` where parent=%s""",
"_T-Employee-0001")
def _test_leave_approval_valid_leave_approver_insert(self):
self._clear_applications()
self._add_employee_leave_approver("_T-Employee-0001", "test2@example.com")
original_department = webnotes.conn.get_value("Employee", "_T-Employee-0001", "department")
webnotes.conn.set_value("Employee", "_T-Employee-0001", "department", None)
# change to valid leave approver and try to create and submit leave application
webnotes.session.user = "test2@example.com"
application = self.get_application(test_records[1])
application.doc.leave_approver = "test2@example.com"
application.insert()
application.doc.status = "Approved"
application.submit()
self.assertEqual(webnotes.conn.get_value("Leave Application", application.doc.name,
"docstatus"), 1)
webnotes.conn.sql("""delete from `tabEmployee Leave Approver` where parent=%s""",
"_T-Employee-0001")
webnotes.conn.set_value("Employee", "_T-Employee-0001", "department", original_department)
test_dependencies = ["Leave Block List"] test_dependencies = ["Leave Block List"]
test_records = [ test_records = [

38
hr/utils.py Normal file
View File

@ -0,0 +1,38 @@
# 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 _
@webnotes.whitelist()
def get_leave_approver_list():
roles = [r[0] for r in webnotes.conn.sql("""select distinct parent from `tabUserRole`
where role='Leave Approver'""")]
if not roles:
webnotes.msgprint(_("No Leave Approvers. Please assign 'Leave Approver' Role to atleast one user."))
return roles
@webnotes.whitelist()
def get_expense_approver_list():
roles = [r[0] for r in webnotes.conn.sql("""select distinct parent from `tabUserRole`
where role='Expense Approver'""")]
if not roles:
webnotes.msgprint("No Expense Approvers. Please assign 'Expense Approver' \
Role to atleast one user.")
return roles

View File

@ -6,6 +6,7 @@ def execute():
ml = json.loads(webnotes.conn.get_global("modules_list") or "[]") ml = json.loads(webnotes.conn.get_global("modules_list") or "[]")
webnotes.conn.set_global("hidden_modules", if ml:
json.dumps(list(set(modules.keys()).difference(set(ml))))) webnotes.conn.set_global("hidden_modules",
json.dumps(list(set(modules.keys()).difference(set(ml)))))

View File

@ -0,0 +1,10 @@
import webnotes, json
import webnotes.utils
def execute():
modules = webnotes.get_config().modules
ml = json.loads(webnotes.conn.get_global("hidden_modules") or "[]")
if len(ml) == len(modules.keys()):
webnotes.conn.set_global("hidden_modules", json.dumps([]))

View File

@ -10,8 +10,6 @@ def execute():
and po_item.item_code = %s and po_item.warehouse = %s and po_item.item_code = %s and po_item.warehouse = %s
""", (d[0], d[1])) """, (d[0], d[1]))
if flt(d[3]) != flt(ordered_qty[0][0]): if flt(d[3]) != flt(ordered_qty[0][0]):
print d[3], ordered_qty[0][0]
webnotes.conn.sql("""update `tabBin` set ordered_qty = %s where name = %s""", webnotes.conn.sql("""update `tabBin` set ordered_qty = %s where name = %s""",
(ordered_qty and ordered_qty[0][0] or 0, d[2])) (ordered_qty and ordered_qty[0][0] or 0, d[2]))

View File

@ -17,8 +17,4 @@ def execute():
if ((r["against_voucher_type"]=='Sales Invoice' and flt(r["outstanding"]) >= 0) \ if ((r["against_voucher_type"]=='Sales Invoice' and flt(r["outstanding"]) >= 0) \
or (r["against_voucher_type"]=="Purchase Invoice" and flt(["outstanding"]) <= 0)): or (r["against_voucher_type"]=="Purchase Invoice" and flt(["outstanding"]) <= 0)):
webnotes.conn.set_value(r["against_voucher_type"], r["against_voucher"], webnotes.conn.set_value(r["against_voucher_type"], r["against_voucher"],
"outstanding_amount", abs(flt(r["outstanding"]))) "outstanding_amount", abs(flt(r["outstanding"])))
else:
print r["against_voucher_type"], r["against_voucher"], \
outstanding[0][1], abs(flt(r["outstanding"]))

View File

@ -34,10 +34,8 @@ def execute():
except Exception, e: except Exception, e:
# if duplicate entry, then dont update # if duplicate entry, then dont update
if e[0]!=1062: if e[0]!=1062:
print webnotes.getTraceback()
raise e raise e
print change_map
changed_keys = change_map.keys() changed_keys = change_map.keys()
@ -61,6 +59,5 @@ def execute():
except Exception, e: except Exception, e:
if e[0]!=1146: if e[0]!=1146:
print webnotes.getTraceback()
raise e raise e

View File

@ -23,7 +23,6 @@ def repost_reserved_qty():
i = 0 i = 0
for d in bins: for d in bins:
i += 1 i += 1
print i
reserved_qty = webnotes.conn.sql(""" reserved_qty = webnotes.conn.sql("""
select select
sum((dnpi_qty / so_item_qty) * (so_item_qty - so_item_delivered_qty)) sum((dnpi_qty / so_item_qty) * (so_item_qty - so_item_delivered_qty))
@ -54,7 +53,6 @@ def repost_reserved_qty():
""", (d[0], d[1])) """, (d[0], d[1]))
if flt(d[3]) != flt(reserved_qty[0][0]): if flt(d[3]) != flt(reserved_qty[0][0]):
print d[3], reserved_qty[0][0]
webnotes.conn.sql(""" webnotes.conn.sql("""
update `tabBin` set reserved_qty = %s where name = %s update `tabBin` set reserved_qty = %s where name = %s
""", (reserved_qty and reserved_qty[0][0] or 0, d[2])) """, (reserved_qty and reserved_qty[0][0] or 0, d[2]))
@ -77,7 +75,6 @@ def cleanup_wrong_sle():
) )
""") """)
if sle: if sle:
print sle
for d in sle: for d in sle:
webnotes.conn.sql("update `tabStock Ledger Entry` set is_cancelled = 'Yes' where name = %s", d[3]) webnotes.conn.sql("update `tabStock Ledger Entry` set is_cancelled = 'Yes' where name = %s", d[3])
create_comment(d[3]) create_comment(d[3])

View File

@ -24,7 +24,6 @@ def handle_custom_fields():
* Create property setter entry of previous field * Create property setter entry of previous field
* Remove custom fields from tabDocField * Remove custom fields from tabDocField
""" """
print "in handle custom fields"
cf = get_cf() cf = get_cf()
assign_idx(cf) assign_idx(cf)
create_prev_field_prop_setter(cf) create_prev_field_prop_setter(cf)
@ -120,7 +119,6 @@ def create_file_list():
webnotes.clear_cache(doctype=obj.doc.name) webnotes.clear_cache(doctype=obj.doc.name)
def change_to_decimal(): def change_to_decimal():
print "in change to decimal"
webnotes.conn.commit() webnotes.conn.commit()
tables = webnotes.conn.sql("SHOW TABLES") tables = webnotes.conn.sql("SHOW TABLES")
alter_tables_list = [] alter_tables_list = []

View File

@ -7,7 +7,6 @@ def execute():
webnotes.conn.auto_commit_on_many_writes = True webnotes.conn.auto_commit_on_many_writes = True
for company in webnotes.conn.sql("select name from `tabCompany`"): for company in webnotes.conn.sql("select name from `tabCompany`"):
print company[0]
stock_ledger_entries = webnotes.conn.sql("""select item_code, voucher_type, voucher_no, stock_ledger_entries = webnotes.conn.sql("""select item_code, voucher_type, voucher_no,
voucher_detail_no, posting_date, posting_time, stock_value, voucher_detail_no, posting_date, posting_time, stock_value,
warehouse, actual_qty as qty from `tabStock Ledger Entry` warehouse, actual_qty as qty from `tabStock Ledger Entry`
@ -17,7 +16,6 @@ def execute():
dn_list = webnotes.conn.sql("""select name from `tabDelivery Note` dn_list = webnotes.conn.sql("""select name from `tabDelivery Note`
where docstatus < 2 and company = %s""", company[0]) where docstatus < 2 and company = %s""", company[0])
print "Total Delivery Note: ", len(dn_list)
for dn in dn_list: for dn in dn_list:
dn = webnotes.get_obj("Delivery Note", dn[0], with_children = 1) dn = webnotes.get_obj("Delivery Note", dn[0], with_children = 1)
@ -25,7 +23,6 @@ def execute():
si_list = webnotes.conn.sql("""select name from `tabSales Invoice` si_list = webnotes.conn.sql("""select name from `tabSales Invoice`
where docstatus < 2 and company = %s""", company[0]) where docstatus < 2 and company = %s""", company[0])
print "Total Sales Invoice: ", len(si_list)
for si in si_list: for si in si_list:
si = webnotes.get_obj("Sales Invoice", si[0], with_children = 1) si = webnotes.get_obj("Sales Invoice", si[0], with_children = 1)
si.set_buying_amount(stock_ledger_entries) si.set_buying_amount(stock_ledger_entries)

View File

@ -56,12 +56,13 @@ def add_accounts(accounts_to_add, check_fn=None):
where company=%s and ifnull(parent_account, '')=''""", company)[0][0] where company=%s and ifnull(parent_account, '')=''""", company)[0][0]
if count > 4: if count > 4:
print "Company", company, \ webnotes.errprint("Company" + company +
"has more than 4 root accounts. cannot apply patch to this company." "has more than 4 root accounts. cannot apply patch to this company.")
continue continue
for account_name, parent_account_name, group_or_ledger, account_type in accounts_to_add: for account_name, parent_account_name, group_or_ledger, account_type in accounts_to_add:
if not webnotes.conn.exists("Account", "%s - %s" % (account_name, abbr)): if not webnotes.conn.sql("""select name from `tabAccount` where account_name = %s
and company = %s""", (account_name, company)):
parent_account = "%s - %s" % (parent_account_name, abbr) parent_account = "%s - %s" % (parent_account_name, abbr)
if check_fn: if check_fn:
parent_account = check_fn(parent_account, company) parent_account = check_fn(parent_account, company)
@ -77,12 +78,13 @@ def add_accounts(accounts_to_add, check_fn=None):
def add_aii_cost_center(): def add_aii_cost_center():
for company, abbr in webnotes.conn.sql("""select name, abbr from `tabCompany`"""): for company, abbr in webnotes.conn.sql("""select name, abbr from `tabCompany`"""):
if not webnotes.conn.exists("Cost Center", "Auto Inventory Accounting - %s" % abbr): if not webnotes.conn.sql("""select name from `tabCost Center` where cost_center_name =
'Auto Inventory Accounting' and company_name = %s""", company):
parent_cost_center = webnotes.conn.get_value("Cost Center", parent_cost_center = webnotes.conn.get_value("Cost Center",
{"parent_cost_center['']": '', "company_name": company}) {"parent_cost_center['']": '', "company_name": company})
if not parent_cost_center: if not parent_cost_center:
print "Company", company, "does not have a root cost center" webnotes.errprint("Company " + company + "does not have a root cost center")
continue continue
cc = webnotes.bean({ cc = webnotes.bean({

View File

@ -12,6 +12,5 @@ def execute():
'Sales Invoice Spartan', 'Sales Invoice Spartan',
'Sales Invoice Modern' 'Sales Invoice Modern'
]: ]:
print r.get('name')
webnotes.modules.reload_doc(r.get('module'), 'Print Format', r.get('name')) webnotes.modules.reload_doc(r.get('module'), 'Print Format', r.get('name'))

View File

@ -12,5 +12,4 @@ def execute():
where voucher_type = %s and voucher_no = %s""", where voucher_type = %s and voucher_no = %s""",
(entry['voucher_type'], entry['voucher_no'])) (entry['voucher_type'], entry['voucher_no']))
except Exception, e: except Exception, e:
print entry pass
print e

View File

@ -231,7 +231,6 @@ patch_list = [
"patches.march_2013.p12_set_item_tax_rate_in_json", "patches.march_2013.p12_set_item_tax_rate_in_json",
"patches.march_2013.p07_update_valuation_rate", "patches.march_2013.p07_update_valuation_rate",
"patches.march_2013.p08_create_aii_accounts", "patches.march_2013.p08_create_aii_accounts",
"patches.march_2013.p03_update_buying_amount",
"patches.april_2013.p01_update_serial_no_valuation_rate", "patches.april_2013.p01_update_serial_no_valuation_rate",
"patches.april_2013.p02_add_country_and_currency", "patches.april_2013.p02_add_country_and_currency",
"patches.april_2013.p03_fixes_for_lead_in_quotation", "patches.april_2013.p03_fixes_for_lead_in_quotation",
@ -241,4 +240,6 @@ patch_list = [
"patches.april_2013.p04_reverse_modules_list", "patches.april_2013.p04_reverse_modules_list",
"execute:webnotes.delete_doc('Search Criteria', 'time_log_summary')", "execute:webnotes.delete_doc('Search Criteria', 'time_log_summary')",
"patches.april_2013.p04_update_role_in_pages", "patches.april_2013.p04_update_role_in_pages",
"patches.april_2013.p05_fixes_in_reverse_modules",
"execute:webnotes.delete_doc('DocType Mapper', 'Delivery Note-Packing Slip')"
] ]

View File

@ -133,10 +133,8 @@ erpnext.queries.item = function(opts) {
WHERE tabItem.docstatus!=2 \ WHERE tabItem.docstatus!=2 \
AND (ifnull(`tabItem`.`end_of_life`,"") in ("", "0000-00-00") \ AND (ifnull(`tabItem`.`end_of_life`,"") in ("", "0000-00-00") \
OR `tabItem`.`end_of_life` > NOW()) \ OR `tabItem`.`end_of_life` > NOW()) \
AND tabItem.%(key)s LIKE "%s" ' + (conditions AND (tabItem.%(key)s LIKE \"%s\" OR tabItem.item_name LIKE \"%%%s\")' +
? (" AND " + conditions.join(" AND ")) (conditions ? (" AND " + conditions.join(" AND ")) : "") + " LIMIT 50"
: "")
+ " LIMIT 50"
} }
erpnext.queries.item_std = function() { erpnext.queries.item_std = function() {

View File

@ -136,10 +136,7 @@ erpnext.startup.set_periodic_updates = function() {
erpnext.hide_naming_series = function() { erpnext.hide_naming_series = function() {
if(cur_frm.fields_dict.naming_series) { if(cur_frm.fields_dict.naming_series) {
hide_field('naming_series'); cur_frm.toggle_display("naming_series", cur_frm.doc.__islocal?true:false);
if(cur_frm.doc.__islocal) {
unhide_field('naming_series');
}
} }
} }

View File

@ -1,8 +1,8 @@
[ [
{ {
"creation": "2013-01-28 17:07:01", "creation": "2013-04-10 11:45:37",
"docstatus": 0, "docstatus": 0,
"modified": "2013-03-26 14:05:01", "modified": "2013-04-10 11:49:11",
"modified_by": "Administrator", "modified_by": "Administrator",
"owner": "Administrator" "owner": "Administrator"
}, },
@ -23,13 +23,18 @@
"permlevel": 0 "permlevel": 0
}, },
{ {
"amend": 0,
"create": 1,
"doctype": "DocPerm", "doctype": "DocPerm",
"name": "__common__", "name": "__common__",
"parent": "Lead", "parent": "Lead",
"parentfield": "permissions", "parentfield": "permissions",
"parenttype": "DocType", "parenttype": "DocType",
"permlevel": 0,
"read": 1, "read": 1,
"submit": 0 "report": 1,
"submit": 0,
"write": 1
}, },
{ {
"doctype": "DocType", "doctype": "DocType",
@ -445,69 +450,13 @@
"label": "Blog Subscriber" "label": "Blog Subscriber"
}, },
{ {
"create": 1,
"doctype": "DocPerm",
"permlevel": 0,
"report": 1,
"role": "Guest",
"write": 1
},
{
"amend": 0,
"cancel": 0,
"create": 0,
"doctype": "DocPerm",
"permlevel": 1,
"report": 0,
"role": "Sales User",
"write": 0
},
{
"amend": 0,
"cancel": 0,
"create": 0,
"doctype": "DocPerm",
"permlevel": 1,
"report": 0,
"role": "Sales Manager",
"write": 0
},
{
"amend": 0,
"cancel": 1, "cancel": 1,
"create": 1,
"doctype": "DocPerm", "doctype": "DocPerm",
"permlevel": 0, "role": "Sales Manager"
"report": 1,
"role": "Sales Manager",
"write": 1
}, },
{ {
"amend": 0,
"cancel": 0, "cancel": 0,
"create": 1,
"doctype": "DocPerm", "doctype": "DocPerm",
"permlevel": 0, "role": "Sales User"
"report": 1,
"role": "Sales User",
"write": 1
},
{
"amend": 0,
"cancel": 0,
"create": 0,
"doctype": "DocPerm",
"permlevel": 1,
"role": "All"
},
{
"amend": 0,
"cancel": 0,
"create": 1,
"doctype": "DocPerm",
"permlevel": 0,
"report": 1,
"role": "System Manager",
"write": 1
} }
] ]

View File

@ -125,8 +125,7 @@ class DocType(TransactionBase):
def get_item_details(self, args, obj): def get_item_details(self, args, obj):
import json import json
if not obj.doc.price_list_name: if not obj.doc.price_list_name:
msgprint("Please Select Price List before selecting Items") msgprint("Please Select Price List before selecting Items", raise_exception=True)
raise Exception
item = webnotes.conn.sql("""select description, item_name, brand, item_group, stock_uom, item = webnotes.conn.sql("""select description, item_name, brand, item_group, stock_uom,
default_warehouse, default_income_account, default_sales_cost_center, default_warehouse, default_income_account, default_sales_cost_center,
purchase_account, description_html, barcode from `tabItem` purchase_account, description_html, barcode from `tabItem`

View File

@ -39,10 +39,7 @@ report.get_query = function() {
sp = this.get_filter('Sales Person', 'Sales Person').get_value(); sp = this.get_filter('Sales Person', 'Sales Person').get_value();
date_fld = 'transaction_date'; date_fld = 'transaction_date';
if(based_on == 'Sales Invoice') { if(based_on == 'Sales Invoice' || based_on == "Delivery Note") date_fld = 'posting_date';
based_on = 'Sales Invoice';
date_fld = 'posting_date';
}
sp_cond = ''; sp_cond = '';
if (from_date) sp_cond += ' AND t1.' + date_fld + '>= "' + from_date + '"'; if (from_date) sp_cond += ' AND t1.' + date_fld + '>= "' + from_date + '"';

View File

@ -153,7 +153,7 @@ class DocType:
for d in acc_list_common: for d in acc_list_common:
self.add_acc(d) self.add_acc(d)
country = sql("select value from tabSingles where field = 'country' and doctype = 'Control Panel'") country = webnotes.conn.sql("select value from tabSingles where field = 'country' and doctype = 'Control Panel'")
country = country and cstr(country[0][0]) or '' country = country and cstr(country[0][0]) or ''
# load taxes (only for India) # load taxes (only for India)
@ -265,26 +265,31 @@ class DocType:
""" """
Trash accounts and cost centers for this company if no gl entry exists Trash accounts and cost centers for this company if no gl entry exists
""" """
rec = sql("SELECT name from `tabGL Entry` where ifnull(is_cancelled, 'No') = 'No' and company = %s", self.doc.name) rec = webnotes.conn.sql("SELECT name from `tabGL Entry` where ifnull(is_cancelled, 'No') = 'No' and company = %s", self.doc.name)
if not rec: if not rec:
# delete gl entry # delete gl entry
sql("delete from `tabGL Entry` where company = %s", self.doc.name) webnotes.conn.sql("delete from `tabGL Entry` where company = %s", self.doc.name)
#delete tabAccount #delete tabAccount
sql("delete from `tabAccount` where company = %s order by lft desc, rgt desc", self.doc.name) webnotes.conn.sql("delete from `tabAccount` where company = %s order by lft desc, rgt desc", self.doc.name)
#delete cost center child table - budget detail #delete cost center child table - budget detail
sql("delete bd.* from `tabBudget Detail` bd, `tabCost Center` cc where bd.parent = cc.name and cc.company_name = %s", self.doc.name) webnotes.conn.sql("delete bd.* from `tabBudget Detail` bd, `tabCost Center` cc where bd.parent = cc.name and cc.company_name = %s", self.doc.name)
#delete cost center #delete cost center
sql("delete from `tabCost Center` WHERE company_name = %s order by lft desc, rgt desc", self.doc.name) webnotes.conn.sql("delete from `tabCost Center` WHERE company_name = %s order by lft desc, rgt desc", self.doc.name)
webnotes.defaults.clear_default("company", value=self.doc.name) webnotes.defaults.clear_default("company", value=self.doc.name)
webnotes.conn.sql("""update `tabSingles` set value=""
where doctype='Global Defaults' and field='default_company'
and value=%s""", self.doc.name)
#update value as blank for tabSingles Global Defaults
sql("update `tabSingles` set value = '' where doctype='Global Defaults' and field = 'default_company' and value = %s", self.doc.name)
def on_rename(self,newdn,olddn): def on_rename(self,newdn,olddn):
sql("update `tabCompany` set company_name = '%s' where name = '%s'" %(newdn,olddn)) webnotes.conn.sql("""update `tabCompany` set company_name=%s
sql("update `tabSingles` set value = %s where doctype='Global Defaults' and field = 'default_company' and value = %s", (newdn, olddn)) where name=%s""", (newdn, olddn))
if webnotes.defaults.get_global_default('company') == olddn:
webnotes.defaults.set_global_default('company', newdn) webnotes.conn.sql("""update `tabSingles` set value=%s
where doctype='Global Defaults' and field='default_company'
and value=%s""", (newdn, olddn))
webnotes.defaults.clear_default("company", value=olddn)

View File

@ -94,8 +94,7 @@ class DocType(DocListController):
msg_for_this_receipient = self.get_msg_html(self.get_user_specific_content(user_id) + \ msg_for_this_receipient = self.get_msg_html(self.get_user_specific_content(user_id) + \
common_msg) common_msg)
from webnotes.utils.email_lib import sendmail from webnotes.utils.email_lib import sendmail
sendmail(recipients=user_id, subject=(self.doc.frequency + " Digest"), sendmail(recipients=user_id, subject="[ERPNext] " + (self.doc.frequency + " Digest"),
sender="ERPNext Notifications <notifications+email_digest@erpnext.com>",
msg=msg_for_this_receipient) msg=msg_for_this_receipient)
def get_digest_msg(self): def get_digest_msg(self):

View File

@ -2,7 +2,7 @@
{ {
"creation": "2012-02-02 11:50:33", "creation": "2012-02-02 11:50:33",
"docstatus": 0, "docstatus": 0,
"modified": "2013-04-05 16:08:22", "modified": "2013-04-16 12:26:28",
"modified_by": "Administrator", "modified_by": "Administrator",
"owner": "Administrator" "owner": "Administrator"
}, },
@ -60,6 +60,13 @@
"match_id": 1, "match_id": 1,
"to_field": "dn_detail" "to_field": "dn_detail"
}, },
{
"doctype": "Field Mapper Detail",
"from_field": "eval: flt(obj.qty) - flt(obj.packed_qty)",
"map": "Yes",
"match_id": 1,
"to_field": "qty"
},
{ {
"doctype": "Table Mapper Detail", "doctype": "Table Mapper Detail",
"from_table": "Delivery Note", "from_table": "Delivery Note",

View File

@ -158,7 +158,6 @@ cur_frm.fields_dict['sales_order_no'].get_query = function(doc) {
} }
// ****************************** DELIVERY TYPE ************************************
cur_frm.cscript.delivery_type = function(doc, cdt, cdn) { cur_frm.cscript.delivery_type = function(doc, cdt, cdn) {
if (doc.delivery_type = 'Sample') cfn_set_fields(doc, cdt, cdn); if (doc.delivery_type = 'Sample') cfn_set_fields(doc, cdt, cdn);
} }
@ -185,7 +184,6 @@ cur_frm.fields_dict['transporter_name'].get_query = function(doc) {
return 'SELECT DISTINCT `tabSupplier`.`name` FROM `tabSupplier` WHERE `tabSupplier`.supplier_type = "transporter" AND `tabSupplier`.docstatus != 2 AND `tabSupplier`.%(key)s LIKE "%s" ORDER BY `tabSupplier`.`name` LIMIT 50'; return 'SELECT DISTINCT `tabSupplier`.`name` FROM `tabSupplier` WHERE `tabSupplier`.supplier_type = "transporter" AND `tabSupplier`.docstatus != 2 AND `tabSupplier`.%(key)s LIKE "%s" ORDER BY `tabSupplier`.`name` LIMIT 50';
} }
//-----------------------------------Make Sales Invoice----------------------------------------------
cur_frm.cscript['Make Sales Invoice'] = function() { cur_frm.cscript['Make Sales Invoice'] = function() {
var doc = cur_frm.doc var doc = cur_frm.doc
n = wn.model.make_new_doc_and_get_name('Sales Invoice'); n = wn.model.make_new_doc_and_get_name('Sales Invoice');
@ -201,7 +199,6 @@ cur_frm.cscript['Make Sales Invoice'] = function() {
); );
} }
//-----------------------------------Make Installation Note----------------------------------------------
cur_frm.cscript['Make Installation Note'] = function() { cur_frm.cscript['Make Installation Note'] = function() {
var doc = cur_frm.doc; var doc = cur_frm.doc;
if(doc.per_installed < 99.99){ if(doc.per_installed < 99.99){
@ -221,31 +218,19 @@ cur_frm.cscript['Make Installation Note'] = function() {
msgprint("Item installation is already completed") msgprint("Item installation is already completed")
} }
//-----------------------------------Make Sales Invoice----------------------------------------------
cur_frm.cscript['Make Packing Slip'] = function() { cur_frm.cscript['Make Packing Slip'] = function() {
var doc = cur_frm.doc
n = wn.model.make_new_doc_and_get_name('Packing Slip'); n = wn.model.make_new_doc_and_get_name('Packing Slip');
$c('dt_map', args={ ps = locals["Packing Slip"][n];
'docs':wn.model.compress([locals['Packing Slip'][n]]), ps.delivery_note = cur_frm.doc.name;
'from_doctype':doc.doctype, loaddoc('Packing Slip', n);
'to_doctype':'Packing Slip',
'from_docname':doc.name,
'from_to_list':"[['Delivery Note','Packing Slip'],['Delivery Note Item','Packing Slip Item']]"
}, function(r,rt) {
loaddoc('Packing Slip', n);
}
);
} }
//get query select Territory //get query select Territory
//=======================================================================================================================
cur_frm.fields_dict['territory'].get_query = function(doc,cdt,cdn) { cur_frm.fields_dict['territory'].get_query = function(doc,cdt,cdn) {
return 'SELECT `tabTerritory`.`name`,`tabTerritory`.`parent_territory` FROM `tabTerritory` WHERE `tabTerritory`.`is_group` = "No" AND `tabTerritory`.`docstatus`!= 2 AND `tabTerritory`.%(key)s LIKE "%s" ORDER BY `tabTerritory`.`name` ASC LIMIT 50'; return 'SELECT `tabTerritory`.`name`,`tabTerritory`.`parent_territory` FROM `tabTerritory` WHERE `tabTerritory`.`is_group` = "No" AND `tabTerritory`.`docstatus`!= 2 AND `tabTerritory`.%(key)s LIKE "%s" ORDER BY `tabTerritory`.`name` ASC LIMIT 50';
} }
//------------------------for printing without amount----------
var set_print_hide= function(doc, cdt, cdn){ var set_print_hide= function(doc, cdt, cdn){
var dn_fields = wn.meta.docfield_map['Delivery Note']; var dn_fields = wn.meta.docfield_map['Delivery Note'];
var dn_item_fields = wn.meta.docfield_map['Delivery Note Item']; var dn_item_fields = wn.meta.docfield_map['Delivery Note Item'];

View File

@ -20,7 +20,7 @@ import webnotes
from webnotes.utils import cstr, flt, getdate, cint from webnotes.utils import cstr, flt, getdate, cint
from webnotes.model.bean import getlist from webnotes.model.bean import getlist
from webnotes.model.code import get_obj from webnotes.model.code import get_obj
from webnotes import msgprint from webnotes import msgprint, _
import webnotes.defaults import webnotes.defaults
@ -333,17 +333,15 @@ class DocType(SellingController):
""" """
Cancel submitted packing slips related to this delivery note Cancel submitted packing slips related to this delivery note
""" """
res = webnotes.conn.sql("""\ res = webnotes.conn.sql("""SELECT name FROM `tabPacking Slip` WHERE delivery_note = %s
SELECT name, count(*) FROM `tabPacking Slip` AND docstatus = 1""", self.doc.name)
WHERE delivery_note = %s AND docstatus = 1
""", self.doc.name)
if res and res[0][1]>0: if res:
from webnotes.model.bean import Bean from webnotes.model.bean import Bean
for r in res: for r in res:
ps = Bean(dt='Packing Slip', dn=r[0]) ps = Bean(dt='Packing Slip', dn=r[0])
ps.cancel() ps.cancel()
webnotes.msgprint("%s Packing Slip(s) Cancelled" % res[0][1]) webnotes.msgprint(_("Packing Slip(s) Cancelled"))
def update_stock_ledger(self, update_stock): def update_stock_ledger(self, update_stock):
@ -421,4 +419,4 @@ class DocType(SellingController):
if gl_entries: if gl_entries:
from accounts.general_ledger import make_gl_entries from accounts.general_ledger import make_gl_entries
make_gl_entries(gl_entries) make_gl_entries(gl_entries)

View File

@ -2,7 +2,7 @@
{ {
"creation": "2013-03-26 11:03:09", "creation": "2013-03-26 11:03:09",
"docstatus": 0, "docstatus": 0,
"modified": "2013-03-28 15:42:41", "modified": "2013-04-17 17:20:45",
"modified_by": "Administrator", "modified_by": "Administrator",
"owner": "Administrator" "owner": "Administrator"
}, },
@ -332,17 +332,6 @@
"read_only": 1, "read_only": 1,
"width": "150px" "width": "150px"
}, },
{
"allow_on_submit": 1,
"default": "0",
"doctype": "DocField",
"fieldname": "packed_qty",
"fieldtype": "Float",
"label": "Packed Quantity",
"no_copy": 1,
"print_hide": 1,
"read_only": 1
},
{ {
"doctype": "DocField", "doctype": "DocField",
"fieldname": "prevdoc_doctype", "fieldname": "prevdoc_doctype",

View File

@ -22,12 +22,10 @@ from webnotes.model.doc import addchild
from webnotes.model.bean import getlist from webnotes.model.bean import getlist
from webnotes import msgprint, _ from webnotes import msgprint, _
sql = webnotes.conn.sql
from webnotes.model.controller import DocListController from webnotes.model.controller import DocListController
class DocType(DocListController): class DocType(DocListController):
def get_tax_rate(self, tax_type): def get_tax_rate(self, tax_type):
rate = sql("select tax_rate from tabAccount where name = %s", tax_type) rate = webnotes.conn.sql("select tax_rate from tabAccount where name = %s", tax_type)
ret = { ret = {
'tax_rate' : rate and flt(rate[0][0]) or 0 'tax_rate' : rate and flt(rate[0][0]) or 0
} }
@ -39,7 +37,8 @@ class DocType(DocListController):
# webpage updates # webpage updates
self.update_website() self.update_website()
bin = sql("select stock_uom from `tabBin` where item_code = '%s' " % self.doc.item_code) bin = webnotes.conn.sql("select stock_uom from `tabBin` where item_code = %s",
self.doc.item_code)
if bin and cstr(bin[0][0]) and cstr(bin[0][0]) != cstr(self.doc.stock_uom): if bin and cstr(bin[0][0]) and cstr(bin[0][0]) != cstr(self.doc.stock_uom):
msgprint("Please Update Stock UOM with the help of Stock UOM Replace Utility.") msgprint("Please Update Stock UOM with the help of Stock UOM Replace Utility.")
raise Exception raise Exception
@ -107,8 +106,8 @@ class DocType(DocListController):
# On delete 1. Delete BIN (if none of the corrosponding transactions present, it gets deleted. if present, rolled back due to exception) # On delete 1. Delete BIN (if none of the corrosponding transactions present, it gets deleted. if present, rolled back due to exception)
def on_trash(self): def on_trash(self):
sql("""delete from tabBin where item_code=%s""", self.doc.item_code) webnotes.conn.sql("""delete from tabBin where item_code=%s""", self.doc.item_code)
sql("""delete from `tabStock Ledger Entry` webnotes.conn.sql("""delete from `tabStock Ledger Entry`
where item_code=%s and is_cancelled='Yes' """, self.doc.item_code) where item_code=%s and is_cancelled='Yes' """, self.doc.item_code)
if self.doc.page_name: if self.doc.page_name:
@ -149,7 +148,7 @@ class DocType(DocListController):
def check_for_active_boms(self, field_label): def check_for_active_boms(self, field_label):
if field_label in ['Is Active', 'Is Purchase Item']: if field_label in ['Is Active', 'Is Purchase Item']:
bom_mat = sql("select distinct t1.parent from `tabBOM Item` t1, `tabBOM` t2 where t1.item_code ='%s' and (t1.bom_no = '' or t1.bom_no is NULL) and t2.name = t1.parent and t2.is_active = 1 and t2.docstatus = 1 and t1.docstatus =1 " % self.doc.name ) bom_mat = webnotes.conn.sql("select distinct t1.parent from `tabBOM Item` t1, `tabBOM` t2 where t1.item_code =%s and (t1.bom_no = '' or t1.bom_no is NULL) and t2.name = t1.parent and t2.is_active = 1 and t2.docstatus = 1 and t1.docstatus =1 ", self.doc.name)
if bom_mat and bom_mat[0][0]: if bom_mat and bom_mat[0][0]:
msgprint("%s should be 'Yes'. As Item %s is present in one or many Active BOMs." % (cstr(field_label), cstr(self.doc.name))) msgprint("%s should be 'Yes'. As Item %s is present in one or many Active BOMs." % (cstr(field_label), cstr(self.doc.name)))
raise Exception raise Exception
@ -157,25 +156,27 @@ class DocType(DocListController):
and self.doc.is_sub_contracted_item != 'Yes') and self.doc.is_sub_contracted_item != 'Yes')
or (field_label == 'Is Sub Contracted Item' or (field_label == 'Is Sub Contracted Item'
and self.doc.is_manufactured_item != 'Yes')): and self.doc.is_manufactured_item != 'Yes')):
bom = sql("select name from `tabBOM` where item = '%s' and is_active = 1" % cstr(self.doc.name)) bom = webnotes.conn.sql("select name from `tabBOM` where item = %s and is_active = 1",
(self.doc.name,))
if bom and bom[0][0]: if bom and bom[0][0]:
msgprint("%s should be 'Yes'. As Item %s is present in one or many Active BOMs." % (cstr(field_label), cstr(self.doc.name))) msgprint("%s should be 'Yes'. As Item %s is present in one or many Active BOMs." % (cstr(field_label), cstr(self.doc.name)))
raise Exception raise Exception
def validate_barcode(self): def validate_barcode(self):
if self.doc.barcode: if self.doc.barcode:
duplicate = 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" % (self.doc.barcode, cstr(duplicate[0][0])), raise_exception = 1) msgprint("Barcode: %s already used in item: %s" % (self.doc.barcode, cstr(duplicate[0][0])), raise_exception = 1)
def validate(self): def validate(self):
fl = {'is_manufactured_item' :'Allow Bill of Materials', if not cint(self.doc.fields.get("__islocal")):
fl = {'is_manufactured_item' :'Allow Bill of Materials',
'is_sub_contracted_item':'Is Sub Contracted Item', 'is_sub_contracted_item':'Is Sub Contracted Item',
'is_purchase_item' :'Is Purchase Item', 'is_purchase_item' :'Is Purchase Item',
'is_pro_applicable' :'Allow Production Order'} 'is_pro_applicable' :'Allow Production Order'}
for d in fl: for d in fl:
if cstr(self.doc.fields.get(d)) != 'Yes': if cstr(self.doc.fields.get(d)) != 'Yes':
self.check_for_active_boms(fl[d]) self.check_for_active_boms(fl[d])
self.check_ref_rate_detail() self.check_ref_rate_detail()
self.fill_customer_code() self.fill_customer_code()
self.check_item_tax() self.check_item_tax()
@ -197,7 +198,7 @@ class DocType(DocListController):
def check_non_asset_warehouse(self): def check_non_asset_warehouse(self):
if self.doc.is_asset_item == "Yes": if self.doc.is_asset_item == "Yes":
existing_qty = 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." % (e[1],e[0])) msgprint("%s Units exist in Warehouse %s, which is not an Asset Warehouse." % (e[1],e[0]))
if existing_qty: if existing_qty:
@ -206,7 +207,7 @@ class DocType(DocListController):
raise Exception raise Exception
def get_file_details(self, arg = ''): def get_file_details(self, arg = ''):
file = sql("select file_group, description from tabFile where name = %s", eval(arg)['file_name'], as_dict = 1) file = webnotes.conn.sql("select file_group, description from tabFile where name = %s", eval(arg)['file_name'], as_dict = 1)
ret = { ret = {
'file_group' : file and file[0]['file_group'] or '', 'file_group' : file and file[0]['file_group'] or '',
@ -216,11 +217,11 @@ class DocType(DocListController):
def check_if_sle_exists(self): def check_if_sle_exists(self):
sle = sql("select name from `tabStock Ledger Entry` where item_code = %s and ifnull(is_cancelled, 'No') = 'No'", self.doc.name) sle = webnotes.conn.sql("select name from `tabStock Ledger Entry` where item_code = %s and ifnull(is_cancelled, 'No') = 'No'", self.doc.name)
return sle and 'exists' or 'not exists' return sle and 'exists' or 'not exists'
def on_rename(self,newdn,olddn): def on_rename(self,newdn,olddn):
sql("update tabItem set item_code = %s where name = %s", (newdn, olddn)) webnotes.conn.sql("update tabItem set item_code = %s where name = %s", (newdn, olddn))
if self.doc.page_name: if self.doc.page_name:
from webnotes.webutils import clear_cache from webnotes.webutils import clear_cache
clear_cache(self.doc.page_name) clear_cache(self.doc.page_name)
@ -239,10 +240,10 @@ class DocType(DocListController):
vals = webnotes.conn.get_value("Item", self.doc.name, vals = webnotes.conn.get_value("Item", self.doc.name,
["has_serial_no", "is_stock_item", "valuation_method"], as_dict=True) ["has_serial_no", "is_stock_item", "valuation_method"], as_dict=True)
if vals and (vals.has_serial_no != self.doc.has_serial_no or if vals and ((self.doc.is_stock_item == "No" and vals.is_stock_item == "Yes") or
vals.is_stock_item != self.doc.is_stock_item or vals.has_serial_no != self.doc.has_serial_no or
vals.valuation_method != self.doc.valuation_method): vals.valuation_method != self.doc.valuation_method):
if self.check_if_sle_exists(): if self.check_if_sle_exists() == "exists":
webnotes.msgprint(_("As there are existing stock transactions for this \ webnotes.msgprint(_("As there are existing stock transactions for this \
item, you can not change the values of 'Has Serial No', \ item, you can not change the values of 'Has Serial No', \
'Is Stock Item' and 'Valuation Method'"), raise_exception=1) 'Is Stock Item' and 'Valuation Method'"), raise_exception=1)

View File

@ -23,52 +23,36 @@ cur_frm.fields_dict['item_details'].grid.get_field('item_code').get_query =
function(doc, cdt, cdn) { function(doc, cdt, cdn) {
var query = 'SELECT name, item_name, description FROM `tabItem` WHERE name IN ( \ var query = 'SELECT name, item_name, description FROM `tabItem` WHERE name IN ( \
SELECT item_code FROM `tabDelivery Note Item` dnd \ SELECT item_code FROM `tabDelivery Note Item` dnd \
WHERE parent="' + doc.delivery_note + '" AND IFNULL(qty, 0) > IFNULL(packed_qty, 0)) AND %(key)s LIKE "%s" LIMIT 50'; WHERE parent="' + doc.delivery_note + '" AND IFNULL(qty, 0) > IFNULL(packed_qty, 0)) \
AND %(key)s LIKE "%s" LIMIT 50';
return query; return query;
} }
// Fetch item details
cur_frm.add_fetch("item_code", "item_name", "item_name");
cur_frm.add_fetch("item_code", "stock_uom", "stock_uom");
cur_frm.add_fetch("item_code", "net_weight", "net_weight");
cur_frm.add_fetch("item_code", "weight_uom", "weight_uom");
cur_frm.cscript.onload_post_render = function(doc, cdt, cdn) { cur_frm.cscript.onload_post_render = function(doc, cdt, cdn) {
if(doc.delivery_note && doc.__islocal) { if(doc.delivery_note && doc.__islocal) {
var ps_detail = getchildren('Packing Slip Item', doc.name, 'item_details'); cur_frm.cscript.get_items(doc, cdt, cdn);
if(!(flt(ps_detail.net_weight) && cstr(ps_detail.weight_uom))) {
cur_frm.cscript.update_item_details(doc);
}
} }
} }
cur_frm.cscript.refresh = function(doc, dt, dn) { cur_frm.cscript.get_items = function(doc, cdt, cdn) {
if(!doc.amended_from) { this.frm.call({
hide_field('misc_details'); doc: this.frm.doc,
} else { method: "get_items",
unhide_field('misc_details'); callback: function(r) {
} if(!r.exc) cur_frm.refresh();
}
cur_frm.cscript.update_item_details = function(doc) {
$c_obj(make_doclist(doc.doctype, doc.name), 'update_item_details', '', function(r, rt) {
if(r.exc) {
msgprint(r.exc);
} else {
refresh_many(['item_details', 'naming_series', 'from_case_no', 'to_case_no'])
} }
}); });
} }
cur_frm.cscript.refresh = function(doc, dt, dn) {
cur_frm.toggle_display("misc_details", doc.amended_from);
}
cur_frm.cscript.validate = function(doc, cdt, cdn) { cur_frm.cscript.validate = function(doc, cdt, cdn) {
cur_frm.cscript.validate_case_nos(doc); cur_frm.cscript.validate_case_nos(doc);
cur_frm.cscript.validate_calculate_item_details(doc); cur_frm.cscript.validate_calculate_item_details(doc);
} }
// To Case No. cannot be less than From Case No. // To Case No. cannot be less than From Case No.
cur_frm.cscript.validate_case_nos = function(doc) { cur_frm.cscript.validate_case_nos = function(doc) {
doc = locals[doc.doctype][doc.name]; doc = locals[doc.doctype][doc.name];
@ -99,7 +83,7 @@ cur_frm.cscript.validate_calculate_item_details = function(doc) {
cur_frm.cscript.validate_duplicate_items = function(doc, ps_detail) { cur_frm.cscript.validate_duplicate_items = function(doc, ps_detail) {
for(var i=0; i<ps_detail.length; i++) { for(var i=0; i<ps_detail.length; i++) {
for(var j=0; j<ps_detail.length; j++) { for(var j=0; j<ps_detail.length; j++) {
if(i!=j && ps_detail[i].dn_detail && ps_detail[i].dn_detail==ps_detail[j].dn_detail) { if(i!=j && ps_detail[i].item_code && ps_detail[i].item_code==ps_detail[j].item_code) {
msgprint("You have entered duplicate items. Please rectify and try again."); msgprint("You have entered duplicate items. Please rectify and try again.");
validated = false; validated = false;
return; return;
@ -138,3 +122,17 @@ cur_frm.cscript.calc_net_total_pkg = function(doc, ps_detail) {
refresh_many(['net_weight_pkg', 'net_weight_uom', 'gross_weight_uom', 'gross_weight_pkg']); refresh_many(['net_weight_pkg', 'net_weight_uom', 'gross_weight_uom', 'gross_weight_pkg']);
} }
var make_row = function(title,val,bold){
var bstart = '<b>'; var bend = '</b>';
return '<tr><td class="datalabelcell">'+(bold?bstart:'')+title+(bold?bend:'')+'</td>'
+'<td class="datainputcell" style="text-align:left;">'+ val +'</td>'
+'</tr>'
}
cur_frm.pformat.net_weight_pkg= function(doc){
return '<table style="width:100%">' + make_row('Net Weight', doc.net_weight_pkg) + '</table>'
}
cur_frm.pformat.gross_weight_pkg= function(doc){
return '<table style="width:100%">' + make_row('Gross Weight', doc.gross_weight_pkg) + '</table>'
}

View File

@ -16,13 +16,14 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import webnotes import webnotes
from webnotes.utils import flt, cint, now from webnotes.utils import flt, cint
from webnotes import msgprint, _
from webnotes.model.doc import addchild
class DocType: class DocType:
def __init__(self, d, dl): def __init__(self, d, dl):
self.doc, self.doclist = d, dl self.doc, self.doclist = d, dl
def validate(self): def validate(self):
""" """
* Validate existence of submitted Delivery Note * Validate existence of submitted Delivery Note
@ -32,48 +33,48 @@ class DocType:
It is necessary to validate case nos before checking quantity It is necessary to validate case nos before checking quantity
""" """
self.validate_delivery_note() self.validate_delivery_note()
self.validate_items_mandatory()
self.validate_case_nos() self.validate_case_nos()
self.validate_qty() self.validate_qty()
def validate_delivery_note(self): def validate_delivery_note(self):
""" """
Validates if delivery note has status as submitted Validates if delivery note has status as draft
""" """
res = webnotes.conn.sql("""SELECT docstatus FROM `tabDelivery Note` if cint(webnotes.conn.get_value("Delivery Note", self.doc.delivery_note, "docstatus")) != 0:
WHERE name=%(delivery_note)s""", self.doc.fields) msgprint(_("""Invalid Delivery Note. Delivery Note should exist and should be in
draft state. Please rectify and try again."""), raise_exception=1)
if not(res and res[0][0]==0):
webnotes.msgprint("""Invalid Delivery Note. Delivery Note should exist def validate_items_mandatory(self):
and should be in draft state. Please rectify and try again.""", raise_exception=1) rows = [d.item_code for d in self.doclist.get({"parentfield": "item_details"})]
if not rows:
webnotes.msgprint(_("No Items to Pack"), raise_exception=1)
def validate_case_nos(self): def validate_case_nos(self):
""" """
Validate if case nos overlap Validate if case nos overlap. If they do, recommend next case no.
If they do, recommend next case no.
""" """
if not cint(self.doc.from_case_no): if not cint(self.doc.from_case_no):
webnotes.msgprint("Please specify a valid 'From Case No.'", raise_exception=1) webnotes.msgprint(_("Please specify a valid 'From Case No.'"), raise_exception=1)
elif not self.doc.to_case_no: elif not self.doc.to_case_no:
self.doc.to_case_no = self.doc.from_case_no self.doc.to_case_no = self.doc.from_case_no
elif self.doc.from_case_no > self.doc.to_case_no: elif self.doc.from_case_no > self.doc.to_case_no:
webnotes.msgprint("'To Case No.' cannot be less than 'From Case No.'", webnotes.msgprint(_("'To Case No.' cannot be less than 'From Case No.'"),
raise_exception=1) raise_exception=1)
res = webnotes.conn.sql("""SELECT name FROM `tabPacking Slip` res = webnotes.conn.sql("""SELECT name FROM `tabPacking Slip`
WHERE delivery_note = %(delivery_note)s AND docstatus = 1 AND WHERE delivery_note = %(delivery_note)s AND docstatus = 1 AND
(from_case_no BETWEEN %(from_case_no)s AND %(to_case_no)s (from_case_no BETWEEN %(from_case_no)s AND %(to_case_no)s
OR to_case_no BETWEEN %(from_case_no)s AND %(to_case_no)s) OR to_case_no BETWEEN %(from_case_no)s AND %(to_case_no)s
OR %(from_case_no)s BETWEEN from_case_no AND to_case_no)
""", self.doc.fields) """, self.doc.fields)
if res: if res:
webnotes.msgprint("""Case No(s). already in use. Please rectify and try again. webnotes.msgprint(_("""Case No(s) already in use. Please rectify and try again.
Recommended <b>From Case No. = %s</b>""" % self.get_recommended_case_no(), Recommended <b>From Case No. = %s</b>""") % self.get_recommended_case_no(),
raise_exception=1) raise_exception=1)
def validate_qty(self): def validate_qty(self):
""" """
Check packed qty across packing slips and delivery note Check packed qty across packing slips and delivery note
@ -82,8 +83,9 @@ class DocType:
dn_details, ps_item_qty, no_of_cases = self.get_details_for_packing() dn_details, ps_item_qty, no_of_cases = self.get_details_for_packing()
for item in dn_details: for item in dn_details:
new_packed_qty = (flt(ps_item_qty[item['item_code']]) * no_of_cases) + flt(item['packed_qty']) new_packed_qty = (flt(ps_item_qty[item['item_code']]) * no_of_cases) + \
if new_packed_qty > flt(item['qty']): flt(item['packed_qty'])
if new_packed_qty > flt(item['qty']) and no_of_cases:
self.recommend_new_qty(item, ps_item_qty, no_of_cases) self.recommend_new_qty(item, ps_item_qty, no_of_cases)
@ -94,29 +96,26 @@ class DocType:
* Item Quantity dict of current packing slip doc * Item Quantity dict of current packing slip doc
* No. of Cases of this packing slip * No. of Cases of this packing slip
""" """
item_codes = ", ".join([('"' + d.item_code + '"') for d in
self.doclist])
items = [d.item_code for d in self.doclist.get({"parentfield": "item_details"})] rows = [d.item_code for d in self.doclist.get({"parentfield": "item_details"})]
if not item_codes: webnotes.msgprint("No Items to Pack", condition = ""
raise_exception=1) if rows:
condition = " and item_code in (%s)" % (", ".join(["%s"]*len(rows)))
# gets item code, qty per item code, latest packed qty per item code and stock uom # gets item code, qty per item code, latest packed qty per item code and stock uom
res = webnotes.conn.sql("""select item_code, ifnull(sum(qty), 0) as qty, res = webnotes.conn.sql("""select item_code, ifnull(sum(qty), 0) as qty,
(select sum(ifnull(psi.qty, 0) * (abs(ps.to_case_no - ps.from_case_no) + 1)) (select sum(ifnull(psi.qty, 0) * (abs(ps.to_case_no - ps.from_case_no) + 1))
from `tabPacking Slip` ps, `tabPacking Slip Item` psi from `tabPacking Slip` ps, `tabPacking Slip Item` psi
where ps.name = psi.parent and ps.docstatus = 1 where ps.name = psi.parent and ps.docstatus = 1
and ps.delivery_note = dni.parent and psi.item_code=dni.item_code) and ps.delivery_note = dni.parent and psi.item_code=dni.item_code) as packed_qty,
as packed_qty, stock_uom, item_name
stock_uom
from `tabDelivery Note Item` dni from `tabDelivery Note Item` dni
where parent=%s and item_code in (%s) where parent=%s %s
group by item_code""" % ("%s", ", ".join(["%s"]*len(items))), group by item_code""" % ("%s", condition),
tuple([self.doc.delivery_note] + items), as_dict=1) tuple([self.doc.delivery_note] + rows), as_dict=1)
ps_item_qty = dict([[d.item_code, d.qty] for d in self.doclist])
ps_item_qty = dict([[d.item_code, d.qty] for d in self.doclist])
no_of_cases = cint(self.doc.to_case_no) - cint(self.doc.from_case_no) + 1 no_of_cases = cint(self.doc.to_case_no) - cint(self.doc.from_case_no) + 1
return res, ps_item_qty, no_of_cases return res, ps_item_qty, no_of_cases
@ -136,45 +135,6 @@ class DocType:
<b>Recommended quantity for %(item_code)s = %(recommended_qty)s <b>Recommended quantity for %(item_code)s = %(recommended_qty)s
%(stock_uom)s</b>""" % item, raise_exception=1) %(stock_uom)s</b>""" % item, raise_exception=1)
def on_submit(self):
"""
* Update packed qty for all items
"""
self.update_packed_qty(event='submit')
def on_cancel(self):
"""
* Update packed qty for all items
"""
self.update_packed_qty(event='cancel')
def update_packed_qty(self, event=''):
"""
Updates packed qty for all items
"""
if event not in ['submit', 'cancel']:
raise Exception('update_packed_quantity can only be called on submit or cancel')
# Get Delivery Note Items, Item Quantity Dict and No. of Cases for this Packing slip
dn_details, ps_item_qty, no_of_cases = self.get_details_for_packing()
for item in dn_details:
new_packed_qty = flt(item['packed_qty'])
if (new_packed_qty < 0) or (new_packed_qty > flt(item['qty'])):
webnotes.msgprint("""Invalid new packed quantity for item %s.
Please try again or contact support@erpnext.com""" %
item['item_code'], raise_exception=1)
webnotes.conn.sql("""UPDATE `tabDelivery Note Item`
SET packed_qty = %s WHERE parent = %s AND item_code = %s""",
(new_packed_qty, self.doc.delivery_note, item['item_code']))
webnotes.conn.set_value("Delivery Note", self.doc.delivery_note, "modified", now())
def update_item_details(self): def update_item_details(self):
""" """
Fill empty columns in Packing Slip Item Fill empty columns in Packing Slip Item
@ -183,28 +143,12 @@ class DocType:
self.doc.from_case_no = self.get_recommended_case_no() self.doc.from_case_no = self.get_recommended_case_no()
for d in self.doclist.get({"parentfield": "item_details"}): for d in self.doclist.get({"parentfield": "item_details"}):
self.set_item_details(d) res = webnotes.conn.get_value("Item", d.item_code,
["net_weight", "weight_uom"], as_dict=True)
def set_item_details(self, row):
res = webnotes.conn.sql("""SELECT item_name, SUM(IFNULL(qty, 0)) as total_qty,
IFNULL(packed_qty, 0) as packed_qty, stock_uom
FROM `tabDelivery Note Item`
WHERE parent=%s AND item_code=%s GROUP BY item_code""",
(self.doc.delivery_note, row.item_code), as_dict=1)
if res and len(res)>0:
qty = res[0]['total_qty'] - res[0]['packed_qty']
if not row.qty:
row.qty = qty >= 0 and qty or 0
res = webnotes.conn.sql("""SELECT net_weight, weight_uom FROM `tabItem`
WHERE name=%s""", row.item_code, as_dict=1)
if res and len(res)>0: if res and len(res)>0:
row.net_weight = res[0]["net_weight"] d.net_weight = res["net_weight"]
row.weight_uom = res[0]["weight_uom"] d.weight_uom = res["weight_uom"]
def get_recommended_case_no(self): def get_recommended_case_no(self):
""" """
@ -213,5 +157,18 @@ class DocType:
""" """
recommended_case_no = webnotes.conn.sql("""SELECT MAX(to_case_no) FROM `tabPacking Slip` recommended_case_no = webnotes.conn.sql("""SELECT MAX(to_case_no) FROM `tabPacking Slip`
WHERE delivery_note = %(delivery_note)s AND docstatus=1""", self.doc.fields) WHERE delivery_note = %(delivery_note)s AND docstatus=1""", self.doc.fields)
return cint(recommended_case_no[0][0]) + 1 return cint(recommended_case_no[0][0]) + 1
def get_items(self):
self.doclist = self.doc.clear_table(self.doclist, "item_details", 1)
dn_details = self.get_details_for_packing()[0]
for item in dn_details:
if flt(item.qty) > flt(item.packed_qty):
ch = addchild(self.doc, 'item_details', 'Packing Slip Item', self.doclist)
ch.item_code = item.item_code
ch.item_name = item.item_name
ch.stock_uom = item.stock_uom
ch.qty = flt(item.qty) - flt(item.packed_qty)
self.update_item_details()

View File

@ -1,8 +1,8 @@
[ [
{ {
"creation": "2013-03-07 18:50:31", "creation": "2013-04-11 15:32:24",
"docstatus": 0, "docstatus": 0,
"modified": "2013-04-05 15:40:59", "modified": "2013-04-16 17:33:38",
"modified_by": "Administrator", "modified_by": "Administrator",
"owner": "Administrator" "owner": "Administrator"
}, },
@ -130,6 +130,12 @@
"label": "Package Item Details", "label": "Package Item Details",
"read_only": 0 "read_only": 0
}, },
{
"doctype": "DocField",
"fieldname": "get_items",
"fieldtype": "Button",
"label": "Get Items"
},
{ {
"doctype": "DocField", "doctype": "DocField",
"fieldname": "item_details", "fieldname": "item_details",

View File

@ -1,8 +1,8 @@
[ [
{ {
"creation": "2013-03-07 11:42:59", "creation": "2013-04-08 13:10:16",
"docstatus": 0, "docstatus": 0,
"modified": "2013-04-05 16:06:40", "modified": "2013-04-11 15:06:05",
"modified_by": "Administrator", "modified_by": "Administrator",
"owner": "Administrator" "owner": "Administrator"
}, },
@ -70,7 +70,7 @@
"fieldtype": "Float", "fieldtype": "Float",
"label": "Net Weight", "label": "Net Weight",
"print_width": "100px", "print_width": "100px",
"read_only": 1, "read_only": 0,
"width": "100px" "width": "100px"
}, },
{ {
@ -80,7 +80,7 @@
"label": "Weight UOM", "label": "Weight UOM",
"options": "UOM", "options": "UOM",
"print_width": "100px", "print_width": "100px",
"read_only": 1, "read_only": 0,
"width": "100px" "width": "100px"
}, },
{ {
@ -95,6 +95,7 @@
"fieldname": "dn_detail", "fieldname": "dn_detail",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 1, "hidden": 1,
"label": "DN Detail" "label": "DN Detail",
"read_only": 0
} }
] ]

View File

@ -79,7 +79,6 @@ class DocType(StockController):
values = [{ values = [{
'item_code' : self.doc.item_code, 'item_code' : self.doc.item_code,
'warehouse' : self.doc.warehouse, 'warehouse' : self.doc.warehouse,
'transaction_date' : nowdate(),
'posting_date' : self.doc.purchase_date or (self.doc.creation and self.doc.creation.split(' ')[0]) or nowdate(), 'posting_date' : self.doc.purchase_date or (self.doc.creation and self.doc.creation.split(' ')[0]) or nowdate(),
'posting_time' : self.doc.purchase_time or '00:00', 'posting_time' : self.doc.purchase_time or '00:00',
'voucher_type' : 'Serial No', 'voucher_type' : 'Serial No',

View File

@ -84,7 +84,6 @@ class DocType:
item_details = webnotes.conn.sql("""select item_group, warranty_period item_details = webnotes.conn.sql("""select item_group, warranty_period
from `tabItem` where name = '%s' and (ifnull(end_of_life,'')='' or from `tabItem` where name = '%s' and (ifnull(end_of_life,'')='' or
end_of_life = '0000-00-00' or end_of_life > now()) """ %(d.item_code), as_dict=1) end_of_life = '0000-00-00' or end_of_life > now()) """ %(d.item_code), as_dict=1)
webnotes.errprint([d.item_code, d.valuation_rate])
s.purchase_document_type = obj.doc.doctype s.purchase_document_type = obj.doc.doctype
s.purchase_document_no = obj.doc.name s.purchase_document_no = obj.doc.name

View File

@ -1,8 +1,8 @@
[ [
{ {
"creation": "2013-03-07 11:55:11", "creation": "2013-03-26 06:51:18",
"docstatus": 0, "docstatus": 0,
"modified": "2013-03-13 16:25:22", "modified": "2013-04-17 11:51:24",
"modified_by": "Administrator", "modified_by": "Administrator",
"owner": "Administrator" "owner": "Administrator"
}, },
@ -50,7 +50,7 @@
"fieldtype": "Link", "fieldtype": "Link",
"label": "Home Page", "label": "Home Page",
"options": "Web Page", "options": "Web Page",
"reqd": 1 "reqd": 0
}, },
{ {
"description": "The name of your company / website as you want to appear on browser title bar. All pages will have this as the prefix to the title.", "description": "The name of your company / website as you want to appear on browser title bar. All pages will have this as the prefix to the title.",
@ -236,13 +236,6 @@
"no_copy": 1, "no_copy": 1,
"print_hide": 1 "print_hide": 1
}, },
{
"create": 1,
"doctype": "DocPerm",
"permlevel": 0,
"role": "System Manager",
"write": 1
},
{ {
"create": 1, "create": 1,
"doctype": "DocPerm", "doctype": "DocPerm",

View File

@ -14,25 +14,40 @@ def generate(domain):
import urllib, os import urllib, os
import webnotes import webnotes
import webnotes.webutils import webnotes.webutils
from webnotes.utils import nowdate
# settings # settings
max_doctypes = 10
max_items = 1000 max_items = 1000
count = 0
site_map = '' site_map = ''
page_list = []
if domain: if domain:
# list of all pages in web cache today = nowdate()
for doctype in webnotes.webutils.page_map:
d = webnotes.webutils.page_map[doctype]; # generated pages
for doctype, opts in webnotes.webutils.get_generators().items():
pages = webnotes.conn.sql("""select page_name, `modified` pages = webnotes.conn.sql("""select page_name, `modified`
from `tab%s` where ifnull(%s,0)=1 from `tab%s` where ifnull(%s,0)=1
order by modified desc""" % (doctype, d.condition_field)) order by modified desc""" % (doctype, opts.get("condition_field")))
for p in pages: for p in pages:
if count >= max_items: break
page_url = os.path.join(domain, urllib.quote(p[0])) page_url = os.path.join(domain, urllib.quote(p[0]))
modified = p[1].strftime('%Y-%m-%d') modified = p[1].strftime('%Y-%m-%d')
site_map += link_xml % (page_url, modified) site_map += link_xml % (page_url, modified)
count += 1
if count >= max_items: break
# standard pages
for page, opts in webnotes.get_config()["web"]["pages"].items():
if "no_cache" in opts:
continue
if count >= max_items: break
page_url = os.path.join(domain, urllib.quote(page))
modified = today
site_map += link_xml % (page_url, modified)
count += 1
return frame_xml % site_map return frame_xml % site_map