Merge branch 'develop' of github.com:frappe/erpnext into develop
diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py
index 471da9e..05a3c11 100644
--- a/erpnext/accounts/party.py
+++ b/erpnext/accounts/party.py
@@ -337,13 +337,18 @@
def validate_party_frozen_disabled(party_type, party_name):
if party_type and party_name:
- party = frappe.db.get_value(party_type, party_name, ["is_frozen", "disabled"], as_dict=True)
- if party.disabled:
- frappe.throw(_("{0} {1} is disabled").format(party_type, party_name), PartyDisabled)
- elif party.is_frozen:
- frozen_accounts_modifier = frappe.db.get_value( 'Accounts Settings', None,'frozen_accounts_modifier')
- if not frozen_accounts_modifier in frappe.get_roles():
- frappe.throw(_("{0} {1} is frozen").format(party_type, party_name), PartyFrozen)
+ if party_type in ("Customer", "Supplier"):
+ party = frappe.db.get_value(party_type, party_name, ["is_frozen", "disabled"], as_dict=True)
+ if party.disabled:
+ frappe.throw(_("{0} {1} is disabled").format(party_type, party_name), PartyDisabled)
+ elif party.get("is_frozen"):
+ frozen_accounts_modifier = frappe.db.get_value( 'Accounts Settings', None,'frozen_accounts_modifier')
+ if not frozen_accounts_modifier in frappe.get_roles():
+ frappe.throw(_("{0} {1} is frozen").format(party_type, party_name), PartyFrozen)
+
+ elif party_type == "Employee":
+ if frappe.db.get_value("Employee", party_name, "status") == "Left":
+ frappe.msgprint(_("{0} {1} is not active").format(party_type, party_name), PartyDisabled, alert=True)
def get_timeline_data(doctype, name):
'''returns timeline data for the past one year'''
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.js b/erpnext/accounts/report/general_ledger/general_ledger.js
index dc79d1f..ab7ad49 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.js
+++ b/erpnext/accounts/report/general_ledger/general_ledger.js
@@ -48,6 +48,12 @@
"fieldtype": "Data",
},
{
+ "fieldname":"project",
+ "label": __("Project"),
+ "fieldtype": "Link",
+ "options": "Project"
+ },
+ {
"fieldtype": "Break",
},
{
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.py b/erpnext/accounts/report/general_ledger/general_ledger.py
index 00c17e8..d09ac70 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.py
+++ b/erpnext/accounts/report/general_ledger/general_ledger.py
@@ -149,6 +149,9 @@
if not (filters.get("account") or filters.get("party") or filters.get("group_by_account")):
conditions.append("posting_date >=%(from_date)s")
+ if filters.get("project"):
+ conditions.append("project=%(project)s")
+
from frappe.desk.reportview import build_match_conditions
match_conditions = build_match_conditions("GL Entry")
if match_conditions: conditions.append(match_conditions)
diff --git a/erpnext/buying/doctype/purchase_common/purchase_common.js b/erpnext/buying/doctype/purchase_common/purchase_common.js
index 720a1dc..c03ccc8 100644
--- a/erpnext/buying/doctype/purchase_common/purchase_common.js
+++ b/erpnext/buying/doctype/purchase_common/purchase_common.js
@@ -21,20 +21,12 @@
if(this.frm.get_field('shipping_address')) {
this.frm.set_query("shipping_address", function(){
if(me.frm.doc.customer){
- return{
- filters:{
- "customer": me.frm.doc.customer
- }
- }
- }
- else{
- return{
- filters:{
- "is_your_company_address": 1,
- "company": me.frm.doc.company
- }
- }
- }
+ return {
+ query: 'frappe.geo.doctype.address.address.address_query',
+ filters: { link_doctype: 'Customer', link_name: me.frm.doc.customer }
+ };
+ } else
+ return erpnext.queries.company_address_query(me.frm.doc)
});
}
},
diff --git a/erpnext/buying/doctype/supplier/supplier.js b/erpnext/buying/doctype/supplier/supplier.js
index ce6f451..7e5e045 100644
--- a/erpnext/buying/doctype/supplier/supplier.js
+++ b/erpnext/buying/doctype/supplier/supplier.js
@@ -26,11 +26,11 @@
if(frm.doc.__islocal){
hide_field(['address_html','contact_html']);
- erpnext.utils.clear_address_and_contact(frm);
+ frappe.geo.clear_address_and_contact(frm);
}
else {
unhide_field(['address_html','contact_html']);
- erpnext.utils.render_address_and_contact(frm);
+ frappe.geo.render_address_and_contact(frm);
// custom buttons
frm.add_custom_button(__('Accounting Ledger'), function() {
diff --git a/erpnext/buying/doctype/supplier/supplier.py b/erpnext/buying/doctype/supplier/supplier.py
index 9eaaad1..7f92767 100644
--- a/erpnext/buying/doctype/supplier/supplier.py
+++ b/erpnext/buying/doctype/supplier/supplier.py
@@ -6,7 +6,7 @@
import frappe.defaults
from frappe import msgprint, _
from frappe.model.naming import make_autoname
-from erpnext.utilities.address_and_contact import (load_address_and_contact,
+from frappe.geo.address_and_contact import (load_address_and_contact,
delete_contact_and_address)
from erpnext.utilities.transaction_base import TransactionBase
@@ -61,14 +61,6 @@
validate_party_accounts(self)
self.status = get_party_status(self)
- def get_contacts(self,nm):
- if nm:
- contact_details =frappe.db.convert_to_lists(frappe.db.sql("select name, CONCAT(IFNULL(first_name,''),' ',IFNULL(last_name,'')),contact_no,email_id from `tabContact` where supplier = %s", nm))
-
- return contact_details
- else:
- return ''
-
def on_trash(self):
delete_contact_and_address('Supplier', self.name)
diff --git a/erpnext/buying/report/supplier_addresses_and_contacts/__init__.py b/erpnext/buying/report/supplier_addresses_and_contacts/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/erpnext/buying/report/supplier_addresses_and_contacts/__init__.py
+++ /dev/null
diff --git a/erpnext/buying/report/supplier_addresses_and_contacts/supplier_addresses_and_contacts.json b/erpnext/buying/report/supplier_addresses_and_contacts/supplier_addresses_and_contacts.json
deleted file mode 100644
index 128548f..0000000
--- a/erpnext/buying/report/supplier_addresses_and_contacts/supplier_addresses_and_contacts.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "apply_user_permissions": 1,
- "creation": "2013-10-09 10:38:40",
- "docstatus": 0,
- "doctype": "Report",
- "idx": 1,
- "is_standard": "Yes",
- "modified": "2014-09-11 08:53:17.358554",
- "modified_by": "Administrator",
- "module": "Buying",
- "name": "Supplier Addresses and Contacts",
- "owner": "Administrator",
- "query": "SELECT\n `tabSupplier`.name as \"Supplier:Link/Supplier:120\",\n\t`tabSupplier`.supplier_name as \"Supplier Name::120\",\n\t`tabSupplier`.supplier_type as \"Supplier Type:Link/Supplier Type:120\",\n\tconcat_ws(', ', \n\t\ttrim(',' from `tabAddress`.address_line1), \n\t\ttrim(',' from tabAddress.address_line2), \n\t\ttabAddress.state, tabAddress.pincode, tabAddress.country\n\t) as 'Address::180',\n concat_ws(', ', `tabContact`.first_name, `tabContact`.last_name) as \"Contact Name::180\",\n\t`tabContact`.phone as \"Phone\",\n\t`tabContact`.mobile_no as \"Mobile No\",\n\t`tabContact`.email_id as \"Email Address::120\",\n\t`tabContact`.is_primary_contact as \"Is Primary Contact::120\"\nFROM\n\t`tabSupplier`\n\tleft join `tabAddress` on (\n\t\t`tabAddress`.supplier=`tabSupplier`.name\n\t)\n\tleft join `tabContact` on (\n\t\t`tabContact`.supplier=`tabSupplier`.name\n\t)\nWHERE\n\t`tabSupplier`.docstatus<2\nORDER BY\n\t`tabSupplier`.name asc",
- "ref_doctype": "Supplier",
- "report_name": "Supplier Addresses and Contacts",
- "report_type": "Query Report"
-}
\ No newline at end of file
diff --git a/erpnext/config/buying.py b/erpnext/config/buying.py
index e246266..990ca7a 100644
--- a/erpnext/config/buying.py
+++ b/erpnext/config/buying.py
@@ -172,8 +172,12 @@
{
"type": "report",
"is_query_report": True,
- "name": "Supplier Addresses and Contacts",
- "doctype": "Supplier"
+ "name": "Addresses And Contacts",
+ "label": "Supplier Addresses And Contacts",
+ "doctype": "Address",
+ "route_options": {
+ "party_type": "Supplier"
+ }
},
]
},
diff --git a/erpnext/config/hr.py b/erpnext/config/hr.py
index 3a18a27..366d771 100644
--- a/erpnext/config/hr.py
+++ b/erpnext/config/hr.py
@@ -266,6 +266,26 @@
]
},
{
+ "label": _("Employee Loan Management"),
+ "icon": "icon-list",
+ "items": [
+ {
+ "type": "doctype",
+ "name": "Loan Type",
+ "description": _("Define various loan types")
+ },
+ {
+ "type": "doctype",
+ "name": "Employee Loan Application",
+ "description": _("Employee Loan Application")
+ },
+ {
+ "type": "doctype",
+ "name": "Employee Loan"
+ },
+ ]
+ },
+ {
"label": _("Help"),
"icon": "fa fa-facetime-video",
"items": [
diff --git a/erpnext/config/schools.py b/erpnext/config/schools.py
index 903f54b..a4c5744 100644
--- a/erpnext/config/schools.py
+++ b/erpnext/config/schools.py
@@ -160,23 +160,6 @@
]
},
{
- "label": _("LMS"),
- "items": [
- {
- "type": "doctype",
- "name": "Announcement"
- },
- {
- "type": "doctype",
- "name": "Topic"
- },
- {
- "type": "doctype",
- "name": "Discussion"
- }
- ]
- },
- {
"label": _("Setup"),
"items": [
{
diff --git a/erpnext/config/selling.py b/erpnext/config/selling.py
index c406d09..bbae245 100644
--- a/erpnext/config/selling.py
+++ b/erpnext/config/selling.py
@@ -120,6 +120,16 @@
{
"type": "report",
"is_query_report": True,
+ "name": "Addresses And Contacts",
+ "label": "Sales Partner Addresses And Contacts",
+ "doctype": "Address",
+ "route_options": {
+ "party_type": "Sales Partner"
+ }
+ },
+ {
+ "type": "report",
+ "is_query_report": True,
"name": "Territory Target Variance (Item Group-Wise)",
"route": "query-report/Territory Target Variance Item Group-Wise",
"doctype": "Territory"
@@ -215,8 +225,12 @@
{
"type": "report",
"is_query_report": True,
- "name": "Customer Addresses And Contacts",
- "doctype": "Contact"
+ "name": "Addresses And Contacts",
+ "label": "Customer Addresses And Contacts",
+ "doctype": "Address",
+ "route_options": {
+ "party_type": "Customer"
+ }
},
{
"type": "report",
diff --git a/erpnext/crm/doctype/lead/lead.js b/erpnext/crm/doctype/lead/lead.js
index be3cd82..7e22125 100644
--- a/erpnext/crm/doctype/lead/lead.js
+++ b/erpnext/crm/doctype/lead/lead.js
@@ -25,6 +25,7 @@
refresh: function() {
var doc = this.frm.doc;
erpnext.toggle_naming_series();
+ frappe.dynamic_link = {doc: this.frm.doc, fieldname: 'name', doctype: 'Lead'}
if(!this.frm.doc.__islocal && this.frm.doc.__onload && !this.frm.doc.__onload.is_customer) {
this.frm.add_custom_button(__("Customer"), this.create_customer, __("Make"));
@@ -34,9 +35,9 @@
}
if(!this.frm.doc.__islocal) {
- erpnext.utils.render_address_and_contact(cur_frm);
+ frappe.geo.render_address_and_contact(cur_frm);
} else {
- erpnext.utils.clear_address_and_contact(cur_frm);
+ frappe.geo.clear_address_and_contact(cur_frm);
}
},
diff --git a/erpnext/crm/doctype/lead/lead.py b/erpnext/crm/doctype/lead/lead.py
index 4b2899d..411f597 100644
--- a/erpnext/crm/doctype/lead/lead.py
+++ b/erpnext/crm/doctype/lead/lead.py
@@ -8,7 +8,7 @@
from frappe.model.mapper import get_mapped_doc
from erpnext.controllers.selling_controller import SellingController
-from erpnext.utilities.address_and_contact import load_address_and_contact
+from frappe.geo.address_and_contact import load_address_and_contact
from erpnext.accounts.party import set_taxes
sender_field = "email_id"
@@ -127,7 +127,7 @@
@frappe.whitelist()
def make_opportunity(source_name, target_doc=None):
- target_doc = get_mapped_doc("Lead", source_name,
+ target_doc = get_mapped_doc("Lead", source_name,
{"Lead": {
"doctype": "Opportunity",
"field_map": {
diff --git a/erpnext/crm/doctype/opportunity/opportunity.py b/erpnext/crm/doctype/opportunity/opportunity.py
index 4bb6765..301dc82 100644
--- a/erpnext/crm/doctype/opportunity/opportunity.py
+++ b/erpnext/crm/doctype/opportunity/opportunity.py
@@ -106,30 +106,6 @@
lead_name, company_name = frappe.db.get_value("Lead", self.lead, ["lead_name", "company_name"])
self.customer_name = company_name or lead_name
- def get_cust_address(self,name):
- details = frappe.db.sql("""select customer_name, address, territory, customer_group
- from `tabCustomer` where name = %s and docstatus != 2""", (name), as_dict = 1)
- if details:
- ret = {
- 'customer_name': details and details[0]['customer_name'] or '',
- 'address' : details and details[0]['address'] or '',
- 'territory' : details and details[0]['territory'] or '',
- 'customer_group' : details and details[0]['customer_group'] or ''
- }
- # ********** get primary contact details (this is done separately coz. , in case there is no primary contact thn it would not be able to fetch customer details in case of join query)
-
- contact_det = frappe.db.sql("""select contact_name, contact_no, email_id
- from `tabContact` where customer = %s and is_customer = 1
- and is_primary_contact = 'Yes' and docstatus != 2""", name, as_dict = 1)
-
- ret['contact_person'] = contact_det and contact_det[0]['contact_name'] or ''
- ret['contact_no'] = contact_det and contact_det[0]['contact_no'] or ''
- ret['email_id'] = contact_det and contact_det[0]['email_id'] or ''
-
- return ret
- else:
- frappe.throw(_("Customer {0} does not exist").format(name), frappe.DoesNotExistError)
-
def on_update(self):
self.add_calendar_event()
diff --git a/erpnext/docs/assets/img/human-resources/employee-loan-application.png b/erpnext/docs/assets/img/human-resources/employee-loan-application.png
new file mode 100644
index 0000000..317de4f
--- /dev/null
+++ b/erpnext/docs/assets/img/human-resources/employee-loan-application.png
Binary files differ
diff --git a/erpnext/docs/assets/img/human-resources/employee-loan.png b/erpnext/docs/assets/img/human-resources/employee-loan.png
new file mode 100644
index 0000000..19f3181
--- /dev/null
+++ b/erpnext/docs/assets/img/human-resources/employee-loan.png
Binary files differ
diff --git a/erpnext/docs/assets/img/human-resources/loan-repayment-salary-slip.png b/erpnext/docs/assets/img/human-resources/loan-repayment-salary-slip.png
new file mode 100644
index 0000000..4e5f340
--- /dev/null
+++ b/erpnext/docs/assets/img/human-resources/loan-repayment-salary-slip.png
Binary files differ
diff --git a/erpnext/docs/assets/img/human-resources/loan-type.png b/erpnext/docs/assets/img/human-resources/loan-type.png
new file mode 100644
index 0000000..9146b89
--- /dev/null
+++ b/erpnext/docs/assets/img/human-resources/loan-type.png
Binary files differ
diff --git a/erpnext/docs/assets/img/human-resources/repayment-info.png b/erpnext/docs/assets/img/human-resources/repayment-info.png
new file mode 100644
index 0000000..5b8bdf7
--- /dev/null
+++ b/erpnext/docs/assets/img/human-resources/repayment-info.png
Binary files differ
diff --git a/erpnext/docs/assets/img/human-resources/repayment-schedule.png b/erpnext/docs/assets/img/human-resources/repayment-schedule.png
new file mode 100644
index 0000000..f2ddf02
--- /dev/null
+++ b/erpnext/docs/assets/img/human-resources/repayment-schedule.png
Binary files differ
diff --git a/erpnext/docs/user/manual/en/human-resources/employee-loan-management.md b/erpnext/docs/user/manual/en/human-resources/employee-loan-management.md
new file mode 100644
index 0000000..b76a226
--- /dev/null
+++ b/erpnext/docs/user/manual/en/human-resources/employee-loan-management.md
@@ -0,0 +1,56 @@
+# Employee Loan Management
+This module enables companies which provides employee loans to define and manage employee loans.
+Employees can request loans, which are then reviewed and approved. For the approved loans,
+repayment schedule for the entire loan cycle can be generated and automatic deduction from salary can also be set up.
+
+### Loan Type
+To create a new Loan Type go to:
+
+> Human Resources > Employee Loan Management > Loan Type > New Loan Type
+
+Configure Loan limit and Rate of interest.
+
+<img class="screenshot" alt="Loan Type" src="{{docs_base_url}}/assets/img/human-resources/loan-type.png">
+
+### Employee Loan Application
+
+Employee can apply for loan by going to:
+
+> Human Resources > Employee Loan Management > Employee Loan Application > New Employee Loan Application
+
+<img class="screenshot" alt="Employee Loan Application" src="{{docs_base_url}}/assets/img/human-resources/employee-loan-application.png">
+
+#### In the Employee Loan Application,
+
+ * Enter Employee details and Loan details
+ * Select the repayment method, and based on your selection enter Repayment Period in Months or repayment Amount
+
+On save, Employee can see Repayment Information and make changes if required before submitting.
+
+<img class="screenshot" alt="Employee Loan Application" src="{{docs_base_url}}/assets/img/human-resources/repayment-info.png">
+
+### Employee Loan
+
+Once the Loan is approved, Manager can create Employee Loan record for the Employee.
+
+> Human Resources > Employee Loan Management > Employee Loan > New Employee Loan
+
+<img class="screenshot" alt="Employee Loan Application" src="{{docs_base_url}}/assets/img/human-resources/employee-loan.png">
+
+#### In the Employee Loan,
+
+ * Enter Employee and Loan Application
+ * Check "Repay from Salary" if the loan repayment will be deducted from the salary
+ * Enter Disbursement Date and Account Info
+ * As soon as you hit save, the repayment schedule is generated.
+
+<img class="screenshot" alt="repayment Schedule" src="{{docs_base_url}}/assets/img/human-resources/repayment-schedule.png">
+
+#### Loan repayment deduction from Salary
+
+To auto deduct the Loan repayment from Salary, check "Repay from Salary" in Employee Loan. It will appear as Loan repayment in Salary Slip.
+
+<img class="screenshot" alt="Salary Slip" src="{{docs_base_url}}/assets/img/human-resources/loan-repayment-salary-slip.png">
+
+
+
\ No newline at end of file
diff --git a/erpnext/docs/user/manual/en/human-resources/index.txt b/erpnext/docs/user/manual/en/human-resources/index.txt
index f91edfa..673efdb 100644
--- a/erpnext/docs/user/manual/en/human-resources/index.txt
+++ b/erpnext/docs/user/manual/en/human-resources/index.txt
@@ -15,4 +15,5 @@
human-resource-setup
daily-work-summary
fleet-management
+employee-loan-management
articles
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index 8443cdf..66acdb1 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -107,7 +107,6 @@
{"title": _("Shipments"), "route": "/shipments", "reference_doctype": "Delivery Note", "role":"Customer"},
{"title": _("Issues"), "route": "/issues", "reference_doctype": "Issue", "role":"Customer"},
{"title": _("Addresses"), "route": "/addresses", "reference_doctype": "Address"},
- {"title": _("Announcements"), "route": "/announcement", "reference_doctype": "Announcement"},
{"title": _("Fees"), "route": "/fees", "reference_doctype": "Fees", "role":"Student"}
]
@@ -122,18 +121,7 @@
"Sales Invoice": "erpnext.controllers.website_list_for_contact.has_website_permission",
"Supplier Quotation": "erpnext.controllers.website_list_for_contact.has_website_permission",
"Delivery Note": "erpnext.controllers.website_list_for_contact.has_website_permission",
- "Issue": "erpnext.support.doctype.issue.issue.has_website_permission",
- "Discussion": "erpnext.schools.web_form.discussion.discussion.has_website_permission"
-}
-
-permission_query_conditions = {
- "Contact": "erpnext.utilities.address_and_contact.get_permission_query_conditions_for_contact",
- "Address": "erpnext.utilities.address_and_contact.get_permission_query_conditions_for_address"
-}
-
-has_permission = {
- "Contact": "erpnext.utilities.address_and_contact.has_permission",
- "Address": "erpnext.utilities.address_and_contact.has_permission"
+ "Issue": "erpnext.support.doctype.issue.issue.has_website_permission"
}
dump_report_map = "erpnext.startup.report_data_map.data_map"
@@ -153,7 +141,7 @@
"after_insert": "frappe.email.doctype.contact.contact.update_contact",
"validate": "erpnext.hr.doctype.employee.employee.validate_employee_role",
"on_update": "erpnext.hr.doctype.employee.employee.update_user_permissions",
- "on_update": "erpnext.utilities.address_and_contact.set_default_role"
+ "on_update": "frappe.geo.address_and_contact.set_default_role"
},
("Sales Taxes and Charges Template", 'Price List'): {
"on_update": "erpnext.shopping_cart.doctype.shopping_cart_settings.shopping_cart_settings.validate_cart_settings"
diff --git a/erpnext/schools/doctype/discussion/__init__.py b/erpnext/hr/doctype/employee_loan/__init__.py
similarity index 100%
rename from erpnext/schools/doctype/discussion/__init__.py
rename to erpnext/hr/doctype/employee_loan/__init__.py
diff --git a/erpnext/hr/doctype/employee_loan/employee_loan.js b/erpnext/hr/doctype/employee_loan/employee_loan.js
new file mode 100644
index 0000000..a03dbda
--- /dev/null
+++ b/erpnext/hr/doctype/employee_loan/employee_loan.js
@@ -0,0 +1,88 @@
+// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Employee Loan', {
+ onload: function(frm) {
+ frm.set_query("employee_loan_application", function() {
+ return {
+ "filters": {
+ "employee": frm.doc.employee,
+ "docstatus": 1,
+ "status": "Approved"
+ }
+ };
+ });
+
+ $.each(["payment_account", "employee_loan_account"], function(i, field) {
+ frm.set_query(field, function() {
+ return {
+ "filters": {
+ "company": frm.doc.company,
+ "root_type": "Asset",
+ "is_group": 0
+ }
+ };
+ });
+ })
+ },
+
+ mode_of_payment: function(frm){
+ frappe.call({
+ method: "erpnext.accounts.doctype.sales_invoice.sales_invoice.get_bank_cash_account",
+ args: {
+ "mode_of_payment": frm.doc.mode_of_payment,
+ "company": frm.doc.company
+ },
+ callback: function(r, rt) {
+ if(r.message) {
+ frm.set_value("payment_account", r.message.account);
+ }
+ }
+ });
+ },
+
+ refresh: function(frm) {
+ frm.trigger("toggle_fields");
+
+ if(frm.doc.docstatus==1) {
+ frm.add_custom_button(__('Ledger'), function() {
+ frappe.route_options = {
+ "voucher_no": frm.doc.name,
+ "from_date": frm.doc.posting_date,
+ "to_date": frm.doc.posting_date,
+ "company": frm.doc.company,
+ group_by_voucher: 0
+ };
+ frappe.set_route("query-report", "General Ledger");
+ }, "fa fa-table");
+ }
+ },
+
+ employee_loan_application: function(frm) {
+ return frm.call({
+ method: "erpnext.hr.doctype.employee_loan.employee_loan.get_employee_loan_application",
+ args: {
+ "employee_loan_application": frm.doc.employee_loan_application
+ },
+ callback: function(r){
+ if(!r.exc && r.message) {
+ frm.set_value("loan_type", r.message.loan_type);
+ frm.set_value("loan_amount", r.message.loan_amount);
+ frm.set_value("repayment_method", r.message.repayment_method);
+ frm.set_value("monthly_repayment_amount", r.message.repayment_amount);
+ frm.set_value("repayment_periods", r.message.repayment_periods);
+ frm.set_value("rate_of_interest", r.message.rate_of_interest);
+ }
+ }
+ })
+ },
+
+ repayment_method: function(frm) {
+ frm.trigger("toggle_fields")
+ },
+
+ toggle_fields: function(frm) {
+ frm.toggle_enable("monthly_repayment_amount", frm.doc.repayment_method=="Repay Fixed Amount per Period")
+ frm.toggle_enable("repayment_periods", frm.doc.repayment_method=="Repay Over Number of Periods")
+ }
+});
diff --git a/erpnext/hr/doctype/employee_loan/employee_loan.json b/erpnext/hr/doctype/employee_loan/employee_loan.json
new file mode 100644
index 0000000..560515f
--- /dev/null
+++ b/erpnext/hr/doctype/employee_loan/employee_loan.json
@@ -0,0 +1,892 @@
+{
+ "allow_copy": 0,
+ "allow_import": 1,
+ "allow_rename": 0,
+ "autoname": "ELN.####",
+ "beta": 0,
+ "creation": "2016-12-02 10:11:49.673604",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "Document",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "employee",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 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": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "employee_name",
+ "fieldtype": "Read Only",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Employee Name",
+ "length": 0,
+ "no_copy": 0,
+ "options": "employee.employee_name",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "employee_loan_application",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Employee Loan Application",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Employee Loan Application",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "loan_type",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Loan Type",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Loan 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,
+ "unique": 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_list_view": 0,
+ "in_standard_filter": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "",
+ "fieldname": "posting_date",
+ "fieldtype": "Date",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Posting Date",
+ "length": 0,
+ "no_copy": 1,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 1,
+ "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": 1,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 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_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Status",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Loan Unpaid\nLoan Paid\nEMI in progress\nLoan Repaid",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "repay_from_salary",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Repay from Salary",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "section_break_8",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Loan Details",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "loan_amount",
+ "fieldtype": "Currency",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Loan 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,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "",
+ "fieldname": "rate_of_interest",
+ "fieldtype": "Percent",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Rate of Interest (%) / Year",
+ "length": 0,
+ "no_copy": 0,
+ "options": "loan_type.rate_of_interest",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "disbursement_date",
+ "fieldtype": "Date",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Disbursement 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,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "column_break_11",
+ "fieldtype": "Column Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "Repay Over Number of Periods",
+ "fieldname": "repayment_method",
+ "fieldtype": "Select",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Repayment Method",
+ "length": 0,
+ "no_copy": 0,
+ "options": "\nRepay Fixed Amount per Period\nRepay Over Number of Periods",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "",
+ "depends_on": "",
+ "fieldname": "repayment_periods",
+ "fieldtype": "Int",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Repayment Period in Months",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "",
+ "depends_on": "",
+ "fieldname": "monthly_repayment_amount",
+ "fieldtype": "Currency",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Repayment 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": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "account_info",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Account Info",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "mode_of_payment",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Mode of Payment",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Mode of Payment",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "payment_account",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Payment Account",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Account",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "column_break_9",
+ "fieldtype": "Column Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "employee_loan_account",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Employee Loan Account",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Account",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "section_break_15",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Repayment Schedule",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "repayment_schedule",
+ "fieldtype": "Table",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Repayment Schedule",
+ "length": 0,
+ "no_copy": 1,
+ "options": "Repayment Schedule",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "section_break_17",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Totals",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "0",
+ "fieldname": "total_payment",
+ "fieldtype": "Currency",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Total Payment",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "column_break_19",
+ "fieldtype": "Column Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "0",
+ "fieldname": "total_interest_payable",
+ "fieldtype": "Currency",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Total Interest Payable",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "amended_from",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Amended From",
+ "length": 0,
+ "no_copy": 1,
+ "options": "Employee Loan",
+ "permlevel": 0,
+ "print_hide": 1,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ }
+ ],
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "in_dialog": 0,
+ "is_submittable": 1,
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2017-01-17 07:13:10.704520",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Employee Loan",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "amend": 0,
+ "apply_user_permissions": 0,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "is_custom": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "HR Manager",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 1,
+ "write": 1
+ }
+ ],
+ "quick_entry": 0,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "search_fields": "posting_date",
+ "sort_field": "creation",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/employee_loan/employee_loan.py b/erpnext/hr/doctype/employee_loan/employee_loan.py
new file mode 100644
index 0000000..4d7a9f3
--- /dev/null
+++ b/erpnext/hr/doctype/employee_loan/employee_loan.py
@@ -0,0 +1,128 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe, math
+import erpnext
+from frappe import _
+from frappe.utils import flt, rounded, add_months, nowdate
+from erpnext.controllers.accounts_controller import AccountsController
+from erpnext.accounts.general_ledger import make_gl_entries
+
+class EmployeeLoan(AccountsController):
+ def validate(self):
+ check_repayment_method(self.repayment_method, self.loan_amount, self.monthly_repayment_amount, self.repayment_periods)
+ if not self.company:
+ self.company = erpnext.get_default_company()
+ if not self.posting_date:
+ self.posting_date = nowdate()
+ if self.loan_type and not self.rate_of_interest:
+ self.rate_of_interest = frappe.db.get_value("Loan Type", self.loan_type, "rate_of_interest")
+ if self.repayment_method == "Repay Over Number of Periods":
+ self.monthly_repayment_amount = get_monthly_repayment_amount(self.repayment_method, self.loan_amount, self.rate_of_interest, self.repayment_periods)
+
+ self.make_repayment_schedule()
+ self.set_repayment_period()
+ self.calculate_totals()
+
+ def on_submit(self):
+ self.make_gl_entries()
+
+ def on_cancel(self):
+ self.make_gl_entries()
+
+ def make_gl_entries(self):
+ gl_entries = []
+ # Gl entries for employee loan account
+ gl_entries.append(
+ self.get_gl_dict({
+ "account": self.employee_loan_account,
+ "party_type": "Employee",
+ "party": self.employee,
+ "debit": self.loan_amount,
+ "debit_in_account_currency": self.loan_amount
+ })
+ )
+ # Gl entries for payment account
+ gl_entries.append(
+ self.get_gl_dict({
+ "account": self.payment_account,
+ "credit": self.loan_amount,
+ "credit_in_account_currency": self.loan_amount
+ })
+ )
+ make_gl_entries(gl_entries, cancel=(self.docstatus == 2))
+
+ def make_repayment_schedule(self):
+ self.repayment_schedule = []
+ payment_date = self.disbursement_date
+ balance_amount = self.loan_amount
+
+ while(balance_amount > 0):
+ interest_amount = rounded(balance_amount * flt(self.rate_of_interest) / (12*100))
+ principal_amount = self.monthly_repayment_amount - interest_amount
+ balance_amount = rounded(balance_amount + interest_amount - self.monthly_repayment_amount)
+
+ if balance_amount < 0:
+ principal_amount += balance_amount
+ balance_amount = 0.0
+
+ total_payment = principal_amount + interest_amount
+
+ self.append("repayment_schedule", {
+ "payment_date": payment_date,
+ "principal_amount": principal_amount,
+ "interest_amount": interest_amount,
+ "total_payment": total_payment,
+ "balance_loan_amount": balance_amount
+ })
+
+ next_payment_date = add_months(payment_date, 1)
+ payment_date = next_payment_date
+
+ def set_repayment_period(self):
+ if self.repayment_method == "Repay Fixed Amount per Period":
+ repayment_periods = len(self.repayment_schedule)
+
+ self.repayment_periods = repayment_periods
+
+ def calculate_totals(self):
+ self.total_payment = 0
+ self.total_interest_payable = 0
+ for data in self.repayment_schedule:
+ self.total_payment += data.total_payment
+ self.total_interest_payable +=data.interest_amount
+
+ def update_status(self):
+ if self.disbursement_date:
+ self.status = "Loan Paid"
+ if len(self.repayment_schedule)>0:
+ self.status = "repayment in progress"
+
+def check_repayment_method(repayment_method, loan_amount, monthly_repayment_amount, repayment_periods):
+ if repayment_method == "Repay Over Number of Periods" and not repayment_periods:
+ frappe.throw(_("Please enter Repayment Periods"))
+
+ if repayment_method == "Repay Fixed Amount per Period":
+ if not monthly_repayment_amount:
+ frappe.throw(_("Please enter repayment Amount"))
+ if monthly_repayment_amount > loan_amount:
+ frappe.throw(_("Monthly Repayment Amount cannot be greater than Loan Amount"))
+
+def get_monthly_repayment_amount(repayment_method, loan_amount, rate_of_interest, repayment_periods):
+ if repayment_method == "Repay Over Number of Periods":
+ if rate_of_interest:
+ monthly_interest_rate = flt(rate_of_interest) / (12 *100)
+ monthly_repayment_amount = math.ceil((loan_amount * monthly_interest_rate *
+ (1 + monthly_interest_rate)**repayment_periods) \
+ / ((1 + monthly_interest_rate)**repayment_periods - 1))
+ else:
+ monthly_repayment_amount = math.ceil(flt(loan_amount) / repayment_periods)
+ return monthly_repayment_amount
+
+@frappe.whitelist()
+def get_employee_loan_application(employee_loan_application):
+ employee_loan = frappe.get_doc("Employee Loan Application", employee_loan_application)
+ if employee_loan:
+ return employee_loan
\ No newline at end of file
diff --git a/erpnext/hr/doctype/employee_loan/test_employee_loan.py b/erpnext/hr/doctype/employee_loan/test_employee_loan.py
new file mode 100644
index 0000000..c1c6ba2
--- /dev/null
+++ b/erpnext/hr/doctype/employee_loan/test_employee_loan.py
@@ -0,0 +1,68 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import erpnext
+import unittest
+from frappe.utils import nowdate
+from erpnext.hr.doctype.salary_structure.test_salary_structure import make_employee
+
+class TestEmployeeLoan(unittest.TestCase):
+ def setUp(self):
+ create_loan_type("Personal Loan", 500000, 8.4)
+ self.employee = make_employee("robert_loan@loan.com")
+ create_employee_loan(self.employee, "Personal Loan", 280000, "Repay Over Number of Periods", 20)
+
+ def test_employee_loan(self):
+ employee_loan = frappe.get_doc("Employee Loan", {"employee":self.employee})
+ self.assertEquals(employee_loan.monthly_repayment_amount, 15052)
+ self.assertEquals(employee_loan.total_interest_payable, 21034)
+ self.assertEquals(employee_loan.total_payment, 301034)
+
+ schedule = employee_loan.repayment_schedule
+
+ self.assertEquals(len(schedule), 20)
+
+ for idx, principal_amount, interest_amount, balance_loan_amount in [[3, 13369, 1683, 227079], [19, 14941, 105, 0], [17, 14740, 312, 29785]]:
+ self.assertEquals(schedule[idx].principal_amount, principal_amount)
+ self.assertEquals(schedule[idx].interest_amount, interest_amount)
+ self.assertEquals(schedule[idx].balance_loan_amount, balance_loan_amount)
+
+ employee_loan.repayment_method = "Repay Fixed Amount per Period"
+ employee_loan.monthly_repayment_amount = 14000
+ employee_loan.save()
+
+ self.assertEquals(len(employee_loan.repayment_schedule), 22)
+ self.assertEquals(employee_loan.total_interest_payable, 22712)
+ self.assertEquals(employee_loan.total_payment, 302712)
+
+
+def create_loan_type(loan_name, maximum_loan_amount, rate_of_interest):
+ if not frappe.db.get_value("Loan Type", loan_name):
+ frappe.get_doc({
+ "doctype": "Loan Type",
+ "loan_name": loan_name,
+ "maximum_loan_amount": maximum_loan_amount,
+ "rate_of_interest": rate_of_interest
+ }).insert()
+
+def create_employee_loan(employee, loan_type, loan_amount, repayment_method, repayment_periods):
+ if not frappe.db.get_value("Employee Loan", {"employee":employee}):
+ employee_loan = frappe.new_doc("Employee Loan")
+ employee_loan.update({
+ "employee": employee,
+ "loan_type": loan_type,
+ "loan_amount": loan_amount,
+ "repayment_method": repayment_method,
+ "repayment_periods": repayment_periods,
+ "disbursement_date": nowdate(),
+ "mode_of_payment": frappe.db.get_value('Mode of Payment', {'type': 'Cash'}, 'name'),
+ "payment_account": frappe.db.get_value('Account', {'account_type': 'Cash', 'company': erpnext.get_default_company(),'is_group':0}, "name"),
+ "employee_loan_account": frappe.db.get_value('Account', {'account_type': 'Cash', 'company': erpnext.get_default_company(),'is_group':0}, "name")
+ })
+ employee_loan.insert()
+ return employee_loan
+ else:
+ return frappe.get_doc("Employee Loan", {"employee":employee})
\ No newline at end of file
diff --git a/erpnext/schools/doctype/discussion/__init__.py b/erpnext/hr/doctype/employee_loan_application/__init__.py
similarity index 100%
copy from erpnext/schools/doctype/discussion/__init__.py
copy to erpnext/hr/doctype/employee_loan_application/__init__.py
diff --git a/erpnext/hr/doctype/employee_loan_application/employee_loan_application.js b/erpnext/hr/doctype/employee_loan_application/employee_loan_application.js
new file mode 100644
index 0000000..6958bea
--- /dev/null
+++ b/erpnext/hr/doctype/employee_loan_application/employee_loan_application.js
@@ -0,0 +1,16 @@
+// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Employee Loan Application', {
+ refresh: function(frm) {
+ frm.trigger("toggle_fields")
+ },
+ repayment_method: function(frm) {
+ frm.trigger("toggle_fields")
+ },
+
+ toggle_fields: function(frm) {
+ frm.toggle_enable("repayment_amount", frm.doc.repayment_method=="Repay Fixed Amount per Period")
+ frm.toggle_enable("repayment_periods", frm.doc.repayment_method=="Repay Over Number of Periods")
+ }
+});
diff --git a/erpnext/hr/doctype/employee_loan_application/employee_loan_application.json b/erpnext/hr/doctype/employee_loan_application/employee_loan_application.json
new file mode 100644
index 0000000..e30dc5a
--- /dev/null
+++ b/erpnext/hr/doctype/employee_loan_application/employee_loan_application.json
@@ -0,0 +1,681 @@
+{
+ "allow_copy": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "autoname": "ELA/.#####",
+ "beta": 0,
+ "creation": "2016-12-02 12:35:56.046811",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "Today",
+ "fieldname": "posting_date",
+ "fieldtype": "Date",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Posting Date",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "employee",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 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": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "employee_name",
+ "fieldtype": "Read Only",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 1,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Employee Name",
+ "length": 0,
+ "no_copy": 0,
+ "options": "employee.employee_name",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_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_list_view": 0,
+ "in_standard_filter": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 1,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "status",
+ "fieldtype": "Select",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Status",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Open\nApproved\nRejected",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 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": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "section_break_4",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Loan Info",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "loan_type",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Loan Type",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Loan 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,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "loan_amount",
+ "fieldtype": "Currency",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Loan 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,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "required_by_date",
+ "fieldtype": "Date",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Required by Date",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_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_list_view": 0,
+ "in_standard_filter": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_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_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Reason",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "repayment_info",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Repayment Info",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "repayment_method",
+ "fieldtype": "Select",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Repayment Method",
+ "length": 0,
+ "no_copy": 0,
+ "options": "\nRepay Fixed Amount per Period\nRepay Over Number of Periods",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "rate_of_interest",
+ "fieldtype": "Percent",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Rate of Interest",
+ "length": 0,
+ "no_copy": 0,
+ "options": "loan_type.rate_of_interest",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "total_payable_interest",
+ "fieldtype": "Currency",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Total Payable Interest",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "column_break_11",
+ "fieldtype": "Column Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "depends_on": "",
+ "fieldname": "repayment_amount",
+ "fieldtype": "Currency",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Repayment 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": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "depends_on": "",
+ "fieldname": "repayment_periods",
+ "fieldtype": "Int",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Repayment Period in Months",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "total_payable_amount",
+ "fieldtype": "Currency",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Total Payable 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,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "amended_from",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Amended From",
+ "length": 0,
+ "no_copy": 1,
+ "options": "Employee Loan Application",
+ "permlevel": 0,
+ "print_hide": 1,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ }
+ ],
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "in_dialog": 0,
+ "is_submittable": 1,
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2017-01-09 12:02:36.562577",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Employee Loan Application",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "amend": 0,
+ "apply_user_permissions": 0,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "is_custom": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "HR Manager",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 1,
+ "write": 1
+ },
+ {
+ "amend": 0,
+ "apply_user_permissions": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "is_custom": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Employee",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 1,
+ "write": 1
+ }
+ ],
+ "quick_entry": 0,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "search_fields": "employee, employee_name, loan_type, loan_amount",
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "timeline_field": "employee",
+ "title_field": "employee_name",
+ "track_changes": 1,
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/employee_loan_application/employee_loan_application.py b/erpnext/hr/doctype/employee_loan_application/employee_loan_application.py
new file mode 100644
index 0000000..15dbd4e
--- /dev/null
+++ b/erpnext/hr/doctype/employee_loan_application/employee_loan_application.py
@@ -0,0 +1,34 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe, math
+from frappe import _
+from frappe.utils import flt
+from frappe.model.document import Document
+
+from erpnext.hr.doctype.employee_loan.employee_loan import get_monthly_repayment_amount, check_repayment_method
+
+class EmployeeLoanApplication(Document):
+ def validate(self):
+ check_repayment_method(self.repayment_method, self.loan_amount, self.repayment_amount, self.repayment_periods)
+ self.validate_loan_amount()
+ self.get_repayment_details()
+
+ def validate_loan_amount(self):
+ maximum_loan_limit = frappe.db.get_value('Loan Type', self.loan_type, 'maximum_loan_amount')
+ if self.loan_amount > maximum_loan_limit:
+ frappe.throw(_("Loan Amount cannot exceed Maximum Loan Amount of {0}").format(maximum_loan_limit))
+
+ def get_repayment_details(self):
+ if self.repayment_method == "Repay Over Number of Periods":
+ self.repayment_amount = get_monthly_repayment_amount(self.repayment_method, self.loan_amount, self.rate_of_interest, self.repayment_periods)
+
+ if self.repayment_method == "Repay Fixed Amount per Period":
+ monthly_interest_rate = flt(self.rate_of_interest) / (12 *100)
+ self.repayment_periods = math.ceil((math.log(self.repayment_amount) - math.log(self.repayment_amount - \
+ (self.loan_amount*monthly_interest_rate)))/(math.log(1+monthly_interest_rate)))
+
+ self.total_payable_amount = self.repayment_amount * self.repayment_periods
+ self.total_payable_interest = self.total_payable_amount - self.loan_amount
\ No newline at end of file
diff --git a/erpnext/hr/doctype/employee_loan_application/test_employee_loan_application.py b/erpnext/hr/doctype/employee_loan_application/test_employee_loan_application.py
new file mode 100644
index 0000000..1d157d6
--- /dev/null
+++ b/erpnext/hr/doctype/employee_loan_application/test_employee_loan_application.py
@@ -0,0 +1,51 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+from erpnext.hr.doctype.salary_structure.test_salary_structure import make_employee
+
+class TestEmployeeLoanApplication(unittest.TestCase):
+ def setUp(self):
+ self.create_loan_type()
+ self.employee = make_employee("kate_loan@loan.com")
+ self.create_loan_application()
+
+ def create_loan_type(self):
+ if not frappe.db.get_value("Loan Type", "Home Loan"):
+ frappe.get_doc({
+ "doctype": "Loan Type",
+ "loan_name": "Home Loan",
+ "maximum_loan_amount": 500000,
+ "rate_of_interest": 9.2
+ }).insert()
+
+ def create_loan_application(self):
+ if not frappe.db.get_value("Employee Loan Application", {"employee":self.employee}, "name"):
+ loan_application = frappe.new_doc("Employee Loan Application")
+ loan_application.update({
+ "employee": self.employee,
+ "loan_type": "Home Loan",
+ "rate_of_interest": 9.2,
+ "loan_amount": 250000,
+ "repayment_method": "Repay Over Number of Periods",
+ "repayment_periods": 24
+ })
+ loan_application.insert()
+
+
+ def test_loan_totals(self):
+ loan_application = frappe.get_doc("Employee Loan Application", {"employee":self.employee})
+ self.assertEquals(loan_application.repayment_amount, 11445)
+ self.assertEquals(loan_application.total_payable_interest, 24680)
+ self.assertEquals(loan_application.total_payable_amount, 274680)
+
+ loan_application.repayment_method = "Repay Fixed Amount per Period"
+ loan_application.repayment_amount = 15000
+ loan_application.save()
+
+ self.assertEquals(loan_application.repayment_periods, 18)
+ self.assertEquals(loan_application.total_payable_interest, 20000)
+ self.assertEquals(loan_application.total_payable_amount, 270000)
\ No newline at end of file
diff --git a/erpnext/schools/doctype/topic/__init__.py b/erpnext/hr/doctype/loan_type/__init__.py
similarity index 100%
rename from erpnext/schools/doctype/topic/__init__.py
rename to erpnext/hr/doctype/loan_type/__init__.py
diff --git a/erpnext/hr/doctype/loan_type/loan_type.js b/erpnext/hr/doctype/loan_type/loan_type.js
new file mode 100644
index 0000000..72f5775
--- /dev/null
+++ b/erpnext/hr/doctype/loan_type/loan_type.js
@@ -0,0 +1,7 @@
+// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Loan Type', {
+ refresh: function(frm) {
+ }
+});
diff --git a/erpnext/hr/doctype/loan_type/loan_type.json b/erpnext/hr/doctype/loan_type/loan_type.json
new file mode 100644
index 0000000..f9441ea
--- /dev/null
+++ b/erpnext/hr/doctype/loan_type/loan_type.json
@@ -0,0 +1,230 @@
+{
+ "allow_copy": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "autoname": "field:loan_name",
+ "beta": 0,
+ "creation": "2016-12-02 10:41:40.732843",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "loan_name",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Loan 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,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "maximum_loan_amount",
+ "fieldtype": "Currency",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Maximum Loan 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": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "rate_of_interest",
+ "fieldtype": "Percent",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Rate of Interest (%) Yearly",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_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_list_view": 0,
+ "in_standard_filter": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "",
+ "fieldname": "disabled",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Disabled",
+ "length": 0,
+ "no_copy": 0,
+ "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": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "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_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,
+ "unique": 0
+ }
+ ],
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "in_dialog": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2016-12-29 15:54:17.716285",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Loan Type",
+ "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,
+ "is_custom": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "HR Manager",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ }
+ ],
+ "quick_entry": 0,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/loan_type/loan_type.py b/erpnext/hr/doctype/loan_type/loan_type.py
new file mode 100644
index 0000000..2714e20
--- /dev/null
+++ b/erpnext/hr/doctype/loan_type/loan_type.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2015, 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 LoanType(Document):
+ pass
diff --git a/erpnext/hr/doctype/loan_type/test_loan_type.py b/erpnext/hr/doctype/loan_type/test_loan_type.py
new file mode 100644
index 0000000..078e11e
--- /dev/null
+++ b/erpnext/hr/doctype/loan_type/test_loan_type.py
@@ -0,0 +1,12 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+
+# test_records = frappe.get_test_records('Loan Type')
+
+class TestLoanType(unittest.TestCase):
+ pass
diff --git a/erpnext/schools/doctype/announcement/__init__.py b/erpnext/hr/doctype/repayment_schedule/__init__.py
similarity index 100%
rename from erpnext/schools/doctype/announcement/__init__.py
rename to erpnext/hr/doctype/repayment_schedule/__init__.py
diff --git a/erpnext/hr/doctype/repayment_schedule/repayment_schedule.json b/erpnext/hr/doctype/repayment_schedule/repayment_schedule.json
new file mode 100644
index 0000000..3a0dfd3
--- /dev/null
+++ b/erpnext/hr/doctype/repayment_schedule/repayment_schedule.json
@@ -0,0 +1,179 @@
+{
+ "allow_copy": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "beta": 0,
+ "creation": "2016-12-20 15:32:25.078334",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 2,
+ "fieldname": "payment_date",
+ "fieldtype": "Date",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Payment Date",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 2,
+ "fieldname": "principal_amount",
+ "fieldtype": "Currency",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Principal Amount",
+ "length": 0,
+ "no_copy": 1,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 2,
+ "fieldname": "interest_amount",
+ "fieldtype": "Currency",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Interest Amount",
+ "length": 0,
+ "no_copy": 1,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 2,
+ "fieldname": "total_payment",
+ "fieldtype": "Currency",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Total Payment",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 2,
+ "fieldname": "balance_loan_amount",
+ "fieldtype": "Currency",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Balance Loan Amount",
+ "length": 0,
+ "no_copy": 1,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ }
+ ],
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "in_dialog": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 1,
+ "max_attachments": 0,
+ "modified": "2017-01-09 12:00:10.818772",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Repayment Schedule",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/repayment_schedule/repayment_schedule.py b/erpnext/hr/doctype/repayment_schedule/repayment_schedule.py
new file mode 100644
index 0000000..8abee5e
--- /dev/null
+++ b/erpnext/hr/doctype/repayment_schedule/repayment_schedule.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2015, 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 RepaymentSchedule(Document):
+ pass
diff --git a/erpnext/hr/doctype/salary_slip/salary_slip.js b/erpnext/hr/doctype/salary_slip/salary_slip.js
index 8b0dd16..0262259 100644
--- a/erpnext/hr/doctype/salary_slip/salary_slip.js
+++ b/erpnext/hr/doctype/salary_slip/salary_slip.js
@@ -110,6 +110,7 @@
calculate_earning_total(doc, dt, dn, true);
calculate_ded_total(doc, dt, dn, true);
calculate_net_pay(doc, dt, dn);
+ refresh_many(['amount','gross_pay', 'rounded_total', 'net_pay', 'loan_repayment']);
};
// Calculate earning total
diff --git a/erpnext/hr/doctype/salary_slip/salary_slip.json b/erpnext/hr/doctype/salary_slip/salary_slip.json
index e558d73..7d5dbe9 100644
--- a/erpnext/hr/doctype/salary_slip/salary_slip.json
+++ b/erpnext/hr/doctype/salary_slip/salary_slip.json
@@ -1266,7 +1266,35 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "description": "Gross Pay + Arrear Amount +Encashment Amount - Total Deduction",
+ "fieldname": "loan_repayment",
+ "fieldtype": "Currency",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Loan Repayment",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "description": "Gross Pay + Arrear Amount + Encashment Amount - Total Deduction - Loan Repayment",
"fieldname": "net_pay",
"fieldtype": "Currency",
"hidden": 0,
@@ -1362,7 +1390,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2016-12-14 08:26:31.400930",
+ "modified": "2017-01-09 12:37:03.802501",
"modified_by": "Administrator",
"module": "HR",
"name": "Salary Slip",
@@ -1413,7 +1441,7 @@
},
{
"amend": 0,
- "apply_user_permissions": 0,
+ "apply_user_permissions": 1,
"cancel": 0,
"create": 0,
"delete": 0,
@@ -1430,6 +1458,7 @@
"set_user_permissions": 0,
"share": 0,
"submit": 0,
+ "user_permission_doctypes": "[\"Employee\"]",
"write": 0
}
],
@@ -1440,5 +1469,6 @@
"sort_order": "DESC",
"timeline_field": "employee",
"title_field": "employee_name",
+ "track_changes": 0,
"track_seen": 0
}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/salary_slip/salary_slip.py b/erpnext/hr/doctype/salary_slip/salary_slip.py
index eeec6e8..de205e3 100644
--- a/erpnext/hr/doctype/salary_slip/salary_slip.py
+++ b/erpnext/hr/doctype/salary_slip/salary_slip.py
@@ -329,11 +329,21 @@
self.sum_components('earnings', 'gross_pay')
self.sum_components('deductions', 'total_deduction')
+
+ self.set_loan_repayment()
- self.net_pay = flt(self.gross_pay) - flt(self.total_deduction)
+ self.net_pay = flt(self.gross_pay) - (flt(self.total_deduction) + flt(self.loan_repayment))
self.rounded_total = rounded(self.net_pay,
self.precision("net_pay") if disable_rounded_total else 0)
+ def set_loan_repayment(self):
+ employee_loan = frappe.db.sql("""select sum(total_payment) as loan_repayment from `tabRepayment Schedule`
+ where payment_date between %s and %s and parent in (select name from `tabEmployee Loan`
+ where employee = %s and repay_from_salary = 1 and docstatus = 1)""",
+ (self.start_date, self.end_date, self.employee), as_dict=True)
+ if employee_loan:
+ self.loan_repayment = employee_loan[0].loan_repayment
+
def on_submit(self):
if self.net_pay < 0:
frappe.throw(_("Net Pay cannot be less than 0"))
diff --git a/erpnext/hr/doctype/salary_slip/test_salary_slip.py b/erpnext/hr/doctype/salary_slip/test_salary_slip.py
index 3d119c3..9999f1e 100644
--- a/erpnext/hr/doctype/salary_slip/test_salary_slip.py
+++ b/erpnext/hr/doctype/salary_slip/test_salary_slip.py
@@ -7,7 +7,7 @@
import erpnext
import calendar
from erpnext.accounts.utils import get_fiscal_year
-from frappe.utils import getdate, nowdate, add_days
+from frappe.utils import getdate, nowdate, add_days, flt
from erpnext.hr.doctype.salary_structure.salary_structure import make_salary_slip
from erpnext.hr.doctype.process_payroll.test_process_payroll import get_salary_component_account
from erpnext.hr.doctype.process_payroll.process_payroll import get_month_details
@@ -24,7 +24,6 @@
frappe.db.set_value("Company", erpnext.get_default_company(), "default_holiday_list", "Salary Slip Test Holiday List")
-
def tearDown(self):
frappe.db.set_value("HR Settings", None, "include_holidays_in_total_working_days", 0)
frappe.set_user("Administrator")
@@ -40,12 +39,12 @@
self.assertEquals(ss.total_working_days, no_of_days[0])
self.assertEquals(ss.payment_days, no_of_days[0])
- self.assertEquals(ss.earnings[0].amount, 5000)
+ self.assertEquals(ss.earnings[0].amount, 25000)
self.assertEquals(ss.earnings[1].amount, 3000)
self.assertEquals(ss.deductions[0].amount, 5000)
- self.assertEquals(ss.deductions[1].amount, 2500)
- self.assertEquals(ss.gross_pay, 10500)
- self.assertEquals(ss.net_pay, 3000)
+ self.assertEquals(ss.deductions[1].amount, 5000)
+ self.assertEquals(ss.gross_pay, 40500)
+ self.assertEquals(ss.net_pay, 29918)
def test_salary_slip_with_holidays_excluded(self):
no_of_days = self.get_no_of_days()
@@ -58,13 +57,13 @@
self.assertEquals(ss.total_working_days, no_of_days[0] - no_of_days[1])
self.assertEquals(ss.payment_days, no_of_days[0] - no_of_days[1])
- self.assertEquals(ss.earnings[0].amount, 5000)
- self.assertEquals(ss.earnings[0].default_amount, 5000)
+ self.assertEquals(ss.earnings[0].amount, 25000)
+ self.assertEquals(ss.earnings[0].default_amount, 25000)
self.assertEquals(ss.earnings[1].amount, 3000)
self.assertEquals(ss.deductions[0].amount, 5000)
- self.assertEquals(ss.deductions[1].amount, 2500)
- self.assertEquals(ss.gross_pay, 10500)
- self.assertEquals(ss.net_pay, 3000)
+ self.assertEquals(ss.deductions[1].amount, 5000)
+ self.assertEquals(ss.gross_pay, 40500)
+ self.assertEquals(ss.net_pay, 29918)
def test_payment_days(self):
no_of_days = self.get_no_of_days()
@@ -130,9 +129,23 @@
ss = frappe.get_doc("Salary Slip",
self.make_employee_salary_slip("test_employee@salary.com", "Monthly"))
ss.submit()
+
email_queue = frappe.db.sql("""select name from `tabEmail Queue`""")
self.assertTrue(email_queue)
+ def test_loan_repayment_salary_slip(self):
+ from erpnext.hr.doctype.employee_loan.test_employee_loan import create_loan_type, create_employee_loan
+ employee = self.make_employee("test_employee@salary.com")
+ create_loan_type("Car Loan", 500000, 6.4)
+ employee_loan = create_employee_loan(employee, "Car Loan", 11000, "Repay Over Number of Periods", 20)
+ employee_loan.repay_from_salary = 1
+ employee_loan.submit()
+ ss = frappe.get_doc("Salary Slip",
+ self.make_employee_salary_slip("test_employee@salary.com", "Monthly"))
+ ss.submit()
+ self.assertEquals(ss.loan_repayment, 582)
+ self.assertEquals(ss.net_pay, (flt(ss.gross_pay) - (flt(ss.total_deduction) + flt(ss.loan_repayment))))
+
def test_payroll_frequency(self):
fiscal_year = get_fiscal_year(nowdate(), company="_Test Company")[0]
month = "%02d" % getdate(nowdate()).month
@@ -167,7 +180,7 @@
}).insert()
if not frappe.db.get_value("Employee", {"user_id": user}):
- frappe.get_doc({
+ employee = frappe.get_doc({
"doctype": "Employee",
"naming_series": "EMP-",
"employee_name": user,
@@ -183,6 +196,9 @@
"status": "Active",
"employment_type": "Intern"
}).insert()
+ return employee.name
+ else:
+ return frappe.get_value("Employee", {"employee_name":user}, "name")
def make_holiday_list(self):
fiscal_year = get_fiscal_year(nowdate(), company="_Test Company")
@@ -278,7 +294,7 @@
def get_employee_details(employee):
return [{"employee": employee,
- "base": 25000,
+ "base": 50000,
"variable": 5000
}
]
@@ -289,14 +305,14 @@
"salary_component": 'Basic Salary',
"abbr":'BS',
"condition": 'base > 10000',
- "formula": 'base*.2',
+ "formula": 'base*.5',
"idx": 1
},
{
"salary_component": 'Basic Salary',
"abbr":'BS',
"condition": 'base < 10000',
- "formula": 'base*.1',
+ "formula": 'base*.2',
"idx": 2
},
{
@@ -320,13 +336,13 @@
"salary_component": 'Professional Tax',
"abbr":'PT',
"condition": 'base > 10000',
- "formula": 'base*.2',
+ "formula": 'base*.1',
"idx": 1
},
{
"salary_component": 'TDS',
"abbr":'T',
- "formula": 'base*.5',
+ "formula": 'base*.1',
"idx": 2
},
{
diff --git a/erpnext/hr/doctype/salary_structure/test_salary_structure.py b/erpnext/hr/doctype/salary_structure/test_salary_structure.py
index fe88d9a..36e50d3 100644
--- a/erpnext/hr/doctype/salary_structure/test_salary_structure.py
+++ b/erpnext/hr/doctype/salary_structure/test_salary_structure.py
@@ -19,8 +19,8 @@
frappe.db.set_value("Company", erpnext.get_default_company(), "default_holiday_list", "Salary Structure Test Holiday List")
make_earning_salary_component(["Basic Salary", "Allowance", "HRA"])
make_deduction_salary_component(["Professional Tax", "TDS"])
- self.make_employee("test_employee@salary.com")
- self.make_employee("test_employee_2@salary.com")
+ make_employee("test_employee@salary.com")
+ make_employee("test_employee_2@salary.com")
def make_holiday_list(self):
if not frappe.db.get_value("Holiday List", "Salary Structure Test Holiday List"):
@@ -33,37 +33,6 @@
}).insert()
holiday_list.get_weekly_off_dates()
holiday_list.save()
-
- def make_employee(self, user):
- if not frappe.db.get_value("User", user):
- frappe.get_doc({
- "doctype": "User",
- "email": user,
- "first_name": user,
- "new_password": "password",
- "user_roles": [{"doctype": "UserRole", "role": "Employee"}]
- }).insert()
-
-
- if not frappe.db.get_value("Employee", {"user_id": user}):
- emp = frappe.get_doc({
- "doctype": "Employee",
- "naming_series": "EMP-",
- "employee_name": user,
- "company": erpnext.get_default_company(),
- "user_id": user,
- "date_of_birth": "1990-05-08",
- "date_of_joining": "2013-01-01",
- "relieving_date": "",
- "department": frappe.get_all("Department", fields="name")[0].name,
- "gender": "Female",
- "company_email": user,
- "status": "Active",
- "employment_type": "Intern"
- }).insert()
- return emp.name
- else:
- return frappe.get_value("Employee", {"employee_name":user}, "name")
def test_amount_totals(self):
sal_slip = frappe.get_value("Salary Slip", {"employee_name":"test_employee@salary.com"})
@@ -76,6 +45,36 @@
self.assertEquals(sal_slip.get("total_deduction"), 7500)
self.assertEquals(sal_slip.get("net_pay"), 7500)
+def make_employee(user):
+ if not frappe.db.get_value("User", user):
+ frappe.get_doc({
+ "doctype": "User",
+ "email": user,
+ "first_name": user,
+ "new_password": "password",
+ "user_roles": [{"doctype": "UserRole", "role": "Employee"}]
+ }).insert()
+
+
+ if not frappe.db.get_value("Employee", {"user_id": user}):
+ emp = frappe.get_doc({
+ "doctype": "Employee",
+ "naming_series": "EMP-",
+ "employee_name": user,
+ "company": erpnext.get_default_company(),
+ "user_id": user,
+ "date_of_birth": "1990-05-08",
+ "date_of_joining": "2013-01-01",
+ "relieving_date": "",
+ "department": frappe.get_all("Department", fields="name")[0].name,
+ "gender": "Female",
+ "company_email": user,
+ "status": "Active",
+ "employment_type": "Intern"
+ }).insert()
+ return emp.name
+ else:
+ return frappe.get_value("Employee", {"employee_name":user}, "name")
def make_salary_slip_from_salary_structure(employee):
sal_struct = make_salary_structure('Salary Structure Sample')
diff --git a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py
index 7f1c442..8105e1a 100644
--- a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py
+++ b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py
@@ -30,28 +30,31 @@
return columns
def get_data(filters, leave_types):
-
+ user = frappe.session.user
allocation_records_based_on_to_date = get_leave_allocation_records(filters.to_date)
active_employees = frappe.get_all("Employee",
filters = { "status": "Active", "company": filters.company},
- fields = ["name", "employee_name", "department"])
+ fields = ["name", "employee_name", "department", "user_id"])
data = []
for employee in active_employees:
- row = [employee.name, employee.employee_name, employee.department]
+ leave_approvers = [l.leave_approver for l in frappe.db.sql("""select leave_approver from `tabEmployee Leave Approver` where parent = %s""",
+ (employee.name),as_dict=True)]
+ if (len(leave_approvers) and user in leave_approvers) or (user in ["Administrator", employee.user_id]) or ("HR Manager" in frappe.get_roles(user)):
+ row = [employee.name, employee.employee_name, employee.department]
- for leave_type in leave_types:
- # leaves taken
- leaves_taken = get_approved_leaves_for_period(employee.name, leave_type,
- filters.from_date, filters.to_date)
+ for leave_type in leave_types:
+ # leaves taken
+ leaves_taken = get_approved_leaves_for_period(employee.name, leave_type,
+ filters.from_date, filters.to_date)
- # closing balance
- closing = get_leave_balance_on(employee.name, leave_type, filters.to_date,
- allocation_records_based_on_to_date.get(employee.name, frappe._dict()))
+ # closing balance
+ closing = get_leave_balance_on(employee.name, leave_type, filters.to_date,
+ allocation_records_based_on_to_date.get(employee.name, frappe._dict()))
- row += [leaves_taken, closing]
+ row += [leaves_taken, closing]
- data.append(row)
+ data.append(row)
return data
\ No newline at end of file
diff --git a/erpnext/patches/v7_0/set_portal_settings.py b/erpnext/patches/v7_0/set_portal_settings.py
index f7ee205..54a17dc 100644
--- a/erpnext/patches/v7_0/set_portal_settings.py
+++ b/erpnext/patches/v7_0/set_portal_settings.py
@@ -8,7 +8,7 @@
def execute():
frappe.reload_doctype('Role')
- for dt in ("assessment", "announcement", "course", "fees"):
+ for dt in ("assessment", "course", "fees"):
frappe.reload_doc("schools", "doctype", dt)
frappe.reload_doc('website', 'doctype', 'portal_menu_item')
diff --git a/erpnext/patches/v7_2/update_assessment_modules.py b/erpnext/patches/v7_2/update_assessment_modules.py
index 2ea9f6e..ac04294 100644
--- a/erpnext/patches/v7_2/update_assessment_modules.py
+++ b/erpnext/patches/v7_2/update_assessment_modules.py
@@ -20,7 +20,8 @@
frappe.reload_doc("schools", "doctype", "evaluation_criteria")
- for assessment in frappe.get_all("Assessment Plan", fields=["name", "grading_scale"]):
+ for assessment in frappe.get_all("Assessment Plan", fields=["name", "grading_scale"], filters = [["docstatus", "!=", 2 ]]):
+ print assessment
for stud_result in frappe.db.sql("select * from `tabAssessment Result` where parent= %s", assessment.name, as_dict=True):
if stud_result.result:
assessment_result = frappe.new_doc("Assessment Result")
@@ -30,6 +31,7 @@
assessment_result.grading_scale = assessment.grading_scale
assessment_result.total_score = stud_result.result
assessment_result.flags.ignore_validate = True
+ assessment_result.flags.ignore_mandatory = True
assessment_result.save()
frappe.db.sql("""delete from `tabAssessment Result` where parent != '' or parent is not null""")
\ No newline at end of file
diff --git a/erpnext/projects/doctype/task/task.json b/erpnext/projects/doctype/task/task.json
index 9cd2aa8..7433222 100644
--- a/erpnext/projects/doctype/task/task.json
+++ b/erpnext/projects/doctype/task/task.json
@@ -1,7 +1,7 @@
{
"allow_copy": 0,
"allow_import": 1,
- "allow_rename": 0,
+ "allow_rename": 1,
"autoname": "TASK.#####",
"beta": 0,
"creation": "2013-01-29 19:25:50",
@@ -944,7 +944,7 @@
"istable": 0,
"max_attachments": 5,
"menu_index": 0,
- "modified": "2016-11-07 05:12:23.294476",
+ "modified": "2017-01-27 01:26:24.985167",
"modified_by": "Administrator",
"module": "Projects",
"name": "Task",
@@ -960,7 +960,6 @@
"export": 0,
"if_owner": 0,
"import": 0,
- "is_custom": 0,
"permlevel": 0,
"print": 1,
"read": 1,
@@ -979,5 +978,6 @@
"sort_order": "DESC",
"timeline_field": "project",
"title_field": "subject",
+ "track_changes": 0,
"track_seen": 1
}
\ No newline at end of file
diff --git a/erpnext/public/js/financial_statements.js b/erpnext/public/js/financial_statements.js
index 16385e1..7115205 100644
--- a/erpnext/public/js/financial_statements.js
+++ b/erpnext/public/js/financial_statements.js
@@ -31,7 +31,8 @@
"account": data.account,
"company": frappe.query_report_filters_by_name.company.get_value(),
"from_date": data.from_date || data.year_start_date,
- "to_date": data.to_date || data.year_end_date
+ "to_date": data.to_date || data.year_end_date,
+ "project": $.grep(frappe.query_report.filters, function(e){ return e.df.fieldname == 'project'; })[0].$input.val()
};
frappe.set_route("query-report", "General Ledger");
},
diff --git a/erpnext/public/js/queries.js b/erpnext/public/js/queries.js
index 1141f99..f3167bb 100644
--- a/erpnext/public/js/queries.js
+++ b/erpnext/public/js/queries.js
@@ -36,7 +36,7 @@
customer_filter: function(doc) {
if(!doc.customer) {
- frappe.throw(__("Please set {0}", __(frappe.meta.get_label(doc.doctype, "customer", doc.name))));
+ frappe.throw(__("Please set {0}", [__(frappe.meta.get_label(doc.doctype, "customer", doc.name))]));
}
return { filters: { customer: doc.customer } };
@@ -45,8 +45,8 @@
contact_query: function(doc) {
if(frappe.dynamic_link) {
if(!doc[frappe.dynamic_link.fieldname]) {
- frappe.throw(__("Please set {0}", __(frappe.meta.get_label(doc.doctype,
- frappe.dynamic_link.fieldname, doc.name))));
+ frappe.throw(__("Please set {0}",
+ [__(frappe.meta.get_label(doc.doctype, frappe.dynamic_link.fieldname, doc.name))]));
}
return {
@@ -58,8 +58,8 @@
address_query: function(doc) {
if(frappe.dynamic_link) {
if(!doc[frappe.dynamic_link.fieldname]) {
- frappe.throw(__("Please set {0}", __(frappe.meta.get_label(doc.doctype,
- frappe.dynamic_link.fieldname, doc.name))));
+ frappe.throw(__("Please set {0}",
+ [__(frappe.meta.get_label(doc.doctype, frappe.dynamic_link.fieldname, doc.name))]));
}
return {
@@ -68,9 +68,16 @@
}
},
+ company_address_query: function(doc) {
+ return {
+ query: 'frappe.geo.doctype.address.address.address_query',
+ filters: { is_your_company_address: 1, link_doctype: 'Company', link_name: doc.company || '' }
+ };
+ },
+
supplier_filter: function(doc) {
if(!doc.supplier) {
- frappe.throw(__("Please set {0}", __(frappe.meta.get_label(doc.doctype, "supplier", doc.name))));
+ frappe.throw(__("Please set {0}", [__(frappe.meta.get_label(doc.doctype, "supplier", doc.name))]));
}
return { filters: { supplier: doc.supplier } };
@@ -78,8 +85,8 @@
lead_filter: function(doc) {
if(!doc.lead) {
- frappe.throw(__("Please specify a") + " " +
- __(frappe.meta.get_label(doc.doctype, "lead", doc.name)));
+ frappe.throw(__("Please specify a {0}",
+ [__(frappe.meta.get_label(doc.doctype, "lead", doc.name))]));
}
return { filters: { lead: doc.lead } };
diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js
index 74e9fb6..551ea51 100644
--- a/erpnext/public/js/utils.js
+++ b/erpnext/public/js/utils.js
@@ -82,32 +82,6 @@
$.extend(erpnext.utils, {
- clear_address_and_contact: function(frm) {
- $(frm.fields_dict['address_html'].wrapper).html("");
- frm.fields_dict['contact_html'] && $(frm.fields_dict['contact_html'].wrapper).html("");
- },
-
- render_address_and_contact: function(frm) {
- // render address
- $(frm.fields_dict['address_html'].wrapper)
- .html(frappe.render_template("address_list",
- cur_frm.doc.__onload))
- .find(".btn-address").on("click", function() {
- frappe.new_doc("Address");
- });
-
- // render contact
- if(frm.fields_dict['contact_html']) {
- $(frm.fields_dict['contact_html'].wrapper)
- .html(frappe.render_template("contact_list",
- cur_frm.doc.__onload))
- .find(".btn-contact").on("click", function() {
- frappe.new_doc("Contact");
- }
- );
- }
- },
-
set_party_dashboard_indicators: function(frm) {
if(frm.doc.__onload && frm.doc.__onload.dashboard_info) {
var info = frm.doc.__onload.dashboard_info;
diff --git a/erpnext/schools/doctype/announcement/announcement.js b/erpnext/schools/doctype/announcement/announcement.js
deleted file mode 100644
index 5b1d1c0..0000000
--- a/erpnext/schools/doctype/announcement/announcement.js
+++ /dev/null
@@ -1,9 +0,0 @@
-// Copyright (c) 2016, Frappe and contributors
-// For license information, please see license.txt
-
-frappe.ui.form.on('Announcement', {
- onload: function(frm) {
- frm.add_fetch('instructor', 'instructor_name' , 'posted_by');
- }
-});
-
diff --git a/erpnext/schools/doctype/announcement/announcement.json b/erpnext/schools/doctype/announcement/announcement.json
deleted file mode 100644
index 831b71f..0000000
--- a/erpnext/schools/doctype/announcement/announcement.json
+++ /dev/null
@@ -1,315 +0,0 @@
-{
- "allow_copy": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "autoname": "announcement.#####",
- "beta": 0,
- "creation": "2016-06-23 05:37:33.996289",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Document",
- "editable_grid": 0,
- "fields": [
- {
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "default": "",
- "fieldname": "receiver",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 1,
- "label": "Receiver",
- "length": 0,
- "no_copy": 0,
- "options": "Student\nStudent Group\nAll Students",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 1,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "fieldname": "instructor",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 0,
- "label": "Instructor",
- "length": 0,
- "no_copy": 0,
- "options": "Instructor",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "fieldname": "column_break_3",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "depends_on": "eval: doc.receiver == \"Student\"",
- "fieldname": "student",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 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,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 1,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "depends_on": "eval: doc.receiver == \"Student Group\"",
- "fieldname": "student_group",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 1,
- "label": "Student Group",
- "length": 0,
- "no_copy": 0,
- "options": "Student Group",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 1,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "fieldname": "posted_by",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 0,
- "label": "Posted By",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "fieldname": "section_break_5",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "fieldname": "subject",
- "fieldtype": "Small Text",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 0,
- "label": "Subject",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "fieldname": "description",
- "fieldtype": "Text Editor",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 0,
- "label": "Description",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "fieldname": "amended_from",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 0,
- "label": "Amended From",
- "length": 0,
- "no_copy": 1,
- "options": "Announcement",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- }
- ],
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "in_dialog": 0,
- "is_submittable": 1,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2016-07-21 06:30:12.825629",
- "modified_by": "r@r.com",
- "module": "Schools",
- "name": "Announcement",
- "name_case": "",
- "owner": "demo@erpnext.com",
- "permissions": [
- {
- "amend": 1,
- "apply_user_permissions": 0,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Academics User",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
- "write": 1
- }
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "title_field": "subject",
- "track_seen": 1
-}
\ No newline at end of file
diff --git a/erpnext/schools/doctype/announcement/announcement.py b/erpnext/schools/doctype/announcement/announcement.py
deleted file mode 100644
index 1a3fe75d..0000000
--- a/erpnext/schools/doctype/announcement/announcement.py
+++ /dev/null
@@ -1,75 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2015, Frappe and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-import frappe
-from frappe.model.document import Document
-from frappe import _
-
-class Announcement(Document):
- def validate(self):
- self.validate_receiver()
- self.set_posted_by()
-
- def validate_receiver(self):
- if self.receiver == "Student":
- if not self.student:
- frappe.throw(_("Please select a Student"))
- self.student_group = None
- elif self.receiver == "Student Group":
- if not self.student_group:
- frappe.throw(_("Please select a Student Group"))
- self.student = None
- else:
- self.student_group = None
- self.student = None
-
- def set_posted_by(self):
- if self.instructor:
- self.posted_by = frappe.db.get_value("Instructor", self.instructor, "instructor_name")
- else:
- self.posted_by = frappe.session.user
-
-
-
-
-def get_message_list(doctype, txt, filters, limit_start, limit_page_length=20):
- user = frappe.session.user
- student = frappe.db.sql("select name from `tabStudent` where student_email_id= %s", user)
- if student:
- sg_list = frappe.db.sql("""select parent from `tabStudent Group Student` as sgs
- where sgs.student = %s """,(student))
-
- data = frappe.db.sql("""select name, receiver, subject, description, posted_by, modified,
- student, student_group
- from `tabAnnouncement` as announce
- where (announce.receiver = "Student" and announce.student = %s)
- or (announce.receiver = "Student Group" and announce.student_group in %s)
- or announce.receiver = "All Students"
- and announce.docstatus = 1
- order by announce.idx asc limit {0} , {1}"""
- .format(limit_start, limit_page_length), (student,sg_list), as_dict = True)
-
- for announcement in data:
- try:
- num_attachments = frappe.db.sql(""" select count(file_url) from tabFile as file
- where file.attached_to_name=%s
- and file.attached_to_doctype=%s""",(announcement.name,"Announcement"))
-
- except IOError or frappe.DoesNotExistError:
- pass
- frappe.local.message_log.pop()
-
- announcement.num_attachments = num_attachments[0][0]
-
- return data
-
-def get_list_context(context=None):
- return {
- "show_sidebar": True,
- 'no_breadcrumbs': True,
- "title": _("Announcements"),
- "get_list": get_message_list,
- "row_template": "templates/includes/announcement/announcement_row.html"
- }
\ No newline at end of file
diff --git a/erpnext/schools/doctype/announcement/test_announcement.py b/erpnext/schools/doctype/announcement/test_announcement.py
deleted file mode 100644
index b0200a2..0000000
--- a/erpnext/schools/doctype/announcement/test_announcement.py
+++ /dev/null
@@ -1,12 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2015, Frappe and Contributors
-# See license.txt
-from __future__ import unicode_literals
-
-import frappe
-import unittest
-
-# test_records = frappe.get_test_records('Announcement')
-
-class TestAnnouncement(unittest.TestCase):
- pass
diff --git a/erpnext/schools/doctype/assessment_plan/assessment_plan.py b/erpnext/schools/doctype/assessment_plan/assessment_plan.py
index aa84ae3..1b4b671 100644
--- a/erpnext/schools/doctype/assessment_plan/assessment_plan.py
+++ b/erpnext/schools/doctype/assessment_plan/assessment_plan.py
@@ -13,7 +13,7 @@
frappe.throw(_("Please select Student Group or Student Batch"))
self.validate_student_batch()
self.validate_overlap()
-
+ self.validate_max_score()
def validate_overlap(self):
"""Validates overlap for Student Group/Student Batch, Instructor, Room"""
@@ -42,4 +42,11 @@
def validate_student_batch(self):
if self.student_group:
- self.student_batch = frappe.db.get_value("Student Group", self.student_group, "student_batch")
\ No newline at end of file
+ self.student_batch = frappe.db.get_value("Student Group", self.student_group, "student_batch")
+
+ def validate_max_score(self):
+ max_score = 0
+ for d in self.evaluation_criterias:
+ max_score += d.maximum_score
+ if self.maximum_assessment_score != max_score:
+ frappe.throw(_("Sum of Scores of Evaluation Criterias needs to be {0}.".format(self.maximum_assessment_score)))
\ No newline at end of file
diff --git a/erpnext/schools/doctype/discussion/discussion.js b/erpnext/schools/doctype/discussion/discussion.js
deleted file mode 100644
index df3c2b8..0000000
--- a/erpnext/schools/doctype/discussion/discussion.js
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright (c) 2016, Frappe and contributors
-// For license information, please see license.txt
-
-frappe.ui.form.on('Discussion', {
- refresh: function(frm) {
-
- }
-});
diff --git a/erpnext/schools/doctype/discussion/discussion.json b/erpnext/schools/doctype/discussion/discussion.json
deleted file mode 100644
index 57ebfba..0000000
--- a/erpnext/schools/doctype/discussion/discussion.json
+++ /dev/null
@@ -1,175 +0,0 @@
-{
- "allow_copy": 0,
- "allow_import": 1,
- "allow_rename": 0,
- "autoname": "Discussion.####",
- "beta": 0,
- "creation": "2016-06-13 07:57:38.326925",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Document",
- "editable_grid": 0,
- "engine": "InnoDB",
- "fields": [
- {
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "subject",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Subject",
- "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": 1,
- "set_only_once": 0,
- "unique": 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_list_view": 1,
- "in_standard_filter": 1,
- "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": 0,
- "search_index": 1,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "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_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,
- "unique": 0
- },
- {
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "amended_from",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Amended From",
- "length": 0,
- "no_copy": 1,
- "options": "Discussion",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- }
- ],
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "in_dialog": 0,
- "is_submittable": 1,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2016-11-07 05:28:34.032169",
- "modified_by": "Administrator",
- "module": "Schools",
- "name": "Discussion",
- "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,
- "is_custom": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Academics User",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
- "write": 1
- }
- ],
- "quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "title_field": "subject",
- "track_seen": 1
-}
\ No newline at end of file
diff --git a/erpnext/schools/doctype/discussion/discussion.py b/erpnext/schools/doctype/discussion/discussion.py
deleted file mode 100644
index 96732e3..0000000
--- a/erpnext/schools/doctype/discussion/discussion.py
+++ /dev/null
@@ -1,37 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2015, Frappe 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 Discussion(Document):
- def validate(self):
- if not self.owner== frappe.session.user:
- frappe.throw(_("Not Permitted"))
-
-def get_discussions(doctype, txt, filters, limit_start, limit_page_length=20):
- from frappe.www.list import get_list
- if not filters:
- filters = []
- filters.append(("Discussion", "course", "=", frappe.form_dict.course))
- return get_list(doctype, txt, filters, limit_start, limit_page_length, ignore_permissions=True)
-
-def get_list_context(context=None):
- course_name = frappe.form_dict.course
- portal_items = [{'reference_doctype': u'Topic', 'route': u"/topic?course=" + str(course_name), 'show_always': 0L, 'title': u'Topics'},
- {'reference_doctype': u'Discussion', 'route': u"/discussion?course=" + str(course_name), 'show_always': 0L, 'title': u'Discussions'},
-
- ]
- sidebar_title = course_name
- return {
- "show_sidebar": True,
- 'no_breadcrumbs': True,
- "get_list" : get_discussions,
- "title": _("Discussions"),
- "sidebar_items" : portal_items,
- "sidebar_title" : sidebar_title,
- "row_template": "templates/includes/discussion/discussion_row.html"
- }
\ No newline at end of file
diff --git a/erpnext/schools/doctype/discussion/test_discussion.py b/erpnext/schools/doctype/discussion/test_discussion.py
deleted file mode 100644
index 31799f0..0000000
--- a/erpnext/schools/doctype/discussion/test_discussion.py
+++ /dev/null
@@ -1,12 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2015, Frappe and Contributors
-# See license.txt
-from __future__ import unicode_literals
-
-import frappe
-import unittest
-
-# test_records = frappe.get_test_records('Discussion')
-
-class TestDiscussion(unittest.TestCase):
- pass
diff --git a/erpnext/schools/doctype/topic/test_topic.py b/erpnext/schools/doctype/topic/test_topic.py
deleted file mode 100644
index 1d2974e..0000000
--- a/erpnext/schools/doctype/topic/test_topic.py
+++ /dev/null
@@ -1,12 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2015, Frappe and Contributors
-# See license.txt
-from __future__ import unicode_literals
-
-import frappe
-import unittest
-
-# test_records = frappe.get_test_records('Topic')
-
-class TestTopic(unittest.TestCase):
- pass
diff --git a/erpnext/schools/doctype/topic/topic.js b/erpnext/schools/doctype/topic/topic.js
deleted file mode 100644
index bd9379d..0000000
--- a/erpnext/schools/doctype/topic/topic.js
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright (c) 2016, Frappe and contributors
-// For license information, please see license.txt
-
-frappe.ui.form.on('Topic', {
- refresh: function(frm) {
-
- }
-});
diff --git a/erpnext/schools/doctype/topic/topic.json b/erpnext/schools/doctype/topic/topic.json
deleted file mode 100644
index 0a69f88..0000000
--- a/erpnext/schools/doctype/topic/topic.json
+++ /dev/null
@@ -1,175 +0,0 @@
-{
- "allow_copy": 0,
- "allow_import": 0,
- "allow_rename": 1,
- "autoname": "Topic.####",
- "beta": 0,
- "creation": "2016-06-28 07:06:38.749398",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Document",
- "editable_grid": 0,
- "engine": "InnoDB",
- "fields": [
- {
- "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_list_view": 1,
- "in_standard_filter": 1,
- "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": 1,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "topic_name",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 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": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "introduction",
- "fieldtype": "Text",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Introduction",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 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_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": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- }
- ],
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "in_dialog": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2016-11-07 05:29:20.531725",
- "modified_by": "Administrator",
- "module": "Schools",
- "name": "Topic",
- "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,
- "is_custom": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Academics User",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
- "write": 1
- }
- ],
- "quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "title_field": "course",
- "track_seen": 0
-}
\ No newline at end of file
diff --git a/erpnext/schools/doctype/topic/topic.py b/erpnext/schools/doctype/topic/topic.py
deleted file mode 100644
index 5dba561..0000000
--- a/erpnext/schools/doctype/topic/topic.py
+++ /dev/null
@@ -1,49 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2015, Frappe and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-import frappe
-from frappe.model.document import Document
-from frappe import _
-
-class Topic(Document):
- pass
-
-def get_topic_list(doctype, txt, filters, limit_start, limit_page_length=20):
- user = frappe.session.user
- student = frappe.db.sql("select name from `tabStudent` where student_email_id= %s", user)
- if student:
- data = frappe. db.sql('''select name, course, modified,topic_name, introduction, content from `tabTopic` as topic
- where topic.course = %s
- order by idx asc limit {0} , {1}'''.format(limit_start, limit_page_length),filters.course,as_dict = True)
-
- for topic in data:
- try:
- num_attachments = frappe.db.sql(""" select count(file_url) from tabFile as file
- where file.attached_to_name=%s
- and file.attached_to_doctype=%s""",(topic.name,"Topic"))
-
- except IOError or frappe.DoesNotExistError:
- pass
- frappe.local.message_log.pop()
-
- topic.num_attachments = num_attachments[0][0]
-
- return data
-
-def get_list_context(context=None):
- course = frappe.get_doc('Course', frappe.form_dict.course)
- portal_items = [{'reference_doctype': u'Topic', 'route': u"/topic?course=" + str(course.name), 'show_always': 0L, 'title': u'Topics'},
- {'reference_doctype': u'Discussion', 'route': u"/discussion?course=" + str(course.name), 'show_always': 0L, 'title': u'Discussions'},
-
- ]
- return {
- "show_sidebar": True,
- "title": _("Topic"),
- 'no_breadcrumbs': True,
- "sidebar_items" : portal_items,
- "sidebar_title" : course.name,
- "get_list": get_topic_list,
- "row_template": "templates/includes/topic/topic_row.html"
- }
\ No newline at end of file
diff --git a/erpnext/schools/report/student_monthly_attendance_sheet/student_monthly_attendance_sheet.py b/erpnext/schools/report/student_monthly_attendance_sheet/student_monthly_attendance_sheet.py
index cd2c82c..01cee58 100644
--- a/erpnext/schools/report/student_monthly_attendance_sheet/student_monthly_attendance_sheet.py
+++ b/erpnext/schools/report/student_monthly_attendance_sheet/student_monthly_attendance_sheet.py
@@ -61,7 +61,7 @@
students_with_leave_application = get_students_with_leave_application(from_date, to_date, students_list)
for d in attendance_list:
att_map.setdefault(d.student, frappe._dict()).setdefault(d.date, "")
- if students_with_leave_application and d.student in students_with_leave_application.get(d.date,[]):
+ if students_with_leave_application and d.student in students_with_leave_application.get(d.date):
att_map[d.student][d.date] = "Present"
else:
att_map[d.student][d.date] = d.status
diff --git a/erpnext/selling/doctype/customer/customer.js b/erpnext/selling/doctype/customer/customer.js
index 747b31e..540ec28 100644
--- a/erpnext/selling/doctype/customer/customer.js
+++ b/erpnext/selling/doctype/customer/customer.js
@@ -37,7 +37,7 @@
frm.toggle_display(['address_html','contact_html'], !frm.doc.__islocal);
if(!frm.doc.__islocal) {
- erpnext.utils.render_address_and_contact(frm);
+ frappe.geo.render_address_and_contact(frm);
// custom buttons
frm.add_custom_button(__('Accounting Ledger'), function() {
@@ -53,7 +53,7 @@
erpnext.utils.set_party_dashboard_indicators(frm);
} else {
- erpnext.utils.clear_address_and_contact(frm);
+ frappe.geo.clear_address_and_contact(frm);
}
var grid = cur_frm.get_field("sales_team").grid;
diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py
index d8011af..e14cde0 100644
--- a/erpnext/selling/doctype/customer/customer.py
+++ b/erpnext/selling/doctype/customer/customer.py
@@ -9,7 +9,7 @@
from frappe.utils import flt, cint, cstr
from frappe.desk.reportview import build_match_conditions
from erpnext.utilities.transaction_base import TransactionBase
-from erpnext.utilities.address_and_contact import load_address_and_contact, delete_contact_and_address
+from frappe.geo.address_and_contact import load_address_and_contact, delete_contact_and_address
from erpnext.accounts.party import validate_party_accounts, get_timeline_data # keep this
from erpnext.accounts.party_status import get_party_status
from erpnext import get_default_currency
@@ -95,9 +95,14 @@
def create_lead_address_contact(self):
if self.lead_name:
# assign lead address to customer (if already not set)
- address_name = frappe.get_value('Dynamic Link', dict(parenttype='Address', link_doctype='Lead', link_name=self.name))
- if address_name:
- address = frappe.get_doc('Address', address_name)
+ address_names = frappe.get_all('Dynamic Link', filters={
+ "parenttype":"Address",
+ "link_doctype":"Lead",
+ "link_name":self.lead_name
+ }, fields=["parent as name"])
+
+ for address_name in address_names:
+ address = frappe.get_doc('Address', address_name.get('name'))
if not address.has_link('Customer', self.name):
address.append('links', dict(link_doctype='Customer', link_name=self.name))
address.save()
@@ -105,17 +110,17 @@
lead = frappe.db.get_value("Lead", self.lead_name, ["lead_name", "email_id", "phone", "mobile_no"], as_dict=True)
# create contact from lead
- c = frappe.new_doc('Contact')
- c.first_name = lead.lead_name
- c.email_id = lead.email_id
- c.phone = lead.phone
- c.mobile_no = lead.mobile_no
- c.is_primary_contact = 1
- c.append('links', dict(link_doctype='Customer', link_name=self.name))
- c.flags.ignore_permissions = self.flags.ignore_permissions
- c.autoname()
- if not frappe.db.exists("Contact", c.name):
- c.insert()
+ contact = frappe.new_doc('Contact')
+ contact.first_name = lead.lead_name
+ contact.email_id = lead.email_id
+ contact.phone = lead.phone
+ contact.mobile_no = lead.mobile_no
+ contact.is_primary_contact = 1
+ contact.append('links', dict(link_doctype='Customer', link_name=self.name))
+ contact.flags.ignore_permissions = self.flags.ignore_permissions
+ contact.autoname()
+ if not frappe.db.exists("Contact", contact.name):
+ contact.insert()
def validate_name_with_customer_group(self):
if frappe.db.exists("Customer Group", self.name):
@@ -133,7 +138,7 @@
def on_trash(self):
delete_contact_and_address('Customer', self.name)
if self.lead_name:
- frappe.db.sql("update `tabLead` set status='Interested' where name=%s",self.lead_name)
+ frappe.db.sql("update `tabLead` set status='Interested' where name=%s", self.lead_name)
def after_rename(self, olddn, newdn, merge=False):
if frappe.defaults.get_global_default('cust_master_name') == 'Customer Name':
diff --git a/erpnext/selling/page/sales_funnel/sales_funnel.py b/erpnext/selling/page/sales_funnel/sales_funnel.py
index 4d12efd..3c4d528 100644
--- a/erpnext/selling/page/sales_funnel/sales_funnel.py
+++ b/erpnext/selling/page/sales_funnel/sales_funnel.py
@@ -12,9 +12,9 @@
where (date(`modified`) between %s and %s)
and status != "Do Not Contact" """, (from_date, to_date))[0][0]
- active_leads += frappe.db.sql("""select count(distinct customer) from `tabContact`
- where (date(`modified`) between %s and %s)
- and status != "Passive" """, (from_date, to_date))[0][0]
+ active_leads += frappe.db.sql("""select count(distinct contact.name) from `tabContact` contact
+ left join `tabDynamic Link` dl on (dl.parent=contact.name) where dl.link_doctype='Customer'
+ and (date(contact.modified) between %s and %s) and status != "Passive" """, (from_date, to_date))[0][0]
opportunities = frappe.db.sql("""select count(*) from `tabOpportunity`
where (date(`creation`) between %s and %s)
diff --git a/erpnext/selling/report/customer_addresses_and_contacts/__init__.py b/erpnext/selling/report/customer_addresses_and_contacts/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/erpnext/selling/report/customer_addresses_and_contacts/__init__.py
+++ /dev/null
diff --git a/erpnext/selling/report/customer_addresses_and_contacts/customer_addresses_and_contacts.json b/erpnext/selling/report/customer_addresses_and_contacts/customer_addresses_and_contacts.json
deleted file mode 100644
index 1f6707b..0000000
--- a/erpnext/selling/report/customer_addresses_and_contacts/customer_addresses_and_contacts.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "add_total_row": 0,
- "apply_user_permissions": 1,
- "creation": "2012-10-04 18:45:27",
- "disabled": 0,
- "docstatus": 0,
- "doctype": "Report",
- "idx": 1,
- "is_standard": "Yes",
- "modified": "2015-08-24 11:44:00.711112",
- "modified_by": "Administrator",
- "module": "Selling",
- "name": "Customer Addresses And Contacts",
- "owner": "Administrator",
- "query": "SELECT\n\t`tabCustomer`.name as \"Customer ID:Link/Customer\",\n\t`tabCustomer`.customer_name as \"Customer Name\",\n\t`tabCustomer`.customer_group as \"Customer Group:Link/Customer Group\",\n\t`tabAddress`.address_line1 as \"Address Line 1\",\n\t`tabAddress`.address_line2 as \"Address Line 2\",\n\t`tabAddress`.city as \"City\",\n\t`tabAddress`.state as \"State\",\n\t`tabAddress`.pincode as \"Postal Code\",\n\t`tabAddress`.country as \"Country\",\n\t`tabAddress`.is_primary_address as \"Is Primary Address:Check\", \n\t`tabContact`.first_name as \"First Name\",\n\t`tabContact`.last_name as \"Last Name\",\n\t`tabContact`.phone as \"Phone\",\n\t`tabContact`.mobile_no as \"Mobile No\",\n\t`tabContact`.email_id as \"Email Address\",\n\t`tabContact`.is_primary_contact as \"Is Primary Contact:Check\"\nFROM\n\t`tabCustomer`\n\tleft join `tabAddress` on (\n\t\t`tabAddress`.customer=`tabCustomer`.name\n\t)\n\tleft join `tabContact` on (\n\t\t`tabContact`.customer=`tabCustomer`.name\n\t)\nWHERE\n\t`tabCustomer`.docstatus<2\nORDER BY\n\t`tabCustomer`.name asc",
- "ref_doctype": "Customer",
- "report_name": "Customer Addresses And Contacts",
- "report_type": "Query Report"
-}
\ No newline at end of file
diff --git a/erpnext/selling/report/lead_details/lead_details.json b/erpnext/selling/report/lead_details/lead_details.json
index 387b5f8..047b4b7 100644
--- a/erpnext/selling/report/lead_details/lead_details.json
+++ b/erpnext/selling/report/lead_details/lead_details.json
@@ -1,16 +1,18 @@
{
+ "add_total_row": 0,
"apply_user_permissions": 1,
"creation": "2013-10-22 11:58:16",
+ "disabled": 0,
"docstatus": 0,
"doctype": "Report",
"idx": 1,
"is_standard": "Yes",
- "modified": "2015-02-02 11:39:57.231750",
+ "modified": "2017-01-19 15:44:59.742195",
"modified_by": "Administrator",
"module": "Selling",
"name": "Lead Details",
"owner": "Administrator",
- "query": "SELECT\n `tabLead`.name as \"Lead Id:Link/Lead:120\",\n `tabLead`.lead_name as \"Lead Name::120\",\n\t`tabLead`.company_name as \"Company Name::120\",\n\t`tabLead`.status as \"Status::120\",\n\tconcat_ws(', ', \n\t\ttrim(',' from `tabAddress`.address_line1), \n\t\ttrim(',' from tabAddress.address_line2)\n\t) as 'Address::180',\n\t`tabAddress`.state as \"State::100\",\n\t`tabAddress`.pincode as \"Pincode::70\",\n\t`tabAddress`.country as \"Country::100\",\n\t`tabLead`.phone as \"Phone::100\",\n\t`tabLead`.mobile_no as \"Mobile No::100\",\n\t`tabLead`.email_id as \"Email Address::120\",\n\t`tabLead`.lead_owner as \"Lead Owner::120\",\n\t`tabLead`.source as \"Source::120\",\n\t`tabLead`.territory as \"Territory::120\",\n `tabLead`.owner as \"Owner:Link/User:120\"\nFROM\n\t`tabLead`\n\tleft join `tabAddress` on (\n\t\t`tabAddress`.lead=`tabLead`.name\n\t)\nWHERE\n\t`tabLead`.docstatus<2\nORDER BY\n\t`tabLead`.name asc",
+ "query": "SELECT\n `tabLead`.name as \"Lead Id:Link/Lead:120\",\n `tabLead`.lead_name as \"Lead Name::120\",\n\t`tabLead`.company_name as \"Company Name::120\",\n\t`tabLead`.status as \"Status::120\",\n\tconcat_ws(', ', \n\t\ttrim(',' from `tabAddress`.address_line1), \n\t\ttrim(',' from tabAddress.address_line2)\n\t) as 'Address::180',\n\t`tabAddress`.state as \"State::100\",\n\t`tabAddress`.pincode as \"Pincode::70\",\n\t`tabAddress`.country as \"Country::100\",\n\t`tabLead`.phone as \"Phone::100\",\n\t`tabLead`.mobile_no as \"Mobile No::100\",\n\t`tabLead`.email_id as \"Email Id::120\",\n\t`tabLead`.lead_owner as \"Lead Owner::120\",\n\t`tabLead`.source as \"Source::120\",\n\t`tabLead`.territory as \"Territory::120\",\n `tabLead`.owner as \"Owner:Link/User:120\"\nFROM\n\t`tabLead`\n\tleft join `tabDynamic Link` on (\n\t\t`tabDynamic Link`.link_name=`tabLead`.name\n\t)\n\tleft join `tabAddress` on (\n\t\t`tabAddress`.name=`tabDynamic Link`.parent\n\t)\nWHERE\n\t`tabLead`.docstatus<2\nORDER BY\n\t`tabLead`.name asc",
"ref_doctype": "Lead",
"report_name": "Lead Details",
"report_type": "Query Report"
diff --git a/erpnext/setup/doctype/company/delete_company_transactions.py b/erpnext/setup/doctype/company/delete_company_transactions.py
index eb5c043..eef8599 100644
--- a/erpnext/setup/doctype/company/delete_company_transactions.py
+++ b/erpnext/setup/doctype/company/delete_company_transactions.py
@@ -73,11 +73,23 @@
def delete_lead_addresses(company_name):
"""Delete addresses to which leads are linked"""
- for lead in frappe.get_all("Lead", filters={"company": company_name}):
- frappe.db.sql("""delete from `tabAddress`
- where lead=%s and (customer='' or customer is null) and (supplier='' or supplier is null)""", lead.name)
+ leads = frappe.get_all("Lead", filters={"company": company_name})
+ leads = [ "'%s'"%row.get("name") for row in leads ]
+ addresses = []
+ if leads:
+ addresses = frappe.db.sql_list("""select parent from `tabDynamic Link` where link_name
+ in ({leads})""".format(leads=",".join(leads)), debug=True)
+ addresses = ["'%s'"%addr for addr in addresses]
- frappe.db.sql("""update `tabAddress` set lead=null, lead_name=null where lead=%s""", lead.name)
+ frappe.db.sql("""delete from tabAddress where name in ({addresses}) and
+ name not in (select distinct dl1.parent from `tabDynamic Link` dl1
+ inner join `tabDynamic Link` dl2 on dl1.parent=dl2.parent
+ and dl1.link_doctype<>dl2.link_doctype)""".format(addresses=",".join(addresses)), debug=True)
+
+ frappe.db.sql("""delete from `tabDynamic Link` where link_doctype='Lead' and parenttype='Address'
+ and link_name in ({leads})""".format(leads=",".join(leads)), debug=True)
+
+ frappe.db.sql("""update tabCustomer set lead_name=NULL where lead_name in ({leads})""".format(leads=",".join(leads)), debug=True)
def delete_communications(doctype, company_name, company_fieldname):
frappe.db.sql("""
diff --git a/erpnext/setup/doctype/sales_partner/sales_partner.js b/erpnext/setup/doctype/sales_partner/sales_partner.js
index 1bfba98..84cf749 100644
--- a/erpnext/setup/doctype/sales_partner/sales_partner.js
+++ b/erpnext/setup/doctype/sales_partner/sales_partner.js
@@ -6,12 +6,12 @@
frappe.dynamic_link = {doc: frm.doc, fieldname: 'name', doctype: 'Sales Person'}
if(frm.doc.__islocal){
- hide_field(['address_html', 'contact_html']);
- erpnext.utils.clear_address_and_contact(frm);
+ hide_field(['address_html', 'contact_html', 'address_contacts']);
+ frappe.geo.clear_address_and_contact(frm);
}
else{
- unhide_field(['address_html', 'contact_html']);
- erpnext.utils.render_address_and_contact(frm);
+ unhide_field(['address_html', 'contact_html', 'address_contacts']);
+ frappe.geo.render_address_and_contact(frm);
}
}
});
diff --git a/erpnext/setup/doctype/sales_partner/sales_partner.py b/erpnext/setup/doctype/sales_partner/sales_partner.py
index 5a2aa49..96211af 100644
--- a/erpnext/setup/doctype/sales_partner/sales_partner.py
+++ b/erpnext/setup/doctype/sales_partner/sales_partner.py
@@ -5,7 +5,7 @@
import frappe
from frappe.utils import cstr, filter_strip_join
from frappe.website.website_generator import WebsiteGenerator
-from erpnext.utilities.address_and_contact import load_address_and_contact
+from frappe.geo.address_and_contact import load_address_and_contact
class SalesPartner(WebsiteGenerator):
website = frappe._dict(
@@ -28,15 +28,6 @@
if self.partner_website and not self.partner_website.startswith("http"):
self.partner_website = "http://" + self.partner_website
- def get_contacts(self, nm):
- if nm:
- return frappe.db.convert_to_lists(frappe.db.sql("""
- select name, CONCAT(IFNULL(first_name,''),
- ' ',IFNULL(last_name,'')),contact_no,email_id
- from `tabContact` where sales_partner = %s""", nm))
- else:
- return ''
-
def get_context(self, context):
address = frappe.db.get_value("Address",
{"sales_partner": self.name, "is_primary_address": 1},
diff --git a/erpnext/templates/pages/announcements.html b/erpnext/templates/pages/announcements.html
deleted file mode 100644
index d6e0d73..0000000
--- a/erpnext/templates/pages/announcements.html
+++ /dev/null
@@ -1,20 +0,0 @@
-{% extends "templates/web.html" %}
-
-{% block header %}
- <h1> {{doc.subject}} </h1>
-{% endblock %}
-
-{% block page_content %}
-
-<p class="post-description"> {{doc.description}} </p>
-<p class="post-by text-muted small">
- {% for file in attached_files%}
- <a href="{{file.file_url}}" target="_new">{{file.file_name}}</a>
- <br>
- {% endfor %}
- <br>
- <i>{{ doc.posted_by }}</i>
- <i class="blog-dot"></i> {{ frappe.format_date(doc.modified) }}
-</p>
-
-{% endblock %}
\ No newline at end of file
diff --git a/erpnext/templates/pages/announcements.py b/erpnext/templates/pages/announcements.py
deleted file mode 100644
index 4a61fc8..0000000
--- a/erpnext/templates/pages/announcements.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
-# License: GNU General Public License v3. See license.txt
-
-from __future__ import unicode_literals
-import frappe
-
-def get_context(context):
- announcement = frappe.get_doc('Announcement', frappe.form_dict.announcement)
- context.no_cache = 1
- context.show_sidebar = True
- announcement.has_permission('read')
- context.doc = announcement
- attachments = frappe.db.sql("""select file_url, file_name from tabFile as file
- where file.attached_to_name=%s """,(announcement.name), as_dict = True)
-
- context.attached_files = attachments
-
-
diff --git a/erpnext/templates/pages/courses.py b/erpnext/templates/pages/courses.py
index 5b1410e..c80d8e7 100644
--- a/erpnext/templates/pages/courses.py
+++ b/erpnext/templates/pages/courses.py
@@ -15,14 +15,6 @@
course = frappe.get_doc('Course', frappe.form_dict.course)
course.has_permission('read')
context.doc = course
- portal_items = [{'reference_doctype': u'Topic', 'route': u"/topic?course=" + str(course.name), 'show_always': 0L, 'title': u'Topics'},
- {'reference_doctype': u'Discussion', 'route': u"/discussion?course=" + str(course.name), 'show_always': 0L, 'title': u'Discussions'},
-
- ]
-
- context.sidebar_items = portal_items
-
context.sidebar_title = sidebar_title
-
context.intro = course.course_intro
diff --git a/erpnext/templates/pages/discussions.html b/erpnext/templates/pages/discussions.html
deleted file mode 100644
index 28eb01f..0000000
--- a/erpnext/templates/pages/discussions.html
+++ /dev/null
@@ -1,15 +0,0 @@
-{% extends "templates/web.html" %}
-
-{% block header %}
- <h2> {{doc.subject}} </h2>
- <p> {{doc.description}} </p>
- <p class="text-muted small">Started by: {{doc.owner}} </p>
-{% endblock %}
-
-{% block page_content %}
-
-<div>
- {% include 'templates/includes/comments/comments.html' %}
-</div>
-
-{% endblock %}
diff --git a/erpnext/templates/pages/discussions.py b/erpnext/templates/pages/discussions.py
deleted file mode 100644
index 22a1bef..0000000
--- a/erpnext/templates/pages/discussions.py
+++ /dev/null
@@ -1,21 +0,0 @@
-# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
-# License: GNU General Public License v3. See license.txt
-
-from __future__ import unicode_literals
-import frappe
-from frappe.website.utils import get_comment_list
-
-def get_context(context):
- context.doc = frappe.get_doc('Discussion', frappe.form_dict.discussion)
- portal_items = [{'reference_doctype': u'Topic', 'route': u"/topic?course=" + str(context.doc.course), 'show_always': 0L, 'title': u'Topics'},
- {'reference_doctype': u'Discussion', 'route': u"/discussion?course=" + str(context.doc.course), 'show_always': 0L, 'title': u'Discussions'},
-
- ]
- context.show_sidebar = True
- context.sidebar_items = portal_items
- context.no_cache = 1
- context.doc.has_permission('read')
- context.sidebar_title = context.doc.course
- context.reference_doctype = "Discussion"
- context.reference_name = context.doc.name
- context.comment_list = get_comment_list(context.doc.doctype,context.doc.name)
\ No newline at end of file
diff --git a/erpnext/templates/pages/topics.html b/erpnext/templates/pages/topics.html
deleted file mode 100644
index 94d7a17..0000000
--- a/erpnext/templates/pages/topics.html
+++ /dev/null
@@ -1,12 +0,0 @@
-{% extends "templates/web.html" %}
-
-
-{% block header %}
- <h2> {{ doc.introduction }} </h1>
-{% endblock %}
-
-{% block page_content %}
-
-<p class="post-description"> {{ doc.content }} </p>
-
-{% endblock %}
\ No newline at end of file
diff --git a/erpnext/templates/pages/topics.py b/erpnext/templates/pages/topics.py
deleted file mode 100644
index 8a55b64..0000000
--- a/erpnext/templates/pages/topics.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# License: GNU General Public License v3. See license.txt
-
-from __future__ import unicode_literals
-import frappe
-
-
-def get_context(context):
- topic = frappe.get_doc('Topic', frappe.form_dict.topic)
- context.no_cache = 1
- context.show_sidebar = True
- context.doc = topic
- attachments = frappe.db.sql("""select file_url, file_name from tabFile as file
- where file.attached_to_name=%s """,(topic.name), as_dict = True)
-
- context.attached_files = attachments
diff --git a/erpnext/utilities/address_and_contact.py b/erpnext/utilities/address_and_contact.py
deleted file mode 100644
index 12ceb5b..0000000
--- a/erpnext/utilities/address_and_contact.py
+++ /dev/null
@@ -1,134 +0,0 @@
-# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
-# License: GNU General Public License v3. See license.txt
-
-from __future__ import unicode_literals
-import frappe
-
-def load_address_and_contact(doc, key):
- """Loads address list and contact list in `__onload`"""
- from frappe.geo.doctype.address.address import get_address_display
-
- address_list = [frappe.get_value('Address', a.parent, '*')
- for a in frappe.get_all('Dynamic Link', fields='parent',
- filters=dict(parenttype='Address', link_doctype=doc.doctype, link_name=doc.name))]
-
- address_list = [a.update({"display": get_address_display(a)})
- for a in address_list]
-
- address_list = sorted(address_list,
- lambda a, b:
- (int(a.is_primary_address - b.is_primary_address)) or
- (1 if a.modified - b.modified else 0))
-
- doc.set_onload('addr_list', address_list)
-
- if doc.doctype != "Lead":
- contact_list = [frappe.get_value('Contact', a.parent, '*')
- for a in frappe.get_all('Dynamic Link', fields='parent',
- filters=dict(parenttype='Contact', link_doctype=doc.doctype, link_name=doc.name))]
-
- contact_list = sorted(contact_list,
- lambda a, b:
- (int(a.is_primary_contact - b.is_primary_contact)) or
- (1 if a.modified - b.modified else 0))
-
- doc.set_onload('contact_list', contact_list)
-
-def set_default_role(doc, method):
- '''Set customer, supplier, student based on email'''
- if frappe.flags.setting_role:
- return
- contact_name = frappe.get_value('Contact', dict(email_id=doc.email))
- if contact_name:
- contact = frappe.get_doc('Contact', contact_name)
- for link in contact.links:
- frappe.flags.setting_role = True
- if link.link_doctype=='Customer':
- doc.add_roles('Customer')
- elif link.link_doctype=='Supplier':
- doc.add_roles('Supplier')
- elif frappe.get_value('Student', dict(student_email_id=doc.email)):
- doc.add_roles('Student')
-
-def has_permission(doc, ptype, user):
- links = get_permitted_and_not_permitted_links(doc.doctype)
- if not links.get("not_permitted_links"):
- # optimization: don't determine permissions based on link fields
- return True
-
- # True if any one is True or all are empty
- names = []
- for df in (links.get("permitted_links") + links.get("not_permitted_links")):
- doctype = df.options
- name = doc.get(df.fieldname)
- names.append(name)
-
- if name and frappe.has_permission(doctype, ptype, doc=name):
- return True
-
- if not any(names):
- return True
- return False
-
-def get_permission_query_conditions_for_contact(user):
- return get_permission_query_conditions("Contact")
-
-def get_permission_query_conditions_for_address(user):
- return get_permission_query_conditions("Address")
-
-def get_permission_query_conditions(doctype):
- links = get_permitted_and_not_permitted_links(doctype)
-
- if not links.get("not_permitted_links"):
- # when everything is permitted, don't add additional condition
- return ""
-
- elif not links.get("permitted_links"):
- conditions = []
-
- # when everything is not permitted
- for df in links.get("not_permitted_links"):
- # like ifnull(customer, '')='' and ifnull(supplier, '')=''
- conditions.append("ifnull(`tab{doctype}`.`{fieldname}`, '')=''".format(doctype=doctype, fieldname=df.fieldname))
-
- return "( " + " and ".join(conditions) + " )"
-
- else:
- conditions = []
-
- for df in links.get("permitted_links"):
- # like ifnull(customer, '')!='' or ifnull(supplier, '')!=''
- conditions.append("ifnull(`tab{doctype}`.`{fieldname}`, '')!=''".format(doctype=doctype, fieldname=df.fieldname))
-
- return "( " + " or ".join(conditions) + " )"
-
-def get_permitted_and_not_permitted_links(doctype):
- permitted_links = []
- not_permitted_links = []
-
- meta = frappe.get_meta(doctype)
-
- for df in meta.get_link_fields():
- if df.options not in ("Customer", "Supplier", "Company", "Sales Partner"):
- continue
-
- if frappe.has_permission(df.options):
- permitted_links.append(df)
- else:
- not_permitted_links.append(df)
-
- return {
- "permitted_links": permitted_links,
- "not_permitted_links": not_permitted_links
- }
-
-def delete_contact_and_address(doctype, name):
- for parenttype in ('Contact', 'Address'):
- items = frappe.db.sql("""select parent from `tabDynamic Link`
- where parenttype=%s and link_doctype=%s and link_name=%s""",
- (parenttype, doctype, name))
-
- for name in items:
- doc = frappe.get_doc(parenttype, name)
- if len(doc.links)==1:
- doc.delete()