Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
applepay.php
1<?php
2
4
9
14final class ApplePay
15{
16 private const MERCHANT_SESSION_GATEWAY = "https://apple-pay-gateway.apple.com/paymentservices/paymentSession";
17 private const FILE_PREFIX = "apple_pay_cert_";
18
19 private const HTTP_RESPONSE_CODE_OK = 200;
20
22 private $merchantIdentifier;
24 private $displayName;
26 private $domainName;
28 private $initiativeContext;
30 private $applePayCert;
31
40 public function __construct(string $merchantIdentifier, string $displayName, string $domainName, string $applePayCert)
41 {
42 $this->merchantIdentifier = $merchantIdentifier;
43 $this->displayName = $displayName;
44 $this->domainName = $domainName;
45 $this->applePayCert = $applePayCert;
46 }
47
51 public function setInitiativeContext(string $initiativeContext): void
52 {
53 $this->initiativeContext = $initiativeContext;
54 }
55
60 public function getWebSession($url): ServiceResult
61 {
62 $result = new ServiceResult();
63
64 $requestParameters = [
65 "merchantIdentifier" => $this->merchantIdentifier,
66 "displayName" => $this->displayName,
67 "initiativeContext" => $this->domainName,
68 "initiative" => "web",
69 ];
70
71 try
72 {
73 $result = $this->sendRequest($url, $requestParameters);
74 }
75 catch (Main\SystemException $ex)
76 {
77 $result->addError(new Main\Error("Failed to get web session"));
78 }
79
80 return $result;
81 }
82
87 {
88 $result = new ServiceResult();
89
90 $requestParameters = [
91 "merchantIdentifier" => hash("sha256", $this->merchantIdentifier),
92 "displayName" => $this->displayName,
93 "domainName" => $this->domainName,
94 "initiative" => "messaging",
95 "initiativeContext" => $this->initiativeContext,
96 ];
97
98 try
99 {
100 $result = $this->sendRequest(self::MERCHANT_SESSION_GATEWAY, $requestParameters);
101 }
102 catch (Main\SystemException $ex)
103 {
104 $result->addError(new Main\Error("Failed to get messenger session"));
105 }
106
107 return $result;
108 }
109
116 public function getIMessagePayment(Payment $payment, array $config): ServiceResult
117 {
118 $result = new ServiceResult();
119
120 $checkConfigResult = $this->checkConfig($config);
121 if (!$checkConfigResult->isSuccess())
122 {
123 $result->addErrors($checkConfigResult->getErrors());
124 return $result;
125 }
126
127 $messengerDataResult = $this->prepareIMessageData($payment, $config);
128 if (!$messengerDataResult->isSuccess())
129 {
130 $result->addErrors($messengerDataResult->getErrors());
131 return $result;
132 }
133
134 $result->setData($messengerDataResult->getData());
135
136 return $result;
137 }
138
145 private function prepareIMessageData(Payment $payment, array $config): ServiceResult
146 {
147 $result = new ServiceResult();
148
149 $merchantSessionResult = $this->getIMessageSession();
150 if (!$merchantSessionResult->isSuccess())
151 {
152 $result->addErrors($merchantSessionResult->getErrors());
153 return $result;
154 }
155
156 $orderId = $payment->getOrder()->getId();
157 $paymentSum = PriceMaths::roundPrecision($payment->getSum());
158
159 $receivedMessage = [
160 "style" => "icon",
161 "title" => $config["merchantDisplayName"],
162 "subtitle" => Loc::getMessage(
163 "SALE_APPLE_PAY_ORDER_SUBTITLE",
164 [
165 "#ORDER_ID#" => $orderId,
166 "#SUM#" => \SaleFormatCurrency($paymentSum, $payment->getField('CURRENCY')),
167 ]
168 ),
169 ];
170
171 $replyMessage = [
172 "title" => Loc::getMessage(
173 "SALE_APPLE_PAY_ORDER_SUBTITLE",
174 [
175 "#ORDER_ID#" => $orderId,
176 "#SUM#" => \SaleFormatCurrency($paymentSum, $payment->getField('CURRENCY')),
177 ]
178 ),
179 ];
180
181 $data = [
182 "requestIdentifier" => self::getUuid(),
183 "mspVersion" => "1.0",
184 "payment" => [
185 "paymentRequest" => [
186 "lineItems" => [
187 [
188 "label" => Loc::getMessage(
189 "SALE_APPLE_PAY_LINE_ITEM_ORDER",
190 [
191 "#ORDER_ID#" => $orderId,
192 ]
193 ),
194 "amount" => (string)$paymentSum,
195 "type" => "final"
196 ],
197 ],
198 "total" => [
199 "label" => Loc::getMessage("SALE_APPLE_PAY_LINE_ITEM_TOTAL"),
200 "amount" => (string)$paymentSum,
201 "type" => "final"
202 ],
203 "applePay" => [
204 "merchantIdentifier" => $this->merchantIdentifier,
205 "supportedNetworks" => $config["supportedNetworks"],
206 "merchantCapabilities" => $config["merchantCapabilities"] ?? ["supports3DS"],
207 ],
208 "merchantName" => $config["merchantName"],
209 "countryCode" => $config["countryCode"],
210 "currencyCode" => $payment->getField("CURRENCY"),
211 "requiredBillingContactFields" => $config["requiredBillingContactFields"] ?? [],
212 "requiredShippingContactFields" => $config["requiredShippingContactFields"] ?? [],
213 ],
214 "merchantSession" => $merchantSessionResult->getData(),
215 "endpoints" => $config["endpoints"]
216 ]
217 ];
218
219 $result->setData([
220 "replyMessage" => $replyMessage,
221 "receivedMessage" => $receivedMessage,
222 "data" => $data,
223 ]);
224
225 return $result;
226 }
227
232 private function checkConfig(array $config): ServiceResult
233 {
234 $result = new ServiceResult();
235
236 if (empty($config["merchantDisplayName"]))
237 {
238 $result->addError(new Main\Error("merchantDisplayName is empty", "merchantDisplayName"));
239 }
240
241 if (empty($config["supportedNetworks"]))
242 {
243 $result->addError(new Main\Error("supportedNetworks is empty", "supportedNetworks"));
244 }
245
246 if (empty($config["merchantName"]))
247 {
248 $result->addError(new Main\Error("merchantName is empty", "merchantName"));
249 }
250
251 if (empty($config["countryCode"]))
252 {
253 $result->addError(new Main\Error("countryCode is empty", "countryCode"));
254 }
255
256 if (empty($config["endpoints"]))
257 {
258 $result->addError(new Main\Error("endpoints is empty", "endpoints"));
259 }
260
261 return $result;
262 }
263
274 private function sendRequest($url, array $params = array()): ServiceResult
275 {
276 $result = new ServiceResult();
277
278 $httpClient = new Main\Web\HttpClient();
279 foreach ($this->getHeaders() as $name => $value)
280 {
281 $httpClient->setHeader($name, $value);
282 }
283
284 $httpClient->setContextOptions($this->getContextOptions($this->applePayCert));
285
286 $postData = null;
287 if ($params)
288 {
289 $postData = static::encode($params);
290 }
291
292 Logger::addDebugInfo("ApplePay: request data: ".$postData);
293
294 $response = $httpClient->post($url, $postData);
295 if ($response === false)
296 {
297 $errors = $httpClient->getError();
298 foreach ($errors as $code => $message)
299 {
300 $result->addError(new Main\Error($message, $code));
301 }
302
303 return $result;
304 }
305
306 Logger::addDebugInfo("ApplePay: response data: ".$response);
307
308 if ($response = static::decode($response))
309 {
310 $httpStatus = $httpClient->getStatus();
311 if ($httpStatus !== self::HTTP_RESPONSE_CODE_OK)
312 {
313 if (isset($response["statusMessage"]))
314 {
315 $result->addError(
316 new Main\Error(
318 "SALE_APPLE_PAY_HTTP_STATUS_MESSAGE",
319 [
320 "#HTTP_STATUS#" => $httpStatus,
321 "#STATUS_MESSAGE#" => $response["statusMessage"],
322 ]
323 )
324 )
325 );
326 }
327 else
328 {
329 $result->addError(
330 new Main\Error(
332 "SALE_APPLE_PAY_HTTP_STATUS_CODE",
333 [
334 "#HTTP_STATUS#" => $httpStatus,
335 ]
336 )
337 )
338 );
339 }
340 }
341
342 $result->setData($response);
343 }
344
345 return $result;
346 }
347
351 private function getHeaders(): array
352 {
353 return [
354 "Content-Type" => "application/json",
355 ];
356 }
357
362 private function getContextOptions($applePayCert): array
363 {
364 if ($applePayCert)
365 {
366 $applePayCertPath = $this->createTmpFile($applePayCert);
367 if ($applePayCertPath)
368 {
369 return [
370 "ssl" => [
371 "local_cert" => $applePayCertPath,
372 "local_pk" => $applePayCertPath
373 ]
374 ];
375 }
376 }
377
378 return [];
379 }
380
385 private function createTmpFile($data): string
386 {
387 $filePath = \CTempFile::GetFileName(self::FILE_PREFIX.randString());
388 CheckDirPath($filePath);
389 if ($filePath && ($data !== null))
390 {
391 file_put_contents($filePath, $data);
392 }
393
394 return $filePath ?? "";
395 }
396
402 private static function encode(array $data)
403 {
404 return Main\Web\Json::encode($data, JSON_UNESCAPED_UNICODE);
405 }
406
411 private static function decode($data)
412 {
413 try
414 {
415 return Main\Web\Json::decode($data);
416 }
417 catch (Main\ArgumentException $exception)
418 {
419 return false;
420 }
421 }
422
426 private static function getUuid(): string
427 {
428 return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
429 mt_rand(0, 0xffff), mt_rand(0, 0xffff),
430 mt_rand(0, 0xffff),
431 mt_rand(0, 0x0fff) | 0x4000,
432 mt_rand(0, 0x3fff) | 0x8000,
433 mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
434 );
435 }
436
444 public static function isApplePaySystem(array $paySystem): bool
445 {
449 [$className] = Manager::includeHandler('adyen');
450
451 return
452 isset($paySystem['ACTION_FILE'], $paySystem['PS_MODE'])
453 && $paySystem['ACTION_FILE'] === Manager::getFolderFromClassName($className)
454 && $paySystem['PS_MODE'] === $className::PAYMENT_METHOD_APPLE_PAY
455 ;
456 }
457}
static getMessage($code, $replace=null, $language=null)
Definition loc.php:29
__construct(string $merchantIdentifier, string $displayName, string $domainName, string $applePayCert)
Definition applepay.php:40
getIMessagePayment(Payment $payment, array $config)
Definition applepay.php:116
setInitiativeContext(string $initiativeContext)
Definition applepay.php:51
static addDebugInfo($debugInfo)
Definition logger.php:56
static getFolderFromClassName($className)
Definition manager.php:222
static includeHandler($actionFile)
Definition manager.php:1041
static roundPrecision($value)