Warning
This version requires NetBox 4.6.0 or later. Read the Breaking Changes below before upgrading: the upgrade converts the contract costs and invoice templates into contract lines, and changes how invoices are created and locked.
Breaking Changes
- A new invoice can no longer be linked to more than one contract. Existing invoices linked to several contracts stay as they are and can be edited, but no contract can be added to them. These rules also apply to bulk edits of invoices, whose Template field is offered only when
show_deprecated_fieldsisTrue. (#278) - A new invoice must have the currency of its contract, and cannot be created for a non-billable contract. (#278)
- Creating an invoice (web interface or
POST invoices/) now generates its invoice lines from the contract lines, and is refused when the invoice amount is lower than their total. Invoice lines are not generated when an invoice is edited or imported. (#278) - The copy of invoice template lines onto a new invoice is removed. Invoice templates are no longer used to pre-fill invoices; the pre-fill uses the contract lines instead of
mrcandyrc. (#278) - New invoices are Draft by default (previously Posted), in the web interface and the REST API; imports still set the status given in the file. (#278)
- Posted invoices are locked: their amount, currency, period and contracts cannot change, lines cannot be added or deleted, and the unit, unit price, quantity and amount of their lines cannot change. Set an invoice back to Draft to correct it. (#278)
- The amount of every invoice line is quantity x unit price and can no longer be typed, as in most ERPs; the unit price is required and the quantity defaults to 1. An import or API call that gives only an amount still works: the amount becomes the unit price with quantity 1. Migration 0049 gives existing lines a unit price without changing any amount. (#278)
- Contract lines are locked once their contract has an invoice (any status) or once an invoice line references them: a new contract must be created. Their accounting dimensions, comments and tags remain editable, and their price or quantity can be amended from a date after the last invoiced period. The billing method and months of a unit used by such lines are locked too. (#278)
- The billable flag of a contract cannot change once the contract, one of its parents or one of its children has invoices. The currency of a contract cannot change once it has invoices or invoice lines; without invoices, its contract lines follow the new currency. Changing the currency of a contract also changes its non-billable descendants of the same currency, unless one of them has invoices. (#278)
- A contract whose lines (or those of its child contracts) are on posted invoices can no longer be deleted. (#278)
- The contract cost fields, new invoice templates and the invoice template section of the contract page are hidden unless
show_deprecated_fieldsisTrue; templates remain reachable from the invoice list. The mandatory and hidden field settings ignore a deprecated field that is not shown (with a warning in the log) instead of failing. (#278) - The custom scripts
create_invoice_templateandcreate_invoice_linesare removed: they read fields that no longer exist and are superseded by the conversion. (#278) - API clients that passed filters to
serviceproviders/,contracttype/,accountingdimension/orcontractassignment/now get the filtered list instead of every object. (#307) - Amending a contract line requires the new amend permission action. The add and change contract line permissions (required since #307) are no longer enough; administrators grant the new action to the users who amend lines. This applies to the screen and to the REST action
POST contract-lines/{id}/amend/. (#309) - The related tables of detail pages show the default columns of their lists (for example the contract lines of a contract show the contract line list columns, without the contract). Users who want other columns choose them on the list with Configure Table. (#309)
- On the contract page, the deprecated costs (
mrc,yrc,nrc, shown withshow_deprecated_fields) are grouped in a Deprecated costs panel. The invoice page applies thehidden_invoice_fieldssetting, which it ignored until now. (#309) - Contract type descriptions are limited to 200 characters, as on core objects: a longer description is refused (form, import, REST API). On upgrade, every contract type gets a slug derived from its name, made unique with
-2,-3, ... when needed, and a longer description is shortened at a word boundary (ending with "…") with its full text moved to the new comments; the migration prints every slug it made unique and every description it moved. Migrating back restores the moved descriptions. (#309) - Code that creates contract types with
bulk_create()must give a slug, sincebulk_create()does not callsave(), which derives it. (#309) - OpenAPI schema: the components
NestedInvoice,NestedAccountingDimensionandNestedContractLineare replaced byBriefInvoice,BriefAccountingDimensionandBriefContractLine, with the same properties (on NetBox 4.6.10 or later; earlier 4.6 releases document the accounting dimension lists with theAccountingDimensioncomponent). Clients generated from the schema must be regenerated; the responses are unchanged. (#309)
New Features
Contract Lines and Units (#278)
Contract lines replace the contract costs (mrc, yrc, nrc) and the invoice templates. The new Unit model defines a billing method (one-time, recurring or usage-based) and the number of months one unit price covers; a Contract line has a description, quantity, unit price, unit, currency, start and end dates and accounting dimensions. Both have list, detail, edit, bulk import, bulk edit and bulk delete screens.
Contracts get a billable flag and three computed values: total contract value, yearly value and yearly billable value (which includes the lines of non-billable descendants).
On upgrade, a data migration converts the monthly, yearly and non-recurring costs and the invoice templates into contract lines (units "One-time", "Monthly", "Yearly") and prints a report. It can be run again with python manage.py convert_contract_lines. Every existing contract is billable. Invoices and invoice lines are not changed.
Invoices Generated from Contract Lines (#278)
The invoice add screen proposes the amount from the contract lines and previews the invoice lines that will be generated, with their amounts and total. Their quantities, unit prices and accounting dimensions can be changed, and lines without contract line added, before saving; the invoice and its lines are created in one step.
Invoice lines reference their contract line and carry their own quantity, unit and unit price, taken from the contract line by default and editable as long as the invoice is not posted (for example a discount on one invoice). Their amount is calculated as quantity x unit price. Migration 0047 copies the unit and unit price of the contract line into existing lines without changing their amounts.
Contract Line Amendments (#278, #309)
The unit price or quantity of a recurring or usage-based line can be amended from a date (Amend button, or POST contract-lines/{id}/amend/): the line ends the day before and a new line replaces it, invoiced periods keep their price, and the required reason is recorded in the change log. Amending has its own amend permission action (migration 0050), which can be limited with constraints; the Amend button is shown on the line page, in contract line tables and on the edit page only for the lines the user may amend.
Currency Consistency and Posted Invoice Locking (#278)
Contract lines, invoices and invoice lines must have the currency of their contract or invoice, and a non-billable child contract has the currency of its parent. The new read-only custom script "Report currency mismatches" lists existing mismatches without changing them.
Posted invoices are locked: their amounts, period and contracts, and the amounts of their lines, can no longer change, and lines can no longer be added or deleted. Accounting dimensions, comments and tags remain editable, and the status can change back to Draft.
GraphQL API (#309)
Contracts, contract lines, contract types, contract assignments, invoices, invoice lines, units, accounting dimensions and service providers can be queried and filtered in NetBox's GraphQL API, with permissions applied. It has the stored fields and relations; the computed contract and line values stay in the REST API, and an assigned object is resolved for the models of the default supported_models setting (see the API documentation).
Enhancements
- #278 - Invoice lines have a readable name (
<invoice number> line <id>) in search results, the change log and reports - #308 - Add the Journal tab to invoice lines, accounting dimensions, contract types and contract assignments
- #308 - Filter forms offer NetBox's lookup modifiers (contains, starts with, is not, is empty, ...)
- #308 - Add, edit, bulk edit and filter forms group their fields into sections (for contracts: Contract, Parties, Dates and terms, Billing, Tenancy)
- #308 - The invoice and invoice line add screens support NetBox's quick add and partial refresh; values given in the page address (for example
?date=or?period_start=) are kept by the invoice pre-fill instead of being replaced - #308 - The contract type description is a plain text field in the filter, bulk edit and import forms, and can be cleared in bulk
- #308 - Invoice line tables (list, invoice page) show the linked ID by default, so a line can be opened; users who saved their own column choice add it from Configure Table
- #308 - Refresh the translations and translate the new texts of 2.5.0 into French
- #309 - The detail pages of the nine object types are built from NetBox's standard panels; their related tables are the tables of the corresponding lists filtered to the object, so their columns can be chosen with Configure Table on the list (#294)
- #309 - Contract line tables decide their actions line by line: a locked line offers no Delete, and an amendable line offers Amend
- #309 - Add the contract list filter
invoice_id(UI and REST API): the contracts of an invoice - #309 - Contract types become NetBox organizational objects, with a slug, comments and an owner; service providers become NetBox primary objects, with a description and an owner (migrations 0051 and 0052). Both can be filtered by owner, and the owner can be set in bulk and imported. A contract type's slug is derived from its name when it is not given
Bug Fixes
- #307 - The Contracts tab of assigned objects (sites, devices, circuits, ...) is shown to users with the view contract assignment permission; it was shown to superusers only, because it checked a permission of a non-existent
contractsapp - #307 - The REST endpoints
serviceproviders/,contracttype/,accountingdimension/andcontractassignment/ignored their filters (name,q,tag,contract, ...) and always returned the whole list - #307 - The OpenAPI schema documents
external_party_object(contracts, and the contract nested in contract lines and assignments) andcontent_object(contract assignments) as objects instead of strings - #307 - The invoice line add form pre-fills the unit price and currency only from an invoice the user may view, and no longer fails with a server error when the
invoiceparameter is unknown or not a number - #307 - The Amend button of contract lines was shown to users with the change permission alone, who then got a "forbidden" page
- #308 - Editing an existing invoice showed today's date in place of its date
Plugins
- #308 - Every screen of the plugin is registered with
register_model_view, so other plugins can add tabs and actions to any plugin object; page addresses do not change - #309 - Other plugins can add content to the left, right and full-width areas of every plugin page
- #309 - The template shown at the bottom of assigned objects moved to
netbox_contract/inc/contract_assignments_bottom.html, and the unusedcontract_list_bottom.htmlwas removed
Deprecations
- #278 - The contract fields
mrc,yrcandnrcand the invoice templates are deprecated. They are kept (never deleted, shown with a "deprecated" badge) and hidden by default; the new plugin settingshow_deprecated_fields(defaultFalse) shows them again. They remain in the bulk import and the REST API - #309 - REST API fields, to be removed by a later release (see the API documentation; read
contracts/{id}/orinvoices/{id}/instead):- Nested contract (
contractof assignments and contract lines,parentof contracts):contract_type,external_party_object_type,external_party_object_id,external_party_object,external_reference,internal_party,tenant,start_date,end_date,initial_term,renewal_term,notice_period,currency,mrc,yrc,nrc,invoice_frequency,comments,documents; it will keepid,url,display,nameandstatus contractsof an invoice become brief contracts: the fields above andbillable,total_contract_value,yearly_contract_value,yearly_billable_value,parent,tags,custom_fields,created,last_updatedwill be removedcontracts/?brief=true:contract_type,external_party_object_type,external_party_object_id,external_party_object,external_reference,internal_party,tenant,start_date,end_date,initial_term,renewal_term,currency,mrc,yrc,nrc,invoice_frequency,billable,comments,parentinvoices/?brief=true:date,template,contracts,period_start,period_end,currency,amount,comments
- Nested contract (
Other Changes
- #278 - CI runs the tests against the NetBox v4.6.10 tag
- #307 - The plugin no longer depends on
drf_yasg, which NetBox does not use
REST API Changes
- Added the following endpoints:
GET/POST /api/plugins/contracts/units/GET/PUT/PATCH/DELETE /api/plugins/contracts/units/<id>/GET/POST /api/plugins/contracts/contract-lines/GET/PUT/PATCH/DELETE /api/plugins/contracts/contract-lines/<id>/POST /api/plugins/contracts/contract-lines/<id>/amend/
netbox_contract.Contract- Add the
billableboolean field - Add the read-only
total_contract_value,yearly_contract_valueandyearly_billable_valuefields - Add the
invoice_idfilter mrc,yrcandnrcare deprecated
- Add the
netbox_contract.ContractType- Add the
slug,commentsandownerfields - The brief representation gains
sluganddescription
- Add the
netbox_contract.ServiceProvider- Add the
descriptionandownerfields - The brief representation gains
sluganddescription
- Add the
netbox_contract.Invoice- New invoices default to the
draftstatus templateis deprecated- The nested invoice uses NetBox's brief representation (same fields)
- New invoices default to the
netbox_contract.InvoiceLine- Add the
contract_line,quantity,unitandunit_pricefields;amountis calculated - The brief representation gains
idandcurrencyand no longer declares the non-existentname
- Add the
netbox_contract.ContractLine- The brief representation (also used for the replaced line,
replaces) includesstart_dateandend_date
- The brief representation (also used for the replaced line,
netbox_contract.AccountingDimension- The nested accounting dimensions use NetBox's brief representation (same fields)
Full Changelog: v2.4.7...v2.5.0