|
|
@@ -2446,98 +2446,132 @@ class OutputPresenter:
|
|
|
)
|
|
|
return '\n'.join(lines)
|
|
|
|
|
|
- return self._success_result(content, '\n'.join(lines), meta)
|
|
|
-
|
|
|
def _present_freightower_track(self, data, meta):
|
|
|
- if set(data) != {'schedule', 'ports', 'tracks'}:
|
|
|
+ expected = {'schedule', 'ports', 'containers', 'tracks', 'terminal_plan'}
|
|
|
+ if set(data) != expected:
|
|
|
return self._format_error(meta)
|
|
|
- schedule = data.get('schedule')
|
|
|
- ports = data.get('ports')
|
|
|
- tracks = data.get('tracks')
|
|
|
- schedule_keys = (
|
|
|
- 'bl_number', 'container_code', 'vessel', 'voyage', 'etd', 'eta',
|
|
|
- )
|
|
|
- if (
|
|
|
- not isinstance(schedule, dict)
|
|
|
- or set(schedule) != set(schedule_keys)
|
|
|
- or not isinstance(ports, list)
|
|
|
- or not isinstance(tracks, list)
|
|
|
- ):
|
|
|
+ schedule = self._freightower_object(data.get('schedule'), (
|
|
|
+ ('bl_number', '提单号'),
|
|
|
+ ('container_code', '柜号'),
|
|
|
+ ('carrier_name', '船公司'),
|
|
|
+ ('vessel', '船名'),
|
|
|
+ ('voyage', '航次'),
|
|
|
+ ('route_code', '航线'),
|
|
|
+ ('current_status', '当前状态'),
|
|
|
+ ('current_status_time', '当前状态时间'),
|
|
|
+ ('current_status_place', '当前状态地点'),
|
|
|
+ ('update_time', '数据更新时间'),
|
|
|
+ ('etd', '预计离港'),
|
|
|
+ ('atd', '实际离港'),
|
|
|
+ ('eta', '预计到达'),
|
|
|
+ ))
|
|
|
+ if schedule is None:
|
|
|
+ return self._format_error(meta)
|
|
|
+ ports = self._freightower_rows(data.get('ports'), (
|
|
|
+ ('place_type', '地点类型'),
|
|
|
+ ('port_name', '港口'),
|
|
|
+ ('terminal_name', '码头'),
|
|
|
+ ('etd', '预计离港'),
|
|
|
+ ('atd', '实际离港'),
|
|
|
+ ('eta', '预计到达'),
|
|
|
+ ('ata', '实际到达'),
|
|
|
+ ), {'place_type': ('起运港', '中转港', '目的港', '交货地')})
|
|
|
+ containers = self._freightower_rows(data.get('containers'), (
|
|
|
+ ('container_no', '箱号'),
|
|
|
+ ('container_type', '箱型'),
|
|
|
+ ('seal_no', '铅封号'),
|
|
|
+ ('current_status', '当前状态'),
|
|
|
+ ('off_load', '是否甩柜'),
|
|
|
+ ), {'off_load': ('', '是', '否')})
|
|
|
+ tracks = self._freightower_rows(data.get('tracks'), (
|
|
|
+ ('time', '时间'),
|
|
|
+ ('location', '地点'),
|
|
|
+ ('content', '内容'),
|
|
|
+ ('event_code', '状态代码'),
|
|
|
+ ('estimate_flag', '实际/预计'),
|
|
|
+ ('vessel_voyage', '船名航次'),
|
|
|
+ ('terminal_name', '码头'),
|
|
|
+ ), {'estimate_flag': ('实际', '预计')})
|
|
|
+ terminal_plan = self._freightower_object(data.get('terminal_plan'), (
|
|
|
+ ('port_name', '港口'),
|
|
|
+ ('terminal_name', '码头'),
|
|
|
+ ('open_time', '开港'),
|
|
|
+ ('close_time', '截港'),
|
|
|
+ ('etd', '预计离港'),
|
|
|
+ ('atd', '实际离港'),
|
|
|
+ ('shipping_agent', '船代'),
|
|
|
+ ))
|
|
|
+ if None in (ports, containers, tracks, terminal_plan):
|
|
|
return self._format_error(meta)
|
|
|
- labels = {
|
|
|
- 'bl_number': '提单号',
|
|
|
- 'container_code': '柜号',
|
|
|
- 'vessel': '船名',
|
|
|
- 'voyage': '航次',
|
|
|
- 'etd': '预计离港',
|
|
|
- 'eta': '预计到达',
|
|
|
- }
|
|
|
- safe_schedule = {}
|
|
|
- for key in schedule_keys:
|
|
|
- value = schedule.get(key)
|
|
|
- if not isinstance(value, str):
|
|
|
- return self._format_error(meta)
|
|
|
- safe_schedule[labels[key]] = value
|
|
|
- safe_ports = []
|
|
|
- for port in ports:
|
|
|
- if not isinstance(port, dict) or set(port) != {
|
|
|
- 'place_type', 'port_name', 'eta', 'ata',
|
|
|
- }:
|
|
|
- return self._format_error(meta)
|
|
|
- if port['place_type'] not in ('中转港', '目的港', '交货地'):
|
|
|
- return self._format_error(meta)
|
|
|
- for key in ('port_name', 'eta', 'ata'):
|
|
|
- if not isinstance(port[key], str):
|
|
|
- return self._format_error(meta)
|
|
|
- safe_ports.append({
|
|
|
- '地点类型': port['place_type'],
|
|
|
- '港口': port['port_name'],
|
|
|
- '预计到达': port['eta'],
|
|
|
- '实际到达': port['ata'],
|
|
|
- })
|
|
|
- safe_tracks = []
|
|
|
- for track in tracks:
|
|
|
- if not isinstance(track, dict) or set(track) != {
|
|
|
- 'time', 'location', 'content', 'event_code',
|
|
|
- }:
|
|
|
- return self._format_error(meta)
|
|
|
- for key in ('time', 'location', 'content', 'event_code'):
|
|
|
- if not isinstance(track[key], str):
|
|
|
- return self._format_error(meta)
|
|
|
- safe_tracks.append({
|
|
|
- '时间': track['time'],
|
|
|
- '地点': track['location'],
|
|
|
- '内容': track['content'],
|
|
|
- '状态代码': track['event_code'],
|
|
|
- })
|
|
|
content = {
|
|
|
- '船期': safe_schedule,
|
|
|
- '港口': safe_ports,
|
|
|
- '轨迹': safe_tracks,
|
|
|
+ '船期': schedule,
|
|
|
+ '港口': ports,
|
|
|
+ '箱子': containers,
|
|
|
+ '轨迹': tracks,
|
|
|
+ '港区计划': terminal_plan,
|
|
|
}
|
|
|
lines = ['飞驼船期']
|
|
|
- for label, value in safe_schedule.items():
|
|
|
+ for label, value in schedule.items():
|
|
|
lines.append('- {0}: {1}'.format(label, value))
|
|
|
- lines.append('港口')
|
|
|
- if not safe_ports:
|
|
|
- lines.append('- 无')
|
|
|
- for port in safe_ports:
|
|
|
- lines.append(
|
|
|
- '- {0} {1} 预计到达 {2} 实际到达 {3}'.format(
|
|
|
- port['地点类型'], port['港口'], port['预计到达'], port['实际到达'],
|
|
|
- )
|
|
|
- )
|
|
|
- lines.append('轨迹')
|
|
|
- if not safe_tracks:
|
|
|
+ lines.extend(self._freightower_section('港口', ports, (
|
|
|
+ '地点类型', '港口', '码头', '预计离港', '实际离港', '预计到达', '实际到达',
|
|
|
+ )))
|
|
|
+ lines.extend(self._freightower_section('箱子', containers, (
|
|
|
+ '箱号', '箱型', '铅封号', '当前状态', '是否甩柜',
|
|
|
+ )))
|
|
|
+ lines.extend(self._freightower_section('轨迹', tracks, (
|
|
|
+ '时间', '地点', '内容', '状态代码', '实际/预计', '船名航次', '码头',
|
|
|
+ )))
|
|
|
+ if any(terminal_plan.values()):
|
|
|
+ lines.append('港区计划')
|
|
|
+ for label, value in terminal_plan.items():
|
|
|
+ lines.append('- {0}: {1}'.format(label, value))
|
|
|
+ else:
|
|
|
+ lines.append('港区计划')
|
|
|
lines.append('- 无')
|
|
|
- for track in safe_tracks:
|
|
|
- lines.append(
|
|
|
- '- {0} {1} {2} {3}'.format(
|
|
|
- track['时间'], track['地点'], track['内容'], track['状态代码'],
|
|
|
- )
|
|
|
- )
|
|
|
return self._success_result(content, '\n'.join(lines), meta)
|
|
|
|
|
|
+ def _freightower_object(self, value, fields):
|
|
|
+ if not isinstance(value, dict) or set(value) != {key for key, _label in fields}:
|
|
|
+ return None
|
|
|
+ result = {}
|
|
|
+ for key, label in fields:
|
|
|
+ item = value.get(key)
|
|
|
+ if not isinstance(item, str):
|
|
|
+ return None
|
|
|
+ result[label] = item
|
|
|
+ return result
|
|
|
+
|
|
|
+ def _freightower_rows(self, rows, fields, choices):
|
|
|
+ if not isinstance(rows, list):
|
|
|
+ return None
|
|
|
+ keys = {key for key, _label in fields}
|
|
|
+ result = []
|
|
|
+ for row in rows:
|
|
|
+ if not isinstance(row, dict) or set(row) != keys:
|
|
|
+ return None
|
|
|
+ item = {}
|
|
|
+ for key, label in fields:
|
|
|
+ cell = row.get(key)
|
|
|
+ if not isinstance(cell, str):
|
|
|
+ return None
|
|
|
+ allowed = choices.get(key)
|
|
|
+ if allowed is not None and cell not in allowed:
|
|
|
+ return None
|
|
|
+ item[label] = cell
|
|
|
+ result.append(item)
|
|
|
+ return result
|
|
|
+
|
|
|
+ @staticmethod
|
|
|
+ def _freightower_section(title, rows, labels):
|
|
|
+ lines = [title]
|
|
|
+ if not rows:
|
|
|
+ lines.append('- 无')
|
|
|
+ return lines
|
|
|
+ for row in rows:
|
|
|
+ lines.append('- ' + ' '.join(row[label] for label in labels))
|
|
|
+ return lines
|
|
|
+
|
|
|
@staticmethod
|
|
|
def _success_result(content, text, meta):
|
|
|
return {
|