Merge branch 'develop' of https://github.com/frappe/erpnext into project-refresh
This commit is contained in:
commit
846ca09950
@ -5,7 +5,7 @@ import frappe
|
|||||||
from erpnext.hooks import regional_overrides
|
from erpnext.hooks import regional_overrides
|
||||||
from frappe.utils import getdate
|
from frappe.utils import getdate
|
||||||
|
|
||||||
__version__ = '12.0.0-dev'
|
__version__ = '13.0.0-dev'
|
||||||
|
|
||||||
def get_default_company(user=None):
|
def get_default_company(user=None):
|
||||||
'''Get default company for user'''
|
'''Get default company for user'''
|
||||||
|
@ -6,7 +6,7 @@ import frappe, json
|
|||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.utils import add_to_date, date_diff, getdate, nowdate, get_last_day, formatdate, get_link_to_form
|
from frappe.utils import add_to_date, date_diff, getdate, nowdate, get_last_day, formatdate, get_link_to_form
|
||||||
from erpnext.accounts.report.general_ledger.general_ledger import execute
|
from erpnext.accounts.report.general_ledger.general_ledger import execute
|
||||||
from frappe.core.page.dashboard.dashboard import cache_source, get_from_date_from_timespan
|
from frappe.utils.dashboard import cache_source, get_from_date_from_timespan
|
||||||
from frappe.desk.doctype.dashboard_chart.dashboard_chart import get_period_ending
|
from frappe.desk.doctype.dashboard_chart.dashboard_chart import get_period_ending
|
||||||
|
|
||||||
from frappe.utils.nestedset import get_descendants_of
|
from frappe.utils.nestedset import get_descendants_of
|
||||||
|
127
erpnext/accounts/dashboard_fixtures.py
Normal file
127
erpnext/accounts/dashboard_fixtures.py
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
|
||||||
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
from erpnext import get_default_company
|
||||||
|
|
||||||
|
import frappe
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
def get_data():
|
||||||
|
data = frappe._dict({
|
||||||
|
"dashboards": [],
|
||||||
|
"charts": []
|
||||||
|
})
|
||||||
|
company = get_company_for_dashboards()
|
||||||
|
if company:
|
||||||
|
company_doc = frappe.get_doc("Company", company)
|
||||||
|
data.dashboards = get_dashboards()
|
||||||
|
data.charts = get_charts(company_doc)
|
||||||
|
return data
|
||||||
|
|
||||||
|
def get_dashboards():
|
||||||
|
return [{
|
||||||
|
"name": "Accounts",
|
||||||
|
"dashboard_name": "Accounts",
|
||||||
|
"charts": [
|
||||||
|
{ "chart": "Outgoing Bills (Sales Invoice)" },
|
||||||
|
{ "chart": "Incoming Bills (Purchase Invoice)" },
|
||||||
|
{ "chart": "Bank Balance" },
|
||||||
|
{ "chart": "Income" },
|
||||||
|
{ "chart": "Expenses" }
|
||||||
|
]
|
||||||
|
}]
|
||||||
|
|
||||||
|
def get_charts(company):
|
||||||
|
income_account = company.default_income_account or get_account("Income Account", company.name)
|
||||||
|
expense_account = company.default_expense_account or get_account("Expense Account", company.name)
|
||||||
|
bank_account = company.default_bank_account or get_account("Bank", company.name)
|
||||||
|
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"doctype": "Dashboard Chart",
|
||||||
|
"time_interval": "Quarterly",
|
||||||
|
"name": "Income",
|
||||||
|
"chart_name": "Income",
|
||||||
|
"timespan": "Last Year",
|
||||||
|
"color": None,
|
||||||
|
"filters_json": json.dumps({"company": company.name, "account": income_account}),
|
||||||
|
"source": "Account Balance Timeline",
|
||||||
|
"chart_type": "Custom",
|
||||||
|
"timeseries": 1,
|
||||||
|
"owner": "Administrator",
|
||||||
|
"type": "Line"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"doctype": "Dashboard Chart",
|
||||||
|
"time_interval": "Quarterly",
|
||||||
|
"name": "Expenses",
|
||||||
|
"chart_name": "Expenses",
|
||||||
|
"timespan": "Last Year",
|
||||||
|
"color": None,
|
||||||
|
"filters_json": json.dumps({"company": company.name, "account": expense_account}),
|
||||||
|
"source": "Account Balance Timeline",
|
||||||
|
"chart_type": "Custom",
|
||||||
|
"timeseries": 1,
|
||||||
|
"owner": "Administrator",
|
||||||
|
"type": "Line"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"doctype": "Dashboard Chart",
|
||||||
|
"time_interval": "Quarterly",
|
||||||
|
"name": "Bank Balance",
|
||||||
|
"chart_name": "Bank Balance",
|
||||||
|
"timespan": "Last Year",
|
||||||
|
"color": "#ffb868",
|
||||||
|
"filters_json": json.dumps({"company": company.name, "account": bank_account}),
|
||||||
|
"source": "Account Balance Timeline",
|
||||||
|
"chart_type": "Custom",
|
||||||
|
"timeseries": 1,
|
||||||
|
"owner": "Administrator",
|
||||||
|
"type": "Line"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"doctype": "Dashboard Chart",
|
||||||
|
"time_interval": "Monthly",
|
||||||
|
"name": "Incoming Bills (Purchase Invoice)",
|
||||||
|
"chart_name": "Incoming Bills (Purchase Invoice)",
|
||||||
|
"timespan": "Last Year",
|
||||||
|
"color": "#a83333",
|
||||||
|
"value_based_on": "base_grand_total",
|
||||||
|
"filters_json": json.dumps({}),
|
||||||
|
"chart_type": "Sum",
|
||||||
|
"timeseries": 1,
|
||||||
|
"based_on": "posting_date",
|
||||||
|
"owner": "Administrator",
|
||||||
|
"document_type": "Purchase Invoice",
|
||||||
|
"type": "Bar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"doctype": "Dashboard Chart",
|
||||||
|
"time_interval": "Monthly",
|
||||||
|
"name": "Outgoing Bills (Sales Invoice)",
|
||||||
|
"chart_name": "Outgoing Bills (Sales Invoice)",
|
||||||
|
"timespan": "Last Year",
|
||||||
|
"color": "#7b933d",
|
||||||
|
"value_based_on": "base_grand_total",
|
||||||
|
"filters_json": json.dumps({}),
|
||||||
|
"chart_type": "Sum",
|
||||||
|
"timeseries": 1,
|
||||||
|
"based_on": "posting_date",
|
||||||
|
"owner": "Administrator",
|
||||||
|
"document_type": "Sales Invoice",
|
||||||
|
"type": "Bar"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
def get_account(account_type, company):
|
||||||
|
accounts = frappe.get_list("Account", filters={"account_type": account_type, "company": company})
|
||||||
|
if accounts:
|
||||||
|
return accounts[0].name
|
||||||
|
|
||||||
|
def get_company_for_dashboards():
|
||||||
|
company = get_default_company()
|
||||||
|
if not company:
|
||||||
|
company_list = frappe.get_list("Company")
|
||||||
|
if company_list:
|
||||||
|
company = company_list[0].name
|
||||||
|
return company
|
@ -80,7 +80,7 @@ def make_journal_entry(doc, supplier, mode_of_payment=None):
|
|||||||
paid_amt += d.amount
|
paid_amt += d.amount
|
||||||
|
|
||||||
je.append('accounts', {
|
je.append('accounts', {
|
||||||
'account': doc.references[0].account,
|
'account': doc.account,
|
||||||
'credit_in_account_currency': paid_amt
|
'credit_in_account_currency': paid_amt
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"actions": [],
|
||||||
"autoname": "naming_series:",
|
"autoname": "naming_series:",
|
||||||
"creation": "2015-12-15 22:23:24.745065",
|
"creation": "2015-12-15 22:23:24.745065",
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
@ -210,13 +211,14 @@
|
|||||||
"label": "IBAN"
|
"label": "IBAN"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fetch_from": "bank_account.branch_code",
|
"fetch_from": "bank.branch_code",
|
||||||
|
"fetch_if_empty": 1,
|
||||||
"fieldname": "branch_code",
|
"fieldname": "branch_code",
|
||||||
"fieldtype": "Read Only",
|
"fieldtype": "Read Only",
|
||||||
"label": "Branch Code"
|
"label": "Branch Code"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fetch_from": "bank_account.swift_number",
|
"fetch_from": "bank.swift_number",
|
||||||
"fieldname": "swift_number",
|
"fieldname": "swift_number",
|
||||||
"fieldtype": "Read Only",
|
"fieldtype": "Read Only",
|
||||||
"label": "SWIFT Number"
|
"label": "SWIFT Number"
|
||||||
@ -348,7 +350,8 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"modified": "2020-03-28 16:07:31.960798",
|
"links": [],
|
||||||
|
"modified": "2020-05-08 10:23:02.815237",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Payment Request",
|
"name": "Payment Request",
|
||||||
|
@ -297,7 +297,8 @@ def make_reverse_gl_entries(gl_entries=None, voucher_type=None, voucher_no=None,
|
|||||||
fields = ["*"],
|
fields = ["*"],
|
||||||
filters = {
|
filters = {
|
||||||
"voucher_type": voucher_type,
|
"voucher_type": voucher_type,
|
||||||
"voucher_no": voucher_no
|
"voucher_no": voucher_no,
|
||||||
|
"is_cancelled": 0
|
||||||
})
|
})
|
||||||
|
|
||||||
if gl_entries:
|
if gl_entries:
|
||||||
|
@ -2,16 +2,19 @@
|
|||||||
# License: GNU General Public License v3. See license.txt
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
import datetime
|
||||||
|
from six import iteritems
|
||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.utils import flt
|
from frappe.utils import flt, formatdate
|
||||||
from frappe.utils import formatdate
|
|
||||||
from erpnext.controllers.trends import get_period_date_ranges, get_period_month_ranges
|
from erpnext.controllers.trends import get_period_date_ranges, get_period_month_ranges
|
||||||
|
|
||||||
from six import iteritems
|
|
||||||
from pprint import pprint
|
|
||||||
def execute(filters=None):
|
def execute(filters=None):
|
||||||
if not filters: filters = {}
|
if not filters:
|
||||||
|
filters = {}
|
||||||
|
|
||||||
columns = get_columns(filters)
|
columns = get_columns(filters)
|
||||||
if filters.get("budget_against_filter"):
|
if filters.get("budget_against_filter"):
|
||||||
@ -43,20 +46,25 @@ def execute(filters=None):
|
|||||||
|
|
||||||
period_data[0] += last_total
|
period_data[0] += last_total
|
||||||
|
|
||||||
if(filters.get("show_cumulative")):
|
if filters.get("show_cumulative"):
|
||||||
last_total = period_data[0] - period_data[1]
|
last_total = period_data[0] - period_data[1]
|
||||||
|
|
||||||
period_data[2] = period_data[0] - period_data[1]
|
period_data[2] = period_data[0] - period_data[1]
|
||||||
row += period_data
|
row += period_data
|
||||||
totals[2] = totals[0] - totals[1]
|
totals[2] = totals[0] - totals[1]
|
||||||
if filters["period"] != "Yearly" :
|
if filters["period"] != "Yearly":
|
||||||
row += totals
|
row += totals
|
||||||
data.append(row)
|
data.append(row)
|
||||||
|
|
||||||
return columns, data
|
return columns, data
|
||||||
|
|
||||||
|
|
||||||
def get_columns(filters):
|
def get_columns(filters):
|
||||||
columns = [_(filters.get("budget_against")) + ":Link/%s:150"%(filters.get("budget_against")), _("Account") + ":Link/Account:150"]
|
columns = [
|
||||||
|
_(filters.get("budget_against"))
|
||||||
|
+ ":Link/%s:150" % (filters.get("budget_against")),
|
||||||
|
_("Account") + ":Link/Account:150"
|
||||||
|
]
|
||||||
|
|
||||||
group_months = False if filters["period"] == "Monthly" else True
|
group_months = False if filters["period"] == "Monthly" else True
|
||||||
|
|
||||||
@ -65,84 +73,181 @@ def get_columns(filters):
|
|||||||
for year in fiscal_year:
|
for year in fiscal_year:
|
||||||
for from_date, to_date in get_period_date_ranges(filters["period"], year[0]):
|
for from_date, to_date in get_period_date_ranges(filters["period"], year[0]):
|
||||||
if filters["period"] == "Yearly":
|
if filters["period"] == "Yearly":
|
||||||
labels = [_("Budget") + " " + str(year[0]), _("Actual ") + " " + str(year[0]), _("Variance ") + " " + str(year[0])]
|
labels = [
|
||||||
|
_("Budget") + " " + str(year[0]),
|
||||||
|
_("Actual ") + " " + str(year[0]),
|
||||||
|
_("Variance ") + " " + str(year[0])
|
||||||
|
]
|
||||||
for label in labels:
|
for label in labels:
|
||||||
columns.append(label+":Float:150")
|
columns.append(label + ":Float:150")
|
||||||
else:
|
else:
|
||||||
for label in [_("Budget") + " (%s)" + " " + str(year[0]), _("Actual") + " (%s)" + " " + str(year[0]), _("Variance") + " (%s)" + " " + str(year[0])]:
|
for label in [
|
||||||
|
_("Budget") + " (%s)" + " " + str(year[0]),
|
||||||
|
_("Actual") + " (%s)" + " " + str(year[0]),
|
||||||
|
_("Variance") + " (%s)" + " " + str(year[0])
|
||||||
|
]:
|
||||||
if group_months:
|
if group_months:
|
||||||
label = label % (formatdate(from_date, format_string="MMM") + "-" + formatdate(to_date, format_string="MMM"))
|
label = label % (
|
||||||
|
formatdate(from_date, format_string="MMM")
|
||||||
|
+ "-"
|
||||||
|
+ formatdate(to_date, format_string="MMM")
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
label = label % formatdate(from_date, format_string="MMM")
|
label = label % formatdate(from_date, format_string="MMM")
|
||||||
|
|
||||||
columns.append(label+":Float:150")
|
columns.append(label + ":Float:150")
|
||||||
|
|
||||||
if filters["period"] != "Yearly" :
|
if filters["period"] != "Yearly":
|
||||||
return columns + [_("Total Budget") + ":Float:150", _("Total Actual") + ":Float:150",
|
return columns + [
|
||||||
_("Total Variance") + ":Float:150"]
|
_("Total Budget") + ":Float:150",
|
||||||
|
_("Total Actual") + ":Float:150",
|
||||||
|
_("Total Variance") + ":Float:150"
|
||||||
|
]
|
||||||
else:
|
else:
|
||||||
return columns
|
return columns
|
||||||
|
|
||||||
|
|
||||||
def get_cost_centers(filters):
|
def get_cost_centers(filters):
|
||||||
cond = "and 1=1"
|
order_by = ""
|
||||||
if filters.get("budget_against") == "Cost Center":
|
if filters.get("budget_against") == "Cost Center":
|
||||||
cond = "order by lft"
|
order_by = "order by lft"
|
||||||
|
|
||||||
if filters.get("budget_against") in ["Cost Center", "Project"]:
|
if filters.get("budget_against") in ["Cost Center", "Project"]:
|
||||||
return frappe.db.sql_list("""select name from `tab{tab}` where company=%s
|
return frappe.db.sql_list(
|
||||||
{cond}""".format(tab=filters.get("budget_against"), cond=cond), filters.get("company"))
|
"""
|
||||||
|
select
|
||||||
|
name
|
||||||
|
from
|
||||||
|
`tab{tab}`
|
||||||
|
where
|
||||||
|
company = %s
|
||||||
|
{order_by}
|
||||||
|
""".format(tab=filters.get("budget_against"), order_by=order_by),
|
||||||
|
filters.get("company"))
|
||||||
else:
|
else:
|
||||||
return frappe.db.sql_list("""select name from `tab{tab}`""".format(tab=filters.get("budget_against"))) #nosec
|
return frappe.db.sql_list(
|
||||||
|
"""
|
||||||
|
select
|
||||||
|
name
|
||||||
|
from
|
||||||
|
`tab{tab}`
|
||||||
|
""".format(tab=filters.get("budget_against"))) # nosec
|
||||||
|
|
||||||
#Get dimension & target details
|
|
||||||
|
# Get dimension & target details
|
||||||
def get_dimension_target_details(filters):
|
def get_dimension_target_details(filters):
|
||||||
|
budget_against = frappe.scrub(filters.get("budget_against"))
|
||||||
cond = ""
|
cond = ""
|
||||||
if filters.get("budget_against_filter"):
|
if filters.get("budget_against_filter"):
|
||||||
cond += " and b.{budget_against} in (%s)".format(budget_against = \
|
cond += """ and b.{budget_against} in (%s)""".format(
|
||||||
frappe.scrub(filters.get('budget_against'))) % ', '.join(['%s']* len(filters.get('budget_against_filter')))
|
budget_against=budget_against) % ", ".join(["%s"] * len(filters.get("budget_against_filter")))
|
||||||
|
|
||||||
return frappe.db.sql("""
|
return frappe.db.sql(
|
||||||
select b.{budget_against} as budget_against, b.monthly_distribution, ba.account, ba.budget_amount,b.fiscal_year
|
"""
|
||||||
from `tabBudget` b, `tabBudget Account` ba
|
select
|
||||||
where b.name=ba.parent and b.docstatus = 1 and b.fiscal_year between %s and %s
|
b.{budget_against} as budget_against,
|
||||||
and b.budget_against = %s and b.company=%s {cond} order by b.fiscal_year
|
b.monthly_distribution,
|
||||||
""".format(budget_against=filters.get("budget_against").replace(" ", "_").lower(), cond=cond),
|
ba.account,
|
||||||
tuple([filters.from_fiscal_year,filters.to_fiscal_year,filters.budget_against, filters.company] + filters.get('budget_against_filter')),
|
ba.budget_amount,
|
||||||
as_dict=True)
|
b.fiscal_year
|
||||||
|
from
|
||||||
|
`tabBudget` b,
|
||||||
|
`tabBudget Account` ba
|
||||||
|
where
|
||||||
|
b.name = ba.parent
|
||||||
|
and b.docstatus = 1
|
||||||
|
and b.fiscal_year between %s and %s
|
||||||
|
and b.budget_against = %s
|
||||||
|
and b.company = %s
|
||||||
|
{cond}
|
||||||
|
order by
|
||||||
|
b.fiscal_year
|
||||||
|
""".format(
|
||||||
|
budget_against=budget_against,
|
||||||
|
cond=cond,
|
||||||
|
),
|
||||||
|
tuple(
|
||||||
|
[
|
||||||
|
filters.from_fiscal_year,
|
||||||
|
filters.to_fiscal_year,
|
||||||
|
filters.budget_against,
|
||||||
|
filters.company,
|
||||||
|
]
|
||||||
|
+ filters.get("budget_against_filter")
|
||||||
|
), as_dict=True)
|
||||||
|
|
||||||
|
|
||||||
#Get target distribution details of accounts of cost center
|
# Get target distribution details of accounts of cost center
|
||||||
def get_target_distribution_details(filters):
|
def get_target_distribution_details(filters):
|
||||||
target_details = {}
|
target_details = {}
|
||||||
for d in frappe.db.sql("""select md.name, mdp.month, mdp.percentage_allocation
|
for d in frappe.db.sql(
|
||||||
from `tabMonthly Distribution Percentage` mdp, `tabMonthly Distribution` md
|
"""
|
||||||
where mdp.parent=md.name and md.fiscal_year between %s and %s order by md.fiscal_year""",(filters.from_fiscal_year, filters.to_fiscal_year), as_dict=1):
|
select
|
||||||
target_details.setdefault(d.name, {}).setdefault(d.month, flt(d.percentage_allocation))
|
md.name,
|
||||||
|
mdp.month,
|
||||||
|
mdp.percentage_allocation
|
||||||
|
from
|
||||||
|
`tabMonthly Distribution Percentage` mdp,
|
||||||
|
`tabMonthly Distribution` md
|
||||||
|
where
|
||||||
|
mdp.parent = md.name
|
||||||
|
and md.fiscal_year between %s and %s
|
||||||
|
order by
|
||||||
|
md.fiscal_year
|
||||||
|
""",
|
||||||
|
(filters.from_fiscal_year, filters.to_fiscal_year), as_dict=1):
|
||||||
|
target_details.setdefault(d.name, {}).setdefault(
|
||||||
|
d.month, flt(d.percentage_allocation)
|
||||||
|
)
|
||||||
|
|
||||||
return target_details
|
return target_details
|
||||||
|
|
||||||
#Get actual details from gl entry
|
# Get actual details from gl entry
|
||||||
def get_actual_details(name, filters):
|
def get_actual_details(name, filters):
|
||||||
cond = "1=1"
|
budget_against = frappe.scrub(filters.get("budget_against"))
|
||||||
budget_against=filters.get("budget_against").replace(" ", "_").lower()
|
cond = ""
|
||||||
|
|
||||||
if filters.get("budget_against") == "Cost Center":
|
if filters.get("budget_against") == "Cost Center":
|
||||||
cc_lft, cc_rgt = frappe.db.get_value("Cost Center", name, ["lft", "rgt"])
|
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)
|
cond = """
|
||||||
|
and lft >= "{lft}"
|
||||||
|
and rgt <= "{rgt}"
|
||||||
|
""".format(lft=cc_lft, rgt=cc_rgt)
|
||||||
|
|
||||||
ac_details = frappe.db.sql("""select gl.account, gl.debit, gl.credit,gl.fiscal_year,
|
ac_details = frappe.db.sql(
|
||||||
MONTHNAME(gl.posting_date) as month_name, b.{budget_against} as budget_against
|
"""
|
||||||
from `tabGL Entry` gl, `tabBudget Account` ba, `tabBudget` b
|
select
|
||||||
where
|
gl.account,
|
||||||
b.name = ba.parent
|
gl.debit,
|
||||||
and b.docstatus = 1
|
gl.credit,
|
||||||
and ba.account=gl.account
|
gl.fiscal_year,
|
||||||
and b.{budget_against} = gl.{budget_against}
|
MONTHNAME(gl.posting_date) as month_name,
|
||||||
and gl.fiscal_year between %s and %s
|
b.{budget_against} as budget_against
|
||||||
and b.{budget_against}=%s
|
from
|
||||||
and exists(select name from `tab{tab}` where name=gl.{budget_against} and {cond}) group by gl.name order by gl.fiscal_year
|
`tabGL Entry` gl,
|
||||||
""".format(tab = filters.budget_against, budget_against = budget_against, cond = cond,from_year=filters.from_fiscal_year,to_year=filters.to_fiscal_year),
|
`tabBudget Account` ba,
|
||||||
(filters.from_fiscal_year, filters.to_fiscal_year, name), as_dict=1)
|
`tabBudget` b
|
||||||
|
where
|
||||||
|
b.name = ba.parent
|
||||||
|
and b.docstatus = 1
|
||||||
|
and ba.account=gl.account
|
||||||
|
and b.{budget_against} = gl.{budget_against}
|
||||||
|
and gl.fiscal_year between %s and %s
|
||||||
|
and b.{budget_against} = %s
|
||||||
|
and exists(
|
||||||
|
select
|
||||||
|
name
|
||||||
|
from
|
||||||
|
`tab{tab}`
|
||||||
|
where
|
||||||
|
name = gl.{budget_against}
|
||||||
|
{cond}
|
||||||
|
)
|
||||||
|
group by
|
||||||
|
gl.name
|
||||||
|
order by gl.fiscal_year
|
||||||
|
""".format(tab=filters.budget_against, budget_against=budget_against, cond=cond),
|
||||||
|
(filters.from_fiscal_year, filters.to_fiscal_year, name), as_dict=1)
|
||||||
|
|
||||||
cc_actual_details = {}
|
cc_actual_details = {}
|
||||||
for d in ac_details:
|
for d in ac_details:
|
||||||
@ -151,7 +256,6 @@ def get_actual_details(name, filters):
|
|||||||
return cc_actual_details
|
return cc_actual_details
|
||||||
|
|
||||||
def get_dimension_account_month_map(filters):
|
def get_dimension_account_month_map(filters):
|
||||||
import datetime
|
|
||||||
dimension_target_details = get_dimension_target_details(filters)
|
dimension_target_details = get_dimension_target_details(filters)
|
||||||
tdd = get_target_distribution_details(filters)
|
tdd = get_target_distribution_details(filters)
|
||||||
|
|
||||||
@ -161,28 +265,43 @@ def get_dimension_account_month_map(filters):
|
|||||||
actual_details = get_actual_details(ccd.budget_against, filters)
|
actual_details = get_actual_details(ccd.budget_against, filters)
|
||||||
|
|
||||||
for month_id in range(1, 13):
|
for month_id in range(1, 13):
|
||||||
month = datetime.date(2013, month_id, 1).strftime('%B')
|
month = datetime.date(2013, month_id, 1).strftime("%B")
|
||||||
cam_map.setdefault(ccd.budget_against, {}).setdefault(ccd.account, {}).setdefault(ccd.fiscal_year,{})\
|
cam_map.setdefault(ccd.budget_against, {}).setdefault(
|
||||||
.setdefault(month, frappe._dict({
|
ccd.account, {}
|
||||||
"target": 0.0, "actual": 0.0
|
).setdefault(ccd.fiscal_year, {}).setdefault(
|
||||||
}))
|
month, frappe._dict({"target": 0.0, "actual": 0.0})
|
||||||
|
)
|
||||||
|
|
||||||
tav_dict = cam_map[ccd.budget_against][ccd.account][ccd.fiscal_year][month]
|
tav_dict = cam_map[ccd.budget_against][ccd.account][ccd.fiscal_year][month]
|
||||||
month_percentage = tdd.get(ccd.monthly_distribution, {}).get(month, 0) \
|
month_percentage = (
|
||||||
if ccd.monthly_distribution else 100.0/12
|
tdd.get(ccd.monthly_distribution, {}).get(month, 0)
|
||||||
|
if ccd.monthly_distribution
|
||||||
|
else 100.0 / 12
|
||||||
|
)
|
||||||
|
|
||||||
tav_dict.target = flt(ccd.budget_amount) * month_percentage / 100
|
tav_dict.target = flt(ccd.budget_amount) * month_percentage / 100
|
||||||
|
|
||||||
for ad in actual_details.get(ccd.account, []):
|
for ad in actual_details.get(ccd.account, []):
|
||||||
if ad.month_name == month:
|
if ad.month_name == month and ad.fiscal_year == ccd.fiscal_year:
|
||||||
tav_dict.actual += flt(ad.debit) - flt(ad.credit)
|
tav_dict.actual += flt(ad.debit) - flt(ad.credit)
|
||||||
|
|
||||||
return cam_map
|
return cam_map
|
||||||
|
|
||||||
|
|
||||||
def get_fiscal_years(filters):
|
def get_fiscal_years(filters):
|
||||||
|
|
||||||
fiscal_year = frappe.db.sql("""select name from `tabFiscal Year` where
|
fiscal_year = frappe.db.sql(
|
||||||
name between %(from_fiscal_year)s and %(to_fiscal_year)s""",
|
"""
|
||||||
{'from_fiscal_year': filters["from_fiscal_year"], 'to_fiscal_year': filters["to_fiscal_year"]})
|
select
|
||||||
|
name
|
||||||
|
from
|
||||||
|
`tabFiscal Year`
|
||||||
|
where
|
||||||
|
name between %(from_fiscal_year)s and %(to_fiscal_year)s
|
||||||
|
""",
|
||||||
|
{
|
||||||
|
"from_fiscal_year": filters["from_fiscal_year"],
|
||||||
|
"to_fiscal_year": filters["to_fiscal_year"]
|
||||||
|
})
|
||||||
|
|
||||||
return fiscal_year
|
return fiscal_year
|
||||||
|
@ -9,8 +9,8 @@ from erpnext.accounts.report.financial_statements import (get_period_list, get_c
|
|||||||
import copy
|
import copy
|
||||||
|
|
||||||
def execute(filters=None):
|
def execute(filters=None):
|
||||||
period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year,
|
period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year, filters.period_start_date,
|
||||||
filters.periodicity, filters.accumulated_values, filters.company)
|
filters.period_end_date, filters.filter_based_on, filters.periodicity, filters.accumulated_values, filters.company)
|
||||||
|
|
||||||
columns, data = [], []
|
columns, data = [], []
|
||||||
|
|
||||||
|
@ -141,7 +141,7 @@
|
|||||||
],
|
],
|
||||||
"is_tree": 1,
|
"is_tree": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-03-18 18:00:08.885805",
|
"modified": "2020-05-08 16:11:11.375701",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Assets",
|
"module": "Assets",
|
||||||
"name": "Location",
|
"name": "Location",
|
||||||
@ -221,7 +221,6 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"quick_entry": 1,
|
"quick_entry": 1,
|
||||||
"restrict_to_domain": "Agriculture",
|
|
||||||
"show_name_in_global_search": 1,
|
"show_name_in_global_search": 1,
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
|
@ -153,7 +153,7 @@ class Lead(SellingController):
|
|||||||
if not self.lead_name:
|
if not self.lead_name:
|
||||||
self.set_lead_name()
|
self.set_lead_name()
|
||||||
|
|
||||||
names = self.lead_name.split(" ")
|
names = self.lead_name.strip().split(" ")
|
||||||
if len(names) > 1:
|
if len(names) > 1:
|
||||||
first_name, last_name = names[0], " ".join(names[1:])
|
first_name, last_name = names[0], " ".join(names[1:])
|
||||||
else:
|
else:
|
||||||
|
@ -62,6 +62,8 @@ frappe.ui.form.on('LinkedIn Settings', {
|
|||||||
callback : function(r) {
|
callback : function(r) {
|
||||||
window.location.href = r.message;
|
window.location.href = r.message;
|
||||||
}
|
}
|
||||||
|
}).fail(function() {
|
||||||
|
frappe.dom.unfreeze();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -15,7 +15,7 @@ class LinkedInSettings(Document):
|
|||||||
params = urlencode({
|
params = urlencode({
|
||||||
"response_type":"code",
|
"response_type":"code",
|
||||||
"client_id": self.consumer_key,
|
"client_id": self.consumer_key,
|
||||||
"redirect_uri": get_site_url(frappe.local.site) + "/?cmd=erpnext.crm.doctype.linkedin_settings.linkedin_settings.callback",
|
"redirect_uri": get_site_url(frappe.local.site) + "/api/method/erpnext.crm.doctype.linkedin_settings.linkedin_settings.callback?",
|
||||||
"scope": "r_emailaddress w_organization_social r_basicprofile r_liteprofile r_organization_social rw_organization_admin w_member_social"
|
"scope": "r_emailaddress w_organization_social r_basicprofile r_liteprofile r_organization_social rw_organization_admin w_member_social"
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ class LinkedInSettings(Document):
|
|||||||
"code": code,
|
"code": code,
|
||||||
"client_id": self.consumer_key,
|
"client_id": self.consumer_key,
|
||||||
"client_secret": self.get_password(fieldname="consumer_secret"),
|
"client_secret": self.get_password(fieldname="consumer_secret"),
|
||||||
"redirect_uri": get_site_url(frappe.local.site) + "/?cmd=erpnext.crm.doctype.linkedin_settings.linkedin_settings.callback",
|
"redirect_uri": get_site_url(frappe.local.site) + "/api/method/erpnext.crm.doctype.linkedin_settings.linkedin_settings.callback?",
|
||||||
}
|
}
|
||||||
headers = {
|
headers = {
|
||||||
"Content-Type": "application/x-www-form-urlencoded"
|
"Content-Type": "application/x-www-form-urlencoded"
|
||||||
@ -154,7 +154,7 @@ class LinkedInSettings(Document):
|
|||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist(allow_guest=True)
|
||||||
def callback(code=None, error=None, error_description=None):
|
def callback(code=None, error=None, error_description=None):
|
||||||
if not error:
|
if not error:
|
||||||
linkedin_settings = frappe.get_doc("LinkedIn Settings")
|
linkedin_settings = frappe.get_doc("LinkedIn Settings")
|
||||||
|
@ -47,6 +47,8 @@ frappe.ui.form.on('Twitter Settings', {
|
|||||||
callback : function(r) {
|
callback : function(r) {
|
||||||
window.location.href = r.message;
|
window.location.href = r.message;
|
||||||
}
|
}
|
||||||
|
}).fail(function() {
|
||||||
|
frappe.dom.unfreeze();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -12,13 +12,12 @@ from tweepy.error import TweepError
|
|||||||
|
|
||||||
class TwitterSettings(Document):
|
class TwitterSettings(Document):
|
||||||
def get_authorize_url(self):
|
def get_authorize_url(self):
|
||||||
callback_url = "{0}/?cmd=erpnext.crm.doctype.twitter_settings.twitter_settings.callback".format(frappe.utils.get_url())
|
callback_url = "{0}/api/method/erpnext.crm.doctype.twitter_settings.twitter_settings.callback?".format(frappe.utils.get_url())
|
||||||
auth = tweepy.OAuthHandler(self.consumer_key, self.get_password(fieldname="consumer_secret"), callback_url)
|
auth = tweepy.OAuthHandler(self.consumer_key, self.get_password(fieldname="consumer_secret"), callback_url)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
redirect_url = auth.get_authorization_url()
|
redirect_url = auth.get_authorization_url()
|
||||||
return redirect_url
|
return redirect_url
|
||||||
except:
|
except tweepy.TweepError as e:
|
||||||
frappe.msgprint(_("Error! Failed to get request token."))
|
frappe.msgprint(_("Error! Failed to get request token."))
|
||||||
frappe.throw(_('Invalid {0} or {1}').format(frappe.bold("Consumer Key"), frappe.bold("Consumer Secret Key")))
|
frappe.throw(_('Invalid {0} or {1}').format(frappe.bold("Consumer Key"), frappe.bold("Consumer Secret Key")))
|
||||||
|
|
||||||
@ -91,8 +90,12 @@ class TwitterSettings(Document):
|
|||||||
frappe.db.commit()
|
frappe.db.commit()
|
||||||
frappe.throw(content["message"],title="Twitter Error {0} {1}".format(e.response.status_code, e.response.reason))
|
frappe.throw(content["message"],title="Twitter Error {0} {1}".format(e.response.status_code, e.response.reason))
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist(allow_guest=True)
|
||||||
def callback(oauth_token, oauth_verifier):
|
def callback(oauth_token = None, oauth_verifier = None):
|
||||||
twitter_settings = frappe.get_single("Twitter Settings")
|
if oauth_token and oauth_verifier:
|
||||||
twitter_settings.get_access_token(oauth_token,oauth_verifier)
|
twitter_settings = frappe.get_single("Twitter Settings")
|
||||||
frappe.db.commit()
|
twitter_settings.get_access_token(oauth_token,oauth_verifier)
|
||||||
|
frappe.db.commit()
|
||||||
|
else:
|
||||||
|
frappe.local.response["type"] = "redirect"
|
||||||
|
frappe.local.response["location"] = get_url_to_form("Twitter Settings","Twitter Settings")
|
||||||
|
@ -19,6 +19,5 @@ def update_lead_phone_numbers(contact, method):
|
|||||||
mobile_no = primary_mobile_nos[0]
|
mobile_no = primary_mobile_nos[0]
|
||||||
|
|
||||||
lead = frappe.get_doc("Lead", contact_lead)
|
lead = frappe.get_doc("Lead", contact_lead)
|
||||||
lead.phone = phone
|
lead.db_set("phone", phone)
|
||||||
lead.mobile_no = mobile_no
|
lead.db_set("mobile_no", mobile_no)
|
||||||
lead.save()
|
|
||||||
|
@ -1,790 +1,207 @@
|
|||||||
{
|
{
|
||||||
"allow_copy": 0,
|
"actions": [],
|
||||||
"allow_guest_to_view": 0,
|
|
||||||
"allow_import": 1,
|
"allow_import": 1,
|
||||||
"allow_rename": 0,
|
|
||||||
"autoname": "EDU-ASP-.YYYY.-.#####",
|
"autoname": "EDU-ASP-.YYYY.-.#####",
|
||||||
"beta": 0,
|
|
||||||
"creation": "2015-11-12 16:34:34.658092",
|
"creation": "2015-11-12 16:34:34.658092",
|
||||||
"custom": 0,
|
|
||||||
"docstatus": 0,
|
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "Setup",
|
"document_type": "Setup",
|
||||||
"editable_grid": 0,
|
|
||||||
"engine": "InnoDB",
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"student_group",
|
||||||
|
"assessment_name",
|
||||||
|
"assessment_group",
|
||||||
|
"grading_scale",
|
||||||
|
"column_break_2",
|
||||||
|
"course",
|
||||||
|
"program",
|
||||||
|
"academic_year",
|
||||||
|
"academic_term",
|
||||||
|
"section_break_5",
|
||||||
|
"schedule_date",
|
||||||
|
"room",
|
||||||
|
"examiner",
|
||||||
|
"examiner_name",
|
||||||
|
"column_break_4",
|
||||||
|
"from_time",
|
||||||
|
"to_time",
|
||||||
|
"supervisor",
|
||||||
|
"supervisor_name",
|
||||||
|
"section_break_20",
|
||||||
|
"maximum_assessment_score",
|
||||||
|
"assessment_criteria",
|
||||||
|
"amended_from"
|
||||||
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "student_group",
|
"fieldname": "student_group",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 1,
|
"in_global_search": 1,
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 1,
|
"in_standard_filter": 1,
|
||||||
"label": "Student Group",
|
"label": "Student Group",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Student Group",
|
"options": "Student Group",
|
||||||
"permlevel": 0,
|
"reqd": 1
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "assessment_name",
|
"fieldname": "assessment_name",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 1,
|
"in_global_search": 1,
|
||||||
"in_list_view": 0,
|
"label": "Assessment Name"
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Assessment Name",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "assessment_group",
|
"fieldname": "assessment_group",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 1,
|
"in_standard_filter": 1,
|
||||||
"label": "Assessment Group",
|
"label": "Assessment Group",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Assessment Group",
|
"options": "Assessment Group",
|
||||||
"permlevel": 0,
|
"reqd": 1
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_from": "course.default_grading_scale",
|
"fetch_from": "course.default_grading_scale",
|
||||||
|
"fetch_if_empty": 1,
|
||||||
"fieldname": "grading_scale",
|
"fieldname": "grading_scale",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 1,
|
"in_standard_filter": 1,
|
||||||
"label": "Grading Scale",
|
"label": "Grading Scale",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Grading Scale",
|
"options": "Grading Scale",
|
||||||
"permlevel": 0,
|
"reqd": 1
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "column_break_2",
|
"fieldname": "column_break_2",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break"
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_from": "student_group.course",
|
"fetch_from": "student_group.course",
|
||||||
|
"fetch_if_empty": 1,
|
||||||
"fieldname": "course",
|
"fieldname": "course",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 1,
|
"in_global_search": 1,
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 1,
|
"in_standard_filter": 1,
|
||||||
"label": "Course",
|
"label": "Course",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Course",
|
"options": "Course",
|
||||||
"permlevel": 0,
|
"reqd": 1
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_from": "student_group.program",
|
"fetch_from": "student_group.program",
|
||||||
"fieldname": "program",
|
"fieldname": "program",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 1,
|
"in_global_search": 1,
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Program",
|
"label": "Program",
|
||||||
"length": 0,
|
"options": "Program"
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Program",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_from": "student_group.academic_year",
|
"fetch_from": "student_group.academic_year",
|
||||||
"fieldname": "academic_year",
|
"fieldname": "academic_year",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Academic Year",
|
"label": "Academic Year",
|
||||||
"length": 0,
|
"options": "Academic Year"
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Academic Year",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_from": "student_group.academic_term",
|
"fetch_from": "student_group.academic_term",
|
||||||
"fieldname": "academic_term",
|
"fieldname": "academic_term",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Academic Term",
|
"label": "Academic Term",
|
||||||
"length": 0,
|
"options": "Academic Term"
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Academic Term",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"collapsible_depends_on": "",
|
|
||||||
"columns": 0,
|
|
||||||
"depends_on": "",
|
|
||||||
"fieldname": "section_break_5",
|
"fieldname": "section_break_5",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"hidden": 0,
|
"label": "Schedule"
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Schedule",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"default": "Today",
|
"default": "Today",
|
||||||
"fieldname": "schedule_date",
|
"fieldname": "schedule_date",
|
||||||
"fieldtype": "Date",
|
"fieldtype": "Date",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Schedule Date",
|
"label": "Schedule Date",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"permlevel": 0,
|
"reqd": 1
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "room",
|
"fieldname": "room",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Room",
|
"label": "Room",
|
||||||
"length": 0,
|
"options": "Room"
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Room",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "examiner",
|
"fieldname": "examiner",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Examiner",
|
"label": "Examiner",
|
||||||
"length": 0,
|
"options": "Instructor"
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Instructor",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_from": "examiner.instructor_name",
|
"fetch_from": "examiner.instructor_name",
|
||||||
"fieldname": "examiner_name",
|
"fieldname": "examiner_name",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Examiner Name",
|
"label": "Examiner Name",
|
||||||
"length": 0,
|
"read_only": 1
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "column_break_4",
|
"fieldname": "column_break_4",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break"
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "from_time",
|
"fieldname": "from_time",
|
||||||
"fieldtype": "Time",
|
"fieldtype": "Time",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "From Time",
|
"label": "From Time",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"permlevel": 0,
|
"reqd": 1
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "to_time",
|
"fieldname": "to_time",
|
||||||
"fieldtype": "Time",
|
"fieldtype": "Time",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "To Time",
|
"label": "To Time",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"permlevel": 0,
|
"reqd": 1
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "supervisor",
|
"fieldname": "supervisor",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Supervisor",
|
"label": "Supervisor",
|
||||||
"length": 0,
|
"options": "Instructor"
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Instructor",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_from": "supervisor.instructor_name",
|
"fetch_from": "supervisor.instructor_name",
|
||||||
"fieldname": "supervisor_name",
|
"fieldname": "supervisor_name",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 1,
|
"in_global_search": 1,
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Supervisor Name",
|
"label": "Supervisor Name",
|
||||||
"length": 0,
|
"read_only": 1
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "section_break_20",
|
"fieldname": "section_break_20",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"hidden": 0,
|
"label": "Evaluate"
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Evaluate",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "maximum_assessment_score",
|
"fieldname": "maximum_assessment_score",
|
||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Maximum Assessment Score",
|
"label": "Maximum Assessment Score",
|
||||||
"length": 0,
|
"reqd": 1
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "assessment_criteria",
|
"fieldname": "assessment_criteria",
|
||||||
"fieldtype": "Table",
|
"fieldtype": "Table",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Assessment Criteria",
|
"label": "Assessment Criteria",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Assessment Plan Criteria",
|
"options": "Assessment Plan Criteria",
|
||||||
"permlevel": 0,
|
"reqd": 1
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "amended_from",
|
"fieldname": "amended_from",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Amended From",
|
"label": "Amended From",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"options": "Assessment Plan",
|
"options": "Assessment Plan",
|
||||||
"permlevel": 0,
|
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"print_hide_if_no_value": 0,
|
"read_only": 1
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"has_web_view": 0,
|
|
||||||
"hide_heading": 0,
|
|
||||||
"hide_toolbar": 0,
|
|
||||||
"idx": 0,
|
|
||||||
"image_view": 0,
|
|
||||||
"in_create": 0,
|
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"issingle": 0,
|
"links": [],
|
||||||
"istable": 0,
|
"modified": "2020-05-09 14:56:26.746988",
|
||||||
"max_attachments": 0,
|
|
||||||
"menu_index": 0,
|
|
||||||
"modified": "2018-08-30 00:48:03.475522",
|
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Education",
|
"module": "Education",
|
||||||
"name": "Assessment Plan",
|
"name": "Assessment Plan",
|
||||||
"name_case": "",
|
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"permissions": [
|
"permissions": [
|
||||||
{
|
{
|
||||||
@ -794,28 +211,17 @@
|
|||||||
"delete": 1,
|
"delete": 1,
|
||||||
"email": 1,
|
"email": 1,
|
||||||
"export": 1,
|
"export": 1,
|
||||||
"if_owner": 0,
|
|
||||||
"import": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print": 1,
|
"print": 1,
|
||||||
"read": 1,
|
"read": 1,
|
||||||
"report": 1,
|
"report": 1,
|
||||||
"role": "Academics User",
|
"role": "Academics User",
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
"share": 1,
|
||||||
"submit": 1,
|
"submit": 1,
|
||||||
"write": 1
|
"write": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"quick_entry": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"read_only_onload": 0,
|
|
||||||
"restrict_to_domain": "Education",
|
"restrict_to_domain": "Education",
|
||||||
"show_name_in_global_search": 0,
|
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
"title_field": "assessment_name",
|
"title_field": "assessment_name"
|
||||||
"track_changes": 0,
|
|
||||||
"track_seen": 0,
|
|
||||||
"track_views": 0
|
|
||||||
}
|
}
|
@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"actions": [],
|
||||||
"creation": "2017-04-05 13:33:04.519313",
|
"creation": "2017-04-05 13:33:04.519313",
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"editable_grid": 1,
|
"editable_grid": 1,
|
||||||
@ -42,12 +43,14 @@
|
|||||||
"fieldtype": "Column Break"
|
"fieldtype": "Column Break"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": "0",
|
||||||
"description": "For Batch based Student Group, the Student Batch will be validated for every Student from the Program Enrollment.",
|
"description": "For Batch based Student Group, the Student Batch will be validated for every Student from the Program Enrollment.",
|
||||||
"fieldname": "validate_batch",
|
"fieldname": "validate_batch",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Validate Batch for Students in Student Group"
|
"label": "Validate Batch for Students in Student Group"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": "0",
|
||||||
"description": "For Course based Student Group, the Course will be validated for every Student from the enrolled Courses in Program Enrollment.",
|
"description": "For Course based Student Group, the Course will be validated for every Student from the enrolled Courses in Program Enrollment.",
|
||||||
"fieldname": "validate_course",
|
"fieldname": "validate_course",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
@ -74,13 +77,13 @@
|
|||||||
{
|
{
|
||||||
"fieldname": "web_academy_settings_section",
|
"fieldname": "web_academy_settings_section",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"label": "LMS Settings"
|
"label": "Learning Management System Settings"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"depends_on": "eval: doc.enable_lms",
|
"depends_on": "eval: doc.enable_lms",
|
||||||
"fieldname": "portal_title",
|
"fieldname": "portal_title",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"label": "LMS Title"
|
"label": "Learning Management System Title"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"depends_on": "eval: doc.enable_lms",
|
"depends_on": "eval: doc.enable_lms",
|
||||||
@ -89,9 +92,10 @@
|
|||||||
"label": "Description"
|
"label": "Description"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": "0",
|
||||||
"fieldname": "enable_lms",
|
"fieldname": "enable_lms",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "Enable LMS"
|
"label": "Enable Learning Management System"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "0",
|
"default": "0",
|
||||||
@ -102,7 +106,8 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"issingle": 1,
|
"issingle": 1,
|
||||||
"modified": "2019-05-13 18:36:13.127563",
|
"links": [],
|
||||||
|
"modified": "2020-05-07 19:18:10.639356",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Education",
|
"module": "Education",
|
||||||
"name": "Education Settings",
|
"name": "Education Settings",
|
||||||
|
41
erpnext/healthcare/dashboard_fixtures.py
Normal file
41
erpnext/healthcare/dashboard_fixtures.py
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
|
||||||
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
|
import frappe
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
def get_data():
|
||||||
|
return frappe._dict({
|
||||||
|
"dashboards": get_dashboards(),
|
||||||
|
"charts": get_charts(),
|
||||||
|
})
|
||||||
|
|
||||||
|
def get_dashboards():
|
||||||
|
return [{
|
||||||
|
"name": "Healthcare",
|
||||||
|
"dashboard_name": "Healthcare",
|
||||||
|
"charts": [
|
||||||
|
{ "chart": "Patient Appointments" }
|
||||||
|
]
|
||||||
|
}]
|
||||||
|
|
||||||
|
def get_charts():
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"doctype": "Dashboard Chart",
|
||||||
|
"time_interval": "Daily",
|
||||||
|
"name": "Patient Appointments",
|
||||||
|
"chart_name": "Patient Appointments",
|
||||||
|
"timespan": "Last Month",
|
||||||
|
"color": "#77ecca",
|
||||||
|
"filters_json": json.dumps({}),
|
||||||
|
"chart_type": "Count",
|
||||||
|
"timeseries": 1,
|
||||||
|
"based_on": "appointment_datetime",
|
||||||
|
"owner": "Administrator",
|
||||||
|
"document_type": "Patient Appointment",
|
||||||
|
"type": "Line",
|
||||||
|
"width": "Half"
|
||||||
|
}
|
||||||
|
]
|
@ -191,7 +191,7 @@
|
|||||||
"default": "Leave",
|
"default": "Leave",
|
||||||
"fieldname": "payroll_based_on",
|
"fieldname": "payroll_based_on",
|
||||||
"fieldtype": "Select",
|
"fieldtype": "Select",
|
||||||
"label": "Calculate Working Days in Payroll based on",
|
"label": "Calculate Payroll Working Days Based On",
|
||||||
"options": "Leave\nAttendance"
|
"options": "Leave\nAttendance"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -206,7 +206,7 @@
|
|||||||
"idx": 1,
|
"idx": 1,
|
||||||
"issingle": 1,
|
"issingle": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-04-13 21:20:59.382394",
|
"modified": "2020-05-11 13:02:51.274347",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "HR Settings",
|
"name": "HR Settings",
|
||||||
|
@ -145,7 +145,7 @@ def import_attendances(rows):
|
|||||||
|
|
||||||
def remove_holidays(rows):
|
def remove_holidays(rows):
|
||||||
rows = [ row for row in rows if row[4] != "Holiday"]
|
rows = [ row for row in rows if row[4] != "Holiday"]
|
||||||
return
|
return rows
|
||||||
|
|
||||||
from frappe.modules import scrub
|
from frappe.modules import scrub
|
||||||
|
|
||||||
|
@ -215,7 +215,7 @@ def get_conditions(filters):
|
|||||||
def get_employee_details(group_by, company):
|
def get_employee_details(group_by, company):
|
||||||
emp_map = {}
|
emp_map = {}
|
||||||
query = """select name, employee_name, designation, department, branch, company,
|
query = """select name, employee_name, designation, department, branch, company,
|
||||||
holiday_list from `tabEmployee` where company = '%s' """ % frappe.db.escape(company)
|
holiday_list from `tabEmployee` where company = %s """ % frappe.db.escape(company)
|
||||||
|
|
||||||
if group_by:
|
if group_by:
|
||||||
group_by = group_by.lower()
|
group_by = group_by.lower()
|
||||||
|
@ -248,8 +248,7 @@ def create_loan_security_unpledge(loan, applicant_type, applicant, company, as_d
|
|||||||
for loan_security in loan_security_pledge_details:
|
for loan_security in loan_security_pledge_details:
|
||||||
unpledge_request.append('securities', {
|
unpledge_request.append('securities', {
|
||||||
"loan_security": loan_security.loan_security,
|
"loan_security": loan_security.loan_security,
|
||||||
"qty": loan_security.qty,
|
"qty": loan_security.qty
|
||||||
"against_pledge": loan_security.parent
|
|
||||||
})
|
})
|
||||||
|
|
||||||
if as_dict:
|
if as_dict:
|
||||||
|
@ -15,6 +15,7 @@ from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_
|
|||||||
from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import days_in_year
|
from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import days_in_year
|
||||||
from erpnext.loan_management.doctype.process_loan_security_shortfall.process_loan_security_shortfall import create_process_loan_security_shortfall
|
from erpnext.loan_management.doctype.process_loan_security_shortfall.process_loan_security_shortfall import create_process_loan_security_shortfall
|
||||||
from erpnext.loan_management.doctype.loan.loan import create_loan_security_unpledge
|
from erpnext.loan_management.doctype.loan.loan import create_loan_security_unpledge
|
||||||
|
from erpnext.loan_management.doctype.loan_security_unpledge.loan_security_unpledge import get_pledged_security_qty
|
||||||
|
|
||||||
class TestLoan(unittest.TestCase):
|
class TestLoan(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@ -152,7 +153,7 @@ class TestLoan(unittest.TestCase):
|
|||||||
repayment_entry.save()
|
repayment_entry.save()
|
||||||
repayment_entry.submit()
|
repayment_entry.submit()
|
||||||
|
|
||||||
penalty_amount = (accrued_interest_amount * 5 * 25) / (100 * days_in_year(get_datetime(first_date).year))
|
penalty_amount = (accrued_interest_amount * 4 * 25) / (100 * days_in_year(get_datetime(first_date).year))
|
||||||
self.assertEquals(flt(repayment_entry.penalty_amount, 2), flt(penalty_amount, 2))
|
self.assertEquals(flt(repayment_entry.penalty_amount, 2), flt(penalty_amount, 2))
|
||||||
|
|
||||||
amounts = frappe.db.get_value('Loan Interest Accrual', {'loan': loan.name}, ['paid_interest_amount',
|
amounts = frappe.db.get_value('Loan Interest Accrual', {'loan': loan.name}, ['paid_interest_amount',
|
||||||
@ -305,7 +306,7 @@ class TestLoan(unittest.TestCase):
|
|||||||
make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=first_date)
|
make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=first_date)
|
||||||
process_loan_interest_accrual_for_demand_loans(posting_date = last_date)
|
process_loan_interest_accrual_for_demand_loans(posting_date = last_date)
|
||||||
|
|
||||||
repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(last_date, 5),
|
repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(last_date, 6),
|
||||||
"Loan Closure", flt(loan.loan_amount + accrued_interest_amount))
|
"Loan Closure", flt(loan.loan_amount + accrued_interest_amount))
|
||||||
repayment_entry.submit()
|
repayment_entry.submit()
|
||||||
|
|
||||||
@ -319,13 +320,12 @@ class TestLoan(unittest.TestCase):
|
|||||||
unpledge_request.submit()
|
unpledge_request.submit()
|
||||||
unpledge_request.status = 'Approved'
|
unpledge_request.status = 'Approved'
|
||||||
unpledge_request.save()
|
unpledge_request.save()
|
||||||
|
|
||||||
loan_security_pledge.load_from_db()
|
|
||||||
loan.load_from_db()
|
loan.load_from_db()
|
||||||
|
|
||||||
|
pledged_qty = get_pledged_security_qty(loan.name)
|
||||||
|
|
||||||
self.assertEqual(loan.status, 'Closed')
|
self.assertEqual(loan.status, 'Closed')
|
||||||
for security in loan_security_pledge.securities:
|
self.assertEquals(sum(pledged_qty.values()), 0)
|
||||||
self.assertEquals(security.qty, 0)
|
|
||||||
|
|
||||||
|
|
||||||
def create_loan_accounts():
|
def create_loan_accounts():
|
||||||
|
@ -264,6 +264,7 @@ def get_amounts(amounts, against_loan, posting_date, payment_type):
|
|||||||
penalty_amount = 0
|
penalty_amount = 0
|
||||||
payable_principal_amount = 0
|
payable_principal_amount = 0
|
||||||
final_due_date = ''
|
final_due_date = ''
|
||||||
|
due_date = ''
|
||||||
|
|
||||||
for entry in accrued_interest_entries:
|
for entry in accrued_interest_entries:
|
||||||
# Loan repayment due date is one day after the loan interest is accrued
|
# Loan repayment due date is one day after the loan interest is accrued
|
||||||
@ -272,7 +273,7 @@ def get_amounts(amounts, against_loan, posting_date, payment_type):
|
|||||||
|
|
||||||
due_date = add_days(entry.posting_date, 1)
|
due_date = add_days(entry.posting_date, 1)
|
||||||
no_of_late_days = date_diff(posting_date,
|
no_of_late_days = date_diff(posting_date,
|
||||||
add_days(due_date, loan_type_details.grace_period_in_days)) + 1
|
add_days(due_date, loan_type_details.grace_period_in_days))
|
||||||
|
|
||||||
if no_of_late_days > 0 and (not against_loan_doc.repay_from_salary):
|
if no_of_late_days > 0 and (not against_loan_doc.repay_from_salary):
|
||||||
penalty_amount += (entry.interest_amount * (loan_type_details.penalty_interest_rate / 100) * no_of_late_days)/365
|
penalty_amount += (entry.interest_amount * (loan_type_details.penalty_interest_rate / 100) * no_of_late_days)/365
|
||||||
@ -290,9 +291,9 @@ def get_amounts(amounts, against_loan, posting_date, payment_type):
|
|||||||
|
|
||||||
pending_principal_amount = against_loan_doc.total_payment - against_loan_doc.total_principal_paid - against_loan_doc.total_interest_payable
|
pending_principal_amount = against_loan_doc.total_payment - against_loan_doc.total_principal_paid - against_loan_doc.total_interest_payable
|
||||||
|
|
||||||
if payment_type == "Loan Closure" and not payable_principal_amount:
|
if payment_type == "Loan Closure":
|
||||||
if final_due_date:
|
if due_date:
|
||||||
pending_days = date_diff(posting_date, final_due_date)
|
pending_days = date_diff(posting_date, due_date) + 1
|
||||||
else:
|
else:
|
||||||
pending_days = date_diff(posting_date, against_loan_doc.disbursement_date) + 1
|
pending_days = date_diff(posting_date, against_loan_doc.disbursement_date) + 1
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ def check_for_ltv_shortfall(process_loan_security_shortfall):
|
|||||||
loan_security_map[loan.name]['security_value'] += current_loan_security_amount - (current_loan_security_amount * loan.haircut/100)
|
loan_security_map[loan.name]['security_value'] += current_loan_security_amount - (current_loan_security_amount * loan.haircut/100)
|
||||||
|
|
||||||
for loan, value in iteritems(loan_security_map):
|
for loan, value in iteritems(loan_security_map):
|
||||||
if (value["security_value"]/value["loan_amount"]) < ltv_ratio:
|
if (value["loan_amount"]/value['security_value'] * 100) > ltv_ratio:
|
||||||
create_loan_security_shortfall(loan, value, process_loan_security_shortfall)
|
create_loan_security_shortfall(loan, value, process_loan_security_shortfall)
|
||||||
|
|
||||||
def create_loan_security_shortfall(loan, value, process_loan_security_shortfall):
|
def create_loan_security_shortfall(loan, value, process_loan_security_shortfall):
|
||||||
|
@ -4,10 +4,8 @@
|
|||||||
frappe.ui.form.on('Loan Security Unpledge', {
|
frappe.ui.form.on('Loan Security Unpledge', {
|
||||||
refresh: function(frm) {
|
refresh: function(frm) {
|
||||||
|
|
||||||
frm.set_query("against_pledge", "securities", () => {
|
if (frm.doc.docstatus == 1 && frm.doc.status == 'Approved') {
|
||||||
return {
|
frm.set_df_property('status', 'read_only', 1);
|
||||||
filters : [["status", "in", ["Pledged", "Partially Pledged"]]]
|
}
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -8,12 +8,13 @@ from frappe import _
|
|||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe.utils import get_datetime, flt
|
from frappe.utils import get_datetime, flt
|
||||||
import json
|
import json
|
||||||
|
from six import iteritems
|
||||||
from erpnext.loan_management.doctype.loan_security_price.loan_security_price import get_loan_security_price
|
from erpnext.loan_management.doctype.loan_security_price.loan_security_price import get_loan_security_price
|
||||||
|
|
||||||
class LoanSecurityUnpledge(Document):
|
class LoanSecurityUnpledge(Document):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
self.validate_pledges()
|
|
||||||
self.validate_duplicate_securities()
|
self.validate_duplicate_securities()
|
||||||
|
self.validate_unpledge_qty()
|
||||||
|
|
||||||
def on_cancel(self):
|
def on_cancel(self):
|
||||||
self.update_loan_security_pledge(cancel=1)
|
self.update_loan_security_pledge(cancel=1)
|
||||||
@ -23,80 +24,52 @@ class LoanSecurityUnpledge(Document):
|
|||||||
def validate_duplicate_securities(self):
|
def validate_duplicate_securities(self):
|
||||||
security_list = []
|
security_list = []
|
||||||
for d in self.securities:
|
for d in self.securities:
|
||||||
security = [d.loan_security, d.against_pledge]
|
if d.loan_security not in security_list:
|
||||||
if security not in security_list:
|
security_list.append(d.loan_security)
|
||||||
security_list.append(security)
|
|
||||||
else:
|
else:
|
||||||
frappe.throw(_("Row {0}: Loan Security {1} against Loan Security Pledge {2} added multiple times").format(
|
frappe.throw(_("Row {0}: Loan Security {1} added multiple times").format(
|
||||||
d.idx, frappe.bold(d.loan_security), frappe.bold(d.against_pledge)))
|
d.idx, frappe.bold(d.loan_security)))
|
||||||
|
|
||||||
def validate_pledges(self):
|
def validate_unpledge_qty(self):
|
||||||
pledge_qty_map = self.get_pledge_details()
|
pledge_qty_map = get_pledged_security_qty(self.loan)
|
||||||
loan = frappe.get_doc("Loan", self.loan)
|
|
||||||
|
|
||||||
remaining_qty = 0
|
ltv_ratio_map = frappe._dict(frappe.get_all("Loan Security Type",
|
||||||
unpledge_value = 0
|
fields=["name", "loan_to_value_ratio"], as_list=1))
|
||||||
|
|
||||||
|
loan_security_price_map = frappe._dict(frappe.get_all("Loan Security Price",
|
||||||
|
fields=["loan_security", "loan_security_price"],
|
||||||
|
filters = {
|
||||||
|
"valid_from": ("<=", get_datetime()),
|
||||||
|
"valid_upto": (">=", get_datetime())
|
||||||
|
}, as_list=1))
|
||||||
|
|
||||||
|
loan_amount, principal_paid = frappe.get_value("Loan", self.loan, ['loan_amount', 'total_principal_paid'])
|
||||||
|
pending_principal_amount = loan_amount - principal_paid
|
||||||
|
security_value = 0
|
||||||
|
|
||||||
for security in self.securities:
|
for security in self.securities:
|
||||||
pledged_qty = pledge_qty_map.get((security.against_pledge, security.loan_security), 0)
|
pledged_qty = pledge_qty_map.get(security.loan_security)
|
||||||
if not pledged_qty:
|
|
||||||
frappe.throw(_("Zero qty of {0} pledged against loan {1}").format(frappe.bold(security.loan_security),
|
|
||||||
frappe.bold(self.loan)))
|
|
||||||
|
|
||||||
unpledge_qty = pledged_qty - security.qty
|
if security.qty > pledged_qty:
|
||||||
security_price = security.qty * get_loan_security_price(security.loan_security)
|
frappe.throw(_("""Row {0}: {1} {2} of {3} is pledged against Loan {4}.
|
||||||
|
You are trying to unpledge more""").format(security.idx, pledged_qty, security.uom,
|
||||||
|
frappe.bold(security.loan_security), frappe.bold(self.loan)))
|
||||||
|
|
||||||
if unpledge_qty < 0:
|
qty_after_unpledge = pledged_qty - security.qty
|
||||||
frappe.throw(_("""Row {0}: Cannot unpledge more than {1} qty of {2} against
|
ltv_ratio = ltv_ratio_map.get(security.loan_security_type)
|
||||||
Loan Security Pledge {3}""").format(security.idx, frappe.bold(pledged_qty),
|
|
||||||
frappe.bold(security.loan_security), frappe.bold(security.against_pledge)))
|
|
||||||
|
|
||||||
remaining_qty += unpledge_qty
|
security_value += qty_after_unpledge * loan_security_price_map.get(security.loan_security)
|
||||||
unpledge_value += security_price - flt(security_price * security.haircut/100)
|
|
||||||
|
|
||||||
if unpledge_value > loan.total_principal_paid:
|
if not security_value and pending_principal_amount > 0:
|
||||||
frappe.throw(_("Cannot Unpledge, loan security value is greater than the repaid amount"))
|
frappe.throw("Cannot Unpledge, loan to value ratio is breaching")
|
||||||
|
|
||||||
def get_pledge_details(self):
|
if security_value and (pending_principal_amount/security_value) * 100 > ltv_ratio:
|
||||||
pledge_qty_map = {}
|
frappe.throw("Cannot Unpledge, loan to value ratio is breaching")
|
||||||
|
|
||||||
pledge_details = frappe.db.sql("""
|
|
||||||
SELECT p.parent, p.loan_security, p.qty FROM
|
|
||||||
`tabLoan Security Pledge` lsp,
|
|
||||||
`tabPledge` p
|
|
||||||
WHERE
|
|
||||||
p.parent = lsp.name
|
|
||||||
AND lsp.loan = %s
|
|
||||||
AND lsp.docstatus = 1
|
|
||||||
AND lsp.status in ('Pledged', 'Partially Pledged')
|
|
||||||
""", (self.loan), as_dict=1)
|
|
||||||
|
|
||||||
for pledge in pledge_details:
|
|
||||||
pledge_qty_map.setdefault((pledge.parent, pledge.loan_security), pledge.qty)
|
|
||||||
|
|
||||||
return pledge_qty_map
|
|
||||||
|
|
||||||
def on_update_after_submit(self):
|
def on_update_after_submit(self):
|
||||||
if self.status == "Approved":
|
if self.status == "Approved":
|
||||||
self.update_loan_security_pledge()
|
|
||||||
self.update_loan_status()
|
self.update_loan_status()
|
||||||
|
self.db_set('unpledge_time', get_datetime())
|
||||||
def update_loan_security_pledge(self, cancel=0):
|
|
||||||
if cancel:
|
|
||||||
new_qty = 'p.qty + u.qty'
|
|
||||||
else:
|
|
||||||
new_qty = 'p.qty - u.qty'
|
|
||||||
|
|
||||||
frappe.db.sql("""
|
|
||||||
UPDATE
|
|
||||||
`tabPledge` p, `tabUnpledge` u, `tabLoan Security Pledge` lsp, `tabLoan Security Unpledge` lsu
|
|
||||||
SET p.qty = {new_qty}
|
|
||||||
WHERE
|
|
||||||
lsp.loan = %s
|
|
||||||
AND p.parent = u.against_pledge
|
|
||||||
AND p.parent = lsp.name
|
|
||||||
AND lsp.docstatus = 1
|
|
||||||
AND p.loan_security = u.loan_security""".format(new_qty=new_qty),(self.loan))
|
|
||||||
|
|
||||||
def update_loan_status(self, cancel=0):
|
def update_loan_status(self, cancel=0):
|
||||||
if cancel:
|
if cancel:
|
||||||
@ -104,10 +77,45 @@ class LoanSecurityUnpledge(Document):
|
|||||||
if loan_status == 'Closed':
|
if loan_status == 'Closed':
|
||||||
frappe.db.set_value('Loan', self.loan, 'status', 'Loan Closure Requested')
|
frappe.db.set_value('Loan', self.loan, 'status', 'Loan Closure Requested')
|
||||||
else:
|
else:
|
||||||
pledge_qty = frappe.db.sql("""SELECT SUM(c.qty)
|
pledged_qty = 0
|
||||||
FROM `tabLoan Security Pledge` p, `tabPledge` c
|
current_pledges = get_pledged_security_qty(self.loan)
|
||||||
WHERE p.loan = %s AND c.parent = p.name""", (self.loan))[0][0]
|
|
||||||
|
|
||||||
if not pledge_qty:
|
for security, qty in iteritems(current_pledges):
|
||||||
|
pledged_qty += qty
|
||||||
|
|
||||||
|
if not pledged_qty:
|
||||||
frappe.db.set_value('Loan', self.loan, 'status', 'Closed')
|
frappe.db.set_value('Loan', self.loan, 'status', 'Closed')
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def get_pledged_security_qty(loan):
|
||||||
|
|
||||||
|
current_pledges = {}
|
||||||
|
|
||||||
|
unpledges = frappe._dict(frappe.db.sql("""
|
||||||
|
SELECT u.loan_security, sum(u.qty) as qty
|
||||||
|
FROM `tabLoan Security Unpledge` up, `tabUnpledge` u
|
||||||
|
WHERE up.loan = %s
|
||||||
|
AND u.parent = up.name
|
||||||
|
AND up.status = 'Approved'
|
||||||
|
GROUP BY u.loan_security
|
||||||
|
""", (loan)))
|
||||||
|
|
||||||
|
pledges = frappe._dict(frappe.db.sql("""
|
||||||
|
SELECT p.loan_security, sum(p.qty) as qty
|
||||||
|
FROM `tabLoan Security Pledge` lp, `tabPledge`p
|
||||||
|
WHERE lp.loan = %s
|
||||||
|
AND p.parent = lp.name
|
||||||
|
AND lp.status = 'Pledged'
|
||||||
|
GROUP BY p.loan_security
|
||||||
|
""", (loan)))
|
||||||
|
|
||||||
|
for security, qty in iteritems(pledges):
|
||||||
|
current_pledges.setdefault(security, qty)
|
||||||
|
current_pledges[security] -= unpledges.get(security, 0.0)
|
||||||
|
|
||||||
|
return current_pledges
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
|
"actions": [],
|
||||||
"creation": "2019-09-21 13:22:19.793797",
|
"creation": "2019-09-21 13:22:19.793797",
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"editable_grid": 1,
|
"editable_grid": 1,
|
||||||
"engine": "InnoDB",
|
"engine": "InnoDB",
|
||||||
"field_order": [
|
"field_order": [
|
||||||
"loan_security",
|
"loan_security",
|
||||||
"against_pledge",
|
|
||||||
"loan_security_type",
|
"loan_security_type",
|
||||||
"loan_security_code",
|
"loan_security_code",
|
||||||
"haircut",
|
"haircut",
|
||||||
@ -54,14 +54,6 @@
|
|||||||
"label": "Quantity",
|
"label": "Quantity",
|
||||||
"reqd": 1
|
"reqd": 1
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"fieldname": "against_pledge",
|
|
||||||
"fieldtype": "Link",
|
|
||||||
"in_list_view": 1,
|
|
||||||
"label": "Against Pledge",
|
|
||||||
"options": "Loan Security Pledge",
|
|
||||||
"reqd": 1
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"fetch_from": "loan_security.haircut",
|
"fetch_from": "loan_security.haircut",
|
||||||
"fieldname": "haircut",
|
"fieldname": "haircut",
|
||||||
@ -71,7 +63,8 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"modified": "2019-10-02 12:48:18.588236",
|
"links": [],
|
||||||
|
"modified": "2020-05-06 10:50:18.448552",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Loan Management",
|
"module": "Loan Management",
|
||||||
"name": "Unpledge",
|
"name": "Unpledge",
|
||||||
|
@ -206,30 +206,31 @@ class JobCard(Document):
|
|||||||
for_quantity, time_in_mins = 0, 0
|
for_quantity, time_in_mins = 0, 0
|
||||||
from_time_list, to_time_list = [], []
|
from_time_list, to_time_list = [], []
|
||||||
|
|
||||||
|
field = "operation_id" if self.operation_id else "operation"
|
||||||
data = frappe.get_all('Job Card',
|
data = frappe.get_all('Job Card',
|
||||||
fields = ["sum(total_time_in_mins) as time_in_mins", "sum(total_completed_qty) as completed_qty"],
|
fields = ["sum(total_time_in_mins) as time_in_mins", "sum(total_completed_qty) as completed_qty"],
|
||||||
filters = {"docstatus": 1, "work_order": self.work_order,
|
filters = {"docstatus": 1, "work_order": self.work_order,
|
||||||
"workstation": self.workstation, "operation": self.operation})
|
"workstation": self.workstation, field: self.get(field)})
|
||||||
|
|
||||||
if data and len(data) > 0:
|
if data and len(data) > 0:
|
||||||
for_quantity = data[0].completed_qty
|
for_quantity = data[0].completed_qty
|
||||||
time_in_mins = data[0].time_in_mins
|
time_in_mins = data[0].time_in_mins
|
||||||
|
|
||||||
if for_quantity:
|
if self.get(field):
|
||||||
time_data = frappe.db.sql("""
|
time_data = frappe.db.sql("""
|
||||||
SELECT
|
SELECT
|
||||||
min(from_time) as start_time, max(to_time) as end_time
|
min(from_time) as start_time, max(to_time) as end_time
|
||||||
FROM `tabJob Card` jc, `tabJob Card Time Log` jctl
|
FROM `tabJob Card` jc, `tabJob Card Time Log` jctl
|
||||||
WHERE
|
WHERE
|
||||||
jctl.parent = jc.name and jc.work_order = %s
|
jctl.parent = jc.name and jc.work_order = %s
|
||||||
and jc.workstation = %s and jc.operation = %s and jc.docstatus = 1
|
and jc.workstation = %s and jc.{0} = %s and jc.docstatus = 1
|
||||||
""", (self.work_order, self.workstation, self.operation), as_dict=1)
|
""".format(field), (self.work_order, self.workstation, self.get(field)), as_dict=1)
|
||||||
|
|
||||||
wo = frappe.get_doc('Work Order', self.work_order)
|
wo = frappe.get_doc('Work Order', self.work_order)
|
||||||
|
|
||||||
|
work_order_field = "name" if field == "operation_id" else field
|
||||||
for data in wo.operations:
|
for data in wo.operations:
|
||||||
if data.workstation == self.workstation and data.operation == self.operation:
|
if data.get(work_order_field) == self.get(field) and data.workstation == self.workstation:
|
||||||
data.completed_qty = for_quantity
|
data.completed_qty = for_quantity
|
||||||
data.actual_operation_time = time_in_mins
|
data.actual_operation_time = time_in_mins
|
||||||
data.actual_start_time = time_data[0].start_time if time_data else None
|
data.actual_start_time = time_data[0].start_time if time_data else None
|
||||||
|
@ -421,6 +421,9 @@ class WorkOrder(Document):
|
|||||||
return holidays[holiday_list]
|
return holidays[holiday_list]
|
||||||
|
|
||||||
def update_operation_status(self):
|
def update_operation_status(self):
|
||||||
|
allowance_percentage = flt(frappe.db.get_single_value("Manufacturing Settings", "overproduction_percentage_for_work_order"))
|
||||||
|
max_allowed_qty_for_wo = flt(self.qty) + (allowance_percentage/100 * flt(self.qty))
|
||||||
|
|
||||||
for d in self.get("operations"):
|
for d in self.get("operations"):
|
||||||
if not d.completed_qty:
|
if not d.completed_qty:
|
||||||
d.status = "Pending"
|
d.status = "Pending"
|
||||||
@ -428,6 +431,8 @@ class WorkOrder(Document):
|
|||||||
d.status = "Work in Progress"
|
d.status = "Work in Progress"
|
||||||
elif flt(d.completed_qty) == flt(self.qty):
|
elif flt(d.completed_qty) == flt(self.qty):
|
||||||
d.status = "Completed"
|
d.status = "Completed"
|
||||||
|
elif flt(d.completed_qty) <= max_allowed_qty_for_wo:
|
||||||
|
d.status = "Completed"
|
||||||
else:
|
else:
|
||||||
frappe.throw(_("Completed Qty can not be greater than 'Qty to Manufacture'"))
|
frappe.throw(_("Completed Qty can not be greater than 'Qty to Manufacture'"))
|
||||||
|
|
||||||
|
@ -495,6 +495,7 @@ erpnext.patches.v10_0.rename_offer_letter_to_job_offer
|
|||||||
execute:frappe.delete_doc('DocType', 'Production Planning Tool', ignore_missing=True)
|
execute:frappe.delete_doc('DocType', 'Production Planning Tool', ignore_missing=True)
|
||||||
erpnext.patches.v10_0.migrate_daily_work_summary_settings_to_daily_work_summary_group # 24-12-2018
|
erpnext.patches.v10_0.migrate_daily_work_summary_settings_to_daily_work_summary_group # 24-12-2018
|
||||||
erpnext.patches.v10_0.add_default_cash_flow_mappers
|
erpnext.patches.v10_0.add_default_cash_flow_mappers
|
||||||
|
erpnext.patches.v11_0.rename_duplicate_item_code_values
|
||||||
erpnext.patches.v11_0.make_quality_inspection_template
|
erpnext.patches.v11_0.make_quality_inspection_template
|
||||||
erpnext.patches.v10_0.update_status_for_multiple_source_in_po
|
erpnext.patches.v10_0.update_status_for_multiple_source_in_po
|
||||||
erpnext.patches.v10_0.set_auto_created_serial_no_in_stock_entry
|
erpnext.patches.v10_0.set_auto_created_serial_no_in_stock_entry
|
||||||
@ -630,7 +631,6 @@ execute:frappe.reload_doc('desk', 'doctype', 'dashboard')
|
|||||||
execute:frappe.reload_doc('desk', 'doctype', 'dashboard_chart_source')
|
execute:frappe.reload_doc('desk', 'doctype', 'dashboard_chart_source')
|
||||||
execute:frappe.reload_doc('desk', 'doctype', 'dashboard_chart')
|
execute:frappe.reload_doc('desk', 'doctype', 'dashboard_chart')
|
||||||
execute:frappe.reload_doc('desk', 'doctype', 'dashboard_chart_field')
|
execute:frappe.reload_doc('desk', 'doctype', 'dashboard_chart_field')
|
||||||
erpnext.patches.v12_0.add_default_dashboards # 2020-05-05
|
|
||||||
erpnext.patches.v12_0.remove_bank_remittance_custom_fields
|
erpnext.patches.v12_0.remove_bank_remittance_custom_fields
|
||||||
erpnext.patches.v12_0.generate_leave_ledger_entries
|
erpnext.patches.v12_0.generate_leave_ledger_entries
|
||||||
execute:frappe.delete_doc_if_exists("Report", "Loan Repayment")
|
execute:frappe.delete_doc_if_exists("Report", "Loan Repayment")
|
||||||
@ -679,3 +679,5 @@ erpnext.patches.v12_0.fix_quotation_expired_status
|
|||||||
erpnext.patches.v12_0.update_appointment_reminder_scheduler_entry
|
erpnext.patches.v12_0.update_appointment_reminder_scheduler_entry
|
||||||
erpnext.patches.v12_0.retain_permission_rules_for_video_doctype
|
erpnext.patches.v12_0.retain_permission_rules_for_video_doctype
|
||||||
erpnext.patches.v13_0.patch_to_fix_reverse_linking_in_additional_salary_encashment_and_incentive
|
erpnext.patches.v13_0.patch_to_fix_reverse_linking_in_additional_salary_encashment_and_incentive
|
||||||
|
execute:frappe.delete_doc_if_exists("Page", "appointment-analytic")
|
||||||
|
execute:frappe.rename_doc("Desk Page", "Getting Started", "Home", force=True)
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
import frappe
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
items = []
|
||||||
|
items = frappe.db.sql("""select item_code from `tabItem` group by item_code having count(*) > 1""", as_dict=True)
|
||||||
|
if items:
|
||||||
|
for item in items:
|
||||||
|
frappe.db.sql("""update `tabItem` set item_code=name where item_code = %s""", (item.item_code))
|
@ -1,8 +1,9 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
from frappe import _
|
||||||
import frappe
|
import frappe
|
||||||
|
|
||||||
def execute():
|
def execute():
|
||||||
hr_settings = frappe.get_single("HR Settings")
|
hr_settings = frappe.get_single("HR Settings")
|
||||||
hr_settings.leave_approval_notification_template = "Leave Approval Notification"
|
hr_settings.leave_approval_notification_template = _("Leave Approval Notification")
|
||||||
hr_settings.leave_status_notification_template = "Leave Status Notification"
|
hr_settings.leave_status_notification_template = _("Leave Status Notification")
|
||||||
hr_settings.save()
|
hr_settings.save()
|
@ -1,10 +0,0 @@
|
|||||||
# Copyright (c) 2019, Frappe and Contributors
|
|
||||||
# License: GNU General Public License v3. See license.txt
|
|
||||||
|
|
||||||
import frappe
|
|
||||||
from erpnext.setup.setup_wizard.operations.install_fixtures import add_dashboards
|
|
||||||
|
|
||||||
def execute():
|
|
||||||
frappe.reload_doc("desk", "doctype", "number_card_link")
|
|
||||||
frappe.reload_doc("healthcare", "doctype", "patient_appointment")
|
|
||||||
add_dashboards()
|
|
@ -3,6 +3,10 @@ import frappe
|
|||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
|
||||||
def execute():
|
def execute():
|
||||||
|
|
||||||
|
frappe.reload_doc('stock', 'doctype', 'delivery_note_item', force=True)
|
||||||
|
frappe.reload_doc('stock', 'doctype', 'purchase_receipt_item', force=True)
|
||||||
|
|
||||||
def map_rows(doc_row, return_doc_row, detail_field, doctype):
|
def map_rows(doc_row, return_doc_row, detail_field, doctype):
|
||||||
"""Map rows after identifying similar ones."""
|
"""Map rows after identifying similar ones."""
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ import frappe
|
|||||||
from frappe.model.utils.rename_field import rename_field
|
from frappe.model.utils.rename_field import rename_field
|
||||||
|
|
||||||
def execute():
|
def execute():
|
||||||
if not frappe.db.table_exists("Payroll Period"):
|
if not (frappe.db.table_exists("Payroll Period") and frappe.db.table_exists("Taxable Salary Slab")):
|
||||||
return
|
return
|
||||||
|
|
||||||
for doctype in ("income_tax_slab", "salary_structure_assignment", "employee_other_income", "income_tax_slab_other_charges"):
|
for doctype in ("income_tax_slab", "salary_structure_assignment", "employee_other_income", "income_tax_slab_other_charges"):
|
||||||
@ -60,6 +60,9 @@ def execute():
|
|||||||
""", (income_tax_slab.name, company.name, period.start_date))
|
""", (income_tax_slab.name, company.name, period.start_date))
|
||||||
|
|
||||||
# move other incomes to separate document
|
# move other incomes to separate document
|
||||||
|
if not frappe.db.table_exists("Employee Tax Exemption Proof Submission"):
|
||||||
|
return
|
||||||
|
|
||||||
migrated = []
|
migrated = []
|
||||||
proofs = frappe.get_all("Employee Tax Exemption Proof Submission",
|
proofs = frappe.get_all("Employee Tax Exemption Proof Submission",
|
||||||
filters = {'docstatus': 1},
|
filters = {'docstatus': 1},
|
||||||
@ -79,6 +82,9 @@ def execute():
|
|||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
if not frappe.db.table_exists("Employee Tax Exemption Declaration"):
|
||||||
|
return
|
||||||
|
|
||||||
declerations = frappe.get_all("Employee Tax Exemption Declaration",
|
declerations = frappe.get_all("Employee Tax Exemption Declaration",
|
||||||
filters = {'docstatus': 1},
|
filters = {'docstatus': 1},
|
||||||
fields =['payroll_period', 'employee', 'company', 'income_from_other_sources']
|
fields =['payroll_period', 'employee', 'company', 'income_from_other_sources']
|
||||||
|
4
erpnext/regional/address_template/templates/taiwan.html
Normal file
4
erpnext/regional/address_template/templates/taiwan.html
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{{ country }}<br>{% if pincode %}{{ pincode }}<br>{% endif -%}{{ county }}{{ city }}{{ address_line1 }}{% if address_line2 %}{{ address_line2 }}{% endif -%}
|
||||||
|
{% if phone %}<br>Phone: {{ phone }}{% endif -%}
|
||||||
|
{% if fax %}<br>Fax: {{ fax }}{% endif -%}
|
||||||
|
{% if email_id %}<br>Email: {{ email_id }}{% endif -%}
|
@ -7,7 +7,7 @@
|
|||||||
"doctype": "Report",
|
"doctype": "Report",
|
||||||
"idx": 0,
|
"idx": 0,
|
||||||
"is_standard": "Yes",
|
"is_standard": "Yes",
|
||||||
"modified": "2019-05-24 05:37:02.866139",
|
"modified": "2020-04-30 19:49:02.303320",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Selling",
|
"module": "Selling",
|
||||||
"name": "Sales Analytics",
|
"name": "Sales Analytics",
|
||||||
|
@ -194,6 +194,9 @@ class Analytics(object):
|
|||||||
def get_rows(self):
|
def get_rows(self):
|
||||||
self.data = []
|
self.data = []
|
||||||
self.get_periodic_data()
|
self.get_periodic_data()
|
||||||
|
total_row = {
|
||||||
|
"entity": "Total",
|
||||||
|
}
|
||||||
|
|
||||||
for entity, period_data in iteritems(self.entity_periodic_data):
|
for entity, period_data in iteritems(self.entity_periodic_data):
|
||||||
row = {
|
row = {
|
||||||
@ -207,6 +210,9 @@ class Analytics(object):
|
|||||||
row[scrub(period)] = amount
|
row[scrub(period)] = amount
|
||||||
total += amount
|
total += amount
|
||||||
|
|
||||||
|
if not total_row.get(scrub(period)): total_row[scrub(period)] = 0
|
||||||
|
total_row[scrub(period)] += amount
|
||||||
|
|
||||||
row["total"] = total
|
row["total"] = total
|
||||||
|
|
||||||
if self.filters.tree_type == "Item":
|
if self.filters.tree_type == "Item":
|
||||||
@ -214,6 +220,8 @@ class Analytics(object):
|
|||||||
|
|
||||||
self.data.append(row)
|
self.data.append(row)
|
||||||
|
|
||||||
|
self.data.append(total_row)
|
||||||
|
|
||||||
def get_rows_by_group(self):
|
def get_rows_by_group(self):
|
||||||
self.get_periodic_data()
|
self.get_periodic_data()
|
||||||
out = []
|
out = []
|
||||||
@ -232,8 +240,10 @@ class Analytics(object):
|
|||||||
self.entity_periodic_data.setdefault(d.parent, frappe._dict()).setdefault(period, 0.0)
|
self.entity_periodic_data.setdefault(d.parent, frappe._dict()).setdefault(period, 0.0)
|
||||||
self.entity_periodic_data[d.parent][period] += amount
|
self.entity_periodic_data[d.parent][period] += amount
|
||||||
total += amount
|
total += amount
|
||||||
|
|
||||||
row["total"] = total
|
row["total"] = total
|
||||||
out = [row] + out
|
out = [row] + out
|
||||||
|
|
||||||
self.data = out
|
self.data = out
|
||||||
|
|
||||||
def get_periodic_data(self):
|
def get_periodic_data(self):
|
||||||
|
@ -33,6 +33,21 @@ class TestAnalytics(unittest.TestCase):
|
|||||||
report = execute(filters)
|
report = execute(filters)
|
||||||
|
|
||||||
expected_data = [
|
expected_data = [
|
||||||
|
{
|
||||||
|
'entity': 'Total',
|
||||||
|
'apr_2017': 0.0,
|
||||||
|
'may_2017': 0.0,
|
||||||
|
'jun_2017': 2000.0,
|
||||||
|
'jul_2017': 1000.0,
|
||||||
|
'aug_2017': 0.0,
|
||||||
|
'sep_2017': 1500.0,
|
||||||
|
'oct_2017': 1000.0,
|
||||||
|
'nov_2017': 0.0,
|
||||||
|
'dec_2017': 0.0,
|
||||||
|
'jan_2018': 0.0,
|
||||||
|
'feb_2018': 2000.0,
|
||||||
|
'mar_2018': 0.0
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"entity": "_Test Customer 1",
|
"entity": "_Test Customer 1",
|
||||||
"entity_name": "_Test Customer 1",
|
"entity_name": "_Test Customer 1",
|
||||||
@ -134,6 +149,21 @@ class TestAnalytics(unittest.TestCase):
|
|||||||
report = execute(filters)
|
report = execute(filters)
|
||||||
|
|
||||||
expected_data = [
|
expected_data = [
|
||||||
|
{
|
||||||
|
'entity': 'Total',
|
||||||
|
'apr_2017': 0.0,
|
||||||
|
'may_2017': 0.0,
|
||||||
|
'jun_2017': 20.0,
|
||||||
|
'jul_2017': 10.0,
|
||||||
|
'aug_2017': 0.0,
|
||||||
|
'sep_2017': 15.0,
|
||||||
|
'oct_2017': 10.0,
|
||||||
|
'nov_2017': 0.0,
|
||||||
|
'dec_2017': 0.0,
|
||||||
|
'jan_2018': 0.0,
|
||||||
|
'feb_2018': 20.0,
|
||||||
|
'mar_2018': 0.0
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"entity": "_Test Customer 1",
|
"entity": "_Test Customer 1",
|
||||||
"entity_name": "_Test Customer 1",
|
"entity_name": "_Test Customer 1",
|
||||||
|
@ -47,26 +47,20 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"category": "Modules",
|
"category": "Modules",
|
||||||
"charts": [
|
"charts": [],
|
||||||
{
|
|
||||||
"chart_name": "Bank Balance",
|
|
||||||
"label": "Bank Balance"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"creation": "2020-01-23 13:46:38.833076",
|
"creation": "2020-01-23 13:46:38.833076",
|
||||||
"developer_mode_only": 0,
|
"developer_mode_only": 0,
|
||||||
"disable_user_customization": 0,
|
"disable_user_customization": 0,
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"doctype": "Desk Page",
|
"doctype": "Desk Page",
|
||||||
"extends_another_page": 0,
|
"extends_another_page": 0,
|
||||||
"icon": "",
|
|
||||||
"idx": 0,
|
"idx": 0,
|
||||||
"is_standard": 1,
|
"is_standard": 1,
|
||||||
"label": "Getting Started",
|
"label": "Home",
|
||||||
"modified": "2020-04-01 11:30:19.763099",
|
"modified": "2020-05-11 10:20:37.358701",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Setup",
|
"module": "Setup",
|
||||||
"name": "Getting Started",
|
"name": "Home",
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"pin_to_bottom": 0,
|
"pin_to_bottom": 0,
|
||||||
"pin_to_top": 1,
|
"pin_to_top": 1,
|
@ -485,8 +485,6 @@ def install_defaults(args=None):
|
|||||||
# bank account same as a CoA entry
|
# bank account same as a CoA entry
|
||||||
pass
|
pass
|
||||||
|
|
||||||
add_dashboards()
|
|
||||||
|
|
||||||
# Now, with fixtures out of the way, onto concrete stuff
|
# Now, with fixtures out of the way, onto concrete stuff
|
||||||
records = [
|
records = [
|
||||||
|
|
||||||
@ -504,27 +502,6 @@ def install_defaults(args=None):
|
|||||||
|
|
||||||
make_records(records)
|
make_records(records)
|
||||||
|
|
||||||
def add_dashboards():
|
|
||||||
from erpnext.setup.setup_wizard.data.dashboard_charts import get_company_for_dashboards
|
|
||||||
|
|
||||||
if not get_company_for_dashboards():
|
|
||||||
return
|
|
||||||
|
|
||||||
from erpnext.setup.setup_wizard.data.dashboard_charts import get_default_dashboards
|
|
||||||
from frappe.modules.import_file import import_file_by_path
|
|
||||||
|
|
||||||
dashboard_data = get_default_dashboards()
|
|
||||||
|
|
||||||
# create account balance timeline before creating dashbaord charts
|
|
||||||
doctype = "dashboard_chart_source"
|
|
||||||
docname = "account_balance_timeline"
|
|
||||||
folder = os.path.dirname(frappe.get_module("erpnext.accounts").__file__)
|
|
||||||
doc_path = os.path.join(folder, doctype, docname, docname) + ".json"
|
|
||||||
import_file_by_path(doc_path, force=0, for_sync=True)
|
|
||||||
|
|
||||||
make_records(dashboard_data["Charts"])
|
|
||||||
make_records(dashboard_data["Dashboards"])
|
|
||||||
|
|
||||||
|
|
||||||
def get_fy_details(fy_start_date, fy_end_date):
|
def get_fy_details(fy_start_date, fy_end_date):
|
||||||
start_year = getdate(fy_start_date).year
|
start_year = getdate(fy_start_date).year
|
||||||
|
@ -7,7 +7,7 @@ import frappe
|
|||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe.model.naming import make_autoname, revert_series_if_last
|
from frappe.model.naming import make_autoname, revert_series_if_last
|
||||||
from frappe.utils import flt, cint
|
from frappe.utils import flt, cint, get_link_to_form
|
||||||
from frappe.utils.jinja import render_template
|
from frappe.utils.jinja import render_template
|
||||||
from frappe.utils.data import add_days
|
from frappe.utils.data import add_days
|
||||||
from six import string_types
|
from six import string_types
|
||||||
@ -124,7 +124,7 @@ class Batch(Document):
|
|||||||
if has_expiry_date and not self.expiry_date:
|
if has_expiry_date and not self.expiry_date:
|
||||||
frappe.throw(msg=_("Please set {0} for Batched Item {1}, which is used to set {2} on Submit.") \
|
frappe.throw(msg=_("Please set {0} for Batched Item {1}, which is used to set {2} on Submit.") \
|
||||||
.format(frappe.bold("Shelf Life in Days"),
|
.format(frappe.bold("Shelf Life in Days"),
|
||||||
frappe.utils.get_link_to_form("Item", self.item),
|
get_link_to_form("Item", self.item),
|
||||||
frappe.bold("Batch Expiry Date")),
|
frappe.bold("Batch Expiry Date")),
|
||||||
title=_("Expiry Date Mandatory"))
|
title=_("Expiry Date Mandatory"))
|
||||||
|
|
||||||
@ -264,16 +264,20 @@ def get_batch_no(item_code, warehouse, qty=1, throw=False, serial_no=None):
|
|||||||
def get_batches(item_code, warehouse, qty=1, throw=False, serial_no=None):
|
def get_batches(item_code, warehouse, qty=1, throw=False, serial_no=None):
|
||||||
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
|
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
|
||||||
cond = ''
|
cond = ''
|
||||||
if serial_no:
|
if serial_no and frappe.get_cached_value('Item', item_code, 'has_batch_no'):
|
||||||
|
serial_nos = get_serial_nos(serial_no)
|
||||||
batch = frappe.get_all("Serial No",
|
batch = frappe.get_all("Serial No",
|
||||||
fields = ["distinct batch_no"],
|
fields = ["distinct batch_no"],
|
||||||
filters= {
|
filters= {
|
||||||
"item_code": item_code,
|
"item_code": item_code,
|
||||||
"warehouse": warehouse,
|
"warehouse": warehouse,
|
||||||
"name": ("in", get_serial_nos(serial_no))
|
"name": ("in", serial_nos)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if not batch:
|
||||||
|
validate_serial_no_with_batch(serial_nos, item_code)
|
||||||
|
|
||||||
if batch and len(batch) > 1:
|
if batch and len(batch) > 1:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
@ -289,3 +293,14 @@ def get_batches(item_code, warehouse, qty=1, throw=False, serial_no=None):
|
|||||||
group by batch_id
|
group by batch_id
|
||||||
order by `tabBatch`.expiry_date ASC, `tabBatch`.creation ASC
|
order by `tabBatch`.expiry_date ASC, `tabBatch`.creation ASC
|
||||||
""".format(cond), (item_code, warehouse), as_dict=True)
|
""".format(cond), (item_code, warehouse), as_dict=True)
|
||||||
|
|
||||||
|
def validate_serial_no_with_batch(serial_nos, item_code):
|
||||||
|
if frappe.get_cached_value("Serial No", serial_nos[0], "item_code") != item_code:
|
||||||
|
frappe.throw(_("The serial no {0} does not belong to item {1}")
|
||||||
|
.format(get_link_to_form("Serial No", serial_nos[0]), get_link_to_form("Item", item_code)))
|
||||||
|
|
||||||
|
serial_no_link = ','.join([get_link_to_form("Serial No", sn) for sn in serial_nos])
|
||||||
|
|
||||||
|
message = "Serial Nos" if len(serial_nos) > 1 else "Serial No"
|
||||||
|
frappe.throw(_("There is no batch found against the {0}: {1}")
|
||||||
|
.format(message, serial_no_link))
|
@ -572,6 +572,13 @@ class Item(WebsiteGenerator):
|
|||||||
frappe.throw(_("Barcode {0} is not a valid {1} code").format(
|
frappe.throw(_("Barcode {0} is not a valid {1} code").format(
|
||||||
item_barcode.barcode, item_barcode.barcode_type), InvalidBarcode)
|
item_barcode.barcode, item_barcode.barcode_type), InvalidBarcode)
|
||||||
|
|
||||||
|
if item_barcode.barcode != item_barcode.name:
|
||||||
|
# if barcode is getting updated , the row name has to reset.
|
||||||
|
# Delete previous old row doc and re-enter row as if new to reset name in db.
|
||||||
|
item_barcode.set("__islocal", True)
|
||||||
|
item_barcode.name = None
|
||||||
|
frappe.delete_doc("Item Barcode", item_barcode.name)
|
||||||
|
|
||||||
def validate_warehouse_for_reorder(self):
|
def validate_warehouse_for_reorder(self):
|
||||||
'''Validate Reorder level table for duplicate and conditional mandatory'''
|
'''Validate Reorder level table for duplicate and conditional mandatory'''
|
||||||
warehouse = []
|
warehouse = []
|
||||||
|
@ -181,7 +181,7 @@ class StockEntry(StockController):
|
|||||||
stock_items = self.get_stock_items()
|
stock_items = self.get_stock_items()
|
||||||
serialized_items = self.get_serialized_items()
|
serialized_items = self.get_serialized_items()
|
||||||
for item in self.get("items"):
|
for item in self.get("items"):
|
||||||
if item.qty and item.qty < 0:
|
if flt(item.qty) and flt(item.qty) < 0:
|
||||||
frappe.throw(_("Row {0}: The item {1}, quantity must be positive number")
|
frappe.throw(_("Row {0}: The item {1}, quantity must be positive number")
|
||||||
.format(item.idx, frappe.bold(item.item_code)))
|
.format(item.idx, frappe.bold(item.item_code)))
|
||||||
|
|
||||||
@ -470,7 +470,7 @@ class StockEntry(StockController):
|
|||||||
"qty": item.s_warehouse and -1*flt(item.transfer_qty) or flt(item.transfer_qty),
|
"qty": item.s_warehouse and -1*flt(item.transfer_qty) or flt(item.transfer_qty),
|
||||||
"serial_no": item.serial_no,
|
"serial_no": item.serial_no,
|
||||||
"voucher_type": self.doctype,
|
"voucher_type": self.doctype,
|
||||||
"voucher_no": item.name,
|
"voucher_no": self.name,
|
||||||
"company": self.company,
|
"company": self.company,
|
||||||
"allow_zero_valuation": item.allow_zero_valuation_rate,
|
"allow_zero_valuation": item.allow_zero_valuation_rate,
|
||||||
})
|
})
|
||||||
|
@ -177,7 +177,7 @@ def convert_to_group_or_ledger():
|
|||||||
return frappe.get_doc("Warehouse", args.docname).convert_to_group_or_ledger()
|
return frappe.get_doc("Warehouse", args.docname).convert_to_group_or_ledger()
|
||||||
|
|
||||||
def get_child_warehouses(warehouse):
|
def get_child_warehouses(warehouse):
|
||||||
lft, rgt = frappe.get_cached_value("Warehouse", warehouse, [lft, rgt])
|
lft, rgt = frappe.get_cached_value("Warehouse", warehouse, ["lft", "rgt"])
|
||||||
|
|
||||||
return frappe.db.sql_list("""select name from `tabWarehouse`
|
return frappe.db.sql_list("""select name from `tabWarehouse`
|
||||||
where lft >= %s and rgt <= %s""", (lft, rgt))
|
where lft >= %s and rgt <= %s""", (lft, rgt))
|
||||||
|
@ -548,7 +548,16 @@ def get_valuation_rate(item_code, warehouse, voucher_type, voucher_no,
|
|||||||
if not allow_zero_rate and not valuation_rate and raise_error_if_no_rate \
|
if not allow_zero_rate and not valuation_rate and raise_error_if_no_rate \
|
||||||
and cint(erpnext.is_perpetual_inventory_enabled(company)):
|
and cint(erpnext.is_perpetual_inventory_enabled(company)):
|
||||||
frappe.local.message_log = []
|
frappe.local.message_log = []
|
||||||
frappe.throw(_("Valuation rate not found for the Item {0}, which is required to do accounting entries for {1} {2}. If the item is transacting as a zero valuation rate item in the {1}, please mention that in the {1} Item table. Otherwise, please create an incoming stock transaction for the item or mention valuation rate in the Item record, and then try submiting / cancelling this entry.")
|
form_link = frappe.utils.get_link_to_form("Item", item_code)
|
||||||
.format(item_code, voucher_type, voucher_no))
|
|
||||||
|
message = _("Valuation Rate for the Item {0}, is required to do accounting entries for {1} {2}.").format(form_link, voucher_type, voucher_no)
|
||||||
|
message += "<br><br>" + _(" Here are the options to proceed:")
|
||||||
|
solutions = "<li>" + _("If the item is transacting as a Zero Valuation Rate item in this entry, please enable 'Allow Zero Valuation Rate' in the {0} Item table.").format(voucher_type) + "</li>"
|
||||||
|
solutions += "<li>" + _("If not, you can Cancel / Submit this entry ") + _("{0}").format(frappe.bold("after")) + _(" performing either one below:") + "</li>"
|
||||||
|
sub_solutions = "<ul><li>" + _("Create an incoming stock transaction for the Item.") + "</li>"
|
||||||
|
sub_solutions += "<li>" + _("Mention Valuation Rate in the Item master.") + "</li></ul>"
|
||||||
|
msg = message + solutions + sub_solutions + "</li>"
|
||||||
|
|
||||||
|
frappe.throw(msg=msg, title=_("Valuation Rate Missing"))
|
||||||
|
|
||||||
return valuation_rate
|
return valuation_rate
|
||||||
|
Loading…
Reference in New Issue
Block a user