This commit is contained in:
norohind 2024-08-29 13:20:32 +02:00
commit e4689c6632
3 changed files with 92 additions and 0 deletions

11
pyproject.toml Normal file
View File

@ -0,0 +1,11 @@
[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"
[project]
name = "taxgovme"
version = "0.0.1"
description = "A toolset to parse invoices from mapr.tax.gov.me"
requires-python = ">=3.10"
dependencies = ["requests", "pydantic"]
license = {text = "MIT"}

2
requirements.txt Normal file
View File

@ -0,0 +1,2 @@
pydantic
requests

79
src/taxgovme.py Normal file
View File

@ -0,0 +1,79 @@
import datetime
import json
from pydantic import BaseModel, Field, field_validator, ValidationInfo, ValidationError, computed_field, AliasPath
from decimal import Decimal
import requests
from urllib.parse import urlparse, parse_qs
class Item(BaseModel):
name: str
quantity: Decimal
unit_price: Decimal = Field(alias='unitPriceAfterVat')
total_price: Decimal = Field(alias='priceAfterVat')
barcode: str | None = Field(default=None, alias='code')
unit: str | None = Field(default=None, alias='unit')
@field_validator('total_price')
def total_price_validate(cls, total_price: Decimal, info: ValidationInfo) -> Decimal:
total_price = round(total_price, 2)
# calculated_total_price = round(info.data['quantity'] * info.data['unit_price'], 2)
# if calculated_total_price != total_price:
# raise ValueError(f"{calculated_total_price=}. Invoice {total_price=}")
return total_price
@computed_field(return_type=Decimal)
def rounding_errors(self):
return self.total_price - round(self.unit_price * self.quantity, 2)
@field_validator('name')
def name_normalize(cls, name: str, infok) -> str:
return ' '.join(name.split())
class Invoice(BaseModel):
total_price: Decimal = Field(alias='totalPrice')
timestamp: datetime.datetime = Field(alias='dateTimeCreated')
seller_name: str | None = Field(validation_alias=AliasPath('seller', 'name'))
items: list[Item]
@computed_field(return_type=Decimal)
def rounding_errors(self) -> Decimal:
return self.total_price - sum(i.total_price for i in self.items)
def query_verify_invoice(iic, dateTimeCreated, tin) -> dict:
r = requests.post(
'https://mapr.tax.gov.me/ic/api/verifyInvoice',
params={'iic': iic, 'dateTimeCreated': dateTimeCreated, 'tin': tin}
)
try:
r.raise_for_status()
doc = r.json()
return doc
except (requests.HTTPError, json.decoder.JSONDecodeError):
print(r.status_code)
print(r.content)
raise
except ValidationError:
print(json.dumps(doc, ensure_ascii=False, indent=2))
raise
def extract_params_from_url(url: str) -> tuple[str, str, str]:
parsed = urlparse(url, allow_fragments=False)
params = parse_qs(parsed.query)
return params['iic'][0], params['crtd'][0], params['tin'][0]
def query_verify_invoice_by_url(url) -> dict:
params = extract_params_from_url(url)
return query_verify_invoice(*params)
def invoice_by_url(url: str) -> Invoice:
invoice_dict = query_verify_invoice_by_url(url)
inv = Invoice.model_validate(invoice_dict)
inv.items.sort(key=lambda item: item.total_price, reverse=True)
return inv