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("تعداد انتقال باید بیشتر از صفر باشد.")