Merge pull request #7170 from rohitwaghchaure/pos_enhancement_v7_2
[POS] Provision to delete the offline records
diff --git a/erpnext/__init__.py b/erpnext/__init__.py
index b54ba59..e88e00d 100644
--- a/erpnext/__init__.py
+++ b/erpnext/__init__.py
@@ -2,7 +2,7 @@
from __future__ import unicode_literals
import frappe
-__version__ = '7.1.22'
+__version__ = '7.1.24'
def get_default_company(user=None):
'''Get default company for user'''
diff --git a/erpnext/accounts/doctype/account/account_tree.js b/erpnext/accounts/doctype/account/account_tree.js
index fc6a1b4..1fbbf4f 100644
--- a/erpnext/accounts/doctype/account/account_tree.js
+++ b/erpnext/accounts/doctype/account/account_tree.js
@@ -30,13 +30,13 @@
options: ['Asset', 'Liability', 'Equity', 'Income', 'Expense'].join('\n'),
depends_on: 'eval:doc.is_group && !doc.parent_account'},
{fieldtype:'Select', fieldname:'account_type', label:__('Account Type'),
- options: ['', 'Accumulated Depreciation', 'Bank', 'Cash', 'Chargeable', 'Cost of Goods Sold', 'Depreciation',
- 'Equity', 'Expense Account', 'Expenses Included In Valuation', 'Fixed Asset', 'Income Account', 'Payable', 'Receivable',
+ options: ['', 'Accumulated Depreciation', 'Bank', 'Cash', 'Chargeable', 'Cost of Goods Sold', 'Depreciation',
+ 'Equity', 'Expense Account', 'Expenses Included In Valuation', 'Fixed Asset', 'Income Account', 'Payable', 'Receivable',
'Round Off', 'Stock', 'Stock Adjustment', 'Stock Received But Not Billed', 'Tax', 'Temporary'].join('\n'),
description: __("Optional. This setting will be used to filter in various transactions.")
},
{fieldtype:'Float', fieldname:'tax_rate', label:__('Tax Rate'),
- depends_on: 'eval:doc.is_group==1&&doc.account_type=="Tax"'},
+ depends_on: 'eval:doc.is_group==0&&doc.account_type=="Tax"'},
{fieldtype:'Link', fieldname:'warehouse', label:__('Warehouse'), options:"Warehouse",
depends_on: 'eval:(!doc.is_group&&doc.account_type=="Stock")',
get_query: function() {
diff --git a/erpnext/accounts/doctype/budget/budget.js b/erpnext/accounts/doctype/budget/budget.js
index 40e929a..6697b17 100644
--- a/erpnext/accounts/doctype/budget/budget.js
+++ b/erpnext/accounts/doctype/budget/budget.js
@@ -36,5 +36,18 @@
}
}
})
+ },
+
+ refresh: function(frm) {
+ frm.trigger("toggle_reqd_fields")
+ },
+
+ budget_against: function(frm) {
+ frm.trigger("toggle_reqd_fields")
+ },
+
+ toggle_reqd_fields: function(frm) {
+ frm.toggle_reqd("cost_center", frm.doc.budget_against=="Cost Center");
+ frm.toggle_reqd("project", frm.doc.budget_against=="Project");
}
});
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.js b/erpnext/accounts/doctype/journal_entry/journal_entry.js
index 06ba5df..c98e77f 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.js
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.js
@@ -35,6 +35,14 @@
multi_currency: function(frm) {
erpnext.journal_entry.toggle_fields_based_on_currency(frm);
+ },
+
+ posting_date: function(frm) {
+ if(!frm.doc.multi_currency) return;
+
+ $.each(frm.doc.accounts || [], function(i, row) {
+ erpnext.journal_entry.set_exchange_rate(frm, row.doctype, row.name);
+ })
}
})
@@ -345,7 +353,7 @@
});
}
},
-
+
debit_in_account_currency: function(frm, cdt, cdn) {
erpnext.journal_entry.set_exchange_rate(frm, cdt, cdn);
},
@@ -420,6 +428,7 @@
frappe.call({
method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_exchange_rate",
args: {
+ posting_date: frm.doc.posting_date,
account: row.account,
account_currency: row.account_currency,
company: frm.doc.company,
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py
index 2f3b101..cd79363 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.py
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py
@@ -326,8 +326,9 @@
if d.account_currency == self.company_currency:
d.exchange_rate = 1
elif not d.exchange_rate or d.exchange_rate == 1 or \
- (d.reference_type in ("Sales Invoice", "Purchase Invoice") and d.reference_name):
- d.exchange_rate = get_exchange_rate(d.account, d.account_currency, self.company,
+ (d.reference_type in ("Sales Invoice", "Purchase Invoice") and d.reference_name and d.posting_date):
+ # Modified to include the posting date for which to retreive the exchange rate
+ d.exchange_rate = get_exchange_rate(self.posting_date, d.account, d.account_currency, self.company,
d.reference_type, d.reference_name, d.debit, d.credit, d.exchange_rate)
if not d.exchange_rate:
@@ -648,7 +649,9 @@
cost_center = frappe.db.get_value("Company", ref_doc.company, "cost_center")
exchange_rate = 1
if args.get("party_account"):
- exchange_rate = get_exchange_rate(args.get("party_account"), args.get("party_account_currency"),
+ # Modified to include the posting date for which the exchange rate is required.
+ # Assumed to be the posting date in the reference document
+ exchange_rate = get_exchange_rate(ref_doc.posting_date, args.get("party_account"), args.get("party_account_currency"),
ref_doc.company, ref_doc.doctype, ref_doc.name)
je = frappe.new_doc("Journal Entry")
@@ -681,7 +684,9 @@
bank_account = get_default_bank_cash_account(ref_doc.company, "Bank", account=args.get("bank_account"))
if bank_account:
bank_row.update(bank_account)
- bank_row.exchange_rate = get_exchange_rate(bank_account["account"],
+ # Modified to include the posting date for which the exchange rate is required.
+ # Assumed to be the posting date of the reference date
+ bank_row.exchange_rate = get_exchange_rate(ref_doc.posting_date, bank_account["account"],
bank_account["account_currency"], ref_doc.company)
bank_row.cost_center = cost_center
@@ -805,7 +810,10 @@
"party_type": party_type,
"account_type": account_details.account_type,
"account_currency": account_details.account_currency or company_currency,
- "exchange_rate": get_exchange_rate(account, account_details.account_currency,
+
+ # The date used to retreive the exchange rate here is the date passed in
+ # as an argument to this function. It is assumed to be the date on which the balance is sought
+ "exchange_rate": get_exchange_rate(date, account, account_details.account_currency,
company, debit=debit, credit=credit, exchange_rate=exchange_rate)
}
@@ -815,8 +823,9 @@
return grid_values
+# Added posting_date as one of the parameters of get_exchange_rate
@frappe.whitelist()
-def get_exchange_rate(account, account_currency=None, company=None,
+def get_exchange_rate(posting_date, account, account_currency=None, company=None,
reference_type=None, reference_name=None, debit=None, credit=None, exchange_rate=None):
from erpnext.setup.utils import get_exchange_rate
account_details = frappe.db.get_value("Account", account,
@@ -842,9 +851,10 @@
(account_details.root_type == "Liability" and debit)):
exchange_rate = get_average_exchange_rate(account)
- if not exchange_rate and account_currency:
- exchange_rate = get_exchange_rate(account_currency, company_currency)
-
+ # The date used to retreive the exchange rate here is the date passed
+ # in as an argument to this function.
+ if not exchange_rate and account_currency and posting_date:
+ exchange_rate = get_exchange_rate(account_currency, company_currency, posting_date)
else:
exchange_rate = 1
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js
index 1f6199e..d3dbd31 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.js
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js
@@ -327,6 +327,7 @@
frappe.call({
method: "erpnext.setup.utils.get_exchange_rate",
args: {
+ transaction_date: frm.doc.posting_date,
from_currency: from_currency,
to_currency: to_currency
},
@@ -335,6 +336,10 @@
}
})
},
+
+ posting_date: function(frm) {
+ frm.events.paid_from_account_currency(frm);
+ },
source_exchange_rate: function(frm) {
if (frm.doc.paid_amount) {
@@ -425,6 +430,7 @@
method: 'erpnext.accounts.doctype.payment_entry.payment_entry.get_outstanding_reference_documents',
args: {
args: {
+ "posting_date": frm.doc.posting_date,
"company": frm.doc.company,
"party_type": frm.doc.party_type,
"payment_type": frm.doc.payment_type,
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index d4f8edb..02d2b6b 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -153,11 +153,11 @@
self.source_exchange_rate = get_average_exchange_rate(self.paid_from)
else:
self.source_exchange_rate = get_exchange_rate(self.paid_from_account_currency,
- self.company_currency)
+ self.company_currency, self.posting_date)
if self.paid_to and not self.target_exchange_rate:
self.target_exchange_rate = get_exchange_rate(self.paid_to_account_currency,
- self.company_currency)
+ self.company_currency, self.posting_date)
def validate_mandatory(self):
for field in ("paid_amount", "received_amount", "source_exchange_rate", "target_exchange_rate"):
@@ -482,12 +482,12 @@
d["exchange_rate"] = frappe.db.get_value(d.voucher_type, d.voucher_no, "conversion_rate")
# Get all SO / PO which are not fully billed or aginst which full advance not paid
- orders_to_be_billed = get_orders_to_be_billed(args.get("party_type"), args.get("party"),
+ orders_to_be_billed = get_orders_to_be_billed(args.get("posting_date"),args.get("party_type"), args.get("party"),
party_account_currency, company_currency)
return negative_outstanding_invoices + outstanding_invoices + orders_to_be_billed
-def get_orders_to_be_billed(party_type, party, party_account_currency, company_currency):
+def get_orders_to_be_billed(posting_date, party_type, party, party_account_currency, company_currency):
voucher_type = 'Sales Order' if party_type == "Customer" else 'Purchase Order'
ref_field = "base_grand_total" if party_account_currency == company_currency else "grand_total"
@@ -517,7 +517,9 @@
order_list = []
for d in orders:
d["voucher_type"] = voucher_type
- d["exchange_rate"] = get_exchange_rate(party_account_currency, company_currency)
+ # This assumes that the exchange rate required is the one in the SO
+ d["exchange_rate"] = get_exchange_rate(party_account_currency,
+ company_currency, posting_date)
order_list.append(d)
return order_list
@@ -592,14 +594,19 @@
exchange_rate = 1
else:
total_amount = ref_doc.grand_total
+
+ # Get the exchange rate from the original ref doc
+ # or get it based on the posting date of the ref doc
exchange_rate = ref_doc.get("conversion_rate") or \
- get_exchange_rate(party_account_currency, ref_doc.company_currency)
+ get_exchange_rate(party_account_currency, ref_doc.company_currency, ref_doc.posting_date)
outstanding_amount = ref_doc.get("outstanding_amount") \
if reference_doctype in ("Sales Invoice", "Purchase Invoice") \
else flt(total_amount) - flt(ref_doc.advance_paid)
else:
- exchange_rate = get_exchange_rate(party_account_currency, ref_doc.company_currency)
+ # Get the exchange rate based on the posting date of the ref doc
+ exchange_rate = get_exchange_rate(party_account_currency,
+ ref_doc.company_currency, ref_doc.posting_date)
return frappe._dict({
"due_date": ref_doc.get("due_date"),
@@ -639,7 +646,7 @@
if party_amount:
grand_total = outstanding_amount = party_amount
elif dt in ("Sales Invoice", "Purchase Invoice"):
- grand_total = doc.grand_total
+ grand_total = doc.base_grand_total if party_account_currency == doc.company_currency else doc.grand_total
outstanding_amount = doc.outstanding_amount
else:
total_field = "base_grand_total" if party_account_currency == doc.company_currency else "grand_total"
diff --git a/erpnext/accounts/doctype/payment_request/payment_request.json b/erpnext/accounts/doctype/payment_request/payment_request.json
index b4c3349..574103d 100644
--- a/erpnext/accounts/doctype/payment_request/payment_request.json
+++ b/erpnext/accounts/doctype/payment_request/payment_request.json
@@ -447,7 +447,7 @@
"collapsible": 0,
"columns": 0,
"fieldname": "payment_url",
- "fieldtype": "Data",
+ "fieldtype": "Small Text",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@@ -681,7 +681,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2016-11-07 05:55:42.339193",
+ "modified": "2016-12-12 13:30:42.858205",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Request",
diff --git a/erpnext/accounts/doctype/payment_request/test_payment_request.py b/erpnext/accounts/doctype/payment_request/test_payment_request.py
index 73c412f..bf3e24f 100644
--- a/erpnext/accounts/doctype/payment_request/test_payment_request.py
+++ b/erpnext/accounts/doctype/payment_request/test_payment_request.py
@@ -9,7 +9,6 @@
from erpnext.accounts.doctype.payment_request.payment_request import make_payment_request
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
from erpnext.setup.utils import get_exchange_rate
-# test_records = frappe.get_test_records('Payment Request')
test_dependencies = ["Currency Exchange", "Journal Entry", "Contact", "Address"]
diff --git a/erpnext/accounts/doctype/pos_profile/pos_profile.js b/erpnext/accounts/doctype/pos_profile/pos_profile.js
index bbbab73..c1aa0c3 100755
--- a/erpnext/accounts/doctype/pos_profile/pos_profile.js
+++ b/erpnext/accounts/doctype/pos_profile/pos_profile.js
@@ -26,30 +26,6 @@
});
});
-frappe.ui.form.on("POS Profile", {
- setup: function(frm) {
- frm.trigger("get_query_for_groups")
- },
-
- get_query_for_groups: function(frm) {
- frm.fields_dict['item_groups'].grid.get_field('item_group').get_query = function(frm, cdt, cdn) {
- return{
- filters: {
- 'is_group': 0
- }
- }
- }
-
- frm.fields_dict['customer_groups'].grid.get_field('customer_group').get_query = function(frm, cdt, cdn) {
- return{
- filters: {
- 'is_group': 0
- }
- }
- }
- }
-})
-
// Income Account
// --------------------------------
cur_frm.fields_dict['income_account'].get_query = function(doc,cdt,cdn) {
diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
index 3476ddd..3a41851 100644
--- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
+++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
@@ -138,6 +138,8 @@
})
if args.ignore_pricing_rule or not args.item_code:
+ if args.name and args.get("pricing_rule"):
+ item_details = remove_pricing_rule(args, item_details)
return item_details
if not (args.item_group and args.brand):
@@ -178,9 +180,16 @@
else:
item_details.discount_percentage = pricing_rule.discount_percentage
elif args.get('pricing_rule'):
- if frappe.db.get_value('Pricing Rule', args.get('pricing_rule'), 'price_or_discount') == 'Discount Percentage':
- item_details.discount_percentage = 0.0
+ item_details = remove_pricing_rule(args, item_details)
+ return item_details
+
+def remove_pricing_rule(args, item_details):
+ pricing_rule = frappe.db.get_value('Pricing Rule', args.get('pricing_rule'), ['price_or_discount', 'margin_type'], as_dict=1)
+ if pricing_rule and pricing_rule.price_or_discount == 'Discount Percentage':
+ item_details.discount_percentage = 0.0
+
+ if pricing_rule and pricing_rule.margin_type in ['Percentage', 'Amount']:
item_details.margin_rate_or_amount = 0.0
item_details.margin_type = None
diff --git a/erpnext/accounts/doctype/sales_invoice/pos.py b/erpnext/accounts/doctype/sales_invoice/pos.py
index 4e4ad78..3619e98 100644
--- a/erpnext/accounts/doctype/sales_invoice/pos.py
+++ b/erpnext/accounts/doctype/sales_invoice/pos.py
@@ -3,7 +3,6 @@
from __future__ import unicode_literals
import frappe, json
-from frappe import _
from frappe.utils import nowdate
from erpnext.setup.utils import get_exchange_rate
from erpnext.stock.get_item_details import get_pos_profile
@@ -63,8 +62,10 @@
doc.currency = pos_profile.get('currency') or company_data.default_currency
doc.conversion_rate = 1.0
+
if doc.currency != company_data.default_currency:
- doc.conversion_rate = get_exchange_rate(doc.currency, company_data.default_currency)
+ doc.conversion_rate = get_exchange_rate(doc.currency, company_data.default_currency, doc.posting_date)
+
doc.selling_price_list = pos_profile.get('selling_price_list') or \
frappe.db.get_value('Selling Settings', None, 'selling_price_list')
doc.naming_series = pos_profile.get('naming_series') or 'SINV-'
@@ -115,9 +116,9 @@
item_groups = []
if pos_profile.get('item_groups'):
# Get items based on the item groups defined in the POS profile
-
- cond = "item_group in (%s)"%(', '.join(['%s']*len(pos_profile.get('item_groups'))))
- item_groups = [d.item_group for d in pos_profile.get('item_groups')]
+ for d in pos_profile.get('item_groups'):
+ item_groups.extend(get_child_nodes('Item Group', d.item_group))
+ cond = "item_group in (%s)"%(', '.join(['%s']*len(item_groups)))
return frappe.db.sql("""
select
@@ -135,14 +136,19 @@
customer_groups = []
if pos_profile.get('customer_groups'):
# Get customers based on the customer groups defined in the POS profile
-
- cond = "customer_group in (%s)"%(', '.join(['%s']*len(pos_profile.get('customer_groups'))))
- customer_groups = [d.customer_group for d in pos_profile.get('customer_groups')]
+ for d in pos_profile.get('customer_groups'):
+ customer_groups.extend(get_child_nodes('Customer Group', d.customer_group))
+ cond = "customer_group in (%s)"%(', '.join(['%s']*len(customer_groups)))
return frappe.db.sql(""" select name, customer_name, customer_group,
territory from tabCustomer where disabled = 0
and {cond}""".format(cond=cond), tuple(customer_groups), as_dict=1) or {}
+def get_child_nodes(group_type, root):
+ lft, rgt = frappe.db.get_value(group_type, root, ["lft", "rgt"])
+ return frappe.db.sql_list(""" Select name from `tab{tab}` where
+ lft >= {lft} and rgt <= {rgt}""".format(tab=group_type, lft=lft, rgt=rgt))
+
def get_serial_no_data(pos_profile, company):
# get itemwise serial no data
# example {'Nokia Lumia 1020': {'SN0001': 'Pune'}}
@@ -240,8 +246,7 @@
for docs in doc_list:
for name, doc in docs.items():
- if not frappe.db.exists('Sales Invoice',
- {'offline_pos_name': name, 'docstatus': ("<", "2")}):
+ if not frappe.db.exists('Sales Invoice', {'offline_pos_name': name}):
validate_records(doc)
si_doc = frappe.new_doc('Sales Invoice')
si_doc.offline_pos_name = name
@@ -286,6 +291,7 @@
try:
si_doc.insert()
si_doc.submit()
+ frappe.db.commit()
except Exception, e:
if frappe.message_log: frappe.message_log.pop()
frappe.db.rollback()
diff --git a/erpnext/accounts/report/budget_variance_report/budget_variance_report.js b/erpnext/accounts/report/budget_variance_report/budget_variance_report.js
index 8cfbc83..2b7f1f3 100644
--- a/erpnext/accounts/report/budget_variance_report/budget_variance_report.js
+++ b/erpnext/accounts/report/budget_variance_report/budget_variance_report.js
@@ -31,6 +31,14 @@
options: "Company",
default: frappe.defaults.get_user_default("Company"),
reqd: 1
+ },
+ {
+ fieldname: "budget_against",
+ label: __("Budget Against"),
+ fieldtype: "Select",
+ options: ["Cost Center", "Project"],
+ default: "Cost Center",
+ reqd: 1
}
]
}
diff --git a/erpnext/accounts/report/budget_variance_report/budget_variance_report.py b/erpnext/accounts/report/budget_variance_report/budget_variance_report.py
index 0be0b3d..875ec99 100644
--- a/erpnext/accounts/report/budget_variance_report/budget_variance_report.py
+++ b/erpnext/accounts/report/budget_variance_report/budget_variance_report.py
@@ -12,7 +12,7 @@
if not filters: filters = {}
columns = get_columns(filters)
- cost_centers = get_cost_centers(filters.company)
+ cost_centers = get_cost_centers(filters)
period_month_ranges = get_period_month_ranges(filters["period"], filters["fiscal_year"])
cam_map = get_cost_center_account_month_map(filters)
@@ -40,7 +40,7 @@
return columns, data
def get_columns(filters):
- columns = [_("Cost Center") + ":Link/Cost Center:120", _("Account") + ":Link/Account:120"]
+ columns = [_(filters.get("budget_against")) + ":Link/%s:120"%(filters.get("budget_against")), _("Account") + ":Link/Account:120"]
group_months = False if filters["period"] == "Monthly" else True
@@ -56,16 +56,23 @@
return columns + [_("Total Target") + ":Float:120", _("Total Actual") + ":Float:120",
_("Total Variance") + ":Float:120"]
-def get_cost_centers(company):
- return frappe.db.sql_list("select name from `tabCost Center` where company=%s order by lft", company)
+def get_cost_centers(filters):
+ cond = "and 1=1"
+ if filters.get("budget_against") == "Cost Center":
+ cond = "order by lft"
+
+ return frappe.db.sql_list("""select name from `tab{tab}` where company=%s
+ {cond}""".format(tab=filters.get("budget_against"), cond=cond), filters.get("company"))
#Get cost center & target details
def get_cost_center_target_details(filters):
return frappe.db.sql("""
- select b.cost_center, b.monthly_distribution, ba.account, ba.budget_amount
+ select b.{budget_against} as budget_against, b.monthly_distribution, ba.account, ba.budget_amount
from `tabBudget` b, `tabBudget Account` ba
- where b.name=ba.parent and b.docstatus = 1 and b.fiscal_year=%s and b.company=%s
- """, (filters.fiscal_year, filters.company), as_dict=True)
+ where b.name=ba.parent and b.docstatus = 1 and b.fiscal_year=%s
+ and b.budget_against = %s and b.company=%s
+ """.format(budget_against=filters.get("budget_against").replace(" ", "_").lower()),
+ (filters.fiscal_year, filters.budget_against, filters.company), as_dict=True)
#Get target distribution details of accounts of cost center
def get_target_distribution_details(filters):
@@ -78,20 +85,26 @@
return target_details
#Get actual details from gl entry
-def get_actual_details(cost_center, fiscal_year):
- cc_lft, cc_rgt = frappe.db.get_value("Cost Center", cost_center, ["lft", "rgt"])
+def get_actual_details(name, filters):
+ cond = "1=1"
+ budget_against=filters.get("budget_against").replace(" ", "_").lower()
+
+ if filters.get("budget_against") == "Cost Center":
+ cc_lft, cc_rgt = frappe.db.get_value("Cost Center", name, ["lft", "rgt"])
+ cond = "lft>='{lft}' and rgt<='{rgt}'".format(lft = cc_lft, rgt=cc_rgt)
ac_details = frappe.db.sql("""select gl.account, gl.debit, gl.credit,
- MONTHNAME(gl.posting_date) as month_name, b.cost_center
+ MONTHNAME(gl.posting_date) as month_name, b.{budget_against} as budget_against
from `tabGL Entry` gl, `tabBudget Account` ba, `tabBudget` b
where
b.name = ba.parent
and b.docstatus = 1
and ba.account=gl.account
and gl.fiscal_year=%s
- and b.cost_center=%s
- and exists(select name from `tabCost Center` where name=gl.cost_center and lft>=%s and rgt<=%s)
- """, (fiscal_year, cost_center, cc_lft, cc_rgt), as_dict=1)
+ and b.{budget_against}=%s
+ and exists(select name from `tab{tab}` where name=gl.{budget_against} and {cond})
+ """.format(tab = filters.budget_against, budget_against = budget_against, cond = cond),
+ (filters.fiscal_year, name), as_dict=1)
cc_actual_details = {}
for d in ac_details:
@@ -107,17 +120,17 @@
cam_map = {}
for ccd in cost_center_target_details:
- actual_details = get_actual_details(ccd.cost_center, filters.fiscal_year)
+ actual_details = get_actual_details(ccd.budget_against, filters)
for month_id in range(1, 13):
month = datetime.date(2013, month_id, 1).strftime('%B')
- cam_map.setdefault(ccd.cost_center, {}).setdefault(ccd.account, {})\
+ cam_map.setdefault(ccd.budget_against, {}).setdefault(ccd.account, {})\
.setdefault(month, frappe._dict({
"target": 0.0, "actual": 0.0
}))
- tav_dict = cam_map[ccd.cost_center][ccd.account][month]
+ tav_dict = cam_map[ccd.budget_against][ccd.account][month]
month_percentage = tdd.get(ccd.monthly_distribution, {}).get(month, 0) \
if ccd.monthly_distribution else 100.0/12
diff --git a/erpnext/accounts/report/financial_statements.py b/erpnext/accounts/report/financial_statements.py
index e66d20e..bc4a220 100644
--- a/erpnext/accounts/report/financial_statements.py
+++ b/erpnext/accounts/report/financial_statements.py
@@ -42,9 +42,6 @@
if to_date == get_first_day(to_date):
# if to_date is the first day, get the last day of previous month
to_date = add_days(to_date, -1)
- else:
- # to_date should be the last day of the new to_date's month
- to_date = get_last_day(to_date)
if to_date <= year_end_date:
# the normal case
diff --git a/erpnext/accounts/report/purchase_register/purchase_register.py b/erpnext/accounts/report/purchase_register/purchase_register.py
index 4bba066..47f79f1 100644
--- a/erpnext/accounts/report/purchase_register/purchase_register.py
+++ b/erpnext/accounts/report/purchase_register/purchase_register.py
@@ -185,7 +185,7 @@
pr_list = [d.purchase_receipt]
elif d.po_detail:
pr_list = frappe.db.sql_list("""select distinct parent from `tabPurchase Receipt Item`
- where docstatus=1 and prevdoc_detail_docname=%s""", d.po_detail)
+ where docstatus=1 and purchase_order_item=%s""", d.po_detail)
if pr_list:
invoice_po_pr_map.setdefault(d.parent, frappe._dict()).setdefault("purchase_receipt", pr_list)
diff --git a/erpnext/buying/report/quoted_item_comparison/quoted_item_comparison.py b/erpnext/buying/report/quoted_item_comparison/quoted_item_comparison.py
index 1793fc3..f627b4a 100644
--- a/erpnext/buying/report/quoted_item_comparison/quoted_item_comparison.py
+++ b/erpnext/buying/report/quoted_item_comparison/quoted_item_comparison.py
@@ -3,11 +3,9 @@
from __future__ import unicode_literals
from erpnext.setup.utils import get_exchange_rate
-
import frappe
def execute(filters=None):
-
qty_list = get_quantity_list(filters.item)
data = get_quote_list(filters.item, qty_list)
@@ -15,12 +13,9 @@
columns = get_columns(qty_list)
return columns, data
-
def get_quote_list(item, qty_list):
-
out = []
-
if item:
price_data = []
suppliers = []
@@ -38,8 +33,11 @@
#Add a row for each supplier
for root in set(suppliers):
- supplier_currency = frappe.db.get_value("Supplier",root,"default_currency")
- exg = get_exchange_rate(supplier_currency,company_currency)
+ supplier_currency = frappe.db.get_value("Supplier", root, "default_currency")
+ if supplier_currency:
+ exchange_rate = get_exchange_rate(supplier_currency, company_currency)
+ else:
+ exchange_rate = 1
row = frappe._dict({
"supplier_name": root
@@ -48,7 +46,7 @@
# Get the quantity for this row
for item_price in price_data:
if str(item_price.qty) == col.key and item_price.supplier == root:
- row[col.key] = item_price.rate * exg
+ row[col.key] = item_price.rate * exchange_rate
row[col.key + "QUOTE"] = item_price.parent
break
else:
@@ -56,15 +54,11 @@
row[col.key + "QUOTE"] = ""
out.append(row)
-
-
return out
def get_quantity_list(item):
-
out = []
-
if item:
qty_list = frappe.db.sql("""select distinct qty from `tabSupplier Quotation Item` where ifnull(item_code,'')=%s and docstatus < 2""", item, as_dict=1)
qty_list.sort(reverse=False)
@@ -102,5 +96,4 @@
"width": 90
})
-
- return columns
\ No newline at end of file
+ return columns
diff --git a/erpnext/config/docs.py b/erpnext/config/docs.py
index 7b6915a..2d2cc0a 100644
--- a/erpnext/config/docs.py
+++ b/erpnext/config/docs.py
@@ -1,3 +1,7 @@
+from __future__ import unicode_literals
+
+docs_version = "7.x.x"
+
source_link = "https://github.com/frappe/erpnext"
docs_base_url = "https://frappe.github.io/erpnext"
headline = "ERPNext Documentation"
@@ -15,8 +19,8 @@
listed as one of the Best Open Source Softwares in the world by many online
blogs."""
-docs_version = "7.x.x"
splash_light_background = True
+google_analytics_id = 'UA-8911157-22'
def get_context(context):
context.brand_html = ('<img class="brand-logo" src="'+context.docs_base_url
diff --git a/erpnext/config/hr.py b/erpnext/config/hr.py
index 0b21fec..55363ab 100644
--- a/erpnext/config/hr.py
+++ b/erpnext/config/hr.py
@@ -150,12 +150,23 @@
},
{
- "label": _("Tools"),
- "icon": "fa fa-wrench",
+ "label": _("Training"),
"items": [
-
+ {
+ "type": "doctype",
+ "name": "Training Event"
+ },
+ {
+ "type": "doctype",
+ "name": "Training Result"
+ },
+ {
+ "type": "doctype",
+ "name": "Training Feedback"
+ },
]
},
+
{
"label": _("Setup"),
"icon": "fa fa-cog",
diff --git a/erpnext/config/schools.py b/erpnext/config/schools.py
index f9696d0..1d33d4d 100644
--- a/erpnext/config/schools.py
+++ b/erpnext/config/schools.py
@@ -68,7 +68,7 @@
},
{
"type": "doctype",
- "name": "Student Batch Attendance Tool"
+ "name": "Student Attendance Tool"
},
{
"type": "report",
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 5796a4d..554529c 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -127,6 +127,11 @@
validate_due_date(self.posting_date, self.due_date, "Supplier", self.supplier, self.company)
def set_price_list_currency(self, buying_or_selling):
+ if self.meta.get_field("posting_date"):
+ transaction_date = self.posting_date
+ else:
+ transaction_date = self.transaction_date
+
if self.meta.get_field("currency"):
# price list part
fieldname = "selling_price_list" if buying_or_selling.lower() == "selling" \
@@ -139,8 +144,8 @@
self.plc_conversion_rate = 1.0
elif not self.plc_conversion_rate:
- self.plc_conversion_rate = get_exchange_rate(
- self.price_list_currency, self.company_currency)
+ self.plc_conversion_rate = get_exchange_rate(self.price_list_currency,
+ self.company_currency, transaction_date)
# currency
if not self.currency:
@@ -150,7 +155,7 @@
self.conversion_rate = 1.0
elif not self.conversion_rate:
self.conversion_rate = get_exchange_rate(self.currency,
- self.company_currency)
+ self.company_currency, transaction_date)
def set_missing_item_details(self, for_validate=False):
"""set missing item values"""
@@ -602,7 +607,6 @@
for item in duplicate_list:
self.remove(item)
-
@frappe.whitelist()
def get_tax_rate(account_head):
return frappe.db.get_value("Account", account_head, ["tax_rate", "account_name"], as_dict=True)
diff --git a/erpnext/crm/doctype/opportunity/opportunity.py b/erpnext/crm/doctype/opportunity/opportunity.py
index 6be0768..6ee9003 100644
--- a/erpnext/crm/doctype/opportunity/opportunity.py
+++ b/erpnext/crm/doctype/opportunity/opportunity.py
@@ -205,7 +205,8 @@
if company_currency == quotation.currency:
exchange_rate = 1
else:
- exchange_rate = get_exchange_rate(quotation.currency, company_currency)
+ exchange_rate = get_exchange_rate(quotation.currency, company_currency,
+ quotation.transaction_date)
quotation.conversion_rate = exchange_rate
diff --git a/erpnext/docs/assets/img/human-resources/training_event.png b/erpnext/docs/assets/img/human-resources/training_event.png
new file mode 100644
index 0000000..04162eb
--- /dev/null
+++ b/erpnext/docs/assets/img/human-resources/training_event.png
Binary files differ
diff --git a/erpnext/docs/assets/img/human-resources/training_event_employee.png b/erpnext/docs/assets/img/human-resources/training_event_employee.png
new file mode 100644
index 0000000..aea90b4
--- /dev/null
+++ b/erpnext/docs/assets/img/human-resources/training_event_employee.png
Binary files differ
diff --git a/erpnext/docs/assets/img/human-resources/training_feedback.png b/erpnext/docs/assets/img/human-resources/training_feedback.png
new file mode 100644
index 0000000..84a2ec2
--- /dev/null
+++ b/erpnext/docs/assets/img/human-resources/training_feedback.png
Binary files differ
diff --git a/erpnext/docs/assets/img/human-resources/training_result.png b/erpnext/docs/assets/img/human-resources/training_result.png
new file mode 100644
index 0000000..36f086c
--- /dev/null
+++ b/erpnext/docs/assets/img/human-resources/training_result.png
Binary files differ
diff --git a/erpnext/docs/user/manual/en/human-resources/index.txt b/erpnext/docs/user/manual/en/human-resources/index.txt
index 2543b4b..5615790 100644
--- a/erpnext/docs/user/manual/en/human-resources/index.txt
+++ b/erpnext/docs/user/manual/en/human-resources/index.txt
@@ -7,6 +7,7 @@
job-applicant
job-opening
offer-letter
+training
tools
human-resources-reports
setup
diff --git a/erpnext/docs/user/manual/en/human-resources/training.md b/erpnext/docs/user/manual/en/human-resources/training.md
new file mode 100644
index 0000000..5d55b6c
--- /dev/null
+++ b/erpnext/docs/user/manual/en/human-resources/training.md
@@ -0,0 +1,28 @@
+### Training Event
+
+Schedule seminars, workshops, conferences etc using Training Event. You can also invite your employees to attend the event using this feature.
+
+<img class="screenshot" alt="Employee" src="{{docs_base_url}}/assets/img/human-resources/training_event.png">
+
+### Inviting Employees for Event
+
+You can invite your employees to attend the event. You can do so by selecting the employees to be invited in the employee table.
+By default the status of the employee will be 'Open'.
+The system shall notify the employee with status 'Open' by sending a email to the office email address of the employee as mentioned in the employee master if you have selected 'Send Email' checkbox.
+The status is changed to 'Invited' when an invitation email is sent to the employee by the system.
+When an Employee confirms his/her presence for the event you can change the status to 'Confirmed'.
+
+<img class="screenshot" alt="Employee" src="{{docs_base_url}}/assets/img/human-resources/training_event_employee.png">
+
+### Training Result
+
+After compleation of the training Employee Wise training results can be stored based on the Feedback received from the Trainer.
+
+<img class="screenshot" alt="Employee" src="{{docs_base_url}}/assets/img/human-resources/training_result.png">
+
+
+### Trainig Feedback
+
+Collect feedback regarding the event from your Employees using Training Feedback.
+
+<img class="screenshot" alt="Employee" src="{{docs_base_url}}/assets/img/human-resources/training_feedback.png">
diff --git a/erpnext/hr/doctype/appraisal_template/appraisal_template.json b/erpnext/hr/doctype/appraisal_template/appraisal_template.json
index 22ee3dd..97402ac 100644
--- a/erpnext/hr/doctype/appraisal_template/appraisal_template.json
+++ b/erpnext/hr/doctype/appraisal_template/appraisal_template.json
@@ -3,16 +3,19 @@
"allow_import": 1,
"allow_rename": 1,
"autoname": "field:kra_title",
+ "beta": 0,
"creation": "2012-07-03 13:30:39",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "Setup",
+ "editable_grid": 0,
"fields": [
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"fieldname": "kra_title",
"fieldtype": "Data",
"hidden": 0,
@@ -20,6 +23,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
+ "in_standard_filter": 0,
"label": "Appraisal Template Title",
"length": 0,
"no_copy": 0,
@@ -29,6 +33,7 @@
"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,
@@ -39,6 +44,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"fieldname": "description",
"fieldtype": "Small Text",
"hidden": 0,
@@ -46,6 +52,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
+ "in_standard_filter": 0,
"label": "Description",
"length": 0,
"no_copy": 0,
@@ -56,6 +63,7 @@
"print_hide_if_no_value": 0,
"print_width": "300px",
"read_only": 0,
+ "remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
@@ -67,6 +75,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"fieldname": "goals",
"fieldtype": "Table",
"hidden": 0,
@@ -74,6 +83,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Goals",
"length": 0,
"no_copy": 0,
@@ -84,6 +94,7 @@
"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,
@@ -93,15 +104,16 @@
],
"hide_heading": 0,
"hide_toolbar": 0,
- "icon": "fa fa-file-text",
+ "icon": "icon-file-text",
"idx": 1,
+ "image_view": 0,
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2016-04-13 01:49:21.815151",
+ "modified": "2016-12-13 12:37:56.937023",
"modified_by": "Administrator",
"module": "HR",
"name": "Appraisal Template",
@@ -117,6 +129,7 @@
"export": 0,
"if_owner": 0,
"import": 0,
+ "is_custom": 0,
"permlevel": 0,
"print": 1,
"read": 1,
@@ -126,8 +139,30 @@
"share": 1,
"submit": 0,
"write": 1
+ },
+ {
+ "amend": 0,
+ "apply_user_permissions": 0,
+ "cancel": 0,
+ "create": 0,
+ "delete": 0,
+ "email": 0,
+ "export": 0,
+ "if_owner": 0,
+ "import": 0,
+ "is_custom": 0,
+ "permlevel": 0,
+ "print": 0,
+ "read": 1,
+ "report": 0,
+ "role": "Employee",
+ "set_user_permissions": 0,
+ "share": 0,
+ "submit": 0,
+ "write": 0
}
],
+ "quick_entry": 0,
"read_only": 0,
"read_only_onload": 0,
"sort_order": "DESC",
diff --git a/erpnext/hr/doctype/employee/employee.js b/erpnext/hr/doctype/employee/employee.js
index 98f9f6e..0a8d9a1 100755
--- a/erpnext/hr/doctype/employee/employee.js
+++ b/erpnext/hr/doctype/employee/employee.js
@@ -58,6 +58,15 @@
},
update_contact:function(frm){
frm.set_value("prefered_email",frm.fields_dict[frappe.model.scrub(frm.doc.prefered_contact_email)].value)
- }
+ },
+ status: function(frm) {
+ return frm.call({
+ method: "deactivate_sales_person",
+ args: {
+ employee: frm.doc.employee,
+ status: frm.doc.status
+ }
+ });
+ },
});
cur_frm.cscript = new erpnext.hr.EmployeeController({frm: cur_frm});
diff --git a/erpnext/hr/doctype/employee/employee.py b/erpnext/hr/doctype/employee/employee.py
index e2e541b..58d1262 100755
--- a/erpnext/hr/doctype/employee/employee.py
+++ b/erpnext/hr/doctype/employee/employee.py
@@ -244,3 +244,9 @@
if holiday_list:
return frappe.get_all('Holiday List', dict(name=holiday_list, holiday_date=date)) and True or False
+@frappe.whitelist()
+def deactivate_sales_person(status = None, employee = None):
+ if status == "Left":
+ sales_person = frappe.db.get_value("Sales Person", {"Employee": employee})
+ if sales_person:
+ frappe.db.set_value("Sales Person", sales_person, "enabled", 0)
diff --git a/erpnext/hr/doctype/salary_slip/salary_slip.py b/erpnext/hr/doctype/salary_slip/salary_slip.py
index 95bea7a..ffd1136 100644
--- a/erpnext/hr/doctype/salary_slip/salary_slip.py
+++ b/erpnext/hr/doctype/salary_slip/salary_slip.py
@@ -222,7 +222,6 @@
["date_of_joining", "relieving_date"])
holidays = self.get_holidays_for_employee(self.start_date, self.end_date)
-
working_days = date_diff(self.end_date, self.start_date) + 1
if not cint(frappe.db.get_value("HR Settings", None, "include_holidays_in_total_working_days")):
working_days -= len(holidays)
diff --git a/erpnext/hr/doctype/salary_structure/test_salary_structure.py b/erpnext/hr/doctype/salary_structure/test_salary_structure.py
index 9217c64..fe88d9a 100644
--- a/erpnext/hr/doctype/salary_structure/test_salary_structure.py
+++ b/erpnext/hr/doctype/salary_structure/test_salary_structure.py
@@ -6,12 +6,15 @@
import unittest
import erpnext
from frappe.utils.make_random import get_random
-from frappe.utils import nowdate, add_days, add_years
+from frappe.utils import nowdate, add_days, add_years, getdate
from erpnext.hr.doctype.salary_structure.salary_structure import make_salary_slip
-from erpnext.hr.doctype.salary_slip.test_salary_slip import make_earning_salary_component, make_deduction_salary_component
+from erpnext.hr.doctype.salary_slip.test_salary_slip \
+ import make_earning_salary_component, make_deduction_salary_component
+
+test_dependencies = ["Fiscal Year"]
class TestSalaryStructure(unittest.TestCase):
- def test_setup(self):
+ def setUp(self):
self.make_holiday_list()
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"])
diff --git a/erpnext/schools/doctype/student_batch_attendance_tool/__init__.py b/erpnext/hr/doctype/training_event/__init__.py
similarity index 100%
copy from erpnext/schools/doctype/student_batch_attendance_tool/__init__.py
copy to erpnext/hr/doctype/training_event/__init__.py
diff --git a/erpnext/hr/doctype/training_event/test_training_event.py b/erpnext/hr/doctype/training_event/test_training_event.py
new file mode 100644
index 0000000..03416ee
--- /dev/null
+++ b/erpnext/hr/doctype/training_event/test_training_event.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('Training Event')
+
+class TestTrainingEvent(unittest.TestCase):
+ pass
diff --git a/erpnext/hr/doctype/training_event/training_event.js b/erpnext/hr/doctype/training_event/training_event.js
new file mode 100644
index 0000000..ebe0c79
--- /dev/null
+++ b/erpnext/hr/doctype/training_event/training_event.js
@@ -0,0 +1,21 @@
+// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Training Event', {
+ refresh: function(frm) {
+ if(!frm.doc.__islocal) {
+ frm.add_custom_button(__("Training Result"), function() {
+ frappe.route_options = {
+ training_event: frm.doc.name
+ }
+ frappe.set_route("List", "Training Result");
+ });
+ frm.add_custom_button(__("Training Feedback"), function() {
+ frappe.route_options = {
+ training_event: frm.doc.name
+ }
+ frappe.set_route("List", "Training Feedback");
+ });
+ }
+ }
+});
diff --git a/erpnext/hr/doctype/training_event/training_event.json b/erpnext/hr/doctype/training_event/training_event.json
new file mode 100644
index 0000000..168943d
--- /dev/null
+++ b/erpnext/hr/doctype/training_event/training_event.json
@@ -0,0 +1,679 @@
+{
+ "allow_copy": 0,
+ "allow_import": 1,
+ "allow_rename": 1,
+ "autoname": "field:event_name",
+ "beta": 0,
+ "creation": "2016-08-08 04:53:58.355206",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "fields": [
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "event_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": "Event 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": 1,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "event_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": "Event Status",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Scheduled\nCompleted\nCancelled",
+ "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,
+ "fieldname": "type",
+ "fieldtype": "Select",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Type",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Seminar\nTheory\nWorkshop\nConference\nExam\nInternet",
+ "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,
+ "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": "trainer_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": "Trainer Name",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "trainer_email",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Trainer Email",
+ "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": "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": "supplier",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Supplier",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Supplier",
+ "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": "contact_number",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Contact Number",
+ "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_9",
+ "fieldtype": "Section 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": "course",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Course",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Course",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 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": "location",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Location",
+ "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_12",
+ "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": "start_time",
+ "fieldtype": "Datetime",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Start Time",
+ "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": "end_time",
+ "fieldtype": "Datetime",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "End Time",
+ "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": "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,
+ "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": "introduction",
+ "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": "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": "section_break_18",
+ "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": "Attendees",
+ "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,
+ "description": "Will send an email about the event to employees with status 'Open'",
+ "fieldname": "send_email",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Send Email",
+ "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": "employees",
+ "fieldtype": "Table",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Employees",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Training Event Employee",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "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": "Training Event",
+ "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-12-14 11:46:25.712779",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Training Event",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "amend": 1,
+ "apply_user_permissions": 0,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 1,
+ "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": 1,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "search_fields": "event_name",
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "title_field": "event_name",
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/training_event/training_event.py b/erpnext/hr/doctype/training_event/training_event.py
new file mode 100644
index 0000000..c9be3dd
--- /dev/null
+++ b/erpnext/hr/doctype/training_event/training_event.py
@@ -0,0 +1,27 @@
+# -*- 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 import _
+from frappe.model.document import Document
+
+class TrainingEvent(Document):
+ def validate(self):
+ if self.event_status == "Scheduled":
+ self.invite_employee()
+
+ def on_update_after_submit(self):
+ if self.event_status == "Scheduled" and self.send_email:
+ self.invite_employee()
+
+ def invite_employee(self):
+ subject = _("""You are invited for to attend {0} - {1} scheduled from {2} to {3} at {4}."""\
+ .format(self.type, self.event_name, self.start_time, self.end_time, self.location))
+
+ for emp in self.employees:
+ if emp.status== "Open":
+ frappe.sendmail(frappe.db.get_value("Employee", emp.employee, "company_email"), \
+ subject=subject, content= self.introduction)
+ emp.status= "Invited"
\ No newline at end of file
diff --git a/erpnext/schools/doctype/student_batch_attendance_tool/__init__.py b/erpnext/hr/doctype/training_event_employee/__init__.py
similarity index 100%
copy from erpnext/schools/doctype/student_batch_attendance_tool/__init__.py
copy to erpnext/hr/doctype/training_event_employee/__init__.py
diff --git a/erpnext/hr/doctype/training_event_employee/training_event_employee.json b/erpnext/hr/doctype/training_event_employee/training_event_employee.json
new file mode 100644
index 0000000..575d0e7
--- /dev/null
+++ b/erpnext/hr/doctype/training_event_employee/training_event_employee.json
@@ -0,0 +1,152 @@
+{
+ "allow_copy": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "beta": 0,
+ "creation": "2016-08-08 05:33:39.965305",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "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": 1,
+ "in_standard_filter": 0,
+ "label": "Employee",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Employee",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "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": "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": 1,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "Open",
+ "fieldname": "status",
+ "fieldtype": "Select",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Status",
+ "length": 0,
+ "no_copy": 1,
+ "options": "Open\nInvited\nConfirmed\nAttended\nWithdrawn",
+ "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": 1,
+ "max_attachments": 0,
+ "modified": "2016-12-14 11:43:40.996578",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Training Event Employee",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "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/schools/doctype/student_batch_attendance_tool/student_batch_attendance_tool.py b/erpnext/hr/doctype/training_event_employee/training_event_employee.py
similarity index 84%
rename from erpnext/schools/doctype/student_batch_attendance_tool/student_batch_attendance_tool.py
rename to erpnext/hr/doctype/training_event_employee/training_event_employee.py
index 49a5ae8..234e958 100644
--- a/erpnext/schools/doctype/student_batch_attendance_tool/student_batch_attendance_tool.py
+++ b/erpnext/hr/doctype/training_event_employee/training_event_employee.py
@@ -6,5 +6,5 @@
import frappe
from frappe.model.document import Document
-class StudentBatchAttendanceTool(Document):
+class TrainingEventEmployee(Document):
pass
diff --git a/erpnext/schools/doctype/student_batch_attendance_tool/__init__.py b/erpnext/hr/doctype/training_feedback/__init__.py
similarity index 100%
copy from erpnext/schools/doctype/student_batch_attendance_tool/__init__.py
copy to erpnext/hr/doctype/training_feedback/__init__.py
diff --git a/erpnext/hr/doctype/training_feedback/test_training_feedback.py b/erpnext/hr/doctype/training_feedback/test_training_feedback.py
new file mode 100644
index 0000000..3455998
--- /dev/null
+++ b/erpnext/hr/doctype/training_feedback/test_training_feedback.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('Training Feedback')
+
+class TestTrainingFeedback(unittest.TestCase):
+ pass
diff --git a/erpnext/hr/doctype/training_feedback/training_feedback.js b/erpnext/hr/doctype/training_feedback/training_feedback.js
new file mode 100644
index 0000000..0dea098
--- /dev/null
+++ b/erpnext/hr/doctype/training_feedback/training_feedback.js
@@ -0,0 +1,10 @@
+// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Training Feedback', {
+ onload: function(frm) {
+ frm.add_fetch("training_event", "course", "course");
+ frm.add_fetch("training_event", "event_name", "event_name");
+ frm.add_fetch("training_event", "trainer_name", "trainer_name");
+ }
+});
\ No newline at end of file
diff --git a/erpnext/hr/doctype/training_feedback/training_feedback.json b/erpnext/hr/doctype/training_feedback/training_feedback.json
new file mode 100644
index 0000000..932d4a7
--- /dev/null
+++ b/erpnext/hr/doctype/training_feedback/training_feedback.json
@@ -0,0 +1,354 @@
+{
+ "allow_copy": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "autoname": "Feedback.####",
+ "beta": 0,
+ "creation": "2016-08-08 06:35:34.158568",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "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,
+ "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,
+ "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": "course",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Course",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Course",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "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_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,
+ "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": "training_event",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Training Event",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Training Event",
+ "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,
+ "columns": 0,
+ "fieldname": "event_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": "Event Name",
+ "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,
+ "columns": 0,
+ "fieldname": "trainer_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": "Trainer Name",
+ "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,
+ "columns": 0,
+ "fieldname": "section_break_6",
+ "fieldtype": "Section 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,
+ "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": "feedback",
+ "fieldtype": "Text",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Feedback",
+ "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,
+ "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": "Training Feedback",
+ "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-11-04 08:53:24.731178",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Training Feedback",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "amend": 1,
+ "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": 0,
+ "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,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "title_field": "employee_name",
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/schools/doctype/student_batch_attendance_tool/student_batch_attendance_tool.py b/erpnext/hr/doctype/training_feedback/training_feedback.py
similarity index 84%
copy from erpnext/schools/doctype/student_batch_attendance_tool/student_batch_attendance_tool.py
copy to erpnext/hr/doctype/training_feedback/training_feedback.py
index 49a5ae8..2a0403b 100644
--- a/erpnext/schools/doctype/student_batch_attendance_tool/student_batch_attendance_tool.py
+++ b/erpnext/hr/doctype/training_feedback/training_feedback.py
@@ -6,5 +6,5 @@
import frappe
from frappe.model.document import Document
-class StudentBatchAttendanceTool(Document):
+class TrainingFeedback(Document):
pass
diff --git a/erpnext/schools/doctype/student_batch_attendance_tool/__init__.py b/erpnext/hr/doctype/training_result/__init__.py
similarity index 100%
copy from erpnext/schools/doctype/student_batch_attendance_tool/__init__.py
copy to erpnext/hr/doctype/training_result/__init__.py
diff --git a/erpnext/hr/doctype/training_result/test_training_result.py b/erpnext/hr/doctype/training_result/test_training_result.py
new file mode 100644
index 0000000..29ed2a0
--- /dev/null
+++ b/erpnext/hr/doctype/training_result/test_training_result.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('Training Result')
+
+class TestTrainingResult(unittest.TestCase):
+ pass
diff --git a/erpnext/hr/doctype/training_result/training_result.js b/erpnext/hr/doctype/training_result/training_result.js
new file mode 100644
index 0000000..3a3d70a
--- /dev/null
+++ b/erpnext/hr/doctype/training_result/training_result.js
@@ -0,0 +1,32 @@
+// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Training Result', {
+ onload: function(frm) {
+ if (frm.doc.training_event) {
+ frm.trigger("training_event");
+ }
+ },
+
+ training_event: function(frm) {
+ if (frm.doc.training_event) {
+ frappe.call({
+ method: "erpnext.hr.doctype.training_result.training_result.get_employees",
+ args: {
+ "training_event": frm.doc.training_event
+ },
+ callback: function(r) {
+ frm.set_value("employees" ,"");
+ if (r.message) {
+ $.each(r.message, function(i, d) {
+ var row = frappe.model.add_child(cur_frm.doc, "Training Result Employee", "employees");
+ row.employee = d.employee;
+ row.employee_name = d.employee_name;
+ });
+ }
+ refresh_field("employees");
+ }
+ });
+ }
+ }
+});
diff --git a/erpnext/hr/doctype/training_result/training_result.json b/erpnext/hr/doctype/training_result/training_result.json
new file mode 100644
index 0000000..52b9a16
--- /dev/null
+++ b/erpnext/hr/doctype/training_result/training_result.json
@@ -0,0 +1,171 @@
+{
+ "allow_copy": 0,
+ "allow_import": 0,
+ "allow_rename": 1,
+ "autoname": "TRES.#####",
+ "beta": 0,
+ "creation": "2016-11-04 02:13:48.407576",
+ "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": "training_event",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Training Event",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Training Event",
+ "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": 1
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "section_break_3",
+ "fieldtype": "Section 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,
+ "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": "employees",
+ "fieldtype": "Table",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Employees",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Training Result Employee",
+ "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,
+ "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": "Training Result",
+ "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-11-04 08:53:48.597031",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Training Result",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "amend": 1,
+ "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,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "title_field": "training_event",
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/training_result/training_result.py b/erpnext/hr/doctype/training_result/training_result.py
new file mode 100644
index 0000000..16b76a7
--- /dev/null
+++ b/erpnext/hr/doctype/training_result/training_result.py
@@ -0,0 +1,23 @@
+# -*- 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 import _
+from frappe.model.document import Document
+
+class TrainingResult(Document):
+ def on_submit(self):
+ self.send_result()
+
+ def send_result(self):
+ for emp in self.employees:
+ message = "Thank You for attending {0}. You grade is {1}".format(self.training_event, emp.grade)
+ frappe.sendmail(frappe.db.get_value("Employee", emp.employee, "company_email"), \
+ subject=_("{0} Results".format(self.training_event)), \
+ content=message)
+
+@frappe.whitelist()
+def get_employees(training_event):
+ return frappe.get_doc("Training Event", training_event).employees
diff --git a/erpnext/schools/doctype/student_batch_attendance_tool/__init__.py b/erpnext/hr/doctype/training_result_employee/__init__.py
similarity index 100%
copy from erpnext/schools/doctype/student_batch_attendance_tool/__init__.py
copy to erpnext/hr/doctype/training_result_employee/__init__.py
diff --git a/erpnext/hr/doctype/training_result_employee/training_result_employee.json b/erpnext/hr/doctype/training_result_employee/training_result_employee.json
new file mode 100644
index 0000000..477a8e6
--- /dev/null
+++ b/erpnext/hr/doctype/training_result_employee/training_result_employee.json
@@ -0,0 +1,254 @@
+{
+ "allow_copy": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "beta": 0,
+ "creation": "2016-11-04 02:39:12.825569",
+ "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": "employee",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 1,
+ "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,
+ "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,
+ "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_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,
+ "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": "section_break_5",
+ "fieldtype": "Section 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,
+ "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": "hours",
+ "fieldtype": "Float",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Hours",
+ "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": 1,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "grade",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Grade",
+ "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,
+ "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,
+ "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": "comments",
+ "fieldtype": "Text",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Comments",
+ "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
+ }
+ ],
+ "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": "2016-11-04 03:31:08.624394",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Training Result Employee",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "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/schools/doctype/student_batch_attendance_tool/student_batch_attendance_tool.py b/erpnext/hr/doctype/training_result_employee/training_result_employee.py
similarity index 84%
copy from erpnext/schools/doctype/student_batch_attendance_tool/student_batch_attendance_tool.py
copy to erpnext/hr/doctype/training_result_employee/training_result_employee.py
index 49a5ae8..54e2a18 100644
--- a/erpnext/schools/doctype/student_batch_attendance_tool/student_batch_attendance_tool.py
+++ b/erpnext/hr/doctype/training_result_employee/training_result_employee.py
@@ -6,5 +6,5 @@
import frappe
from frappe.model.document import Document
-class StudentBatchAttendanceTool(Document):
+class TrainingResultEmployee(Document):
pass
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index c4b66e7..aad8d42 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -354,4 +354,7 @@
erpnext.patches.v7_0.update_autoname_field
erpnext.patches.v7_1.update_bom_base_currency
erpnext.patches.v7_0.update_status_of_po_so
-erpnext.patches.v7_1.set_budget_against_as_cost_center
\ No newline at end of file
+erpnext.patches.v7_1.set_budget_against_as_cost_center
+erpnext.patches.v7_1.set_currency_exchange_date
+erpnext.patches.v7_1.set_sales_person_status
+erpnext.patches.v7_1.repost_stock_for_deleted_bins_for_merging_items
diff --git a/erpnext/patches/v6_16/update_billing_status_in_dn_and_pr.py b/erpnext/patches/v6_16/update_billing_status_in_dn_and_pr.py
index b660d39..481f130 100644
--- a/erpnext/patches/v6_16/update_billing_status_in_dn_and_pr.py
+++ b/erpnext/patches/v6_16/update_billing_status_in_dn_and_pr.py
@@ -22,7 +22,7 @@
# Update billed_amt in DN and PR which are not against any order
for d in frappe.db.sql("""select name from `tabPurchase Receipt Item` item
- where (prevdoc_detail_docname is null or prevdoc_detail_docname = '') and docstatus=1""", as_dict=1):
+ where (purchase_order_item is null or purchase_order_item = '') and docstatus=1""", as_dict=1):
billed_amt = frappe.db.sql("""select sum(amount) from `tabPurchase Invoice Item`
where pr_detail=%s and docstatus=1""", d.name)
diff --git a/erpnext/patches/v7_0/update_status_of_po_so.py b/erpnext/patches/v7_0/update_status_of_po_so.py
index 0e2dd74..c0b6f59 100644
--- a/erpnext/patches/v7_0/update_status_of_po_so.py
+++ b/erpnext/patches/v7_0/update_status_of_po_so.py
@@ -18,9 +18,9 @@
`tabPurchase Order`.per_received = round((select sum(if(qty > ifnull(received_qty, 0),
ifnull(received_qty, 0), qty)) / sum(qty) *100 from `tabPurchase Order Item`
where parent = `tabPurchase Order`.name), 2),
- `tabPurchase Order`.per_billed = round((select sum( if(amount > ifnull(billed_amt, 0),
+ `tabPurchase Order`.per_billed = ifnull(round((select sum( if(amount > ifnull(billed_amt, 0),
ifnull(billed_amt, 0), amount)) / sum(amount) *100 from `tabPurchase Order Item`
- where parent = `tabPurchase Order`.name), 2)""")
+ where parent = `tabPurchase Order`.name), 2), 0)""")
def update_so_per_delivered_per_billed():
frappe.db.sql("""
@@ -30,9 +30,9 @@
`tabSales Order`.per_delivered = round((select sum( if(qty > ifnull(delivered_qty, 0),
ifnull(delivered_qty, 0), qty)) / sum(qty) *100 from `tabSales Order Item`
where parent = `tabSales Order`.name), 2),
- `tabSales Order`.per_billed = round((select sum( if(amount > ifnull(billed_amt, 0),
+ `tabSales Order`.per_billed = ifnull(round((select sum( if(amount > ifnull(billed_amt, 0),
ifnull(billed_amt, 0), amount)) / sum(amount) *100 from `tabSales Order Item`
- where parent = `tabSales Order`.name), 2)""")
+ where parent = `tabSales Order`.name), 2), 0)""")
def update_status():
frappe.db.sql("""
diff --git a/erpnext/patches/v7_1/repost_stock_for_deleted_bins_for_merging_items.py b/erpnext/patches/v7_1/repost_stock_for_deleted_bins_for_merging_items.py
new file mode 100644
index 0000000..5c63c00
--- /dev/null
+++ b/erpnext/patches/v7_1/repost_stock_for_deleted_bins_for_merging_items.py
@@ -0,0 +1,41 @@
+from __future__ import unicode_literals
+import frappe
+from erpnext.stock.stock_balance import repost_stock
+
+def execute():
+ modified_items = frappe.db.sql_list("""
+ select name from `tabItem`
+ where is_stock_item=1 and modified >= '2016-10-31'
+ """)
+
+ if not modified_items:
+ return
+
+ item_warehouses_with_transactions = []
+ transactions = ("Sales Order Item", "Material Request Item", "Purchase Order Item",
+ "Stock Ledger Entry", "Packed Item")
+
+ for doctype in transactions:
+ item_warehouses_with_transactions += list(frappe.db.sql("""
+ select distinct item_code, warehouse
+ from `tab{0}` where docstatus=1 and item_code in ({1})"""
+ .format(doctype, ', '.join(['%s']*len(modified_items))), tuple(modified_items)))
+
+ item_warehouses_with_transactions += list(frappe.db.sql("""
+ select distinct production_item, fg_warehouse
+ from `tabProduction Order` where docstatus=1 and production_item in ({0})"""
+ .format(', '.join(['%s']*len(modified_items))), tuple(modified_items)))
+
+ item_warehouses_with_transactions += list(frappe.db.sql("""
+ select distinct pr_item.item_code, pr.source_warehouse
+ from `tabProduction Order` pr, `tabProduction Order Item` pr_item
+ where pr_item.parent and pr.name and pr.docstatus=1 and pr_item.item_code in ({0})"""
+ .format(', '.join(['%s']*len(modified_items))), tuple(modified_items)))
+
+ item_warehouses_with_bin = list(frappe.db.sql("select distinct item_code, warehouse from `tabBin`"))
+
+ item_warehouses_with_missing_bin = list(
+ set(item_warehouses_with_transactions) - set(item_warehouses_with_bin))
+
+ for item_code, warehouse in item_warehouses_with_missing_bin:
+ repost_stock(item_code, warehouse)
diff --git a/erpnext/patches/v7_1/set_currency_exchange_date.py b/erpnext/patches/v7_1/set_currency_exchange_date.py
new file mode 100644
index 0000000..7d8e4f0
--- /dev/null
+++ b/erpnext/patches/v7_1/set_currency_exchange_date.py
@@ -0,0 +1,9 @@
+import frappe
+
+def execute():
+ frappe.reload_doctype("Currency Exchange")
+ frappe.db.sql("""
+ update `tabCurrency Exchange`
+ set `date` = '2010-01-01'
+ where date is null or date = '' or date = '0000-00-00'
+ """)
\ No newline at end of file
diff --git a/erpnext/patches/v7_1/set_sales_person_status.py b/erpnext/patches/v7_1/set_sales_person_status.py
new file mode 100644
index 0000000..929beac
--- /dev/null
+++ b/erpnext/patches/v7_1/set_sales_person_status.py
@@ -0,0 +1,8 @@
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+ frappe.reload_doc('setup','doctype','sales_person')
+ frappe.db.sql("""update `tabSales Person` set enabled=1
+ where (employee is null or employee = ''
+ or employee IN (select employee from tabEmployee where status != "Left"))""")
diff --git a/erpnext/projects/doctype/activity_type/activity_type.json b/erpnext/projects/doctype/activity_type/activity_type.json
index fb6d1b2..65a0fa1 100644
--- a/erpnext/projects/doctype/activity_type/activity_type.json
+++ b/erpnext/projects/doctype/activity_type/activity_type.json
@@ -15,6 +15,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"fieldname": "activity_type",
"fieldtype": "Data",
"hidden": 0,
@@ -22,6 +23,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Activity Type",
"length": 0,
"no_copy": 0,
@@ -29,6 +31,7 @@
"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,
@@ -39,6 +42,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"fieldname": "costing_rate",
"fieldtype": "Currency",
"hidden": 0,
@@ -46,6 +50,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Default Costing Rate",
"length": 0,
"no_copy": 0,
@@ -54,6 +59,7 @@
"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,
@@ -64,6 +70,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"fieldname": "column_break_3",
"fieldtype": "Column Break",
"hidden": 0,
@@ -71,6 +78,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -78,6 +86,7 @@
"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,
@@ -88,6 +97,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"fieldname": "billing_rate",
"fieldtype": "Currency",
"hidden": 0,
@@ -95,6 +105,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Default Billing Rate",
"length": 0,
"no_copy": 0,
@@ -103,6 +114,7 @@
"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,
@@ -112,7 +124,7 @@
],
"hide_heading": 0,
"hide_toolbar": 0,
- "icon": "fa fa-flag",
+ "icon": "icon-flag",
"idx": 1,
"image_view": 0,
"in_create": 0,
@@ -121,7 +133,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2016-08-22 08:53:43.680463",
+ "modified": "2016-12-13 12:38:18.218618",
"modified_by": "Administrator",
"module": "Projects",
"name": "Activity Type",
@@ -137,6 +149,7 @@
"export": 1,
"if_owner": 0,
"import": 1,
+ "is_custom": 0,
"permlevel": 0,
"print": 1,
"read": 1,
@@ -157,6 +170,7 @@
"export": 0,
"if_owner": 0,
"import": 0,
+ "is_custom": 0,
"permlevel": 0,
"print": 1,
"read": 1,
@@ -166,6 +180,27 @@
"share": 1,
"submit": 0,
"write": 1
+ },
+ {
+ "amend": 0,
+ "apply_user_permissions": 0,
+ "cancel": 0,
+ "create": 0,
+ "delete": 0,
+ "email": 0,
+ "export": 0,
+ "if_owner": 0,
+ "import": 0,
+ "is_custom": 0,
+ "permlevel": 0,
+ "print": 0,
+ "read": 1,
+ "report": 0,
+ "role": "Employee",
+ "set_user_permissions": 0,
+ "share": 0,
+ "submit": 0,
+ "write": 0
}
],
"quick_entry": 1,
diff --git a/erpnext/projects/doctype/task/task.js b/erpnext/projects/doctype/task/task.js
index c6b6664..7c4eb80 100644
--- a/erpnext/projects/doctype/task/task.js
+++ b/erpnext/projects/doctype/task/task.js
@@ -67,4 +67,12 @@
});
+cur_frm.fields_dict['depends_on'].grid.get_field('task').get_query = function(doc) {
+ if(doc.project) {
+ return {
+ filters: {'project': doc.project}
+ }
+ }
+}
+
cur_frm.add_fetch('task', 'subject', 'subject');
diff --git a/erpnext/public/build.json b/erpnext/public/build.json
index ac1c7c3..30b0900 100644
--- a/erpnext/public/build.json
+++ b/erpnext/public/build.json
@@ -1,37 +1,38 @@
{
- "css/erpnext.css": [
- "public/css/erpnext.css"
- ],
- "js/erpnext-web.min.js": [
- "public/js/website_utils.js",
- "public/js/shopping_cart.js"
- ],
- "js/erpnext.min.js": [
- "public/js/conf.js",
- "public/js/utils.js",
- "public/js/queries.js",
- "public/js/sms_manager.js",
- "public/js/utils/party.js",
- "public/js/templates/address_list.html",
- "public/js/templates/contact_list.html",
- "public/js/controllers/stock_controller.js",
- "public/js/payment/payments.js",
- "public/js/controllers/taxes_and_totals.js",
- "public/js/controllers/transaction.js",
- "public/js/pos/pos.html",
- "public/js/pos/pos_bill_item.html",
- "public/js/pos/pos_item.html",
- "public/js/pos/pos_tax_row.html",
- "public/js/pos/pos_invoice_list.html",
- "public/js/payment/pos_payment.html",
- "public/js/payment/payment_details.html",
- "public/js/templates/item_selector.html",
- "public/js/utils/item_selector.js",
- "public/js/help_links.js"
- ],
- "js/item-dashboard.min.js": [
- "stock/dashboard/item_dashboard.html",
- "stock/dashboard/item_dashboard_list.html",
- "stock/dashboard/item_dashboard.js"
- ]
-}
+ "css/erpnext.css": [
+ "public/css/erpnext.css"
+ ],
+ "js/erpnext-web.min.js": [
+ "public/js/website_utils.js",
+ "public/js/shopping_cart.js"
+ ],
+ "js/erpnext.min.js": [
+ "public/js/conf.js",
+ "public/js/utils.js",
+ "public/js/queries.js",
+ "public/js/sms_manager.js",
+ "public/js/utils/party.js",
+ "public/js/templates/address_list.html",
+ "public/js/templates/contact_list.html",
+ "public/js/controllers/stock_controller.js",
+ "public/js/payment/payments.js",
+ "public/js/controllers/taxes_and_totals.js",
+ "public/js/controllers/transaction.js",
+ "public/js/pos/pos.html",
+ "public/js/pos/pos_bill_item.html",
+ "public/js/pos/pos_item.html",
+ "public/js/pos/pos_tax_row.html",
+ "public/js/pos/pos_invoice_list.html",
+ "public/js/payment/pos_payment.html",
+ "public/js/payment/payment_details.html",
+ "public/js/templates/item_selector.html",
+ "public/js/utils/item_selector.js",
+ "public/js/help_links.js",
+ "public/js/schools/student_button.html"
+ ],
+ "js/item-dashboard.min.js": [
+ "stock/dashboard/item_dashboard.html",
+ "stock/dashboard/item_dashboard_list.html",
+ "stock/dashboard/item_dashboard.js"
+ ]
+}
\ No newline at end of file
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index 954b03b..dcbb56b 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -413,6 +413,7 @@
transaction_date: function() {
if (this.frm.doc.transaction_date) {
this.frm.transaction_date = this.frm.doc.transaction_date;
+ frappe.ui.form.trigger(this.frm.doc.doctype, "currency");
}
},
@@ -434,9 +435,12 @@
callback: function(r, rt) {
if(r.message) {
me.frm.set_value("due_date", r.message);
+ frappe.ui.form.trigger(me.frm.doc.doctype, "currency");
}
}
})
+ } else {
+ frappe.ui.form.trigger(me.frm.doc.doctype, "currency");
}
}
},
@@ -450,6 +454,10 @@
},
currency: function() {
+ /* manqala 19/09/2016: let the translation date be whichever of the transaction_date or posting_date is available */
+ var transaction_date = this.frm.doc.transaction_date || this.frm.doc.posting_date;
+ /* end manqala */
+
var me = this;
this.set_dynamic_labels();
@@ -457,7 +465,7 @@
// Added `ignore_pricing_rule` to determine if document is loading after mapping from another doc
if(this.frm.doc.currency && this.frm.doc.currency !== company_currency
&& !this.frm.doc.ignore_pricing_rule) {
- this.get_exchange_rate(this.frm.doc.currency, company_currency,
+ this.get_exchange_rate(transaction_date, this.frm.doc.currency, company_currency,
function(exchange_rate) {
me.frm.set_value("conversion_rate", exchange_rate);
});
@@ -485,10 +493,11 @@
}
},
- get_exchange_rate: function(from_currency, to_currency, callback) {
+ get_exchange_rate: function(transaction_date, from_currency, to_currency, callback) {
return frappe.call({
method: "erpnext.setup.utils.get_exchange_rate",
args: {
+ transaction_date: transaction_date,
from_currency: from_currency,
to_currency: to_currency
},
@@ -505,7 +514,7 @@
var company_currency = this.get_company_currency();
// Added `ignore_pricing_rule` to determine if document is loading after mapping from another doc
if(this.frm.doc.price_list_currency !== company_currency && !this.frm.doc.ignore_pricing_rule) {
- this.get_exchange_rate(this.frm.doc.price_list_currency, company_currency,
+ this.get_exchange_rate(this.frm.doc.posting_date, this.frm.doc.price_list_currency, company_currency,
function(exchange_rate) {
me.frm.set_value("plc_conversion_rate", exchange_rate);
});
@@ -893,13 +902,17 @@
get_terms: function() {
var me = this;
if(this.frm.doc.tc_name) {
- return this.frm.call({
- method: "frappe.client.get_value",
+ return frappe.call({
+ method: 'erpnext.setup.doctype.terms_and_conditions.terms_and_conditions.get_terms_and_conditions',
args: {
- doctype: "Terms and Conditions",
- fieldname: "terms",
- filters: { name: this.frm.doc.tc_name },
+ template_name: this.frm.doc.tc_name,
+ doc: this.frm.doc
},
+ callback: function(r) {
+ if(!r.exc) {
+ me.frm.set_value("terms", r.message);
+ }
+ }
});
}
},
diff --git a/erpnext/public/js/schools/student_button.html b/erpnext/public/js/schools/student_button.html
new file mode 100644
index 0000000..dabaf26
--- /dev/null
+++ b/erpnext/public/js/schools/student_button.html
@@ -0,0 +1,20 @@
+<div class="col-sm-3">
+ <div class="checkbox {% if status %} text-muted {% endif %}">
+ <label>
+ <input
+ type="checkbox"
+ data-idx="{{idx}}"
+ data-student="{{student}}"
+ data-student-name="{{student_name}}"
+ class="students-check"
+ {% if status %}
+ disabled="true"
+ {% endif %}
+ {% if status === "Present" %}
+ checked
+ {% endif %}
+ >
+ {{ idx }} - {{ student_name }}
+ </label>
+ </div>
+</div>
\ No newline at end of file
diff --git a/erpnext/schools/api.py b/erpnext/schools/api.py
index 7cb02a3..bf09351 100644
--- a/erpnext/schools/api.py
+++ b/erpnext/schools/api.py
@@ -52,8 +52,10 @@
:param student_batch: Student Batch.
:param date: Date.
"""
+
present = json.loads(students_present)
absent = json.loads(students_absent)
+
for d in present:
make_attendance_records(d["student"], d["student_name"], "Present", course_schedule, student_batch, date)
diff --git a/erpnext/schools/doctype/course/course.json b/erpnext/schools/doctype/course/course.json
index cd8362a..6fada19 100644
--- a/erpnext/schools/doctype/course/course.json
+++ b/erpnext/schools/doctype/course/course.json
@@ -219,7 +219,7 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
- "modified": "2016-11-07 05:28:55.089882",
+ "modified": "2016-08-08 05:26:26.442635",
"modified_by": "Administrator",
"module": "Schools",
"name": "Course",
@@ -246,6 +246,26 @@
"share": 1,
"submit": 0,
"write": 1
+ },
+ {
+ "amend": 0,
+ "apply_user_permissions": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "HR Manager",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
}
],
"quick_entry": 0,
diff --git a/erpnext/schools/doctype/course_schedule/course_schedule.js b/erpnext/schools/doctype/course_schedule/course_schedule.js
index 04a8cde..12e8522 100644
--- a/erpnext/schools/doctype/course_schedule/course_schedule.js
+++ b/erpnext/schools/doctype/course_schedule/course_schedule.js
@@ -1,134 +1,15 @@
frappe.provide("schools")
frappe.ui.form.on("Course Schedule", {
- onload: function(frm) {
- if (frm.doc.from_datetime && frm.doc.to_datetime) {
- var from_datetime = moment(frm.doc.from_datetime);
- var to_datetime = moment(frm.doc.to_datetime);
- frm.doc.schedule_date = from_datetime.format(moment.defaultFormat);
- frm.doc.from_time = from_datetime.format("HH:mm:ss");
- frm.doc.to_time = to_datetime.format("HH:mm:ss");
- }
- },
-
refresh: function(frm) {
- if (!frm.doc.__islocal && frm.doc.student_group) {
- frappe.call({
- method: "erpnext.schools.api.check_attendance_records_exist",
- args: {
- "course_schedule": frm.doc.name
- },
- callback: function(r) {
- if (r.message) {
- hide_field('attendance');
- frm.events.view_attendance(frm)
- } else {
- frappe.call({
- method: "erpnext.schools.api.get_student_group_students",
- args: {
- "student_group": frm.doc.student_group
- },
- callback: function(r) {
- if (r.message) {
- frm.events.get_students(frm, r.message)
- }
- }
- });
- }
+ if (!frm.doc.__islocal) {
+ frm.add_custom_button(__("Attendance"), function() {
+ frappe.route_options = {
+ based_on: "Course Schedule",
+ course_schedule: frm.doc.name
}
+ frappe.set_route("Form", "Student Attendance Tool");
});
- } else {
- hide_field('attendance');
}
- },
-
- view_attendance: function(frm) {
- hide_field('attendance');
- frm.add_custom_button(__("View attendance"), function() {
- frappe.route_options = {
- course_schedule: frm.doc.name
- }
- frappe.set_route("List", "Student Attendance");
- });
- },
-
- get_students: function(frm, students) {
- if (!frm.students_area) {
- frm.students_area = $('<div>')
- .appendTo(frm.fields_dict.students_html.wrapper);
- }
- frm.students_editor = new schools.StudentsEditor(frm, frm.students_area, students)
}
-});
-
-
-schools.StudentsEditor = Class.extend({
- init: function(frm, wrapper, students) {
- this.wrapper = wrapper;
- this.frm = frm;
- this.make(frm, students);
- },
- make: function(frm, students) {
- var me = this;
-
- $(this.wrapper).empty();
- var student_toolbar = $('<p>\
- <button class="btn btn-default btn-add btn-xs" style="margin-right: 5px;"></button>\
- <button class="btn btn-xs btn-default btn-remove" style="margin-right: 5px;"></button>\
- <button class="btn btn-default btn-primary btn-mark-att btn-xs"></button></p>').appendTo($(this.wrapper));
-
- student_toolbar.find(".btn-add")
- .html(__('Check all'))
- .on("click", function() {
- $(me.wrapper).find('input[type="checkbox"]').each(function(i, check) {
- if (!$(check).is(":checked")) {
- check.checked = true;
- }
- });
- });
-
- student_toolbar.find(".btn-remove")
- .html(__('Uncheck all'))
- .on("click", function() {
- $(me.wrapper).find('input[type="checkbox"]').each(function(i, check) {
- if ($(check).is(":checked")) {
- check.checked = false;
- }
- });
- });
-
- student_toolbar.find(".btn-mark-att")
- .html(__('Mark Attendence'))
- .on("click", function() {
- var students_present = [];
- var students_absent = [];
- $(me.wrapper).find('input[type="checkbox"]').each(function(i, check) {
- if ($(check).is(":checked")) {
- students_present.push(students[i]);
- } else {
- students_absent.push(students[i]);
- }
- });
- frappe.call({
- method: "erpnext.schools.api.mark_attendance",
- args: {
- "students_present": students_present,
- "students_absent": students_absent,
- "course_schedule": frm.doc.name
- },
- callback: function(r) {
- frm.events.view_attendance(frm)
- }
- });
- });
-
-
- $.each(students, function(i, m) {
- $(repl('<div class="col-sm-6">\
- <div class="checkbox">\
- <label><input type="checkbox" class="students-check" student="%(student)s">\
- %(student)s</label>\
- </div></div>', { student: m.student_name })).appendTo(me.wrapper);
- });
- }
-})
\ No newline at end of file
+});
\ No newline at end of file
diff --git a/erpnext/schools/doctype/course_schedule/course_schedule.json b/erpnext/schools/doctype/course_schedule/course_schedule.json
index 122285e..450d7cf 100644
--- a/erpnext/schools/doctype/course_schedule/course_schedule.json
+++ b/erpnext/schools/doctype/course_schedule/course_schedule.json
@@ -385,62 +385,6 @@
{
"allow_on_submit": 0,
"bold": 0,
- "collapsible": 1,
- "columns": 0,
- "fieldname": "attendance",
- "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": "Attendance",
- "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": "students_html",
- "fieldtype": "HTML",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Students HTML",
- "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": "title",
@@ -478,7 +422,7 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
- "modified": "2016-12-01 12:59:25.086606",
+ "modified": "2016-12-09 17:00:02.822788",
"modified_by": "Administrator",
"module": "Schools",
"name": "Course Schedule",
diff --git a/erpnext/schools/doctype/student_attendance/student_attendance.py b/erpnext/schools/doctype/student_attendance/student_attendance.py
index 45b3014..e2d01b5 100644
--- a/erpnext/schools/doctype/student_attendance/student_attendance.py
+++ b/erpnext/schools/doctype/student_attendance/student_attendance.py
@@ -31,9 +31,9 @@
(self.student, self.course_schedule, self.name))
else:
attendance_records= frappe.db.sql("""select name from `tabStudent Attendance` where \
- student= %s and date= %s and name != %s and docstatus=1 and \
+ student= %s and student_batch= %s and date= %s and name != %s and docstatus=1 and \
(course_schedule is Null or course_schedule='')""",
- (self.student, self.date, self.name))
+ (self.student, self.student_batch, self.date, self.name))
if attendance_records:
frappe.throw(_("Attendance Record {0} exists against Student {1}")
diff --git a/erpnext/schools/doctype/student_batch_attendance_tool/__init__.py b/erpnext/schools/doctype/student_attendance_tool/__init__.py
similarity index 100%
rename from erpnext/schools/doctype/student_batch_attendance_tool/__init__.py
rename to erpnext/schools/doctype/student_attendance_tool/__init__.py
diff --git a/erpnext/schools/doctype/student_attendance_tool/student_attendance_tool.js b/erpnext/schools/doctype/student_attendance_tool/student_attendance_tool.js
new file mode 100644
index 0000000..7dd9dda
--- /dev/null
+++ b/erpnext/schools/doctype/student_attendance_tool/student_attendance_tool.js
@@ -0,0 +1,150 @@
+// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+frappe.provide("schools")
+
+frappe.ui.form.on('Student Attendance Tool', {
+ refresh: function(frm) {
+ frm.disable_save();
+ },
+
+ based_on: function(frm) {
+ if (frm.doc.based_on == "Student Batch") {
+ frm.set_value("course_schedule", "");
+ } else {
+ frm.set_value("student_batch", "");
+ }
+ },
+
+ student_batch: function(frm) {
+ if ((frm.doc.student_batch && frm.doc.date) || frm.doc.course_schedule) {
+ var method = "erpnext.schools.doctype.student_attendance_tool.student_attendance_tool.get_student_attendance_records";
+
+ frappe.call({
+ method: method,
+ args: {
+ based_on: frm.doc.based_on,
+ student_batch: frm.doc.student_batch,
+ date: frm.doc.date,
+ course_schedule: frm.doc.course_schedule
+ },
+ callback: function(r) {
+ frm.events.get_students(frm, r.message);
+ }
+ })
+ }
+ },
+
+ date: function(frm) {
+ frm.trigger("student_batch");
+ },
+
+ course_schedule: function(frm) {
+ frm.trigger("student_batch");
+ },
+
+ get_students: function(frm, students) {
+ if (!frm.students_area) {
+ frm.students_area = $('<div>')
+ .appendTo(frm.fields_dict.students_html.wrapper);
+ }
+ frm.students_editor = new schools.StudentsEditor(frm, frm.students_area, students)
+ }
+});
+
+
+schools.StudentsEditor = Class.extend({
+ init: function(frm, wrapper, students) {
+ this.wrapper = wrapper;
+ this.frm = frm;
+ this.make(frm, students);
+ },
+ make: function(frm, students) {
+ var me = this;
+
+ $(this.wrapper).empty();
+ var student_toolbar = $('<p>\
+ <button class="btn btn-default btn-add btn-xs" style="margin-right: 5px;"></button>\
+ <button class="btn btn-xs btn-default btn-remove" style="margin-right: 5px;"></button>\
+ <button class="btn btn-default btn-primary btn-mark-att btn-xs"></button></p>').appendTo($(this.wrapper));
+
+ student_toolbar.find(".btn-add")
+ .html(__('Check all'))
+ .on("click", function() {
+ $(me.wrapper).find('input[type="checkbox"]').each(function(i, check) {
+ if (!$(check).prop("disabled")) {
+ check.checked = true;
+ }
+ });
+ });
+
+ student_toolbar.find(".btn-remove")
+ .html(__('Uncheck all'))
+ .on("click", function() {
+ $(me.wrapper).find('input[type="checkbox"]').each(function(i, check) {
+ if (!$(check).prop("disabled")) {
+ check.checked = false;
+ }
+ });
+ });
+
+ var get_present_student = function(student) {
+ return students.filter(function(s) {
+ return s.idx === idx;
+ })
+ }
+ var get_absent_student = function(idx) {
+ return students.filter(function(s) {
+ return s.idx === idx;
+ })
+ }
+
+ student_toolbar.find(".btn-mark-att")
+ .html(__('Mark Attendence'))
+ .on("click", function() {
+ var studs = [];
+ $(me.wrapper.find('input[type="checkbox"]')).each(function(i, check) {
+ var $check = $(check);
+ studs.push({
+ student: $check.data().student,
+ student_name: $check.data().studentName,
+ idx: $check.data().idx,
+ disabled: $check.prop("disabled"),
+ checked: $check.is(":checked")
+ });
+ });
+
+ var students_present = studs.filter(function(stud) {
+ return !stud.disabled && stud.checked;
+ });
+
+ var students_absent = studs.filter(function(stud) {
+ return !stud.disabled && !stud.checked;
+ });
+
+ frappe.call({
+ method: "erpnext.schools.api.mark_attendance",
+ args: {
+ "students_present": students_present,
+ "students_absent": students_absent,
+ "student_batch": frm.doc.student_batch,
+ "course_schedule": frm.doc.course_schedule,
+ "date": frm.doc.date
+ },
+ callback: function(r) {
+ frm.trigger("student_batch");
+ }
+ });
+ });
+
+ var htmls = students.map(function(student) {
+ return frappe.render_template("student_button", {
+ student: student.student,
+ student_name: student.student_name,
+ idx: student.idx,
+ status: student.status
+ })
+ });
+
+ $(htmls.join("")).appendTo(me.wrapper);
+ }
+});
\ No newline at end of file
diff --git a/erpnext/schools/doctype/student_batch_attendance_tool/student_batch_attendance_tool.json b/erpnext/schools/doctype/student_attendance_tool/student_attendance_tool.json
similarity index 72%
rename from erpnext/schools/doctype/student_batch_attendance_tool/student_batch_attendance_tool.json
rename to erpnext/schools/doctype/student_attendance_tool/student_attendance_tool.json
index defc886..092af04 100644
--- a/erpnext/schools/doctype/student_batch_attendance_tool/student_batch_attendance_tool.json
+++ b/erpnext/schools/doctype/student_attendance_tool/student_attendance_tool.json
@@ -16,18 +16,19 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "fieldname": "student_batch",
- "fieldtype": "Link",
+ "default": "",
+ "fieldname": "based_on",
+ "fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"in_standard_filter": 0,
- "label": "Student Batch",
+ "label": "Based On",
"length": 0,
"no_copy": 0,
- "options": "Student Batch",
+ "options": "Student Batch\nCourse Schedule",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -35,7 +36,7 @@
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
- "reqd": 1,
+ "reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
@@ -72,6 +73,67 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "depends_on": "eval:doc.based_on ==\"Student Batch\"",
+ "fieldname": "student_batch",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Student Batch",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Student Batch",
+ "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,
+ "depends_on": "eval:doc.based_on ==\"Course Schedule\"",
+ "fieldname": "course_schedule",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Course Schedule",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Course 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": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "depends_on": "eval:doc.based_on ==\"Student Batch\"",
"fieldname": "date",
"fieldtype": "Date",
"hidden": 0,
@@ -100,7 +162,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "depends_on": "",
+ "depends_on": "eval: (doc.course_schedule \n|| (doc.student_batch && doc.date))",
"fieldname": "attendance",
"fieldtype": "Section Break",
"hidden": 0,
@@ -163,10 +225,10 @@
"issingle": 1,
"istable": 0,
"max_attachments": 0,
- "modified": "2016-12-01 12:58:31.822014",
+ "modified": "2016-12-09 17:36:28.739318",
"modified_by": "Administrator",
"module": "Schools",
- "name": "Student Batch Attendance Tool",
+ "name": "Student Attendance Tool",
"name_case": "",
"owner": "Administrator",
"permissions": [
diff --git a/erpnext/schools/doctype/student_attendance_tool/student_attendance_tool.py b/erpnext/schools/doctype/student_attendance_tool/student_attendance_tool.py
new file mode 100644
index 0000000..30a692c
--- /dev/null
+++ b/erpnext/schools/doctype/student_attendance_tool/student_attendance_tool.py
@@ -0,0 +1,40 @@
+# -*- 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 StudentAttendanceTool(Document):
+ pass
+
+@frappe.whitelist()
+def get_student_attendance_records(based_on, date=None, student_batch=None, course_schedule=None):
+ student_list = []
+ student_attendance_list = []
+
+ if based_on=="Course Schedule":
+ student_group = frappe.db.get_value("Course Schedule", course_schedule, "student_group")
+ if student_group:
+ student_list = frappe.get_list("Student Group Student", fields=["student", "student_name", "idx"] , \
+ filters={"parent": student_group}, order_by= "idx")
+ else:
+ student_batch = frappe.db.get_value("Course Schedule", course_schedule, "student_batch")
+ if not student_list:
+ student_list = frappe.get_list("Student Batch Student", fields=["student", "student_name", "idx"] , filters={"parent": student_batch}, order_by= "idx")
+
+ if course_schedule:
+ student_attendance_list= frappe.db.sql("""select student, status from `tabStudent Attendance` where \
+ course_schedule= %s and docstatus=1""", (course_schedule), as_dict=1)
+ else:
+ student_attendance_list= frappe.db.sql("""select student, status from `tabStudent Attendance` where \
+ student_batch= %s and date= %s and docstatus=1 and \
+ (course_schedule is Null or course_schedule='')""",
+ (student_batch, date), as_dict=1)
+
+ for attendance in student_attendance_list:
+ for student in student_list:
+ if student.student == attendance.student:
+ student.status = attendance.status
+ return student_list
\ No newline at end of file
diff --git a/erpnext/schools/doctype/student_batch_attendance_tool/student_batch_attendance_tool.js b/erpnext/schools/doctype/student_batch_attendance_tool/student_batch_attendance_tool.js
deleted file mode 100644
index 2dc6a85..0000000
--- a/erpnext/schools/doctype/student_batch_attendance_tool/student_batch_attendance_tool.js
+++ /dev/null
@@ -1,136 +0,0 @@
-// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
-// For license information, please see license.txt
-frappe.provide("schools")
-
-frappe.ui.form.on('Student Batch Attendance Tool', {
- refresh: function(frm) {
- frm.disable_save();
- hide_field('attendance');
- },
-
- student_batch: function(frm) {
- if (frm.doc.student_batch && frm.doc.date) {
- frappe.call({
- method: "erpnext.schools.api.check_attendance_records_exist",
- args: {
- "student_batch": frm.doc.student_batch,
- "date": frm.doc.date
- },
- callback: function(r) {
- if (r.message) {
- frappe.msgprint("Attendance already marked.");
- hide_field('attendance');
- } else {
- frappe.call({
- method: "erpnext.schools.api.get_student_batch_students",
- args: {
- "student_batch": frm.doc.student_batch
- },
- callback: function(r) {
- if (r.message) {
- unhide_field('attendance');
- frm.events.get_students(frm, r.message)
- }
- }
- });
- }
- }
- });
- }
- },
-
- date: function(frm) {
- frm.trigger("student_batch");
- },
-
- get_students: function(frm, students) {
- if (!frm.students_area) {
- frm.students_area = $('<div>')
- .appendTo(frm.fields_dict.students_html.wrapper);
- }
- frm.students_editor = new schools.StudentsEditor(frm, frm.students_area, students)
- }
-});
-
-
-schools.StudentsEditor = Class.extend({
- init: function(frm, wrapper, students) {
- this.wrapper = wrapper;
- this.frm = frm;
- this.make(frm, students);
- },
- make: function(frm, students) {
- var me = this;
-
- $(this.wrapper).empty();
- var student_toolbar = $('<p>\
- <button class="btn btn-default btn-add btn-xs" style="margin-right: 5px;"></button>\
- <button class="btn btn-xs btn-default btn-remove" style="margin-right: 5px;"></button>\
- <button class="btn btn-default btn-primary btn-mark-att btn-xs"></button></p>').appendTo($(this.wrapper));
-
- student_toolbar.find(".btn-add")
- .html(__('Check all'))
- .on("click", function() {
- $(me.wrapper).find('input[type="checkbox"]').each(function(i, check) {
- if (!$(check).is(":checked")) {
- check.checked = true;
- }
- });
- });
-
- student_toolbar.find(".btn-remove")
- .html(__('Uncheck all'))
- .on("click", function() {
- $(me.wrapper).find('input[type="checkbox"]').each(function(i, check) {
- if ($(check).is(":checked")) {
- check.checked = false;
- }
- });
- });
-
- var get_student = function(idx) {
- return students.filter(function(s) {
- return s.idx === idx;
- })[0]
- }
-
- student_toolbar.find(".btn-mark-att")
- .html(__('Mark Attendence'))
- .on("click", function() {
- var students_present = [];
- var students_absent = [];
- $(me.wrapper).find('input[type="checkbox"]').each(function(i, check) {
- var idx = $(check).data().idx;
- if ($(check).is(":checked")) {
- students_present.push(get_student(idx));
- } else {
- students_absent.push(get_student(idx));
- }
- });
- frappe.call({
- method: "erpnext.schools.api.mark_attendance",
- args: {
- "students_present": students_present,
- "students_absent": students_absent,
- "student_batch": frm.doc.student_batch,
- "date": frm.doc.date
- },
- callback: function(r) {
- hide_field('attendance');
- }
- });
- });
-
-
- $.each(students, function(i, m) {
- $(repl('<div class="col-sm-6">\
- <div class="checkbox">\
- <label><input data-idx="%(idx)s" type="checkbox" class="students-check" data-student="%(name)s">\
- %(idx)s - %(name)s</label>\
- </div></div>', {
- name: m.student_name,
- idx: m.idx
- })).appendTo(me.wrapper);
- });
- }
-});
\ No newline at end of file
diff --git a/erpnext/setup/doctype/company/fixtures/india/__init__.py b/erpnext/setup/doctype/company/fixtures/india/__init__.py
index 2aeec99..0f4bd4f 100644
--- a/erpnext/setup/doctype/company/fixtures/india/__init__.py
+++ b/erpnext/setup/doctype/company/fixtures/india/__init__.py
@@ -7,9 +7,10 @@
def install(company):
docs = [
- {'doctype': 'Salary Component', 'salary_component': 'Professional Tax', 'description': 'Professional Tax'},
- {'doctype': 'Salary Component', 'salary_component': 'Provident Fund', 'description': 'Provident fund'},
- {'doctype': 'Salary Component', 'salary_component': 'House Rent Allowance', 'description': 'House Rent Allowance'}
+ {'doctype': 'Salary Component', 'salary_component': 'Professional Tax', 'description': 'Professional Tax', 'type': 'Deduction'},
+ {'doctype': 'Salary Component', 'salary_component': 'Provident Fund', 'description': 'Provident fund', 'type': 'Deduction'},
+ {'doctype': 'Salary Component', 'salary_component': 'House Rent Allowance', 'description': 'House Rent Allowance', 'type': 'Earning'},
+ {'doctype': 'Salary Component', 'salary_component': 'Basic', 'description': 'Basic', 'type': 'Earning'}
]
for d in docs:
diff --git a/erpnext/setup/doctype/currency_exchange/currency_exchange.json b/erpnext/setup/doctype/currency_exchange/currency_exchange.json
index 44cea20..76e1a6b 100644
--- a/erpnext/setup/doctype/currency_exchange/currency_exchange.json
+++ b/erpnext/setup/doctype/currency_exchange/currency_exchange.json
@@ -17,6 +17,33 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fieldname": "date",
+ "fieldtype": "Date",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 1,
+ "label": "Date",
+ "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,
+ "width": "5"
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
"fieldname": "from_currency",
"fieldtype": "Link",
"hidden": 0,
@@ -38,7 +65,8 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
- "unique": 0
+ "unique": 0,
+ "width": "3"
},
{
"allow_on_submit": 0,
@@ -66,7 +94,8 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
- "unique": 0
+ "unique": 0,
+ "width": "3"
},
{
"allow_on_submit": 0,
@@ -94,7 +123,8 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
- "unique": 0
+ "unique": 0,
+ "width": "3"
}
],
"hide_heading": 0,
@@ -108,7 +138,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2016-11-07 05:28:09.772560",
+ "modified": "2016-11-08 05:28:09.772560",
"modified_by": "Administrator",
"module": "Setup",
"name": "Currency Exchange",
@@ -202,5 +232,8 @@
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
+ "sort_field": "name",
+ "sort_order": "DESC",
+ "title_field": "",
"track_seen": 0
}
\ No newline at end of file
diff --git a/erpnext/setup/doctype/currency_exchange/currency_exchange.py b/erpnext/setup/doctype/currency_exchange/currency_exchange.py
index 6022812..7f1a43c 100644
--- a/erpnext/setup/doctype/currency_exchange/currency_exchange.py
+++ b/erpnext/setup/doctype/currency_exchange/currency_exchange.py
@@ -7,13 +7,15 @@
import frappe
from frappe import _
from frappe.model.document import Document
+from frappe.utils import get_datetime, get_datetime_str, formatdate
class CurrencyExchange(Document):
- def autoname(self):
- self.name = self.from_currency + "-" + self.to_currency
+ def autoname(self):
+ self.name = formatdate(get_datetime_str(self.date),"yyyy-MM-dd") + "-" + self.from_currency + "-" + self.to_currency
+ #self.name = self.date + "-" + self.from_currency + "-" + self.to_currency
- def validate(self):
- self.validate_value("exchange_rate", ">", 0)
+ def validate(self):
+ self.validate_value("exchange_rate", ">", 0)
- if self.from_currency == self.to_currency:
- frappe.throw(_("From Currency and To Currency cannot be same"))
+ if self.from_currency == self.to_currency:
+ frappe.throw(_("From Currency and To Currency cannot be same"))
diff --git a/erpnext/setup/doctype/currency_exchange/test_currency_exchange.py b/erpnext/setup/doctype/currency_exchange/test_currency_exchange.py
index 0077630..181f072 100644
--- a/erpnext/setup/doctype/currency_exchange/test_currency_exchange.py
+++ b/erpnext/setup/doctype/currency_exchange/test_currency_exchange.py
@@ -3,5 +3,18 @@
from __future__ import unicode_literals
-import frappe
-test_records = frappe.get_test_records('Currency Exchange')
\ No newline at end of file
+import frappe, unittest
+test_records = frappe.get_test_records('Currency Exchange')
+
+class TestCurrencyExchange(unittest.TestCase):
+ def test_exchnage_rate(self):
+ from erpnext.setup.utils import get_exchange_rate
+
+ # Exchange rate as on 15th Jan, 2016, should be fetched from Currency Exchange record
+ exchange_rate = get_exchange_rate("USD", "INR", "2016-01-15")
+ self.assertEqual(exchange_rate, 60.0)
+
+ # Exchange rate as on 15th Dec, 2015, should be fetched from fixer.io
+ exchange_rate = get_exchange_rate("USD", "INR", "2015-12-15")
+ self.assertFalse(exchange_rate==60)
+
\ No newline at end of file
diff --git a/erpnext/setup/doctype/currency_exchange/test_records.json b/erpnext/setup/doctype/currency_exchange/test_records.json
index 784bf26..23edd8a 100644
--- a/erpnext/setup/doctype/currency_exchange/test_records.json
+++ b/erpnext/setup/doctype/currency_exchange/test_records.json
@@ -1,18 +1,21 @@
[
{
"doctype": "Currency Exchange",
+ "date": "2016-01-01",
"exchange_rate": 60.0,
"from_currency": "USD",
"to_currency": "INR"
},
{
"doctype": "Currency Exchange",
+ "date": "2016-01-01",
"exchange_rate": 0.773,
"from_currency": "USD",
"to_currency": "EUR"
},
{
"doctype": "Currency Exchange",
+ "date": "2016-01-01",
"exchange_rate": 0.0167,
"from_currency": "INR",
"to_currency": "USD"
diff --git a/erpnext/setup/doctype/sales_person/sales_person.json b/erpnext/setup/doctype/sales_person/sales_person.json
index 1665ba5..595552e 100644
--- a/erpnext/setup/doctype/sales_person/sales_person.json
+++ b/erpnext/setup/doctype/sales_person/sales_person.json
@@ -29,7 +29,7 @@
"label": "Name and Employee ID",
"length": 0,
"no_copy": 0,
- "options": "fa fa-user",
+ "options": "icon-user",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
@@ -190,6 +190,35 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "default": "1",
+ "fieldname": "enabled",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Enabled",
+ "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": "lft",
"fieldtype": "Int",
"hidden": 1,
@@ -290,7 +319,7 @@
"length": 0,
"no_copy": 0,
"oldfieldtype": "Section Break",
- "options": "fa fa-bullseye",
+ "options": "icon-bullseye",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
@@ -366,7 +395,7 @@
],
"hide_heading": 0,
"hide_toolbar": 0,
- "icon": "fa fa-user",
+ "icon": "icon-user",
"idx": 1,
"image_view": 0,
"in_create": 0,
@@ -375,7 +404,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2016-11-07 05:29:29.299529",
+ "modified": "2016-12-12 18:47:13.924225",
"modified_by": "Administrator",
"module": "Setup",
"name": "Sales Person",
diff --git a/erpnext/setup/doctype/terms_and_conditions/terms_and_conditions.json b/erpnext/setup/doctype/terms_and_conditions/terms_and_conditions.json
index ce057c2..bede595 100644
--- a/erpnext/setup/doctype/terms_and_conditions/terms_and_conditions.json
+++ b/erpnext/setup/doctype/terms_and_conditions/terms_and_conditions.json
@@ -16,6 +16,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"fieldname": "title",
"fieldtype": "Data",
"hidden": 0,
@@ -23,6 +24,7 @@
"ignore_xss_filter": 0,
"in_filter": 1,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Title",
"length": 0,
"no_copy": 1,
@@ -32,6 +34,7 @@
"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,
@@ -42,6 +45,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"fieldname": "disabled",
"fieldtype": "Check",
"hidden": 0,
@@ -49,6 +53,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
+ "in_standard_filter": 0,
"label": "Disabled",
"length": 0,
"no_copy": 0,
@@ -57,6 +62,7 @@
"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,
@@ -67,6 +73,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"fieldname": "terms",
"fieldtype": "Text Editor",
"hidden": 0,
@@ -74,6 +81,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Terms and Conditions",
"length": 0,
"no_copy": 0,
@@ -83,6 +91,36 @@
"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": "terms_and_conditions_help",
+ "fieldtype": "HTML",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Terms and Conditions Help",
+ "length": 0,
+ "no_copy": 0,
+ "options": "<h4>Standard Terms and Conditions Example</h4>\n\n<pre>Delivery Terms for Order number {{ name }}\n\n-Order Date : {{ transaction_date }} \n-Expected Delivery Date : {{ delivery_date }}\n</pre>\n\n<h4>How to get fieldnames</h4>\n\n<p>The fieldnames you can use in your standard reply are the fields in the document from which you are sending the email. You can find out the fields of any documents via Setup > Customize Form View and selecting the document type (e.g. Sales Invoice)</p>\n\n<h4>Templating</h4>\n\n<p>Templates are compiled using the Jinja Templating Langauge. To learn more about Jinja, <a class=\"strong\" href=\"http://jinja.pocoo.org/docs/dev/templates/\">read this documentation.</a></p>",
+ "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,
@@ -92,7 +130,7 @@
],
"hide_heading": 0,
"hide_toolbar": 0,
- "icon": "fa fa-legal",
+ "icon": "icon-legal",
"idx": 1,
"image_view": 0,
"in_create": 0,
@@ -101,7 +139,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2016-07-25 05:24:25.093905",
+ "modified": "2016-12-12 17:31:53.349301",
"modified_by": "Administrator",
"module": "Setup",
"name": "Terms and Conditions",
@@ -117,6 +155,7 @@
"export": 0,
"if_owner": 0,
"import": 0,
+ "is_custom": 0,
"permlevel": 0,
"print": 1,
"read": 1,
@@ -137,6 +176,7 @@
"export": 0,
"if_owner": 0,
"import": 0,
+ "is_custom": 0,
"permlevel": 0,
"print": 0,
"read": 1,
@@ -157,6 +197,7 @@
"export": 0,
"if_owner": 0,
"import": 0,
+ "is_custom": 0,
"permlevel": 0,
"print": 0,
"read": 1,
@@ -177,6 +218,7 @@
"export": 0,
"if_owner": 0,
"import": 0,
+ "is_custom": 0,
"permlevel": 0,
"print": 1,
"read": 1,
@@ -197,6 +239,7 @@
"export": 0,
"if_owner": 0,
"import": 0,
+ "is_custom": 0,
"permlevel": 0,
"print": 1,
"read": 1,
@@ -217,6 +260,7 @@
"export": 0,
"if_owner": 0,
"import": 0,
+ "is_custom": 0,
"permlevel": 0,
"print": 0,
"read": 1,
@@ -231,5 +275,6 @@
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
+ "sort_order": "ASC",
"track_seen": 0
}
\ No newline at end of file
diff --git a/erpnext/setup/doctype/terms_and_conditions/terms_and_conditions.py b/erpnext/setup/doctype/terms_and_conditions/terms_and_conditions.py
index 52f5156..d2b68b4 100644
--- a/erpnext/setup/doctype/terms_and_conditions/terms_and_conditions.py
+++ b/erpnext/setup/doctype/terms_and_conditions/terms_and_conditions.py
@@ -3,8 +3,18 @@
from __future__ import unicode_literals
import frappe
-
+import json
from frappe.model.document import Document
+from frappe.utils.jinja import validate_template
class TermsandConditions(Document):
- pass
\ No newline at end of file
+ def validate(self):
+ validate_template(self.terms)
+
+@frappe.whitelist()
+def get_terms_and_conditions(template_name, doc):
+ if isinstance(doc, basestring):
+ doc = json.loads(doc)
+
+ terms_and_conditions = frappe.get_doc("Terms and Conditions", template_name)
+ return frappe.render_template(terms_and_conditions.terms, doc)
\ No newline at end of file
diff --git a/erpnext/setup/utils.py b/erpnext/setup/utils.py
index eda2042..0c214e4 100644
--- a/erpnext/setup/utils.py
+++ b/erpnext/setup/utils.py
@@ -5,7 +5,8 @@
import frappe
from frappe import _, throw
from frappe.utils import flt
-
+from frappe.utils import get_datetime_str, nowdate
+
def get_company_currency(company):
currency = frappe.db.get_value("Company", company, "default_currency", cache=True)
if not currency:
@@ -64,36 +65,44 @@
frappe.db.commit()
@frappe.whitelist()
-def get_exchange_rate(from_currency, to_currency):
+def get_exchange_rate(from_currency, to_currency, transaction_date=None):
+ if not transaction_date:
+ transaction_date = nowdate()
if not (from_currency and to_currency):
+ # manqala 19/09/2016: Should this be an empty return or should it throw and exception?
return
if from_currency == to_currency:
return 1
- exchange = "%s-%s" % (from_currency, to_currency)
- value = flt(frappe.db.get_value("Currency Exchange", exchange, "exchange_rate"))
+ # cksgb 19/09/2016: get last entry in Currency Exchange with from_currency and to_currency.
+ entries = frappe.get_all("Currency Exchange", fields = ["exchange_rate"],
+ filters=[
+ ["date", "<=", get_datetime_str(transaction_date)],
+ ["from_currency", "=", from_currency],
+ ["to_currency", "=", to_currency]
+ ], order_by="date desc", limit=1)
+
+ if entries:
+ return flt(entries[0].exchange_rate)
- if not value:
- try:
- cache = frappe.cache()
- key = "currency_exchange_rate:{0}:{1}".format(from_currency, to_currency)
- value = cache.get(key)
+ try:
+ cache = frappe.cache()
+ key = "currency_exchange_rate:{0}:{1}".format(from_currency, to_currency)
+ value = cache.get(key)
- if not value:
- import requests
- response = requests.get("http://api.fixer.io/latest", params={
- "base": from_currency,
- "symbols": to_currency
- })
- # expire in 6 hours
- response.raise_for_status()
- value = response.json()["rates"][to_currency]
- cache.setex(key, value, 6 * 60 * 60)
+ if not value:
+ import requests
+ response = requests.get("http://api.fixer.io/latest", params={
+ "base": from_currency,
+ "symbols": to_currency
+ })
+ # expire in 6 hours
+ response.raise_for_status()
+ value = response.json()["rates"][to_currency]
+ cache.setex(key, value, 6 * 60 * 60)
- return flt(value)
- except:
- frappe.msgprint(_("Unable to find exchange rate for {0} to {1}").format(from_currency, to_currency))
- return 0.0
- else:
- return value
+ return flt(value)
+ except:
+ frappe.msgprint(_("Unable to find exchange rate for {0} to {1} for key date {2}").format(from_currency, to_currency, transaction_date))
+ return 0.0
\ No newline at end of file
diff --git a/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.py b/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.py
index d8d00ef..6915ef5 100644
--- a/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.py
+++ b/erpnext/shopping_cart/doctype/shopping_cart_settings/shopping_cart_settings.py
@@ -8,6 +8,7 @@
from frappe import _, msgprint
from frappe.utils import comma_and
from frappe.model.document import Document
+from frappe.utils import get_datetime, get_datetime_str, now_datetime
class ShoppingCartSetupError(frappe.ValidationError): pass
@@ -38,11 +39,18 @@
expected_to_exist = [currency + "-" + company_currency
for currency in price_list_currency_map.values()
if currency != company_currency]
+
+ # manqala 20/09/2016: set up selection parameters for query from tabCurrency Exchange
+ from_currency = [currency for currency in price_list_currency_map.values() if currency != company_currency]
+ to_currency = company_currency
+ # manqala end
if expected_to_exist:
- exists = frappe.db.sql_list("""select name from `tabCurrency Exchange`
- where name in (%s)""" % (", ".join(["%s"]*len(expected_to_exist)),),
- tuple(expected_to_exist))
+ # manqala 20/09/2016: modify query so that it uses date in the selection from Currency Exchange.
+ # exchange rates defined with date less than the date on which this document is being saved will be selected
+ exists = frappe.db.sql_list("""select CONCAT(from_currency,'-',to_currency) from `tabCurrency Exchange`
+ where from_currency in (%s) and to_currency = "%s" and date <= curdate()""" % (", ".join(["%s"]*len(from_currency)), to_currency), tuple(from_currency))
+ # manqala end
missing = list(set(expected_to_exist).difference(exists))
diff --git a/erpnext/stock/doctype/item/item.json b/erpnext/stock/doctype/item/item.json
index bad8416..5d2d557 100644
--- a/erpnext/stock/doctype/item/item.json
+++ b/erpnext/stock/doctype/item/item.json
@@ -343,7 +343,7 @@
"columns": 0,
"depends_on": "eval:(doc.__islocal&&doc.is_stock_item && !doc.has_serial_no && !doc.has_batch_no)",
"fieldname": "opening_stock",
- "fieldtype": "Int",
+ "fieldtype": "Float",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@@ -2683,7 +2683,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 1,
- "modified": "2016-11-18 02:19:54.507883",
+ "modified": "2016-12-13 02:19:54.507883",
"modified_by": "Administrator",
"module": "Stock",
"name": "Item",
diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py
index 3d248d1..98d0ebc 100644
--- a/erpnext/stock/doctype/item/item.py
+++ b/erpnext/stock/doctype/item/item.py
@@ -532,8 +532,6 @@
frappe.throw(_("To merge, following properties must be same for both items")
+ ": \n" + ", ".join([self.meta.get_label(fld) for fld in field_list]))
- frappe.db.sql("delete from `tabBin` where item_code=%s", old_name)
-
def after_rename(self, old_name, new_name, merge):
if self.route:
invalidate_cache_for_item(self)
@@ -567,8 +565,14 @@
existing_allow_negative_stock = frappe.db.get_value("Stock Settings", None, "allow_negative_stock")
frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1)
- for warehouse in frappe.db.sql("select warehouse from `tabBin` where item_code=%s", new_name):
- repost_stock(new_name, warehouse[0])
+ repost_stock_for_warehouses = frappe.db.sql_list("""select distinct warehouse
+ from tabBin where item_code=%s""", new_name)
+
+ # Delete all existing bins to avoid duplicate bins for the same item and warehouse
+ frappe.db.sql("delete from `tabBin` where item_code=%s", new_name)
+
+ for warehouse in repost_stock_for_warehouses:
+ repost_stock(new_name, warehouse)
frappe.db.set_value("Stock Settings", None, "allow_negative_stock", existing_allow_negative_stock)
frappe.db.auto_commit_on_many_writes = 0
diff --git a/erpnext/stock/doctype/item/test_item.py b/erpnext/stock/doctype/item/test_item.py
index aceefc0..706fd5a 100644
--- a/erpnext/stock/doctype/item/test_item.py
+++ b/erpnext/stock/doctype/item/test_item.py
@@ -9,6 +9,9 @@
from erpnext.controllers.item_variant import (create_variant, ItemVariantExistsError,
InvalidItemAttributeValueError)
+from frappe.model.rename_doc import rename_doc
+from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
+
test_ignore = ["BOM"]
test_dependencies = ["Warehouse"]
@@ -164,11 +167,31 @@
variant.item_name = "_Test Numeric Variant Large 1.1m"
self.assertRaises(InvalidItemAttributeValueError, variant.save)
- variant = create_variant("_Test Numeric Template Item", {"Test Size": "Large", "Test Item Length": 1.5})
+ variant = create_variant("_Test Numeric Template Item",
+ {"Test Size": "Large", "Test Item Length": 1.5})
self.assertEquals(variant.item_code, None)
variant.item_code = "_Test Numeric Variant-L-1.5"
variant.item_name = "_Test Numeric Variant Large 1.5m"
variant.save()
+
+ def test_item_merging(self):
+ create_item("Test Item for Merging 1")
+ create_item("Test Item for Merging 2")
+
+ make_stock_entry(item_code="Test Item for Merging 1", target="_Test Warehouse - _TC",
+ qty=1, rate=100)
+ make_stock_entry(item_code="Test Item for Merging 2", target="_Test Warehouse 1 - _TC",
+ qty=1, rate=100)
+
+ rename_doc("Item", "Test Item for Merging 1", "Test Item for Merging 2", merge=True)
+
+ self.assertFalse(frappe.db.exists("Item", "Test Item for Merging 1"))
+
+ self.assertTrue(frappe.db.get_value("Bin",
+ {"item_code": "Test Item for Merging 2", "warehouse": "_Test Warehouse - _TC"}))
+
+ self.assertTrue(frappe.db.get_value("Bin",
+ {"item_code": "Test Item for Merging 2", "warehouse": "_Test Warehouse 1 - _TC"}))
def make_item_variant():
if not frappe.db.exists("Item", "_Test Variant Item-S"):
@@ -184,3 +207,14 @@
return total_qty[0].projected_qty if total_qty else 0.0
test_records = frappe.get_test_records('Item')
+
+def create_item(item_code, is_stock_item=None):
+ if not frappe.db.exists("Item", item_code):
+ item = frappe.new_doc("Item")
+ item.item_code = item_code
+ item.item_name = item_code
+ item.description = item_code
+ item.item_group = "All Item Groups"
+ item.is_stock_item = is_stock_item or 1
+ item.save()
+
\ No newline at end of file
diff --git a/erpnext/stock/doctype/material_request_item/material_request_item.json b/erpnext/stock/doctype/material_request_item/material_request_item.json
index f7ca7d9..b1d6ec0 100644
--- a/erpnext/stock/doctype/material_request_item/material_request_item.json
+++ b/erpnext/stock/doctype/material_request_item/material_request_item.json
@@ -23,6 +23,7 @@
"ignore_xss_filter": 0,
"in_filter": 1,
"in_list_view": 1,
+ "in_standard_filter": 0,
"label": "Item Code",
"length": 0,
"no_copy": 0,
@@ -34,6 +35,7 @@
"print_hide_if_no_value": 0,
"print_width": "100px",
"read_only": 0,
+ "remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 1,
@@ -53,12 +55,14 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"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,
@@ -77,6 +81,7 @@
"ignore_xss_filter": 0,
"in_filter": 1,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Item Name",
"length": 0,
"no_copy": 0,
@@ -87,6 +92,7 @@
"print_hide_if_no_value": 0,
"print_width": "100px",
"read_only": 0,
+ "remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 1,
@@ -106,6 +112,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Description",
"length": 0,
"no_copy": 0,
@@ -114,6 +121,7 @@
"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,
@@ -132,6 +140,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Description",
"length": 0,
"no_copy": 0,
@@ -142,6 +151,7 @@
"print_hide_if_no_value": 0,
"print_width": "250px",
"read_only": 0,
+ "remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
@@ -161,6 +171,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -168,6 +179,7 @@
"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,
@@ -186,6 +198,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Image",
"length": 0,
"no_copy": 0,
@@ -194,6 +207,7 @@
"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,
@@ -212,6 +226,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Quantity and Warehouse",
"length": 0,
"no_copy": 0,
@@ -219,6 +234,7 @@
"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,
@@ -237,6 +253,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
+ "in_standard_filter": 0,
"label": "Quantity",
"length": 0,
"no_copy": 0,
@@ -247,6 +264,7 @@
"print_hide_if_no_value": 0,
"print_width": "80px",
"read_only": 0,
+ "remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
@@ -266,6 +284,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Stock UOM",
"length": 0,
"no_copy": 0,
@@ -277,6 +296,7 @@
"print_hide_if_no_value": 0,
"print_width": "70px",
"read_only": 1,
+ "remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
@@ -296,6 +316,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
+ "in_standard_filter": 0,
"label": "For Warehouse",
"length": 0,
"no_copy": 0,
@@ -307,6 +328,7 @@
"print_hide_if_no_value": 0,
"print_width": "100px",
"read_only": 0,
+ "remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
@@ -326,12 +348,14 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"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,
@@ -351,6 +375,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
+ "in_standard_filter": 0,
"label": "Required Date",
"length": 0,
"no_copy": 0,
@@ -361,6 +386,7 @@
"print_hide_if_no_value": 0,
"print_width": "100px",
"read_only": 0,
+ "remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
@@ -380,6 +406,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "More Information",
"length": 0,
"no_copy": 0,
@@ -387,6 +414,7 @@
"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,
@@ -406,6 +434,7 @@
"ignore_xss_filter": 0,
"in_filter": 1,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Item Group",
"length": 0,
"no_copy": 0,
@@ -416,6 +445,7 @@
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 1,
+ "remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 1,
@@ -434,6 +464,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Brand",
"length": 0,
"no_copy": 0,
@@ -445,6 +476,7 @@
"print_hide_if_no_value": 0,
"print_width": "100px",
"read_only": 1,
+ "remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
@@ -464,6 +496,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Lead Time Date",
"length": 0,
"no_copy": 1,
@@ -473,6 +506,7 @@
"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,
@@ -491,6 +525,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Sales Order",
"length": 0,
"no_copy": 0,
@@ -499,6 +534,7 @@
"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,
@@ -517,6 +553,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Project",
"length": 0,
"no_copy": 0,
@@ -526,6 +563,7 @@
"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,
@@ -544,12 +582,14 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"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,
@@ -568,6 +608,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Min Order Qty",
"length": 0,
"no_copy": 1,
@@ -578,6 +619,7 @@
"print_hide_if_no_value": 0,
"print_width": "70px",
"read_only": 1,
+ "remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
@@ -597,6 +639,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Projected Qty",
"length": 0,
"no_copy": 1,
@@ -607,6 +650,7 @@
"print_hide_if_no_value": 0,
"print_width": "70px",
"read_only": 1,
+ "remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
@@ -626,6 +670,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Actual Qty",
"length": 0,
"no_copy": 1,
@@ -634,6 +679,7 @@
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 1,
+ "remember_last_selected_value": 0,
"report_hide": 1,
"reqd": 0,
"search_index": 0,
@@ -652,6 +698,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Completed Qty",
"length": 0,
"no_copy": 1,
@@ -661,6 +708,7 @@
"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,
@@ -679,6 +727,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Page Break",
"length": 0,
"no_copy": 1,
@@ -688,6 +737,7 @@
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
+ "remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
@@ -705,7 +755,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
- "modified": "2016-10-17 04:58:33.317145",
+ "modified": "2016-12-08 14:49:48.397015",
"modified_by": "Administrator",
"module": "Stock",
"name": "Material Request Item",
diff --git a/erpnext/stock/doctype/quality_inspection/quality_inspection.py b/erpnext/stock/doctype/quality_inspection/quality_inspection.py
index 3ba3056..c3808f7 100644
--- a/erpnext/stock/doctype/quality_inspection/quality_inspection.py
+++ b/erpnext/stock/doctype/quality_inspection/quality_inspection.py
@@ -33,12 +33,11 @@
def on_cancel(self):
if self.reference_type and self.reference_name:
- frappe.db.sql("""update `tab{doctype} Item` t1, `tab{doctype}` t2
- set t1.quality_inspection = null, t2.modified = %s
- where t1.parent = %s and t1.item_code = %s and t1.parent = t2.name"""
- .format(doctype=self.reference_type),
- (self.modified, self.reference_name, self.item_code))
-
+ frappe.db.sql("""update `tab{doctype} Item`
+ set quality_inspection = null, modified=%s
+ where quality_inspection = %s"""
+ .format(doctype=self.reference_type), (self.modified, self.name))
+
def item_query(doctype, txt, searchfield, start, page_len, filters):
if filters.get("from"):
from frappe.desk.reportview import get_match_cond
diff --git a/erpnext/stock/doctype/warehouse/test_warehouse.py b/erpnext/stock/doctype/warehouse/test_warehouse.py
index 2232584..edc5400 100644
--- a/erpnext/stock/doctype/warehouse/test_warehouse.py
+++ b/erpnext/stock/doctype/warehouse/test_warehouse.py
@@ -1,7 +1,10 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-
+from frappe.model.rename_doc import rename_doc
+from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
+from frappe.utils import cint
+from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory
import frappe
import unittest
@@ -21,5 +24,77 @@
for child_warehouse in child_warehouses:
self.assertEquals(p_warehouse.name, child_warehouse.parent_warehouse)
self.assertEquals(child_warehouse.is_group, 0)
+
+ def test_warehouse_renaming(self):
+ set_perpetual_inventory(1)
+ create_warehouse("Test Warehouse for Renaming 1")
+ self.assertTrue(frappe.db.exists("Account", "Test Warehouse for Renaming 1 - _TC"))
+ self.assertTrue(frappe.db.get_value("Account",
+ filters={"warehouse": "Test Warehouse for Renaming 1 - _TC"}))
+ # Rename with abbr
+ if frappe.db.exists("Warehouse", "Test Warehouse for Renaming 2 - _TC"):
+ frappe.delete_doc("Warehouse", "Test Warehouse for Renaming 2 - _TC")
+ rename_doc("Warehouse", "Test Warehouse for Renaming 1 - _TC", "Test Warehouse for Renaming 2 - _TC")
+
+ self.assertTrue(frappe.db.exists("Account", "Test Warehouse for Renaming 2 - _TC"))
+ self.assertTrue(frappe.db.get_value("Account",
+ filters={"warehouse": "Test Warehouse for Renaming 2 - _TC"}))
+
+ # Rename without abbr
+ if frappe.db.exists("Warehouse", "Test Warehouse for Renaming 3 - _TC"):
+ frappe.delete_doc("Warehouse", "Test Warehouse for Renaming 3 - _TC")
+
+ rename_doc("Warehouse", "Test Warehouse for Renaming 2 - _TC", "Test Warehouse for Renaming 3")
+
+ self.assertTrue(frappe.db.exists("Account", "Test Warehouse for Renaming 3 - _TC"))
+ self.assertTrue(frappe.db.get_value("Account",
+ filters={"warehouse": "Test Warehouse for Renaming 3 - _TC"}))
+
+ set_perpetual_inventory(0)
+
+ def test_warehouse_merging(self):
+ set_perpetual_inventory(1)
+
+ create_warehouse("Test Warehouse for Merging 1")
+ create_warehouse("Test Warehouse for Merging 2")
+
+ make_stock_entry(item_code="_Test Item", target="Test Warehouse for Merging 1 - _TC",
+ qty=1, rate=100)
+ make_stock_entry(item_code="_Test Item", target="Test Warehouse for Merging 2 - _TC",
+ qty=1, rate=100)
+
+ existing_bin_qty = (
+ cint(frappe.db.get_value("Bin",
+ {"item_code": "_Test Item", "warehouse": "Test Warehouse for Merging 1 - _TC"}, "actual_qty"))
+ + cint(frappe.db.get_value("Bin",
+ {"item_code": "_Test Item", "warehouse": "Test Warehouse for Merging 2 - _TC"}, "actual_qty"))
+ )
+
+ rename_doc("Warehouse", "Test Warehouse for Merging 1 - _TC",
+ "Test Warehouse for Merging 2 - _TC", merge=True)
+
+ self.assertFalse(frappe.db.exists("Warehouse", "Test Warehouse for Merging 1 - _TC"))
+
+ bin_qty = frappe.db.get_value("Bin",
+ {"item_code": "_Test Item", "warehouse": "Test Warehouse for Merging 2 - _TC"}, "actual_qty")
+
+ self.assertEqual(bin_qty, existing_bin_qty)
+
+ self.assertFalse(frappe.db.exists("Account", "Test Warehouse for Merging 1 - _TC"))
+ self.assertTrue(frappe.db.exists("Account", "Test Warehouse for Merging 2 - _TC"))
+ self.assertTrue(frappe.db.get_value("Account",
+ filters={"warehouse": "Test Warehouse for Merging 2 - _TC"}))
+
+ set_perpetual_inventory(0)
+
+def create_warehouse(warehouse_name):
+ if not frappe.db.exists("Warehouse", warehouse_name + " - _TC"):
+ w = frappe.new_doc("Warehouse")
+ w.warehouse_name = warehouse_name
+ w.parent_warehouse = "_Test Warehouse Group - _TC"
+ w.company = "_Test Company"
+ w.save()
+
+
\ No newline at end of file
diff --git a/erpnext/stock/doctype/warehouse/warehouse.py b/erpnext/stock/doctype/warehouse/warehouse.py
index 5d0951b..e01cc0b 100644
--- a/erpnext/stock/doctype/warehouse/warehouse.py
+++ b/erpnext/stock/doctype/warehouse/warehouse.py
@@ -143,9 +143,7 @@
if self.company != frappe.db.get_value("Warehouse", new_warehouse, "company"):
frappe.throw(_("Both Warehouse must belong to same Company"))
- frappe.db.sql("delete from `tabBin` where warehouse=%s", olddn)
-
- self.rename_account_for(olddn, newdn, merge)
+ self.rename_account_for(olddn, new_warehouse, merge)
return new_warehouse
@@ -195,8 +193,14 @@
existing_allow_negative_stock = frappe.db.get_value("Stock Settings", None, "allow_negative_stock")
frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1)
- for item in frappe.db.sql(""" select distinct item_code from tabBin where warehouse = %s""", newdn):
- repost_stock(item[0], newdn)
+ repost_stock_for_items = frappe.db.sql_list("""select distinct item_code
+ from tabBin where warehouse=%s""", newdn)
+
+ # Delete all existing bins to avoid duplicate bins for the same item and warehouse
+ frappe.db.sql("delete from `tabBin` where warehouse=%s", newdn)
+
+ for item_code in repost_stock_for_items:
+ repost_stock(item_code, newdn)
frappe.db.set_value("Stock Settings", None, "allow_negative_stock", existing_allow_negative_stock)
frappe.db.auto_commit_on_many_writes = 0
diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py
index 0caf1cd..7bcad08 100644
--- a/erpnext/stock/get_item_details.py
+++ b/erpnext/stock/get_item_details.py
@@ -172,7 +172,7 @@
"net_amount": 0.0,
"discount_percentage": 0.0,
"supplier": item.default_supplier,
- "delivered_by_supplier": item.delivered_by_supplier,
+ "delivered_by_supplier": item.delivered_by_supplier if args.get("doctype") in ["Sales Order", "Sales Invoice"] else 0,
"is_fixed_asset": item.is_fixed_asset
})
@@ -481,7 +481,9 @@
if (not plc_conversion_rate) or (price_list_currency and args.price_list_currency \
and price_list_currency != args.price_list_currency):
- plc_conversion_rate = get_exchange_rate(price_list_currency, args.currency) or plc_conversion_rate
+ # cksgb 19/09/2016: added args.transaction_date as posting_date argument for get_exchange_rate
+ plc_conversion_rate = get_exchange_rate(price_list_currency, args.currency,
+ args.transaction_date) or plc_conversion_rate
return frappe._dict({
"price_list_currency": price_list_currency,
diff --git a/erpnext/support/doctype/warranty_claim/warranty_claim.json b/erpnext/support/doctype/warranty_claim/warranty_claim.json
index 4e63bb6..d1b0b8f 100644
--- a/erpnext/support/doctype/warranty_claim/warranty_claim.json
+++ b/erpnext/support/doctype/warranty_claim/warranty_claim.json
@@ -1124,7 +1124,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2016-11-07 05:06:08.638760",
+ "modified": "2016-12-13 11:17:40.538428",
"modified_by": "Administrator",
"module": "Support",
"name": "Warranty Claim",
diff --git a/erpnext/support/web_form/issues/issues.json b/erpnext/support/web_form/issues/issues.json
index 4b7c70c..6474799 100644
--- a/erpnext/support/web_form/issues/issues.json
+++ b/erpnext/support/web_form/issues/issues.json
@@ -1,8 +1,12 @@
{
+ "accept_payment": 0,
"allow_comments": 1,
"allow_delete": 1,
"allow_edit": 1,
+ "allow_incomplete": 0,
"allow_multiple": 1,
+ "allow_print": 0,
+ "amount": 0.0,
"breadcrumbs": "[{\"title\":\"Issues\", \"name\":\"issues\"}]",
"creation": "2016-06-24 15:50:33.186483",
"doc_type": "Issue",
@@ -11,13 +15,16 @@
"idx": 0,
"is_standard": 1,
"login_required": 1,
- "modified": "2016-06-24 15:52:24.768558",
+ "max_attachment_size": 0,
+ "modified": "2016-12-07 04:26:13.917693",
"modified_by": "Administrator",
"module": "Support",
"name": "issues",
"owner": "Administrator",
"published": 1,
"route": "issues",
+ "show_sidebar": 1,
+ "sidebar_items": [],
"success_message": "",
"success_url": "/issues",
"title": "Issue",
@@ -27,6 +34,8 @@
"fieldtype": "Data",
"hidden": 0,
"label": "Subject",
+ "max_length": 0,
+ "max_value": 0,
"read_only": 0,
"reqd": 1
},
@@ -36,15 +45,30 @@
"fieldtype": "Select",
"hidden": 0,
"label": "Status",
+ "max_length": 0,
+ "max_value": 0,
"options": "Open\nReplied\nHold\nClosed",
"read_only": 1,
"reqd": 0
},
{
+ "fieldname": "customer",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "label": "Customer",
+ "max_length": 0,
+ "max_value": 0,
+ "options": "Customer",
+ "read_only": 1,
+ "reqd": 0
+ },
+ {
"fieldname": "description",
"fieldtype": "Text",
"hidden": 0,
"label": "Description",
+ "max_length": 0,
+ "max_value": 0,
"read_only": 0,
"reqd": 0
},
@@ -53,6 +77,8 @@
"fieldtype": "Attach",
"hidden": 0,
"label": "Attachment",
+ "max_length": 0,
+ "max_value": 0,
"read_only": 0,
"reqd": 0
}
diff --git a/erpnext/utilities/web_form/addresses/addresses.json b/erpnext/utilities/web_form/addresses/addresses.json
index 50fe6e9..6d3fefc 100644
--- a/erpnext/utilities/web_form/addresses/addresses.json
+++ b/erpnext/utilities/web_form/addresses/addresses.json
@@ -1,8 +1,12 @@
{
+ "accept_payment": 0,
"allow_comments": 0,
"allow_delete": 0,
"allow_edit": 1,
+ "allow_incomplete": 0,
"allow_multiple": 1,
+ "allow_print": 0,
+ "amount": 0.0,
"creation": "2016-06-24 15:50:33.196990",
"doc_type": "Address",
"docstatus": 0,
@@ -10,13 +14,16 @@
"idx": 0,
"is_standard": 1,
"login_required": 1,
- "modified": "2016-06-24 16:11:28.802353",
+ "max_attachment_size": 0,
+ "modified": "2016-12-07 04:17:02.020768",
"modified_by": "Administrator",
"module": "Utilities",
"name": "addresses",
"owner": "Administrator",
"published": 1,
"route": "address",
+ "show_sidebar": 0,
+ "sidebar_items": [],
"success_url": "/addresses",
"title": "Address",
"web_form_fields": [
@@ -26,6 +33,8 @@
"fieldtype": "Data",
"hidden": 0,
"label": "Address Title",
+ "max_length": 0,
+ "max_value": 0,
"read_only": 0,
"reqd": 0
},
@@ -34,6 +43,8 @@
"fieldtype": "Select",
"hidden": 0,
"label": "Address Type",
+ "max_length": 0,
+ "max_value": 0,
"options": "Billing\nShipping\nOffice\nPersonal\nPlant\nPostal\nShop\nSubsidiary\nWarehouse\nOther",
"read_only": 0,
"reqd": 1
@@ -43,6 +54,8 @@
"fieldtype": "Data",
"hidden": 0,
"label": "Address Line 1",
+ "max_length": 0,
+ "max_value": 0,
"read_only": 0,
"reqd": 1
},
@@ -51,6 +64,8 @@
"fieldtype": "Data",
"hidden": 0,
"label": "Address Line 2",
+ "max_length": 0,
+ "max_value": 0,
"read_only": 0,
"reqd": 0
},
@@ -59,6 +74,8 @@
"fieldtype": "Data",
"hidden": 0,
"label": "City/Town",
+ "max_length": 0,
+ "max_value": 0,
"read_only": 0,
"reqd": 1
},
@@ -67,6 +84,8 @@
"fieldtype": "Data",
"hidden": 0,
"label": "State",
+ "max_length": 0,
+ "max_value": 0,
"read_only": 0,
"reqd": 0
},
@@ -75,6 +94,8 @@
"fieldtype": "Data",
"hidden": 0,
"label": "Postal Code",
+ "max_length": 0,
+ "max_value": 0,
"read_only": 0,
"reqd": 0
},
@@ -83,6 +104,8 @@
"fieldtype": "Link",
"hidden": 0,
"label": "Country",
+ "max_length": 0,
+ "max_value": 0,
"options": "Country",
"read_only": 0,
"reqd": 1
@@ -90,6 +113,8 @@
{
"fieldtype": "Column Break",
"hidden": 0,
+ "max_length": 0,
+ "max_value": 0,
"read_only": 0,
"reqd": 0
},
@@ -98,6 +123,8 @@
"fieldtype": "Data",
"hidden": 0,
"label": "Email Id",
+ "max_length": 0,
+ "max_value": 0,
"read_only": 0,
"reqd": 0
},
@@ -106,6 +133,8 @@
"fieldtype": "Data",
"hidden": 0,
"label": "Phone",
+ "max_length": 0,
+ "max_value": 0,
"read_only": 0,
"reqd": 1
},
@@ -116,6 +145,8 @@
"fieldtype": "Check",
"hidden": 0,
"label": "Preferred Billing Address",
+ "max_length": 0,
+ "max_value": 0,
"read_only": 0,
"reqd": 0
},
@@ -126,6 +157,8 @@
"fieldtype": "Check",
"hidden": 0,
"label": "Preferred Shipping Address",
+ "max_length": 0,
+ "max_value": 0,
"read_only": 0,
"reqd": 0
}