Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions stdnum/om/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# __init__.py - collection of Omani numbers
# coding: utf-8
#
# Copyright (C) 2026 Devashish Moghe
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, see <https://www.gnu.org/licenses/>.

"""Collection of Omani numbers."""
84 changes: 84 additions & 0 deletions stdnum/om/vat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# vat.py - functions for handling Oman VAT numbers
# coding: utf-8
#
# Copyright (C) 2026 Devashish Moghe
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, see <https://www.gnu.org/licenses/>.

"""VAT (Oman value added tax number).

The Oman VAT identification number (VATIN) is issued by the Oman Tax
Authority to businesses registered for value added tax. It consists of the
letters ``OM`` followed by 10 digits (12 characters in total).

There is no check digit; a number can be verified online through the Oman
Tax Authority portal.

More information:

* https://tms.taxoman.gov.om/portal/web/taxportal/vatin-validation

>>> validate('OM1100006083')
'OM1100006083'
>>> validate('OM 1100 0060 83')
'OM1100006083'
>>> validate('110000608312') # missing prefix
Traceback (most recent call last):
...
InvalidFormat: ...
>>> validate('OM110000608') # too short
Traceback (most recent call last):
...
InvalidLength: ...
>>> validate('OM11000060AB')
Traceback (most recent call last):
...
InvalidFormat: ...
"""

from __future__ import annotations

import re

from stdnum.exceptions import *
from stdnum.util import clean


# the VATIN consists of the OM prefix followed by ten digits
_vatin_re = re.compile(r'^OM[0-9]{10}$')


def compact(number: str) -> str:
"""Convert the number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
return clean(number, ' -').upper().strip()


def validate(number: str) -> str:
"""Check if the number is a valid Oman VAT number. This checks the
length and formatting."""
number = compact(number)
if len(number) != 12:
raise InvalidLength()
if not _vatin_re.match(number):
raise InvalidFormat()
return number


def is_valid(number: str) -> bool:
"""Check if the number is a valid Oman VAT number."""
try:
return bool(validate(number))
except ValidationError:
return False
65 changes: 65 additions & 0 deletions tests/test_om_vat.doctest
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
test_om_vat.doctest - more detailed doctests for the stdnum.om.vat module

Copyright (C) 2026 Devashish Moghe

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <https://www.gnu.org/licenses/>.


This file contains more detailed doctests for the stdnum.om.vat module. It
tries to validate a number of numbers that have been found online.

>>> from stdnum.om import vat
>>> from stdnum.exceptions import *


Tests for some corner cases.

>>> vat.validate('OM1100006083')
'OM1100006083'
>>> vat.validate('om1100006083')
'OM1100006083'
>>> vat.compact('OM 1100 0060 83')
'OM1100006083'
>>> vat.is_valid('OM1100006083')
True
>>> vat.is_valid('OM110000608')
False
>>> vat.validate('OM110000608')
Traceback (most recent call last):
...
InvalidLength: ...
>>> vat.validate('110000608312')
Traceback (most recent call last):
...
InvalidFormat: ...
>>> vat.validate('OM11000060AB')
Traceback (most recent call last):
...
InvalidFormat: ...


These have been found online and should all be valid numbers.

>>> numbers = '''
...
... OM1100002920
... OM1100005523
... OM1100006083
... OM1100006999
... OM1100011333
... OM1100018164
...
... '''
>>> [x for x in numbers.splitlines() if x and not vat.is_valid(x)]
[]
Loading