Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix finance.routingNumber() implementation #3290

Open
woldaker opened this issue Nov 30, 2024 · 10 comments · May be fixed by #3429
Open

Fix finance.routingNumber() implementation #3290

woldaker opened this issue Nov 30, 2024 · 10 comments · May be fixed by #3429
Assignees
Labels
c: bug Something isn't working m: finance Something is referring to the finance module p: 1-normal Nothing urgent s: accepted Accepted feature / Confirmed bug
Milestone

Comments

@woldaker
Copy link

woldaker commented Nov 30, 2024

Problem Description

There are rules regarding what is and isn't possibly a legitimate routing number according to the American Bankers Association and/or the Federal Reserve. As of now, faker complies with only a part of this ruleset (the check digit validation), but based on a few tests I ran locally, the Federal Reserve Routing Symbol (the first 4 digits) and the Institution Identifier (the next 4 digits) of FinanceModule.routingNumber have failed to correspond to an actual, usable-in-the-wild value.

Note: This proposal is primarily concerned with modifications that would produce a routing number with a valid Federal Reserve Routing Symbol (first 4 digits), and not the Institution Identifier (next 4 digits). Also note that, despite using the words "in the wild", that is not the goal of this proposal, but rather to produce a routing number that is significantly closer to what a real, usable routing number would be than what faker currently produces.

Suggested solution (if the proposed data meets all requirements for licensing/copyright)

Link to "Proposed Data"

In FinanceModule.routingNumber():

digits [0-3] (Federal Reserve Routing Symbol) = Pull from a static lookup table derived from the proposed data.
digits [4-7] (Institution Identifier) = 4 random digits. (I am not proposing to attempt to solve this problem.)
digits[8] (Check Digit) = derived from digits[0-7]

Alternative (if the proposed data does NOT meet requirements for licensing/copyright)

digits [0-1] (Federal Reserve District Identitifer) = Random number between 1 and 12, left-padded with a zero. This would correspond to the 12 federal reserve banks, and would be better than nothing at all.

Note: '00' is reserved for U.S. government use and, in my opinion, should not be allowed to be produced as [I assume] almost anybody using this library is not going to be concerned with routing numbers starting with '00', but that may be a false assumption; you tell me.

digits [2-3] (Federal Reserve Branch Office City Identifier) = 2 random digits, left-padded with a zero.

Note: The wikipedia page for ABA Routing Numbers lists what appears to be all of these, but no source is cited, and therefore cannot be used as a source of truth. Furthermore, it lists a 3-digit value '101' as belonging to American territories such as American Samoa, Puerto Rico, Guam, etc., which doesn't make much sense. Also, this isn't strictly necessary for the proposal, anyway.

The rest is the same as the primary proposed solution:

digits [4-7] (Institution Identifier) = 4 random digits.
digits[8] (Check Digit) = derived from digits[0-7]

Additional context

The trouble with implementing a feature like this is that technically, the "rules" surrounding what does or does not constitute a routing number which corresponds to a real financial institution are always in flux. However, practically, the majority of these rules either have never changed since the Federal Reserve's inception in 1913, as far as I can tell anyway (e.g. routing numbers starting in '80' for traveler's checks), or have not changed in such a long time that they can be effectively treated as though they've never changed (e.g. "thrift" institutions codes have not changed since the mid-1980s). Therefore, even if the updates to the rules vs this library were not fully in sync, there would still be a vastly improved chance of getting a valid, real routing number than otherwise. The main part which I believe can be improved is that of the Federal Reserve Routing Symbol, which is simply the first 4 characters of the routing number, which is further broken down as the first 2 characters designating the Federal Reserve District and the second 2 characters designating the city of the reserve branch within that district. These do not change very often (I'm not entirely sure, after some research, the last time they have).

You can check validation here (https://routingnumber.aba.com/Search1.aspx) to see for yourself (one simple test is to use '522814402' (the routing number given in the comment above the function definition), but this is a business and using that API is of course not viable for an open-source product. I mentioned this simply as a quick way to verify the legitimacy of the need for this feature.

And just in case this point is raised, I suppose I can address it with my own opinion now. It is arguable that since faker's purpose is to produce fake data anyway, it shouldn't need to be a real financial institution at all. However, I am of the opinion that since test code will inevitably use portions of production code, and it cannot be assumed that that production code was written in a way that makes it feasible to isolate its mechanics from its semantics, it should not be a concern for those using this library to need to differentiate between a valid (real-world) routing number and an invalid routing number that simply passes check digit validation.

Furthermore, it may be best simply to augment the existing functionality of routingNumber() to just return one with either its first 4 digits from the lookup table or the first 2 constrained to between '01' - '12', and not have an optional boolean argument at all. After all, using the proposed boolean switch should simply produce a routing number that is a member of a subset of all the routing numbers that it currently produces, so any valid routing number when using the switch should also be among the set of those produced without it.

@woldaker woldaker added c: feature Request for new feature s: pending triage Pending Triage s: waiting for user interest Waiting for more users interested in this feature labels Nov 30, 2024
@woldaker woldaker changed the title Change finance.routingNumber() to take an optional boolean argument which forces the result to correspond to a real financial institution. Change finance.routingNumber() to take an optional boolean argument which forces the result to attempt to correspond to a real financial institution. Nov 30, 2024
@xDivisionByZerox xDivisionByZerox added s: needs decision Needs team/maintainer decision m: finance Something is referring to the finance module and removed s: pending triage Pending Triage labels Nov 30, 2024
@xDivisionByZerox
Copy link
Member

I'll mark this with "needs decision" since I'm not sure whether a boolean flag or "fixing" te current implementation is the right way to go here.

@ST-DDT ST-DDT added this to the vAnytime milestone Dec 19, 2024
@ST-DDT ST-DDT added c: bug Something isn't working s: accepted Accepted feature / Confirmed bug p: 1-normal Nothing urgent and removed c: feature Request for new feature s: needs decision Needs team/maintainer decision s: waiting for user interest Waiting for more users interested in this feature labels Dec 19, 2024
@faker-js faker-js deleted a comment from github-actions bot Dec 19, 2024
@ST-DDT
Copy link
Member

ST-DDT commented Dec 19, 2024

faker.finance.routingNumber

Team Decision

In our opinion, the current behavior is insufficient => a bug.
The method should return valid routing numbers if possible or at least match simple validation patterns.

  • digits [0-3] (Federal Reserve Routing Symbol) = Lookup table without 00 prefix
  • digits [4-7] (Institution Identifier) = 4 random digits
  • digits[8] (Check Digit) = derived from digits[0-7]

The lookup table should be statically referenced in the implementation to allow for tree-shaking and to simplify potential data structure refactors (e.g. adding a district option).

@woldaker Would you like to create a PR for this?

@woldaker
Copy link
Author

woldaker commented Dec 19, 2024 via email

@ST-DDT ST-DDT changed the title Change finance.routingNumber() to take an optional boolean argument which forces the result to attempt to correspond to a real financial institution. Fix finance.routingNumber() implementation Dec 24, 2024
@ST-DDT
Copy link
Member

ST-DDT commented Mar 1, 2025

@woldaker How are you doing? Are you still interested in contributing this feature?

@woldaker
Copy link
Author

woldaker commented Mar 1, 2025 via email

@ST-DDT
Copy link
Member

ST-DDT commented Mar 1, 2025

No hurry and thanks for your fast response ❤️

@woldaker
Copy link
Author

woldaker commented Mar 1, 2025

A few questions for you:

  1. From what I see in the code and from what I've read in the contribution guide, I am assuming that the static lookup data should go in a newly-added file at path src/modules/finance/routing-number.ts?

EDIT: I also found, as a precedent: src/modules/commerce/index.ts which has ISBN_LENGTH_RULES at the top of the file. That actually looks much more like the kind of static lookup data you're thinking of. Now I'm thinking that's the precedent I need to follow, and therefore just put the data either at the top of the src/modules/finance/index.ts file or directly above the routingNumber() method.

EDIT 2: Now I'm looking through the src/locales/ directory, and I'm also seeing static lookup data in there. I am assuming that you don't want me to add this to anything locale-specific. That just wouldn't make sense. It's always a US ABA routing number, no matter who's requesting it, and there's nothing locale-specific about it. But it does raise the option of putting that data into the newly-added file src/locales/base/database/finance/routing-number.ts. Something doesn't feel quite right about doing that though, in my opinion, simply because as I mentioned, this really isn't locale-related at all, so putting it anywhere in the locales directory just feels off.

For now I'm just going to put it in src/modules/finance/index.ts, right above the module. I guess I'll see what happens on the PR if that's acceptable or not.

EDIT 3: Okay I finally figured it out. It will go in src/locales/base/finance/*

  1. I view SWIFT/BIC numbers as just a different kind of routing number, and therefore found the function name being simply routingNumber() and not something like abaRoutingNumber() a little confusing. Obviously the function name can't just change now due to regression, but should an alias be made so that abaRoutingNumber() calls routingNumber()?

EDIT: Sorry forgot to ping you, not sure if you'd ever see this otherwise @ST-DDT

@woldaker
Copy link
Author

woldaker commented Mar 1, 2025

I've never actually submitted a PR in github before. I hope I did it right.

Here is the PR.

@ST-DDT

@matthewmayer
Copy link
Contributor

  1. I view SWIFT/BIC numbers as just a different kind of routing number, and therefore found the function name being simply routingNumber() and not something like abaRoutingNumber() a little confusing. Obviously the function name can't just change now due to regression, but should an alias be made so that abaRoutingNumber() calls routingNumber()?

While routingNumber is perhaps not the ideal name, the costs of changing it probably outweigh just leaving it for now. If in the future there'a a request to add a different type of routing number, we could consider changing it then.

@ST-DDT
Copy link
Member

ST-DDT commented Mar 2, 2025

EDIT: Sorry forgot to ping you, not sure if you'd ever see this otherwise @ST-DDT

No problem. I see the messages either way. Pinging me is usually not necessary unless I forgot to react to a previous message.

I've never actually submitted a PR in github before. I hope I did it right.

Looks good to me. I will review it soon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c: bug Something isn't working m: finance Something is referring to the finance module p: 1-normal Nothing urgent s: accepted Accepted feature / Confirmed bug
Projects
None yet
4 participants