Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

version 2.0.5 #78

Merged
merged 8 commits into from
Jun 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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="marc@famillelebreuil.net" },
]
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 = 'marc@famillelebreuil.net'
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