1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-10 21:22:58 +01:00

Merge pull request #8668 from turbo124/v5-develop

Fixes for Signatures
This commit is contained in:
David Bomba 2023-07-26 12:23:49 +10:00 committed by GitHub
commit 7758bcaafe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
98 changed files with 1370 additions and 570 deletions

View File

@ -711,6 +711,29 @@ class CreateSingleAccount extends Command
$cg->save();
}
if (config('ninja.testvars.paypal_rest') && ($this->gateway == 'all' || $this->gateway == 'paypal_rest')) {
$cg = new CompanyGateway;
$cg->company_id = $company->id;
$cg->user_id = $user->id;
$cg->gateway_key = '80af24a6a691230bbec33e930ab40665';
$cg->require_cvv = true;
$cg->require_billing_address = true;
$cg->require_shipping_address = true;
$cg->update_details = true;
$cg->config = encrypt(config('ninja.testvars.paypal_rest'));
$cg->save();
$gateway_types = $cg->driver()->gatewayTypes();
$fees_and_limits = new stdClass;
$fees_and_limits->{$gateway_types[0]} = new FeesAndLimits;
$cg->fees_and_limits = $fees_and_limits;
$cg->save();
}
if (config('ninja.testvars.checkout') && ($this->gateway == 'all' || $this->gateway == 'checkout')) {
$cg = new CompanyGateway;
$cg->company_id = $company->id;

View File

@ -37,7 +37,6 @@ class AccountCreated extends GenericCounter
*
* date("Y-m-d H:i:s")
*
* @var \DateTime
*/
public $datetime;

View File

@ -37,7 +37,6 @@ class AccountDeleted extends GenericCounter
*
* date("Y-m-d H:i:s")
*
* @var \DateTime
*/
public $datetime;

View File

@ -37,7 +37,6 @@ class AccountPlatform extends GenericMixedMetric
*
* date("Y-m-d H:i:s")
*
* @var \DateTime
*/
public $datetime;

View File

@ -37,7 +37,6 @@ class AccountSignup extends GenericMixedMetric
*
* date("Y-m-d H:i:s")
*
* @var \DateTime
*/
public $datetime;
@ -61,7 +60,7 @@ class AccountSignup extends GenericMixedMetric
* The counter
* set to 1.
*
* @var string
* @var int
*/
public $int_metric1 = 1;

View File

@ -37,7 +37,6 @@ class BankAccountsCreated extends GenericMixedMetric
*
* date("Y-m-d H:i:s")
*
* @var \DateTime
*/
public $datetime;

View File

@ -37,7 +37,6 @@ class DbQuery extends GenericMixedMetric
*
* date("Y-m-d H:i:s")
*
* @var \DateTime
*/
public $datetime;
@ -57,7 +56,7 @@ class DbQuery extends GenericMixedMetric
* The counter
* set to 1.
*
* @var string
* @var int
*/
public $int_metric1 = 1;

View File

@ -37,7 +37,6 @@ class EmailCount extends GenericMixedMetric
*
* date("Y-m-d H:i:s")
*
* @var \DateTime
*/
public $datetime;

View File

@ -37,7 +37,6 @@ class EmailFailure extends GenericMixedMetric
*
* date("Y-m-d H:i:s")
*
* @var \DateTime
*/
public $datetime;
@ -61,7 +60,6 @@ class EmailFailure extends GenericMixedMetric
* The counter
* set to 1.
*
* @var string
*/
public $int_metric1 = 1;

View File

@ -37,7 +37,6 @@ class EmailInvoiceFailure extends GenericMixedMetric
*
* date("Y-m-d H:i:s")
*
* @var \DateTime
*/
public $datetime;

View File

@ -37,7 +37,6 @@ class EmailSuccess extends GenericMixedMetric
*
* date("Y-m-d H:i:s")
*
* @var \DateTime
*/
public $datetime;
@ -61,7 +60,6 @@ class EmailSuccess extends GenericMixedMetric
* The counter
* set to 1.
*
* @var string
*/
public $int_metric1 = 1;

View File

@ -37,7 +37,6 @@ class LivePreview extends GenericCounter
*
* date("Y-m-d H:i:s")
*
* @var \DateTime
*/
public $datetime;

View File

@ -37,7 +37,6 @@ class LoginFailure extends GenericCounter
*
* date("Y-m-d H:i:s")
*
* @var \DateTime
*/
public $datetime;

View File

@ -37,7 +37,6 @@ class LoginSuccess extends GenericCounter
*
* date("Y-m-d H:i:s")
*
* @var \DateTime
*/
public $datetime;

View File

@ -37,7 +37,6 @@ class EmailBounce extends GenericMixedMetric
*
* date("Y-m-d H:i:s")
*
* @var \DateTime
*/
public $datetime;
@ -67,7 +66,6 @@ class EmailBounce extends GenericMixedMetric
* The counter
* set to 1.
*
* @var string
*/
public $int_metric1 = 1;

View File

@ -16,13 +16,13 @@ namespace App\DataMapper;
*/
class BaseSettings
{
//@deprecated
public function __construct($obj)
{
// foreach ($obj as $key => $value) {
// $obj->{$key} = $value;
// }
}
// //@deprecated
// public function __construct($obj)
// {
// // foreach ($obj as $key => $value) {
// // $obj->{$key} = $value;
// // }
// }
public static function setCasts($obj, $casts)
{

View File

@ -47,17 +47,17 @@ class ClientSettings extends BaseSettings
'send_reminders' => 'bool',
];
/**
* Cast object values and return entire class
* prevents missing properties from not being returned
* and always ensure an up to date class is returned.
*
* @param $obj
*/
public function __construct($obj)
{
parent::__construct($obj);
}
// /**
// * Cast object values and return entire class
// * prevents missing properties from not being returned
// * and always ensure an up to date class is returned.
// *
// * @param $obj
// */
// public function __construct($obj)
// {
// // parent::__construct($obj);
// }
/**
* Default Client Settings scaffold.
@ -78,8 +78,8 @@ class ClientSettings extends BaseSettings
/**
* Merges settings from Company to Client.
*
* @param stdClass $company_settings
* @param stdClass $client_settings
* @param $company_settings
* @param $client_settings
* @return stdClass of merged settings
*/
public static function buildClientSettings($company_settings, $client_settings)

View File

@ -767,18 +767,18 @@ class CompanySettings extends BaseSettings
'purchase_order_design_id',
];
/**
* Cast object values and return entire class
* prevents missing properties from not being returned
* and always ensure an up to date class is returned.
*
* @param $obj
* @deprecated
*/
public function __construct()
{
// parent::__construct($obj);
}
// /**
// * Cast object values and return entire class
// * prevents missing properties from not being returned
// * and always ensure an up to date class is returned.
// *
// * @param $obj
// * @deprecated
// */
// public function __construct()
// {
// // parent::__construct($obj);
// }
/**
* Provides class defaults on init.

View File

@ -34,13 +34,4 @@ class DefaultSettings extends BaseSettings
];
}
/**
* @return stdClass
*/
private static function userSettingsObject() : stdClass
{
return (object) [
// 'per_page' => self::$per_page,
];
}
}
}

View File

@ -24,92 +24,78 @@ class EmailTemplateDefaults
case 'email_template_invoice':
return self::emailInvoiceTemplate();
break;
case 'email_template_quote':
return self::emailQuoteTemplate();
break;
case 'email_template_credit':
return self::emailCreditTemplate();
break;
case 'email_template_payment':
return self::emailPaymentTemplate();
break;
case 'email_template_payment_partial':
return self::emailPaymentPartialTemplate();
break;
case 'email_template_statement':
return self::emailStatementTemplate();
break;
case 'email_template_reminder1':
return self::emailReminder1Template();
break;
case 'email_template_reminder2':
return self::emailReminder2Template();
break;
case 'email_template_reminder3':
return self::emailReminder3Template();
break;
case 'email_template_reminder_endless':
return self::emailReminderEndlessTemplate();
break;
case 'email_template_custom1':
return self::emailInvoiceTemplate();
break;
case 'email_template_custom2':
return self::emailInvoiceTemplate();
break;
case 'email_template_custom3':
return self::emailInvoiceTemplate();
case 'email_template_purchase_order':
return self::emailPurchaseOrderTemplate();
break;
/* Subject */
case 'email_subject_purchase_order':
return self::emailPurchaseOrderSubject();
case 'email_subject_invoice':
return self::emailInvoiceSubject();
break;
case 'email_subject_quote':
return self::emailQuoteSubject();
break;
case 'email_subject_credit':
return self::emailCreditSubject();
break;
case 'email_subject_payment':
return self::emailPaymentSubject();
break;
case 'email_subject_payment_partial':
return self::emailPaymentPartialSubject();
break;
case 'email_subject_statement':
return self::emailStatementSubject();
break;
case 'email_subject_reminder1':
return self::emailReminder1Subject();
break;
case 'email_subject_reminder2':
return self::emailReminder2Subject();
break;
case 'email_subject_reminder3':
return self::emailReminder3Subject();
break;
case 'email_subject_reminder_endless':
return self::emailReminderEndlessSubject();
break;
case 'email_subject_custom1':
return self::emailInvoiceSubject();
break;
case 'email_subject_custom2':
return self::emailInvoiceSubject();
break;
case 'email_subject_custom3':
return self::emailInvoiceSubject();
break;
default:
return self::emailInvoiceTemplate();
break;
}
}

View File

@ -141,7 +141,6 @@ class FreeCompanySettings extends BaseSettings
public static $casts = [
'portal_design_id' => 'string',
'currency_id' => 'string',
'task_number_pattern' => 'string',
'task_number_counter' => 'int',
'expense_number_pattern' => 'string',
@ -191,16 +190,16 @@ class FreeCompanySettings extends BaseSettings
'website' => 'string',
];
/**
* Cast object values and return entire class
* prevents missing properties from not being returned
* and always ensure an up to date class is returned.
*
* @param $obj
*/
public function __construct($obj)
{
}
// /**
// * Cast object values and return entire class
// * prevents missing properties from not being returned
// * and always ensure an up to date class is returned.
// *
// * @param $obj
// */
// public function __construct($obj)
// {
// }
/**
* Provides class defaults on init.
@ -223,7 +222,7 @@ class FreeCompanySettings extends BaseSettings
$data->date_format_id = (string) config('ninja.i18n.date_format_id');
$data->country_id = (string) config('ninja.i18n.country_id');
$data->translations = (object) [];
$data->pdf_variables = (object) self::getEntityVariableDefaults();
// $data->pdf_variables = (object) self::getEntityVariableDefaults();
return self::setCasts($data, self::$casts);
}

View File

@ -251,7 +251,7 @@ class Rule extends BaseRule implements RuleInterface
// }
$this->tax_rate = $this->client->company->tax_data->regions->AU->subregions->{$this->client->company->country()->iso_3166_2}->tax_rate;
$this->reduced_tax_rate = $this->client->company->tax_data->regions->AU->subregions->{$this->client->company->country()->iso_3166_2}->reduced_tax_rate;
$this->reduced_tax_rate = $this->client->company->tax_data->regions->AU->subregions->{$this->client->company->country()->iso_3166_2}->tax_rate;
return $this;

View File

@ -197,7 +197,7 @@ class BaseRule implements RuleInterface
}
/** If we are in a Origin based state, force the company tax here */
if($company->origin_tax_data?->originDestination == 'O' && ($company->tax_data?->seller_subregion == $this->client_subregion)) {
if($company->origin_tax_data->originDestination == 'O' && ($company->tax_data?->seller_subregion == $this->client_subregion)) {
$tax_data = $company->origin_tax_data;

View File

@ -33859,8 +33859,6 @@ class USStates
'99926' => 'AK',
'99927' => 'AK',
'99929' => 'AK',
'13021' => 'NY',
'13024' => 'NY',
];
public static function get(): array

View File

@ -30,7 +30,7 @@ class DesignWasCreated
/**
* Get the channels the event should broadcast on.
*
* @return PrivateChannel
* @return PrivateChannel|array
*/
public function broadcastOn()
{

View File

@ -30,7 +30,7 @@ class DesignWasDeleted
/**
* Get the channels the event should broadcast on.
*
* @return PrivateChannel
* @return PrivateChannel|array
*/
public function broadcastOn()
{

View File

@ -30,7 +30,7 @@ class DesignWasRestored
/**
* Get the channels the event should broadcast on.
*
* @return PrivateChannel
* @return PrivateChannel|array
*/
public function broadcastOn()
{

View File

@ -30,7 +30,7 @@ class DesignWasUpdated
/**
* Get the channels the event should broadcast on.
*
* @return PrivateChannel
* @return PrivateChannel|array
*/
public function broadcastOn()
{

View File

@ -17,8 +17,10 @@ use App\Utils\Ninja;
use Sentry\State\Scope;
use Illuminate\Support\Arr;
use Illuminate\Http\Request;
use InvalidArgumentException;
use Sentry\Laravel\Integration;
use Illuminate\Support\Facades\Schema;
use Aws\Exception\CredentialsException;
use GuzzleHttp\Exception\ConnectException;
use Illuminate\Auth\AuthenticationException;
use League\Flysystem\UnableToCreateDirectory;
@ -34,7 +36,6 @@ use Symfony\Component\Console\Exception\CommandNotFoundException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
use Illuminate\Database\Eloquent\ModelNotFoundException as ModelNotFoundException;
use InvalidArgumentException;
class Handler extends ExceptionHandler
{
@ -64,7 +65,7 @@ class Handler extends ExceptionHandler
ConnectException::class,
RuntimeException::class,
InvalidArgumentException::class,
Aws\Exception\CredentialsException::class,
CredentialsException::class,
];
protected $hostedDontReport = [

View File

@ -14,7 +14,7 @@ namespace App\Exceptions;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Http\JsonResponse;
class PaymentRefundFailed extends Exception
{
@ -32,14 +32,14 @@ class PaymentRefundFailed extends Exception
* Render the exception into an HTTP response.
*
* @param Request $request
* @return Response
* @return JsonResponse
*/
public function render($request)
{
// $msg = 'Unable to refund the transaction';
$msg = ctrans('texts.warning_local_refund');
if ($this->getMessage() && strlen($this->getMessage()) >= 1) {
if ($this->getMessage() && strlen($this->getMessage()) > 1) {
$msg = $this->getMessage();
}

View File

@ -14,7 +14,7 @@ namespace App\Exceptions;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Http\JsonResponse;
class QuoteConversion extends Exception
{
@ -32,7 +32,7 @@ class QuoteConversion extends Exception
* Render the exception into an HTTP response.
*
* @param Request $request
* @return Response
* @return JsonResponse
*/
public function render($request)
{

View File

@ -14,7 +14,7 @@ namespace App\Exceptions;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Http\JsonResponse;
class YodleeApiException extends Exception
{
@ -32,14 +32,14 @@ class YodleeApiException extends Exception
* Render the exception into an HTTP response.
*
* @param Request $request
* @return Response
* @return JsonResponse
*/
public function render($request)
{
// $msg = 'Unable to refund the transaction';
$msg = ctrans('texts.error');
if ($this->getMessage() && strlen($this->getMessage()) >= 1) {
if ($this->getMessage() && strlen($this->getMessage()) > 1) {
$msg = $this->getMessage();
}

View File

@ -373,6 +373,8 @@ class BaseExport
if(!is_array($parts) || count($parts) < 2)
return '';
$value = '';
match($parts[0]) {
'contact' => $value = $this->resolveClientContactKey($parts[1], $entity, $transformer),
'client' => $value = $this->resolveClientKey($parts[1], $entity, $transformer),
@ -385,7 +387,7 @@ class BaseExport
'purchase_order' => $value = $this->resolvePurchaseOrderKey($parts[1], $entity, $transformer),
'payment' => $value = $this->resolvePaymentKey($parts[1], $entity, $transformer),
'task' => $value = $this->resolveTaskKey($parts[1], $entity, $transformer),
default => $value = ''
default => $value = '',
};
return $value;
@ -580,6 +582,7 @@ class BaseExport
private function resolveInvoiceKey($column, $entity, $transformer)
{
nlog("searching for {$column}");
$transformed_invoice = false;
if($transformer instanceof PaymentTransformer) {
$transformed_invoices = $transformer->includeInvoices($entity);
@ -615,14 +618,14 @@ class BaseExport
}
if(array_key_exists($column, $transformed_invoice)) {
if($transformed_invoice && array_key_exists($column, $transformed_invoice)) {
return $transformed_invoice[$column];
} elseif (array_key_exists(str_replace("invoice.", "", $column), $transformed_invoice)) {
} elseif ($transformed_invoice && array_key_exists(str_replace("invoice.", "", $column), $transformed_invoice)) {
return $transformed_invoice[$column];
}
if($column == 'status')
return $entity->stringStatus($entity->status_id);
// if($column == 'status')
// return $entity->stringStatus($entity->status_id);
return '';
}

View File

@ -37,7 +37,7 @@ class BankTransactionFilters extends QueryFilters
/**
* Filter based on search text.
*
* @param string query filter
* @param string $filter
* @return Builder
* @deprecated
*/
@ -118,7 +118,7 @@ class BankTransactionFilters extends QueryFilters
/**
* Sorts the list based on $sort.
*
* @param string sort formatted as column|asc
* @param string $sort formatted as column|asc
* @return Builder
*/
public function sort(string $sort = ''): Builder

View File

@ -36,7 +36,7 @@ class BankTransactionRuleFilters extends QueryFilters
/**
* Filter based on search text.
*
* @param string query filter
* @param string $filter
* @return Builder
* @deprecated
*/
@ -54,7 +54,7 @@ class BankTransactionRuleFilters extends QueryFilters
/**
* Sorts the list based on $sort.
*
* @param string sort formatted as column|asc
* @param string $sort formatted as column|asc
* @return Builder
*/
public function sort(string $sort = ''): Builder

View File

@ -21,7 +21,7 @@ class PaymentTermFilters extends QueryFilters
/**
* Filter based on search text.
*
* @param string query filter
* @param string $filter
* @return Builder
* @deprecated
*/
@ -39,7 +39,7 @@ class PaymentTermFilters extends QueryFilters
/**
* Sorts the list based on $sort.
*
* @param string sort formatted as column|asc
* @param string $sort formatted as column|asc
* @return Builder
*/
public function sort(string $sort = ''): Builder

View File

@ -22,7 +22,7 @@ class QuoteFilters extends QueryFilters
/**
* Filter based on search text.
*
* @param string query filter
* @param string $filter
* @return Builder
* @deprecated
*/
@ -124,7 +124,7 @@ class QuoteFilters extends QueryFilters
/**
* Sorts the list based on $sort.
*
* @param string sort formatted as column|asc
* @param string $sort formatted as column|asc
* @return Builder
*/
public function sort(string $sort = ''): Builder

View File

@ -21,7 +21,7 @@ class RecurringExpenseFilters extends QueryFilters
/**
* Filter based on search text.
*
* @param string query filter
* @param string $filter
* @return Builder
* @deprecated
*/
@ -52,7 +52,7 @@ class RecurringExpenseFilters extends QueryFilters
/**
* Sorts the list based on $sort.
*
* @param string sort formatted as column|asc
* @param string $sort formatted as column|asc
* @return Builder
*/
public function sort(string $sort = ''): Builder

View File

@ -21,7 +21,7 @@ class SubscriptionFilters extends QueryFilters
/**
* Filter based on search text.
*
* @param string query filter
* @param string $filter
* @return Builder
* @deprecated
*/
@ -39,7 +39,7 @@ class SubscriptionFilters extends QueryFilters
/**
* Sorts the list based on $sort.
*
* @param string sort formatted as column|asc
* @param string $sort formatted as column|asc
* @return Builder
*/
public function sort(string $sort = ''): Builder

View File

@ -48,7 +48,7 @@ class SystemLogFilters extends QueryFilters
/**
* Filter based on search text.
*
* @param string query filter
* @param string $filter
* @return Builder
* @deprecated
*/
@ -64,7 +64,7 @@ class SystemLogFilters extends QueryFilters
/**
* Sorts the list based on $sort.
*
* @param string sort formatted as column|asc
* @param string $sort formatted as column|asc
* @return Builder
*/
public function sort(string $sort = ''): Builder

View File

@ -24,7 +24,7 @@ class TaskFilters extends QueryFilters
/**
* Filter based on search text.
*
* @param string query filter
* @param string $filter
* @return Builder
* @deprecated
*/
@ -99,7 +99,7 @@ class TaskFilters extends QueryFilters
/**
* Sorts the list based on $sort.
*
* @param string sort formatted as column|asc
* @param string $sort formatted as column|asc
* @return Builder
*/
public function sort(string $sort = ''): Builder
@ -131,8 +131,8 @@ class TaskFilters extends QueryFilters
$status_parameters = explode(',', $value);
if(count($status_parameters) > 0)
return $this->builder->whereIn('status_id', $this->transformKeys($status_parameters));
if(count($status_parameters) >= 1)
$this->builder->whereIn('status_id', $this->transformKeys($status_parameters));
return $this->builder;
}

View File

@ -21,7 +21,7 @@ class TaskStatusFilters extends QueryFilters
/**
* Filter based on search text.
*
* @param string query filter
* @param string $filter
* @return Builder
* @deprecated
*/
@ -39,7 +39,7 @@ class TaskStatusFilters extends QueryFilters
/**
* Sorts the list based on $sort.
*
* @param string sort formatted as column|asc
* @param string $sort formatted as column|asc
* @return Builder
*/
public function sort(string $sort = ''): Builder

View File

@ -21,7 +21,7 @@ class TaxRateFilters extends QueryFilters
/**
* Filter based on search text.
*
* @param string query filter
* @param string $filter
* @return Builder
* @deprecated
*/
@ -39,7 +39,7 @@ class TaxRateFilters extends QueryFilters
/**
* Sorts the list based on $sort.
*
* @param string sort formatted as column|asc
* @param string $sort formatted as column|asc
* @return Builder
*/
public function sort(string $sort = ''): Builder

View File

@ -21,7 +21,7 @@ class TokenFilters extends QueryFilters
/**
* Filter based on search text.
*
* @param string query filter
* @param string $filter
* @return Builder
* @deprecated
*/
@ -45,7 +45,7 @@ class TokenFilters extends QueryFilters
/**
* Sorts the list based on $sort.
*
* @param string sort formatted as column|asc
* @param string $sort formatted as column|asc
* @return Builder
*/
public function sort(string $sort = ''): Builder

View File

@ -21,7 +21,7 @@ class UserFilters extends QueryFilters
/**
* Filter based on search text.
*
* @param string query filter
* @param string $filter
* @return Builder
* @deprecated
*/
@ -43,7 +43,7 @@ class UserFilters extends QueryFilters
/**
* Sorts the list based on $sort.
*
* @param string sort formatted as column|asc
* @param string $sort formatted as column|asc
* @return Builder
*/
public function sort(string $sort = ''): Builder
@ -69,6 +69,19 @@ class UserFilters extends QueryFilters
});
}
/**
* Filters users that have been removed from the
* company, but not deleted from the system.
*
* @return void
*/
public function hideRemovedUsers()
{
return $this->builder->whereHas('company_users', function ($q) {
$q->where('company_id', '=', auth()->user()->company()->id)->whereNull('deleted_at');
});
}
/**
* Overrides the base with() function as no company ID
* exists on the user table

View File

@ -21,7 +21,7 @@ class VendorFilters extends QueryFilters
/**
* Filter based on search text.
*
* @param string query filter
* @param string $filter
* @return Builder
* @deprecated
*/
@ -58,7 +58,7 @@ class VendorFilters extends QueryFilters
/**
* Sorts the list based on $sort.
*
* @param string sort formatted as column|asc
* @param string $sort formatted as column|asc
* @return Builder
*/
public function sort(string $sort = ''): Builder

View File

@ -21,7 +21,7 @@ class WebhookFilters extends QueryFilters
/**
* Filter based on search text.
*
* @param string query filter
* @param string $filter
* @return Builder
* @deprecated
*/
@ -39,7 +39,7 @@ class WebhookFilters extends QueryFilters
/**
* Sorts the list based on $sort.
*
* @param string sort formatted as column|asc
* @param string $sort formatted as column|asc
* @return Builder
*/
public function sort(string $sort = ''): Builder

View File

@ -19,7 +19,7 @@ use Illuminate\View\View;
*
* @param $page
* @param bool $boolean
* @return bool
* @return bool | string
*/
function isActive($page, bool $boolean = false)
{
@ -40,8 +40,6 @@ function isActive($page, bool $boolean = false)
return true;
}
return false;
}

View File

@ -53,9 +53,8 @@ class EpcQrGenerator
$qr = $writer->writeString($this->encodeMessage(), 'utf-8');
} catch(\Throwable $e) {
return '';
} catch(\Exception $e) {
return '';
}
}
return "<svg viewBox='0 0 200 200' width='200' height='200' x='0' y='0' xmlns='http://www.w3.org/2000/svg'>
<rect x='0' y='0' width='100%'' height='100%' />{$qr}</svg>";
}

View File

@ -12,6 +12,7 @@
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use App\Models\BankIntegration;
use App\Utils\Traits\MakesHash;
use Illuminate\Http\JsonResponse;
@ -50,7 +51,7 @@ class BankIntegrationController extends BaseController
/**
* @param BankIntegrationFilters $filters
* @return Responsec
* @return Response
*/
public function index(BankIntegrationFilters $filters)
{
@ -250,7 +251,7 @@ class BankIntegrationController extends BaseController
* Return the remote list of accounts stored on the third party provider
* and update our local cache.
*
* @return Response
* @return Response | JsonResponse
*
*/

View File

@ -71,7 +71,7 @@ class BankTransactionController extends BaseController
public function create(CreateBankTransactionRequest $request)
{
$bank_transaction = BankTransactionFactory::create(auth()->user()->company()->id, auth()->user()->id, auth()->user()->account_id);
$bank_transaction = BankTransactionFactory::create(auth()->user()->company()->id, auth()->user()->id);
return $this->itemResponse($bank_transaction);
}
@ -79,7 +79,7 @@ class BankTransactionController extends BaseController
public function store(StoreBankTransactionRequest $request)
{
//stub to store the model
$bank_transaction = $this->bank_transaction_repo->save($request->all(), BankTransactionFactory::create(auth()->user()->company()->id, auth()->user()->id, auth()->user()->account_id));
$bank_transaction = $this->bank_transaction_repo->save($request->all(), BankTransactionFactory::create(auth()->user()->company()->id, auth()->user()->id));
return $this->itemResponse($bank_transaction);
}

View File

@ -185,7 +185,7 @@ class QuoteController extends Controller
$quote->service()->approve(auth()->user())->save();
if (request()->has('signature') && ! is_null(request()->signature) && ! empty(request()->signature)) {
InjectSignature::dispatch($quote, request()->signature);
InjectSignature::dispatch($quote, auth()->guard('contact')->user()->id, request()->signature, request()->getClientIp());
}
}

View File

@ -186,8 +186,7 @@ class PurchaseOrderController extends Controller
->save();
if (request()->has('signature') && ! is_null(request()->signature) && ! empty(request()->signature)) {
(new InjectSignature($purchase_order, request()->signature))->handle();
// InjectSignature::dispatch($purchase_order, request()->signature);
(new InjectSignature($purchase_order, auth()->guard('vendor')->user()->id, request()->signature, request()->getClientIp()))->handle();
}
event(new PurchaseOrderWasAccepted($purchase_order, auth()->guard('vendor')->user(), $purchase_order->company, Ninja::eventVars()));

View File

@ -53,6 +53,8 @@ class PdfSlot extends Component
public $route_entity = 'client';
public $is_quote = false;
public function mount()
{
MultiDB::setDb($this->db);
@ -111,9 +113,9 @@ class PdfSlot extends Component
$this->show_line_total = in_array('$product.line_total', $this->settings->pdf_variables->product_quote_columns);
}
$this->html_variables = $this->entity->client ?
(new HtmlEngine($this->invitation))->generateLabelsAndValues() :
(new VendorHtmlEngine($this->invitation))->generateLabelsAndValues();
$this->html_variables = $this->entity_type == 'purchase_order' ?
(new VendorHtmlEngine($this->invitation))->generateLabelsAndValues() :
(new HtmlEngine($this->invitation))->generateLabelsAndValues();
return render('components.livewire.pdf-slot', [
'invitation' => $this->invitation,
@ -230,15 +232,16 @@ class PdfSlot extends Component
private function getProducts()
{
$product_items = collect($this->entity->line_items)->filter(function ($item) {
return $item->type_id == 1 || $item->type_id == 6 || $item->type_id == 5;
})->map(function ($item){
$notes = strlen($item->notes) > 4 ? $item->notes : $item->product_key;
return [
'quantity' => $item->quantity,
'cost' => Number::formatMoney($item->cost, $this->entity->client ?: $this->entity->vendor),
'notes' => $this->invitation->company->markdown_enabled ? DesignHelpers::parseMarkdownToHtml($item->notes) : $item->notes,
'notes' => $this->invitation->company->markdown_enabled ? DesignHelpers::parseMarkdownToHtml($notes) : $notes,
'line_total' => Number::formatMoney($item->line_total, $this->entity->client ?: $this->entity->vendor),
];
});
@ -268,6 +271,7 @@ class PdfSlot extends Component
if ($this->invitation instanceof InvoiceInvitation) {
return 'invoice';
} elseif ($this->invitation instanceof QuoteInvitation) {
$this->is_quote = true;
return 'quote';
} elseif ($this->invitation instanceof CreditInvitation) {
return 'credit';

View File

@ -47,11 +47,11 @@ class MatchBankTransactions implements ShouldQueue
private array $input;
protected Company $company;
protected ?Company $company;
public Invoice $invoice;
private BankTransaction $bt;
private ?BankTransaction $bt;
private $categories;
@ -78,8 +78,6 @@ class MatchBankTransactions implements ShouldQueue
/**
* Execute the job.
*
*
* @return void
*/
public function handle()
{

View File

@ -108,10 +108,12 @@ class ProcessBankTransactions implements ShouldQueue
$at = new AccountTransformer();
$account = $at->transform($account_summary);
$this->bank_integration->balance = $account['current_balance'];
$this->bank_integration->currency = $account['account_currency'];
$this->bank_integration->save();
if($account[0]['current_balance']) {
$this->bank_integration->balance = $account['current_balance'];
$this->bank_integration->currency = $account['account_currency'];
$this->bank_integration->save();
}
}
}
catch(\Exception $e) {

View File

@ -52,7 +52,7 @@ class CompanyTaxRate implements ShouldQueue
/** State must be calculated else default to the company state for taxes */
if(array_key_exists($this->company->settings->state, USStates::get())) {
$calculated_state = $this->company->setting->state;
$calculated_state = $this->company->settings->state;
}
else {

View File

@ -2,21 +2,19 @@
namespace App\Jobs\Invoice;
use App\Jobs\Entity\CreateEntityPdf;
use App\Jobs\Vendor\CreatePurchaseOrderPdf;
use App\Models\PurchaseOrder;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class InjectSignature implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* @var App\Models\Invoice|App\Models\Quote
* @var \App\Models\Invoice | \App\Models\Quote | \App\Models\Credit | \App\Models\PurchaseOrder
*/
public $entity;
@ -25,17 +23,26 @@ class InjectSignature implements ShouldQueue
*/
public $signature;
public $contact_id;
public $ip;
/**
* Create a new job instance.
*
* @param $entity
* @param string $signature
*/
public function __construct($entity, string $signature)
public function __construct($entity, $contact_id, string $signature, ?string $ip)
{
$this->entity = $entity;
$this->contact_id = $contact_id;
$this->signature = $signature;
$this->ip = $ip;
}
/**
@ -45,20 +52,31 @@ class InjectSignature implements ShouldQueue
*/
public function handle()
{
$invitation = $this->entity->invitations->whereNotNull('signature_base64')->first();
$invitation = false;
if($this->entity instanceof PurchaseOrder){
$invitation = $this->entity->invitations()->where('vendor_contact_id', $this->contact_id)->first();
if(!$invitation)
$invitation = $this->entity->invitations->first();
}
else {
$invitation = $this->entity->invitations()->where('client_contact_id', $this->contact_id)->first();
if(!$invitation)
$invitation = $this->entity->invitations->first();
}
if (! $invitation) {
return;
}
$invitation->signature_base64 = $this->signature;
$invitation->signature_date = now();
$invitation->signature_ip = $this->ip;
$invitation->save();
$this->entity->refresh()->service()->touchPdf(true);
// if($this->entity instanceof PurchaseOrder)
// (new CreatePurchaseOrderPdf($invitation))->handle();
// else
// (new CreateEntityPdf($invitation))->handle();
}
}

View File

@ -13,6 +13,7 @@ namespace App\Models;
use App\Utils\Number;
use App\Utils\Traits\MakesHash;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
/**
* App\Models\Activity
@ -302,161 +303,120 @@ class Activity extends StaticModel
'backup',
];
/**
* @return mixed
*/
public function getHashedIdAttribute()
{
return $this->encodePrimaryKey($this->id);
}
/**
* @return mixed
*/
public function getEntityType()
{
return self::class;
}
/**
* @return mixed
*/
public function backup()
{
return $this->hasOne(Backup::class);
}
/**
* @return mixed
*/
public function history()
{
return $this->hasOne(Backup::class);
}
/**
* @return mixed
*/
public function user()
public function user() :BelongsTo
{
return $this->belongsTo(User::class)->withTrashed();
}
/**
* @return mixed
*/
public function contact()
{
return $this->belongsTo(ClientContact::class, 'client_contact_id', 'id')->withTrashed();
}
/**
* @return mixed
*/
public function client()
{
return $this->belongsTo(Client::class)->withTrashed();
}
/**
* @return mixed
*/
public function invoice()
{
return $this->belongsTo(Invoice::class)->withTrashed();
}
/**
* @return mixed
*/
public function vendor()
{
return $this->belongsTo(Vendor::class)->withTrashed();
}
/**
* @return mixed
*/
public function recurring_invoice()
{
return $this->belongsTo(RecurringInvoice::class)->withTrashed();
}
/**
* @return mixed
*/
public function credit()
{
return $this->belongsTo(Credit::class)->withTrashed();
}
/**
* @return mixed
*/
public function quote()
{
return $this->belongsTo(Quote::class)->withTrashed();
}
/**
* @return mixed
*/
public function subscription()
{
return $this->belongsTo(Subscription::class)->withTrashed();
}
/**
* @return mixed
*/
public function payment()
{
return $this->belongsTo(Payment::class)->withTrashed();
}
/**
* @return mixed
*/
public function expense()
{
return $this->belongsTo(Expense::class)->withTrashed();
}
/**
* @return mixed
*/
public function recurring_expense()
{
return $this->belongsTo(RecurringExpense::class)->withTrashed();
}
/**
* @return mixed
*/
public function purchase_order()
{
return $this->belongsTo(PurchaseOrder::class)->withTrashed();
}
/**
* @return mixed
*/
public function vendor_contact()
{
return $this->belongsTo(VendorContact::class)->withTrashed();
}
/**
* @return mixed
*/
public function task()
{
return $this->belongsTo(Task::class)->withTrashed();
}
/**
* @return mixed
*/
public function company()
{
return $this->belongsTo(Company::class);

View File

@ -50,12 +50,6 @@ class BankAccount extends BaseModel
{
use SoftDeletes;
/**
* @var array
*/
/**
* @var array
*/
protected $fillable = [
'bank_id',
'app_version',

View File

@ -31,30 +31,35 @@ use Illuminate\Database\Eloquent\ModelNotFoundException as ModelNotFoundExceptio
* @property-read mixed $hashed_id
* @property string $number
* @property int $company_id
* @property int $id
* @property \App\Models\Company $company
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel|Illuminate\Database\Eloquent\Relations\BelongsTo|\Awobaz\Compoships\Database\Eloquent\Relations\BelongsTo|\App\Models\Company company()
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel|Illuminate\Database\Eloquent\Relations\HasMany|BaseModel orderBy()
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel exclude($columns)
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel with()
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel newQuery()
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel with($value)
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel newModelQuery($query)
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel newQuery($query)
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel query()
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel exclude(array $excludeable)
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel withTrashed()
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel scopeExclude()
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel find()
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel whereIn()
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel where()
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel scopeExclude($query)
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel find($value)
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel whereIn($query)
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel where($query)
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel count()
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel create()
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel insert()
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel create($query)
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel insert($query)
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel service()
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel whereHas()
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel withTrashed()
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel orderBy($column, $direction)
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel invitations()
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel createInvitations()
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel whereHas($query)
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\InvoiceInvitation | \App\Models\CreditInvitation | \App\Models\QuoteInvitation | \App\Models\RecurringInvoiceInvitation> $invitations
* @property-read int|null $invitations_count
*
* @method \App\Models\Company company()
* @method int companyId()
* @method createInvitations()
* @method Builder|static exclude($columns)
* @method static \Illuminate\Database\Eloquent\Builder exclude(array $columns)
* @mixin \Eloquent

View File

@ -11,21 +11,26 @@
namespace App\Models;
use App\Models\GatewayType;
use App\Utils\Traits\AppSetup;
use App\Utils\Traits\MakesHash;
use App\Utils\Traits\MakesDates;
use App\DataMapper\FeesAndLimits;
use App\Models\Traits\Excludable;
use App\DataMapper\ClientSettings;
use App\DataMapper\CompanySettings;
use App\DataMapper\FeesAndLimits;
use App\Models\Presenters\ClientPresenter;
use App\Models\Traits\Excludable;
use App\Services\Client\ClientService;
use App\Utils\Traits\AppSetup;
use App\Utils\Traits\ClientGroupSettingsSaver;
use App\Utils\Traits\GeneratesCounter;
use App\Utils\Traits\MakesDates;
use App\Utils\Traits\MakesHash;
use Illuminate\Contracts\Translation\HasLocalePreference;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Facades\Cache;
use App\Services\Client\ClientService;
use App\Utils\Traits\GeneratesCounter;
use Laracasts\Presenter\PresentableTrait;
use App\Models\Presenters\ClientPresenter;
use Illuminate\Database\Eloquent\SoftDeletes;
use App\Utils\Traits\ClientGroupSettingsSaver;
use App\Libraries\Currency\Conversion\CurrencyApi;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Contracts\Translation\HasLocalePreference;
/**
* App\Models\Client
@ -65,6 +70,7 @@ use Laracasts\Presenter\PresentableTrait;
* @property string|null $shipping_postal_code
* @property int|null $shipping_country_id
* @property object|null $settings
* @property object|null $group_settings
* @property bool $is_deleted
* @property int|null $group_settings_id
* @property string|null $vat_number
@ -114,68 +120,12 @@ use Laracasts\Presenter\PresentableTrait;
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\RecurringInvoice> $recurring_invoices
* @property-read int|null $tasks_count
* @property-read \App\Models\User $user
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel company()
* @method static \Illuminate\Database\Eloquent\Builder|Client exclude($columns)
* @method static \Database\Factories\ClientFactory factory($count = null, $state = [])
* @method static \Illuminate\Database\Eloquent\Builder|Client filter(\App\Filters\QueryFilters $filters)
* @method static \Illuminate\Database\Eloquent\Builder|Client newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|Client newQuery()
* @method static \Illuminate\Database\Eloquent\Builder|Client onlyTrashed()
* @method static \Illuminate\Database\Eloquent\Builder|Client query()
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel scope()
* @method static \Illuminate\Database\Eloquent\Builder|Client whereAddress1($value)
* @method static \Illuminate\Database\Eloquent\Builder|Client whereAddress2($value)
* @method static \Illuminate\Database\Eloquent\Builder|Client whereAssignedUserId($value)
* @method static \Illuminate\Database\Eloquent\Builder|Client whereBalance($value)
* @method static \Illuminate\Database\Eloquent\Builder|Client whereCity($value)
* @method static \Illuminate\Database\Eloquent\Builder|Client whereClientHash($value)
* @method static \Illuminate\Database\Eloquent\Builder|Client whereCompanyId($value)
* @method static \Illuminate\Database\Eloquent\Builder|Client whereCountryId($value)
* @method static \Illuminate\Database\Eloquent\Builder|Client whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|Client whereCreditBalance($value)
* @method static \Illuminate\Database\Eloquent\Builder|Client whereCustomValue1($value)
* @method static \Illuminate\Database\Eloquent\Builder|Client whereCustomValue2($value)
* @method static \Illuminate\Database\Eloquent\Builder|Client whereCustomValue3($value)
* @method static \Illuminate\Database\Eloquent\Builder|Client whereCustomValue4($value)
* @method static \Illuminate\Database\Eloquent\Builder|Client whereDeletedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|Client whereGroupSettingsId($value)
* @method static \Illuminate\Database\Eloquent\Builder|Client whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder|Client whereIdNumber($value)
* @method static \Illuminate\Database\Eloquent\Builder|Client whereIndustryId($value)
* @method static \Illuminate\Database\Eloquent\Builder|Client whereIsDeleted($value)
* @method static \Illuminate\Database\Eloquent\Builder|Client whereLastLogin($value)
* @method static \Illuminate\Database\Eloquent\Builder|Client whereLogo($value)
* @method static \Illuminate\Database\Eloquent\Builder|Client whereName($value)
* @method static \Illuminate\Database\Eloquent\Builder|Client whereNumber($value)
* @method static \Illuminate\Database\Eloquent\Builder|Client wherePaidToDate($value)
* @method static \Illuminate\Database\Eloquent\Builder|Client wherePhone($value)
* @method static \Illuminate\Database\Eloquent\Builder|Client wherePostalCode($value)
* @method static \Illuminate\Database\Eloquent\Builder|Client wherePrivateNotes($value)
* @method static \Illuminate\Database\Eloquent\Builder|Client wherePublicNotes($value)
* @method static \Illuminate\Database\Eloquent\Builder|Client whereSettings($value)
* @method static \Illuminate\Database\Eloquent\Builder|Client whereShippingAddress1($value)
* @method static \Illuminate\Database\Eloquent\Builder|Client whereShippingAddress2($value)
* @method static \Illuminate\Database\Eloquent\Builder|Client whereShippingCity($value)
* @method static \Illuminate\Database\Eloquent\Builder|Client whereShippingCountryId($value)
* @method static \Illuminate\Database\Eloquent\Builder|Client whereShippingPostalCode($value)
* @method static \Illuminate\Database\Eloquent\Builder|Client whereShippingState($value)
* @method static \Illuminate\Database\Eloquent\Builder|Client whereSizeId($value)
* @method static \Illuminate\Database\Eloquent\Builder|Client whereState($value)
* @method static \Illuminate\Database\Eloquent\Builder|Client whereUpdatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|Client whereUserId($value)
* @method static \Illuminate\Database\Eloquent\Builder|Client whereVatNumber($value)
* @method static \Illuminate\Database\Eloquent\Builder|Client whereWebsite($value)
* @method static \Illuminate\Database\Eloquent\Builder|Client withTrashed()
* @method static \Illuminate\Database\Eloquent\Builder|Client withoutTrashed()
* @method static \Illuminate\Database\Eloquent\Builder|Client with()
* @method static \Illuminate\Database\Eloquent\Builder|Client where()
* @property string $payment_balance
* @method static \Illuminate\Database\Eloquent\Builder|Client wherePaymentBalance($value)
* @property mixed $tax_data
* @method static \Illuminate\Database\Eloquent\Builder|Client whereTaxData($value)
* @property int $is_tax_exempt
* @method static \Illuminate\Database\Eloquent\Builder|Client whereIsTaxExempt($value)
* @property int $has_valid_vat_number
* @mixin \Eloquent
*/
@ -357,62 +307,62 @@ class Client extends BaseModel implements HasLocalePreference
return $this->hasMany(Activity::class)->take(50)->orderBy('id', 'desc');
}
public function contacts()
public function contacts() :HasMany
{
return $this->hasMany(ClientContact::class)->orderBy('is_primary', 'desc');
}
public function primary_contact()
public function primary_contact():HasMany
{
return $this->hasMany(ClientContact::class)->where('is_primary', true);
}
public function company()
public function company() :BelongsTo
{
return $this->belongsTo(Company::class);
}
public function user()
public function user() :BelongsTo
{
return $this->belongsTo(User::class)->withTrashed();
}
public function assigned_user()
public function assigned_user() :BelongsTo
{
return $this->belongsTo(User::class, 'assigned_user_id', 'id')->withTrashed();
}
public function country()
public function country() :BelongsTo
{
return $this->belongsTo(Country::class);
}
public function invoices()
public function invoices() :HasMany
{
return $this->hasMany(Invoice::class)->withTrashed();
}
public function quotes()
public function quotes() :HasMany
{
return $this->hasMany(Quote::class)->withTrashed();
}
public function tasks()
public function tasks() :HasMany
{
return $this->hasMany(Task::class)->withTrashed();
}
public function payments()
public function payments() :HasMany
{
return $this->hasMany(Payment::class)->withTrashed();
}
public function recurring_invoices()
public function recurring_invoices() :HasMany
{
return $this->hasMany(RecurringInvoice::class)->withTrashed();
}
public function recurring_expenses()
public function recurring_expenses() :HasMany
{
return $this->hasMany(RecurringExpense::class)->withTrashed();
}
@ -422,12 +372,12 @@ class Client extends BaseModel implements HasLocalePreference
return $this->belongsTo(Country::class, 'shipping_country_id', 'id');
}
public function system_logs()
public function system_logs() :HasMany
{
return $this->hasMany(SystemLog::class)->take(50)->orderBy('id', 'desc');
}
public function timezone()
public function timezone() :Timezone
{
return Timezone::find($this->getSetting('timezone_id'));
}
@ -445,17 +395,17 @@ class Client extends BaseModel implements HasLocalePreference
})->first();
}
public function industry()
public function industry() :BelongsTo
{
return $this->belongsTo(Industry::class);
}
public function size()
public function size() :BelongsTo
{
return $this->belongsTo(Size::class);
}
public function locale()
public function locale() :string
{
if (! $this->language()) {
return 'en';
@ -526,7 +476,7 @@ class Client extends BaseModel implements HasLocalePreference
* @param string $setting The Setting parameter
* @return mixed The setting requested
*/
public function getSetting($setting)
public function getSetting($setting) :mixed
{
/*Client Settings*/
if ($this->settings && property_exists($this->settings, $setting) && isset($this->settings->{$setting})) {
@ -556,7 +506,6 @@ class Client extends BaseModel implements HasLocalePreference
return '';
// throw new \Exception("Settings corrupted", 1);
}
public function getSettingEntity($setting)
@ -582,12 +531,12 @@ class Client extends BaseModel implements HasLocalePreference
throw new \Exception('Could not find a settings object', 1);
}
public function documents()
public function documents() :MorphMany
{
return $this->morphMany(Document::class, 'documentable');
}
public function group_settings()
public function group_settings() :BelongsTo
{
return $this->belongsTo(GroupSetting::class);
}
@ -710,7 +659,7 @@ class Client extends BaseModel implements HasLocalePreference
}
}
public function getCurrencyCode()
public function getCurrencyCode(): string
{
if ($this->currency()) {
return $this->currency()->code;
@ -751,51 +700,51 @@ class Client extends BaseModel implements HasLocalePreference
})->first()->locale;
}
public function backup_path()
public function backup_path() :string
{
return $this->company->company_key.'/'.$this->client_hash.'/backups';
}
public function invoice_filepath($invitation)
public function invoice_filepath($invitation) :string
{
$contact_key = $invitation->contact->contact_key;
return $this->company->company_key.'/'.$this->client_hash.'/'.$contact_key.'/invoices/';
}
public function e_invoice_filepath($invitation)
public function e_invoice_filepath($invitation) :string
{
$contact_key = $invitation->contact->contact_key;
return $this->company->company_key.'/'.$this->client_hash.'/'.$contact_key.'/e_invoice/';
}
public function quote_filepath($invitation)
public function quote_filepath($invitation) :string
{
$contact_key = $invitation->contact->contact_key;
return $this->company->company_key.'/'.$this->client_hash.'/'.$contact_key.'/quotes/';
}
public function credit_filepath($invitation)
public function credit_filepath($invitation) :string
{
$contact_key = $invitation->contact->contact_key;
return $this->company->company_key.'/'.$this->client_hash.'/'.$contact_key.'/credits/';
}
public function recurring_invoice_filepath($invitation)
public function recurring_invoice_filepath($invitation) :string
{
$contact_key = $invitation->contact->contact_key;
return $this->company->company_key.'/'.$this->client_hash.'/'.$contact_key.'/recurring_invoices/';
}
public function company_filepath()
public function company_filepath() :string
{
return $this->company->company_key.'/';
}
public function document_filepath()
public function document_filepath() :string
{
return $this->company->company_key.'/documents/';
}
@ -820,10 +769,13 @@ class Client extends BaseModel implements HasLocalePreference
$defaults['public_notes'] = $this->public_notes;
}
$exchange_rate = new CurrencyApi();
$defaults['exchange_rate'] = 1/$exchange_rate->exchangeRate($this->getSetting('currency_id'), $this->company->settings->currency_id);
return $defaults;
}
public function timezone_offset()
public function timezone_offset() :int
{
$offset = 0;
@ -853,7 +805,7 @@ class Client extends BaseModel implements HasLocalePreference
];
}
public function translate_entity()
public function translate_entity() :string
{
return ctrans('texts.client');
}

View File

@ -130,59 +130,8 @@ use Laracasts\Presenter\PresentableTrait;
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\RecurringInvoiceInvitation> $recurring_invoice_invitations
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CreditInvitation> $credit_invitations
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\InvoiceInvitation> $invoice_invitations
* @property-read \Illuminate\Notifications\DatabaseNotificationCollection<int, \Illuminate\Notifications\DatabaseNotification> $notifications
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\QuoteInvitation> $quote_invitations
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\RecurringInvoiceInvitation> $recurring_invoice_invitations
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CreditInvitation> $credit_invitations
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\InvoiceInvitation> $invoice_invitations
* @property-read \Illuminate\Notifications\DatabaseNotificationCollection<int, \Illuminate\Notifications\DatabaseNotification> $notifications
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\QuoteInvitation> $quote_invitations
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\RecurringInvoiceInvitation> $recurring_invoice_invitations
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CreditInvitation> $credit_invitations
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\InvoiceInvitation> $invoice_invitations
* @property-read \Illuminate\Notifications\DatabaseNotificationCollection<int, \Illuminate\Notifications\DatabaseNotification> $notifications
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\QuoteInvitation> $quote_invitations
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\RecurringInvoiceInvitation> $recurring_invoice_invitations
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CreditInvitation> $credit_invitations
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\InvoiceInvitation> $invoice_invitations
* @property-read \Illuminate\Notifications\DatabaseNotificationCollection<int, \Illuminate\Notifications\DatabaseNotification> $notifications
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\QuoteInvitation> $quote_invitations
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\RecurringInvoiceInvitation> $recurring_invoice_invitations
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CreditInvitation> $credit_invitations
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\InvoiceInvitation> $invoice_invitations
* @property-read \Illuminate\Notifications\DatabaseNotificationCollection<int, \Illuminate\Notifications\DatabaseNotification> $notifications
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\QuoteInvitation> $quote_invitations
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\RecurringInvoiceInvitation> $recurring_invoice_invitations
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CreditInvitation> $credit_invitations
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\InvoiceInvitation> $invoice_invitations
* @property-read \Illuminate\Notifications\DatabaseNotificationCollection<int, \Illuminate\Notifications\DatabaseNotification> $notifications
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\QuoteInvitation> $quote_invitations
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\RecurringInvoiceInvitation> $recurring_invoice_invitations
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CreditInvitation> $credit_invitations
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\InvoiceInvitation> $invoice_invitations
* @property-read \Illuminate\Notifications\DatabaseNotificationCollection<int, \Illuminate\Notifications\DatabaseNotification> $notifications
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\QuoteInvitation> $quote_invitations
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\RecurringInvoiceInvitation> $recurring_invoice_invitations
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CreditInvitation> $credit_invitations
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\InvoiceInvitation> $invoice_invitations
* @property-read \Illuminate\Notifications\DatabaseNotificationCollection<int, \Illuminate\Notifications\DatabaseNotification> $notifications
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\QuoteInvitation> $quote_invitations
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\RecurringInvoiceInvitation> $recurring_invoice_invitations
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CreditInvitation> $credit_invitations
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\InvoiceInvitation> $invoice_invitations
* @property-read \Illuminate\Notifications\DatabaseNotificationCollection<int, \Illuminate\Notifications\DatabaseNotification> $notifications
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\QuoteInvitation> $quote_invitations
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\RecurringInvoiceInvitation> $recurring_invoice_invitations
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CreditInvitation> $credit_invitations
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\InvoiceInvitation> $invoice_invitations
* @property-read \Illuminate\Notifications\DatabaseNotificationCollection<int, \Illuminate\Notifications\DatabaseNotification> $notifications
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\QuoteInvitation> $quote_invitations
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\RecurringInvoiceInvitation> $recurring_invoice_invitations
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\CreditInvitation> $credit_invitations
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\InvoiceInvitation> $invoice_invitations
* @property-read \Illuminate\Notifications\DatabaseNotificationCollection<int, \Illuminate\Notifications\DatabaseNotification> $notifications
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\QuoteInvitation> $quote_invitations
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\RecurringInvoiceInvitation> $recurring_invoice_invitations
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Client> $client
* @mixin \Eloquent
*/
class ClientContact extends Authenticatable implements HasLocalePreference

View File

@ -37,29 +37,6 @@ use Illuminate\Database\Eloquent\SoftDeletes;
* @property-read \App\Models\GatewayType|null $gateway_type
* @property-read mixed $hashed_id
* @property-read \App\Models\User $user
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel company()
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel exclude($columns)
* @method static \Illuminate\Database\Eloquent\Builder|ClientGatewayToken newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|ClientGatewayToken newQuery()
* @method static \Illuminate\Database\Eloquent\Builder|ClientGatewayToken onlyTrashed()
* @method static \Illuminate\Database\Eloquent\Builder|ClientGatewayToken query()
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel scope()
* @method static \Illuminate\Database\Eloquent\Builder|ClientGatewayToken whereClientId($value)
* @method static \Illuminate\Database\Eloquent\Builder|ClientGatewayToken whereCompanyGatewayId($value)
* @method static \Illuminate\Database\Eloquent\Builder|ClientGatewayToken whereCompanyId($value)
* @method static \Illuminate\Database\Eloquent\Builder|ClientGatewayToken whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|ClientGatewayToken whereDeletedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|ClientGatewayToken whereGatewayCustomerReference($value)
* @method static \Illuminate\Database\Eloquent\Builder|ClientGatewayToken whereGatewayTypeId($value)
* @method static \Illuminate\Database\Eloquent\Builder|ClientGatewayToken whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder|ClientGatewayToken whereIsDefault($value)
* @method static \Illuminate\Database\Eloquent\Builder|ClientGatewayToken whereIsDeleted($value)
* @method static \Illuminate\Database\Eloquent\Builder|ClientGatewayToken whereMeta($value)
* @method static \Illuminate\Database\Eloquent\Builder|ClientGatewayToken whereRoutingNumber($value)
* @method static \Illuminate\Database\Eloquent\Builder|ClientGatewayToken whereToken($value)
* @method static \Illuminate\Database\Eloquent\Builder|ClientGatewayToken whereUpdatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|ClientGatewayToken withTrashed()
* @method static \Illuminate\Database\Eloquent\Builder|ClientGatewayToken withoutTrashed()
* @mixin \Eloquent
*/
class ClientGatewayToken extends BaseModel

View File

@ -393,17 +393,17 @@ class Company extends BaseModel
return $this->morphMany(Document::class, 'documentable');
}
public function schedulers()
public function schedulers() :HasMany
{
return $this->hasMany(Scheduler::class);
}
public function task_schedulers() //alias for schedulers
public function task_schedulers() :HasMany
{
return $this->hasMany(Scheduler::class);
}
public function all_documents()
public function all_documents() :HasMany
{
return $this->hasMany(Document::class);
}
@ -413,22 +413,22 @@ class Company extends BaseModel
return self::class;
}
public function ledger()
public function ledger() :HasMany
{
return $this->hasMany(CompanyLedger::class);
}
public function bank_integrations()
public function bank_integrations() :HasMany
{
return $this->hasMany(BankIntegration::class);
}
public function bank_transactions()
public function bank_transactions() :HasMany
{
return $this->hasMany(BankTransaction::class);
}
public function bank_transaction_rules()
public function bank_transaction_rules() :HasMany
{
return $this->hasMany(BankTransactionRule::class);
}
@ -443,7 +443,7 @@ class Company extends BaseModel
return $this->belongsTo(Account::class);
}
public function client_contacts()
public function client_contacts() :HasMany
{
return $this->hasMany(ClientContact::class)->withTrashed();
}
@ -453,27 +453,27 @@ class Company extends BaseModel
return $this->hasManyThrough(User::class, CompanyUser::class, 'company_id', 'id', 'id', 'user_id')->withTrashed();
}
public function expense_categories()
public function expense_categories() :HasMany
{
return $this->hasMany(ExpenseCategory::class)->withTrashed();
}
public function subscriptions()
public function subscriptions() :HasMany
{
return $this->hasMany(Subscription::class)->withTrashed();
}
public function purchase_orders()
public function purchase_orders() :HasMany
{
return $this->hasMany(PurchaseOrder::class)->withTrashed();
}
public function task_statuses()
public function task_statuses() :HasMany
{
return $this->hasMany(TaskStatus::class)->withTrashed();
}
public function clients()
public function clients() :HasMany
{
return $this->hasMany(Client::class)->withTrashed();
}
@ -481,12 +481,12 @@ class Company extends BaseModel
/**
* @return HasMany
*/
public function tasks()
public function tasks() :HasMany
{
return $this->hasMany(Task::class)->withTrashed();
}
public function webhooks()
public function webhooks() :HasMany
{
return $this->hasMany(Webhook::class);
}
@ -494,7 +494,7 @@ class Company extends BaseModel
/**
* @return HasMany
*/
public function projects()
public function projects() :HasMany
{
return $this->hasMany(Project::class)->withTrashed();
}
@ -502,17 +502,17 @@ class Company extends BaseModel
/**
* @return HasMany
*/
public function vendors()
public function vendors() :HasMany
{
return $this->hasMany(Vendor::class)->withTrashed();
}
public function all_activities()
public function all_activities() :HasMany
{
return $this->hasMany(Activity::class);
}
public function activities()
public function activities() :HasMany
{
return $this->hasMany(Activity::class)->orderBy('id', 'DESC')->take(50);
}

View File

@ -28,7 +28,7 @@ use Illuminate\Database\Eloquent\SoftDeletes;
* @property int|null $update_details
* @property int $is_deleted
* @property string $config
* @property object $fees_and_limits
* @property mixed $fees_and_limits
* @property string|null $custom_value1
* @property string|null $custom_value2
* @property string|null $custom_value3
@ -232,7 +232,8 @@ class CompanyGateway extends BaseModel
/* This is the public entry point into the payment superclass */
public function driver(Client $client = null)
{
$class = static::driver_class();
// $class = static::driver_class();
$class = self::driver_class();
if (!$class) {
return false;
@ -343,10 +344,10 @@ class CompanyGateway extends BaseModel
return ! empty($this->getConfigField('enable_pay_pal'));
}
public function feesEnabled()
{
return floatval($this->fee_amount) || floatval($this->fee_percent);
}
// public function feesEnabled()
// {
// return floatval($this->fee_amount) || floatval($this->fee_percent);
// }
/**
* Returns the current test mode of the gateway.

View File

@ -53,7 +53,6 @@ use Illuminate\Database\Eloquent\SoftDeletes;
* @method static \Illuminate\Database\Eloquent\Builder|CompanyToken whereUserId($value)
* @method static \Illuminate\Database\Eloquent\Builder|CompanyToken withTrashed()
* @method static \Illuminate\Database\Eloquent\Builder|CompanyToken withoutTrashed()
* @method static \Illuminate\Database\Eloquent\Builder|CompanyToken with()
* @mixin \Eloquent
*/
class CompanyToken extends BaseModel

View File

@ -180,7 +180,6 @@ class Gateway extends StaticModel
GatewayType::SEPA => ['refund' => false, 'token_billing' => true, 'webhooks' => [' ']],
GatewayType::INSTANT_BANK_PAY => ['refund' => false, 'token_billing' => true, 'webhooks' => [' ']],
];
break;
case 58:
return [
GatewayType::HOSTED_PAGE => ['refund' => false, 'token_billing' => false, 'webhooks' => [' ']], // Razorpay
@ -190,6 +189,20 @@ class Gateway extends StaticModel
GatewayType::CREDIT_CARD => ['refund' => true, 'token_billing' => true], // Forte
GatewayType::BANK_TRANSFER => ['refund' => true, 'token_billing' => true, 'webhooks' => [' ']],
];
case 60:
return [
GatewayType::PAYPAL => ['refund' => false, 'token_billing' => false],
GatewayType::CREDIT_CARD => ['refund' => false, 'token_billing' => false],
GatewayType::VENMO => ['refund' => false, 'token_billing' => false],
// GatewayType::SEPA => ['refund' => false, 'token_billing' => false],
// GatewayType::BANCONTACT => ['refund' => false, 'token_billing' => false],
// GatewayType::EPS => ['refund' => false, 'token_billing' => false],
// GatewayType::MYBANK => ['refund' => false, 'token_billing' => false],
// GatewayType::PAYLATER => ['refund' => false, 'token_billing' => false],
// GatewayType::PRZELEWY24 => ['refund' => false, 'token_billing' => false],
// GatewayType::SOFORT => ['refund' => false, 'token_billing' => false],
]; //Paypal
default:
return [];
}

View File

@ -29,17 +29,6 @@ namespace App\Models;
* @method static \Illuminate\Database\Eloquent\Builder|GatewayType whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder|GatewayType whereName($value)
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\PaymentType> $payment_methods
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\PaymentType> $payment_methods
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\PaymentType> $payment_methods
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\PaymentType> $payment_methods
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\PaymentType> $payment_methods
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\PaymentType> $payment_methods
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\PaymentType> $payment_methods
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\PaymentType> $payment_methods
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\PaymentType> $payment_methods
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\PaymentType> $payment_methods
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\PaymentType> $payment_methods
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\PaymentType> $payment_methods
* @mixin \Eloquent
*/
class GatewayType extends StaticModel
@ -94,6 +83,14 @@ class GatewayType extends StaticModel
const BACS = 24;
const VENMO = 25;
const MERCADOPAGO = 26;
const MYBANK = 27;
const PAYLATER = 28;
public function gateway()
{
return $this->belongsTo(Gateway::class);
@ -153,9 +150,17 @@ class GatewayType extends StaticModel
return ctrans('texts.fpx');
case self::KLARNA:
return ctrans('texts.klarna');
case self::VENMO:
return ctrans('texts.payment_type_Venmo');
case self::MERCADOPAGO:
return ctrans('texts.mercado_pago');
case self::MYBANK:
return ctrans('texts.mybank');
case self::PAYLATER:
return ctrans('texts.paypal_paylater');
default:
return ' ';
break;
}
}
}

View File

@ -57,9 +57,6 @@ class PaymentTerm extends BaseModel
*/
public $timestamps = true;
/**
* @var array
*/
protected $fillable = ['num_days'];
public function getNumDays()

View File

@ -25,8 +25,6 @@ class CompanyPresenter extends EntityPresenter
*/
public function name()
{
$settings = $this->entity->settings;
return $this->settings->name ?: ctrans('texts.untitled_account');
}

View File

@ -53,7 +53,7 @@ class InvoicePresenter extends EntityPresenter
$properties->itemized_receipt[] = $this->itemRbits($item);
}
$data = new stdClass();
$data = new \stdClass();
$data->receive_time = time();
$data->type = 'transaction_details';
$data->source = 'user';
@ -64,7 +64,7 @@ class InvoicePresenter extends EntityPresenter
public function itemRbits($item)
{
$data = new stdClass();
$data = new \stdClass();
$data->description = $item->notes;
$data->item_price = floatval($item->cost);
$data->quantity = floatval($item->quantity);

View File

@ -106,12 +106,6 @@ class Project extends BaseModel
use PresentableTrait;
use Filterable;
/**
* @var array
*/
/**
* @var array
*/
protected $fillable = [
'name',
'client_id',

View File

@ -22,13 +22,13 @@ use Illuminate\Database\Eloquent\ModelNotFoundException as ModelNotFoundExceptio
* @property-read mixed $id
* @method static \Illuminate\Database\Eloquent\Builder|StaticModel company()
* @method static \Illuminate\Database\Eloquent\Builder|StaticModel exclude($columns)
* @method static \Illuminate\Database\Eloquent\Builder|StaticModel newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|StaticModel newQuery()
* @method static \Illuminate\Database\Eloquent\Builder|StaticModel query()
* @method static \Illuminate\Database\Eloquent\Builder|StaticModel find()
* @method static \Illuminate\Database\Eloquent\Builder|StaticModel with()
* @method static \Illuminate\Database\Eloquent\Builder|StaticModel withTrashed()
* @method static \Illuminate\Database\Eloquent\Builder|StaticModel findOrFail()
* @method static \Illuminate\Database\Eloquent\Builder|StaticModel newModelQuery($value)
* @method static \Illuminate\Database\Eloquent\Builder|StaticModel newQuery($value)
* @method static \Illuminate\Database\Eloquent\Builder|StaticModel query($value)
* @method static \Illuminate\Database\Eloquent\Builder|StaticModel find($value)
* @method static \Illuminate\Database\Eloquent\Builder|StaticModel with($value)
* @method static \Illuminate\Database\Eloquent\Builder|StaticModel withTrashed($value)
* @method static \Illuminate\Database\Eloquent\Builder|StaticModel findOrFail($value)
* @mixin \Eloquent
*/
class StaticModel extends Model

View File

@ -98,6 +98,7 @@ use Illuminate\Foundation\Auth\User as Authenticatable;
* @method static \Illuminate\Database\Eloquent\Builder|User newQuery()
* @method static \Illuminate\Database\Eloquent\Builder|User onlyTrashed()
* @method static \Illuminate\Database\Eloquent\Builder|User query()
* @method static \Illuminate\Database\Eloquent\Builder|User where($column, $value)
* @method static \Illuminate\Database\Eloquent\Builder|User whereAcceptedTermsVersion($value)
* @method static \Illuminate\Database\Eloquent\Builder|User whereAccountId($value)
* @method static \Illuminate\Database\Eloquent\Builder|User whereAvatar($value)
@ -336,13 +337,6 @@ class User extends Authenticatable implements MustVerifyEmail
return $this->getCompany();
}
// private function setCompanyByGuard()
// {
// if (Auth::guard('contact')->check()) {
// $this->setCompany(auth()->user()->client->company);
// }
// }
public function company_users()
{
return $this->hasMany(CompanyUser::class)->withTrashed();

View File

@ -88,7 +88,7 @@ class ClientObserver
{
/** Monitor postal code changes for US based clients for tax calculations */
if($client->getOriginal('postal_code') != $client->postal_code && $client->country_id == 840 && $client->company->calculate_taxes && !$client->company->account->isFreeHostedClient()) {
if(($client->getOriginal('shipping_postal_code') != $client->shipping_postal_code || $client->getOriginal('postal_code') != $client->postal_code) && $client->country_id == 840 && $client->company->calculate_taxes && !$client->company->account->isFreeHostedClient()) {
UpdateTaxData::dispatch($client, $client->company);
}

View File

@ -16,9 +16,9 @@ use App\Models\Subscription;
class SubscriptionObserver
{
/**
* Handle the billing_subscription "created" event.
* Handle the subscription "created" event.
*
* @param Subscription $billing_subscription
* @param Subscription $subscription
* @return void
*/
public function created(Subscription $subscription)
@ -27,9 +27,9 @@ class SubscriptionObserver
}
/**
* Handle the billing_subscription "updated" event.
* Handle the subscription "updated" event.
*
* @param Subscription $billing_subscription
* @param Subscription $subscription
* @return void
*/
public function updated(Subscription $subscription)
@ -38,9 +38,9 @@ class SubscriptionObserver
}
/**
* Handle the billing_subscription "deleted" event.
* Handle the subscription "deleted" event.
*
* @param Subscription $billing_subscription
* @param Subscription $subscription
* @return void
*/
public function deleted(Subscription $subscription)
@ -49,9 +49,9 @@ class SubscriptionObserver
}
/**
* Handle the billing_subscription "restored" event.
* Handle the subscription "restored" event.
*
* @param Subscription $billing_subscription
* @param Subscription $subscription
* @return void
*/
public function restored(Subscription $subscription)
@ -60,9 +60,9 @@ class SubscriptionObserver
}
/**
* Handle the billing_subscription "force deleted" event.
* Handle the subscription "force deleted" event.
*
* @param Subscription $billing_subscription
* @param Subscription $subscription
* @return void
*/
public function forceDeleted(Subscription $subscription)

View File

@ -0,0 +1,432 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\PaymentDrivers;
use Omnipay\Omnipay;
use App\Models\Invoice;
use App\Models\SystemLog;
use App\Models\GatewayType;
use App\Models\PaymentType;
use App\Jobs\Util\SystemLogger;
use App\Utils\Traits\MakesHash;
use App\Exceptions\PaymentFailed;
use Illuminate\Support\Facades\Http;
class PayPalRestPaymentDriver extends BaseDriver
{
use MakesHash;
public $token_billing = false;
public $can_authorise_credit_card = false;
private $omnipay_gateway;
private float $fee = 0;
public const SYSTEM_LOG_TYPE = SystemLog::TYPE_PAYPAL;
private string $api_endpoint_url = '';
private string $paypal_payment_method = '';
private array $funding_options = [
3 => 'paypal',
1 => 'card',
25 => 'venmo',
9 => 'sepa',
12 => 'bancontact',
17 => 'eps',
15 => 'giropay',
13 => 'ideal',
26 => 'mercadopago',
27 => 'mybank',
28 => 'paylater',
16 => 'p24',
7 => 'sofort'
];
public function gatewayTypes()
{
$funding_options = [];
foreach ($this->company_gateway->fees_and_limits as $key => $value) {
if ($value->is_enabled) {
$funding_options[] = $key;
}
}
return $funding_options;
}
public function init()
{
$this->omnipay_gateway = Omnipay::create(
$this->company_gateway->gateway->provider
);
$this->omnipay_gateway->initialize((array) $this->company_gateway->getConfig());
$this->api_endpoint_url = $this->company_gateway->getConfigField('testMode') ? 'https://api-m.sandbox.paypal.com' : 'https://api-m.paypal.com';
return $this;
}
public function setPaymentMethod($payment_method_id)
{
if(!$payment_method_id)
return $this;
$this->paypal_payment_method = $this->funding_options[$payment_method_id];
return $this;
}
public function authorizeView($payment_method)
{
// PayPal doesn't support direct authorization.
return $this;
}
public function authorizeResponse($request)
{
// PayPal doesn't support direct authorization.
return $this;
}
public function processPaymentView($data)
{
$this->init();
$data['gateway'] = $this;
$this->payment_hash->data = array_merge((array) $this->payment_hash->data, ['amount' => $data['total']['amount_with_fee']]);
$this->payment_hash->save();
$data['client_id'] = $this->company_gateway->getConfigField('clientId');
$data['token'] = $this->getClientToken();
$data['order_id'] = $this->createOrder($data);
$data['funding_options'] = $this->paypal_payment_method;
return render('gateways.paypal.pay', $data);
}
private function getFundingOptions():string
{
$enums = [
3 => 'paypal',
1 => 'card',
25 => 'venmo',
// 9 => 'sepa',
// 12 => 'bancontact',
// 17 => 'eps',
// 15 => 'giropay',
// 13 => 'ideal',
// 26 => 'mercadopago',
// 27 => 'mybank',
// 28 => 'paylater',
// 16 => 'p24',
// 7 => 'sofort'
];
$funding_options = '';
foreach($this->company_gateway->fees_and_limits as $key => $value) {
if($value->is_enabled) {
$funding_options .=$enums[$key].',';
}
}
return rtrim($funding_options, ',');
}
public function processPaymentResponse($request)
{
$response = json_decode($request['gateway_response'], true);
if($response['status'] == 'COMPLETED' && isset($response['purchase_units'])){
$data = [
'payment_type' => PaymentType::PAYPAL,
'amount' => $response['purchase_units'][0]['amount']['value'],
'transaction_reference' => $response['purchase_units'][0]['payments']['captures'][0]['id'],
'gateway_type_id' => GatewayType::PAYPAL,
];
$payment = $this->createPayment($data, \App\Models\Payment::STATUS_COMPLETED);
SystemLogger::dispatch(
['response' => $response, 'data' => $data],
SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_SUCCESS,
SystemLog::TYPE_PAYPAL,
$this->client,
$this->client->company,
);
return redirect()->route('client.payments.show', ['payment' => $this->encodePrimaryKey($payment->id)]);
}
else {
SystemLogger::dispatch(
['response' => $response],
SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_FAILURE,
SystemLog::TYPE_PAYPAL,
$this->client,
$this->client->company,
);
throw new PaymentFailed('Payment failed. Please try again.', 401);
}
}
private function getClientToken(): string
{
$r = $this->gatewayRequest('/v1/identity/generate-token', 'post', ['body' => '']);
if($r->successful())
return $r->json()['client_token'];
throw new PaymentFailed('Unable to gain client token from Paypal. Check your configuration', 401);
}
private function createOrder(array $data): string
{
$_invoice = collect($this->payment_hash->data->invoices)->first();
$invoice = Invoice::withTrashed()->find($this->decodePrimaryKey($_invoice->invoice_id));
$order = [
"intent" => "CAPTURE",
"payer" => [
"name" => [
"given_name" => $this->client->present()->first_name(),
"surname" => $this->client->present()->last_name(),
],
"email_address" => $this->client->present()->email(),
"address" => [
"address_line_1" => $this->client->address1,
"address_line_2" => $this->client->address2,
"admin_area_1" => $this->client->city,
"admin_area_2" => $this->client->state,
"postal_code" => $this->client->postal_code,
"country_code" => $this->client->country->iso_3166_2,
]
],
"purchase_units" => [
[
"description" =>ctrans('texts.invoice_number').'# '.$invoice->number,
"invoice_id" => $invoice->number,
"amount" => [
"value" => (string)$data['amount_with_fee'],
"currency_code"=> $this->client->currency()->code,
"breakdown" => [
"item_total" => [
"currency_code" => $this->client->currency()->code,
"value" => (string)$data['amount_with_fee']
]
]
],
"items"=> [
[
"name" => ctrans('texts.invoice_number').'# '.$invoice->number,
"quantity" => "1",
"unit_amount" => [
"currency_code" => $this->client->currency()->code,
"value" => (string)$data['amount_with_fee']
],
],
],
]
]
];
$r = $this->gatewayRequest('/v2/checkout/orders', 'post', $order);
return $r->json()['id'];
}
public function gatewayRequest(string $uri, string $verb, array $data, ?array $headers = [])
{
$r = Http::withToken($this->omnipay_gateway->getToken())
->withHeaders($this->getHeaders($headers))
->{$verb}("{$this->api_endpoint_url}{$uri}", $data);
if($r->successful())
return $r;
throw new PaymentFailed("Gateway failure - {$r->body()}", 401);
}
private function getHeaders(array $headers = []): array
{
return array_merge([
'Accept' => 'application/json',
'Content-type' => 'application/json',
'Accept-Language' => 'en_US',
], $headers);
}
/*
public function processPaymentResponse($request)
{
$this->initializeOmnipayGateway();
$response = $this->omnipay_gateway
->completePurchase(['amount' => $this->payment_hash->data->amount, 'currency' => $this->client->getCurrencyCode()])
->send();
if ($response->isCancelled() && $this->client->getSetting('enable_client_portal')) {
return redirect()->route('client.invoices.index')->with('warning', ctrans('texts.status_cancelled'));
} elseif ($response->isCancelled() && !$this->client->getSetting('enable_client_portal')) {
redirect()->route('client.invoices.show', ['invoice' => $this->payment_hash->fee_invoice])->with('warning', ctrans('texts.status_cancelled'));
}
if ($response->isSuccessful()) {
$data = [
'payment_method' => $response->getData()['TOKEN'],
'payment_type' => PaymentType::PAYPAL,
'amount' => $this->payment_hash->data->amount,
'transaction_reference' => $response->getTransactionReference(),
'gateway_type_id' => GatewayType::PAYPAL,
];
$payment = $this->createPayment($data, \App\Models\Payment::STATUS_COMPLETED);
SystemLogger::dispatch(
['response' => (array) $response->getData(), 'data' => $data],
SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_SUCCESS,
SystemLog::TYPE_PAYPAL,
$this->client,
$this->client->company,
);
return redirect()->route('client.payments.show', ['payment' => $this->encodePrimaryKey($payment->id)]);
}
if (! $response->isSuccessful()) {
$data = $response->getData();
$this->sendFailureMail($response->getMessage() ?: '');
$message = [
'server_response' => $data['L_LONGMESSAGE0'],
'data' => $this->payment_hash->data,
];
SystemLogger::dispatch(
$message,
SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_FAILURE,
SystemLog::TYPE_PAYPAL,
$this->client,
$this->client->company,
);
throw new PaymentFailed($response->getMessage(), $response->getCode());
}
}
public function generatePaymentDetails(array $data)
{
$_invoice = collect($this->payment_hash->data->invoices)->first();
$invoice = Invoice::withTrashed()->find($this->decodePrimaryKey($_invoice->invoice_id));
// $this->fee = $this->feeCalc($invoice, $data['total']['amount_with_fee']);
return [
'currency' => $this->client->getCurrencyCode(),
'transactionType' => 'Purchase',
'clientIp' => request()->getClientIp(),
// 'amount' => round(($data['total']['amount_with_fee'] + $this->fee),2),
'amount' => round($data['total']['amount_with_fee'], 2),
'returnUrl' => route('client.payments.response', [
'company_gateway_id' => $this->company_gateway->id,
'payment_hash' => $this->payment_hash->hash,
'payment_method_id' => GatewayType::PAYPAL,
]),
'cancelUrl' => $this->client->company->domain()."/client/invoices/{$invoice->hashed_id}",
'description' => implode(',', collect($this->payment_hash->data->invoices)
->map(function ($invoice) {
return sprintf('%s: %s', ctrans('texts.invoice_number'), $invoice->invoice_number);
})->toArray()),
'transactionId' => $this->payment_hash->hash.'-'.time(),
'ButtonSource' => 'InvoiceNinja_SP',
'solutionType' => 'Sole',
];
}
public function generatePaymentItems(array $data)
{
$_invoice = collect($this->payment_hash->data->invoices)->first();
$invoice = Invoice::withTrashed()->find($this->decodePrimaryKey($_invoice->invoice_id));
$items = [];
$items[] = new Item([
'name' => ' ',
'description' => ctrans('texts.invoice_number').'# '.$invoice->number,
'price' => $data['total']['amount_with_fee'],
'quantity' => 1,
]);
return $items;
}
*/
private function feeCalc($invoice, $invoice_total)
{
$invoice->service()->removeUnpaidGatewayFees();
$invoice = $invoice->fresh();
$balance = floatval($invoice->balance);
$_updated_invoice = $invoice->service()->addGatewayFee($this->company_gateway, GatewayType::PAYPAL, $invoice_total)->save();
if (floatval($_updated_invoice->balance) > $balance) {
$fee = floatval($_updated_invoice->balance) - $balance;
$this->payment_hash->fee_total = $fee;
$this->payment_hash->save();
return $fee;
}
return 0;
}
}

View File

@ -165,6 +165,7 @@ class BaseRepository
if (! $model->id) {
$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);
}

View File

@ -175,8 +175,11 @@ class InstantPayment
}
if ($this->request->has('signature') && ! is_null($this->request->signature) && ! empty($this->request->signature)) {
$invoices->each(function ($invoice) {
InjectSignature::dispatch($invoice, $this->request->signature);
$contact_id = auth()->guard('contact')->user() ? auth()->guard('contact')->user()->id : null;
$invoices->each(function ($invoice) use($contact_id) {
InjectSignature::dispatch($invoice, $contact_id, $this->request->signature, request()->getClientIp());
});
}

View File

@ -78,9 +78,9 @@ class InvoiceService
* Sets the exchange rate on the invoice if the client currency
* is different to the company currency.
*/
public function setExchangeRate()
public function setExchangeRate($force = false)
{
if ($this->invoice->exchange_rate != 1) {
if ($this->invoice->exchange_rate != 1 || $force) {
return $this;
}

View File

@ -11,22 +11,17 @@
namespace App\Services\Quote;
use App\Events\Quote\QuoteWasMarkedSent;
use App\Models\Quote;
use App\Models\Webhook;
use App\Utils\Ninja;
use Carbon\Carbon;
use App\Utils\Ninja;
use App\Models\Quote;
use App\Models\Client;
use App\Models\Webhook;
use App\Events\Quote\QuoteWasMarkedSent;
class MarkSent
{
private $client;
private $quote;
public function __construct($client, $quote)
public function __construct(private Client $client, private Quote $quote)
{
$this->client = $client;
$this->quote = $quote;
}
public function run()
@ -38,9 +33,9 @@ class MarkSent
$this->quote->markInvitationsSent();
if ($this->quote->due_date != '' || $this->quote->client->getSetting('valid_until') == '') {
if ($this->quote->due_date != '' || $this->client->getSetting('valid_until') == '') {
} else {
$this->quote->due_date = Carbon::parse($this->quote->date)->addDays($this->quote->client->getSetting('valid_until'));
$this->quote->due_date = Carbon::parse($this->quote->date)->addDays($this->client->getSetting('valid_until'));
}
$this->quote

View File

@ -19,7 +19,6 @@ use App\Models\Invoice;
use App\Utils\Ninja;
use App\Utils\Number;
use App\Utils\Traits\MakesDates;
use Carbon\Carbon;
use Illuminate\Support\Facades\App;
use League\Csv\Writer;
@ -33,6 +32,8 @@ class ARSummaryReport extends BaseExport
public Client $client;
private float $total = 0;
public array $report_keys = [
'client_name',
'client_number',
@ -101,7 +102,7 @@ class ARSummaryReport extends BaseExport
{
$this->client = $client;
return [
$row = [
$this->client->present()->name(),
$this->client->number,
$this->client->id_number,
@ -111,7 +112,12 @@ class ARSummaryReport extends BaseExport
$this->getAgingAmount('90'),
$this->getAgingAmount('120'),
$this->getAgingAmount('120+'),
Number::formatMoney($this->total, $this->client),
];
$this->total = 0;
return $row;
}
private function getCurrent(): string
@ -128,6 +134,8 @@ class ARSummaryReport extends BaseExport
})
->sum('balance');
$this->total += $amount;
return Number::formatMoney($amount, $this->client);
}
@ -153,6 +161,8 @@ class ARSummaryReport extends BaseExport
->whereBetween('due_date', [$to, $from])
->sum('balance');
$this->total += $amount;
return Number::formatMoney($amount, $this->client);
}

View File

@ -366,7 +366,7 @@ class ProfitLoss
$csv->insertOne(['--------------------']);
$csv->insertOne([ctrans('texts.total_revenue'), Number::formatMoney($this->income, $this->company)]);
$csv->insertOne([ctrans('texts.total_revenue'), Number::formatMoney($this->income - $this->income_taxes, $this->company)]);
//total taxes
@ -386,7 +386,7 @@ class ProfitLoss
$csv->insertOne([ctrans('texts.total_taxes'), Number::formatMoney(array_sum(array_column($this->expense_break_down, 'tax')), $this->company)]);
$csv->insertOne(['--------------------']);
$csv->insertOne([ctrans('texts.total_profit'), Number::formatMoney($this->income - array_sum(array_column($this->expense_break_down, 'total')), $this->company)]);
$csv->insertOne([ctrans('texts.total_profit'), Number::formatMoney($this->income - $this->income_taxes - array_sum(array_column($this->expense_break_down, 'total'))- array_sum(array_column($this->expense_break_down, 'tax')), $this->company)]);
//net profit

View File

@ -68,6 +68,8 @@ trait Inviteable
$qr = $writer->writeString($this->getPaymentLink(), 'utf-8');
return "<div>$qr</div>";
return "<svg class='pqrcode' viewBox='0 0 200 200' width='200' height='200' x='0' y='0' xmlns='http://www.w3.org/2000/svg'>
<rect x='0' y='0' width='100%' height='100%' />{$qr}</svg>";
}

View File

@ -62,7 +62,7 @@ trait MakesHash
return $hashids->encode($value);
}
public function decodePrimaryKey($value) : string
public function decodePrimaryKey($value)
{
try {
$hashids = new Hashids(config('ninja.hash_salt'), 10);
@ -71,7 +71,6 @@ trait MakesHash
if (! is_array($decoded_array)) {
throw new \Exception('Invalid Primary Key');
//response()->json(['error'=>'Invalid primary key'], 400);
}
return $decoded_array[0];

View File

@ -84,6 +84,7 @@ return [
'password' => 'password',
'stripe' => env('STRIPE_KEYS', ''),
'paypal' => env('PAYPAL_KEYS', ''),
'paypal_rest' => env('PAYPAL_REST_KEYS', ''),
'authorize' => env('AUTHORIZE_KEYS', ''),
'checkout' => env('CHECKOUT_KEYS', ''),
'travis' => env('TRAVIS', false),

View File

@ -0,0 +1,48 @@
<?php
use App\Models\Gateway;
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
if(!Gateway::find(60))
{
$fields = new \stdClass;
$fields->clientId = "";
$fields->secret = "";
$fields->testMode = false;
$paypal = new Gateway;
$paypal->id = 60;
$paypal->name = 'PayPal REST';
$paypal->key = '80af24a6a691230bbec33e930ab40665';
$paypal->provider = 'PayPal_Rest';
$paypal->is_offsite = false;
$paypal->fields = \json_encode($fields);
$paypal->visible = 1;
$paypal->site_url = 'https://www.paypal.com/';
$paypal->save();
}
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
//
}
};

View File

@ -83,6 +83,7 @@ class PaymentLibrariesSeeder extends Seeder
['id' => 57, 'name' => 'Square', 'provider' => 'Square', 'is_offsite' => false, 'sort_order' => 21, 'key' => '65faab2ab6e3223dbe848b1686490baz', 'fields' => '{"accessToken":"","applicationId":"","locationId":"","testMode":false}'],
['id' => 58, 'name' => 'Razorpay', 'provider' => 'Razorpay', 'is_offsite' => false, 'sort_order' => 21, 'key' => 'hxd6gwg3ekb9tb3v9lptgx1mqyg69zu9', 'fields' => '{"apiKey":"","apiSecret":""}'],
['id' => 59, 'name' => 'Forte', 'provider' => 'Forte', 'is_offsite' => false, 'sort_order' => 21, 'key' => 'kivcvjexxvdiyqtj3mju5d6yhpeht2xs', 'fields' => '{"testMode":false,"apiLoginId":"","apiAccessId":"","secureKey":"","authOrganizationId":"","organizationId":"","locationId":""}'],
['id' => 60, 'name' => 'PayPal REST', 'provider' => 'PayPal_Rest', 'key' => '80af24a6a691230bbec33e930ab40665', 'fields' => '{"clientId":"","secret":"","signature":"","testMode":false}'],
];
foreach ($gateways as $gateway) {
@ -99,7 +100,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])->update(['visible' => 1]);
Gateway::whereIn('id', [1,3,7,11,15,20,39,46,55,50,57,52,58,59,60])->update(['visible' => 1]);
if (Ninja::isHosted()) {
Gateway::whereIn('id', [20])->update(['visible' => 0]);

View File

@ -882,7 +882,7 @@ $LANG = array(
'custom_invoice_charges_helps' => 'Add a text input to the invoice create/edit page and include the charge in the invoice subtotals.',
'token_expired' => 'Validation token was expired. Please try again.',
'invoice_link' => 'Invoice Link',
'button_confirmation_message' => 'Confirm your email.',
'button_confirmation_message' => 'Klik for at bekræfte din e-mail.',
'confirm' => 'Confirm',
'email_preferences' => 'Email Preferences',
'created_invoices' => 'Successfully created :count invoice(s)',
@ -1179,7 +1179,7 @@ $LANG = array(
'plan_started' => 'Plan Started',
'plan_expires' => 'Plan Expires',
'white_label_button' => 'Purchase White Label',
'white_label_button' => 'Køb whitelabel licens',
'pro_plan_year_description' => 'One year enrollment in the Invoice Ninja Pro Plan.',
'pro_plan_month_description' => 'One month enrollment in the Invoice Ninja Pro Plan.',
@ -1853,7 +1853,7 @@ $LANG = array(
'task' => 'Opgave',
'contact_name' => 'Kontakt navn',
'city_state_postal' => 'By/Postnummer',
'postal_city' => 'Postal/City',
'postal_city' => 'Postnr og by',
'custom_field' => 'Brugerdefineret felt',
'account_fields' => 'Virksomheds felter',
'facebook_and_twitter' => 'Facebook og Twitter',
@ -2060,8 +2060,8 @@ $LANG = array(
'group_when_sorted' => 'Group Sort',
'group_dates_by' => 'Gruppér datoer efter',
'year' => 'År',
'view_statement' => 'View Statement',
'statement' => 'Statement',
'view_statement' => 'Se kontoudskrift',
'statement' => 'Kontoudtog',
'statement_date' => 'Statement Date',
'mark_active' => 'Markér som aktiv',
'send_automatically' => 'Send automatisk',
@ -4972,7 +4972,7 @@ $LANG = array(
'xinvoice_payable' => 'Payable within :payeddue days net until :paydate',
'xinvoice_no_buyers_reference' => "No buyer's reference given",
'xinvoice_online_payment' => 'The invoice needs to be paid online via the provided link',
'pre_payment' => 'Pre Payment',
'pre_payment' => 'Forudbetaling',
'number_of_payments' => 'Number of payments',
'number_of_payments_helper' => 'The number of times this payment will be made',
'pre_payment_indefinitely' => 'Continue until cancelled',
@ -5113,6 +5113,16 @@ $LANG = array(
'item_tax_rate2' => 'Item Tax Rate 2',
'item_tax_rate3' => 'Item Tax Rate 3',
'buy_price' => 'Buy Price',
'country_Macedonia' => 'Macedonia',
'admin_initiated_payments' => 'Admin Initiated Payments',
'admin_initiated_payments_help' => 'Support entering a payment in the admin portal without an invoice',
'paid_date' => 'Paid Date',
'downloaded_entities' => 'An email will be sent with the PDFs',
'lang_French - Swiss' => 'French - Swiss',
'currency_swazi_lilangeni' => 'Swazi Lilangeni',
'income' => 'Income',
'amount_received_help' => 'Enter a value here if the total amount received was MORE than the invoice amount, or when recording a payment with no invoices. Otherwise this field should be left blank.',
'vendor_phone' => 'Vendor Phone',
);

View File

@ -5124,6 +5124,17 @@ $LANG = array(
'income' => 'Income',
'amount_received_help' => 'Enter a value here if the total amount received was MORE than the invoice amount, or when recording a payment with no invoices. Otherwise this field should be left blank.',
'vendor_phone' => 'Vendor Phone',
'mercado_pago' => 'Mercado Pago',
'mybank' => 'MyBank',
'paypal_paylater' => 'Pay in 4',
'paid_date' => 'Paid Date',
'district' => 'District',
'region' => 'Region',
'county' => 'County',
'tax_details' => 'Tax Details',
'activity_10_online' => ':contact entered payment :payment for invoice :invoice for :client',
'activity_10_manual' => ':user entered payment :payment for invoice :invoice for :client',
'default_payment_type' => 'Default Payment Type',
);

View File

@ -4947,8 +4947,8 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette
'click_to_variables' => 'Cliquez ici pour voir toutes les variables',
'ship_to' => 'Livrer à',
'stripe_direct_debit_details' => 'Veuillez transférer dans le compte bancaire indiqué ci-dessus.',
'branch_name' => 'Nom de branche',
'branch_code' => 'Code de branche',
'branch_name' => 'Nom de succursale',
'branch_code' => 'Code de succursale',
'bank_name' => 'Nom de l\'institution bancaire',
'bank_code' => 'Code de l\'institution bancaire',
'bic' => 'BIC',
@ -5114,7 +5114,8 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette
'lang_French - Swiss' => 'Français - Suisse',
'currency_swazi_lilangeni' => 'Lilangeni Eswatinien',
'income' => 'Revenu',
'amount_received_help' => 'Saisissez une valeur si le montant total reçu été PLUS élevé que le montant de la facture, ou lors de l\'enregistrement d\'un paiement sans factures. Sinon, ce champ devrait rester vide.',
'vendor_phone' => 'Téléphone du fournisseur',
);

View File

@ -4569,7 +4569,7 @@ Quando tiver as quantias, volte a esta página de formas de pagamento e clique "
'activity_134' => ':user restored purchase order :purchase_order',
'activity_135' => ':user emailed purchase order :purchase_order',
'activity_136' => ':contact viewed purchase order :purchase_order',
'purchase_order_subject' => 'New Purchase Order :number from :account',
'purchase_order_subject' => 'Novo pedido de compra',
'purchase_order_message' => 'To view your purchase order for :amount, click the link below.',
'view_purchase_order' => 'View Purchase Order',
'purchase_orders_backup_subject' => 'Your purchase orders are ready for download',
@ -4639,7 +4639,7 @@ Quando tiver as quantias, volte a esta página de formas de pagamento e clique "
'purchase_order_footer' => 'Purchase Order Footer',
'require_purchase_order_signature' => 'Purchase Order Signature',
'require_purchase_order_signature_help' => 'Require vendor to provide their signature.',
'new_purchase_order' => 'New Purchase Order',
'new_purchase_order' => 'Novo pedido de compra',
'edit_purchase_order' => 'Edit Purchase Order',
'created_purchase_order' => 'Successfully created purchase order',
'updated_purchase_order' => 'Successfully updated purchase order',
@ -5108,6 +5108,16 @@ Quando tiver as quantias, volte a esta página de formas de pagamento e clique "
'item_tax_rate2' => 'Item Tax Rate 2',
'item_tax_rate3' => 'Item Tax Rate 3',
'buy_price' => 'Buy Price',
'country_Macedonia' => 'Macedonia',
'admin_initiated_payments' => 'Admin Initiated Payments',
'admin_initiated_payments_help' => 'Support entering a payment in the admin portal without an invoice',
'paid_date' => 'Paid Date',
'downloaded_entities' => 'An email will be sent with the PDFs',
'lang_French - Swiss' => 'French - Swiss',
'currency_swazi_lilangeni' => 'Swazi Lilangeni',
'income' => 'Income',
'amount_received_help' => 'Enter a value here if the total amount received was MORE than the invoice amount, or when recording a payment with no invoices. Otherwise this field should be left blank.',
'vendor_phone' => 'Vendor Phone',
);

View File

@ -1,19 +1,13 @@
includes:
- ./vendor/nunomaduro/larastan/extension.neon
- phpstan-baseline.neon
parameters:
treatPhpDocTypesAsCertain: false
parallel:
jobSize: 10
maximumNumberOfProcesses: 1
processTimeout: 60.0
ignoreErrors:
- '#Call to an undefined method .*badMethod\(\)#'
- '#Call to an undefined method Illuminate\Database\Eloquent\Builder::exclude#'
level: 4
paths:
- 'app/'
excludePaths:
- 'vendor/'
- 'app/Jobs/Ninja/*'
- 'app/Console/Commands/*'
- 'app/DataMapper/Analytics/*'
universalObjectCratesClasses:
- App\DataMapper\Tax\RuleInterface

View File

@ -136,10 +136,12 @@ span {
<td style="text-align:left; padding-right:10px;" class="text-lg">{{ ctrans('texts.total') }}</td>
<td style="text-align:right; padding-right:10px;" class="text-lg">{{ $amount }}</td>
</tr>
@if(!$is_quote)
<tr>
<td style="text-align:left; padding-right:10px;" class="text-lg">{{ ctrans('texts.balance') }}</td>
<td style="text-align:right; padding-right:10px;" class="text-lg">{{ $balance }}</td>
</tr>
@endif
</tbody>
</table>

View File

@ -0,0 +1,68 @@
@extends('portal.ninja2020.layout.payments', ['gateway_title' => ctrans('texts.payment_type_credit_card'), 'card_title' => 'PayPal'])
@section('gateway_head')
<link
rel="stylesheet"
type="text/css"
href="https://www.paypalobjects.com/webstatic/en_US/developer/docs/css/cardfields.css"
/>
@endsection
@section('gateway_content')
<form action="{{ route('client.payments.response') }}" method="post" id="server_response">
@csrf
<input type="hidden" name="payment_hash" value="{{ $payment_hash }}">
<input type="hidden" name="company_gateway_id" value="{{ $gateway->company_gateway->id }}">
<input type="hidden" name="gateway_response" id="gateway_response">
<input type="hidden" name="amount_with_fee" id="amount_with_fee" value="{{ $total['amount_with_fee'] }}"/>
</form>
<div class="alert alert-failure mb-4" hidden id="errors"></div>
<div id="paypal-button-container" class="paypal-button-container"></div>
@endsection
@section('gateway_footer')
@endsection
@push('footer')
<script src="https://www.paypal.com/sdk/js?enable-funding={!! $funding_options !!}&disable-funding=credit&components=buttons,hosted-fields,funding-eligibility&intent=capture&client-id={!! $client_id !!}" data-client-token="{!! $token !!}">
</script>
<script>
paypal.Buttons({
env: "{{ $gateway->company_gateway->getConfigField('testMode') ? 'sandbox' : 'production' }}",
client: {
@if($gateway->company_gateway->getConfigField('testMode'))
sandbox: "{{ $gateway->company_gateway->getConfigField('clientId') }}"
@else
production: "{{ $gateway->company_gateway->getConfigField('clientId') }}"
@endif
},
createOrder: function(data, actions) {
return "{!! $order_id !!}"
},
onApprove: function(data, actions) {
return actions.order.capture().then(function(details) {
document.getElementById("gateway_response").value =JSON.stringify( details );
document.getElementById("server_response").submit();
});
},
onError: function(err) {
console.log(err);
}
}).render('#paypal-button-container');
</script>
@endpush

View File

@ -120,6 +120,108 @@ class ProfitAndLossReportTest extends TestCase
$this->account->delete();
}
public function testExpenseResolution()
{
$this->buildData();
Expense::factory()->create([
'company_id' => $this->company->id,
'user_id' => $this->user->id,
'amount' => 121,
'date' => now()->format('Y-m-d'),
'uses_inclusive_taxes' => true,
'tax_rate1' => 21,
'tax_name1' => 'VAT',
'calculate_tax_by_amount' => false,
'exchange_rate' => 1,
]);
$pl = new ProfitLoss($this->company, $this->payload);
$pl->build();
$expense_breakdown = $pl->getExpenseBreakDown();
$this->assertEquals(100, array_sum(array_column($expense_breakdown, 'total')));
$this->assertEquals(21, array_sum(array_column($expense_breakdown, 'tax')));
$this->account->delete();
}
public function testMultiCurrencyInvoiceIncome()
{
$this->buildData();
$settings = ClientSettings::defaults();
$settings->currency_id = 2;
$client = Client::factory()->create([
'user_id' => $this->user->id,
'company_id' => $this->company->id,
'is_deleted' => 0,
'settings' => $settings
]);
$client2 = Client::factory()->create([
'user_id' => $this->user->id,
'company_id' => $this->company->id,
'is_deleted' => 0,
]);
Invoice::factory()->create([
'client_id' => $client->id,
'user_id' => $this->user->id,
'company_id' => $this->company->id,
'amount' => 10,
'balance' => 10,
'status_id' => 2,
'total_taxes' => 1,
'date' => now()->format('Y-m-d'),
'terms' => 'nada',
'discount' => 0,
'tax_rate1' => 0,
'tax_rate2' => 0,
'tax_rate3' => 0,
'tax_name1' => '',
'tax_name2' => '',
'tax_name3' => '',
'uses_inclusive_taxes' => false,
'exchange_rate' => 2
]);
Invoice::factory()->create([
'client_id' => $client2->id,
'user_id' => $this->user->id,
'company_id' => $this->company->id,
'amount' => 10,
'balance' => 10,
'status_id' => 2,
'total_taxes' => 1,
'date' => now()->format('Y-m-d'),
'terms' => 'nada',
'discount' => 0,
'tax_rate1' => 0,
'tax_rate2' => 0,
'tax_rate3' => 0,
'tax_name1' => '',
'tax_name2' => '',
'tax_name3' => '',
'uses_inclusive_taxes' => false,
'exchange_rate' => 1
]);
$pl = new ProfitLoss($this->company, $this->payload);
$pl->build();
$this->assertEquals(13.5, $pl->getIncome());
$this->assertEquals(1.5, $pl->getIncomeTaxes());
$this->account->delete();
}
public function testSimpleInvoiceIncome()
{
$this->buildData();

View File

@ -70,6 +70,60 @@ class ReportCsvGenerationTest extends TestCase
public $cu;
private $all_client_report_keys = ["client.name","client.user","client.assigned_user","client.balance","client.paid_to_date","client.currency_id","client.website","client.private_notes","client.industry_id","client.size_id","client.address1","client.address2","client.city","client.state","client.postal_code","client.country_id","contact.custom_value4","client.shipping_address1","client.shipping_address2","client.shipping_city","client.shipping_state","client.shipping_postal_code","client.shipping_country_id","client.payment_terms","client.vat_number","client.id_number","client.public_notes","client.phone","contact.first_name","contact.last_name","contact.email","contact.phone"];
private $all_payment_report_keys = [
'payment.date',
'payment.amount',
'payment.refunded',
'payment.applied',
'payment.transaction_reference',
'payment.currency',
'payment.exchange_rate',
'payment.number',
'payment.method',
'payment.status',
'payment.private_notes',
'payment.custom_value1',
'payment.custom_value2',
'payment.custom_value3',
'payment.custom_value4',
'payment.user_id',
'payment.assigned_user_id'
];
private $all_invoice_report_keys = [
'invoice.number',
'invoice.amount',
'invoice.balance',
'invoice.paid_to_date',
'invoice.discount',
'invoice.po_number',
'invoice.date',
'invoice.due_date',
'invoice.terms',
'invoice.footer',
'invoice.status',
'invoice.public_notes',
'invoice.private_notes',
'invoice.uses_inclusive_taxes',
'invoice.is_amount_discount',
'invoice.partial',
'invoice.partial_due_date',
'invoice.custom_value1',
'invoice.custom_value2',
'invoice.custom_value3',
'invoice.custom_value4',
'invoice.custom_surcharge1',
'invoice.custom_surcharge2',
'invoice.custom_surcharge3',
'invoice.custom_surcharge4',
'invoice.exchange_rate',
'invoice.total_taxes',
'invoice.assigned_user_id',
'invoice.user_id',
];
/**
* start_date - Y-m-d
end_date - Y-m-d
@ -329,6 +383,32 @@ class ReportCsvGenerationTest extends TestCase
$this->assertEquals('123456', $this->getFirstValueByColumn($csv, 'Invoice Invoice Number'));
$this->assertEquals(1000, $this->getFirstValueByColumn($csv, 'Invoice Amount'));
$data = [
'date_range' => 'all',
'report_keys' => $this->all_client_report_keys,
'send_email' => false,
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->post('/api/v1/reports/tasks', $data)->assertStatus(200);
$data = [
'date_range' => 'all',
'report_keys' => array_merge(["task.date","task.number"], $this->all_invoice_report_keys),
'send_email' => false,
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->post('/api/v1/reports/tasks', $data);
}
@ -474,6 +554,33 @@ class ReportCsvGenerationTest extends TestCase
$this->assertEquals(0, $this->getFirstValueByColumn($csv, 'Client Balance'));
$this->assertEquals(100, $this->getFirstValueByColumn($csv, 'Client Paid to Date'));
$data = [
'date_range' => 'all',
'report_keys' => $this->all_client_report_keys,
'send_email' => false,
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->post('/api/v1/reports/payments', $data)->assertStatus(200);
$data = [
'date_range' => 'all',
'report_keys' => array_merge(["payment.amount","payment.date"],$this->all_invoice_report_keys),
'send_email' => false,
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->post('/api/v1/reports/payments', $data);
}
@ -603,6 +710,17 @@ class ReportCsvGenerationTest extends TestCase
$this->assertEquals('Unpaid', $this->getFirstValueByColumn($csv, 'Payment Amount'));
$this->assertEquals('', $this->getFirstValueByColumn($csv, 'Payment Date'));
$data = [
'date_range' => 'all',
'report_keys' => $this->all_payment_report_keys,
'send_email' => false,
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->post('/api/v1/reports/credits', $data)->assertStatus(200);
}
public function testInvoiceCustomColumnsCsvGeneration()
@ -625,7 +743,7 @@ class ReportCsvGenerationTest extends TestCase
$data = [
'date_range' => 'all',
'report_keys' => ["client.name","invoice.number","invoice.amount","payment.date", "payment.amount"],
'report_keys' => ["client.name","invoice.number","invoice.amount","payment.date", "payment.amount","invoice.user"],
'send_email' => false,
];
@ -641,6 +759,33 @@ class ReportCsvGenerationTest extends TestCase
$this->assertEquals('Unpaid', $this->getFirstValueByColumn($csv, 'Payment Amount'));
$this->assertEquals('', $this->getFirstValueByColumn($csv, 'Payment Date'));
$data = [
'date_range' => 'all',
'report_keys' => $this->all_client_report_keys,
'send_email' => false,
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->post('/api/v1/reports/invoices', $data)->assertStatus(200);
$data = [
'date_range' => 'all',
'report_keys' => $this->all_payment_report_keys,
'send_email' => false,
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->post('/api/v1/reports/invoices', $data)->assertStatus(200);
}
public function testRecurringInvoiceCustomColumnsCsvGeneration()
@ -679,6 +824,20 @@ class ReportCsvGenerationTest extends TestCase
$this->assertEquals('1234', $this->getFirstValueByColumn($csv, 'Recurring Invoice Invoice Number'));
$this->assertEquals('Daily', $this->getFirstValueByColumn($csv, 'Recurring Invoice How Often'));
$data = [
'date_range' => 'all',
'report_keys' => $this->all_client_report_keys,
'send_email' => false,
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->post('/api/v1/reports/recurring_invoices', $data)->assertStatus(200);
}
@ -745,6 +904,33 @@ class ReportCsvGenerationTest extends TestCase
$this->assertEquals('GST', $this->getFirstValueByColumn($csv, 'Tax Name 1'));
$this->assertEquals('10', $this->getFirstValueByColumn($csv, 'Tax Rate 1'));
$data = [
'date_range' => 'all',
'report_keys' => $this->all_client_report_keys,
'send_email' => false,
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->post('/api/v1/reports/invoice_items', $data)->assertStatus(200);
$data = [
'date_range' => 'all',
'report_keys' => $this->all_payment_report_keys,
'send_email' => false,
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->post('/api/v1/reports/invoice_items', $data)->assertStatus(200);
}
@ -810,6 +996,20 @@ class ReportCsvGenerationTest extends TestCase
$this->assertEquals('GST', $this->getFirstValueByColumn($csv, 'Tax Name 1'));
$this->assertEquals('10', $this->getFirstValueByColumn($csv, 'Tax Rate 1'));
$data = [
'date_range' => 'all',
'report_keys' => $this->all_client_report_keys,
'send_email' => false,
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->post('/api/v1/reports/quote_items', $data)->assertStatus(200);
}
@ -973,6 +1173,20 @@ class ReportCsvGenerationTest extends TestCase
$this->assertEquals('1234', $this->getFirstValueByColumn($csv, 'Quote Number'));
$this->assertEquals('100', $this->getFirstValueByColumn($csv, 'Quote Amount'));
$data = [
'date_range' => 'all',
'report_keys' => $this->all_client_report_keys,
'send_email' => false,
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->post('/api/v1/reports/quotes', $data)->assertStatus(200);
}
@ -1104,6 +1318,33 @@ class ReportCsvGenerationTest extends TestCase
$this->assertEquals('Public', $this->getFirstValueByColumn($csv, 'Public Notes'));
$this->assertEquals('Private', $this->getFirstValueByColumn($csv, 'Private Notes'));
$this->assertEquals('Terms', $this->getFirstValueByColumn($csv, 'Terms'));
$data = [
'date_range' => 'all',
'report_keys' => $this->all_client_report_keys,
'send_email' => false,
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->post('/api/v1/reports/credits', $data)->assertStatus(200);
$data = [
'date_range' => 'all',
'report_keys' => $this->all_payment_report_keys,
'send_email' => false,
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->post('/api/v1/reports/credits', $data)->assertStatus(200);
}
public function testInvoiceCsvGeneration()
@ -1364,6 +1605,21 @@ class ReportCsvGenerationTest extends TestCase
$this->assertEquals('Private', $this->getFirstValueByColumn($csv, 'Private Notes'));
$this->assertEquals($this->user->present()->name(), $this->getFirstValueByColumn($csv, 'User'));
$data = [
'date_range' => 'all',
'report_keys' => $this->all_client_report_keys,
'send_email' => false,
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->post('/api/v1/reports/expenses', $data)->assertStatus(200);
}
public function testExpenseCustomColumnsCsvGeneration()