baseline: 批次A-D 成果 + membership 半成品(测试红)

This commit is contained in:
agent
2026-09-11 23:11:35 +08:00
commit b3f3095d53
311 changed files with 40540 additions and 0 deletions
+70
View File
@@ -0,0 +1,70 @@
"""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