mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-07 17:54:30 -04:00
commit
8d0cadf88e
@ -1 +1 @@
|
||||
5.3.30
|
||||
5.3.31
|
@ -178,7 +178,8 @@ class EmailTemplateDefaults
|
||||
|
||||
public static function emailReminder1Template()
|
||||
{
|
||||
return '';
|
||||
return self::emailInvoiceTemplate();
|
||||
//return '';
|
||||
}
|
||||
|
||||
public static function emailReminder2Subject()
|
||||
@ -188,7 +189,8 @@ class EmailTemplateDefaults
|
||||
|
||||
public static function emailReminder2Template()
|
||||
{
|
||||
return '';
|
||||
return self::emailInvoiceTemplate();
|
||||
//return '';
|
||||
}
|
||||
|
||||
public static function emailReminder3Subject()
|
||||
@ -198,7 +200,8 @@ class EmailTemplateDefaults
|
||||
|
||||
public static function emailReminder3Template()
|
||||
{
|
||||
return '';
|
||||
return self::emailInvoiceTemplate();
|
||||
//return '';
|
||||
}
|
||||
|
||||
public static function emailReminderEndlessSubject()
|
||||
@ -208,6 +211,7 @@ class EmailTemplateDefaults
|
||||
|
||||
public static function emailReminderEndlessTemplate()
|
||||
{
|
||||
return self::emailInvoiceTemplate();
|
||||
return '';
|
||||
}
|
||||
|
||||
|
30
app/Helpers/Document/WithTypeHelpers.php
Normal file
30
app/Helpers/Document/WithTypeHelpers.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?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\Helpers\Document;
|
||||
|
||||
trait WithTypeHelpers
|
||||
{
|
||||
/**
|
||||
* Returns boolean based on checks for image.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isImage(): bool
|
||||
{
|
||||
if (in_array($this->type, ['png', 'svg', 'jpeg', 'jpg', 'tiff', 'gif'])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
@ -59,7 +59,6 @@ class InvoiceController extends Controller
|
||||
|
||||
$invoice->service()->removeUnpaidGatewayFees()->save();
|
||||
|
||||
|
||||
$invitation = $invoice->invitations()->where('client_contact_id', auth()->user()->id)->first();
|
||||
|
||||
if ($invitation && auth()->guard('contact') && ! request()->has('silent') && ! $invitation->viewed_date) {
|
||||
|
@ -13,12 +13,31 @@
|
||||
namespace App\Http\Controllers\ClientPortal;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\RecurringInvoice;
|
||||
use App\Utils\Ninja;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class SubscriptionController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
|
||||
if(Ninja::isHosted()){
|
||||
|
||||
|
||||
$count = RecurringInvoice::query()
|
||||
->where('client_id', auth('contact')->user()->client->id)
|
||||
->where('company_id', auth('contact')->user()->client->company_id)
|
||||
->where('status_id', RecurringInvoice::STATUS_ACTIVE)
|
||||
->whereNotNull('subscription_id')
|
||||
->count();
|
||||
|
||||
if($count == 0)
|
||||
return redirect()->route('client.ninja_contact_login', ['contact_key' => auth('contact')->user()->contact_key, 'company_key' => auth('contact')->user()->company->company_key]);
|
||||
|
||||
}
|
||||
|
||||
|
||||
return render('subscriptions.index');
|
||||
}
|
||||
}
|
||||
|
@ -83,7 +83,7 @@ class ImportController extends Controller {
|
||||
$contents = file_get_contents( $file->getPathname() );
|
||||
|
||||
// Store the csv in cache with an expiry of 10 minutes
|
||||
Cache::put( $hash . '-' . $entityType, base64_encode( $contents ), 3600 );
|
||||
Cache::put( $hash . '-' . $entityType, base64_encode( $contents ), 600 );
|
||||
|
||||
// Parse CSV
|
||||
$csv_array = $this->getCsvData( $contents );
|
||||
@ -111,7 +111,7 @@ class ImportController extends Controller {
|
||||
$contents = file_get_contents( $file->getPathname() );
|
||||
|
||||
// Store the csv in cache with an expiry of 10 minutes
|
||||
Cache::put( $hash . '-' . $entityType, base64_encode( $contents ), 3600 );
|
||||
Cache::put( $hash . '-' . $entityType, base64_encode( $contents ), 600 );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -522,9 +522,6 @@ class InvoiceController extends BaseController
|
||||
|
||||
$ids = request()->input('ids');
|
||||
|
||||
nlog($action);
|
||||
nlog($ids);
|
||||
|
||||
$invoices = Invoice::withTrashed()->whereIn('id', $this->transformKeys($ids))->company()->get();
|
||||
|
||||
if (! $invoices) {
|
||||
@ -542,7 +539,7 @@ nlog($ids);
|
||||
return response()->json(['message' => ctrans('text.access_denied')]);
|
||||
}
|
||||
});
|
||||
nlog("bulky");
|
||||
|
||||
ZipInvoices::dispatch($invoices, $invoices->first()->company, auth()->user());
|
||||
|
||||
return response()->json(['message' => ctrans('texts.sent_message')], 200);
|
||||
|
@ -293,7 +293,7 @@ class BillingPortalPurchase extends Component
|
||||
return $this;
|
||||
}
|
||||
|
||||
if ((int)$this->subscription->price == 0)
|
||||
if ((int)$this->price == 0)
|
||||
$this->steps['payment_required'] = false;
|
||||
else
|
||||
$this->steps['fetched_payment_methods'] = true;
|
||||
|
@ -42,7 +42,7 @@ class RecurringInvoicesTable extends Component
|
||||
$query = $query
|
||||
->where('client_id', auth('contact')->user()->client->id)
|
||||
->where('company_id', $this->company->id)
|
||||
->whereIn('status_id', [RecurringInvoice::STATUS_PENDING, RecurringInvoice::STATUS_ACTIVE, RecurringInvoice::STATUS_PAUSED,RecurringInvoice::STATUS_COMPLETED])
|
||||
->whereIn('status_id', [RecurringInvoice::STATUS_ACTIVE])
|
||||
->orderBy('status_id', 'asc')
|
||||
->with('client')
|
||||
->orderBy($this->sort_field, $this->sort_asc ? 'asc' : 'desc')
|
||||
|
@ -38,6 +38,7 @@ class SubscriptionRecurringInvoicesTable extends Component
|
||||
->where('client_id', auth('contact')->user()->client->id)
|
||||
->where('company_id', $this->company->id)
|
||||
->whereNotNull('subscription_id')
|
||||
->where('status_id', RecurringInvoice::STATUS_ACTIVE)
|
||||
->orderBy($this->sort_field, $this->sort_asc ? 'asc' : 'desc')
|
||||
->withTrashed()
|
||||
->paginate($this->per_page);
|
||||
|
@ -42,6 +42,16 @@ class TokenAuth
|
||||
return response()->json($error, 403);
|
||||
}
|
||||
|
||||
if(Ninja::isHosted() && $company_token->is_system == 0 && !$user->account->isPaid()){
|
||||
|
||||
$error = [
|
||||
'message' => 'Feature not available with free / unpaid account.',
|
||||
'errors' => new stdClass,
|
||||
];
|
||||
|
||||
return response()->json($error, 403);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
||||
| Necessary evil here: As we are authenticating on CompanyToken,
|
||||
|
@ -221,6 +221,9 @@ class BaseTransformer
|
||||
{
|
||||
$name = strtolower(trim($name));
|
||||
|
||||
if(strlen($name) == 2)
|
||||
return $this->getCountryIdBy2($name);
|
||||
|
||||
return isset($this->maps['countries'][$name]) ? $this->maps['countries'][$name] : null;
|
||||
}
|
||||
|
||||
|
@ -587,7 +587,7 @@ class CSVImport implements ShouldQueue {
|
||||
}
|
||||
|
||||
private function getCsvData( $entityType ) {
|
||||
$base64_encoded_csv = Cache::get( $this->hash . '-' . $entityType );
|
||||
$base64_encoded_csv = Cache::pull( $this->hash . '-' . $entityType );
|
||||
if ( empty( $base64_encoded_csv ) ) {
|
||||
return null;
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ class ZipInvoices implements ShouldQueue
|
||||
*/
|
||||
|
||||
public function handle()
|
||||
{nlog("bulky");
|
||||
{
|
||||
# create new zip object
|
||||
$zip = new ZipArchive();
|
||||
|
||||
|
@ -232,6 +232,7 @@ class Import implements ShouldQueue
|
||||
|
||||
$account = $this->company->account;
|
||||
$account->default_company_id = $this->company->id;
|
||||
$account->is_migrated = true;
|
||||
$account->save();
|
||||
|
||||
//company size check
|
||||
|
@ -49,15 +49,19 @@ class SystemLogger implements ShouldQueue
|
||||
|
||||
public function handle() :void
|
||||
{
|
||||
if(!$this->company)
|
||||
if(!$this->company){
|
||||
nlog("SystemLogger:: No company");
|
||||
return;
|
||||
}
|
||||
|
||||
MultiDB::setDb($this->company->db);
|
||||
|
||||
$client_id = $this->client ? $this->client->id : null;
|
||||
|
||||
if(!$this->client && !$this->company->owner())
|
||||
if(!$this->client && !$this->company->owner()){
|
||||
nlog("SystemLogger:: could not find client and/or company owner");
|
||||
return;
|
||||
}
|
||||
|
||||
$user_id = $this->client ? $this->client->user_id : $this->company->owner()->id;
|
||||
|
||||
@ -71,9 +75,16 @@ class SystemLogger implements ShouldQueue
|
||||
'type_id' => $this->type_id,
|
||||
];
|
||||
|
||||
if(!$this->log)
|
||||
if(!$this->log){
|
||||
nlog("SystemLogger:: no log to store");
|
||||
return;
|
||||
}
|
||||
|
||||
SystemLog::create($sl);
|
||||
}
|
||||
|
||||
public function failed($e)
|
||||
{
|
||||
nlog($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
@ -52,6 +52,10 @@ class InvoiceCreatedNotification implements ShouldQueue
|
||||
|
||||
/* The User */
|
||||
$user = $company_user->user;
|
||||
|
||||
if(!$user)
|
||||
continue;
|
||||
|
||||
/* This is only here to handle the alternate message channels - ie Slack */
|
||||
// $notification = new EntitySentNotification($event->invitation, 'invoice');
|
||||
|
||||
@ -71,11 +75,6 @@ class InvoiceCreatedNotification implements ShouldQueue
|
||||
|
||||
}
|
||||
|
||||
/* Override the methods in the Notification Class */
|
||||
// $notification->method = $methods;
|
||||
|
||||
// Notify on the alternate channels
|
||||
// $user->notify($notification);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -53,6 +53,9 @@ class QuoteCreatedNotification implements ShouldQueue
|
||||
/* The User */
|
||||
$user = $company_user->user;
|
||||
|
||||
if(!$user)
|
||||
continue;
|
||||
|
||||
/* This is only here to handle the alternate message channels - ie Slack */
|
||||
// $notification = new EntitySentNotification($event->invitation, 'quote');
|
||||
|
||||
|
@ -75,7 +75,7 @@ class ClientPaymentFailureObject
|
||||
$mail_obj->amount = $this->getAmount();
|
||||
$mail_obj->subject = $this->getSubject();
|
||||
$mail_obj->data = $this->getData();
|
||||
$mail_obj->markdown = 'email.admin.generic';
|
||||
$mail_obj->markdown = 'email.client.generic';
|
||||
$mail_obj->tag = $this->company->company_key;
|
||||
|
||||
return $mail_obj;
|
||||
@ -113,14 +113,15 @@ class ClientPaymentFailureObject
|
||||
]
|
||||
),
|
||||
'greeting' => ctrans('texts.email_salutation', ['name' => $this->client->present()->name]),
|
||||
'message' => ctrans('texts.client_payment_failure_body', ['invoice' => implode(",", $this->invoices->pluck('number')->toArray()), 'amount' => $this->getAmount()]),
|
||||
'content' => ctrans('texts.client_payment_failure_body', ['invoice' => implode(",", $this->invoices->pluck('number')->toArray()), 'amount' => $this->getAmount()]),
|
||||
'signature' => $signature,
|
||||
'logo' => $this->company->present()->logo(),
|
||||
'settings' => $this->client->getMergedSettings(),
|
||||
'whitelabel' => $this->company->account->isPaid() ? true : false,
|
||||
'url' => route('client.login'),
|
||||
'button' => ctrans('texts.login'),
|
||||
'additional_info' => false
|
||||
'url' => $this->invoices->first()->invitations->first()->getPaymentLink(),
|
||||
'button' => 'texts.pay_now',
|
||||
'additional_info' => false,
|
||||
'company' => $this->company,
|
||||
];
|
||||
|
||||
return $data;
|
||||
|
@ -3,9 +3,11 @@
|
||||
namespace App\Mail;
|
||||
|
||||
use App\Models\Company;
|
||||
use App\Utils\Ninja;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\App;
|
||||
|
||||
class MigrationCompleted extends Mailable
|
||||
{
|
||||
@ -33,6 +35,11 @@ class MigrationCompleted extends Mailable
|
||||
*/
|
||||
public function build()
|
||||
{
|
||||
|
||||
App::forgetInstance('translator');
|
||||
$t = app('translator');
|
||||
$t->replace(Ninja::transformTranslations($this->company->settings));
|
||||
|
||||
$data['settings'] = $this->company->settings;
|
||||
$data['company'] = $this->company->fresh();
|
||||
$data['whitelabel'] = $this->company->account->isPaid() ? true : false;
|
||||
|
@ -217,6 +217,9 @@ class ClientContact extends Authenticatable implements HasLocalePreference
|
||||
{
|
||||
$languages = Cache::get('languages');
|
||||
|
||||
if(!$languages)
|
||||
$this->buildCache(true);
|
||||
|
||||
return $languages->filter(function ($item) {
|
||||
return $item->id == $this->client->getSetting('language_id');
|
||||
})->first()->locale;
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Helpers\Document\WithTypeHelpers;
|
||||
use App\Models\Filterable;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
@ -19,6 +20,7 @@ class Document extends BaseModel
|
||||
{
|
||||
use SoftDeletes;
|
||||
use Filterable;
|
||||
use WithTypeHelpers;
|
||||
|
||||
const DOCUMENT_PREVIEW_SIZE = 300; // pixels
|
||||
|
||||
|
@ -63,8 +63,8 @@ class CreditCard
|
||||
$transaction = [
|
||||
'Reference' => $this->eway_driver->client->number,
|
||||
'Title' => '',
|
||||
'FirstName' => $this->eway_driver->client->contacts()->first()->present()->last_name(),
|
||||
'LastName' => $this->eway_driver->client->contacts()->first()->present()->first_name(),
|
||||
'FirstName' => $this->eway_driver->client->contacts()->first()->present()->first_name(),
|
||||
'LastName' => $this->eway_driver->client->contacts()->first()->present()->last_name(),
|
||||
'CompanyName' => $this->eway_driver->client->name,
|
||||
'Street1' => $this->eway_driver->client->address1,
|
||||
'Street2' => $this->eway_driver->client->address2,
|
||||
|
@ -57,7 +57,7 @@ class HandleReversal extends AbstractService
|
||||
$paymentables->each(function ($paymentable) use ($total_paid) {
|
||||
|
||||
//new concept - when reversing, we unwind the payments
|
||||
$payment = Payment::find($paymentable->payment_id);
|
||||
$payment = Payment::withTrashed()->find($paymentable->payment_id);
|
||||
|
||||
$reversable_amount = $paymentable->amount - $paymentable->refunded;
|
||||
$total_paid -= $reversable_amount;
|
||||
|
@ -37,34 +37,37 @@ class MarkSent extends AbstractService
|
||||
return $this->invoice;
|
||||
}
|
||||
|
||||
$adjustment = $this->invoice->amount;
|
||||
|
||||
/*Set status*/
|
||||
$this->invoice
|
||||
->service()
|
||||
->setStatus(Invoice::STATUS_SENT)
|
||||
->updateBalance($adjustment, true)
|
||||
->save();
|
||||
|
||||
$this->invoice
|
||||
/*Adjust client balance*/
|
||||
$this->client
|
||||
->service()
|
||||
->updateBalance($adjustment)
|
||||
->save();
|
||||
|
||||
/*Update ledger*/
|
||||
$this->invoice
|
||||
->ledger()
|
||||
->updateInvoiceBalance($adjustment, "Invoice {$this->invoice->number} marked as sent.");
|
||||
|
||||
/* Perform additional actions on invoice */
|
||||
$this->invoice
|
||||
->service()
|
||||
->applyNumber()
|
||||
->setDueDate()
|
||||
->updateBalance($this->invoice->amount, true)
|
||||
->deletePdf()
|
||||
->setReminder()
|
||||
->save();
|
||||
|
||||
$this->invoice->markInvitationsSent();
|
||||
|
||||
/*Adjust client balance*/
|
||||
$this->client
|
||||
->service()
|
||||
->updateBalance($this->invoice->balance)
|
||||
->save();
|
||||
|
||||
/*Update ledger*/
|
||||
$this->invoice
|
||||
->ledger()
|
||||
->updateInvoiceBalance($this->invoice->balance, "Invoice {$this->invoice->number} marked as sent.");
|
||||
|
||||
event(new InvoiceWasUpdated($this->invoice, $this->invoice->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
|
||||
|
||||
return $this->invoice->fresh();
|
||||
|
@ -34,6 +34,9 @@ class UpdateBalance extends AbstractService
|
||||
if ($this->invoice->is_deleted) {
|
||||
return $this->invoice;
|
||||
}
|
||||
nlog("invoice id = {$this->invoice->id}");
|
||||
nlog("invoice balance = {$this->invoice->balance}");
|
||||
nlog("invoice adjustment = {$this->balance_adjustment}");
|
||||
|
||||
$this->invoice->balance += floatval($this->balance_adjustment);
|
||||
|
||||
@ -41,6 +44,8 @@ class UpdateBalance extends AbstractService
|
||||
$this->invoice->status_id = Invoice::STATUS_PAID;
|
||||
}
|
||||
|
||||
nlog("final balance = {$this->invoice->balance}");
|
||||
|
||||
return $this->invoice;
|
||||
}
|
||||
}
|
||||
|
@ -290,6 +290,9 @@ class SubscriptionService
|
||||
|
||||
$days_in_frequency = $this->getDaysInFrequency();
|
||||
|
||||
if($days_of_subscription_used >= $days_in_frequency)
|
||||
return 0;
|
||||
|
||||
$pro_rata_refund = round((($days_in_frequency - $days_of_subscription_used)/$days_in_frequency) * $invoice->amount ,2);
|
||||
|
||||
// nlog("days in frequency = {$days_in_frequency} - days of subscription used {$days_of_subscription_used}");
|
||||
@ -322,7 +325,8 @@ class SubscriptionService
|
||||
|
||||
$days_of_subscription_used = $start_date->diffInDays($current_date);
|
||||
|
||||
$days_in_frequency = $this->getDaysInFrequency();
|
||||
// $days_in_frequency = $this->getDaysInFrequency();
|
||||
$days_in_frequency = $invoice->subscription->service()->getDaysInFrequency();
|
||||
|
||||
$ratio = ($days_in_frequency - $days_of_subscription_used)/$days_in_frequency;
|
||||
|
||||
@ -427,6 +431,8 @@ class SubscriptionService
|
||||
|
||||
nlog("total payable = {$total_payable}");
|
||||
|
||||
$credit = false;
|
||||
|
||||
/* Only generate a credit if the previous invoice was paid in full. */
|
||||
if($last_invoice->balance == 0)
|
||||
$credit = $this->createCredit($last_invoice, $target_subscription, $is_credit);
|
||||
@ -436,7 +442,7 @@ class SubscriptionService
|
||||
$context = [
|
||||
'context' => 'change_plan',
|
||||
'recurring_invoice' => $new_recurring_invoice->hashed_id,
|
||||
'credit' => $credit->hashed_id,
|
||||
'credit' => $credit ? $credit->hashed_id : null,
|
||||
'client' => $new_recurring_invoice->client->hashed_id,
|
||||
'subscription' => $target_subscription->hashed_id,
|
||||
'contact' => auth('contact')->user()->hashed_id,
|
||||
@ -446,7 +452,10 @@ class SubscriptionService
|
||||
|
||||
nlog($response);
|
||||
|
||||
return $this->handleRedirect('/client/credits/'.$credit->hashed_id);
|
||||
if($credit)
|
||||
return $this->handleRedirect('/client/credits/'.$credit->hashed_id);
|
||||
else
|
||||
return $this->handleRedirect('/client/credits');
|
||||
|
||||
}
|
||||
|
||||
@ -545,6 +554,9 @@ class SubscriptionService
|
||||
|
||||
$old_recurring_invoice = RecurringInvoice::find($payment_hash->data->billing_context->recurring_invoice);
|
||||
|
||||
if(!$old_recurring_invoice)
|
||||
return $this->handleRedirect('/client/recurring_invoices/');
|
||||
|
||||
$recurring_invoice = $this->createNewRecurringInvoice($old_recurring_invoice);
|
||||
|
||||
$context = [
|
||||
@ -702,7 +714,7 @@ class SubscriptionService
|
||||
|
||||
$recurring_invoice = RecurringInvoiceFactory::create($this->subscription->company_id, $this->subscription->user_id);
|
||||
$recurring_invoice->client_id = $client_id;
|
||||
$recurring_invoice->line_items = $subscription_repo->generateLineItems($this->subscription, true);
|
||||
$recurring_invoice->line_items = $subscription_repo->generateLineItems($this->subscription, true, false);
|
||||
$recurring_invoice->subscription_id = $this->subscription->id;
|
||||
$recurring_invoice->frequency_id = $this->subscription->frequency_id ?: RecurringInvoice::FREQUENCY_MONTHLY;
|
||||
$recurring_invoice->date = now();
|
||||
|
@ -82,6 +82,7 @@ class AccountTransformer extends EntityTransformer
|
||||
'disable_auto_update' => (bool) config('ninja.disable_auto_update'),
|
||||
'emails_sent' => (int) $account->emailsSent(),
|
||||
'email_quota' => (int) $account->getDailyEmailLimit(),
|
||||
'is_migrated' => (bool) $account->is_migrated,
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -481,6 +481,8 @@ class HtmlEngine
|
||||
$data['$statement_amount'] = ['value' => '', 'label' => ctrans('texts.amount')];
|
||||
$data['$statement'] = ['value' => '', 'label' => ctrans('texts.statement')];
|
||||
|
||||
$data['$entity_images'] = ['value' => $this->generateEntityImagesMarkup(), 'label' => ''];
|
||||
|
||||
$arrKeysLength = array_map('strlen', array_keys($data));
|
||||
array_multisort($arrKeysLength, SORT_DESC, $data);
|
||||
|
||||
@ -737,4 +739,38 @@ html {
|
||||
|
||||
return $css;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate markup for HTML images on entity.
|
||||
*
|
||||
* @return string|void
|
||||
*/
|
||||
protected function generateEntityImagesMarkup()
|
||||
{
|
||||
if ($this->client->getSetting('embed_documents') === false) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$dom = new \DOMDocument('1.0', 'UTF-8');
|
||||
|
||||
$container = $dom->createElement('div');
|
||||
$container->setAttribute('style', 'display:grid; grid-auto-flow: row; grid-template-columns: repeat(4, 1fr); grid-template-rows: repeat(2, 1fr);');
|
||||
|
||||
foreach ($this->entity->documents as $document) {
|
||||
if (!$document->isImage()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$image = $dom->createElement('img');
|
||||
|
||||
$image->setAttribute('src', $document->generateUrl());
|
||||
$image->setAttribute('style', 'max-height: 100px; margin-top: 20px;');
|
||||
|
||||
$container->appendChild($image);
|
||||
}
|
||||
|
||||
$dom->appendChild($container);
|
||||
|
||||
return $dom->saveHTML();
|
||||
}
|
||||
}
|
||||
|
@ -113,8 +113,14 @@ class Ninja
|
||||
|
||||
public static function eventVars($user_id = null)
|
||||
{
|
||||
|
||||
if(request()->hasHeader('Cf-Connecting-Ip'))
|
||||
$ip = request()->header('Cf-Connecting-Ip');
|
||||
else
|
||||
$ip = request()->getClientIp();
|
||||
|
||||
return [
|
||||
'ip' => request()->getClientIp(),
|
||||
'ip' => $ip,
|
||||
'token' => request()->header('X-API-TOKEN'),
|
||||
'is_system' => app()->runningInConsole(),
|
||||
'user_id' => $user_id,
|
||||
|
@ -207,7 +207,7 @@ return [
|
||||
['options' => [
|
||||
'replication' => 'sentinel',
|
||||
'service' => env('REDIS_SENTINEL_SERVICE', 'mymaster'),
|
||||
'sentinel_timeout' => 1.0,
|
||||
'sentinel_timeout' => 2.0,
|
||||
'parameters' => [
|
||||
'password' => env('REDIS_PASSWORD', null),
|
||||
'database' => env('REDIS_DB', 0),
|
||||
@ -226,7 +226,7 @@ return [
|
||||
['options' => [
|
||||
'replication' => 'sentinel',
|
||||
'service' => env('REDIS_SENTINEL_SERVICE', 'mymaster'),
|
||||
'sentinel_timeout' => 1.0,
|
||||
'sentinel_timeout' => 2.0,
|
||||
'parameters' => [
|
||||
'password' => env('REDIS_PASSWORD', null),
|
||||
'database' => env('REDIS_CACHE_DB', 1),
|
||||
|
@ -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.3.30',
|
||||
'app_tag' => '5.3.30',
|
||||
'app_version' => '5.3.31',
|
||||
'app_tag' => '5.3.31',
|
||||
'minimum_client_version' => '5.0.16',
|
||||
'terms_version' => '1.0.1',
|
||||
'api_secret' => env('API_SECRET', ''),
|
||||
|
@ -1,21 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class Onboarding extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('accounts', function (Blueprint $table) {
|
||||
$table->boolean('is_onboarding')->default(false);
|
||||
$table->mediumText('onboarding')->nullable();
|
||||
});
|
||||
}
|
||||
}
|
37
database/migrations/2021_11_08_131308_onboarding.php
Normal file
37
database/migrations/2021_11_08_131308_onboarding.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class Onboarding extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
|
||||
if (!Schema::hasColumn('accounts', 'is_onboarding'))
|
||||
{
|
||||
|
||||
Schema::table('accounts', function (Blueprint $table) {
|
||||
$table->boolean('is_onboarding')->default(false);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (!Schema::hasColumn('accounts', 'onboarding'))
|
||||
{
|
||||
|
||||
Schema::table('accounts', function (Blueprint $table) {
|
||||
$table->mediumText('onboarding')->nullable();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddIsMigrateColumnToAccountsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('accounts', function (Blueprint $table) {
|
||||
$table->boolean('is_migrated')->default(false);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('accounts', function (Blueprint $table) {
|
||||
//
|
||||
});
|
||||
}
|
||||
}
|
663
package-lock.json
generated
663
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -7207,31 +7207,6 @@ 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.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
flutter_share
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 Lucas Britto
|
||||
|
||||
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.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
flutter_slidable
|
||||
|
||||
|
8
public/flutter_service_worker.js
vendored
8
public/flutter_service_worker.js
vendored
@ -6,12 +6,12 @@ const RESOURCES = {
|
||||
"icons/Icon-512.png": "0f9aff01367f0a0c69773d25ca16ef35",
|
||||
"icons/Icon-192.png": "bb1cf5f6982006952211c7c8404ffbed",
|
||||
"favicon.png": "dca91c54388f52eded692718d5a98b8b",
|
||||
"/": "542e2d73b9cfe7a3d5174afa95366cc3",
|
||||
"/": "1c5f475f85b7fcd619029ee7f07d9d02",
|
||||
"manifest.json": "ef43d90e57aa7682d7e2cfba2f484a40",
|
||||
"favicon.ico": "51636d3a390451561744c42188ccd628",
|
||||
"version.json": "6d65f0d3d61870372cdbb5f485e4da00",
|
||||
"version.json": "9c7b0edc83733da56c726678aacd9fd3",
|
||||
"assets/fonts/MaterialIcons-Regular.otf": "4e6447691c9509f7acdbf8a931a85ca1",
|
||||
"assets/NOTICES": "9eb7e2eb2888ea5bae5f536720db37cd",
|
||||
"assets/NOTICES": "7610cf8f301427a1104669ea3f4074ac",
|
||||
"assets/packages/material_design_icons_flutter/lib/fonts/materialdesignicons-webfont.ttf": "174c02fc4609e8fc4389f5d21f16a296",
|
||||
"assets/FontManifest.json": "cf3c681641169319e61b61bd0277378f",
|
||||
"assets/assets/images/payment_types/paypal.png": "8e06c094c1871376dfea1da8088c29d1",
|
||||
@ -34,7 +34,7 @@ const RESOURCES = {
|
||||
"assets/assets/images/google_logo.png": "0f118259ce403274f407f5e982e681c3",
|
||||
"assets/assets/images/logo_light.png": "e5f46d5a78e226e7a9553d4ca6f69219",
|
||||
"assets/AssetManifest.json": "38d9aea341601f3a5c6fa7b5a1216ea5",
|
||||
"main.dart.js": "9ce1905069f75f930622606502e06e31"
|
||||
"main.dart.js": "97d45d9acc730c1517f80cecf1a90511"
|
||||
};
|
||||
|
||||
// The application shell files that are downloaded before a service worker can
|
||||
|
2
public/js/app.js
vendored
2
public/js/app.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/clients/invoices/payment.js
vendored
2
public/js/clients/invoices/payment.js
vendored
@ -1,2 +1,2 @@
|
||||
/*! For license information please see payment.js.LICENSE.txt */
|
||||
(()=>{function e(e,t){for(var n=0;n<t.length;n++){var a=t[n];a.enumerable=a.enumerable||!1,a.configurable=!0,"value"in a&&(a.writable=!0),Object.defineProperty(e,a.key,a)}}var t=function(){function t(e,n){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,t),this.shouldDisplayTerms=e,this.shouldDisplaySignature=n,this.termsAccepted=!1}var n,a,i;return n=t,(a=[{key:"handleMethodSelect",value:function(e){var t=this;document.getElementById("company_gateway_id").value=e.dataset.companyGatewayId,document.getElementById("payment_method_id").value=e.dataset.gatewayTypeId,this.shouldDisplaySignature&&!this.shouldDisplayTerms&&(this.displayTerms(),document.getElementById("accept-terms-button").addEventListener("click",(function(){t.termsAccepted=!0,t.submitForm()}))),!this.shouldDisplaySignature&&this.shouldDisplayTerms&&(this.displaySignature(),document.getElementById("signature-next-step").addEventListener("click",(function(){document.querySelector('input[name="signature"').value=t.signaturePad.toDataURL(),t.submitForm()}))),this.shouldDisplaySignature&&this.shouldDisplayTerms&&(this.displaySignature(),document.getElementById("signature-next-step").addEventListener("click",(function(){t.displayTerms(),document.getElementById("accept-terms-button").addEventListener("click",(function(){document.querySelector('input[name="signature"').value=t.signaturePad.toDataURL(),t.termsAccepted=!0,t.submitForm()}))}))),this.shouldDisplaySignature||this.shouldDisplayTerms||this.submitForm()}},{key:"submitForm",value:function(){document.getElementById("payment-form").submit()}},{key:"displayTerms",value:function(){document.getElementById("displayTermsModal").removeAttribute("style")}},{key:"displaySignature",value:function(){document.getElementById("displaySignatureModal").removeAttribute("style");var e=new SignaturePad(document.getElementById("signature-pad"),{penColor:"rgb(0, 0, 0)"});this.signaturePad=e}},{key:"handle",value:function(){var e=this;document.querySelectorAll(".dropdown-gateway-button").forEach((function(t){t.addEventListener("click",(function(){return e.handleMethodSelect(t)}))}))}}])&&e(n.prototype,a),i&&e(n,i),t}(),n=document.querySelector('meta[name="require-invoice-signature"]').content,a=document.querySelector('meta[name="show-invoice-terms"]').content;new t(Boolean(+n),Boolean(+a)).handle()})();
|
||||
(()=>{function e(e,t){for(var n=0;n<t.length;n++){var a=t[n];a.enumerable=a.enumerable||!1,a.configurable=!0,"value"in a&&(a.writable=!0),Object.defineProperty(e,a.key,a)}}var t=function(){function t(e,n){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,t),this.shouldDisplayTerms=e,this.shouldDisplaySignature=n,this.termsAccepted=!1,this.submitting=!1}var n,a,i;return n=t,(a=[{key:"handleMethodSelect",value:function(e){var t=this;document.getElementById("company_gateway_id").value=e.dataset.companyGatewayId,document.getElementById("payment_method_id").value=e.dataset.gatewayTypeId,this.shouldDisplaySignature&&!this.shouldDisplayTerms&&(this.displayTerms(),document.getElementById("accept-terms-button").addEventListener("click",(function(){t.termsAccepted=!0,t.submitForm()}))),!this.shouldDisplaySignature&&this.shouldDisplayTerms&&(this.displaySignature(),document.getElementById("signature-next-step").addEventListener("click",(function(){document.querySelector('input[name="signature"').value=t.signaturePad.toDataURL(),t.submitForm()}))),this.shouldDisplaySignature&&this.shouldDisplayTerms&&(this.displaySignature(),document.getElementById("signature-next-step").addEventListener("click",(function(){t.displayTerms(),document.getElementById("accept-terms-button").addEventListener("click",(function(){document.querySelector('input[name="signature"').value=t.signaturePad.toDataURL(),t.termsAccepted=!0,t.submitForm()}))}))),this.shouldDisplaySignature||this.shouldDisplayTerms||this.submitForm()}},{key:"submitForm",value:function(){document.getElementById("payment-form").submit()}},{key:"displayTerms",value:function(){document.getElementById("displayTermsModal").removeAttribute("style")}},{key:"displaySignature",value:function(){document.getElementById("displaySignatureModal").removeAttribute("style");var e=new SignaturePad(document.getElementById("signature-pad"),{penColor:"rgb(0, 0, 0)"});this.signaturePad=e}},{key:"handle",value:function(){var e=this;document.querySelectorAll(".dropdown-gateway-button").forEach((function(t){t.addEventListener("click",(function(){e.submitting||(e.handleMethodSelect(t),e.submitting=!0)}))}))}}])&&e(n.prototype,a),i&&e(n,i),t}(),n=document.querySelector('meta[name="require-invoice-signature"]').content,a=document.querySelector('meta[name="show-invoice-terms"]').content;new t(Boolean(+n),Boolean(+a)).handle()})();
|
2
public/js/clients/linkify-urls.js
vendored
2
public/js/clients/linkify-urls.js
vendored
@ -1 +1 @@
|
||||
(()=>{var e,t={8945:(e,t,r)=>{"use strict";const a=r(920),n=r(3523),s=r(2263),o=new Set(n);e.exports=e=>{if((e=Object.assign({name:"div",attributes:{},html:""},e)).html&&e.text)throw new Error("The `html` and `text` options are mutually exclusive");const t=e.text?s.escape(e.text):e.html;let r=`<${e.name}${a(e.attributes)}>`;return o.has(e.name)||(r+=`${t}</${e.name}>`),r}},3523:(e,t,r)=>{"use strict";e.exports=r(8346)},2263:(e,t)=>{"use strict";t.escape=e=>e.replace(/&/g,"&").replace(/"/g,""").replace(/'/g,"'").replace(/</g,"<").replace(/>/g,">"),t.unescape=e=>e.replace(/>/g,">").replace(/</g,"<").replace(/'/g,"'").replace(/"/g,'"').replace(/&/g,"&"),t.escapeTag=function(e){let r=e[0];for(let a=1;a<arguments.length;a++)r=r+t.escape(arguments[a])+e[a];return r},t.unescapeTag=function(e){let r=e[0];for(let a=1;a<arguments.length;a++)r=r+t.unescape(arguments[a])+e[a];return r}},1881:(e,t,r)=>{"use strict";const a=r(8945),n=(e,t)=>a({name:"a",attributes:{href:"",...t.attributes,href:e},text:void 0===t.value?e:void 0,html:void 0===t.value?void 0:"function"==typeof t.value?t.value(e):t.value});e.exports=(e,t)=>{if("string"===(t={attributes:{},type:"string",...t}).type)return((e,t)=>e.replace(/((?<!\+)(?:https?(?::\/\/))(?:www\.)?(?:[a-zA-Z\d-_.]+(?:(?:\.|@)[a-zA-Z\d]{2,})|localhost)(?:(?:[-a-zA-Z\d:%_+.~#*$!?&//=@]*)(?:[,](?![\s]))*)*)/g,(e=>n(e,t))))(e,t);if("dom"===t.type)return((e,t)=>{const r=document.createDocumentFragment();for(const[s,o]of Object.entries(e.split(/((?<!\+)(?:https?(?::\/\/))(?:www\.)?(?:[a-zA-Z\d-_.]+(?:(?:\.|@)[a-zA-Z\d]{2,})|localhost)(?:(?:[-a-zA-Z\d:%_+.~#*$!?&//=@]*)(?:[,](?![\s]))*)*)/g)))s%2?r.append((a=n(o,t),document.createRange().createContextualFragment(a))):o.length>0&&r.append(o);var a;return r})(e,t);throw new Error("The type option must be either `dom` or `string`")}},920:(e,t,r)=>{"use strict";const a=r(2263);e.exports=e=>{const t=[];for(const r of Object.keys(e)){let n=e[r];if(!1===n)continue;Array.isArray(n)&&(n=n.join(" "));let s=a.escape(r);!0!==n&&(s+=`="${a.escape(String(n))}"`),t.push(s)}return t.length>0?" "+t.join(" "):""}},8346:e=>{"use strict";e.exports=JSON.parse('["area","base","br","col","embed","hr","img","input","link","menuitem","meta","param","source","track","wbr"]')}},r={};function a(e){var n=r[e];if(void 0!==n)return n.exports;var s=r[e]={exports:{}};return t[e](s,s.exports,a),s.exports}e=a(1881),document.querySelectorAll("[data-ref=entity-terms]").forEach((function(t){t.innerHTML=e(t.innerText,{attributes:{target:"_blank",class:"text-primary"}})}))})();
|
||||
(()=>{var e,t={2623:(e,t,r)=>{"use strict";e.exports=r(4666)},1886:(e,t)=>{"use strict";const r=e=>e.replace(/&/g,"&").replace(/"/g,""").replace(/'/g,"'").replace(/</g,"<").replace(/>/g,">"),n=e=>e.replace(/>/g,">").replace(/</g,"<").replace(/�?39;/g,"'").replace(/"/g,'"').replace(/&/g,"&");t.T=(e,...t)=>{if("string"==typeof e)return r(e);let n=e[0];for(const[o,a]of t.entries())n=n+r(String(a))+e[o+1];return n}},7636:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>s});var n=r(1886);var o=r(2623);const a=e=>e.replace(/&/g,"&").replace(/"/g,""").replace(/'/g,"'").replace(/</g,"<").replace(/>/g,">");const i=new Set(o);function c({name:e="div",attributes:t={},html:r="",text:o}={}){if(r&&o)throw new Error("The `html` and `text` options are mutually exclusive");const c=o?function(e,...t){if("string"==typeof e)return a(e);let r=e[0];for(const[n,o]of t.entries())r=r+a(String(o))+e[n+1];return r}(o):r;let l=`<${e}${function(e){const t=[];for(let[r,o]of Object.entries(e)){if(!1===o)continue;Array.isArray(o)&&(o=o.join(" "));let e=(0,n.T)(r);!0!==o&&(e+=`="${(0,n.T)(String(o))}"`),t.push(e)}return t.length>0?" "+t.join(" "):""}(t)}>`;return i.has(e)||(l+=`${c}</${e}>`),l}const l=(e,t)=>c({name:"a",attributes:{href:"",...t.attributes,href:e},text:void 0===t.value?e:void 0,html:void 0===t.value?void 0:"function"==typeof t.value?t.value(e):t.value});function s(e,t){if("string"===(t={attributes:{},type:"string",...t}).type)return((e,t)=>e.replace(/((?<!\+)https?:\/\/(?:www\.)?(?:[-\w.]+?[.@][a-zA-Z\d]{2,}|localhost)(?:[-\w.:%+~#*$!?&/=@]*?(?:,(?!\s))*?)*)/g,(e=>l(e,t))))(e,t);if("dom"===t.type)return((e,t)=>{const r=document.createDocumentFragment();for(const[o,a]of Object.entries(e.split(/((?<!\+)https?:\/\/(?:www\.)?(?:[-\w.]+?[.@][a-zA-Z\d]{2,}|localhost)(?:[-\w.:%+~#*$!?&/=@]*?(?:,(?!\s))*?)*)/g)))o%2?r.append((n=l(a,t),document.createRange().createContextualFragment(n))):a.length>0&&r.append(a);var n;return r})(e,t);throw new TypeError("The type option must be either `dom` or `string`")}},4666:e=>{"use strict";e.exports=JSON.parse('["area","base","br","col","embed","hr","img","input","link","menuitem","meta","param","source","track","wbr"]')}},r={};function n(e){var o=r[e];if(void 0!==o)return o.exports;var a=r[e]={exports:{}};return t[e](a,a.exports,n),a.exports}n.d=(e,t)=>{for(var r in t)n.o(t,r)&&!n.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},e=n(7636),document.querySelectorAll("[data-ref=entity-terms]").forEach((function(t){t.innerHTML=e(t.innerText,{attributes:{target:"_blank",class:"text-primary"}})}))})();
|
@ -1,2 +1,2 @@
|
||||
/*! For license information please see wepay-bank-account.js.LICENSE.txt */
|
||||
(()=>{function e(e,n){for(var t=0;t<n.length;t++){var o=n[t];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(e,o.key,o)}}var n=function(){function n(){!function(e,n){if(!(e instanceof n))throw new TypeError("Cannot call a class as a function")}(this,n)}var t,o,r;return t=n,(o=[{key:"initializeWePay",value:function(){var e,n=null===(e=document.querySelector('meta[name="wepay-environment"]'))||void 0===e?void 0:e.content;return WePay.set_endpoint("staging"===n?"stage":"production"),this}},{key:"showBankPopup",value:function(){var e,n;WePay.bank_account.create({client_id:null===(e=document.querySelector("meta[name=wepay-client-id]"))||void 0===e?void 0:e.content,email:null===(n=document.querySelector("meta[name=contact-email]"))||void 0===n?void 0:n.content},(function(e){e.error?(errors.textContent="",errors.textContent=e.error_description,errors.hidden=!1):(document.querySelector('input[name="bank_account_id"]').value=e.bank_account_id,document.getElementById("server_response").submit())}),(function(e){e.error&&(errors.textContent="",errors.textContent=e.error_description,errors.hidden=!1)}))}},{key:"handle",value:function(){this.initializeWePay().showBankPopup()}}])&&e(t.prototype,o),r&&e(t,r),n}();document.addEventListener("DOMContentLoaded",(function(){(new n).handle()}))})();
|
||||
(()=>{function e(e,n){for(var t=0;t<n.length;t++){var o=n[t];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(e,o.key,o)}}var n=function(){function n(){!function(e,n){if(!(e instanceof n))throw new TypeError("Cannot call a class as a function")}(this,n)}var t,o,r;return t=n,(o=[{key:"initializeWePay",value:function(){var e,n=null===(e=document.querySelector('meta[name="wepay-environment"]'))||void 0===e?void 0:e.content;return WePay.set_endpoint("staging"===n?"stage":"production"),this}},{key:"showBankPopup",value:function(){var e,n;WePay.bank_account.create({client_id:null===(e=document.querySelector("meta[name=wepay-client-id]"))||void 0===e?void 0:e.content,email:null===(n=document.querySelector("meta[name=contact-email]"))||void 0===n?void 0:n.content,options:{avoidMicrodeposits:!0}},(function(e){e.error?(errors.textContent="",errors.textContent=e.error_description,errors.hidden=!1):(document.querySelector('input[name="bank_account_id"]').value=e.bank_account_id,document.getElementById("server_response").submit())}),(function(e){e.error&&(errors.textContent="",errors.textContent=e.error_description,errors.hidden=!1)}))}},{key:"handle",value:function(){this.initializeWePay().showBankPopup()}}])&&e(t.prototype,o),r&&e(t,r),n}();document.addEventListener("DOMContentLoaded",(function(){(new n).handle()}))})();
|
2
public/js/setup/setup.js
vendored
2
public/js/setup/setup.js
vendored
File diff suppressed because one or more lines are too long
233641
public/main.dart.js
vendored
233641
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
245747
public/main.foss.dart.js
vendored
245747
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
226467
public/main.html.dart.js
vendored
226467
public/main.html.dart.js
vendored
File diff suppressed because one or more lines are too long
182566
public/main.next.dart.js
vendored
182566
public/main.next.dart.js
vendored
File diff suppressed because one or more lines are too long
10259
public/main.profile.dart.js
vendored
10259
public/main.profile.dart.js
vendored
File diff suppressed because one or more lines are too long
@ -1,25 +1,25 @@
|
||||
{
|
||||
"/js/app.js": "/js/app.js?id=0d1e02ebdcc97462d422",
|
||||
"/js/app.js": "/js/app.js?id=0e3959ab851d3350364d",
|
||||
"/js/clients/payment_methods/authorize-authorize-card.js": "/js/clients/payment_methods/authorize-authorize-card.js?id=de4468c682d6861847de",
|
||||
"/js/clients/payments/authorize-credit-card-payment.js": "/js/clients/payments/authorize-credit-card-payment.js?id=cfe5de1cf87a0b01568d",
|
||||
"/js/clients/payments/stripe-ach.js": "/js/clients/payments/stripe-ach.js?id=5e74bc0d346beeb57ee9",
|
||||
"/js/clients/invoices/action-selectors.js": "/js/clients/invoices/action-selectors.js?id=6b79265cbb8c963eef19",
|
||||
"/js/clients/invoices/payment.js": "/js/clients/invoices/payment.js?id=5b79f72432f92a85fefa",
|
||||
"/js/clients/invoices/payment.js": "/js/clients/invoices/payment.js?id=d9132fae12153a6943a6",
|
||||
"/js/clients/payments/stripe-sofort.js": "/js/clients/payments/stripe-sofort.js?id=926c7b9d1ee48bbf786b",
|
||||
"/js/clients/payments/stripe-alipay.js": "/js/clients/payments/stripe-alipay.js?id=1e159400d6a5ca4662c1",
|
||||
"/js/clients/payments/checkout-credit-card.js": "/js/clients/payments/checkout-credit-card.js?id=0b47ce36fe20191adb33",
|
||||
"/js/clients/quotes/action-selectors.js": "/js/clients/quotes/action-selectors.js?id=63f0688329be80ee8693",
|
||||
"/js/clients/quotes/approve.js": "/js/clients/quotes/approve.js?id=795d2f44cf3d117a554e",
|
||||
"/js/clients/payments/stripe-credit-card.js": "/js/clients/payments/stripe-credit-card.js?id=ea4250be693260798735",
|
||||
"/js/setup/setup.js": "/js/setup/setup.js?id=6b870beeb350d83668c5",
|
||||
"/js/setup/setup.js": "/js/setup/setup.js?id=7e19431f4cb9ad45e177",
|
||||
"/js/clients/payments/card-js.min.js": "/js/clients/payments/card-js.min.js?id=8ce33c3deae058ad314f",
|
||||
"/js/clients/shared/pdf.js": "/js/clients/shared/pdf.js?id=73a0d914ad3577f257f4",
|
||||
"/js/clients/shared/multiple-downloads.js": "/js/clients/shared/multiple-downloads.js?id=c2caa29f753ad1f3a12c",
|
||||
"/js/clients/linkify-urls.js": "/js/clients/linkify-urls.js?id=448d055fa1e8357130e6",
|
||||
"/js/clients/linkify-urls.js": "/js/clients/linkify-urls.js?id=44c51b4838d1f135bbe3",
|
||||
"/js/clients/payments/braintree-credit-card.js": "/js/clients/payments/braintree-credit-card.js?id=a334dd9257dd510a1feb",
|
||||
"/js/clients/payments/braintree-paypal.js": "/js/clients/payments/braintree-paypal.js?id=37950e8a39281d2f596a",
|
||||
"/js/clients/payments/wepay-credit-card.js": "/js/clients/payments/wepay-credit-card.js?id=ba4d5b7175117ababdb2",
|
||||
"/js/clients/payment_methods/wepay-bank-account.js": "/js/clients/payment_methods/wepay-bank-account.js?id=b1704cb9bd7975605310",
|
||||
"/js/clients/payment_methods/wepay-bank-account.js": "/js/clients/payment_methods/wepay-bank-account.js?id=8328c6c32a65cd3e8a3d",
|
||||
"/js/clients/payments/paytrace-credit-card.js": "/js/clients/payments/paytrace-credit-card.js?id=59d9913b746fe5a540ff",
|
||||
"/js/clients/payments/mollie-credit-card.js": "/js/clients/payments/mollie-credit-card.js?id=c2cf632fb3cc91b4ff7c",
|
||||
"/js/clients/payments/eway-credit-card.js": "/js/clients/payments/eway-credit-card.js?id=ff17e039dd15d505448f",
|
||||
|
@ -1 +1 @@
|
||||
{"app_name":"invoiceninja_flutter","version":"5.0.64","build_number":"64"}
|
||||
{"app_name":"invoiceninja_flutter","version":"5.0.67","build_number":"67"}
|
11
resources/js/clients/invoices/payment.js
vendored
11
resources/js/clients/invoices/payment.js
vendored
@ -13,6 +13,7 @@ class Payment {
|
||||
this.shouldDisplayTerms = displayTerms;
|
||||
this.shouldDisplaySignature = displaySignature;
|
||||
this.termsAccepted = false;
|
||||
this.submitting = false;
|
||||
}
|
||||
|
||||
handleMethodSelect(element) {
|
||||
@ -95,9 +96,13 @@ class Payment {
|
||||
document
|
||||
.querySelectorAll(".dropdown-gateway-button")
|
||||
.forEach(element => {
|
||||
element.addEventListener("click", () =>
|
||||
this.handleMethodSelect(element)
|
||||
);
|
||||
element.addEventListener("click", () => {
|
||||
if (!this.submitting) {
|
||||
this.handleMethodSelect(element)
|
||||
|
||||
this.submitting = true;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,10 @@ class WePayBank {
|
||||
showBankPopup() {
|
||||
WePay.bank_account.create({
|
||||
client_id: document.querySelector('meta[name=wepay-client-id]')?.content,
|
||||
email: document.querySelector('meta[name=contact-email]')?.content
|
||||
email: document.querySelector('meta[name=contact-email]')?.content,
|
||||
options: {
|
||||
avoidMicrodeposits:true
|
||||
}
|
||||
}, function (data) {
|
||||
if (data.error) {
|
||||
errors.textContent = '';
|
||||
|
@ -367,6 +367,9 @@
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
$entity_images
|
||||
|
||||
<div id="footer">
|
||||
<div>
|
||||
<p data-ref="total_table-footer">$entity_footer</p>
|
||||
|
@ -294,7 +294,7 @@
|
||||
/** To find out selectors on your own: https://invoiceninja.github.io/docs/custom-fields/#snippets **/
|
||||
</style>
|
||||
|
||||
<table>
|
||||
<table style="min-width: 100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<td>
|
||||
@ -347,6 +347,8 @@
|
||||
|
||||
<div class="repeating-header" id="header"></div>
|
||||
|
||||
$entity_images
|
||||
|
||||
<div class="repeating-footer" id="footer">
|
||||
<p data-ref="total_table-footer">$entity_footer</p>
|
||||
</div>
|
||||
|
@ -258,7 +258,7 @@
|
||||
/** To find out selectors on your own: https://invoiceninja.github.io/docs/custom-fields/#snippets **/
|
||||
</style>
|
||||
|
||||
<table>
|
||||
<table style="min-width: 100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<td>
|
||||
@ -309,6 +309,8 @@
|
||||
|
||||
<div class="repeating-header" id="header"></div>
|
||||
|
||||
$entity_images
|
||||
|
||||
<div class="repeating-footer" id="footer">
|
||||
<p data-ref="total_table-footer">$entity_footer</p>
|
||||
</div>
|
||||
|
@ -247,7 +247,7 @@
|
||||
/** To find out selectors on your own: https://invoiceninja.github.io/docs/custom-fields/#snippets **/
|
||||
</style>
|
||||
|
||||
<table>
|
||||
<table style="min-width: 100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<td>
|
||||
@ -307,6 +307,8 @@
|
||||
<p data-ref="total_table-footer">$entity_footer</p>
|
||||
</div>
|
||||
|
||||
$entity_images
|
||||
|
||||
<script>
|
||||
// Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present.
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
|
@ -317,6 +317,8 @@
|
||||
<p data-ref="total_table-footer">$entity_footer</p>
|
||||
</div>
|
||||
|
||||
$entity_images
|
||||
|
||||
<script>
|
||||
// Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present.
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
|
@ -272,7 +272,7 @@
|
||||
/** To find out selectors on your own: https://invoiceninja.github.io/docs/custom-fields/#snippets **/
|
||||
</style>
|
||||
|
||||
<table>
|
||||
<table style="min-width: 100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<td>
|
||||
@ -358,6 +358,8 @@
|
||||
<p data-ref="total_table-footer">$entity_footer</p>
|
||||
</div>
|
||||
|
||||
$entity_images
|
||||
|
||||
<script>
|
||||
// Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present.
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
|
@ -344,6 +344,8 @@
|
||||
</table>
|
||||
</div>
|
||||
|
||||
$entity_images
|
||||
|
||||
<div id="footer">
|
||||
<div class="footer-content">
|
||||
<div>
|
||||
|
@ -238,7 +238,7 @@
|
||||
/** To find out selectors on your own: https://invoiceninja.github.io/docs/custom-fields/#snippets **/
|
||||
</style>
|
||||
|
||||
<table>
|
||||
<table style="min-width: 100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<td>
|
||||
@ -292,6 +292,8 @@
|
||||
<p data-ref="total_table-footer">$entity_footer</p>
|
||||
</div>
|
||||
|
||||
$entity_images
|
||||
|
||||
<script>
|
||||
// Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present.
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
|
@ -375,7 +375,9 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="repeating-footer" id="footer">
|
||||
$entity_images
|
||||
|
||||
<div class="repeating-footer" id="footer">
|
||||
<p data-ref="total_table-footer">$entity_footer</p>
|
||||
|
||||
<div id="footer-colors">
|
||||
|
@ -357,6 +357,8 @@
|
||||
<p data-ref="total_table-footer">$entity_footer</p>
|
||||
</div>
|
||||
|
||||
$entity_images
|
||||
|
||||
<script>
|
||||
// Clear up space a bit, if [product-table, tasks-table, delivery-note-table] isn't present.
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
|
@ -1,23 +1,42 @@
|
||||
@if($entity->documents->count() > 0)
|
||||
@if ($entity->documents->count() > 0 || $entity->company->documents->count() > 0)
|
||||
<div class="bg-white shadow sm:rounded-lg my-4">
|
||||
<div class="px-4 py-5 sm:p-6">
|
||||
<div class="sm:flex sm:items-start sm:justify-between">
|
||||
<div>
|
||||
<p class="text-lg leading-6 font-medium text-gray-900">{{ ctrans('texts.attachments') }}:</p>
|
||||
@foreach($entity->documents as $document)
|
||||
@foreach ($entity->documents as $document)
|
||||
<div class="inline-flex items-center space-x-1">
|
||||
<a href="{{ route('client.documents.show', $document->hashed_id) }}" target="_blank"
|
||||
class="block text-sm button-link text-primary">{{ Illuminate\Support\Str::limit($document->name, 40) }}</a>
|
||||
class="block text-sm button-link text-primary">{{ Illuminate\Support\Str::limit($document->name, 40) }}</a>
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"
|
||||
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
||||
stroke-linejoin="round" class="text-primary h-6 w-4">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
|
||||
class="text-primary h-6 w-4">
|
||||
<path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>
|
||||
<polyline points="15 3 21 3 21 9"></polyline>
|
||||
<line x1="10" y1="14" x2="21" y2="3"></line>
|
||||
</svg>
|
||||
|
||||
@if(!$loop->last)
|
||||
@if (!$loop->last)
|
||||
<span>—</span>
|
||||
@endif
|
||||
</div>
|
||||
@endforeach
|
||||
|
||||
@foreach ($entity->company->documents as $document)
|
||||
<div class="inline-flex items-center space-x-1">
|
||||
<a href="{{ route('client.documents.show', $document->hashed_id) }}" target="_blank"
|
||||
class="block text-sm button-link text-primary">{{ Illuminate\Support\Str::limit($document->name, 40) }}</a>
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
|
||||
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
|
||||
class="text-primary h-6 w-4">
|
||||
<path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>
|
||||
<polyline points="15 3 21 3 21 9"></polyline>
|
||||
<line x1="10" y1="14" x2="21" y2="3"></line>
|
||||
</svg>
|
||||
|
||||
@if (!$loop->last)
|
||||
<span>—</span>
|
||||
@endif
|
||||
</div>
|
||||
|
@ -64,7 +64,7 @@
|
||||
<option>15</option>
|
||||
<option>20</option>
|
||||
</select>
|
||||
<button x-on:click="document.getElementById('multiple-downloads').submit()" class="button button-primary bg-primary py-2 ml-2">
|
||||
<button onclick="document.getElementById('multiple-downloads').submit(); setTimeout(() => this.disabled = true, 0); setTimeout(() => this.disabled = false, 5000);" class="button button-primary bg-primary py-2 ml-2">
|
||||
<span class="hidden md:block">
|
||||
{{ ctrans('texts.download_selected') }}
|
||||
</span>
|
||||
|
@ -99,7 +99,7 @@
|
||||
@csrf
|
||||
<input type="hidden" name="invoices[]" value="{{ $invoice->hashed_id }}">
|
||||
<input type="hidden" name="action" value="payment">
|
||||
<button class="px-2 py-1 mr-3 text-xs uppercase button button-primary bg-primary" dusk="pay-now">
|
||||
<button onclick="setTimeout(() => this.disabled = true, 0); return true;" class="px-2 py-1 mr-3 text-xs uppercase button button-primary bg-primary" dusk="pay-now">
|
||||
{{ ctrans('texts.pay_now') }}
|
||||
</button>
|
||||
</form>
|
||||
|
@ -61,7 +61,7 @@
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@elseif($amount < 0)
|
||||
@elseif($amount <= 0)
|
||||
<div class="relative flex justify-center text-sm leading-5">
|
||||
<h1 class="text-2xl font-bold tracking-wide bg-gray-100 px-6 py-0">
|
||||
{{ ctrans('texts.total') }}: {{ \App\Utils\Number::formatMoney($amount, $subscription->company) }}
|
||||
|
@ -15,10 +15,10 @@
|
||||
<div class="flex items-center">
|
||||
<form action="{{ route('client.invoices.bulk') }}" method="post" id="bulkActions">
|
||||
@csrf
|
||||
<button type="submit" class="button button-primary bg-primary" name="action" value="download">{{ ctrans('texts.download') }}</button>
|
||||
<button type="submit" onclick="setTimeout(() => this.disabled = true, 0); setTimeout(() => this.disabled = false, 5000); return true;" class="button button-primary bg-primary" name="action" value="download">{{ ctrans('texts.download') }}</button>
|
||||
|
||||
@if(!empty(auth()->user()->client->service()->getPaymentMethods(0)))
|
||||
<button type="submit" class="button button-primary bg-primary" name="action" value="payment">{{ ctrans('texts.pay_now') }}</button>
|
||||
<button onclick="setTimeout(() => this.disabled = true, 0); return true;" type="submit" class="button button-primary bg-primary" name="action" value="payment">{{ ctrans('texts.pay_now') }}</button>
|
||||
@endif
|
||||
</form>
|
||||
</div>
|
||||
|
@ -36,7 +36,7 @@
|
||||
<form action="{{ route('client.payment_methods.destroy', [$payment_method->hashed_id, 'method' => $payment_method->gateway_type->id]) }}" method="post">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<button type="submit" class="button button-danger button-block" dusk="confirm-payment-removal">
|
||||
<button type="submit" onclick="setTimeout(() => this.disabled = true, 0); return true;" class="button button-danger button-block" dusk="confirm-payment-removal">
|
||||
{{ ctrans('texts.remove') }}
|
||||
</button>
|
||||
</form>
|
||||
|
@ -26,7 +26,7 @@
|
||||
<div class="relative inline-block text-left">
|
||||
<div>
|
||||
<div class="rounded-md shadow-sm">
|
||||
<button type="button" id="approve-button"
|
||||
<button type="button" id="approve-button" onclick="setTimeout(() => this.disabled = true, 0); return true;"
|
||||
class="inline-flex justify-center w-full rounded-md border border-gray-300 px-4 py-2 bg-white text-sm leading-5 font-medium text-gray-700 hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:ring-blue active:bg-gray-50 active:text-gray-800 transition ease-in-out duration-150">
|
||||
{{ ctrans('texts.approve') }}
|
||||
</button>
|
||||
|
@ -1,27 +1,30 @@
|
||||
<form action="{{ route('client.quotes.bulk') }}" method="post" id="approve-form" />
|
||||
@csrf
|
||||
<input type="hidden" name="action" value="approve">
|
||||
<input type="hidden" name="process" value="true">
|
||||
<input type="hidden" name="quotes[]" value="{{ $quote->hashed_id }}">
|
||||
<input type="hidden" name="signature">
|
||||
@csrf
|
||||
|
||||
<div class="bg-white shadow sm:rounded-lg">
|
||||
<div class="px-4 py-5 sm:p-6">
|
||||
<div class="sm:flex sm:items-start sm:justify-between">
|
||||
<h3 class="text-lg leading-6 font-medium text-gray-900">
|
||||
{{ ctrans('texts.approve') }}
|
||||
</h3>
|
||||
<input type="hidden" name="action" value="approve">
|
||||
<input type="hidden" name="process" value="true">
|
||||
<input type="hidden" name="quotes[]" value="{{ $quote->hashed_id }}">
|
||||
<input type="hidden" name="signature">
|
||||
|
||||
<div class="mt-5 sm:mt-0 sm:ml-6 sm:flex-shrink-0 sm:flex sm:items-center">
|
||||
@yield('quote-not-approved-right-side')
|
||||
<div class="bg-white shadow sm:rounded-lg">
|
||||
<div class="px-4 py-5 sm:p-6">
|
||||
<div class="sm:flex sm:items-start sm:justify-between">
|
||||
<h3 class="text-lg leading-6 font-medium text-gray-900">
|
||||
{{ ctrans('texts.approve') }}
|
||||
</h3>
|
||||
|
||||
<div class="inline-flex rounded-md shadow-sm">
|
||||
<input type="hidden" name="action" value="payment">
|
||||
<button type="button" class="button button-primary bg-primary" id="approve-button">{{ ctrans('texts.approve') }}</button>
|
||||
</div>
|
||||
<div class="mt-5 sm:mt-0 sm:ml-6 sm:flex-shrink-0 sm:flex sm:items-center">
|
||||
@yield('quote-not-approved-right-side')
|
||||
|
||||
<div class="inline-flex rounded-md shadow-sm">
|
||||
<input type="hidden" name="action" value="payment">
|
||||
<button onclick="setTimeout(() => this.disabled = true, 0); return true;" type="button"
|
||||
class="button button-primary bg-primary"
|
||||
id="approve-button">{{ ctrans('texts.approve') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
@ -2,9 +2,9 @@
|
||||
@section('meta_title', ctrans('texts.quotes'))
|
||||
|
||||
@section('header')
|
||||
@if($errors->any())
|
||||
@if ($errors->any())
|
||||
<div class="alert alert-failure mb-4">
|
||||
@foreach($errors->all() as $error)
|
||||
@foreach ($errors->all() as $error)
|
||||
<p>{{ $error }}</p>
|
||||
@endforeach
|
||||
</div>
|
||||
@ -15,13 +15,17 @@
|
||||
<div class="flex justify-between items-center">
|
||||
<form action="{{ route('client.quotes.bulk') }}" method="post" id="bulkActions">
|
||||
@csrf
|
||||
<button type="submit" class="button button-primary bg-primary" name="action"
|
||||
value="download">{{ ctrans('texts.download') }}</button>
|
||||
<button type="submit" class="button button-primary bg-primary" name="action"
|
||||
value="approve">{{ ctrans('texts.approve') }}</button>
|
||||
<button type="submit"
|
||||
onclick="setTimeout(() => this.disabled = true, 0); setTimeout(() => this.disabled = false, 5000); return true;"
|
||||
class="button button-primary bg-primary" name="action"
|
||||
value="download">{{ ctrans('texts.download') }}</button>
|
||||
<button type="submit" onclick="setTimeout(() => this.disabled = true, 0); return true;"
|
||||
class="button button-primary bg-primary" name="action"
|
||||
value="approve">{{ ctrans('texts.approve') }}</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col mt-4">
|
||||
@livewire('quotes-table', ['company' => $company])
|
||||
</div>
|
||||
@endsection
|
||||
@endsection
|
||||
|
@ -31,7 +31,7 @@
|
||||
<span class="ml-2">{{ ctrans('texts.show_aging') }}</span>
|
||||
</label> <!-- End show aging checkbox -->
|
||||
</div>
|
||||
<button id="pdf-download" class="button button-primary bg-primary mt-4 md:mt-0">{{ ctrans('texts.download') }}</button>
|
||||
<button onclick="setTimeout(() => this.disabled = true, 0); setTimeout(() => this.disabled = false, 5000); return true;" id="pdf-download" class="button button-primary bg-primary mt-4 md:mt-0">{{ ctrans('texts.download') }}</button>
|
||||
</div>
|
||||
|
||||
@include('portal.ninja2020.components.pdf-viewer', ['url' => route('client.statement.raw')])
|
||||
|
@ -297,6 +297,8 @@ class ClientTest extends TestCase
|
||||
$company_token->account_id = $account->id;
|
||||
$company_token->name = $user->first_name.' '.$user->last_name;
|
||||
$company_token->token = Str::random(64);
|
||||
$company_token->is_system = true;
|
||||
|
||||
$company_token->save();
|
||||
|
||||
$this->token = $company_token->token;
|
||||
@ -353,6 +355,7 @@ class ClientTest extends TestCase
|
||||
$company_token->account_id = $account->id;
|
||||
$company_token->name = $user->first_name.' '.$user->last_name;
|
||||
$company_token->token = Str::random(64);
|
||||
$company_token->is_system = true;
|
||||
$company_token->save();
|
||||
|
||||
$this->token = $company_token->token;
|
||||
|
@ -160,6 +160,7 @@ class LoginTest extends TestCase
|
||||
$company_token->account_id = $account->id;
|
||||
$company_token->name = $user->first_name.' '.$user->last_name;
|
||||
$company_token->token = \Illuminate\Support\Str::random(64);
|
||||
$company_token->is_system = true;
|
||||
$company_token->save();
|
||||
|
||||
$user->companies()->attach($company->id, [
|
||||
|
@ -167,6 +167,7 @@ class UserTest extends TestCase
|
||||
$company_token->account_id = $this->account->id;
|
||||
$company_token->name = 'test token';
|
||||
$company_token->token = \Illuminate\Support\Str::random(64);
|
||||
$company_token->is_system = true;
|
||||
$company_token->save();
|
||||
|
||||
/*Manually link this user to the company*/
|
||||
|
@ -128,6 +128,7 @@ class CompanyLedgerTest extends TestCase
|
||||
$company_token->account_id = $this->account->id;
|
||||
$company_token->name = 'test token';
|
||||
$company_token->token = $this->token;
|
||||
$company_token->is_system = true;
|
||||
$company_token->save();
|
||||
|
||||
$this->client = Client::factory()->create([
|
||||
|
45
tests/Unit/WithTypeHelpersTest.php
Normal file
45
tests/Unit/WithTypeHelpersTest.php
Normal file
@ -0,0 +1,45 @@
|
||||
<?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 Tests\Unit;
|
||||
|
||||
use App\Models\Account;
|
||||
use App\Models\Company;
|
||||
use App\Models\Document;
|
||||
use Tests\TestCase;
|
||||
|
||||
class WithTypeHelpersTest extends TestCase
|
||||
{
|
||||
public function testIsImageHelper(): void
|
||||
{
|
||||
$account = Account::factory()->create();
|
||||
|
||||
$company = Company::factory()->create([
|
||||
'account_id' => $account->id,
|
||||
]);
|
||||
|
||||
/** @var Document */
|
||||
$document = Document::factory()->create([
|
||||
'company_id' => $company->id,
|
||||
'type' => 'jpeg',
|
||||
]);
|
||||
|
||||
$this->assertTrue($document->isImage());
|
||||
|
||||
/** @var Document */
|
||||
$document = Document::factory()->create([
|
||||
'company_id' => $company->id,
|
||||
]);
|
||||
|
||||
$this->assertFalse($document->isImage());
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user