Skip to content

Commit

Permalink
Merge pull request #78 from mlebreuil/develop
Browse files Browse the repository at this point in the history
version 2.0.5
  • Loading branch information
mlebreuil authored Jun 25, 2023
2 parents 1831746 + 5511e83 commit 83f8a32
Show file tree
Hide file tree
Showing 8 changed files with 122 additions and 38 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,10 @@ Add support for Netbox 3.5 which become the minimum version supported to accomod
* [#65](https://github.com/mlebreuil/netbox-contract/issues/65) Add end date to contact import form.
* Removed the possibility of add or modify circuits to contracts. The field becomes read only and will be removed in next major release.
* Make accounting dimensions optional.

#### version 2.0.5

* [#75](https://github.com/mlebreuil/netbox-contract/issues/74) Fix contract assignement for service providers.
* [#73](https://github.com/mlebreuil/netbox-contract/issues/73) Add comment field to contract import form
* [#72](https://github.com/mlebreuil/netbox-contract/issues/72) Add fields to the contract assignement bottom tables
* Remove the 'add' actions from the contract assignment list view
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "netbox-contract"
version = "2.0.4"
version = "2.0.5"
authors = [
{ name="Marc Lebreuil", email="[email protected]" },
]
Expand Down
2 changes: 1 addition & 1 deletion src/netbox_contract/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ class ContractsConfig(PluginConfig):
name = 'netbox_contract'
verbose_name = 'Netbox contract'
description = 'Contract management plugin for Netbox'
version = '2.0.4'
version = '2.0.5'
author = 'Marc Lebreuil'
author_email = '[email protected]'
base_url = 'contracts'
Expand Down
10 changes: 7 additions & 3 deletions src/netbox_contract/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from django.contrib.contenttypes.models import ContentType
import django_filters
from netbox.forms import NetBoxModelForm, NetBoxModelFilterSetForm, NetBoxModelBulkEditForm, NetBoxModelImportForm
from utilities.forms.fields import CommentField, DynamicModelChoiceField, DynamicModelMultipleChoiceField, MultipleChoiceField, CSVModelChoiceField, SlugField, CSVContentTypeField
from utilities.forms.fields import CommentField, CSVChoiceField, DynamicModelChoiceField, DynamicModelMultipleChoiceField, MultipleChoiceField, CSVModelChoiceField, SlugField, CSVContentTypeField
from utilities.forms.widgets import DatePicker
from extras.filters import TagFilter
from circuits.models import Circuit
Expand Down Expand Up @@ -98,6 +98,10 @@ class ContractCSVForm(NetBoxModelImportForm):
help_text='Tenant name',
required=False
)
status = CSVChoiceField(
choices=StatusChoices,
help_text='Contract status'
)
parent = CSVModelChoiceField(
queryset=Contract.objects.all(),
to_field_name='name',
Expand All @@ -108,9 +112,9 @@ class ContractCSVForm(NetBoxModelImportForm):
class Meta:
model = Contract
fields = [
'name', 'external_partie', 'internal_partie','tenant', 'status',
'name', 'external_partie', 'internal_partie', 'external_reference','tenant', 'status',
'start_date', 'end_date','initial_term', 'renewal_term', 'mrc', 'nrc',
'invoice_frequency', 'parent'
'invoice_frequency', 'documents', 'comments', 'parent'
]

class ContractBulkEditForm(NetBoxModelBulkEditForm):
Expand Down
14 changes: 10 additions & 4 deletions src/netbox_contract/tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,25 +34,31 @@ class ContractAssignementObjectTable(NetBoxTable):

class Meta(NetBoxTable.Meta):
model = ContractAssignement
fields = ('pk','contract','contract__external_partie','contract__status', 'actions')
default_columns = ('pk', 'contract','contract__external_partie','contract__status')
fields = ('pk','contract','contract__external_partie','contract__status','contract__start_date',
'contract__end_date','contract__mrc','contract__nrc', 'actions')
default_columns = ('pk', 'contract','contract__external_partie','contract__status','contract__start_date',
'contract__end_date','contract__mrc','contract__nrc',)

class ContractAssignementContractTable(NetBoxTable):
content_type = columns.ContentTypeColumn(
verbose_name='Object Type'
)
content_object = tables.Column(
linkify=True,
verbose_name='Object',
orderable=False
)
content_object__status = tables.Column(
verbose_name='Status'
)
actions = columns.ActionsColumn(
actions=('edit', 'delete')
)

class Meta(NetBoxTable.Meta):
model = ContractAssignement
fields = ('pk', 'content_type', 'content_object','actions')
default_columns = ('pk', 'content_type', 'content_object')
fields = ('pk', 'content_type', 'content_object','content_object__status','actions')
default_columns = ('pk', 'content_type', 'content_object','content_object__status')

class ContractListTable(NetBoxTable):

Expand Down
63 changes: 63 additions & 0 deletions src/netbox_contract/templates/contact_assignements_bottom.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
{% load helpers %}

<div class="card">
<h5 class="card-header">Contacts</h5>
<div class="card-body">
{% with contacts=object.contacts.all %}
{% if contacts.exists %}
<table class="table table-hover">
<tr>
<th>Name</th>
<th>Role</th>
<th>Priority</th>
<th>Phone</th>
<th>Email</th>
<th></th>
</tr>
{% for contact in contacts %}
<tr>
<td>{{ contact.contact|linkify }}</td>
<td>{{ contact.role|placeholder }}</td>
<td>{{ contact.get_priority_display|placeholder }}</td>
<td>
{% if contact.contact.phone %}
<a href="tel:{{ contact.contact.phone }}">{{ contact.contact.phone }}</a>
{% else %}
{{ ''|placeholder }}
{% endif %}
</td>
<td>
{% if contact.contact.email %}
<a href="mailto:{{ contact.contact.email }}">{{ contact.contact.email }}</a>
{% else %}
{{ ''|placeholder }}
{% endif %}
</td>
<td class="text-end noprint">
{% if perms.tenancy.change_contactassignment %}
<a href="{% url 'tenancy:contactassignment_edit' pk=contact.pk %}?return_url={{ object.get_absolute_url }}" class="btn btn-warning btn-sm lh-1" title="Edit">
<i class="mdi mdi-pencil" aria-hidden="true"></i>
</a>
{% endif %}
{% if perms.tenancy.delete_contactassignment %}
<a href="{% url 'tenancy:contactassignment_delete' pk=contact.pk %}?return_url={{ object.get_absolute_url }}" class="btn btn-danger btn-sm lh-1" title="Delete">
<i class="mdi mdi-trash-can-outline" aria-hidden="true"></i>
</a>
{% endif %}
</td>
</tr>
{% endfor %}
</table>
{% else %}
<div class="text-muted">None</div>
{% endif %}
{% endwith %}
</div>
{% if perms.tenancy.add_contactassignment %}
<div class="card-footer text-end noprint">
<a href="{% url 'tenancy:contactassignment_add' %}?content_type={{ object|content_type_id }}&object_id={{ object.pk }}&return_url={{ object.get_absolute_url }}" class="btn btn-primary btn-sm">
<i class="mdi mdi-plus-thick" aria-hidden="true"></i> Add a contact
</a>
</div>
{% endif %}
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ <h5 class="card-header">Service Provider</h5>
{% include 'inc/panels/custom_fields.html' %}
{% include 'inc/panels/comments.html' %}
{% include 'inc/panels/tags.html' %}
{% include 'inc/panels/contacts.html' %}
{% include 'contact_assignements_bottom.html' %}
</div>
</div>
{% endblock content %}
60 changes: 32 additions & 28 deletions src/netbox_contract/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,59 +4,63 @@
from django.contrib.contenttypes.models import ContentType
from django.shortcuts import render, get_object_or_404
from netbox.views import generic
from tenancy.views import ObjectContactsView
from netbox.views.generic.utils import get_prerequisite_model
from utilities.utils import count_related, normalize_querydict
from utilities.forms import restrict_form_fields
from utilities.views import ViewTab, register_model_view
from circuits.models import Circuit
from . import forms, models, tables, filtersets
from .models import ServiceProvider, ContractAssignement, Contract, Invoice
from . import forms, tables, filtersets

# ServiceProvider views

class ServiceProviderView(generic.ObjectView):
queryset = models.ServiceProvider.objects.all()
queryset = ServiceProvider.objects.all()

class ServiceProviderListView(generic.ObjectListView):
queryset = models.ServiceProvider.objects.all()
queryset = ServiceProvider.objects.all()
table = tables.ServiceProviderListTable
filterset = filtersets.ServiceProviderFilterSet
filterset_form = forms.ServiceProviderFilterSetForm

class ServiceProviderEditView(generic.ObjectEditView):
queryset = models.ServiceProvider.objects.all()
queryset = ServiceProvider.objects.all()
form = forms.ServiceProviderForm

class ServiceProviderDeleteView(generic.ObjectDeleteView):
queryset = models.ServiceProvider.objects.all()
queryset = ServiceProvider.objects.all()

class ServiceProviderBulkImportView(generic.BulkImportView):
queryset = models.ServiceProvider.objects.all()
queryset = ServiceProvider.objects.all()
model_form = forms.ServiceProviderCSVForm
table = tables.ServiceProviderListTable

class ServiceProviderBulkEditView(generic.BulkEditView):
queryset = models.ServiceProvider.objects.annotate()
queryset = ServiceProvider.objects.annotate()
filterset = filtersets.ServiceProviderFilterSet
table = tables.ServiceProviderListTable
form = forms.ServiceProviderBulkEditForm

class ServiceProviderBulkDeleteView(generic.BulkDeleteView):
queryset = models.ServiceProvider.objects.annotate()
queryset = ServiceProvider.objects.annotate()
filterset = filtersets.ServiceProviderFilterSet
table = tables.ServiceProviderListTable

# Contract assignement view

class ContractAssignementView(generic.ObjectView):
queryset = models.ContractAssignement.objects.all()
queryset = ContractAssignement.objects.all()

class ContractAssignementListView(generic.ObjectListView):
queryset = models.ContractAssignement.objects.all()
queryset = ContractAssignement.objects.all()
table = tables.ContractAssignementListTable
filterset = filtersets.ContractAssignementFilterSet
filterset_form = forms.ContractAssignementFilterSetForm
actions = ['import', 'export', ]

class ContractAssignementEditView(generic.ObjectEditView):
queryset = models.ContractAssignement.objects.all()
queryset = ContractAssignement.objects.all()
form = forms.ContractAssignementForm

def alter_object(self, instance, request, args, kwargs):
Expand All @@ -73,17 +77,17 @@ def get_extra_addanother_params(self, request):
}

class ContractAssignementDeleteView(generic.ObjectDeleteView):
queryset = models.ContractAssignement.objects.all()
queryset = ContractAssignement.objects.all()

class ContractAssignementBulkImportView(generic.BulkImportView):
queryset = models.ContractAssignement.objects.all()
queryset = ContractAssignement.objects.all()
model_form = forms.ContractAssignementImportForm
table = tables.ContractAssignementListTable

# Contract views

class ContractView(generic.ObjectView):
queryset = models.Contract.objects.all()
queryset = Contract.objects.all()

def get_extra_context(self, request, instance):
invoices_table = tables.InvoiceListTable(instance.invoices.all())
Expand All @@ -100,33 +104,33 @@ def get_extra_context(self, request, instance):
}

class ContractListView(generic.ObjectListView):
queryset = models.Contract.objects.all()
queryset = Contract.objects.all()
table = tables.ContractListTable
filterset = filtersets.ContractFilterSet
filterset_form = forms.ContractFilterSetForm

class ContractEditView(generic.ObjectEditView):
queryset = models.Contract.objects.all()
queryset = Contract.objects.all()
form = forms.ContractForm

class ContractDeleteView(generic.ObjectDeleteView):
queryset = models.Contract.objects.all()
queryset = Contract.objects.all()

class ContractBulkImportView(generic.BulkImportView):
queryset = models.Contract.objects.all()
queryset = Contract.objects.all()
model_form = forms.ContractCSVForm
table = tables.ContractListTable

class ContractBulkEditView(generic.BulkEditView):
queryset = models.Contract.objects.annotate(
queryset = Contract.objects.annotate(
count_circuits=count_related(Circuit, 'contracts')
)
filterset = filtersets.ContractFilterSet
table = tables.ContractListTable
form = forms.ContractBulkEditForm

class ContractBulkDeleteView(generic.BulkDeleteView):
queryset = models.Contract.objects.annotate(
queryset = Contract.objects.annotate(
count_circuits=count_related(Circuit, 'contracts')
)
filterset = filtersets.ContractFilterSet
Expand All @@ -135,7 +139,7 @@ class ContractBulkDeleteView(generic.BulkDeleteView):
# Invoice views

class InvoiceView(generic.ObjectView):
queryset = models.Invoice.objects.all()
queryset = Invoice.objects.all()

def get_extra_context(self, request, instance):
contracts_table = tables.ContractListTable(instance.contracts.all())
Expand All @@ -146,13 +150,13 @@ def get_extra_context(self, request, instance):
}

class InvoiceListView(generic.ObjectListView):
queryset = models.Invoice.objects.all()
queryset = Invoice.objects.all()
table = tables.InvoiceListTable
filterset = filtersets.InvoiceFilterSet
filterset_form = forms.InvoiceFilterSetForm

class InvoiceEditView(generic.ObjectEditView):
queryset = models.Invoice.objects.all()
queryset = Invoice.objects.all()
form = forms.InvoiceForm

def get(self, request, *args, **kwargs):
Expand All @@ -171,7 +175,7 @@ def get(self, request, *args, **kwargs):
initial_data = normalize_querydict(request.GET)
initial_data['date'] = date.today()
if 'contracts' in initial_data.keys():
contract = models.Contract.objects.get(pk=initial_data['contracts'])
contract = Contract.objects.get(pk=initial_data['contracts'])

try:
last_invoice = contract.invoices.latest('period_end')
Expand Down Expand Up @@ -206,20 +210,20 @@ def get(self, request, *args, **kwargs):
})

class InvoiceDeleteView(generic.ObjectDeleteView):
queryset = models.Invoice.objects.all()
queryset = Invoice.objects.all()

class InvoiceBulkImportView(generic.BulkImportView):
queryset = models.Invoice.objects.all()
queryset = Invoice.objects.all()
model_form = forms.InvoiceCSVForm
table = tables.InvoiceListTable

class InvoiceBulkEditView(generic.BulkEditView):
queryset = models.Invoice.objects.all()
queryset = Invoice.objects.all()
filterset = filtersets.InvoiceFilterSet
table = tables.InvoiceListTable
form = forms.InvoiceBulkEditForm

class InvoiceBulkDeleteView(generic.BulkDeleteView):
queryset = models.Invoice.objects.all()
queryset = Invoice.objects.all()
filterset = filtersets.InvoiceFilterSet
table = tables.InvoiceListTable

0 comments on commit 83f8a32

Please sign in to comment.