Initial commit: macOS receipt workspace
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
import argparse
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
from PIL import Image
|
||||
|
||||
|
||||
def invoke(command, request):
|
||||
process = subprocess.run(command, input=json.dumps(request, ensure_ascii=False) + '\n', capture_output=True, text=True, timeout=180)
|
||||
events = [json.loads(line) for line in process.stdout.splitlines() if line.strip()]
|
||||
errors = [event for event in events if event['event'] == 'error']
|
||||
if process.returncode or errors:
|
||||
raise RuntimeError(str(errors) + '\n' + process.stderr)
|
||||
results = [event['result'] for event in events if event['event'] == 'result']
|
||||
if len(results) != 1:
|
||||
raise AssertionError('处理引擎没有返回唯一结果')
|
||||
return results[0]
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--binary')
|
||||
parser.add_argument('--output', required=True)
|
||||
arguments = parser.parse_args()
|
||||
root = Path(__file__).resolve().parents[3]
|
||||
output = Path(arguments.output).resolve()
|
||||
output.mkdir(parents=True, exist_ok=True)
|
||||
engine = Path(__file__).resolve().parents[1] / 'engine.py'
|
||||
command = [arguments.binary] if arguments.binary else [sys.executable, str(engine)]
|
||||
state = invoke(command, dict(operation='scan', path=str(root / 'fapiao/demo-materials'), workspacePath=str(output / 'materials'), folderName='演示报账材料'))
|
||||
assert len(state['invoices']) == 2
|
||||
assert len(state['payments']) == 2
|
||||
assert len(state['photos']) == 1
|
||||
assert len(state['matches']) == 2
|
||||
assert {match['category'] for match in state['matches']} == {'餐饮', '住宿'}
|
||||
assert state['directoryPaymentTotal'] == 596.5
|
||||
assert sum(match['expenseAmount'] for match in state['matches']) == 596.5
|
||||
assert not state['warnings']
|
||||
(output / 'state.json').write_text(json.dumps(state, ensure_ascii=False, indent=2))
|
||||
for operation, extension in [('ppt', 'pptx'), ('expense', 'xlsx')]:
|
||||
destination = output / ('演示报账材料.' + extension)
|
||||
invoke(command, dict(operation=operation, state=state, destination=str(destination), classified=True, purposes={match['id']: match['category'] + '费用' for match in state['matches']}, signatures=['经办人', '财务']))
|
||||
assert destination.stat().st_size > 1000
|
||||
pdf_input = output / 'pdf-input'
|
||||
(pdf_input / '发票').mkdir(parents=True, exist_ok=True)
|
||||
(pdf_input / '付款截图').mkdir(parents=True, exist_ok=True)
|
||||
with Image.open(root / 'fapiao/demo-materials/发票/住宿_差旅发票_A001.png') as original:
|
||||
original.convert('RGB').save(pdf_input / '发票/两页发票.pdf', save_all=True, append_images=[Image.new('RGB', (800, 500), 'white')])
|
||||
(pdf_input / '发票/损坏文件.pdf').write_bytes(b'not a pdf')
|
||||
shutil.copyfile(root / 'fapiao/demo-materials/付款截图/酒店支付记录_B009.png', pdf_input / '付款截图/付款.png')
|
||||
pdf_state = invoke(command, dict(operation='scan', path=str(pdf_input), workspacePath=str(output / 'pdf-materials')))
|
||||
assert len(pdf_state['invoices']) == 2
|
||||
assert len(pdf_state['matches']) == 1
|
||||
assert pdf_state['matches'][0]['expenseAmount'] == 468
|
||||
assert sum(item['ocr']['status'] == 'failed' for item in pdf_state['invoices']) == 1
|
||||
invoke(command, dict(operation='ppt', state=pdf_state, destination=str(output / 'PDF首页贴票.pptx')))
|
||||
print('完整链路通过:5 份材料、2 组自动核对、总额 596.50;PPT、个人报销单、PDF 首页与损坏文件降级均通过。')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user