netbox-contract 2.2.3__tar.gz → 2.2.4__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.2.3/src/netbox_contract.egg-info → netbox_contract-2.2.4}/PKG-INFO +1 -1
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/pyproject.toml +1 -1
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/__init__.py +1 -1
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/api/serializers.py +161 -6
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/forms.py +21 -2
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/templates/netbox_contract/contract.html +29 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/templates/netbox_contract/invoice.html +5 -5
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/views.py +21 -3
- {netbox_contract-2.2.3 → netbox_contract-2.2.4/src/netbox_contract.egg-info}/PKG-INFO +1 -1
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/LICENSE +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/MANIFEST.in +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/README.md +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/setup.cfg +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/setup.py +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/api/__init__.py +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/api/urls.py +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/api/views.py +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/constants.py +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/filtersets.py +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/migrations/0001_initial.py +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/migrations/0002_alter_contract_circuit_and_more.py +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/migrations/0003_alter_contract_custom_field_data_and_more.py +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/migrations/0004_contract_currency_invoice_currency.py +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/migrations/0005_contract_accounting_dimensions_and_more.py +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/migrations/0006_alter_contract_circuit.py +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/migrations/0007_invoice_date.py +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/migrations/0008_invoice_comments.py +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/migrations/0009_contract_external_reference.py +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/migrations/0010_invoice_contracts.py +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/migrations/0011_auto_20230122_2112.py +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/migrations/0012_remove_invoice_contract.py +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/migrations/0013_contract_documents_invoice_documents.py +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/migrations/0014_contract_end_date.py +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/migrations/0015_contractassignement.py +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/migrations/0016_contract_parent.py +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/migrations/0017_alter_contract_accounting_dimensions.py +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/migrations/0018_contract_external_partie_object_id_and_more.py +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/migrations/0019_auto_20230924_1813.py +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/migrations/0020_alter_contract_external_partie.py +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/migrations/0021_alter_contract_external_partie.py +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/migrations/0022_alter_contract_internal_partie_alter_contract_parent.py +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/migrations/0023_rename_contractassignement_contractassignment_and_more.py +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/migrations/0024_remove_contract_external_partie.py +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/migrations/0025_remove_contract_circuit_and_more.py +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/migrations/0026_auto_20240421_1550.py +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/migrations/0027_invoiceline.py +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/migrations/0028_invoiceline_accounting_dimensions.py +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/migrations/0029_remove_invoiceline_accounting_dimensions_and_more.py +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/migrations/0030_alter_invoiceline_accounting_dimensions.py +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/migrations/0031_contract_invoice_template_invoice_template.py +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/migrations/0032_alter_invoice_period_end_alter_invoice_period_start_and_more.py +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/migrations/0033_remove_contract_invoice_template.py +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/migrations/0034_contract_yrc_alter_contract_mrc.py +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/migrations/0035_accountingdimension_status_and_more.py +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/migrations/0036_alter_invoiceline_accounting_dimensions.py +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/migrations/__init__.py +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/models.py +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/navigation.py +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/search.py +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/tables.py +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/template_content.py +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/templates/contract_assignments_bottom.html +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/templates/contract_list_bottom.html +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/templates/netbox_contract/accountingdimension.html +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/templates/netbox_contract/contractassignment.html +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/templates/netbox_contract/invoiceline.html +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/templates/netbox_contract/serviceprovider.html +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/urls.py +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract.egg-info/SOURCES.txt +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract.egg-info/dependency_links.txt +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract.egg-info/not-zip-safe +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract.egg-info/requires.txt +0 -0
- {netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract.egg-info/top_level.txt +0 -0
|
@@ -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.2.
|
|
8
|
+
version = '2.2.4'
|
|
9
9
|
author = 'Marc Lebreuil'
|
|
10
10
|
author_email = 'marc@famillelebreuil.net'
|
|
11
11
|
base_url = 'contracts'
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from django.contrib.auth.models import ContentType
|
|
2
|
+
from django.core.exceptions import ObjectDoesNotExist
|
|
2
3
|
from drf_yasg.utils import swagger_serializer_method
|
|
3
|
-
from netbox.api.fields import ContentTypeField
|
|
4
|
+
from netbox.api.fields import ContentTypeField, SerializedPKRelatedField
|
|
4
5
|
from netbox.api.serializers import NetBoxModelSerializer, WritableNestedSerializer
|
|
5
6
|
from netbox.constants import NESTED_SERIALIZER_PREFIX
|
|
6
7
|
from rest_framework import serializers
|
|
@@ -31,10 +32,46 @@ class NestedContractSerializer(WritableNestedSerializer):
|
|
|
31
32
|
url = serializers.HyperlinkedIdentityField(
|
|
32
33
|
view_name='plugins-api:netbox_contract-api:contract-detail'
|
|
33
34
|
)
|
|
35
|
+
yrc = serializers.DecimalField(max_digits=10, decimal_places=2, read_only=True)
|
|
36
|
+
tenant = NestedTenantSerializer(many=False, required=False)
|
|
37
|
+
external_partie_object_type = ContentTypeField(queryset=ContentType.objects.all())
|
|
38
|
+
external_partie_object = serializers.SerializerMethodField(read_only=True)
|
|
34
39
|
|
|
35
40
|
class Meta:
|
|
36
41
|
model = Contract
|
|
37
|
-
fields =
|
|
42
|
+
fields = fields = (
|
|
43
|
+
'id',
|
|
44
|
+
'url',
|
|
45
|
+
'display',
|
|
46
|
+
'name',
|
|
47
|
+
'external_partie_object_type',
|
|
48
|
+
'external_partie_object_id',
|
|
49
|
+
'external_partie_object',
|
|
50
|
+
'external_reference',
|
|
51
|
+
'internal_partie',
|
|
52
|
+
'tenant',
|
|
53
|
+
'status',
|
|
54
|
+
'start_date',
|
|
55
|
+
'end_date',
|
|
56
|
+
'initial_term',
|
|
57
|
+
'renewal_term',
|
|
58
|
+
'currency',
|
|
59
|
+
'accounting_dimensions',
|
|
60
|
+
'mrc',
|
|
61
|
+
'yrc',
|
|
62
|
+
'nrc',
|
|
63
|
+
'invoice_frequency',
|
|
64
|
+
'comments',
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
@swagger_serializer_method(serializer_or_field=serializers.JSONField)
|
|
68
|
+
def get_external_partie_object(self, instance):
|
|
69
|
+
serializer = get_serializer_for_model(
|
|
70
|
+
instance.external_partie_object_type.model_class(),
|
|
71
|
+
prefix=NESTED_SERIALIZER_PREFIX,
|
|
72
|
+
)
|
|
73
|
+
context = {'request': self.context['request']}
|
|
74
|
+
return serializer(instance.external_partie_object, context=context).data
|
|
38
75
|
|
|
39
76
|
|
|
40
77
|
class NestedInvoiceSerializer(WritableNestedSerializer):
|
|
@@ -134,8 +171,25 @@ class ContractSerializer(NetBoxModelSerializer):
|
|
|
134
171
|
'url',
|
|
135
172
|
'display',
|
|
136
173
|
'name',
|
|
174
|
+
'external_partie_object_type',
|
|
175
|
+
'external_partie_object_id',
|
|
137
176
|
'external_partie_object',
|
|
177
|
+
'external_reference',
|
|
178
|
+
'internal_partie',
|
|
179
|
+
'tenant',
|
|
138
180
|
'status',
|
|
181
|
+
'start_date',
|
|
182
|
+
'end_date',
|
|
183
|
+
'initial_term',
|
|
184
|
+
'renewal_term',
|
|
185
|
+
'currency',
|
|
186
|
+
'accounting_dimensions',
|
|
187
|
+
'mrc',
|
|
188
|
+
'yrc',
|
|
189
|
+
'nrc',
|
|
190
|
+
'invoice_frequency',
|
|
191
|
+
'comments',
|
|
192
|
+
'parent',
|
|
139
193
|
)
|
|
140
194
|
|
|
141
195
|
@swagger_serializer_method(serializer_or_field=serializers.JSONField)
|
|
@@ -152,7 +206,12 @@ class InvoiceSerializer(NetBoxModelSerializer):
|
|
|
152
206
|
url = serializers.HyperlinkedIdentityField(
|
|
153
207
|
view_name='plugins-api:netbox_contract-api:invoice-detail'
|
|
154
208
|
)
|
|
155
|
-
contracts =
|
|
209
|
+
contracts = SerializedPKRelatedField(
|
|
210
|
+
queryset=Contract.objects.all(),
|
|
211
|
+
serializer=ContractSerializer,
|
|
212
|
+
required=False,
|
|
213
|
+
many=True,
|
|
214
|
+
)
|
|
156
215
|
|
|
157
216
|
class Meta:
|
|
158
217
|
model = Invoice
|
|
@@ -162,6 +221,7 @@ class InvoiceSerializer(NetBoxModelSerializer):
|
|
|
162
221
|
'display',
|
|
163
222
|
'number',
|
|
164
223
|
'date',
|
|
224
|
+
'template',
|
|
165
225
|
'contracts',
|
|
166
226
|
'period_start',
|
|
167
227
|
'period_end',
|
|
@@ -174,7 +234,87 @@ class InvoiceSerializer(NetBoxModelSerializer):
|
|
|
174
234
|
'created',
|
|
175
235
|
'last_updated',
|
|
176
236
|
)
|
|
177
|
-
brief_fields = (
|
|
237
|
+
brief_fields = (
|
|
238
|
+
'id',
|
|
239
|
+
'url',
|
|
240
|
+
'display',
|
|
241
|
+
'number',
|
|
242
|
+
'date',
|
|
243
|
+
'template',
|
|
244
|
+
'contracts',
|
|
245
|
+
'period_start',
|
|
246
|
+
'period_end',
|
|
247
|
+
'currency',
|
|
248
|
+
'accounting_dimensions',
|
|
249
|
+
'amount',
|
|
250
|
+
'comments',
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
def validate(self, data):
|
|
254
|
+
data = super().validate(data)
|
|
255
|
+
|
|
256
|
+
# template checks
|
|
257
|
+
if data['template']:
|
|
258
|
+
# Check that there is only one invoice template per contract
|
|
259
|
+
contracts = data['contracts']
|
|
260
|
+
for contract in contracts:
|
|
261
|
+
for invoice in contract.invoices.all():
|
|
262
|
+
if invoice.template and invoice != self.instance:
|
|
263
|
+
raise serializers.ValidationError(
|
|
264
|
+
'Only one invoice template allowed per contract'
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
# Prefix the invoice name with _template
|
|
268
|
+
data['number'] = '_invoice_template_' + contract.name
|
|
269
|
+
|
|
270
|
+
# set the periode start and end date to null
|
|
271
|
+
data['period_start'] = None
|
|
272
|
+
data['period_end'] = None
|
|
273
|
+
return data
|
|
274
|
+
|
|
275
|
+
def create(self, validated_data):
|
|
276
|
+
instance = super().create(validated_data)
|
|
277
|
+
|
|
278
|
+
if not instance.template:
|
|
279
|
+
contracts = instance.contracts.all()
|
|
280
|
+
|
|
281
|
+
for contract in contracts:
|
|
282
|
+
try:
|
|
283
|
+
template_exists = True
|
|
284
|
+
invoice_template = Invoice.objects.get(
|
|
285
|
+
template=True, contracts=contract
|
|
286
|
+
)
|
|
287
|
+
except ObjectDoesNotExist:
|
|
288
|
+
template_exists = False
|
|
289
|
+
|
|
290
|
+
if template_exists:
|
|
291
|
+
first = True
|
|
292
|
+
for line in invoice_template.invoicelines.all():
|
|
293
|
+
dimensions = line.accounting_dimensions.all()
|
|
294
|
+
line.pk = None
|
|
295
|
+
line.id = None
|
|
296
|
+
line._state.adding = True
|
|
297
|
+
line.invoice = instance
|
|
298
|
+
|
|
299
|
+
# adjust the first invoice line amount
|
|
300
|
+
amount = validated_data['amount']
|
|
301
|
+
if (
|
|
302
|
+
first
|
|
303
|
+
and amount != invoice_template.total_invoicelines_amount
|
|
304
|
+
):
|
|
305
|
+
line.amount = (
|
|
306
|
+
line.amount
|
|
307
|
+
+ amount
|
|
308
|
+
- invoice_template.total_invoicelines_amount
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
line.save()
|
|
312
|
+
|
|
313
|
+
for dimension in dimensions:
|
|
314
|
+
line.accounting_dimensions.add(dimension)
|
|
315
|
+
first = False
|
|
316
|
+
|
|
317
|
+
return instance
|
|
178
318
|
|
|
179
319
|
|
|
180
320
|
class ServiceProviderSerializer(NetBoxModelSerializer):
|
|
@@ -235,8 +375,11 @@ class InvoiceLineSerializer(NetBoxModelSerializer):
|
|
|
235
375
|
view_name='plugins-api:netbox_contract-api:invoiceline-detail'
|
|
236
376
|
)
|
|
237
377
|
invoice = NestedInvoiceSerializer(many=False, required=False)
|
|
238
|
-
accounting_dimensions =
|
|
239
|
-
|
|
378
|
+
accounting_dimensions = SerializedPKRelatedField(
|
|
379
|
+
queryset=AccountingDimension.objects.all(),
|
|
380
|
+
serializer=NestedAccountingDimensionSerializer,
|
|
381
|
+
required=False,
|
|
382
|
+
many=True,
|
|
240
383
|
)
|
|
241
384
|
|
|
242
385
|
class Meta:
|
|
@@ -264,6 +407,18 @@ class InvoiceLineSerializer(NetBoxModelSerializer):
|
|
|
264
407
|
'name',
|
|
265
408
|
)
|
|
266
409
|
|
|
410
|
+
def validate(self, data):
|
|
411
|
+
super().validate(data)
|
|
412
|
+
# check for duplicate dimensions
|
|
413
|
+
accounting_dimensions = data['accounting_dimensions']
|
|
414
|
+
dimensions_names = []
|
|
415
|
+
for dimension in accounting_dimensions:
|
|
416
|
+
if dimension.name in dimensions_names:
|
|
417
|
+
raise serializers.ValidationError('duplicate accounting dimension')
|
|
418
|
+
else:
|
|
419
|
+
dimensions_names.append(dimension.name)
|
|
420
|
+
return data
|
|
421
|
+
|
|
267
422
|
|
|
268
423
|
class AccountingDimensionSerializer(NetBoxModelSerializer):
|
|
269
424
|
url = serializers.HyperlinkedIdentityField(
|
|
@@ -30,6 +30,7 @@ from .models import (
|
|
|
30
30
|
AccountingDimensionStatusChoices,
|
|
31
31
|
Contract,
|
|
32
32
|
ContractAssignment,
|
|
33
|
+
CurrencyChoices,
|
|
33
34
|
InternalEntityChoices,
|
|
34
35
|
Invoice,
|
|
35
36
|
InvoiceLine,
|
|
@@ -227,13 +228,17 @@ class ContractCSVForm(NetBoxModelImportForm):
|
|
|
227
228
|
|
|
228
229
|
class ContractBulkEditForm(NetBoxModelBulkEditForm):
|
|
229
230
|
name = forms.CharField(max_length=100, required=False)
|
|
230
|
-
|
|
231
231
|
external_reference = forms.CharField(max_length=100, required=False)
|
|
232
232
|
internal_partie = forms.ChoiceField(choices=InternalEntityChoices, required=False)
|
|
233
|
+
tenant = DynamicModelChoiceField(queryset=Tenant.objects.all(), required=False)
|
|
234
|
+
accounting_dimensions = Dimensions(required=False)
|
|
233
235
|
comments = CommentField(required=False)
|
|
234
236
|
parent = DynamicModelChoiceField(queryset=Contract.objects.all(), required=False)
|
|
235
237
|
|
|
236
|
-
nullable_fields = (
|
|
238
|
+
nullable_fields = (
|
|
239
|
+
'accounting_dimensions',
|
|
240
|
+
'comments',
|
|
241
|
+
)
|
|
237
242
|
model = Contract
|
|
238
243
|
|
|
239
244
|
|
|
@@ -386,9 +391,23 @@ class InvoiceCSVForm(NetBoxModelImportForm):
|
|
|
386
391
|
|
|
387
392
|
class InvoiceBulkEditForm(NetBoxModelBulkEditForm):
|
|
388
393
|
number = forms.CharField(max_length=100, required=True)
|
|
394
|
+
template = forms.BooleanField(required=False)
|
|
395
|
+
date = forms.DateField(required=False)
|
|
389
396
|
contracts = DynamicModelMultipleChoiceField(
|
|
390
397
|
queryset=Contract.objects.all(), required=False
|
|
391
398
|
)
|
|
399
|
+
period_start = forms.DateField(required=False)
|
|
400
|
+
period_end = forms.DateField(required=False)
|
|
401
|
+
currency = forms.ChoiceField(choices=CurrencyChoices, required=False)
|
|
402
|
+
accounting_dimensions = Dimensions(required=False)
|
|
403
|
+
amount = forms.DecimalField(max_digits=10, decimal_places=2, required=False)
|
|
404
|
+
documents = forms.URLField(required=False)
|
|
405
|
+
comments = CommentField()
|
|
406
|
+
nullable_fields = (
|
|
407
|
+
'accounting_dimensions',
|
|
408
|
+
'comments',
|
|
409
|
+
)
|
|
410
|
+
|
|
392
411
|
model = Invoice
|
|
393
412
|
|
|
394
413
|
|
|
@@ -120,6 +120,33 @@
|
|
|
120
120
|
<div class="col col-md-6">
|
|
121
121
|
{% include 'inc/panels/tags.html' %}
|
|
122
122
|
{% include 'inc/panels/comments.html' %}
|
|
123
|
+
{% if invoice_template %}
|
|
124
|
+
<div class="card">
|
|
125
|
+
<h5 class="card-header">
|
|
126
|
+
Invoice template
|
|
127
|
+
</h5>
|
|
128
|
+
<table class="table table-hover attr-table">
|
|
129
|
+
<tr>
|
|
130
|
+
<th scope="row">Number</th>
|
|
131
|
+
<td>
|
|
132
|
+
<a href="{{ invoice_template.get_absolute_url }}">{{ invoice_template.number }}</a>
|
|
133
|
+
</td>
|
|
134
|
+
</tr>
|
|
135
|
+
<tr>
|
|
136
|
+
<th scope="row">Currency</th>
|
|
137
|
+
<td>{{ invoice_template.currency }}</td>
|
|
138
|
+
</tr>
|
|
139
|
+
<tr>
|
|
140
|
+
<th scope="row">Total amount</th>
|
|
141
|
+
<td>{{ invoice_template.total_invoicelines_amount }}</td>
|
|
142
|
+
</tr>
|
|
143
|
+
</table>
|
|
144
|
+
<h5 class="card-header">
|
|
145
|
+
Invoice template lines
|
|
146
|
+
</h5>
|
|
147
|
+
{% render_table invoicelines_table %}
|
|
148
|
+
</div>
|
|
149
|
+
{% endif %}
|
|
123
150
|
</div>
|
|
124
151
|
</div>
|
|
125
152
|
<div class="row">
|
|
@@ -130,6 +157,7 @@
|
|
|
130
157
|
</div>
|
|
131
158
|
</div>
|
|
132
159
|
</div>
|
|
160
|
+
{% if childs_table %}
|
|
133
161
|
<div class="row">
|
|
134
162
|
<div class="col col-md-12">
|
|
135
163
|
<div class="card">
|
|
@@ -138,6 +166,7 @@
|
|
|
138
166
|
</div>
|
|
139
167
|
</div>
|
|
140
168
|
</div>
|
|
169
|
+
{% endif %}
|
|
141
170
|
{% if perms.netbox_contract.view_invoice %}
|
|
142
171
|
<div class="row">
|
|
143
172
|
<div class="col col-md-12">
|
|
@@ -13,16 +13,16 @@
|
|
|
13
13
|
<div class="row mb-3">
|
|
14
14
|
<div class="col col-md-6">
|
|
15
15
|
<div class="card">
|
|
16
|
-
|
|
16
|
+
{% if object.template %}
|
|
17
|
+
<h5 class="card-header">Invoice template</h5>
|
|
18
|
+
{% else %}
|
|
19
|
+
<h5 class="card-header">Invoice</h5>
|
|
20
|
+
{% endif %}
|
|
17
21
|
<table class="table table-hover attr-table">
|
|
18
22
|
<tr>
|
|
19
23
|
<th scope="row">Number</th>
|
|
20
24
|
<td>{{ object.number }}</td>
|
|
21
25
|
</tr>
|
|
22
|
-
<tr>
|
|
23
|
-
<th scope="row">Template</th>
|
|
24
|
-
<td>{{ object.template }}</td>
|
|
25
|
-
</tr>
|
|
26
26
|
<tr>
|
|
27
27
|
<th scope="row">Date</th>
|
|
28
28
|
<td>{{ object.date }}</td>
|
|
@@ -138,20 +138,38 @@ class ContractView(generic.ObjectView):
|
|
|
138
138
|
)
|
|
139
139
|
|
|
140
140
|
def get_extra_context(self, request, instance):
|
|
141
|
-
invoices_table = tables.InvoiceListTable(
|
|
141
|
+
invoices_table = tables.InvoiceListTable(
|
|
142
|
+
instance.invoices.exclude(template=True)
|
|
143
|
+
)
|
|
144
|
+
invoices_table.columns.hide('contracts')
|
|
142
145
|
invoices_table.configure(request)
|
|
143
146
|
assignments_table = tables.ContractAssignmentContractTable(
|
|
144
147
|
instance.assignments.all()
|
|
145
148
|
)
|
|
149
|
+
invoice_template = instance.invoices.filter(template=True).first()
|
|
150
|
+
if invoice_template:
|
|
151
|
+
invoicelines_table = tables.InvoiceLineListTable(
|
|
152
|
+
invoice_template.invoicelines.all()
|
|
153
|
+
)
|
|
154
|
+
invoicelines_table.columns.hide('invoice')
|
|
155
|
+
invoicelines_table.columns.hide('currency')
|
|
156
|
+
invoicelines_table.configure(request)
|
|
157
|
+
else:
|
|
158
|
+
invoicelines_table = None
|
|
146
159
|
assignments_table.configure(request)
|
|
147
|
-
|
|
148
|
-
|
|
160
|
+
if instance.childs.all():
|
|
161
|
+
childs_table = tables.ContractListBottomTable(instance.childs.all())
|
|
162
|
+
childs_table.configure(request)
|
|
163
|
+
else:
|
|
164
|
+
childs_table = None
|
|
149
165
|
|
|
150
166
|
hidden_fields = plugin_settings.get('hidden_contract_fields')
|
|
151
167
|
|
|
152
168
|
return {
|
|
153
169
|
'hidden_fields': hidden_fields,
|
|
154
170
|
'invoices_table': invoices_table,
|
|
171
|
+
'invoice_template': invoice_template,
|
|
172
|
+
'invoicelines_table': invoicelines_table,
|
|
155
173
|
'assignments_table': assignments_table,
|
|
156
174
|
'childs_table': childs_table,
|
|
157
175
|
}
|
|
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.2.3 → netbox_contract-2.2.4}/src/netbox_contract/migrations/0001_initial.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/netbox_contract/migrations/0007_invoice_date.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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{netbox_contract-2.2.3 → netbox_contract-2.2.4}/src/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
|
|
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.2.3 → netbox_contract-2.2.4}/src/netbox_contract.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|