mirror of
				https://github.com/invoiceninja/invoiceninja.git
				synced 2025-11-03 23:57:33 -05:00 
			
		
		
		
	
						commit
						0b383ad970
					
				@ -1 +1 @@
 | 
			
		||||
5.4.4
 | 
			
		||||
5.4.5
 | 
			
		||||
@ -25,6 +25,9 @@ class CompanySettings extends BaseSettings
 | 
			
		||||
    /*Invoice*/
 | 
			
		||||
    public $auto_archive_invoice = false; // @implemented
 | 
			
		||||
 | 
			
		||||
    public $qr_iban = ''; //@implemented
 | 
			
		||||
    public $besr_id = ''; //@implemented
 | 
			
		||||
 | 
			
		||||
    public $lock_invoices = 'off'; //off,when_sent,when_paid //@implemented
 | 
			
		||||
 | 
			
		||||
    public $enable_client_portal_tasks = false; //@ben to implement
 | 
			
		||||
@ -289,6 +292,8 @@ class CompanySettings extends BaseSettings
 | 
			
		||||
    public $auto_archive_invoice_cancelled = false;
 | 
			
		||||
 | 
			
		||||
    public static $casts = [
 | 
			
		||||
        'besr_id'                            => 'string',
 | 
			
		||||
        'qr_iban'                            => 'string',
 | 
			
		||||
        'email_subject_purchase_order'       => 'string',
 | 
			
		||||
        'email_template_purchase_order'      => 'string',
 | 
			
		||||
        'require_purchase_order_signature'   => 'bool',
 | 
			
		||||
 | 
			
		||||
@ -11,6 +11,7 @@
 | 
			
		||||
 | 
			
		||||
namespace App\Factory;
 | 
			
		||||
 | 
			
		||||
use App\Models\CompanyUser;
 | 
			
		||||
use App\Models\User;
 | 
			
		||||
 | 
			
		||||
class UserFactory
 | 
			
		||||
 | 
			
		||||
@ -138,6 +138,14 @@ class InvoiceFilters extends QueryFilters
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function without_deleted_clients()
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
        return $this->builder->whereHas('client', function ($query) {
 | 
			
		||||
                        $query->where('is_deleted',0);
 | 
			
		||||
                       });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function upcoming()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->builder
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										151
									
								
								app/Helpers/SwissQr/SwissQrGenerator.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										151
									
								
								app/Helpers/SwissQr/SwissQrGenerator.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,151 @@
 | 
			
		||||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * Invoice Ninja (https://invoiceninja.com).
 | 
			
		||||
 *
 | 
			
		||||
 * @link https://github.com/invoiceninja/invoiceninja source repository
 | 
			
		||||
 *
 | 
			
		||||
 * @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
 | 
			
		||||
 *
 | 
			
		||||
 * @license https://www.elastic.co/licensing/elastic-license
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
namespace App\Helpers\SwissQr;
 | 
			
		||||
 | 
			
		||||
use App\Models\Client;
 | 
			
		||||
use App\Models\Company;
 | 
			
		||||
use App\Models\Invoice;
 | 
			
		||||
use Sprain\SwissQrBill as QrBill;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * SwissQrGenerator.
 | 
			
		||||
 */
 | 
			
		||||
class SwissQrGenerator 
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    protected Company $company;
 | 
			
		||||
 | 
			
		||||
    protected $invoice;
 | 
			
		||||
 | 
			
		||||
    protected Client $client;
 | 
			
		||||
 | 
			
		||||
    public function __construct($invoice, Company $company)
 | 
			
		||||
    {
 | 
			
		||||
        $this->company = $company;
 | 
			
		||||
 | 
			
		||||
        $this->invoice = $invoice;
 | 
			
		||||
    
 | 
			
		||||
        $this->client = $invoice->client;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function calcDueAmount()
 | 
			
		||||
    {
 | 
			
		||||
        if($this->invoice->partial > 0)
 | 
			
		||||
            return $this->invoice->partial;
 | 
			
		||||
 | 
			
		||||
        if($this->invoice->status_id == Invoice::STATUS_DRAFT)
 | 
			
		||||
            return $this->invoice->amount;
 | 
			
		||||
 | 
			
		||||
        return $this->invoice->balance;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function run()
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
    // This is an example how to create a typical qr bill:
 | 
			
		||||
    // - with reference number
 | 
			
		||||
    // - with known debtor
 | 
			
		||||
    // - with specified amount
 | 
			
		||||
    // - with human-readable additional information
 | 
			
		||||
    // - using your QR-IBAN
 | 
			
		||||
    //
 | 
			
		||||
    // Likely the most common use-case in the business world.
 | 
			
		||||
 | 
			
		||||
    // Create a new instance of QrBill, containing default headers with fixed values
 | 
			
		||||
    $qrBill = QrBill\QrBill::create();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // Add creditor information
 | 
			
		||||
    // Who will receive the payment and to which bank account?
 | 
			
		||||
    $qrBill->setCreditor(
 | 
			
		||||
        QrBill\DataGroup\Element\CombinedAddress::create(
 | 
			
		||||
            $this->company->present()->name(),
 | 
			
		||||
            $this->company->present()->address1(),
 | 
			
		||||
            $this->company->present()->getCompanyCityState(),
 | 
			
		||||
            'CH'
 | 
			
		||||
        ));
 | 
			
		||||
 | 
			
		||||
    $qrBill->setCreditorInformation(
 | 
			
		||||
        QrBill\DataGroup\Element\CreditorInformation::create(
 | 
			
		||||
            $this->company->present()->qr_iban() ?: '' // This is a special QR-IBAN. Classic IBANs will not be valid here.
 | 
			
		||||
        ));
 | 
			
		||||
 | 
			
		||||
    // Add debtor information
 | 
			
		||||
    // Who has to pay the invoice? This part is optional.
 | 
			
		||||
    //
 | 
			
		||||
    // Notice how you can use two different styles of addresses: CombinedAddress or StructuredAddress
 | 
			
		||||
    // They are interchangeable for creditor as well as debtor.
 | 
			
		||||
    $qrBill->setUltimateDebtor(
 | 
			
		||||
        QrBill\DataGroup\Element\StructuredAddress::createWithStreet(
 | 
			
		||||
            substr($this->client->present()->name(), 0 , 70),
 | 
			
		||||
            $this->client->address1 ? substr($this->client->address1, 0 , 70) : '',
 | 
			
		||||
            $this->client->address2 ? substr($this->client->address2, 0 , 16) : '',
 | 
			
		||||
            $this->client->postal_code ? substr($this->client->postal_code, 0, 16) : '',
 | 
			
		||||
            $this->client->city ? substr($this->client->postal_code, 0, 35) : '',
 | 
			
		||||
            'CH'
 | 
			
		||||
        ));
 | 
			
		||||
 | 
			
		||||
    // Add payment amount information
 | 
			
		||||
    // What amount is to be paid?
 | 
			
		||||
    $qrBill->setPaymentAmountInformation(
 | 
			
		||||
        QrBill\DataGroup\Element\PaymentAmountInformation::create(
 | 
			
		||||
            'CHF',
 | 
			
		||||
            $this->calcDueAmount()
 | 
			
		||||
        ));
 | 
			
		||||
 | 
			
		||||
    // Add payment reference
 | 
			
		||||
    // This is what you will need to identify incoming payments.
 | 
			
		||||
    $referenceNumber = QrBill\Reference\QrPaymentReferenceGenerator::generate(
 | 
			
		||||
        $this->company->present()->besr_id() ?: '',  // You receive this number from your bank (BESR-ID). Unless your bank is PostFinance, in that case use NULL.
 | 
			
		||||
        $this->invoice->number// A number to match the payment with your internal data, e.g. an invoice number
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    $qrBill->setPaymentReference(
 | 
			
		||||
        QrBill\DataGroup\Element\PaymentReference::create(
 | 
			
		||||
            QrBill\DataGroup\Element\PaymentReference::TYPE_QR,
 | 
			
		||||
            $referenceNumber
 | 
			
		||||
        ));
 | 
			
		||||
 | 
			
		||||
    // Optionally, add some human-readable information about what the bill is for.
 | 
			
		||||
    $qrBill->setAdditionalInformation(
 | 
			
		||||
        QrBill\DataGroup\Element\AdditionalInformation::create(
 | 
			
		||||
            $this->invoice->public_notes ?: ''
 | 
			
		||||
        )
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // Now get the QR code image and save it as a file.
 | 
			
		||||
        try {
 | 
			
		||||
 | 
			
		||||
            $output = new QrBill\PaymentPart\Output\HtmlOutput\HtmlOutput($qrBill, 'en');
 | 
			
		||||
 | 
			
		||||
            $html = $output
 | 
			
		||||
                ->setPrintable(false)
 | 
			
		||||
                ->getPaymentPart();
 | 
			
		||||
 | 
			
		||||
                return $html;
 | 
			
		||||
 | 
			
		||||
        } catch (\Exception $e) {
 | 
			
		||||
 | 
			
		||||
            foreach($qrBill->getViolations() as $key => $violation) {
 | 
			
		||||
                nlog("qr");
 | 
			
		||||
                nlog($violation);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return '';
 | 
			
		||||
            // return $e->getMessage();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -332,11 +332,6 @@ class LoginController extends BaseController
 | 
			
		||||
        if (request()->input('provider') == 'google') {
 | 
			
		||||
            return $this->handleGoogleOauth();
 | 
			
		||||
        } elseif (request()->input('provider') == 'microsoft') {
 | 
			
		||||
            // if (request()->has('token')) {
 | 
			
		||||
            //     return $this->handleSocialiteLogin('microsoft', request()->get('token'));
 | 
			
		||||
            // } else {
 | 
			
		||||
            //     $message = 'Bearer token missing for the microsoft login';
 | 
			
		||||
            // }
 | 
			
		||||
            return $this->handleMicrosoftOauth();
 | 
			
		||||
        } elseif (request()->input('provider') == 'apple') {
 | 
			
		||||
            // if (request()->has('token')) {
 | 
			
		||||
@ -498,8 +493,10 @@ class LoginController extends BaseController
 | 
			
		||||
    {
 | 
			
		||||
        if(request()->has('accessToken'))
 | 
			
		||||
            $accessToken = request()->input('accessToken');
 | 
			
		||||
        elseif(request()->has('access_token'))
 | 
			
		||||
            $accessToken = request()->input('access_token');
 | 
			
		||||
        else
 | 
			
		||||
            return response()->json(['message' => 'Invalid response from oauth server'], 400);
 | 
			
		||||
            return response()->json(['message' => 'Invalid response from oauth server, no access token in response.'], 400);
 | 
			
		||||
 | 
			
		||||
        $graph = new \Microsoft\Graph\Graph();
 | 
			
		||||
        $graph->setAccessToken($accessToken);
 | 
			
		||||
@ -510,7 +507,6 @@ class LoginController extends BaseController
 | 
			
		||||
 | 
			
		||||
        if($user){
 | 
			
		||||
 | 
			
		||||
            $account = request()->input('account');
 | 
			
		||||
            $email = $user->getMail() ?: $user->getUserPrincipalName();
 | 
			
		||||
 | 
			
		||||
            $query = [
 | 
			
		||||
@ -551,6 +547,8 @@ class LoginController extends BaseController
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return response()->json(['message' => 'Unable to authenticate this user'], 400);
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function existingOauthUser($existing_user)
 | 
			
		||||
@ -698,7 +696,7 @@ class LoginController extends BaseController
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if($provider == 'microsoft'){
 | 
			
		||||
            $scopes = ['email', 'Mail.ReadWrite', 'Mail.Send', 'offline_access', 'profile', 'User.Read openid'];
 | 
			
		||||
            $scopes = ['email', 'Mail.Send', 'offline_access', 'profile', 'User.Read openid'];
 | 
			
		||||
            $parameters = ['response_type' => 'code', 'redirect_uri' => config('ninja.app_url')."/auth/microsoft"];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -770,6 +768,8 @@ class LoginController extends BaseController
 | 
			
		||||
 | 
			
		||||
        $oauth_user_token = $socialite_user->accessTokenResponseBody['access_token'];
 | 
			
		||||
 | 
			
		||||
        $oauth_expiry = now()->addSeconds($socialite_user->accessTokenResponseBody['expires_in']) ?: now()->addSeconds(300);
 | 
			
		||||
 | 
			
		||||
        if($user = OAuth::handleAuth($socialite_user, $provider))
 | 
			
		||||
        {
 | 
			
		||||
 | 
			
		||||
@ -783,7 +783,8 @@ class LoginController extends BaseController
 | 
			
		||||
                'oauth_user_id' => $socialite_user->getId(),
 | 
			
		||||
                'oauth_provider_id' => $provider,
 | 
			
		||||
                'oauth_user_token' => $oauth_user_token,
 | 
			
		||||
                'oauth_user_refresh_token' => $socialite_user->accessTokenResponseBody['refresh_token']
 | 
			
		||||
                'oauth_user_refresh_token' => $socialite_user->accessTokenResponseBody['refresh_token'],
 | 
			
		||||
                'oauth_user_token_expiry' => $oauth_expiry,
 | 
			
		||||
            ];
 | 
			
		||||
 | 
			
		||||
            $user->update($update_user);
 | 
			
		||||
 | 
			
		||||
@ -79,6 +79,7 @@ class BaseController extends Controller
 | 
			
		||||
          'company.groups.documents',
 | 
			
		||||
          'company.invoices.invitations.contact',
 | 
			
		||||
          'company.invoices.invitations.company',
 | 
			
		||||
          'company.purchase_orders.invitations',
 | 
			
		||||
          'company.invoices.documents',
 | 
			
		||||
          'company.products',
 | 
			
		||||
          'company.products.documents',
 | 
			
		||||
@ -778,8 +779,13 @@ class BaseController extends Controller
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            /* Clean up URLs and remove query parameters from the URL*/
 | 
			
		||||
            if(request()->has('login') && request()->input('login') == 'true')
 | 
			
		||||
                return redirect('/')->with(['login' => "true"]);
 | 
			
		||||
            if (request()->has('login') && request()->input('login') == 'true') {
 | 
			
		||||
                return redirect('/')->with(['login' => 'true']);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (request()->has('signup') && request()->input('signup') == 'true') {
 | 
			
		||||
                return redirect('/')->with(['signup' => 'true']);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $data = [];
 | 
			
		||||
 | 
			
		||||
@ -789,10 +795,16 @@ class BaseController extends Controller
 | 
			
		||||
            //pass referral code to front end
 | 
			
		||||
            $data['rc'] = request()->has('rc') ? request()->input('rc') : '';
 | 
			
		||||
            $data['build'] = request()->has('build') ? request()->input('build') : '';
 | 
			
		||||
            $data['login'] = request()->has('login') ? request()->input('login') : "false";
 | 
			
		||||
            $data['login'] = request()->has('login') ? request()->input('login') : 'false';
 | 
			
		||||
            $data['signup'] = request()->has('signup') ? request()->input('signup') : 'false';
 | 
			
		||||
 | 
			
		||||
            if(request()->session()->has('login'))
 | 
			
		||||
                $data['login'] = "true";
 | 
			
		||||
            if (request()->session()->has('login')) {
 | 
			
		||||
                $data['login'] = 'true';
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if(request()->session()->has('signup')){
 | 
			
		||||
                $data['signup'] = 'true';
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $data['user_agent'] = request()->server('HTTP_USER_AGENT');
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -235,6 +235,9 @@ class InvitationController extends Controller
 | 
			
		||||
                                    ->with('contact.client')
 | 
			
		||||
                                    ->firstOrFail();
 | 
			
		||||
 | 
			
		||||
        if($invitation->contact->trashed())
 | 
			
		||||
            $invitation->contact->restore();
 | 
			
		||||
        
 | 
			
		||||
        auth()->guard('contact')->loginUsingId($invitation->contact->id, true);
 | 
			
		||||
 | 
			
		||||
        $invoice = $invitation->invoice;
 | 
			
		||||
 | 
			
		||||
@ -25,6 +25,7 @@ use App\Models\GatewayType;
 | 
			
		||||
use App\Models\Invoice;
 | 
			
		||||
use App\Models\RecurringInvoice;
 | 
			
		||||
use App\Models\Subscription;
 | 
			
		||||
use App\Notifications\Ninja\NewAccountNotification;
 | 
			
		||||
use App\Repositories\SubscriptionRepository;
 | 
			
		||||
use App\Utils\Ninja;
 | 
			
		||||
use App\Utils\Traits\MakesHash;
 | 
			
		||||
@ -165,6 +166,9 @@ class NinjaPlanController extends Controller
 | 
			
		||||
                 ->increment()
 | 
			
		||||
                 ->queue();
 | 
			
		||||
 | 
			
		||||
        $ninja_company = Company::on('db-ninja-01')->find(config('ninja.ninja_default_company_id'));
 | 
			
		||||
        $ninja_company->notification(new NewAccountNotification($account, $client))->ninja();
 | 
			
		||||
 | 
			
		||||
        return $this->render('plan.trial_confirmed', $data);
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -190,7 +190,7 @@ class QuoteController extends Controller
 | 
			
		||||
        if ($process) {
 | 
			
		||||
            foreach ($quotes as $quote) {
 | 
			
		||||
                $quote->service()->approve(auth()->user())->save();
 | 
			
		||||
                event(new QuoteWasApproved(auth()->guard('contact')->user(), $quote, $quote->company, Ninja::eventVars()));
 | 
			
		||||
                // event(new QuoteWasApproved(auth()->guard('contact')->user(), $quote, $quote->company, Ninja::eventVars()));
 | 
			
		||||
 | 
			
		||||
                if (request()->has('signature') && !is_null(request()->signature) && !empty(request()->signature)) {
 | 
			
		||||
                    InjectSignature::dispatch($quote, request()->signature);
 | 
			
		||||
 | 
			
		||||
@ -22,6 +22,7 @@ use Google_Client;
 | 
			
		||||
use Illuminate\Http\Request;
 | 
			
		||||
use Illuminate\Support\Facades\Cache;
 | 
			
		||||
use Illuminate\Support\Str;
 | 
			
		||||
use Microsoft\Graph\Model;
 | 
			
		||||
 | 
			
		||||
class ConnectedAccountController extends BaseController
 | 
			
		||||
{
 | 
			
		||||
@ -81,12 +82,61 @@ class ConnectedAccountController extends BaseController
 | 
			
		||||
            return $this->handleGoogleOauth();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ($request->input('provider') == 'microsoft') {
 | 
			
		||||
            return $this->handleMicrosoftOauth($request);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return response()
 | 
			
		||||
        ->json(['message' => 'Provider not supported'], 400)
 | 
			
		||||
        ->header('X-App-Version', config('ninja.app_version'))
 | 
			
		||||
        ->header('X-Api-Version', config('ninja.minimum_client_version'));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function handleMicrosoftOauth($request)
 | 
			
		||||
    {
 | 
			
		||||
        nlog($request->all());
 | 
			
		||||
 | 
			
		||||
        if(!$request->has('access_token'))
 | 
			
		||||
            return response()->json(['message' => 'No access_token parameter found!'], 400);
 | 
			
		||||
 | 
			
		||||
        $graph = new \Microsoft\Graph\Graph();
 | 
			
		||||
        $graph->setAccessToken($request->input('access_token'));
 | 
			
		||||
 | 
			
		||||
        $user = $graph->createRequest("GET", "/me")
 | 
			
		||||
                      ->setReturnType(Model\User::class)
 | 
			
		||||
                      ->execute();
 | 
			
		||||
 | 
			
		||||
        if($user){
 | 
			
		||||
 | 
			
		||||
            $email = $user->getMail() ?: $user->getUserPrincipalName();
 | 
			
		||||
 | 
			
		||||
            if(auth()->user()->email != $email && MultiDB::checkUserEmailExists($email))
 | 
			
		||||
                return response()->json(['message' => ctrans('texts.email_already_register')], 400);
 | 
			
		||||
 | 
			
		||||
            $connected_account = [
 | 
			
		||||
                'email' => $email,
 | 
			
		||||
                'oauth_user_id' => $user->getId(),
 | 
			
		||||
                'oauth_provider_id' => 'microsoft',
 | 
			
		||||
                'email_verified_at' =>now()
 | 
			
		||||
            ];
 | 
			
		||||
 | 
			
		||||
            auth()->user()->update($connected_account);
 | 
			
		||||
            auth()->user()->email_verified_at = now();
 | 
			
		||||
            auth()->user()->save();
 | 
			
		||||
            
 | 
			
		||||
            $this->setLoginCache(auth()->user());
 | 
			
		||||
            
 | 
			
		||||
            return $this->itemResponse(auth()->user());
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return response()
 | 
			
		||||
        ->json(['message' => ctrans('texts.invalid_credentials')], 401)
 | 
			
		||||
        ->header('X-App-Version', config('ninja.app_version'))
 | 
			
		||||
        ->header('X-Api-Version', config('ninja.minimum_client_version'));
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function handleGoogleOauth()
 | 
			
		||||
    {
 | 
			
		||||
        $user = false;
 | 
			
		||||
 | 
			
		||||
@ -284,12 +284,11 @@ class PreviewController extends BaseController
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        catch(\Exception $e){
 | 
			
		||||
 | 
			
		||||
            nlog($e->getMessage());
 | 
			
		||||
            DB::connection(config('database.default'))->rollBack();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            //if phantom js...... inject here..
 | 
			
		||||
            if (config('ninja.phantomjs_pdf_generation') || config('ninja.pdf_generator') == 'phantom') {
 | 
			
		||||
                return (new Phantom)->convertHtmlToPdf($maker->getCompiledHTML(true));
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										470
									
								
								app/Http/Controllers/PreviewPurchaseOrderController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										470
									
								
								app/Http/Controllers/PreviewPurchaseOrderController.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,470 @@
 | 
			
		||||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * Invoice Ninja (https://invoiceninja.com).
 | 
			
		||||
 *
 | 
			
		||||
 * @link https://github.com/invoiceninja/invoiceninja source repository
 | 
			
		||||
 *
 | 
			
		||||
 * @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
 | 
			
		||||
 *
 | 
			
		||||
 * @license https://www.elastic.co/licensing/elastic-license
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
namespace App\Http\Controllers;
 | 
			
		||||
 | 
			
		||||
use App\DataMapper\Analytics\LivePreview;
 | 
			
		||||
use App\Factory\CreditFactory;
 | 
			
		||||
use App\Factory\InvoiceFactory;
 | 
			
		||||
use App\Factory\PurchaseOrderFactory;
 | 
			
		||||
use App\Factory\QuoteFactory;
 | 
			
		||||
use App\Factory\RecurringInvoiceFactory;
 | 
			
		||||
use App\Http\Requests\Invoice\StoreInvoiceRequest;
 | 
			
		||||
use App\Http\Requests\Preview\PreviewInvoiceRequest;
 | 
			
		||||
use App\Http\Requests\Preview\PreviewPurchaseOrderRequest;
 | 
			
		||||
use App\Jobs\Util\PreviewPdf;
 | 
			
		||||
use App\Libraries\MultiDB;
 | 
			
		||||
use App\Models\Client;
 | 
			
		||||
use App\Models\ClientContact;
 | 
			
		||||
use App\Models\Credit;
 | 
			
		||||
use App\Models\Invoice;
 | 
			
		||||
use App\Models\InvoiceInvitation;
 | 
			
		||||
use App\Models\PurchaseOrder;
 | 
			
		||||
use App\Models\PurchaseOrderInvitation;
 | 
			
		||||
use App\Models\Quote;
 | 
			
		||||
use App\Models\RecurringInvoice;
 | 
			
		||||
use App\Models\Vendor;
 | 
			
		||||
use App\Models\VendorContact;
 | 
			
		||||
use App\Repositories\CreditRepository;
 | 
			
		||||
use App\Repositories\InvoiceRepository;
 | 
			
		||||
use App\Repositories\PurchaseOrderRepository;
 | 
			
		||||
use App\Repositories\QuoteRepository;
 | 
			
		||||
use App\Repositories\RecurringInvoiceRepository;
 | 
			
		||||
use App\Services\PdfMaker\Design as PdfDesignModel;
 | 
			
		||||
use App\Services\PdfMaker\Design as PdfMakerDesign;
 | 
			
		||||
use App\Services\PdfMaker\Design;
 | 
			
		||||
use App\Services\PdfMaker\PdfMaker;
 | 
			
		||||
use App\Utils\HostedPDF\NinjaPdf;
 | 
			
		||||
use App\Utils\HtmlEngine;
 | 
			
		||||
use App\Utils\Ninja;
 | 
			
		||||
use App\Utils\PhantomJS\Phantom;
 | 
			
		||||
use App\Utils\Traits\MakesHash;
 | 
			
		||||
use App\Utils\Traits\MakesInvoiceHtml;
 | 
			
		||||
use App\Utils\Traits\Pdf\PageNumbering;
 | 
			
		||||
use App\Utils\VendorHtmlEngine;
 | 
			
		||||
use Illuminate\Support\Facades\App;
 | 
			
		||||
use Illuminate\Support\Facades\DB;
 | 
			
		||||
use Illuminate\Support\Facades\Lang;
 | 
			
		||||
use Illuminate\Support\Facades\Response;
 | 
			
		||||
use Turbo124\Beacon\Facades\LightLogs;
 | 
			
		||||
 | 
			
		||||
class PreviewPurchaseOrderController extends BaseController
 | 
			
		||||
{
 | 
			
		||||
    use MakesHash;
 | 
			
		||||
    use MakesInvoiceHtml;
 | 
			
		||||
    use PageNumbering;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public function __construct()
 | 
			
		||||
    {
 | 
			
		||||
        parent::__construct();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns a template filled with entity variables.
 | 
			
		||||
     *
 | 
			
		||||
     * @return \Illuminate\Http\Response
 | 
			
		||||
     *
 | 
			
		||||
     * @OA\Post(
 | 
			
		||||
     *      path="/api/v1/preview/purchase_order",
 | 
			
		||||
     *      operationId="getPreviewPurchaseOrder",
 | 
			
		||||
     *      tags={"preview"},
 | 
			
		||||
     *      summary="Returns a pdf preview for purchase order",
 | 
			
		||||
     *      description="Returns a pdf preview for purchase order.",
 | 
			
		||||
     *      @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
 | 
			
		||||
     *      @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
 | 
			
		||||
     *      @OA\Response(
 | 
			
		||||
     *          response=200,
 | 
			
		||||
     *          description="The pdf response",
 | 
			
		||||
     *          @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
 | 
			
		||||
     *          @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
 | 
			
		||||
     *          @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
 | 
			
		||||
     *       ),
 | 
			
		||||
     *       @OA\Response(
 | 
			
		||||
     *          response=422,
 | 
			
		||||
     *          description="Validation error",
 | 
			
		||||
     *          @OA\JsonContent(ref="#/components/schemas/ValidationError"),
 | 
			
		||||
 | 
			
		||||
     *       ),
 | 
			
		||||
     *       @OA\Response(
 | 
			
		||||
     *           response="default",
 | 
			
		||||
     *           description="Unexpected Error",
 | 
			
		||||
     *           @OA\JsonContent(ref="#/components/schemas/Error"),
 | 
			
		||||
     *       ),
 | 
			
		||||
     *     )
 | 
			
		||||
     */
 | 
			
		||||
    public function show()
 | 
			
		||||
    {
 | 
			
		||||
        if (request()->has('entity') &&
 | 
			
		||||
            request()->has('entity_id') &&
 | 
			
		||||
            ! empty(request()->input('entity')) &&
 | 
			
		||||
            ! empty(request()->input('entity_id')) &&
 | 
			
		||||
            request()->has('body')) {
 | 
			
		||||
            
 | 
			
		||||
            $design_object = json_decode(json_encode(request()->input('design')));
 | 
			
		||||
 | 
			
		||||
            if (! is_object($design_object)) {
 | 
			
		||||
                return response()->json(['message' => ctrans('texts.invalid_design_object')], 400);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $entity_obj = PurchaseOrder::whereId($this->decodePrimaryKey(request()->input('entity_id')))->company()->first();
 | 
			
		||||
 | 
			
		||||
            if (! $entity_obj) {
 | 
			
		||||
                return $this->blankEntity();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            App::forgetInstance('translator');
 | 
			
		||||
            $t = app('translator');
 | 
			
		||||
            App::setLocale($entity_obj->company->locale());
 | 
			
		||||
            $t->replace(Ninja::transformTranslations($entity_obj->company->settings));
 | 
			
		||||
 | 
			
		||||
            $html = new VendorHtmlEngine($entity_obj->invitations()->first());
 | 
			
		||||
 | 
			
		||||
            $design_namespace = 'App\Services\PdfMaker\Designs\\'.request()->design['name'];
 | 
			
		||||
 | 
			
		||||
            $design_class = new $design_namespace();
 | 
			
		||||
 | 
			
		||||
            $state = [
 | 
			
		||||
                'template' => $design_class->elements([
 | 
			
		||||
                    'client' => null,
 | 
			
		||||
                    'vendor' => $entity_obj->vendor,
 | 
			
		||||
                    'entity' => $entity_obj,
 | 
			
		||||
                    'pdf_variables' => (array) $entity_obj->company->settings->pdf_variables,
 | 
			
		||||
                    'variables' => $html->generateLabelsAndValues(),
 | 
			
		||||
                ]),
 | 
			
		||||
                'variables' => $html->generateLabelsAndValues(),
 | 
			
		||||
                'process_markdown' => $entity_obj->company->markdown_enabled,
 | 
			
		||||
            ];
 | 
			
		||||
 | 
			
		||||
            $design = new Design(request()->design['name']);
 | 
			
		||||
            $maker = new PdfMaker($state);
 | 
			
		||||
 | 
			
		||||
            $maker
 | 
			
		||||
                ->design($design)
 | 
			
		||||
                ->build();
 | 
			
		||||
 | 
			
		||||
            if (request()->query('html') == 'true') {
 | 
			
		||||
                return $maker->getCompiledHTML();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            //if phantom js...... inject here..
 | 
			
		||||
            if (config('ninja.phantomjs_pdf_generation') || config('ninja.pdf_generator') == 'phantom') {
 | 
			
		||||
                return (new Phantom)->convertHtmlToPdf($maker->getCompiledHTML(true));
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            if(config('ninja.invoiceninja_hosted_pdf_generation') || config('ninja.pdf_generator') == 'hosted_ninja'){
 | 
			
		||||
                $pdf = (new NinjaPdf())->build($maker->getCompiledHTML(true));
 | 
			
		||||
 | 
			
		||||
                $numbered_pdf = $this->pageNumbering($pdf, auth()->user()->company());
 | 
			
		||||
 | 
			
		||||
                if($numbered_pdf)
 | 
			
		||||
                    $pdf = $numbered_pdf;
 | 
			
		||||
 | 
			
		||||
                return $pdf;
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            //else
 | 
			
		||||
            $file_path = PreviewPdf::dispatchNow($maker->getCompiledHTML(true), auth()->user()->company());
 | 
			
		||||
 | 
			
		||||
            return response()->download($file_path, basename($file_path), ['Cache-Control:' => 'no-cache'])->deleteFileAfterSend(true);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $this->blankEntity();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function live(PreviewPurchaseOrderRequest $request)
 | 
			
		||||
    {
 | 
			
		||||
        $company = auth()->user()->company();
 | 
			
		||||
 | 
			
		||||
        MultiDB::setDb($company->db);
 | 
			
		||||
 | 
			
		||||
        $repo = new PurchaseOrderRepository();
 | 
			
		||||
        $entity_obj = PurchaseOrderFactory::create($company->id, auth()->user()->id);
 | 
			
		||||
        $class = PurchaseOrder::class;
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
 | 
			
		||||
            DB::connection(config('database.default'))->beginTransaction();
 | 
			
		||||
 | 
			
		||||
            if($request->has('entity_id')){
 | 
			
		||||
 | 
			
		||||
                $entity_obj = $class::on(config('database.default'))
 | 
			
		||||
                                    ->with('vendor.company')
 | 
			
		||||
                                    ->where('id', $this->decodePrimaryKey($request->input('entity_id')))
 | 
			
		||||
                                    ->where('company_id', $company->id)
 | 
			
		||||
                                    ->withTrashed()
 | 
			
		||||
                                    ->first();
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $entity_obj = $repo->save($request->all(), $entity_obj);
 | 
			
		||||
 | 
			
		||||
            if(!$request->has('entity_id'))
 | 
			
		||||
                $entity_obj->service()->fillDefaults()->save();
 | 
			
		||||
                
 | 
			
		||||
            App::forgetInstance('translator');
 | 
			
		||||
            $t = app('translator');
 | 
			
		||||
            App::setLocale($entity_obj->company->locale());
 | 
			
		||||
            $t->replace(Ninja::transformTranslations($entity_obj->company->settings));
 | 
			
		||||
 | 
			
		||||
            $html = new VendorHtmlEngine($entity_obj->invitations()->first());
 | 
			
		||||
 | 
			
		||||
            $design = \App\Models\Design::find($entity_obj->design_id);
 | 
			
		||||
 | 
			
		||||
            /* Catch all in case migration doesn't pass back a valid design */
 | 
			
		||||
            if(!$design)
 | 
			
		||||
                $design = \App\Models\Design::find(2);
 | 
			
		||||
 | 
			
		||||
            if ($design->is_custom) {
 | 
			
		||||
                $options = [
 | 
			
		||||
                'custom_partials' => json_decode(json_encode($design->design), true)
 | 
			
		||||
              ];
 | 
			
		||||
                $template = new PdfMakerDesign(PdfDesignModel::CUSTOM, $options);
 | 
			
		||||
            } else {
 | 
			
		||||
                $template = new PdfMakerDesign(strtolower($design->name));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $variables = $html->generateLabelsAndValues();
 | 
			
		||||
 | 
			
		||||
            $state = [
 | 
			
		||||
                'template' => $template->elements([
 | 
			
		||||
                    'client' => null,
 | 
			
		||||
                    'vendor' => $entity_obj->vendor,
 | 
			
		||||
                    'entity' => $entity_obj,
 | 
			
		||||
                    'pdf_variables' => (array) $entity_obj->company->settings->pdf_variables,
 | 
			
		||||
                    'variables' => $html->generateLabelsAndValues(),
 | 
			
		||||
                    '$product' => $design->design->product,
 | 
			
		||||
                ]),
 | 
			
		||||
                'variables' => $html->generateLabelsAndValues(),
 | 
			
		||||
                'process_markdown' => $entity_obj->company->markdown_enabled,
 | 
			
		||||
            ];
 | 
			
		||||
 | 
			
		||||
            $maker = new PdfMaker($state);
 | 
			
		||||
 | 
			
		||||
            $maker
 | 
			
		||||
                ->design($template)
 | 
			
		||||
                ->build();
 | 
			
		||||
 | 
			
		||||
            DB::connection(config('database.default'))->rollBack();
 | 
			
		||||
 | 
			
		||||
            if (request()->query('html') == 'true') {
 | 
			
		||||
                return $maker->getCompiledHTML();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        catch(\Exception $e){
 | 
			
		||||
 | 
			
		||||
            DB::connection(config('database.default'))->rollBack();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            //if phantom js...... inject here..
 | 
			
		||||
            if (config('ninja.phantomjs_pdf_generation') || config('ninja.pdf_generator') == 'phantom') {
 | 
			
		||||
                return (new Phantom)->convertHtmlToPdf($maker->getCompiledHTML(true));
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            if(config('ninja.invoiceninja_hosted_pdf_generation') || config('ninja.pdf_generator') == 'hosted_ninja'){
 | 
			
		||||
                $pdf = (new NinjaPdf())->build($maker->getCompiledHTML(true));
 | 
			
		||||
 | 
			
		||||
                $numbered_pdf = $this->pageNumbering($pdf, auth()->user()->company());
 | 
			
		||||
 | 
			
		||||
                if($numbered_pdf)
 | 
			
		||||
                    $pdf = $numbered_pdf;
 | 
			
		||||
 | 
			
		||||
                return $pdf;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $file_path = PreviewPdf::dispatchNow($maker->getCompiledHTML(true), $company);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            if(Ninja::isHosted())
 | 
			
		||||
            {
 | 
			
		||||
                LightLogs::create(new LivePreview())
 | 
			
		||||
                         ->increment()
 | 
			
		||||
                         ->queue();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        $response = Response::make($file_path, 200);
 | 
			
		||||
        $response->header('Content-Type', 'application/pdf');
 | 
			
		||||
 | 
			
		||||
        return $response;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function blankEntity()
 | 
			
		||||
    {
 | 
			
		||||
        App::forgetInstance('translator');
 | 
			
		||||
        $t = app('translator');
 | 
			
		||||
        $t->replace(Ninja::transformTranslations(auth()->user()->company()->settings));
 | 
			
		||||
 | 
			
		||||
        $invitation = PurchaseOrderInvitation::where('company_id', auth()->user()->company()->id)->orderBy('id', 'desc')->first();
 | 
			
		||||
 | 
			
		||||
        /* If we don't have a valid invitation in the system - create a mock using transactions */
 | 
			
		||||
        if(!$invitation)
 | 
			
		||||
            return $this->mockEntity();
 | 
			
		||||
 | 
			
		||||
        $design_object = json_decode(json_encode(request()->input('design')));
 | 
			
		||||
 | 
			
		||||
        if (! is_object($design_object)) {
 | 
			
		||||
            return response()->json(['message' => 'Invalid custom design object'], 400);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $html = new VendorHtmlEngine($invitation);
 | 
			
		||||
 | 
			
		||||
        $design = new Design(Design::CUSTOM, ['custom_partials' => request()->design['design']]);
 | 
			
		||||
 | 
			
		||||
        $state = [
 | 
			
		||||
            'template' => $design->elements([
 | 
			
		||||
                'client' => null,
 | 
			
		||||
                'vendor' => $invitation->purchase_order->vendor,
 | 
			
		||||
                'entity' => $invitation->purchase_order,
 | 
			
		||||
                'pdf_variables' => (array) $invitation->company->settings->pdf_variables,
 | 
			
		||||
                'products' => request()->design['design']['product'],
 | 
			
		||||
            ]),
 | 
			
		||||
            'variables' => $html->generateLabelsAndValues(),
 | 
			
		||||
            'process_markdown' => $invitation->company->markdown_enabled,
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        $maker = new PdfMaker($state);
 | 
			
		||||
 | 
			
		||||
        $maker
 | 
			
		||||
            ->design($design)
 | 
			
		||||
            ->build();
 | 
			
		||||
 | 
			
		||||
        if (request()->query('html') == 'true') {
 | 
			
		||||
            return $maker->getCompiledHTML();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (config('ninja.phantomjs_pdf_generation') || config('ninja.pdf_generator') == 'phantom') {
 | 
			
		||||
            return (new Phantom)->convertHtmlToPdf($maker->getCompiledHTML(true));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if(config('ninja.invoiceninja_hosted_pdf_generation') || config('ninja.pdf_generator') == 'hosted_ninja'){
 | 
			
		||||
            $pdf =  (new NinjaPdf())->build($maker->getCompiledHTML(true));
 | 
			
		||||
 | 
			
		||||
            $numbered_pdf = $this->pageNumbering($pdf, auth()->user()->company());
 | 
			
		||||
 | 
			
		||||
                if($numbered_pdf)
 | 
			
		||||
                    $pdf = $numbered_pdf;
 | 
			
		||||
 | 
			
		||||
                return $pdf;
 | 
			
		||||
        }
 | 
			
		||||
            
 | 
			
		||||
        $file_path = PreviewPdf::dispatchNow($maker->getCompiledHTML(true), auth()->user()->company());
 | 
			
		||||
 | 
			
		||||
        $response = Response::make($file_path, 200);
 | 
			
		||||
        $response->header('Content-Type', 'application/pdf');
 | 
			
		||||
 | 
			
		||||
        return $response;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function mockEntity()
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
        DB::connection(auth()->user()->company()->db)->beginTransaction();
 | 
			
		||||
 | 
			
		||||
        $vendor = Vendor::factory()->create([
 | 
			
		||||
                'user_id' => auth()->user()->id,
 | 
			
		||||
                'company_id' => auth()->user()->company()->id,
 | 
			
		||||
            ]);
 | 
			
		||||
 | 
			
		||||
        $contact = VendorContact::factory()->create([
 | 
			
		||||
                'user_id' => auth()->user()->id,
 | 
			
		||||
                'company_id' => auth()->user()->company()->id,
 | 
			
		||||
                'vendor_id' => $vendor->id,
 | 
			
		||||
                'is_primary' => 1,
 | 
			
		||||
                'send_email' => true,
 | 
			
		||||
            ]);
 | 
			
		||||
 | 
			
		||||
        $purchase_order = PurchaseOrder::factory()->create([
 | 
			
		||||
                    'user_id' => auth()->user()->id,
 | 
			
		||||
                    'company_id' => auth()->user()->company()->id,
 | 
			
		||||
                    'vendor_id' => $vendor->id,
 | 
			
		||||
                    'terms' => 'Sample Terms',
 | 
			
		||||
                    'footer' => 'Sample Footer',
 | 
			
		||||
                    'public_notes' => 'Sample Public Notes',
 | 
			
		||||
                ]);
 | 
			
		||||
 | 
			
		||||
        $invitation = PurchaseOrderInvitation::factory()->create([
 | 
			
		||||
                    'user_id' => auth()->user()->id,
 | 
			
		||||
                    'company_id' => auth()->user()->company()->id,
 | 
			
		||||
                    'purchase_order_id' => $purchase_order->id,
 | 
			
		||||
                    'vendor_contact_id' => $contact->id,
 | 
			
		||||
        ]);
 | 
			
		||||
 | 
			
		||||
        $purchase_order->setRelation('invitations', $invitation);
 | 
			
		||||
        $purchase_order->setRelation('vendor', $vendor);
 | 
			
		||||
        $purchase_order->setRelation('company', auth()->user()->company());
 | 
			
		||||
        $purchase_order->load('vendor.company');
 | 
			
		||||
 | 
			
		||||
        $design_object = json_decode(json_encode(request()->input('design')));
 | 
			
		||||
 | 
			
		||||
        if (! is_object($design_object)) {
 | 
			
		||||
            return response()->json(['message' => 'Invalid custom design object'], 400);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $html = new VendorHtmlEngine($purchase_order->invitations()->first());
 | 
			
		||||
 | 
			
		||||
        $design = new Design(Design::CUSTOM, ['custom_partials' => request()->design['design']]);
 | 
			
		||||
 | 
			
		||||
        $state = [
 | 
			
		||||
            'template' => $design->elements([
 | 
			
		||||
                'client' => null,
 | 
			
		||||
                'vendor' => $purchase_order->vendor,
 | 
			
		||||
                'entity' => $purchase_order,
 | 
			
		||||
                'pdf_variables' => (array) $purchase_order->company->settings->pdf_variables,
 | 
			
		||||
                'products' => request()->design['design']['product'],
 | 
			
		||||
            ]),
 | 
			
		||||
            'variables' => $html->generateLabelsAndValues(),
 | 
			
		||||
            'process_markdown' => $purchase_order->company->markdown_enabled,
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        $maker = new PdfMaker($state);
 | 
			
		||||
 | 
			
		||||
        $maker
 | 
			
		||||
            ->design($design)
 | 
			
		||||
            ->build();
 | 
			
		||||
 | 
			
		||||
        DB::connection(auth()->user()->company()->db)->rollBack();
 | 
			
		||||
 | 
			
		||||
        if (request()->query('html') == 'true') {
 | 
			
		||||
            return $maker->getCompiledHTML();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (config('ninja.phantomjs_pdf_generation') || config('ninja.pdf_generator') == 'phantom') {
 | 
			
		||||
            return (new Phantom)->convertHtmlToPdf($maker->getCompiledHTML(true));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if(config('ninja.invoiceninja_hosted_pdf_generation') || config('ninja.pdf_generator') == 'hosted_ninja'){
 | 
			
		||||
            $pdf = (new NinjaPdf())->build($maker->getCompiledHTML(true));
 | 
			
		||||
 | 
			
		||||
            $numbered_pdf = $this->pageNumbering($pdf, auth()->user()->company());
 | 
			
		||||
 | 
			
		||||
                if($numbered_pdf)
 | 
			
		||||
                    $pdf = $numbered_pdf;
 | 
			
		||||
 | 
			
		||||
                return $pdf;
 | 
			
		||||
        }
 | 
			
		||||
            
 | 
			
		||||
        $file_path = PreviewPdf::dispatchNow($maker->getCompiledHTML(true), auth()->user()->company());
 | 
			
		||||
 | 
			
		||||
        $response = Response::make($file_path, 200);
 | 
			
		||||
        $response->header('Content-Type', 'application/pdf');
 | 
			
		||||
 | 
			
		||||
        return $response;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -633,11 +633,23 @@ class PurchaseOrderController extends BaseController
 | 
			
		||||
                //check query parameter for email_type and set the template else use calculateTemplate
 | 
			
		||||
                PurchaseOrderEmail::dispatch($purchase_order, $purchase_order->company);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                if (! $bulk) {
 | 
			
		||||
                    return response()->json(['message' => 'email sent'], 200);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
            case 'cancel':
 | 
			
		||||
 | 
			
		||||
                if($purchase_order->status_id <= PurchaseOrder::STATUS_SENT)
 | 
			
		||||
                {
 | 
			
		||||
                    $purchase_order->status_id = PurchaseOrder::STATUS_CANCELLED;
 | 
			
		||||
                    $purchase_order->save();
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                if (! $bulk) {
 | 
			
		||||
                    return $this->listResponse($purchase_order);
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
            default:
 | 
			
		||||
                return response()->json(['message' => ctrans('texts.action_unavailable', ['action' => $action])], 400);
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
@ -158,7 +158,7 @@ class UserController extends BaseController
 | 
			
		||||
     */
 | 
			
		||||
    public function create(CreateUserRequest $request)
 | 
			
		||||
    {
 | 
			
		||||
        $user = UserFactory::create(auth()->user()->account->id);
 | 
			
		||||
        $user = UserFactory::create(auth()->user()->account_id);
 | 
			
		||||
 | 
			
		||||
        return $this->itemResponse($user);
 | 
			
		||||
    }
 | 
			
		||||
@ -396,7 +396,7 @@ class UserController extends BaseController
 | 
			
		||||
            UserEmailChanged::dispatch($new_user, json_decode($old_user), auth()->user()->company());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $user->company_users()->update(["permissions_updated_at" => now()]);        
 | 
			
		||||
       // $user->company_users()->update(["permissions_updated_at" => now()]);        
 | 
			
		||||
 | 
			
		||||
        event(new UserWasUpdated($user, auth()->user(), auth()->user()->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -17,11 +17,13 @@ use App\Events\Misc\InvitationWasViewed;
 | 
			
		||||
use App\Events\Quote\QuoteWasViewed;
 | 
			
		||||
use App\Http\Controllers\Controller;
 | 
			
		||||
use App\Jobs\Entity\CreateRawPdf;
 | 
			
		||||
use App\Jobs\Vendor\CreatePurchaseOrderPdf;
 | 
			
		||||
use App\Models\Client;
 | 
			
		||||
use App\Models\ClientContact;
 | 
			
		||||
use App\Models\CreditInvitation;
 | 
			
		||||
use App\Models\InvoiceInvitation;
 | 
			
		||||
use App\Models\Payment;
 | 
			
		||||
use App\Models\PurchaseOrder;
 | 
			
		||||
use App\Models\PurchaseOrderInvitation;
 | 
			
		||||
use App\Models\QuoteInvitation;
 | 
			
		||||
use App\Services\ClientPortal\InstantPayment;
 | 
			
		||||
@ -95,50 +97,32 @@ class InvitationController extends Controller
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function download(string $invitation_key)
 | 
			
		||||
    {
 | 
			
		||||
        $invitation = PurchaseOrderInvitation::withTrashed()
 | 
			
		||||
                            ->where('key', $invitation_key)
 | 
			
		||||
                            ->with('contact.vendor')
 | 
			
		||||
                            ->firstOrFail();
 | 
			
		||||
 | 
			
		||||
        if(!$invitation)
 | 
			
		||||
            return response()->json(["message" => "no record found"], 400);
 | 
			
		||||
 | 
			
		||||
    // public function routerForDownload(string $entity, string $invitation_key)
 | 
			
		||||
    // {
 | 
			
		||||
 | 
			
		||||
    //     set_time_limit(45);
 | 
			
		||||
 | 
			
		||||
    //     if(Ninja::isHosted())
 | 
			
		||||
    //         return $this->returnRawPdf($entity, $invitation_key);
 | 
			
		||||
 | 
			
		||||
    //     return redirect('client/'.$entity.'/'.$invitation_key.'/download_pdf');
 | 
			
		||||
    // }
 | 
			
		||||
 | 
			
		||||
    // private function returnRawPdf(string $entity, string $invitation_key)
 | 
			
		||||
    // {
 | 
			
		||||
 | 
			
		||||
    //     if(!in_array($entity, ['invoice', 'credit', 'quote', 'recurring_invoice']))
 | 
			
		||||
    //         return response()->json(['message' => 'Invalid resource request']);
 | 
			
		||||
 | 
			
		||||
    //     $key = $entity.'_id';
 | 
			
		||||
 | 
			
		||||
    //     $entity_obj = 'App\Models\\'.ucfirst(Str::camel($entity)).'Invitation';
 | 
			
		||||
 | 
			
		||||
    //     $invitation = $entity_obj::where('key', $invitation_key)
 | 
			
		||||
    //                                 ->with('contact.client')
 | 
			
		||||
    //                                 ->firstOrFail();
 | 
			
		||||
 | 
			
		||||
    //     if(!$invitation)
 | 
			
		||||
    //         return response()->json(["message" => "no record found"], 400);
 | 
			
		||||
 | 
			
		||||
    //     $file_name = $invitation->purchase_order->numberFormatter().'.pdf';
 | 
			
		||||
        $file_name = $invitation->purchase_order->numberFormatter().'.pdf';
 | 
			
		||||
 | 
			
		||||
        // $file = CreateRawPdf::dispatchNow($invitation, $invitation->company->db);
 | 
			
		||||
 | 
			
		||||
    //     $headers = ['Content-Type' => 'application/pdf'];
 | 
			
		||||
        $file = (new CreatePurchaseOrderPdf($invitation))->rawPdf();
 | 
			
		||||
 | 
			
		||||
    //     if(request()->input('inline') == 'true')
 | 
			
		||||
    //         $headers = array_merge($headers, ['Content-Disposition' => 'inline']);
 | 
			
		||||
        $headers = ['Content-Type' => 'application/pdf'];
 | 
			
		||||
 | 
			
		||||
    //     return response()->streamDownload(function () use($file) {
 | 
			
		||||
    //             echo $file;
 | 
			
		||||
    //     },  $file_name, $headers);
 | 
			
		||||
        if(request()->input('inline') == 'true')
 | 
			
		||||
            $headers = array_merge($headers, ['Content-Disposition' => 'inline']);
 | 
			
		||||
 | 
			
		||||
        return response()->streamDownload(function () use($file) {
 | 
			
		||||
                echo $file;
 | 
			
		||||
        },  $file_name, $headers);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -63,6 +63,8 @@ class PasswordProtection
 | 
			
		||||
 | 
			
		||||
            //user is attempting to reauth with OAuth - check the token value
 | 
			
		||||
            //todo expand this to include all OAuth providers
 | 
			
		||||
            if(auth()->user()->oauth_provider_id == 'google')
 | 
			
		||||
            {
 | 
			
		||||
                $user = false;
 | 
			
		||||
                $google = new Google();
 | 
			
		||||
                $user = $google->getTokenResponse(request()->header('X-API-OAUTH-PASSWORD'));
 | 
			
		||||
@ -92,6 +94,26 @@ class PasswordProtection
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
            elseif(auth()->user()->oauth_provider_id == 'microsoft')
 | 
			
		||||
            {
 | 
			
		||||
                try{
 | 
			
		||||
                    $payload = json_decode(base64_decode(str_replace('_', '/', str_replace('-','+',explode('.', request()->header('X-API-OAUTH-PASSWORD'))[1]))));
 | 
			
		||||
                }
 | 
			
		||||
                catch(\Exception $e){
 | 
			
		||||
                    nlog("could not decode microsoft response");
 | 
			
		||||
                    return response()->json(['message' => 'Could not decode the response from Microsoft'], 412);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if($payload->preferred_username == auth()->user()->email){
 | 
			
		||||
 | 
			
		||||
                    Cache::put(auth()->user()->hashed_id.'_'.auth()->user()->account_id.'_logged_in', Str::random(64), $timeout);
 | 
			
		||||
                    return $next($request);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            return response()->json($error, 412);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -73,6 +73,8 @@ class UpdatePaymentRequest extends Request
 | 
			
		||||
 | 
			
		||||
        if (isset($input['invoices']) && is_array($input['invoices']) !== false) {
 | 
			
		||||
            foreach ($input['invoices'] as $key => $value) {
 | 
			
		||||
 | 
			
		||||
                if(array_key_exists('invoice_id', $input['invoices'][$key]))
 | 
			
		||||
                    $input['invoices'][$key]['invoice_id'] = $this->decodePrimaryKey($value['invoice_id']);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										62
									
								
								app/Http/Requests/Preview/PreviewPurchaseOrderRequest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								app/Http/Requests/Preview/PreviewPurchaseOrderRequest.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,62 @@
 | 
			
		||||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * Invoice Ninja (https://invoiceninja.com).
 | 
			
		||||
 *
 | 
			
		||||
 * @link https://github.com/invoiceninja/invoiceninja source repository
 | 
			
		||||
 *
 | 
			
		||||
 * @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
 | 
			
		||||
 *
 | 
			
		||||
 * @license https://www.elastic.co/licensing/elastic-license
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
namespace App\Http\Requests\Preview;
 | 
			
		||||
 | 
			
		||||
use App\Http\Requests\Request;
 | 
			
		||||
use App\Http\ValidationRules\Project\ValidProjectForClient;
 | 
			
		||||
use App\Models\Credit;
 | 
			
		||||
use App\Models\Invoice;
 | 
			
		||||
use App\Models\PurchaseOrder;
 | 
			
		||||
use App\Models\Quote;
 | 
			
		||||
use App\Models\RecurringInvoice;
 | 
			
		||||
use App\Utils\Traits\CleanLineItems;
 | 
			
		||||
use App\Utils\Traits\MakesHash;
 | 
			
		||||
use Illuminate\Validation\Rule;
 | 
			
		||||
 | 
			
		||||
class PreviewPurchaseOrderRequest extends Request
 | 
			
		||||
{
 | 
			
		||||
    use MakesHash;
 | 
			
		||||
    use CleanLineItems;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Determine if the user is authorized to make this request.
 | 
			
		||||
     *
 | 
			
		||||
     * @return bool
 | 
			
		||||
     */
 | 
			
		||||
    public function authorize() : bool
 | 
			
		||||
    {
 | 
			
		||||
        return auth()->user()->can('create', PurchaseOrder::class);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function rules()
 | 
			
		||||
    {
 | 
			
		||||
        $rules = [];
 | 
			
		||||
 | 
			
		||||
        $rules['number'] = ['nullable'];
 | 
			
		||||
 | 
			
		||||
        return $rules;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function prepareForValidation()
 | 
			
		||||
    {
 | 
			
		||||
        $input = $this->all();
 | 
			
		||||
 | 
			
		||||
        $input = $this->decodePrimaryKeys($input);
 | 
			
		||||
 | 
			
		||||
        $input['line_items'] = isset($input['line_items']) ? $this->cleanItems($input['line_items']) : [];
 | 
			
		||||
        $input['amount'] = 0;
 | 
			
		||||
        $input['balance'] = 0;
 | 
			
		||||
        $input['number'] = ctrans('texts.live_preview') . " #". rand(0,1000);
 | 
			
		||||
        
 | 
			
		||||
        $this->replace($input);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -58,6 +58,6 @@ class StoreProjectRequest extends Request
 | 
			
		||||
 | 
			
		||||
    public function getClient($client_id)
 | 
			
		||||
    {
 | 
			
		||||
        return Client::find($client_id);
 | 
			
		||||
        return Client::withTrashed()->find($client_id);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -14,12 +14,15 @@ namespace App\Http\Requests\PurchaseOrder;
 | 
			
		||||
 | 
			
		||||
use App\Http\Requests\Request;
 | 
			
		||||
use App\Models\PurchaseOrder;
 | 
			
		||||
use App\Utils\Traits\CleanLineItems;
 | 
			
		||||
use App\Utils\Traits\MakesHash;
 | 
			
		||||
use Illuminate\Validation\Rule;
 | 
			
		||||
 | 
			
		||||
class StorePurchaseOrderRequest extends Request
 | 
			
		||||
{
 | 
			
		||||
    use MakesHash;
 | 
			
		||||
    use CleanLineItems;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Determine if the user is authorized to make this request.
 | 
			
		||||
     *
 | 
			
		||||
@ -43,8 +46,6 @@ class StorePurchaseOrderRequest extends Request
 | 
			
		||||
        $rules['number'] = ['nullable', Rule::unique('purchase_orders')->where('company_id', auth()->user()->company()->id)];
 | 
			
		||||
        $rules['discount']  = 'sometimes|numeric';
 | 
			
		||||
        $rules['is_amount_discount'] = ['boolean'];
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        $rules['line_items'] = 'array';
 | 
			
		||||
 | 
			
		||||
        return $rules;
 | 
			
		||||
@ -56,6 +57,12 @@ class StorePurchaseOrderRequest extends Request
 | 
			
		||||
 | 
			
		||||
        $input = $this->decodePrimaryKeys($input);
 | 
			
		||||
 | 
			
		||||
        if (isset($input['line_items']) && is_array($input['line_items'])) 
 | 
			
		||||
            $input['line_items'] = isset($input['line_items']) ? $this->cleanItems($input['line_items']) : [];
 | 
			
		||||
 | 
			
		||||
        $input['amount'] = 0;
 | 
			
		||||
        $input['balance'] = 0;
 | 
			
		||||
 | 
			
		||||
        $this->replace($input);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -14,6 +14,7 @@ namespace App\Http\Requests\PurchaseOrder;
 | 
			
		||||
 | 
			
		||||
use App\Http\Requests\Request;
 | 
			
		||||
use App\Utils\Traits\ChecksEntityStatus;
 | 
			
		||||
use App\Utils\Traits\CleanLineItems;
 | 
			
		||||
use App\Utils\Traits\MakesHash;
 | 
			
		||||
use Illuminate\Validation\Rule;
 | 
			
		||||
 | 
			
		||||
@ -21,6 +22,7 @@ class UpdatePurchaseOrderRequest extends Request
 | 
			
		||||
{
 | 
			
		||||
    use ChecksEntityStatus;
 | 
			
		||||
    use MakesHash;
 | 
			
		||||
    use CleanLineItems;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Determine if the user is authorized to make this request.
 | 
			
		||||
@ -57,6 +59,10 @@ class UpdatePurchaseOrderRequest extends Request
 | 
			
		||||
 | 
			
		||||
        $input['id'] = $this->purchase_order->id;
 | 
			
		||||
 | 
			
		||||
        if (isset($input['line_items']) && is_array($input['line_items'])) {
 | 
			
		||||
            $input['line_items'] = isset($input['line_items']) ? $this->cleanItems($input['line_items']) : [];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $this->replace($input);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1423,21 +1423,21 @@ class CompanyImport implements ShouldQueue
 | 
			
		||||
                $new_obj->company_id = $this->company->id;
 | 
			
		||||
                $new_obj->fill($obj_array);
 | 
			
		||||
                $new_obj->save(['timestamps' => false]);
 | 
			
		||||
                $new_obj->number = $this->getNextInvoiceNumber($client = Client::find($obj_array['client_id']),$new_obj);
 | 
			
		||||
                $new_obj->number = $this->getNextInvoiceNumber($client = Client::withTrashed()->find($obj_array['client_id']),$new_obj);
 | 
			
		||||
            }
 | 
			
		||||
            elseif($class == 'App\Models\Payment' && is_null($obj->{$match_key})){
 | 
			
		||||
                $new_obj = new Payment();
 | 
			
		||||
                $new_obj->company_id = $this->company->id;
 | 
			
		||||
                $new_obj->fill($obj_array);
 | 
			
		||||
                $new_obj->save(['timestamps' => false]);
 | 
			
		||||
                $new_obj->number = $this->getNextPaymentNumber($client = Client::find($obj_array['client_id']), $new_obj);
 | 
			
		||||
                $new_obj->number = $this->getNextPaymentNumber($client = Client::withTrashed()->find($obj_array['client_id']), $new_obj);
 | 
			
		||||
            }
 | 
			
		||||
            elseif($class == 'App\Models\Quote' && is_null($obj->{$match_key})){
 | 
			
		||||
                $new_obj = new Quote();
 | 
			
		||||
                $new_obj->company_id = $this->company->id;
 | 
			
		||||
                $new_obj->fill($obj_array);
 | 
			
		||||
                $new_obj->save(['timestamps' => false]);
 | 
			
		||||
                $new_obj->number = $this->getNextQuoteNumber($client = Client::find($obj_array['client_id']), $new_obj);
 | 
			
		||||
                $new_obj->number = $this->getNextQuoteNumber($client = Client::withTrashed()->find($obj_array['client_id']), $new_obj);
 | 
			
		||||
            }
 | 
			
		||||
            elseif($class == 'App\Models\ClientContact'){
 | 
			
		||||
                $new_obj = new ClientContact();
 | 
			
		||||
 | 
			
		||||
@ -200,6 +200,14 @@ class NinjaMailerJob implements ShouldQueue
 | 
			
		||||
 | 
			
		||||
        $user = User::find($this->decodePrimaryKey($sending_user));
 | 
			
		||||
        
 | 
			
		||||
        /* Always ensure the user is set on the correct account */
 | 
			
		||||
        if($user->account_id != $this->company->account_id){
 | 
			
		||||
 | 
			
		||||
            $this->nmo->settings->email_sending_method = 'default';
 | 
			
		||||
            return $this->setMailDriver();
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        nlog("Sending via {$user->name()}");
 | 
			
		||||
 | 
			
		||||
        $token = $this->refreshOfficeToken($user);
 | 
			
		||||
@ -236,6 +244,14 @@ class NinjaMailerJob implements ShouldQueue
 | 
			
		||||
 | 
			
		||||
        $user = User::find($this->decodePrimaryKey($sending_user));
 | 
			
		||||
 | 
			
		||||
        /* Always ensure the user is set on the correct account */
 | 
			
		||||
        if($user->account_id != $this->company->account_id){
 | 
			
		||||
 | 
			
		||||
            $this->nmo->settings->email_sending_method = 'default';
 | 
			
		||||
            return $this->setMailDriver();
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        nlog("Sending via {$user->name()}");
 | 
			
		||||
 | 
			
		||||
        $google = (new Google())->init();
 | 
			
		||||
@ -292,8 +308,9 @@ class NinjaMailerJob implements ShouldQueue
 | 
			
		||||
 | 
			
		||||
    private function preFlightChecksFail()
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
        /* If we are migrating data we don't want to fire any emails */
 | 
			
		||||
        if ($this->nmo->company->is_disabled && !$this->override) 
 | 
			
		||||
        if($this->company->is_disabled && !$this->override) 
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
        /* On the hosted platform we set default contacts a @example.com email address - we shouldn't send emails to these types of addresses */
 | 
			
		||||
@ -301,17 +318,25 @@ class NinjaMailerJob implements ShouldQueue
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
        /* GMail users are uncapped */
 | 
			
		||||
        if(Ninja::isHosted() && $this->nmo->settings->email_sending_method == 'gmail')
 | 
			
		||||
        if(Ninja::isHosted() && ($this->nmo->settings->email_sending_method == 'gmail' || $this->nmo->settings->email_sending_method == 'office365')) 
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        /* On the hosted platform, if the user is over the email quotas, we do not send the email. */
 | 
			
		||||
        if(Ninja::isHosted() && $this->company->account && $this->company->account->emailQuotaExceeded())
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
        /* To handle spam users we drop all emails from flagged accounts */
 | 
			
		||||
        if(Ninja::isHosted() && $this->company->account && $this->company->account->is_flagged) 
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
        /* Ensure the user has a valid email address */
 | 
			
		||||
        if(!str_contains($this->nmo->to_user->email, "@"))
 | 
			
		||||
            return true;
 | 
			
		||||
     
 | 
			
		||||
        /* On the hosted platform we actively scan all outbound emails to ensure outbound email quality remains high */
 | 
			
		||||
        // if(Ninja::isHosted())
 | 
			
		||||
        //     return (new \Modules\Admin\Jobs\Account\EmailQuality($this->nmo, $this->company))->run();
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -341,6 +366,10 @@ class NinjaMailerJob implements ShouldQueue
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function refreshOfficeToken($user)
 | 
			
		||||
    {
 | 
			
		||||
        $expiry = $user->oauth_user_token_expiry ?: now()->subDay();
 | 
			
		||||
 | 
			
		||||
        if($expiry->lt(now()))
 | 
			
		||||
        {
 | 
			
		||||
            $guzzle = new \GuzzleHttp\Client(); 
 | 
			
		||||
            $url = 'https://login.microsoftonline.com/common/oauth2/v2.0/token'; 
 | 
			
		||||
@ -349,16 +378,37 @@ class NinjaMailerJob implements ShouldQueue
 | 
			
		||||
                'form_params' => [
 | 
			
		||||
                    'client_id' => config('ninja.o365.client_id') ,
 | 
			
		||||
                    'client_secret' => config('ninja.o365.client_secret') ,
 | 
			
		||||
                'scope' => 'email Mail.ReadWrite Mail.Send offline_access profile User.Read openid',
 | 
			
		||||
                    'scope' => 'email Mail.Send offline_access profile User.Read openid',
 | 
			
		||||
                    'grant_type' => 'refresh_token',
 | 
			
		||||
                    'refresh_token' => $user->oauth_user_refresh_token
 | 
			
		||||
                ],
 | 
			
		||||
            ])->getBody()->getContents());
 | 
			
		||||
 | 
			
		||||
        if($token)
 | 
			
		||||
            nlog($token);
 | 
			
		||||
            
 | 
			
		||||
            if($token){
 | 
			
		||||
                
 | 
			
		||||
                $user->oauth_user_refresh_token = property_exists($token, 'refresh_token') ? $token->refresh_token : $user->oauth_user_refresh_token;
 | 
			
		||||
                $user->oauth_user_token = $token->access_token;
 | 
			
		||||
                $user->oauth_user_token_expiry = now()->addSeconds($token->expires_in);
 | 
			
		||||
                $user->save();
 | 
			
		||||
 | 
			
		||||
                return $token->access_token;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $user->oauth_user_refresh_token;
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Is this the cleanest way to requeue a job?
 | 
			
		||||
     * 
 | 
			
		||||
     * $this->delete();
 | 
			
		||||
     *
 | 
			
		||||
     * $job = NinjaMailerJob::dispatch($this->nmo, $this->override)->delay(3600);
 | 
			
		||||
    */
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										53
									
								
								app/Jobs/Vendor/CreatePurchaseOrderPdf.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										53
									
								
								app/Jobs/Vendor/CreatePurchaseOrderPdf.php
									
									
									
									
										vendored
									
									
								
							@ -65,6 +65,10 @@ class CreatePurchaseOrderPdf implements ShouldQueue
 | 
			
		||||
 | 
			
		||||
    public $vendor;
 | 
			
		||||
 | 
			
		||||
    private string $path = '';
 | 
			
		||||
 | 
			
		||||
    private string $file_path = '';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create a new job instance.
 | 
			
		||||
     *
 | 
			
		||||
@ -88,6 +92,32 @@ class CreatePurchaseOrderPdf implements ShouldQueue
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function handle()
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
        $pdf = $this->rawPdf();
 | 
			
		||||
 | 
			
		||||
        if ($pdf) {
 | 
			
		||||
 | 
			
		||||
            try{
 | 
			
		||||
                
 | 
			
		||||
                if(!Storage::disk($this->disk)->exists($this->path)) 
 | 
			
		||||
                    Storage::disk($this->disk)->makeDirectory($this->path, 0775);
 | 
			
		||||
 | 
			
		||||
                Storage::disk($this->disk)->put($this->file_path, $pdf, 'public');
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
            catch(\Exception $e)
 | 
			
		||||
            {
 | 
			
		||||
 | 
			
		||||
                throw new FilePermissionsFailure($e->getMessage());
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        return $this->file_path;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function rawPdf()
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
        MultiDB::setDb($this->company->db);
 | 
			
		||||
@ -109,10 +139,10 @@ class CreatePurchaseOrderPdf implements ShouldQueue
 | 
			
		||||
 | 
			
		||||
        $entity_design_id = '';
 | 
			
		||||
        
 | 
			
		||||
        $path = $this->vendor->purchase_order_filepath($this->invitation);
 | 
			
		||||
        $this->path = $this->vendor->purchase_order_filepath($this->invitation);
 | 
			
		||||
        $entity_design_id = 'purchase_order_design_id';
 | 
			
		||||
 | 
			
		||||
        $file_path = $path.$this->entity->numberFormatter().'.pdf';
 | 
			
		||||
        $this->file_path = $this->path.$this->entity->numberFormatter().'.pdf';
 | 
			
		||||
 | 
			
		||||
        $entity_design_id = $this->entity->design_id ? $this->entity->design_id : $this->decodePrimaryKey('Wpmbk5ezJn');
 | 
			
		||||
 | 
			
		||||
@ -191,25 +221,8 @@ class CreatePurchaseOrderPdf implements ShouldQueue
 | 
			
		||||
            info($maker->getCompiledHTML());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ($pdf) {
 | 
			
		||||
        return $pdf;
 | 
			
		||||
 | 
			
		||||
            try{
 | 
			
		||||
                
 | 
			
		||||
                if(!Storage::disk($this->disk)->exists($path)) 
 | 
			
		||||
                    Storage::disk($this->disk)->makeDirectory($path, 0775);
 | 
			
		||||
 | 
			
		||||
                Storage::disk($this->disk)->put($file_path, $pdf, 'public');
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
            catch(\Exception $e)
 | 
			
		||||
            {
 | 
			
		||||
 | 
			
		||||
                throw new FilePermissionsFailure($e->getMessage());
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        return $file_path;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function failed($e)
 | 
			
		||||
 | 
			
		||||
@ -33,7 +33,7 @@ class Account extends BaseModel
 | 
			
		||||
    use PresentableTrait;
 | 
			
		||||
    use MakesHash;
 | 
			
		||||
 | 
			
		||||
    private $free_plan_email_quota = 250;
 | 
			
		||||
    private $free_plan_email_quota = 100;
 | 
			
		||||
 | 
			
		||||
    private $paid_plan_email_quota = 500;
 | 
			
		||||
    /**
 | 
			
		||||
@ -373,10 +373,15 @@ class Account extends BaseModel
 | 
			
		||||
 | 
			
		||||
    public function getDailyEmailLimit()
 | 
			
		||||
    {
 | 
			
		||||
        if($this->is_flagged)
 | 
			
		||||
            return 0;
 | 
			
		||||
 | 
			
		||||
        if(Carbon::createFromTimestamp($this->created_at)->diffInWeeks() == 0)
 | 
			
		||||
            return 20;
 | 
			
		||||
 | 
			
		||||
        if(Carbon::createFromTimestamp($this->created_at)->diffInWeeks() <= 2 && !$this->payment_id)
 | 
			
		||||
            return 20;
 | 
			
		||||
 | 
			
		||||
        if($this->isPaid()){
 | 
			
		||||
            $limit = $this->paid_plan_email_quota;
 | 
			
		||||
            $limit += Carbon::createFromTimestamp($this->created_at)->diffInMonths() * 100;
 | 
			
		||||
 | 
			
		||||
@ -63,6 +63,8 @@ class Gateway extends StaticModel
 | 
			
		||||
            $link = 'https://applications.sagepay.com/apply/2C02C252-0F8A-1B84-E10D-CF933EFCAA99';
 | 
			
		||||
        } elseif ($this->id == 20 || $this->id == 56) {
 | 
			
		||||
            $link = 'https://dashboard.stripe.com/account/apikeys';
 | 
			
		||||
        } elseif ($this->id == 59) {
 | 
			
		||||
            $link = 'https://www.forte.net/';
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $link;
 | 
			
		||||
@ -170,6 +172,12 @@ class Gateway extends StaticModel
 | 
			
		||||
                    GatewayType::HOSTED_PAGE => ['refund' => false, 'token_billing' => false, 'webhooks' => [' ']] // Razorpay
 | 
			
		||||
                ];
 | 
			
		||||
                break;
 | 
			
		||||
            case 59:
 | 
			
		||||
                return [
 | 
			
		||||
                    GatewayType::CREDIT_CARD => ['refund' => true, 'token_billing' => true], // Forte
 | 
			
		||||
                    GatewayType::BANK_TRANSFER => ['refund' => true, 'token_billing' => true, 'webhooks' => [' ']],
 | 
			
		||||
                ];
 | 
			
		||||
                break;
 | 
			
		||||
            default:
 | 
			
		||||
                return [];
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
@ -126,6 +126,26 @@ class CompanyPresenter extends EntityPresenter
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function address1()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->entity->settings->address1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function address2()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->entity->settings->address2;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function qr_iban()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->entity->getSetting('qr_iban');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function besr_id()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->entity->getSetting('besr_id');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getSpcQrCode($client_currency, $invoice_number, $balance_due_raw, $user_iban)
 | 
			
		||||
    {
 | 
			
		||||
        $settings = $this->entity->settings;
 | 
			
		||||
 | 
			
		||||
@ -34,7 +34,6 @@ class PurchaseOrder extends BaseModel
 | 
			
		||||
        'discount',
 | 
			
		||||
        'company_id',
 | 
			
		||||
        'status_id',
 | 
			
		||||
        'user_id',
 | 
			
		||||
        'last_sent_date',
 | 
			
		||||
        'is_deleted',
 | 
			
		||||
        'po_number',
 | 
			
		||||
@ -84,7 +83,7 @@ class PurchaseOrder extends BaseModel
 | 
			
		||||
        'balance',
 | 
			
		||||
        'partial',
 | 
			
		||||
        'paid_to_date',
 | 
			
		||||
        'subscription_id',
 | 
			
		||||
        // 'subscription_id',
 | 
			
		||||
        'vendor_id',
 | 
			
		||||
        'last_viewed'
 | 
			
		||||
    ];
 | 
			
		||||
@ -154,7 +153,7 @@ class PurchaseOrder extends BaseModel
 | 
			
		||||
 | 
			
		||||
    public function vendor()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->belongsTo(Vendor::class);
 | 
			
		||||
        return $this->belongsTo(Vendor::class)->withTrashed();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function history()
 | 
			
		||||
 | 
			
		||||
@ -106,6 +106,7 @@ class User extends Authenticatable implements MustVerifyEmail
 | 
			
		||||
        'updated_at'       => 'timestamp',
 | 
			
		||||
        'created_at'       => 'timestamp',
 | 
			
		||||
        'deleted_at'       => 'timestamp',
 | 
			
		||||
        'oauth_user_token_expiry' => 'datetime',
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										93
									
								
								app/Notifications/Ninja/NewAccountNotification.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								app/Notifications/Ninja/NewAccountNotification.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,93 @@
 | 
			
		||||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * Invoice Ninja (https://invoiceninja.com).
 | 
			
		||||
 *
 | 
			
		||||
 * @link https://github.com/invoiceninja/invoiceninja source repository
 | 
			
		||||
 *
 | 
			
		||||
 * @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
 | 
			
		||||
 *
 | 
			
		||||
 * @license https://www.elastic.co/licensing/elastic-license
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
namespace App\Notifications\Ninja;
 | 
			
		||||
 | 
			
		||||
use App\Models\Account;
 | 
			
		||||
use App\Models\Client;
 | 
			
		||||
use Illuminate\Bus\Queueable;
 | 
			
		||||
use Illuminate\Contracts\Queue\ShouldQueue;
 | 
			
		||||
use Illuminate\Foundation\Bus\Dispatchable;
 | 
			
		||||
use Illuminate\Notifications\Messages\MailMessage;
 | 
			
		||||
use Illuminate\Notifications\Messages\SlackMessage;
 | 
			
		||||
use Illuminate\Notifications\Notification;
 | 
			
		||||
use Illuminate\Queue\InteractsWithQueue;
 | 
			
		||||
use Illuminate\Queue\SerializesModels;
 | 
			
		||||
 | 
			
		||||
class NewAccountNotification extends Notification 
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create a new notification instance.
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    protected Account $account;
 | 
			
		||||
 | 
			
		||||
    protected Client $client;
 | 
			
		||||
 | 
			
		||||
    public function __construct(Account $account, Client $client)
 | 
			
		||||
    {
 | 
			
		||||
        $this->account = $account;
 | 
			
		||||
        $this->client = $client;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the notification's delivery channels.
 | 
			
		||||
     *
 | 
			
		||||
     * @param  mixed  $notifiable
 | 
			
		||||
     * @return array
 | 
			
		||||
     */
 | 
			
		||||
    public function via($notifiable)
 | 
			
		||||
    {
 | 
			
		||||
        return ['slack'];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the mail representation of the notification.
 | 
			
		||||
     *
 | 
			
		||||
     * @param  mixed  $notifiable
 | 
			
		||||
     * @return MailMessage
 | 
			
		||||
     */
 | 
			
		||||
    public function toMail($notifiable)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the array representation of the notification.
 | 
			
		||||
     *
 | 
			
		||||
     * @param  mixed  $notifiable
 | 
			
		||||
     * @return array
 | 
			
		||||
     */
 | 
			
		||||
    public function toArray($notifiable)
 | 
			
		||||
    {
 | 
			
		||||
        return [
 | 
			
		||||
            //
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function toSlack($notifiable)
 | 
			
		||||
    {
 | 
			
		||||
        $content = "New Trial Started\n";
 | 
			
		||||
        $content = "{$this->client->name}\n";
 | 
			
		||||
        $content = "Account key: {$this->account->key}\n";
 | 
			
		||||
        $content = "Users: {$this->account->users()->pluck('email')}\n";
 | 
			
		||||
        $content = "Contacts: {$this->client->contacts()->pluck('email')}\n";
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        return (new SlackMessage)
 | 
			
		||||
                ->success()
 | 
			
		||||
                ->from(ctrans('texts.notification_bot'))
 | 
			
		||||
                ->image('https://app.invoiceninja.com/favicon.png')
 | 
			
		||||
                ->content($content);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										121
									
								
								app/Notifications/Ninja/SpamNotification.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								app/Notifications/Ninja/SpamNotification.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,121 @@
 | 
			
		||||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * Invoice Ninja (https://invoiceninja.com).
 | 
			
		||||
 *
 | 
			
		||||
 * @link https://github.com/invoiceninja/invoiceninja source repository
 | 
			
		||||
 *
 | 
			
		||||
 * @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
 | 
			
		||||
 *
 | 
			
		||||
 * @license https://www.elastic.co/licensing/elastic-license
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
namespace App\Notifications\Ninja;
 | 
			
		||||
 | 
			
		||||
use Illuminate\Bus\Queueable;
 | 
			
		||||
use Illuminate\Contracts\Queue\ShouldQueue;
 | 
			
		||||
use Illuminate\Foundation\Bus\Dispatchable;
 | 
			
		||||
use Illuminate\Notifications\Messages\MailMessage;
 | 
			
		||||
use Illuminate\Notifications\Messages\SlackMessage;
 | 
			
		||||
use Illuminate\Notifications\Notification;
 | 
			
		||||
use Illuminate\Queue\InteractsWithQueue;
 | 
			
		||||
use Illuminate\Queue\SerializesModels;
 | 
			
		||||
 | 
			
		||||
class SpamNotification extends Notification 
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create a new notification instance.
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    protected array $spam_list;
 | 
			
		||||
 | 
			
		||||
    public function __construct($spam_list)
 | 
			
		||||
    {
 | 
			
		||||
        $this->spam_list = $spam_list;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the notification's delivery channels.
 | 
			
		||||
     *
 | 
			
		||||
     * @param  mixed  $notifiable
 | 
			
		||||
     * @return array
 | 
			
		||||
     */
 | 
			
		||||
    public function via($notifiable)
 | 
			
		||||
    {
 | 
			
		||||
        return ['slack'];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the mail representation of the notification.
 | 
			
		||||
     *
 | 
			
		||||
     * @param  mixed  $notifiable
 | 
			
		||||
     * @return MailMessage
 | 
			
		||||
     */
 | 
			
		||||
    public function toMail($notifiable)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the array representation of the notification.
 | 
			
		||||
     *
 | 
			
		||||
     * @param  mixed  $notifiable
 | 
			
		||||
     * @return array
 | 
			
		||||
     */
 | 
			
		||||
    public function toArray($notifiable)
 | 
			
		||||
    {
 | 
			
		||||
        return [
 | 
			
		||||
            //
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function toSlack($notifiable)
 | 
			
		||||
    {
 | 
			
		||||
        $content = '';
 | 
			
		||||
 | 
			
		||||
        foreach($this->spam_list as $spam_list)
 | 
			
		||||
        {
 | 
			
		||||
 | 
			
		||||
            if(array_key_exists('companies', $spam_list))
 | 
			
		||||
            {
 | 
			
		||||
                $content .= " Companies \n";
 | 
			
		||||
 | 
			
		||||
                foreach($spam_list['companies'] as $company)
 | 
			
		||||
                {
 | 
			
		||||
                    $content .= "{$company['name']} - c_key={$company['company_key']} - a_key={$company['account_key']} - {$company['owner']} \n";
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if(array_key_exists('templates', $spam_list))
 | 
			
		||||
            {
 | 
			
		||||
                $content .= " Templates \n";
 | 
			
		||||
 | 
			
		||||
                foreach($spam_list['templates'] as $company)
 | 
			
		||||
                {
 | 
			
		||||
                    $content .= "{$company['name']} - c_key={$company['company_key']} - a_key={$company['account_key']} - {$company['owner']} \n";
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            if(array_key_exists('users', $spam_list))
 | 
			
		||||
            {
 | 
			
		||||
 | 
			
		||||
                $content .= ' Users \n';
 | 
			
		||||
 | 
			
		||||
                foreach($spam_list['users'] as $user)
 | 
			
		||||
                {
 | 
			
		||||
                    $content .= "{$user['email']} - a_key={$user['account_key']} - created={$user['created']} \n";
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return (new SlackMessage)
 | 
			
		||||
                ->success()
 | 
			
		||||
                ->from(ctrans('texts.notification_bot'))
 | 
			
		||||
                ->image('https://app.invoiceninja.com/favicon.png')
 | 
			
		||||
                ->content($content);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										150
									
								
								app/PaymentDrivers/Forte/ACH.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								app/PaymentDrivers/Forte/ACH.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,150 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Invoice Ninja (https://invoiceninja.com).
 | 
			
		||||
 *
 | 
			
		||||
 * @link https://github.com/invoiceninja/invoiceninja source repository
 | 
			
		||||
 *
 | 
			
		||||
 * @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
 | 
			
		||||
 *
 | 
			
		||||
 * @license https://www.elastic.co/licensing/elastic-license
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
namespace App\PaymentDrivers\Forte;
 | 
			
		||||
 | 
			
		||||
use App\Models\Payment;
 | 
			
		||||
use App\Models\GatewayType;
 | 
			
		||||
use App\Models\PaymentHash;
 | 
			
		||||
use App\Models\PaymentType;
 | 
			
		||||
use App\Http\Requests\Request;
 | 
			
		||||
use App\Utils\Traits\MakesHash;
 | 
			
		||||
use Illuminate\Support\Facades\Validator;
 | 
			
		||||
use App\PaymentDrivers\FortePaymentDriver;
 | 
			
		||||
 | 
			
		||||
class ACH
 | 
			
		||||
{
 | 
			
		||||
    use MakesHash;
 | 
			
		||||
    
 | 
			
		||||
    public $forte;
 | 
			
		||||
 | 
			
		||||
    private $forte_base_uri="";
 | 
			
		||||
    private $forte_api_access_id="";
 | 
			
		||||
    private $forte_secure_key="";
 | 
			
		||||
    private $forte_auth_organization_id="";
 | 
			
		||||
    private $forte_organization_id="";
 | 
			
		||||
    private $forte_location_id="";
 | 
			
		||||
    
 | 
			
		||||
    public function __construct(FortePaymentDriver $forte)
 | 
			
		||||
    {
 | 
			
		||||
        $this->forte = $forte;
 | 
			
		||||
 | 
			
		||||
        $this->forte_base_uri = "https://sandbox.forte.net/api/v3/";
 | 
			
		||||
        if($this->forte->company_gateway->getConfigField('testMode') == false){
 | 
			
		||||
            $this->forte_base_uri = "https://api.forte.net/v3/";
 | 
			
		||||
        }
 | 
			
		||||
        $this->forte_api_access_id = $this->forte->company_gateway->getConfigField('apiAccessId');
 | 
			
		||||
        $this->forte_secure_key = $this->forte->company_gateway->getConfigField('secureKey');
 | 
			
		||||
        $this->forte_auth_organization_id = $this->forte->company_gateway->getConfigField('authOrganizationId');
 | 
			
		||||
        $this->forte_organization_id = $this->forte->company_gateway->getConfigField('organizationId');
 | 
			
		||||
        $this->forte_location_id = $this->forte->company_gateway->getConfigField('locationId');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function authorizeView(array $data)
 | 
			
		||||
    {
 | 
			
		||||
        return render('gateways.forte.ach.authorize', $data);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function authorizeResponse(Request $request)
 | 
			
		||||
    {
 | 
			
		||||
        
 | 
			
		||||
        $payment_meta = new \stdClass;
 | 
			
		||||
        $payment_meta->brand = (string)ctrans('texts.ach');
 | 
			
		||||
        $payment_meta->last4 = (string) $request->last_4;
 | 
			
		||||
        $payment_meta->exp_year = '-';
 | 
			
		||||
        $payment_meta->type = GatewayType::BANK_TRANSFER;
 | 
			
		||||
 | 
			
		||||
        $data = [
 | 
			
		||||
            'payment_meta' => $payment_meta,
 | 
			
		||||
            'token' => $request->one_time_token,
 | 
			
		||||
            'payment_method_id' => $request->gateway_type_id,
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        $this->forte->storeGatewayToken($data);
 | 
			
		||||
 | 
			
		||||
        return redirect()->route('client.payment_methods.index')->withSuccess('Payment Method added.');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function paymentView(array $data)
 | 
			
		||||
    {
 | 
			
		||||
        $this->forte->payment_hash->data = array_merge((array) $this->forte->payment_hash->data, $data);
 | 
			
		||||
        $this->forte->payment_hash->save();
 | 
			
		||||
 | 
			
		||||
        $data['gateway'] = $this;
 | 
			
		||||
        return render('gateways.forte.ach.pay', $data);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function paymentResponse($request)
 | 
			
		||||
    {
 | 
			
		||||
        $payment_hash = PaymentHash::whereRaw('BINARY `hash`= ?', [$request->input('payment_hash')])->firstOrFail();
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            $curl = curl_init();
 | 
			
		||||
            curl_setopt_array($curl, array(
 | 
			
		||||
            CURLOPT_URL => $this->forte_base_uri.'organizations/'.$this->forte_organization_id.'/locations/'.$this->forte_location_id.'/transactions',
 | 
			
		||||
            CURLOPT_RETURNTRANSFER => true,
 | 
			
		||||
            CURLOPT_ENCODING => '',
 | 
			
		||||
            CURLOPT_MAXREDIRS => 10,
 | 
			
		||||
            CURLOPT_TIMEOUT => 0,
 | 
			
		||||
            CURLOPT_FOLLOWLOCATION => true,
 | 
			
		||||
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
 | 
			
		||||
            CURLOPT_CUSTOMREQUEST => 'POST',
 | 
			
		||||
            CURLOPT_POSTFIELDS =>'{
 | 
			
		||||
                "action":"sale",
 | 
			
		||||
                "authorization_amount": '.$payment_hash->data->total->amount_with_fee.',
 | 
			
		||||
                "echeck":{
 | 
			
		||||
                    "sec_code":"PPD",
 | 
			
		||||
                },
 | 
			
		||||
                "billing_address":{
 | 
			
		||||
                    "first_name": "'.$this->forte->client->name.'",
 | 
			
		||||
                    "last_name": "'.$this->forte->client->name.'"
 | 
			
		||||
                },
 | 
			
		||||
                "echeck":{
 | 
			
		||||
                   "one_time_token":"'.$request->payment_token.'"
 | 
			
		||||
                }
 | 
			
		||||
            }',
 | 
			
		||||
            CURLOPT_HTTPHEADER => array(
 | 
			
		||||
                'X-Forte-Auth-Organization-Id: '.$this->forte_organization_id,
 | 
			
		||||
                'Content-Type: application/json',
 | 
			
		||||
                'Authorization: Basic '.base64_encode($this->forte_api_access_id.':'.$this->forte_secure_key),
 | 
			
		||||
                'Cookie: visid_incap_621087=u18+3REYR/iISgzZxOF5s2ODW2IAAAAAQUIPAAAAAADuGqKgECQLS81FcSDrmhGe; nlbi_621087=YHngadhJ2VU+yr7/R1efXgAAAAD3mQyhqmnLls8PRu4iN58G; incap_ses_1136_621087=CVdrXUdhIlm9WJNDieLDD4QVXGIAAAAAvBwvkUcwhM0+OwvdPm2stg=='
 | 
			
		||||
            ),
 | 
			
		||||
            ));
 | 
			
		||||
 | 
			
		||||
            $response = curl_exec($curl);
 | 
			
		||||
            $httpcode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
 | 
			
		||||
 | 
			
		||||
            curl_close($curl);
 | 
			
		||||
 | 
			
		||||
            $response=json_decode($response);
 | 
			
		||||
        } catch (\Throwable $th) {
 | 
			
		||||
            throw $th;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        if ($httpcode>299) {
 | 
			
		||||
            $error = Validator::make([], []);
 | 
			
		||||
            $error->getMessageBag()->add('gateway_error', $response->response->response_desc);
 | 
			
		||||
            return redirect('client/invoices')->withErrors($error);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $data = [
 | 
			
		||||
            'payment_method' => $request->payment_method_id,
 | 
			
		||||
            'payment_type' => PaymentType::ACH,
 | 
			
		||||
            'amount' => $payment_hash->data->amount_with_fee,
 | 
			
		||||
            'transaction_reference' => $response->transaction_id,
 | 
			
		||||
            'gateway_type_id' => GatewayType::BANK_TRANSFER,
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        $payment=$this->forte->createPayment($data, Payment::STATUS_COMPLETED);
 | 
			
		||||
        return redirect('client/invoices')->withSuccess('Invoice paid.');
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										160
									
								
								app/PaymentDrivers/Forte/CreditCard.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										160
									
								
								app/PaymentDrivers/Forte/CreditCard.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,160 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Invoice Ninja (https://invoiceninja.com).
 | 
			
		||||
 *
 | 
			
		||||
 * @link https://github.com/invoiceninja/invoiceninja source repository
 | 
			
		||||
 *
 | 
			
		||||
 * @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
 | 
			
		||||
 *
 | 
			
		||||
 * @license https://www.elastic.co/licensing/elastic-license
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
namespace App\PaymentDrivers\Forte;
 | 
			
		||||
 | 
			
		||||
use App\Models\Payment;
 | 
			
		||||
use App\Models\GatewayType;
 | 
			
		||||
use App\Models\PaymentHash;
 | 
			
		||||
use App\Models\PaymentType;
 | 
			
		||||
use App\Utils\Traits\MakesHash;
 | 
			
		||||
use Illuminate\Support\Facades\Session;
 | 
			
		||||
use Illuminate\Support\Facades\Validator;
 | 
			
		||||
use App\PaymentDrivers\FortePaymentDriver;
 | 
			
		||||
use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest;
 | 
			
		||||
 | 
			
		||||
class CreditCard
 | 
			
		||||
{
 | 
			
		||||
    use MakesHash;
 | 
			
		||||
    
 | 
			
		||||
    public $forte;
 | 
			
		||||
 | 
			
		||||
    private $forte_base_uri="";
 | 
			
		||||
    private $forte_api_access_id="";
 | 
			
		||||
    private $forte_secure_key="";
 | 
			
		||||
    private $forte_auth_organization_id="";
 | 
			
		||||
    private $forte_organization_id="";
 | 
			
		||||
    private $forte_location_id="";
 | 
			
		||||
    
 | 
			
		||||
    public function __construct(FortePaymentDriver $forte)
 | 
			
		||||
    {
 | 
			
		||||
        $this->forte = $forte;
 | 
			
		||||
 | 
			
		||||
        $this->forte_base_uri = "https://sandbox.forte.net/api/v3/";
 | 
			
		||||
            if($this->forte->company_gateway->getConfigField('testMode') == false){
 | 
			
		||||
                $this->forte_base_uri = "https://api.forte.net/v3/";
 | 
			
		||||
            }
 | 
			
		||||
        $this->forte_api_access_id = $this->forte->company_gateway->getConfigField('apiAccessId');
 | 
			
		||||
        $this->forte_secure_key = $this->forte->company_gateway->getConfigField('secureKey');
 | 
			
		||||
        $this->forte_auth_organization_id = $this->forte->company_gateway->getConfigField('authOrganizationId');
 | 
			
		||||
        $this->forte_organization_id = $this->forte->company_gateway->getConfigField('organizationId');
 | 
			
		||||
        $this->forte_location_id = $this->forte->company_gateway->getConfigField('locationId');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function authorizeView(array $data)
 | 
			
		||||
    {
 | 
			
		||||
        return render('gateways.forte.credit_card.authorize', $data);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function authorizeResponse($request)
 | 
			
		||||
    {
 | 
			
		||||
        $payment_meta = new \stdClass;
 | 
			
		||||
        $payment_meta->exp_month = (string) $request->expire_month;
 | 
			
		||||
        $payment_meta->exp_year = (string) $request->expire_year;
 | 
			
		||||
        $payment_meta->brand = (string) $request->card_type;
 | 
			
		||||
        $payment_meta->last4 = (string) $request->last_4;
 | 
			
		||||
        $payment_meta->type = GatewayType::CREDIT_CARD;
 | 
			
		||||
 | 
			
		||||
        $data = [
 | 
			
		||||
            'payment_meta' => $payment_meta,
 | 
			
		||||
            'token' => $request->one_time_token,
 | 
			
		||||
            'payment_method_id' => $request->payment_method_id,
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        $this->forte->storeGatewayToken($data);
 | 
			
		||||
 | 
			
		||||
        return redirect()->route('client.payment_methods.index')->withSuccess('Payment Method added.');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function paymentView(array $data)
 | 
			
		||||
    {
 | 
			
		||||
        $this->forte->payment_hash->data = array_merge((array) $this->forte->payment_hash->data, $data);
 | 
			
		||||
        $this->forte->payment_hash->save();
 | 
			
		||||
 | 
			
		||||
        $data['gateway'] = $this;
 | 
			
		||||
        return render('gateways.forte.credit_card.pay', $data);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function paymentResponse(PaymentResponseRequest $request)
 | 
			
		||||
    {
 | 
			
		||||
        $payment_hash = PaymentHash::whereRaw('BINARY `hash`= ?', [$request->input('payment_hash')])->firstOrFail();
 | 
			
		||||
        $amount_with_fee = $payment_hash->data->total->amount_with_fee;
 | 
			
		||||
        $invoice_totals = $payment_hash->data->total->invoice_totals;
 | 
			
		||||
        $fee_total = 0;
 | 
			
		||||
 | 
			
		||||
        for ($i = ($invoice_totals * 100) ; $i < ($amount_with_fee * 100); $i++) { 
 | 
			
		||||
            $calculated_fee = ( 3 * $i) / 100;
 | 
			
		||||
            $calculated_amount_with_fee = round(($i + $calculated_fee) / 100,2);
 | 
			
		||||
            if ($calculated_amount_with_fee == $amount_with_fee) {
 | 
			
		||||
                $fee_total = round($calculated_fee / 100,2);
 | 
			
		||||
                $amount_with_fee = $calculated_amount_with_fee;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        try {
 | 
			
		||||
            $curl = curl_init();
 | 
			
		||||
 | 
			
		||||
            curl_setopt_array($curl, array(
 | 
			
		||||
                CURLOPT_URL => $this->forte_base_uri.'organizations/'.$this->forte_organization_id.'/locations/'.$this->forte_location_id.'/transactions',
 | 
			
		||||
                CURLOPT_RETURNTRANSFER => true,
 | 
			
		||||
                CURLOPT_ENCODING => '',
 | 
			
		||||
                CURLOPT_MAXREDIRS => 10,
 | 
			
		||||
                CURLOPT_TIMEOUT => 0,
 | 
			
		||||
                CURLOPT_FOLLOWLOCATION => true,
 | 
			
		||||
                CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
 | 
			
		||||
                CURLOPT_CUSTOMREQUEST => 'POST',
 | 
			
		||||
                CURLOPT_POSTFIELDS =>'{
 | 
			
		||||
                     "action":"sale", 
 | 
			
		||||
                     "authorization_amount":'.$amount_with_fee.',
 | 
			
		||||
                     "service_fee_amount":'.$fee_total.',
 | 
			
		||||
                     "billing_address":{
 | 
			
		||||
                        "first_name":"'.$this->forte->client->name.'",
 | 
			
		||||
                        "last_name":"'.$this->forte->client->name.'"
 | 
			
		||||
                     },
 | 
			
		||||
                     "card":{
 | 
			
		||||
                        "one_time_token":"'.$request->payment_token.'"
 | 
			
		||||
                     }
 | 
			
		||||
              }',
 | 
			
		||||
                CURLOPT_HTTPHEADER => array(
 | 
			
		||||
                  'Content-Type: application/json',
 | 
			
		||||
                  'X-Forte-Auth-Organization-Id: '.$this->forte_organization_id,
 | 
			
		||||
                  'Authorization: Basic '.base64_encode($this->forte_api_access_id.':'.$this->forte_secure_key)
 | 
			
		||||
                ),
 | 
			
		||||
              ));
 | 
			
		||||
 | 
			
		||||
            $response = curl_exec($curl);
 | 
			
		||||
            $httpcode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
 | 
			
		||||
 | 
			
		||||
            curl_close($curl);
 | 
			
		||||
 | 
			
		||||
            $response=json_decode($response);
 | 
			
		||||
        } catch (\Throwable $th) {
 | 
			
		||||
            throw $th;
 | 
			
		||||
        }
 | 
			
		||||
        if ($httpcode>299) {
 | 
			
		||||
            $error = Validator::make([], []);
 | 
			
		||||
            $error->getMessageBag()->add('gateway_error', $response->response->response_desc);
 | 
			
		||||
            return redirect('client/invoices')->withErrors($error);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $data = [
 | 
			
		||||
            'payment_method' => $request->payment_method_id,
 | 
			
		||||
            'payment_type' => PaymentType::parseCardType(strtolower($request->card_brand)) ?: PaymentType::CREDIT_CARD_OTHER,
 | 
			
		||||
            'amount' => $payment_hash->data->amount_with_fee,
 | 
			
		||||
            'transaction_reference' => $response->transaction_id,
 | 
			
		||||
            'gateway_type_id' => GatewayType::CREDIT_CARD,
 | 
			
		||||
        ];
 | 
			
		||||
        $payment=$this->forte->createPayment($data, Payment::STATUS_COMPLETED);
 | 
			
		||||
        return redirect('client/invoices')->withSuccess('Invoice paid.');
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										90
									
								
								app/PaymentDrivers/FortePaymentDriver.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								app/PaymentDrivers/FortePaymentDriver.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,90 @@
 | 
			
		||||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * Invoice Ninja (https://invoiceninja.com).
 | 
			
		||||
 *
 | 
			
		||||
 * @link https://github.com/invoiceninja/invoiceninja source repository
 | 
			
		||||
 *
 | 
			
		||||
 * @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
 | 
			
		||||
 *
 | 
			
		||||
 * @license https://opensource.org/licenses/AAL
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
namespace App\PaymentDrivers;
 | 
			
		||||
 | 
			
		||||
use App\Models\SystemLog;
 | 
			
		||||
use App\Models\GatewayType;
 | 
			
		||||
use App\Utils\Traits\MakesHash;
 | 
			
		||||
use App\PaymentDrivers\Forte\ACH;
 | 
			
		||||
use App\PaymentDrivers\Forte\CreditCard;
 | 
			
		||||
 | 
			
		||||
class FortePaymentDriver extends BaseDriver
 | 
			
		||||
{
 | 
			
		||||
    use MakesHash;
 | 
			
		||||
 | 
			
		||||
    public $refundable = true; //does this gateway support refunds?
 | 
			
		||||
 | 
			
		||||
    public $token_billing = true; //does this gateway support token billing?
 | 
			
		||||
 | 
			
		||||
    public $can_authorise_credit_card = true; //does this gateway support authorizations?
 | 
			
		||||
 | 
			
		||||
    public $gateway; //initialized gateway
 | 
			
		||||
 | 
			
		||||
    public $payment_method; //initialized payment method
 | 
			
		||||
 | 
			
		||||
    public static $methods = [
 | 
			
		||||
        GatewayType::CREDIT_CARD => CreditCard::class,
 | 
			
		||||
        GatewayType::BANK_TRANSFER => ACH::class,
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the gateway types.
 | 
			
		||||
     */
 | 
			
		||||
    public function gatewayTypes(): array
 | 
			
		||||
    {
 | 
			
		||||
        $types = [];
 | 
			
		||||
 | 
			
		||||
            $types[] = GatewayType::CREDIT_CARD;
 | 
			
		||||
            $types[] = GatewayType::BANK_TRANSFER;
 | 
			
		||||
 | 
			
		||||
        return $types;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const SYSTEM_LOG_TYPE = SystemLog::TYPE_STRIPE; //define a constant for your gateway ie TYPE_YOUR_CUSTOM_GATEWAY - set the const in the SystemLog model
 | 
			
		||||
 | 
			
		||||
    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); //this is your custom implementation from here
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function authorizeResponse($request)
 | 
			
		||||
    {
 | 
			
		||||
        return $this->payment_method->authorizeResponse($request);  //this is your custom implementation from here
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function processPaymentView(array $data)
 | 
			
		||||
    {
 | 
			
		||||
        return $this->payment_method->paymentView($data);  //this is your custom implementation from here
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function processPaymentResponse($request)
 | 
			
		||||
    {
 | 
			
		||||
        return $this->payment_method->paymentResponse($request); //this is your custom implementation from here
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // public function refund(Payment $payment, $amount, $return_client_response = false)
 | 
			
		||||
    // {
 | 
			
		||||
    //     return $this->payment_method->yourRefundImplementationHere(); //this is your custom implementation from here
 | 
			
		||||
    // }
 | 
			
		||||
 | 
			
		||||
    // public function tokenBilling(ClientGatewayToken $cgt, PaymentHash $payment_hash)
 | 
			
		||||
    // {
 | 
			
		||||
    //     return $this->payment_method->yourTokenBillingImplmentation(); //this is your custom implementation from here
 | 
			
		||||
    // }
 | 
			
		||||
}
 | 
			
		||||
@ -121,7 +121,19 @@ class PaymentIntentWebhook implements ShouldQueue
 | 
			
		||||
            nlog("payment intent");
 | 
			
		||||
            nlog($this->stripe_request);
 | 
			
		||||
 | 
			
		||||
            if(optional($this->stripe_request['object']['charges']['data'][0]['metadata']['payment_hash']) && in_array('card', $this->stripe_request['object']['allowed_source_types']))
 | 
			
		||||
            if(array_key_exists('allowed_source_types', $this->stripe_request['object']) && optional($this->stripe_request['object']['charges']['data'][0]['metadata']['payment_hash']) && in_array('card', $this->stripe_request['object']['allowed_source_types']))
 | 
			
		||||
            {
 | 
			
		||||
                nlog("hash found");
 | 
			
		||||
 | 
			
		||||
                $hash = $this->stripe_request['object']['charges']['data'][0]['metadata']['payment_hash'];
 | 
			
		||||
 | 
			
		||||
                $payment_hash = PaymentHash::where('hash', $hash)->first();
 | 
			
		||||
                $invoice = Invoice::with('client')->find($payment_hash->fee_invoice_id);
 | 
			
		||||
                $client = $invoice->client;
 | 
			
		||||
 | 
			
		||||
                $this->updateCreditCardPayment($payment_hash, $client);
 | 
			
		||||
            }
 | 
			
		||||
            elseif(array_key_exists('payment_method_types', $this->stripe_request['object']) && optional($this->stripe_request['object']['charges']['data'][0]['metadata']['payment_hash']) && in_array('card', $this->stripe_request['object']['payment_method_types']))
 | 
			
		||||
            {
 | 
			
		||||
                nlog("hash found");
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -220,6 +220,7 @@ class Statement
 | 
			
		||||
    protected function getInvoices(): \Illuminate\Support\LazyCollection
 | 
			
		||||
    {
 | 
			
		||||
        return Invoice::withTrashed()
 | 
			
		||||
            ->with('payments.type')
 | 
			
		||||
            ->where('is_deleted', false)
 | 
			
		||||
            ->where('company_id', $this->client->company_id)
 | 
			
		||||
            ->where('client_id', $this->client->id)
 | 
			
		||||
 | 
			
		||||
@ -255,6 +255,7 @@ class InstantPayment
 | 
			
		||||
            'tokens' => $tokens,
 | 
			
		||||
            'payment_method_id' => $payment_method_id,
 | 
			
		||||
            'amount_with_fee' => $invoice_totals + $fee_totals,
 | 
			
		||||
            'client' => $client,
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        if ($is_credit_payment || $totals <= 0) {
 | 
			
		||||
 | 
			
		||||
@ -60,6 +60,8 @@ class Design extends BaseDesign
 | 
			
		||||
 | 
			
		||||
    public $company;
 | 
			
		||||
 | 
			
		||||
    public $client_or_vendor_entity;
 | 
			
		||||
 | 
			
		||||
    /** @var array */
 | 
			
		||||
    public $aging = [];
 | 
			
		||||
 | 
			
		||||
@ -173,9 +175,27 @@ class Design extends BaseDesign
 | 
			
		||||
                    $this->sharedFooterElements(),
 | 
			
		||||
                ],
 | 
			
		||||
            ],
 | 
			
		||||
            // 'swiss-qr' => [
 | 
			
		||||
            //     'id' => 'swiss-qr',
 | 
			
		||||
            //     'elements' => $this->swissQrCodeElement(),
 | 
			
		||||
            // ]
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public function swissQrCodeElement() :array
 | 
			
		||||
    {
 | 
			
		||||
        if($this->type == self::DELIVERY_NOTE)
 | 
			
		||||
            return [];
 | 
			
		||||
 | 
			
		||||
        $elements = [];
 | 
			
		||||
 | 
			
		||||
        if(strlen($this->company->getSetting('qr_iban')) > 5 && strlen($this->company->getSetting('besr_id')) > 1)
 | 
			
		||||
            $elements[] = ['element' => 'qr_code', 'content' => '$swiss_qr', 'show_empty' => false, 'properties' => ['data-ref' => 'swiss-qr-code']];
 | 
			
		||||
 | 
			
		||||
        return $elements; 
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function companyDetails(): array
 | 
			
		||||
    {
 | 
			
		||||
        $variables = $this->context['pdf_variables']['company_details'];
 | 
			
		||||
@ -785,7 +805,7 @@ class Design extends BaseDesign
 | 
			
		||||
                foreach ($taxes as $i => $tax) {
 | 
			
		||||
                    $elements[1]['elements'][] = ['element' => 'div', 'elements' => [
 | 
			
		||||
                        ['element' => 'span', 'content', 'content' => $tax['name'], 'properties' => ['data-ref' => 'totals-table-total_tax_' . $i . '-label']],
 | 
			
		||||
                        ['element' => 'span', 'content', 'content' => Number::formatMoney($tax['total'], $this->context['client']), 'properties' => ['data-ref' => 'totals-table-total_tax_' . $i]],
 | 
			
		||||
                        ['element' => 'span', 'content', 'content' => Number::formatMoney($tax['total'], $this->client_or_vendor_entity), 'properties' => ['data-ref' => 'totals-table-total_tax_' . $i]],
 | 
			
		||||
                    ]];
 | 
			
		||||
                }
 | 
			
		||||
            } elseif ($variable == '$line_taxes') {
 | 
			
		||||
@ -798,13 +818,13 @@ class Design extends BaseDesign
 | 
			
		||||
                foreach ($taxes as $i => $tax) {
 | 
			
		||||
                    $elements[1]['elements'][] = ['element' => 'div', 'elements' => [
 | 
			
		||||
                        ['element' => 'span', 'content', 'content' => $tax['name'], 'properties' => ['data-ref' => 'totals-table-line_tax_' . $i . '-label']],
 | 
			
		||||
                        ['element' => 'span', 'content', 'content' => Number::formatMoney($tax['total'], $this->context['client']), 'properties' => ['data-ref' => 'totals-table-line_tax_' . $i]],
 | 
			
		||||
                        ['element' => 'span', 'content', 'content' => Number::formatMoney($tax['total'], $this->client_or_vendor_entity), 'properties' => ['data-ref' => 'totals-table-line_tax_' . $i]],
 | 
			
		||||
                    ]];
 | 
			
		||||
                }
 | 
			
		||||
            } elseif (Str::startsWith($variable, '$custom_surcharge')) {
 | 
			
		||||
                $_variable = ltrim($variable, '$'); // $custom_surcharge1 -> custom_surcharge1
 | 
			
		||||
 | 
			
		||||
                $visible = (int)$this->entity->{$_variable} != 0 || $this->entity->{$_variable} != '0' || !$this->entity->{$_variable};
 | 
			
		||||
                $visible = (int)$this->entity->{$_variable} > 0 || (int)$this->entity->{$_variable} < 0 || !$this->entity->{$_variable};
 | 
			
		||||
 | 
			
		||||
                $elements[1]['elements'][] = ['element' => 'div', 'elements' => [
 | 
			
		||||
                    ['element' => 'span', 'content' => $variable . '_label', 'properties' => ['hidden' => !$visible, 'data-ref' => 'totals_table-' . substr($variable, 1) . '-label']],
 | 
			
		||||
 | 
			
		||||
@ -32,10 +32,12 @@ trait DesignHelpers
 | 
			
		||||
 | 
			
		||||
        if (isset($this->context['vendor'])) {
 | 
			
		||||
            $this->vendor = $this->context['vendor'];
 | 
			
		||||
            $this->client_or_vendor_entity = $this->context['vendor'];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (isset($this->context['client'])) {
 | 
			
		||||
            $this->client = $this->context['client'];
 | 
			
		||||
            $this->client_or_vendor_entity = $this->context['client'];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (isset($this->context['entity'])) {
 | 
			
		||||
 | 
			
		||||
@ -51,7 +51,6 @@ class PurchaseOrderService
 | 
			
		||||
 | 
			
		||||
        // //TODO implement design, footer, terms
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // /* If client currency differs from the company default currency, then insert the client exchange rate on the model.*/
 | 
			
		||||
        // if (!isset($this->purchase_order->exchange_rate) && $this->purchase_order->client->currency()->id != (int)$this->purchase_order->company->settings->currency_id)
 | 
			
		||||
        //     $this->purchase_order->exchange_rate = $this->purchase_order->client->currency()->exchange_rate;
 | 
			
		||||
@ -89,7 +88,6 @@ class PurchaseOrderService
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public function touchPdf($force = false)
 | 
			
		||||
    {
 | 
			
		||||
        try {
 | 
			
		||||
 | 
			
		||||
@ -89,7 +89,7 @@ class PurchaseOrderTransformer extends EntityTransformer
 | 
			
		||||
            'custom_surcharge_tax3' => (bool)$purchase_order->custom_surcharge_tax3,
 | 
			
		||||
            'custom_surcharge_tax4' => (bool)$purchase_order->custom_surcharge_tax4,
 | 
			
		||||
            'line_items' => $purchase_order->line_items ?: (array)[],
 | 
			
		||||
            'entity_type' => 'purchase_order',
 | 
			
		||||
            'entity_type' => 'purchaseOrder',
 | 
			
		||||
            'exchange_rate' => (float)$purchase_order->exchange_rate,
 | 
			
		||||
            'paid_to_date' => (float)$purchase_order->paid_to_date,
 | 
			
		||||
            'subscription_id' => $this->encodePrimaryKey($purchase_order->subscription_id),
 | 
			
		||||
 | 
			
		||||
@ -12,6 +12,7 @@
 | 
			
		||||
 | 
			
		||||
namespace App\Utils;
 | 
			
		||||
 | 
			
		||||
use App\Helpers\SwissQr\SwissQrGenerator;
 | 
			
		||||
use App\Models\Country;
 | 
			
		||||
use App\Models\CreditInvitation;
 | 
			
		||||
use App\Models\GatewayType;
 | 
			
		||||
@ -162,6 +163,17 @@ class HtmlEngine
 | 
			
		||||
            if($this->entity->vendor) {
 | 
			
		||||
                $data['$invoice.vendor'] = ['value' => $this->entity->vendor->present()->name(), 'label' => ctrans('texts.vendor_name')];
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if(strlen($this->company->getSetting('qr_iban')) > 5 && strlen($this->company->getSetting('besr_id')) > 1)
 | 
			
		||||
            {
 | 
			
		||||
                try{
 | 
			
		||||
                    $data['$swiss_qr'] = ['value' => (new SwissQrGenerator($this->entity, $this->company))->run(), 'label' => ''];
 | 
			
		||||
                }
 | 
			
		||||
                catch(\Exception $e){
 | 
			
		||||
                    $data['$swiss_qr'] = ['value' => '', 'label' => ''];
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ($this->entity_string == 'quote') {
 | 
			
		||||
@ -281,6 +293,7 @@ class HtmlEngine
 | 
			
		||||
        $data['$assigned_to_user'] = ['value' => $this->entity->assigned_user ? $this->entity->assigned_user->present()->name() : '', 'label' => ctrans('texts.name')];
 | 
			
		||||
 | 
			
		||||
        $data['$user_iban'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'company1', $this->settings->custom_value1, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'company1')];
 | 
			
		||||
 | 
			
		||||
        $data['$invoice.custom1'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'invoice1', $this->entity->custom_value1, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'invoice1')];
 | 
			
		||||
        $data['$invoice.custom2'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'invoice2', $this->entity->custom_value2, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'invoice2')];
 | 
			
		||||
        $data['$invoice.custom3'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'invoice3', $this->entity->custom_value3, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'invoice3')];
 | 
			
		||||
 | 
			
		||||
@ -16,16 +16,22 @@ use App\Models\Client;
 | 
			
		||||
use App\Models\ClientContact;
 | 
			
		||||
use App\Models\Invoice;
 | 
			
		||||
use App\Models\InvoiceInvitation;
 | 
			
		||||
use App\Models\PurchaseOrder;
 | 
			
		||||
use App\Models\PurchaseOrderInvitation;
 | 
			
		||||
use App\Models\Quote;
 | 
			
		||||
use App\Models\QuoteInvitation;
 | 
			
		||||
use App\Models\Vendor;
 | 
			
		||||
use App\Models\VendorContact;
 | 
			
		||||
use App\Services\PdfMaker\Designs\Utilities\DesignHelpers;
 | 
			
		||||
use App\Utils\Ninja;
 | 
			
		||||
use App\Utils\Traits\MakesHash;
 | 
			
		||||
use App\Utils\Traits\MakesInvoiceHtml;
 | 
			
		||||
use App\Utils\Traits\MakesTemplateData;
 | 
			
		||||
use App\Utils\VendorHtmlEngine;
 | 
			
		||||
use DB;
 | 
			
		||||
use Illuminate\Support\Facades\App;
 | 
			
		||||
use Illuminate\Support\Facades\Lang;
 | 
			
		||||
use Illuminate\Support\Str;
 | 
			
		||||
use League\CommonMark\CommonMarkConverter;
 | 
			
		||||
use TijsVerkoyen\CssToInlineStyles\CssToInlineStyles;
 | 
			
		||||
 | 
			
		||||
@ -78,6 +84,10 @@ class TemplateEngine
 | 
			
		||||
 | 
			
		||||
    public function build()
 | 
			
		||||
    {
 | 
			
		||||
        
 | 
			
		||||
        if ($this->template == 'email_template_null')
 | 
			
		||||
            $this->template = 'email_template_purchase_order';
 | 
			
		||||
 | 
			
		||||
        return $this->setEntity()
 | 
			
		||||
                 ->setSettingsObject()
 | 
			
		||||
                 ->setTemplates()
 | 
			
		||||
@ -88,7 +98,7 @@ class TemplateEngine
 | 
			
		||||
    private function setEntity()
 | 
			
		||||
    {
 | 
			
		||||
        if (strlen($this->entity) > 1 && strlen($this->entity_id) > 1) {
 | 
			
		||||
            $class = 'App\Models\\'.ucfirst($this->entity);
 | 
			
		||||
            $class = 'App\Models\\'.ucfirst(Str::camel($this->entity));
 | 
			
		||||
            $this->entity_obj = $class::withTrashed()->where('id', $this->decodePrimaryKey($this->entity_id))->company()->first();
 | 
			
		||||
        } else {
 | 
			
		||||
            $this->mockEntity();
 | 
			
		||||
@ -99,7 +109,11 @@ class TemplateEngine
 | 
			
		||||
 | 
			
		||||
    private function setSettingsObject()
 | 
			
		||||
    {
 | 
			
		||||
        if ($this->entity_obj) {
 | 
			
		||||
        if($this->entity == 'purchaseOrder'){
 | 
			
		||||
            $this->settings_entity = auth()->user()->company();
 | 
			
		||||
            $this->settings = $this->settings_entity->settings;
 | 
			
		||||
        }
 | 
			
		||||
        elseif ($this->entity_obj->client()->exists()) {
 | 
			
		||||
            $this->settings_entity = $this->entity_obj->client;
 | 
			
		||||
            $this->settings = $this->settings_entity->getMergedSettings();
 | 
			
		||||
        } else {
 | 
			
		||||
@ -143,9 +157,13 @@ class TemplateEngine
 | 
			
		||||
        $this->raw_body = $this->body;
 | 
			
		||||
        $this->raw_subject  = $this->subject;
 | 
			
		||||
 | 
			
		||||
        if ($this->entity_obj) {
 | 
			
		||||
        if($this->entity == 'purchaseOrder'){
 | 
			
		||||
            $this->fakerValues();
 | 
			
		||||
        }
 | 
			
		||||
        elseif ($this->entity_obj->client()->exists()) {
 | 
			
		||||
            $this->entityValues($this->entity_obj->client->primary_contact()->first());
 | 
			
		||||
        } else {
 | 
			
		||||
        } 
 | 
			
		||||
        else {
 | 
			
		||||
            $this->fakerValues();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -172,11 +190,13 @@ class TemplateEngine
 | 
			
		||||
 | 
			
		||||
    private function entityValues($contact)
 | 
			
		||||
    {
 | 
			
		||||
        if($this->entity == 'purchaseOrder')
 | 
			
		||||
            $this->labels_and_values = (new VendorHtmlEngine($this->entity_obj->invitations->first()))->generateLabelsAndValues();
 | 
			
		||||
        else
 | 
			
		||||
            $this->labels_and_values = (new HtmlEngine($this->entity_obj->invitations->first()))->generateLabelsAndValues();
 | 
			
		||||
 | 
			
		||||
        $this->body = strtr($this->body, $this->labels_and_values['labels']);
 | 
			
		||||
        $this->body = strtr($this->body, $this->labels_and_values['values']);
 | 
			
		||||
//        $this->body = str_replace("\n", "<br>", $this->body);
 | 
			
		||||
 | 
			
		||||
        $this->subject = strtr($this->subject, $this->labels_and_values['labels']);
 | 
			
		||||
        $this->subject = strtr($this->subject, $this->labels_and_values['values']);
 | 
			
		||||
@ -198,7 +218,18 @@ class TemplateEngine
 | 
			
		||||
        $data['footer'] = '';
 | 
			
		||||
        $data['logo'] = auth()->user()->company()->present()->logo();
 | 
			
		||||
 | 
			
		||||
        if($this->entity_obj->client()->exists())
 | 
			
		||||
            $data = array_merge($data, Helpers::sharedEmailVariables($this->entity_obj->client));
 | 
			
		||||
        else{
 | 
			
		||||
 | 
			
		||||
            $data['signature'] = $this->settings->email_signature;
 | 
			
		||||
            $data['settings'] = $this->settings;
 | 
			
		||||
            $data['whitelabel'] = $this->entity_obj ? $this->entity_obj->company->account->isPaid() : true;
 | 
			
		||||
            $data['company'] = $this->entity_obj ? $this->entity_obj->company : '';
 | 
			
		||||
            $data['settings'] = $this->settings;
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        if ($email_style == 'custom') {
 | 
			
		||||
            $wrapper = $this->settings_entity->getSetting('email_style_custom');
 | 
			
		||||
@ -241,8 +272,13 @@ class TemplateEngine
 | 
			
		||||
 | 
			
		||||
    private function mockEntity()
 | 
			
		||||
    {
 | 
			
		||||
        if(!$this->entity && $this->template && str_contains($this->template, 'purchase_order'))
 | 
			
		||||
            $this->entity = 'purchaseOrder';
 | 
			
		||||
 | 
			
		||||
        DB::connection(config('database.default'))->beginTransaction();
 | 
			
		||||
 | 
			
		||||
        $vendor = false;
 | 
			
		||||
 | 
			
		||||
        $client = Client::factory()->create([
 | 
			
		||||
                'user_id' => auth()->user()->id,
 | 
			
		||||
                'company_id' => auth()->user()->company()->id,
 | 
			
		||||
@ -289,6 +325,53 @@ class TemplateEngine
 | 
			
		||||
            ]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        if($this->entity == 'purchaseOrder')
 | 
			
		||||
        {
 | 
			
		||||
 | 
			
		||||
            $vendor = Vendor::factory()->create([
 | 
			
		||||
                    'user_id' => auth()->user()->id,
 | 
			
		||||
                    'company_id' => auth()->user()->company()->id,
 | 
			
		||||
                ]);
 | 
			
		||||
 | 
			
		||||
            $contact = VendorContact::factory()->create([
 | 
			
		||||
                    'user_id' => auth()->user()->id,
 | 
			
		||||
                    'company_id' => auth()->user()->company()->id,
 | 
			
		||||
                    'vendor_id' => $vendor->id,
 | 
			
		||||
                    'is_primary' => 1,
 | 
			
		||||
                    'send_email' => true,
 | 
			
		||||
                ]);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            $this->entity_obj = PurchaseOrder::factory()->create([
 | 
			
		||||
                        'user_id' => auth()->user()->id,
 | 
			
		||||
                        'company_id' => auth()->user()->company()->id,
 | 
			
		||||
                        'vendor_id' => $vendor->id,
 | 
			
		||||
                    ]);
 | 
			
		||||
 | 
			
		||||
            $invitation = PurchaseOrderInvitation::factory()->create([
 | 
			
		||||
                        'user_id' => auth()->user()->id,
 | 
			
		||||
                        'company_id' => auth()->user()->company()->id,
 | 
			
		||||
                        'purchase_order_id' => $this->entity_obj->id,
 | 
			
		||||
                        'vendor_contact_id' => $contact->id,
 | 
			
		||||
            ]);
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if($vendor)
 | 
			
		||||
        {
 | 
			
		||||
 | 
			
		||||
            $this->entity_obj->setRelation('invitations', $invitation);
 | 
			
		||||
            $this->entity_obj->setRelation('vendor', $vendor);
 | 
			
		||||
            $this->entity_obj->setRelation('company', auth()->user()->company());
 | 
			
		||||
            $this->entity_obj->load('vendor');
 | 
			
		||||
            $vendor->setRelation('company', auth()->user()->company());
 | 
			
		||||
            $vendor->load('company');
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        else 
 | 
			
		||||
        {
 | 
			
		||||
            $this->entity_obj->setRelation('invitations', $invitation);
 | 
			
		||||
            $this->entity_obj->setRelation('client', $client);
 | 
			
		||||
            $this->entity_obj->setRelation('company', auth()->user()->company());
 | 
			
		||||
@ -296,6 +379,7 @@ class TemplateEngine
 | 
			
		||||
            $client->setRelation('company', auth()->user()->company());
 | 
			
		||||
            $client->load('company');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function tearDown()
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
@ -111,6 +111,10 @@ trait AppSetup
 | 
			
		||||
                'subject' => EmailTemplateDefaults::emailCreditSubject(),
 | 
			
		||||
                'body' => EmailTemplateDefaults::emailCreditTemplate(),
 | 
			
		||||
            ],
 | 
			
		||||
            'purchase_order' => [
 | 
			
		||||
                'subject' => EmailTemplateDefaults::emailPurchaseOrderSubject(),
 | 
			
		||||
                'body' => EmailTemplateDefaults::emailPurchaseOrderTemplate(),
 | 
			
		||||
            ],
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        Cache::forever($name, $data);
 | 
			
		||||
 | 
			
		||||
@ -120,6 +120,9 @@ trait CompanySettingsSaver
 | 
			
		||||
            elseif (substr($key, -3) == '_id' || substr($key, -14) == 'number_counter') {
 | 
			
		||||
                $value = 'integer';
 | 
			
		||||
 | 
			
		||||
                if($key == 'besr_id')
 | 
			
		||||
                    $value = 'string';
 | 
			
		||||
 | 
			
		||||
                if (! property_exists($settings, $key)) {
 | 
			
		||||
                    continue;
 | 
			
		||||
                } elseif (! $this->checkAttribute($value, $settings->{$key})) {
 | 
			
		||||
@ -187,6 +190,9 @@ trait CompanySettingsSaver
 | 
			
		||||
                if($key == 'gmail_sending_user_id')
 | 
			
		||||
                    $value = 'string';
 | 
			
		||||
 | 
			
		||||
                if($key == 'besr_id')
 | 
			
		||||
                    $value = 'string';
 | 
			
		||||
 | 
			
		||||
                if (! property_exists($settings, $key)) {
 | 
			
		||||
                    continue;
 | 
			
		||||
                } elseif ($this->checkAttribute($value, $settings->{$key})) {
 | 
			
		||||
 | 
			
		||||
@ -200,56 +200,33 @@ trait MakesTemplateData
 | 
			
		||||
        $data['$task.tax_name3'] = ['value' => 'CA Sales Tax', 'label' => ctrans('texts.tax')];
 | 
			
		||||
        $data['$task.line_total'] = ['value' => '$100.00', 'label' => ctrans('texts.line_total')];
 | 
			
		||||
 | 
			
		||||
        //$data['$paid_to_date'] = ;
 | 
			
		||||
        // $data['$your_invoice'] = ;
 | 
			
		||||
        // $data['$quote'] = ;
 | 
			
		||||
        // $data['$your_quote'] = ;
 | 
			
		||||
        // $data['$invoice_issued_to'] = ;
 | 
			
		||||
        // $data['$quote_issued_to'] = ;
 | 
			
		||||
        // $data['$rate'] = ;
 | 
			
		||||
        // $data['$hours'] = ;
 | 
			
		||||
        // $data['$from'] = ;
 | 
			
		||||
        // $data['$to'] = ;
 | 
			
		||||
        // $data['$invoice_to'] = ;
 | 
			
		||||
        // $data['$quote_to'] = ;
 | 
			
		||||
        // $data['$details'] = ;
 | 
			
		||||
        // $data['custom_label1']              = ['value' => '', 'label' => ctrans('texts.')];
 | 
			
		||||
        // $data['custom_label2']              = ['value' => '', 'label' => ctrans('texts.')];
 | 
			
		||||
        // $data['custom_label3']              = ['value' => '', 'label' => ctrans('texts.')];
 | 
			
		||||
        // $data['custom_label4']              = ['value' => '', 'label' => ctrans('texts.')];
 | 
			
		||||
        //$data['$blank'] = ;
 | 
			
		||||
        //$data['$surcharge'] = ;
 | 
			
		||||
        /*
 | 
			
		||||
        $data['$tax_invoice'] =
 | 
			
		||||
        $data['$tax_quote'] =
 | 
			
		||||
        $data['$statement'] = ;
 | 
			
		||||
        $data['$statement_date'] = ;
 | 
			
		||||
        $data['$your_statement'] = ;
 | 
			
		||||
        $data['$statement_issued_to'] = ;
 | 
			
		||||
        $data['$statement_to'] = ;
 | 
			
		||||
        $data['$credit_note'] = ;
 | 
			
		||||
        $data['$credit_date'] = ;
 | 
			
		||||
        $data['$credit_issued_to'] = ;
 | 
			
		||||
        $data['$credit_to'] = ;
 | 
			
		||||
        $data['$your_credit'] = ;
 | 
			
		||||
        $data['$phone'] = ;
 | 
			
		||||
        $data['$vendor_name'] = ['value' => 'Joey Diaz Denkins', 'label' => ctrans('texts.vendor_name')];;
 | 
			
		||||
        $data['$vendor.name'] = &$data['$vendor_name'];
 | 
			
		||||
        $data['$vendor'] = &$data['$vendor_name'];
 | 
			
		||||
 | 
			
		||||
        $data['$outstanding'] = ;
 | 
			
		||||
        $data['$invoice_due_date'] = ;
 | 
			
		||||
        $data['$quote_due_date'] = ;
 | 
			
		||||
        $data['$service'] = ;
 | 
			
		||||
        $data['$product_key'] = ;
 | 
			
		||||
        $data['$unit_cost'] = ;
 | 
			
		||||
        $data['$custom_value1'] = ;
 | 
			
		||||
        $data['$custom_value2'] = ;
 | 
			
		||||
        $data['$delivery_note'] = ;
 | 
			
		||||
        $data['$date'] = ;
 | 
			
		||||
        $data['$method'] = ;
 | 
			
		||||
        $data['$payment_date'] = ;
 | 
			
		||||
        $data['$reference'] = ;
 | 
			
		||||
        $data['$amount'] = ;
 | 
			
		||||
        $data['$amount_paid'] =;
 | 
			
		||||
        	*/
 | 
			
		||||
        $data['$vendor.address1'] = &$data['$address1'];
 | 
			
		||||
        $data['$vendor.address2'] = &$data['$address2'];
 | 
			
		||||
        $data['$vendor_address'] = ['value' => '5 Kalamazoo Way\n Jimbuckeroo\n USA 90210', 'label' => ctrans('texts.address')];
 | 
			
		||||
        $data['$vendor.address'] = &$data['$vendor_address'];
 | 
			
		||||
        $data['$vendor.postal_code'] = ['value' => '90210', 'label' => ctrans('texts.postal_code')];
 | 
			
		||||
        $data['$vendor.public_notes'] = $data['$invoice.public_notes'];
 | 
			
		||||
        $data['$vendor.city'] = &$data['$company.city'];
 | 
			
		||||
        $data['$vendor.state'] = &$data['$company.state'];
 | 
			
		||||
        $data['$vendor.id_number'] = &$data['$id_number'];
 | 
			
		||||
        $data['$vendor.vat_number'] = &$data['$vat_number'];
 | 
			
		||||
        $data['$vendor.website'] = &$data['$website'];
 | 
			
		||||
        $data['$vendor.phone'] = &$data['$phone'];
 | 
			
		||||
        $data['$vendor.city_state_postal'] = &$data['$city_state_postal'];
 | 
			
		||||
        $data['$vendor.postal_city_state'] = &$data['$postal_city_state'];
 | 
			
		||||
        $data['$vendor.country'] = &$data['$country'];
 | 
			
		||||
        $data['$vendor.email'] = &$data['$email'];
 | 
			
		||||
        
 | 
			
		||||
        $data['$vendor.billing_address1'] = &$data['$vendor.address1'];
 | 
			
		||||
        $data['$vendor.billing_address2'] = &$data['$vendor.address2'];
 | 
			
		||||
        $data['$vendor.billing_city'] = &$data['$vendor.city'];
 | 
			
		||||
        $data['$vendor.billing_state'] = &$data['$vendor.state'];
 | 
			
		||||
        $data['$vendor.billing_postal_code'] = &$data['$vendor.postal_code'];
 | 
			
		||||
        $data['$vendor.billing_country'] = &$data['$vendor.country'];
 | 
			
		||||
 | 
			
		||||
        $arrKeysLength = array_map('strlen', array_keys($data));
 | 
			
		||||
        array_multisort($arrKeysLength, SORT_DESC, $data);
 | 
			
		||||
 | 
			
		||||
@ -55,7 +55,7 @@ trait SettingsSaver
 | 
			
		||||
            elseif (substr($key, -3) == '_id' || substr($key, -14) == 'number_counter' || ($key == 'payment_terms' && strlen($settings->{$key}) >= 1) || ($key == 'valid_until' && strlen($settings->{$key}) >= 1)) {    
 | 
			
		||||
                $value = 'integer';
 | 
			
		||||
 | 
			
		||||
                if($key == 'gmail_sending_user_id')
 | 
			
		||||
                if($key == 'gmail_sending_user_id' || $key == 'besr_id')
 | 
			
		||||
                    $value = 'string';
 | 
			
		||||
 | 
			
		||||
                if (! property_exists($settings, $key)) {
 | 
			
		||||
 | 
			
		||||
@ -63,6 +63,11 @@ class VendorHtmlEngine
 | 
			
		||||
        
 | 
			
		||||
        $this->vendor = $this->contact->vendor->load('company','country');
 | 
			
		||||
        
 | 
			
		||||
        if(!$this->vendor->currency_id){
 | 
			
		||||
            $this->vendor->currency_id = $this->company->settings->currency_id;
 | 
			
		||||
            $this->vendor->save();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $this->entity->load('vendor');
 | 
			
		||||
 | 
			
		||||
        $this->settings = $this->company->settings;
 | 
			
		||||
 | 
			
		||||
@ -85,6 +85,7 @@
 | 
			
		||||
        "setasign/fpdi": "^2.3",
 | 
			
		||||
        "socialiteproviders/apple": "^5.2",
 | 
			
		||||
        "socialiteproviders/microsoft": "^4.1",
 | 
			
		||||
        "sprain/swiss-qr-bill": "^3.2",
 | 
			
		||||
        "square/square": "13.0.0.20210721",
 | 
			
		||||
        "stripe/stripe-php": "^7.50",
 | 
			
		||||
        "symfony/http-client": "^5.2",
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1167
									
								
								composer.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1167
									
								
								composer.lock
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@ -14,8 +14,8 @@ return [
 | 
			
		||||
    'require_https' => env('REQUIRE_HTTPS', true),
 | 
			
		||||
    'app_url' => rtrim(env('APP_URL', ''), '/'),
 | 
			
		||||
    'app_domain' => env('APP_DOMAIN', 'invoicing.co'),
 | 
			
		||||
    'app_version' => '5.4.4',
 | 
			
		||||
    'app_tag' => '5.4.4',
 | 
			
		||||
    'app_version' => '5.4.5',
 | 
			
		||||
    'app_tag' => '5.4.5',
 | 
			
		||||
    'minimum_client_version' => '5.0.16',
 | 
			
		||||
    'terms_version' => '1.0.1',
 | 
			
		||||
    'api_secret' => env('API_SECRET', ''),
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										51
									
								
								database/factories/PurchaseOrderFactory.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								database/factories/PurchaseOrderFactory.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,51 @@
 | 
			
		||||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * Invoice Ninja (https://invoiceninja.com).
 | 
			
		||||
 *
 | 
			
		||||
 * @link https://github.com/invoiceninja/invoiceninja source repository
 | 
			
		||||
 *
 | 
			
		||||
 * @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
 | 
			
		||||
 *
 | 
			
		||||
 * @license https://www.elastic.co/licensing/elastic-license 
 | 
			
		||||
 */
 | 
			
		||||
namespace Database\Factories;
 | 
			
		||||
 | 
			
		||||
use App\Factory\InvoiceItemFactory;
 | 
			
		||||
use App\Models\Invoice;
 | 
			
		||||
use App\Models\PurchaseOrder;
 | 
			
		||||
use Illuminate\Database\Eloquent\Factories\Factory;
 | 
			
		||||
 | 
			
		||||
class PurchaseOrderFactory extends Factory
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * The name of the factory's corresponding model.
 | 
			
		||||
     *
 | 
			
		||||
     * @var string
 | 
			
		||||
     */
 | 
			
		||||
    protected $model = PurchaseOrder::class;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Define the model's default state.
 | 
			
		||||
     *
 | 
			
		||||
     * @return array
 | 
			
		||||
     */
 | 
			
		||||
    public function definition()
 | 
			
		||||
    {
 | 
			
		||||
        return [
 | 
			
		||||
            'status_id' => Invoice::STATUS_SENT,
 | 
			
		||||
            'number' => $this->faker->ean13(),
 | 
			
		||||
            'discount' => $this->faker->numberBetween(1, 10),
 | 
			
		||||
            'is_amount_discount' => (bool) random_int(0, 1),
 | 
			
		||||
            'tax_name1' => 'GST',
 | 
			
		||||
            'tax_rate1' => 10,
 | 
			
		||||
            'tax_name2' => 'VAT',
 | 
			
		||||
            'tax_rate2' => 17.5,
 | 
			
		||||
            'is_deleted' => false,
 | 
			
		||||
            'po_number' => $this->faker->text(10),
 | 
			
		||||
            'date' => $this->faker->date(),
 | 
			
		||||
            'due_date' => $this->faker->date(),
 | 
			
		||||
            'line_items' => InvoiceItemFactory::generate(5),
 | 
			
		||||
            'terms' => $this->faker->text(500),
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,50 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
use App\Models\Gateway;
 | 
			
		||||
use App\Models\GatewayType;
 | 
			
		||||
use Illuminate\Support\Str;
 | 
			
		||||
use Illuminate\Support\Facades\Schema;
 | 
			
		||||
use Illuminate\Database\Schema\Blueprint;
 | 
			
		||||
use Illuminate\Database\Migrations\Migration;
 | 
			
		||||
 | 
			
		||||
class FortePaymentGateway extends Migration
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * Run the migrations.
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
    public function up()
 | 
			
		||||
    {
 | 
			
		||||
        $fields = new \stdClass;
 | 
			
		||||
        $fields->testMode = false;
 | 
			
		||||
        $fields->apiLoginId = "";
 | 
			
		||||
        $fields->apiAccessId = "";
 | 
			
		||||
        $fields->secureKey = "";
 | 
			
		||||
        $fields->authOrganizationId = "";
 | 
			
		||||
        $fields->organizationId = "";
 | 
			
		||||
        $fields->locationId = "";
 | 
			
		||||
 | 
			
		||||
        $forte = new Gateway;
 | 
			
		||||
        $forte->id = 59;
 | 
			
		||||
        $forte->name = 'Forte'; 
 | 
			
		||||
        $forte->key = 'kivcvjexxvdiyqtj3mju5d6yhpeht2xs'; 
 | 
			
		||||
        $forte->provider = 'Forte';
 | 
			
		||||
        $forte->is_offsite = true;
 | 
			
		||||
        $forte->fields = \json_encode($fields);
 | 
			
		||||
        $forte->visible = 1;
 | 
			
		||||
        $forte->site_url = 'https://www.forte.net/';
 | 
			
		||||
        $forte->default_gateway_type_id = GatewayType::CREDIT_CARD;
 | 
			
		||||
        $forte->save();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Reverse the migrations.
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
    public function down()
 | 
			
		||||
    {
 | 
			
		||||
        //
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -24,7 +24,7 @@ class AddJobRelatedFieldsToSchedulersTable extends Migration
 | 
			
		||||
        Schema::table('schedulers', function (Blueprint $table) {
 | 
			
		||||
            $table->string('action_name')->index();
 | 
			
		||||
            $table->string('action_class');
 | 
			
		||||
            $table->json('parameters')->nullable();
 | 
			
		||||
            $table->mediumText('parameters')->nullable();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,28 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
use Illuminate\Database\Migrations\Migration;
 | 
			
		||||
use Illuminate\Database\Schema\Blueprint;
 | 
			
		||||
use Illuminate\Support\Facades\Schema;
 | 
			
		||||
 | 
			
		||||
class FixesForDescriptionInPdfDesigns extends Migration
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * Run the migrations.
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
    public function up()
 | 
			
		||||
    {
 | 
			
		||||
        \Illuminate\Support\Facades\Artisan::call('ninja:design-update');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Reverse the migrations.
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
    public function down()
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,30 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
use Illuminate\Database\Migrations\Migration;
 | 
			
		||||
use Illuminate\Database\Schema\Blueprint;
 | 
			
		||||
use Illuminate\Support\Facades\Schema;
 | 
			
		||||
 | 
			
		||||
class SetOauthExpiryColumn extends Migration
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * Run the migrations.
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
    public function up()
 | 
			
		||||
    {
 | 
			
		||||
        Schema::table('users', function (Blueprint $table) {
 | 
			
		||||
            $table->datetime('oauth_user_token_expiry')->nullable();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Reverse the migrations.
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
    public function down()
 | 
			
		||||
    {
 | 
			
		||||
        //
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,31 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
use Illuminate\Database\Migrations\Migration;
 | 
			
		||||
use Illuminate\Database\Schema\Blueprint;
 | 
			
		||||
use Illuminate\Support\Facades\Schema;
 | 
			
		||||
 | 
			
		||||
class AddFlagToAccountsTable extends Migration
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * Run the migrations.
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
    public function up()
 | 
			
		||||
    {
 | 
			
		||||
        Schema::table('accounts', function (Blueprint $table) {
 | 
			
		||||
            $table->boolean('is_flagged')->default(0);
 | 
			
		||||
            $table->boolean('is_verified_account')->default(0);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Reverse the migrations.
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
    public function down()
 | 
			
		||||
    {
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -98,7 +98,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])->update(['visible' => 1]);
 | 
			
		||||
        Gateway::whereIn('id', [1,3,7,11,15,20,39,46,55,50,57,52,58,59])->update(['visible' => 1]);
 | 
			
		||||
 | 
			
		||||
        if (Ninja::isHosted()) {
 | 
			
		||||
            Gateway::whereIn('id', [20])->update(['visible' => 0]);
 | 
			
		||||
 | 
			
		||||
@ -2157,6 +2157,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
--------------------------------------------------------------------------------
 | 
			
		||||
attributed_text
 | 
			
		||||
super_editor
 | 
			
		||||
super_text_layout
 | 
			
		||||
 | 
			
		||||
Copyright (c) 2021 Superlist, SuperDeclarative! and the contributors
 | 
			
		||||
 | 
			
		||||
@ -5969,7 +5970,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 | 
			
		||||
--------------------------------------------------------------------------------
 | 
			
		||||
cross_file
 | 
			
		||||
flutter_lints
 | 
			
		||||
flutter_plugin_android_lifecycle
 | 
			
		||||
google_sign_in
 | 
			
		||||
google_sign_in_android
 | 
			
		||||
@ -15096,37 +15096,6 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
SOFTWARE.
 | 
			
		||||
 | 
			
		||||
--------------------------------------------------------------------------------
 | 
			
		||||
lints
 | 
			
		||||
 | 
			
		||||
Copyright 2021, the Dart project authors.
 | 
			
		||||
 | 
			
		||||
Redistribution and use in source and binary forms, with or without
 | 
			
		||||
modification, are permitted provided that the following conditions are
 | 
			
		||||
met:
 | 
			
		||||
 | 
			
		||||
    * Redistributions of source code must retain the above copyright
 | 
			
		||||
      notice, this list of conditions and the following disclaimer.
 | 
			
		||||
    * Redistributions in binary form must reproduce the above
 | 
			
		||||
      copyright notice, this list of conditions and the following
 | 
			
		||||
      disclaimer in the documentation and/or other materials provided
 | 
			
		||||
      with the distribution.
 | 
			
		||||
    * Neither the name of Google LLC nor the names of its
 | 
			
		||||
      contributors may be used to endorse or promote products derived
 | 
			
		||||
      from this software without specific prior written permission.
 | 
			
		||||
 | 
			
		||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | 
			
		||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
			
		||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | 
			
		||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | 
			
		||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
			
		||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | 
			
		||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
			
		||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
			
		||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
			
		||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | 
			
		||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 | 
			
		||||
--------------------------------------------------------------------------------
 | 
			
		||||
markdown
 | 
			
		||||
 | 
			
		||||
@ -15239,6 +15208,31 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
			
		||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | 
			
		||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 | 
			
		||||
--------------------------------------------------------------------------------
 | 
			
		||||
msal_js
 | 
			
		||||
 | 
			
		||||
MIT License
 | 
			
		||||
 | 
			
		||||
Copyright (c) 2021 Ethan Lafrenais
 | 
			
		||||
 | 
			
		||||
Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
in the Software without restriction, including without limitation the rights
 | 
			
		||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
furnished to do so, subject to the following conditions:
 | 
			
		||||
 | 
			
		||||
The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
copies or substantial portions of the Software.
 | 
			
		||||
 | 
			
		||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
SOFTWARE.
 | 
			
		||||
 | 
			
		||||
--------------------------------------------------------------------------------
 | 
			
		||||
msix
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										60
									
								
								public/flutter_service_worker.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										60
									
								
								public/flutter_service_worker.js
									
									
									
									
										vendored
									
									
								
							@ -3,43 +3,43 @@ const MANIFEST = 'flutter-app-manifest';
 | 
			
		||||
const TEMP = 'flutter-temp-cache';
 | 
			
		||||
const CACHE_NAME = 'flutter-app-cache';
 | 
			
		||||
const RESOURCES = {
 | 
			
		||||
  "icons/Icon-192.png": "bb1cf5f6982006952211c7c8404ffbed",
 | 
			
		||||
"icons/Icon-512.png": "0f9aff01367f0a0c69773d25ca16ef35",
 | 
			
		||||
"/": "2e739a78eec983322924f724ebfa09ba",
 | 
			
		||||
"main.dart.js": "fa4a0263712be1ce1df7d59ca0ede10e",
 | 
			
		||||
"version.json": "d72bd323e3b8e22ce5acdc247f4e6f62",
 | 
			
		||||
  "favicon.png": "dca91c54388f52eded692718d5a98b8b",
 | 
			
		||||
"flutter.js": "0816e65a103ba8ba51b174eeeeb2cb67",
 | 
			
		||||
"favicon.ico": "51636d3a390451561744c42188ccd628",
 | 
			
		||||
"canvaskit/canvaskit.wasm": "4b83d89d9fecbea8ca46f2f760c5a9ba",
 | 
			
		||||
"canvaskit/profiling/canvaskit.wasm": "95e736ab31147d1b2c7b25f11d4c32cd",
 | 
			
		||||
"canvaskit/profiling/canvaskit.js": "ae2949af4efc61d28a4a80fffa1db900",
 | 
			
		||||
"canvaskit/canvaskit.js": "c2b4e5f3d7a3d82aed024e7249a78487",
 | 
			
		||||
"canvaskit/profiling/canvaskit.js": "ae2949af4efc61d28a4a80fffa1db900",
 | 
			
		||||
"canvaskit/profiling/canvaskit.wasm": "95e736ab31147d1b2c7b25f11d4c32cd",
 | 
			
		||||
"canvaskit/canvaskit.wasm": "4b83d89d9fecbea8ca46f2f760c5a9ba",
 | 
			
		||||
"/": "46443d15dbe8e491c73190330d91d4e2",
 | 
			
		||||
"flutter.js": "0816e65a103ba8ba51b174eeeeb2cb67",
 | 
			
		||||
"icons/Icon-512.png": "0f9aff01367f0a0c69773d25ca16ef35",
 | 
			
		||||
"icons/Icon-192.png": "bb1cf5f6982006952211c7c8404ffbed",
 | 
			
		||||
"manifest.json": "ef43d90e57aa7682d7e2cfba2f484a40",
 | 
			
		||||
"version.json": "d72bd323e3b8e22ce5acdc247f4e6f62",
 | 
			
		||||
"favicon.ico": "51636d3a390451561744c42188ccd628",
 | 
			
		||||
"assets/FontManifest.json": "cf3c681641169319e61b61bd0277378f",
 | 
			
		||||
"assets/AssetManifest.json": "38d9aea341601f3a5c6fa7b5a1216ea5",
 | 
			
		||||
"assets/packages/material_design_icons_flutter/lib/fonts/materialdesignicons-webfont.ttf": "b62641afc9ab487008e996a5c5865e56",
 | 
			
		||||
"assets/fonts/MaterialIcons-Regular.otf": "95db9098c58fd6db106f1116bae85a0b",
 | 
			
		||||
"assets/assets/images/logo_light.png": "e5f46d5a78e226e7a9553d4ca6f69219",
 | 
			
		||||
"assets/assets/images/payment_types/discover.png": "6c0a386a00307f87db7bea366cca35f5",
 | 
			
		||||
"assets/assets/images/payment_types/carteblanche.png": "d936e11fa3884b8c9f1bd5c914be8629",
 | 
			
		||||
"assets/assets/images/payment_types/other.png": "d936e11fa3884b8c9f1bd5c914be8629",
 | 
			
		||||
"assets/assets/images/payment_types/laser.png": "b4e6e93dd35517ac429301119ff05868",
 | 
			
		||||
"assets/assets/images/payment_types/ach.png": "7433f0aff779dc98a649b7a2daf777cf",
 | 
			
		||||
"assets/assets/images/payment_types/dinerscard.png": "06d85186ba858c18ab7c9caa42c92024",
 | 
			
		||||
"assets/assets/images/payment_types/unionpay.png": "7002f52004e0ab8cc0b7450b0208ccb2",
 | 
			
		||||
"assets/assets/images/payment_types/maestro.png": "e533b92bfb50339fdbfa79e3dfe81f08",
 | 
			
		||||
"assets/assets/images/payment_types/paypal.png": "8e06c094c1871376dfea1da8088c29d1",
 | 
			
		||||
"assets/assets/images/payment_types/visa.png": "3ddc4a4d25c946e8ad7e6998f30fd4e3",
 | 
			
		||||
"assets/assets/images/payment_types/solo.png": "2030c3ccaccf5d5e87916a62f5b084d6",
 | 
			
		||||
"assets/assets/images/payment_types/amex.png": "c49a4247984b3732a4af50a3390aa978",
 | 
			
		||||
"assets/assets/images/payment_types/switch.png": "4fa11c45327f5fdc20205821b2cfd9cc",
 | 
			
		||||
"assets/assets/images/payment_types/jcb.png": "07e0942d16c5592118b72e74f2f7198c",
 | 
			
		||||
"assets/assets/images/payment_types/mastercard.png": "6f6cdc29ee2e22e06b1ac029cb52ef71",
 | 
			
		||||
"assets/AssetManifest.json": "38d9aea341601f3a5c6fa7b5a1216ea5",
 | 
			
		||||
"assets/assets/images/icon.png": "090f69e23311a4b6d851b3880ae52541",
 | 
			
		||||
"assets/assets/images/google_logo.png": "0f118259ce403274f407f5e982e681c3",
 | 
			
		||||
"assets/assets/images/logo_light.png": "e5f46d5a78e226e7a9553d4ca6f69219",
 | 
			
		||||
"assets/assets/images/logo_dark.png": "a233ed1d4d0f7414bf97a9a10f11fb0a",
 | 
			
		||||
"assets/NOTICES": "52d7174bb068ef86545951d5bc8c5744",
 | 
			
		||||
"manifest.json": "ef43d90e57aa7682d7e2cfba2f484a40"
 | 
			
		||||
"assets/assets/images/payment_types/jcb.png": "07e0942d16c5592118b72e74f2f7198c",
 | 
			
		||||
"assets/assets/images/payment_types/amex.png": "c49a4247984b3732a4af50a3390aa978",
 | 
			
		||||
"assets/assets/images/payment_types/visa.png": "3ddc4a4d25c946e8ad7e6998f30fd4e3",
 | 
			
		||||
"assets/assets/images/payment_types/mastercard.png": "6f6cdc29ee2e22e06b1ac029cb52ef71",
 | 
			
		||||
"assets/assets/images/payment_types/maestro.png": "e533b92bfb50339fdbfa79e3dfe81f08",
 | 
			
		||||
"assets/assets/images/payment_types/ach.png": "7433f0aff779dc98a649b7a2daf777cf",
 | 
			
		||||
"assets/assets/images/payment_types/discover.png": "6c0a386a00307f87db7bea366cca35f5",
 | 
			
		||||
"assets/assets/images/payment_types/solo.png": "2030c3ccaccf5d5e87916a62f5b084d6",
 | 
			
		||||
"assets/assets/images/payment_types/laser.png": "b4e6e93dd35517ac429301119ff05868",
 | 
			
		||||
"assets/assets/images/payment_types/paypal.png": "8e06c094c1871376dfea1da8088c29d1",
 | 
			
		||||
"assets/assets/images/payment_types/carteblanche.png": "d936e11fa3884b8c9f1bd5c914be8629",
 | 
			
		||||
"assets/assets/images/payment_types/switch.png": "4fa11c45327f5fdc20205821b2cfd9cc",
 | 
			
		||||
"assets/assets/images/payment_types/unionpay.png": "7002f52004e0ab8cc0b7450b0208ccb2",
 | 
			
		||||
"assets/assets/images/payment_types/dinerscard.png": "06d85186ba858c18ab7c9caa42c92024",
 | 
			
		||||
"assets/assets/images/payment_types/other.png": "d936e11fa3884b8c9f1bd5c914be8629",
 | 
			
		||||
"assets/packages/material_design_icons_flutter/lib/fonts/materialdesignicons-webfont.ttf": "b62641afc9ab487008e996a5c5865e56",
 | 
			
		||||
"assets/NOTICES": "9b6b63256d3a6491659b71127ee9f3b6",
 | 
			
		||||
"main.dart.js": "0f10062693740735811a5a29bc063592"
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// The application shell files that are downloaded before a service worker can
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										81
									
								
								public/js/clients/payments/forte-ach-payment.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								public/js/clients/payments/forte-ach-payment.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,81 @@
 | 
			
		||||
/******/ (() => { // webpackBootstrap
 | 
			
		||||
var __webpack_exports__ = {};
 | 
			
		||||
/*!************************************************************!*\
 | 
			
		||||
  !*** ./resources/js/clients/payments/forte-ach-payment.js ***!
 | 
			
		||||
  \************************************************************/
 | 
			
		||||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 | 
			
		||||
 | 
			
		||||
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Invoice Ninja (https://invoiceninja.com)
 | 
			
		||||
 *
 | 
			
		||||
 * @link https://github.com/invoiceninja/invoiceninja source repository
 | 
			
		||||
 *
 | 
			
		||||
 * @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
 | 
			
		||||
 *
 | 
			
		||||
 * @license https://opensource.org/licenses/AAL
 | 
			
		||||
 */
 | 
			
		||||
var ForteAuthorizeACH = function ForteAuthorizeACH(apiLoginId) {
 | 
			
		||||
  var _this = this;
 | 
			
		||||
 | 
			
		||||
  _classCallCheck(this, ForteAuthorizeACH);
 | 
			
		||||
 | 
			
		||||
  _defineProperty(this, "handleAuthorization", function () {
 | 
			
		||||
    var account_number = document.getElementById('account-number').value;
 | 
			
		||||
    var routing_number = document.getElementById('routing-number').value;
 | 
			
		||||
    var data = {
 | 
			
		||||
      api_login_id: _this.apiLoginId,
 | 
			
		||||
      account_number: account_number,
 | 
			
		||||
      routing_number: routing_number,
 | 
			
		||||
      account_type: 'checking'
 | 
			
		||||
    };
 | 
			
		||||
    var payNowButton = document.getElementById('pay-now');
 | 
			
		||||
 | 
			
		||||
    if (payNowButton) {
 | 
			
		||||
      document.getElementById('pay-now').disabled = true;
 | 
			
		||||
      document.querySelector('#pay-now > svg').classList.remove('hidden');
 | 
			
		||||
      document.querySelector('#pay-now > span').classList.add('hidden');
 | 
			
		||||
    } // console.log(data);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    forte.createToken(data).success(_this.successResponseHandler).error(_this.failedResponseHandler);
 | 
			
		||||
    return false;
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  _defineProperty(this, "successResponseHandler", function (response) {
 | 
			
		||||
    document.getElementById('payment_token').value = response.onetime_token;
 | 
			
		||||
    document.getElementById('server_response').submit();
 | 
			
		||||
    return false;
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  _defineProperty(this, "failedResponseHandler", function (response) {
 | 
			
		||||
    var errors = '<div class="alert alert-failure mb-4"><ul><li>' + response.response_description + '</li></ul></div>';
 | 
			
		||||
    document.getElementById('forte_errors').innerHTML = errors;
 | 
			
		||||
    document.getElementById('pay-now').disabled = false;
 | 
			
		||||
    document.querySelector('#pay-now > svg').classList.add('hidden');
 | 
			
		||||
    document.querySelector('#pay-now > span').classList.remove('hidden');
 | 
			
		||||
    return false;
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  _defineProperty(this, "handle", function () {
 | 
			
		||||
    var payNowButton = document.getElementById('pay-now');
 | 
			
		||||
 | 
			
		||||
    if (payNowButton) {
 | 
			
		||||
      payNowButton.addEventListener('click', function (e) {
 | 
			
		||||
        _this.handleAuthorization();
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return _this;
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  this.apiLoginId = apiLoginId;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
var apiLoginId = document.querySelector('meta[name="forte-api-login-id"]').content;
 | 
			
		||||
/** @handle */
 | 
			
		||||
 | 
			
		||||
new ForteAuthorizeACH(apiLoginId).handle();
 | 
			
		||||
/******/ })()
 | 
			
		||||
;
 | 
			
		||||
							
								
								
									
										669
									
								
								public/js/clients/payments/forte-card-js.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										669
									
								
								public/js/clients/payments/forte-card-js.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,669 @@
 | 
			
		||||
(() => {
 | 
			
		||||
    function t(t) {
 | 
			
		||||
        (this.elem = jQuery(t)),
 | 
			
		||||
            (this.captureName =
 | 
			
		||||
                !!this.elem.data('capture-name') &&
 | 
			
		||||
                this.elem.data('capture-name')),
 | 
			
		||||
            (this.iconColour =
 | 
			
		||||
                !!this.elem.data('icon-colour') &&
 | 
			
		||||
                this.elem.data('icon-colour')),
 | 
			
		||||
            (this.stripe =
 | 
			
		||||
                !!this.elem.data('stripe') && this.elem.data('stripe')),
 | 
			
		||||
            this.stripe && (this.captureName = !1),
 | 
			
		||||
            this.initCardNumberInput(),
 | 
			
		||||
            this.initNameInput(),
 | 
			
		||||
            this.initExpiryMonthInput(),
 | 
			
		||||
            this.initExpiryYearInput(),
 | 
			
		||||
            this.initCvcInput(),
 | 
			
		||||
            this.elem.empty(),
 | 
			
		||||
            this.setupCardNumberInput(),
 | 
			
		||||
            this.setupNameInput(),
 | 
			
		||||
            this.setupExpiryInput(),
 | 
			
		||||
            this.setupCvcInput(),
 | 
			
		||||
            this.iconColour && this.setIconColour(this.iconColour),
 | 
			
		||||
            this.refreshCreditCardTypeIcon();
 | 
			
		||||
    }
 | 
			
		||||
    !(function (e) {
 | 
			
		||||
        var r = {
 | 
			
		||||
            init: function () {
 | 
			
		||||
                return this.data('cardjs', new t(this)), this;
 | 
			
		||||
            },
 | 
			
		||||
            cardNumber: function () {
 | 
			
		||||
                return this.data('cardjs').getCardNumber();
 | 
			
		||||
            },
 | 
			
		||||
            cardType: function () {
 | 
			
		||||
                return this.data('cardjs').getCardType();
 | 
			
		||||
            },
 | 
			
		||||
            name: function () {
 | 
			
		||||
                return this.data('cardjs').getName();
 | 
			
		||||
            },
 | 
			
		||||
            expiryMonth: function () {
 | 
			
		||||
                return this.data('cardjs').getExpiryMonth();
 | 
			
		||||
            },
 | 
			
		||||
            expiryYear: function () {
 | 
			
		||||
                return this.data('cardjs').getExpiryYear();
 | 
			
		||||
            },
 | 
			
		||||
            cvc: function () {
 | 
			
		||||
                return this.data('cardjs').getCvc();
 | 
			
		||||
            },
 | 
			
		||||
        };
 | 
			
		||||
        e.fn.CardJs = function (t) {
 | 
			
		||||
            return r[t]
 | 
			
		||||
                ? r[t].apply(this, Array.prototype.slice.call(arguments, 1))
 | 
			
		||||
                : 'object' != typeof t && t
 | 
			
		||||
                ? void e.error(
 | 
			
		||||
                      'Method ' + t + ' does not exist on jQuery.CardJs'
 | 
			
		||||
                  )
 | 
			
		||||
                : r.init.apply(this, arguments);
 | 
			
		||||
        };
 | 
			
		||||
    })(jQuery),
 | 
			
		||||
        $(function () {
 | 
			
		||||
            $('.card-js').each(function (t, e) {
 | 
			
		||||
                $(e).CardJs();
 | 
			
		||||
            });
 | 
			
		||||
        }),
 | 
			
		||||
        (t.prototype.constructor = t),
 | 
			
		||||
        (t.KEYS = {
 | 
			
		||||
            0: 48,
 | 
			
		||||
            9: 57,
 | 
			
		||||
            NUMPAD_0: 96,
 | 
			
		||||
            NUMPAD_9: 105,
 | 
			
		||||
            DELETE: 46,
 | 
			
		||||
            BACKSPACE: 8,
 | 
			
		||||
            ARROW_LEFT: 37,
 | 
			
		||||
            ARROW_RIGHT: 39,
 | 
			
		||||
            ARROW_UP: 38,
 | 
			
		||||
            ARROW_DOWN: 40,
 | 
			
		||||
            HOME: 36,
 | 
			
		||||
            END: 35,
 | 
			
		||||
            TAB: 9,
 | 
			
		||||
            A: 65,
 | 
			
		||||
            X: 88,
 | 
			
		||||
            C: 67,
 | 
			
		||||
            V: 86,
 | 
			
		||||
        }),
 | 
			
		||||
        (t.CREDIT_CARD_NUMBER_DEFAULT_MASK = 'XXXX XXXX XXXX XXXX'),
 | 
			
		||||
        (t.CREDIT_CARD_NUMBER_VISA_MASK = 'XXXX XXXX XXXX XXXX'),
 | 
			
		||||
        (t.CREDIT_CARD_NUMBER_MASTERCARD_MASK = 'XXXX XXXX XXXX XXXX'),
 | 
			
		||||
        (t.CREDIT_CARD_NUMBER_DISCOVER_MASK = 'XXXX XXXX XXXX XXXX'),
 | 
			
		||||
        (t.CREDIT_CARD_NUMBER_JCB_MASK = 'XXXX XXXX XXXX XXXX'),
 | 
			
		||||
        (t.CREDIT_CARD_NUMBER_AMEX_MASK = 'XXXX XXXXXX XXXXX'),
 | 
			
		||||
        (t.CREDIT_CARD_NUMBER_DINERS_MASK = 'XXXX XXXX XXXX XX'),
 | 
			
		||||
        (t.prototype.creditCardNumberMask = t.CREDIT_CARD_NUMBER_DEFAULT_MASK),
 | 
			
		||||
        (t.CREDIT_CARD_NUMBER_PLACEHOLDER = 'Card number'),
 | 
			
		||||
        (t.NAME_PLACEHOLDER = 'Name on card'),
 | 
			
		||||
        (t.EXPIRY_MASK = 'XX / XXXX'),
 | 
			
		||||
        (t.EXPIRY_PLACEHOLDER = 'MM / YYYY'),
 | 
			
		||||
        (t.EXPIRY_USE_DROPDOWNS = !1),
 | 
			
		||||
        (t.EXPIRY_NUMBER_OF_YEARS = 10),
 | 
			
		||||
        (t.CVC_MASK_3 = 'XXX'),
 | 
			
		||||
        (t.CVC_MASK_4 = 'XXXX'),
 | 
			
		||||
        (t.CVC_PLACEHOLDER = 'CVC'),
 | 
			
		||||
        (t.CREDIT_CARD_SVG =
 | 
			
		||||
            '<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="3px" width="24px" height="17px" viewBox="0 0 216 146" enable-background="new 0 0 216 146" xml:space="preserve"><g><path class="svg" d="M182.385,14.258c-2.553-2.553-5.621-3.829-9.205-3.829H42.821c-3.585,0-6.653,1.276-9.207,3.829c-2.553,2.553-3.829,5.621-3.829,9.206v99.071c0,3.585,1.276,6.654,3.829,9.207c2.554,2.553,5.622,3.829,9.207,3.829H173.18c3.584,0,6.652-1.276,9.205-3.829s3.83-5.622,3.83-9.207V23.464C186.215,19.879,184.938,16.811,182.385,14.258z M175.785,122.536c0,0.707-0.258,1.317-0.773,1.834c-0.516,0.515-1.127,0.772-1.832,0.772H42.821c-0.706,0-1.317-0.258-1.833-0.773c-0.516-0.518-0.774-1.127-0.774-1.834V73h135.571V122.536z M175.785,41.713H40.214v-18.25c0-0.706,0.257-1.316,0.774-1.833c0.516-0.515,1.127-0.773,1.833-0.773H173.18c0.705,0,1.316,0.257,1.832,0.773c0.516,0.517,0.773,1.127,0.773,1.833V41.713z"/><rect class="svg" x="50.643" y="104.285" width="20.857" height="10.429"/><rect class="svg" x="81.929" y="104.285" width="31.286" height="10.429"/></g></svg>'),
 | 
			
		||||
        (t.LOCK_SVG =
 | 
			
		||||
            '<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="3px" width="24px" height="17px" viewBox="0 0 216 146" enable-background="new 0 0 216 146" xml:space="preserve"><path class="svg" d="M152.646,70.067c-1.521-1.521-3.367-2.281-5.541-2.281H144.5V52.142c0-9.994-3.585-18.575-10.754-25.745c-7.17-7.17-15.751-10.755-25.746-10.755s-18.577,3.585-25.746,10.755C75.084,33.567,71.5,42.148,71.5,52.142v15.644h-2.607c-2.172,0-4.019,0.76-5.54,2.281c-1.521,1.52-2.281,3.367-2.281,5.541v46.929c0,2.172,0.76,4.019,2.281,5.54c1.521,1.52,3.368,2.281,5.54,2.281h78.214c2.174,0,4.02-0.76,5.541-2.281c1.52-1.521,2.281-3.368,2.281-5.54V75.607C154.93,73.435,154.168,71.588,152.646,70.067z M128.857,67.786H87.143V52.142c0-5.757,2.037-10.673,6.111-14.746c4.074-4.074,8.989-6.11,14.747-6.11s10.673,2.036,14.746,6.11c4.073,4.073,6.11,8.989,6.11,14.746V67.786z"/></svg>'),
 | 
			
		||||
        (t.CALENDAR_SVG =
 | 
			
		||||
            '<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="4px" width="24px" height="16px" viewBox="0 0 216 146" enable-background="new 0 0 216 146" xml:space="preserve"><path class="svg" d="M172.691,23.953c-2.062-2.064-4.508-3.096-7.332-3.096h-10.428v-7.822c0-3.584-1.277-6.653-3.83-9.206c-2.554-2.553-5.621-3.83-9.207-3.83h-5.213c-3.586,0-6.654,1.277-9.207,3.83c-2.554,2.553-3.83,5.622-3.83,9.206v7.822H92.359v-7.822c0-3.584-1.277-6.653-3.83-9.206c-2.553-2.553-5.622-3.83-9.207-3.83h-5.214c-3.585,0-6.654,1.277-9.207,3.83c-2.553,2.553-3.83,5.622-3.83,9.206v7.822H50.643c-2.825,0-5.269,1.032-7.333,3.096s-3.096,4.509-3.096,7.333v104.287c0,2.823,1.032,5.267,3.096,7.332c2.064,2.064,4.508,3.096,7.333,3.096h114.714c2.824,0,5.27-1.032,7.332-3.096c2.064-2.064,3.096-4.509,3.096-7.332V31.286C175.785,28.461,174.754,26.017,172.691,23.953z M134.073,13.036c0-0.761,0.243-1.386,0.731-1.874c0.488-0.488,1.113-0.733,1.875-0.733h5.213c0.762,0,1.385,0.244,1.875,0.733c0.488,0.489,0.732,1.114,0.732,1.874V36.5c0,0.761-0.244,1.385-0.732,1.874c-0.49,0.488-1.113,0.733-1.875,0.733h-5.213c-0.762,0-1.387-0.244-1.875-0.733s-0.731-1.113-0.731-1.874V13.036z M71.501,13.036c0-0.761,0.244-1.386,0.733-1.874c0.489-0.488,1.113-0.733,1.874-0.733h5.214c0.761,0,1.386,0.244,1.874,0.733c0.488,0.489,0.733,1.114,0.733,1.874V36.5c0,0.761-0.244,1.386-0.733,1.874c-0.489,0.488-1.113,0.733-1.874,0.733h-5.214c-0.761,0-1.386-0.244-1.874-0.733c-0.488-0.489-0.733-1.113-0.733-1.874V13.036z M165.357,135.572H50.643V52.143h114.714V135.572z"/></svg>'),
 | 
			
		||||
        (t.USER_SVG =
 | 
			
		||||
            '<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="4px" width="24px" height="16px" viewBox="0 0 216 146" enable-background="new 0 0 216 146" xml:space="preserve"><g><path class="svg" d="M107.999,73c8.638,0,16.011-3.056,22.12-9.166c6.111-6.11,9.166-13.483,9.166-22.12c0-8.636-3.055-16.009-9.166-22.12c-6.11-6.11-13.484-9.165-22.12-9.165c-8.636,0-16.01,3.055-22.12,9.165c-6.111,6.111-9.166,13.484-9.166,22.12c0,8.637,3.055,16.01,9.166,22.12C91.99,69.944,99.363,73,107.999,73z"/><path class="svg" d="M165.07,106.037c-0.191-2.743-0.571-5.703-1.141-8.881c-0.57-3.178-1.291-6.124-2.16-8.84c-0.869-2.715-2.037-5.363-3.504-7.943c-1.466-2.58-3.15-4.78-5.052-6.6s-4.223-3.272-6.965-4.358c-2.744-1.086-5.772-1.63-9.085-1.63c-0.489,0-1.63,0.584-3.422,1.752s-3.815,2.472-6.069,3.911c-2.254,1.438-5.188,2.743-8.799,3.909c-3.612,1.168-7.237,1.752-10.877,1.752c-3.639,0-7.264-0.584-10.876-1.752c-3.611-1.166-6.545-2.471-8.799-3.909c-2.254-1.439-4.277-2.743-6.069-3.911c-1.793-1.168-2.933-1.752-3.422-1.752c-3.313,0-6.341,0.544-9.084,1.63s-5.065,2.539-6.966,4.358c-1.901,1.82-3.585,4.02-5.051,6.6s-2.634,5.229-3.503,7.943c-0.869,2.716-1.589,5.662-2.159,8.84c-0.571,3.178-0.951,6.137-1.141,8.881c-0.19,2.744-0.285,5.554-0.285,8.433c0,6.517,1.983,11.664,5.948,15.439c3.965,3.774,9.234,5.661,15.806,5.661h71.208c6.572,0,11.84-1.887,15.806-5.661c3.966-3.775,5.948-8.921,5.948-15.439C165.357,111.591,165.262,108.78,165.07,106.037z"/></g></svg>'),
 | 
			
		||||
        (t.MAIL_SVG =
 | 
			
		||||
            '<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"x="0px" y="4px" width="24px" height="16px" viewBox="0 0 216 146" enable-background="new 0 0 216 146" xml:space="preserve"><path class="svg" d="M177.171,19.472c-2.553-2.553-5.622-3.829-9.206-3.829H48.036c-3.585,0-6.654,1.276-9.207,3.829C36.276,22.025,35,25.094,35,28.679v88.644c0,3.585,1.276,6.652,3.829,9.205c2.553,2.555,5.622,3.83,9.207,3.83h119.929c3.584,0,6.653-1.275,9.206-3.83c2.554-2.553,3.829-5.621,3.829-9.205V28.679C181,25.094,179.725,22.025,177.171,19.472zM170.57,117.321c0,0.706-0.258,1.317-0.774,1.833s-1.127,0.773-1.832,0.773H48.035c-0.706,0-1.317-0.257-1.833-0.773c-0.516-0.516-0.774-1.127-0.774-1.833V54.75c1.738,1.955,3.612,3.748,5.622,5.377c14.557,11.189,26.126,20.368,34.708,27.538c2.77,2.336,5.024,4.155,6.762,5.459s4.087,2.62,7.047,3.951s5.744,1.995,8.351,1.995H108h0.081c2.606,0,5.392-0.664,8.351-1.995c2.961-1.331,5.311-2.647,7.049-3.951c1.737-1.304,3.992-3.123,6.762-5.459c8.582-7.17,20.15-16.349,34.707-27.538c2.01-1.629,3.885-3.422,5.621-5.377V117.321z M170.57,30.797v0.896c0,3.204-1.262,6.776-3.787,10.713c-2.525,3.938-5.256,7.075-8.188,9.41c-10.484,8.257-21.373,16.865-32.672,25.827c-0.326,0.271-1.277,1.073-2.852,2.403c-1.574,1.331-2.824,2.351-3.748,3.056c-0.924,0.707-2.131,1.562-3.625,2.566s-2.865,1.752-4.114,2.24s-2.417,0.732-3.503,0.732H108h-0.082c-1.086,0-2.253-0.244-3.503-0.732c-1.249-0.488-2.621-1.236-4.114-2.24c-1.493-1.004-2.702-1.859-3.625-2.566c-0.923-0.705-2.173-1.725-3.748-3.056c-1.575-1.33-2.526-2.132-2.852-2.403c-11.297-8.962-22.187-17.57-32.67-25.827c-7.985-6.3-11.977-14.013-11.977-23.138c0-0.706,0.258-1.317,0.774-1.833c0.516-0.516,1.127-0.774,1.833-0.774h119.929c0.434,0.244,0.814,0.312,1.141,0.204c0.326-0.11,0.57,0.094,0.732,0.61c0.163,0.516,0.312,0.76,0.448,0.733c0.136-0.027,0.218,0.312,0.245,1.019c0.025,0.706,0.039,1.061,0.039,1.061V30.797z"/></svg>'),
 | 
			
		||||
        (t.INFORMATION_SVG =
 | 
			
		||||
            '<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="4px" width="24px" height="16px" viewBox="0 0 216 146" enable-background="new 0 0 216 146" xml:space="preserve"><g><path class="svg" d="M97.571,41.714h20.859c1.411,0,2.633-0.516,3.666-1.548c1.031-1.031,1.547-2.254,1.547-3.666V20.857c0-1.412-0.516-2.634-1.549-3.667c-1.031-1.031-2.254-1.548-3.666-1.548H97.571c-1.412,0-2.634,0.517-3.666,1.548c-1.032,1.032-1.548,2.255-1.548,3.667V36.5c0,1.412,0.516,2.635,1.548,3.666C94.937,41.198,96.159,41.714,97.571,41.714z"/><path class="svg" d="M132.523,111.048c-1.031-1.032-2.254-1.548-3.666-1.548h-5.215V62.571c0-1.412-0.516-2.634-1.547-3.666c-1.033-1.032-2.255-1.548-3.666-1.548H87.143c-1.412,0-2.634,0.516-3.666,1.548c-1.032,1.032-1.548,2.254-1.548,3.666V73c0,1.412,0.516,2.635,1.548,3.666c1.032,1.032,2.254,1.548,3.666,1.548h5.215V109.5h-5.215c-1.412,0-2.634,0.516-3.666,1.548c-1.032,1.032-1.548,2.254-1.548,3.666v10.429c0,1.412,0.516,2.635,1.548,3.668c1.032,1.03,2.254,1.547,3.666,1.547h41.714c1.412,0,2.634-0.517,3.666-1.547c1.031-1.033,1.547-2.256,1.547-3.668v-10.429C134.07,113.302,133.557,112.08,132.523,111.048z"/></g></svg>'),
 | 
			
		||||
        (t.keyCodeFromEvent = function (t) {
 | 
			
		||||
            return t.which || t.keyCode;
 | 
			
		||||
        }),
 | 
			
		||||
        (t.keyIsCommandFromEvent = function (t) {
 | 
			
		||||
            return t.ctrlKey || t.metaKey;
 | 
			
		||||
        }),
 | 
			
		||||
        (t.keyIsNumber = function (e) {
 | 
			
		||||
            return t.keyIsTopNumber(e) || t.keyIsKeypadNumber(e);
 | 
			
		||||
        }),
 | 
			
		||||
        (t.keyIsTopNumber = function (e) {
 | 
			
		||||
            var r = t.keyCodeFromEvent(e);
 | 
			
		||||
            return r >= t.KEYS[0] && r <= t.KEYS[9];
 | 
			
		||||
        }),
 | 
			
		||||
        (t.keyIsKeypadNumber = function (e) {
 | 
			
		||||
            var r = t.keyCodeFromEvent(e);
 | 
			
		||||
            return r >= t.KEYS.NUMPAD_0 && r <= t.KEYS.NUMPAD_9;
 | 
			
		||||
        }),
 | 
			
		||||
        (t.keyIsDelete = function (e) {
 | 
			
		||||
            return t.keyCodeFromEvent(e) == t.KEYS.DELETE;
 | 
			
		||||
        }),
 | 
			
		||||
        (t.keyIsBackspace = function (e) {
 | 
			
		||||
            return t.keyCodeFromEvent(e) == t.KEYS.BACKSPACE;
 | 
			
		||||
        }),
 | 
			
		||||
        (t.keyIsDeletion = function (e) {
 | 
			
		||||
            return t.keyIsDelete(e) || t.keyIsBackspace(e);
 | 
			
		||||
        }),
 | 
			
		||||
        (t.keyIsArrow = function (e) {
 | 
			
		||||
            var r = t.keyCodeFromEvent(e);
 | 
			
		||||
            return r >= t.KEYS.ARROW_LEFT && r <= t.KEYS.ARROW_DOWN;
 | 
			
		||||
        }),
 | 
			
		||||
        (t.keyIsNavigation = function (e) {
 | 
			
		||||
            var r = t.keyCodeFromEvent(e);
 | 
			
		||||
            return r == t.KEYS.HOME || r == t.KEYS.END;
 | 
			
		||||
        }),
 | 
			
		||||
        (t.keyIsKeyboardCommand = function (e) {
 | 
			
		||||
            var r = t.keyCodeFromEvent(e);
 | 
			
		||||
            return (
 | 
			
		||||
                t.keyIsCommandFromEvent(e) &&
 | 
			
		||||
                (r == t.KEYS.A ||
 | 
			
		||||
                    r == t.KEYS.X ||
 | 
			
		||||
                    r == t.KEYS.C ||
 | 
			
		||||
                    r == t.KEYS.V)
 | 
			
		||||
            );
 | 
			
		||||
        }),
 | 
			
		||||
        (t.keyIsTab = function (e) {
 | 
			
		||||
            return t.keyCodeFromEvent(e) == t.KEYS.TAB;
 | 
			
		||||
        }),
 | 
			
		||||
        (t.copyAllElementAttributes = function (t, e) {
 | 
			
		||||
            $.each(t[0].attributes, function (t, r) {
 | 
			
		||||
                e.attr(r.nodeName, r.nodeValue);
 | 
			
		||||
            });
 | 
			
		||||
        }),
 | 
			
		||||
        (t.numbersOnlyString = function (t) {
 | 
			
		||||
            for (var e = '', r = 0; r < t.length; r++) {
 | 
			
		||||
                var n = t.charAt(r);
 | 
			
		||||
                !isNaN(parseInt(n)) && (e += n);
 | 
			
		||||
            }
 | 
			
		||||
            return e;
 | 
			
		||||
        }),
 | 
			
		||||
        (t.applyFormatMask = function (t, e) {
 | 
			
		||||
            for (var r = '', n = 0, i = 0; i < e.length; i++) {
 | 
			
		||||
                var a = e[i];
 | 
			
		||||
                if ('X' == a) {
 | 
			
		||||
                    if (!t.charAt(n)) break;
 | 
			
		||||
                    (r += t.charAt(n)), n++;
 | 
			
		||||
                } else r += a;
 | 
			
		||||
            }
 | 
			
		||||
            return r;
 | 
			
		||||
        }),
 | 
			
		||||
        (t.cardTypeFromNumber = function (t) {
 | 
			
		||||
            if (((e = new RegExp('^30[0-5]')), null != t.match(e)))
 | 
			
		||||
                return 'Diners - Carte Blanche';
 | 
			
		||||
            if (((e = new RegExp('^(30[6-9]|36|38)')), null != t.match(e)))
 | 
			
		||||
                return 'Diners';
 | 
			
		||||
            if (((e = new RegExp('^35(2[89]|[3-8][0-9])')), null != t.match(e)))
 | 
			
		||||
                return 'JCB';
 | 
			
		||||
            if (((e = new RegExp('^3[47]')), null != t.match(e))) return 'AMEX';
 | 
			
		||||
            if (
 | 
			
		||||
                ((e = new RegExp('^(4026|417500|4508|4844|491(3|7))')),
 | 
			
		||||
                null != t.match(e))
 | 
			
		||||
            )
 | 
			
		||||
                return 'Visa Electron';
 | 
			
		||||
            var e = new RegExp('^4');
 | 
			
		||||
            return null != t.match(e)
 | 
			
		||||
                ? 'Visa'
 | 
			
		||||
                : ((e = new RegExp('^5[1-5]')),
 | 
			
		||||
                  null != t.match(e)
 | 
			
		||||
                      ? 'Mastercard'
 | 
			
		||||
                      : ((e = new RegExp(
 | 
			
		||||
                            '^(6011|622(12[6-9]|1[3-9][0-9]|[2-8][0-9]{2}|9[0-1][0-9]|92[0-5]|64[4-9])|65)'
 | 
			
		||||
                        )),
 | 
			
		||||
                        null != t.match(e) ? 'Discover' : ''));
 | 
			
		||||
        }),
 | 
			
		||||
        (t.caretStartPosition = function (t) {
 | 
			
		||||
            return 'number' == typeof t.selectionStart && t.selectionStart;
 | 
			
		||||
        }),
 | 
			
		||||
        (t.caretEndPosition = function (t) {
 | 
			
		||||
            return 'number' == typeof t.selectionEnd && t.selectionEnd;
 | 
			
		||||
        }),
 | 
			
		||||
        (t.setCaretPosition = function (t, e) {
 | 
			
		||||
            if (null != t)
 | 
			
		||||
                if (t.createTextRange) {
 | 
			
		||||
                    var r = t.createTextRange();
 | 
			
		||||
                    r.move('character', e), r.select();
 | 
			
		||||
                } else
 | 
			
		||||
                    t.selectionStart
 | 
			
		||||
                        ? (t.focus(), t.setSelectionRange(e, e))
 | 
			
		||||
                        : t.focus();
 | 
			
		||||
        }),
 | 
			
		||||
        (t.normaliseCaretPosition = function (t, e) {
 | 
			
		||||
            var r = 0;
 | 
			
		||||
            if (0 > e || e > t.length) return 0;
 | 
			
		||||
            for (var n = 0; n < t.length; n++) {
 | 
			
		||||
                if (n == e) return r;
 | 
			
		||||
                'X' == t[n] && r++;
 | 
			
		||||
            }
 | 
			
		||||
            return r;
 | 
			
		||||
        }),
 | 
			
		||||
        (t.denormaliseCaretPosition = function (t, e) {
 | 
			
		||||
            var r = 0;
 | 
			
		||||
            if (0 > e || e > t.length) return 0;
 | 
			
		||||
            for (var n = 0; n < t.length; n++) {
 | 
			
		||||
                if (r == e) return n;
 | 
			
		||||
                'X' == t[n] && r++;
 | 
			
		||||
            }
 | 
			
		||||
            return t.length;
 | 
			
		||||
        }),
 | 
			
		||||
        (t.filterNumberOnlyKey = function (e) {
 | 
			
		||||
            var r = t.keyIsNumber(e),
 | 
			
		||||
                n = t.keyIsDeletion(e),
 | 
			
		||||
                i = t.keyIsArrow(e),
 | 
			
		||||
                a = t.keyIsNavigation(e),
 | 
			
		||||
                s = t.keyIsKeyboardCommand(e),
 | 
			
		||||
                p = t.keyIsTab(e);
 | 
			
		||||
            r || n || i || a || s || p || e.preventDefault();
 | 
			
		||||
        }),
 | 
			
		||||
        (t.digitFromKeyCode = function (e) {
 | 
			
		||||
            return e >= t.KEYS[0] && e <= t.KEYS[9]
 | 
			
		||||
                ? e - t.KEYS[0]
 | 
			
		||||
                : e >= t.KEYS.NUMPAD_0 && e <= t.KEYS.NUMPAD_9
 | 
			
		||||
                ? e - t.KEYS.NUMPAD_0
 | 
			
		||||
                : null;
 | 
			
		||||
        }),
 | 
			
		||||
        (t.handleMaskedNumberInputKey = function (e, r) {
 | 
			
		||||
            t.filterNumberOnlyKey(e);
 | 
			
		||||
            var n = e.which || e.keyCode,
 | 
			
		||||
                i = e.target,
 | 
			
		||||
                a = t.caretStartPosition(i),
 | 
			
		||||
                s = t.caretEndPosition(i),
 | 
			
		||||
                p = t.normaliseCaretPosition(r, a),
 | 
			
		||||
                c = t.normaliseCaretPosition(r, s),
 | 
			
		||||
                o = a,
 | 
			
		||||
                u = t.keyIsNumber(e),
 | 
			
		||||
                h = t.keyIsDelete(e),
 | 
			
		||||
                d = t.keyIsBackspace(e);
 | 
			
		||||
            if (u || h || d) {
 | 
			
		||||
                e.preventDefault();
 | 
			
		||||
                var l = $(i).val(),
 | 
			
		||||
                    y = t.numbersOnlyString(l),
 | 
			
		||||
                    m = t.digitFromKeyCode(n),
 | 
			
		||||
                    C = c > p;
 | 
			
		||||
                C && (y = y.slice(0, p) + y.slice(c)),
 | 
			
		||||
                    a != r.length &&
 | 
			
		||||
                        (u &&
 | 
			
		||||
                            l.length <= r.length &&
 | 
			
		||||
                            ((y = y.slice(0, p) + m + y.slice(p)),
 | 
			
		||||
                            (o = Math.max(
 | 
			
		||||
                                t.denormaliseCaretPosition(r, p + 1),
 | 
			
		||||
                                t.denormaliseCaretPosition(r, p + 2) - 1
 | 
			
		||||
                            ))),
 | 
			
		||||
                        h && (y = y.slice(0, p) + y.slice(p + 1))),
 | 
			
		||||
                    0 != a &&
 | 
			
		||||
                        d &&
 | 
			
		||||
                        !C &&
 | 
			
		||||
                        ((y = y.slice(0, p - 1) + y.slice(p)),
 | 
			
		||||
                        (o = t.denormaliseCaretPosition(r, p - 1))),
 | 
			
		||||
                    $(i).val(t.applyFormatMask(y, r)),
 | 
			
		||||
                    t.setCaretPosition(i, o);
 | 
			
		||||
            }
 | 
			
		||||
        }),
 | 
			
		||||
        (t.handleCreditCardNumberKey = function (e, r) {
 | 
			
		||||
            t.handleMaskedNumberInputKey(e, r);
 | 
			
		||||
        }),
 | 
			
		||||
        (t.handleCreditCardNumberChange = function (t) {}),
 | 
			
		||||
        (t.handleExpiryKey = function (e) {
 | 
			
		||||
            t.handleMaskedNumberInputKey(e, t.EXPIRY_MASK);
 | 
			
		||||
        }),
 | 
			
		||||
        (t.prototype.getCardNumber = function () {
 | 
			
		||||
            return this.cardNumberInput.val();
 | 
			
		||||
        }),
 | 
			
		||||
        (t.prototype.getCardType = function () {
 | 
			
		||||
            return t.cardTypeFromNumber(this.getCardNumber());
 | 
			
		||||
        }),
 | 
			
		||||
        (t.prototype.getName = function () {
 | 
			
		||||
            return this.nameInput.val();
 | 
			
		||||
        }),
 | 
			
		||||
        (t.prototype.getExpiryMonth = function () {
 | 
			
		||||
            return this.expiryMonthInput.val();
 | 
			
		||||
        }),
 | 
			
		||||
        (t.prototype.getExpiryYear = function () {
 | 
			
		||||
            return this.expiryYearInput.val();
 | 
			
		||||
        }),
 | 
			
		||||
        (t.prototype.getCvc = function () {
 | 
			
		||||
            return this.cvcInput.val();
 | 
			
		||||
        }),
 | 
			
		||||
        (t.prototype.setIconColour = function (t) {
 | 
			
		||||
            this.elem.find('.icon .svg').css({ fill: t });
 | 
			
		||||
        }),
 | 
			
		||||
        (t.prototype.setIconColour = function (t) {
 | 
			
		||||
            this.elem.find('.icon .svg').css({ fill: t });
 | 
			
		||||
        }),
 | 
			
		||||
        (t.prototype.refreshCreditCardTypeIcon = function () {
 | 
			
		||||
            this.setCardTypeIconFromNumber(
 | 
			
		||||
                t.numbersOnlyString(this.cardNumberInput.val())
 | 
			
		||||
            );
 | 
			
		||||
        }),
 | 
			
		||||
        (t.prototype.clearCardTypeIcon = function () {
 | 
			
		||||
            this.elem
 | 
			
		||||
                .find('.card-number-wrapper .card-type-icon')
 | 
			
		||||
                .removeClass('show');
 | 
			
		||||
        }),
 | 
			
		||||
        (t.prototype.setCardTypeIconAsVisa = function () {
 | 
			
		||||
            this.elem
 | 
			
		||||
                .find('.card-number-wrapper .card-type-icon')
 | 
			
		||||
                .attr('class', 'card-type-icon show visa');
 | 
			
		||||
        }),
 | 
			
		||||
        (t.prototype.setCardTypeIconAsMasterCard = function () {
 | 
			
		||||
            this.elem
 | 
			
		||||
                .find('.card-number-wrapper .card-type-icon')
 | 
			
		||||
                .attr('class', 'card-type-icon show master-card');
 | 
			
		||||
        }),
 | 
			
		||||
        (t.prototype.setCardTypeIconAsAmericanExpress = function () {
 | 
			
		||||
            this.elem
 | 
			
		||||
                .find('.card-number-wrapper .card-type-icon')
 | 
			
		||||
                .attr('class', 'card-type-icon show american-express');
 | 
			
		||||
        }),
 | 
			
		||||
        (t.prototype.setCardTypeIconAsDiscover = function () {
 | 
			
		||||
            this.elem
 | 
			
		||||
                .find('.card-number-wrapper .card-type-icon')
 | 
			
		||||
                .attr('class', 'card-type-icon show discover');
 | 
			
		||||
        }),
 | 
			
		||||
        (t.prototype.setCardTypeIconAsDiners = function () {
 | 
			
		||||
            this.elem
 | 
			
		||||
                .find('.card-number-wrapper .card-type-icon')
 | 
			
		||||
                .attr('class', 'card-type-icon show diners');
 | 
			
		||||
        }),
 | 
			
		||||
        (t.prototype.setCardTypeIconAsJcb = function () {
 | 
			
		||||
            this.elem
 | 
			
		||||
                .find('.card-number-wrapper .card-type-icon')
 | 
			
		||||
                .attr('class', 'card-type-icon show jcb');
 | 
			
		||||
        }),
 | 
			
		||||
        (t.prototype.setCardTypeIconFromNumber = function (e) {
 | 
			
		||||
            switch (t.cardTypeFromNumber(e)) {
 | 
			
		||||
                case 'Visa Electron':
 | 
			
		||||
                case 'Visa':
 | 
			
		||||
                    this.setCardTypeAsVisa();
 | 
			
		||||
                    break;
 | 
			
		||||
                case 'Mastercard':
 | 
			
		||||
                    this.setCardTypeAsMasterCard();
 | 
			
		||||
                    break;
 | 
			
		||||
                case 'AMEX':
 | 
			
		||||
                    this.setCardTypeAsAmericanExpress();
 | 
			
		||||
                    break;
 | 
			
		||||
                case 'Discover':
 | 
			
		||||
                    this.setCardTypeAsDiscover();
 | 
			
		||||
                    break;
 | 
			
		||||
                case 'Diners - Carte Blanche':
 | 
			
		||||
                case 'Diners':
 | 
			
		||||
                    this.setCardTypeAsDiners();
 | 
			
		||||
                    break;
 | 
			
		||||
                case 'JCB':
 | 
			
		||||
                    this.setCardTypeAsJcb();
 | 
			
		||||
                    break;
 | 
			
		||||
                default:
 | 
			
		||||
                    this.clearCardType();
 | 
			
		||||
            }
 | 
			
		||||
        }),
 | 
			
		||||
        (t.prototype.setCardMask = function (t) {
 | 
			
		||||
            (this.creditCardNumberMask = t),
 | 
			
		||||
                this.cardNumberInput.attr('maxlength', t.length);
 | 
			
		||||
        }),
 | 
			
		||||
        (t.prototype.setCvc3 = function () {
 | 
			
		||||
            this.cvcInput.attr('maxlength', t.CVC_MASK_3.length);
 | 
			
		||||
        }),
 | 
			
		||||
        (t.prototype.setCvc4 = function () {
 | 
			
		||||
            this.cvcInput.attr('maxlength', t.CVC_MASK_4.length);
 | 
			
		||||
        }),
 | 
			
		||||
        (t.prototype.clearCardType = function () {
 | 
			
		||||
            this.clearCardTypeIcon(),
 | 
			
		||||
                this.setCardMask(t.CREDIT_CARD_NUMBER_DEFAULT_MASK),
 | 
			
		||||
                this.setCvc3();
 | 
			
		||||
        }),
 | 
			
		||||
        (t.prototype.setCardTypeAsVisa = function () {
 | 
			
		||||
            this.setCardTypeIconAsVisa(),
 | 
			
		||||
                this.setCardMask(t.CREDIT_CARD_NUMBER_VISA_MASK),
 | 
			
		||||
                this.setCvc3();
 | 
			
		||||
        }),
 | 
			
		||||
        (t.prototype.setCardTypeAsMasterCard = function () {
 | 
			
		||||
            this.setCardTypeIconAsMasterCard(),
 | 
			
		||||
                this.setCardMask(t.CREDIT_CARD_NUMBER_MASTERCARD_MASK),
 | 
			
		||||
                this.setCvc3();
 | 
			
		||||
        }),
 | 
			
		||||
        (t.prototype.setCardTypeAsAmericanExpress = function () {
 | 
			
		||||
            this.setCardTypeIconAsAmericanExpress(),
 | 
			
		||||
                this.setCardMask(t.CREDIT_CARD_NUMBER_AMEX_MASK),
 | 
			
		||||
                this.setCvc4();
 | 
			
		||||
        }),
 | 
			
		||||
        (t.prototype.setCardTypeAsDiscover = function () {
 | 
			
		||||
            this.setCardTypeIconAsDiscover(),
 | 
			
		||||
                this.setCardMask(t.CREDIT_CARD_NUMBER_DISCOVER_MASK),
 | 
			
		||||
                this.setCvc3();
 | 
			
		||||
        }),
 | 
			
		||||
        (t.prototype.setCardTypeAsDiners = function () {
 | 
			
		||||
            this.setCardTypeIconAsDiners(),
 | 
			
		||||
                this.setCardMask(t.CREDIT_CARD_NUMBER_DINERS_MASK),
 | 
			
		||||
                this.setCvc3();
 | 
			
		||||
        }),
 | 
			
		||||
        (t.prototype.setCardTypeAsJcb = function () {
 | 
			
		||||
            this.setCardTypeIconAsJcb(),
 | 
			
		||||
                this.setCardMask(t.CREDIT_CARD_NUMBER_JCB_MASK),
 | 
			
		||||
                this.setCvc3();
 | 
			
		||||
        }),
 | 
			
		||||
        (t.prototype.initCardNumberInput = function () {
 | 
			
		||||
            var e = this;
 | 
			
		||||
            (this.cardNumberInput = this.elem.find('.card-number')),
 | 
			
		||||
                this.cardNumberInput[0]
 | 
			
		||||
                    ? this.cardNumberInput.detach()
 | 
			
		||||
                    : (this.cardNumberInput = $(
 | 
			
		||||
                          "<input class='card-number' />"
 | 
			
		||||
                      )),
 | 
			
		||||
                this.cardNumberInput.attr('type', 'tel'),
 | 
			
		||||
                this.cardNumberInput.attr('placeholder') ||
 | 
			
		||||
                    this.cardNumberInput.attr(
 | 
			
		||||
                        'placeholder',
 | 
			
		||||
                        t.CREDIT_CARD_NUMBER_PLACEHOLDER
 | 
			
		||||
                    ),
 | 
			
		||||
                this.cardNumberInput.attr(
 | 
			
		||||
                    'maxlength',
 | 
			
		||||
                    this.creditCardNumberMask.length
 | 
			
		||||
                ),
 | 
			
		||||
                this.cardNumberInput.attr('x-autocompletetype', 'cc-number'),
 | 
			
		||||
                this.cardNumberInput.attr('autocompletetype', 'cc-number'),
 | 
			
		||||
                this.cardNumberInput.attr('autocorrect', 'off'),
 | 
			
		||||
                this.cardNumberInput.attr('spellcheck', 'off'),
 | 
			
		||||
                this.cardNumberInput.attr('autocapitalize', 'off'),
 | 
			
		||||
                this.cardNumberInput.keydown(function (r) {
 | 
			
		||||
                    t.handleCreditCardNumberKey(r, e.creditCardNumberMask);
 | 
			
		||||
                }),
 | 
			
		||||
                this.cardNumberInput.keyup(function (t) {
 | 
			
		||||
                    e.refreshCreditCardTypeIcon();
 | 
			
		||||
                }),
 | 
			
		||||
                this.cardNumberInput.change(t.handleCreditCardNumberChange);
 | 
			
		||||
        }),
 | 
			
		||||
        (t.prototype.initNameInput = function () {
 | 
			
		||||
            (this.nameInput = this.elem.find('.name')),
 | 
			
		||||
                this.nameInput[0]
 | 
			
		||||
                    ? ((this.captureName = !0), this.nameInput.detach())
 | 
			
		||||
                    : (this.nameInput = $("<input class='name' />")),
 | 
			
		||||
                this.nameInput.attr('placeholder') ||
 | 
			
		||||
                    this.nameInput.attr('placeholder', t.NAME_PLACEHOLDER);
 | 
			
		||||
        }),
 | 
			
		||||
        (t.prototype.initExpiryMonthInput = function () {
 | 
			
		||||
            (this.expiryMonthInput = this.elem.find('.expiry-month')),
 | 
			
		||||
                this.expiryMonthInput[0]
 | 
			
		||||
                    ? this.expiryMonthInput.detach()
 | 
			
		||||
                    : (this.expiryMonthInput = $(
 | 
			
		||||
                          "<input class='expiry-month' />"
 | 
			
		||||
                      ));
 | 
			
		||||
        }),
 | 
			
		||||
        (t.prototype.initExpiryYearInput = function () {
 | 
			
		||||
            (this.expiryYearInput = this.elem.find('.expiry-year')),
 | 
			
		||||
                this.expiryYearInput[0]
 | 
			
		||||
                    ? this.expiryYearInput.detach()
 | 
			
		||||
                    : (this.expiryYearInput = $(
 | 
			
		||||
                          "<input class='expiry-year' name='expiry-year' />"
 | 
			
		||||
                      ));
 | 
			
		||||
        }),
 | 
			
		||||
        (t.prototype.initCvcInput = function () {
 | 
			
		||||
            (this.cvcInput = this.elem.find('.cvc')),
 | 
			
		||||
                this.cvcInput[0]
 | 
			
		||||
                    ? this.cvcInput.detach()
 | 
			
		||||
                    : (this.cvcInput = $("<input class='cvc' />")),
 | 
			
		||||
                this.cvcInput.attr('type', 'tel'),
 | 
			
		||||
                this.cvcInput.attr('placeholder') ||
 | 
			
		||||
                    this.cvcInput.attr('placeholder', t.CVC_PLACEHOLDER),
 | 
			
		||||
                this.cvcInput.attr('maxlength', t.CVC_MASK_3.length),
 | 
			
		||||
                this.cvcInput.attr('x-autocompletetype', 'cc-csc'),
 | 
			
		||||
                this.cvcInput.attr('autocompletetype', 'cc-csc'),
 | 
			
		||||
                this.cvcInput.attr('autocorrect', 'off'),
 | 
			
		||||
                this.cvcInput.attr('spellcheck', 'off'),
 | 
			
		||||
                this.cvcInput.attr('autocapitalize', 'off'),
 | 
			
		||||
                this.cvcInput.keydown(t.filterNumberOnlyKey);
 | 
			
		||||
        }),
 | 
			
		||||
        (t.prototype.setupCardNumberInput = function () {
 | 
			
		||||
            this.stripe && this.cardNumberInput.attr('data-stripe', 'number'),
 | 
			
		||||
                this.elem.append("<div class='card-number-wrapper'></div>");
 | 
			
		||||
            var e = this.elem.find('.card-number-wrapper');
 | 
			
		||||
            e.append(this.cardNumberInput),
 | 
			
		||||
                e.append("<div class='card-type-icon'></div>"),
 | 
			
		||||
                e.append("<div class='icon'></div>"),
 | 
			
		||||
                e.find('.icon').append(t.CREDIT_CARD_SVG);
 | 
			
		||||
        }),
 | 
			
		||||
        (t.prototype.setupNameInput = function () {
 | 
			
		||||
            if (this.captureName) {
 | 
			
		||||
                this.elem.append("<div class='name-wrapper'></div>");
 | 
			
		||||
                var e = this.elem.find('.name-wrapper');
 | 
			
		||||
                e.append(this.nameInput),
 | 
			
		||||
                    e.append("<div class='icon'></div>"),
 | 
			
		||||
                    e.find('.icon').append(t.USER_SVG);
 | 
			
		||||
            }
 | 
			
		||||
        }),
 | 
			
		||||
        (t.prototype.setupExpiryInput = function () {
 | 
			
		||||
            this.elem.append(
 | 
			
		||||
                "<div class='expiry-container'><div class='expiry-wrapper'></div></div>"
 | 
			
		||||
            );
 | 
			
		||||
            var e,
 | 
			
		||||
                r = this.elem.find('.expiry-wrapper');
 | 
			
		||||
            if (this.EXPIRY_USE_DROPDOWNS) {
 | 
			
		||||
                e = $('<div></div>');
 | 
			
		||||
                var n = $(
 | 
			
		||||
                        "<select><option value='any' selected='' hidden=''>MM</option><option value='1'>01</option><option value='2'>02</option><option value='3'>03</option><option value='4'>04</option><option value='5'>05</option><option value='6'>06</option><option value='7'>07</option><option value='8'>08</option><option value='9'>09</option><option value='10'>10</option><option value='11'>11</option><option value='12'>12</option></select>"
 | 
			
		||||
                    ),
 | 
			
		||||
                    i = this.expiryMonthInput;
 | 
			
		||||
                t.copyAllElementAttributes(i, n),
 | 
			
		||||
                    this.expiryMonthInput.remove(),
 | 
			
		||||
                    (this.expiryMonthInput = n);
 | 
			
		||||
                for (
 | 
			
		||||
                    var a = $(
 | 
			
		||||
                            "<select><option value='any' selected='' hidden=''>YY</option></select>"
 | 
			
		||||
                        ),
 | 
			
		||||
                        s = parseInt(
 | 
			
		||||
                            new Date().getFullYear().toString().substring(2, 4)
 | 
			
		||||
                        ),
 | 
			
		||||
                        p = 0;
 | 
			
		||||
                    p < t.EXPIRY_NUMBER_OF_YEARS;
 | 
			
		||||
                    p++
 | 
			
		||||
                )
 | 
			
		||||
                    a.append("<option value='" + s + "'>" + s + '</option>'),
 | 
			
		||||
                        (s = (s + 1) % 100);
 | 
			
		||||
                var c = this.expiryYearInput;
 | 
			
		||||
                t.copyAllElementAttributes(c, a),
 | 
			
		||||
                    this.expiryYearInput.remove(),
 | 
			
		||||
                    (this.expiryYearInput = a),
 | 
			
		||||
                    e.append(this.expiryMonthInput),
 | 
			
		||||
                    e.append(this.expiryYearInput);
 | 
			
		||||
            } else {
 | 
			
		||||
                (e = $('<div></div>')),
 | 
			
		||||
                    (this.expiryMonthInput = $(
 | 
			
		||||
                        "<input type='hidden' name='expiry-month' />"
 | 
			
		||||
                    )),
 | 
			
		||||
                    (this.expiryYearInput = $(
 | 
			
		||||
                        "<input type='hidden' name='expiry-year' />"
 | 
			
		||||
                    )),
 | 
			
		||||
                    this.stripe &&
 | 
			
		||||
                        (this.expiryMonthInput.attr('data-stripe', 'exp-month'),
 | 
			
		||||
                        this.expiryYearInput.attr('data-stripe', 'exp-year')),
 | 
			
		||||
                    (this.expiryMonthYearInput = $("<input class='expiry' />")),
 | 
			
		||||
                    this.expiryMonthYearInput.attr('type', 'tel'),
 | 
			
		||||
                    this.expiryMonthYearInput.attr('placeholder') ||
 | 
			
		||||
                        this.expiryMonthYearInput.attr(
 | 
			
		||||
                            'placeholder',
 | 
			
		||||
                            t.EXPIRY_PLACEHOLDER
 | 
			
		||||
                        ),
 | 
			
		||||
                    this.expiryMonthYearInput.attr(
 | 
			
		||||
                        'maxlength',
 | 
			
		||||
                        t.EXPIRY_MASK.length
 | 
			
		||||
                    ),
 | 
			
		||||
                    this.expiryMonthYearInput.attr(
 | 
			
		||||
                        'x-autocompletetype',
 | 
			
		||||
                        'cc-exp'
 | 
			
		||||
                    ),
 | 
			
		||||
                    this.expiryMonthYearInput.attr(
 | 
			
		||||
                        'autocompletetype',
 | 
			
		||||
                        'cc-exp'
 | 
			
		||||
                    ),
 | 
			
		||||
                    this.expiryMonthYearInput.attr('autocorrect', 'off'),
 | 
			
		||||
                    this.expiryMonthYearInput.attr('spellcheck', 'off'),
 | 
			
		||||
                    this.expiryMonthYearInput.attr('autocapitalize', 'off');
 | 
			
		||||
                var o = this;
 | 
			
		||||
                this.expiryMonthYearInput.keydown(function (e) {
 | 
			
		||||
                    t.handleExpiryKey(e);
 | 
			
		||||
                    var r = o.expiryMonthYearInput.val();
 | 
			
		||||
                    1 == r.length &&
 | 
			
		||||
                        parseInt(r) > 1 &&
 | 
			
		||||
                        t.keyIsNumber(e) &&
 | 
			
		||||
                        o.expiryMonthYearInput.val(
 | 
			
		||||
                            t.applyFormatMask('0' + r, t.EXPIRY_MASK)
 | 
			
		||||
                        ),
 | 
			
		||||
                        o.EXPIRY_USE_DROPDOWNS ||
 | 
			
		||||
                            null == o.expiryMonthYearInput ||
 | 
			
		||||
                            (o.expiryMonthInput.val(o.expiryMonth()),
 | 
			
		||||
                            o.expiryYearInput.val(
 | 
			
		||||
                                9 == r.length ? r.substr(5, 4) : null
 | 
			
		||||
                            ));
 | 
			
		||||
                }),
 | 
			
		||||
                    this.expiryMonthYearInput.blur(function (t) {
 | 
			
		||||
                        o.refreshExpiryMonthValidation();
 | 
			
		||||
                    }),
 | 
			
		||||
                    e.append(this.expiryMonthYearInput),
 | 
			
		||||
                    e.append(this.expiryMonthInput),
 | 
			
		||||
                    e.append(this.expiryYearInput);
 | 
			
		||||
            }
 | 
			
		||||
            r.append(e),
 | 
			
		||||
                r.append("<div class='icon'></div>"),
 | 
			
		||||
                r.find('.icon').append(t.CALENDAR_SVG);
 | 
			
		||||
        }),
 | 
			
		||||
        (t.prototype.setupCvcInput = function () {
 | 
			
		||||
            this.stripe && this.cvcInput.attr('data-stripe', 'cvc'),
 | 
			
		||||
                this.elem.append(
 | 
			
		||||
                    "<div class='cvc-container'><div class='cvc-wrapper'></div></div>"
 | 
			
		||||
                );
 | 
			
		||||
            var e = this.elem.find('.cvc-wrapper');
 | 
			
		||||
            e.append(this.cvcInput),
 | 
			
		||||
                e.append("<div class='icon'></div>"),
 | 
			
		||||
                e.find('.icon').append(t.LOCK_SVG);
 | 
			
		||||
        }),
 | 
			
		||||
        (t.prototype.expiryMonth = function () {
 | 
			
		||||
            if (
 | 
			
		||||
                !this.EXPIRY_USE_DROPDOWNS &&
 | 
			
		||||
                null != this.expiryMonthYearInput
 | 
			
		||||
            ) {
 | 
			
		||||
                var t = this.expiryMonthYearInput.val();
 | 
			
		||||
                return t.length >= 2 ? parseInt(t.substr(0, 2)) : null;
 | 
			
		||||
            }
 | 
			
		||||
            return null;
 | 
			
		||||
        }),
 | 
			
		||||
        (t.isValidMonth = function (t) {
 | 
			
		||||
            return t >= 1 && 12 >= t;
 | 
			
		||||
        }),
 | 
			
		||||
        (t.isExpiryValid = function (e, r) {
 | 
			
		||||
            var n = new Date(),
 | 
			
		||||
                i = n.getMonth() + 1,
 | 
			
		||||
                a = '' + n.getFullYear();
 | 
			
		||||
            return (
 | 
			
		||||
                2 == ('' + r).length && (r = a.substring(0, 2) + '' + r),
 | 
			
		||||
                (i = parseInt(i)),
 | 
			
		||||
                (a = parseInt(a)),
 | 
			
		||||
                (e = parseInt(e)),
 | 
			
		||||
                (r = parseInt(r)),
 | 
			
		||||
                t.isValidMonth(e) && (r > a || (r == a && e >= i))
 | 
			
		||||
            );
 | 
			
		||||
        }),
 | 
			
		||||
        (t.prototype.refreshExpiryMonthValidation = function () {
 | 
			
		||||
            t.isExpiryValid(this.getExpiryMonth(), this.getExpiryYear())
 | 
			
		||||
                ? this.setExpiryMonthAsValid()
 | 
			
		||||
                : this.setExpiryMonthAsInvalid();
 | 
			
		||||
        }),
 | 
			
		||||
        (t.prototype.setExpiryMonthAsValid = function () {
 | 
			
		||||
            this.EXPIRY_USE_DROPDOWNS ||
 | 
			
		||||
                this.expiryMonthYearInput.parent().removeClass('has-error');
 | 
			
		||||
        }),
 | 
			
		||||
        (t.prototype.setExpiryMonthAsInvalid = function () {
 | 
			
		||||
            this.EXPIRY_USE_DROPDOWNS ||
 | 
			
		||||
                this.expiryMonthYearInput.parent().addClass('has-error');
 | 
			
		||||
        });
 | 
			
		||||
})();
 | 
			
		||||
							
								
								
									
										82
									
								
								public/js/clients/payments/forte-credit-card-payment.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								public/js/clients/payments/forte-credit-card-payment.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,82 @@
 | 
			
		||||
/******/ (() => { // webpackBootstrap
 | 
			
		||||
var __webpack_exports__ = {};
 | 
			
		||||
/*!********************************************************************!*\
 | 
			
		||||
  !*** ./resources/js/clients/payments/forte-credit-card-payment.js ***!
 | 
			
		||||
  \********************************************************************/
 | 
			
		||||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 | 
			
		||||
 | 
			
		||||
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Invoice Ninja (https://invoiceninja.com)
 | 
			
		||||
 *
 | 
			
		||||
 * @link https://github.com/invoiceninja/invoiceninja source repository
 | 
			
		||||
 *
 | 
			
		||||
 * @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
 | 
			
		||||
 *
 | 
			
		||||
 * @license https://opensource.org/licenses/AAL
 | 
			
		||||
 */
 | 
			
		||||
var ForteAuthorizeCard = function ForteAuthorizeCard(apiLoginId) {
 | 
			
		||||
  var _this = this;
 | 
			
		||||
 | 
			
		||||
  _classCallCheck(this, ForteAuthorizeCard);
 | 
			
		||||
 | 
			
		||||
  _defineProperty(this, "handleAuthorization", function () {
 | 
			
		||||
    var myCard = $('#my-card');
 | 
			
		||||
    var data = {
 | 
			
		||||
      api_login_id: _this.apiLoginId,
 | 
			
		||||
      card_number: myCard.CardJs('cardNumber').replace(/[^\d]/g, ''),
 | 
			
		||||
      expire_year: myCard.CardJs('expiryYear').replace(/[^\d]/g, ''),
 | 
			
		||||
      expire_month: myCard.CardJs('expiryMonth').replace(/[^\d]/g, ''),
 | 
			
		||||
      cvv: document.getElementById('cvv').value.replace(/[^\d]/g, '')
 | 
			
		||||
    };
 | 
			
		||||
    var payNowButton = document.getElementById('pay-now');
 | 
			
		||||
 | 
			
		||||
    if (payNowButton) {
 | 
			
		||||
      document.getElementById('pay-now').disabled = true;
 | 
			
		||||
      document.querySelector('#pay-now > svg').classList.remove('hidden');
 | 
			
		||||
      document.querySelector('#pay-now > span').classList.add('hidden');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    forte.createToken(data).success(_this.successResponseHandler).error(_this.failedResponseHandler);
 | 
			
		||||
    return false;
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  _defineProperty(this, "successResponseHandler", function (response) {
 | 
			
		||||
    document.getElementById('payment_token').value = response.onetime_token;
 | 
			
		||||
    document.getElementById('card_brand').value = response.card_type;
 | 
			
		||||
    document.getElementById('server_response').submit();
 | 
			
		||||
    return false;
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  _defineProperty(this, "failedResponseHandler", function (response) {
 | 
			
		||||
    var errors = '<div class="alert alert-failure mb-4"><ul><li>' + response.response_description + '</li></ul></div>';
 | 
			
		||||
    document.getElementById('forte_errors').innerHTML = errors;
 | 
			
		||||
    document.getElementById('pay-now').disabled = false;
 | 
			
		||||
    document.querySelector('#pay-now > svg').classList.add('hidden');
 | 
			
		||||
    document.querySelector('#pay-now > span').classList.remove('hidden');
 | 
			
		||||
    return false;
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  _defineProperty(this, "handle", function () {
 | 
			
		||||
    var payNowButton = document.getElementById('pay-now');
 | 
			
		||||
 | 
			
		||||
    if (payNowButton) {
 | 
			
		||||
      payNowButton.addEventListener('click', function (e) {
 | 
			
		||||
        _this.handleAuthorization();
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return _this;
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  this.apiLoginId = apiLoginId;
 | 
			
		||||
  this.cardHolderName = document.getElementById('cardholder_name');
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
var apiLoginId = document.querySelector('meta[name="forte-api-login-id"]').content;
 | 
			
		||||
/** @handle */
 | 
			
		||||
 | 
			
		||||
new ForteAuthorizeCard(apiLoginId).handle();
 | 
			
		||||
/******/ })()
 | 
			
		||||
;
 | 
			
		||||
							
								
								
									
										322623
									
								
								public/main.dart.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										322623
									
								
								public/main.dart.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										317715
									
								
								public/main.foss.dart.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										317715
									
								
								public/main.foss.dart.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										283989
									
								
								public/main.next.dart.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										283989
									
								
								public/main.next.dart.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										31967
									
								
								public/main.profile.dart.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										31967
									
								
								public/main.profile.dart.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										81
									
								
								resources/js/clients/payments/forte-ach-payment.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								resources/js/clients/payments/forte-ach-payment.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,81 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Invoice Ninja (https://invoiceninja.com)
 | 
			
		||||
 *
 | 
			
		||||
 * @link https://github.com/invoiceninja/invoiceninja source repository
 | 
			
		||||
 *
 | 
			
		||||
 * @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
 | 
			
		||||
 *
 | 
			
		||||
 * @license https://opensource.org/licenses/AAL
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
class ForteAuthorizeACH {
 | 
			
		||||
    constructor(apiLoginId) {
 | 
			
		||||
        this.apiLoginId = apiLoginId;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    handleAuthorization = () => {
 | 
			
		||||
        var account_number = document.getElementById('account-number').value;
 | 
			
		||||
        var routing_number = document.getElementById('routing-number').value;
 | 
			
		||||
 | 
			
		||||
        var data = {
 | 
			
		||||
            api_login_id: this.apiLoginId,
 | 
			
		||||
            account_number: account_number,
 | 
			
		||||
            routing_number: routing_number,
 | 
			
		||||
            account_type: 'checking',
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        let payNowButton = document.getElementById('pay-now');
 | 
			
		||||
 | 
			
		||||
        if (payNowButton) {
 | 
			
		||||
            document.getElementById('pay-now').disabled = true;
 | 
			
		||||
            document.querySelector('#pay-now > svg').classList.remove('hidden');
 | 
			
		||||
            document.querySelector('#pay-now > span').classList.add('hidden');
 | 
			
		||||
        }
 | 
			
		||||
        // console.log(data);
 | 
			
		||||
        forte
 | 
			
		||||
            .createToken(data)
 | 
			
		||||
            .success(this.successResponseHandler)
 | 
			
		||||
            .error(this.failedResponseHandler);
 | 
			
		||||
        return false;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    successResponseHandler = (response) => {
 | 
			
		||||
        document.getElementById('payment_token').value = response.onetime_token;
 | 
			
		||||
 | 
			
		||||
        document.getElementById('server_response').submit();
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    failedResponseHandler = (response) => {
 | 
			
		||||
        var errors =
 | 
			
		||||
            '<div class="alert alert-failure mb-4"><ul><li>' +
 | 
			
		||||
            response.response_description +
 | 
			
		||||
            '</li></ul></div>';
 | 
			
		||||
        document.getElementById('forte_errors').innerHTML = errors;
 | 
			
		||||
        document.getElementById('pay-now').disabled = false;
 | 
			
		||||
        document.querySelector('#pay-now > svg').classList.add('hidden');
 | 
			
		||||
        document.querySelector('#pay-now > span').classList.remove('hidden');
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    handle = () => {
 | 
			
		||||
        let payNowButton = document.getElementById('pay-now');
 | 
			
		||||
 | 
			
		||||
        if (payNowButton) {
 | 
			
		||||
            payNowButton.addEventListener('click', (e) => {
 | 
			
		||||
                this.handleAuthorization();
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return this;
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const apiLoginId = document.querySelector(
 | 
			
		||||
    'meta[name="forte-api-login-id"]'
 | 
			
		||||
).content;
 | 
			
		||||
 | 
			
		||||
/** @handle */
 | 
			
		||||
new ForteAuthorizeACH(apiLoginId).handle();
 | 
			
		||||
							
								
								
									
										83
									
								
								resources/js/clients/payments/forte-credit-card-payment.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								resources/js/clients/payments/forte-credit-card-payment.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,83 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Invoice Ninja (https://invoiceninja.com)
 | 
			
		||||
 *
 | 
			
		||||
 * @link https://github.com/invoiceninja/invoiceninja source repository
 | 
			
		||||
 *
 | 
			
		||||
 * @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
 | 
			
		||||
 *
 | 
			
		||||
 * @license https://opensource.org/licenses/AAL
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
class ForteAuthorizeCard {
 | 
			
		||||
    constructor(apiLoginId) {
 | 
			
		||||
        this.apiLoginId = apiLoginId;
 | 
			
		||||
        this.cardHolderName = document.getElementById('cardholder_name');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    handleAuthorization = () => {
 | 
			
		||||
        var myCard = $('#my-card');
 | 
			
		||||
 | 
			
		||||
        var data = {
 | 
			
		||||
            api_login_id: this.apiLoginId,
 | 
			
		||||
            card_number: myCard.CardJs('cardNumber').replace(/[^\d]/g, ''),
 | 
			
		||||
            expire_year: myCard.CardJs('expiryYear').replace(/[^\d]/g, ''),
 | 
			
		||||
            expire_month: myCard.CardJs('expiryMonth').replace(/[^\d]/g, ''),
 | 
			
		||||
            cvv: document.getElementById('cvv').value.replace(/[^\d]/g, ''),
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        let payNowButton = document.getElementById('pay-now');
 | 
			
		||||
 | 
			
		||||
        if (payNowButton) {
 | 
			
		||||
            document.getElementById('pay-now').disabled = true;
 | 
			
		||||
            document.querySelector('#pay-now > svg').classList.remove('hidden');
 | 
			
		||||
            document.querySelector('#pay-now > span').classList.add('hidden');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        forte
 | 
			
		||||
            .createToken(data)
 | 
			
		||||
            .success(this.successResponseHandler)
 | 
			
		||||
            .error(this.failedResponseHandler);
 | 
			
		||||
        return false;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    successResponseHandler = (response) => {
 | 
			
		||||
        document.getElementById('payment_token').value = response.onetime_token;
 | 
			
		||||
        document.getElementById('card_brand').value = response.card_type;
 | 
			
		||||
 | 
			
		||||
        document.getElementById('server_response').submit();
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    failedResponseHandler = (response) => {
 | 
			
		||||
        var errors =
 | 
			
		||||
            '<div class="alert alert-failure mb-4"><ul><li>' +
 | 
			
		||||
            response.response_description +
 | 
			
		||||
            '</li></ul></div>';
 | 
			
		||||
        document.getElementById('forte_errors').innerHTML = errors;
 | 
			
		||||
        document.getElementById('pay-now').disabled = false;
 | 
			
		||||
        document.querySelector('#pay-now > svg').classList.add('hidden');
 | 
			
		||||
        document.querySelector('#pay-now > span').classList.remove('hidden');
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    handle = () => {
 | 
			
		||||
        let payNowButton = document.getElementById('pay-now');
 | 
			
		||||
 | 
			
		||||
        if (payNowButton) {
 | 
			
		||||
            payNowButton.addEventListener('click', (e) => {
 | 
			
		||||
                this.handleAuthorization();
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return this;
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const apiLoginId = document.querySelector(
 | 
			
		||||
    'meta[name="forte-api-login-id"]'
 | 
			
		||||
).content;
 | 
			
		||||
 | 
			
		||||
/** @handle */
 | 
			
		||||
new ForteAuthorizeCard(apiLoginId).handle();
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<html data-report-errors="{{ $report_errors }}" data-rc="{{ $rc }}" data-user-agent="{{ $user_agent }}" data-login="{{ $login }}">
 | 
			
		||||
<html data-report-errors="{{ $report_errors }}" data-rc="{{ $rc }}" data-user-agent="{{ $user_agent }}" data-login="{{ $login }}" data-signup="{{ $signup }}">
 | 
			
		||||
<head>
 | 
			
		||||
    <!-- Source: https://github.com/invoiceninja/invoiceninja -->
 | 
			
		||||
    <!-- Version: {{ config('ninja.app_version') }} -->
 | 
			
		||||
@ -152,6 +152,12 @@
 | 
			
		||||
 | 
			
		||||
  <script defer src="{{ $path }}?v={{ config('ninja.app_version') }}" type="application/javascript"></script>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  <script type="text/javascript" 
 | 
			
		||||
    src="https://alcdn.msauth.net/browser/2.14.2/js/msal-browser.min.js"
 | 
			
		||||
    integrity="sha384-ggh+EF1aSqm+Y4yvv2n17KpurNcZTeYtUZUvhPziElsstmIEubyEB6AIVpKLuZgr"
 | 
			
		||||
    crossorigin="anonymous">
 | 
			
		||||
  </script>
 | 
			
		||||
  <center style="padding-top: 150px" id="loader">
 | 
			
		||||
    <div class="loader"></div>
 | 
			
		||||
  </center>
 | 
			
		||||
 | 
			
		||||
@ -278,6 +278,13 @@
 | 
			
		||||
        margin-top: 1rem;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    [data-element='product_table-product.description-td'], td {
 | 
			
		||||
        min-width:100%;
 | 
			
		||||
        max-width: 300px;
 | 
			
		||||
        overflow-wrap: break-word; 
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Useful snippets, uncomment to enable. **/
 | 
			
		||||
 | 
			
		||||
    /** Hide company logo **/
 | 
			
		||||
 | 
			
		||||
@ -270,6 +270,12 @@
 | 
			
		||||
        bottom: 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [data-element='product_table-product.description-td'], td {
 | 
			
		||||
        min-width:100%;
 | 
			
		||||
        max-width: 300px;
 | 
			
		||||
        overflow-wrap: break-word; 
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Useful snippets, uncomment to enable. **/
 | 
			
		||||
 | 
			
		||||
    /** Hide company logo **/
 | 
			
		||||
 | 
			
		||||
@ -240,6 +240,12 @@
 | 
			
		||||
        bottom: 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [data-element='product_table-product.description-td'], td {
 | 
			
		||||
        min-width:100%;
 | 
			
		||||
        max-width: 300px;
 | 
			
		||||
        overflow-wrap: break-word; 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /** Useful snippets, uncomment to enable. **/
 | 
			
		||||
 | 
			
		||||
    /** Hide company logo **/
 | 
			
		||||
@ -335,7 +341,7 @@ $entity_images
 | 
			
		||||
                    'product-table', 'task-table', 'delivery-note-table',
 | 
			
		||||
                    'statement-invoice-table', 'statement-payment-table', 'statement-aging-table-totals',
 | 
			
		||||
                    'statement-invoice-table-totals', 'statement-payment-table-totals', 'statement-aging-table',
 | 
			
		||||
                    'client-details','vendor-details'
 | 
			
		||||
                    'client-details','vendor-details', 'swiss-qr'
 | 
			
		||||
                ];
 | 
			
		||||
 | 
			
		||||
                tables.forEach((tableIdentifier) => {
 | 
			
		||||
 | 
			
		||||
@ -223,6 +223,12 @@
 | 
			
		||||
        bottom: 0;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    [data-element='product_table-product.description-td'], td {
 | 
			
		||||
        min-width:100%;
 | 
			
		||||
        max-width: 300px;
 | 
			
		||||
        overflow-wrap: break-word; 
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Useful snippets, uncomment to enable. **/
 | 
			
		||||
 | 
			
		||||
    /** Hide company logo **/
 | 
			
		||||
 | 
			
		||||
@ -228,6 +228,12 @@
 | 
			
		||||
        bottom: 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [data-element='product_table-product.description-td'], td {
 | 
			
		||||
        min-width:100%;
 | 
			
		||||
        max-width: 300px;
 | 
			
		||||
        overflow-wrap: break-word; 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /** Useful snippets, uncomment to enable. **/
 | 
			
		||||
 | 
			
		||||
    /** Hide company logo **/
 | 
			
		||||
 | 
			
		||||
@ -245,6 +245,12 @@
 | 
			
		||||
        bottom: 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [data-element='product_table-product.description-td'], td {
 | 
			
		||||
        min-width:100%;
 | 
			
		||||
        max-width: 300px;
 | 
			
		||||
        overflow-wrap: break-word; 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /** Useful snippets, uncomment to enable. **/
 | 
			
		||||
 | 
			
		||||
    /** Hide company logo **/
 | 
			
		||||
 | 
			
		||||
@ -272,6 +272,12 @@
 | 
			
		||||
        white-space: nowrap;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      [data-element='product_table-product.description-td'], td {
 | 
			
		||||
        min-width:100%;
 | 
			
		||||
        max-width: 300px;
 | 
			
		||||
        overflow-wrap: break-word; 
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      /** Useful snippets, uncomment to enable. **/
 | 
			
		||||
 | 
			
		||||
      /** Hide company logo **/
 | 
			
		||||
 | 
			
		||||
@ -215,6 +215,12 @@
 | 
			
		||||
        bottom: 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [data-element='product_table-product.description-td'], td {
 | 
			
		||||
        min-width:100%;
 | 
			
		||||
        max-width: 300px;
 | 
			
		||||
        overflow-wrap: break-word; 
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Useful snippets, uncomment to enable. **/
 | 
			
		||||
 | 
			
		||||
    /** Hide company logo **/
 | 
			
		||||
 | 
			
		||||
@ -288,6 +288,12 @@
 | 
			
		||||
        bottom: 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [data-element='product_table-product.description-td'], td {
 | 
			
		||||
        min-width:100%;
 | 
			
		||||
        max-width: 300px;
 | 
			
		||||
        overflow-wrap: break-word; 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /** Useful snippets, uncomment to enable. **/
 | 
			
		||||
 | 
			
		||||
    /** Hide company logo **/
 | 
			
		||||
 | 
			
		||||
@ -252,6 +252,12 @@
 | 
			
		||||
        bottom: 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [data-element='product_table-product.description-td'], td {
 | 
			
		||||
        min-width:100%;
 | 
			
		||||
        max-width: 300px;
 | 
			
		||||
        overflow-wrap: break-word; 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /** Useful snippets, uncomment to enable. **/
 | 
			
		||||
 | 
			
		||||
    /** Hide company logo **/
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,131 @@
 | 
			
		||||
@extends('portal.ninja2020.layout.payments', ['gateway_title' => 'Bank Details', 'card_title' => 'Bank Details'])
 | 
			
		||||
 | 
			
		||||
@section('gateway_head')
 | 
			
		||||
    @if($gateway->getConfigField('testMode'))
 | 
			
		||||
        <script type="text/javascript" src="https://sandbox.forte.net/api/js/v1"></script>
 | 
			
		||||
    @else
 | 
			
		||||
        <script type="text/javascript" src="https://api.forte.net/js/v1"></script>
 | 
			
		||||
    @endif
 | 
			
		||||
@endsection
 | 
			
		||||
 | 
			
		||||
@section('gateway_content')
 | 
			
		||||
    @if(session()->has('ach_error'))
 | 
			
		||||
        <div class="alert alert-failure mb-4">
 | 
			
		||||
            <p>{{ session('ach_error') }}</p>
 | 
			
		||||
        </div>
 | 
			
		||||
    @endif
 | 
			
		||||
    @if(Session::has('error'))
 | 
			
		||||
        <div class="alert alert-failure mb-4" id="errors">{{ Session::get('error') }}</div>
 | 
			
		||||
    @endif
 | 
			
		||||
    <div id="forte_errors"></div>
 | 
			
		||||
    @if ($errors->any())
 | 
			
		||||
        <div class="alert alert-failure mb-4">
 | 
			
		||||
            <ul>
 | 
			
		||||
                @foreach ($errors->all() as $error)
 | 
			
		||||
                    <li>{{ $error }}</li>
 | 
			
		||||
                @endforeach
 | 
			
		||||
            </ul>
 | 
			
		||||
        </div>
 | 
			
		||||
    @endif
 | 
			
		||||
 | 
			
		||||
    <form action="{{ route('client.payment_methods.store', ['method' => App\Models\GatewayType::BANK_TRANSFER]) }}" method="post" id="server_response">
 | 
			
		||||
        @csrf
 | 
			
		||||
 | 
			
		||||
        <input type="hidden" name="gateway_type_id" value="2">
 | 
			
		||||
        <input type="hidden" name="gateway_response" id="gateway_response">
 | 
			
		||||
        <input type="hidden" name="is_default" id="is_default">
 | 
			
		||||
        <input type="hidden" name="last_4" id="last_4">
 | 
			
		||||
        <input type="hidden" name="one_time_token" id="one_time_token">
 | 
			
		||||
 | 
			
		||||
        <div class="alert alert-failure mb-4" hidden id="errors"></div>
 | 
			
		||||
 | 
			
		||||
        @component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.account_holder_type')])
 | 
			
		||||
            <span class="flex items-center mr-4">
 | 
			
		||||
                <input class="form-radio mr-2" type="radio" value="individual" name="account-holder-type" checked>
 | 
			
		||||
                <span>{{ __('texts.individual_account') }}</span>
 | 
			
		||||
            </span>
 | 
			
		||||
            <span class="flex items-center">
 | 
			
		||||
                <input class="form-radio mr-2" type="radio" value="company" name="account-holder-type">
 | 
			
		||||
                <span>{{ __('texts.company_account') }}</span>
 | 
			
		||||
            </span>
 | 
			
		||||
        @endcomponent
 | 
			
		||||
 | 
			
		||||
        @component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.account_holder_name')])
 | 
			
		||||
            <input class="input w-full" id="account-holder-name" type="text" name="account_holder_name" placeholder="{{ ctrans('texts.name') }}" required>
 | 
			
		||||
        @endcomponent
 | 
			
		||||
 | 
			
		||||
        @component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.country')])
 | 
			
		||||
            <select name="countries" id="country" name="country" class="form-select input w-full" required>
 | 
			
		||||
                @foreach($countries as $country)
 | 
			
		||||
                    <option value="{{ $country->iso_3166_2 }}" {{$country->iso_3166_2 == 'US' ? "selected" : ""}}>{{ $country->iso_3166_2 }} ({{ $country->name }})</option>
 | 
			
		||||
                @endforeach
 | 
			
		||||
            </select>
 | 
			
		||||
        @endcomponent
 | 
			
		||||
 | 
			
		||||
        @component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.currency')])
 | 
			
		||||
            <select name="currencies" id="currency" name="currency" class="form-select input w-full">
 | 
			
		||||
                @foreach($currencies as $currency)
 | 
			
		||||
                    <option value="{{ $currency->code }}" {{$currency->code == 'USD' ? "selected" : ""}}>{{ $currency->code }} ({{ $currency->name }})</option>
 | 
			
		||||
                @endforeach
 | 
			
		||||
            </select>
 | 
			
		||||
        @endcomponent
 | 
			
		||||
 | 
			
		||||
        @component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.routing_number')])
 | 
			
		||||
            <input class="input w-full" id="routing-number" type="text" required>
 | 
			
		||||
        @endcomponent
 | 
			
		||||
 | 
			
		||||
        @component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.account_number')])
 | 
			
		||||
            <input class="input w-full" id="account-number" type="text" required>
 | 
			
		||||
        @endcomponent
 | 
			
		||||
 | 
			
		||||
        @component('portal.ninja2020.components.general.card-element-single')
 | 
			
		||||
            <input type="checkbox" class="form-checkbox mr-1" name="accept_terms" id="accept-terms" required>
 | 
			
		||||
            <label for="accept-terms" class="cursor-pointer">{{ ctrans('texts.ach_authorization', ['company' => auth()->user()->company->present()->name, 'email' => auth('contact')->user()->client->company->settings->email]) }}</label>
 | 
			
		||||
        @endcomponent
 | 
			
		||||
 | 
			
		||||
        <div class="bg-white px-4 py-5 flex justify-end">
 | 
			
		||||
            <button type="button"
 | 
			
		||||
                onclick="submitACH()"
 | 
			
		||||
                class="button button-primary bg-primary {{ $class ?? '' }}">
 | 
			
		||||
                    <svg class="animate-spin h-5 w-5 text-white hidden" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
 | 
			
		||||
                        <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
 | 
			
		||||
                        <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
 | 
			
		||||
                    </svg>
 | 
			
		||||
                <span>{{ $slot ?? ctrans('texts.add_payment_method') }}</span>
 | 
			
		||||
            </button>
 | 
			
		||||
            <input type="submit" style="display: none" id="form_btn">
 | 
			
		||||
        </div>
 | 
			
		||||
    </form>
 | 
			
		||||
 | 
			
		||||
@endsection
 | 
			
		||||
 | 
			
		||||
@section('gateway_footer')
 | 
			
		||||
    <script>
 | 
			
		||||
        function onTokenCreated(params) {
 | 
			
		||||
            document.getElementById('one_time_token').value=params.onetime_token;
 | 
			
		||||
            document.getElementById('last_4').value=params.last_4;
 | 
			
		||||
            let button = document.querySelector("#form_btn");
 | 
			
		||||
            button.click();
 | 
			
		||||
        }
 | 
			
		||||
        function onTokenFailed(params) {
 | 
			
		||||
            var errors = '<div class="alert alert-failure mb-4"><ul><li>'+ params.response_description +'</li></ul></div>';
 | 
			
		||||
            document.getElementById("forte_errors").innerHTML = errors;
 | 
			
		||||
        }
 | 
			
		||||
        function submitACH(){
 | 
			
		||||
            var account_number=document.getElementById('account-number').value;
 | 
			
		||||
            var routing_number=document.getElementById('routing-number').value;
 | 
			
		||||
 | 
			
		||||
            var data = {
 | 
			
		||||
               api_login_id: '{{$gateway->getConfigField("apiLoginId")}}',
 | 
			
		||||
               account_number: account_number,
 | 
			
		||||
               routing_number: routing_number, 
 | 
			
		||||
               account_type: "checking",
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            forte.createToken(data)
 | 
			
		||||
               .success(onTokenCreated)
 | 
			
		||||
               .error(onTokenFailed);
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    </script>
 | 
			
		||||
@endsection
 | 
			
		||||
@ -0,0 +1,53 @@
 | 
			
		||||
@extends('portal.ninja2020.layout.payments', ['gateway_title' => 'Bank Transfer', 'card_title' => 'Bank Transfer'])
 | 
			
		||||
 | 
			
		||||
@section('gateway_head')
 | 
			
		||||
    <meta name="forte-api-login-id" content="{{$gateway->forte->company_gateway->getConfigField("apiLoginId")}}">
 | 
			
		||||
@endsection
 | 
			
		||||
 | 
			
		||||
@section('gateway_content')
 | 
			
		||||
    <form action="{{ route('client.payments.response') }}" method="post" id="server_response">
 | 
			
		||||
        @csrf
 | 
			
		||||
        <input type="hidden" name="payment_hash" value="{{ $payment_hash }}">
 | 
			
		||||
        <input type="hidden" name="company_gateway_id" value="{{ $gateway->forte->company_gateway->id }}">
 | 
			
		||||
        <input type="hidden" name="payment_method_id" value="{{$payment_method_id}}">
 | 
			
		||||
        <input type="hidden" name="gateway_response" id="gateway_response">
 | 
			
		||||
        <input type="hidden" name="dataValue" id="dataValue"/>
 | 
			
		||||
        <input type="hidden" name="dataDescriptor" id="dataDescriptor"/>
 | 
			
		||||
        <input type="hidden" name="token" id="token"/>
 | 
			
		||||
        <input type="hidden" name="store_card" id="store_card"/>
 | 
			
		||||
        <input type="submit" style="display: none" id="form_btn">
 | 
			
		||||
    </form>
 | 
			
		||||
 | 
			
		||||
    <div id="forte_errors"></div>
 | 
			
		||||
 | 
			
		||||
    @component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.payment_type')])
 | 
			
		||||
        Bank Transfer
 | 
			
		||||
    @endcomponent
 | 
			
		||||
 | 
			
		||||
    @include('portal.ninja2020.gateways.includes.payment_details')
 | 
			
		||||
 | 
			
		||||
    @component('portal.ninja2020.components.general.card-element', ['title' => 'Pay with Bank Transfer'])
 | 
			
		||||
        <input type="hidden" name="payment_token" id="payment_token">
 | 
			
		||||
        <div class="bg-white px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6"
 | 
			
		||||
            style="display: flex!important; justify-content: center!important;">
 | 
			
		||||
            <input class="input w-full" id="routing-number" type="text" placeholder="{{ctrans('texts.routing_number')}}" required>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="bg-white px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6"
 | 
			
		||||
            style="display: flex!important; justify-content: center!important;">
 | 
			
		||||
            <input class="input w-full" id="account-number" type="text" placeholder="{{ctrans('texts.account_number')}}" required>
 | 
			
		||||
        </div>
 | 
			
		||||
    @endcomponent
 | 
			
		||||
 | 
			
		||||
    @include('portal.ninja2020.gateways.includes.pay_now')
 | 
			
		||||
 | 
			
		||||
@endsection
 | 
			
		||||
 | 
			
		||||
@section('gateway_footer')
 | 
			
		||||
    @if($gateway->forte->company_gateway->getConfigField('testMode'))
 | 
			
		||||
        <script type="text/javascript" src="https://sandbox.forte.net/api/js/v1"></script>
 | 
			
		||||
    @else
 | 
			
		||||
        <script type="text/javascript" src="https://api.forte.net/js/v1"></script>
 | 
			
		||||
    @endif
 | 
			
		||||
    
 | 
			
		||||
    <script src="{{ asset('js/clients/payments/forte-ach-payment.js') }}"></script>
 | 
			
		||||
@endsection
 | 
			
		||||
@ -0,0 +1,122 @@
 | 
			
		||||
@extends('portal.ninja2020.layout.payments', ['gateway_title' => ctrans('texts.credit_card'), 'card_title' => ctrans('texts.credit_card')])
 | 
			
		||||
 | 
			
		||||
@section('gateway_head')
 | 
			
		||||
    <meta name="year-invalid" content="{{ ctrans('texts.year_invalid') }}">
 | 
			
		||||
    <meta name="month-invalid" content="{{ ctrans('texts.month_invalid') }}">
 | 
			
		||||
    <meta name="credit-card-invalid" content="{{ ctrans('texts.credit_card_invalid') }}">
 | 
			
		||||
 | 
			
		||||
    <script src="https://code.jquery.com/jquery-1.11.3.min.js"></script>
 | 
			
		||||
    <script src="{{ asset('js/clients/payments/forte-card-js.min.js') }}"></script>
 | 
			
		||||
 | 
			
		||||
    <link href="{{ asset('css/card-js.min.css') }}" rel="stylesheet" type="text/css">
 | 
			
		||||
    @if($gateway->getConfigField('testMode'))
 | 
			
		||||
        <script type="text/javascript" src="https://sandbox.forte.net/api/js/v1"></script>
 | 
			
		||||
    @else
 | 
			
		||||
        <script type="text/javascript" src="https://api.forte.net/js/v1"></script>
 | 
			
		||||
    @endif
 | 
			
		||||
@endsection
 | 
			
		||||
 | 
			
		||||
@section('gateway_content')
 | 
			
		||||
    <form action="{{ route('client.payment_methods.store', ['method' => App\Models\GatewayType::CREDIT_CARD]) }}"
 | 
			
		||||
          method="post" id="server_response">
 | 
			
		||||
        @csrf
 | 
			
		||||
 | 
			
		||||
        <input type="hidden" name="payment_method_id" value="1">
 | 
			
		||||
        <input type="hidden" name="one_time_token" id="one_time_token">
 | 
			
		||||
        <input type="hidden" name="card_type" id="card_type">
 | 
			
		||||
        <input type="hidden" name="expire_year" id="expire_year">
 | 
			
		||||
        <input type="hidden" name="expire_month" id="expire_month">
 | 
			
		||||
        <input type="hidden" name="last_4" id="last_4">
 | 
			
		||||
 | 
			
		||||
        @if(!Request::isSecure())
 | 
			
		||||
            <p class="alert alert-failure">{{ ctrans('texts.https_required') }}</p>
 | 
			
		||||
        @endif
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        @if(Session::has('error'))
 | 
			
		||||
            <div class="alert alert-failure mb-4" id="errors">{{ Session::get('error') }}</div>
 | 
			
		||||
        @endif
 | 
			
		||||
        <div id="forte_errors"></div>
 | 
			
		||||
        @if ($errors->any())
 | 
			
		||||
            <div class="alert alert-failure mb-4">
 | 
			
		||||
                <ul>
 | 
			
		||||
                    @foreach ($errors->all() as $error)
 | 
			
		||||
                        <li>{{ $error }}</li>
 | 
			
		||||
                    @endforeach
 | 
			
		||||
                </ul>
 | 
			
		||||
            </div>
 | 
			
		||||
        @endif
 | 
			
		||||
 | 
			
		||||
        @component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.method')])
 | 
			
		||||
            {{ ctrans('texts.credit_card') }}
 | 
			
		||||
        @endcomponent
 | 
			
		||||
 | 
			
		||||
        @include('portal.ninja2020.gateways.forte.includes.credit_card')
 | 
			
		||||
 | 
			
		||||
        <div class="bg-white px-4 py-5 flex justify-end">
 | 
			
		||||
            <button type="button"
 | 
			
		||||
                onclick="submitCard()"
 | 
			
		||||
                class="button button-primary bg-primary {{ $class ?? '' }}">
 | 
			
		||||
                    <svg class="animate-spin h-5 w-5 text-white hidden" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
 | 
			
		||||
                        <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
 | 
			
		||||
                        <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
 | 
			
		||||
                    </svg>
 | 
			
		||||
                <span>{{ $slot ?? ctrans('texts.add_payment_method') }}</span>
 | 
			
		||||
            </button>
 | 
			
		||||
            <input type="submit" style="display: none" id="form_btn">
 | 
			
		||||
        </div>
 | 
			
		||||
        
 | 
			
		||||
    </form>
 | 
			
		||||
@endsection
 | 
			
		||||
 | 
			
		||||
@section('gateway_footer')
 | 
			
		||||
    <script>
 | 
			
		||||
        function onTokenCreated(params) {
 | 
			
		||||
            document.getElementById('one_time_token').value=params.onetime_token;
 | 
			
		||||
            document.getElementById('last_4').value=params.last_4;
 | 
			
		||||
            let button = document.querySelector("#form_btn");
 | 
			
		||||
            button.click();
 | 
			
		||||
        }
 | 
			
		||||
        function onTokenFailed(params) {
 | 
			
		||||
            var errors = '<div class="alert alert-failure mb-4"><ul><li>'+ params.response_description +'</li></ul></div>';
 | 
			
		||||
            document.getElementById("forte_errors").innerHTML = errors;
 | 
			
		||||
        }
 | 
			
		||||
        function submitCard(){
 | 
			
		||||
            var doc = document.getElementsByClassName("card-number-wrapper");
 | 
			
		||||
            var cardType=doc[0].childNodes[1].classList[2];
 | 
			
		||||
            if (cardType=='master-card') {
 | 
			
		||||
                document.getElementById('card_type').value='mast';
 | 
			
		||||
            } else if(cardType=='visa') {
 | 
			
		||||
                document.getElementById('card_type').value='visa';
 | 
			
		||||
            }else if(cardType=='jcb') {
 | 
			
		||||
                document.getElementById('card_type').value='jcb';
 | 
			
		||||
            }else if(cardType=='discover') {
 | 
			
		||||
                document.getElementById('card_type').value='disc';
 | 
			
		||||
            }else if(cardType=='american-express') {
 | 
			
		||||
                document.getElementById('card_type').value='amex';
 | 
			
		||||
            }else{
 | 
			
		||||
                document.getElementById('card_type').value=cardType;
 | 
			
		||||
            }
 | 
			
		||||
            var month=document.querySelector('input[name=expiry-month]').value;
 | 
			
		||||
            var year=document.querySelector('input[name=expiry-year]').value;
 | 
			
		||||
            var cc=document.getElementById('card_number').value.replaceAll(' ','');
 | 
			
		||||
            var cvv=document.getElementById('cvv').value;
 | 
			
		||||
            
 | 
			
		||||
            document.getElementById('expire_year').value=year;
 | 
			
		||||
            document.getElementById('expire_month').value=month;
 | 
			
		||||
            
 | 
			
		||||
            var data = {
 | 
			
		||||
               api_login_id: '{{$gateway->getConfigField("apiLoginId")}}',
 | 
			
		||||
               card_number: cc,
 | 
			
		||||
               expire_year: year, 
 | 
			
		||||
               expire_month: month,
 | 
			
		||||
               cvv: cvv,
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            forte.createToken(data)
 | 
			
		||||
               .success(onTokenCreated)
 | 
			
		||||
               .error(onTokenFailed);
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    </script>
 | 
			
		||||
@endsection
 | 
			
		||||
@ -0,0 +1,51 @@
 | 
			
		||||
@extends('portal.ninja2020.layout.payments', ['gateway_title' => ctrans('texts.payment_type_credit_card'), 'card_title' => ctrans('texts.payment_type_credit_card')])
 | 
			
		||||
 | 
			
		||||
@section('gateway_head')
 | 
			
		||||
    <meta name="forte-api-login-id" content="{{$gateway->forte->company_gateway->getConfigField("apiLoginId")}}">
 | 
			
		||||
    <script src="https://code.jquery.com/jquery-1.11.3.min.js"></script>
 | 
			
		||||
    <script src="{{ asset('js/clients/payments/forte-card-js.min.js') }}"></script>
 | 
			
		||||
 | 
			
		||||
    <link href="{{ asset('css/card-js.min.css') }}" rel="stylesheet" type="text/css">
 | 
			
		||||
@endsection
 | 
			
		||||
 | 
			
		||||
@section('gateway_content')
 | 
			
		||||
    <form action="{{ route('client.payments.response') }}" method="post" id="server_response">
 | 
			
		||||
        @csrf
 | 
			
		||||
        <input type="hidden" name="card_brand" id="card_brand">
 | 
			
		||||
        <input type="hidden" name="payment_token" id="payment_token">
 | 
			
		||||
        <input type="hidden" name="payment_hash" value="{{ $payment_hash }}">
 | 
			
		||||
        <input type="hidden" name="company_gateway_id" value="{{ $gateway->forte->company_gateway->id }}">
 | 
			
		||||
        <input type="hidden" name="payment_method_id" value="{{$payment_method_id}}">
 | 
			
		||||
        <input type="hidden" name="gateway_response" id="gateway_response">
 | 
			
		||||
        <input type="hidden" name="dataValue" id="dataValue"/>
 | 
			
		||||
        <input type="hidden" name="dataDescriptor" id="dataDescriptor"/>
 | 
			
		||||
        <input type="hidden" name="token" id="token"/>
 | 
			
		||||
        <input type="hidden" name="store_card" id="store_card"/>
 | 
			
		||||
        <input type="submit" style="display: none" id="form_btn">
 | 
			
		||||
    </form>
 | 
			
		||||
 | 
			
		||||
    <div id="forte_errors"></div>
 | 
			
		||||
 | 
			
		||||
    @component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.payment_type')])
 | 
			
		||||
        {{ ctrans('texts.credit_card') }}
 | 
			
		||||
     @endcomponent
 | 
			
		||||
 | 
			
		||||
    @include('portal.ninja2020.gateways.includes.payment_details')
 | 
			
		||||
 | 
			
		||||
    @component('portal.ninja2020.components.general.card-element', ['title' => 'Pay with Credit Card'])
 | 
			
		||||
       @include('portal.ninja2020.gateways.forte.includes.credit_card')
 | 
			
		||||
    @endcomponent
 | 
			
		||||
 | 
			
		||||
    @include('portal.ninja2020.gateways.includes.pay_now')
 | 
			
		||||
 | 
			
		||||
@endsection
 | 
			
		||||
 | 
			
		||||
@section('gateway_footer')
 | 
			
		||||
    @if($gateway->forte->company_gateway->getConfigField('testMode'))
 | 
			
		||||
        <script type="text/javascript" src="https://sandbox.forte.net/api/js/v1"></script>
 | 
			
		||||
    @else
 | 
			
		||||
        <script type="text/javascript" src="https://api.forte.net/js/v1"></script>
 | 
			
		||||
    @endif
 | 
			
		||||
    
 | 
			
		||||
    <script src="{{ asset('js/clients/payments/forte-credit-card-payment.js') }}"></script>
 | 
			
		||||
@endsection
 | 
			
		||||
@ -0,0 +1,12 @@
 | 
			
		||||
<div class="bg-white px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6"
 | 
			
		||||
     style="display: flex!important; justify-content: center!important;" id="authorize--credit-card-container">
 | 
			
		||||
    <div class="card-js" id="my-card" data-capture-name="true">
 | 
			
		||||
        <input class="name" id="cardholder_name" name="card_holders_name" placeholder="{{ ctrans('texts.name')}}">
 | 
			
		||||
        <input class="card-number my-custom-class" id="card_number">
 | 
			
		||||
        <input type="hidden" name="expiry_month" id="expiration_month">
 | 
			
		||||
        <input type="hidden" name="expiry_year" id="expiration_year">
 | 
			
		||||
        <input class="cvc" name="cvc" id="cvv">
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div id="errors"></div>
 | 
			
		||||
</div>
 | 
			
		||||
@ -3,7 +3,7 @@
 | 
			
		||||
 | 
			
		||||
@push('head')
 | 
			
		||||
    <meta name="show-purchase_order-terms" content="false">
 | 
			
		||||
    <meta name="require-purchase_order-signature" content="{{ $purchase_order->company->account->hasFeature(\App\Models\Account::FEATURE_INVOICE_SETTINGS) && $settings->require_purchase_order_signature }}">
 | 
			
		||||
    <meta name="require-purchase_order-signature" content="{{ $purchase_order->company->account->hasFeature(\App\Models\Account::FEATURE_INVOICE_SETTINGS) && property_exists($settings, 'require_purchase_order_signature') && $settings->require_purchase_order_signature }}">
 | 
			
		||||
    @include('portal.ninja2020.components.no-cache')
 | 
			
		||||
    
 | 
			
		||||
    <script src="{{ asset('vendor/signature_pad@2.3.2/signature_pad.min.js') }}"></script>
 | 
			
		||||
 | 
			
		||||
@ -129,6 +129,9 @@ Route::group(['middleware' => ['throttle:100,1', 'api_db', 'token_auth', 'locale
 | 
			
		||||
    Route::post('preview', 'PreviewController@show')->name('preview.show');
 | 
			
		||||
    Route::post('live_preview', 'PreviewController@live')->name('preview.live');
 | 
			
		||||
 | 
			
		||||
    Route::post('preview/purchase_order', 'PreviewPurchaseOrderController@show')->name('preview_purchase_order.show');
 | 
			
		||||
    Route::post('live_preview/purchase_order', 'PreviewPurchaseOrderController@live')->name('preview_purchase_order.live');
 | 
			
		||||
 | 
			
		||||
    Route::resource('products', 'ProductController'); // name = (products. index / create / show / update / destroy / edit
 | 
			
		||||
    Route::post('products/bulk', 'ProductController@bulk')->name('products.bulk');
 | 
			
		||||
    Route::put('products/{product}/upload', 'ProductController@upload');
 | 
			
		||||
@ -212,6 +215,7 @@ Route::group(['middleware' => ['throttle:100,1', 'api_db', 'token_auth', 'locale
 | 
			
		||||
    Route::get('purchase_orders/{purchase_order}/{action}', 'PurchaseOrderController@action')->name('purchase_orders.action');
 | 
			
		||||
 | 
			
		||||
    Route::get('users', 'UserController@index');
 | 
			
		||||
    Route::get('users/create', 'UserController@create')->middleware('password_protected');
 | 
			
		||||
    Route::get('users/{user}', 'UserController@show')->middleware('password_protected');
 | 
			
		||||
    Route::put('users/{user}', 'UserController@update')->middleware('password_protected');
 | 
			
		||||
    Route::post('users', 'UserController@store')->middleware('password_protected');
 | 
			
		||||
 | 
			
		||||
@ -20,6 +20,8 @@ Route::get('vendors', [VendorContactLoginController::class, 'catch'])->name('ven
 | 
			
		||||
Route::group(['middleware' => ['invite_db'], 'prefix' => 'vendor', 'as' => 'vendor.'], function () {
 | 
			
		||||
    /*Invitation catches*/
 | 
			
		||||
    Route::get('purchase_order/{invitation_key}', [InvitationController::class, 'purchaseOrder']);
 | 
			
		||||
    Route::get('purchase_order/{invitation_key}/download', [InvitationController::class, 'download']);
 | 
			
		||||
 | 
			
		||||
 //   Route::get('purchase_order/{invitation_key}/download_pdf', 'PurchaseOrderController@downloadPdf')->name('recurring_invoice.download_invitation_key');
 | 
			
		||||
 //   Route::get('purchase_order/{invitation_key}/download', 'ClientPortal\InvitationController@routerForDownload');
 | 
			
		||||
 | 
			
		||||
@ -40,4 +42,7 @@ Route::group(['middleware' => ['auth:vendor', 'vendor_locale', 'domain_db'], 'pr
 | 
			
		||||
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Route::fallback('BaseController@notFoundVendor');
 | 
			
		||||
@ -56,7 +56,7 @@ class CompanySettingsTest extends TestCase
 | 
			
		||||
            $response = $this->withHeaders([
 | 
			
		||||
                'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
                'X-API-Token' => $this->token,
 | 
			
		||||
            ])->put('/api/v1/companies/'.$this->encodePrimaryKey($this->company->id), $this->company->toArray());
 | 
			
		||||
            ])->putJson('/api/v1/companies/'.$this->encodePrimaryKey($this->company->id), $this->company->toArray());
 | 
			
		||||
        } catch (ValidationException $e) {
 | 
			
		||||
            $message = json_decode($e->validator->getMessageBag(), 1);
 | 
			
		||||
        }
 | 
			
		||||
@ -78,11 +78,13 @@ class CompanySettingsTest extends TestCase
 | 
			
		||||
 | 
			
		||||
        $this->company->saveSettings($settings, $this->company);
 | 
			
		||||
 | 
			
		||||
        $response = false;
 | 
			
		||||
        
 | 
			
		||||
        try {
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
                'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
                'X-API-Token' => $this->token,
 | 
			
		||||
            ])->put('/api/v1/companies/'.$this->encodePrimaryKey($this->company->id), $this->company->toArray());
 | 
			
		||||
            ])->putJson('/api/v1/companies/'.$this->encodePrimaryKey($this->company->id), $this->company->toArray());
 | 
			
		||||
        } catch (ValidationException $e) {
 | 
			
		||||
            $message = json_decode($e->validator->getMessageBag(), 1);
 | 
			
		||||
            nlog($message);
 | 
			
		||||
@ -109,7 +111,7 @@ class CompanySettingsTest extends TestCase
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
                'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
                'X-API-Token' => $this->token,
 | 
			
		||||
            ])->put('/api/v1/companies/'.$this->encodePrimaryKey($this->company->id), $this->company->toArray());
 | 
			
		||||
            ])->putJson('/api/v1/companies/'.$this->encodePrimaryKey($this->company->id), $this->company->toArray());
 | 
			
		||||
 | 
			
		||||
        $response->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
@ -135,7 +137,7 @@ class CompanySettingsTest extends TestCase
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
                'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
                'X-API-Token' => $this->token,
 | 
			
		||||
            ])->put('/api/v1/companies/'.$this->encodePrimaryKey($this->company->id), $this->company->toArray());
 | 
			
		||||
            ])->putJson('/api/v1/companies/'.$this->encodePrimaryKey($this->company->id), $this->company->toArray());
 | 
			
		||||
 | 
			
		||||
        $response->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
@ -162,7 +164,7 @@ class CompanySettingsTest extends TestCase
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
                'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
                'X-API-Token' => $this->token,
 | 
			
		||||
            ])->put('/api/v1/companies/'.$this->encodePrimaryKey($this->company->id), $this->company->toArray());
 | 
			
		||||
            ])->putJson('/api/v1/companies/'.$this->encodePrimaryKey($this->company->id), $this->company->toArray());
 | 
			
		||||
 | 
			
		||||
        $response->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
@ -185,7 +187,7 @@ class CompanySettingsTest extends TestCase
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-Token' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/companies?include=company', $this->company->toArray());
 | 
			
		||||
        ])->postJson('/api/v1/companies?include=company', $this->company->toArray());
 | 
			
		||||
 | 
			
		||||
        $arr = $response->json();
 | 
			
		||||
        $response->assertStatus(200);
 | 
			
		||||
@ -203,7 +205,7 @@ class CompanySettingsTest extends TestCase
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-Token' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/companies?include=company', $this->company->toArray());
 | 
			
		||||
        ])->postJson('/api/v1/companies?include=company', $this->company->toArray());
 | 
			
		||||
 | 
			
		||||
        $arr = $response->json();
 | 
			
		||||
        $response->assertStatus(200);
 | 
			
		||||
@ -221,7 +223,7 @@ class CompanySettingsTest extends TestCase
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-Token' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/companies?include=company', $this->company->toArray());
 | 
			
		||||
        ])->postJson('/api/v1/companies?include=company', $this->company->toArray());
 | 
			
		||||
 | 
			
		||||
        $arr = $response->json();
 | 
			
		||||
        $response->assertStatus(200);
 | 
			
		||||
@ -239,7 +241,7 @@ class CompanySettingsTest extends TestCase
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-Token' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/companies?include=company', $this->company->toArray());
 | 
			
		||||
        ])->postJson('/api/v1/companies?include=company', $this->company->toArray());
 | 
			
		||||
 | 
			
		||||
        $arr = $response->json();
 | 
			
		||||
        $response->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
@ -47,6 +47,31 @@ class PreviewTest extends TestCase
 | 
			
		||||
        $response->assertStatus(200);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testPurchaseOrderPreviewRoute()
 | 
			
		||||
    {
 | 
			
		||||
        $data = $this->getData();
 | 
			
		||||
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
                'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
                'X-API-TOKEN' => $this->token,
 | 
			
		||||
            ])->post('/api/v1/preview/purchase_order', $data);
 | 
			
		||||
 | 
			
		||||
        $response->assertStatus(200);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testPurchaseOrderPreviewHtmlResponse()
 | 
			
		||||
    {
 | 
			
		||||
        $data = $this->getData();
 | 
			
		||||
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
                'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
                'X-API-TOKEN' => $this->token,
 | 
			
		||||
            ])->post('/api/v1/preview/purchase_order?html=true', $data);
 | 
			
		||||
 | 
			
		||||
        $response->assertStatus(200);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public function testPreviewHtmlResponse()
 | 
			
		||||
    {
 | 
			
		||||
        $data = $this->getData();
 | 
			
		||||
 | 
			
		||||
@ -124,7 +124,7 @@ class EventTest extends TestCase
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/expenses/', $data)
 | 
			
		||||
        ])->postJson('/api/v1/expenses/', $data)
 | 
			
		||||
            ->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -137,7 +137,7 @@ class EventTest extends TestCase
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->put('/api/v1/expenses/' . $arr['data']['id'], $data)
 | 
			
		||||
        ])->putJson('/api/v1/expenses/' . $arr['data']['id'], $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -148,19 +148,19 @@ class EventTest extends TestCase
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/expenses/bulk?action=archive', $data)
 | 
			
		||||
        ])->postJson('/api/v1/expenses/bulk?action=archive', $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/expenses/bulk?action=restore', $data)
 | 
			
		||||
        ])->postJson('/api/v1/expenses/bulk?action=restore', $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/expenses/bulk?action=delete', $data)
 | 
			
		||||
        ])->postJson('/api/v1/expenses/bulk?action=delete', $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -183,7 +183,7 @@ class EventTest extends TestCase
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/vendors/', $data)
 | 
			
		||||
        ])->postJson('/api/v1/vendors/', $data)
 | 
			
		||||
            ->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -197,7 +197,7 @@ class EventTest extends TestCase
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->put('/api/v1/vendors/' . $arr['data']['id'], $data)
 | 
			
		||||
        ])->putJson('/api/v1/vendors/' . $arr['data']['id'], $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -208,19 +208,19 @@ class EventTest extends TestCase
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/vendors/bulk?action=archive', $data)
 | 
			
		||||
        ])->postJson('/api/v1/vendors/bulk?action=archive', $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/vendors/bulk?action=restore', $data)
 | 
			
		||||
        ])->postJson('/api/v1/vendors/bulk?action=restore', $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/vendors/bulk?action=delete', $data)
 | 
			
		||||
        ])->postJson('/api/v1/vendors/bulk?action=delete', $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -245,7 +245,7 @@ class EventTest extends TestCase
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/tasks/', $data)
 | 
			
		||||
        ])->postJson('/api/v1/tasks/', $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -259,7 +259,7 @@ class EventTest extends TestCase
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->put('/api/v1/tasks/' . $arr['data']['id'], $data)
 | 
			
		||||
        ])->putJson('/api/v1/tasks/' . $arr['data']['id'], $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -270,19 +270,19 @@ class EventTest extends TestCase
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/tasks/bulk?action=archive', $data)
 | 
			
		||||
        ])->postJson('/api/v1/tasks/bulk?action=archive', $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/tasks/bulk?action=restore', $data)
 | 
			
		||||
        ])->postJson('/api/v1/tasks/bulk?action=restore', $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/tasks/bulk?action=delete', $data)
 | 
			
		||||
        ])->postJson('/api/v1/tasks/bulk?action=delete', $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -306,7 +306,7 @@ class EventTest extends TestCase
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/credits/', $data)
 | 
			
		||||
        ])->postJson('/api/v1/credits/', $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -320,7 +320,7 @@ class EventTest extends TestCase
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->put('/api/v1/credits/' . $arr['data']['id'], $data)
 | 
			
		||||
        ])->putJson('/api/v1/credits/' . $arr['data']['id'], $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -331,19 +331,19 @@ class EventTest extends TestCase
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/credits/bulk?action=archive', $data)
 | 
			
		||||
        ])->postJson('/api/v1/credits/bulk?action=archive', $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/credits/bulk?action=restore', $data)
 | 
			
		||||
        ])->postJson('/api/v1/credits/bulk?action=restore', $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/credits/bulk?action=delete', $data)
 | 
			
		||||
        ])->postJson('/api/v1/credits/bulk?action=delete', $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -368,7 +368,7 @@ class EventTest extends TestCase
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/quotes/', $data)
 | 
			
		||||
        ])->postJson('/api/v1/quotes/', $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -382,7 +382,7 @@ class EventTest extends TestCase
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->put('/api/v1/quotes/' . $arr['data']['id'], $data)
 | 
			
		||||
        ])->putJson('/api/v1/quotes/' . $arr['data']['id'], $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -397,25 +397,25 @@ class EventTest extends TestCase
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/quotes/bulk?action=archive', $data)
 | 
			
		||||
        ])->postJson('/api/v1/quotes/bulk?action=archive', $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/quotes/bulk?action=restore', $data)
 | 
			
		||||
        ])->postJson('/api/v1/quotes/bulk?action=restore', $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/quotes/bulk?action=approve', $data)
 | 
			
		||||
        ])->postJson('/api/v1/quotes/bulk?action=approve', $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/quotes/bulk?action=delete', $data)
 | 
			
		||||
        ])->postJson('/api/v1/quotes/bulk?action=delete', $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -449,7 +449,7 @@ class EventTest extends TestCase
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/payments?include=invoices', $data)
 | 
			
		||||
        ])->postJson('/api/v1/payments?include=invoices', $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
        $arr = $response->json();
 | 
			
		||||
@ -461,7 +461,7 @@ class EventTest extends TestCase
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->put('/api/v1/payments/' . $arr['data']['id'], $data)
 | 
			
		||||
        ])->putJson('/api/v1/payments/' . $arr['data']['id'], $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
        $data = [
 | 
			
		||||
@ -471,19 +471,19 @@ class EventTest extends TestCase
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/payments/bulk?action=archive', $data)
 | 
			
		||||
        ])->postJson('/api/v1/payments/bulk?action=archive', $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/payments/bulk?action=restore', $data)
 | 
			
		||||
        ])->postJson('/api/v1/payments/bulk?action=restore', $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/payments/bulk?action=delete', $data)
 | 
			
		||||
        ])->postJson('/api/v1/payments/bulk?action=delete', $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -507,7 +507,7 @@ class EventTest extends TestCase
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/invoices/', $data)
 | 
			
		||||
        ])->postJson('/api/v1/invoices/', $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -521,7 +521,7 @@ class EventTest extends TestCase
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->put('/api/v1/invoices/' . $arr['data']['id'], $data)
 | 
			
		||||
        ])->putJson('/api/v1/invoices/' . $arr['data']['id'], $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -532,19 +532,19 @@ class EventTest extends TestCase
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/invoices/bulk?action=archive', $data)
 | 
			
		||||
        ])->postJson('/api/v1/invoices/bulk?action=archive', $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/invoices/bulk?action=restore', $data)
 | 
			
		||||
        ])->postJson('/api/v1/invoices/bulk?action=restore', $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/invoices/bulk?action=delete', $data)
 | 
			
		||||
        ])->postJson('/api/v1/invoices/bulk?action=delete', $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -571,7 +571,7 @@ class EventTest extends TestCase
 | 
			
		||||
            $response = $this->withHeaders([
 | 
			
		||||
                'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
                'X-API-TOKEN' => $this->token,
 | 
			
		||||
            ])->post('/api/v1/recurring_invoices/', $data);
 | 
			
		||||
            ])->postJson('/api/v1/recurring_invoices/', $data);
 | 
			
		||||
        } catch (ValidationException $e) {
 | 
			
		||||
            $message = json_decode($e->validator->getMessageBag(), 1);
 | 
			
		||||
        }
 | 
			
		||||
@ -590,7 +590,7 @@ class EventTest extends TestCase
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->put('/api/v1/recurring_invoices/' . $arr['data']['id'], $data)
 | 
			
		||||
        ])->putJson('/api/v1/recurring_invoices/' . $arr['data']['id'], $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -601,19 +601,19 @@ class EventTest extends TestCase
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/recurring_invoices/bulk?action=archive', $data)
 | 
			
		||||
        ])->postJson('/api/v1/recurring_invoices/bulk?action=archive', $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/recurring_invoices/bulk?action=restore', $data)
 | 
			
		||||
        ])->postJson('/api/v1/recurring_invoices/bulk?action=restore', $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/recurring_invoices/bulk?action=delete', $data)
 | 
			
		||||
        ])->postJson('/api/v1/recurring_invoices/bulk?action=delete', $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -636,7 +636,7 @@ class EventTest extends TestCase
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/clients/', $data)
 | 
			
		||||
        ])->postJson('/api/v1/clients/', $data)
 | 
			
		||||
            ->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -650,7 +650,7 @@ class EventTest extends TestCase
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->put('/api/v1/clients/' . $arr['data']['id'], $data)
 | 
			
		||||
        ])->putJson('/api/v1/clients/' . $arr['data']['id'], $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -661,19 +661,19 @@ class EventTest extends TestCase
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/clients/bulk?action=archive', $data)
 | 
			
		||||
        ])->postJson('/api/v1/clients/bulk?action=archive', $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/clients/bulk?action=restore', $data)
 | 
			
		||||
        ])->postJson('/api/v1/clients/bulk?action=restore', $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/clients/bulk?action=delete', $data)
 | 
			
		||||
        ])->postJson('/api/v1/clients/bulk?action=delete', $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -705,7 +705,7 @@ class EventTest extends TestCase
 | 
			
		||||
                'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
                'X-API-TOKEN' => $this->token,
 | 
			
		||||
                'X-API-PASSWORD' => 'ALongAndBriliantPassword',
 | 
			
		||||
        ])->post('/api/v1/users?include=company_user', $data)
 | 
			
		||||
        ])->postJson('/api/v1/users?include=company_user', $data)
 | 
			
		||||
          ->assertStatus(200);
 | 
			
		||||
       
 | 
			
		||||
        $arr = $response->json();
 | 
			
		||||
@ -725,7 +725,7 @@ class EventTest extends TestCase
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
            'X-API-PASSWORD' => 'ALongAndBriliantPassword',
 | 
			
		||||
        ])->put('/api/v1/users/' . $arr['data']['id'], $data)
 | 
			
		||||
        ])->putJson('/api/v1/users/' . $arr['data']['id'], $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -737,21 +737,21 @@ class EventTest extends TestCase
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
            'X-API-PASSWORD' => 'ALongAndBriliantPassword',
 | 
			
		||||
        ])->post('/api/v1/users/bulk?action=archive', $data)
 | 
			
		||||
        ])->postJson('/api/v1/users/bulk?action=archive', $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
            'X-API-PASSWORD' => 'ALongAndBriliantPassword',
 | 
			
		||||
        ])->post('/api/v1/users/bulk?action=restore', $data)
 | 
			
		||||
        ])->postJson('/api/v1/users/bulk?action=restore', $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
            'X-API-PASSWORD' => 'ALongAndBriliantPassword',
 | 
			
		||||
        ])->post('/api/v1/users/bulk?action=delete', $data)
 | 
			
		||||
        ])->postJson('/api/v1/users/bulk?action=delete', $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -772,7 +772,7 @@ class EventTest extends TestCase
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/subscriptions/', $data)
 | 
			
		||||
        ])->postJson('/api/v1/subscriptions/', $data)
 | 
			
		||||
            ->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -785,7 +785,7 @@ class EventTest extends TestCase
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->put('/api/v1/subscriptions/' . $arr['data']['id'], $data)
 | 
			
		||||
        ])->putJson('/api/v1/subscriptions/' . $arr['data']['id'], $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -796,19 +796,19 @@ class EventTest extends TestCase
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/subscriptions/bulk?action=archive', $data)
 | 
			
		||||
        ])->postJson('/api/v1/subscriptions/bulk?action=archive', $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/subscriptions/bulk?action=restore', $data)
 | 
			
		||||
        ])->postJson('/api/v1/subscriptions/bulk?action=restore', $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/subscriptions/bulk?action=delete', $data)
 | 
			
		||||
        ])->postJson('/api/v1/subscriptions/bulk?action=delete', $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -833,7 +833,7 @@ public function PurchaseOrderEvents()
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/purchase_orders/', $data)
 | 
			
		||||
        ])->postJson('/api/v1/purchase_orders/', $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -847,7 +847,7 @@ public function PurchaseOrderEvents()
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->put('/api/v1/purchase_orders/' . $arr['data']['id'], $data)
 | 
			
		||||
        ])->putJson('/api/v1/purchase_orders/' . $arr['data']['id'], $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -862,25 +862,25 @@ public function PurchaseOrderEvents()
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/purchase_orders/bulk?action=archive', $data)
 | 
			
		||||
        ])->postJson('/api/v1/purchase_orders/bulk?action=archive', $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/purchase_orders/bulk?action=restore', $data)
 | 
			
		||||
        ])->postJson('/api/v1/purchase_orders/bulk?action=restore', $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/purchase_orders/bulk?action=approve', $data)
 | 
			
		||||
        ])->postJson('/api/v1/purchase_orders/bulk?action=approve', $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
 | 
			
		||||
        $response = $this->withHeaders([
 | 
			
		||||
            'X-API-SECRET' => config('ninja.api_secret'),
 | 
			
		||||
            'X-API-TOKEN' => $this->token,
 | 
			
		||||
        ])->post('/api/v1/purchase_orders/bulk?action=delete', $data)
 | 
			
		||||
        ])->postJson('/api/v1/purchase_orders/bulk?action=delete', $data)
 | 
			
		||||
        ->assertStatus(200);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										8
									
								
								webpack.mix.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								webpack.mix.js
									
									
									
									
										vendored
									
									
								
							@ -10,6 +10,14 @@ mix.js("resources/js/app.js", "public/js")
 | 
			
		||||
        "resources/js/clients/payments/authorize-credit-card-payment.js",
 | 
			
		||||
        "public/js/clients/payments/authorize-credit-card-payment.js"
 | 
			
		||||
    )
 | 
			
		||||
    .js(
 | 
			
		||||
        "resources/js/clients/payments/forte-credit-card-payment.js",
 | 
			
		||||
        "public/js/clients/payments/forte-credit-card-payment.js"
 | 
			
		||||
    )
 | 
			
		||||
    .js(
 | 
			
		||||
        "resources/js/clients/payments/forte-ach-payment.js",
 | 
			
		||||
        "public/js/clients/payments/forte-ach-payment.js"
 | 
			
		||||
    )
 | 
			
		||||
    .js(
 | 
			
		||||
        "resources/js/clients/payments/stripe-ach.js",
 | 
			
		||||
        "public/js/clients/payments/stripe-ach.js"
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user