netbox-contract 2.3.1__tar.gz → 2.3.2__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 (90) hide show
  1. {netbox_contract-2.3.1 → netbox_contract-2.3.2}/CONTRIBUTING.md +17 -13
  2. {netbox_contract-2.3.1 → netbox_contract-2.3.2}/MANIFEST.in +2 -2
  3. {netbox_contract-2.3.1/src/netbox_contract.egg-info → netbox_contract-2.3.2}/PKG-INFO +7 -7
  4. {netbox_contract-2.3.1 → netbox_contract-2.3.2}/README.md +6 -6
  5. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/__init__.py +1 -1
  6. netbox_contract-2.3.2/netbox_contract/constants.py +13 -0
  7. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/forms.py +38 -11
  8. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/migrations/0019_auto_20230924_1813.py +1 -1
  9. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/migrations/0026_auto_20240421_1550.py +1 -1
  10. netbox_contract-2.3.2/netbox_contract/migrations/0040_alter_contract_currency_alter_invoice_currency_and_more.py +28 -0
  11. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/models.py +14 -0
  12. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/tables.py +11 -3
  13. netbox_contract-2.3.2/netbox_contract/tests/custom.py +18 -0
  14. netbox_contract-2.3.2/netbox_contract/tests/test_views.py +449 -0
  15. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/urls.py +16 -6
  16. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/views.py +20 -6
  17. {netbox_contract-2.3.1 → netbox_contract-2.3.2/netbox_contract.egg-info}/PKG-INFO +7 -7
  18. netbox_contract-2.3.2/netbox_contract.egg-info/SOURCES.txt +84 -0
  19. {netbox_contract-2.3.1 → netbox_contract-2.3.2}/pyproject.toml +8 -19
  20. netbox_contract-2.3.1/src/netbox_contract/constants.py +0 -6
  21. netbox_contract-2.3.1/src/netbox_contract.egg-info/SOURCES.txt +0 -83
  22. netbox_contract-2.3.1/src/netbox_contract.egg-info/not-zip-safe +0 -1
  23. netbox_contract-2.3.1/tests/test_netbox_contract.py +0 -5
  24. {netbox_contract-2.3.1 → netbox_contract-2.3.2}/LICENSE +0 -0
  25. {netbox_contract-2.3.1 → netbox_contract-2.3.2}/docs/img/accounting_dimensions.png +0 -0
  26. {netbox_contract-2.3.1 → netbox_contract-2.3.2}/docs/img/contract.png +0 -0
  27. {netbox_contract-2.3.1 → netbox_contract-2.3.2}/docs/img/contract_linked_objects.png +0 -0
  28. {netbox_contract-2.3.1 → netbox_contract-2.3.2}/docs/img/invoice.png +0 -0
  29. {netbox_contract-2.3.1 → netbox_contract-2.3.2}/docs/img/invoice_line.png +0 -0
  30. {netbox_contract-2.3.1 → netbox_contract-2.3.2}/docs/img/invoice_linked_objects.png +0 -0
  31. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/api/__init__.py +0 -0
  32. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/api/serializers.py +0 -0
  33. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/api/urls.py +0 -0
  34. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/api/views.py +0 -0
  35. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/filtersets.py +0 -0
  36. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/migrations/0001_initial.py +0 -0
  37. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/migrations/0002_alter_contract_circuit_and_more.py +0 -0
  38. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/migrations/0003_alter_contract_custom_field_data_and_more.py +0 -0
  39. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/migrations/0004_contract_currency_invoice_currency.py +0 -0
  40. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/migrations/0005_contract_accounting_dimensions_and_more.py +0 -0
  41. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/migrations/0006_alter_contract_circuit.py +0 -0
  42. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/migrations/0007_invoice_date.py +0 -0
  43. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/migrations/0008_invoice_comments.py +0 -0
  44. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/migrations/0009_contract_external_reference.py +0 -0
  45. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/migrations/0010_invoice_contracts.py +0 -0
  46. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/migrations/0011_auto_20230122_2112.py +0 -0
  47. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/migrations/0012_remove_invoice_contract.py +0 -0
  48. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/migrations/0013_contract_documents_invoice_documents.py +0 -0
  49. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/migrations/0014_contract_end_date.py +0 -0
  50. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/migrations/0015_contractassignement.py +0 -0
  51. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/migrations/0016_contract_parent.py +0 -0
  52. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/migrations/0017_alter_contract_accounting_dimensions.py +0 -0
  53. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/migrations/0018_contract_external_partie_object_id_and_more.py +0 -0
  54. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/migrations/0020_alter_contract_external_partie.py +0 -0
  55. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/migrations/0021_alter_contract_external_partie.py +0 -0
  56. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/migrations/0022_alter_contract_internal_partie_alter_contract_parent.py +0 -0
  57. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/migrations/0023_rename_contractassignement_contractassignment_and_more.py +0 -0
  58. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/migrations/0024_remove_contract_external_partie.py +0 -0
  59. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/migrations/0025_remove_contract_circuit_and_more.py +0 -0
  60. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/migrations/0027_invoiceline.py +0 -0
  61. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/migrations/0028_invoiceline_accounting_dimensions.py +0 -0
  62. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/migrations/0029_remove_invoiceline_accounting_dimensions_and_more.py +0 -0
  63. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/migrations/0030_alter_invoiceline_accounting_dimensions.py +0 -0
  64. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/migrations/0031_contract_invoice_template_invoice_template.py +0 -0
  65. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/migrations/0032_alter_invoice_period_end_alter_invoice_period_start_and_more.py +0 -0
  66. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/migrations/0033_remove_contract_invoice_template.py +0 -0
  67. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/migrations/0034_contract_yrc_alter_contract_mrc.py +0 -0
  68. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/migrations/0035_accountingdimension_status_and_more.py +0 -0
  69. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/migrations/0036_alter_invoiceline_accounting_dimensions.py +0 -0
  70. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/migrations/0037_contract_notice_period_alter_contract_currency_and_more.py +0 -0
  71. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/migrations/0038_alter_accountingdimension_options_and_more.py +0 -0
  72. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/migrations/0039_alter_accountingdimension_status_and_more.py +0 -0
  73. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/migrations/__init__.py +0 -0
  74. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/navigation.py +0 -0
  75. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/search.py +0 -0
  76. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/template_content.py +0 -0
  77. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/templates/contract_assignments_bottom.html +0 -0
  78. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/templates/contract_list_bottom.html +0 -0
  79. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/templates/netbox_contract/accountingdimension.html +0 -0
  80. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/templates/netbox_contract/contract.html +0 -0
  81. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/templates/netbox_contract/contractassignment.html +0 -0
  82. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/templates/netbox_contract/invoice.html +0 -0
  83. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/templates/netbox_contract/invoiceline.html +0 -0
  84. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract/templates/netbox_contract/serviceprovider.html +0 -0
  85. {netbox_contract-2.3.1 → netbox_contract-2.3.2/netbox_contract}/tests/__init__.py +0 -0
  86. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract.egg-info/dependency_links.txt +0 -0
  87. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract.egg-info/requires.txt +0 -0
  88. {netbox_contract-2.3.1/src → netbox_contract-2.3.2}/netbox_contract.egg-info/top_level.txt +0 -0
  89. {netbox_contract-2.3.1 → netbox_contract-2.3.2}/setup.cfg +0 -0
  90. {netbox_contract-2.3.1 → netbox_contract-2.3.2}/setup.py +0 -0
@@ -20,20 +20,18 @@ and "help wanted" is open to whoever wants to implement it.
20
20
 
21
21
  ## Coding conventions
22
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/)
23
+ Netbox [Style Guide](https://netboxlabs.com/docs/netbox/en/stable/development/style-guide/)
24
+ Django [Coding style](https://docs.djangoproject.com/en/stable/internals/contributing/writing-code/coding-style/)
25
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
26
+ ## linting
29
27
 
30
- [isort](https://github.com/PyCQA/isort#readme) is used to automate import sorting.
28
+ The [ruff](https://docs.astral.sh/ruff/) linter is used to enforce code style. A [pre-commit hook](./getting-started.md#3-enable-pre-commit-hooks) which runs this automatically is included with NetBox. To invoke `ruff` manually, run:
29
+
30
+ ```
31
+ python3 -m pip install ruff
32
+ ruff check netbox_contract/
33
+ ```
31
34
 
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
35
 
38
36
  The pre-commit Python framework is used to simplify the managment of pre-commit hooks.
39
37
  Config is stored in .pre-commit-config.yaml
@@ -100,7 +98,13 @@ Make sure taht at the Netbox installtion step you follow the "Option B: Clone th
100
98
 
101
99
  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
100
 
103
- 9. Commit your changes and push your branch to GitHub:
101
+ 9. Run unittest
102
+
103
+ ```
104
+ $ python3 netbox/netbox/manage.py test netbox_contract
105
+ ```
106
+
107
+ 10. Commit your changes and push your branch to GitHub:
104
108
 
105
109
  ```
106
110
  $ git add .
@@ -108,7 +112,7 @@ Make sure taht at the Netbox installtion step you follow the "Option B: Clone th
108
112
  $ git push origin name-of-your-bugfix-or-feature
109
113
  ```
110
114
 
111
- 10. Submit a pull request through the GitHub website.
115
+ 1. Submit a pull request through the GitHub website.
112
116
 
113
117
  ## Model changes
114
118
 
@@ -9,5 +9,5 @@ recursive-exclude * *.py[co]
9
9
  recursive-include docs *.rst conf.py Makefile make.bat *.jpg *.png *.gif
10
10
 
11
11
 
12
- graft src/netbox_contract/templates
13
- graft src/netbox_contract/templates/netbox_contract
12
+ graft netbox_contract/templates
13
+ graft netbox_contract/templates/netbox_contract
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: netbox-contract
3
- Version: 2.3.1
3
+ Version: 2.3.2
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
@@ -14,7 +14,7 @@ License-File: LICENSE
14
14
  Requires-Dist: python-dateutil
15
15
  Requires-Dist: drf_yasg
16
16
 
17
- # Contract pluggin
17
+ # Contract plugin
18
18
 
19
19
  NetBox plugin to manage contracts.
20
20
 
@@ -24,11 +24,11 @@ NetBox plugin to manage contracts.
24
24
 
25
25
  ## Features
26
26
 
27
- The pluggin adds contracts and invoices model to Netbox.
27
+ The plugin adds contracts and invoices model to NetBox.
28
28
  It allows to link contract with objects.
29
29
  And link invoice templates and invoices with contracts.
30
30
  Invoice lines can be linked to each invoice / invoice template.
31
- Accounitng dimentoins can be linked with invoice lines.
31
+ Accounting dimensions can be linked with invoice lines.
32
32
 
33
33
  ## Compatibility
34
34
 
@@ -54,7 +54,7 @@ $ python3 -m pip install netbox-contract
54
54
 
55
55
  ### Configure NetBox
56
56
 
57
- Finally, we need to configure NetBox to enable our new plugin. Over in the NetBox installation path, open `netbox/netbox/configuration.py` and look for the `PLUGINS` parameter; this should be an empty list. (If it's not yet defined, go ahead and create it.) Add the name of our plugin to this list:
57
+ Finally, we need to configure NetBox to enable our new plugin. In the NetBox installation directory, open `netbox/netbox/configuration.py` and locate the `PLUGINS` parameter; it should be an empty list. (If it's not yet defined, go ahead and create it.) Add the name of our plugin to this list:
58
58
 
59
59
  ```python
60
60
  # configuration.py
@@ -65,7 +65,7 @@ PLUGINS = [
65
65
 
66
66
  ### Customize the plugin
67
67
 
68
- The following configurationitems can be set:
68
+ The following configuration items can be set:
69
69
 
70
70
  ```python
71
71
  # configuration.py
@@ -100,7 +100,7 @@ FIELD_CHOICES = {
100
100
  ('entity2', 'Entity 2', 'yellow'),
101
101
  ),
102
102
  'netbox_contract.Contract.currency': (
103
- ('usd', 'USD'),
103
+ ('usd', 'USD'), # 1st position is the default currency
104
104
  ('eur', 'EUR'),
105
105
  ('chf', 'CHF'),
106
106
  ('pln', 'PLN'),
@@ -1,4 +1,4 @@
1
- # Contract pluggin
1
+ # Contract plugin
2
2
 
3
3
  NetBox plugin to manage contracts.
4
4
 
@@ -8,11 +8,11 @@ NetBox plugin to manage contracts.
8
8
 
9
9
  ## Features
10
10
 
11
- The pluggin adds contracts and invoices model to Netbox.
11
+ The plugin adds contracts and invoices model to NetBox.
12
12
  It allows to link contract with objects.
13
13
  And link invoice templates and invoices with contracts.
14
14
  Invoice lines can be linked to each invoice / invoice template.
15
- Accounitng dimentoins can be linked with invoice lines.
15
+ Accounting dimensions can be linked with invoice lines.
16
16
 
17
17
  ## Compatibility
18
18
 
@@ -38,7 +38,7 @@ $ python3 -m pip install netbox-contract
38
38
 
39
39
  ### Configure NetBox
40
40
 
41
- Finally, we need to configure NetBox to enable our new plugin. Over in the NetBox installation path, open `netbox/netbox/configuration.py` and look for the `PLUGINS` parameter; this should be an empty list. (If it's not yet defined, go ahead and create it.) Add the name of our plugin to this list:
41
+ Finally, we need to configure NetBox to enable our new plugin. In the NetBox installation directory, open `netbox/netbox/configuration.py` and locate the `PLUGINS` parameter; it should be an empty list. (If it's not yet defined, go ahead and create it.) Add the name of our plugin to this list:
42
42
 
43
43
  ```python
44
44
  # configuration.py
@@ -49,7 +49,7 @@ PLUGINS = [
49
49
 
50
50
  ### Customize the plugin
51
51
 
52
- The following configurationitems can be set:
52
+ The following configuration items can be set:
53
53
 
54
54
  ```python
55
55
  # configuration.py
@@ -84,7 +84,7 @@ FIELD_CHOICES = {
84
84
  ('entity2', 'Entity 2', 'yellow'),
85
85
  ),
86
86
  'netbox_contract.Contract.currency': (
87
- ('usd', 'USD'),
87
+ ('usd', 'USD'), # 1st position is the default currency
88
88
  ('eur', 'EUR'),
89
89
  ('chf', 'CHF'),
90
90
  ('pln', 'PLN'),
@@ -5,7 +5,7 @@ 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.1'
8
+ version = '2.3.2'
9
9
  author = 'Marc Lebreuil'
10
10
  author_email = 'marc@famillelebreuil.net'
11
11
  base_url = 'contracts'
@@ -0,0 +1,13 @@
1
+ from django.db.models import Q
2
+
3
+ SERVICE_PROVIDER_MODELS = Q(
4
+ Q(app_label='circuits', model__in=('provider',))
5
+ | Q(app_label='netbox_contract', model__in=('serviceprovider',))
6
+ )
7
+
8
+ ASSIGNEMENT_MODELS = Q(
9
+ Q(app_label='circuits', model__in=('circuit',))
10
+ | Q(app_label='dcim', model__in=('site',))
11
+ | Q(app_label='dcim', model__in=('device',))
12
+ | Q(app_label='virtualization', model__in=('virtualmachine',))
13
+ )
@@ -10,6 +10,7 @@ from netbox.forms import (
10
10
  NetBoxModelImportForm,
11
11
  )
12
12
  from tenancy.models import Tenant
13
+ from tenancy.forms import TenancyFilterForm
13
14
  from utilities.forms import BOOLEAN_WITH_BLANK_CHOICES
14
15
  from utilities.forms.fields import (
15
16
  CommentField,
@@ -25,7 +26,7 @@ from utilities.forms.fields import (
25
26
  )
26
27
  from utilities.forms.widgets import DatePicker, HTMXSelect
27
28
 
28
- from .constants import SERVICE_PROVIDER_MODELS
29
+ from .constants import SERVICE_PROVIDER_MODELS, ASSIGNEMENT_MODELS
29
30
  from .models import (
30
31
  AccountingDimension,
31
32
  AccountingDimensionStatusChoices,
@@ -134,10 +135,9 @@ class ContractForm(NetBoxModelForm):
134
135
  raise ValidationError('you should set monthly OR yearly recuring costs not both')
135
136
 
136
137
 
137
- class ContractFilterForm(NetBoxModelFilterSetForm):
138
+ class ContractFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
138
139
  model = Contract
139
140
 
140
- tenant = DynamicModelChoiceField(queryset=Tenant.objects.all(), required=False, selector=True, label=_('Tenant'))
141
141
  external_reference = forms.CharField(required=False, label=_('External reference'))
142
142
  internal_partie = forms.ChoiceField(choices=InternalEntityChoices, required=False, label=_('Internal partie'))
143
143
  status = forms.ChoiceField(choices=StatusChoices, required=False, label=_('Status'))
@@ -353,7 +353,7 @@ class InvoiceFilterForm(NetBoxModelFilterSetForm):
353
353
 
354
354
 
355
355
  class InvoiceCSVForm(NetBoxModelImportForm):
356
- contracts = CSVModelChoiceField(
356
+ contracts = CSVModelMultipleChoiceField(
357
357
  queryset=Contract.objects.all(),
358
358
  to_field_name='name',
359
359
  help_text='Related Contracts',
@@ -378,7 +378,7 @@ class InvoiceCSVForm(NetBoxModelImportForm):
378
378
 
379
379
 
380
380
  class InvoiceBulkEditForm(NetBoxModelBulkEditForm):
381
- number = forms.CharField(max_length=100, required=True, label=_('Number'))
381
+ number = forms.CharField(max_length=100, required=False, label=_('Number'))
382
382
  template = forms.BooleanField(
383
383
  required=False,
384
384
  label=_('Template'),
@@ -453,7 +453,7 @@ class ServiceProviderCSVForm(NetBoxModelImportForm):
453
453
 
454
454
 
455
455
  class ServiceProviderBulkEditForm(NetBoxModelBulkEditForm):
456
- name = forms.CharField(max_length=100, required=True, label=_('Name'))
456
+ name = forms.CharField(max_length=100, required=False, label=_('Name'))
457
457
  comments = CommentField(label=_('Comments'))
458
458
  nullable_fields = ('comments',)
459
459
  model = ServiceProvider
@@ -463,21 +463,32 @@ class ServiceProviderBulkEditForm(NetBoxModelBulkEditForm):
463
463
 
464
464
 
465
465
  class ContractAssignmentForm(NetBoxModelForm):
466
- contract = DynamicModelChoiceField(queryset=Contract.objects.all(), selector=True, label=_('Contract'))
466
+
467
+ content_type = ContentTypeChoiceField(
468
+ queryset=ContentType.objects.all(),
469
+ limit_choices_to=ASSIGNEMENT_MODELS,
470
+ label=_('object type'),
471
+ )
472
+
473
+ contract = DynamicModelChoiceField(
474
+ queryset=Contract.objects.all(),
475
+ selector=True,
476
+ label=_('Contract'))
467
477
 
468
478
  class Meta:
469
479
  model = ContractAssignment
470
480
  fields = ['content_type', 'object_id', 'contract', 'tags']
471
- widgets = {
472
- 'content_type': forms.HiddenInput(),
473
- 'object_id': forms.HiddenInput(),
474
- }
481
+ # widgets = {
482
+ # 'content_type': forms.HiddenInput(),
483
+ # 'object_id': forms.HiddenInput(),
484
+ # }
475
485
 
476
486
 
477
487
  class ContractAssignmentFilterForm(NetBoxModelFilterSetForm):
478
488
  model = ContractAssignment
479
489
  contract = DynamicModelChoiceField(
480
490
  queryset=Contract.objects.all(),
491
+ required=False,
481
492
  selector=True,
482
493
  label=_('Contract'),
483
494
  )
@@ -486,6 +497,7 @@ class ContractAssignmentFilterForm(NetBoxModelFilterSetForm):
486
497
  class ContractAssignmentImportForm(NetBoxModelImportForm):
487
498
  content_type = CSVContentTypeField(
488
499
  queryset=ContentType.objects.all(),
500
+ limit_choices_to=ASSIGNEMENT_MODELS,
489
501
  help_text='Content Type in the form <app>.<model>',
490
502
  label=_('Content type'),
491
503
  )
@@ -500,6 +512,16 @@ class ContractAssignmentImportForm(NetBoxModelImportForm):
500
512
  fields = ['content_type', 'object_id', 'contract', 'tags']
501
513
 
502
514
 
515
+ class ContractAssignmentBulkEditForm(NetBoxModelBulkEditForm):
516
+ contract = DynamicModelChoiceField(
517
+ queryset=Contract.objects.all(),
518
+ required=False,
519
+ selector=True,
520
+ label=_('Contract'),
521
+ )
522
+ model = ContractAssignment
523
+
524
+
503
525
  # InvoiceLine
504
526
 
505
527
 
@@ -578,6 +600,7 @@ class InvoiceLineImportForm(NetBoxModelImportForm):
578
600
  accounting_dimensions = CSVModelMultipleChoiceField(
579
601
  queryset=AccountingDimension.objects.all(),
580
602
  to_field_name='id',
603
+ required=False,
581
604
  help_text='accounting dimension id',
582
605
  label=_('Accounting dimensions'),
583
606
  )
@@ -602,6 +625,8 @@ class InvoiceLineBulkEditForm(NetBoxModelBulkEditForm):
602
625
  selector=True,
603
626
  label=_('Accounting dimensions'),
604
627
  )
628
+ comments = CommentField(label=_('Comments'))
629
+ nullable_fields = ('comments',)
605
630
  model = InvoiceLine
606
631
 
607
632
 
@@ -649,4 +674,6 @@ class AccountingDimensionImportForm(NetBoxModelImportForm):
649
674
  class AccountingDimensionBulkEditForm(NetBoxModelBulkEditForm):
650
675
  name = forms.CharField(max_length=20, required=False, label=_('Name'))
651
676
  value = forms.CharField(max_length=20, required=False, label=_('Value'))
677
+ comments = CommentField(label=_('Comments'))
678
+ nullable_fields = ('comments',)
652
679
  model = AccountingDimension
@@ -39,5 +39,5 @@ class Migration(migrations.Migration):
39
39
  ]
40
40
 
41
41
  operations = [
42
- migrations.RunPython(migrate_external_partie, reverse_external_partie),
42
+ # migrations.RunPython(migrate_external_partie, reverse_external_partie),
43
43
  ]
@@ -27,5 +27,5 @@ class Migration(migrations.Migration):
27
27
  ]
28
28
 
29
29
  operations = [
30
- migrations.RunPython(update_changed_object_type),
30
+ # migrations.RunPython(update_changed_object_type),
31
31
  ]
@@ -0,0 +1,28 @@
1
+ # Generated by Django 5.1.5 on 2025-02-23 09:21
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ("netbox_contract", "0039_alter_accountingdimension_status_and_more"),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.AlterField(
14
+ model_name="contract",
15
+ name="currency",
16
+ field=models.CharField(default="usd", max_length=3),
17
+ ),
18
+ migrations.AlterField(
19
+ model_name="invoice",
20
+ name="currency",
21
+ field=models.CharField(default="usd", max_length=3),
22
+ ),
23
+ migrations.AlterField(
24
+ model_name="invoiceline",
25
+ name="currency",
26
+ field=models.CharField(default="usd", max_length=3),
27
+ ),
28
+ ]
@@ -9,6 +9,8 @@ from django.utils.translation import gettext_lazy as _
9
9
  from netbox.models import NetBoxModel
10
10
  from netbox.models.features import ContactsMixin
11
11
  from utilities.choices import ChoiceSet
12
+ from dcim.choices import DeviceStatusChoices, SiteStatusChoices
13
+ from virtualization.choices import VirtualMachineStatusChoices
12
14
 
13
15
 
14
16
  class StatusChoices(ChoiceSet):
@@ -135,6 +137,18 @@ class ContractAssignment(NetBoxModel):
135
137
  def get_absolute_url(self):
136
138
  return reverse('plugins:netbox_contract:contractassignment', args=[self.pk])
137
139
 
140
+ def get_contract__status_color(self):
141
+ return StatusChoices.colors.get(self.contract.status)
142
+
143
+ def get_content_object__status_color(self):
144
+ STATUS_MAPPING = {
145
+ 'virtualmachine': VirtualMachineStatusChoices.colors,
146
+ 'device': DeviceStatusChoices.colors,
147
+ 'site': SiteStatusChoices.colors,
148
+ }
149
+ status_colors = STATUS_MAPPING.get(self.content_type.model, StatusChoices.colors)
150
+ return status_colors.get(self.content_object.status)
151
+
138
152
 
139
153
  class Contract(NetBoxModel):
140
154
  name = models.CharField(max_length=100, verbose_name=_('name'))
@@ -12,16 +12,18 @@ from .models import (
12
12
 
13
13
 
14
14
  class ContractAssignmentListTable(NetBoxTable):
15
+ id = tables.Column(linkify=True)
15
16
  content_type = columns.ContentTypeColumn(verbose_name='Object Type')
16
17
  content_object = tables.Column(linkify=True, orderable=False)
17
18
  contract = tables.Column(linkify=True)
18
19
  actions = columns.ActionsColumn(actions=('edit', 'delete'))
19
20
  contract__external_partie_object = tables.Column(linkify=True)
21
+ tags = columns.TagColumn(url_name='plugins:netbox_contract:contractassignment_list')
20
22
 
21
23
  class Meta(NetBoxTable.Meta):
22
24
  model = ContractAssignment
23
25
  fields = (
24
- 'pk',
26
+ 'id',
25
27
  'content_type',
26
28
  'content_object',
27
29
  'contract',
@@ -30,7 +32,7 @@ class ContractAssignmentListTable(NetBoxTable):
30
32
  'actions',
31
33
  )
32
34
  default_columns = (
33
- 'pk',
35
+ 'id',
34
36
  'content_type',
35
37
  'content_object',
36
38
  'contract',
@@ -108,6 +110,7 @@ class ContractListTable(NetBoxTable):
108
110
  status = columns.ChoiceFieldColumn(
109
111
  verbose_name=('Status'),
110
112
  )
113
+ tags = columns.TagColumn(url_name='plugins:netbox_contract:contract_list')
111
114
 
112
115
  class Meta(NetBoxTable.Meta):
113
116
  model = Contract
@@ -171,6 +174,7 @@ class ContractListBottomTable(NetBoxTable):
171
174
  class InvoiceListTable(NetBoxTable):
172
175
  contracts = tables.ManyToManyColumn(linkify=True)
173
176
  number = tables.Column(linkify=True)
177
+ tags = columns.TagColumn(url_name='plugins:netbox_contract:invoiceline_list')
174
178
 
175
179
  class Meta(NetBoxTable.Meta):
176
180
  model = Invoice
@@ -200,6 +204,7 @@ class InvoiceListTable(NetBoxTable):
200
204
 
201
205
  class ServiceProviderListTable(NetBoxTable):
202
206
  name = tables.Column(linkify=True)
207
+ tags = columns.TagColumn(url_name='plugins:netbox_contract:serviceprovider_list')
203
208
 
204
209
  class Meta(NetBoxTable.Meta):
205
210
  model = ServiceProvider
@@ -209,7 +214,8 @@ class ServiceProviderListTable(NetBoxTable):
209
214
 
210
215
  class InvoiceLineListTable(NetBoxTable):
211
216
  invoice = tables.Column(linkify=True)
212
- accounting_dimensions = tables.ManyToManyColumn(linkify=True, filter=lambda qs: qs.order_by('name'))
217
+ accounting_dimensions = tables.ManyToManyColumn(linkify_item=True, filter=lambda qs: qs.order_by('name'))
218
+ tags = columns.TagColumn(url_name='plugins:netbox_contract:invoiceline_list')
213
219
 
214
220
  class Meta(NetBoxTable.Meta):
215
221
  model = InvoiceLine
@@ -232,9 +238,11 @@ class InvoiceLineListTable(NetBoxTable):
232
238
 
233
239
 
234
240
  class AccountingDimensionListTable(NetBoxTable):
241
+ name = tables.Column(linkify=True)
235
242
  status = columns.ChoiceFieldColumn(
236
243
  verbose_name=('Status'),
237
244
  )
245
+ tags = columns.TagColumn(url_name='plugins:netbox_contract:accountingdimension_list')
238
246
 
239
247
  class Meta(NetBoxTable.Meta):
240
248
  model = AccountingDimension
@@ -0,0 +1,18 @@
1
+ from django.urls import reverse
2
+ from utilities.testing.api import APITestCase as NetBoxAPITestCase
3
+ from utilities.testing.views import ModelViewTestCase as NetBoxModelViewTestCase
4
+
5
+
6
+ class ModelViewTestCase(NetBoxModelViewTestCase):
7
+ def _get_base_url(self):
8
+ return f'plugins:{self.model._meta.app_label}:{self.model._meta.model_name}_{{}}'
9
+
10
+
11
+ class APITestCase(NetBoxAPITestCase):
12
+ def _get_detail_url(self, instance):
13
+ viewname = f'plugins-api:{self._get_view_namespace()}:{instance._meta.model_name}-detail'
14
+ return reverse(viewname, kwargs={'pk': instance.pk})
15
+
16
+ def _get_list_url(self):
17
+ viewname = f'plugins-api:{self._get_view_namespace()}:{self.model._meta.model_name}-list'
18
+ return reverse(viewname)