diff --git a/Makefile b/Makefile index 55dc220..31cb71e 100644 --- a/Makefile +++ b/Makefile @@ -10,8 +10,10 @@ default: build build: test go install -v ./... -.PHONY: generate -generate: +$(GOBIN)/banking-registry: + cd registry; go install ./cmd/banking-registry + +generate: $(GOBIN)/banking-registry go generate -v ./... .PHONY: test diff --git a/docs/registry.yml b/docs/registry.yml index 1eda01a..12392b3 100644 --- a/docs/registry.yml +++ b/docs/registry.yml @@ -460,6 +460,14 @@ countries: account_number: 3:13 sepa: false + - code: MN + name: Mongolia + IBAN: MN2!n4!n12!n + BBAN: 4!n12!n + bank_code: 0:4 + account_number: 4:16 + sepa: false + - code: MR name: Mauritania IBAN: MR2!n5!n5!n11!n2!n @@ -488,6 +496,14 @@ countries: account_number: 8:26 sepa: false + - code: NI + name: Nicaragua + IBAN: NI2!n4!a20!n + BBAN: 4!a20!n + bank_code: 0:4 + account_number: 4:24 + sepa: false + - code: NL name: The Netherlands IBAN: NL2!n4!a10!n diff --git a/iban/bban_helper.go b/iban/bban_helper.go index c0707c2..227aa53 100644 --- a/iban/bban_helper.go +++ b/iban/bban_helper.go @@ -120,12 +120,16 @@ func GetBBAN(iban string) (BBAN, error) { return getMontenegroBBAN(iban) case mk: return getMacedoniaBBAN(iban) + case mn: + return getMongoliaBBAN(iban) case mr: return getMauritaniaBBAN(iban) case mt: return getMaltaBBAN(iban) case mu: return getMauritiusBBAN(iban) + case ni: + return getNicaraguaBBAN(iban) case nl: return getTheNetherlandsBBAN(iban) case no: diff --git a/iban/bban_test.go b/iban/bban_test.go index c7380d8..df67ed3 100644 --- a/iban/bban_test.go +++ b/iban/bban_test.go @@ -853,6 +853,28 @@ func TestBBAN(t *testing.T) { AccountNumber: "001000100141", }, }, + { + iban: "MN121234123456789123", + wantErr: false, + bban: iban.BBAN{ + BBAN: "1234123456789123", + BankCode: "1234", + BranchCode: "", + NationalChecksum: "", + AccountNumber: "123456789123", + }, + }, + { + iban: "NI45BAPR00000013000003558124", + wantErr: false, + bban: iban.BBAN{ + BBAN: "BAPR00000013000003558124", + BankCode: "BAPR", + BranchCode: "", + NationalChecksum: "", + AccountNumber: "00000013000003558124", + }, + }, } for _, tt := range tests { t.Run(tt.iban, diff --git a/iban/checksum_test.go b/iban/checksum_test.go index 92d2550..913fbd3 100644 --- a/iban/checksum_test.go +++ b/iban/checksum_test.go @@ -78,6 +78,7 @@ func TestChecksum(t *testing.T) { {iban: "IQ98NBIQ850123456789012", want: "98"}, {iban: "BR9700360305000010009795493P1", want: "97"}, {iban: "DK0206715394960066", want: "02"}, + {iban: "NI45BAPR00000013000003558124", want: "45"}, } for _, tt := range tests { tt := tt diff --git a/iban/country_constants.go b/iban/country_constants.go index e86f667..fd31f96 100644 --- a/iban/country_constants.go +++ b/iban/country_constants.go @@ -109,12 +109,16 @@ const ( me = "ME" // Country Code Macedonia mk = "MK" + // Country Code Mongolia + mn = "MN" // Country Code Mauritania mr = "MR" // Country Code Malta mt = "MT" // Country Code Mauritius mu = "MU" + // Country Code Nicaragua + ni = "NI" // Country Code The Netherlands nl = "NL" // Country Code Norway diff --git a/iban/country_mongolia.go b/iban/country_mongolia.go new file mode 100644 index 0000000..49a14f3 --- /dev/null +++ b/iban/country_mongolia.go @@ -0,0 +1,56 @@ +// Code generated by banking/registry; DO NOT EDIT. + +package iban + +import ( + "fmt" + "github.com/jacoelho/banking/ascii" + "github.com/jacoelho/banking/pool" +) + +// validateMongoliaIBAN validates Mongolia IBAN +func validateMongoliaIBAN(iban string) error { + if len(iban) != 20 { + return fmt.Errorf("unexpected length, want: 20: %w", ErrValidation) + } + + if subject := iban[0:2]; subject != "MN" { + return fmt.Errorf("static value rule, pos: 0, expected value: MN, found %s: %w", subject, ErrValidation) + } + + if subject := iban[2:20]; !ascii.Every(subject, ascii.IsDigit) { + return fmt.Errorf("range rule, start pos: 2, length: 18, expected type Digit, found %s: %w", subject, ErrValidation) + } + + if c := checksum(iban); c != iban[2:4] { + return fmt.Errorf("incorrect checksum: %w", ErrValidation) + } + + return nil +} + +// generateMongoliaIBAN generates Mongolia IBAN +func generateMongoliaIBAN() (string, error) { + sb := pool.BytesPool.Get() + defer sb.Free() + + sb.WriteString("MN") + ascii.Digits(sb, 18) + + return ReplaceChecksum(sb.String()) +} + +// getMongoliaBBAN retrieves BBAN structure from Mongolia IBAN +func getMongoliaBBAN(iban string) (BBAN, error) { + if len(iban) != 20 { + return BBAN{}, fmt.Errorf("unexpected length, want: 20: %w", ErrValidation) + } + + return BBAN{ + BBAN: iban[4:20], + BankCode: iban[4:8], + BranchCode: "", + NationalChecksum: "", + AccountNumber: iban[8:20], + }, nil +} diff --git a/iban/country_nicaragua.go b/iban/country_nicaragua.go new file mode 100644 index 0000000..573799f --- /dev/null +++ b/iban/country_nicaragua.go @@ -0,0 +1,66 @@ +// Code generated by banking/registry; DO NOT EDIT. + +package iban + +import ( + "fmt" + "github.com/jacoelho/banking/ascii" + "github.com/jacoelho/banking/pool" +) + +// validateNicaraguaIBAN validates Nicaragua IBAN +func validateNicaraguaIBAN(iban string) error { + if len(iban) != 28 { + return fmt.Errorf("unexpected length, want: 28: %w", ErrValidation) + } + + if subject := iban[0:2]; subject != "NI" { + return fmt.Errorf("static value rule, pos: 0, expected value: NI, found %s: %w", subject, ErrValidation) + } + + if subject := iban[2:4]; !ascii.Every(subject, ascii.IsDigit) { + return fmt.Errorf("range rule, start pos: 2, length: 2, expected type Digit, found %s: %w", subject, ErrValidation) + } + + if subject := iban[4:8]; !ascii.Every(subject, ascii.IsUpperCaseLetter) { + return fmt.Errorf("range rule, start pos: 4, length: 4, expected type UpperCaseLetters, found %s: %w", subject, ErrValidation) + } + + if subject := iban[8:28]; !ascii.Every(subject, ascii.IsDigit) { + return fmt.Errorf("range rule, start pos: 8, length: 20, expected type Digit, found %s: %w", subject, ErrValidation) + } + + if c := checksum(iban); c != iban[2:4] { + return fmt.Errorf("incorrect checksum: %w", ErrValidation) + } + + return nil +} + +// generateNicaraguaIBAN generates Nicaragua IBAN +func generateNicaraguaIBAN() (string, error) { + sb := pool.BytesPool.Get() + defer sb.Free() + + sb.WriteString("NI") + ascii.Digits(sb, 2) + ascii.UpperCaseLetters(sb, 4) + ascii.Digits(sb, 20) + + return ReplaceChecksum(sb.String()) +} + +// getNicaraguaBBAN retrieves BBAN structure from Nicaragua IBAN +func getNicaraguaBBAN(iban string) (BBAN, error) { + if len(iban) != 28 { + return BBAN{}, fmt.Errorf("unexpected length, want: 28: %w", ErrValidation) + } + + return BBAN{ + BBAN: iban[4:28], + BankCode: iban[4:8], + BranchCode: "", + NationalChecksum: "", + AccountNumber: iban[8:28], + }, nil +} diff --git a/iban/generate.go b/iban/generate.go index 514ba55..621e5b5 100644 --- a/iban/generate.go +++ b/iban/generate.go @@ -115,12 +115,16 @@ func Generate(countryCode string) (string, error) { return generateMontenegroIBAN() case mk: return generateMacedoniaIBAN() + case mn: + return generateMongoliaIBAN() case mr: return generateMauritaniaIBAN() case mt: return generateMaltaIBAN() case mu: return generateMauritiusIBAN() + case ni: + return generateNicaraguaIBAN() case nl: return generateTheNetherlandsIBAN() case no: diff --git a/iban/iban.go b/iban/iban.go index 953d076..8a38243 100644 --- a/iban/iban.go +++ b/iban/iban.go @@ -2,6 +2,8 @@ package iban import "github.com/jacoelho/banking/pool" +//go:generate banking-registry -registry-file ../docs/registry.yml -dst-directory . + // PaperFormat returns iban in paper format // Follows EBS 204 - 5 IBAN Format 2) Paper Format func PaperFormat(iban string) string { diff --git a/iban/sepa.go b/iban/sepa.go index 2630f69..8428e18 100644 --- a/iban/sepa.go +++ b/iban/sepa.go @@ -172,6 +172,9 @@ func IsSEPACountryCode(countryCode string) (bool, error) { // Country Code Macedonia case mk: return false, nil + // Country Code Mongolia + case mn: + return false, nil // Country Code Mauritania case mr: return false, nil @@ -181,6 +184,9 @@ func IsSEPACountryCode(countryCode string) (bool, error) { // Country Code Mauritius case mu: return false, nil + // Country Code Nicaragua + case ni: + return false, nil // Country Code The Netherlands case nl: return true, nil diff --git a/iban/sepa_test.go b/iban/sepa_test.go index 423820c..76a0ff1 100644 --- a/iban/sepa_test.go +++ b/iban/sepa_test.go @@ -1,5 +1,3 @@ -//go:build validation - package iban import ( @@ -242,6 +240,16 @@ func TestIsSEPACountry(t *testing.T) { want: false, wantErr: false, }, + { + countryCode: "MN", + want: false, + wantErr: false, + }, + { + countryCode: "NI", + want: false, + wantErr: false, + }, } for _, tt := range tests { tt := tt diff --git a/iban/validate.go b/iban/validate.go index a72ecab..8712cf9 100644 --- a/iban/validate.go +++ b/iban/validate.go @@ -120,12 +120,16 @@ func Validate(iban string) error { return validateMontenegroIBAN(iban) case mk: return validateMacedoniaIBAN(iban) + case mn: + return validateMongoliaIBAN(iban) case mr: return validateMauritaniaIBAN(iban) case mt: return validateMaltaIBAN(iban) case mu: return validateMauritiusIBAN(iban) + case ni: + return validateNicaraguaIBAN(iban) case nl: return validateTheNetherlandsIBAN(iban) case no: diff --git a/iban/validate_test.go b/iban/validate_test.go index d84a489..fde8bb1 100644 --- a/iban/validate_test.go +++ b/iban/validate_test.go @@ -335,6 +335,14 @@ func TestValidateIBAN(t *testing.T) { iban: "SO211000001001000100141", wantErr: false, }, + { + iban: "MN121234123456789123", + wantErr: false, + }, + { + iban: "NI45BAPR00000013000003558124", + wantErr: false, + }, } for _, tt := range tests { tt := tt diff --git a/registry/cmd/generator/main.go b/registry/cmd/banking-registry/main.go similarity index 100% rename from registry/cmd/generator/main.go rename to registry/cmd/banking-registry/main.go