feat: handle resolve and unresolved errors
restructured and reused components
diff --git a/erpnext/erpnext_integrations/doctype/tally_migration/tally_migration.js b/erpnext/erpnext_integrations/doctype/tally_migration/tally_migration.js
index d06fe53..9235bab 100644
--- a/erpnext/erpnext_integrations/doctype/tally_migration/tally_migration.js
+++ b/erpnext/erpnext_integrations/doctype/tally_migration/tally_migration.js
@@ -35,8 +35,10 @@
}
});
},
+
refresh: function (frm) {
- frm.trigger("show_import_log");
+ frm.trigger("show_logs_preview");
+
["default_round_off_account", "default_warehouse", "default_cost_center"].forEach(account => {
frm.toggle_reqd(account, frm.doc.is_master_data_imported === 1)
})
@@ -63,6 +65,7 @@
}
}
},
+
add_button: function (frm, label, method) {
frm.add_custom_button(
label,
@@ -76,94 +79,30 @@
}
);
},
- show_import_log(frm) {
- let index = 0;
- let import_log = JSON.parse(frm.doc.failed_import_log || "[]");
- let logs = import_log.slice(0, 20);
- let hidden_logs = import_log.slice(20);
- frm.toggle_display("import_log_section", logs.length > 0);
-
-
- const getError = (traceback) => {
- let exc_error_idx = traceback.trim().lastIndexOf("\n") + 1
- let error_line = traceback.substr(exc_error_idx)
- let split_str_idx = (error_line.indexOf(':') > 0) ? error_line.indexOf(':') + 1 : 0;
-
- return error_line.slice(split_str_idx).trim();
+ render_html_table(frm, shown_logs, hidden_logs, field) {
+ if (shown_logs && shown_logs.length > 0) {
+ frm.toggle_display(field, true);
+ } else {
+ frm.toggle_display(field, false);
+ return
}
+ let rows = get_html_rows(shown_logs, field);
+ let rows_head;
- const cleanDoc = (obj) => {
- let temp = obj;
- $.each(temp, function(key, value){
- if (value === "" || value === null){
- delete obj[key];
- } else if (Object.prototype.toString.call(value) === '[object Object]') {
- cleanDoc(value);
- } else if ($.isArray(value)) {
- $.each(value, function (k,v) { cleanDoc(v); });
- }
- });
- return temp;
- };
-
- let rows = logs
- .map(({ doc, exc }) => {
- let id = frappe.dom.get_unique_id();
- let traceback = exc;
-
- let error_message = getError(traceback);
- index++;
-
- let html = `
- <button class="btn btn-default btn-xs m-3" type="button" data-toggle="collapse" data-target="#${id}-traceback" aria-expanded="false" aria-controls="${id}-traceback">
- ${__("Show Traceback")}
- </button>
- <div class="collapse margin-top" id="${id}-traceback">
- <div class="well">
- <pre style="font-size: smaller;">${traceback}</pre>
- </div>
- </div>`;
-
- let show_doc = `
- <button class='btn btn-default btn-xs m-3' type='button' data-toggle='collapse' data-target='#${id}-doc' aria-expanded='false' aria-controls='${id}-doc'>
- ${__("Show Document")}
- </button>
- <div class="collapse margin-top" id="${id}-doc">
- <div class="well">
- <pre style="font-size: smaller;">${JSON.stringify(cleanDoc(doc), null, 1)}</pre>
- </div>
- </div>`;
-
- let create_button = `
- <button class='btn btn-default btn-xs m-3' type='button' onclick='frappe.new_doc("${doc.doctype}", ${JSON.stringify(doc)})'>
- ${__("Create Document")}
- </button>`
-
- return `<tr>
- <td>${index}</td>
- <td>
- <div>${doc.doctype}</div>
- </td>
- <td>
- <div>${error_message}</div>
- <div>${html}</div>
- <div>${show_doc}</div>
- </td>
- <td>
- <div>${create_button}</div>
- </td>
- </tr>`;
- })
- .join("");
-
- frm.get_field("failed_import_preview").$wrapper.html(`
+ if (field === "fixed_error_log_preview") {
+ rows_head = `<th width="75%">${__("Meta Data")}</th>
+ <th width="10%">${__("Unresolve")}</th>`
+ } else {
+ rows_head = `<th width="75%">${__("Error Message")}</th>
+ <th width="10%">${__("Create")}</th>`
+ }
+ frm.get_field(field).$wrapper.html(`
<table class="table table-bordered">
<tr class="text-muted">
<th width="5%">${__("#")}</th>
<th width="10%">${__("DocType")}</th>
- <th width="75%">${__("Error Message")}</th>
- <th width="10%">${__("Create")}</th>
+ ${rows_head}
</tr>
${rows}
<tr class="text-muted">
@@ -171,5 +110,201 @@
</tr>
</table>
`);
+ },
+
+ show_error_summary() {
+ let summary = import_log.reduce((summary, row) => {
+ if (row.doc) {
+ if (summary[row.doc.doctype]) {
+ summary[row.doc.doctype] += 1;
+ } else {
+ summary[row.doc.doctype] = 1;
+ }
+ }
+ return summary
+ }, {});
+ console.table(summary);
+ },
+
+ show_logs_preview(frm) {
+ let empty = "[]";
+ let import_log = frm.doc.failed_import_log || empty;
+ let completed_log = frm.doc.fixed_errors_log || empty;
+ let render_section = !(import_log === completed_log && import_log === empty);
+
+ frm.toggle_display("import_log_section", render_section);
+
+ if (render_section) {
+ frm.trigger("show_errored_import_log");
+ frm.trigger("show_fixed_errors_log");
+ }
+ },
+
+ show_errored_import_log(frm) {
+ let import_log = JSON.parse(frm.doc.failed_import_log || "[]");
+
+ let logs = import_log.slice(0, 20);
+ let hidden_logs = import_log.slice(20);
+
+ frm.events.render_html_table(frm, logs, hidden_logs, "failed_import_preview");
+ },
+
+ show_fixed_errors_log(frm) {
+ let completed_log = JSON.parse(frm.doc.fixed_errors_log || "[]");
+ let logs = completed_log.slice(0, 20);
+ let hidden_logs = completed_log.slice(20);
+
+ frm.events.render_html_table(frm, logs, hidden_logs, "fixed_error_log_preview");
}
});
+
+const getError = (traceback) => {
+ /* Extracts the Error Message from the Python Traceback or Solved error */
+ let is_multiline = traceback.trim().indexOf("\n") != -1;
+ let message;
+
+ if (is_multiline) {
+ let exc_error_idx = traceback.trim().lastIndexOf("\n") + 1
+ let error_line = traceback.substr(exc_error_idx)
+ let split_str_idx = (error_line.indexOf(':') > 0) ? error_line.indexOf(':') + 1 : 0;
+ message = error_line.slice(split_str_idx).trim();
+ } else {
+ message = traceback;
+ }
+
+ return message
+}
+
+const cleanDoc = (obj) => {
+ /* Strips all null and empty values of your JSON object */
+ let temp = obj;
+ $.each(temp, function(key, value){
+ if (value === "" || value === null){
+ delete obj[key];
+ } else if (Object.prototype.toString.call(value) === '[object Object]') {
+ cleanDoc(value);
+ } else if ($.isArray(value)) {
+ $.each(value, function (k,v) { cleanDoc(v); });
+ }
+ });
+ return temp;
+}
+
+window.unresolve = (document) => {
+ let frm = cur_frm;
+ let failed_log = JSON.parse(frm.doc.failed_import_log);
+ let fixed_log = JSON.parse(frm.doc.fixed_errors_log);
+
+ let modified_fixed_log = fixed_log.filter(row => {
+ if (!frappe.utils.deep_equal(cleanDoc(row.doc), document)) {
+ return row
+ }
+ });
+
+ failed_log.push({ doc: document, exc: `Marked unresolved on ${Date()}` });
+
+ frm.doc.failed_import_log = JSON.stringify(failed_log);
+ frm.doc.fixed_errors_log = JSON.stringify(modified_fixed_log);
+
+ // frm.trigger('show_logs_preview')
+ frm.dirty();
+ frm.save();
+}
+
+window.create_new_doc = (doctype, document) => {
+ let frm = cur_frm;
+ let failed_log = JSON.parse(frm.doc.failed_import_log);
+ let fixed_log = JSON.parse(frm.doc.fixed_errors_log);
+
+ let modified_failed_log = failed_log.filter(row => {
+ if (!frappe.utils.deep_equal(cleanDoc(row.doc), document)) {
+ return row
+ }
+ });
+ fixed_log.push({ doc: document, exc: `Solved on ${Date()}` });
+
+ frm.doc.failed_import_log = JSON.stringify(modified_failed_log);
+ frm.doc.fixed_errors_log = JSON.stringify(fixed_log);
+
+ // frm.trigger('show_logs_preview')
+ frm.dirty();
+ frm.save();
+ frappe.new_doc(doctype, document);
+}
+
+const get_html_rows = (logs, field) => {
+ let index = 0;
+ let rows = logs
+ .map(({ doc, exc }) => {
+ let id = frappe.dom.get_unique_id();
+ let traceback = exc;
+
+ let error_message = getError(traceback);
+ index++;
+
+ let show_traceback = `
+ <button class="btn btn-default btn-xs m-3" type="button" data-toggle="collapse" data-target="#${id}-traceback" aria-expanded="false" aria-controls="${id}-traceback">
+ ${__("Show Traceback")}
+ </button>
+ <div class="collapse margin-top" id="${id}-traceback">
+ <div class="well">
+ <pre style="font-size: smaller;">${traceback}</pre>
+ </div>
+ </div>`;
+
+ let show_doc = `
+ <button class='btn btn-default btn-xs m-3' type='button' data-toggle='collapse' data-target='#${id}-doc' aria-expanded='false' aria-controls='${id}-doc'>
+ ${__("Show Document")}
+ </button>
+ <div class="collapse margin-top" id="${id}-doc">
+ <div class="well">
+ <pre style="font-size: smaller;">${JSON.stringify(cleanDoc(doc), null, 1)}</pre>
+ </div>
+ </div>`;
+
+ let create_button = `
+ <button class='btn btn-default btn-xs m-3' type='button' onclick='create_new_doc("${doc.doctype}", ${JSON.stringify(doc)})'>
+ ${__("Create Document")}
+ </button>`
+
+ let mark_as_unresolved = `
+ <button class='btn btn-default btn-xs m-3' type='button' onclick='unresolve(${JSON.stringify(doc)})'>
+ ${__("Mark as unresolved")}
+ </button>`
+
+ if (field === "fixed_error_log_preview") {
+ return `<tr>
+ <td>${index}</td>
+ <td>
+ <div>${doc.doctype}</div>
+ </td>
+ <td>
+ <div>${error_message}</div>
+ <div>${show_traceback}</div>
+ <div>${show_doc}</div>
+ </td>
+ <td>
+ <div>${mark_as_unresolved}</div>
+ </td>
+ </tr>`;
+ } else {
+ return `<tr>
+ <td>${index}</td>
+ <td>
+ <div>${doc.doctype}</div>
+ </td>
+ <td>
+ <div>${error_message}</div>
+ <div>${show_traceback}</div>
+ <div>${show_doc}</div>
+ </td>
+ <td>
+ <div>${create_button}</div>
+ </td>
+ </tr>`;
+ }
+ })
+ .join("");
+
+ return rows
+}
\ No newline at end of file