Fix: Spell receiptUrl the way the 2.1 schemas do - #780
Merged
Merged
Conversation
snake_to_camel_case turns any key ending in _url into ...URL. That is right for
responderURL, and ocpp_csms_url is already special-cased, but the OCPP 2.1
NotifySettlement schemas spell the field receiptUrl - so a NotifySettlement
carrying a receipt is serialised as receiptURL and rejected by the library's own
payload validation, in both directions:
>>> snake_to_camel_case({"receipt_url": "https://example.com/r/1"})
{'receiptURL': 'https://example.com/r/1'}
jsonschema.exceptions.ValidationError:
Additional properties are not allowed ('receiptURL' was unexpected)
A charging station reporting a settled payment therefore cannot send the receipt
URL it generated, and cannot receive the one the CSMS generated.
receiptUrl, responderURL and ocppCsmsUrl are the only URL-shaped keys in the 2.1
schemas, so this completes the set. camel_to_snake_case already reverses
receiptUrl correctly; a test is added for both directions.
There was a problem hiding this comment.
Copilot review overview
🟢 Approval recommended
The focused change matches the NotifySettlement schemas and has tests for both conversions.
Review effort: Balanced
Findings: None
What changed in this PR
This PR makes URL field conversion match the OCPP 2.1 NotifySettlement schemas, so receipt URLs use receiptUrl.
Changes:
- Special-cases
receipt_urlduring serialization. - Adds tests for conversion in both directions.
| File | Description |
|---|---|
| tests/test_charge_point.py | Tests both receiptUrl conversions. |
| ocpp/charge_point.py | Serializes receipt_url as receiptUrl. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
mdwcrft
approved these changes
Sep 30, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Current behavior
snake_to_camel_caserewrites any key ending in_urlto...URL. That is correct forresponderURL, andocpp_csms_urlis already special-cased just above it, but OCPP 2.1spells the NotifySettlement field
receiptUrl:The library therefore produces a payload its own validation rejects, in both directions:
In practice a charging station reporting a settled payment can neither send the receipt
URL it generated nor relay the one the CSMS returned —
NotifySettlementRequestandNotifySettlementResponseboth carryreceiptUrl, so both fail withFormatViolationand the receipt is lost. Found on a live 2.1 link between a charging station and a CSMS,
where the CSMS answered with a correct
receiptUrland the station's own schema checkrefused it on the way back.
The comment above these lines already notes that the spec is inconsistent about URL
casing;
receipt_urlis simply a case that was never added.New behavior
One replacement alongside the existing
ocpp_csms_urlcase:camel_to_snake_casealready reversesreceiptUrlcorrectly, so nothing was neededthere; a test covers both directions.
Impact
No breaking change, and nothing to do for users.
receiptUrl,responderURLandocppCsmsUrlare the complete set of URL-shaped keysacross the 1.6, 2.0.1 and 2.1 schemas.
responderURLandocppCsmsUrlare untouchedand serialise exactly as before; this completes the set.
receiptfield at all, so no message in any earlier versiongoes near this rule.
receipt_urlappears in exactly two places in the library,v21/call.pyandv21/call_result.py, bothNotifySettlement.receiptURL, so the old spelling was never validand nothing can have depended on it — anything that produced it was already being
rejected by payload validation.
Checklist
pytest testspasses (tests/test_messages.pyneedshypothesis, which myenvironment lacks; it is untouched by this change).
One row added to each of the existing
test_snake_to_camel_caseandtest_camel_to_snake_casetables, so both directions are covered.black --check,isort --check-onlyandflake8 --config .flake8are clean on thechanged files.