-
Notifications
You must be signed in to change notification settings - Fork 19
Add Klarna Adapter #59
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
Einswilli
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for contributoins!
easyswitch/integrators/klarna.py
Outdated
|
|
||
| def validate_credentials(self) -> bool: | ||
| """Validate Klarna API credentials.""" | ||
| return bool(self.config.api_key and getattr(self.config, "api_username", None)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think api_username must be in the extra attr.
self.config here is an instance of ProviderConfig so it'd be better to have api_username and other aggregator specific config attrs in extra...
easyswitch/integrators/klarna.py
Outdated
| """Validate Klarna webhook signature (if provided).""" | ||
| # Klarna allows optional signature validation via HMAC | ||
| signature = headers.get("klarna-signature") | ||
| secret = getattr(self.config, "webhook_secret", None) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Put webhook_secret in self.contiig.extra.
| "locale": "en-SE", | ||
| "order_amount": int(transaction.amount * 100), | ||
| "order_tax_amount": 0, | ||
| "order_lines": [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Plase can you explain this section to me??? :-)
easyswitch/integrators/klarna.py
Outdated
| } | ||
| ], | ||
| "merchant_urls": { | ||
| "confirmation": transaction.callback_url or "https://example.com/confirm", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use transaction.callback_url or self.config.callback_url.
easyswitch/integrators/klarna.py
Outdated
| transaction_id=data.get("session_id"), | ||
| reference=transaction.reference, | ||
| provider=self.provider_name(), | ||
| status=TransactionStatus.PENDING.value, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need unnecessary .value here.
easyswitch/integrators/klarna.py
Outdated
| raw_response=data, | ||
| ) | ||
|
|
||
| async def cancel_transaction(self, transaction_id: str) -> None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cancel_transaction must return a boolean.
| @pytest.fixture | ||
| def klarna_config(): | ||
| return { | ||
| "api_username": "test_user", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This goes to extra...
| "api_username": "test_user", | ||
| "api_key": "test_key", | ||
| "environment": "sandbox", | ||
| "webhook_secret": "secret123", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also this...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you'll need to refractor tests based on the adapter changes...
|
I have done the changes, please check once |
|
Hey @Einswilli Can you please accept the pr, if the changes are correct? |
|
Hi @Sakshi146-eng can you please provide a screenshot of the tests??? |
Klarna Payment Adapter Integration
This PR introduces a new payment adapter for Klarna, enabling global “Pay Later” and “Pay Now” transactions via the EasySwitch SDK.
Addresses issue #58
✨ What's New
New Adapter:
KlarnaIntegratorfollowing the EasySwitchBaseAdapterinterfaceGlobal Support: Integration with Klarna’s REST API covering EU, US, and APAC regions
Flexible Payment Options: Supports deferred, installment, and direct payment methods
HMAC Webhook Security: Validates all incoming webhook signatures securely
Comprehensive Unit Tests & Documentation: Ensures full coverage and integration clarity
🌍 Supported Regions & Currencies
🔒 Webhook Security
Uses HMAC-SHA256 with the configured
webhook_secretValidates signature through
validate_webhook()Parses payload and normalizes status via
parse_webhook()Raises
PaymentErrorfor invalid or tampered webhooks🏗️ Architecture
Inherits from
BaseAdapterImplements all core abstract methods:
send_payment()check_status()refund()cancel_transaction()get_transaction_detail()Registered via
@AdaptersRegistry.register("klarna")Returns unified response types (
TransactionResult,WebhookEvent)Consistent exception handling through
PaymentError🧪 Tests
Unit Tests:
tests/test_klarna.pyCoverage includes:
Credential validation
Header generation (Base64 Auth)
Webhook parsing and signature validation
Transaction formatting and sending
Error handling for failed requests
Run with:
🚫 Unsupported / Not Implemented
❌ Partial refund operations (currently under evaluation)
❌ Currency conversion between unsupported Klarna markets