+
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
index 7ab7f14902..d224961bd8 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
@@ -285,6 +285,7 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
is_paid: function() {
hide_fields(this.frm.doc);
if(cint(this.frm.doc.is_paid)) {
+ this.frm.set_value("allocate_advances_automatically", 0);
if(!this.frm.doc.company) {
this.frm.set_value("is_paid", 0)
frappe.msgprint(__("Please specify Company to proceed"));
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index 0af273c518..95d49a4421 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -21,8 +21,8 @@ from erpnext.accounts.general_ledger import get_round_off_account_and_cost_cente
from erpnext.assets.doctype.asset.asset import get_asset_account, is_cwip_accounting_disabled
from frappe.model.mapper import get_mapped_doc
from six import iteritems
-from erpnext.accounts.doctype.sales_invoice.sales_invoice import validate_inter_company_party, update_linked_invoice,\
- unlink_inter_company_invoice
+from erpnext.accounts.doctype.sales_invoice.sales_invoice import validate_inter_company_party, update_linked_doc,\
+ unlink_inter_company_doc
from erpnext.accounts.doctype.tax_withholding_category.tax_withholding_category import get_party_tax_withholding_details
from erpnext.accounts.deferred_revenue import validate_service_stop_date
@@ -348,7 +348,7 @@ class PurchaseInvoice(BuyingController):
self.make_gl_entries()
self.update_project()
- update_linked_invoice(self.doctype, self.name, self.inter_company_invoice_reference)
+ update_linked_doc(self.doctype, self.name, self.inter_company_invoice_reference)
def make_gl_entries(self, gl_entries=None, repost_future_gle=True, from_repost=False):
if not self.grand_total:
@@ -778,7 +778,7 @@ class PurchaseInvoice(BuyingController):
self.update_project()
frappe.db.set(self, 'status', 'Cancelled')
- unlink_inter_company_invoice(self.doctype, self.name, self.inter_company_invoice_reference)
+ unlink_inter_company_doc(self.doctype, self.name, self.inter_company_invoice_reference)
def update_project(self):
project_list = []
@@ -917,5 +917,5 @@ def block_invoice(name, hold_comment):
@frappe.whitelist()
def make_inter_company_sales_invoice(source_name, target_doc=None):
- from erpnext.accounts.doctype.sales_invoice.sales_invoice import make_inter_company_invoice
- return make_inter_company_invoice("Purchase Invoice", source_name, target_doc)
+ from erpnext.accounts.doctype.sales_invoice.sales_invoice import make_inter_company_transaction
+ return make_inter_company_transaction("Purchase Invoice", source_name, target_doc)
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index 44af743ebf..f21fbd9794 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -369,6 +369,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
set_pos_data: function() {
if(this.frm.doc.is_pos) {
+ this.frm.set_value("allocate_advances_automatically", 0);
if(!this.frm.doc.company) {
this.frm.set_value("is_pos", 0);
frappe.msgprint(__("Please specify Company to proceed"));
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 2089f15c7c..31a9c66f6f 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -179,7 +179,7 @@ class SalesInvoice(SellingController):
if frappe.db.get_single_value('Selling Settings', 'sales_update_frequency') == "Each Transaction":
update_company_current_month_sales(self.company)
self.update_project()
- update_linked_invoice(self.doctype, self.name, self.inter_company_invoice_reference)
+ update_linked_doc(self.doctype, self.name, self.inter_company_invoice_reference)
# create the loyalty point ledger entry if the customer is enrolled in any loyalty program
if not self.is_return and self.loyalty_program:
@@ -243,7 +243,7 @@ class SalesInvoice(SellingController):
against_si_doc.delete_loyalty_point_entry()
against_si_doc.make_loyalty_point_entry()
- unlink_inter_company_invoice(self.doctype, self.name, self.inter_company_invoice_reference)
+ unlink_inter_company_doc(self.doctype, self.name, self.inter_company_invoice_reference)
# Healthcare Service Invoice.
domain_settings = frappe.get_doc('Domain Settings')
@@ -1165,21 +1165,29 @@ class SalesInvoice(SellingController):
self.set_missing_values(for_validate = True)
-def validate_inter_company_party(doctype, party, company, inter_company_invoice_reference):
- if doctype == "Sales Invoice":
+def validate_inter_company_party(doctype, party, company, inter_company_reference):
+ if doctype in ["Sales Invoice", "Sales Order"]:
partytype, ref_partytype, internal = "Customer", "Supplier", "is_internal_customer"
- ref_doc = "Purchase Invoice"
+
+ if doctype == "Sales Invoice":
+ ref_doc = "Purchase Invoice"
+ else:
+ ref_doc = "Purchase Order"
else:
partytype, ref_partytype, internal = "Supplier", "Customer", "is_internal_supplier"
- ref_doc = "Sales Invoice"
- if inter_company_invoice_reference:
- doc = frappe.get_doc(ref_doc, inter_company_invoice_reference)
- ref_party = doc.supplier if doctype == "Sales Invoice" else doc.customer
+ if doctype == "Purchase Invoice":
+ ref_doc = "Sales Invoice"
+ else:
+ ref_doc = "Sales Order"
+
+ if inter_company_reference:
+ doc = frappe.get_doc(ref_doc, inter_company_reference)
+ ref_party = doc.supplier if doctype in ["Sales Invoice", "Sales Order"] else doc.customer
if not frappe.db.get_value(partytype, {"represents_company": doc.company}, "name") == party:
- frappe.throw(_("Invalid {0} for Inter Company Invoice.").format(partytype))
+ frappe.throw(_("Invalid {0} for Inter Company Transaction.").format(partytype))
if not frappe.get_cached_value(ref_partytype, ref_party, "represents_company") == company:
- frappe.throw(_("Invalid Company for Inter Company Invoice."))
+ frappe.throw(_("Invalid Company for Inter Company Transaction."))
elif frappe.db.get_value(partytype, {"name": party, internal: 1}, "name") == party:
companies = frappe.db.sql("""select company from `tabAllowed To Transact With`
@@ -1188,18 +1196,29 @@ def validate_inter_company_party(doctype, party, company, inter_company_invoice_
if not company in companies:
frappe.throw(_("{0} not allowed to transact with {1}. Please change the Company.").format(partytype, company))
-def update_linked_invoice(doctype, name, inter_company_invoice_reference):
- if inter_company_invoice_reference:
- frappe.db.set_value(doctype, inter_company_invoice_reference,\
- "inter_company_invoice_reference", name)
+def update_linked_doc(doctype, name, inter_company_reference):
-def unlink_inter_company_invoice(doctype, name, inter_company_invoice_reference):
- ref_doc = "Purchase Invoice" if doctype == "Sales Invoice" else "Sales Invoice"
- if inter_company_invoice_reference:
- frappe.db.set_value(doctype, name,\
- "inter_company_invoice_reference", "")
- frappe.db.set_value(ref_doc, inter_company_invoice_reference,\
- "inter_company_invoice_reference", "")
+ if doctype in ["Sales Invoice", "Purchase Invoice"]:
+ ref_field = "inter_company_invoice_reference"
+ else:
+ ref_field = "inter_company_order_reference"
+
+ if inter_company_reference:
+ frappe.db.set_value(doctype, inter_company_reference,\
+ ref_field, name)
+
+def unlink_inter_company_doc(doctype, name, inter_company_reference):
+
+ if doctype in ["Sales Invoice", "Purchase Invoice"]:
+ ref_doc = "Purchase Invoice" if doctype == "Sales Invoice" else "Sales Invoice"
+ ref_field = "inter_company_invoice_reference"
+ else:
+ ref_doc = "Purchase Order" if doctype == "Sales Order" else "Sales Order"
+ ref_field = "inter_company_order_reference"
+
+ if inter_company_reference:
+ frappe.db.set_value(doctype, name, ref_field, "")
+ frappe.db.set_value(ref_doc, inter_company_reference, ref_field, "")
def get_list_context(context=None):
from erpnext.controllers.website_list_for_contact import get_list_context
@@ -1299,7 +1318,7 @@ def set_account_for_mode_of_payment(self):
data.account = get_bank_cash_account(data.mode_of_payment, self.company).get("account")
def get_inter_company_details(doc, doctype):
- if doctype == "Sales Invoice":
+ if doctype in ["Sales Invoice", "Sales Order"]:
party = frappe.db.get_value("Supplier", {"disabled": 0, "is_internal_supplier": 1, "represents_company": doc.company}, "name")
company = frappe.get_cached_value("Customer", doc.customer, "represents_company")
else:
@@ -1312,21 +1331,21 @@ def get_inter_company_details(doc, doctype):
}
-def validate_inter_company_invoice(doc, doctype):
+def validate_inter_company_transaction(doc, doctype):
details = get_inter_company_details(doc, doctype)
- price_list = doc.selling_price_list if doctype == "Sales Invoice" else doc.buying_price_list
+ price_list = doc.selling_price_list if doctype in ["Sales Invoice", "Sales Order"] else doc.buying_price_list
valid_price_list = frappe.db.get_value("Price List", {"name": price_list, "buying": 1, "selling": 1})
if not valid_price_list:
frappe.throw(_("Selected Price List should have buying and selling fields checked."))
party = details.get("party")
if not party:
- partytype = "Supplier" if doctype == "Sales Invoice" else "Customer"
+ partytype = "Supplier" if doctype in ["Sales Invoice", "Sales Order"] else "Customer"
frappe.throw(_("No {0} found for Inter Company Transactions.").format(partytype))
company = details.get("company")
- default_currency = frappe.get_cached_value('Company', company, "default_currency")
+ default_currency = frappe.get_cached_value('Company', company, "default_currency")
if default_currency != doc.currency:
frappe.throw(_("Company currencies of both the companies should match for Inter Company Transactions."))
@@ -1334,17 +1353,17 @@ def validate_inter_company_invoice(doc, doctype):
@frappe.whitelist()
def make_inter_company_purchase_invoice(source_name, target_doc=None):
- return make_inter_company_invoice("Sales Invoice", source_name, target_doc)
+ return make_inter_company_transaction("Sales Invoice", source_name, target_doc)
-def make_inter_company_invoice(doctype, source_name, target_doc=None):
- if doctype == "Sales Invoice":
- source_doc = frappe.get_doc("Sales Invoice", source_name)
- target_doctype = "Purchase Invoice"
+def make_inter_company_transaction(doctype, source_name, target_doc=None):
+ if doctype in ["Sales Invoice", "Sales Order"]:
+ source_doc = frappe.get_doc(doctype, source_name)
+ target_doctype = "Purchase Invoice" if doctype == "Sales Invoice" else "Purchase Order"
else:
- source_doc = frappe.get_doc("Purchase Invoice", source_name)
- target_doctype = "Sales Invoice"
+ source_doc = frappe.get_doc(doctype, source_name)
+ target_doctype = "Sales Invoice" if doctype == "Purchase Invoice" else "Sales Order"
- validate_inter_company_invoice(source_doc, doctype)
+ validate_inter_company_transaction(source_doc, doctype)
details = get_inter_company_details(source_doc, doctype)
def set_missing_values(source, target):
@@ -1352,7 +1371,7 @@ def make_inter_company_invoice(doctype, source_name, target_doc=None):
def update_details(source_doc, target_doc, source_parent):
target_doc.inter_company_invoice_reference = source_doc.name
- if target_doc.doctype == "Purchase Invoice":
+ if target_doc.doctype in ["Purchase Invoice", "Purchase Order"]:
target_doc.company = details.get("company")
target_doc.supplier = details.get("party")
target_doc.buying_price_list = source_doc.selling_price_list
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index 74c5f0ec1b..47c60839b3 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -18,6 +18,7 @@ from erpnext.accounts.doctype.account.test_account import get_inventory_account,
from erpnext.controllers.taxes_and_totals import get_itemised_tax_breakup_data
from erpnext.stock.doctype.item.test_item import create_item
from six import iteritems
+from erpnext.accounts.doctype.sales_invoice.sales_invoice import make_inter_company_transaction
class TestSalesInvoice(unittest.TestCase):
def make(self):
w = frappe.copy_doc(test_records[0])
@@ -1625,6 +1626,61 @@ class TestSalesInvoice(unittest.TestCase):
self.assertEqual(expected_gle[i][2], gle.credit)
self.assertEqual(getdate(expected_gle[i][3]), gle.posting_date)
+ def test_inter_company_transaction(self):
+
+ if not frappe.db.exists("Customer", "_Test Internal Customer"):
+ customer = frappe.get_doc({
+ "customer_group": "_Test Customer Group",
+ "customer_name": "_Test Internal Customer",
+ "customer_type": "Individual",
+ "doctype": "Customer",
+ "territory": "_Test Territory",
+ "is_internal_customer": 1,
+ "represents_company": "_Test Company 1"
+ })
+
+ customer.append("companies", {
+ "company": "Wind Power LLC"
+ })
+
+ customer.insert()
+
+ if not frappe.db.exists("Supplier", "_Test Internal Supplier"):
+ supplier = frappe.get_doc({
+ "supplier_group": "_Test Supplier Group",
+ "supplier_name": "_Test Internal Supplier",
+ "doctype": "Supplier",
+ "is_internal_supplier": 1,
+ "represents_company": "Wind Power LLC"
+ })
+
+ supplier.append("companies", {
+ "company": "_Test Company 1"
+ })
+
+ supplier.insert()
+
+ si = create_sales_invoice(
+ company = "Wind Power LLC",
+ customer = "_Test Internal Customer",
+ debit_to = "Debtors - WP",
+ warehouse = "Stores - WP",
+ income_account = "Sales - WP",
+ expense_account = "Cost of Goods Sold - WP",
+ cost_center = "Main - WP",
+ currency = "USD",
+ do_not_save = 1
+ )
+
+ si.selling_price_list = "_Test Price List Rest of the World"
+ si.submit()
+
+ target_doc = make_inter_company_transaction("Sales Invoice", si.name)
+ target_doc.submit()
+
+ self.assertEqual(target_doc.company, "_Test Company 1")
+ self.assertEqual(target_doc.supplier, "_Test Internal Supplier")
+
def create_sales_invoice(**args):
si = frappe.new_doc("Sales Invoice")
args = frappe._dict(args)
diff --git a/erpnext/accounts/report/financial_statements.py b/erpnext/accounts/report/financial_statements.py
index f358b4a205..48663cac7e 100644
--- a/erpnext/accounts/report/financial_statements.py
+++ b/erpnext/accounts/report/financial_statements.py
@@ -359,7 +359,8 @@ def set_gl_entries_by_account(
"from_date": from_date,
"to_date": to_date,
"cost_center": filters.cost_center,
- "project": filters.project
+ "project": filters.project,
+ "finance_book": filters.get("finance_book")
},
as_dict=True)
diff --git a/erpnext/accounts/report/share_ledger/share_ledger.json b/erpnext/accounts/report/share_ledger/share_ledger.json
index d374bb7747..fe158a6f00 100644
--- a/erpnext/accounts/report/share_ledger/share_ledger.json
+++ b/erpnext/accounts/report/share_ledger/share_ledger.json
@@ -1,23 +1,27 @@
{
"add_total_row": 0,
- "apply_user_permissions": 1,
"creation": "2017-12-27 16:15:52.615453",
+ "disable_prepared_report": 0,
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
- "modified": "2017-12-27 16:46:54.422356",
+ "modified": "2019-04-19 10:50:36.061588",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Share Ledger",
"owner": "Administrator",
+ "prepared_report": 0,
"ref_doctype": "Share Transfer",
"report_name": "Share Ledger",
"report_type": "Script Report",
"roles": [
{
"role": "Administrator"
+ },
+ {
+ "role": "System Manager"
}
]
}
\ No newline at end of file
diff --git a/erpnext/assets/doctype/asset/asset.js b/erpnext/assets/doctype/asset/asset.js
index e9a0f70b33..2d78d2693d 100644
--- a/erpnext/assets/doctype/asset/asset.js
+++ b/erpnext/assets/doctype/asset/asset.js
@@ -296,6 +296,12 @@ frappe.ui.form.on('Asset', {
frm.toggle_reqd("finance_books", frm.doc.calculate_depreciation);
},
+ gross_purchase_amount: function(frm) {
+ frm.doc.finance_books.forEach(d => {
+ frm.events.set_depreciation_rate(frm, d);
+ })
+ },
+
set_depreciation_rate: function(frm, row) {
if (row.total_number_of_depreciations && row.frequency_of_depreciation) {
frappe.call({
diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py
index 8011038b1b..72f5c627a7 100644
--- a/erpnext/assets/doctype/asset/asset.py
+++ b/erpnext/assets/doctype/asset/asset.py
@@ -101,7 +101,7 @@ class Asset(AccountsController):
def set_depreciation_rate(self):
for d in self.get("finance_books"):
- d.rate_of_depreciation = self.get_depreciation_rate(d)
+ d.rate_of_depreciation = self.get_depreciation_rate(d, on_validate=True)
def make_depreciation_schedule(self):
depreciation_method = [d.depreciation_method for d in self.finance_books]
@@ -125,7 +125,7 @@ class Asset(AccountsController):
no_of_depreciations * cint(d.frequency_of_depreciation))
total_days = date_diff(end_date, self.available_for_use_date)
- rate_per_day = value_after_depreciation / total_days
+ rate_per_day = (value_after_depreciation - d.get("expected_value_after_useful_life")) / total_days
number_of_pending_depreciations = cint(d.total_number_of_depreciations) - \
cint(self.number_of_depreciations_booked)
@@ -291,8 +291,8 @@ class Asset(AccountsController):
def validate_expected_value_after_useful_life(self):
for row in self.get('finance_books'):
- accumulated_depreciation_after_full_schedule = \
- max([d.accumulated_depreciation_amount for d in self.get("schedules") if d.finance_book_id == row.idx])
+ accumulated_depreciation_after_full_schedule = max([d.accumulated_depreciation_amount
+ for d in self.get("schedules") if cint(d.finance_book_id) == row.idx])
asset_value_after_full_schedule = flt(flt(self.gross_purchase_amount) -
flt(accumulated_depreciation_after_full_schedule),
@@ -403,7 +403,7 @@ class Asset(AccountsController):
make_gl_entries(gl_entries)
self.db_set('booked_fixed_asset', 1)
- def get_depreciation_rate(self, args):
+ def get_depreciation_rate(self, args, on_validate=False):
if isinstance(args, string_types):
args = json.loads(args)
@@ -420,7 +420,10 @@ class Asset(AccountsController):
if args.get("depreciation_method") == 'Double Declining Balance':
return 200.0 / args.get("total_number_of_depreciations")
- if args.get("depreciation_method") == "Written Down Value" and not args.get("rate_of_depreciation"):
+ if args.get("depreciation_method") == "Written Down Value":
+ if args.get("rate_of_depreciation") and on_validate:
+ return args.get("rate_of_depreciation")
+
no_of_years = flt(args.get("total_number_of_depreciations") * flt(args.get("frequency_of_depreciation"))) / 12
value = flt(args.get("expected_value_after_useful_life")) / flt(self.gross_purchase_amount)
diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py
index 985097b447..ef85ffa1cb 100644
--- a/erpnext/assets/doctype/asset/test_asset.py
+++ b/erpnext/assets/doctype/asset/test_asset.py
@@ -102,9 +102,9 @@ class TestAsset(unittest.TestCase):
asset.save()
self.assertEqual(asset.status, "Draft")
expected_schedules = [
- ["2020-06-06", 163.93, 163.93],
- ["2021-04-06", 49836.07, 50000.0],
- ["2022-02-06", 40000.0, 90000.00]
+ ["2020-06-06", 147.54, 147.54],
+ ["2021-04-06", 44852.46, 45000.0],
+ ["2022-02-06", 45000.0, 90000.00]
]
schedules = [[cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount]
@@ -130,8 +130,8 @@ class TestAsset(unittest.TestCase):
self.assertEqual(asset.status, "Draft")
asset.save()
expected_schedules = [
- ["2020-06-06", 197.37, 40197.37],
- ["2021-04-06", 49802.63, 90000.00]
+ ["2020-06-06", 164.47, 40164.47],
+ ["2021-04-06", 49835.53, 90000.00]
]
schedules = [[cstr(d.schedule_date), flt(d.depreciation_amount, 2), d.accumulated_depreciation_amount]
for d in asset.get("schedules")]
@@ -266,8 +266,8 @@ class TestAsset(unittest.TestCase):
self.assertEqual(asset.get("schedules")[0].journal_entry[:4], "DEPR")
expected_gle = (
- ("_Test Accumulated Depreciations - _TC", 0.0, 35699.15),
- ("_Test Depreciations - _TC", 35699.15, 0.0)
+ ("_Test Accumulated Depreciations - _TC", 0.0, 32129.24),
+ ("_Test Depreciations - _TC", 32129.24, 0.0)
)
gle = frappe.db.sql("""select account, debit, credit from `tabGL Entry`
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js
index 28ceab5918..e63ef605b0 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.js
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.js
@@ -138,6 +138,20 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
erpnext.utils.make_subscription(doc.doctype, doc.name)
}, __('Create'))
}
+
+ if (doc.docstatus === 1 && !doc.inter_company_order_reference) {
+ let me = this;
+ frappe.model.with_doc("Supplier", me.frm.doc.supplier, () => {
+ let supplier = frappe.model.get_doc("Supplier", me.frm.doc.supplier);
+ let internal = supplier.is_internal_supplier;
+ let disabled = supplier.disabled;
+ if (internal === 1 && disabled === 0) {
+ me.frm.add_custom_button("Inter Company Order", function() {
+ me.make_inter_company_order(me.frm);
+ }, __('Create'));
+ }
+ });
+ }
}
if(flt(doc.per_billed)==0) {
this.frm.add_custom_button(__('Payment Request'),
@@ -296,6 +310,13 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
});
},
+ make_inter_company_order: function(frm) {
+ frappe.model.open_mapped_doc({
+ method: "erpnext.buying.doctype.purchase_order.purchase_order.make_inter_company_sales_order",
+ frm: frm
+ });
+ },
+
make_purchase_receipt: function() {
frappe.model.open_mapped_doc({
method: "erpnext.buying.doctype.purchase_order.purchase_order.make_purchase_receipt",
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json
index 46f48fb2d7..13a097a0d7 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.json
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.json
@@ -298,6 +298,7 @@
"collapsible": 0,
"columns": 0,
"default": "Today",
+ "fetch_if_empty": 0,
"fieldname": "transaction_date",
"fieldtype": "Date",
"hidden": 0,
@@ -332,6 +333,7 @@
"collapsible": 0,
"columns": 0,
"default": "",
+ "fetch_if_empty": 0,
"fieldname": "schedule_date",
"fieldtype": "Date",
"hidden": 0,
@@ -365,6 +367,7 @@
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.docstatus===1",
+ "fetch_if_empty": 0,
"fieldname": "order_confirmation_no",
"fieldtype": "Data",
"hidden": 0,
@@ -398,6 +401,7 @@
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.order_confirmation_no",
+ "fetch_if_empty": 0,
"fieldname": "order_confirmation_date",
"fieldtype": "Date",
"hidden": 0,
@@ -430,6 +434,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "amended_from",
"fieldtype": "Link",
"hidden": 0,
@@ -465,6 +470,7 @@
"collapsible": 0,
"collapsible_depends_on": "",
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "drop_ship",
"fieldtype": "Section Break",
"hidden": 0,
@@ -498,6 +504,7 @@
"collapsible": 0,
"columns": 0,
"depends_on": "",
+ "fetch_if_empty": 0,
"fieldname": "customer",
"fieldtype": "Link",
"hidden": 0,
@@ -532,6 +539,7 @@
"collapsible": 0,
"columns": 0,
"depends_on": "",
+ "fetch_if_empty": 0,
"fieldname": "customer_name",
"fieldtype": "Data",
"hidden": 0,
@@ -564,6 +572,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "column_break_19",
"fieldtype": "Column Break",
"hidden": 0,
@@ -596,6 +605,7 @@
"collapsible": 0,
"columns": 0,
"depends_on": "",
+ "fetch_if_empty": 0,
"fieldname": "customer_contact_person",
"fieldtype": "Link",
"hidden": 0,
@@ -629,6 +639,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "customer_contact_display",
"fieldtype": "Small Text",
"hidden": 1,
@@ -661,6 +672,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "customer_contact_mobile",
"fieldtype": "Small Text",
"hidden": 1,
@@ -693,6 +705,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "customer_contact_email",
"fieldtype": "Code",
"hidden": 1,
@@ -726,6 +739,7 @@
"bold": 0,
"collapsible": 1,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "section_addresses",
"fieldtype": "Section Break",
"hidden": 0,
@@ -758,6 +772,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "supplier_address",
"fieldtype": "Link",
"hidden": 0,
@@ -790,6 +805,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "contact_person",
"fieldtype": "Link",
"hidden": 0,
@@ -823,6 +839,7 @@
"collapsible": 0,
"columns": 0,
"depends_on": "",
+ "fetch_if_empty": 0,
"fieldname": "address_display",
"fieldtype": "Small Text",
"hidden": 0,
@@ -854,6 +871,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "contact_display",
"fieldtype": "Small Text",
"hidden": 0,
@@ -885,6 +903,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "contact_mobile",
"fieldtype": "Small Text",
"hidden": 0,
@@ -916,6 +935,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "contact_email",
"fieldtype": "Small Text",
"hidden": 0,
@@ -947,6 +967,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "col_break_address",
"fieldtype": "Column Break",
"hidden": 0,
@@ -979,6 +1000,7 @@
"collapsible": 0,
"columns": 0,
"depends_on": "",
+ "fetch_if_empty": 0,
"fieldname": "shipping_address",
"fieldtype": "Link",
"hidden": 0,
@@ -1012,6 +1034,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "shipping_address_display",
"fieldtype": "Small Text",
"hidden": 0,
@@ -1044,6 +1067,7 @@
"bold": 0,
"collapsible": 1,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "currency_and_price_list",
"fieldtype": "Section Break",
"hidden": 0,
@@ -1076,6 +1100,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "currency",
"fieldtype": "Link",
"hidden": 0,
@@ -1111,6 +1136,7 @@
"collapsible": 0,
"columns": 0,
"description": "",
+ "fetch_if_empty": 0,
"fieldname": "conversion_rate",
"fieldtype": "Float",
"hidden": 0,
@@ -1145,6 +1171,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "cb_price_list",
"fieldtype": "Column Break",
"hidden": 0,
@@ -1175,6 +1202,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "buying_price_list",
"fieldtype": "Link",
"hidden": 0,
@@ -1207,6 +1235,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "price_list_currency",
"fieldtype": "Link",
"hidden": 0,
@@ -1239,6 +1268,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "plc_conversion_rate",
"fieldtype": "Float",
"hidden": 0,
@@ -1271,6 +1301,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "ignore_pricing_rule",
"fieldtype": "Check",
"hidden": 0,
@@ -1302,6 +1333,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "sec_warehouse",
"fieldtype": "Section Break",
"hidden": 0,
@@ -1333,6 +1365,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "set_warehouse",
"fieldtype": "Link",
"hidden": 0,
@@ -1366,6 +1399,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "col_break_warehouse",
"fieldtype": "Column Break",
"hidden": 0,
@@ -1398,6 +1432,7 @@
"collapsible": 0,
"columns": 0,
"default": "No",
+ "fetch_if_empty": 0,
"fieldname": "is_subcontracted",
"fieldtype": "Select",
"hidden": 0,
@@ -1431,6 +1466,7 @@
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.is_subcontracted==\"Yes\"",
+ "fetch_if_empty": 0,
"fieldname": "supplier_warehouse",
"fieldtype": "Link",
"hidden": 0,
@@ -1464,6 +1500,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "items_section",
"fieldtype": "Section Break",
"hidden": 0,
@@ -1497,6 +1534,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "scan_barcode",
"fieldtype": "Data",
"hidden": 0,
@@ -1529,6 +1567,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "items",
"fieldtype": "Table",
"hidden": 0,
@@ -1563,6 +1602,7 @@
"bold": 0,
"collapsible": 1,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "section_break_48",
"fieldtype": "Section Break",
"hidden": 0,
@@ -1596,6 +1636,7 @@
"collapsible": 0,
"collapsible_depends_on": "",
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "pricing_rules",
"fieldtype": "Table",
"hidden": 0,
@@ -1630,6 +1671,7 @@
"collapsible": 0,
"collapsible_depends_on": "supplied_items",
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "raw_material_details",
"fieldtype": "Section Break",
"hidden": 0,
@@ -1663,6 +1705,7 @@
"collapsible": 0,
"columns": 0,
"depends_on": "",
+ "fetch_if_empty": 0,
"fieldname": "supplied_items",
"fieldtype": "Table",
"hidden": 0,
@@ -1697,6 +1740,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "sb_last_purchase",
"fieldtype": "Section Break",
"hidden": 0,
@@ -1727,6 +1771,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "total_qty",
"fieldtype": "Float",
"hidden": 0,
@@ -1759,6 +1804,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "base_total",
"fieldtype": "Currency",
"hidden": 0,
@@ -1792,6 +1838,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "base_net_total",
"fieldtype": "Currency",
"hidden": 0,
@@ -1826,6 +1873,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "column_break_26",
"fieldtype": "Column Break",
"hidden": 0,
@@ -1856,6 +1904,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "total",
"fieldtype": "Currency",
"hidden": 0,
@@ -1889,6 +1938,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "net_total",
"fieldtype": "Currency",
"hidden": 0,
@@ -1923,6 +1973,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "total_net_weight",
"fieldtype": "Float",
"hidden": 0,
@@ -1955,6 +2006,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "taxes_section",
"fieldtype": "Section Break",
"hidden": 0,
@@ -1989,6 +2041,7 @@
"collapsible": 0,
"columns": 0,
"description": "",
+ "fetch_if_empty": 0,
"fieldname": "taxes_and_charges",
"fieldtype": "Link",
"hidden": 0,
@@ -2023,6 +2076,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "column_break_50",
"fieldtype": "Column Break",
"hidden": 0,
@@ -2054,6 +2108,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "shipping_rule",
"fieldtype": "Link",
"hidden": 0,
@@ -2087,6 +2142,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "section_break_52",
"fieldtype": "Section Break",
"hidden": 0,
@@ -2118,6 +2174,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "taxes",
"fieldtype": "Table",
"hidden": 0,
@@ -2152,6 +2209,7 @@
"bold": 0,
"collapsible": 1,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "sec_tax_breakup",
"fieldtype": "Section Break",
"hidden": 0,
@@ -2184,6 +2242,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "other_charges_calculation",
"fieldtype": "Text",
"hidden": 0,
@@ -2216,6 +2275,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "totals",
"fieldtype": "Section Break",
"hidden": 0,
@@ -2249,6 +2309,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "base_taxes_and_charges_added",
"fieldtype": "Currency",
"hidden": 0,
@@ -2283,6 +2344,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "base_taxes_and_charges_deducted",
"fieldtype": "Currency",
"hidden": 0,
@@ -2317,6 +2379,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "base_total_taxes_and_charges",
"fieldtype": "Currency",
"hidden": 0,
@@ -2351,6 +2414,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "column_break_39",
"fieldtype": "Column Break",
"hidden": 0,
@@ -2382,6 +2446,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "taxes_and_charges_added",
"fieldtype": "Currency",
"hidden": 0,
@@ -2416,6 +2481,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "taxes_and_charges_deducted",
"fieldtype": "Currency",
"hidden": 0,
@@ -2450,6 +2516,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "total_taxes_and_charges",
"fieldtype": "Currency",
"hidden": 0,
@@ -2484,6 +2551,7 @@
"collapsible": 1,
"collapsible_depends_on": "discount_amount",
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "discount_section",
"fieldtype": "Section Break",
"hidden": 0,
@@ -2517,6 +2585,7 @@
"collapsible": 0,
"columns": 0,
"default": "Grand Total",
+ "fetch_if_empty": 0,
"fieldname": "apply_discount_on",
"fieldtype": "Select",
"hidden": 0,
@@ -2550,6 +2619,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "base_discount_amount",
"fieldtype": "Currency",
"hidden": 0,
@@ -2583,6 +2653,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "column_break_45",
"fieldtype": "Column Break",
"hidden": 0,
@@ -2614,6 +2685,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "additional_discount_percentage",
"fieldtype": "Float",
"hidden": 0,
@@ -2646,6 +2718,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "discount_amount",
"fieldtype": "Currency",
"hidden": 0,
@@ -2679,6 +2752,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "totals_section",
"fieldtype": "Section Break",
"hidden": 0,
@@ -2710,6 +2784,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "base_grand_total",
"fieldtype": "Currency",
"hidden": 0,
@@ -2744,6 +2819,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "base_rounding_adjustment",
"fieldtype": "Currency",
"hidden": 0,
@@ -2778,6 +2854,7 @@
"collapsible": 0,
"columns": 0,
"description": "In Words will be visible once you save the Purchase Order.",
+ "fetch_if_empty": 0,
"fieldname": "base_in_words",
"fieldtype": "Data",
"hidden": 0,
@@ -2811,6 +2888,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "base_rounded_total",
"fieldtype": "Currency",
"hidden": 0,
@@ -2845,6 +2923,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "column_break4",
"fieldtype": "Column Break",
"hidden": 0,
@@ -2876,6 +2955,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "grand_total",
"fieldtype": "Currency",
"hidden": 0,
@@ -2910,6 +2990,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "rounding_adjustment",
"fieldtype": "Currency",
"hidden": 0,
@@ -2943,6 +3024,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "rounded_total",
"fieldtype": "Currency",
"hidden": 0,
@@ -2975,6 +3057,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "disable_rounded_total",
"fieldtype": "Check",
"hidden": 0,
@@ -3007,6 +3090,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "in_words",
"fieldtype": "Data",
"hidden": 0,
@@ -3040,6 +3124,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "advance_paid",
"fieldtype": "Currency",
"hidden": 0,
@@ -3072,6 +3157,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "payment_schedule_section",
"fieldtype": "Section Break",
"hidden": 0,
@@ -3104,6 +3190,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "payment_terms_template",
"fieldtype": "Link",
"hidden": 0,
@@ -3137,6 +3224,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "payment_schedule",
"fieldtype": "Table",
"hidden": 0,
@@ -3171,6 +3259,7 @@
"collapsible": 1,
"collapsible_depends_on": "terms",
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "terms_section_break",
"fieldtype": "Section Break",
"hidden": 0,
@@ -3204,6 +3293,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "tc_name",
"fieldtype": "Link",
"hidden": 0,
@@ -3238,6 +3328,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "terms",
"fieldtype": "Text Editor",
"hidden": 0,
@@ -3271,6 +3362,7 @@
"bold": 0,
"collapsible": 1,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "more_info",
"fieldtype": "Section Break",
"hidden": 0,
@@ -3304,6 +3396,7 @@
"collapsible": 0,
"columns": 0,
"default": "Draft",
+ "fetch_if_empty": 0,
"fieldname": "status",
"fieldtype": "Select",
"hidden": 0,
@@ -3338,6 +3431,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "ref_sq",
"fieldtype": "Data",
"hidden": 1,
@@ -3371,6 +3465,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "party_account_currency",
"fieldtype": "Link",
"hidden": 1,
@@ -3404,6 +3499,41 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "inter_company_order_reference",
+ "fieldtype": "Link",
+ "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": "Inter Company Order Reference",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Sales Order",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "column_break_74",
"fieldtype": "Column Break",
"hidden": 0,
@@ -3437,6 +3567,7 @@
"columns": 0,
"depends_on": "eval:!doc.__islocal",
"description": "",
+ "fetch_if_empty": 0,
"fieldname": "per_received",
"fieldtype": "Percent",
"hidden": 0,
@@ -3472,6 +3603,7 @@
"columns": 0,
"depends_on": "eval:!doc.__islocal",
"description": "",
+ "fetch_if_empty": 0,
"fieldname": "per_billed",
"fieldtype": "Percent",
"hidden": 0,
@@ -3505,6 +3637,7 @@
"bold": 0,
"collapsible": 1,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "column_break5",
"fieldtype": "Section Break",
"hidden": 0,
@@ -3906,17 +4039,15 @@
}
],
"has_web_view": 0,
- "hide_heading": 0,
"hide_toolbar": 0,
"icon": "fa fa-file-text",
"idx": 105,
- "image_view": 0,
"in_create": 0,
"is_submittable": 1,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2019-02-14 19:36:49.390935",
+ "modified": "2019-04-18 19:43:17.239390",
"modified_by": "Administrator",
"module": "Buying",
"name": "Purchase Order",
@@ -4001,7 +4132,6 @@
],
"quick_entry": 0,
"read_only": 0,
- "read_only_onload": 1,
"search_fields": "status, transaction_date, supplier,grand_total",
"show_name_in_global_search": 1,
"sort_field": "modified",
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py
index 1c3469ec58..4353976ba1 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.py
@@ -17,6 +17,8 @@ from erpnext.accounts.party import get_party_account_currency
from six import string_types
from erpnext.stock.doctype.item.item import get_item_defaults
from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults
+from erpnext.accounts.doctype.sales_invoice.sales_invoice import validate_inter_company_party, update_linked_doc,\
+ unlink_inter_company_doc
form_grid_templates = {
"items": "templates/form_grid/item_grid.html"
@@ -56,6 +58,7 @@ class PurchaseOrder(BuyingController):
self.validate_bom_for_subcontracting_items()
self.create_raw_materials_supplied("supplied_items")
self.set_received_qty_for_drop_ship_items()
+ validate_inter_company_party(self.doctype, self.supplier, self.company, self.inter_company_order_reference)
def validate_with_previous_doc(self):
super(PurchaseOrder, self).validate_with_previous_doc({
@@ -219,6 +222,7 @@ class PurchaseOrder(BuyingController):
self.update_blanket_order()
+ update_linked_doc(self.doctype, self.name, self.inter_company_order_reference)
def on_cancel(self):
super(PurchaseOrder, self).on_cancel()
@@ -244,6 +248,7 @@ class PurchaseOrder(BuyingController):
self.update_blanket_order()
+ unlink_inter_company_doc(self.doctype, self.name, self.inter_company_order_reference)
def on_update(self):
pass
@@ -492,3 +497,9 @@ def update_status(status, name):
po = frappe.get_doc("Purchase Order", name)
po.update_status(status)
po.update_delivered_qty_in_sales_order()
+
+@frappe.whitelist()
+def make_inter_company_sales_order(source_name, target_doc=None):
+ from erpnext.accounts.doctype.sales_invoice.sales_invoice import make_inter_company_transaction
+ return make_inter_company_transaction("Purchase Order", source_name, target_doc)
+
diff --git a/erpnext/config/accounting.py b/erpnext/config/accounting.py
index 1b8bf2717b..6664c4d4af 100644
--- a/erpnext/config/accounting.py
+++ b/erpnext/config/accounting.py
@@ -78,6 +78,11 @@ def get_data():
"name": "Payment Entry",
"description": _("Bank/Cash transactions against party or for internal transfer")
},
+ {
+ "type": "doctype",
+ "name": "Payment Term",
+ "description": _("Payment Terms based on conditions")
+ },
# Reports
{
@@ -131,6 +136,11 @@ def get_data():
"name": "Currency Exchange",
"description": _("Currency exchange rate master.")
},
+ {
+ "type": "doctype",
+ "name": "Exchange Rate Revaluation",
+ "description": _("Exchange Rate Revaluation master.")
+ },
{
"type": "doctype",
"name": "Payment Gateway Account",
diff --git a/erpnext/config/education.py b/erpnext/config/education.py
index d5f9e2dca4..4efaaa65cd 100644
--- a/erpnext/config/education.py
+++ b/erpnext/config/education.py
@@ -33,6 +33,10 @@ def get_data():
"type": "doctype",
"name": "Student Applicant"
},
+ {
+ "type": "doctype",
+ "name": "Web Academy Applicant"
+ },
{
"type": "doctype",
"name": "Student Admission"
@@ -180,6 +184,10 @@ def get_data():
{
"label": _("Masters"),
"items": [
+ {
+ "type": "doctype",
+ "name": "Program",
+ },
{
"type": "doctype",
"name": "Course",
@@ -187,7 +195,7 @@ def get_data():
},
{
"type": "doctype",
- "name": "Program"
+ "name": "Topic",
},
{
"type": "doctype",
@@ -201,6 +209,40 @@ def get_data():
}
]
},
+ {
+ "label": _("Content Masters"),
+ "items": [
+ {
+ "type": "doctype",
+ "name": "Article"
+ },
+ {
+ "type": "doctype",
+ "name": "Video"
+ },
+ {
+ "type": "doctype",
+ "name": "Quiz"
+ }
+ ]
+ },
+ {
+ "label": _("LMS Activity"),
+ "items": [
+ {
+ "type": "doctype",
+ "name": "Course Enrollment"
+ },
+ {
+ "type": "doctype",
+ "name": "Course Activity"
+ },
+ {
+ "type": "doctype",
+ "name": "Quiz Activity"
+ }
+ ]
+ },
{
"label": _("Settings"),
"items": [
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 63ea2591c5..155a996a15 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -89,7 +89,8 @@ class AccountsController(TransactionBase):
self.validate_paid_amount()
if self.doctype in ['Purchase Invoice', 'Sales Invoice']:
- if cint(self.allocate_advances_automatically):
+ pos_check_field = "is_pos" if self.doctype=="Sales Invoice" else "is_paid"
+ if cint(self.allocate_advances_automatically) and not cint(self.get(pos_check_field)):
self.set_advances()
if self.is_return:
diff --git a/erpnext/crm/doctype/lead/lead.py b/erpnext/crm/doctype/lead/lead.py
index 442b6c2db2..d42502dc3b 100644
--- a/erpnext/crm/doctype/lead/lead.py
+++ b/erpnext/crm/doctype/lead/lead.py
@@ -10,6 +10,7 @@ from frappe.model.mapper import get_mapped_doc
from erpnext.controllers.selling_controller import SellingController
from frappe.contacts.address_and_contact import load_address_and_contact
from erpnext.accounts.party import set_taxes
+from frappe.email.inbox import link_communication_to_document
sender_field = "email_id"
@@ -199,3 +200,29 @@ def get_lead_details(lead, posting_date=None, company=None):
out['taxes_and_charges'] = taxes_and_charges
return out
+
+@frappe.whitelist()
+def make_lead_from_communication(communication, ignore_communication_links=False):
+ """ raise a issue from email """
+
+ doc = frappe.get_doc("Communication", communication)
+ lead_name = None
+ if doc.sender:
+ lead_name = frappe.db.get_value("Lead", {"email_id": doc.sender})
+ if not lead_name and doc.phone_no:
+ lead_name = frappe.db.get_value("Lead", {"mobile_no": doc.phone_no})
+ if not lead_name:
+ lead = frappe.get_doc({
+ "doctype": "Lead",
+ "lead_name": doc.sender_full_name,
+ "email_id": doc.sender,
+ "mobile_no": doc.phone_no
+ })
+ lead.flags.ignore_mandatory = True
+ lead.flags.ignore_permissions = True
+ lead.insert()
+
+ lead_name = lead.name
+
+ link_communication_to_document(doc, "Lead", lead_name, ignore_communication_links)
+ return lead_name
\ No newline at end of file
diff --git a/erpnext/crm/doctype/opportunity/opportunity.py b/erpnext/crm/doctype/opportunity/opportunity.py
index 2e02e75b73..4d4593641a 100644
--- a/erpnext/crm/doctype/opportunity/opportunity.py
+++ b/erpnext/crm/doctype/opportunity/opportunity.py
@@ -10,6 +10,7 @@ from erpnext.setup.utils import get_exchange_rate
from erpnext.utilities.transaction_base import TransactionBase
from erpnext.accounts.party import get_party_account_currency
from frappe.desk.form import assign_to
+from frappe.email.inbox import link_communication_to_document
subject_field = "title"
sender_field = "contact_email"
@@ -349,3 +350,23 @@ def assign_to_user(doc, subject_field):
"name": doc.name,
"description": doc.get(subject_field)
})
+@frappe.whitelist()
+def make_opportunity_from_communication(communication, ignore_communication_links=False):
+ from erpnext.crm.doctype.lead.lead import make_lead_from_communication
+ doc = frappe.get_doc("Communication", communication)
+
+ lead = doc.reference_name if doc.reference_doctype == "Lead" else None
+ if not lead:
+ lead = make_lead_from_communication(communication, ignore_communication_links=True)
+
+ enquiry_from = "Lead"
+
+ opportunity = frappe.get_doc({
+ "doctype": "Opportunity",
+ "enquiry_from": enquiry_from,
+ "lead": lead
+ }).insert(ignore_permissions=True)
+
+ link_communication_to_document(doc, "Opportunity", opportunity.name, ignore_communication_links)
+
+ return opportunity.name
diff --git a/erpnext/domains/education.py b/erpnext/domains/education.py
index c640576457..55e4eed801 100644
--- a/erpnext/domains/education.py
+++ b/erpnext/domains/education.py
@@ -14,7 +14,7 @@ data = {
'Student Attendance Tool',
'Student Applicant'
],
- 'default_portal_role': 'Guardian',
+ 'default_portal_role': 'LMS User',
'restricted_roles': [
'Student',
'Instructor',
diff --git a/erpnext/education/api.py b/erpnext/education/api.py
index 30d5588073..1a19716b50 100644
--- a/erpnext/education/api.py
+++ b/erpnext/education/api.py
@@ -38,7 +38,7 @@ def enroll_student(source_name):
program_enrollment.student = student.name
program_enrollment.student_name = student.title
program_enrollment.program = frappe.db.get_value("Student Applicant", source_name, "program")
- frappe.publish_realtime('enroll_student_progress', {"progress": [4, 4]}, user=frappe.session.user)
+ frappe.publish_realtime('enroll_student_progress', {"progress": [2, 4]}, user=frappe.session.user)
return program_enrollment
@@ -69,7 +69,7 @@ def mark_attendance(students_present, students_absent, course_schedule=None, stu
present = json.loads(students_present)
absent = json.loads(students_absent)
-
+
for d in present:
make_attendance_records(d["student"], d["student_name"], "Present", course_schedule, student_group, date)
@@ -89,7 +89,7 @@ def make_attendance_records(student, student_name, status, course_schedule=None,
:param status: Status (Present/Absent)
"""
student_attendance = frappe.get_doc({
- "doctype": "Student Attendance",
+ "doctype": "Student Attendance",
"student": student,
"course_schedule": course_schedule,
"student_group": student_group,
@@ -112,7 +112,7 @@ def get_student_guardians(student):
:param student: Student.
"""
- guardians = frappe.get_list("Student Guardian", fields=["guardian"] ,
+ guardians = frappe.get_list("Student Guardian", fields=["guardian"] ,
filters={"parent": student})
return guardians
@@ -353,7 +353,7 @@ def update_email_group(doctype, name):
for guard in get_student_guardians(stud.student):
email = frappe.db.get_value("Guardian", guard.guardian, "email_address")
if email:
- email_list.append(email)
+ email_list.append(email)
add_subscribers(name, email_list)
@frappe.whitelist()
diff --git a/erpnext/education/doctype/article/__init__.py b/erpnext/education/doctype/article/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/education/doctype/article/article.js b/erpnext/education/doctype/article/article.js
new file mode 100644
index 0000000000..4c9c6f01f0
--- /dev/null
+++ b/erpnext/education/doctype/article/article.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Article', {
+ refresh: function(frm) {
+
+ }
+});
diff --git a/erpnext/education/doctype/article/article.json b/erpnext/education/doctype/article/article.json
new file mode 100644
index 0000000000..c30cd189d6
--- /dev/null
+++ b/erpnext/education/doctype/article/article.json
@@ -0,0 +1,230 @@
+{
+ "allow_copy": 0,
+ "allow_events_in_timeline": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 1,
+ "allow_rename": 0,
+ "autoname": "field:title",
+ "beta": 0,
+ "creation": "2018-10-17 05:45:38.471670",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 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,
+ "translatable": 0,
+ "unique": 1
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "author",
+ "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": "Author",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "content",
+ "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": "Content",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "publish_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": "Publish Date",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ }
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2018-11-25 19:06:56.016865",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Article",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "amend": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Academics User",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ },
+ {
+ "amend": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Instructor",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ },
+ {
+ "amend": 0,
+ "cancel": 0,
+ "create": 0,
+ "delete": 0,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "LMS User",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 0
+ }
+ ],
+ "quick_entry": 1,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 0,
+ "track_views": 0
+}
\ No newline at end of file
diff --git a/erpnext/education/doctype/article/article.py b/erpnext/education/doctype/article/article.py
new file mode 100644
index 0000000000..7dc850be37
--- /dev/null
+++ b/erpnext/education/doctype/article/article.py
@@ -0,0 +1,15 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe.model.document import Document
+
+class Article(Document):
+
+
+ def get_article(self):
+ pass
+
+
diff --git a/erpnext/education/doctype/article/test_article.js b/erpnext/education/doctype/article/test_article.js
new file mode 100644
index 0000000000..9dbf063e84
--- /dev/null
+++ b/erpnext/education/doctype/article/test_article.js
@@ -0,0 +1,23 @@
+/* eslint-disable */
+// rename this file from _test_[name] to test_[name] to activate
+// and remove above this line
+
+QUnit.test("test: Article", function (assert) {
+ let done = assert.async();
+
+ // number of asserts
+ assert.expect(1);
+
+ frappe.run_serially([
+ // insert a new Article
+ () => frappe.tests.make('Article', [
+ // values to be set
+ {key: 'value'}
+ ]),
+ () => {
+ assert.equal(cur_frm.doc.key, 'value');
+ },
+ () => done()
+ ]);
+
+});
diff --git a/erpnext/education/doctype/article/test_article.py b/erpnext/education/doctype/article/test_article.py
new file mode 100644
index 0000000000..2fce07f82c
--- /dev/null
+++ b/erpnext/education/doctype/article/test_article.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+
+class TestArticle(unittest.TestCase):
+ pass
diff --git a/erpnext/education/doctype/content_activity/__init__.py b/erpnext/education/doctype/content_activity/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/education/doctype/content_activity/content_activity.json b/erpnext/education/doctype/content_activity/content_activity.json
new file mode 100644
index 0000000000..b4c95dad9c
--- /dev/null
+++ b/erpnext/education/doctype/content_activity/content_activity.json
@@ -0,0 +1,141 @@
+{
+ "allow_copy": 0,
+ "allow_events_in_timeline": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "beta": 0,
+ "creation": "2018-10-16 03:55:53.283893",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "content",
+ "fieldtype": "Link",
+ "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": "Content",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Content",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_from": "content.content_type",
+ "fieldname": "content_type",
+ "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": "Content Type",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "last_activity",
+ "fieldtype": "Datetime",
+ "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": "Last Activity ",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ }
+ ],
+ "has_web_view": 0,
+ "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-10-16 03:55:58.202436",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Content Activity",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 0,
+ "track_views": 0
+}
\ No newline at end of file
diff --git a/erpnext/education/doctype/content_activity/content_activity.py b/erpnext/education/doctype/content_activity/content_activity.py
new file mode 100644
index 0000000000..2ae7a5c94c
--- /dev/null
+++ b/erpnext/education/doctype/content_activity/content_activity.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe.model.document import Document
+
+class ContentActivity(Document):
+ pass
diff --git a/erpnext/education/doctype/content_question/__init__.py b/erpnext/education/doctype/content_question/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/education/doctype/content_question/content_question.js b/erpnext/education/doctype/content_question/content_question.js
new file mode 100644
index 0000000000..7615f5efcf
--- /dev/null
+++ b/erpnext/education/doctype/content_question/content_question.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Content Question', {
+ refresh: function(frm) {
+
+ }
+});
diff --git a/erpnext/education/doctype/content_question/content_question.json b/erpnext/education/doctype/content_question/content_question.json
new file mode 100644
index 0000000000..d390e8ef70
--- /dev/null
+++ b/erpnext/education/doctype/content_question/content_question.json
@@ -0,0 +1,76 @@
+{
+ "allow_copy": 0,
+ "allow_events_in_timeline": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "beta": 0,
+ "creation": "2018-10-15 14:35:40.728454",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "question_link",
+ "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": "Question Link",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Question",
+ "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,
+ "translatable": 0,
+ "unique": 0
+ }
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 1,
+ "max_attachments": 0,
+ "modified": "2018-10-15 14:41:31.729083",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Content Question",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 0,
+ "track_views": 0
+}
\ No newline at end of file
diff --git a/erpnext/education/doctype/content_question/content_question.py b/erpnext/education/doctype/content_question/content_question.py
new file mode 100644
index 0000000000..b239d211a3
--- /dev/null
+++ b/erpnext/education/doctype/content_question/content_question.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe.model.document import Document
+
+class ContentQuestion(Document):
+ pass
diff --git a/erpnext/education/doctype/content_question/test_content_question.js b/erpnext/education/doctype/content_question/test_content_question.js
new file mode 100644
index 0000000000..cc869a87fc
--- /dev/null
+++ b/erpnext/education/doctype/content_question/test_content_question.js
@@ -0,0 +1,23 @@
+/* eslint-disable */
+// rename this file from _test_[name] to test_[name] to activate
+// and remove above this line
+
+QUnit.test("test: Content Question", function (assert) {
+ let done = assert.async();
+
+ // number of asserts
+ assert.expect(1);
+
+ frappe.run_serially([
+ // insert a new Content Question
+ () => frappe.tests.make('Content Question', [
+ // values to be set
+ {key: 'value'}
+ ]),
+ () => {
+ assert.equal(cur_frm.doc.key, 'value');
+ },
+ () => done()
+ ]);
+
+});
diff --git a/erpnext/education/doctype/content_question/test_content_question.py b/erpnext/education/doctype/content_question/test_content_question.py
new file mode 100644
index 0000000000..268b9be2e7
--- /dev/null
+++ b/erpnext/education/doctype/content_question/test_content_question.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+
+class TestContentQuestion(unittest.TestCase):
+ pass
diff --git a/erpnext/education/doctype/course/course.json b/erpnext/education/doctype/course/course.json
index 15360f8d58..072e8b4afb 100644
--- a/erpnext/education/doctype/course/course.json
+++ b/erpnext/education/doctype/course/course.json
@@ -1,5 +1,6 @@
{
"allow_copy": 0,
+ "allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 1,
@@ -15,10 +16,12 @@
"fields": [
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "course_name",
"fieldtype": "Data",
"hidden": 0,
@@ -41,14 +44,17 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "department",
"fieldtype": "Link",
"hidden": 0,
@@ -72,14 +78,17 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "parent_course",
"fieldtype": "Data",
"hidden": 0,
@@ -102,14 +111,17 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "column_break_3",
"fieldtype": "Column Break",
"hidden": 0,
@@ -131,14 +143,17 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "course_code",
"fieldtype": "Data",
"hidden": 0,
@@ -161,14 +176,17 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
- "unique": 0
+ "translatable": 0,
+ "unique": 1
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "course_abbreviation",
"fieldtype": "Data",
"hidden": 0,
@@ -191,14 +209,17 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "section_break_6",
"fieldtype": "Section Break",
"hidden": 0,
@@ -220,16 +241,53 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "topics",
+ "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": "Topics",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Course Topic",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "course_intro",
- "fieldtype": "Text Editor",
+ "fieldtype": "Small Text",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@@ -250,14 +308,50 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "hero_image",
+ "fieldtype": "Attach Image",
+ "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": "Hero Image",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "assessment",
"fieldtype": "Section Break",
"hidden": 0,
@@ -280,14 +374,17 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "default_grading_scale",
"fieldtype": "Link",
"hidden": 0,
@@ -311,14 +408,17 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "assessment_criteria",
"fieldtype": "Table",
"hidden": 0,
@@ -342,21 +442,20 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
}
],
"has_web_view": 0,
- "hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
- "image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
- "modified": "2017-11-10 19:06:28.909585",
+ "modified": "2019-04-09 11:35:27.354877",
"modified_by": "Administrator",
"module": "Education",
"name": "Course",
@@ -365,7 +464,6 @@
"permissions": [
{
"amend": 0,
- "apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
@@ -385,7 +483,6 @@
},
{
"amend": 0,
- "apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
@@ -397,7 +494,7 @@
"print": 1,
"read": 1,
"report": 1,
- "role": "HR Manager",
+ "role": "Instructor",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
@@ -406,12 +503,12 @@
],
"quick_entry": 0,
"read_only": 0,
- "read_only_onload": 0,
"restrict_to_domain": "Education",
"search_fields": "course_name",
"show_name_in_global_search": 1,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 0,
- "track_seen": 0
+ "track_seen": 0,
+ "track_views": 0
}
\ No newline at end of file
diff --git a/erpnext/education/doctype/course/course.py b/erpnext/education/doctype/course/course.py
index 69d2fca63e..987823a01e 100644
--- a/erpnext/education/doctype/course/course.py
+++ b/erpnext/education/doctype/course/course.py
@@ -10,7 +10,7 @@ from frappe import _
class Course(Document):
def validate(self):
self.validate_assessment_criteria()
-
+
def validate_assessment_criteria(self):
if self.assessment_criteria:
total_weightage = 0
@@ -18,3 +18,11 @@ class Course(Document):
total_weightage += criteria.weightage or 0
if total_weightage != 100:
frappe.throw(_("Total Weightage of all Assessment Criteria must be 100%"))
+
+ def get_topics(self):
+ try:
+ topic_list = self.get_all_children()
+ topic_data = [frappe.get_doc("Topic", topic.topic) for topic in topic_list]
+ except frappe.DoesNotExistError:
+ return None
+ return topic_data
\ No newline at end of file
diff --git a/erpnext/education/doctype/course/test_course.py b/erpnext/education/doctype/course/test_course.py
index b18f4a94be..a24ba8a527 100644
--- a/erpnext/education/doctype/course/test_course.py
+++ b/erpnext/education/doctype/course/test_course.py
@@ -2,6 +2,7 @@
# Copyright (c) 2015, Frappe Technologies and Contributors
# See license.txt
from __future__ import unicode_literals
+from erpnext.education.doctype.topic.test_topic import make_topic
import frappe
import unittest
@@ -9,4 +10,35 @@ import unittest
# test_records = frappe.get_test_records('Course')
class TestCourse(unittest.TestCase):
- pass
+ def setUp(self):
+ make_course_and_linked_topic("_Test Course 1", ["_Test Topic 1", "_Test Topic 2"])
+
+ def test_get_topics(self):
+ course = frappe.get_doc("Course", "_Test Course 1")
+ topics = course.get_topics()
+ self.assertEqual(topics[0].name, "_Test Topic 1")
+ self.assertEqual(topics[1].name, "_Test Topic 2")
+ frappe.db.rollback()
+
+def make_course(name):
+ try:
+ course = frappe.get_doc("Course", name)
+ except frappe.DoesNotExistError:
+ course = frappe.get_doc({
+ "doctype": "Course",
+ "course_name": name,
+ "course_code": name
+ }).insert()
+ return course.name
+
+def make_course_and_linked_topic(course_name, topic_name_list):
+ try:
+ course = frappe.get_doc("Course", course_name)
+ except frappe.DoesNotExistError:
+ make_course(course_name)
+ course = frappe.get_doc("Course", course_name)
+ topic_list = [make_topic(topic_name) for topic_name in topic_name_list]
+ for topic in topic_list:
+ course.append("topics", {"topic": topic})
+ course.save()
+ return course
diff --git a/erpnext/education/doctype/course_activity/__init__.py b/erpnext/education/doctype/course_activity/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/education/doctype/course_activity/course_activity.js b/erpnext/education/doctype/course_activity/course_activity.js
new file mode 100644
index 0000000000..5115fc415e
--- /dev/null
+++ b/erpnext/education/doctype/course_activity/course_activity.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Course Activity', {
+ refresh: function(frm) {
+
+ }
+});
diff --git a/erpnext/education/doctype/course_activity/course_activity.json b/erpnext/education/doctype/course_activity/course_activity.json
new file mode 100644
index 0000000000..99ae9aee56
--- /dev/null
+++ b/erpnext/education/doctype/course_activity/course_activity.json
@@ -0,0 +1,301 @@
+{
+ "allow_copy": 0,
+ "allow_events_in_timeline": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "autoname": "format:EDU-CA-{YYYY}-{#####}",
+ "beta": 1,
+ "creation": "2018-10-01 17:35:54.391413",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "enrollment",
+ "fieldtype": "Link",
+ "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": "Enrollment",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Course Enrollment",
+ "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": 1,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_from": "enrollment.course",
+ "fieldname": "course",
+ "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": 1,
+ "label": "Course",
+ "length": 0,
+ "no_copy": 0,
+ "options": "",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 1,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_from": "enrollment.student",
+ "fieldname": "student",
+ "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": 1,
+ "label": "Student",
+ "length": 0,
+ "no_copy": 0,
+ "options": "",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 1,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "content_type",
+ "fieldtype": "Select",
+ "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": "Content Type",
+ "length": 0,
+ "no_copy": 0,
+ "options": "\nArticle\nVideo",
+ "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": 1,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "content",
+ "fieldtype": "Dynamic 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": "Content",
+ "length": 0,
+ "no_copy": 0,
+ "options": "content_type",
+ "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": 1,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "activity_date",
+ "fieldtype": "Datetime",
+ "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": "Activity Date",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 1,
+ "translatable": 0,
+ "unique": 0
+ }
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2018-12-06 11:53:08.006123",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Course Activity",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "amend": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Academics User",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ },
+ {
+ "amend": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 0,
+ "email": 1,
+ "export": 1,
+ "if_owner": 1,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "LMS User",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 0
+ },
+ {
+ "amend": 0,
+ "cancel": 0,
+ "create": 0,
+ "delete": 0,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Instructor",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 0
+ }
+ ],
+ "quick_entry": 1,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 0,
+ "track_views": 0
+}
\ No newline at end of file
diff --git a/erpnext/education/doctype/course_activity/course_activity.py b/erpnext/education/doctype/course_activity/course_activity.py
new file mode 100644
index 0000000000..054b192097
--- /dev/null
+++ b/erpnext/education/doctype/course_activity/course_activity.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe import _
+from frappe.model.document import Document
+
+class CourseActivity(Document):
+ def validate(self):
+ self.check_if_enrolled()
+
+
+ def check_if_enrolled(self):
+ if frappe.db.exists("Course Enrollment", self.enrollment):
+ return True
+ else:
+ frappe.throw(_("Course Enrollment {0} does not exists".format(self.enrollment)))
\ No newline at end of file
diff --git a/erpnext/education/doctype/course_activity/test_course_activity.js b/erpnext/education/doctype/course_activity/test_course_activity.js
new file mode 100644
index 0000000000..c89c89e5d3
--- /dev/null
+++ b/erpnext/education/doctype/course_activity/test_course_activity.js
@@ -0,0 +1,23 @@
+/* eslint-disable */
+// rename this file from _test_[name] to test_[name] to activate
+// and remove above this line
+
+QUnit.test("test: Course Activity", function (assert) {
+ let done = assert.async();
+
+ // number of asserts
+ assert.expect(1);
+
+ frappe.run_serially([
+ // insert a new Course Activity
+ () => frappe.tests.make('Course Activity', [
+ // values to be set
+ {key: 'value'}
+ ]),
+ () => {
+ assert.equal(cur_frm.doc.key, 'value');
+ },
+ () => done()
+ ]);
+
+});
diff --git a/erpnext/education/doctype/course_activity/test_course_activity.py b/erpnext/education/doctype/course_activity/test_course_activity.py
new file mode 100644
index 0000000000..5269a6b71a
--- /dev/null
+++ b/erpnext/education/doctype/course_activity/test_course_activity.py
@@ -0,0 +1,24 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+
+class TestCourseActivity(unittest.TestCase):
+ pass
+
+def make_course_activity(enrollment, content_type, content):
+ activity = frappe.get_all("Course Activity", filters={'enrollment': enrollment, 'content_type': content_type, 'content': content})
+ try:
+ activity = frappe.get_doc("Course Activity", activity[0]['name'])
+ except (IndexError, frappe.DoesNotExistError):
+ activity = frappe.get_doc({
+ "doctype": "Course Activity",
+ "enrollment": enrollment,
+ "content_type": content_type,
+ "content": content,
+ "activity_date": frappe.utils.datetime.datetime.now()
+ }).insert()
+ return activity
diff --git a/erpnext/education/doctype/course_content/__init__.py b/erpnext/education/doctype/course_content/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/education/doctype/course_content/course_content.js b/erpnext/education/doctype/course_content/course_content.js
new file mode 100644
index 0000000000..b9faf99aaf
--- /dev/null
+++ b/erpnext/education/doctype/course_content/course_content.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Course Content', {
+ refresh: function(frm) {
+
+ }
+});
diff --git a/erpnext/education/doctype/course_content/course_content.json b/erpnext/education/doctype/course_content/course_content.json
new file mode 100644
index 0000000000..378e56005f
--- /dev/null
+++ b/erpnext/education/doctype/course_content/course_content.json
@@ -0,0 +1,142 @@
+{
+ "allow_copy": 0,
+ "allow_events_in_timeline": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "beta": 0,
+ "creation": "2018-10-01 13:04:09.313771",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_from": "",
+ "fieldname": "content_type",
+ "fieldtype": "Select",
+ "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": "Content Type",
+ "length": 0,
+ "no_copy": 0,
+ "options": "\nArticle\nVideo\nQuiz",
+ "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,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "column_break_2",
+ "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,
+ "label": "",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "content",
+ "fieldtype": "Dynamic 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": "Content",
+ "length": 0,
+ "no_copy": 0,
+ "options": "content_type",
+ "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,
+ "translatable": 0,
+ "unique": 0
+ }
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 1,
+ "max_attachments": 0,
+ "modified": "2018-10-17 07:36:04.029818",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Course Content",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 0,
+ "track_views": 0
+}
\ No newline at end of file
diff --git a/erpnext/education/doctype/course_content/course_content.py b/erpnext/education/doctype/course_content/course_content.py
new file mode 100644
index 0000000000..0d2f85ab50
--- /dev/null
+++ b/erpnext/education/doctype/course_content/course_content.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe.model.document import Document
+
+class CourseContent(Document):
+ pass
diff --git a/erpnext/education/doctype/course_content/test_course_content.js b/erpnext/education/doctype/course_content/test_course_content.js
new file mode 100644
index 0000000000..786e67e9a3
--- /dev/null
+++ b/erpnext/education/doctype/course_content/test_course_content.js
@@ -0,0 +1,23 @@
+/* eslint-disable */
+// rename this file from _test_[name] to test_[name] to activate
+// and remove above this line
+
+QUnit.test("test: Course Content", function (assert) {
+ let done = assert.async();
+
+ // number of asserts
+ assert.expect(1);
+
+ frappe.run_serially([
+ // insert a new Course Content
+ () => frappe.tests.make('Course Content', [
+ // values to be set
+ {key: 'value'}
+ ]),
+ () => {
+ assert.equal(cur_frm.doc.key, 'value');
+ },
+ () => done()
+ ]);
+
+});
diff --git a/erpnext/education/doctype/course_content/test_course_content.py b/erpnext/education/doctype/course_content/test_course_content.py
new file mode 100644
index 0000000000..9be4b1f5ce
--- /dev/null
+++ b/erpnext/education/doctype/course_content/test_course_content.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+
+class TestCourseContent(unittest.TestCase):
+ pass
diff --git a/erpnext/education/doctype/course_enrollment/__init__.py b/erpnext/education/doctype/course_enrollment/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/education/doctype/course_enrollment/course_enrollment.js b/erpnext/education/doctype/course_enrollment/course_enrollment.js
new file mode 100644
index 0000000000..b5d3cc56e5
--- /dev/null
+++ b/erpnext/education/doctype/course_enrollment/course_enrollment.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Course Enrollment', {
+ refresh: function(frm) {
+
+ }
+});
diff --git a/erpnext/education/doctype/course_enrollment/course_enrollment.json b/erpnext/education/doctype/course_enrollment/course_enrollment.json
new file mode 100644
index 0000000000..6286ec1e66
--- /dev/null
+++ b/erpnext/education/doctype/course_enrollment/course_enrollment.json
@@ -0,0 +1,233 @@
+{
+ "allow_copy": 0,
+ "allow_events_in_timeline": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "autoname": "format:EDU-CE-{YYYY}-{#####}",
+ "beta": 1,
+ "creation": "2018-10-15 15:35:39.375161",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "program_enrollment",
+ "fieldtype": "Link",
+ "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": "Program Enrollment",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Program Enrollment",
+ "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": 1,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "student",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 1,
+ "label": "Student",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Student",
+ "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": 1,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "course",
+ "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": "Course",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Course",
+ "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": 1,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "enrollment_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": "Enrollment Date",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 1,
+ "translatable": 0,
+ "unique": 0
+ }
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2018-11-25 18:59:01.742377",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Course Enrollment",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "amend": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Academics User",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ },
+ {
+ "amend": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 0,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "LMS User",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ },
+ {
+ "amend": 0,
+ "cancel": 0,
+ "create": 0,
+ "delete": 0,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Instructor",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 0
+ }
+ ],
+ "quick_entry": 1,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 0,
+ "track_views": 0
+}
\ No newline at end of file
diff --git a/erpnext/education/doctype/course_enrollment/course_enrollment.py b/erpnext/education/doctype/course_enrollment/course_enrollment.py
new file mode 100644
index 0000000000..9508636d2f
--- /dev/null
+++ b/erpnext/education/doctype/course_enrollment/course_enrollment.py
@@ -0,0 +1,76 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe import _
+from frappe.model.document import Document
+from functools import reduce
+
+class CourseEnrollment(Document):
+ def get_progress(self, student):
+ """
+ Returns Progress of given student for a particular course enrollment
+
+ :param self: Course Enrollment Object
+ :param student: Student Object
+ """
+ course = frappe.get_doc('Course', self.course)
+ topics = course.get_topics()
+ progress = []
+ for topic in topics:
+ progress.append(student.get_topic_progress(self.name, topic))
+ return reduce(lambda x,y: x+y, progress) # Flatten out the List
+
+ def validate_duplication(self):
+ enrollment = frappe.get_all("Course Enrollment", filters={
+ "student": self.student,
+ "course": self.course,
+ "program_enrollment": self.program_enrollment
+ })
+ if enrollment:
+ frappe.throw(_("Student is already enrolled."))
+
+ def add_quiz_activity(self, quiz_name, quiz_response,answers, score, status):
+ result = {k: ('Correct' if v else 'Wrong') for k,v in answers.items()}
+ result_data = []
+ for key in answers:
+ item = {}
+ item['question'] = key
+ item['quiz_result'] = result[key]
+ try:
+ if isinstance(quiz_response[key], list):
+ item['selected_option'] = ', '.join(frappe.get_value('Options', res, 'option') for res in quiz_response[key])
+ else:
+ item['selected_option'] = frappe.get_value('Options', quiz_response[key], 'option')
+ except KeyError:
+ item['selected_option'] = "Unattempted"
+ result_data.append(item)
+
+ quiz_activity = frappe.get_doc({
+ "doctype": "Quiz Activity",
+ "enrollment": self.name,
+ "quiz": quiz_name,
+ "activity_date": frappe.utils.datetime.datetime.now(),
+ "result": result_data,
+ "score": score,
+ "status": status
+ }).insert()
+
+ def add_activity(self, content_type, content):
+ if check_activity_exists(self.name, content_type, content):
+ pass
+ else:
+ activity = frappe.get_doc({
+ "doctype": "Course Activity",
+ "enrollment": self.name,
+ "content_type": content_type,
+ "content": content,
+ "activity_date": frappe.utils.datetime.datetime.now()
+ })
+ activity.insert()
+
+def check_activity_exists(enrollment, content_type, content):
+ activity = frappe.get_all("Course Activity", filters={'enrollment': enrollment, 'content_type': content_type, 'content': content})
+ return bool(activity)
\ No newline at end of file
diff --git a/erpnext/education/doctype/course_enrollment/test_course_enrollment.js b/erpnext/education/doctype/course_enrollment/test_course_enrollment.js
new file mode 100644
index 0000000000..216cc30799
--- /dev/null
+++ b/erpnext/education/doctype/course_enrollment/test_course_enrollment.js
@@ -0,0 +1,23 @@
+/* eslint-disable */
+// rename this file from _test_[name] to test_[name] to activate
+// and remove above this line
+
+QUnit.test("test: Course Enrollment", function (assert) {
+ let done = assert.async();
+
+ // number of asserts
+ assert.expect(1);
+
+ frappe.run_serially([
+ // insert a new Course Enrollment
+ () => frappe.tests.make('Course Enrollment', [
+ // values to be set
+ {key: 'value'}
+ ]),
+ () => {
+ assert.equal(cur_frm.doc.key, 'value');
+ },
+ () => done()
+ ]);
+
+});
diff --git a/erpnext/education/doctype/course_enrollment/test_course_enrollment.py b/erpnext/education/doctype/course_enrollment/test_course_enrollment.py
new file mode 100644
index 0000000000..5ecace2a60
--- /dev/null
+++ b/erpnext/education/doctype/course_enrollment/test_course_enrollment.py
@@ -0,0 +1,34 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+
+
+from erpnext.education.doctype.student.test_student import create_student
+from erpnext.education.doctype.student.test_student import get_student
+from erpnext.education.doctype.program.test_program import setup_program
+from erpnext.education.doctype.course_activity.test_course_activity import make_course_activity
+
+class TestCourseEnrollment(unittest.TestCase):
+ def setUp(self):
+ setup_program()
+ student = create_student({"first_name": "_Test First", "last_name": "_Test Last", "email": "_test_student_1@example.com"})
+ program_enrollment = student.enroll_in_program("_Test Program")
+ course_enrollment = student.enroll_in_course("_Test Course 1", program_enrollment.name)
+ make_course_activity(course_enrollment.name, "Article", "_Test Article 1-1")
+
+ def test_get_progress(self):
+ student = get_student("_test_student_1@example.com")
+ program_enrollment_name = frappe.get_list("Program Enrollment", filters={"student": student.name, "Program": "_Test Program"})[0].name
+ course_enrollment_name = frappe.get_list("Course Enrollment", filters={"student": student.name, "course": "_Test Course 1", "program_enrollment": program_enrollment_name})[0].name
+ course_enrollment = frappe.get_doc("Course Enrollment", course_enrollment_name)
+ progress = course_enrollment.get_progress(student)
+ finished = {'content': '_Test Article 1-1', 'content_type': 'Article', 'is_complete': True}
+ self.assertTrue(finished in progress)
+ frappe.db.rollback()
+
+
+
diff --git a/erpnext/education/doctype/course_topic/__init__.py b/erpnext/education/doctype/course_topic/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/education/doctype/course_topic/course_topic.js b/erpnext/education/doctype/course_topic/course_topic.js
new file mode 100644
index 0000000000..7d03ba32ff
--- /dev/null
+++ b/erpnext/education/doctype/course_topic/course_topic.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Course Topic', {
+ refresh: function(frm) {
+
+ }
+});
diff --git a/erpnext/education/doctype/course_topic/course_topic.json b/erpnext/education/doctype/course_topic/course_topic.json
new file mode 100644
index 0000000000..3fcddc169e
--- /dev/null
+++ b/erpnext/education/doctype/course_topic/course_topic.json
@@ -0,0 +1,109 @@
+{
+ "allow_copy": 0,
+ "allow_events_in_timeline": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "beta": 0,
+ "creation": "2018-12-12 11:51:25.952740",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "topic",
+ "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": "Topic",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Topic",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_from": "topic.topic_name",
+ "fieldname": "topic_name",
+ "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": "Topic Name",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ }
+ ],
+ "has_web_view": 0,
+ "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-12-12 13:01:58.960425",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Course Topic",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 0,
+ "track_views": 0
+}
\ No newline at end of file
diff --git a/erpnext/education/doctype/course_topic/course_topic.py b/erpnext/education/doctype/course_topic/course_topic.py
new file mode 100644
index 0000000000..2364f17a49
--- /dev/null
+++ b/erpnext/education/doctype/course_topic/course_topic.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe.model.document import Document
+
+class CourseTopic(Document):
+ pass
diff --git a/erpnext/education/doctype/course_topic/test_course_topic.js b/erpnext/education/doctype/course_topic/test_course_topic.js
new file mode 100644
index 0000000000..d8d154fb9c
--- /dev/null
+++ b/erpnext/education/doctype/course_topic/test_course_topic.js
@@ -0,0 +1,23 @@
+/* eslint-disable */
+// rename this file from _test_[name] to test_[name] to activate
+// and remove above this line
+
+QUnit.test("test: Course Topic", function (assert) {
+ let done = assert.async();
+
+ // number of asserts
+ assert.expect(1);
+
+ frappe.run_serially([
+ // insert a new Course Topic
+ () => frappe.tests.make('Course Topic', [
+ // values to be set
+ {key: 'value'}
+ ]),
+ () => {
+ assert.equal(cur_frm.doc.key, 'value');
+ },
+ () => done()
+ ]);
+
+});
diff --git a/erpnext/education/doctype/course_topic/test_course_topic.py b/erpnext/education/doctype/course_topic/test_course_topic.py
new file mode 100644
index 0000000000..7ce46d28ad
--- /dev/null
+++ b/erpnext/education/doctype/course_topic/test_course_topic.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+
+class TestCourseTopic(unittest.TestCase):
+ pass
diff --git a/erpnext/education/doctype/education_settings/education_settings.json b/erpnext/education/doctype/education_settings/education_settings.json
index c1eaa11284..3be4988d21 100644
--- a/erpnext/education/doctype/education_settings/education_settings.json
+++ b/erpnext/education/doctype/education_settings/education_settings.json
@@ -1,359 +1,492 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2017-04-05 13:33:04.519313",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "allow_copy": 0,
+ "allow_events_in_timeline": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "beta": 0,
+ "creation": "2017-04-05 13:33:04.519313",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "current_academic_year",
- "fieldtype": "Link",
- "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": "Current Academic Year",
- "length": 0,
- "no_copy": 0,
- "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": 0,
- "search_index": 0,
- "set_only_once": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "current_academic_year",
+ "fieldtype": "Link",
+ "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": "Current Academic Year",
+ "length": 0,
+ "no_copy": 0,
+ "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": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "current_academic_term",
- "fieldtype": "Link",
- "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": "Current Academic Term",
- "length": 0,
- "no_copy": 0,
- "options": "Academic Term",
- "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,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "current_academic_term",
+ "fieldtype": "Link",
+ "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": "Current Academic Term",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Academic Term",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "attendance_freeze_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": "Attendance Freeze Date",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "attendance_freeze_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": "Attendance Freeze Date",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
- },
+ },
{
- "allow_bulk_edit": 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,
+ "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
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "For Batch based Student Group, the Student Batch will be validated for every Student from the Program Enrollment.",
- "fieldname": "validate_batch",
- "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": "Validate Batch for Students in Student Group",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "description": "For Batch based Student Group, the Student Batch will be validated for every Student from the Program Enrollment.",
+ "fieldname": "validate_batch",
+ "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": "Validate Batch for Students in Student Group",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "For Course based Student Group, the Course will be validated for every Student from the enrolled Courses in Program Enrollment.",
- "fieldname": "validate_course",
- "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": "Validate Enrolled Course for Students in Student Group",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "description": "For Course based Student Group, the Course will be validated for every Student from the enrolled Courses in Program Enrollment.",
+ "fieldname": "validate_course",
+ "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": "Validate Enrolled Course for Students in Student Group",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "0",
- "description": "If enabled, field Academic Term will be Mandatory in Program Enrollment Tool.",
- "fieldname": "academic_term_reqd",
- "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": "Make Academic Term Mandatory",
- "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,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "0",
+ "description": "If enabled, field Academic Term will be Mandatory in Program Enrollment Tool.",
+ "fieldname": "academic_term_reqd",
+ "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": "Make Academic Term Mandatory",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_7",
- "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,
- "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,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "section_break_7",
+ "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,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Full Name",
- "fieldname": "instructor_created_by",
- "fieldtype": "Select",
- "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": "Instructor Records to be created by",
- "length": 0,
- "no_copy": 0,
- "options": "Full Name\nNaming Series\nEmployee Number",
- "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,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "Full Name",
+ "fieldname": "instructor_created_by",
+ "fieldtype": "Select",
+ "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": "Instructor Records to be created by",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Full Name\nNaming Series\nEmployee Number",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "web_academy_settings_section",
+ "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": "LMS Settings",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "portal_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": "Portal 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,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "description",
+ "fieldtype": "Small Text",
+ "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": "Description",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 1,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2018-07-26 04:43:35.406690",
- "modified_by": "Administrator",
- "module": "Education",
- "name": "Education Settings",
- "name_case": "",
- "owner": "Administrator",
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 1,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2018-12-11 15:49:15.045116",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Education Settings",
+ "name_case": "",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "apply_user_permissions": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 0,
- "role": "System Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "amend": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 0,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 0,
+ "role": "System Manager",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
"write": 1
- },
+ },
{
- "amend": 0,
- "apply_user_permissions": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 0,
- "role": "Education Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "amend": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 0,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 0,
+ "role": "Education Manager",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
"write": 1
+ },
+ {
+ "amend": 0,
+ "cancel": 0,
+ "create": 0,
+ "delete": 0,
+ "email": 1,
+ "export": 0,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 0,
+ "role": "Guest",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 0
}
- ],
- "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
+ ],
+ "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
}
\ No newline at end of file
diff --git a/erpnext/education/doctype/options/__init__.py b/erpnext/education/doctype/options/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/education/doctype/options/options.json b/erpnext/education/doctype/options/options.json
new file mode 100644
index 0000000000..59deab7837
--- /dev/null
+++ b/erpnext/education/doctype/options/options.json
@@ -0,0 +1,107 @@
+{
+ "allow_copy": 0,
+ "allow_events_in_timeline": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "beta": 0,
+ "creation": "2018-10-15 14:05:28.601274",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "option",
+ "fieldtype": "Small Text",
+ "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": "Option",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "is_correct",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Is Correct",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ }
+ ],
+ "has_web_view": 0,
+ "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-10-15 14:16:18.303156",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Options",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 0,
+ "track_views": 0
+}
\ No newline at end of file
diff --git a/erpnext/education/doctype/options/options.py b/erpnext/education/doctype/options/options.py
new file mode 100644
index 0000000000..a11d77afb2
--- /dev/null
+++ b/erpnext/education/doctype/options/options.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe.model.document import Document
+
+class Options(Document):
+ pass
diff --git a/erpnext/education/doctype/program/program.js b/erpnext/education/doctype/program/program.js
index 5146a19322..98263b55a1 100644
--- a/erpnext/education/doctype/program/program.js
+++ b/erpnext/education/doctype/program/program.js
@@ -4,40 +4,5 @@
cur_frm.add_fetch('fee_structure', 'total_amount', 'amount');
frappe.ui.form.on("Program", "refresh", function(frm) {
- if(!frm.doc.__islocal) {
- frm.add_custom_button(__("Student Applicant"), function() {
- frappe.route_options = {
- program: frm.doc.name
- }
- frappe.set_route("List", "Student Applicant");
- });
-
- frm.add_custom_button(__("Program Enrollment"), function() {
- frappe.route_options = {
- program: frm.doc.name
- }
- frappe.set_route("List", "Program Enrollment");
- });
-
- frm.add_custom_button(__("Student Group"), function() {
- frappe.route_options = {
- program: frm.doc.name
- }
- frappe.set_route("List", "Student Group");
- });
-
- frm.add_custom_button(__("Fee Structure"), function() {
- frappe.route_options = {
- program: frm.doc.name
- }
- frappe.set_route("List", "Fee Structure");
- });
-
- frm.add_custom_button(__("Fees"), function() {
- frappe.route_options = {
- program: frm.doc.name
- }
- frappe.set_route("List", "Fees");
- });
- }
+
});
\ No newline at end of file
diff --git a/erpnext/education/doctype/program/program.json b/erpnext/education/doctype/program/program.json
index 05e35a2a53..cb8d7786e1 100644
--- a/erpnext/education/doctype/program/program.json
+++ b/erpnext/education/doctype/program/program.json
@@ -1,277 +1,627 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 1,
- "allow_rename": 1,
- "autoname": "field:program_code",
- "beta": 0,
- "creation": "2015-09-07 12:54:03.609282",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 0,
- "engine": "InnoDB",
+ "allow_copy": 0,
+ "allow_events_in_timeline": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 1,
+ "allow_rename": 1,
+ "autoname": "field:program_code",
+ "beta": 0,
+ "creation": "2015-09-07 12:54:03.609282",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 0,
+ "engine": "InnoDB",
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "program_name",
- "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": "Program Name",
- "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,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "program_name",
+ "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": "Program Name",
+ "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,
+ "translatable": 0,
"unique": 0
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "department",
- "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": "Department",
- "length": 0,
- "no_copy": 0,
- "options": "Department",
- "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,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "department",
+ "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": "Department",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Department",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
- },
+ },
{
- "allow_bulk_edit": 0,
- "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,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 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,
+ "translatable": 0,
"unique": 0
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "program_code",
- "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": "Program Code",
- "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,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "program_code",
+ "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": "Program Code",
+ "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,
+ "translatable": 0,
+ "unique": 1
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "program_abbreviation",
+ "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": "Program Abbreviation",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "program_abbreviation",
- "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": "Program Abbreviation",
- "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,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "depends_on": "",
+ "fetch_if_empty": 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": "Portal Settings",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
- },
+ },
{
- "allow_bulk_edit": 0,
- "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": "Course",
- "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,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "courses",
+ "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": "Courses",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Program Course",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "courses",
- "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": "Courses",
- "length": 0,
- "no_copy": 0,
- "options": "Program Course",
- "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,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "section_break_9",
+ "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,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "description",
+ "fieldtype": "Small Text",
+ "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": "Description",
+ "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,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "intro_video",
+ "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": "Intro Video",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "hero_image",
+ "fieldtype": "Attach Image",
+ "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": "Hero Image",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "column_break_11",
+ "fieldtype": "Column Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "0",
+ "fetch_if_empty": 0,
+ "fieldname": "is_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": "Is Published",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "0",
+ "fetch_if_empty": 0,
+ "fieldname": "is_featured",
+ "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": "Is Featured",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "menu_index": 0,
- "modified": "2017-11-10 18:56:18.413911",
- "modified_by": "Administrator",
- "module": "Education",
- "name": "Program",
- "name_case": "",
- "owner": "Administrator",
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "menu_index": 0,
+ "modified": "2019-03-18 15:26:56.737903",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Program",
+ "name_case": "",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "apply_user_permissions": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Academics User",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "amend": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Academics User",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ },
+ {
+ "amend": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Instructor",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ },
+ {
+ "amend": 0,
+ "cancel": 0,
+ "create": 0,
+ "delete": 0,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Guest",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 0
+ },
+ {
+ "amend": 0,
+ "cancel": 0,
+ "create": 0,
+ "delete": 0,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "LMS User",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 0
+ },
+ {
+ "amend": 0,
+ "cancel": 0,
+ "create": 0,
+ "delete": 0,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Student",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 0
+ },
+ {
+ "amend": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
"write": 1
}
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "restrict_to_domain": "Education",
- "search_fields": "program_name",
- "show_name_in_global_search": 1,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 0,
- "track_seen": 0
+ ],
+ "quick_entry": 0,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "restrict_to_domain": "Education",
+ "route": "",
+ "search_fields": "program_name",
+ "show_name_in_global_search": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 0,
+ "track_seen": 0,
+ "track_views": 0
}
\ No newline at end of file
diff --git a/erpnext/education/doctype/program/program.py b/erpnext/education/doctype/program/program.py
index f626880b2a..dbeda40775 100644
--- a/erpnext/education/doctype/program/program.py
+++ b/erpnext/education/doctype/program/program.py
@@ -7,4 +7,8 @@ import frappe
from frappe.model.document import Document
class Program(Document):
- pass
\ No newline at end of file
+
+ def get_course_list(self):
+ program_course_list = self.get_all_children()
+ course_list = [frappe.get_doc("Course", program_course.course) for program_course in program_course_list]
+ return course_list
\ No newline at end of file
diff --git a/erpnext/education/doctype/program/program_dashboard.py b/erpnext/education/doctype/program/program_dashboard.py
new file mode 100644
index 0000000000..cb8f74207e
--- /dev/null
+++ b/erpnext/education/doctype/program/program_dashboard.py
@@ -0,0 +1,20 @@
+from frappe import _
+
+def get_data():
+ return {
+ 'fieldname': 'program',
+ 'transactions': [
+ {
+ 'label': _('Admission and Enrollment'),
+ 'items': ['Student Applicant', 'Program Enrollment']
+ },
+ {
+ 'label': _('Student Activity'),
+ 'items': ['Student Group' ]
+ },
+ {
+ 'label': _('Fee'),
+ 'items': ['Fees','Fee Structure']
+ }
+ ]
+ }
\ No newline at end of file
diff --git a/erpnext/education/doctype/program/test_program.py b/erpnext/education/doctype/program/test_program.py
index a4accdaaf7..3bcca3a7f1 100644
--- a/erpnext/education/doctype/program/test_program.py
+++ b/erpnext/education/doctype/program/test_program.py
@@ -2,11 +2,85 @@
# Copyright (c) 2015, Frappe Technologies and Contributors
# See license.txt
from __future__ import unicode_literals
+from erpnext.education.doctype.course.test_course import make_course
+from erpnext.education.doctype.topic.test_topic import make_topic_and_linked_content
+from erpnext.education.doctype.course.test_course import make_course_and_linked_topic
import frappe
import unittest
-# test_records = frappe.get_test_records('Program')
+test_data = {
+ "program_name": "_Test Program",
+ "description": "_Test Program",
+ "course": [{
+ "course_name": "_Test Course 1",
+ "topic": [{
+ "topic_name": "_Test Topic 1-1",
+ "content": [{
+ "type": "Article",
+ "name": "_Test Article 1-1"
+ }, {
+ "type": "Article",
+ "name": "_Test Article 1-2"
+ }]
+ },
+ {
+ "topic_name": "_Test Topic 1-2",
+ "content": [{
+ "type": "Article",
+ "name": "_Test Article 1-3"
+ }, {
+ "type": "Article",
+ "name": "_Test Article 1-4"
+ }]
+ }
+ ]
+ }]
+}
class TestProgram(unittest.TestCase):
- pass
+ def setUp(self):
+ make_program_and_linked_courses("_Test Program 1", ["_Test Course 1", "_Test Course 2"])
+
+ def test_get_course_list(self):
+ program = frappe.get_doc("Program", "_Test Program 1")
+ course = program.get_course_list()
+ self.assertEqual(course[0].name, "_Test Course 1")
+ self.assertEqual(course[1].name, "_Test Course 2")
+ frappe.db.rollback()
+
+def make_program(name):
+ program = frappe.get_doc({
+ "doctype": "Program",
+ "program_name": name,
+ "program_code": name,
+ "description": "_test description",
+ "is_published": True,
+ "is_featured": True,
+ }).insert()
+ return program.name
+
+def make_program_and_linked_courses(program_name, course_name_list):
+ try:
+ program = frappe.get_doc("Program", program_name)
+ except frappe.DoesNotExistError:
+ make_program(program_name)
+ program = frappe.get_doc("Program", program_name)
+ course_list = [make_course(course_name) for course_name in course_name_list]
+ for course in course_list:
+ program.append("courses", {"course": course})
+ program.save()
+ return program
+
+def setup_program():
+ topic_list = [course['topic'] for course in test_data['course']]
+ for topic in topic_list[0]:
+ make_topic_and_linked_content(topic['topic_name'], topic['content'])
+
+ all_courses_list = [{'course': course['course_name'], 'topic': [topic['topic_name'] for topic in course['topic']]} for course in test_data['course']] # returns [{'course': 'Applied Math', 'topic': ['Trignometry', 'Geometry']}]
+ for course in all_courses_list:
+ make_course_and_linked_topic(course['course'], course['topic'])
+
+ course_list = [course['course_name'] for course in test_data['course']]
+ program = make_program_and_linked_courses(test_data['program_name'], course_list)
+ return program
\ No newline at end of file
diff --git a/erpnext/education/doctype/program/test_records.json b/erpnext/education/doctype/program/test_records.json
index e5eda70982..7901db3225 100644
--- a/erpnext/education/doctype/program/test_records.json
+++ b/erpnext/education/doctype/program/test_records.json
@@ -1,12 +1,14 @@
[
{
- "program_name": "_Test Program",
+ "program_name": "_Test Program 1",
"program_code": "_TP1",
+ "description": "Test Description",
"program_abbreviation": "TP1"
},
{
"program_name": "_Test Program 2",
"program_code": "_TP2",
+ "description": "Test Description",
"program_abbreviation": "TP2"
}
-]
+]
\ No newline at end of file
diff --git a/erpnext/education/doctype/program_enrollment/program_enrollment.json b/erpnext/education/doctype/program_enrollment/program_enrollment.json
index 5f4621f368..1d8a4344a7 100644
--- a/erpnext/education/doctype/program_enrollment/program_enrollment.json
+++ b/erpnext/education/doctype/program_enrollment/program_enrollment.json
@@ -1,5 +1,6 @@
{
"allow_copy": 0,
+ "allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 0,
@@ -714,7 +715,7 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
- "modified": "2018-08-21 16:15:35.014952",
+ "modified": "2018-11-07 21:13:06.502279",
"modified_by": "Administrator",
"module": "Education",
"name": "Program Enrollment",
@@ -739,6 +740,25 @@
"share": 1,
"submit": 1,
"write": 1
+ },
+ {
+ "amend": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 0,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "LMS User",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 1,
+ "write": 1
}
],
"quick_entry": 0,
diff --git a/erpnext/education/doctype/program_enrollment/program_enrollment.py b/erpnext/education/doctype/program_enrollment/program_enrollment.py
index 320a58a924..22cca86fcf 100644
--- a/erpnext/education/doctype/program_enrollment/program_enrollment.py
+++ b/erpnext/education/doctype/program_enrollment/program_enrollment.py
@@ -8,6 +8,7 @@ from frappe import msgprint, _
from frappe.model.document import Document
from frappe.desk.reportview import get_match_cond, get_filters_cond
from frappe.utils import comma_and
+import erpnext.www.lms as lms
class ProgramEnrollment(Document):
def validate(self):
@@ -16,11 +17,12 @@ class ProgramEnrollment(Document):
self.student_name = frappe.db.get_value("Student", self.student, "title")
if not self.courses:
self.extend("courses", self.get_courses())
-
+
def on_submit(self):
self.update_student_joining_date()
self.make_fee_records()
-
+ self.create_course_enrollments()
+
def validate_duplication(self):
enrollment = frappe.get_all("Program Enrollment", filters={
"student": self.student,
@@ -31,11 +33,11 @@ class ProgramEnrollment(Document):
})
if enrollment:
frappe.throw(_("Student is already enrolled."))
-
+
def update_student_joining_date(self):
date = frappe.db.sql("select min(enrollment_date) from `tabProgram Enrollment` where student= %s", self.student)
frappe.db.set_value("Student", self.student, "joining_date", date)
-
+
def make_fee_records(self):
from erpnext.education.api import get_fee_components
fee_list = []
@@ -54,7 +56,7 @@ class ProgramEnrollment(Document):
"program_enrollment": self.name,
"components": fee_components
})
-
+
fees.save()
fees.submit()
fee_list.append(fees.name)
@@ -66,6 +68,56 @@ class ProgramEnrollment(Document):
def get_courses(self):
return frappe.db.sql('''select course, course_name from `tabProgram Course` where parent = %s and required = 1''', (self.program), as_dict=1)
+ def create_course_enrollments(self):
+ student = frappe.get_doc("Student", self.student)
+ program = frappe.get_doc("Program", self.program)
+ course_list = [course.course for course in program.get_all_children()]
+ for course_name in course_list:
+ student.enroll_in_course(course_name=course_name, program_enrollment=self.name)
+
+ def get_all_course_enrollments(self):
+ course_enrollment_names = frappe.get_list("Course Enrollment", filters={'program_enrollment': self.name})
+ return [frappe.get_doc('Course Enrollment', course_enrollment.name) for course_enrollment in course_enrollment_names]
+
+ def get_quiz_progress(self):
+ student = frappe.get_doc("Student", self.student)
+ quiz_progress = frappe._dict()
+ progress_list = []
+ for course_enrollment in self.get_all_course_enrollments():
+ course_progress = course_enrollment.get_progress(student)
+ for progress_item in course_progress:
+ if progress_item['content_type'] == "Quiz":
+ progress_item['course'] = course_enrollment.course
+ progress_list.append(progress_item)
+ if not progress_list:
+ return None
+ quiz_progress.quiz_attempt = progress_list
+ quiz_progress.name = self.program
+ quiz_progress.program = self.program
+ return quiz_progress
+
+ def get_program_progress(self):
+ import math
+ program = frappe.get_doc("Program", self.program)
+ program_progress = {}
+ progress = []
+ for course in program.get_all_children():
+ course_progress = lms.get_student_course_details(course.course, self.program)
+ is_complete = False
+ if course_progress['flag'] == "Completed":
+ is_complete = True
+ progress.append({'course_name': course.course_name, 'name': course.course, 'is_complete': is_complete})
+
+ program_progress['progress'] = progress
+ program_progress['name'] = self.program
+ program_progress['program'] = frappe.get_value("Program", self.program, 'program_name')
+
+ try:
+ program_progress['percentage'] = math.ceil((sum([item['is_complete'] for item in progress] * 100)/len(progress)))
+ except ZeroDivisionError:
+ program_progress['percentage'] = 0
+
+ return program_progress
@frappe.whitelist()
def get_program_courses(doctype, txt, searchfield, start, page_len, filters):
@@ -102,11 +154,11 @@ def get_students(doctype, txt, searchfield, start, page_len, filters):
return frappe.db.sql("""select
name, title from tabStudent
- where
+ where
name not in (%s)
- and
+ and
`%s` LIKE %s
- order by
+ order by
idx desc, name
limit %s, %s"""%(
", ".join(['%s']*len(students)), searchfield, "%s", "%s", "%s"),
diff --git a/erpnext/education/doctype/program_enrollment/test_program_enrollment.py b/erpnext/education/doctype/program_enrollment/test_program_enrollment.py
index c26e89920b..c6cbee1b75 100644
--- a/erpnext/education/doctype/program_enrollment/test_program_enrollment.py
+++ b/erpnext/education/doctype/program_enrollment/test_program_enrollment.py
@@ -6,7 +6,21 @@ from __future__ import unicode_literals
import frappe
import unittest
-# test_records = frappe.get_test_records('Program Enrollment')
+from erpnext.education.doctype.student.test_student import create_student
+from erpnext.education.doctype.student.test_student import get_student
+from erpnext.education.doctype.program.test_program import make_program_and_linked_courses
+from erpnext.education.doctype.course_activity.test_course_activity import make_course_activity
class TestProgramEnrollment(unittest.TestCase):
- pass
+
+ def setUp(self):
+ create_student({"first_name": "_Test Name", "last_name": "_Test Last Name", "email": "_test_student@example.com"})
+ make_program_and_linked_courses("_Test Program 1", ["_Test Course 1", "_Test Course 2"])
+
+ def test_create_course_enrollments(self):
+ student = get_student("_test_student@example.com")
+ enrollment = student.enroll_in_program("_Test Program 1")
+ course_enrollments = student.get_all_course_enrollments()
+ self.assertTrue("_Test Course 1" in course_enrollments.keys())
+ self.assertTrue("_Test Course 2" in course_enrollments.keys())
+ frappe.db.rollback()
\ No newline at end of file
diff --git a/erpnext/education/doctype/program_enrollment_tool/program_enrollment_tool.py b/erpnext/education/doctype/program_enrollment_tool/program_enrollment_tool.py
index db23ac744d..9f8f9f4dc0 100644
--- a/erpnext/education/doctype/program_enrollment_tool/program_enrollment_tool.py
+++ b/erpnext/education/doctype/program_enrollment_tool/program_enrollment_tool.py
@@ -48,7 +48,7 @@ class ProgramEnrollmentTool(Document):
return students
else:
frappe.throw(_("No students Found"))
-
+
def enroll_students(self):
total = len(self.students)
for i, stud in enumerate(self.students):
diff --git a/erpnext/education/doctype/question/__init__.py b/erpnext/education/doctype/question/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/education/doctype/question/question.js b/erpnext/education/doctype/question/question.js
new file mode 100644
index 0000000000..01b3091b58
--- /dev/null
+++ b/erpnext/education/doctype/question/question.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Question', {
+ refresh: function(frm) {
+
+ }
+});
diff --git a/erpnext/education/doctype/question/question.json b/erpnext/education/doctype/question/question.json
new file mode 100644
index 0000000000..14a9f3ce92
--- /dev/null
+++ b/erpnext/education/doctype/question/question.json
@@ -0,0 +1,167 @@
+{
+ "allow_copy": 0,
+ "allow_events_in_timeline": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 1,
+ "allow_rename": 0,
+ "autoname": "format:QUESTION-{#####}",
+ "beta": 0,
+ "creation": "2018-10-01 15:58:00.696815",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "question",
+ "fieldtype": "Small Text",
+ "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": "Question",
+ "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,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "description": "",
+ "fetch_if_empty": 0,
+ "fieldname": "options",
+ "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": "Options",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Options",
+ "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,
+ "translatable": 0,
+ "unique": 0
+ }
+ ],
+ "has_web_view": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2019-04-22 14:02:08.140652",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Question",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "amend": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Academics User",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ },
+ {
+ "amend": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Instructor",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ },
+ {
+ "amend": 0,
+ "cancel": 0,
+ "create": 0,
+ "delete": 0,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "LMS User",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 0
+ }
+ ],
+ "quick_entry": 1,
+ "read_only": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 0,
+ "track_seen": 0,
+ "track_views": 0
+}
\ No newline at end of file
diff --git a/erpnext/education/doctype/question/question.py b/erpnext/education/doctype/question/question.py
new file mode 100644
index 0000000000..8cd23983ce
--- /dev/null
+++ b/erpnext/education/doctype/question/question.py
@@ -0,0 +1,38 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe import _
+from frappe.model.document import Document
+
+class Question(Document):
+
+ def validate(self):
+ self.check_at_least_one_option()
+ self.check_minimum_one_correct_answer()
+
+ def check_at_least_one_option(self):
+ if len(self.options) <= 1:
+ frappe.throw(_("A question must have more than one options"))
+ else:
+ pass
+
+ def check_minimum_one_correct_answer(self):
+ correct_options = [option.is_correct for option in self.options]
+ if bool(sum(correct_options)):
+ pass
+ else:
+ frappe.throw(_("A qustion must have at least one correct options"))
+
+ def get_answer(self):
+ options = self.options
+ answers = [item.name for item in options if item.is_correct == True]
+ if len(answers) == 0:
+ frappe.throw("No correct answer is set for {0}".format(self.name))
+ return None
+ elif len(answers) == 1:
+ return answers[0]
+ else:
+ return answers
\ No newline at end of file
diff --git a/erpnext/education/doctype/question/test_question.js b/erpnext/education/doctype/question/test_question.js
new file mode 100644
index 0000000000..509939c6b5
--- /dev/null
+++ b/erpnext/education/doctype/question/test_question.js
@@ -0,0 +1,23 @@
+/* eslint-disable */
+// rename this file from _test_[name] to test_[name] to activate
+// and remove above this line
+
+QUnit.test("test: Question", function (assert) {
+ let done = assert.async();
+
+ // number of asserts
+ assert.expect(1);
+
+ frappe.run_serially([
+ // insert a new Question
+ () => frappe.tests.make('Question', [
+ // values to be set
+ {key: 'value'}
+ ]),
+ () => {
+ assert.equal(cur_frm.doc.key, 'value');
+ },
+ () => done()
+ ]);
+
+});
diff --git a/erpnext/education/doctype/question/test_question.py b/erpnext/education/doctype/question/test_question.py
new file mode 100644
index 0000000000..552872e15f
--- /dev/null
+++ b/erpnext/education/doctype/question/test_question.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+
+class TestQuestion(unittest.TestCase):
+ pass
diff --git a/erpnext/education/doctype/quiz/__init__.py b/erpnext/education/doctype/quiz/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/education/doctype/quiz/quiz.js b/erpnext/education/doctype/quiz/quiz.js
new file mode 100644
index 0000000000..122cf37818
--- /dev/null
+++ b/erpnext/education/doctype/quiz/quiz.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Quiz', {
+ refresh: function(frm) {
+
+ }
+});
diff --git a/erpnext/education/doctype/quiz/quiz.json b/erpnext/education/doctype/quiz/quiz.json
new file mode 100644
index 0000000000..f91bc0f021
--- /dev/null
+++ b/erpnext/education/doctype/quiz/quiz.json
@@ -0,0 +1,299 @@
+{
+ "allow_copy": 0,
+ "allow_events_in_timeline": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "autoname": "field:title",
+ "beta": 0,
+ "creation": "2018-10-17 05:52:50.149904",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 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": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 1
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "question",
+ "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": "Question",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Quiz Question",
+ "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,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "quiz_configuration_section",
+ "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": "Quiz Configuration",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "passing_score",
+ "fieldtype": "Float",
+ "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": "Passing Score",
+ "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,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "1",
+ "description": "Enter 0 to waive limit",
+ "fieldname": "max_attempts",
+ "fieldtype": "Int",
+ "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": "Max Attempts",
+ "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,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "Last Highest Score",
+ "fieldname": "grading_basis",
+ "fieldtype": "Select",
+ "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": "Grading Basis",
+ "length": 0,
+ "no_copy": 0,
+ "options": "\nLast Attempt\nLast Highest Score",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ }
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2018-11-25 19:07:36.190116",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Quiz",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "amend": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Academics User",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ },
+ {
+ "amend": 0,
+ "cancel": 0,
+ "create": 0,
+ "delete": 0,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "LMS User",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 0
+ },
+ {
+ "amend": 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": "Instructor",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ }
+ ],
+ "quick_entry": 1,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 0,
+ "track_views": 0
+}
\ No newline at end of file
diff --git a/erpnext/education/doctype/quiz/quiz.py b/erpnext/education/doctype/quiz/quiz.py
new file mode 100644
index 0000000000..6da50a6e25
--- /dev/null
+++ b/erpnext/education/doctype/quiz/quiz.py
@@ -0,0 +1,64 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe.model.document import Document
+
+class Quiz(Document):
+
+ def validate_quiz_attempts(self, enrollment, quiz_name):
+ if self.max_attempts > 0:
+ try:
+ if len(frappe.get_all("Quiz Activity", {'enrollment': enrollment.name, 'quiz': quiz_name})) >= self.max_attempts:
+ frappe.throw('Maximum attempts reached!')
+ except Exception as e:
+ pass
+
+
+ def evaluate(self, response_dict, quiz_name):
+ # self.validate_quiz_attempts(enrollment, quiz_name)
+ questions = [frappe.get_doc('Question', question.question_link) for question in self.question]
+ answers = {q.name:q.get_answer() for q in questions}
+ correct_answers = {}
+ for key in answers:
+ try:
+ if isinstance(response_dict[key], list):
+ result = compare_list_elementwise(response_dict[key], answers[key])
+ else:
+ result = (response_dict[key] == answers[key])
+ except:
+ result = False
+ correct_answers[key] = result
+ score = (sum(correct_answers.values()) * 100 ) / len(answers)
+ if score >= self.passing_score:
+ status = "Pass"
+ else:
+ status = "Fail"
+ return correct_answers, score, status
+
+
+ def get_questions(self):
+ quiz_question = self.get_all_children()
+ if quiz_question:
+ questions = [frappe.get_doc('Question', question.question_link).as_dict() for question in quiz_question]
+ for question in questions:
+ correct_options = [option.is_correct for option in question.options]
+ if sum(correct_options) > 1:
+ question['type'] = "MultipleChoice"
+ else:
+ question['type'] = "SingleChoice"
+ return questions
+ else:
+ return None
+
+def compare_list_elementwise(*args):
+ try:
+ if all(len(args[0]) == len(_arg) for _arg in args[1:]):
+ return all(all([element in (item) for element in args[0]]) for item in args[1:])
+ else:
+ return False
+ except TypeError:
+ frappe.throw("Compare List function takes on list arguments")
+
diff --git a/erpnext/education/doctype/quiz/test_quiz.js b/erpnext/education/doctype/quiz/test_quiz.js
new file mode 100644
index 0000000000..147d13952a
--- /dev/null
+++ b/erpnext/education/doctype/quiz/test_quiz.js
@@ -0,0 +1,23 @@
+/* eslint-disable */
+// rename this file from _test_[name] to test_[name] to activate
+// and remove above this line
+
+QUnit.test("test: Quiz", function (assert) {
+ let done = assert.async();
+
+ // number of asserts
+ assert.expect(1);
+
+ frappe.run_serially([
+ // insert a new Quiz
+ () => frappe.tests.make('Quiz', [
+ // values to be set
+ {key: 'value'}
+ ]),
+ () => {
+ assert.equal(cur_frm.doc.key, 'value');
+ },
+ () => done()
+ ]);
+
+});
diff --git a/erpnext/education/doctype/quiz/test_quiz.py b/erpnext/education/doctype/quiz/test_quiz.py
new file mode 100644
index 0000000000..344fd544ee
--- /dev/null
+++ b/erpnext/education/doctype/quiz/test_quiz.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+
+class TestQuiz(unittest.TestCase):
+ pass
diff --git a/erpnext/education/doctype/quiz_activity/__init__.py b/erpnext/education/doctype/quiz_activity/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/education/doctype/quiz_activity/quiz_activity.js b/erpnext/education/doctype/quiz_activity/quiz_activity.js
new file mode 100644
index 0000000000..f6ba12ca4d
--- /dev/null
+++ b/erpnext/education/doctype/quiz_activity/quiz_activity.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Quiz Activity', {
+ refresh: function(frm) {
+
+ }
+});
diff --git a/erpnext/education/doctype/quiz_activity/quiz_activity.json b/erpnext/education/doctype/quiz_activity/quiz_activity.json
new file mode 100644
index 0000000000..e78db42f7d
--- /dev/null
+++ b/erpnext/education/doctype/quiz_activity/quiz_activity.json
@@ -0,0 +1,490 @@
+{
+ "allow_copy": 0,
+ "allow_events_in_timeline": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "autoname": "format:EDU-QA-{YYYY}-{#####}",
+ "beta": 1,
+ "creation": "2018-10-15 15:48:40.482821",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "enrollment",
+ "fieldtype": "Link",
+ "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": "Enrollment",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Course Enrollment",
+ "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": 1,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_from": "enrollment.student",
+ "fieldname": "student",
+ "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": "Student",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Student",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 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,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_from": "enrollment.course",
+ "fieldname": "course",
+ "fieldtype": "Link",
+ "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": "Course",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Course",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 1,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 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,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "quiz",
+ "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": "Quiz",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Quiz",
+ "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": 1,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "column_break_7",
+ "fieldtype": "Column Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "status",
+ "fieldtype": "Select",
+ "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": "Status",
+ "length": 0,
+ "no_copy": 0,
+ "options": "\nPass\nFail",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "section_break_9",
+ "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,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "result",
+ "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": "Result",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Quiz Result",
+ "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": 1,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "activity_date",
+ "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": "Activity Date",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 1,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "score",
+ "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": "Score",
+ "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": 1,
+ "translatable": 0,
+ "unique": 0
+ }
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2018-11-25 19:05:52.434437",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Quiz Activity",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "amend": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Academics User",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ },
+ {
+ "amend": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "LMS User",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ },
+ {
+ "amend": 0,
+ "cancel": 0,
+ "create": 0,
+ "delete": 0,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Instructor",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 0
+ }
+ ],
+ "quick_entry": 1,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 0,
+ "track_views": 0
+}
\ No newline at end of file
diff --git a/erpnext/education/doctype/quiz_activity/quiz_activity.py b/erpnext/education/doctype/quiz_activity/quiz_activity.py
new file mode 100644
index 0000000000..24c7175397
--- /dev/null
+++ b/erpnext/education/doctype/quiz_activity/quiz_activity.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe.model.document import Document
+
+class QuizActivity(Document):
+ pass
diff --git a/erpnext/education/doctype/quiz_activity/test_quiz_activity.js b/erpnext/education/doctype/quiz_activity/test_quiz_activity.js
new file mode 100644
index 0000000000..94b5ab796a
--- /dev/null
+++ b/erpnext/education/doctype/quiz_activity/test_quiz_activity.js
@@ -0,0 +1,23 @@
+/* eslint-disable */
+// rename this file from _test_[name] to test_[name] to activate
+// and remove above this line
+
+QUnit.test("test: Quiz Activity", function (assert) {
+ let done = assert.async();
+
+ // number of asserts
+ assert.expect(1);
+
+ frappe.run_serially([
+ // insert a new Quiz Activity
+ () => frappe.tests.make('Quiz Activity', [
+ // values to be set
+ {key: 'value'}
+ ]),
+ () => {
+ assert.equal(cur_frm.doc.key, 'value');
+ },
+ () => done()
+ ]);
+
+});
diff --git a/erpnext/education/doctype/quiz_activity/test_quiz_activity.py b/erpnext/education/doctype/quiz_activity/test_quiz_activity.py
new file mode 100644
index 0000000000..fb0425d809
--- /dev/null
+++ b/erpnext/education/doctype/quiz_activity/test_quiz_activity.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+
+class TestQuizActivity(unittest.TestCase):
+ pass
diff --git a/erpnext/education/doctype/quiz_question/__init__.py b/erpnext/education/doctype/quiz_question/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/education/doctype/quiz_question/quiz_question.json b/erpnext/education/doctype/quiz_question/quiz_question.json
new file mode 100644
index 0000000000..3857c5ca8d
--- /dev/null
+++ b/erpnext/education/doctype/quiz_question/quiz_question.json
@@ -0,0 +1,110 @@
+{
+ "allow_copy": 0,
+ "allow_events_in_timeline": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "beta": 0,
+ "creation": "2018-10-17 06:13:00.098883",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "question_link",
+ "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": "Question Link",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Question",
+ "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,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_from": "question_link.question",
+ "fieldname": "question",
+ "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": "Question",
+ "length": 0,
+ "no_copy": 0,
+ "options": "",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ }
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 1,
+ "max_attachments": 0,
+ "modified": "2018-10-18 15:35:12.195250",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Quiz Question",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 0,
+ "track_views": 0
+}
\ No newline at end of file
diff --git a/erpnext/education/doctype/quiz_question/quiz_question.py b/erpnext/education/doctype/quiz_question/quiz_question.py
new file mode 100644
index 0000000000..317e75b2cb
--- /dev/null
+++ b/erpnext/education/doctype/quiz_question/quiz_question.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe.model.document import Document
+
+class QuizQuestion(Document):
+ pass
diff --git a/erpnext/education/doctype/quiz_result/__init__.py b/erpnext/education/doctype/quiz_result/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/education/doctype/quiz_result/quiz_result.js b/erpnext/education/doctype/quiz_result/quiz_result.js
new file mode 100644
index 0000000000..a018749e69
--- /dev/null
+++ b/erpnext/education/doctype/quiz_result/quiz_result.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Quiz Result', {
+ refresh: function(frm) {
+
+ }
+});
diff --git a/erpnext/education/doctype/quiz_result/quiz_result.json b/erpnext/education/doctype/quiz_result/quiz_result.json
new file mode 100644
index 0000000000..86505ac756
--- /dev/null
+++ b/erpnext/education/doctype/quiz_result/quiz_result.json
@@ -0,0 +1,145 @@
+{
+ "allow_copy": 0,
+ "allow_events_in_timeline": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "beta": 0,
+ "creation": "2018-10-15 15:52:25.766374",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "question",
+ "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": "Question",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Question",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 1,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "selected_option",
+ "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": "Selected Option",
+ "length": 0,
+ "no_copy": 0,
+ "options": "",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 1,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "quiz_result",
+ "fieldtype": "Select",
+ "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": "Result",
+ "length": 0,
+ "no_copy": 0,
+ "options": "\nCorrect\nWrong",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 1,
+ "translatable": 0,
+ "unique": 0
+ }
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 1,
+ "max_attachments": 0,
+ "modified": "2019-03-27 17:58:54.388848",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Quiz Result",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 0,
+ "track_views": 0
+}
\ No newline at end of file
diff --git a/erpnext/education/doctype/quiz_result/quiz_result.py b/erpnext/education/doctype/quiz_result/quiz_result.py
new file mode 100644
index 0000000000..a4fd9f062f
--- /dev/null
+++ b/erpnext/education/doctype/quiz_result/quiz_result.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe.model.document import Document
+
+class QuizResult(Document):
+ pass
diff --git a/erpnext/education/doctype/quiz_result/test_quiz_result.js b/erpnext/education/doctype/quiz_result/test_quiz_result.js
new file mode 100644
index 0000000000..43f53a1dc7
--- /dev/null
+++ b/erpnext/education/doctype/quiz_result/test_quiz_result.js
@@ -0,0 +1,23 @@
+/* eslint-disable */
+// rename this file from _test_[name] to test_[name] to activate
+// and remove above this line
+
+QUnit.test("test: Quiz Result", function (assert) {
+ let done = assert.async();
+
+ // number of asserts
+ assert.expect(1);
+
+ frappe.run_serially([
+ // insert a new Quiz Result
+ () => frappe.tests.make('Quiz Result', [
+ // values to be set
+ {key: 'value'}
+ ]),
+ () => {
+ assert.equal(cur_frm.doc.key, 'value');
+ },
+ () => done()
+ ]);
+
+});
diff --git a/erpnext/education/doctype/quiz_result/test_quiz_result.py b/erpnext/education/doctype/quiz_result/test_quiz_result.py
new file mode 100644
index 0000000000..86ee52d87d
--- /dev/null
+++ b/erpnext/education/doctype/quiz_result/test_quiz_result.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+
+class TestQuizResult(unittest.TestCase):
+ pass
diff --git a/erpnext/education/doctype/student/student.json b/erpnext/education/doctype/student/student.json
index af6c8b16bc..bee915e91d 100644
--- a/erpnext/education/doctype/student/student.json
+++ b/erpnext/education/doctype/student/student.json
@@ -1,5 +1,6 @@
{
"allow_copy": 0,
+ "allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 1,
@@ -20,6 +21,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "section_break_1",
"fieldtype": "Section Break",
"hidden": 0,
@@ -52,6 +54,7 @@
"collapsible": 0,
"columns": 0,
"default": "1",
+ "fetch_if_empty": 0,
"fieldname": "enabled",
"fieldtype": "Check",
"hidden": 0,
@@ -84,6 +87,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "section_break_3",
"fieldtype": "Section Break",
"hidden": 0,
@@ -115,6 +119,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "first_name",
"fieldtype": "Data",
"hidden": 0,
@@ -147,6 +152,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "middle_name",
"fieldtype": "Data",
"hidden": 0,
@@ -179,6 +185,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "last_name",
"fieldtype": "Data",
"hidden": 0,
@@ -211,6 +218,41 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "user",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "User ID",
+ "length": 0,
+ "no_copy": 0,
+ "options": "User",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "column_break_4",
"fieldtype": "Column Break",
"hidden": 0,
@@ -243,6 +285,7 @@
"collapsible": 0,
"columns": 0,
"default": "",
+ "fetch_if_empty": 0,
"fieldname": "naming_series",
"fieldtype": "Select",
"hidden": 0,
@@ -276,6 +319,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "student_email_id",
"fieldtype": "Data",
"hidden": 0,
@@ -295,7 +339,7 @@
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
- "reqd": 0,
+ "reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
@@ -308,6 +352,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "student_mobile_number",
"fieldtype": "Data",
"hidden": 0,
@@ -342,6 +387,7 @@
"collapsible": 0,
"columns": 0,
"default": "Today",
+ "fetch_if_empty": 0,
"fieldname": "joining_date",
"fieldtype": "Date",
"hidden": 0,
@@ -374,6 +420,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "image",
"fieldtype": "Attach Image",
"hidden": 1,
@@ -408,6 +455,7 @@
"collapsible": 0,
"collapsible_depends_on": "",
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "section_break_7",
"fieldtype": "Section Break",
"hidden": 0,
@@ -440,6 +488,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "date_of_birth",
"fieldtype": "Date",
"hidden": 0,
@@ -472,6 +521,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "blood_group",
"fieldtype": "Select",
"hidden": 0,
@@ -505,6 +555,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "column_break_3",
"fieldtype": "Column Break",
"hidden": 0,
@@ -536,6 +587,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "gender",
"fieldtype": "Select",
"hidden": 0,
@@ -569,6 +621,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "nationality",
"fieldtype": "Data",
"hidden": 0,
@@ -602,6 +655,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "student_applicant",
"fieldtype": "Link",
"hidden": 0,
@@ -635,6 +689,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "section_break_22",
"fieldtype": "Section Break",
"hidden": 0,
@@ -667,6 +722,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "address_line_1",
"fieldtype": "Data",
"hidden": 0,
@@ -699,6 +755,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "address_line_2",
"fieldtype": "Data",
"hidden": 0,
@@ -731,6 +788,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "pincode",
"fieldtype": "Data",
"hidden": 0,
@@ -763,6 +821,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "column_break_20",
"fieldtype": "Column Break",
"hidden": 0,
@@ -794,6 +853,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "city",
"fieldtype": "Data",
"hidden": 0,
@@ -826,6 +886,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "state",
"fieldtype": "Data",
"hidden": 0,
@@ -858,6 +919,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "section_break_18",
"fieldtype": "Section Break",
"hidden": 0,
@@ -890,6 +952,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "guardians",
"fieldtype": "Table",
"hidden": 0,
@@ -923,6 +986,7 @@
"bold": 0,
"collapsible": 1,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "section_break_20",
"fieldtype": "Section Break",
"hidden": 0,
@@ -956,6 +1020,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "siblings",
"fieldtype": "Table",
"hidden": 0,
@@ -989,6 +1054,7 @@
"bold": 0,
"collapsible": 1,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "exit",
"fieldtype": "Section Break",
"hidden": 0,
@@ -1021,6 +1087,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "date_of_leaving",
"fieldtype": "Date",
"hidden": 0,
@@ -1053,6 +1120,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "leaving_certificate_number",
"fieldtype": "Data",
"hidden": 0,
@@ -1085,6 +1153,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "column_break_31",
"fieldtype": "Column Break",
"hidden": 0,
@@ -1116,6 +1185,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "reason_for_leaving",
"fieldtype": "Text",
"hidden": 0,
@@ -1149,6 +1219,7 @@
"collapsible": 0,
"columns": 0,
"default": "",
+ "fetch_if_empty": 0,
"fieldname": "title",
"fieldtype": "Data",
"hidden": 1,
@@ -1176,18 +1247,16 @@
}
],
"has_web_view": 0,
- "hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_field": "image",
- "image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
- "modified": "2018-08-21 14:44:35.278833",
+ "modified": "2019-04-10 17:46:26.893020",
"modified_by": "Administrator",
"module": "Education",
"name": "Student",
@@ -1231,11 +1300,48 @@
"share": 1,
"submit": 0,
"write": 1
+ },
+ {
+ "amend": 0,
+ "cancel": 0,
+ "create": 0,
+ "delete": 0,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Student",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 0
+ },
+ {
+ "amend": 0,
+ "cancel": 0,
+ "create": 0,
+ "delete": 0,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "LMS User",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 0
}
],
"quick_entry": 0,
"read_only": 0,
- "read_only_onload": 0,
"restrict_to_domain": "Education",
"show_name_in_global_search": 1,
"sort_field": "modified",
diff --git a/erpnext/education/doctype/student/student.py b/erpnext/education/doctype/student/student.py
index 53bf6f7273..cf8407c4ea 100644
--- a/erpnext/education/doctype/student/student.py
+++ b/erpnext/education/doctype/student/student.py
@@ -7,7 +7,7 @@ import frappe
from frappe.model.document import Document
from frappe import _
from frappe.desk.form.linked_with import get_linked_doctypes
-
+from erpnext.education.utils import check_content_completion, check_quiz_completion
class Student(Document):
def validate(self):
self.title = " ".join(filter(None, [self.first_name, self.middle_name, self.last_name]))
@@ -39,11 +39,99 @@ class Student(Document):
if student:
frappe.throw(_("Student {0} exist against student applicant {1}").format(student[0][0], self.student_applicant))
+ def after_insert(self):
+ self.create_student_user()
+
+ def create_student_user(self):
+ """Create a website user for student creation if not already exists"""
+ if not frappe.db.exists("User", self.student_email_id):
+ student_user = frappe.get_doc({
+ 'doctype':'User',
+ 'first_name': self.first_name,
+ 'last_name': self.last_name,
+ 'email': self.student_email_id,
+ 'gender': self.gender,
+ 'send_welcome_email': 1,
+ 'user_type': 'Website User'
+ })
+ student_user.add_roles("Student", "LMS User")
+ student_user.save()
+ update_password_link = student_user.reset_password()
+
def update_applicant_status(self):
"""Updates Student Applicant status to Admitted"""
if self.student_applicant:
frappe.db.set_value("Student Applicant", self.student_applicant, "application_status", "Admitted")
+ def get_all_course_enrollments(self):
+ """Returns a list of course enrollments linked with the current student"""
+ course_enrollments = frappe.get_all("Course Enrollment", filters={"student": self.name}, fields=['course', 'name'])
+ if not course_enrollments:
+ return None
+ else:
+ enrollments = {item['course']:item['name'] for item in course_enrollments}
+ return enrollments
+
+ def get_program_enrollments(self):
+ """Returns a list of course enrollments linked with the current student"""
+ program_enrollments = frappe.get_all("Program Enrollment", filters={"student": self.name}, fields=['program'])
+ if not program_enrollments:
+ return None
+ else:
+ enrollments = [item['program'] for item in program_enrollments]
+ return enrollments
+
+ def get_topic_progress(self, course_enrollment_name, topic):
+ """
+ Get Progress Dictionary of a student for a particular topic
+ :param self: Student Object
+ :param course_enrollment_name: Name of the Course Enrollment
+ :param topic: Topic DocType Object
+ """
+ contents = topic.get_contents()
+ progress = []
+ for content in contents:
+ if content.doctype in ('Article', 'Video'):
+ status = check_content_completion(content.name, content.doctype, course_enrollment_name)
+ progress.append({'content': content.name, 'content_type': content.doctype, 'is_complete': status})
+ elif content.doctype == 'Quiz':
+ status, score, result = check_quiz_completion(content, course_enrollment_name)
+ progress.append({'content': content.name, 'content_type': content.doctype, 'is_complete': status, 'score': score, 'result': result})
+ return progress
+
+ def enroll_in_program(self, program_name):
+ try:
+ enrollment = frappe.get_doc({
+ "doctype": "Program Enrollment",
+ "student": self.name,
+ "academic_year": frappe.get_last_doc("Academic Year").name,
+ "program": program_name,
+ "enrollment_date": frappe.utils.datetime.datetime.now()
+ })
+ enrollment.save(ignore_permissions=True)
+ except frappe.exceptions.ValidationError:
+ enrollment_name = frappe.get_list("Program Enrollment", filters={"student": self.name, "Program": program_name})[0].name
+ return frappe.get_doc("Program Enrollment", enrollment_name)
+ else:
+ enrollment.submit()
+ return enrollment
+
+ def enroll_in_course(self, course_name, program_enrollment, enrollment_date=frappe.utils.datetime.datetime.now()):
+ try:
+ enrollment = frappe.get_doc({
+ "doctype": "Course Enrollment",
+ "student": self.name,
+ "course": course_name,
+ "program_enrollment": program_enrollment,
+ "enrollment_date": enrollment_date
+ })
+ enrollment.save(ignore_permissions=True)
+ except frappe.exceptions.ValidationError:
+ enrollment_name = frappe.get_list("Course Enrollment", filters={"student": self.name, "course": course_name, "program_enrollment": program_enrollment})[0].name
+ return frappe.get_doc("Program Enrollment", enrollment_name)
+ else:
+ return enrollment
+
def get_timeline_data(doctype, name):
'''Return timeline for attendance'''
return dict(frappe.db.sql('''select unix_timestamp(`date`), count(*)
diff --git a/erpnext/education/doctype/student/student_dashboard.py b/erpnext/education/doctype/student/student_dashboard.py
index d86f4f231c..0cbd17b8a4 100644
--- a/erpnext/education/doctype/student/student_dashboard.py
+++ b/erpnext/education/doctype/student/student_dashboard.py
@@ -9,7 +9,7 @@ def get_data():
'transactions': [
{
'label': _('Admission'),
- 'items': ['Program Enrollment']
+ 'items': ['Program Enrollment', 'Course Enrollment']
},
{
'label': _('Student Activity'),
@@ -19,6 +19,10 @@ def get_data():
'label': _('Assessment'),
'items': ['Assessment Result']
},
+ {
+ 'label': _('Student LMS Activity'),
+ 'items': ['Course Activity', 'Quiz Activity' ]
+ },
{
'label': _('Attendance'),
'items': ['Student Attendance', 'Student Leave Application']
diff --git a/erpnext/education/doctype/student/test_records.json b/erpnext/education/doctype/student/test_records.json
index 6acc4b688f..8ad3afa6a8 100644
--- a/erpnext/education/doctype/student/test_records.json
+++ b/erpnext/education/doctype/student/test_records.json
@@ -6,6 +6,7 @@
"program": "TC101",
"date_of_birth": "2000-01-01",
"gender": "Male",
+ "student_email_id": "_test_student@example.com",
"blood_group": "A+"
},
@@ -16,6 +17,7 @@
"program": "TC101",
"date_of_birth": "2000-01-01",
"gender": "Male",
+ "student_email_id": "_test_student_1@example.com",
"blood_group": "A+"
},
@@ -25,27 +27,8 @@
"last_name": "Name 2",
"program": "TC101",
"date_of_birth": "2000-01-01",
- "gender": "Male",
- "blood_group": "A+"
-
- },
- {
- "first_name": "_Test",
- "middle_name": "Student",
- "last_name": "Name 3",
- "program": "TC101",
- "date_of_birth": "2000-01-01",
- "gender": "Male",
- "blood_group": "A+"
-
- },
- {
- "first_name": "_Test",
- "middle_name": "Student",
- "last_name": "Name 4",
- "program": "TC101",
- "date_of_birth": "2000-01-01",
- "gender": "Male",
+ "gender": "Female",
+ "student_email_id": "_test_student_2@example.com",
"blood_group": "A+"
}
diff --git a/erpnext/education/doctype/student/test_student.py b/erpnext/education/doctype/student/test_student.py
index cc6537f865..8610edbf28 100644
--- a/erpnext/education/doctype/student/test_student.py
+++ b/erpnext/education/doctype/student/test_student.py
@@ -2,11 +2,60 @@
# Copyright (c) 2015, Frappe Technologies and Contributors
# See license.txt
from __future__ import unicode_literals
+from frappe.test_runner import make_test_records
+from erpnext.education.doctype.program.test_program import make_program_and_linked_courses
+from erpnext.education.doctype.course.test_course import make_course
import frappe
import unittest
-# test_records = frappe.get_test_records('Student')
-
+test_records = frappe.get_test_records('Student')
class TestStudent(unittest.TestCase):
- pass
+ def setUp(self):
+ create_student({"first_name": "_Test Name", "last_name": "_Test Last Name", "email": "_test_student@example.com"})
+ make_program_and_linked_courses("_Test Program 1", ["_Test Course 1", "_Test Course 2"])
+
+ def test_create_student_user(self):
+ self.assertTrue(bool(frappe.db.exists("User", "_test_student@example.com")))
+ frappe.db.rollback()
+
+ def test_enroll_in_program(self):
+ student = get_student("_test_student@example.com")
+ enrollment = student.enroll_in_program("_Test Program 1")
+ test_enrollment = frappe.get_all("Program Enrollment", filters={"student": student.name, "Program": "_Test Program 1"})
+ self.assertTrue(len(test_enrollment))
+ self.assertEqual(test_enrollment[0]['name'], enrollment.name)
+ frappe.db.rollback()
+
+ def test_get_program_enrollments(self):
+ student = get_student("_test_student@example.com")
+ enrollment = student.enroll_in_program("_Test Program 1")
+ program_enrollments = student.get_program_enrollments()
+ self.assertTrue("_Test Program 1" in program_enrollments)
+ frappe.db.rollback()
+
+ def test_get_all_course_enrollments(self):
+ student = get_student("_test_student@example.com")
+ enrollment = student.enroll_in_program("_Test Program 1")
+ course_enrollments = student.get_all_course_enrollments()
+ self.assertTrue("_Test Course 1" in course_enrollments.keys())
+ self.assertTrue("_Test Course 2" in course_enrollments.keys())
+ frappe.db.rollback()
+
+def create_student(student_dict):
+ student = get_student(student_dict['email'])
+ if not student:
+ student = frappe.get_doc({
+ "doctype": "Student",
+ "first_name": student_dict['first_name'],
+ "last_name": student_dict['last_name'],
+ "student_email_id": student_dict['email']
+ }).insert()
+ return student
+
+def get_student(email):
+ try:
+ student_id = frappe.get_all("Student", {"student_email_id": email}, ["name"])[0].name
+ return frappe.get_doc("Student", student_id)
+ except IndexError:
+ return None
\ No newline at end of file
diff --git a/erpnext/education/doctype/student_applicant/student_applicant.json b/erpnext/education/doctype/student_applicant/student_applicant.json
index 297821f753..71134e0907 100644
--- a/erpnext/education/doctype/student_applicant/student_applicant.json
+++ b/erpnext/education/doctype/student_applicant/student_applicant.json
@@ -143,6 +143,39 @@
"translatable": 0,
"unique": 0
},
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "0",
+ "fieldname": "lms_only",
+ "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": "LMS Only",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
@@ -627,7 +660,7 @@
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
- "reqd": 0,
+ "reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
@@ -1160,7 +1193,7 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
- "modified": "2018-08-21 14:44:30.146264",
+ "modified": "2018-10-05 13:15:59.283862",
"modified_by": "Administrator",
"module": "Education",
"name": "Student Applicant",
diff --git a/erpnext/education/doctype/topic/__init__.py b/erpnext/education/doctype/topic/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/education/doctype/topic/test_topic.js b/erpnext/education/doctype/topic/test_topic.js
new file mode 100644
index 0000000000..4460b79478
--- /dev/null
+++ b/erpnext/education/doctype/topic/test_topic.js
@@ -0,0 +1,23 @@
+/* eslint-disable */
+// rename this file from _test_[name] to test_[name] to activate
+// and remove above this line
+
+QUnit.test("test: Topic", function (assert) {
+ let done = assert.async();
+
+ // number of asserts
+ assert.expect(1);
+
+ frappe.run_serially([
+ // insert a new Topic
+ () => frappe.tests.make('Topic', [
+ // values to be set
+ {key: 'value'}
+ ]),
+ () => {
+ assert.equal(cur_frm.doc.key, 'value');
+ },
+ () => done()
+ ]);
+
+});
diff --git a/erpnext/education/doctype/topic/test_topic.py b/erpnext/education/doctype/topic/test_topic.py
new file mode 100644
index 0000000000..d03db1cb93
--- /dev/null
+++ b/erpnext/education/doctype/topic/test_topic.py
@@ -0,0 +1,49 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+
+class TestTopic(unittest.TestCase):
+ def setUp(self):
+ make_topic_and_linked_content("_Test Topic 1", [{"type":"Article", "name": "_Test Article 1"}])
+
+ def test_get_contents(self):
+ topic = frappe.get_doc("Topic", "_Test Topic 1")
+ contents = topic.get_contents()
+ self.assertEqual(contents[0].doctype, "Article")
+ self.assertEqual(contents[0].name, "_Test Article 1")
+ frappe.db.rollback()
+
+def make_topic(name):
+ try:
+ topic = frappe.get_doc("Topic", name)
+ except frappe.DoesNotExistError:
+ topic = frappe.get_doc({
+ "doctype": "Topic",
+ "topic_name": name,
+ "topic_code": name,
+ }).insert()
+ return topic.name
+
+def make_topic_and_linked_content(topic_name, content_dict_list):
+ try:
+ topic = frappe.get_doc("Topic", topic_name)
+ except frappe.DoesNotExistError:
+ make_topic(topic_name)
+ topic = frappe.get_doc("Topic", topic_name)
+ content_list = [make_content(content['type'], content['name']) for content in content_dict_list]
+ for content in content_list:
+ topic.append("topic_content", {"content": content.title, "content_type": content.doctype})
+ topic.save()
+ return topic
+
+
+def make_content(type, name):
+ try:
+ content = frappe.get_doc(type, name)
+ except frappe.DoesNotExistError:
+ content = frappe.get_doc({"doctype": type, "title": name}).insert()
+ return content
diff --git a/erpnext/education/doctype/topic/topic.js b/erpnext/education/doctype/topic/topic.js
new file mode 100644
index 0000000000..695c17476c
--- /dev/null
+++ b/erpnext/education/doctype/topic/topic.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Topic', {
+ refresh: function(frm) {
+
+ }
+});
diff --git a/erpnext/education/doctype/topic/topic.json b/erpnext/education/doctype/topic/topic.json
new file mode 100644
index 0000000000..f47b10d780
--- /dev/null
+++ b/erpnext/education/doctype/topic/topic.json
@@ -0,0 +1,297 @@
+{
+ "allow_copy": 0,
+ "allow_events_in_timeline": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "autoname": "field:topic_code",
+ "beta": 0,
+ "creation": "2018-12-12 11:37:39.917760",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "topic_name",
+ "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": "Name",
+ "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,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "column_break_2",
+ "fieldtype": "Column Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "topic_code",
+ "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": "Code",
+ "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,
+ "translatable": 0,
+ "unique": 1
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "section_break_4",
+ "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,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "topic_content",
+ "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": "Topic Content",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Topic Content",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "hero_image",
+ "fieldtype": "Attach Image",
+ "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": "Hero Image",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ }
+ ],
+ "has_web_view": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "menu_index": 0,
+ "modified": "2019-04-09 11:35:34.137040",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Topic",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "amend": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ },
+ {
+ "amend": 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": "Administrator",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ },
+ {
+ "amend": 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": "Instructor",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ }
+ ],
+ "quick_entry": 1,
+ "read_only": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 0,
+ "track_views": 0
+}
\ No newline at end of file
diff --git a/erpnext/education/doctype/topic/topic.py b/erpnext/education/doctype/topic/topic.py
new file mode 100644
index 0000000000..339fc7d887
--- /dev/null
+++ b/erpnext/education/doctype/topic/topic.py
@@ -0,0 +1,17 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe.model.document import Document
+
+class Topic(Document):
+ def get_contents(self):
+ try:
+ topic_content_list = self.get_all_children()
+ content_data = [frappe.get_doc(topic_content.content_type, topic_content.content) for topic_content in topic_content_list]
+ except Exception as e:
+ frappe.log_error(frappe.get_traceback())
+ return None
+ return content_data
\ No newline at end of file
diff --git a/erpnext/education/doctype/topic_content/__init__.py b/erpnext/education/doctype/topic_content/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/education/doctype/topic_content/test_topic_content.js b/erpnext/education/doctype/topic_content/test_topic_content.js
new file mode 100644
index 0000000000..bf9a62d037
--- /dev/null
+++ b/erpnext/education/doctype/topic_content/test_topic_content.js
@@ -0,0 +1,23 @@
+/* eslint-disable */
+// rename this file from _test_[name] to test_[name] to activate
+// and remove above this line
+
+QUnit.test("test: Topic Content", function (assert) {
+ let done = assert.async();
+
+ // number of asserts
+ assert.expect(1);
+
+ frappe.run_serially([
+ // insert a new Topic Content
+ () => frappe.tests.make('Topic Content', [
+ // values to be set
+ {key: 'value'}
+ ]),
+ () => {
+ assert.equal(cur_frm.doc.key, 'value');
+ },
+ () => done()
+ ]);
+
+});
diff --git a/erpnext/education/doctype/topic_content/test_topic_content.py b/erpnext/education/doctype/topic_content/test_topic_content.py
new file mode 100644
index 0000000000..cf304f60bc
--- /dev/null
+++ b/erpnext/education/doctype/topic_content/test_topic_content.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+
+class TestTopicContent(unittest.TestCase):
+ pass
diff --git a/erpnext/education/doctype/topic_content/topic_content.js b/erpnext/education/doctype/topic_content/topic_content.js
new file mode 100644
index 0000000000..9cda0cabb2
--- /dev/null
+++ b/erpnext/education/doctype/topic_content/topic_content.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Topic Content', {
+ refresh: function(frm) {
+
+ }
+});
diff --git a/erpnext/education/doctype/topic_content/topic_content.json b/erpnext/education/doctype/topic_content/topic_content.json
new file mode 100644
index 0000000000..52207882e0
--- /dev/null
+++ b/erpnext/education/doctype/topic_content/topic_content.json
@@ -0,0 +1,140 @@
+{
+ "allow_copy": 0,
+ "allow_events_in_timeline": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "beta": 0,
+ "creation": "2018-12-12 11:42:57.987434",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "content_type",
+ "fieldtype": "Select",
+ "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": "Content Type",
+ "length": 0,
+ "no_copy": 0,
+ "options": "\nArticle\nVideo\nQuiz",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "column_break_2",
+ "fieldtype": "Column Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "content",
+ "fieldtype": "Dynamic 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": "Content",
+ "length": 0,
+ "no_copy": 0,
+ "options": "content_type",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ }
+ ],
+ "has_web_view": 0,
+ "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-12-12 11:46:46.112018",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Topic Content",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 0,
+ "track_views": 0
+}
\ No newline at end of file
diff --git a/erpnext/education/doctype/topic_content/topic_content.py b/erpnext/education/doctype/topic_content/topic_content.py
new file mode 100644
index 0000000000..9b2c90bb4f
--- /dev/null
+++ b/erpnext/education/doctype/topic_content/topic_content.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe.model.document import Document
+
+class TopicContent(Document):
+ pass
diff --git a/erpnext/education/doctype/video/__init__.py b/erpnext/education/doctype/video/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/education/doctype/video/test_video.js b/erpnext/education/doctype/video/test_video.js
new file mode 100644
index 0000000000..a82a221319
--- /dev/null
+++ b/erpnext/education/doctype/video/test_video.js
@@ -0,0 +1,23 @@
+/* eslint-disable */
+// rename this file from _test_[name] to test_[name] to activate
+// and remove above this line
+
+QUnit.test("test: Video", function (assert) {
+ let done = assert.async();
+
+ // number of asserts
+ assert.expect(1);
+
+ frappe.run_serially([
+ // insert a new Video
+ () => frappe.tests.make('Video', [
+ // values to be set
+ {key: 'value'}
+ ]),
+ () => {
+ assert.equal(cur_frm.doc.key, 'value');
+ },
+ () => done()
+ ]);
+
+});
diff --git a/erpnext/education/doctype/video/test_video.py b/erpnext/education/doctype/video/test_video.py
new file mode 100644
index 0000000000..ecb09a2f9e
--- /dev/null
+++ b/erpnext/education/doctype/video/test_video.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+
+class TestVideo(unittest.TestCase):
+ pass
diff --git a/erpnext/education/doctype/video/video.js b/erpnext/education/doctype/video/video.js
new file mode 100644
index 0000000000..c35c19b0c1
--- /dev/null
+++ b/erpnext/education/doctype/video/video.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Video', {
+ refresh: function(frm) {
+
+ }
+});
diff --git a/erpnext/education/doctype/video/video.json b/erpnext/education/doctype/video/video.json
new file mode 100644
index 0000000000..cc8f718ba4
--- /dev/null
+++ b/erpnext/education/doctype/video/video.json
@@ -0,0 +1,262 @@
+{
+ "allow_copy": 0,
+ "allow_events_in_timeline": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 1,
+ "allow_rename": 0,
+ "autoname": "field:title",
+ "beta": 0,
+ "creation": "2018-10-17 05:47:13.087395",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 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,
+ "translatable": 0,
+ "unique": 1
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "description",
+ "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": "Description",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "duration",
+ "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": "Duration",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "url",
+ "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": "URL",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "publish_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": "Publish Date",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ }
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2018-11-25 19:07:17.134288",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Video",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "amend": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Academics User",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ },
+ {
+ "amend": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Instructor",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ },
+ {
+ "amend": 0,
+ "cancel": 0,
+ "create": 0,
+ "delete": 0,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "LMS User",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 0
+ }
+ ],
+ "quick_entry": 1,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 0,
+ "track_views": 0
+}
\ No newline at end of file
diff --git a/erpnext/education/doctype/video/video.py b/erpnext/education/doctype/video/video.py
new file mode 100644
index 0000000000..b19f81258c
--- /dev/null
+++ b/erpnext/education/doctype/video/video.py
@@ -0,0 +1,13 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe.model.document import Document
+
+class Video(Document):
+
+
+ def get_video(self):
+ pass
diff --git a/erpnext/education/utils.py b/erpnext/education/utils.py
index 1b93c9d71e..bf766adc09 100644
--- a/erpnext/education/utils.py
+++ b/erpnext/education/utils.py
@@ -2,7 +2,7 @@
# Copyright (c) 2015, Frappe Technologies and contributors
# For lice
-from __future__ import unicode_literals
+from __future__ import unicode_literals, division
import frappe
from frappe import _
@@ -10,19 +10,19 @@ class OverlapError(frappe.ValidationError): pass
def validate_overlap_for(doc, doctype, fieldname, value=None):
"""Checks overlap for specified field.
-
- :param fieldname: Checks Overlap for this field
+
+ :param fieldname: Checks Overlap for this field
"""
-
+
existing = get_overlap_for(doc, doctype, fieldname, value)
if existing:
frappe.throw(_("This {0} conflicts with {1} for {2} {3}").format(doc.doctype, existing.name,
doc.meta.get_label(fieldname) if not value else fieldname , value or doc.get(fieldname)), OverlapError)
-
+
def get_overlap_for(doc, doctype, fieldname, value=None):
"""Returns overlaping document for specified field.
-
- :param fieldname: Checks Overlap for this field
+
+ :param fieldname: Checks Overlap for this field
"""
existing = frappe.db.sql("""select name, from_time, to_time from `tab{0}`
@@ -42,7 +42,8 @@ def get_overlap_for(doc, doctype, fieldname, value=None):
}, as_dict=True)
return existing[0] if existing else None
-
+
+
def validate_duplicate_student(students):
unique_students= []
for stud in students:
@@ -51,3 +52,93 @@ def validate_duplicate_student(students):
.format(stud.student, stud.student_name, unique_students.index(stud.student)+1, stud.idx))
else:
unique_students.append(stud.student)
+
+ return None
+
+# LMS Utils
+def get_current_student():
+ """
+ Returns student user name, example EDU-STU-2018-00001 (Based on the naming series).
+ Takes email from from frappe.session.user
+ """
+ email = frappe.session.user
+ if email in ('Administrator', 'Guest'):
+ return None
+ try:
+ student_id = frappe.get_all("Student", {"student_email_id": email}, ["name"])[0].name
+ return frappe.get_doc("Student", student_id)
+ except (IndexError, frappe.DoesNotExistError):
+ return None
+
+def check_super_access():
+ current_user = frappe.get_doc('User', frappe.session.user)
+ roles = set([role.role for role in current_user.roles])
+ return bool(roles & {'Administrator', 'Instructor', 'Education Manager', 'System Manager', 'Academic User'})
+
+def get_program_enrollment(program_name):
+ """
+ Function to get program enrollments for a particular student for a program
+ """
+ student = get_current_student()
+ if not student:
+ return None
+ else:
+ enrollment = frappe.get_all("Program Enrollment", filters={'student':student.name, 'program': program_name})
+ if enrollment:
+ return enrollment[0].name
+ else:
+ return None
+
+def get_program_and_enrollment_status(program_name):
+ program = frappe.get_doc('Program', program_name)
+ is_enrolled = bool(get_program_enrollment(program_name)) or check_super_access()
+ return {'program': program, 'is_enrolled': is_enrolled}
+
+def get_course_enrollment(course_name):
+ student = get_current_student()
+ if not student:
+ return None
+ enrollment_name = frappe.get_all("Course Enrollment", filters={'student': student.name, 'course':course_name})
+ try:
+ name = enrollment_name[0].name
+ enrollment = frappe.get_doc("Course Enrollment", name)
+ return enrollment
+ except:
+ return None
+
+def create_student_from_current_user():
+ user = frappe.get_doc("User", frappe.session.user)
+ student = frappe.get_doc({
+ "doctype": "Student",
+ "first_name": user.first_name,
+ "last_name": user.last_name,
+ "student_email_id": user.email,
+ "user": frappe.session.user
+ })
+ student.save(ignore_permissions=True)
+ return student
+
+def enroll_in_course(course_name, program_name):
+ student = get_current_student()
+ return student.enroll_in_course(course_name=course_name, program_enrollment=get_program_enrollment(program_name))
+
+def check_content_completion(content_name, content_type, enrollment_name):
+ activity = frappe.get_all("Course Activity", filters={'enrollment': enrollment_name, 'content_type': content_type, 'content': content_name})
+ if activity:
+ return True
+ else:
+ return False
+
+def check_quiz_completion(quiz, enrollment_name):
+ attempts = frappe.get_all("Quiz Activity", filters={'enrollment': enrollment_name, 'quiz': quiz.name}, fields=["name", "activity_date", "score", "status"])
+ status = False if quiz.max_attempts == 0 else bool(len(attempts) == quiz.max_attempts)
+ score = None
+ result = None
+ if attempts:
+ if quiz.grading_basis == 'Last Highest Score':
+ attempts = sorted(attempts, key = lambda i: int(i.score), reverse=True)
+ score = attempts[0]['score']
+ result = attempts[0]['status']
+ if result == 'Pass':
+ status = True
+ return status, score, result
\ No newline at end of file
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index 608e8b2225..47d205692c 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -11,6 +11,7 @@ app_email = "info@erpnext.com"
app_license = "GNU General Public License (v3)"
source_link = "https://github.com/frappe/erpnext"
+
develop_version = '12.x.x-develop'
error_report_email = "support@erpnext.com"
diff --git a/erpnext/hr/doctype/designation/designation.json b/erpnext/hr/doctype/designation/designation.json
index 1d4a3cf7b7..4c3888be4a 100644
--- a/erpnext/hr/doctype/designation/designation.json
+++ b/erpnext/hr/doctype/designation/designation.json
@@ -1,119 +1,194 @@
{
- "allow_copy": 0,
- "allow_import": 1,
- "allow_rename": 1,
- "autoname": "field:designation_name",
- "beta": 0,
- "creation": "2013-01-10 16:34:13",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Setup",
- "editable_grid": 0,
+ "allow_copy": 0,
+ "allow_events_in_timeline": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 1,
+ "allow_rename": 1,
+ "autoname": "field:designation_name",
+ "beta": 0,
+ "creation": "2013-01-10 16:34:13",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "Setup",
+ "editable_grid": 0,
"fields": [
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "designation_name",
- "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": "Designation",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "designation_name",
- "oldfieldtype": "Data",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "designation_name",
+ "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": "Designation",
+ "length": 0,
+ "no_copy": 0,
+ "oldfieldname": "designation_name",
+ "oldfieldtype": "Data",
+ "permlevel": 0,
+ "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,
+ "translatable": 0,
+ "unique": 1
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "description",
- "fieldtype": "Text",
- "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": "Description",
- "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,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "description",
+ "fieldtype": "Text",
+ "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": "Description",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "required_skills_section",
+ "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": "Required Skills",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "skills",
+ "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": "Skills",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Designation Skill",
+ "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
}
- ],
- "hide_heading": 0,
- "hide_toolbar": 0,
- "icon": "fa fa-bookmark",
- "idx": 1,
- "image_view": 0,
- "in_create": 0,
-
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2017-02-17 16:53:43.895882",
- "modified_by": "Administrator",
- "module": "HR",
- "name": "Designation",
- "owner": "Administrator",
+ ],
+ "has_web_view": 0,
+ "hide_toolbar": 0,
+ "icon": "fa fa-bookmark",
+ "idx": 1,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "menu_index": 0,
+ "modified": "2019-04-16 10:02:23.277734",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Designation",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "apply_user_permissions": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "HR User",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "amend": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 0,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "HR User",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
"write": 1
}
- ],
- "quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 1,
- "sort_order": "ASC",
- "track_changes": 0,
- "track_seen": 0
+ ],
+ "quick_entry": 1,
+ "read_only": 0,
+ "show_name_in_global_search": 1,
+ "sort_order": "ASC",
+ "track_changes": 0,
+ "track_seen": 0,
+ "track_views": 0
}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/designation_skill/__init__.py b/erpnext/hr/doctype/designation_skill/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/hr/doctype/designation_skill/designation_skill.json b/erpnext/hr/doctype/designation_skill/designation_skill.json
new file mode 100644
index 0000000000..30e23d0f02
--- /dev/null
+++ b/erpnext/hr/doctype/designation_skill/designation_skill.json
@@ -0,0 +1,74 @@
+{
+ "allow_copy": 0,
+ "allow_events_in_timeline": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "beta": 0,
+ "creation": "2019-04-16 10:01:05.259881",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "skill",
+ "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": "Skill",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Skill",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ }
+ ],
+ "has_web_view": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 1,
+ "max_attachments": 0,
+ "modified": "2019-04-16 13:42:10.760449",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Designation Skill",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "read_only": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "ASC",
+ "track_changes": 1,
+ "track_seen": 0,
+ "track_views": 0
+}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/designation_skill/designation_skill.py b/erpnext/hr/doctype/designation_skill/designation_skill.py
new file mode 100644
index 0000000000..c37d21f454
--- /dev/null
+++ b/erpnext/hr/doctype/designation_skill/designation_skill.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+# import frappe
+from frappe.model.document import Document
+
+class DesignationSkill(Document):
+ pass
diff --git a/erpnext/hr/doctype/employee_skill/__init__.py b/erpnext/hr/doctype/employee_skill/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/hr/doctype/employee_skill/employee_skill.json b/erpnext/hr/doctype/employee_skill/employee_skill.json
new file mode 100644
index 0000000000..4b1419e1ec
--- /dev/null
+++ b/erpnext/hr/doctype/employee_skill/employee_skill.json
@@ -0,0 +1,141 @@
+{
+ "allow_copy": 0,
+ "allow_events_in_timeline": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "beta": 0,
+ "creation": "2019-04-16 09:57:52.751635",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "skill",
+ "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": "Skill",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Skill",
+ "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,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "proficiency",
+ "fieldtype": "Rating",
+ "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": "Proficiency",
+ "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,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "Today",
+ "fetch_if_empty": 0,
+ "fieldname": "evaluation_date",
+ "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": "Evaluation Date",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ }
+ ],
+ "has_web_view": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 1,
+ "max_attachments": 0,
+ "modified": "2019-04-16 14:13:17.111035",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Employee Skill",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "read_only": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "ASC",
+ "track_changes": 1,
+ "track_seen": 0,
+ "track_views": 0
+}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/employee_skill/employee_skill.py b/erpnext/hr/doctype/employee_skill/employee_skill.py
new file mode 100644
index 0000000000..ac05fba624
--- /dev/null
+++ b/erpnext/hr/doctype/employee_skill/employee_skill.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+# import frappe
+from frappe.model.document import Document
+
+class EmployeeSkill(Document):
+ pass
diff --git a/erpnext/hr/doctype/employee_skill_map/__init__.py b/erpnext/hr/doctype/employee_skill_map/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/hr/doctype/employee_skill_map/employee_skill_map.js b/erpnext/hr/doctype/employee_skill_map/employee_skill_map.js
new file mode 100644
index 0000000000..b82b18d43b
--- /dev/null
+++ b/erpnext/hr/doctype/employee_skill_map/employee_skill_map.js
@@ -0,0 +1,21 @@
+// Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Employee Skill Map', {
+ // refresh: function(frm) {
+
+ // }
+ designation: (frm) => {
+ frm.set_value('employee_skills', null);
+ if (frm.doc.designation) {
+ frappe.db.get_doc('Designation', frm.doc.designation).then((designation) => {
+ designation.skills.forEach(designation_skill => {
+ let row = frappe.model.add_child(frm.doc, 'Employee Skill', 'employee_skills');
+ row.skill = designation_skill.skill;
+ row.proficiency = 1;
+ });
+ refresh_field('employee_skills');
+ });
+ }
+ }
+});
diff --git a/erpnext/hr/doctype/employee_skill_map/employee_skill_map.json b/erpnext/hr/doctype/employee_skill_map/employee_skill_map.json
new file mode 100644
index 0000000000..624145f23a
--- /dev/null
+++ b/erpnext/hr/doctype/employee_skill_map/employee_skill_map.json
@@ -0,0 +1,298 @@
+{
+ "allow_copy": 0,
+ "allow_events_in_timeline": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "autoname": "field:employee",
+ "beta": 0,
+ "creation": "2019-04-16 10:07:48.303426",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 0,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "employee",
+ "fieldtype": "Link",
+ "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": "Employee",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Employee",
+ "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": 1
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_from": "employee.employee_name",
+ "fetch_if_empty": 0,
+ "fieldname": "employee_name",
+ "fieldtype": "Read Only",
+ "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": "Employee Name",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_from": "employee.designation",
+ "fetch_if_empty": 0,
+ "fieldname": "designation",
+ "fieldtype": "Read Only",
+ "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": "Designation",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "skills_section",
+ "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": "Skills",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "employee_skills",
+ "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": "Employee Skills",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Employee Skill",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "trainings_section",
+ "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": "Trainings",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "trainings",
+ "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": "Trainings",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Employee Training",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ }
+ ],
+ "has_web_view": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2019-04-16 16:16:40.058429",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Employee Skill Map",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "amend": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ }
+ ],
+ "quick_entry": 1,
+ "read_only": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "ASC",
+ "title_field": "employee_name",
+ "track_changes": 0,
+ "track_seen": 0,
+ "track_views": 0
+}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/employee_skill_map/employee_skill_map.py b/erpnext/hr/doctype/employee_skill_map/employee_skill_map.py
new file mode 100644
index 0000000000..073f02fa25
--- /dev/null
+++ b/erpnext/hr/doctype/employee_skill_map/employee_skill_map.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+# import frappe
+from frappe.model.document import Document
+
+class EmployeeSkillMap(Document):
+ pass
diff --git a/erpnext/hr/doctype/employee_tax_exemption_category/employee_tax_exemption_category.json b/erpnext/hr/doctype/employee_tax_exemption_category/employee_tax_exemption_category.json
index 7b2804b326..66fac5bee5 100644
--- a/erpnext/hr/doctype/employee_tax_exemption_category/employee_tax_exemption_category.json
+++ b/erpnext/hr/doctype/employee_tax_exemption_category/employee_tax_exemption_category.json
@@ -1,5 +1,6 @@
{
"allow_copy": 0,
+ "allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 1,
@@ -20,6 +21,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "max_amount",
"fieldtype": "Currency",
"hidden": 0,
@@ -29,7 +31,7 @@
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
- "label": "Max Amount",
+ "label": "Max Exemption Amount",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -39,7 +41,7 @@
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
- "reqd": 1,
+ "reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
@@ -52,6 +54,8 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "default": "1",
+ "fetch_if_empty": 0,
"fieldname": "is_active",
"fieldtype": "Check",
"hidden": 0,
@@ -88,7 +92,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2018-06-19 16:33:48.419267",
+ "modified": "2019-04-25 13:20:31.367158",
"modified_by": "Administrator",
"module": "HR",
"name": "Employee Tax Exemption Category",
@@ -159,6 +163,7 @@
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0
+ "track_changes": 0,
+ "track_seen": 0,
+ "track_views": 0
}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/employee_tax_exemption_declaration/employee_tax_exemption_declaration.js b/erpnext/hr/doctype/employee_tax_exemption_declaration/employee_tax_exemption_declaration.js
index 9560df53e1..a827eca1c4 100644
--- a/erpnext/hr/doctype/employee_tax_exemption_declaration/employee_tax_exemption_declaration.js
+++ b/erpnext/hr/doctype/employee_tax_exemption_declaration/employee_tax_exemption_declaration.js
@@ -10,6 +10,7 @@ frappe.ui.form.on('Employee Tax Exemption Declaration', {
}
}
});
+
frm.set_query('payroll_period', function() {
const fields = {'employee': 'Employee', 'company': 'Company'};
@@ -27,6 +28,7 @@ frappe.ui.form.on('Employee Tax Exemption Declaration', {
}
}
});
+
frm.set_query('exemption_sub_category', 'declarations', function() {
return {
filters: {
@@ -34,5 +36,16 @@ frappe.ui.form.on('Employee Tax Exemption Declaration', {
}
}
});
+ },
+
+ refresh: function(frm) {
+ if(frm.doc.docstatus==1) {
+ frm.add_custom_button(__('Submit Proof'), function() {
+ frappe.model.open_mapped_doc({
+ method: "erpnext.hr.doctype.employee_tax_exemption_declaration.employee_tax_exemption_declaration.make_proof_submission",
+ frm: frm
+ });
+ }).addClass("btn-primary");
+ }
}
});
diff --git a/erpnext/hr/doctype/employee_tax_exemption_declaration/employee_tax_exemption_declaration.json b/erpnext/hr/doctype/employee_tax_exemption_declaration/employee_tax_exemption_declaration.json
index 865e8219b3..8891b97a5d 100644
--- a/erpnext/hr/doctype/employee_tax_exemption_declaration/employee_tax_exemption_declaration.json
+++ b/erpnext/hr/doctype/employee_tax_exemption_declaration/employee_tax_exemption_declaration.json
@@ -1,5 +1,6 @@
{
"allow_copy": 0,
+ "allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 1,
@@ -20,6 +21,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "employee",
"fieldtype": "Link",
"hidden": 0,
@@ -53,9 +55,10 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "fetch_from": "employee.company",
- "fieldname": "company",
- "fieldtype": "Link",
+ "fetch_from": "employee.employee_name",
+ "fetch_if_empty": 0,
+ "fieldname": "employee_name",
+ "fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@@ -63,104 +66,7 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
- "label": "Company",
- "length": 0,
- "no_copy": 0,
- "options": "Company",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_2",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "payroll_period",
- "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": "Payroll Period",
- "length": 0,
- "no_copy": 0,
- "options": "Payroll Period",
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "total_exemption_amount",
- "fieldtype": "Currency",
- "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": "Total Exemption Amount",
+ "label": "Employee Name",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -184,6 +90,7 @@
"collapsible": 0,
"columns": 0,
"fetch_from": "employee.department",
+ "fetch_if_empty": 0,
"fieldname": "department",
"fieldtype": "Link",
"hidden": 0,
@@ -217,6 +124,108 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "column_break_2",
+ "fieldtype": "Column Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "payroll_period",
+ "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": "Payroll Period",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Payroll Period",
+ "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,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_from": "employee.company",
+ "fetch_if_empty": 0,
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "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": "Company",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Company",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "amended_from",
"fieldtype": "Link",
"hidden": 0,
@@ -249,6 +258,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "section_break_8",
"fieldtype": "Section Break",
"hidden": 0,
@@ -280,6 +290,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "declarations",
"fieldtype": "Table",
"hidden": 0,
@@ -300,7 +311,137 @@
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
- "reqd": 1,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "section_break_10",
+ "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,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "total_declared_amount",
+ "fieldtype": "Currency",
+ "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": "Total Declared Amount",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "column_break_12",
+ "fieldtype": "Column Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "total_exemption_amount",
+ "fieldtype": "Currency",
+ "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": "Total Exemption Amount",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
@@ -317,7 +458,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2018-08-21 16:15:49.363307",
+ "modified": "2019-04-25 16:38:05.847925",
"modified_by": "Administrator",
"module": "HR",
"name": "Employee Tax Exemption Declaration",
diff --git a/erpnext/hr/doctype/employee_tax_exemption_declaration/employee_tax_exemption_declaration.py b/erpnext/hr/doctype/employee_tax_exemption_declaration/employee_tax_exemption_declaration.py
index 186b2e1052..cbdfcf8ecd 100644
--- a/erpnext/hr/doctype/employee_tax_exemption_declaration/employee_tax_exemption_declaration.py
+++ b/erpnext/hr/doctype/employee_tax_exemption_declaration/employee_tax_exemption_declaration.py
@@ -6,28 +6,61 @@ from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
from frappe import _
-from erpnext.hr.utils import validate_tax_declaration, calculate_annual_eligible_hra_exemption
+from frappe.utils import flt
+from frappe.model.mapper import get_mapped_doc
+from erpnext.hr.utils import validate_tax_declaration, get_total_exemption_amount, calculate_annual_eligible_hra_exemption
+
+class DuplicateDeclarationError(frappe.ValidationError): pass
class EmployeeTaxExemptionDeclaration(Document):
def validate(self):
validate_tax_declaration(self.declarations)
- self.total_exemption_amount = 0
+ self.validate_duplicate()
+ self.set_total_declared_amount()
+ self.set_total_exemption_amount()
self.calculate_hra_exemption()
- for item in self.declarations:
- self.total_exemption_amount += item.amount
- def before_submit(self):
- if frappe.db.exists({"doctype": "Employee Tax Exemption Declaration",
- "employee": self.employee,
- "payroll_period": self.payroll_period,
- "docstatus": 1}):
- frappe.throw(_("Tax Declaration of {0} for period {1} already submitted.")\
- .format(self.employee, self.payroll_period), frappe.DocstatusTransitionError)
+ def validate_duplicate(self):
+ duplicate = frappe.db.get_value("Employee Tax Exemption Declaration",
+ filters = {
+ "employee": self.employee,
+ "payroll_period": self.payroll_period,
+ "name": ["!=", self.name]
+ }
+ )
+ if duplicate:
+ frappe.throw(_("Duplicate Tax Declaration of {0} for period {1}")
+ .format(self.employee, self.payroll_period), DuplicateDeclarationError)
+
+ def set_total_declared_amount(self):
+ self.total_declared_amount = 0.0
+ for d in self.declarations:
+ self.total_declared_amount += flt(d.amount)
+
+ def set_total_exemption_amount(self):
+ self.total_exemption_amount = get_total_exemption_amount(self.declarations)
def calculate_hra_exemption(self):
- hra_exemption = calculate_annual_eligible_hra_exemption(self)
- if hra_exemption:
- self.total_exemption_amount += hra_exemption["annual_exemption"]
- self.salary_structure_hra = hra_exemption["hra_amount"]
- self.annual_hra_exemption = hra_exemption["annual_exemption"]
- self.monthly_hra_exemption = hra_exemption["monthly_exemption"]
+ self.salary_structure_hra, self.annual_hra_exemption, self.monthly_hra_exemption = 0, 0, 0
+ if self.get("monthly_house_rent"):
+ hra_exemption = calculate_annual_eligible_hra_exemption(self)
+ if hra_exemption:
+ self.total_exemption_amount += hra_exemption["annual_exemption"]
+ self.salary_structure_hra = hra_exemption["hra_amount"]
+ self.annual_hra_exemption = hra_exemption["annual_exemption"]
+ self.monthly_hra_exemption = hra_exemption["monthly_exemption"]
+
+@frappe.whitelist()
+def make_proof_submission(source_name, target_doc=None):
+ doclist = get_mapped_doc("Employee Tax Exemption Declaration", source_name, {
+ "Employee Tax Exemption Declaration": {
+ "doctype": "Employee Tax Exemption Proof Submission",
+ "field_no_map": ["monthly_house_rent", "monthly_hra_exemption"]
+ },
+ "Employee Tax Exemption Declaration Category": {
+ "doctype": "Employee Tax Exemption Proof Submission Detail",
+ "add_if_empty": True
+ }
+ }, target_doc)
+
+ return doclist
diff --git a/erpnext/hr/doctype/employee_tax_exemption_declaration/test_employee_tax_exemption_declaration.py b/erpnext/hr/doctype/employee_tax_exemption_declaration/test_employee_tax_exemption_declaration.py
index beaddd98dd..9c87bbd1f3 100644
--- a/erpnext/hr/doctype/employee_tax_exemption_declaration/test_employee_tax_exemption_declaration.py
+++ b/erpnext/hr/doctype/employee_tax_exemption_declaration/test_employee_tax_exemption_declaration.py
@@ -6,6 +6,7 @@ from __future__ import unicode_literals
import frappe, erpnext
import unittest
from erpnext.hr.doctype.employee.test_employee import make_employee
+from erpnext.hr.doctype.employee_tax_exemption_declaration.employee_tax_exemption_declaration import DuplicateDeclarationError
class TestEmployeeTaxExemptionDeclaration(unittest.TestCase):
def setUp(self):
@@ -15,71 +16,71 @@ class TestEmployeeTaxExemptionDeclaration(unittest.TestCase):
create_exemption_category()
frappe.db.sql("""delete from `tabEmployee Tax Exemption Declaration`""")
- def test_exemption_amount_greater_than_category_max(self):
- declaration = frappe.get_doc({
- "doctype": "Employee Tax Exemption Declaration",
- "employee": frappe.get_value("Employee", {"user_id":"employee@taxexepmtion.com"}, "name"),
- "payroll_period": "_Test Payroll Period",
- "declarations": [dict(exemption_sub_category = "_Test Sub Category",
- exemption_category = "_Test Category",
- amount = 150000)]
- })
- self.assertRaises(frappe.ValidationError, declaration.save)
- declaration = frappe.get_doc({
- "doctype": "Employee Tax Exemption Declaration",
- "payroll_period": "_Test Payroll Period",
- "employee": frappe.get_value("Employee", {"user_id":"employee@taxexepmtion.com"}, "name"),
- "declarations": [dict(exemption_sub_category = "_Test Sub Category",
- exemption_category = "_Test Category",
- amount = 90000)]
- })
- self.assertTrue(declaration.save)
-
def test_duplicate_category_in_declaration(self):
declaration = frappe.get_doc({
"doctype": "Employee Tax Exemption Declaration",
"employee": frappe.get_value("Employee", {"user_id":"employee@taxexepmtion.com"}, "name"),
"company": erpnext.get_default_company(),
"payroll_period": "_Test Payroll Period",
- "declarations": [dict(exemption_sub_category = "_Test Sub Category",
- exemption_category = "_Test Category",
- amount = 100000),
- dict(exemption_sub_category = "_Test Sub Category",
- exemption_category = "_Test Category",
- amount = 50000),
- ]
+ "declarations": [
+ dict(exemption_sub_category = "_Test Sub Category",
+ exemption_category = "_Test Category",
+ amount = 100000),
+ dict(exemption_sub_category = "_Test Sub Category",
+ exemption_category = "_Test Category",
+ amount = 50000)
+ ]
})
self.assertRaises(frappe.ValidationError, declaration.save)
- def test_duplicate_submission_for_payroll_period(self):
+ def test_duplicate_entry_for_payroll_period(self):
declaration = frappe.get_doc({
"doctype": "Employee Tax Exemption Declaration",
"employee": frappe.get_value("Employee", {"user_id":"employee@taxexepmtion.com"}, "name"),
"company": erpnext.get_default_company(),
"payroll_period": "_Test Payroll Period",
- "declarations": [dict(exemption_sub_category = "_Test Sub Category",
- exemption_category = "_Test Category",
- amount = 100000),
- dict(exemption_sub_category = "_Test1 Sub Category",
- exemption_category = "_Test Category",
- amount = 50000),
- ]
+ "declarations": [
+ dict(exemption_sub_category = "_Test Sub Category",
+ exemption_category = "_Test Category",
+ amount = 100000),
+ dict(exemption_sub_category = "_Test1 Sub Category",
+ exemption_category = "_Test Category",
+ amount = 50000),
+ ]
}).insert()
- declaration.submit()
- self.assertEquals(declaration.docstatus, 1)
+
duplicate_declaration = frappe.get_doc({
"doctype": "Employee Tax Exemption Declaration",
"employee": frappe.get_value("Employee", {"user_id":"employee@taxexepmtion.com"}, "name"),
"company": erpnext.get_default_company(),
"payroll_period": "_Test Payroll Period",
- "declarations": [dict(exemption_sub_category = "_Test Sub Category",
- exemption_category = "_Test Category",
- amount = 100000)
- ]
- }).insert()
- self.assertRaises(frappe.DocstatusTransitionError, duplicate_declaration.submit)
+ "declarations": [
+ dict(exemption_sub_category = "_Test Sub Category",
+ exemption_category = "_Test Category",
+ amount = 100000)
+ ]
+ })
+ self.assertRaises(DuplicateDeclarationError, duplicate_declaration.insert)
duplicate_declaration.employee = frappe.get_value("Employee", {"user_id":"employee1@taxexepmtion.com"}, "name")
- self.assertTrue(duplicate_declaration.submit)
+ self.assertTrue(duplicate_declaration.insert)
+
+ def test_exemption_amount(self):
+ declaration = frappe.get_doc({
+ "doctype": "Employee Tax Exemption Declaration",
+ "employee": frappe.get_value("Employee", {"user_id":"employee@taxexepmtion.com"}, "name"),
+ "company": erpnext.get_default_company(),
+ "payroll_period": "_Test Payroll Period",
+ "declarations": [
+ dict(exemption_sub_category = "_Test Sub Category",
+ exemption_category = "_Test Category",
+ amount = 80000),
+ dict(exemption_sub_category = "_Test1 Sub Category",
+ exemption_category = "_Test Category",
+ amount = 60000),
+ ]
+ }).insert()
+
+ self.assertEqual(declaration.total_exemption_amount, 100000)
def create_payroll_period():
if not frappe.db.exists("Payroll Period", "_Test Payroll Period"):
diff --git a/erpnext/hr/doctype/employee_tax_exemption_declaration_category/employee_tax_exemption_declaration_category.json b/erpnext/hr/doctype/employee_tax_exemption_declaration_category/employee_tax_exemption_declaration_category.json
index ebde4c9c71..56556c1030 100644
--- a/erpnext/hr/doctype/employee_tax_exemption_declaration_category/employee_tax_exemption_declaration_category.json
+++ b/erpnext/hr/doctype/employee_tax_exemption_declaration_category/employee_tax_exemption_declaration_category.json
@@ -1,140 +1,179 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2018-04-13 16:56:23.333041",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "allow_copy": 0,
+ "allow_events_in_timeline": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "beta": 0,
+ "creation": "2018-04-13 16:56:23.333041",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "exemption_sub_category",
- "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": "Exemption Sub Category",
- "length": 0,
- "no_copy": 0,
- "options": "Employee Tax Exemption Sub Category",
- "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,
- "translatable": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "exemption_sub_category",
+ "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": "Exemption Sub Category",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Employee Tax Exemption Sub Category",
+ "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,
+ "translatable": 0,
"unique": 0
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "exemption_sub_category.exemption_category",
- "fieldname": "exemption_category",
- "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": "Exemption Category",
- "length": 0,
- "no_copy": 0,
- "options": "Employee Tax Exemption Category",
- "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,
- "translatable": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_from": "exemption_sub_category.exemption_category",
+ "fetch_if_empty": 0,
+ "fieldname": "exemption_category",
+ "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": "Exemption Category",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Employee Tax Exemption Category",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "amount",
- "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": "Amount",
- "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,
- "translatable": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_from": "exemption_sub_category.max_amount",
+ "fetch_if_empty": 0,
+ "fieldname": "max_amount",
+ "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": "Maximum Exemption Amount",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "amount",
+ "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": "Declared Amount",
+ "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,
+ "translatable": 0,
"unique": 0
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 1,
- "max_attachments": 0,
- "modified": "2018-05-29 15:58:05.779031",
- "modified_by": "Administrator",
- "module": "HR",
- "name": "Employee Tax Exemption Declaration Category",
- "name_case": "",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0
+ ],
+ "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": "2019-04-25 15:45:11.279158",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Employee Tax Exemption Declaration Category",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 0,
+ "track_views": 0
}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/employee_tax_exemption_proof_submission/employee_tax_exemption_proof_submission.js b/erpnext/hr/doctype/employee_tax_exemption_proof_submission/employee_tax_exemption_proof_submission.js
index 99bec14b18..66118c0811 100644
--- a/erpnext/hr/doctype/employee_tax_exemption_proof_submission/employee_tax_exemption_proof_submission.js
+++ b/erpnext/hr/doctype/employee_tax_exemption_proof_submission/employee_tax_exemption_proof_submission.js
@@ -10,6 +10,7 @@ frappe.ui.form.on('Employee Tax Exemption Proof Submission', {
}
}
});
+
frm.set_query('payroll_period', function() {
if(frm.doc.employee && frm.doc.company){
return {
@@ -21,6 +22,7 @@ frappe.ui.form.on('Employee Tax Exemption Proof Submission', {
frappe.msgprint(__("Please select Employee"));
}
});
+
frm.set_query('exemption_sub_category', 'tax_exemption_proofs', function() {
return {
filters: {
@@ -29,11 +31,28 @@ frappe.ui.form.on('Employee Tax Exemption Proof Submission', {
}
});
},
- employee: function(frm){
- if(frm.doc.employee){
- frm.add_fetch('employee', 'company', 'company');
- }else{
- frm.set_value('company', '');
+
+ refresh: function(frm) {
+ if(frm.doc.docstatus === 0) {
+ let filters = {
+ docstatus: 1,
+ company: frm.doc.company
+ };
+ if(frm.doc.employee) filters["employee"] = frm.doc.employee;
+ if(frm.doc.payroll_period) filters["payroll_period"] = frm.doc.payroll_period;
+
+ frm.add_custom_button(__('Get Details From Declaration'), function() {
+ erpnext.utils.map_current_doc({
+ method: "erpnext.hr.doctype.employee_tax_exemption_declaration.employee_tax_exemption_declaration.make_proof_submission",
+ source_doctype: "Employee Tax Exemption Declaration",
+ target: frm,
+ date_field: "creation",
+ setters: {
+ employee: frm.doc.employee || undefined
+ },
+ get_query_filters: filters
+ });
+ });
}
}
});
diff --git a/erpnext/hr/doctype/employee_tax_exemption_proof_submission/employee_tax_exemption_proof_submission.json b/erpnext/hr/doctype/employee_tax_exemption_proof_submission/employee_tax_exemption_proof_submission.json
index ebc04353e0..76c09d6c7b 100644
--- a/erpnext/hr/doctype/employee_tax_exemption_proof_submission/employee_tax_exemption_proof_submission.json
+++ b/erpnext/hr/doctype/employee_tax_exemption_proof_submission/employee_tax_exemption_proof_submission.json
@@ -1,8 +1,9 @@
{
"allow_copy": 0,
+ "allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
+ "allow_import": 1,
+ "allow_rename": 1,
"autoname": "HR-TAX-PRF-.YYYY.-.#####",
"beta": 0,
"creation": "2018-04-13 17:24:11.456132",
@@ -20,6 +21,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "employee",
"fieldtype": "Link",
"hidden": 0,
@@ -53,8 +55,10 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "fieldname": "company",
- "fieldtype": "Link",
+ "fetch_from": "employee.employee_name",
+ "fetch_if_empty": 0,
+ "fieldname": "employee_name",
+ "fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@@ -62,10 +66,9 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
- "label": "Company",
+ "label": "Employee Name",
"length": 0,
"no_copy": 0,
- "options": "Company",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -79,70 +82,6 @@
"translatable": 0,
"unique": 0
},
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_2",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "payroll_period",
- "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": "Payroll Period",
- "length": 0,
- "no_copy": 0,
- "options": "Payroll Period",
- "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,
- "translatable": 0,
- "unique": 0
- },
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
@@ -151,6 +90,7 @@
"collapsible": 0,
"columns": 0,
"fetch_from": "employee.department",
+ "fetch_if_empty": 0,
"fieldname": "department",
"fieldtype": "Link",
"hidden": 0,
@@ -184,8 +124,9 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "fieldname": "submission_date",
- "fieldtype": "Date",
+ "fetch_if_empty": 0,
+ "fieldname": "column_break_2",
+ "fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@@ -193,7 +134,6 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
- "label": "Submission Date",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -216,6 +156,273 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "default": "Today",
+ "fetch_if_empty": 0,
+ "fieldname": "submission_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": "Submission Date",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "payroll_period",
+ "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": "Payroll Period",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Payroll Period",
+ "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,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_from": "employee.company",
+ "fetch_if_empty": 0,
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "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": "Company",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Company",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 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,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "tax_exemption_proofs",
+ "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": "Tax Exemption Proofs",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Employee Tax Exemption Proof Submission Detail",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "section_break_10",
+ "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,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "total_actual_amount",
+ "fieldtype": "Currency",
+ "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": "Total Actual Amount",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "column_break_12",
+ "fieldtype": "Column Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "exemption_amount",
"fieldtype": "Currency",
"hidden": 0,
@@ -248,70 +455,7 @@
"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,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "tax_exemption_proofs",
- "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": "Tax Exemption Proofs",
- "length": 0,
- "no_copy": 0,
- "options": "Employee Tax Exemption Proof Submission Detail",
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "attachment_section",
"fieldtype": "Section Break",
"hidden": 0,
@@ -344,6 +488,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "attachments",
"fieldtype": "Attach",
"hidden": 0,
@@ -376,6 +521,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "amended_from",
"fieldtype": "Link",
"hidden": 0,
@@ -412,7 +558,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2018-08-21 16:15:38.096846",
+ "modified": "2019-04-25 17:06:36.569549",
"modified_by": "Administrator",
"module": "HR",
"name": "Employee Tax Exemption Proof Submission",
diff --git a/erpnext/hr/doctype/employee_tax_exemption_proof_submission/employee_tax_exemption_proof_submission.py b/erpnext/hr/doctype/employee_tax_exemption_proof_submission/employee_tax_exemption_proof_submission.py
index 54e0b2041b..97ceb63476 100644
--- a/erpnext/hr/doctype/employee_tax_exemption_proof_submission/employee_tax_exemption_proof_submission.py
+++ b/erpnext/hr/doctype/employee_tax_exemption_proof_submission/employee_tax_exemption_proof_submission.py
@@ -6,20 +6,30 @@ from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
from frappe import _
-from erpnext.hr.utils import validate_tax_declaration, calculate_hra_exemption_for_period
+from frappe.utils import flt
+from erpnext.hr.utils import validate_tax_declaration, get_total_exemption_amount, calculate_hra_exemption_for_period
class EmployeeTaxExemptionProofSubmission(Document):
def validate(self):
validate_tax_declaration(self.tax_exemption_proofs)
- self.exemption_amount = 0
+ self.set_total_actual_amount()
+ self.set_total_exemption_amount()
self.calculate_hra_exemption()
- for proof in self.tax_exemption_proofs:
- self.exemption_amount += proof.amount
+
+ def set_total_actual_amount(self):
+ self.total_actual_amount = flt(self.get("house_rent_payment_amount"))
+ for d in self.tax_exemption_proofs:
+ self.total_actual_amount += flt(d.amount)
+
+ def set_total_exemption_amount(self):
+ self.exemption_amount = get_total_exemption_amount(self.tax_exemption_proofs)
def calculate_hra_exemption(self):
- hra_exemption = calculate_hra_exemption_for_period(self)
- if hra_exemption:
- self.exemption_amount += hra_exemption["total_eligible_hra_exemption"]
- self.monthly_hra_exemption = hra_exemption["monthly_exemption"]
- self.monthly_house_rent = hra_exemption["monthly_house_rent"]
- self.total_eligible_hra_exemption = hra_exemption["total_eligible_hra_exemption"]
+ self.monthly_hra_exemption, self.monthly_house_rent, self.total_eligible_hra_exemption = 0, 0, 0
+ if self.get("house_rent_payment_amount"):
+ hra_exemption = calculate_hra_exemption_for_period(self)
+ if hra_exemption:
+ self.exemption_amount += hra_exemption["total_eligible_hra_exemption"]
+ self.monthly_hra_exemption = hra_exemption["monthly_exemption"]
+ self.monthly_house_rent = hra_exemption["monthly_house_rent"]
+ self.total_eligible_hra_exemption = hra_exemption["total_eligible_hra_exemption"]
\ No newline at end of file
diff --git a/erpnext/hr/doctype/employee_tax_exemption_proof_submission_detail/employee_tax_exemption_proof_submission_detail.json b/erpnext/hr/doctype/employee_tax_exemption_proof_submission_detail/employee_tax_exemption_proof_submission_detail.json
index c1c5896d7f..b9254afad0 100644
--- a/erpnext/hr/doctype/employee_tax_exemption_proof_submission_detail/employee_tax_exemption_proof_submission_detail.json
+++ b/erpnext/hr/doctype/employee_tax_exemption_proof_submission_detail/employee_tax_exemption_proof_submission_detail.json
@@ -1,5 +1,6 @@
{
"allow_copy": 0,
+ "allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
@@ -14,10 +15,12 @@
"fields": [
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "exemption_sub_category",
"fieldtype": "Link",
"hidden": 0,
@@ -41,16 +44,18 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
- "fetch_from": "exemption_sub_category.exemption_category",
+ "fetch_from": "exemption_sub_category.exemption_category",
+ "fetch_if_empty": 0,
"fieldname": "exemption_category",
"fieldtype": "Read Only",
"hidden": 0,
@@ -74,15 +79,51 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_from": "exemption_sub_category.max_amount",
+ "fetch_if_empty": 0,
+ "fieldname": "max_amount",
+ "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": "Maximum Exemption Amount",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "type_of_proof",
"fieldtype": "Data",
"hidden": 0,
@@ -106,15 +147,17 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "amount",
"fieldtype": "Currency",
"hidden": 0,
@@ -124,7 +167,7 @@
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
- "label": "Amount",
+ "label": "Actual Amount",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -134,10 +177,10 @@
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
- "reqd": 1,
+ "reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
}
],
@@ -151,7 +194,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
- "modified": "2018-05-16 22:42:59.750733",
+ "modified": "2019-04-25 15:45:03.154904",
"modified_by": "Administrator",
"module": "HR",
"name": "Employee Tax Exemption Proof Submission Detail",
@@ -165,5 +208,6 @@
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
- "track_seen": 0
+ "track_seen": 0,
+ "track_views": 0
}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/employee_tax_exemption_sub_category/employee_tax_exemption_sub_category.json b/erpnext/hr/doctype/employee_tax_exemption_sub_category/employee_tax_exemption_sub_category.json
index dc99785067..b0e492e7ca 100644
--- a/erpnext/hr/doctype/employee_tax_exemption_sub_category/employee_tax_exemption_sub_category.json
+++ b/erpnext/hr/doctype/employee_tax_exemption_sub_category/employee_tax_exemption_sub_category.json
@@ -1,5 +1,6 @@
{
"allow_copy": 0,
+ "allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 1,
@@ -15,10 +16,12 @@
"fields": [
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "exemption_category",
"fieldtype": "Link",
"hidden": 0,
@@ -26,8 +29,8 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 1,
"label": "Tax Exemption Category",
"length": 0,
"no_copy": 0,
@@ -42,14 +45,18 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_from": "exemption_category.max_amount",
+ "fetch_if_empty": 1,
"fieldname": "max_amount",
"fieldtype": "Currency",
"hidden": 0,
@@ -59,7 +66,7 @@
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
- "label": "Max Amount",
+ "label": "Max Exemption Amount",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -69,17 +76,21 @@
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
- "reqd": 1,
+ "reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "default": "1",
+ "fetch_if_empty": 0,
"fieldname": "is_active",
"fieldtype": "Check",
"hidden": 0,
@@ -102,6 +113,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
}
],
@@ -115,7 +127,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2018-05-09 13:25:01.595240",
+ "modified": "2019-04-25 13:24:05.164877",
"modified_by": "Administrator",
"module": "HR",
"name": "Employee Tax Exemption Sub Category",
@@ -124,7 +136,6 @@
"permissions": [
{
"amend": 0,
- "apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
@@ -144,7 +155,6 @@
},
{
"amend": 0,
- "apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
@@ -164,7 +174,6 @@
},
{
"amend": 0,
- "apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
@@ -189,6 +198,7 @@
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0
+ "track_changes": 0,
+ "track_seen": 0,
+ "track_views": 0
}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/employee_tax_exemption_sub_category/employee_tax_exemption_sub_category.py b/erpnext/hr/doctype/employee_tax_exemption_sub_category/employee_tax_exemption_sub_category.py
index cd58136d8d..a8dd7e4d6d 100644
--- a/erpnext/hr/doctype/employee_tax_exemption_sub_category/employee_tax_exemption_sub_category.py
+++ b/erpnext/hr/doctype/employee_tax_exemption_sub_category/employee_tax_exemption_sub_category.py
@@ -4,7 +4,13 @@
from __future__ import unicode_literals
import frappe
+from frappe import _
+from frappe.utils import flt
from frappe.model.document import Document
class EmployeeTaxExemptionSubCategory(Document):
- pass
+ def validate(self):
+ category_max_amount = frappe.db.get_value("Employee Tax Exemption Category", self.exemption_category, "max_amount")
+ if flt(self.max_amount) > flt(category_max_amount):
+ frappe.throw(_("Max Exemption Amount cannot be greater than maximum exemption amount {0} of Tax Exemption Category {1}")
+ .format(category_max_amount, self.exemption_category))
\ No newline at end of file
diff --git a/erpnext/hr/doctype/employee_training/__init__.py b/erpnext/hr/doctype/employee_training/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/hr/doctype/employee_training/employee_training.json b/erpnext/hr/doctype/employee_training/employee_training.json
new file mode 100644
index 0000000000..0e0dc15195
--- /dev/null
+++ b/erpnext/hr/doctype/employee_training/employee_training.json
@@ -0,0 +1,108 @@
+{
+ "allow_copy": 0,
+ "allow_events_in_timeline": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "beta": 0,
+ "creation": "2019-04-16 16:15:50.931545",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "training",
+ "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": "Training",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Training Event",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_from": "training.end_time",
+ "fetch_if_empty": 0,
+ "fieldname": "training_date",
+ "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": "Training Date",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ }
+ ],
+ "has_web_view": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 1,
+ "max_attachments": 0,
+ "modified": "2019-04-22 12:48:56.925419",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Employee Training",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "read_only": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "ASC",
+ "track_changes": 1,
+ "track_seen": 0,
+ "track_views": 0
+}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/employee_training/employee_training.py b/erpnext/hr/doctype/employee_training/employee_training.py
new file mode 100644
index 0000000000..810796d66c
--- /dev/null
+++ b/erpnext/hr/doctype/employee_training/employee_training.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+# import frappe
+from frappe.model.document import Document
+
+class EmployeeTraining(Document):
+ pass
diff --git a/erpnext/hr/doctype/salary_slip/salary_slip.py b/erpnext/hr/doctype/salary_slip/salary_slip.py
index 9e13cb6739..1b487a6423 100644
--- a/erpnext/hr/doctype/salary_slip/salary_slip.py
+++ b/erpnext/hr/doctype/salary_slip/salary_slip.py
@@ -167,7 +167,7 @@ class SalarySlip(TransactionBase):
if d.amount_based_on_formula:
formula = d.formula.strip() if d.formula else None
if formula:
- amount = frappe.safe_eval(formula, self.whitelisted_globals, data)
+ amount = rounded(frappe.safe_eval(formula, self.whitelisted_globals, data))
if amount:
data[d.abbr] = amount
@@ -602,12 +602,11 @@ class SalarySlip(TransactionBase):
annual_earning = taxable_earning["taxable_earning"] * period_factor
exemption_amount = 0
if frappe.db.exists("Employee Tax Exemption Declaration", {"employee": self.employee,
- "payroll_period": payroll_period.name, "docstatus": 1}):
+ "payroll_period": payroll_period.name, "docstatus": 1}):
exemption_amount = frappe.db.get_value("Employee Tax Exemption Declaration",
{"employee": self.employee, "payroll_period": payroll_period.name, "docstatus": 1},
"total_exemption_amount")
annual_taxable_earning = annual_earning - exemption_amount
-
if self.deduct_tax_for_unclaimed_employee_benefits or self.deduct_tax_for_unsubmitted_tax_exemption_proof:
tax_detail = self.get_tax_paid_in_period(payroll_period, tax_component)
if tax_detail:
@@ -739,22 +738,24 @@ class SalarySlip(TransactionBase):
# less paid taxes
if args.get("pro_rata_tax_paid"):
tax_amount -= args.get("pro_rata_tax_paid")
+ tax_amount = rounded(tax_amount)
struct_row = self.get_salary_slip_row(args.get("tax_component"))
return [struct_row, tax_amount, benefit_tax, additional_tax]
- def calculate_tax_by_tax_slab(self, payroll_period, annual_earning):
+ def calculate_tax_by_tax_slab(self, payroll_period, annual_taxable_earning):
payroll_period_obj = frappe.get_doc("Payroll Period", payroll_period)
data = self.get_data_for_eval()
+ data.update({"annual_taxable_earning": annual_taxable_earning})
taxable_amount = 0
for slab in payroll_period_obj.taxable_salary_slabs:
if slab.condition and not self.eval_tax_slab_condition(slab.condition, data):
continue
- if not slab.to_amount and annual_earning > slab.from_amount:
- taxable_amount += (annual_earning - slab.from_amount) * slab.percent_deduction *.01
+ if not slab.to_amount and annual_taxable_earning > slab.from_amount:
+ taxable_amount += (annual_taxable_earning - slab.from_amount) * slab.percent_deduction *.01
continue
- if annual_earning > slab.from_amount and annual_earning < slab.to_amount:
- taxable_amount += (annual_earning - slab.from_amount) * slab.percent_deduction *.01
- elif annual_earning > slab.from_amount and annual_earning > slab.to_amount:
+ if annual_taxable_earning > slab.from_amount and annual_taxable_earning < slab.to_amount:
+ taxable_amount += (annual_taxable_earning - slab.from_amount) * slab.percent_deduction *.01
+ elif annual_taxable_earning > slab.from_amount and annual_taxable_earning > slab.to_amount:
taxable_amount += (slab.to_amount - slab.from_amount) * slab.percent_deduction * .01
return taxable_amount
@@ -773,13 +774,21 @@ class SalarySlip(TransactionBase):
def get_period_factor(self, period_start, period_end, start_date=None, end_date=None):
# TODO if both deduct checked update the factor to make tax consistent
+ joining_date, relieving_date = frappe.db.get_value("Employee", self.employee, ["date_of_joining", "relieving_date"])
+ if getdate(joining_date) > getdate(period_start):
+ period_start = joining_date
+ if relieving_date and getdate(relieving_date) < getdate(period_end):
+ period_end = relieving_date
+
payroll_days = date_diff(period_end, period_start) + 1
if start_date and end_date:
salary_days = date_diff(end_date, start_date) + 1
return flt(payroll_days)/flt(salary_days)
+
# if period configured for a year and monthly frequency return 12 to make tax calc consistent
if 360 <= payroll_days <= 370 and self.payroll_frequency == "Monthly":
return 12
+
salary_days = date_diff(self.end_date, self.start_date) + 1
return flt(payroll_days)/flt(salary_days)
diff --git a/erpnext/hr/doctype/salary_slip/test_salary_slip.py b/erpnext/hr/doctype/salary_slip/test_salary_slip.py
index 079bec51b2..746bf8cff1 100644
--- a/erpnext/hr/doctype/salary_slip/test_salary_slip.py
+++ b/erpnext/hr/doctype/salary_slip/test_salary_slip.py
@@ -13,7 +13,8 @@ from frappe.utils import getdate, nowdate, add_days, add_months, flt, get_first_
from erpnext.hr.doctype.salary_structure.salary_structure import make_salary_slip
from erpnext.hr.doctype.payroll_entry.payroll_entry import get_month_details
from erpnext.hr.doctype.employee.test_employee import make_employee
-from erpnext.hr.doctype.employee_tax_exemption_declaration.test_employee_tax_exemption_declaration import create_payroll_period, create_exemption_category
+from erpnext.hr.doctype.employee_tax_exemption_declaration.test_employee_tax_exemption_declaration \
+ import create_payroll_period, create_exemption_category
class TestSalarySlip(unittest.TestCase):
def setUp(self):
@@ -36,8 +37,10 @@ class TestSalarySlip(unittest.TestCase):
no_of_days = self.get_no_of_days()
frappe.db.set_value("HR Settings", None, "include_holidays_in_total_working_days", 1)
make_employee("test_employee@salary.com")
- frappe.db.set_value("Employee", frappe.get_value("Employee", {"employee_name":"test_employee@salary.com"}, "name"), "relieving_date", None)
- frappe.db.set_value("Employee", frappe.get_value("Employee", {"employee_name":"test_employee@salary.com"}, "name"), "status", "Active")
+ frappe.db.set_value("Employee", frappe.get_value("Employee",
+ {"employee_name":"test_employee@salary.com"}, "name"), "relieving_date", None)
+ frappe.db.set_value("Employee", frappe.get_value("Employee",
+ {"employee_name":"test_employee@salary.com"}, "name"), "status", "Active")
ss = make_employee_salary_slip("test_employee@salary.com", "Monthly")
self.assertEqual(ss.total_working_days, no_of_days[0])
@@ -53,8 +56,10 @@ class TestSalarySlip(unittest.TestCase):
no_of_days = self.get_no_of_days()
frappe.db.set_value("HR Settings", None, "include_holidays_in_total_working_days", 0)
make_employee("test_employee@salary.com")
- frappe.db.set_value("Employee", frappe.get_value("Employee", {"employee_name":"test_employee@salary.com"}, "name"), "relieving_date", None)
- frappe.db.set_value("Employee", frappe.get_value("Employee", {"employee_name":"test_employee@salary.com"}, "name"), "status", "Active")
+ frappe.db.set_value("Employee", frappe.get_value("Employee",
+ {"employee_name":"test_employee@salary.com"}, "name"), "relieving_date", None)
+ frappe.db.set_value("Employee", frappe.get_value("Employee",
+ {"employee_name":"test_employee@salary.com"}, "name"), "status", "Active")
ss = make_employee_salary_slip("test_employee@salary.com", "Monthly")
self.assertEqual(ss.total_working_days, no_of_days[0] - no_of_days[1])
@@ -100,16 +105,21 @@ class TestSalarySlip(unittest.TestCase):
self.assertEqual(ss.payment_days, (no_of_days[0] - getdate(date_of_joining).day + 1))
# set relieving date in the same month
- frappe.db.set_value("Employee", frappe.get_value("Employee", {"employee_name":"test_employee@salary.com"}, "name"), "date_of_joining", (add_days(nowdate(),-60)))
- frappe.db.set_value("Employee", frappe.get_value("Employee", {"employee_name":"test_employee@salary.com"}, "name"), "relieving_date", relieving_date)
- frappe.db.set_value("Employee", frappe.get_value("Employee", {"employee_name":"test_employee@salary.com"}, "name"), "status", "Left")
+ frappe.db.set_value("Employee",frappe.get_value("Employee",
+ {"employee_name":"test_employee@salary.com"}, "name"), "date_of_joining", (add_days(nowdate(),-60)))
+ frappe.db.set_value("Employee", frappe.get_value("Employee",
+ {"employee_name":"test_employee@salary.com"}, "name"), "relieving_date", relieving_date)
+ frappe.db.set_value("Employee", frappe.get_value("Employee",
+ {"employee_name":"test_employee@salary.com"}, "name"), "status", "Left")
ss.save()
self.assertEqual(ss.total_working_days, no_of_days[0])
self.assertEqual(ss.payment_days, getdate(relieving_date).day)
- frappe.db.set_value("Employee", frappe.get_value("Employee", {"employee_name":"test_employee@salary.com"}, "name"), "relieving_date", None)
- frappe.db.set_value("Employee", frappe.get_value("Employee", {"employee_name":"test_employee@salary.com"}, "name"), "status", "Active")
+ frappe.db.set_value("Employee", frappe.get_value("Employee",
+ {"employee_name":"test_employee@salary.com"}, "name"), "relieving_date", None)
+ frappe.db.set_value("Employee", frappe.get_value("Employee",
+ {"employee_name":"test_employee@salary.com"}, "name"), "status", "Active")
def test_employee_salary_slip_read_permission(self):
make_employee("test_employee@salary.com")
@@ -168,17 +178,22 @@ class TestSalarySlip(unittest.TestCase):
def test_tax_for_payroll_period(self):
data = {}
- # test the impact of tax exemption declaration, tax exemption proof submission and deduct check boxes in annual tax calculation
+ # test the impact of tax exemption declaration, tax exemption proof submission
+ # and deduct check boxes in annual tax calculation
# as per assigned salary structure 40500 in monthly salary so 236000*5/100/12
frappe.db.sql("""delete from `tabPayroll Period`""")
frappe.db.sql("""delete from `tabSalary Component`""")
payroll_period = create_payroll_period()
create_tax_slab(payroll_period)
employee = make_employee("test_tax@salary.slip")
- delete_docs = ["Salary Slip", "Additional Salary",
- "Employee Tax Exemption Declaration",
- "Employee Tax Exemption Proof Submission",
- "Employee Benefit Claim", "Salary Structure Assignment"]
+ delete_docs = [
+ "Salary Slip",
+ "Additional Salary",
+ "Employee Tax Exemption Declaration",
+ "Employee Tax Exemption Proof Submission",
+ "Employee Benefit Claim",
+ "Salary Structure Assignment"
+ ]
for doc in delete_docs:
frappe.db.sql("delete from `tab%s` where employee='%s'" % (doc, employee))
@@ -298,12 +313,11 @@ def make_employee_salary_slip(user, payroll_frequency, salary_structure=None):
if not salary_slip:
salary_slip = make_salary_slip(salary_structure_doc.name, employee = employee)
- salary_slip.employee_name = frappe.get_value("Employee", {"name":frappe.db.get_value("Employee", {"user_id": user})}, "employee_name")
+ salary_slip.employee_name = frappe.get_value("Employee",
+ {"name":frappe.db.get_value("Employee", {"user_id": user})}, "employee_name")
salary_slip.payroll_frequency = payroll_frequency
salary_slip.posting_date = nowdate()
salary_slip.insert()
- # salary_slip.submit()
- # salary_slip = salary_slip.name
return salary_slip
@@ -338,99 +352,99 @@ def create_account(company):
salary_account = frappe.db.get_value("Account", "Salary - " + frappe.get_cached_value('Company', company, 'abbr'))
if not salary_account:
frappe.get_doc({
- "doctype": "Account",
- "account_name": "Salary",
- "parent_account": "Indirect Expenses - " + frappe.get_cached_value('Company', company, 'abbr'),
- "company": company
+ "doctype": "Account",
+ "account_name": "Salary",
+ "parent_account": "Indirect Expenses - " + frappe.get_cached_value('Company', company, 'abbr'),
+ "company": company
}).insert()
return salary_account
def make_earning_salary_component(setup=False, test_tax=False):
data = [
+ {
+ "salary_component": 'Basic Salary',
+ "abbr":'BS',
+ "condition": 'base > 10000',
+ "formula": 'base*.5',
+ "type": "Earning",
+ "amount_based_on_formula": 1
+ },
+ {
+ "salary_component": 'HRA',
+ "abbr":'H',
+ "amount": 3000,
+ "type": "Earning"
+ },
+ {
+ "salary_component": 'Special Allowance',
+ "abbr":'SA',
+ "condition": 'H < 10000',
+ "formula": 'BS*.5',
+ "type": "Earning",
+ "amount_based_on_formula": 1
+ },
+ {
+ "salary_component": "Leave Encashment",
+ "abbr": 'LE',
+ "is_additional_component": 1,
+ "type": "Earning"
+ }
+ ]
+ if test_tax:
+ data.extend([
{
- "salary_component": 'Basic Salary',
- "abbr":'BS',
- "condition": 'base > 10000',
- "formula": 'base*.5',
+ "salary_component": "Leave Travel Allowance",
+ "abbr": 'B',
+ "is_flexible_benefit": 1,
"type": "Earning",
- "amount_based_on_formula": 1
+ "pay_against_benefit_claim": 1,
+ "max_benefit_amount": 100000
},
{
- "salary_component": 'HRA',
- "abbr":'H',
- "amount": 3000,
- "type": "Earning"
- },
- {
- "salary_component": 'Special Allowance',
- "abbr":'SA',
- "condition": 'H < 10000',
- "formula": 'BS*.5',
+ "salary_component": "Medical Allowance",
+ "abbr": 'B',
+ "is_flexible_benefit": 1,
+ "pay_against_benefit_claim": 0,
"type": "Earning",
- "amount_based_on_formula": 1
+ "max_benefit_amount": 15000
},
{
- "salary_component": "Leave Encashment",
- "abbr": 'LE',
+ "salary_component": "Perfomance Bonus",
+ "abbr": 'B',
"is_additional_component": 1,
"type": "Earning"
}
- ]
- if test_tax:
- data.extend([
- {
- "salary_component": "Leave Travel Allowance",
- "abbr": 'B',
- "is_flexible_benefit": 1,
- "type": "Earning",
- "pay_against_benefit_claim": 1,
- "max_benefit_amount": 100000
- },
- {
- "salary_component": "Medical Allowance",
- "abbr": 'B',
- "is_flexible_benefit": 1,
- "pay_against_benefit_claim": 0,
- "type": "Earning",
- "max_benefit_amount": 15000
- },
- {
- "salary_component": "Perfomance Bonus",
- "abbr": 'B',
- "is_additional_component": 1,
- "type": "Earning"
- }
- ])
+ ])
if setup or test_tax:
make_salary_component(data, test_tax)
data.append({
- "salary_component": 'Basic Salary',
- "abbr":'BS',
- "condition": 'base < 10000',
- "formula": 'base*.2',
- "type": "Earning",
- "amount_based_on_formula": 1
- })
+ "salary_component": 'Basic Salary',
+ "abbr":'BS',
+ "condition": 'base < 10000',
+ "formula": 'base*.2',
+ "type": "Earning",
+ "amount_based_on_formula": 1
+ })
return data
def make_deduction_salary_component(setup=False, test_tax=False):
data = [
- {
- "salary_component": 'Professional Tax',
- "abbr":'PT',
- "condition": 'base > 10000',
- "formula": 'base*.1',
- "type": "Deduction",
- "amount_based_on_formula": 1
- },
- {
- "salary_component": 'TDS',
- "abbr":'T',
- "formula": 'base*.1',
- "type": "Deduction",
- "amount_based_on_formula": 1
- }
- ]
+ {
+ "salary_component": 'Professional Tax',
+ "abbr":'PT',
+ "condition": 'base > 10000',
+ "formula": 'base*.1',
+ "type": "Deduction",
+ "amount_based_on_formula": 1
+ },
+ {
+ "salary_component": 'TDS',
+ "abbr":'T',
+ "formula": 'base*.1',
+ "type": "Deduction",
+ "amount_based_on_formula": 1
+ }
+ ]
if not test_tax:
data.append({
"salary_component": 'TDS',
@@ -453,48 +467,63 @@ def get_tax_paid_in_period(employee):
def create_exemption_declaration(employee, payroll_period):
create_exemption_category()
- declaration = frappe.get_doc({"doctype": "Employee Tax Exemption Declaration",
- "employee": employee,
- "payroll_period": payroll_period,
- "company": erpnext.get_default_company()})
- declaration.append("declarations", {"exemption_sub_category": "_Test Sub Category",
- "exemption_category": "_Test Category",
- "amount": 100000})
+ declaration = frappe.get_doc({
+ "doctype": "Employee Tax Exemption Declaration",
+ "employee": employee,
+ "payroll_period": payroll_period,
+ "company": erpnext.get_default_company()
+ })
+ declaration.append("declarations", {
+ "exemption_sub_category": "_Test Sub Category",
+ "exemption_category": "_Test Category",
+ "amount": 100000
+ })
declaration.submit()
def create_proof_submission(employee, payroll_period, amount):
submission_date = add_months(payroll_period.start_date, random.randint(0, 11))
- proof_submission = frappe.get_doc({"doctype": "Employee Tax Exemption Proof Submission",
- "employee": employee,
- "payroll_period": payroll_period.name,
- "submission_date": submission_date})
- proof_submission.append("tax_exemption_proofs", {"exemption_sub_category": "_Test Sub Category",
- "exemption_category": "_Test Category", "type_of_proof": "Test", "amount": amount})
+ proof_submission = frappe.get_doc({
+ "doctype": "Employee Tax Exemption Proof Submission",
+ "employee": employee,
+ "payroll_period": payroll_period.name,
+ "submission_date": submission_date
+ })
+ proof_submission.append("tax_exemption_proofs", {
+ "exemption_sub_category": "_Test Sub Category",
+ "exemption_category": "_Test Category",
+ "type_of_proof": "Test", "amount": amount
+ })
proof_submission.submit()
return submission_date
def create_benefit_claim(employee, payroll_period, amount, component):
claim_date = add_months(payroll_period.start_date, random.randint(0, 11))
- frappe.get_doc({"doctype": "Employee Benefit Claim", "employee": employee,
- "claimed_amount": amount, "claim_date": claim_date, "earning_component":
- component}).submit()
+ frappe.get_doc({
+ "doctype": "Employee Benefit Claim",
+ "employee": employee,
+ "claimed_amount": amount,
+ "claim_date": claim_date,
+ "earning_component": component
+ }).submit()
return claim_date
def create_tax_slab(payroll_period):
- data = [{
- "from_amount": 250000,
- "to_amount": 500000,
- "percent_deduction": 5
- },
- {
- "from_amount": 500000,
- "to_amount": 1000000,
- "percent_deduction": 20
- },
- {
- "from_amount": 1000000,
- "percent_deduction": 30
- }]
+ data = [
+ {
+ "from_amount": 250000,
+ "to_amount": 500000,
+ "percent_deduction": 5
+ },
+ {
+ "from_amount": 500000,
+ "to_amount": 1000000,
+ "percent_deduction": 20
+ },
+ {
+ "from_amount": 1000000,
+ "percent_deduction": 30
+ }
+ ]
payroll_period.taxable_salary_slabs = []
for item in data:
payroll_period.append("taxable_salary_slabs", item)
@@ -526,9 +555,13 @@ def create_salary_slips_for_payroll_period(employee, salary_structure, payroll_p
def create_additional_salary(employee, payroll_period, amount):
salary_date = add_months(payroll_period.start_date, random.randint(0, 11))
- frappe.get_doc({"doctype": "Additional Salary", "employee": employee,
- "company": erpnext.get_default_company(),
- "salary_component": "Perfomance Bonus",
- "payroll_date": salary_date,
- "amount": amount, "type": "Earning"}).submit()
+ frappe.get_doc({
+ "doctype": "Additional Salary",
+ "employee": employee,
+ "company": erpnext.get_default_company(),
+ "salary_component": "Perfomance Bonus",
+ "payroll_date": salary_date,
+ "amount": amount,
+ "type": "Earning"
+ }).submit()
return salary_date
diff --git a/erpnext/hr/doctype/skill/__init__.py b/erpnext/hr/doctype/skill/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/hr/doctype/skill/skill.js b/erpnext/hr/doctype/skill/skill.js
new file mode 100644
index 0000000000..a939ff0dab
--- /dev/null
+++ b/erpnext/hr/doctype/skill/skill.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Skill', {
+ // refresh: function(frm) {
+
+ // }
+});
diff --git a/erpnext/hr/doctype/skill/skill.json b/erpnext/hr/doctype/skill/skill.json
new file mode 100644
index 0000000000..518297395b
--- /dev/null
+++ b/erpnext/hr/doctype/skill/skill.json
@@ -0,0 +1,113 @@
+{
+ "allow_copy": 0,
+ "allow_events_in_timeline": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "autoname": "field:skill_name",
+ "beta": 0,
+ "creation": "2019-04-16 09:54:39.486915",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 0,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_if_empty": 0,
+ "fieldname": "skill_name",
+ "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": "Skill Name",
+ "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": 1
+ }
+ ],
+ "has_web_view": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2019-04-16 09:55:00.536328",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Skill",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "amend": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ },
+ {
+ "amend": 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": "HR Manager",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ }
+ ],
+ "quick_entry": 1,
+ "read_only": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "ASC",
+ "track_changes": 1,
+ "track_seen": 0,
+ "track_views": 0
+}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/skill/skill.py b/erpnext/hr/doctype/skill/skill.py
new file mode 100644
index 0000000000..8d24212075
--- /dev/null
+++ b/erpnext/hr/doctype/skill/skill.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+# import frappe
+from frappe.model.document import Document
+
+class Skill(Document):
+ pass
diff --git a/erpnext/hr/utils.py b/erpnext/hr/utils.py
index 313cfc453f..a600e75884 100644
--- a/erpnext/hr/utils.py
+++ b/erpnext/hr/utils.py
@@ -221,16 +221,30 @@ def get_employee_leave_policy(employee):
def validate_tax_declaration(declarations):
subcategories = []
- for declaration in declarations:
- if declaration.exemption_sub_category in subcategories:
- frappe.throw(_("More than one selection for {0} not \
- allowed").format(declaration.exemption_sub_category), frappe.ValidationError)
- subcategories.append(declaration.exemption_sub_category)
- max_amount = frappe.db.get_value("Employee Tax Exemption Sub Category", \
- declaration.exemption_sub_category, "max_amount")
- if declaration.amount > max_amount:
- frappe.throw(_("Max exemption amount for {0} is {1}").format(\
- declaration.exemption_sub_category, max_amount), frappe.ValidationError)
+ for d in declarations:
+ if d.exemption_sub_category in subcategories:
+ frappe.throw(_("More than one selection for {0} not allowed").format(d.exemption_sub_category))
+ subcategories.append(d.exemption_sub_category)
+
+def get_total_exemption_amount(declarations):
+ exemptions = frappe._dict()
+ for d in declarations:
+ exemptions.setdefault(d.exemption_category, frappe._dict())
+ category_max_amount = exemptions.get(d.exemption_category).max_amount
+ if not category_max_amount:
+ category_max_amount = frappe.db.get_value("Employee Tax Exemption Category", d.exemption_category, "max_amount")
+ exemptions.get(d.exemption_category).max_amount = category_max_amount
+ sub_category_exemption_amount = d.max_amount \
+ if (d.max_amount and flt(d.amount) > flt(d.max_amount)) else d.amount
+
+ exemptions.get(d.exemption_category).setdefault("total_exemption_amount", 0.0)
+ exemptions.get(d.exemption_category).total_exemption_amount += flt(sub_category_exemption_amount)
+
+ if category_max_amount and exemptions.get(d.exemption_category).total_exemption_amount > category_max_amount:
+ exemptions.get(d.exemption_category).total_exemption_amount = category_max_amount
+
+ total_exemption_amount = sum([flt(d.total_exemption_amount) for d in exemptions.values()])
+ return total_exemption_amount
def get_leave_period(from_date, to_date, company):
leave_period = frappe.db.sql("""
diff --git a/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.py b/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.py
index 59861ceba3..a7d1d859dd 100644
--- a/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.py
+++ b/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.py
@@ -20,13 +20,12 @@ class BOMUpdateTool(Document):
for bom in bom_list:
try:
bom_obj = frappe.get_doc("BOM", bom)
- bom_obj.get_doc_before_save()
+ bom_obj.load_doc_before_save()
updated_bom = bom_obj.update_cost_and_exploded_items(updated_bom)
bom_obj.calculate_cost()
bom_obj.update_parent_cost()
bom_obj.db_update()
- if (getattr(bom_obj.meta, 'track_changes', False)
- and bom_obj._doc_before_save and not bom_obj.flags.ignore_version):
+ if (getattr(bom_obj.meta, 'track_changes', False) and not bom_obj.flags.ignore_version):
bom_obj.save_version()
frappe.db.commit()
@@ -37,7 +36,7 @@ class BOMUpdateTool(Document):
def validate_bom(self):
if cstr(self.current_bom) == cstr(self.new_bom):
frappe.throw(_("Current BOM and New BOM can not be same"))
-
+
if frappe.db.get_value("BOM", self.current_bom, "item") \
!= frappe.db.get_value("BOM", self.new_bom, "item"):
frappe.throw(_("The selected BOMs are not for the same item"))
diff --git a/erpnext/patches/v12_0/move_item_tax_to_item_tax_template.py b/erpnext/patches/v12_0/move_item_tax_to_item_tax_template.py
index 575ebebadb..02203d29d4 100644
--- a/erpnext/patches/v12_0/move_item_tax_to_item_tax_template.py
+++ b/erpnext/patches/v12_0/move_item_tax_to_item_tax_template.py
@@ -13,19 +13,19 @@ def execute():
old_item_taxes.setdefault(d.item_code, [])
old_item_taxes[d.item_code].append(d)
- frappe.reload_doc("accounts", "doctype", "item_tax_template_detail")
- frappe.reload_doc("accounts", "doctype", "item_tax_template")
- frappe.reload_doc("stock", "doctype", "item")
- frappe.reload_doc("stock", "doctype", "item_tax")
- frappe.reload_doc("selling", "doctype", "quotation_item")
- frappe.reload_doc("selling", "doctype", "sales_order_item")
- frappe.reload_doc("stock", "doctype", "delivery_note_item")
- frappe.reload_doc("accounts", "doctype", "sales_invoice_item")
- frappe.reload_doc("buying", "doctype", "supplier_quotation_item")
- frappe.reload_doc("buying", "doctype", "purchase_order_item")
- frappe.reload_doc("stock", "doctype", "purchase_receipt_item")
- frappe.reload_doc("accounts", "doctype", "purchase_invoice_item")
- frappe.reload_doc("accounts", "doctype", "accounts_settings")
+ frappe.reload_doc("accounts", "doctype", "item_tax_template_detail", force=1)
+ frappe.reload_doc("accounts", "doctype", "item_tax_template", force=1)
+ frappe.reload_doc("stock", "doctype", "item", force=1)
+ frappe.reload_doc("stock", "doctype", "item_tax", force=1)
+ frappe.reload_doc("selling", "doctype", "quotation_item", force=1)
+ frappe.reload_doc("selling", "doctype", "sales_order_item", force=1)
+ frappe.reload_doc("stock", "doctype", "delivery_note_item", force=1)
+ frappe.reload_doc("accounts", "doctype", "sales_invoice_item", force=1)
+ frappe.reload_doc("buying", "doctype", "supplier_quotation_item", force=1)
+ frappe.reload_doc("buying", "doctype", "purchase_order_item", force=1)
+ frappe.reload_doc("stock", "doctype", "purchase_receipt_item", force=1)
+ frappe.reload_doc("accounts", "doctype", "purchase_invoice_item", force=1)
+ frappe.reload_doc("accounts", "doctype", "accounts_settings", force=1)
# for each item that have item tax rates
for item_code in old_item_taxes.keys():
@@ -77,6 +77,21 @@ def get_item_tax_template(item_tax_templates, rename_template_to_untitled, item_
item_tax_template = frappe.new_doc("Item Tax Template")
item_tax_template.title = "{}--{}".format(parent, item_code) if parent else "Item-{}".format(item_code)
for tax_type, tax_rate in iteritems(item_tax_map):
+ if not frappe.db.exists("Account", tax_type):
+ parts = tax_type.strip().split(" - ")
+ account_name = " - ".join(parts[:-1])
+ company = frappe.db.get_value("Company", filters={"abbr": parts[-1]})
+ parent_account = frappe.db.get_value("Account",
+ filters={"account_type": "Tax", "root_type": "Liability", "is_group": 0}, fieldname="parent_account")
+
+ frappe.get_doc({
+ "doctype": "Account",
+ "account_name": account_name,
+ "company": company,
+ "account_type": "Tax",
+ "parent_account": parent_account
+ }).insert()
+
item_tax_template.append("taxes", {"tax_type": tax_type, "tax_rate": tax_rate})
item_tax_templates.setdefault(item_tax_template.title, {})
item_tax_templates[item_tax_template.title][tax_type] = tax_rate
diff --git a/erpnext/portal/product_configurator/utils.py b/erpnext/portal/product_configurator/utils.py
index f02212c6a6..405a6d8c31 100644
--- a/erpnext/portal/product_configurator/utils.py
+++ b/erpnext/portal/product_configurator/utils.py
@@ -167,13 +167,17 @@ def get_attributes_and_values(item_code):
if attribute in attribute_list:
valid_options.setdefault(attribute, set()).add(attribute_value)
+ item_attribute_values = frappe.db.get_all('Item Attribute Value',
+ ['parent', 'attribute_value', 'idx'], order_by='parent asc, idx asc')
+ ordered_attribute_value_map = frappe._dict()
+ for iv in item_attribute_values:
+ ordered_attribute_value_map.setdefault(iv.parent, []).append(iv.attribute_value)
+
# build attribute values in idx order
- ordered_attribute_value_map = item_cache.get_ordered_attribute_values()
for attr in attributes:
valid_attribute_values = valid_options.get(attr.attribute, [])
ordered_values = ordered_attribute_value_map.get(attr.attribute, [])
attr['values'] = [v for v in ordered_values if v in valid_attribute_values]
- attr['values'] = valid_attribute_values
return attributes
diff --git a/erpnext/public/build.json b/erpnext/public/build.json
index 60e72dad71..45de6eb294 100644
--- a/erpnext/public/build.json
+++ b/erpnext/public/build.json
@@ -54,5 +54,8 @@
"stock/dashboard/item_dashboard.html",
"stock/dashboard/item_dashboard_list.html",
"stock/dashboard/item_dashboard.js"
+ ],
+ "js/lms.min.js": [
+ "public/js/education/lms/lms.js"
]
}
diff --git a/erpnext/public/js/communication.js b/erpnext/public/js/communication.js
index 49701b88b6..5316eb45b5 100644
--- a/erpnext/public/js/communication.js
+++ b/erpnext/public/js/communication.js
@@ -33,7 +33,7 @@ frappe.ui.form.on("Communication", {
make_lead_from_communication: (frm) => {
return frappe.call({
- method: "frappe.email.inbox.make_lead_from_communication",
+ method: "erpnext.crm.doctype.lead.lead.make_lead_from_communication",
args: {
communication: frm.doc.name
},
@@ -48,7 +48,7 @@ frappe.ui.form.on("Communication", {
make_issue_from_communication: (frm) => {
return frappe.call({
- method: "frappe.email.inbox.make_issue_from_communication",
+ method: "erpnext.support.doctype.issue.issue.make_issue_from_communication",
args: {
communication: frm.doc.name
},
@@ -63,7 +63,7 @@ frappe.ui.form.on("Communication", {
make_opportunity_from_communication: (frm) => {
return frappe.call({
- method: "frappe.email.inbox.make_opportunity_from_communication",
+ method: "erpnext.crm.doctype.opportunity.opportunity.make_opportunity_from_communication",
args: {
communication: frm.doc.name
},
diff --git a/erpnext/public/js/education/lms/call.js b/erpnext/public/js/education/lms/call.js
new file mode 100644
index 0000000000..e35acbdd75
--- /dev/null
+++ b/erpnext/public/js/education/lms/call.js
@@ -0,0 +1,15 @@
+frappe.ready(() => {
+ frappe.provide('lms');
+
+ lms.call = (method, args) => {
+ const method_path = 'erpnext.www.lms.' + method;
+ return new Promise((resolve, reject) => {
+ return frappe.call({
+ method: method_path,
+ args,
+ })
+ .then(r => resolve(r.message))
+ .fail(reject);
+ });
+ };
+});
\ No newline at end of file
diff --git a/erpnext/public/js/education/lms/components/Article.vue b/erpnext/public/js/education/lms/components/Article.vue
new file mode 100644
index 0000000000..eab1424455
--- /dev/null
+++ b/erpnext/public/js/education/lms/components/Article.vue
@@ -0,0 +1,44 @@
+
+
+ {{ title }}
+
+ Published on {{ publishDate }}
+ — {{ author }}
+
+
+ {{ course.course_name }}
+
+ Topics
+
+
+
+ {{ fullName }}
+
+
+
+
+ None
+ {{ program.program_name }}
+ {{ programData.program }}
+
+
+
+ {{ question.question }}
+
+{{ question.question }}
+
+{{ quizData.program }}
+
+
+ - Unattempted
+ {{ topic.topic_name }}
+
+ Content
+
+
+
+ {{ contentData.name }}
+
+ {{ contentData.duration }} Mins
+ — Published on {{ contentData.publish_date }}.
+
+
+
{%= __("No address added yet.") %}
{% } %} - + diff --git a/erpnext/public/js/templates/contact_list.html b/erpnext/public/js/templates/contact_list.html index 2144893961..893b4e0ec2 100644 --- a/erpnext/public/js/templates/contact_list.html +++ b/erpnext/public/js/templates/contact_list.html @@ -10,7 +10,7 @@ – {%= contact_list[i].designation %} {% } %} {%= __("Edit") %} @@ -33,6 +33,6 @@ {% if(!contact_list.length) { %}{%= __("No contacts added yet.") %}
{% } %} -