122 lines
4.7 KiB
Python
122 lines
4.7 KiB
Python
import unittest
|
|
import hashlib
|
|
import json
|
|
|
|
from pydantic import ValidationError
|
|
|
|
from module_business.domain.enums import PalletEventType
|
|
from module_business.entity.do.master_do import BizTunnel
|
|
from module_business.entity.do.operation_do import BizPalletEvent, BizPalletInventory, BizReturnItem, BizUsageRecord
|
|
from module_business.entity.vo.master_vo import PalletCreateModel, TunnelModel, TunnelPageQueryModel
|
|
from module_business.entity.vo.operation_vo import FillingCreateModel, TunnelEntryCreateModel, UsageCreateModel
|
|
from module_business.service.usage_service import UsageService
|
|
|
|
|
|
class TestTunnelFlowContract(unittest.TestCase):
|
|
def test_tunnel_master_data_belongs_to_site_and_has_scoped_code(self) -> None:
|
|
self.assertEqual(BizTunnel.__tablename__, 'biz_tunnel')
|
|
self.assertIn('site_id', BizTunnel.__table__.c)
|
|
self.assertIn('tunnel_code', BizTunnel.__table__.c)
|
|
self.assertIn('current_trace_no', BizTunnel.__table__.c)
|
|
self.assertEqual(
|
|
{constraint.name for constraint in BizTunnel.__table__.constraints if constraint.name},
|
|
{
|
|
'uq_biz_tunnel_site_code',
|
|
'ck_biz_tunnel_status',
|
|
},
|
|
)
|
|
|
|
def test_tunnel_master_vo_supports_list_and_write_contract(self) -> None:
|
|
tunnel = TunnelModel(
|
|
siteId=9,
|
|
tunnelCode='T-01',
|
|
tunnelName='一号隧道',
|
|
)
|
|
self.assertEqual(tunnel.model_dump(by_alias=True)['tunnelCode'], 'T-01')
|
|
query = TunnelPageQueryModel(siteId=9, tunnelCode='T-01')
|
|
self.assertEqual(query.site_id, 9)
|
|
|
|
def test_usage_requires_tunnel_but_keeps_line_optional(self) -> None:
|
|
usage = UsageCreateModel(
|
|
qrToken='qr-1',
|
|
tunnelId=9,
|
|
usedPackages=20,
|
|
idempotencyKey='usage-key',
|
|
)
|
|
self.assertIsNone(usage.line_id)
|
|
with self.assertRaises(ValidationError):
|
|
UsageCreateModel(
|
|
qrToken='qr-1',
|
|
usedPackages=20,
|
|
idempotencyKey='usage-key',
|
|
)
|
|
|
|
def test_tunnel_entry_is_idempotent_command(self) -> None:
|
|
command = TunnelEntryCreateModel(
|
|
qrToken='qr-1',
|
|
tunnelId=9,
|
|
idempotencyKey='entry-key',
|
|
)
|
|
self.assertEqual(command.tunnel_id, 9)
|
|
|
|
def test_flow_records_keep_tunnel_and_trace_snapshots(self) -> None:
|
|
self.assertIn('tunnel_id', BizPalletInventory.__table__.c)
|
|
self.assertIn('trace_no', BizPalletInventory.__table__.c)
|
|
self.assertIn('tunnel_id', BizUsageRecord.__table__.c)
|
|
self.assertIn('trace_no', BizUsageRecord.__table__.c)
|
|
self.assertIn('batch_no_snapshot', BizUsageRecord.__table__.c)
|
|
self.assertIn('tunnel_id_snapshot', BizReturnItem.__table__.c)
|
|
self.assertIn('trace_no_snapshot', BizReturnItem.__table__.c)
|
|
self.assertIn('before_tunnel_id', BizPalletEvent.__table__.c)
|
|
self.assertIn('after_tunnel_id', BizPalletEvent.__table__.c)
|
|
self.assertIn('trace_no', BizPalletEvent.__table__.c)
|
|
self.assertEqual(PalletEventType.TUNNEL_ENTERED.value, 'TUNNEL_ENTERED')
|
|
|
|
def test_new_pallet_and_filling_are_fixed_to_one_hundred_packages(self) -> None:
|
|
PalletCreateModel(palletCode='P-001', capacityPackages=100)
|
|
FillingCreateModel(
|
|
qrToken='qr-1',
|
|
warehouseId=1,
|
|
strainId=1,
|
|
batchNo='B-1',
|
|
productionDate='2026-10-01',
|
|
expiryDate='2027-04-01',
|
|
packageSpec='标准包',
|
|
initialPackages=100,
|
|
idempotencyKey='fill-key',
|
|
)
|
|
with self.assertRaises(ValidationError):
|
|
PalletCreateModel(palletCode='P-002', capacityPackages=20)
|
|
with self.assertRaises(ValidationError):
|
|
FillingCreateModel(
|
|
qrToken='qr-1',
|
|
warehouseId=1,
|
|
strainId=1,
|
|
batchNo='B-1',
|
|
packageSpec='标准包',
|
|
initialPackages=20,
|
|
idempotencyKey='fill-key',
|
|
)
|
|
|
|
def test_usage_idempotency_hash_includes_tunnel(self) -> None:
|
|
command = UsageCreateModel(
|
|
qrToken=' qr-1 ',
|
|
tunnelId=9,
|
|
lineId=None,
|
|
usedPackages=20,
|
|
idempotencyKey='usage-key',
|
|
)
|
|
expected = hashlib.sha256(
|
|
json.dumps(
|
|
{
|
|
'qr_token': 'qr-1',
|
|
'tunnel_id': 9,
|
|
'line_id': None,
|
|
'used_packages': 20,
|
|
},
|
|
sort_keys=True,
|
|
separators=(',', ':'),
|
|
).encode()
|
|
).hexdigest()
|
|
self.assertEqual(expected, UsageService._build_request_hash(command))
|