16 private const MERCHANT_SESSION_GATEWAY =
"https://apple-pay-gateway.apple.com/paymentservices/paymentSession";
17 private const FILE_PREFIX =
"apple_pay_cert_";
19 private const HTTP_RESPONSE_CODE_OK = 200;
22 private $merchantIdentifier;
28 private $initiativeContext;
30 private $applePayCert;
40 public function __construct(
string $merchantIdentifier,
string $displayName,
string $domainName,
string $applePayCert)
42 $this->merchantIdentifier = $merchantIdentifier;
43 $this->displayName = $displayName;
44 $this->domainName = $domainName;
45 $this->applePayCert = $applePayCert;
53 $this->initiativeContext = $initiativeContext;
64 $requestParameters = [
65 "merchantIdentifier" => $this->merchantIdentifier,
66 "displayName" => $this->displayName,
67 "initiativeContext" => $this->domainName,
68 "initiative" =>
"web",
73 $result = $this->sendRequest($url, $requestParameters);
77 $result->addError(
new Main\
Error(
"Failed to get web session"));
90 $requestParameters = [
91 "merchantIdentifier" => hash(
"sha256", $this->merchantIdentifier),
92 "displayName" => $this->displayName,
93 "domainName" => $this->domainName,
94 "initiative" =>
"messaging",
95 "initiativeContext" => $this->initiativeContext,
100 $result = $this->sendRequest(self::MERCHANT_SESSION_GATEWAY, $requestParameters);
104 $result->addError(
new Main\
Error(
"Failed to get messenger session"));
120 $checkConfigResult = $this->checkConfig($config);
121 if (!$checkConfigResult->isSuccess())
123 $result->addErrors($checkConfigResult->getErrors());
127 $messengerDataResult = $this->prepareIMessageData($payment, $config);
128 if (!$messengerDataResult->isSuccess())
130 $result->addErrors($messengerDataResult->getErrors());
134 $result->setData($messengerDataResult->getData());
150 if (!$merchantSessionResult->isSuccess())
152 $result->addErrors($merchantSessionResult->getErrors());
156 $orderId = $payment->
getOrder()->getId();
161 "title" => $config[
"merchantDisplayName"],
163 "SALE_APPLE_PAY_ORDER_SUBTITLE",
165 "#ORDER_ID#" => $orderId,
166 "#SUM#" => \SaleFormatCurrency($paymentSum, $payment->getField(
'CURRENCY')),
173 "SALE_APPLE_PAY_ORDER_SUBTITLE",
175 "#ORDER_ID#" => $orderId,
176 "#SUM#" => \SaleFormatCurrency($paymentSum, $payment->getField(
'CURRENCY')),
182 "requestIdentifier" => self::getUuid(),
183 "mspVersion" =>
"1.0",
185 "paymentRequest" => [
189 "SALE_APPLE_PAY_LINE_ITEM_ORDER",
191 "#ORDER_ID#" => $orderId,
194 "amount" => (string)$paymentSum,
200 "amount" => (string)$paymentSum,
204 "merchantIdentifier" => $this->merchantIdentifier,
205 "supportedNetworks" => $config[
"supportedNetworks"],
206 "merchantCapabilities" => $config[
"merchantCapabilities"] ?? [
"supports3DS"],
208 "merchantName" => $config[
"merchantName"],
209 "countryCode" => $config[
"countryCode"],
210 "currencyCode" => $payment->getField(
"CURRENCY"),
211 "requiredBillingContactFields" => $config[
"requiredBillingContactFields"] ?? [],
212 "requiredShippingContactFields" => $config[
"requiredShippingContactFields"] ?? [],
214 "merchantSession" => $merchantSessionResult->getData(),
215 "endpoints" => $config[
"endpoints"]
220 "replyMessage" => $replyMessage,
221 "receivedMessage" => $receivedMessage,
232 private function checkConfig(array $config): ServiceResult
234 $result =
new ServiceResult();
236 if (empty($config[
"merchantDisplayName"]))
238 $result->addError(
new Main\Error(
"merchantDisplayName is empty",
"merchantDisplayName"));
241 if (empty($config[
"supportedNetworks"]))
243 $result->addError(
new Main\Error(
"supportedNetworks is empty",
"supportedNetworks"));
246 if (empty($config[
"merchantName"]))
248 $result->addError(
new Main\
Error(
"merchantName is empty",
"merchantName"));
251 if (empty($config[
"countryCode"]))
253 $result->addError(
new Main\
Error(
"countryCode is empty",
"countryCode"));
256 if (empty($config[
"endpoints"]))
258 $result->addError(
new Main\
Error(
"endpoints is empty",
"endpoints"));
274 private function sendRequest($url, array $params = array()): ServiceResult
276 $result =
new ServiceResult();
278 $httpClient =
new Main\Web\HttpClient();
279 foreach ($this->getHeaders() as $name => $value)
281 $httpClient->setHeader($name, $value);
284 $httpClient->setContextOptions($this->getContextOptions($this->applePayCert));
289 $postData = static::encode($params);
294 $response = $httpClient->post($url, $postData);
295 if ($response ===
false)
297 $errors = $httpClient->getError();
298 foreach ($errors as $code => $message)
300 $result->addError(
new Main\
Error($message, $code));
308 if ($response = static::decode($response))
310 $httpStatus = $httpClient->getStatus();
311 if ($httpStatus !== self::HTTP_RESPONSE_CODE_OK)
313 if (isset($response[
"statusMessage"]))
318 "SALE_APPLE_PAY_HTTP_STATUS_MESSAGE",
320 "#HTTP_STATUS#" => $httpStatus,
321 "#STATUS_MESSAGE#" => $response[
"statusMessage"],
332 "SALE_APPLE_PAY_HTTP_STATUS_CODE",
334 "#HTTP_STATUS#" => $httpStatus,
342 $result->setData($response);
351 private function getHeaders(): array
354 "Content-Type" =>
"application/json",
362 private function getContextOptions($applePayCert): array
366 $applePayCertPath = $this->createTmpFile($applePayCert);
367 if ($applePayCertPath)
371 "local_cert" => $applePayCertPath,
372 "local_pk" => $applePayCertPath
385 private function createTmpFile($data): string
387 $filePath = \CTempFile::GetFileName(self::FILE_PREFIX.randString());
388 CheckDirPath($filePath);
389 if ($filePath && ($data !==
null))
391 file_put_contents($filePath, $data);
394 return $filePath ??
"";
402 private static function encode(array $data)
404 return Main\Web\Json::encode($data, JSON_UNESCAPED_UNICODE);
411 private static function decode($data)
415 return Main\Web\Json::decode($data);
417 catch (Main\ArgumentException $exception)
426 private static function getUuid(): string
428 return sprintf(
'%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
429 mt_rand(0, 0xffff), 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)
444 public static function isApplePaySystem(array $paySystem): bool
452 isset($paySystem[
'ACTION_FILE'], $paySystem[
'PS_MODE'])
454 && $paySystem[
'PS_MODE'] === $className::PAYMENT_METHOD_APPLE_PAY
static getMessage($code, $replace=null, $language=null)