@artilingo/artiframe-cli 1.3.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/core-stubs/bin/SystemMethod.php +600 -521
- package/core-stubs/bin/ViewMethod.php +591 -393
- package/core-stubs/docs/de.html +853 -1172
- package/core-stubs/docs/en.html +585 -904
- package/core-stubs/docs/es.html +934 -1253
- package/core-stubs/docs/fr.html +913 -1232
- package/core-stubs/docs/tr.html +4212 -5021
- package/package.json +1 -1
- package/src/App.php +38 -0
- package/src/Commands/AddCommand.php +1 -1
- package/src/Commands/AuthCommand.php +219 -0
- package/src/Commands/IssuesCommand.php +174 -0
- package/src/Commands/ListCommand.php +2 -1
- package/src/Commands/MakeApiCommand.php +1 -1
- package/src/Commands/MakeClassCommand.php +1 -1
- package/src/Commands/MakeViewCommand.php +1 -1
- package/src/Commands/NewProjectCommand.php +37 -25
- package/src/Commands/RemoveCommand.php +21 -10
- package/src/Commands/ServeCommand.php +29 -9
- package/src/Commands/SuggestCommand.php +143 -0
- package/src/Commands/TableCommand.php +2 -1
- package/src/Commands/UpgradeCommand.php +209 -0
- package/src/Commands/VersionCommand.php +2 -1
- package/src/Lang/de.php +9 -1
- package/src/Lang/en.php +8 -0
- package/src/Lang/es.php +9 -1
- package/src/Lang/fr.php +8 -0
- package/src/Lang/tr.php +10 -2
- package/src/Services/Safeguard.php +25 -0
- package/stubs/service/image.stub +334 -334
- package/stubs/service/iyzico.stub +637 -637
- package/stubs/service/jwt.stub +312 -312
- package/stubs/service/phpmailer.stub +143 -143
- package/stubs/service/pusher.stub +232 -232
- package/stubs/service/qrcode.stub +169 -169
- package/stubs/service/redis.stub +361 -361
- package/stubs/service/s3.stub +377 -377
- package/stubs/service/sentry.stub +76 -106
- package/stubs/service/stripe.stub +526 -526
- package/stubs/service/twilio.stub +361 -361
- package/core-stubs/app/R2Manager.php +0 -130
|
@@ -1,637 +1,637 @@
|
|
|
1
|
-
<?php
|
|
2
|
-
|
|
3
|
-
namespace Service;
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Iyzico Payment Service
|
|
7
|
-
*
|
|
8
|
-
* Provides a clean wrapper around the iyzipay-php SDK for payment processing,
|
|
9
|
-
* 3D Secure flows, refunds, cancellations, card vault, and marketplace sub-merchants.
|
|
10
|
-
*
|
|
11
|
-
* Required environment variables:
|
|
12
|
-
* IYZICO_API_KEY — Your iyzico API key
|
|
13
|
-
* IYZICO_SECRET_KEY — Your iyzico secret key
|
|
14
|
-
* IYZICO_BASE_URL — API base URL (https://sandbox-api.iyzipay.com or https://api.iyzipay.com)
|
|
15
|
-
*
|
|
16
|
-
* @package Service
|
|
17
|
-
*/
|
|
18
|
-
class Iyzico
|
|
19
|
-
{
|
|
20
|
-
/**
|
|
21
|
-
* Iyzipay connection options.
|
|
22
|
-
*
|
|
23
|
-
* @var \Iyzipay\Options
|
|
24
|
-
*/
|
|
25
|
-
private \Iyzipay\Options $options;
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Create a new Iyzico service instance.
|
|
29
|
-
*
|
|
30
|
-
* Reads API credentials and base URL from $_ENV and builds
|
|
31
|
-
* the \Iyzipay\Options object used by every SDK call.
|
|
32
|
-
*/
|
|
33
|
-
public function __construct()
|
|
34
|
-
{
|
|
35
|
-
$this->options = new \Iyzipay\Options();
|
|
36
|
-
$this->options->setApiKey($_ENV['IYZICO_API_KEY']);
|
|
37
|
-
$this->options->setSecretKey($_ENV['IYZICO_SECRET_KEY']);
|
|
38
|
-
$this->options->setBaseUrl($_ENV['IYZICO_BASE_URL']);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Process a single (non-3D) payment.
|
|
43
|
-
*
|
|
44
|
-
* @param array $data {
|
|
45
|
-
* @type float $price Base price
|
|
46
|
-
* @type float $paidPrice Final charged price (including installment cost)
|
|
47
|
-
* @type string $currency ISO currency code (default: TRY)
|
|
48
|
-
* @type int $installment Number of installments (default: 1)
|
|
49
|
-
* @type array $card {
|
|
50
|
-
* @type string $holder Card holder full name
|
|
51
|
-
* @type string $number Card number
|
|
52
|
-
* @type string $month Expiry month (2 digits)
|
|
53
|
-
* @type string $year Expiry year (4 digits)
|
|
54
|
-
* @type string $cvc CVC / CVV code
|
|
55
|
-
* }
|
|
56
|
-
* @type array $buyer {
|
|
57
|
-
* @type string $id Merchant-side buyer ID
|
|
58
|
-
* @type string $name First name
|
|
59
|
-
* @type string $surname Last name
|
|
60
|
-
* @type string $email E-mail address
|
|
61
|
-
* @type string $phone Phone number
|
|
62
|
-
* @type string $ip IP address of buyer
|
|
63
|
-
* @type string $city City
|
|
64
|
-
* @type string $country Country
|
|
65
|
-
* @type string $address Full address line
|
|
66
|
-
* @type string $zipCode ZIP / postal code
|
|
67
|
-
* }
|
|
68
|
-
* @type array $items Array of basket items, each having name, price, category
|
|
69
|
-
* }
|
|
70
|
-
* @return array Standardised response with status, message, and data keys
|
|
71
|
-
*/
|
|
72
|
-
public function pay(array $data): array
|
|
73
|
-
{
|
|
74
|
-
try {
|
|
75
|
-
$request = new \Iyzipay\Request\CreatePaymentRequest();
|
|
76
|
-
$request->setLocale(\Iyzipay\Model\Locale::TR);
|
|
77
|
-
$request->setConversationId(uniqid('pay_'));
|
|
78
|
-
$request->setPrice($data['price']);
|
|
79
|
-
$request->setPaidPrice($data['paidPrice']);
|
|
80
|
-
$request->setCurrency($data['currency'] ?? \Iyzipay\Model\Currency::TL);
|
|
81
|
-
$request->setInstallment($data['installment'] ?? 1);
|
|
82
|
-
$request->setPaymentChannel(\Iyzipay\Model\PaymentChannel::WEB);
|
|
83
|
-
$request->setPaymentGroup(\Iyzipay\Model\PaymentGroup::PRODUCT);
|
|
84
|
-
|
|
85
|
-
// Payment card
|
|
86
|
-
$card = new \Iyzipay\Model\PaymentCard();
|
|
87
|
-
$card->setCardHolderName($data['card']['holder']);
|
|
88
|
-
$card->setCardNumber($data['card']['number']);
|
|
89
|
-
$card->setExpireMonth($data['card']['month']);
|
|
90
|
-
$card->setExpireYear($data['card']['year']);
|
|
91
|
-
$card->setCvc($data['card']['cvc']);
|
|
92
|
-
$card->setRegisterCard(0);
|
|
93
|
-
$request->setPaymentCard($card);
|
|
94
|
-
|
|
95
|
-
// Buyer
|
|
96
|
-
$buyer = new \Iyzipay\Model\Buyer();
|
|
97
|
-
$buyer->setId($data['buyer']['id']);
|
|
98
|
-
$buyer->setName($data['buyer']['name']);
|
|
99
|
-
$buyer->setSurname($data['buyer']['surname']);
|
|
100
|
-
$buyer->setEmail($data['buyer']['email']);
|
|
101
|
-
$buyer->setGsmNumber($data['buyer']['phone']);
|
|
102
|
-
$buyer->setIp($data['buyer']['ip']);
|
|
103
|
-
$buyer->setCity($data['buyer']['city']);
|
|
104
|
-
$buyer->setCountry($data['buyer']['country']);
|
|
105
|
-
$buyer->setRegistrationAddress($data['buyer']['address']);
|
|
106
|
-
$buyer->setZipCode($data['buyer']['zipCode']);
|
|
107
|
-
$buyer->setIdentityNumber('00000000000');
|
|
108
|
-
$request->setBuyer($buyer);
|
|
109
|
-
|
|
110
|
-
// Shipping & billing address (use buyer address for both)
|
|
111
|
-
$address = new \Iyzipay\Model\Address();
|
|
112
|
-
$address->setContactName($data['buyer']['name'] . ' ' . $data['buyer']['surname']);
|
|
113
|
-
$address->setCity($data['buyer']['city']);
|
|
114
|
-
$address->setCountry($data['buyer']['country']);
|
|
115
|
-
$address->setAddress($data['buyer']['address']);
|
|
116
|
-
$address->setZipCode($data['buyer']['zipCode']);
|
|
117
|
-
$request->setShippingAddress($address);
|
|
118
|
-
$request->setBillingAddress($address);
|
|
119
|
-
|
|
120
|
-
// Basket items
|
|
121
|
-
$basketItems = [];
|
|
122
|
-
foreach ($data['items'] as $index => $item) {
|
|
123
|
-
$basketItem = new \Iyzipay\Model\BasketItem();
|
|
124
|
-
$basketItem->setId('ITEM_' . ($index + 1));
|
|
125
|
-
$basketItem->setName($item['name']);
|
|
126
|
-
$basketItem->setCategory1($item['category'] ?? 'Default');
|
|
127
|
-
$basketItem->setItemType(\Iyzipay\Model\BasketItemType::PHYSICAL);
|
|
128
|
-
$basketItem->setPrice($item['price']);
|
|
129
|
-
$basketItems[] = $basketItem;
|
|
130
|
-
}
|
|
131
|
-
$request->setBasketItems($basketItems);
|
|
132
|
-
|
|
133
|
-
$payment = \Iyzipay\Model\Payment::create($request, $this->options);
|
|
134
|
-
|
|
135
|
-
if ($payment->getStatus() === 'success') {
|
|
136
|
-
return [
|
|
137
|
-
'status' => 'success',
|
|
138
|
-
'message' => 'Payment processed successfully.',
|
|
139
|
-
'data' => [
|
|
140
|
-
'paymentId' => $payment->getPaymentId(),
|
|
141
|
-
'price' => $payment->getPrice(),
|
|
142
|
-
'paidPrice' => $payment->getPaidPrice(),
|
|
143
|
-
'currency' => $payment->getCurrency(),
|
|
144
|
-
'installment' => $payment->getInstallment(),
|
|
145
|
-
'paymentTransactionId' => $payment->getPaymentItems()[0]->getPaymentTransactionId() ?? null,
|
|
146
|
-
'fraudStatus' => $payment->getFraudStatus(),
|
|
147
|
-
],
|
|
148
|
-
];
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
return [
|
|
152
|
-
'status' => 'error',
|
|
153
|
-
'message' => $payment->getErrorMessage() ?? 'Payment failed.',
|
|
154
|
-
'data' => ['errorCode' => $payment->getErrorCode()],
|
|
155
|
-
];
|
|
156
|
-
} catch (\Exception $e) {
|
|
157
|
-
return [
|
|
158
|
-
'status' => 'error',
|
|
159
|
-
'message' => $e->getMessage(),
|
|
160
|
-
'data' => [],
|
|
161
|
-
];
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
/**
|
|
166
|
-
* Initialise a 3D Secure payment flow.
|
|
167
|
-
*
|
|
168
|
-
* Returns an HTML snippet that must be rendered in the buyer's browser
|
|
169
|
-
* to redirect them to the bank's 3D Secure verification page.
|
|
170
|
-
*
|
|
171
|
-
* @param array $data Same structure as pay() with an additional `callbackUrl` key
|
|
172
|
-
* @return array Response containing threeDSHtmlContent on success
|
|
173
|
-
*/
|
|
174
|
-
public function threeDSecureInit(array $data): array
|
|
175
|
-
{
|
|
176
|
-
try {
|
|
177
|
-
$request = new \Iyzipay\Request\CreatePaymentRequest();
|
|
178
|
-
$request->setLocale(\Iyzipay\Model\Locale::TR);
|
|
179
|
-
$request->setConversationId(uniqid('3ds_'));
|
|
180
|
-
$request->setPrice($data['price']);
|
|
181
|
-
$request->setPaidPrice($data['paidPrice']);
|
|
182
|
-
$request->setCurrency($data['currency'] ?? \Iyzipay\Model\Currency::TL);
|
|
183
|
-
$request->setInstallment($data['installment'] ?? 1);
|
|
184
|
-
$request->setPaymentChannel(\Iyzipay\Model\PaymentChannel::WEB);
|
|
185
|
-
$request->setPaymentGroup(\Iyzipay\Model\PaymentGroup::PRODUCT);
|
|
186
|
-
$request->setCallbackUrl($data['callbackUrl']);
|
|
187
|
-
|
|
188
|
-
// Payment card
|
|
189
|
-
$card = new \Iyzipay\Model\PaymentCard();
|
|
190
|
-
$card->setCardHolderName($data['card']['holder']);
|
|
191
|
-
$card->setCardNumber($data['card']['number']);
|
|
192
|
-
$card->setExpireMonth($data['card']['month']);
|
|
193
|
-
$card->setExpireYear($data['card']['year']);
|
|
194
|
-
$card->setCvc($data['card']['cvc']);
|
|
195
|
-
$card->setRegisterCard(0);
|
|
196
|
-
$request->setPaymentCard($card);
|
|
197
|
-
|
|
198
|
-
// Buyer
|
|
199
|
-
$buyer = new \Iyzipay\Model\Buyer();
|
|
200
|
-
$buyer->setId($data['buyer']['id']);
|
|
201
|
-
$buyer->setName($data['buyer']['name']);
|
|
202
|
-
$buyer->setSurname($data['buyer']['surname']);
|
|
203
|
-
$buyer->setEmail($data['buyer']['email']);
|
|
204
|
-
$buyer->setGsmNumber($data['buyer']['phone']);
|
|
205
|
-
$buyer->setIp($data['buyer']['ip']);
|
|
206
|
-
$buyer->setCity($data['buyer']['city']);
|
|
207
|
-
$buyer->setCountry($data['buyer']['country']);
|
|
208
|
-
$buyer->setRegistrationAddress($data['buyer']['address']);
|
|
209
|
-
$buyer->setZipCode($data['buyer']['zipCode']);
|
|
210
|
-
$buyer->setIdentityNumber('00000000000');
|
|
211
|
-
$request->setBuyer($buyer);
|
|
212
|
-
|
|
213
|
-
// Address
|
|
214
|
-
$address = new \Iyzipay\Model\Address();
|
|
215
|
-
$address->setContactName($data['buyer']['name'] . ' ' . $data['buyer']['surname']);
|
|
216
|
-
$address->setCity($data['buyer']['city']);
|
|
217
|
-
$address->setCountry($data['buyer']['country']);
|
|
218
|
-
$address->setAddress($data['buyer']['address']);
|
|
219
|
-
$address->setZipCode($data['buyer']['zipCode']);
|
|
220
|
-
$request->setShippingAddress($address);
|
|
221
|
-
$request->setBillingAddress($address);
|
|
222
|
-
|
|
223
|
-
// Basket items
|
|
224
|
-
$basketItems = [];
|
|
225
|
-
foreach ($data['items'] as $index => $item) {
|
|
226
|
-
$basketItem = new \Iyzipay\Model\BasketItem();
|
|
227
|
-
$basketItem->setId('ITEM_' . ($index + 1));
|
|
228
|
-
$basketItem->setName($item['name']);
|
|
229
|
-
$basketItem->setCategory1($item['category'] ?? 'Default');
|
|
230
|
-
$basketItem->setItemType(\Iyzipay\Model\BasketItemType::PHYSICAL);
|
|
231
|
-
$basketItem->setPrice($item['price']);
|
|
232
|
-
$basketItems[] = $basketItem;
|
|
233
|
-
}
|
|
234
|
-
$request->setBasketItems($basketItems);
|
|
235
|
-
|
|
236
|
-
$threedsInit = \Iyzipay\Model\ThreedsInitialize::create($request, $this->options);
|
|
237
|
-
|
|
238
|
-
if ($threedsInit->getStatus() === 'success') {
|
|
239
|
-
return [
|
|
240
|
-
'status' => 'success',
|
|
241
|
-
'message' => '3D Secure initialisation successful.',
|
|
242
|
-
'data' => [
|
|
243
|
-
'threeDSHtmlContent' => $threedsInit->getHtmlContent(),
|
|
244
|
-
],
|
|
245
|
-
];
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
return [
|
|
249
|
-
'status' => 'error',
|
|
250
|
-
'message' => $threedsInit->getErrorMessage() ?? '3D Secure initialisation failed.',
|
|
251
|
-
'data' => ['errorCode' => $threedsInit->getErrorCode()],
|
|
252
|
-
];
|
|
253
|
-
} catch (\Exception $e) {
|
|
254
|
-
return [
|
|
255
|
-
'status' => 'error',
|
|
256
|
-
'message' => $e->getMessage(),
|
|
257
|
-
'data' => [],
|
|
258
|
-
];
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
/**
|
|
263
|
-
* Complete a 3D Secure payment after bank verification callback.
|
|
264
|
-
*
|
|
265
|
-
* Call this from your callback URL handler with the paymentId received
|
|
266
|
-
* from the bank's POST response.
|
|
267
|
-
*
|
|
268
|
-
* @param array $data {
|
|
269
|
-
* @type string $paymentId The payment ID returned by the bank callback
|
|
270
|
-
* }
|
|
271
|
-
* @return array Standardised response
|
|
272
|
-
*/
|
|
273
|
-
public function threeDSecureComplete(array $data): array
|
|
274
|
-
{
|
|
275
|
-
try {
|
|
276
|
-
$request = new \Iyzipay\Request\CreateThreedsPaymentRequest();
|
|
277
|
-
$request->setLocale(\Iyzipay\Model\Locale::TR);
|
|
278
|
-
$request->setConversationId(uniqid('3ds_complete_'));
|
|
279
|
-
$request->setPaymentId($data['paymentId']);
|
|
280
|
-
|
|
281
|
-
$threedsPayment = \Iyzipay\Model\ThreedsPayment::create($request, $this->options);
|
|
282
|
-
|
|
283
|
-
if ($threedsPayment->getStatus() === 'success') {
|
|
284
|
-
return [
|
|
285
|
-
'status' => 'success',
|
|
286
|
-
'message' => '3D Secure payment completed successfully.',
|
|
287
|
-
'data' => [
|
|
288
|
-
'paymentId' => $threedsPayment->getPaymentId(),
|
|
289
|
-
'price' => $threedsPayment->getPrice(),
|
|
290
|
-
'paidPrice' => $threedsPayment->getPaidPrice(),
|
|
291
|
-
'currency' => $threedsPayment->getCurrency(),
|
|
292
|
-
'fraudStatus' => $threedsPayment->getFraudStatus(),
|
|
293
|
-
],
|
|
294
|
-
];
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
return [
|
|
298
|
-
'status' => 'error',
|
|
299
|
-
'message' => $threedsPayment->getErrorMessage() ?? '3D Secure completion failed.',
|
|
300
|
-
'data' => ['errorCode' => $threedsPayment->getErrorCode()],
|
|
301
|
-
];
|
|
302
|
-
} catch (\Exception $e) {
|
|
303
|
-
return [
|
|
304
|
-
'status' => 'error',
|
|
305
|
-
'message' => $e->getMessage(),
|
|
306
|
-
'data' => [],
|
|
307
|
-
];
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
/**
|
|
312
|
-
* Refund a specific payment transaction.
|
|
313
|
-
*
|
|
314
|
-
* @param string $paymentTransactionId The transaction ID to refund (from basket item)
|
|
315
|
-
* @param float $price Amount to refund
|
|
316
|
-
* @return array Standardised response
|
|
317
|
-
*/
|
|
318
|
-
public function refund(string $paymentTransactionId, float $price): array
|
|
319
|
-
{
|
|
320
|
-
try {
|
|
321
|
-
$request = new \Iyzipay\Request\CreateRefundRequest();
|
|
322
|
-
$request->setLocale(\Iyzipay\Model\Locale::TR);
|
|
323
|
-
$request->setConversationId(uniqid('refund_'));
|
|
324
|
-
$request->setPaymentTransactionId($paymentTransactionId);
|
|
325
|
-
$request->setPrice($price);
|
|
326
|
-
$request->setCurrency(\Iyzipay\Model\Currency::TL);
|
|
327
|
-
$request->setIp('127.0.0.1');
|
|
328
|
-
|
|
329
|
-
$refund = \Iyzipay\Model\Refund::create($request, $this->options);
|
|
330
|
-
|
|
331
|
-
if ($refund->getStatus() === 'success') {
|
|
332
|
-
return [
|
|
333
|
-
'status' => 'success',
|
|
334
|
-
'message' => 'Refund processed successfully.',
|
|
335
|
-
'data' => [
|
|
336
|
-
'paymentId' => $refund->getPaymentId(),
|
|
337
|
-
'paymentTransactionId' => $refund->getPaymentTransactionId(),
|
|
338
|
-
'price' => $refund->getPrice(),
|
|
339
|
-
],
|
|
340
|
-
];
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
return [
|
|
344
|
-
'status' => 'error',
|
|
345
|
-
'message' => $refund->getErrorMessage() ?? 'Refund failed.',
|
|
346
|
-
'data' => ['errorCode' => $refund->getErrorCode()],
|
|
347
|
-
];
|
|
348
|
-
} catch (\Exception $e) {
|
|
349
|
-
return [
|
|
350
|
-
'status' => 'error',
|
|
351
|
-
'message' => $e->getMessage(),
|
|
352
|
-
'data' => [],
|
|
353
|
-
];
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
/**
|
|
358
|
-
* Cancel an entire payment.
|
|
359
|
-
*
|
|
360
|
-
* @param string $paymentId The payment ID to cancel
|
|
361
|
-
* @return array Standardised response
|
|
362
|
-
*/
|
|
363
|
-
public function cancel(string $paymentId): array
|
|
364
|
-
{
|
|
365
|
-
try {
|
|
366
|
-
$request = new \Iyzipay\Request\CreateCancelRequest();
|
|
367
|
-
$request->setLocale(\Iyzipay\Model\Locale::TR);
|
|
368
|
-
$request->setConversationId(uniqid('cancel_'));
|
|
369
|
-
$request->setPaymentId($paymentId);
|
|
370
|
-
$request->setIp('127.0.0.1');
|
|
371
|
-
|
|
372
|
-
$cancel = \Iyzipay\Model\Cancel::create($request, $this->options);
|
|
373
|
-
|
|
374
|
-
if ($cancel->getStatus() === 'success') {
|
|
375
|
-
return [
|
|
376
|
-
'status' => 'success',
|
|
377
|
-
'message' => 'Payment cancelled successfully.',
|
|
378
|
-
'data' => [
|
|
379
|
-
'paymentId' => $cancel->getPaymentId(),
|
|
380
|
-
'price' => $cancel->getPrice(),
|
|
381
|
-
'currency' => $cancel->getCurrency(),
|
|
382
|
-
],
|
|
383
|
-
];
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
return [
|
|
387
|
-
'status' => 'error',
|
|
388
|
-
'message' => $cancel->getErrorMessage() ?? 'Cancellation failed.',
|
|
389
|
-
'data' => ['errorCode' => $cancel->getErrorCode()],
|
|
390
|
-
];
|
|
391
|
-
} catch (\Exception $e) {
|
|
392
|
-
return [
|
|
393
|
-
'status' => 'error',
|
|
394
|
-
'message' => $e->getMessage(),
|
|
395
|
-
'data' => [],
|
|
396
|
-
];
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
/**
|
|
401
|
-
* Save a card to the iyzico card vault for future payments.
|
|
402
|
-
*
|
|
403
|
-
* @param array $cardData {
|
|
404
|
-
* @type string $holder Card holder full name
|
|
405
|
-
* @type string $number Card number
|
|
406
|
-
* @type string $month Expiry month
|
|
407
|
-
* @type string $year Expiry year
|
|
408
|
-
* @type string $alias A user-friendly card alias (e.g. "My Visa")
|
|
409
|
-
* }
|
|
410
|
-
* @param string $email Buyer e-mail (used as external identifier)
|
|
411
|
-
* @return array Standardised response with cardUserKey and cardToken
|
|
412
|
-
*/
|
|
413
|
-
public function saveCard(array $cardData, string $email): array
|
|
414
|
-
{
|
|
415
|
-
try {
|
|
416
|
-
$request = new \Iyzipay\Request\CreateCardRequest();
|
|
417
|
-
$request->setLocale(\Iyzipay\Model\Locale::TR);
|
|
418
|
-
$request->setConversationId(uniqid('card_'));
|
|
419
|
-
$request->setEmail($email);
|
|
420
|
-
$request->setExternalId(md5($email));
|
|
421
|
-
|
|
422
|
-
$cardInfo = new \Iyzipay\Model\CardInformation();
|
|
423
|
-
$cardInfo->setCardAlias($cardData['alias'] ?? 'Default Card');
|
|
424
|
-
$cardInfo->setCardHolderName($cardData['holder']);
|
|
425
|
-
$cardInfo->setCardNumber($cardData['number']);
|
|
426
|
-
$cardInfo->setExpireMonth($cardData['month']);
|
|
427
|
-
$cardInfo->setExpireYear($cardData['year']);
|
|
428
|
-
$request->setCard($cardInfo);
|
|
429
|
-
|
|
430
|
-
$card = \Iyzipay\Model\Card::create($request, $this->options);
|
|
431
|
-
|
|
432
|
-
if ($card->getStatus() === 'success') {
|
|
433
|
-
return [
|
|
434
|
-
'status' => 'success',
|
|
435
|
-
'message' => 'Card saved successfully.',
|
|
436
|
-
'data' => [
|
|
437
|
-
'cardUserKey' => $card->getCardUserKey(),
|
|
438
|
-
'cardToken' => $card->getCardToken(),
|
|
439
|
-
'cardAlias' => $card->getCardAlias(),
|
|
440
|
-
'lastFour' => $card->getLastFourDigits(),
|
|
441
|
-
'cardType' => $card->getCardType(),
|
|
442
|
-
],
|
|
443
|
-
];
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
return [
|
|
447
|
-
'status' => 'error',
|
|
448
|
-
'message' => $card->getErrorMessage() ?? 'Card save failed.',
|
|
449
|
-
'data' => ['errorCode' => $card->getErrorCode()],
|
|
450
|
-
];
|
|
451
|
-
} catch (\Exception $e) {
|
|
452
|
-
return [
|
|
453
|
-
'status' => 'error',
|
|
454
|
-
'message' => $e->getMessage(),
|
|
455
|
-
'data' => [],
|
|
456
|
-
];
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
/**
|
|
461
|
-
* Retrieve all saved cards for a given card user key.
|
|
462
|
-
*
|
|
463
|
-
* @param string $cardUserKey The user key returned when a card was first saved
|
|
464
|
-
* @return array Standardised response with array of cards
|
|
465
|
-
*/
|
|
466
|
-
public function listCards(string $cardUserKey): array
|
|
467
|
-
{
|
|
468
|
-
try {
|
|
469
|
-
$request = new \Iyzipay\Request\RetrieveCardListRequest();
|
|
470
|
-
$request->setLocale(\Iyzipay\Model\Locale::TR);
|
|
471
|
-
$request->setConversationId(uniqid('cards_'));
|
|
472
|
-
$request->setCardUserKey($cardUserKey);
|
|
473
|
-
|
|
474
|
-
$cardList = \Iyzipay\Model\CardList::retrieve($request, $this->options);
|
|
475
|
-
|
|
476
|
-
if ($cardList->getStatus() === 'success') {
|
|
477
|
-
$cards = [];
|
|
478
|
-
foreach ($cardList->getCardDetails() as $card) {
|
|
479
|
-
$cards[] = [
|
|
480
|
-
'cardToken' => $card->getCardToken(),
|
|
481
|
-
'cardAlias' => $card->getCardAlias(),
|
|
482
|
-
'binNumber' => $card->getBinNumber(),
|
|
483
|
-
'lastFourDigits' => $card->getLastFourDigits(),
|
|
484
|
-
'cardType' => $card->getCardType(),
|
|
485
|
-
'cardAssociation'=> $card->getCardAssociation(),
|
|
486
|
-
'cardFamily' => $card->getCardFamily(),
|
|
487
|
-
];
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
return [
|
|
491
|
-
'status' => 'success',
|
|
492
|
-
'message' => 'Cards retrieved successfully.',
|
|
493
|
-
'data' => [
|
|
494
|
-
'cardUserKey' => $cardList->getCardUserKey(),
|
|
495
|
-
'cards' => $cards,
|
|
496
|
-
],
|
|
497
|
-
];
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
return [
|
|
501
|
-
'status' => 'error',
|
|
502
|
-
'message' => $cardList->getErrorMessage() ?? 'Could not retrieve cards.',
|
|
503
|
-
'data' => ['errorCode' => $cardList->getErrorCode()],
|
|
504
|
-
];
|
|
505
|
-
} catch (\Exception $e) {
|
|
506
|
-
return [
|
|
507
|
-
'status' => 'error',
|
|
508
|
-
'message' => $e->getMessage(),
|
|
509
|
-
'data' => [],
|
|
510
|
-
];
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
/**
|
|
515
|
-
* Query the status of an existing payment.
|
|
516
|
-
*
|
|
517
|
-
* @param string $paymentId The payment ID to query
|
|
518
|
-
* @return array Standardised response with payment details
|
|
519
|
-
*/
|
|
520
|
-
public function checkPayment(string $paymentId): array
|
|
521
|
-
{
|
|
522
|
-
try {
|
|
523
|
-
$request = new \Iyzipay\Request\RetrievePaymentRequest();
|
|
524
|
-
$request->setLocale(\Iyzipay\Model\Locale::TR);
|
|
525
|
-
$request->setConversationId(uniqid('check_'));
|
|
526
|
-
$request->setPaymentId($paymentId);
|
|
527
|
-
|
|
528
|
-
$payment = \Iyzipay\Model\Payment::retrieve($request, $this->options);
|
|
529
|
-
|
|
530
|
-
if ($payment->getStatus() === 'success') {
|
|
531
|
-
$items = [];
|
|
532
|
-
if ($payment->getPaymentItems()) {
|
|
533
|
-
foreach ($payment->getPaymentItems() as $item) {
|
|
534
|
-
$items[] = [
|
|
535
|
-
'itemId' => $item->getItemId(),
|
|
536
|
-
'paymentTransactionId' => $item->getPaymentTransactionId(),
|
|
537
|
-
'price' => $item->getPrice(),
|
|
538
|
-
'paidPrice' => $item->getPaidPrice(),
|
|
539
|
-
'transactionStatus' => $item->getTransactionStatus(),
|
|
540
|
-
];
|
|
541
|
-
}
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
return [
|
|
545
|
-
'status' => 'success',
|
|
546
|
-
'message' => 'Payment details retrieved.',
|
|
547
|
-
'data' => [
|
|
548
|
-
'paymentId' => $payment->getPaymentId(),
|
|
549
|
-
'price' => $payment->getPrice(),
|
|
550
|
-
'paidPrice' => $payment->getPaidPrice(),
|
|
551
|
-
'currency' => $payment->getCurrency(),
|
|
552
|
-
'installment' => $payment->getInstallment(),
|
|
553
|
-
'paymentStatus'=> $payment->getPaymentStatus(),
|
|
554
|
-
'fraudStatus' => $payment->getFraudStatus(),
|
|
555
|
-
'cardType' => $payment->getCardType(),
|
|
556
|
-
'lastFourDigits' => $payment->getLastFourDigits(),
|
|
557
|
-
'items' => $items,
|
|
558
|
-
],
|
|
559
|
-
];
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
return [
|
|
563
|
-
'status' => 'error',
|
|
564
|
-
'message' => $payment->getErrorMessage() ?? 'Could not retrieve payment.',
|
|
565
|
-
'data' => ['errorCode' => $payment->getErrorCode()],
|
|
566
|
-
];
|
|
567
|
-
} catch (\Exception $e) {
|
|
568
|
-
return [
|
|
569
|
-
'status' => 'error',
|
|
570
|
-
'message' => $e->getMessage(),
|
|
571
|
-
'data' => [],
|
|
572
|
-
];
|
|
573
|
-
}
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
/**
|
|
577
|
-
* Register a new sub-merchant for marketplace payments.
|
|
578
|
-
*
|
|
579
|
-
* @param array $data {
|
|
580
|
-
* @type string $name Sub-merchant legal name
|
|
581
|
-
* @type string $type PERSONAL_COMPANY | PRIVATE_COMPANY | LIMITED_OR_JOINT_STOCK_COMPANY
|
|
582
|
-
* @type string $taxOffice Tax office name
|
|
583
|
-
* @type string $taxNumber Tax / identity number
|
|
584
|
-
* @type string $legalCompanyName Legal company title
|
|
585
|
-
* @type string $email Contact e-mail
|
|
586
|
-
* @type string $phone Contact phone (GSM)
|
|
587
|
-
* @type string $address Registered address
|
|
588
|
-
* @type string $iban IBAN for payouts
|
|
589
|
-
* @type string $currency Currency code (default: TRY)
|
|
590
|
-
* @type string $subMerchantExternalId Unique external identifier
|
|
591
|
-
* }
|
|
592
|
-
* @return array Standardised response with subMerchantKey
|
|
593
|
-
*/
|
|
594
|
-
public function createSubMerchant(array $data): array
|
|
595
|
-
{
|
|
596
|
-
try {
|
|
597
|
-
$request = new \Iyzipay\Request\CreateSubMerchantRequest();
|
|
598
|
-
$request->setLocale(\Iyzipay\Model\Locale::TR);
|
|
599
|
-
$request->setConversationId(uniqid('sub_'));
|
|
600
|
-
$request->setSubMerchantExternalId($data['subMerchantExternalId'] ?? uniqid('sm_'));
|
|
601
|
-
$request->setSubMerchantType($data['type'] ?? \Iyzipay\Model\SubMerchantType::LIMITED_OR_JOINT_STOCK_COMPANY);
|
|
602
|
-
$request->setAddress($data['address']);
|
|
603
|
-
$request->setTaxOffice($data['taxOffice'] ?? '');
|
|
604
|
-
$request->setLegalCompanyTitle($data['legalCompanyName'] ?? $data['name']);
|
|
605
|
-
$request->setEmail($data['email']);
|
|
606
|
-
$request->setGsmNumber($data['phone']);
|
|
607
|
-
$request->setName($data['name']);
|
|
608
|
-
$request->setIban($data['iban']);
|
|
609
|
-
$request->setIdentityNumber($data['taxNumber'] ?? '00000000000');
|
|
610
|
-
$request->setCurrency($data['currency'] ?? \Iyzipay\Model\Currency::TL);
|
|
611
|
-
|
|
612
|
-
$subMerchant = \Iyzipay\Model\SubMerchant::create($request, $this->options);
|
|
613
|
-
|
|
614
|
-
if ($subMerchant->getStatus() === 'success') {
|
|
615
|
-
return [
|
|
616
|
-
'status' => 'success',
|
|
617
|
-
'message' => 'Sub-merchant created successfully.',
|
|
618
|
-
'data' => [
|
|
619
|
-
'subMerchantKey' => $subMerchant->getSubMerchantKey(),
|
|
620
|
-
],
|
|
621
|
-
];
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
return [
|
|
625
|
-
'status' => 'error',
|
|
626
|
-
'message' => $subMerchant->getErrorMessage() ?? 'Sub-merchant creation failed.',
|
|
627
|
-
'data' => ['errorCode' => $subMerchant->getErrorCode()],
|
|
628
|
-
];
|
|
629
|
-
} catch (\Exception $e) {
|
|
630
|
-
return [
|
|
631
|
-
'status' => 'error',
|
|
632
|
-
'message' => $e->getMessage(),
|
|
633
|
-
'data' => [],
|
|
634
|
-
];
|
|
635
|
-
}
|
|
636
|
-
}
|
|
637
|
-
}
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
namespace Src\Service;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Iyzico Payment Service
|
|
7
|
+
*
|
|
8
|
+
* Provides a clean wrapper around the iyzipay-php SDK for payment processing,
|
|
9
|
+
* 3D Secure flows, refunds, cancellations, card vault, and marketplace sub-merchants.
|
|
10
|
+
*
|
|
11
|
+
* Required environment variables:
|
|
12
|
+
* IYZICO_API_KEY — Your iyzico API key
|
|
13
|
+
* IYZICO_SECRET_KEY — Your iyzico secret key
|
|
14
|
+
* IYZICO_BASE_URL — API base URL (https://sandbox-api.iyzipay.com or https://api.iyzipay.com)
|
|
15
|
+
*
|
|
16
|
+
* @package Service
|
|
17
|
+
*/
|
|
18
|
+
class Iyzico
|
|
19
|
+
{
|
|
20
|
+
/**
|
|
21
|
+
* Iyzipay connection options.
|
|
22
|
+
*
|
|
23
|
+
* @var \Iyzipay\Options
|
|
24
|
+
*/
|
|
25
|
+
private \Iyzipay\Options $options;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Create a new Iyzico service instance.
|
|
29
|
+
*
|
|
30
|
+
* Reads API credentials and base URL from $_ENV and builds
|
|
31
|
+
* the \Iyzipay\Options object used by every SDK call.
|
|
32
|
+
*/
|
|
33
|
+
public function __construct()
|
|
34
|
+
{
|
|
35
|
+
$this->options = new \Iyzipay\Options();
|
|
36
|
+
$this->options->setApiKey($_ENV['IYZICO_API_KEY']);
|
|
37
|
+
$this->options->setSecretKey($_ENV['IYZICO_SECRET_KEY']);
|
|
38
|
+
$this->options->setBaseUrl($_ENV['IYZICO_BASE_URL']);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Process a single (non-3D) payment.
|
|
43
|
+
*
|
|
44
|
+
* @param array $data {
|
|
45
|
+
* @type float $price Base price
|
|
46
|
+
* @type float $paidPrice Final charged price (including installment cost)
|
|
47
|
+
* @type string $currency ISO currency code (default: TRY)
|
|
48
|
+
* @type int $installment Number of installments (default: 1)
|
|
49
|
+
* @type array $card {
|
|
50
|
+
* @type string $holder Card holder full name
|
|
51
|
+
* @type string $number Card number
|
|
52
|
+
* @type string $month Expiry month (2 digits)
|
|
53
|
+
* @type string $year Expiry year (4 digits)
|
|
54
|
+
* @type string $cvc CVC / CVV code
|
|
55
|
+
* }
|
|
56
|
+
* @type array $buyer {
|
|
57
|
+
* @type string $id Merchant-side buyer ID
|
|
58
|
+
* @type string $name First name
|
|
59
|
+
* @type string $surname Last name
|
|
60
|
+
* @type string $email E-mail address
|
|
61
|
+
* @type string $phone Phone number
|
|
62
|
+
* @type string $ip IP address of buyer
|
|
63
|
+
* @type string $city City
|
|
64
|
+
* @type string $country Country
|
|
65
|
+
* @type string $address Full address line
|
|
66
|
+
* @type string $zipCode ZIP / postal code
|
|
67
|
+
* }
|
|
68
|
+
* @type array $items Array of basket items, each having name, price, category
|
|
69
|
+
* }
|
|
70
|
+
* @return array Standardised response with status, message, and data keys
|
|
71
|
+
*/
|
|
72
|
+
public function pay(array $data): array
|
|
73
|
+
{
|
|
74
|
+
try {
|
|
75
|
+
$request = new \Iyzipay\Request\CreatePaymentRequest();
|
|
76
|
+
$request->setLocale(\Iyzipay\Model\Locale::TR);
|
|
77
|
+
$request->setConversationId(uniqid('pay_'));
|
|
78
|
+
$request->setPrice($data['price']);
|
|
79
|
+
$request->setPaidPrice($data['paidPrice']);
|
|
80
|
+
$request->setCurrency($data['currency'] ?? \Iyzipay\Model\Currency::TL);
|
|
81
|
+
$request->setInstallment($data['installment'] ?? 1);
|
|
82
|
+
$request->setPaymentChannel(\Iyzipay\Model\PaymentChannel::WEB);
|
|
83
|
+
$request->setPaymentGroup(\Iyzipay\Model\PaymentGroup::PRODUCT);
|
|
84
|
+
|
|
85
|
+
// Payment card
|
|
86
|
+
$card = new \Iyzipay\Model\PaymentCard();
|
|
87
|
+
$card->setCardHolderName($data['card']['holder']);
|
|
88
|
+
$card->setCardNumber($data['card']['number']);
|
|
89
|
+
$card->setExpireMonth($data['card']['month']);
|
|
90
|
+
$card->setExpireYear($data['card']['year']);
|
|
91
|
+
$card->setCvc($data['card']['cvc']);
|
|
92
|
+
$card->setRegisterCard(0);
|
|
93
|
+
$request->setPaymentCard($card);
|
|
94
|
+
|
|
95
|
+
// Buyer
|
|
96
|
+
$buyer = new \Iyzipay\Model\Buyer();
|
|
97
|
+
$buyer->setId($data['buyer']['id']);
|
|
98
|
+
$buyer->setName($data['buyer']['name']);
|
|
99
|
+
$buyer->setSurname($data['buyer']['surname']);
|
|
100
|
+
$buyer->setEmail($data['buyer']['email']);
|
|
101
|
+
$buyer->setGsmNumber($data['buyer']['phone']);
|
|
102
|
+
$buyer->setIp($data['buyer']['ip']);
|
|
103
|
+
$buyer->setCity($data['buyer']['city']);
|
|
104
|
+
$buyer->setCountry($data['buyer']['country']);
|
|
105
|
+
$buyer->setRegistrationAddress($data['buyer']['address']);
|
|
106
|
+
$buyer->setZipCode($data['buyer']['zipCode']);
|
|
107
|
+
$buyer->setIdentityNumber('00000000000');
|
|
108
|
+
$request->setBuyer($buyer);
|
|
109
|
+
|
|
110
|
+
// Shipping & billing address (use buyer address for both)
|
|
111
|
+
$address = new \Iyzipay\Model\Address();
|
|
112
|
+
$address->setContactName($data['buyer']['name'] . ' ' . $data['buyer']['surname']);
|
|
113
|
+
$address->setCity($data['buyer']['city']);
|
|
114
|
+
$address->setCountry($data['buyer']['country']);
|
|
115
|
+
$address->setAddress($data['buyer']['address']);
|
|
116
|
+
$address->setZipCode($data['buyer']['zipCode']);
|
|
117
|
+
$request->setShippingAddress($address);
|
|
118
|
+
$request->setBillingAddress($address);
|
|
119
|
+
|
|
120
|
+
// Basket items
|
|
121
|
+
$basketItems = [];
|
|
122
|
+
foreach ($data['items'] as $index => $item) {
|
|
123
|
+
$basketItem = new \Iyzipay\Model\BasketItem();
|
|
124
|
+
$basketItem->setId('ITEM_' . ($index + 1));
|
|
125
|
+
$basketItem->setName($item['name']);
|
|
126
|
+
$basketItem->setCategory1($item['category'] ?? 'Default');
|
|
127
|
+
$basketItem->setItemType(\Iyzipay\Model\BasketItemType::PHYSICAL);
|
|
128
|
+
$basketItem->setPrice($item['price']);
|
|
129
|
+
$basketItems[] = $basketItem;
|
|
130
|
+
}
|
|
131
|
+
$request->setBasketItems($basketItems);
|
|
132
|
+
|
|
133
|
+
$payment = \Iyzipay\Model\Payment::create($request, $this->options);
|
|
134
|
+
|
|
135
|
+
if ($payment->getStatus() === 'success') {
|
|
136
|
+
return [
|
|
137
|
+
'status' => 'success',
|
|
138
|
+
'message' => 'Payment processed successfully.',
|
|
139
|
+
'data' => [
|
|
140
|
+
'paymentId' => $payment->getPaymentId(),
|
|
141
|
+
'price' => $payment->getPrice(),
|
|
142
|
+
'paidPrice' => $payment->getPaidPrice(),
|
|
143
|
+
'currency' => $payment->getCurrency(),
|
|
144
|
+
'installment' => $payment->getInstallment(),
|
|
145
|
+
'paymentTransactionId' => $payment->getPaymentItems()[0]->getPaymentTransactionId() ?? null,
|
|
146
|
+
'fraudStatus' => $payment->getFraudStatus(),
|
|
147
|
+
],
|
|
148
|
+
];
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return [
|
|
152
|
+
'status' => 'error',
|
|
153
|
+
'message' => $payment->getErrorMessage() ?? 'Payment failed.',
|
|
154
|
+
'data' => ['errorCode' => $payment->getErrorCode()],
|
|
155
|
+
];
|
|
156
|
+
} catch (\Exception $e) {
|
|
157
|
+
return [
|
|
158
|
+
'status' => 'error',
|
|
159
|
+
'message' => $e->getMessage(),
|
|
160
|
+
'data' => [],
|
|
161
|
+
];
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Initialise a 3D Secure payment flow.
|
|
167
|
+
*
|
|
168
|
+
* Returns an HTML snippet that must be rendered in the buyer's browser
|
|
169
|
+
* to redirect them to the bank's 3D Secure verification page.
|
|
170
|
+
*
|
|
171
|
+
* @param array $data Same structure as pay() with an additional `callbackUrl` key
|
|
172
|
+
* @return array Response containing threeDSHtmlContent on success
|
|
173
|
+
*/
|
|
174
|
+
public function threeDSecureInit(array $data): array
|
|
175
|
+
{
|
|
176
|
+
try {
|
|
177
|
+
$request = new \Iyzipay\Request\CreatePaymentRequest();
|
|
178
|
+
$request->setLocale(\Iyzipay\Model\Locale::TR);
|
|
179
|
+
$request->setConversationId(uniqid('3ds_'));
|
|
180
|
+
$request->setPrice($data['price']);
|
|
181
|
+
$request->setPaidPrice($data['paidPrice']);
|
|
182
|
+
$request->setCurrency($data['currency'] ?? \Iyzipay\Model\Currency::TL);
|
|
183
|
+
$request->setInstallment($data['installment'] ?? 1);
|
|
184
|
+
$request->setPaymentChannel(\Iyzipay\Model\PaymentChannel::WEB);
|
|
185
|
+
$request->setPaymentGroup(\Iyzipay\Model\PaymentGroup::PRODUCT);
|
|
186
|
+
$request->setCallbackUrl($data['callbackUrl']);
|
|
187
|
+
|
|
188
|
+
// Payment card
|
|
189
|
+
$card = new \Iyzipay\Model\PaymentCard();
|
|
190
|
+
$card->setCardHolderName($data['card']['holder']);
|
|
191
|
+
$card->setCardNumber($data['card']['number']);
|
|
192
|
+
$card->setExpireMonth($data['card']['month']);
|
|
193
|
+
$card->setExpireYear($data['card']['year']);
|
|
194
|
+
$card->setCvc($data['card']['cvc']);
|
|
195
|
+
$card->setRegisterCard(0);
|
|
196
|
+
$request->setPaymentCard($card);
|
|
197
|
+
|
|
198
|
+
// Buyer
|
|
199
|
+
$buyer = new \Iyzipay\Model\Buyer();
|
|
200
|
+
$buyer->setId($data['buyer']['id']);
|
|
201
|
+
$buyer->setName($data['buyer']['name']);
|
|
202
|
+
$buyer->setSurname($data['buyer']['surname']);
|
|
203
|
+
$buyer->setEmail($data['buyer']['email']);
|
|
204
|
+
$buyer->setGsmNumber($data['buyer']['phone']);
|
|
205
|
+
$buyer->setIp($data['buyer']['ip']);
|
|
206
|
+
$buyer->setCity($data['buyer']['city']);
|
|
207
|
+
$buyer->setCountry($data['buyer']['country']);
|
|
208
|
+
$buyer->setRegistrationAddress($data['buyer']['address']);
|
|
209
|
+
$buyer->setZipCode($data['buyer']['zipCode']);
|
|
210
|
+
$buyer->setIdentityNumber('00000000000');
|
|
211
|
+
$request->setBuyer($buyer);
|
|
212
|
+
|
|
213
|
+
// Address
|
|
214
|
+
$address = new \Iyzipay\Model\Address();
|
|
215
|
+
$address->setContactName($data['buyer']['name'] . ' ' . $data['buyer']['surname']);
|
|
216
|
+
$address->setCity($data['buyer']['city']);
|
|
217
|
+
$address->setCountry($data['buyer']['country']);
|
|
218
|
+
$address->setAddress($data['buyer']['address']);
|
|
219
|
+
$address->setZipCode($data['buyer']['zipCode']);
|
|
220
|
+
$request->setShippingAddress($address);
|
|
221
|
+
$request->setBillingAddress($address);
|
|
222
|
+
|
|
223
|
+
// Basket items
|
|
224
|
+
$basketItems = [];
|
|
225
|
+
foreach ($data['items'] as $index => $item) {
|
|
226
|
+
$basketItem = new \Iyzipay\Model\BasketItem();
|
|
227
|
+
$basketItem->setId('ITEM_' . ($index + 1));
|
|
228
|
+
$basketItem->setName($item['name']);
|
|
229
|
+
$basketItem->setCategory1($item['category'] ?? 'Default');
|
|
230
|
+
$basketItem->setItemType(\Iyzipay\Model\BasketItemType::PHYSICAL);
|
|
231
|
+
$basketItem->setPrice($item['price']);
|
|
232
|
+
$basketItems[] = $basketItem;
|
|
233
|
+
}
|
|
234
|
+
$request->setBasketItems($basketItems);
|
|
235
|
+
|
|
236
|
+
$threedsInit = \Iyzipay\Model\ThreedsInitialize::create($request, $this->options);
|
|
237
|
+
|
|
238
|
+
if ($threedsInit->getStatus() === 'success') {
|
|
239
|
+
return [
|
|
240
|
+
'status' => 'success',
|
|
241
|
+
'message' => '3D Secure initialisation successful.',
|
|
242
|
+
'data' => [
|
|
243
|
+
'threeDSHtmlContent' => $threedsInit->getHtmlContent(),
|
|
244
|
+
],
|
|
245
|
+
];
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return [
|
|
249
|
+
'status' => 'error',
|
|
250
|
+
'message' => $threedsInit->getErrorMessage() ?? '3D Secure initialisation failed.',
|
|
251
|
+
'data' => ['errorCode' => $threedsInit->getErrorCode()],
|
|
252
|
+
];
|
|
253
|
+
} catch (\Exception $e) {
|
|
254
|
+
return [
|
|
255
|
+
'status' => 'error',
|
|
256
|
+
'message' => $e->getMessage(),
|
|
257
|
+
'data' => [],
|
|
258
|
+
];
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Complete a 3D Secure payment after bank verification callback.
|
|
264
|
+
*
|
|
265
|
+
* Call this from your callback URL handler with the paymentId received
|
|
266
|
+
* from the bank's POST response.
|
|
267
|
+
*
|
|
268
|
+
* @param array $data {
|
|
269
|
+
* @type string $paymentId The payment ID returned by the bank callback
|
|
270
|
+
* }
|
|
271
|
+
* @return array Standardised response
|
|
272
|
+
*/
|
|
273
|
+
public function threeDSecureComplete(array $data): array
|
|
274
|
+
{
|
|
275
|
+
try {
|
|
276
|
+
$request = new \Iyzipay\Request\CreateThreedsPaymentRequest();
|
|
277
|
+
$request->setLocale(\Iyzipay\Model\Locale::TR);
|
|
278
|
+
$request->setConversationId(uniqid('3ds_complete_'));
|
|
279
|
+
$request->setPaymentId($data['paymentId']);
|
|
280
|
+
|
|
281
|
+
$threedsPayment = \Iyzipay\Model\ThreedsPayment::create($request, $this->options);
|
|
282
|
+
|
|
283
|
+
if ($threedsPayment->getStatus() === 'success') {
|
|
284
|
+
return [
|
|
285
|
+
'status' => 'success',
|
|
286
|
+
'message' => '3D Secure payment completed successfully.',
|
|
287
|
+
'data' => [
|
|
288
|
+
'paymentId' => $threedsPayment->getPaymentId(),
|
|
289
|
+
'price' => $threedsPayment->getPrice(),
|
|
290
|
+
'paidPrice' => $threedsPayment->getPaidPrice(),
|
|
291
|
+
'currency' => $threedsPayment->getCurrency(),
|
|
292
|
+
'fraudStatus' => $threedsPayment->getFraudStatus(),
|
|
293
|
+
],
|
|
294
|
+
];
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
return [
|
|
298
|
+
'status' => 'error',
|
|
299
|
+
'message' => $threedsPayment->getErrorMessage() ?? '3D Secure completion failed.',
|
|
300
|
+
'data' => ['errorCode' => $threedsPayment->getErrorCode()],
|
|
301
|
+
];
|
|
302
|
+
} catch (\Exception $e) {
|
|
303
|
+
return [
|
|
304
|
+
'status' => 'error',
|
|
305
|
+
'message' => $e->getMessage(),
|
|
306
|
+
'data' => [],
|
|
307
|
+
];
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Refund a specific payment transaction.
|
|
313
|
+
*
|
|
314
|
+
* @param string $paymentTransactionId The transaction ID to refund (from basket item)
|
|
315
|
+
* @param float $price Amount to refund
|
|
316
|
+
* @return array Standardised response
|
|
317
|
+
*/
|
|
318
|
+
public function refund(string $paymentTransactionId, float $price): array
|
|
319
|
+
{
|
|
320
|
+
try {
|
|
321
|
+
$request = new \Iyzipay\Request\CreateRefundRequest();
|
|
322
|
+
$request->setLocale(\Iyzipay\Model\Locale::TR);
|
|
323
|
+
$request->setConversationId(uniqid('refund_'));
|
|
324
|
+
$request->setPaymentTransactionId($paymentTransactionId);
|
|
325
|
+
$request->setPrice($price);
|
|
326
|
+
$request->setCurrency(\Iyzipay\Model\Currency::TL);
|
|
327
|
+
$request->setIp('127.0.0.1');
|
|
328
|
+
|
|
329
|
+
$refund = \Iyzipay\Model\Refund::create($request, $this->options);
|
|
330
|
+
|
|
331
|
+
if ($refund->getStatus() === 'success') {
|
|
332
|
+
return [
|
|
333
|
+
'status' => 'success',
|
|
334
|
+
'message' => 'Refund processed successfully.',
|
|
335
|
+
'data' => [
|
|
336
|
+
'paymentId' => $refund->getPaymentId(),
|
|
337
|
+
'paymentTransactionId' => $refund->getPaymentTransactionId(),
|
|
338
|
+
'price' => $refund->getPrice(),
|
|
339
|
+
],
|
|
340
|
+
];
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
return [
|
|
344
|
+
'status' => 'error',
|
|
345
|
+
'message' => $refund->getErrorMessage() ?? 'Refund failed.',
|
|
346
|
+
'data' => ['errorCode' => $refund->getErrorCode()],
|
|
347
|
+
];
|
|
348
|
+
} catch (\Exception $e) {
|
|
349
|
+
return [
|
|
350
|
+
'status' => 'error',
|
|
351
|
+
'message' => $e->getMessage(),
|
|
352
|
+
'data' => [],
|
|
353
|
+
];
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Cancel an entire payment.
|
|
359
|
+
*
|
|
360
|
+
* @param string $paymentId The payment ID to cancel
|
|
361
|
+
* @return array Standardised response
|
|
362
|
+
*/
|
|
363
|
+
public function cancel(string $paymentId): array
|
|
364
|
+
{
|
|
365
|
+
try {
|
|
366
|
+
$request = new \Iyzipay\Request\CreateCancelRequest();
|
|
367
|
+
$request->setLocale(\Iyzipay\Model\Locale::TR);
|
|
368
|
+
$request->setConversationId(uniqid('cancel_'));
|
|
369
|
+
$request->setPaymentId($paymentId);
|
|
370
|
+
$request->setIp('127.0.0.1');
|
|
371
|
+
|
|
372
|
+
$cancel = \Iyzipay\Model\Cancel::create($request, $this->options);
|
|
373
|
+
|
|
374
|
+
if ($cancel->getStatus() === 'success') {
|
|
375
|
+
return [
|
|
376
|
+
'status' => 'success',
|
|
377
|
+
'message' => 'Payment cancelled successfully.',
|
|
378
|
+
'data' => [
|
|
379
|
+
'paymentId' => $cancel->getPaymentId(),
|
|
380
|
+
'price' => $cancel->getPrice(),
|
|
381
|
+
'currency' => $cancel->getCurrency(),
|
|
382
|
+
],
|
|
383
|
+
];
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
return [
|
|
387
|
+
'status' => 'error',
|
|
388
|
+
'message' => $cancel->getErrorMessage() ?? 'Cancellation failed.',
|
|
389
|
+
'data' => ['errorCode' => $cancel->getErrorCode()],
|
|
390
|
+
];
|
|
391
|
+
} catch (\Exception $e) {
|
|
392
|
+
return [
|
|
393
|
+
'status' => 'error',
|
|
394
|
+
'message' => $e->getMessage(),
|
|
395
|
+
'data' => [],
|
|
396
|
+
];
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* Save a card to the iyzico card vault for future payments.
|
|
402
|
+
*
|
|
403
|
+
* @param array $cardData {
|
|
404
|
+
* @type string $holder Card holder full name
|
|
405
|
+
* @type string $number Card number
|
|
406
|
+
* @type string $month Expiry month
|
|
407
|
+
* @type string $year Expiry year
|
|
408
|
+
* @type string $alias A user-friendly card alias (e.g. "My Visa")
|
|
409
|
+
* }
|
|
410
|
+
* @param string $email Buyer e-mail (used as external identifier)
|
|
411
|
+
* @return array Standardised response with cardUserKey and cardToken
|
|
412
|
+
*/
|
|
413
|
+
public function saveCard(array $cardData, string $email): array
|
|
414
|
+
{
|
|
415
|
+
try {
|
|
416
|
+
$request = new \Iyzipay\Request\CreateCardRequest();
|
|
417
|
+
$request->setLocale(\Iyzipay\Model\Locale::TR);
|
|
418
|
+
$request->setConversationId(uniqid('card_'));
|
|
419
|
+
$request->setEmail($email);
|
|
420
|
+
$request->setExternalId(md5($email));
|
|
421
|
+
|
|
422
|
+
$cardInfo = new \Iyzipay\Model\CardInformation();
|
|
423
|
+
$cardInfo->setCardAlias($cardData['alias'] ?? 'Default Card');
|
|
424
|
+
$cardInfo->setCardHolderName($cardData['holder']);
|
|
425
|
+
$cardInfo->setCardNumber($cardData['number']);
|
|
426
|
+
$cardInfo->setExpireMonth($cardData['month']);
|
|
427
|
+
$cardInfo->setExpireYear($cardData['year']);
|
|
428
|
+
$request->setCard($cardInfo);
|
|
429
|
+
|
|
430
|
+
$card = \Iyzipay\Model\Card::create($request, $this->options);
|
|
431
|
+
|
|
432
|
+
if ($card->getStatus() === 'success') {
|
|
433
|
+
return [
|
|
434
|
+
'status' => 'success',
|
|
435
|
+
'message' => 'Card saved successfully.',
|
|
436
|
+
'data' => [
|
|
437
|
+
'cardUserKey' => $card->getCardUserKey(),
|
|
438
|
+
'cardToken' => $card->getCardToken(),
|
|
439
|
+
'cardAlias' => $card->getCardAlias(),
|
|
440
|
+
'lastFour' => $card->getLastFourDigits(),
|
|
441
|
+
'cardType' => $card->getCardType(),
|
|
442
|
+
],
|
|
443
|
+
];
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
return [
|
|
447
|
+
'status' => 'error',
|
|
448
|
+
'message' => $card->getErrorMessage() ?? 'Card save failed.',
|
|
449
|
+
'data' => ['errorCode' => $card->getErrorCode()],
|
|
450
|
+
];
|
|
451
|
+
} catch (\Exception $e) {
|
|
452
|
+
return [
|
|
453
|
+
'status' => 'error',
|
|
454
|
+
'message' => $e->getMessage(),
|
|
455
|
+
'data' => [],
|
|
456
|
+
];
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* Retrieve all saved cards for a given card user key.
|
|
462
|
+
*
|
|
463
|
+
* @param string $cardUserKey The user key returned when a card was first saved
|
|
464
|
+
* @return array Standardised response with array of cards
|
|
465
|
+
*/
|
|
466
|
+
public function listCards(string $cardUserKey): array
|
|
467
|
+
{
|
|
468
|
+
try {
|
|
469
|
+
$request = new \Iyzipay\Request\RetrieveCardListRequest();
|
|
470
|
+
$request->setLocale(\Iyzipay\Model\Locale::TR);
|
|
471
|
+
$request->setConversationId(uniqid('cards_'));
|
|
472
|
+
$request->setCardUserKey($cardUserKey);
|
|
473
|
+
|
|
474
|
+
$cardList = \Iyzipay\Model\CardList::retrieve($request, $this->options);
|
|
475
|
+
|
|
476
|
+
if ($cardList->getStatus() === 'success') {
|
|
477
|
+
$cards = [];
|
|
478
|
+
foreach ($cardList->getCardDetails() as $card) {
|
|
479
|
+
$cards[] = [
|
|
480
|
+
'cardToken' => $card->getCardToken(),
|
|
481
|
+
'cardAlias' => $card->getCardAlias(),
|
|
482
|
+
'binNumber' => $card->getBinNumber(),
|
|
483
|
+
'lastFourDigits' => $card->getLastFourDigits(),
|
|
484
|
+
'cardType' => $card->getCardType(),
|
|
485
|
+
'cardAssociation'=> $card->getCardAssociation(),
|
|
486
|
+
'cardFamily' => $card->getCardFamily(),
|
|
487
|
+
];
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
return [
|
|
491
|
+
'status' => 'success',
|
|
492
|
+
'message' => 'Cards retrieved successfully.',
|
|
493
|
+
'data' => [
|
|
494
|
+
'cardUserKey' => $cardList->getCardUserKey(),
|
|
495
|
+
'cards' => $cards,
|
|
496
|
+
],
|
|
497
|
+
];
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
return [
|
|
501
|
+
'status' => 'error',
|
|
502
|
+
'message' => $cardList->getErrorMessage() ?? 'Could not retrieve cards.',
|
|
503
|
+
'data' => ['errorCode' => $cardList->getErrorCode()],
|
|
504
|
+
];
|
|
505
|
+
} catch (\Exception $e) {
|
|
506
|
+
return [
|
|
507
|
+
'status' => 'error',
|
|
508
|
+
'message' => $e->getMessage(),
|
|
509
|
+
'data' => [],
|
|
510
|
+
];
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
/**
|
|
515
|
+
* Query the status of an existing payment.
|
|
516
|
+
*
|
|
517
|
+
* @param string $paymentId The payment ID to query
|
|
518
|
+
* @return array Standardised response with payment details
|
|
519
|
+
*/
|
|
520
|
+
public function checkPayment(string $paymentId): array
|
|
521
|
+
{
|
|
522
|
+
try {
|
|
523
|
+
$request = new \Iyzipay\Request\RetrievePaymentRequest();
|
|
524
|
+
$request->setLocale(\Iyzipay\Model\Locale::TR);
|
|
525
|
+
$request->setConversationId(uniqid('check_'));
|
|
526
|
+
$request->setPaymentId($paymentId);
|
|
527
|
+
|
|
528
|
+
$payment = \Iyzipay\Model\Payment::retrieve($request, $this->options);
|
|
529
|
+
|
|
530
|
+
if ($payment->getStatus() === 'success') {
|
|
531
|
+
$items = [];
|
|
532
|
+
if ($payment->getPaymentItems()) {
|
|
533
|
+
foreach ($payment->getPaymentItems() as $item) {
|
|
534
|
+
$items[] = [
|
|
535
|
+
'itemId' => $item->getItemId(),
|
|
536
|
+
'paymentTransactionId' => $item->getPaymentTransactionId(),
|
|
537
|
+
'price' => $item->getPrice(),
|
|
538
|
+
'paidPrice' => $item->getPaidPrice(),
|
|
539
|
+
'transactionStatus' => $item->getTransactionStatus(),
|
|
540
|
+
];
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
return [
|
|
545
|
+
'status' => 'success',
|
|
546
|
+
'message' => 'Payment details retrieved.',
|
|
547
|
+
'data' => [
|
|
548
|
+
'paymentId' => $payment->getPaymentId(),
|
|
549
|
+
'price' => $payment->getPrice(),
|
|
550
|
+
'paidPrice' => $payment->getPaidPrice(),
|
|
551
|
+
'currency' => $payment->getCurrency(),
|
|
552
|
+
'installment' => $payment->getInstallment(),
|
|
553
|
+
'paymentStatus'=> $payment->getPaymentStatus(),
|
|
554
|
+
'fraudStatus' => $payment->getFraudStatus(),
|
|
555
|
+
'cardType' => $payment->getCardType(),
|
|
556
|
+
'lastFourDigits' => $payment->getLastFourDigits(),
|
|
557
|
+
'items' => $items,
|
|
558
|
+
],
|
|
559
|
+
];
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
return [
|
|
563
|
+
'status' => 'error',
|
|
564
|
+
'message' => $payment->getErrorMessage() ?? 'Could not retrieve payment.',
|
|
565
|
+
'data' => ['errorCode' => $payment->getErrorCode()],
|
|
566
|
+
];
|
|
567
|
+
} catch (\Exception $e) {
|
|
568
|
+
return [
|
|
569
|
+
'status' => 'error',
|
|
570
|
+
'message' => $e->getMessage(),
|
|
571
|
+
'data' => [],
|
|
572
|
+
];
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
/**
|
|
577
|
+
* Register a new sub-merchant for marketplace payments.
|
|
578
|
+
*
|
|
579
|
+
* @param array $data {
|
|
580
|
+
* @type string $name Sub-merchant legal name
|
|
581
|
+
* @type string $type PERSONAL_COMPANY | PRIVATE_COMPANY | LIMITED_OR_JOINT_STOCK_COMPANY
|
|
582
|
+
* @type string $taxOffice Tax office name
|
|
583
|
+
* @type string $taxNumber Tax / identity number
|
|
584
|
+
* @type string $legalCompanyName Legal company title
|
|
585
|
+
* @type string $email Contact e-mail
|
|
586
|
+
* @type string $phone Contact phone (GSM)
|
|
587
|
+
* @type string $address Registered address
|
|
588
|
+
* @type string $iban IBAN for payouts
|
|
589
|
+
* @type string $currency Currency code (default: TRY)
|
|
590
|
+
* @type string $subMerchantExternalId Unique external identifier
|
|
591
|
+
* }
|
|
592
|
+
* @return array Standardised response with subMerchantKey
|
|
593
|
+
*/
|
|
594
|
+
public function createSubMerchant(array $data): array
|
|
595
|
+
{
|
|
596
|
+
try {
|
|
597
|
+
$request = new \Iyzipay\Request\CreateSubMerchantRequest();
|
|
598
|
+
$request->setLocale(\Iyzipay\Model\Locale::TR);
|
|
599
|
+
$request->setConversationId(uniqid('sub_'));
|
|
600
|
+
$request->setSubMerchantExternalId($data['subMerchantExternalId'] ?? uniqid('sm_'));
|
|
601
|
+
$request->setSubMerchantType($data['type'] ?? \Iyzipay\Model\SubMerchantType::LIMITED_OR_JOINT_STOCK_COMPANY);
|
|
602
|
+
$request->setAddress($data['address']);
|
|
603
|
+
$request->setTaxOffice($data['taxOffice'] ?? '');
|
|
604
|
+
$request->setLegalCompanyTitle($data['legalCompanyName'] ?? $data['name']);
|
|
605
|
+
$request->setEmail($data['email']);
|
|
606
|
+
$request->setGsmNumber($data['phone']);
|
|
607
|
+
$request->setName($data['name']);
|
|
608
|
+
$request->setIban($data['iban']);
|
|
609
|
+
$request->setIdentityNumber($data['taxNumber'] ?? '00000000000');
|
|
610
|
+
$request->setCurrency($data['currency'] ?? \Iyzipay\Model\Currency::TL);
|
|
611
|
+
|
|
612
|
+
$subMerchant = \Iyzipay\Model\SubMerchant::create($request, $this->options);
|
|
613
|
+
|
|
614
|
+
if ($subMerchant->getStatus() === 'success') {
|
|
615
|
+
return [
|
|
616
|
+
'status' => 'success',
|
|
617
|
+
'message' => 'Sub-merchant created successfully.',
|
|
618
|
+
'data' => [
|
|
619
|
+
'subMerchantKey' => $subMerchant->getSubMerchantKey(),
|
|
620
|
+
],
|
|
621
|
+
];
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
return [
|
|
625
|
+
'status' => 'error',
|
|
626
|
+
'message' => $subMerchant->getErrorMessage() ?? 'Sub-merchant creation failed.',
|
|
627
|
+
'data' => ['errorCode' => $subMerchant->getErrorCode()],
|
|
628
|
+
];
|
|
629
|
+
} catch (\Exception $e) {
|
|
630
|
+
return [
|
|
631
|
+
'status' => 'error',
|
|
632
|
+
'message' => $e->getMessage(),
|
|
633
|
+
'data' => [],
|
|
634
|
+
];
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
}
|