init
This commit is contained in:
commit
e4689c6632
11
pyproject.toml
Normal file
11
pyproject.toml
Normal 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
2
requirements.txt
Normal file
@ -0,0 +1,2 @@
|
||||
pydantic
|
||||
requests
|
79
src/taxgovme.py
Normal file
79
src/taxgovme.py
Normal 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
|
Loading…
x
Reference in New Issue
Block a user