from rest_framework.exceptions import ParseError from django.db import transaction from apps.utils.viewsets import CustomModelViewSet from apps.wf.mixins import TicketMixin from apps.wf.models import Ticket from apps.mpr.models import ( PurchaseRequisition, PurchaseRequisitionItem, WarehouseEntry, WarehouseEntryItem, WarehouseStock, MaterialRequisition, MaterialRequisitionItem, ) from apps.mpr.serializers import ( PurchaseRequisitionListSerializer, PurchaseRequisitionDetailSerializer, PurchaseRequisitionCreateSerializer, PurchaseRequisitionItemSerializer, WarehouseEntryListSerializer, WarehouseEntryDetailSerializer, WarehouseEntryCreateSerializer, WarehouseEntryItemSerializer, WarehouseStockSerializer, MaterialRequisitionListSerializer, MaterialRequisitionDetailSerializer, MaterialRequisitionCreateSerializer, MaterialRequisitionItemSerializer, ) from apps.mpr.filters import ( PurchaseRequisitionFilter, WarehouseEntryFilter, WarehouseStockFilter, MaterialRequisitionFilter, ) class PurchaseRequisitionViewSet(TicketMixin, CustomModelViewSet): """ 物资申购单 """ queryset = PurchaseRequisition.objects.all() serializer_class = PurchaseRequisitionListSerializer retrieve_serializer_class = PurchaseRequisitionDetailSerializer create_serializer_class = PurchaseRequisitionCreateSerializer update_serializer_class = PurchaseRequisitionCreateSerializer select_related_fields = ['create_by', 'belong_dept', 'ticket', 'ticket__state'] search_fields = ['number', 'create_by__name'] filterset_class = PurchaseRequisitionFilter ordering = '-create_time' workflow_key = 'wf_mpr' def gen_other_ticket_data(self, instance): dept_name = instance.belong_dept.name if instance.belong_dept else '' return {"dept_name": dept_name} class PurchaseRequisitionItemViewSet(CustomModelViewSet): """ 物资申购明细 """ queryset = PurchaseRequisitionItem.objects.all() serializer_class = PurchaseRequisitionItemSerializer filterset_fields = ['requisition'] ordering = 'create_time' class WarehouseEntryViewSet(TicketMixin, CustomModelViewSet): """ 仓库入库单 """ queryset = WarehouseEntry.objects.all() serializer_class = WarehouseEntryListSerializer retrieve_serializer_class = WarehouseEntryDetailSerializer create_serializer_class = WarehouseEntryCreateSerializer update_serializer_class = WarehouseEntryCreateSerializer select_related_fields = ['create_by', 'belong_dept', 'warehouse', 'ticket', 'ticket__state'] search_fields = ['number', 'create_by__name', 'warehouse__name'] filterset_class = WarehouseEntryFilter ordering = '-create_time' workflow_key = 'wf_warehouse_entry' def gen_other_ticket_data(self, instance): return {"warehouse_name": instance.warehouse.name if instance.warehouse else ''} @staticmethod def approve_entry(ticket: Ticket, transition, new_ticket_data: dict): """审批通过后,将入库明细写入物料库存""" entry: WarehouseEntry = WarehouseEntry.objects.get(ticket=ticket) if WarehouseStock.objects.filter(entry=entry).exists(): raise ParseError('该入库单已入库,不可重复操作') for item in entry.items.all(): WarehouseStock.objects.create( warehouse=entry.warehouse, entry=entry, entry_number=entry.number, entry_date=entry.entry_date, entry_type=entry.entry_type, entry_method=entry.entry_method, name=item.name, spec=item.spec, unit=item.unit, quantity=item.quantity, unit_price=item.unit_price, amount=item.amount, supplier_name=item.supplier_name, invoice_received=item.invoice_received, ) class WarehouseEntryItemViewSet(CustomModelViewSet): """ 入库明细 """ queryset = WarehouseEntryItem.objects.all() serializer_class = WarehouseEntryItemSerializer filterset_fields = ['entry'] ordering = 'create_time' class WarehouseStockViewSet(CustomModelViewSet): """ 物料库存 """ queryset = WarehouseStock.objects.all() serializer_class = WarehouseStockSerializer select_related_fields = ['warehouse', 'entry'] search_fields = ['name', 'spec', 'supplier_name', 'entry_number'] filterset_class = WarehouseStockFilter ordering = '-create_time' perms_map = {'get': '*', 'post': 'warehouse_stock.create', 'put': 'warehouse_stock.update', 'delete': 'warehouse_stock.delete'} class MaterialRequisitionViewSet(TicketMixin, CustomModelViewSet): """ 物资领用单 """ queryset = MaterialRequisition.objects.all() serializer_class = MaterialRequisitionListSerializer retrieve_serializer_class = MaterialRequisitionDetailSerializer create_serializer_class = MaterialRequisitionCreateSerializer update_serializer_class = MaterialRequisitionCreateSerializer select_related_fields = ['create_by', 'belong_dept', 'ticket', 'ticket__state'] search_fields = ['number', 'create_by__name', 'collector'] filterset_class = MaterialRequisitionFilter ordering = '-create_time' workflow_key = 'wf_material_requis' def gen_other_ticket_data(self, instance): dept_name = instance.belong_dept.name if instance.belong_dept else '' return {"dept_name": dept_name, "collector": instance.collector or ''} @staticmethod def approve_requisition(ticket: Ticket, transition, new_ticket_data: dict): """审批通过后,将库存物品状态改为已领用""" req = MaterialRequisition.objects.get(ticket=ticket) for item in req.items.filter(is_stock_item=True, stock__isnull=False): stock = WarehouseStock.objects.select_for_update().get(id=item.stock_id) stock.status = 'requisitioned' stock.save(update_fields=['status']) @staticmethod def reject_requisition(ticket: Ticket, transition, new_ticket_data: dict): """审批拒绝后,恢复库存数量和状态""" from apps.mpr.serializers import MaterialRequisitionCreateSerializer req = MaterialRequisition.objects.get(ticket=ticket) MaterialRequisitionCreateSerializer._restore_stock(req) class MaterialRequisitionItemViewSet(CustomModelViewSet): """ 物资领用明细 """ queryset = MaterialRequisitionItem.objects.all() serializer_class = MaterialRequisitionItemSerializer filterset_fields = ['requisition'] ordering = 'create_time'