feat: 新增现场日历并将四类日历的起止地改为选填,以支持现场派车记录。
This commit is contained in:
1 parent
0453e90000
commit
cd99b040aa
15 files changed
+172
-31
No files matched your search
@@ -24,7 +24,7 @@ class PlDispatchCalendar(Base):
|
||||
quantity = Column(String(16), nullable=True, comment="数量文本(吨),最多两位小数,不参与汇总")
|
||||
calendar_kind = Column(
|
||||
String(16), nullable=False, default="acid", server_default="acid",
|
||||
comment="日历类型:acid酸派车 alkali碱派车 other其他",
|
||||
comment="日历类型:acid酸派车 alkali碱派车 other其他 site现场",
|
||||
)
|
||||
tenant_no = Column(String(64), nullable=False, comment="租户编号")
|
||||
order_num = Column(Integer, nullable=True, comment="排序号")
|
||||
|
||||
@@ -12,8 +12,8 @@ class CreateBody(BaseModel):
|
||||
dispatch_date: date = Field(..., alias="dispatchDate", description="派车日期,范围 1900-01-01 至 2100-12-31")
|
||||
vehicle_id: str = Field(..., alias="vehicleId", min_length=1, max_length=64)
|
||||
product_id: str = Field(..., alias="productId", min_length=1, max_length=64)
|
||||
origin: str = Field(..., min_length=1, max_length=255)
|
||||
destination: str = Field(..., min_length=1, max_length=255)
|
||||
origin: str = Field(default="", max_length=255)
|
||||
destination: str = Field(default="", max_length=255)
|
||||
quantity: Optional[str] = Field(default=None, max_length=16, description="数量文本,单位吨,最多两位小数;不参与汇总")
|
||||
calendar_kind: str = Field(default="acid", alias="calendarKind", min_length=1, max_length=16)
|
||||
remark: Optional[str] = Field(default=None, max_length=500)
|
||||
@@ -51,8 +51,8 @@ class CreateBody(BaseModel):
|
||||
@field_validator("calendar_kind")
|
||||
@classmethod
|
||||
def validate_calendar_kind(cls, value: str) -> str:
|
||||
if value not in ("acid", "alkali", "other"):
|
||||
raise ValueError("日历类型须为 acid、alkali 或 other")
|
||||
if value not in ("acid", "alkali", "other", "site"):
|
||||
raise ValueError("日历类型须为 acid、alkali、other 或 site")
|
||||
return value
|
||||
|
||||
|
||||
|
||||
@@ -14,13 +14,13 @@ from app.models.pl_models import PlVehicle
|
||||
from app.schemas.pl.dispatch_calendar import CreateBody, UpdateBody
|
||||
from app.services.pl_data_scope import apply_pl_scope
|
||||
|
||||
CALENDAR_KINDS = ("acid", "alkali", "other")
|
||||
CALENDAR_KINDS = ("acid", "alkali", "other", "site")
|
||||
|
||||
|
||||
def _calendar_kind(kind: Optional[str]) -> str:
|
||||
value = kind or "acid"
|
||||
if value not in CALENDAR_KINDS:
|
||||
raise HTTPException(status_code=422, detail="日历类型须为 acid、alkali 或 other")
|
||||
raise HTTPException(status_code=422, detail="日历类型须为 acid、alkali、other 或 site")
|
||||
return value
|
||||
|
||||
|
||||
|
||||
@@ -166,7 +166,7 @@ def test_invalid_cross_tenant_and_deleted_relations_rejected(db, field, value):
|
||||
|
||||
@pytest.mark.parametrize('bad', [
|
||||
{'dispatchDate': '2026-02-30'}, {'dispatchDate': '1899-12-31'}, {'dispatchDate': '2101-01-01'},
|
||||
{'dispatchDate': 1792972800}, {'dispatchDate': '2026-10-26T00:00:00'}, {'origin': ' '}, {'destination': 'x' * 256},
|
||||
{'dispatchDate': 1792972800}, {'dispatchDate': '2026-10-26T00:00:00'}, {'origin': 'x' * 256}, {'destination': 'x' * 256},
|
||||
{'vehicleId': ''}, {'productId': ''}, {'remark': 'x' * 501}, {'calendarKind': 'salt'}, {'tenantNo': 't2'},
|
||||
{'licensePlate': '伪造'}, {'productName': '伪造'}, {'createBy': 'other'},
|
||||
])
|
||||
@@ -340,3 +340,51 @@ def test_calendar_openapi_schema_can_be_generated():
|
||||
for schema in ('CreateBody', 'UpdateBody'):
|
||||
field = document['components']['schemas'][schema]['properties']['dispatchDate']
|
||||
assert field['type'] == 'string' and field['format'] == 'date'
|
||||
|
||||
|
||||
def test_site_calendar_crud_isolation_and_kind_protection(db):
|
||||
model, _, update, svc = modules()
|
||||
existing = {kind: create(db, calendarKind=kind) for kind in ('acid', 'alkali', 'other')}
|
||||
site = create(db, calendarKind='site', origin='现场', quantity='32.50')
|
||||
original_id, original_created = site.id, site.create_time
|
||||
page = svc.list_records(db, 't1', user(), month='2026-10', calendar_kind='site')
|
||||
assert page['total'] == 1 and page['list'][0]['id'] == site.id
|
||||
assert page['list'][0]['calendarKind'] == 'site'
|
||||
assert svc.list_records(db, 't2', user(tenant='t2'), month='2026-10', calendar_kind='site')['total'] == 0
|
||||
assert svc.list_records(db, 't1', user(), month='2026-10', calendar_kind='site', vehicle_id='v2')['total'] == 0
|
||||
for kind, row in existing.items():
|
||||
assert svc.list_records(db, 't1', user(), month='2026-10', calendar_kind=kind)['list'][0]['id'] == row.id
|
||||
with pytest.raises(HTTPException) as moved:
|
||||
svc.update_record(db, 't1', user(), site.id, update(**payload(calendarKind=kind)))
|
||||
assert moved.value.status_code == 422
|
||||
kept = svc.update_record(db, 't1', user(), site.id, update(**payload(calendarKind='site', destination='现场仓库')))
|
||||
assert kept.id == original_id and kept.create_time == original_created
|
||||
assert kept.calendar_kind == 'site' and kept.destination == '现场仓库'
|
||||
assert svc.delete_record(db, 't1', user(), site.id) == 1
|
||||
assert db.get(model, original_id).del_flag == 1
|
||||
assert svc.list_records(db, 't1', user(), month='2026-10', calendar_kind='site')['total'] == 0
|
||||
|
||||
|
||||
@pytest.mark.parametrize('kind', ['acid', 'alkali', 'other', 'site'])
|
||||
@pytest.mark.parametrize('addresses', [
|
||||
{'origin': '', 'destination': '重庆'},
|
||||
{'origin': '宜昌', 'destination': ''},
|
||||
{'origin': ' ', 'destination': ' '},
|
||||
])
|
||||
def test_calendar_addresses_optional_on_create_and_update(db, kind, addresses):
|
||||
_, schema, update, svc = modules()
|
||||
created = create(db, calendarKind=kind, **addresses)
|
||||
result = svc._row_to_dict(created)
|
||||
assert result['origin'] == addresses['origin'].strip()
|
||||
assert result['destination'] == addresses['destination'].strip()
|
||||
existing = create(db, calendarKind=kind)
|
||||
updated = svc.update_record(db, 't1', user(), existing.id,
|
||||
update(**payload(calendarKind=kind, **addresses)))
|
||||
assert updated.id == existing.id
|
||||
assert updated.origin == addresses['origin'].strip()
|
||||
assert updated.destination == addresses['destination'].strip()
|
||||
omitted = payload(calendarKind=kind)
|
||||
omitted.pop('origin')
|
||||
omitted.pop('destination')
|
||||
body = schema(**omitted)
|
||||
assert body.origin == body.destination == ''
|
||||
Reference in new issue
Block a user