netbox-contract 2.3.0__tar.gz → 2.3.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. netbox_contract-2.3.1/CONTRIBUTING.md +144 -0
  2. netbox_contract-2.3.1/MANIFEST.in +13 -0
  3. {netbox_contract-2.3.0/src/netbox_contract.egg-info → netbox_contract-2.3.1}/PKG-INFO +23 -14
  4. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/README.md +22 -13
  5. netbox_contract-2.3.1/docs/img/accounting_dimensions.png +0 -0
  6. netbox_contract-2.3.1/docs/img/contract.png +0 -0
  7. netbox_contract-2.3.1/docs/img/contract_linked_objects.png +0 -0
  8. netbox_contract-2.3.1/docs/img/invoice.png +0 -0
  9. netbox_contract-2.3.1/docs/img/invoice_line.png +0 -0
  10. netbox_contract-2.3.1/docs/img/invoice_linked_objects.png +0 -0
  11. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/pyproject.toml +1 -1
  12. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/__init__.py +2 -2
  13. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/forms.py +26 -80
  14. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/models.py +16 -42
  15. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/tables.py +11 -4
  16. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/templates/netbox_contract/contract.html +3 -3
  17. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/templates/netbox_contract/contractassignment.html +1 -1
  18. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/templates/netbox_contract/invoice.html +1 -1
  19. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/templates/netbox_contract/invoiceline.html +1 -1
  20. {netbox_contract-2.3.0 → netbox_contract-2.3.1/src/netbox_contract.egg-info}/PKG-INFO +23 -14
  21. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract.egg-info/SOURCES.txt +10 -1
  22. netbox_contract-2.3.1/tests/__init__.py +1 -0
  23. netbox_contract-2.3.1/tests/test_netbox_contract.py +5 -0
  24. netbox_contract-2.3.0/MANIFEST.in +0 -2
  25. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/LICENSE +0 -0
  26. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/setup.cfg +0 -0
  27. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/setup.py +0 -0
  28. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/api/__init__.py +0 -0
  29. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/api/serializers.py +0 -0
  30. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/api/urls.py +0 -0
  31. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/api/views.py +0 -0
  32. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/constants.py +0 -0
  33. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/filtersets.py +0 -0
  34. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/migrations/0001_initial.py +0 -0
  35. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/migrations/0002_alter_contract_circuit_and_more.py +0 -0
  36. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/migrations/0003_alter_contract_custom_field_data_and_more.py +0 -0
  37. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/migrations/0004_contract_currency_invoice_currency.py +0 -0
  38. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/migrations/0005_contract_accounting_dimensions_and_more.py +0 -0
  39. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/migrations/0006_alter_contract_circuit.py +0 -0
  40. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/migrations/0007_invoice_date.py +0 -0
  41. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/migrations/0008_invoice_comments.py +0 -0
  42. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/migrations/0009_contract_external_reference.py +0 -0
  43. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/migrations/0010_invoice_contracts.py +0 -0
  44. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/migrations/0011_auto_20230122_2112.py +0 -0
  45. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/migrations/0012_remove_invoice_contract.py +0 -0
  46. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/migrations/0013_contract_documents_invoice_documents.py +0 -0
  47. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/migrations/0014_contract_end_date.py +0 -0
  48. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/migrations/0015_contractassignement.py +0 -0
  49. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/migrations/0016_contract_parent.py +0 -0
  50. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/migrations/0017_alter_contract_accounting_dimensions.py +0 -0
  51. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/migrations/0018_contract_external_partie_object_id_and_more.py +0 -0
  52. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/migrations/0019_auto_20230924_1813.py +0 -0
  53. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/migrations/0020_alter_contract_external_partie.py +0 -0
  54. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/migrations/0021_alter_contract_external_partie.py +0 -0
  55. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/migrations/0022_alter_contract_internal_partie_alter_contract_parent.py +0 -0
  56. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/migrations/0023_rename_contractassignement_contractassignment_and_more.py +0 -0
  57. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/migrations/0024_remove_contract_external_partie.py +0 -0
  58. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/migrations/0025_remove_contract_circuit_and_more.py +0 -0
  59. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/migrations/0026_auto_20240421_1550.py +0 -0
  60. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/migrations/0027_invoiceline.py +0 -0
  61. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/migrations/0028_invoiceline_accounting_dimensions.py +0 -0
  62. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/migrations/0029_remove_invoiceline_accounting_dimensions_and_more.py +0 -0
  63. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/migrations/0030_alter_invoiceline_accounting_dimensions.py +0 -0
  64. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/migrations/0031_contract_invoice_template_invoice_template.py +0 -0
  65. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/migrations/0032_alter_invoice_period_end_alter_invoice_period_start_and_more.py +0 -0
  66. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/migrations/0033_remove_contract_invoice_template.py +0 -0
  67. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/migrations/0034_contract_yrc_alter_contract_mrc.py +0 -0
  68. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/migrations/0035_accountingdimension_status_and_more.py +0 -0
  69. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/migrations/0036_alter_invoiceline_accounting_dimensions.py +0 -0
  70. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/migrations/0037_contract_notice_period_alter_contract_currency_and_more.py +0 -0
  71. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/migrations/0038_alter_accountingdimension_options_and_more.py +0 -0
  72. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/migrations/0039_alter_accountingdimension_status_and_more.py +0 -0
  73. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/migrations/__init__.py +0 -0
  74. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/navigation.py +0 -0
  75. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/search.py +0 -0
  76. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/template_content.py +0 -0
  77. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/templates/contract_assignments_bottom.html +0 -0
  78. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/templates/contract_list_bottom.html +0 -0
  79. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/templates/netbox_contract/accountingdimension.html +0 -0
  80. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/templates/netbox_contract/serviceprovider.html +0 -0
  81. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/urls.py +0 -0
  82. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract/views.py +0 -0
  83. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract.egg-info/dependency_links.txt +0 -0
  84. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract.egg-info/not-zip-safe +0 -0
  85. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract.egg-info/requires.txt +0 -0
  86. {netbox_contract-2.3.0 → netbox_contract-2.3.1}/src/netbox_contract.egg-info/top_level.txt +0 -0
@@ -0,0 +1,144 @@
1
+ # Contributing
2
+
3
+ Contributions are welcome!
4
+
5
+ ## Types of contributions
6
+
7
+ ### Report bugs or submit feedback
8
+
9
+ Report bugs and submit feetback [here](https://github.com/mlebreuil/netbox-contract/issues).
10
+
11
+ ### Fix bugs
12
+
13
+ Look through the GitHub issues for bugs. Anything tagged with "bug" and "help
14
+ wanted" is open to whoever wants to implement it.
15
+
16
+ ### Implement features
17
+
18
+ Look through the GitHub issues for features. Anything tagged with "enhancement"
19
+ and "help wanted" is open to whoever wants to implement it.
20
+
21
+ ## Coding conventions
22
+
23
+ Netbox [Style Guide](https://docs.netbox.dev/en/stable/development/style-guide/)
24
+ Django [Coding style](https://docs.djangoproject.com/en/4.2/internals/contributing/writing-code/coding-style/)
25
+
26
+ For this:
27
+ All files will be formated using the [black](https://black.readthedocs.io/en/stable/) auto-formatter.
28
+ Configuration is stored in pyproject.toml
29
+
30
+ [isort](https://github.com/PyCQA/isort#readme) is used to automate import sorting.
31
+
32
+ Linting and PEP8 style enforcement will be done with [Flake8](https://flake8.pycqa.org/en/latest/) which is a wrapper arround:
33
+ - PyFlakes
34
+ - pycodestyle
35
+ - Ned Batchelder’s McCabe script
36
+ Configuration is maintained in the .flake8 file (no support for pyproject.toml)
37
+
38
+ The pre-commit Python framework is used to simplify the managment of pre-commit hooks.
39
+ Config is stored in .pre-commit-config.yaml
40
+
41
+ ## Repository structure
42
+
43
+ There are 2 permanent branch in the repository:
44
+
45
+ * master - The current stable release. Individual changes should never be pushed directly to this branch, but rather merged from develop.
46
+ * develop - Active development for the upcoming patch release. Pull requests will typically be based on this branch unless they introduce breaking changes that must be deferred until the next minor release.
47
+
48
+ For each new feature or bug fix a branch is created from the corresponding issue.
49
+
50
+ ## Setup your development environment
51
+
52
+
53
+ 1. [Install Netbox](https://github.com/netbox-community/netbox/blob/develop/docs/installation/).
54
+ Make sure taht at the Netbox installtion step you follow the "Option B: Clone the Git Repository"
55
+
56
+ 2. From the Netbox directory you activate the NetBox virtual environment
57
+
58
+ ```
59
+ $ cd netbox
60
+ $ source venv/netbox/bin/activate
61
+ ```
62
+
63
+ 3. Fork the [netbox-contract](https://github.com/mlebreuil/netbox-contract/) repo on GitHub.
64
+ 4. Clone your fork locally
65
+
66
+ ```
67
+ $ cd ..
68
+ $ git clone git@github.com:your_name_here/netbox-contract.git
69
+ ```
70
+
71
+ 5. Add the plugin to NetBox virtual environment:
72
+
73
+ ```
74
+ $ cd netbox-contract
75
+ $ python3 -m pip install -e .
76
+ ```
77
+
78
+ 6. install pre-commit:
79
+
80
+ ```bash
81
+ python -m pip install pre-commit
82
+ pre-commit install
83
+ ```
84
+
85
+ 6. Update the Netbox configuration and run the database migrations as mentionned in the plugin installation steps.
86
+
87
+ 7. Create a branch for local development:
88
+
89
+ ```
90
+ $ git checkout -b name-of-your-bugfix-or-feature
91
+ ```
92
+
93
+ Make your changes locally.
94
+
95
+ 8. You can test your changes using the django development server:
96
+
97
+ ```
98
+ $ python3 netbox/netbox/manage.py runserver 0.0.0.0:8000 --insecure
99
+ ```
100
+
101
+ Connect to the name or IP of the server (as defined in ALLOWED_HOSTS) on port 8000; for example, http://127.0.0.1:8000/.
102
+
103
+ 9. Commit your changes and push your branch to GitHub:
104
+
105
+ ```
106
+ $ git add .
107
+ $ git commit -m "Your detailed description of your changes."
108
+ $ git push origin name-of-your-bugfix-or-feature
109
+ ```
110
+
111
+ 10. Submit a pull request through the GitHub website.
112
+
113
+ ## Model changes
114
+
115
+ Create the migrations:
116
+
117
+ ```bash
118
+ source netbox/venv/bin/activate
119
+ python3 netbox/netbox/manage.py makemigrations netbox_contract --dry-run
120
+ python3 netbox/netbox/manage.py makemigrations netbox_contract
121
+ ```
122
+
123
+ Apply the migrations:
124
+
125
+ ```bash
126
+ source netbox/venv/bin/activate
127
+ python3 netbox/netbox/manage.py migrate
128
+ ```
129
+
130
+ ## Pull Request Guidelines
131
+
132
+ Before you submit a pull request, check that it meets these guidelines:
133
+
134
+ 1. The pull request should include tests.
135
+ 2. If the pull request adds functionality, the docs should be updated.
136
+ 3. The pull request should work for Python 3.10 and 3.11. Check [Actions](https://github.com/mlebreuil/netbox-contract/actions)
137
+ and make sure that the tests pass for all supported Python versions.
138
+
139
+
140
+ ## Deploying
141
+
142
+ A reminder for the maintainers on how to deploy.
143
+ Make sure all your changes are committed (including an entry in CHANGELOG.md) and that all tests pass.
144
+ Then in the github project go to `Releases` and create a new release with a new tag. This will automatically upload the release to pypi:
@@ -0,0 +1,13 @@
1
+ include CONTRIBUTING.md
2
+ include LICENSE
3
+ include README.md
4
+
5
+ recursive-include tests *
6
+ recursive-exclude * __pycache__
7
+ recursive-exclude * *.py[co]
8
+
9
+ recursive-include docs *.rst conf.py Makefile make.bat *.jpg *.png *.gif
10
+
11
+
12
+ graft src/netbox_contract/templates
13
+ graft src/netbox_contract/templates/netbox_contract
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: netbox-contract
3
- Version: 2.3.0
3
+ Version: 2.3.1
4
4
  Summary: Contract management plugin for Netbox
5
5
  Author-email: Marc Lebreuil <marc@famillelebreuil.net>
6
6
  Project-URL: Homepage, https://github.com/mlebreuil/netbox-contract
@@ -15,14 +15,29 @@ Requires-Dist: python-dateutil
15
15
  Requires-Dist: drf_yasg
16
16
 
17
17
  # Contract pluggin
18
- ## Overview
18
+
19
+ NetBox plugin to manage contracts.
20
+
21
+
22
+ * Free software: MIT
23
+ * Documentation: https://mlebreuil.github.io/netbox-contract/
24
+
25
+ ## Features
26
+
19
27
  The pluggin adds contracts and invoices model to Netbox.
20
- It allows to register contract with objects.
21
- Add invoices to contracts.
28
+ It allows to link contract with objects.
29
+ And link invoice templates and invoices with contracts.
30
+ Invoice lines can be linked to each invoice / invoice template.
31
+ Accounitng dimentoins can be linked with invoice lines.
32
+
33
+ ## Compatibility
22
34
 
23
- Check the [documentation](https://mlebreuil.github.io/netbox-contract/) for additional information
35
+ | NetBox Version | Plugin Version |
36
+ |----------------|----------------|
37
+ | 4.1 | 2.2 |
38
+ | 4.2 | 2.3 |
24
39
 
25
- ## Installation
40
+ ## Installing
26
41
 
27
42
  ### Activate venv
28
43
  To ensure our plugin is accessible to the NetBox installation, we first need to activate the Python [virtual environment](https://docs.python.org/3/library/venv.html) that was created when we installed NetBox. To do this, determine the virtual environment's path (this will be `/opt/netbox/venv/` if you use the documentation's defaults) and activate it:
@@ -57,11 +72,6 @@ The following configurationitems can be set:
57
72
  PLUGINS_CONFIG = {
58
73
  'netbox_contract': {
59
74
  'top_level_menu': True,
60
- 'default_accounting_dimensions':{
61
- "account": "",
62
- "project": "",
63
- "cost center": ""
64
- },
65
75
  'mandatory_contract_fields': [],
66
76
  'hidden_contract_fields': [],
67
77
  'mandatory_invoice_fields': [],
@@ -86,9 +96,8 @@ The first currency will also be the default currency for contracts.
86
96
  # configuration.py
87
97
  FIELD_CHOICES = {
88
98
  'netbox_contract.Contract.internal_partie': (
89
- ('Nagravision SARL', 'Nagravision SARL', 'green'),
90
- ('Nagra USA', 'Nagra USA', 'green'),
91
- ('Nagra India', 'Nagra India', 'green'),
99
+ ('entity1', 'Entity 1', 'green'),
100
+ ('entity2', 'Entity 2', 'yellow'),
92
101
  ),
93
102
  'netbox_contract.Contract.currency': (
94
103
  ('usd', 'USD'),
@@ -1,12 +1,27 @@
1
1
  # Contract pluggin
2
- ## Overview
2
+
3
+ NetBox plugin to manage contracts.
4
+
5
+
6
+ * Free software: MIT
7
+ * Documentation: https://mlebreuil.github.io/netbox-contract/
8
+
9
+ ## Features
10
+
3
11
  The pluggin adds contracts and invoices model to Netbox.
4
- It allows to register contract with objects.
5
- Add invoices to contracts.
12
+ It allows to link contract with objects.
13
+ And link invoice templates and invoices with contracts.
14
+ Invoice lines can be linked to each invoice / invoice template.
15
+ Accounitng dimentoins can be linked with invoice lines.
16
+
17
+ ## Compatibility
6
18
 
7
- Check the [documentation](https://mlebreuil.github.io/netbox-contract/) for additional information
19
+ | NetBox Version | Plugin Version |
20
+ |----------------|----------------|
21
+ | 4.1 | 2.2 |
22
+ | 4.2 | 2.3 |
8
23
 
9
- ## Installation
24
+ ## Installing
10
25
 
11
26
  ### Activate venv
12
27
  To ensure our plugin is accessible to the NetBox installation, we first need to activate the Python [virtual environment](https://docs.python.org/3/library/venv.html) that was created when we installed NetBox. To do this, determine the virtual environment's path (this will be `/opt/netbox/venv/` if you use the documentation's defaults) and activate it:
@@ -41,11 +56,6 @@ The following configurationitems can be set:
41
56
  PLUGINS_CONFIG = {
42
57
  'netbox_contract': {
43
58
  'top_level_menu': True,
44
- 'default_accounting_dimensions':{
45
- "account": "",
46
- "project": "",
47
- "cost center": ""
48
- },
49
59
  'mandatory_contract_fields': [],
50
60
  'hidden_contract_fields': [],
51
61
  'mandatory_invoice_fields': [],
@@ -70,9 +80,8 @@ The first currency will also be the default currency for contracts.
70
80
  # configuration.py
71
81
  FIELD_CHOICES = {
72
82
  'netbox_contract.Contract.internal_partie': (
73
- ('Nagravision SARL', 'Nagravision SARL', 'green'),
74
- ('Nagra USA', 'Nagra USA', 'green'),
75
- ('Nagra India', 'Nagra India', 'green'),
83
+ ('entity1', 'Entity 1', 'green'),
84
+ ('entity2', 'Entity 2', 'yellow'),
76
85
  ),
77
86
  'netbox_contract.Contract.currency': (
78
87
  ('usd', 'USD'),
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "netbox-contract"
3
- version = "2.3.0"
3
+ version = "2.3.1"
4
4
  authors = [
5
5
  { name="Marc Lebreuil", email="marc@famillelebreuil.net" },
6
6
  ]
@@ -5,11 +5,11 @@ class ContractsConfig(PluginConfig):
5
5
  name = 'netbox_contract'
6
6
  verbose_name = 'Netbox contract'
7
7
  description = 'Contract management plugin for Netbox'
8
- version = '2.3.0'
8
+ version = '2.3.1'
9
9
  author = 'Marc Lebreuil'
10
10
  author_email = 'marc@famillelebreuil.net'
11
11
  base_url = 'contracts'
12
- min_version = '4.1.10'
12
+ min_version = '4.2.0'
13
13
  required_settings = []
14
14
  default_settings = {
15
15
  'top_level_menu': False,
@@ -54,12 +54,8 @@ class ContractForm(NetBoxModelForm):
54
54
  widget=HTMXSelect(),
55
55
  label=_('External partie object type'),
56
56
  )
57
- external_partie_object = forms.ModelChoiceField(
58
- queryset=None, label=_('External partie object')
59
- )
60
- tenant = DynamicModelChoiceField(
61
- queryset=Tenant.objects.all(), required=False, selector=True, label=_('Tenant')
62
- )
57
+ external_partie_object = forms.ModelChoiceField(queryset=None, label=_('External partie object'))
58
+ tenant = DynamicModelChoiceField(queryset=Tenant.objects.all(), required=False, selector=True, label=_('Tenant'))
63
59
  parent = DynamicModelChoiceField(
64
60
  queryset=Contract.objects.all(),
65
61
  required=False,
@@ -73,37 +69,22 @@ class ContractForm(NetBoxModelForm):
73
69
 
74
70
  # Initialize the external party object gfk
75
71
  if initial and 'external_partie_object_type' in initial:
76
- external_partie_object_type = ContentType.objects.get_for_id(
77
- initial['external_partie_object_type']
78
- )
72
+ external_partie_object_type = ContentType.objects.get_for_id(initial['external_partie_object_type'])
79
73
  external_partie_class = external_partie_object_type.model_class()
80
- self.fields[
81
- 'external_partie_object'
82
- ].queryset = external_partie_class.objects.all()
74
+ self.fields['external_partie_object'].queryset = external_partie_class.objects.all()
83
75
  if (
84
76
  self.instance.external_partie_object_type
85
- and self.instance.external_partie_object_type.id
86
- == external_partie_object_type.id
77
+ and self.instance.external_partie_object_type.id == external_partie_object_type.id
87
78
  ):
88
- self.fields[
89
- 'external_partie_object'
90
- ].initial = self.instance.external_partie_object
79
+ self.fields['external_partie_object'].initial = self.instance.external_partie_object
91
80
  else:
92
81
  self.fields['external_partie_object'].initial = None
93
82
  elif self.instance.external_partie_object_type:
94
- external_partie_class = (
95
- self.instance.external_partie_object_type.model_class()
96
- )
97
- self.fields[
98
- 'external_partie_object'
99
- ].queryset = external_partie_class.objects.all()
100
- self.fields[
101
- 'external_partie_object'
102
- ].initial = self.instance.external_partie_object
83
+ external_partie_class = self.instance.external_partie_object_type.model_class()
84
+ self.fields['external_partie_object'].queryset = external_partie_class.objects.all()
85
+ self.fields['external_partie_object'].initial = self.instance.external_partie_object
103
86
  else:
104
- self.fields[
105
- 'external_partie_object'
106
- ].queryset = ServiceProvider.objects.all()
87
+ self.fields['external_partie_object'].queryset = ServiceProvider.objects.all()
107
88
  self.fields['external_partie_object'].initial = None
108
89
 
109
90
  # Initialise fields settings
@@ -150,25 +131,17 @@ class ContractForm(NetBoxModelForm):
150
131
  super().clean()
151
132
 
152
133
  if self.cleaned_data['mrc'] and self.cleaned_data['yrc']:
153
- raise ValidationError(
154
- 'you should set monthly OR yearly recuring costs not both'
155
- )
134
+ raise ValidationError('you should set monthly OR yearly recuring costs not both')
156
135
 
157
136
 
158
137
  class ContractFilterForm(NetBoxModelFilterSetForm):
159
138
  model = Contract
160
139
 
161
- tenant = DynamicModelChoiceField(
162
- queryset=Tenant.objects.all(), required=False, selector=True, label=_('Tenant')
163
- )
140
+ tenant = DynamicModelChoiceField(queryset=Tenant.objects.all(), required=False, selector=True, label=_('Tenant'))
164
141
  external_reference = forms.CharField(required=False, label=_('External reference'))
165
- internal_partie = forms.ChoiceField(
166
- choices=InternalEntityChoices, required=False, label=_('Internal partie')
167
- )
142
+ internal_partie = forms.ChoiceField(choices=InternalEntityChoices, required=False, label=_('Internal partie'))
168
143
  status = forms.ChoiceField(choices=StatusChoices, required=False, label=_('Status'))
169
- currency = forms.ChoiceField(
170
- choices=CurrencyChoices, required=False, label=_('Currency')
171
- )
144
+ currency = forms.ChoiceField(choices=CurrencyChoices, required=False, label=_('Currency'))
172
145
  parent = DynamicModelChoiceField(
173
146
  queryset=Contract.objects.all(),
174
147
  required=False,
@@ -194,9 +167,7 @@ class ContractCSVForm(NetBoxModelImportForm):
194
167
  required=False,
195
168
  label=_('Tenant'),
196
169
  )
197
- status = CSVChoiceField(
198
- choices=StatusChoices, help_text='Contract status', label=_('Status')
199
- )
170
+ status = CSVChoiceField(choices=StatusChoices, help_text='Contract status', label=_('Status'))
200
171
  parent = CSVModelChoiceField(
201
172
  queryset=Contract.objects.all(),
202
173
  to_field_name='name',
@@ -231,27 +202,17 @@ class ContractCSVForm(NetBoxModelImportForm):
231
202
 
232
203
  def clean_external_partie_object_id(self):
233
204
  name = self.cleaned_data.get('external_partie_object_id')
234
- external_partie_object_type = self.cleaned_data.get(
235
- 'external_partie_object_type'
236
- )
237
- external_partie_object = external_partie_object_type.get_object_for_this_type(
238
- name=name
239
- )
205
+ external_partie_object_type = self.cleaned_data.get('external_partie_object_type')
206
+ external_partie_object = external_partie_object_type.get_object_for_this_type(name=name)
240
207
 
241
208
  return external_partie_object.id
242
209
 
243
210
 
244
211
  class ContractBulkEditForm(NetBoxModelBulkEditForm):
245
212
  name = forms.CharField(max_length=100, required=False, label=_('Name'))
246
- external_reference = forms.CharField(
247
- max_length=100, required=False, label=_('External reference')
248
- )
249
- internal_partie = forms.ChoiceField(
250
- choices=InternalEntityChoices, required=False, label=_('Internal partie')
251
- )
252
- tenant = DynamicModelChoiceField(
253
- queryset=Tenant.objects.all(), required=False, selector=True, label=_('Tenant')
254
- )
213
+ external_reference = forms.CharField(max_length=100, required=False, label=_('External reference'))
214
+ internal_partie = forms.ChoiceField(choices=InternalEntityChoices, required=False, label=_('Internal partie'))
215
+ tenant = DynamicModelChoiceField(queryset=Tenant.objects.all(), required=False, selector=True, label=_('Tenant'))
255
216
  comments = CommentField(required=False, label=_('Comments'))
256
217
  parent = DynamicModelChoiceField(
257
218
  queryset=Contract.objects.all(),
@@ -302,9 +263,7 @@ class InvoiceForm(NetBoxModelForm):
302
263
  for contract in contracts:
303
264
  for invoice in contract.invoices.all():
304
265
  if invoice.template and invoice.pk != self.instance.pk:
305
- raise ValidationError(
306
- 'Only one invoice template allowed per contract'
307
- )
266
+ raise ValidationError('Only one invoice template allowed per contract')
308
267
 
309
268
  # Prefix the invoice name with _template
310
269
  self.cleaned_data['number'] = '_invoice_template_' + contract.name
@@ -324,9 +283,7 @@ class InvoiceForm(NetBoxModelForm):
324
283
  for contract in contracts:
325
284
  try:
326
285
  template_exists = True
327
- invoice_template = Invoice.objects.get(
328
- template=True, contracts=contract
329
- )
286
+ invoice_template = Invoice.objects.get(template=True, contracts=contract)
330
287
  except ObjectDoesNotExist:
331
288
  template_exists = False
332
289
 
@@ -341,15 +298,8 @@ class InvoiceForm(NetBoxModelForm):
341
298
 
342
299
  # adjust the first invoice line amount
343
300
  amount = self.cleaned_data['amount']
344
- if (
345
- first
346
- and amount != invoice_template.total_invoicelines_amount
347
- ):
348
- line.amount = (
349
- line.amount
350
- + amount
351
- - invoice_template.total_invoicelines_amount
352
- )
301
+ if first and amount != invoice_template.total_invoicelines_amount:
302
+ line.amount = line.amount + amount - invoice_template.total_invoicelines_amount
353
303
 
354
304
  line.save()
355
305
 
@@ -392,9 +342,7 @@ class InvoiceFilterForm(NetBoxModelFilterSetForm):
392
342
  widget=forms.Select(choices=BOOLEAN_WITH_BLANK_CHOICES),
393
343
  label=_('Template'),
394
344
  )
395
- currency = forms.ChoiceField(
396
- choices=CurrencyChoices, required=False, label=_('Currency')
397
- )
345
+ currency = forms.ChoiceField(choices=CurrencyChoices, required=False, label=_('Currency'))
398
346
  contracts = DynamicModelMultipleChoiceField(
399
347
  queryset=Contract.objects.all(),
400
348
  required=False,
@@ -515,9 +463,7 @@ class ServiceProviderBulkEditForm(NetBoxModelBulkEditForm):
515
463
 
516
464
 
517
465
  class ContractAssignmentForm(NetBoxModelForm):
518
- contract = DynamicModelChoiceField(
519
- queryset=Contract.objects.all(), selector=True, label=_('Contract')
520
- )
466
+ contract = DynamicModelChoiceField(queryset=Contract.objects.all(), selector=True, label=_('Contract'))
521
467
 
522
468
  class Meta:
523
469
  model = ContractAssignment
@@ -86,13 +86,9 @@ class AccountingDimension(NetBoxModel):
86
86
 
87
87
  def get_status_color(self):
88
88
  return AccountingDimensionStatusChoices.colors.get(self.status)
89
-
89
+
90
90
  class Meta:
91
- constraints = [
92
- models.UniqueConstraint(
93
- fields=['name', 'value'], name='unique_accounting_dimension'
94
- )
95
- ]
91
+ constraints = [models.UniqueConstraint(fields=['name', 'value'], name='unique_accounting_dimension')]
96
92
  ordering = ('name', 'value')
97
93
  verbose_name = _('accounting dimension')
98
94
  verbose_name_plural = _('accounting dimensions')
@@ -117,9 +113,7 @@ class ServiceProvider(ContactsMixin, NetBoxModel):
117
113
 
118
114
 
119
115
  class ContractAssignment(NetBoxModel):
120
- content_type = models.ForeignKey(
121
- to=ContentType, on_delete=models.CASCADE, verbose_name=_('content type')
122
- )
116
+ content_type = models.ForeignKey(to=ContentType, on_delete=models.CASCADE, verbose_name=_('content type'))
123
117
  object_id = models.PositiveBigIntegerField(verbose_name=_('object ID'))
124
118
  content_object = GenericForeignKey(ct_field='content_type', fk_field='object_id')
125
119
  contract = models.ForeignKey(
@@ -157,12 +151,9 @@ class Contract(NetBoxModel):
157
151
  external_partie_object = GenericForeignKey(
158
152
  ct_field='external_partie_object_type', fk_field='external_partie_object_id'
159
153
  )
160
- external_reference = models.CharField(
161
- max_length=100, blank=True, null=True, verbose_name=_('external reference')
162
- )
163
- internal_partie = models.CharField(
164
- max_length=50, choices=InternalEntityChoices, verbose_name=_('internal partie')
165
- )
154
+ external_partie_object.editable = True
155
+ external_reference = models.CharField(max_length=100, blank=True, null=True, verbose_name=_('external reference'))
156
+ internal_partie = models.CharField(max_length=50, choices=InternalEntityChoices, verbose_name=_('internal partie'))
166
157
  tenant = models.ForeignKey(
167
158
  to='tenancy.Tenant',
168
159
  on_delete=models.PROTECT,
@@ -220,9 +211,7 @@ class Contract(NetBoxModel):
220
211
  null=True,
221
212
  help_text=_('Use either this field of the yearly recuring cost field'),
222
213
  )
223
- nrc = models.DecimalField(
224
- verbose_name=_('none recuring cost'), default=0, max_digits=10, decimal_places=2
225
- )
214
+ nrc = models.DecimalField(verbose_name=_('none recuring cost'), default=0, max_digits=10, decimal_places=2)
226
215
  invoice_frequency = models.IntegerField(
227
216
  help_text=_('The frequency of invoices in month'),
228
217
  default=1,
@@ -248,12 +237,11 @@ class Contract(NetBoxModel):
248
237
 
249
238
  def get_status_color(self):
250
239
  return StatusChoices.colors.get(self.status)
240
+
251
241
  class Meta:
252
242
  ordering = ('name',)
253
243
  indexes = [
254
- models.Index(
255
- fields=['external_partie_object_type', 'external_partie_object_id']
256
- ),
244
+ models.Index(fields=['external_partie_object_type', 'external_partie_object_id']),
257
245
  ]
258
246
  verbose_name = _('contract')
259
247
  verbose_name_plural = _('contracts')
@@ -276,12 +264,8 @@ class Invoice(NetBoxModel):
276
264
  help_text=_('Wether this invoice is a template or not'),
277
265
  )
278
266
  date = models.DateField(blank=True, null=True, verbose_name=_('date'))
279
- contracts = models.ManyToManyField(
280
- Contract, related_name='invoices', blank=True, verbose_name=_('contracts')
281
- )
282
- period_start = models.DateField(
283
- blank=True, null=True, verbose_name=_('period start')
284
- )
267
+ contracts = models.ManyToManyField(Contract, related_name='invoices', blank=True, verbose_name=_('contracts'))
268
+ period_start = models.DateField(blank=True, null=True, verbose_name=_('period start'))
285
269
  period_end = models.DateField(blank=True, null=True, verbose_name=_('period end'))
286
270
  currency = models.CharField(
287
271
  max_length=3,
@@ -289,9 +273,7 @@ class Invoice(NetBoxModel):
289
273
  default=CURRENCY_DEFAULT,
290
274
  verbose_name=_('currency'),
291
275
  )
292
- amount = models.DecimalField(
293
- max_digits=10, decimal_places=2, verbose_name=_('amount')
294
- )
276
+ amount = models.DecimalField(max_digits=10, decimal_places=2, verbose_name=_('amount'))
295
277
  documents = models.URLField(
296
278
  blank=True,
297
279
  verbose_name=_('documents'),
@@ -331,9 +313,7 @@ class InvoiceLine(NetBoxModel):
331
313
  default=CURRENCY_DEFAULT,
332
314
  verbose_name=_('currency'),
333
315
  )
334
- amount = models.DecimalField(
335
- max_digits=10, decimal_places=2, verbose_name=_('amount')
336
- )
316
+ amount = models.DecimalField(max_digits=10, decimal_places=2, verbose_name=_('amount'))
337
317
  accounting_dimensions = models.ManyToManyField(
338
318
  AccountingDimension, blank=True, verbose_name=_('accounting dimensions')
339
319
  )
@@ -355,14 +335,8 @@ class InvoiceLine(NetBoxModel):
355
335
  is_new = not bool(self.pk)
356
336
  if is_new:
357
337
  if amount > (invoice.amount - invoice.total_invoicelines_amount):
358
- raise ValidationError(
359
- 'Sum of invoice line amount greater than invoice amount'
360
- )
338
+ raise ValidationError('Sum of invoice line amount greater than invoice amount')
361
339
  else:
362
340
  previous_amount = self.__class__.objects.get(pk=self.pk).amount
363
- if amount > (
364
- invoice.amount - invoice.total_invoicelines_amount + previous_amount
365
- ):
366
- raise ValidationError(
367
- 'Sum of invoice line amount greater than invoice amount'
368
- )
341
+ if amount > (invoice.amount - invoice.total_invoicelines_amount + previous_amount):
342
+ raise ValidationError('Sum of invoice line amount greater than invoice amount')
@@ -45,6 +45,9 @@ class ContractAssignmentObjectTable(NetBoxTable):
45
45
  contract__external_partie_object = tables.Column(
46
46
  verbose_name='Partner', linkify=True
47
47
  )
48
+ contract__status = columns.ChoiceFieldColumn(
49
+ verbose_name=('Status'),
50
+ )
48
51
 
49
52
  class Meta(NetBoxTable.Meta):
50
53
  model = ContractAssignment
@@ -75,7 +78,9 @@ class ContractAssignmentObjectTable(NetBoxTable):
75
78
  class ContractAssignmentContractTable(NetBoxTable):
76
79
  content_type = columns.ContentTypeColumn(verbose_name='Object Type')
77
80
  content_object = tables.Column(linkify=True, verbose_name='Object', orderable=False)
78
- content_object__status = tables.Column(verbose_name='Status')
81
+ content_object__status = columns.ChoiceFieldColumn(
82
+ verbose_name=('Status'),
83
+ )
79
84
  actions = columns.ActionsColumn(actions=('edit', 'delete'))
80
85
 
81
86
  class Meta(NetBoxTable.Meta):
@@ -136,6 +141,9 @@ class ContractListTable(NetBoxTable):
136
141
  class ContractListBottomTable(NetBoxTable):
137
142
  name = tables.Column(linkify=True)
138
143
  external_partie_object = tables.Column(linkify=True)
144
+ status = columns.ChoiceFieldColumn(
145
+ verbose_name=('Status'),
146
+ )
139
147
 
140
148
  class Meta(NetBoxTable.Meta):
141
149
  model = Contract
@@ -201,9 +209,7 @@ class ServiceProviderListTable(NetBoxTable):
201
209
 
202
210
  class InvoiceLineListTable(NetBoxTable):
203
211
  invoice = tables.Column(linkify=True)
204
- accounting_dimensions = tables.ManyToManyColumn(
205
- linkify=True, filter=lambda qs: qs.order_by('name')
206
- )
212
+ accounting_dimensions = tables.ManyToManyColumn(linkify=True, filter=lambda qs: qs.order_by('name'))
207
213
 
208
214
  class Meta(NetBoxTable.Meta):
209
215
  model = InvoiceLine
@@ -229,6 +235,7 @@ class AccountingDimensionListTable(NetBoxTable):
229
235
  status = columns.ChoiceFieldColumn(
230
236
  verbose_name=('Status'),
231
237
  )
238
+
232
239
  class Meta(NetBoxTable.Meta):
233
240
  model = AccountingDimension
234
241
  fields = (
@@ -76,7 +76,7 @@
76
76
  {% endif %}
77
77
  <tr>
78
78
  <th scope="row">{% trans "Currency" %}</th>
79
- <td>{{ object.currency }}</td>
79
+ <td>{{ object.get_currency_display }}</td>
80
80
  </tr>
81
81
  <tr>
82
82
  <th scope="row">{% trans "Monthly recuring costs" %}</th>
@@ -87,7 +87,7 @@
87
87
  <td>{{ object.yrc }}</td>
88
88
  </tr>
89
89
  <tr>
90
- <th scope="row">{% trans "calculated corresponding Yearly or Monthly value" %}</th>
90
+ <th scope="row">{% trans "Calculated corresponding Yearly or Monthly value" %}</th>
91
91
  <td>{{ object.calculated_rc }}</td>
92
92
  </tr>
93
93
  <tr>
@@ -135,7 +135,7 @@
135
135
  </tr>
136
136
  <tr>
137
137
  <th scope="row">{% trans "Currency" %}</th>
138
- <td>{{ invoice_template.currency }}</td>
138
+ <td>{{ invoice_template.get_currency_display }}</td>
139
139
  </tr>
140
140
  <tr>
141
141
  <th scope="row">{% trans "Total amount" %}</th>
@@ -12,7 +12,7 @@
12
12
  </tr>
13
13
  <tr>
14
14
  <th scope="row">{% trans "Object" %}</th>
15
- <td><a href="{{ object.content_object.get_absolute_url }}">{{ object.content_object.name }}</a></td>
15
+ <td><a href="{{ object.content_object.get_absolute_url }}">{{ object.content_object }}</a></td>
16
16
  </tr>
17
17
  <tr>
18
18
  <th scope="row">{% trans "Contract" %}</th>
@@ -40,7 +40,7 @@
40
40
  {% endif %}
41
41
  <tr>
42
42
  <th scope="row">{% trans "Currency" %}</th>
43
- <td>{{ object.currency }}</td>
43
+ <td>{{ object.get_currency_display }}</td>
44
44
  </tr>
45
45
  <tr>
46
46
  <th scope="row">{% trans "Amount" %}</th>
@@ -26,7 +26,7 @@
26
26
  </tr>
27
27
  <tr>
28
28
  <th scope="row">{% trans "Currency" %}</th>
29
- <td>{{ object.currency }}</td>
29
+ <td>{{ object.get_currency_display }}</td>
30
30
  </tr>
31
31
  <tr>
32
32
  <th scope="row">{% trans "Accounting dimensions" %}</th>
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: netbox-contract
3
- Version: 2.3.0
3
+ Version: 2.3.1
4
4
  Summary: Contract management plugin for Netbox
5
5
  Author-email: Marc Lebreuil <marc@famillelebreuil.net>
6
6
  Project-URL: Homepage, https://github.com/mlebreuil/netbox-contract
@@ -15,14 +15,29 @@ Requires-Dist: python-dateutil
15
15
  Requires-Dist: drf_yasg
16
16
 
17
17
  # Contract pluggin
18
- ## Overview
18
+
19
+ NetBox plugin to manage contracts.
20
+
21
+
22
+ * Free software: MIT
23
+ * Documentation: https://mlebreuil.github.io/netbox-contract/
24
+
25
+ ## Features
26
+
19
27
  The pluggin adds contracts and invoices model to Netbox.
20
- It allows to register contract with objects.
21
- Add invoices to contracts.
28
+ It allows to link contract with objects.
29
+ And link invoice templates and invoices with contracts.
30
+ Invoice lines can be linked to each invoice / invoice template.
31
+ Accounitng dimentoins can be linked with invoice lines.
32
+
33
+ ## Compatibility
22
34
 
23
- Check the [documentation](https://mlebreuil.github.io/netbox-contract/) for additional information
35
+ | NetBox Version | Plugin Version |
36
+ |----------------|----------------|
37
+ | 4.1 | 2.2 |
38
+ | 4.2 | 2.3 |
24
39
 
25
- ## Installation
40
+ ## Installing
26
41
 
27
42
  ### Activate venv
28
43
  To ensure our plugin is accessible to the NetBox installation, we first need to activate the Python [virtual environment](https://docs.python.org/3/library/venv.html) that was created when we installed NetBox. To do this, determine the virtual environment's path (this will be `/opt/netbox/venv/` if you use the documentation's defaults) and activate it:
@@ -57,11 +72,6 @@ The following configurationitems can be set:
57
72
  PLUGINS_CONFIG = {
58
73
  'netbox_contract': {
59
74
  'top_level_menu': True,
60
- 'default_accounting_dimensions':{
61
- "account": "",
62
- "project": "",
63
- "cost center": ""
64
- },
65
75
  'mandatory_contract_fields': [],
66
76
  'hidden_contract_fields': [],
67
77
  'mandatory_invoice_fields': [],
@@ -86,9 +96,8 @@ The first currency will also be the default currency for contracts.
86
96
  # configuration.py
87
97
  FIELD_CHOICES = {
88
98
  'netbox_contract.Contract.internal_partie': (
89
- ('Nagravision SARL', 'Nagravision SARL', 'green'),
90
- ('Nagra USA', 'Nagra USA', 'green'),
91
- ('Nagra India', 'Nagra India', 'green'),
99
+ ('entity1', 'Entity 1', 'green'),
100
+ ('entity2', 'Entity 2', 'yellow'),
92
101
  ),
93
102
  'netbox_contract.Contract.currency': (
94
103
  ('usd', 'USD'),
@@ -1,8 +1,15 @@
1
+ CONTRIBUTING.md
1
2
  LICENSE
2
3
  MANIFEST.in
3
4
  README.md
4
5
  pyproject.toml
5
6
  setup.py
7
+ docs/img/accounting_dimensions.png
8
+ docs/img/contract.png
9
+ docs/img/contract_linked_objects.png
10
+ docs/img/invoice.png
11
+ docs/img/invoice_line.png
12
+ docs/img/invoice_linked_objects.png
6
13
  src/netbox_contract/__init__.py
7
14
  src/netbox_contract/constants.py
8
15
  src/netbox_contract/filtersets.py
@@ -71,4 +78,6 @@ src/netbox_contract/templates/netbox_contract/contract.html
71
78
  src/netbox_contract/templates/netbox_contract/contractassignment.html
72
79
  src/netbox_contract/templates/netbox_contract/invoice.html
73
80
  src/netbox_contract/templates/netbox_contract/invoiceline.html
74
- src/netbox_contract/templates/netbox_contract/serviceprovider.html
81
+ src/netbox_contract/templates/netbox_contract/serviceprovider.html
82
+ tests/__init__.py
83
+ tests/test_netbox_contract.py
@@ -0,0 +1 @@
1
+ """Unit test package for test_plugin."""
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env python
2
+
3
+ """Tests for `netbox_contract` package."""
4
+
5
+ # from netbox_contract import netbox_contract
@@ -1,2 +0,0 @@
1
- graft src/netbox_contract/templates
2
- graft src/netbox_contract/templates/netbox_contract
File without changes