Add automatic pix#122
Conversation
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
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 <[email protected]>
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) <[email protected]>
| """# Retrieve a specific PixPullRequest.Log | ||
| ## Parameters (required): | ||
| - id [string]: object unique id. ex: "5656565656565656" | ||
| ## Return: |
There was a problem hiding this comment.
Faltou a opção do user aqui:
## Parameters (optional):
- user [Organization/Project object, default None]: Organization or Project object. Not necessary if starkinfra.user was set before function call
| - before [datetime.date or string, default None] | ||
| - types [list of strings, default None] | ||
| - request_ids [list of strings, default None]: list of PixPullRequest ids to filter retrieved objects. | ||
| - user [Organization/Project object, default None] |
There was a problem hiding this comment.
Bom mudar para o mesmo formato do comentário do GET supracitado
|
|
||
|
|
||
| def page(cursor=None, limit=None, after=None, before=None, types=None, request_ids=None, user=None): | ||
| """# Retrieve paged PixPullRequest.Logs |
There was a problem hiding this comment.
Faltaram os parâmetros de filtro aqui
| - ids [list of strings, default None]: list of ids to filter retrieved objects. | ||
| - subscription_ids [list of strings, default None]: filter by parent PixPullSubscription ids. | ||
| - flow [string, default None]: direction of money flow. Options: "in", "out". | ||
| - user [Organization/Project object, default None]: Organization or Project object. |
There was a problem hiding this comment.
Adicionar Not necessary if starkinfra.user was set before function call.
| - ids [list of strings, default None] | ||
| - subscription_ids [list of strings, default None] | ||
| - flow [string, default None]: direction of money flow. Options: "in", "out". | ||
| - user [Organization/Project object, default None] |
There was a problem hiding this comment.
Colocar o mesmo complemento supracitado
| _ALPHANUM = string.ascii_uppercase + string.digits | ||
|
|
||
|
|
||
| def _generate_end_to_end_id(): |
There was a problem hiding this comment.
já tem um método que gera o e2e, está no utils do SDK
| - tags [list of strings, default None]: tags to filter retrieved objects. | ||
| - ids [list of strings, default None]: list of ids to filter retrieved objects. | ||
| - subscription_ids [list of strings, default None]: filter by parent PixPullSubscription ids. | ||
| - flow [string, default None]: direction of money flow. Options: "in", "out". |
There was a problem hiding this comment.
Aqui é "flows", no plural
| tags=tags, | ||
| ids=ids, | ||
| subscription_ids=subscription_ids, | ||
| flow=flow, |
|
|
||
|
|
||
| def query(limit=None, after=None, before=None, status=None, tags=None, ids=None, user=None): | ||
| """# Retrieve PixPullSubscriptions |
There was a problem hiding this comment.
Faltou o parâmetro opcional "flows"
| import starkinfra | ||
| from datetime import datetime | ||
|
|
||
| subscriptions = starkinfra.pixpullsubscription.create([ |
There was a problem hiding this comment.
Esse exemplo não funciona, estão faltando campos obrigatórios (receiver_bank_code, reference_code e sender_city_code)
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