wendajia/backend/tests/test_refund_records.py

136 lines
6.9 KiB
Python

import csv
import io
from datetime import datetime
import pytest
from sqlalchemy import select
from test_refund_amounts import setup
from app import main
from app.models import (AdminUser, AnswerScreenshot, RefundRecord, RefundRecipient, RefundPaymentAccount,
AskTask, AskQuestion, AskAssignment, AskAssignmentQuestion,
AskAssignmentBatch, AskAssignmentScreenshot, AskAssignmentBatchScreenshot)
def test_answer_confirmation_snapshot_survives_changes_and_deletion(setup):
db, client, owner, _, task = setup
task.shop_name = "测试店铺"
db.commit()
url = f"/api/admin/task-board/{task.id}/confirm-refund"
payer_id = db.scalar(select(RefundPaymentAccount.id))
response = client.post(url, data={"refund_amount": "2.35", "payer_account_id": payer_id, "payer_account": "伪造账户", "alipay_trade_no": "ALI123"})
assert response.status_code == 200, response.text
assert client.post(url, data={"payer_account_id": payer_id}).status_code == 409
rows = client.get("/api/admin/refund-records").json()["data"]
assert rows["total"] == 1 and rows["total_amount_fen"] == 235
row = rows["items"][0]
assert (row["payee_name"], row["payee_account"], row["operator_name"], row["payer_account"], row["alipay_trade_no"]) == ("张三", "buyer@example.com", owner.display_name, "公司账户", "")
recipient = db.scalar(select(RefundRecipient).where(RefundRecipient.target_kind == "answer_submission"))
recipient.payee_name = "修改后姓名"
db.delete(task)
db.commit()
assert client.get("/api/admin/refund-records").json()["data"]["items"][0] == row
def test_refund_snapshot_is_idempotent_when_callback_wins_race(setup):
db, _, owner, _, task = setup
payer = db.scalar(select(RefundPaymentAccount))
first = main._snapshot_refund(
db, task, "answer_submission", owner, payer.name, "ALI-RACE-001"
)
db.commit()
second = main._snapshot_refund(
db, task, "answer_submission", owner, payer.name, "ALI-RACE-001"
)
db.commit()
assert second.id == first.id
assert db.scalars(select(RefundRecord)).all() == [first]
@pytest.mark.parametrize("batched", [True, False])
def test_ask_confirmation_creates_record(setup, batched):
db, client, owner, person, _ = setup
task = AskTask(task_no="TASK-refund", product_link="https://example.com", product_name="商品", shop_name="提问店铺", owner_id=owner.id, status="已发布")
db.add(task)
db.flush()
assignment = AskAssignment(task_id=task.id, user_id=person.id, status="已通过")
question = AskQuestion(task_id=task.id, sequence_no=1, question_text="问题")
db.add_all([assignment, question])
db.flush()
db.add(AskAssignmentQuestion(assignment_id=assignment.id, question_id=question.id, selected=True))
if batched:
record = AskAssignmentBatch(assignment_id=assignment.id, status="approved", selected_question_ids=str(question.id))
db.add(record)
db.flush()
kind, route = "ask_batch", "ask-batches"
else:
record = assignment
kind, route = "ask_assignment", "ask-assignments"
db.add(RefundRecipient(target_kind=kind, target_id=record.id, account="ask@example.com", payee_name="提问人"))
db.commit()
url = f"/api/admin/task-board/{route}/{record.id}/confirm-refund"
payer_id = db.scalar(select(RefundPaymentAccount.id))
owner = db.get(AdminUser, task.owner_id)
owner.refund_payment_account_id = None
db.commit()
assert client.post(url, data={"payer_account_id": payer_id}).status_code == 403
owner.refund_payment_account_id = payer_id
db.commit()
response = client.post(url, data={"payer_account_id": payer_id})
assert response.status_code == 200, response.text
assert client.post(url, data={"payer_account_id": payer_id}).status_code == 409
row = client.get("/api/admin/refund-records").json()["data"]["items"][0]
assert row["amount_fen"] == 50
assert row["payee_name"] == "提问人" and row["order_no"] == "TASK-refund"
def test_available_accounts_and_disabled_account_rejection(setup):
db, client, _, _, task = setup
disabled = RefundPaymentAccount(name="停用账户", alipay_account="disabled@example.com", single_limit_fen=50000, is_active=False)
db.add(disabled)
db.commit()
accounts = client.get("/api/admin/refund-payment-accounts/available")
assert accounts.status_code == 200
assert [item["name"] for item in accounts.json()["data"]] == ["公司账户"]
assert client.get("/api/admin/refund-payment-accounts").status_code == 403
url = f"/api/admin/task-board/{task.id}/confirm-refund"
for account_id in (disabled.id, 99999):
response = client.post(url, data={"payer_account_id": account_id})
assert response.status_code == 400, response.text
assert task.status == "已通过"
assert db.scalar(select(RefundRecord.id)) is None
def test_scope_date_range_pagination_and_export(setup):
db, client, owner, _, _ = setup
owner.dingtalk_dept_id = 10
colleague = AdminUser(username="colleague", display_name="同事", password_hash="x", dingtalk_dept_id=11, dingtalk_dept_path=",10,11,")
stranger = AdminUser(username="stranger", display_name="外部门", password_hash="x", dingtalk_dept_id=20)
db.add_all([colleague, stranger])
db.flush()
for i in range(14):
db.add(RefundRecord(target_kind="answer_submission", target_id=100 + i, owner_id=owner.id if i < 12 else colleague.id if i == 12 else stranger.id,
order_no=f"TASK-{i}", amount_fen=50, operator_name="运营", shop_name="=unsafe",
transferred_at=datetime(2026, 10, 21, 16, 0) if i < 13 else datetime(2026, 10, 22, 16, 0)))
db.commit()
query = "start_date=2026-10-22&end_date=2026-10-22"
page = client.get(f"/api/admin/refund-records?{query}&page=2").json()["data"]
assert len(page["items"]) == 2 and page["total"] == 12 and page["total_amount_fen"] == 600
exported = client.get(f"/api/admin/refund-records/export?{query}")
rows = list(csv.reader(io.StringIO(exported.content.decode("utf-8-sig"))))
assert len(rows) == 14 and rows[-1][5] == "6.00"
assert rows[1][0] == "'=unsafe" and rows[1][1] == "2026-10-22 00:00:00"
owner.role_code = "dept_manager"
db.commit()
assert client.get(f"/api/admin/refund-records?{query}").json()["data"]["total"] == 13
owner.role_code = "super_admin"
db.commit()
assert client.get("/api/admin/refund-records").json()["data"]["total"] == 14
assert client.get(f"/api/admin/refund-records?{query}&q=TASK-13").json()["data"]["total"] == 0
assert client.get("/api/admin/refund-records?q=TASK-13").json()["data"]["total"] == 1
for path in ["/api/admin/refund-records", "/api/admin/refund-records/export"]:
assert client.get(path + "?start_date=wrong").status_code == 400
assert client.get(path + "?start_date=2026-10-23&end_date=2026-10-22").status_code == 400