Merge branch 'develop' into rfq-multi-uom
diff --git a/.github/workflows/docker-release.yml b/.github/workflows/docker-release.yml
index d36b115..8f67858 100644
--- a/.github/workflows/docker-release.yml
+++ b/.github/workflows/docker-release.yml
@@ -11,4 +11,4 @@
- name: curl
run: |
apk add curl bash
- curl -s -X POST -H "Content-Type: application/json" -H "Accept: application/json" -H "Travis-API-Version: 3" -H "Authorization: token ${{ secrets.TRAVIS_CI_TOKEN }}" -d '{"request":{"branch":"master"}}' https://api.travis-ci.org/repo/frappe%2Ffrappe_docker/requests
+ curl -s -X POST -H "Content-Type: application/json" -H "Accept: application/json" -H "Travis-API-Version: 3" -H "Authorization: token ${{ secrets.TRAVIS_CI_TOKEN }}" -d '{"request":{"branch":"master"}}' https://api.travis-ci.com/repo/frappe%2Ffrappe_docker/requests
diff --git a/erpnext/accounts/doctype/cost_center/cost_center.json b/erpnext/accounts/doctype/cost_center/cost_center.json
index c9bbbab..e7fa954 100644
--- a/erpnext/accounts/doctype/cost_center/cost_center.json
+++ b/erpnext/accounts/doctype/cost_center/cost_center.json
@@ -146,7 +146,7 @@
"idx": 1,
"is_tree": 1,
"links": [],
- "modified": "2020-04-29 16:09:30.025214",
+ "modified": "2020-06-17 16:09:30.025214",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Cost Center",
diff --git a/erpnext/controllers/item_variant.py b/erpnext/controllers/item_variant.py
index 50b17ab..1f95e00 100644
--- a/erpnext/controllers/item_variant.py
+++ b/erpnext/controllers/item_variant.py
@@ -102,7 +102,7 @@
frappe.throw(_("{0} is not a valid Value for Attribute {1} of Item {2}.").format(
frappe.bold(attribute_value), frappe.bold(attribute), frappe.bold(item)), InvalidItemAttributeValueError, title=_("Invalid Value"))
else:
- msg = _("The value {0} is already assigned to an exisiting Item {1}.").format(
+ msg = _("The value {0} is already assigned to an existing Item {1}.").format(
frappe.bold(attribute_value), frappe.bold(item))
msg += "<br>" + _("To still proceed with editing this Attribute Value, enable {0} in Item Variant Settings.").format(frappe.bold("Allow Rename Attribute Value"))
diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py
index 2888c76..759c6cd 100644
--- a/erpnext/controllers/stock_controller.py
+++ b/erpnext/controllers/stock_controller.py
@@ -227,7 +227,9 @@
def check_expense_account(self, item):
if not item.get("expense_account"):
- frappe.throw(_("Expense Account not set for Item {0}. Please set an Expense Account for the item in the Items table").format(item.item_code))
+ frappe.throw(_("Row #{0}: Expense Account not set for Item {1}. Please set an Expense \
+ Account in the Items table").format(item.idx, frappe.bold(item.item_code)),
+ title=_("Expense Account Missing"))
else:
is_expense_account = frappe.db.get_value("Account",
diff --git a/erpnext/education/doctype/fee_structure/fee_structure.js b/erpnext/education/doctype/fee_structure/fee_structure.js
index 7606565..f09d2ef 100644
--- a/erpnext/education/doctype/fee_structure/fee_structure.js
+++ b/erpnext/education/doctype/fee_structure/fee_structure.js
@@ -9,6 +9,14 @@
},
onload: function(frm) {
+ frm.set_query("academic_term", function() {
+ return {
+ "filters": {
+ "academic_year": frm.doc.academic_year
+ }
+ };
+ });
+
frm.set_query("receivable_account", function(doc) {
return {
filters: {
diff --git a/erpnext/education/doctype/fee_structure/fee_structure.json b/erpnext/education/doctype/fee_structure/fee_structure.json
index 8ff6851..67e4637 100644
--- a/erpnext/education/doctype/fee_structure/fee_structure.json
+++ b/erpnext/education/doctype/fee_structure/fee_structure.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"allow_import": 1,
"allow_rename": 1,
"autoname": "naming_series:",
@@ -11,8 +12,8 @@
"program",
"student_category",
"column_break_2",
- "academic_term",
"academic_year",
+ "academic_term",
"section_break_4",
"components",
"section_break_6",
@@ -157,7 +158,8 @@
],
"icon": "fa fa-flag",
"is_submittable": 1,
- "modified": "2019-05-26 09:04:17.765758",
+ "links": [],
+ "modified": "2020-06-16 15:34:57.295010",
"modified_by": "Administrator",
"module": "Education",
"name": "Fee Structure",
diff --git a/erpnext/education/doctype/student_admission/student_admission.json b/erpnext/education/doctype/student_admission/student_admission.json
index b3c10d4..1096888 100644
--- a/erpnext/education/doctype/student_admission/student_admission.json
+++ b/erpnext/education/doctype/student_admission/student_admission.json
@@ -1,398 +1,119 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 1,
- "allow_import": 0,
- "allow_rename": 1,
- "autoname": "",
- "beta": 0,
- "creation": "2016-09-13 03:05:27.154713",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Document",
- "editable_grid": 1,
+ "actions": [],
+ "allow_guest_to_view": 1,
+ "allow_rename": 1,
+ "creation": "2016-09-13 03:05:27.154713",
+ "doctype": "DocType",
+ "document_type": "Document",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "title",
+ "route",
+ "column_break_3",
+ "academic_year",
+ "admission_start_date",
+ "admission_end_date",
+ "published",
+ "enable_admission_application",
+ "section_break_5",
+ "program_details",
+ "introduction"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "title",
- "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,
- "label": "Title",
- "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
- },
+ "fieldname": "title",
+ "fieldtype": "Data",
+ "label": "Title"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fieldname": "route",
- "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,
- "label": "Route",
- "length": 0,
- "no_copy": 1,
- "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,
+ "fieldname": "route",
+ "fieldtype": "Data",
+ "label": "Route",
+ "no_copy": 1,
"unique": 1
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "application_form_route",
- "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,
- "label": "Application Form Route",
- "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": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "fieldname": "column_break_3",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_3",
- "fieldtype": "Column 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,
- "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
- },
+ "fieldname": "academic_year",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Academic Year",
+ "no_copy": 1,
+ "options": "Academic Year",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "academic_year",
- "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": 1,
- "label": "Academic Year",
- "length": 0,
- "no_copy": 1,
- "options": "Academic Year",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "fieldname": "admission_start_date",
+ "fieldtype": "Date",
+ "label": "Admission Start Date",
+ "no_copy": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "admission_start_date",
- "fieldtype": "Date",
- "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": "Admission Start Date",
- "length": 0,
- "no_copy": 1,
- "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
- },
+ "fieldname": "admission_end_date",
+ "fieldtype": "Date",
+ "label": "Admission End Date",
+ "no_copy": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "admission_end_date",
- "fieldtype": "Date",
- "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": "Admission End Date",
- "length": 0,
- "no_copy": 1,
- "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
- },
+ "default": "0",
+ "fieldname": "published",
+ "fieldtype": "Check",
+ "label": "Publish on website"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "published",
- "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": "Publish on website",
- "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
- },
+ "fieldname": "section_break_5",
+ "fieldtype": "Section Break",
+ "label": "Eligibility and Details"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_5",
- "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": "Eligibility and Details",
- "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
- },
+ "fieldname": "program_details",
+ "fieldtype": "Table",
+ "label": "Eligibility and Details",
+ "options": "Student Admission Program"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "program_details",
- "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": "Eligibility and Details",
- "length": 0,
- "no_copy": 0,
- "options": "Student Admission Program",
- "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
- },
+ "fieldname": "introduction",
+ "fieldtype": "Text Editor",
+ "label": "Introduction"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "introduction",
- "fieldtype": "Text Editor",
- "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": "Introduction",
- "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
+ "default": "0",
+ "fieldname": "enable_admission_application",
+ "fieldtype": "Check",
+ "label": "Enable Admission Application"
}
- ],
- "has_web_view": 1,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_published_field": "published",
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2017-11-10 18:57:34.570376",
- "modified_by": "Administrator",
- "module": "Education",
- "name": "Student Admission",
- "name_case": "",
- "owner": "Administrator",
+ ],
+ "has_web_view": 1,
+ "is_published_field": "published",
+ "links": [],
+ "modified": "2020-06-15 20:18:38.591626",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Student Admission",
+ "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,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Academics User",
+ "share": 1,
"write": 1
}
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "restrict_to_domain": "Education",
- "route": "admissions",
- "show_name_in_global_search": 1,
- "sort_field": "modified",
- "sort_order": "DESC",
- "title_field": "title",
- "track_changes": 0,
- "track_seen": 0
+ ],
+ "restrict_to_domain": "Education",
+ "route": "admissions",
+ "show_name_in_global_search": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "title_field": "title"
}
\ No newline at end of file
diff --git a/erpnext/education/doctype/student_admission/templates/student_admission.html b/erpnext/education/doctype/student_admission/templates/student_admission.html
index 25afaca..e5a9ead 100644
--- a/erpnext/education/doctype/student_admission/templates/student_admission.html
+++ b/erpnext/education/doctype/student_admission/templates/student_admission.html
@@ -43,8 +43,8 @@
<thead>
<tr class="active">
<th style="width: 90px">Program/Std.</th>
- <th style="width: 170px">Minumum Age(DOB)</th>
- <th style="width: 170px">Maximum Age(DOB)</th>
+ <th style="width: 170px">Minumum Age</th>
+ <th style="width: 170px">Maximum Age</th>
<th style="width: 100px">Application Fee</th>
</tr>
</thead>
@@ -52,8 +52,8 @@
{% for row in program_details %}
<tr>
<td>{{ row.program }}</td>
- <td>{{ row.minimum_age }}</td>
- <td>{{ row.maximum_age }}</td>
+ <td>{{ row.min_age }}</td>
+ <td>{{ row.max_age }}</td>
<td>{{ row.application_fee }}</td>
</tr>
{% endfor %}
@@ -61,12 +61,11 @@
</table>
</div>
{% endif %}
-
- {%- if application_form_route -%}
+ {%- if doc.enable_admission_application -%}
<br>
<p>
<a class='btn btn-primary'
- href='/{{ doc.application_form_route }}?new=1'>
+ href='/student-applicant?new=1&student_admission={{doc.name}}'>
{{ _("Apply Now") }}</a>
</p>
{% endif %}
diff --git a/erpnext/education/doctype/student_admission/test_student_admission.js b/erpnext/education/doctype/student_admission/test_student_admission.js
index ed794b2..3a0bb0b 100644
--- a/erpnext/education/doctype/student_admission/test_student_admission.js
+++ b/erpnext/education/doctype/student_admission/test_student_admission.js
@@ -11,7 +11,7 @@
{admission_start_date: '2016-04-20'},
{admission_end_date: '2016-05-31'},
{title: '2016-17 Admissions'},
- {application_form_route: 'student-applicant'},
+ {enable_admission_application: 1},
{introduction: 'Test intro'},
{program_details: [
[
@@ -28,7 +28,7 @@
assert.ok(cur_frm.doc.admission_start_date == '2016-04-20');
assert.ok(cur_frm.doc.admission_end_date == '2016-05-31');
assert.ok(cur_frm.doc.title == '2016-17 Admissions');
- assert.ok(cur_frm.doc.application_form_route == 'student-applicant');
+ assert.ok(cur_frm.doc.enable_admission_application == 1);
assert.ok(cur_frm.doc.introduction == 'Test intro');
assert.ok(cur_frm.doc.program_details[0].program == 'Standard Test', 'Program correctly selected');
assert.ok(cur_frm.doc.program_details[0].application_fee == 1000);
diff --git a/erpnext/education/doctype/student_admission_program/student_admission_program.json b/erpnext/education/doctype/student_admission_program/student_admission_program.json
index 97b1bba..e9f041e 100644
--- a/erpnext/education/doctype/student_admission_program/student_admission_program.json
+++ b/erpnext/education/doctype/student_admission_program/student_admission_program.json
@@ -1,237 +1,77 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "autoname": "",
- "beta": 0,
- "creation": "2017-09-15 12:59:43.207923",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "actions": [],
+ "creation": "2017-09-15 12:59:43.207923",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "program",
+ "min_age",
+ "max_age",
+ "column_break_4",
+ "application_fee",
+ "applicant_naming_series"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "program",
- "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": "Program",
- "length": 0,
- "no_copy": 0,
- "options": "Program",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "program",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Program",
+ "options": "Program",
+ "show_days": 1,
+ "show_seconds": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "minimum_age",
- "fieldtype": "Date",
- "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": "Minimum Age",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_4",
+ "fieldtype": "Column Break",
+ "show_days": 1,
+ "show_seconds": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "maximum_age",
- "fieldtype": "Date",
- "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": "Maximum Age",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "application_fee",
+ "fieldtype": "Currency",
+ "in_list_view": 1,
+ "label": "Application Fee",
+ "show_days": 1,
+ "show_seconds": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_4",
- "fieldtype": "Column 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,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "applicant_naming_series",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Naming Series (for Student Applicant)",
+ "show_days": 1,
+ "show_seconds": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "application_fee",
- "fieldtype": "Currency",
- "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": "Application Fee",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "min_age",
+ "fieldtype": "Int",
+ "in_list_view": 1,
+ "label": "Minimum Age",
+ "show_days": 1,
+ "show_seconds": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "applicant_naming_series",
- "fieldtype": "Data",
- "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": "Naming Series (for Student Applicant)",
- "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,
- "translatable": 0,
- "unique": 0
+ "fieldname": "max_age",
+ "fieldtype": "Int",
+ "in_list_view": 1,
+ "label": "Maximum Age",
+ "show_days": 1,
+ "show_seconds": 1
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 1,
- "max_attachments": 0,
- "modified": "2018-11-04 03:37:17.408427",
- "modified_by": "Administrator",
- "module": "Education",
- "name": "Student Admission Program",
- "name_case": "",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "restrict_to_domain": "Education",
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0,
- "track_views": 0
+ ],
+ "istable": 1,
+ "links": [],
+ "modified": "2020-06-10 23:06:30.037404",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Student Admission Program",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "restrict_to_domain": "Education",
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/education/doctype/student_applicant/student_applicant.py b/erpnext/education/doctype/student_applicant/student_applicant.py
index ab94780..2113482 100644
--- a/erpnext/education/doctype/student_applicant/student_applicant.py
+++ b/erpnext/education/doctype/student_applicant/student_applicant.py
@@ -6,7 +6,7 @@
import frappe
from frappe import _
from frappe.model.document import Document
-from frappe.utils import getdate
+from frappe.utils import getdate, add_years, nowdate, date_diff
class StudentApplicant(Document):
def autoname(self):
@@ -31,6 +31,7 @@
def validate(self):
self.validate_dates()
self.title = " ".join(filter(None, [self.first_name, self.middle_name, self.last_name]))
+
if self.student_admission and self.program and self.date_of_birth:
self.validation_from_student_admission()
@@ -48,16 +49,16 @@
frappe.throw(_("Please select Student Admission which is mandatory for the paid student applicant"))
def validation_from_student_admission(self):
+
student_admission = get_student_admission_data(self.student_admission, self.program)
- # 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.min_age and \
+ date_diff(nowdate(), add_years(getdate(self.date_of_birth), student_admission.min_age)) < 0:
+ frappe.throw(_("Not eligible for the admission in this program as per Date Of Birth"))
- 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"))
+ if student_admission and student_admission.max_age and \
+ date_diff(nowdate(), add_years(getdate(self.date_of_birth), student_admission.max_age)) > 0:
+ frappe.throw(_("Not eligible for the admission in this program as per Date Of Birth"))
def on_payment_authorized(self, *args, **kwargs):
@@ -65,10 +66,12 @@
def get_student_admission_data(student_admission, program):
+
student_admission = frappe.db.sql("""select sa.admission_start_date, sa.admission_end_date,
- sap.program, sap.minimum_age, sap.maximum_age, sap.applicant_naming_series
+ sap.program, sap.min_age, sap.max_age, sap.applicant_naming_series
from `tabStudent Admission` sa, `tabStudent Admission Program` sap
where sa.name = sap.parent and sa.name = %s and sap.program = %s""", (student_admission, program), as_dict=1)
+
if student_admission:
return student_admission[0]
else:
diff --git a/erpnext/education/web_form/student_applicant/student_applicant.json b/erpnext/education/web_form/student_applicant/student_applicant.json
index b1ad754..1810f07 100644
--- a/erpnext/education/web_form/student_applicant/student_applicant.json
+++ b/erpnext/education/web_form/student_applicant/student_applicant.json
@@ -1,200 +1,248 @@
{
- "accept_payment": 0,
- "allow_comments": 0,
- "allow_delete": 0,
- "allow_edit": 1,
- "allow_incomplete": 0,
- "allow_multiple": 1,
- "allow_print": 0,
- "amount": 0.0,
- "amount_based_on_field": 0,
- "creation": "2016-09-22 13:10:10.792735",
- "doc_type": "Student Applicant",
- "docstatus": 0,
- "doctype": "Web Form",
- "idx": 0,
- "is_standard": 1,
- "login_required": 1,
- "max_attachment_size": 0,
- "modified": "2017-02-21 05:44:46.022738",
- "modified_by": "Administrator",
- "module": "Education",
- "name": "student-applicant",
- "owner": "Administrator",
- "payment_button_label": "Buy Now",
- "published": 1,
- "route": "student-applicant",
- "show_sidebar": 1,
- "sidebar_items": [],
- "success_url": "/student-applicant",
- "title": "Student Applicant",
+ "accept_payment": 0,
+ "allow_comments": 0,
+ "allow_delete": 0,
+ "allow_edit": 1,
+ "allow_incomplete": 0,
+ "allow_multiple": 1,
+ "allow_print": 0,
+ "amount": 0.0,
+ "amount_based_on_field": 0,
+ "creation": "2016-09-22 13:10:10.792735",
+ "doc_type": "Student Applicant",
+ "docstatus": 0,
+ "doctype": "Web Form",
+ "idx": 0,
+ "is_standard": 1,
+ "login_required": 1,
+ "max_attachment_size": 0,
+ "modified": "2020-06-11 22:53:45.875310",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "student-applicant",
+ "owner": "Administrator",
+ "payment_button_label": "Buy Now",
+ "published": 1,
+ "route": "student-applicant",
+ "route_to_success_link": 0,
+ "show_attachments": 0,
+ "show_in_grid": 0,
+ "show_sidebar": 1,
+ "sidebar_items": [],
+ "success_url": "/student-applicant",
+ "title": "Student Applicant",
"web_form_fields": [
{
- "fieldname": "first_name",
- "fieldtype": "Data",
- "hidden": 0,
- "label": "First Name",
- "max_length": 0,
- "max_value": 0,
- "read_only": 0,
- "reqd": 1
- },
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "first_name",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "label": "First Name",
+ "max_length": 0,
+ "max_value": 0,
+ "read_only": 0,
+ "reqd": 1,
+ "show_in_filter": 0
+ },
{
- "fieldname": "middle_name",
- "fieldtype": "Data",
- "hidden": 0,
- "label": "Middle Name",
- "max_length": 0,
- "max_value": 0,
- "read_only": 0,
- "reqd": 0
- },
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "middle_name",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "label": "Middle Name",
+ "max_length": 0,
+ "max_value": 0,
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
{
- "fieldname": "last_name",
- "fieldtype": "Data",
- "hidden": 0,
- "label": "Last Name",
- "max_length": 0,
- "max_value": 0,
- "read_only": 0,
- "reqd": 0
- },
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "last_name",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "label": "Last Name",
+ "max_length": 0,
+ "max_value": 0,
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
{
- "fieldname": "image",
- "fieldtype": "Data",
- "hidden": 0,
- "label": "Image",
- "max_length": 0,
- "max_value": 0,
- "read_only": 0,
- "reqd": 0
- },
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "image",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "label": "Image",
+ "max_length": 0,
+ "max_value": 0,
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
{
- "fieldname": "program",
- "fieldtype": "Link",
- "hidden": 0,
- "label": "Program",
- "max_length": 0,
- "max_value": 0,
- "options": "Program",
- "read_only": 0,
- "reqd": 1
- },
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "program",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "label": "Program",
+ "max_length": 0,
+ "max_value": 0,
+ "options": "Program",
+ "read_only": 0,
+ "reqd": 1,
+ "show_in_filter": 0
+ },
{
- "fieldname": "academic_year",
- "fieldtype": "Link",
- "hidden": 0,
- "label": "Academic Year",
- "max_length": 0,
- "max_value": 0,
- "options": "Academic Year",
- "read_only": 0,
- "reqd": 0
- },
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "academic_year",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "label": "Academic Year",
+ "max_length": 0,
+ "max_value": 0,
+ "options": "Academic Year",
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
{
- "fieldname": "date_of_birth",
- "fieldtype": "Date",
- "hidden": 0,
- "label": "Date of Birth",
- "max_length": 0,
- "max_value": 0,
- "read_only": 0,
- "reqd": 0
- },
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "date_of_birth",
+ "fieldtype": "Date",
+ "hidden": 0,
+ "label": "Date of Birth",
+ "max_length": 0,
+ "max_value": 0,
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
{
- "fieldname": "blood_group",
- "fieldtype": "Select",
- "hidden": 0,
- "label": "Blood Group",
- "max_length": 0,
- "max_value": 0,
- "options": "\nA+\nA-\nB+\nB-\nO+\nO-\nAB+\nAB-",
- "read_only": 0,
- "reqd": 0
- },
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "blood_group",
+ "fieldtype": "Select",
+ "hidden": 0,
+ "label": "Blood Group",
+ "max_length": 0,
+ "max_value": 0,
+ "options": "\nA+\nA-\nB+\nB-\nO+\nO-\nAB+\nAB-",
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
{
- "fieldname": "student_email_id",
- "fieldtype": "Data",
- "hidden": 0,
- "label": "Student Email ID",
- "max_length": 0,
- "max_value": 0,
- "read_only": 0,
- "reqd": 0
- },
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "student_email_id",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "label": "Student Email ID",
+ "max_length": 0,
+ "max_value": 0,
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
{
- "fieldname": "student_mobile_number",
- "fieldtype": "Data",
- "hidden": 0,
- "label": "Student Mobile Number",
- "max_length": 0,
- "max_value": 0,
- "read_only": 0,
- "reqd": 0
- },
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "student_mobile_number",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "label": "Student Mobile Number",
+ "max_length": 0,
+ "max_value": 0,
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
{
- "default": "INDIAN",
- "fieldname": "nationality",
- "fieldtype": "Data",
- "hidden": 0,
- "label": "Nationality",
- "max_length": 0,
- "max_value": 0,
- "options": "",
- "read_only": 0,
- "reqd": 0
- },
+ "allow_read_on_all_link_options": 0,
+ "default": "INDIAN",
+ "fieldname": "nationality",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "label": "Nationality",
+ "max_length": 0,
+ "max_value": 0,
+ "options": "",
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
{
- "fieldname": "address_line_1",
- "fieldtype": "Data",
- "hidden": 0,
- "label": "Address Line 1",
- "max_length": 0,
- "max_value": 0,
- "read_only": 0,
- "reqd": 0
- },
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "address_line_1",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "label": "Address Line 1",
+ "max_length": 0,
+ "max_value": 0,
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
{
- "fieldname": "address_line_2",
- "fieldtype": "Data",
- "hidden": 0,
- "label": "Address Line 2",
- "max_length": 0,
- "max_value": 0,
- "read_only": 0,
- "reqd": 0
- },
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "address_line_2",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "label": "Address Line 2",
+ "max_length": 0,
+ "max_value": 0,
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
{
- "fieldname": "pincode",
- "fieldtype": "Data",
- "hidden": 0,
- "label": "Pincode",
- "max_length": 0,
- "max_value": 0,
- "read_only": 0,
- "reqd": 0
- },
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "pincode",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "label": "Pincode",
+ "max_length": 0,
+ "max_value": 0,
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
{
- "fieldname": "guardians",
- "fieldtype": "Table",
- "hidden": 0,
- "label": "Guardians",
- "max_length": 0,
- "max_value": 0,
- "options": "Student Guardian",
- "read_only": 0,
- "reqd": 0
- },
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "guardians",
+ "fieldtype": "Table",
+ "hidden": 0,
+ "label": "Guardians",
+ "max_length": 0,
+ "max_value": 0,
+ "options": "Student Guardian",
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
{
- "fieldname": "siblings",
- "fieldtype": "Table",
- "hidden": 0,
- "label": "Siblings",
- "max_length": 0,
- "max_value": 0,
- "options": "Student Sibling",
- "read_only": 0,
- "reqd": 0
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "siblings",
+ "fieldtype": "Table",
+ "hidden": 0,
+ "label": "Siblings",
+ "max_length": 0,
+ "max_value": 0,
+ "options": "Student Sibling",
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
+ {
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "student_admission",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "label": "Student Admission",
+ "max_length": 0,
+ "max_value": 0,
+ "options": "Student Admission",
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
}
]
}
\ No newline at end of file
diff --git a/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.py b/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.py
index 64c3b2d..25ffd28 100644
--- a/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.py
+++ b/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.py
@@ -8,6 +8,7 @@
from frappe import _
from frappe.model.document import Document
from frappe.utils import get_request_session
+from requests.exceptions import HTTPError
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
from erpnext.erpnext_integrations.utils import get_webhook_address
from erpnext.erpnext_integrations.doctype.shopify_log.shopify_log import make_shopify_log
@@ -29,19 +30,24 @@
webhooks = ["orders/create", "orders/paid", "orders/fulfilled"]
# url = get_shopify_url('admin/webhooks.json', self)
created_webhooks = [d.method for d in self.webhooks]
- url = get_shopify_url('admin/api/2019-04/webhooks.json', self)
+ url = get_shopify_url('admin/api/2020-04/webhooks.json', self)
for method in webhooks:
session = get_request_session()
try:
- d = session.post(url, data=json.dumps({
+ res = session.post(url, data=json.dumps({
"webhook": {
"topic": method,
"address": get_webhook_address(connector_name='shopify_connection', method='store_request_data'),
"format": "json"
}
}), headers=get_header(self))
- d.raise_for_status()
- self.update_webhook_table(method, d.json())
+ res.raise_for_status()
+ self.update_webhook_table(method, res.json())
+
+ except HTTPError as e:
+ error_message = res.json().get('errors', e)
+ make_shopify_log(status="Warning", exception=error_message, rollback=True)
+
except Exception as e:
make_shopify_log(status="Warning", exception=e, rollback=True)
@@ -50,13 +56,18 @@
deleted_webhooks = []
for d in self.webhooks:
- url = get_shopify_url('admin/api/2019-04/webhooks/{0}.json'.format(d.webhook_id), self)
+ url = get_shopify_url('admin/api/2020-04/webhooks/{0}.json'.format(d.webhook_id), self)
try:
res = session.delete(url, headers=get_header(self))
res.raise_for_status()
deleted_webhooks.append(d)
+
+ except HTTPError as e:
+ error_message = res.json().get('errors', e)
+ make_shopify_log(status="Warning", exception=error_message, rollback=True)
+
except Exception as e:
- frappe.log_error(message=frappe.get_traceback(), title=e)
+ frappe.log_error(message=e, title='Shopify Webhooks Issue')
for d in deleted_webhooks:
self.remove(d)
@@ -125,4 +136,3 @@
}
create_custom_fields(custom_fields)
-
diff --git a/erpnext/erpnext_integrations/doctype/shopify_settings/sync_product.py b/erpnext/erpnext_integrations/doctype/shopify_settings/sync_product.py
index bde1011..f9f0bb3 100644
--- a/erpnext/erpnext_integrations/doctype/shopify_settings/sync_product.py
+++ b/erpnext/erpnext_integrations/doctype/shopify_settings/sync_product.py
@@ -8,7 +8,7 @@
shopify_variants_attr_list = ["option1", "option2", "option3"]
def sync_item_from_shopify(shopify_settings, item):
- url = get_shopify_url("admin/api/2019-04/products/{0}.json".format(item.get("product_id")), shopify_settings)
+ url = get_shopify_url("admin/api/2020-04/products/{0}.json".format(item.get("product_id")), shopify_settings)
session = get_request_session()
try:
diff --git a/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.py b/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.py
index 0c13b6a..3dc7c1e 100644
--- a/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.py
+++ b/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.py
@@ -70,6 +70,7 @@
if frappe.db.get_value('Item', item, 'is_stock_item'):
frappe.throw(_(msg))
+@frappe.whitelist()
def get_practitioner_list(doctype, txt, searchfield, start, page_len, filters=None):
fields = ['name', 'practitioner_name', 'mobile_phone']
diff --git a/erpnext/hr/desk_page/hr/hr.json b/erpnext/hr/desk_page/hr/hr.json
index 1c24444..12548d4 100644
--- a/erpnext/hr/desk_page/hr/hr.json
+++ b/erpnext/hr/desk_page/hr/hr.json
@@ -93,7 +93,7 @@
"idx": 0,
"is_standard": 1,
"label": "HR",
- "modified": "2020-06-10 12:41:41.695669",
+ "modified": "2020-06-16 19:20:50.976045",
"modified_by": "Administrator",
"module": "HR",
"name": "HR",
@@ -126,7 +126,7 @@
},
{
"label": "Salary Structure",
- "link_to": "Payroll Entry",
+ "link_to": "Salary Structure",
"type": "DocType"
},
{
diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py
index 2543eec..7d31a1c 100644
--- a/erpnext/manufacturing/doctype/bom/bom.py
+++ b/erpnext/manufacturing/doctype/bom/bom.py
@@ -119,6 +119,7 @@
"description": d.description,
"time_in_mins": d.time_in_mins,
"batch_size": d.batch_size,
+ "operating_cost": d.operating_cost,
"idx": d.idx
})
child.hour_rate = flt(d.hour_rate / self.conversion_rate, 2)
diff --git a/erpnext/manufacturing/doctype/bom_operation/bom_operation.json b/erpnext/manufacturing/doctype/bom_operation/bom_operation.json
index 3ca851d..0350e2c 100644
--- a/erpnext/manufacturing/doctype/bom_operation/bom_operation.json
+++ b/erpnext/manufacturing/doctype/bom_operation/bom_operation.json
@@ -78,6 +78,7 @@
"read_only": 1
},
{
+ "depends_on": "eval:parent.doctype == 'BOM'",
"fieldname": "base_hour_rate",
"fieldtype": "Currency",
"label": "Base Hour Rate(Company Currency)",
@@ -87,6 +88,7 @@
},
{
"default": "5",
+ "depends_on": "eval:parent.doctype == 'BOM'",
"fieldname": "base_operating_cost",
"fieldtype": "Currency",
"label": "Operating Cost(Company Currency)",
@@ -108,12 +110,12 @@
],
"idx": 1,
"istable": 1,
- "modified": "2019-07-16 22:35:55.374037",
- "modified_by": "govindsmenokee@gmail.com",
+ "modified": "2020-06-16 17:01:11.128420",
+ "modified_by": "Administrator",
"module": "Manufacturing",
"name": "BOM Operation",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC"
-}
+}
\ No newline at end of file
diff --git a/erpnext/manufacturing/doctype/routing/routing.js b/erpnext/manufacturing/doctype/routing/routing.js
index 6cfd0ba..d7589fa 100644
--- a/erpnext/manufacturing/doctype/routing/routing.js
+++ b/erpnext/manufacturing/doctype/routing/routing.js
@@ -44,7 +44,6 @@
name: d.workstation
},
callback: function (data) {
- frappe.model.set_value(d.doctype, d.name, "base_hour_rate", data.message.hour_rate);
frappe.model.set_value(d.doctype, d.name, "hour_rate", data.message.hour_rate);
frm.events.calculate_operating_cost(frm, d);
}
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 3c27647..b3a38b6 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -698,4 +698,5 @@
erpnext.patches.v13_0.delete_old_purchase_reports
erpnext.patches.v12_0.set_italian_import_supplier_invoice_permissions
erpnext.patches.v13_0.update_sla_enhancements
+erpnext.patches.v12_0.update_address_template_for_india
erpnext.patches.v12_0.set_multi_uom_in_rfq
diff --git a/erpnext/patches/v12_0/move_due_advance_amount_to_pending_amount.py b/erpnext/patches/v12_0/move_due_advance_amount_to_pending_amount.py
index f1ffaf9..6013eaa 100644
--- a/erpnext/patches/v12_0/move_due_advance_amount_to_pending_amount.py
+++ b/erpnext/patches/v12_0/move_due_advance_amount_to_pending_amount.py
@@ -6,4 +6,6 @@
def execute():
''' Move from due_advance_amount to pending_amount '''
- frappe.db.sql(''' UPDATE `tabEmployee Advance` SET pending_amount=due_advance_amount ''')
+
+ if frappe.db.has_column("Employee Advance", "due_advance_amount"):
+ frappe.db.sql(''' UPDATE `tabEmployee Advance` SET pending_amount=due_advance_amount ''')
diff --git a/erpnext/patches/v12_0/update_address_template_for_india.py b/erpnext/patches/v12_0/update_address_template_for_india.py
new file mode 100644
index 0000000..0d582da
--- /dev/null
+++ b/erpnext/patches/v12_0/update_address_template_for_india.py
@@ -0,0 +1,12 @@
+# Copyright (c) 2020, Frappe and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+from erpnext.regional.address_template.setup import set_up_address_templates
+
+def execute():
+ if frappe.db.get_value('Company', {'country': 'India'}, 'name'):
+ address_template = frappe.db.get_value('Address Template', 'India', 'template')
+ if not address_template or "gstin" not in address_template:
+ set_up_address_templates(default_country='India')
diff --git a/erpnext/portal/product_configurator/utils.py b/erpnext/portal/product_configurator/utils.py
index 0993e69..6b6b8c5 100644
--- a/erpnext/portal/product_configurator/utils.py
+++ b/erpnext/portal/product_configurator/utils.py
@@ -1,4 +1,5 @@
import frappe
+from frappe.utils import cint
from erpnext.portal.product_configurator.item_variants_cache import ItemVariantsCacheManager
def get_field_filter_data():
@@ -243,6 +244,8 @@
else:
product_info = None
+ product_info["allow_items_not_in_stock"] = cint(data.cart_settings.allow_items_not_in_stock)
+
return {
'next_attribute': next_attribute,
'valid_options_for_attributes': valid_options_for_attributes,
diff --git a/erpnext/projects/doctype/timesheet/test_timesheet.py b/erpnext/projects/doctype/timesheet/test_timesheet.py
index 32f0428..cbc624c 100644
--- a/erpnext/projects/doctype/timesheet/test_timesheet.py
+++ b/erpnext/projects/doctype/timesheet/test_timesheet.py
@@ -13,7 +13,7 @@
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
from erpnext.hr.doctype.salary_structure.test_salary_structure \
import make_salary_structure, create_salary_structure_assignment
-
+from erpnext.hr.doctype.employee.test_employee import make_employee
class TestTimesheet(unittest.TestCase):
def setUp(self):
@@ -25,8 +25,10 @@
def test_timesheet_billing_amount(self):
- make_salary_structure_for_timesheet("_T-Employee-00001")
- timesheet = make_timesheet("_T-Employee-00001", simulate=True, billable=1)
+ emp = make_employee("test_employee_6@salary.com")
+
+ make_salary_structure_for_timesheet(emp)
+ timesheet = make_timesheet(emp, simulate=True, billable=1)
self.assertEqual(timesheet.total_hours, 2)
self.assertEqual(timesheet.total_billable_hours, 2)
@@ -35,8 +37,10 @@
self.assertEqual(timesheet.total_billable_amount, 100)
def test_timesheet_billing_amount_not_billable(self):
- make_salary_structure_for_timesheet("_T-Employee-00001")
- timesheet = make_timesheet("_T-Employee-00001", simulate=True, billable=0)
+ emp = make_employee("test_employee_6@salary.com")
+
+ make_salary_structure_for_timesheet(emp)
+ timesheet = make_timesheet(emp, simulate=True, billable=0)
self.assertEqual(timesheet.total_hours, 2)
self.assertEqual(timesheet.total_billable_hours, 0)
@@ -45,8 +49,10 @@
self.assertEqual(timesheet.total_billable_amount, 0)
def test_salary_slip_from_timesheet(self):
- salary_structure = make_salary_structure_for_timesheet("_T-Employee-00001")
- timesheet = make_timesheet("_T-Employee-00001", simulate = True, billable=1)
+ emp = make_employee("test_employee_6@salary.com")
+
+ salary_structure = make_salary_structure_for_timesheet(emp)
+ timesheet = make_timesheet(emp, simulate = True, billable=1)
salary_slip = make_salary_slip(timesheet.name)
salary_slip.submit()
@@ -65,7 +71,9 @@
self.assertEqual(timesheet.status, 'Submitted')
def test_sales_invoice_from_timesheet(self):
- timesheet = make_timesheet("_T-Employee-00001", simulate=True, billable=1)
+ emp = make_employee("test_employee_6@salary.com")
+
+ timesheet = make_timesheet(emp, simulate=True, billable=1)
sales_invoice = make_sales_invoice(timesheet.name, '_Test Item', '_Test Customer')
sales_invoice.due_date = nowdate()
sales_invoice.submit()
@@ -80,7 +88,9 @@
self.assertEqual(item.rate, 50.00)
def test_timesheet_billing_based_on_project(self):
- timesheet = make_timesheet("_T-Employee-00001", simulate=True, billable=1, project = '_Test Project', company='_Test Company')
+ emp = make_employee("test_employee_6@salary.com")
+
+ timesheet = make_timesheet(emp, simulate=True, billable=1, project = '_Test Project', company='_Test Company')
sales_invoice = create_sales_invoice(do_not_save=True)
sales_invoice.project = '_Test Project'
sales_invoice.submit()
@@ -90,6 +100,8 @@
self.assertEqual(ts.time_logs[0].sales_invoice, sales_invoice.name)
def test_timesheet_time_overlap(self):
+ emp = make_employee("test_employee_6@salary.com")
+
settings = frappe.get_single('Projects Settings')
initial_setting = settings.ignore_employee_time_overlap
settings.ignore_employee_time_overlap = 0
@@ -97,7 +109,7 @@
update_activity_type("_Test Activity Type")
timesheet = frappe.new_doc("Timesheet")
- timesheet.employee = "_T-Employee-00001"
+ timesheet.employee = emp
timesheet.append(
'time_logs',
{
@@ -129,12 +141,14 @@
settings.save()
def test_timesheet_std_working_hours(self):
+ emp = make_employee("test_employee_6@salary.com")
+
company = frappe.get_doc('Company', "_Test Company")
company.standard_working_hours = 8
company.save()
timesheet = frappe.new_doc("Timesheet")
- timesheet.employee = "_T-Employee-00001"
+ timesheet.employee = emp
timesheet.company = '_Test Company'
timesheet.append(
'time_logs',
@@ -156,7 +170,7 @@
company.save()
timesheet = frappe.new_doc("Timesheet")
- timesheet.employee = "_T-Employee-00001"
+ timesheet.employee = emp
timesheet.company = '_Test Company'
timesheet.append(
'time_logs',
diff --git a/erpnext/public/scss/website.scss b/erpnext/public/scss/website.scss
index 735b417..617e916 100644
--- a/erpnext/public/scss/website.scss
+++ b/erpnext/public/scss/website.scss
@@ -81,4 +81,10 @@
.place-order-container {
text-align: right;
+}
+
+.kb-card {
+ .card-body > .card-title {
+ line-height: 1.3;
+ }
}
\ No newline at end of file
diff --git a/erpnext/regional/address_template/templates/india.html b/erpnext/regional/address_template/templates/india.html
index ffb9d05..5d2329e 100644
--- a/erpnext/regional/address_template/templates/india.html
+++ b/erpnext/regional/address_template/templates/india.html
@@ -1,7 +1,7 @@
{{ address_line1 }}<br>{% if address_line2 %}{{ address_line2 }}<br>{% endif -%}{{ city }}<br>
{% if gst_state %}{{ gst_state }}{% endif -%}
{% if gst_state_number %}, State Code: {{ gst_state_number }}<br>{% endif -%}
-{% if pincode %}PIN: {{ pincode }}<br>{% endif -%}
+{% if pincode %}Postal Code: {{ pincode }}<br>{% endif -%}
{{ country }}<br>
{% if phone %}Phone: {{ phone }}<br>{% endif -%}
{% if fax %}Fax: {{ fax }}<br>{% endif -%}
diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py
index ac3bc20..682dfed 100644
--- a/erpnext/selling/doctype/customer/customer.py
+++ b/erpnext/selling/doctype/customer/customer.py
@@ -339,6 +339,7 @@
return lp_details
+@frappe.whitelist()
def get_customer_list(doctype, txt, searchfield, start, page_len, filters=None):
from erpnext.controllers.queries import get_fields
diff --git a/erpnext/selling/report/customer_acquisition_and_loyalty/customer_acquisition_and_loyalty.py b/erpnext/selling/report/customer_acquisition_and_loyalty/customer_acquisition_and_loyalty.py
index e78d0ff..f15f63d 100644
--- a/erpnext/selling/report/customer_acquisition_and_loyalty/customer_acquisition_and_loyalty.py
+++ b/erpnext/selling/report/customer_acquisition_and_loyalty/customer_acquisition_and_loyalty.py
@@ -5,7 +5,7 @@
import calendar
import frappe
from frappe import _
-from frappe.utils import cint, cstr
+from frappe.utils import cint, cstr, getdate
def execute(filters=None):
common_columns = [
@@ -160,7 +160,7 @@
return columns, data, None, None, None, 1
def get_customer_stats(filters, tree_view=False):
- """ Calculates number of new and repeated customers. """
+ """ Calculates number of new and repeated customers and revenue. """
company_condition = ''
if filters.get('company'):
company_condition = ' and company=%(company)s'
@@ -174,14 +174,14 @@
filters, as_dict=1):
key = si.territory if tree_view else si.posting_date.strftime('%Y-%m')
+ new_or_repeat = 'new' if si.customer not in customers else 'repeat'
customers_in.setdefault(key, {'new': [0, 0.0], 'repeat': [0, 0.0]})
- if not si.customer in customers:
- customers_in[key]['new'][0] += 1
- customers_in[key]['new'][1] += si.base_grand_total
+ # if filters.from_date <= si.posting_date.strftime('%Y-%m-%d'):
+ if getdate(filters.from_date) <= getdate(si.posting_date):
+ customers_in[key][new_or_repeat][0] += 1
+ customers_in[key][new_or_repeat][1] += si.base_grand_total
+ if new_or_repeat == 'new':
customers.append(si.customer)
- else:
- customers_in[key]['repeat'][0] += 1
- customers_in[key]['repeat'][1] += si.base_grand_total
return customers_in
diff --git a/erpnext/setup/doctype/terms_and_conditions/terms_and_conditions.json b/erpnext/setup/doctype/terms_and_conditions/terms_and_conditions.json
index aba6a79..28d1d16 100644
--- a/erpnext/setup/doctype/terms_and_conditions/terms_and_conditions.json
+++ b/erpnext/setup/doctype/terms_and_conditions/terms_and_conditions.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"allow_import": 1,
"allow_rename": 1,
"autoname": "field:title",
@@ -49,7 +50,7 @@
"fieldname": "terms_and_conditions_help",
"fieldtype": "HTML",
"label": "Terms and Conditions Help",
- "options": "<h4>Standard Terms and Conditions Example</h4>\n\n<pre>Delivery Terms for Order number {{ name }}\n\n-Order Date : {{ transaction_date }} \n-Expected Delivery Date : {{ delivery_date }}\n</pre>\n\n<h4>How to get fieldnames</h4>\n\n<p>The fieldnames you can use in your email template are the fields in the document from which you are sending the email. You can find out the fields of any documents via Setup > Customize Form View and selecting the document type (e.g. Sales Invoice)</p>\n\n<h4>Templating</h4>\n\n<p>Templates are compiled using the Jinja Templating Langauge. To learn more about Jinja, <a class=\"strong\" href=\"http://jinja.pocoo.org/docs/dev/templates/\">read this documentation.</a></p>"
+ "options": "<h4>Standard Terms and Conditions Example</h4>\n\n<pre>Delivery Terms for Order number {{ name }}\n\n-Order Date : {{ transaction_date }} \n-Expected Delivery Date : {{ delivery_date }}\n</pre>\n\n<h4>How to get fieldnames</h4>\n\n<p>The fieldnames you can use in your email template are the fields in the document from which you are sending the email. You can find out the fields of any documents via Setup > Customize Form View and selecting the document type (e.g. Sales Invoice)</p>\n\n<h4>Templating</h4>\n\n<p>Templates are compiled using the Jinja Templating Language. To learn more about Jinja, <a class=\"strong\" href=\"http://jinja.pocoo.org/docs/dev/templates/\">read this documentation.</a></p>"
},
{
"fieldname": "applicable_modules_section",
@@ -81,7 +82,8 @@
],
"icon": "icon-legal",
"idx": 1,
- "modified": "2019-07-04 13:31:30.393425",
+ "links": [],
+ "modified": "2020-06-16 22:54:38.094844",
"modified_by": "Administrator",
"module": "Setup",
"name": "Terms and Conditions",
diff --git a/erpnext/shopping_cart/cart.py b/erpnext/shopping_cart/cart.py
index 7096c17..a7e8388 100644
--- a/erpnext/shopping_cart/cart.py
+++ b/erpnext/shopping_cart/cart.py
@@ -42,9 +42,9 @@
return {
"doc": decorate_quotation_doc(doc),
- "shipping_addresses": [{"name": address.name, "display": address.display}
+ "shipping_addresses": [{"name": address.name, "title": address.address_title, "display": address.display}
for address in addresses if address.address_type == "Shipping"],
- "billing_addresses": [{"name": address.name, "display": address.display}
+ "billing_addresses": [{"name": address.name, "title": address.address_title, "display": address.display}
for address in addresses if address.address_type == "Billing"],
"shipping_rules": get_applicable_shipping_rules(party),
"cart_settings": frappe.get_cached_doc("Shopping Cart Settings")
@@ -78,8 +78,10 @@
if is_stock_item:
item_stock = get_qty_in_stock(item.item_code, "website_warehouse")
+ if not cint(item_stock.in_stock):
+ throw(_("{1} Not in Stock").format(item.item_code))
if item.qty > item_stock.stock_qty[0][0]:
- throw(_("Only {0} in stock for item {1}").format(item_stock.stock_qty[0][0], item.item_code))
+ throw(_("Only {0} in Stock for item {1}").format(item_stock.stock_qty[0][0], item.item_code))
sales_order.flags.ignore_permissions = True
sales_order.insert()
diff --git a/erpnext/support/doctype/issue/test_issue.py b/erpnext/support/doctype/issue/test_issue.py
index a004843..fb8ceb5 100644
--- a/erpnext/support/doctype/issue/test_issue.py
+++ b/erpnext/support/doctype/issue/test_issue.py
@@ -5,7 +5,7 @@
import frappe
import unittest
from erpnext.support.doctype.service_level_agreement.test_service_level_agreement import create_service_level_agreements_for_issues
-from frappe.utils import now_datetime, get_datetime
+from frappe.utils import now_datetime, get_datetime, flt
import datetime
from datetime import timedelta
@@ -120,7 +120,7 @@
create_communication(issue.name, "test@example.com", "Received", creation)
issue.reload()
- self.assertEqual(issue.total_hold_time, 2700)
+ self.assertEqual(flt(issue.total_hold_time, 2), 2700)
self.assertEqual(issue.resolution_by, datetime.datetime(2020, 3, 4, 16, 45))
creation = datetime.datetime(2020, 3, 4, 5, 5)
@@ -132,7 +132,7 @@
issue.save()
issue.reload()
- self.assertEqual(issue.total_hold_time, 2700)
+ self.assertEqual(flt(issue.total_hold_time, 2), 2700)
def make_issue(creation=None, customer=None, index=0):
diff --git a/erpnext/support/doctype/support_settings/support_settings.json b/erpnext/support/doctype/support_settings/support_settings.json
index 1c1b0c3..5d3d3ac 100644
--- a/erpnext/support/doctype/support_settings/support_settings.json
+++ b/erpnext/support/doctype/support_settings/support_settings.json
@@ -1,5 +1,5 @@
{
- "actions": [],
+ "actions": "",
"creation": "2017-02-17 13:07:35.686409",
"doctype": "DocType",
"editable_grid": 1,
@@ -22,6 +22,10 @@
"post_description_key",
"post_route_key",
"post_route_string",
+ "greetings_section_section",
+ "greeting_title",
+ "column_break_19",
+ "greeting_subtitle",
"search_apis_sb",
"search_apis"
],
@@ -127,11 +131,40 @@
"fieldname": "allow_resetting_service_level_agreement",
"fieldtype": "Check",
"label": "Allow Resetting Service Level Agreement"
+ },
+ {
+ "default": "We're here to help",
+ "fieldname": "greeting_title",
+ "fieldtype": "Data",
+ "label": "Greeting Title",
+ "show_days": 1,
+ "show_seconds": 1
+ },
+ {
+ "fieldname": "column_break_19",
+ "fieldtype": "Column Break",
+ "show_days": 1,
+ "show_seconds": 1
+ },
+ {
+ "default": "Browse help topics",
+ "fieldname": "greeting_subtitle",
+ "fieldtype": "Data",
+ "label": "Greeting Subtitle",
+ "show_days": 1,
+ "show_seconds": 1
+ },
+ {
+ "fieldname": "greetings_section_section",
+ "fieldtype": "Section Break",
+ "label": "Greetings Section",
+ "show_days": 1,
+ "show_seconds": 1
}
],
"issingle": 1,
"links": [],
- "modified": "2020-06-05 17:56:17.491684",
+ "modified": "2020-06-11 13:08:38.473616",
"modified_by": "Administrator",
"module": "Support",
"name": "Support Settings",
diff --git a/erpnext/templates/generators/item/item_configure.js b/erpnext/templates/generators/item/item_configure.js
index 5fd9011..163c955 100644
--- a/erpnext/templates/generators/item/item_configure.js
+++ b/erpnext/templates/generators/item/item_configure.js
@@ -193,14 +193,17 @@
filtered_items_count === 1 ?
filtered_items[0] : '';
+ // Allow Add to Cart if adding out of stock items enabled in Shopping Cart else check stock.
+ const in_stock = product_info.allow_items_not_in_stock ? 1 : product_info.in_stock;
+ const add_to_cart = `<a href data-action="btn_add_to_cart" data-item-code="${one_item}">${__('Add to cart')}</a>`;
+ const product_action = in_stock ? add_to_cart : `<a style="color:#74808b;">${__('Not in Stock')}</a>`;
+
const item_add_to_cart = one_item ? `
<div class="alert alert-success d-flex justify-content-between align-items-center" role="alert">
<div>
<div>${one_item} ${product_info && product_info.price ? '(' + product_info.price.formatted_price_sales_uom + ')' : ''}</div>
</div>
- <a href data-action="btn_add_to_cart" data-item-code="${one_item}">
- ${__('Add to cart')}
- </a>
+ ${product_action}
</div>
`: '';
diff --git a/erpnext/templates/generators/student_admission.html b/erpnext/templates/generators/student_admission.html
index ae70df8..8b15344 100644
--- a/erpnext/templates/generators/student_admission.html
+++ b/erpnext/templates/generators/student_admission.html
@@ -14,12 +14,12 @@
{%- if introduction -%}
<div>{{ introduction }}</div>
-{% endif %}
+{% endif %}
-{%- if application_form_route -%}
+{%- if doc.enable_admission_application -%}
<p>
<a class='btn btn-primary'
- href='/{{ doc.application_form_route }}'>
+ href='/student-applicant'>
{{ _("Apply Now") }}</a>
</p>
{% endif %}
diff --git a/erpnext/templates/includes/cart/address_card.html b/erpnext/templates/includes/cart/address_card.html
index c91723e..646210e 100644
--- a/erpnext/templates/includes/cart/address_card.html
+++ b/erpnext/templates/includes/cart/address_card.html
@@ -3,7 +3,7 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-check"><polyline points="20 6 9 17 4 12"></polyline></svg>
</div>
<div class="card-body">
- <h5 class="card-title">{{ address.name }}</h5>
+ <h5 class="card-title">{{ address.title }}</h5>
<p class="card-text text-muted">
{{ address.display }}
</p>
diff --git a/erpnext/templates/includes/cart/cart_address.html b/erpnext/templates/includes/cart/cart_address.html
index 60de3af..aa25c88 100644
--- a/erpnext/templates/includes/cart/cart_address.html
+++ b/erpnext/templates/includes/cart/cart_address.html
@@ -109,7 +109,7 @@
reqd: 1
},
{
- label: __('Pin Code'),
+ label: __('Postal Code'),
fieldname: 'pincode',
fieldtype: 'Data'
},
diff --git a/erpnext/www/support/__init__.py b/erpnext/www/support/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/www/support/__init__.py
diff --git a/erpnext/www/support/index.html b/erpnext/www/support/index.html
new file mode 100644
index 0000000..93da503
--- /dev/null
+++ b/erpnext/www/support/index.html
@@ -0,0 +1,58 @@
+{% extends "templates/web.html" %}
+
+{% block content %}
+<section class="section section-padding-top section-padding-bottom">
+ <div class='container'>
+ <div class="hero-content">
+ <h1 class="hero-title">{{ greeting_title or _("We're here to help!") }}</h1>
+ {% if greeting_subtitle %}
+ <p class="hero-subtitle">{{ greeting_subtitle }}</p>
+ {% endif %}
+ </div>
+ </div>
+</section>
+
+{% if favorite_article_list %}
+<section class="section section-padding-top section-padding-bottom bg-light">
+ <div class='container'>
+ <h2>{{ _("Frequently Read Articles") }}</h2>
+ <div class="row">
+ {% for favorite_article in favorite_article_list %}
+ <div class="mt-4 col-12 col-sm-6 col-lg-4">
+ <div class="card card-md h-100 kb-card">
+ <div class="card-body">
+ <h6 class="card-subtitle mb-2 text-uppercase small text-muted">
+ {{ favorite_article['category'] }}</h6>
+ <h3 class="card-title">{{ favorite_article['title'] }}</h3>
+ <p class="card-text">{{ favorite_article['description'] }}</p>
+ </div>
+ <a href="{{ favorite_article['route'] }}" class="stretched-link"></a>
+ </div>
+ </div>
+ {% endfor %}
+ </div>
+ </div>
+</section>
+{% endif %}
+
+{% if help_article_list %}
+<section class="section section-padding-top section-padding-bottom">
+ <div class='container'>
+ <h2>{{ _("Help Articles") }}</h2>
+ <div class="row">
+ {% for item in help_article_list %}
+ <div class="mt-5 col-12 col-sm-6 col-lg-4">
+ <h5>{{ item['category'].name }}</h5>
+ <div>
+ {% for article in item['articles'] %}
+ <a href="{{ article.route }}" class="mt-2 d-block">{{ article.title }}</a>
+ {% endfor %}
+ </div>
+ </div>
+ {% endfor %}
+ </div>
+ </div>
+</section>
+{% endif %}
+
+{% endblock %}
\ No newline at end of file
diff --git a/erpnext/www/support/index.py b/erpnext/www/support/index.py
new file mode 100644
index 0000000..5d26743
--- /dev/null
+++ b/erpnext/www/support/index.py
@@ -0,0 +1,74 @@
+from __future__ import unicode_literals
+import frappe
+
+def get_context(context):
+ context.no_cache = 1
+ context.align_greeting = ''
+ setting = frappe.get_doc("Support Settings")
+
+ context.greeting_title = setting.greeting_title
+ context.greeting_subtitle = setting.greeting_subtitle
+
+ # Support content
+ favorite_articles = get_favorite_articles_by_page_view()
+ if len(favorite_articles) < 6:
+ name_list = []
+ if favorite_articles:
+ for article in favorite_articles:
+ name_list.append(article.name)
+ for record in (frappe.get_all("Help Article",
+ fields=["title", "content", "route", "category"],
+ filters={"name": ['not in', tuple(name_list)], "published": 1},
+ order_by="creation desc", limit=(6-len(favorite_articles)))):
+ favorite_articles.append(record)
+
+ context.favorite_article_list = get_favorite_articles(favorite_articles)
+ context.help_article_list = get_help_article_list()
+
+def get_favorite_articles_by_page_view():
+ return frappe.db.sql(
+ """
+ SELECT
+ t1.name as name,
+ t1.title as title,
+ t1.content as content,
+ t1.route as route,
+ t1.category as category,
+ count(t1.route) as count
+ FROM `tabHelp Article` AS t1
+ INNER JOIN
+ `tabWeb Page View` AS t2
+ ON t1.route = t2.path
+ WHERE t1.published = 1
+ GROUP BY route
+ ORDER BY count DESC
+ LIMIT 6;
+ """, as_dict=True)
+
+def get_favorite_articles(favorite_articles):
+ favorite_article_list=[]
+ for article in favorite_articles:
+ description = frappe.utils.strip_html(article.content)
+ if len(description) > 120:
+ description = description[:120] + '...'
+ favorite_article_dict = {
+ 'title': article.title,
+ 'description': description,
+ 'route': article.route,
+ 'category': article.category,
+ }
+ favorite_article_list.append(favorite_article_dict)
+ return favorite_article_list
+
+def get_help_article_list():
+ help_article_list=[]
+ category_list = frappe.get_all("Help Category", fields="name")
+ for category in category_list:
+ help_articles = frappe.get_all("Help Article", fields="*", filters={"category": category.name, "published": 1}, order_by="modified desc", limit=5)
+ if help_articles:
+ help_aricles_per_caetgory = {
+ 'category': category,
+ 'articles': help_articles,
+ }
+ help_article_list.append(help_aricles_per_caetgory)
+ return help_article_list
\ No newline at end of file