This commit is contained in:
javad committed 2026-10-09 20:02:36 +03:30
1 parent 6f36db63a1
commit 250cdbab7f
42 files changed
+96363 -11699

No files matched your search

+148
View File
@@ -0,0 +1,148 @@
from django.core.exceptions import ValidationError
from django.db import models
from django.contrib.auth.models import User
class StoreRoom(models.Model):
class Meta:
permissions = [
("ViewStore", "ViewStore"),
("AddStore", "AddStore"),
("EditStore", "EditStore"),
("DelStore", "DelStore")
]
store_name = models.CharField(max_length=200)
user = models.ManyToManyField(User,
blank=True,
verbose_name="دسترسی مشاهده انبار احتمالا",
help_text="از این برای دسترسی مشاهده آن اتبار استفاده می شود"
)
owners = models.ManyToManyField(
User,
through='StoreRoomOwner', # کلید حل مشکل بدون شکستن کدهای قبلی
blank=True,
related_name="owned_storerooms",
verbose_name="مالکین انبار در فاکتور و موجودی و...",
help_text="این کاربران اگر فاکتور بزنند از این انبار کسر می‌گردد"
)
def __str__(self):
return self.store_name
class StoreRoomOwner(models.Model):
"""
این جدول واسط، پشت صحنه قرار می‌گیرد تا فقط قانون مالکیت را مدیریت کند.
کدهای دیگر پروژه اصلاً نیازی ندارند مستقیم با این جدول درگیر شوند.
"""
storeroom = models.ForeignKey(StoreRoom, on_delete=models.CASCADE)
# OneToOneField تضمین می‌کند یک کاربر نمی‌تواند در این جدول (و هیچ انبار دیگری) تکرار شود
user = models.OneToOneField(
User,
on_delete=models.CASCADE,
error_messages={
'unique': 'این کاربر در حال حاضر مالک انبار دیگری است.'
}
)
class ProductStockHistory(models.Model):
store_room = models.ForeignKey(StoreRoom, on_delete=models.CASCADE, related_name='stock_histories')
product = models.ForeignKey('Product', on_delete=models.CASCADE, related_name='stock_histories')
quantity_changed = models.IntegerField(help_text="مقدار تغییر یافته (مثبت برای ورود، منفی برای خروج)")
current_stock = models.IntegerField(help_text="موجودی کل انبار در این لحظه")
created_at = models.DateTimeField(auto_now_add=True)
desc = models.CharField(max_length=255, blank=True, null=True)
class Meta:
ordering = ['-created_at']
def __str__(self):
return f"{self.product.product_name} in {self.store_room.store_name} - Stock: {self.current_stock}"
class StoreTransferRequest(models.Model):
class Status(models.TextChoices):
PENDING = 'PENDING', 'در انتظار تایید انبار مقصد'
APPROVED = 'APPROVED', 'تایید شده و منتقل شده'
REJECTED = 'REJECTED', 'رد شده توسط انبار مقصد'
CANCELED = 'CANCELED', 'انصراف توسط مبدا'
source_store = models.ForeignKey(
'StoreRoom',
on_delete=models.PROTECT,
related_name='outgoing_transfers',
verbose_name="انبار مبدا"
)
target_store = models.ForeignKey(
'StoreRoom',
on_delete=models.PROTECT,
related_name='incoming_transfers',
verbose_name="انبار مقصد"
)
product = models.ForeignKey(
'Product',
on_delete=models.PROTECT,
verbose_name="کالا"
)
quantity = models.PositiveIntegerField(verbose_name="تعداد انتقال")
status = models.CharField(
max_length=15,
choices=Status.choices,
default=Status.PENDING,
db_index=True,
verbose_name="وضعیت"
)
desc = models.CharField(max_length=500, blank=True, null=True, verbose_name="توضیحات درخواست")
rejection_reason = models.CharField(max_length=500, blank=True, null=True, verbose_name="دلیل رد درخواست")
requester = models.ForeignKey(
User,
on_delete=models.PROTECT,
related_name='requested_transfers',
verbose_name="کاربر درخواست‌دهنده"
)
approver = models.ForeignKey(
User,
on_delete=models.PROTECT,
null=True,
blank=True,
related_name='processed_transfers',
verbose_name="کاربر تعیین‌تکلیف‌کننده"
)
created_at = models.DateTimeField(auto_now_add=True, db_index=True, verbose_name="زمان ثبت درخواست")
updated_at = models.DateTimeField(auto_now=True, verbose_name="زمان آخرین به‌روزرسانی")
action_date = models.DateTimeField(null=True, blank=True, db_index=True, verbose_name="زمان تعیین تکلیف")
out_transaction = models.ForeignKey(
'ProductInStore',
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name='transfer_out_ref',
verbose_name="سند خروج انبار مبدا"
)
in_transaction = models.ForeignKey(
'ProductInStore',
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name='transfer_in_ref',
verbose_name="سند ورود انبار مقصد"
)
class Meta:
ordering = ['-created_at']
def __str__(self):
return f"[{self.get_status_display()}] {self.quantity} عدد {self.product.product_name} از {self.source_store.store_name} به {self.target_store.store_name}"
def clean(self):
super().clean()
if self.source_store_id == self.target_store_id:
raise ValidationError("انبار مبدا و مقصد نمی‌توانند یکسان باشند.")
if self.quantity and self.quantity <= 0:
raise ValidationError("تعداد انتقال باید بیشتر از صفر باشد.")