Files

71 lines
2.7 KiB
Python

"""inventory async ViewSets。
库存账面与流水是只读对外接口(写入走 services);
仓库可增删改。
"""
from adrf.viewsets import ModelViewSet, ReadOnlyModelViewSet
from datetime import timedelta
from django.utils import timezone
from apps.core.viewset import BaseTenantViewSet
from apps.core.viewset import StandardAsyncPagination
from .models import Warehouse, Stock, StockBatch, StockMovement
from .serializers import WarehouseSerializer, StockSerializer, StockMovementSerializer, StockBatchSerializer
class WarehouseViewSet(BaseTenantViewSet):
model = Warehouse
serializer_class = WarehouseSerializer
search_fields = ["code", "name"]
class StockViewSet(BaseTenantViewSet):
model = Stock
serializer_class = StockSerializer
search_fields = ["product__code", "product__name", "warehouse__code"]
http_method_names = ["get", "head", "options"] # 只读
select_related_fields = ("product", "warehouse", "product__base_unit")
class StockMovementViewSet(BaseTenantViewSet):
model = StockMovement
serializer_class = StockMovementSerializer
search_fields = ["product__code", "product__name", "source_ref"]
http_method_names = ["get", "head", "options"] # 只读
select_related_fields = ("product", "warehouse")
class StockBatchViewSet(BaseTenantViewSet):
"""批次库存(只读;写入走 inbound/outbound 服务)。"""
model = StockBatch
serializer_class = StockBatchSerializer
search_fields = ["batch_no", "product__code", "product__name", "warehouse__code"]
http_method_names = ["get", "head", "options"] # 只读
select_related_fields = ("product", "warehouse", "product__base_unit")
async def get_queryset(self):
qs = await super().get_queryset()
# 支持按 product / warehouse 过滤,且默认只看有量批次
product_id = self.request.query_params.get("product")
warehouse_id = self.request.query_params.get("warehouse")
in_stock = self.request.query_params.get("in_stock", "")
near_expiry = self.request.query_params.get("near_expiry", "")
expiry_days = self.request.query_params.get("expiry_days", "30")
if product_id:
qs = qs.filter(product_id=product_id)
if warehouse_id:
qs = qs.filter(warehouse_id=warehouse_id)
if in_stock in ("1", "true", "True"):
qs = qs.filter(on_hand__gt=0)
if near_expiry in ("1", "true", "True"):
try:
days = max(0, min(int(expiry_days), 3650))
except (TypeError, ValueError):
days = 30
cutoff = timezone.localdate() + timedelta(days=days)
qs = qs.filter(expiry_date__isnull=False, expiry_date__lte=cutoff)
return qs