added voucher import tool

This commit is contained in:
Rushabh Mehta 2012-09-26 19:00:00 +05:30
parent 65a2b5b69a
commit c74290191a
24 changed files with 579 additions and 302 deletions

View file

@ -20,9 +20,9 @@ Listen 8080
# rewrite rule
RewriteEngine on
# don't filter static files
# disallow static files
RewriteRule ^(.*)/(lib/|app/|js/|css/|files/|backup/)(.*)$ $1/$2$3 [L]
RewriteRule ^(.*)/(app.html|unsupported.html|rss.xml|sitemap.xml|web.py|server.py)(.*)$ $1/$2$3 [L]
RewriteRule ^(.*)/(app.html|unsupported.html|blank.html|rss.xml|sitemap.xml|web.py|server.py)(.*)$ $1/$2$3 [L]
# everything else is a web page
RewriteRule ^(.*)/([^/]*)$ $1/web.py?page=$2 [L]

View file

@ -117,18 +117,16 @@ def getdocfield(fieldname):
@webnotes.whitelist(allow_roles=['System Manager', 'Administrator'])
def upload():
"""upload data"""
import csv
global doctype_dl
from webnotes.utils.file_manager import get_uploaded_content
import webnotes.model.doctype
from webnotes.model.doc import Document
from webnotes.utils.datautils import read_csv_content_from_uploaded_file
fname, fcontent = get_uploaded_content()
overwrite = webnotes.form_dict.get('overwrite')
ret = []
rows = read_csv_content(fcontent)
rows = read_csv_content_from_uploaded_file()
# doctype
doctype = rows[0][0].split(':')[1].strip()
@ -184,41 +182,11 @@ def upload():
webnotes.errprint(webnotes.getTraceback())
return ret
def read_csv_content(fcontent):
import csv
import webnotes
from webnotes.utils import cstr
rows = []
try:
reader = csv.reader(fcontent.splitlines())
# decode everything
csvrows = [[val for val in row] for row in reader]
for row in csvrows:
newrow = []
for val in row:
if webnotes.form_dict.get('ignore_encoding_errors'):
newrow.append(cstr(val.strip()))
else:
try:
newrow.append(unicode(val.strip(), 'utf-8'))
except UnicodeDecodeError, e:
raise Exception, """Some character(s) in row #%s, column #%s are
not readable by utf-8. Ignoring them. If you are importing a non
english language, please make sure your file is saved in the 'utf-8'
encoding.""" % (csvrows.index(row)+1, row.index(val)+1)
rows.append(newrow)
return rows
except Exception, e:
webnotes.msgprint("Not a valid Comma Separated Value (CSV File)")
raise e
def check_record(d, parenttype):
"""check for mandatory, select options, dates. these should ideally be in doclist"""
from webnotes.utils.dateutils import user_to_str
if parenttype and not d.get('parent'):
raise Exception, "parent is required."
@ -240,14 +208,7 @@ def check_record(d, parenttype):
raise Exception, "%s must be one of:" % key
if docfield.fieldtype=='Date' and val:
import datetime
dateformats = {
'yyyy-mm-dd':'%Y-%m-%d',
'dd/mm/yyyy':'%d/%m/%Y',
'mm/dd/yyyy':'%m/%d/%Y'
}
d[key] = datetime.datetime.strptime(val,
dateformats[webnotes.form_dict['date_format']]).strftime('%Y-%m-%d')
d[key] = user_to_str(val, webnotes.form_dict['date_format'])
def getlink(doctype, name):
return '<a href="#Form/%(doctype)s/%(name)s">%(name)s</a>' % locals()

View file

@ -11,6 +11,7 @@
"lib/public/js/wn/misc/user.js",
"lib/public/js/lib/public/json2.js",
"lib/public/js/wn/router.js",
"lib/public/js/wn/ui/messages.js",
"lib/public/js/wn/ui/listing.js",
"lib/public/js/wn/ui/filters.js",
"lib/public/js/wn/views/container.js",

0
public/html/blank.html Normal file
View file

View file

@ -110,7 +110,7 @@ function $s(ele, v, ftype, fopt) {
ele.style.textAlign = 'right';
ele.innerHTML = v;
} else if(ftype == 'Check') {
if(v) ele.innerHTML = '<img src="images/lib/ui/tick.gif">';
if(v) ele.innerHTML = '<img src="lib/images/ui/tick.gif">';
else ele.innerHTML = '';
} else {
ele.innerHTML = v;

View file

@ -874,7 +874,7 @@ CheckField.prototype.validate = function(v) {
CheckField.prototype.onmake = function() {
this.checkimg = $a(this.disp_area, 'div');
var img = $a(this.checkimg, 'img');
img.src = 'images/lib/ui/tick.gif';
img.src = 'lib/images/ui/tick.gif';
$dh(this.checkimg);
}

View file

@ -99,7 +99,7 @@ Listing.prototype.make = function(parent) {
// results
this.results = $a($a(this.body_area, 'div','srs_results_area'),'div');
this.fetching_area = $a(this.body_area, 'div','',{height:'120px', background:'url("images/lib/ui/square_loading.gif") center no-repeat', display:'none'});
this.fetching_area = $a(this.body_area, 'div','',{height:'120px', background:'url("lib/images/ui/square_loading.gif") center no-repeat', display:'none'});
this.show_no_records = $a(this.body_area,'div','',{margin:'200px 0px', textAlign:'center', fontSize:'14px', color:'#888', display:'none'});
this.show_no_records.innerHTML = 'No Result';
@ -155,7 +155,7 @@ Listing.prototype.make_toolbar = function() {
}
this.loading_img = $a(this.btn_area,'img','',{display:'none',marginBottom:'-2px'});
this.loading_img.src = 'images/lib/ui/button-load.gif';
this.loading_img.src = 'lib/images/ui/button-load.gif';
if(!keys(this.buttons).length)
$dh(this.btn_area);
@ -202,7 +202,7 @@ Listing.prototype.add_filter = function(label, ftype, options, tname, fname, con
// filter label
var d1= $a(c,'div','',{fontSize:'11px', marginBottom:'2px'}); d1.innerHTML = label;
if(ftype=='Link') d1.innerHTML += ' <img src="images/lib/icons/link.png" style="margin-bottom:-5px" title="Link">';
if(ftype=='Link') d1.innerHTML += ' <img src="lib/images/icons/link.png" style="margin-bottom:-5px" title="Link">';
var d2= $a(c,'div');

View file

@ -89,14 +89,14 @@ _r.DataTable = function(html_fieldname, dt, repname, hide_toolbar) {
this.no_data_tag = $a(this.wrapper, 'div', 'report_no_data');
this.no_data_tag.innerHTML = 'No Records Found';
this.fetching_tag = $a(this.wrapper, 'div', '', {height:'100%', background:'url("images/lib/ui/square_loading.gif") center no-repeat', display:'none'});
this.fetching_tag = $a(this.wrapper, 'div', '', {height:'100%', background:'url("lib/images/ui/square_loading.gif") center no-repeat', display:'none'});
}
_r.DataTable.prototype.add_icon = function(parent, imgsrc) {
var i = $a(parent, 'img');
i.style.padding = '2px';
i.style.cursor = 'pointer';
i.setAttribute('src', 'images/lib/icons/'+imgsrc+'.gif');
i.setAttribute('src', 'lib/images/icons/'+imgsrc+'.gif');
return i;
}
@ -184,10 +184,10 @@ _r.DataTable.prototype.make_toolbar = function(parent) {
}
_r.DataTable.prototype.set_desc = function() {
this.sort_icon.src = 'images/lib/icons/arrow_down.gif'; this.sort_order='DESC';
this.sort_icon.src = 'lib/images/icons/arrow_down.gif'; this.sort_order='DESC';
}
_r.DataTable.prototype.set_asc = function(icon) {
this.sort_icon.src = 'images/lib/icons/arrow_up.gif'; this.sort_order='ASC';
this.sort_icon.src = 'lib/images/icons/arrow_up.gif'; this.sort_order='ASC';
}
////

View file

@ -31,8 +31,8 @@ function Tree(parent, width, do_animate) {
this.is_root = 1;
this.do_animate = do_animate;
var me = this;
this.exp_img = 'images/lib/icons/plus.gif';
this.col_img = 'images/lib/icons/minus.gif';
this.exp_img = 'lib/images/icons/plus.gif';
this.col_img = 'lib/images/icons/minus.gif';
this.body = $a(parent, 'div');
if(width)$w(this.body, width);
@ -124,7 +124,7 @@ function TreeNode(tree, parent, id, imagesrc, onclick, onexpand, opts, label) {
$y(t2,{borderCollapse:'collapse'});
this.img_cell = $td(t2, 0, 0);
$y(this.img_cell, {cursor:'pointer',verticalAlign:'middle',width:'20px'});
if(!imagesrc) imagesrc = "images/lib/icons/folder.gif";
if(!imagesrc) imagesrc = "lib/images/icons/folder.gif";
this.usrimg = $a(this.img_cell, 'img');
this.usrimg.src = imagesrc;

View file

@ -6,17 +6,17 @@ classes should alter those!
*/
.slick-header-columns {
background: url('js/lib/slickgrid/images/header-columns-bg.gif') repeat-x center bottom;
background: url('lib/js/lib/slickgrid/images/header-columns-bg.gif') repeat-x center bottom;
border-bottom: 1px solid silver;
}
.slick-header-column {
background: url('js/lib/slickgrid/images/header-columns-bg.gif') repeat-x center bottom;
background: url('lib/js/lib/slickgrid/images/header-columns-bg.gif') repeat-x center bottom;
border-right: 1px solid silver;
}
.slick-header-column:hover, .slick-header-column-active {
background: white url('js/lib/slickgrid/images/header-columns-over-bg.gif') repeat-x center bottom;
background: white url('lib/js/lib/slickgrid/images/header-columns-over-bg.gif') repeat-x center bottom;
}
.slick-headerrow {
@ -61,11 +61,11 @@ classes should alter those!
}
.slick-group-toggle.expanded {
background: url(js/lib/slickgrid/images/collapse.gif) no-repeat center center;
background: url(lib/js/lib/slickgrid/images/collapse.gif) no-repeat center center;
}
.slick-group-toggle.collapsed {
background: url(js/lib/slickgrid/images/expand.gif) no-repeat center center;
background: url(lib/js/lib/slickgrid/images/expand.gif) no-repeat center center;
}
.slick-group-totals {
@ -107,7 +107,7 @@ classes should alter those!
border: 1px solid gray;
border-bottom: 0;
border-top: 0;
background: url('js/lib/slickgrid/images/header-bg.gif') repeat-x center top;
background: url('lib/js/lib/slickgrid/images/header-bg.gif') repeat-x center top;
color: black;
height: 24px;
line-height: 24px;
@ -229,7 +229,7 @@ input.editor-percentcomplete {
display: inline-block;
width: 16px;
height: 100%;
background: url("js/lib/slickgrid/images/pencil.gif") no-repeat center center;
background: url("lib/js/lib/slickgrid/images/pencil.gif") no-repeat center center;
overflow: visible;
z-index: 1000;
float: right;
@ -240,7 +240,7 @@ input.editor-percentcomplete {
position: absolute;
top: -2px;
left: -9px;
background: url("js/lib/slickgrid/images/editor-helper-bg.gif") no-repeat top left;
background: url("lib/js/lib/slickgrid/images/editor-helper-bg.gif") no-repeat top left;
padding-left: 9px;
width: 120px;

View file

@ -0,0 +1,13 @@
wn.provide("wn.messages")
wn.messages.waiting = function(parent, msg, bar_percent) {
if(!bar_percent) bar_percent = '100';
return $(repl('<div class="well" style="width: 63%; margin: 30px auto;">\
<p style="text-align: center;">%(msg)s</p>\
<div class="progress progress-striped active">\
<div class="bar" style="width: %(bar_percent)s%"></div></div>', {
bar_percent: bar_percent,
msg: msg
}))
.appendTo(parent);
},

View file

@ -1,46 +0,0 @@
// 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.
//
// overlay an element
// http://blog.learnboost.com/blog/a-css3-overlay-system/
wn.ui.Overlay = function(ele) {
wn.require('lib/css/ui/overlay.css');
var me = this;
$.extend(this, {
render: function() {
me.wrap = wn.dom.add(
wn.dom.add(
wn.dom.add($('body').get(0), 'div', 'overlay')
, 'div', 'wrap-outer')
, 'div', 'wrap');
me.wrap.appendChild(ele);
$('body').addClass('overlaid');
},
hide: function() {
wn.dom.hide(me.wrap);
$('body').removeClass('overlaid');
}
});
me.render();
}

View file

@ -200,12 +200,7 @@ wn.views.GridReport = Class.extend({
});
},
make_waiting: function() {
this.waiting = $('<div class="well" style="width: 63%; margin: 30px auto;">\
<p style="text-align: center;">Loading Report...</p>\
<div class="progress progress-striped active">\
<div class="bar" style="width: 10%"></div></div>')
.appendTo(this.wrapper);
this.waiting = wn.messages.waiting(this.wrapper, "Loading Report...", '10');
},
load_filter_values: function() {
var me = this;

View file

@ -19,6 +19,7 @@ def make():
["web.py", "../lib/public/html/web.py"],
["server.py", "../lib/public/html/server.py"],
["app.html", "../lib/public/html/app.html"],
["blank.html", "../lib/public/html/blank.html"],
["unsupported.html", "../lib/public/html/unsupported.html"],
["sitemap.xml", "../lib/public/html/sitemap.xml"],
["rss.xml", "../lib/public/html/rss.xml"],

View file

@ -0,0 +1,396 @@
# 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.
#
"""
Transactions are defined as collection of classes, a DocList represents collection of Document
objects for a transaction with main and children.
Group actions like save, etc are performed on doclists
"""
import webnotes
import json, os
import webnotes.model
import webnotes.model.doc
import webnotes.model.doclist
import webnotes.utils.cache
from webnotes import _
from webnotes.utils import cint, cstr, now_datetime, get_datetime, get_datetime_str, comma_and, cast
controllers = webnotes.DictObj()
def get(doctype, name=None, module=None):
"""return controller object"""
global controllers
doclist = doctype
if isinstance(doctype, list):
doctype = doclist[0]["doctype"]
# return if already loaded
if doctype not in controllers:
from webnotes.modules import get_doc_path, scrub
module_name = module or webnotes.conn.get_value("DocType", doctype, "module") or "Core"
doc_path = get_doc_path(module_name, 'doctype', doctype)
module_path = os.path.join(doc_path, scrub(doctype)+'.py')
# load translations
if webnotes.can_translate():
from webnotes.utils.translate import get_lang_data
webnotes._messages.update(get_lang_data(doc_path, None, 'py'))
# vanilla controller
controllers[doctype] = get_controller_class(module_name, doctype, module_path)
return controllers[doctype](doclist, name)
def get_controller_class(module_name, doctype, module_path):
if os.path.exists(module_path):
from webnotes.modules import get_doc_path, scrub
module = __import__(scrub(module_name) + '.doctype.' + scrub(doctype) + '.' \
+ scrub(doctype), fromlist = [scrub(doctype)])
# find controller in module
import inspect
for attr in dir(module):
attrobj = getattr(module, attr)
if inspect.isclass(attrobj) and attr.startswith(doctype.replace(' ', '').replace('-', '')) \
and issubclass(attrobj, DocListController):
return attrobj
return DocListController
class DocListController(object):
"""
Collection of Documents with one parent and multiple children
"""
def __init__(self, doctype=None, name=None):
if doctype:
self.load(doctype, name)
if hasattr(self, "setup"):
self.setup()
def load(self, doctype, name=None):
if isinstance(doctype, list):
self.set_doclist(doctype)
return
if not name: name = doctype
self.set_doclist(self.load_doclist(doctype, name))
def load_doclist(self, doctype, name):
return webnotes.model.doclist.load(doctype, name)
def set_doclist(self, doclist):
if not isinstance(doclist, webnotes.model.doclist.DocList):
self.doclist = webnotes.model.doclist.objectify(doclist)
else:
self.doclist = doclist
self.doc = self.doclist[0]
def save(self):
"""Save the doclist"""
# if docstatus is null, set it as 0
self.doc.docstatus = self.doc.docstatus or 0
self.prepare_for_save()
self.run('validate')
self.doctype_validate()
from webnotes.model.doctype import get_property
if get_property(self.doc.doctype, "document_type") in ["Master", "Transaction"]\
and not self.doc.get("__islocal"):
from webnotes.model.doclist import load
# get the old doclist
try:
oldlist = load(self.doc.doctype, self.doc.name)
except NameError, e:
oldlist = None
else:
oldlist = None
self.save_main()
self.save_children()
self.run('on_update')
# version is saved after save, because we need names
if oldlist:
self.save_version(oldlist)
def prepare_for_save(self):
"""Set owner, modified etc before saving"""
self.check_if_latest()
self.check_permission()
self.check_links()
self.check_mandatory()
self.update_timestamps()
def save_main(self):
"""Save the main doc"""
self.doc.save(cint(self.doc.get('__islocal')))
def save_children(self):
"""Save Children, with the new parent name"""
child_map = {}
for d in self.doclist[1:]:
if d.has_key('parentfield'):
d.parent = self.doc.name # rename if reqd
d.parenttype = self.doc.doctype
# set docstatus of children as that of parent
d.docstatus = self.doc.docstatus
d.modified = self.doc.modified
d.modified_by = self.doc.modified_by
d.save(new = cint(d.get('__islocal')))
child_map.setdefault(d.doctype, []).append(d.name)
# delete all children in database that are not in the child_map
self.remove_children(child_map)
def save_version(self, oldlist):
"""create a new version of given difflist"""
from webnotes.model.versions import save_version
save_version(oldlist, self.doclist)
def remove_children(self, child_map):
"""delete children from database if they do not exist in the doclist"""
# get all children types
tablefields = webnotes.conn.get_table_fields(self.doc.doctype)
for dt in tablefields:
cnames = child_map.get(dt['options']) or []
if cnames:
webnotes.conn.sql("""delete from `tab%s` where parent=%s
and parenttype=%s and name not in (%s)""" % \
(dt['options'], '%s', '%s', ','.join(['%s'] * len(cnames))),
tuple([self.doc.name, self.doc.doctype] + cnames))
else:
webnotes.conn.sql("""delete from `tab%s` where parent=%s
and parenttype=%s""" % (dt['options'], '%s', '%s'),
(self.doc.name, self.doc.doctype))
def check_if_latest(self):
"""Raises exception if the modified time is not the same as in the database"""
if not (webnotes.conn.is_single(self.doc.doctype) or \
cint(self.doc.get('__islocal'))):
modified = webnotes.conn.sql("""select modified from `tab%s`
where name=%s for update""" % (self.doc.doctype, "%s"),
self.doc.name or "")
if modified and get_datetime_str(modified[0].modified) != \
get_datetime_str(self.doc.modified):
webnotes.msgprint(_("""Document has been modified after you have opened it.
To maintain the integrity of the data, you will not be able to save
your changes. Please refresh this document.)"""),
raise_exception=webnotes.IntegrityError)
def check_permission(self):
"""Raises exception if permission is not valid"""
# hail the administrator - nothing can stop you!
if webnotes.session.user == "Administrator":
return
doctypelist = webnotes.model.get_doctype("DocType", self.doc.doctype)
if not hasattr(self, "user_roles"):
self.user_roles = webnotes.user and webnotes.user.get_roles() or ["Guest"]
if not hasattr(self, "user_defaults"):
self.user_defaults = webnotes.user and webnotes.user.get_defaults() or {}
has_perm = False
match = []
# check if permission exists and if there is any match condition
for perm in doctypelist.get({"doctype": "DocPerm"}):
if cint(perm.permlevel) == 0 and cint(perm.read) == 1 and perm.role in self.user_roles:
has_perm = True
if perm.match and match != -1:
match.append(perm.match)
else:
# this indicates that there exists atleast one permission
# where match is not specified
match = -1
# check match conditions
if has_perm and match and match != -1:
for match_field in match:
if self.doc.get(match_field, "no_value") in self.user_defaults.get(match_field, []):
# field value matches with user's credentials
has_perm = True
break
else:
# oops, illegal value
has_perm = False
webnotes.msgprint(_("""Value: "%s" is not allowed for field "%s" """) % \
(self.doc.get(match_field, "no_value"),
doctypelist.get_field(match_field).label))
if not has_perm:
webnotes.msgprint(_("""Not enough permissions to save %s: "%s" """) % \
(self.doc.doctype, self.doc.name), raise_exception=webnotes.PermissionError)
def check_links(self):
"""Checks integrity of links (throws exception if links are invalid)"""
from webnotes.model.doctype import get_link_fields
link_fields = {}
error_list = []
for doc in self.doclist:
for lf in link_fields.setdefault(doc.doctype, get_link_fields(doc.doctype)):
options = (lf.options or "").split("\n")[0].strip()
options = options.startswith("link:") and options[5:] or options
if doc.get(lf.fieldname) and options and \
not webnotes.conn.exists(options, doc[lf.fieldname]):
error_list.append((options, doc[lf.fieldname], lf.label))
if error_list:
webnotes.msgprint(_("""The following values do not exist in the database: %s.
Please correct these values and try to save again.""") % \
comma_and(["%s: \"%s\" (specified in field: %s)" % err for err in error_list]),
raise_exception=webnotes.InvalidLinkError)
def check_mandatory(self):
"""check if all required fields have value"""
reqd = []
for doc in self.doclist:
for df in webnotes.model.get_doctype(doc.doctype).get({
"parent": doc.doctype, "doctype": "DocField", "reqd": 1}):
if doc.get(df.fieldname) is None:
reqd.append("""\"%s\" is a Mandatory field [in %s%s]""" % \
(df.label, df.parent, doc.idx and " - %d" % doc.idx or ""))
if reqd:
webnotes.msgprint(_("In") + " %s - %s\n" % (self.doc.doctype, self.doc.name or "") +
"\n".join(reqd),
raise_exception=webnotes.MandatoryError)
def update_timestamps(self):
"""Update owner, creation, modified_by, modified, docstatus"""
ts = get_datetime(now_datetime())
for d in self.doclist:
if self.doc.get('__islocal'):
d.owner = webnotes.session.user
d.creation = ts
d.modified_by = webnotes.session.user
d.modified = ts
def doctype_validate(self):
"""run DocType Validator"""
from core.doctype.doctype_validator.doctype_validator import validate
validate(self)
def run(self, method, args=None):
if hasattr(self, method):
if args:
getattr(self, method)(args)
else:
getattr(self, method)()
# if possible, deprecate
trigger(method, self.doclist[0])
def clear_table(self, table_field):
self.doclist = filter(lambda d: d.parentfield != table_field, self.doclist)
def add_child(self, doc):
"""add a child doc to doclist"""
# make child
if not isinstance(doc, webnotes.model.doc.Document):
doc = webnotes.model.doc.Document(fielddata = doc)
doc.__islocal = 1
doc.parent = self.doc.name
doc.parenttype = self.doc.doctype
# parentfield is to be supplied in the doc
# add to doclist
self.doclist.append(doc)
def export(self):
"""export current doc to file system"""
import conf
if (getattr(conf,'developer_mode', 0) and not getattr(webnotes, 'syncing', False)
and not getattr(webnotes, "testing", False)):
from webnotes.modules.export import export_to_files
export_to_files(record_list=self.doclist)
def set_as_default(self, filters=None):
"""sets is_default to 0 in rest of the related documents"""
if self.doc.is_default:
conditions, filters = webnotes.conn.build_conditions(filters)
filters.update({"name": self.doc.name})
webnotes.conn.sql("""update `tab%s` set `is_default`=0
where %s and name!=%s""" % (self.doc.doctype, conditions, "%(name)s"),
filters)
def set_default_values(self):
"""set's default values in doclist"""
import webnotes.model.utils
for doc in self.doclist:
for df in webnotes.model.get_doctype(doc.doctype).get({
"parent": doc.doctype, "doctype": "DocField"}):
if doc.get(df.fieldname) in [None, ""] and df.default:
doc[df.fieldname] = cast(df, df.default)
# TODO: should this method be here?
def get_csv_from_attachment(self):
"""get csv from attachment"""
if not self.doc.file_list:
msgprint("File not attached!")
raise Exception
# get file_id
fid = self.doc.file_list.split(',')[1]
# get file from file_manager
try:
from webnotes.utils import file_manager
fn, content = file_manager.get_file(fid)
except Exception, e:
webnotes.msgprint(_("Unable to open attached file. Please try again."))
raise e
# convert char to string (?)
if not isinstance(content, basestring) and hasattr(content, 'tostring'):
content = content.tostring()
import csv
return csv.reader(content.splitlines())
def trigger(method, doc):
"""trigger doctype events"""
try:
import startup.event_handlers
except ImportError:
return
if hasattr(startup.event_handlers, method):
getattr(startup.event_handlers, method)(doc)
if hasattr(startup.event_handlers, 'doclist_all'):
startup.event_handlers.doclist_all(doc, method)

View file

@ -73,9 +73,9 @@ class Document:
self._prefix = prefix
if fielddata:
self.fields = fielddata
self.fields = webnotes.DictObj(fielddata)
else:
self.fields = {}
self.fields = webnotes.DictObj()
if not self.fields.has_key('name'):
self.fields['name']='' # required on save
@ -95,6 +95,9 @@ class Document:
else:
if not fielddata:
self.fields['__islocal'] = 1
if not self.fields.docstatus:
self.fields.docstatus = 0
def __nonzero__(self):
return True
@ -541,7 +544,7 @@ class Document:
d.owner = webnotes.session['user']
if local:
d.fields['__islocal'] = '1' # for Client to identify unsaved doc
d.fields['__islocal'] = 1 # for Client to identify unsaved doc
else:
d.save(new=1)

View file

@ -219,7 +219,7 @@ class DocList:
for d in self.children:
if d.fields.has_key('parent'):
if d.parent and (not d.parent.startswith('old_parent:')):
if d.parent:
d.parent = self.doc.name # rename if reqd
d.parenttype = self.doc.doctype
@ -257,7 +257,7 @@ class DocList:
Save & Submit - set docstatus = 1, run "on_submit"
"""
if self.doc.docstatus != 0:
msgprint("Only draft can be submitted", raise_exception=1)
webnotes.msgprint("Only draft can be submitted", raise_exception=1)
self.to_docstatus = 1
self.save()
self.run_method('on_submit')

View file

@ -4,6 +4,8 @@ from __future__ import unicode_literals
perms will get synced only if none exist
"""
import webnotes
import os
import conf
def sync_all(force=0):
modules = []
@ -18,41 +20,38 @@ def sync_all(force=0):
return modules
def sync_core_doctypes(force=0):
import os
import core
# doctypes
return walk_and_sync(os.path.abspath(os.path.dirname(core.__file__)), force)
return walk_and_sync(os.path.join(os.path.dirname(conf.__file__), 'lib'), force)
def sync_modules(force=0):
import conf, os
return walk_and_sync(os.path.join(os.path.dirname(conf.__file__), 'app'), force)
def walk_and_sync(start_path, force=0):
"""walk and sync all doctypes and pages"""
import os
from webnotes.modules import reload_doc
modules = []
for path, folders, files in os.walk(start_path):
for f in files:
if f.endswith(".txt"):
# great grand-parent folder is module_name
module_name = path.split(os.sep)[-3]
if not module_name in modules:
modules.append(module_name)
if os.path.basename(os.path.dirname(path)) in ('doctype', 'page'):
for f in files:
if f.endswith(".txt"):
# great grand-parent folder is module_name
module_name = path.split(os.sep)[-3]
if not module_name in modules:
modules.append(module_name)
# grand parent folder is doctype
doctype = path.split(os.sep)[-2]
# grand parent folder is doctype
doctype = path.split(os.sep)[-2]
# parent folder is the name
name = path.split(os.sep)[-1]
# parent folder is the name
name = path.split(os.sep)[-1]
if doctype == 'doctype':
sync(module_name, name, force)
elif doctype in ['page']:#, 'search_criteria', 'Print Format', 'DocType Mapper']:
if reload_doc(module_name, doctype, name):
print module_name + ' | ' + doctype + ' | ' + name
if doctype == 'doctype':
sync(module_name, name, force)
elif doctype in ['page']:#, 'search_criteria', 'Print Format', 'DocType Mapper']:
if reload_doc(module_name, doctype, name):
print module_name + ' | ' + doctype + ' | ' + name
return modules
@ -87,7 +86,6 @@ def sync(module_name, docname, force=0):
def get_file_path(module_name, docname):
if not (module_name and docname):
raise Exception('No Module Name or DocName specified')
import os
module = __import__(module_name)
module_init_path = os.path.abspath(module.__file__)
module_path = os.sep.join(module_init_path.split(os.sep)[:-1])
@ -139,7 +137,6 @@ def sync_install(force=1):
load_install_docs(modules)
def load_install_docs(modules):
import os
if isinstance(modules, basestring): modules = [modules]
for module_name in modules:

View file

@ -100,7 +100,7 @@ def getlist(doclist, field):
from webnotes.utils import cint
l = []
for d in doclist:
if d.parent and (not d.parent.lower().startswith('old_parent:')) and d.parentfield == field:
if d.parentfield == field:
l.append(d)
l.sort(lambda a, b: cint(a.idx) - cint(b.idx))

View file

@ -1,9 +0,0 @@
## Password Reset
Dear %(user)s,
Your new password is: %(password)s
Please log in using this new password, and don't forget to change it.
Thanks!

View file

@ -259,13 +259,18 @@ user_format = None
* dd/mm/yyyy
"""
def formatdate(string_date):
def formatdate(string_date=None):
"""
Convers the given string date to :data:`user_format`
"""
global user_format
if not user_format:
user_format = webnotes.conn.get_value('Control Panel', None, 'date_format')
if not string_date:
string_date = nowdate()
if not isinstance(string_date, basestring):
string_date = str(string_date)
d = string_date.split('-');

View file

@ -0,0 +1,57 @@
# 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.
#
def read_csv_content_from_uploaded_file():
import csv
import webnotes
from webnotes.utils import cstr
from webnotes.utils.file_manager import get_uploaded_content
fname, fcontent = get_uploaded_content()
rows = []
try:
reader = csv.reader(fcontent.splitlines())
# decode everything
csvrows = [[val for val in row] for row in reader]
for row in csvrows:
newrow = []
for val in row:
if webnotes.form_dict.get('ignore_encoding_errors'):
newrow.append(cstr(val.strip()))
else:
try:
newrow.append(unicode(val.strip(), 'utf-8'))
except UnicodeDecodeError, e:
raise Exception, """Some character(s) in row #%s, column #%s are
not readable by utf-8. Ignoring them. If you are importing a non
english language, please make sure your file is saved in the 'utf-8'
encoding.""" % (csvrows.index(row)+1, row.index(val)+1)
rows.append(newrow)
return rows
except Exception, e:
webnotes.msgprint("Not a valid Comma Separated Value (CSV File)")
raise e

View file

@ -0,0 +1,48 @@
# 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.
#
import webnotes
user_date_format = None
def user_to_str(date, date_format = None):
if not date: return date
import datetime
if not date_format:
if not user_date_format:
global user_date_format
user_date_format = webnotes.conn.get_value("Control Panel", None, "date_format")
date_format = user_date_format
dateformats = {
'yyyy-mm-dd':'%Y-%m-%d',
'dd/mm/yyyy':'%d/%m/%Y',
'mm/dd/yyyy':'%m/%d/%Y',
'dd-mm-yyyy':'%d-%m-%Y'
}
return datetime.datetime.strptime(date,
dateformats[date_format]).strftime('%Y-%m-%d')

View file

@ -1,145 +0,0 @@
# 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.
#
from __future__ import unicode_literals
import webnotes
import webnotes.utils
class FrameworkServer:
"""
Connect to a remote server via HTTP (webservice).
* `remote_host` is the the address of the remote server
* `path` is the path of the Framework (excluding index.cgi)
"""
def __init__(self, remote_host, path, user='', password='', account='', cookies=None, opts=None, https = 0):
# validate
if not (remote_host and path):
raise Exception, "Server address and path necessary"
if not ((user and password) or (cookies)):
raise Exception, "Either cookies or user/password necessary"
self.remote_host = remote_host
self.path = path
self.cookies = cookies or {}
self.webservice_method='POST'
self.account = account
self.account_id = None
self.https = https
self.conn = None
# login
if not cookies:
args = { 'usr': user, 'pwd': password, 'ac_name': account }
if opts:
args.update(opts)
res = self.http_get_response('login', args)
ret = res.read()
try:
ret = eval(ret)
except Exception, e:
webnotes.msgprint(ret)
raise Exception, e
if 'message' in ret and ret['message']!='Logged In':
webnotes.msgprint(ret.get('server_messages'), raise_exception=1)
if ret.get('exc'):
raise Exception, ret.get('exc')
self._extract_cookies(res)
self.account_id = self.cookies.get('account_id')
self.sid = self.cookies.get('sid')
self.login_response = res
self.login_return = ret
# -----------------------------------------------------------------------------------------
def http_get_response(self, method, args):
"""
Run a method on the remote server, with the given arguments
"""
# get response from remote server
import urllib, urllib2, os
args['cmd'] = method
if self.path.startswith('/'): self.path = self.path[1:]
protocol = self.https and 'https://' or 'http://'
req = urllib2.Request(protocol + os.path.join(self.remote_host, self.path, 'index.cgi'), \
urllib.urlencode(args))
for key in self.cookies:
req.add_header('cookie', '; '.join(['%s=%s' % (key, self.cookies[key]) \
for key in self.cookies]))
return urllib2.urlopen(req)
# -----------------------------------------------------------------------------------------
def _extract_cookies(self, res):
import Cookie
cookies = Cookie.SimpleCookie()
cookies.load(res.headers.get('set-cookie'))
for c in cookies.values():
self.cookies[c.key] = c.value.rstrip(',')
# -----------------------------------------------------------------------------------------
def runserverobj(self, doctype, docname, method, arg=''):
"""
Returns the response of a remote method called on a system object specified by `doctype` and `docname`
"""
import json
res = self.http_get_response('runserverobj', args = {
'doctype':doctype
,'docname':docname
,'method':method
,'arg':arg
})
ret = json.loads(res.read())
if ret.get('exc'):
raise Exception, ret.get('exc')
return ret
# -----------------------------------------------------------------------------------------
def run_method(self, method, args={}):
"""
Run a method on the remote server
"""
res = self.http_get_response(method, args).read()
import json
try:
ret = json.loads(res)
except Exception, e:
webnotes.msgprint('Bad Response: ' + res, raise_exception=1)
if ret.get('exc'):
raise Exception, ret.get('exc')
return ret