补齐证书齐备、证件折算、移动用证和合同绑定,并带上报销批量发放、付款备注以及个人开发流程升级,便于继续讨论已安排计划的调整规则。 Co-authored-by: Cursor <cursoragent@cursor.com>
104 lines
5.4 KiB
Python
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()
|