Arthur de Jong

Open Source / Free Software developer

summaryrefslogtreecommitdiffstats
path: root/stdnum/do/ncf.py
diff options
context:
space:
mode:
authorJeffry Jesus De La Rosa <jeffryjesus@gmail.com>2019-06-10 22:55:05 +0200
committerArthur de Jong <arthur@arthurdejong.org>2019-06-14 13:53:57 +0200
commit5d0f288eb18793048fa10f9d9de82df087f7e71e (patch)
treef840d1b86e57052d2d54e9e00f8ee9d89e13d425 /stdnum/do/ncf.py
parent7fb390e748e7125d91c2fa4723eb6f4189da68cf (diff)
Support Dominican Republic e-CF within NCF
e-CF is the new way of DGII document, is the same as NCF, but the difference one to another, is that e-CF has 13 digit and is electronic invoice, with this change it will validate the correct NCF and e-CF. Closes https://github.com/arthurdejong/python-stdnum/pull/135
Diffstat (limited to 'stdnum/do/ncf.py')
-rw-r--r--stdnum/do/ncf.py58
1 files changed, 40 insertions, 18 deletions
diff --git a/stdnum/do/ncf.py b/stdnum/do/ncf.py
index 5a03fb8..ce53d16 100644
--- a/stdnum/do/ncf.py
+++ b/stdnum/do/ncf.py
@@ -22,16 +22,29 @@
"""NCF (Números de Comprobante Fiscal, Dominican Republic receipt number).
-The NCF is used to number invoices and other documents for the purposes of
-tax filing. The number is 19 digits long and consists of a letter (A or P) to
-indicate that the number was assigned by the taxpayer or the DGIT, followed a
-2-digit business unit number, a 3-digit location number, a 3-digit mechanism
-identifier, a 2-digit document type and a 8-digit serial number.
+The NCF is used to number invoices and other documents for the purpose of tax
+filing. The e-CF (Comprobante Fiscal Electrónico) is used together with a
+digital certificate for the same purpose. The number is either 19, 11 or 13
+(e-CF) digits long.
+
+The 19 digit number starts wit a letter (A or P) to indicate that the number
+was assigned by the taxpayer or the DGII, followed a 2-digit business unit
+number, a 3-digit location number, a 3-digit mechanism identifier, a 2-digit
+document type and a 8-digit serial number.
+
+The 11 digit number always starts with a B followed a 2-digit document type
+and a 7-digit serial number.
+
+The 13 digit e-CF starts with an E followed a 2-digit document type and an
+8-digit serial number.
More information:
* https://www.dgii.gov.do/
+ * https://dgii.gov.do/legislacion/normas/Documents/Norma05-19.pdf
+>>> validate('E010000000005') # format since 2019-04-08
+'E010000000005'
>>> validate('B0100000005') # format since 2018-05-01
'B0100000005'
>>> validate('A020010210100000005') # format before 2018-05-01
@@ -53,30 +66,39 @@ def compact(number):
# The following document types are known:
-# 01 invoices for fiscal declaration (or tax reporting)
-# 02 invoices for final consumer
-# 03 debit note
-# 04 credit note (refunds)
-# 11 informal supplier invoices (purchases)
-# 12 single income record
-# 13 minor expenses invoices (purchases)
-# 14 invoices for special customers (tourists, free zones)
-# 15 invoices for the government
+_document_types = (
+ '01', # invoices for fiscal declaration (or tax reporting)
+ '02', # invoices for final consumer
+ '03', # debit note
+ '04', # credit note (refunds)
+ '11', # informal supplier invoices (purchases)
+ '12', # single income record
+ '13', # minor expenses invoices (purchases)
+ '14', # invoices for special customers (tourists, free zones)
+ '15', # invoices for the government
+)
+
def validate(number):
"""Check if the number provided is a valid NCF."""
number = compact(number)
- if len(number) == 11:
+ if len(number) == 13:
+ if number[0] != 'E' or not isdigits(number[1:]):
+ raise InvalidFormat()
+ if number[1:3] not in _document_types:
+ raise InvalidComponent()
+ elif len(number) == 11:
if number[0] != 'B' or not isdigits(number[1:]):
raise InvalidFormat()
+ if number[1:3] not in _document_types:
+ raise InvalidComponent()
elif len(number) == 19:
if number[0] not in 'AP' or not isdigits(number[1:]):
raise InvalidFormat()
+ if number[9:11] not in _document_types:
+ raise InvalidComponent()
else:
raise InvalidLength()
- if number[-10:-8] not in (
- '01', '02', '03', '04', '11', '12', '13', '14', '15'):
- raise InvalidComponent()
return number