Merge branch 'develop' into staging

This commit is contained in:
Nabin Hait 2017-11-10 11:46:50 +05:30
commit 29741fee08
67 changed files with 4676 additions and 3675 deletions

View File

@ -132,6 +132,7 @@
"get_url_arg": true,
"get_server_fields": true,
"set_multiple": true,
"QUnit": true
"QUnit": true,
"Chart": true
}
}

View File

@ -205,12 +205,10 @@ class Account(Document):
return new_account
def after_rename(self, old, new, merge=False):
super(Account, self).after_rename(old, new, merge)
if not merge:
frappe.db.set_value("Account", new, "account_name",
" - ".join(new.split(" - ")[:-1]))
else:
from frappe.utils.nestedset import rebuild_tree
rebuild_tree("Account", "parent_account")
frappe.db.set_value("Account", new, "account_name", " - ".join(new.split(" - ")[:-1]))
def get_parent_account(doctype, txt, searchfield, start, page_len, filters):
return frappe.db.sql("""select name from tabAccount

View File

@ -59,9 +59,8 @@ class CostCenter(NestedSet):
return new_cost_center
def after_rename(self, olddn, newdn, merge=False):
super(CostCenter, self).after_rename(olddn, newdn, merge)
if not merge:
frappe.db.set_value("Cost Center", newdn, "cost_center_name",
" - ".join(newdn.split(" - ")[:-1]))
else:
super(CostCenter, self).after_rename(olddn, newdn, merge)

View File

@ -566,17 +566,26 @@ def get_default_bank_cash_account(company, account_type=None, mode_of_payment=No
account = get_bank_cash_account(mode_of_payment, company).get("account")
if not account:
'''
Set the default account first. If the user hasn't set any default account then, he doesn't
want us to set any random account. In this case set the account only if there is single
account (of that type), otherwise return empty dict.
'''
if account_type=="Bank":
account = frappe.db.get_value("Company", company, "default_bank_account")
if not account:
account = frappe.db.get_value("Account",
{"company": company, "account_type": "Bank", "is_group": 0})
account_list = frappe.get_all("Account", filters = {"company": company,
"account_type": "Bank", "is_group": 0})
if len(account_list) == 1:
account = account_list[0].name
elif account_type=="Cash":
account = frappe.db.get_value("Company", company, "default_cash_account")
if not account:
account = frappe.db.get_value("Account",
{"company": company, "account_type": "Cash", "is_group": 0})
account_list = frappe.get_all("Account", filters = {"company": company,
"account_type": "Cash", "is_group": 0})
if len(account_list) == 1:
account = account_list[0].name
if account:
account_details = frappe.db.get_value("Account", account,

View File

@ -294,7 +294,7 @@ def get_gateway_details(args):
if args.get("payment_gateway"):
return get_payment_gateway_account(args.get("payment_gateway"))
if args.cart:
if args.order_type == "Shopping Cart":
payment_gateway_account = frappe.get_doc("Shopping Cart Settings").payment_gateway_account
return get_payment_gateway_account(payment_gateway_account)

View File

@ -480,7 +480,67 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "",
"fieldname": "section_break_15",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Applicable for Users",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "applicable_for_users",
"fieldtype": "Table",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Applicable for Users",
"length": 0,
"no_copy": 0,
"options": "POS Profile User",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "section_break_11",
"fieldtype": "Section Break",
"hidden": 0,
@ -1471,7 +1531,7 @@
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"title_field": "user",
"title_field": "pos_profile_name",
"track_changes": 0,
"track_seen": 0
}

View File

@ -11,7 +11,7 @@ from frappe.model.document import Document
class POSProfile(Document):
def validate(self):
self.check_for_duplicate()
# self.check_for_duplicate()
self.validate_all_link_fields()
self.validate_duplicate_groups()
self.check_default_payment()
@ -94,3 +94,45 @@ class POSProfile(Document):
@frappe.whitelist()
def get_series():
return frappe.get_meta("Sales Invoice").get_field("naming_series").options or ""
@frappe.whitelist()
def get_pos_profiles_for_user(user=None):
out = []
if not user:
user = frappe.session.user
res = frappe.db.sql('''
select
parent
from
`tabPOS Profile User`
where
user = %s
''', (user), as_dict=1)
if not res:
company = frappe.defaults.get_user_default('company')
res = frappe.db.sql('''
select
pos_profile_name
from
`tabPOS Profile`
where
company = %s
''', (company), as_dict=1)
out = [r.pos_profile_name for r in res]
return out
for r in res:
name = frappe.db.get_value('POS Profile', r.parent, 'pos_profile_name')
out.append(name)
return out
@frappe.whitelist()
def get_pos_profile(pos_profile_name=None):
if not pos_profile_name: return
name = frappe.db.get_value('POS Profile', { 'pos_profile_name': pos_profile_name })
return frappe.get_doc('POS Profile', name)

View File

@ -0,0 +1,6 @@
// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('POS Profile User', {
});

View File

@ -0,0 +1,93 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
"creation": "2017-10-27 16:46:06.060930",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "user",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "User",
"length": 0,
"no_copy": 0,
"options": "User",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-10-27 16:46:12.784244",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Profile User",
"name_case": "",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
}
],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0
}

View File

@ -0,0 +1,9 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
from frappe.model.document import Document
class POSProfileUser(Document):
pass

View File

@ -16,6 +16,8 @@ def get_pos_data():
doc = frappe.new_doc('Sales Invoice')
doc.is_pos = 1;
pos_profile = get_pos_profile(doc.company) or {}
if not pos_profile:
frappe.throw(_("POS Profile is required to use Point-of-Sale"))
if not doc.company: doc.company = pos_profile.get('company')
doc.update_stock = pos_profile.get('update_stock')

View File

@ -4433,7 +4433,7 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
"modified": "2017-10-24 12:46:48.331723",
"modified": "2017-11-03 05:31:56.636424",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",
@ -4531,5 +4531,5 @@
"timeline_field": "customer",
"title_field": "title",
"track_changes": 1,
"track_seen": 0
"track_seen": 1
}

View File

@ -309,14 +309,16 @@ class ReceivablePayableReport(object):
rows = []
for d in data:
rows.append(d[self.ageing_col_idx_start : self.ageing_col_idx_start+4])
if rows:
rows.insert(0, [[d.get("label")] for d in ageing_columns])
rows.append(
{
'values': d[self.ageing_col_idx_start : self.ageing_col_idx_start+4]
}
)
return {
"data": {
'labels': rows
'labels': [d.get("label") for d in ageing_columns],
'datasets': rows
},
"type": 'percentage'
}

View File

@ -1,5 +1,5 @@
{
"add_total_row": 0,
"add_total_row": 1,
"apply_user_permissions": 1,
"creation": "2013-07-30 17:28:49",
"disabled": 0,
@ -7,7 +7,7 @@
"doctype": "Report",
"idx": 3,
"is_standard": "Yes",
"modified": "2017-02-24 20:20:20.613388",
"modified": "2017-11-06 13:04:36.338268",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Delivered Items To Be Billed",

View File

@ -1,5 +1,5 @@
{
"add_total_row": 0,
"add_total_row": 1,
"apply_user_permissions": 1,
"creation": "2013-02-21 14:26:44",
"disabled": 0,
@ -7,7 +7,7 @@
"doctype": "Report",
"idx": 3,
"is_standard": "Yes",
"modified": "2017-02-24 20:20:13.972178",
"modified": "2017-11-06 13:04:51.559061",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Ordered Items To Be Billed",

View File

@ -1,5 +1,5 @@
{
"add_total_row": 0,
"add_total_row": 1,
"apply_user_permissions": 1,
"creation": "2013-07-30 18:35:10",
"disabled": 0,
@ -7,7 +7,7 @@
"doctype": "Report",
"idx": 3,
"is_standard": "Yes",
"modified": "2017-02-24 19:59:52.887744",
"modified": "2017-11-06 13:04:26.094432",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Received Items To Be Billed",

View File

@ -0,0 +1,57 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
frappe.query_reports["Sales Payment Summary"] = {
"filters": [
{
"fieldname":"from_date",
"label": __("From Date"),
"fieldtype": "Date",
"default": frappe.datetime.get_today(),
"width": "80"
},
{
"fieldname":"to_date",
"label": __("To Date"),
"fieldtype": "Date",
"default": frappe.datetime.get_today()
},
{
"fieldname":"company",
"label": __("Company"),
"fieldtype": "Link",
"options": "Company",
"default": frappe.defaults.get_user_default("Company")
},
{
"fieldname":"mode_of_payment",
"label": __("Mode of Payment"),
"fieldtype": "Link",
"options": "Mode of Payment"
},
{
"fieldname":"owner",
"label": __("Owner"),
"fieldtype": "Link",
"options": "User",
"defaults": user
},
{
"fieldname":"cost_center",
"label": __("Cost Center"),
"fieldtype": "Link",
"options": "Cost Center"
},
{
"fieldname":"warehouse",
"label": __("Warehouse"),
"fieldtype": "Link",
"options": "Warehouse"
},
{
"fieldname":"is_pos",
"label": __("POS?"),
"fieldtype": "Check"
}
]
};

View File

@ -0,0 +1,26 @@
{
"add_total_row": 1,
"apply_user_permissions": 1,
"creation": "2017-11-03 16:31:45.757516",
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
"modified": "2017-11-04 05:15:35.892659",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Payment Summary",
"owner": "Administrator",
"ref_doctype": "Sales Invoice",
"report_name": "Sales Payment Summary",
"report_type": "Script Report",
"roles": [
{
"role": "Accounts Manager"
},
{
"role": "Accounts User"
}
]
}

View File

@ -0,0 +1,66 @@
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe import _
def execute(filters=None):
columns, data = [], []
columns=get_columns()
data=get_sales_payment_data(filters, columns)
return columns, data
def get_columns():
return [
_("Date") + ":Date:80",
_("Owner") + "::150",
_("Payment Mode") + "::120",
_("Warehouse") + ":Link/Cost Center:100",
_("Cost Center") + ":Link/Warehouse:100",
_("Sales and Returns") + ":Currency/currency:120",
_("Taxes") + ":Currency/currency:120",
_("Payments") + ":Currency/currency:120",
_("Reconciliation") + ":Currency/currency:120"
]
def get_sales_payment_data(filters, columns):
sales_invoice_data = get_sales_invoice_data(filters)
data = []
for inv in sales_invoice_data:
row = [inv.posting_date, inv.owner, inv.mode_of_payment,inv.warehouse,
inv.cost_center,inv.net_total, inv.total_taxes, inv.paid_amount,
(inv.net_total + inv.total_taxes - inv.paid_amount)]
data.append(row)
return data
def get_conditions(filters):
conditions = ""
if filters.get("company"): conditions += " a.company=%(company)s"
if filters.get("customer"): conditions += " and a.customer = %(customer)s"
if filters.get("owner"): conditions += " and a.owner = %(owner)s"
if filters.get("from_date"): conditions += " and a.posting_date >= %(from_date)s"
if filters.get("to_date"): conditions += " and a.posting_date <= %(to_date)s"
if filters.get("mode_of_payment"): conditions += " and c.mode_of_payment >= %(mode_of_payment)s"
if filters.get("warehouse"): conditions += " and b.warehouse <= %(warehouse)s"
if filters.get("cost_center"): conditions += " and b.cost_center <= %(cost_center)s"
if filters.get("is_pos"): conditions += " and a.is_pos = %(is_pos)s"
return conditions
def get_sales_invoice_data(filters):
conditions = get_conditions(filters)
return frappe.db.sql("""
select
a.owner, a.posting_date, c.mode_of_payment, b.warehouse, b.cost_center,
sum(a.net_total) as "net_total",
sum(a.total_taxes_and_charges) as "total_taxes",
sum(a.base_paid_amount) as "paid_amount"
from `tabSales Invoice` a, `tabSales Invoice Item` b, `tabSales Invoice Payment` c
where
a.name = b.parent
and a.name = c.parent
and {conditions}
group by
a.owner, a.posting_date, c.mode_of_payment, b.warehouse, b.cost_center
""".format(conditions=conditions), filters, as_dict=1)

View File

@ -468,6 +468,12 @@ def get_data():
"name": "Customer Credit Balance",
"doctype": "Customer"
},
{
"type": "report",
"is_query_report": True,
"name": "Sales Payment Summary",
"doctype": "Sales Invoice"
}
]
},
{

View File

@ -15,6 +15,7 @@ def get_data():
{
"type": "doctype",
"name": "Task",
"route": "Tree/Task",
"description": _("Project activity / task."),
},
{

View File

@ -56,6 +56,17 @@ Integer field holds numeric value, without decimal place.
Link field is connected to another master from where it fetches data. For example, in the Quotation master, Customer is a Link field.
- Geolocation
Use Geolocation field to store GeoJSON <a href="https://tools.ietf.org/html/rfc7946#section-3.3">featurecollection</a>. Stores polygons, lines and points. Internally it uses following custom properties for identifying a circle.
```
{
"point_type": "circle",
"radius": 10.00
}
```
- Password
Password field will have decode value in it.

View File

@ -15,13 +15,16 @@ def enable_hub():
return hub_settings
@frappe.whitelist()
def get_items(start=0, limit=20, category=None, order_by=None, text=None):
def get_items(start=0, limit=20, category=None, order_by=None, company=None, text=None):
connection = get_connection()
filters = {
'hub_category': category,
}
if text:
filters.update({'item_name': ('like', '%' + text + '%')})
if company:
filters.update({'company_name': company})
response = connection.get_list('Hub Item',
limit_start=start, limit_page_length=limit,
filters=filters)

View File

@ -215,7 +215,7 @@ erpnext.hub.Hub = class Hub {
.on('click', '.company-link a', function(e) {
e.preventDefault();
const company_name = $(this).attr('data-company-name');
me.get_company_details(company_name);
frappe.set_route('hub', 'Company', company_name);
})
.on('click', '.breadcrumb li', function(e) {
e.preventDefault();
@ -476,10 +476,13 @@ erpnext.hub.Hub = class Hub {
}
get_company_details(company_id) {
this.company_cache = this.company_cache || {};
return new Promise(resolve => {
// get from cache if exists
let company_details = this.company_cache[company_id];
if(this.company_cache[company_id]) {
this.go_to_company_page(company_details);
if(company_details) {
resolve(company_details);
return;
}
frappe.call({
@ -487,15 +490,20 @@ erpnext.hub.Hub = class Hub {
args: {hub_sync_id: company_id}
}).then((r) => {
if (r.message) {
const company_details = r.message.company_details;
const company_details = r.message;
this.company_cache[company_id] = company_details;
this.go_to_company_page(company_details)
resolve(company_details)
}
});
})
}
go_to_company_page(company_details) {
frappe.set_route('hub', 'Company', company_details.company_name);
go_to_company_page(company_id) {
this.get_company_details(company_id)
.then(this.show_company_page.bind(this));
}
show_company_page(company_details) {
this.$hub_main_section.empty();
let $company_page =
@ -574,10 +582,10 @@ erpnext.hub.Hub = class Hub {
<h2>${ company_details.company_name }</h2>
</div>
<div class="company">
<span class="">${ company_details.seller_city }</span>
<span class="">${ company_details.country }</span>
</div>
<div class="description">
<span class="small">${ company_details.seller_description }</span>
<span class="small">${ company_details.site_name }</span>
</div>
</div>
@ -836,7 +844,7 @@ erpnext.hub.HubList = class HubList {
</div>
</a>
<div class="company-link">
<a data-company-name="${ item.company_id }" class="">${ item.company_name }</a>
<a data-company-name="${ item.company_name }" class="">${ item.company_name }</a>
</div>
<div>${ item.formatted_price ? item.formatted_price : ''}</div>
</div>

View File

@ -17,6 +17,14 @@ frappe.ui.form.on("Production Order", {
}
});
frm.set_query("source_warehouse", function() {
return {
filters: {
'company': frm.doc.company,
}
}
});
frm.set_query("source_warehouse", "required_items", function() {
return {
filters: {

View File

@ -1358,7 +1358,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-07-10 14:29:00.457874",
"modified": "2017-11-03 05:31:56.636424",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Production Order",
@ -1412,5 +1412,5 @@
"sort_order": "ASC",
"title_field": "production_item",
"track_changes": 1,
"track_seen": 0
"track_seen": 1
}

View File

@ -64,7 +64,7 @@ erpnext.ProductionAnalytics = frappe.views.GridReportWithPlot.extend({
var chart_data = this.get_chart_data ? this.get_chart_data() : null;
this.chart = new frappe.chart.FrappeChart({
this.chart = new Chart({
parent: ".chart",
data: chart_data,
type: 'line'

View File

@ -448,6 +448,7 @@ erpnext.patches.v8_9.remove_employee_from_salary_structure_parent
erpnext.patches.v8_9.delete_gst_doctypes_for_outside_india_accounts
erpnext.patches.v8_9.set_default_fields_in_variant_settings
erpnext.patches.v8_9.update_billing_gstin_for_indian_account
erpnext.patches.v9_0.add_user_to_child_table_in_pos_profile
erpnext.patches.v9_0.set_schedule_date_for_material_request_and_purchase_order
erpnext.patches.v9_0.student_admission_childtable_migrate
erpnext.patches.v9_0.fix_subscription_next_date #2017-10-23
@ -455,5 +456,6 @@ erpnext.patches.v9_0.add_healthcare_domain
erpnext.patches.v9_0.set_variant_item_description
erpnext.patches.v9_0.set_uoms_in_variant_field
erpnext.patches.v9_0.copy_old_fees_field_data
execute:frappe.delete_doc_if_exists("DocType", "Program Fee")
erpnext.patches.v9_0.set_pos_profile_name
erpnext.patches.v9_0.remove_non_existing_warehouse_from_stock_settings

View File

@ -1,5 +1,5 @@
import frappe
from MySQLdb import OperationalError
from pymysql import InternalError
def execute():
frappe.reload_doctype("Journal Entry Account")
@ -15,6 +15,6 @@ def execute():
frappe.db.sql("""update `tabJournal Entry Account`
set reference_type=%s, reference_name={0} where ifnull({0}, '') != ''
""".format(fieldname), doctype)
except OperationalError:
except InternalError:
# column not found
pass

View File

@ -3,7 +3,7 @@
from __future__ import print_function, unicode_literals
import frappe
import MySQLdb
from frappe.exceptions import SQLError
def execute():
"""
@ -31,7 +31,7 @@ def execute():
try:
migrate_item_variants()
except MySQLdb.ProgrammingError:
except SQLError:
print("`tabItem Variant` not found")
def rename_and_reload_doctypes():

View File

@ -0,0 +1,22 @@
# Copyright (c) 2017, Frappe and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import frappe
def execute():
doctype = 'POS Profile'
frappe.reload_doc('accounts', 'doctype', doctype)
frappe.reload_doc('accounts', 'doctype', 'POS Profile User')
for doc in frappe.get_all(doctype):
_doc = frappe.get_doc(doctype, doc.name)
user = frappe.db.get_value(doctype, doc.name, 'user')
if not user: continue
_doc.append('applicable_for_users', {
'user': user
})
_doc.pos_profile_name = user + ' - ' + _doc.company
_doc.save()

View File

@ -19,6 +19,14 @@ frappe.ui.form.on("Task", {
},
refresh: function(frm) {
frm.fields_dict['parent_task'].get_query = function() {
return {
filters: {
"is_group": 1,
}
}
}
if(!frm.is_group){
var doc = frm.doc;
if(doc.__islocal) {
if(!frm.doc.exp_end_date) {
@ -54,6 +62,7 @@ frappe.ui.form.on("Task", {
}
}
}
}
},
setup: function(frm) {
@ -71,6 +80,21 @@ frappe.ui.form.on("Task", {
}
},
is_group: function(frm) {
frappe.call({
method:"erpnext.projects.doctype.task.task.check_if_child_exists",
args: {
name: frm.doc.name
},
callback: function(r){
if(r.message){
frappe.msgprint(__('Cannot convert it to non-group. Child Tasks exist.'));
frm.reload_doc();
}
}
})
},
validate: function(frm) {
frm.doc.project && frappe.model.remove_from_locals("Project",
frm.doc.project);

View File

@ -3,7 +3,7 @@
"allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 1,
"autoname": "TASK.#####",
"autoname": "field:subject",
"beta": 0,
"creation": "2013-01-29 19:25:50",
"custom": 0,
@ -30,9 +30,8 @@
"label": "Subject",
"length": 0,
"no_copy": 0,
"oldfieldname": "subject",
"oldfieldtype": "Data",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
@ -75,6 +74,37 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 1,
"collapsible": 0,
"columns": 0,
"default": "0",
"fieldname": "is_group",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Is Group",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@ -173,9 +203,42 @@
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"bold": 1,
"collapsible": 0,
"columns": 0,
"fieldname": "parent_task",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 1,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Parent Task",
"length": 0,
"no_copy": 0,
"options": "Task",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 1,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"collapsible_depends_on": "",
"columns": 0,
"depends_on": "",
"fieldname": "section_break_10",
"fieldtype": "Section Break",
"hidden": 0,
@ -205,6 +268,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "",
"fieldname": "exp_start_date",
"fieldtype": "Date",
"hidden": 0,
@ -237,6 +301,7 @@
"collapsible": 0,
"columns": 0,
"default": "0",
"depends_on": "",
"description": "",
"fieldname": "expected_time",
"fieldtype": "Float",
@ -269,6 +334,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "",
"fieldname": "task_weight",
"fieldtype": "Float",
"hidden": 0,
@ -328,6 +394,7 @@
"bold": 1,
"collapsible": 0,
"columns": 0,
"depends_on": "",
"fieldname": "exp_end_date",
"fieldtype": "Date",
"hidden": 0,
@ -359,6 +426,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "",
"fieldname": "progress",
"fieldtype": "Percent",
"hidden": 0,
@ -389,6 +457,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "",
"fieldname": "is_milestone",
"fieldtype": "Check",
"hidden": 0,
@ -418,7 +487,9 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"collapsible_depends_on": "",
"columns": 0,
"depends_on": "",
"fieldname": "section_break0",
"fieldtype": "Section Break",
"hidden": 0,
@ -449,6 +520,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "",
"fieldname": "description",
"fieldtype": "Text Editor",
"hidden": 0,
@ -481,7 +553,9 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"collapsible_depends_on": "",
"columns": 0,
"depends_on": "",
"fieldname": "section_break",
"fieldtype": "Section Break",
"hidden": 0,
@ -512,6 +586,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "",
"fieldname": "depends_on",
"fieldtype": "Table",
"hidden": 0,
@ -543,6 +618,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "",
"fieldname": "depends_on_tasks",
"fieldtype": "Data",
"hidden": 1,
@ -572,7 +648,9 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"collapsible_depends_on": "",
"columns": 0,
"depends_on": "",
"description": "",
"fieldname": "actual",
"fieldtype": "Section Break",
@ -606,6 +684,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "",
"fieldname": "act_start_date",
"fieldtype": "Date",
"hidden": 0,
@ -638,6 +717,7 @@
"collapsible": 0,
"columns": 0,
"default": "",
"depends_on": "",
"description": "",
"fieldname": "actual_time",
"fieldtype": "Float",
@ -699,6 +779,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "",
"fieldname": "act_end_date",
"fieldtype": "Date",
"hidden": 0,
@ -730,6 +811,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "",
"fieldname": "section_break_17",
"fieldtype": "Section Break",
"hidden": 0,
@ -759,6 +841,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "",
"fieldname": "total_costing_amount",
"fieldtype": "Currency",
"hidden": 0,
@ -791,6 +874,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "",
"fieldname": "total_expense_claim",
"fieldtype": "Currency",
"hidden": 0,
@ -851,6 +935,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "",
"fieldname": "total_billing_amount",
"fieldtype": "Currency",
"hidden": 0,
@ -1025,6 +1110,96 @@
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "lft",
"fieldtype": "Int",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "lft",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "rgt",
"fieldtype": "Int",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "rgt",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "old_parent",
"fieldtype": "Data",
"hidden": 1,
"ignore_user_permissions": 1,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Old Parent",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
}
],
"has_web_view": 0,
@ -1039,7 +1214,7 @@
"istable": 0,
"max_attachments": 5,
"menu_index": 0,
"modified": "2017-05-23 11:28:28.161600",
"modified": "2017-10-06 03:57:37.901446",
"modified_by": "Administrator",
"module": "Projects",
"name": "Task",

View File

@ -5,13 +5,14 @@ from __future__ import unicode_literals
import frappe, json
from frappe.utils import getdate, date_diff, add_days, cstr
from frappe import _
from frappe.model.document import Document
from frappe import _, throw
from frappe.utils.nestedset import NestedSet, rebuild_tree
class CircularReferenceError(frappe.ValidationError): pass
class Task(Document):
class Task(NestedSet):
nsm_parent_field = 'parent_task'
def get_feed(self):
return '{0}: {1}'.format(_(self.status), self.subject)
@ -59,7 +60,11 @@ class Task(Document):
depends_on_tasks += d.task + ","
self.depends_on_tasks = depends_on_tasks
def update_nsm_model(self):
frappe.utils.nestedset.update_nsm(self)
def on_update(self):
self.update_nsm_model()
self.check_recursion()
self.reschedule_dependent_tasks()
self.update_project()
@ -105,16 +110,20 @@ class Task(Document):
frappe.throw(_("Circular Reference Error"), CircularReferenceError)
if b[0]:
task_list.append(b[0])
if count == 15:
break
def reschedule_dependent_tasks(self):
end_date = self.exp_end_date or self.act_end_date
if end_date:
for task_name in frappe.db.sql("""select name from `tabTask` as parent where parent.project = %(project)s and parent.name in \
(select parent from `tabTask Depends On` as child where child.task = %(task)s and child.project = %(project)s)""",
{'project': self.project, 'task':self.name }, as_dict=1):
for task_name in frappe.db.sql("""
select name from `tabTask` as parent
where parent.project = %(project)s
and parent.name in (
select parent from `tabTask Depends On` as child
where child.task = %(task)s and child.project = %(project)s)
""", {'project': self.project, 'task':self.name }, as_dict=1):
task = frappe.get_doc("Task", task_name.name)
if task.exp_start_date and task.exp_end_date and task.exp_start_date < getdate(end_date) and task.status == "Open":
task_duration = date_diff(task.exp_end_date, task.exp_start_date)
@ -128,6 +137,17 @@ class Task(Document):
if project_user:
return True
def on_trash(self):
if check_if_child_exists(self.name):
throw(_("Child Task exists for this Task. You can not delete this Task."))
self.update_nsm_model()
@frappe.whitelist()
def check_if_child_exists(name):
return frappe.db.sql("""select name from `tabTask`
where parent_task = %s""", name)
@frappe.whitelist()
def get_events(start, end, filters=None):
"""Returns events for Gantt / Calendar view rendering.
@ -177,4 +197,48 @@ def set_tasks_as_overdue():
and exp_end_date < CURDATE()
and `status` not in ('Closed', 'Cancelled')""")
@frappe.whitelist()
def get_children():
doctype = frappe.local.form_dict.get('doctype')
parent_field = 'parent_' + doctype.lower().replace(' ', '_')
parent = frappe.form_dict.get("parent") or ""
if parent == "task":
parent = ""
tasks = frappe.db.sql("""select name as value,
is_group as expandable
from `tab{doctype}`
where docstatus < 2
and ifnull(`{parent_field}`,'') = %s
order by name""".format(doctype=frappe.db.escape(doctype),
parent_field=frappe.db.escape(parent_field)), (parent), as_dict=1)
# return tasks
return tasks
@frappe.whitelist()
def add_node():
from frappe.desk.treeview import make_tree_args
args = frappe.form_dict
args.update({
"name_field": "subject"
})
args = make_tree_args(**args)
if args.parent_task == 'task':
args.parent_task = None
frappe.get_doc(args).insert()
@frappe.whitelist()
def add_multiple_tasks(data, parent):
data = json.loads(data)['tasks']
tasks = data.split('\n')
new_doc = {'doctype': 'Task', 'parent_task': parent}
for d in tasks:
new_doc['subject'] = d
new_task = frappe.get_doc(new_doc)
new_task.insert()

View File

@ -25,7 +25,9 @@ frappe.listview_settings['Task'] = {
return [__(doc.status), colors[doc.status], "status,=," + doc.status];
},
gantt_custom_popup_html: function(ganttobj, task) {
var html = `<h5>${ganttobj.name}</h5>`;
var html = `<h5><a style="text-decoration:underline"\
href="#Form/Task/${ganttobj.id}""> ${ganttobj.name} </a></h5>`;
if(task.project) html += `<p>Project: ${task.project}</p>`;
html += `<p>Progress: ${ganttobj.progress}</p>`;

View File

@ -0,0 +1,59 @@
frappe.provide("frappe.treeview_settings");
frappe.treeview_settings['Task'] = {
get_tree_nodes: "erpnext.projects.doctype.task.task.get_children",
add_tree_node: "erpnext.projects.doctype.task.task.add_node",
filters: [
{
fieldname: "task",
fieldtype:"Link",
options: "Task",
label: __("Task"),
get_query: function(){
return {
filters: [["Task", 'is_group', '=', 1]]
};
}
}
],
title: "Task",
breadcrumb: "Projects",
get_tree_root: false,
root_label: "task",
ignore_fields:["parent_task"],
get_label: function(node) {
return node.data.value;
},
onload: function(me){
me.make_tree();
me.set_root = true;
},
toolbar: [
{
label:__("Add Multiple"),
condition: function(node) {
return node.expandable;
},
click: function(node) {
var d = new frappe.ui.Dialog({
'fields': [
{'fieldname': 'tasks', 'label': 'Tasks', 'fieldtype': 'Text'},
],
primary_action: function(){
d.hide();
return frappe.call({
method: "erpnext.projects.doctype.task.task.add_multiple_tasks",
args: {
data: d.get_values(),
parent: node.data.value
},
callback: function() { }
});
}
});
d.show();
}
}
],
extend_toolbar: true
};

View File

@ -1,15 +0,0 @@
[
{
"status": "Open",
"subject": "_Test Task",
"name": "task001"
},
{
"status": "Open",
"subject": "_Test Task 1"
},
{
"status": "Open",
"subject": "_Test Task 2"
}
]

View File

@ -5,134 +5,58 @@ import frappe
import unittest
from frappe.utils import getdate, nowdate, add_days
# test_records = frappe.get_test_records('Task')
from erpnext.projects.doctype.task.task import CircularReferenceError
class TestTask(unittest.TestCase):
def test_circular_reference(self):
task1 = create_task("_Test Task 1", nowdate(), add_days(nowdate(), 10))
task2 = create_task("_Test Task 2", add_days(nowdate(), 11), add_days(nowdate(), 15), task1.name)
task3 = create_task("_Test Task 3", add_days(nowdate(), 11), add_days(nowdate(), 15), task2.name)
task1 = frappe.new_doc('Task')
task1.update({
"status": "Open",
"subject": "_Test Task 1",
"project": "_Test Project",
"exp_start_date": "2015-1-1",
"exp_end_date": "2015-1-10"
})
task1.save()
task2 = frappe.new_doc('Task')
task2.update({
"status": "Open",
"subject": "_Test Task 2",
"project": "_Test Project",
"exp_start_date": "2015-1-11",
"exp_end_date": "2015-1-15",
"depends_on":[
{
"task": task1.name
}
]
})
task2.save()
task3 = frappe.new_doc('Task')
task3.update({
"status": "Open",
"subject": "_Test Task 2",
"project": "_Test Project",
"exp_start_date": "2015-1-11",
"exp_end_date": "2015-1-15",
"depends_on":[
{
"task": task2.name
}
]
})
task3.save()
task1.reload()
task1.append("depends_on", {
"task": task3.name
})
self.assertRaises(CircularReferenceError, task1.save)
task1.set("depends_on", [])
task1.save()
task4 = frappe.new_doc('Task')
task4.update({
"status": "Open",
"subject": "_Test Task 1",
"exp_start_date": "2015-1-1",
"exp_end_date": "2015-1-15",
"depends_on":[
{
"task": task1.name
}
]
})
task4.save()
task4 = create_task("_Test Task 4", nowdate(), add_days(nowdate(), 15), task1.name)
task3.append("depends_on", {
"task": task4.name
})
def test_reschedule_dependent_task(self):
task1 = frappe.new_doc('Task')
task1.update({
"status": "Open",
"subject": "_Test Task 1",
"project": "_Test Project",
"exp_start_date": "2015-1-1",
"exp_end_date": "2015-1-10"
})
task1.save()
task1 = create_task("_Test Task 1", nowdate(), add_days(nowdate(), 10))
task2 = frappe.new_doc('Task')
task2.update({
"status": "Open",
"subject": "_Test Task 2",
"project": "_Test Project",
"exp_start_date": "2015-1-11",
"exp_end_date": "2015-1-15",
"depends_on":[
{
"task": task1.name,
"project": "_Test Project"
}
]
})
task2 = create_task("_Test Task 2", add_days(nowdate(), 11), add_days(nowdate(), 15), task1.name)
task2.get("depends_on")[0].project = "_Test Project"
task2.save()
task3 = frappe.new_doc('Task')
task3.update({
"status": "Open",
"subject": "_Test Task 3",
"project": "_Test Project",
"exp_start_date": "2015-1-16",
"exp_end_date": "2015-1-18",
"depends_on":[
{
"task": task2.name,
"project": "_Test Project"
}
]
})
task3 = create_task("_Test Task 3", add_days(nowdate(), 11), add_days(nowdate(), 15), task2.name)
task3.get("depends_on")[0].project = "_Test Project"
task3.save()
task1.update({
"exp_end_date": "2015-1-20"
"exp_end_date": add_days(nowdate(), 20)
})
task1.save()
self.assertEqual(frappe.db.get_value("Task", task2.name, "exp_start_date"), getdate('2015-1-21'))
self.assertEqual(frappe.db.get_value("Task", task2.name, "exp_end_date"), getdate('2015-1-25'))
self.assertEqual(frappe.db.get_value("Task", task2.name, "exp_start_date"),
getdate(add_days(nowdate(), 21)))
self.assertEqual(frappe.db.get_value("Task", task2.name, "exp_end_date"),
getdate(add_days(nowdate(), 25)))
self.assertEqual(frappe.db.get_value("Task", task3.name, "exp_start_date"), getdate('2015-1-26'))
self.assertEqual(frappe.db.get_value("Task", task3.name, "exp_end_date"), getdate('2015-1-28'))
self.assertEqual(frappe.db.get_value("Task", task3.name, "exp_start_date"),
getdate(add_days(nowdate(), 26)))
self.assertEqual(frappe.db.get_value("Task", task3.name, "exp_end_date"),
getdate(add_days(nowdate(), 30)))
def test_close_assignment(self):
if not frappe.db.exists("Task", "Test Close Assignment"):
task = frappe.new_doc("Task")
task.subject = "Test Close Assignment"
task.insert()
@ -147,8 +71,10 @@ class TestTask(unittest.TestCase):
})
def get_owner_and_status():
return frappe.db.get_value("ToDo", filters={"reference_type": task.doctype, "reference_name": task.name,
"description": "Close this task"}, fieldname=("owner", "status"), as_dict=True)
return frappe.db.get_value("ToDo",
filters={"reference_type": task.doctype, "reference_name": task.name,
"description": "Close this task"},
fieldname=("owner", "status"), as_dict=True)
assign()
todo = get_owner_and_status()
@ -164,16 +90,29 @@ class TestTask(unittest.TestCase):
self.assertEquals(todo.status, "Closed")
def test_overdue(self):
task = frappe.get_doc({
"doctype":"Task",
"subject": "Testing Overdue",
"status": "Open",
"exp_end_date": add_days(nowdate(), -1)
})
task.insert()
task = create_task("Testing Overdue", add_days(nowdate(), -10), add_days(nowdate(), -5))
from erpnext.projects.doctype.task.task import set_tasks_as_overdue
set_tasks_as_overdue()
self.assertEquals(frappe.db.get_value("Task", task.name, "status"), "Overdue")
def create_task(subject, start=None, end=None, depends_on=None, project=None):
if not frappe.db.exists("Task", subject):
task = frappe.new_doc('Task')
task.status = "Open"
task.subject = subject
task.exp_start_date = start or nowdate()
task.exp_end_date = end or nowdate()
task.project = project or "_Test Project"
task.save()
else:
task = frappe.get_doc("Task", subject)
if depends_on:
task.append("depends_on", {
"task": depends_on
})
task.save()
return task

View File

@ -0,0 +1,99 @@
/* eslint-disable */
// rename this file from _test_[name] to test_[name] to activate
// and remove above this line
QUnit.test("test: Task Tree", function (assert) {
let done = assert.async();
// number of asserts
assert.expect(5);
frappe.run_serially([
// insert a new Task
() => frappe.set_route('Tree', 'Task'),
() => frappe.timeout(0.5),
// Checking adding child without selecting any Node
() => frappe.tests.click_button('New'),
() => frappe.timeout(0.5),
() => {assert.equal($(`.msgprint`).text(), "Select a group node first.", "Error message success");},
() => frappe.tests.click_button('Close'),
() => frappe.timeout(0.5),
// Creating child nodes
() => frappe.tests.click_link('task'),
() => frappe.map_group.make('Test-1'),
() => frappe.map_group.make('Test-2'),
() => frappe.map_group.make('Test-3', 1),
() => frappe.timeout(1),
() => frappe.tests.click_link('Test-3'),
() => frappe.map_group.make('Test-4', 0),
// Checking Edit button
() => frappe.timeout(0.5),
() => frappe.tests.click_link('Test-1'),
() => frappe.tests.click_button('Edit'),
() => frappe.timeout(0.5),
() => {assert.deepEqual(frappe.get_route(), ["Form", "Task", "Test-1"], "Edit route checks");},
// Deleting child Node
() => frappe.set_route('Tree', 'Task'),
() => frappe.timeout(0.5),
() => frappe.tests.click_link('Test-1'),
() => frappe.tests.click_button('Delete'),
() => frappe.timeout(0.5),
() => frappe.tests.click_button('Yes'),
// Deleting Group Node that has child nodes in it
() => frappe.timeout(0.5),
() => frappe.tests.click_link('Test-3'),
() => frappe.tests.click_button('Delete'),
() => frappe.timeout(0.5),
() => frappe.tests.click_button('Yes'),
() => frappe.timeout(1),
() => {assert.equal(cur_dialog.title, 'Message', 'Error thrown correctly');},
() => frappe.tests.click_button('Close'),
// Renaming Child node
() => frappe.timeout(0.5),
() => frappe.tests.click_link('Test-2'),
() => frappe.tests.click_button('Rename'),
() => frappe.timeout(1),
() => cur_dialog.set_value('new_name', 'Test-5'),
() => frappe.timeout(1.5),
() => cur_dialog.get_primary_btn().click(),
() => frappe.timeout(1),
() => {assert.equal($(`a:contains("Test-5"):visible`).length, 1, 'Rename successfull');},
// Add multiple child tasks
() => frappe.tests.click_link('Test-3'),
() => frappe.timeout(0.5),
() => frappe.click_button('Add Multiple'),
() => frappe.timeout(1),
() => cur_dialog.set_value('tasks', 'Test-6\nTest-7'),
() => frappe.timeout(0.5),
() => frappe.click_button('Submit'),
() => frappe.timeout(2),
() => frappe.click_button('Expand All'),
() => frappe.timeout(1),
() => {
let count = $(`a:contains("Test-6"):visible`).length + $(`a:contains("Test-7"):visible`).length;
assert.equal(count, 2, "Multiple Tasks added successfully");
},
() => done()
]);
});
frappe.map_group = {
make:function(subject, is_group = 0){
return frappe.run_serially([
() => frappe.click_button('Add Child'),
() => frappe.timeout(1),
() => cur_dialog.set_value('is_group', is_group),
() => cur_dialog.set_value('subject', subject),
() => frappe.click_button('Create New'),
() => frappe.timeout(1.5)
]);
}
};

View File

@ -8,7 +8,7 @@
<input type="tel" class="form-control cell" disabled value="{%= price_list_rate %}"/>
</div>
<div class="pos-list-row">
<div class="cell">{{ __("Discount") }}:</div>
<div class="cell">{{ __("Discount") }}: %</div>
<input type="tel" class="form-control cell pos-item-disc" value="{%= discount_percentage %}">
</div>
<div class="pos-list-row">

View File

@ -43,7 +43,7 @@ class AssessmentPlan(Document):
assessment_criteria_list = frappe.db.sql_list(''' select apc.assessment_criteria
from `tabAssessment Plan` ap , `tabAssessment Plan Criteria` apc
where ap.name = apc.parent and ap.course=%s and ap.student_group=%s and ap.assessment_group=%s
and ap.name != %s''', (self.course, self.student_group, self.assessment_group, self.name))
and ap.name != %s and ap.docstatus=1''', (self.course, self.student_group, self.assessment_group, self.name))
for d in self.assessment_criteria:
if d.assessment_criteria in assessment_criteria_list:
frappe.throw(_("You have already assessed for the assessment criteria {}.")

View File

@ -2,7 +2,7 @@
QUnit.module('schools');
QUnit.test('Test: Assessment Plan', function(assert){
assert.expect(7);
assert.expect(6);
let done = assert.async();
let room_name, instructor_name, assessment_name;
@ -49,10 +49,6 @@ QUnit.test('Test: Assessment Plan', function(assert){
assert.equal(cur_frm.doc.assessment_plan, assessment_name, 'Assessment correctly set');
assert.equal(cur_frm.doc.student_group, 'test-course-wise-group-2', 'Course for Assessment correctly set');
},
() => cur_frm.print_doc(),
() => frappe.timeout(1),
() => {assert.ok($('.btn-print-print').is(':visible'), "Print Format Available");},
() => done()
]);
});

View File

@ -7,6 +7,7 @@ cur_frm.add_fetch("assessment_plan", "maximum_assessment_score", "maximum_score"
frappe.ui.form.on("Assessment Result", {
assessment_plan: function(frm) {
if (frm.doc.assessment_plan) {
frappe.call({
method: "erpnext.schools.api.get_assessment_details",
args: {
@ -25,6 +26,7 @@ frappe.ui.form.on("Assessment Result", {
}
});
}
}
});
frappe.ui.form.on("Assessment Result Detail", {

View File

@ -175,7 +175,7 @@
"issingle": 1,
"istable": 0,
"max_attachments": 0,
"modified": "2017-06-30 08:21:47.184562",
"modified": "2017-11-08 11:51:43.247815",
"modified_by": "Administrator",
"module": "Schools",
"name": "Assessment Result Tool",
@ -188,17 +188,17 @@
"cancel": 0,
"create": 1,
"delete": 0,
"email": 1,
"email": 0,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"print": 0,
"read": 1,
"report": 0,
"role": "Academics User",
"set_user_permissions": 0,
"share": 1,
"share": 0,
"submit": 0,
"write": 1
}

View File

@ -90,7 +90,7 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
"modified": "2017-06-30 08:21:47.851347",
"modified": "2017-11-02 17:57:18.069158",
"modified_by": "Administrator",
"module": "Schools",
"name": "Fee Category",
@ -116,6 +116,46 @@
"share": 1,
"submit": 0,
"write": 1
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts User",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
}
],
"quick_entry": 1,

View File

@ -25,7 +25,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_global_search": 1,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Fee Structure",
@ -1029,7 +1029,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-09-19 16:24:17.266071",
"modified": "2017-11-02 17:55:22.851581",
"modified_by": "Administrator",
"module": "Schools",
"name": "Fee Schedule",
@ -1039,7 +1039,7 @@
{
"amend": 1,
"apply_user_permissions": 0,
"cancel": 1,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
@ -1053,6 +1053,46 @@
"role": "Academics User",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts User",
"set_user_permissions": 0,
"share": 1,
"submit": 1,
"write": 1
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 1,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 1,
"write": 1
}
@ -1060,6 +1100,7 @@
"quick_entry": 0,
"read_only": 0,
"read_only_onload": 0,
"restrict_to_domain": "Education",
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",

View File

@ -165,7 +165,7 @@
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"reqd": 0,
"search_index": 1,
"set_only_once": 0,
"unique": 0,
@ -197,7 +197,7 @@
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
@ -577,7 +577,7 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
"modified": "2017-09-11 15:18:27.975666",
"modified": "2017-11-02 17:43:16.796845",
"modified_by": "Administrator",
"module": "Schools",
"name": "Fee Structure",
@ -587,7 +587,7 @@
{
"amend": 1,
"apply_user_permissions": 0,
"cancel": 1,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
@ -601,6 +601,46 @@
"role": "Academics User",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts User",
"set_user_permissions": 0,
"share": 1,
"submit": 1,
"write": 1
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 1,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 1,
"write": 1
}
@ -609,6 +649,7 @@
"read_only": 0,
"read_only_onload": 0,
"restrict_to_domain": "Education",
"search_fields": "program, student_category, academic_year",
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",

View File

@ -1,7 +1,7 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_import": 1,
"allow_rename": 0,
"autoname": "naming_series:",
"beta": 1,
@ -87,7 +87,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_global_search": 1,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Student Name",
@ -118,7 +118,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_global_search": 1,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Fee Schedule",
@ -158,7 +158,7 @@
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
@ -249,7 +249,7 @@
"options": "Company",
"permlevel": 0,
"precision": "",
"print_hide": 1,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 1,
@ -310,7 +310,7 @@
"no_copy": 1,
"permlevel": 0,
"precision": "",
"print_hide": 1,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
@ -494,7 +494,7 @@
"options": "Student Batch Name",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
@ -708,7 +708,7 @@
"options": "Currency",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
@ -739,7 +739,7 @@
"options": "Fee Structure",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
@ -1011,7 +1011,7 @@
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
@ -1132,7 +1132,7 @@
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
@ -1163,7 +1163,7 @@
"options": "Account",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
@ -1194,7 +1194,7 @@
"options": "Account",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
@ -1223,7 +1223,7 @@
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
@ -1254,6 +1254,35 @@
"options": "Cost Center",
"permlevel": 0,
"precision": "",
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "data_42",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
@ -1276,13 +1305,53 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
"modified": "2017-09-20 23:17:09.819606",
"modified": "2017-11-02 17:31:47.155873",
"modified_by": "Administrator",
"module": "Schools",
"name": "Fees",
"name_case": "",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Academics User",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts User",
"set_user_permissions": 0,
"share": 1,
"submit": 1,
"write": 1
},
{
"amend": 0,
"apply_user_permissions": 0,
@ -1297,7 +1366,7 @@
"print": 1,
"read": 1,
"report": 1,
"role": "Academics User",
"role": "Accounts Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 1,
@ -1308,7 +1377,8 @@
"read_only": 0,
"read_only_onload": 0,
"restrict_to_domain": "Education",
"show_name_in_global_search": 0,
"search_fields": "student, student_name",
"show_name_in_global_search": 1,
"sort_field": "modified",
"sort_order": "DESC",
"title_field": "student_name",

View File

@ -223,67 +223,6 @@
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "fee_schedule",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Fee Schedule",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "fees",
"fieldtype": "Table",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Fees",
"length": 0,
"no_copy": 0,
"options": "Program Fee",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
}
],
"has_web_view": 0,
@ -297,7 +236,7 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
"modified": "2017-06-30 08:21:49.176708",
"modified": "2017-11-02 18:08:20.823972",
"modified_by": "Administrator",
"module": "Schools",
"name": "Program",

View File

@ -13,9 +13,12 @@ class StudentApplicant(Document):
from frappe.model.naming import set_name_by_naming_series
if self.student_admission:
if self.program:
# set the naming series from the student admission if provided.
student_admission = get_student_admission_data(self.student_admission, self.program)
if student_admission:
naming_series = student_admission.get("applicant_naming_series")
else:
naming_series = None
else:
frappe.throw(_("Select the program first"))
@ -40,16 +43,17 @@ class StudentApplicant(Document):
def validation_from_student_admission(self):
student_admission = get_student_admission_data(self.student_admission, self.program)
if student_admission:
if ((
student_admission.minimum_age
and getdate(student_admission.minimum_age) > getdate(self.date_of_birth)
) or (
student_admission.maximum_age
and getdate(student_admission.maximum_age) < getdate(self.date_of_birth)
)):
# different validation for minimum and maximum age so that either min/max can also work independently.
if student_admission and student_admission.minimum_age and \
getdate(student_admission.minimum_age) < getdate(self.date_of_birth):
frappe.throw(_("Not eligible for the admission in this program as per DOB"))
if student_admission and student_admission.maximum_age and \
getdate(student_admission.maximum_age) > getdate(self.date_of_birth):
frappe.throw(_("Not eligible for the admission in this program as per DOB"))
def on_payment_authorized(self, *args, **kwargs):
self.db_set('paid', 1)

View File

@ -273,7 +273,7 @@
"issingle": 1,
"istable": 0,
"max_attachments": 0,
"modified": "2017-06-30 08:21:51.390809",
"modified": "2017-11-08 11:53:27.994112",
"modified_by": "Administrator",
"module": "Schools",
"name": "Student Attendance Tool",
@ -306,17 +306,17 @@
"cancel": 0,
"create": 1,
"delete": 0,
"email": 1,
"email": 0,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"print": 0,
"read": 1,
"report": 0,
"role": "Academics User",
"set_user_permissions": 0,
"share": 1,
"share": 0,
"submit": 0,
"write": 1
}

View File

@ -7,6 +7,7 @@ import frappe
from frappe.model.document import Document
from frappe import _
from erpnext.schools.utils import validate_duplicate_student
from frappe.utils import cint
class StudentGroup(Document):
def validate(self):
@ -34,9 +35,13 @@ class StudentGroup(Document):
for d in self.students:
if not frappe.db.get_value("Student", d.student, "enabled") and d.active:
frappe.throw(_("{0} - {1} is inactive student".format(d.group_roll_number, d.student_name)))
if self.group_based_on == "Batch" and d.student not in students and frappe.defaults.get_defaults().validate_batch:
if (self.group_based_on == "Batch") and cint(frappe.defaults.get_defaults().validate_batch)\
and d.student not in students:
frappe.throw(_("{0} - {1} is not enrolled in the Batch {2}".format(d.group_roll_number, d.student_name, self.batch)))
if self.group_based_on == "Course" and d.student not in students and frappe.defaults.get_defaults().validate_course:
if (self.group_based_on == "Course") and cint(frappe.defaults.get_defaults().validate_course)\
and (d.student not in students):
frappe.throw(_("{0} - {1} is not enrolled in the Course {2}".format(d.group_roll_number, d.student_name, self.course)))
def validate_and_set_child_table_fields(self):
@ -108,14 +113,14 @@ def fetch_students(doctype, txt, searchfield, start, page_len, filters):
students = ([d.student for d in enrolled_students if d.student not in student_group_student]
if enrolled_students else [""]) or [""]
return frappe.db.sql("""select name, title from tabStudent
where name in ({0}) and `{1}` LIKE %s
where name in ({0}) and (`{1}` LIKE %s or title LIKE %s)
order by idx desc, name
limit %s, %s""".format(", ".join(['%s']*len(students)), searchfield),
tuple(students + ["%%%s%%" % txt, start, page_len]))
tuple(students + ["%%%s%%" % txt, "%%%s%%" % txt, start, page_len]))
else:
return frappe.db.sql("""select name, title from tabStudent
where `{0}` LIKE %s
where `{0}` LIKE %s or title LIKE %s
order by idx desc, name
limit %s, %s""".format(searchfield),
tuple(["%%%s%%" % txt, start, page_len]))
tuple(["%%%s%%" % txt, "%%%s%%" % txt, start, page_len]))

View File

@ -173,14 +173,16 @@ def get_column(assessment_criteria, total_maximum_score):
def get_chart_data(grades, assessment_criteria_list, kounter):
grades = sorted(grades)
datasets = []
for grade in grades:
tmp = []
for ac in assessment_criteria_list:
if grade in kounter[ac]:
tmp.append(kounter[ac][grade])
tmp = frappe._dict({"values":[], "title": grade})
for criteria in assessment_criteria_list:
if grade in kounter[criteria]:
tmp["values"].append(kounter[criteria][grade])
else:
tmp.append(0)
tmp["values"].append(0)
datasets.append(tmp)
return {
"data": {
"labels": assessment_criteria_list,

View File

@ -3406,7 +3406,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-10-24 12:52:28.115742",
"modified": "2017-11-03 05:31:56.636424",
"modified_by": "Administrator",
"module": "Selling",
"name": "Sales Order",
@ -3543,5 +3543,5 @@
"timeline_field": "customer",
"title_field": "title",
"track_changes": 1,
"track_seen": 0
"track_seen": 1
}

View File

@ -285,25 +285,67 @@ erpnext.pos.PointOfSale = class PointOfSale {
}
setup_pos_profile() {
return new Promise(resolve => {
frappe.call({
method: 'erpnext.stock.get_item_details.get_pos_profile',
args: {
company: this.company
}
}).then(r => {
this.pos_profile = r.message;
return new Promise((resolve) => {
if (!this.pos_profile) {
const load_default = () => {
this.pos_profile = {
company: this.company,
currency: frappe.defaults.get_default('currency'),
selling_price_list: frappe.defaults.get_default('selling_price_list')
};
resolve();
}
const on_submit = ({ pos_profile }) => {
this.get_pos_profile_doc(pos_profile)
.then(doc => {
this.pos_profile = doc;
if (!this.pos_profile) {
load_default();
}
resolve();
});
})
}
frappe.call({
method: 'erpnext.accounts.doctype.pos_profile.pos_profile.get_pos_profiles_for_user'
}).then((r) => {
if (r && r.message) {
const pos_profiles = r.message.filter(a => a);
if (pos_profiles.length === 0) {
load_default();
} else if(pos_profiles.length === 1) {
// load profile directly
on_submit({pos_profile: pos_profiles[0]});
} else {
// ask prompt
frappe.prompt(
[{ fieldtype: 'Select', label: 'POS Profile', options: pos_profiles }],
on_submit,
__('Select POS Profile')
);
}
} else {
frappe.dom.unfreeze();
frappe.throw(__("POS Profile is required to use Point-of-Sale"));
}
});
});
}
get_pos_profile_doc(pos_profile_name) {
return new Promise(resolve => {
frappe.call({
method: 'erpnext.accounts.doctype.pos_profile.pos_profile.get_pos_profile',
args: {
pos_profile_name
},
callback: (r) => {
resolve(r.message);
}
});
});
}
setup_company() {

View File

@ -47,9 +47,6 @@ class ItemGroup(NestedSet, WebsiteGenerator):
return self.route
def after_rename(self, olddn, newdn, merge=False):
NestedSet.after_rename(self, olddn, newdn, merge)
def on_trash(self):
NestedSet.on_trash(self)
WebsiteGenerator.on_trash(self)

View File

@ -24,6 +24,11 @@ frappe.ui.form.on('Batch', {
frm.trigger('make_dashboard');
}
},
item: (frm) => {
frappe.db.get_value('Item', {name: frm.doc.item}, 'has_expiry_date', (r) => {
frm.toggle_reqd('expiry_date', r.has_expiry_date);
});
},
make_dashboard: (frm) => {
if(!frm.is_new()) {
frappe.call({

View File

@ -3610,7 +3610,7 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
"modified": "2017-09-19 11:21:59.084183",
"modified": "2017-11-03 05:31:56.636424",
"modified_by": "Administrator",
"module": "Stock",
"name": "Delivery Note",
@ -3727,5 +3727,5 @@
"timeline_field": "customer",
"title_field": "title",
"track_changes": 1,
"track_seen": 0
"track_seen": 1
}

View File

@ -1183,6 +1183,37 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "has_batch_no",
"fieldname": "has_expiry_date",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Has Expiry Date",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@ -3329,7 +3360,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 1,
"modified": "2017-10-25 14:08:02.948326",
"modified": "2017-11-01 11:53:52.060505",
"modified_by": "Administrator",
"module": "Stock",
"name": "Item",

View File

@ -2,11 +2,13 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import frappe
from frappe.utils import flt, cint
from frappe import _
import frappe
from frappe import _
from frappe.model import no_value_fields
from frappe.model.document import Document
from frappe.utils import cint, flt
class PackingSlip(Document):
@ -84,11 +86,12 @@ class PackingSlip(Document):
* No. of Cases of this packing slip
"""
# also pick custom fields from delivery note
rows = [d.item_code for d in self.get("items")]
custom_fields = ', '.join(['dni.`{0}`'.format(d.fieldname) for d in \
frappe.get_meta("Delivery Note Item").get_custom_fields()])
# also pick custom fields from delivery note
custom_fields = ', '.join(['dni.`{0}`'.format(d.fieldname)
for d in frappe.get_meta("Delivery Note Item").get_custom_fields()
if d.fieldtype not in no_value_fields])
if custom_fields:
custom_fields = ', ' + custom_fields

View File

@ -64,6 +64,8 @@ class Warehouse(NestedSet):
where parent_warehouse = %s""", self.name)
def before_rename(self, old_name, new_name, merge=False):
super(Warehouse, self).before_rename(old_name, new_name, merge)
# Add company abbr if not provided
new_warehouse = erpnext.encode_company_abbr(new_name, self.company)
@ -77,6 +79,8 @@ class Warehouse(NestedSet):
return new_warehouse
def after_rename(self, old_name, new_name, merge=False):
super(Warehouse, self).after_rename(old_name, new_name, merge)
new_warehouse_name = self.get_new_warehouse_name_without_abbr(new_name)
self.db_set("warehouse_name", new_warehouse_name)

View File

@ -1,5 +1,5 @@
{
"add_total_row": 0,
"add_total_row": 1,
"apply_user_permissions": 1,
"creation": "2013-02-22 18:01:55",
"disabled": 0,
@ -7,7 +7,7 @@
"doctype": "Report",
"idx": 3,
"is_standard": "Yes",
"modified": "2017-09-18 12:28:49.322622",
"modified": "2017-11-06 13:05:38.965229",
"modified_by": "Administrator",
"module": "Stock",
"name": "Ordered Items To Be Delivered",

View File

@ -4,7 +4,7 @@ frappe.ui.form.on("Issue", {
},
"refresh": function(frm) {
if(frm.doc.status==="Open") {
if(frm.doc.status!=="Closed") {
frm.add_custom_button(__("Close"), function() {
frm.set_value("status", "Closed");
frm.save();

View File

@ -50,8 +50,8 @@ erpnext/schools/doctype/room/test_room.js
erpnext/schools/doctype/instructor/test_instructor.js
erpnext/stock/doctype/warehouse/test_warehouse.js
erpnext/manufacturing/doctype/production_order/test_production_order.js #long
erpnext/selling/page/point_of_sale/tests/test_point_of_sale.js
erpnext/accounts/page/pos/test_pos.js
erpnext/selling/page/point_of_sale/tests/test_point_of_sale.js
erpnext/selling/doctype/product_bundle/test_product_bundle.js
erpnext/stock/doctype/delivery_note/test_delivery_note.js
erpnext/stock/doctype/material_request/tests/test_material_request.js
@ -133,3 +133,4 @@ erpnext/restaurant/doctype/restaurant/test_restaurant.js
erpnext/restaurant/doctype/restaurant_table/test_restaurant_table.js
erpnext/restaurant/doctype/restaurant_menu/test_restaurant_menu.js
erpnext/restaurant/doctype/restaurant_order_entry/restaurant_order_entry.js
erpnext/projects/doctype/task/tests/test_task_tree.js