Merge branch 'master' of github.com:webnotes/erpnext
This commit is contained in:
commit
989ca93b17
@ -20,7 +20,7 @@ def get_companies():
|
||||
else:
|
||||
return [r[0] for r in webnotes.conn.sql("""select name from tabCompany
|
||||
where docstatus!=2""")]
|
||||
|
||||
|
||||
@webnotes.whitelist()
|
||||
def get_children():
|
||||
args = webnotes.form_dict
|
||||
|
@ -1,31 +1,27 @@
|
||||
# Search Criteria, creditors_ledger
|
||||
[
|
||||
|
||||
# These values are common in all dictionaries
|
||||
{
|
||||
'creation': '2012-04-03 12:49:51',
|
||||
'docstatus': 0,
|
||||
'modified': '2012-04-03 12:49:51',
|
||||
'modified_by': u'Administrator',
|
||||
'owner': u'nabin@webnotestech.com'
|
||||
},
|
||||
|
||||
# These values are common for all Search Criteria
|
||||
{
|
||||
'criteria_name': u"Creditor's Ledger",
|
||||
'doc_type': u'GL Entry',
|
||||
'doctype': 'Search Criteria',
|
||||
'filters': u"{'GL Entry\x01Voucher Type':'','GL Entry\x01Is Cancelled':'','GL Entry\x01Is Opening':'','GL Entry\x01Fiscal Year':''}",
|
||||
'module': u'Accounts',
|
||||
'name': '__common__',
|
||||
'page_len': 50,
|
||||
'sort_order': u'DESC',
|
||||
'standard': u'Yes'
|
||||
},
|
||||
|
||||
# Search Criteria, creditors_ledger
|
||||
{
|
||||
'doctype': 'Search Criteria',
|
||||
'name': u'creditors_ledger'
|
||||
}
|
||||
{
|
||||
"owner": "nabin@erpnext.com",
|
||||
"docstatus": 0,
|
||||
"creation": "2012-05-14 18:05:41",
|
||||
"modified_by": "nabin@erpnext.com",
|
||||
"modified": "2012-12-06 11:36:09"
|
||||
},
|
||||
{
|
||||
"custom_query": null,
|
||||
"report_script": null,
|
||||
"page_len": 50,
|
||||
"module": "Accounts",
|
||||
"standard": "Yes",
|
||||
"sort_order": "DESC",
|
||||
"filters": "{\"GL Entry\\u0001Voucher Type\":[],\"GL Entry\\u0001Is Cancelled\":[\"No\"],\"GL Entry\\u0001Is Opening\":[\"\"],\"GL Entry\\u0001Fiscal Year\":[\"\"]}",
|
||||
"doc_type": "GL Entry",
|
||||
"name": "__common__",
|
||||
"doctype": "Search Criteria",
|
||||
"sort_by": "`tabGL Entry`.`name`",
|
||||
"criteria_name": "Creditor's Ledger"
|
||||
},
|
||||
{
|
||||
"name": "creditors_ledger",
|
||||
"doctype": "Search Criteria"
|
||||
}
|
||||
]
|
@ -1,31 +1,27 @@
|
||||
# Search Criteria, debtors_ledger
|
||||
[
|
||||
|
||||
# These values are common in all dictionaries
|
||||
{
|
||||
'creation': '2012-04-03 12:49:51',
|
||||
'docstatus': 0,
|
||||
'modified': '2012-04-03 12:49:51',
|
||||
'modified_by': u'Administrator',
|
||||
'owner': u'nabin@webnotestech.com'
|
||||
},
|
||||
|
||||
# These values are common for all Search Criteria
|
||||
{
|
||||
'criteria_name': u"Debtor's Ledger",
|
||||
'doc_type': u'GL Entry',
|
||||
'doctype': 'Search Criteria',
|
||||
'filters': u"{'GL Entry\x01Voucher Type':'','GL Entry\x01Is Cancelled':'No','GL Entry\x01Is Opening':'','GL Entry\x01Fiscal Year':''}",
|
||||
'module': u'Accounts',
|
||||
'name': '__common__',
|
||||
'page_len': 50,
|
||||
'sort_order': u'DESC',
|
||||
'standard': u'Yes'
|
||||
},
|
||||
|
||||
# Search Criteria, debtors_ledger
|
||||
{
|
||||
'doctype': 'Search Criteria',
|
||||
'name': u'debtors_ledger'
|
||||
}
|
||||
{
|
||||
"owner": "nabin@erpnext.com",
|
||||
"docstatus": 0,
|
||||
"creation": "2012-05-14 18:05:42",
|
||||
"modified_by": "nabin@erpnext.com",
|
||||
"modified": "2012-12-06 11:37:15"
|
||||
},
|
||||
{
|
||||
"custom_query": null,
|
||||
"report_script": null,
|
||||
"page_len": 50,
|
||||
"module": "Accounts",
|
||||
"standard": "Yes",
|
||||
"sort_order": "DESC",
|
||||
"filters": "{\"GL Entry\\u0001Voucher Type\":[],\"GL Entry\\u0001Is Cancelled\":[\"No\"],\"GL Entry\\u0001Is Opening\":[],\"GL Entry\\u0001Fiscal Year\":[]}",
|
||||
"doc_type": "GL Entry",
|
||||
"name": "__common__",
|
||||
"doctype": "Search Criteria",
|
||||
"sort_by": "`tabGL Entry`.`name`",
|
||||
"criteria_name": "Debtor's Ledger"
|
||||
},
|
||||
{
|
||||
"name": "debtors_ledger",
|
||||
"doctype": "Search Criteria"
|
||||
}
|
||||
]
|
@ -199,23 +199,35 @@ cur_frm.cscript.update_stock_qty = function(doc,cdt,cdn){
|
||||
}
|
||||
|
||||
//==================== UOM ======================================================================
|
||||
cur_frm.cscript.uom = function(doc, cdt, cdn) {
|
||||
cur_frm.cscript.uom = function(doc, cdt, cdn, args) {
|
||||
if(!args) args = {};
|
||||
|
||||
// args passed can contain conversion_factor
|
||||
var d = locals[cdt][cdn];
|
||||
if (d.item_code && d.uom) {
|
||||
call_back = function(doc, cdt, cdn){
|
||||
cur_frm.cscript.calc_amount(doc, 2);
|
||||
}
|
||||
str_arg = {'item_code':d.item_code, 'uom':d.uom, 'stock_qty':flt(d.stock_qty), 'qty': flt(d.qty), 'conversion_rate':doc.conversion_rate, 'doc_name': doc.name}
|
||||
// Updates Conversion Factor, Qty and Purchase Rate
|
||||
get_server_fields('get_uom_details',JSON.stringify(str_arg), fname, doc,cdt,cdn,1, call_back);
|
||||
// don't make mistake of calling update_stock_qty() the get_uom_details returns stock_qty as per conversion factor properly
|
||||
$.extend(args, {
|
||||
item_code: d.item_code,
|
||||
uom: d.uom,
|
||||
stock_qty: flt(d.stock_qty),
|
||||
});
|
||||
|
||||
if(d.item_code && d.uom) {
|
||||
cur_frm.call({
|
||||
method: "buying.doctype.purchase_common.purchase_common.get_uom_details",
|
||||
args: { args: args },
|
||||
child: d,
|
||||
callback: function(r) {
|
||||
cur_frm.cscript.calc_amount(doc, 2);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==================== Conversion factor =========================================================
|
||||
cur_frm.cscript.conversion_factor = function(doc, cdt, cdn) {
|
||||
cur_frm.cscript.uom(doc, cdt, cdn);
|
||||
var item = locals[cdt][cdn];
|
||||
|
||||
cur_frm.cscript.uom(doc, cdt, cdn, { conversion_factor: item.conversion_factor });
|
||||
}
|
||||
|
||||
//==================== stock qty ======================================================================
|
||||
|
@ -182,39 +182,6 @@ class DocType(TransactionBase):
|
||||
ret = { 'projected_qty' : bin and flt(bin[0]['projected_qty']) or 0 }
|
||||
return ret
|
||||
|
||||
def get_uom_details(self, arg = ''):
|
||||
"""fetches details on change of UOM"""
|
||||
import json
|
||||
arg, ret = json.loads(arg), {}
|
||||
|
||||
uom = webnotes.conn.sql("""\
|
||||
select conversion_factor
|
||||
from `tabUOM Conversion Detail`
|
||||
where parent = %s and uom = %s""", (arg['item_code'],arg['uom']), as_dict = 1)
|
||||
|
||||
if not uom: return ret
|
||||
|
||||
last_purchase_details, last_purchase_date = self.get_last_purchase_details(arg['item_code'], arg['doc_name'])
|
||||
|
||||
conversion_factor = flt(uom[0]['conversion_factor'])
|
||||
conversion_rate = flt(arg['conversion_rate'])
|
||||
purchase_ref_rate = last_purchase_details and \
|
||||
(last_purchase_details['purchase_ref_rate'] * conversion_factor) or 0
|
||||
purchase_rate = last_purchase_details and \
|
||||
(last_purchase_details['purchase_rate'] * conversion_factor) or 0
|
||||
|
||||
ret = {
|
||||
'conversion_factor': conversion_factor,
|
||||
'qty': flt(arg['stock_qty']) / conversion_factor,
|
||||
'purchase_ref_rate': purchase_ref_rate,
|
||||
'purchase_rate': purchase_rate,
|
||||
'import_ref_rate': purchase_ref_rate / conversion_rate,
|
||||
'import_rate': purchase_rate / conversion_rate,
|
||||
}
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
# --- Last Purchase Rate related methods ---
|
||||
|
||||
def update_last_purchase_rate(self, obj, is_submit):
|
||||
@ -683,3 +650,27 @@ class DocType(TransactionBase):
|
||||
if d.prevdoc_doctype and d.prevdoc_docname:
|
||||
dt = sql("select transaction_date from `tab%s` where name = '%s'" % (d.prevdoc_doctype, d.prevdoc_docname))
|
||||
d.prevdoc_date = dt and dt[0][0].strftime('%Y-%m-%d') or ''
|
||||
|
||||
@webnotes.whitelist()
|
||||
def get_uom_details(args=None):
|
||||
"""fetches details on change of UOM"""
|
||||
if not args:
|
||||
return {}
|
||||
|
||||
if isinstance(args, basestring):
|
||||
import json
|
||||
args = json.loads(args)
|
||||
|
||||
uom = webnotes.conn.sql("""select conversion_factor
|
||||
from `tabUOM Conversion Detail` where parent = %s and uom = %s""",
|
||||
(args['item_code'], args['uom']), as_dict=1)
|
||||
|
||||
if not uom: return {}
|
||||
|
||||
conversion_factor = args.get("conversion_factor") or \
|
||||
flt(uom[0]["conversion_factor"])
|
||||
|
||||
return {
|
||||
"conversion_factor": conversion_factor,
|
||||
"qty": flt(args["stock_qty"]) / conversion_factor,
|
||||
}
|
@ -69,10 +69,6 @@ class DocType(TransactionBase):
|
||||
|
||||
|
||||
|
||||
# Get UOM Details
|
||||
def get_uom_details(self, arg = ''):
|
||||
return get_obj('Purchase Common').get_uom_details(arg)
|
||||
|
||||
# get available qty at warehouse
|
||||
def get_bin_details(self, arg = ''):
|
||||
return get_obj(dt='Purchase Common').get_bin_details(arg)
|
||||
|
@ -27,7 +27,7 @@ wn.doclistviews['Purchase Order'] = wn.views.ListView.extend({
|
||||
},
|
||||
css: {'text-align':'right'}
|
||||
},
|
||||
{width: '8%', content: 'per_received', type:'bar-graph', label:'Delivered'},
|
||||
{width: '8%', content: 'per_received', type:'bar-graph', label:'Received'},
|
||||
{width: '8%', content: 'per_billed', type:'bar-graph', label:'Billed'},
|
||||
{width: '12%', content:'transaction_date',
|
||||
css: {'text-align': 'right', 'color':'#777'},
|
||||
|
@ -121,11 +121,6 @@ class DocType:
|
||||
doc.fields[r] = ret[r]
|
||||
|
||||
|
||||
# Get UOM Details
|
||||
# ---------------------------------
|
||||
def get_uom_details(self, arg = ''):
|
||||
return get_obj(dt='Purchase Common').get_uom_details(arg)
|
||||
|
||||
# GET TERMS & CONDITIONS
|
||||
#-----------------------------
|
||||
def get_tc_details(self):
|
||||
@ -219,4 +214,4 @@ class DocType:
|
||||
self.update_bin(is_submit = 0, is_stopped = (cstr(self.doc.status) == 'Stopped') and 1 or 0)
|
||||
|
||||
# Step 5:=> Set Status
|
||||
webnotes.conn.set(self.doc,'status','Cancelled')
|
||||
webnotes.conn.set(self.doc,'status','Cancelled')
|
@ -140,7 +140,7 @@ class TaxController(TransactionController):
|
||||
self.doc.net_total = flt(self.doc.net_total, self.precision.main.net_total)
|
||||
self.doc.fields[self.fmap.net_total_print] = \
|
||||
flt(self.doc.fields.get(self.fmap.net_total_print),
|
||||
self.precision.main[self.fmap.net_total_print])
|
||||
self.precision.main.get(self.fmap.net_total_print))
|
||||
|
||||
def calculate_taxes(self):
|
||||
for item in self.item_doclist:
|
||||
|
@ -1,5 +1,7 @@
|
||||
erpnext.updates = [
|
||||
["5th December 2012", [
|
||||
"Leave Application: Now can set approver.",
|
||||
"New Roles Added: Leave Approver and Expense Approver.",
|
||||
"Production Order is now linked with sales order.",
|
||||
"Production Planning Tool: The field 'Allow SA items as raw material' has been renamed to 'Use multi-level BOM', 'Include in plan' column from SO table has been deleted",
|
||||
"Batch nos are now filtered with item and available qty",
|
||||
|
@ -3,4 +3,6 @@ install_docs = [
|
||||
{"doctype":"Role", "role_name":"Employee", "name":"Employee"},
|
||||
{"doctype":"Role", "role_name":"HR Manager", "name":"HR Manager"},
|
||||
{"doctype":"Role", "role_name":"HR User", "name":"HR User"},
|
||||
{"doctype":"Role", "role_name":"Leave Approver", "name":"Leave Approver"},
|
||||
{"doctype":"Role", "role_name":"Expense Approver", "name":"Expense Approver"},
|
||||
]
|
||||
|
@ -15,79 +15,84 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
cur_frm.add_fetch('employee', 'company', 'company');
|
||||
cur_frm.add_fetch('employee','employee_name','employee_name');
|
||||
|
||||
cur_frm.cscript.onload = function(doc,cdt,cdn){
|
||||
//
|
||||
if(!doc.approval_status) set_multiple(cdt,cdn,{approval_status:'Draft'});
|
||||
if(doc.employee) cur_frm.cscript.employee(doc,cdt,cdn);
|
||||
|
||||
if(!doc.approval_status)
|
||||
cur_frm.set_value("approval_status", "Draft")
|
||||
|
||||
if (doc.__islocal) {
|
||||
if(doc.amended_from) set_multiple(cdt,cdn,{approval_status:'Draft'});
|
||||
var val = getchildren('Expense Claim Detail', doc.name, 'expense_voucher_details', doc.doctype);
|
||||
for(var i = 0; i<val.length; i++){
|
||||
val[i].sanctioned_amount ='';
|
||||
}
|
||||
doc.total_sanctioned_amount = '';
|
||||
refresh_many(['sanctioned_amount', 'total_sanctioned_amount']);
|
||||
cur_frm.set_value("posting_date", dateutil.get_today());
|
||||
if(doc.amended_from)
|
||||
cur_frm.set_value("approval_status", "Draft");
|
||||
cur_frm.cscript.clear_sanctioned(doc);
|
||||
}
|
||||
|
||||
cur_frm.call({
|
||||
method:"get_approver_list",
|
||||
callback: function(r) {
|
||||
cur_frm.set_df_property("exp_approver", "options", r.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
cur_frm.cscript.clear_sanctioned = function(doc) {
|
||||
var val = getchildren('Expense Claim Detail', doc.name,
|
||||
'expense_voucher_details', doc.doctype);
|
||||
for(var i = 0; i<val.length; i++){
|
||||
val[i].sanctioned_amount ='';
|
||||
}
|
||||
|
||||
doc.total_sanctioned_amount = '';
|
||||
refresh_many(['sanctioned_amount', 'total_sanctioned_amount']);
|
||||
}
|
||||
|
||||
cur_frm.cscript.refresh = function(doc,cdt,cdn){
|
||||
hide_field('calculate_total_amount');
|
||||
if(user == doc.exp_approver && doc.approval_status == 'Submitted'){
|
||||
unhide_field(['update_voucher', 'approve', 'reject', 'calculate_total_amount']);
|
||||
cur_frm.fields_dict['expense_voucher_details'].grid.set_column_disp('sanctioned_amount', true);
|
||||
set_field_permlevel('remark', 0);
|
||||
cur_frm.set_intro("");
|
||||
if(doc.__islocal && !in_list(user_roles, "HR User")) {
|
||||
cur_frm.set_intro("Fill the form and save it")
|
||||
} else {
|
||||
hide_field(['update_voucher', 'approve', 'reject']);
|
||||
cur_frm.fields_dict['expense_voucher_details'].grid.set_column_disp('sanctioned_amount', false);
|
||||
set_field_permlevel('remark', 1);
|
||||
if(doc.approval_status=="Draft") {
|
||||
if(user==doc.exp_approver) {
|
||||
if(doc.approval_status=="Draft") {
|
||||
cur_frm.set_intro("You are the Expense Approver for this record. Please Update the 'Status' and Save");
|
||||
cur_frm.toggle_enable("approval_status", true);
|
||||
}
|
||||
} else {
|
||||
cur_frm.set_intro("Expense Claim is pending approval. Only the Expense Approver can update status.");
|
||||
cur_frm.toggle_enable("approval_status", false);
|
||||
}
|
||||
} else {
|
||||
if(doc.approval_status=="Approved") {
|
||||
cur_frm.set_intro("Expense Claim has been approved.");
|
||||
} else if(doc.approval_status=="Rejected") {
|
||||
cur_frm.set_intro("Expense Claim has been rejected.");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (doc.docstatus == 0) unhide_field('calculate_total_amount');
|
||||
}
|
||||
|
||||
if(doc.approval_status=="Approved" && doc.docstatus==0) {
|
||||
cur_frm.savesubmit()
|
||||
}}
|
||||
|
||||
cur_frm.cscript.validate = function(doc) {
|
||||
if(cint(doc.docstatus) == 0) {
|
||||
doc.approval_status = "Draft";
|
||||
}
|
||||
cur_frm.cscript.calculate_total(doc);
|
||||
}
|
||||
|
||||
cur_frm.cscript.employee = function(doc,cdt,cdn){
|
||||
if(doc.employee){
|
||||
$c_obj(make_doclist(doc.doctype, doc.name),'set_approver','', function(r,rt){
|
||||
if(r.message){
|
||||
doc.employee_name = r.message['emp_nm'];
|
||||
wn.meta.get_docfield(doc.doctype, 'exp_approver' , doc.name).options = r.message['app_lst'];
|
||||
refresh_many(['exp_approver','employee_name']);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
cur_frm.cscript.calculate_total = function(doc,cdt,cdn){
|
||||
if(doc.approval_status == 'Draft'){
|
||||
var val = getchildren('Expense Claim Detail', doc.name, 'expense_voucher_details', doc.doctype);
|
||||
var total_claim =0;
|
||||
for(var i = 0; i<val.length; i++){
|
||||
val[i].sanctioned_amount = val[i].claim_amount;
|
||||
total_claim = flt(total_claim)+flt(val[i].claim_amount);
|
||||
refresh_field('sactioned_amount', val[i].name, 'expense_voucher_details');
|
||||
doc.total_claimed_amount = 0;
|
||||
doc.total_sanctioned_amount = 0;
|
||||
$.each(wn.model.get("Expense Claim Detail", {parent:doc.name}), function(i, d) {
|
||||
doc.total_claimed_amount += d.claim_amount;
|
||||
if(d.sanctioned_amount==null) {
|
||||
d.sanctioned_amount = d.claim_amount;
|
||||
}
|
||||
doc.total_claimed_amount = flt(total_claim);
|
||||
refresh_field('total_claimed_amount');
|
||||
}
|
||||
else if(doc.approval_status == 'Submitted'){
|
||||
var val = getchildren('Expense Claim Detail', doc.name, 'expense_voucher_details', doc.doctype);
|
||||
var total_sanctioned = 0;
|
||||
for(var i = 0; i<val.length; i++){
|
||||
total_sanctioned = flt(total_sanctioned)+flt(val[i].sanctioned_amount);
|
||||
refresh_field('sactioned_amount', val[i].name, 'expense_voucher_details');
|
||||
|
||||
}
|
||||
doc.total_sanctioned_amount = flt(total_sanctioned);
|
||||
refresh_field('total_sanctioned_amount');
|
||||
}
|
||||
doc.total_sanctioned_amount += d.sanctioned_amount;
|
||||
});
|
||||
|
||||
refresh_field("total_claimed_amount");
|
||||
refresh_field('total_sanctioned_amount');
|
||||
|
||||
}
|
||||
|
||||
cur_frm.cscript.calculate_total_amount = function(doc,cdt,cdn){
|
||||
@ -100,155 +105,8 @@ cur_frm.cscript.sanctioned_amount = function(doc,cdt,cdn){
|
||||
cur_frm.cscript.calculate_total(doc,cdt,cdn);
|
||||
}
|
||||
|
||||
cur_frm.cscript.approve = function(doc,cdt,cdn){
|
||||
cur_frm.cscript.calculate_total(doc,cdt,cdn);
|
||||
|
||||
if(user == doc.exp_approver){
|
||||
var approve_voucher_dialog;
|
||||
|
||||
set_approve_voucher_dialog = function() {
|
||||
approve_voucher_dialog = new Dialog(400, 200, 'Approve Voucher');
|
||||
approve_voucher_dialog.make_body([
|
||||
['HTML', 'Message', '<div class = "comment">You wont be able to do any changes after approving this expense voucher. Are you sure, you want to approve it ?</div>'],
|
||||
['HTML', 'Response', '<div class = "comment" id="approve_voucher_dialog_response"></div>'],
|
||||
['HTML', 'Approve Voucher', '<div></div>']
|
||||
]);
|
||||
|
||||
var approve_voucher_btn1 = $a($i(approve_voucher_dialog.widgets['Approve Voucher']), 'button', 'button');
|
||||
approve_voucher_btn1.innerHTML = 'Yes';
|
||||
approve_voucher_btn1.onclick = function(){ approve_voucher_dialog.add(); }
|
||||
|
||||
var approve_voucher_btn2 = $a($i(approve_voucher_dialog.widgets['Approve Voucher']), 'button', 'button');
|
||||
approve_voucher_btn2.innerHTML = 'No';
|
||||
$y(approve_voucher_btn2,{marginLeft:'4px'});
|
||||
approve_voucher_btn2.onclick = function(){ approve_voucher_dialog.hide();}
|
||||
|
||||
approve_voucher_dialog.onshow = function() {
|
||||
$i('approve_voucher_dialog_response').innerHTML = '';
|
||||
}
|
||||
|
||||
approve_voucher_dialog.add = function() {
|
||||
// sending...
|
||||
$i('approve_voucher_dialog_response').innerHTML = 'Processing...';
|
||||
|
||||
$c_obj(make_doclist(this.doc.doctype, this.doc.name),'approve_voucher','', function(r,rt){
|
||||
if(r.message == 'Approved'){
|
||||
$i('approve_voucher_dialog_response').innerHTML = 'Approved';
|
||||
refresh_field('approval_status');
|
||||
hide_field(['update_voucher', 'approve', 'reject', 'calculate_total_amount']);
|
||||
approve_voucher_dialog.hide();
|
||||
var args = {
|
||||
type: 'Expense Claim Approved',
|
||||
doctype: 'Expense Claim',
|
||||
contact_name: doc.employee_name,
|
||||
send_to: doc.email_id
|
||||
}
|
||||
cur_frm.cscript.notify(doc, args);
|
||||
}
|
||||
else if(r.message == 'Incomplete'){
|
||||
$i('approve_voucher_dialog_response').innerHTML = 'Incomplete Voucher';
|
||||
}
|
||||
else if(r.message == 'No Amount'){
|
||||
$i('approve_voucher_dialog_response').innerHTML = 'Calculate total amount';
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if(!approve_voucher_dialog){
|
||||
set_approve_voucher_dialog();
|
||||
}
|
||||
approve_voucher_dialog.doc = doc;
|
||||
approve_voucher_dialog.cdt = cdt;
|
||||
approve_voucher_dialog.cdn = cdn;
|
||||
approve_voucher_dialog.show();
|
||||
refresh_field('expense_voucher_details');
|
||||
doc.__unsaved = 0;
|
||||
cur_frm.refresh_header();
|
||||
}else{
|
||||
msgprint("Expense Claim can be approved by Approver only");
|
||||
}
|
||||
}
|
||||
|
||||
cur_frm.cscript.reject = function(doc,cdt,cdn){
|
||||
cur_frm.cscript.calculate_total(doc,cdt,cdn);
|
||||
|
||||
if(user == doc.exp_approver){
|
||||
var reject_voucher_dialog;
|
||||
|
||||
set_reject_voucher_dialog = function() {
|
||||
reject_voucher_dialog = new Dialog(400, 200, 'Reject Voucher');
|
||||
reject_voucher_dialog.make_body([
|
||||
['HTML', 'Message', '<div class = "comment">You wont be able to do any changes after rejecting this expense voucher. Are you sure, you want to reject it ?</div>'],
|
||||
['HTML', 'Response', '<div class = "comment" id="reject_voucher_dialog_response"></div>'],
|
||||
['HTML', 'Reject Voucher', '<div></div>']
|
||||
]);
|
||||
|
||||
var reject_voucher_btn1 = $a($i(reject_voucher_dialog.widgets['Reject Voucher']), 'button', 'button');
|
||||
reject_voucher_btn1.innerHTML = 'Yes';
|
||||
reject_voucher_btn1.onclick = function(){ reject_voucher_dialog.add(); }
|
||||
|
||||
var reject_voucher_btn2 = $a($i(reject_voucher_dialog.widgets['Reject Voucher']), 'button', 'button');
|
||||
reject_voucher_btn2.innerHTML = 'No';
|
||||
$y(reject_voucher_btn2,{marginLeft:'4px'});
|
||||
reject_voucher_btn2.onclick = function(){ reject_voucher_dialog.hide();}
|
||||
|
||||
reject_voucher_dialog.onshow = function() {
|
||||
$i('reject_voucher_dialog_response').innerHTML = '';
|
||||
}
|
||||
|
||||
reject_voucher_dialog.add = function() {
|
||||
// sending...
|
||||
$i('reject_voucher_dialog_response').innerHTML = 'Processing...';
|
||||
|
||||
$c_obj(make_doclist(this.doc.doctype, this.doc.name),'reject_voucher','', function(r,rt){
|
||||
if(r.message == 'Rejected'){
|
||||
$i('reject_voucher_dialog_response').innerHTML = 'Rejected';
|
||||
refresh_field('approval_status');
|
||||
hide_field(['update_voucher', 'approve', 'reject', 'calculate_total_amount']);
|
||||
reject_voucher_dialog.hide();
|
||||
var args = {
|
||||
type: 'Expense Claim Rejected',
|
||||
doctype: 'Expense Claim',
|
||||
contact_name: doc.employee_name,
|
||||
send_to: doc.email_id
|
||||
}
|
||||
cur_frm.cscript.notify(doc, args);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if(!reject_voucher_dialog){
|
||||
set_reject_voucher_dialog();
|
||||
}
|
||||
reject_voucher_dialog.doc = doc;
|
||||
reject_voucher_dialog.cdt = cdt;
|
||||
reject_voucher_dialog.cdn = cdn;
|
||||
reject_voucher_dialog.show();
|
||||
refresh_field('expense_voucher_details');
|
||||
doc.__unsaved = 0;
|
||||
cur_frm.refresh_header();
|
||||
}else{
|
||||
msgprint("Expense Claim can be rejected by Approver only");
|
||||
}
|
||||
}
|
||||
|
||||
//update follow up
|
||||
//=================================================================================
|
||||
cur_frm.cscript.update_voucher = function(doc){
|
||||
|
||||
$c_obj(make_doclist(doc.doctype, doc.name),'update_voucher','',function(r, rt){
|
||||
refresh_field('expense_voucher_details');
|
||||
doc.__unsaved = 0;
|
||||
cur_frm.refresh_header();
|
||||
});
|
||||
}
|
||||
|
||||
cur_frm.cscript.on_submit = function(doc, cdt, cdn) {
|
||||
if(cint(wn.boot.notification_settings.expense_claim)) {
|
||||
if(cint(wn.boot.notification_settings && wn.boot.notification_settings.expense_claim)) {
|
||||
cur_frm.email_doc(wn.boot.notification_settings.expense_claim_message);
|
||||
}
|
||||
}
|
||||
|
||||
cur_frm.fields_dict.employee.get_query = erpnext.utils.employee_query;
|
||||
}
|
@ -17,86 +17,27 @@
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
|
||||
from webnotes.utils import add_days, cstr
|
||||
from webnotes.model import db_exists
|
||||
from webnotes.model.wrapper import getlist, copy_doclist
|
||||
from webnotes.model.code import get_obj
|
||||
from webnotes.utils import add_days
|
||||
from webnotes.model.wrapper import getlist
|
||||
from webnotes import form, msgprint
|
||||
|
||||
sql = webnotes.conn.sql
|
||||
|
||||
|
||||
|
||||
class DocType:
|
||||
def __init__(self, doc, doclist=[]):
|
||||
self.doc = doc
|
||||
self.doclist = doclist
|
||||
|
||||
def get_employee_name(self):
|
||||
emp_dtl = sql("select employee_name,company_email from `tabEmployee` where name=%s", self.doc.employee)
|
||||
emp_nm = emp_dtl and emp_dtl[0][0] or ''
|
||||
self.doc.employee_name = emp_nm
|
||||
self.doc.email_id = emp_dtl and emp_dtl[0][1] or ''
|
||||
|
||||
return cstr(emp_nm)
|
||||
|
||||
def get_approver_lst(self):
|
||||
approver_lst =[]
|
||||
approver_lst1 = get_obj('Authorization Control').get_approver_name(self.doc.doctype,0,self)
|
||||
if approver_lst1:
|
||||
approver_lst=approver_lst1
|
||||
else:
|
||||
approver_lst = [x[0] for x in sql("select distinct name from `tabProfile` where enabled=1 and name!='Administrator' and name!='Guest' and docstatus!=2")]
|
||||
return approver_lst
|
||||
|
||||
def set_approver(self):
|
||||
ret={}
|
||||
approver_lst =[]
|
||||
emp_nm = self.get_employee_name()
|
||||
approver_lst = self.get_approver_lst()
|
||||
ret = {'app_lst':"\n" + "\n".join(approver_lst), 'emp_nm':cstr(emp_nm)}
|
||||
return ret
|
||||
|
||||
def update_voucher(self):
|
||||
sql("delete from `tabExpense Claim Detail` where parent = '%s'"%self.doc.name)
|
||||
for d in getlist(self.doclist, 'expense_voucher_details'):
|
||||
if not d.expense_type or not d.claim_amount:
|
||||
msgprint("Please remove the extra blank row added")
|
||||
raise Exception
|
||||
d.save(1)
|
||||
if self.doc.total_sanctioned_amount:
|
||||
webnotes.conn.set(self.doc,'total_sanctioned_amount',self.doc.total_sanctioned_amount)
|
||||
if self.doc.remark:
|
||||
webnotes.conn.set(self.doc, 'remark', self.doc.remark)
|
||||
|
||||
def approve_voucher(self):
|
||||
missing_count = 0
|
||||
for d in getlist(self.doclist, 'expense_voucher_details'):
|
||||
if not d.sanctioned_amount:
|
||||
missing_count += 1
|
||||
if missing_count == len(getlist(self.doclist, 'expense_voucher_details')):
|
||||
msgprint("Please add 'Sanctioned Amount' for atleast one expense")
|
||||
return cstr('Incomplete')
|
||||
|
||||
if not self.doc.total_sanctioned_amount:
|
||||
msgprint("Please calculate total sanctioned amount using button 'Calculate Total Amount'")
|
||||
return cstr('No Amount')
|
||||
self.update_voucher()
|
||||
|
||||
webnotes.conn.set(self.doc, 'approval_status', 'Approved')
|
||||
# on approval notification
|
||||
#get_obj('Notification Control').notify_contact('Expense Claim Approved', self.doc.doctype, self.doc.name, self.doc.email_id, self.doc.employee_name)
|
||||
|
||||
return cstr('Approved')
|
||||
|
||||
def reject_voucher(self):
|
||||
|
||||
if self.doc.remark:
|
||||
webnotes.conn.set(self.doc, 'remark', self.doc.remark)
|
||||
webnotes.conn.set(self.doc, 'approval_status', 'Rejected')
|
||||
|
||||
return cstr('Rejected')
|
||||
|
||||
def validate(self):
|
||||
if self.doc.exp_approver == self.doc.owner:
|
||||
webnotes.msgprint("""Self Approval is not allowed.""", raise_exception=1)
|
||||
self.validate_fiscal_year()
|
||||
self.validate_exp_details()
|
||||
|
||||
def on_submit(self):
|
||||
if self.doc.approval_status=="Draft":
|
||||
webnotes.msgprint("""Please set Approval Status to 'Approved' or 'Rejected' before submitting""",
|
||||
raise_exception=1)
|
||||
|
||||
def validate_fiscal_year(self):
|
||||
fy=sql("select year_start_date from `tabFiscal Year` where name='%s'"%self.doc.fiscal_year)
|
||||
@ -105,33 +46,16 @@ class DocType:
|
||||
if str(self.doc.posting_date) < str(ysd) or str(self.doc.posting_date) > str(yed):
|
||||
msgprint("Posting Date is not within the Fiscal Year selected")
|
||||
raise Exception
|
||||
|
||||
def validate(self):
|
||||
self.validate_fiscal_year()
|
||||
|
||||
def on_update(self):
|
||||
webnotes.conn.set(self.doc, 'approval_status', 'Draft')
|
||||
|
||||
|
||||
def validate_exp_details(self):
|
||||
if not getlist(self.doclist, 'expense_voucher_details'):
|
||||
msgprint("Please add expense voucher details")
|
||||
raise Exception
|
||||
|
||||
if not self.doc.total_claimed_amount:
|
||||
msgprint("Please calculate Total Claimed Amount")
|
||||
raise Exception
|
||||
|
||||
if not self.doc.exp_approver:
|
||||
msgprint("Please select Expense Claim approver")
|
||||
raise Exception
|
||||
|
||||
def on_submit(self):
|
||||
self.validate_exp_details()
|
||||
webnotes.conn.set(self.doc, 'approval_status', 'Submitted')
|
||||
|
||||
def on_cancel(self):
|
||||
webnotes.conn.set(self.doc, 'approval_status', 'Cancelled')
|
||||
|
||||
def get_formatted_message(self, args):
|
||||
""" get formatted message for auto notification"""
|
||||
return get_obj('Notification Control').get_formatted_message(args)
|
||||
@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
|
||||
|
@ -1,390 +1,271 @@
|
||||
# DocType, Expense Claim
|
||||
[
|
||||
|
||||
# These values are common in all dictionaries
|
||||
{
|
||||
'creation': '2012-03-27 14:35:56',
|
||||
'docstatus': 0,
|
||||
'modified': '2012-03-27 14:45:48',
|
||||
'modified_by': u'Administrator',
|
||||
'owner': u'harshada@webnotestech.com'
|
||||
},
|
||||
|
||||
# These values are common for all DocType
|
||||
{
|
||||
'_last_update': u'1308808105',
|
||||
'autoname': u'EXP.######',
|
||||
'colour': u'White:FFF',
|
||||
'default_print_format': u'Standard',
|
||||
'doctype': 'DocType',
|
||||
'is_submittable': 1,
|
||||
'module': u'HR',
|
||||
'name': '__common__',
|
||||
'search_fields': u'approval_status,employee,employee_name',
|
||||
'section_style': u'Simple',
|
||||
'server_code_error': u' ',
|
||||
'show_in_menu': 0,
|
||||
'subject': u'From %(employee_name)s for %(total_claimed_amount)s (claimed)',
|
||||
'tag_fields': u'approval_status',
|
||||
'version': 135
|
||||
},
|
||||
|
||||
# These values are common for all DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'name': '__common__',
|
||||
'parent': u'Expense Claim',
|
||||
'parentfield': u'fields',
|
||||
'parenttype': u'DocType'
|
||||
},
|
||||
|
||||
# These values are common for all DocPerm
|
||||
{
|
||||
'doctype': u'DocPerm',
|
||||
'name': '__common__',
|
||||
'parent': u'Expense Claim',
|
||||
'parentfield': u'permissions',
|
||||
'parenttype': u'DocType',
|
||||
'read': 1
|
||||
},
|
||||
|
||||
# DocType, Expense Claim
|
||||
{
|
||||
'doctype': 'DocType',
|
||||
'name': u'Expense Claim'
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'doctype': u'DocPerm',
|
||||
'permlevel': 1,
|
||||
'role': u'All'
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'amend': 1,
|
||||
'cancel': 1,
|
||||
'create': 1,
|
||||
'doctype': u'DocPerm',
|
||||
'match': u'owner',
|
||||
'permlevel': 0,
|
||||
'submit': 1,
|
||||
'write': 1
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'amend': 1,
|
||||
'cancel': 1,
|
||||
'create': 1,
|
||||
'doctype': u'DocPerm',
|
||||
'permlevel': 0,
|
||||
'role': u'HR Manager',
|
||||
'submit': 1,
|
||||
'write': 1
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'amend': 1,
|
||||
'cancel': 1,
|
||||
'create': 1,
|
||||
'doctype': u'DocPerm',
|
||||
'permlevel': 0,
|
||||
'role': u'HR User',
|
||||
'submit': 1,
|
||||
'write': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'details',
|
||||
'fieldtype': u'Section Break',
|
||||
'label': u'Details',
|
||||
'oldfieldtype': u'Section Break',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'default': u'Draft',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'approval_status',
|
||||
'fieldtype': u'Select',
|
||||
'in_filter': 1,
|
||||
'label': u'Approval Status',
|
||||
'no_copy': 1,
|
||||
'oldfieldname': u'approval_status',
|
||||
'oldfieldtype': u'Select',
|
||||
'options': u'\nDraft\nSubmitted\nApproved \nRejected\nCancelled',
|
||||
'permlevel': 1,
|
||||
'search_index': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'employee',
|
||||
'fieldtype': u'Link',
|
||||
'in_filter': 1,
|
||||
'label': u'From Employee',
|
||||
'oldfieldname': u'employee',
|
||||
'oldfieldtype': u'Link',
|
||||
'options': u'Employee',
|
||||
'permlevel': 0,
|
||||
'reqd': 1,
|
||||
'search_index': 1,
|
||||
'trigger': u'Client'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'employee_name',
|
||||
'fieldtype': u'Data',
|
||||
'in_filter': 1,
|
||||
'label': u'Employee Name',
|
||||
'oldfieldname': u'employee_name',
|
||||
'oldfieldtype': u'Data',
|
||||
'permlevel': 1,
|
||||
'search_index': 0,
|
||||
'width': u'150px'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'fiscal_year',
|
||||
'fieldtype': u'Select',
|
||||
'in_filter': 1,
|
||||
'label': u'Fiscal Year',
|
||||
'oldfieldname': u'fiscal_year',
|
||||
'oldfieldtype': u'Select',
|
||||
'options': u'link:Fiscal Year',
|
||||
'permlevel': 0,
|
||||
'reqd': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'company',
|
||||
'fieldtype': u'Select',
|
||||
'in_filter': 1,
|
||||
'label': u'Company',
|
||||
'oldfieldname': u'company',
|
||||
'oldfieldtype': u'Link',
|
||||
'options': u'link:Company',
|
||||
'permlevel': 0,
|
||||
'reqd': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'column_break0',
|
||||
'fieldtype': u'Column Break',
|
||||
'oldfieldtype': u'Column Break',
|
||||
'permlevel': 0,
|
||||
'width': u'50%'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'posting_date',
|
||||
'fieldtype': u'Date',
|
||||
'in_filter': 1,
|
||||
'label': u'Posting Date',
|
||||
'oldfieldname': u'posting_date',
|
||||
'oldfieldtype': u'Date',
|
||||
'permlevel': 0,
|
||||
'reqd': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'exp_approver',
|
||||
'fieldtype': u'Select',
|
||||
'label': u'Approver',
|
||||
'oldfieldname': u'exp_approver',
|
||||
'oldfieldtype': u'Select',
|
||||
'permlevel': 0,
|
||||
'width': u'160px'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'allow_on_submit': 1,
|
||||
'colour': u'White:FFF',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'remark',
|
||||
'fieldtype': u'Small Text',
|
||||
'label': u'Remark',
|
||||
'no_copy': 1,
|
||||
'oldfieldname': u'remark',
|
||||
'oldfieldtype': u'Small Text',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'amended_from',
|
||||
'fieldtype': u'Data',
|
||||
'label': u'Amended From',
|
||||
'no_copy': 1,
|
||||
'oldfieldname': u'amended_from',
|
||||
'oldfieldtype': u'Data',
|
||||
'permlevel': 1,
|
||||
'print_hide': 1,
|
||||
'report_hide': 1,
|
||||
'width': u'160px'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'amendment_date',
|
||||
'fieldtype': u'Date',
|
||||
'label': u'Amendment Date',
|
||||
'no_copy': 1,
|
||||
'oldfieldname': u'amendment_date',
|
||||
'oldfieldtype': u'Date',
|
||||
'permlevel': 1,
|
||||
'print_hide': 1,
|
||||
'report_hide': 1,
|
||||
'width': u'160px'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'allow_on_submit': 1,
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'approve',
|
||||
'fieldtype': u'Button',
|
||||
'hidden': 1,
|
||||
'label': u'Approve',
|
||||
'oldfieldtype': u'Button',
|
||||
'permlevel': 0,
|
||||
'print_hide': 1,
|
||||
'trigger': u'Client'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'allow_on_submit': 1,
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'reject',
|
||||
'fieldtype': u'Button',
|
||||
'hidden': 1,
|
||||
'label': u'Reject',
|
||||
'oldfieldtype': u'Button',
|
||||
'permlevel': 0,
|
||||
'print_hide': 1,
|
||||
'trigger': u'Client'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'expense_details',
|
||||
'fieldtype': u'Section Break',
|
||||
'label': u'Expense Details',
|
||||
'oldfieldtype': u'Section Break',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'allow_on_submit': 1,
|
||||
'colour': u'White:FFF',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'calculate_total_amount',
|
||||
'fieldtype': u'Button',
|
||||
'label': u'Calculate Total Amount',
|
||||
'oldfieldtype': u'Button',
|
||||
'permlevel': 0,
|
||||
'print_hide': 1,
|
||||
'report_hide': 1,
|
||||
'trigger': u'Client'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'total_claimed_amount',
|
||||
'fieldtype': u'Currency',
|
||||
'in_filter': 0,
|
||||
'label': u'Total Claimed Amount',
|
||||
'no_copy': 1,
|
||||
'oldfieldname': u'total_claimed_amount',
|
||||
'oldfieldtype': u'Currency',
|
||||
'permlevel': 1,
|
||||
'reqd': 0,
|
||||
'width': u'160px'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'total_sanctioned_amount',
|
||||
'fieldtype': u'Currency',
|
||||
'in_filter': 0,
|
||||
'label': u'Total Sanctioned Amount',
|
||||
'no_copy': 1,
|
||||
'oldfieldname': u'total_sanctioned_amount',
|
||||
'oldfieldtype': u'Currency',
|
||||
'permlevel': 1,
|
||||
'width': u'160px'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'allow_on_submit': 1,
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'update_voucher',
|
||||
'fieldtype': u'Button',
|
||||
'hidden': 1,
|
||||
'label': u'Update Voucher',
|
||||
'oldfieldtype': u'Button',
|
||||
'permlevel': 0,
|
||||
'print_hide': 1,
|
||||
'trigger': u'Client'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'allow_on_submit': 1,
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'expense_voucher_details',
|
||||
'fieldtype': u'Table',
|
||||
'label': u'Expense Claim Details',
|
||||
'oldfieldname': u'expense_voucher_details',
|
||||
'oldfieldtype': u'Table',
|
||||
'options': u'Expense Claim Detail',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'email_id',
|
||||
'fieldtype': u'Data',
|
||||
'hidden': 1,
|
||||
'label': u'Employees Email Id',
|
||||
'oldfieldname': u'email_id',
|
||||
'oldfieldtype': u'Data',
|
||||
'permlevel': 0,
|
||||
'print_hide': 1
|
||||
}
|
||||
{
|
||||
"owner": "harshada@webnotestech.com",
|
||||
"docstatus": 0,
|
||||
"creation": "2012-12-05 14:11:53",
|
||||
"modified_by": "Administrator",
|
||||
"modified": "2012-12-05 14:22:27"
|
||||
},
|
||||
{
|
||||
"is_submittable": 1,
|
||||
"autoname": "EXP.######",
|
||||
"name": "__common__",
|
||||
"default_print_format": "Standard",
|
||||
"search_fields": "approval_status,employee,employee_name",
|
||||
"module": "HR",
|
||||
"doctype": "DocType"
|
||||
},
|
||||
{
|
||||
"name": "__common__",
|
||||
"parent": "Expense Claim",
|
||||
"doctype": "DocField",
|
||||
"parenttype": "DocType",
|
||||
"parentfield": "fields"
|
||||
},
|
||||
{
|
||||
"name": "__common__",
|
||||
"parent": "Expense Claim",
|
||||
"read": 1,
|
||||
"doctype": "DocPerm",
|
||||
"parenttype": "DocType",
|
||||
"parentfield": "permissions"
|
||||
},
|
||||
{
|
||||
"name": "Expense Claim",
|
||||
"doctype": "DocType"
|
||||
},
|
||||
{
|
||||
"oldfieldtype": "Section Break",
|
||||
"doctype": "DocField",
|
||||
"label": "Details",
|
||||
"fieldname": "details",
|
||||
"fieldtype": "Section Break",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"permlevel": 1,
|
||||
"no_copy": 1,
|
||||
"oldfieldtype": "Select",
|
||||
"colour": "White:FFF",
|
||||
"doctype": "DocField",
|
||||
"label": "Approval Status",
|
||||
"oldfieldname": "approval_status",
|
||||
"default": "Draft",
|
||||
"fieldname": "approval_status",
|
||||
"fieldtype": "Select",
|
||||
"search_index": 1,
|
||||
"options": "\nDraft\nApproved\nRejected",
|
||||
"in_filter": 1
|
||||
},
|
||||
{
|
||||
"oldfieldtype": "Select",
|
||||
"doctype": "DocField",
|
||||
"label": "Approver",
|
||||
"oldfieldname": "exp_approver",
|
||||
"width": "160px",
|
||||
"fieldname": "exp_approver",
|
||||
"fieldtype": "Select",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"oldfieldtype": "Date",
|
||||
"doctype": "DocField",
|
||||
"label": "Posting Date",
|
||||
"oldfieldname": "posting_date",
|
||||
"fieldname": "posting_date",
|
||||
"fieldtype": "Date",
|
||||
"reqd": 1,
|
||||
"permlevel": 0,
|
||||
"in_filter": 1
|
||||
},
|
||||
{
|
||||
"oldfieldtype": "Column Break",
|
||||
"doctype": "DocField",
|
||||
"width": "50%",
|
||||
"fieldname": "column_break0",
|
||||
"fieldtype": "Column Break",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"oldfieldtype": "Link",
|
||||
"colour": "White:FFF",
|
||||
"doctype": "DocField",
|
||||
"label": "From Employee",
|
||||
"oldfieldname": "employee",
|
||||
"permlevel": 0,
|
||||
"trigger": "Client",
|
||||
"fieldname": "employee",
|
||||
"fieldtype": "Link",
|
||||
"search_index": 1,
|
||||
"reqd": 1,
|
||||
"options": "Employee",
|
||||
"in_filter": 1
|
||||
},
|
||||
{
|
||||
"oldfieldtype": "Data",
|
||||
"doctype": "DocField",
|
||||
"label": "Employee Name",
|
||||
"oldfieldname": "employee_name",
|
||||
"width": "150px",
|
||||
"fieldname": "employee_name",
|
||||
"fieldtype": "Data",
|
||||
"search_index": 0,
|
||||
"permlevel": 1,
|
||||
"in_filter": 1
|
||||
},
|
||||
{
|
||||
"no_copy": 1,
|
||||
"oldfieldtype": "Small Text",
|
||||
"colour": "White:FFF",
|
||||
"allow_on_submit": 0,
|
||||
"doctype": "DocField",
|
||||
"label": "Remark",
|
||||
"oldfieldname": "remark",
|
||||
"fieldname": "remark",
|
||||
"fieldtype": "Small Text",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"print_hide": 1,
|
||||
"no_copy": 1,
|
||||
"oldfieldtype": "Data",
|
||||
"colour": "White:FFF",
|
||||
"doctype": "DocField",
|
||||
"label": "Amended From",
|
||||
"oldfieldname": "amended_from",
|
||||
"width": "160px",
|
||||
"fieldname": "amended_from",
|
||||
"fieldtype": "Data",
|
||||
"permlevel": 1,
|
||||
"report_hide": 1
|
||||
},
|
||||
{
|
||||
"print_hide": 1,
|
||||
"no_copy": 1,
|
||||
"oldfieldtype": "Date",
|
||||
"colour": "White:FFF",
|
||||
"doctype": "DocField",
|
||||
"label": "Amendment Date",
|
||||
"oldfieldname": "amendment_date",
|
||||
"width": "160px",
|
||||
"fieldname": "amendment_date",
|
||||
"fieldtype": "Date",
|
||||
"permlevel": 1,
|
||||
"report_hide": 1
|
||||
},
|
||||
{
|
||||
"oldfieldtype": "Section Break",
|
||||
"doctype": "DocField",
|
||||
"label": "Expense Details",
|
||||
"fieldname": "expense_details",
|
||||
"fieldtype": "Section Break",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"oldfieldtype": "Table",
|
||||
"allow_on_submit": 0,
|
||||
"doctype": "DocField",
|
||||
"label": "Expense Claim Details",
|
||||
"oldfieldname": "expense_voucher_details",
|
||||
"options": "Expense Claim Detail",
|
||||
"fieldname": "expense_voucher_details",
|
||||
"fieldtype": "Table",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"no_copy": 1,
|
||||
"oldfieldtype": "Currency",
|
||||
"colour": "White:FFF",
|
||||
"doctype": "DocField",
|
||||
"label": "Total Claimed Amount",
|
||||
"oldfieldname": "total_claimed_amount",
|
||||
"width": "160px",
|
||||
"fieldname": "total_claimed_amount",
|
||||
"fieldtype": "Currency",
|
||||
"reqd": 0,
|
||||
"permlevel": 1,
|
||||
"in_filter": 0
|
||||
},
|
||||
{
|
||||
"no_copy": 1,
|
||||
"oldfieldtype": "Currency",
|
||||
"colour": "White:FFF",
|
||||
"doctype": "DocField",
|
||||
"label": "Total Sanctioned Amount",
|
||||
"oldfieldname": "total_sanctioned_amount",
|
||||
"width": "160px",
|
||||
"fieldname": "total_sanctioned_amount",
|
||||
"fieldtype": "Currency",
|
||||
"permlevel": 1,
|
||||
"in_filter": 0
|
||||
},
|
||||
{
|
||||
"print_hide": 1,
|
||||
"oldfieldtype": "Data",
|
||||
"doctype": "DocField",
|
||||
"label": "Employees Email Id",
|
||||
"oldfieldname": "email_id",
|
||||
"fieldname": "email_id",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 1,
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"oldfieldtype": "Select",
|
||||
"doctype": "DocField",
|
||||
"label": "Fiscal Year",
|
||||
"oldfieldname": "fiscal_year",
|
||||
"options": "link:Fiscal Year",
|
||||
"fieldname": "fiscal_year",
|
||||
"fieldtype": "Select",
|
||||
"reqd": 1,
|
||||
"permlevel": 0,
|
||||
"in_filter": 1
|
||||
},
|
||||
{
|
||||
"oldfieldtype": "Link",
|
||||
"doctype": "DocField",
|
||||
"label": "Company",
|
||||
"oldfieldname": "company",
|
||||
"options": "link:Company",
|
||||
"fieldname": "company",
|
||||
"fieldtype": "Select",
|
||||
"reqd": 1,
|
||||
"permlevel": 0,
|
||||
"in_filter": 1
|
||||
},
|
||||
{
|
||||
"create": 1,
|
||||
"doctype": "DocPerm",
|
||||
"write": 1,
|
||||
"role": "Employee",
|
||||
"permlevel": 0,
|
||||
"match": "owner"
|
||||
},
|
||||
{
|
||||
"amend": 1,
|
||||
"create": 1,
|
||||
"doctype": "DocPerm",
|
||||
"submit": 1,
|
||||
"write": 1,
|
||||
"cancel": 1,
|
||||
"role": "Expense Approver",
|
||||
"permlevel": 0,
|
||||
"match": "exp_approver:user"
|
||||
},
|
||||
{
|
||||
"amend": 1,
|
||||
"create": 1,
|
||||
"doctype": "DocPerm",
|
||||
"submit": 1,
|
||||
"write": 1,
|
||||
"cancel": 1,
|
||||
"role": "HR User",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"doctype": "DocPerm",
|
||||
"role": "All",
|
||||
"permlevel": 1
|
||||
}
|
||||
]
|
@ -1,103 +1,80 @@
|
||||
# DocType, Expense Claim Detail
|
||||
[
|
||||
|
||||
# These values are common in all dictionaries
|
||||
{
|
||||
'creation': '2012-03-27 14:35:56',
|
||||
'docstatus': 0,
|
||||
'modified': '2012-03-27 14:35:56',
|
||||
'modified_by': u'Administrator',
|
||||
'owner': u'harshada@webnotestech.com'
|
||||
},
|
||||
|
||||
# These values are common for all DocType
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'doctype': 'DocType',
|
||||
'istable': 1,
|
||||
'module': u'HR',
|
||||
'name': '__common__',
|
||||
'section_style': u'Simple',
|
||||
'server_code_error': u' ',
|
||||
'version': 5
|
||||
},
|
||||
|
||||
# These values are common for all DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'name': '__common__',
|
||||
'parent': u'Expense Claim Detail',
|
||||
'parentfield': u'fields',
|
||||
'parenttype': u'DocType',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# DocType, Expense Claim Detail
|
||||
{
|
||||
'doctype': 'DocType',
|
||||
'name': u'Expense Claim Detail'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'expense_date',
|
||||
'fieldtype': u'Date',
|
||||
'label': u'Expense Date',
|
||||
'oldfieldname': u'expense_date',
|
||||
'oldfieldtype': u'Date',
|
||||
'reqd': 0,
|
||||
'width': u'150px'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'expense_type',
|
||||
'fieldtype': u'Link',
|
||||
'label': u'Expense Claim Type',
|
||||
'oldfieldname': u'expense_type',
|
||||
'oldfieldtype': u'Link',
|
||||
'options': u'Expense Claim Type',
|
||||
'reqd': 1,
|
||||
'width': u'150px'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'description',
|
||||
'fieldtype': u'Small Text',
|
||||
'label': u'Description',
|
||||
'oldfieldname': u'description',
|
||||
'oldfieldtype': u'Small Text',
|
||||
'width': u'300px'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'claim_amount',
|
||||
'fieldtype': u'Currency',
|
||||
'label': u'Claim Amount',
|
||||
'oldfieldname': u'claim_amount',
|
||||
'oldfieldtype': u'Currency',
|
||||
'reqd': 1,
|
||||
'trigger': u'Client',
|
||||
'width': u'150px'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'allow_on_submit': 1,
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'sanctioned_amount',
|
||||
'fieldtype': u'Currency',
|
||||
'label': u'Sanctioned Amount',
|
||||
'no_copy': 1,
|
||||
'oldfieldname': u'sanctioned_amount',
|
||||
'oldfieldtype': u'Currency',
|
||||
'trigger': u'Client',
|
||||
'width': u'150px'
|
||||
}
|
||||
{
|
||||
"owner": "harshada@webnotestech.com",
|
||||
"docstatus": 0,
|
||||
"creation": "2012-07-03 13:30:39",
|
||||
"modified_by": "Administrator",
|
||||
"modified": "2012-12-05 14:22:03"
|
||||
},
|
||||
{
|
||||
"istable": 1,
|
||||
"name": "__common__",
|
||||
"doctype": "DocType",
|
||||
"module": "HR"
|
||||
},
|
||||
{
|
||||
"name": "__common__",
|
||||
"parent": "Expense Claim Detail",
|
||||
"doctype": "DocField",
|
||||
"parenttype": "DocType",
|
||||
"permlevel": 0,
|
||||
"parentfield": "fields"
|
||||
},
|
||||
{
|
||||
"name": "Expense Claim Detail",
|
||||
"doctype": "DocType"
|
||||
},
|
||||
{
|
||||
"oldfieldtype": "Date",
|
||||
"doctype": "DocField",
|
||||
"label": "Expense Date",
|
||||
"oldfieldname": "expense_date",
|
||||
"width": "150px",
|
||||
"fieldname": "expense_date",
|
||||
"fieldtype": "Date",
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"oldfieldtype": "Link",
|
||||
"doctype": "DocField",
|
||||
"label": "Expense Claim Type",
|
||||
"oldfieldname": "expense_type",
|
||||
"width": "150px",
|
||||
"fieldname": "expense_type",
|
||||
"fieldtype": "Select",
|
||||
"reqd": 1,
|
||||
"options": "link:Expense Claim Type"
|
||||
},
|
||||
{
|
||||
"oldfieldtype": "Small Text",
|
||||
"doctype": "DocField",
|
||||
"label": "Description",
|
||||
"oldfieldname": "description",
|
||||
"width": "300px",
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Small Text"
|
||||
},
|
||||
{
|
||||
"oldfieldtype": "Currency",
|
||||
"doctype": "DocField",
|
||||
"label": "Claim Amount",
|
||||
"oldfieldname": "claim_amount",
|
||||
"width": "150px",
|
||||
"trigger": "Client",
|
||||
"fieldname": "claim_amount",
|
||||
"fieldtype": "Currency",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"no_copy": 1,
|
||||
"oldfieldtype": "Currency",
|
||||
"allow_on_submit": 0,
|
||||
"doctype": "DocField",
|
||||
"label": "Sanctioned Amount",
|
||||
"oldfieldname": "sanctioned_amount",
|
||||
"width": "150px",
|
||||
"trigger": "Client",
|
||||
"fieldname": "sanctioned_amount",
|
||||
"fieldtype": "Currency"
|
||||
}
|
||||
]
|
@ -8,14 +8,23 @@
|
||||
//
|
||||
// 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
|
||||
// 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/>.
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
cur_frm.add_fetch('employee','employee_name','employee_name');
|
||||
|
||||
cur_frm.cscript.onload = function(doc, dt, dn) {
|
||||
if(!doc.posting_date) set_multiple(dt,dn,{posting_date:get_today()});
|
||||
if(!doc.posting_date)
|
||||
set_multiple(dt,dn,{posting_date:get_today()});
|
||||
cur_frm.call({
|
||||
method:"get_approver_list",
|
||||
callback: function(r) {
|
||||
cur_frm.set_df_property("leave_approver", "options", r.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
cur_frm.cscript.refresh = function(doc, dt, dn) {
|
||||
@ -23,14 +32,16 @@ cur_frm.cscript.refresh = function(doc, dt, dn) {
|
||||
if(doc.__islocal && !in_list(user_roles, "HR User")) {
|
||||
cur_frm.set_intro("Fill the form and save it")
|
||||
} else {
|
||||
if(in_list(user_roles, "HR User")) {
|
||||
if(doc.status=="Open") {
|
||||
cur_frm.set_intro("Please Approve (and Submit) or Reject, or re-assign to applicant for further review.");
|
||||
if(doc.status=="Open") {
|
||||
if(user==doc.leave_approver) {
|
||||
cur_frm.set_intro("You are the Leave Approver for this record. Please Update the 'Status' and Save");
|
||||
cur_frm.toggle_enable("status", true);
|
||||
} else {
|
||||
cur_frm.set_intro("This Leave Application is pending approval. Only the Leave Apporver can update status.")
|
||||
cur_frm.toggle_enable("status", false);
|
||||
}
|
||||
} else {
|
||||
if(doc.status=="Open") {
|
||||
cur_frm.set_intro("Leave application is pending approval.");
|
||||
} else if(doc.status=="Approved") {
|
||||
if(doc.status=="Approved") {
|
||||
cur_frm.set_intro("Leave application has been approved.");
|
||||
} else if(doc.status=="Rejected") {
|
||||
cur_frm.set_intro("Leave application has been rejected.");
|
||||
@ -38,61 +49,67 @@ cur_frm.cscript.refresh = function(doc, dt, dn) {
|
||||
}
|
||||
}
|
||||
|
||||
if(doc.status=="Approved" && doc.docstatus!=1) {
|
||||
if(doc.status=="Approved" && doc.docstatus==0) {
|
||||
cur_frm.savesubmit()
|
||||
}
|
||||
}
|
||||
|
||||
cur_frm.add_fetch('employee','employee_name','employee_name');
|
||||
|
||||
cur_frm.cscript.employee = function (doc, dt, dn){
|
||||
get_leave_balance(doc, dt, dn);
|
||||
get_leave_balance(doc, dt, dn);
|
||||
}
|
||||
|
||||
cur_frm.cscript.fiscal_year = function (doc, dt, dn){
|
||||
get_leave_balance(doc, dt, dn);
|
||||
get_leave_balance(doc, dt, dn);
|
||||
}
|
||||
|
||||
cur_frm.cscript.leave_type = function (doc, dt, dn){
|
||||
get_leave_balance(doc, dt, dn);
|
||||
get_leave_balance(doc, dt, dn);
|
||||
}
|
||||
|
||||
cur_frm.cscript.half_day = function(doc, dt, dn) {
|
||||
if(doc.from_date) {
|
||||
set_multiple(dt,dn,{to_date:doc.from_date});
|
||||
calculate_total_days(doc, dt, dn);
|
||||
}
|
||||
if(doc.from_date) {
|
||||
set_multiple(dt,dn,{to_date:doc.from_date});
|
||||
calculate_total_days(doc, dt, dn);
|
||||
}
|
||||
}
|
||||
|
||||
cur_frm.cscript.from_date = function(doc, dt, dn) {
|
||||
if(cint(doc.half_day) == 1){
|
||||
set_multiple(dt,dn,{to_date:doc.from_date});
|
||||
}
|
||||
calculate_total_days(doc, dt, dn);
|
||||
if(cint(doc.half_day) == 1){
|
||||
set_multiple(dt,dn,{to_date:doc.from_date});
|
||||
}
|
||||
calculate_total_days(doc, dt, dn);
|
||||
}
|
||||
|
||||
cur_frm.cscript.to_date = function(doc, dt, dn) {
|
||||
if(cint(doc.half_day) == 1 && cstr(doc.from_date) && doc.from_date != doc.to_date){
|
||||
msgprint("To Date should be same as From Date for Half Day leave");
|
||||
set_multiple(dt,dn,{to_date:doc.from_date});
|
||||
}
|
||||
calculate_total_days(doc, dt, dn);
|
||||
if(cint(doc.half_day) == 1 && cstr(doc.from_date) && doc.from_date != doc.to_date){
|
||||
msgprint("To Date should be same as From Date for Half Day leave");
|
||||
set_multiple(dt,dn,{to_date:doc.from_date});
|
||||
}
|
||||
calculate_total_days(doc, dt, dn);
|
||||
}
|
||||
|
||||
|
||||
get_leave_balance = function(doc, dt, dn) {
|
||||
if(doc.employee && doc.leave_type && doc.fiscal_year)
|
||||
get_server_fields('get_leave_balance', '','', doc, dt, dn, 1);
|
||||
if(doc.employee && doc.leave_type && doc.fiscal_year) {
|
||||
cur_frm.call({
|
||||
method: "get_leave_balance",
|
||||
args: {
|
||||
employee: doc.employee,
|
||||
fiscal_year: doc.fiscal_year,
|
||||
leave_type: doc.leave_type
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
calculate_total_days = function(doc, dt, dn) {
|
||||
if(doc.from_date && doc.to_date){
|
||||
if(cint(doc.half_day) == 1) set_multiple(dt,dn,{total_leave_days:0.5});
|
||||
else{
|
||||
//d = new DateFn();
|
||||
//set_multiple(dt,dn,{total_leave_days:d.get_diff(d.str_to_obj(doc.to_date),d.str_to_obj(doc.from_date))+1});
|
||||
get_server_fields('get_total_leave_days', '', '', doc, dt, dn, 1);
|
||||
}
|
||||
}
|
||||
if(doc.from_date && doc.to_date){
|
||||
if(cint(doc.half_day) == 1) set_multiple(dt,dn,{total_leave_days:0.5});
|
||||
else{
|
||||
//d = new DateFn();
|
||||
//set_multiple(dt,dn,{total_leave_days:d.get_diff(d.str_to_obj(doc.to_date),d.str_to_obj(doc.from_date))+1});
|
||||
get_server_fields('get_total_leave_days', '', '', doc, dt, dn, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cur_frm.fields_dict.employee.get_query = erpnext.utils.employee_query;
|
@ -30,14 +30,6 @@ class DocType:
|
||||
self.doc = doc
|
||||
self.doclist = doclist
|
||||
|
||||
def get_leave_balance(self):
|
||||
leave_all = sql("select total_leaves_allocated from `tabLeave Allocation` where employee = '%s' and leave_type = '%s' and fiscal_year = '%s' and docstatus = 1" % (self.doc.employee, self.doc.leave_type, self.doc.fiscal_year))
|
||||
leave_all = leave_all and flt(leave_all[0][0]) or 0
|
||||
leave_app = sql("select SUM(total_leave_days) from `tabLeave Application` where employee = '%s' and leave_type = '%s' and fiscal_year = '%s' and docstatus = 1" % (self.doc.employee, self.doc.leave_type, self.doc.fiscal_year))
|
||||
leave_app = leave_app and flt(leave_app[0][0]) or 0
|
||||
ret = {'leave_balance':leave_all - leave_app}
|
||||
return ret
|
||||
|
||||
def get_holidays(self):
|
||||
"""
|
||||
get total holidays
|
||||
@ -71,7 +63,8 @@ class DocType:
|
||||
|
||||
def validate_balance_leaves(self):
|
||||
if self.doc.from_date and self.doc.to_date and not self.is_lwp():
|
||||
bal = self.get_leave_balance()
|
||||
bal = get_leave_balance(self.doc.leave_type, self.doc.employee,
|
||||
self.doc.fiscal_year)["leave_balance"]
|
||||
tot_leaves = self.get_total_leave_days()
|
||||
bal, tot_leaves = bal, tot_leaves
|
||||
webnotes.conn.set(self.doc,'leave_balance',flt(bal['leave_balance']))
|
||||
@ -98,6 +91,9 @@ class DocType:
|
||||
raise Exception
|
||||
|
||||
def validate(self):
|
||||
if self.doc.leave_approver == self.doc.owner:
|
||||
webnotes.msgprint("""Self Approval is not allowed.""", raise_exception=1)
|
||||
|
||||
self.validate_to_date()
|
||||
self.validate_balance_leaves()
|
||||
self.validate_leave_overlap()
|
||||
@ -107,3 +103,30 @@ class DocType:
|
||||
if self.doc.status != "Approved":
|
||||
webnotes.msgprint("""Only Approved Leave Applications can be Submitted.""",
|
||||
raise_exception=True)
|
||||
|
||||
@webnotes.whitelist()
|
||||
def get_leave_balance(employee, leave_type, fiscal_year):
|
||||
leave_all = webnotes.conn.sql("""select total_leaves_allocated
|
||||
from `tabLeave Allocation` where employee = %s and leave_type = %s
|
||||
and fiscal_year = %s and docstatus = 1""", (employee,
|
||||
leave_type, fiscal_year))
|
||||
|
||||
leave_all = leave_all and flt(leave_all[0][0]) or 0
|
||||
|
||||
leave_app = webnotes.conn.sql("""select SUM(total_leave_days)
|
||||
from `tabLeave Application`
|
||||
where employee = %s and leave_type = %s and fiscal_year = %s
|
||||
and docstatus = 1""", (employee, leave_type, fiscal_year))
|
||||
leave_app = leave_app and flt(leave_app[0][0]) or 0
|
||||
|
||||
ret = {'leave_balance':leave_all - leave_app}
|
||||
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
|
||||
|
@ -2,9 +2,9 @@
|
||||
{
|
||||
"owner": "Administrator",
|
||||
"docstatus": 0,
|
||||
"creation": "2012-11-02 17:16:54",
|
||||
"creation": "2012-12-05 14:11:53",
|
||||
"modified_by": "Administrator",
|
||||
"modified": "2012-11-30 12:17:27"
|
||||
"modified": "2012-12-05 17:38:26"
|
||||
},
|
||||
{
|
||||
"is_submittable": 1,
|
||||
@ -44,6 +44,15 @@
|
||||
"fieldtype": "Select",
|
||||
"permlevel": 3
|
||||
},
|
||||
{
|
||||
"description": "Leave can be approved by users with Role, \"Leave Approver\"",
|
||||
"colour": "White:FFF",
|
||||
"doctype": "DocField",
|
||||
"label": "Leave Approver",
|
||||
"fieldname": "leave_approver",
|
||||
"fieldtype": "Select",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"search_index": 1,
|
||||
"doctype": "DocField",
|
||||
@ -215,13 +224,30 @@
|
||||
"cancel": 1,
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"amend": 1,
|
||||
"create": 1,
|
||||
"doctype": "DocPerm",
|
||||
"submit": 1,
|
||||
"write": 1,
|
||||
"role": "Leave Approver",
|
||||
"cancel": 1,
|
||||
"permlevel": 0,
|
||||
"match": "leave_approver:user"
|
||||
},
|
||||
{
|
||||
"doctype": "DocPerm",
|
||||
"write": 1,
|
||||
"role": "HR User",
|
||||
"permlevel": 2
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"create": 0,
|
||||
"doctype": "DocPerm",
|
||||
"submit": 0,
|
||||
"write": 1,
|
||||
"role": "HR User",
|
||||
"role": "Leave Approver",
|
||||
"cancel": 0,
|
||||
"permlevel": 2
|
||||
},
|
||||
@ -229,11 +255,5 @@
|
||||
"doctype": "DocPerm",
|
||||
"role": "All",
|
||||
"permlevel": 3
|
||||
},
|
||||
{
|
||||
"doctype": "DocPerm",
|
||||
"write": 1,
|
||||
"role": "HR User",
|
||||
"permlevel": 3
|
||||
}
|
||||
]
|
26
patches/december_2012/expense_leave_reload.py
Normal file
26
patches/december_2012/expense_leave_reload.py
Normal file
@ -0,0 +1,26 @@
|
||||
import webnotes
|
||||
|
||||
def execute():
|
||||
# new roles
|
||||
roles = [r[0] for r in webnotes.conn.sql("""select name from tabRole""")]
|
||||
if not "Leave Approver" in roles:
|
||||
webnotes.model_wrapper([{"doctype":"Role", "role_name":"Leave Approver",
|
||||
"__islocal":1, "module":"HR"}]).save()
|
||||
if not "Expense Approver" in roles:
|
||||
webnotes.model_wrapper([{"doctype":"Role", "role_name":"Expense Approver",
|
||||
"__islocal":1, "module":"HR"}]).save()
|
||||
|
||||
# reload
|
||||
webnotes.clear_perms("Leave Application")
|
||||
webnotes.reload_doc("hr", "doctype", "leave_application")
|
||||
|
||||
webnotes.clear_perms("Expense Claim")
|
||||
webnotes.reload_doc("hr", "doctype", "expense_claim")
|
||||
|
||||
# remove extra space in Approved Expense Vouchers
|
||||
webnotes.conn.sql("""update `tabExpense Claim` set approval_status='Approved'
|
||||
where approval_status='Approved '""")
|
||||
|
||||
webnotes.conn.commit()
|
||||
for t in ['__CacheItem', '__SessionCache', 'tabSupport Ticket Response']:
|
||||
webnotes.conn.sql("drop table if exists `%s`" % t)
|
5
patches/december_2012/reload_debtors_creditors_ledger.py
Normal file
5
patches/december_2012/reload_debtors_creditors_ledger.py
Normal file
@ -0,0 +1,5 @@
|
||||
def execute():
|
||||
import webnotes
|
||||
from webnotes.modules import reload_doc
|
||||
reload_doc("accounts", "search_criteria", "debtors_ledger")
|
||||
reload_doc("accounts", "search_criteria", "creditors_ledger")
|
@ -709,6 +709,10 @@ patch_list = [
|
||||
'patch_module': 'patches.december_2012',
|
||||
'patch_file': 'deprecate_tds',
|
||||
},
|
||||
{
|
||||
'patch_module': 'patches.december_2012',
|
||||
'patch_file': 'expense_leave_reload',
|
||||
},
|
||||
{
|
||||
'patch_module': 'patches.december_2012',
|
||||
'patch_file': 'repost_ordered_qty',
|
||||
@ -717,4 +721,8 @@ patch_list = [
|
||||
'patch_module': 'patches.december_2012',
|
||||
'patch_file': 'repost_projected_qty',
|
||||
},
|
||||
{
|
||||
'patch_module': 'patches.december_2012',
|
||||
'patch_file': 'reload_debtors_creditors_ledger',
|
||||
},
|
||||
]
|
@ -43,8 +43,8 @@ cur_frm.cscript.item_code = function(doc, cdt, cdn) {
|
||||
}
|
||||
|
||||
|
||||
cur_frm.cscript.onload = function(doc, cdt, cdn) {
|
||||
if(doc.delivery_note) {
|
||||
cur_frm.cscript.onload_post_render = function(doc, cdt, cdn) {
|
||||
if(doc.delivery_note && doc.__islocal) {
|
||||
var ps_detail = getchildren('Packing Slip Item', doc.name, 'item_details');
|
||||
if(!(flt(ps_detail[0].net_weight) && cstr(ps_detail[0].weight_uom))) {
|
||||
cur_frm.cscript.update_item_details(doc);
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
from webnotes.utils import flt, cint
|
||||
from webnotes.utils import flt, cint, now
|
||||
|
||||
class DocType:
|
||||
def __init__(self, d, dl):
|
||||
@ -56,6 +56,15 @@ class DocType:
|
||||
Validate if case nos overlap
|
||||
If they do, recommend next case no.
|
||||
"""
|
||||
if not cint(self.doc.from_case_no):
|
||||
webnotes.msgprint("Please specify a valid 'From Case No.'", raise_exception=1)
|
||||
elif not self.doc.to_case_no:
|
||||
self.doc.to_case_no = self.doc.from_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.'",
|
||||
raise_exception=1)
|
||||
|
||||
|
||||
res = webnotes.conn.sql("""\
|
||||
SELECT name FROM `tabPacking Slip`
|
||||
WHERE delivery_note = %(delivery_note)s AND docstatus = 1 AND
|
||||
@ -92,16 +101,24 @@ class DocType:
|
||||
item_codes = ", ".join([('"' + d.item_code + '"') for d in
|
||||
self.doclist])
|
||||
|
||||
items = [d.item_code for d in self.doclist.get({"parentfield": "item_details"})]
|
||||
|
||||
if not item_codes: webnotes.msgprint("No Items to Pack",
|
||||
raise_exception=1)
|
||||
|
||||
res = webnotes.conn.sql("""\
|
||||
SELECT item_code, IFNULL(SUM(qty), 0) as qty, IFNULL(packed_qty, 0) as packed_qty, stock_uom
|
||||
FROM `tabDelivery Note Item`
|
||||
WHERE parent = "%s" AND item_code IN (%s)
|
||||
GROUP BY item_code""" % (self.doc.delivery_note, item_codes),
|
||||
as_dict=1)
|
||||
|
||||
|
||||
# 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,
|
||||
(select sum(ifnull(psi.qty, 0) * (abs(ps.to_case_no - ps.from_case_no) + 1))
|
||||
from `tabPacking Slip` ps, `tabPacking Slip Item` psi
|
||||
where ps.name = psi.parent and ps.docstatus = 1
|
||||
and ps.delivery_note = dni.parent and psi.item_code=dni.item_code)
|
||||
as packed_qty,
|
||||
stock_uom
|
||||
from `tabDelivery Note Item` dni
|
||||
where parent=%s and item_code in (%s)
|
||||
group by item_code""" % ("%s", ", ".join(["%s"]*len(items))),
|
||||
tuple([self.doc.delivery_note] + items), as_dict=1, debug=1)
|
||||
|
||||
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
|
||||
@ -148,28 +165,29 @@ class DocType:
|
||||
dn_details, ps_item_qty, no_of_cases = self.get_details_for_packing()
|
||||
|
||||
for item in dn_details:
|
||||
if event=='submit':
|
||||
new_packed_qty = flt(item['packed_qty']) + (flt(ps_item_qty[item['item_code']]) * no_of_cases)
|
||||
|
||||
elif event=='cancel':
|
||||
new_packed_qty = flt(item['packed_qty']) - (flt(ps_item_qty[item['item_code']]) * no_of_cases)
|
||||
|
||||
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)
|
||||
|
||||
|
||||
delivery_note_item = webnotes.conn.get_value("Delivery Note Item", {
|
||||
"parent": self.doc.delivery_note, "item_code": item["item_code"]})
|
||||
|
||||
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']))
|
||||
(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):
|
||||
"""
|
||||
Fill empty columns in Packing Slip Item
|
||||
"""
|
||||
self.doc.from_case_no = self.get_recommended_case_no()
|
||||
if not self.doc.from_case_no:
|
||||
self.doc.from_case_no = self.get_recommended_case_no()
|
||||
|
||||
from webnotes.model.code import get_obj
|
||||
for d in self.doclist:
|
||||
|
@ -64,10 +64,6 @@ class DocType(TransactionBase):
|
||||
doc.fields[r] = ret[r]
|
||||
|
||||
|
||||
# Get UOM Details
|
||||
def get_uom_details(self, arg = ''):
|
||||
return get_obj(dt='Purchase Common').get_uom_details(arg)
|
||||
|
||||
# GET TERMS & CONDITIONS
|
||||
# =====================================================================================
|
||||
def get_tc_details(self):
|
||||
|
@ -19,8 +19,8 @@ import webnotes
|
||||
from webnotes.utils import load_json, cstr, now
|
||||
|
||||
@webnotes.whitelist()
|
||||
def update_item(args):
|
||||
args = load_json(args)
|
||||
def update_item(arg):
|
||||
args = load_json(arg)
|
||||
|
||||
webnotes.conn.sql("update `tab%s` set `%s`=%s, modified=%s where name=%s" \
|
||||
% (args['dt'], args['fn'], '%s', '%s', '%s'), (args['text'], now(), args['dn']))
|
||||
|
@ -1 +0,0 @@
|
||||
from __future__ import unicode_literals
|
@ -1,46 +0,0 @@
|
||||
.user-card {
|
||||
border-radius: 5px;
|
||||
width: 200px;
|
||||
margin: 11px;
|
||||
padding: 11px;
|
||||
background-color: #FFEDBD;
|
||||
box-shadow: 3px 3px 5px #888;
|
||||
float: left;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.user-card.disabled {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
.user-card img {
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
.user-role {
|
||||
padding: 5px;
|
||||
width: 45%;
|
||||
float: left;
|
||||
}
|
||||
|
||||
table.user-perm {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
table.user-perm td, table.user-perm th {
|
||||
padding: 5px;
|
||||
text-align: center;
|
||||
border-bottom: 1px solid #aaa;
|
||||
min-width: 30px;
|
||||
}
|
||||
|
||||
.subscription-info-box {
|
||||
margin: 0px 11px;
|
||||
background-color: #EEEEEE;
|
||||
border: 1px solid #DDDBDB;
|
||||
padding: 5px 3px;
|
||||
}
|
||||
|
||||
.subscription-info {
|
||||
padding: 0px 10px;
|
||||
}
|
@ -1,415 +0,0 @@
|
||||
// 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/>.
|
||||
|
||||
$.extend(wn.pages.users, {
|
||||
onload: function(wrapper) {
|
||||
var w = wn.pages.users;
|
||||
wn.ui.make_app_page({
|
||||
parent: w,
|
||||
title: "Users",
|
||||
single_column: true
|
||||
});
|
||||
w.profiles = {};
|
||||
w.refresh();
|
||||
w.setup();
|
||||
w.role_editor = new erpnext.RoleEditor();
|
||||
},
|
||||
setup: function() {
|
||||
wn.pages.users.appframe.add_button('+ Add User', function() {
|
||||
wn.pages.users.add_user();
|
||||
});
|
||||
|
||||
// set roles
|
||||
var w = wn.pages.users;
|
||||
$(w).on('click', '.btn.user-roles', function() {
|
||||
var uid = $(this).parent().parent().attr('data-name');
|
||||
wn.pages.users.role_editor.show(uid);
|
||||
});
|
||||
|
||||
// settings
|
||||
$(w).on('click', '.btn.user-settings', function() {
|
||||
var uid = $(this).parent().parent().attr('data-name');
|
||||
wn.pages.users.show_settings(uid);
|
||||
});
|
||||
|
||||
// delete
|
||||
$(w).on('click', 'a.close', function() {
|
||||
$card = $(this).parent();
|
||||
var uid = $card.attr('data-name');
|
||||
$card.css('opacity', 0.6);
|
||||
wn.call({
|
||||
method: 'utilities.page.users.users.delete',
|
||||
args: {'uid': uid},
|
||||
callback: function(r,rt) {
|
||||
if(!r.exc)
|
||||
$card.fadeOut()
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
},
|
||||
refresh: function() {
|
||||
// make the list
|
||||
wn.call({
|
||||
method:'utilities.page.users.users.get',
|
||||
callback: function(r, rt) {
|
||||
$(wn.pages.users).find('.layout-main').empty();
|
||||
for(var i in r.message) {
|
||||
var p = r.message[i];
|
||||
wn.pages.users.profiles[p.name] = p;
|
||||
wn.pages.users.render(p);
|
||||
}
|
||||
}
|
||||
});
|
||||
if(!$('.subscription-info').length && (wn.boot.max_users || wn.boot.expires_on)) {
|
||||
var $sub_info = $('<div class="subscription-info-box"><div>')
|
||||
.insertAfter($(wn.pages.users).find('.help'));
|
||||
if(wn.boot.max_users) {
|
||||
$sub_info.append(repl('\
|
||||
<span class="subscription-info"> \
|
||||
Max Users: <b>%(max_users)s</b> \
|
||||
</span>', { max_users: wn.boot.max_users }));
|
||||
}
|
||||
if(wn.boot.expires_on) {
|
||||
$sub_info.append(repl('\
|
||||
<span class="subscription-info"> \
|
||||
Expires On: <b>%(expires_on)s</b> \
|
||||
</span>', { expires_on: dateutil.str_to_user(wn.boot.expires_on) }));
|
||||
}
|
||||
}
|
||||
},
|
||||
render: function(data) {
|
||||
if(data.file_list) {
|
||||
data.imgsrc = 'files/' + data.file_list.split('\n')[0].split(',')[1];
|
||||
} else {
|
||||
data.imgsrc = 'lib/images/ui/no_img_' + (data.gender=='Female' ? 'f' : 'm') + '.gif';
|
||||
}
|
||||
data.fullname = wn.user_info(data.name).fullname;
|
||||
data.delete_html = '';
|
||||
if(!data.enabled)
|
||||
data.delete_html = '<a class="close" title="delete">×</a>';
|
||||
|
||||
$(wn.pages.users).find('.layout-main').append(repl('<div class="user-card" data-name="%(name)s">\
|
||||
%(delete_html)s\
|
||||
<img src="%(imgsrc)s">\
|
||||
<div class="user-info">\
|
||||
<b class="user-fullname">%(fullname)s</b><br>\
|
||||
%(name)s<br>\
|
||||
<button class="btn btn-small user-roles"><i class="icon-user"></i> Roles</button>\
|
||||
<button class="btn btn-small user-settings"><i class="icon-cog"></i> Settings</button>\
|
||||
</div>\
|
||||
</div>', data));
|
||||
|
||||
if(!data.enabled) {
|
||||
$(wn.pages.users).find('.layout-main .user-card:last')
|
||||
.addClass('disabled')
|
||||
.find('.user-fullname').html('Disabled');
|
||||
}
|
||||
},
|
||||
show_settings: function(uid) {
|
||||
var me = wn.pages.users;
|
||||
if(!me.settings_dialog)
|
||||
me.make_settings_dialog();
|
||||
|
||||
var p = me.profiles[uid];
|
||||
me.uid = uid;
|
||||
|
||||
me.settings_dialog.set_values({
|
||||
restrict_ip: p.restrict_ip || '',
|
||||
login_before: p.login_before || '',
|
||||
login_after: p.login_after || '',
|
||||
enabled: p.enabled || 0,
|
||||
new_password: ''
|
||||
});
|
||||
|
||||
me.settings_dialog.show();
|
||||
|
||||
},
|
||||
make_settings_dialog: function() {
|
||||
var me = wn.pages.users;
|
||||
me.settings_dialog = new wn.ui.Dialog({
|
||||
title: 'Set User Security',
|
||||
width: 500,
|
||||
fields: [
|
||||
{
|
||||
label:'Enabled',
|
||||
description: 'Uncheck to disable',
|
||||
fieldtype: 'Check', fieldname: 'enabled'
|
||||
},
|
||||
{
|
||||
label:'IP Address',
|
||||
description: 'Restrict user login by IP address, partial ips (111.111.111), \
|
||||
multiple addresses (separated by commas) allowed',
|
||||
fieldname:'restrict_ip', fieldtype:'Data'
|
||||
},
|
||||
{
|
||||
label:'Login After',
|
||||
description: 'User can only login after this hour (0-24)',
|
||||
fieldtype: 'Int', fieldname: 'login_after'
|
||||
},
|
||||
{
|
||||
label:'Login Before',
|
||||
description: 'User can only login before this hour (0-24)',
|
||||
fieldtype: 'Int', fieldname: 'login_before'
|
||||
},
|
||||
{
|
||||
label:'New Password',
|
||||
description: 'Update the current user password',
|
||||
fieldtype: 'Data', fieldname: 'new_password'
|
||||
},
|
||||
{
|
||||
label:'Update', fieldtype:'Button', fieldname:'update'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
this.settings_dialog.fields_dict.update.input.onclick = function() {
|
||||
var btn = this;
|
||||
var args = me.settings_dialog.get_values();
|
||||
args.user = me.uid;
|
||||
|
||||
if (args.new_password) {
|
||||
me.get_password(btn, args);
|
||||
} else {
|
||||
me.update_security(btn, args);
|
||||
}
|
||||
};
|
||||
|
||||
},
|
||||
update_security: function(btn, args) {
|
||||
var me = wn.pages.users;
|
||||
$(btn).set_working();
|
||||
$c_page('utilities', 'users', 'update_security', JSON.stringify(args), function(r,rt) {
|
||||
$(btn).done_working();
|
||||
if(r.exc) {
|
||||
msgprint(r.exc);
|
||||
return;
|
||||
}
|
||||
me.settings_dialog.hide();
|
||||
$.extend(me.profiles[me.uid], me.settings_dialog.get_values());
|
||||
me.refresh();
|
||||
});
|
||||
},
|
||||
get_password: function(btn, args) {
|
||||
var me = wn.pages.users;
|
||||
var pass_d = new wn.ui.Dialog({
|
||||
title: 'Your Password',
|
||||
width: 300,
|
||||
fields: [
|
||||
{
|
||||
label: 'Please Enter <b style="color: black">Your Password</b>',
|
||||
description: "Your password is required to update the user's password",
|
||||
fieldtype: 'Password', fieldname: 'sys_admin_pwd', reqd: 1
|
||||
},
|
||||
{
|
||||
label: 'Continue', fieldtype: 'Button', fieldname: 'continue'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
pass_d.fields_dict.continue.input.onclick = function() {
|
||||
btn.pwd_dialog.hide();
|
||||
args.sys_admin_pwd = btn.pwd_dialog.get_values().sys_admin_pwd;
|
||||
btn.set_working();
|
||||
me.update_security(btn, args);
|
||||
btn.done_working();
|
||||
}
|
||||
|
||||
pass_d.show();
|
||||
btn.pwd_dialog = pass_d;
|
||||
btn.done_working();
|
||||
},
|
||||
add_user: function() {
|
||||
var me = wn.pages.users;
|
||||
var active_users = $('.user-card:not(.disabled)');
|
||||
if(wn.boot.max_users && (active_users.length >= wn.boot.max_users)) {
|
||||
msgprint(repl("You already have <b>%(active_users)s</b> active users, \
|
||||
which is the maximum number that you are currently allowed to add. <br /><br /> \
|
||||
So, to add more users, you can:<br /> \
|
||||
1. <b>Upgrade to the unlimited users plan</b>, or<br /> \
|
||||
2. <b>Disable one or more of your existing users and try again</b>",
|
||||
{active_users: active_users.length}));
|
||||
return;
|
||||
}
|
||||
var d = new wn.ui.Dialog({
|
||||
title: 'Add User',
|
||||
width: 400,
|
||||
fields: [{
|
||||
fieldtype: 'Data', fieldname: 'user', reqd: 1,
|
||||
label: 'Email Id of the user to add'
|
||||
}, {
|
||||
fieldtype: 'Data', fieldname: 'first_name', reqd: 1, label: 'First Name'
|
||||
}, {
|
||||
fieldtype: 'Data', fieldname: 'last_name', label: 'Last Name'
|
||||
}, {
|
||||
fieldtype: 'Data', fieldname: 'password', reqd: 1, label: 'Password'
|
||||
}, {
|
||||
fieldtype: 'Button', label: 'Add', fieldname: 'add'
|
||||
}]
|
||||
});
|
||||
|
||||
d.make();
|
||||
d.fields_dict.add.input.onclick = function() {
|
||||
v = d.get_values();
|
||||
if(v) {
|
||||
d.fields_dict.add.input.set_working();
|
||||
$c_page('utilities', 'users', 'add_user', v, function(r,rt) {
|
||||
if(r.exc) { msgprint(r.exc); return; }
|
||||
else {
|
||||
wn.boot.user_info[v.user] = {fullname:v.first_name + ' ' + (v.last_name || '')};
|
||||
d.hide();
|
||||
me.refresh();
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
d.show();
|
||||
}
|
||||
});
|
||||
|
||||
erpnext.RoleEditor = Class.extend({
|
||||
init: function() {
|
||||
this.dialog = new wn.ui.Dialog({
|
||||
title: 'Set Roles'
|
||||
});
|
||||
var me = this;
|
||||
$(this.dialog.body).html('<div class="help">Loading...</div>')
|
||||
wn.call({
|
||||
method:'utilities.page.users.users.get_roles',
|
||||
callback: function(r) {
|
||||
me.roles = r.message;
|
||||
me.show_roles();
|
||||
}
|
||||
});
|
||||
},
|
||||
show_roles: function() {
|
||||
var me = this;
|
||||
$(this.dialog.body).empty();
|
||||
for(var i in this.roles) {
|
||||
$(this.dialog.body).append(repl('<div class="user-role" \
|
||||
data-user-role="%(role)s">\
|
||||
<input type="checkbox"> \
|
||||
<a href="#"><i class="icon-question-sign"></i></a> %(role)s\
|
||||
</div>', {role: this.roles[i]}));
|
||||
}
|
||||
$(this.dialog.body).append('<div style="clear: both">\
|
||||
<button class="btn btn-small btn-info">Save</button></div>');
|
||||
$(this.dialog.body).find('button.btn-info').click(function() {
|
||||
me.save();
|
||||
});
|
||||
$(this.dialog.body).find('.user-role a').click(function() {
|
||||
me.show_permissions($(this).parent().attr('data-user-role'))
|
||||
return false;
|
||||
})
|
||||
},
|
||||
show: function(uid) {
|
||||
var me = this;
|
||||
this.uid = uid;
|
||||
this.dialog.show();
|
||||
// set user roles
|
||||
wn.call({
|
||||
method:'utilities.page.users.users.get_user_roles',
|
||||
args: {uid:uid},
|
||||
callback: function(r, rt) {
|
||||
$(me.dialog.body).find('input[type="checkbox"]').attr('checked', false);
|
||||
for(var i in r.message) {
|
||||
$(me.dialog.body)
|
||||
.find('[data-user-role="'+r.message[i]
|
||||
+'"] input[type="checkbox"]').attr('checked',true);
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
save: function() {
|
||||
var set_roles = [];
|
||||
var unset_roles = [];
|
||||
$(this.dialog.body).find('[data-user-role]').each(function() {
|
||||
var $check = $(this).find('input[type="checkbox"]');
|
||||
if($check.attr('checked')) {
|
||||
set_roles.push($(this).attr('data-user-role'));
|
||||
} else {
|
||||
unset_roles.push($(this).attr('data-user-role'));
|
||||
}
|
||||
})
|
||||
wn.call({
|
||||
method:'utilities.page.users.users.update_roles',
|
||||
args: {
|
||||
set_roles: JSON.stringify(set_roles),
|
||||
unset_roles: JSON.stringify(unset_roles),
|
||||
uid: this.uid
|
||||
},
|
||||
btn: $(this.dialog.body).find('.btn-info').get(0),
|
||||
callback: function() {
|
||||
|
||||
}
|
||||
})
|
||||
},
|
||||
show_permissions: function(role) {
|
||||
// show permissions for a role
|
||||
var me = this;
|
||||
if(!this.perm_dialog)
|
||||
this.make_perm_dialog()
|
||||
$(this.perm_dialog.body).empty();
|
||||
wn.call({
|
||||
method:'utilities.page.users.users.get_perm_info',
|
||||
args: {role: role},
|
||||
callback: function(r) {
|
||||
var $body = $(me.perm_dialog.body);
|
||||
$body.append('<table class="user-perm"><tbody><tr>\
|
||||
<th style="text-align: left">Document Type</th>\
|
||||
<th>Level</th>\
|
||||
<th>Read</th>\
|
||||
<th>Write</th>\
|
||||
<th>Submit</th>\
|
||||
<th>Cancel</th>\
|
||||
<th>Amend</th></tr></tbody></table>');
|
||||
for(var i in r.message) {
|
||||
var perm = r.message[i];
|
||||
|
||||
// if permission -> icon
|
||||
for(key in perm) {
|
||||
if(key!='parent' && key!='permlevel') {
|
||||
if(perm[key]) {
|
||||
perm[key] = '<i class="icon-ok"></i>';
|
||||
} else {
|
||||
perm[key] = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$body.find('tbody').append(repl('<tr>\
|
||||
<td style="text-align: left">%(parent)s</td>\
|
||||
<td>%(permlevel)s</td>\
|
||||
<td>%(read)s</td>\
|
||||
<td>%(write)s</td>\
|
||||
<td>%(submit)s</td>\
|
||||
<td>%(cancel)s</td>\
|
||||
<td>%(amend)s</td>\
|
||||
</tr>', perm))
|
||||
}
|
||||
|
||||
me.perm_dialog.show();
|
||||
}
|
||||
});
|
||||
|
||||
},
|
||||
make_perm_dialog: function() {
|
||||
this.perm_dialog = new wn.ui.Dialog({
|
||||
title:'Role Permissions',
|
||||
width: 500
|
||||
});
|
||||
}
|
||||
})
|
@ -1,202 +0,0 @@
|
||||
# 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
|
||||
import json
|
||||
|
||||
from webnotes.model.doc import Document
|
||||
from webnotes.utils import cint
|
||||
|
||||
@webnotes.whitelist()
|
||||
def get(arg=None):
|
||||
"""return all users"""
|
||||
return webnotes.conn.sql("""select name, file_list, enabled, gender,
|
||||
restrict_ip, login_before, login_after from tabProfile
|
||||
where docstatus<2 and name not in ('Administrator', 'Guest') order by
|
||||
ifnull(enabled,0) desc, name""", as_dict=1)
|
||||
|
||||
@webnotes.whitelist()
|
||||
def get_roles(arg=None):
|
||||
"""return all roles except standard"""
|
||||
return _get_roles(webnotes.form_dict['uid'])
|
||||
|
||||
def _get_roles(user):
|
||||
"""return all roles except standard"""
|
||||
return [r[0] for r in webnotes.conn.sql("""select name from tabRole
|
||||
where name not in ('Administrator', 'Guest', 'All') order by name""", user)]
|
||||
|
||||
@webnotes.whitelist()
|
||||
def get_user_roles(arg=None):
|
||||
"""get roles for a user"""
|
||||
return [r[0] for r in webnotes.conn.sql("""select role from tabUserRole
|
||||
where parent=%s""", webnotes.form_dict['uid'])]
|
||||
|
||||
@webnotes.whitelist()
|
||||
def get_perm_info(arg=None):
|
||||
"""get permission info"""
|
||||
return webnotes.conn.sql("""select parent, permlevel, `read`, `write`, submit,
|
||||
cancel, amend from tabDocPerm where role=%s
|
||||
and docstatus<2 order by parent, permlevel""",
|
||||
webnotes.form_dict['role'], as_dict=1)
|
||||
|
||||
@webnotes.whitelist()
|
||||
def update_roles(arg=None):
|
||||
"""update set and unset roles"""
|
||||
# remove roles
|
||||
unset = json.loads(webnotes.form_dict['unset_roles'])
|
||||
webnotes.conn.sql("""delete from tabUserRole where parent='%s'
|
||||
and role in ('%s')""" % (webnotes.form_dict['uid'], "','".join(unset)))
|
||||
|
||||
# check for 1 system manager
|
||||
if not webnotes.conn.sql("""select parent from tabUserRole where role='System Manager'
|
||||
and docstatus<2"""):
|
||||
webnotes.msgprint("Sorry there must be atleast one 'System Manager'")
|
||||
raise webnotes.ValidationError
|
||||
|
||||
# add roles
|
||||
roles = get_user_roles()
|
||||
toset = json.loads(webnotes.form_dict['set_roles'])
|
||||
for role in toset:
|
||||
if not role in roles:
|
||||
d = Document('UserRole')
|
||||
d.role = role
|
||||
d.parent = webnotes.form_dict['uid']
|
||||
d.save()
|
||||
|
||||
webnotes.msgprint('Roles Updated')
|
||||
|
||||
@webnotes.whitelist()
|
||||
def update_security(args=''):
|
||||
args = json.loads(args)
|
||||
webnotes.conn.set_value('Profile', args['user'], 'restrict_ip', args.get('restrict_ip') or '')
|
||||
webnotes.conn.set_value('Profile', args['user'], 'login_after', args.get('login_after') or None)
|
||||
webnotes.conn.set_value('Profile', args['user'], 'login_before', args.get('login_before') or None)
|
||||
webnotes.conn.set_value('Profile', args['user'], 'enabled', int(args.get('enabled',0)) or 0)
|
||||
|
||||
# logout a disabled user
|
||||
if not int(args.get('enabled',0) or 0):
|
||||
webnotes.login_manager.logout(user=args['user'])
|
||||
|
||||
if args.get('new_password') and args.get('sys_admin_pwd'):
|
||||
from webnotes.utils import cint
|
||||
webnotes.conn.sql("update tabProfile set password=password(%s) where name=%s",
|
||||
(args['new_password'], args['user']))
|
||||
else:
|
||||
webnotes.msgprint('Settings Updated')
|
||||
|
||||
|
||||
|
||||
#
|
||||
# user addition
|
||||
#
|
||||
|
||||
@webnotes.whitelist()
|
||||
def add_user(args):
|
||||
args = json.loads(args)
|
||||
add_profile(args)
|
||||
|
||||
@webnotes.whitelist()
|
||||
def add_profile(args):
|
||||
from webnotes.utils import validate_email_add, now
|
||||
email = args['user']
|
||||
sql = webnotes.conn.sql
|
||||
|
||||
# validate max number of users exceeded or not
|
||||
import conf
|
||||
if hasattr(conf, 'max_users'):
|
||||
active_users = sql("""select count(*) from tabProfile
|
||||
where ifnull(enabled, 0)=1 and docstatus<2
|
||||
and name not in ('Administrator', 'Guest')""")[0][0]
|
||||
if active_users >= conf.max_users and conf.max_users:
|
||||
# same message as in users.js
|
||||
webnotes.msgprint("""Alas! <br />\
|
||||
You already have <b>%(active_users)s</b> active users, \
|
||||
which is the maximum number that you are currently allowed to add. <br /><br /> \
|
||||
So, to add more users, you can:<br /> \
|
||||
1. <b>Upgrade to the unlimited users plan</b>, or<br /> \
|
||||
2. <b>Disable one or more of your existing users and try again</b>""" \
|
||||
% {'active_users': active_users}, raise_exception=1)
|
||||
|
||||
if not email:
|
||||
email = webnotes.form_dict.get('user')
|
||||
if not validate_email_add(email):
|
||||
raise Exception
|
||||
return 'Invalid Email Id'
|
||||
|
||||
if sql("select name from tabProfile where name = %s", email):
|
||||
# exists, enable it
|
||||
sql("update tabProfile set enabled = 1, docstatus=0 where name = %s", email)
|
||||
webnotes.msgprint('Profile exists, enabled it with new password')
|
||||
else:
|
||||
# does not exist, create it!
|
||||
pr = Document('Profile')
|
||||
pr.name = email
|
||||
pr.email = email
|
||||
pr.first_name = args.get('first_name')
|
||||
pr.last_name = args.get('last_name')
|
||||
pr.enabled = 1
|
||||
pr.user_type = 'System User'
|
||||
pr.save(1)
|
||||
|
||||
if args.get('password'):
|
||||
sql("""
|
||||
UPDATE tabProfile
|
||||
SET password = PASSWORD(%s), modified = %s
|
||||
WHERE name = %s""", (args.get('password'), now, email))
|
||||
|
||||
send_welcome_mail(email, args)
|
||||
|
||||
@webnotes.whitelist()
|
||||
def send_welcome_mail(email, args):
|
||||
"""send welcome mail to user with password and login url"""
|
||||
pr = Document('Profile', email)
|
||||
from webnotes.utils.email_lib import sendmail_md
|
||||
args.update({
|
||||
'company': webnotes.conn.get_default('company'),
|
||||
'password': args.get('password'),
|
||||
'account_url': webnotes.conn.get_value('Website Settings',
|
||||
'Website Settings', 'subdomain') or ""
|
||||
})
|
||||
if not args.get('last_name'): args['last_name'] = ''
|
||||
sendmail_md(pr.email, subject="Welcome to ERPNext", msg=welcome_txt % args)
|
||||
|
||||
#
|
||||
# delete user
|
||||
#
|
||||
@webnotes.whitelist()
|
||||
def delete(arg=None):
|
||||
"""delete user"""
|
||||
webnotes.conn.sql("update tabProfile set enabled=0, docstatus=2 where name=%s",
|
||||
webnotes.form_dict['uid'])
|
||||
webnotes.login_manager.logout(user=webnotes.form_dict['uid'])
|
||||
|
||||
welcome_txt = """
|
||||
## %(company)s
|
||||
|
||||
Dear %(first_name)s %(last_name)s
|
||||
|
||||
Welcome!
|
||||
|
||||
A new account has been created for you, here are your details:
|
||||
|
||||
login-id: %(user)s
|
||||
password: %(password)s
|
||||
|
||||
To login to your new ERPNext account, please go to:
|
||||
|
||||
%(account_url)s
|
||||
"""
|
@ -1,28 +0,0 @@
|
||||
# Page, users
|
||||
[
|
||||
|
||||
# These values are common in all dictionaries
|
||||
{
|
||||
'creation': '2012-02-28 10:29:39',
|
||||
'docstatus': 0,
|
||||
'modified': '2012-02-28 10:29:39',
|
||||
'modified_by': u'Administrator',
|
||||
'owner': u'Administrator'
|
||||
},
|
||||
|
||||
# These values are common for all Page
|
||||
{
|
||||
'doctype': 'Page',
|
||||
'module': u'Utilities',
|
||||
'name': '__common__',
|
||||
'page_name': u'users',
|
||||
'standard': u'Yes',
|
||||
'title': u'Users'
|
||||
},
|
||||
|
||||
# Page, users
|
||||
{
|
||||
'doctype': 'Page',
|
||||
'name': u'users'
|
||||
}
|
||||
]
|
Loading…
x
Reference in New Issue
Block a user