mirror of
				https://github.com/invoiceninja/invoiceninja.git
				synced 2025-11-04 02:27:29 -05:00 
			
		
		
		
	
						commit
						0fc7a27cf4
					
				@ -1 +1 @@
 | 
			
		||||
5.10.26
 | 
			
		||||
5.10.27
 | 
			
		||||
@ -140,7 +140,7 @@ class EmailTemplateDefaults
 | 
			
		||||
 | 
			
		||||
    public static function emailPaymentFailedTemplate()
 | 
			
		||||
    {
 | 
			
		||||
        return '<p>$client<br><br>'.ctrans('texts.client_payment_failure_body', ['invoice' => '$number', 'amount' => '$amount']).'</p><div class="center">$gateway_payment_error</div><br><div class="center">$payment_button</div>';
 | 
			
		||||
        return '<p>$client<br><br>'.ctrans('texts.client_payment_failure_body', ['invoice' => '$number', 'amount' => '$amount']).'</p><div>$payment_error</div><br><div>$payment_button</div>';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function emailQuoteReminder1Subject()
 | 
			
		||||
@ -151,7 +151,7 @@ class EmailTemplateDefaults
 | 
			
		||||
    public static function emailQuoteReminder1Body()
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
        return '<p>$client<br><br>'.self::transformText('quote_reminder_message').'</p><div class="center">$view_button</div>';
 | 
			
		||||
        return '<p>$client<br><br>'.self::transformText('quote_reminder_message').'</p><div>$view_button</div>';
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -177,14 +177,14 @@ class EmailTemplateDefaults
 | 
			
		||||
 | 
			
		||||
    public static function emailInvoiceTemplate()
 | 
			
		||||
    {
 | 
			
		||||
        $invoice_message = '<p>$client<br><br>'.self::transformText('invoice_message').'</p><div class="center">$view_button</div>';
 | 
			
		||||
        $invoice_message = '<p>$client<br><br>'.self::transformText('invoice_message').'</p><div>$view_button</div>';
 | 
			
		||||
 | 
			
		||||
        return $invoice_message;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function emailInvoiceReminderTemplate()
 | 
			
		||||
    {
 | 
			
		||||
        $invoice_message = '<p>$client<br><br>'.self::transformText('reminder_message').'</p><div class="center">$view_button</div>';
 | 
			
		||||
        $invoice_message = '<p>$client<br><br>'.self::transformText('reminder_message').'</p><div>$view_button</div>';
 | 
			
		||||
 | 
			
		||||
        return $invoice_message;
 | 
			
		||||
    }
 | 
			
		||||
@ -196,7 +196,7 @@ class EmailTemplateDefaults
 | 
			
		||||
 | 
			
		||||
    public static function emailQuoteTemplate()
 | 
			
		||||
    {
 | 
			
		||||
        $quote_message = '<p>$client<br><br>'.self::transformText('quote_message').'</p><div class="center">$view_button</div>';
 | 
			
		||||
        $quote_message = '<p>$client<br><br>'.self::transformText('quote_message').'</p><div>$view_button</div>';
 | 
			
		||||
 | 
			
		||||
        return $quote_message;
 | 
			
		||||
    }
 | 
			
		||||
@ -213,28 +213,28 @@ class EmailTemplateDefaults
 | 
			
		||||
 | 
			
		||||
    public static function emailPurchaseOrderTemplate()
 | 
			
		||||
    {
 | 
			
		||||
        $purchase_order_message = '<p>$vendor<br><br>'.self::transformText('purchase_order_message').'</p><div class="center">$view_button</div>';
 | 
			
		||||
        $purchase_order_message = '<p>$vendor<br><br>'.self::transformText('purchase_order_message').'</p><div>$view_button</div>';
 | 
			
		||||
 | 
			
		||||
        return $purchase_order_message;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function emailPaymentTemplate()
 | 
			
		||||
    {
 | 
			
		||||
        $payment_message = '<p>$client<br><br>'.self::transformText('payment_message').'<br><br>$invoices</p><div class="center">$view_button</div>';
 | 
			
		||||
        $payment_message = '<p>$client<br><br>'.self::transformText('payment_message').'<br><br>$invoices</p><div>$view_button</div>';
 | 
			
		||||
 | 
			
		||||
        return $payment_message;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function emailCreditTemplate()
 | 
			
		||||
    {
 | 
			
		||||
        $credit_message = '<p>$client<br><br>'.self::transformText('credit_message').'</p><div class="center">$view_button</div>';
 | 
			
		||||
        $credit_message = '<p>$client<br><br>'.self::transformText('credit_message').'</p><div>$view_button</div>';
 | 
			
		||||
 | 
			
		||||
        return $credit_message;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function emailPaymentPartialTemplate()
 | 
			
		||||
    {
 | 
			
		||||
        $payment_message = '<p>$client<br><br>'.self::transformText('payment_message').'<br><br>$invoices</p><div class="center">$view_button</div>';
 | 
			
		||||
        $payment_message = '<p>$client<br><br>'.self::transformText('payment_message').'<br><br>$invoices</p><div>$view_button</div>';
 | 
			
		||||
 | 
			
		||||
        return $payment_message;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -266,58 +266,6 @@ class InvoiceFilters extends QueryFilters
 | 
			
		||||
        return $this->builder->where('due_date', '>=', $date);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Filter by date range
 | 
			
		||||
     *
 | 
			
		||||
     * @param string $date_range
 | 
			
		||||
     * @return Builder
 | 
			
		||||
     */
 | 
			
		||||
    public function date_range(string $date_range = ''): Builder
 | 
			
		||||
    {
 | 
			
		||||
        $parts = explode(",", $date_range);
 | 
			
		||||
 | 
			
		||||
        if (count($parts) != 2) {
 | 
			
		||||
            return $this->builder;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
 | 
			
		||||
            $start_date = Carbon::parse($parts[0]);
 | 
			
		||||
            $end_date = Carbon::parse($parts[1]);
 | 
			
		||||
 | 
			
		||||
            return $this->builder->whereBetween('date', [$start_date, $end_date]);
 | 
			
		||||
        } catch(\Exception $e) {
 | 
			
		||||
            return $this->builder;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Filter by due date range
 | 
			
		||||
     *
 | 
			
		||||
     * @param string $date_range
 | 
			
		||||
     * @return Builder
 | 
			
		||||
     */
 | 
			
		||||
    public function due_date_range(string $date_range = ''): Builder
 | 
			
		||||
    {
 | 
			
		||||
        $parts = explode(",", $date_range);
 | 
			
		||||
 | 
			
		||||
        if (count($parts) != 2) {
 | 
			
		||||
            return $this->builder;
 | 
			
		||||
        }
 | 
			
		||||
        try {
 | 
			
		||||
 | 
			
		||||
            $start_date = Carbon::parse($parts[0]);
 | 
			
		||||
            $end_date = Carbon::parse($parts[1]);
 | 
			
		||||
 | 
			
		||||
            return $this->builder->whereBetween('due_date', [$start_date, $end_date]);
 | 
			
		||||
        } catch(\Exception $e) {
 | 
			
		||||
            return $this->builder;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sorts the list based on $sort.
 | 
			
		||||
     *
 | 
			
		||||
 | 
			
		||||
@ -331,4 +331,61 @@ abstract class QueryFilters
 | 
			
		||||
            ->orderByRaw("{$this->with_property} = ? DESC", [$value])
 | 
			
		||||
            ->company();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Filter by date range
 | 
			
		||||
     *
 | 
			
		||||
     * @param string $date_range
 | 
			
		||||
     * @return Builder
 | 
			
		||||
     */
 | 
			
		||||
    public function date_range(string $date_range = ''): Builder
 | 
			
		||||
    {
 | 
			
		||||
        $parts = explode(",", $date_range);
 | 
			
		||||
 | 
			
		||||
        if (count($parts) != 2 || !in_array('date', \Illuminate\Support\Facades\Schema::getColumnListing($this->builder->getModel()->getTable()))) {
 | 
			
		||||
            return $this->builder;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
 | 
			
		||||
            $start_date = Carbon::parse($parts[0]);
 | 
			
		||||
            $end_date = Carbon::parse($parts[1]);
 | 
			
		||||
 | 
			
		||||
            return $this->builder->whereBetween('date', [$start_date, $end_date]);
 | 
			
		||||
        } catch(\Exception $e) {
 | 
			
		||||
            return $this->builder;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Filter by due date range
 | 
			
		||||
     *
 | 
			
		||||
     * @param string $date_range
 | 
			
		||||
     * @return Builder
 | 
			
		||||
     */
 | 
			
		||||
    public function due_date_range(string $date_range = ''): Builder
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
        $parts = explode(",", $date_range);
 | 
			
		||||
 | 
			
		||||
        if (count($parts) != 2 || !in_array('due_date', \Illuminate\Support\Facades\Schema::getColumnListing($this->builder->getModel()->getTable()))) {
 | 
			
		||||
            return $this->builder;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
 | 
			
		||||
            $start_date = Carbon::parse($parts[0]);
 | 
			
		||||
            $end_date = Carbon::parse($parts[1]);
 | 
			
		||||
 | 
			
		||||
            return $this->builder->whereBetween('due_date', [$start_date, $end_date]);
 | 
			
		||||
        } catch(\Exception $e) {
 | 
			
		||||
            return $this->builder;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -23,12 +23,12 @@ class ProRata
 | 
			
		||||
     * the time interval and the frequency duration
 | 
			
		||||
     *
 | 
			
		||||
     * @param float $amount
 | 
			
		||||
     * @param Carbon $from_date
 | 
			
		||||
     * @param Carbon $to_date
 | 
			
		||||
     * @param \Illuminate\Support\Carbon | \Carbon\Carbon $from_date
 | 
			
		||||
     * @param \Illuminate\Support\Carbon | \Carbon\Carbon $to_date
 | 
			
		||||
     * @param int $frequency
 | 
			
		||||
     * @return float
 | 
			
		||||
     */
 | 
			
		||||
    public function refund(float $amount, Carbon $from_date, Carbon $to_date, int $frequency): float
 | 
			
		||||
    public function refund(float $amount, $from_date, $to_date, int $frequency): float
 | 
			
		||||
    {
 | 
			
		||||
        $days = intval(abs($from_date->copy()->diffInDays($to_date)));
 | 
			
		||||
        $days_in_frequency = $this->getDaysInFrequency($frequency);
 | 
			
		||||
@ -41,12 +41,12 @@ class ProRata
 | 
			
		||||
     * the time interval and the frequency duration
 | 
			
		||||
     *
 | 
			
		||||
     * @param float $amount
 | 
			
		||||
     * @param Carbon $from_date
 | 
			
		||||
     * @param Carbon $to_date
 | 
			
		||||
     * @param \Illuminate\Support\Carbon | \Carbon\Carbon  $from_date
 | 
			
		||||
     * @param \Illuminate\Support\Carbon | \Carbon\Carbon  $to_date
 | 
			
		||||
     * @param int $frequency
 | 
			
		||||
     * @return float
 | 
			
		||||
     */
 | 
			
		||||
    public function charge(float $amount, Carbon $from_date, Carbon $to_date, int $frequency): float
 | 
			
		||||
    public function charge(float $amount, $from_date, $to_date, int $frequency): float
 | 
			
		||||
    {
 | 
			
		||||
        $days = intval(abs($from_date->copy()->diffInDays($to_date)));
 | 
			
		||||
        $days_in_frequency = $this->getDaysInFrequency($frequency);
 | 
			
		||||
 | 
			
		||||
@ -13,13 +13,11 @@ namespace App\Http\Requests\Client;
 | 
			
		||||
 | 
			
		||||
use App\DataMapper\ClientSettings;
 | 
			
		||||
use App\Http\Requests\Request;
 | 
			
		||||
use App\Http\ValidationRules\Client\CountryCodeExistsRule;
 | 
			
		||||
use App\Http\ValidationRules\Ninja\CanStoreClientsRule;
 | 
			
		||||
use App\Http\ValidationRules\ValidClientGroupSettingsRule;
 | 
			
		||||
use App\Models\Client;
 | 
			
		||||
use App\Models\GroupSetting;
 | 
			
		||||
use App\Utils\Traits\MakesHash;
 | 
			
		||||
use Illuminate\Support\Facades\Cache;
 | 
			
		||||
use Illuminate\Validation\Rule;
 | 
			
		||||
 | 
			
		||||
class StoreClientRequest extends Request
 | 
			
		||||
 | 
			
		||||
@ -50,7 +50,7 @@ class StoreCompanyRequest extends Request
 | 
			
		||||
            $rules['portal_domain'] = 'sometimes|url';
 | 
			
		||||
        } else {
 | 
			
		||||
            if (Ninja::isHosted()) {
 | 
			
		||||
                $rules['subdomain'] = ['nullable', 'regex:/^[a-zA-Z0-9][a-zA-Z0-9.-]+[a-zA-Z0-9]$/', new ValidSubdomain()];
 | 
			
		||||
                $rules['subdomain'] = ['nullable', 'regex:/^[a-zA-Z0-9-]{1,63}$/', new ValidSubdomain()];
 | 
			
		||||
            } else {
 | 
			
		||||
                $rules['subdomain'] = 'nullable|alpha_num';
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@ -1,59 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * Credit Ninja (https://creditninja.com).
 | 
			
		||||
 *
 | 
			
		||||
 * @link https://github.com/creditninja/creditninja source repository
 | 
			
		||||
 *
 | 
			
		||||
 * @copyright Copyright (c) 2022. Credit Ninja LLC (https://creditninja.com)
 | 
			
		||||
 *
 | 
			
		||||
 * @license https://www.elastic.co/licensing/elastic-license
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
namespace App\Http\ValidationRules\Client;
 | 
			
		||||
 | 
			
		||||
use App\Models\Country;
 | 
			
		||||
use Illuminate\Contracts\Validation\Rule;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class UniqueCreditNumberRule.
 | 
			
		||||
 */
 | 
			
		||||
class CountryCodeExistsRule implements Rule
 | 
			
		||||
{
 | 
			
		||||
    public function __construct()
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param string $attribute
 | 
			
		||||
     * @param mixed $value
 | 
			
		||||
     * @return bool
 | 
			
		||||
     */
 | 
			
		||||
    public function passes($attribute, $value)
 | 
			
		||||
    {
 | 
			
		||||
        return $this->checkIfCodeExists($value); //if it exists, return false!
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @return string
 | 
			
		||||
     */
 | 
			
		||||
    public function message()
 | 
			
		||||
    {
 | 
			
		||||
        return 'Country code does not exist';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @return bool
 | 
			
		||||
     */
 | 
			
		||||
    private function checkIfCodeExists($value): bool
 | 
			
		||||
    {
 | 
			
		||||
        $country = Country::where('iso_3166_2', $value)
 | 
			
		||||
                        ->orWhere('iso_3166_3', $value)
 | 
			
		||||
                        ->exists();
 | 
			
		||||
 | 
			
		||||
        if ($country) {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -12,36 +12,26 @@
 | 
			
		||||
namespace App\Http\ValidationRules\Company;
 | 
			
		||||
 | 
			
		||||
use App\Utils\Ninja;
 | 
			
		||||
use Illuminate\Contracts\Validation\Rule;
 | 
			
		||||
use Closure;
 | 
			
		||||
use Illuminate\Contracts\Validation\ValidationRule;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class ValidCompanyQuantity.
 | 
			
		||||
 */
 | 
			
		||||
class ValidCompanyQuantity implements Rule
 | 
			
		||||
class ValidCompanyQuantity implements ValidationRule
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * @param string $attribute
 | 
			
		||||
     * @param mixed $value
 | 
			
		||||
     * @return bool
 | 
			
		||||
     */
 | 
			
		||||
    public function passes($attribute, $value)
 | 
			
		||||
    
 | 
			
		||||
    public function validate(string $attribute, mixed $value, Closure $fail): void
 | 
			
		||||
    {
 | 
			
		||||
        if (config('ninja.testvars.travis')) {
 | 
			
		||||
            return true;
 | 
			
		||||
        $message = ctrans('texts.company_limit_reached', ['limit' => Ninja::isSelfHost() ? 10 : auth()->user()->company()->account->hosted_company_count]);
 | 
			
		||||
 | 
			
		||||
        $test = Ninja::isSelfHost() ? 
 | 
			
		||||
            auth()->user()->company()->account->companies->count() < 10 : 
 | 
			
		||||
            (auth()->user()->account->isPaid() || auth()->user()->account->isTrial()) && auth()->user()->company()->account->companies->count() < 10 ;
 | 
			
		||||
 | 
			
		||||
        if (!$test) {
 | 
			
		||||
            $fail($message);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        if (Ninja::isSelfHost()) {
 | 
			
		||||
            return auth()->user()->company()->account->companies->count() < 10;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return (auth()->user()->account->isPaid() || auth()->user()->account->isTrial()) && auth()->user()->company()->account->companies->count() < 10 ;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @return string
 | 
			
		||||
     */
 | 
			
		||||
    public function message()
 | 
			
		||||
    {
 | 
			
		||||
        return ctrans('texts.company_limit_reached', ['limit' => Ninja::isSelfHost() ? 10 : auth()->user()->company()->account->hosted_company_count]);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -12,31 +12,22 @@
 | 
			
		||||
namespace App\Http\ValidationRules\Company;
 | 
			
		||||
 | 
			
		||||
use App\Libraries\MultiDB;
 | 
			
		||||
use Illuminate\Contracts\Validation\Rule;
 | 
			
		||||
use Closure;
 | 
			
		||||
use Illuminate\Contracts\Validation\ValidationRule;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class ValidCompanyQuantity.
 | 
			
		||||
 * Class ValidSubdomain.
 | 
			
		||||
 */
 | 
			
		||||
class ValidSubdomain implements Rule
 | 
			
		||||
class ValidSubdomain implements ValidationRule
 | 
			
		||||
{
 | 
			
		||||
    public function __construct()
 | 
			
		||||
    public function validate(string $attribute, mixed $value, Closure $fail): void
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function passes($attribute, $value)
 | 
			
		||||
    {
 | 
			
		||||
        if (empty($value)) {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        if(empty($value))
 | 
			
		||||
            return;
 | 
			
		||||
        
 | 
			
		||||
        return MultiDB::checkDomainAvailable($value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @return string
 | 
			
		||||
     */
 | 
			
		||||
    public function message()
 | 
			
		||||
    {
 | 
			
		||||
        return ctrans('texts.subdomain_taken');
 | 
			
		||||
        if (!MultiDB::checkDomainAvailable($value)) {
 | 
			
		||||
            $fail(ctrans('texts.subdomain_taken'));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -165,6 +165,7 @@ class InvoicePay extends Component
 | 
			
		||||
            return $this->required_fields = true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /** @var \App\Models\ClientContact $contact */
 | 
			
		||||
        $contact = $this->getContext()['contact'];
 | 
			
		||||
 | 
			
		||||
        foreach ($fields as $index => $field) {
 | 
			
		||||
@ -173,7 +174,7 @@ class InvoicePay extends Component
 | 
			
		||||
            if (\Illuminate\Support\Str::startsWith($field['name'], 'client_')) {
 | 
			
		||||
                if (
 | 
			
		||||
                    empty($contact->client->{$_field})
 | 
			
		||||
                    || is_null($contact->client->{$_field})
 | 
			
		||||
                    || is_null($contact->client->{$_field}) //@phpstan-ignore-line
 | 
			
		||||
                ) {
 | 
			
		||||
 | 
			
		||||
                    return $this->required_fields = true;
 | 
			
		||||
@ -182,7 +183,7 @@ class InvoicePay extends Component
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (\Illuminate\Support\Str::startsWith($field['name'], 'contact_')) {
 | 
			
		||||
                if (empty($contact->{$_field}) || is_null($contact->{$_field}) || str_contains($contact->{$_field}, '@example.com')) {
 | 
			
		||||
                if (empty($contact->{$_field}) || is_null($contact->{$_field}) || str_contains($contact->{$_field}, '@example.com')) { //@phpstan-ignore-line
 | 
			
		||||
                    return $this->required_fields = true;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@ -123,7 +123,7 @@ class ClientPaymentFailureObject
 | 
			
		||||
        $signature = $this->client->getSetting('email_signature');
 | 
			
		||||
        $html_variables = (new HtmlEngine($invitation))->makeValues();
 | 
			
		||||
        
 | 
			
		||||
        $html_variables['$gateway_payment_error'] = $this->error ?? '';
 | 
			
		||||
        $html_variables['$payment_error'] = $this->error ?? '';
 | 
			
		||||
        $html_variables['$total'] = $this->getAmount();
 | 
			
		||||
 | 
			
		||||
        $signature = str_replace(array_keys($html_variables), array_values($html_variables), $signature);
 | 
			
		||||
 | 
			
		||||
@ -298,12 +298,37 @@ class BaseModel extends Model
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // special catch here for einvoicing eventing
 | 
			
		||||
        if($event_id == Webhook::EVENT_SENT_INVOICE && ($this instanceof Invoice) && is_null($this->backup)){
 | 
			
		||||
        if($event_id == Webhook::EVENT_SENT_INVOICE && ($this instanceof Invoice) && is_null($this->backup) && $this->client->getSetting('e_invoice_type') == 'PEPPOL'){
 | 
			
		||||
            \App\Services\EDocument\Jobs\SendEDocument::dispatch(get_class($this), $this->id, $this->company->db);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * arrayFilterRecursive
 | 
			
		||||
     *
 | 
			
		||||
     * Removes null properties from an array
 | 
			
		||||
     * 
 | 
			
		||||
     * @param  array $array
 | 
			
		||||
     * @return array
 | 
			
		||||
     */
 | 
			
		||||
    public function arrayFilterRecursive(array $array): array
 | 
			
		||||
    {
 | 
			
		||||
        foreach ($array as $key => $value) {
 | 
			
		||||
            if (is_array($value)) {
 | 
			
		||||
                // Recursively filter the nested array
 | 
			
		||||
                $array[$key] = $this->arrayFilterRecursive($value);
 | 
			
		||||
            }
 | 
			
		||||
            // Remove null values
 | 
			
		||||
            if (is_null($array[$key])) {
 | 
			
		||||
                unset($array[$key]);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $array;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the base64 encoded PDF string of the entity
 | 
			
		||||
     * @deprecated - unused implementation
 | 
			
		||||
 | 
			
		||||
@ -50,7 +50,7 @@ use Laracasts\Presenter\PresentableTrait;
 | 
			
		||||
 * @property int|null $last_login
 | 
			
		||||
 * @property int|null $industry_id
 | 
			
		||||
 * @property int|null $size_id
 | 
			
		||||
 * @property object|null $e_invoice
 | 
			
		||||
 * @property object|array|null $e_invoice
 | 
			
		||||
 * @property string|null $address1
 | 
			
		||||
 * @property string|null $address2
 | 
			
		||||
 * @property string|null $city
 | 
			
		||||
 | 
			
		||||
@ -37,6 +37,7 @@ use Laracasts\Presenter\PresentableTrait;
 | 
			
		||||
 * @property-read Project|null $project
 | 
			
		||||
 * @property-read int|null $tasks_count
 | 
			
		||||
 * @property-read \App\Models\User $user
 | 
			
		||||
 * @property-read \App\Models\User $assigned_user
 | 
			
		||||
 * @property-read \App\Models\Vendor|null $vendor
 | 
			
		||||
 * @method static \Illuminate\Database\Eloquent\Builder|BaseModel company()
 | 
			
		||||
 * @method static \Illuminate\Database\Eloquent\Builder|BaseModel exclude($columns)
 | 
			
		||||
@ -117,6 +118,11 @@ class Project extends BaseModel
 | 
			
		||||
        return $this->belongsTo(User::class)->withTrashed();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function assigned_user(): \Illuminate\Database\Eloquent\Relations\BelongsTo
 | 
			
		||||
    {
 | 
			
		||||
        return $this->belongsTo(User::class, 'assigned_user_id', 'id')->withTrashed();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function tasks(): \Illuminate\Database\Eloquent\Relations\HasMany
 | 
			
		||||
    {
 | 
			
		||||
        return $this->hasMany(Task::class);
 | 
			
		||||
 | 
			
		||||
@ -400,8 +400,12 @@ class BaseDriver extends AbstractPaymentDriver
 | 
			
		||||
        $invoice = $this->payment_hash->fee_invoice;
 | 
			
		||||
 | 
			
		||||
        $fee_count = collect($invoice->line_items)
 | 
			
		||||
                        ->map(function ($item){
 | 
			
		||||
                            $item->gross_line_total = round($item->gross_line_total, 2);
 | 
			
		||||
                            return $item;
 | 
			
		||||
                        })
 | 
			
		||||
                        ->whereIn('type_id', ['3','4'])
 | 
			
		||||
                        ->where('gross_line_total', $fee_total)
 | 
			
		||||
                        ->where('gross_line_total', round($fee_total,2))
 | 
			
		||||
                        ->count();
 | 
			
		||||
 | 
			
		||||
        if($invoice && $fee_count == 0){
 | 
			
		||||
 | 
			
		||||
@ -105,6 +105,9 @@ class InstantBankPay implements MethodInterface
 | 
			
		||||
                $this->go_cardless->payment_hash->data->billing_request
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            nlog($billing_request);
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            $payment = $this->go_cardless->gateway->payments()->get(
 | 
			
		||||
                $billing_request->payment_request->links->payment
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
@ -286,7 +286,8 @@ class MolliePaymentDriver extends BaseDriver
 | 
			
		||||
    public function processWebhookRequest(PaymentWebhookRequest $request)
 | 
			
		||||
    {
 | 
			
		||||
        // Allow app to catch up with webhook request.
 | 
			
		||||
        sleep(4);
 | 
			
		||||
        // sleep(4);
 | 
			
		||||
        usleep(rand(2800000, 4000000));
 | 
			
		||||
 | 
			
		||||
        $validator = Validator::make($request->all(), [
 | 
			
		||||
            'id' => ['required', 'starts_with:tr'],
 | 
			
		||||
 | 
			
		||||
@ -125,6 +125,13 @@ class ImportCustomers
 | 
			
		||||
                $settings->currency_id = (string) $currency->id;
 | 
			
		||||
                $client->settings = $settings;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        }else {
 | 
			
		||||
 | 
			
		||||
            $settings = $client->settings;
 | 
			
		||||
            $settings->currency_id = (string) $this->stripe->company_gateway->company->settings->currency_id;
 | 
			
		||||
            $client->settings = $settings;
 | 
			
		||||
            
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $client->name = $customer->name ? $customer->name : $customer->email;
 | 
			
		||||
 | 
			
		||||
@ -147,8 +147,7 @@ class BaseRepository
 | 
			
		||||
     * @throws \ReflectionException
 | 
			
		||||
     */
 | 
			
		||||
    protected function alternativeSave($data, $model)
 | 
			
		||||
    {   //$start = microtime(true);
 | 
			
		||||
        //forces the client_id if it doesn't exist
 | 
			
		||||
    {   
 | 
			
		||||
        if (array_key_exists('client_id', $data)) {
 | 
			
		||||
            $model->client_id = $data['client_id'];
 | 
			
		||||
        }
 | 
			
		||||
@ -167,7 +166,7 @@ class BaseRepository
 | 
			
		||||
            $company_defaults = $client->setCompanyDefaults($data, lcfirst($resource));
 | 
			
		||||
            $data['exchange_rate'] = $company_defaults['exchange_rate'];
 | 
			
		||||
            $model->uses_inclusive_taxes = $client->getSetting('inclusive_taxes');
 | 
			
		||||
            // $data = array_merge($company_defaults, $data);
 | 
			
		||||
 | 
			
		||||
            $data = array_merge($data, $company_defaults);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -321,6 +320,17 @@ class BaseRepository
 | 
			
		||||
                UpdateTaxData::dispatch($client, $client->company);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            /** If Peppol is enabled - we will save the e_invoice document here at this point, document will not update after being sent */
 | 
			
		||||
            if(strlen($model->backup ?? '') == 0 && $client->getSetting('e_invoice_type') == 'PEPPOL' && $model->company->legal_entity_id)
 | 
			
		||||
            {
 | 
			
		||||
                try{
 | 
			
		||||
                    $model->service()->getEInvoice();
 | 
			
		||||
                }
 | 
			
		||||
                catch(\Exception $e){
 | 
			
		||||
                    nlog("EXCEPTION:: BASEREPOSITORY:: Error generating e_invoice for model {$model->id}");
 | 
			
		||||
                    nlog($e->getMessage());
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ($model instanceof Credit) {
 | 
			
		||||
 | 
			
		||||
@ -76,6 +76,13 @@ class ClientRepository extends BaseRepository
 | 
			
		||||
            $client->country_id = $company->settings->country_id;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if(isset($data['e_invoice']) && is_array($data['e_invoice'])) {
 | 
			
		||||
            //ensure it is normalized first!
 | 
			
		||||
            $data['e_invoice'] = $client->arrayFilterRecursive($data['e_invoice']);
 | 
			
		||||
 | 
			
		||||
            $client->e_invoice = $data['e_invoice'];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $client->save();
 | 
			
		||||
 | 
			
		||||
        if (! isset($client->number) || empty($client->number) || strlen($client->number) == 0) {
 | 
			
		||||
@ -107,6 +114,7 @@ class ClientRepository extends BaseRepository
 | 
			
		||||
            $this->contact_repo->save($contact_data, $client);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        return $client;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -60,7 +60,7 @@ class CompanyRepository extends BaseRepository
 | 
			
		||||
 | 
			
		||||
        if(isset($data['e_invoice']) && is_array($data['e_invoice'])){
 | 
			
		||||
            //ensure it is normalized first!
 | 
			
		||||
            $data['e_invoice'] = $this->arrayFilterRecursive($data['e_invoice']);
 | 
			
		||||
            $data['e_invoice'] = $company->arrayFilterRecursive($data['e_invoice']);
 | 
			
		||||
 | 
			
		||||
            $company->e_invoice = $data['e_invoice'];
 | 
			
		||||
        }
 | 
			
		||||
@ -70,24 +70,6 @@ class CompanyRepository extends BaseRepository
 | 
			
		||||
        return $company;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    private function arrayFilterRecursive(array $array): array
 | 
			
		||||
    {
 | 
			
		||||
        foreach ($array as $key => $value) {
 | 
			
		||||
            if (is_array($value)) {
 | 
			
		||||
                // Recursively filter the nested array
 | 
			
		||||
                $array[$key] = $this->arrayFilterRecursive($value);
 | 
			
		||||
            }
 | 
			
		||||
            // Remove null values
 | 
			
		||||
            if (is_null($array[$key])) {
 | 
			
		||||
                unset($array[$key]);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $array;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * parseCustomFields
 | 
			
		||||
     *
 | 
			
		||||
 | 
			
		||||
@ -69,7 +69,7 @@ class RFFService
 | 
			
		||||
            if (Str::startsWith($field['name'], 'client_')) {
 | 
			
		||||
                if (
 | 
			
		||||
                    empty($_contact->client->{$_field})
 | 
			
		||||
                    || is_null($_contact->client->{$_field})
 | 
			
		||||
                    || is_null($_contact->client->{$_field}) //@phpstan-ignore-line
 | 
			
		||||
                ) {
 | 
			
		||||
                    // $this->show_form = true;
 | 
			
		||||
                    $this->unfilled_fields++;
 | 
			
		||||
@ -79,7 +79,7 @@ class RFFService
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (Str::startsWith($field['name'], 'contact_')) {
 | 
			
		||||
                if (empty($_contact->{$_field}) || is_null($_contact->{$_field}) || str_contains($_contact->{$_field}, '@example.com')) {
 | 
			
		||||
                if (empty($_contact->{$_field}) || is_null($_contact->{$_field}) || str_contains($_contact->{$_field}, '@example.com')) { //@phpstan-ignore-line
 | 
			
		||||
                    $this->unfilled_fields++;
 | 
			
		||||
                } else {
 | 
			
		||||
                    $this->fields[$index]['filled'] = true;
 | 
			
		||||
 | 
			
		||||
@ -261,7 +261,7 @@ class Storecove
 | 
			
		||||
     *
 | 
			
		||||
     * @param  int $id
 | 
			
		||||
     * @param  array $data
 | 
			
		||||
     * @return array
 | 
			
		||||
     * @return mixed
 | 
			
		||||
     */
 | 
			
		||||
    public function updateLegalEntity(int $id, array $data)
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
@ -50,10 +50,11 @@ class SendEDocument implements ShouldQueue
 | 
			
		||||
        MultiDB::setDB($this->db);
 | 
			
		||||
 | 
			
		||||
        $model = $this->entity::find($this->id);
 | 
			
		||||
        $e_invoice_standard = $model->client ? $model->client->getSetting('e_invoice_type') : $model->company->getSetting('e_invoice_type');
 | 
			
		||||
 | 
			
		||||
        if($e_invoice_standard != 'PEPPOL')
 | 
			
		||||
            return;
 | 
			
		||||
        // $e_invoice_standard = $model->client ? $model->client->getSetting('e_invoice_type') : $model->company->getSetting('e_invoice_type');
 | 
			
		||||
 | 
			
		||||
        // if($e_invoice_standard != 'PEPPOL')
 | 
			
		||||
        //     return;
 | 
			
		||||
 | 
			
		||||
        if(Ninja::isSelfHost() && ($model instanceof Invoice) && $model->company->legal_entity_id)
 | 
			
		||||
        {
 | 
			
		||||
@ -122,10 +123,11 @@ class SendEDocument implements ShouldQueue
 | 
			
		||||
        $activity->company_id = $model->company_id;
 | 
			
		||||
        $activity->activity_type_id = Activity::EMAIL_EINVOICE_SUCCESS;
 | 
			
		||||
        $activity->invoice_id = $model->id;
 | 
			
		||||
        $activity->notes = $guid;
 | 
			
		||||
        $activity->notes = str_replace('"', '', $guid);
 | 
			
		||||
 | 
			
		||||
        $activity->save();
 | 
			
		||||
 | 
			
		||||
        $model->backup = $guid;
 | 
			
		||||
        $model->backup = str_replace('"', '', $guid);
 | 
			
		||||
        $model->saveQuietly();
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -100,7 +100,7 @@ class OrderXDocument extends AbstractService
 | 
			
		||||
            $this->orderxdocument->setDocumentShipToAddress($settings_entity->shipping_address1, $settings_entity->shipping_address2, "", $settings_entity->shipping_postal_code, $settings_entity->shipping_city, $settings_entity->shipping_country->iso_3166_2, $settings_entity->shipping_state);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $this->orderxdocument->addDocumentPaymentMean(68, ctrans("texts.xinvoice_online_payment"));
 | 
			
		||||
        $this->orderxdocument->addDocumentPaymentMean('68', ctrans("texts.xinvoice_online_payment"));
 | 
			
		||||
 | 
			
		||||
        if (str_contains($company->getSetting('vat_number'), "/")) {
 | 
			
		||||
            $this->orderxdocument->addDocumentSellerTaxRegistration("FC", $company->getSetting('vat_number'));
 | 
			
		||||
 | 
			
		||||
@ -276,7 +276,7 @@ class Peppol extends AbstractService
 | 
			
		||||
            $this->p_invoice->DueDate = new \DateTime($this->invoice->due_date);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $this->p_invoice->InvoiceTypeCode = 380; //
 | 
			
		||||
        $this->p_invoice->InvoiceTypeCode = ($this->invoice->amount >= 0) ? 380 : 381; //
 | 
			
		||||
        $this->p_invoice->AccountingSupplierParty = $this->getAccountingSupplierParty();
 | 
			
		||||
        $this->p_invoice->AccountingCustomerParty = $this->getAccountingCustomerParty();
 | 
			
		||||
        $this->p_invoice->InvoiceLine = $this->getInvoiceLines();
 | 
			
		||||
@ -287,8 +287,11 @@ class Peppol extends AbstractService
 | 
			
		||||
        $this->senderSpecificLevelMutators()
 | 
			
		||||
             ->receiverSpecificLevelMutators();
 | 
			
		||||
 | 
			
		||||
        if(strlen($this->invoice->backup ?? '') == 0)
 | 
			
		||||
        {
 | 
			
		||||
            $this->invoice->e_invoice = $this->toObject();
 | 
			
		||||
            $this->invoice->save();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
 | 
			
		||||
@ -335,7 +338,7 @@ class Peppol extends AbstractService
 | 
			
		||||
    /**
 | 
			
		||||
     * getInvoice
 | 
			
		||||
     *
 | 
			
		||||
     * @return InvoiceNinja\EInvoice\Models\Peppol\Invoice
 | 
			
		||||
     * @return \InvoiceNinja\EInvoice\Models\Peppol\Invoice
 | 
			
		||||
     */
 | 
			
		||||
    public function getInvoice(): \InvoiceNinja\EInvoice\Models\Peppol\Invoice
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
@ -124,9 +124,9 @@ class ZugferdEDokument extends AbstractService
 | 
			
		||||
 | 
			
		||||
        //Payment Means - Switcher
 | 
			
		||||
        if($company->settings->custom_value1 == '42') {
 | 
			
		||||
            $this->xdocument->addDocumentPaymentMean(typecode: 42, payeeIban: $company->settings->custom_value2, payeeAccountName: $company->settings->custom_value4, payeeBic: $company->settings->custom_value3);
 | 
			
		||||
            $this->xdocument->addDocumentPaymentMean(typecode: '42', payeeIban: $company->settings->custom_value2, payeeAccountName: $company->settings->custom_value4, payeeBic: $company->settings->custom_value3);
 | 
			
		||||
        } else {
 | 
			
		||||
            $this->xdocument->addDocumentPaymentMean(68, ctrans("texts.xinvoice_online_payment"));
 | 
			
		||||
            $this->xdocument->addDocumentPaymentMean('68', ctrans("texts.xinvoice_online_payment"));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (str_contains($company->getSetting('vat_number'), "/")) {
 | 
			
		||||
 | 
			
		||||
@ -92,6 +92,8 @@ class AddGatewayFee extends AbstractService
 | 
			
		||||
        /**Refresh Invoice values*/
 | 
			
		||||
        $this->invoice = $this->invoice->calc()->getInvoice();
 | 
			
		||||
 | 
			
		||||
        nlog($this->invoice->line_items);
 | 
			
		||||
        
 | 
			
		||||
        $new_balance = $this->invoice->balance;
 | 
			
		||||
 | 
			
		||||
        if (floatval($new_balance) - floatval($balance) != 0) {
 | 
			
		||||
@ -141,12 +143,6 @@ class AddGatewayFee extends AbstractService
 | 
			
		||||
        if (floatval($new_balance) - floatval($balance) != 0) {
 | 
			
		||||
            $adjustment = $new_balance - $balance;
 | 
			
		||||
 | 
			
		||||
            // $this->invoice
 | 
			
		||||
            // ->client
 | 
			
		||||
            // ->service()
 | 
			
		||||
            // ->updateBalance($adjustment * -1)
 | 
			
		||||
            // ->save();
 | 
			
		||||
 | 
			
		||||
            $this->invoice
 | 
			
		||||
            ->ledger()
 | 
			
		||||
            ->updateInvoiceBalance($adjustment * -1, 'Adjustment for adding gateway DISCOUNT');
 | 
			
		||||
 | 
			
		||||
@ -148,9 +148,9 @@ class AutoBillInvoice extends AbstractService
 | 
			
		||||
        ]);
 | 
			
		||||
 | 
			
		||||
        nlog("Payment hash created => {$payment_hash->id}");
 | 
			
		||||
        $this->invoice->saveQuietly();
 | 
			
		||||
 | 
			
		||||
        $payment = false;
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            $payment = $gateway_token->gateway
 | 
			
		||||
                ->driver($this->client)
 | 
			
		||||
@ -163,6 +163,7 @@ class AutoBillInvoice extends AbstractService
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $this->invoice = $this->invoice->fresh();
 | 
			
		||||
        $this->invoice->auto_bill_tries += 1;
 | 
			
		||||
 | 
			
		||||
        if ($this->invoice->auto_bill_tries == 3) {
 | 
			
		||||
 | 
			
		||||
@ -102,9 +102,9 @@ class QuickbooksSync implements ShouldQueue
 | 
			
		||||
    private function processEntitySync(string $entity, $records)
 | 
			
		||||
    {
 | 
			
		||||
        match($entity){
 | 
			
		||||
            // 'client' => $this->syncQbToNinjaClients($records),
 | 
			
		||||
            'client' => $this->syncQbToNinjaClients($records),
 | 
			
		||||
            'product' => $this->syncQbToNinjaProducts($records),
 | 
			
		||||
            // 'invoice' => $this->syncQbToNinjaInvoices($records),
 | 
			
		||||
            'invoice' => $this->syncQbToNinjaInvoices($records),
 | 
			
		||||
            // 'vendor' => $this->syncQbToNinjaClients($records),
 | 
			
		||||
            // 'quote' => $this->syncInvoices($records),
 | 
			
		||||
            // 'purchase_order' => $this->syncInvoices($records),
 | 
			
		||||
 | 
			
		||||
@ -949,6 +949,7 @@ class TemplateService
 | 
			
		||||
                'custom_value4' => $task->custom_value4 ?: '',
 | 
			
		||||
                'status' => $task->status ? $task->status->name : '',
 | 
			
		||||
                'user' => $this->userInfo($task->user),
 | 
			
		||||
                'assigned_user' => $task->assigned_user ? $this->userInfo($task->assigned_user) : [],
 | 
			
		||||
                'client' => $this->getClient($task),
 | 
			
		||||
            ];
 | 
			
		||||
 | 
			
		||||
@ -1007,6 +1008,7 @@ class TemplateService
 | 
			
		||||
            'tasks' => ($project->tasks && !$nested) ? $this->processTasks($project->tasks, true) : [], //@phpstan-ignore-line
 | 
			
		||||
            'client' => $this->getClient($project),
 | 
			
		||||
            'user' => $this->userInfo($project->user),
 | 
			
		||||
            'assigned_user' => $project->assigned_user ? $this->userInfo($project->assigned_user) : [],
 | 
			
		||||
            'invoices' => $this->processInvoices($project->invoices)
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -401,11 +401,17 @@ class HtmlEngine
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        $data['$user.name'] = ['value' => $this->entity->user->present()->name(), 'label' => ctrans('texts.name')];
 | 
			
		||||
 | 
			
		||||
        $data['$user.signature'] = ['value' => $this->entity->user->signature ?? '', 'label' => ctrans('texts.signature')];
 | 
			
		||||
        $data['$user.first_name'] = ['value' => $this->entity->user->first_name, 'label' => ctrans('texts.first_name')];
 | 
			
		||||
        $data['$user.last_name'] = ['value' => $this->entity->user->last_name, 'label' => ctrans('texts.last_name')];
 | 
			
		||||
        $data['$created_by_user'] = &$data['$user.name'];
 | 
			
		||||
 | 
			
		||||
        $data['$assigned_to_user'] = ['value' => $this->entity->assigned_user ? $this->entity->assigned_user->present()->name() : '', 'label' => ctrans('texts.name')];
 | 
			
		||||
        $data['$assigned_user.signature'] = ['value' => $this->entity->assigned_user ? $this->entity->assigned_user->signature : '', 'label' => ctrans('texts.signature')];
 | 
			
		||||
 | 
			
		||||
        $data['$assigned_user.first_name'] = ['value' => $this->entity->assigned_user ? $this->entity->assigned_user->first_name : '', 'label' => ctrans('texts.first_name')];
 | 
			
		||||
        $data['$assigned_user.last_name'] = ['value' => $this->entity->assigned_user ? $this->entity->assigned_user->last_name : '', 'label' => ctrans('texts.last_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')];
 | 
			
		||||
 | 
			
		||||
@ -666,7 +672,7 @@ class HtmlEngine
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $data['$contact.signature_raw'] = ['value' => $this->invitation->signature_base64, 'label' => ctrans('texts.signature')];
 | 
			
		||||
        $data['$contact.signature_date'] = ['value' => $this->translateDate($this->invitation->signature_date ?? '1970-01-01', $this->client->date_format(), $this->client->locale()), 'label' => ctrans('texts.date')];
 | 
			
		||||
        $data['$contact.signature_date'] = ['value' => $this->invitation->signature_date ? $this->translateDate($this->invitation->signature_date, $this->client->date_format(), $this->client->locale()) : ' ', 'label' => ctrans('texts.date')];
 | 
			
		||||
        $data['$contact.signature_ip'] = ['value' => $this->invitation->signature_ip ?? '', 'label' => ctrans('texts.address')];
 | 
			
		||||
 | 
			
		||||
        $data['$thanks'] = ['value' => '', 'label' => ctrans('texts.thanks')];
 | 
			
		||||
@ -733,7 +739,7 @@ class HtmlEngine
 | 
			
		||||
        $data['$payment.number'] = ['value' => '', 'label' => ctrans('texts.payment_number')];
 | 
			
		||||
        $data['$payment.transaction_reference'] = ['value' => '', 'label' => ctrans('texts.transaction_reference')];
 | 
			
		||||
        $data['$payment.refunded'] = ['value' => '', 'label' => ctrans('texts.refund')];
 | 
			
		||||
        $data['$gateway_payment_error'] = ['value' => '', 'label' => ctrans('texts.error')];
 | 
			
		||||
        $data['$payment_error'] = ['value' => '', 'label' => ctrans('texts.error')];
 | 
			
		||||
 | 
			
		||||
        if ($this->entity_string == 'invoice' && $this->entity->net_payments()->exists()) {
 | 
			
		||||
            $payment_list = '<br><br>';
 | 
			
		||||
@ -1166,7 +1172,7 @@ class HtmlEngine
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return '
 | 
			
		||||
<div>
 | 
			
		||||
<div class=\"center\">
 | 
			
		||||
<!--[if (gte mso 9)|(IE)]>
 | 
			
		||||
<table align="center" cellspacing="0" cellpadding="0" style="width: 600px;">
 | 
			
		||||
    <tr>
 | 
			
		||||
 | 
			
		||||
@ -17,8 +17,8 @@ return [
 | 
			
		||||
    'require_https' => env('REQUIRE_HTTPS', true),
 | 
			
		||||
    'app_url' => rtrim(env('APP_URL', ''), '/'),
 | 
			
		||||
    'app_domain' => env('APP_DOMAIN', 'invoicing.co'),
 | 
			
		||||
    'app_version' => env('APP_VERSION', '5.10.26'),
 | 
			
		||||
    'app_tag' => env('APP_TAG', '5.10.26'),
 | 
			
		||||
    'app_version' => env('APP_VERSION', '5.10.27'),
 | 
			
		||||
    'app_tag' => env('APP_TAG', '5.10.27'),
 | 
			
		||||
    'minimum_client_version' => '5.0.16',
 | 
			
		||||
    'terms_version' => '1.0.1',
 | 
			
		||||
    'api_secret' => env('API_SECRET', false),
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,6 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
use App\Models\Gateway;
 | 
			
		||||
use Illuminate\Database\Migrations\Migration;
 | 
			
		||||
use Illuminate\Database\Schema\Blueprint;
 | 
			
		||||
use Illuminate\Support\Facades\Schema;
 | 
			
		||||
@ -25,6 +26,12 @@ return new class extends Migration
 | 
			
		||||
            $currency->symbol = 'лв';
 | 
			
		||||
            $currency->save();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if($gateway = Gateway::find(15))
 | 
			
		||||
        {
 | 
			
		||||
            $gateway->visible = 0;
 | 
			
		||||
            $gateway->save();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 | 
			
		||||
@ -105,7 +105,7 @@ class PaymentLibrariesSeeder extends Seeder
 | 
			
		||||
 | 
			
		||||
        Gateway::query()->update(['visible' => 0]);
 | 
			
		||||
 | 
			
		||||
        Gateway::whereIn('id', [1, 3, 7, 11, 15, 20, 39, 46, 55, 50, 57, 52, 58, 59, 60, 62, 63])->update(['visible' => 1]);
 | 
			
		||||
        Gateway::whereIn('id', [1, 3, 7, 11, 20, 39, 46, 55, 50, 57, 52, 58, 59, 60, 62, 63])->update(['visible' => 1]);
 | 
			
		||||
 | 
			
		||||
        if (Ninja::isHosted()) {
 | 
			
		||||
            Gateway::whereIn('id', [20, 49])->update(['visible' => 0]);
 | 
			
		||||
 | 
			
		||||
@ -5325,7 +5325,9 @@ $lang = array(
 | 
			
		||||
    'activity_143' => 'Auto Bill succeeded for invoice :invoice',
 | 
			
		||||
    'activity_144' => 'Auto Bill failed for invoice :invoice. :notes',
 | 
			
		||||
    'activity_145' => 'EInvoice :invoice for :client was e-delivered. :notes',
 | 
			
		||||
 | 
			
		||||
    'payment_failed' => 'Payment Failed',
 | 
			
		||||
    'ssl_host_override' => 'SSL Host Override',
 | 
			
		||||
    'upload_logo_short' => 'Upload Logo',
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
return $lang;
 | 
			
		||||
 | 
			
		||||
@ -5319,6 +5319,13 @@ E-mail: :email<b><br><b>',
 | 
			
		||||
    'one_page_checkout' => 'Afrekenen op één pagina',
 | 
			
		||||
    'one_page_checkout_help' => 'Schakel de nieuwe betaalflow \'afrekenen op één pagina\' in',
 | 
			
		||||
    'applies_to' => 'Is van toepassing op',
 | 
			
		||||
    'accept_purchase_order' => 'Accepteer inkooporder',
 | 
			
		||||
    'round_to_seconds' => 'Afronden op seconden',
 | 
			
		||||
    'activity_142' => 'Quote :number reminder 1 sent',
 | 
			
		||||
    'activity_143' => 'Auto Bill succeeded for invoice :invoice',
 | 
			
		||||
    'activity_144' => 'Auto Bill failed for invoice :invoice. :notes',
 | 
			
		||||
    'activity_145' => 'EInvoice :invoice for :client was e-delivered. :notes',
 | 
			
		||||
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
return $lang;
 | 
			
		||||
 | 
			
		||||
@ -67,7 +67,7 @@ use InvoiceNinja\EInvoice\Models\Peppol\TaxCategoryType\TaxCategory;
 | 
			
		||||
/**
 | 
			
		||||
 * @test
 | 
			
		||||
 */
 | 
			
		||||
class FACT1Test extends TestCase
 | 
			
		||||
class Fact1Test extends TestCase
 | 
			
		||||
{
 | 
			
		||||
    use MockAccountData;
 | 
			
		||||
    use DatabaseTransactions;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										68
									
								
								tests/Integration/Validation/ValidCompanyQuantityTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								tests/Integration/Validation/ValidCompanyQuantityTest.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,68 @@
 | 
			
		||||
<?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\Integration\Validation;
 | 
			
		||||
 | 
			
		||||
use Tests\TestCase;
 | 
			
		||||
use App\Models\Company;
 | 
			
		||||
use Tests\MockUnitData;
 | 
			
		||||
use Illuminate\Support\Facades\Validator;
 | 
			
		||||
use App\Http\ValidationRules\Company\ValidCompanyQuantity;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @test
 | 
			
		||||
 */
 | 
			
		||||
class ValidCompanyQuantityTest extends TestCase
 | 
			
		||||
{
 | 
			
		||||
    use MockUnitData;
 | 
			
		||||
 | 
			
		||||
    protected function setUp(): void
 | 
			
		||||
    {
 | 
			
		||||
        parent::setUp();
 | 
			
		||||
 | 
			
		||||
        $this->makeTestData();
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** @test */
 | 
			
		||||
    public function testCompanyQuantityValidation()
 | 
			
		||||
    {
 | 
			
		||||
        auth()->login($this->user, true);
 | 
			
		||||
 | 
			
		||||
        $data =[];
 | 
			
		||||
        $rules = ['name' => [new ValidCompanyQuantity()]];
 | 
			
		||||
 | 
			
		||||
        $validator = Validator::make($data, $rules);
 | 
			
		||||
 | 
			
		||||
        $this->assertTrue($validator->passes());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /** @test */
 | 
			
		||||
    public function testCompanyQuantityValidationFails()
 | 
			
		||||
    {
 | 
			
		||||
        
 | 
			
		||||
        auth()->login($this->user, true);
 | 
			
		||||
        auth()->user()->setCompany($this->company);
 | 
			
		||||
 | 
			
		||||
        $data =['name' => 'bob'];
 | 
			
		||||
        $rules = ['name' => [new ValidCompanyQuantity()]];
 | 
			
		||||
 | 
			
		||||
        Company::factory()->count(10)->create([
 | 
			
		||||
            'account_id' => auth()->user()->account->id,
 | 
			
		||||
        ]);
 | 
			
		||||
        
 | 
			
		||||
        $validator = Validator::make($data, $rules);
 | 
			
		||||
 | 
			
		||||
        $this->assertFalse($validator->passes());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										84
									
								
								tests/Integration/Validation/ValidSubdomainTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								tests/Integration/Validation/ValidSubdomainTest.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,84 @@
 | 
			
		||||
<?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\Integration\Validation;
 | 
			
		||||
 | 
			
		||||
use Tests\TestCase;
 | 
			
		||||
use App\Models\Company;
 | 
			
		||||
use Tests\MockUnitData;
 | 
			
		||||
use Illuminate\Support\Facades\Validator;
 | 
			
		||||
use App\Http\ValidationRules\Company\ValidCompanyQuantity;
 | 
			
		||||
use App\Http\ValidationRules\Company\ValidSubdomain;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @test
 | 
			
		||||
 */
 | 
			
		||||
class ValidSubdomainTest extends TestCase
 | 
			
		||||
{
 | 
			
		||||
    use MockUnitData;
 | 
			
		||||
 | 
			
		||||
    protected function setUp(): void
 | 
			
		||||
    {
 | 
			
		||||
        parent::setUp();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** @test */
 | 
			
		||||
    public function testCheckValidSubdomainName()
 | 
			
		||||
    {
 | 
			
		||||
        
 | 
			
		||||
        $data = ['subdomain' => 'invoiceyninjay'];
 | 
			
		||||
        $rules = ['subdomain' => ['nullable', 'regex:/^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$/',new ValidSubdomain()]];
 | 
			
		||||
 | 
			
		||||
        $validator = Validator::make($data, $rules);
 | 
			
		||||
 | 
			
		||||
        $this->assertTrue($validator->passes());
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testCheckEmptyValidSubdomainName()
 | 
			
		||||
    {
 | 
			
		||||
        
 | 
			
		||||
        $data = ['subdomain' => ''];
 | 
			
		||||
        $rules = ['subdomain' => ['nullable', 'regex:/^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$/',new ValidSubdomain()]];
 | 
			
		||||
 | 
			
		||||
        $validator = Validator::make($data, $rules);
 | 
			
		||||
 | 
			
		||||
        $this->assertTrue($validator->passes());
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testCheckEmpty2ValidSubdomainName()
 | 
			
		||||
    {
 | 
			
		||||
        
 | 
			
		||||
        $data = ['subdomain' => ' '];
 | 
			
		||||
        $rules = ['subdomain' => ['nullable', 'regex:/^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$/',new ValidSubdomain()]];
 | 
			
		||||
 | 
			
		||||
        $validator = Validator::make($data, $rules);
 | 
			
		||||
 | 
			
		||||
        $this->assertTrue($validator->passes());
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** @test */
 | 
			
		||||
    public function testCheckInValidSubdomainName()
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
        $data = ['subdomain' => 'domain.names'];
 | 
			
		||||
        $rules = ['subdomain' => ['nullable', 'regex:/^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$/',new ValidSubdomain()]];
 | 
			
		||||
 | 
			
		||||
        $validator = Validator::make($data, $rules);
 | 
			
		||||
 | 
			
		||||
        $this->assertFalse($validator->passes());
 | 
			
		||||
 | 
			
		||||
      
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -9,6 +9,8 @@
 | 
			
		||||
 * @license https://www.elastic.co/licensing/elastic-license
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
namespace Tests\Unit;
 | 
			
		||||
 | 
			
		||||
use App\Jobs\EDocument\CreateEDocument;
 | 
			
		||||
use App\Jobs\Entity\CreateRawPdf;
 | 
			
		||||
use horstoeko\zugferd\ZugferdDocumentReader;
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user