"""协议列表可显式读取 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()