def list(loan, from_date, to_date): if getdate(to_date) < getdate(from_date): return frappe.throw('To date cannot be less than From date') conds = [ "loan = '{}'".format(loan), "docstatus = 1", "start_date BETWEEN '{}' AND '{}'".format(from_date, to_date), ] existing = frappe.db.sql( """ SELECT name, status, period, posting_date, start_date, billed_amount, paid_amount, fine_amount FROM `tabMicrofinance Loan Interest` WHERE {conds} """.format(conds=join(" AND ")(conds)), as_dict=True, ) existing_dict = dict((row.name, row) for row in existing) get_item = compose(existing_dict.get, partial(make_name, loan)) make_item = compose(_make_list_item, get_item) loan_end_date, loan_start_date = frappe.get_value( 'Microfinance Loan', loan, ['clear_date', 'posting_date']) def make_empty(d): return { 'name': make_name(loan, d), 'period': d.strftime('%b %Y'), 'start_date': max(loan_start_date, d), 'status': 'Unbilled' } effective_date = frappe.get_value('Microfinance Loan Settings', None, 'effective_date') is_not_sys_mgr = 'System Manager' not in frappe.permissions.get_roles() def change_status(row): start_date = row.get('start_date') status = 'Clear' \ if is_not_sys_mgr \ and getdate(effective_date) > getdate(start_date) \ else row.get('status') return update({ 'status': status, })(row) fd = compose(partial(max, loan_start_date), getdate) td = compose(partial(min, loan_end_date), getdate) \ if loan_end_date else getdate dates = _gen_dates(fd(from_date), td(to_date)) return compose( partial(map, change_status), partial(map, lambda x: make_item(x) if get_item(x) else make_empty(x)), )(dates)
def get_sum_of(doctype, field): def fn(loan): return frappe.get_all( doctype, filters={'docstatus': 1, 'loan': loan}, fields=field, ) return compose(sum, partial(map, pick(field)), fn)
def create(loan, period, start_date, billed_amount=None): if 'System Manager' not in frappe.permissions.get_roles(): prev = compose( partial(frappe.db.exists, 'Microfinance Loan Interest'), partial(make_name, loan), getdate, partial(add_months, months=-1), )(start_date) if not prev: return frappe.throw( 'Interest for previous interval does not exists') end_date = compose(get_last_day, getdate)(start_date) interest = frappe.get_doc({ 'doctype': 'Microfinance Loan Interest', 'loan': loan, 'posting_date': add_days(end_date, 1), 'period': period, 'start_date': getdate(start_date), 'end_date': end_date, 'billed_amount': billed_amount, }) interest.insert() interest.submit() return interest
def fine(name): interest = frappe.get_doc('Microfinance Loan Interest', name) loan_start_date = frappe.get_value('Microfinance Loan', interest.loan, 'posting_date') prev_status = compose( partial(frappe.get_value, 'Microfinance Loan Interest', fieldname='status'), partial(make_name, interest.loan), partial(add_months, months=-1), )(interest.end_date) if interest.start_date > loan_start_date else 'Clear' if prev_status not in ['Clear', 'Fined']: return frappe.throw('Previous interest is not cleared or fined') if _has_next_interest(interest): return frappe.throw('Interest for next interval already exists') interest.run_method('set_fine_amount') return interest
def get_current_interest(loan, posting_date): calculation_slab, rate_of_interest, recovery_status = frappe.get_value( 'Microfinance Loan', loan, ['calculation_slab', 'rate_of_interest', 'recovery_status'], ) if recovery_status == 'NPA': return 0 prev_billed_amount = compose( partial(frappe.get_value, 'Microfinance Loan Interest', fieldname='billed_amount'), partial(make_name, loan), getdate, partial(add_months, months=-1), )(posting_date) if prev_billed_amount: return prev_billed_amount outstanding = get_outstanding_principal(loan, posting_date) return calc_interest(outstanding, rate_of_interest, calculation_slab)
from loan_management.loan_management.utils.fp import compose, join from loan_management.loan_management.api.loan import get_outstanding_principal def _accum_reducer(acc, row): return acc + [row[:-1] + (acc[-1][5] + row[4], ) + row[-1:]] def _col_sum(idx): def fn(rows): return reduce(lambda a, x: a + x[idx], rows, 0) return fn _stringify_accounts = compose(join(', '), partial(map, lambda x: "'{}'".format(x))) def execute(filters={}): columns = [ _("Posting Date") + ":Date:90", _("Account") + ":Link/Account:240", _("Credit") + ":Currency/currency:90", _("Debit") + ":Currency/currency:90", _("Amount") + ":Currency/currency:90", _("Cummulative") + ":Currency/currency:90", _("Remarks") + "::240", ] loan_account = frappe.get_value('Customer Loan Application', filters.get('loan'),
def _is_advance(per, posting_date): scheduled_pd = compose( partial(add_days, days=1), per.get, )('end_date') return getdate(posting_date) < getdate(scheduled_pd)
def _has_next_interest(interest): return compose( partial(frappe.db.exists, 'Microfinance Loan Interest'), partial(make_name, interest.loan), partial(add_months, months=1), )(interest.start_date)