kontonummer
Version:
A validator for swedish banking numbers
182 lines (141 loc) • 6.27 kB
Markdown
# Kontonummer
[](https://github.com/swantzter/kontonummer/actions/workflows/qa.yml)
[](https://github.com/swantzter/kontonummer/actions/workflows/release.yml)
[](https://codecov.io/gh/swantzter/kontonummer)
> [!IMPORTANT]
> Currently implements the 2024-02-22 version of the
> [Bank Account Numbers in Swedish Banks](https://www.bankgirot.se/globalassets/dokument/anvandarmanualer/bankernaskontonummeruppbyggnad_anvandarmanual_sv.pdf)
> specification from Bankgirot.
This is a reimagination of [jop-io/kontonummer.js](https://github.com/jop-io/kontonummer.js)
with some additional goals:
- Provide a similar API to [Personnummer](https://personnummer.dev)
- Stretch goal: Calculate IBAN (and BIC/SWIFT-code)
- Stretch goal: Handle BankGirot and PlusGirot numbers
Some Code (c) [Jonas Persson](https://github.com/jop-io) and
[Tobbe Lundberg](https://github.com/Tobbe) which they have gracefully released
under a MIT license. See [LICENSE](LICENSE)
This implementation is written in TypeScript but the following specification
should be applicable to other languages as well. But some language specific
modifications may be required.
## Important Caveat
As explained in the [research](#research) section below there are some bank
account numbers that are impossible to validate (as they do not have a check
digit) that are indistinguishable from validatable accounts. I recommend using
this library on form input fields, but do not prevent form submission if the
account number is reported as invalid. A good idea would be something like a
warning saying "There is a chance this is not a valid bank account number;
you may want to double-check."
## Specification [v1]
### Class
The package should include a class that which should be the return value of `parse`
```typescript
class Kontonummer {
constructor (sortingCode: string | number, accountNumber: string | number, options?: InitOptions)
constructor (sortingCodeAndAccountNumber: string | number, options?: InitOptions)
}
```
- `sortingCode` (sv. clearing nummer) should be one of the following formats
- `SSSS`
- `SSSS-C`
- `accountNumber` the allowed length varies, further explained in section
[Account Number](#account-number)
White-space should be allowed in any position. Basically, only characters
matching the regex `/\d/` should be taken into consideration; all other
characters should be discarded.
- `sortingCodeAndAccountNumber` should be one of the following formats
(where `S` is sorting code, `A` is account number and `C` is a check digit.
White-space should be allowed in any position. Basically, only characters
matching the regex `/\d/` should be taken into consideration; all other
characters should be discarded.
- `SSSS,AC`
- `SSSSAC`
- `S-C,AC`
- `S-CAC`
- `S-C,A-C`
- `S-CA-C`
- etc.
### `InitOptions`
- `mode: 'strict' | 'semi' | 'lax'`
- `strict` should validate sorting code, account number length and account
number check digit. Should throw if any of these checks fail.
- `semi` should do strict checks for type 1 account numbers (4+7) but lax
checks for type 2 account numbers.
- `lax` should not throw if the check digit of the account number cannot be
validated. Should instead set the `valid` property to false if the check
digit or length is invalid. Should still throw for invalid sorting codes.
### Properties
The class should expose the following properties once initialised
```typescript
class Kontonummer {
readonly bankName: string
readonly sortingCode: string
readonly accountNumber: string
readonly type: 1 | 2
readonly comment: 1 | 2 | 3
readonly valid: boolean // only relevant in `lax` mode
}
```
### Errors
All methods except for `validate` should throw an exception or return an error
as a second return value. Error handling may be different depending on language.
The exception/error class should be prefixed with `Kontonummer`.
### Parse
The class should include a static `parse` method that creates a new instance of
the class. It should take the same arguments as the class constructor. This
function should also be an exported standalone method of the package.
Pseudocode:
```typescript
class Kontonummer {
static parse (...args) {
return new Kontonummer(...args)
}
}
export const parse = Kontonummer.parse
```
### Validate
The class should include a static `validate` method that attempts to parse the
provided input and returns a boolean that indicates if it succeeded. `validate`
should not accept any options. This function should also be an exported
standalone method of the package.
Pseudocode:
```typescript
class Kontonummer {
validate (sortingCode, accountNumber)
validate (sortingCodeAndAccountNumber) {
try {
new Kontonummer(sortingCode, accountNumber)
return true
} catch {
return false
}
}
}
export const validate = Kontonummer.validate
```
### Format
Format key:
- `S`: Sorting Code
- `A`: Account number
- `C`: Check digit
- `K`: IBAN check digit
- `B`: IBAN bank code
The class should include a public `format` method that returns the sortingCode
and accountNumber in one string. Some different formats should be available.
If no argument is provided it should default to `numeric`.
```typescript
type Format = 'numeric' | 'pretty'
type Part = 'full' | 'sortingCode' | 'accountNumber'
class Kontonummer {
format (format?: Format = 'numeric', part?: Part = 'full'): string
}
```
| Name | Format |
| ---- | ---- |
| **numeric**<br/>_(default)_ | `S[C]AC`<br/>where the account number is padded to the appropriate max length depending on account type |
| pretty | Depends on type and bank, see [research](#research) below |
<!-- | separated | `S[C],AC` |
| separated-check | `S[-C],A-C` |
| grouped | TBD | -->
`[]` brackets marks optional
## [Research](https://i.imgur.com/5wuurYD.png)
**Moved** to [swantzter.se](https://swantzter.se/deep-dives/kontonummer) where I plan to publish research on other topics as well