ActiveLogin.Identity icon indicating copy to clipboard operation
ActiveLogin.Identity copied to clipboard

Add support for SwedishCompanyRegistrationNumber

Open PeterOrneholm opened this issue 7 years ago • 6 comments

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

PeterOrneholm avatar Oct 12 '18 08:10 PeterOrneholm

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.

viktorvan avatar Feb 14 '19 17:02 viktorvan

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) .

viktorvan avatar Feb 19 '19 07:02 viktorvan

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.

PeterOrneholm avatar Feb 23 '19 11:02 PeterOrneholm

Some findings that we (probably) have to handle:

  1. A Swedish coordination number can be a valid organizational number, we should therefore probably implement that first.

  2. 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.

  3. 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

PeterOrneholm avatar Feb 23 '19 12:02 PeterOrneholm

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.

viktorvan avatar Feb 23 '19 12:02 viktorvan

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.

viktorvan avatar Feb 23 '19 12:02 viktorvan