From f596b5950ebd137abfdfb9b32cbd944743d5f3cb Mon Sep 17 00:00:00 2001 From: Abhishek Balam Date: Fri, 12 Jun 2020 11:07:28 +0530 Subject: [PATCH 01/26] indent to tabs --- .../customer_acquisition_and_loyalty.py | 310 +++++++++--------- 1 file changed, 155 insertions(+), 155 deletions(-) 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 88bd9c135d5..7cdad4a5141 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 @@ -8,180 +8,180 @@ from frappe import _ from frappe.utils import cint, cstr def execute(filters=None): - common_columns = [ - { - 'label': _('New Customers'), - 'fieldname': 'new_customers', - 'fieldtype': 'Int', - 'default': 0, - 'width': 125 - }, - { - 'label': _('Repeat Customers'), - 'fieldname': 'repeat_customers', - 'fieldtype': 'Int', - 'default': 0, - 'width': 125 - }, - { - 'label': _('Total'), - 'fieldname': 'total', - 'fieldtype': 'Int', - 'default': 0, - 'width': 100 - }, - { - 'label': _('New Customer Revenue'), - 'fieldname': 'new_customer_revenue', - 'fieldtype': 'Currency', - 'default': 0.0, - 'width': 175 - }, - { - 'label': _('Repeat Customer Revenue'), - 'fieldname': 'repeat_customer_revenue', - 'fieldtype': 'Currency', - 'default': 0.0, - 'width': 175 - }, - { - 'label': _('Total Revenue'), - 'fieldname': 'total_revenue', - 'fieldtype': 'Currency', - 'default': 0.0, - 'width': 175 - } - ] - if filters.get('view_type') == 'Monthly': - return get_data_by_time(filters, common_columns) - else: - return get_data_by_territory(filters, common_columns) + common_columns = [ + { + 'label': _('New Customers'), + 'fieldname': 'new_customers', + 'fieldtype': 'Int', + 'default': 0, + 'width': 125 + }, + { + 'label': _('Repeat Customers'), + 'fieldname': 'repeat_customers', + 'fieldtype': 'Int', + 'default': 0, + 'width': 125 + }, + { + 'label': _('Total'), + 'fieldname': 'total', + 'fieldtype': 'Int', + 'default': 0, + 'width': 100 + }, + { + 'label': _('New Customer Revenue'), + 'fieldname': 'new_customer_revenue', + 'fieldtype': 'Currency', + 'default': 0.0, + 'width': 175 + }, + { + 'label': _('Repeat Customer Revenue'), + 'fieldname': 'repeat_customer_revenue', + 'fieldtype': 'Currency', + 'default': 0.0, + 'width': 175 + }, + { + 'label': _('Total Revenue'), + 'fieldname': 'total_revenue', + 'fieldtype': 'Currency', + 'default': 0.0, + 'width': 175 + } + ] + if filters.get('view_type') == 'Monthly': + return get_data_by_time(filters, common_columns) + else: + return get_data_by_territory(filters, common_columns) def get_data_by_time(filters, common_columns): - # key yyyy-mm - columns = [ - { - 'label': _('Year'), - 'fieldname': 'year', - 'fieldtype': 'Data', - 'width': 100 - }, - { - 'label': _('Month'), - 'fieldname': 'month', - 'fieldtype': 'Data', - 'width': 100 - }, - ] - columns += common_columns + # key yyyy-mm + columns = [ + { + 'label': _('Year'), + 'fieldname': 'year', + 'fieldtype': 'Data', + 'width': 100 + }, + { + 'label': _('Month'), + 'fieldname': 'month', + 'fieldtype': 'Data', + 'width': 100 + }, + ] + columns += common_columns - customers_in = get_customer_stats(filters) + customers_in = get_customer_stats(filters) - # time series - from_year, from_month, temp = filters.get('from_date').split('-') - to_year, to_month, temp = filters.get('to_date').split('-') + # time series + from_year, from_month, temp = filters.get('from_date').split('-') + to_year, to_month, temp = filters.get('to_date').split('-') - from_year, from_month, to_year, to_month = \ - cint(from_year), cint(from_month), cint(to_year), cint(to_month) + from_year, from_month, to_year, to_month = \ + cint(from_year), cint(from_month), cint(to_year), cint(to_month) - out = [] - for year in range(from_year, to_year+1): - for month in range(from_month if year==from_year else 1, (to_month+1) if year==to_year else 13): - key = '{year}-{month:02d}'.format(year=year, month=month) - data = customers_in.get(key) - new = data['new'] if data else [0, 0.0] - repeat = data['repeat'] if data else [0, 0.0] - out.append({ - 'year': cstr(year), - 'month': calendar.month_name[month], - 'new_customers': new[0], - 'repeat_customers': repeat[0], - 'total': new[0] + repeat[0], - 'new_customer_revenue': new[1], - 'repeat_customer_revenue': repeat[1], - 'total_revenue': new[1] + repeat[1] - }) - return columns, out + out = [] + for year in range(from_year, to_year+1): + for month in range(from_month if year==from_year else 1, (to_month+1) if year==to_year else 13): + key = '{year}-{month:02d}'.format(year=year, month=month) + data = customers_in.get(key) + new = data['new'] if data else [0, 0.0] + repeat = data['repeat'] if data else [0, 0.0] + out.append({ + 'year': cstr(year), + 'month': calendar.month_name[month], + 'new_customers': new[0], + 'repeat_customers': repeat[0], + 'total': new[0] + repeat[0], + 'new_customer_revenue': new[1], + 'repeat_customer_revenue': repeat[1], + 'total_revenue': new[1] + repeat[1] + }) + return columns, out def get_data_by_territory(filters, common_columns): - columns = [{ - 'label': 'Territory', - 'fieldname': 'territory', - 'fieldtype': 'Link', - 'options': 'Territory', - 'width': 150 - }] - columns += common_columns + columns = [{ + 'label': 'Territory', + 'fieldname': 'territory', + 'fieldtype': 'Link', + 'options': 'Territory', + 'width': 150 + }] + columns += common_columns - customers_in = get_customer_stats(filters, tree_view=True) + customers_in = get_customer_stats(filters, tree_view=True) - territory_dict = {} - for t in frappe.db.sql('''SELECT name, lft, parent_territory, is_group FROM `tabTerritory` ORDER BY lft''', as_dict=1): - territory_dict.update({ - t.name: { - 'parent': t.parent_territory, - 'is_group': t.is_group - } - }) + territory_dict = {} + for t in frappe.db.sql('''SELECT name, lft, parent_territory, is_group FROM `tabTerritory` ORDER BY lft''', as_dict=1): + territory_dict.update({ + t.name: { + 'parent': t.parent_territory, + 'is_group': t.is_group + } + }) - depth_map = frappe._dict() - for name, info in territory_dict.items(): - default = depth_map.get(info['parent']) + 1 if info['parent'] else 0 - depth_map.setdefault(name, default) + depth_map = frappe._dict() + for name, info in territory_dict.items(): + default = depth_map.get(info['parent']) + 1 if info['parent'] else 0 + depth_map.setdefault(name, default) - data = [] - for name, indent in depth_map.items(): - condition = customers_in.get(name) - new = customers_in[name]['new'] if condition else [0, 0.0] - repeat = customers_in[name]['repeat'] if condition else [0, 0.0] - temp = { - 'territory': name, - 'parent_territory': territory_dict[name]['parent'], - 'indent': indent, - 'new_customers': new[0], - 'repeat_customers': repeat[0], - 'total': new[0] + repeat[0], - 'new_customer_revenue': new[1], - 'repeat_customer_revenue': repeat[1], - 'total_revenue': new[1] + repeat[1], - 'bold': 0 if indent else 1 - } - data.append(temp) + data = [] + for name, indent in depth_map.items(): + condition = customers_in.get(name) + new = customers_in[name]['new'] if condition else [0, 0.0] + repeat = customers_in[name]['repeat'] if condition else [0, 0.0] + temp = { + 'territory': name, + 'parent_territory': territory_dict[name]['parent'], + 'indent': indent, + 'new_customers': new[0], + 'repeat_customers': repeat[0], + 'total': new[0] + repeat[0], + 'new_customer_revenue': new[1], + 'repeat_customer_revenue': repeat[1], + 'total_revenue': new[1] + repeat[1], + 'bold': 0 if indent else 1 + } + data.append(temp) - loop_data = sorted(data, key=lambda k: k['indent'], reverse=True) + loop_data = sorted(data, key=lambda k: k['indent'], reverse=True) - for ld in loop_data: - if ld['parent_territory']: - parent_data = [x for x in data if x['territory'] == ld['parent_territory']][0] - for key in parent_data.keys(): - if key not in ['indent', 'territory', 'parent_territory', 'bold']: - parent_data[key] += ld[key] + for ld in loop_data: + if ld['parent_territory']: + parent_data = [x for x in data if x['territory'] == ld['parent_territory']][0] + for key in parent_data.keys(): + if key not in ['indent', 'territory', 'parent_territory', 'bold']: + parent_data[key] += ld[key] - return columns, data, None, None, None, 1 + return columns, data, None, None, None, 1 def get_customer_stats(filters, tree_view=False): - """ Calculates number of new and repeated customers. """ - company_condition = '' - if filters.get('company'): - company_condition = ' and company=%(company)s' + """ Calculates number of new and repeated customers and revenue. """ + company_condition = '' + if filters.get('company'): + company_condition = ' and company=%(company)s' - customers = [] - customers_in = {} + customers = [] + customers_in = {} - for si in frappe.db.sql('''select territory, posting_date, customer, base_grand_total from `tabSales Invoice` - where docstatus=1 and posting_date <= %(to_date)s and posting_date >= %(from_date)s - {company_condition} order by posting_date'''.format(company_condition=company_condition), - filters, as_dict=1): + for si in frappe.db.sql('''select territory, posting_date, customer, base_grand_total from `tabSales Invoice` + where docstatus=1 and posting_date <= %(to_date)s + {company_condition} order by posting_date'''.format(company_condition=company_condition), + filters, as_dict=1): - key = si.territory if tree_view else si.posting_date.strftime('%Y-%m') - customers_in.setdefault(key, {'new': [0, 0.0], 'repeat': [0, 0.0]}) + key = si.territory if tree_view else si.posting_date.strftime('%Y-%m') + 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 - customers.append(si.customer) - else: - customers_in[key]['repeat'][0] += 1 - customers_in[key]['repeat'][1] += si.base_grand_total + if not si.customer in customers: + customers_in[key]['new'][0] += 1 + customers_in[key]['new'][1] += si.base_grand_total + 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 \ No newline at end of file From 72450d2af30ded6d2a66b8a47dc2a4b92fb14414 Mon Sep 17 00:00:00 2001 From: Abhishek Balam Date: Fri, 12 Jun 2020 11:07:57 +0530 Subject: [PATCH 02/26] add revenue if within date range --- .../customer_acquisition_and_loyalty.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) 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 7cdad4a5141..0ab6eda6478 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 @@ -175,13 +175,16 @@ def get_customer_stats(filters, tree_view=False): key = si.territory if tree_view else si.posting_date.strftime('%Y-%m') customers_in.setdefault(key, {'new': [0, 0.0], 'repeat': [0, 0.0]}) + revenue_condition = (filters.from_date <= si.posting_date.strftime('%Y-%m-%d')) if not si.customer in customers: customers_in[key]['new'][0] += 1 - customers_in[key]['new'][1] += si.base_grand_total + if revenue_condition: + customers_in[key]['new'][1] += si.base_grand_total customers.append(si.customer) else: customers_in[key]['repeat'][0] += 1 - customers_in[key]['repeat'][1] += si.base_grand_total + if revenue_condition: + customers_in[key]['repeat'][1] += si.base_grand_total return customers_in \ No newline at end of file From 996b306cdae6417492e9866ab3dfca27943c9d72 Mon Sep 17 00:00:00 2001 From: Abhishek Balam Date: Fri, 12 Jun 2020 11:38:07 +0530 Subject: [PATCH 03/26] fix territory count --- .../customer_acquisition_and_loyalty.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) 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 0ab6eda6478..4288b52acac 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 @@ -174,17 +174,15 @@ def get_customer_stats(filters, tree_view=False): 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]}) revenue_condition = (filters.from_date <= si.posting_date.strftime('%Y-%m-%d')) - if not si.customer in customers: - customers_in[key]['new'][0] += 1 - if revenue_condition: - customers_in[key]['new'][1] += si.base_grand_total + if revenue_condition: + 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 - if revenue_condition: - customers_in[key]['repeat'][1] += si.base_grand_total return customers_in \ No newline at end of file From 6c4a24a6c31b5d2a04757191afa1a4fa5670fdc1 Mon Sep 17 00:00:00 2001 From: Abhishek Balam Date: Mon, 15 Jun 2020 11:36:56 +0530 Subject: [PATCH 04/26] cleanup --- .../customer_acquisition_and_loyalty.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) 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 8967c6bad9f..d10b1ca88f6 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 @@ -175,11 +175,9 @@ def get_customer_stats(filters, tree_view=False): 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]}) - revenue_condition = (filters.from_date <= si.posting_date.strftime('%Y-%m-%d')) - if revenue_condition: + if filters.from_date <= si.posting_date.strftime('%Y-%m-%d'): customers_in[key][new_or_repeat][0] += 1 customers_in[key][new_or_repeat][1] += si.base_grand_total if new_or_repeat == 'new': From 2112834743388b08981cd14177908a9bf7d36a1e Mon Sep 17 00:00:00 2001 From: Marica Date: Tue, 16 Jun 2020 00:20:57 +0530 Subject: [PATCH 05/26] fix: Handle unavailable Variants in Website (#22195) * fix: Handle unavailable Variants in Website * fix: Fetch cart setting from argument --- erpnext/portal/product_configurator/utils.py | 3 +++ erpnext/shopping_cart/cart.py | 4 +++- erpnext/templates/generators/item/item_configure.js | 9 ++++++--- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/erpnext/portal/product_configurator/utils.py b/erpnext/portal/product_configurator/utils.py index 0993e69e042..6b6b8c579be 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 @@ def get_next_attribute_and_values(item_code, selected_attributes): 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/shopping_cart/cart.py b/erpnext/shopping_cart/cart.py index 7096c17fb18..5bd30ab2e89 100644 --- a/erpnext/shopping_cart/cart.py +++ b/erpnext/shopping_cart/cart.py @@ -78,8 +78,10 @@ def place_order(): 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/templates/generators/item/item_configure.js b/erpnext/templates/generators/item/item_configure.js index 5fd901169f0..163c955c566 100644 --- a/erpnext/templates/generators/item/item_configure.js +++ b/erpnext/templates/generators/item/item_configure.js @@ -193,14 +193,17 @@ class ItemConfigure { 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 = `${__('Add to cart')}`; + const product_action = in_stock ? add_to_cart : `${__('Not in Stock')}`; + const item_add_to_cart = one_item ? ` `: ''; From fa6e4f62e24c9d0f1c498131e4f198531bc14cff Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Mon, 15 Jun 2020 22:21:04 +0530 Subject: [PATCH 06/26] fix: travis for develop --- ...ve_due_advance_amount_to_pending_amount.py | 4 +- .../doctype/timesheet/test_timesheet.py | 38 +++++++++++++------ erpnext/support/doctype/issue/test_issue.py | 6 +-- 3 files changed, 32 insertions(+), 16 deletions(-) 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 f1ffaf9d2d4..6013eaa29c6 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 @@ import frappe 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/projects/doctype/timesheet/test_timesheet.py b/erpnext/projects/doctype/timesheet/test_timesheet.py index 32f0428fcd8..cbc624c064f 100644 --- a/erpnext/projects/doctype/timesheet/test_timesheet.py +++ b/erpnext/projects/doctype/timesheet/test_timesheet.py @@ -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.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 @@ class TestTimesheet(unittest.TestCase): 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 @@ class TestTimesheet(unittest.TestCase): 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 @@ class TestTimesheet(unittest.TestCase): 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 @@ class TestTimesheet(unittest.TestCase): 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 @@ class TestTimesheet(unittest.TestCase): 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 @@ class TestTimesheet(unittest.TestCase): 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 @@ class TestTimesheet(unittest.TestCase): 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 @@ class TestTimesheet(unittest.TestCase): 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 @@ class TestTimesheet(unittest.TestCase): 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/support/doctype/issue/test_issue.py b/erpnext/support/doctype/issue/test_issue.py index a0048432705..fb8ceb53b21 100644 --- a/erpnext/support/doctype/issue/test_issue.py +++ b/erpnext/support/doctype/issue/test_issue.py @@ -5,7 +5,7 @@ from __future__ import unicode_literals 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 @@ class TestIssue(unittest.TestCase): 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 @@ class TestIssue(unittest.TestCase): 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): From 58831ecc7d18f477b08e767fbc505fa11a00a9e6 Mon Sep 17 00:00:00 2001 From: Anurag Mishra <32095923+Anurag810@users.noreply.github.com> Date: Tue, 16 Jun 2020 19:23:52 +0530 Subject: [PATCH 07/26] fix(HR): wrong shortcut in desk page (#22269) --- erpnext/hr/desk_page/hr/hr.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/hr/desk_page/hr/hr.json b/erpnext/hr/desk_page/hr/hr.json index 1c24444fdd2..12548d48a74 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" }, { From c159556c24dd90f18d2b5dafacd94abfacfff4d8 Mon Sep 17 00:00:00 2001 From: Kenneth Sequeira <33246109+kennethsequeira@users.noreply.github.com> Date: Wed, 17 Jun 2020 09:34:58 +0530 Subject: [PATCH 08/26] fix: typo for language in Terms description (#22270) --- .../doctype/terms_and_conditions/terms_and_conditions.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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 aba6a791a4e..28d1d16a051 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": "

Standard Terms and Conditions Example

\n\n
Delivery Terms for Order number {{ name }}\n\n-Order Date : {{ transaction_date }} \n-Expected Delivery Date : {{ delivery_date }}\n
\n\n

How to get fieldnames

\n\n

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)

\n\n

Templating

\n\n

Templates are compiled using the Jinja Templating Langauge. To learn more about Jinja, read this documentation.

" + "options": "

Standard Terms and Conditions Example

\n\n
Delivery Terms for Order number {{ name }}\n\n-Order Date : {{ transaction_date }} \n-Expected Delivery Date : {{ delivery_date }}\n
\n\n

How to get fieldnames

\n\n

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)

\n\n

Templating

\n\n

Templates are compiled using the Jinja Templating Language. To learn more about Jinja, read this documentation.

" }, { "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", From 8d856659afec9bb6bfb17ad28a9697ffc93c0a39 Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Wed, 17 Jun 2020 09:37:41 +0530 Subject: [PATCH 09/26] refactor: hide company currency fields in the routing (#22267) (cherry picked from commit fd3ff6be18b0bd5accc88aea22e3adfe48e62aff) --- erpnext/manufacturing/doctype/bom/bom.py | 1 + .../doctype/bom_operation/bom_operation.json | 8 +++++--- erpnext/manufacturing/doctype/routing/routing.js | 1 - 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py index 2543eec53e4..7d31a1cd15e 100644 --- a/erpnext/manufacturing/doctype/bom/bom.py +++ b/erpnext/manufacturing/doctype/bom/bom.py @@ -119,6 +119,7 @@ class BOM(WebsiteGenerator): "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 3ca851d783b..0350e2cb374 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 6cfd0bae5b5..d7589fa3907 100644 --- a/erpnext/manufacturing/doctype/routing/routing.js +++ b/erpnext/manufacturing/doctype/routing/routing.js @@ -44,7 +44,6 @@ frappe.ui.form.on('BOM Operation', { 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); } From 0a3c34de01fe4a08db9540c3de86debc8b11d3dc Mon Sep 17 00:00:00 2001 From: Anupam Kumar Date: Wed, 17 Jun 2020 10:53:13 +0530 Subject: [PATCH 10/26] address label chages (#22137) Co-authored-by: Marica --- erpnext/patches.txt | 3 ++- .../v12_0/update_address_template_for_india.py | 12 ++++++++++++ .../regional/address_template/templates/india.html | 2 +- erpnext/shopping_cart/cart.py | 4 ++-- erpnext/templates/includes/cart/address_card.html | 2 +- erpnext/templates/includes/cart/cart_address.html | 2 +- 6 files changed, 19 insertions(+), 6 deletions(-) create mode 100644 erpnext/patches/v12_0/update_address_template_for_india.py diff --git a/erpnext/patches.txt b/erpnext/patches.txt index db9610b62ba..279c453e350 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -697,4 +697,5 @@ execute:frappe.rename_doc("Desk Page", "Loan Management", "Loan", force=True) erpnext.patches.v12_0.update_uom_conversion_factor 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 \ No newline at end of file +erpnext.patches.v13_0.update_sla_enhancements +erpnext.patches.v12_0.update_address_template_for_india 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 00000000000..0d582da4b5c --- /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/regional/address_template/templates/india.html b/erpnext/regional/address_template/templates/india.html index ffb9d0547e0..5d2329efffa 100644 --- a/erpnext/regional/address_template/templates/india.html +++ b/erpnext/regional/address_template/templates/india.html @@ -1,7 +1,7 @@ {{ address_line1 }}
{% if address_line2 %}{{ address_line2 }}
{% endif -%}{{ city }}
{% if gst_state %}{{ gst_state }}{% endif -%} {% if gst_state_number %}, State Code: {{ gst_state_number }}
{% endif -%} -{% if pincode %}PIN: {{ pincode }}
{% endif -%} +{% if pincode %}Postal Code: {{ pincode }}
{% endif -%} {{ country }}
{% if phone %}Phone: {{ phone }}
{% endif -%} {% if fax %}Fax: {{ fax }}
{% endif -%} diff --git a/erpnext/shopping_cart/cart.py b/erpnext/shopping_cart/cart.py index 5bd30ab2e89..a7e8388be9d 100644 --- a/erpnext/shopping_cart/cart.py +++ b/erpnext/shopping_cart/cart.py @@ -42,9 +42,9 @@ def get_cart_quotation(doc=None): 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") diff --git a/erpnext/templates/includes/cart/address_card.html b/erpnext/templates/includes/cart/address_card.html index c91723e91e7..646210e65f1 100644 --- a/erpnext/templates/includes/cart/address_card.html +++ b/erpnext/templates/includes/cart/address_card.html @@ -3,7 +3,7 @@
-
{{ address.name }}
+
{{ address.title }}

{{ address.display }}

diff --git a/erpnext/templates/includes/cart/cart_address.html b/erpnext/templates/includes/cart/cart_address.html index 60de3af17bf..aa25c885fee 100644 --- a/erpnext/templates/includes/cart/cart_address.html +++ b/erpnext/templates/includes/cart/cart_address.html @@ -109,7 +109,7 @@ frappe.ready(() => { reqd: 1 }, { - label: __('Pin Code'), + label: __('Postal Code'), fieldname: 'pincode', fieldtype: 'Data' }, From 8d4ba6c7ec53674c267ebc8979ef69a3db1b2cb1 Mon Sep 17 00:00:00 2001 From: Anupam K Date: Tue, 16 Jun 2020 16:19:33 +0530 Subject: [PATCH 11/26] Adding filter in academic term --- erpnext/education/doctype/fee_structure/fee_structure.js | 8 ++++++++ .../education/doctype/fee_structure/fee_structure.json | 6 ++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/erpnext/education/doctype/fee_structure/fee_structure.js b/erpnext/education/doctype/fee_structure/fee_structure.js index 7606565fadb..f09d2efcb9e 100644 --- a/erpnext/education/doctype/fee_structure/fee_structure.js +++ b/erpnext/education/doctype/fee_structure/fee_structure.js @@ -9,6 +9,14 @@ frappe.ui.form.on('Fee Structure', { }, 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 8ff6851d90a..67e46372f82 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", From c6592c880a2873adcb7bf78883e9c3f20b25e59b Mon Sep 17 00:00:00 2001 From: Anupam Kumar Date: Wed, 17 Jun 2020 12:38:31 +0530 Subject: [PATCH 12/26] fix: Student Admission (#22255) * Student Admission fix * adding check for application * adding check for application * updating error message * added date_diff for date comparision --- .../student_admission/student_admission.json | 477 ++++-------------- .../templates/student_admission.html | 13 +- .../test_student_admission.js | 4 +- .../student_admission_program.json | 294 +++-------- .../student_applicant/student_applicant.py | 21 +- .../student_applicant/student_applicant.json | 406 ++++++++------- .../generators/student_admission.html | 6 +- 7 files changed, 416 insertions(+), 805 deletions(-) diff --git a/erpnext/education/doctype/student_admission/student_admission.json b/erpnext/education/doctype/student_admission/student_admission.json index b3c10d43316..1096888d4d2 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 25afaca84dc..e5a9ead31ed 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 @@ Program/Std. - Minumum Age(DOB) - Maximum Age(DOB) + Minumum Age + Maximum Age Application Fee @@ -52,8 +52,8 @@ {% for row in program_details %} {{ row.program }} - {{ row.minimum_age }} - {{ row.maximum_age }} + {{ row.min_age }} + {{ row.max_age }} {{ row.application_fee }} {% endfor %} @@ -61,12 +61,11 @@
{% endif %} - - {%- if application_form_route -%} + {%- if doc.enable_admission_application -%}

+ href='/student-applicant?new=1&student_admission={{doc.name}}'> {{ _("Apply Now") }}

{% endif %} diff --git a/erpnext/education/doctype/student_admission/test_student_admission.js b/erpnext/education/doctype/student_admission/test_student_admission.js index ed794b2482e..3a0bb0b2f23 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 @@ QUnit.test('Test: Student Admission', function(assert) { {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 @@ QUnit.test('Test: Student Admission', function(assert) { 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 97b1bba4217..e9f041e101f 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 ab947807dd8..211348201e3 100644 --- a/erpnext/education/doctype/student_applicant/student_applicant.py +++ b/erpnext/education/doctype/student_applicant/student_applicant.py @@ -6,7 +6,7 @@ from __future__ import print_function, unicode_literals 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 @@ class StudentApplicant(Document): 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 @@ class StudentApplicant(Document): 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 @@ class StudentApplicant(Document): 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 b1ad754c327..1810f07a054 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/templates/generators/student_admission.html b/erpnext/templates/generators/student_admission.html index ae70df8b08b..8b153448eea 100644 --- a/erpnext/templates/generators/student_admission.html +++ b/erpnext/templates/generators/student_admission.html @@ -14,12 +14,12 @@ {%- if introduction -%}
{{ introduction }}
-{% endif %} +{% endif %} -{%- if application_form_route -%} +{%- if doc.enable_admission_application -%}

+ href='/student-applicant'> {{ _("Apply Now") }}

{% endif %} From 17422a3e45fc61cf686931a89321fede0cde8141 Mon Sep 17 00:00:00 2001 From: marination Date: Wed, 17 Jun 2020 13:46:21 +0530 Subject: [PATCH 13/26] fix: Message Formatting --- erpnext/controllers/stock_controller.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index 2888c764ef7..759c6cd73eb 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -227,7 +227,9 @@ class StockController(AccountsController): 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", From 8546b71358534ecfb13e519ac8d49815f0382d91 Mon Sep 17 00:00:00 2001 From: Afshan <33727827+AfshanKhan@users.noreply.github.com> Date: Wed, 17 Jun 2020 16:16:59 +0530 Subject: [PATCH 14/26] feat: /support (#22194) * added: /support * refactor code and implemented fail checks * removed unused imports * changed filter from from title to name * refactor code to move context inside main * removed unused variable * added: /support * refactor code and implemented fail checks * removed unused imports * changed filter from from title to name * refactor code to move context inside main * removed unused variable * refactor: renamed set to get Co-authored-by: Shivam Mishra Co-authored-by: Anurag Mishra <32095923+Anurag810@users.noreply.github.com> --- .../support_settings/support_settings.json | 37 +++++++++- erpnext/www/support/__init__.py | 0 erpnext/www/support/index.html | 55 ++++++++++++++ erpnext/www/support/index.py | 74 +++++++++++++++++++ 4 files changed, 164 insertions(+), 2 deletions(-) create mode 100644 erpnext/www/support/__init__.py create mode 100644 erpnext/www/support/index.html create mode 100644 erpnext/www/support/index.py diff --git a/erpnext/support/doctype/support_settings/support_settings.json b/erpnext/support/doctype/support_settings/support_settings.json index 1c1b0c3517e..5d3d3ace59d 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/www/support/__init__.py b/erpnext/www/support/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/www/support/index.html b/erpnext/www/support/index.html new file mode 100644 index 00000000000..824f0bd5ba8 --- /dev/null +++ b/erpnext/www/support/index.html @@ -0,0 +1,55 @@ +{% extends "templates/web.html" %} + +{% block content %} +
+
+
+

{{ _(greeting_title) or _("We're here to help") }}

+

{{ greeting_subtitle or _("Browse help topics.") }}

+
+
+
+ +{% if favorite_article_list %} +
+
+

{{ _("Frequently Read Articles") }}

+
+ {% for favorite_article in favorite_article_list %} +
+
+
+
{{ favorite_article['category'] }}
+

{{ favorite_article['title'] }}

+

{{ favorite_article['description'] }}

+
+ +
+
+ {% endfor %} +
+
+
+{% endif %} + +{% if help_article_list %} +
+
+

{{ _("Help Articles") }}

+
+ {% for item in help_article_list %} +
+
{{ item['category'].name }}
+
+ {% for article in item['articles'] %} + {{ article.title }} + {% endfor %} +
+
+ {% endfor %} +
+
+
+{% 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 00000000000..58ca8f72816 --- /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) > 175: + description = description[:172] + '...' + 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 From a4cd9e2389a5485b4079f534b21be4d53bfd3494 Mon Sep 17 00:00:00 2001 From: Abhishek Balam Date: Wed, 17 Jun 2020 17:13:13 +0530 Subject: [PATCH 15/26] use getdate() for comparing dates --- .../customer_acquisition_and_loyalty.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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 d10b1ca88f6..f15f63d7bb7 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 @@ from __future__ import unicode_literals 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 = [ @@ -177,7 +177,8 @@ def get_customer_stats(filters, tree_view=False): 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 filters.from_date <= si.posting_date.strftime('%Y-%m-%d'): + # 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': From fec894f530a60a75cdc035d8bc1ffce423245fa8 Mon Sep 17 00:00:00 2001 From: Kaviya Periyasamy <36359901+KaviyaPeriyasamy@users.noreply.github.com> Date: Wed, 17 Jun 2020 17:39:12 +0530 Subject: [PATCH 16/26] fix: modified time updated with the latest date (#22286) --- erpnext/accounts/doctype/cost_center/cost_center.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/cost_center/cost_center.json b/erpnext/accounts/doctype/cost_center/cost_center.json index c9bbbabe798..e7fa954e018 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", From 7057a807ca175cdd1d7f1f20f425c332f6768ab9 Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Wed, 17 Jun 2020 18:35:38 +0530 Subject: [PATCH 17/26] refactor: minor layout fixes to portal --- erpnext/public/scss/website.scss | 6 ++++++ erpnext/www/support/index.html | 6 +++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/erpnext/public/scss/website.scss b/erpnext/public/scss/website.scss index 735b417da17..617e916724d 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/www/support/index.html b/erpnext/www/support/index.html index 824f0bd5ba8..afc437052db 100644 --- a/erpnext/www/support/index.html +++ b/erpnext/www/support/index.html @@ -11,13 +11,13 @@ {% if favorite_article_list %} -
+

{{ _("Frequently Read Articles") }}

{% for favorite_article in favorite_article_list %}
-
+
{{ favorite_article['category'] }}

{{ favorite_article['title'] }}

@@ -33,7 +33,7 @@ {% endif %} {% if help_article_list %} -
+

{{ _("Help Articles") }}

From 2b18bdfe72479cc3936e5dd7f1d4c164080e7ac6 Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Wed, 17 Jun 2020 18:36:51 +0530 Subject: [PATCH 18/26] fix: title for support --- erpnext/www/support/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/www/support/index.html b/erpnext/www/support/index.html index afc437052db..36cd8c68f3e 100644 --- a/erpnext/www/support/index.html +++ b/erpnext/www/support/index.html @@ -4,7 +4,7 @@
-

{{ _(greeting_title) or _("We're here to help") }}

+

{{ _(greeting_title) or _("We're here to help") }}

{{ greeting_subtitle or _("Browse help topics.") }}

From 2462f07c87d1fe3d3d69a8814bd7ef7a9230b05a Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Wed, 17 Jun 2020 18:39:49 +0530 Subject: [PATCH 19/26] refactor: update titles --- erpnext/www/support/index.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/erpnext/www/support/index.html b/erpnext/www/support/index.html index 36cd8c68f3e..491604f09c0 100644 --- a/erpnext/www/support/index.html +++ b/erpnext/www/support/index.html @@ -4,7 +4,7 @@
-

{{ _(greeting_title) or _("We're here to help") }}

+

{{ _(greeting_title) or _("We're here to help") }}

{{ greeting_subtitle or _("Browse help topics.") }}

@@ -13,7 +13,7 @@ {% if favorite_article_list %}
-

{{ _("Frequently Read Articles") }}

+

{{ _("Frequently Read Articles") }}

{% for favorite_article in favorite_article_list %}
@@ -35,7 +35,7 @@ {% if help_article_list %}
-

{{ _("Help Articles") }}

+

{{ _("Help Articles") }}

{% for item in help_article_list %}
From 6e231ae0cba6f5decb83293c8ebb87ddff5eac8c Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Wed, 17 Jun 2020 18:43:59 +0530 Subject: [PATCH 20/26] refactor: remove translation --- erpnext/www/support/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/www/support/index.html b/erpnext/www/support/index.html index 491604f09c0..2b1c282d184 100644 --- a/erpnext/www/support/index.html +++ b/erpnext/www/support/index.html @@ -4,7 +4,7 @@
-

{{ _(greeting_title) or _("We're here to help") }}

+

{{ greeting_title or _("We're here to help") }}

{{ greeting_subtitle or _("Browse help topics.") }}

From 64d772480b0d0dc7dc5a6ce9f5c99f442322d899 Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Wed, 17 Jun 2020 13:18:15 +0000 Subject: [PATCH 21/26] fix: limit max length for cards (#22289) --- erpnext/www/support/index.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/www/support/index.py b/erpnext/www/support/index.py index 58ca8f72816..5d267430c16 100644 --- a/erpnext/www/support/index.py +++ b/erpnext/www/support/index.py @@ -49,8 +49,8 @@ def get_favorite_articles(favorite_articles): favorite_article_list=[] for article in favorite_articles: description = frappe.utils.strip_html(article.content) - if len(description) > 175: - description = description[:172] + '...' + if len(description) > 120: + description = description[:120] + '...' favorite_article_dict = { 'title': article.title, 'description': description, From 91dfd000ede897bc456510456f3bf8e5cafeddc6 Mon Sep 17 00:00:00 2001 From: marination Date: Wed, 17 Jun 2020 19:05:40 +0530 Subject: [PATCH 22/26] fix: Typo --- erpnext/controllers/item_variant.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/controllers/item_variant.py b/erpnext/controllers/item_variant.py index 50b17abbe6d..1f95e004244 100644 --- a/erpnext/controllers/item_variant.py +++ b/erpnext/controllers/item_variant.py @@ -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.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 += "
" + _("To still proceed with editing this Attribute Value, enable {0} in Item Variant Settings.").format(frappe.bold("Allow Rename Attribute Value")) From 53b601523b81c32a0b5c10c721f99c184d09bcd8 Mon Sep 17 00:00:00 2001 From: Mangesh-Khairnar Date: Wed, 17 Jun 2020 19:31:57 +0530 Subject: [PATCH 23/26] fix: update shopify api version (#22284) Co-authored-by: Saurabh --- .../shopify_settings/shopify_settings.py | 24 +++++++++++++------ .../doctype/shopify_settings/sync_product.py | 2 +- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.py b/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.py index 64c3b2d2730..25ffd281099 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 @@ import json 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 @@ class ShopifySettings(Document): 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 @@ class ShopifySettings(Document): 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 @@ def setup_custom_fields(): } 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 bde101123db..f9f0bb3cecc 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 @@ from erpnext.erpnext_integrations.doctype.shopify_settings.shopify_settings impo 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: From ea78b2403581303973b307abfe4fbedfc494fceb Mon Sep 17 00:00:00 2001 From: Afshan <33727827+AfshanKhan@users.noreply.github.com> Date: Thu, 18 Jun 2020 09:49:35 +0530 Subject: [PATCH 24/26] style: subtitle to be displayed if provided else empty (#22298) * added: /support * refactor code and implemented fail checks * removed unused imports * changed filter from from title to name * refactor code to move context inside main * removed unused variable * added: /support * refactor code and implemented fail checks * removed unused imports * changed filter from from title to name * refactor code to move context inside main * removed unused variable * refactor: renamed set to get * style: subtitle to be displyed if provided else empty Co-authored-by: Shivam Mishra Co-authored-by: Anurag Mishra <32095923+Anurag810@users.noreply.github.com> --- erpnext/www/support/index.html | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/erpnext/www/support/index.html b/erpnext/www/support/index.html index 2b1c282d184..93da503dbb0 100644 --- a/erpnext/www/support/index.html +++ b/erpnext/www/support/index.html @@ -4,8 +4,10 @@
-

{{ greeting_title or _("We're here to help") }}

-

{{ greeting_subtitle or _("Browse help topics.") }}

+

{{ greeting_title or _("We're here to help!") }}

+ {% if greeting_subtitle %} +

{{ greeting_subtitle }}

+ {% endif %}
@@ -16,16 +18,17 @@

{{ _("Frequently Read Articles") }}

{% for favorite_article in favorite_article_list %} -
-
-
-
{{ favorite_article['category'] }}
-

{{ favorite_article['title'] }}

-

{{ favorite_article['description'] }}

-
- +
+
+
+
+ {{ favorite_article['category'] }}
+

{{ favorite_article['title'] }}

+

{{ favorite_article['description'] }}

+
+
{% endfor %}
From 755e7c812a8a9670b40b208b092d72a1d9fa7488 Mon Sep 17 00:00:00 2001 From: Chinmay Pai Date: Thu, 18 Jun 2020 10:05:53 +0530 Subject: [PATCH 25/26] chore: update travis url for docker build action (#22274) Signed-off-by: Chinmay D. Pai --- .github/workflows/docker-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker-release.yml b/.github/workflows/docker-release.yml index d36b11553ce..8f678583066 100644 --- a/.github/workflows/docker-release.yml +++ b/.github/workflows/docker-release.yml @@ -11,4 +11,4 @@ jobs: - 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 From 96100e95077db9d9a2a27b384030460109cdd0f2 Mon Sep 17 00:00:00 2001 From: Chinmay Pai Date: Thu, 18 Jun 2020 11:58:54 +0530 Subject: [PATCH 26/26] chore: add standard queries hooks to whitelist (#21939) standard queries are used within the search widget, and now require to be whitelisted before they can be executed through the search widget. Signed-off-by: Chinmay D. Pai Co-authored-by: sahil28297 <37302950+sahil28297@users.noreply.github.com> --- .../doctype/healthcare_practitioner/healthcare_practitioner.py | 1 + erpnext/selling/doctype/customer/customer.py | 1 + 2 files changed, 2 insertions(+) diff --git a/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.py b/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.py index 0c13b6af9db..3dc7c1ec393 100644 --- a/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.py +++ b/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.py @@ -70,6 +70,7 @@ def validate_service_item(item, msg): 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/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py index ac3bc201e96..682dfede72f 100644 --- a/erpnext/selling/doctype/customer/customer.py +++ b/erpnext/selling/doctype/customer/customer.py @@ -339,6 +339,7 @@ def get_loyalty_programs(doc): return lp_details +@frappe.whitelist() def get_customer_list(doctype, txt, searchfield, start, page_len, filters=None): from erpnext.controllers.queries import get_fields