mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-10 05:02:36 +01:00
wip
This commit is contained in:
parent
049f30104e
commit
d37064e393
@ -126,7 +126,6 @@ class PaymentController extends Controller
|
||||
|
||||
public function response(Request $request)
|
||||
{
|
||||
|
||||
$gateway = CompanyGateway::find($request->input('company_gateway_id'));
|
||||
|
||||
return $gateway
|
||||
|
@ -35,6 +35,7 @@ class SystemLog extends Model
|
||||
const TYPE_STRIPE = 301;
|
||||
const TYPE_LEDGER = 302;
|
||||
const TYPE_FAILURE = 303;
|
||||
const TYPE_CHECKOUT = 304;
|
||||
|
||||
const TYPE_QUOTA_EXCEEDED = 400;
|
||||
const TYPE_UPSTREAM_FAILURE = 401;
|
||||
|
@ -23,4 +23,25 @@ trait Utilities
|
||||
|
||||
return $this->company_gateway->getConfig()->publicApiKey;
|
||||
}
|
||||
|
||||
public function convertToCheckoutAmount($amount, $currency)
|
||||
{
|
||||
$cases = [
|
||||
'option_1' => ['BIF', 'DJF', 'GNF', 'ISK', 'KMF', 'XAF', 'CLF', 'XPF', 'JPY', 'PYG', 'RWF', 'KRW', 'VUV', 'VND', 'XOF'],
|
||||
'option_2' => ['BHD', 'IQD', 'JOD', 'KWD', 'LYD', 'OMR', 'TND'],
|
||||
];
|
||||
|
||||
// https://docs.checkout.com/resources/calculating-the-value#Calculatingthevalue-Option1:Thefullvaluefullvalue
|
||||
if (in_array($currency, $cases['option_1'])) {
|
||||
return round($amount);
|
||||
}
|
||||
|
||||
// https://docs.checkout.com/resources/calculating-the-value#Calculatingthevalue-Option2:Thevaluedividedby1000valuediv1000
|
||||
if (in_array($currency, $cases['option_2'])) {
|
||||
return round($amount * 1000);
|
||||
}
|
||||
|
||||
// https://docs.checkout.com/resources/calculating-the-value#Calculatingthevalue-Option3:Thevaluedividedby100valuediv100
|
||||
return round($amount * 100);
|
||||
}
|
||||
}
|
||||
|
@ -12,9 +12,19 @@
|
||||
|
||||
namespace App\PaymentDrivers;
|
||||
|
||||
use App\Events\Payment\PaymentWasCreated;
|
||||
use App\Jobs\Mail\PaymentFailureMailer;
|
||||
use App\Jobs\Util\SystemLogger;
|
||||
use App\Models\GatewayType;
|
||||
use App\Models\Payment as NinjaPaymentModel;
|
||||
use App\Models\PaymentType;
|
||||
use App\Models\SystemLog;
|
||||
use App\PaymentDrivers\CheckoutCom\Utilities;
|
||||
use App\Utils\Traits\SystemLogTrait;
|
||||
use Checkout\CheckoutApi;
|
||||
use Checkout\Library\Exceptions\CheckoutHttpException;
|
||||
use Checkout\Models\Payments\Payment;
|
||||
use Checkout\Models\Payments\TokenSource;
|
||||
|
||||
class CheckoutComPaymentDriver extends BasePaymentDriver
|
||||
{
|
||||
@ -22,7 +32,7 @@ class CheckoutComPaymentDriver extends BasePaymentDriver
|
||||
|
||||
/* The company gateway instance*/
|
||||
public $company_gateway;
|
||||
|
||||
|
||||
/* The Invitation */
|
||||
protected $invitation;
|
||||
|
||||
@ -46,7 +56,9 @@ class CheckoutComPaymentDriver extends BasePaymentDriver
|
||||
|
||||
public function init()
|
||||
{
|
||||
// $this->gateway
|
||||
$secret_key = $this->company_gateway->getConfig()->secretApiKey;
|
||||
|
||||
$this->gateway = new CheckoutApi($secret_key); // @todo: 2nd (sandbox), 3rd (public)
|
||||
}
|
||||
|
||||
public function viewForType($gateway_type_id)
|
||||
@ -65,7 +77,8 @@ class CheckoutComPaymentDriver extends BasePaymentDriver
|
||||
$data['gateway'] = $this;
|
||||
$data['client'] = $this->client;
|
||||
$data['currency'] = $this->client->getCurrencyCode();
|
||||
$data['value'] = $data['amount_with_fee']; // Fix for currencies.
|
||||
$data['value'] = $this->convertToCheckoutAmount($data['amount_with_fee'], $this->client->getCurrencyCode());
|
||||
$data['raw_value'] = $data['amount_with_fee'];
|
||||
$data['customer_email'] = $this->client->present()->email;
|
||||
|
||||
return render($this->viewForType($data['payment_method_id']), $data);
|
||||
@ -73,6 +86,116 @@ class CheckoutComPaymentDriver extends BasePaymentDriver
|
||||
|
||||
public function processPaymentResponse($request)
|
||||
{
|
||||
dd($request->all());
|
||||
$this->init();
|
||||
|
||||
$state = [
|
||||
'server_response' => json_decode($request->gateway_response),
|
||||
'value' => $request->value,
|
||||
'raw_value' => $request->raw_value,
|
||||
'currency' => $request->currency,
|
||||
];
|
||||
|
||||
$state = array_merge($state, $request->all());
|
||||
|
||||
$method = new TokenSource($state['server_response']->cardToken);
|
||||
|
||||
$payment = new Payment($method, $state['currency']);
|
||||
$payment->amount = $state['value'];
|
||||
// $payment->{"3ds"} = [
|
||||
// 'enabled' => true,
|
||||
// ];
|
||||
|
||||
try {
|
||||
$response = $this->gateway->payments()->request($payment);
|
||||
$state['payment_response'] = $response;
|
||||
|
||||
if ($response->status === 'Authorized') {
|
||||
return $this->processSuccessfulPayment($state);
|
||||
}
|
||||
|
||||
if ($response->status === 'Pending') {
|
||||
return $this->processPendingPayment($state);
|
||||
}
|
||||
|
||||
if ($response->status === 'Declined') {
|
||||
return $this->processUnsuccessfulPayment($state);
|
||||
}
|
||||
} catch (CheckoutHttpException $e) {
|
||||
return $this->processInternallyFailedPayment($e, $state);
|
||||
}
|
||||
}
|
||||
|
||||
public function processSuccessfulPayment($state)
|
||||
{
|
||||
$state['charge_id'] = $state['payment_response']->id;
|
||||
|
||||
if (isset($state['store_card'])) {
|
||||
// ..
|
||||
}
|
||||
|
||||
$data = [
|
||||
'payment_method' => $state['charge_id'],
|
||||
'payment_type' => PaymentType::CREDIT_CARD_OTHER, // @todo: needs proper status
|
||||
'amount' => $state['raw_value'],
|
||||
];
|
||||
|
||||
$payment = $this->createPayment($data, NinjaPaymentModel::STATUS_COMPLETED);
|
||||
|
||||
$this->attachInvoices($payment, $state['hashed_ids']);
|
||||
|
||||
$payment->service()->updateInvoicePayment();
|
||||
|
||||
event(new PaymentWasCreated($payment, $payment->company));
|
||||
|
||||
$logger_message = [
|
||||
'server_response' => $state['payment_response'],
|
||||
'data' => $data
|
||||
];
|
||||
|
||||
SystemLogger::dispatch($logger_message, SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_SUCCESS, SystemLog::TYPE_CHECKOUT, $this->client);
|
||||
|
||||
return redirect()->route('client.payments.show', ['payment' => $this->encodePrimaryKey($payment->id)]);
|
||||
}
|
||||
|
||||
public function processPendingPayment($state)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function processUnsuccessfulPayment($state)
|
||||
{
|
||||
dd($state);
|
||||
}
|
||||
|
||||
public function processInternallyFailedPayment($e, $state)
|
||||
{
|
||||
$message = json_decode($e->getBody());
|
||||
|
||||
PaymentFailureMailer::dispatch($this->client, $message->error_type, $this->client->company, $state['value']);
|
||||
|
||||
$message = [
|
||||
'server_response' => $state['server_response'],
|
||||
'data' => $message,
|
||||
];
|
||||
|
||||
SystemLogger::dispatch($message, SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_FAILURE, SystemLog::TYPE_CHECKOUT, $this->client);
|
||||
|
||||
throw new \Exception('Failed to process the payment.', 1);
|
||||
}
|
||||
|
||||
public function createPayment($data, $status = NinjaPaymentModel::STATUS_COMPLETED): NinjaPaymentModel
|
||||
{
|
||||
$payment = parent::createPayment($data, $status);
|
||||
|
||||
$client_contact = $this->getContact();
|
||||
$client_contact_id = $client_contact ? $client_contact->id : null;
|
||||
|
||||
$payment->amount = $data['amount'];
|
||||
$payment->type_id = $data['payment_type'];
|
||||
$payment->transaction_reference = $data['payment_method'];
|
||||
$payment->client_contact_id = $client_contact_id;
|
||||
$payment->save();
|
||||
|
||||
return $payment;
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,6 @@
|
||||
"php": ">=7.3",
|
||||
"ext-json": "*",
|
||||
"asgrim/ofxparser": "^1.2",
|
||||
"beganovich/omnipay-checkout": "dev-master",
|
||||
"checkout/checkout-sdk-php": "^1.0",
|
||||
"cleverit/ubl_invoice": "^1.3",
|
||||
"composer/composer": "^1.10",
|
||||
@ -80,7 +79,8 @@
|
||||
"App\\": "app/"
|
||||
},
|
||||
"files": [
|
||||
"app/Libraries/OFX.php" ]
|
||||
"app/Libraries/OFX.php"
|
||||
]
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
@ -89,8 +89,7 @@
|
||||
},
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"dont-discover": [
|
||||
]
|
||||
"dont-discover": []
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
|
94
composer.lock
generated
94
composer.lock
generated
@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "723f03b92457a3f3410083e2b42f96c3",
|
||||
"content-hash": "92303801b323e8ec67d40803e6b4127f",
|
||||
"packages": [
|
||||
{
|
||||
"name": "asgrim/ofxparser",
|
||||
@ -147,30 +147,29 @@
|
||||
"time": "2020-06-09T18:11:16+00:00"
|
||||
},
|
||||
{
|
||||
"name": "beganovich/omnipay-checkout",
|
||||
"version": "dev-master",
|
||||
"name": "checkout/checkout-sdk-php",
|
||||
"version": "1.0.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/beganovich/omnipay-checkout.git",
|
||||
"reference": "a4e78bc3ce6ea39ea2c2b7da3019b3966fc86a21"
|
||||
"url": "https://github.com/checkout/checkout-sdk-php.git",
|
||||
"reference": "c83ecc54e549efde8ac53cf1bc9701e800d98b0b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/beganovich/omnipay-checkout/zipball/a4e78bc3ce6ea39ea2c2b7da3019b3966fc86a21",
|
||||
"reference": "a4e78bc3ce6ea39ea2c2b7da3019b3966fc86a21",
|
||||
"url": "https://api.github.com/repos/checkout/checkout-sdk-php/zipball/c83ecc54e549efde8ac53cf1bc9701e800d98b0b",
|
||||
"reference": "c83ecc54e549efde8ac53cf1bc9701e800d98b0b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"omnipay/common": "^3",
|
||||
"php": "^7.1"
|
||||
"php": ">=5.4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"omnipay/tests": "^3"
|
||||
"phpunit/phpunit": "^6"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Omnipay\\Checkout\\": "src"
|
||||
"Checkout\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
@ -179,18 +178,28 @@
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Benjamin Beganović",
|
||||
"email": "ben@invoiceninja.com",
|
||||
"role": "Developer"
|
||||
"name": "Checkout.com",
|
||||
"email": "platforms@checkout.com",
|
||||
"homepage": "https://github.com/checkout/checkout-sdk-php/graphs/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Checkout driver for the Omnipay PHP payment processing library",
|
||||
"homepage": "https://github.com/beganovich/omnipay-checkout",
|
||||
"description": "Checkout.com SDK for PHP",
|
||||
"homepage": "https://github.com/checkout/checkout-sdk-php",
|
||||
"keywords": [
|
||||
"beganovich",
|
||||
"omnipay-checkout"
|
||||
"CKO",
|
||||
"GW3",
|
||||
"Reboot",
|
||||
"api",
|
||||
"checkout",
|
||||
"checkout.com",
|
||||
"checkoutcom",
|
||||
"gateway",
|
||||
"library",
|
||||
"payment",
|
||||
"php",
|
||||
"sdk"
|
||||
],
|
||||
"time": "2020-05-11T22:18:27+00:00"
|
||||
"time": "2019-07-05T16:22:08+00:00"
|
||||
},
|
||||
{
|
||||
"name": "cleverit/ubl_invoice",
|
||||
@ -8653,6 +8662,52 @@
|
||||
],
|
||||
"time": "2020-05-05T10:53:32+00:00"
|
||||
},
|
||||
{
|
||||
"name": "beganovich/omnipay-checkout",
|
||||
"version": "dev-master",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/beganovich/omnipay-checkout.git",
|
||||
"reference": "a4e78bc3ce6ea39ea2c2b7da3019b3966fc86a21"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/beganovich/omnipay-checkout/zipball/a4e78bc3ce6ea39ea2c2b7da3019b3966fc86a21",
|
||||
"reference": "a4e78bc3ce6ea39ea2c2b7da3019b3966fc86a21",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"omnipay/common": "^3",
|
||||
"php": "^7.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"omnipay/tests": "^3"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Omnipay\\Checkout\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Benjamin Beganović",
|
||||
"email": "ben@invoiceninja.com",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "Checkout driver for the Omnipay PHP payment processing library",
|
||||
"homepage": "https://github.com/beganovich/omnipay-checkout",
|
||||
"keywords": [
|
||||
"beganovich",
|
||||
"omnipay-checkout"
|
||||
],
|
||||
"time": "2020-05-11T22:18:27+00:00"
|
||||
},
|
||||
{
|
||||
"name": "beyondcode/laravel-dump-server",
|
||||
"version": "1.3.0",
|
||||
@ -11005,7 +11060,6 @@
|
||||
"aliases": [],
|
||||
"minimum-stability": "dev",
|
||||
"stability-flags": {
|
||||
"beganovich/omnipay-checkout": 20,
|
||||
"webpatser/laravel-countries": 20
|
||||
},
|
||||
"prefer-stable": true,
|
||||
|
2
public/js/clients/payments/checkout.com.js
vendored
2
public/js/clients/payments/checkout.com.js
vendored
@ -1,2 +1,2 @@
|
||||
/*! For license information please see checkout.com.js.LICENSE.txt */
|
||||
!function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="/",n(n.s=8)}({8:function(e,t,n){e.exports=n("XYrq")},XYrq:function(e,t){window.CKOConfig={publicKey:document.querySelector('meta[name="public-key"]').content,customerEmail:document.querySelector('meta[name="customer-email"]').content,value:document.querySelector('meta[name="value"]').content,currency:document.querySelector('meta[name="currency"]').content,paymentMode:"cards",cardFormMode:"cardTokenisation",cardTokenised:function(e){document.querySelector('input[name="gateway_response"]').value=JSON.stringify(e.data),document.getElementById("server-response").submit()}}}});
|
||||
!function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="/",n(n.s=8)}({8:function(e,t,n){e.exports=n("XYrq")},XYrq:function(e,t){window.CKOConfig={publicKey:document.querySelector('meta[name="public-key"]').content,customerEmail:document.querySelector('meta[name="customer-email"]').content,value:document.querySelector('meta[name="value"]').content,currency:document.querySelector('meta[name="currency"]').content,paymentMode:"cards",cardFormMode:"cardTokenisation",cardTokenised:function(e){document.querySelector('input[name="gateway_response"]').value=JSON.stringify(e.data),document.querySelector('input[name="store_card"]').value=document.getElementById("store-card-checkbox").checked,document.getElementById("server-response").submit()}}}});
|
@ -7,7 +7,7 @@
|
||||
"/js/clients/payment_methods/authorize-authorize-card.js": "/js/clients/payment_methods/authorize-authorize-card.js?id=b0a1bd21a57e12cd491a",
|
||||
"/js/clients/payment_methods/authorize-stripe-card.js": "/js/clients/payment_methods/authorize-stripe-card.js?id=f4c45f0da9868d840799",
|
||||
"/js/clients/payments/alipay.js": "/js/clients/payments/alipay.js?id=04778cbf46488e8f6b5f",
|
||||
"/js/clients/payments/checkout.com.js": "/js/clients/payments/checkout.com.js?id=c644b7555ae3c1a918ab",
|
||||
"/js/clients/payments/checkout.com.js": "/js/clients/payments/checkout.com.js?id=ad0a824fb0f79cb8200b",
|
||||
"/js/clients/payments/process.js": "/js/clients/payments/process.js?id=be2b10b1b5e3a727f6e2",
|
||||
"/js/clients/payments/sofort.js": "/js/clients/payments/sofort.js?id=f9253aea74535bc46886",
|
||||
"/js/clients/quotes/action-selectors.js": "/js/clients/quotes/action-selectors.js?id=88ff76c9ca1c15fc011b",
|
||||
|
@ -20,6 +20,10 @@ window.CKOConfig = {
|
||||
document.querySelector(
|
||||
'input[name="gateway_response"]'
|
||||
).value = JSON.stringify(event.data);
|
||||
|
||||
document.querySelector(
|
||||
'input[name="store_card"]'
|
||||
).value = document.getElementById('store-card-checkbox').checked;
|
||||
|
||||
document.getElementById('server-response').submit();
|
||||
},
|
||||
|
@ -20,6 +20,9 @@
|
||||
@endforeach
|
||||
<input type="hidden" name="company_gateway_id" value="{{ $gateway->getCompanyGatewayId() }}">
|
||||
<input type="hidden" name="payment_method_id" value="{{ $payment_method_id }}">
|
||||
<input type="hidden" name="value" value="{{ $value }}">
|
||||
<input type="hidden" name="raw_value" value="{{ $raw_value }}">
|
||||
<input type="hidden" name="currency" value="{{ $currency }}">
|
||||
</form>
|
||||
|
||||
<div class="container mx-auto">
|
||||
@ -51,12 +54,20 @@
|
||||
<span class="font-bold">{{ App\Utils\Number::formatMoney($amount, $client) }}</span>
|
||||
</dd>
|
||||
</div>
|
||||
<div class="bg-gray-50 px-4 py-5 flex justify-end">
|
||||
<div class="bg-gray-50 px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6 flex items-center">
|
||||
<dt class="text-sm leading-5 font-medium text-gray-500 mr-4">
|
||||
{{ ctrans('texts.token_billing_checkbox') }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
|
||||
<input type="checkbox" id="store-card-checkbox" class="form-checkbox">
|
||||
</dd>
|
||||
</div>
|
||||
<div class="bg-white px-4 py-5 flex justify-end">
|
||||
<form class="payment-form" method="POST" action="https://merchant.com/successUrl">
|
||||
@if(app()->environment() == 'production')
|
||||
<script async src="https://cdn.checkout.com/js/checkout.js"></script>
|
||||
<script async src="https://cdn.checkout.com/js/checkout.js"></script>
|
||||
@else
|
||||
<script async src="https://cdn.checkout.com/sandbox/js/checkout.js"></script>
|
||||
<script async src="https://cdn.checkout.com/sandbox/js/checkout.js"></script>
|
||||
@endif
|
||||
</form>
|
||||
</div>
|
||||
|
@ -19,14 +19,14 @@
|
||||
</form>
|
||||
<div class="container mx-auto">
|
||||
<div class="grid grid-cols-6 gap-4">
|
||||
<div class="col-span-6 md:col-start-2 md:col-span-4">
|
||||
<div class="col-span-6 md:col-start-2 md:col-span-4">
|
||||
<div class="alert alert-failure mb-4" hidden id="errors"></div>
|
||||
<div class="bg-white shadow overflow-hidden sm:rounded-lg">
|
||||
<div class="px-4 py-5 border-b border-gray-200 sm:px-6">
|
||||
<h3 class="text-lg leading-6 font-medium text-gray-900">
|
||||
{{ ctrans('texts.pay_now') }}
|
||||
</h3>
|
||||
<p class="mt-1 max-w-2xl text-sm leading-5 text-gray-500" translate>
|
||||
<p class="mt-1 max-w-2xl text-sm leading-5 text-gray-500">
|
||||
{{ ctrans('texts.complete_your_payment') }}
|
||||
</p>
|
||||
</div>
|
||||
|
Loading…
Reference in New Issue
Block a user