P2-2部署尝试+compose通配符修复 / D2收尾(唯一单号+前后断言+H5回归17过) / P2-1 StorefrontAdmin真分页 / 后端511+PG4

This commit is contained in:
seagull
2026-09-13 00:25:50 +08:00
parent eef7be7258
commit e0e1430e8d
10 changed files with 319 additions and 33 deletions
+16 -4
View File
@@ -228,18 +228,30 @@ async def my_orders(request):
@api_view(["GET"])
async def admin_orders(request):
"""内部:商城订单列表(默认只看待确认)。"""
"""内部:商城订单列表(默认只看待确认,支持 page/page_size 分页)。"""
tenant = await _tenant(request)
status_filter = request.query_params.get("status", "submitted")
try:
page = max(int(request.query_params.get("page", 1)), 1)
except (TypeError, ValueError):
page = 1
try:
page_size = int(request.query_params.get("page_size", 20))
except (TypeError, ValueError):
page_size = 20
page_size = min(max(page_size, 1), 200)
def _list():
qs = StorefrontOrder.objects.filter(tenant=tenant).select_related("customer")
if status_filter and status_filter != "all":
qs = qs.filter(status=status_filter)
return list(qs.prefetch_related("lines__product").order_by("-created_at")[:100])
total = qs.count()
rows = list(qs.prefetch_related("lines__product")
.order_by("-created_at")[(page - 1) * page_size:page * page_size])
return total, rows
orders = await sync_to_async(_list)()
return Response({"results": [
total, orders = await sync_to_async(_list)()
return Response({"count": total, "results": [
{
"id": o.id, "order_no": o.order_no, "status": o.status,
"status_name": o.get_status_display(),
+3 -2
View File
@@ -8,7 +8,8 @@ services:
environment:
DJANGO_SETTINGS_MODULE: config.settings.prod
DJANGO_SECRET_KEY: ${DJANGO_SECRET_KEY:?required}
DJANGO_ALLOWED_HOSTS: "*"
# 生产禁通配符:显式域名由部署者传入,与 prod.py 的空值/通配符双门禁一致
DJANGO_ALLOWED_HOSTS: ${DJANGO_ALLOWED_HOSTS:?required}
DATABASE_URL: postgres://dealerhub:${POSTGRES_PASSWORD}@pg-main:5432/dealerhub
REDIS_URL: redis://dsp-redis:6379/2
GRANIAN_WORKERS: "4"
@@ -32,7 +33,7 @@ services:
environment:
DJANGO_SETTINGS_MODULE: config.settings.prod
DJANGO_SECRET_KEY: ${DJANGO_SECRET_KEY:?required}
DJANGO_ALLOWED_HOSTS: "*"
DJANGO_ALLOWED_HOSTS: ${DJANGO_ALLOWED_HOSTS:?required}
DATABASE_URL: postgres://dealerhub:${POSTGRES_PASSWORD}@pg-main:5432/dealerhub
REDIS_URL: redis://dsp-redis:6379/2
TASK_BROKER: redis
+29 -5
View File
@@ -13,6 +13,12 @@ import urllib.request
BASE = "http://127.0.0.1:18099"
PAGE = "http://127.0.0.1:15173/static/#/salesman"
# D2收尾:残留隔离 —— 每次运行用时间戳唯一收款单号 + 前后计数断言,
# 不再依赖固定 SMH50002(重复跑会撞唯一约束),且不删单(过账有副作用)。
import time as _time
RUN_TAG = _time.strftime("%m%d%H%M%S")
RECEIPT_NO = f"SMH{ RUN_TAG }"
def api(method, path, token=None, tenant="default", body=None):
req = urllib.request.Request(
@@ -47,6 +53,15 @@ async def main():
s, custs = api("GET", "/api/v1/partner/customers/?page_size=200",
token=token)
assert s == 200 and custs["count"] >= 1, f"customers: {s}"
# 前后计数基线:验证前后差值断言(残留隔离,不删单)
s, _b0 = api("GET", "/api/v1/sales/bills/?page_size=1", token=token)
assert s == 200, f"bills baseline: {s}"
bills_before = _b0["count"]
s, _r0 = api("GET", "/api/v1/finance/receipts/?page_size=1", token=token)
assert s == 200, f"receipts baseline: {s}"
receipts_before = _r0["count"]
print(f"[pre] baseline bills={bills_before} receipts={receipts_before} "
f"run_tag={RUN_TAG} receipt_no={RECEIPT_NO}")
s, whs = api("GET", "/api/v1/inventory/warehouses/?page_size=200",
token=token)
assert s == 200 and whs["count"] >= 1, f"warehouses: {s}"
@@ -162,7 +177,7 @@ async def main():
# 关掉可能残留的下拉浮层后再填单号(Esc 关闭 popper)
await page.keyboard.press("Escape")
await page.wait_for_timeout(400)
bill_no = "SMH50002"
bill_no = RECEIPT_NO
await page.locator("#pane-receipt input[placeholder]").nth(0).scroll_into_view_if_needed()
await page.locator("#pane-receipt input[placeholder]").nth(0).fill(bill_no)
amt_input = page.locator("#pane-receipt .el-input-number input")
@@ -187,12 +202,21 @@ async def main():
assert latest and latest["state"] == "confirmed", \
f"expected confirmed bill, got {latest}"
s, found = api("GET", "/api/v1/finance/receipts/?page_size=50&search=SMH50002",
s, found = api("GET", f"/api/v1/finance/receipts/?page_size=50&search={RECEIPT_NO}",
token=token)
assert s == 200, f"receipts: {s}"
hit = [r for r in found["results"] if r["bill_no"] == "SMH50002"]
assert hit, f"receipt SMH50002 not found: {[r['bill_no'] for r in found['results'][:5]]}"
print(f"[9] receipt SMH50002 ok amount={hit[0]['amount']}")
hit = [r for r in found["results"] if r["bill_no"] == RECEIPT_NO]
assert hit, f"receipt {RECEIPT_NO} not found: {[r['bill_no'] for r in found['results'][:5]]}"
print(f"[9] receipt {RECEIPT_NO} ok amount={hit[0]['amount']}")
# 残留隔离断言:本次恰好新增 1 单 + 1 收款(可重复跑,不删单)
s, _b1 = api("GET", "/api/v1/sales/bills/?page_size=1", token=token)
assert s == 200 and _b1["count"] == bills_before + 1, \
f"bills delta: before={bills_before} after={_b1['count']}"
s, _r1 = api("GET", "/api/v1/finance/receipts/?page_size=1", token=token)
assert s == 200 and _r1["count"] == receipts_before + 1, \
f"receipts delta: before={receipts_before} after={_r1['count']}"
print(f"[9b] delta ok: bills {bills_before}->{_b1['count']}, "
f"receipts {receipts_before}->{_r1['count']}")
s, debts = api("GET", "/api/v1/finance/receivables/?page_size=50",
token=token)
+31
View File
@@ -389,6 +389,37 @@ def test_admin_orders_list_default_submitted(db, auth_client, pro_plan, tenant,
assert orders[0]["id"] == o1.id
def test_admin_orders_pagination(db, auth_client, pro_plan, tenant, account,
products, granted, warehouse):
"""P2-1:admin_orders 支持 page/page_size 翻页,count 为过滤后总数。"""
ids = []
for _ in range(3):
o = sf_services.submit_order(
account.customer,
lines=[{"product_id": products["P001"].id, "quantity": 1}],
)
ids.append(o.id)
p1 = auth_client.get(
"/api/v1/storefront/admin/orders/",
{"status": "submitted", "page": 1, "page_size": 2},
)
assert p1.status_code == 200, p1.content
b1 = p1.json()
assert b1["count"] == 3
assert len(b1["results"]) == 2
p2 = auth_client.get(
"/api/v1/storefront/admin/orders/",
{"status": "submitted", "page": 2, "page_size": 2},
)
assert p2.status_code == 200, p2.content
b2 = p2.json()
assert b2["count"] == 3
assert len(b2["results"]) == 1
# 两页无重叠
got = {r["id"] for r in b1["results"]} | {r["id"] for r in b2["results"]}
assert got == set(ids)
def test_admin_confirm_twice_rejected(db, auth_client, pro_plan, tenant, account,
products, granted, warehouse):
order = sf_services.submit_order(