netbox-contract 2.4.2__tar.gz → 2.4.3__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.
- {netbox_contract-2.4.2/netbox_contract.egg-info → netbox_contract-2.4.3}/PKG-INFO +2 -1
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/README.md +1 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/__init__.py +1 -1
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/constants.py +7 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/filtersets.py +34 -3
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/forms.py +64 -4
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/tables.py +30 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/template_content.py +88 -21
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/templates/netbox_contract/serviceprovider.html +10 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/views.py +13 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3/netbox_contract.egg-info}/PKG-INFO +2 -1
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/pyproject.toml +1 -1
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/CONTRIBUTING.md +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/LICENSE +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/MANIFEST.in +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/docs/img/accounting_dimensions.png +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/docs/img/contract.png +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/docs/img/contract_linked_objects.png +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/docs/img/invoice.png +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/docs/img/invoice_line.png +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/docs/img/invoice_linked_objects.png +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/api/__init__.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/api/serializers.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/api/urls.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/api/views.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/locale/en/LC_MESSAGES/django.mo +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/locale/en/LC_MESSAGES/django.po +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/locale/fr/LC_MESSAGES/django.mo +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/locale/fr/LC_MESSAGES/django.po +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0001_initial.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0002_alter_contract_circuit_and_more.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0003_alter_contract_custom_field_data_and_more.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0004_contract_currency_invoice_currency.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0005_contract_accounting_dimensions_and_more.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0006_alter_contract_circuit.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0007_invoice_date.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0008_invoice_comments.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0009_contract_external_reference.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0010_invoice_contracts.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0011_auto_20230122_2112.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0012_remove_invoice_contract.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0013_contract_documents_invoice_documents.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0014_contract_end_date.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0015_contractassignement.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0016_contract_parent.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0017_alter_contract_accounting_dimensions.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0018_contract_external_partie_object_id_and_more.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0019_auto_20230924_1813.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0020_alter_contract_external_partie.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0021_alter_contract_external_partie.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0022_alter_contract_internal_partie_alter_contract_parent.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0023_rename_contractassignement_contractassignment_and_more.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0024_remove_contract_external_partie.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0025_remove_contract_circuit_and_more.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0026_auto_20240421_1550.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0027_invoiceline.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0028_invoiceline_accounting_dimensions.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0029_remove_invoiceline_accounting_dimensions_and_more.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0030_alter_invoiceline_accounting_dimensions.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0031_contract_invoice_template_invoice_template.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0032_alter_invoice_period_end_alter_invoice_period_start_and_more.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0033_remove_contract_invoice_template.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0034_contract_yrc_alter_contract_mrc.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0035_accountingdimension_status_and_more.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0036_alter_invoiceline_accounting_dimensions.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0037_contract_notice_period_alter_contract_currency_and_more.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0038_alter_accountingdimension_options_and_more.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0039_alter_accountingdimension_status_and_more.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0040_alter_contract_currency_alter_invoice_currency_and_more.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0041_contracttype_contract_contract_type.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0042_remove_contract_netbox_cont_externa_6343fb_idx_and_more.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0043_invoice_status.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/__init__.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/models.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/navigation.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/search.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/templates/contract_assignments_bottom.html +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/templates/contract_list_bottom.html +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/templates/netbox_contract/accountingdimension.html +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/templates/netbox_contract/contract.html +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/templates/netbox_contract/contractassignment.html +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/templates/netbox_contract/contracttype.html +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/templates/netbox_contract/invoice.html +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/templates/netbox_contract/invoiceline.html +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/urls.py +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract.egg-info/SOURCES.txt +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract.egg-info/dependency_links.txt +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract.egg-info/requires.txt +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract.egg-info/top_level.txt +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/setup.cfg +0 -0
- {netbox_contract-2.4.2 → netbox_contract-2.4.3}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: netbox-contract
|
|
3
|
-
Version: 2.4.
|
|
3
|
+
Version: 2.4.3
|
|
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
|
|
@@ -48,6 +48,7 @@ Accounting dimensions can be linked with invoice lines.
|
|
|
48
48
|
| 4.1 | 2.2 |
|
|
49
49
|
| 4.2 | 2.3 |
|
|
50
50
|
| 4.3 | 2.4 |
|
|
51
|
+
| 4.4 | 2.4 |
|
|
51
52
|
|
|
52
53
|
## Installing
|
|
53
54
|
|
|
@@ -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.4.
|
|
8
|
+
version = '2.4.3'
|
|
9
9
|
author = 'Marc Lebreuil'
|
|
10
10
|
author_email = 'marc@famillelebreuil.net'
|
|
11
11
|
base_url = 'contracts'
|
|
@@ -5,10 +5,17 @@ SERVICE_PROVIDER_MODELS = Q(
|
|
|
5
5
|
| Q(app_label='netbox_contract', model__in=('serviceprovider',))
|
|
6
6
|
)
|
|
7
7
|
|
|
8
|
+
SERVICE_PROVIDER_TYPES = (
|
|
9
|
+
'provider',
|
|
10
|
+
'serviceprovider',
|
|
11
|
+
)
|
|
12
|
+
|
|
8
13
|
ASSIGNEMENT_MODELS = Q(
|
|
9
14
|
Q(app_label='circuits', model__in=('circuit',))
|
|
10
15
|
| Q(app_label='circuits', model__in=('virtualcircuit',))
|
|
11
16
|
| Q(app_label='dcim', model__in=('site',))
|
|
12
17
|
| Q(app_label='dcim', model__in=('device',))
|
|
18
|
+
| Q(app_label='dcim', model__in=('rack',))
|
|
13
19
|
| Q(app_label='virtualization', model__in=('virtualmachine',))
|
|
20
|
+
| Q(app_label='virtualization', model__in=('cluster',))
|
|
14
21
|
)
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import django_filters
|
|
2
2
|
from django.db.models import Q
|
|
3
|
+
from django.contrib.contenttypes.models import ContentType
|
|
3
4
|
from netbox.filtersets import NetBoxModelFilterSet
|
|
4
5
|
from tenancy.filtersets import ContactModelFilterSet, TenancyFilterSet
|
|
6
|
+
from circuits.models import Provider
|
|
5
7
|
|
|
6
8
|
from .models import (
|
|
7
9
|
AccountingDimension,
|
|
@@ -31,16 +33,29 @@ class ContractFilterSet(ContactModelFilterSet, NetBoxModelFilterSet, TenancyFilt
|
|
|
31
33
|
field_name='contract_type__name', to_field_name='name', queryset=ContractType.objects.all()
|
|
32
34
|
)
|
|
33
35
|
|
|
36
|
+
service_provider_id = django_filters.NumberFilter(
|
|
37
|
+
field_name='external_party_object_id',
|
|
38
|
+
method='filter_by_service_provider',
|
|
39
|
+
label='Service provider'
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
provider_id = django_filters.NumberFilter(
|
|
43
|
+
field_name='external_party_object_id',
|
|
44
|
+
method='filter_by_circuit_provider',
|
|
45
|
+
label='Circuit provider'
|
|
46
|
+
)
|
|
47
|
+
|
|
34
48
|
class Meta:
|
|
35
49
|
model = Contract
|
|
36
50
|
fields = (
|
|
37
51
|
'id',
|
|
38
52
|
'name',
|
|
53
|
+
'status',
|
|
54
|
+
'internal_party',
|
|
55
|
+
'currency',
|
|
39
56
|
'contract_type',
|
|
57
|
+
'external_party_object_id',
|
|
40
58
|
'external_reference',
|
|
41
|
-
'start_date',
|
|
42
|
-
'end_date',
|
|
43
|
-
'initial_term',
|
|
44
59
|
'parent',
|
|
45
60
|
)
|
|
46
61
|
|
|
@@ -52,6 +67,22 @@ class ContractFilterSet(ContactModelFilterSet, NetBoxModelFilterSet, TenancyFilt
|
|
|
52
67
|
Q(status__iexact='Active'),
|
|
53
68
|
)
|
|
54
69
|
|
|
70
|
+
def filter_by_service_provider(self, queryset, name, value):
|
|
71
|
+
if not value:
|
|
72
|
+
return queryset
|
|
73
|
+
return queryset.filter(
|
|
74
|
+
external_party_object_id=value,
|
|
75
|
+
external_party_object_type=ContentType.objects.get_for_model(ServiceProvider)
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
def filter_by_circuit_provider(self, queryset, name, value):
|
|
79
|
+
if not value:
|
|
80
|
+
return queryset
|
|
81
|
+
return queryset.filter(
|
|
82
|
+
external_party_object_id=value,
|
|
83
|
+
external_party_object_type=ContentType.objects.get_for_model(Provider)
|
|
84
|
+
)
|
|
85
|
+
|
|
55
86
|
|
|
56
87
|
class InvoiceFilterSet(NetBoxModelFilterSet):
|
|
57
88
|
status = django_filters.MultipleChoiceFilter(choices=InvoiceStatusChoices, null_value=None)
|
|
@@ -11,7 +11,8 @@ from netbox.forms import (
|
|
|
11
11
|
)
|
|
12
12
|
from tenancy.forms import ContactModelFilterForm, TenancyFilterForm
|
|
13
13
|
from tenancy.models import Tenant
|
|
14
|
-
from
|
|
14
|
+
from circuits.models import Provider
|
|
15
|
+
from utilities.forms import BOOLEAN_WITH_BLANK_CHOICES, get_field_value
|
|
15
16
|
from utilities.forms.fields import (
|
|
16
17
|
ColorField,
|
|
17
18
|
CommentField,
|
|
@@ -26,8 +27,9 @@ from utilities.forms.fields import (
|
|
|
26
27
|
TagFilterField,
|
|
27
28
|
)
|
|
28
29
|
from utilities.forms.widgets import DatePicker, HTMXSelect
|
|
30
|
+
from utilities.templatetags.builtins.filters import bettertitle
|
|
29
31
|
|
|
30
|
-
from .constants import ASSIGNEMENT_MODELS, SERVICE_PROVIDER_MODELS
|
|
32
|
+
from .constants import ASSIGNEMENT_MODELS, SERVICE_PROVIDER_MODELS, SERVICE_PROVIDER_TYPES
|
|
31
33
|
from .models import (
|
|
32
34
|
AccountingDimension,
|
|
33
35
|
AccountingDimensionStatusChoices,
|
|
@@ -151,16 +153,46 @@ class ContractFilterForm(ContactModelFilterForm, TenancyFilterForm, NetBoxModelF
|
|
|
151
153
|
selector=True,
|
|
152
154
|
label=_('Contract type'),
|
|
153
155
|
)
|
|
156
|
+
|
|
157
|
+
service_provider_id = DynamicModelChoiceField(
|
|
158
|
+
queryset=ServiceProvider.objects.all(),
|
|
159
|
+
required=False,
|
|
160
|
+
selector=True,
|
|
161
|
+
label=_('Service provider'),
|
|
162
|
+
help_text=_('Filter by Service Provider'),
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
provider_id = DynamicModelChoiceField(
|
|
166
|
+
queryset=Provider.objects.all(),
|
|
167
|
+
required=False,
|
|
168
|
+
selector=True,
|
|
169
|
+
label=_('Circuit Provider'),
|
|
170
|
+
help_text=_('Filter by Circuit Provider'),
|
|
171
|
+
)
|
|
172
|
+
|
|
154
173
|
external_reference = forms.CharField(required=False, label=_('External reference'))
|
|
155
|
-
|
|
174
|
+
|
|
175
|
+
internal_party = forms.ChoiceField(
|
|
176
|
+
choices=[('', '-----')] + list(InternalEntityChoices),
|
|
177
|
+
required=False,
|
|
178
|
+
label=_('Internal party')
|
|
179
|
+
)
|
|
180
|
+
|
|
156
181
|
status = forms.ChoiceField(choices=StatusChoices, required=False, label=_('Status'))
|
|
157
|
-
|
|
182
|
+
|
|
183
|
+
currency = forms.ChoiceField(
|
|
184
|
+
choices=[('', '-----')] + list(CurrencyChoices),
|
|
185
|
+
required=False,
|
|
186
|
+
label=_('Currency')
|
|
187
|
+
)
|
|
188
|
+
|
|
158
189
|
parent = DynamicModelChoiceField(
|
|
159
190
|
queryset=Contract.objects.all(),
|
|
160
191
|
required=False,
|
|
161
192
|
selector=True,
|
|
162
193
|
label=_('Parent'),
|
|
163
194
|
)
|
|
195
|
+
|
|
164
196
|
tag = TagFilterField(model)
|
|
165
197
|
|
|
166
198
|
|
|
@@ -237,6 +269,21 @@ class ContractBulkEditForm(NetBoxModelBulkEditForm):
|
|
|
237
269
|
selector=True,
|
|
238
270
|
label=_('Contract Type')
|
|
239
271
|
)
|
|
272
|
+
|
|
273
|
+
external_party_object_type = ContentTypeChoiceField(
|
|
274
|
+
queryset=ContentType.objects.filter(model__in=SERVICE_PROVIDER_TYPES),
|
|
275
|
+
widget=HTMXSelect(method='post', attrs={'hx-select': '#form_fields'}),
|
|
276
|
+
required=False,
|
|
277
|
+
label=_('External party type')
|
|
278
|
+
)
|
|
279
|
+
external_party_object = DynamicModelChoiceField(
|
|
280
|
+
label=_('External party'),
|
|
281
|
+
queryset=ServiceProvider.objects.none(), # Initial queryset
|
|
282
|
+
required=False,
|
|
283
|
+
disabled=True,
|
|
284
|
+
selector=True
|
|
285
|
+
)
|
|
286
|
+
|
|
240
287
|
external_reference = forms.CharField(max_length=100, required=False, label=_('External reference'))
|
|
241
288
|
internal_party = forms.ChoiceField(choices=InternalEntityChoices, required=False, label=_('Internal party'))
|
|
242
289
|
tenant = DynamicModelChoiceField(queryset=Tenant.objects.all(), required=False, selector=True, label=_('Tenant'))
|
|
@@ -251,6 +298,19 @@ class ContractBulkEditForm(NetBoxModelBulkEditForm):
|
|
|
251
298
|
nullable_fields = ('comments',)
|
|
252
299
|
model = Contract
|
|
253
300
|
|
|
301
|
+
def __init__(self, *args, **kwargs):
|
|
302
|
+
super().__init__(*args, **kwargs)
|
|
303
|
+
|
|
304
|
+
if external_party_object_type_id := get_field_value(self, 'external_party_object_type'):
|
|
305
|
+
try:
|
|
306
|
+
external_party_object_type = ContentType.objects.get(pk=external_party_object_type_id)
|
|
307
|
+
model = external_party_object_type.model_class()
|
|
308
|
+
self.fields['external_party_object'].queryset = model.objects.all()
|
|
309
|
+
self.fields['external_party_object'].widget.attrs['selector'] = model._meta.label_lower
|
|
310
|
+
self.fields['external_party_object'].disabled = False
|
|
311
|
+
self.fields['external_party_object'].label = _(bettertitle(model._meta.verbose_name))
|
|
312
|
+
except ObjectDoesNotExist:
|
|
313
|
+
pass
|
|
254
314
|
|
|
255
315
|
# ContractType
|
|
256
316
|
|
|
@@ -193,6 +193,36 @@ class ContractListBottomTable(NetBoxTable):
|
|
|
193
193
|
)
|
|
194
194
|
|
|
195
195
|
|
|
196
|
+
class ContractProviderBottomTable(NetBoxTable):
|
|
197
|
+
name = tables.Column(linkify=True)
|
|
198
|
+
external_party_object = tables.Column(linkify=True)
|
|
199
|
+
status = columns.ChoiceFieldColumn(
|
|
200
|
+
verbose_name=('Status'),
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
class Meta(NetBoxTable.Meta):
|
|
204
|
+
model = Contract
|
|
205
|
+
fields = (
|
|
206
|
+
'pk',
|
|
207
|
+
'id',
|
|
208
|
+
'name',
|
|
209
|
+
'start_date',
|
|
210
|
+
'end_date',
|
|
211
|
+
'external_reference',
|
|
212
|
+
'status',
|
|
213
|
+
'mrc',
|
|
214
|
+
'comments',
|
|
215
|
+
'actions',
|
|
216
|
+
)
|
|
217
|
+
default_columns = (
|
|
218
|
+
'name',
|
|
219
|
+
'status',
|
|
220
|
+
'external_reference',
|
|
221
|
+
'start_date',
|
|
222
|
+
'end_date',
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
|
|
196
226
|
class InvoiceListTable(NetBoxTable):
|
|
197
227
|
contracts = tables.ManyToManyColumn(linkify=True)
|
|
198
228
|
number = tables.Column(linkify=True)
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
from circuits.models import Circuit, VirtualCircuit
|
|
2
|
-
from dcim.models import Device, Site
|
|
1
|
+
from circuits.models import Circuit, VirtualCircuit, Provider
|
|
2
|
+
from dcim.models import Device, Site, Rack
|
|
3
3
|
from django.contrib.contenttypes.models import ContentType
|
|
4
4
|
from netbox.plugins import PluginTemplateExtension
|
|
5
|
-
from virtualization.models import VirtualMachine
|
|
5
|
+
from virtualization.models import VirtualMachine, Cluster
|
|
6
6
|
|
|
7
7
|
from . import tables
|
|
8
|
-
from .models import ContractAssignment
|
|
8
|
+
from .models import ContractAssignment, Contract
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
class CircuitContractAssignments(PluginTemplateExtension):
|
|
@@ -28,15 +28,16 @@ class CircuitContractAssignments(PluginTemplateExtension):
|
|
|
28
28
|
)
|
|
29
29
|
|
|
30
30
|
|
|
31
|
-
class
|
|
32
|
-
models = ['
|
|
31
|
+
class VirtualCircuitContractAssignments(PluginTemplateExtension):
|
|
32
|
+
models = ['circuits.virtualcircuit']
|
|
33
33
|
|
|
34
34
|
def full_width_page(self):
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
virtualcircuit = self.context['object']
|
|
36
|
+
virtualcircuit_type = ContentType.objects.get_for_model(VirtualCircuit)
|
|
37
37
|
contract_assignments = ContractAssignment.objects.filter(
|
|
38
|
-
content_type__pk=
|
|
38
|
+
content_type__pk=virtualcircuit_type.id, object_id=virtualcircuit.id
|
|
39
39
|
)
|
|
40
|
+
|
|
40
41
|
assignments_table = tables.ContractAssignmentObjectTable(contract_assignments)
|
|
41
42
|
assignments_table.configure(self.context['request'])
|
|
42
43
|
|
|
@@ -48,14 +49,36 @@ class DeviceContractAssignments(PluginTemplateExtension):
|
|
|
48
49
|
)
|
|
49
50
|
|
|
50
51
|
|
|
51
|
-
class
|
|
52
|
-
models = ['
|
|
52
|
+
class ProviderContracts(PluginTemplateExtension):
|
|
53
|
+
models = ['circuits.provider']
|
|
53
54
|
|
|
54
55
|
def full_width_page(self):
|
|
55
|
-
|
|
56
|
-
|
|
56
|
+
provider = self.context['object']
|
|
57
|
+
provider_type = ContentType.objects.get_for_model(Provider)
|
|
58
|
+
contracts = Contract.objects.filter(
|
|
59
|
+
external_party_object_type__pk=provider_type.id,
|
|
60
|
+
external_party_object_id=provider.id
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
contracts_table = tables.ContractProviderBottomTable(contracts)
|
|
64
|
+
contracts_table.configure(self.context['request'])
|
|
65
|
+
|
|
66
|
+
return self.render(
|
|
67
|
+
'contract_list_bottom.html',
|
|
68
|
+
extra_context={
|
|
69
|
+
'contracts_table': contracts_table,
|
|
70
|
+
},
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class DeviceContractAssignments(PluginTemplateExtension):
|
|
75
|
+
models = ['dcim.device']
|
|
76
|
+
|
|
77
|
+
def full_width_page(self):
|
|
78
|
+
device = self.context['object']
|
|
79
|
+
device_type = ContentType.objects.get_for_model(Device)
|
|
57
80
|
contract_assignments = ContractAssignment.objects.filter(
|
|
58
|
-
content_type__pk=
|
|
81
|
+
content_type__pk=device_type.id, object_id=device.id
|
|
59
82
|
)
|
|
60
83
|
assignments_table = tables.ContractAssignmentObjectTable(contract_assignments)
|
|
61
84
|
assignments_table.configure(self.context['request'])
|
|
@@ -88,14 +111,55 @@ class SiteContractAssignments(PluginTemplateExtension):
|
|
|
88
111
|
)
|
|
89
112
|
|
|
90
113
|
|
|
91
|
-
class
|
|
92
|
-
models = ['
|
|
114
|
+
class RackContractAssignments(PluginTemplateExtension):
|
|
115
|
+
models = ['dcim.rack']
|
|
93
116
|
|
|
94
117
|
def full_width_page(self):
|
|
95
|
-
|
|
96
|
-
|
|
118
|
+
rack = self.context['object']
|
|
119
|
+
rack_type = ContentType.objects.get_for_model(Rack)
|
|
97
120
|
contract_assignments = ContractAssignment.objects.filter(
|
|
98
|
-
content_type__pk=
|
|
121
|
+
content_type__pk=rack_type.id, object_id=rack.id
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
assignments_table = tables.ContractAssignmentObjectTable(contract_assignments)
|
|
125
|
+
assignments_table.configure(self.context['request'])
|
|
126
|
+
|
|
127
|
+
return self.render(
|
|
128
|
+
'contract_assignments_bottom.html',
|
|
129
|
+
extra_context={
|
|
130
|
+
'assignments_table': assignments_table,
|
|
131
|
+
},
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
class VMContractAssignments(PluginTemplateExtension):
|
|
136
|
+
models = ['virtualization.virtualmachine']
|
|
137
|
+
|
|
138
|
+
def full_width_page(self):
|
|
139
|
+
vm = self.context['object']
|
|
140
|
+
vm_type = ContentType.objects.get_for_model(VirtualMachine)
|
|
141
|
+
contract_assignments = ContractAssignment.objects.filter(
|
|
142
|
+
content_type__pk=vm_type.id, object_id=vm.id
|
|
143
|
+
)
|
|
144
|
+
assignments_table = tables.ContractAssignmentObjectTable(contract_assignments)
|
|
145
|
+
assignments_table.configure(self.context['request'])
|
|
146
|
+
|
|
147
|
+
return self.render(
|
|
148
|
+
'contract_assignments_bottom.html',
|
|
149
|
+
extra_context={
|
|
150
|
+
'assignments_table': assignments_table,
|
|
151
|
+
},
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
class ClusterContractAssignments(PluginTemplateExtension):
|
|
156
|
+
models = ['virtualization.cluster']
|
|
157
|
+
|
|
158
|
+
def full_width_page(self):
|
|
159
|
+
cluster = self.context['object']
|
|
160
|
+
cluster_type = ContentType.objects.get_for_model(Cluster)
|
|
161
|
+
contract_assignments = ContractAssignment.objects.filter(
|
|
162
|
+
content_type__pk=cluster_type.id, object_id=cluster.id
|
|
99
163
|
)
|
|
100
164
|
|
|
101
165
|
assignments_table = tables.ContractAssignmentObjectTable(contract_assignments)
|
|
@@ -111,8 +175,11 @@ class VirtualCircuitContractAssignments(PluginTemplateExtension):
|
|
|
111
175
|
|
|
112
176
|
template_extensions = [
|
|
113
177
|
CircuitContractAssignments,
|
|
178
|
+
VirtualCircuitContractAssignments,
|
|
179
|
+
ProviderContracts,
|
|
114
180
|
DeviceContractAssignments,
|
|
115
|
-
VMContractAssignments,
|
|
116
181
|
SiteContractAssignments,
|
|
117
|
-
|
|
182
|
+
RackContractAssignments,
|
|
183
|
+
VMContractAssignments,
|
|
184
|
+
ClusterContractAssignments,
|
|
118
185
|
]
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
{% extends 'generic/object.html' %}
|
|
2
|
+
{% load plugins %}
|
|
3
|
+
{% load render_table from django_tables2 %}
|
|
2
4
|
{% load static %}
|
|
3
5
|
{% load helpers %}
|
|
4
6
|
{% load i18n %}
|
|
@@ -31,6 +33,14 @@
|
|
|
31
33
|
{% include 'inc/panels/custom_fields.html' %}
|
|
32
34
|
{% include 'inc/panels/comments.html' %}
|
|
33
35
|
{% include 'inc/panels/tags.html' %}
|
|
36
|
+
<div class="row">
|
|
37
|
+
<div class="col col-md-12">
|
|
38
|
+
<div class="card">
|
|
39
|
+
<h5 class="card-header">{% trans "Contracts" %}</h5>
|
|
40
|
+
{% render_table contracts_table %}
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
34
44
|
</div>
|
|
35
45
|
</div>
|
|
36
46
|
{% endblock content %}
|
|
@@ -75,6 +75,19 @@ class ContractTypeBulkDeleteView(generic.BulkDeleteView):
|
|
|
75
75
|
class ServiceProviderView(generic.ObjectView):
|
|
76
76
|
queryset = ServiceProvider.objects.all()
|
|
77
77
|
|
|
78
|
+
def get_extra_context(self, request, instance):
|
|
79
|
+
provider_type = ContentType.objects.get_for_model(ServiceProvider)
|
|
80
|
+
contracts = Contract.objects.filter(
|
|
81
|
+
external_party_object_type__pk=provider_type.id,
|
|
82
|
+
external_party_object_id=instance.id
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
contracts_table = tables.ContractProviderBottomTable(contracts)
|
|
86
|
+
contracts_table.configure(request)
|
|
87
|
+
return {
|
|
88
|
+
'contracts_table': contracts_table,
|
|
89
|
+
}
|
|
90
|
+
|
|
78
91
|
|
|
79
92
|
class ServiceProviderListView(generic.ObjectListView):
|
|
80
93
|
queryset = ServiceProvider.objects.all()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: netbox-contract
|
|
3
|
-
Version: 2.4.
|
|
3
|
+
Version: 2.4.3
|
|
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
|
|
@@ -48,6 +48,7 @@ Accounting dimensions can be linked with invoice lines.
|
|
|
48
48
|
| 4.1 | 2.2 |
|
|
49
49
|
| 4.2 | 2.3 |
|
|
50
50
|
| 4.3 | 2.4 |
|
|
51
|
+
| 4.4 | 2.4 |
|
|
51
52
|
|
|
52
53
|
## Installing
|
|
53
54
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/locale/en/LC_MESSAGES/django.mo
RENAMED
|
File without changes
|
{netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/locale/en/LC_MESSAGES/django.po
RENAMED
|
File without changes
|
{netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/locale/fr/LC_MESSAGES/django.mo
RENAMED
|
File without changes
|
{netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/locale/fr/LC_MESSAGES/django.po
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0007_invoice_date.py
RENAMED
|
File without changes
|
{netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0008_invoice_comments.py
RENAMED
|
File without changes
|
|
File without changes
|
{netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0010_invoice_contracts.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0014_contract_end_date.py
RENAMED
|
File without changes
|
|
File without changes
|
{netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0016_contract_parent.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0027_invoiceline.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/migrations/0043_invoice_status.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract/templates/contract_list_bottom.html
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{netbox_contract-2.4.2 → netbox_contract-2.4.3}/netbox_contract.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|