134 lines
5.5 KiB
Python
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" |