API
Core models
These are the core models which will normally be used for Receipt
validation.
- class django_afip.models.PointOfSales(*args, **kwargs)[source]
Represents an existing AFIP point of sale.
Points of sales need to be created via AFIP’s web interface and it is recommended that you use
fetch_points_of_sales()
to fetch these programatically.Note that deleting or altering these models will not affect upstream point of sales.
This model also contains a few fields that are not required or sent to the AFIP when validating receipt. They are used only for PDF generation. Those fields are:
issuing_name
issuing_address
issuing_email
vat_condition
gross_income_condition
sales_terms
These fields may be ignored when using an external mechanism to generate PDF or printable receipts.
- Parameters:
id (AutoField) – Primary key: ID
number (PositiveSmallIntegerField) – Number
issuance_type (CharField) – Issuance type. Indicates if this POS emits using CAE and CAEA.
blocked (BooleanField) – Blocked
drop_date (DateField) – Drop date
issuing_name (CharField) – Issuing name. The name of the issuing entity as shown on receipts.
issuing_address (TextField) – Issuing address. The address of the issuing entity as shown on receipts.
issuing_email (CharField) – Issuing email. The email of the issuing entity as shown on receipts.
vat_condition (CharField) – Vat condition
gross_income_condition (CharField) – Gross income condition
sales_terms (CharField) – Sales terms. The terms of the sale printed onto receipts by default (eg: single payment, checking account, etc).
Relationship fields:
- Parameters:
owner (
ForeignKey
toTaxPayer
) – Owner (related name:points_of_sales
)
Reverse relationships:
- Parameters:
receipts (Reverse
ForeignKey
fromReceipt
) – All receipts of this point of sales (related name ofpoint_of_sales
)
- exception DoesNotExist
- exception MultipleObjectsReturned
- class django_afip.models.Receipt(*args, **kwargs)[source]
A receipt, as sent to AFIP.
Note that AFIP allows sending ranges of receipts, but this isn’t generally what you want, so we model invoices individually.
You’ll probably want to relate some Sale or Order object from your model with each Receipt.
All
document_
fields contain the recipient’s data.If the taxpayer has taxes or pays VAT, you need to attach
Tax
and/orVat
instances to the Receipt.Application code SHOULD NOT set the receipt_number code. It will be set by
validate()
internally. When writing code outside django-afip, this should be considered read-only. The sole exception is importing previously-validated receipts from another database. `- Parameters:
id (AutoField) – Primary key: ID
document_number (BigIntegerField) – Document number. The document number of the recipient of this receipt.
receipt_number (PositiveIntegerField) – Receipt number. If left blank, the next valid number will assigned when validating the receipt.
issued_date (DateField) – Issued date. Can diverge up to 5 days for good, or 10 days otherwise.
total_amount (DecimalField) – Total amount. Must be equal to the sum of net_taxed, exempt_amount, net_taxes, and all taxes and vats.
net_untaxed (DecimalField) – Total untaxable amount. The total amount to which taxes do not apply.<br>For C-type receipts, this must be zero.
net_taxed (DecimalField) – Total taxable amount. The total amount to which taxes apply.<br>For C-type receipts, this is equal to the subtotal.
exempt_amount (DecimalField) – Exempt amount. Only for categories which are tax-exempt.<br>For C-type receipts, this must be zero.
service_start (DateField) – Service start date. Date on which a service started. No applicable for goods.
service_end (DateField) – Service end date. Date on which a service ended. No applicable for goods.
expiration_date (DateField) – Receipt expiration date. Date on which this receipt expires. No applicable for goods.
currency_quote (DecimalField) – Currency quote. The currency’s quote on the day this receipt was issued.
Relationship fields:
- Parameters:
point_of_sales (
ForeignKey
toPointOfSales
) – Point of sales (related name:receipts
)receipt_type (
ForeignKey
toReceiptType
) – Receipt type (related name:receipts
)concept (
ForeignKey
toConceptType
) – Concept (related name:receipts
)document_type (
ForeignKey
toDocumentType
) – Document type. The document type of the recipient of this receipt. (related name:receipts
)currency (
ForeignKey
toCurrencyType
) – Currency. Currency in which this receipt is issued. (related name:documents
)related_receipts (
ManyToManyField
toReceipt
) – Related receipts (related name:receipt
)
Reverse relationships:
- Parameters:
receipt (Reverse
ManyToManyField
fromReceipt
) – All receipts of this receipt (related name ofrelated_receipts
)receiptpdf (Reverse
OneToOneField
fromReceiptPDF
) – The receipt pdf of this receipt (related name ofreceipt
)entries (Reverse
ForeignKey
fromReceiptEntry
) – All entries of this receipt (related name ofreceipt
)taxes (Reverse
ForeignKey
fromTax
) – All taxes of this receipt (related name ofreceipt
)vat (Reverse
ForeignKey
fromVat
) – All vat of this receipt (related name ofreceipt
)optionals (Reverse
ForeignKey
fromOptional
) – All optionals of this receipt (related name ofreceipt
)validation (Reverse
OneToOneField
fromReceiptValidation
) – The validation of this receipt (related name ofreceipt
)
- exception DoesNotExist
- exception MultipleObjectsReturned
- approximate_date() bool [source]
Approximate the date of the receipt as close as possible.
If a receipt should have been validated in a past date, adjust its date as close as possible:
Receipts can only be validated with dates as far as 14 days ago for services and 5 days ago for products. If the receipt date is older than that, set it to 14 or 5 days ago.
If other receipts have been validated on a more recent date, the receipt cannot be older than the most recent one.
If the
issued_date
needs to be changed, the field in the input receipt will be updated and atomically saved to the database.Returns
True
if the date has been changed.
- property formatted_number: str | None
This receipt’s number in the usual format:
0001-00003087
.
- property is_validated: bool
True if this instance is validated.
Note that resolving this property requires a DB query, so if you’ve a very large amount of receipts you should prefetch (see django’s
select_related
) thevalidation
field. Even so, a DB query may be triggered.If you need a large list of validated receipts, you should actually filter them via a QuerySet:
Receipt.objects.filter(validation__result==RESULT_APPROVED)
- objects = <django_afip.models.ReceiptManager object>
Django manager to access the ORM Use
Receipt.objects.all()
to fetch all objects.The default manager includes extra methods including helpers for validation.
See
ReceiptManager
and alsoReceiptQuerySet
.
- revalidate() ReceiptValidation | None [source]
Fetches data of a validated receipt from AFIP’s servers.
If the receipt was already sent to AFIP before this method will create a
ReceiptValidation
instance and return it. Otherwise returnsNone
. If there is already aReceiptValidation
for this instance that one is returned instead.This should be used for verification purpose, for example, to fetch missing data from AFIP’s servers or to complete an incomplete validation (e.g.: after a power failure).
Any new validation data is persisted into the database before returning.
- property total_tax: int
Returns the sum of all Tax objects.
- property total_vat: int
Returns the sum of all Vat objects.
- validate(ticket: AuthTicket | None = None, raise_: bool = False) list[str] [source]
Validates this receipt.
This is a shortcut to
validate()
. See the documentation for that method for details. Calling this validates only this instance.Changed in version 11: The
raise_
flag has been deprecated.- Parameters:
ticket – Use this ticket. If None, one will be loaded or created automatically.
raise – If True, an exception will be raised when validation fails.
- class django_afip.models.ReceiptValidation(*args, **kwargs)[source]
The validation for a single
Receipt
.This contains all validation-related data for a receipt, including its CAE and the CAE expiration, unless validation has failed.
The
observation
field may contain any data returned by AFIP regarding validation failure.- Parameters:
id (AutoField) – Primary key: ID
result (CharField) – Result. Indicates whether the validation was succesful or not.
processed_date (DateTimeField) – Processed date
cae (CharField) – Cae. The CAE as returned by the AFIP.
cae_expiration (DateField) – Cae expiration. The CAE expiration as returned by the AFIP.
Relationship fields:
- Parameters:
receipt (
OneToOneField
toReceipt
) – Receipt. The Receipt for which this validation applies. (related name:validation
)observations (
ManyToManyField
toObservation
) – Observations. The observations as returned by the AFIP. These are generally present for failed validations. (related name:validations
)
- exception DoesNotExist
- exception MultipleObjectsReturned
- class django_afip.models.Tax(*args, **kwargs)[source]
A tax (type+amount) for a specific Receipt.
- Parameters:
id (AutoField) – Primary key: ID
description (CharField) – Description
base_amount (DecimalField) – Base amount
aliquot (DecimalField) – Aliquot
amount (DecimalField) – Amount
Relationship fields:
- Parameters:
tax_type (
ForeignKey
toTaxType
) – Tax type (related name:tax
)receipt (
ForeignKey
toReceipt
) – Receipt (related name:taxes
)
- exception DoesNotExist
- exception MultipleObjectsReturned
- class django_afip.models.TaxPayer(*args, **kwargs)[source]
Represents an AFIP TaxPayer.
Note that multiple instances of this object can actually represent the same taxpayer, each using a different key.
The following fields are only used for generating printables, and are never sent to AFIP, hence, are entirely optional:
logo
- Parameters:
id (AutoField) – Primary key: ID
name (CharField) – Name. A friendly name to recognize this taxpayer.
key (FileField) – Key
certificate (FileField) – Certificate
cuit (BigIntegerField) – Cuit
is_sandboxed (BooleanField) – Is sandboxed. Indicates if this taxpayer should use with the sandbox servers rather than the production servers.
certificate_expiration (DateTimeField) – Certificate expiration. Stores expiration for the current certificate.<br>Note that this field is updated pre-save, so the value may be invalid for unsaved models.
active_since (DateField) – Active since. Date since which this taxpayer has been legally active.
logo (ImageField) – Logo. A logo to use when generating printable receipts.
Reverse relationships:
- Parameters:
points_of_sales (Reverse
ForeignKey
fromPointOfSales
) – All points of sales of this taxpayer (related name ofowner
)auth_tickets (Reverse
ForeignKey
fromAuthTicket
) – All auth tickets of this taxpayer (related name ofowner
)
- exception DoesNotExist
- exception MultipleObjectsReturned
- property certificate_object: X509 | None
Returns the certificate as an OpenSSL object
Returns the certificate as an OpenSSL object (rather than as a file object).
- create_ticket(service: str) AuthTicket [source]
Create an AuthTicket for a given service.
Tickets are saved to the database. It is recommended to use the
get_or_create_ticket()
method instead.
- fetch_points_of_sales(ticket: AuthTicket | None = None) list[tuple[PointOfSales, bool]] [source]
Fetch all point of sales objects.
Fetch all point of sales from the WS and store (or update) them locally.
Returns a list of tuples with the format
(pos, created,)
.
- generate_csr(basename: str = 'djangoafip') BinaryIO [source]
Creates a CSR with this TaxPayer’s key
The CSR (certificate signing request) can be used to request a new certificate via AFIP’s website. After generating a new CSR, it should be manually uploaded to AFIP’s website, and a new certificate will be returned. That certificate should be uploaded to the
certificate
field.It is safe to use with when renovating expired certificates on production systems.
- generate_key(force: bool = False) bool [source]
Creates a key file for this TaxPayer
Creates a key file for this TaxPayer if it does not have one, and immediately saves it.
A new key will not be generated if one is already set, unless the
force
parameter is true. This is to prevent overwriting a potentially in-use key.Returns True if and only if a key was created.
- get_certificate_expiration() datetime | None [source]
Return the certificate expiration from the current certificate
Gets the certificate expiration from the certificate file. Note that this value is stored into
certificate_expiration
when an instance is saved, so you should generally prefer that method (since this one requires reading and parsing the entire certificate).
- get_or_create_ticket(service: str) AuthTicket [source]
Return or create a new AuthTicket for a given serivce.
Return an existing ticket for a service if one is available, otherwise, create a new one and return that.
This is generally the preferred method of obtaining tickets for any service.
- get_ticket(service: str) AuthTicket | None [source]
Return an existing AuthTicket for a given service, if any.
It is recommended to use the
get_or_create_ticket()
method instead.
- property logo_as_data_uri: str
This TaxPayer’s logo as a data uri.
This can be used to embed the image into an HTML or PDF file.
- class django_afip.models.Vat(*args, **kwargs)[source]
A VAT (type+amount) for a specific Receipt.
- Parameters:
id (AutoField) – Primary key: ID
base_amount (DecimalField) – Base amount
amount (DecimalField) – Amount
Relationship fields:
- Parameters:
vat_type (
ForeignKey
toVatType
) – Vat type (related name:vat
)receipt (
ForeignKey
toReceipt
) – Receipt (related name:vat
)
- exception DoesNotExist
- exception MultipleObjectsReturned
- class django_afip.models.Optional(*args, **kwargs)[source]
A optional (type+value) for a specific Receipt.
Relationship fields:
- Parameters:
optional_type (
ForeignKey
toOptionalType
) – Optional type (related name:optional
)receipt (
ForeignKey
toReceipt
) – Receipt (related name:optionals
)
- exception DoesNotExist
- exception MultipleObjectsReturned
PDF builder
- class django_afip.pdf.PdfBuilder(entries_per_page: int = 15)[source]
Builds PDF files for Receipts.
Creating a new instance of a builder does nothing; use
render_pdf()
to actually render the file.This type can be subclassed to add custom behaviour or data into PDF files.
- get_template_names(receipt: Receipt) list[str] [source]
Return the templates use to render the Receipt PDF.
Template discovery tries to find any of the below receipts:
receipts/{taxpayer}/pos_{point_of_sales}/code_{code}.html receipts/{taxpayer}/code_{code}.html receipts/code_{code}.html receipts/{code}.html
To override, for example, the “Factura C” template for point of sales 0002 for Taxpayer 20-32964233-0, use:
receipts/20329642330/pos_2/code_6.html
Metadata models
These models represent metadata like currency types or document types.
You should make sure you populate these tables either via the afipmetadata
command, or the load_metadata
function:
- class django_afip.models.ConceptType(*args, **kwargs)[source]
An AFIP concept type.
See the AFIP’s documentation for details on each concept type.
- Parameters:
Reverse relationships:
- Parameters:
receipts (Reverse
ForeignKey
fromReceipt
) – All receipts of this concept type (related name ofconcept
)
- exception DoesNotExist
- exception MultipleObjectsReturned
- class django_afip.models.CurrencyType(*args, **kwargs)[source]
An AFIP curreny type.
See the AFIP’s documentation for details on each currency type.
- Parameters:
Reverse relationships:
- Parameters:
documents (Reverse
ForeignKey
fromReceipt
) – All documents of this currency type (related name ofcurrency
)
- exception DoesNotExist
- exception MultipleObjectsReturned
- class django_afip.models.DocumentType(*args, **kwargs)[source]
An AFIP document type.
See the AFIP’s documentation for details on each document type.
- Parameters:
Reverse relationships:
- Parameters:
receipts (Reverse
ForeignKey
fromReceipt
) – All receipts of this document type (related name ofdocument_type
)
- exception DoesNotExist
- exception MultipleObjectsReturned
- class django_afip.models.Observation(*args, **kwargs)[source]
An observation returned by AFIP.
AFIP seems to assign re-used codes to Observation, so we actually store them as separate objects, and link to them from failed validations.
- Parameters:
id (AutoField) – Primary key: ID
code (PositiveSmallIntegerField) – Code
message (CharField) – Message
Reverse relationships:
- Parameters:
validations (Reverse
ManyToManyField
fromReceiptValidation
) – All validations of this observation (related name ofobservations
)
- exception DoesNotExist
- exception MultipleObjectsReturned
- class django_afip.models.ReceiptType(*args, **kwargs)[source]
An AFIP receipt type.
See the AFIP’s documentation for details on each receipt type.
- Parameters:
Reverse relationships:
- Parameters:
receipts (Reverse
ForeignKey
fromReceipt
) – All receipts of this receipt type (related name ofreceipt_type
)
- exception DoesNotExist
- exception MultipleObjectsReturned
- class django_afip.models.TaxType(*args, **kwargs)[source]
An AFIP tax type.
See the AFIP’s documentation for details on each tax type.
- Parameters:
Reverse relationships:
- Parameters:
tax (Reverse
ForeignKey
fromTax
) – All taxes of this tax type (related name oftax_type
)
- exception DoesNotExist
- exception MultipleObjectsReturned
- class django_afip.models.VatType(*args, **kwargs)[source]
An AFIP VAT type.
See the AFIP’s documentation for details on each VAT type.
- Parameters:
Reverse relationships:
- Parameters:
receipt_entries (Reverse
ForeignKey
fromReceiptEntry
) – All receipt entries of this vat type (related name ofvat
)vat (Reverse
ForeignKey
fromVat
) – All vat of this vat type (related name ofvat_type
)
- exception DoesNotExist
- exception MultipleObjectsReturned
- property as_decimal: Decimal
Return this VatType as a Decimal.
Parses the percent amount from the
description
field. This number is usable when calculating the Vat for entries which have this type. If Vat is 21%, then the returned value isDecimal("0.21")
.Assuming that an item pays 21% vat, when using a net price for the calculation, the following are all correct:
total_price = net_price * Decimal(1.21) vat = net_price * Decimal(0.21) vat = total_price - net_price
If using the total price, this approach should be used (this can be derived from the above):
net_price = total_price / Decimal(1.21) vat = total_price - net_price
Keep in mind that AFIP requires the usage of “round half even”, which is what Python’s
Decimal
class uses by default (Seedecimal.ROUND_HALF_EVEN
).
- class django_afip.models.OptionalType(*args, **kwargs)[source]
An AFIP optional type.
See the AFIP’s documentation for details on each optional type.
- Parameters:
Reverse relationships:
- Parameters:
optional (Reverse
ForeignKey
fromOptional
) – All optionals of this optional type (related name ofoptional_type
)
- exception DoesNotExist
- exception MultipleObjectsReturned
Managers
Managers should be accessed via models. For example, ReceiptManager
should be accessed using Receipt.objects
.
- class django_afip.models.ReceiptManager(*args, **kwargs)[source]
Default manager for the
Receipt
class.This should be accessed using
Receipt.objects
.- fetch_last_receipt_number(point_of_sales: PointOfSales, receipt_type: ReceiptType) int [source]
Returns the number for the last validated receipt.
- fetch_receipt_data(receipt_type: str, receipt_number: int, point_of_sales: PointOfSales)[source]
Returns receipt related data
- get_queryset() ReceiptQuerySet [source]
Return a new QuerySet object.
This always joins with
ReceiptType
.
- class django_afip.models.ReceiptPDFManager(*args, **kwargs)[source]
- create_for_receipt(receipt: Receipt, **kwargs) ReceiptPDF [source]
Creates a ReceiptPDF object for a given receipt.
Does not actually generate the related PDF file.
All attributes will be completed with the information for the relevant
PointOfSales
instance.- Parameters:
receipt – The receipt for the PDF which will be generated.
kwargs – Passed directly to the
ReceiptPDF
constructor.
QuerySets
QuerySets are generally accessed via their models. For example,
Receipt.objects.filter()
will return a ReceiptQuerySet
.
- class django_afip.models.ReceiptQuerySet(model=None, query=None, using=None, hints=None)[source]
The default queryset obtains when querying via
ReceiptManager
.- check_groupable() ReceiptQuerySet [source]
Check that all receipts returned by this queryset are groupable.
“Groupable” means that they can be validated together: they have the same POS and receipt type.
Returns the same queryset is all receipts are groupable, otherwise, raises
CannotValidateTogether
.
- validate(ticket: AuthTicket | None = None) list[str] [source]
Validate all receipts matching this queryset.
Note that, due to how AFIP implements its numbering, this method is not thread-safe, or even multiprocess-safe. You MAY however, call this method concurrently for receipts from different
PointOfSales
.It is possible that not all instances matching this queryset are validated properly. This method is written in a way that the database will always remain in a consistent state.
Only successfully validated receipts will marked as such. This method takes care of saving all changes to database.
Returns a list of errors as returned from AFIP’s webservices. When AFIP returns a failure response, an exception is not raised because partial failures are possible. Network issues (e.g.: DNS failure) _will_ raise an exception.
Receipts that successfully validate will have a
ReceiptValidation
object attached to them with a validation date and CAE information.Already-validated receipts are ignored.
Attempting to validate an empty queryset will simply return an empty list.
This method takes the following steps:
Assigns numbers to all receipts.
Saves the assigned numbers to the database.
Sends the receipts to AFIP.
Saves the results into the local DB.
Should execution be interrupted (e.g.: a power failure), receipts will have been saved with their number. In this case, the
revalidate
method should be used, to determine if they have been registered by AFIP, or if the interruption happened before sending them.Calling this method inside a transaction will raise
RuntimeError
, since doing so risks leaving the database in an inconsistent state should there be any fatal interruptions. In particular, the receipt numbers will not have been saved, so it would be impossible to recover from the incomplete operation.
Helpers
- django_afip.helpers.get_server_status(production: bool) ServerStatus [source]
Return the status of AFIP’s WS servers
- Parameters:
production – Whether to check the production servers. If false, the testing servers will be checked instead.
- class django_afip.helpers.ServerStatus(app: bool, db: bool, auth: bool)[source]
A dataclass holding the server’s reported status.
An instance is truthy if all services are okay, or evaluates to
False
if at least one isn’t:if not server_status: print("At least one service is down") else print("All serivces are up")
- __init__(app: bool, db: bool, auth: bool) None
- app: bool
Whether the application server is working.
- auth: bool
Whether the authentication server is working.
- db: bool
Whether the database server is working.
Exceptions
WebService clients
These clients provide direct access to AFIP’s WS. These are reserved for advanced usage.
- django_afip.clients.get_client(service_name: str, sandbox: bool = False) Client [source]
Return a client for a given service.
The sandbox argument should only be necessary if the client will be used to make a request. If it will only be used to serialize objects, it is irrelevant. A caller can avoid the overhead of determining the sandbox mode in the calling context if only serialization operations will take place.
This function is cached with lru_cache, and will re-use existing clients if possible.
- Parameters:
service_name – The name of the web services.
sandbox – Whether the sandbox (or production) environment should be used by the returned client.
- Returns:
A zeep client to communicate with an AFIP web service.