# Excel import A one-time converter from `Wochenspeiseplan.xlsm` to a Recipe Bundle ([format](../../docs/recipe-bundle-format.md)) that you then import into CookIt on the phone. The workbook and the bundle are private data and stay out of git. ```sh cd tools/excel-import python -m venv .venv .venv/Scripts/pip install -r requirements.txt # Windows; use .venv/bin/pip elsewhere .venv/Scripts/python convert.py ../../Wochenspeiseplan.xlsm # -> out/cookit-rezepte.zip; copy it to the phone and use Einstellungen → Rezepte importieren .venv/Scripts/python -m pytest ``` The tests in `tests/test_workbook.py` run only when the workbook is at the repo root, or wherever `COOKIT_WORKBOOK` points. ## What it does - Reads every sheet built from the recipe template (`C2 = Menge`, `E2 = Zutat`) and skips `Leeres Rezept` and `Spinat-Feta-Pizza`. - **Ingredients:** C/D/E from row 3 down. - A blank row starts a new (unnamed) Ingredient Group. - An `ODER` row starts a group named "Alternative". - Cell comments such as "Zutaten für die Sauce" name the group starting at that row. - Units are mapped to canonical keys, including typos. - "100 g" typed into the unit column is split into amount and unit. - Rows without an ingredient name that hold only numbers (left over from rescaling) are dropped. - A repeated copy of the ingredient list is dropped. - **Steps:** text from the F column. - Blank lines separate Steps. - If there are no blank lines, each line is a Step. - Short lines ("Teig", "Soße:") and inline headings ("Salat:Die Zwiebel…") become Step Sections. - **Calories:** more than 1500 kcal counts as the whole recipe, otherwise per serving. A "Pro Portion" comment on the cell settles it. The guess isn't flagged: on review it matched every value in the workbook. - **Notes & Sources:** - The comment field (B12) and any cell outside the template go into Notes, one line per sheet row. - URLs anywhere become Sources. - The template text "Löschen Sie dieses Rezeptarbeitsblatt nicht." is dropped. - **Photos:** pictures on the sheet, top-left first, re-encoded as JPEG, at most 1600 px. The template's stock picture (copied onto every sheet made from `Leeres Rezept`) is dropped, so those Recipes simply have no Photo. - **Review Flags:** anything the converter guessed or moved adds a German reason to `reviewReasons`, shown in the app under "zu prüfen". - **IDs:** Recipe IDs come from the sheet name (UUIDv5), so converting again gives the same IDs and a second import skips Recipes already there.