mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-05 06:28:29 +00:00
moved directory structure
This commit is contained in:
42
utilities/__init__.py
Normal file
42
utilities/__init__.py
Normal file
@@ -0,0 +1,42 @@
|
||||
# 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
|
||||
|
||||
@webnotes.whitelist()
|
||||
def get_sc_list(arg=None):
|
||||
"""return list of reports for the given module module"""
|
||||
webnotes.response['values'] = webnotes.conn.sql("""select
|
||||
distinct criteria_name, doc_type, parent_doc_type
|
||||
from `tabSearch Criteria`
|
||||
where module='%(module)s'
|
||||
and docstatus in (0, NULL)
|
||||
and ifnull(disabled, 0) = 0
|
||||
order by criteria_name
|
||||
limit %(limit_start)s, %(limit_page_length)s""" % webnotes.form_dict, as_dict=True)
|
||||
|
||||
@webnotes.whitelist()
|
||||
def get_report_list():
|
||||
"""return list on new style reports for modules"""
|
||||
webnotes.response['values'] = webnotes.conn.sql("""select
|
||||
distinct tabReport.name, tabReport.ref_doctype
|
||||
from `tabReport`, `tabDocType`
|
||||
where tabDocType.module='%(module)s'
|
||||
and tabDocType.name = tabReport.ref_doctype
|
||||
and tabReport.docstatus in (0, NULL)
|
||||
order by tabReport.name
|
||||
limit %(limit_start)s, %(limit_page_length)s""" % webnotes.form_dict, as_dict=True)
|
||||
208
utilities/cleanup_data.py
Normal file
208
utilities/cleanup_data.py
Normal file
@@ -0,0 +1,208 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# This script is for cleaning up of all data from system including
|
||||
# all transactions and masters (excludes default masters).
|
||||
# Basically after running this file, system will reset to it's
|
||||
# initial state.
|
||||
# This script can be executed from lib/wnf.py using
|
||||
# lib/wnf.py --cleanup-data
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import sys
|
||||
sys.path.append("lib/py")
|
||||
sys.path.append(".")
|
||||
sys.path.append("erpnext")
|
||||
|
||||
import webnotes
|
||||
|
||||
#--------------------------------
|
||||
|
||||
def delete_transactions():
|
||||
print "Deleting transactions..."
|
||||
|
||||
trans = ['Timesheet','Task','Support Ticket','Stock Reconciliation', 'Stock Ledger Entry', \
|
||||
'Stock Entry','Sales Order','Salary Slip','Sales Invoice','Quotation', 'Quality Inspection', \
|
||||
'Purchase Receipt','Purchase Order','Production Order', 'POS Setting','Period Closing Voucher', \
|
||||
'Purchase Invoice','Maintenance Visit','Maintenance Schedule','Leave Application', \
|
||||
'Leave Allocation', 'Lead', 'Journal Voucher', 'Installation Note','Purchase Request', \
|
||||
'GL Entry','Expense Claim','Opportunity','Delivery Note','Customer Issue','Bin', \
|
||||
'Authorization Rule','Attendance','Account Balance', 'C-Form', 'Form 16A', 'Lease Agreement', \
|
||||
'Lease Installment', 'TDS Payment', 'TDS Return Acknowledgement', 'Appraisal', \
|
||||
'Installation Note', 'Communication'
|
||||
]
|
||||
for d in trans:
|
||||
for t in webnotes.conn.sql("select options from tabDocField where parent='%s' and fieldtype='Table'" % d):
|
||||
webnotes.conn.sql("delete from `tab%s`" % (t))
|
||||
webnotes.conn.sql("delete from `tab%s`" % (d))
|
||||
webnotes.conn.sql("COMMIT")
|
||||
webnotes.conn.sql("START TRANSACTION")
|
||||
print "Deleted " + d
|
||||
|
||||
|
||||
|
||||
def delete_masters():
|
||||
print "Deleting masters...."
|
||||
masters = {
|
||||
'Workstation':['Default Workstation'],
|
||||
'Warehouse Type':['Default Warehouse Type', 'Fixed Asset', 'Rejected', 'Reserved',
|
||||
'Sample', 'Stores', 'WIP Warehouse'],
|
||||
'Warehouse':['Default Warehouse'],
|
||||
'UOM':['Kg', 'Mtr', 'Box', 'Ltr', 'Nos', 'Ft', 'Pair', 'Set'],
|
||||
'Territory':['All Territories', 'Default Territory'],
|
||||
'Terms and Conditions':'',
|
||||
'Tag':'',
|
||||
'Supplier Type':['Default Supplier Type'],
|
||||
'Supplier':'',
|
||||
'Serial No':'',
|
||||
'Sales Person':['All Sales Persons'],
|
||||
'Sales Partner':'',
|
||||
'Sales BOM':'',
|
||||
'Salary Structure':'',
|
||||
'Purchase Taxes and Charges Master':'',
|
||||
'Project':'',
|
||||
'Print Heading':'',
|
||||
'Price List':['Default Price List'],
|
||||
'Period':'',
|
||||
'Sales Taxes and Charges Master':'',
|
||||
'Letter Head':'',
|
||||
'Leave Type':['Leave Without Pay', 'Privilege Leave', 'Casual Leave', 'PL', 'CL', 'LWP',
|
||||
'Compensatory Off', 'Sick Leave'],
|
||||
'Landed Cost Master':'',
|
||||
'Appraisal Template':'',
|
||||
'Item Group':['All Item Groups', 'Default'],
|
||||
'Item':'',
|
||||
'Holiday List':'',
|
||||
'Grade':'',
|
||||
'Feed':'',
|
||||
'Expense Claim Type':['Travel', 'Medical', 'Calls', 'Food', 'Others'],
|
||||
'Event':'',
|
||||
'Employment Type':'',
|
||||
'Employee':'',
|
||||
'Earning Type':['Basic', 'Conveyance', 'House Rent Allowance', 'Dearness Allowance',
|
||||
'Medical Allowance', 'Telephone'],
|
||||
'Designation':'',
|
||||
'Department':'',
|
||||
'Deduction Type':['Income Tax', 'Professional Tax', 'Provident Fund', 'Leave Deduction'],
|
||||
'Customer Group':['All Customer Groups', 'Default Customer Group'],
|
||||
'Customer':'',
|
||||
'Cost Center':'',
|
||||
'Contact':'',
|
||||
'Campaign':'',
|
||||
'Budget Distribution':'',
|
||||
'Brand':'',
|
||||
'Branch':'',
|
||||
'Batch':'',
|
||||
'Appraisal':'',
|
||||
'Account':'',
|
||||
'BOM': ''
|
||||
}
|
||||
for d in masters.keys():
|
||||
for t in webnotes.conn.sql("select options from tabDocField where parent='%s' \
|
||||
and fieldtype='Table'" % d):
|
||||
webnotes.conn.sql("delete from `tab%s`" % (t))
|
||||
lst = '"'+'","'.join(masters[d])+ '"'
|
||||
webnotes.conn.sql("delete from `tab%s` where name not in (%s)" % (d, lst))
|
||||
webnotes.conn.sql("COMMIT")
|
||||
webnotes.conn.sql("START TRANSACTION")
|
||||
print "Deleted " + d
|
||||
|
||||
|
||||
|
||||
def reset_all_series():
|
||||
# Reset master series
|
||||
webnotes.conn.sql("""update tabSeries set current = 0 where name not in
|
||||
('Ann/', 'BSD', 'DEF', 'DF', 'EV', 'Event Updates/', 'FileData-',
|
||||
'FL', 'FMD/', 'GLM Detail', 'Login Page/', 'MDI', 'MDR', 'MI', 'MIR',
|
||||
'PERM', 'PR', 'SRCH/C/', 'TD', 'TIC/', 'TMD/', 'TW', 'UR', '_FEED',
|
||||
'_SRCH', '_TRIGGER', '__NSO', 'CustomField', 'Letter')
|
||||
""")
|
||||
print "Series updated"
|
||||
|
||||
def reset_transaction_series():
|
||||
webnotes.conn.sql("""update tabSeries set current = 0 where name in
|
||||
('JV', 'INV', 'BILL', 'SO', 'DN', 'PO', 'LEAD', 'ENQUIRY', 'ENQ', 'CI',
|
||||
'IN', 'PS', 'IDT', 'QAI', 'QTN', 'STE', 'SQTN', 'SUP', 'TDSP', 'SR',
|
||||
'POS', 'LAP', 'LAL', 'EXP')""")
|
||||
print "Series updated"
|
||||
|
||||
|
||||
def delete_main_masters():
|
||||
main_masters = ['Fiscal Year','Company', 'DefaultValue']
|
||||
for d in main_masters:
|
||||
for t in webnotes.conn.sql("select options from tabDocField where parent='%s' and fieldtype='Table'" % d):
|
||||
webnotes.conn.sql("delete from `tab%s`" % (t))
|
||||
webnotes.conn.sql("delete from `tab%s`" % (d))
|
||||
webnotes.conn.sql("COMMIT")
|
||||
webnotes.conn.sql("START TRANSACTION")
|
||||
print "Deleted " + d
|
||||
|
||||
|
||||
|
||||
def reset_global_defaults():
|
||||
flds = {
|
||||
'default_company': '',
|
||||
'default_currency': '',
|
||||
'default_currency_format': 'Lacs',
|
||||
'default_currency_fraction': '',
|
||||
'current_fiscal_year': '',
|
||||
'date_format': 'dd-mm-yyyy',
|
||||
'sms_sender_name': '',
|
||||
'default_item_group': 'Default',
|
||||
'default_stock_uom': 'Nos',
|
||||
'default_valuation_method': 'FIFO',
|
||||
'default_warehouse_type': 'Default Warehouse Type',
|
||||
'tolerance': '',
|
||||
'acc_frozen_upto': '',
|
||||
'bde_auth_role': '',
|
||||
'credit_controller': '',
|
||||
'default_customer_group': 'Default Customer Group',
|
||||
'default_territory': 'Default',
|
||||
'default_price_list': 'Standard',
|
||||
'default_supplier_type': 'Default Supplier Type'
|
||||
}
|
||||
|
||||
from webnotes.model.code import get_obj
|
||||
gd = get_obj('Global Defaults', 'Global Defaults')
|
||||
for d in flds:
|
||||
gd.doc.fields[d] = flds[d]
|
||||
gd.doc.save()
|
||||
|
||||
webnotes.clear_cache()
|
||||
|
||||
|
||||
def run():
|
||||
webnotes.connect()
|
||||
|
||||
# Confirmation from user
|
||||
confirm = ''
|
||||
while not confirm:
|
||||
confirm = raw_input("Are you sure you want to delete the data from the system (N/Y)?")
|
||||
if confirm.lower() != 'y':
|
||||
raise Exception
|
||||
|
||||
cleanup_type = ''
|
||||
while cleanup_type not in ['1', '2']:
|
||||
cleanup_type = raw_input("""\nWhat type of cleanup you want ot perform?
|
||||
1. Only Transactions
|
||||
2. Both Masters and Transactions
|
||||
|
||||
Please enter your choice (1/2):
|
||||
""")
|
||||
|
||||
# delete
|
||||
delete_transactions()
|
||||
|
||||
if cleanup_type == '1':
|
||||
reset_transaction_series()
|
||||
else:
|
||||
delete_masters()
|
||||
reset_all_series()
|
||||
delete_main_masters()
|
||||
reset_global_defaults()
|
||||
|
||||
print "System cleaned up succesfully"
|
||||
webnotes.conn.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
run()
|
||||
1
utilities/doctype/__init__.py
Normal file
1
utilities/doctype/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from __future__ import unicode_literals
|
||||
1
utilities/doctype/address/__init__.py
Normal file
1
utilities/doctype/address/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from __future__ import unicode_literals
|
||||
44
utilities/doctype/address/address.js
Normal file
44
utilities/doctype/address/address.js
Normal file
@@ -0,0 +1,44 @@
|
||||
// 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/>.
|
||||
|
||||
cur_frm.cscript.onload = function(doc, cdt, cdn) {
|
||||
if(doc.customer) cur_frm.add_fetch('customer', 'customer_name', 'customer_name');
|
||||
if(doc.supplier) cur_frm.add_fetch('supplier', 'supplier_name', 'supplier_name');
|
||||
|
||||
var route = wn.get_route();
|
||||
if(route[1]=='Supplier') {
|
||||
var supplier = wn.container.page.frm.doc;
|
||||
doc.supplier = supplier.name;
|
||||
doc.supplier_name = supplier.supplier_name;
|
||||
doc.address_type = 'Office';
|
||||
} else if(route[1]=='Customer') {
|
||||
var customer = wn.container.page.frm.doc;
|
||||
doc.customer = customer.name;
|
||||
doc.customer_name = customer.customer_name;
|
||||
doc.address_type = 'Office';
|
||||
} else if(route[1]=='Sales Partner') {
|
||||
var sp = wn.container.page.frm.doc;
|
||||
doc.sales_partner = sp.name;
|
||||
doc.address_type = 'Office';
|
||||
}
|
||||
}
|
||||
|
||||
cur_frm.cscript.hide_dialog = function() {
|
||||
if(cur_frm.address_list)
|
||||
cur_frm.address_list.run();
|
||||
}
|
||||
|
||||
|
||||
79
utilities/doctype/address/address.py
Normal file
79
utilities/doctype/address/address.py
Normal file
@@ -0,0 +1,79 @@
|
||||
# ERPNext - web based ERP (http://erpnext.com)
|
||||
# Copyright (C) 2012 Web Notes Technologies Pvt Ltd
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Please edit this list and import only required elements
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
|
||||
from webnotes.model.doc import Document
|
||||
from webnotes import session, form, msgprint, errprint
|
||||
|
||||
# -----------------------------------------------------------------------------------------
|
||||
class DocType:
|
||||
def __init__(self, doc, doclist=[]):
|
||||
self.doc = doc
|
||||
self.doclist = doclist
|
||||
|
||||
def autoname(self):
|
||||
if self.doc.customer:
|
||||
self.doc.name = self.doc.customer + '-' + self.doc.address_type
|
||||
elif self.doc.supplier:
|
||||
self.doc.name = self.doc.supplier + '-' + self.doc.address_type
|
||||
elif self.doc.sales_partner:
|
||||
self.doc.name = self.doc.sales_partner + '-' + self.doc.address_type
|
||||
|
||||
|
||||
def validate(self):
|
||||
self.validate_for_whom()
|
||||
self.validate_primary_address()
|
||||
self.validate_shipping_address()
|
||||
|
||||
def validate_for_whom(self):
|
||||
if not (self.doc.customer or self.doc.supplier or self.doc.sales_partner):
|
||||
msgprint("Please enter value in atleast one of customer, supplier and sales partner field", raise_exception=1)
|
||||
|
||||
def validate_primary_address(self):
|
||||
"""Validate that there can only be one primary address for particular customer, supplier"""
|
||||
sql = webnotes.conn.sql
|
||||
if self.doc.is_primary_address == 1:
|
||||
if self.doc.customer:
|
||||
sql("update tabAddress set is_primary_address=0 where customer = '%s'" % (self.doc.customer))
|
||||
elif self.doc.supplier:
|
||||
sql("update tabAddress set is_primary_address=0 where supplier = '%s'" % (self.doc.supplier))
|
||||
elif self.doc.sales_partner:
|
||||
sql("update tabAddress set is_primary_address=0 where sales_partner = '%s'" % (self.doc.sales_partner))
|
||||
elif not self.doc.is_shipping_address:
|
||||
if self.doc.customer:
|
||||
if not sql("select name from tabAddress where is_primary_address=1 and customer = '%s'" % (self.doc.customer)):
|
||||
self.doc.is_primary_address = 1
|
||||
elif self.doc.supplier:
|
||||
if not sql("select name from tabAddress where is_primary_address=1 and supplier = '%s'" % (self.doc.supplier)):
|
||||
self.doc.is_primary_address = 1
|
||||
elif self.doc.sales_partner:
|
||||
if not sql("select name from tabAddress where is_primary_address=1 and sales_partner = '%s'" % (self.doc.sales_partner)):
|
||||
self.doc.is_primary_address = 1
|
||||
|
||||
|
||||
def validate_shipping_address(self):
|
||||
"""Validate that there can only be one shipping address for particular customer, supplier"""
|
||||
sql = webnotes.conn.sql
|
||||
if self.doc.is_shipping_address == 1:
|
||||
if self.doc.customer:
|
||||
sql("update tabAddress set is_shipping_address=0 where customer = '%s'" % (self.doc.customer))
|
||||
elif self.doc.supplier:
|
||||
sql("update tabAddress set is_shipping_address=0 where supplier = '%s'" % (self.doc.supplier))
|
||||
elif self.doc.sales_partner:
|
||||
sql("update tabAddress set is_shipping_address=0 where sales_partner = '%s'" % (self.doc.sales_partner))
|
||||
395
utilities/doctype/address/address.txt
Normal file
395
utilities/doctype/address/address.txt
Normal file
@@ -0,0 +1,395 @@
|
||||
# DocType, Address
|
||||
[
|
||||
|
||||
# These values are common in all dictionaries
|
||||
{
|
||||
'creation': '2012-07-02 19:57:47',
|
||||
'docstatus': 0,
|
||||
'modified': '2012-07-02 20:24:15',
|
||||
'modified_by': u'Administrator',
|
||||
'owner': u'Administrator'
|
||||
},
|
||||
|
||||
# These values are common for all DocType
|
||||
{
|
||||
'_last_update': u'1319016431',
|
||||
'allow_trash': 1,
|
||||
'colour': u'White:FFF',
|
||||
'default_print_format': u'Standard',
|
||||
'doctype': 'DocType',
|
||||
'document_type': u'Master',
|
||||
'in_dialog': 1,
|
||||
'module': u'Utilities',
|
||||
'name': '__common__',
|
||||
'search_fields': u'customer, supplier, sales_partner, country, state',
|
||||
'section_style': u'Simple',
|
||||
'show_in_menu': 0,
|
||||
'version': 1
|
||||
},
|
||||
|
||||
# These values are common for all DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'name': '__common__',
|
||||
'parent': u'Address',
|
||||
'parentfield': u'fields',
|
||||
'parenttype': u'DocType'
|
||||
},
|
||||
|
||||
# These values are common for all DocPerm
|
||||
{
|
||||
'doctype': u'DocPerm',
|
||||
'name': '__common__',
|
||||
'parent': u'Address',
|
||||
'parentfield': u'permissions',
|
||||
'parenttype': u'DocType',
|
||||
'read': 1
|
||||
},
|
||||
|
||||
# DocType, Address
|
||||
{
|
||||
'doctype': 'DocType',
|
||||
'name': u'Address'
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'cancel': 1,
|
||||
'create': 1,
|
||||
'doctype': u'DocPerm',
|
||||
'permlevel': 0,
|
||||
'role': u'System Manager',
|
||||
'write': 1
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'cancel': 1,
|
||||
'create': 1,
|
||||
'doctype': u'DocPerm',
|
||||
'permlevel': 0,
|
||||
'role': u'Sales Master Manager',
|
||||
'write': 1
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'cancel': 1,
|
||||
'create': 1,
|
||||
'doctype': u'DocPerm',
|
||||
'permlevel': 0,
|
||||
'role': u'Purchase Master Manager',
|
||||
'write': 1
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'cancel': 0,
|
||||
'create': 1,
|
||||
'doctype': u'DocPerm',
|
||||
'permlevel': 0,
|
||||
'role': u'Maintenance Manager',
|
||||
'write': 1
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'cancel': 0,
|
||||
'create': 1,
|
||||
'doctype': u'DocPerm',
|
||||
'permlevel': 0,
|
||||
'role': u'Accounts Manager',
|
||||
'write': 1
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'create': 1,
|
||||
'doctype': u'DocPerm',
|
||||
'permlevel': 0,
|
||||
'role': u'Sales Manager',
|
||||
'write': 1
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'create': 1,
|
||||
'doctype': u'DocPerm',
|
||||
'permlevel': 0,
|
||||
'role': u'Purchase Manager',
|
||||
'write': 1
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'create': 1,
|
||||
'doctype': u'DocPerm',
|
||||
'permlevel': 0,
|
||||
'role': u'Sales User',
|
||||
'write': 1
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'create': 1,
|
||||
'doctype': u'DocPerm',
|
||||
'permlevel': 0,
|
||||
'role': u'Purchase User',
|
||||
'write': 1
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'create': 1,
|
||||
'doctype': u'DocPerm',
|
||||
'permlevel': 0,
|
||||
'role': u'Maintenance User',
|
||||
'write': 1
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'create': 1,
|
||||
'doctype': u'DocPerm',
|
||||
'permlevel': 0,
|
||||
'role': u'Accounts User',
|
||||
'write': 1
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'cancel': 0,
|
||||
'create': 0,
|
||||
'doctype': u'DocPerm',
|
||||
'permlevel': 1,
|
||||
'role': u'All',
|
||||
'write': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'address_details',
|
||||
'fieldtype': u'Section Break',
|
||||
'label': u'Address Details',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'description': u'<em>e.g. Office, Billing, Shipping</em>',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'address_type',
|
||||
'fieldtype': u'Data',
|
||||
'label': u'Address Type',
|
||||
'permlevel': 0,
|
||||
'reqd': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'address_line1',
|
||||
'fieldtype': u'Data',
|
||||
'label': u'Address Line1',
|
||||
'permlevel': 0,
|
||||
'reqd': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'address_line2',
|
||||
'fieldtype': u'Data',
|
||||
'label': u'Address Line2',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'city',
|
||||
'fieldtype': u'Data',
|
||||
'in_filter': 1,
|
||||
'label': u'City/Town',
|
||||
'permlevel': 0,
|
||||
'reqd': 1,
|
||||
'search_index': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'pincode',
|
||||
'fieldtype': u'Data',
|
||||
'in_filter': 1,
|
||||
'label': u'Pincode',
|
||||
'permlevel': 0,
|
||||
'search_index': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'country',
|
||||
'fieldtype': u'Select',
|
||||
'in_filter': 1,
|
||||
'label': u'Country',
|
||||
'options': u'link:Country',
|
||||
'permlevel': 0,
|
||||
'reqd': 1,
|
||||
'search_index': 1,
|
||||
'trigger': u'Client'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'state',
|
||||
'fieldtype': u'Data',
|
||||
'in_filter': 1,
|
||||
'label': u'State',
|
||||
'options': u'Suggest',
|
||||
'permlevel': 0,
|
||||
'search_index': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'column_break0',
|
||||
'fieldtype': u'Column Break',
|
||||
'permlevel': 0,
|
||||
'print_hide': 0,
|
||||
'width': u'50%'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'phone',
|
||||
'fieldtype': u'Data',
|
||||
'label': u'Phone',
|
||||
'permlevel': 0,
|
||||
'reqd': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'email_id',
|
||||
'fieldtype': u'Data',
|
||||
'label': u'Email Id',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'fax',
|
||||
'fieldtype': u'Data',
|
||||
'in_filter': 1,
|
||||
'label': u'Fax',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'depends_on': u'eval:!doc.supplier && !doc.sales_partner',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'customer',
|
||||
'fieldtype': u'Link',
|
||||
'label': u'Customer',
|
||||
'options': u'Customer',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'depends_on': u'eval:!doc.supplier && !doc.sales_partner',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'customer_name',
|
||||
'fieldtype': u'Data',
|
||||
'in_filter': 1,
|
||||
'label': u'Customer Name',
|
||||
'permlevel': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'depends_on': u'eval:!doc.customer && !doc.sales_partner',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'supplier',
|
||||
'fieldtype': u'Link',
|
||||
'label': u'Supplier',
|
||||
'options': u'Supplier',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'depends_on': u'eval:!doc.customer && !doc.sales_partner',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'supplier_name',
|
||||
'fieldtype': u'Data',
|
||||
'in_filter': 1,
|
||||
'label': u'Supplier Name',
|
||||
'permlevel': 1,
|
||||
'search_index': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'depends_on': u'eval:!doc.customer && !doc.supplier',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'sales_partner',
|
||||
'fieldtype': u'Link',
|
||||
'label': u'Sales Partner',
|
||||
'options': u'Sales Partner',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'default': u'0',
|
||||
'description': u'Check to make primary address',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'is_primary_address',
|
||||
'fieldtype': u'Check',
|
||||
'label': u'Is Primary Address',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'default': u'0',
|
||||
'description': u'Check to make Shipping Address',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'is_shipping_address',
|
||||
'fieldtype': u'Check',
|
||||
'label': u'Is Shipping Address',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'trash_reason',
|
||||
'fieldtype': u'Small Text',
|
||||
'label': u'Trash Reason',
|
||||
'permlevel': 0
|
||||
}
|
||||
]
|
||||
55
utilities/doctype/address/address_list.js
Normal file
55
utilities/doctype/address/address_list.js
Normal file
@@ -0,0 +1,55 @@
|
||||
wn.doclistviews['Address'] = wn.views.ListView.extend({
|
||||
init: function(d) {
|
||||
this._super(d)
|
||||
this.fields = this.fields.concat([
|
||||
"`tabAddress`.customer_name",
|
||||
"`tabAddress`.supplier",
|
||||
"`tabAddress`.supplier_name",
|
||||
"`tabAddress`.sales_partner",
|
||||
"`tabAddress`.city",
|
||||
"`tabAddress`.country",
|
||||
"ifnull(`tabAddress`.is_shipping_address, 0) as is_shipping_address",
|
||||
]);
|
||||
},
|
||||
|
||||
prepare_data: function(data) {
|
||||
this._super(data);
|
||||
|
||||
// prepare address
|
||||
var address = []
|
||||
$.each(['city', 'country'], function(i, v) {
|
||||
if(data[v]) address.push(data[v]);
|
||||
});
|
||||
data.address = address.join(", ");
|
||||
|
||||
// prepare shipping tag
|
||||
if(data.is_shipping_address) {
|
||||
data.shipping = '<span class="label label-info">Shipping</span>';
|
||||
}
|
||||
|
||||
|
||||
// prepare description
|
||||
if(data.customer) {
|
||||
data.description = (data.customer_name || data.customer);
|
||||
data.contact_type = 'Customer';
|
||||
} else if (data.supplier) {
|
||||
data.description = (data.supplier_name || data.supplier);
|
||||
data.contact_type = 'Supplier';
|
||||
} else if (data.sales_partner) {
|
||||
data.description = data.sales_partner;
|
||||
data.contact_type = 'Sales Partner'
|
||||
} else {
|
||||
data.description = '';
|
||||
data.contact_type = '';
|
||||
}
|
||||
},
|
||||
|
||||
columns: [
|
||||
{width: '3%', content: 'check'},
|
||||
{width: '20%', content: 'name'},
|
||||
{width: '15%', content: 'contact_type'},
|
||||
{width: '20%', content: 'description'},
|
||||
{width: '30%', content: 'address+shipping+tags', css: {'padding': '2px 0px'}},
|
||||
{width: '12%', content: 'modified', css: {'text-align': 'right', 'color':'#777'}}
|
||||
]
|
||||
});
|
||||
1
utilities/doctype/answer/__init__.py
Normal file
1
utilities/doctype/answer/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from __future__ import unicode_literals
|
||||
102
utilities/doctype/answer/answer.txt
Normal file
102
utilities/doctype/answer/answer.txt
Normal file
@@ -0,0 +1,102 @@
|
||||
# DocType, Answer
|
||||
[
|
||||
|
||||
# These values are common in all dictionaries
|
||||
{
|
||||
'creation': '2012-03-27 14:36:01',
|
||||
'docstatus': 0,
|
||||
'modified': '2012-03-27 14:36:01',
|
||||
'modified_by': u'Administrator',
|
||||
'owner': u'Administrator'
|
||||
},
|
||||
|
||||
# These values are common for all DocType
|
||||
{
|
||||
'allow_attach': 0,
|
||||
'allow_trash': 1,
|
||||
'autoname': u'_ANS.#######',
|
||||
'colour': u'White:FFF',
|
||||
'doctype': 'DocType',
|
||||
'in_create': 1,
|
||||
'module': u'Utilities',
|
||||
'name': '__common__',
|
||||
'read_only': 1,
|
||||
'section_style': u'Simple',
|
||||
'server_code_error': u' ',
|
||||
'show_in_menu': 0,
|
||||
'version': 3
|
||||
},
|
||||
|
||||
# These values are common for all DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'name': '__common__',
|
||||
'parent': u'Answer',
|
||||
'parentfield': u'fields',
|
||||
'parenttype': u'DocType',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# These values are common for all DocPerm
|
||||
{
|
||||
'cancel': 1,
|
||||
'create': 1,
|
||||
'doctype': u'DocPerm',
|
||||
'name': '__common__',
|
||||
'parent': u'Answer',
|
||||
'parentfield': u'permissions',
|
||||
'parenttype': u'DocType',
|
||||
'permlevel': 0,
|
||||
'read': 1,
|
||||
'role': u'All',
|
||||
'write': 1
|
||||
},
|
||||
|
||||
# DocType, Answer
|
||||
{
|
||||
'doctype': 'DocType',
|
||||
'name': u'Answer'
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'doctype': u'DocPerm'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'question',
|
||||
'fieldtype': u'Link',
|
||||
'label': u'Question',
|
||||
'options': u'Question'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'answer',
|
||||
'fieldtype': u'Text',
|
||||
'label': u'Answer',
|
||||
'oldfieldname': u'question',
|
||||
'oldfieldtype': u'Text'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'points',
|
||||
'fieldtype': u'Int',
|
||||
'label': u'Points'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'_users_voted',
|
||||
'fieldtype': u'Text',
|
||||
'hidden': 1,
|
||||
'label': u'Users Voted',
|
||||
'print_hide': 1
|
||||
}
|
||||
]
|
||||
1
utilities/doctype/contact/__init__.py
Normal file
1
utilities/doctype/contact/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from __future__ import unicode_literals
|
||||
45
utilities/doctype/contact/contact.js
Normal file
45
utilities/doctype/contact/contact.js
Normal file
@@ -0,0 +1,45 @@
|
||||
// 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/>.
|
||||
|
||||
//--------- ONLOAD -------------
|
||||
cur_frm.cscript.onload = function(doc, cdt, cdn) {
|
||||
if(doc.customer) cur_frm.add_fetch('customer', 'customer_name', 'customer_name');
|
||||
if(doc.supplier) cur_frm.add_fetch('supplier', 'supplier_name', 'supplier_name');
|
||||
|
||||
var route = wn.get_route();
|
||||
if(route[1]=='Supplier') {
|
||||
var supplier = wn.container.page.frm.doc;
|
||||
doc.supplier = supplier.name;
|
||||
doc.supplier_name = supplier.supplier_name;
|
||||
} else if(route[1]=='Customer') {
|
||||
var customer = wn.container.page.frm.doc;
|
||||
doc.customer = customer.name;
|
||||
doc.customer_name = customer.customer_name;
|
||||
if(customer.customer_type == 'Individual') {
|
||||
doc.first_name = customer.customer_name;
|
||||
}
|
||||
} else if(route[1]=='Sales Partner') {
|
||||
var sp = wn.container.page.frm.doc;
|
||||
doc.sales_partner = sp.name;
|
||||
}
|
||||
}
|
||||
|
||||
cur_frm.cscript.hide_dialog = function() {
|
||||
if(cur_frm.contact_list)
|
||||
cur_frm.contact_list.run();
|
||||
}
|
||||
|
||||
|
||||
67
utilities/doctype/contact/contact.py
Normal file
67
utilities/doctype/contact/contact.py
Normal file
@@ -0,0 +1,67 @@
|
||||
# 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/>.
|
||||
|
||||
# Please edit this list and import only required elements
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
|
||||
from webnotes.model.doc import Document
|
||||
from webnotes import session, form, msgprint, errprint
|
||||
|
||||
# -----------------------------------------------------------------------------------------
|
||||
class DocType:
|
||||
def __init__(self, doc, doclist=[]):
|
||||
self.doc = doc
|
||||
self.doclist = doclist
|
||||
|
||||
def autoname(self):
|
||||
if self.doc.customer:
|
||||
self.doc.name = self.doc.first_name + (self.doc.last_name and ' ' + self.doc.last_name or '') + '-' + self.doc.customer
|
||||
elif self.doc.supplier:
|
||||
self.doc.name = self.doc.first_name + (self.doc.last_name and ' ' + self.doc.last_name or '') + '-' + self.doc.supplier
|
||||
elif self.doc.sales_partner:
|
||||
self.doc.name = self.doc.first_name + (self.doc.last_name and ' ' + self.doc.last_name or '') + '-' + self.doc.sales_partner
|
||||
else:
|
||||
self.doc.name = self.doc.first_name + (self.doc.last_name and ' ' + self.doc.last_name or '')
|
||||
|
||||
#----------------------
|
||||
# Call to Validate
|
||||
#----------------------
|
||||
def validate(self):
|
||||
self.validate_primary_contact()
|
||||
|
||||
#----------------------
|
||||
# Validate that there can only be one primary contact for particular customer, supplier
|
||||
#----------------------
|
||||
def validate_primary_contact(self):
|
||||
sql = webnotes.conn.sql
|
||||
if self.doc.is_primary_contact == 1:
|
||||
if self.doc.customer:
|
||||
sql("update tabContact set is_primary_contact=0 where customer = '%s'" % (self.doc.customer))
|
||||
elif self.doc.supplier:
|
||||
sql("update tabContact set is_primary_contact=0 where supplier = '%s'" % (self.doc.supplier))
|
||||
elif self.doc.sales_partner:
|
||||
sql("update tabContact set is_primary_contact=0 where sales_partner = '%s'" % (self.doc.sales_partner))
|
||||
else:
|
||||
if self.doc.customer:
|
||||
if not sql("select name from tabContact where is_primary_contact=1 and customer = '%s'" % (self.doc.customer)):
|
||||
self.doc.is_primary_contact = 1
|
||||
elif self.doc.supplier:
|
||||
if not sql("select name from tabContact where is_primary_contact=1 and supplier = '%s'" % (self.doc.supplier)):
|
||||
self.doc.is_primary_contact = 1
|
||||
elif self.doc.sales_partner:
|
||||
if not sql("select name from tabContact where is_primary_contact=1 and sales_partner = '%s'" % (self.doc.sales_partner)):
|
||||
self.doc.is_primary_contact = 1
|
||||
257
utilities/doctype/contact/contact.txt
Normal file
257
utilities/doctype/contact/contact.txt
Normal file
@@ -0,0 +1,257 @@
|
||||
# DocType, Contact
|
||||
[
|
||||
|
||||
# These values are common in all dictionaries
|
||||
{
|
||||
'creation': '2012-07-03 14:22:38',
|
||||
'docstatus': 0,
|
||||
'modified': '2012-08-02 13:16:48',
|
||||
'modified_by': u'Administrator',
|
||||
'owner': u'Administrator'
|
||||
},
|
||||
|
||||
# These values are common for all DocType
|
||||
{
|
||||
'_last_update': u'1327314958',
|
||||
'allow_trash': 1,
|
||||
'colour': u'White:FFF',
|
||||
'default_print_format': u'Standard',
|
||||
'doctype': 'DocType',
|
||||
'document_type': u'Master',
|
||||
'in_create': 0,
|
||||
'in_dialog': 1,
|
||||
'module': u'Utilities',
|
||||
'name': '__common__',
|
||||
'section_style': u'Simple',
|
||||
'server_code_error': u' ',
|
||||
'show_in_menu': 0,
|
||||
'subject': u'%(first_name)s %(last_name)s - Email: %(email_id)s | Contact: %(phone)s | Mobile: %(mobile_no)s',
|
||||
'version': 1
|
||||
},
|
||||
|
||||
# These values are common for all DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'name': '__common__',
|
||||
'parent': u'Contact',
|
||||
'parentfield': u'fields',
|
||||
'parenttype': u'DocType'
|
||||
},
|
||||
|
||||
# DocType, Contact
|
||||
{
|
||||
'doctype': 'DocType',
|
||||
'name': u'Contact'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'contact_details',
|
||||
'fieldtype': u'Section Break',
|
||||
'label': u'Contact Details',
|
||||
'oldfieldtype': u'Section Break',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# 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'first_name',
|
||||
'fieldtype': u'Data',
|
||||
'label': u'First Name',
|
||||
'oldfieldname': u'first_name',
|
||||
'oldfieldtype': u'Data',
|
||||
'permlevel': 0,
|
||||
'reqd': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'last_name',
|
||||
'fieldtype': u'Data',
|
||||
'label': u'Last Name',
|
||||
'oldfieldname': u'last_name',
|
||||
'oldfieldtype': u'Data',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'depends_on': u'eval:!doc.supplier && !doc.sales_partner',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'customer',
|
||||
'fieldtype': u'Link',
|
||||
'label': u'Customer',
|
||||
'oldfieldname': u'customer',
|
||||
'oldfieldtype': u'Link',
|
||||
'options': u'Customer',
|
||||
'permlevel': 0,
|
||||
'print_hide': 0,
|
||||
'trigger': u'Client'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'depends_on': u'eval:!doc.supplier && !doc.sales_partner',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'customer_name',
|
||||
'fieldtype': u'Data',
|
||||
'label': u'Customer Name',
|
||||
'permlevel': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'depends_on': u'eval:!doc.customer && !doc.sales_partner',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'supplier',
|
||||
'fieldtype': u'Link',
|
||||
'label': u'Supplier',
|
||||
'options': u'Supplier',
|
||||
'permlevel': 0,
|
||||
'trigger': u'Client'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'allow_on_submit': 0,
|
||||
'colour': u'White:FFF',
|
||||
'depends_on': u'eval:!doc.customer && !doc.sales_partner',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'supplier_name',
|
||||
'fieldtype': u'Data',
|
||||
'label': u'Supplier Name',
|
||||
'permlevel': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'depends_on': u'eval:!doc.customer && !doc.supplier',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'sales_partner',
|
||||
'fieldtype': u'Link',
|
||||
'label': u'Sales Partner',
|
||||
'options': u'Sales Partner',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'default': u'0',
|
||||
'depends_on': u'eval:(doc.customer || doc.supplier || doc.sales_partner)',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'is_primary_contact',
|
||||
'fieldtype': u'Check',
|
||||
'label': u'Is Primary Contact',
|
||||
'oldfieldname': u'is_primary_contact',
|
||||
'oldfieldtype': u'Select',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'column_break1',
|
||||
'fieldtype': u'Column Break',
|
||||
'oldfieldtype': u'Column Break',
|
||||
'permlevel': 0,
|
||||
'width': u'50%'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'email_id',
|
||||
'fieldtype': u'Data',
|
||||
'label': u'Email Id',
|
||||
'oldfieldname': u'email_id',
|
||||
'oldfieldtype': u'Data',
|
||||
'permlevel': 0,
|
||||
'reqd': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'phone',
|
||||
'fieldtype': u'Data',
|
||||
'label': u'Phone',
|
||||
'oldfieldname': u'contact_no',
|
||||
'oldfieldtype': u'Data',
|
||||
'permlevel': 0,
|
||||
'reqd': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'mobile_no',
|
||||
'fieldtype': u'Data',
|
||||
'label': u'Mobile No',
|
||||
'oldfieldname': u'mobile_no',
|
||||
'oldfieldtype': u'Data',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'description': u'Enter department to which this Contact belongs',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'department',
|
||||
'fieldtype': u'Data',
|
||||
'label': u'Department',
|
||||
'options': u'Suggest',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'description': u'Enter designation of this Contact',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'designation',
|
||||
'fieldtype': u'Data',
|
||||
'label': u'Designation',
|
||||
'options': u'Suggest',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'unsubscribed',
|
||||
'fieldtype': u'Check',
|
||||
'label': u'Unsubscribed',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'trash_reason',
|
||||
'fieldtype': u'Small Text',
|
||||
'label': u'Trash Reason',
|
||||
'oldfieldname': u'trash_reason',
|
||||
'oldfieldtype': u'Small Text',
|
||||
'permlevel': 1
|
||||
}
|
||||
]
|
||||
50
utilities/doctype/contact/contact_list.js
Normal file
50
utilities/doctype/contact/contact_list.js
Normal file
@@ -0,0 +1,50 @@
|
||||
wn.doclistviews['Contact'] = wn.views.ListView.extend({
|
||||
init: function(d) {
|
||||
this._super(d)
|
||||
this.fields = this.fields.concat([
|
||||
"`tabContact`.first_name",
|
||||
"`tabContact`.last_name",
|
||||
"`tabContact`.customer",
|
||||
"`tabContact`.customer_name",
|
||||
"`tabContact`.supplier",
|
||||
"`tabContact`.supplier_name",
|
||||
"`tabContact`.sales_partner",
|
||||
"`tabContact`.email_id",
|
||||
]);
|
||||
},
|
||||
|
||||
prepare_data: function(data) {
|
||||
this._super(data);
|
||||
|
||||
// prepare fullname
|
||||
data.fullname = (data.first_name || '') +
|
||||
(data.last_name ? ' ' + data.last_name : '');
|
||||
if(!data.fullname) data.fullname = data.name;
|
||||
data.fullname = repl("<a href='#!Form/Contact/%(name)s'>%(fullname)s\
|
||||
</a>", data);
|
||||
|
||||
// prepare description
|
||||
if(data.customer) {
|
||||
data.description = (data.customer_name || data.customer);
|
||||
data.contact_type = 'Customer';
|
||||
} else if (data.supplier) {
|
||||
data.description = (data.supplier_name || data.supplier);
|
||||
data.contact_type = 'Supplier';
|
||||
} else if (data.sales_partner) {
|
||||
data.description = data.sales_partner;
|
||||
data.contact_type = 'Sales Partner'
|
||||
} else {
|
||||
data.description = '';
|
||||
data.contact_type = '';
|
||||
}
|
||||
},
|
||||
|
||||
columns: [
|
||||
{width: '3%', content: 'check'},
|
||||
{width: '20%', content: 'fullname'},
|
||||
{width: '15%', content: 'contact_type'},
|
||||
{width: '20%', content: 'description+tags'},
|
||||
{width: '30%', content: 'email_id'},
|
||||
{width: '12%', content:'modified', css: {'text-align': 'right', 'color':'#777'}}
|
||||
]
|
||||
});
|
||||
1
utilities/doctype/gl_mapper/__init__.py
Normal file
1
utilities/doctype/gl_mapper/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from __future__ import unicode_literals
|
||||
93
utilities/doctype/gl_mapper/gl_mapper.txt
Normal file
93
utilities/doctype/gl_mapper/gl_mapper.txt
Normal file
@@ -0,0 +1,93 @@
|
||||
# DocType, GL Mapper
|
||||
[
|
||||
|
||||
# These values are common in all dictionaries
|
||||
{
|
||||
'creation': '2012-04-13 11:56:40',
|
||||
'docstatus': 0,
|
||||
'modified': '2012-04-23 12:27:38',
|
||||
'modified_by': u'Administrator',
|
||||
'owner': u'Administrator'
|
||||
},
|
||||
|
||||
# These values are common for all DocType
|
||||
{
|
||||
'_last_update': u'1305006361',
|
||||
'autoname': u'field:doc_type',
|
||||
'colour': u'White:FFF',
|
||||
'doctype': 'DocType',
|
||||
'module': u'Utilities',
|
||||
'name': '__common__',
|
||||
'section_style': u'Simple',
|
||||
'server_code_error': u' ',
|
||||
'show_in_menu': 0,
|
||||
'version': 1
|
||||
},
|
||||
|
||||
# These values are common for all DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'name': '__common__',
|
||||
'parent': u'GL Mapper',
|
||||
'parentfield': u'fields',
|
||||
'parenttype': u'DocType',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# These values are common for all DocPerm
|
||||
{
|
||||
'create': 0,
|
||||
'doctype': u'DocPerm',
|
||||
'name': '__common__',
|
||||
'parent': u'GL Mapper',
|
||||
'parentfield': u'permissions',
|
||||
'parenttype': u'DocType',
|
||||
'permlevel': 0,
|
||||
'read': 1
|
||||
},
|
||||
|
||||
# DocType, GL Mapper
|
||||
{
|
||||
'doctype': 'DocType',
|
||||
'name': u'GL Mapper'
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'amend': 0,
|
||||
'cancel': 0,
|
||||
'doctype': u'DocPerm',
|
||||
'role': u'Accounts User',
|
||||
'submit': 0,
|
||||
'write': 0
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'doctype': u'DocPerm',
|
||||
'role': u'System Manager',
|
||||
'write': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'doc_type',
|
||||
'fieldtype': u'Data',
|
||||
'label': u'Doc Type',
|
||||
'oldfieldname': u'doc_type',
|
||||
'oldfieldtype': u'Link',
|
||||
'reqd': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'fields',
|
||||
'fieldtype': u'Table',
|
||||
'label': u'Fields',
|
||||
'oldfieldname': u'fields',
|
||||
'oldfieldtype': u'Table',
|
||||
'options': u'GL Mapper Detail'
|
||||
}
|
||||
]
|
||||
1
utilities/doctype/gl_mapper_detail/__init__.py
Normal file
1
utilities/doctype/gl_mapper_detail/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from __future__ import unicode_literals
|
||||
208
utilities/doctype/gl_mapper_detail/gl_mapper_detail.txt
Normal file
208
utilities/doctype/gl_mapper_detail/gl_mapper_detail.txt
Normal file
@@ -0,0 +1,208 @@
|
||||
# DocType, GL Mapper Detail
|
||||
[
|
||||
|
||||
# These values are common in all dictionaries
|
||||
{
|
||||
'creation': '2012-03-27 14:36:46',
|
||||
'docstatus': 0,
|
||||
'modified': '2012-03-27 14:36:46',
|
||||
'modified_by': u'Administrator',
|
||||
'owner': u'Administrator'
|
||||
},
|
||||
|
||||
# These values are common for all DocType
|
||||
{
|
||||
'autoname': u'GLMDetail.#####',
|
||||
'colour': u'White:FFF',
|
||||
'default_print_format': u'Standard',
|
||||
'doctype': 'DocType',
|
||||
'istable': 1,
|
||||
'module': u'Utilities',
|
||||
'name': '__common__',
|
||||
'section_style': u'Tray',
|
||||
'server_code_error': u' ',
|
||||
'show_in_menu': 0,
|
||||
'version': 4
|
||||
},
|
||||
|
||||
# These values are common for all DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldtype': u'Data',
|
||||
'name': '__common__',
|
||||
'oldfieldtype': u'Data',
|
||||
'parent': u'GL Mapper Detail',
|
||||
'parentfield': u'fields',
|
||||
'parenttype': u'DocType',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# DocType, GL Mapper Detail
|
||||
{
|
||||
'doctype': 'DocType',
|
||||
'name': u'GL Mapper Detail'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'table_field',
|
||||
'label': u'Table Field',
|
||||
'oldfieldname': u'table_field'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'account',
|
||||
'label': u'Account',
|
||||
'oldfieldname': u'account',
|
||||
'reqd': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'debit',
|
||||
'label': u'Debit',
|
||||
'oldfieldname': u'debit',
|
||||
'reqd': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'credit',
|
||||
'label': u'Credit',
|
||||
'oldfieldname': u'credit',
|
||||
'reqd': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'cost_center',
|
||||
'label': u'Cost Center',
|
||||
'oldfieldname': u'cost_center',
|
||||
'reqd': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'against',
|
||||
'label': u'Against',
|
||||
'oldfieldname': u'against',
|
||||
'reqd': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'remarks',
|
||||
'label': u'Remarks',
|
||||
'no_copy': 1,
|
||||
'oldfieldname': u'remarks',
|
||||
'reqd': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'voucher_type',
|
||||
'label': u'Voucher Type',
|
||||
'oldfieldname': u'voucher_type',
|
||||
'reqd': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'voucher_no',
|
||||
'label': u'Voucher No',
|
||||
'oldfieldname': u'voucher_no',
|
||||
'reqd': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'description': u'The date at which current entry will get or has actually executed.',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'posting_date',
|
||||
'label': u'Posting Date',
|
||||
'oldfieldname': u'posting_date',
|
||||
'reqd': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'description': u'The date at which current entry is made in system.',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'transaction_date',
|
||||
'label': u'Transaction Date',
|
||||
'oldfieldname': u'transaction_date',
|
||||
'reqd': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'aging_date',
|
||||
'label': u'Aging Date',
|
||||
'oldfieldname': u'aging_date',
|
||||
'reqd': 1
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'fiscal_year',
|
||||
'in_filter': 1,
|
||||
'label': u'Fiscal Year',
|
||||
'oldfieldname': u'fiscal_year',
|
||||
'reqd': 1,
|
||||
'search_index': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'against_voucher',
|
||||
'label': u'Against Voucher',
|
||||
'oldfieldname': u'against_voucher'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'against_voucher_type',
|
||||
'label': u'Against Voucher Type',
|
||||
'oldfieldname': u'against_voucher_type'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'company',
|
||||
'in_filter': 1,
|
||||
'label': u'Company',
|
||||
'oldfieldname': u'company',
|
||||
'search_index': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'is_opening',
|
||||
'label': u'Is Opening',
|
||||
'oldfieldname': u'is_opening'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'is_advance',
|
||||
'label': u'Is Advance',
|
||||
'oldfieldname': u'is_advance'
|
||||
}
|
||||
]
|
||||
1
utilities/doctype/profile_control/__init__.py
Normal file
1
utilities/doctype/profile_control/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from __future__ import unicode_literals
|
||||
75
utilities/doctype/profile_control/profile_control.py
Normal file
75
utilities/doctype/profile_control/profile_control.py
Normal file
@@ -0,0 +1,75 @@
|
||||
# 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/>.
|
||||
|
||||
# Please edit this list and import only required elements
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
|
||||
from webnotes.utils import add_days, add_months, add_years, cint, cstr, date_diff, default_fields, flt, fmt_money, formatdate, generate_hash, getTraceback, get_defaults, get_first_day, get_last_day, getdate, has_common, month_name, now, nowdate, replace_newlines, sendmail, set_default, str_esc_quote, user_format, validate_email_add
|
||||
from webnotes.model import db_exists
|
||||
from webnotes.model.doc import Document, addchild, getchildren, make_autoname
|
||||
from webnotes.model.doclist import getlist, copy_doclist
|
||||
from webnotes.model.code import get_obj, get_server_obj, run_server_obj, updatedb, check_syntax
|
||||
from webnotes import session, form, is_testing, msgprint, errprint
|
||||
|
||||
set = webnotes.conn.set
|
||||
sql = webnotes.conn.sql
|
||||
get_value = webnotes.conn.get_value
|
||||
in_transaction = webnotes.conn.in_transaction
|
||||
convert_to_lists = webnotes.conn.convert_to_lists
|
||||
|
||||
# -----------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
class DocType:
|
||||
def __init__(self,d,dl):
|
||||
self.doc, self.doclist = d,dl
|
||||
self.last_profile = None
|
||||
|
||||
def get_role_permission(self,role):
|
||||
perm = sql("select distinct t1.`parent`, t1.`read`, t1.`write`, t1.`create`, t1.`submit`,t1.`cancel`,t1.`amend` from `tabDocPerm` t1, `tabDocType` t2 where t1.`role` ='%s' and t1.docstatus !=2 and t1.permlevel = 0 and t1.`read` = 1 and t2.module != 'Recycle Bin' and t1.parent=t2.name "%role)
|
||||
return perm or ''
|
||||
|
||||
#------------return role list -------------------------------------------------------------------------------------------------
|
||||
# All roles of Role Master
|
||||
def get_role(self):
|
||||
r_list=sql("select name from `tabRole` where name not in ('Administrator','All','Guest')")
|
||||
if r_list[0][0]:
|
||||
r_list = [x[0] for x in r_list]
|
||||
return r_list
|
||||
|
||||
# Only user specific role
|
||||
def get_user_role(self,usr):
|
||||
r_list=sql("select role from `tabUserRole` where parent=%s and role not in ('Administrator','All','Guest')",usr)
|
||||
if r_list[0][0]:
|
||||
r_list = [x[0] for x in r_list]
|
||||
else:
|
||||
r_list=[]
|
||||
return r_list
|
||||
|
||||
# adding new role
|
||||
def add_user_role(self,args):
|
||||
arg=eval(args)
|
||||
sql("delete from `tabUserRole` where parenttype='Profile' and parent ='%s'" % (cstr(arg['user'])))
|
||||
role_list = arg['role_list'].split(',')
|
||||
for r in role_list:
|
||||
pr=Document('UserRole')
|
||||
pr.parent = arg['user']
|
||||
pr.parenttype = 'Profile'
|
||||
pr.role = r
|
||||
pr.parentfield = 'userroles'
|
||||
pr.save(1)
|
||||
|
||||
31
utilities/doctype/profile_control/profile_control.txt
Normal file
31
utilities/doctype/profile_control/profile_control.txt
Normal file
@@ -0,0 +1,31 @@
|
||||
# DocType, Profile Control
|
||||
[
|
||||
|
||||
# These values are common in all dictionaries
|
||||
{
|
||||
'creation': '2012-03-27 14:36:47',
|
||||
'docstatus': 0,
|
||||
'modified': '2012-03-27 14:36:47',
|
||||
'modified_by': u'Administrator',
|
||||
'owner': u'Administrator'
|
||||
},
|
||||
|
||||
# These values are common for all DocType
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'doctype': 'DocType',
|
||||
'issingle': 1,
|
||||
'module': u'Utilities',
|
||||
'name': '__common__',
|
||||
'section_style': u'Simple',
|
||||
'server_code_error': u' ',
|
||||
'show_in_menu': 0,
|
||||
'version': 12
|
||||
},
|
||||
|
||||
# DocType, Profile Control
|
||||
{
|
||||
'doctype': 'DocType',
|
||||
'name': u'Profile Control'
|
||||
}
|
||||
]
|
||||
1
utilities/doctype/question/__init__.py
Normal file
1
utilities/doctype/question/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from __future__ import unicode_literals
|
||||
25
utilities/doctype/question/question.py
Normal file
25
utilities/doctype/question/question.py
Normal file
@@ -0,0 +1,25 @@
|
||||
# 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
|
||||
class DocType:
|
||||
def __init__(self, d, dl):
|
||||
self.doc, self.doclist = d, dl
|
||||
|
||||
def on_trash(self):
|
||||
import webnotes
|
||||
webnotes.conn.sql("delete from tabAnswer where question=%s", self.doc.name)
|
||||
|
||||
158
utilities/doctype/question/question.txt
Normal file
158
utilities/doctype/question/question.txt
Normal file
@@ -0,0 +1,158 @@
|
||||
# DocType, Question
|
||||
[
|
||||
|
||||
# These values are common in all dictionaries
|
||||
{
|
||||
'creation': '2012-03-27 14:36:01',
|
||||
'docstatus': 0,
|
||||
'modified': '2012-03-27 14:36:01',
|
||||
'modified_by': u'Administrator',
|
||||
'owner': u'Administrator'
|
||||
},
|
||||
|
||||
# These values are common for all DocType
|
||||
{
|
||||
'allow_attach': 0,
|
||||
'allow_trash': 1,
|
||||
'autoname': u'QUES.#######',
|
||||
'colour': u'White:FFF',
|
||||
'doctype': 'DocType',
|
||||
'in_create': 1,
|
||||
'module': u'Utilities',
|
||||
'name': '__common__',
|
||||
'read_only': 1,
|
||||
'section_style': u'Simple',
|
||||
'server_code_error': u' ',
|
||||
'show_in_menu': 0,
|
||||
'version': 7
|
||||
},
|
||||
|
||||
# These values are common for all DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'name': '__common__',
|
||||
'parent': u'Question',
|
||||
'parentfield': u'fields',
|
||||
'parenttype': u'DocType',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# These values are common for all DocPerm
|
||||
{
|
||||
'cancel': 1,
|
||||
'create': 1,
|
||||
'doctype': u'DocPerm',
|
||||
'name': '__common__',
|
||||
'parent': u'Question',
|
||||
'parentfield': u'permissions',
|
||||
'parenttype': u'DocType',
|
||||
'permlevel': 0,
|
||||
'read': 1,
|
||||
'role': u'All',
|
||||
'write': 1
|
||||
},
|
||||
|
||||
# DocType, Question
|
||||
{
|
||||
'doctype': 'DocType',
|
||||
'name': u'Question'
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'doctype': u'DocPerm'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'question',
|
||||
'fieldtype': u'Text',
|
||||
'label': u'Question',
|
||||
'oldfieldname': u'question',
|
||||
'oldfieldtype': u'Text'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'points',
|
||||
'fieldtype': u'Int',
|
||||
'hidden': 1,
|
||||
'label': u'Points'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'answer',
|
||||
'fieldtype': u'Text Editor',
|
||||
'label': u'Answer',
|
||||
'oldfieldname': u'answer',
|
||||
'oldfieldtype': u'Text Editor'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'_user_tags',
|
||||
'fieldtype': u'Data',
|
||||
'hidden': 1,
|
||||
'label': u'User Tags'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'tag_1',
|
||||
'fieldtype': u'Link',
|
||||
'label': u'Tag 1',
|
||||
'oldfieldname': u'tag_1',
|
||||
'oldfieldtype': u'Link',
|
||||
'options': u'Question Tag',
|
||||
'search_index': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'_users_voted',
|
||||
'fieldtype': u'Text',
|
||||
'label': u'Users Voted'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'tag_2',
|
||||
'fieldtype': u'Link',
|
||||
'label': u'Tag 2',
|
||||
'oldfieldname': u'tag_2',
|
||||
'oldfieldtype': u'Link',
|
||||
'options': u'Question Tag',
|
||||
'search_index': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'tag_3',
|
||||
'fieldtype': u'Link',
|
||||
'label': u'Tag 3',
|
||||
'oldfieldname': u'tag_3',
|
||||
'oldfieldtype': u'Link',
|
||||
'options': u'Question Tag',
|
||||
'search_index': 0
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'file_list',
|
||||
'fieldtype': u'Text',
|
||||
'hidden': 1,
|
||||
'label': u'File List',
|
||||
'oldfieldname': u'file_list',
|
||||
'oldfieldtype': u'Text'
|
||||
}
|
||||
]
|
||||
1
utilities/doctype/rename_tool/__init__.py
Executable file
1
utilities/doctype/rename_tool/__init__.py
Executable file
@@ -0,0 +1 @@
|
||||
from __future__ import unicode_literals
|
||||
21
utilities/doctype/rename_tool/rename_tool.js
Normal file
21
utilities/doctype/rename_tool/rename_tool.js
Normal file
@@ -0,0 +1,21 @@
|
||||
// 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/>.
|
||||
|
||||
// over-ride the link query to return relevant link names
|
||||
|
||||
cur_frm.fields_dict.document_to_rename.get_query = function(doc, dt, dn) {
|
||||
return "SELECT name FROM `tab"+doc.select_doctype+"` WHERE docstatus<2 AND name LIKE '%s' LIMIT 50";
|
||||
}
|
||||
37
utilities/doctype/rename_tool/rename_tool.py
Normal file
37
utilities/doctype/rename_tool/rename_tool.py
Normal file
@@ -0,0 +1,37 @@
|
||||
# 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
|
||||
class DocType:
|
||||
def __init__(self, d, dl=[]):
|
||||
self.doc, self.doclist = d, dl
|
||||
|
||||
def rename(self):
|
||||
"""
|
||||
Generate update quereies for rename
|
||||
"""
|
||||
import webnotes.model
|
||||
from webnotes.model.code import get_obj
|
||||
|
||||
# call on_rename method if exists
|
||||
obj = get_obj(self.doc.select_doctype, self.doc.document_to_rename)
|
||||
if hasattr(obj, 'on_rename'):
|
||||
obj.on_rename(self.doc.new_name,self.doc.document_to_rename)
|
||||
|
||||
# rename the document
|
||||
webnotes.model.rename(self.doc.select_doctype, self.doc.document_to_rename, self.doc.new_name)
|
||||
|
||||
webnotes.msgprint("Successfully renamed "+self.doc.select_doctype+" : '"+self.doc.document_to_rename+"' to <b>"+self.doc.new_name+"</b>")
|
||||
98
utilities/doctype/rename_tool/rename_tool.txt
Executable file
98
utilities/doctype/rename_tool/rename_tool.txt
Executable file
@@ -0,0 +1,98 @@
|
||||
# DocType, Rename Tool
|
||||
[
|
||||
|
||||
# These values are common in all dictionaries
|
||||
{
|
||||
'creation': '2012-05-03 18:43:31',
|
||||
'docstatus': 0,
|
||||
'modified': '2012-05-25 11:58:44',
|
||||
'modified_by': u'Administrator',
|
||||
'owner': u'Administrator'
|
||||
},
|
||||
|
||||
# These values are common for all DocType
|
||||
{
|
||||
'_last_update': u'1308739509',
|
||||
'allow_email': 1,
|
||||
'allow_print': 1,
|
||||
'colour': u'White:FFF',
|
||||
'doctype': 'DocType',
|
||||
'hide_heading': 0,
|
||||
'hide_toolbar': 0,
|
||||
'issingle': 1,
|
||||
'module': u'Utilities',
|
||||
'name': '__common__',
|
||||
'section_style': u'Simple',
|
||||
'show_in_menu': 0,
|
||||
'version': 1
|
||||
},
|
||||
|
||||
# These values are common for all DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'name': '__common__',
|
||||
'parent': u'Rename Tool',
|
||||
'parentfield': u'fields',
|
||||
'parenttype': u'DocType',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# These values are common for all DocPerm
|
||||
{
|
||||
'create': 1,
|
||||
'doctype': u'DocPerm',
|
||||
'name': '__common__',
|
||||
'parent': u'Rename Tool',
|
||||
'parentfield': u'permissions',
|
||||
'parenttype': u'DocType',
|
||||
'permlevel': 0,
|
||||
'read': 1,
|
||||
'role': u'System Manager',
|
||||
'write': 1
|
||||
},
|
||||
|
||||
# DocType, Rename Tool
|
||||
{
|
||||
'doctype': 'DocType',
|
||||
'name': u'Rename Tool'
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'doctype': u'DocPerm'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'select_doctype',
|
||||
'fieldtype': u'Select',
|
||||
'label': u'Select DocType',
|
||||
'options': u'\nAccount\nCompany\nCustomer\nSupplier\nEmployee\nWarehouse\nItem\nProfile'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'document_to_rename',
|
||||
'fieldtype': u'Link',
|
||||
'label': u'Document to rename'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'new_name',
|
||||
'fieldtype': u'Data',
|
||||
'label': u'New Name'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'rename',
|
||||
'fieldtype': u'Button',
|
||||
'label': u'Rename',
|
||||
'options': u'rename'
|
||||
}
|
||||
]
|
||||
1
utilities/doctype/reposting_tool/__init__.py
Normal file
1
utilities/doctype/reposting_tool/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from __future__ import unicode_literals
|
||||
79
utilities/doctype/reposting_tool/reposting_tool.js
Normal file
79
utilities/doctype/reposting_tool/reposting_tool.js
Normal file
@@ -0,0 +1,79 @@
|
||||
// ERPNext - web based ERP (http://erpnext.com)
|
||||
// Copyright (C) 2012 Web Notes Technologies Pvt Ltd
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
var bin_list = [];
|
||||
var msg = [];
|
||||
var binidx = 0;
|
||||
|
||||
cur_frm.cscript.repost_bin = function(doc,cdt,cdn) {
|
||||
args = {'check': 'Bin'};
|
||||
$c_obj('Reposting Tool','get_count_for_reposting', docstring(args), function(r,rt) {
|
||||
bin_list = r.message;
|
||||
repair_bin();
|
||||
});
|
||||
}
|
||||
|
||||
function repair_single_bin(){
|
||||
$c_obj('Reposting Tool', 'repair_bin', cstr(bin_list[binidx]), function(r,rt) {
|
||||
for(i = 0; i < r.message.length ; i++){
|
||||
msg.push(r.message[i]);
|
||||
}
|
||||
repair_bin();
|
||||
});
|
||||
}
|
||||
|
||||
function repair_bin(){
|
||||
if(binidx >= 10) {
|
||||
args = {'msg': msg, 'subject': 'Item Quantity'};
|
||||
$c_obj('Reposting Tool', 'send_mail', docstring(args));
|
||||
alert('Completed');
|
||||
return;
|
||||
}
|
||||
repair_single_bin();
|
||||
binidx ++;
|
||||
}
|
||||
|
||||
// Batch for Account Balances
|
||||
//======================================================
|
||||
var acc_list = [];
|
||||
var accidx = 0;
|
||||
cur_frm.cscript.repost_account_balances = function(doc,cdt,cdn) {
|
||||
args = {'check': 'Account Balance'};
|
||||
$c_obj('Reposting Tool','get_count_for_reposting', docstring(args), function(r,rt) {
|
||||
acc_list = r.message;
|
||||
repair_acc_bal();
|
||||
});
|
||||
}
|
||||
|
||||
function repair_single_acc_bal(){
|
||||
$c_obj('Reposting Tool', 'repair_acc_bal', cstr(acc_list[accidx]), function(r,rt) {
|
||||
for(i = 0; i < r.message.length; i++){
|
||||
msg.push(r.message[i]);
|
||||
}
|
||||
repair_acc_bal();
|
||||
});
|
||||
}
|
||||
|
||||
function repair_acc_bal(){
|
||||
if(accidx >= 15) {
|
||||
args = {'msg' : msg, 'subject': 'Account Balance'};
|
||||
$c_obj('Reposting Tool', 'send_mail', docstring(args));
|
||||
alert('Completed');
|
||||
return;
|
||||
}
|
||||
repair_single_acc_bal();
|
||||
accidx ++;
|
||||
}
|
||||
211
utilities/doctype/reposting_tool/reposting_tool.py
Normal file
211
utilities/doctype/reposting_tool/reposting_tool.py
Normal file
@@ -0,0 +1,211 @@
|
||||
# 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/>.
|
||||
|
||||
# Please edit this list and import only required elements
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
|
||||
from webnotes.utils import add_days, add_months, add_years, cint, cstr, date_diff, default_fields, flt, fmt_money, formatdate, generate_hash, getTraceback, get_defaults, get_first_day, get_last_day, getdate, has_common, month_name, now, nowdate, replace_newlines, sendmail, set_default, str_esc_quote, user_format, validate_email_add
|
||||
from webnotes.model import db_exists
|
||||
from webnotes.model.doc import Document, addchild, getchildren, make_autoname
|
||||
from webnotes.model.doclist import getlist, copy_doclist
|
||||
from webnotes.model.code import get_obj, get_server_obj, run_server_obj, updatedb, check_syntax
|
||||
from webnotes import session, form, is_testing, msgprint, errprint
|
||||
|
||||
set = webnotes.conn.set
|
||||
sql = webnotes.conn.sql
|
||||
get_value = webnotes.conn.get_value
|
||||
in_transaction = webnotes.conn.in_transaction
|
||||
convert_to_lists = webnotes.conn.convert_to_lists
|
||||
|
||||
# -----------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
class DocType:
|
||||
def __init__(self, doc, doclist=[]):
|
||||
self.doc = doc
|
||||
self.doclist = doclist
|
||||
self.msg = []
|
||||
|
||||
|
||||
# =============================================================================
|
||||
def get_count_for_reposting(self, args):
|
||||
args = eval(args)
|
||||
if args['check'] == 'Bin':
|
||||
return [d[0] for d in sql("select name from `tabBin` where item_code = 'Repost Item' " )]
|
||||
|
||||
if args['check'] == 'Account Balance':
|
||||
# message
|
||||
if not self.doc.past_year:
|
||||
msgprint('<div style="color: ORANGE"> Warning: Opening balances were not imported </div>')
|
||||
|
||||
# do not repost from same year
|
||||
if self.doc.past_year == self.doc.name:
|
||||
msgprint("Cannot import from the current year")
|
||||
|
||||
return [d[0] for d in sql("select name from `tabAccount` ")]
|
||||
|
||||
# =============================================================================
|
||||
def get_bin_qty(self, wh, item):
|
||||
# get actual_qty
|
||||
act_qty = sql("select sum(actual_qty) from `tabStock Ledger Entry` where warehouse = '%s' and item_code = '%s' and ifnull(is_cancelled, 'No') = 'No'" % (wh, item))
|
||||
act_qty = act_qty and flt(act_qty[0][0]) or 0
|
||||
|
||||
# get indented_qty
|
||||
ind_qty = sql("select sum(if( ifnull(t2.qty, 0) > ifnull(t2.ordered_qty, 0), ifnull(t2.qty, 0) - ifnull(t2.ordered_qty, 0), 0) ) from `tabPurchase Request` t1, `tabPurchase Request Item`t2 where t1.name = t2.parent and t1.docstatus = 1 and t2.warehouse = '%s' and t2.item_code = '%s' and status != 'Stopped'" % (wh, item))
|
||||
ind_qty = ind_qty and flt(ind_qty[0][0]) or 0
|
||||
|
||||
# get ordered_qty
|
||||
ord_qty = sql("select sum(if ( ifnull(t2.qty, 0) > ifnull(t2.received_qty, 0), (ifnull(t2.qty, 0) - ifnull(t2.received_qty, 0)) * ifnull(t2.conversion_factor, 0) , 0) ) from `tabPurchase Order` t1, `tabPurchase Order Item` t2 where t1.name = t2.parent and t1.docstatus = 1 and t2.warehouse = '%s' and t2.item_code = '%s' and status != 'Stopped'" % (wh, item))
|
||||
ord_qty = ord_qty and flt(ord_qty[0][0]) or 0
|
||||
|
||||
|
||||
# get reserved_qty
|
||||
res_qty =sql("select sum(if ( ifnull(t2.qty, 0) > ifnull(t2.delivered_qty, 0), ifnull(t2.qty, 0) - ifnull(t2.delivered_qty, 0) , 0) ) from `tabSales Order` t1, `tabSales Order Item` t2 where t1.name = t2.parent and t1.docstatus = 1 and t2.reserved_warehouse = '%s' and t2.item_code = '%s' and status != 'Stopped'" % (wh, item))
|
||||
res_qty = res_qty and flt(res_qty[0][0]) or 0
|
||||
|
||||
# get planned_qty
|
||||
plan_qty = sql("select sum(if ( ifnull(qty, 0) > ifnull(produced_qty,0), ifnull(qty, 0) - ifnull(produced_qty, 0), 0) ) from `tabProduction Order` where fg_warehouse = '%s' and production_item = '%s' and docstatus = 1" % (wh, item))
|
||||
plan_qty = plan_qty and flt(plan_qty[0][0]) or 0
|
||||
|
||||
return {'actual_qty': act_qty, 'indented_qty': ind_qty, 'ordered_qty': ord_qty, 'reserved_qty': res_qty, 'planned_qty': plan_qty }
|
||||
|
||||
# =============================================================================
|
||||
def check_bin_qty(self, bin_obj, qty_dict):
|
||||
label_dict = {'actual_qty': 'Actual Qty', 'indented_qty': 'Quantity Requested for Purchase', 'ordered_qty': 'Ordered Qty', 'reserved_qty': 'Reserved Qty', 'planned_qty': 'Planned Qty'}
|
||||
for f in qty_dict:
|
||||
if flt(bin_obj.doc.fields[f]) != qty_dict[f]:
|
||||
msgprint('<div style="color: RED"> Difference found in %s for Item:= %s and Warehouse:= %s (Before : %s; After : %s)</div>' % (label_dict[f], bin_obj.doc.item_code, bin_obj.doc.warehouse, cstr(bin_obj.doc.fields[f]), cstr(qty_dict[f])))
|
||||
self.msg.append('<div style="color: RED"> Difference found in %s for Item:= %s and Warehouse:= %s (Before : %s; After : %s)</div>' % (label_dict[f], bin_obj.doc.item_code, bin_obj.doc.warehouse, cstr(bin_obj.doc.fields[f]), cstr(qty_dict[f])))
|
||||
|
||||
# Check projected qty
|
||||
projected_qty = flt(qty_dict['actual_qty']) + flt(qty_dict['indented_qty']) + flt(qty_dict['ordered_qty']) + flt(qty_dict['planned_qty']) - flt(qty_dict['reserved_qty'])
|
||||
if flt(projected_qty) != flt(bin_obj.doc.projected_qty):
|
||||
msgprint('<div style="color: RED">Difference found in Projected Qty for Item:= %s and Warehouse:= %s (Before : %s; After : %s)</div>' % (bin_obj.doc.item_code, bin_obj.doc.warehouse, bin_obj.doc.projected_qty, cstr(projected_qty)))
|
||||
self.msg.append('<div style="color: RED">Difference found in Projected Qty for Item:= %s and Warehouse:= %s (Before : %s; After : %s)</div>' % (bin_obj.doc.item_code, bin_obj.doc.warehouse, bin_obj.doc.projected_qty, cstr(projected_qty)))
|
||||
|
||||
|
||||
# =============================================================================
|
||||
def repair_bin(self, bin):
|
||||
import webnotes
|
||||
bin_obj = get_obj('Bin',bin)
|
||||
bin_act_qty = flt(bin_obj.doc.actual_qty)
|
||||
try:
|
||||
# udpate actual qty and item valuation
|
||||
bin_obj.update_entries_after('0000-00-00', '00:00')
|
||||
# get bin qty
|
||||
qty_dict = self.get_bin_qty(bin_obj.doc.warehouse, bin_obj.doc.item_code)
|
||||
|
||||
# check bin qty
|
||||
self.check_bin_qty(bin_obj, qty_dict)
|
||||
|
||||
projected_qty = flt(qty_dict['indented_qty']) + flt(qty_dict['ordered_qty']) - flt(qty_dict['reserved_qty']) + flt(qty_dict['planned_qty']) + flt(qty_dict['actual_qty'])
|
||||
# update indented_qty, ordered_qty, reserved_qty, planned_qty
|
||||
sql("update `tabBin` set indented_qty = '%s', ordered_qty = '%s', reserved_qty = '%s', planned_qty = '%s', projected_qty = '%s' where warehouse = '%s' and item_code = '%s'" % ( flt(qty_dict['indented_qty']), flt(qty_dict['ordered_qty']), flt(qty_dict['reserved_qty']), flt(qty_dict['planned_qty']), projected_qty, bin_obj.doc.warehouse, bin_obj.doc.item_code))
|
||||
|
||||
# update projected_qty
|
||||
sql("update `tabBin` set projected_qty = ifnull(indented_qty, 0) + ifnull(ordered_qty,0) + ifnull(actual_qty, 0) + ifnull(planned_qty, 0) - ifnull(reserved_qty,0) where warehouse = '%s' and item_code = '%s' " % (bin_obj.doc.warehouse, bin_obj.doc.item_code))
|
||||
if not self.msg:
|
||||
msgprint('<div style="color: GREEN"> Reposting of Stock for Item %s and Warehouse %s completed Successfully. </div>' % (bin_obj.doc.item_code, bin_obj.doc.warehouse))
|
||||
except Exception:
|
||||
msgprint('<div style="color: RED"> Handle Item %s and Warehouse %s seprately. </div> <div style="color: RED"> ERROR: %s</div>' % (bin_obj.doc.item_code, bin_obj.doc.warehouse, str(webnotes.utils.getTraceback())))
|
||||
self.msg.append('<div style="color: RED"> ERROR: %s</div>' % (str(webnotes.utils.getTraceback())))
|
||||
|
||||
# =============================================================================
|
||||
def repair_all_bins(self):
|
||||
bins = sql("select name from tabBin")
|
||||
cnt = 0
|
||||
for bin in bins:
|
||||
if cnt % 20 == 0:
|
||||
sql("commit")
|
||||
sql("start transaction")
|
||||
cnt += 1
|
||||
|
||||
self.repair_bin(bin[0])
|
||||
|
||||
# =============================================================================
|
||||
def repair_bins_for_illegal_cancelled(self, after_date = '2011-01-01'):
|
||||
bins = sql("select name from tabBin where modified >= %s", after_date)
|
||||
cnt = 0
|
||||
for bin in bins:
|
||||
if cnt % 20 == 0:
|
||||
sql("commit")
|
||||
sql("start transaction")
|
||||
cnt += 1
|
||||
|
||||
self.repair_bin(bin[0])
|
||||
# =============================================================================
|
||||
def repair_opening_bal(self, d, acc_obj, past_yr, fiscal_yr):
|
||||
# check opening balance
|
||||
opbal = sql("select balance from `tabAccount Balance` where account=%s and period = %s", (acc_obj.doc.name, past_yr))
|
||||
if flt(d.opening) != flt(opbal and flt(opbal[0][0]) or 0):
|
||||
msgprint('<div style="color: RED"> Difference found in Opening of Account %s for Period %s in Fiscal Year %s (Before : %s; After : %s) </div>' % (acc_obj.doc.name, d.period, fiscal_yr, flt(d.opening), opbal and flt(opbal[0][0]) or 0))
|
||||
self.msg.append('<div style="color: RED"> Difference found in Opening of Account %s for Period %s in Fiscal Year %s (Before : %s; After : %s) </div>' % (acc_obj.doc.name, d.period, fiscal_yr, flt(d.opening), opbal and flt(opbal[0][0]) or 0))
|
||||
sql("update `tabAccount Balance` set opening = '%s' where period = '%s' and account = '%s' " % (opbal and flt(opbal[0][0]) or 0, fiscal_yr, acc_obj.doc.name))
|
||||
|
||||
|
||||
# =============================================================================
|
||||
def repair_bal(self, d, acc_obj, fiscal_yr):
|
||||
# check balances
|
||||
ysd = get_value('Fiscal Year', fiscal_yr, 'year_start_date')
|
||||
bal = get_obj('GL Control').get_as_on_balance(acc_obj.doc.name, fiscal_yr, d.end_date, acc_obj.doc.debit_or_credit, acc_obj.doc.is_pl_account, acc_obj.doc.lft, acc_obj.doc.rgt, ysd)
|
||||
if flt(d.balance) != flt(bal):
|
||||
msgprint('<div style="color: RED"> Difference found in Balance of Account %s for Period %s in Fiscal Year %s (Before : %s; After : %s) </div>' % (acc_obj.doc.name, d.period, fiscal_yr, flt(d.balance), flt(bal)))
|
||||
self.msg.append('<div style="color: RED"> Difference found in Balance of Account %s for Period %s in Fiscal Year %s (Before : %s; After : %s) </div>' % (acc_obj.doc.name, d.period, fiscal_yr, flt(d.balance), flt(bal)))
|
||||
sql("update `tabAccount Balance` set balance = '%s' where period = '%s' and account = '%s' " % (bal, d.period, acc_obj.doc.name))
|
||||
|
||||
|
||||
# =============================================================================
|
||||
def repair_acc_bal(self, acc, past_yr = '' , fiscal_yr = ''):
|
||||
# get account obj
|
||||
acc_obj = get_obj('Account', acc, with_children = 1)
|
||||
|
||||
# get fiscal yr & past yr
|
||||
if not fiscal_yr:
|
||||
import webnotes.utils
|
||||
fiscal_yr = webnotes.utils.get_defaults()['fiscal_year']
|
||||
if not past_yr: past_yr = get_value('Fiscal Year', fiscal_yr, 'past_year')
|
||||
|
||||
# Repair Opening and Balance For Account Balances
|
||||
for d in getlist(acc_obj.doclist, 'account_balances'):
|
||||
if d.fiscal_year == fiscal_yr:
|
||||
if past_yr and (past_yr != fiscal_yr) and d.period == fiscal_yr:
|
||||
self.repair_opening_bal(d, acc_obj, past_yr, fiscal_yr)
|
||||
else:
|
||||
self.repair_bal(d, acc_obj, fiscal_yr)
|
||||
|
||||
# Acknowledge USer
|
||||
if not self.msg:
|
||||
msgprint('<div style="color: GREEN"> Openings & Balances of Account %s for Fiscal Year %s updated successfully. </div>' % ( acc_obj.doc.name, fiscal_yr))
|
||||
|
||||
return self.msg
|
||||
|
||||
|
||||
# =============================================================================
|
||||
def send_mail(self, args):
|
||||
args = eval(args)
|
||||
self.msg, subject = args['msg'], args['subject']
|
||||
msgprint(self.msg)
|
||||
if self.msg:
|
||||
email_msg = """ Dear Administrator,
|
||||
|
||||
In Account := %s User := %s has Reposted %s and following was found:-
|
||||
|
||||
%s
|
||||
|
||||
""" % (get_value('Control Panel', None,'account_id'), session['user'], subject, '\n'.join(self.msg))
|
||||
|
||||
sendmail(['support@iwebnotes.com'], subject='Repair of ' + cstr(subject), parts = [('text/plain', email_msg)])
|
||||
94
utilities/doctype/reposting_tool/reposting_tool.txt
Normal file
94
utilities/doctype/reposting_tool/reposting_tool.txt
Normal file
@@ -0,0 +1,94 @@
|
||||
# DocType, Reposting Tool
|
||||
[
|
||||
|
||||
# These values are common in all dictionaries
|
||||
{
|
||||
'creation': '2012-03-27 14:36:47',
|
||||
'docstatus': 0,
|
||||
'modified': '2012-03-27 14:36:47',
|
||||
'modified_by': u'Administrator',
|
||||
'owner': u'Administrator'
|
||||
},
|
||||
|
||||
# These values are common for all DocType
|
||||
{
|
||||
'allow_copy': 1,
|
||||
'allow_email': 1,
|
||||
'allow_print': 1,
|
||||
'colour': u'Light Blue:DEF',
|
||||
'default_print_format': u'Standard',
|
||||
'doctype': 'DocType',
|
||||
'hide_toolbar': 1,
|
||||
'in_create': 0,
|
||||
'issingle': 1,
|
||||
'module': u'Utilities',
|
||||
'name': '__common__',
|
||||
'read_only': 1,
|
||||
'section_style': u'Simple',
|
||||
'server_code_error': u' ',
|
||||
'show_in_menu': 1,
|
||||
'version': 173
|
||||
},
|
||||
|
||||
# These values are common for all DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'name': '__common__',
|
||||
'parent': u'Reposting Tool',
|
||||
'parentfield': u'fields',
|
||||
'parenttype': u'DocType',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# These values are common for all DocPerm
|
||||
{
|
||||
'create': 1,
|
||||
'doctype': u'DocPerm',
|
||||
'name': '__common__',
|
||||
'parent': u'Reposting Tool',
|
||||
'parentfield': u'permissions',
|
||||
'parenttype': u'DocType',
|
||||
'permlevel': 0,
|
||||
'read': 1,
|
||||
'role': u'System Manager',
|
||||
'write': 1
|
||||
},
|
||||
|
||||
# DocType, Reposting Tool
|
||||
{
|
||||
'doctype': 'DocType',
|
||||
'name': u'Reposting Tool'
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'doctype': u'DocPerm'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'recalculate_mar_&_actual_qty',
|
||||
'fieldtype': u'Data',
|
||||
'label': u'Recalculate MAR & Actual Qty'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'repost_bin',
|
||||
'fieldtype': u'Button',
|
||||
'label': u'Repost Bin',
|
||||
'trigger': u'Client'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'repost_account_balances',
|
||||
'fieldtype': u'Button',
|
||||
'label': u'Repost Account Balances',
|
||||
'trigger': u'Client'
|
||||
}
|
||||
]
|
||||
1
utilities/doctype/sms_control/__init__.py
Normal file
1
utilities/doctype/sms_control/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from __future__ import unicode_literals
|
||||
109
utilities/doctype/sms_control/sms_control.js
Normal file
109
utilities/doctype/sms_control/sms_control.js
Normal file
@@ -0,0 +1,109 @@
|
||||
// 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/>.
|
||||
|
||||
function SMSManager() {
|
||||
var me = this;
|
||||
this.get_contact_number = function(contact, key, value) {
|
||||
$c_obj('SMS Control', 'get_contact_number', {
|
||||
contact_name:contact,
|
||||
value:value,
|
||||
key:key
|
||||
}, function(r,rt) {
|
||||
if(r.exc) { msgprint(r.exc); return; }
|
||||
me.number = r.message;
|
||||
me.show_dialog();
|
||||
}
|
||||
);
|
||||
}
|
||||
this.show = function(contact, key, value, mobile_nos, message) {
|
||||
this.message = message;
|
||||
if (mobile_nos) {
|
||||
|
||||
me.number = mobile_nos;
|
||||
me.show_dialog();
|
||||
} else if (contact){
|
||||
this.get_contact_number(contact, key, value)
|
||||
} else {
|
||||
me.show_dialog();
|
||||
}
|
||||
}
|
||||
this.show_dialog = function() {
|
||||
if(!me.dialog)
|
||||
me.make_dialog();
|
||||
me.dialog.set_values({
|
||||
'message': me.message,
|
||||
'number': me.number
|
||||
})
|
||||
me.dialog.show();
|
||||
}
|
||||
this.make_dialog = function() {
|
||||
var d = new wn.widgets.Dialog({
|
||||
title: 'Send SMS',
|
||||
width: 400,
|
||||
fields: [
|
||||
{fieldname:'number', fieldtype:'Data', label:'Mobile Number', reqd:1},
|
||||
{fieldname:'message', fieldtype:'Text', label:'Message', reqd:1},
|
||||
{fieldname:'send', fieldtype:'Button', label:'Send'}
|
||||
]
|
||||
})
|
||||
d.make();
|
||||
d.fields_dict.send.input.onclick = function() {
|
||||
var btn = d.fields_dict.send.input;
|
||||
var v = me.dialog.get_values();
|
||||
if(v) {
|
||||
btn.set_working();
|
||||
$c_obj('SMS Control', 'send_form_sms', v, function(r,rt) {
|
||||
btn.done_working();
|
||||
if(r.exc) {msgprint(r.exc); return; }
|
||||
msgprint('Message Sent');
|
||||
me.dialog.hide();
|
||||
})
|
||||
}
|
||||
}
|
||||
this.dialog = d;
|
||||
}
|
||||
}
|
||||
|
||||
cur_frm.cscript.send_sms = function(doc,dt,dn) {
|
||||
var doc = cur_frm.doc;
|
||||
var sms_man = new SMSManager();
|
||||
var default_msg = {
|
||||
'Lead' : '',
|
||||
'Opportunity' : 'Your enquiry has been logged into the system. Ref No: ' + doc.name,
|
||||
'Quotation' : 'Quotation ' + doc.name + ' has been sent via email. Thanks!',
|
||||
'Sales Order' : 'Sales Order ' + doc.name + ' has been created against '
|
||||
+ (doc.quotation_no ? ('Quote No:' + doc.quotation_no) : '')
|
||||
+ (doc.po_no ? (' for your PO: ' + doc.po_no) : ''),
|
||||
'Delivery Note' : 'Items has been delivered against delivery note: ' + doc.name
|
||||
+ (doc.po_no ? (' for your PO: ' + doc.po_no) : ''),
|
||||
'Sales Invoice': 'Invoice ' + doc.name + ' has been sent via email '
|
||||
+ (doc.po_no ? (' for your PO: ' + doc.po_no) : ''),
|
||||
'Purchase Request' : 'Purchase Request ' + doc.name + ' has been raised in the system',
|
||||
'Purchase Order' : 'Purchase Order ' + doc.name + ' has been sent via email',
|
||||
'Purchase Receipt' : 'Items has been received against purchase receipt: ' + doc.name
|
||||
}
|
||||
|
||||
if (in_list(['Quotation', 'Sales Order', 'Delivery Note', 'Sales Invoice'], doc.doctype))
|
||||
sms_man.show(doc.contact_person, 'customer', doc.customer, '', default_msg[doc.doctype]);
|
||||
else if (in_list(['Purchase Order', 'Purchase Receipt'], doc.doctype))
|
||||
sms_man.show(doc.contact_person, 'supplier', doc.supplier, '', default_msg[doc.doctype]);
|
||||
else if (doc.doctype == 'Lead')
|
||||
sms_man.show('', '', '', doc.mobile_no, default_msg[doc.doctype]);
|
||||
else if (doc.doctype == 'Opportunity')
|
||||
sms_man.show('', '', '', doc.contact_no, default_msg[doc.doctype]);
|
||||
else if (doc.doctype == 'Purchase Request')
|
||||
sms_man.show('', '', '', '', default_msg[doc.doctype]);
|
||||
}
|
||||
164
utilities/doctype/sms_control/sms_control.py
Normal file
164
utilities/doctype/sms_control/sms_control.py
Normal file
@@ -0,0 +1,164 @@
|
||||
# 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/>.
|
||||
|
||||
# Please edit this list and import only required elements
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
|
||||
from webnotes.utils import cint, flt, load_json, nowdate, cstr
|
||||
from webnotes.model.code import get_obj
|
||||
from webnotes.model.doc import Document
|
||||
from webnotes import session, msgprint
|
||||
from webnotes.model.doclist import getlist, copy_doclist
|
||||
|
||||
sql = webnotes.conn.sql
|
||||
get_value = webnotes.conn.get_value
|
||||
|
||||
# -----------------------------------------------------------------------------------------
|
||||
class DocType:
|
||||
def __init__(self, doc, doclist=[]):
|
||||
self.doc = doc
|
||||
self.doclist = doclist
|
||||
|
||||
# validate receiver numbers
|
||||
# =========================================================
|
||||
def validate_receiver_nos(self,receiver_list):
|
||||
validated_receiver_list = []
|
||||
for d in receiver_list:
|
||||
# remove invalid character
|
||||
invalid_char_list = [' ', '+', '-', '(', ')']
|
||||
for x in invalid_char_list:
|
||||
d = d.replace(x, '')
|
||||
|
||||
# mobile no validation for erpnext gateway
|
||||
if get_value('SMS Settings', None, 'sms_gateway_url'):
|
||||
mob_no = d
|
||||
else:
|
||||
if not d.startswith("0") and len(d) == 10:
|
||||
mob_no = "91" + d
|
||||
elif d.startswith("0") and len(d) == 11:
|
||||
mob_no = "91" + d[1:]
|
||||
elif len(d) == 12:
|
||||
mob_no = d
|
||||
else:
|
||||
msgprint("Invalid mobile no : " + cstr(d))
|
||||
raise Exception
|
||||
|
||||
if not mob_no.isdigit():
|
||||
msgprint("Invalid mobile no : " + cstr(mob_no))
|
||||
raise Exception
|
||||
|
||||
validated_receiver_list.append(mob_no)
|
||||
|
||||
if not validated_receiver_list:
|
||||
msgprint("Please enter valid mobile nos")
|
||||
raise Exception
|
||||
|
||||
return validated_receiver_list
|
||||
|
||||
|
||||
def get_sender_name(self):
|
||||
"returns name as SMS sender"
|
||||
sender_name = webnotes.conn.get_value('Global Defaults', None, 'sms_sender_name') or 'ERPNXT'
|
||||
if len(sender_name) > 6:
|
||||
msgprint("""
|
||||
As per TRAI rule, sender name must be exactly 6 characters.
|
||||
Kindly change sender name in Setup --> Global Defaults.
|
||||
|
||||
Note: Hyphen, space, numeric digit, special characters are not allowed.
|
||||
""", raise_exception=1)
|
||||
return sender_name
|
||||
|
||||
def get_contact_number(self, arg):
|
||||
"returns mobile number of the contact"
|
||||
args = load_json(arg)
|
||||
number = sql('select mobile_no, phone from tabContact where name=%s and %s=%s' % ('%s', args['key'], '%s'),\
|
||||
(args['contact_name'], args['value']))
|
||||
return number and (number[0][0] or number[0][1]) or ''
|
||||
|
||||
def send_form_sms(self, arg):
|
||||
"called from client side"
|
||||
args = load_json(arg)
|
||||
self.send_sms([str(args['number'])], str(args['message']))
|
||||
|
||||
|
||||
# Send SMS
|
||||
# =========================================================
|
||||
def send_sms(self, receiver_list, msg, sender_name = ''):
|
||||
receiver_list = self.validate_receiver_nos(receiver_list)
|
||||
|
||||
arg = { 'account_name' : webnotes.conn.get_value('Control Panel',None,'account_id'),
|
||||
'receiver_list' : receiver_list,
|
||||
'message' : msg,
|
||||
'sender_name' : sender_name or self.get_sender_name()
|
||||
}
|
||||
|
||||
# personalized or erpnext gateway
|
||||
if get_value('SMS Settings', None, 'sms_gateway_url'):
|
||||
ret = self.send_via_personalized_gateway(arg)
|
||||
msgprint(ret)
|
||||
|
||||
|
||||
# Send sms via personalized gateway
|
||||
# ==========================================================
|
||||
def send_via_personalized_gateway(self, arg):
|
||||
ss = get_obj('SMS Settings', 'SMS Settings', with_children=1)
|
||||
args = {ss.doc.message_parameter : arg.get('message')}
|
||||
for d in getlist(ss.doclist, 'static_parameter_details'):
|
||||
args[d.parameter] = d.value
|
||||
|
||||
resp = []
|
||||
for d in arg.get('receiver_list'):
|
||||
args[ss.doc.receiver_parameter] = d
|
||||
resp.append(self.send_request(ss.doc.sms_gateway_url, args))
|
||||
|
||||
return resp
|
||||
|
||||
# Send Request
|
||||
# =========================================================
|
||||
def send_request(self, gateway_url, args):
|
||||
import httplib, urllib
|
||||
server, api_url = self.scrub_gateway_url(gateway_url)
|
||||
conn = httplib.HTTPConnection(server) # open connection
|
||||
headers = {}
|
||||
headers['Accept'] = "text/plain, text/html, */*"
|
||||
conn.request('GET', api_url + urllib.urlencode(args), headers = headers) # send request
|
||||
resp = conn.getresponse() # get response
|
||||
resp = resp.read()
|
||||
return resp
|
||||
|
||||
# Split gateway url to server and api url
|
||||
# =========================================================
|
||||
def scrub_gateway_url(self, url):
|
||||
url = url.replace('http://', '').strip().split('/')
|
||||
server = url.pop(0)
|
||||
api_url = '/' + '/'.join(url)
|
||||
if not api_url.endswith('?'):
|
||||
api_url += '?'
|
||||
return server, api_url
|
||||
|
||||
|
||||
# Create SMS Log
|
||||
# =========================================================
|
||||
def create_sms_log(self, arg, sent_sms):
|
||||
sl = Document('SMS Log')
|
||||
sl.sender_name = arg['sender_name']
|
||||
sl.sent_on = nowdate()
|
||||
sl.receiver_list = cstr(arg['receiver_list'])
|
||||
sl.message = arg['message']
|
||||
sl.no_of_requested_sms = len(arg['receiver_list'])
|
||||
sl.no_of_sent_sms = sent_sms
|
||||
sl.save(new=1)
|
||||
57
utilities/doctype/sms_control/sms_control.txt
Normal file
57
utilities/doctype/sms_control/sms_control.txt
Normal file
@@ -0,0 +1,57 @@
|
||||
# DocType, SMS Control
|
||||
[
|
||||
|
||||
# These values are common in all dictionaries
|
||||
{
|
||||
'creation': '2012-03-27 14:36:47',
|
||||
'docstatus': 0,
|
||||
'modified': '2012-03-27 14:36:47',
|
||||
'modified_by': u'Administrator',
|
||||
'owner': u'Administrator'
|
||||
},
|
||||
|
||||
# These values are common for all DocType
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'doctype': 'DocType',
|
||||
'in_create': 0,
|
||||
'issingle': 1,
|
||||
'module': u'Utilities',
|
||||
'name': '__common__',
|
||||
'section_style': u'Simple',
|
||||
'server_code_error': u' ',
|
||||
'show_in_menu': 0,
|
||||
'version': 8
|
||||
},
|
||||
|
||||
# These values are common for all DocPerm
|
||||
{
|
||||
'doctype': u'DocPerm',
|
||||
'name': '__common__',
|
||||
'parent': u'SMS Control',
|
||||
'parentfield': u'permissions',
|
||||
'parenttype': u'DocType',
|
||||
'read': 1,
|
||||
'role': u'System Manager'
|
||||
},
|
||||
|
||||
# DocType, SMS Control
|
||||
{
|
||||
'doctype': 'DocType',
|
||||
'name': u'SMS Control'
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'create': 1,
|
||||
'doctype': u'DocPerm',
|
||||
'permlevel': 0,
|
||||
'write': 1
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'doctype': u'DocPerm',
|
||||
'permlevel': 1
|
||||
}
|
||||
]
|
||||
1
utilities/doctype/sms_log/__init__.py
Normal file
1
utilities/doctype/sms_log/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from __future__ import unicode_literals
|
||||
123
utilities/doctype/sms_log/sms_log.txt
Normal file
123
utilities/doctype/sms_log/sms_log.txt
Normal file
@@ -0,0 +1,123 @@
|
||||
# DocType, SMS Log
|
||||
[
|
||||
|
||||
# These values are common in all dictionaries
|
||||
{
|
||||
'creation': '2012-03-27 14:36:47',
|
||||
'docstatus': 0,
|
||||
'modified': '2012-03-27 14:36:47',
|
||||
'modified_by': u'Administrator',
|
||||
'owner': u'Administrator'
|
||||
},
|
||||
|
||||
# These values are common for all DocType
|
||||
{
|
||||
'autoname': u'SMSLOG/.########',
|
||||
'colour': u'White:FFF',
|
||||
'doctype': 'DocType',
|
||||
'module': u'Utilities',
|
||||
'name': '__common__',
|
||||
'section_style': u'Simple',
|
||||
'show_in_menu': 0,
|
||||
'version': 3
|
||||
},
|
||||
|
||||
# These values are common for all DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'name': '__common__',
|
||||
'parent': u'SMS Log',
|
||||
'parentfield': u'fields',
|
||||
'parenttype': u'DocType',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# These values are common for all DocPerm
|
||||
{
|
||||
'create': 0,
|
||||
'doctype': u'DocPerm',
|
||||
'name': '__common__',
|
||||
'parent': u'SMS Log',
|
||||
'parentfield': u'permissions',
|
||||
'parenttype': u'DocType',
|
||||
'permlevel': 0,
|
||||
'read': 1,
|
||||
'role': u'System Manager',
|
||||
'write': 0
|
||||
},
|
||||
|
||||
# DocType, SMS Log
|
||||
{
|
||||
'doctype': 'DocType',
|
||||
'name': u'SMS Log'
|
||||
},
|
||||
|
||||
# DocPerm
|
||||
{
|
||||
'doctype': u'DocPerm'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'column_break0',
|
||||
'fieldtype': u'Column Break',
|
||||
'width': u'50%'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'sender_name',
|
||||
'fieldtype': u'Data',
|
||||
'label': u'Sender Name'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'sent_on',
|
||||
'fieldtype': u'Date',
|
||||
'label': u'Sent On'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'receiver_list',
|
||||
'fieldtype': u'Small Text',
|
||||
'label': u'Receiver List'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'column_break1',
|
||||
'fieldtype': u'Column Break',
|
||||
'width': u'50%'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'no_of_requested_sms',
|
||||
'fieldtype': u'Int',
|
||||
'label': u'No of Requested SMS'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'no_of_sent_sms',
|
||||
'fieldtype': u'Int',
|
||||
'label': u'No of Sent SMS'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'message',
|
||||
'fieldtype': u'Small Text',
|
||||
'label': u'Message'
|
||||
}
|
||||
]
|
||||
1
utilities/doctype/sms_receiver/__init__.py
Normal file
1
utilities/doctype/sms_receiver/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from __future__ import unicode_literals
|
||||
69
utilities/doctype/sms_receiver/sms_receiver.txt
Normal file
69
utilities/doctype/sms_receiver/sms_receiver.txt
Normal file
@@ -0,0 +1,69 @@
|
||||
# DocType, SMS Receiver
|
||||
[
|
||||
|
||||
# These values are common in all dictionaries
|
||||
{
|
||||
'creation': '2012-03-27 14:36:47',
|
||||
'docstatus': 0,
|
||||
'modified': '2012-03-27 14:36:47',
|
||||
'modified_by': u'Administrator',
|
||||
'owner': u'Administrator'
|
||||
},
|
||||
|
||||
# These values are common for all DocType
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'doctype': 'DocType',
|
||||
'istable': 1,
|
||||
'module': u'Utilities',
|
||||
'name': '__common__',
|
||||
'section_style': u'Tray',
|
||||
'server_code_error': u' ',
|
||||
'version': 2
|
||||
},
|
||||
|
||||
# These values are common for all DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldtype': u'Data',
|
||||
'name': '__common__',
|
||||
'oldfieldtype': u'Data',
|
||||
'parent': u'SMS Receiver',
|
||||
'parentfield': u'fields',
|
||||
'parenttype': u'DocType',
|
||||
'permlevel': 0
|
||||
},
|
||||
|
||||
# DocType, SMS Receiver
|
||||
{
|
||||
'doctype': 'DocType',
|
||||
'name': u'SMS Receiver'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'customer_name',
|
||||
'label': u'Customer Name',
|
||||
'oldfieldname': u'customer_name'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'receiver_name',
|
||||
'label': u'Receiver Name',
|
||||
'oldfieldname': u'receiver_name',
|
||||
'width': u'350px'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
'doctype': u'DocField',
|
||||
'fieldname': u'mobile_no',
|
||||
'label': u'Mobile No',
|
||||
'oldfieldname': u'mobile_no',
|
||||
'reqd': 1,
|
||||
'width': u'200px'
|
||||
}
|
||||
]
|
||||
1
utilities/doctype/trash_control/__init__.py
Normal file
1
utilities/doctype/trash_control/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from __future__ import unicode_literals
|
||||
76
utilities/doctype/trash_control/trash_control.py
Normal file
76
utilities/doctype/trash_control/trash_control.py
Normal file
@@ -0,0 +1,76 @@
|
||||
# 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/>.
|
||||
|
||||
# Please edit this list and import only required elements
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
|
||||
from webnotes.utils import add_days, add_months, add_years, cint, cstr, date_diff, default_fields, flt, fmt_money, formatdate, generate_hash, getTraceback, get_defaults, get_first_day, get_last_day, getdate, has_common, month_name, now, nowdate, replace_newlines, sendmail, set_default, str_esc_quote, user_format, validate_email_add
|
||||
from webnotes.model import db_exists
|
||||
from webnotes.model.doc import Document, addchild, getchildren, make_autoname
|
||||
from webnotes.model.doclist import getlist, copy_doclist
|
||||
from webnotes.model.code import get_obj, get_server_obj, run_server_obj, updatedb, check_syntax
|
||||
from webnotes import session, form, is_testing, msgprint, errprint
|
||||
|
||||
set = webnotes.conn.set
|
||||
sql = webnotes.conn.sql
|
||||
get_value = webnotes.conn.get_value
|
||||
in_transaction = webnotes.conn.in_transaction
|
||||
convert_to_lists = webnotes.conn.convert_to_lists
|
||||
|
||||
# -----------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
class DocType:
|
||||
def __init__(self, d, dl):
|
||||
self.doc, self.doclist = d, dl
|
||||
|
||||
|
||||
# Get Masters
|
||||
# -----------
|
||||
def get_masters(self):
|
||||
mlist = []
|
||||
res = sql("select distinct t1.name from tabDocType t1, tabDocPerm t2 where ifnull(t1.allow_trash, 0) = 1 and (ifnull(t2.write, 0) = 1 or ifnull(t2.create, 0) = 1) and t2.role in (%s) and t2.parent = t1.name and t1.module not in ('DocType','Application Internal','Recycle Bin','Development','Testing','Testing System','Test') ORDER BY t1.name" % ("'"+"', '".join(webnotes.user.get_roles())+"'"))
|
||||
for r in res:
|
||||
mlist.append(r[0])
|
||||
return mlist
|
||||
|
||||
|
||||
# Get Trash Records
|
||||
# -----------------
|
||||
def get_trash_records(self, mast_name):
|
||||
mlist = []
|
||||
rec_dict = {}
|
||||
if mast_name == 'All':
|
||||
mlist = self.get_masters()
|
||||
else:
|
||||
mlist.append(mast_name)
|
||||
for i in mlist:
|
||||
rec = [r[0] for r in sql("select name from `tab%s` where docstatus = 2" % i)]
|
||||
if rec:
|
||||
rec_dict[i] = rec
|
||||
return rec_dict
|
||||
|
||||
|
||||
# Restore Records
|
||||
# ---------------
|
||||
def restore_records(self, arg):
|
||||
arg = eval(arg)
|
||||
for k in arg:
|
||||
for r in arg[k]:
|
||||
sql("update `tab%s` set docstatus = 0, modified = '%s', trash_reason = '' where name = '%s'" % (k, now(), r))
|
||||
dt_obj = get_obj(k,r)
|
||||
if hasattr(dt_obj, 'on_restore'): dt_obj.on_restore()
|
||||
32
utilities/doctype/trash_control/trash_control.txt
Normal file
32
utilities/doctype/trash_control/trash_control.txt
Normal file
@@ -0,0 +1,32 @@
|
||||
# DocType, Trash Control
|
||||
[
|
||||
|
||||
# These values are common in all dictionaries
|
||||
{
|
||||
'creation': '2012-03-27 14:36:47',
|
||||
'docstatus': 0,
|
||||
'modified': '2012-03-27 14:36:47',
|
||||
'modified_by': u'Administrator',
|
||||
'owner': u'Administrator'
|
||||
},
|
||||
|
||||
# These values are common for all DocType
|
||||
{
|
||||
'colour': u'White:FFF',
|
||||
'doctype': 'DocType',
|
||||
'in_create': 1,
|
||||
'issingle': 1,
|
||||
'module': u'Utilities',
|
||||
'name': '__common__',
|
||||
'read_only': 1,
|
||||
'section_style': u'Simple',
|
||||
'server_code_error': u' ',
|
||||
'version': 35
|
||||
},
|
||||
|
||||
# DocType, Trash Control
|
||||
{
|
||||
'doctype': 'DocType',
|
||||
'name': u'Trash Control'
|
||||
}
|
||||
]
|
||||
1
utilities/page/__init__.py
Normal file
1
utilities/page/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from __future__ import unicode_literals
|
||||
1
utilities/page/calendar/__init__.py
Normal file
1
utilities/page/calendar/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from __future__ import unicode_literals
|
||||
169
utilities/page/calendar/calendar.css
Normal file
169
utilities/page/calendar/calendar.css
Normal file
@@ -0,0 +1,169 @@
|
||||
/**** CALENDAR ****/
|
||||
|
||||
div.cal_body {
|
||||
margin: 16px;
|
||||
background-color: #DDD;
|
||||
position: relative;
|
||||
border-radius: 5px;
|
||||
-moz-border-radius: 5px;
|
||||
-webkit-border-radius: 5px;
|
||||
padding: 16px;
|
||||
-moz-box-shadow: 1px 1px 8px #555;
|
||||
-webkit-box-shadow: 1px 1px 8px #555;
|
||||
box-shadow: 1px 1px 8px #555;
|
||||
}
|
||||
|
||||
div.cal_body h4 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
div.cal_head {
|
||||
margin: 16px;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
div.cal_head div {
|
||||
font-size: 18px;
|
||||
color: #666;
|
||||
padding-top: 8px;
|
||||
}
|
||||
|
||||
div.cal_toolbar {
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
div.cal_toolbar .btn {
|
||||
text-align: center;
|
||||
margin: 0px;
|
||||
margin-left: -1px;
|
||||
}
|
||||
|
||||
div.cal_view_body {
|
||||
}
|
||||
|
||||
div.cal_view_body_plain {
|
||||
margin: 16px;
|
||||
}
|
||||
|
||||
div.cal_month_head {
|
||||
margin: 8px 0px 8px 0px;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
div.cal_month_head .btn {
|
||||
float: right;
|
||||
}
|
||||
|
||||
span.cal_view_title {
|
||||
display: inline-block;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
div.cal_month_body {
|
||||
}
|
||||
|
||||
.cal_month_headtable {
|
||||
/*table-layout:fixed;*/
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.cal_month_name {
|
||||
width: 100%;
|
||||
color: #888;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.cal_month_headtable tr td{
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
table.cal_month_table {
|
||||
border-collapse: collapse;
|
||||
/*table-layout:fixed;*/
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
table.cal_month_table td {
|
||||
width: 14.29%;
|
||||
height: 20%;
|
||||
/*overflow:hidden;*/
|
||||
padding:0px;
|
||||
}
|
||||
|
||||
div.cal_month_date {
|
||||
width:100%;
|
||||
font-size: 10px;
|
||||
/*background-color: #EEF;*/
|
||||
}
|
||||
|
||||
div.cal_month_date_holiday {
|
||||
/*background-color: #FFF;*/
|
||||
}
|
||||
|
||||
div.cal_month_unit {
|
||||
width:100%;
|
||||
min-height: 100px;
|
||||
overflow:hidden;
|
||||
cursor:pointer;
|
||||
/*background-color:#FFF;*/
|
||||
}
|
||||
|
||||
div.cal_vu_disabled {
|
||||
background-color:#FFF;
|
||||
cursor:default;
|
||||
}
|
||||
|
||||
table.cal_day_table {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
table.cal_day_table td {
|
||||
}
|
||||
|
||||
div.cal_day_body {
|
||||
width: 100%;
|
||||
overflow-x: hidden;
|
||||
border-top: 1px solid #AAA;
|
||||
}
|
||||
|
||||
div.cal_day_unit{
|
||||
width:100%;
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
table.cal_week_table {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
table.cal_week_table td {
|
||||
width: 12.5%;
|
||||
}
|
||||
|
||||
div.cal_week_body {
|
||||
width: 100%;
|
||||
overflow-x: hidden;
|
||||
border-top: 1px solid #888;
|
||||
}
|
||||
|
||||
div.cal_week_unit{
|
||||
width: 100%;
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
div.cal_event_Public {
|
||||
color: GREEN;
|
||||
}
|
||||
|
||||
div.cal_event_Private {
|
||||
color: BLUE;
|
||||
}
|
||||
|
||||
div.cal_event_hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
26
utilities/page/calendar/calendar.html
Normal file
26
utilities/page/calendar/calendar.html
Normal file
@@ -0,0 +1,26 @@
|
||||
<div class="cal_body">
|
||||
<a class="close" onclick="window.history.back();">×</a>
|
||||
<div class="cal_toolbar btn-group">
|
||||
<button class="btn btn-small" onclick="erpnext.calendar.add_event()">
|
||||
<i class="icon-plus"></i> Add Event
|
||||
</button>
|
||||
<button class="btn btn-small" onclick="erpnext.calendar.refresh('Day')">
|
||||
Day View
|
||||
</button>
|
||||
<button class="btn btn-small" onclick="erpnext.calendar.refresh('Week')">
|
||||
Week View
|
||||
</button>
|
||||
<button class="btn btn-small" onclick="erpnext.calendar.refresh('Month')">
|
||||
Month View
|
||||
</button>
|
||||
</div>
|
||||
<div class="cal_month_head">
|
||||
<span class="cal_view_title"></span>
|
||||
<button class="btn btn-small" onclick="erpnext.calendar.cur_view.next()">
|
||||
<i class="icon-arrow-right"></i>
|
||||
</button>
|
||||
<button class="btn btn-small" onclick="erpnext.calendar.cur_view.prev()">
|
||||
<i class="icon-arrow-left"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
690
utilities/page/calendar/calendar.js
Normal file
690
utilities/page/calendar/calendar.js
Normal file
@@ -0,0 +1,690 @@
|
||||
// Copyright (c) 2012 Web Notes Technologies Pvt Ltd (http://erpnext.com)
|
||||
//
|
||||
// MIT License (MIT)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
||||
// OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
pscript.onload_calendar = function(wrapper) {
|
||||
if(!erpnext.calendar) {
|
||||
erpnext.calendar = new Calendar();
|
||||
erpnext.calendar.init(wrapper);
|
||||
|
||||
var me = this;
|
||||
$(document).bind('rename', function(event, dt, old_name, new_name) {
|
||||
erpnext.calendar.rename_notify(dt, old_name, new_name)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
///// CALENDAR
|
||||
|
||||
Calendar=function() {
|
||||
this.views=[];
|
||||
this.events = {};
|
||||
this.events_by_name = {};
|
||||
this.weekdays = new Array("Sun","Mon","Tue","Wed","Thu","Fri","Sat");
|
||||
}
|
||||
|
||||
Calendar.prototype.init=function (parent) {
|
||||
|
||||
this.wrapper = parent;
|
||||
this.body = $('.cal_body').get(0);
|
||||
|
||||
//this.make_head_buttons();
|
||||
//this.make_header();
|
||||
this.view_title = $('.cal_view_title').get(0);
|
||||
|
||||
this.todays_date = new Date();
|
||||
this.selected_date = this.todays_date;
|
||||
this.selected_hour = 8;
|
||||
|
||||
// Create views
|
||||
this.views['Month'] = new Calendar.MonthView(this);
|
||||
this.views['Week'] = new Calendar.WeekView(this);
|
||||
this.views['Day'] = new Calendar.DayView(this);
|
||||
|
||||
// Month view as initial
|
||||
this.cur_view = this.views['Month'];
|
||||
this.views['Month'].show();
|
||||
|
||||
}
|
||||
|
||||
Calendar.prototype.rename_notify = function(dt, old_name, new_name) {
|
||||
// calendar
|
||||
if(dt = 'Event'){
|
||||
if(this.events_by_name[old_name]) {
|
||||
delete this.events_by_name[old_name];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
|
||||
Calendar.prototype.show_event = function(ev, cal_ev) {
|
||||
var me = this;
|
||||
if(!this.event_dialog) {
|
||||
var d = new Dialog(400, 400, 'Calendar Event');
|
||||
d.make_body([
|
||||
['HTML','Heading']
|
||||
,['Text','Description']
|
||||
,['HTML', 'Ref Link']
|
||||
,['Check', 'Public Event']
|
||||
,['Check', 'Cancel Event']
|
||||
,['HTML', 'Event Link']
|
||||
,['Button', 'Save']
|
||||
])
|
||||
|
||||
// show the event when the dialog opens
|
||||
d.onshow = function() {
|
||||
// heading
|
||||
var c = me.selected_date;
|
||||
var tmp = time_to_ampm(this.ev.event_hour);
|
||||
tmp = tmp[0]+':'+tmp[1]+' '+tmp[2];
|
||||
|
||||
this.widgets['Heading'].innerHTML =
|
||||
'<div style="text-align: center; padding:4px; font-size: 14px">'
|
||||
+ erpnext.calendar.weekdays[c.getDay()] + ', ' + c.getDate() + ' ' + month_list_full[c.getMonth()] + ' ' + c.getFullYear()
|
||||
+ ' - <b>'+tmp+'</b></div>';
|
||||
|
||||
// set
|
||||
this.widgets['Description'].value = cstr(this.ev.description);
|
||||
|
||||
this.widgets['Public Event'].checked = false;
|
||||
this.widgets['Cancel Event'].checked = false;
|
||||
|
||||
if(this.ev.event_type=='Public')
|
||||
this.widgets['Public Event'].checked = true;
|
||||
|
||||
this.widgets['Event Link'].innerHTML = '';
|
||||
this.widgets['Ref Link'].innerHTML = '';
|
||||
|
||||
if(this.ev.ref_type) {
|
||||
$(repl('<span>Reference: <a href="#Form/%(ref_type)s/%(ref_name)s" \
|
||||
onclick="cur_dialog.hide()">%(ref_type)s: %(ref_name)s</a></span>', this.ev))
|
||||
.appendTo(this.widgets['Ref Link'])
|
||||
}
|
||||
|
||||
$(repl('<a href="#Form/Event/%(name)s" \
|
||||
onclick="cur_dialog.hide()">More Options</a>', this.ev))
|
||||
.appendTo(this.widgets['Event Link'])
|
||||
}
|
||||
|
||||
// event save
|
||||
d.widgets['Save'].onclick = function() {
|
||||
var d = me.event_dialog;
|
||||
|
||||
// save values
|
||||
d.ev.description = d.widgets['Description'].value;
|
||||
if(d.widgets['Cancel Event'].checked)
|
||||
d.ev.event_type='Cancel';
|
||||
else if(d.widgets['Public Event'].checked)
|
||||
d.ev.event_type='Public';
|
||||
|
||||
me.event_dialog.hide();
|
||||
|
||||
// if new event
|
||||
me.save_event(d.ev);
|
||||
}
|
||||
this.event_dialog = d;
|
||||
}
|
||||
this.event_dialog.ev = ev;
|
||||
this.event_dialog.cal_ev = cal_ev ? cal_ev : null;
|
||||
this.event_dialog.show();
|
||||
|
||||
}
|
||||
|
||||
Calendar.prototype.save_event = function(doc) {
|
||||
var me = this;
|
||||
save_doclist('Event', doc.name, 'Save', function(r) {
|
||||
var doc = locals['Event'][r.docname];
|
||||
var cal = erpnext.calendar;
|
||||
cal.cur_view.refresh();
|
||||
|
||||
// if cancelled, hide
|
||||
if(doc.event_type=='Cancel') {
|
||||
$(cal.events_by_name[doc.name].body).toggle(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
|
||||
Calendar.prototype.add_event = function() {
|
||||
|
||||
var ev = LocalDB.create('Event');
|
||||
ev = locals['Event'][ev];
|
||||
|
||||
ev.event_date = dateutil.obj_to_str(this.selected_date);
|
||||
ev.event_hour = this.selected_hour+':00';
|
||||
ev.event_type = 'Private';
|
||||
|
||||
this.show_event(ev);
|
||||
}
|
||||
//------------------------------------------------------
|
||||
|
||||
Calendar.prototype.get_month_events = function(call_back) {
|
||||
// ret fn
|
||||
var me = this;
|
||||
var f = function(r, rt) {
|
||||
if(me.cur_view) me.cur_view.refresh();
|
||||
if(call_back)call_back();
|
||||
}
|
||||
|
||||
//load
|
||||
var y=this.selected_date.getFullYear(); var m = this.selected_date.getMonth();
|
||||
if(!this.events[y] || !this.events[y][m]) {
|
||||
$c('webnotes.widgets.event.load_month_events', args = {
|
||||
'month': m + 1,
|
||||
'year' : y},
|
||||
f);
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------
|
||||
|
||||
Calendar.prototype.get_daily_event_list=function(day) {
|
||||
var el = [];
|
||||
var d = day.getDate(); var m = day.getMonth(); var y = day.getFullYear()
|
||||
if(this.events[y] && this.events[y][m] &&
|
||||
this.events[y][m][d]) {
|
||||
var l = this.events[y][m][d]
|
||||
for(var i in l) {
|
||||
for(var j in l[i]) el[el.length] = l[i][j];
|
||||
}
|
||||
return el;
|
||||
}
|
||||
else return [];
|
||||
}
|
||||
//------------------------------------------------------
|
||||
|
||||
Calendar.prototype.set_event = function(ev) {
|
||||
// don't duplicate
|
||||
if(this.events_by_name[ev.name]) {
|
||||
return this.events_by_name[ev.name];
|
||||
}
|
||||
|
||||
var dt = dateutil.str_to_obj(ev.event_date);
|
||||
var m = dt.getMonth();
|
||||
var d = dt.getDate();
|
||||
var y = dt.getFullYear();
|
||||
|
||||
if(!this.events[y]) this.events[y] = [];
|
||||
if(!this.events[y][m]) this.events[y][m] = [];
|
||||
if(!this.events[y][m][d]) this.events[y][m][d] = [];
|
||||
if(!this.events[y][m][d][cint(ev.event_hour)])
|
||||
this.events[y][m][d][cint(ev.event_hour)] = [];
|
||||
|
||||
var cal_ev = new Calendar.CalEvent(ev, this);
|
||||
this.events[y][m][d][cint(ev.event_hour)].push(cal_ev);
|
||||
this.events_by_name[ev.name] = cal_ev;
|
||||
|
||||
return cal_ev;
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
|
||||
Calendar.prototype.refresh = function(viewtype){//Sets the viewtype of the Calendar and Calls the View class based on the viewtype
|
||||
if(viewtype)
|
||||
this.viewtype = viewtype;
|
||||
// switch view if reqd
|
||||
if(this.cur_view.viewtype!=this.viewtype) {
|
||||
this.cur_view.hide();
|
||||
this.cur_view = this.views[this.viewtype];
|
||||
this.cur_view.in_home = false; // for home page
|
||||
this.cur_view.show();
|
||||
}
|
||||
else{
|
||||
this.cur_view.refresh(this);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
|
||||
Calendar.CalEvent= function(doc, cal) {
|
||||
this.body = document.createElement('div');
|
||||
this.link = $a(this.body, 'a', '', {}, locals['Event'][doc.name].description || '');
|
||||
this.doc = doc;
|
||||
var me = this;
|
||||
|
||||
this.link.onclick = function() {
|
||||
if(me.doc.name) {
|
||||
cal.show_event(me.doc, me);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Calendar.CalEvent.prototype.show = function(vu) {
|
||||
|
||||
var t = this.doc.event_type;
|
||||
this.my_class = 'cal_event_'+ t;
|
||||
|
||||
if(this.body.parentNode)
|
||||
this.body.parentNode.removeChild(this.body);
|
||||
vu.body.appendChild(this.body);
|
||||
|
||||
// refresh
|
||||
this.link.innerHTML = this.doc.description || '';
|
||||
this.body.className = this.my_class;
|
||||
}
|
||||
|
||||
|
||||
// ----------
|
||||
|
||||
Calendar.View =function() { this.daystep = 0; this.monthstep = 0; }
|
||||
Calendar.View.prototype.init=function(cal) {
|
||||
this.cal = cal;
|
||||
this.body = $a(cal.body, 'div', 'cal_view_body');
|
||||
this.body.style.display = 'none';
|
||||
this.create_table();
|
||||
}
|
||||
|
||||
|
||||
Calendar.View.prototype.show=function() {
|
||||
this.get_events(); this.refresh(); this.body.style.display = 'block';
|
||||
}
|
||||
|
||||
Calendar.View.prototype.hide=function() { this.body.style.display = 'none';}
|
||||
|
||||
Calendar.View.prototype.next = function() {
|
||||
var s = this.cal.selected_date;
|
||||
this.cal.selected_date = new Date(s.getFullYear(), s.getMonth() + this.monthstep, s.getDate() + this.daystep);
|
||||
this.get_events(); this.refresh();
|
||||
}
|
||||
|
||||
Calendar.View.prototype.prev = function() {
|
||||
var s = this.cal.selected_date;
|
||||
this.cal.selected_date = new Date(s.getFullYear(), s.getMonth() - this.monthstep, s.getDate() - this.daystep);
|
||||
this.get_events(); this.refresh();
|
||||
}
|
||||
|
||||
Calendar.View.prototype.get_events = function() {
|
||||
this.cal.get_month_events();
|
||||
}
|
||||
Calendar.View.prototype.add_unit = function(vu) {
|
||||
this.viewunits[this.viewunits.length] = vu;
|
||||
}
|
||||
Calendar.View.prototype.refresh_units = function() {
|
||||
// load the events
|
||||
if(locals['Event']) {
|
||||
for(var name in locals['Event']) {
|
||||
this.cal.set_event(locals['Event'][name]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for(var r in this.table.rows) {
|
||||
for(var c in this.table.rows[r].cells) {
|
||||
if(this.table.rows[r].cells[c].viewunit) {
|
||||
this.table.rows[r].cells[c].viewunit.refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ................. Month View..........................
|
||||
Calendar.MonthView = function(cal) { this.init(cal); this.monthstep = 1; this.rows = 5; this.cells = 7; }
|
||||
Calendar.MonthView.prototype=new Calendar.View();
|
||||
Calendar.MonthView.prototype.create_table = function() {
|
||||
|
||||
// create head
|
||||
this.head_wrapper = $a(this.body, 'div', 'cal_month_head');
|
||||
|
||||
// create headers
|
||||
this.headtable = $a(this.head_wrapper, 'table', 'cal_month_headtable');
|
||||
var r = this.headtable.insertRow(0);
|
||||
for(var j=0;j<7;j++) {
|
||||
var cell = r.insertCell(j);
|
||||
cell.innerHTML = erpnext.calendar.weekdays[j]; $w(cell, (100 / 7) + '%');
|
||||
}
|
||||
|
||||
this.main = $a(this.body, 'div', 'cal_month_body');
|
||||
this.table = $a(this.main, 'table', 'cal_month_table');
|
||||
var me = this;
|
||||
|
||||
// create body
|
||||
for(var i=0;i<5;i++) {
|
||||
var r = this.table.insertRow(i);
|
||||
for(var j=0;j<7;j++) {
|
||||
var cell = r.insertCell(j);
|
||||
cell.viewunit = new Calendar.MonthViewUnit(cell);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Calendar.MonthView.prototype.refresh = function() {
|
||||
var c =this.cal.selected_date;
|
||||
var me=this;
|
||||
// fill other days
|
||||
|
||||
var cur_row = 0;
|
||||
|
||||
var cur_month = c.getMonth();
|
||||
var cur_year = c.getFullYear();
|
||||
|
||||
var d = new Date(cur_year, cur_month, 1);
|
||||
var day = 1 - d.getDay();
|
||||
|
||||
|
||||
// set day headers
|
||||
var d = new Date(cur_year, cur_month, day);
|
||||
|
||||
this.cal.view_title.innerHTML = month_list_full[cur_month] + ' ' + cur_year;
|
||||
|
||||
for(var i=0;i<6;i++) {
|
||||
if((i<5) || cur_month==d.getMonth()) { // if this month
|
||||
for(var j=0;j<7;j++) {
|
||||
var cell = this.table.rows[cur_row].cells[j];
|
||||
|
||||
if((i<5) || cur_month==d.getMonth()) { // if this month
|
||||
cell.viewunit.day = d;
|
||||
cell.viewunit.hour = 8;
|
||||
if(cur_month == d.getMonth()) {
|
||||
cell.viewunit.is_disabled = false;
|
||||
|
||||
if(same_day(this.cal.todays_date, d))
|
||||
cell.viewunit.is_today = true;
|
||||
else
|
||||
cell.viewunit.is_today = false;
|
||||
|
||||
} else {
|
||||
cell.viewunit.is_disabled = true;
|
||||
}
|
||||
}
|
||||
// new date
|
||||
day++;
|
||||
d = new Date(cur_year, cur_month, day);
|
||||
}
|
||||
}
|
||||
cur_row++;
|
||||
if(cur_row == 5) {cur_row = 0;} // back to top
|
||||
}
|
||||
this.refresh_units();
|
||||
|
||||
}
|
||||
// ................. Daily View..........................
|
||||
Calendar.DayView=function(cal){ this.init(cal); this.daystep = 1; }
|
||||
Calendar.DayView.prototype=new Calendar.View();
|
||||
Calendar.DayView.prototype.create_table = function() {
|
||||
|
||||
// create body
|
||||
this.main = $a(this.body, 'div', 'cal_day_body');
|
||||
this.table = $a(this.main, 'table', 'cal_day_table');
|
||||
var me = this;
|
||||
|
||||
for(var i=0;i<24;i++) {
|
||||
var r = this.table.insertRow(i);
|
||||
for(var j=0;j<2;j++) {
|
||||
var cell = r.insertCell(j);
|
||||
if(j==0) {
|
||||
var tmp = time_to_ampm((i)+':00');
|
||||
cell.innerHTML = tmp[0]+':'+tmp[1]+' '+tmp[2];
|
||||
$w(cell, '10%');
|
||||
} else {
|
||||
cell.viewunit = new Calendar.DayViewUnit(cell);
|
||||
cell.viewunit.hour = i;
|
||||
$w(cell, '90%');
|
||||
if((i>=7)&&(i<=20)) {
|
||||
cell.viewunit.is_daytime = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Calendar.DayView.prototype.refresh = function() {
|
||||
var c =this.cal.selected_date;
|
||||
|
||||
// fill other days
|
||||
var me=this;
|
||||
|
||||
this.cal.view_title.innerHTML = erpnext.calendar.weekdays[c.getDay()] + ', '
|
||||
+ c.getDate() + ' ' + month_list_full[c.getMonth()] + ' ' + c.getFullYear();
|
||||
|
||||
// headers
|
||||
var d = c;
|
||||
|
||||
for(var i=0;i<24;i++) {
|
||||
var cell = this.table.rows[i].cells[1];
|
||||
if(same_day(this.cal.todays_date, d)) cell.viewunit.is_today = true;
|
||||
else cell.viewunit.is_today = false;
|
||||
cell.viewunit.day = d;
|
||||
}
|
||||
this.refresh_units();
|
||||
}
|
||||
|
||||
// ................. Weekly View..........................
|
||||
Calendar.WeekView=function(cal) { this.init(cal); this.daystep = 7; }
|
||||
Calendar.WeekView.prototype=new Calendar.View();
|
||||
Calendar.WeekView.prototype.create_table = function() {
|
||||
|
||||
// create head
|
||||
this.head_wrapper = $a(this.body, 'div', 'cal_month_head');
|
||||
|
||||
// day headers
|
||||
this.headtable = $a(this.head_wrapper, 'table', 'cal_month_headtable');
|
||||
var r = this.headtable.insertRow(0);
|
||||
for(var j=0;j<8;j++) {
|
||||
var cell = r.insertCell(j);
|
||||
$w(cell, (100 / 8) + '%');
|
||||
}
|
||||
|
||||
// hour header
|
||||
|
||||
// create body
|
||||
this.main = $a(this.body, 'div', 'cal_week_body');
|
||||
this.table = $a(this.main, 'table', 'cal_week_table');
|
||||
var me = this;
|
||||
|
||||
for(var i=0;i<24;i++) {
|
||||
var r = this.table.insertRow(i);
|
||||
for(var j=0;j<8;j++) {
|
||||
var cell = r.insertCell(j);
|
||||
if(j==0) {
|
||||
var tmp = time_to_ampm(i+':00');
|
||||
cell.innerHTML = tmp[0]+':'+tmp[1]+' '+tmp[2];
|
||||
|
||||
$w(cell, '10%');
|
||||
} else {
|
||||
cell.viewunit = new Calendar.WeekViewUnit(cell);
|
||||
cell.viewunit.hour = i;
|
||||
if((i>=7)&&(i<=20)) {
|
||||
cell.viewunit.is_daytime = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Calendar.WeekView.prototype.refresh = function() {
|
||||
var c =this.cal.selected_date;
|
||||
// fill other days
|
||||
var me=this;
|
||||
|
||||
this.cal.view_title.innerHTML = month_list_full[c.getMonth()] + ' ' + c.getFullYear();
|
||||
|
||||
// headers
|
||||
var d = new Date(c.getFullYear(), c.getMonth(), c.getDate() - c.getDay());
|
||||
|
||||
for (var k=1;k<8;k++) {
|
||||
this.headtable.rows[0].cells[k].innerHTML = erpnext.calendar.weekdays[d.getDay()] + ' ' + d.getDate();
|
||||
|
||||
for(var i=0;i<24;i++) {
|
||||
var cell = this.table.rows[i].cells[k];
|
||||
if(same_day(this.cal.todays_date, d))
|
||||
cell.viewunit.is_today = true;
|
||||
else cell.viewunit.is_today = false;
|
||||
|
||||
cell.viewunit.day = d;
|
||||
//cell.viewunit.refresh();
|
||||
}
|
||||
d=new Date(d.getFullYear(),d.getMonth(),d.getDate() + 1);
|
||||
|
||||
}
|
||||
|
||||
this.refresh_units();
|
||||
}
|
||||
|
||||
//------------------------------------------------------.
|
||||
|
||||
Calendar.ViewUnit = function() {}
|
||||
Calendar.ViewUnit.prototype.init = function(parent) {
|
||||
parent.style.border = "1px solid #CCC" ;
|
||||
this.body = $a(parent, 'div', this.default_class);
|
||||
this.parent = parent;
|
||||
|
||||
var me = this;
|
||||
this.body.onclick = function() {
|
||||
erpnext.calendar.selected_date = me.day;
|
||||
erpnext.calendar.selected_hour = me.hour;
|
||||
|
||||
if(erpnext.calendar.cur_vu && erpnext.calendar.cur_vu!=me){
|
||||
erpnext.calendar.cur_vu.deselect();
|
||||
me.select();
|
||||
erpnext.calendar.cur_vu = me;
|
||||
}
|
||||
}
|
||||
this.body.ondblclick = function() {
|
||||
erpnext.calendar.add_event();
|
||||
}
|
||||
}
|
||||
|
||||
Calendar.ViewUnit.prototype.set_header=function(v) {
|
||||
this.header.innerHTML = v;
|
||||
}
|
||||
|
||||
Calendar.ViewUnit.prototype.set_today = function() {
|
||||
this.is_today = true;
|
||||
this.set_display();
|
||||
}
|
||||
|
||||
Calendar.ViewUnit.prototype.clear = function() {
|
||||
if(this.header)this.header.innerHTML = '';
|
||||
|
||||
// clear body
|
||||
while(this.body.childNodes.length)
|
||||
this.body.removeChild(this.body.childNodes[0]);
|
||||
}
|
||||
|
||||
Calendar.ViewUnit.prototype.set_display = function() {
|
||||
var cn = '#FFF';
|
||||
|
||||
// colors
|
||||
var col_tod_sel = '#EEE';
|
||||
var col_tod = '#FFF';
|
||||
var col_sel = '#EEF';
|
||||
|
||||
if(this.is_today) {
|
||||
if(this.selected) cn = col_tod_sel;
|
||||
else cn = col_tod;
|
||||
} else
|
||||
if(this.selected) cn = col_sel;
|
||||
|
||||
if(this.header) {
|
||||
if(this.is_disabled) {
|
||||
this.body.className = this.default_class + ' cal_vu_disabled';
|
||||
this.header.style.color = '#BBB';
|
||||
} else {
|
||||
this.body.className = this.default_class;
|
||||
this.header.style.color = '#000';
|
||||
}
|
||||
|
||||
if(this.day&&this.day.getDay()==0)
|
||||
this.header.style.backgroundColor = '#FEE';
|
||||
else
|
||||
this.header.style.backgroundColor = '';
|
||||
}
|
||||
this.parent.style.backgroundColor = cn;
|
||||
}
|
||||
|
||||
Calendar.ViewUnit.prototype.is_selected = function() {
|
||||
return (same_day(this.day, erpnext.calendar.selected_date)
|
||||
&& this.hour==erpnext.calendar.selected_hour)
|
||||
}
|
||||
|
||||
Calendar.ViewUnit.prototype.get_event_list = function() {
|
||||
var y = this.day.getFullYear();
|
||||
var m = this.day.getMonth();
|
||||
var d = this.day.getDate();
|
||||
if(erpnext.calendar.events[y] && erpnext.calendar.events[y][m] &&
|
||||
erpnext.calendar.events[y][m][d] &&
|
||||
erpnext.calendar.events[y][m][d][this.hour]) {
|
||||
return erpnext.calendar.events[y][m][d][this.hour];
|
||||
} else
|
||||
return [];
|
||||
}
|
||||
|
||||
Calendar.ViewUnit.prototype.refresh = function() {
|
||||
this.clear();
|
||||
|
||||
if(this.is_selected()) {
|
||||
if(erpnext.calendar.cur_vu)erpnext.calendar.cur_vu.deselect();
|
||||
this.selected = true;
|
||||
erpnext.calendar.cur_vu = this;
|
||||
}
|
||||
this.set_display();
|
||||
this.el = this.get_event_list();
|
||||
if(this.onrefresh)this.onrefresh();
|
||||
|
||||
for(var i in this.el) {
|
||||
this.el[i].show(this);
|
||||
}
|
||||
|
||||
var me = this;
|
||||
}
|
||||
|
||||
Calendar.ViewUnit.prototype.select=function() { this.selected = true; this.set_display(); }
|
||||
Calendar.ViewUnit.prototype.deselect=function() { this.selected = false; this.set_display(); }
|
||||
Calendar.ViewUnit.prototype.setevent=function() { }
|
||||
|
||||
Calendar.MonthViewUnit=function(parent) {
|
||||
this.header = $a(parent, 'div' , "cal_month_date");
|
||||
this.default_class = "cal_month_unit";
|
||||
|
||||
this.init(parent);
|
||||
|
||||
this.onrefresh = function() {
|
||||
this.header.innerHTML = this.day.getDate();
|
||||
}
|
||||
}
|
||||
Calendar.MonthViewUnit.prototype = new Calendar.ViewUnit();
|
||||
Calendar.MonthViewUnit.prototype.is_selected = function() {
|
||||
return same_day(this.day, erpnext.calendar.selected_date)
|
||||
}
|
||||
|
||||
Calendar.MonthViewUnit.prototype.get_event_list = function() {
|
||||
return erpnext.calendar.get_daily_event_list(this.day);
|
||||
}
|
||||
|
||||
Calendar.DayViewUnit= function(parent) {
|
||||
this.default_class = "cal_day_unit"; this.init(parent);
|
||||
}
|
||||
Calendar.DayViewUnit.prototype = new Calendar.ViewUnit();
|
||||
Calendar.DayViewUnit.prototype.onrefresh = function() {
|
||||
if(this.el.length<3)
|
||||
this.body.style.height = '30px';
|
||||
else this.body.style.height = '';
|
||||
}
|
||||
|
||||
Calendar.WeekViewUnit=function(parent) {
|
||||
this.default_class = "cal_week_unit"; this.init(parent);
|
||||
}
|
||||
Calendar.WeekViewUnit.prototype = new Calendar.ViewUnit();
|
||||
Calendar.WeekViewUnit.prototype.onrefresh = function() {
|
||||
if(this.el.length<3) this.body.style.height = '30px';
|
||||
else this.body.style.height = '';
|
||||
}
|
||||
1
utilities/page/calendar/calendar.py
Normal file
1
utilities/page/calendar/calendar.py
Normal file
@@ -0,0 +1 @@
|
||||
from __future__ import unicode_literals
|
||||
28
utilities/page/calendar/calendar.txt
Normal file
28
utilities/page/calendar/calendar.txt
Normal file
@@ -0,0 +1,28 @@
|
||||
# Page, calendar
|
||||
[
|
||||
|
||||
# These values are common in all dictionaries
|
||||
{
|
||||
'creation': '2012-02-24 11:24:12',
|
||||
'docstatus': 0,
|
||||
'modified': '2012-02-24 11:24:12',
|
||||
'modified_by': u'Administrator',
|
||||
'owner': u'Administrator'
|
||||
},
|
||||
|
||||
# These values are common for all Page
|
||||
{
|
||||
'doctype': 'Page',
|
||||
'module': u'Utilities',
|
||||
'name': '__common__',
|
||||
'page_name': u'calendar',
|
||||
'standard': u'Yes',
|
||||
'title': u'Calendar'
|
||||
},
|
||||
|
||||
# Page, calendar
|
||||
{
|
||||
'doctype': 'Page',
|
||||
'name': u'calendar'
|
||||
}
|
||||
]
|
||||
1
utilities/page/markdown_reference/__init__.py
Normal file
1
utilities/page/markdown_reference/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from __future__ import unicode_literals
|
||||
150
utilities/page/markdown_reference/markdown_reference.html
Normal file
150
utilities/page/markdown_reference/markdown_reference.html
Normal file
@@ -0,0 +1,150 @@
|
||||
<div class="layout-wrapper layout-wrapper-background">
|
||||
<div class="layout-appframe">
|
||||
<div class="appframe-titlebar">
|
||||
<span class="appframe-title">Markdown Reference</span>
|
||||
<span class="close" onclick="window.history.back()">×</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-main">
|
||||
<div style="width: 60%" class="markdown">
|
||||
<h3>Phrase Emphasis</h3>
|
||||
<pre><code>*italic* **bold**
|
||||
_italic_ __bold__
|
||||
</code></pre>
|
||||
|
||||
<h3>Links</h3>
|
||||
|
||||
<p>Inline:</p>
|
||||
|
||||
<pre><code>An [example](http://url.com/ "Title")
|
||||
</code></pre>
|
||||
|
||||
<p>Reference-style labels (titles are optional):</p>
|
||||
|
||||
<pre><code>An [example][id]. Then, anywhere
|
||||
else in the doc, define the link:
|
||||
|
||||
[id]: http://example.com/ "Title"
|
||||
</code></pre>
|
||||
|
||||
<h3>Images</h3>
|
||||
|
||||
<p>Inline (titles are optional):</p>
|
||||
|
||||
<pre><code>
|
||||
</code></pre>
|
||||
|
||||
<p>Reference-style:</p>
|
||||
|
||||
<pre><code>![alt text][id]
|
||||
|
||||
[id]: /url/to/img.jpg "Title"
|
||||
</code></pre>
|
||||
|
||||
<h3>Headers</h3>
|
||||
|
||||
<p>Setext-style:</p>
|
||||
|
||||
<pre><code>Header 1
|
||||
========
|
||||
|
||||
Header 2
|
||||
--------
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>atx-style (closing #'s are optional):</p>
|
||||
|
||||
<pre><code># Header 1 #
|
||||
|
||||
|
||||
</code></pre>
|
||||
|
||||
<h3>Lists</h3>
|
||||
|
||||
<p>Ordered, without paragraphs:</p>
|
||||
|
||||
<pre><code>1. Foo
|
||||
2. Bar
|
||||
</code></pre>
|
||||
|
||||
<p>Unordered, with paragraphs:</p>
|
||||
|
||||
<pre><code>* A list item.
|
||||
|
||||
With multiple paragraphs.
|
||||
|
||||
* Bar
|
||||
</code></pre>
|
||||
|
||||
<p>You can nest them:</p>
|
||||
|
||||
<pre><code>* Abacus
|
||||
* ass
|
||||
* Bastard
|
||||
1. bitch
|
||||
2. bupkis
|
||||
* BELITTLER
|
||||
3. burper
|
||||
* Cunning
|
||||
</code></pre>
|
||||
|
||||
<h3>Blockquotes</h3>
|
||||
|
||||
<pre><code>> Email-style angle brackets
|
||||
|
||||
> are used for blockquotes.
|
||||
|
||||
> > And, they can be nested.
|
||||
|
||||
> >
|
||||
> * You can quote a list.
|
||||
> * Etc.
|
||||
</code></pre>
|
||||
|
||||
<h3>Code Spans</h3>
|
||||
|
||||
<pre><code>`<code>` spans are delimited
|
||||
by backticks.
|
||||
|
||||
You can include literal backticks
|
||||
like `` `this` ``.
|
||||
</code></pre>
|
||||
|
||||
<h3>Preformatted Code Blocks</h3>
|
||||
|
||||
<p>Indent every line of a code block by at least 4 spaces or 1 tab, and use a colon at the end of the preceding paragraph.</p>
|
||||
|
||||
<pre><code>This is a normal paragraph:
|
||||
|
||||
This is a preformatted
|
||||
code block.
|
||||
|
||||
Preceded by a space, the colon
|
||||
disappears. :
|
||||
|
||||
This is a preformatted
|
||||
code block.
|
||||
</code></pre>
|
||||
|
||||
<h3>Horizontal Rules</h3>
|
||||
|
||||
<p>Three or more dashes or asterisks:</p>
|
||||
|
||||
<pre><code>---
|
||||
|
||||
* * *
|
||||
|
||||
- - - -
|
||||
</code></pre>
|
||||
|
||||
<h3>Manual Line Breaks</h3>
|
||||
|
||||
<p>End a line with two or more spaces:</p>
|
||||
|
||||
<pre><code>Roses are red,
|
||||
Violets are blue.
|
||||
</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
1
utilities/page/markdown_reference/markdown_reference.js
Normal file
1
utilities/page/markdown_reference/markdown_reference.js
Normal file
@@ -0,0 +1 @@
|
||||
wn.pages['markdown-reference'].onload = function(wrapper) { }
|
||||
2
utilities/page/markdown_reference/markdown_reference.py
Normal file
2
utilities/page/markdown_reference/markdown_reference.py
Normal file
@@ -0,0 +1,2 @@
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
28
utilities/page/markdown_reference/markdown_reference.txt
Normal file
28
utilities/page/markdown_reference/markdown_reference.txt
Normal file
@@ -0,0 +1,28 @@
|
||||
# Page, markdown-reference
|
||||
[
|
||||
|
||||
# These values are common in all dictionaries
|
||||
{
|
||||
'creation': '2012-08-07 12:35:30',
|
||||
'docstatus': 0,
|
||||
'modified': '2012-08-07 12:35:30',
|
||||
'modified_by': u'Administrator',
|
||||
'owner': u'Administrator'
|
||||
},
|
||||
|
||||
# These values are common for all Page
|
||||
{
|
||||
'doctype': 'Page',
|
||||
'module': u'Utilities',
|
||||
'name': '__common__',
|
||||
'page_name': u'Markdown Reference',
|
||||
'standard': u'Yes',
|
||||
'title': u'Markdown Reference'
|
||||
},
|
||||
|
||||
# Page, markdown-reference
|
||||
{
|
||||
'doctype': 'Page',
|
||||
'name': u'markdown-reference'
|
||||
}
|
||||
]
|
||||
1
utilities/page/messages/__init__.py
Normal file
1
utilities/page/messages/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from __future__ import unicode_literals
|
||||
35
utilities/page/messages/messages.css
Normal file
35
utilities/page/messages/messages.css
Normal file
@@ -0,0 +1,35 @@
|
||||
#message-post-text {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
#message-list {
|
||||
|
||||
}
|
||||
|
||||
.message {
|
||||
border-radius: 5px;
|
||||
max-width: 60%;
|
||||
min-width: 40%;
|
||||
padding: 7px;
|
||||
margin-bottom: 7px;
|
||||
}
|
||||
|
||||
.message .help {
|
||||
margin-bottom: 0px;
|
||||
padding-bottom: 0px;
|
||||
color: #888;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.message-other {
|
||||
background-color: #EBFF9C;
|
||||
border: 1px solid #C3CF78;
|
||||
float: right;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.message-self {
|
||||
background-color: #eee;
|
||||
border: 1px solid #ccc;
|
||||
float: left;
|
||||
}
|
||||
28
utilities/page/messages/messages.html
Normal file
28
utilities/page/messages/messages.html
Normal file
@@ -0,0 +1,28 @@
|
||||
<div class="layout-wrapper layout-wrapper-background">
|
||||
<div class="layout-main-section">
|
||||
<a class="close" onclick="window.history.back();">×</a>
|
||||
<h1>Messages</h1>
|
||||
<div class="well">
|
||||
<input id="message-post-text"></input>
|
||||
<button disabled="disabled" id="message-post" class="btn btn-small"><i class="icon-play"></i> Post</button>
|
||||
</div>
|
||||
<div id="message-list">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-side-section">
|
||||
<div class="psidebar">
|
||||
<div class="section">
|
||||
<div class="section-head">
|
||||
Messages By
|
||||
</div>
|
||||
<div class="section-body">
|
||||
<div class="section-item">
|
||||
<a href="#!messages"><b>All messages</b></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="clear: both;">
|
||||
</div>
|
||||
</div>
|
||||
163
utilities/page/messages/messages.js
Normal file
163
utilities/page/messages/messages.js
Normal file
@@ -0,0 +1,163 @@
|
||||
// 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/>.
|
||||
|
||||
wn.provide('erpnext.messages');
|
||||
|
||||
wn.pages.messages.onload = function(wrapper) {
|
||||
erpnext.messages.show_active_users();
|
||||
erpnext.messages.make_list();
|
||||
erpnext.update_messages('reset'); //Resets notification icons
|
||||
|
||||
// post message
|
||||
$('#message-post').click(function() {
|
||||
var txt = $('#message-post-text').val();
|
||||
if(txt) {
|
||||
wn.call({
|
||||
module:'utilities',
|
||||
page:'messages',
|
||||
method:'post',
|
||||
args: {
|
||||
txt: txt,
|
||||
contact: erpnext.messages.contact
|
||||
},
|
||||
callback:function(r,rt) {
|
||||
$('#message-post-text').val('')
|
||||
erpnext.messages.list.run();
|
||||
},
|
||||
btn: this
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// enable, disable button
|
||||
$('#message-post-text').keyup(function(e) {
|
||||
if($(this).val()) {
|
||||
$('#message-post').attr('disabled', false);
|
||||
} else {
|
||||
$('#message-post').attr('disabled', true);
|
||||
}
|
||||
|
||||
if(e.which==13) {
|
||||
$('#message-post').click();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
$(wn.pages.messages).bind('show', function() {
|
||||
erpnext.messages.show();
|
||||
setTimeout(erpnext.messages.refresh, 7000);
|
||||
$('#message-post-text').focus();
|
||||
})
|
||||
|
||||
erpnext.messages = {
|
||||
show: function() {
|
||||
var contact = erpnext.messages.get_contact();
|
||||
|
||||
// can't send message to self
|
||||
$(wn.pages.messages).find('.well').toggle(contact==user ? false : true);
|
||||
|
||||
$(wn.pages.messages).find('h1:first').html('Messages: '
|
||||
+ (user==contact ? 'From everyone' : wn.user_info(contact).fullname));
|
||||
|
||||
erpnext.messages.contact = contact;
|
||||
erpnext.messages.list.opts.args.contact = contact;
|
||||
erpnext.messages.list.run();
|
||||
|
||||
},
|
||||
// check for updates every 5 seconds if page is active
|
||||
refresh: function() {
|
||||
setTimeout(erpnext.messages.refresh, 7000);
|
||||
if(wn.container.page.label != 'Messages') return;
|
||||
erpnext.messages.show();
|
||||
},
|
||||
get_contact: function() {
|
||||
var route = location.hash;
|
||||
if(route.indexOf('/')!=-1) {
|
||||
var name = decodeURIComponent(route.split('/')[1]);
|
||||
if(name.indexOf('__at__')!=-1) {
|
||||
name = name.replace('__at__', '@');
|
||||
}
|
||||
return name;
|
||||
}
|
||||
return user;
|
||||
},
|
||||
make_list: function() {
|
||||
erpnext.messages.list = new wn.ui.Listing({
|
||||
parent: $('#message-list').get(0),
|
||||
method: 'utilities.page.messages.messages.get_list',
|
||||
args: {
|
||||
contact: null
|
||||
},
|
||||
render_row: function(wrapper, data) {
|
||||
$(wrapper).removeClass('list-row');
|
||||
|
||||
data.creation = dateutil.comment_when(data.creation);
|
||||
data.comment_by_fullname = wn.user_info(data.owner).fullname;
|
||||
|
||||
data.reply_html = '';
|
||||
if(data.owner==user) {
|
||||
data.cls = 'message-self';
|
||||
data.comment_by_fullname = 'You';
|
||||
data.delete_html = repl('<a class="close" \
|
||||
onclick="erpnext.messages.delete(this)"\
|
||||
data-name="%(name)s">×</a>', data);
|
||||
} else {
|
||||
data.cls = 'message-other';
|
||||
data.delete_html = '';
|
||||
if(erpnext.messages.contact==user) {
|
||||
data.reply_html = repl('<a href="#!messages/%(owner)s">\
|
||||
<i class="icon-share-alt"></i> Reply</a>', data)
|
||||
}
|
||||
}
|
||||
|
||||
wrapper.innerHTML = repl('<div class="message %(cls)s">%(delete_html)s\
|
||||
<b>%(comment)s</b>\
|
||||
<div class="help">by %(comment_by_fullname)s, %(creation)s</div>\
|
||||
%(reply_html)s</div>\
|
||||
<div style="clear: both;"></div>', data);
|
||||
}
|
||||
});
|
||||
},
|
||||
delete: function(ele) {
|
||||
$(ele).parent().css('opacity', 0.6);
|
||||
wn.call({
|
||||
method:'utilities.page.messages.messages.delete',
|
||||
args: {name : $(ele).attr('data-name')},
|
||||
callback: function() {
|
||||
$(ele).parent().toggle(false);
|
||||
}
|
||||
});
|
||||
},
|
||||
show_active_users: function() {
|
||||
wn.call({
|
||||
module:'utilities',
|
||||
page:'messages',
|
||||
method:'get_active_users',
|
||||
callback: function(r,rt) {
|
||||
var $body = $(wn.pages.messages).find('.section-body');
|
||||
for(var i in r.message) {
|
||||
var p = r.message[i];
|
||||
p.fullname = wn.user_info(p.name).fullname;
|
||||
p.name = p.name.replace('@', '__at__');
|
||||
$body.append(repl('<div class="section-item">\
|
||||
<a href="#!messages/%(name)s">%(fullname)s</a></div>', p))
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
108
utilities/page/messages/messages.py
Normal file
108
utilities/page/messages/messages.py
Normal file
@@ -0,0 +1,108 @@
|
||||
# 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
|
||||
|
||||
@webnotes.whitelist()
|
||||
def get_list(arg=None):
|
||||
"""get list of messages"""
|
||||
webnotes.form_dict['limit_start'] = int(webnotes.form_dict['limit_start'])
|
||||
webnotes.form_dict['limit_page_length'] = int(webnotes.form_dict['limit_page_length'])
|
||||
webnotes.form_dict['user'] = webnotes.session['user']
|
||||
|
||||
if webnotes.form_dict['contact'] == webnotes.session['user']:
|
||||
# set all messages as read
|
||||
webnotes.conn.sql("""UPDATE `tabComment`
|
||||
set docstatus = 1 where comment_doctype in ('My Company', 'Message')
|
||||
and comment_docname = %s
|
||||
""", webnotes.user.name)
|
||||
|
||||
# return messages
|
||||
return webnotes.conn.sql("""select * from `tabComment`
|
||||
where (owner=%(contact)s or comment_docname=%(user)s)
|
||||
and comment_doctype in ('My Company', 'Message')
|
||||
order by creation desc
|
||||
limit %(limit_start)s, %(limit_page_length)s""", webnotes.form_dict, as_dict=1)
|
||||
else:
|
||||
return webnotes.conn.sql("""select * from `tabComment`
|
||||
where (owner=%(contact)s and comment_docname=%(user)s)
|
||||
or (owner=%(user)s and comment_docname=%(contact)s)
|
||||
and comment_doctype in ('My Company', 'Message')
|
||||
order by creation desc
|
||||
limit %(limit_start)s, %(limit_page_length)s""", webnotes.form_dict, as_dict=1)
|
||||
|
||||
|
||||
@webnotes.whitelist()
|
||||
def get_active_users(arg=None):
|
||||
return webnotes.conn.sql("""select name from tabProfile
|
||||
where ifnull(enabled,0)=1 and
|
||||
docstatus < 2 and
|
||||
name not in ('Administrator', 'Guest')
|
||||
order by first_name""", as_dict=1)
|
||||
|
||||
@webnotes.whitelist()
|
||||
def post(arg=None):
|
||||
import webnotes
|
||||
"""post message"""
|
||||
if arg:
|
||||
import json
|
||||
arg = json.loads(arg)
|
||||
else:
|
||||
arg = {}
|
||||
arg.update(webnotes.form_dict)
|
||||
from webnotes.model.doc import Document
|
||||
d = Document('Comment')
|
||||
d.comment = arg['txt']
|
||||
d.comment_docname = arg['contact']
|
||||
d.comment_doctype = 'Message'
|
||||
d.save()
|
||||
|
||||
import webnotes.utils
|
||||
if webnotes.utils.cint(arg.get('notify')):
|
||||
notify(arg)
|
||||
|
||||
@webnotes.whitelist()
|
||||
def delete(arg=None):
|
||||
webnotes.conn.sql("""delete from `tabComment` where name=%s""",
|
||||
webnotes.form_dict['name']);
|
||||
|
||||
def notify(arg=None):
|
||||
from webnotes.utils import cstr
|
||||
fn = webnotes.conn.sql('select first_name, last_name from tabProfile where name=%s', webnotes.user.name)[0]
|
||||
if fn[0] or f[1]:
|
||||
fn = cstr(fn[0]) + (fn[0] and ' ' or '') + cstr(fn[1])
|
||||
else:
|
||||
fn = webnotes.user.name
|
||||
|
||||
message = '''A new comment has been posted on your page by %s:
|
||||
|
||||
<b>Comment:</b> %s
|
||||
|
||||
To answer, please login to your erpnext account!
|
||||
''' % (fn, arg['txt'])
|
||||
|
||||
from webnotes.model.code import get_obj
|
||||
note = get_obj('Notification Control')
|
||||
email_msg = note.prepare_message({
|
||||
'type': 'New Comment',
|
||||
'message': message
|
||||
})
|
||||
|
||||
sender = webnotes.user.name!='Administrator' and webnotes.user.name or 'support+admin_post@erpnext.com'
|
||||
|
||||
from webnotes.utils.email_lib import sendmail
|
||||
sendmail([arg['contact']], sender, email_msg, fn + ' has posted a new comment')
|
||||
28
utilities/page/messages/messages.txt
Normal file
28
utilities/page/messages/messages.txt
Normal file
@@ -0,0 +1,28 @@
|
||||
# Page, messages
|
||||
[
|
||||
|
||||
# These values are common in all dictionaries
|
||||
{
|
||||
'creation': '2012-02-24 11:21:57',
|
||||
'docstatus': 0,
|
||||
'modified': '2012-02-24 11:21:57',
|
||||
'modified_by': u'Administrator',
|
||||
'owner': u'Administrator'
|
||||
},
|
||||
|
||||
# These values are common for all Page
|
||||
{
|
||||
'doctype': 'Page',
|
||||
'module': u'Utilities',
|
||||
'name': '__common__',
|
||||
'page_name': u'messages',
|
||||
'standard': u'Yes',
|
||||
'title': u'Messages'
|
||||
},
|
||||
|
||||
# Page, messages
|
||||
{
|
||||
'doctype': 'Page',
|
||||
'name': u'messages'
|
||||
}
|
||||
]
|
||||
1
utilities/page/question_view/__init__.py
Normal file
1
utilities/page/question_view/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from __future__ import unicode_literals
|
||||
44
utilities/page/question_view/question_view.css
Normal file
44
utilities/page/question_view/question_view.css
Normal file
@@ -0,0 +1,44 @@
|
||||
.qv-body {
|
||||
padding: 13px;
|
||||
}
|
||||
|
||||
|
||||
.qv-input {
|
||||
font-size: 14px;
|
||||
height: 2.5em;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.qv-text {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.qv-ans-input {
|
||||
height: 5em;
|
||||
}
|
||||
|
||||
.qv-ans-text {
|
||||
color: #444;
|
||||
line-height: 1.7em;
|
||||
}
|
||||
|
||||
.qv-question-wrapper {
|
||||
}
|
||||
|
||||
.qv-add-answer {
|
||||
width: 50%;
|
||||
margin: 7px 0px;
|
||||
padding: 7px;
|
||||
background-color: #E2E2EE;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.qv-add-answer textarea {
|
||||
height: 17em;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.qv-answer {
|
||||
|
||||
}
|
||||
11
utilities/page/question_view/question_view.html
Normal file
11
utilities/page/question_view/question_view.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<div class="layout-wrapper layout-wrapper-appframe">
|
||||
<div class="layout-appframe"></div>
|
||||
<div class="layout-main" style="min-height: 400px">
|
||||
<div class="qv-question-wrapper">
|
||||
</div>
|
||||
<hr>
|
||||
<div class="qv-answer-wrapper">
|
||||
</div>
|
||||
<div class="add-answer-area"></div>
|
||||
</div>
|
||||
</div>
|
||||
189
utilities/page/question_view/question_view.js
Normal file
189
utilities/page/question_view/question_view.js
Normal file
@@ -0,0 +1,189 @@
|
||||
// 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/>.
|
||||
|
||||
pscript['onload_question-view'] = function(wrapper) {
|
||||
wrapper.appframe = new wn.ui.AppFrame($(wrapper).find('.layout-appframe'));
|
||||
wrapper.appframe.title('<span class="breadcrumbs"><a href="#questions">Knowledge Base</a></span>');
|
||||
|
||||
wrapper.add_answer_area = $('.add-answer-area').get(0);
|
||||
}
|
||||
|
||||
pscript['refresh_question-view'] = function(wrapper) {
|
||||
// href
|
||||
var qid = window.location.hash.split('/')[1];
|
||||
if(qid) {
|
||||
pscript.question_view(qid);
|
||||
}
|
||||
}
|
||||
|
||||
pscript.question_view = function(qid, qtext) {
|
||||
var w = wn.pages['question-view'];
|
||||
new KBQuestionView(w, qid, qtext);
|
||||
}
|
||||
|
||||
KBQuestionView = function(w, qid, qtext) {
|
||||
var me = this;
|
||||
|
||||
this.make_question = function() {
|
||||
$(w).find('.qv-question-wrapper').empty();
|
||||
$(w.add_answer_area).empty();
|
||||
new EditableText({
|
||||
parent: $(w).find('.qv-question-wrapper').get(0),
|
||||
dt: 'Question',
|
||||
dn: qid,
|
||||
fieldname: 'question',
|
||||
text: qtext,
|
||||
inp_class: 'qv-input',
|
||||
disp_class: 'qv-text'
|
||||
});
|
||||
|
||||
// show tags
|
||||
}
|
||||
|
||||
// answer list
|
||||
this.make_answer_list = function() {
|
||||
$(w).find('.qv-answer-wrapper').empty();
|
||||
this.ans_list = new KBAnswerList({
|
||||
parent: $(w).find('.qv-answer-wrapper').get(0),
|
||||
qid: qid
|
||||
})
|
||||
}
|
||||
|
||||
// check if users has answered
|
||||
// (if no) then add a box to add a new answer
|
||||
this.make_add_answer = function() {
|
||||
$c_page('utilities', 'question_view', 'has_answered', qid, function(r, rt) {
|
||||
if(r.message=='No') {
|
||||
me.make_answer_box_link();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// add a link to open add answer
|
||||
this.make_answer_box_link = function() {
|
||||
wn.pages['question-view'].appframe.add_button('Add your answer', function() {
|
||||
$(this).toggle(false);
|
||||
me.make_answer_box();
|
||||
}, 'icon-plus');
|
||||
}
|
||||
|
||||
// answer box
|
||||
// text area + add button
|
||||
this.make_answer_box = function() {
|
||||
$ds(w.add_answer_area);
|
||||
$(w.add_answer_area, '<h3>Add your Answer</h3>\
|
||||
<div class="help">In markdown format</div>');
|
||||
this.input = $a(w.add_answer_area, 'textarea');
|
||||
//wn.tinymce.add_simple(this.input);
|
||||
|
||||
this.btn = $btn($a(w.add_answer_area, 'div'), 'Post', function() {
|
||||
var v = $(me.input).val();
|
||||
if(!v) { msgprint('Write something!'); return; }
|
||||
me.btn.set_working();
|
||||
$c_page('utilities', 'question_view', 'add_answer', {qid: qid, answer:v},
|
||||
function(r, rt) {
|
||||
me.btn.done_working();
|
||||
me.ans_list.list.run();
|
||||
$dh(w.add_answer_area);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
this.setup = function() {
|
||||
if(qtext) {
|
||||
this.make();
|
||||
}
|
||||
else {
|
||||
$c_page('utilities', 'question_view', 'get_question', qid, function(r, rt) {
|
||||
qtext = r.message;
|
||||
me.make();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.make = function() {
|
||||
set_title(qtext);
|
||||
this.make_question();
|
||||
this.make_answer_list();
|
||||
this.make_add_answer();
|
||||
}
|
||||
|
||||
this.setup();
|
||||
}
|
||||
|
||||
|
||||
// kb answer list
|
||||
KBAnswerList = function(args) {
|
||||
var me = this;
|
||||
$.extend(this, args);
|
||||
|
||||
this.make_list = function() {
|
||||
wn.pages['question-view'].appframe.clear_buttons();
|
||||
this.list = new wn.ui.Listing({
|
||||
parent: me.parent,
|
||||
appframe: wn.pages['question-view'].appframe,
|
||||
as_dict: 1,
|
||||
no_result_message: 'No answers yet, be the first one to answer!',
|
||||
render_row: function(body, data) {
|
||||
new KBAnswer(body, data, me)
|
||||
},
|
||||
get_query: function() {
|
||||
return repl("SELECT t1.name, t1.owner, t1.answer, t1._users_voted, t2.first_name, "
|
||||
+"t2.last_name, t1.modified from tabAnswer t1, tabProfile t2 "
|
||||
+"where question='%(qid)s' and t1.owner = t2.name "
|
||||
+"order by t1.modified desc", {qid: me.qid})
|
||||
}
|
||||
});
|
||||
|
||||
this.list.run();
|
||||
|
||||
}
|
||||
|
||||
this.make_list();
|
||||
|
||||
}
|
||||
|
||||
// kb answer
|
||||
// answer
|
||||
// by xxx | on xxx
|
||||
KBAnswer = function(body, data, ans_list) {
|
||||
body.className = 'qv-answer';
|
||||
var edtxt = new EditableText({
|
||||
parent: body,
|
||||
dt: 'Answer',
|
||||
dn: data.name,
|
||||
fieldname: 'answer',
|
||||
text: data.answer,
|
||||
inp_class: 'qv-ans-input',
|
||||
disp_class: 'qv-ans-text',
|
||||
height: '300px'
|
||||
});
|
||||
|
||||
$(edtxt.wrapper).addClass('well');
|
||||
|
||||
var div = $a(body, 'div', '', {})
|
||||
new KBItemToolbar({
|
||||
parent: div,
|
||||
det: data,
|
||||
with_tags: 0,
|
||||
doctype: 'Answer'
|
||||
}, ans_list)
|
||||
|
||||
}
|
||||
|
||||
|
||||
wn.require('erpnext/utilities/page/kb_common/kb_common.js');
|
||||
48
utilities/page/question_view/question_view.py
Normal file
48
utilities/page/question_view/question_view.py
Normal file
@@ -0,0 +1,48 @@
|
||||
# ERPNext - web based ERP (http://erpnext.com)
|
||||
# Copyright (C) 2012 Web Notes Technologies Pvt Ltd
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
from webnotes.utils import load_json, cstr, now
|
||||
|
||||
@webnotes.whitelist()
|
||||
def update_item(args):
|
||||
args = load_json(args)
|
||||
|
||||
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']))
|
||||
|
||||
@webnotes.whitelist()
|
||||
def has_answered(arg):
|
||||
return webnotes.conn.sql("select name from tabAnswer where owner=%s and question=%s", (webnotes.user.name, arg)) and 'Yes' or 'No'
|
||||
|
||||
@webnotes.whitelist()
|
||||
def get_question(arg):
|
||||
return cstr(webnotes.conn.sql("select question from tabQuestion where name=%s", arg)[0][0])
|
||||
|
||||
@webnotes.whitelist()
|
||||
def add_answer(args):
|
||||
args = load_json(args)
|
||||
|
||||
from webnotes.model.doc import Document
|
||||
|
||||
a = Document('Answer')
|
||||
a.answer = args['answer']
|
||||
a.question = args['qid']
|
||||
a.points = 1
|
||||
a.save(1)
|
||||
|
||||
webnotes.conn.set_value('Question', args['qid'], 'modified', now())
|
||||
27
utilities/page/question_view/question_view.txt
Normal file
27
utilities/page/question_view/question_view.txt
Normal file
@@ -0,0 +1,27 @@
|
||||
# Page, question-view
|
||||
[
|
||||
|
||||
# These values are common in all dictionaries
|
||||
{
|
||||
'creation': '2011-05-04 11:09:50',
|
||||
'docstatus': 0,
|
||||
'modified': '2011-03-29 13:54:27',
|
||||
'modified_by': 'Administrator',
|
||||
'owner': 'Administrator'
|
||||
},
|
||||
|
||||
# These values are common for all Page
|
||||
{
|
||||
'doctype': 'Page',
|
||||
'module': 'Utilities',
|
||||
'name': '__common__',
|
||||
'page_name': 'Question View',
|
||||
'standard': 'Yes'
|
||||
},
|
||||
|
||||
# Page, question-view
|
||||
{
|
||||
'doctype': 'Page',
|
||||
'name': 'question-view'
|
||||
}
|
||||
]
|
||||
1
utilities/page/questions/__init__.py
Normal file
1
utilities/page/questions/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from __future__ import unicode_literals
|
||||
31
utilities/page/questions/questions.css
Normal file
31
utilities/page/questions/questions.css
Normal file
@@ -0,0 +1,31 @@
|
||||
div.kb-search-wrapper textarea {
|
||||
height: 2.2em;
|
||||
width: 80%;
|
||||
font-size: 14px;
|
||||
padding: 3px;
|
||||
margin-bottom: 7px;
|
||||
}
|
||||
|
||||
.kb-question-wrapper {
|
||||
padding-bottom: 3px;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
.kb-questions {
|
||||
}
|
||||
|
||||
.un-answered {
|
||||
color: #f33;
|
||||
}
|
||||
|
||||
.kb-question-details {
|
||||
margin: 11px 0px 11px 29px;
|
||||
}
|
||||
|
||||
.kb-tag-filter-area {
|
||||
padding: 7px;
|
||||
background-color: #F2F2E8;
|
||||
color: #222;
|
||||
margin: 7px 0px;
|
||||
display: none;
|
||||
}
|
||||
19
utilities/page/questions/questions.html
Normal file
19
utilities/page/questions/questions.html
Normal file
@@ -0,0 +1,19 @@
|
||||
<div class="layout-wrapper layout-wrapper-background">
|
||||
<div class="layout-appframe"></div>
|
||||
<div class="layout-main-section">
|
||||
<div class="kb-search-wrapper">
|
||||
<textarea></textarea>
|
||||
<div>
|
||||
<button class="btn btn-small search" onclick="">
|
||||
<i class="icon-search"></i> Search</button>
|
||||
<button class="btn btn-small ask">
|
||||
<i class="icon-question-sign"></i> Ask</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layout-side-section">
|
||||
<div class="questions-tags"></div>
|
||||
<p class="help">A wiki or Q&A for your organization</p>
|
||||
</div>
|
||||
<div style="clear: both;"></div>
|
||||
</div>
|
||||
218
utilities/page/questions/questions.js
Normal file
218
utilities/page/questions/questions.js
Normal file
@@ -0,0 +1,218 @@
|
||||
// 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/>.
|
||||
|
||||
pscript.onload_questions = function(wrapper) {
|
||||
body = $(wrapper).find('.layout-main-section').get(0);
|
||||
|
||||
wrapper.appframe = new wn.ui.AppFrame($(wrapper).find('.layout-appframe'));
|
||||
wrapper.appframe.title('Knowledge Base');
|
||||
|
||||
// kb
|
||||
var kb = new KnowledgeBase(body);
|
||||
|
||||
// sidebar
|
||||
this.sidebar = new wn.widgets.PageSidebar($(wrapper).find('.questions-tags').get(0), {
|
||||
sections: [
|
||||
{
|
||||
title: 'Top Tags',
|
||||
render: function(body) {
|
||||
new wn.widgets.TagCloud(body, 'Question', function(tag)
|
||||
{ kb.set_tag_filter(tag) });
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
set_title('Knowledge Base');
|
||||
}
|
||||
|
||||
// knowledge base object
|
||||
// has a box for search or ask a question
|
||||
// and list of top rated search results
|
||||
//
|
||||
function KnowledgeBase(w) {
|
||||
var me = this;
|
||||
this.sort_by = 'modified';
|
||||
this.tag_filter_dict = {};
|
||||
|
||||
this.make_search_bar = function() {
|
||||
this.search = $(w).find('.kb-search-wrapper textarea').get(0);
|
||||
|
||||
$(w).find('.btn.search').click(function() {
|
||||
me.run();
|
||||
})
|
||||
$(w).find('.btn.ask').click(function() {
|
||||
me.ask();
|
||||
})
|
||||
}
|
||||
|
||||
// ask a new question
|
||||
this.ask = function() {
|
||||
if(this.search.value==$(this.search).attr('default_text')) {
|
||||
msgprint('Please enter some text'); return;
|
||||
}
|
||||
this.add_question([]);
|
||||
}
|
||||
|
||||
// suggest a few users who can answer
|
||||
this.suggest = function() {
|
||||
this.dialog = new wn.widgets.Dialog({
|
||||
title: 'Suggest a users',
|
||||
width: 400,
|
||||
fields: [
|
||||
{fieldtype:'HTML', options:'Optional: Suggest a few users who can help you answer this question<br>'},
|
||||
{fieldtype:'Link', fieldname:'profile1', label:'1st User',options:'Profile'},
|
||||
{fieldtype:'Link', fieldname:'profile2', label:'2nd User',options:'Profile'},
|
||||
{fieldtype:'Link', fieldname:'profile3', label:'3rd User',options:'Profile'},
|
||||
{fieldtype:'Button', fieldname:'ask', label:'Add the Question'}
|
||||
]
|
||||
});
|
||||
this.dialog.fields_dict.ask.input.onclick = function() {
|
||||
me.dialog.hide();
|
||||
me.add_question(values(me.dialog.get_values()));
|
||||
}
|
||||
this.dialog.show();
|
||||
}
|
||||
|
||||
// add a new question to the database
|
||||
this.add_question = function(suggest_list) {
|
||||
$c_page('utilities', 'questions', 'add_question', {
|
||||
question: this.search.value,
|
||||
suggest: suggest_list
|
||||
}, function(r,rt) {
|
||||
$(me.search).val('').blur();
|
||||
me.run();
|
||||
})
|
||||
}
|
||||
|
||||
// where tags that filter will be displayed
|
||||
this.make_tag_filter_area = function() {
|
||||
this.tag_filters = $a(w, 'div', 'kb-tag-filter-area');
|
||||
$a(this.tag_filters,'span','',{marginRight:'4px',color:'#442'}, '<i>Showing for:</i>');
|
||||
this.tag_area = $a(this.tag_filters, 'span');
|
||||
}
|
||||
|
||||
// make a list of questions
|
||||
this.make_list = function() {
|
||||
this.make_tag_filter_area();
|
||||
this.list_area = $a(w, 'div', '', {marginRight:'13px'})
|
||||
this.no_result = $a(w, 'div','help_box',{display:'none'},'No questions asked yet! Be the first one to ask')
|
||||
|
||||
this.list = new wn.ui.Listing({
|
||||
parent: this.list_area,
|
||||
no_results_message: 'No questions found. Ask a new question!',
|
||||
appframe: wn.pages.questions.appframe,
|
||||
as_dict: 1,
|
||||
method: 'utilities.page.questions.questions.get_questions',
|
||||
get_args: function() {
|
||||
var args = {};
|
||||
if(me.search.value) {
|
||||
args.search_text = me.search.value;
|
||||
}
|
||||
if(me.tag_filter_dict) {
|
||||
args.tag_filters = keys(me.tag_filter_dict);
|
||||
}
|
||||
return args
|
||||
},
|
||||
render_row: function(parent, data, listing) {
|
||||
new KBQuestion(parent, data, me);
|
||||
}
|
||||
});
|
||||
|
||||
this.list.run();
|
||||
|
||||
}
|
||||
|
||||
// add a tag filter to the search in the
|
||||
// main page
|
||||
this.set_tag_filter = function(tag) {
|
||||
|
||||
// check if exists
|
||||
if(in_list(keys(me.tag_filter_dict), tag.label)) return;
|
||||
|
||||
// create a tag in filters
|
||||
var filter_tag = new SingleTag({
|
||||
parent: me.tag_area,
|
||||
label: tag.label,
|
||||
dt: 'Question',
|
||||
color: tag.color
|
||||
});
|
||||
|
||||
// remove tag from filters
|
||||
filter_tag.remove = function(tag_remove) {
|
||||
$(tag_remove.body).fadeOut();
|
||||
delete me.tag_filter_dict[tag_remove.label];
|
||||
|
||||
// hide everything?
|
||||
if(!keys(me.tag_filter_dict).length) {
|
||||
$(me.tag_filters).slideUp(); // hide
|
||||
}
|
||||
|
||||
// run
|
||||
me.run();
|
||||
}
|
||||
|
||||
// add to dict
|
||||
me.tag_filter_dict[tag.label] = filter_tag;
|
||||
$ds(me.tag_filters);
|
||||
|
||||
// run
|
||||
me.run();
|
||||
}
|
||||
this.run = function() {
|
||||
this.list.run();
|
||||
}
|
||||
|
||||
this.make_search_bar();
|
||||
this.make_list();
|
||||
|
||||
}
|
||||
|
||||
// single kb question
|
||||
// "question
|
||||
// points | tag list"
|
||||
|
||||
KBQuestion = function(parent, det, kb) {
|
||||
|
||||
this.make = function() {
|
||||
this.wrapper = $a(parent, 'div', 'kb-question-wrapper');
|
||||
this.q_area = $a($a(this.wrapper, 'div'), 'h3',
|
||||
'kb-questions link_type', {display:'inline', textDecoration:'none'}, det.question);
|
||||
if(det.answers==0) {
|
||||
$(this.q_area).addClass('un-answered')
|
||||
}
|
||||
|
||||
this.q_area.onclick = function() {
|
||||
var q = this;
|
||||
window.location.href = '#!question-view/' + q.id;
|
||||
//loadpage('question-view', function() { pscript.question_view(q.id, q.txt) })
|
||||
}
|
||||
|
||||
this.q_area.id = det.name; this.q_area.txt = det.question;
|
||||
|
||||
new KBItemToolbar({
|
||||
parent: this.wrapper,
|
||||
det: det,
|
||||
with_tags: 1,
|
||||
doctype: 'Question'
|
||||
}, kb)
|
||||
|
||||
}
|
||||
|
||||
|
||||
this.make()
|
||||
}
|
||||
|
||||
wn.require('app/js/kb_common.js');
|
||||
74
utilities/page/questions/questions.py
Normal file
74
utilities/page/questions/questions.py
Normal file
@@ -0,0 +1,74 @@
|
||||
# ERPNext - web based ERP (http://erpnext.com)
|
||||
# Copyright (C) 2012 Web Notes Technologies Pvt Ltd
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
|
||||
from webnotes.utils import load_json, cint, cstr
|
||||
import json
|
||||
|
||||
@webnotes.whitelist()
|
||||
def get_questions():
|
||||
"""get list of questions"""
|
||||
import json
|
||||
conds = ''
|
||||
|
||||
if 'search_text' in webnotes.form_dict:
|
||||
conds = ' and t1.question like "%'+ webnotes.form_dict['search_text'] + '%"'
|
||||
|
||||
if 'tag_filters' in webnotes.form_dict:
|
||||
tag_filters = json.loads(webnotes.form_dict['tag_filters'])
|
||||
for t in tag_filters:
|
||||
conds += ' and t1._user_tags like "%'+ t +'%"'
|
||||
|
||||
return webnotes.conn.sql("""select t1.name, t1.owner, t1.question, t1.modified, t1._user_tags,
|
||||
t2.first_name, t2.last_name, (select count(*) from tabAnswer where
|
||||
tabAnswer.question = t1.name) as answers
|
||||
from tabQuestion t1, tabProfile t2
|
||||
where t1.docstatus!=2
|
||||
and t1.owner = t2.name
|
||||
%(conds)s
|
||||
order by t1.modified desc""" % {"conds":conds}, as_dict=1)
|
||||
|
||||
# add a new question
|
||||
@webnotes.whitelist()
|
||||
def add_question(arg):
|
||||
args = load_json(arg)
|
||||
|
||||
from webnotes.model.doc import Document
|
||||
d = Document('Question')
|
||||
d.question = args['question']
|
||||
d.points = 1
|
||||
d.save(1)
|
||||
|
||||
if args['suggest']:
|
||||
from utilities.page.messages import messages
|
||||
for s in args['suggest']:
|
||||
if s:
|
||||
messages.post(json.dumps({
|
||||
'contact': s,
|
||||
'txt': 'Please help me and answer the question "%s" in the Knowledge Base' % d.question,
|
||||
'notify': 1
|
||||
}))
|
||||
|
||||
@webnotes.whitelist()
|
||||
def delete(arg):
|
||||
"""
|
||||
delete a question or answer (called from kb toolbar)
|
||||
"""
|
||||
args = load_json(arg)
|
||||
from webnotes.model import delete_doc
|
||||
delete_doc(args['dt'], args['dn'])
|
||||
27
utilities/page/questions/questions.txt
Normal file
27
utilities/page/questions/questions.txt
Normal file
@@ -0,0 +1,27 @@
|
||||
# Page, questions
|
||||
[
|
||||
|
||||
# These values are common in all dictionaries
|
||||
{
|
||||
'creation': '2011-05-04 11:09:49',
|
||||
'docstatus': 0,
|
||||
'modified': '2011-03-29 13:53:57',
|
||||
'modified_by': 'Administrator',
|
||||
'owner': 'Administrator'
|
||||
},
|
||||
|
||||
# These values are common for all Page
|
||||
{
|
||||
'doctype': 'Page',
|
||||
'module': 'Utilities',
|
||||
'name': '__common__',
|
||||
'page_name': 'Questions',
|
||||
'standard': 'Yes'
|
||||
},
|
||||
|
||||
# Page, questions
|
||||
{
|
||||
'doctype': 'Page',
|
||||
'name': 'questions'
|
||||
}
|
||||
]
|
||||
1
utilities/page/todo/__init__.py
Normal file
1
utilities/page/todo/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from __future__ import unicode_literals
|
||||
50
utilities/page/todo/todo.css
Normal file
50
utilities/page/todo/todo.css
Normal file
@@ -0,0 +1,50 @@
|
||||
.todoitem {
|
||||
padding-bottom: 3px;
|
||||
min-height: 45px;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.todoitem .label {
|
||||
width: 50px;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
margin-right: 11px;
|
||||
margin-top: 3px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.todoitem .close {
|
||||
margin-left: 5px;
|
||||
font-size: 17px;
|
||||
}
|
||||
|
||||
.todoitem .close-span {
|
||||
display: inline-block;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.todoitem .description {
|
||||
padding: 3px 0px;
|
||||
display: inline-block;
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
#todo-list, #assigned-todo-list {
|
||||
float: left;
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.todo-separator {
|
||||
border-bottom: 1px solid #DEB85F;
|
||||
margin-bottom: 5px;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.todo-content {
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
||||
.todo-layout {
|
||||
background-color: #FFFDC9;
|
||||
min-height: 300px;
|
||||
}
|
||||
16
utilities/page/todo/todo.html
Normal file
16
utilities/page/todo/todo.html
Normal file
@@ -0,0 +1,16 @@
|
||||
<div class="layout-wrapper layout-wrapper-background">
|
||||
<div class="appframe-area"></div>
|
||||
<div class="layout-main todo-layout">
|
||||
<div>
|
||||
<div id="todo-list">
|
||||
<h4>My List</h4><br>
|
||||
<div class="todo-content"></div>
|
||||
</div>
|
||||
<div id="assigned-todo-list">
|
||||
<h4>Assigned to others</h4><br>
|
||||
<div class="todo-content"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="clear: both"></div>
|
||||
</div>
|
||||
</div>
|
||||
205
utilities/page/todo/todo.js
Normal file
205
utilities/page/todo/todo.js
Normal file
@@ -0,0 +1,205 @@
|
||||
// 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/>.
|
||||
|
||||
wn.provide('erpnext.todo');
|
||||
|
||||
erpnext.todo.refresh = function() {
|
||||
wn.call({
|
||||
method: 'utilities.page.todo.todo.get',
|
||||
callback: function(r,rt) {
|
||||
var todo_list = $('#todo-list div.todo-content');
|
||||
var assigned_todo_list = $('#assigned-todo-list div.todo-content');
|
||||
todo_list.empty();
|
||||
assigned_todo_list.empty();
|
||||
|
||||
var nothing_to_do = function() {
|
||||
$('#todo-list div.todo-content')
|
||||
.html('<div class="help-box">Nothing to do :)</div>');
|
||||
}
|
||||
|
||||
var nothing_delegated = function() {
|
||||
$('#assigned-todo-list div.todo-content')
|
||||
.html('<div class="help-box">Nothing assigned to other users. \
|
||||
Use "Assign To" in a form to delegate work.</div>');
|
||||
}
|
||||
|
||||
if(r.message) {
|
||||
for(var i in r.message) {
|
||||
new erpnext.todo.ToDoItem(r.message[i]);
|
||||
}
|
||||
if (!todo_list.html()) { nothing_to_do(); }
|
||||
if (!assigned_todo_list.html()) { nothing_delegated(); }
|
||||
} else {
|
||||
nothing_to_do();
|
||||
nothing_delegated();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
erpnext.todo.ToDoItem = Class.extend({
|
||||
init: function(todo) {
|
||||
label_map = {
|
||||
'High': 'label-important',
|
||||
'Medium': 'label-info',
|
||||
'Low':''
|
||||
}
|
||||
todo.labelclass = label_map[todo.priority];
|
||||
todo.userdate = dateutil.str_to_user(todo.date) || '';
|
||||
|
||||
todo.fullname = '';
|
||||
if(todo.assigned_by) {
|
||||
var assigned_by = wn.boot.user_info[todo.assigned_by]
|
||||
todo.fullname = repl("[By %(fullname)s] ", {
|
||||
fullname: (assigned_by ? assigned_by.fullname : todo.assigned_by),
|
||||
});
|
||||
}
|
||||
|
||||
var parent_list = "#todo-list";
|
||||
if(todo.owner !== user) {
|
||||
parent_list = "#assigned-todo-list";
|
||||
var owner = wn.boot.user_info[todo.owner];
|
||||
todo.fullname = repl("[To %(fullname)s] ", {
|
||||
fullname: (owner ? owner.fullname : todo.owner),
|
||||
});
|
||||
}
|
||||
parent_list += " div.todo-content";
|
||||
|
||||
if(todo.reference_name && todo.reference_type) {
|
||||
todo.link = repl('<br><a href="#!Form/%(reference_type)s/%(reference_name)s">\
|
||||
%(reference_type)s: %(reference_name)s</a>', todo);
|
||||
} else if(todo.reference_type) {
|
||||
todo.link = repl('<br><a href="#!List/%(reference_type)s">\
|
||||
%(reference_type)s</a>', todo);
|
||||
} else {
|
||||
todo.link = '';
|
||||
}
|
||||
if(!todo.description) todo.description = '';
|
||||
|
||||
todo.desc = wn.markdown(todo.description);
|
||||
|
||||
$(parent_list).append(repl('\
|
||||
<div class="todoitem">\
|
||||
<span class="label %(labelclass)s">%(priority)s</span>\
|
||||
<span class="description">\
|
||||
<span class="help" style="margin-right: 7px">%(userdate)s</span>\
|
||||
%(fullname)s%(desc)s\
|
||||
<span class="popup-on-click"><a href="#"> [edit]</a></span>\
|
||||
<span class="ref_link">%(link)s</span>\
|
||||
</span>\
|
||||
<span class="close-span"><a href="#" class="close">×</a></span>\
|
||||
</div>\
|
||||
<div class="todo-separator"></div>', todo));
|
||||
$todo = $(parent_list + ' div.todoitem:last');
|
||||
|
||||
if(todo.checked) {
|
||||
$todo.find('.description').css('text-decoration', 'line-through');
|
||||
}
|
||||
|
||||
if(!todo.reference_type)
|
||||
$todo.find('.ref_link').toggle(false);
|
||||
|
||||
$todo.find('.popup-on-click')
|
||||
.data('todo', todo)
|
||||
.click(function() {
|
||||
erpnext.todo.make_dialog($(this).data('todo'));
|
||||
return false;
|
||||
});
|
||||
|
||||
$todo.find('.close')
|
||||
.data('name', todo.name)
|
||||
.click(function() {
|
||||
$(this).parent().css('opacity', 0.5);
|
||||
wn.call({
|
||||
method:'utilities.page.todo.todo.delete',
|
||||
args: {name: $(this).data('name')},
|
||||
callback: function() {
|
||||
erpnext.todo.refresh();
|
||||
}
|
||||
});
|
||||
return false;
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
erpnext.todo.make_dialog = function(det) {
|
||||
if(!erpnext.todo.dialog) {
|
||||
var dialog = new wn.widgets.Dialog();
|
||||
dialog.make({
|
||||
width: 480,
|
||||
title: 'To Do',
|
||||
fields: [
|
||||
{fieldtype:'Text', fieldname:'description', label:'Description',
|
||||
reqd:1, description:'Use <a href="#markdown-reference">markdown</a> to \
|
||||
format content'},
|
||||
{fieldtype:'Date', fieldname:'date', label:'Event Date', reqd:1},
|
||||
{fieldtype:'Check', fieldname:'checked', label:'Completed'},
|
||||
{fieldtype:'Select', fieldname:'priority', label:'Priority', reqd:1, 'options':['Medium','High','Low'].join('\n')},
|
||||
{fieldtype:'Button', fieldname:'save', label:'Save'}
|
||||
]
|
||||
});
|
||||
|
||||
dialog.fields_dict.save.input.onclick = function() {
|
||||
erpnext.todo.save(this);
|
||||
}
|
||||
erpnext.todo.dialog = dialog;
|
||||
}
|
||||
|
||||
if(det) {
|
||||
erpnext.todo.dialog.set_values({
|
||||
date: det.date,
|
||||
priority: det.priority,
|
||||
description: det.description,
|
||||
checked: det.checked
|
||||
});
|
||||
erpnext.todo.dialog.det = det;
|
||||
}
|
||||
erpnext.todo.dialog.show();
|
||||
|
||||
}
|
||||
|
||||
erpnext.todo.save = function(btn) {
|
||||
var d = erpnext.todo.dialog;
|
||||
var det = d.get_values();
|
||||
|
||||
if(!det) {
|
||||
return;
|
||||
}
|
||||
|
||||
det.name = d.det.name || '';
|
||||
wn.call({
|
||||
method:'utilities.page.todo.todo.edit',
|
||||
args: det,
|
||||
btn: btn,
|
||||
callback: function() {
|
||||
erpnext.todo.dialog.hide();
|
||||
erpnext.todo.refresh();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
wn.pages.todo.onload = function(wrapper) {
|
||||
// create app frame
|
||||
wrapper.appframe = new wn.ui.AppFrame($(wrapper).find('.appframe-area'), 'To Do');
|
||||
wrapper.appframe.add_button('Refresh', erpnext.todo.refresh, 'icon-refresh');
|
||||
wrapper.appframe.add_button('Add', function() {
|
||||
erpnext.todo.make_dialog({
|
||||
date:get_today(), priority:'Medium', checked:0, description:''});
|
||||
}, 'icon-plus');
|
||||
|
||||
// load todos
|
||||
erpnext.todo.refresh();
|
||||
}
|
||||
64
utilities/page/todo/todo.py
Normal file
64
utilities/page/todo/todo.py
Normal file
@@ -0,0 +1,64 @@
|
||||
# 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.model.doc import Document
|
||||
|
||||
@webnotes.whitelist()
|
||||
def get(arg=None):
|
||||
"""get todo list"""
|
||||
return webnotes.conn.sql("""select name, owner, description, date,
|
||||
priority, checked, reference_type, reference_name, assigned_by
|
||||
from `tabToDo` where (owner=%s or assigned_by=%s)
|
||||
order by field(priority, 'High', 'Medium', 'Low') asc, date asc""",
|
||||
(webnotes.session['user'], webnotes.session['user']), as_dict=1)
|
||||
|
||||
@webnotes.whitelist()
|
||||
def edit(arg=None):
|
||||
import markdown2
|
||||
args = webnotes.form_dict
|
||||
|
||||
d = Document('ToDo', args.get('name') or None)
|
||||
d.description = args['description']
|
||||
d.date = args['date']
|
||||
d.priority = args['priority']
|
||||
d.checked = args.get('checked', 0)
|
||||
if not d.owner: d.owner = webnotes.session['user']
|
||||
d.save(not args.get('name') and 1 or 0)
|
||||
|
||||
if args.get('name') and d.checked:
|
||||
notify_assignment(d)
|
||||
|
||||
return d.name
|
||||
|
||||
@webnotes.whitelist()
|
||||
def delete(arg=None):
|
||||
name = webnotes.form_dict['name']
|
||||
d = Document('ToDo', name)
|
||||
if d and d.name and d.owner != webnotes.session['user']:
|
||||
notify_assignment(d)
|
||||
webnotes.conn.sql("delete from `tabToDo` where name = %s", name)
|
||||
|
||||
def notify_assignment(d):
|
||||
doc_type = d.reference_type
|
||||
doc_name = d.reference_name
|
||||
assigned_by = d.assigned_by
|
||||
|
||||
if doc_type and doc_name and assigned_by:
|
||||
from webnotes.widgets.form import assign_to
|
||||
assign_to.notify_assignment(assigned_by, d.owner, doc_type, doc_name)
|
||||
|
||||
28
utilities/page/todo/todo.txt
Normal file
28
utilities/page/todo/todo.txt
Normal file
@@ -0,0 +1,28 @@
|
||||
# Page, todo
|
||||
[
|
||||
|
||||
# These values are common in all dictionaries
|
||||
{
|
||||
'creation': '2012-02-23 13:59:03',
|
||||
'docstatus': 0,
|
||||
'modified': '2012-02-23 13:59:03',
|
||||
'modified_by': u'Administrator',
|
||||
'owner': u'Administrator'
|
||||
},
|
||||
|
||||
# These values are common for all Page
|
||||
{
|
||||
'doctype': 'Page',
|
||||
'module': u'Utilities',
|
||||
'name': '__common__',
|
||||
'page_name': u'todo',
|
||||
'standard': u'Yes',
|
||||
'title': u'To Do'
|
||||
},
|
||||
|
||||
# Page, todo
|
||||
{
|
||||
'doctype': 'Page',
|
||||
'name': u'todo'
|
||||
}
|
||||
]
|
||||
1
utilities/page/trash/__init__.py
Normal file
1
utilities/page/trash/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from __future__ import unicode_literals
|
||||
4
utilities/page/trash/trash.html
Normal file
4
utilities/page/trash/trash.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<div class="layout_wrapper">
|
||||
<div id="trash_header"></div>
|
||||
<div id="trash_div" style="margin: 0px;"></div>
|
||||
</div>
|
||||
144
utilities/page/trash/trash.js
Normal file
144
utilities/page/trash/trash.js
Normal file
@@ -0,0 +1,144 @@
|
||||
// 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/>.
|
||||
|
||||
pscript['onload_Trash'] = function() {
|
||||
|
||||
// header and toolbar
|
||||
var h = new PageHeader('trash_header','Trash Bin','Restore the documents that you have trashed')
|
||||
|
||||
if(!pscript.trash_bin) pscript.trash_bin = new pscript.Trash();
|
||||
}
|
||||
|
||||
pscript.Trash = function() {
|
||||
// create UI elements
|
||||
this.wrapper = $i('trash_div');
|
||||
|
||||
this.head = $a(this.wrapper, 'div');
|
||||
this.body = $a(this.wrapper, 'div');
|
||||
$y(this.body, {margin:'8px'})
|
||||
|
||||
this.make_head();
|
||||
this.load_masters();
|
||||
}
|
||||
|
||||
// Make Button
|
||||
// ------------
|
||||
pscript.Trash.prototype.make_button = function(label, area){
|
||||
var me = this;
|
||||
var w = $a(area, 'div', '', {margin:'8px'});
|
||||
var t = make_table(w,1,1,'400px',['50%','50%']);
|
||||
var s = $a($td(t,0,0),'button');
|
||||
s.innerHTML = label;
|
||||
s.wrapper = w;
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
// Make Head
|
||||
// -------------
|
||||
pscript.Trash.prototype.make_head = function() {
|
||||
var me = this;
|
||||
|
||||
var make_select = function(label) {
|
||||
var w = $a(me.head, 'div', '', {margin:'8px'});
|
||||
var t = make_table(w,1,2,'400px',['50%','50%']);
|
||||
$td(t,0,0).innerHTML = label;
|
||||
var s = $a($td(t,0,1),'select','',{width:'140px'});
|
||||
s.wrapper = w;
|
||||
return s;
|
||||
}
|
||||
|
||||
// Select Master Name
|
||||
this.master_select = make_select('Select Master');
|
||||
|
||||
var me = this;
|
||||
// Get Records
|
||||
this.get_records_button = me.make_button('Get Records', me.head);
|
||||
this.get_records_button.onclick = function() {
|
||||
me.get_records();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Load Masters
|
||||
// -------------
|
||||
pscript.Trash.prototype.load_masters = function(){
|
||||
var me = this;
|
||||
var callback = function(r, rt){
|
||||
// Masters
|
||||
empty_select(me.master_select);
|
||||
add_sel_options(me.master_select,add_lists(['All'], r.message), 'All');
|
||||
}
|
||||
$c_obj('Trash Control','get_masters','',callback);
|
||||
}
|
||||
|
||||
|
||||
// Get Records
|
||||
// -----------
|
||||
pscript.Trash.prototype.get_records = function(){
|
||||
var me = this;
|
||||
me.body.innerHTML = '';
|
||||
var callback = function(r, rt){
|
||||
if(r.message) me.generate_trash_records(r.message);
|
||||
else msgprint("No Records Found");
|
||||
}
|
||||
$c_obj('Trash Control','get_trash_records',sel_val(me.master_select),callback);
|
||||
}
|
||||
|
||||
|
||||
// Generate Trash Records
|
||||
// -----------------------
|
||||
pscript.Trash.prototype.generate_trash_records = function(rec_dict){
|
||||
var me = this;
|
||||
pscript.all_checkboxes = [];
|
||||
mnames = keys(rec_dict).sort();
|
||||
for(var i = 0; i < mnames.length; i ++){
|
||||
var head = $a(me.body, 'h3'); head.innerHTML = mnames[i];
|
||||
var rec_table = make_table(me.body,rec_dict[mnames[i]].length,2,'375px',['350px','25px'],{border:'1px solid #AAA',padding:'2px'});
|
||||
for(var j = 0; j < rec_dict[mnames[i]].length; j++){
|
||||
$a_input($td(rec_table,j,0), 'data');
|
||||
$td(rec_table,j,0).innerHTML = rec_dict[mnames[i]][j];
|
||||
var chk = $a_input($td(rec_table,j,1), 'checkbox');
|
||||
chk.master = mnames[i];
|
||||
chk.record = rec_dict[mnames[i]][j];
|
||||
pscript.all_checkboxes.push(chk);
|
||||
}
|
||||
}
|
||||
this.restore_button = me.make_button('Restore Selected', me.body);
|
||||
this.restore_button.onclick = function() {
|
||||
me.restore_records(0);
|
||||
}
|
||||
this.restore_all_button = me.make_button('Restore All', me.body);
|
||||
this.restore_all_button.onclick = function() {
|
||||
me.restore_records(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Restore Records
|
||||
// ---------------
|
||||
pscript.Trash.prototype.restore_records = function(restore_all){
|
||||
var me = this;
|
||||
var out = {};
|
||||
for(i in pscript.all_checkboxes) {
|
||||
c = pscript.all_checkboxes[i];
|
||||
if (restore_all || (!restore_all && c.checked)) {
|
||||
if(!out[c.master]) out[c.master] = [c.record];
|
||||
else {out[c.master].push(c.record);}
|
||||
}
|
||||
}
|
||||
$c_obj('Trash Control','restore_records',JSON.stringify(out),function(r, rt){me.get_records();})
|
||||
}
|
||||
72
utilities/page/trash/trash.txt
Normal file
72
utilities/page/trash/trash.txt
Normal file
@@ -0,0 +1,72 @@
|
||||
# Page, Trash
|
||||
[
|
||||
|
||||
# These values are common in all dictionaries
|
||||
{
|
||||
'creation': '2010-10-12 15:19:32',
|
||||
'docstatus': 0,
|
||||
'modified': '2010-12-30 11:44:36',
|
||||
'modified_by': 'Administrator',
|
||||
'owner': 'Administrator'
|
||||
},
|
||||
|
||||
# These values are common for all Page
|
||||
{
|
||||
'doctype': 'Page',
|
||||
'module': 'Utilities',
|
||||
'name': '__common__',
|
||||
'page_name': 'Trash',
|
||||
'show_in_menu': 0,
|
||||
'standard': 'Yes'
|
||||
},
|
||||
|
||||
# These values are common for all Page Role
|
||||
{
|
||||
'doctype': 'Page Role',
|
||||
'name': '__common__',
|
||||
'parent': 'Trash',
|
||||
'parentfield': 'roles',
|
||||
'parenttype': 'Page'
|
||||
},
|
||||
|
||||
# Page, Trash
|
||||
{
|
||||
'doctype': 'Page',
|
||||
'name': 'Trash'
|
||||
},
|
||||
|
||||
# Page Role
|
||||
{
|
||||
'doctype': 'Page Role',
|
||||
'idx': 1,
|
||||
'role': 'Administrator'
|
||||
},
|
||||
|
||||
# Page Role
|
||||
{
|
||||
'doctype': 'Page Role',
|
||||
'idx': 2,
|
||||
'role': 'Sales Master Manager'
|
||||
},
|
||||
|
||||
# Page Role
|
||||
{
|
||||
'doctype': 'Page Role',
|
||||
'idx': 3,
|
||||
'role': 'Material Master Manager'
|
||||
},
|
||||
|
||||
# Page Role
|
||||
{
|
||||
'doctype': 'Page Role',
|
||||
'idx': 4,
|
||||
'role': 'Purchase Master Manager'
|
||||
},
|
||||
|
||||
# Page Role
|
||||
{
|
||||
'doctype': 'Page Role',
|
||||
'idx': 5,
|
||||
'role': 'Accounts Manager'
|
||||
}
|
||||
]
|
||||
1
utilities/page/users/__init__.py
Normal file
1
utilities/page/users/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from __future__ import unicode_literals
|
||||
46
utilities/page/users/users.css
Normal file
46
utilities/page/users/users.css
Normal file
@@ -0,0 +1,46 @@
|
||||
.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;
|
||||
}
|
||||
0
utilities/page/users/users.html
Normal file
0
utilities/page/users/users.html
Normal file
415
utilities/page/users/users.js
Normal file
415
utilities/page/users/users.js
Normal file
@@ -0,0 +1,415 @@
|
||||
// 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 = 'images/lib/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.widgets.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.widgets.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.widgets.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.widgets.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.widgets.Dialog({
|
||||
title:'Role Permissions',
|
||||
width: 500
|
||||
});
|
||||
}
|
||||
})
|
||||
202
utilities/page/users/users.py
Normal file
202
utilities/page/users/users.py
Normal file
@@ -0,0 +1,202 @@
|
||||
# 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
|
||||
"""
|
||||
28
utilities/page/users/users.txt
Normal file
28
utilities/page/users/users.txt
Normal file
@@ -0,0 +1,28 @@
|
||||
# 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'
|
||||
}
|
||||
]
|
||||
1
utilities/page/wip_monitor/__init__.py
Normal file
1
utilities/page/wip_monitor/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from __future__ import unicode_literals
|
||||
2
utilities/page/wip_monitor/wip_monitor.html
Normal file
2
utilities/page/wip_monitor/wip_monitor.html
Normal file
@@ -0,0 +1,2 @@
|
||||
<div id="wip_head"></div>
|
||||
<div id="wip_body" style="margin:16px"></div>
|
||||
104
utilities/page/wip_monitor/wip_monitor.js
Normal file
104
utilities/page/wip_monitor/wip_monitor.js
Normal file
@@ -0,0 +1,104 @@
|
||||
// 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/>.
|
||||
|
||||
pscript['onload_WIP Monitor'] = function(){
|
||||
wip = new WIP_Monitor();
|
||||
|
||||
var h = new PageHeader('wip_head','Work in Progress Monitor','A quick glance at your work in progress and pipeline');
|
||||
h.add_button('Refresh', function(){ wip = new WIP_Monitor();}, 1, 'ui-icon-refresh');
|
||||
|
||||
}
|
||||
|
||||
// Work In Progress Monitor
|
||||
// =========================================================================================================================================================
|
||||
WIP_Monitor = function(){
|
||||
var me = this;
|
||||
this.row_index = 0;
|
||||
$c_obj('Home Control','get_wip_counts','',function(r,rt){
|
||||
me.make_wip_dashboard(r.message);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Make wip dashboard
|
||||
// ------------------
|
||||
WIP_Monitor.prototype.make_wip_dashboard = function(wip_dict)
|
||||
{
|
||||
var me = this;
|
||||
// list of doctypes which user can read
|
||||
var can_read_dt = ['Lead', 'Opportunity', 'Sales Order', 'Sales Invoice', 'Purchase Request', 'Purchase Order', 'Purchase Invoice', 'Delivery Note', 'Task', 'Serial No'];
|
||||
|
||||
$i('wip_body').innerHTML = '';
|
||||
this.tab = make_table('wip_body',1,0,'100%',[],{padding:'4px'});
|
||||
|
||||
for(var k=0; k<can_read_dt.length; k++){
|
||||
|
||||
// check if the user can read these doctypes
|
||||
if(in_list(profile.can_read, get_doctype_label(can_read_dt[k])))
|
||||
{
|
||||
var work = can_read_dt[k];
|
||||
if(this.tab.rows[this.row_index].cells.length==2){
|
||||
this.row_index = this.row_index + 1;
|
||||
this.tab.insertRow(this.tab.rows.length);
|
||||
}
|
||||
var parent = this.tab.rows[this.row_index].insertCell(this.tab.rows[this.row_index].cells.length);
|
||||
$y(parent, {paddingBottom:'16px', width:'50%', paddingLeft:'8px'})
|
||||
me.show_wip_dashboard(parent, work, wip_dict[work]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Show wip dashboard
|
||||
// ------------------
|
||||
WIP_Monitor.prototype.show_wip_dashboard = function(parent, head, report_dict)
|
||||
{
|
||||
var me = this;
|
||||
var report_dt
|
||||
|
||||
// dictionary for labels to be displayed
|
||||
var wip_lbl_map = {'Lead':'Lead', 'Opportunity':'Enquiries', 'Sales Order':'Sales Order', 'Sales Invoice':'Invoices', 'Purchase Request':'Purchase Request', 'Purchase Order':'Purchase Order', 'Purchase Invoice':'Bills', 'Delivery Note':'Delivery Note', 'Task':'Tasks', 'Serial No':'Maintenance'};
|
||||
|
||||
// header
|
||||
var h = $a(parent,'h3');
|
||||
|
||||
h.innerHTML = wip_lbl_map[head];
|
||||
report_dt = head;
|
||||
|
||||
for(report in report_dict){
|
||||
me.make_report_body(parent, report, report_dict[report], report_dt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Make wip report body
|
||||
// --------------------
|
||||
WIP_Monitor.prototype.make_report_body = function(parent, lbl, records, rep_dt)
|
||||
{
|
||||
var me = this;
|
||||
|
||||
dt_color = lbl=='Overdue' ? 'red' : 'black';
|
||||
var tab2 = make_table(parent,1,2, '70%', ['10%', '90%'], {padding:'4px'});
|
||||
|
||||
// no of records
|
||||
var s1 = $a($td(tab2,0,0), 'span', '', {fontWeight:'bold', fontSize:'12px', color:dt_color});
|
||||
s1.innerHTML = records;
|
||||
|
||||
// link to report
|
||||
var s1 = $a($td(tab2,0,1), 'span', 'link_type', {cursor:'pointer', color:'#DFH'});
|
||||
s1.dt = rep_dt; s1.cn = rep_dt + '-' + lbl; s1.innerHTML = lbl;
|
||||
s1.onclick = function() { loadreport(this.dt, this.cn); }
|
||||
}
|
||||
28
utilities/page/wip_monitor/wip_monitor.txt
Normal file
28
utilities/page/wip_monitor/wip_monitor.txt
Normal file
@@ -0,0 +1,28 @@
|
||||
# Page, WIP Monitor
|
||||
[
|
||||
|
||||
# These values are common in all dictionaries
|
||||
{
|
||||
'creation': '2010-12-14 10:23:29',
|
||||
'docstatus': 0,
|
||||
'modified': '2011-01-04 11:12:39',
|
||||
'modified_by': 'Administrator',
|
||||
'owner': 'Administrator'
|
||||
},
|
||||
|
||||
# These values are common for all Page
|
||||
{
|
||||
'doctype': 'Page',
|
||||
'module': 'Utilities',
|
||||
'name': '__common__',
|
||||
'page_name': 'WIP Monitor',
|
||||
'show_in_menu': 0,
|
||||
'standard': 'Yes'
|
||||
},
|
||||
|
||||
# Page, WIP Monitor
|
||||
{
|
||||
'doctype': 'Page',
|
||||
'name': 'WIP Monitor'
|
||||
}
|
||||
]
|
||||
257
utilities/transaction_base.py
Normal file
257
utilities/transaction_base.py
Normal file
@@ -0,0 +1,257 @@
|
||||
# ERPNext - web based ERP (http://erpnext.com)
|
||||
# Copyright (C) 2012 Web Notes Technologies Pvt Ltd
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
from webnotes.utils import load_json, cint, cstr, flt, get_defaults
|
||||
from webnotes.model.doc import Document, addchild, getchildren
|
||||
from webnotes.model.doclist import getlist, copy_doclist
|
||||
from webnotes.model.code import get_obj
|
||||
from webnotes import msgprint
|
||||
|
||||
class TransactionBase:
|
||||
|
||||
# Get Customer Default Primary Address - first load
|
||||
# -----------------------
|
||||
def get_default_customer_address(self, args=''):
|
||||
address_text, address_name = self.get_address_text(customer=self.doc.customer)
|
||||
contact_text, contact_name, contact_email, contact_mobile = self.get_contact_text(customer=self.doc.customer)
|
||||
self.doc.customer_address = address_name or ''
|
||||
self.doc.contact_person = contact_name or ''
|
||||
self.doc.address_display = address_text or ''
|
||||
self.doc.contact_display = contact_text or ''
|
||||
self.doc.contact_email = contact_email or ''
|
||||
self.doc.contact_mobile = contact_mobile or ''
|
||||
|
||||
if args != 'onload':
|
||||
self.get_customer_details(self.doc.customer)
|
||||
self.get_sales_person(self.doc.customer)
|
||||
|
||||
# Get Customer Default Shipping Address - first load
|
||||
# -----------------------
|
||||
def get_default_customer_shipping_address(self, args=''):
|
||||
address_text, address_name = self.get_address_text(customer=self.doc.customer,is_shipping_address=1)
|
||||
contact_text, contact_name, contact_email, contact_mobile = self.get_contact_text(customer=self.doc.customer)
|
||||
self.doc.customer_address = address_name or ''
|
||||
self.doc.contact_person = contact_name or ''
|
||||
self.doc.address_display = address_text or ''
|
||||
self.doc.contact_display = contact_text or ''
|
||||
self.doc.contact_email = contact_email or ''
|
||||
self.doc.contact_mobile = contact_mobile or ''
|
||||
|
||||
if self.doc.doctype != 'Quotation' and args != 'onload':
|
||||
self.get_customer_details(self.doc.customer)
|
||||
self.get_sales_person(self.doc.customer)
|
||||
|
||||
# Get Customer Address
|
||||
# -----------------------
|
||||
def get_customer_address(self, args):
|
||||
args = load_json(args)
|
||||
address_text, address_name = self.get_address_text(address_name=args['address'])
|
||||
contact_text, contact_name, contact_email, contact_mobile = self.get_contact_text(contact_name=args['contact'])
|
||||
ret = {
|
||||
'customer_address' : address_name,
|
||||
'contact_person' : contact_name,
|
||||
'address_display' : address_text,
|
||||
'contact_display' : contact_text,
|
||||
'contact_email' : contact_email,
|
||||
'contact_mobile' : contact_mobile
|
||||
}
|
||||
return ret
|
||||
|
||||
# Get Address Text
|
||||
# -----------------------
|
||||
def get_address_text(self, customer=None, address_name=None, supplier=None, is_shipping_address=None):
|
||||
if customer:
|
||||
cond = customer and 'customer="%s"' % customer or 'name="%s"' % address_name
|
||||
elif supplier:
|
||||
cond = supplier and 'supplier="%s"' % supplier or 'name="%s"' % address_name
|
||||
else:
|
||||
cond = 'name="%s"' % address_name
|
||||
|
||||
if is_shipping_address:
|
||||
details = webnotes.conn.sql("select name, address_line1, address_line2, city, country, pincode, state, phone, fax from `tabAddress` where %s and docstatus != 2 order by is_shipping_address desc limit 1" % cond, as_dict = 1)
|
||||
else:
|
||||
details = webnotes.conn.sql("select name, address_line1, address_line2, city, country, pincode, state, phone, fax from `tabAddress` where %s and docstatus != 2 order by is_primary_address desc limit 1" % cond, as_dict = 1)
|
||||
|
||||
extract = lambda x: details and details[0] and details[0].get(x,'') or ''
|
||||
address_fields = [('','address_line1'),('\n','address_line2'),('\n','city'),(' ','pincode'),('\n','state'),('\n','country'),('\nPhone: ','phone'),('\nFax: ', 'fax')]
|
||||
address_display = ''.join([a[0]+extract(a[1]) for a in address_fields if extract(a[1])])
|
||||
if address_display.startswith('\n'): address_display = address_display[1:]
|
||||
|
||||
address_name = details and details[0]['name'] or ''
|
||||
return address_display, address_name
|
||||
|
||||
# Get Contact Text
|
||||
# -----------------------
|
||||
def get_contact_text(self, customer=None, contact_name=None, supplier=None):
|
||||
if customer:
|
||||
cond = customer and 'customer="%s"' % customer or 'name="%s"' % contact_name
|
||||
elif supplier:
|
||||
cond = supplier and 'supplier="%s"' % supplier or 'name="%s"' % contact_name
|
||||
else:
|
||||
cond = 'name="%s"' % contact_name
|
||||
|
||||
details = webnotes.conn.sql("select name, first_name, last_name, email_id, phone, mobile_no, department, designation from `tabContact` where %s and docstatus != 2 order by is_primary_contact desc limit 1" % cond, as_dict = 1)
|
||||
|
||||
extract = lambda x: details and details[0] and details[0].get(x,'') or ''
|
||||
contact_fields = [('','first_name'),(' ','last_name')]
|
||||
contact_display = ''.join([a[0]+cstr(extract(a[1])) for a in contact_fields if extract(a[1])])
|
||||
if contact_display.startswith('\n'): contact_display = contact_display[1:]
|
||||
|
||||
contact_name = details and details[0]['name'] or ''
|
||||
contact_email = details and details[0]['email_id'] or ''
|
||||
contact_mobile = details and details[0]['mobile_no'] or ''
|
||||
return contact_display, contact_name, contact_email, contact_mobile
|
||||
|
||||
def get_customer_details(self, name):
|
||||
"""
|
||||
Get customer details like name, group, territory
|
||||
and other such defaults
|
||||
"""
|
||||
customer_details = webnotes.conn.sql("""\
|
||||
select
|
||||
customer_name, customer_group, territory,
|
||||
default_sales_partner, default_commission_rate, default_currency,
|
||||
default_price_list
|
||||
from `tabCustomer`
|
||||
where name = %s and docstatus < 2""", name, as_dict=1)
|
||||
if customer_details:
|
||||
for f in ['customer_name', 'customer_group', 'territory']:
|
||||
self.doc.fields[f] = customer_details[0][f] or self.doc.fields.get(f)
|
||||
|
||||
# fields prepended with default in Customer doctype
|
||||
for f in ['sales_partner', 'commission_rate', 'currency']:
|
||||
self.doc.fields[f] = customer_details[0]["default_%s" % f] or self.doc.fields.get(f)
|
||||
|
||||
# optionally fetch default price list from Customer Group
|
||||
self.doc.price_list_name = (customer_details[0]['default_price_list']
|
||||
or webnotes.conn.get_value('Customer Group', self.doc.customer_group,
|
||||
'default_price_list')
|
||||
or self.doc.fields.get('price_list_name'))
|
||||
|
||||
# Get Customer Shipping Address
|
||||
# -----------------------
|
||||
def get_shipping_address(self, name):
|
||||
details = webnotes.conn.sql("select name, address_line1, address_line2, city, country, pincode, state, phone from `tabAddress` where customer = '%s' and docstatus != 2 order by is_shipping_address desc limit 1" %(name), as_dict = 1)
|
||||
|
||||
extract = lambda x: details and details[0] and details[0].get(x,'') or ''
|
||||
address_fields = [('','address_line1'),('\n','address_line2'),('\n','city'),(' ','pincode'),('\n','state'),('\n','country'),('\nPhone: ','phone')]
|
||||
address_display = ''.join([a[0]+extract(a[1]) for a in address_fields if extract(a[1])])
|
||||
if address_display.startswith('\n'): address_display = address_display[1:]
|
||||
|
||||
ret = {
|
||||
'shipping_address_name' : details and details[0]['name'] or '',
|
||||
'shipping_address' : address_display
|
||||
}
|
||||
return ret
|
||||
|
||||
# Get Lead Details
|
||||
# -----------------------
|
||||
def get_lead_details(self, name):
|
||||
details = webnotes.conn.sql("select name, lead_name, address_line1, address_line2, city, country, state, pincode, territory, contact_no, mobile_no, email_id, company_name from `tabLead` where name = '%s'" %(name), as_dict = 1)
|
||||
|
||||
extract = lambda x: details and details[0] and details[0].get(x,'') or ''
|
||||
address_fields = [('','address_line1'),('\n','address_line2'),('\n','city'),(' ','pincode'),('\n','state'),('\n','country'),('\nPhone: ','contact_no')]
|
||||
address_display = ''.join([a[0]+extract(a[1]) for a in address_fields if extract(a[1])])
|
||||
if address_display.startswith('\n'): address_display = address_display[1:]
|
||||
|
||||
ret = {
|
||||
'lead_name' : extract('lead_name'),
|
||||
'address_display' : address_display,
|
||||
'territory' : extract('territory'),
|
||||
'contact_mobile' : extract('mobile_no'),
|
||||
'contact_email' : extract('email_id'),
|
||||
'organization' : extract('company_name')
|
||||
}
|
||||
return ret
|
||||
|
||||
|
||||
# Get Supplier Default Primary Address - first load
|
||||
# -----------------------
|
||||
def get_default_supplier_address(self, args):
|
||||
args = load_json(args)
|
||||
address_text, address_name = self.get_address_text(supplier=args['supplier'])
|
||||
contact_text, contact_name, contact_email, contact_mobile = self.get_contact_text(supplier=args['supplier'])
|
||||
ret = {
|
||||
'supplier_address' : address_name,
|
||||
'address_display' : address_text,
|
||||
'contact_person' : contact_name,
|
||||
'contact_display' : contact_text,
|
||||
'contact_email' : contact_email,
|
||||
'contact_mobile' : contact_mobile
|
||||
}
|
||||
ret.update(self.get_supplier_details(args['supplier']))
|
||||
return ret
|
||||
|
||||
# Get Supplier Address
|
||||
# -----------------------
|
||||
def get_supplier_address(self, args):
|
||||
args = load_json(args)
|
||||
address_text, address_name = self.get_address_text(address_name=args['address'])
|
||||
contact_text, contact_name, contact_email, contact_mobile = self.get_contact_text(contact_name=args['contact'])
|
||||
ret = {
|
||||
'supplier_address' : address_name,
|
||||
'address_display' : address_text,
|
||||
'contact_person' : contact_name,
|
||||
'contact_display' : contact_text,
|
||||
'contact_email' : contact_email,
|
||||
'contact_mobile' : contact_mobile
|
||||
}
|
||||
return ret
|
||||
|
||||
# Get Supplier Details
|
||||
# -----------------------
|
||||
def get_supplier_details(self, name):
|
||||
supplier_details = webnotes.conn.sql("""\
|
||||
select supplier_name, default_currency
|
||||
from `tabSupplier`
|
||||
where name = %s and docstatus < 2""", name, as_dict=1)
|
||||
if supplier_details:
|
||||
return {
|
||||
'supplier_name': (supplier_details[0]['supplier_name']
|
||||
or self.doc.fields.get('supplier_name')),
|
||||
'currency': (supplier_details[0]['default_currency']
|
||||
or self.doc.fields.get('currency')),
|
||||
}
|
||||
else:
|
||||
return {}
|
||||
|
||||
# Get Sales Person Details of Customer
|
||||
# ------------------------------------
|
||||
def get_sales_person(self, name):
|
||||
self.doclist = self.doc.clear_table(self.doclist,'sales_team')
|
||||
idx = 0
|
||||
for d in webnotes.conn.sql("select sales_person, allocated_percentage, allocated_amount, incentives from `tabSales Team` where parent = '%s'" % name):
|
||||
ch = addchild(self.doc, 'sales_team', 'Sales Team', 1, self.doclist)
|
||||
ch.sales_person = d and cstr(d[0]) or ''
|
||||
ch.allocated_percentage = d and flt(d[1]) or 0
|
||||
ch.allocated_amount = d and flt(d[2]) or 0
|
||||
ch.incentives = d and flt(d[3]) or 0
|
||||
ch.idx = idx
|
||||
idx += 1
|
||||
|
||||
# Get Company Specific Default Currency
|
||||
# -------------------------------------
|
||||
def get_company_currency(self, name):
|
||||
ret = webnotes.conn.sql("select default_currency from tabCompany where name = '%s'" %(name))
|
||||
dcc = ret and ret[0][0] or get_defaults()['currency']
|
||||
return dcc
|
||||
|
||||
|
||||
def get_formatted_message(self, args):
|
||||
""" get formatted message for auto notification"""
|
||||
return get_obj('Notification Control').get_formatted_message(args)
|
||||
Reference in New Issue
Block a user