Skip to content

Pthmint 108#54

Open
zulquer wants to merge 11 commits intomasterfrom
PTHMINT-108
Open

Pthmint 108#54
zulquer wants to merge 11 commits intomasterfrom
PTHMINT-108

Conversation

@zulquer
Copy link
Copy Markdown
Collaborator

@zulquer zulquer commented Apr 13, 2026

This pull request introduces several new Cloud POS and terminal management example scripts, improves environment variable configuration. It also adds new API managers to the public SDK interface. These changes collectively make it easier to work with Cloud POS flows, manage terminals and terminal groups, and configure the SDK for various environments.

zulquer added 11 commits April 13, 2026 15:44
Allow passing a custom API base_url for local development while preventing custom URLs in non-dev builds. Client now accepts base_url and resolves it via _resolve_base_url (uses MSP_SDK_BUILD_PROFILE, MSP_SDK_ALLOW_CUSTOM_BASE_URL, MSP_SDK_CUSTOM_BASE_URL); _normalize_base_url validates/normalizes the URL. Sdk forwards base_url to Client. Added unit tests covering default test/live URLs, dev-only custom URL acceptance, env-provided URL, and blocking in release/when flag disabled. README updated with usage and guardrails.
Reject invalid custom base URLs with query strings, fragments, or malformed hosts. Add unit coverage for invalid URL cases and document environment-variable precedence for custom base URLs.
Improve Client._normalize_base_url by rejecting URLs that include path parameters (parsed.params) and standardize the error message to "Invalid base URL.". Update unit tests to expect the new message, add a test ensuring an explicit base_url argument takes precedence over environment settings, and add a test that rejects base URLs containing params.
Use a dedicated E2E_API_KEY, centralize E2E SDK bootstrap in shared fixtures, and keep end-to-end tests isolated from the general SDK environment configuration. Update the E2E documentation and environment example accordingly.
Ensure E2E fixtures remain isolated from local custom-base-url overrides. The E2E SDK factory now temporarily clears MSP_SDK_BUILD_PROFILE, MSP_SDK_ALLOW_CUSTOM_BASE_URL and MSP_SDK_CUSTOM_BASE_URL while instantiating the SDK, then restores previous values. Added a guard to assert the resulting client URL is Client.TEST_URL, so E2E always targets the test environment when using E2E_API_KEY.
Introduce POS and terminal-related functionality and add order cancel support. Added PosManager (get_receipt) with POS receipt models and components; TerminalManager (create/get terminals) with CreateTerminalRequest and Terminal response model; TerminalGroupManager (list terminals by group). Added request/response models for cancelling an order transaction (CancelTransactionRequest, CancelTransaction) and wired cancel_transaction into OrderManager. Exposed new managers via api.paths and Sdk getters. Includes validation, custom response adapters and pager/listing support.
Introduce a credential resolver API and wire scoped auth into the client and managers. Adds src/multisafepay/client/credential_resolver.py (AuthScope, CredentialResolver protocol, ScopedCredentialResolver). Client now accepts an optional CredentialResolver, exposes auth scope constants, and supports an auth_scope argument for endpoint requests; it normalizes scopes, resolves API keys via the resolver, and uses the resolved key in Authorization headers. Updated managers to pass AuthScope for terminal-group and partner-affiliate requests and exported resolver types from client.__init__. The SDK constructor now accepts a credential_resolver to propagate into Client. Terminal-group resolution enforces group_id and falls back to defaults when appropriate.
Introduce SSE event stream support and Cloud POS/terminal examples. Added EventStream parsing (SSE) and EventManager helpers, plus unit tests for both. Updated Order response to normalize legacy/singular event fields (events_token/events_stream_url) and updated OrderManager.create to accept terminal_group_id and pass a terminal-group AuthScope. Made Client and Sdk accept optional api_key (require credential_resolver when missing) and added validation in ScopedCredentialResolver; improved credential resolution for partner and default scopes. Small API tweaks: CreateTerminalRequest default values and param type adjustments. Many example scripts and integration/unit tests added to cover the new functionality.
@codecov
Copy link
Copy Markdown

codecov bot commented Apr 13, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 88.67%. Comparing base (ee15a54) to head (2ab39c0).
⚠️ Report is 1 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master      #54      +/-   ##
==========================================
- Coverage   90.81%   88.67%   -2.14%     
==========================================
  Files         147      173      +26     
  Lines        2579     3187     +608     
==========================================
+ Hits         2342     2826     +484     
- Misses        237      361     +124     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR expands the Python SDK’s support for Cloud POS workflows by adding scoped credential resolution, event streaming helpers, and new terminal/POS managers, while also improving environment configuration for custom base URLs and E2E testing.

Changes:

  • Added CredentialResolver/AuthScope support in Client/Sdk to enable scoped API-key selection (default / partner-affiliate / terminal-group).
  • Introduced new managers and models for events (SSE), POS receipts, terminals, and terminal groups; updated order responses for legacy/plural events field compatibility.
  • Refactored E2E tests to use dedicated E2E_* environment variables and added extensive unit tests for the new behavior.

Reviewed changes

Copilot reviewed 75 out of 75 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
tests/multisafepay/unit/test_unit_sdk.py SDK guardrails + resolver wiring tests
tests/multisafepay/unit/client/test_unit_credential_resolver.py Scoped credential resolver unit tests
tests/multisafepay/unit/client/test_unit_client.py Client base URL + auth scope/resolver tests
tests/multisafepay/unit/api/path/terminals/response/test_unit_terminal_response.py Terminal response model tests
tests/multisafepay/unit/api/path/terminals/request/test_unit_create_terminal_request.py CreateTerminalRequest tests
tests/multisafepay/unit/api/path/orders/response/test_unit_order_response.py Order events field compatibility tests
tests/multisafepay/unit/api/path/orders/manager/test_unit_order_manager.py OrderManager terminal-group scope tests
tests/multisafepay/unit/api/path/events/test_unit_event_manager.py EventManager subscription helper tests
tests/multisafepay/unit/api/path/events/stream/test_unit_event_stream.py SSE parsing tests for EventStream
tests/multisafepay/integration/api/path/orders/manager/test_integration_order_manager_create.py Integration-style tests updated for events/auth scope
tests/multisafepay/e2e/examples/transport/test_custom_urllib3_transport.py E2E transport example uses shared E2E fixtures
tests/multisafepay/e2e/examples/transport/test_custom_requests_session_transport.py E2E requests.Session transport fixture refactor
tests/multisafepay/e2e/examples/transport/test_custom_httpx_transport.py E2E httpx transport fixture refactor
tests/multisafepay/e2e/examples/transaction_manager/test_get_transactions.py E2E uses e2e_sdk fixture
tests/multisafepay/e2e/examples/recurring_manager/test_recurring.py E2E uses e2e_sdk fixture
tests/multisafepay/e2e/examples/payment_method_manager/test_get_payment_methods.py E2E uses e2e_sdk fixture
tests/multisafepay/e2e/examples/payment_method_manager/test_get_by_gateway_code.py E2E uses e2e_sdk fixture
tests/multisafepay/e2e/examples/order_manager/test_update.py E2E uses e2e_sdk fixture
tests/multisafepay/e2e/examples/order_manager/test_refund.py E2E uses e2e_sdk fixture
tests/multisafepay/e2e/examples/order_manager/test_refund_by_shopping_cart.py E2E uses e2e_sdk fixture
tests/multisafepay/e2e/examples/order_manager/test_refund_by_item.py E2E uses e2e_sdk fixture
tests/multisafepay/e2e/examples/order_manager/test_get_order.py E2E uses e2e_sdk fixture
tests/multisafepay/e2e/examples/order_manager/test_create.py E2E uses e2e_sdk fixture
tests/multisafepay/e2e/examples/order_manager/test_capture.py E2E uses e2e_sdk fixture
tests/multisafepay/e2e/examples/me_manager/test_get_me.py E2E uses e2e_sdk fixture
tests/multisafepay/e2e/examples/issuer_manager/test_get_issuers_by_gateway_code.py E2E uses e2e_sdk fixture
tests/multisafepay/e2e/examples/gateway_manager/test_get_gateways.py E2E uses e2e_sdk fixture
tests/multisafepay/e2e/examples/gateway_manager/test_get_by_code.py E2E uses e2e_sdk fixture
tests/multisafepay/e2e/examples/category_manager/test_get_categories.py E2E uses e2e_sdk fixture
tests/multisafepay/e2e/examples/capture_manager/test_capture_reservation_cancel.py E2E uses e2e_sdk fixture
tests/multisafepay/e2e/examples/auth_manager/test_get_api_token.py E2E uses e2e_sdk fixture
tests/multisafepay/e2e/conftest.py Adds E2E_API_KEY/E2E_BASE_URL fixtures + validation
src/multisafepay/sdk.py Public SDK surface expanded (events/pos/terminals/groups)
src/multisafepay/client/credential_resolver.py Adds resolver protocol + scoped resolver + AuthScope
src/multisafepay/client/client.py Base URL guardrails + scoped auth header resolution
src/multisafepay/client/init.py Exposes new resolver/public types
src/multisafepay/api/paths/terminals/terminal_manager.py Adds /json/terminals manager
src/multisafepay/api/paths/terminals/response/terminal.py Adds Terminal response model
src/multisafepay/api/paths/terminals/response/init.py Exports terminal response models
src/multisafepay/api/paths/terminals/request/create_terminal_request.py Adds create-terminal request model
src/multisafepay/api/paths/terminals/request/init.py Exports terminal request models
src/multisafepay/api/paths/terminals/init.py Exposes TerminalManager
src/multisafepay/api/paths/terminal_groups/terminal_group_manager.py Adds terminal-group listing manager
src/multisafepay/api/paths/terminal_groups/init.py Exposes TerminalGroupManager
src/multisafepay/api/paths/pos/receipt/response/receipt.py Adds Receipt response model
src/multisafepay/api/paths/pos/receipt/response/components/related_transactions.py Receipt related-transactions component
src/multisafepay/api/paths/pos/receipt/response/components/payment.py Receipt payment component
src/multisafepay/api/paths/pos/receipt/response/components/order.py Receipt order + item/tip component models
src/multisafepay/api/paths/pos/receipt/response/components/merchant.py Receipt merchant component
src/multisafepay/api/paths/pos/receipt/response/components/init.py Exports receipt component models
src/multisafepay/api/paths/pos/receipt/response/init.py Exports receipt response models
src/multisafepay/api/paths/pos/receipt/init.py POS receipt package init
src/multisafepay/api/paths/pos/pos_manager.py Adds POS receipt retrieval manager
src/multisafepay/api/paths/pos/init.py Exposes PosManager
src/multisafepay/api/paths/orders/response/order_response.py Adds plural events fields + normalization
src/multisafepay/api/paths/orders/order_manager.py Adds terminal-group scoping + cancel endpoint
src/multisafepay/api/paths/orders/order_id/cancel/response/cancel_transaction.py Adds cancel-transaction response model
src/multisafepay/api/paths/orders/order_id/cancel/response/init.py Exports cancel response models
src/multisafepay/api/paths/orders/order_id/cancel/request/cancel_transaction_request.py Adds cancel-transaction request model
src/multisafepay/api/paths/orders/order_id/cancel/request/init.py Exports cancel request models
src/multisafepay/api/paths/orders/order_id/cancel/init.py Cancel endpoint package init
src/multisafepay/api/paths/events/stream/event_stream.py Adds SSE stream opener/parser
src/multisafepay/api/paths/events/stream/init.py Exposes EventStream/Event types
src/multisafepay/api/paths/events/event_manager.py Adds event subscription helpers
src/multisafepay/api/paths/events/init.py Exposes EventManager
src/multisafepay/api/paths/init.py Public paths exports include new managers
README.md Documents base URL guardrails + E2E env vars
examples/terminal_manager/get_terminals.py Terminal listing example using resolver
examples/terminal_manager/create.py Terminal creation example
examples/terminal_group_manager/get_terminals_by_group.py Terminal-group listing example
examples/pos_manager/get_receipt.py Cloud POS receipt flow example
examples/order_manager/cloud_pos_order.py Cloud POS order creation example
examples/order_manager/cancel.py Cloud POS cancel flow example
examples/event_manager/subscribe_events.py Cloud POS event subscription example
.env.example Adds E2E/POS/partner env variable examples

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +77 to +83
response = self.client.create_get_request(
endpoint,
context=context,
auth_scope=AuthScope(
scope=Client.AUTH_SCOPE_TERMINAL_GROUP,
group_id=terminal_group_id,
),
Comment on lines +347 to +353
response = self.client.create_post_request(
endpoint,
context=context,
auth_scope=AuthScope(
scope=Client.AUTH_SCOPE_TERMINAL_GROUP,
group_id=terminal_group_id,
),
Comment on lines +67 to +70
def add_group_id(
self: "CreateTerminalRequest",
group_id: str,
) -> "CreateTerminalRequest":
Comment on lines +64 to +69
.add_currency("EUR")
.add_gateway_info(
{
"terminal_id": terminal_id,
},
)
Comment on lines +31 to +37
def _validate_e2e_base_url(base_url: str) -> str:
parsed = urlparse(base_url)
if parsed.scheme != "https" or not parsed.netloc:
msg = f"{E2E_BASE_URL_ENV} must be a valid https URL"
raise pytest.UsageError(msg)

parsed = urlparse(base_url)
Comment on lines +263 to +270
def _create_endpoint_request(
self: "Client",
method: str,
endpoint: str,
params: Optional[dict[str, Any]] = None,
request_body: Optional[dict[str, Any]] = None,
context: Optional[dict[str, Any]] = None,
*,
Comment on lines +35 to +45
id: Optional[str]
provider: Optional[str]
name: Optional[str]
code: Optional[str]
created: Optional[str]
last_updated: Optional[str]
manufacturer_id: Optional[str]
serial_number: Optional[str]
active: Optional[bool]
group_id: Optional[int]
country: Optional[str]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants