ActiveLogin.Identity
ActiveLogin.Identity copied to clipboard
Add support for SwedishCompanyRegistrationNumber
Swedish companies all have a unique number (Organisationsnummer), called company registration number, that is used for taxes and similiar places when you need to identify a company.
As it's a common usecase and an implementation would be very similar to a PersonalIdentityNumber we aim to implement this.
Info and definitions:
- http://bolagsverket.se/ff/foretagsformer/organisationsnummer-1.7902
- https://sv.wikipedia.org/wiki/Organisationsnummer
- http://www.mira.se/knowledge-base/vad-heter-personnummer-och-samordningsnummer-pa-engelska/
- https://www.skatteverket.se/foretagochorganisationer/startaochdrivaforetag/startaochregistrera/organisationsnummer.4.361dc8c15312eff6fd235d1.html
I would like to get started on this, so we need to put some thought into the api. I think we should follow as closely to the PersonalIdentityNumber api as we can.
Individual firms
One special usecase is numbers for “enskild firma” (individual firm/enterprise/ sole proprietor?) where the number is the same as the individual’s personal identity number.
If our validation accepts these type of numbers by default, I feel that it may be too blunt, too allowing. We would open up for false positives where someone enters their personal identity number by mistake? Or am I wrong, is that the expected behavior?
So should we have something like:
ParseCompany(string input) {...}`` that only accepts company registration numbers and ParseIndividualFirm(string input) {...}which could delegate toSwedishIdentityNumber.Parse()andParse(string input) {...}that accepts both? But maybeParseCompanyshould be the default, and we should use another name forParse`?
12 digit numbers
What’s the deal with these? We need to be able to parse them? Is there a clear 1 to 1 relationship between 12- and 10-digit numbers? Are we guaranteed to be able to map between them?
Hints
I am ok to leave these out-of-scope for the first version.
Unified api
I.e. an additional parse-method that returns a PersonalIdentityNumber or a CompanyRegistrationNumber could be useful, but should probably be discussed in its’ own issue.
After some offline discussions we reached the following conclusions:
-
Parsing individual firms In v1 we will have a single
.Parse(string input)function that allows for company registration numbers, individual numbers (i.e. personal identity numbers) and VAT-numbers. We can later add overloads with options to only allow parsing a subset of numbers. -
10- and 12-digit numbers. We need to investigate if we can map a 10-digit number to a 12-digit numbers in all cases. E.g. can we know to use 16 or 11 as the first digits.
-
Provide a .ToVATString() function to convert a company organisation numbers to a VAT-number (i.e. prefix SE, suffix 01).
-
Hints will be considered out-of-scope for v1.
-
Separate issues will be created for External validation(#76) and Unified api (#75) .
Here is a proposed class structure. Almost identitcal as for personal identity number, but with the addition of ToVatString():
public class SwedishCompanyRegistrationNumber
{
public SwedishCompanyRegistrationNumber(int x, int y, int z, int q, int checksum) { }
public int X { get; set; } //TODO: Find proper name
public int Y { get; set; } //TODO: Find proper name
public int Z { get; set; } //TODO: Find proper name
public int Q { get; set; } //TODO: Find proper name
public int Checksum { get; set; }
public SwedishCompanyRegistrationNumber ParseInSpecificYear(string s, int year) { }
public SwedishCompanyRegistrationNumber Parse(string s) { }
public bool TryParseInSpecificYear(string s, int year, out SwedishCompanyRegistrationNumber parseResult) { }
public bool TryParse(string s, out SwedishCompanyRegistrationNumber parseResult) { }
public string To10DigitStringInSpecificYear(int serializationYear) { }
public string To10DigitString() { }
public string To12DigitString() { }
public string ToVatString() { }
public string ToString() { }
public bool Equals(object b) { }
public int GetHashCode() { }
public static bool operator ==(SwedishCompanyRegistrationNumber a, SwedishCompanyRegistrationNumber b) { }
}
We need to decide what the indivudual parts should be named. Year/Month/Day/Birthnumber only applies for "enksild firma", so that is not correct.
Also, we need to figure out if an "Enskild firma" ever can contain a + as delmiter. I have not so far been able to find any info on this subject. A full 12 digit version of the SwedishCompanyRegistrationNumber will contain the full year, so then it's not a problem, but when displayed as 10 digit or parsed as 10 digit it can be.
Some findings that we (probably) have to handle:
-
A Swedish coordination number can be a valid organizational number, we should therefore probably implement that first.
-
An organizational number can contain letters, see the last section Search by registration number . Never heard of thit before and haven't found any spec on it yet. Example from the link OC34875.
-
If a person using his or hers personal identity number for the firm, and has mulltiple enteprises, they should be suffixed with a number saying which one it is. Example 001, 002 etc. Full should then be: 19123456-7890001
All texts I find for “Enskild firma” states that you use the owner’s personal identity number. Therefore I draw the conclusion that the same rules must apply, i.e. plus is a valid delimiter, however unlikely that situation might be.
I realize that we will need the ...InSpecificYear overloads but I do not like them. They are for only required for “enskild firma” and only solve the use case when parsing before and after the year a person turns 100. Or am I missing something. It is such a small subset of company registration numbers where that would apply. In reality I am guessing zero, unless an estate(?) (dödsbo) can keep using a personal identity number after a persons death?
If would like to propose an alternative api for that use case: We remove the InSpecificYear-overloads and instead provide an option to create a CompanyRegistrationNumber from a PersonalIdentityNumber (a constructor or factory-method). And also the other way around a method .ToPersonalIdentityNumber() which you then can call .ToXXDigitStringInSpecificYear() on. Then the use case is fulfilled (in a somewhat roundabout way) but we keep the api on CompanyRegistrationNumber free from SpecificYear-stuff which I find is definitely the hardest thing to explain to a user of our library.
I have seen the suffixes before could not figure out what they meant. Great find! We should support this. But I think we should treat them as suffixes and still name our methods to12digitstring and let it return a 12digitstring + suffix. If a number has a suffix it is invalid to return it without a suffix. Possibly we could use a flag to indicate if you want to hide the suffix if it is 001, not sure about this yet though.
I agree we need to do Coordination number first now.
We need to find more information on letters in registration numbers. The number in your link: OC34875 looks like another type of number completely.