From 657c07cbb4a4e4cfac95b2cb64eb5eaaf42d43b7 Mon Sep 17 00:00:00 2001 From: deryacakmak <97deryacakmak@gmail.com> Date: Wed, 3 Jun 2026 11:48:11 +0300 Subject: [PATCH 1/4] Add meal voucher card tokenization functionality and remove unused BKM Express methods --- craftgate/__init__.py | 3 + craftgate/adapter/__init__.py | 1 + .../adapter/bkm_express_payment_adapter.py | 11 --- .../meal_voucher_card_tokenization_adapter.py | 50 ++++++++++++++ craftgate/request/__init__.py | 5 +- .../meal_voucher_card_tokenization_data.py | 15 +++++ ..._meal_voucher_card_tokenization_request.py | 14 ++++ ...cher_card_tokenization_complete_request.py | 9 +++ ...er_card_tokenization_regenerate_request.py | 10 +++ craftgate/response/__init__.py | 3 + ...meal_voucher_card_tokenization_response.py | 16 +++++ ...her_card_tokenization_complete_response.py | 16 +++++ .../meal_voucher_card_tokenization_sample.py | 67 +++++++++++++++++++ tests/test_bkm_express_payment_sample.py | 7 -- 14 files changed, 208 insertions(+), 19 deletions(-) create mode 100644 craftgate/adapter/meal_voucher_card_tokenization_adapter.py create mode 100644 craftgate/request/dto/meal_voucher_card_tokenization_data.py create mode 100644 craftgate/request/init_meal_voucher_card_tokenization_request.py create mode 100644 craftgate/request/meal_voucher_card_tokenization_complete_request.py create mode 100644 craftgate/request/meal_voucher_card_tokenization_regenerate_request.py create mode 100644 craftgate/response/init_meal_voucher_card_tokenization_response.py create mode 100644 craftgate/response/meal_voucher_card_tokenization_complete_response.py create mode 100644 tests/meal_voucher_card_tokenization_sample.py diff --git a/craftgate/__init__.py b/craftgate/__init__.py index 74744e4..f67c579 100644 --- a/craftgate/__init__.py +++ b/craftgate/__init__.py @@ -76,3 +76,6 @@ def settlement_reporting(self): def wallet(self): return WalletAdapter(self.options) + + def meal_voucher_card_tokenization(self): + return MealVoucherCardTokenizationAdapter(self.options) diff --git a/craftgate/adapter/__init__.py b/craftgate/adapter/__init__.py index 92313c1..5929435 100644 --- a/craftgate/adapter/__init__.py +++ b/craftgate/adapter/__init__.py @@ -1,4 +1,5 @@ from .bank_account_tracking_adapter import BankAccountTrackingAdapter +from .meal_voucher_card_tokenization_adapter import MealVoucherCardTokenizationAdapter from .base_adapter import BaseAdapter from .bkm_express_payment_adapter import BkmExpressPaymentAdapter from .file_reporting_adapter import FileReportingAdapter diff --git a/craftgate/adapter/bkm_express_payment_adapter.py b/craftgate/adapter/bkm_express_payment_adapter.py index c78d53b..a6ae47b 100644 --- a/craftgate/adapter/bkm_express_payment_adapter.py +++ b/craftgate/adapter/bkm_express_payment_adapter.py @@ -34,17 +34,6 @@ def complete(self, request: CompleteBkmExpressRequest) -> PaymentResponse: response_type=PaymentResponse ) - def retrieve_payment(self, ticket_id: str) -> PaymentResponse: - path = "/payment/v1/bkm-express/payments/{}".format(ticket_id) - headers = self._create_headers(None, path) - return self._http_client.request( - method="GET", - url=self.request_options.base_url + path, - headers=headers, - body=None, - response_type=PaymentResponse - ) - def retrieve_payment_by_token(self, token: str) -> PaymentResponse: path = "/payment/v1/bkm-express/{}".format(token) headers = self._create_headers(None, path) diff --git a/craftgate/adapter/meal_voucher_card_tokenization_adapter.py b/craftgate/adapter/meal_voucher_card_tokenization_adapter.py new file mode 100644 index 0000000..022f7f5 --- /dev/null +++ b/craftgate/adapter/meal_voucher_card_tokenization_adapter.py @@ -0,0 +1,50 @@ +from craftgate.adapter.base_adapter import BaseAdapter +from craftgate.net.base_http_client import BaseHttpClient +from craftgate.request.init_meal_voucher_card_tokenization_request import InitMealVoucherCardTokenizationRequest +from craftgate.request.meal_voucher_card_tokenization_regenerate_request import \ + MealVoucherCardTokenizationRegenerateRequest +from craftgate.request.meal_voucher_card_tokenization_complete_request import \ + MealVoucherCardTokenizationCompleteRequest +from craftgate.request_options import RequestOptions +from craftgate.response.init_meal_voucher_card_tokenization_response import InitMealVoucherCardTokenizationResponse +from craftgate.response.meal_voucher_card_tokenization_complete_response import \ + MealVoucherCardTokenizationCompleteResponse + + +class MealVoucherCardTokenizationAdapter(BaseAdapter): + def __init__(self, request_options: RequestOptions) -> None: + super(MealVoucherCardTokenizationAdapter, self).__init__(request_options) + self._http_client = BaseHttpClient() + + def init(self, request: InitMealVoucherCardTokenizationRequest) -> InitMealVoucherCardTokenizationResponse: + path = "/payment/v1/meal-voucher/card-tokenizations/init" + headers = self._create_headers(request, path) + return self._http_client.request( + method="POST", + url=self.request_options.base_url + path, + headers=headers, + body=request, + response_type=InitMealVoucherCardTokenizationResponse + ) + + def regenerate(self, session_id: str, request: MealVoucherCardTokenizationRegenerateRequest) -> InitMealVoucherCardTokenizationResponse: + path = f"/payment/v1/meal-voucher/card-tokenizations/{session_id}/regenerate" + headers = self._create_headers(request, path) + return self._http_client.request( + method="POST", + url=self.request_options.base_url + path, + headers=headers, + body=request, + response_type=InitMealVoucherCardTokenizationResponse + ) + + def complete(self, session_id: str, request: MealVoucherCardTokenizationCompleteRequest) -> MealVoucherCardTokenizationCompleteResponse: + path = f"/payment/v1/meal-voucher/card-tokenizations/{session_id}/complete" + headers = self._create_headers(request, path) + return self._http_client.request( + method="POST", + url=self.request_options.base_url + path, + headers=headers, + body=request, + response_type=MealVoucherCardTokenizationCompleteResponse + ) diff --git a/craftgate/request/__init__.py b/craftgate/request/__init__.py index be3f525..b3ab8b3 100644 --- a/craftgate/request/__init__.py +++ b/craftgate/request/__init__.py @@ -1,6 +1,7 @@ from .apple_pay_merchant_session_create_request import ApplePayMerchantSessionCreateRequest from .approve_payment_transactions_request import ApprovePaymentTransactionsRequest from .bnpl_payment_offer_request import BnplPaymentOfferRequest +from .bnpl_limit_inquiry_request import BnplLimitInquiryRequest from .check_masterpass_user_request import CheckMasterpassUserRequest from .clone_card_request import CloneCardRequest from .complete_apm_payment_request import CompleteApmPaymentRequest @@ -28,12 +29,12 @@ from .fraud_value_list_request import FraudValueListRequest from .init_apm_deposit_payment_request import InitApmDepositPaymentRequest from .init_apm_payment_request import InitApmPaymentRequest -from .bnpl_limit_inquiry_request import BnplLimitInquiryRequest from .init_bkm_express_request import InitBkmExpressRequest from .init_bnpl_payment_request import InitBnplPaymentRequest from .init_checkout_card_verify_request import InitCheckoutCardVerifyRequest from .init_checkout_payment_request import InitCheckoutPaymentRequest from .init_garanti_pay_payment_request import InitGarantiPayPaymentRequest +from .init_meal_voucher_card_tokenization_request import InitMealVoucherCardTokenizationRequest from .init_juzdan_payment_request import InitJuzdanPaymentRequest from .init_pos_apm_payment_request import InitPosApmPaymentRequest from .init_three_ds_payment_request import InitThreeDSPaymentRequest @@ -42,6 +43,8 @@ from .masterpass_payment_threeds_init_request import MasterpassPaymentThreeDSInitRequest from .masterpass_payment_token_generate_request import MasterpassPaymentTokenGenerateRequest from .masterpass_retrieve_loyalties_request import MasterpassRetrieveLoyaltiesRequest +from .meal_voucher_card_tokenization_regenerate_request import MealVoucherCardTokenizationRegenerateRequest +from .meal_voucher_card_tokenization_complete_request import MealVoucherCardTokenizationCompleteRequest from .post_auth_payment_request import PostAuthPaymentRequest from .refund_payment_request import RefundPaymentRequest from .refund_payment_transaction_mark_as_refunded_request import RefundPaymentTransactionMarkAsRefundedRequest diff --git a/craftgate/request/dto/meal_voucher_card_tokenization_data.py b/craftgate/request/dto/meal_voucher_card_tokenization_data.py new file mode 100644 index 0000000..3203c3e --- /dev/null +++ b/craftgate/request/dto/meal_voucher_card_tokenization_data.py @@ -0,0 +1,15 @@ +from typing import Optional + + +class MealVoucherCardTokenizationData: + def __init__( + self, + card_number: Optional[str] = None, + user_reference_number: Optional[str] = None, + gsm_number: Optional[str] = None, + callback_url: Optional[str] = None + ) -> None: + self.card_number = card_number + self.user_reference_number = user_reference_number + self.gsm_number = gsm_number + self.callback_url = callback_url diff --git a/craftgate/request/init_meal_voucher_card_tokenization_request.py b/craftgate/request/init_meal_voucher_card_tokenization_request.py new file mode 100644 index 0000000..63adc63 --- /dev/null +++ b/craftgate/request/init_meal_voucher_card_tokenization_request.py @@ -0,0 +1,14 @@ +from typing import Optional + +from craftgate.model.apm_type import ApmType +from craftgate.request.dto.meal_voucher_card_tokenization_data import MealVoucherCardTokenizationData + + +class InitMealVoucherCardTokenizationRequest: + def __init__( + self, + apm_type: Optional[ApmType] = None, + meal_voucher_card_tokenization_data: Optional[MealVoucherCardTokenizationData] = None + ) -> None: + self.apm_type = apm_type + self.meal_voucher_card_tokenization_data = meal_voucher_card_tokenization_data diff --git a/craftgate/request/meal_voucher_card_tokenization_complete_request.py b/craftgate/request/meal_voucher_card_tokenization_complete_request.py new file mode 100644 index 0000000..ffab182 --- /dev/null +++ b/craftgate/request/meal_voucher_card_tokenization_complete_request.py @@ -0,0 +1,9 @@ +from typing import Optional + + +class MealVoucherCardTokenizationCompleteRequest: + def __init__( + self, + validation_code: Optional[str] = None + ) -> None: + self.validation_code = validation_code diff --git a/craftgate/request/meal_voucher_card_tokenization_regenerate_request.py b/craftgate/request/meal_voucher_card_tokenization_regenerate_request.py new file mode 100644 index 0000000..db72884 --- /dev/null +++ b/craftgate/request/meal_voucher_card_tokenization_regenerate_request.py @@ -0,0 +1,10 @@ +from typing import Optional +from craftgate.request.dto.meal_voucher_card_tokenization_data import MealVoucherCardTokenizationData + + +class MealVoucherCardTokenizationRegenerateRequest: + def __init__( + self, + meal_voucher_card_tokenization_data: Optional[MealVoucherCardTokenizationData] = None + ) -> None: + self.meal_voucher_card_tokenization_data = meal_voucher_card_tokenization_data diff --git a/craftgate/response/__init__.py b/craftgate/response/__init__.py index 44e3826..48ff1bd 100644 --- a/craftgate/response/__init__.py +++ b/craftgate/response/__init__.py @@ -22,6 +22,9 @@ from .init_checkout_payment_response import InitCheckoutPaymentResponse from .init_garanti_pay_payment_response import InitGarantiPayPaymentResponse from .init_juzdan_payment_response import InitJuzdanPaymentResponse +from .init_meal_voucher_card_tokenization_response import InitMealVoucherCardTokenizationResponse +MealVoucherCardTokenizationInitResponse = InitMealVoucherCardTokenizationResponse +from .meal_voucher_card_tokenization_complete_response import MealVoucherCardTokenizationCompleteResponse from .init_pos_apm_payment_response import InitPosApmPaymentResponse from .init_three_ds_payment_response import InitThreeDSPaymentResponse from .installment_list_response import InstallmentListResponse diff --git a/craftgate/response/init_meal_voucher_card_tokenization_response.py b/craftgate/response/init_meal_voucher_card_tokenization_response.py new file mode 100644 index 0000000..5f8b7ca --- /dev/null +++ b/craftgate/response/init_meal_voucher_card_tokenization_response.py @@ -0,0 +1,16 @@ +from typing import Optional +from craftgate.model.apm_additional_action import ApmAdditionalAction + + +class InitMealVoucherCardTokenizationResponse: + def __init__( + self, + session_id: Optional[str] = None, + additional_action: Optional[ApmAdditionalAction] = None, + html_content: Optional[str] = None, + redirect_url: Optional[str] = None + ) -> None: + self.session_id = session_id + self.additional_action = additional_action + self.html_content = html_content + self.redirect_url = redirect_url diff --git a/craftgate/response/meal_voucher_card_tokenization_complete_response.py b/craftgate/response/meal_voucher_card_tokenization_complete_response.py new file mode 100644 index 0000000..48b62b8 --- /dev/null +++ b/craftgate/response/meal_voucher_card_tokenization_complete_response.py @@ -0,0 +1,16 @@ +from typing import Optional +from decimal import Decimal + + +class MealVoucherCardTokenizationCompleteResponse: + def __init__( + self, + session_id: Optional[str] = None, + masked_card_number: Optional[str] = None, + fingerprint: Optional[str] = None, + balance: Optional[Decimal] = None + ) -> None: + self.session_id = session_id + self.masked_card_number = masked_card_number + self.fingerprint = fingerprint + self.balance = balance diff --git a/tests/meal_voucher_card_tokenization_sample.py b/tests/meal_voucher_card_tokenization_sample.py new file mode 100644 index 0000000..3e5169c --- /dev/null +++ b/tests/meal_voucher_card_tokenization_sample.py @@ -0,0 +1,67 @@ +import os +import unittest + +from craftgate import Craftgate, RequestOptions +from craftgate.model import ApmType +from craftgate.request import InitMealVoucherCardTokenizationRequest, MealVoucherCardTokenizationRegenerateRequest, \ + MealVoucherCardTokenizationCompleteRequest +from craftgate.request.dto.meal_voucher_card_tokenization_data import MealVoucherCardTokenizationData + + +class MealVoucherCardTokenizationSample(unittest.TestCase): + API_KEY = os.environ.get("CG_API_KEY", "api-key-2") + SECRET_KEY = os.environ.get("CG_SECRET_KEY", "secret-key") + BASE_URL = os.environ.get("CG_BASE_URL", "http://localhost:8000") + + @classmethod + def setUpClass(cls): + options = RequestOptions( + api_key=cls.API_KEY, + secret_key=cls.SECRET_KEY, + base_url=cls.BASE_URL + ) + cls.meal_voucher_card_tokenization = Craftgate(options).meal_voucher_card_tokenization() + + def test_init_meal_voucher_card_tokenization(self): + request = InitMealVoucherCardTokenizationRequest( + apm_type=ApmType.SETCARD, + meal_voucher_card_tokenization_data=MealVoucherCardTokenizationData( + callback_url="https://webhook.site/e806070a-da76-4d02-a67b-54ba9e8332d3" + ) + ) + + response = self.meal_voucher_card_tokenization.init(request) + + print(response.__dict__) + self.assertIsNotNone(response.session_id) + self.assertIsNotNone(response) + + def test_regenerate_meal_voucher_card_tokenization(self): + session_id = "session-id" + request = MealVoucherCardTokenizationRegenerateRequest( + meal_voucher_card_tokenization_data=MealVoucherCardTokenizationData( + callback_url="https://webhook.site/e806070a-da76-4d02-a67b-54ba9e8332d3" + ) + ) + + response = self.meal_voucher_card_tokenization.regenerate(session_id, request) + + print(response.__dict__) + self.assertIsNotNone(response.session_id) + self.assertIsNotNone(response) + + def test_complete_meal_voucher_card_tokenization(self): + session_id = "session-id" + request = MealVoucherCardTokenizationCompleteRequest( + validation_code="123456" + ) + + response = self.meal_voucher_card_tokenization.complete(session_id, request) + + print(response.__dict__) + self.assertIsNotNone(response.session_id) + self.assertIsNotNone(response) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_bkm_express_payment_sample.py b/tests/test_bkm_express_payment_sample.py index e4a9212..db73f00 100644 --- a/tests/test_bkm_express_payment_sample.py +++ b/tests/test_bkm_express_payment_sample.py @@ -61,13 +61,6 @@ def test_complete_bkm_express(self): self.assertIsNotNone(response) self.assertIsNotNone(response.order_id) - def test_retrieve_payment_by_ticket_id(self): - ticket_id = os.environ.get("BKM_TICKET_ID", "ce6d93c3-b399-406d-8efc-fdba0b37768c") - - response = self.bkm_express_payment.retrieve_payment(ticket_id) - print(response) - self.assertIsNotNone(response) - def test_retrieve_payment_by_token(self): token = os.environ.get("BKM_TOKEN", "cb90071c-1f2c-4fb7-9049-c5f13f9f7286") From 6fbd34049196d66250b48ed424aeaf4c7b751d84 Mon Sep 17 00:00:00 2001 From: deryacakmak <97deryacakmak@gmail.com> Date: Wed, 3 Jun 2026 11:49:41 +0300 Subject: [PATCH 2/4] Update test variables in meal voucher card tokenization sample --- ...ple.py => test_meal_voucher_card_tokenization_sample.py} | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename tests/{meal_voucher_card_tokenization_sample.py => test_meal_voucher_card_tokenization_sample.py} (91%) diff --git a/tests/meal_voucher_card_tokenization_sample.py b/tests/test_meal_voucher_card_tokenization_sample.py similarity index 91% rename from tests/meal_voucher_card_tokenization_sample.py rename to tests/test_meal_voucher_card_tokenization_sample.py index 3e5169c..9c60566 100644 --- a/tests/meal_voucher_card_tokenization_sample.py +++ b/tests/test_meal_voucher_card_tokenization_sample.py @@ -9,9 +9,9 @@ class MealVoucherCardTokenizationSample(unittest.TestCase): - API_KEY = os.environ.get("CG_API_KEY", "api-key-2") - SECRET_KEY = os.environ.get("CG_SECRET_KEY", "secret-key") - BASE_URL = os.environ.get("CG_BASE_URL", "http://localhost:8000") + API_KEY = os.environ.get("CG_API_KEY", "YOUR_API_KEY") + SECRET_KEY = os.environ.get("CG_SECRET_KEY", "YOUR_SECRET_KEY") + BASE_URL = os.environ.get("CG_BASE_URL", "https://sandbox-api.craftgate.io") @classmethod def setUpClass(cls): From 996efec2d90d6df8db434c25247b0dab7f32c7ec Mon Sep 17 00:00:00 2001 From: deryacakmak <97deryacakmak@gmail.com> Date: Wed, 3 Jun 2026 16:01:53 +0300 Subject: [PATCH 3/4] Improve assertions and logging in meal voucher card tokenization tests --- tests/test_meal_voucher_card_tokenization_sample.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_meal_voucher_card_tokenization_sample.py b/tests/test_meal_voucher_card_tokenization_sample.py index 9c60566..3e6e7be 100644 --- a/tests/test_meal_voucher_card_tokenization_sample.py +++ b/tests/test_meal_voucher_card_tokenization_sample.py @@ -32,8 +32,8 @@ def test_init_meal_voucher_card_tokenization(self): response = self.meal_voucher_card_tokenization.init(request) - print(response.__dict__) self.assertIsNotNone(response.session_id) + self.assertIsNotNone(response.html_content) self.assertIsNotNone(response) def test_regenerate_meal_voucher_card_tokenization(self): @@ -46,7 +46,7 @@ def test_regenerate_meal_voucher_card_tokenization(self): response = self.meal_voucher_card_tokenization.regenerate(session_id, request) - print(response.__dict__) + print(response) self.assertIsNotNone(response.session_id) self.assertIsNotNone(response) @@ -58,7 +58,7 @@ def test_complete_meal_voucher_card_tokenization(self): response = self.meal_voucher_card_tokenization.complete(session_id, request) - print(response.__dict__) + print(response) self.assertIsNotNone(response.session_id) self.assertIsNotNone(response) From 83013648891826aa65a870143a40039f89490119 Mon Sep 17 00:00:00 2001 From: deryacakmak <97deryacakmak@gmail.com> Date: Thu, 4 Jun 2026 11:42:25 +0300 Subject: [PATCH 4/4] Update callback URL in meal voucher card tokenization test cases --- tests/test_meal_voucher_card_tokenization_sample.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_meal_voucher_card_tokenization_sample.py b/tests/test_meal_voucher_card_tokenization_sample.py index 3e6e7be..548b3aa 100644 --- a/tests/test_meal_voucher_card_tokenization_sample.py +++ b/tests/test_meal_voucher_card_tokenization_sample.py @@ -26,7 +26,7 @@ def test_init_meal_voucher_card_tokenization(self): request = InitMealVoucherCardTokenizationRequest( apm_type=ApmType.SETCARD, meal_voucher_card_tokenization_data=MealVoucherCardTokenizationData( - callback_url="https://webhook.site/e806070a-da76-4d02-a67b-54ba9e8332d3" + callback_url="https://www.yourdomain.com/callback" ) ) @@ -40,7 +40,7 @@ def test_regenerate_meal_voucher_card_tokenization(self): session_id = "session-id" request = MealVoucherCardTokenizationRegenerateRequest( meal_voucher_card_tokenization_data=MealVoucherCardTokenizationData( - callback_url="https://webhook.site/e806070a-da76-4d02-a67b-54ba9e8332d3" + callback_url="https://www.yourdomain.com/callback" ) )