Merge branch 'develop' into support-search

This commit is contained in:
Shivam Mishra 2020-08-11 14:54:10 +00:00 committed by GitHub
commit 1679c7af88
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
159 changed files with 3038 additions and 2819 deletions

View File

@ -244,6 +244,8 @@ class Account(NestedSet):
super(Account, self).on_trash(True) super(Account, self).on_trash(True)
@frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def get_parent_account(doctype, txt, searchfield, start, page_len, filters): def get_parent_account(doctype, txt, searchfield, start, page_len, filters):
return frappe.db.sql("""select name from tabAccount return frappe.db.sql("""select name from tabAccount
where is_group = 1 and docstatus != 2 and company = %s where is_group = 1 and docstatus != 2 and company = %s

View File

@ -225,7 +225,7 @@ def build_tree_from_json(chart_template, chart_data=None):
account['parent_account'] = parent account['parent_account'] = parent
account['expandable'] = True if identify_is_group(child) else False account['expandable'] = True if identify_is_group(child) else False
account['value'] = (child.get('account_number') + ' - ' + account_name) \ account['value'] = (cstr(child.get('account_number')).strip() + ' - ' + account_name) \
if child.get('account_number') else account_name if child.get('account_number') else account_name
accounts.append(account) accounts.append(account)
_import_accounts(child, account['value']) _import_accounts(child, account['value'])

View File

@ -225,7 +225,7 @@
"idx": 1, "idx": 1,
"issingle": 1, "issingle": 1,
"links": [], "links": [],
"modified": "2020-06-22 20:13:26.043092", "modified": "2020-08-03 20:13:26.043092",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Accounts Settings", "name": "Accounts Settings",

View File

@ -60,12 +60,12 @@ class BankClearance(Document):
""".format(condition=condition), {"account": self.account, "from":self.from_date, """.format(condition=condition), {"account": self.account, "from":self.from_date,
"to": self.to_date, "bank_account": self.bank_account}, as_dict=1) "to": self.to_date, "bank_account": self.bank_account}, as_dict=1)
pos_entries = [] pos_sales_invoices, pos_purchase_invoices = [], []
if self.include_pos_transactions: if self.include_pos_transactions:
pos_entries = frappe.db.sql(""" pos_sales_invoices = frappe.db.sql("""
select select
"Sales Invoice Payment" as payment_document, sip.name as payment_entry, sip.amount as debit, "Sales Invoice Payment" as payment_document, sip.name as payment_entry, sip.amount as debit,
si.posting_date, si.debit_to as against_account, sip.clearance_date, si.posting_date, si.customer as against_account, sip.clearance_date,
account.account_currency, 0 as credit account.account_currency, 0 as credit
from `tabSales Invoice Payment` sip, `tabSales Invoice` si, `tabAccount` account from `tabSales Invoice Payment` sip, `tabSales Invoice` si, `tabAccount` account
where where
@ -75,7 +75,20 @@ class BankClearance(Document):
si.posting_date ASC, si.name DESC si.posting_date ASC, si.name DESC
""", {"account":self.account, "from":self.from_date, "to":self.to_date}, as_dict=1) """, {"account":self.account, "from":self.from_date, "to":self.to_date}, as_dict=1)
entries = sorted(list(payment_entries)+list(journal_entries+list(pos_entries)), pos_purchase_invoices = frappe.db.sql("""
select
"Purchase Invoice" as payment_document, pi.name as payment_entry, pi.paid_amount as credit,
pi.posting_date, pi.supplier as against_account, pi.clearance_date,
account.account_currency, 0 as debit
from `tabPurchase Invoice` pi, `tabAccount` account
where
pi.cash_bank_account=%(account)s and pi.docstatus=1 and account.name = pi.cash_bank_account
and pi.posting_date >= %(from)s and pi.posting_date <= %(to)s
order by
pi.posting_date ASC, pi.name DESC
""", {"account": self.account, "from": self.from_date, "to": self.to_date}, as_dict=1)
entries = sorted(list(payment_entries) + list(journal_entries + list(pos_sales_invoices) + list(pos_purchase_invoices)),
key=lambda k: k['posting_date'] or getdate(nowdate())) key=lambda k: k['posting_date'] or getdate(nowdate()))
self.set('payment_entries', []) self.set('payment_entries', [])

View File

@ -44,6 +44,19 @@ frappe.ui.form.on("Dunning", {
); );
frm.page.set_inner_btn_group_as_primary(__("Create")); frm.page.set_inner_btn_group_as_primary(__("Create"));
} }
if(frm.doc.docstatus > 0) {
frm.add_custom_button(__('Ledger'), function() {
frappe.route_options = {
"voucher_no": frm.doc.name,
"from_date": frm.doc.posting_date,
"to_date": frm.doc.posting_date,
"company": frm.doc.company,
"show_cancelled_entries": frm.doc.docstatus === 2
};
frappe.set_route("query-report", "General Ledger");
}, __('View'));
}
}, },
overdue_days: function (frm) { overdue_days: function (frm) {
frappe.db.get_value( frappe.db.get_value(
@ -125,9 +138,9 @@ frappe.ui.form.on("Dunning", {
}, },
calculate_interest_and_amount: function (frm) { calculate_interest_and_amount: function (frm) {
const interest_per_year = frm.doc.outstanding_amount * frm.doc.rate_of_interest / 100; const interest_per_year = frm.doc.outstanding_amount * frm.doc.rate_of_interest / 100;
const interest_amount = interest_per_year / 365 * frm.doc.overdue_days || 0; const interest_amount = flt((interest_per_year * cint(frm.doc.overdue_days)) / 365 || 0, precision('interest_amount'));
const dunning_amount = interest_amount + frm.doc.dunning_fee; const dunning_amount = flt(interest_amount + frm.doc.dunning_fee, precision('dunning_amount'));
const grand_total = frm.doc.outstanding_amount + dunning_amount; const grand_total = flt(frm.doc.outstanding_amount + dunning_amount, precision('grand_total'));
frm.set_value("interest_amount", interest_amount); frm.set_value("interest_amount", interest_amount);
frm.set_value("dunning_amount", dunning_amount); frm.set_value("dunning_amount", dunning_amount);
frm.set_value("grand_total", grand_total); frm.set_value("grand_total", grand_total);

View File

@ -29,10 +29,10 @@
"company_address_display", "company_address_display",
"section_break_6", "section_break_6",
"dunning_type", "dunning_type",
"interest_amount", "dunning_fee",
"column_break_8", "column_break_8",
"rate_of_interest", "rate_of_interest",
"dunning_fee", "interest_amount",
"section_break_12", "section_break_12",
"dunning_amount", "dunning_amount",
"grand_total", "grand_total",
@ -215,7 +215,7 @@
}, },
{ {
"default": "0", "default": "0",
"fetch_from": "dunning_type.interest_rate", "fetch_from": "dunning_type.rate_of_interest",
"fetch_if_empty": 1, "fetch_if_empty": 1,
"fieldname": "rate_of_interest", "fieldname": "rate_of_interest",
"fieldtype": "Float", "fieldtype": "Float",
@ -315,7 +315,7 @@
], ],
"is_submittable": 1, "is_submittable": 1,
"links": [], "links": [],
"modified": "2020-07-21 18:20:23.512151", "modified": "2020-08-03 18:55:43.683053",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Dunning", "name": "Dunning",

View File

@ -6,7 +6,7 @@ from __future__ import unicode_literals
import frappe import frappe
import json import json
from six import string_types from six import string_types
from frappe.utils import getdate, get_datetime, rounded, flt from frappe.utils import getdate, get_datetime, rounded, flt, cint
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.accounts.general_ledger import make_gl_entries, make_reverse_gl_entries from erpnext.accounts.general_ledger import make_gl_entries, make_reverse_gl_entries
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions
@ -27,11 +27,11 @@ class Dunning(AccountsController):
amounts = calculate_interest_and_amount( amounts = calculate_interest_and_amount(
self.posting_date, self.outstanding_amount, self.rate_of_interest, self.dunning_fee, self.overdue_days) self.posting_date, self.outstanding_amount, self.rate_of_interest, self.dunning_fee, self.overdue_days)
if self.interest_amount != amounts.get('interest_amount'): if self.interest_amount != amounts.get('interest_amount'):
self.interest_amount = amounts.get('interest_amount') self.interest_amount = flt(amounts.get('interest_amount'), self.precision('interest_amount'))
if self.dunning_amount != amounts.get('dunning_amount'): if self.dunning_amount != amounts.get('dunning_amount'):
self.dunning_amount = amounts.get('dunning_amount') self.dunning_amount = flt(amounts.get('dunning_amount'), self.precision('dunning_amount'))
if self.grand_total != amounts.get('grand_total'): if self.grand_total != amounts.get('grand_total'):
self.grand_total = amounts.get('grand_total') self.grand_total = flt(amounts.get('grand_total'), self.precision('grand_total'))
def on_submit(self): def on_submit(self):
self.make_gl_entries() self.make_gl_entries()
@ -47,10 +47,13 @@ class Dunning(AccountsController):
gl_entries = [] gl_entries = []
invoice_fields = ["project", "cost_center", "debit_to", "party_account_currency", "conversion_rate", "cost_center"] invoice_fields = ["project", "cost_center", "debit_to", "party_account_currency", "conversion_rate", "cost_center"]
inv = frappe.db.get_value("Sales Invoice", self.sales_invoice, invoice_fields, as_dict=1) inv = frappe.db.get_value("Sales Invoice", self.sales_invoice, invoice_fields, as_dict=1)
accounting_dimensions = get_accounting_dimensions() accounting_dimensions = get_accounting_dimensions()
invoice_fields.extend(accounting_dimensions) invoice_fields.extend(accounting_dimensions)
dunning_in_company_currency = flt(self.dunning_amount * inv.conversion_rate) dunning_in_company_currency = flt(self.dunning_amount * inv.conversion_rate)
default_cost_center = frappe.get_cached_value('Company', self.company, 'cost_center') default_cost_center = frappe.get_cached_value('Company', self.company, 'cost_center')
gl_entries.append( gl_entries.append(
self.get_gl_dict({ self.get_gl_dict({
"account": inv.debit_to, "account": inv.debit_to,
@ -90,10 +93,10 @@ def resolve_dunning(doc, state):
def calculate_interest_and_amount(posting_date, outstanding_amount, rate_of_interest, dunning_fee, overdue_days): def calculate_interest_and_amount(posting_date, outstanding_amount, rate_of_interest, dunning_fee, overdue_days):
interest_amount = 0 interest_amount = 0
grand_total = 0
if rate_of_interest: if rate_of_interest:
interest_per_year = rounded(flt(outstanding_amount) * flt(rate_of_interest))/100 interest_per_year = flt(outstanding_amount) * flt(rate_of_interest) / 100
interest_amount = ( interest_amount = (interest_per_year * cint(overdue_days)) / 365
interest_per_year / days_in_year(get_datetime(posting_date).year)) * int(overdue_days)
grand_total = flt(outstanding_amount) + flt(interest_amount) + flt(dunning_fee) grand_total = flt(outstanding_amount) + flt(interest_amount) + flt(dunning_fee)
dunning_amount = flt(interest_amount) + flt(dunning_fee) dunning_amount = flt(interest_amount) + flt(dunning_fee)
return { return {

View File

@ -0,0 +1,17 @@
from __future__ import unicode_literals
from frappe import _
def get_data():
return {
'fieldname': 'dunning',
'non_standard_fieldnames': {
'Journal Entry': 'reference_name',
'Payment Entry': 'reference_name'
},
'transactions': [
{
'label': _('Payment'),
'items': ['Payment Entry', 'Journal Entry']
}
]
}

View File

@ -841,13 +841,33 @@ def get_opening_accounts(company):
@frappe.whitelist() @frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def get_against_jv(doctype, txt, searchfield, start, page_len, filters): def get_against_jv(doctype, txt, searchfield, start, page_len, filters):
return frappe.db.sql("""select jv.name, jv.posting_date, jv.user_remark if not frappe.db.has_column('Journal Entry', searchfield):
from `tabJournal Entry` jv, `tabJournal Entry Account` jv_detail return []
where jv_detail.parent = jv.name and jv_detail.account = %s and ifnull(jv_detail.party, '') = %s
and (jv_detail.reference_type is null or jv_detail.reference_type = '') return frappe.db.sql("""
and jv.docstatus = 1 and jv.`{0}` like %s order by jv.name desc limit %s, %s""".format(searchfield), SELECT jv.name, jv.posting_date, jv.user_remark
(filters.get("account"), cstr(filters.get("party")), "%{0}%".format(txt), start, page_len)) FROM `tabJournal Entry` jv, `tabJournal Entry Account` jv_detail
WHERE jv_detail.parent = jv.name
AND jv_detail.account = %(account)s
AND IFNULL(jv_detail.party, '') = %(party)s
AND (
jv_detail.reference_type IS NULL
OR jv_detail.reference_type = ''
)
AND jv.docstatus = 1
AND jv.`{0}` LIKE %(txt)s
ORDER BY jv.name DESC
LIMIT %(offset)s, %(limit)s
""".format(searchfield), dict(
account=filters.get("account"),
party=cstr(filters.get("party")),
txt="%{0}%".format(txt),
offset=start,
limit=page_len
)
)
@frappe.whitelist() @frappe.whitelist()

View File

@ -42,7 +42,8 @@ frappe.ui.form.on('Payment Entry', {
frm.set_query("bank_account", function() { frm.set_query("bank_account", function() {
return { return {
filters: { filters: {
is_company_account: 1 is_company_account: 1,
company: frm.doc.company
} }
} }
}); });

View File

@ -897,7 +897,7 @@ def get_reference_details(reference_doctype, reference_name, party_account_curre
total_amount = ref_doc.get("grand_total") total_amount = ref_doc.get("grand_total")
exchange_rate = 1 exchange_rate = 1
outstanding_amount = ref_doc.get("outstanding_amount") outstanding_amount = ref_doc.get("outstanding_amount")
if reference_doctype == "Dunning": elif reference_doctype == "Dunning":
total_amount = ref_doc.get("dunning_amount") total_amount = ref_doc.get("dunning_amount")
exchange_rate = 1 exchange_rate = 1
outstanding_amount = ref_doc.get("dunning_amount") outstanding_amount = ref_doc.get("dunning_amount")

View File

@ -27,6 +27,7 @@ class PaymentOrder(Document):
frappe.db.set_value(self.payment_order_type, d.get(frappe.scrub(self.payment_order_type)), ref_field, status) frappe.db.set_value(self.payment_order_type, d.get(frappe.scrub(self.payment_order_type)), ref_field, status)
@frappe.whitelist() @frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def get_mop_query(doctype, txt, searchfield, start, page_len, filters): def get_mop_query(doctype, txt, searchfield, start, page_len, filters):
return frappe.db.sql(""" select mode_of_payment from `tabPayment Order Reference` return frappe.db.sql(""" select mode_of_payment from `tabPayment Order Reference`
where parent = %(parent)s and mode_of_payment like %(txt)s where parent = %(parent)s and mode_of_payment like %(txt)s
@ -38,6 +39,7 @@ def get_mop_query(doctype, txt, searchfield, start, page_len, filters):
}) })
@frappe.whitelist() @frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def get_supplier_query(doctype, txt, searchfield, start, page_len, filters): def get_supplier_query(doctype, txt, searchfield, start, page_len, filters):
return frappe.db.sql(""" select supplier from `tabPayment Order Reference` return frappe.db.sql(""" select supplier from `tabPayment Order Reference`
where parent = %(parent)s and supplier like %(txt)s and where parent = %(parent)s and supplier like %(txt)s and

View File

@ -41,6 +41,7 @@ class POSClosingEntry(Document):
{"data": self, "currency": currency}) {"data": self, "currency": currency})
@frappe.whitelist() @frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def get_cashiers(doctype, txt, searchfield, start, page_len, filters): def get_cashiers(doctype, txt, searchfield, start, page_len, filters):
cashiers_list = frappe.get_all("POS Profile User", filters=filters, fields=['user']) cashiers_list = frappe.get_all("POS Profile User", filters=filters, fields=['user'])
return [c['user'] for c in cashiers_list] return [c['user'] for c in cashiers_list]

View File

@ -31,8 +31,7 @@ frappe.ui.form.on('POS Profile', {
frm.set_query("print_format", function() { frm.set_query("print_format", function() {
return { return {
filters: [ filters: [
['Print Format', 'doc_type', '=', 'Sales Invoice'], ['Print Format', 'doc_type', '=', 'POS Invoice']
['Print Format', 'print_format_type', '=', 'Jinja'],
] ]
}; };
}); });
@ -45,10 +44,6 @@ frappe.ui.form.on('POS Profile', {
}; };
}); });
frm.set_query("print_format", function() {
return { filters: { doc_type: "Sales Invoice", print_format_type: "JS"} };
});
frm.set_query('company_address', function(doc) { frm.set_query('company_address', function(doc) {
if(!doc.company) { if(!doc.company) {
frappe.throw(__('Please set Company')); frappe.throw(__('Please set Company'));

View File

@ -105,6 +105,7 @@ def get_series():
return frappe.get_meta("POS Invoice").get_field("naming_series").options or "s" return frappe.get_meta("POS Invoice").get_field("naming_series").options or "s"
@frappe.whitelist() @frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def pos_profile_query(doctype, txt, searchfield, start, page_len, filters): def pos_profile_query(doctype, txt, searchfield, start, page_len, filters):
user = frappe.session['user'] user = frappe.session['user']
company = filters.get('company') or frappe.defaults.get_user_default('company') company = filters.get('company') or frappe.defaults.get_user_default('company')

View File

@ -433,14 +433,14 @@ def make_pricing_rule(doctype, docname):
return doc return doc
@frappe.whitelist() @frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def get_item_uoms(doctype, txt, searchfield, start, page_len, filters): def get_item_uoms(doctype, txt, searchfield, start, page_len, filters):
items = [filters.get('value')] items = [filters.get('value')]
if filters.get('apply_on') != 'Item Code': if filters.get('apply_on') != 'Item Code':
field = frappe.scrub(filters.get('apply_on')) field = frappe.scrub(filters.get('apply_on'))
items = [d.name for d in frappe.db.get_all("Item", filters={field: filters.get('value')})]
items = frappe.db.sql_list("""select name return frappe.get_all('UOM Conversion Detail', filters={
from `tabItem` where {0} = %s""".format(field), filters.get('value')) 'parent': ('in', items),
'uom': ("like", "{0}%".format(txt))
return frappe.get_all('UOM Conversion Detail', }, fields = ["distinct uom"], as_list=1)
filters = {'parent': ('in', items), 'uom': ("like", "{0}%".format(txt))},
fields = ["distinct uom"], as_list=1)

View File

@ -0,0 +1,89 @@
<h1 class="text-center" style="page-break-before:always">{{ filters.party[0] }}</h1>
<h3 class="text-center">{{ _("Statement of Accounts") }}</h3>
<h5 class="text-center">
{{ frappe.format(filters.from_date, 'Date')}}
{{ _("to") }}
{{ frappe.format(filters.to_date, 'Date')}}
</h5>
<table class="table table-bordered">
<thead>
<tr>
<th style="width: 12%">{{ _("Date") }}</th>
<th style="width: 15%">{{ _("Ref") }}</th>
<th style="width: 25%">{{ _("Party") }}</th>
<th style="width: 15%">{{ _("Debit") }}</th>
<th style="width: 15%">{{ _("Credit") }}</th>
<th style="width: 18%">{{ _("Balance (Dr - Cr)") }}</th>
</tr>
</thead>
<tbody>
{% for row in data %}
<tr>
{% if(row.posting_date) %}
<td>{{ frappe.format(row.posting_date, 'Date') }}</td>
<td>{{ row.voucher_type }}
<br>{{ row.voucher_no }}</td>
<td>
{% if not (filters.party or filters.account) %}
{{ row.party or row.account }}
<br>
{% endif %}
{{ _("Against") }}: {{ row.against }}
<br>{{ _("Remarks") }}: {{ row.remarks }}
{% if row.bill_no %}
<br>{{ _("Supplier Invoice No") }}: {{ row.bill_no }}
{% endif %}
</td>
<td style="text-align: right">
{{ frappe.utils.fmt_money(row.debit, filters.presentation_currency) }}</td>
<td style="text-align: right">
{{ frappe.utils.fmt_money(row.credit, filters.presentation_currency) }}</td>
{% else %}
<td></td>
<td></td>
<td><b>{{ frappe.format(row.account, {fieldtype: "Link"}) or "&nbsp;" }}</b></td>
<td style="text-align: right">
{{ row.account and frappe.utils.fmt_money(row.debit, filters.presentation_currency) }}
</td>
<td style="text-align: right">
{{ row.account and frappe.utils.fmt_money(row.credit, filters.presentation_currency) }}
</td>
{% endif %}
<td style="text-align: right">
{{ frappe.utils.fmt_money(row.balance, filters.presentation_currency) }}
</td>
</tr>
{% endfor %}
</tbody>
</table>
<br><br>
{% if aging %}
<h3 class="text-center">{{ _("Ageing Report Based On ") }} {{ aging.ageing_based_on }}</h3>
<h5 class="text-center">
{{ _("Up to " ) }} {{ frappe.format(filters.to_date, 'Date')}}
</h5>
<br>
<table class="table table-bordered">
<thead>
<tr>
<th style="width: 12%">30 Days</th>
<th style="width: 15%">60 Days</th>
<th style="width: 25%">90 Days</th>
<th style="width: 15%">120 Days</th>
</tr>
</thead>
<tbody>
<tr>
<td>{{ aging.range1 }}</td>
<td>{{ aging.range2 }}</td>
<td>{{ aging.range3 }}</td>
<td>{{ aging.range4 }}</td>
</tr>
</tbody>
</table>
{% endif %}
<p class="text-right text-muted">Printed On {{ frappe.format(frappe.utils.get_datetime(), 'Datetime') }}</p>

View File

@ -0,0 +1,132 @@
// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('Process Statement Of Accounts', {
view_properties: function(frm) {
frappe.route_options = {doc_type: 'Customer'};
frappe.set_route("Form", "Customize Form");
},
refresh: function(frm){
if(!frm.doc.__islocal) {
frm.add_custom_button('Send Emails',function(){
frappe.call({
method: "erpnext.accounts.doctype.process_statement_of_accounts.process_statement_of_accounts.send_emails",
args: {
"document_name": frm.doc.name,
},
callback: function(r) {
if(r && r.message) {
frappe.show_alert({message: __('Emails Queued'), indicator: 'blue'});
}
else{
frappe.msgprint('No Records for these settings.')
}
}
});
});
frm.add_custom_button('Download',function(){
var url = frappe.urllib.get_full_url(
'/api/method/erpnext.accounts.doctype.process_statement_of_accounts.process_statement_of_accounts.download_statements?'
+ 'document_name='+encodeURIComponent(frm.doc.name))
$.ajax({
url: url,
type: 'GET',
success: function(result) {
if(jQuery.isEmptyObject(result)){
frappe.msgprint('No Records for these settings.');
}
else{
window.location = url;
}
}
});
});
}
},
onload: function(frm) {
frm.set_query('currency', function(){
return {
filters: {
'enabled': 1
}
}
});
if(frm.doc.__islocal){
frm.set_value('from_date', frappe.datetime.add_months(frappe.datetime.get_today(), -1));
frm.set_value('to_date', frappe.datetime.get_today());
}
},
customer_collection: function(frm){
frm.set_value('collection_name', '');
if(frm.doc.customer_collection){
frm.get_field('collection_name').set_label(frm.doc.customer_collection);
}
},
frequency: function(frm){
if(frm.doc.frequency != ''){
frm.set_value('start_date', frappe.datetime.get_today());
}
else{
frm.set_value('start_date', '');
}
},
fetch_customers: function(frm){
if(frm.doc.collection_name){
frappe.call({
method: "erpnext.accounts.doctype.process_statement_of_accounts.process_statement_of_accounts.fetch_customers",
args: {
'customer_collection': frm.doc.customer_collection,
'collection_name': frm.doc.collection_name,
'primary_mandatory': frm.doc.primary_mandatory
},
callback: function(r) {
if(!r.exc) {
if(r.message.length){
frm.clear_table('customers');
for (const customer of r.message){
var row = frm.add_child('customers');
row.customer = customer.name;
row.primary_email = customer.primary_email;
row.billing_email = customer.billing_email;
}
frm.refresh_field('customers');
}
else{
frappe.msgprint('No Customers found with selected options.');
}
}
}
});
}
else {
frappe.throw('Enter ' + frm.doc.customer_collection + ' name.');
}
}
});
frappe.ui.form.on('Process Statement Of Accounts Customer', {
customer: function(frm, cdt, cdn){
var row = locals[cdt][cdn];
if (!row.customer){
return;
}
frappe.call({
method: 'erpnext.accounts.doctype.process_statement_of_accounts.process_statement_of_accounts.get_customer_emails',
args: {
'customer_name': row.customer,
'primary_mandatory': frm.doc.primary_mandatory
},
callback: function(r){
if(!r.exe){
if(r.message.length){
frappe.model.set_value(cdt, cdn, "primary_email", r.message[0])
frappe.model.set_value(cdt, cdn, "billing_email", r.message[1])
}
else {
return
}
}
}
})
}
});

View File

@ -0,0 +1,310 @@
{
"actions": [],
"allow_workflow": 1,
"autoname": "Prompt",
"creation": "2020-05-22 16:46:18.712954",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"section_break_11",
"from_date",
"company",
"account",
"group_by",
"cost_center",
"column_break_14",
"to_date",
"finance_book",
"currency",
"project",
"section_break_3",
"customer_collection",
"collection_name",
"fetch_customers",
"column_break_6",
"primary_mandatory",
"column_break_17",
"customers",
"preferences",
"orientation",
"section_break_14",
"include_ageing",
"ageing_based_on",
"section_break_1",
"enable_auto_email",
"section_break_18",
"frequency",
"filter_duration",
"column_break_21",
"start_date",
"section_break_33",
"subject",
"column_break_28",
"cc_to",
"section_break_30",
"body",
"help_text"
],
"fields": [
{
"fieldname": "frequency",
"fieldtype": "Select",
"label": "Frequency",
"options": "Weekly\nMonthly\nQuarterly"
},
{
"fieldname": "company",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Company",
"options": "Company",
"reqd": 1
},
{
"depends_on": "eval:doc.enable_auto_email == 0;",
"fieldname": "from_date",
"fieldtype": "Date",
"label": "From Date",
"mandatory_depends_on": "eval:doc.frequency == '';"
},
{
"depends_on": "eval:doc.enable_auto_email == 0;",
"fieldname": "to_date",
"fieldtype": "Date",
"label": "To Date",
"mandatory_depends_on": "eval:doc.frequency == '';"
},
{
"fieldname": "cost_center",
"fieldtype": "Table MultiSelect",
"label": "Cost Center",
"options": "PSOA Cost Center"
},
{
"fieldname": "project",
"fieldtype": "Table MultiSelect",
"label": "Project",
"options": "PSOA Project"
},
{
"fieldname": "section_break_3",
"fieldtype": "Section Break",
"label": "Customers"
},
{
"fieldname": "column_break_6",
"fieldtype": "Column Break"
},
{
"fieldname": "section_break_11",
"fieldtype": "Section Break",
"label": "General Ledger Filters"
},
{
"fieldname": "column_break_14",
"fieldtype": "Column Break"
},
{
"fieldname": "column_break_17",
"fieldtype": "Section Break",
"hide_border": 1
},
{
"fieldname": "customer_collection",
"fieldtype": "Select",
"label": "Select Customers By",
"options": "\nCustomer Group\nTerritory\nSales Partner\nSales Person"
},
{
"depends_on": "eval: doc.customer_collection !== ''",
"fieldname": "collection_name",
"fieldtype": "Dynamic Link",
"label": "Recipient",
"options": "customer_collection"
},
{
"fieldname": "section_break_1",
"fieldtype": "Section Break",
"label": "Email Settings"
},
{
"fieldname": "account",
"fieldtype": "Link",
"label": "Account",
"options": "Account"
},
{
"fieldname": "finance_book",
"fieldtype": "Link",
"label": "Finance Book",
"options": "Finance Book"
},
{
"fieldname": "preferences",
"fieldtype": "Section Break",
"label": "Print Preferences"
},
{
"fieldname": "orientation",
"fieldtype": "Select",
"label": "Orientation",
"options": "Landscape\nPortrait"
},
{
"default": "Today",
"fieldname": "start_date",
"fieldtype": "Date",
"label": "Start Date"
},
{
"default": "Group by Voucher (Consolidated)",
"fieldname": "group_by",
"fieldtype": "Select",
"label": "Group By",
"options": "\nGroup by Voucher\nGroup by Voucher (Consolidated)"
},
{
"fieldname": "currency",
"fieldtype": "Link",
"label": "Currency",
"options": "Currency"
},
{
"default": "0",
"fieldname": "include_ageing",
"fieldtype": "Check",
"in_list_view": 1,
"label": "Include Ageing Summary"
},
{
"default": "Due Date",
"depends_on": "eval:doc.include_ageing === 1",
"fieldname": "ageing_based_on",
"fieldtype": "Select",
"label": "Ageing Based On",
"options": "Due Date\nPosting Date"
},
{
"default": "0",
"fieldname": "enable_auto_email",
"fieldtype": "Check",
"in_list_view": 1,
"label": "Enable Auto Email"
},
{
"fieldname": "section_break_14",
"fieldtype": "Column Break",
"hide_border": 1
},
{
"depends_on": "eval: doc.enable_auto_email ==1",
"fieldname": "section_break_18",
"fieldtype": "Section Break",
"hide_border": 1
},
{
"fieldname": "column_break_21",
"fieldtype": "Column Break"
},
{
"depends_on": "eval: doc.customer_collection !== ''",
"fieldname": "fetch_customers",
"fieldtype": "Button",
"label": "Fetch Customers",
"options": "fetch_customers",
"print_hide": 1,
"report_hide": 1
},
{
"default": "1",
"fieldname": "primary_mandatory",
"fieldtype": "Check",
"label": "Send To Primary Contact"
},
{
"fieldname": "cc_to",
"fieldtype": "Link",
"label": "CC To",
"options": "User"
},
{
"default": "1",
"fieldname": "filter_duration",
"fieldtype": "Int",
"label": "Filter Duration (Months)"
},
{
"fieldname": "customers",
"fieldtype": "Table",
"label": "Customers",
"options": "Process Statement Of Accounts Customer",
"reqd": 1
},
{
"fieldname": "column_break_28",
"fieldtype": "Column Break"
},
{
"fieldname": "section_break_30",
"fieldtype": "Section Break",
"hide_border": 1
},
{
"fieldname": "section_break_33",
"fieldtype": "Section Break",
"hide_border": 1
},
{
"fieldname": "help_text",
"fieldtype": "HTML",
"label": "Help Text",
"options": "<br>\n<h4>Note</h4>\n<ul>\n<li>\nYou can use <a href=\"https://jinja.palletsprojects.com/en/2.11.x/\" target=\"_blank\">Jinja tags</a> in <b>Subject</b> and <b>Body</b> fields for dynamic values.\n</li><li>\n All fields in this doctype are available under the <b>doc</b> object and all fields for the customer to whom the mail will go to is available under the <b>customer</b> object.\n</li></ul>\n<h4> Examples</h4>\n<!-- {% raw %} -->\n<ul>\n <li><b>Subject</b>:<br><br><pre><code>Statement Of Accounts for {{ customer.name }}</code></pre><br></li>\n <li><b>Body</b>: <br><br>\n<pre><code>Hello {{ customer.name }},<br>PFA your Statement Of Accounts from {{ doc.from_date }} to {{ doc.to_date }}.</code> </pre></li>\n</ul>\n<!-- {% endraw %} -->"
},
{
"fieldname": "subject",
"fieldtype": "Data",
"label": "Subject"
},
{
"fieldname": "body",
"fieldtype": "Text Editor",
"label": "Body"
}
],
"links": [],
"modified": "2020-08-08 08:47:09.185728",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Process Statement Of Accounts",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts User",
"share": 1,
"write": 1
},
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts Manager",
"share": 1,
"write": 1
}
],
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}

View File

@ -0,0 +1,271 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
from erpnext.accounts.report.general_ledger.general_ledger import execute as get_soa
from erpnext.accounts.report.accounts_receivable_summary.accounts_receivable_summary import execute as get_ageing
from frappe.core.doctype.communication.email import make
from frappe.utils.print_format import report_to_pdf
from frappe.utils.pdf import get_pdf
from frappe.utils import today, add_days, add_months, getdate, format_date
from frappe.utils.jinja import validate_template
import copy
from datetime import timedelta
from frappe.www.printview import get_print_style
class ProcessStatementOfAccounts(Document):
def validate(self):
if not self.subject:
self.subject = 'Statement Of Accounts for {{ customer.name }}'
if not self.body:
self.body = 'Hello {{ customer.name }},<br>PFA your Statement Of Accounts from {{ doc.from_date }} to {{ doc.to_date }}.'
validate_template(self.subject)
validate_template(self.body)
if not self.customers:
frappe.throw(frappe._('Customers not selected.'))
if self.enable_auto_email:
self.to_date = self.start_date
self.from_date = add_months(self.to_date, -1 * self.filter_duration)
def get_report_pdf(doc, consolidated=True):
statement_dict = {}
aging = ''
base_template_path = "frappe/www/printview.html"
template_path = "erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html"
for entry in doc.customers:
if doc.include_ageing:
ageing_filters = frappe._dict({
'company': doc.company,
'report_date': doc.to_date,
'ageing_based_on': doc.ageing_based_on,
'range1': 30,
'range2': 60,
'range3': 90,
'range4': 120,
'customer': entry.customer
})
col1, aging = get_ageing(ageing_filters)
aging[0]['ageing_based_on'] = doc.ageing_based_on
tax_id = frappe.get_doc('Customer', entry.customer).tax_id
filters= frappe._dict({
'from_date': doc.from_date,
'to_date': doc.to_date,
'company': doc.company,
'finance_book': doc.finance_book if doc.finance_book else None,
"account": doc.account if doc.account else None,
'party_type': 'Customer',
'party': [entry.customer],
'group_by': doc.group_by,
'currency': doc.currency,
'cost_center': [cc.cost_center_name for cc in doc.cost_center],
'project': [p.project_name for p in doc.project],
'show_opening_entries': 0,
'include_default_book_entries': 0,
'show_cancelled_entries': 1,
'tax_id': tax_id if tax_id else None
})
col, res = get_soa(filters)
for x in [0, -2, -1]:
res[x]['account'] = res[x]['account'].replace("'","")
if len(res) == 3:
continue
html = frappe.render_template(template_path, \
{"filters": filters, "data": res, "aging": aging[0] if doc.include_ageing else None})
html = frappe.render_template(base_template_path, {"body": html, \
"css": get_print_style(), "title": "Statement For " + entry.customer})
statement_dict[entry.customer] = html
if not bool(statement_dict):
return False
elif consolidated:
result = ''.join(list(statement_dict.values()))
return get_pdf(result, {'orientation': doc.orientation})
else:
for customer, statement_html in statement_dict.items():
statement_dict[customer]=get_pdf(statement_html, {'orientation': doc.orientation})
return statement_dict
def get_customers_based_on_territory_or_customer_group(customer_collection, collection_name):
fields_dict = {
'Customer Group': 'customer_group',
'Territory': 'territory',
}
collection = frappe.get_doc(customer_collection, collection_name)
selected = [customer.name for customer in frappe.get_list(customer_collection, filters=[
['lft', '>=', collection.lft],
['rgt', '<=', collection.rgt]
],
fields=['name'],
order_by='lft asc, rgt desc'
)]
return frappe.get_list('Customer', fields=['name', 'email_id'], \
filters=[[fields_dict[customer_collection], 'IN', selected]])
def get_customers_based_on_sales_person(sales_person):
lft, rgt = frappe.db.get_value("Sales Person",
sales_person, ["lft", "rgt"])
records = frappe.db.sql("""
select distinct parent, parenttype
from `tabSales Team` steam
where parenttype = 'Customer'
and exists(select name from `tabSales Person` where lft >= %s and rgt <= %s and name = steam.sales_person)
""", (lft, rgt), as_dict=1)
sales_person_records = frappe._dict()
for d in records:
sales_person_records.setdefault(d.parenttype, set()).add(d.parent)
customers = frappe.get_list('Customer', fields=['name', 'email_id'], \
filters=[['name', 'in', list(sales_person_records['Customer'])]])
return customers
def get_recipients_and_cc(customer, doc):
recipients = []
for clist in doc.customers:
if clist.customer == customer:
recipients.append(clist.billing_email)
if doc.primary_mandatory and clist.primary_email:
recipients.append(clist.primary_email)
cc = []
if doc.cc_to != '':
try:
cc=[frappe.get_value('User', doc.cc_to, 'email')]
except:
pass
return recipients, cc
def get_context(customer, doc):
template_doc = copy.deepcopy(doc)
del template_doc.customers
template_doc.from_date = format_date(template_doc.from_date)
template_doc.to_date = format_date(template_doc.to_date)
return {
'doc': template_doc,
'customer': frappe.get_doc('Customer', customer),
'frappe': frappe.utils
}
@frappe.whitelist()
def fetch_customers(customer_collection, collection_name, primary_mandatory):
customer_list = []
customers = []
if customer_collection == 'Sales Person':
customers = get_customers_based_on_sales_person(collection_name)
if not bool(customers):
frappe.throw('No Customers found with selected options.')
else:
if customer_collection == 'Sales Partner':
customers = frappe.get_list('Customer', fields=['name', 'email_id'], \
filters=[['default_sales_partner', '=', collection_name]])
else:
customers = get_customers_based_on_territory_or_customer_group(customer_collection, collection_name)
for customer in customers:
primary_email = customer.get('email_id') or ''
billing_email = get_customer_emails(customer.name, 1, billing_and_primary=False)
if billing_email == '' or (primary_email == '' and int(primary_mandatory)):
continue
customer_list.append({
'name': customer.name,
'primary_email': primary_email,
'billing_email': billing_email
})
return customer_list
@frappe.whitelist()
def get_customer_emails(customer_name, primary_mandatory, billing_and_primary=True):
billing_email = frappe.db.sql("""
SELECT c.email_id FROM `tabContact` AS c JOIN `tabDynamic Link` AS l ON c.name=l.parent \
WHERE l.link_doctype='Customer' and l.link_name='""" + customer_name + """' and \
c.is_billing_contact=1 \
order by c.creation desc""")
if len(billing_email) == 0 or (billing_email[0][0] is None):
if billing_and_primary:
frappe.throw('No billing email found for customer: '+ customer_name)
else:
return ''
if billing_and_primary:
primary_email = frappe.get_value('Customer', customer_name, 'email_id')
if primary_email is None and int(primary_mandatory):
frappe.throw('No primary email found for customer: '+ customer_name)
return [primary_email or '', billing_email[0][0]]
else:
return billing_email[0][0] or ''
@frappe.whitelist()
def download_statements(document_name):
doc = frappe.get_doc('Process Statement Of Accounts', document_name)
report = get_report_pdf(doc)
if report:
frappe.local.response.filename = doc.name + '.pdf'
frappe.local.response.filecontent = report
frappe.local.response.type = "download"
@frappe.whitelist()
def send_emails(document_name, from_scheduler=False):
doc = frappe.get_doc('Process Statement Of Accounts', document_name)
report = get_report_pdf(doc, consolidated=False)
if report:
for customer, report_pdf in report.items():
attachments = [{
'fname': customer + '.pdf',
'fcontent': report_pdf
}]
recipients, cc = get_recipients_and_cc(customer, doc)
context = get_context(customer, doc)
subject = frappe.render_template(doc.subject, context)
message = frappe.render_template(doc.body, context)
frappe.enqueue(
queue='short',
method=frappe.sendmail,
recipients=recipients,
sender=frappe.session.user,
cc=cc,
subject=subject,
message=message,
now=True,
reference_doctype='Process Statement Of Accounts',
reference_name=document_name,
attachments=attachments
)
if doc.enable_auto_email and from_scheduler:
new_to_date = getdate(today())
if doc.frequency == 'Weekly':
new_to_date = add_days(new_to_date, 7)
else:
new_to_date = add_months(new_to_date, 1 if doc.frequency == 'Monthly' else 3)
new_from_date = add_months(new_to_date, -1 * doc.filter_duration)
doc.add_comment('Comment', 'Emails sent on: ' + frappe.utils.format_datetime(frappe.utils.now()))
doc.db_set('to_date', new_to_date, commit=True)
doc.db_set('from_date', new_from_date, commit=True)
return True
else:
return False
@frappe.whitelist()
def send_auto_email():
selected = frappe.get_list('Process Statement Of Accounts', filters={'to_date': format_date(today()), 'enable_auto_email': 1})
for entry in selected:
send_emails(entry.name, from_scheduler=True)
return True

View File

@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
# import frappe
import unittest
class TestProcessStatementOfAccounts(unittest.TestCase):
pass

View File

@ -0,0 +1,47 @@
{
"actions": [],
"allow_workflow": 1,
"creation": "2020-08-03 16:35:21.852178",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"customer",
"billing_email",
"primary_email"
],
"fields": [
{
"fieldname": "customer",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Customer",
"options": "Customer",
"reqd": 1
},
{
"fieldname": "primary_email",
"fieldtype": "Read Only",
"in_list_view": 1,
"label": "Primary Contact Email"
},
{
"fieldname": "billing_email",
"fieldtype": "Read Only",
"in_list_view": 1,
"label": "Billing Email"
}
],
"istable": 1,
"links": [],
"modified": "2020-08-03 22:55:38.875601",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Process Statement Of Accounts Customer",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}

View File

@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
# import frappe
from frappe.model.document import Document
class ProcessStatementOfAccountsCustomer(Document):
pass

View File

@ -0,0 +1,30 @@
{
"actions": [],
"creation": "2020-08-03 16:56:45.744905",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"cost_center_name"
],
"fields": [
{
"fieldname": "cost_center_name",
"fieldtype": "Link",
"label": "Cost Center",
"options": "Cost Center"
}
],
"istable": 1,
"links": [],
"modified": "2020-08-03 16:56:45.744905",
"modified_by": "Administrator",
"module": "Accounts",
"name": "PSOA Cost Center",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}

View File

@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
# import frappe
from frappe.model.document import Document
class PSOACostCenter(Document):
pass

View File

@ -0,0 +1,30 @@
{
"actions": [],
"creation": "2020-08-03 16:52:14.731978",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"project_name"
],
"fields": [
{
"fieldname": "project_name",
"fieldtype": "Link",
"label": "Project",
"options": "Project"
}
],
"istable": 1,
"links": [],
"modified": "2020-08-03 16:53:39.219736",
"modified_by": "Administrator",
"module": "Accounts",
"name": "PSOA Project",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}

View File

@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
# import frappe
from frappe.model.document import Document
class PSOAProject(Document):
pass

View File

@ -180,7 +180,7 @@
"no_copy": 1, "no_copy": 1,
"oldfieldname": "naming_series", "oldfieldname": "naming_series",
"oldfieldtype": "Select", "oldfieldtype": "Select",
"options": "ACC-PINV-.YYYY.-", "options": "ACC-PINV-.YYYY.-\nACC-PINV-RET-.YYYY.-",
"print_hide": 1, "print_hide": 1,
"reqd": 1, "reqd": 1,
"set_only_once": 1 "set_only_once": 1
@ -969,8 +969,10 @@
{ {
"fieldname": "clearance_date", "fieldname": "clearance_date",
"fieldtype": "Date", "fieldtype": "Date",
"hidden": 1, "label": "Clearance Date",
"label": "Clearance Date" "no_copy": 1,
"print_hide": 1,
"read_only": 1
}, },
{ {
"fieldname": "col_br_payments", "fieldname": "col_br_payments",
@ -1332,7 +1334,7 @@
"idx": 204, "idx": 204,
"is_submittable": 1, "is_submittable": 1,
"links": [], "links": [],
"modified": "2020-07-24 09:46:40.405463", "modified": "2020-08-03 23:20:04.466153",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Purchase Invoice", "name": "Purchase Invoice",

View File

@ -1,7 +1,6 @@
{ {
"actions": [], "actions": [],
"allow_import": 1, "allow_import": 1,
"allow_workflow": 1,
"autoname": "naming_series:", "autoname": "naming_series:",
"creation": "2013-05-24 19:29:05", "creation": "2013-05-24 19:29:05",
"doctype": "DocType", "doctype": "DocType",
@ -217,7 +216,7 @@
"no_copy": 1, "no_copy": 1,
"oldfieldname": "naming_series", "oldfieldname": "naming_series",
"oldfieldtype": "Select", "oldfieldtype": "Select",
"options": "ACC-SINV-.YYYY.-", "options": "ACC-SINV-.YYYY.-\nACC-SINV-RET-.YYYY.-",
"print_hide": 1, "print_hide": 1,
"reqd": 1, "reqd": 1,
"set_only_once": 1 "set_only_once": 1
@ -1947,7 +1946,7 @@
"idx": 181, "idx": 181,
"is_submittable": 1, "is_submittable": 1,
"links": [], "links": [],
"modified": "2020-07-18 05:07:16.725974", "modified": "2020-08-03 23:31:12.675040",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Sales Invoice", "name": "Sales Invoice",

View File

@ -18,7 +18,7 @@ def get_data():
'transactions': [ 'transactions': [
{ {
'label': _('Payment'), 'label': _('Payment'),
'items': ['Payment Entry', 'Payment Request', 'Journal Entry', 'Invoice Discounting'] 'items': ['Payment Entry', 'Payment Request', 'Journal Entry', 'Invoice Discounting', 'Dunning']
}, },
{ {
'label': _('Reference'), 'label': _('Reference'),

View File

@ -64,6 +64,7 @@
"fieldname": "clearance_date", "fieldname": "clearance_date",
"fieldtype": "Date", "fieldtype": "Date",
"label": "Clearance Date", "label": "Clearance Date",
"no_copy": 1,
"print_hide": 1, "print_hide": 1,
"read_only": 1 "read_only": 1
}, },
@ -78,7 +79,7 @@
], ],
"istable": 1, "istable": 1,
"links": [], "links": [],
"modified": "2020-05-05 16:51:20.091441", "modified": "2020-08-03 12:45:39.986598",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Sales Invoice Payment", "name": "Sales Invoice Payment",

View File

@ -8,7 +8,7 @@ def get_data():
'fieldname': 'taxes_and_charges', 'fieldname': 'taxes_and_charges',
'non_standard_fieldnames': { 'non_standard_fieldnames': {
'Tax Rule': 'sales_tax_template', 'Tax Rule': 'sales_tax_template',
'Subscription': 'tax_template', 'Subscription': 'sales_tax_template',
'Restaurant': 'default_tax_template' 'Restaurant': 'default_tax_template'
}, },
'transactions': [ 'transactions': [

View File

@ -7,8 +7,8 @@ import unittest
import frappe import frappe
from erpnext.accounts.doctype.subscription.subscription import get_prorata_factor from erpnext.accounts.doctype.subscription.subscription import get_prorata_factor
from frappe.utils.data import nowdate, add_days, add_to_date, add_months, date_diff, flt, get_date_str from frappe.utils.data import (nowdate, add_days, add_to_date, add_months, date_diff, flt, get_date_str,
get_first_day, get_last_day)
def create_plan(): def create_plan():
if not frappe.db.exists('Subscription Plan', '_Test Plan Name'): if not frappe.db.exists('Subscription Plan', '_Test Plan Name'):
@ -68,14 +68,14 @@ class TestSubscription(unittest.TestCase):
subscription.party_type = 'Customer' subscription.party_type = 'Customer'
subscription.party = '_Test Customer' subscription.party = '_Test Customer'
subscription.trial_period_start = nowdate() subscription.trial_period_start = nowdate()
subscription.trial_period_end = add_days(nowdate(), 30) subscription.trial_period_end = add_months(nowdate(), 1)
subscription.append('plans', {'plan': '_Test Plan Name', 'qty': 1}) subscription.append('plans', {'plan': '_Test Plan Name', 'qty': 1})
subscription.save() subscription.save()
self.assertEqual(subscription.trial_period_start, nowdate()) self.assertEqual(subscription.trial_period_start, nowdate())
self.assertEqual(subscription.trial_period_end, add_days(nowdate(), 30)) self.assertEqual(subscription.trial_period_end, add_months(nowdate(), 1))
self.assertEqual(add_days(subscription.trial_period_end, 1), get_date_str(subscription.current_invoice_start)) self.assertEqual(add_days(subscription.trial_period_end, 1), get_date_str(subscription.current_invoice_start))
self.assertEqual(add_days(subscription.current_invoice_start, 30), get_date_str(subscription.current_invoice_end)) self.assertEqual(add_to_date(subscription.current_invoice_start, months=1, days=-1), get_date_str(subscription.current_invoice_end))
self.assertEqual(subscription.invoices, []) self.assertEqual(subscription.invoices, [])
self.assertEqual(subscription.status, 'Trialling') self.assertEqual(subscription.status, 'Trialling')

View File

@ -290,6 +290,7 @@ def get_matching_transactions_payments(description_matching):
return [] return []
@frappe.whitelist() @frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def payment_entry_query(doctype, txt, searchfield, start, page_len, filters): def payment_entry_query(doctype, txt, searchfield, start, page_len, filters):
account = frappe.db.get_value("Bank Account", filters.get("bank_account"), "account") account = frappe.db.get_value("Bank Account", filters.get("bank_account"), "account")
if not account: if not account:
@ -319,6 +320,7 @@ def payment_entry_query(doctype, txt, searchfield, start, page_len, filters):
) )
@frappe.whitelist() @frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def journal_entry_query(doctype, txt, searchfield, start, page_len, filters): def journal_entry_query(doctype, txt, searchfield, start, page_len, filters):
account = frappe.db.get_value("Bank Account", filters.get("bank_account"), "account") account = frappe.db.get_value("Bank Account", filters.get("bank_account"), "account")
@ -355,6 +357,7 @@ def journal_entry_query(doctype, txt, searchfield, start, page_len, filters):
) )
@frappe.whitelist() @frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def sales_invoices_query(doctype, txt, searchfield, start, page_len, filters): def sales_invoices_query(doctype, txt, searchfield, start, page_len, filters):
return frappe.db.sql(""" return frappe.db.sql("""
SELECT SELECT

View File

@ -611,7 +611,7 @@ def get_partywise_advanced_payment_amount(party_type, posting_date = None, futur
cond = "posting_date <= '{0}'".format(posting_date) cond = "posting_date <= '{0}'".format(posting_date)
if company: if company:
cond += "and company = '{0}'".format(company) cond += "and company = {0}".format(frappe.db.escape(company))
data = frappe.db.sql(""" SELECT party, sum({0}) as amount data = frappe.db.sql(""" SELECT party, sum({0}) as amount
FROM `tabGL Entry` FROM `tabGL Entry`

View File

@ -643,6 +643,8 @@ class ReceivablePayableReport(object):
account_type = "Receivable" if self.party_type == "Customer" else "Payable" account_type = "Receivable" if self.party_type == "Customer" else "Payable"
accounts = [d.name for d in frappe.get_all("Account", accounts = [d.name for d in frappe.get_all("Account",
filters={"account_type": account_type, "company": self.filters.company})] filters={"account_type": account_type, "company": self.filters.company})]
if accounts:
conditions.append("account in (%s)" % ','.join(['%s'] *len(accounts))) conditions.append("account in (%s)" % ','.join(['%s'] *len(accounts)))
values += accounts values += accounts

View File

@ -122,7 +122,7 @@ def get_balance_on(account=None, date=None, party_type=None, party=None, company
cost_center = frappe.form_dict.get("cost_center") cost_center = frappe.form_dict.get("cost_center")
cond = [] cond = ["is_cancelled=0"]
if date: if date:
cond.append("posting_date <= %s" % frappe.db.escape(cstr(date))) cond.append("posting_date <= %s" % frappe.db.escape(cstr(date)))
else: else:
@ -206,7 +206,7 @@ def get_balance_on(account=None, date=None, party_type=None, party=None, company
return flt(bal) return flt(bal)
def get_count_on(account, fieldname, date): def get_count_on(account, fieldname, date):
cond = [] cond = ["is_cancelled=0"]
if date: if date:
cond.append("posting_date <= %s" % frappe.db.escape(cstr(date))) cond.append("posting_date <= %s" % frappe.db.escape(cstr(date)))
else: else:

View File

@ -1,4 +1,5 @@
{ {
"actions": [],
"allow_import": 1, "allow_import": 1,
"allow_rename": 1, "allow_rename": 1,
"autoname": "naming_series:", "autoname": "naming_series:",
@ -7,8 +8,9 @@
"document_type": "Document", "document_type": "Document",
"engine": "InnoDB", "engine": "InnoDB",
"field_order": [ "field_order": [
"is_existing_asset",
"section_break_2",
"naming_series", "naming_series",
"asset_name",
"item_code", "item_code",
"item_name", "item_name",
"asset_category", "asset_category",
@ -17,29 +19,31 @@
"supplier", "supplier",
"customer", "customer",
"image", "image",
"purchase_invoice", "journal_entry_for_scrap",
"column_break_3", "column_break_3",
"company", "company",
"asset_name",
"location", "location",
"custodian", "custodian",
"department", "department",
"purchase_date",
"disposal_date", "disposal_date",
"journal_entry_for_scrap",
"purchase_receipt",
"accounting_dimensions_section", "accounting_dimensions_section",
"cost_center", "cost_center",
"dimension_col_break", "dimension_col_break",
"section_break_5", "purchase_details_section",
"gross_purchase_amount", "purchase_receipt",
"purchase_invoice",
"available_for_use_date", "available_for_use_date",
"column_break_18", "column_break_23",
"gross_purchase_amount",
"purchase_date",
"section_break_23",
"calculate_depreciation", "calculate_depreciation",
"allow_monthly_depreciation", "allow_monthly_depreciation",
"is_existing_asset", "column_break_33",
"opening_accumulated_depreciation", "opening_accumulated_depreciation",
"number_of_depreciations_booked", "number_of_depreciations_booked",
"section_break_23", "section_break_36",
"finance_books", "finance_books",
"section_break_33", "section_break_33",
"depreciation_method", "depreciation_method",
@ -64,7 +68,6 @@
"status", "status",
"booked_fixed_asset", "booked_fixed_asset",
"column_break_51", "column_break_51",
"purchase_receipt_amount", "purchase_receipt_amount",
"default_finance_book", "default_finance_book",
"amended_from" "amended_from"
@ -187,6 +190,8 @@
"fieldname": "purchase_date", "fieldname": "purchase_date",
"fieldtype": "Date", "fieldtype": "Date",
"label": "Purchase Date", "label": "Purchase Date",
"read_only": 1,
"read_only_depends_on": "eval:!doc.is_existing_asset",
"reqd": 1 "reqd": 1
}, },
{ {
@ -204,25 +209,20 @@
"print_hide": 1, "print_hide": 1,
"read_only": 1 "read_only": 1
}, },
{
"fieldname": "section_break_5",
"fieldtype": "Section Break"
},
{ {
"fieldname": "gross_purchase_amount", "fieldname": "gross_purchase_amount",
"fieldtype": "Currency", "fieldtype": "Currency",
"label": "Gross Purchase Amount", "label": "Gross Purchase Amount",
"options": "Company:company:default_currency", "options": "Company:company:default_currency",
"read_only": 1,
"read_only_depends_on": "eval:!doc.is_existing_asset",
"reqd": 1 "reqd": 1
}, },
{ {
"fieldname": "available_for_use_date", "fieldname": "available_for_use_date",
"fieldtype": "Date", "fieldtype": "Date",
"label": "Available-for-use Date" "label": "Available-for-use Date",
}, "reqd": 1
{
"fieldname": "column_break_18",
"fieldtype": "Column Break"
}, },
{ {
"default": "0", "default": "0",
@ -252,12 +252,14 @@
"no_copy": 1 "no_copy": 1
}, },
{ {
"depends_on": "calculate_depreciation", "collapsible": 1,
"collapsible_depends_on": "eval:doc.calculate_depreciation || doc.is_existing_asset",
"fieldname": "section_break_23", "fieldname": "section_break_23",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"label": "Depreciation" "label": "Depreciation"
}, },
{ {
"columns": 10,
"fieldname": "finance_books", "fieldname": "finance_books",
"fieldtype": "Table", "fieldtype": "Table",
"label": "Finance Books", "label": "Finance Books",
@ -305,8 +307,7 @@
{ {
"depends_on": "calculate_depreciation", "depends_on": "calculate_depreciation",
"fieldname": "section_break_14", "fieldname": "section_break_14",
"fieldtype": "Section Break", "fieldtype": "Section Break"
"label": "Depreciation Schedule"
}, },
{ {
"fieldname": "schedules", "fieldname": "schedules",
@ -456,12 +457,37 @@
"fieldname": "allow_monthly_depreciation", "fieldname": "allow_monthly_depreciation",
"fieldtype": "Check", "fieldtype": "Check",
"label": "Allow Monthly Depreciation" "label": "Allow Monthly Depreciation"
},
{
"fieldname": "section_break_2",
"fieldtype": "Section Break"
},
{
"collapsible": 1,
"collapsible_depends_on": "is_existing_asset",
"fieldname": "purchase_details_section",
"fieldtype": "Section Break",
"label": "Purchase Details"
},
{
"fieldname": "column_break_23",
"fieldtype": "Column Break"
},
{
"fieldname": "column_break_33",
"fieldtype": "Column Break"
},
{
"depends_on": "calculate_depreciation",
"fieldname": "section_break_36",
"fieldtype": "Section Break"
} }
], ],
"idx": 72, "idx": 72,
"image_field": "image", "image_field": "image",
"is_submittable": 1, "is_submittable": 1,
"modified": "2019-10-22 15:47:36.050828", "links": [],
"modified": "2020-07-28 15:04:44.452224",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Assets", "module": "Assets",
"name": "Asset", "name": "Asset",

View File

@ -106,6 +106,7 @@ def update_maintenance_log(asset_maintenance, item_code, item_name, task):
maintenance_log.save() maintenance_log.save()
@frappe.whitelist() @frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def get_team_members(doctype, txt, searchfield, start, page_len, filters): def get_team_members(doctype, txt, searchfield, start, page_len, filters):
return frappe.db.get_values('Maintenance Team Member', { 'parent': filters.get("maintenance_team") }) return frappe.db.get_values('Maintenance Team Member', { 'parent': filters.get("maintenance_team") })

View File

@ -41,6 +41,7 @@ class AssetMaintenanceLog(Document):
asset_maintenance_doc.save() asset_maintenance_doc.save()
@frappe.whitelist() @frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def get_maintenance_tasks(doctype, txt, searchfield, start, page_len, filters): def get_maintenance_tasks(doctype, txt, searchfield, start, page_len, filters):
asset_maintenance_tasks = frappe.db.get_values('Asset Maintenance Task', {'parent':filters.get("asset_maintenance")}, 'maintenance_task') asset_maintenance_tasks = frappe.db.get_values('Asset Maintenance Task', {'parent':filters.get("asset_maintenance")}, 'maintenance_task')
return asset_maintenance_tasks return asset_maintenance_tasks

View File

@ -8,6 +8,7 @@ from frappe import _
from frappe.utils import flt, getdate, cint, date_diff, formatdate from frappe.utils import flt, getdate, cint, date_diff, formatdate
from erpnext.assets.doctype.asset.depreciation import get_depreciation_accounts from erpnext.assets.doctype.asset.depreciation import get_depreciation_accounts
from frappe.model.document import Document from frappe.model.document import Document
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_checks_for_pl_and_bs_accounts
class AssetValueAdjustment(Document): class AssetValueAdjustment(Document):
def validate(self): def validate(self):
@ -53,18 +54,34 @@ class AssetValueAdjustment(Document):
je.company = self.company je.company = self.company
je.remark = "Depreciation Entry against {0} worth {1}".format(self.asset, self.difference_amount) je.remark = "Depreciation Entry against {0} worth {1}".format(self.asset, self.difference_amount)
je.append("accounts", { credit_entry = {
"account": accumulated_depreciation_account, "account": accumulated_depreciation_account,
"credit_in_account_currency": self.difference_amount, "credit_in_account_currency": self.difference_amount,
"cost_center": depreciation_cost_center or self.cost_center "cost_center": depreciation_cost_center or self.cost_center
}) }
je.append("accounts", { debit_entry = {
"account": depreciation_expense_account, "account": depreciation_expense_account,
"debit_in_account_currency": self.difference_amount, "debit_in_account_currency": self.difference_amount,
"cost_center": depreciation_cost_center or self.cost_center "cost_center": depreciation_cost_center or self.cost_center
}
accounting_dimensions = get_checks_for_pl_and_bs_accounts()
for dimension in accounting_dimensions:
if dimension.get('mandatory_for_bs'):
credit_entry.update({
dimension['fieldname']: self.get(dimension['fieldname']) or dimension.get('default_dimension')
}) })
if dimension.get('mandatory_for_pl'):
debit_entry.update({
dimension['fieldname']: self.get(dimension['fieldname']) or dimension.get('default_dimension')
})
je.append("accounts", credit_entry)
je.append("accounts", debit_entry)
je.flags.ignore_permissions = True je.flags.ignore_permissions = True
je.submit() je.submit()

View File

@ -1084,7 +1084,7 @@
"idx": 105, "idx": 105,
"is_submittable": 1, "is_submittable": 1,
"links": [], "links": [],
"modified": "2020-07-18 05:09:33.800633", "modified": "2020-07-31 14:13:44.610190",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Buying", "module": "Buying",
"name": "Purchase Order", "name": "Purchase Order",
@ -1135,5 +1135,5 @@
"sort_field": "modified", "sort_field": "modified",
"sort_order": "DESC", "sort_order": "DESC",
"timeline_field": "supplier", "timeline_field": "supplier",
"title_field": "title" "title_field": "supplier"
} }

View File

@ -207,6 +207,7 @@ def get_list_context(context=None):
return list_context return list_context
@frappe.whitelist() @frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def get_supplier_contacts(doctype, txt, searchfield, start, page_len, filters): def get_supplier_contacts(doctype, txt, searchfield, start, page_len, filters):
return frappe.db.sql("""select `tabContact`.name from `tabContact`, `tabDynamic Link` return frappe.db.sql("""select `tabContact`.name from `tabContact`, `tabDynamic Link`
where `tabDynamic Link`.link_doctype = 'Supplier' and (`tabDynamic Link`.link_name=%(name)s where `tabDynamic Link`.link_doctype = 'Supplier' and (`tabDynamic Link`.link_name=%(name)s

View File

@ -479,7 +479,11 @@ class AccountsController(TransactionBase):
if d.against_order: if d.against_order:
allocated_amount = flt(d.amount) allocated_amount = flt(d.amount)
else: else:
amount = self.rounded_total or self.grand_total if self.get('party_account_currency') == self.company_currency:
amount = self.get('base_rounded_total') or self.base_grand_total
else:
amount = self.get('rounded_total') or self.grand_total
allocated_amount = min(amount - advance_allocated, d.amount) allocated_amount = min(amount - advance_allocated, d.amount)
advance_allocated += flt(allocated_amount) advance_allocated += flt(allocated_amount)
@ -802,10 +806,22 @@ class AccountsController(TransactionBase):
self.payment_terms_template = '' self.payment_terms_template = ''
return return
party_account_currency = self.get('party_account_currency')
if not party_account_currency:
party_type, party = self.get_party()
if party_type and party:
party_account_currency = get_party_account_currency(party_type, party, self.company)
posting_date = self.get("bill_date") or self.get("posting_date") or self.get("transaction_date") posting_date = self.get("bill_date") or self.get("posting_date") or self.get("transaction_date")
date = self.get("due_date") date = self.get("due_date")
due_date = date or posting_date due_date = date or posting_date
if party_account_currency == self.company_currency:
grand_total = self.get("base_rounded_total") or self.base_grand_total
else:
grand_total = self.get("rounded_total") or self.grand_total grand_total = self.get("rounded_total") or self.grand_total
if self.doctype in ("Sales Invoice", "Purchase Invoice"): if self.doctype in ("Sales Invoice", "Purchase Invoice"):
grand_total = grand_total - flt(self.write_off_amount) grand_total = grand_total - flt(self.write_off_amount)
@ -850,13 +866,25 @@ class AccountsController(TransactionBase):
def validate_payment_schedule_amount(self): def validate_payment_schedule_amount(self):
if self.doctype == 'Sales Invoice' and self.is_pos: return if self.doctype == 'Sales Invoice' and self.is_pos: return
party_account_currency = self.get('party_account_currency')
if not party_account_currency:
party_type, party = self.get_party()
if party_type and party:
party_account_currency = get_party_account_currency(party_type, party, self.company)
if self.get("payment_schedule"): if self.get("payment_schedule"):
total = 0 total = 0
for d in self.get("payment_schedule"): for d in self.get("payment_schedule"):
total += flt(d.payment_amount) total += flt(d.payment_amount)
total = flt(total, self.precision("grand_total"))
if party_account_currency == self.company_currency:
total = flt(total, self.precision("base_grand_total"))
grand_total = flt(self.get("base_rounded_total") or self.base_grand_total, self.precision('base_grand_total'))
else:
total = flt(total, self.precision("grand_total"))
grand_total = flt(self.get("rounded_total") or self.grand_total, self.precision('grand_total')) grand_total = flt(self.get("rounded_total") or self.grand_total, self.precision('grand_total'))
if self.get("total_advance"): if self.get("total_advance"):
grand_total -= self.get("total_advance") grand_total -= self.get("total_advance")

View File

@ -12,6 +12,7 @@ from frappe.utils import unique
# searches for active employees # searches for active employees
@frappe.whitelist() @frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def employee_query(doctype, txt, searchfield, start, page_len, filters): def employee_query(doctype, txt, searchfield, start, page_len, filters):
conditions = [] conditions = []
fields = get_fields("Employee", ["name", "employee_name"]) fields = get_fields("Employee", ["name", "employee_name"])
@ -42,6 +43,7 @@ def employee_query(doctype, txt, searchfield, start, page_len, filters):
# searches for leads which are not converted # searches for leads which are not converted
@frappe.whitelist() @frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def lead_query(doctype, txt, searchfield, start, page_len, filters): def lead_query(doctype, txt, searchfield, start, page_len, filters):
fields = get_fields("Lead", ["name", "lead_name", "company_name"]) fields = get_fields("Lead", ["name", "lead_name", "company_name"])
@ -72,6 +74,7 @@ def lead_query(doctype, txt, searchfield, start, page_len, filters):
# searches for customer # searches for customer
@frappe.whitelist() @frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def customer_query(doctype, txt, searchfield, start, page_len, filters): def customer_query(doctype, txt, searchfield, start, page_len, filters):
conditions = [] conditions = []
cust_master_name = frappe.defaults.get_user_default("cust_master_name") cust_master_name = frappe.defaults.get_user_default("cust_master_name")
@ -110,8 +113,10 @@ def customer_query(doctype, txt, searchfield, start, page_len, filters):
# searches for supplier # searches for supplier
@frappe.whitelist() @frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def supplier_query(doctype, txt, searchfield, start, page_len, filters): def supplier_query(doctype, txt, searchfield, start, page_len, filters):
supp_master_name = frappe.defaults.get_user_default("supp_master_name") supp_master_name = frappe.defaults.get_user_default("supp_master_name")
if supp_master_name == "Supplier Name": if supp_master_name == "Supplier Name":
fields = ["name", "supplier_group"] fields = ["name", "supplier_group"]
else: else:
@ -142,32 +147,49 @@ def supplier_query(doctype, txt, searchfield, start, page_len, filters):
@frappe.whitelist() @frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def tax_account_query(doctype, txt, searchfield, start, page_len, filters): def tax_account_query(doctype, txt, searchfield, start, page_len, filters):
company_currency = erpnext.get_company_currency(filters.get('company')) company_currency = erpnext.get_company_currency(filters.get('company'))
tax_accounts = frappe.db.sql("""select name, parent_account from tabAccount def get_accounts(with_account_type_filter):
where tabAccount.docstatus!=2 account_type_condition = ''
and account_type in (%s) if with_account_type_filter:
and is_group = 0 account_type_condition = "AND account_type in %(account_types)s"
and company = %s
and account_currency = %s accounts = frappe.db.sql("""
and `%s` LIKE %s SELECT name, parent_account
order by idx desc, name FROM `tabAccount`
limit %s, %s""" % WHERE `tabAccount`.docstatus!=2
(", ".join(['%s']*len(filters.get("account_type"))), "%s", "%s", searchfield, "%s", "%s", "%s"), {account_type_condition}
tuple(filters.get("account_type") + [filters.get("company"), company_currency, "%%%s%%" % txt, AND is_group = 0
start, page_len])) AND company = %(company)s
AND account_currency = %(currency)s
AND `{searchfield}` LIKE %(txt)s
ORDER BY idx DESC, name
LIMIT %(offset)s, %(limit)s
""".format(account_type_condition=account_type_condition, searchfield=searchfield),
dict(
account_types=filters.get("account_type"),
company=filters.get("company"),
currency=company_currency,
txt="%{}%".format(txt),
offset=start,
limit=page_len
)
)
return accounts
tax_accounts = get_accounts(True)
if not tax_accounts: if not tax_accounts:
tax_accounts = frappe.db.sql("""select name, parent_account from tabAccount tax_accounts = get_accounts(False)
where tabAccount.docstatus!=2 and is_group = 0
and company = %s and account_currency = %s and `%s` LIKE %s limit %s, %s""" #nosec
% ("%s", "%s", searchfield, "%s", "%s", "%s"),
(filters.get("company"), company_currency, "%%%s%%" % txt, start, page_len))
return tax_accounts return tax_accounts
@frappe.whitelist() @frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def item_query(doctype, txt, searchfield, start, page_len, filters, as_dict=False): def item_query(doctype, txt, searchfield, start, page_len, filters, as_dict=False):
conditions = [] conditions = []
@ -215,7 +237,6 @@ def item_query(doctype, txt, searchfield, start, page_len, filters, as_dict=Fals
idx desc, idx desc,
name, item_name name, item_name
limit %(start)s, %(page_len)s """.format( limit %(start)s, %(page_len)s """.format(
key=searchfield,
columns=columns, columns=columns,
scond=searchfields, scond=searchfields,
fcond=get_filters_cond(doctype, filters, conditions).replace('%', '%%'), fcond=get_filters_cond(doctype, filters, conditions).replace('%', '%%'),
@ -231,6 +252,7 @@ def item_query(doctype, txt, searchfield, start, page_len, filters, as_dict=Fals
@frappe.whitelist() @frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def bom(doctype, txt, searchfield, start, page_len, filters): def bom(doctype, txt, searchfield, start, page_len, filters):
conditions = [] conditions = []
fields = get_fields("BOM", ["name", "item"]) fields = get_fields("BOM", ["name", "item"])
@ -258,6 +280,7 @@ def bom(doctype, txt, searchfield, start, page_len, filters):
@frappe.whitelist() @frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def get_project_name(doctype, txt, searchfield, start, page_len, filters): def get_project_name(doctype, txt, searchfield, start, page_len, filters):
cond = '' cond = ''
if filters.get('customer'): if filters.get('customer'):
@ -285,6 +308,7 @@ def get_project_name(doctype, txt, searchfield, start, page_len, filters):
@frappe.whitelist() @frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def get_delivery_notes_to_be_billed(doctype, txt, searchfield, start, page_len, filters, as_dict): def get_delivery_notes_to_be_billed(doctype, txt, searchfield, start, page_len, filters, as_dict):
fields = get_fields("Delivery Note", ["name", "customer", "posting_date"]) fields = get_fields("Delivery Note", ["name", "customer", "posting_date"])
@ -315,6 +339,7 @@ def get_delivery_notes_to_be_billed(doctype, txt, searchfield, start, page_len,
@frappe.whitelist() @frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def get_batch_no(doctype, txt, searchfield, start, page_len, filters): def get_batch_no(doctype, txt, searchfield, start, page_len, filters):
cond = "" cond = ""
if filters.get("posting_date"): if filters.get("posting_date"):
@ -373,6 +398,7 @@ def get_batch_no(doctype, txt, searchfield, start, page_len, filters):
@frappe.whitelist() @frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def get_account_list(doctype, txt, searchfield, start, page_len, filters): def get_account_list(doctype, txt, searchfield, start, page_len, filters):
filter_list = [] filter_list = []
@ -395,8 +421,8 @@ def get_account_list(doctype, txt, searchfield, start, page_len, filters):
fields = ["name", "parent_account"], fields = ["name", "parent_account"],
limit_start=start, limit_page_length=page_len, as_list=True) limit_start=start, limit_page_length=page_len, as_list=True)
@frappe.whitelist() @frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def get_blanket_orders(doctype, txt, searchfield, start, page_len, filters): def get_blanket_orders(doctype, txt, searchfield, start, page_len, filters):
return frappe.db.sql("""select distinct bo.name, bo.blanket_order_type, bo.to_date return frappe.db.sql("""select distinct bo.name, bo.blanket_order_type, bo.to_date
from `tabBlanket Order` bo, `tabBlanket Order Item` boi from `tabBlanket Order` bo, `tabBlanket Order Item` boi
@ -413,6 +439,7 @@ def get_blanket_orders(doctype, txt, searchfield, start, page_len, filters):
@frappe.whitelist() @frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def get_income_account(doctype, txt, searchfield, start, page_len, filters): def get_income_account(doctype, txt, searchfield, start, page_len, filters):
from erpnext.controllers.queries import get_match_cond from erpnext.controllers.queries import get_match_cond
@ -439,6 +466,7 @@ def get_income_account(doctype, txt, searchfield, start, page_len, filters):
@frappe.whitelist() @frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def get_expense_account(doctype, txt, searchfield, start, page_len, filters): def get_expense_account(doctype, txt, searchfield, start, page_len, filters):
from erpnext.controllers.queries import get_match_cond from erpnext.controllers.queries import get_match_cond
@ -463,6 +491,7 @@ def get_expense_account(doctype, txt, searchfield, start, page_len, filters):
@frappe.whitelist() @frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def warehouse_query(doctype, txt, searchfield, start, page_len, filters): def warehouse_query(doctype, txt, searchfield, start, page_len, filters):
# Should be used when item code is passed in filters. # Should be used when item code is passed in filters.
conditions, bin_conditions = [], [] conditions, bin_conditions = [], []
@ -506,6 +535,7 @@ def get_doctype_wise_filters(filters):
@frappe.whitelist() @frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def get_batch_numbers(doctype, txt, searchfield, start, page_len, filters): def get_batch_numbers(doctype, txt, searchfield, start, page_len, filters):
query = """select batch_id from `tabBatch` query = """select batch_id from `tabBatch`
where disabled = 0 where disabled = 0
@ -519,6 +549,7 @@ def get_batch_numbers(doctype, txt, searchfield, start, page_len, filters):
@frappe.whitelist() @frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def item_manufacturer_query(doctype, txt, searchfield, start, page_len, filters): def item_manufacturer_query(doctype, txt, searchfield, start, page_len, filters):
item_filters = [ item_filters = [
['manufacturer', 'like', '%' + txt + '%'], ['manufacturer', 'like', '%' + txt + '%'],
@ -537,6 +568,7 @@ def item_manufacturer_query(doctype, txt, searchfield, start, page_len, filters)
@frappe.whitelist() @frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def get_purchase_receipts(doctype, txt, searchfield, start, page_len, filters): def get_purchase_receipts(doctype, txt, searchfield, start, page_len, filters):
query = """ query = """
select pr.name select pr.name
@ -551,6 +583,7 @@ def get_purchase_receipts(doctype, txt, searchfield, start, page_len, filters):
@frappe.whitelist() @frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def get_purchase_invoices(doctype, txt, searchfield, start, page_len, filters): def get_purchase_invoices(doctype, txt, searchfield, start, page_len, filters):
query = """ query = """
select pi.name select pi.name
@ -565,6 +598,7 @@ def get_purchase_invoices(doctype, txt, searchfield, start, page_len, filters):
@frappe.whitelist() @frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def get_tax_template(doctype, txt, searchfield, start, page_len, filters): def get_tax_template(doctype, txt, searchfield, start, page_len, filters):
item_doc = frappe.get_cached_doc('Item', filters.get('item_code')) item_doc = frappe.get_cached_doc('Item', filters.get('item_code'))
@ -579,9 +613,12 @@ def get_tax_template(doctype, txt, searchfield, start, page_len, filters):
if not taxes: if not taxes:
return frappe.db.sql(""" SELECT name FROM `tabItem Tax Template` """) return frappe.db.sql(""" SELECT name FROM `tabItem Tax Template` """)
else: else:
valid_from = filters.get('valid_from')
valid_from = valid_from[1] if isinstance(valid_from, list) else valid_from
args = { args = {
'item_code': filters.get('item_code'), 'item_code': filters.get('item_code'),
'posting_date': filters.get('valid_from'), 'posting_date': valid_from,
'tax_category': filters.get('tax_category'), 'tax_category': filters.get('tax_category'),
'company': filters.get('company') 'company': filters.get('company')
} }

View File

@ -16,6 +16,7 @@
"opportunity_from", "opportunity_from",
"party_name", "party_name",
"customer_name", "customer_name",
"source",
"column_break0", "column_break0",
"title", "title",
"opportunity_type", "opportunity_type",
@ -49,10 +50,9 @@
"contact_email", "contact_email",
"contact_mobile", "contact_mobile",
"more_info", "more_info",
"source", "company",
"campaign", "campaign",
"column_break1", "column_break1",
"company",
"transaction_date", "transaction_date",
"amended_from", "amended_from",
"lost_reasons" "lost_reasons"
@ -344,7 +344,7 @@
"collapsible": 1, "collapsible": 1,
"fieldname": "more_info", "fieldname": "more_info",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"label": "Source", "label": "More Information",
"oldfieldtype": "Section Break", "oldfieldtype": "Section Break",
"options": "fa fa-file-text" "options": "fa fa-file-text"
}, },
@ -424,7 +424,7 @@
"icon": "fa fa-info-sign", "icon": "fa fa-info-sign",
"idx": 195, "idx": 195,
"links": [], "links": [],
"modified": "2020-07-14 16:49:15.888503", "modified": "2020-08-11 17:34:35.066961",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "CRM", "module": "CRM",
"name": "Opportunity", "name": "Opportunity",

View File

@ -119,6 +119,14 @@ class Opportunity(TransactionBase):
and q.status not in ('Lost', 'Closed')""", self.name) and q.status not in ('Lost', 'Closed')""", self.name)
def has_ordered_quotation(self): def has_ordered_quotation(self):
if not self.with_items:
return frappe.get_all('Quotation',
{
'opportunity': self.name,
'status': 'Ordered',
'docstatus': 1
}, 'name')
else:
return frappe.db.sql(""" return frappe.db.sql("""
select q.name select q.name
from `tabQuotation` q, `tabQuotation Item` qi from `tabQuotation` q, `tabQuotation Item` qi
@ -330,7 +338,7 @@ def make_opportunity_from_communication(communication, ignore_communication_link
opportunity = frappe.get_doc({ opportunity = frappe.get_doc({
"doctype": "Opportunity", "doctype": "Opportunity",
"opportunity_from": opportunity_from, "opportunity_from": opportunity_from,
"lead": lead "party_name": lead
}).insert(ignore_permissions=True) }).insert(ignore_permissions=True)
link_communication_to_document(doc, "Opportunity", opportunity.name, ignore_communication_links) link_communication_to_document(doc, "Opportunity", opportunity.name, ignore_communication_links)

View File

@ -0,0 +1,31 @@
{
"based_on": "",
"chart_name": "Course wise Enrollment",
"chart_type": "Group By",
"creation": "2020-07-23 18:24:38.214220",
"docstatus": 0,
"doctype": "Dashboard Chart",
"document_type": "Course Enrollment",
"dynamic_filters_json": "[]",
"filters_json": "[[\"Course Enrollment\",\"enrollment_date\",\"Timespan\",\"this year\",false]]",
"group_by_based_on": "course",
"group_by_type": "Count",
"idx": 0,
"is_public": 1,
"is_standard": 1,
"last_synced_on": "2020-07-27 17:50:32.490587",
"modified": "2020-07-27 17:54:09.829206",
"modified_by": "Administrator",
"module": "Education",
"name": "Course wise Enrollment",
"number_of_groups": 0,
"owner": "Administrator",
"source": "",
"time_interval": "Yearly",
"timeseries": 0,
"timespan": "Last Year",
"type": "Percentage",
"use_report_chart": 0,
"value_based_on": "",
"y_axis": []
}

View File

@ -0,0 +1,31 @@
{
"based_on": "",
"chart_name": "Course wise Student Count",
"chart_type": "Group By",
"creation": "2020-07-27 17:24:39.136163",
"docstatus": 0,
"doctype": "Dashboard Chart",
"document_type": "Course Enrollment",
"dynamic_filters_json": "[]",
"filters_json": "[[\"Course Enrollment\",\"enrollment_date\",\"Timespan\",\"this year\",false]]",
"group_by_based_on": "course",
"group_by_type": "Count",
"idx": 0,
"is_public": 1,
"is_standard": 1,
"last_synced_on": "2020-07-27 17:24:56.184236",
"modified": "2020-07-27 17:25:46.232846",
"modified_by": "Administrator",
"module": "Education",
"name": "Course wise Student Count",
"number_of_groups": 0,
"owner": "Administrator",
"source": "",
"time_interval": "Yearly",
"timeseries": 0,
"timespan": "Last Year",
"type": "Donut",
"use_report_chart": 0,
"value_based_on": "",
"y_axis": []
}

View File

@ -0,0 +1,31 @@
{
"based_on": "",
"chart_name": "Instructor Gender Diversity Ratio",
"chart_type": "Group By",
"creation": "2020-07-23 18:35:02.544019",
"docstatus": 0,
"doctype": "Dashboard Chart",
"document_type": "Instructor",
"dynamic_filters_json": "[]",
"filters_json": "[[\"Instructor\",\"status\",\"=\",\"Active\",false]]",
"group_by_based_on": "gender",
"group_by_type": "Count",
"idx": 0,
"is_public": 1,
"is_standard": 1,
"last_synced_on": "2020-07-27 17:50:32.783820",
"modified": "2020-07-27 17:55:41.595260",
"modified_by": "Administrator",
"module": "Education",
"name": "Instructor Gender Diversity Ratio",
"number_of_groups": 0,
"owner": "Administrator",
"source": "",
"time_interval": "Yearly",
"timeseries": 0,
"timespan": "Last Year",
"type": "Donut",
"use_report_chart": 0,
"value_based_on": "",
"y_axis": []
}

View File

@ -0,0 +1,30 @@
{
"based_on": "enrollment_date",
"chart_name": "Program Enrollments",
"chart_type": "Count",
"creation": "2020-07-23 18:27:53.641616",
"docstatus": 0,
"doctype": "Dashboard Chart",
"document_type": "Program Enrollment",
"dynamic_filters_json": "[]",
"filters_json": "[[\"Program Enrollment\",\"docstatus\",\"=\",\"1\",false]]",
"group_by_type": "Count",
"idx": 0,
"is_public": 1,
"is_standard": 1,
"last_synced_on": "2020-07-27 17:50:32.203069",
"modified": "2020-07-27 17:51:59.022909",
"modified_by": "Administrator",
"module": "Education",
"name": "Program Enrollments",
"number_of_groups": 0,
"owner": "Administrator",
"source": "",
"time_interval": "Daily",
"timeseries": 1,
"timespan": "Last Month",
"type": "Line",
"use_report_chart": 0,
"value_based_on": "",
"y_axis": []
}

View File

@ -0,0 +1,31 @@
{
"based_on": "",
"chart_name": "Program wise Enrollment",
"chart_type": "Group By",
"creation": "2020-07-23 18:23:45.192748",
"docstatus": 0,
"doctype": "Dashboard Chart",
"document_type": "Program Enrollment",
"dynamic_filters_json": "[]",
"filters_json": "[[\"Program Enrollment\",\"docstatus\",\"=\",\"1\",false],[\"Program Enrollment\",\"enrollment_date\",\"Timespan\",\"this year\",false]]",
"group_by_based_on": "program",
"group_by_type": "Count",
"idx": 0,
"is_public": 1,
"is_standard": 1,
"last_synced_on": "2020-07-27 17:50:32.629321",
"modified": "2020-07-27 17:53:36.269098",
"modified_by": "Administrator",
"module": "Education",
"name": "Program wise Enrollment",
"number_of_groups": 0,
"owner": "Administrator",
"source": "",
"time_interval": "Yearly",
"timeseries": 0,
"timespan": "Last Year",
"type": "Percentage",
"use_report_chart": 0,
"value_based_on": "",
"y_axis": []
}

View File

@ -0,0 +1,28 @@
{
"chart_name": "Program wise Fee Collection",
"chart_type": "Report",
"creation": "2020-08-05 16:19:53.398335",
"custom_options": "",
"docstatus": 0,
"doctype": "Dashboard Chart",
"dynamic_filters_json": "{\"from_date\":\"frappe.datetime.add_months(frappe.datetime.get_today(), -1)\",\"to_date\":\"frappe.datetime.nowdate()\"}",
"filters_json": "{}",
"group_by_type": "Count",
"idx": 0,
"is_public": 1,
"is_standard": 1,
"modified": "2020-08-05 16:20:47.436847",
"modified_by": "Administrator",
"module": "Education",
"name": "Program wise Fee Collection",
"number_of_groups": 0,
"owner": "Administrator",
"report_name": "Program wise Fee Collection",
"time_interval": "Yearly",
"timeseries": 0,
"timespan": "Last Year",
"type": "Bar",
"use_report_chart": 1,
"x_field": "",
"y_axis": []
}

View File

@ -0,0 +1,31 @@
{
"based_on": "",
"chart_name": "Student Category wise Program Enrollments",
"chart_type": "Group By",
"creation": "2020-07-27 17:37:47.116446",
"docstatus": 0,
"doctype": "Dashboard Chart",
"document_type": "Program Enrollment",
"dynamic_filters_json": "[]",
"filters_json": "[[\"Program Enrollment\",\"enrollment_date\",\"Timespan\",\"this year\",false],[\"Program Enrollment\",\"docstatus\",\"=\",\"1\",false]]",
"group_by_based_on": "student_category",
"group_by_type": "Count",
"idx": 0,
"is_public": 1,
"is_standard": 1,
"last_synced_on": "2020-07-27 17:46:54.901911",
"modified": "2020-07-27 17:47:21.370866",
"modified_by": "Administrator",
"module": "Education",
"name": "Student Category wise Program Enrollments",
"number_of_groups": 0,
"owner": "Administrator",
"source": "",
"time_interval": "Yearly",
"timeseries": 0,
"timespan": "Last Year",
"type": "Donut",
"use_report_chart": 0,
"value_based_on": "",
"y_axis": []
}

View File

@ -0,0 +1,30 @@
{
"based_on": "",
"chart_name": "Student Gender Diversity Ratio",
"chart_type": "Group By",
"creation": "2020-07-23 18:12:15.972123",
"docstatus": 0,
"doctype": "Dashboard Chart",
"document_type": "Student",
"dynamic_filters_json": "[]",
"filters_json": "[[\"Student\",\"enabled\",\"=\",1,false]]",
"group_by_based_on": "gender",
"group_by_type": "Count",
"idx": 0,
"is_public": 1,
"is_standard": 1,
"modified": "2020-07-23 18:12:21.606772",
"modified_by": "Administrator",
"module": "Education",
"name": "Student Gender Diversity Ratio",
"number_of_groups": 0,
"owner": "Administrator",
"source": "",
"time_interval": "Yearly",
"timeseries": 0,
"timespan": "Last Year",
"type": "Donut",
"use_report_chart": 0,
"value_based_on": "",
"y_axis": []
}

View File

@ -2,18 +2,13 @@
"cards": [ "cards": [
{ {
"hidden": 0, "hidden": 0,
"label": "Tools", "label": "Student and Instructor",
"links": "[\n {\n \"label\": \"Student Attendance Tool\",\n \"name\": \"Student Attendance Tool\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Assessment Result Tool\",\n \"name\": \"Assessment Result Tool\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Student Group Creation Tool\",\n \"name\": \"Student Group Creation Tool\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Program Enrollment Tool\",\n \"name\": \"Program Enrollment Tool\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Course Scheduling Tool\",\n \"name\": \"Course Scheduling Tool\",\n \"type\": \"doctype\"\n }\n]" "links": "[\n {\n \"label\": \"Student\",\n \"name\": \"Student\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Instructor\",\n \"name\": \"Instructor\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Guardian\",\n \"name\": \"Guardian\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Student Group\",\n \"name\": \"Student Group\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Student Log\",\n \"name\": \"Student Log\",\n \"type\": \"doctype\"\n }\n]"
}, },
{ {
"hidden": 0, "hidden": 0,
"label": "Other Reports", "label": "Masters",
"links": "[\n {\n \"dependencies\": [\n \"Program Enrollment\"\n ],\n \"doctype\": \"Program Enrollment\",\n \"is_query_report\": true,\n \"label\": \"Student and Guardian Contact Details\",\n \"name\": \"Student and Guardian Contact Details\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Student Attendance\"\n ],\n \"doctype\": \"Student Attendance\",\n \"is_query_report\": true,\n \"label\": \"Student Monthly Attendance Sheet\",\n \"name\": \"Student Monthly Attendance Sheet\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Fees\"\n ],\n \"doctype\": \"Fees\",\n \"is_query_report\": true,\n \"label\": \"Student Fee Collection\",\n \"name\": \"Student Fee Collection\",\n \"type\": \"report\"\n }\n]" "links": "[\n {\n \"label\": \"Program\",\n \"name\": \"Program\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Course\",\n \"name\": \"Course\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Topic\",\n \"name\": \"Topic\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Room\",\n \"name\": \"Room\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n }\n]"
},
{
"hidden": 0,
"label": "Settings",
"links": "[\n {\n \"label\": \"Student Category\",\n \"name\": \"Student Category\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Student Batch Name\",\n \"name\": \"Student Batch Name\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Grading Scale\",\n \"name\": \"Grading Scale\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Academic Term\",\n \"name\": \"Academic Term\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Academic Year\",\n \"name\": \"Academic Year\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Education Settings\",\n \"name\": \"Education Settings\",\n \"type\": \"doctype\"\n }\n]"
}, },
{ {
"hidden": 0, "hidden": 0,
@ -22,33 +17,18 @@
}, },
{ {
"hidden": 0, "hidden": 0,
"label": "Attendance", "label": "Settings",
"links": "[\n {\n \"label\": \"Student Attendance\",\n \"name\": \"Student Attendance\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Student Leave Application\",\n \"name\": \"Student Leave Application\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Student Attendance\"\n ],\n \"doctype\": \"Student Attendance\",\n \"is_query_report\": true,\n \"label\": \"Absent Student Report\",\n \"name\": \"Absent Student Report\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Student Attendance\"\n ],\n \"doctype\": \"Student Attendance\",\n \"is_query_report\": true,\n \"label\": \"Student Batch-Wise Attendance\",\n \"name\": \"Student Batch-Wise Attendance\",\n \"type\": \"report\"\n }\n]" "links": "[\n {\n \"label\": \"Education Settings\",\n \"name\": \"Education Settings\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Student Category\",\n \"name\": \"Student Category\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Student Batch Name\",\n \"name\": \"Student Batch Name\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Grading Scale\",\n \"name\": \"Grading Scale\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Academic Term\",\n \"name\": \"Academic Term\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Academic Year\",\n \"name\": \"Academic Year\",\n \"type\": \"doctype\"\n }\n]"
}, },
{ {
"hidden": 0, "hidden": 0,
"label": "Admission", "label": "Admission",
"links": "[\n {\n \"label\": \"Student Applicant\",\n \"name\": \"Student Applicant\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Student Admission\",\n \"name\": \"Student Admission\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Program Enrollment\",\n \"name\": \"Program Enrollment\",\n \"type\": \"doctype\"\n }\n]" "links": "[\n {\n \"label\": \"Student Applicant\",\n \"name\": \"Student Applicant\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Student Admission\",\n \"name\": \"Student Admission\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Program Enrollment\",\n \"name\": \"Program Enrollment\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Course Enrollment\",\n \"name\": \"Course Enrollment\",\n \"type\": \"doctype\"\n }\n]"
}, },
{ {
"hidden": 0, "hidden": 0,
"label": "Assessment", "label": "Fees",
"links": "[\n {\n \"label\": \"Assessment Plan\",\n \"name\": \"Assessment Plan\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Assessment Group\",\n \"link\": \"Tree/Assessment Group\",\n \"name\": \"Assessment Group\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Assessment Result\",\n \"name\": \"Assessment Result\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Assessment Criteria\",\n \"name\": \"Assessment Criteria\",\n \"type\": \"doctype\"\n }\n]" "links": "[\n {\n \"label\": \"Fee Structure\",\n \"name\": \"Fee Structure\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Fee Category\",\n \"name\": \"Fee Category\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Fee Schedule\",\n \"name\": \"Fee Schedule\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Fees\",\n \"name\": \"Fees\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Fees\"\n ],\n \"doctype\": \"Fees\",\n \"is_query_report\": true,\n \"label\": \"Student Fee Collection Report\",\n \"name\": \"Student Fee Collection\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Fees\"\n ],\n \"doctype\": \"Fees\",\n \"is_query_report\": true,\n \"label\": \"Program wise Fee Collection Report\",\n \"name\": \"Program wise Fee Collection\",\n \"type\": \"report\"\n }\n]"
},
{
"hidden": 0,
"label": "Student",
"links": "[\n {\n \"label\": \"Student\",\n \"name\": \"Student\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Guardian\",\n \"name\": \"Guardian\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Student Log\",\n \"name\": \"Student Log\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Student Group\",\n \"name\": \"Student Group\",\n \"type\": \"doctype\"\n }\n]"
},
{
"hidden": 0,
"label": "Masters",
"links": "[\n {\n \"label\": \"Program\",\n \"name\": \"Program\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Course\",\n \"name\": \"Course\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Topic\",\n \"name\": \"Topic\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Instructor\",\n \"name\": \"Instructor\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Room\",\n \"name\": \"Room\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n }\n]"
},
{
"hidden": 0,
"label": "LMS Activity",
"links": "[\n {\n \"label\": \"Course Enrollment\",\n \"name\": \"Course Enrollment\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Course Activity\",\n \"name\": \"Course Activity\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Quiz Activity\",\n \"name\": \"Quiz Activity\",\n \"type\": \"doctype\"\n }\n]"
}, },
{ {
"hidden": 0, "hidden": 0,
@ -57,8 +37,18 @@
}, },
{ {
"hidden": 0, "hidden": 0,
"label": "Fees", "label": "Attendance",
"links": "[\n {\n \"label\": \"Fees\",\n \"name\": \"Fees\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Fee Schedule\",\n \"name\": \"Fee Schedule\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Fee Structure\",\n \"name\": \"Fee Structure\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Fee Category\",\n \"name\": \"Fee Category\",\n \"type\": \"doctype\"\n }\n]" "links": "[\n {\n \"label\": \"Student Attendance\",\n \"name\": \"Student Attendance\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Student Leave Application\",\n \"name\": \"Student Leave Application\",\n \"type\": \"doctype\"\n },\n {\n \"dependencies\": [\n \"Student Attendance\"\n ],\n \"doctype\": \"Student Attendance\",\n \"is_query_report\": true,\n \"label\": \"Student Monthly Attendance Sheet\",\n \"name\": \"Student Monthly Attendance Sheet\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Student Attendance\"\n ],\n \"doctype\": \"Student Attendance\",\n \"is_query_report\": true,\n \"label\": \"Absent Student Report\",\n \"name\": \"Absent Student Report\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Student Attendance\"\n ],\n \"doctype\": \"Student Attendance\",\n \"is_query_report\": true,\n \"label\": \"Student Batch-Wise Attendance\",\n \"name\": \"Student Batch-Wise Attendance\",\n \"type\": \"report\"\n }\n]"
},
{
"hidden": 0,
"label": "LMS Activity",
"links": "[\n {\n \"label\": \"Course Enrollment\",\n \"name\": \"Course Enrollment\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Course Activity\",\n \"name\": \"Course Activity\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Quiz Activity\",\n \"name\": \"Quiz Activity\",\n \"type\": \"doctype\"\n }\n]"
},
{
"hidden": 0,
"label": "Assessment",
"links": "[\n {\n \"label\": \"Assessment Plan\",\n \"name\": \"Assessment Plan\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Assessment Group\",\n \"link\": \"Tree/Assessment Group\",\n \"name\": \"Assessment Group\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Assessment Result\",\n \"name\": \"Assessment Result\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Assessment Criteria\",\n \"name\": \"Assessment Criteria\",\n \"type\": \"doctype\"\n }\n]"
}, },
{ {
"hidden": 0, "hidden": 0,
@ -67,28 +57,98 @@
}, },
{ {
"hidden": 0, "hidden": 0,
"label": "Reports", "label": "Tools",
"links": "[\n {\n \"dependencies\": [\n \"Fees\"\n ],\n \"doctype\": \"Fees\",\n \"is_query_report\": true,\n \"label\": \"Student Fee Collection\",\n \"name\": \"Student Fee Collection\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Student Attendance\"\n ],\n \"doctype\": \"Student Attendance\",\n \"is_query_report\": true,\n \"label\": \"Student Monthly Attendance Sheet\",\n \"name\": \"Student Monthly Attendance Sheet\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Student Attendance\"\n ],\n \"doctype\": \"Student Attendance\",\n \"is_query_report\": true,\n \"label\": \"Absent Student Report\",\n \"name\": \"Absent Student Report\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Program Enrollment\"\n ],\n \"doctype\": \"Program Enrollment\",\n \"is_query_report\": true,\n \"label\": \"Student and Guardian Contact Details\",\n \"name\": \"Student and Guardian Contact Details\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Student Attendance\"\n ],\n \"doctype\": \"Student Attendance\",\n \"is_query_report\": true,\n \"label\": \"Student Batch-Wise Attendance\",\n \"name\": \"Student Batch-Wise Attendance\",\n \"type\": \"report\"\n }\n]" "links": "[\n {\n \"label\": \"Student Attendance Tool\",\n \"name\": \"Student Attendance Tool\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Assessment Result Tool\",\n \"name\": \"Assessment Result Tool\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Student Group Creation Tool\",\n \"name\": \"Student Group Creation Tool\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Program Enrollment Tool\",\n \"name\": \"Program Enrollment Tool\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Course Scheduling Tool\",\n \"name\": \"Course Scheduling Tool\",\n \"type\": \"doctype\"\n }\n]"
},
{
"hidden": 0,
"label": "Other Reports",
"links": "[\n {\n \"dependencies\": [\n \"Program Enrollment\"\n ],\n \"doctype\": \"Program Enrollment\",\n \"is_query_report\": true,\n \"label\": \"Student and Guardian Contact Details\",\n \"name\": \"Student and Guardian Contact Details\",\n \"type\": \"report\"\n }\n]"
} }
], ],
"category": "Domains", "category": "Domains",
"charts": [], "charts": [
{
"chart_name": "Program Enrollments",
"label": "Program Enrollments"
}
],
"creation": "2020-03-02 17:22:57.066401", "creation": "2020-03-02 17:22:57.066401",
"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,
"hide_custom": 0,
"idx": 0, "idx": 0,
"is_standard": 1, "is_standard": 1,
"label": "Education", "label": "Education",
"modified": "2020-05-22 01:09:13.058482", "modified": "2020-07-27 19:35:18.832694",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Education", "module": "Education",
"name": "Education", "name": "Education",
"onboarding": "Education",
"owner": "Administrator", "owner": "Administrator",
"pin_to_bottom": 0, "pin_to_bottom": 0,
"pin_to_top": 0, "pin_to_top": 0,
"restrict_to_domain": "Education", "restrict_to_domain": "Education",
"shortcuts": [] "shortcuts": [
{
"color": "#cef6d1",
"format": "{} Active",
"label": "Student",
"link_to": "Student",
"stats_filter": "{\n \"enabled\": 1\n}",
"type": "DocType"
},
{
"color": "#cef6d1",
"format": "{} Active",
"label": "Instructor",
"link_to": "Instructor",
"stats_filter": "{\n \"status\": \"Active\"\n}",
"type": "DocType"
},
{
"color": "",
"format": "",
"label": "Program",
"link_to": "Program",
"stats_filter": "",
"type": "DocType"
},
{
"label": "Course",
"link_to": "Course",
"type": "DocType"
},
{
"color": "#ffe8cd",
"format": "{} Unpaid",
"label": "Fees",
"link_to": "Fees",
"stats_filter": "{\n \"outstanding_amount\": [\"!=\", 0.0]\n}",
"type": "DocType"
},
{
"label": "Student Monthly Attendance Sheet",
"link_to": "Student Monthly Attendance Sheet",
"type": "Report"
},
{
"label": "Course Scheduling Tool",
"link_to": "Course Scheduling Tool",
"type": "DocType"
},
{
"label": "Student Attendance Tool",
"link_to": "Student Attendance Tool",
"type": "DocType"
},
{
"label": "Dashboard",
"link_to": "Education",
"type": "Dashboard"
}
]
} }

View File

@ -6,10 +6,11 @@ frappe.ui.form.on('Assessment Result', {
if (!frm.doc.__islocal) { if (!frm.doc.__islocal) {
frm.trigger('setup_chart'); frm.trigger('setup_chart');
} }
frm.set_df_property('details', 'read_only', 1);
}, },
onload: function(frm) { onload: function(frm) {
frm.set_query('assessment_plan', function(){ frm.set_query('assessment_plan', function() {
return { return {
filters: { filters: {
docstatus: 1 docstatus: 1
@ -27,14 +28,14 @@ frappe.ui.form.on('Assessment Result', {
}, },
callback: function(r) { callback: function(r) {
if (r.message) { if (r.message) {
frm.doc.details = []; frappe.model.clear_table(frm.doc, 'details');
$.each(r.message, function(i, d) { $.each(r.message, function(i, d) {
var row = frappe.model.add_child(frm.doc, 'Assessment Result Detail', 'details'); var row = frm.add_child('details');
row.assessment_criteria = d.assessment_criteria; row.assessment_criteria = d.assessment_criteria;
row.maximum_score = d.maximum_score; row.maximum_score = d.maximum_score;
}); });
frm.refresh_field('details');
} }
refresh_field('details');
} }
}); });
} }
@ -80,7 +81,7 @@ frappe.ui.form.on('Assessment Result Detail', {
score: function(frm, cdt, cdn) { score: function(frm, cdt, cdn) {
var d = locals[cdt][cdn]; var d = locals[cdt][cdn];
if(!d.maximum_score || !frm.doc.grading_scale) { if (!d.maximum_score || !frm.doc.grading_scale) {
d.score = ''; d.score = '';
frappe.throw(__('Please fill in all the details to generate Assessment Result.')); frappe.throw(__('Please fill in all the details to generate Assessment Result.'));
} }

View File

@ -1,724 +1,182 @@
{ {
"allow_copy": 0, "actions": [],
"allow_guest_to_view": 0,
"allow_import": 1, "allow_import": 1,
"allow_rename": 0,
"autoname": "EDU-RES-.YYYY.-.#####", "autoname": "EDU-RES-.YYYY.-.#####",
"beta": 0,
"creation": "2015-11-13 17:18:06.468332", "creation": "2015-11-13 17:18:06.468332",
"custom": 0,
"docstatus": 0,
"doctype": "DocType", "doctype": "DocType",
"document_type": "",
"editable_grid": 1, "editable_grid": 1,
"engine": "InnoDB", "engine": "InnoDB",
"field_order": [
"assessment_plan",
"program",
"course",
"academic_year",
"academic_term",
"column_break_3",
"student",
"student_name",
"student_group",
"assessment_group",
"grading_scale",
"section_break_5",
"details",
"section_break_8",
"maximum_score",
"column_break_11",
"total_score",
"grade",
"section_break_13",
"comment",
"amended_from"
],
"fields": [ "fields": [
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "assessment_plan", "fieldname": "assessment_plan",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0,
"label": "Assessment Plan", "label": "Assessment Plan",
"length": 0,
"no_copy": 0,
"options": "Assessment Plan", "options": "Assessment Plan",
"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": "assessment_plan.program", "fetch_from": "assessment_plan.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": 0,
"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": "assessment_plan.course", "fetch_from": "assessment_plan.course",
"fieldname": "course", "fieldname": "course",
"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": "Course", "label": "Course",
"length": 0, "options": "Course"
"no_copy": 0,
"options": "Course",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"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": "assessment_plan.academic_year", "fetch_from": "assessment_plan.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": "assessment_plan.academic_term", "fetch_from": "assessment_plan.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,
"columns": 0,
"fieldname": "column_break_3", "fieldname": "column_break_3",
"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": "student", "fieldname": "student",
"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": "Student", "label": "Student",
"length": 0,
"no_copy": 0,
"options": "Student", "options": "Student",
"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.title", "fetch_from": "student.title",
"fieldname": "student_name", "fieldname": "student_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": 1, "in_list_view": 1,
"in_standard_filter": 0,
"label": "Student Name", "label": "Student 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,
"fetch_from": "assessment_plan.student_group", "fetch_from": "assessment_plan.student_group",
"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": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Student Group", "label": "Student Group",
"length": 0, "options": "Student Group"
"no_copy": 0,
"options": "Student Group",
"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": "assessment_plan.assessment_group", "fetch_from": "assessment_plan.assessment_group",
"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": 0,
"label": "Assessment Group", "label": "Assessment Group",
"length": 0, "options": "Assessment Group"
"no_copy": 0,
"options": "Assessment Group",
"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": "assessment_plan.grading_scale", "fetch_from": "assessment_plan.grading_scale",
"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": 0,
"label": "Grading Scale", "label": "Grading Scale",
"length": 0,
"no_copy": 0,
"options": "Grading Scale", "options": "Grading Scale",
"permlevel": 0, "read_only": 1
"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_5", "fieldname": "section_break_5",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "label": "Result"
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Result",
"length": 0,
"no_copy": 0,
"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,
"depends_on": "",
"fieldname": "details", "fieldname": "details",
"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": "Details", "label": "Details",
"length": 0,
"no_copy": 0,
"options": "Assessment Result Detail", "options": "Assessment Result Detail",
"permlevel": 0, "reqd": 1
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "section_break_8", "fieldname": "section_break_8",
"fieldtype": "Section Break", "fieldtype": "Section Break"
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_from": "assessment_plan.maximum_assessment_score", "fetch_from": "assessment_plan.maximum_assessment_score",
"fieldname": "maximum_score", "fieldname": "maximum_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 Score", "label": "Maximum Score",
"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,
"fetch_from": "assessment_plan.maximum_assessment_score", "fetch_from": "assessment_plan.maximum_assessment_score",
"fieldname": "column_break_11", "fieldname": "column_break_11",
"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": "total_score", "fieldname": "total_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": 1, "in_list_view": 1,
"in_standard_filter": 0,
"label": "Total Score", "label": "Total Score",
"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": "grade", "fieldname": "grade",
"fieldtype": "Data", "fieldtype": "Data",
"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": "Grade", "label": "Grade",
"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_13", "fieldname": "section_break_13",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "label": "Summary"
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Summary",
"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": "comment", "fieldname": "comment",
"fieldtype": "Small Text", "fieldtype": "Small Text",
"hidden": 0, "label": "Comment"
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Comment",
"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": "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 Result", "options": "Assessment Result",
"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-08-03 11:47:54.119486",
"max_attachments": 0,
"modified": "2018-08-30 02:10:36.813413",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Education", "module": "Education",
"name": "Assessment Result", "name": "Assessment Result",
"name_case": "",
"owner": "Administrator", "owner": "Administrator",
"permissions": [ "permissions": [
{ {
@ -728,28 +186,18 @@
"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": 1, "show_name_in_global_search": 1,
"sort_field": "modified", "sort_field": "modified",
"sort_order": "DESC", "sort_order": "DESC",
"title_field": "student_name", "title_field": "student_name"
"track_changes": 0,
"track_seen": 0,
"track_views": 0
} }

View File

@ -1,194 +1,66 @@
{ {
"allow_copy": 0, "actions": [],
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"autoname": "",
"beta": 0,
"creation": "2016-12-14 17:44:35.583123", "creation": "2016-12-14 17:44:35.583123",
"custom": 0,
"docstatus": 0,
"doctype": "DocType", "doctype": "DocType",
"document_type": "",
"editable_grid": 1, "editable_grid": 1,
"engine": "InnoDB", "engine": "InnoDB",
"field_order": [
"assessment_criteria",
"maximum_score",
"column_break_2",
"score",
"grade"
],
"fields": [ "fields": [
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 4, "columns": 4,
"fieldname": "assessment_criteria", "fieldname": "assessment_criteria",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0,
"label": "Assessment Criteria", "label": "Assessment Criteria",
"length": 0,
"no_copy": 0,
"options": "Assessment Criteria", "options": "Assessment Criteria",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1, "read_only": 1,
"remember_last_selected_value": 0, "reqd": 1
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 2, "columns": 2,
"fieldname": "maximum_score", "fieldname": "maximum_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": 1, "in_list_view": 1,
"in_standard_filter": 0,
"label": "Maximum Score", "label": "Maximum Score",
"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,
"unique": 0
}, },
{ {
"allow_bulk_edit": 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,
"label": "",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 2, "columns": 2,
"fieldname": "score", "fieldname": "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": 1, "in_list_view": 1,
"in_standard_filter": 0,
"label": "Score", "label": "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,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 2, "columns": 2,
"fieldname": "grade", "fieldname": "grade",
"fieldtype": "Data", "fieldtype": "Data",
"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": "Grade", "label": "Grade",
"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,
"unique": 0
} }
], ],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1, "istable": 1,
"max_attachments": 0, "links": [],
"modified": "2017-11-10 19:11:14.362410", "modified": "2020-07-31 13:27:17.699022",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Education", "module": "Education",
"name": "Assessment Result Detail", "name": "Assessment Result Detail",
"name_case": "",
"owner": "Administrator", "owner": "Administrator",
"permissions": [], "permissions": [],
"quick_entry": 1, "quick_entry": 1,
"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"
"track_changes": 0,
"track_seen": 0
} }

View File

@ -160,7 +160,8 @@
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 1, "in_standard_filter": 1,
"label": "Program", "label": "Program",
"options": "Program" "options": "Program",
"reqd": 1
}, },
{ {
"fieldname": "student_batch", "fieldname": "student_batch",
@ -339,7 +340,7 @@
], ],
"is_submittable": 1, "is_submittable": 1,
"links": [], "links": [],
"modified": "2020-07-18 05:00:00.621010", "modified": "2020-08-05 14:05:47.728409",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Education", "module": "Education",
"name": "Fees", "name": "Fees",

View File

@ -7,7 +7,7 @@ import frappe
import unittest import unittest
from frappe.utils import nowdate from frappe.utils import nowdate
from frappe.utils.make_random import get_random from frappe.utils.make_random import get_random
from erpnext.education.doctype.program.test_program import make_program_and_linked_courses
# test_records = frappe.get_test_records('Fees') # test_records = frappe.get_test_records('Fees')
@ -15,6 +15,7 @@ class TestFees(unittest.TestCase):
def test_fees(self): def test_fees(self):
student = get_random("Student") student = get_random("Student")
program = make_program_and_linked_courses("_Test Program 1", ["_Test Course 1", "_Test Course 2"])
fee = frappe.new_doc("Fees") fee = frappe.new_doc("Fees")
fee.posting_date = nowdate() fee.posting_date = nowdate()
fee.due_date = nowdate() fee.due_date = nowdate()
@ -23,6 +24,7 @@ class TestFees(unittest.TestCase):
fee.income_account = "Sales - _TC" fee.income_account = "Sales - _TC"
fee.cost_center = "_Test Cost Center - _TC" fee.cost_center = "_Test Cost Center - _TC"
fee.company = "_Test Company" fee.company = "_Test Company"
fee.program = program.name
fee.extend("components", [ fee.extend("components", [
{ {

View File

@ -1,348 +1,125 @@
{ {
"allow_copy": 0, "actions": [],
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 1, "allow_import": 1,
"allow_rename": 0,
"autoname": "naming_series:", "autoname": "naming_series:",
"beta": 0,
"creation": "2015-11-04 15:56:30.004034", "creation": "2015-11-04 15:56:30.004034",
"custom": 0,
"docstatus": 0,
"doctype": "DocType", "doctype": "DocType",
"document_type": "Other", "document_type": "Other",
"editable_grid": 0,
"engine": "InnoDB", "engine": "InnoDB",
"field_order": [
"instructor_name",
"employee",
"gender",
"column_break_5",
"status",
"naming_series",
"department",
"image",
"log_details",
"instructor_log"
],
"fields": [ "fields": [
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "instructor_name", "fieldname": "instructor_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": "Instructor Name", "label": "Instructor Name",
"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": "employee", "fieldname": "employee",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0,
"label": "Employee", "label": "Employee",
"length": 0, "options": "Employee"
"no_copy": 0,
"options": "Employee",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_5", "fieldname": "column_break_5",
"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,
"default": "",
"fieldname": "naming_series", "fieldname": "naming_series",
"fieldtype": "Select", "fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Naming Series", "label": "Naming Series",
"length": 0,
"no_copy": 0,
"options": "EDU-INS-.YYYY.-", "options": "EDU-INS-.YYYY.-",
"permlevel": 0, "set_only_once": 1
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 1,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_from": "employee.department", "fetch_from": "employee.department",
"fieldname": "department", "fieldname": "department",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 1, "in_standard_filter": 1,
"label": "Department", "label": "Department",
"length": 0, "options": "Department"
"no_copy": 0,
"options": "Department",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "image", "fieldname": "image",
"fieldtype": "Attach Image", "fieldtype": "Attach Image",
"hidden": 1, "hidden": 1,
"ignore_user_permissions": 0, "label": "Image"
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Image",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "log_details", "fieldname": "log_details",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "label": "Instructor Log"
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Instructor Log",
"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": "instructor_log", "fieldname": "instructor_log",
"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": "Instructor Log", "label": "Instructor Log",
"length": 0, "options": "Instructor Log"
"no_copy": 0, },
"options": "Instructor Log", {
"permlevel": 0, "default": "Active",
"precision": "", "fieldname": "status",
"print_hide": 0, "fieldtype": "Select",
"print_hide_if_no_value": 0, "in_list_view": 1,
"read_only": 0, "in_standard_filter": 1,
"remember_last_selected_value": 0, "label": "Status",
"report_hide": 0, "options": "Active\nLeft"
"reqd": 0, },
"search_index": 0, {
"set_only_once": 0, "fetch_from": "employee.gender",
"translatable": 0, "fieldname": "gender",
"unique": 0 "fieldtype": "Link",
"label": "Gender",
"options": "Gender",
"read_only_depends_on": "employee"
} }
], ],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_field": "image", "image_field": "image",
"image_view": 0, "links": [],
"in_create": 0, "modified": "2020-07-23 18:33:57.904398",
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
"modified": "2019-01-30 11:28:17.571207",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Education", "module": "Education",
"name": "Instructor", "name": "Instructor",
"name_case": "",
"owner": "Administrator", "owner": "Administrator",
"permissions": [ "permissions": [
{ {
"amend": 0,
"cancel": 0,
"create": 0,
"delete": 0,
"email": 1, "email": 1,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1, "print": 1,
"read": 1, "read": 1,
"report": 1, "report": 1,
"role": "Instructor", "role": "Instructor"
"set_user_permissions": 0,
"share": 0,
"submit": 0,
"write": 0
}, },
{ {
"amend": 0,
"cancel": 0,
"create": 1, "create": 1,
"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": "Education Manager", "role": "Education Manager",
"set_user_permissions": 1, "set_user_permissions": 1,
"share": 1, "share": 1,
"submit": 0,
"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": 1, "show_name_in_global_search": 1,
"sort_field": "modified", "sort_field": "modified",
"sort_order": "DESC", "sort_order": "DESC",
"title_field": "instructor_name", "title_field": "instructor_name"
"track_changes": 0,
"track_seen": 0,
"track_views": 0
} }

View File

@ -97,6 +97,7 @@ class ProgramEnrollment(Document):
return quiz_progress return quiz_progress
@frappe.whitelist() @frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def get_program_courses(doctype, txt, searchfield, start, page_len, filters): def get_program_courses(doctype, txt, searchfield, start, page_len, filters):
if filters.get('program'): if filters.get('program'):
return frappe.db.sql("""select course, course_name from `tabProgram Course` return frappe.db.sql("""select course, course_name from `tabProgram Course`
@ -115,6 +116,7 @@ def get_program_courses(doctype, txt, searchfield, start, page_len, filters):
}) })
@frappe.whitelist() @frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def get_students(doctype, txt, searchfield, start, page_len, filters): def get_students(doctype, txt, searchfield, start, page_len, filters):
if not filters.get("academic_term"): if not filters.get("academic_term"):
filters["academic_term"] = frappe.defaults.get_defaults().academic_term filters["academic_term"] = frappe.defaults.get_defaults().academic_term

File diff suppressed because it is too large Load Diff

View File

@ -108,6 +108,7 @@ def get_program_enrollment(academic_year, academic_term=None, program=None, batc
@frappe.whitelist() @frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def fetch_students(doctype, txt, searchfield, start, page_len, filters): def fetch_students(doctype, txt, searchfield, start, page_len, filters):
if filters.get("group_based_on") != "Activity": if filters.get("group_based_on") != "Activity":
enrolled_students = get_program_enrollment(filters.get('academic_year'), filters.get('academic_term'), enrolled_students = get_program_enrollment(filters.get('academic_year'), filters.get('academic_term'),

View File

@ -0,0 +1,62 @@
{
"cards": [
{
"card": "Total Students"
},
{
"card": "Total Instructors"
},
{
"card": "Program Enrollments"
},
{
"card": "Student Applicants to Review"
}
],
"charts": [
{
"chart": "Program Enrollments",
"width": "Full"
},
{
"chart": "Program wise Enrollment",
"width": "Half"
},
{
"chart": "Course wise Enrollment",
"width": "Half"
},
{
"chart": "Course wise Student Count",
"width": "Half"
},
{
"chart": "Student Category wise Program Enrollments",
"width": "Half"
},
{
"chart": "Student Gender Diversity Ratio",
"width": "Half"
},
{
"chart": "Instructor Gender Diversity Ratio",
"width": "Half"
},
{
"chart": "Program wise Fee Collection",
"width": "Full"
}
],
"creation": "2020-07-22 18:51:02.195762",
"dashboard_name": "Education",
"docstatus": 0,
"doctype": "Dashboard",
"idx": 0,
"is_default": 0,
"is_standard": 1,
"modified": "2020-08-05 16:22:17.428101",
"modified_by": "Administrator",
"module": "Education",
"name": "Education",
"owner": "Administrator"
}

View File

@ -0,0 +1,50 @@
{
"allow_roles": [
{
"role": "Education Manager"
}
],
"creation": "2020-07-27 19:02:49.561391",
"docstatus": 0,
"doctype": "Module Onboarding",
"documentation_url": "https://docs.erpnext.com/docs/user/manual/en/education",
"idx": 0,
"is_complete": 0,
"modified": "2020-07-27 21:10:46.722961",
"modified_by": "Administrator",
"module": "Education",
"name": "Education",
"owner": "Administrator",
"steps": [
{
"step": "Create a Student"
},
{
"step": "Create an Instructor"
},
{
"step": "Introduction to Program and Courses"
},
{
"step": "Create a Topic"
},
{
"step": "Create a Course"
},
{
"step": "Create a Program"
},
{
"step": "Enroll a Student in a Program"
},
{
"step": "Introduction to Student Group"
},
{
"step": "Introduction to Student Attendance"
}
],
"subtitle": "Students, Instructors, Programs and more.",
"success_message": "The Education Module is all set up!",
"title": "Let's Set Up the Education Module."
}

View File

@ -0,0 +1,23 @@
{
"aggregate_function_based_on": "",
"creation": "2020-07-27 18:26:27.005186",
"docstatus": 0,
"doctype": "Number Card",
"document_type": "Program Enrollment",
"dynamic_filters_json": "[]",
"filters_json": "[[\"Program Enrollment\",\"docstatus\",\"=\",\"1\",false],[\"Program Enrollment\",\"enrollment_date\",\"Timespan\",\"this year\",false]]",
"function": "Count",
"idx": 0,
"is_public": 1,
"is_standard": 1,
"label": "Program Enrollments",
"modified": "2020-07-27 18:26:32.512624",
"modified_by": "Administrator",
"module": "Education",
"name": "Program Enrollments",
"owner": "Administrator",
"report_function": "Sum",
"show_percentage_stats": 1,
"stats_time_interval": "Yearly",
"type": "Document Type"
}

View File

@ -0,0 +1,23 @@
{
"aggregate_function_based_on": "",
"creation": "2020-07-27 18:42:33.366862",
"docstatus": 0,
"doctype": "Number Card",
"document_type": "Student Applicant",
"dynamic_filters_json": "[]",
"filters_json": "[[\"Student Applicant\",\"application_status\",\"=\",\"Applied\",false]]",
"function": "Count",
"idx": 0,
"is_public": 1,
"is_standard": 1,
"label": "Student Applicants to Review",
"modified": "2020-07-27 18:42:42.739710",
"modified_by": "Administrator",
"module": "Education",
"name": "Student Applicants to Review",
"owner": "Administrator",
"report_function": "Sum",
"show_percentage_stats": 1,
"stats_time_interval": "Monthly",
"type": "Document Type"
}

View File

@ -0,0 +1,23 @@
{
"aggregate_function_based_on": "",
"creation": "2020-07-23 14:19:38.423190",
"docstatus": 0,
"doctype": "Number Card",
"document_type": "Instructor",
"dynamic_filters_json": "[]",
"filters_json": "[[\"Instructor\",\"status\",\"=\",\"Active\",false]]",
"function": "Count",
"idx": 0,
"is_public": 1,
"is_standard": 1,
"label": "Total Instructors",
"modified": "2020-07-23 14:19:47.623306",
"modified_by": "Administrator",
"module": "Education",
"name": "Total Instructors",
"owner": "Administrator",
"report_function": "Sum",
"show_percentage_stats": 1,
"stats_time_interval": "Monthly",
"type": "Document Type"
}

View File

@ -0,0 +1,23 @@
{
"aggregate_function_based_on": "",
"creation": "2020-07-23 14:18:07.732298",
"docstatus": 0,
"doctype": "Number Card",
"document_type": "Student",
"dynamic_filters_json": "[]",
"filters_json": "[[\"Student\",\"enabled\",\"=\",1,false]]",
"function": "Count",
"idx": 0,
"is_public": 1,
"is_standard": 1,
"label": "Total Students",
"modified": "2020-07-23 14:18:40.603947",
"modified_by": "Administrator",
"module": "Education",
"name": "Total Students",
"owner": "Administrator",
"report_function": "Sum",
"show_percentage_stats": 1,
"stats_time_interval": "Monthly",
"type": "Document Type"
}

View File

@ -0,0 +1,19 @@
{
"action": "Create Entry",
"creation": "2020-07-27 19:09:04.493932",
"docstatus": 0,
"doctype": "Onboarding Step",
"idx": 0,
"is_complete": 0,
"is_mandatory": 0,
"is_single": 0,
"is_skipped": 0,
"modified": "2020-07-27 19:09:04.493932",
"modified_by": "Administrator",
"name": "Create a Course",
"owner": "Administrator",
"reference_document": "Course",
"show_full_form": 1,
"title": "Create a Course",
"validate_action": 1
}

View File

@ -0,0 +1,19 @@
{
"action": "Create Entry",
"creation": "2020-07-27 19:09:35.451945",
"docstatus": 0,
"doctype": "Onboarding Step",
"idx": 0,
"is_complete": 0,
"is_mandatory": 0,
"is_single": 0,
"is_skipped": 0,
"modified": "2020-07-27 19:09:35.451945",
"modified_by": "Administrator",
"name": "Create a Program",
"owner": "Administrator",
"reference_document": "Program",
"show_full_form": 1,
"title": "Create a Program",
"validate_action": 1
}

View File

@ -0,0 +1,19 @@
{
"action": "Create Entry",
"creation": "2020-07-27 19:17:20.326837",
"docstatus": 0,
"doctype": "Onboarding Step",
"idx": 0,
"is_complete": 0,
"is_mandatory": 1,
"is_single": 0,
"is_skipped": 0,
"modified": "2020-07-27 19:49:47.724289",
"modified_by": "Administrator",
"name": "Create a Student",
"owner": "Administrator",
"reference_document": "Student",
"show_full_form": 1,
"title": "Create a Student",
"validate_action": 1
}

View File

@ -0,0 +1,19 @@
{
"action": "Create Entry",
"creation": "2020-07-27 19:08:40.754534",
"docstatus": 0,
"doctype": "Onboarding Step",
"idx": 0,
"is_complete": 0,
"is_mandatory": 0,
"is_single": 0,
"is_skipped": 0,
"modified": "2020-07-27 19:09:13.231995",
"modified_by": "Administrator",
"name": "Create a Topic",
"owner": "Administrator",
"reference_document": "Topic",
"show_full_form": 1,
"title": "Create a Topic",
"validate_action": 1
}

View File

@ -0,0 +1,19 @@
{
"action": "Create Entry",
"creation": "2020-07-27 19:17:39.158037",
"docstatus": 0,
"doctype": "Onboarding Step",
"idx": 0,
"is_complete": 0,
"is_mandatory": 1,
"is_single": 0,
"is_skipped": 0,
"modified": "2020-07-27 19:49:47.723494",
"modified_by": "Administrator",
"name": "Create an Instructor",
"owner": "Administrator",
"reference_document": "Instructor",
"show_full_form": 1,
"title": "Create an Instructor",
"validate_action": 1
}

View File

@ -0,0 +1,19 @@
{
"action": "Create Entry",
"creation": "2020-07-27 19:10:28.530226",
"docstatus": 0,
"doctype": "Onboarding Step",
"idx": 0,
"is_complete": 0,
"is_mandatory": 0,
"is_single": 0,
"is_skipped": 0,
"modified": "2020-07-27 19:10:28.530226",
"modified_by": "Administrator",
"name": "Enroll a Student in a Program",
"owner": "Administrator",
"reference_document": "Program Enrollment",
"show_full_form": 0,
"title": "Enroll a Student in a Program",
"validate_action": 1
}

View File

@ -0,0 +1,19 @@
{
"action": "Watch Video",
"creation": "2020-07-27 19:05:12.663987",
"docstatus": 0,
"doctype": "Onboarding Step",
"idx": 0,
"is_complete": 0,
"is_mandatory": 0,
"is_single": 0,
"is_skipped": 0,
"modified": "2020-07-27 20:18:11.831789",
"modified_by": "Administrator",
"name": "Introduction to Program and Courses",
"owner": "Administrator",
"show_full_form": 0,
"title": "Introduction to Program and Courses",
"validate_action": 1,
"video_url": "https://www.youtube.com/watch?v=1ueE4seFTp8"
}

View File

@ -0,0 +1,19 @@
{
"action": "Watch Video",
"creation": "2020-07-27 19:14:57.176131",
"docstatus": 0,
"doctype": "Onboarding Step",
"idx": 0,
"is_complete": 0,
"is_mandatory": 0,
"is_single": 0,
"is_skipped": 0,
"modified": "2020-07-27 19:55:55.411032",
"modified_by": "Administrator",
"name": "Introduction to Student Attendance",
"owner": "Administrator",
"show_full_form": 0,
"title": "Introduction to Student Attendance",
"validate_action": 1,
"video_url": "https://youtu.be/j9pgkPuyiaI"
}

View File

@ -0,0 +1,20 @@
{
"action": "Watch Video",
"creation": "2020-07-27 19:12:05.046465",
"docstatus": 0,
"doctype": "Onboarding Step",
"idx": 0,
"is_complete": 0,
"is_mandatory": 0,
"is_single": 0,
"is_skipped": 0,
"modified": "2020-07-27 19:42:47.286441",
"modified_by": "Administrator",
"name": "Introduction to Student Group",
"owner": "Administrator",
"reference_document": "Student Group",
"show_full_form": 0,
"title": "Introduction to Student Group",
"validate_action": 1,
"video_url": "https://youtu.be/5K_smeeE1Q4"
}

View File

@ -0,0 +1,22 @@
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
/* eslint-disable */
frappe.query_reports["Program wise Fee Collection"] = {
"filters": [
{
"fieldname": "from_date",
"label": __("From Date"),
"fieldtype": "Date",
"default": frappe.datetime.add_months(frappe.datetime.get_today(), -1),
"reqd": 1
},
{
"fieldname": "to_date",
"label": __("To Date"),
"fieldtype": "Date",
"default": frappe.datetime.get_today(),
"reqd": 1
}
]
};

View File

@ -0,0 +1,32 @@
{
"add_total_row": 1,
"creation": "2020-07-27 16:05:33.263539",
"disable_prepared_report": 0,
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
"json": "{}",
"modified": "2020-08-05 14:14:12.410515",
"modified_by": "Administrator",
"module": "Education",
"name": "Program wise Fee Collection",
"owner": "Administrator",
"prepared_report": 0,
"query": "SELECT \n FeesCollected.program AS \"Program:Link/Program:200\",\n FeesCollected.paid_amount AS \"Fees Collected:Currency:150\",\n FeesCollected.outstanding_amount AS \"Outstanding Amount:Currency:150\",\n FeesCollected.grand_total \"Grand Total:Currency:150\"\nFROM (\n SELECT \n sum(grand_total) - sum(outstanding_amount) AS paid_amount, program,\n sum(outstanding_amount) AS outstanding_amount,\n sum(grand_total) AS grand_total\n FROM `tabFees`\n WHERE docstatus = 1\n GROUP BY program\n) AS FeesCollected\nORDER BY FeesCollected.paid_amount DESC",
"ref_doctype": "Fees",
"report_name": "Program wise Fee Collection",
"report_type": "Script Report",
"roles": [
{
"role": "Academics User"
},
{
"role": "Accounts User"
},
{
"role": "Accounts Manager"
}
]
}

View File

@ -0,0 +1,124 @@
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe import _
def execute(filters=None):
if not filters:
filters = {}
columns = get_columns(filters)
data = get_data(filters)
chart = get_chart_data(data)
return columns, data, None, chart
def get_columns(filters=None):
return [
{
'label': _('Program'),
'fieldname': 'program',
'fieldtype': 'Link',
'options': 'Program',
'width': 300
},
{
'label': _('Fees Collected'),
'fieldname': 'fees_collected',
'fieldtype': 'Currency',
'width': 200
},
{
'label': _('Outstanding Amount'),
'fieldname': 'outstanding_amount',
'fieldtype': 'Currency',
'width': 200
},
{
'label': _('Grand Total'),
'fieldname': 'grand_total',
'fieldtype': 'Currency',
'width': 200
}
]
def get_data(filters=None):
data = []
conditions = get_filter_conditions(filters)
fee_details = frappe.db.sql(
"""
SELECT
FeesCollected.program,
FeesCollected.paid_amount,
FeesCollected.outstanding_amount,
FeesCollected.grand_total
FROM (
SELECT
sum(grand_total) - sum(outstanding_amount) AS paid_amount, program,
sum(outstanding_amount) AS outstanding_amount,
sum(grand_total) AS grand_total
FROM `tabFees`
WHERE
docstatus = 1 and
program IS NOT NULL
%s
GROUP BY program
) AS FeesCollected
ORDER BY FeesCollected.paid_amount DESC
""" % (conditions)
, as_dict=1)
for entry in fee_details:
data.append({
'program': entry.program,
'fees_collected': entry.paid_amount,
'outstanding_amount': entry.outstanding_amount,
'grand_total': entry.grand_total
})
return data
def get_filter_conditions(filters):
conditions = ''
if filters.get('from_date') and filters.get('to_date'):
conditions += " and posting_date BETWEEN '%s' and '%s'" % (filters.get('from_date'), filters.get('to_date'))
return conditions
def get_chart_data(data):
if not data:
return
labels = []
fees_collected = []
outstanding_amount = []
for entry in data:
labels.append(entry.get('program'))
fees_collected.append(entry.get('fees_collected'))
outstanding_amount.append(entry.get('outstanding_amount'))
return {
'data': {
'labels': labels,
'datasets': [
{
'name': _('Fees Collected'),
'values': fees_collected
},
{
'name': _('Outstanding Amt'),
'values': outstanding_amount
}
]
},
'type': 'bar'
}

View File

@ -1,8 +1,5 @@
import traceback import traceback
import pycountry
import taxjar
import frappe import frappe
from erpnext import get_default_company from erpnext import get_default_company
from frappe import _ from frappe import _
@ -32,6 +29,7 @@ def get_client():
def create_transaction(doc, method): def create_transaction(doc, method):
import taxjar
"""Create an order transaction in TaxJar""" """Create an order transaction in TaxJar"""
if not TAXJAR_CREATE_TRANSACTIONS: if not TAXJAR_CREATE_TRANSACTIONS:
@ -208,6 +206,7 @@ def get_shipping_address_details(doc):
def get_iso_3166_2_state_code(address): def get_iso_3166_2_state_code(address):
import pycountry
country_code = frappe.db.get_value("Country", address.get("country"), "code") country_code = frappe.db.get_value("Country", address.get("country"), "code")
error_message = _("""{0} is not a valid state! Check for typos or enter the ISO code for your state.""").format(address.get("state")) error_message = _("""{0} is not a valid state! Check for typos or enter the ISO code for your state.""").format(address.get("state"))

View File

@ -71,6 +71,7 @@ def validate_service_item(item, msg):
frappe.throw(_(msg)) frappe.throw(_(msg))
@frappe.whitelist() @frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def get_practitioner_list(doctype, txt, searchfield, start, page_len, filters=None): def get_practitioner_list(doctype, txt, searchfield, start, page_len, filters=None):
fields = ['name', 'practitioner_name', 'mobile_phone'] fields = ['name', 'practitioner_name', 'mobile_phone']

View File

@ -39,7 +39,9 @@ class HealthcareServiceUnitType(Document):
def on_trash(self): def on_trash(self):
if self.item: if self.item:
try: try:
frappe.delete_doc('Item', self.item) item = self.item
self.db_set('item', '')
frappe.delete_doc('Item', item)
except Exception: except Exception:
frappe.throw(_('Not permitted. Please disable the Service Unit Type')) frappe.throw(_('Not permitted. Please disable the Service Unit Type'))

View File

@ -134,7 +134,7 @@ let transfer_patient_dialog = function(frm) {
{fieldtype: 'Link', label: 'Leave From', fieldname: 'leave_from', options: 'Healthcare Service Unit', reqd: 1, read_only:1}, {fieldtype: 'Link', label: 'Leave From', fieldname: 'leave_from', options: 'Healthcare Service Unit', reqd: 1, read_only:1},
{fieldtype: 'Link', label: 'Service Unit Type', fieldname: 'service_unit_type', options: 'Healthcare Service Unit Type'}, {fieldtype: 'Link', label: 'Service Unit Type', fieldname: 'service_unit_type', options: 'Healthcare Service Unit Type'},
{fieldtype: 'Link', label: 'Transfer To', fieldname: 'service_unit', options: 'Healthcare Service Unit', reqd: 1}, {fieldtype: 'Link', label: 'Transfer To', fieldname: 'service_unit', options: 'Healthcare Service Unit', reqd: 1},
{fieldtype: 'Datetime', label: 'Check In', fieldname: 'check_in', reqd: 1} {fieldtype: 'Datetime', label: 'Check In', fieldname: 'check_in', reqd: 1, default: frappe.datetime.now_datetime()}
], ],
primary_action_label: __('Transfer'), primary_action_label: __('Transfer'),
primary_action : function() { primary_action : function() {
@ -147,7 +147,12 @@ let transfer_patient_dialog = function(frm) {
if(dialog.get_value('service_unit')){ if(dialog.get_value('service_unit')){
service_unit = dialog.get_value('service_unit'); service_unit = dialog.get_value('service_unit');
} }
if(!check_in){ if(check_in > frappe.datetime.now_datetime()){
frappe.msgprint({
title: __('Not Allowed'),
message: __('Check-in time cannot be greater than the current time'),
indicator: 'red'
});
return; return;
} }
frappe.call({ frappe.call({

View File

@ -5,7 +5,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe, json import frappe, json
from frappe import _ from frappe import _
from frappe.utils import today, now_datetime, getdate from frappe.utils import today, now_datetime, getdate, get_datetime
from frappe.model.document import Document from frappe.model.document import Document
from frappe.desk.reportview import get_match_cond from frappe.desk.reportview import get_match_cond
@ -30,6 +30,11 @@ class InpatientRecord(Document):
(getdate(self.discharge_ordered_date) < getdate(self.scheduled_date)): (getdate(self.discharge_ordered_date) < getdate(self.scheduled_date)):
frappe.throw(_('Expected and Discharge dates cannot be less than Admission Schedule date')) frappe.throw(_('Expected and Discharge dates cannot be less than Admission Schedule date'))
for entry in self.inpatient_occupancies:
if entry.check_in and entry.check_out and \
get_datetime(entry.check_in) > get_datetime(entry.check_out):
frappe.throw(_('Row #{0}: Check Out datetime cannot be less than Check In datetime').format(entry.idx))
def validate_already_scheduled_or_admitted(self): def validate_already_scheduled_or_admitted(self):
query = """ query = """
select name, status select name, status
@ -217,6 +222,7 @@ def patient_leave_service_unit(inpatient_record, check_out, leave_from):
inpatient_record.save(ignore_permissions = True) inpatient_record.save(ignore_permissions = True)
@frappe.whitelist() @frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def get_leave_from(doctype, txt, searchfield, start, page_len, filters): def get_leave_from(doctype, txt, searchfield, start, page_len, filters):
docname = filters['docname'] docname = filters['docname']

View File

@ -322,7 +322,8 @@ scheduler_events = {
"erpnext.crm.doctype.email_campaign.email_campaign.set_email_campaign_status", "erpnext.crm.doctype.email_campaign.email_campaign.set_email_campaign_status",
"erpnext.selling.doctype.quotation.quotation.set_expired_status", "erpnext.selling.doctype.quotation.quotation.set_expired_status",
"erpnext.healthcare.doctype.patient_appointment.patient_appointment.update_appointment_status", "erpnext.healthcare.doctype.patient_appointment.patient_appointment.update_appointment_status",
"erpnext.buying.doctype.supplier_quotation.supplier_quotation.set_expired_status" "erpnext.buying.doctype.supplier_quotation.supplier_quotation.set_expired_status",
"erpnext.accounts.doctype.process_statement_of_accounts.process_statement_of_accounts.send_auto_email"
], ],
"daily_long": [ "daily_long": [
"erpnext.setup.doctype.email_digest.email_digest.send", "erpnext.setup.doctype.email_digest.email_digest.send",

View File

@ -7,14 +7,14 @@
"doctype": "Dashboard Chart", "doctype": "Dashboard Chart",
"document_type": "Job Applicant", "document_type": "Job Applicant",
"dynamic_filters_json": "", "dynamic_filters_json": "",
"filters_json": "[[\"Job Applicant\",\"creation\",\"Previous\",\"1 month\"]]", "filters_json": "[[\"Job Applicant\",\"creation\",\"Timespan\",\"last month\",false]]",
"group_by_based_on": "status", "group_by_based_on": "status",
"group_by_type": "Count", "group_by_type": "Count",
"idx": 0, "idx": 0,
"is_public": 1, "is_public": 1,
"is_standard": 1, "is_standard": 1,
"last_synced_on": "2020-07-22 14:27:40.118498", "last_synced_on": "2020-07-28 16:19:12.109979",
"modified": "2020-07-22 14:33:00.404144", "modified": "2020-07-28 16:19:45.279490",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "HR", "module": "HR",
"name": "Job Application Status", "name": "Job Application Status",

View File

@ -78,7 +78,7 @@
"idx": 0, "idx": 0,
"is_standard": 1, "is_standard": 1,
"label": "HR", "label": "HR",
"modified": "2020-06-16 19:20:50.976045", "modified": "2020-08-11 17:04:38.655417",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "HR", "module": "HR",
"name": "HR", "name": "HR",
@ -88,7 +88,7 @@
"pin_to_top": 0, "pin_to_top": 0,
"shortcuts": [ "shortcuts": [
{ {
"color": "#9deca2", "color": "#cef6d1",
"format": "{} Active", "format": "{} Active",
"label": "Employee", "label": "Employee",
"link_to": "Employee", "link_to": "Employee",
@ -96,18 +96,19 @@
"type": "DocType" "type": "DocType"
}, },
{ {
"label": "Attendance", "color": "#ffe8cd",
"link_to": "Attendance",
"stats_filter": "",
"type": "DocType"
},
{
"format": "{} Open", "format": "{} Open",
"label": "Leave Application", "label": "Leave Application",
"link_to": "Leave Application", "link_to": "Leave Application",
"stats_filter": "{\"status\":\"Open\"}", "stats_filter": "{\"status\":\"Open\"}",
"type": "DocType" "type": "DocType"
}, },
{
"label": "Attendance",
"link_to": "Attendance",
"stats_filter": "",
"type": "DocType"
},
{ {
"label": "Job Applicant", "label": "Job Applicant",
"link_to": "Job Applicant", "link_to": "Job Applicant",

View File

@ -11,6 +11,7 @@ class DepartmentApprover(Document):
pass pass
@frappe.whitelist() @frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def get_approvers(doctype, txt, searchfield, start, page_len, filters): def get_approvers(doctype, txt, searchfield, start, page_len, filters):
if not filters.get("employee"): if not filters.get("employee"):

View File

@ -35,7 +35,15 @@ frappe.query_reports["Monthly Attendance Sheet"] = {
"fieldname":"employee", "fieldname":"employee",
"label": __("Employee"), "label": __("Employee"),
"fieldtype": "Link", "fieldtype": "Link",
"options": "Employee" "options": "Employee",
get_query: () => {
var company = frappe.query_report.get_filter_value('company');
return {
filters: {
'company': company
}
};
}
}, },
{ {
"fieldname":"company", "fieldname":"company",

View File

@ -96,6 +96,7 @@ def get_data(filters):
def get_parent_row(sp_jo_map, sp, jo_ja_map, ja_joff_map): def get_parent_row(sp_jo_map, sp, jo_ja_map, ja_joff_map):
data = [] data = []
if sp in sp_jo_map.keys():
for jo in sp_jo_map[sp]: for jo in sp_jo_map[sp]:
row = { row = {
"staffing_plan" : sp, "staffing_plan" : sp,
@ -108,6 +109,7 @@ def get_parent_row(sp_jo_map, sp, jo_ja_map, ja_joff_map):
def get_child_row(jo, jo_ja_map, ja_joff_map): def get_child_row(jo, jo_ja_map, ja_joff_map):
data = [] data = []
if jo in jo_ja_map.keys():
for ja in jo_ja_map[jo]: for ja in jo_ja_map[jo]:
row = { row = {
"indent":1, "indent":1,
@ -177,7 +179,7 @@ def get_job_applicant(jo_list):
def get_job_offer(ja_list): def get_job_offer(ja_list):
ja_joff_map = {} ja_joff_map = {}
offers = frappe.get_all("Job offer", filters = [["job_applicant", "IN", ja_list]], fields =["name", "job_applicant", "status", 'offer_date', 'designation']) offers = frappe.get_all("Job Offer", filters = [["job_applicant", "IN", ja_list]], fields =["name", "job_applicant", "status", 'offer_date', 'designation'])
for offer in offers: for offer in offers:
if offer.job_applicant not in ja_joff_map.keys(): if offer.job_applicant not in ja_joff_map.keys():

View File

@ -3,7 +3,7 @@
{ {
"hidden": 0, "hidden": 0,
"label": "Loan", "label": "Loan",
"links": "[\n {\n \"description\": \"Loan Type for interest and penalty rates\",\n \"label\": \"Loan Type\",\n \"name\": \"Loan Type\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Loan Applications from customers and employees.\",\n \"label\": \"Loan Application\",\n \"name\": \"Loan Application\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Loans provided to customers and employees.\",\n \"label\": \"Loan\",\n \"name\": \"Loan\",\n \"type\": \"doctype\"\n }\n]" "links": "[\n {\n \"description\": \"Loan Type for interest and penalty rates\",\n \"label\": \"Loan Type\",\n \"name\": \"Loan Type\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Loan Applications from customers and employees.\",\n \"label\": \"Loan Application\",\n \"name\": \"Loan Application\",\n \"type\": \"doctype\"\n },\n { \"dependencies\": [\n \"Loan Type\"\n ],\n \"description\": \"Loans provided to customers and employees.\",\n \"label\": \"Loan\",\n \"name\": \"Loan\",\n \"type\": \"doctype\"\n }\n]"
}, },
{ {
"hidden": 0, "hidden": 0,

Some files were not shown because too many files have changed in this diff Show More