Code Monkey home page Code Monkey logo

lending's Introduction

Introduction

Open Source Lending software.

Key Features

  • Loan Management

Installation

Manual Installation

  1. Install bench.

  2. Install ERPNext.

  3. Once ERPNext is installed, add the lending app to your bench by running

    $ bench get-app lending
  4. After that, you can install the lending app on the required site by running

    $ bench --site sitename install-app lending

Learning and Community

  1. Documentation - Extensive documentation for Frappe Lending.
  2. User Forum - Engage with the community of ERPNext users and service providers.

Contribute

  1. Issue Guidelines - Create an issue
  2. Contribution Guidelines

License

GNU GPL V3 (see license.txt).

The Lending code is licensed as GNU General Public License (v3) and the copyright is owned by Frappe Technologies Pvt Ltd (Frappe) and Contributors.

lending's People

Contributors

aakvatech avatar abhinavxd avatar abhishek8848 avatar abhishekbalam avatar afshankhan avatar anandbaburajan avatar ankush avatar anupamvs avatar anurag810 avatar bosue avatar chillaranand avatar deepeshgarg007 avatar fproldan avatar kittiu avatar lebmatter avatar marination avatar nabinhait avatar nextchamp-saqib avatar pateljannat avatar rmehta avatar rohitwaghchaure avatar ruchamahabal avatar ruthra-kumar avatar sagarvora avatar saurabh6790 avatar scmmishra avatar shariquerik avatar surajshetty3416 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

lending's Issues

issue setting up the date for loan security

Information about bug

date doesn't work properly. it should work the same way when setting the from data
Screenshot 2023-12-14 at 21 11 47

Module

Loan Management

Version

v0.01

Installation method

None

Relevant log output / Stack trace / Full Error Message.

No response

Code of Conduct

  • I agree to follow this project's Code of Conduct

Various calculated amounts disappear in new Loan draft, only reappear (in part) when saved

When creating a new Loan application,

  • Maximum loan amount (for secured loans)
  • Monthly repayment amount
  • Total payable amount, and
  • Total payable interest

are calculated and displayed:

IMG_1516

However, when moving on to the actual Loan draft, these calculated fields don‘t stay there, nor do they disappear. Even more confusing, they‘re now presented as 0.00:

IMG_1517

It’s only after submission that most of these reappear, with the exception of the Maximum loan amount that will never reappear:

IMG_1518

Error while installing the app

Information about bug

I got the error An error occurred while installing lending: Cannot link cancelled document: Loan: ACC-LOAN-2023-00006 while installing the app, which led to a lot problems post-that. I had to manually delete the cancelled docs (total: 3) from the Db for it to go through. Can we have a proper way to handle it?

Waiting on a solution before upgrading my production enviornment

Module

Loan Management

Version

ERPNext: v15.8.3 (version-15)
Frappe Framework: v15.7.0 (version-15)
Frappe HR: v15.7.1 (version-15)
Ksa: v0.0.1 (dev)
Frappe Lending: v0.0.1 (version-15)
Payments: v0.0.1 (develop)

Installation method

manual install

Relevant log output / Stack trace / Full Error Message.

ubuntu@ec2-54-84-187-196:~/frappe-bench$ bench --site $sitename install-app lending
App erpnext already installed

Installing lending...

Updating DocTypes for lending       : [========================================] 100%

Running post-install patches to patch existing data...

An error occurred while installing lending: Cannot link cancelled document: Loan: ACC-LOAN-2023-00006
Traceback (most recent call last):
  File "apps/frappe/frappe/commands/site.py", line 462, in install_app
    _install_app(app, verbose=context.verbose, force=force)
  File "apps/frappe/frappe/installer.py", line 311, in install_app
    frappe.get_attr(after_install)()
  File "apps/lending/lending/install.py", line 236, in after_install
    run_patches(get_post_install_patches())
  File "apps/lending/lending/install.py", line 227, in run_patches
    frappe.get_attr(f"lending.patches.v15_0.{patch}.execute")()
  File "apps/lending/lending/patches/v15_0/generate_loan_repayment_schedule.py", line 39, in execute
    loan_repayment_schedule.submit()
  File "apps/frappe/frappe/utils/typing_validations.py", line 31, in wrapper
    return func(*args, **kwargs)
  File "apps/frappe/frappe/model/document.py", line 1038, in submit
    return self._submit()
  File "apps/frappe/frappe/model/document.py", line 1019, in _submit
    return self.save()
  File "apps/frappe/frappe/model/document.py", line 334, in save
    return self._save(*args, **kwargs)
  File "apps/frappe/frappe/model/document.py", line 356, in _save
    return self.insert()
  File "apps/frappe/frappe/model/document.py", line 278, in insert
    self._validate_links()
  File "apps/frappe/frappe/model/document.py", line 922, in _validate_links
    frappe.throw(_("Cannot link cancelled document: {0}").format(msg), frappe.CancelledLinkError)
  File "apps/frappe/frappe/__init__.py", line 603, in throw
    msgprint(
  File "apps/frappe/frappe/__init__.py", line 575, in msgprint
    _raise_exception()
  File "apps/frappe/frappe/__init__.py", line 526, in _raise_exception
    raise exc
frappe.exceptions.CancelledLinkError: Cannot link cancelled document: Loan: ACC-LOAN-2023-00006

Code of Conduct

  • I agree to follow this project's Code of Conduct

Integrate with ERPNext Asset doctype rather than building our own Loan Security “ecosystem” of doctypes

Loan securities may be guarantees or assignments / cessions or actual assets.

Whenever they are assets, I can see no valid point in duplicating erpnext‘s Asset doctype, just with waaay fewer functionality and both a duplicated code base and scattered data structure.

Capitalized assets and non-capitalized assets, collateral assets (and the edge case of capitalized collateral assets)

In general, assets may be capitalized (and then depreciated) or they may not be. Mostly yes, sometimes not. This, however, isn‘t a black-or-white thing, it may rather depend on subtle differences, even if the company is legal owner, and may even differ between financial reports and tax statements.

The same may hold for collateralized assets, just the other way around. Legal ownership will mostly remain with the customer, but may in some scenarios, such as Sale-and-lease-back-transactions, even be capitalized and depreciated with the lessor / lender.

Finally it‘s all about conflicting fields of law. Tax code and their authorities always wants the company to state as much earnings as possible. Commercial law and regulatory authorities always want to stay on the safe side, tending to understate what may be capitalized. Civil law on the other hand will be searching for a systematic approach that reconciles all parties interests, playing the role of a fair mediator rather than an interested party.

Depreciation / devaluation

If the asset is not capitalized, there‘s of course no depreciation in the legal sense. But the reduction in collateral value that needs to be deducted over the months and years may still (have to) be scheduled exactly the way depreciations are implemented.

Or – if official depreciation rules are out of touch with reality, which they often are – we need a separate, more realistic set of devaluation rules. But in this case we may / will need them for our capitalized assets just as well, so we know what they‘re real market value is, no matter what the official depreciation rules may say.

More similarities

The owner documents of a collateralized security (e.g. a car) will mostly be with the bank, exactly the same way as for capitalized assets, so we need a register of vehicle registration numbers, vehicle identity numbers, vehicle registration offices, and various document handling procedures, standard letters and forms.

Even insurance or vehicle tax may (have to) be paid by the bank and included in the credit / leasing installments. So do we want two separate registers and two separate sets of documents and workflows, each siloed in a different Frappe module? No, certainly not.

Conclusion

Long story short: Everything the Asset doctype “ecosystem” including all its integrations may give us for capitalized assets would be valuable for collateral assets just as well, and the other way around.

So we definitely shouldn‘t reinvent the wheel here, but integrate with the ERPNext Asset “ecosystem“ and maybe extend it a bit so it caters to frappe/lending’s needs.

Thereby, we would earn a lot:

  • Deduplicate code, improving maintainability
  • Receive far more features and integrations from the ERPNext Asset doctype and its integrations
  • Contribute back quite a lot of improvements and polish to the ERPNext Asset doctype, which in any case would become way more flexible and powerful, and – if we focus on UX ourselves – may still get easier rather than harder to use for all usecases.
  • Avoid siloed data for capitalized assets vs. non-capitalized, collateral assets
  • Avoid duplication of data if collaterals need to be capitalized as assets

(edited for clarity)

Adjusted interest?

What exactly is the “Adjusted Interest“ field (in absolute values) supposed to do, and why is it added upfront to the first term? I think this is wrong. You can’t simply adjust individual interest amounts, leading to incorrect interest totals.

If this is about upfront costs / charges, that’s fine, but then they need to go outside the repayment schedule.

RPReplay_Final1695202295.mov

Rename “monthly_repayment_amount” to “annuity“

As #26 and #33 show, the field names / properties we’re using aren’t always consistent and often quite long.

Sometimes it’s “monthly_repayment_amount”, sometimes just “repayment_amount”, etc. This leads to errors and is quite hard to read in code, and even in the UI it makes things look quite bulky.

How much we can do about it depends. But let’s start with one that we can improve quite a lot.

Today, I‘m strongly suggesting to rename “monthly_repayment_amount” to the wonderfully short and concise term “annuity,” and do so everywhere, both in code and in the UI.

Whoever works in finance, knows what an annuity is: exactly this. Annuity is the technical term for a uniform, (monthly or yearly) loan repayment installment. For those who don’t know, we may add a user facing description as well.

pymysql.err.ProgrammingError: ('DocType', 'Loan Product')

Information about bug

Happens when Loan Product Menu is clicked
image

Module

Loan Management

Version

ERPNext: v15.2.0 (HEAD)
Frappe Framework: v15.1.0 (HEAD)
Frappe HR: v15.3.0 (HEAD)
Frappe Lending: v0.0.1 (HEAD)

Installation method

FrappeCloud

Relevant log output / Stack trace / Full Error Message.

request.js:473 Traceback (most recent call last):
  File "apps/frappe/frappe/app.py", line 110, in application
    response = frappe.api.handle(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "apps/frappe/frappe/api/__init__.py", line 49, in handle
    data = endpoint(**arguments)
           ^^^^^^^^^^^^^^^^^^^^^
  File "apps/frappe/frappe/api/v1.py", line 36, in handle_rpc_call
    return frappe.handler.handle()
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "apps/frappe/frappe/handler.py", line 49, in handle
    data = execute_cmd(cmd)
           ^^^^^^^^^^^^^^^^
  File "apps/frappe/frappe/handler.py", line 85, in execute_cmd
    return frappe.call(method, **frappe.form_dict)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "apps/frappe/frappe/__init__.py", line 1683, in call
    return fn(*args, **newargs)
           ^^^^^^^^^^^^^^^^^^^^
  File "apps/frappe/frappe/utils/typing_validations.py", line 31, in wrapper
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "apps/frappe/frappe/__init__.py", line 848, in wrapper_fn
    retval = fn(*args, **get_newargs(fn, kwargs))
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "apps/frappe/frappe/desk/reportview.py", line 28, in get
    data = compress(execute(**args), args=args)
                    ^^^^^^^^^^^^^^^
  File "apps/frappe/frappe/desk/reportview.py", line 64, in execute
    return DatabaseQuery(doctype).execute(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "apps/frappe/frappe/model/db_query.py", line 194, in execute
    self.columns = self.get_table_columns()
                   ^^^^^^^^^^^^^^^^^^^^^^^^
  File "apps/frappe/frappe/model/db_query.py", line 552, in get_table_columns
    return get_table_columns(self.doctype)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "apps/frappe/frappe/model/meta.py", line 73, in get_table_columns
    return frappe.db.get_table_columns(doctype)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "apps/frappe/frappe/database/database.py", line 1122, in get_table_columns
    raise self.TableMissingError("DocType", doctype)
pymysql.err.ProgrammingError: ('DocType', 'Loan Product')

Code of Conduct

  • I agree to follow this project's Code of Conduct

Implement basic Scorecards for Loan applicants

As part of a full contracting workflow, see #25, we need to model our credit decision process based on scorecards.

To accomplish this, we may build upon ERPNext’s already existing Supplier Scorecards, once they are expanded to all Party Types, see frappe/erpnext#36271. As a prerequisite, I‘m working on a PR moving generalized scorecards out to a separate Risk (management) module that may and will later be refined and expanded.

Minor CSS errors

Testing results keep mentioning the following three CSS errors:

ERROR   PropertyValue: Missing token for production Choice(ColorValue, Dimension, URIValue, Value, variable, MSValue, CSSCalc, function): ('HASH', '#0000001a', 1, 3198)
ERROR   PropertyValue: Unknown syntax or no value: 0 3px 6px #0000001a
ERROR   CSSStyleDeclaration: Syntax Error in Property: box-shadow:0 3px 6px #0000001a

Unknown table '_cef4968b8549ea81.tabLoan Product'

Information about bug

Hi, I was trying to install lending to a fresh v14 install of ERPnext and experienced this error. Is "lending" even meant to be installed on 14? Unfortunately also the old Loan Module now doesnt work anymore (I think doctypes are missing).
Is there a way to delete all Loan specific doc types and database entries and install lending fresh?

thanks for your help!

Module

Loan Management

Version

erpnext 14.48.1
frappe 14.55.0
lending 0.0.1

Installation method

manual install

Relevant log output / Stack trace / Full Error Message.

Installing lending...
Updating DocTypes for lending       : [========================================] 100%

Running post-install patches to patch existing data...

An error occurred while installing lending: (1051, "Unknown table '_cef4968b8549ea81.tabLoan Product'")
Traceback (most recent call last):
  File "apps/frappe/frappe/commands/site.py", line 415, in install_app
    _install_app(app, verbose=context.verbose, force=force)
  File "apps/frappe/frappe/installer.py", line 307, in install_app
    frappe.get_attr(after_install)()
  File "apps/lending/lending/install.py", line 236, in after_install
    run_patches(get_post_install_patches())
  File "apps/lending/lending/install.py", line 227, in run_patches
    frappe.get_attr(f"lending.patches.v15_0.{patch}.execute")()
  File "apps/lending/lending/patches/v15_0/rename_loan_type_to_loan_product.py", line 11, in execute
    frappe.db.sql_ddl("DROP TABLE `tabLoan Product`")
  File "apps/frappe/frappe/database/database.py", line 378, in sql_ddl
    self.sql(query, debug=debug)
  File "apps/frappe/frappe/database/database.py", line 220, in sql
    self._cursor.execute(query, values)
  File "env/lib/python3.10/site-packages/pymysql/cursors.py", line 158, in execute
    result = self._query(query)
  File "env/lib/python3.10/site-packages/pymysql/cursors.py", line 325, in _query
    conn.query(q)
  File "env/lib/python3.10/site-packages/pymysql/connections.py", line 549, in query
    self._affected_rows = self._read_query_result(unbuffered=unbuffered)
  File "env/lib/python3.10/site-packages/pymysql/connections.py", line 779, in _read_query_result
    result.read()
  File "env/lib/python3.10/site-packages/pymysql/connections.py", line 1157, in read
    first_packet = self.connection._read_packet()
  File "env/lib/python3.10/site-packages/pymysql/connections.py", line 729, in _read_packet
    packet.raise_for_error()
  File "env/lib/python3.10/site-packages/pymysql/protocol.py", line 221, in raise_for_error
    err.raise_mysql_exception(self._data)
  File "env/lib/python3.10/site-packages/pymysql/err.py", line 143, in raise_mysql_exception
    raise errorclass(errno, errval)
pymysql.err.OperationalError: (1051, "Unknown table '_cef4968b8549ea81.tabLoan Product'")

Code of Conduct

  • I agree to follow this project's Code of Conduct

repay from salary

Information about bug

repay from salary checkbox was removed from loan doctype in erp next version 14 but we still get issues when submitting loan doctype like this one

AttributeError: 'Loan' object has no attribute 'repay_from_salary'

Module

Loan Management

Version

ERPNext: v14.46.1 (version-14)

Frappe Framework: v14.54.0 (version-14)

Installation method

docker

Relevant log output / Stack trace / Full Error Message.

### App Versions

{
	"erpnext": "14.46.1",
	"frappe": "14.54.0",
	"hrms": "16.0.0-dev"
}

Route

Form/Loan/new-loan-myogzjlkmu

Traceback

Traceback (most recent call last):
  File "apps/frappe/frappe/app.py", line 95, in application
    response = frappe.api.handle()
  File "apps/frappe/frappe/api.py", line 54, in handle
    return frappe.handler.handle()
  File "apps/frappe/frappe/handler.py", line 47, in handle
    data = execute_cmd(cmd)
  File "apps/frappe/frappe/handler.py", line 85, in execute_cmd
    return frappe.call(method, **frappe.form_dict)
  File "apps/frappe/frappe/__init__.py", line 1622, in call
    return fn(*args, **newargs)
  File "apps/frappe/frappe/desk/form/save.py", line 31, in savedocs
    doc.save()
  File "apps/frappe/frappe/model/document.py", line 309, in save
    return self._save(*args, **kwargs)
  File "apps/frappe/frappe/model/document.py", line 331, in _save
    return self.insert()
  File "apps/frappe/frappe/model/document.py", line 262, in insert
    self.run_before_save_methods()
  File "apps/frappe/frappe/model/document.py", line 1055, in run_before_save_methods
    self.run_method("validate")
  File "apps/frappe/frappe/model/document.py", line 919, in run_method
    out = Document.hook(fn)(self, *args, **kwargs)
  File "apps/frappe/frappe/model/document.py", line 1281, in composer
    return composed(self, method, *args, **kwargs)
  File "apps/frappe/frappe/model/document.py", line 1265, in runner
    add_to_return_value(self, f(self, method, *args, **kwargs))
  File "apps/hrms/hrms/hr/utils.py", line 687, in validate_loan_repay_from_salary
    if doc.applicant_type == "Employee" and doc.repay_from_salary:
AttributeError: 'Loan' object has no attribute 'repay_from_salary'

Code of Conduct

  • I agree to follow this project's Code of Conduct

No further disbursement entry if Loan amount is fully disbursed

Is your feature request related to a problem? Please describe.

Validation correctly prohibits disbursements that are exceeding the full Loan amount.

This holds as well if the Loan has been fully disbursed. In this particular case, the “Add new Loan Disbursement” icon should however be disabled in the first place.

IMG_1487
IMG_1489

Describe the solution you'd like

No response

Describe the alternatives you've considered

No response

Additional context

No response

Disallow zero-amount Loan disbursements

Is your feature request related to a problem? Please describe.

I think, loan disbursement amounts of 0.00 should be disallowed by validation. They will always be result of a user mistake. Is there an edge case I’m missing?

IMG_1488

Describe the solution you'd like

No response

Describe the alternatives you've considered

No response

Additional context

No response

Implement a full loan contracting workflow with calculations, quotes and offers

Before customers may actually apply for a loan, they need either a (binding) offer or at least a (non-binding) quote how the loan might look like and how much it would cost.

A simplified workflow may look like this:
IMG_1524

Note that I focussed on business needs, not data structures.

Some lenders may only offer standardized products in the low-risk segment, others won’t have standardized products at all, so will consider every loan request individually. But all in all I’m quite positive about this being more or less how it’s handled everywhere.

Now we need to figure out how many separate doctypes we really need and which of this may instead be solved by building upon the basic workflow as proposed in #23.

To accommodate for such and similar workflows, there are (at least) three ways to go forward:

Variant A: one doctype

Consolidate all steps into a single Loan doctype. Finally, the fields needed are more or less all the same, just a few status fields, assignments and permissions have to be updated, various inputs and actions enabled resp. disabled

  1. Remove “Loan application” doctype
  2. Instead model the whole process using the Workflow module

Variant B: three doctypes

There may be a point or two in keeping a finalized Loan contract separate from ay preliminary stages:

  • Reduce DX complexity
  • Fields may be similar, but tasks and “Connections” are way different
  • Signature handling and increased document security is only needed for (unilaterally binding) loan offers, (unilaterally binding) loan applications, and (bilaterally binding) loan contracts.
  • Simplify handling of lists and reports

Also, the timespan after which data may or even has to be deleted, varies a lot:

  • Very early stages such as initial requests or mere quotes that never led to an actual (unilaterally binding) loan offer or loan application may be archived and deleted after a few years (and may even have to be deleted on a recurring basis, per GDPR)
  • Once an approval process has taken place, no matter what the outcome may be, all collected data however needs to be stored for some 5 years (per regulatory law), so the quality of risk assessment, including rejections, may be analyzed by regulatory authorities.
  • Once a legally (unilaterally binding) application resp. offer has been received resp. extended, the general document retention requirements, usually five to ten years, have to be observed.
  • Once a contract has been signed, it has to be kept at least for the duration of the loan plus the general document retention requirements, usually five to ten years. If there are several contracts, this is extended to at least five years after the business relationship with the particular customers ended altogether.

Moreover, it makes a lot of sense to keep the Loan Contract even in its final stage as a mere contractual matter separate from the resulting material fact of an actual Loan. The contract, bilaterally binding as it may be, may be cancelled for various reasons, while an actual loan creates monetary and accounting facts. Once the actual Loan is disbursed, in (hopefully) most cases noone will care about the underlying contract anymore. Once disbursed, the actual Loan will be the relevant perspective and will constitute the perfect dashboard for all subsequent tasks.

In this case we would:

  1. Add a Loan Request doctype with a Loan Calculation child doctype (1:n to a given loan request) that allows creation of mere loan quotes as a PDF
  2. Turn the Loan Application doctype into a Loan Contract doctype (naming is up for discussion) that takes the data from a Loan Request and the preferred Loan Calculation.
  • The latter may initially represent a Loan Application (unilaterally binding to the customer) or a Loan Offer (unilaterally binding to the bank)
  • In the case of a Loan Application by the customer subsequently, in the submitted stage, it may be approved or denied by the bank.
  • In the case of a Loan Offer by the bank it may be approved or denied in the draft stage, before being sent to the customer.
  • Once submitted, it will constitute an actual contract that may only be cancelled or amended with bilateral agreement (a choice of amendments on the one hand and on the other hand cancelling while duplicating the values to a new draft Loan Contract should be present)
  • Once signed by both parties, it may be used as a basis for (non-technically speaking: it may be “turned“ into) the actual Loan doctype.

Variant C: five doctypes

Of course, we could also have a separate DocType for each and every document (status):

  1. Loan Request with the 1:n Loan Calculation child doctype
  2. Loan Application (unilaterally binding to the customer)
  3. Loan Offer (unilaterally binding to the bank)
  4. Loan Contract (as a result of either 3 or 4 being approved and signed by the other party)
  5. the actual Loan

Effectively there would be two more doctypes than in variant B.

Conclusion

From what I can see, both for DX and UX reasons, variant B seems the best way to go in terms of balancing simplicity of the whole doctype workflow with simplicity of each single doctype.

I would therefore propose working on an implementation of variant B, tied into Frappes Workflow module. Only in the case unforeseen problems arise, we might want to consider switching to either of variant A or variant C.

(edit: refined flowchart)

Build files preventing clean `bench update`

Information about bug

This application's distribution currently includes all built js files in the public/dist folder. By default, these should not be included in the distribution but rather built on installation. The solution is to add lending/public/dist to the .gitignore file. If the maintainers agree, I can submit a pull request.

Module

Loan Management

Version

Frappe v15, ERPNext v15, Lending develop

Installation method

manual install

Relevant log output / Stack trace / Full Error Message.

No response

Code of Conduct

  • I agree to follow this project's Code of Conduct

Rename app to “loans”

This may be late, but hopefully not too late.

The app name “lending” may appropriately cover what the app is currently capable of.

However ERPNext is currently lacking and in urgent need of bank loan functionality where the company is on the receiving end. If I remember it right, extending the loan_management module to cater for both incoming and outgoing loans, has been suggested before.

Now, while even more companies will be on the receiving end of loans than helping out employees, so incorporating one but not the other in ERPNext would be plausible, in the end the basic concepts and much of the functionality are resp. will be the same. So consolidating both directions in a single module / app seems to make a lot of sense.

However, while the name “Loan management” or “Loans” was and remains fine, the new name of the app “lending” is not.
English language distinguishes between “lending” money to someone while “borrowing” it from someone else. Only the noun “loan” is the same for both, outgoing and incoming.

Naming this app “lending” effectively manifests an architectural decision that any bank loan functionality won’t live in “lending” nor will a “bank loan” app be reusing functionality present in “lending”. That’s okay, but then we should make sure all functionality shared by lending and borrowing is incorporated directly into ERPNext. And this, I think, is exactly what wasn’t the idea behind separating it out into its own app.

So while late, there’s still no initial v1 release of “lending,” and I think we should rename it now and not later, or not at all. In the latter case most functionality common to both lending and borrowing would have to continue being incorporated into ERPNext or be duplicated in a separate “borrowing” app, or there will forever be confusion.

Implement a Loan Product doctype below Loan Type

Loan Types are the basic loan types, including but not restricted to:

  • Amortizing loans, particularly amortizing term loans
  • Non-amortizing loans, which include:
    • Non-amortizing term loans, such as bullet loans and their subtype, balloon loans
    • Revolving loans, etc.

The taxonomy is deep, asymmetric and multidimensional, so for practical reasons, we need to flatten it a bit while still allowing for proper categorization and composition of features. A bullet loan (with optional balloon features) would be considered a loan type in its own right, just as well as a term loan (with optional amortizing features).

For the Sales team or even end users, we need to break this down further by creating Loan Products. These are basically defined as instances of a Loan Type with a specific set of features, limited availability (per country/territory, entity, and party type), maximum loan amount, and other requirements, as well as a product name.

While the more technical aspects, such as accounting configuration, should optimally reside in the Loan Types and may be set up by the Back-office—comprising legal and accounting teams, risk managers, or executives—the more customer-oriented configuration should be part of the Loan Product.

Goal is that Loan Products may be freely composed and fully maintained by senior Sales officers. Breaking things such as combinations of features that may not work or aren’t allowed together, should at this point be impossible. To fully reach this goal, we will probably have to define Loan Sub-types or still a tree-like structure at a later point. This will however not be part of my effort here.

I'm already working on an implementation of the Loan Product as outlined here and will submit a PR as soon as at least the general data design is 70% complete.

Implement various amortization types for term loans

Term loans are not necessarily linearly amortized to 0.

There may be a residual value in the end, and the amortization may be progressive or (more often) degressive rather than linear. There doesn‘t even have to be any amortization, just payment of interest or not even that, and still it is a term loan, just not an amortized one.

See the list of amortization types as proposed in #54.

While we want to strip down #54 to a minimum viable product, this may be implemented independently, either right away or later. For reasons of complexity it‘s probably gonna happen later though.

Make Loan Type non-submittable

I think, the loan type needs to editable, not submittable.

While I can see that many of these settings affect all loans based on this type, and should therefore only be changed with caution, almost every single of these fields may have to be changed at a later point, purposely affecting the loans based on this type:

  • The maximum loan amount, a grace period is a business strategy decision
  • The Rate of Interest may or may not be variable. In some loan types it might be adapted to the Central Bank’s new reference rate or by refinance rates.
  • The penalty interest rate is usually governed by the Central Bank reference rate, so may change as well.
  • Days past due threshold for NPL will often be subject to changed regulations or risk assessments.
  • The mode of payment may have to change, based on available options.
  • Accounts may be restructured as well.

The only field that probably won’t and shouldn’t change is “Is Term Loan”. Actually, this is the real Loan Type (or at least one of the variants, others including Bullet Loans, Revolving Loans and various other types). Next step, a sensible approach would be a two-tiered structure with just a few basic Loan Types, each with various variants / subtypes / products. Atm, this is out of scope though.

Implementation:

Just turn the loan type into an editable DocType.

The only really tricky part is a potentially changing Rate of Interest here. We need to accommodate at least a choice of:

  • fixed-rate loan
  • variable-rate loan

with further types to be added later.

I will come up with yet another feature request focussing on this aspect, but here, in this issue, further considerations would be way out of scope.

In the meantime, let‘s just use the Loan Type‘s interest rate as an editable default when creating a new individual Loan of this type. So for now, if the Loan Type‘s interest rate changes, the individual loan will not be affected, effectively making it a fixed-rate loan for now.

The amortization structure (currently „Is term loan“) should be more prominent, too. There are several types possible, so even if we may currently only support two of them, we should use a Select field, not a checkbox.

The mode of repayment and some other aspects also need further considerations, but that’d be out of scope here. Let‘s start with what we have here!

IMG_1491

Rounding the monthly repayment amount to the next full currency unit needs to be optional

In the most basic case of a term loan, with a repayment Monthly as per repayment start date, annuities differ from what every other loan calculator I checked would come up with.

Also, the last annuity is slightly lower than all the other ones:

IMG_1553

Reason turns out to be that annuities are – always – automatically rounded to the next full currency unit – in this case from 3,226.25 to 3,227.00. Thus, in the end, slightly less than a full annuity remains open.

I can see that for some currencies, subunits are so small they may or may not be considered at all. But this needs to be some kind of optional “Round up“ feature rather than being built into the original formula.

For comparison, here are two calculators and some full repayment schedules:

Remove Loan Repayment connection from Loan Type

I have no idea why this “Connection” exists:
IMG_1526

From what I can say, it doesn’t seem to make too much sense here and should go, but maybe I’m missing something!?

(edit: sry, this is no bug. Please recategorize as I can’t.)

Disallow substantial editing of a Loan after there’s an approved Application

This one is a bug, as there’s no point in a formalized Loan Application procedure if the risk content can be substantially increased by:

  • exchanging the borrower (e.g. from Mrs. Billionaire to Mr. Bankrupt
  • raising the Loan amount
  • prolonging the repayment period
  • etc.
RPReplay_Final1694897864.mov

If we really must allow Loans be created without a prior Loan Application at all, then this should only be possible for Loan Types with a checkbox “Allow bypassing Application process”, if no Application is given.

Yes, for real life applications you would define certain thresholds of leeway for minor deviations from the initial Application. But this needs far more considerations and tools we currently don‘t have.

For now: let the approved Loan Application govern every single detail of a Loan, leaving no risk-relevant leeway at all. And allow bypassing the process if someone really wishes so.

Implement the contract number (Loan ID) as an accounting dimension

As per #56, more individualization on the accounting side is requested.

I think the best way, providing sufficient means for individualization, is perusing the Contract Number (Loan ID) as an (additional) accounting dimension to make sure every single accounting record is tagged and identifiable even amidst thousands and tens of thousands of records.

Even if it may not prove sufficient for every single use case, in most use cases or even almost all of them, the contract number is going to be a loan‘s main identifier over the whole course of a loan contract. Therefore this particular dimension should be configured out of the box, not left to admins to define and implement.

There may be an opt-out though for a couple of edge use cases. Imagine some company only administering a handful of employee loans and not wanting the whole CoA be littered with another, rarely used accounting dimension.

Apply accounting defaults to loan types

Specifying the (many!) accounts again and again for each Loan Type is quite bothersome and may lead to errors:

IMG_1563

Usually, the accounts will be mostly the same for all loan types.

Solution:
We should allow specifying defaults that may be overridden in a particular Loan Type.

Implementation:
While we may want to allow for Loan Subtypes at a later point, so would put the defaults into a root Loan Type, at the moment we should probably have a simple settings page for default loan-related accounts.

Allow Loan Partner shareables to have a minimum (partner) amount

As implemented in #35, Loan Partner currently supports shareables in terms of ratio or percentage shared.

Often, loan partners will instead expect a fixed amount or lump sum of a particular shareable revenue.

It would be nice if the Loan Partner Shareable doctype could be amended to allow fixed amounts as well.

Add dinamic payments periods and interest calculations Loan module

Is your feature request related to a problem? Please describe.
ERPNEXT has only monthly payments

Describe the solution you'd like
Add weekly, bi-weekly, monthly, quarterly, end of period loan options

Describe alternatives you've considered
Be able to select from weekly, bi-weekly, monthly, quarterly, end of period loan options, with the ability to choose between interest flat, same EMI, and decreasing principal repayment options.

Additional context

Please refer to this free excel tool for reference:

https://www.mftransparency.org/resources/calculating-transparent-pricing-tool/

Other option is to make an integration to Apache Fineract (multi-tenanted opensource microfinance platform): https://demo.mifos.io/api-docs/apiLive.htm

Implement an Interest Rate Timeline for the penalty rate

The penalty interest rate is usually governed by the Central Bank reference rate, so may change frequently while not necessarily being an arbitrary business decision.

For periods before the reference rate changed, the old interest rate needs to be used.

Take as an example, an unpaid sales invoice or loan installment due 20.06.2023.
In Germany the late payment interest rate is legally defined as 8 p.p. above the Bundesbank reference rate which itself is derived from the ECB reference rate. Effectively we‘re supposed to bill:

10.62 % for 10 days until 30.06.2023 = EUR 3.12
12.12 % for 62 days starting 01.07.2023 = EUR 10.50
= late payment interest: EUR 13.62

I don‘t have to detail how this would look like for a bill due since last year or an even older Receivable. Reference rates may change several times and still need to be correctly reflected in today’s dunnings, period by period.

To reflect this, we need a flexible and reliable mechanism that may then be used throughout ERPNext, both for standard dunnings and for our penalty interest rates here.

In frappe/erpnext#37095, I therefore proposed an Interest Rate Timeline DocType in the ERPNext queue that may then be perused by us here as well.

Next step, even a Variable-rate Loan‘s main Rate of Interest may be derived from this, but let‘s start with the lower-hanging fruit.

error while installing app

Information about bug

Installing lending...
Updating payroll setup for loans
An error occurred while installing lending: Could not find DocType: Loan
Traceback (most recent call last):
File "apps/frappe/frappe/commands/site.py", line 462, in install_app
_install_app(app, verbose=context.verbose, force=force)
File "apps/frappe/frappe/installer.py", line 309, in install_app
frappe.get_attr(fn)(name)
File "apps/hrms/hrms/setup.py", line 310, in after_app_install
create_custom_fields(SALARY_SLIP_LOAN_FIELDS)
File "apps/frappe/frappe/custom/doctype/custom_field/custom_field.py", line 32 6, in create_custom_fields
create_custom_field(doctype, df, ignore_validate=ignore_validate)
File "apps/frappe/frappe/custom/doctype/custom_field/custom_field.py", line 29 2, in create_custom_field
custom_field.insert()
File "apps/frappe/frappe/model/document.py", line 276, in insert
self._validate_links()
File "apps/frappe/frappe/model/document.py", line 905, in validate_links
frappe.throw(
("Could not find {0}").format(msg), frappe.LinkValidationError )
File "apps/frappe/frappe/init.py", line 570, in throw
msgprint(
File "apps/frappe/frappe/init.py", line 542, in msgprint
_raise_exception()
File "apps/frappe/frappe/init.py", line 491, in _raise_exception
raise raise_exception(msg)
frappe.exceptions.LinkValidationError: Could not find DocType: Loan

Module

Loan Management

Version

v15
v14

Installation method

manual install

Relevant log output / Stack trace / Full Error Message.

No response

Code of Conduct

  • I agree to follow this project's Code of Conduct

Error adding loan repayment missing column in Loan product.

Information about bug

The charges_receivable_account field is missing in Loan Product doctype.
The same field is being used in loan_repayment.py

Added stacktrace for reference.

Module

Loan Management

Version

"erpnext": "15.0.0-dev",
"frappe": "15.0.0-dev",
"india_compliance": "16.0.0-dev",
"lending": "0.0.1",

Installation method

None

Relevant log output / Stack trace / Full Error Message.

### App Versions

{
	"erpnext": "15.0.0-dev",
	"frappe": "15.0.0-dev",
	"india_compliance": "16.0.0-dev",
	"lending": "0.0.1",
}

Route

Form/Loan Repayment/LM-REP-56902

Traceback

Traceback (most recent call last):
  File "apps/frappe/frappe/app.py", line 110, in application
    response = frappe.api.handle(request)
  File "apps/frappe/frappe/api/__init__.py", line 49, in handle
    data = endpoint(**arguments)
  File "apps/frappe/frappe/api/v1.py", line 36, in handle_rpc_call
    return frappe.handler.handle()
  File "apps/frappe/frappe/handler.py", line 49, in handle
    data = execute_cmd(cmd)
  File "apps/frappe/frappe/handler.py", line 85, in execute_cmd
    return frappe.call(method, **frappe.form_dict)
  File "apps/frappe/frappe/__init__.py", line 1677, in call
    return fn(*args, **newargs)
  File "apps/frappe/frappe/utils/typing_validations.py", line 31, in wrapper
    return func(*args, **kwargs)
  File "apps/frappe/frappe/desk/form/save.py", line 37, in savedocs
    doc.submit()
  File "apps/frappe/frappe/utils/typing_validations.py", line 31, in wrapper
    return func(*args, **kwargs)
  File "apps/frappe/frappe/model/document.py", line 1038, in submit
    return self._submit()
  File "apps/frappe/frappe/model/document.py", line 1019, in _submit
    return self.save()
  File "apps/frappe/frappe/model/document.py", line 334, in save
    return self._save(*args, **kwargs)
  File "apps/frappe/frappe/model/document.py", line 386, in _save
    self.run_post_save_methods()
  File "apps/frappe/frappe/model/document.py", line 1121, in run_post_save_methods
    self.run_method("on_submit")
  File "apps/frappe/frappe/model/document.py", line 950, in run_method
    out = Document.hook(fn)(self, *args, **kwargs)
  File "apps/frappe/frappe/model/document.py", line 1316, in composer
    return composed(self, method, *args, **kwargs)
  File "apps/frappe/frappe/model/document.py", line 1298, in runner
    add_to_return_value(self, fn(self, *args, **kwargs))
  File "apps/frappe/frappe/model/document.py", line 947, in fn
    return method_object(*args, **kwargs)
  File "apps/lending/lending/loan_management/doctype/loan_repayment/loan_repayment.py", line 56, in on_submit
    self.make_gl_entries()
  File "apps/lending/lending/loan_management/doctype/loan_repayment/loan_repayment.py", line 634, in make_gl_entries
    account_details = frappe.db.get_value(
  File "apps/frappe/frappe/database/database.py", line 466, in get_value
    result = self.get_values(
  File "apps/frappe/frappe/database/database.py", line 563, in get_values
    out = self._get_values_from_table(
  File "apps/frappe/frappe/database/database.py", line 827, in _get_values_from_table
    return query.run(as_dict=as_dict, debug=debug, update=update, run=run, pluck=pluck)
  File "apps/frappe/frappe/query_builder/utils.py", line 87, in execute_query
    result = frappe.db.sql(query, params, *args, **kwargs)  # nosemgrep
  File "apps/frappe/frappe/database/database.py", line 217, in sql
    self._cursor.execute(query, values)
  File "env/lib/python3.10/site-packages/pymysql/cursors.py", line 153, in execute
    result = self._query(query)
  File "env/lib/python3.10/site-packages/pymysql/cursors.py", line 322, in _query
    conn.query(q)
  File "env/lib/python3.10/site-packages/pymysql/connections.py", line 558, in query
    self._affected_rows = self._read_query_result(unbuffered=unbuffered)
  File "env/lib/python3.10/site-packages/pymysql/connections.py", line 822, in _read_query_result
    result.read()
  File "env/lib/python3.10/site-packages/pymysql/connections.py", line 1200, in read
    first_packet = self.connection._read_packet()
  File "env/lib/python3.10/site-packages/pymysql/connections.py", line 772, in _read_packet
    packet.raise_for_error()
  File "env/lib/python3.10/site-packages/pymysql/protocol.py", line 221, in raise_for_error
    err.raise_mysql_exception(self._data)
  File "env/lib/python3.10/site-packages/pymysql/err.py", line 143, in raise_mysql_exception
    raise errorclass(errno, errval)
pymysql.err.OperationalError: (1054, "Unknown column 'charges_receivable_account' in 'field list'")

Request Data

{
	"type": "POST",
	"args": {
      REDACTED
	},
	"btn": {
		"jQuery370048498111882097251": {
			"events": {
				"click": [
					{
						"type": "click",
						"origType": "click",
						"guid": 1696,
						"namespace": ""
					}
				]
			}
		}
	},
	"freeze": true,
	"headers": {},
	"error_handlers": {},
	"url": "/api/method/frappe.desk.form.save.savedocs",
	"request_id": null
}

Response Data

{
	"exception": "pymysql.err.OperationalError: (1054, \"Unknown column 'charges_receivable_account' in 'field list'\")",
	"exc_type": "OperationalError",
	"_exc_source": "lending (app)"
}


### Code of Conduct

- [X] I agree to follow this project's Code of Conduct

Error on Saving Loan Restructure | 1054, \"Unknown column 'tabLoan Charges.event' in 'where clause'

Information about bug

When I am creating Loan Restructure below error is showing.

1054, "Unknown column 'tabLoan Charges.event' in 'where clause'

Module

Loan Management

Version

erpnext -14.x.x-develop develop
frappe -15.x.x-develop develop
hrms - 16.0.0-dev develop
lending - 0.0.1 develop

Installation method

manual install

Relevant log output / Stack trace / Full Error Message.

### App Versions

{
	"erpnext": "16.0.0-dev",
	"frappe": "16.0.0-dev",
	"hrms": "16.0.0-dev",
	"lending": "0.0.1"
}

Route

Form/Loan Restructure/new-loan-restructure-vsybeqlieg

Traceback

Traceback (most recent call last):
  File "apps/frappe/frappe/app.py", line 110, in application
    response = frappe.api.handle(request)
  File "apps/frappe/frappe/api/__init__.py", line 49, in handle
    data = endpoint(**arguments)
  File "apps/frappe/frappe/api/v1.py", line 36, in handle_rpc_call
    return frappe.handler.handle()
  File "apps/frappe/frappe/handler.py", line 49, in handle
    data = execute_cmd(cmd)
  File "apps/frappe/frappe/handler.py", line 85, in execute_cmd
    return frappe.call(method, **frappe.form_dict)
  File "apps/frappe/frappe/__init__.py", line 1704, in call
    return fn(*args, **newargs)
  File "apps/frappe/frappe/utils/typing_validations.py", line 31, in wrapper
    return func(*args, **kwargs)
  File "apps/frappe/frappe/desk/form/save.py", line 39, in savedocs
    doc.save()
  File "apps/frappe/frappe/model/document.py", line 334, in save
    return self._save(*args, **kwargs)
  File "apps/frappe/frappe/model/document.py", line 356, in _save
    return self.insert()
  File "apps/frappe/frappe/model/document.py", line 286, in insert
    self.run_before_save_methods()
  File "apps/frappe/frappe/model/document.py", line 1081, in run_before_save_methods
    self.run_method("validate")
  File "apps/frappe/frappe/model/document.py", line 950, in run_method
    out = Document.hook(fn)(self, *args, **kwargs)
  File "apps/frappe/frappe/model/document.py", line 1316, in composer
    return composed(self, method, *args, **kwargs)
  File "apps/frappe/frappe/model/document.py", line 1298, in runner
    add_to_return_value(self, fn(self, *args, **kwargs))
  File "apps/frappe/frappe/model/document.py", line 947, in fn
    return method_object(*args, **kwargs)
  File "apps/lending/lending/loan_management/doctype/loan_restructure/loan_restructure.py", line 37, in validate
    self.add_restructure_charges()
  File "apps/lending/lending/loan_management/doctype/loan_restructure/loan_restructure.py", line 154, in add_restructure_charges
    for charge in frappe.get_all(
  File "apps/frappe/frappe/__init__.py", line 1995, in get_all
    return get_list(doctype, *args, **kwargs)
  File "apps/frappe/frappe/__init__.py", line 1970, in get_list
    return frappe.model.db_query.DatabaseQuery(doctype).execute(*args, **kwargs)
  File "apps/frappe/frappe/model/db_query.py", line 199, in execute
    result = self.build_and_run()
  File "apps/frappe/frappe/model/db_query.py", line 239, in build_and_run
    return frappe.db.sql(
  File "apps/frappe/frappe/database/database.py", line 217, in sql
    self._cursor.execute(query, values)
  File "env/lib/python3.10/site-packages/pymysql/cursors.py", line 153, in execute
    result = self._query(query)
  File "env/lib/python3.10/site-packages/pymysql/cursors.py", line 322, in _query
    conn.query(q)
  File "env/lib/python3.10/site-packages/pymysql/connections.py", line 558, in query
    self._affected_rows = self._read_query_result(unbuffered=unbuffered)
  File "env/lib/python3.10/site-packages/pymysql/connections.py", line 822, in _read_query_result
    result.read()
  File "env/lib/python3.10/site-packages/pymysql/connections.py", line 1200, in read
    first_packet = self.connection._read_packet()
  File "env/lib/python3.10/site-packages/pymysql/connections.py", line 772, in _read_packet
    packet.raise_for_error()
  File "env/lib/python3.10/site-packages/pymysql/protocol.py", line 221, in raise_for_error
    err.raise_mysql_exception(self._data)
  File "env/lib/python3.10/site-packages/pymysql/err.py", line 143, in raise_mysql_exception
    raise errorclass(errno, errval)
pymysql.err.OperationalError: (1054, "Unknown column 'tabLoan Charges.event' in 'where clause'")

Request Data

{
	"type": "POST",
	"args": {
		"doc": "{\"docstatus\":0,\"doctype\":\"Loan Restructure\",\"name\":\"new-loan-restructure-vsybeqlieg\",\"__islocal\":1,\"__unsaved\":1,\"owner\":\"Administrator\",\"applicant_type\":\"Employee\",\"restructure_type\":\"Normal Restructure\",\"status\":\"\",\"company\":\"\",\"waive_off_restructure_charges\":1,\"treatment_of_normal_interest\":\"Add To First EMI\",\"unaccrued_interest_treatment\":\"Add To First EMI\",\"treatment_of_penal_interest\":\"Capitalize\",\"treatment_of_other_charges\":\"Capitalize\",\"new_repayment_method\":\"Repay Over Number of Periods\",\"applicant\":\"W003\",\"repayment_method\":\"Repay Over Number of Periods\",\"total_amount_paid\":0,\"total_principal_paid\":0,\"loan_product\":\"PL\",\"old_rate_of_interest\":0,\"old_loan_amount\":120000,\"old_emi\":5000,\"current_restructure_count\":0,\"pre_restructure_dpd\":0,\"disbursed_amount\":120000,\"loan\":\"ACC-LOAN-2023-00003\",\"idx\":0,\"old_tenure\":0,\"completed_tenure\":0,\"total_overdue_amount\":0,\"restructure_charges\":0,\"pending_principal_amount\":120000,\"available_security_deposit\":null,\"principal_overdue\":0,\"principal_adjusted\":0,\"balance_principal\":0,\"interest_overdue\":0,\"unaccrued_interest\":0,\"penalty_overdue\":0,\"charges_overdue\":0,\"adjusted_interest_amount\":0,\"adjusted_unaccrued_interest\":0,\"interest_waiver_amount\":0,\"unaccrued_interest_waiver\":0,\"penal_interest_waiver\":0,\"other_charges_waiver\":0,\"balance_interest_amount\":0,\"balance_unaccrued_interest\":0,\"balance_penalty_amount\":0,\"balance_charges\":0,\"new_rate_of_interest\":0,\"new_repayment_period_in_months\":48,\"new_monthly_repayment_amount\":0,\"new_loan_amount\":0,\"restructure_date\":\"2023-12-11\",\"repayment_start_date\":\"2024-01-01\"}",
		"action": "Save"
	},
	"btn": {
		"jQuery3700076979342372257561": {
			"events": {
				"click": [
					{
						"type": "click",
						"origType": "click",
						"guid": 1215,
						"namespace": ""
					}
				]
			}
		}
	},
	"freeze": true,
	"headers": {},
	"error_handlers": {},
	"url": "/api/method/frappe.desk.form.save.savedocs",
	"request_id": null
}

Response Data

{
	"exception": "pymysql.err.OperationalError: (1054, \"Unknown column 'tabLoan Charges.event' in 'where clause'\")",
	"exc_type": "OperationalError",
	"_exc_source": "lending (app)"
}


### Code of Conduct

- [X] I agree to follow this project's Code of Conduct

Error on installing Lending

Information about bug

An error occurred while installing lending: HTTPSConnectionPool(host='api.github.com', port=443): Max retries exceeded with url: /repos/frappe/erpnext (Caused by NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x7f26b7c13250>: Failed to establish a new connection: [Errno -2] Name or service not known'))

Module

Loan Management

Version

Frappe version 14.48.1
Erpnext version v14.38.0

Installation method

manual install

Relevant log output / Stack trace / Full Error Message.

An error occurred while installing lending: HTTPSConnectionPool(host='api.github.com', port=443): Max retries exceeded with url: /repos/frappe/erpnext (Caused by NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x7f26b7c13250>: Failed to establish a new connection: [Errno -2] Name or service not known'))
Traceback (most recent call last):
  File "apps/frappe/frappe/installer.py", line 218, in fetch_details_from_tag
    org, repo = org_repo
ValueError: not enough values to unpack (expected 2, got 1)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "env/lib/python3.10/site-packages/urllib3/connection.py", line 174, in _new_conn
    conn = connection.create_connection(
  File "env/lib/python3.10/site-packages/urllib3/util/connection.py", line 72, in create_connection
    for res in socket.getaddrinfo(host, port, family, socket.SOCK_STREAM):
  File "/usr/lib/python3.10/socket.py", line 955, in getaddrinfo
    for res in _socket.getaddrinfo(host, port, family, type, proto, flags):
socket.gaierror: [Errno -2] Name or service not known

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "env/lib/python3.10/site-packages/urllib3/connectionpool.py", line 703, in urlopen
    httplib_response = self._make_request(
  File "env/lib/python3.10/site-packages/urllib3/connectionpool.py", line 386, in _make_request
    self._validate_conn(conn)
  File "env/lib/python3.10/site-packages/urllib3/connectionpool.py", line 1042, in _validate_conn
    conn.connect()
  File "env/lib/python3.10/site-packages/urllib3/connection.py", line 363, in connect
    self.sock = conn = self._new_conn()
  File "env/lib/python3.10/site-packages/urllib3/connection.py", line 186, in _new_conn
    raise NewConnectionError(
urllib3.exceptions.NewConnectionError: <urllib3.connection.HTTPSConnection object at 0x7f26b7c13250>: Failed to establish a new connection: [Errno -2] Name or service not known

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "env/lib/python3.10/site-packages/requests/adapters.py", line 486, in send
    resp = conn.urlopen(
  File "env/lib/python3.10/site-packages/urllib3/connectionpool.py", line 787, in urlopen
    retries = retries.increment(
  File "env/lib/python3.10/site-packages/urllib3/util/retry.py", line 592, in increment
    raise MaxRetryError(_pool, url, error or ResponseError(cause))
urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='api.github.com', port=443): Max retries exceeded with url: /repos/frappe/erpnext (Caused by NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x7f26b7c13250>: Failed to establish a new connection: [Errno -2] Name or service not known'))

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "apps/frappe/frappe/commands/site.py", line 415, in install_app
    _install_app(app, verbose=context.verbose, force=force)
  File "apps/frappe/frappe/installer.py", line 268, in install_app
    required_app = parse_app_name(app)
  File "apps/frappe/frappe/installer.py", line 248, in parse_app_name
    _, repo, _ = fetch_details_from_tag(name)
  File "apps/frappe/frappe/installer.py", line 220, in fetch_details_from_tag
    org, repo = find_org(org_repo[0])
  File "apps/frappe/frappe/installer.py", line 188, in find_org
    response = requests.head(f"https://api.github.com/repos/{org}/{org_repo}")
  File "env/lib/python3.10/site-packages/requests/api.py", line 100, in head
    return request("head", url, **kwargs)
  File "env/lib/python3.10/site-packages/requests/api.py", line 59, in request
    return session.request(method=method, url=url, **kwargs)
  File "env/lib/python3.10/site-packages/requests/sessions.py", line 589, in request
    resp = self.send(prep, **send_kwargs)
  File "env/lib/python3.10/site-packages/requests/sessions.py", line 703, in send
    r = adapter.send(request, **kwargs)
  File "env/lib/python3.10/site-packages/requests/adapters.py", line 519, in send
    raise ConnectionError(e, request=request)
requests.exceptions.ConnectionError: HTTPSConnectionPool(host='api.github.com', port=443): Max retries exceeded with url: /repos/frappe/erpnext (Caused by NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x7f26b7c13250>: Failed to establish a new connection: [Errno -2] Name or service not known'))

Code of Conduct

  • I agree to follow this project's Code of Conduct

Implement tiered interest margin lists

For various reasons, interest margins are usually tiered by loan amount. Large loans may be just a bit cheaper than small loans:

IMG_1620

I initially implemented a proof of concept of this feature in #54, however per discussion in #19, we want to strip this overly large and slightly complex PR to a minimum viable product and introduce additional features in separate tickets.

Implementation should be as follows:

  • Allow the back office to define a bandwidth of interest margins to be available for Loan Products of this Loan Type.
  • Allow the product / sales manager, when defining a Loan Product, to either pick a particular margin for a rather standardized product or to stick with the bandwidth for full flexibility on the Loan Application side or to further reduce the bandwidth appropriately. Expanding it should obviously not be supported on the Loan Product side.

All of this per tier, so administrative and refinancing costs may be appropriately reflected in the resulting end price (interest rate).

Obviously, implementation is postponed on #54.

loan repayment not reducing loan amount and also not generating any ledger transaction

Information about bug

When repaying the loan, the amount paid does not reduce loan (capital and interest). In one example, I paid the total loan including interest however, when trying to close the loan, the system, still showing a debt of the same amount since contract was issued
Screenshot 2023-12-14 at 20 28 14
Screenshot 2023-12-14 at 20 28 05
Screenshot 2023-12-14 at 20 24 27

Module

Loan Management

Version

Screenshot 2023-12-14 at 20 21 37

Installation method

None

Relevant log output / Stack trace / Full Error Message.

No response

Code of Conduct

  • I agree to follow this project's Code of Conduct

Write off creates numerous useless drafts

Minor bug, but still annoying:

Skipping the first step was probably supposed to streamline the task of writing off.

But it is very much inconsistent to all the other submittable documents and creates lots of drafts on a single click, if then the Write Off is not submitted:

IMG_1493
IMG_1494

If the Write Off account isn‘t set in the Company doc, the auto-save-on-click trick fails with a semi-helpful message:
IMG_1495
This is even though the Write Off account could actually be added in the document, but is trying to be saved before shown.

Sticking with the regular two-step workflow might in the end be the better solution. Finally, why would Write Offs be a routine thing at all? And if they‘re not, they‘ll probably need more rather than less safeguards.

Multiple bugs when trying to enter Loan Security Details

Information about bug

  1. Create new Loan Security via Quick Entry without the chance to enter a price => “No valid Loan Security Price found”
  2. Now trying to enter the “Loan Security Price” in the child table => field is disabled
  3. Now trying to edit the Row in the form => No “Loan Security Price“ field there.
  4. Trying to enter an Amount => ends up getting reset to 0 every time.
  5. Trying to enter at least a Quantity => application freezes completely, browser tab needs to be closed.

Finally:
6. How is the (diminishing) value of a security at any point a “Price”? It’s not (yet) up for sale, and probably won’t be ever, so it may just be called a (Loan Security) “Market Value”.

RPReplay_Final1698136138.mov

Of course I do know that Loan Security Prices are a separate table and that the Amount is Price x Qty. But do I care? And does the user know or care? When entering a security at a given moment, noone cares about a timeline of values. At the moment there is a single value, and the rest should either be deferred to a later point or handled silently in the background.

So we should either autocreate a “Price” (actually “Market Value”) doc, either when saving the Loan Security doc in the first place (and update it every time it may be changed). Or, maybe better, only create a “Price” (or “Market Value”) doc from an “Initial Price” or “Initial Market Value” as entered initially, once needed. When exactly it may be needed, we will figure out step by step.

To fix every single of these bugs, we need to make sure one fix doesn’t move the rest out of sight. Probably best to start with the freezing, which may be the worst one.

Module

Loan Management

Version

All dev

Installation method

manual install

error while submit Salary slip, in produce loan

Information about bug

while process the salary slip it throws follwoing error - (1054, "Unknown column 'charges_receivable_account' in 'field list'")

I can't see any field in tabLoan Product table, should be the bug ,pls check

Module

Loan Management

Version

Frappe- 15
Leanding

Installation method

manual install

Relevant log output / Stack trace / Full Error Message.

sql = b"SELECT `interest_receivable_account`,`suspense_interest_receivable`,`suspense_interest_income`,`interest_income_account`,`charges_receivable_account` FROM `tabLoan Product` WHERE `name`='SEL' ORDER BY `modified` DESC LIMIT 1"
      unbuffered = False
  File "env/lib/python3.10/site-packages/pymysql/connections.py", line 822, in _read_query_result
    result.read()
      self = <pymysql.connections.Connection object at 0x7f553296cd60>
      unbuffered = False
      result = <pymysql.connections.MySQLResult object at 0x7f5533ce1e70>
  File "env/lib/python3.10/site-packages/pymysql/connections.py", line 1200, in read
    first_packet = self.connection._read_packet()
      self = <pymysql.connections.MySQLResult object at 0x7f5533ce1e70>
  File "env/lib/python3.10/site-packages/pymysql/connections.py", line 772, in _read_packet
    packet.raise_for_error()
      self = <pymysql.connections.Connection object at 0x7f553296cd60>
      packet_type = <class 'pymysql.protocol.MysqlPacket'>
      buff = bytearray(b"\xff\x1e\x04#42S22Unknown column \'charges_receivable_account\' in \'field list\'")
      packet_header = b'D\x00\x00\x01'
      btrl = 68
      btrh = 0
      packet_number = 1
      bytes_to_read = 68
      recv_data = b"\xff\x1e\x04#42S22Unknown column 'charges_receivable_account' in 'field list'"
      packet = <pymysql.protocol.MysqlPacket object at 0x7f5530fd4190>
  File "env/lib/python3.10/site-packages/pymysql/protocol.py", line 221, in raise_for_error
    err.raise_mysql_exception(self._data)
      self = <pymysql.protocol.MysqlPacket object at 0x7f5530fd4190>
      errno = 1054
  File "env/lib/python3.10/site-packages/pymysql/err.py", line 143, in raise_mysql_exception
    raise errorclass(errno, errval)
      data = b"\xff\x1e\x04#42S22Unknown column 'charges_receivable_account' in 'field list'"
      errno = 1054
      errval = "Unknown column 'charges_receivable_account' in 'field list'"
      errorclass = <class 'pymysql.err.OperationalError'>
pymysql.err.OperationalError: (1054, "Unknown column 'charges_receivable_account' in 'field list'")

Code of Conduct

  • I agree to follow this project's Code of Conduct

Multiple payment methods while lending

Is your feature request related to a problem? Please describe.

Currently, it looks like it is not possible to lend using multiple payment methods, i.e. partially by cash and remaining by bank transfer, UPI etc.

As per Registrar General of Money Lenders, Maharashtra State this limit is 20,000.
(https://sahakarayukta.maharashtra.gov.in/site/upload/documents/Circular%2028%20Aug%202018.pdf)

Describe the solution you'd like

From my pov solution looks like:

  1. Single doctype which defines this limit.
  2. A payment screen/section where multiple mode of payments (mop) are available.
  3. While making payment with mode of payment as cash check if this limit is obeyed, if not, error screen is shown and entered lending value for cash mop is auto-updated to 20,000 (as defined in single doctype) and remaining amount is taken for bank transfer mop.
  4. Such accounting effects are made against cash a/c and bank a/c.

Describe the alternatives you've considered

No response

Additional context

No response

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.