feat(backend): persist and return samplePayments for market protocols
Mobile protocol create/update saves v2 per-sample payments; detail includes samplePayments for edit hydration. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
9c61f36db8
commit
be22c37196
2 files changed
+94
No files matched your search
@@ -10,6 +10,7 @@ from sqlalchemy.orm import Session
|
||||
|
||||
from app.core.utils import parse_datetime
|
||||
from app.crud import collection_protocol as cell_crud
|
||||
from app.crud import protocol_sample_payment as psp_crud
|
||||
from app.crud import research_donation as donation_crud
|
||||
from app.models.models import (
|
||||
BizCellSampleType,
|
||||
@@ -772,6 +773,37 @@ def _attach_sample_eta(
|
||||
return sample_dicts
|
||||
|
||||
|
||||
def _persist_sample_payments_if_any(
|
||||
db: Session,
|
||||
*,
|
||||
row: BizCollectionProtocol,
|
||||
body: MarketProtocolBody,
|
||||
ctx: MarketFieldContext,
|
||||
) -> None:
|
||||
"""细胞存储:将 body.sample_payments 写入 v2 按样本缴费方案。"""
|
||||
if body.source != SOURCE_CELL:
|
||||
if body.sample_payments:
|
||||
raise ValueError('科研捐赠不支持样本缴费方案')
|
||||
return
|
||||
if body.sample_payments is None:
|
||||
return
|
||||
version = int(getattr(row, 'payment_model_version', None) or 1)
|
||||
if version < 2:
|
||||
row.payment_model_version = 2
|
||||
db.add(row)
|
||||
db.flush()
|
||||
raw = [
|
||||
p.model_dump(by_alias=True, exclude_none=False) for p in body.sample_payments
|
||||
]
|
||||
psp_crud.save_sample_payments_for_protocol(
|
||||
db,
|
||||
collection_protocol_id=row.id,
|
||||
tenant_no=ctx.tenant_no,
|
||||
user_id=ctx.user_id,
|
||||
sample_payments=raw,
|
||||
)
|
||||
|
||||
|
||||
def _cell_detail(db: Session, row: BizCollectionProtocol, tenant_no: str) -> dict:
|
||||
party = cell_crud.get_party_customer(db, row.id, tenant_no)
|
||||
collection = cell_crud.get_collection_info(db, row.id, tenant_no)
|
||||
@@ -779,6 +811,12 @@ def _cell_detail(db: Session, row: BizCollectionProtocol, tenant_no: str) -> dic
|
||||
payment = cell_crud.get_payment_by_protocol_id(db, row.id, tenant_no)
|
||||
transports = cell_crud.list_sample_transports(db, row.id, tenant_no)
|
||||
transport_by_sample_id = {str(t.sample_id): t for t in transports}
|
||||
version = int(getattr(row, 'payment_model_version', None) or 1)
|
||||
sample_payments = []
|
||||
if version >= 2:
|
||||
sample_payments = psp_crud.get_sample_payments_bundle(
|
||||
db, collection_protocol_id=row.id, tenant_no=tenant_no
|
||||
)
|
||||
detail = {
|
||||
'source': SOURCE_CELL,
|
||||
'basic': cell_crud._protocol_to_dict(row),
|
||||
@@ -791,6 +829,8 @@ def _cell_detail(db: Session, row: BizCollectionProtocol, tenant_no: str) -> dic
|
||||
transport_by_sample_id,
|
||||
),
|
||||
'payment': cell_crud._payment_to_dict(payment) if payment else None,
|
||||
'paymentModelVersion': version,
|
||||
'samplePayments': sample_payments,
|
||||
'attachments': {
|
||||
'protocolAttachments': row.protocol_attachments or '',
|
||||
'consentFormUrls': row.consent_form_urls or '',
|
||||
@@ -1100,11 +1140,14 @@ def create_protocol(
|
||||
create_dept_id=dept_id,
|
||||
commit=False,
|
||||
)
|
||||
_persist_sample_payments_if_any(db, row=row, body=body, ctx=ctx)
|
||||
assert_cell_protocol_access(db, row.id, ctx, user_info=user_info)
|
||||
db.commit()
|
||||
db.refresh(row)
|
||||
return _cell_detail(db, row, ctx.tenant_no)
|
||||
|
||||
if body.sample_payments:
|
||||
raise ValueError('科研捐赠不支持样本缴费方案')
|
||||
data = {
|
||||
'donation_no': body.donation_no or '',
|
||||
'donation_date': body.donation_date,
|
||||
@@ -1280,6 +1323,7 @@ def update_protocol(
|
||||
create_dept_id=dept_id,
|
||||
commit=False,
|
||||
)
|
||||
_persist_sample_payments_if_any(db, row=row, body=body, ctx=ctx)
|
||||
row = assert_cell_protocol_access(
|
||||
db, row.id, ctx, user_info=user_info
|
||||
)
|
||||
|
||||
@@ -23,8 +23,10 @@ from app.models.models import (
|
||||
BizProtocolPaymentDetail,
|
||||
BizProtocolPaymentSchedule,
|
||||
BizProtocolPaymentTransfer,
|
||||
BizProtocolSamplePayment,
|
||||
BizProtocolSample,
|
||||
BizProtocolSampleTransport,
|
||||
BizPresignOrder,
|
||||
BizSampleCode,
|
||||
BizSampleReception,
|
||||
SysPost,
|
||||
@@ -57,8 +59,10 @@ def _session():
|
||||
BizProtocolSampleTransport.__table__,
|
||||
BizProtocolPayment.__table__,
|
||||
BizProtocolPaymentDetail.__table__,
|
||||
BizProtocolSamplePayment.__table__,
|
||||
BizProtocolPaymentSchedule.__table__,
|
||||
BizProtocolPaymentTransfer.__table__,
|
||||
BizPresignOrder.__table__,
|
||||
BizSampleCode.__table__,
|
||||
BizSampleReception.__table__,
|
||||
BizResearchDonation.__table__,
|
||||
@@ -844,6 +848,52 @@ def test_market_protocol_body_accepts_sample_payments():
|
||||
assert body.sample_payments[0].pay_mode == 'dj'
|
||||
|
||||
|
||||
def test_protocol_create_persists_sample_payments():
|
||||
from app.services.market_protocol import create_protocol, get_protocol
|
||||
|
||||
db = _session()
|
||||
_masters(db)
|
||||
body = _body(
|
||||
samplePayments=[
|
||||
{
|
||||
'sampleCode': 'S-001',
|
||||
'payMode': 'dj',
|
||||
'contractAmount': 20000,
|
||||
'lumpSumDeadline': '20261231',
|
||||
'schedules': [
|
||||
{
|
||||
'scheduleNo': 1,
|
||||
'dueAmount': 20000,
|
||||
'dueDate': '20261231',
|
||||
'scheduleStatus': 'open',
|
||||
'transfers': [],
|
||||
}
|
||||
],
|
||||
}
|
||||
]
|
||||
)
|
||||
created = create_protocol(
|
||||
db, body=body, ctx=_ctx('specialist'), user_info=_user()
|
||||
)
|
||||
protocol_id = created['basic']['id']
|
||||
pays = created.get('samplePayments') or []
|
||||
assert len(pays) == 1
|
||||
assert pays[0]['sampleCode'] == 'S-001'
|
||||
assert pays[0]['payMode'] == 'dj'
|
||||
assert float(pays[0]['contractAmount']) == 20000
|
||||
assert str(pays[0]['schedules'][0].get('dueDate') or '').replace('-', '')[:8] == '20261231'
|
||||
|
||||
detail = get_protocol(
|
||||
db,
|
||||
source='cell_storage',
|
||||
protocol_id=protocol_id,
|
||||
ctx=_ctx('specialist'),
|
||||
user_info=_user(),
|
||||
)
|
||||
assert len(detail.get('samplePayments') or []) == 1
|
||||
assert detail['samplePayments'][0]['sampleCode'] == 'S-001'
|
||||
|
||||
|
||||
def test_protocol_body_rejects_status_finance_and_conversion_fields():
|
||||
from app.schemas.market_mobile import MarketProtocolBody
|
||||
|
||||
|
||||
Reference in new issue
Block a user