[tests] [projects] merged tasks and projects and added quick edit of tasks from projects

This commit is contained in:
Rushabh Mehta 2015-02-22 22:32:39 +05:30
parent 65a2759432
commit d54031f3b5
45 changed files with 291 additions and 277 deletions

View File

@ -1,10 +0,0 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors and Contributors
# See license.txt
import frappe
import unittest
test_records = frappe.get_test_records('C-Form')
class TestC-Form(unittest.TestCase):
pass

View File

@ -1,6 +0,0 @@
[
{
"doctype": "C-Form",
"name": "_Test C-Form 1"
}
]

View File

@ -1,10 +0,0 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors and Contributors
# See license.txt
import frappe
import unittest
test_records = frappe.get_test_records('Mode of Payment')
class TestModeofPayment(unittest.TestCase):
pass

View File

@ -1,6 +0,0 @@
[
{
"doctype": "Mode of Payment",
"name": "_Test Mode of Payment 1"
}
]

View File

@ -4,7 +4,7 @@
import frappe
import unittest
test_records = frappe.get_test_records('Quality Inspection')
# test_records = frappe.get_test_records('Quality Inspection')
class TestQualityInspection(unittest.TestCase):
pass

View File

@ -1,6 +0,0 @@
[
{
"doctype": "Quality Inspection",
"name": "_Test Quality Inspection 1"
}
]

View File

@ -6,6 +6,7 @@ import frappe.permissions
from erpnext.controllers.recurring_document import date_field_map
def test_recurring_document(obj, test_records):
pass
from frappe.utils import get_first_day, get_last_day, add_to_date, nowdate, getdate, add_days
from erpnext.accounts.utils import get_fiscal_year
frappe.db.set_value("Print Settings", "Print Settings", "send_print_as_pdf", 1)
@ -102,6 +103,7 @@ def test_recurring_document(obj, test_records):
_test_recurring_document(obj, doc7, date_field, True)
def _test_recurring_document(obj, base_doc, date_field, first_and_last_day):
pass
from frappe.utils import add_months, get_last_day
from erpnext.controllers.recurring_document import manage_recurring_documents, \
get_next_date

View File

@ -1,10 +0,0 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors and Contributors
# See license.txt
import frappe
import unittest
test_records = frappe.get_test_records('Appraisal')
class TestAppraisal(unittest.TestCase):
pass

View File

@ -1,6 +0,0 @@
[
{
"doctype": "Appraisal",
"name": "_Test Appraisal 1"
}
]

View File

@ -1,10 +0,0 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors and Contributors
# See license.txt
import frappe
import unittest
test_records = frappe.get_test_records('Appraisal Template')
class TestAppraisalTemplate(unittest.TestCase):
pass

View File

@ -1,6 +0,0 @@
[
{
"doctype": "Appraisal Template",
"name": "_Test Appraisal Template 1"
}
]

View File

@ -52,11 +52,22 @@ class SalaryStructure(Document):
self.make_table('Deduction Type','deductions', 'Salary Structure Deduction')
def check_existing(self):
ret = self.get_other_active_salary_structure()
if ret and self.is_active=='Yes':
frappe.throw(_("Another Salary Structure {0} is active for employee {1}. Please make its status 'Inactive' to proceed.").format(ret, self.employee))
def get_other_active_salary_structure(self):
ret = frappe.db.sql("""select name from `tabSalary Structure` where is_active = 'Yes'
and employee = %s and name!=%s""", (self.employee,self.name))
if ret and self.is_active=='Yes':
frappe.throw(_("Another Salary Structure {0} is active for employee {1}. Please make its status 'Inactive' to proceed.").format(cstr(ret[0][0]), self.employee))
return ret[0][0] if ret else None
def before_test_insert(self):
"""Make any existing salary structure for employee inactive."""
ret = self.get_other_active_salary_structure()
if ret:
frappe.db.set_value("Salary Structure", ret, "is_active", "No")
def validate_amount(self):
if flt(self.net_pay) < 0:

View File

@ -173,8 +173,12 @@ frappe.ui.form.on("BOM Operation", "operation", function(frm, cdt, cdn) {
name: d.operation
},
callback: function (data) {
frappe.model.set_value(d.doctype, d.name, "opn_description", data.message.opn_description);
frappe.model.set_value(d.doctype, d.name, "workstation", data.message.workstation);
if(data.message.description) {
frappe.model.set_value(d.doctype, d.name, "description", data.message.description);
}
if(data.message.workstation) {
frappe.model.set_value(d.doctype, d.name, "workstation", data.message.workstation);
}
}
})
});

View File

@ -168,7 +168,7 @@
{
"fieldname": "more_info_section",
"fieldtype": "Section Break",
"label": "More Info",
"label": "",
"permlevel": 0
},
{
@ -279,7 +279,7 @@
"is_submittable": 1,
"issingle": 0,
"istable": 0,
"modified": "2015-02-18 14:58:32.967368",
"modified": "2015-02-21 10:31:18.889394",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "BOM",

View File

@ -7,7 +7,7 @@ import unittest
import frappe
from frappe.utils import cstr
test_records = frappe.get_test_records('Bom')
test_records = frappe.get_test_records('BOM')
class TestBOM(unittest.TestCase):
def test_get_items(self):

View File

@ -61,7 +61,7 @@
"operation": "_Test Operation 1",
"opn_description": "_Test",
"workstation": "_Test Workstation 1",
"time_in_min": 60,
"time_in_mins": 60,
"operating_cost": 100
}
],
@ -100,7 +100,7 @@
"operation": "_Test Operation 1",
"opn_description": "_Test",
"workstation": "_Test Workstation 1",
"time_in_min": 60,
"time_in_mins": 60,
"operating_cost": 140
}
],

View File

@ -26,7 +26,7 @@
"reqd": 0
},
{
"fieldname": "opn_description",
"fieldname": "description",
"fieldtype": "Text",
"in_list_view": 1,
"label": "Operation Description",
@ -77,7 +77,7 @@
],
"idx": 1,
"istable": 1,
"modified": "2015-02-12 17:49:00.126034",
"modified": "2015-02-22 10:26:15.377498",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "BOM Operation",

View File

@ -50,7 +50,7 @@
"precision": ""
},
{
"fieldname": "opn_description",
"fieldname": "description",
"fieldtype": "Text",
"label": "Operation Description",
"permlevel": 0,
@ -65,7 +65,7 @@
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"modified": "2015-02-05 05:11:41.666429",
"modified": "2015-02-22 10:24:26.834166",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Operation",

View File

@ -170,7 +170,7 @@ class ProductionOrder(Document):
self.set('operations', [])
operations = frappe.db.sql("""select operation, opn_description, workstation,
operations = frappe.db.sql("""select operation, description, workstation,
hour_rate, time_in_mins, operating_cost as "planned_operating_cost", "Pending" as status
from `tabBOM Operation` where parent = %s""", self.bom_no, as_dict=1)

View File

@ -121,3 +121,4 @@ erpnext.patches.v5_0.update_item_description_and_image
erpnext.patches.v5_0.update_material_transferred_for_qty
erpnext.patches.v5_0.stock_entry_update_value
erpnext.patches.v5_0.convert_stock_reconciliation
erpnext.patches.v5_0.update_projects

View File

@ -0,0 +1,21 @@
import frappe
def execute():
# convert milestones to tasks
frappe.reload_doctype("Project")
for m in frappe.get_all("Project Milestone", "*"):
frappe.get_doc({
"doctype": "Task",
"subject": m.milestone,
"expected_start_date": m.milestone_date,
"status": "Open" if m.status=="Pending" else "Closed",
"project": m.parent,
}).insert(ignore_permissions=True)
# remove project milestone
frappe.delete_doc("DocType", "Project Milestone")
# remove calendar events for milestone
for e in frappe.get_all("Event", ["name"], {"ref_type": "Project"}):
frappe.delete_doc("Event", e.name)

View File

@ -1,6 +1,15 @@
// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
frappe.ui.form.on("Project Task", "edit_task", function(frm, doctype, name) {
var doc = frappe.get_doc(doctype, name);
if(doc.task_id) {
frappe.set_route("Form", "Task", doc.task_id);
} else {
msgprint(__("Save the document first."));
}
})
// show tasks
cur_frm.cscript.refresh = function(doc) {
if(!doc.__islocal) {

View File

@ -21,7 +21,7 @@
"permlevel": 0
},
{
"description": "Project will get saved and will be searchable with project name given",
"description": "",
"fieldname": "project_name",
"fieldtype": "Data",
"label": "Project Name",
@ -119,27 +119,24 @@
{
"fieldname": "sb_milestones",
"fieldtype": "Section Break",
"label": "Milestones",
"label": "Tasks",
"oldfieldtype": "Section Break",
"options": "icon-flag",
"permlevel": 0
},
{
"description": "Milestones will be added as Events in the Calendar",
"fieldname": "milestones",
"fieldname": "tasks",
"fieldtype": "Table",
"label": "Milestones",
"no_copy": 0,
"oldfieldname": "project_milestones",
"oldfieldtype": "Table",
"options": "Project Milestone",
"label": "Tasks",
"options": "Project Task",
"permlevel": 0,
"search_index": 0
"precision": ""
},
{
"fieldname": "percent_milestones_completed",
"fieldname": "percent_complete",
"fieldtype": "Percent",
"label": "% Milestones Completed",
"in_list_view": 0,
"label": "% Tasks Completed",
"permlevel": 0,
"read_only": 1
},
@ -161,14 +158,6 @@
"permlevel": 0,
"search_index": 0
},
{
"fieldname": "percent_complete",
"fieldtype": "Percent",
"in_list_view": 0,
"label": "% Tasks Completed",
"permlevel": 0,
"read_only": 1
},
{
"fieldname": "company",
"fieldtype": "Link",
@ -273,7 +262,7 @@
"icon": "icon-puzzle-piece",
"idx": 1,
"max_attachments": 4,
"modified": "2015-02-20 05:08:08.569007",
"modified": "2015-02-22 11:17:49.051755",
"modified_by": "Administrator",
"module": "Projects",
"name": "Project",

View File

@ -6,7 +6,6 @@ import frappe
from frappe.utils import flt, getdate
from frappe import _
from erpnext.utilities.transaction_base import delete_events
from frappe.model.document import Document
@ -14,6 +13,18 @@ class Project(Document):
def get_feed(self):
return '{0}: {1}'.format(_(self.status), self.project_name)
def onload(self):
"""Load project tasks for quick view"""
for task in frappe.get_all("Task", "*", {"project": self.name}, order_by="exp_start_date asc"):
self.append("tasks", {
"title": task.subject,
"status": task.status,
"start_date": task.exp_start_date,
"end_date": task.exp_end_date,
"desciption": task.description,
"task_id": task.name
})
def get_gross_profit(self):
pft, per_pft =0, 0
pft = flt(self.project_value) - flt(self.est_material_cost)
@ -23,20 +34,40 @@ class Project(Document):
return ret
def validate(self):
"""validate start date before end date"""
if self.project_start_date and self.completion_date:
if getdate(self.completion_date) < getdate(self.project_start_date):
frappe.throw(_("Expected Completion Date can not be less than Project Start Date"))
self.update_milestones_completed()
self.sync_tasks()
def update_milestones_completed(self):
if self.milestones:
completed = filter(lambda x: x.status=="Completed", self.milestones)
self.percent_milestones_completed = len(completed) * 100 / len(self.milestones)
def sync_tasks(self):
"""sync tasks and remove table"""
task_names = []
for t in self.tasks:
if t.task_id:
task = frappe.get_doc("Task", t.task_id)
else:
task = frappe.new_doc("Task")
task.project = self.name
def on_update(self):
self.add_calendar_event()
task.update({
"subject": t.title,
"status": t.status,
"exp_start_date": t.start_date,
"exp_end_date": t.end_date,
"desciption": t.description,
})
task.flags.ignore_links = True
task.flags.from_project = True
task.save(ignore_permissions = True)
task_names.append(task.name)
# delete
for t in frappe.get_all("Task", ["name"], {"project": self.name, "name": ("not in", task_names)}):
frappe.delete_doc("Task", t.name)
self.tasks = []
def update_percent_complete(self):
total = frappe.db.sql("""select count(*) from tabTask where project=%s""",
@ -48,28 +79,6 @@ class Project(Document):
int(float(completed) / total * 100))
def add_calendar_event(self):
# delete any earlier event for this project
delete_events(self.doctype, self.name)
# add events
for milestone in self.get("milestones"):
if milestone.milestone_date:
description = (milestone.milestone or "Milestone") + " for " + self.name
frappe.get_doc({
"doctype": "Event",
"owner": self.owner,
"subject": description,
"description": description,
"starts_on": milestone.milestone_date + " 10:00:00",
"event_type": "Private",
"ref_type": self.doctype,
"ref_name": self.name
}).insert(ignore_permissions=True)
def on_trash(self):
delete_events(self.doctype, self.name)
@frappe.whitelist()
def get_cost_center_name(project_name):
return frappe.db.get_value("Project", project_name, "cost_center")

View File

@ -1 +0,0 @@
Important date in the project lifecycle.

View File

@ -1 +0,0 @@
from __future__ import unicode_literals

View File

@ -1,45 +0,0 @@
{
"creation": "2013-02-22 01:27:50.000000",
"docstatus": 0,
"doctype": "DocType",
"fields": [
{
"fieldname": "milestone_date",
"fieldtype": "Date",
"in_list_view": 1,
"label": "Milestone Date",
"oldfieldname": "milestone_date",
"oldfieldtype": "Date",
"permlevel": 0
},
{
"fieldname": "milestone",
"fieldtype": "Text",
"in_list_view": 1,
"label": "Milestone",
"oldfieldname": "milestone",
"oldfieldtype": "Text",
"permlevel": 0,
"print_width": "300px",
"width": "300px"
},
{
"fieldname": "status",
"fieldtype": "Select",
"in_list_view": 1,
"label": "Status",
"no_copy": 1,
"oldfieldname": "status",
"oldfieldtype": "Select",
"options": "Pending\nCompleted",
"permlevel": 0
}
],
"idx": 1,
"istable": 1,
"modified": "2013-12-20 19:23:27.000000",
"modified_by": "Administrator",
"module": "Projects",
"name": "Project Milestone",
"owner": "Administrator"
}

View File

@ -0,0 +1,157 @@
{
"allow_copy": 0,
"allow_import": 0,
"allow_rename": 0,
"creation": "2015-02-22 11:15:28.201059",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "Other",
"fields": [
{
"allow_on_submit": 0,
"fieldname": "title",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Title",
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0
},
{
"allow_on_submit": 0,
"default": "Open",
"fieldname": "status",
"fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Status",
"no_copy": 0,
"options": "Open\nClosed",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0
},
{
"fieldname": "edit_task",
"fieldtype": "Button",
"label": "Edit Task",
"permlevel": 0,
"precision": ""
},
{
"fieldname": "column_break_3",
"fieldtype": "Column Break",
"permlevel": 0,
"precision": ""
},
{
"allow_on_submit": 0,
"fieldname": "start_date",
"fieldtype": "Date",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Start Date",
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0
},
{
"allow_on_submit": 0,
"default": "",
"fieldname": "end_date",
"fieldtype": "Date",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "End Date",
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0
},
{
"fieldname": "section_break_6",
"fieldtype": "Section Break",
"permlevel": 0,
"precision": ""
},
{
"allow_on_submit": 0,
"fieldname": "description",
"fieldtype": "Text",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Description",
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0
},
{
"fieldname": "task_id",
"fieldtype": "Link",
"hidden": 1,
"label": "Task ID",
"no_copy": 1,
"options": "Task",
"permlevel": 0,
"precision": ""
}
],
"hide_heading": 0,
"hide_toolbar": 0,
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"modified": "2015-02-22 11:53:23.317993",
"modified_by": "Administrator",
"module": "Projects",
"name": "Project Task",
"name_case": "",
"owner": "Administrator",
"permissions": [],
"read_only": 0,
"read_only_onload": 0,
"sort_field": "modified",
"sort_order": "DESC"
}

View File

@ -1,10 +1,9 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
class ProjectMilestone(Document):
pass
class ProjectTask(Document):
pass

View File

@ -44,7 +44,7 @@ class Task(Document):
def on_update(self):
"""update percent complete in project"""
if self.project:
if self.project and not self.flags.from_project:
project = frappe.get_doc("Project", self.project)
project.run_method("update_percent_complete")

View File

@ -1,6 +0,0 @@
[
{
"doctype": "Time Log Batch",
"name": "_Test Time Log Batch 1"
}
]

View File

@ -1,10 +0,0 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors and Contributors
# See license.txt
import frappe
import unittest
test_records = frappe.get_test_records('Installation Note')
class TestInstallationNote(unittest.TestCase):
pass

View File

@ -72,7 +72,7 @@
"fieldname": "charts_section",
"fieldtype": "Section Break",
"hidden": 0,
"label": "Localization",
"label": "Country Settings",
"permlevel": 0
},
{
@ -272,7 +272,7 @@
"depends_on": "eval:!doc.__islocal",
"fieldname": "auto_accounting_for_stock_settings",
"fieldtype": "Section Break",
"label": "Auto Accounting For Stock Settings",
"label": "Stock Settings",
"permlevel": 0,
"read_only": 0
},
@ -380,7 +380,7 @@
"description": "Company registration numbers for your reference. Example: VAT Registration Numbers etc.",
"fieldname": "registration_info",
"fieldtype": "Section Break",
"label": "Registration Info",
"label": "",
"oldfieldtype": "Section Break",
"permlevel": 0,
"read_only": 0,
@ -399,7 +399,7 @@
],
"icon": "icon-building",
"idx": 1,
"modified": "2015-02-20 05:09:51.973367",
"modified": "2015-02-21 10:32:38.523900",
"modified_by": "Administrator",
"module": "Setup",
"name": "Company",

View File

@ -160,7 +160,7 @@ def install(country=None):
from erpnext.setup.page.setup_wizard.fixtures import industry_type, operations
records += [{"doctype":"Industry Type", "industry": d} for d in industry_type.items]
records += [{"doctype":"Operation", "operation": d} for d in operations.items]
# records += [{"doctype":"Operation", "operation": d} for d in operations.items]
from frappe.modules import scrub
for r in records:

View File

@ -1,6 +0,0 @@
[
{
"doctype": "Batch",
"name": "_Test Batch 1"
}
]

View File

@ -1,6 +0,0 @@
[
{
"doctype": "Landed Cost Voucher",
"name": "_Test Landed Cost Voucher 1"
}
]

View File

@ -1,10 +0,0 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors and Contributors
# See license.txt
import frappe
import unittest
test_records = frappe.get_test_records('Packing Slip')
class TestPackingSlip(unittest.TestCase):
pass

View File

@ -1,6 +0,0 @@
[
{
"doctype": "Packing Slip",
"name": "_Test Packing Slip 1"
}
]

View File

@ -12,6 +12,9 @@ from erpnext.accounts.utils import get_fiscal_year, get_stock_and_account_differ
class TestStockReconciliation(unittest.TestCase):
def setUp(self):
frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1)
def test_reco_for_fifo(self):
frappe.defaults.set_global_default("auto_accounting_for_stock", 0)
# [[qty, valuation_rate, posting_date,
@ -183,10 +186,12 @@ class TestStockReconciliation(unittest.TestCase):
"company": "_Test Company",
"expense_account": "Stock Adjustment - _TC",
"cost_center": "_Test Cost Center - _TC",
"reconciliation_json": json.dumps([
["Item Code", "Warehouse", "Quantity", "Valuation Rate"],
["_Test Item", "_Test Warehouse - _TC", qty, rate]
]),
"items": [{
"item_code": "_Test Item",
"warehouse": "_Test Warehouse - _TC",
"qty": qty,
"valuation_rate": rate
}]
})
stock_reco.insert()
stock_reco.submit()

View File

@ -241,9 +241,9 @@ class update_entries_after(object):
if new_stock_qty:
self.valuation_rate = new_stock_value / flt(new_stock_qty)
elif not self.valuation_rate and self.qty_after_transaction <= 0:
valuation_rate = get_valuation_rate(sle.item_code, sle.warehouse, self.allow_zero_rate)
self.valuation_rate = get_valuation_rate(sle.item_code, sle.warehouse, self.allow_zero_rate)
return abs(flt(valuation_rate))
return abs(flt(self.valuation_rate))
def get_fifo_values(self, sle):
incoming_rate = flt(sle.incoming_rate)

View File

@ -1,10 +0,0 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors and Contributors
# See license.txt
import frappe
import unittest
test_records = frappe.get_test_records('Maintenance Schedule')
class TestMaintenanceSchedule(unittest.TestCase):
pass

View File

@ -1,6 +0,0 @@
[
{
"doctype": "Maintenance Schedule",
"name": "_Test Maintenance Schedule 1"
}
]

View File

@ -1,10 +0,0 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors and Contributors
# See license.txt
import frappe
import unittest
test_records = frappe.get_test_records('Maintenance Visit')
class TestMaintenanceVisit(unittest.TestCase):
pass

View File

@ -1,6 +0,0 @@
[
{
"doctype": "Warranty Claim",
"name": "_Test Warranty Claim 1"
}
]