feat: duplicate linked task in project (#19271)
* feat: create a duplicate project
* fix: allow duplication via form
* feat: fetch old task and link project
* fix: link task with project
* fix: parse json string as python object
* fix: avoid duplicate task based on the project template
* fix: ask user for the new project name
* fix: display a descriptive message on switching to a new route
* fix: override duplicate in menu
* fix: check for duplicate project name after submitting prompt
* fix: set the project template
* fix: minor changes
* fix: function call
* refactor: add a separate button for duplicate
* Update project.js
diff --git a/erpnext/projects/doctype/project/project.js b/erpnext/projects/doctype/project/project.js
index 192e1bc..4a03a58 100644
--- a/erpnext/projects/doctype/project/project.js
+++ b/erpnext/projects/doctype/project/project.js
@@ -19,7 +19,7 @@
frappe.ui.form.make_quick_entry(doctype, null, null, new_doc);
});
},
- }
+ };
},
onload: function (frm) {
var so = frappe.meta.get_docfield("Project", "sales_order");
@@ -28,15 +28,15 @@
return {
"customer": frm.doc.customer,
"project_name": frm.doc.name
- }
- }
+ };
+ };
frm.set_query('customer', 'erpnext.controllers.queries.customer_query');
frm.set_query("user", "users", function () {
return {
query: "erpnext.projects.doctype.project.project.get_users_for_project"
- }
+ };
});
// sales order
@@ -51,7 +51,7 @@
return {
filters: filters
- }
+ };
});
if (frappe.model.can_read("Task")) {
@@ -85,6 +85,10 @@
set_buttons: function(frm) {
if (!frm.is_new()) {
+ frm.add_custom_button(__('Duplicate Project with Tasks'), () => {
+ frm.events.create_duplicate(frm);
+ });
+
frm.add_custom_button(__('Completed'), () => {
frm.events.set_status(frm, 'Completed');
}, __('Set Status'));
@@ -95,6 +99,22 @@
}
},
+ create_duplicate: function(frm) {
+ return new Promise(resolve => {
+ frappe.prompt('Project Name', (data) => {
+ frappe.xcall('erpnext.projects.doctype.project.project.create_duplicate_project',
+ {
+ prev_doc: frm.doc,
+ project_name: data.value
+ }).then(() => {
+ frappe.set_route('Form', "Project", data.value);
+ frappe.show_alert(__("Duplicate project has been created"));
+ });
+ resolve();
+ });
+ });
+ },
+
set_status: function(frm, status) {
frappe.confirm(__('Set Project and all Tasks to status {0}?', [status.bold()]), () => {
frappe.xcall('erpnext.projects.doctype.project.project.set_project_status',
diff --git a/erpnext/projects/doctype/project/project.py b/erpnext/projects/doctype/project/project.py
index 783bcf3..bf6e21a 100644
--- a/erpnext/projects/doctype/project/project.py
+++ b/erpnext/projects/doctype/project/project.py
@@ -323,6 +323,37 @@
if get_time(nowtime()) >= get_time(time):
return True
+
+@frappe.whitelist()
+def create_duplicate_project(prev_doc, project_name):
+ ''' Create duplicate project based on the old project '''
+ import json
+ prev_doc = json.loads(prev_doc)
+
+ if project_name == prev_doc.get('name'):
+ frappe.throw(_("Use a name that is different from previous project name"))
+
+ # change the copied doc name to new project name
+ project = frappe.copy_doc(prev_doc)
+ project.name = project_name
+ project.project_template = ''
+ project.project_name = project_name
+ project.insert()
+
+ # fetch all the task linked with the old project
+ task_list = frappe.get_all("Task", filters={
+ 'project': prev_doc.get('name')
+ }, fields=['name'])
+
+ # Create duplicate task for all the task
+ for task in task_list:
+ task = frappe.get_doc('Task', task)
+ new_task = frappe.copy_doc(task)
+ new_task.project = project.name
+ new_task.insert()
+
+ project.db_set('project_template', prev_doc.get('project_template'))
+
def get_projects_for_collect_progress(frequency, fields):
fields.extend(["name"])