71 lines
2.7 KiB
Python
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
|