Files
zkxw/backend/tests/test_protocol_v2_payment_mode_summary.py
T
zlwuandCursor 476f744ee9 fix(backend): 协议列表从 V2 样本缴费补齐已收金额
自存表导出依赖 paymentSummary.receivedAmount,原先仅汇总 V1
biz_protocol_payment;现对 include_sample_payment_modes 路径补齐
合同额、已收、分期明细与退费,避免已缴/退款列为空。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-11-11 14:15:02 +08:00

219 lines
8.7 KiB
Python

"""协议列表可显式读取 V2 样本方案,其他费用摘要消费者保持原行为。"""
from datetime import datetime
from decimal import Decimal
import pytest
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from app.models.base import Base
from app.models.models import (
BizProtocolPaymentSchedule,
BizProtocolPaymentTransfer,
BizProtocolRefundRecord,
BizProtocolSamplePayment,
)
from app.services.qc_work_order_fee_summary import build_protocol_payment_summaries
@pytest.mark.parametrize('modes,expected,label', [
(['dj'], 'dj', '趸交'),
(['fq', 'fq'], 'fq', '分期'),
(['fgd'], 'fgd', '分改趸'),
(['fq', 'dj'], 'djfq', '趸交+分期'),
(['fgd', 'fq'], 'fq+fgd', '分期+分改趸'),
])
def test_protocol_list_uses_active_tenant_v2_payment_modes(modes, expected, label):
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
with sessionmaker(bind=engine)() as db:
for i, mode in enumerate(modes):
db.add(BizProtocolSamplePayment(id=str(i), collection_protocol_id='p1', sample_code=str(i), pay_mode=mode, tenant_no='tenant-a', del_flag=0))
db.add_all([
BizProtocolSamplePayment(id='deleted', collection_protocol_id='p1', sample_code='deleted', pay_mode='djfq', tenant_no='tenant-a', del_flag=1),
BizProtocolSamplePayment(id='foreign', collection_protocol_id='p1', sample_code='foreign', pay_mode='djfq', tenant_no='tenant-b', del_flag=0),
])
db.commit()
result = build_protocol_payment_summaries(db, ['p1'], 'tenant-a', include_sample_payment_modes=True)
assert result['p1']['payMode'] == expected
assert result['p1']['payModeLabel'] == label
assert build_protocol_payment_summaries(db, ['p1'], 'tenant-a') == {}
engine.dispose()
def test_protocol_list_fills_received_from_v2_sample_transfers():
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
with sessionmaker(bind=engine)() as db:
db.add_all(
[
BizProtocolSamplePayment(
id='sp-dj',
collection_protocol_id='p-v2',
sample_code='S1',
pay_mode='dj',
contract_amount=Decimal('12800'),
tenant_no='tenant-a',
del_flag=0,
),
BizProtocolSamplePayment(
id='sp-fq',
collection_protocol_id='p-v2',
sample_code='S2',
pay_mode='fq',
contract_amount=Decimal('22880'),
tenant_no='tenant-a',
del_flag=0,
),
BizProtocolPaymentSchedule(
id='sch-dj-1',
sample_payment_id='sp-dj',
collection_protocol_id='p-v2',
sample_code='S1',
schedule_no=1,
due_amount=Decimal('12800'),
due_date='20260915',
schedule_status='cleared',
tenant_no='tenant-a',
del_flag=0,
),
BizProtocolPaymentSchedule(
id='sch-fq-1',
sample_payment_id='sp-fq',
collection_protocol_id='p-v2',
sample_code='S2',
schedule_no=1,
due_amount=Decimal('6480'),
due_date='20260915',
schedule_status='cleared',
tenant_no='tenant-a',
del_flag=0,
),
BizProtocolPaymentSchedule(
id='sch-fq-2',
sample_payment_id='sp-fq',
collection_protocol_id='p-v2',
sample_code='S2',
schedule_no=2,
due_amount=Decimal('16400'),
due_date='20261015',
schedule_status='open',
tenant_no='tenant-a',
del_flag=0,
),
BizProtocolPaymentTransfer(
id='tr-dj',
schedule_id='sch-dj-1',
sample_payment_id='sp-dj',
collection_protocol_id='p-v2',
sample_code='S1',
transfer_amount=Decimal('12800'),
transfer_time=datetime(2026, 9, 15, 12, 0, 0),
pay_status='yjf',
tenant_no='tenant-a',
del_flag=0,
),
BizProtocolPaymentTransfer(
id='tr-fq',
schedule_id='sch-fq-1',
sample_payment_id='sp-fq',
collection_protocol_id='p-v2',
sample_code='S2',
transfer_amount=Decimal('6480'),
transfer_time=datetime(2026, 9, 15, 11, 13, 1),
pay_status='yjf',
tenant_no='tenant-a',
del_flag=0,
),
BizProtocolPaymentTransfer(
id='tr-pending',
schedule_id='sch-fq-2',
sample_payment_id='sp-fq',
collection_protocol_id='p-v2',
sample_code='S2',
transfer_amount=None,
transfer_time=None,
pay_status='dfj',
tenant_no='tenant-a',
del_flag=0,
),
]
)
db.commit()
result = build_protocol_payment_summaries(
db, ['p-v2'], 'tenant-a', include_sample_payment_modes=True
)
summary = result['p-v2']
assert summary['payMode'] == 'djfq'
assert summary['contractAmount'] == 35680.0
assert summary['receivedAmount'] == 19280.0
assert summary['pendingAmount'] == 16400.0
details = summary['paymentDetails']
assert len(details) == 3
first = [d for d in details if d['installmentNo'] == 1]
assert sum(float(d['dueAmount'] or 0) for d in first) == 19280.0
assert sum(float(d['transferAmount'] or 0) for d in first) == 19280.0
# 未开启 include 时不补齐 V2 已收(质检费用摘要保持原语义)
plain = build_protocol_payment_summaries(db, ['p-v2'], 'tenant-a')
assert plain['p-v2'].get('receivedAmount') is None
assert plain['p-v2'].get('paymentDetails') == []
engine.dispose()
def test_protocol_list_fills_refund_amount_from_v2_refund_records():
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
with sessionmaker(bind=engine)() as db:
db.add_all(
[
BizProtocolSamplePayment(
id='sp-void',
collection_protocol_id='p-void',
sample_code='S9',
pay_mode='dj',
contract_amount=Decimal('5000'),
tenant_no='tenant-a',
del_flag=0,
),
BizProtocolPaymentSchedule(
id='sch-void',
sample_payment_id='sp-void',
collection_protocol_id='p-void',
sample_code='S9',
schedule_no=1,
due_amount=Decimal('5000'),
due_date='20260918',
schedule_status='cleared',
tenant_no='tenant-a',
del_flag=0,
),
BizProtocolPaymentTransfer(
id='tr-void',
schedule_id='sch-void',
sample_payment_id='sp-void',
collection_protocol_id='p-void',
sample_code='S9',
transfer_amount=Decimal('5000'),
transfer_time=datetime(2026, 9, 18, 14, 55, 4),
pay_status='yjf',
tenant_no='tenant-a',
del_flag=0,
),
BizProtocolRefundRecord(
id='rf-void',
collection_protocol_id='p-void',
refund_amount=Decimal('5000'),
refund_time=datetime(2026, 9, 19, 10, 0, 0),
tenant_no='tenant-a',
del_flag=0,
),
]
)
db.commit()
summary = build_protocol_payment_summaries(
db, ['p-void'], 'tenant-a', include_sample_payment_modes=True
)['p-void']
assert summary['receivedAmount'] == 5000.0
assert summary['refundAmount'] == 5000.0
engine.dispose()