added voucher import tool
This commit is contained in:
parent
65a2b5b69a
commit
c74290191a
24 changed files with 579 additions and 302 deletions
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
0
public/html/blank.html
Normal 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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
}
|
||||
|
||||
////
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
13
public/js/wn/ui/messages.js
Normal file
13
public/js/wn/ui/messages.js
Normal 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);
|
||||
},
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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"],
|
||||
|
|
|
|||
396
webnotes/model/controller.py
Normal file
396
webnotes/model/controller.py
Normal 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)
|
||||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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!
|
||||
|
|
@ -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('-');
|
||||
|
|
|
|||
57
webnotes/utils/datautils.py
Normal file
57
webnotes/utils/datautils.py
Normal 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
|
||||
48
webnotes/utils/dateutils.py
Normal file
48
webnotes/utils/dateutils.py
Normal 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')
|
||||
|
||||
|
||||
|
|
@ -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
|
||||
Loading…
Add table
Reference in a new issue