From 38a7c28c943a759b0baac4975c5020d5011037fe Mon Sep 17 00:00:00 2001 From: Leonix Date: Tue, 24 Sep 2024 11:50:38 +0300 Subject: [PATCH] =?UTF-8?q?wa-plugins/payment/tinkoff=20v.1.1.0=20=20=20*?= =?UTF-8?q?=20=D0=9F=D0=BE=D0=B4=D0=B4=D0=B5=D1=80=D0=B6=D0=BA=D0=B0=20?= =?UTF-8?q?=D0=BE=D0=BF=D0=BB=D0=B0=D1=82=D1=8B=20=D0=BF=D0=BE=20QR-=D0=BA?= =?UTF-8?q?=D0=BE=D0=B4=D1=83=20=D0=BD=D0=B0=20=D1=81=D0=B0=D0=B9=D1=82?= =?UTF-8?q?=D0=B5=20=D0=B8=20=D0=B2=20=D0=BC=D0=BE=D0=B1=D0=B8=D0=BB=D1=8C?= =?UTF-8?q?=D0=BD=D0=BE=D0=B9=20=D0=BA=D0=B0=D1=81=D1=81=D0=B5.=20=20=20*?= =?UTF-8?q?=20=D0=9F=D0=BE=D0=B4=D0=B4=D0=B5=D1=80=D0=B6=D0=BA=D0=B0=20?= =?UTF-8?q?=D1=86=D0=B5=D0=BD=D1=82=D1=80=D0=B0=D0=BB=D0=B8=D0=B7=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=D0=BD=D0=BD=D0=BE=D0=B3=D0=BE=20=D0=BA=D0=BE=D0=BD?= =?UTF-8?q?=D1=82=D1=80=D0=BE=D0=BB=D1=8F=20=D1=84=D0=B8=D1=81=D0=BA=D0=B0?= =?UTF-8?q?=D0=BB=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D0=B8=20=D0=BF=D0=BB=D0=B0?= =?UTF-8?q?=D1=82=D0=B5=D0=B6=D0=B5=D0=B9.=20=20=20*=20=D0=9F=D0=B5=D1=80?= =?UTF-8?q?=D0=B5=D0=B4=D0=B0=D1=87=D0=B0=20=D0=BD=D0=BE=D0=BC=D0=B5=D1=80?= =?UTF-8?q?=D0=B0=20=D0=B7=D0=B0=D0=BA=D0=B0=D0=B7=D0=B0=20=D0=B2=20=D1=87?= =?UTF-8?q?=D0=B5=D0=BA=20=D0=BE=D0=B1=20=D0=BE=D0=BF=D0=BB=D0=B0=D1=82?= =?UTF-8?q?=D0=B5.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- wa-plugins/payment/tinkoff/img/qr-test.svg | 1 + wa-plugins/payment/tinkoff/img/tinkoff.png | Bin 731 -> 2504 bytes wa-plugins/payment/tinkoff/img/tinkoff.svg | 4 + wa-plugins/payment/tinkoff/img/tinkoff16.png | Bin 276 -> 617 bytes .../payment/tinkoff/lib/config/guide.php | 6 +- .../payment/tinkoff/lib/config/plugin.php | 10 +- .../tinkoff/lib/config/requirements.php | 2 +- .../payment/tinkoff/lib/config/settings.php | 8 +- .../tinkoff/lib/config/shop_support.json | 2 +- .../tinkoff/lib/tinkoffPayment.class.php | 205 ++++++++++++++++-- .../en_US/LC_MESSAGES/payment_tinkoff.mo | Bin 0 -> 678 bytes .../en_US/LC_MESSAGES/payment_tinkoff.po | 7 +- .../ru_RU/LC_MESSAGES/payment_tinkoff.mo | Bin 879 -> 847 bytes .../ru_RU/LC_MESSAGES/payment_tinkoff.po | 9 +- 14 files changed, 222 insertions(+), 32 deletions(-) create mode 100644 wa-plugins/payment/tinkoff/img/qr-test.svg create mode 100644 wa-plugins/payment/tinkoff/img/tinkoff.svg create mode 100644 wa-plugins/payment/tinkoff/locale/en_US/LC_MESSAGES/payment_tinkoff.mo diff --git a/wa-plugins/payment/tinkoff/img/qr-test.svg b/wa-plugins/payment/tinkoff/img/qr-test.svg new file mode 100644 index 000000000..cf747dc19 --- /dev/null +++ b/wa-plugins/payment/tinkoff/img/qr-test.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wa-plugins/payment/tinkoff/img/tinkoff.png b/wa-plugins/payment/tinkoff/img/tinkoff.png index c9224b1c080d95c61f98e267331f6f9c49fdc68f..b4ef7be7a74f5443c783f6df936a07843170a4f0 100644 GIT binary patch literal 2504 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 N002ovPDHLkV1ke?TB`s6 diff --git a/wa-plugins/payment/tinkoff/img/tinkoff.svg b/wa-plugins/payment/tinkoff/img/tinkoff.svg new file mode 100644 index 000000000..a888c9ff0 --- /dev/null +++ b/wa-plugins/payment/tinkoff/img/tinkoff.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/wa-plugins/payment/tinkoff/img/tinkoff16.png b/wa-plugins/payment/tinkoff/img/tinkoff16.png index 16b6881c2119eef603f0df228ed68a15ca159e7f..f59107ce7264b4fe4aedafde9e4cbd61aa5c4343 100644 GIT binary patch literal 617 zcmV-v0+#)WP)vl>|8=+_y z8CX<9Fpa@PT3{{=H_c3C#@u2-OC|To)dTr0yp5a zwl&qz-fD?QEbAK}{YkhpSXIF3Je_CfHsxyu-n=tB9CoYC(||EBaAThBjrx16y1F=d zbhjnGXMuD4h^3=lJo^t0EigiXxGTb2++qUX0|sO+K>ay`%5-4zqSFS=C;i6FmRPgd zIforrjHID<-3uV&Cu;IbvDoC4Z}BYkX2i(W=QF^4Kas<)iw!(W_}tGb4`gHV`>%Vz z^npEt!@ZEn!v2U7kK_x+1<1}oeVvp14??zYF>b-oc*|9kORfbh3#z@+l6Tr|&!r|k6YIy=A*|j84)_#KpxP--sgZId zr^*)E5<81%AF#=TJ_UM#aO$oIo=>8$rPa~B4XiOeKo?N^*K`iJ$$ajbG^fA0=B%i< z`o1Mh75yxp7G((Rd1)H`P)WXup<}V5Ivzc?oE$#^-n5{cOBy}=00000NkvXXu0mjf Du^%Cp literal 276 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b z3=G`DAk4@xYmNj^kiEpy*OmPNixj64Q`pTtvw%ViJzX3_EKV;CcI0a|;OVYBC2`5( z&B01Z_AA?GoW9jMA;n|!k;ZFVP?(tZ2Ay@%&*ul>F2#I7587jG5_2`VKWbDY0?)BIjTH;${fe}75gTehwyNcX|c z$y=vHe&3zAv)O^>xh?triU3E3zspqDQOK&L^;=K>buG7r#w)^|vBs Si90~YGI+ZBxvX '%RELAY_URL%', 'title' => 'URL для нотификации по HTTP', 'description' => 'Значение настройки URL для оповещения активного протокола
-Указанный в этом поле адрес скопируйте и сохраните в анкете подключения к интернет-эквайрингу банка Тинькофф', +Указанный в этом поле адрес скопируйте и сохраните в анкете подключения к интернет-эквайрингу от Т-Кассы (Тинькофф)', ), array( 'value' => '%RELAY_URL%', 'title' => 'Страница успешного платежа', 'description' => 'URL возврата покупателя обратно на сайт после успешной оплаты
-Указанный в этом поле адрес скопируйте и сохраните в анкете подключения к интернет-эквайрингу банка Тинькофф', +Указанный в этом поле адрес скопируйте и сохраните в анкете подключения к интернет-эквайрингу от Т-Кассы (Тинькофф)', ), array( 'value' => '%RELAY_URL%', 'title' => 'Страница ошибки оплаты', 'description' => 'URL возврата покупателя обратно на сайт в случае ошибки оплаты
-Указанный в этом поле адрес скопируйте и сохраните в анкете подключения к интернет-эквайрингу банка Тинькофф', +Указанный в этом поле адрес скопируйте и сохраните в анкете подключения к интернет-эквайрингу от Т-Кассы (Тинькофф)', ), ); diff --git a/wa-plugins/payment/tinkoff/lib/config/plugin.php b/wa-plugins/payment/tinkoff/lib/config/plugin.php index f7efc0c38..be31c49c2 100644 --- a/wa-plugins/payment/tinkoff/lib/config/plugin.php +++ b/wa-plugins/payment/tinkoff/lib/config/plugin.php @@ -1,11 +1,11 @@ 'Банк Тинькофф', - 'description' => 'Оплата картами VISA, MasterCard и Maestro через интернет-эквайринг банка Тинькофф', - 'icon' => 'img/tinkoff16.png', - 'logo' => 'img/tinkoff.png', + 'name' => 'Т-Касса', + 'description' => 'Интернет-эквайринг от «Т-Банка»: банковские карты, СБП, SberPay, T-Pay, MirPay', + 'icon' => 'img/tinkoff.svg', + 'logo' => 'img/tinkoff.png?v2', 'vendor' => 'webasyst', - 'version' => '1.0.22', + 'version' => '1.1.0', 'type' => waPayment::TYPE_ONLINE, 'partial_refund' => true, 'partial_capture' => true, diff --git a/wa-plugins/payment/tinkoff/lib/config/requirements.php b/wa-plugins/payment/tinkoff/lib/config/requirements.php index d054b2f23..e16e29332 100644 --- a/wa-plugins/payment/tinkoff/lib/config/requirements.php +++ b/wa-plugins/payment/tinkoff/lib/config/requirements.php @@ -1,7 +1,7 @@ array( - 'version' => '>=1.13', + 'version' => '>=3.2.0', 'strict' => true, ), 'php.hash' => array( diff --git a/wa-plugins/payment/tinkoff/lib/config/settings.php b/wa-plugins/payment/tinkoff/lib/config/settings.php index 6c04b6255..54c0c95d5 100644 --- a/wa-plugins/payment/tinkoff/lib/config/settings.php +++ b/wa-plugins/payment/tinkoff/lib/config/settings.php @@ -10,6 +10,12 @@ 'value' => '', 'title' => /*_wp*/('Пароль'), 'control_type' => waHtmlControl::PASSWORD, + 'description' => << +Подключайтесь к Т-Кассе через Webasyst по этой ссылке и получите данные для заполнения Terminal ID и пароля. + +HTML + , ), 'currency_id' => array( 'value' => '', @@ -23,7 +29,7 @@ 'two_steps' => array( 'value' => false, 'title' => 'Схема подключения', - 'description' => /*_wp*/('Вариант обработки платежей, выбранный при заключении договора с банком Тинькофф.
Двухстадийную схему подключения можно использовать только с поддерживаемым приложением, например, Shop-Script версии не ниже 8.6.'), + 'description' => /*_wp*/('Вариант обработки платежей, выбранный при заключении договора с Т-Кассой.
Двухстадийную схему подключения можно использовать только с поддерживаемым приложением, например, Shop-Script версии не ниже 8.6.'), 'control_type' => waHtmlControl::RADIOGROUP, 'options' => array( '0' => 'Одностадийная', diff --git a/wa-plugins/payment/tinkoff/lib/config/shop_support.json b/wa-plugins/payment/tinkoff/lib/config/shop_support.json index c2004d817..e38c21e47 100644 --- a/wa-plugins/payment/tinkoff/lib/config/shop_support.json +++ b/wa-plugins/payment/tinkoff/lib/config/shop_support.json @@ -1,4 +1,4 @@ { "support_premium": "yes", - "support_premium_description": "

Дробное количество товаров передаётся в «Тинькофф Банк» точно так, как указано в заказе.

Единицы измерения количества товаров не передаются — такая возможность не предусмотрена платёжной системой.

" + "support_premium_description": "

Дробное количество товаров передаётся в «Т-Кассу» точно так, как указано в заказе.

Единицы измерения количества товаров не передаются — такая возможность не предусмотрена платёжной системой.

" } diff --git a/wa-plugins/payment/tinkoff/lib/tinkoffPayment.class.php b/wa-plugins/payment/tinkoff/lib/tinkoffPayment.class.php index ec83a49d4..1d2c8e922 100644 --- a/wa-plugins/payment/tinkoff/lib/tinkoffPayment.class.php +++ b/wa-plugins/payment/tinkoff/lib/tinkoffPayment.class.php @@ -22,7 +22,7 @@ * @property-read string $payment_method_type * */ -class tinkoffPayment extends waPayment implements waIPayment, waIPaymentRefund, waIPaymentRecurrent, waIPaymentCancel, waIPaymentCapture +class tinkoffPayment extends waPayment implements waIPayment, waIPaymentRefund, waIPaymentRecurrent, waIPaymentCancel, waIPaymentCapture, waIPaymentImage { private $order_id; private $receipt; @@ -163,6 +163,18 @@ private function genToken($args) * @throws waPaymentException */ private function checkToken($args) + { + $token = ifset($args, 'Token', false); + unset($args['Token']); + + $expected_token = $this->calculateToken($args); + + if (empty($token) || ($token !== $expected_token)) { + throw new waPaymentException('Invalid token'); + } + } + + private function calculateToken($args) { $args['Password'] = trim($this->getSettings('terminal_password')); @@ -170,10 +182,6 @@ private function checkToken($args) throw new waPaymentException('Password misconfiguration'); } - $token = ifset($args, 'Token', false); - unset($args['Token']); - - ksort($args); foreach ($args as $k => &$arg) { if (is_bool($arg)) { @@ -184,17 +192,12 @@ private function checkToken($args) } unset($arg); - $expected_token = hash('sha256', implode('', $args)); - - if (empty($token) || ($token !== $expected_token)) { - throw new waPaymentException('Invalid token'); - } + return hash('sha256', implode('', $args)); } protected function callbackInit($request) { $request = $this->sanitizeRequest($request); - $pattern = '/^([a-z]+)_(\d+)_(.+)$/'; if (!empty($request['OrderId']) && preg_match($pattern, $request['OrderId'], $match)) { $this->app_id = $match[1]; @@ -314,13 +317,20 @@ protected function callbackHandler($data) // Verify token $this->checkToken($data); + if (isset($data['SBPQR'])) { + $this->sbpQrImage($data); + exit; + } + $transaction_data = $this->formalizeData($data); $app_payment_method = null; + $declare_fiscalization = false; switch ($transaction_data['type']) { case self::OPERATION_AUTH_ONLY: if ($transaction_data['result']) { + $declare_fiscalization = true; $app_payment_method = self::CALLBACK_AUTH; } else { $app_payment_method = self::CALLBACK_DECLINE; @@ -329,6 +339,7 @@ protected function callbackHandler($data) case self::OPERATION_AUTH_CAPTURE: if ($transaction_data['result']) { + $declare_fiscalization = true; $app_payment_method = self::CALLBACK_PAYMENT; } else { $app_payment_method = self::CALLBACK_DECLINE; @@ -340,6 +351,7 @@ protected function callbackHandler($data) break; case self::OPERATION_CAPTURE: + $declare_fiscalization = true; $app_payment_method = self::CALLBACK_CAPTURE; break; @@ -370,6 +382,10 @@ protected function callbackHandler($data) //Save transaction and run app callback only if it not repeated callback; $transaction_data = $this->saveTransaction($transaction_data, $data); $this->execAppCallback($app_payment_method, $transaction_data); + + if ($declare_fiscalization && $this->getSettings('check_data_tax')) { + $this->getAdapter()->declareFiscalization($transaction_data['order_id'], $this, ['id' => $transaction_data['native_id']]); + } } else { $log = array( 'message' => 'silent skip callback as repeated', @@ -417,7 +433,10 @@ public function refund($transaction_raw_data) } $res = $this->apiQuery('Cancel', $args); - + if (in_array(ifset($res['Status']), ['ASYNC_REFUNDING', 'REFUNDING'])) { + sleep(1); + $res = $this->apiQuery('GetState', ['PaymentId' => $args['PaymentId']]); + } $response = array( 'result' => 0, @@ -472,7 +491,7 @@ public function refund($transaction_raw_data) return $response; } catch (Exception $ex) { $message = sprintf("Error occurred during %s: %s", __METHOD__, $ex->getMessage()); - self::log($this->id, $message); + self::log($this->id, [$message, $ex->getTraceAsString()]); return array( 'result' => -1, 'data' => null, @@ -544,6 +563,156 @@ public function recurrent($order_data) } + public function sbp($order_data) + { + $order_data = waOrder::factory($order_data); + + // https://www.tbank.ru/kassa/dev/payments/#tag/Oplata-cherez-SBP + $args = array( + 'Amount' => round($order_data['amount'] * 100), + 'Currency' => ifset(self::$currencies[$this->currency_id]), + 'OrderId' => $this->app_id.'_'.$this->merchant_id.'_'.$order_data['order_id'], + 'Description' => ifempty($order_data, 'description', ''), + 'PayType' => $this->two_steps ? 'T' : 'O', + 'DATA' => [], + ); + + if ($this->getSettings('check_data_tax')) { + $full_order_data = $order_data; + if (!$full_order_data->items) { + $full_order_data = $this->getAdapter()->getOrderData($order_data['order_id']); + } + $args['Receipt'] = $this->getReceiptData($full_order_data, $this); + if (!$args['Receipt']) { + return 'Данный вариант платежа недоступен. Воспользуйтесь другим способом оплаты.'; + } + } + + if (!empty($order_data['customer_contact_id'])) { + $args['CustomerKey'] = $order_data['customer_contact_id']; + try { + $c = new waContact($order_data['customer_contact_id']); + $email = $c->get('email', 'default'); + $phone = $c->get('phone', 'default'); + } catch (waException $e) { + // contact is deleted + } + if (empty($email)) { + //$email = $this->getDefaultEmail(); + } + if (!empty($email)) { + $args['DATA']['Email'] = $email; + } + if (!empty($phone)) { + $args['DATA']['Phone'] = $phone; + } + } + if (empty($args['DATA'])) { + unset($args['DATA']); + } + + try { + $payment_id = null; + $cache_key = 'tinkoff/sbp/' . md5('SBP'.$args['OrderId'].$args['Amount']); + $cache = new waSerializeCache($cache_key, -1, $this->app_id); + if ($cache->isCached()) { + $payment_id = $cache->get(); + $check_payment_data = $this->apiQuery('GetState', ['PaymentId' => $payment_id]); + if (ifset($check_payment_data, 'ErrorCode', 0) != 0 || !in_array(ifset($check_payment_data, 'State', ''), ['NEW', 'FORM_SHOWED'])) { + unset($payment_id); + } + } + + if (empty($payment_id)) { + $payment_data = $this->apiQuery('Init', $args); + $payment_id = ifset($payment_data, 'PaymentId', ''); + } + + if (empty($payment_id)) { + $cache->delete(); + return null; + } else { + $cache->set($payment_id); + } + + if ($this->isTestMode()) { + try { + // Запрашивает успешную оплату по СБП для текущего счёта + // https://www.tbank.ru/kassa/dev/payments/#tag/Oplata-cherez-SBP/operation/SbpPayTest + $test_sbp_result = $this->apiQuery('SbpPayTest', [ + 'PaymentId' => $payment_id, + ]); + } catch (Exception $ex) { + self::log($this->id, ['Unable create test QR code, using hardcoded stub', $ex->getMessage(), $ex->getTraceAsString()]); + return [ + 'svg' => file_get_contents($this->path.'/img/qr-test.svg'), + 'url' => wa()->getRootUrl().'wa-plugins/payment/tinkoff/img/qr-test.svg', + ]; + } + } + + $qr_data = $this->apiQuery('GetQr', [ + 'PaymentId' => $payment_id, + 'DataType' => 'IMAGE' + ]); + if (ifset($qr_data, 'Success', false)) { + $qr_link = $this->apiQuery('GetQr', [ + 'PaymentId' => $payment_id, + 'DataType' => 'PAYLOAD' + ]); + + if (ifset($qr_link, 'Success', false)) { + return [ + 'svg' => $qr_data['Data'], + 'url' => $qr_link['Data'], + ]; + } + } + $cache->delete(); + return null; + } catch (Exception $ex) { + self::log($this->id, [$ex->getMessage(), $ex->getTraceAsString()]); + $cache->delete(); + return false; + } + } + + private function sbpQrImage($params) + { + $order_data = [ + 'order_id' => $this->order_id, + 'amount' => $params['amount'], + 'customer_contact_id' => $params['customer_contact_id'], + ]; + + $sbp = $this->sbp($order_data); + if (empty($sbp['svg'])) { + throw new waException('Не удалось получить QR-код'); + } + + $response = wa()->getResponse(); + $response->addHeader('Content-Type', 'image/svg+xml', true); + echo $sbp['svg']; + exit; + } + + public function image($order_data) + { + $args = array( + 'OrderId' => $this->app_id.'_'.$this->merchant_id.'_'.$order_data['order_id'], + 'amount' => $order_data['amount'], + 'description' => ifempty($order_data, 'description', ''), + 'customer_contact_id' => $order_data['customer_contact_id'], + 'SBPQR' => 1, + ); + $args['Token'] = $this->calculateToken($args); + return [ + // At least one of keys `image_url` and `image_data_url` is required. Both are ok, too. + 'image_url' => wa()->getRootUrl(true) . 'payments.php/tinkoff/?' . http_build_query($args), + //'image_data_url' => 'data:image/png;base64,........', + ]; + } + public function cancel($transaction_raw_data) { try { @@ -553,6 +722,10 @@ public function cancel($transaction_raw_data) ); $data = $this->apiQuery('Cancel', $args); + if (in_array(ifset($data['Status']), ['ASYNC_REFUNDING', 'REFUNDING'])) { + sleep(1); + $data = $this->apiQuery('GetState', ['PaymentId' => $args['PaymentId']]); + } $transaction_data = $this->formalizeData($data); $this->saveTransaction($transaction_data, $data); @@ -565,7 +738,7 @@ public function cancel($transaction_raw_data) } catch (Exception $ex) { $message = sprintf("Error occurred during %s: %s", __METHOD__, $ex->getMessage()); - self::log($this->id, $message); + self::log($this->id, [$message, $ex->getTraceAsString()]); return array( 'result' => -1, 'description' => $ex->getMessage(), @@ -940,6 +1113,10 @@ private function getReceiptData(waOrder $order) 'Items' => array(), 'Taxation' => $this->getSettings('taxation'), 'Email' => $email, + 'AddUserProp' => [ + 'Name' => 'Номер заказа', + 'Value' => $order->id_str + ] ); if ($phone = $order->getContactField('phone')) { $this->receipt['Phone'] = sprintf('+%s', preg_replace('/^8/', '7', $phone)); diff --git a/wa-plugins/payment/tinkoff/locale/en_US/LC_MESSAGES/payment_tinkoff.mo b/wa-plugins/payment/tinkoff/locale/en_US/LC_MESSAGES/payment_tinkoff.mo new file mode 100644 index 0000000000000000000000000000000000000000..4043db5c7408206e7219943ac76511949c2d937c GIT binary patch literal 678 zcma))%}(1u5P-MPUVPxdxragOp$M%*k{*zwT!4TgCBgz1acif}IN9RtTD$8&jywQI zo`MT^PUJy&mX2}Npa`Lk^m*)^-<|RE=Epn1vd(;FzA>Me0aM9OW`{wh&D=5%AB1>f zy}{TuA-=G_Va>;a)k`i`wZu4w%vhM4(t@!g;-`kieWLWG$uihSeYto9r#y*M8YxSu zS9%QIyzTUotibt{v=75j#Mb=g5ZNEebFxku9l;gKA}_~EyT)J72Is8G1@VbIrJ1Vy zjDYly?`OfVKkO|#Y=*nRfzh5XA(MH* zZFsu&jUq>-JCIJ$I`ZApXL4`pSGAatl|7xB5zi=sy*PpkM{&+u0hyq-<&YQZR^sldd8tK-CHX~G3IX}4DVZe-#(KtjMw7dlQW$k7|6{TPlHSZJ01lEW AR{#J2 delta 217 zcmX@l_MUBmiP&F828M$S3=G~tyq}4IAsI+>GjH_bXPlhLSW~Z|p^>L*XrO6pYpAKF z2H_ZJD%u(vYHHeR7-(7n6+o5P*&4x>XxiACXo7iQ?FO1QKr?D;VETbd4KzUp7;0J> zX=++?Md$|Pr>10<==vn)rI#kAr&=i#mBt5!PBvq*n!K1vX!0B;fBp+QF6_P7b79wo UeHU9UwkS+~!(@jcrp>GZ0P{0I_y7O^ diff --git a/wa-plugins/payment/tinkoff/locale/ru_RU/LC_MESSAGES/payment_tinkoff.po b/wa-plugins/payment/tinkoff/locale/ru_RU/LC_MESSAGES/payment_tinkoff.po index f1ef14c42..854aea98a 100644 --- a/wa-plugins/payment/tinkoff/locale/ru_RU/LC_MESSAGES/payment_tinkoff.po +++ b/wa-plugins/payment/tinkoff/locale/ru_RU/LC_MESSAGES/payment_tinkoff.po @@ -5,18 +5,19 @@ msgstr "" "PO-Revision-Date: \n" "Last-Translator: wa-plugins/payment/tinkoff\n" "Language-Team: wa-plugins/payment/tinkoff\n" +"Language: ru_RU\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n" -"X-Poedit-Language: ru_RU\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : 2);\n" "X-Poedit-SourceCharset: utf-8\n" "X-Poedit-Basepath: utf-8\n" +"X-Generator: Poedit 3.3.2\n" "X-Poedit-SearchPath-0: .\n" "X-Poedit-SearchPath-1: .\n" msgid "Redirecting to «Tinkoff Bank» site for payment..." -msgstr "Перенаправление на сайт «Тинькофф Банка» для оплаты..." +msgstr "Перенаправление на сайт «Т-Банка» для оплаты..." msgid "Pay for your order on «Tinkoff Bank» site" -msgstr "Оплатить заказ на сайте «Тинькофф Банка»" +msgstr "Оплатить заказ на сайте «Т-Банка»"