"""Проверка схемы среза ЕХ ex-payload-v1 (docs #208): примеры проходят, типовые ошибки — нет. Запуск: .venv/bin/python -I scripts/kfo_contract/test_ex_payload.py """ import copy import json import sys from pathlib import Path from jsonschema import Draft202012Validator ROOT = Path(__file__).resolve().parents[2] SCHEMA = ROOT / "contracts" / "ex-payload-v1.schema.json" EXAMPLES = sorted((ROOT / "contracts" / "examples").glob("ex-payload-*.json")) REQUIRED_TYPES = {"summary_osv", "vgo_pairs", "chess", "kfo_balance", "kfo_income", "goodwill", "corrections", "version_card"} def main(): schema = json.loads(SCHEMA.read_text(encoding="utf-8")) Draft202012Validator.check_schema(schema) v = Draft202012Validator(schema) by_type = {} for p in EXAMPLES: doc = json.loads(p.read_text(encoding="utf-8")) errs = list(v.iter_errors(doc)) assert not errs, f"{p.name}: {errs[0].message[:200]}" by_type[doc["item_type"]] = doc missing = REQUIRED_TYPES - set(by_type) assert not missing, f"нет примеров: {sorted(missing)}" def rejected(doc, why): assert list(v.iter_errors(doc)), f"схема пропустила: {why}" # 1. item_type конверта не совпадает с формой data bad = copy.deepcopy(by_type["kfo_balance"]) bad["data"] = copy.deepcopy(by_type["goodwill"]["data"]) rejected(bad, "kfo_balance с данными гудвилла") # 2. kfo_balance без сводки корректировок в реквизитах bad = copy.deepcopy(by_type["kfo_balance"]) del bad["data"]["requisites"]["corrections_balance"] rejected(bad, "нет requisites.corrections_balance") # 4. деньги числом bad = copy.deepcopy(by_type["kfo_balance"]) bad["data"]["balance"]["lines"][0]["bank_amount"] = 2500.0 rejected(bad, "деньги числом") # конверт: лишнее поле и неизвестная единица bad = copy.deepcopy(by_type["version_card"]) bad["extra"] = 1 rejected(bad, "лишнее поле конверта") bad = copy.deepcopy(by_type["summary_osv"]) bad["units"] = "mln_rub" rejected(bad, "неизвестная единица") # единица не соответствует типу bad = copy.deepcopy(by_type["summary_osv"]) bad["units"] = "thousand_rub" rejected(bad, "summary_osv в тысячах") print(f"OK: примеров {len(EXAMPLES)}, отрицательных случаев 6") return 0 if __name__ == "__main__": sys.exit(main())