Commit b5f149d
refactor(mcp): extract _format_money helper + standardize currency rendering (#752)
**Helper extraction (closes #744)**
Pulled the duplicated ``f"${amount:,.2f} {currency or 'USD'}"`` block
out of three create-card builders (PO create, SO create, PO receipt)
plus the variant-detail price display into a single
``_format_money(amount, currency)`` helper in ``prefab_ui.py``.
**Babel for currency-aware formatting**
The old inline format hard-coded ``$`` and 2 decimals — wrong for
EUR (``$1,500.00 EUR`` instead of ``€1,500.00``), wrong for JPY
(JPY has no decimals on the wire), wrong for any currency whose
symbol isn't ``$``. ``_format_money`` now delegates to
``babel.numbers.format_currency`` so the rendered string picks up
the right symbol, decimal-digit count, and grouping per ISO 4217.
Examples (verified in new ``TestFormatMoney`` cases):
- ``_format_money(1500.0, "USD")`` → ``"$1,500.00"``
- ``_format_money(1500.0, "EUR")`` → ``"€1,500.00"``
- ``_format_money(1500, "JPY")`` → ``"¥1,500"`` (no decimals)
- ``_format_money(None, "USD")`` → ``"$0.00"``
- Unknown ISO code → ``"XYZ1,500.00"`` (code prefix, doesn't raise)
Added ``babel>=2.17`` to ``katana_mcp_server/pyproject.toml`` (it
was already a transitive dep via mkdocs-material; promoting to a
direct dependency).
**Two Katana currency concepts, both surfaced**
The helper's docstring records the two-currency model so future
callers know which to pass:
- **Transaction currency** — ``SalesOrder.currency`` /
``PurchaseOrder.currency``; the currency line totals (``total``,
``price_per_unit``, ``cogs_value``) are denominated in.
- **Factory base currency** — ``Factory.base_currency_code``;
the tenant home currency. Pass this when formatting
``*_in_base_currency`` amounts. Threading factory data into
card builders is the remaining piece — currently only the
three migrated Total metrics receive transaction currency; the
variant-price builder falls back to USD because the factory
record isn't plumbed into it yet. Tracked as a follow-up.
**MCP boundary fixes for the #749 schema changes**
PR #749 reclassified two MO recipe row fields from ``number`` to
``string`` (their wire format). The consumer in
``_recipe_row_info_from_attrs`` passed the strings straight
through to ``RecipeRowInfo``'s ``float | None`` field annotations
— it worked via pydantic coercion but was inconsistent with the
boundary pattern established in #741 for SalesOrderRow. Wrapped
the affected reads with ``float_or_none(unwrap_unset(...))`` to
match. Also fixed ``MO operation row`` consumers for the five
string-on-wire fields that were already strings before #749.
And ``invoicing_status`` on ``SalesOrderSummary`` / the get-SO
response was passed bare while its sibling status fields used
``enum_to_str``. After #749 made it an actual enum, the bare
pass relied on StrEnum coincidence; brought it in line with
``status`` / ``production_status``.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>1 parent 8c3c69c commit b5f149d
6 files changed
Lines changed: 101 additions & 17 deletions
File tree
- katana_mcp_server
- src/katana_mcp/tools
- foundation
- tests
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
47 | 47 | | |
48 | 48 | | |
49 | 49 | | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
50 | 54 | | |
51 | 55 | | |
52 | 56 | | |
| |||
Lines changed: 19 additions & 8 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
60 | 60 | | |
61 | 61 | | |
62 | 62 | | |
| 63 | + | |
63 | 64 | | |
64 | 65 | | |
65 | 66 | | |
| |||
838 | 839 | | |
839 | 840 | | |
840 | 841 | | |
841 | | - | |
842 | | - | |
| 842 | + | |
| 843 | + | |
| 844 | + | |
| 845 | + | |
| 846 | + | |
| 847 | + | |
843 | 848 | | |
844 | 849 | | |
845 | 850 | | |
846 | 851 | | |
847 | 852 | | |
848 | 853 | | |
849 | 854 | | |
850 | | - | |
| 855 | + | |
851 | 856 | | |
852 | 857 | | |
853 | 858 | | |
| |||
885 | 890 | | |
886 | 891 | | |
887 | 892 | | |
888 | | - | |
889 | | - | |
890 | | - | |
| 893 | + | |
| 894 | + | |
| 895 | + | |
| 896 | + | |
| 897 | + | |
| 898 | + | |
| 899 | + | |
891 | 900 | | |
892 | 901 | | |
893 | | - | |
894 | | - | |
| 902 | + | |
| 903 | + | |
| 904 | + | |
| 905 | + | |
895 | 906 | | |
896 | 907 | | |
897 | 908 | | |
| |||
Lines changed: 2 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
917 | 917 | | |
918 | 918 | | |
919 | 919 | | |
920 | | - | |
| 920 | + | |
921 | 921 | | |
922 | 922 | | |
923 | 923 | | |
| |||
1335 | 1335 | | |
1336 | 1336 | | |
1337 | 1337 | | |
1338 | | - | |
| 1338 | + | |
1339 | 1339 | | |
1340 | 1340 | | |
1341 | 1341 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
48 | 48 | | |
49 | 49 | | |
50 | 50 | | |
| 51 | + | |
51 | 52 | | |
52 | 53 | | |
53 | 54 | | |
| |||
830 | 831 | | |
831 | 832 | | |
832 | 833 | | |
833 | | - | |
| 834 | + | |
| 835 | + | |
| 836 | + | |
| 837 | + | |
| 838 | + | |
| 839 | + | |
834 | 840 | | |
835 | 841 | | |
836 | 842 | | |
| |||
1339 | 1345 | | |
1340 | 1346 | | |
1341 | 1347 | | |
| 1348 | + | |
| 1349 | + | |
| 1350 | + | |
| 1351 | + | |
| 1352 | + | |
| 1353 | + | |
| 1354 | + | |
| 1355 | + | |
| 1356 | + | |
| 1357 | + | |
| 1358 | + | |
| 1359 | + | |
| 1360 | + | |
| 1361 | + | |
| 1362 | + | |
| 1363 | + | |
| 1364 | + | |
| 1365 | + | |
| 1366 | + | |
| 1367 | + | |
| 1368 | + | |
| 1369 | + | |
| 1370 | + | |
| 1371 | + | |
| 1372 | + | |
| 1373 | + | |
| 1374 | + | |
| 1375 | + | |
| 1376 | + | |
| 1377 | + | |
1342 | 1378 | | |
1343 | 1379 | | |
1344 | 1380 | | |
| |||
1850 | 1886 | | |
1851 | 1887 | | |
1852 | 1888 | | |
1853 | | - | |
| 1889 | + | |
| 1890 | + | |
| 1891 | + | |
1854 | 1892 | | |
1855 | 1893 | | |
1856 | 1894 | | |
| |||
1861 | 1899 | | |
1862 | 1900 | | |
1863 | 1901 | | |
1864 | | - | |
| 1902 | + | |
1865 | 1903 | | |
1866 | 1904 | | |
1867 | 1905 | | |
| |||
1885 | 1923 | | |
1886 | 1924 | | |
1887 | 1925 | | |
1888 | | - | |
| 1926 | + | |
1889 | 1927 | | |
1890 | 1928 | | |
1891 | 1929 | | |
| |||
1945 | 1983 | | |
1946 | 1984 | | |
1947 | 1985 | | |
1948 | | - | |
| 1986 | + | |
1949 | 1987 | | |
1950 | 1988 | | |
1951 | 1989 | | |
| |||
1966 | 2004 | | |
1967 | 2005 | | |
1968 | 2006 | | |
1969 | | - | |
| 2007 | + | |
1970 | 2008 | | |
1971 | 2009 | | |
1972 | 2010 | | |
| |||
2736 | 2774 | | |
2737 | 2775 | | |
2738 | 2776 | | |
2739 | | - | |
| 2777 | + | |
| 2778 | + | |
| 2779 | + | |
2740 | 2780 | | |
2741 | 2781 | | |
2742 | 2782 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
15 | 15 | | |
16 | 16 | | |
17 | 17 | | |
| 18 | + | |
18 | 19 | | |
19 | 20 | | |
20 | 21 | | |
| |||
112 | 113 | | |
113 | 114 | | |
114 | 115 | | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
115 | 142 | | |
116 | 143 | | |
117 | 144 | | |
| |||
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
0 commit comments