diff --git a/app/DataProviders/CAProvinces.php b/app/DataProviders/CAProvinces.php new file mode 100644 index 000000000000..251f6e7c9262 --- /dev/null +++ b/app/DataProviders/CAProvinces.php @@ -0,0 +1,55 @@ + 'Alberta', + 'BC' => 'British Columbia', + 'MB' => 'Manitoba', + 'NB' => 'New Brunswick', + 'NL' => 'Newfoundland And Labrador', + 'NS' => 'Nova Scotia', + 'ON' => 'Ontario', + 'PE' => 'Prince Edward Island', + 'QC' => 'Quebec', + 'SK' => 'Saskatchewan', + 'NT' => 'Northwest Territories', + 'NU' => 'Nunavut', + 'YT' => 'Yukon' + ]; + + /** + * Get the name of the province or territory for a given abbreviation. + * + * @param string $abbreviation + * @return string + */ + public static function getName($abbreviation) { + return self::$provinces[$abbreviation]; + } + + /** + * Get all provinces and territories. + * + * @return array + */ + public static function get() { + return self::$provinces; + } + + /** + * Get the abbreviation for a given province or territory name. + * + * @param string $name + * @return string + */ + public static function getAbbreviation($name) { + return array_search(ucwords($name), self::$provinces); + } +} diff --git a/app/DataProviders/Frequencies.php b/app/DataProviders/Frequencies.php new file mode 100644 index 000000000000..503d40973dc4 --- /dev/null +++ b/app/DataProviders/Frequencies.php @@ -0,0 +1,19 @@ + null, + 'routing_number' => null, + 'institution_number' => null, + 'transit_number' => null, + 'bank_name' => ' ', + 'account_number' => null, + 'country' => 'US', + "authorization_type" => 'Online' + ]; + + public array $account; + + public function __construct(array $account) { + $this->account = $account; + $this->attributes = $this->newAttributeBag(Arr::only($this->account, $this->fields) ); + } + + public function render() + { + + return render('gateways.rotessa.components.account', $this->attributes->getAttributes() + $this->defaults); + } +} diff --git a/app/Http/ViewComposers/Components/Rotessa/AddressComponent.php b/app/Http/ViewComposers/Components/Rotessa/AddressComponent.php new file mode 100644 index 000000000000..b26222b18c53 --- /dev/null +++ b/app/Http/ViewComposers/Components/Rotessa/AddressComponent.php @@ -0,0 +1,48 @@ + 'US' + ]; + + public array $address; + + public function __construct(array $address) { + $this->address = $address; + if(strlen($this->address['state']) > 2 ) { + $this->address['state'] = $this->address['country'] == 'US' ? array_search($this->address['state'], USStates::$states) : CAProvinces::getAbbreviation($this->address['state']); + } + + $this->attributes = $this->newAttributeBag( + Arr::only(Arr::mapWithKeys($this->address, function ($item, $key) { + return in_array($key, ['address1','address2','state'])?[ (['address1'=>'address_1','address2'=>'address_2','state'=>'province_code'])[$key] => $item ] :[ $key => $item ]; + }), + $this->fields) ); + } + + + public function render() + { + return render('gateways.rotessa.components.address', $this->attributes->getAttributes() + $this->defaults ); + } +} diff --git a/app/Http/ViewComposers/Components/Rotessa/ContactComponent.php b/app/Http/ViewComposers/Components/Rotessa/ContactComponent.php new file mode 100644 index 000000000000..3557cd05351f --- /dev/null +++ b/app/Http/ViewComposers/Components/Rotessa/ContactComponent.php @@ -0,0 +1,50 @@ +client->contacts->firstWhere('is_primary', 1)->toArray())->merge([ + 'home_phone' =>$contact->client->phone, + 'custom_identifier' => $contact->client->number, + 'name' =>$contact->client->name, + 'id' => $contact->client->contact_key, + ] )->all(); + + $this->attributes = $this->newAttributeBag(Arr::only($contact, $this->fields) ); + } + + private $fields = [ + 'name', + 'email', + 'home_phone', + 'phone', + 'custom_identifier', + 'customer_type' , + 'id' + ]; + + private $defaults = [ + 'customer_type' => "Business", + 'custom_identifier' => null, + 'customer_id' => null + ]; + + public function render() + { + \Debugbar::debug($this->attributes->getAttributes() + $this->defaults); + return render('gateways.rotessa.components.contact', $this->attributes->getAttributes() + $this->defaults ); + } +} diff --git a/app/Http/ViewComposers/Components/RotessaComponents.php b/app/Http/ViewComposers/Components/RotessaComponents.php new file mode 100644 index 000000000000..b984d0bb2339 --- /dev/null +++ b/app/Http/ViewComposers/Components/RotessaComponents.php @@ -0,0 +1,123 @@ +client->contacts->firstWhere('is_primary', 1)->toArray())->merge([ + 'home_phone' =>$contact->client->phone, + 'custom_identifier' => $contact->client->number, + 'name' =>$contact->client->name, + 'id' => null + ] )->all(); + + $this->attributes = $this->newAttributeBag(Arr::only($contact, $this->fields) ); + } + + private $fields = [ + 'name', + 'email', + 'home_phone', + 'phone', + 'custom_identifier', + 'customer_type' , + 'id' + ]; + + private $defaults = [ + 'customer_type' => "Business", + 'customer_identifier' => null, + 'id' => null + ]; + + public function render() + { + return render('gateways.rotessa.components.contact', array_merge($this->defaults, $this->attributes->getAttributes() ) ); + } +} + +// Address Component +class AddressComponent extends Component +{ + private $fields = [ + 'address_1', + 'address_2', + 'city', + 'postal_code', + 'province_code', + 'country' + ]; + + private $defaults = [ + 'country' => 'US' + ]; + + public array $address; + + public function __construct(array $address) { + $this->address = $address; + if(strlen($this->address['state']) > 2 ) { + $this->address['state'] = $this->address['country'] == 'US' ? array_search($this->address['state'], USStates::$states) : CAProvinces::getAbbreviation($this->address['state']); + } + + $this->attributes = $this->newAttributeBag( + Arr::only(Arr::mapWithKeys($this->address, function ($item, $key) { + return in_array($key, ['address1','address2','state'])?[ (['address1'=>'address_1','address2'=>'address_2','state'=>'province_code'])[$key] => $item ] :[ $key => $item ]; + }), + $this->fields) ); + } + + + public function render() + { + return render('gateways.rotessa.components.address',array_merge( $this->defaults, $this->attributes->getAttributes() ) ); + } +} + +// AmericanBankInfo Component +class AccountComponent extends Component +{ + private $fields = [ + 'bank_account_type', + 'routing_number', + 'institution_number', + 'transit_number', + 'bank_name', + 'country', + 'account_number' + ]; + + private $defaults = [ + 'bank_account_type' => null, + 'routing_number' => null, + 'institution_number' => null, + 'transit_number' => null, + 'bank_name' => ' ', + 'account_number' => null, + 'country' => 'US', + "authorization_type" => 'Online' + ]; + + public array $account; + + public function __construct(array $account) { + $this->account = $account; + $this->attributes = $this->newAttributeBag(Arr::only($this->account, $this->fields) ); + } + + public function render() + { + return render('gateways.rotessa.components.account', array_merge($this->attributes->getAttributes(), $this->defaults) ); + } +} diff --git a/app/Http/ViewComposers/RotessaComposer.php b/app/Http/ViewComposers/RotessaComposer.php new file mode 100644 index 000000000000..493d955267b4 --- /dev/null +++ b/app/Http/ViewComposers/RotessaComposer.php @@ -0,0 +1,16 @@ +with('states', $states); +}); + +// CAProvinces View Composer +View::composer(['*.rotessa.components.address','*.rotessa.components.banks.CA.bank','*.rotessa.components.dropdowns.country.CA'], function ($view) { + $provinces = CAProvinces::get(); + $view->with('provinces', $provinces); +}); \ No newline at end of file diff --git a/app/Models/Gateway.php b/app/Models/Gateway.php index 2fcdfe7ee4d0..43bbfe8fa719 100644 --- a/app/Models/Gateway.php +++ b/app/Models/Gateway.php @@ -105,7 +105,9 @@ class Gateway extends StaticModel $link = 'https://www.forte.net/'; } elseif ($this->id == 62) { $link = 'https://docs.btcpayserver.org/InvoiceNinja/'; - } + } elseif ($this->id == 63) { + $link = 'https://rotessa.com'; + } return $link; } @@ -224,6 +226,15 @@ class Gateway extends StaticModel return [ GatewayType::CRYPTO => ['refund' => true, 'token_billing' => false, 'webhooks' => ['confirmed', 'paid_out', 'failed', 'fulfilled']], ]; //BTCPay + case 63: + return [ + GatewayType::BANK_TRANSFER => [ + 'refund' => false, + 'token_billing' => true, + 'webhooks' => [], + ], + GatewayType::ACSS => ['refund' => false, 'token_billing' => true, 'webhooks' => []] + ]; // Rotessa default: return []; } diff --git a/app/Models/SystemLog.php b/app/Models/SystemLog.php index f61b6c4fbf45..10eb1f2629a8 100644 --- a/app/Models/SystemLog.php +++ b/app/Models/SystemLog.php @@ -152,6 +152,8 @@ class SystemLog extends Model public const TYPE_BTC_PAY = 324; + public const TYPE_ROTESSA = 325; + public const TYPE_QUOTA_EXCEEDED = 400; public const TYPE_UPSTREAM_FAILURE = 401; diff --git a/app/PaymentDrivers/Rotessa/PaymentMethod.php b/app/PaymentDrivers/Rotessa/PaymentMethod.php new file mode 100755 index 000000000000..09717a0da75c --- /dev/null +++ b/app/PaymentDrivers/Rotessa/PaymentMethod.php @@ -0,0 +1,216 @@ +rotessa = $rotessa; + $this->rotessa->init(); + } + + /** + * Show the authorization page for Rotessa. + * + * @param array $data + * @return \Illuminate\View\View + */ + public function authorizeView(array $data): View + { + $data['contact'] = collect($data['client']->contacts->firstWhere('is_primary', 1)->toArray())->merge([ + 'home_phone' => $data['client']->phone, + 'custom_identifier' => $data['client']->number, + 'name' => $data['client']->name, + 'id' => null + ] )->all(); + $data['gateway'] = $this->rotessa; + // Set gateway type according to client country + // $data['gateway_type_id'] = $data['client']->country->iso_3166_2 == 'US' ? GatewayType::BANK_TRANSFER : ( $data['client']->country->iso_3166_2 == 'CA' ? GatewayType::ACSS : (int) request('method')); + // TODO: detect GatewayType based on client country USA vs CAN + $data['gateway_type_id'] = GatewayType::ACSS ; + $data['account'] = [ + 'routing_number' => $data['client']->routing_id, + 'country' => $data['client']->country->iso_3166_2 + ]; + $data['address'] = collect($data['client']->toArray())->merge(['country' => $data['client']->country->iso_3166_2 ])->all(); + + return render('gateways.rotessa.bank_transfer.authorize', $data ); + } + /** + * Handle the authorization page for Rotessa. + * + * @param Request $request + * @return RedirectResponse + */ + public function authorizeResponse(Request $request): RedirectResponse + { + try { + $request->validate([ + 'gateway_type_id' => ['required','integer'], + 'country' => ['required'], + 'name' => ['required'], + 'address_1' => ['required'], + 'address_2' => ['required'], + 'city' => ['required'], + 'email' => ['required','email:filter'], + 'province_code' => ['required','size:2','alpha'], + 'postal_code' => ['required'], + 'authorization_type' => ['required'], + 'account_number' => ['required'], + 'bank_name' => ['required'], + 'phone' => ['required'], + 'home_phone' => ['required'], + 'bank_account_type'=>['required_if:country,US'], + 'routing_number'=>['required_if:country,US'], + 'institution_number'=>['required_if:country,CA','numeric'], + 'transit_number'=>['required_if:country,CA','numeric'], + 'custom_identifier'=>['required_without:customer_id'], + 'customer_id'=>['required_without:custom_identifier','integer'], + ]); + $customer = new Customer( ['address' => $request->only('address_1','address_2','city','postal_code','province_code','country'), 'custom_identifier' => $request->input('custom_identifier') ] + $request->all()); + $this->rotessa->findOrCreateCustomer($customer->resolve()); + + return redirect()->route('client.payment_methods.index')->withMessage(ctrans('texts.payment_method_added')); + + } catch (\Throwable $e) { + return $this->rotessa->processInternallyFailedPayment($this->rotessa, new ClientPortalAuthorizationException( get_class( $e) . " : {$e->getMessage()}", (int) $e->getCode() )); + } + + return back()->withMessage(ctrans('texts.unable_to_verify_payment_method')); + } + + /** + * Payment view for the Rotessa. + * + * @param array $data + * @return \Illuminate\View\View + */ + public function paymentView(array $data): View + { + $data['gateway'] = $this->rotessa; + $data['amount'] = $data['total']['amount_with_fee']; + $data['due_date'] = date('Y-m-d', min(max(strtotime($data['invoices']->max('due_date')), strtotime('now')), strtotime('+1 day'))); + $data['process_date'] = $data['due_date']; + $data['currency'] = $this->rotessa->client->getCurrencyCode(); + $data['frequency'] = Frequencies::getOnePayment(); + $data['installments'] = 1; + $data['invoice_nums'] = $data['invoices']->pluck('invoice_number')->join(', '); + return render('gateways.rotessa.bank_transfer.pay', $data ); + } + + /** + * Handle payments page for Rotessa. + * + * @param PaymentResponseRequest $request + * @return void + */ + public function paymentResponse(PaymentResponseRequest $request) + { + $response= null; + $customer = null; + try { + $request->validate([ + 'source' => ['required','string','exists:client_gateway_tokens,token'], + 'amount' => ['required','numeric'], + 'process_date'=> ['required','date','after_or_equal:today'], + ]); + $customer = ClientGatewayToken::query() + ->where('company_gateway_id', $this->rotessa->company_gateway->id) + ->where('client_id', $this->rotessa->client->id) + ->where('token', $request->input('source')) + ->first(); + if(!$customer) throw new \Exception('Client gateway token not found!', SystemLog::TYPE_ROTESSA); + + $transaction = new Transaction($request->only('frequency' ,'installments','amount','process_date') + ['comment' => $this->rotessa->getDescription(false) ]); + $transaction->additional(['customer_id' => $customer->gateway_customer_reference]); + $transaction = array_filter( $transaction->resolve()); + $response = $this->rotessa->gateway->capture($transaction)->send(); + if(!$response->isSuccessful()) throw new \Exception($response->getMessage(), (int) $response->getCode()); + + return $this->processPendingPayment($response->getParameter('id'), (float) $response->getParameter('amount'), (int) $customer->gateway_type_id , $customer->token); + } catch(\Throwable $e) { + $this->processUnsuccessfulPayment( new InvalidResponseException($e->getMessage(), (int) $e->getCode()) ); + } + } + + public function processPendingPayment($payment_id, float $amount, int $gateway_type_id, $payment_method ) + { + $data = [ + 'payment_method' => $payment_method, + 'payment_type' => $gateway_type_id, + 'amount' => $amount, + 'transaction_reference' =>$payment_id, + 'gateway_type_id' => $gateway_type_id, + ]; + $payment = $this->rotessa->createPayment($data, Payment::STATUS_PENDING); + SystemLogger::dispatch( + [ 'data' => $data ], + SystemLog::CATEGORY_GATEWAY_RESPONSE, + SystemLog::EVENT_GATEWAY_SUCCESS, + SystemLog::TYPE_ROTESSA, + $this->rotessa->client, + $this->rotessa->client->company, + ); + + return redirect()->route('client.payments.show', [ 'payment' => $payment->hashed_id ]); + } + + /** + * Handle unsuccessful payment for Rotessa. + * + * @param Exception $exception + * @throws PaymentFailed + * @return void + */ + public function processUnsuccessfulPayment(\Exception $exception): void + { + $this->rotessa->sendFailureMail($exception->getMessage()); + + SystemLogger::dispatch( + $exception->getMessage(), + SystemLog::CATEGORY_GATEWAY_RESPONSE, + SystemLog::EVENT_GATEWAY_FAILURE, + SystemLog::TYPE_ROTESSA, + $this->rotessa->client, + $this->rotessa->client->company, + ); + + throw new PaymentFailed($exception->getMessage(), $exception->getCode()); + } +} diff --git a/app/PaymentDrivers/Rotessa/Resources/Customer.php b/app/PaymentDrivers/Rotessa/Resources/Customer.php new file mode 100644 index 000000000000..c2514dfdd8c1 --- /dev/null +++ b/app/PaymentDrivers/Rotessa/Resources/Customer.php @@ -0,0 +1,22 @@ +resource->jsonSerialize(); + } + + function toArray(Request $request) : array { + return $this->additional + parent::toArray($request); + } +} diff --git a/app/PaymentDrivers/Rotessa/Resources/Transaction.php b/app/PaymentDrivers/Rotessa/Resources/Transaction.php new file mode 100644 index 000000000000..84ce332860f8 --- /dev/null +++ b/app/PaymentDrivers/Rotessa/Resources/Transaction.php @@ -0,0 +1,23 @@ +resource->jsonSerialize(); + } + + function toArray(Request $request) : array { + return $this->additional + parent::toArray($request); + } +} diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/AbstractClient.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/AbstractClient.php new file mode 100644 index 000000000000..c84a97322717 --- /dev/null +++ b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/AbstractClient.php @@ -0,0 +1,21 @@ +default_parameters; + } + + public function setDefaultParameters(array $params) { + $this->default_parameters = $params; + } + +} diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/ApiTrait.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/ApiTrait.php new file mode 100644 index 000000000000..5fc947713f3a --- /dev/null +++ b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/ApiTrait.php @@ -0,0 +1,41 @@ +createRequest('GetCustomers', [] ); + } + public function postCustomers(array $params) : RequestInterface { + return $this->createRequest('PostCustomers', $params ); + } + public function getCustomersId(array $params) : RequestInterface { + return $this->createRequest('GetCustomersId', $params ); + } + public function patchCustomersId(array $params) : RequestInterface { + return $this->createRequest('PatchCustomersId', $params ); + } + public function postCustomersShowWithCustomIdentifier(array $params) : RequestInterface { + return $this->createRequest('PostCustomersShowWithCustomIdentifier', $params ); + } + public function getTransactionSchedulesId(array $params) : RequestInterface { + return $this->createRequest('GetTransactionSchedulesId', $params ); + } + public function deleteTransactionSchedulesId(array $params) : RequestInterface { + return $this->createRequest('DeleteTransactionSchedulesId', $params ); + } + public function patchTransactionSchedulesId(array $params) : RequestInterface { + return $this->createRequest('PatchTransactionSchedulesId', $params ); + } + public function postTransactionSchedules(array $params) : RequestInterface { + return $this->createRequest('PostTransactionSchedules', $params ); + } + public function postTransactionSchedulesCreateWithCustomIdentifier(array $params) : RequestInterface { + return $this->createRequest('PostTransactionSchedulesCreateWithCustomIdentifier', $params ); + } + public function postTransactionSchedulesUpdateViaPost(array $params) : RequestInterface { + return $this->createRequest('PostTransactionSchedulesUpdateViaPost', $params ); + } + } diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/ClientInterface.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/ClientInterface.php new file mode 100644 index 000000000000..4d08fb0441f2 --- /dev/null +++ b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/ClientInterface.php @@ -0,0 +1,11 @@ + 1234567890 ]; + + protected $test_mode = true; + + protected $api_key; + + public function getName() + { + return 'Rotessa'; + } + + public function getDefaultParameters() : array + { + return array_merge($this->default_parameters, array('api_key' => $this->api_key, 'test_mode' => $this->test_mode ) ); + } + + public function setTestMode($value) { + $this->test_mode = $value; + } + + public function getTestMode() { + return $this->test_mode; + } + + protected function createRequest($class_name, ?array $parameters = [] ) :RequestInterface { + $class = null; + $class_name = "Omnipay\\Rotessa\\Message\\Request\\$class_name"; + $parameters = $class_name::hasModel() ? (($parameters = ($class_name::getModel($parameters)))->validate() ? $parameters->jsonSerialize() : null ) : $parameters; + try { + $class = new $class_name($this->httpClient, $this->httpRequest, $this->getDefaultParameters() + $parameters ); + } catch (\Throwable $th) { + throw $th; + } + + return $class; + } + + function setApiKey($value) { + $this->api_key = $value; + } + + function getApiKey() { + return $this->api_key; + } + + function authorize(array $options = []) : RequestInterface { + return $this->postCustomers($options); + } + + function capture(array $options = []) : RequestInterface { + return array_key_exists('customer_id', $options)? $this->postTransactionSchedules($options) : $this->postTransactionSchedulesCreateWithCustomIdentifier($options) ; + } + + function updateCustomer(array $options) : RequestInterface { + return $this->patchCustomersId($options); + } + + function fetchTransaction($id = null) : RequestInterface { + return $this->getTransactionSchedulesId(compact('id')); + } + +} \ No newline at end of file diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Http/Client.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Http/Client.php new file mode 100644 index 000000000000..4c8ea0d29075 --- /dev/null +++ b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Http/Client.php @@ -0,0 +1,82 @@ +httpClient = $httpClient ?: HttpClientDiscovery::find(); + $this->requestFactory = $requestFactory ?: MessageFactoryDiscovery::find(); + parent::__construct($httpClient, $requestFactory); + } + + /** + * @param $method + * @param $uri + * @param array $headers + * @param string|array|resource|StreamInterface|null $body + * @param string $protocolVersion + * @return ResponseInterface + * @throws \Http\Client\Exception + */ + public function request( + $method, + $uri, + array $headers = [], + $body = null, + $protocolVersion = '1.1' + ) { + return $this->sendRequest($method, $uri, $headers, $body, $protocolVersion); + + } + + /** + * @param RequestInterface $request + * @return ResponseInterface + * @throws \Http\Client\Exception + */ + private function sendRequest( $method, + $uri, + array $headers = [], + $body = null, + $protocolVersion = '1.1') + { + + $response = null; + + try { + if( method_exists($this->httpClient, 'sendRequest')) + $response = $this->httpClient->sendRequest( $this->requestFactory->createRequest($method, $uri, $headers, $body, $protocolVersion)); + else $response = $this->httpClient->request($method, $uri, compact('body','headers')); + } catch (\Http\Client\Exception\NetworkException $networkException) { + throw new NetworkException($networkException->getMessage(), $request, $networkException); + } catch (\Exception $exception) { + throw new RequestException($exception->getMessage(), $request, $exception); + } + + return $response; + } +} \ No newline at end of file diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Http/Response/Response.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Http/Response/Response.php new file mode 100644 index 000000000000..8d665ac8546e --- /dev/null +++ b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Http/Response/Response.php @@ -0,0 +1,32 @@ +content, true) )) { + $data = $data['errors'][0]; + $this->reason_phrase = $data['error_message'] ; + $this->reason_code = $data['error_message'] ; + } + } + + public function getReasonPhrase() { + return $this->reason_phrase; + } + + public function getReasonCode() { + return $this->reason_code; + } +} diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/IsValidTypeTrait.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/IsValidTypeTrait.php new file mode 100644 index 000000000000..266ba3036d9d --- /dev/null +++ b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/IsValidTypeTrait.php @@ -0,0 +1,12 @@ +api_key = $value; + } + + public function getData() { + try { + if(empty($this->api_key)) throw new \Exception('No Api Key Found!'); + $this->validate( ...array_keys($data = $this->getParameters())); + } catch (\Throwable $th) { + throw new \Omnipay\Rotessa\Exception\ValidationException($th->getMessage() , 600, $th); + } + + return (array) $data; + } + + abstract public function sendData($data) : ResponseInterface; + + abstract protected function sendRequest(string $method, string $endpoint, array $headers = [], array $data = [] ); + + abstract protected function createResponse(array $data) : ResponseInterface; + + abstract public function getEndpointUrl(): string; + + public function getEndpoint() : string { + return $this->endpoint; + } + + public function getTestMode() { + return $this->test_mode; + } + + public function setTestMode($mode) { + $this->test_mode = $mode; + } + } \ No newline at end of file diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/BaseRequest.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/BaseRequest.php new file mode 100644 index 000000000000..4b68cf0aa2ff --- /dev/null +++ b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/BaseRequest.php @@ -0,0 +1,93 @@ +initialize($model); + } + + protected function sendRequest(string $method, string $endpoint, array $headers = [], array $data = []) + { + /** + * @param $method + * @param $uri + * @param array $headers + * @param string|resource|StreamInterface|null $body + * @param string $protocolVersion + * @return ResponseInterface + * @throws \Http\Client\Exception + */ + $response = $this->httpClient->request($method, $endpoint, $headers, json_encode($data) ) ; + $this->response = new Response ($response->getBody()->getContents(), $response->getStatusCode(), $response->getHeaders(), true); + } + + + protected function createResponse(array $data): ResponseInterface { + + return new BaseResponse($this, $data, $this->response->getStatusCode(), $this->response->getReasonPhrase()); + } + + protected function replacePlaceholder($string, $array) { + $pattern = "/\{([^}]+)\}/"; + $replacement = function($matches) use($array) { + $key = $matches[1]; + if (array_key_exists($key, $array)) { + return $array[$key]; + } else { + return $matches[0]; + } + }; + + return preg_replace_callback($pattern, $replacement, $string); + } + + public function sendData($data) :ResponseInterface { + $headers = [ + 'Content-Type' => 'application/json', + 'Accept' => 'application/json', + 'Authorization' => "Token token={$this->api_key}" + ]; + + $this->sendRequest( + $this->method, + $this->getEndpointUrl(), + $headers, + $data); + + return $this->createResponse(json_decode($this->response->getContent(), true)); + } + + public function getEndpoint() : string { + return $this->replacePlaceholder($this->endpoint, $this->getParameters()); + } + + public function getEndpointUrl() : string { + return sprintf('https://%s.%s/v%d%s',$this->test_mode ? self::ENVIRONMENT_SANDBOX : self::ENVIRONMENT_LIVE ,$this->base_url, $this->api_version, $this->getEndpoint()); + } + + public static function hasModel() : bool { + return (bool) static::$model; + } + + public static function getModel($parameters = []) { + $class_name = static::$model; + $class_name = "Omnipay\\Rotessa\\Model\\{$class_name}Model"; + return new $class_name($parameters); + } +} \ No newline at end of file diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/DeleteTransactionSchedulesId.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/DeleteTransactionSchedulesId.php new file mode 100644 index 000000000000..7c03c42b0dc6 --- /dev/null +++ b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/DeleteTransactionSchedulesId.php @@ -0,0 +1,18 @@ +setParameter('id',$value); + } + +} diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/GetCustomers.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/GetCustomers.php new file mode 100644 index 000000000000..17ffde5355d9 --- /dev/null +++ b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/GetCustomers.php @@ -0,0 +1,14 @@ +setParameter('id',$value); + } +} diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/GetTransactionSchedulesId.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/GetTransactionSchedulesId.php new file mode 100644 index 000000000000..47578d06eb8b --- /dev/null +++ b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/GetTransactionSchedulesId.php @@ -0,0 +1,17 @@ +setParameter('id',$value); + } + } diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PatchCustomersId.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PatchCustomersId.php new file mode 100644 index 000000000000..092e378b9fd5 --- /dev/null +++ b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PatchCustomersId.php @@ -0,0 +1,65 @@ +setParameter('id',$value); + } + public function setCustomIdentifier(string $value) { + $this->setParameter('custom_identifier',$value); + } + public function setName(string $value) { + $this->setParameter('name',$value); + } + public function setEmail(string $value) { + $this->setParameter('email',$value); + } + public function setCustomerType(string $value) { + $this->setParameter('customer_type',$value); + } + public function setHomePhone(string $value) { + $this->setParameter('home_phone',$value); + } + public function setPhone(string $value) { + $this->setParameter('phone',$value); + } + public function setBankName(string $value) { + $this->setParameter('bank_name',$value); + } + public function setInstitutionNumber(string $value) { + $this->setParameter('institution_number',$value); + } + public function setTransitNumber(string $value) { + $this->setParameter('transit_number',$value); + } + public function setBankAccountType(string $value) { + $this->setParameter('bank_account_type',$value); + } + public function setAuthorizationType(string $value) { + $this->setParameter('authorization_type',$value); + } + public function setRoutingNumber(string $value) { + $this->setParameter('routing_number',$value); + } + public function setAccountNumber(string $value) { + $this->setParameter('account_number',$value); + } + public function setAddress(array $value) { + $this->setParameter('address',$value); + } + public function setTransactionSchedules(array $value) { + $this->setParameter('transaction_schedules',$value); + } + public function setFinancialTransactions(array $value) { + $this->setParameter('financial_transactions',$value); + } + } diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PatchTransactionSchedulesId.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PatchTransactionSchedulesId.php new file mode 100644 index 000000000000..fa04b9f05da6 --- /dev/null +++ b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PatchTransactionSchedulesId.php @@ -0,0 +1,22 @@ +setParameter('id',$value); + } + public function setAmount(int $value) { + $this->setParameter('amount',$value); + } + public function setComment(string $value) { + $this->setParameter('comment',$value); + } + } diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PostCustomers.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PostCustomers.php new file mode 100644 index 000000000000..a0c54fe65ca9 --- /dev/null +++ b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PostCustomers.php @@ -0,0 +1,60 @@ +setParameter('id',$value); + } + public function setCustomIdentifier(string $value) { + $this->setParameter('custom_identifier',$value); + } + public function setName(string $value) { + $this->setParameter('name',$value); + } + public function setEmail(string $value) { + $this->setParameter('email',$value); + } + public function setCustomerType(string $value) { + $this->setParameter('customer_type',$value); + } + public function setHomePhone(string $value) { + $this->setParameter('home_phone',$value); + } + public function setPhone(string $value) { + $this->setParameter('phone',$value); + } + public function setBankName(string $value) { + $this->setParameter('bank_name',$value); + } + public function setInstitutionNumber(string $value = '') { + $this->setParameter('institution_number',$value); + } + public function setTransitNumber(string $value = '') { + $this->setParameter('transit_number',$value); + } + public function setBankAccountType(string $value) { + $this->setParameter('bank_account_type',$value); + } + public function setAuthorizationType(string $value = '') { + $this->setParameter('authorization_type',$value); + } + public function setRoutingNumber(string $value = '') { + $this->setParameter('routing_number',$value); + } + public function setAccountNumber(string $value) { + $this->setParameter('account_number',$value); + } + public function setAddress(array $value) { + $this->setParameter('address',$value); + } + } diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PostCustomersShowWithCustomIdentifier.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PostCustomersShowWithCustomIdentifier.php new file mode 100644 index 000000000000..d590cb618526 --- /dev/null +++ b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PostCustomersShowWithCustomIdentifier.php @@ -0,0 +1,19 @@ +setParameter('custom_identifier',$value); + } + +} diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PostTransactionSchedules.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PostTransactionSchedules.php new file mode 100644 index 000000000000..80e28a7f5083 --- /dev/null +++ b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PostTransactionSchedules.php @@ -0,0 +1,31 @@ +setParameter('customer_id',$value); + } + public function setProcessDate(string $value) { + $this->setParameter('process_date',$value); + } + public function setFrequency(string $value) { + $this->setParameter('frequency',$value); + } + public function setInstallments(int $value) { + $this->setParameter('installments',$value); + } + public function setComment(string $value) { + $this->setParameter('comment',$value); + } + } diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PostTransactionSchedulesCreateWithCustomIdentifier.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PostTransactionSchedulesCreateWithCustomIdentifier.php new file mode 100644 index 000000000000..fd5111dc9a74 --- /dev/null +++ b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PostTransactionSchedulesCreateWithCustomIdentifier.php @@ -0,0 +1,16 @@ +setParameter('custom_identifier',$value); + } + +} diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PostTransactionSchedulesUpdateViaPost.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PostTransactionSchedulesUpdateViaPost.php new file mode 100644 index 000000000000..e037c5b4d322 --- /dev/null +++ b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/PostTransactionSchedulesUpdateViaPost.php @@ -0,0 +1,24 @@ +setParameter('id',$value); + } + public function setAmount(int $value) { + $this->setParameter('amount',$value); + } + public function setComment(string $value) { + $this->setParameter('comment',$value); + } + } diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/RequestInterface.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/RequestInterface.php new file mode 100644 index 000000000000..cfbcf0095b24 --- /dev/null +++ b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Request/RequestInterface.php @@ -0,0 +1,10 @@ +code = $code; + $this->message = $message; + } + + public function getData() { + return $this->getParameters(); + } + + public function getCode() { + return (int) $this->code; + } + + public function isSuccessful() { + return $this->code < 300; + } + + public function getMessage() { + return $this->message; + } + + protected function getParameters() { + return $this->data; + } + + public function getParameter(string $key) { + return $this->getParameters()[$key]; + } +} \ No newline at end of file diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Response/ResponseInterface.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Response/ResponseInterface.php new file mode 100644 index 000000000000..080eaab504b1 --- /dev/null +++ b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Message/Response/ResponseInterface.php @@ -0,0 +1,9 @@ +required), array_filter($this->getParameters()) ); + if(!empty($required)) throw new ValidationException("Could not validate " . implode(",", array_keys($required)) ); + + return true; + } + + public function __get($key) { + return array_key_exists($key, $this->attributes) ? $this->getParameter($key) : null; + } + + public function __set($key, $value) { + if(array_key_exists($key, $this->attributes)) $this->setParameter($key, $value); + } + + public function __toString() : string { + return json_encode($this); + } + + public function toString() : string { + return $this->__toString(); + } + + public function __toArray() : array { + return $this->getParameters(); + } + + + public function toArray() : array { + return $this->__toArray(); + } + + public function initialize(array $params = []) { + $this->parameters = new ParameterBag; + $parameters = array_merge($this->defaults, $params); + if ($parameters) { + foreach ($this->attributes as $param => $type) { + $value = @$parameters[$param]; + if($value){ + settype($value, $type); + $this->setParameter($param, $value); + } + } + } + + return $this; + } +} diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Model/BaseModel.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Model/BaseModel.php new file mode 100644 index 000000000000..8064662068c4 --- /dev/null +++ b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Model/BaseModel.php @@ -0,0 +1,24 @@ + "string" + ]; + protected $required = ['id']; + protected $defaults = ['id' => 0 ]; + + public function __construct($parameters = array()) { + $this->initialize($parameters); + } + + public function jsonSerialize() : array { + return array_intersect_key($this->toArray(), array_flip($this->required) ); + } +} diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Model/CustomerModel.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Model/CustomerModel.php new file mode 100644 index 000000000000..0fd67aea9441 --- /dev/null +++ b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Model/CustomerModel.php @@ -0,0 +1,94 @@ + "string", + "custom_identifier" => "string", + "name" => "string", + "email" => "string", + "customer_type" => "string", + "home_phone" => "string", + "phone" => "string", + "bank_name" => "string", + "institution_number" => "string", + "transit_number" => "string", + "bank_account_type" => "string", + "authorization_type" => "string", + "routing_number" => "string", + "account_number" => "string", + "address" => "object", + "transaction_schedules" => "array", + "financial_transactions" => "array", + "active" => "bool" + ]; + + protected $defaults = ["active" => false,"customer_type" =>'Business',"bank_account_type" =>'Savings',"authorization_type" =>'Online',]; + protected $required = ["name","email","customer_type","home_phone","phone","bank_name","institution_number","transit_number","bank_account_type","authorization_type","routing_number","account_number","address",'custom_identifier']; + + public function validate() : bool { + try { + $country = $this->address->country; + if(!self::isValidCountry($country)) throw new \Exception("Invalid country!"); + + $this->required = array_diff($this->required, Country::isAmerican($country) ? ["institution_number", "transit_number"] : ["bank_account_type", "routing_number"]); + parent::validate(); + if(Country::isCanadian($country) ) { + if(!self::isValidTransitNumber($this->getParameter('transit_number'))) throw new \Exception("Invalid transit number!"); + if(!self::isValidInstitutionNumber($this->getParameter('institution_number'))) throw new \Exception("Invalid institution number!"); + } + if(!self::isValidCustomerType($this->getParameter('customer_type'))) throw new \Exception("Invalid customer type!"); + if(!self::isValidBankAccountType($this->getParameter('bank_account_type'))) throw new \Exception("Invalid bank account type!"); + if(!self::isValidAuthorizationType($this->getParameter('authorization_type'))) throw new \Exception("Invalid authorization type!"); + } catch (\Throwable $th) { + throw new ValidationException($th->getMessage()); + } + + return true; + } + + public static function isValidCountry(string $country ) : bool { + return Country::isValidCountryCode($country) || Country::isValidCountryName($country); + } + + public static function isValidTransitNumber(string $value ) : bool { + return strlen($value) == 5; + } + + public static function isValidInstitutionNumber(string $value ) : bool { + return strlen($value) == 3; + } + + public static function isValidCustomerType(string $value ) : bool { + return CustomerType::isValid($value); + } + + public static function isValidBankAccountType(string $value ) : bool { + return BankAccountType::isValid($value); + } + + public static function isValidAuthorizationType(string $value ) : bool { + return AuthorizationType::isValid($value); + } + + public function toArray() : array { + return [ 'address' => (array) $this->getParameter('address') ] + parent::toArray(); + } + + public function jsonSerialize() : array { + $address = (array) $this->getParameter('address'); + unset($address['country']); + + return compact('address') + parent::jsonSerialize(); + } +} diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Model/CustomerPatchModel.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Model/CustomerPatchModel.php new file mode 100644 index 000000000000..c2e51d50b135 --- /dev/null +++ b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Model/CustomerPatchModel.php @@ -0,0 +1,16 @@ + "string", + "amount" => "float", + "comment" => "string", + "created_at" => "date", + "financial_transactions" => "array", + "frequency" => "string", + "installments" => "integer", + "next_process_date" => "date", + "process_date" => "date", + "updated_at" => "date", + "customer_id" => "string", + "custom_identifier" => "string", + ]; + + public const DATE_FORMAT = 'F j, Y'; + + protected $defaults = ["amount" =>0.00,"comment" =>' ',"financial_transactions" =>0,"frequency" =>'Once',"installments" =>1]; + + protected $required = ["amount","comment","frequency","installments","process_date"]; + + public function validate() : bool { + try { + parent::validate(); + if(!self::isValidDate($this->process_date)) throw new \Exception("Could not validate date "); + if(!self::isValidFrequency($this->frequency)) throw new \Exception("Invalid frequency"); + if(is_null($this->customer_id) && is_null($this->custom_identifier)) throw new \Exception("customer id or custom identifier is invalid"); + } catch (\Throwable $th) { + throw new ValidationException($th->getMessage()); + } + + return true; + } + + public function jsonSerialize() : array { + return ['customer_id' => $this->getParameter('customer_id'), 'custom_identifier' => $this->getParameter('custom_identifier') ] + parent::jsonSerialize() ; + } + + public function __toArray() : array { + return parent::__toArray() ; + } + + public function initialize(array $params = [] ) { + $o_params = array_intersect_key( + $params = array_intersect_key($params, $this->attributes), + ($attr = array_filter($this->attributes, fn($p) => $p != "date")) + ); + parent::initialize($o_params); + $d_params = array_diff_key($params, $attr); + array_walk($d_params, function($v,$k) { + $this->setParameter($k, self::formatDate( $v) ); + }, ); + + return $this; + } + + public static function isValidDate($date) : bool { + $d = DateTime::createFromFormat(self::DATE_FORMAT, $date); + // Check if the date is valid and matches the format + return $d && $d->format(self::DATE_FORMAT) === $date; + } + + public static function isValidFrequency($value) : bool { + return Frequency::isValid($value); + } + + protected static function formatDate($date) : string { + $d = new DateTime($date); + return $d->format(self::DATE_FORMAT); + } +} diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Model/TransactionSchedulesIdBodyModel.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Model/TransactionSchedulesIdBodyModel.php new file mode 100644 index 000000000000..119ac03999cb --- /dev/null +++ b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Model/TransactionSchedulesIdBodyModel.php @@ -0,0 +1,23 @@ + "int", + "comment" => "string", + ]; + + public const DATE_FORMAT = 'Y-m-d H:i:s'; + + private $_is_error = false; + + protected $defaults = ["amount" =>0,"comment" =>'0',]; + + protected $required = ["amount","comment",]; +} diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Model/TransactionSchedulesUpdateViaPostBodyModel.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Model/TransactionSchedulesUpdateViaPostBodyModel.php new file mode 100644 index 000000000000..749ae2f6b967 --- /dev/null +++ b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Model/TransactionSchedulesUpdateViaPostBodyModel.php @@ -0,0 +1,24 @@ + "int", + "amount" => "int", + "comment" => "string", + ]; + + public const DATE_FORMAT = 'Y-m-d H:i:s'; + + private $_is_error = false; + + protected $defaults = ["amount" =>0,"comment" =>'0',]; + + protected $required = ["amount","comment",]; +} diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Object/Address.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Object/Address.php new file mode 100644 index 000000000000..1c5952b112ef --- /dev/null +++ b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Object/Address.php @@ -0,0 +1,53 @@ + "string", + "address_2" => "string", + "city" => "string", + "id" => "int", + "postal_code" => "string", + "province_code" => "string", + "country" => "string" + ]; + + protected $required = ["address_1","address_2","city","postal_code","province_code",]; + + public function jsonSerialize() { + return array_intersect_key($this->getParameters(), array_flip($this->required)); + } + + public function getCountry() : string { + return $this->getParameter('country'); + } + + public function initialize(array $parameters) { + foreach($this->attributes as $param => $type) { + $value = @$parameters[$param] ; + settype($value, $type); + $value = $value ?? null; + $this->parameters->set($param, $value); + } + } + + public function __toArray() : array { + return $this->getParameters(); + } + + public function __toString() : string { + return $this->getFullAddress(); + } + + public function getFullAddress() :string { + $full_address = $this->getParameters(); + extract($full_address); + + return "$address_1 $address_2, $city, $postal_code $province_code, $country"; + } +} diff --git a/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Object/AuthorizationType.php b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Object/AuthorizationType.php new file mode 100644 index 000000000000..39dcebfa342f --- /dev/null +++ b/app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/Object/AuthorizationType.php @@ -0,0 +1,28 @@ + BankTransfer::class, + //GatewayType::BACS => Bacs::class, + GatewayType::ACSS => Acss::class, + // GatewayType::DIRECT_DEBIT => DirectDebit::class + ]; + + public function init(): self + { + + $this->gateway = Omnipay::create( + $this->company_gateway->gateway->provider + ); + $this->gateway->initialize((array) $this->company_gateway->getConfig()); + return $this; + } + + public function gatewayTypes(): array + { + $types = []; + + /* + // TODO: needs to test with US test account + if ($this->client + && $this->client->currency() + && in_array($this->client->currency()->code, ['USD']) + && isset($this->client->country) + && in_array($this->client->country->iso_3166_2, ['US'])) { + $types[] = GatewayType::BANK_TRANSFER; + }*/ + + if ($this->client + && $this->client->currency() + && in_array($this->client->currency()->code, ['CAD']) + && isset($this->client->country) + && in_array($this->client->country->iso_3166_2, ['CA'])) { + $types[] = GatewayType::ACSS; + } + + return $types; + } + + + public function setPaymentMethod($payment_method_id) + { + $class = self::$methods[$payment_method_id]; + $this->payment_method = new $class($this); + + return $this; + } + + public function authorizeView(array $data) + { + return $this->payment_method->authorizeView($data); + } + + public function authorizeResponse($request) + { + return $this->payment_method->authorizeResponse($request); + } + + public function processPaymentView(array $data) + { + return $this->payment_method->paymentView($data); + } + + public function processPaymentResponse($request) + { + return $this->payment_method->paymentResponse($request); + } + + public function importCustomers() { + $this->init(); + try { + if(!$result = Cache::has("rotessa-import_customers-{$this->company_gateway->company->company_key}")) { + $result = $this->gateway->getCustomers()->send(); + if(!$result->isSuccessful()) throw new \Exception($result->getMessage(), (int) $result->getCode()); + // cache results + Cache::put("rotessa-import_customers-{$this->company_gateway->company->company_key}", $result->getData(), 60 * 60 * 24); + } + + $result = Cache::get("rotessa-import_customers-{$this->company_gateway->company->company_key}"); + $customers = collect($result)->unique('email'); + $client_emails = $customers->pluck('email')->all(); + $company_id = $this->company_gateway->company->id; + // get existing customers + $client_contacts = ClientContact::where('company_id', $company_id)->whereIn('email', $client_emails )->whereNull('deleted_at')->get(); + $client_contacts = $client_contacts->map(function($item, $key) use ($customers) { + return array_merge([], (array) $customers->firstWhere("email", $item->email) , ['custom_identifier' => $item->client->number, 'identifier' => $item->client->number, 'client_id' => $item->client->id ]); + } ); + // create payment methods + $client_contacts->each( + function($contact) use ($customers) { + $result = $this->gateway->getCustomersId(['id' => ($contact = (object) $contact)->id])->send(); + $this->client = Client::find($contact->client_id); + $customer = (new Customer($result->getData()))->additional(['id' => $contact->id, 'custom_identifier' => $contact->custom_identifier ] ); + $this->findOrCreateCustomer($customer->additional + $customer->jsonSerialize()); + } + ); + + // create new clients from rotessa customers + $client_emails = $client_contacts->pluck('email')->all(); + $client_contacts = $customers->filter(function ($value, $key) use ($client_emails) { + return !in_array(((object) $value)->email, $client_emails); + })->each( function($customer) use ($company_id) { + // create new client contact from rotess customer + $customer = (object) $this->gateway->getCustomersId(['id' => ($customer = (object) $customer)->id])->send()->getData(); + /** + { + "account_number": "11111111" + "active": true, + "address": { + "address_1": "123 Main Street", + "address_2": "Unit 4", + "city": "Birmingham", + "id": 114397, + "postal_code": "36016", + "province_code": "AL" + }, + "authorization_type": "Online", + "bank_account_type": "Checking", + "bank_name": "Scotiabank", + "created_at": "2015-02-10T23:50:45.000-06:00", + "custom_identifier": "Mikey", + "customer_type": "Personal", + "email": "mikesmith@test.com", + "financial_transactions": [], + "home_phone": "(204) 555 5555", + "id": 1, + "identifier": "Mikey", + "institution_number": "", + "name": "Mike Smith", + "phone": "(204) 555 4444", + "routing_number": "111111111", + "transaction_schedules": [], + "transit_number": "", + "updated_at": "2015-02-10T23:50:45.000-06:00" + } + */ + $client = (\App\Factory\ClientFactory::create($this->company_gateway->company_id, $this->company_gateway->user_id))->fill( + [ + 'address1' => $customer->address['address_1'] ?? '', + 'address2' =>$customer->address['address_2'] ?? '', + 'city' => $customer->address['city'] ?? '', + 'postal_code' => $customer->address['postal_code'] ?? '', + 'state' => $customer->address['province_code'] ?? '', + 'country_id' => empty($customer->transit_number) ? 840 : 124, + 'routing_id' => empty(($r = $customer->routing_number))? null : $r, + "number" => str_pad($customer->account_number,3,'0',STR_PAD_LEFT) + ] + ); + $client->saveQuietly(); + $contact = (\App\Factory\ClientContactFactory::create($company_id, $this->company_gateway->user_id))->fill([ + "first_name" => substr($customer->name, 0, stripos($customer->name, " ")), + "last_name" => substr($customer->name, stripos($customer->name, " ")), + "email" => $customer->email, + "phone" => $customer->phone, + "is_primary" => true, + "send_email" => true, + ]); + $client->contacts()->saveMany([$contact]); + $contact = $client->contacts()->first(); + $this->client = $client; + $customer = (new Customer((array) $customer))->additional(['id' => $customer->id, 'custom_identifier' => $customer->custom_identifier ?? $contact->id ] ); + $this->findOrCreateCustomer($customer->additional + $customer->jsonSerialize()); + }); + } catch (\Throwable $th) { + $data = [ + 'transaction_reference' => null, + 'transaction_response' => $th->getMessage(), + 'success' => false, + 'description' => $th->getMessage(), + 'code' =>(int) $th->getCode() + ]; + SystemLogger::dispatch(['server_response' => $th->getMessage(), 'data' => $data], SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_FAILURE, SystemLog::TYPE_ROTESSA , $this->company_gateway->client , $this->company_gateway->company); + + throw $th; + } + + return true; + } + + public function findOrCreateCustomer(array $data) + { + $result = null; + try { + + $existing = ClientGatewayToken::query() + ->where('company_gateway_id', $this->company_gateway->id) + ->where('client_id', $this->client->id) + ->orWhere(function (Builder $query) use ($data) { + $query->where('token', encrypt(join(".", Arr::only($data, 'id','custom_identifier'))) ) + ->where('gateway_customer_reference', Arr::only($data,'id')); + }) + ->exists(); + if ($existing) return true; + else if(!Arr::has($data,'id')) { + $result = $this->gateway->authorize($data)->send(); + if (!$result->isSuccessful()) throw new \Exception($result->getMessage(), (int) $result->getCode()); + + $customer = new Customer($result->getData()); + $data = array_filter($customer->resolve()); + } + + // $payment_method_id = Arr::has($data,'address.postal_code') && ((int) $data['address']['postal_code'])? GatewayType::BANK_TRANSFER: GatewayType::ACSS; + // TODO: Check/ Validate postal code between USA vs CAN + $payment_method_id = GatewayType::ACSS; + $gateway_token = $this->storeGatewayToken( [ + 'payment_meta' => $data + ['brand' => 'Rotessa', 'last4' => $data['bank_name'], 'type' => $data['bank_account_type'] ], + 'token' => encrypt(join(".", Arr::only($data, 'id','custom_identifier'))), + 'payment_method_id' => $payment_method_id , + ], ['gateway_customer_reference' => + $data['id'] + , 'routing_number' => Arr::has($data,'routing_number') ? $data['routing_number'] : $data['transit_number'] ]); + + return $data['id']; + + throw new \Exception($result->getMessage(), (int) $result->getCode()); + + } catch (\Throwable $th) { + $data = [ + 'transaction_reference' => null, + 'transaction_response' => $th->getMessage(), + 'success' => false, + 'description' => $th->getMessage(), + 'code' =>(int) $th->getCode() + ]; + + SystemLogger::dispatch(['server_response' => is_null($result) ? '' : $result->getMessage(), 'data' => $data], SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_FAILURE, 880 , $this->client, $this->company_gateway->company); + + throw $th; + } + } +} diff --git a/app/Providers/ComposerServiceProvider.php b/app/Providers/ComposerServiceProvider.php index d548a3d997ce..9d8d5a94b0bc 100644 --- a/app/Providers/ComposerServiceProvider.php +++ b/app/Providers/ComposerServiceProvider.php @@ -13,6 +13,9 @@ namespace App\Providers; use App\Http\ViewComposers\PortalComposer; use Illuminate\Support\ServiceProvider; +use Illuminate\Support\Facades\Blade; +use App\DataProviders\CAProvinces; +use App\DataProviders\USStates; class ComposerServiceProvider extends ServiceProvider { @@ -24,6 +27,19 @@ class ComposerServiceProvider extends ServiceProvider public function boot() { view()->composer('portal.*', PortalComposer::class); + + view()->composer(['*.rotessa.components.address','*.rotessa.components.banks.US.bank','*.rotessa.components.dropdowns.country.US'], function ($view) { + $states = USStates::get(); + $view->with('states', $states); + }); + + // CAProvinces View Composer + view()->composer(['*.rotessa.components.address','*.rotessa.components.banks.CA.bank','*.rotessa.components.dropdowns.country.CA'], function ($view) { + $provinces = CAProvinces::get(); + $view->with('provinces', $provinces); + }); + + Blade::componentNamespace('App\\Http\\ViewComposers\\Components\\Rotessa', 'rotessa'); } /** @@ -34,5 +50,6 @@ class ComposerServiceProvider extends ServiceProvider public function register() { // + } } diff --git a/app/Providers/RotessaServiceProvider.php b/app/Providers/RotessaServiceProvider.php new file mode 100644 index 000000000000..284bca9c708f --- /dev/null +++ b/app/Providers/RotessaServiceProvider.php @@ -0,0 +1,31 @@ +registerComponent(); + } + + /** + * Register views. + */ + public function registerComponent(): void + { + Blade::componentNamespace('App\\Http\\ViewComposers\\Components\\Rotessa', $this->moduleNameLower); + } +} diff --git a/composer.json b/composer.json index d34361cbf487..0ee5593b8e1e 100644 --- a/composer.json +++ b/composer.json @@ -130,7 +130,8 @@ "app/Helpers/TranslationHelper.php", "app/Helpers/Generic.php", "app/Helpers/ClientPortal.php" - ] + ], + "classmap": ["app/PaymentDrivers/Rotessa/vendor/karneaud/omnipay-rotessa/src/Omnipay/Rotessa/"] }, "autoload-dev": { "psr-4": { diff --git a/config/app.php b/config/app.php index 993f95f210c3..bf44219e3f38 100644 --- a/config/app.php +++ b/config/app.php @@ -200,7 +200,7 @@ return [ App\Providers\MultiDBProvider::class, App\Providers\ClientPortalServiceProvider::class, App\Providers\NinjaTranslationServiceProvider::class, - App\Providers\StaticServiceProvider::class, + App\Providers\StaticServiceProvider::class ], /* diff --git a/database/migrations/2024_06_11_231143_add_rotessa_gateway.php b/database/migrations/2024_06_11_231143_add_rotessa_gateway.php new file mode 100644 index 000000000000..7aed00572e28 --- /dev/null +++ b/database/migrations/2024_06_11_231143_add_rotessa_gateway.php @@ -0,0 +1,37 @@ +apiKey = ''; + $configuration->testMode = true; + + $gateway = new Gateway(); + $gateway->id = 63; + $gateway->name = 'Rotessa'; + $gateway->key = '91be24c7b792230bced33e930ac61676'; + $gateway->provider = 'Rotessa'; + $gateway->is_offsite = true; + $gateway->fields = \json_encode($configuration); + $gateway->visible = 1; + $gateway->site_url = "https://rotessa.com"; + $gateway->default_gateway_type_id = 2; + $gateway->save(); + } + } +}; diff --git a/database/seeders/PaymentLibrariesSeeder.php b/database/seeders/PaymentLibrariesSeeder.php index fc5c50d2bd67..d85f47b782b3 100644 --- a/database/seeders/PaymentLibrariesSeeder.php +++ b/database/seeders/PaymentLibrariesSeeder.php @@ -88,6 +88,7 @@ class PaymentLibrariesSeeder extends Seeder ['id' => 60, 'name' => 'PayPal REST', 'provider' => 'PayPal_Rest', 'key' => '80af24a6a691230bbec33e930ab40665', 'fields' => '{"clientId":"","secret":"","signature":"","testMode":false}'], ['id' => 61, 'name' => 'PayPal Platform', 'provider' => 'PayPal_PPCP', 'key' => '80af24a6a691230bbec33e930ab40666', 'fields' => '{"testMode":false}'], ['id' => 62, 'name' => 'BTCPay', 'provider' => 'BTCPay', 'key' => 'vpyfbmdrkqcicpkjqdusgjfluebftuva', 'fields' => '{"btcpayUrl":"", "apiKey":"", "storeId":"", "webhookSecret":""}'], + ['id' => 63, 'name' => 'Rotessa', 'is_offsite' => false, 'sort_order' => 22, 'provider' => 'Rotessa', 'key' => '91be24c7b792230bced33e930ac61676', 'fields' => '{"apiKey":"", "testMode":""}'], ]; foreach ($gateways as $gateway) { @@ -104,7 +105,7 @@ class PaymentLibrariesSeeder extends Seeder Gateway::query()->update(['visible' => 0]); - Gateway::whereIn('id', [1, 3, 7, 11, 15, 20, 39, 46, 55, 50, 57, 52, 58, 59, 60, 62])->update(['visible' => 1]); + Gateway::whereIn('id', [1, 3, 7, 11, 15, 20, 39, 46, 55, 50, 57, 52, 58, 59, 60, 62, 63])->update(['visible' => 1]); if (Ninja::isHosted()) { Gateway::whereIn('id', [20, 49])->update(['visible' => 0]); diff --git a/lang/ca/texts.php b/lang/ca/texts.php index 182be60bc3f3..cdfde3357540 100644 --- a/lang/ca/texts.php +++ b/lang/ca/texts.php @@ -5300,7 +5300,7 @@ $lang = array( 'merge_to_pdf' => 'Merge to PDF', 'latest_requires_php_version' => 'Note: the latest version requires PHP :version', 'auto_expand_product_table_notes' => 'Automatically expand products table notes', - 'auto_expand_product_table_notes_help' => 'Automatically expands the notes section within the products table to display more lines.', + 'auto_expand_product_table_notes_help' => 'Automatically expands the notes section within the products table to display more lines.' ); return $lang; diff --git a/lang/en/texts.php b/lang/en/texts.php index f00d22cdcf4c..eeab2f9c1673 100644 --- a/lang/en/texts.php +++ b/lang/en/texts.php @@ -5301,6 +5301,15 @@ $lang = array( 'latest_requires_php_version' => 'Note: the latest version requires PHP :version', 'auto_expand_product_table_notes' => 'Automatically expand products table notes', 'auto_expand_product_table_notes_help' => 'Automatically expands the notes section within the products table to display more lines.', + 'institution_number' => 'Institution Number', + 'transit_number' => 'Transit Number', + 'personal' => 'Personal', + 'address_information' => 'Address Information', + 'enter_the_information_for_the_bank_account' => 'Enter the Information for the Bank Account', + 'account_holder_information' => 'Account Holder Information', + 'enter_information_for_the_account_holder' => 'Enter Information for the Account Holder', + 'customer_type' => 'Customer Type', + 'process_date' => 'Process Date' ); return $lang; diff --git a/lang/fr_CA/texts.php b/lang/fr_CA/texts.php index a01d6cf20ce9..08e065a4a226 100644 --- a/lang/fr_CA/texts.php +++ b/lang/fr_CA/texts.php @@ -5298,7 +5298,7 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette 'latest_requires_php_version' => 'Note: La dernière version requiert PHP :version', 'auto_expand_product_table_notes' => 'Développer automatiquement les notes du tableau de produits', 'auto_expand_product_table_notes_help' => ' -Développe automatiquement la section des notes dans le tableau de produits pour afficher plus de lignes.', +Développe automatiquement la section des notes dans le tableau de produits pour afficher plus de lignes.' ); return $lang; diff --git a/public/build/assets/app-02bc3b96.css b/public/build/assets/app-02bc3b96.css new file mode 100644 index 000000000000..8c1544d1c4e3 --- /dev/null +++ b/public/build/assets/app-02bc3b96.css @@ -0,0 +1 @@ +*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Open Sans,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}[type=text],input:where(:not([type])),[type=email],[type=url],[type=password],[type=number],[type=date],[type=datetime-local],[type=month],[type=search],[type=tel],[type=time],[type=week],[multiple],textarea,select{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#6b7280;border-width:1px;border-radius:0;padding:.5rem .75rem;font-size:1rem;line-height:1.5rem;--tw-shadow: 0 0 #0000}[type=text]:focus,input:where(:not([type])):focus,[type=email]:focus,[type=url]:focus,[type=password]:focus,[type=number]:focus,[type=date]:focus,[type=datetime-local]:focus,[type=month]:focus,[type=search]:focus,[type=tel]:focus,[type=time]:focus,[type=week]:focus,[multiple]:focus,textarea:focus,select:focus{outline:2px solid transparent;outline-offset:2px;--tw-ring-inset: var(--tw-empty, );--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: #2563eb;--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);border-color:#2563eb}input::-moz-placeholder,textarea::-moz-placeholder{color:#6b7280;opacity:1}input::placeholder,textarea::placeholder{color:#6b7280;opacity:1}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-date-and-time-value{min-height:1.5em;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit,::-webkit-datetime-edit-year-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute-field,::-webkit-datetime-edit-second-field,::-webkit-datetime-edit-millisecond-field,::-webkit-datetime-edit-meridiem-field{padding-top:0;padding-bottom:0}select{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");background-position:right .5rem center;background-repeat:no-repeat;background-size:1.5em 1.5em;padding-right:2.5rem;-webkit-print-color-adjust:exact;print-color-adjust:exact}[multiple],[size]:where(select:not([size="1"])){background-image:initial;background-position:initial;background-repeat:unset;background-size:initial;padding-right:.75rem;-webkit-print-color-adjust:unset;print-color-adjust:unset}[type=checkbox],[type=radio]{-webkit-appearance:none;-moz-appearance:none;appearance:none;padding:0;-webkit-print-color-adjust:exact;print-color-adjust:exact;display:inline-block;vertical-align:middle;background-origin:border-box;-webkit-user-select:none;-moz-user-select:none;user-select:none;flex-shrink:0;height:1rem;width:1rem;color:#2563eb;background-color:#fff;border-color:#6b7280;border-width:1px;--tw-shadow: 0 0 #0000}[type=checkbox]{border-radius:0}[type=radio]{border-radius:100%}[type=checkbox]:focus,[type=radio]:focus{outline:2px solid transparent;outline-offset:2px;--tw-ring-inset: var(--tw-empty, );--tw-ring-offset-width: 2px;--tw-ring-offset-color: #fff;--tw-ring-color: #2563eb;--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}[type=checkbox]:checked,[type=radio]:checked{border-color:transparent;background-color:currentColor;background-size:100% 100%;background-position:center;background-repeat:no-repeat}[type=checkbox]:checked{background-image:url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e")}@media (forced-colors: active){[type=checkbox]:checked{-webkit-appearance:auto;-moz-appearance:auto;appearance:auto}}[type=radio]:checked{background-image:url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='3'/%3e%3c/svg%3e")}@media (forced-colors: active){[type=radio]:checked{-webkit-appearance:auto;-moz-appearance:auto;appearance:auto}}[type=checkbox]:checked:hover,[type=checkbox]:checked:focus,[type=radio]:checked:hover,[type=radio]:checked:focus{border-color:transparent;background-color:currentColor}[type=checkbox]:indeterminate{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3e%3cpath stroke='white' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3e%3c/svg%3e");border-color:transparent;background-color:currentColor;background-size:100% 100%;background-position:center;background-repeat:no-repeat}@media (forced-colors: active){[type=checkbox]:indeterminate{-webkit-appearance:auto;-moz-appearance:auto;appearance:auto}}[type=checkbox]:indeterminate:hover,[type=checkbox]:indeterminate:focus{border-color:transparent;background-color:currentColor}[type=file]{background:unset;border-color:inherit;border-width:0;border-radius:0;padding:0;font-size:unset;line-height:inherit}[type=file]:focus{outline:1px solid ButtonText;outline:1px auto -webkit-focus-ring-color}*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.container{width:100%}@media (min-width: 640px){.container{max-width:640px}}@media (min-width: 768px){.container{max-width:768px}}@media (min-width: 1024px){.container{max-width:1024px}}@media (min-width: 1280px){.container{max-width:1280px}}@media (min-width: 1536px){.container{max-width:1536px}}.form-input,.form-textarea,.form-select,.form-multiselect{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#6b7280;border-width:1px;border-radius:0;padding:.5rem .75rem;font-size:1rem;line-height:1.5rem;--tw-shadow: 0 0 #0000}.form-input:focus,.form-textarea:focus,.form-select:focus,.form-multiselect:focus{outline:2px solid transparent;outline-offset:2px;--tw-ring-inset: var(--tw-empty, );--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: #2563eb;--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);border-color:#2563eb}.form-select{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");background-position:right .5rem center;background-repeat:no-repeat;background-size:1.5em 1.5em;padding-right:2.5rem;-webkit-print-color-adjust:exact;print-color-adjust:exact}.form-select:where([size]:not([size="1"])){background-image:initial;background-position:initial;background-repeat:unset;background-size:initial;padding-right:.75rem;-webkit-print-color-adjust:unset;print-color-adjust:unset}.form-checkbox,.form-radio{-webkit-appearance:none;-moz-appearance:none;appearance:none;padding:0;-webkit-print-color-adjust:exact;print-color-adjust:exact;display:inline-block;vertical-align:middle;background-origin:border-box;-webkit-user-select:none;-moz-user-select:none;user-select:none;flex-shrink:0;height:1rem;width:1rem;color:#2563eb;background-color:#fff;border-color:#6b7280;border-width:1px;--tw-shadow: 0 0 #0000}.form-checkbox{border-radius:0}.form-radio{border-radius:100%}.form-checkbox:focus,.form-radio:focus{outline:2px solid transparent;outline-offset:2px;--tw-ring-inset: var(--tw-empty, );--tw-ring-offset-width: 2px;--tw-ring-offset-color: #fff;--tw-ring-color: #2563eb;--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.form-checkbox:checked,.form-radio:checked{border-color:transparent;background-color:currentColor;background-size:100% 100%;background-position:center;background-repeat:no-repeat}.form-checkbox:checked{background-image:url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e")}@media (forced-colors: active){.form-checkbox:checked{-webkit-appearance:auto;-moz-appearance:auto;appearance:auto}}.form-radio:checked{background-image:url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='3'/%3e%3c/svg%3e")}@media (forced-colors: active){.form-radio:checked{-webkit-appearance:auto;-moz-appearance:auto;appearance:auto}}.form-checkbox:checked:hover,.form-checkbox:checked:focus,.form-radio:checked:hover,.form-radio:checked:focus{border-color:transparent;background-color:currentColor}.form-checkbox:indeterminate{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3e%3cpath stroke='white' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3e%3c/svg%3e");border-color:transparent;background-color:currentColor;background-size:100% 100%;background-position:center;background-repeat:no-repeat}@media (forced-colors: active){.form-checkbox:indeterminate{-webkit-appearance:auto;-moz-appearance:auto;appearance:auto}}.form-checkbox:indeterminate:hover,.form-checkbox:indeterminate:focus{border-color:transparent;background-color:currentColor}.prose{color:var(--tw-prose-body);max-width:65ch}.prose :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em}.prose :where([class~=lead]):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-lead);font-size:1.25em;line-height:1.6;margin-top:1.2em;margin-bottom:1.2em}.prose :where(a):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-links);text-decoration:underline;font-weight:500}.prose :where(strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-bold);font-weight:600}.prose :where(a strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(blockquote strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(thead th strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal;margin-top:1.25em;margin-bottom:1.25em;padding-left:1.625em}.prose :where(ol[type=A]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=A s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=I]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type=I s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type="1"]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal}.prose :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:disc;margin-top:1.25em;margin-bottom:1.25em;padding-left:1.625em}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{font-weight:400;color:var(--tw-prose-counters)}.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{color:var(--tw-prose-bullets)}.prose :where(dt):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;margin-top:1.25em}.prose :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){border-color:var(--tw-prose-hr);border-top-width:1px;margin-top:3em;margin-bottom:3em}.prose :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:500;font-style:italic;color:var(--tw-prose-quotes);border-left-width:.25rem;border-left-color:var(--tw-prose-quote-borders);quotes:"“""”""‘""’";margin-top:1.6em;margin-bottom:1.6em;padding-left:1em}.prose :where(blockquote p:first-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:open-quote}.prose :where(blockquote p:last-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:close-quote}.prose :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:800;font-size:2.25em;margin-top:0;margin-bottom:.8888889em;line-height:1.1111111}.prose :where(h1 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:900;color:inherit}.prose :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:700;font-size:1.5em;margin-top:2em;margin-bottom:1em;line-height:1.3333333}.prose :where(h2 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:800;color:inherit}.prose :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;font-size:1.25em;margin-top:1.6em;margin-bottom:.6em;line-height:1.6}.prose :where(h3 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:700;color:inherit}.prose :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;margin-top:1.5em;margin-bottom:.5em;line-height:1.5}.prose :where(h4 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:700;color:inherit}.prose :where(img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){display:block;margin-top:2em;margin-bottom:2em}.prose :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:500;font-family:inherit;color:var(--tw-prose-kbd);box-shadow:0 0 0 1px rgb(var(--tw-prose-kbd-shadows) / 10%),0 3px 0 rgb(var(--tw-prose-kbd-shadows) / 10%);font-size:.875em;border-radius:.3125rem;padding:.1875em .375em}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-code);font-weight:600;font-size:.875em}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:"`"}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:"`"}.prose :where(a code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(h1 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(h2 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.875em}.prose :where(h3 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.9em}.prose :where(h4 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(blockquote code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(thead th code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-pre-code);background-color:var(--tw-prose-pre-bg);overflow-x:auto;font-weight:400;font-size:.875em;line-height:1.7142857;margin-top:1.7142857em;margin-bottom:1.7142857em;border-radius:.375rem;padding:.8571429em 1.1428571em}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)){background-color:transparent;border-width:0;border-radius:0;padding:0;font-weight:inherit;color:inherit;font-size:inherit;font-family:inherit;line-height:inherit}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:none}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:none}.prose :where(table):not(:where([class~=not-prose],[class~=not-prose] *)){width:100%;table-layout:auto;text-align:left;margin-top:2em;margin-bottom:2em;font-size:.875em;line-height:1.7142857}.prose :where(thead):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:1px;border-bottom-color:var(--tw-prose-th-borders)}.prose :where(thead th):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;vertical-align:bottom;padding-right:.5714286em;padding-bottom:.5714286em;padding-left:.5714286em}.prose :where(tbody tr):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:1px;border-bottom-color:var(--tw-prose-td-borders)}.prose :where(tbody tr:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:0}.prose :where(tbody td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:baseline}.prose :where(tfoot):not(:where([class~=not-prose],[class~=not-prose] *)){border-top-width:1px;border-top-color:var(--tw-prose-th-borders)}.prose :where(tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:top}.prose :where(figure>*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose :where(figcaption):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-captions);font-size:.875em;line-height:1.4285714;margin-top:.8571429em}.prose{--tw-prose-body: #374151;--tw-prose-headings: #111827;--tw-prose-lead: #4b5563;--tw-prose-links: #111827;--tw-prose-bold: #111827;--tw-prose-counters: #6b7280;--tw-prose-bullets: #d1d5db;--tw-prose-hr: #e5e7eb;--tw-prose-quotes: #111827;--tw-prose-quote-borders: #e5e7eb;--tw-prose-captions: #6b7280;--tw-prose-kbd: #111827;--tw-prose-kbd-shadows: 17 24 39;--tw-prose-code: #111827;--tw-prose-pre-code: #e5e7eb;--tw-prose-pre-bg: #1f2937;--tw-prose-th-borders: #d1d5db;--tw-prose-td-borders: #e5e7eb;--tw-prose-invert-body: #d1d5db;--tw-prose-invert-headings: #fff;--tw-prose-invert-lead: #9ca3af;--tw-prose-invert-links: #fff;--tw-prose-invert-bold: #fff;--tw-prose-invert-counters: #9ca3af;--tw-prose-invert-bullets: #4b5563;--tw-prose-invert-hr: #374151;--tw-prose-invert-quotes: #f3f4f6;--tw-prose-invert-quote-borders: #374151;--tw-prose-invert-captions: #9ca3af;--tw-prose-invert-kbd: #fff;--tw-prose-invert-kbd-shadows: 255 255 255;--tw-prose-invert-code: #fff;--tw-prose-invert-pre-code: #d1d5db;--tw-prose-invert-pre-bg: rgb(0 0 0 / 50%);--tw-prose-invert-th-borders: #4b5563;--tw-prose-invert-td-borders: #374151;font-size:1rem;line-height:1.75}.prose :where(picture>img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose :where(video):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;margin-bottom:.5em}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-left:.375em}.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-left:.375em}.prose :where(.prose>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.prose :where(.prose>ul>li>*:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ul>li>*:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(.prose>ol>li>*:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ol>li>*:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.prose :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em}.prose :where(dd):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;padding-left:1.625em}.prose :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(thead th:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-left:0}.prose :where(thead th:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-right:0}.prose :where(tbody td,tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){padding:.5714286em}.prose :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-left:0}.prose :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-right:0}.prose :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(.prose>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(.prose>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}.button{border-radius:.25rem;padding:.75rem 1rem;font-size:.875rem;line-height:1rem;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1)}button:disabled{cursor:not-allowed;opacity:.5}.button-primary{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.button-primary:hover{font-weight:600}.button-block{display:block;width:100%}.button-danger{--tw-bg-opacity: 1;background-color:rgb(239 68 68 / var(--tw-bg-opacity));--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.button-danger:hover{--tw-bg-opacity: 1;background-color:rgb(220 38 38 / var(--tw-bg-opacity))}.button-secondary{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity))}.button-secondary:hover{--tw-bg-opacity: 1;background-color:rgb(229 231 235 / var(--tw-bg-opacity))}.button-link{--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity))}.button-link:hover{--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity));text-decoration-line:underline}.button-link:focus{text-decoration-line:underline;outline:2px solid transparent;outline-offset:2px}.validation{margin-top:.5rem;margin-bottom:.25rem;border-left-width:2px;--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity));padding:.25rem .75rem}.validation-fail{--tw-border-opacity: 1;border-color:rgb(239 68 68 / var(--tw-border-opacity));font-size:.875rem;line-height:1.25rem;--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity))}.validation-pass{--tw-border-opacity: 1;border-color:rgb(16 185 129 / var(--tw-border-opacity));font-size:.875rem;line-height:1.25rem;--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity))}.input{margin-top:.5rem;align-items:center;border-radius:.25rem;border-width:1px;--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity));padding:.5rem 1rem;font-size:.875rem;line-height:1.25rem}.input:focus{--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity));outline:2px solid transparent;outline-offset:2px}.input-label{font-size:.875rem;line-height:1.25rem;--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity))}.input-slim{padding-top:.5rem;padding-bottom:.5rem}.form-checkbox{cursor:pointer;border-radius:.25rem;border-width:1px;--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity))}.form-select{border-width:1px;--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity))}.alert{margin-top:.5rem;margin-bottom:.25rem;border-left-width:2px;--tw-border-opacity: 1;border-color:rgb(156 163 175 / var(--tw-border-opacity));--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity));padding:.75rem 1rem;font-size:.875rem;line-height:1.25rem}.alert-success{--tw-border-opacity: 1;border-color:rgb(16 185 129 / var(--tw-border-opacity))}.alert-failure{--tw-border-opacity: 1;border-color:rgb(239 68 68 / var(--tw-border-opacity))}.badge{display:inline-flex;align-items:center;border-radius:9999px;padding:.125rem .625rem;font-size:.75rem;font-weight:500;line-height:1rem}.badge-light{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity));--tw-text-opacity: 1;color:rgb(31 41 55 / var(--tw-text-opacity))}.badge-primary{--tw-bg-opacity: 1;background-color:rgb(191 219 254 / var(--tw-bg-opacity));--tw-text-opacity: 1;color:rgb(59 130 246 / var(--tw-text-opacity))}.badge-danger{--tw-bg-opacity: 1;background-color:rgb(254 226 226 / var(--tw-bg-opacity));--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity))}.badge-success{--tw-bg-opacity: 1;background-color:rgb(209 250 229 / var(--tw-bg-opacity));--tw-text-opacity: 1;color:rgb(16 185 129 / var(--tw-text-opacity))}.badge-secondary{--tw-bg-opacity: 1;background-color:rgb(31 41 55 / var(--tw-bg-opacity));--tw-text-opacity: 1;color:rgb(229 231 235 / var(--tw-text-opacity))}.badge-warning{--tw-bg-opacity: 1;background-color:rgb(59 130 246 / var(--tw-bg-opacity));--tw-text-opacity: 1;color:rgb(217 119 6 / var(--tw-text-opacity))}.badge-info{--tw-bg-opacity: 1;background-color:rgb(219 234 254 / var(--tw-bg-opacity));--tw-text-opacity: 1;color:rgb(59 130 246 / var(--tw-text-opacity))}@media (min-width: 640px){.dataTables_length{margin-top:1.25rem!important;margin-bottom:1.25rem!important}}@media (min-width: 1024px){.dataTables_length{margin-top:1rem!important;margin-bottom:1rem!important}}.dataTables_length select{margin-left:.5rem!important;margin-right:.5rem!important;--tw-bg-opacity: 1 !important;background-color:rgb(255 255 255 / var(--tw-bg-opacity))!important;margin-top:.5rem;align-items:center;border-radius:.25rem;border-width:1px;--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity));padding:.5rem 1rem;font-size:.875rem;line-height:1.25rem}.dataTables_length select:focus{--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity));outline:2px solid transparent;outline-offset:2px}.dataTables_filter{margin-bottom:1rem}.dataTables_filter input{margin-top:.5rem;align-items:center;border-radius:.25rem;border-width:1px;--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity));padding:.5rem 1rem;font-size:.875rem;line-height:1.25rem}.dataTables_filter input:focus{--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity));outline:2px solid transparent;outline-offset:2px}@media (min-width: 1024px){.dataTables_filter{margin-top:-3rem!important}}.dataTables_paginate{padding-bottom:1.5rem!important;padding-top:.5rem!important}.dataTables_paginate .paginate_button{margin-right:.25rem!important;cursor:pointer!important;border-width:1px!important;--tw-border-opacity: 1 !important;border-color:rgb(209 213 219 / var(--tw-border-opacity))!important;--tw-bg-opacity: 1 !important;background-color:rgb(255 255 255 / var(--tw-bg-opacity))!important;font-weight:500!important;--tw-text-opacity: 1 !important;color:rgb(55 65 81 / var(--tw-text-opacity))!important;border-radius:.25rem;padding:.75rem 1rem;font-size:.875rem;line-height:1rem;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-duration:.15s;transition-timing-function:cubic-bezier(.4,0,.2,1)}.dataTables_paginate .current{--tw-bg-opacity: 1 !important;background-color:rgb(37 99 235 / var(--tw-bg-opacity))!important;--tw-text-opacity: 1 !important;color:rgb(255 255 255 / var(--tw-text-opacity))!important}.dataTables_info{font-size:.875rem!important;line-height:1.25rem!important}.dataTables_empty{padding-top:1rem!important;padding-bottom:1rem!important}.pagination{display:flex!important;align-items:center!important}.pagination .page-link{margin-top:-1px!important;display:inline-flex!important;cursor:pointer!important;align-items:center!important;border-top-width:2px!important;border-color:transparent!important;padding-left:1rem!important;padding-right:1rem!important;padding-top:1rem!important;font-size:.875rem!important;font-weight:500!important;line-height:1.25rem!important;--tw-text-opacity: 1 !important;color:rgb(107 114 128 / var(--tw-text-opacity))!important;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter!important;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter!important;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter!important;transition-duration:.15s!important;transition-timing-function:cubic-bezier(.4,0,.2,1)!important}.pagination .page-link:hover{--tw-border-opacity: 1 !important;border-color:rgb(209 213 219 / var(--tw-border-opacity))!important;--tw-text-opacity: 1 !important;color:rgb(55 65 81 / var(--tw-text-opacity))!important}.pagination .page-link:focus{--tw-border-opacity: 1;border-color:rgb(156 163 175 / var(--tw-border-opacity));--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity));outline:2px solid transparent;outline-offset:2px}.pagination .active>span{--tw-border-opacity: 1 !important;border-color:rgb(37 99 235 / var(--tw-border-opacity))!important;--tw-text-opacity: 1 !important;color:rgb(37 99 235 / var(--tw-text-opacity))!important}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.pointer-events-none{pointer-events:none}.pointer-events-auto{pointer-events:auto}.visible{visibility:visible}.collapse{visibility:collapse}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{top:0;right:0;bottom:0;left:0}.inset-x-0{left:0;right:0}.inset-y-0{top:0;bottom:0}.bottom-0{bottom:0}.left-0{left:0}.left-1{left:.25rem}.right-0{right:0}.top-0{top:0}.top-1{top:.25rem}.z-0{z-index:0}.z-10{z-index:10}.z-30{z-index:30}.z-40{z-index:40}.z-50{z-index:50}.col-auto{grid-column:auto}.col-span-1{grid-column:span 1 / span 1}.col-span-12{grid-column:span 12 / span 12}.col-span-2{grid-column:span 2 / span 2}.col-span-3{grid-column:span 3 / span 3}.col-span-4{grid-column:span 4 / span 4}.col-span-6{grid-column:span 6 / span 6}.col-span-8{grid-column:span 8 / span 8}.float-right{float:right}.m-0{margin:0}.m-auto{margin:auto}.-my-2{margin-top:-.5rem;margin-bottom:-.5rem}.-my-6{margin-top:-1.5rem;margin-bottom:-1.5rem}.mx-2{margin-left:.5rem;margin-right:.5rem}.mx-4{margin-left:1rem;margin-right:1rem}.mx-6{margin-left:1.5rem;margin-right:1.5rem}.mx-\[22px\]{margin-left:22px;margin-right:22px}.mx-\[40px\]{margin-left:40px;margin-right:40px}.mx-\[auto\],.mx-auto{margin-left:auto;margin-right:auto}.my-10{margin-top:2.5rem;margin-bottom:2.5rem}.my-2{margin-top:.5rem;margin-bottom:.5rem}.my-3{margin-top:.75rem;margin-bottom:.75rem}.my-4{margin-top:1rem;margin-bottom:1rem}.my-6{margin-top:1.5rem;margin-bottom:1.5rem}.-ml-1{margin-left:-.25rem}.-ml-4{margin-left:-1rem}.-ml-px{margin-left:-1px}.-mr-1{margin-right:-.25rem}.-mr-14{margin-right:-3.5rem}.-mt-4{margin-top:-1rem}.-mt-6{margin-top:-1.5rem}.mb-0{margin-bottom:0}.mb-1{margin-bottom:.25rem}.mb-1\.5{margin-bottom:.375rem}.mb-10{margin-bottom:2.5rem}.mb-12{margin-bottom:3rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-5{margin-bottom:1.25rem}.mb-6{margin-bottom:1.5rem}.mb-8{margin-bottom:2rem}.mb-\[10px\]{margin-bottom:10px}.mb-\[11px\]{margin-bottom:11px}.mb-\[20px\]{margin-bottom:20px}.mb-\[25px\]{margin-bottom:25px}.mb-\[26px\]{margin-bottom:26px}.mb-\[36px\]{margin-bottom:36px}.mb-\[40px\]{margin-bottom:40px}.mb-\[5px\]{margin-bottom:5px}.ml-0{margin-left:0}.ml-1{margin-left:.25rem}.ml-2{margin-left:.5rem}.ml-3{margin-left:.75rem}.ml-4{margin-left:1rem}.ml-5{margin-left:1.25rem}.ml-\[10px\]{margin-left:10px}.mr-0{margin-right:0}.mr-1{margin-right:.25rem}.mr-2{margin-right:.5rem}.mr-3{margin-right:.75rem}.mr-4{margin-right:1rem}.mr-5{margin-right:1.25rem}.mt-0{margin-top:0}.mt-1{margin-top:.25rem}.mt-10{margin-top:2.5rem}.mt-2{margin-top:.5rem}.mt-20{margin-top:5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-5{margin-top:1.25rem}.mt-6{margin-top:1.5rem}.mt-8{margin-top:2rem}.mt-\[30px\]{margin-top:30px}.mt-\[50px\]{margin-top:50px}.mt-\[auto\]{margin-top:auto}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.contents{display:contents}.hidden{display:none}.h-0{height:0px}.h-10{height:2.5rem}.h-12{height:3rem}.h-14{height:3.5rem}.h-16{height:4rem}.h-24{height:6rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-64{height:16rem}.h-8{height:2rem}.h-\[40px\]{height:40px}.h-auto{height:auto}.h-fit{height:-moz-fit-content;height:fit-content}.h-full{height:100%}.h-screen{height:100vh}.min-h-\[450px\]{min-height:450px}.min-h-screen{min-height:100vh}.w-0{width:0px}.w-1{width:.25rem}.w-1\/2{width:50%}.w-1\/6{width:16.666667%}.w-10{width:2.5rem}.w-12{width:3rem}.w-14{width:3.5rem}.w-16{width:4rem}.w-24{width:6rem}.w-3\/4{width:75%}.w-4{width:1rem}.w-4\/5{width:80%}.w-4\/6{width:66.666667%}.w-48{width:12rem}.w-5{width:1.25rem}.w-5\/6{width:83.333333%}.w-56{width:14rem}.w-6{width:1.5rem}.w-64{width:16rem}.w-8{width:2rem}.w-80{width:20rem}.w-\[100\%\]{width:100%}.w-\[87px\]{width:87px}.w-auto{width:auto}.w-full{width:100%}.w-screen{width:100vw}.min-w-full{min-width:100%}.max-w-2xl{max-width:42rem}.max-w-4xl{max-width:56rem}.max-w-\[212px\]{max-width:212px}.max-w-\[450px\]{max-width:450px}.max-w-\[625px\]{max-width:625px}.max-w-xl{max-width:36rem}.max-w-xs{max-width:20rem}.flex-1{flex:1 1 0%}.flex-shrink{flex-shrink:1}.flex-shrink-0{flex-shrink:0}.shrink{flex-shrink:1}.flex-grow,.grow{flex-grow:1}.grow-0{flex-grow:0}.basis-1\/2{flex-basis:50%}.basis-full{flex-basis:100%}.table-auto{table-layout:auto}.border-collapse{border-collapse:collapse}.origin-top-right{transform-origin:top right}.-translate-x-full{--tw-translate-x: -100%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-0{--tw-translate-x: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-0{--tw-translate-y: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-4{--tw-translate-y: 1rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.scale-100{--tw-scale-x: 1;--tw-scale-y: 1;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.scale-95{--tw-scale-x: .95;--tw-scale-y: .95;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.cursor-pointer{cursor:pointer}.resize{resize:both}.list-none{list-style-type:none}.appearance-none{-webkit-appearance:none;-moz-appearance:none;appearance:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-12{grid-template-columns:repeat(12,minmax(0,1fr))}.grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}.flex-row{flex-direction:row}.flex-col{flex-direction:column}.flex-col-reverse{flex-direction:column-reverse}.flex-wrap{flex-wrap:wrap}.place-content-end{place-content:end}.place-items-center{place-items:center}.content-center{align-content:center}.content-start{align-content:flex-start}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.items-stretch{align-items:stretch}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.justify-stretch{justify-content:stretch}.gap-4{gap:1rem}.gap-5{gap:1.25rem}.gap-6{gap:1.5rem}.gap-8{gap:2rem}.gap-\[13px\]{gap:13px}.gap-\[44px\]{gap:44px}.gap-x-2{-moz-column-gap:.5rem;column-gap:.5rem}.gap-y-\[20px\]{row-gap:20px}.space-x-1>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(.25rem * var(--tw-space-x-reverse));margin-left:calc(.25rem * calc(1 - var(--tw-space-x-reverse)))}.space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(.5rem * var(--tw-space-x-reverse));margin-left:calc(.5rem * calc(1 - var(--tw-space-x-reverse)))}.space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(1rem * var(--tw-space-x-reverse));margin-left:calc(1rem * calc(1 - var(--tw-space-x-reverse)))}.space-y-10>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(2.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(2.5rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.space-y-5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.25rem * var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse: 0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse))}.divide-gray-200>:not([hidden])~:not([hidden]){--tw-divide-opacity: 1;border-color:rgb(229 231 235 / var(--tw-divide-opacity))}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.overflow-y-scroll{overflow-y:scroll}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.overflow-ellipsis{text-overflow:ellipsis}.whitespace-nowrap{white-space:nowrap}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.rounded{border-radius:.25rem}.rounded-\[10px\]{border-radius:10px}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-none{border-radius:0}.rounded-sm{border-radius:.125rem}.rounded-b-lg{border-bottom-right-radius:.5rem;border-bottom-left-radius:.5rem}.rounded-l-md{border-top-left-radius:.375rem;border-bottom-left-radius:.375rem}.rounded-r-md{border-top-right-radius:.375rem;border-bottom-right-radius:.375rem}.rounded-t-lg{border-top-left-radius:.5rem;border-top-right-radius:.5rem}.border{border-width:1px}.border-0{border-width:0px}.border-2{border-width:2px}.border-4{border-width:4px}.border-b{border-bottom-width:1px}.border-b-2{border-bottom-width:2px}.border-l-2{border-left-width:2px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-t-2{border-top-width:2px}.border-t-4{border-top-width:4px}.border-t-\[0px\]{border-top-width:0px}.border-t-\[10px\]{border-top-width:10px}.border-t-\[1px\]{border-top-width:1px}.border-solid{border-style:solid}.border-dashed{border-style:dashed}.border-none{border-style:none}.border-\[\#E5E7EB\]{--tw-border-opacity: 1;border-color:rgb(229 231 235 / var(--tw-border-opacity))}.border-blue-500{--tw-border-opacity: 1;border-color:rgb(59 130 246 / var(--tw-border-opacity))}.border-emerald-500{--tw-border-opacity: 1;border-color:rgb(16 185 129 / var(--tw-border-opacity))}.border-fuchsia-600{--tw-border-opacity: 1;border-color:rgb(192 38 211 / var(--tw-border-opacity))}.border-gray-100{--tw-border-opacity: 1;border-color:rgb(243 244 246 / var(--tw-border-opacity))}.border-gray-200{--tw-border-opacity: 1;border-color:rgb(229 231 235 / var(--tw-border-opacity))}.border-gray-300{--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity))}.border-gray-500{--tw-border-opacity: 1;border-color:rgb(107 114 128 / var(--tw-border-opacity))}.border-gray-600{--tw-border-opacity: 1;border-color:rgb(75 85 99 / var(--tw-border-opacity))}.border-red-300{--tw-border-opacity: 1;border-color:rgb(252 165 165 / var(--tw-border-opacity))}.border-red-400{--tw-border-opacity: 1;border-color:rgb(248 113 113 / var(--tw-border-opacity))}.border-red-900{--tw-border-opacity: 1;border-color:rgb(127 29 29 / var(--tw-border-opacity))}.border-transparent{border-color:transparent}.border-opacity-50{--tw-border-opacity: .5}.bg-\[\#F2F9FE\]{--tw-bg-opacity: 1;background-color:rgb(242 249 254 / var(--tw-bg-opacity))}.bg-blue-50{--tw-bg-opacity: 1;background-color:rgb(239 246 255 / var(--tw-bg-opacity))}.bg-blue-500{--tw-bg-opacity: 1;background-color:rgb(59 130 246 / var(--tw-bg-opacity))}.bg-blue-600{--tw-bg-opacity: 1;background-color:rgb(37 99 235 / var(--tw-bg-opacity))}.bg-blue-700{--tw-bg-opacity: 1;background-color:rgb(29 78 216 / var(--tw-bg-opacity))}.bg-emerald-600{--tw-bg-opacity: 1;background-color:rgb(5 150 105 / var(--tw-bg-opacity))}.bg-gray-100{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity))}.bg-gray-200{--tw-bg-opacity: 1;background-color:rgb(229 231 235 / var(--tw-bg-opacity))}.bg-gray-50{--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity))}.bg-gray-500{--tw-bg-opacity: 1;background-color:rgb(107 114 128 / var(--tw-bg-opacity))}.bg-gray-600{--tw-bg-opacity: 1;background-color:rgb(75 85 99 / var(--tw-bg-opacity))}.bg-red-100{--tw-bg-opacity: 1;background-color:rgb(254 226 226 / var(--tw-bg-opacity))}.bg-red-500{--tw-bg-opacity: 1;background-color:rgb(239 68 68 / var(--tw-bg-opacity))}.bg-transparent{background-color:transparent}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity))}.bg-opacity-100{--tw-bg-opacity: 1}.bg-clip-padding{background-clip:padding-box}.fill-current{fill:currentColor}.object-cover{-o-object-fit:cover;object-fit:cover}.object-scale-down{-o-object-fit:scale-down;object-fit:scale-down}.object-center{-o-object-position:center;object-position:center}.p-1{padding:.25rem}.p-10{padding:2.5rem}.p-2{padding:.5rem}.p-2\.5{padding:.625rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-5{padding:1.25rem}.p-8{padding:2rem}.p-\[12px\]{padding:12px}.p-\[20px\]{padding:20px}.px-0{padding-left:0;padding-right:0}.px-1{padding-left:.25rem;padding-right:.25rem}.px-12{padding-left:3rem;padding-right:3rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.px-\[12px\]{padding-left:12px;padding-right:12px}.px-\[20px\]{padding-left:20px;padding-right:20px}.px-\[22px\]{padding-left:22px;padding-right:22px}.py-0{padding-top:0;padding-bottom:0}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-10{padding-top:2.5rem;padding-bottom:2.5rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-5{padding-top:1.25rem;padding-bottom:1.25rem}.py-6{padding-top:1.5rem;padding-bottom:1.5rem}.py-8{padding-top:2rem;padding-bottom:2rem}.py-\[33px\]{padding-top:33px;padding-bottom:33px}.py-\[36px\]{padding-top:36px;padding-bottom:36px}.py-\[9\.5px\]{padding-top:9.5px;padding-bottom:9.5px}.pb-10{padding-bottom:2.5rem}.pb-2{padding-bottom:.5rem}.pb-20{padding-bottom:5rem}.pb-3{padding-bottom:.75rem}.pb-4{padding-bottom:1rem}.pb-6{padding-bottom:1.5rem}.pb-\[20px\]{padding-bottom:20px}.pb-\[56px\]{padding-bottom:56px}.pb-\[58px\]{padding-bottom:58px}.pl-0{padding-left:0}.pl-1{padding-left:.25rem}.pl-1\.5{padding-left:.375rem}.pl-2{padding-left:.5rem}.pl-3{padding-left:.75rem}.pl-\[18px\]{padding-left:18px}.pr-10{padding-right:2.5rem}.pr-2{padding-right:.5rem}.pr-4{padding-right:1rem}.pr-\[18px\]{padding-right:18px}.pt-0{padding-top:0}.pt-2{padding-top:.5rem}.pt-4{padding-top:1rem}.pt-5{padding-top:1.25rem}.pt-6{padding-top:1.5rem}.pt-\[20px\]{padding-top:20px}.pt-\[29px\]{padding-top:29px}.pt-\[35px\]{padding-top:35px}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.align-middle{vertical-align:middle}.align-bottom{vertical-align:bottom}.font-\[\'Open_Sans\'\]{font-family:Open Sans}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-5xl{font-size:3rem;line-height:1}.text-\[12px\]{font-size:12px}.text-\[14px\]{font-size:14px}.text-\[15px\]{font-size:15px}.text-\[16px\]{font-size:16px}.text-\[22px\]{font-size:22px}.text-\[24px\]{font-size:24px}.text-\[35px\]{font-size:35px}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-\[16px\]{font-weight:16px}.font-bold{font-weight:700}.font-light{font-weight:300}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.lowercase{text-transform:lowercase}.capitalize{text-transform:capitalize}.italic{font-style:italic}.leading-4{line-height:1rem}.leading-5{line-height:1.25rem}.leading-6{line-height:1.5rem}.leading-9{line-height:2.25rem}.leading-\[1\.2rem\]{line-height:1.2rem}.leading-\[1\.35em\]{line-height:1.35em}.leading-\[1\.36em\]{line-height:1.36em}.leading-\[1\.375em\]{line-height:1.375em}.leading-\[1\.3em\]{line-height:1.3em}.leading-\[1\.5em\]{line-height:1.5em}.leading-\[1\.75em\]{line-height:1.75em}.leading-normal{line-height:1.5}.leading-tight{line-height:1.25}.tracking-wide{letter-spacing:.025em}.tracking-wider{letter-spacing:.05em}.text-\[\#212529\]{--tw-text-opacity: 1;color:rgb(33 37 41 / var(--tw-text-opacity))}.text-\[\#6C727F\]{--tw-text-opacity: 1;color:rgb(108 114 127 / var(--tw-text-opacity))}.text-black{--tw-text-opacity: 1;color:rgb(0 0 0 / var(--tw-text-opacity))}.text-blue-500{--tw-text-opacity: 1;color:rgb(59 130 246 / var(--tw-text-opacity))}.text-blue-600{--tw-text-opacity: 1;color:rgb(37 99 235 / var(--tw-text-opacity))}.text-blue-700{--tw-text-opacity: 1;color:rgb(29 78 216 / var(--tw-text-opacity))}.text-emerald-600{--tw-text-opacity: 1;color:rgb(5 150 105 / var(--tw-text-opacity))}.text-gray-300{--tw-text-opacity: 1;color:rgb(209 213 219 / var(--tw-text-opacity))}.text-gray-400{--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity))}.text-gray-500{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity))}.text-gray-600{--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity))}.text-gray-700{--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity))}.text-gray-800{--tw-text-opacity: 1;color:rgb(31 41 55 / var(--tw-text-opacity))}.text-gray-900{--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity))}.text-indigo-600{--tw-text-opacity: 1;color:rgb(79 70 229 / var(--tw-text-opacity))}.text-red-400{--tw-text-opacity: 1;color:rgb(248 113 113 / var(--tw-text-opacity))}.text-red-500{--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity))}.text-red-600{--tw-text-opacity: 1;color:rgb(220 38 38 / var(--tw-text-opacity))}.text-red-700{--tw-text-opacity: 1;color:rgb(185 28 28 / var(--tw-text-opacity))}.text-red-900{--tw-text-opacity: 1;color:rgb(127 29 29 / var(--tw-text-opacity))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.underline{text-decoration-line:underline}.line-through{text-decoration-line:line-through}.no-underline{text-decoration-line:none}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.opacity-0{opacity:0}.opacity-100{opacity:1}.opacity-25{opacity:.25}.opacity-75{opacity:.75}.shadow{--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / .1), 0 1px 2px -1px rgb(0 0 0 / .1);--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-lg{--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-xl{--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.outline-none{outline:2px solid transparent;outline-offset:2px}.outline{outline-style:solid}.ring-1{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-black{--tw-ring-opacity: 1;--tw-ring-color: rgb(0 0 0 / var(--tw-ring-opacity))}.ring-opacity-5{--tw-ring-opacity: .05}.grayscale{--tw-grayscale: grayscale(100%);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.invert{--tw-invert: invert(100%);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-100{transition-duration:.1s}.duration-1000{transition-duration:1s}.duration-150{transition-duration:.15s}.duration-200{transition-duration:.2s}.duration-300{transition-duration:.3s}.duration-75{transition-duration:75ms}.ease-in{transition-timing-function:cubic-bezier(.4,0,1,1)}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.ease-linear{transition-timing-function:linear}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}.placeholder\:text-gray-500::-moz-placeholder{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity))}.placeholder\:text-gray-500::placeholder{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity))}.after\:absolute:after{content:var(--tw-content);position:absolute}.after\:left-\[8px\]:after{content:var(--tw-content);left:8px}.after\:top-\[5px\]:after{content:var(--tw-content);top:5px}.after\:h-\[30px\]:after{content:var(--tw-content);height:30px}.after\:w-\[30px\]:after{content:var(--tw-content);width:30px}.after\:rounded-full:after{content:var(--tw-content);border-radius:9999px}.after\:bg-white:after{content:var(--tw-content);--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity))}.after\:transition-all:after{content:var(--tw-content);transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.after\:content-\[\'\'\]:after{--tw-content: "";content:var(--tw-content)}.focus-within\:z-10:focus-within{z-index:10}.hover\:list-disc:hover{list-style-type:disc}.hover\:border-blue-600:hover{--tw-border-opacity: 1;border-color:rgb(37 99 235 / var(--tw-border-opacity))}.hover\:border-gray-600:hover{--tw-border-opacity: 1;border-color:rgb(75 85 99 / var(--tw-border-opacity))}.hover\:border-gray-800:hover{--tw-border-opacity: 1;border-color:rgb(31 41 55 / var(--tw-border-opacity))}.hover\:border-transparent:hover{border-color:transparent}.hover\:bg-blue-500:hover{--tw-bg-opacity: 1;background-color:rgb(59 130 246 / var(--tw-bg-opacity))}.hover\:bg-blue-600:hover{--tw-bg-opacity: 1;background-color:rgb(37 99 235 / var(--tw-bg-opacity))}.hover\:bg-gray-100:hover{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity))}.hover\:bg-gray-200:hover{--tw-bg-opacity: 1;background-color:rgb(229 231 235 / var(--tw-bg-opacity))}.hover\:bg-red-900:hover{--tw-bg-opacity: 1;background-color:rgb(127 29 29 / var(--tw-bg-opacity))}.hover\:font-semibold:hover{font-weight:600}.hover\:text-blue-600:hover{--tw-text-opacity: 1;color:rgb(37 99 235 / var(--tw-text-opacity))}.hover\:text-gray-300:hover{--tw-text-opacity: 1;color:rgb(209 213 219 / var(--tw-text-opacity))}.hover\:text-gray-500:hover{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity))}.hover\:text-gray-600:hover{--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity))}.hover\:text-gray-700:hover{--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity))}.hover\:text-gray-800:hover{--tw-text-opacity: 1;color:rgb(31 41 55 / var(--tw-text-opacity))}.hover\:text-gray-900:hover{--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity))}.hover\:text-indigo-900:hover{--tw-text-opacity: 1;color:rgb(49 46 129 / var(--tw-text-opacity))}.hover\:text-red-500:hover{--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity))}.hover\:text-white:hover{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-80:hover{opacity:.8}.hover\:shadow-2xl:hover{--tw-shadow: 0 25px 50px -12px rgb(0 0 0 / .25);--tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.hover\:shadow-lg:hover{--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.focus\:border-blue-300:focus{--tw-border-opacity: 1;border-color:rgb(147 197 253 / var(--tw-border-opacity))}.focus\:border-blue-500:focus{--tw-border-opacity: 1;border-color:rgb(59 130 246 / var(--tw-border-opacity))}.focus\:border-fuchsia-300:focus{--tw-border-opacity: 1;border-color:rgb(240 171 252 / var(--tw-border-opacity))}.focus\:border-indigo-500:focus{--tw-border-opacity: 1;border-color:rgb(99 102 241 / var(--tw-border-opacity))}.focus\:border-red-500:focus{--tw-border-opacity: 1;border-color:rgb(239 68 68 / var(--tw-border-opacity))}.focus\:bg-gray-100:focus{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity))}.focus\:bg-gray-600:focus{--tw-bg-opacity: 1;background-color:rgb(75 85 99 / var(--tw-bg-opacity))}.focus\:bg-white:focus{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity))}.focus\:font-semibold:focus{font-weight:600}.focus\:text-gray-500:focus{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity))}.focus\:text-gray-600:focus{--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity))}.focus\:text-gray-900:focus{--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity))}.focus\:underline:focus{text-decoration-line:underline}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-1:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-blue-500:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(59 130 246 / var(--tw-ring-opacity))}.focus\:ring-gray-500:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(107 114 128 / var(--tw-ring-opacity))}.focus\:ring-indigo-500:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(99 102 241 / var(--tw-ring-opacity))}.focus\:ring-indigo-600:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(79 70 229 / var(--tw-ring-opacity))}.focus\:ring-red-500:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(239 68 68 / var(--tw-ring-opacity))}.focus\:ring-opacity-50:focus{--tw-ring-opacity: .5}.active\:bg-gray-50:active{--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity))}.active\:text-gray-800:active{--tw-text-opacity: 1;color:rgb(31 41 55 / var(--tw-text-opacity))}.active\:outline-none:active{outline:2px solid transparent;outline-offset:2px}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:bg-gray-50:disabled{--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity))}.disabled\:opacity-75:disabled{opacity:.75}.group:hover .group-hover\:border-transparent{border-color:transparent}.group:hover .group-hover\:text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.peer:checked~.peer-checked\:text-black{--tw-text-opacity: 1;color:rgb(0 0 0 / var(--tw-text-opacity))}.peer:checked~.peer-checked\:after\:translate-x-\[140\%\]:after{content:var(--tw-content);--tw-translate-x: 140%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.peer:focus~.peer-focus\:outline-none{outline:2px solid transparent;outline-offset:2px}@media (min-width: 640px){.sm\:inset-0{top:0;right:0;bottom:0;left:0}.sm\:col-span-2{grid-column:span 2 / span 2}.sm\:col-span-3{grid-column:span 3 / span 3}.sm\:col-span-4{grid-column:span 4 / span 4}.sm\:col-span-6{grid-column:span 6 / span 6}.sm\:-mx-6{margin-left:-1.5rem;margin-right:-1.5rem}.sm\:mx-0{margin-left:0;margin-right:0}.sm\:my-8{margin-top:2rem;margin-bottom:2rem}.sm\:ml-3{margin-left:.75rem}.sm\:ml-4{margin-left:1rem}.sm\:ml-6{margin-left:1.5rem}.sm\:mt-0{margin-top:0}.sm\:mt-4{margin-top:1rem}.sm\:mt-6{margin-top:1.5rem}.sm\:block{display:block}.sm\:inline-block{display:inline-block}.sm\:inline{display:inline}.sm\:flex{display:flex}.sm\:grid{display:grid}.sm\:hidden{display:none}.sm\:h-10{height:2.5rem}.sm\:h-screen{height:100vh}.sm\:w-10{width:2.5rem}.sm\:w-auto{width:auto}.sm\:w-full{width:100%}.sm\:max-w-lg{max-width:32rem}.sm\:max-w-sm{max-width:24rem}.sm\:flex-shrink-0{flex-shrink:0}.sm\:translate-y-0{--tw-translate-y: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.sm\:scale-100{--tw-scale-x: 1;--tw-scale-y: 1;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.sm\:scale-95{--tw-scale-x: .95;--tw-scale-y: .95;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.sm\:flex-row-reverse{flex-direction:row-reverse}.sm\:flex-nowrap{flex-wrap:nowrap}.sm\:items-start{align-items:flex-start}.sm\:items-center{align-items:center}.sm\:justify-center{justify-content:center}.sm\:justify-between{justify-content:space-between}.sm\:gap-4{gap:1rem}.sm\:rounded-lg{border-radius:.5rem}.sm\:p-0{padding:0}.sm\:p-6{padding:1.5rem}.sm\:px-0{padding-left:0;padding-right:0}.sm\:px-6{padding-left:1.5rem;padding-right:1.5rem}.sm\:text-left{text-align:left}.sm\:align-middle{vertical-align:middle}.sm\:text-sm{font-size:.875rem;line-height:1.25rem}}@media (min-width: 768px){.md\:col-span-1{grid-column:span 1 / span 1}.md\:col-span-2{grid-column:span 2 / span 2}.md\:col-span-4{grid-column:span 4 / span 4}.md\:col-span-5{grid-column:span 5 / span 5}.md\:col-span-6{grid-column:span 6 / span 6}.md\:col-start-2{grid-column-start:2}.md\:col-start-4{grid-column-start:4}.md\:mx-0,.md\:mx-\[0\]{margin-left:0;margin-right:0}.md\:-mr-1{margin-right:-.25rem}.md\:mb-6{margin-bottom:1.5rem}.md\:mb-\[46px\]{margin-bottom:46px}.md\:ml-2{margin-left:.5rem}.md\:ml-6{margin-left:1.5rem}.md\:mr-0{margin-right:0}.md\:mr-2{margin-right:.5rem}.md\:mt-0{margin-top:0}.md\:mt-10{margin-top:2.5rem}.md\:mt-5{margin-top:1.25rem}.md\:block{display:block}.md\:flex{display:flex}.md\:grid{display:grid}.md\:hidden{display:none}.md\:min-h-\[411px\]{min-height:411px}.md\:w-1\/2{width:50%}.md\:w-1\/3{width:33.333333%}.md\:max-w-3xl{max-width:48rem}.md\:max-w-xl{max-width:36rem}.md\:flex-shrink-0{flex-shrink:0}.md\:shrink{flex-shrink:1}.md\:grow-0{flex-grow:0}.md\:basis-1\/2{flex-basis:50%}.md\:basis-\[449px\]{flex-basis:449px}.md\:grid-cols-12{grid-template-columns:repeat(12,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:flex-row{flex-direction:row}.md\:flex-col{flex-direction:column}.md\:items-center{align-items:center}.md\:justify-center{justify-content:center}.md\:justify-between{justify-content:space-between}.md\:gap-6{gap:1.5rem}.md\:gap-x-\[21px\]{-moz-column-gap:21px;column-gap:21px}.md\:gap-y-6{row-gap:1.5rem}.md\:border-r{border-right-width:1px}.md\:border-\[\#E5E7EB\]{--tw-border-opacity: 1;border-color:rgb(229 231 235 / var(--tw-border-opacity))}.md\:p-24{padding:6rem}.md\:px-8{padding-left:2rem;padding-right:2rem}.md\:px-\[40px\]{padding-left:40px;padding-right:40px}.md\:pb-\[40px\]{padding-bottom:40px}.md\:pl-4{padding-left:1rem}.md\:pl-\[52px\]{padding-left:52px}.md\:pl-\[61px\]{padding-left:61px}.md\:pr-\[20px\]{padding-right:20px}.md\:pr-\[48px\]{padding-right:48px}.md\:pt-0{padding-top:0}.md\:pt-\[58px\]{padding-top:58px}.md\:text-left{text-align:left}.md\:text-center{text-align:center}.md\:text-2xl{font-size:1.5rem;line-height:2rem}.md\:text-\[30px\]{font-size:30px}.md\:text-\[32px\]{font-size:32px}.md\:text-sm{font-size:.875rem;line-height:1.25rem}}@media (min-width: 1024px){.lg\:col-span-3{grid-column:span 3 / span 3}.lg\:col-span-6{grid-column:span 6 / span 6}.lg\:col-span-7{grid-column:span 7 / span 7}.lg\:col-span-8{grid-column:span 8 / span 8}.lg\:col-start-3{grid-column-start:3}.lg\:col-start-4{grid-column-start:4}.lg\:-mx-8{margin-left:-2rem;margin-right:-2rem}.lg\:mt-24{margin-top:6rem}.lg\:block{display:block}.lg\:flex{display:flex}.lg\:grid{display:grid}.lg\:hidden{display:none}.lg\:h-screen{height:100vh}.lg\:w-1\/2{width:50%}.lg\:w-1\/3{width:33.333333%}.lg\:w-1\/4{width:25%}.lg\:w-1\/5{width:20%}.lg\:max-w-\[80\%\]{max-width:80%}.lg\:grid-cols-12{grid-template-columns:repeat(12,minmax(0,1fr))}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:items-center{align-items:center}.lg\:gap-4{gap:1rem}.lg\:rounded-lg{border-radius:.5rem}.lg\:px-16{padding-left:4rem;padding-right:4rem}.lg\:px-2{padding-left:.5rem;padding-right:.5rem}.lg\:px-4{padding-left:1rem;padding-right:1rem}.lg\:px-8{padding-left:2rem;padding-right:2rem}.lg\:py-2{padding-top:.5rem;padding-bottom:.5rem}}@media (min-width: 1280px){.xl\:col-span-4{grid-column:span 4 / span 4}.xl\:col-span-6{grid-column:span 6 / span 6}.xl\:col-span-8{grid-column:span 8 / span 8}.xl\:col-span-9{grid-column:span 9 / span 9}.xl\:col-start-4{grid-column-start:4}.xl\:ml-5{margin-left:1.25rem}.xl\:mt-0{margin-top:0}.xl\:mt-32{margin-top:8rem}.xl\:flex{display:flex}.xl\:w-auto{width:auto}.xl\:basis-auto{flex-basis:auto}.xl\:flex-row{flex-direction:row}.xl\:flex-nowrap{flex-wrap:nowrap}.xl\:justify-center{justify-content:center}.xl\:border-r{border-right-width:1px}.xl\:border-\[\#E5E7EB\]{--tw-border-opacity: 1;border-color:rgb(229 231 235 / var(--tw-border-opacity))}.xl\:px-16{padding-left:4rem;padding-right:4rem}.xl\:px-20{padding-left:5rem;padding-right:5rem}.xl\:px-5{padding-left:1.25rem;padding-right:1.25rem}.xl\:pr-20{padding-right:5rem}}@media (prefers-color-scheme: dark){.dark\:border-gray-600{--tw-border-opacity: 1;border-color:rgb(75 85 99 / var(--tw-border-opacity))}.dark\:bg-gray-700{--tw-bg-opacity: 1;background-color:rgb(55 65 81 / var(--tw-bg-opacity))}.dark\:text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.dark\:placeholder-gray-400::-moz-placeholder{--tw-placeholder-opacity: 1;color:rgb(156 163 175 / var(--tw-placeholder-opacity))}.dark\:placeholder-gray-400::placeholder{--tw-placeholder-opacity: 1;color:rgb(156 163 175 / var(--tw-placeholder-opacity))}.dark\:focus\:border-blue-500:focus{--tw-border-opacity: 1;border-color:rgb(59 130 246 / var(--tw-border-opacity))}.dark\:focus\:ring-blue-500:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(59 130 246 / var(--tw-ring-opacity))}} diff --git a/resources/views/portal/ninja2020/gateways/rotessa/bank_transfer/CA/details.blade.php b/resources/views/portal/ninja2020/gateways/rotessa/bank_transfer/CA/details.blade.php new file mode 100644 index 000000000000..9157edc56c8c --- /dev/null +++ b/resources/views/portal/ninja2020/gateways/rotessa/bank_transfer/CA/details.blade.php @@ -0,0 +1,4 @@ +
{{ session('ach_error') }}
++ {{ ctrans('texts.enter_the_information_for_the_bank_account') }} +
++ {{ ctrans('texts.enter_information_for_the_account_holder') }} +
++ {{ ctrans('texts.enter_information_for_the_account_holder') }} +
+