38240-vm/core/models.py
2026-02-06 11:27:38 +00:00

134 lines
5.5 KiB
Python

from django.db import models
from django.utils import timezone
class Category(models.Model):
name = models.CharField(max_length=100, verbose_name="Nama Kategori")
description = models.TextField(blank=True, verbose_name="Deskripsi")
def __str__(self):
return self.name
class Meta:
verbose_name_plural = "Kategori"
verbose_name = "Kategori"
class Supplier(models.Model):
name = models.CharField(max_length=255, verbose_name="Nama Supplier")
contact_person = models.CharField(max_length=100, blank=True, verbose_name="Kontak Person")
phone = models.CharField(max_length=20, blank=True, verbose_name="Telepon")
address = models.TextField(blank=True, verbose_name="Alamat")
def __str__(self):
return self.name
class Meta:
verbose_name_plural = "Supplier"
verbose_name = "Supplier"
class Medicine(models.Model):
UNIT_CHOICES = [
('Tablet', 'Tablet'),
('Kapsul', 'Kapsul'),
('Botol', 'Botol'),
('Strip', 'Strip'),
('Pcs', 'Pcs'),
('Box', 'Box'),
]
name = models.CharField(max_length=255, verbose_name="Nama Barang")
category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name='medicines', verbose_name="Kategori")
sku = models.CharField(max_length=50, unique=True, verbose_name="SKU/Kode")
unit = models.CharField(max_length=20, choices=UNIT_CHOICES, default='Tablet', verbose_name="Satuan")
min_stock = models.IntegerField(default=10, verbose_name="Stok Minimal")
main_supplier = models.ForeignKey(Supplier, on_delete=models.SET_NULL, null=True, blank=True, related_name='primary_medicines', verbose_name="Supplier Utama")
alternative_supplier = models.ForeignKey(Supplier, on_delete=models.SET_NULL, null=True, blank=True, related_name='alternative_medicines', verbose_name="Supplier Alternatif")
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.name
@property
def total_stock(self):
return sum(batch.quantity for batch in self.batches.all())
@property
def status(self):
total = self.total_stock
if total <= 0:
return "Habis"
if total <= self.min_stock:
return "Stok Menipis"
return "Tersedia"
class Meta:
verbose_name_plural = "Barang/Obat"
verbose_name = "Barang/Obat"
class Faktur(models.Model):
FAKTUR_TYPE_CHOICES = [
('MASUK', 'Faktur Masuk (Supplier)'),
('KELUAR', 'Faktur Keluar'),
]
faktur_number = models.CharField(max_length=100, unique=True, verbose_name="Nomor Faktur")
supplier = models.ForeignKey(Supplier, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="Supplier")
date = models.DateField(default=timezone.now, verbose_name="Tanggal")
faktur_type = models.CharField(max_length=10, choices=FAKTUR_TYPE_CHOICES, default='MASUK', verbose_name="Tipe Faktur")
notes = models.TextField(blank=True, verbose_name="Catatan")
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.faktur_number
class Meta:
verbose_name_plural = "Faktur"
verbose_name = "Faktur"
class Batch(models.Model):
medicine = models.ForeignKey(Medicine, on_delete=models.CASCADE, related_name='batches', verbose_name="Barang")
faktur = models.ForeignKey(Faktur, on_delete=models.SET_NULL, null=True, blank=True, related_name='batches', verbose_name="Faktur")
batch_number = models.CharField(max_length=100, verbose_name="Nomor Batch/Lot")
expiry_date = models.DateField(verbose_name="Tanggal Kadaluarsa")
quantity = models.IntegerField(default=0, verbose_name="Jumlah Stok")
buying_price = models.DecimalField(max_digits=12, decimal_places=2, verbose_name="Harga Beli")
selling_price = models.DecimalField(max_digits=12, decimal_places=2, verbose_name="Harga Jual")
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f"{self.medicine.name} - {self.batch_number}"
@property
def is_expired(self):
return self.expiry_date <= timezone.now().date()
@property
def is_near_expiry(self):
today = timezone.now().date()
diff = self.expiry_date - today
return 0 < diff.days <= 90 # 3 months
class Meta:
verbose_name_plural = "Batch Barang"
verbose_name = "Batch Barang"
class StockTransaction(models.Model):
TRANSACTION_TYPES = [
('IN', 'Barang Masuk'),
('OUT', 'Barang Keluar'),
('ADJ', 'Penyesuaian'),
]
medicine = models.ForeignKey(Medicine, on_delete=models.CASCADE, verbose_name="Barang")
batch = models.ForeignKey(Batch, on_delete=models.SET_NULL, null=True, blank=True, related_name='transactions', verbose_name="Batch")
faktur = models.ForeignKey(Faktur, on_delete=models.SET_NULL, null=True, blank=True, related_name='transactions', verbose_name="Faktur")
transaction_type = models.CharField(max_length=3, choices=TRANSACTION_TYPES, verbose_name="Tipe Transaksi")
quantity = models.IntegerField(verbose_name="Jumlah")
note = models.TextField(blank=True, verbose_name="Keterangan")
created_at = models.DateTimeField(auto_now_add=True, verbose_name="Waktu")
def __str__(self):
return f"{self.get_transaction_type_display()} - {self.medicine.name} ({self.quantity})"
class Meta:
verbose_name_plural = "Transaksi Stok"
verbose_name = "Transaksi Stok"