Add automatic pix#122
Conversation
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Review notesCross-checked the PR diff against the canonical 🔴 Blockers1. Webhook event dispatch is not actually registered. 2. 🟡 Important3. 4. Enum docstrings are incomplete vs. the public docs.
5. Permissive ⚪ Nits
Discarded false positives during cross-check
|
- starkinfra/event/__event.py — register pix-pull-subscription and pix-pull-request in _resource_by_subscription; add their log-resource imports; extend the Event.subscription docstring to list the two new keys plus the missing pix-dispute entry (item A; canonical keys are bare pix-pull-subscription / pix-pull-request, matching the node/php/dotnet SDKs) - starkinfra/pixpullsubscription/__pixpullsubscription.py:27 — expand `type` enum docstring from 2 values to the full set: push, qrcode, qrcodeAndPayment, paymentAndOrQrcode (item D) - starkinfra/pixpullsubscription/__pixpullsubscription.py:43 — expand `status` enum docstring from 4 values to the full set: active, approved, canceled, created, denied, expired, failed, pending (item D) - starkinfra/pixpullrequest/__pixpullrequest.py — remove `flow` from query() and page() signatures, docstrings, and forwards; flow is not a valid server query param for pix-pull-request (item C; the testPixPullRequest.py:34 comment that documented this is now consistent with the SDK signature) - tests/sdk/testPixPullSubscription.py — add TestPixPullSubscriptionNormalization that asserts due/installment_end empty-string -> None via the constructor; locks in the normalization at __pixpullsubscription.py:71-76 without requiring a sandbox-issued signature (item B, applied as constructor coverage since parse() happy-path requires a real signature) Items NOT addressed in this commit (deferred, rationale below): - Item E (tighten broad InputErrors except): the current pattern at testPixPullRequest.py:89-92 / :110-113 and the equivalent in testPixPullSubscription.py already uses `self.assertIn(err.code, allowed_codes)` inside the except, which surfaces any new/unexpected error code rather than swallowing. Splitting into happy-path vs sandbox-rejected cases is deferrable; the current assertion is not "silent". - Item F nits: keeping the one-off `if due == ""` normalization local to __pixpullsubscription.py until a second resource hits it (PixPullRequest does not yet do empty-string normalization in this SDK and was not flagged by this reviewer). Plural-id filter tests, log-level *_ids coverage, and fixed-offset fixture datetimes are nice-to-haves; not blockers.
Move assertEqual() calls out of the try block so they execute only when the API call succeeds, never silently skipped when the sandbox rejects a state transition with an allowed error code. - tests/sdk/testPixPullRequest.py:82-93 — TestPixPullRequestPatch.test_success: assertEqual(updated.id) moved after the except block; return added on the allowed-error path so skipping is explicit, not silent. - tests/sdk/testPixPullRequest.py:104-114 — TestPixPullRequestCancel.test_success: same restructure for pixpullrequest.cancel(). - tests/sdk/testPixPullSubscription.py:75-86 — TestPixPullSubscriptionPatch.test_success: same restructure for pixpullsubscription.update(). - tests/sdk/testPixPullSubscription.py:95-105 — TestPixPullSubscriptionCancel.test_success: same restructure for pixpullsubscription.cancel(). Item 2 (valid-signature parse() happy-path) is intentionally not included: the sandbox-issued (content, signature) pair required to exercise that path is not available in this environment. Deferred per explicit user decision. Co-Authored-By: Lucas Miranda <lucas.miranda@starkbank.com>
Original review points (🔴 / 🟡) below were raised by another Claude agent auditing commit 4644246. Each block quotes the point and explains the fix. ### API compliance (was 🔴) 1) Required fields on PixPullSubscription constructor Point: receiver_bank_code, reference_code, sender_city_code defaulted to None at __pixpullsubscription.py:52-53, but createPixPullSubscriptionView marks all three as required. Fix: promoted all three to required positional parameters; docstring updated to move them out of "Parameters (optional)". 2) Missing `flow` filter on PixPullRequest list endpoint Point: listPixPullRequestView documents flow ("in" | "out") as a filter, but query() and page() at __pixpullrequest.py:105-106,134-135 omit it. Fix: added flow=None to both signatures and forwarded to rest.get_stream / rest.get_page. Mirrors pixinfraction.query's flow handling. 3) PixPullSubscription cancel.reason enum Point: __pixpullsubscription.py:214 lists receiverInternalError and senderDeceased, which the API rejects. Accepted set per docs is accountClosed, receiverOrganizationClosed, subscriptionRequestFailed, fraud, receiverUserRequested, paymentNotFound. Fix: replaced the docstring options with the documented set. 4) Log type enums divergent on both Pix Pull resources Point: pixpullsubscription/log/__log.py:15,51,77 and pixpullrequest/log/__log.py:15,47 list sent/denied/failed/created/ success/approved/credited/refunded/processing; docs publish created/registered/updated/failed/canceling/canceled. Fix: replaced both docstrings with the documented set. 5) PixPullRequest cancel.reason must be optional Point: cancel(id, reason, user=None) at __pixpullrequest.py:185 forces reason positionally; cancelPixPullRequestView marks reason as optional. Fix: changed to cancel(id, reason=None, user=None). Matches the existing pixkey.cancel precedent at pixkey/__pixkey.py:179, which already passes reason as a query kwarg to delete_id when present. 6) PixPullSubscription `type` must be optional Point: __pixpullsubscription.py:50 forces type positionally; docs mark it optional. Fix: moved `type` to kwargs with default None; docstring re-classified. ### Doc/API consistency (was 🟡) - PixPullSubscription.update.status — was status=None; docs mark required. Promoted to required positional (def update(id, status, ...)). - PixPullRequest.update.reason — kept optional in signature (server enforces the conditional rule); docstring now lists it under "## Parameters (conditionally required):" when status="denied". - PixPullSubscription amount / amount_min_limit — added "## Parameters (conditionally required):" section stating at least one of the two MUST be provided. - PixPullRequest cancel.reason enum — docstring updated to the cancelPixPullRequestView set: accountClosed, accountBlocked, pixRequestFailed, other, senderUserRequested, receiverUserRequested. ### Tests (was 🟡 / 🔴) - tests/utils/pixPullSubscription.py — factory now sets sender_city_code (needed by the status="confirmed" patch test at testPixPullSubscription.py:78) and amount_min_limit; reordered to match the new required-positional contract. - testPixPullSubscription.py:34 — trivial assertEqual(len, 0) replaced with a real id round-trip: pre-query, then filter by those ids and assert the returned set is a subset (mirrors the testPixInfraction.py:71 pattern). - TestPixPullSubscriptionNormalization — constructor call updated to pass the new required fields. - testPixPullSubscriptionLog.py — added TestPixPullSubscriptionLogFilter exercising subscription_ids=[…] and asserting log.subscription.id matches. - testPixPullRequestLog.py — added TestPixPullRequestLogFilter exercising request_ids=[…] and asserting log.request.id matches. - testPixPullRequestLog.TestPixPullRequestLogInfoGet — `except InternalServerError: pass` replaced with assertEqual(str(e), "Houston, we have a problem.") because starkcore's InternalServerError carries only a string message, not a .errors list (verified at core-repos/python/starkcore/error.py:23-26). The update/cancel err.code pattern only applies to InputErrors. ### Not addressed in this commit (deliberate) - ""→None coercion inline at __pixpullsubscription.py:71-76: kept inline. check_datetime_or_date in starkcore does NOT accept empty strings, so the workaround is necessary today. Moving it into the core helper would touch core-repos/python, which is off-limits per project policy; that belongs in a separate starkcore PR. - "Filter Nones before rest.patch_id": not the SDK convention. pixinfraction.update and individualidentity.update pass Nones straight through; behavior unchanged here for consistency. - Parse round-trip happy path for PixPullSubscription: no signed-sandbox fixture utility exists; skipped. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
Adds support for the Pix Automático (Automatic Pix) feature: recurring debit authorizations and the per-cycle pulls that draw on them.
New resources
PixPullSubscription— recurring debit authorization. Full CRUD:create(batch),get,query,page,update,cancel. PlusLogsub-resource withget/query/page.PixPullRequest— single pull cycle against an active subscription. Full CRUD +Logsub-resource (same shape).Wiring
pix-pull-subscriptionandpix-pull-request-log.[Unreleased] → Added.Test plan
All integration tests run end-to-end against the sandbox:
testPixPullSubscription.py+testPixPullSubscriptionLog.py— CRUD round-trip,subscription_idsplural filter,Event.parsedispatch, M8 datetime normalization (empty-string → None fordue/installment_end).testPixPullRequest.py+testPixPullRequestLog.py— CRUD,request_idsplural filter, M12 noparsemethod on resource.Notes
cancelusesRest.delete_idwith thereasonforwarded as a query parameter, not body.due,installment_end) toNonebefore parsing.except InputErrorsguards where the sandbox enforces business rules outside the SDK's contract (state-transition restrictions, receiver-only roles). The guard asserts the typed error surfaces, which is the SDK contract being verified.🤖 Generated with Claude Code