Merge branch 'develop' into rfq-multi-uom

This commit is contained in:
Marica 2020-06-18 14:44:46 +05:30 committed by GitHub
commit d6906dccfe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
39 changed files with 709 additions and 862 deletions

View File

@ -11,4 +11,4 @@ jobs:
- name: curl - name: curl
run: | run: |
apk add curl bash 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

View File

@ -146,7 +146,7 @@
"idx": 1, "idx": 1,
"is_tree": 1, "is_tree": 1,
"links": [], "links": [],
"modified": "2020-04-29 16:09:30.025214", "modified": "2020-06-17 16:09:30.025214",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Cost Center", "name": "Cost Center",

View File

@ -102,7 +102,7 @@ def validate_item_attribute_value(attributes_list, attribute, attribute_value, i
frappe.throw(_("{0} is not a valid Value for Attribute {1} of Item {2}.").format( 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")) frappe.bold(attribute_value), frappe.bold(attribute), frappe.bold(item)), InvalidItemAttributeValueError, title=_("Invalid Value"))
else: 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)) 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")) msg += "<br>" + _("To still proceed with editing this Attribute Value, enable {0} in Item Variant Settings.").format(frappe.bold("Allow Rename Attribute Value"))

View File

@ -227,7 +227,9 @@ class StockController(AccountsController):
def check_expense_account(self, item): def check_expense_account(self, item):
if not item.get("expense_account"): 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: else:
is_expense_account = frappe.db.get_value("Account", is_expense_account = frappe.db.get_value("Account",

View File

@ -9,6 +9,14 @@ frappe.ui.form.on('Fee Structure', {
}, },
onload: function(frm) { onload: function(frm) {
frm.set_query("academic_term", function() {
return {
"filters": {
"academic_year": frm.doc.academic_year
}
};
});
frm.set_query("receivable_account", function(doc) { frm.set_query("receivable_account", function(doc) {
return { return {
filters: { filters: {

View File

@ -1,4 +1,5 @@
{ {
"actions": [],
"allow_import": 1, "allow_import": 1,
"allow_rename": 1, "allow_rename": 1,
"autoname": "naming_series:", "autoname": "naming_series:",
@ -11,8 +12,8 @@
"program", "program",
"student_category", "student_category",
"column_break_2", "column_break_2",
"academic_term",
"academic_year", "academic_year",
"academic_term",
"section_break_4", "section_break_4",
"components", "components",
"section_break_6", "section_break_6",
@ -157,7 +158,8 @@
], ],
"icon": "fa fa-flag", "icon": "fa fa-flag",
"is_submittable": 1, "is_submittable": 1,
"modified": "2019-05-26 09:04:17.765758", "links": [],
"modified": "2020-06-16 15:34:57.295010",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Education", "module": "Education",
"name": "Fee Structure", "name": "Fee Structure",

View File

@ -1,398 +1,119 @@
{ {
"allow_copy": 0, "actions": [],
"allow_guest_to_view": 1, "allow_guest_to_view": 1,
"allow_import": 0, "allow_rename": 1,
"allow_rename": 1, "creation": "2016-09-13 03:05:27.154713",
"autoname": "", "doctype": "DocType",
"beta": 0, "document_type": "Document",
"creation": "2016-09-13 03:05:27.154713", "editable_grid": 1,
"custom": 0, "engine": "InnoDB",
"docstatus": 0, "field_order": [
"doctype": "DocType", "title",
"document_type": "Document", "route",
"editable_grid": 1, "column_break_3",
"academic_year",
"admission_start_date",
"admission_end_date",
"published",
"enable_admission_application",
"section_break_5",
"program_details",
"introduction"
],
"fields": [ "fields": [
{ {
"allow_bulk_edit": 0, "fieldname": "title",
"allow_on_submit": 0, "fieldtype": "Data",
"bold": 0, "label": "Title"
"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
},
{ {
"allow_bulk_edit": 0, "fieldname": "route",
"allow_on_submit": 0, "fieldtype": "Data",
"bold": 0, "label": "Route",
"collapsible": 0, "no_copy": 1,
"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,
"unique": 1 "unique": 1
}, },
{ {
"allow_bulk_edit": 0, "fieldname": "column_break_3",
"allow_on_submit": 0, "fieldtype": "Column Break"
"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
},
{ {
"allow_bulk_edit": 0, "fieldname": "academic_year",
"allow_on_submit": 0, "fieldtype": "Link",
"bold": 0, "in_list_view": 1,
"collapsible": 0, "in_standard_filter": 1,
"columns": 0, "label": "Academic Year",
"fieldname": "column_break_3", "no_copy": 1,
"fieldtype": "Column Break", "options": "Academic Year",
"hidden": 0, "reqd": 1
"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
},
{ {
"allow_bulk_edit": 0, "fieldname": "admission_start_date",
"allow_on_submit": 0, "fieldtype": "Date",
"bold": 0, "label": "Admission Start Date",
"collapsible": 0, "no_copy": 1
"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
},
{ {
"allow_bulk_edit": 0, "fieldname": "admission_end_date",
"allow_on_submit": 0, "fieldtype": "Date",
"bold": 0, "label": "Admission End Date",
"collapsible": 0, "no_copy": 1
"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
},
{ {
"allow_bulk_edit": 0, "default": "0",
"allow_on_submit": 0, "fieldname": "published",
"bold": 0, "fieldtype": "Check",
"collapsible": 0, "label": "Publish on website"
"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
},
{ {
"allow_bulk_edit": 0, "fieldname": "section_break_5",
"allow_on_submit": 0, "fieldtype": "Section Break",
"bold": 0, "label": "Eligibility and Details"
"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
},
{ {
"allow_bulk_edit": 0, "fieldname": "program_details",
"allow_on_submit": 0, "fieldtype": "Table",
"bold": 0, "label": "Eligibility and Details",
"collapsible": 0, "options": "Student Admission Program"
"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
},
{ {
"allow_bulk_edit": 0, "fieldname": "introduction",
"allow_on_submit": 0, "fieldtype": "Text Editor",
"bold": 0, "label": "Introduction"
"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
},
{ {
"allow_bulk_edit": 0, "default": "0",
"allow_on_submit": 0, "fieldname": "enable_admission_application",
"bold": 0, "fieldtype": "Check",
"collapsible": 0, "label": "Enable Admission Application"
"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
} }
], ],
"has_web_view": 1, "has_web_view": 1,
"hide_heading": 0, "is_published_field": "published",
"hide_toolbar": 0, "links": [],
"idx": 0, "modified": "2020-06-15 20:18:38.591626",
"image_view": 0, "modified_by": "Administrator",
"in_create": 0, "module": "Education",
"is_published_field": "published", "name": "Student Admission",
"is_submittable": 0, "owner": "Administrator",
"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",
"permissions": [ "permissions": [
{ {
"amend": 0, "create": 1,
"apply_user_permissions": 0, "delete": 1,
"cancel": 0, "email": 1,
"create": 1, "export": 1,
"delete": 1, "print": 1,
"email": 1, "read": 1,
"export": 1, "report": 1,
"if_owner": 0, "role": "Academics User",
"import": 0, "share": 1,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Academics User",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1 "write": 1
} }
], ],
"quick_entry": 0, "restrict_to_domain": "Education",
"read_only": 0, "route": "admissions",
"read_only_onload": 0, "show_name_in_global_search": 1,
"restrict_to_domain": "Education", "sort_field": "modified",
"route": "admissions", "sort_order": "DESC",
"show_name_in_global_search": 1, "title_field": "title"
"sort_field": "modified",
"sort_order": "DESC",
"title_field": "title",
"track_changes": 0,
"track_seen": 0
} }

View File

@ -43,8 +43,8 @@
<thead> <thead>
<tr class="active"> <tr class="active">
<th style="width: 90px">Program/Std.</th> <th style="width: 90px">Program/Std.</th>
<th style="width: 170px">Minumum Age(DOB)</th> <th style="width: 170px">Minumum Age</th>
<th style="width: 170px">Maximum Age(DOB)</th> <th style="width: 170px">Maximum Age</th>
<th style="width: 100px">Application Fee</th> <th style="width: 100px">Application Fee</th>
</tr> </tr>
</thead> </thead>
@ -52,8 +52,8 @@
{% for row in program_details %} {% for row in program_details %}
<tr> <tr>
<td>{{ row.program }}</td> <td>{{ row.program }}</td>
<td>{{ row.minimum_age }}</td> <td>{{ row.min_age }}</td>
<td>{{ row.maximum_age }}</td> <td>{{ row.max_age }}</td>
<td>{{ row.application_fee }}</td> <td>{{ row.application_fee }}</td>
</tr> </tr>
{% endfor %} {% endfor %}
@ -61,12 +61,11 @@
</table> </table>
</div> </div>
{% endif %} {% endif %}
{%- if doc.enable_admission_application -%}
{%- if application_form_route -%}
<br> <br>
<p> <p>
<a class='btn btn-primary' <a class='btn btn-primary'
href='/{{ doc.application_form_route }}?new=1'> href='/student-applicant?new=1&student_admission={{doc.name}}'>
{{ _("Apply Now") }}</a> {{ _("Apply Now") }}</a>
</p> </p>
{% endif %} {% endif %}

View File

@ -11,7 +11,7 @@ QUnit.test('Test: Student Admission', function(assert) {
{admission_start_date: '2016-04-20'}, {admission_start_date: '2016-04-20'},
{admission_end_date: '2016-05-31'}, {admission_end_date: '2016-05-31'},
{title: '2016-17 Admissions'}, {title: '2016-17 Admissions'},
{application_form_route: 'student-applicant'}, {enable_admission_application: 1},
{introduction: 'Test intro'}, {introduction: 'Test intro'},
{program_details: [ {program_details: [
[ [
@ -28,7 +28,7 @@ QUnit.test('Test: Student Admission', function(assert) {
assert.ok(cur_frm.doc.admission_start_date == '2016-04-20'); 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.admission_end_date == '2016-05-31');
assert.ok(cur_frm.doc.title == '2016-17 Admissions'); 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.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].program == 'Standard Test', 'Program correctly selected');
assert.ok(cur_frm.doc.program_details[0].application_fee == 1000); assert.ok(cur_frm.doc.program_details[0].application_fee == 1000);

View File

@ -1,237 +1,77 @@
{ {
"allow_copy": 0, "actions": [],
"allow_events_in_timeline": 0, "creation": "2017-09-15 12:59:43.207923",
"allow_guest_to_view": 0, "doctype": "DocType",
"allow_import": 0, "editable_grid": 1,
"allow_rename": 0, "engine": "InnoDB",
"autoname": "", "field_order": [
"beta": 0, "program",
"creation": "2017-09-15 12:59:43.207923", "min_age",
"custom": 0, "max_age",
"docstatus": 0, "column_break_4",
"doctype": "DocType", "application_fee",
"document_type": "", "applicant_naming_series"
"editable_grid": 1, ],
"engine": "InnoDB",
"fields": [ "fields": [
{ {
"allow_bulk_edit": 0, "fieldname": "program",
"allow_in_quick_entry": 0, "fieldtype": "Link",
"allow_on_submit": 0, "in_list_view": 1,
"bold": 0, "label": "Program",
"collapsible": 0, "options": "Program",
"columns": 0, "show_days": 1,
"fieldname": "program", "show_seconds": 1
"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
},
{ {
"allow_bulk_edit": 0, "fieldname": "column_break_4",
"allow_in_quick_entry": 0, "fieldtype": "Column Break",
"allow_on_submit": 0, "show_days": 1,
"bold": 0, "show_seconds": 1
"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
},
{ {
"allow_bulk_edit": 0, "fieldname": "application_fee",
"allow_in_quick_entry": 0, "fieldtype": "Currency",
"allow_on_submit": 0, "in_list_view": 1,
"bold": 0, "label": "Application Fee",
"collapsible": 0, "show_days": 1,
"columns": 0, "show_seconds": 1
"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
},
{ {
"allow_bulk_edit": 0, "fieldname": "applicant_naming_series",
"allow_in_quick_entry": 0, "fieldtype": "Data",
"allow_on_submit": 0, "in_list_view": 1,
"bold": 0, "label": "Naming Series (for Student Applicant)",
"collapsible": 0, "show_days": 1,
"columns": 0, "show_seconds": 1
"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
},
{ {
"allow_bulk_edit": 0, "fieldname": "min_age",
"allow_in_quick_entry": 0, "fieldtype": "Int",
"allow_on_submit": 0, "in_list_view": 1,
"bold": 0, "label": "Minimum Age",
"collapsible": 0, "show_days": 1,
"columns": 0, "show_seconds": 1
"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
},
{ {
"allow_bulk_edit": 0, "fieldname": "max_age",
"allow_in_quick_entry": 0, "fieldtype": "Int",
"allow_on_submit": 0, "in_list_view": 1,
"bold": 0, "label": "Maximum Age",
"collapsible": 0, "show_days": 1,
"columns": 0, "show_seconds": 1
"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
} }
], ],
"has_web_view": 0, "istable": 1,
"hide_heading": 0, "links": [],
"hide_toolbar": 0, "modified": "2020-06-10 23:06:30.037404",
"idx": 0, "modified_by": "Administrator",
"image_view": 0, "module": "Education",
"in_create": 0, "name": "Student Admission Program",
"is_submittable": 0, "owner": "Administrator",
"issingle": 0, "permissions": [],
"istable": 1, "quick_entry": 1,
"max_attachments": 0, "restrict_to_domain": "Education",
"modified": "2018-11-04 03:37:17.408427", "sort_field": "modified",
"modified_by": "Administrator", "sort_order": "DESC",
"module": "Education", "track_changes": 1
"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
} }

View File

@ -6,7 +6,7 @@ from __future__ import print_function, unicode_literals
import frappe import frappe
from frappe import _ from frappe import _
from frappe.model.document import Document from frappe.model.document import Document
from frappe.utils import getdate from frappe.utils import getdate, add_years, nowdate, date_diff
class StudentApplicant(Document): class StudentApplicant(Document):
def autoname(self): def autoname(self):
@ -31,6 +31,7 @@ class StudentApplicant(Document):
def validate(self): def validate(self):
self.validate_dates() self.validate_dates()
self.title = " ".join(filter(None, [self.first_name, self.middle_name, self.last_name])) 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: if self.student_admission and self.program and self.date_of_birth:
self.validation_from_student_admission() self.validation_from_student_admission()
@ -48,16 +49,16 @@ class StudentApplicant(Document):
frappe.throw(_("Please select Student Admission which is mandatory for the paid student applicant")) frappe.throw(_("Please select Student Admission which is mandatory for the paid student applicant"))
def validation_from_student_admission(self): def validation_from_student_admission(self):
student_admission = get_student_admission_data(self.student_admission, self.program) 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.min_age and \
if student_admission and student_admission.minimum_age and \ date_diff(nowdate(), add_years(getdate(self.date_of_birth), student_admission.min_age)) < 0:
getdate(student_admission.minimum_age) < getdate(self.date_of_birth): frappe.throw(_("Not eligible for the admission in this program as per 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 \ if student_admission and student_admission.max_age and \
getdate(student_admission.maximum_age) > getdate(self.date_of_birth): 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 DOB")) frappe.throw(_("Not eligible for the admission in this program as per Date Of Birth"))
def on_payment_authorized(self, *args, **kwargs): def on_payment_authorized(self, *args, **kwargs):
@ -65,10 +66,12 @@ class StudentApplicant(Document):
def get_student_admission_data(student_admission, program): def get_student_admission_data(student_admission, program):
student_admission = frappe.db.sql("""select sa.admission_start_date, sa.admission_end_date, 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 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) where sa.name = sap.parent and sa.name = %s and sap.program = %s""", (student_admission, program), as_dict=1)
if student_admission: if student_admission:
return student_admission[0] return student_admission[0]
else: else:

View File

@ -1,200 +1,248 @@
{ {
"accept_payment": 0, "accept_payment": 0,
"allow_comments": 0, "allow_comments": 0,
"allow_delete": 0, "allow_delete": 0,
"allow_edit": 1, "allow_edit": 1,
"allow_incomplete": 0, "allow_incomplete": 0,
"allow_multiple": 1, "allow_multiple": 1,
"allow_print": 0, "allow_print": 0,
"amount": 0.0, "amount": 0.0,
"amount_based_on_field": 0, "amount_based_on_field": 0,
"creation": "2016-09-22 13:10:10.792735", "creation": "2016-09-22 13:10:10.792735",
"doc_type": "Student Applicant", "doc_type": "Student Applicant",
"docstatus": 0, "docstatus": 0,
"doctype": "Web Form", "doctype": "Web Form",
"idx": 0, "idx": 0,
"is_standard": 1, "is_standard": 1,
"login_required": 1, "login_required": 1,
"max_attachment_size": 0, "max_attachment_size": 0,
"modified": "2017-02-21 05:44:46.022738", "modified": "2020-06-11 22:53:45.875310",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Education", "module": "Education",
"name": "student-applicant", "name": "student-applicant",
"owner": "Administrator", "owner": "Administrator",
"payment_button_label": "Buy Now", "payment_button_label": "Buy Now",
"published": 1, "published": 1,
"route": "student-applicant", "route": "student-applicant",
"show_sidebar": 1, "route_to_success_link": 0,
"sidebar_items": [], "show_attachments": 0,
"success_url": "/student-applicant", "show_in_grid": 0,
"title": "Student Applicant", "show_sidebar": 1,
"sidebar_items": [],
"success_url": "/student-applicant",
"title": "Student Applicant",
"web_form_fields": [ "web_form_fields": [
{ {
"fieldname": "first_name", "allow_read_on_all_link_options": 0,
"fieldtype": "Data", "fieldname": "first_name",
"hidden": 0, "fieldtype": "Data",
"label": "First Name", "hidden": 0,
"max_length": 0, "label": "First Name",
"max_value": 0, "max_length": 0,
"read_only": 0, "max_value": 0,
"reqd": 1 "read_only": 0,
}, "reqd": 1,
"show_in_filter": 0
},
{ {
"fieldname": "middle_name", "allow_read_on_all_link_options": 0,
"fieldtype": "Data", "fieldname": "middle_name",
"hidden": 0, "fieldtype": "Data",
"label": "Middle Name", "hidden": 0,
"max_length": 0, "label": "Middle Name",
"max_value": 0, "max_length": 0,
"read_only": 0, "max_value": 0,
"reqd": 0 "read_only": 0,
}, "reqd": 0,
"show_in_filter": 0
},
{ {
"fieldname": "last_name", "allow_read_on_all_link_options": 0,
"fieldtype": "Data", "fieldname": "last_name",
"hidden": 0, "fieldtype": "Data",
"label": "Last Name", "hidden": 0,
"max_length": 0, "label": "Last Name",
"max_value": 0, "max_length": 0,
"read_only": 0, "max_value": 0,
"reqd": 0 "read_only": 0,
}, "reqd": 0,
"show_in_filter": 0
},
{ {
"fieldname": "image", "allow_read_on_all_link_options": 0,
"fieldtype": "Data", "fieldname": "image",
"hidden": 0, "fieldtype": "Data",
"label": "Image", "hidden": 0,
"max_length": 0, "label": "Image",
"max_value": 0, "max_length": 0,
"read_only": 0, "max_value": 0,
"reqd": 0 "read_only": 0,
}, "reqd": 0,
"show_in_filter": 0
},
{ {
"fieldname": "program", "allow_read_on_all_link_options": 0,
"fieldtype": "Link", "fieldname": "program",
"hidden": 0, "fieldtype": "Link",
"label": "Program", "hidden": 0,
"max_length": 0, "label": "Program",
"max_value": 0, "max_length": 0,
"options": "Program", "max_value": 0,
"read_only": 0, "options": "Program",
"reqd": 1 "read_only": 0,
}, "reqd": 1,
"show_in_filter": 0
},
{ {
"fieldname": "academic_year", "allow_read_on_all_link_options": 0,
"fieldtype": "Link", "fieldname": "academic_year",
"hidden": 0, "fieldtype": "Link",
"label": "Academic Year", "hidden": 0,
"max_length": 0, "label": "Academic Year",
"max_value": 0, "max_length": 0,
"options": "Academic Year", "max_value": 0,
"read_only": 0, "options": "Academic Year",
"reqd": 0 "read_only": 0,
}, "reqd": 0,
"show_in_filter": 0
},
{ {
"fieldname": "date_of_birth", "allow_read_on_all_link_options": 0,
"fieldtype": "Date", "fieldname": "date_of_birth",
"hidden": 0, "fieldtype": "Date",
"label": "Date of Birth", "hidden": 0,
"max_length": 0, "label": "Date of Birth",
"max_value": 0, "max_length": 0,
"read_only": 0, "max_value": 0,
"reqd": 0 "read_only": 0,
}, "reqd": 0,
"show_in_filter": 0
},
{ {
"fieldname": "blood_group", "allow_read_on_all_link_options": 0,
"fieldtype": "Select", "fieldname": "blood_group",
"hidden": 0, "fieldtype": "Select",
"label": "Blood Group", "hidden": 0,
"max_length": 0, "label": "Blood Group",
"max_value": 0, "max_length": 0,
"options": "\nA+\nA-\nB+\nB-\nO+\nO-\nAB+\nAB-", "max_value": 0,
"read_only": 0, "options": "\nA+\nA-\nB+\nB-\nO+\nO-\nAB+\nAB-",
"reqd": 0 "read_only": 0,
}, "reqd": 0,
"show_in_filter": 0
},
{ {
"fieldname": "student_email_id", "allow_read_on_all_link_options": 0,
"fieldtype": "Data", "fieldname": "student_email_id",
"hidden": 0, "fieldtype": "Data",
"label": "Student Email ID", "hidden": 0,
"max_length": 0, "label": "Student Email ID",
"max_value": 0, "max_length": 0,
"read_only": 0, "max_value": 0,
"reqd": 0 "read_only": 0,
}, "reqd": 0,
"show_in_filter": 0
},
{ {
"fieldname": "student_mobile_number", "allow_read_on_all_link_options": 0,
"fieldtype": "Data", "fieldname": "student_mobile_number",
"hidden": 0, "fieldtype": "Data",
"label": "Student Mobile Number", "hidden": 0,
"max_length": 0, "label": "Student Mobile Number",
"max_value": 0, "max_length": 0,
"read_only": 0, "max_value": 0,
"reqd": 0 "read_only": 0,
}, "reqd": 0,
"show_in_filter": 0
},
{ {
"default": "INDIAN", "allow_read_on_all_link_options": 0,
"fieldname": "nationality", "default": "INDIAN",
"fieldtype": "Data", "fieldname": "nationality",
"hidden": 0, "fieldtype": "Data",
"label": "Nationality", "hidden": 0,
"max_length": 0, "label": "Nationality",
"max_value": 0, "max_length": 0,
"options": "", "max_value": 0,
"read_only": 0, "options": "",
"reqd": 0 "read_only": 0,
}, "reqd": 0,
"show_in_filter": 0
},
{ {
"fieldname": "address_line_1", "allow_read_on_all_link_options": 0,
"fieldtype": "Data", "fieldname": "address_line_1",
"hidden": 0, "fieldtype": "Data",
"label": "Address Line 1", "hidden": 0,
"max_length": 0, "label": "Address Line 1",
"max_value": 0, "max_length": 0,
"read_only": 0, "max_value": 0,
"reqd": 0 "read_only": 0,
}, "reqd": 0,
"show_in_filter": 0
},
{ {
"fieldname": "address_line_2", "allow_read_on_all_link_options": 0,
"fieldtype": "Data", "fieldname": "address_line_2",
"hidden": 0, "fieldtype": "Data",
"label": "Address Line 2", "hidden": 0,
"max_length": 0, "label": "Address Line 2",
"max_value": 0, "max_length": 0,
"read_only": 0, "max_value": 0,
"reqd": 0 "read_only": 0,
}, "reqd": 0,
"show_in_filter": 0
},
{ {
"fieldname": "pincode", "allow_read_on_all_link_options": 0,
"fieldtype": "Data", "fieldname": "pincode",
"hidden": 0, "fieldtype": "Data",
"label": "Pincode", "hidden": 0,
"max_length": 0, "label": "Pincode",
"max_value": 0, "max_length": 0,
"read_only": 0, "max_value": 0,
"reqd": 0 "read_only": 0,
}, "reqd": 0,
"show_in_filter": 0
},
{ {
"fieldname": "guardians", "allow_read_on_all_link_options": 0,
"fieldtype": "Table", "fieldname": "guardians",
"hidden": 0, "fieldtype": "Table",
"label": "Guardians", "hidden": 0,
"max_length": 0, "label": "Guardians",
"max_value": 0, "max_length": 0,
"options": "Student Guardian", "max_value": 0,
"read_only": 0, "options": "Student Guardian",
"reqd": 0 "read_only": 0,
}, "reqd": 0,
"show_in_filter": 0
},
{ {
"fieldname": "siblings", "allow_read_on_all_link_options": 0,
"fieldtype": "Table", "fieldname": "siblings",
"hidden": 0, "fieldtype": "Table",
"label": "Siblings", "hidden": 0,
"max_length": 0, "label": "Siblings",
"max_value": 0, "max_length": 0,
"options": "Student Sibling", "max_value": 0,
"read_only": 0, "options": "Student Sibling",
"reqd": 0 "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
} }
] ]
} }

View File

@ -8,6 +8,7 @@ import json
from frappe import _ from frappe import _
from frappe.model.document import Document from frappe.model.document import Document
from frappe.utils import get_request_session 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 frappe.custom.doctype.custom_field.custom_field import create_custom_fields
from erpnext.erpnext_integrations.utils import get_webhook_address from erpnext.erpnext_integrations.utils import get_webhook_address
from erpnext.erpnext_integrations.doctype.shopify_log.shopify_log import make_shopify_log from erpnext.erpnext_integrations.doctype.shopify_log.shopify_log import make_shopify_log
@ -29,19 +30,24 @@ class ShopifySettings(Document):
webhooks = ["orders/create", "orders/paid", "orders/fulfilled"] webhooks = ["orders/create", "orders/paid", "orders/fulfilled"]
# url = get_shopify_url('admin/webhooks.json', self) # url = get_shopify_url('admin/webhooks.json', self)
created_webhooks = [d.method for d in self.webhooks] 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: for method in webhooks:
session = get_request_session() session = get_request_session()
try: try:
d = session.post(url, data=json.dumps({ res = session.post(url, data=json.dumps({
"webhook": { "webhook": {
"topic": method, "topic": method,
"address": get_webhook_address(connector_name='shopify_connection', method='store_request_data'), "address": get_webhook_address(connector_name='shopify_connection', method='store_request_data'),
"format": "json" "format": "json"
} }
}), headers=get_header(self)) }), headers=get_header(self))
d.raise_for_status() res.raise_for_status()
self.update_webhook_table(method, d.json()) 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: except Exception as e:
make_shopify_log(status="Warning", exception=e, rollback=True) make_shopify_log(status="Warning", exception=e, rollback=True)
@ -50,13 +56,18 @@ class ShopifySettings(Document):
deleted_webhooks = [] deleted_webhooks = []
for d in self.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: try:
res = session.delete(url, headers=get_header(self)) res = session.delete(url, headers=get_header(self))
res.raise_for_status() res.raise_for_status()
deleted_webhooks.append(d) 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: 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: for d in deleted_webhooks:
self.remove(d) self.remove(d)
@ -125,4 +136,3 @@ def setup_custom_fields():
} }
create_custom_fields(custom_fields) create_custom_fields(custom_fields)

View File

@ -8,7 +8,7 @@ from erpnext.erpnext_integrations.doctype.shopify_settings.shopify_settings impo
shopify_variants_attr_list = ["option1", "option2", "option3"] shopify_variants_attr_list = ["option1", "option2", "option3"]
def sync_item_from_shopify(shopify_settings, item): 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() session = get_request_session()
try: try:

View File

@ -70,6 +70,7 @@ def validate_service_item(item, msg):
if frappe.db.get_value('Item', item, 'is_stock_item'): if frappe.db.get_value('Item', item, 'is_stock_item'):
frappe.throw(_(msg)) frappe.throw(_(msg))
@frappe.whitelist()
def get_practitioner_list(doctype, txt, searchfield, start, page_len, filters=None): def get_practitioner_list(doctype, txt, searchfield, start, page_len, filters=None):
fields = ['name', 'practitioner_name', 'mobile_phone'] fields = ['name', 'practitioner_name', 'mobile_phone']

View File

@ -93,7 +93,7 @@
"idx": 0, "idx": 0,
"is_standard": 1, "is_standard": 1,
"label": "HR", "label": "HR",
"modified": "2020-06-10 12:41:41.695669", "modified": "2020-06-16 19:20:50.976045",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "HR", "module": "HR",
"name": "HR", "name": "HR",
@ -126,7 +126,7 @@
}, },
{ {
"label": "Salary Structure", "label": "Salary Structure",
"link_to": "Payroll Entry", "link_to": "Salary Structure",
"type": "DocType" "type": "DocType"
}, },
{ {

View File

@ -119,6 +119,7 @@ class BOM(WebsiteGenerator):
"description": d.description, "description": d.description,
"time_in_mins": d.time_in_mins, "time_in_mins": d.time_in_mins,
"batch_size": d.batch_size, "batch_size": d.batch_size,
"operating_cost": d.operating_cost,
"idx": d.idx "idx": d.idx
}) })
child.hour_rate = flt(d.hour_rate / self.conversion_rate, 2) child.hour_rate = flt(d.hour_rate / self.conversion_rate, 2)

View File

@ -78,6 +78,7 @@
"read_only": 1 "read_only": 1
}, },
{ {
"depends_on": "eval:parent.doctype == 'BOM'",
"fieldname": "base_hour_rate", "fieldname": "base_hour_rate",
"fieldtype": "Currency", "fieldtype": "Currency",
"label": "Base Hour Rate(Company Currency)", "label": "Base Hour Rate(Company Currency)",
@ -87,6 +88,7 @@
}, },
{ {
"default": "5", "default": "5",
"depends_on": "eval:parent.doctype == 'BOM'",
"fieldname": "base_operating_cost", "fieldname": "base_operating_cost",
"fieldtype": "Currency", "fieldtype": "Currency",
"label": "Operating Cost(Company Currency)", "label": "Operating Cost(Company Currency)",
@ -108,12 +110,12 @@
], ],
"idx": 1, "idx": 1,
"istable": 1, "istable": 1,
"modified": "2019-07-16 22:35:55.374037", "modified": "2020-06-16 17:01:11.128420",
"modified_by": "govindsmenokee@gmail.com", "modified_by": "Administrator",
"module": "Manufacturing", "module": "Manufacturing",
"name": "BOM Operation", "name": "BOM Operation",
"owner": "Administrator", "owner": "Administrator",
"permissions": [], "permissions": [],
"sort_field": "modified", "sort_field": "modified",
"sort_order": "DESC" "sort_order": "DESC"
} }

View File

@ -44,7 +44,6 @@ frappe.ui.form.on('BOM Operation', {
name: d.workstation name: d.workstation
}, },
callback: function (data) { 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); frappe.model.set_value(d.doctype, d.name, "hour_rate", data.message.hour_rate);
frm.events.calculate_operating_cost(frm, d); frm.events.calculate_operating_cost(frm, d);
} }

View File

@ -698,4 +698,5 @@ erpnext.patches.v12_0.update_uom_conversion_factor
erpnext.patches.v13_0.delete_old_purchase_reports erpnext.patches.v13_0.delete_old_purchase_reports
erpnext.patches.v12_0.set_italian_import_supplier_invoice_permissions erpnext.patches.v12_0.set_italian_import_supplier_invoice_permissions
erpnext.patches.v13_0.update_sla_enhancements 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 erpnext.patches.v12_0.set_multi_uom_in_rfq

View File

@ -6,4 +6,6 @@ import frappe
def execute(): def execute():
''' Move from due_advance_amount to pending_amount ''' ''' 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 ''')

View File

@ -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')

View File

@ -1,4 +1,5 @@
import frappe import frappe
from frappe.utils import cint
from erpnext.portal.product_configurator.item_variants_cache import ItemVariantsCacheManager from erpnext.portal.product_configurator.item_variants_cache import ItemVariantsCacheManager
def get_field_filter_data(): def get_field_filter_data():
@ -243,6 +244,8 @@ def get_next_attribute_and_values(item_code, selected_attributes):
else: else:
product_info = None product_info = None
product_info["allow_items_not_in_stock"] = cint(data.cart_settings.allow_items_not_in_stock)
return { return {
'next_attribute': next_attribute, 'next_attribute': next_attribute,
'valid_options_for_attributes': valid_options_for_attributes, 'valid_options_for_attributes': valid_options_for_attributes,

View File

@ -13,7 +13,7 @@ from erpnext.projects.doctype.timesheet.timesheet import make_salary_slip, make_
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
from erpnext.hr.doctype.salary_structure.test_salary_structure \ from erpnext.hr.doctype.salary_structure.test_salary_structure \
import make_salary_structure, create_salary_structure_assignment import make_salary_structure, create_salary_structure_assignment
from erpnext.hr.doctype.employee.test_employee import make_employee
class TestTimesheet(unittest.TestCase): class TestTimesheet(unittest.TestCase):
def setUp(self): def setUp(self):
@ -25,8 +25,10 @@ class TestTimesheet(unittest.TestCase):
def test_timesheet_billing_amount(self): def test_timesheet_billing_amount(self):
make_salary_structure_for_timesheet("_T-Employee-00001") emp = make_employee("test_employee_6@salary.com")
timesheet = make_timesheet("_T-Employee-00001", simulate=True, billable=1)
make_salary_structure_for_timesheet(emp)
timesheet = make_timesheet(emp, simulate=True, billable=1)
self.assertEqual(timesheet.total_hours, 2) self.assertEqual(timesheet.total_hours, 2)
self.assertEqual(timesheet.total_billable_hours, 2) self.assertEqual(timesheet.total_billable_hours, 2)
@ -35,8 +37,10 @@ class TestTimesheet(unittest.TestCase):
self.assertEqual(timesheet.total_billable_amount, 100) self.assertEqual(timesheet.total_billable_amount, 100)
def test_timesheet_billing_amount_not_billable(self): def test_timesheet_billing_amount_not_billable(self):
make_salary_structure_for_timesheet("_T-Employee-00001") emp = make_employee("test_employee_6@salary.com")
timesheet = make_timesheet("_T-Employee-00001", simulate=True, billable=0)
make_salary_structure_for_timesheet(emp)
timesheet = make_timesheet(emp, simulate=True, billable=0)
self.assertEqual(timesheet.total_hours, 2) self.assertEqual(timesheet.total_hours, 2)
self.assertEqual(timesheet.total_billable_hours, 0) self.assertEqual(timesheet.total_billable_hours, 0)
@ -45,8 +49,10 @@ class TestTimesheet(unittest.TestCase):
self.assertEqual(timesheet.total_billable_amount, 0) self.assertEqual(timesheet.total_billable_amount, 0)
def test_salary_slip_from_timesheet(self): def test_salary_slip_from_timesheet(self):
salary_structure = make_salary_structure_for_timesheet("_T-Employee-00001") emp = make_employee("test_employee_6@salary.com")
timesheet = make_timesheet("_T-Employee-00001", simulate = True, billable=1)
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 = make_salary_slip(timesheet.name)
salary_slip.submit() salary_slip.submit()
@ -65,7 +71,9 @@ class TestTimesheet(unittest.TestCase):
self.assertEqual(timesheet.status, 'Submitted') self.assertEqual(timesheet.status, 'Submitted')
def test_sales_invoice_from_timesheet(self): 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 = make_sales_invoice(timesheet.name, '_Test Item', '_Test Customer')
sales_invoice.due_date = nowdate() sales_invoice.due_date = nowdate()
sales_invoice.submit() sales_invoice.submit()
@ -80,7 +88,9 @@ class TestTimesheet(unittest.TestCase):
self.assertEqual(item.rate, 50.00) self.assertEqual(item.rate, 50.00)
def test_timesheet_billing_based_on_project(self): 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 = create_sales_invoice(do_not_save=True)
sales_invoice.project = '_Test Project' sales_invoice.project = '_Test Project'
sales_invoice.submit() sales_invoice.submit()
@ -90,6 +100,8 @@ class TestTimesheet(unittest.TestCase):
self.assertEqual(ts.time_logs[0].sales_invoice, sales_invoice.name) self.assertEqual(ts.time_logs[0].sales_invoice, sales_invoice.name)
def test_timesheet_time_overlap(self): def test_timesheet_time_overlap(self):
emp = make_employee("test_employee_6@salary.com")
settings = frappe.get_single('Projects Settings') settings = frappe.get_single('Projects Settings')
initial_setting = settings.ignore_employee_time_overlap initial_setting = settings.ignore_employee_time_overlap
settings.ignore_employee_time_overlap = 0 settings.ignore_employee_time_overlap = 0
@ -97,7 +109,7 @@ class TestTimesheet(unittest.TestCase):
update_activity_type("_Test Activity Type") update_activity_type("_Test Activity Type")
timesheet = frappe.new_doc("Timesheet") timesheet = frappe.new_doc("Timesheet")
timesheet.employee = "_T-Employee-00001" timesheet.employee = emp
timesheet.append( timesheet.append(
'time_logs', 'time_logs',
{ {
@ -129,12 +141,14 @@ class TestTimesheet(unittest.TestCase):
settings.save() settings.save()
def test_timesheet_std_working_hours(self): def test_timesheet_std_working_hours(self):
emp = make_employee("test_employee_6@salary.com")
company = frappe.get_doc('Company', "_Test Company") company = frappe.get_doc('Company', "_Test Company")
company.standard_working_hours = 8 company.standard_working_hours = 8
company.save() company.save()
timesheet = frappe.new_doc("Timesheet") timesheet = frappe.new_doc("Timesheet")
timesheet.employee = "_T-Employee-00001" timesheet.employee = emp
timesheet.company = '_Test Company' timesheet.company = '_Test Company'
timesheet.append( timesheet.append(
'time_logs', 'time_logs',
@ -156,7 +170,7 @@ class TestTimesheet(unittest.TestCase):
company.save() company.save()
timesheet = frappe.new_doc("Timesheet") timesheet = frappe.new_doc("Timesheet")
timesheet.employee = "_T-Employee-00001" timesheet.employee = emp
timesheet.company = '_Test Company' timesheet.company = '_Test Company'
timesheet.append( timesheet.append(
'time_logs', 'time_logs',

View File

@ -81,4 +81,10 @@
.place-order-container { .place-order-container {
text-align: right; text-align: right;
}
.kb-card {
.card-body > .card-title {
line-height: 1.3;
}
} }

View File

@ -1,7 +1,7 @@
{{ address_line1 }}<br>{% if address_line2 %}{{ address_line2 }}<br>{% endif -%}{{ city }}<br> {{ address_line1 }}<br>{% if address_line2 %}{{ address_line2 }}<br>{% endif -%}{{ city }}<br>
{% if gst_state %}{{ gst_state }}{% endif -%} {% if gst_state %}{{ gst_state }}{% endif -%}
{% if gst_state_number %}, State Code: {{ gst_state_number }}<br>{% 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> {{ country }}<br>
{% if phone %}Phone: {{ phone }}<br>{% endif -%} {% if phone %}Phone: {{ phone }}<br>{% endif -%}
{% if fax %}Fax: {{ fax }}<br>{% endif -%} {% if fax %}Fax: {{ fax }}<br>{% endif -%}

View File

@ -339,6 +339,7 @@ def get_loyalty_programs(doc):
return lp_details return lp_details
@frappe.whitelist()
def get_customer_list(doctype, txt, searchfield, start, page_len, filters=None): def get_customer_list(doctype, txt, searchfield, start, page_len, filters=None):
from erpnext.controllers.queries import get_fields from erpnext.controllers.queries import get_fields

View File

@ -5,7 +5,7 @@ from __future__ import unicode_literals
import calendar import calendar
import frappe import frappe
from frappe import _ from frappe import _
from frappe.utils import cint, cstr from frappe.utils import cint, cstr, getdate
def execute(filters=None): def execute(filters=None):
common_columns = [ common_columns = [
@ -160,7 +160,7 @@ def get_data_by_territory(filters, common_columns):
return columns, data, None, None, None, 1 return columns, data, None, None, None, 1
def get_customer_stats(filters, tree_view=False): 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 = '' company_condition = ''
if filters.get('company'): if filters.get('company'):
company_condition = ' and company=%(company)s' company_condition = ' and company=%(company)s'
@ -174,14 +174,14 @@ def get_customer_stats(filters, tree_view=False):
filters, as_dict=1): filters, as_dict=1):
key = si.territory if tree_view else si.posting_date.strftime('%Y-%m') 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]}) customers_in.setdefault(key, {'new': [0, 0.0], 'repeat': [0, 0.0]})
if not si.customer in customers: # if filters.from_date <= si.posting_date.strftime('%Y-%m-%d'):
customers_in[key]['new'][0] += 1 if getdate(filters.from_date) <= getdate(si.posting_date):
customers_in[key]['new'][1] += si.base_grand_total 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) customers.append(si.customer)
else:
customers_in[key]['repeat'][0] += 1
customers_in[key]['repeat'][1] += si.base_grand_total
return customers_in return customers_in

View File

@ -1,4 +1,5 @@
{ {
"actions": [],
"allow_import": 1, "allow_import": 1,
"allow_rename": 1, "allow_rename": 1,
"autoname": "field:title", "autoname": "field:title",
@ -49,7 +50,7 @@
"fieldname": "terms_and_conditions_help", "fieldname": "terms_and_conditions_help",
"fieldtype": "HTML", "fieldtype": "HTML",
"label": "Terms and Conditions Help", "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 &gt; 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 &gt; 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", "fieldname": "applicable_modules_section",
@ -81,7 +82,8 @@
], ],
"icon": "icon-legal", "icon": "icon-legal",
"idx": 1, "idx": 1,
"modified": "2019-07-04 13:31:30.393425", "links": [],
"modified": "2020-06-16 22:54:38.094844",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Setup", "module": "Setup",
"name": "Terms and Conditions", "name": "Terms and Conditions",

View File

@ -42,9 +42,9 @@ def get_cart_quotation(doc=None):
return { return {
"doc": decorate_quotation_doc(doc), "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"], 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"], for address in addresses if address.address_type == "Billing"],
"shipping_rules": get_applicable_shipping_rules(party), "shipping_rules": get_applicable_shipping_rules(party),
"cart_settings": frappe.get_cached_doc("Shopping Cart Settings") "cart_settings": frappe.get_cached_doc("Shopping Cart Settings")
@ -78,8 +78,10 @@ def place_order():
if is_stock_item: if is_stock_item:
item_stock = get_qty_in_stock(item.item_code, "website_warehouse") 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]: 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.flags.ignore_permissions = True
sales_order.insert() sales_order.insert()

View File

@ -5,7 +5,7 @@ from __future__ import unicode_literals
import frappe import frappe
import unittest import unittest
from erpnext.support.doctype.service_level_agreement.test_service_level_agreement import create_service_level_agreements_for_issues 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 import datetime
from datetime import timedelta from datetime import timedelta
@ -120,7 +120,7 @@ class TestIssue(unittest.TestCase):
create_communication(issue.name, "test@example.com", "Received", creation) create_communication(issue.name, "test@example.com", "Received", creation)
issue.reload() 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)) self.assertEqual(issue.resolution_by, datetime.datetime(2020, 3, 4, 16, 45))
creation = datetime.datetime(2020, 3, 4, 5, 5) creation = datetime.datetime(2020, 3, 4, 5, 5)
@ -132,7 +132,7 @@ class TestIssue(unittest.TestCase):
issue.save() issue.save()
issue.reload() 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): def make_issue(creation=None, customer=None, index=0):

View File

@ -1,5 +1,5 @@
{ {
"actions": [], "actions": "",
"creation": "2017-02-17 13:07:35.686409", "creation": "2017-02-17 13:07:35.686409",
"doctype": "DocType", "doctype": "DocType",
"editable_grid": 1, "editable_grid": 1,
@ -22,6 +22,10 @@
"post_description_key", "post_description_key",
"post_route_key", "post_route_key",
"post_route_string", "post_route_string",
"greetings_section_section",
"greeting_title",
"column_break_19",
"greeting_subtitle",
"search_apis_sb", "search_apis_sb",
"search_apis" "search_apis"
], ],
@ -127,11 +131,40 @@
"fieldname": "allow_resetting_service_level_agreement", "fieldname": "allow_resetting_service_level_agreement",
"fieldtype": "Check", "fieldtype": "Check",
"label": "Allow Resetting Service Level Agreement" "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, "issingle": 1,
"links": [], "links": [],
"modified": "2020-06-05 17:56:17.491684", "modified": "2020-06-11 13:08:38.473616",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Support", "module": "Support",
"name": "Support Settings", "name": "Support Settings",

View File

@ -193,14 +193,17 @@ class ItemConfigure {
filtered_items_count === 1 ? filtered_items_count === 1 ?
filtered_items[0] : ''; 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 ? ` const item_add_to_cart = one_item ? `
<div class="alert alert-success d-flex justify-content-between align-items-center" role="alert"> <div class="alert alert-success d-flex justify-content-between align-items-center" role="alert">
<div> <div>
<div>${one_item} ${product_info && product_info.price ? '(' + product_info.price.formatted_price_sales_uom + ')' : ''}</div> <div>${one_item} ${product_info && product_info.price ? '(' + product_info.price.formatted_price_sales_uom + ')' : ''}</div>
</div> </div>
<a href data-action="btn_add_to_cart" data-item-code="${one_item}"> ${product_action}
${__('Add to cart')}
</a>
</div> </div>
`: ''; `: '';

View File

@ -14,12 +14,12 @@
{%- if introduction -%} {%- if introduction -%}
<div>{{ introduction }}</div> <div>{{ introduction }}</div>
{% endif %} {% endif %}
{%- if application_form_route -%} {%- if doc.enable_admission_application -%}
<p> <p>
<a class='btn btn-primary' <a class='btn btn-primary'
href='/{{ doc.application_form_route }}'> href='/student-applicant'>
{{ _("Apply Now") }}</a> {{ _("Apply Now") }}</a>
</p> </p>
{% endif %} {% endif %}

View File

@ -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> <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>
<div class="card-body"> <div class="card-body">
<h5 class="card-title">{{ address.name }}</h5> <h5 class="card-title">{{ address.title }}</h5>
<p class="card-text text-muted"> <p class="card-text text-muted">
{{ address.display }} {{ address.display }}
</p> </p>

View File

@ -109,7 +109,7 @@ frappe.ready(() => {
reqd: 1 reqd: 1
}, },
{ {
label: __('Pin Code'), label: __('Postal Code'),
fieldname: 'pincode', fieldname: 'pincode',
fieldtype: 'Data' fieldtype: 'Data'
}, },

View File

View File

@ -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 %}

View File

@ -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