Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions examples/order_manager/cancel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Copyright (c) MultiSafepay, Inc. All rights reserved.

# This file is licensed under the Open Software License (OSL) version 3.0.
# For a copy of the license, see the LICENSE.txt file in the project root.

# See the DISCLAIMER.md file for disclaimer details.

"""Create a Cloud POS order, wait 5 seconds, and cancel it."""

import os
import time

from dotenv import load_dotenv

from multisafepay import Sdk
from multisafepay.api.paths.orders.request import OrderRequest
from multisafepay.client import ScopedCredentialResolver

load_dotenv()

DEFAULT_ACCOUNT_API_KEY = os.getenv("API_KEY", "")
TERMINAL_GROUP_DEFAULT_API_KEY = os.getenv("TERMINAL_GROUP_API_KEY_GROUP_DEFAULT", "")
CLOUD_POS_TERMINAL_GROUP_ID = os.getenv("CLOUD_POS_TERMINAL_GROUP_ID", "Default")
TERMINAL_ID = os.getenv("CLOUD_POS_TERMINAL_ID", "")

if __name__ == "__main__":
credential_resolver = ScopedCredentialResolver(
default_api_key=DEFAULT_ACCOUNT_API_KEY,
terminal_group_api_keys={
CLOUD_POS_TERMINAL_GROUP_ID: TERMINAL_GROUP_DEFAULT_API_KEY,
},
)

multisafepay_sdk = Sdk(
is_production=False,
credential_resolver=credential_resolver,
)
order_manager = multisafepay_sdk.get_order_manager()

order_request = (
OrderRequest()
.add_type("redirect")
.add_order_id(f"cloud-pos-cancel-{int(time.time())}")
.add_description("Cloud POS cancel order")
.add_amount(100)
.add_currency("EUR")
.add_gateway_info({"terminal_id": TERMINAL_ID})
)

create_response = order_manager.create(
order_request,
terminal_group_id=CLOUD_POS_TERMINAL_GROUP_ID,
)
order = create_response.get_data()
order_id = order.order_id

print(f"Created Cloud POS order: {order_id}")
print("Waiting 5 seconds before cancel...")
time.sleep(5)

cancel_response = order_manager.cancel_transaction(
order_id,
terminal_group_id=CLOUD_POS_TERMINAL_GROUP_ID,
)

print(f"Canceled Cloud POS order: {order_id}")
print(cancel_response.get_data())
58 changes: 58 additions & 0 deletions examples/order_manager/cloud_pos_order.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Copyright (c) MultiSafepay, Inc. All rights reserved.

# This file is licensed under the Open Software License (OSL) version 3.0.
# For a copy of the license, see the LICENSE.txt file in the project root.

# See the DISCLAIMER.md file for disclaimer details.

"""Create a Cloud POS order using terminal-group scoped authentication."""

import os
import time

from dotenv import load_dotenv

from multisafepay import Sdk
from multisafepay.api.paths.orders.request import OrderRequest
from multisafepay.client import ScopedCredentialResolver

load_dotenv()

DEFAULT_ACCOUNT_API_KEY = os.getenv("API_KEY", "")
TERMINAL_GROUP_DEFAULT_API_KEY = os.getenv("TERMINAL_GROUP_API_KEY_GROUP_DEFAULT", "")
CLOUD_POS_TERMINAL_GROUP_ID = os.getenv("CLOUD_POS_TERMINAL_GROUP_ID", "Default")
TERMINAL_ID = os.getenv("CLOUD_POS_TERMINAL_ID", "")

if __name__ == "__main__":
credential_resolver = ScopedCredentialResolver(
default_api_key=DEFAULT_ACCOUNT_API_KEY,
terminal_group_api_keys={
CLOUD_POS_TERMINAL_GROUP_ID: TERMINAL_GROUP_DEFAULT_API_KEY,
},
)

multisafepay_sdk = Sdk(
is_production=False,
credential_resolver=credential_resolver,
)
order_manager = multisafepay_sdk.get_order_manager()

order_request = (
OrderRequest()
.add_type("redirect")
.add_order_id(f"cloud-pos-{int(time.time())}")
.add_description("Cloud POS order")
.add_amount(100)
.add_currency("EUR")
.add_gateway_info({"terminal_id": TERMINAL_ID})
)

create_response = order_manager.create(
order_request,
terminal_group_id=CLOUD_POS_TERMINAL_GROUP_ID,
)
order = create_response.get_data()

print(f"Created Cloud POS order: {order.order_id}")
if order.payment_url:
print(f"Payment URL: {order.payment_url}")
47 changes: 47 additions & 0 deletions examples/pos_manager/get_receipt.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Copyright (c) MultiSafepay, Inc. All rights reserved.

# This file is licensed under the Open Software License (OSL) version 3.0.
# For a copy of the license, see the LICENSE.txt file in the project root.

# See the DISCLAIMER.md file for disclaimer details.

"""Fetch the receipt for an existing Cloud POS order."""

import os

from dotenv import load_dotenv

from multisafepay import Sdk
from multisafepay.client import ScopedCredentialResolver

load_dotenv()

DEFAULT_ACCOUNT_API_KEY = os.getenv("API_KEY", "")
TERMINAL_GROUP_DEFAULT_API_KEY = os.getenv("TERMINAL_GROUP_API_KEY_GROUP_DEFAULT", "")
CLOUD_POS_TERMINAL_GROUP_ID = os.getenv("CLOUD_POS_TERMINAL_GROUP_ID", "Default")
ORDER_ID = os.getenv("CLOUD_POS_ORDER_ID", "")

if __name__ == "__main__":
if not ORDER_ID:
raise SystemExit(
"Set CLOUD_POS_ORDER_ID to a completed Cloud POS order id "
"(receipts are only available for completed orders).",
)

credential_resolver = ScopedCredentialResolver(
default_api_key=DEFAULT_ACCOUNT_API_KEY,
terminal_group_api_keys={
CLOUD_POS_TERMINAL_GROUP_ID: TERMINAL_GROUP_DEFAULT_API_KEY,
},
)
multisafepay_sdk = Sdk(
is_production=False,
credential_resolver=credential_resolver,
)
pos_manager = multisafepay_sdk.get_pos_manager()

receipt_response = pos_manager.get_receipt(
order_id=ORDER_ID,
terminal_group_id=CLOUD_POS_TERMINAL_GROUP_ID,
)
print(receipt_response.get_data())
8 changes: 8 additions & 0 deletions src/multisafepay/api/paths/orders/order_id/cancel/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Copyright (c) MultiSafepay, Inc. All rights reserved.

# This file is licensed under the Open Software License (OSL) version 3.0.
# For a copy of the license, see the LICENSE.txt file in the project root.

# See the DISCLAIMER.md file for disclaimer details.

"""Cancel operations and endpoints for specific orders."""
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Copyright (c) MultiSafepay, Inc. All rights reserved.

# This file is licensed under the Open Software License (OSL) version 3.0.
# For a copy of the license, see the LICENSE.txt file in the project root.

# See the DISCLAIMER.md file for disclaimer details.

"""Request models for order cancellation operations."""

from multisafepay.api.paths.orders.order_id.cancel.request.cancel_transaction_request import (
CancelTransactionRequest,
)

__all__ = [
"CancelTransactionRequest",
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Copyright (c) MultiSafepay, Inc. All rights reserved.

# This file is licensed under the Open Software License (OSL) version 3.0.
# For a copy of the license, see the LICENSE.txt file in the project root.

# See the DISCLAIMER.md file for disclaimer details.

"""Request model for cancel transaction endpoint."""

from multisafepay.model.request_model import RequestModel


class CancelTransactionRequest(RequestModel):
"""
Represents a request to cancel a POS transaction.

Attributes
----------
order_id (str): The order identifier used in the endpoint path.

"""

order_id: str

def add_order_id(
self: "CancelTransactionRequest",
order_id: str,
) -> "CancelTransactionRequest":
"""
Adds order id to the cancellation request.

Parameters
----------
order_id (str): The order identifier.

Returns
-------
CancelTransactionRequest: The updated request instance.

"""
self.order_id = order_id
return self
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Copyright (c) MultiSafepay, Inc. All rights reserved.

# This file is licensed under the Open Software License (OSL) version 3.0.
# For a copy of the license, see the LICENSE.txt file in the project root.

# See the DISCLAIMER.md file for disclaimer details.

"""Response models for order cancellation outcomes."""

from multisafepay.api.paths.orders.order_id.cancel.response.cancel_transaction import (
CancelTransaction,
)

__all__ = [
"CancelTransaction",
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# Copyright (c) MultiSafepay, Inc. All rights reserved.

# This file is licensed under the Open Software License (OSL) version 3.0.
# For a copy of the license, see the LICENSE.txt file in the project root.

# See the DISCLAIMER.md file for disclaimer details.

"""Response model for order cancellation endpoint payload."""

from typing import Optional

from multisafepay.api.base.decorator import Decorator
from multisafepay.api.paths.orders.response.components.payment_details import (
PaymentDetails,
)
from multisafepay.api.shared.costs import Costs
from multisafepay.api.shared.custom_info import CustomInfo
from multisafepay.api.shared.customer import Customer
from multisafepay.api.shared.payment_method import PaymentMethod
from multisafepay.model.response_model import ResponseModel


class CancelTransaction(ResponseModel):
"""
Represents the `data` payload returned by cancel order transaction.

Attributes
----------
costs (Optional[list[Costs]]): The costs of the order.
created (Optional[str]): Creation timestamp.
modified (Optional[str]): Last modification timestamp.
custom_info (Optional[CustomInfo]): Additional custom info.
customer (Optional[Customer]): The customer data.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

There is no "customer" in this response.
https://docs.multisafepay.com/reference/cancelpostransaction#response-schemas
For your reference: the following is a raw response returned by the cancel endpoint:

{'success': True, 'data': {'costs': [], 'created': '2026-05-05T14:17:08', 'custom_info': {'custom_1': None, 'custom_2': None, 'custom_3': None}, 'fastcheckout': 'NO', 'financial_status': None, 'modified': '2026-05-05T14:17:13', 'order_id': 'cloud-pos-cancel-1777983428', 'payment_details': {}, 'payment_methods': None, 'status': 'cancelled'}}

fastcheckout (Optional[str]): Fastcheckout flag/status.
financial_status (Optional[str]): Financial status.
items (Optional[str]): Rendered items payload.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

There is no "items" in this response.
https://docs.multisafepay.com/reference/cancelpostransaction#response-schemas

For your reference: the following is a raw response returned by the cancel endpoint:

{'success': True, 'data': {'costs': [], 'created': '2026-05-05T14:17:08', 'custom_info': {'custom_1': None, 'custom_2': None, 'custom_3': None}, 'fastcheckout': 'NO', 'financial_status': None, 'modified': '2026-05-05T14:17:13', 'order_id': 'cloud-pos-cancel-1777983428', 'payment_details': {}, 'payment_methods': None, 'status': 'cancelled'}}

payment_details (Optional[PaymentDetails]): Payment details.
payment_methods (Optional[list[PaymentMethod]]): Payment methods.
status (Optional[str]): Order status.

"""

costs: Optional[list[Costs]]
created: Optional[str]
modified: Optional[str]
custom_info: Optional[CustomInfo]
customer: Optional[Customer]
fastcheckout: Optional[str]
financial_status: Optional[str]
items: Optional[str]
payment_details: Optional[PaymentDetails]
payment_methods: Optional[list[PaymentMethod]]
status: Optional[str]

@staticmethod
def from_dict(d: dict) -> Optional["CancelTransaction"]:
"""
Create a CancelTransaction from dictionary data.

Parameters
----------
d (dict): The cancellation response data.

Returns
-------
Optional[CancelTransaction]: A cancellation response instance or None.

"""
if d is None:
return None
cancel_dependency_adapter = Decorator(dependencies=d)
dependencies = (
cancel_dependency_adapter.adapt_costs(d.get("costs"))
.adapt_custom_info(d.get("custom_info"))
.adapt_payment_details(d.get("payment_details"))
.adapt_payment_methods(d.get("payment_methods"))
.get_dependencies()
)
return CancelTransaction(**dependencies)
Loading
Loading