arthurdejong / python-stdnum

A Python library to provide functions to handle, parse and validate standard numbers.
https://arthurdejong.org/python-stdnum/
GNU Lesser General Public License v2.1
498 stars 206 forks source link

Romanian CIF - non vat paying companies #231

Closed dotbit1 closed 3 years ago

dotbit1 commented 4 years ago

Current problem: There is no way to handle ~30% of Romanian companies that are not registered for VAT, thus do not have a VAT number.

Romanian companies invoicing other Romanian companies must identify themselves and the counterparty using the CIF (VAT) number and in case the company/counterparty is not registered for VAT, then the CUI (company code) must be used, this is stated explicitly in law. Both numbers have the same position on invoices. CIF='RO'+$CUI. For ex. my company has the following codes: CUI = company code. 16281620. CIF (VAT no, also European VAT no)= RO16281620.

Possible solutions:

  1. Create a new identifier called CUI. This way ~70% of companies that are VAT registered need to have 2 identifiers = redundancy = possible errors.
  2. Retain the RO prefix in the code and use this identifier as a sort of hybrid between CUI and CIF. If the code contains RO then the company is registered for VAT, else it is not. Also there could be functions to return the CUI number from the CIF code (by stripping RO) or a function which returns whether the company is registered for VAT or not. This is simplest for everyone, but perhaps not the most correct. Also perhaps the description of the identifier would have to be adjusted.

I prefeer solution 2, but I am unsure it it is the correct technical solution. On this matter I need the maintainer's input. By the way, this code is already a sort of hybrid by validating cnp. Both CUI, CNP and CIF can be used as fiscal identifiers, so maybe call this fiscal code?

arthurdejong commented 4 years ago

Currently python-stdnum has these Romanian formats:

You mention CIF as VAT number, I think that is what is called CF in python-stdnum but it may not be exactly the same. Note that the CF module is supposed to validate Romanian VAT numbers that are valid within the EU. Specifically, if the EU VIES VAT validation service says it is a valid VAT number the module should at least also mark the same numbers as correct and ideally only those numbers.

The current implementation of CF also allows for the CNP to be a valid CF but the original change (ffc824b) is pretty old has some doubts about that. Otherwise a different checksum algorithm is used.

Note that the two numbers you provided are both considered valid CF by the current implementation.

Some questions:

Thanks for raising this issue.

dotbit1 commented 4 years ago

Since the CF module is supposed to validate Romanian VAT numbers that are valid within the EU, then we can not have this identifier be also for CUI. Then we need another identifier for CUI: stdnum.ro.cui.

Regarding CNP being valid as CF: TIN_country_sheet.pdf. It seems like this can be a valid fiscal identifier, however I am not sure if it must also be a valid VAT number. For ex. on my company's fisc (anaf) certificate it is stated that the company is registered for VAT, on the examples for people (CNP) in the link above it is not stated that they collect/pay VAT, and also I have never seen a physical person be registered for VAT collection/deduction.

Yes, both numbers (16281620 and RO16281620) are considered valid cf numbers. However if I put in RO16281620, the minimal representation is returned: 16281620. In computer science I would consider this correct as the RO does not convey any information, we already know that the type is a Romanian VAT number.

Is CF the same as CIF (or is CIF perhaps the more correct name)?

For a company vat number the correct name is CIF. On the specimen anaf certificate from the link above it also writes CIF. CF was used before 2007 and most likely refered to either CUI or a mix of UI and CIF. I consider a change is not in order before I research this better.

Does every CIF contain a valid CUI?

Logically: If the number is a CNP, then no. If the number is a company cif, then yes as any company can request to be registered for VAT using their CUI id number. Tested: The romanian company database: all CUI numbers validated as stdnum.ro.cf with the following exceptions: '' string, '0' string and two numbers that are not registered according to mfinante.ro. (finance minister)

How can a CUI (that is not a valid CIF) be validated (format, check digit)?

Logically: It is the same number, only without the RO in front. See the check above.

Does the Romanian VAT number usually include the RO as first two letters (the current implementation strips those when returning a compact representation)

Accountant folklore: they all say that all vat numbers start with VAT. Experience: I have not seen any contrary evidence. I believe that all romanian VAT numbers start with RO, however what about CIF that may also include CNP? (!!?!)

Can you give a few examples of problems is with the current implementation (e.g. an example of a number that is incorrectly considered as invalid or a description that gives the wrong impression)?

Example: I use tryton to invoice. I create a new customer (party) and I add onrc and cf identifiers to this party. I write RO1111 in the cf number. Tryton then validates the number, storing 1111 in the database. Then I invoice the customer and on the invoice it will write that I invoice customer 1111. If this customer is vat registered I have to invoice RO1111 according to romanian law. Maybe this is the job of Tryton to work-around this, maybe you can answer this better than me.

Also it is unclear to me if I should use European VAT number or Romanian VAT number for Romanian companies. If I use European VAT number for ex. Tryton allows me to check VIES, but both are the same number, only that European VAT number can also be from other european countries. If I use Romanian VAT number I do not have the option in Tryton to check VIES. Perhaps create a Tryton party module issue that the european countries national vat numbers should also be used for vies?

At the moment the only suggestion I would make is perhaps not strip the RO from the front.

Sorry, so little official documentation exists. I will get back with better research.

dotbit1 commented 4 years ago

I received an answer, which is less precise than I would like:

A CIF is only a VAT number if it has RO infront of it and is based on a CUI. If it is based on a CNP then it is a tax identifier for one-person-companies, but not a VAT number.

Also as I have mentioned, in Romania we need to be able to identify companies even if they are not registered for VAT/can not register for VAT.

Only you can make the decision if we need two codes: Romanian VAT, and company code, or if we should make a hybrid one which can have custom functions that can return for example if the number is a vat number, to return the cui code by stripping RO if needed, etc.

arthurdejong commented 4 years ago

Hi @dotbit1,

After the discussion we had and the information you provided I think this is the best cause of action:

Another option would be to deprecate stdnum.ro.cf and let applications that use python-sdtnum (e.g. Tryton) do the corresponding logic but that would be somewhat a regression in python-stdnum and it seems to be useful to have a module available in which a general Romanian (fiscal) identifier can be used, especially because they seem to be used somewhat interchangeably in some contexts.

dotbit1 commented 4 years ago

@arthurdejong,

Your proposal solves all the problems that exist for anyone using romanian identifiers.

PS: I had the wrong impression about CIF when I started figuring out romanian identifiers. In my first post on this issue it is wrong.

arthurdejong commented 3 years ago

According to Wikipedia (and Google translate) CUI is the old name for the CIF. This means that we could also do:

This means that stdnum.ro.vat name could either be an alias for stdnum.ro.cif or we could make it so that it only accepts numbers with a RO prefix.

Which solution do you think more closely resembles the actual use of the number?

Btw, the ANAF website offers some web services that can also be quite easily integrated into python-stdnum. That allows online lookup of company registration information based on the CUI (does not allow RO prefix and uses that name in the API).

dotbit1 commented 3 years ago

Your previous solution resembles actual use better.

* Introduce a `stdnum.ro.cui` module that only validates numbers without `RO` in front (and does not validate a CNP).
  This module will get a `to_cif()` function for conversion.

* Introduce a `stdnum.ro.cif` module that only validates numbers that start with `RO` (also does not validate a CNP).
  This module will get the `stdnum.ro.vat` alias and as such be used by the `stdnum.eu.vat` module.
  This module will get a `to_cui()` function for conversion.

* Update the `stdnum.ro.cf` module to accept a CIF, CUI or CNP (which means the `RO` prefix will be retained if present).

Yes, ANAF web service integration would be great. Well noted that the web service needs the CUI, so we need to be able to return CUI (withot RO) from the CIF in order to use the web service.

Wikipedia page is outdated, started working on updating it. When I am done I will ask ANAF if they want to review, maybe they will, probably not.

Message me if I can provide any more info, but I prefer to get out of this feedback loop, even if the solution is not 100%, because the Romanian codes are really confusing.

arthurdejong commented 3 years ago

Hi @dotbit1,

Sorry I didn't get back to you sooner. I had to take some time off.

After quite some back-end-forth I ended up merging a change (c5eb2d8) that results in preserving the RO prefix if it is present in the number without making too many other changes.

I did split out CUI/CIF validation in a separate stdnum.ro.cui module in e0417f6. From the information from ANAF you provided in Wikipedia I concluded that the CUI and CIF are basically the same number and the only difference is who assigns it.

According to https://ec.europa.eu/taxation_customs/tin/ a CNP can still be a valid VAT number (I haven't found one that is also valid according to the VIES check though) so I kept that validation in the stdnum.ro.cf module which is still the implementation for stdnum.ro.vat.

Since there is so much confusion around the numbers and the naming I decided making the minimal change is likely the best choice for now.

dotbit1 commented 3 years ago

Hi, I agree. If I manage to get better documentation I will create a new issue+pull request.

Thanks, Dimitrios