Files
shanxia2.0/backend/tests/test_pl_quota_conversion.py
T
wuzilongandCursor 8e9536332a feat: 保存运输证件、报销付款和开发流程的当前实现。
补齐证书齐备、证件折算、移动用证和合同绑定,并带上报销批量发放、付款备注以及个人开发流程升级,便于继续讨论已安排计划的调整规则。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-11-04 21:42:33 +08:00

104 lines
5.4 KiB
Python

"""单位换算只在计量段已绑定异单位证件时成立。"""
from datetime import date, datetime
from types import SimpleNamespace
from sqlalchemy import create_engine
from sqlalchemy.orm import Session
from app.models.pl_models import (
PlPlan, PlPlanDelivery, PlPlanDeliveryProduct, PlPlanLoad, PlPlanLoadProduct, PlPlanProduct,
)
from app.models.pl_quota_models import (
PlContractCertLink, PlContractCertProduct, PlPlanCertUsage, PlPurchaseCert, PlTransportCert,
)
from app.services.pl_menu_badge_service import count_plan_cert_pending
from app.services.pl_quota_conversion import plan_needs_unit_conversion
from app.services.pl_quota_overview import list_plans
def line(line_id, side, unit, contract_product_id='cp', customer='客户', toxic=True):
return {
'id': line_id, 'planProductId': 'pp', 'side': side, 'unit': unit,
'contractProductId': contract_product_id, 'customerName': customer, 'isToxic': toxic,
}
def plan(**values):
return SimpleNamespace(
cert_configuration=values.get('configuration'),
transport_status=values.get('transport_status', 'pending'),
archive_status=values.get('archive_status', 'unarchived'),
)
def test_same_label_and_code_do_not_need_conversion():
current = plan()
assert plan_needs_unit_conversion(current, [line('L', 'load', '吨')], {'cp': ['dun']}, []) is False
assert plan_needs_unit_conversion(current, [line('L', 'load', '吨', toxic=False)], {'cp': ['kg']}, []) is False
assert plan_needs_unit_conversion(
current, [line('L', 'load', '吨', customer='安庆市山峡化工有限公司')], {'cp': ['kg']}, [],
) is True
def test_unbound_and_unselected_legacy_sides_are_display_only():
both = [line('L', 'load', '吨'), line('D', 'delivery', '吨')]
arranged = plan(transport_status='arranged')
assert plan_needs_unit_conversion(arranged, both, {'cp': ['kg']}, []) is False
chosen = plan(transport_status='arranged', configuration={'sourceMapping': [
{'sourceStopType': 'load', 'sourceStopProductId': 'L', 'relatedStopProductIds': ['D']},
]})
assert plan_needs_unit_conversion(chosen, both, {'cp': ['kg']}, []) is True
def test_new_plan_counts_either_stop_when_a_bound_certificate_uses_another_unit():
current = plan()
assert plan_needs_unit_conversion(
current, [line('L', 'load', 'dun'), line('D', 'delivery', 'dun')], {'cp': ['kg']}, [],
) is True
assert plan_needs_unit_conversion(current, [line('L', 'load', 'dun')], {}, []) is False
def test_list_and_badge_count_only_plans_with_a_real_unit_mismatch(monkeypatch):
engine = create_engine('sqlite://')
models = (
PlPlan, PlPlanProduct, PlPlanLoad, PlPlanDelivery, PlPlanLoadProduct, PlPlanDeliveryProduct,
PlContractCertLink, PlContractCertProduct, PlPurchaseCert, PlTransportCert, PlPlanCertUsage,
)
for model in models:
model.__table__.create(engine)
with Session(engine) as db:
user = SimpleNamespace(id='u', tenant_no='t', to_user_info=lambda: {'role': 'super_admin', 'user_id': 'u'})
db.add(PlPlan(id='plain', plan_no='PLAIN', create_date=date(2026, 11, 1), plan_date=date(2026, 11, 1),
plan_type='direct', belongs_company='shanxia', tenant_no='t',
create_time=datetime(2026, 11, 1)))
db.add(PlPlan(id='mix', plan_no='MIX', create_date=date(2026, 11, 2), plan_date=date(2026, 11, 2),
plan_type='direct', belongs_company='shanxia', tenant_no='t',
create_time=datetime(2026, 11, 2)))
db.add(PlPlanProduct(id='pp-plain', plan_id='plain', product_id='sku', product_no='SKU',
product_name='硫酸', is_toxic=1, tenant_no='t'))
db.add(PlPlanProduct(id='pp-mix', plan_id='mix', product_id='sku', product_no='SKU',
product_name='硫酸', is_toxic=1, tenant_no='t'))
db.add(PlPlanLoad(id='load-mix', plan_id='mix', customer_name='外部客户', tenant_no='t'))
db.add(PlPlanLoadProduct(
id='line-mix', load_id='load-mix', plan_id='mix', plan_product_id='pp-mix', product_id='sku',
product_no='SKU', product_name='硫酸', unit='吨', contract_product_id='cp', tenant_no='t',
))
db.add(PlPurchaseCert(
id='buy', cert_no='BUY', product_name_on_cert='硫酸', total_qty=1, quantity_unit='kg',
valid_use_text='多次有效', buyer_name='买方', seller_name='卖方', tenant_no='t',
))
db.add(PlContractCertLink(
id='link', contract_id='c', contract_no_snapshot='C-1', cert_type='purchase', cert_id='buy',
tenant_no='t',
))
db.add(PlContractCertProduct(id='scope', contract_cert_link_id='link', contract_product_id='cp', tenant_no='t'))
db.commit()
monkeypatch.setattr('app.services.pl_menu_badge_service.apply_pl_scope', lambda query, *args, **kwargs: query)
monkeypatch.setattr('app.services.pl_quota_overview.apply_pl_scope', lambda query, *args, **kwargs: query)
listed = {row['planNo']: row['needsUnitConversion'] for row in list_plans(db, user)['list']}
assert listed == {'MIX': True, 'PLAIN': False}
only = list_plans(db, user, conversion_only=True)
assert only['total'] == 1 and only['list'][0]['planNo'] == 'MIX'
assert count_plan_cert_pending(db, 't', user) == 1
engine.dispose()