it_manager+reports: иерархия договоров, биллинг и месячные отчёты
Иерархия рамочных/дочерних договоров и платежей, интернет-биллинг, месячные IT-отчёты (импорт, DOCX/PDF, шаблоны выводов). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+31
-13
@@ -1,5 +1,6 @@
|
||||
from django import forms
|
||||
from django.contrib import admin
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.utils import timezone
|
||||
from django.utils.html import format_html
|
||||
from django.utils.safestring import mark_safe
|
||||
@@ -9,7 +10,7 @@ from unfold.admin import ModelAdmin, TabularInline
|
||||
from .models import (
|
||||
Equipment, EquipmentAssignment, EquipmentModel,
|
||||
Ticket, TicketComment,
|
||||
InternetProvider, InternetContract,
|
||||
InternetProvider, InternetContract, InternetContractPayment,
|
||||
WorkLog, ServiceCall,
|
||||
Consumable,
|
||||
)
|
||||
@@ -17,23 +18,28 @@ from .models import (
|
||||
|
||||
class LocationChoiceField(forms.ModelChoiceField):
|
||||
def label_from_instance(self, obj):
|
||||
type_label = obj.get_location_type_display()
|
||||
addr = obj.get_full_address() or obj.address or ''
|
||||
if obj.location_type == 'pharmacy':
|
||||
try:
|
||||
num = obj.pharmacy.pharmacy_number
|
||||
return f'Аптека №{num} — {addr}'
|
||||
except Exception:
|
||||
pass
|
||||
return f'{type_label} — {addr}' if addr else type_label
|
||||
return str(obj)
|
||||
|
||||
|
||||
class InternetContractForm(forms.ModelForm):
|
||||
location = LocationChoiceField(
|
||||
queryset=None,
|
||||
required=False,
|
||||
label=_('Локация'),
|
||||
)
|
||||
|
||||
def clean(self):
|
||||
cleaned = super().clean()
|
||||
is_framework = cleaned.get('is_framework')
|
||||
location = cleaned.get('location')
|
||||
if is_framework and location:
|
||||
raise ValidationError({'location': _('У рамочного договора локация не указывается.')})
|
||||
if not is_framework and not location:
|
||||
raise ValidationError({'location': _('Укажите локацию для договора.')})
|
||||
if is_framework:
|
||||
cleaned['location'] = None
|
||||
return cleaned
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
from apps.locations.models import Location
|
||||
@@ -400,12 +406,20 @@ class TicketAdmin(ModelAdmin):
|
||||
|
||||
class InternetContractInline(TabularInline):
|
||||
model = InternetContract
|
||||
form = InternetContractForm
|
||||
extra = 0
|
||||
fields = ('location', 'contract_number', 'service_type', 'status',
|
||||
'bandwidth_down', 'bandwidth_up', 'monthly_cost', 'end_date')
|
||||
fields = ('location', 'contract_number', 'is_framework', 'parent_contract', 'service_type', 'status',
|
||||
'start_date', 'bandwidth_down', 'bandwidth_up', 'monthly_cost', 'end_date')
|
||||
show_change_link = True
|
||||
|
||||
|
||||
class InternetContractPaymentInline(TabularInline):
|
||||
model = InternetContractPayment
|
||||
extra = 0
|
||||
fields = ('period', 'amount', 'is_paid', 'paid_at', 'invoice_number', 'recorded_by')
|
||||
readonly_fields = ('recorded_by',)
|
||||
|
||||
|
||||
@admin.register(InternetProvider)
|
||||
class InternetProviderAdmin(ModelAdmin):
|
||||
list_display = ['name', 'phone', 'support_phone', 'email',
|
||||
@@ -443,8 +457,10 @@ class InternetProviderAdmin(ModelAdmin):
|
||||
@admin.register(InternetContract)
|
||||
class InternetContractAdmin(ModelAdmin):
|
||||
form = InternetContractForm
|
||||
inlines = [InternetContractPaymentInline]
|
||||
list_display = [
|
||||
'provider', 'location', 'contract_number', 'service_type_display',
|
||||
'provider', 'location', 'contract_number', 'is_framework', 'parent_contract',
|
||||
'service_type_display',
|
||||
'connection_type_display', 'status_display', 'bandwidth_display',
|
||||
'monthly_cost', 'end_date', 'expiry_display',
|
||||
]
|
||||
@@ -459,10 +475,12 @@ class InternetContractAdmin(ModelAdmin):
|
||||
fieldsets = (
|
||||
(_('Договор'), {
|
||||
'fields': ('provider', 'contract_number', 'account_number',
|
||||
'is_framework', 'parent_contract',
|
||||
'service_type', 'connection_type', 'status'),
|
||||
}),
|
||||
(_('Локация'), {
|
||||
'fields': ('location',),
|
||||
'description': _('Для рамочного договора локация не указывается.'),
|
||||
}),
|
||||
(_('Параметры'), {
|
||||
'fields': ('bandwidth_down', 'bandwidth_up', 'monthly_cost'),
|
||||
|
||||
Reference in New Issue
Block a user