Initial commit
This commit is contained in:
@@ -0,0 +1,641 @@
|
||||
from django import forms
|
||||
from core.forms.base import BaseForm
|
||||
from .models import Customer, Item, Invoice, InvoiceItem, CustomerContact, CustomerLocation, Offer, OfferItem, Reminder
|
||||
from projects.models import Project
|
||||
from time_tracking.models import TimeEntry
|
||||
from finance.models import Expense
|
||||
from django.utils import timezone
|
||||
from django.db.models import Q, Max
|
||||
|
||||
class CustomerForm(BaseForm):
|
||||
class Meta:
|
||||
model = Customer
|
||||
fields = [
|
||||
"customer_number",
|
||||
"customer_type",
|
||||
"company_name",
|
||||
"tax_number",
|
||||
"vat_number",
|
||||
"phone",
|
||||
"email",
|
||||
]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.apply_style()
|
||||
|
||||
|
||||
|
||||
class ItemForm(BaseForm):
|
||||
class Meta:
|
||||
model = Item
|
||||
fields = [
|
||||
"item_type",
|
||||
"description",
|
||||
"unit",
|
||||
"price_net",
|
||||
"tax_rate",
|
||||
]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.apply_style()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class CustomerInvoiceForm(BaseForm):
|
||||
|
||||
contact = forms.ModelChoiceField(
|
||||
queryset=CustomerContact.objects.none(),
|
||||
label="Ansprechpartner",
|
||||
required=True
|
||||
)
|
||||
|
||||
location = forms.ModelChoiceField(
|
||||
queryset=CustomerLocation.objects.none(),
|
||||
label="Standort",
|
||||
required=True
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = Invoice
|
||||
fields = [
|
||||
"customer",
|
||||
"contact",
|
||||
"location",
|
||||
"issue_date",
|
||||
"due_date",
|
||||
"note",
|
||||
]
|
||||
|
||||
widgets = {
|
||||
"issue_date": forms.DateInput(attrs={"type": "date"}),
|
||||
"due_date": forms.DateInput(attrs={"type": "date"}),
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.apply_style()
|
||||
|
||||
customer_id = (
|
||||
self.data.get("customer")
|
||||
or getattr(self.instance, "customer_id", None)
|
||||
)
|
||||
|
||||
if customer_id:
|
||||
self.fields["contact"].queryset = CustomerContact.objects.filter(customer_id=customer_id)
|
||||
self.fields["location"].queryset = CustomerLocation.objects.filter(customer_id=customer_id)
|
||||
else:
|
||||
self.fields["contact"].queryset = CustomerContact.objects.none()
|
||||
self.fields["location"].queryset = CustomerLocation.objects.none()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class ProjectInvoiceForm(BaseForm):
|
||||
|
||||
contact = forms.ModelChoiceField(
|
||||
queryset=CustomerContact.objects.none(),
|
||||
required=False,
|
||||
label="Ansprechpartner",
|
||||
widget=forms.Select(attrs={
|
||||
"class": "customer-field"
|
||||
})
|
||||
)
|
||||
|
||||
location = forms.ModelChoiceField(
|
||||
queryset=CustomerLocation.objects.none(),
|
||||
required=False,
|
||||
label="Standort",
|
||||
widget=forms.Select(attrs={
|
||||
"class": "customer-field"
|
||||
})
|
||||
)
|
||||
|
||||
|
||||
contact_name_manual = forms.CharField(
|
||||
required=False,
|
||||
label="Ansprechpartner",
|
||||
widget=forms.TextInput(attrs={
|
||||
"class": "manual-field"
|
||||
})
|
||||
)
|
||||
|
||||
contact_email_manual = forms.EmailField(
|
||||
required=False,
|
||||
label="E-Mail",
|
||||
widget=forms.EmailInput(attrs={
|
||||
"class": "manual-field"
|
||||
})
|
||||
)
|
||||
|
||||
contact_phone_manual = forms.CharField(
|
||||
required=False,
|
||||
label="Telefon",
|
||||
widget=forms.TextInput(attrs={
|
||||
"class": "manual-field"
|
||||
})
|
||||
)
|
||||
|
||||
|
||||
location_name_manual = forms.CharField(
|
||||
required=False,
|
||||
label="Standort",
|
||||
widget=forms.TextInput(attrs={
|
||||
"class": "manual-field"
|
||||
})
|
||||
)
|
||||
|
||||
location_street_manual = forms.CharField(
|
||||
required=False,
|
||||
label="Straße",
|
||||
widget=forms.TextInput(attrs={
|
||||
"class": "manual-field"
|
||||
})
|
||||
)
|
||||
|
||||
location_zip_manual = forms.CharField(
|
||||
required=False,
|
||||
label="PLZ",
|
||||
widget=forms.TextInput(attrs={
|
||||
"class": "manual-field"
|
||||
})
|
||||
)
|
||||
|
||||
location_city_manual = forms.CharField(
|
||||
required=False,
|
||||
label="Ort",
|
||||
widget=forms.TextInput(attrs={
|
||||
"class": "manual-field"
|
||||
})
|
||||
)
|
||||
|
||||
location_country_manual = forms.CharField(
|
||||
required=False,
|
||||
label="Land",
|
||||
widget=forms.TextInput(attrs={
|
||||
"class": "manual-field"
|
||||
})
|
||||
)
|
||||
|
||||
|
||||
class Meta:
|
||||
|
||||
model = Invoice
|
||||
|
||||
fields = [
|
||||
"project",
|
||||
|
||||
"contact",
|
||||
"location",
|
||||
|
||||
"contact_name_manual",
|
||||
"contact_email_manual",
|
||||
"contact_phone_manual",
|
||||
|
||||
"location_name_manual",
|
||||
"location_street_manual",
|
||||
"location_zip_manual",
|
||||
"location_city_manual",
|
||||
"location_country_manual",
|
||||
|
||||
"issue_date",
|
||||
"due_date",
|
||||
"note",
|
||||
]
|
||||
|
||||
|
||||
widgets = {
|
||||
|
||||
"issue_date": forms.DateInput(
|
||||
attrs={
|
||||
"type": "date"
|
||||
}
|
||||
),
|
||||
|
||||
"due_date": forms.DateInput(
|
||||
attrs={
|
||||
"type": "date"
|
||||
}
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
self.apply_style()
|
||||
|
||||
|
||||
project_id = self.data.get("project") or getattr(
|
||||
self.instance,
|
||||
"project_id",
|
||||
None
|
||||
)
|
||||
|
||||
|
||||
if project_id:
|
||||
|
||||
project = Project.objects.filter(
|
||||
id=project_id
|
||||
).first()
|
||||
|
||||
|
||||
if project and project.customer:
|
||||
|
||||
self.fields["contact"].queryset = CustomerContact.objects.filter(
|
||||
customer=project.customer
|
||||
)
|
||||
|
||||
self.fields["location"].queryset = CustomerLocation.objects.filter(
|
||||
customer=project.customer
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class InvoiceItemForm(BaseForm):
|
||||
|
||||
class Meta:
|
||||
model = InvoiceItem
|
||||
|
||||
fields = [
|
||||
"source_type",
|
||||
"item",
|
||||
"time_entry",
|
||||
"expense",
|
||||
"description",
|
||||
"quantity",
|
||||
"unit",
|
||||
"unit_price_net",
|
||||
"unit_tax_rate",
|
||||
'service_period_from',
|
||||
'service_period_to',
|
||||
]
|
||||
widgets = {
|
||||
|
||||
"quantity": forms.NumberInput(attrs={
|
||||
"step": "1.00"
|
||||
}),
|
||||
|
||||
"unit_price_net": forms.NumberInput(attrs={
|
||||
"step": "1.00"
|
||||
}),
|
||||
|
||||
"unit_tax_rate": forms.NumberInput(attrs={
|
||||
"step": "1.00"
|
||||
}),
|
||||
"issue_date": forms.DateInput(
|
||||
attrs={
|
||||
"type": "date"
|
||||
}
|
||||
),
|
||||
|
||||
"service_period_from": forms.DateInput(
|
||||
attrs={
|
||||
"type": "date"
|
||||
}
|
||||
),
|
||||
|
||||
"service_period_to": forms.DateInput(
|
||||
attrs={
|
||||
"type": "date"
|
||||
}
|
||||
),
|
||||
|
||||
}
|
||||
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*args,
|
||||
invoice=None,
|
||||
**kwargs
|
||||
):
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
self.apply_style()
|
||||
self.invoice = invoice
|
||||
self.fields["item"].queryset = Item.objects.all()
|
||||
self.fields["time_entry"].queryset = TimeEntry.objects.none()
|
||||
self.fields["expense"].queryset = Expense.objects.none()
|
||||
|
||||
|
||||
if invoice and invoice.project:
|
||||
|
||||
|
||||
self.fields["source_type"].choices = [
|
||||
("item", "Artikel"),
|
||||
("time", "Zeiterfassung"),
|
||||
("expense", "Ausgabe"),
|
||||
]
|
||||
|
||||
|
||||
self.fields["time_entry"].queryset = TimeEntry.objects.filter(
|
||||
project=invoice.project,end__isnull=False
|
||||
)
|
||||
|
||||
|
||||
self.fields["expense"].queryset = Expense.objects.filter(
|
||||
project=invoice.project
|
||||
)
|
||||
|
||||
else:
|
||||
self.fields["source_type"].choices = [
|
||||
("item", "Artikel"),
|
||||
]
|
||||
|
||||
self.fields["item"].widget.attrs["class"] += " source-item"
|
||||
self.fields["time_entry"].widget.attrs["class"] += " source-time"
|
||||
self.fields["expense"].widget.attrs["class"] += " source-expense"
|
||||
|
||||
def save(self, commit=True):
|
||||
|
||||
obj = super().save(commit=False)
|
||||
|
||||
|
||||
source = self.cleaned_data.get(
|
||||
"source_type"
|
||||
)
|
||||
|
||||
|
||||
# -------------------------
|
||||
# ARTIKEL
|
||||
# -------------------------
|
||||
|
||||
if source == "item":
|
||||
|
||||
item = self.cleaned_data["item"]
|
||||
|
||||
obj.item = item
|
||||
obj.time_entry = None
|
||||
obj.expense = None
|
||||
|
||||
obj.description = self.cleaned_data["description"]
|
||||
obj.unit = self.cleaned_data["unit"]
|
||||
obj.unit_price_net = self.cleaned_data["unit_price_net"]
|
||||
obj.unit_tax_rate = self.cleaned_data["unit_tax_rate"]
|
||||
|
||||
|
||||
|
||||
# -------------------------
|
||||
# ZEITERFASSUNG
|
||||
# -------------------------
|
||||
|
||||
elif source == "time":
|
||||
|
||||
entry = self.cleaned_data["time_entry"]
|
||||
|
||||
obj.item = None
|
||||
obj.time_entry = entry
|
||||
obj.expense = None
|
||||
|
||||
|
||||
obj.description = self.cleaned_data["description"]
|
||||
obj.unit = self.cleaned_data["unit"]
|
||||
obj.unit_price_net = self.cleaned_data["unit_price_net"]
|
||||
obj.unit_tax_rate = self.cleaned_data["unit_tax_rate"]
|
||||
|
||||
|
||||
|
||||
# -------------------------
|
||||
# AUSGABE
|
||||
# -------------------------
|
||||
|
||||
elif source == "expense":
|
||||
|
||||
expense = self.cleaned_data["expense"]
|
||||
|
||||
obj.item = None
|
||||
obj.time_entry = None
|
||||
obj.expense = expense
|
||||
|
||||
|
||||
obj.description = self.cleaned_data["description"]
|
||||
obj.unit = self.cleaned_data["unit"]
|
||||
obj.unit_price_net = self.cleaned_data["unit_price_net"]
|
||||
obj.unit_tax_rate = self.cleaned_data["unit_tax_rate"]
|
||||
|
||||
|
||||
|
||||
if commit:
|
||||
obj.save()
|
||||
|
||||
|
||||
return obj
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class OfferForm(BaseForm):
|
||||
|
||||
contact = forms.ModelChoiceField(
|
||||
queryset=CustomerContact.objects.none(),
|
||||
label="Ansprechpartner",
|
||||
required=True
|
||||
)
|
||||
|
||||
location = forms.ModelChoiceField(
|
||||
queryset=CustomerLocation.objects.none(),
|
||||
label="Standort",
|
||||
required=True
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = Offer
|
||||
fields = [
|
||||
"customer",
|
||||
"contact",
|
||||
"location",
|
||||
"issue_date",
|
||||
"due_date",
|
||||
"note",
|
||||
]
|
||||
|
||||
widgets = {
|
||||
"issue_date": forms.DateInput(attrs={"type": "date"}),
|
||||
"due_date": forms.DateInput(attrs={"type": "date"}),
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.apply_style()
|
||||
|
||||
customer_id = (
|
||||
self.data.get("customer")
|
||||
or getattr(self.instance, "customer_id", None)
|
||||
)
|
||||
|
||||
if customer_id:
|
||||
self.fields["contact"].queryset = CustomerContact.objects.filter(customer_id=customer_id)
|
||||
self.fields["location"].queryset = CustomerLocation.objects.filter(customer_id=customer_id)
|
||||
else:
|
||||
self.fields["contact"].queryset = CustomerContact.objects.none()
|
||||
self.fields["location"].queryset = CustomerLocation.objects.none()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class OfferItemForm(BaseForm):
|
||||
|
||||
class Meta:
|
||||
model = OfferItem
|
||||
|
||||
fields = [
|
||||
"item",
|
||||
"description",
|
||||
"quantity",
|
||||
"unit",
|
||||
"unit_price_net",
|
||||
"unit_tax_rate",
|
||||
]
|
||||
|
||||
widgets = {
|
||||
"quantity": forms.NumberInput(
|
||||
attrs={"step": "1.00"}
|
||||
),
|
||||
"unit_price_net": forms.NumberInput(
|
||||
attrs={"step": "1.00"}
|
||||
),
|
||||
"unit_tax_rate": forms.NumberInput(
|
||||
attrs={"step": "1.00"}
|
||||
),
|
||||
}
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*args,
|
||||
offer=None,
|
||||
**kwargs
|
||||
):
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
self.apply_style()
|
||||
|
||||
self.offer = offer
|
||||
|
||||
self.fields["item"].queryset = (
|
||||
Item.objects.all()
|
||||
)
|
||||
|
||||
def save(self, commit=True):
|
||||
|
||||
obj = super().save(commit=False)
|
||||
|
||||
item = self.cleaned_data.get("item")
|
||||
|
||||
if item:
|
||||
obj.item = item
|
||||
|
||||
if commit:
|
||||
obj.save()
|
||||
|
||||
return obj
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class ReminderForm(BaseForm):
|
||||
|
||||
class Meta:
|
||||
model = Reminder
|
||||
fields = [
|
||||
"invoice",
|
||||
"issue_date",
|
||||
"due_date",
|
||||
"fee",
|
||||
"note",
|
||||
]
|
||||
|
||||
widgets = {
|
||||
"issue_date": forms.DateInput(attrs={"type": "date"}),
|
||||
"due_date": forms.DateInput(attrs={"type": "date"}),
|
||||
}
|
||||
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
|
||||
possible_invoices = []
|
||||
|
||||
|
||||
invoices = Invoice.objects.filter(
|
||||
status=Invoice.Status.OVERDUE,
|
||||
due_date__lt=timezone.now().date(),
|
||||
).prefetch_related(
|
||||
"reminders"
|
||||
)
|
||||
|
||||
|
||||
for invoice in invoices:
|
||||
|
||||
reminders = invoice.reminders.exclude(
|
||||
status=Reminder.Status.CANCELED
|
||||
).order_by("-level")
|
||||
|
||||
|
||||
# Keine Mahnung vorhanden
|
||||
if not reminders.exists():
|
||||
possible_invoices.append(invoice)
|
||||
continue
|
||||
|
||||
|
||||
last_reminder = reminders.first()
|
||||
|
||||
|
||||
# Nur nach expired möglich
|
||||
if last_reminder.status != Reminder.Status.EXPIRED:
|
||||
continue
|
||||
|
||||
|
||||
# Maximal 3 Mahnungen
|
||||
if last_reminder.level >= 3:
|
||||
continue
|
||||
|
||||
|
||||
possible_invoices.append(invoice)
|
||||
|
||||
|
||||
self.fields["invoice"].queryset = Invoice.objects.filter(
|
||||
id__in=[i.id for i in possible_invoices]
|
||||
).order_by("due_date")
|
||||
|
||||
|
||||
self.apply_style()
|
||||
Reference in New Issue
Block a user