File: /home/django/apps/cargochains/sales/forms_job_order.bak
# sales/forms_job_order.py
from decimal import Decimal, InvalidOperation
from django import forms
from .job_order_model import JobOrder
from partners.models import Customer # proxy customer yang sudah om buat
class JobOrderForm(forms.ModelForm):
# override field angka jadi CharField supaya bisa pakai format "1.000,00"
total_amount = forms.CharField(required=False)
tax_amount = forms.CharField(required=False)
grand_total = forms.CharField(required=False)
# kurs & total IDR juga kita tampilkan sebagai text (format Indonesia)
kurs_idr = forms.CharField(required=False, label="Kurs IDR")
total_in_idr = forms.CharField(required=False, label="Total (IDR)")
class Meta:
model = JobOrder
fields = "__all__"
# tidak ditampilkan di form:
exclude = ["created", "modified", "is_pph", "pph_amount", "sales_user","number"]
widgets = {
"job_date": forms.DateInput(
attrs={"type": "date", "class": "form-control form-control-sm"}
),
"service": forms.Select(attrs={"class": "form-select form-select-sm"}),
"customer": forms.Select(attrs={"class": "form-select form-select-sm"}),
"cargo_description": forms.TextInput(
attrs={"class": "form-control form-control-sm"}
),
"quantity": forms.NumberInput(
attrs={"class": "form-control form-control-sm", "step": "0.01"}
),
"pickup": forms.TextInput(attrs={"class": "form-control form-control-sm"}),
"delivery": forms.TextInput(attrs={"class": "form-control form-control-sm"}),
"pic": forms.TextInput(attrs={"class": "form-control form-control-sm"}),
"payment_term": forms.Select(attrs={"class": "form-select form-select-sm"}),
"currency": forms.Select(attrs={"class": "form-select form-select-sm"}),
"remarks_internal": forms.Textarea(
attrs={"class": "form-control form-control-sm", "rows": 3}
),
"is_tax": forms.CheckboxInput(attrs={"class": "form-check-input"}),
# angka: text + rata kanan
"total_amount": forms.TextInput(
attrs={"class": "form-control form-control-sm text-end"}
),
"tax_amount": forms.TextInput(
attrs={
"class": "form-control form-control-sm text-end",
"readonly": "readonly",
"tabindex": "-1",
}
),
"grand_total": forms.TextInput(
attrs={"class": "form-control form-control-sm text-end"}
),
# kurs & total IDR
"kurs_idr": forms.TextInput(
attrs={"class": "form-control form-control-sm text-end"}
),
"total_in_idr": forms.TextInput(
attrs={
"class": "form-control form-control-sm text-end",
"readonly": "readonly",
"tabindex": "-1",
}
),
}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# pakai proxy Customer biar dropdown cuma role customer
if "customer" in self.fields:
self.fields["customer"].queryset = Customer.objects.all().order_by("name")
# styling massal (kalau ada field yang belum diset widget-nya)
for name, field in self.fields.items():
w = field.widget
if isinstance(w, forms.CheckboxInput):
w.attrs.setdefault("class", "form-check-input")
elif isinstance(w, forms.Select):
w.attrs.setdefault("class", "form-select form-select-sm")
else:
if "form-control" not in w.attrs.get("class", ""):
css = "form-control form-control-sm"
if name in ("total_amount", "tax_amount", "grand_total",
"kurs_idr", "total_in_idr"):
css += " text-end"
w.attrs.setdefault("class", css)
# default angka "0,00" untuk form baru (create)
if not self.instance.pk and not self.is_bound:
self.initial.setdefault("total_amount", "0,00")
self.initial.setdefault("tax_amount", "0,00")
self.initial.setdefault("grand_total", "0,00")
self.initial.setdefault("kurs_idr", "0,00")
self.initial.setdefault("total_in_idr", "0,00")
# ============================ helper angka ============================
def _parse_id_decimal(self, value_str, field_label="angka"):
"""
Ubah string format Indonesia '1.000.000,00' -> Decimal('1000000.00')
Juga aman kalau input '2000000.00' (tanpa koma, dari DB).
"""
if value_str in (None, ""):
return Decimal("0")
s = str(value_str).strip()
s = s.replace(" ", "")
# kalau mengandung koma → anggap format Indonesia
if "," in s:
s = s.replace(".", "").replace(",", ".")
# kalau tidak ada koma → biarkan, '.' dianggap desimal biasa
try:
return Decimal(s)
except InvalidOperation:
raise forms.ValidationError(
f"Format {field_label} tidak valid. Gunakan contoh: 1.000,00"
)
# ============================ clean utama ============================
def clean(self):
cleaned = super().clean()
# 1) TOTAL / TAX / GRAND TOTAL
total_raw = cleaned.get("total_amount") or ""
is_tax = cleaned.get("is_tax") or False
total = self._parse_id_decimal(total_raw, "Total Amount")
if is_tax:
tax = (total * Decimal("0.011")).quantize(Decimal("0.01"))
else:
tax = Decimal("0.00")
grand = (total + tax).quantize(Decimal("0.01"))
cleaned["total_amount"] = total
cleaned["tax_amount"] = tax
cleaned["grand_total"] = grand
# 2) KURS & TOTAL DALAM IDR
currency = cleaned.get("currency")
kurs_raw = cleaned.get("kurs_idr") or ""
if currency and getattr(currency, "code", "").upper() != "IDR":
kurs = self._parse_id_decimal(kurs_raw, "Kurs IDR")
if kurs <= 0:
raise forms.ValidationError("Kurs IDR harus lebih besar dari 0.")
else:
# kalau IDR → kurs 1, dan total_in_idr = grand_total
kurs = Decimal("1.00")
total_in_idr = (grand * kurs).quantize(Decimal("0.01"))
cleaned["kurs_idr"] = kurs
cleaned["total_in_idr"] = total_in_idr
return cleaned