mirror of
				https://github.com/Eledio/superfaktura-client.git
				synced 2025-10-31 16:11:20 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			309 lines
		
	
	
		
			9.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			309 lines
		
	
	
		
			9.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| """
 | |
| Invoice Module.
 | |
| 
 | |
| This module provides classes and functions for working with invoices in the SuperFaktura API.
 | |
| It allows for retrieving, creating, updating, and deleting invoices.
 | |
| 
 | |
| Classes:
 | |
|     - InvoiceModel: Dataclass representing an invoice.
 | |
|     - InvoiceItem: Dataclass representing an invoice item.
 | |
|     - Invoice: Class for interacting with invoices.
 | |
| 
 | |
| Exceptions:
 | |
|     - NoDefaultBankAccountException: Exception for when no default bank account is found.
 | |
| 
 | |
| Functions:
 | |
|     - (none)
 | |
| 
 | |
| Usage:
 | |
|     import superfaktura.invoice
 | |
| 
 | |
|     # Create an instance of Invoice
 | |
|     invoice = superfaktura.invoice.Invoice()
 | |
| 
 | |
|     # Create an invoice
 | |
|     invoice.add(
 | |
|         invoice=superfaktura.invoice.InvoiceModel(
 | |
|             type=superfaktura.invoice.InvoiceType.PROFORMA,
 | |
|             name="Invoice 3",
 | |
|             due=superfaktura.invoice.Date("2025-02-01"),
 | |
|             invoice_currency=superfaktura.invoice.Currencies.CZK,
 | |
|             header_comment="We invoice you for services",
 | |
|             bank_accounts=[bank.default().as_dict()],
 | |
|         ),
 | |
|         items=[
 | |
|             superfaktura.invoice.InvoiceItem(name="Services", unit_price=100, quantity=1,
 | |
|                                             unit="ks", tax=21),
 | |
|             superfaktura.invoice.InvoiceItem(name="SIM card", unit_price=50, quantity=1,
 | |
|                                             tax=21, unit="ks"),
 | |
|             superfaktura.invoice.InvoiceItem(
 | |
|                 name="SIM card 2", unit_price=75, quantity=1, tax=21, unit="ks"
 | |
|             ),
 | |
|         ],
 | |
|         contact=superfaktura.client_contacts.ClientContactModel(
 | |
|             name="Richard Kubíček",
 | |
|             email="kubicekr@eledio.com",
 | |
|             phone="+420 123 456 789",
 | |
|             address="Jaroslava Foglara 861/1",
 | |
|             ico="123",
 | |
|             update=True,
 | |
|             country_id=57,
 | |
|         ),
 | |
|     )
 | |
| """
 | |
| 
 | |
| from dataclasses import dataclass, asdict
 | |
| from typing import Optional, List
 | |
| import json
 | |
| 
 | |
| from superfaktura.client_contacts import ClientContactModel
 | |
| from superfaktura.enumerations.data_format import DataFormat
 | |
| from superfaktura.enumerations.language import Language
 | |
| from superfaktura.superfaktura_api import SuperFakturaAPI
 | |
| from superfaktura.utils.data_types import Date, DateEncoder
 | |
| 
 | |
| 
 | |
| @dataclass
 | |
| class InvoiceModel:
 | |
|     """This dataclass represents an invoice in the SuperFaktura API."""
 | |
| 
 | |
|     add_rounding_item: Optional[int] = 0
 | |
|     already_paid: Optional[int] = None
 | |
|     bank_accounts: Optional[List[dict]] = None
 | |
|     comment: Optional[str] = None
 | |
|     constant: Optional[str] = None
 | |
|     created: Optional[Date] = None
 | |
|     delivery: Optional[Date] = None
 | |
|     delivery_type: Optional[str] = None
 | |
|     deposit: Optional[float] = None
 | |
|     discount: Optional[float] = 0
 | |
|     discount_total: Optional[float] = None
 | |
|     due: Optional[Date] = None
 | |
|     estimate_id: Optional[int] = None
 | |
|     header_comment: Optional[str] = None
 | |
|     internal_comment: Optional[str] = None
 | |
|     invoice_currency: Optional[str] = None
 | |
|     invoice_no_formatted: Optional[str] = None
 | |
|     issued_by: Optional[str] = None
 | |
|     issued_by_email: Optional[str] = None
 | |
|     issued_by_phone: Optional[str] = None
 | |
|     issued_by_web: Optional[str] = None
 | |
|     logo_id: Optional[int] = None
 | |
|     mark_sent: Optional[int] = None
 | |
|     mark_sent_message: Optional[str] = None
 | |
|     mark_sent_subject: Optional[str] = None
 | |
|     name: Optional[str] = None
 | |
|     order_no: Optional[str] = None
 | |
|     parent_id: Optional[int] = None
 | |
|     paydate: Optional[Date] = None
 | |
|     payment_type: Optional[str] = None
 | |
|     proforma_id: Optional[str] = None
 | |
|     rounding: Optional[str] = None
 | |
|     sequence_id: Optional[int] = None
 | |
|     specific: Optional[str] = None
 | |
|     tax_document: Optional[int] = None
 | |
|     type: Optional[str] = None
 | |
|     variable: Optional[str] = None
 | |
|     vat_transfer: Optional[int] = None
 | |
| 
 | |
|     def as_dict(self) -> dict:
 | |
|         """Returns a dictionary representation of the InvoiceModel."""
 | |
|         data = asdict(self)
 | |
|         for key in list(data.keys()):
 | |
|             if data[key] is None:
 | |
|                 del data[key]
 | |
|         return data
 | |
| 
 | |
|     def to_dict(self) -> dict:
 | |
|         """
 | |
|         Converts the Record object to a dictionary for JSON serialization.
 | |
|         """
 | |
|         return {"due": self.due.to_dict() if self.due else None}
 | |
| 
 | |
| 
 | |
| @dataclass
 | |
| class InvoiceItem:
 | |
|     """This dataclass represents an invoice item in the SuperFaktura API."""
 | |
| 
 | |
|     name: str
 | |
|     unit_price: float
 | |
|     description: Optional[str] = None
 | |
|     discount: Optional[float] = 0
 | |
|     discount_description: Optional[str] = None
 | |
|     load_data_from_stock: int = 0
 | |
|     quantity: Optional[float] = 1
 | |
|     sku: Optional[str] = None
 | |
|     stock_item_id: Optional[int] = None
 | |
|     tax: Optional[float] = None
 | |
|     unit: Optional[str] = None
 | |
|     use_document_currency: Optional[int] = 0
 | |
| 
 | |
|     def as_dict(self) -> dict:
 | |
|         """Returns a dictionary representation of the InvoiceItem."""
 | |
|         data = asdict(self)
 | |
|         for key in list(data.keys()):
 | |
|             if data[key] is None:
 | |
|                 del data[key]
 | |
|         return data
 | |
| 
 | |
| 
 | |
| @dataclass
 | |
| class InvoiceRespModel:
 | |
|     """
 | |
|     This dataclass represents the response model for an invoice in the SuperFaktura API.
 | |
| 
 | |
|     Attributes:
 | |
|         - error (int): The error code.
 | |
|         - error_message (str): The error message.
 | |
|         - invoice_id (Optional[int]): The ID of the invoice.
 | |
|         - invoice_token (Optional[str]): The token of
 | |
|     """
 | |
| 
 | |
|     error: int
 | |
|     error_message: str
 | |
|     invoice_id: Optional[int] = None
 | |
|     invoice_token: Optional[str] = None
 | |
| 
 | |
| 
 | |
| @dataclass
 | |
| class InvoiceSettings:
 | |
|     """
 | |
|     This dataclass represents the settings for an invoice in the SuperFaktura API.
 | |
|     """
 | |
| 
 | |
|     language: Optional[str] = None
 | |
|     bysquare: Optional[bool] = None
 | |
|     callback_payment: Optional[str] = None
 | |
|     online_payment: Optional[bool] = None
 | |
|     payment_info: Optional[bool] = None
 | |
|     paypal: Optional[bool] = None
 | |
|     show_prices: Optional[bool] = None
 | |
|     signature: Optional[bool] = None
 | |
|     summary_bg_color: Optional[str] = None
 | |
| 
 | |
|     def as_dict(self) -> dict:
 | |
|         """Returns a dictionary representation of the ClientContactModel."""
 | |
|         data = asdict(self)
 | |
|         for key in list(data.keys()):
 | |
|             if data[key] is None:
 | |
|                 del data[key]
 | |
|         return data
 | |
| 
 | |
| 
 | |
| class InvoiceType:
 | |
|     """
 | |
|     Invoice Type Enumeration.
 | |
| 
 | |
|     This enumeration represents the different types of invoices that can be created.
 | |
| 
 | |
|     Usage:
 | |
|         invoice_type = InvoiceType.PROFORMA
 | |
|     """
 | |
| 
 | |
|     PROFORMA = "proforma"
 | |
|     INVOICE = "regular"
 | |
| 
 | |
| 
 | |
| class Invoice(SuperFakturaAPI):
 | |
|     """
 | |
|     Invoice Class.
 | |
| 
 | |
|     This class provides methods for interacting with invoices in the SuperFaktura API.
 | |
|     It allows for retrieving, creating, updating, and deleting invoices.
 | |
| 
 | |
|     Methods:
 | |
|         - add: Creates a new invoice.
 | |
|         - get: Retrieves an invoice by ID.
 | |
|         - list: Retrieves a list of invoices.
 | |
|         - update: Updates an existing invoice.
 | |
| 
 | |
|     Usage:
 | |
|         invoice = Invoice()
 | |
|         invoice.add(
 | |
|             invoice=InvoiceModel(
 | |
|                 type=InvoiceType.PROFORMA,
 | |
|                 name="Invoice 3",
 | |
|                 due=Date("2025-02-01"),
 | |
|                 invoice_currency=Currencies.CZK,
 | |
|                 header_comment="We invoice you for services",
 | |
|                 bank_accounts=[bank.default().as_dict()],
 | |
|             ),
 | |
|             items=[
 | |
|                 InvoiceItem(name="Services", unit_price=100, quantity=1, unit="ks", tax=21),
 | |
|                 InvoiceItem(name="SIM card", unit_price=50, quantity=1, tax=21, unit="ks"),
 | |
|                 InvoiceItem(
 | |
|                     name="SIM card 2", unit_price=75, quantity=1, tax=21, unit="ks"
 | |
|                 ),
 | |
|             ],
 | |
|             contact=ClientContactModel(
 | |
|                 name="Richard Kubíček",
 | |
|                 email="kubicekr@eledio.com",
 | |
|                 phone="+420 123 456 789",
 | |
|                 address="Jaroslava Foglara 861/1",
 | |
|                 ico="123",
 | |
|                 update=True,
 | |
|                 country_id=57,
 | |
|             ),
 | |
|         )
 | |
|     """
 | |
| 
 | |
|     def __init__(self):
 | |
|         super().__init__()
 | |
| 
 | |
|     def add(
 | |
|         self,
 | |
|         invoice_model: InvoiceModel,
 | |
|         items: List[InvoiceItem],
 | |
|         contact: ClientContactModel,
 | |
|         invoice_settings: Optional[InvoiceSettings],
 | |
|     ) -> InvoiceRespModel:
 | |
|         """
 | |
|         Adds a new invoice.
 | |
| 
 | |
|         Args:
 | |
|             invoice_model (InvoiceModel): The invoice model.
 | |
|             items (List[InvoiceItem]): List of invoice items.
 | |
|             contact (ClientContactModel): The client contact model.
 | |
|             invoice_settings (Optional[InvoiceSettings]): The invoice settings.
 | |
| 
 | |
|         Returns:
 | |
|             InvoiceRespModel: The response model for the invoice.
 | |
|             :param invoice_settings:
 | |
|             :param contact:
 | |
|             :param items:
 | |
|             :param invoice_model:
 | |
|         """
 | |
|         data = {
 | |
|             "Invoice": invoice_model.as_dict(),
 | |
|             "InvoiceItem": [item.as_dict() for item in items],
 | |
|             "Client": contact.as_dict(),
 | |
|             "InvoiceSetting": invoice_settings.as_dict(),
 | |
|         }
 | |
|         url = "invoices/create"
 | |
|         resp = self.post(endpoint=url, data=json.dumps(data, cls=DateEncoder))
 | |
|         invoice_resp = InvoiceRespModel(
 | |
|             error=resp["error"], error_message=resp["error_message"]
 | |
|         )
 | |
|         if "data" in resp:
 | |
|             if "Invoice" in resp["data"]:
 | |
|                 invoice_resp.invoice_id = int(resp["data"]["Invoice"]["id"])
 | |
|                 invoice_resp.invoice_token = resp["data"]["Invoice"]["token"]
 | |
|         return invoice_resp
 | |
| 
 | |
|     def get_pdf(
 | |
|         self, invoice: InvoiceRespModel, language: str = Language.Czech
 | |
|     ) -> bytes:
 | |
|         """
 | |
|         Retrieves the PDF of the invoice.
 | |
| 
 | |
|         Args:
 | |
|             invoice (InvoiceRespModel): The response model for the invoice.
 | |
|             language (str): The language for the PDF.
 | |
| 
 | |
|         Returns:
 | |
|             bytes: A bytes containing the PDF data.
 | |
|         """
 | |
|         url = f"{language}/invoices/pdf/{invoice.invoice_id}/token:{invoice.invoice_token}"
 | |
|         document = self.get(url, data_format=DataFormat.PDF)["pdf"]
 | |
|         return document
 |