Bladeren bron

[ui] data import tool

version-14
Rushabh Mehta 10 jaren geleden
bovenliggende
commit
448d2c78bf
11 gewijzigde bestanden met toevoegingen van 245 en 349 verwijderingen
  1. +0
    -4
      frappe/core/page/data_import_tool/data_import_download.html
  2. +60
    -16
      frappe/core/page/data_import_tool/data_import_main.html
  3. +0
    -20
      frappe/core/page/data_import_tool/data_import_sidebar.html
  4. +3
    -5
      frappe/core/page/data_import_tool/data_import_tool.css
  5. +95
    -244
      frappe/core/page/data_import_tool/data_import_tool.js
  6. +5
    -3
      frappe/core/page/data_import_tool/importer.py
  7. +74
    -35
      frappe/core/page/data_import_tool/test_exporter_fixtures.py
  8. +3
    -3
      frappe/model/document.py
  9. +1
    -1
      frappe/public/css/bootstrap.css
  10. +1
    -1
      frappe/public/js/frappe/ui/page.js
  11. +3
    -17
      frappe/public/js/frappe/upload.js

+ 0
- 4
frappe/core/page/data_import_tool/data_import_download.html Bestand weergeven

@@ -1,4 +0,0 @@
<br>
<p>
<a class="btn btn-default btn-small" href="/api/method/frappe.core.page.data_import_tool.exporter.get_template?doctype={%= me.doctype %}&parent_doctype={%= me.doctype %}&with_data={% me.with_data %}&all_doctypes={% if(data.length > 1) { %}Yes{% } else { %}No{% } %}">{%= __("Download") %}</a>
</p>

+ 60
- 16
frappe/core/page/data_import_tool/data_import_main.html Bestand weergeven

@@ -1,25 +1,69 @@
<div class="data-import-tool"> <div class="data-import-tool">
<div class="data-import-selector"> <div class="data-import-selector">
<select class="form-control doctype" style="width: 200px" placeholder="{%= __("Select Type") %}">
</select>
<h6>{%= __("Select Type of Document to Import") %}</h6>
<div>
<select class="form-control doctype" style="width: 200px" placeholder="{%= __("Select Type") %}">
<option value=""></option>
{% for (var i=0, l= frappe.boot.user.can_import.length; i < l; i++) {
var doctype = frappe.boot.user.can_import[i]; %}
<option value="{%= doctype %}">{%= __(doctype) %}</option>
{% } %}
</select>
</div>
</div> </div>
<div class="section export hide">
<div class="export-import-section hide">
<hr>
<h3>{%= __("Export") %}</h3> <h3>{%= __("Export") %}</h3>
<div class="checkbox">
<label>
<input type="checkbox" name="dit-with-data"> <span>{%= __("Download with data") %}</span>
</label>
<p class="text-muted">{%= __("To import or update records, you must first download the template for importing.") %}</p>
<div class="row" style="max-width: 700px;">
<div class="col-sm-4">
<p><a class="btn btn-default btn-sm btn-download-template">
{%= __("Download Blank Template") %}</a></p>
</div>
<div class="col-sm-8">
<h6 class="text-muted">{%= __("Recommended for inserting new records.") %}</h6>
</div>
</div> </div>
<div class="data-import-download">
<div class="text-muted"><br>{%= __("Select type to export") %}</div>
<div class="row" style="max-width: 700px;">
<div class="col-sm-4">
<p><a class="btn btn-default btn-sm btn-download-data">
{%= __("Download with Data") %}</a></p>
</div>
<div class="col-sm-8">
<h6 class="text-muted">{%= __("Recommended bulk editing records via import, or understanding the import format.") %}</h6>
</div>
</div> </div>
</div>
<div class="section import hide">
<hr>
<h3>{%= __("Import") %}</h3> <h3>{%= __("Import") %}</h3>

</div>
<div class="section help hide">
<h3>{%= __("Help") %}</h3>

<div class="row">
<div class="col-md-6">
<div class="upload-area"></div>
<div class="checkbox">
<label>
<input type="checkbox" name="always_insert">
{%= __("Insert all records, even if ID matches.") %}
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="submit_after_import">
{%= __("Submit after importing.") %}
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="ignore_encoding_errors">
{%= __("Ignore encoding errors.") %}
</label>
</div>
<p>
<button class="btn btn-sm btn-primary btn-import">Import</button>
</p>
</div>
<div class="import-log hide col-md-6">
<h3>Import Log</h3>
<div class="import-log-messages"></div>
</div>
</div>
</div> </div>
</div> </div>

+ 0
- 20
frappe/core/page/data_import_tool/data_import_sidebar.html Bestand weergeven

@@ -1,20 +0,0 @@
<ul class="nav nav-pills nav-stacked" style="margin-right: -15px;">
<li class="h6 module-sidebar-item" data-section="export">
<a class="module-link">
<i class="icon icon-chevron-right pull-right" style="display: none;"></i>
{%= __("Export") %}
</a>
</li>
<li class="h6 module-sidebar-item" data-section="import">
<a class="module-link">
<i class="icon icon-chevron-right pull-right" style="display: none;"></i>
{%= __("Import") %}
</a>
</li>
<li class="h6 module-sidebar-item" data-section="help">
<a class="module-link">
<i class="icon icon-chevron-right pull-right" style="display: none;"></i>
{%= __("Help") %}
</a>
</li>
</ul>

+ 3
- 5
frappe/core/page/data_import_tool/data_import_tool.css Bestand weergeven

@@ -1,9 +1,7 @@
.data-import-tool .section {
.data-import-tool {
padding: 15px; padding: 15px;
} }


.data-import-selector {
padding: 15px;
border-bottom: 1px solid #d1d8dd;
background-color: #F0F4F7;
.data-import-tool hr {
margin: 10px -15px;
} }

+ 95
- 244
frappe/core/page/data_import_tool/data_import_tool.js Bestand weergeven

@@ -1,203 +1,91 @@
frappe.DataImportTool = Class.extend({
init: function(page) {
this.page = page;
this.make_main();
this.make_sidebar();
this.setup_select();
},
make_main: function() {
var me = this;
this.page.main.html(frappe.render_template("data_import_main", {}));
this.select = this.page.main.find("select.doctype");
frappe.call({
method: 'frappe.core.page.data_import_tool.data_import_tool.get_doctypes',
callback: function(r) {
me.select.add_options([""].concat(r.message));
me.doctypes = r.message;
if(frappe.route_options) {
me.set_route_options();
} else {
me.select.focus();
}
}
});
},
make_sidebar: function() {
var me = this;
this.page.sidebar.html(frappe.render_template("data_import_sidebar", {}));
// bind click
this.page.sidebar.find("a").on("click", function() {
var li = $(this).parents("li:first");
if (li.hasClass("active"))
return false;

var section = li.attr("data-section");


// active
me.page.sidebar.find("li.active").removeClass("active");
me.page.main.find(".section").addClass("hide");
me.page.main.find("." + section).removeClass("hide");
li.addClass("active");

});

$(me.page.sidebar.find("a")[0]).click();
},
setup_select: function() {
var me = this;
this.download_area = this.page.main.find(".data-import-download");
this.select.on("change", function(){
me.doctype = $(this).val();

if(!me.doctype) {
return;
}

me.download_area.empty();
me.with_data = $('[name="dit-with-data"]:checked').length ? 'Yes' : 'No'

frappe.model.with_doctype(me.doctype, function() {
// get options
return frappe.call({
btn: this,
method: 'frappe.core.page.data_import_tool.data_import_tool.get_doctype_options',
args: {doctype: me.doctype},
callback: function(r) {
$(frappe.render_template("data_import_download",
{data:r.message, me: me})).appendTo(me.download_area);
}
});
});


frappe.DataImportTool = Class.extend({
init: function(parent) {
this.page = frappe.ui.make_app_page({
parent: parent,
title: __("Data Import Tool"),
single_column: true
}); });

this.make();
this.make_upload();
}, },
set_route_options: function() { set_route_options: function() {
if(frappe.route_options if(frappe.route_options
&& frappe.route_options.doctype && frappe.route_options.doctype
&& in_list(this.doctypes, frappe.route_options.doctype)) {
this.select.val(frappe.route_options.doctype).change();
&& in_list(frappe.boot.user.can_import, frappe.route_options.doctype)) {
me.select.val(frappe.route_options.doctype).change();
frappe.route_options = null; frappe.route_options = null;
} }
}
})

frappe.pages['data-import-tool'].onload = function(wrapper) {
wrapper.app_page = frappe.ui.make_app_page({
parent: wrapper,
title: __("Data Import / Export Tool"),
icon: "icon-upload"
});

frappe.data_import_tool = new frappe.DataImportTool(wrapper.page);


return;



// check permission for import
if(!((frappe.boot.user.can_import && frappe.boot.user.can_import.length) ||
user_roles.indexOf("System Manager")!==-1)) {
frappe.show_not_permitted("data-import-tool");
return false;
}

$(wrapper).find('.layout-main-section').append('<h3>1. ' + __("Download Template") + '</h3>\
<div style="min-height: 150px">\
<p class="help">' + __("Download a template for importing a table.") + '</p>\
<div class="row">\
<div class="col-md-6">\
<select class="form-control" style="width: 200px" name="dit-doctype">\
</select><br><br>\
<label>\
<input type="checkbox" name="dit-with-data"> <span>'+ __("Download with data") + '</span>\
</label>\
<p class="text-muted">' + __("Export all rows in CSV fields for re-upload. This is ideal for bulk-editing.") + '</p>\
</div>\
<div class="col-md-6">\
<div class="alert alert-warning hide" id="dit-download"></div>\
</div>\
</div>\
</div>\
<hr>\
<h3>2. '+ __("Import Data") + '</h3>\
<p class="help">' + __("Attach .csv file to import data") + '</p>\
<div id="dit-upload-area"></div><br>\
<div class="dit-progress-area" style="display: None"></div>\
<p id="dit-output"></p>\
<div class="msg-box">\
<h4>' + __("Help: Importing non-English data in Microsoft Excel") + '</h4>\
<p>' + __("While uploading non English files ensure that the encoding is UTF-8.") + '</p>\
<ol>\
<li>' + __("In Excel, save the file in CSV (Comma Delimited) format") + '</li>\
<li>' + __("Open this saved file in Notepad") + '</li>\
<li>' + __("Click on File -&gt; Save As") + '</li>\
<li>' + __("File Name: &lt;your filename&gt;.csv<br />\
Save as type: Text Documents (*.txt)<br />\
Encoding: UTF-8") + '\
</li>\
<li>' + __("Click on Save") + '</li>\
</ol>\
</p>\
</div>');

$select = $(wrapper).find('[name="dit-doctype"]');

frappe.messages.waiting($(wrapper).find(".dit-progress-area").toggle(false),
__("Performing hardcore import process")+ "....", 100);
},
make: function() {
var me = this;
frappe.boot.user.can_import = frappe.boot.user.can_import.sort();


// check if template with_data is allowed
var validate_download_with_data = function(doctype, verbose) {
// if no export permission, uncheck with data
var with_data = $('[name="dit-with-data"]').prop("checked");
if(with_data && !frappe.model.can_export(doctype)) {
$('[name="dit-with-data"]').prop("checked", false);
with_data = false;
$(frappe.render_template("data_import_main", this)).appendTo(this.page.main);


if(verbose) {
msgprint(__("You are not allowed to export the data of: {0}. Downloading empty template.", [doctype]));
this.select = this.page.main.find("select.doctype");
this.select.on("change", function() {
me.doctype = $(this).val();
me.page.main.find(".export-import-section").toggleClass(!!me.doctype);
if(me.doctype) {
me.set_btn_links();
// set button links
} }
}
return with_data;
};

wrapper.add_template_download_link = function(doctype) {
return $('<a style="cursor: pointer">')
.html(doctype)
.data('doctype', doctype)
.data('all_doctypes', "No")
.click(function() {
var doctype = $(this).data('doctype');
var parent_doctype = $('[name="dit-doctype"]').val();
var with_data = validate_download_with_data(parent_doctype || doctype, true);
window.location.href = repl(frappe.request.url
+ '?cmd=%(cmd)s&doctype=%(doctype)s'
+ '&parent_doctype=%(parent_doctype)s'
+ '&with_data=%(with_data)s'
+ '&all_doctypes=%(all_doctypes)s',
{
cmd: 'frappe.core.page.data_import_tool.exporter.get_template',
doctype: doctype,
parent_doctype: parent_doctype,
with_data: with_data ? 'Yes' : 'No',
all_doctypes: $(this).data('all_doctypes')
});
})
.appendTo('#dit-download');
}
});
},
set_btn_links: function() {
var doctype = encodeURIComponent(this.doctype);
this.page.main.find(".btn-download-template").attr("href",
"/api/method/frappe.core.page.data_import_tool.exporter.get_template?"
+ "doctype=" + doctype
+ "&parent_doctype=" + doctype
+ "&with_data=No&all_doctypes=Yes");

this.page.main.find(".btn-download-data").attr("href",
"/api/method/frappe.core.page.data_import_tool.exporter.get_template?"
+ "doctype=" + doctype
+ "&parent_doctype=" + doctype
+ "&with_data=Yes&all_doctypes=Yes");
},
make_upload: function() {
var me = this;
frappe.upload.make({
parent: this.page.main.find(".upload-area"),
btn: this.page.main.find(".btn-import"),
get_params: function() {
return {
submit_after_import: me.page.main.find('[name="submit_after_import"]').prop("checked"),
ignore_encoding_errors: me.page.main.find('[name="ignore_encoding_errors"]').prop("checked"),
overwrite: !me.page.main.find('[name="always_insert"]').prop("checked")
}
},
args: {
method: 'frappe.core.page.data_import_tool.importer.upload',
},
onerror: function(r) {
me.onerror(r);
},
callback: function(attachment, r) {
if(r.message.error) {
me.onerror(r);
} else {
// replace links if error has occured
r.messages = ["<h5 style='color:green'>" + __("Import Successful!") + "</h5>"].
concat(r.message.messages)


// load options
$select.change(function() {
});
me.write_messages(r);
}
}
});


var write_messages = function(r) {
$(wrapper).find(".dit-progress-area").toggle(false);
$("#dit-output").empty();
},
write_messages: function(r) {
this.page.main.find(".import-log").removeClass("hide");
var parent = this.page.main.find(".import-log-messages").empty();


$.each(r.messages, function(i, v) { $.each(r.messages, function(i, v) {
var $p = $('<p></p>').html(frappe.markdown(v)).appendTo('#dit-output');
$("<hr>").appendTo('#dit-output');
var $p = $('<p></p>').html(frappe.markdown(v)).appendTo(parent);
if(v.substr(0,5)=='Error') { if(v.substr(0,5)=='Error') {
$p.css('color', 'red'); $p.css('color', 'red');
} else if(v.substr(0,8)=='Inserted') { } else if(v.substr(0,8)=='Inserted') {
@@ -208,73 +96,36 @@ frappe.pages['data-import-tool'].onload = function(wrapper) {
$p.css('color', '#777'); $p.css('color', '#777');
} }
}); });
}

var onerror = function(r) {
$(wrapper).find(".dit-progress-area").toggle(false);
r.messages = $.map(r.message.messages, function(v) {
var msg = v.replace("Inserted", "Valid")
.replace("Updated", "Valid").split("<");
if (msg.length > 1) {
v = msg[0] + (msg[1].split(">").slice(-1)[0]);
} else {
v = msg[0];
}
return v;
});


r.messages = ["<h4 style='color:red'>" + __("Import Failed!") + "</h4>"]
.concat(r.messages);
},
onerror: function(r) {
if(r.message) {
// bad design: moves r.messages to r.message.messages
r.messages = $.map(r.message.messages, function(v) {
var msg = v.replace("Inserted", "Valid")
.replace("Updated", "Valid").split("<");
if (msg.length > 1) {
v = msg[0] + (msg[1].split(">").slice(-1)[0]);
} else {
v = msg[0];
}
return v;
});


write_messages(r);
};
r.messages = ["<h4 style='color:red'>" + __("Import Failed") + "</h4>"]
.concat(r.messages);


// upload
frappe.upload.make({
parent: $('#dit-upload-area'),
args: {
method: 'frappe.core.page.data_import_tool.importer.upload'
},
onerror: onerror,
callback: function(attachment, r) {
if(r.message.error) {
onerror(r);
} else {
// replace links if error has occured
r.messages = ["<h4 style='color:green'>" + __("Import Successful!") + "</h4>"].
concat(r.message.messages)
r.messages.push("Please correct and import again.");


write_messages(r);
}
this.write_messages(r);
} }
});

// add overwrite option
var $submit_btn = $('#dit-upload-area button.btn-upload')
.html('<i class="icon-upload"></i> ' + __("Upload and Import"));

$('<label><input type="checkbox" name="overwrite"> <span>' + __("Overwrite") + '</span></label>\
<p class="text-muted">' + __("If you are uploading a child table (for example Item Price), the all the entries of that table will be deleted (for that parent record) and new entries will be made.") + '</p><br>')
.insertBefore($submit_btn);

// add submit option
$('<label><input type="checkbox" name="_submit"> <span>' + __("Submit") + '</span></label>\
<p class="text-muted">' + __("If you are inserting new records (overwrite not checked) \
and if you have submit permission, the record will be submitted.") + '</p><br>')
.insertBefore($submit_btn);

// add ignore option
$('<label><input type="checkbox" name="ignore_encoding_errors"> <span>' + __("Ignore Encoding Errors") + '</span></label><br></br>')
.insertBefore($submit_btn);
}
});


// rename button
$('#dit-upload-area button.btn-upload')
.click(function() {
$('#dit-output').empty();
$(wrapper).find(".dit-progress-area").toggle(true);
});
frappe.pages['data-import-tool'].onload = function(wrapper) {
frappe.data_import_tool = new frappe.DataImportTool(wrapper);
} }


frappe.pages['data-import-tool'].onshow = function(wrapper) { frappe.pages['data-import-tool'].onshow = function(wrapper) {
wrapper.set_route_options && wrapper.set_route_options();
frappe.data_import_tool && frappe.data_import_tool.set_route_options();
} }

+ 5
- 3
frappe/core/page/data_import_tool/importer.py Bestand weergeven

@@ -21,7 +21,7 @@ def upload(rows = None, submit_after_import=None, ignore_encoding_errors=False,
# extra input params # extra input params
params = json.loads(frappe.form_dict.get("params") or '{}') params = json.loads(frappe.form_dict.get("params") or '{}')


if params.get("_submit"):
if params.get("submit_after_import"):
submit_after_import = True submit_after_import = True
if params.get("ignore_encoding_errors"): if params.get("ignore_encoding_errors"):
ignore_encoding_errors = True ignore_encoding_errors = True
@@ -170,6 +170,7 @@ def upload(rows = None, submit_after_import=None, ignore_encoding_errors=False,
make_column_map() make_column_map()


frappe.db.begin() frappe.db.begin()

if overwrite==None: if overwrite==None:
overwrite = params.get('overwrite') overwrite = params.get('overwrite')


@@ -201,7 +202,7 @@ def upload(rows = None, submit_after_import=None, ignore_encoding_errors=False,
ret.append('Inserted row for %s at #%s' % (getlink(parenttype, ret.append('Inserted row for %s at #%s' % (getlink(parenttype,
doc.parent), unicode(doc.idx))) doc.parent), unicode(doc.idx)))
else: else:
if overwrite and frappe.db.exists(doctype, doc["name"]):
if overwrite and doc["name"] and frappe.db.exists(doctype, doc["name"]):
original = frappe.get_doc(doctype, doc["name"]) original = frappe.get_doc(doctype, doc["name"])
original.update(doc) original.update(doc)
original.ignore_links = ignore_links original.ignore_links = ignore_links
@@ -252,4 +253,5 @@ def get_parent_field(doctype, parenttype):
def delete_child_rows(rows, doctype): def delete_child_rows(rows, doctype):
"""delete child rows for all parents""" """delete child rows for all parents"""
for p in list(set([r[1] for r in rows])): for p in list(set([r[1] for r in rows])):
frappe.db.sql("""delete from `tab%s` where parent=%s""" % (doctype, '%s'), p)
if p:
frappe.db.sql("""delete from `tab{0}` where parent=%s""".format(doctype), p)

+ 74
- 35
frappe/core/page/data_import_tool/test_exporter_fixtures.py Bestand weergeven

@@ -7,212 +7,251 @@ from frappe.core.page.data_import_tool.data_import_tool import export_csv
import unittest import unittest


class TestDataImportFixtures(unittest.TestCase): class TestDataImportFixtures(unittest.TestCase):
def setUp(self):
print "\nTeste for export explicit fixtures"
print "see fixtures csv test files in sites folder"
#start test for Custom Script #start test for Custom Script
def test_Custom_Script_fixture_simple(self): def test_Custom_Script_fixture_simple(self):
fixture = "Custom Script" fixture = "Custom Script"
path = frappe.scrub(fixture) + "_original_style.csv" path = frappe.scrub(fixture) + "_original_style.csv"
print "teste done {}".format(path)
export_csv(fixture, path) export_csv(fixture, path)
self.assertTrue(True) self.assertTrue(True)
def test_Custom_Script_fixture_simple_name_equal_default(self): def test_Custom_Script_fixture_simple_name_equal_default(self):
fixture = ["Custom Script", {"name":["Item-Client"]}] fixture = ["Custom Script", {"name":["Item-Client"]}]
path = frappe.scrub(fixture[0]) + "_simple_name_equal_default.csv" path = frappe.scrub(fixture[0]) + "_simple_name_equal_default.csv"
print "teste done {}".format(path)
export_csv(fixture, path) export_csv(fixture, path)
self.assertTrue(True) self.assertTrue(True)
def test_Custom_Script_fixture_simple_name_equal(self): def test_Custom_Script_fixture_simple_name_equal(self):
fixture = ["Custom Script", {"name":["Item-Client"],"op":"="}] fixture = ["Custom Script", {"name":["Item-Client"],"op":"="}]
path = frappe.scrub(fixture[0]) + "_simple_name_equal.csv" path = frappe.scrub(fixture[0]) + "_simple_name_equal.csv"
print "teste done {}".format(path)
export_csv(fixture, path) export_csv(fixture, path)
self.assertTrue(True) self.assertTrue(True)
def test_Custom_Script_fixture_simple_name_not_equal(self): def test_Custom_Script_fixture_simple_name_not_equal(self):
fixture = ["Custom Script", {"name":["Item-Client"],"op":"!="}] fixture = ["Custom Script", {"name":["Item-Client"],"op":"!="}]
path = frappe.scrub(fixture[0]) + "_simple_name_not_equal.csv" path = frappe.scrub(fixture[0]) + "_simple_name_not_equal.csv"
print "teste done {}".format(path)
export_csv(fixture, path) export_csv(fixture, path)
self.assertTrue(True) self.assertTrue(True)
#without [] around the name... #without [] around the name...
def test_Custom_Script_fixture_simple_name_at_least_equal(self): def test_Custom_Script_fixture_simple_name_at_least_equal(self):
fixture = ["Custom Script", {"name":"Item-Cli"}] fixture = ["Custom Script", {"name":"Item-Cli"}]
path = frappe.scrub(fixture[0]) + "_simple_name_at_least_equal.csv" path = frappe.scrub(fixture[0]) + "_simple_name_at_least_equal.csv"
print "teste done {}".format(path)
export_csv(fixture, path) export_csv(fixture, path)
self.assertTrue(True) self.assertTrue(True)
def test_Custom_Script_fixture_multi_name_equal(self): def test_Custom_Script_fixture_multi_name_equal(self):
fixture = ["Custom Script", {"name":["Item-Client", "Customer-Client"],"op":"="}] fixture = ["Custom Script", {"name":["Item-Client", "Customer-Client"],"op":"="}]
path = frappe.scrub(fixture[0]) + "_multi_name_equal.csv" path = frappe.scrub(fixture[0]) + "_multi_name_equal.csv"
print "teste done {}".format(path)
export_csv(fixture, path) export_csv(fixture, path)
self.assertTrue(True) self.assertTrue(True)
def test_Custom_Script_fixture_multi_name_not_equal(self): def test_Custom_Script_fixture_multi_name_not_equal(self):
fixture = ["Custom Script", {"name":["Item-Client", "Customer-Client"],"op":"!="}] fixture = ["Custom Script", {"name":["Item-Client", "Customer-Client"],"op":"!="}]
path = frappe.scrub(fixture[0]) + "_multi_name_not_equal.csv" path = frappe.scrub(fixture[0]) + "_multi_name_not_equal.csv"
print "teste done {}".format(path)
export_csv(fixture, path) export_csv(fixture, path)
self.assertTrue(True) self.assertTrue(True)
def test_Custom_Script_fixture_empty_object(self): def test_Custom_Script_fixture_empty_object(self):
fixture = ["Custom Script", {}] fixture = ["Custom Script", {}]
path = frappe.scrub(fixture[0]) + "_empty_object_should_be_all.csv" path = frappe.scrub(fixture[0]) + "_empty_object_should_be_all.csv"
print "teste done {}".format(path)
export_csv(fixture, path) export_csv(fixture, path)
self.assertTrue(True) self.assertTrue(True)
def test_Custom_Script_fixture_just_list(self): def test_Custom_Script_fixture_just_list(self):
fixture = ["Custom Script"] fixture = ["Custom Script"]
path = frappe.scrub(fixture[0]) + "_just_list_should_be_all.csv" path = frappe.scrub(fixture[0]) + "_just_list_should_be_all.csv"
print "teste done {}".format(path)
export_csv(fixture, path) export_csv(fixture, path)
self.assertTrue(True) self.assertTrue(True)
# Custom Script regular expression # Custom Script regular expression
def test_Custom_Script_fixture_rex_no_flags(self): def test_Custom_Script_fixture_rex_no_flags(self):
fixture = ["Custom Script", {"name":r"^[i|A]"}] fixture = ["Custom Script", {"name":r"^[i|A]"}]
path = frappe.scrub(fixture[0]) + "_rex_no_flags.csv" path = frappe.scrub(fixture[0]) + "_rex_no_flags.csv"
print "teste done {}".format(path)
export_csv(fixture, path) export_csv(fixture, path)
self.assertTrue(True) self.assertTrue(True)
def test_Custom_Script_fixture_rex_with_flags(self): def test_Custom_Script_fixture_rex_with_flags(self):
fixture = ["Custom Script", {"name":r"^[i|A]", "flags":"L,M"}] fixture = ["Custom Script", {"name":r"^[i|A]", "flags":"L,M"}]
path = frappe.scrub(fixture[0]) + "_rex_with_flags.csv" path = frappe.scrub(fixture[0]) + "_rex_with_flags.csv"
print "teste done {}".format(path)
export_csv(fixture, path) export_csv(fixture, path)
self.assertTrue(True) self.assertTrue(True)
#start test for Custom Field #start test for Custom Field
def test_Custom_Field_fixture_simple(self): def test_Custom_Field_fixture_simple(self):
fixture = "Custom Field" fixture = "Custom Field"
path = frappe.scrub(fixture) + "_original_style.csv" path = frappe.scrub(fixture) + "_original_style.csv"
print "teste done {}".format(path)
export_csv(fixture, path) export_csv(fixture, path)
self.assertTrue(True) self.assertTrue(True)
def test_Custom_Field_fixture_simple_name_equal_default(self): def test_Custom_Field_fixture_simple_name_equal_default(self):
fixture = ["Custom Field", {"name":["Item-vat"]}] fixture = ["Custom Field", {"name":["Item-vat"]}]
path = frappe.scrub(fixture[0]) + "_simple_name_equal_default.csv" path = frappe.scrub(fixture[0]) + "_simple_name_equal_default.csv"
print "teste done {}".format(path)
export_csv(fixture, path) export_csv(fixture, path)
self.assertTrue(True) self.assertTrue(True)
def test_Custom_Field_fixture_simple_name_equal(self): def test_Custom_Field_fixture_simple_name_equal(self):
fixture = ["Custom Field", {"name":["Item-vat"],"op":"="}] fixture = ["Custom Field", {"name":["Item-vat"],"op":"="}]
path = frappe.scrub(fixture[0]) + "_simple_name_equal.csv" path = frappe.scrub(fixture[0]) + "_simple_name_equal.csv"
print "teste done {}".format(path)
export_csv(fixture, path) export_csv(fixture, path)
self.assertTrue(True) self.assertTrue(True)
def test_Custom_Field_fixture_simple_name_not_equal(self): def test_Custom_Field_fixture_simple_name_not_equal(self):
fixture = ["Custom Field", {"name":["Item-vat"],"op":"!="}] fixture = ["Custom Field", {"name":["Item-vat"],"op":"!="}]
path = frappe.scrub(fixture[0]) + "_simple_name_not_equal.csv" path = frappe.scrub(fixture[0]) + "_simple_name_not_equal.csv"
print "teste done {}".format(path)
export_csv(fixture, path) export_csv(fixture, path)
self.assertTrue(True) self.assertTrue(True)
#without [] around the name... #without [] around the name...
def test_Custom_Field_fixture_simple_name_at_least_equal(self): def test_Custom_Field_fixture_simple_name_at_least_equal(self):
fixture = ["Custom Field", {"name":"Item-va"}] fixture = ["Custom Field", {"name":"Item-va"}]
path = frappe.scrub(fixture[0]) + "_simple_name_at_least_equal.csv" path = frappe.scrub(fixture[0]) + "_simple_name_at_least_equal.csv"
print "teste done {}".format(path)
export_csv(fixture, path) export_csv(fixture, path)
self.assertTrue(True) self.assertTrue(True)
def test_Custom_Field_fixture_multi_name_equal(self): def test_Custom_Field_fixture_multi_name_equal(self):
fixture = ["Custom Field", {"name":["Item-vat", "Bin-vat"],"op":"="}] fixture = ["Custom Field", {"name":["Item-vat", "Bin-vat"],"op":"="}]
path = frappe.scrub(fixture[0]) + "_multi_name_equal.csv" path = frappe.scrub(fixture[0]) + "_multi_name_equal.csv"
print "teste done {}".format(path)
export_csv(fixture, path) export_csv(fixture, path)
self.assertTrue(True) self.assertTrue(True)
def test_Custom_Field_fixture_multi_name_not_equal(self): def test_Custom_Field_fixture_multi_name_not_equal(self):
fixture = ["Custom Field", {"name":["Item-vat", "Bin-vat"],"op":"!="}] fixture = ["Custom Field", {"name":["Item-vat", "Bin-vat"],"op":"!="}]
path = frappe.scrub(fixture[0]) + "_multi_name_not_equal.csv" path = frappe.scrub(fixture[0]) + "_multi_name_not_equal.csv"
print "teste done {}".format(path)
export_csv(fixture, path) export_csv(fixture, path)
self.assertTrue(True) self.assertTrue(True)
def test_Custom_Field_fixture_empty_object(self): def test_Custom_Field_fixture_empty_object(self):
fixture = ["Custom Field", {}] fixture = ["Custom Field", {}]
path = frappe.scrub(fixture[0]) + "_empty_object_should_be_all.csv" path = frappe.scrub(fixture[0]) + "_empty_object_should_be_all.csv"
print "teste done {}".format(path)
export_csv(fixture, path) export_csv(fixture, path)
self.assertTrue(True) self.assertTrue(True)
def test_Custom_Field_fixture_just_list(self): def test_Custom_Field_fixture_just_list(self):
fixture = ["Custom Field"] fixture = ["Custom Field"]
path = frappe.scrub(fixture[0]) + "_just_list_should_be_all.csv" path = frappe.scrub(fixture[0]) + "_just_list_should_be_all.csv"
print "teste done {}".format(path)
export_csv(fixture, path) export_csv(fixture, path)
self.assertTrue(True) self.assertTrue(True)
# Custom Field regular expression # Custom Field regular expression
def test_Custom_Field_fixture_rex_no_flags(self): def test_Custom_Field_fixture_rex_no_flags(self):
fixture = ["Custom Field", {"name":r"^[r|L]"}] fixture = ["Custom Field", {"name":r"^[r|L]"}]
path = frappe.scrub(fixture[0]) + "_rex_no_flags.csv" path = frappe.scrub(fixture[0]) + "_rex_no_flags.csv"
print "teste done {}".format(path)
export_csv(fixture, path) export_csv(fixture, path)
self.assertTrue(True) self.assertTrue(True)
def test_Custom_Field_fixture_rex_with_flags(self): def test_Custom_Field_fixture_rex_with_flags(self):
fixture = ["Custom Field", {"name":r"^[i|A]", "flags":"L,M"}] fixture = ["Custom Field", {"name":r"^[i|A]", "flags":"L,M"}]
path = frappe.scrub(fixture[0]) + "_rex_with_flags.csv" path = frappe.scrub(fixture[0]) + "_rex_with_flags.csv"
print "teste done {}".format(path)
export_csv(fixture, path) export_csv(fixture, path)
self.assertTrue(True) self.assertTrue(True)
#start test for Doctype #start test for Doctype
def test_Doctype_fixture_simple(self): def test_Doctype_fixture_simple(self):
fixture = "ToDo" fixture = "ToDo"
path = "Doctype_" + frappe.scrub(fixture) + "_original_style_should_be_all.csv" path = "Doctype_" + frappe.scrub(fixture) + "_original_style_should_be_all.csv"
print "teste done {}".format(path)
export_csv(fixture, path) export_csv(fixture, path)
self.assertTrue(True) self.assertTrue(True)
def test_Doctype_fixture_simple_name_equal_default(self): def test_Doctype_fixture_simple_name_equal_default(self):
fixture = ["ToDo", {"name":["TDI00000008"]}] fixture = ["ToDo", {"name":["TDI00000008"]}]
path = "Doctype_" + frappe.scrub(fixture[0]) + "_simple_name_equal_default.csv" path = "Doctype_" + frappe.scrub(fixture[0]) + "_simple_name_equal_default.csv"
print "teste done {}".format(path)
export_csv(fixture, path) export_csv(fixture, path)
self.assertTrue(True) self.assertTrue(True)
def test_Doctype_fixture_simple_name_equal(self): def test_Doctype_fixture_simple_name_equal(self):
fixture = ["ToDo", {"name":["TDI00000002"],"op":"="}] fixture = ["ToDo", {"name":["TDI00000002"],"op":"="}]
path = "Doctype_" + frappe.scrub(fixture[0]) + "_simple_name_equal.csv" path = "Doctype_" + frappe.scrub(fixture[0]) + "_simple_name_equal.csv"
print "teste done {}".format(path)
export_csv(fixture, path) export_csv(fixture, path)
self.assertTrue(True) self.assertTrue(True)
def test_Doctype_simple_name_not_equal(self): def test_Doctype_simple_name_not_equal(self):
fixture = ["ToDo", {"name":["TDI00000002"],"op":"!="}] fixture = ["ToDo", {"name":["TDI00000002"],"op":"!="}]
path = "Doctype_" + frappe.scrub(fixture[0]) + "_simple_name_not_equal.csv" path = "Doctype_" + frappe.scrub(fixture[0]) + "_simple_name_not_equal.csv"
print "teste done {}".format(path)
export_csv(fixture, path) export_csv(fixture, path)
self.assertTrue(True) self.assertTrue(True)
#without [] around the name... #without [] around the name...
def test_Doctype_fixture_simple_name_at_least_equal(self): def test_Doctype_fixture_simple_name_at_least_equal(self):
fixture = ["ToDo", {"name":"TDI"}] fixture = ["ToDo", {"name":"TDI"}]
path = "Doctype_" + frappe.scrub(fixture[0]) + "_simple_name_at_least_equal.csv" path = "Doctype_" + frappe.scrub(fixture[0]) + "_simple_name_at_least_equal.csv"
print "teste done {}".format(path)
export_csv(fixture, path) export_csv(fixture, path)
self.assertTrue(True) self.assertTrue(True)
def test_Doctype_multi_name_equal(self): def test_Doctype_multi_name_equal(self):
fixture = ["ToDo", {"name":["TDI00000002", "TDI00000008"],"op":"="}] fixture = ["ToDo", {"name":["TDI00000002", "TDI00000008"],"op":"="}]
path = "Doctype_" + frappe.scrub(fixture[0]) + "_multi_name_equal.csv" path = "Doctype_" + frappe.scrub(fixture[0]) + "_multi_name_equal.csv"
print "teste done {}".format(path)
export_csv(fixture, path) export_csv(fixture, path)
self.assertTrue(True) self.assertTrue(True)
def test_Doctype_multi_name_not_equal(self): def test_Doctype_multi_name_not_equal(self):
fixture = ["ToDo", {"name":["TDI00000002", "TDI00000008"],"op":"!="}] fixture = ["ToDo", {"name":["TDI00000002", "TDI00000008"],"op":"!="}]
path = "Doctype_" + frappe.scrub(fixture[0]) + "_multi_name_not_equal.csv" path = "Doctype_" + frappe.scrub(fixture[0]) + "_multi_name_not_equal.csv"
print "teste done {}".format(path)
export_csv(fixture, path) export_csv(fixture, path)
self.assertTrue(True) self.assertTrue(True)
def test_Doctype_fixture_empty_object(self): def test_Doctype_fixture_empty_object(self):
fixture = ["ToDo", {}] fixture = ["ToDo", {}]
path = "Doctype_" + frappe.scrub(fixture[0]) + "_empty_object_should_be_all.csv" path = "Doctype_" + frappe.scrub(fixture[0]) + "_empty_object_should_be_all.csv"
print "teste done {}".format(path)
export_csv(fixture, path) export_csv(fixture, path)
self.assertTrue(True) self.assertTrue(True)
def test_Doctype_fixture_just_list(self): def test_Doctype_fixture_just_list(self):
fixture = ["ToDo"] fixture = ["ToDo"]
path = "Doctype_" + frappe.scrub(fixture[0]) + "_just_list_should_be_all.csv" path = "Doctype_" + frappe.scrub(fixture[0]) + "_just_list_should_be_all.csv"
print "teste done {}".format(path)
export_csv(fixture, path) export_csv(fixture, path)
self.assertTrue(True) self.assertTrue(True)
# Doctype regular expression # Doctype regular expression
def test_Doctype_fixture_rex_no_flags(self): def test_Doctype_fixture_rex_no_flags(self):
fixture = ["ToDo", {"name":r"^TDi"}] fixture = ["ToDo", {"name":r"^TDi"}]
path = "Doctype_" + frappe.scrub(fixture[0]) + "_rex_no_flags_should_be_all.csv" path = "Doctype_" + frappe.scrub(fixture[0]) + "_rex_no_flags_should_be_all.csv"
print "teste done {}".format(path)
export_csv(fixture, path) export_csv(fixture, path)
self.assertTrue(True) self.assertTrue(True)
def test_Doctype_fixture_rex_with_flags(self): def test_Doctype_fixture_rex_with_flags(self):
fixture = ["ToDo", {"name":r"^TDi", "flags":"L,M"}] fixture = ["ToDo", {"name":r"^TDi", "flags":"L,M"}]
path = "Doctype_" + frappe.scrub(fixture[0]) + "_rex_with_flags_should_be_none.csv" path = "Doctype_" + frappe.scrub(fixture[0]) + "_rex_with_flags_should_be_none.csv"
print "teste done {}".format(path)
export_csv(fixture, path) export_csv(fixture, path)
self.assertTrue(True) self.assertTrue(True)


+ 3
- 3
frappe/model/document.py Bestand weergeven

@@ -391,7 +391,7 @@ class Document(BaseDocument):
self._action = "submit" self._action = "submit"
self.check_permission("submit") self.check_permission("submit")
else: else:
raise frappe.DocstatusTransitionError("Cannot change docstatus from 0 to 2")
raise frappe.DocstatusTransitionError, _("Cannot change docstatus from 0 to 2")


elif docstatus==1: elif docstatus==1:
if self.docstatus==1: if self.docstatus==1:
@@ -401,10 +401,10 @@ class Document(BaseDocument):
self._action = "cancel" self._action = "cancel"
self.check_permission("cancel") self.check_permission("cancel")
else: else:
raise frappe.DocstatusTransitionError("Cannot change docstatus from 1 to 0")
raise frappe.DocstatusTransitionError, _("Cannot change docstatus from 1 to 0")


elif docstatus==2: elif docstatus==2:
raise frappe.ValidationError
raise frappe.ValidationError, _("Cannot edit cancelled document")


def set_parent_in_children(self): def set_parent_in_children(self):
"""Updates `parent` and `parenttype` property in all children.""" """Updates `parent` and `parenttype` property in all children."""


+ 1
- 1
frappe/public/css/bootstrap.css
Diff onderdrukt omdat het te groot bestand
Bestand weergeven


+ 1
- 1
frappe/public/js/frappe/ui/page.js Bestand weergeven

@@ -16,7 +16,7 @@ frappe.ui.make_app_page = function(opts) {
*/ */


opts.parent.page = new frappe.ui.Page(opts); opts.parent.page = new frappe.ui.Page(opts);
return opts.parent.page;
} }


frappe.ui.Page = Class.extend({ frappe.ui.Page = Class.extend({


+ 3
- 17
frappe/public/js/frappe/upload.js Bestand weergeven

@@ -22,24 +22,10 @@ frappe.upload = {
// get the first file // get the first file
opts.btn.click(function() { opts.btn.click(function() {
// convert functions to values // convert functions to values
for(key in opts.args) {
if(typeof val==="function")
opt.args[key] = opts.args[key]();
}


// add other inputs in the div as arguments
opts.args.params = {};
$upload.find("input[name]").each(function() {
var key = $(this).attr("name");
var type = $(this).attr("type");
if(key!="filedata" && key!="file_url") {
if(type === "checkbox") {
opts.args.params[key] = $(this).is(":checked");
} else {
opts.args.params[key] = $(this).val();
}
}
})
if(opts.get_params) {
opts.args.params = opts.get_params();
}


opts.args.file_url = $upload.find('[name="file_url"]').val(); opts.args.file_url = $upload.find('[name="file_url"]').val();




Laden…
Annuleren
Opslaan