moved directory structure

This commit is contained in:
Rushabh Mehta
2012-09-24 19:13:42 +05:30
parent e47a6779e9
commit 2fa2f7178d
1637 changed files with 47 additions and 11450 deletions

42
utilities/__init__.py Normal file
View 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
View 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()

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View 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();
}

View File

@@ -0,0 +1,79 @@
# ERPNext - web based ERP (http://erpnext.com)
# Copyright (C) 2012 Web Notes Technologies Pvt Ltd
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# 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))

View 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
}
]

View 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'}}
]
});

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View 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
}
]

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View 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();
}

View 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

View 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
}
]

View 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'}}
]
});

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View 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'
}
]

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View 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'
}
]

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View 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)

View 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'
}
]

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View 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)

View 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'
}
]

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View 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";
}

View 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>")

View 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'
}
]

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View File

@@ -0,0 +1,79 @@
// ERPNext - web based ERP (http://erpnext.com)
// Copyright (C) 2012 Web Notes Technologies Pvt Ltd
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
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 ++;
}

View 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)])

View 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'
}
]

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View 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]);
}

View 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)

View 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
}
]

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View 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'
}
]

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View 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'
}
]

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View 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()

View 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'
}
]

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View 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;
}

View File

@@ -0,0 +1,26 @@
<div class="cal_body">
<a class="close" onclick="window.history.back();">&times;</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>

View 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 = '';
}

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View 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'
}
]

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View 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()">&times;</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>![alt text](/path/img.jpg "Title")
</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>&gt; Email-style angle brackets
&gt; are used for blockquotes.
&gt; &gt; And, they can be nested.
&gt; &gt;
&gt; * You can quote a list.
&gt; * Etc.
</code></pre>
<h3>Code Spans</h3>
<pre><code>`&lt;code&gt;` 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>

View File

@@ -0,0 +1 @@
wn.pages['markdown-reference'].onload = function(wrapper) { }

View File

@@ -0,0 +1,2 @@
from __future__ import unicode_literals
import webnotes

View 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'
}
]

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View 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;
}

View File

@@ -0,0 +1,28 @@
<div class="layout-wrapper layout-wrapper-background">
<div class="layout-main-section">
<a class="close" onclick="window.history.back();">&times;</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>

View 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">&times;</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))
}
}
});
}
}

View 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')

View 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'
}
]

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View 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 {
}

View 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>

View 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');

View 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())

View 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'
}
]

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View 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;
}

View 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>

View 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');

View 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'])

View 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'
}
]

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View 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;
}

View 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
View 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] &nbsp;", {
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] &nbsp;", {
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">&times;</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();
}

View 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)

View 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'
}
]

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View File

@@ -0,0 +1,4 @@
<div class="layout_wrapper">
<div id="trash_header"></div>
<div id="trash_div" style="margin: 0px;"></div>
</div>

View 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();})
}

View 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'
}
]

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View 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;
}

View File

View 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">&times;</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
});
}
})

View 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
"""

View 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'
}
]

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View File

@@ -0,0 +1,2 @@
<div id="wip_head"></div>
<div id="wip_body" style="margin:16px"></div>

View 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); }
}

View 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'
}
]

View 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)