mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-09 03:14:30 -04:00
commit
db80be3d69
@ -1 +1 @@
|
|||||||
5.6.1
|
5.6.4
|
@ -53,8 +53,10 @@ class TranslationsExport extends Command
|
|||||||
'fr_CA',
|
'fr_CA',
|
||||||
'he',
|
'he',
|
||||||
'hr',
|
'hr',
|
||||||
|
'hu',
|
||||||
'it',
|
'it',
|
||||||
'ja',
|
'ja',
|
||||||
|
'km_KH',
|
||||||
'lt',
|
'lt',
|
||||||
'lv_LV',
|
'lv_LV',
|
||||||
'mk_MK',
|
'mk_MK',
|
||||||
@ -131,10 +133,11 @@ class TranslationsExport extends Command
|
|||||||
Storage::disk('local')->makeDirectory('lang');
|
Storage::disk('local')->makeDirectory('lang');
|
||||||
|
|
||||||
foreach ($this->langs as $lang) {
|
foreach ($this->langs as $lang) {
|
||||||
|
nlog($lang);
|
||||||
Storage::disk('local')->makeDirectory("lang/{$lang}");
|
Storage::disk('local')->makeDirectory("lang/{$lang}");
|
||||||
|
|
||||||
$translations = Lang::getLoader()->load($lang, 'texts');
|
$translations = Lang::getLoader()->load($lang, 'texts');
|
||||||
|
nlog($translations);
|
||||||
Storage::disk('local')->put("lang/{$lang}/{$lang}.json", json_encode(Arr::dot($translations), JSON_UNESCAPED_UNICODE));
|
Storage::disk('local')->put("lang/{$lang}/{$lang}.json", json_encode(Arr::dot($translations), JSON_UNESCAPED_UNICODE));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,7 @@ class EmailStatement
|
|||||||
public const LAST_QUARTER = "last_quarter";
|
public const LAST_QUARTER = "last_quarter";
|
||||||
public const THIS_YEAR = "this_year";
|
public const THIS_YEAR = "this_year";
|
||||||
public const LAST_YEAR = "last_year";
|
public const LAST_YEAR = "last_year";
|
||||||
|
public const ALL_TIME = "all_time";
|
||||||
public const CUSTOM_RANGE = "custom";
|
public const CUSTOM_RANGE = "custom";
|
||||||
|
|
||||||
|
|
||||||
|
@ -162,14 +162,16 @@ class Rule extends BaseRule implements RuleInterface
|
|||||||
|
|
||||||
if($this->tax_data?->stateSalesTax == 0) {
|
if($this->tax_data?->stateSalesTax == 0) {
|
||||||
|
|
||||||
$this->tax_rate1 = $this->invoice->client->company->tax_data->regions->{$this->client_region}->subregions->{$this->client_subregion}->tax_rate;
|
$this->tax_rate1 = 0;
|
||||||
$this->tax_name1 = "Sales Tax";
|
$this->tax_name1 = '';
|
||||||
|
|
||||||
|
// $this->tax_rate1 = $this->invoice->client->company->tax_data->regions->{$this->client_region}->subregions->{$this->client_subregion}->tax_rate;
|
||||||
|
// $this->tax_name1 = "Sales Tax";
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->tax_rate1 = $this->tax_data->taxSales * 100;
|
$this->tax_rate1 = $this->tax_data->taxSales * 100;
|
||||||
// $this->tax_name1 = "{$this->tax_data->geoState} Sales Tax";
|
|
||||||
$this->tax_name1 = "Sales Tax";
|
$this->tax_name1 = "Sales Tax";
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
|
@ -13,9 +13,10 @@ namespace App\Events\Payment;
|
|||||||
|
|
||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
use App\Models\Payment;
|
use App\Models\Payment;
|
||||||
use Illuminate\Broadcasting\InteractsWithSockets;
|
use App\Models\ClientContact;
|
||||||
use Illuminate\Foundation\Events\Dispatchable;
|
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use Illuminate\Foundation\Events\Dispatchable;
|
||||||
|
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class PaymentWasEmailed.
|
* Class PaymentWasEmailed.
|
||||||
@ -24,26 +25,15 @@ class PaymentWasEmailed
|
|||||||
{
|
{
|
||||||
use Dispatchable, InteractsWithSockets, SerializesModels;
|
use Dispatchable, InteractsWithSockets, SerializesModels;
|
||||||
|
|
||||||
/**
|
|
||||||
* @var Payment
|
|
||||||
*/
|
|
||||||
public $payment;
|
|
||||||
|
|
||||||
public $company;
|
|
||||||
|
|
||||||
public $event_vars;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new event instance.
|
* Create a new event instance.
|
||||||
*
|
*
|
||||||
* @param Payment $payment
|
* @param Payment $payment
|
||||||
* @param Company $company
|
* @param Company $company
|
||||||
|
* @param ClientContact $contact
|
||||||
* @param array $event_vars
|
* @param array $event_vars
|
||||||
*/
|
*/
|
||||||
public function __construct(Payment $payment, Company $company, array $event_vars)
|
public function __construct(public Payment $payment, public Company $company, public ClientContact $contact, public array $event_vars)
|
||||||
{
|
{
|
||||||
$this->payment = $payment;
|
|
||||||
$this->company = $company;
|
|
||||||
$this->event_vars = $event_vars;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -115,6 +115,11 @@ class CreditFilters extends QueryFilters
|
|||||||
return $this->builder;
|
return $this->builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($sort_col[0] == 'client_id') {
|
||||||
|
return $this->builder->orderBy(\App\Models\Client::select('name')
|
||||||
|
->whereColumn('clients.id', 'credits.client_id'), $sort_col[1]);
|
||||||
|
}
|
||||||
|
|
||||||
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
|
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,11 +61,11 @@ class DesignFilters extends QueryFilters
|
|||||||
*/
|
*/
|
||||||
public function entityFilter(): Builder
|
public function entityFilter(): Builder
|
||||||
{
|
{
|
||||||
//19-03-2023 change the scope for the design filters
|
/** @var \App\Models\User $user */
|
||||||
return $this->builder->where(function ($query) {
|
$user = auth()->user();
|
||||||
$query->where('company_id', auth()->user()->company()->id)->orWhere('company_id', null)->orderBy('id', 'asc');
|
|
||||||
// return $this->builder->where('company_id', auth()->user()->company()->id)->orWhere('company_id', null)->orderBy('id', 'asc');
|
|
||||||
|
|
||||||
|
return $this->builder->where(function ($query) use($user){
|
||||||
|
$query->where('company_id', $user->company()->id)->orWhere('company_id', null)->orderBy('id', 'asc');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,12 +11,14 @@
|
|||||||
|
|
||||||
namespace App\Filters;
|
namespace App\Filters;
|
||||||
|
|
||||||
|
use RuntimeException;
|
||||||
|
use App\Models\Client;
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
|
use App\Filters\QueryFilters;
|
||||||
|
use InvalidArgumentException;
|
||||||
|
use Illuminate\Support\Carbon;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Support\Carbon;
|
|
||||||
use InvalidArgumentException;
|
|
||||||
use RuntimeException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* InvoiceFilters.
|
* InvoiceFilters.
|
||||||
@ -204,6 +206,13 @@ class InvoiceFilters extends QueryFilters
|
|||||||
return $this->builder;
|
return $this->builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($sort_col[0] == 'client_id') {
|
||||||
|
|
||||||
|
return $this->builder->orderBy(\App\Models\Client::select('name')
|
||||||
|
->whereColumn('clients.id', 'invoices.client_id'), $sort_col[1]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
|
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +40,10 @@ class PaymentFilters extends QueryFilters
|
|||||||
->orWhere('custom_value1', 'like', '%'.$filter.'%')
|
->orWhere('custom_value1', 'like', '%'.$filter.'%')
|
||||||
->orWhere('custom_value2', 'like', '%'.$filter.'%')
|
->orWhere('custom_value2', 'like', '%'.$filter.'%')
|
||||||
->orWhere('custom_value3', 'like', '%'.$filter.'%')
|
->orWhere('custom_value3', 'like', '%'.$filter.'%')
|
||||||
->orWhere('custom_value4', 'like', '%'.$filter.'%');
|
->orWhere('custom_value4', 'like', '%'.$filter.'%')
|
||||||
|
->orWhereHas('client', function ($q) use ($filter) {
|
||||||
|
$q->where('name', 'like', '%'.$filter.'%');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,6 +158,13 @@ class PaymentFilters extends QueryFilters
|
|||||||
return $this->builder;
|
return $this->builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if ($sort_col[0] == 'client_id') {
|
||||||
|
return $this->builder->orderBy(\App\Models\Client::select('name')
|
||||||
|
->whereColumn('clients.id', 'payments.client_id'), $sort_col[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
|
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,6 +135,13 @@ class QuoteFilters extends QueryFilters
|
|||||||
return $this->builder;
|
return $this->builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if($sort_col[0] == 'client_id'){
|
||||||
|
|
||||||
|
return $this->builder->orderBy(\App\Models\Client::select('name')
|
||||||
|
->whereColumn('clients.id', 'quotes.client_id'), $sort_col[1]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if ($sort_col[0] == 'valid_until') {
|
if ($sort_col[0] == 'valid_until') {
|
||||||
$sort_col[0] = 'due_date';
|
$sort_col[0] = 'due_date';
|
||||||
}
|
}
|
||||||
|
@ -34,10 +34,15 @@ class RecurringInvoiceFilters extends QueryFilters
|
|||||||
}
|
}
|
||||||
|
|
||||||
return $this->builder->where(function ($query) use ($filter) {
|
return $this->builder->where(function ($query) use ($filter) {
|
||||||
$query->where('recurring_invoices.custom_value1', 'like', '%'.$filter.'%')
|
$query->where('date', 'like', '%'.$filter.'%')
|
||||||
->orWhere('recurring_invoices.custom_value2', 'like', '%'.$filter.'%')
|
->orWhere('amount', 'like', '%'.$filter.'%')
|
||||||
->orWhere('recurring_invoices.custom_value3', 'like', '%'.$filter.'%')
|
->orWhere('custom_value1', 'like', '%'.$filter.'%')
|
||||||
->orWhere('recurring_invoices.custom_value4', 'like', '%'.$filter.'%');
|
->orWhere('custom_value2', 'like', '%'.$filter.'%')
|
||||||
|
->orWhere('custom_value3', 'like', '%'.$filter.'%')
|
||||||
|
->orWhere('custom_value4', 'like', '%'.$filter.'%')
|
||||||
|
->orWhereHas('client', function ($q) use ($filter) {
|
||||||
|
$q->where('name', 'like', '%'.$filter.'%');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,6 +115,13 @@ class RecurringInvoiceFilters extends QueryFilters
|
|||||||
return $this->builder;
|
return $this->builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if ($sort_col[0] == 'client_id') {
|
||||||
|
return $this->builder->orderBy(\App\Models\Client::select('name')
|
||||||
|
->whereColumn('clients.id', 'recurring_invoices.client_id'), $sort_col[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
|
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,7 +39,13 @@ class TaskFilters extends QueryFilters
|
|||||||
->orWhere('custom_value1', 'like', '%'.$filter.'%')
|
->orWhere('custom_value1', 'like', '%'.$filter.'%')
|
||||||
->orWhere('custom_value2', 'like', '%'.$filter.'%')
|
->orWhere('custom_value2', 'like', '%'.$filter.'%')
|
||||||
->orWhere('custom_value3', 'like', '%'.$filter.'%')
|
->orWhere('custom_value3', 'like', '%'.$filter.'%')
|
||||||
->orWhere('custom_value4', 'like', '%'.$filter.'%');
|
->orWhere('custom_value4', 'like', '%'.$filter.'%')
|
||||||
|
->orWhereHas('project', function ($q) use ($filter) {
|
||||||
|
$q->where('name', 'like', '%'.$filter.'%');
|
||||||
|
})
|
||||||
|
->orWhereHas('client', function ($q) use ($filter) {
|
||||||
|
$q->where('name', 'like', '%'.$filter.'%');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,6 +110,16 @@ class TaskFilters extends QueryFilters
|
|||||||
return $this->builder;
|
return $this->builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($sort_col[0] == 'client_id') {
|
||||||
|
return $this->builder->orderBy(\App\Models\Client::select('name')
|
||||||
|
->whereColumn('clients.id', 'tasks.client_id'), $sort_col[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($sort_col[0] == 'user_id') {
|
||||||
|
return $this->builder->orderBy(\App\Models\User::select('first_name')
|
||||||
|
->whereColumn('users.id', 'tasks.user_id'), $sort_col[1]);
|
||||||
|
}
|
||||||
|
|
||||||
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
|
return $this->builder->orderBy($sort_col[0], $sort_col[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,7 +165,6 @@ class InvoiceSum
|
|||||||
{
|
{
|
||||||
if (! isset($this->invoice->id) && isset($this->invoice->partial)) {
|
if (! isset($this->invoice->id) && isset($this->invoice->partial)) {
|
||||||
$this->invoice->partial = max(0, min(Number::roundValue($this->invoice->partial, 2), $this->invoice->balance));
|
$this->invoice->partial = max(0, min(Number::roundValue($this->invoice->partial, 2), $this->invoice->balance));
|
||||||
// $this->invoice->partial = max(0, min($this->formatValue($this->invoice->partial, 2), $this->invoice->balance));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
|
@ -85,7 +85,7 @@ class ActivityController extends BaseController
|
|||||||
*/
|
*/
|
||||||
public function index(Request $request)
|
public function index(Request $request)
|
||||||
{
|
{
|
||||||
$default_activities = $request->has('rows') ? $request->input('rows') : 50;
|
$default_activities = $request->has('rows') ? $request->input('rows') : 75;
|
||||||
|
|
||||||
$activities = Activity::with('user')
|
$activities = Activity::with('user')
|
||||||
->orderBy('created_at', 'DESC')
|
->orderBy('created_at', 'DESC')
|
||||||
@ -93,18 +93,22 @@ class ActivityController extends BaseController
|
|||||||
->take($default_activities);
|
->take($default_activities);
|
||||||
|
|
||||||
if ($request->has('react')) {
|
if ($request->has('react')) {
|
||||||
if (!auth()->user()->isAdmin()) {
|
|
||||||
|
/** @var \App\Models\User auth()->user() */
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
|
if (!$user->isAdmin()) {
|
||||||
$activities->where('user_id', auth()->user()->id);
|
$activities->where('user_id', auth()->user()->id);
|
||||||
}
|
}
|
||||||
// return response()->json(['data' => []], 200);
|
|
||||||
|
|
||||||
$system = ctrans('texts.system');
|
$system = ctrans('texts.system');
|
||||||
|
|
||||||
$data = $activities->cursor()->map(function ($activity) use ($system) {
|
$data = $activities->cursor()->map(function ($activity) {
|
||||||
|
|
||||||
$arr =
|
$arr =
|
||||||
[
|
[
|
||||||
'client' => $activity->client ? $activity->client : '',
|
'client' => $activity->client ? $activity->client : '',
|
||||||
'contact' => $activity->contact ? $activity->contact : '',
|
'contact' => $activity->client ? $activity->contact : '',
|
||||||
'quote' => $activity->quote ? $activity->quote : '',
|
'quote' => $activity->quote ? $activity->quote : '',
|
||||||
'user' => $activity->user ? $activity->user : '',
|
'user' => $activity->user ? $activity->user : '',
|
||||||
'expense' => $activity->expense ? $activity->expense : '',
|
'expense' => $activity->expense ? $activity->expense : '',
|
||||||
@ -120,7 +124,28 @@ class ActivityController extends BaseController
|
|||||||
'recurring_expense' => $activity->recurring_expense ? $activity->recurring_expense : '',
|
'recurring_expense' => $activity->recurring_expense ? $activity->recurring_expense : '',
|
||||||
];
|
];
|
||||||
|
|
||||||
return array_merge($arr, $activity->toArray());
|
$activity_array = $activity->toArray();
|
||||||
|
|
||||||
|
return array_merge($arr, $activity_array);
|
||||||
|
});
|
||||||
|
|
||||||
|
return response()->json(['data' => $data->toArray()], 200);
|
||||||
|
}
|
||||||
|
elseif($request->has('reactv2')) {
|
||||||
|
|
||||||
|
/** @var \App\Models\User auth()->user() */
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
|
if (!$user->isAdmin()) {
|
||||||
|
$activities->where('user_id', auth()->user()->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
$system = ctrans('texts.system');
|
||||||
|
|
||||||
|
$data = $activities->cursor()->map(function ($activity) use ($system) {
|
||||||
|
|
||||||
|
return $activity->activity_string();
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return response()->json(['data' => $data->toArray()], 200);
|
return response()->json(['data' => $data->toArray()], 200);
|
||||||
|
@ -58,7 +58,7 @@ class DocumentController extends Controller
|
|||||||
|
|
||||||
$document = Document::where('hash', $document_hash)->firstOrFail();
|
$document = Document::where('hash', $document_hash)->firstOrFail();
|
||||||
|
|
||||||
$headers = [];
|
$headers = ['Cache-Control:' => 'no-cache'];
|
||||||
|
|
||||||
if (request()->input('inline') == 'true') {
|
if (request()->input('inline') == 'true') {
|
||||||
$headers = array_merge($headers, ['Content-Disposition' => 'inline']);
|
$headers = array_merge($headers, ['Content-Disposition' => 'inline']);
|
||||||
|
@ -87,7 +87,7 @@ class CompanyController extends BaseController
|
|||||||
* summary="Gets a list of companies",
|
* summary="Gets a list of companies",
|
||||||
* description="Lists companies, search and filters allow fine grained lists to be generated.
|
* description="Lists companies, search and filters allow fine grained lists to be generated.
|
||||||
|
|
||||||
Query parameters can be added to performed more fine grained filtering of the companies, these are handled by the CompanyFilters class which defines the methods available",
|
* Query parameters can be added to performed more fine grained filtering of the companies, these are handled by the CompanyFilters class which defines the methods available",
|
||||||
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"),
|
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"),
|
||||||
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
|
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
|
||||||
* @OA\Parameter(ref="#/components/parameters/include"),
|
* @OA\Parameter(ref="#/components/parameters/include"),
|
||||||
@ -114,7 +114,10 @@ class CompanyController extends BaseController
|
|||||||
*/
|
*/
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
$companies = Company::whereAccountId(auth()->user()->company()->account->id);
|
/** @var \App\Models\User $user */
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
|
$companies = Company::whereAccountId($user->company()->account->id);
|
||||||
|
|
||||||
return $this->listResponse($companies);
|
return $this->listResponse($companies);
|
||||||
}
|
}
|
||||||
@ -159,8 +162,12 @@ class CompanyController extends BaseController
|
|||||||
*/
|
*/
|
||||||
public function create(CreateCompanyRequest $request)
|
public function create(CreateCompanyRequest $request)
|
||||||
{
|
{
|
||||||
$cf = new \App\Factory\CompanyFactory;
|
/** @var \App\Models\User $user */
|
||||||
$company = $cf->create(auth()->user()->company()->account->id);
|
$user = auth()->user();
|
||||||
|
|
||||||
|
$company_factory = new \App\Factory\CompanyFactory;
|
||||||
|
|
||||||
|
$company = $company_factory->create($user->company()->account->id);
|
||||||
|
|
||||||
return $this->itemResponse($company);
|
return $this->itemResponse($company);
|
||||||
}
|
}
|
||||||
@ -206,15 +213,18 @@ class CompanyController extends BaseController
|
|||||||
{
|
{
|
||||||
$this->forced_includes = ['company_user'];
|
$this->forced_includes = ['company_user'];
|
||||||
|
|
||||||
$company = (new CreateCompany($request->all(), auth()->user()->company()->account))->handle();
|
/** @var \App\Models\User $user */
|
||||||
(new CreateCompanyPaymentTerms($company, auth()->user()))->handle();
|
$user = auth()->user();
|
||||||
(new CreateCompanyTaskStatuses($company, auth()->user()))->handle();
|
|
||||||
|
$company = (new CreateCompany($request->all(), $user->company()->account))->handle();
|
||||||
|
(new CreateCompanyPaymentTerms($company, $user))->handle();
|
||||||
|
(new CreateCompanyTaskStatuses($company, $user))->handle();
|
||||||
|
|
||||||
$company = $this->company_repo->save($request->all(), $company);
|
$company = $this->company_repo->save($request->all(), $company);
|
||||||
|
|
||||||
$this->uploadLogo($request->file('company_logo'), $company, $company);
|
$this->uploadLogo($request->file('company_logo'), $company, $company);
|
||||||
|
|
||||||
auth()->user()->companies()->attach($company->id, [
|
$user->companies()->attach($company->id, [
|
||||||
'account_id' => $company->account->id,
|
'account_id' => $company->account->id,
|
||||||
'is_owner' => 1,
|
'is_owner' => 1,
|
||||||
'is_admin' => 1,
|
'is_admin' => 1,
|
||||||
@ -231,7 +241,7 @@ class CompanyController extends BaseController
|
|||||||
/*
|
/*
|
||||||
* Required dependencies
|
* Required dependencies
|
||||||
*/
|
*/
|
||||||
auth()->user()->setCompany($company);
|
$user->setCompany($company);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create token
|
* Create token
|
||||||
@ -412,9 +422,6 @@ class CompanyController extends BaseController
|
|||||||
|
|
||||||
$company = $this->company_repo->save($request->all(), $company);
|
$company = $this->company_repo->save($request->all(), $company);
|
||||||
|
|
||||||
/** We save the settings in the repository - this is duplicated */
|
|
||||||
// $company->saveSettings($request->input('settings'), $company);
|
|
||||||
|
|
||||||
if ($request->has('documents')) {
|
if ($request->has('documents')) {
|
||||||
$this->saveDocuments($request->input('documents'), $company, false);
|
$this->saveDocuments($request->input('documents'), $company, false);
|
||||||
}
|
}
|
||||||
|
@ -11,12 +11,13 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Http\Requests\CompanyUser\UpdateCompanyUserRequest;
|
|
||||||
use App\Models\CompanyUser;
|
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
|
use App\Models\CompanyUser;
|
||||||
|
use Illuminate\Http\Response;
|
||||||
use App\Transformers\CompanyUserTransformer;
|
use App\Transformers\CompanyUserTransformer;
|
||||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||||
use Illuminate\Http\Response;
|
use App\Http\Requests\CompanyUser\UpdateCompanyUserRequest;
|
||||||
|
use App\Http\Requests\CompanyUser\UpdateCompanyUserPreferencesRequest;
|
||||||
|
|
||||||
class CompanyUserController extends BaseController
|
class CompanyUserController extends BaseController
|
||||||
{
|
{
|
||||||
@ -131,6 +132,24 @@ class CompanyUserController extends BaseController
|
|||||||
return $this->itemResponse($company_user->fresh());
|
return $this->itemResponse($company_user->fresh());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function updatePreferences(UpdateCompanyUserPreferencesRequest $request, User $user)
|
||||||
|
{
|
||||||
|
$company = auth()->user()->company();
|
||||||
|
|
||||||
|
$company_user = CompanyUser::whereUserId($user->id)->whereCompanyId($company->id)->first();
|
||||||
|
|
||||||
|
if (! $company_user) {
|
||||||
|
throw new ModelNotFoundException(ctrans('texts.company_user_not_found'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$company_user->react_settings = $request->react_settings;
|
||||||
|
$company_user->save();
|
||||||
|
|
||||||
|
return $this->itemResponse($company_user->fresh());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove the specified resource from storage.
|
* Remove the specified resource from storage.
|
||||||
*
|
*
|
||||||
|
@ -818,10 +818,11 @@ class InvoiceController extends BaseController
|
|||||||
return response()->json(['message' => 'no record found'], 400);
|
return response()->json(['message' => 'no record found'], 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
$contact = $invitation->contact;
|
|
||||||
$invoice = $invitation->invoice;
|
$invoice = $invitation->invoice;
|
||||||
|
|
||||||
$file = $invoice->service()->getInvoicePdf($contact);
|
$file_name = $invoice->numberFormatter().'.pdf';
|
||||||
|
|
||||||
|
$file = (new \App\Jobs\Entity\CreateRawPdf($invitation, $invitation->company->db))->handle();
|
||||||
|
|
||||||
$headers = ['Content-Type' => 'application/pdf'];
|
$headers = ['Content-Type' => 'application/pdf'];
|
||||||
|
|
||||||
@ -830,8 +831,8 @@ class InvoiceController extends BaseController
|
|||||||
}
|
}
|
||||||
|
|
||||||
return response()->streamDownload(function () use ($file) {
|
return response()->streamDownload(function () use ($file) {
|
||||||
echo Storage::get($file);
|
echo $file;
|
||||||
}, basename($file), $headers);
|
}, $file_name, $headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -565,10 +565,11 @@ class RecurringInvoiceController extends BaseController
|
|||||||
return response()->json(['message' => 'no record found'], 400);
|
return response()->json(['message' => 'no record found'], 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
$contact = $invitation->contact;
|
|
||||||
$invoice = $invitation->recurring_invoice;
|
$invoice = $invitation->recurring_invoice;
|
||||||
|
|
||||||
$file = $invoice->service()->getInvoicePdf($contact);
|
$file_name = $invoice->numberFormatter().'.pdf';
|
||||||
|
|
||||||
|
$file = (new \App\Jobs\Entity\CreateRawPdf($invitation, $invitation->company->db))->handle();
|
||||||
|
|
||||||
$headers = ['Content-Type' => 'application/pdf'];
|
$headers = ['Content-Type' => 'application/pdf'];
|
||||||
|
|
||||||
@ -577,8 +578,9 @@ class RecurringInvoiceController extends BaseController
|
|||||||
}
|
}
|
||||||
|
|
||||||
return response()->streamDownload(function () use ($file) {
|
return response()->streamDownload(function () use ($file) {
|
||||||
echo Storage::get($file);
|
echo $file;
|
||||||
}, basename($file), $headers);
|
}, $file_name, $headers);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,6 @@ class SelfUpdateController extends BaseController
|
|||||||
|
|
||||||
nlog('copying release file');
|
nlog('copying release file');
|
||||||
|
|
||||||
// if (copy($this->getDownloadUrl(), storage_path('app/invoiceninja.zip'))) {
|
|
||||||
if (copy($this->getDownloadUrl(), storage_path("app/{$this->filename}"))) {
|
if (copy($this->getDownloadUrl(), storage_path("app/{$this->filename}"))) {
|
||||||
nlog('Copied file from URL');
|
nlog('Copied file from URL');
|
||||||
} else {
|
} else {
|
||||||
@ -70,7 +69,6 @@ class SelfUpdateController extends BaseController
|
|||||||
|
|
||||||
nlog('Finished copying');
|
nlog('Finished copying');
|
||||||
|
|
||||||
// if($this->use_zip) {
|
|
||||||
$file = Storage::disk('local')->path($this->filename);
|
$file = Storage::disk('local')->path($this->filename);
|
||||||
|
|
||||||
nlog('Extracting tar');
|
nlog('Extracting tar');
|
||||||
@ -81,10 +79,6 @@ class SelfUpdateController extends BaseController
|
|||||||
nlog('Finished extracting files');
|
nlog('Finished extracting files');
|
||||||
|
|
||||||
unlink($file);
|
unlink($file);
|
||||||
// }
|
|
||||||
// else {
|
|
||||||
// $this->extractUsingZip();
|
|
||||||
// }
|
|
||||||
|
|
||||||
nlog('Deleted release zip file');
|
nlog('Deleted release zip file');
|
||||||
|
|
||||||
@ -110,31 +104,13 @@ class SelfUpdateController extends BaseController
|
|||||||
return response()->json(['message' => 'Update completed'], 200);
|
return response()->json(['message' => 'Update completed'], 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
// private function extractUsingZip()
|
|
||||||
// {
|
|
||||||
|
|
||||||
// $file = Storage::disk('local')->path($this->filename);
|
|
||||||
|
|
||||||
// nlog('Extracting zip');
|
|
||||||
|
|
||||||
// $zipFile = new \PhpZip\ZipFile();
|
|
||||||
// $zipFile->openFile($file);
|
|
||||||
// $zipFile->deleteFromName(".htaccess");
|
|
||||||
// $zipFile->rewrite();
|
|
||||||
// $zipFile->extractTo(base_path());
|
|
||||||
// $zipFile->close();
|
|
||||||
// $zipFile = null;
|
|
||||||
|
|
||||||
// unlink($file);
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
private function clearCacheDir()
|
private function clearCacheDir()
|
||||||
{
|
{
|
||||||
$directoryIterator = new \RecursiveDirectoryIterator(base_path('bootstrap/cache'), \RecursiveDirectoryIterator::SKIP_DOTS);
|
$directoryIterator = new \RecursiveDirectoryIterator(base_path('bootstrap/cache'), \RecursiveDirectoryIterator::SKIP_DOTS);
|
||||||
|
|
||||||
foreach (new \RecursiveIteratorIterator($directoryIterator) as $file) {
|
foreach (new \RecursiveIteratorIterator($directoryIterator) as $file) {
|
||||||
unlink(base_path('bootstrap/cache/').$file->getFileName());
|
unlink(base_path('bootstrap/cache/').$file->getFileName());
|
||||||
|
$file = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$directoryIterator = null;
|
$directoryIterator = null;
|
||||||
@ -155,6 +131,8 @@ class SelfUpdateController extends BaseController
|
|||||||
throw new FilePermissionsFailure("Cannot update system because {$file->getFileName()} is not writable");
|
throw new FilePermissionsFailure("Cannot update system because {$file->getFileName()} is not writable");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$file = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$directoryIterator = null;
|
$directoryIterator = null;
|
||||||
@ -169,10 +147,8 @@ class SelfUpdateController extends BaseController
|
|||||||
|
|
||||||
private function getDownloadUrl()
|
private function getDownloadUrl()
|
||||||
{
|
{
|
||||||
$version = $this->checkVersion();
|
|
||||||
|
|
||||||
// if(request()->has('zip'))
|
$version = $this->checkVersion();
|
||||||
// return "https://github.com/invoiceninja/invoiceninja/releases/download/v{$version}/invoiceninja.zip";
|
|
||||||
|
|
||||||
return "https://github.com/invoiceninja/invoiceninja/releases/download/v{$version}/invoiceninja.tar";
|
return "https://github.com/invoiceninja/invoiceninja/releases/download/v{$version}/invoiceninja.tar";
|
||||||
|
|
||||||
|
@ -58,7 +58,11 @@ class PasswordProtection
|
|||||||
Cache::put(auth()->user()->hashed_id.'_'.auth()->user()->account_id.'_logged_in', Str::random(64), $timeout);
|
Cache::put(auth()->user()->hashed_id.'_'.auth()->user()->account_id.'_logged_in', Str::random(64), $timeout);
|
||||||
|
|
||||||
return $next($request);
|
return $next($request);
|
||||||
} elseif ($request->header('X-API-OAUTH-PASSWORD') && strlen($request->header('X-API-OAUTH-PASSWORD')) >=1) {
|
}
|
||||||
|
elseif(strlen(auth()->user()->oauth_provider_id) > 2 && !auth()->user()->company()->oauth_password_required){
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
elseif ($request->header('X-API-OAUTH-PASSWORD') && strlen($request->header('X-API-OAUTH-PASSWORD')) >=1) {
|
||||||
//user is attempting to reauth with OAuth - check the token value
|
//user is attempting to reauth with OAuth - check the token value
|
||||||
//todo expand this to include all OAuth providers
|
//todo expand this to include all OAuth providers
|
||||||
if (auth()->user()->oauth_provider_id == 'google') {
|
if (auth()->user()->oauth_provider_id == 'google') {
|
||||||
|
@ -82,7 +82,7 @@ class UpdateCompanyRequest extends Request
|
|||||||
$input['settings'] = (array)$this->filterSaveableSettings($input['settings']);
|
$input['settings'] = (array)$this->filterSaveableSettings($input['settings']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(array_key_exists('subdomain', $input) && $this->subdomain == $input['subdomain']) {
|
if(array_key_exists('subdomain', $input) && $this->company->subdomain == $input['subdomain']) {
|
||||||
unset($input['subdomain']);
|
unset($input['subdomain']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,37 @@
|
|||||||
|
<?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\Http\Requests\CompanyUser;
|
||||||
|
|
||||||
|
use App\Http\Requests\Request;
|
||||||
|
use App\Utils\Traits\MakesHash;
|
||||||
|
|
||||||
|
class UpdateCompanyUserPreferencesRequest extends Request
|
||||||
|
{
|
||||||
|
use MakesHash;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize() : bool
|
||||||
|
{
|
||||||
|
return auth()->user()->id == $this->user->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'react_settings' => 'required'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@ -88,7 +88,7 @@ class StorePaymentRequest extends Request
|
|||||||
// $input['is_manual'] = true;
|
// $input['is_manual'] = true;
|
||||||
|
|
||||||
if (! isset($input['date'])) {
|
if (! isset($input['date'])) {
|
||||||
$input['date'] = now()->format('Y-m-d');
|
$input['date'] = now()->addSeconds(auth()->user()->company()->timezone()->utc_offset)->format('Y-m-d');
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->replace($input);
|
$this->replace($input);
|
||||||
|
@ -59,6 +59,8 @@ class StorePurchaseOrderRequest extends Request
|
|||||||
$rules['file'] = $this->file_validation;
|
$rules['file'] = $this->file_validation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$rules['status_id'] = 'nullable|integer|in:1,2,3,4,5';
|
||||||
|
|
||||||
return $rules;
|
return $rules;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,6 +62,8 @@ class UpdatePurchaseOrderRequest extends Request
|
|||||||
$rules['file'] = $this->file_validation;
|
$rules['file'] = $this->file_validation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$rules['status_id'] = 'sometimes|integer|in:1,2,3,4,5';
|
||||||
|
|
||||||
return $rules;
|
return $rules;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,6 +95,14 @@ class StoreTaskRequest extends Request
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isset($input['project_id']) && isset($input['client_id'])) {
|
||||||
|
$search_project_with_client = Project::withTrashed()->where('id', $input['project_id'])->where('client_id', $input['client_id'])->company()->doesntExist();
|
||||||
|
|
||||||
|
if ($search_project_with_client) {
|
||||||
|
unset($input['project_id']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$this->replace($input);
|
$this->replace($input);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,6 +104,15 @@ class UpdateTaskRequest extends Request
|
|||||||
$input['color'] = '';
|
$input['color'] = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(isset($input['project_id']) && isset($input['client_id'])){
|
||||||
|
$search_project_with_client = Project::withTrashed()->where('id', $input['project_id'])->where('client_id', $input['client_id'])->company()->doesntExist();
|
||||||
|
|
||||||
|
if($search_project_with_client){
|
||||||
|
unset($input['project_id']);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
$this->replace($input);
|
$this->replace($input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ class StoreSchedulerRequest extends Request
|
|||||||
'template' => 'bail|required|string',
|
'template' => 'bail|required|string',
|
||||||
'parameters' => 'bail|array',
|
'parameters' => 'bail|array',
|
||||||
'parameters.clients' => ['bail','sometimes', 'array', new ValidClientIds()],
|
'parameters.clients' => ['bail','sometimes', 'array', new ValidClientIds()],
|
||||||
'parameters.date_range' => 'bail|sometimes|string|in:last7_days,last30_days,last365_days,this_month,last_month,this_quarter,last_quarter,this_year,last_year,custom',
|
'parameters.date_range' => 'bail|sometimes|string|in:last7_days,last30_days,last365_days,this_month,last_month,this_quarter,last_quarter,this_year,last_year,all_time,custom',
|
||||||
'parameters.start_date' => ['bail', 'sometimes', 'date:Y-m-d', 'required_if:parameters.date_rate,custom'],
|
'parameters.start_date' => ['bail', 'sometimes', 'date:Y-m-d', 'required_if:parameters.date_rate,custom'],
|
||||||
'parameters.end_date' => ['bail', 'sometimes', 'date:Y-m-d', 'required_if:parameters.date_rate,custom', 'after_or_equal:parameters.start_date'],
|
'parameters.end_date' => ['bail', 'sometimes', 'date:Y-m-d', 'required_if:parameters.date_rate,custom', 'after_or_equal:parameters.start_date'],
|
||||||
'parameters.entity' => ['bail', 'sometimes', 'string', 'in:invoice,credit,quote,purchase_order'],
|
'parameters.entity' => ['bail', 'sometimes', 'string', 'in:invoice,credit,quote,purchase_order'],
|
||||||
@ -57,7 +57,7 @@ class StoreSchedulerRequest extends Request
|
|||||||
$input = $this->all();
|
$input = $this->all();
|
||||||
|
|
||||||
if (array_key_exists('next_run', $input) && is_string($input['next_run'])) {
|
if (array_key_exists('next_run', $input) && is_string($input['next_run'])) {
|
||||||
$this->merge(['next_run_client' => $input['next_run']]);
|
$input['next_run_client'] = $input['next_run'];
|
||||||
}
|
}
|
||||||
|
|
||||||
if($input['template'] == 'email_record'){
|
if($input['template'] == 'email_record'){
|
||||||
|
@ -37,7 +37,7 @@ class UpdateSchedulerRequest extends Request
|
|||||||
'template' => 'bail|required|string',
|
'template' => 'bail|required|string',
|
||||||
'parameters' => 'bail|array',
|
'parameters' => 'bail|array',
|
||||||
'parameters.clients' => ['bail','sometimes', 'array', new ValidClientIds()],
|
'parameters.clients' => ['bail','sometimes', 'array', new ValidClientIds()],
|
||||||
'parameters.date_range' => 'bail|sometimes|string|in:last7_days,last30_days,last365_days,this_month,last_month,this_quarter,last_quarter,this_year,last_year,custom',
|
'parameters.date_range' => 'bail|sometimes|string|in:last7_days,last30_days,last365_days,this_month,last_month,this_quarter,last_quarter,this_year,last_year,all_time,custom',
|
||||||
'parameters.start_date' => ['bail', 'sometimes', 'date:Y-m-d', 'required_if:parameters.date_rate,custom'],
|
'parameters.start_date' => ['bail', 'sometimes', 'date:Y-m-d', 'required_if:parameters.date_rate,custom'],
|
||||||
'parameters.end_date' => ['bail', 'sometimes', 'date:Y-m-d', 'required_if:parameters.date_rate,custom', 'after_or_equal:parameters.start_date'],
|
'parameters.end_date' => ['bail', 'sometimes', 'date:Y-m-d', 'required_if:parameters.date_rate,custom', 'after_or_equal:parameters.start_date'],
|
||||||
'parameters.entity' => ['bail', 'sometimes', 'string', 'in:invoice,credit,quote,purchase_order'],
|
'parameters.entity' => ['bail', 'sometimes', 'string', 'in:invoice,credit,quote,purchase_order'],
|
||||||
@ -54,7 +54,7 @@ class UpdateSchedulerRequest extends Request
|
|||||||
$input = $this->all();
|
$input = $this->all();
|
||||||
|
|
||||||
if (array_key_exists('next_run', $input) && is_string($input['next_run'])) {
|
if (array_key_exists('next_run', $input) && is_string($input['next_run'])) {
|
||||||
$this->merge(['next_run_client' => $input['next_run']]);
|
$input['next_run_client'] = $input['next_run'];
|
||||||
}
|
}
|
||||||
|
|
||||||
if($input['template'] == 'email_record') {
|
if($input['template'] == 'email_record') {
|
||||||
|
@ -20,12 +20,14 @@ class BankTransactionMap
|
|||||||
1 => 'transaction.amount',
|
1 => 'transaction.amount',
|
||||||
2 => 'transaction.currency',
|
2 => 'transaction.currency',
|
||||||
3 => 'transaction.account_type',
|
3 => 'transaction.account_type',
|
||||||
4 => 'transaction.category_id',
|
4 => 'transaction.category',
|
||||||
5 => 'transaction.category_type',
|
5 => 'transaction.category_type',
|
||||||
6 => 'transaction.date',
|
6 => 'transaction.date',
|
||||||
7 => 'transaction.bank_account_id',
|
7 => 'transaction.bank_account',
|
||||||
8 => 'transaction.description',
|
8 => 'transaction.description',
|
||||||
9 => 'transaction.base_type',
|
9 => 'transaction.base_type',
|
||||||
|
10 => 'transaction.payment_type_Credit',
|
||||||
|
11 => 'transaction.payment_type_Debit',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,6 +44,8 @@ class BankTransactionMap
|
|||||||
7 => 'texts.bank_account_id',
|
7 => 'texts.bank_account_id',
|
||||||
8 => 'texts.description',
|
8 => 'texts.description',
|
||||||
9 => 'texts.type',
|
9 => 'texts.type',
|
||||||
|
10 => 'transaction.credit',
|
||||||
|
11 => 'transaction.debit',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ class BankTransformer extends BaseTransformer
|
|||||||
$transformed = [
|
$transformed = [
|
||||||
'bank_integration_id' => $transaction['transaction.bank_integration_id'],
|
'bank_integration_id' => $transaction['transaction.bank_integration_id'],
|
||||||
'transaction_id' => $this->getNumber($transaction, 'transaction.transaction_id'),
|
'transaction_id' => $this->getNumber($transaction, 'transaction.transaction_id'),
|
||||||
'amount' => abs($this->getFloat($transaction, 'transaction.amount')),
|
'amount' => $this->calculateAmount($transaction),
|
||||||
'currency_id' => $this->getCurrencyByCode($transaction, 'transaction.currency'),
|
'currency_id' => $this->getCurrencyByCode($transaction, 'transaction.currency'),
|
||||||
'account_type' => strlen($this->getString($transaction, 'transaction.account_type')) > 1 ? $this->getString($transaction, 'transaction.account_type') : 'bank',
|
'account_type' => strlen($this->getString($transaction, 'transaction.account_type')) > 1 ? $this->getString($transaction, 'transaction.account_type') : 'bank',
|
||||||
'category_id' => $this->getNumber($transaction, 'transaction.category_id') > 0 ? $this->getNumber($transaction, 'transaction.category_id') : null,
|
'category_id' => $this->getNumber($transaction, 'transaction.category_id') > 0 ? $this->getNumber($transaction, 'transaction.category_id') : null,
|
||||||
@ -49,13 +49,35 @@ class BankTransformer extends BaseTransformer
|
|||||||
return $transformed;
|
return $transformed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function calculateAmount(array $transaction):float
|
||||||
|
{
|
||||||
|
|
||||||
|
if (array_key_exists('transaction.amount', $transaction) && is_numeric($transaction['transaction.amount'])) {
|
||||||
|
return abs($this->getFloat($transaction, 'transaction.amount'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (array_key_exists('transaction.payment_type_Credit', $transaction) && is_numeric($transaction['transaction.payment_type_Credit'])) {
|
||||||
|
return abs($this->getFloat($transaction, 'transaction.payment_type_Credit'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (array_key_exists('transaction.payment_type_Debit', $transaction) && is_numeric($transaction['transaction.payment_type_Debit'])) {
|
||||||
|
return abs($this->getFloat($transaction, 'transaction.payment_type_Debit'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
private function calculateType($transaction)
|
private function calculateType($transaction)
|
||||||
{
|
{
|
||||||
if (array_key_exists('transaction.base_type', $transaction) && (($transaction['transaction.base_type'] == 'CREDIT') || strtolower($transaction['transaction.base_type']) == 'deposit')) {
|
|
||||||
|
if (array_key_exists('transaction.payment_type_Credit', $transaction) && is_numeric($transaction['transaction.payment_type_Credit'])) {
|
||||||
return 'CREDIT';
|
return 'CREDIT';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (array_key_exists('transaction.transaction.payment_type_Debit', $transaction) && is_numeric($transaction['transaction.payment_type_Debit'])) {
|
||||||
|
return 'DEBIT';
|
||||||
|
}
|
||||||
|
|
||||||
if (array_key_exists('transaction.base_type', $transaction) && (($transaction['transaction.base_type'] == 'DEBIT') || strtolower($transaction['transaction.base_type']) == 'withdrawal')) {
|
if (array_key_exists('transaction.base_type', $transaction) && (($transaction['transaction.base_type'] == 'DEBIT') || strtolower($transaction['transaction.base_type']) == 'withdrawal')) {
|
||||||
return 'DEBIT';
|
return 'DEBIT';
|
||||||
}
|
}
|
||||||
|
@ -246,6 +246,15 @@ class BaseTransformer
|
|||||||
->exists();
|
->exists();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function hasClientIdNumber($id_number)
|
||||||
|
{
|
||||||
|
return Client::where('company_id', $this->company->id)
|
||||||
|
->where('is_deleted', false)
|
||||||
|
->where('id_number', trim($id_number))
|
||||||
|
->exists();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $name
|
* @param $name
|
||||||
*
|
*
|
||||||
|
@ -27,7 +27,12 @@ class ClientTransformer extends BaseTransformer
|
|||||||
*/
|
*/
|
||||||
public function transform($data)
|
public function transform($data)
|
||||||
{
|
{
|
||||||
if (isset($data['Company Name']) && $this->hasClient($data['Company Name'])) {
|
$client_id_proxy = array_key_exists('Customer ID', $data) ? 'Customer ID' : 'Primary Contact ID';
|
||||||
|
|
||||||
|
if(isset($data[$client_id_proxy]) && $this->hasClientIdNumber($data[$client_id_proxy])) {
|
||||||
|
throw new ImportException('Client ID already exists => '. $data[$client_id_proxy]);
|
||||||
|
}
|
||||||
|
elseif (isset($data['Company Name']) && $this->hasClient($data['Company Name'])) {
|
||||||
throw new ImportException('Client already exists => '. $data['Company Name']);
|
throw new ImportException('Client already exists => '. $data['Company Name']);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,8 +43,6 @@ class ClientTransformer extends BaseTransformer
|
|||||||
$settings->payment_terms = $data['Payment Terms'];
|
$settings->payment_terms = $data['Payment Terms'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$client_id_proxy = array_key_exists('Customer ID', $data) ? 'Customer ID' : 'Primary Contact ID';
|
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
'company_id' => $this->company->id,
|
'company_id' => $this->company->id,
|
||||||
'name' => $this->getString($data, 'Display Name'),
|
'name' => $this->getString($data, 'Display Name'),
|
||||||
|
@ -123,7 +123,6 @@ class InvoiceTransformer extends BaseTransformer
|
|||||||
return $client_id_search->first()->id;
|
return $client_id_search->first()->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$client_repository = app()->make(\App\Repositories\ClientRepository::class);
|
$client_repository = app()->make(\App\Repositories\ClientRepository::class);
|
||||||
$client_repository->import_mode = true;
|
$client_repository->import_mode = true;
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ use App\Models\Company;
|
|||||||
use App\Services\Bank\BankMatchingService;
|
use App\Services\Bank\BankMatchingService;
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
use Illuminate\Foundation\Events\Dispatchable;
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
@ -73,12 +73,11 @@ class UpdateTaxData implements ShouldQueue
|
|||||||
nlog("problem getting tax data => ".$e->getMessage());
|
nlog("problem getting tax data => ".$e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Set static tax information */
|
/*
|
||||||
if(!$tax_provider->updatedTaxStatus() && $this->client->country_id == 840){
|
if(!$tax_provider->updatedTaxStatus() && $this->client->country_id == 840){
|
||||||
|
|
||||||
$calculated_state = false;
|
$calculated_state = false;
|
||||||
|
|
||||||
/** State must be calculated else default to the company state for taxes */
|
|
||||||
if(array_key_exists($this->client->shipping_state, USStates::get())) {
|
if(array_key_exists($this->client->shipping_state, USStates::get())) {
|
||||||
$calculated_state = $this->client->shipping_state;
|
$calculated_state = $this->client->shipping_state;
|
||||||
$calculated_postal_code = $this->client->shipping_postal_code;
|
$calculated_postal_code = $this->client->shipping_postal_code;
|
||||||
@ -136,7 +135,7 @@ class UpdateTaxData implements ShouldQueue
|
|||||||
$this->client->saveQuietly();
|
$this->client->saveQuietly();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
public function middleware()
|
public function middleware()
|
||||||
@ -147,6 +146,8 @@ class UpdateTaxData implements ShouldQueue
|
|||||||
public function failed($exception)
|
public function failed($exception)
|
||||||
{
|
{
|
||||||
nlog("UpdateTaxData failed => ".$exception->getMessage());
|
nlog("UpdateTaxData failed => ".$exception->getMessage());
|
||||||
|
config(['queue.failed.driver' => null]);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -67,6 +67,9 @@ class AutoBill implements ShouldQueue
|
|||||||
if ($invitation->contact && ! $invitation->contact->trashed() && strlen($invitation->contact->email) >= 1 && $invoice->client->getSetting('auto_email_invoice')) {
|
if ($invitation->contact && ! $invitation->contact->trashed() && strlen($invitation->contact->email) >= 1 && $invoice->client->getSetting('auto_email_invoice')) {
|
||||||
try {
|
try {
|
||||||
EmailEntity::dispatch($invitation, $invoice->company)->delay(rand(1, 2));
|
EmailEntity::dispatch($invitation, $invoice->company)->delay(rand(1, 2));
|
||||||
|
|
||||||
|
$invoice->entityEmailEvent($invitation, 'invoice', 'email_template_invoice');
|
||||||
|
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
nlog($e->getMessage());
|
nlog($e->getMessage());
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,7 @@ class EmailPayment implements ShouldQueue
|
|||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
if ($this->company->is_disabled) {
|
if ($this->company->is_disabled) {
|
||||||
return true;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->contact->email) {
|
if ($this->contact->email) {
|
||||||
@ -96,7 +96,7 @@ class EmailPayment implements ShouldQueue
|
|||||||
|
|
||||||
(new NinjaMailerJob($nmo))->handle();
|
(new NinjaMailerJob($nmo))->handle();
|
||||||
|
|
||||||
event(new PaymentWasEmailed($this->payment, $this->payment->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
|
event(new PaymentWasEmailed($this->payment, $this->payment->company, $this->contact, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -101,7 +101,7 @@ class EmailRefundPayment implements ShouldQueue
|
|||||||
|
|
||||||
(new NinjaMailerJob($nmo))->handle();
|
(new NinjaMailerJob($nmo))->handle();
|
||||||
|
|
||||||
event(new PaymentWasEmailed($this->payment, $this->payment->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
|
event(new PaymentWasEmailed($this->payment, $this->payment->company, $this->contact, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -122,7 +122,7 @@ class WebhookSingle implements ShouldQueue
|
|||||||
$client = new Client(['headers' => array_merge($base_headers, $headers)]);
|
$client = new Client(['headers' => array_merge($base_headers, $headers)]);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$response = $client->post($subscription->target_url, [
|
$response = $client->{$subscription->rest_method}($subscription->target_url, [
|
||||||
RequestOptions::JSON => $data, // or 'json' => [...]
|
RequestOptions::JSON => $data, // or 'json' => [...]
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
@ -58,7 +58,6 @@ class InvoiceEmailFailedActivity implements ShouldQueue
|
|||||||
$fields->client_contact_id = $event->invitation->client_contact_id;
|
$fields->client_contact_id = $event->invitation->client_contact_id;
|
||||||
$fields->company_id = $event->invitation->invoice->company_id;
|
$fields->company_id = $event->invitation->invoice->company_id;
|
||||||
$fields->activity_type_id = Activity::EMAIL_INVOICE_FAILED;
|
$fields->activity_type_id = Activity::EMAIL_INVOICE_FAILED;
|
||||||
$fields->notes = $event->message;
|
|
||||||
|
|
||||||
$this->activity_repo->save($fields, $event->invitation->invoice, $event->event_vars);
|
$this->activity_repo->save($fields, $event->invitation->invoice, $event->event_vars);
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,7 @@ class PaymentEmailedActivity implements ShouldQueue
|
|||||||
|
|
||||||
$fields->user_id = $user_id;
|
$fields->user_id = $user_id;
|
||||||
$fields->client_id = $event->payment->client_id;
|
$fields->client_id = $event->payment->client_id;
|
||||||
|
$fields->client_contact_id = $event->contact->id;
|
||||||
$fields->company_id = $event->payment->company_id;
|
$fields->company_id = $event->payment->company_id;
|
||||||
$fields->activity_type_id = Activity::PAYMENT_EMAILED;
|
$fields->activity_type_id = Activity::PAYMENT_EMAILED;
|
||||||
$fields->payment_id = $event->payment->id;
|
$fields->payment_id = $event->payment->id;
|
||||||
|
@ -46,7 +46,6 @@ class ArchivedUserActivity implements ShouldQueue
|
|||||||
$user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->creating_user->id;
|
$user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->creating_user->id;
|
||||||
|
|
||||||
$fields->user_id = $user_id;
|
$fields->user_id = $user_id;
|
||||||
$fields->notes = $event->creating_user->present()->name.' Archived User '.$event->user->present()->name();
|
|
||||||
|
|
||||||
$fields->company_id = $event->company->id;
|
$fields->company_id = $event->company->id;
|
||||||
$fields->activity_type_id = Activity::ARCHIVE_USER;
|
$fields->activity_type_id = Activity::ARCHIVE_USER;
|
||||||
|
@ -46,7 +46,6 @@ class CreatedUserActivity implements ShouldQueue
|
|||||||
$user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->creating_user->id;
|
$user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->creating_user->id;
|
||||||
|
|
||||||
$fields->user_id = $user_id;
|
$fields->user_id = $user_id;
|
||||||
$fields->notes = $event->creating_user->present()->name().' Created the user '.$event->user->present()->name();
|
|
||||||
$fields->company_id = $event->company->id;
|
$fields->company_id = $event->company->id;
|
||||||
$fields->activity_type_id = Activity::CREATE_USER;
|
$fields->activity_type_id = Activity::CREATE_USER;
|
||||||
|
|
||||||
|
@ -51,8 +51,6 @@ class DeletedUserActivity implements ShouldQueue
|
|||||||
$user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->creating_user->id;
|
$user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->creating_user->id;
|
||||||
|
|
||||||
$fields->user_id = $user_id;
|
$fields->user_id = $user_id;
|
||||||
|
|
||||||
$fields->notes = $event->creating_user->present()->name().' Deleted the user '.$event->user->present()->name();
|
|
||||||
$fields->company_id = $event->company->id;
|
$fields->company_id = $event->company->id;
|
||||||
$fields->activity_type_id = Activity::DELETE_USER;
|
$fields->activity_type_id = Activity::DELETE_USER;
|
||||||
|
|
||||||
|
@ -45,7 +45,6 @@ class RestoredUserActivity implements ShouldQueue
|
|||||||
$user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->creating_user->id;
|
$user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->creating_user->id;
|
||||||
|
|
||||||
$fields->user_id = $user_id;
|
$fields->user_id = $user_id;
|
||||||
$fields->notes = $event->creating_user->present()->name().' Restored user '.$event->user->present()->name();
|
|
||||||
|
|
||||||
$fields->company_id = $event->company->id;
|
$fields->company_id = $event->company->id;
|
||||||
$fields->activity_type_id = Activity::RESTORE_USER;
|
$fields->activity_type_id = Activity::RESTORE_USER;
|
||||||
|
@ -45,7 +45,6 @@ class UpdatedUserActivity implements ShouldQueue
|
|||||||
$user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->creating_user->id;
|
$user_id = array_key_exists('user_id', $event->event_vars) ? $event->event_vars['user_id'] : $event->creating_user->id;
|
||||||
|
|
||||||
$fields->user_id = $user_id;
|
$fields->user_id = $user_id;
|
||||||
$fields->notes = $event->creating_user->present()->name().' Updated user '.$event->user->present()->name();
|
|
||||||
|
|
||||||
$fields->company_id = $event->company->id;
|
$fields->company_id = $event->company->id;
|
||||||
$fields->activity_type_id = Activity::UPDATE_USER;
|
$fields->activity_type_id = Activity::UPDATE_USER;
|
||||||
|
@ -77,7 +77,6 @@ class EntityFailedSendObject
|
|||||||
|
|
||||||
private function setTemplate()
|
private function setTemplate()
|
||||||
{
|
{
|
||||||
// nlog($this->template);
|
|
||||||
|
|
||||||
switch ($this->template) {
|
switch ($this->template) {
|
||||||
case 'invoice':
|
case 'invoice':
|
||||||
|
@ -104,7 +104,6 @@ class EntitySentObject
|
|||||||
|
|
||||||
private function setTemplate()
|
private function setTemplate()
|
||||||
{
|
{
|
||||||
// nlog($this->template);
|
|
||||||
|
|
||||||
switch ($this->template) {
|
switch ($this->template) {
|
||||||
case 'invoice':
|
case 'invoice':
|
||||||
|
@ -356,6 +356,11 @@ class PaymentEmailEngine extends BaseEmailEngine
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(strlen($invoice_list) < 4){
|
||||||
|
$invoice_list = Number::formatMoney($this->payment->amount, $this->client) ?: ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return $invoice_list;
|
return $invoice_list;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -72,7 +72,7 @@ class ImportCompleted extends Mailable
|
|||||||
'client_gateway_token_count' => $this->company->client_gateway_tokens()->count(),
|
'client_gateway_token_count' => $this->company->client_gateway_tokens()->count(),
|
||||||
'tax_rate_count' => $this->company->tax_rates()->count(),
|
'tax_rate_count' => $this->company->tax_rates()->count(),
|
||||||
'document_count' => $this->company->documents()->count(),
|
'document_count' => $this->company->documents()->count(),
|
||||||
|
'url' => Ninja::isHosted() ? config('ninja.react_url') : config('ninja.app_url'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return $this
|
return $this
|
||||||
|
@ -527,11 +527,11 @@ class Account extends BaseModel
|
|||||||
|
|
||||||
public function emailsSent()
|
public function emailsSent()
|
||||||
{
|
{
|
||||||
if (is_null(Cache::get($this->key))) {
|
if (is_null(Cache::get("email_quota".$this->key))) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Cache::get($this->key);
|
return Cache::get("email_quota".$this->key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function emailQuotaExceeded() :bool
|
public function emailQuotaExceeded() :bool
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Utils\Number;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -346,7 +347,7 @@ class Activity extends StaticModel
|
|||||||
*/
|
*/
|
||||||
public function contact()
|
public function contact()
|
||||||
{
|
{
|
||||||
return $this->belongsTo(ClientContact::class)->withTrashed();
|
return $this->belongsTo(ClientContact::class, 'client_contact_id', 'id')->withTrashed();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -460,4 +461,90 @@ class Activity extends StaticModel
|
|||||||
{
|
{
|
||||||
return $this->belongsTo(Company::class);
|
return $this->belongsTo(Company::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function activity_string()
|
||||||
|
{
|
||||||
|
$intersect = [
|
||||||
|
':invoice',
|
||||||
|
':client',
|
||||||
|
':contact',
|
||||||
|
':user',
|
||||||
|
':vendor',
|
||||||
|
':quote',
|
||||||
|
':credit',
|
||||||
|
':payment',
|
||||||
|
':task',
|
||||||
|
':expense',
|
||||||
|
':purchase_order',
|
||||||
|
':subscription',
|
||||||
|
':recurring_invoice',
|
||||||
|
':recurring_expense',
|
||||||
|
':amount',
|
||||||
|
':balance',
|
||||||
|
':number',
|
||||||
|
':payment_amount',
|
||||||
|
':gateway',
|
||||||
|
':adjustment'
|
||||||
|
];
|
||||||
|
|
||||||
|
$found_variables = array_intersect(explode(" ",trans("texts.activity_{$this->activity_type_id}")), $intersect);
|
||||||
|
|
||||||
|
$replacements = [];
|
||||||
|
|
||||||
|
foreach($found_variables as $var)
|
||||||
|
$replacements = array_merge($replacements, $this->matchVar($var));
|
||||||
|
|
||||||
|
if($this->client)
|
||||||
|
$replacements['client'] = ['label' => $this?->client?->present()->name() ?? '', 'hashed_id' => $this->client->hashed_id ?? ''];
|
||||||
|
|
||||||
|
if($this->vendor)
|
||||||
|
$replacements['vendor'] = ['label' => $this?->vendor?->present()->name() ?? '', 'hashed_id' => $this->vendor->hashed_id ?? ''];
|
||||||
|
|
||||||
|
$replacements['activity_type_id'] = $this->activity_type_id;
|
||||||
|
$replacements['id'] = $this->id;
|
||||||
|
$replacements['hashed_id'] = $this->hashed_id;
|
||||||
|
$replacements['notes'] = $this->notes ?? '';
|
||||||
|
$replacements['created_at'] = $this->created_at ?? '';
|
||||||
|
$replacements['ip'] = $this->ip ?? '';
|
||||||
|
|
||||||
|
return $replacements;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private function matchVar(string $variable)
|
||||||
|
{
|
||||||
|
$system = ctrans('texts.system');
|
||||||
|
|
||||||
|
return match($variable) {
|
||||||
|
':invoice' => $translation = [substr($variable, 1) => [ 'label' => $this?->invoice?->number ?? '', 'hashed_id' => $this->invoice?->hashed_id ?? '']],
|
||||||
|
':contact' => $translation = $this->resolveContact(),
|
||||||
|
':user' => $translation = [substr($variable, 1) => [ 'label' => $this?->user?->present()->name() ?? $system, 'hashed_id' => $this->user->hashed_id ?? '']],
|
||||||
|
':quote' => $translation = [substr($variable, 1) => [ 'label' => $this?->quote?->number ?? '', 'hashed_id' => $this->quote->hashed_id ?? '']],
|
||||||
|
':credit' => $translation = [substr($variable, 1) => [ 'label' => $this?->credit?->number ?? '', 'hashed_id' => $this->credit->hashed_id ?? '']],
|
||||||
|
':payment' => $translation = [substr($variable, 1) => [ 'label' => $this?->payment?->number ?? '', 'hashed_id' => $this->payment->hashed_id ?? '']],
|
||||||
|
':task' => $translation = [substr($variable, 1) => [ 'label' => $this?->task?->number ?? '', 'hashed_id' => $this->task->hashed_id ?? '']],
|
||||||
|
':expense' => $translation = [substr($variable, 1) => [ 'label' => $this?->expense?->number ?? '', 'hashed_id' => $this->expense->hashed_id ?? '']],
|
||||||
|
':purchase_order' => $translation = [substr($variable, 1) => [ 'label' => $this?->purchase_order?->number ?? '', 'hashed_id' => $this->purchase_order->hashed_id ?? '']],
|
||||||
|
':subscription' => $translation = [substr($variable, 1) => [ 'label' => $this?->subscription?->number ?? '', 'hashed_id' => $this->subscription->hashed_id ?? '' ]],
|
||||||
|
':recurring_invoice' => $translation = [substr($variable, 1) =>[ 'label' => $this?->recurring_invoice?->number ??'', 'hashed_id' => $this->recurring_invoice->hashed_id ?? '']],
|
||||||
|
':recurring_expense' => $translation = [substr($variable, 1) => [ 'label' => $this?->recurring_expense?->number ??'', 'hashed_id' => $this->recurring_expense->hashed_id ?? '']],
|
||||||
|
':payment_amount' => $translation = [substr($variable, 1) =>[ 'label' => Number::formatMoney($this?->payment?->amount, $this?->payment?->client) ?? '', 'hashed_id' => '']],
|
||||||
|
':adjustment' => $translation = [substr($variable, 1) =>[ 'label' => Number::formatMoney($this?->payment?->refunded, $this?->payment?->client) ?? '', 'hashed_id' => '']],
|
||||||
|
':ip' => $translation = [ 'ip' => $this->ip ?? ''],
|
||||||
|
default => $translation = [],
|
||||||
|
};
|
||||||
|
|
||||||
|
return $translation;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function resolveContact() : array
|
||||||
|
{
|
||||||
|
$contact = $this->contact ? $this->contact : $this->vendor_contact;
|
||||||
|
|
||||||
|
$entity = $this->contact ? $this->client : $this->vendor;
|
||||||
|
|
||||||
|
$contact_entity = $this->contact ? 'clients' : 'vendors';
|
||||||
|
|
||||||
|
return ['contact' => [ 'label' => $contact?->present()->name() ?? '', 'hashed_id' => $entity->hashed_id ?? '', 'contact_entity' => $contact_entity]];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,9 @@ use Illuminate\Support\Str;
|
|||||||
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel count()
|
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel count()
|
||||||
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel create()
|
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel create()
|
||||||
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel insert()
|
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel insert()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel whereHas()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel withTrashed()
|
||||||
|
*
|
||||||
* @method \App\Models\Company company()
|
* @method \App\Models\Company company()
|
||||||
* @method int companyId()
|
* @method int companyId()
|
||||||
* @method Builder|static exclude($columns)
|
* @method Builder|static exclude($columns)
|
||||||
|
@ -46,8 +46,8 @@ use Laracasts\Presenter\PresentableTrait;
|
|||||||
* @property string|null $email
|
* @property string|null $email
|
||||||
* @property string|null $email_verified_at
|
* @property string|null $email_verified_at
|
||||||
* @property string|null $confirmation_code
|
* @property string|null $confirmation_code
|
||||||
* @property int $is_primary
|
* @property bool $is_primary
|
||||||
* @property int $confirmed
|
* @property bool $confirmed
|
||||||
* @property int|null $last_login
|
* @property int|null $last_login
|
||||||
* @property int|null $failed_logins
|
* @property int|null $failed_logins
|
||||||
* @property string|null $oauth_user_id
|
* @property string|null $oauth_user_id
|
||||||
@ -59,8 +59,8 @@ use Laracasts\Presenter\PresentableTrait;
|
|||||||
* @property string|null $avatar_size
|
* @property string|null $avatar_size
|
||||||
* @property string $password
|
* @property string $password
|
||||||
* @property string|null $token
|
* @property string|null $token
|
||||||
* @property int $is_locked
|
* @property bool $is_locked
|
||||||
* @property int $send_email
|
* @property bool $send_email
|
||||||
* @property string|null $contact_key
|
* @property string|null $contact_key
|
||||||
* @property string|null $remember_token
|
* @property string|null $remember_token
|
||||||
* @property int|null $created_at
|
* @property int|null $created_at
|
||||||
|
@ -76,6 +76,7 @@ class PaymentType extends StaticModel
|
|||||||
const BACS = 49;
|
const BACS = 49;
|
||||||
const STRIPE_BANK_TRANSFER = 50;
|
const STRIPE_BANK_TRANSFER = 50;
|
||||||
const CASH_APP = 51;
|
const CASH_APP = 51;
|
||||||
|
const VENMO = 24;
|
||||||
|
|
||||||
public array $type_names = [
|
public array $type_names = [
|
||||||
self::CREDIT => 'payment_type_Credit',
|
self::CREDIT => 'payment_type_Credit',
|
||||||
@ -119,6 +120,7 @@ class PaymentType extends StaticModel
|
|||||||
self::Interac_E_Transfer => 'payment_type_Interac E Transfer',
|
self::Interac_E_Transfer => 'payment_type_Interac E Transfer',
|
||||||
self::STRIPE_BANK_TRANSFER => 'bank_transfer',
|
self::STRIPE_BANK_TRANSFER => 'bank_transfer',
|
||||||
self::CASH_APP => 'payment_type_Cash App',
|
self::CASH_APP => 'payment_type_Cash App',
|
||||||
|
self::VENMO => 'payment_type_Venmo',
|
||||||
];
|
];
|
||||||
|
|
||||||
public static function parseCardType($cardName)
|
public static function parseCardType($cardName)
|
||||||
|
@ -103,9 +103,9 @@ use Laracasts\Presenter\PresentableTrait;
|
|||||||
* @property-read mixed $valid_until
|
* @property-read mixed $valid_until
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Backup> $history
|
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Backup> $history
|
||||||
* @property-read int|null $history_count
|
* @property-read int|null $history_count
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\QuoteInvitation> $invitations
|
|
||||||
* @property-read int|null $invitations_count
|
* @property-read int|null $invitations_count
|
||||||
* @property-read \App\Models\Invoice|null $invoice
|
* @property-read \App\Models\Invoice|null $invoice
|
||||||
|
* @property-read \App\Models\QuoteInvitation|null $invitations
|
||||||
* @property-read \App\Models\Project|null $project
|
* @property-read \App\Models\Project|null $project
|
||||||
* @property-read \App\Models\User $user
|
* @property-read \App\Models\User $user
|
||||||
* @property-read \App\Models\Vendor|null $vendor
|
* @property-read \App\Models\Vendor|null $vendor
|
||||||
@ -185,50 +185,6 @@ use Laracasts\Presenter\PresentableTrait;
|
|||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Backup> $history
|
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Backup> $history
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\QuoteInvitation> $invitations
|
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\QuoteInvitation> $invitations
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Activity> $activities
|
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Backup> $history
|
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\QuoteInvitation> $invitations
|
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Activity> $activities
|
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Backup> $history
|
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\QuoteInvitation> $invitations
|
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Activity> $activities
|
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Backup> $history
|
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\QuoteInvitation> $invitations
|
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Activity> $activities
|
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Backup> $history
|
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\QuoteInvitation> $invitations
|
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Activity> $activities
|
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Backup> $history
|
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\QuoteInvitation> $invitations
|
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Activity> $activities
|
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Backup> $history
|
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\QuoteInvitation> $invitations
|
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Activity> $activities
|
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Backup> $history
|
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\QuoteInvitation> $invitations
|
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Activity> $activities
|
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Backup> $history
|
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\QuoteInvitation> $invitations
|
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Activity> $activities
|
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Backup> $history
|
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\QuoteInvitation> $invitations
|
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Activity> $activities
|
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Backup> $history
|
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\QuoteInvitation> $invitations
|
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Activity> $activities
|
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Document> $documents
|
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Backup> $history
|
|
||||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\QuoteInvitation> $invitations
|
|
||||||
* @mixin \Eloquent
|
* @mixin \Eloquent
|
||||||
*/
|
*/
|
||||||
class Quote extends BaseModel
|
class Quote extends BaseModel
|
||||||
|
@ -202,5 +202,16 @@ class Scheduler extends BaseModel
|
|||||||
$this->save();
|
$this->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function adjustOffset(): void
|
||||||
|
{
|
||||||
|
if (! $this->next_run) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$offset = $this->company->timezone_offset();
|
||||||
|
|
||||||
|
$this->next_run = $this->next_run->copy()->addSeconds($offset);
|
||||||
|
$this->save();
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,8 @@ use Illuminate\Database\Eloquent\ModelNotFoundException as ModelNotFoundExceptio
|
|||||||
* @method static \Illuminate\Database\Eloquent\Builder|StaticModel newQuery()
|
* @method static \Illuminate\Database\Eloquent\Builder|StaticModel newQuery()
|
||||||
* @method static \Illuminate\Database\Eloquent\Builder|StaticModel query()
|
* @method static \Illuminate\Database\Eloquent\Builder|StaticModel query()
|
||||||
* @method static \Illuminate\Database\Eloquent\Builder|StaticModel find()
|
* @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 findOrFail()
|
||||||
* @mixin \Eloquent
|
* @mixin \Eloquent
|
||||||
*/
|
*/
|
||||||
|
@ -320,7 +320,7 @@ class BaseDriver extends AbstractPaymentDriver
|
|||||||
$payment->company_gateway_id = $this->company_gateway->id;
|
$payment->company_gateway_id = $this->company_gateway->id;
|
||||||
$payment->status_id = $status;
|
$payment->status_id = $status;
|
||||||
$payment->currency_id = $this->client->getSetting('currency_id');
|
$payment->currency_id = $this->client->getSetting('currency_id');
|
||||||
$payment->date = Carbon::now();
|
$payment->date = Carbon::now()->addSeconds($this->client->company->timezone()->utc_offset)->format('Y-m-d');
|
||||||
$payment->gateway_type_id = $data['gateway_type_id'];
|
$payment->gateway_type_id = $data['gateway_type_id'];
|
||||||
|
|
||||||
$client_contact = $this->getContact();
|
$client_contact = $this->getContact();
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
namespace App\Repositories;
|
namespace App\Repositories;
|
||||||
|
|
||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
|
use App\Utils\Ninja;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CompanyRepository.
|
* CompanyRepository.
|
||||||
@ -31,12 +32,18 @@ class CompanyRepository extends BaseRepository
|
|||||||
*/
|
*/
|
||||||
public function save(array $data, Company $company) : ?Company
|
public function save(array $data, Company $company) : ?Company
|
||||||
{
|
{
|
||||||
|
|
||||||
if (isset($data['custom_fields']) && is_array($data['custom_fields'])) {
|
if (isset($data['custom_fields']) && is_array($data['custom_fields'])) {
|
||||||
$data['custom_fields'] = $this->parseCustomFields($data['custom_fields']);
|
$data['custom_fields'] = $this->parseCustomFields($data['custom_fields']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$company->fill($data);
|
$company->fill($data);
|
||||||
|
|
||||||
|
/** Only required to handle v4 migration workloads */
|
||||||
|
if(Ninja::isHosted() && $company->isDirty('is_disabled') && !$company->is_disabled) {
|
||||||
|
Ninja::triggerForwarding($company->company_key, $company->owner()->email);
|
||||||
|
}
|
||||||
|
|
||||||
if (array_key_exists('settings', $data)) {
|
if (array_key_exists('settings', $data)) {
|
||||||
$company->saveSettings($data['settings'], $company);
|
$company->saveSettings($data['settings'], $company);
|
||||||
}
|
}
|
||||||
@ -46,6 +53,12 @@ class CompanyRepository extends BaseRepository
|
|||||||
return $company;
|
return $company;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* parseCustomFields
|
||||||
|
*
|
||||||
|
* @param array $fields
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
private function parseCustomFields($fields) :array
|
private function parseCustomFields($fields) :array
|
||||||
{
|
{
|
||||||
foreach ($fields as &$value) {
|
foreach ($fields as &$value) {
|
||||||
|
@ -122,7 +122,7 @@ class PaymentMigrationRepository extends BaseRepository
|
|||||||
|
|
||||||
$invoices = Invoice::whereIn('id', array_column($data['invoices'], 'invoice_id'))->withTrashed()->get();
|
$invoices = Invoice::whereIn('id', array_column($data['invoices'], 'invoice_id'))->withTrashed()->get();
|
||||||
|
|
||||||
$payment->invoices()->saveMany($invoices);
|
$payment->invoices()->saveMany($invoices); // 1:1 relationship so this is ok
|
||||||
|
|
||||||
$payment->invoices->each(function ($inv) use ($invoice_totals, $refund_totals, $payment) {
|
$payment->invoices->each(function ($inv) use ($invoice_totals, $refund_totals, $payment) {
|
||||||
if ($payment->status_id != Payment::STATUS_CANCELLED || ! $payment->is_deleted) {
|
if ($payment->status_id != Payment::STATUS_CANCELLED || ! $payment->is_deleted) {
|
||||||
|
@ -11,19 +11,20 @@
|
|||||||
|
|
||||||
namespace App\Repositories;
|
namespace App\Repositories;
|
||||||
|
|
||||||
use App\Events\Payment\PaymentWasCreated;
|
use App\Utils\Ninja;
|
||||||
use App\Events\Payment\PaymentWasDeleted;
|
|
||||||
use App\Jobs\Credit\ApplyCreditPayment;
|
|
||||||
use App\Libraries\Currency\Conversion\CurrencyApi;
|
|
||||||
use App\Models\Client;
|
use App\Models\Client;
|
||||||
use App\Models\Credit;
|
use App\Models\Credit;
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
use App\Models\Payment;
|
use App\Models\Payment;
|
||||||
use App\Utils\Ninja;
|
use App\Models\Paymentable;
|
||||||
use App\Utils\Traits\MakesHash;
|
|
||||||
use App\Utils\Traits\SavesDocuments;
|
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Carbon;
|
use Illuminate\Support\Carbon;
|
||||||
|
use App\Utils\Traits\MakesHash;
|
||||||
|
use App\Utils\Traits\SavesDocuments;
|
||||||
|
use App\Jobs\Credit\ApplyCreditPayment;
|
||||||
|
use App\Events\Payment\PaymentWasCreated;
|
||||||
|
use App\Events\Payment\PaymentWasDeleted;
|
||||||
|
use App\Libraries\Currency\Conversion\CurrencyApi;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PaymentRepository.
|
* PaymentRepository.
|
||||||
@ -138,7 +139,7 @@ class PaymentRepository extends BaseRepository
|
|||||||
|
|
||||||
$invoices = Invoice::withTrashed()->whereIn('id', array_column($data['invoices'], 'invoice_id'))->get();
|
$invoices = Invoice::withTrashed()->whereIn('id', array_column($data['invoices'], 'invoice_id'))->get();
|
||||||
|
|
||||||
$payment->invoices()->saveMany($invoices);
|
// $payment->invoices()->saveMany($invoices); //25-06-2023
|
||||||
|
|
||||||
//todo optimize this into a single query
|
//todo optimize this into a single query
|
||||||
foreach ($data['invoices'] as $paid_invoice) {
|
foreach ($data['invoices'] as $paid_invoice) {
|
||||||
@ -146,6 +147,16 @@ class PaymentRepository extends BaseRepository
|
|||||||
$invoice = $invoices->firstWhere('id', $paid_invoice['invoice_id']);
|
$invoice = $invoices->firstWhere('id', $paid_invoice['invoice_id']);
|
||||||
|
|
||||||
if ($invoice) {
|
if ($invoice) {
|
||||||
|
|
||||||
|
//25-06-2023
|
||||||
|
|
||||||
|
$paymentable = new Paymentable();
|
||||||
|
$paymentable->payment_id = $payment->id;
|
||||||
|
$paymentable->paymentable_id = $invoice->id;
|
||||||
|
$paymentable->paymentable_type = 'invoices';
|
||||||
|
$paymentable->amount = $paid_invoice['amount'];
|
||||||
|
$paymentable->save();
|
||||||
|
|
||||||
$invoice = $invoice->service()
|
$invoice = $invoice->service()
|
||||||
->markSent()
|
->markSent()
|
||||||
->applyPayment($payment, $paid_invoice['amount'])
|
->applyPayment($payment, $paid_invoice['amount'])
|
||||||
@ -153,26 +164,30 @@ class PaymentRepository extends BaseRepository
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//payment is made, but not to any invoice, therefore we are applying the payment to the clients paid_to_date only
|
|
||||||
//01-07-2020 i think we were duplicating the paid to date here.
|
|
||||||
//$payment->client->service()->updatePaidToDate($payment->amount)->save();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (array_key_exists('credits', $data) && is_array($data['credits'])) {
|
if (array_key_exists('credits', $data) && is_array($data['credits'])) {
|
||||||
$credit_totals = array_sum(array_column($data['credits'], 'amount'));
|
$credit_totals = array_sum(array_column($data['credits'], 'amount'));
|
||||||
|
|
||||||
// $credits = Credit::whereIn('id', $this->transformKeys(array_column($data['credits'], 'credit_id')))->get();
|
|
||||||
|
|
||||||
$credits = Credit::whereIn('id', array_column($data['credits'], 'credit_id'))->get();
|
$credits = Credit::whereIn('id', array_column($data['credits'], 'credit_id'))->get();
|
||||||
|
|
||||||
$payment->credits()->saveMany($credits);
|
// $payment->credits()->saveMany($credits);
|
||||||
|
|
||||||
//todo optimize into a single query
|
//todo optimize into a single query
|
||||||
foreach ($data['credits'] as $paid_credit) {
|
foreach ($data['credits'] as $paid_credit) {
|
||||||
// $credit = Credit::withTrashed()->find($paid_credit['credit_id']);
|
|
||||||
$credit = $credits->firstWhere('id', $paid_credit['credit_id']);
|
$credit = $credits->firstWhere('id', $paid_credit['credit_id']);
|
||||||
|
|
||||||
if ($credit) {
|
if ($credit) {
|
||||||
|
|
||||||
|
$paymentable = new Paymentable();
|
||||||
|
$paymentable->payment_id = $payment->id;
|
||||||
|
$paymentable->paymentable_id = $credit->id;
|
||||||
|
$paymentable->paymentable_type = Credit::class;
|
||||||
|
$paymentable->amount = $paid_invoice['amount'];
|
||||||
|
$paymentable->save();
|
||||||
|
|
||||||
$credit = $credit->service()->markSent()->save();
|
$credit = $credit->service()->markSent()->save();
|
||||||
(new ApplyCreditPayment($credit, $payment, $paid_credit['amount'], $credit->company))->handle();
|
(new ApplyCreditPayment($credit, $payment, $paid_credit['amount'], $credit->company))->handle();
|
||||||
}
|
}
|
||||||
|
@ -30,8 +30,7 @@ class SchedulerRepository extends BaseRepository
|
|||||||
|
|
||||||
$scheduler->save();
|
$scheduler->save();
|
||||||
|
|
||||||
/** 18-5-2023 set client specific send times. */
|
$scheduler->adjustOffset();
|
||||||
$scheduler->calculateNextRun();
|
|
||||||
|
|
||||||
return $scheduler->fresh();
|
return $scheduler->fresh();
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ use App\Services\Email\Email;
|
|||||||
use App\Services\Email\EmailObject;
|
use App\Services\Email\EmailObject;
|
||||||
use App\Utils\Number;
|
use App\Utils\Number;
|
||||||
use App\Utils\Traits\MakesDates;
|
use App\Utils\Traits\MakesDates;
|
||||||
|
use Carbon\Carbon;
|
||||||
use Illuminate\Mail\Mailables\Address;
|
use Illuminate\Mail\Mailables\Address;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
@ -149,6 +150,11 @@ class ClientService
|
|||||||
$pdf = $statement->run();
|
$pdf = $statement->run();
|
||||||
|
|
||||||
if ($send_email) {
|
if ($send_email) {
|
||||||
|
// If selected, ignore clients that don't have any invoices to put on the statement.
|
||||||
|
if (!empty($options['only_clients_with_invoices']) && $statement->getInvoices()->count() == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return $this->emailStatement($pdf, $statement->options);
|
return $this->emailStatement($pdf, $statement->options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,6 +211,9 @@ class Statement
|
|||||||
$this->options['show_credits_table'] = false;
|
$this->options['show_credits_table'] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!\array_key_exists('only_clients_with_invoices', $this->options)) {
|
||||||
|
$this->options['only_clients_with_invoices'] = false;
|
||||||
|
}
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
@ -220,7 +223,7 @@ class Statement
|
|||||||
*
|
*
|
||||||
* @return Invoice[]|\Illuminate\Support\LazyCollection
|
* @return Invoice[]|\Illuminate\Support\LazyCollection
|
||||||
*/
|
*/
|
||||||
protected function getInvoices(): \Illuminate\Support\LazyCollection
|
public function getInvoices(): \Illuminate\Support\LazyCollection
|
||||||
{
|
{
|
||||||
return Invoice::withTrashed()
|
return Invoice::withTrashed()
|
||||||
->with('payments.type')
|
->with('payments.type')
|
||||||
|
@ -119,7 +119,7 @@ class CreditService
|
|||||||
$payment->type_id = PaymentType::CREDIT;
|
$payment->type_id = PaymentType::CREDIT;
|
||||||
$payment->is_manual = true;
|
$payment->is_manual = true;
|
||||||
$payment->currency_id = $this->credit->client->getSetting('currency_id');
|
$payment->currency_id = $this->credit->client->getSetting('currency_id');
|
||||||
$payment->date = now();
|
$payment->date = now()->addSeconds($this->credit->company->timezone()->utc_offset)->format('Y-m-d');
|
||||||
|
|
||||||
$payment->saveQuietly();
|
$payment->saveQuietly();
|
||||||
$payment->number = $payment->client->getNextPaymentNumber($payment->client, $payment);
|
$payment->number = $payment->client->getNextPaymentNumber($payment->client, $payment);
|
||||||
@ -243,7 +243,7 @@ class CreditService
|
|||||||
|
|
||||||
public function triggeredActions($request)
|
public function triggeredActions($request)
|
||||||
{
|
{
|
||||||
$this->invoice = (new TriggeredActions($this->credit, $request))->run();
|
$this->credit = (new TriggeredActions($this->credit, $request))->run();
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
@ -61,6 +61,10 @@ class TriggeredActions extends AbstractService
|
|||||||
$company->save();
|
$company->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->request->has('mark_paid') && $this->request->input('mark_paid') == 'true') {
|
||||||
|
$this->credit->service()->markPaid()->save();
|
||||||
|
}
|
||||||
|
|
||||||
return $this->credit;
|
return $this->credit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,9 +84,9 @@ class ApplyPayment extends AbstractService
|
|||||||
/* Update Pivot Record amount */
|
/* Update Pivot Record amount */
|
||||||
$this->payment->invoices->each(function ($inv) use ($amount_paid) {
|
$this->payment->invoices->each(function ($inv) use ($amount_paid) {
|
||||||
if ($inv->id == $this->invoice->id) {
|
if ($inv->id == $this->invoice->id) {
|
||||||
$inv->pivot->amount = ($amount_paid * -1);
|
// $inv->pivot->amount = ($amount_paid * -1);
|
||||||
$inv->pivot->save();
|
// $inv->pivot->save();
|
||||||
|
//25-06-2023
|
||||||
$inv->paid_to_date += floatval($amount_paid * -1);
|
$inv->paid_to_date += floatval($amount_paid * -1);
|
||||||
$inv->save();
|
$inv->save();
|
||||||
}
|
}
|
||||||
|
@ -179,7 +179,7 @@ class AutoBillInvoice extends AbstractService
|
|||||||
$payment->applied = $amount;
|
$payment->applied = $amount;
|
||||||
$payment->client_id = $this->invoice->client_id;
|
$payment->client_id = $this->invoice->client_id;
|
||||||
$payment->currency_id = $this->invoice->client->getSetting('currency_id');
|
$payment->currency_id = $this->invoice->client->getSetting('currency_id');
|
||||||
$payment->date = now();
|
$payment->date = now()->addSeconds($this->invoice->company->timezone()->utc_offset)->format('Y-m-d');
|
||||||
$payment->status_id = Payment::STATUS_COMPLETED;
|
$payment->status_id = Payment::STATUS_COMPLETED;
|
||||||
$payment->type_id = PaymentType::CREDIT;
|
$payment->type_id = PaymentType::CREDIT;
|
||||||
$payment->service()->applyNumber()->save();
|
$payment->service()->applyNumber()->save();
|
||||||
|
@ -33,14 +33,7 @@ class SendEmail
|
|||||||
$this->contact = $this->payment->client->contacts()->first();
|
$this->contact = $this->payment->client->contacts()->first();
|
||||||
}
|
}
|
||||||
|
|
||||||
// $this->payment->invoices->sortByDesc('id')->first(function ($invoice) {
|
|
||||||
// $invoice->invitations->each(function ($invitation) {
|
|
||||||
// if (!$invitation->contact->trashed() && $invitation->contact->email) {
|
|
||||||
EmailPayment::dispatch($this->payment, $this->payment->company, $this->contact);
|
EmailPayment::dispatch($this->payment, $this->payment->company, $this->contact);
|
||||||
|
|
||||||
// event(new PaymentWasEmailed($this->payment, $this->payment->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -276,9 +276,8 @@ class Design extends BaseDesign
|
|||||||
|
|
||||||
$header = [];
|
$header = [];
|
||||||
$header[] = ['element' => 'p', 'content' => ctrans('texts.shipping_address'), 'properties' => ['data-ref' => 'shipping_address-label', 'style' => 'font-weight: bold; text-transform: uppercase']];
|
$header[] = ['element' => 'p', 'content' => ctrans('texts.shipping_address'), 'properties' => ['data-ref' => 'shipping_address-label', 'style' => 'font-weight: bold; text-transform: uppercase']];
|
||||||
return array_merge($header, $elements);
|
|
||||||
|
|
||||||
// return $elements;
|
return array_merge($header, $elements);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -320,73 +319,6 @@ class Design extends BaseDesign
|
|||||||
return $elements;
|
return $elements;
|
||||||
}
|
}
|
||||||
|
|
||||||
//@deprecated
|
|
||||||
// public function entityDetailsx(): array
|
|
||||||
// {
|
|
||||||
// if ($this->type === 'statement') {
|
|
||||||
// $s_date = $this->translateDate($this->options['start_date'], $this->client->date_format(), $this->client->locale()) . " - " . $this->translateDate($this->options['end_date'], $this->client->date_format(), $this->client->locale());
|
|
||||||
|
|
||||||
// return [
|
|
||||||
// ['element' => 'p', 'content' => "<h2>".ctrans('texts.statement')."</h2>", 'properties' => ['data-ref' => 'statement-label']],
|
|
||||||
// ['element' => 'p', 'content' => ctrans('texts.statement_date'), 'properties' => ['data-ref' => 'statement-label'],'elements' =>
|
|
||||||
// ['element' => 'span', 'content' => "{$s_date} "]
|
|
||||||
// ],
|
|
||||||
// ['element' => 'p', 'content' => '$balance_due_label', 'properties' => ['data-ref' => 'statement-label'],'elements' =>
|
|
||||||
// ['element' => 'span', 'content' => Number::formatMoney($this->invoices->sum('balance'), $this->client)]
|
|
||||||
// ],
|
|
||||||
// ];
|
|
||||||
// }
|
|
||||||
|
|
||||||
// $variables = $this->context['pdf_variables']['invoice_details'];
|
|
||||||
|
|
||||||
// if ($this->entity instanceof Quote) {
|
|
||||||
// $variables = $this->context['pdf_variables']['quote_details'];
|
|
||||||
|
|
||||||
// if ($this->entity->partial > 0) {
|
|
||||||
// $variables[] = '$quote.balance_due';
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if ($this->entity instanceof Credit) {
|
|
||||||
// $variables = $this->context['pdf_variables']['credit_details'];
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if ($this->vendor) {
|
|
||||||
// $variables = $this->context['pdf_variables']['purchase_order_details'];
|
|
||||||
// }
|
|
||||||
|
|
||||||
// $elements = [];
|
|
||||||
|
|
||||||
// // We don't want to show account balance or invoice total on PDF.. or any amount with currency.
|
|
||||||
// if ($this->type == self::DELIVERY_NOTE) {
|
|
||||||
// $variables = array_filter($variables, function ($m) {
|
|
||||||
// return !in_array($m, ['$invoice.balance_due', '$invoice.total']);
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
// foreach ($variables as $variable) {
|
|
||||||
// $_variable = explode('.', $variable)[1];
|
|
||||||
// $_customs = ['custom1', 'custom2', 'custom3', 'custom4'];
|
|
||||||
|
|
||||||
// /* 2/7/2022 don't show custom values if they are empty */
|
|
||||||
// $var = str_replace("custom", "custom_value", $_variable);
|
|
||||||
|
|
||||||
// if (in_array($_variable, $_customs) && !empty($this->entity->{$var})) {
|
|
||||||
// $elements[] = ['element' => 'div', 'properties' => ['style' => "display: table-row; visibility: {$this->entityVariableCheck($_variable)};"],'elements' => [
|
|
||||||
// ['element' => 'div', 'content' => $variable . '_label', 'properties' => ['class' => 'entity-details-cell', 'data-ref' => 'entity_details-' . substr($variable, 1) . '_label']],
|
|
||||||
// ['element' => 'div', 'content' => $variable, 'properties' => ['class' => 'entity-details-cell', 'data-ref' => 'entity_details-' . substr($variable, 1)]],
|
|
||||||
// ]];
|
|
||||||
// } else {
|
|
||||||
// $elements[] = ['element' => 'div', 'properties' => ['style' => "display: table-row; visibility: {$this->entityVariableCheck($variable)};"], 'elements' => [
|
|
||||||
// ['element' => 'div', 'content' => $variable . '_label', 'properties' => ['class' => 'entity-details-cell','data-ref' => 'entity_details-' . substr($variable, 1) . '_label']],
|
|
||||||
// ['element' => 'div', 'content' => $variable, 'properties' => ['class' => 'entity-details-cell','data-ref' => 'entity_details-' . substr($variable, 1)]],
|
|
||||||
// ]];
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return $elements;
|
|
||||||
// }
|
|
||||||
|
|
||||||
public function entityDetails(): array
|
public function entityDetails(): array
|
||||||
{
|
{
|
||||||
if ($this->type === 'statement') {
|
if ($this->type === 'statement') {
|
||||||
@ -912,7 +844,6 @@ class Design extends BaseDesign
|
|||||||
|
|
||||||
$variables = $this->context['pdf_variables']['total_columns'];
|
$variables = $this->context['pdf_variables']['total_columns'];
|
||||||
|
|
||||||
|
|
||||||
$elements = [
|
$elements = [
|
||||||
['element' => 'div', 'properties' => ['style' => 'display: flex; flex-direction: column;'], 'elements' => [
|
['element' => 'div', 'properties' => ['style' => 'display: flex; flex-direction: column;'], 'elements' => [
|
||||||
['element' => 'p', 'content' => strtr(str_replace(["labels","values"], ["",""], $_variables['values']['$entity.public_notes']), $_variables), 'properties' => ['data-ref' => 'total_table-public_notes', 'style' => 'text-align: left;']],
|
['element' => 'p', 'content' => strtr(str_replace(["labels","values"], ["",""], $_variables['values']['$entity.public_notes']), $_variables), 'properties' => ['data-ref' => 'total_table-public_notes', 'style' => 'text-align: left;']],
|
||||||
|
@ -37,8 +37,6 @@ class SendEmail
|
|||||||
*/
|
*/
|
||||||
public function run()
|
public function run()
|
||||||
{
|
{
|
||||||
nlog($this->reminder_template);
|
|
||||||
nlog("is there a template");
|
|
||||||
|
|
||||||
if (! $this->reminder_template) {
|
if (! $this->reminder_template) {
|
||||||
$this->reminder_template = $this->quote->calculateTemplate('quote');
|
$this->reminder_template = $this->quote->calculateTemplate('quote');
|
||||||
|
@ -20,6 +20,8 @@ class GetInvoicePdf extends AbstractService
|
|||||||
{
|
{
|
||||||
public $entity;
|
public $entity;
|
||||||
|
|
||||||
|
public $contact;
|
||||||
|
|
||||||
public function __construct($entity, ClientContact $contact = null)
|
public function __construct($entity, ClientContact $contact = null)
|
||||||
{
|
{
|
||||||
$this->entity = $entity;
|
$this->entity = $entity;
|
||||||
|
@ -11,18 +11,19 @@
|
|||||||
|
|
||||||
namespace App\Services\Report;
|
namespace App\Services\Report;
|
||||||
|
|
||||||
use App\Libraries\Currency\Conversion\CurrencyApi;
|
|
||||||
use App\Libraries\MultiDB;
|
|
||||||
use App\Models\Company;
|
|
||||||
use App\Models\Currency;
|
|
||||||
use App\Models\Expense;
|
|
||||||
use App\Models\Payment;
|
|
||||||
use App\Utils\Ninja;
|
use App\Utils\Ninja;
|
||||||
use App\Utils\Number;
|
use App\Utils\Number;
|
||||||
|
use League\Csv\Writer;
|
||||||
|
use App\Models\Company;
|
||||||
|
use App\Models\Expense;
|
||||||
|
use App\Models\Invoice;
|
||||||
|
use App\Models\Payment;
|
||||||
|
use App\Models\Currency;
|
||||||
|
use App\Libraries\MultiDB;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
use Illuminate\Support\Carbon;
|
use Illuminate\Support\Carbon;
|
||||||
use Illuminate\Support\Facades\App;
|
use Illuminate\Support\Facades\App;
|
||||||
use Illuminate\Support\Str;
|
use App\Libraries\Currency\Conversion\CurrencyApi;
|
||||||
use League\Csv\Writer;
|
|
||||||
|
|
||||||
class ProfitLoss
|
class ProfitLoss
|
||||||
{
|
{
|
||||||
@ -279,8 +280,6 @@ class ProfitLoss
|
|||||||
->with(['company', 'client'])
|
->with(['company', 'client'])
|
||||||
->cursor()
|
->cursor()
|
||||||
->each(function ($payment) {
|
->each(function ($payment) {
|
||||||
$company = $payment->company;
|
|
||||||
$client = $payment->client;
|
|
||||||
|
|
||||||
$map = new \stdClass;
|
$map = new \stdClass;
|
||||||
$amount_payment_paid = 0;
|
$amount_payment_paid = 0;
|
||||||
@ -293,17 +292,20 @@ class ProfitLoss
|
|||||||
$tax_amount_credit_converted = $tax_amount_credit_converted = 0;
|
$tax_amount_credit_converted = $tax_amount_credit_converted = 0;
|
||||||
|
|
||||||
foreach ($payment->paymentables as $pivot) {
|
foreach ($payment->paymentables as $pivot) {
|
||||||
if ($pivot->paymentable instanceof \App\Models\Invoice) {
|
if ($pivot->paymentable_type == 'invoices') {
|
||||||
$invoice = $pivot->paymentable;
|
$invoice = Invoice::withTrashed()->find($pivot->paymentable_id);
|
||||||
|
|
||||||
$amount_payment_paid += $pivot->amount - $pivot->refunded;
|
$amount_payment_paid += $pivot->amount - $pivot->refunded;
|
||||||
$amount_payment_paid_converted += $amount_payment_paid / ($payment->exchange_rate ?: 1);
|
$amount_payment_paid_converted += $amount_payment_paid / ($payment->exchange_rate ?: 1);
|
||||||
|
|
||||||
|
if ($invoice->amount > 0) {
|
||||||
$tax_amount += ($amount_payment_paid / $invoice->amount) * $invoice->total_taxes;
|
$tax_amount += ($amount_payment_paid / $invoice->amount) * $invoice->total_taxes;
|
||||||
$tax_amount_converted += (($amount_payment_paid / $invoice->amount) * $invoice->total_taxes) / $payment->exchange_rate;
|
$tax_amount_converted += (($amount_payment_paid / $invoice->amount) * $invoice->total_taxes) / $payment->exchange_rate;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($pivot->paymentable instanceof \App\Models\Credit) {
|
}
|
||||||
|
|
||||||
|
if ($pivot->paymentable_type == 'credits') {
|
||||||
$amount_credit_paid += $pivot->amount - $pivot->refunded;
|
$amount_credit_paid += $pivot->amount - $pivot->refunded;
|
||||||
$amount_credit_paid_converted += $amount_payment_paid / ($payment->exchange_rate ?: 1);
|
$amount_credit_paid_converted += $amount_payment_paid / ($payment->exchange_rate ?: 1);
|
||||||
|
|
||||||
@ -593,52 +595,50 @@ class ProfitLoss
|
|||||||
case 'all':
|
case 'all':
|
||||||
$this->start_date = now()->subYears(50);
|
$this->start_date = now()->subYears(50);
|
||||||
$this->end_date = now();
|
$this->end_date = now();
|
||||||
// return $query;
|
break;
|
||||||
// no break
|
|
||||||
case 'last7':
|
case 'last7':
|
||||||
$this->start_date = now()->subDays(7);
|
$this->start_date = now()->subDays(7);
|
||||||
$this->end_date = now();
|
$this->end_date = now();
|
||||||
// return $query->whereBetween($this->date_key, [now()->subDays(7), now()])->orderBy($this->date_key, 'ASC');
|
break;
|
||||||
// no break
|
|
||||||
case 'last30':
|
case 'last30':
|
||||||
$this->start_date = now()->subDays(30);
|
$this->start_date = now()->subDays(30);
|
||||||
$this->end_date = now();
|
$this->end_date = now();
|
||||||
// return $query->whereBetween($this->date_key, [now()->subDays(30), now()])->orderBy($this->date_key, 'ASC');
|
break;
|
||||||
// no break
|
|
||||||
case 'this_month':
|
case 'this_month':
|
||||||
$this->start_date = now()->startOfMonth();
|
$this->start_date = now()->startOfMonth();
|
||||||
$this->end_date = now();
|
$this->end_date = now();
|
||||||
//return $query->whereBetween($this->date_key, [now()->startOfMonth(), now()])->orderBy($this->date_key, 'ASC');
|
break;
|
||||||
// no break
|
|
||||||
case 'last_month':
|
case 'last_month':
|
||||||
$this->start_date = now()->startOfMonth()->subMonth();
|
$this->start_date = now()->startOfMonth()->subMonth();
|
||||||
$this->end_date = now()->startOfMonth()->subMonth()->endOfMonth();
|
$this->end_date = now()->startOfMonth()->subMonth()->endOfMonth();
|
||||||
//return $query->whereBetween($this->date_key, [now()->startOfMonth()->subMonth(), now()->startOfMonth()->subMonth()->endOfMonth()])->orderBy($this->date_key, 'ASC');
|
break;
|
||||||
// no break
|
|
||||||
case 'this_quarter':
|
case 'this_quarter':
|
||||||
$this->start_date = (new \Carbon\Carbon('-3 months'))->firstOfQuarter();
|
$this->start_date = (new \Carbon\Carbon('-3 months'))->firstOfQuarter();
|
||||||
$this->end_date = (new \Carbon\Carbon('-3 months'))->lastOfQuarter();
|
$this->end_date = (new \Carbon\Carbon('-3 months'))->lastOfQuarter();
|
||||||
//return $query->whereBetween($this->date_key, [(new \Carbon\Carbon('-3 months'))->firstOfQuarter(), (new \Carbon\Carbon('-3 months'))->lastOfQuarter()])->orderBy($this->date_key, 'ASC');
|
break;
|
||||||
// no break
|
|
||||||
case 'last_quarter':
|
case 'last_quarter':
|
||||||
$this->start_date = (new \Carbon\Carbon('-6 months'))->firstOfQuarter();
|
$this->start_date = (new \Carbon\Carbon('-6 months'))->firstOfQuarter();
|
||||||
$this->end_date = (new \Carbon\Carbon('-6 months'))->lastOfQuarter();
|
$this->end_date = (new \Carbon\Carbon('-6 months'))->lastOfQuarter();
|
||||||
//return $query->whereBetween($this->date_key, [(new \Carbon\Carbon('-6 months'))->firstOfQuarter(), (new \Carbon\Carbon('-6 months'))->lastOfQuarter()])->orderBy($this->date_key, 'ASC');
|
break;
|
||||||
// no break
|
|
||||||
case 'this_year':
|
case 'this_year':
|
||||||
$this->start_date = now()->startOfYear();
|
$this->start_date = now()->startOfYear();
|
||||||
$this->end_date = now();
|
$this->end_date = now();
|
||||||
//return $query->whereBetween($this->date_key, [now()->startOfYear(), now()])->orderBy($this->date_key, 'ASC');
|
break;
|
||||||
// no break
|
|
||||||
case 'custom':
|
case 'custom':
|
||||||
$this->start_date = $custom_start_date;
|
$this->start_date = $custom_start_date;
|
||||||
$this->end_date = $custom_end_date;
|
$this->end_date = $custom_end_date;
|
||||||
//return $query->whereBetween($this->date_key, [$custom_start_date, $custom_end_date])->orderBy($this->date_key, 'ASC');
|
break;
|
||||||
// no break
|
|
||||||
default:
|
default:
|
||||||
$this->start_date = now()->startOfYear();
|
$this->start_date = now()->startOfYear();
|
||||||
$this->end_date = now();
|
$this->end_date = now();
|
||||||
// return $query->whereBetween($this->date_key, [now()->startOfYear(), now()])->orderBy($this->date_key, 'ASC');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
|
@ -11,11 +11,12 @@
|
|||||||
|
|
||||||
namespace App\Services\Scheduler;
|
namespace App\Services\Scheduler;
|
||||||
|
|
||||||
|
use App\DataMapper\Schedule\EmailStatement;
|
||||||
use App\Models\Client;
|
use App\Models\Client;
|
||||||
use App\Models\Scheduler;
|
use App\Models\Scheduler;
|
||||||
use App\Utils\Traits\MakesHash;
|
|
||||||
use App\DataMapper\Schedule\EmailStatement;
|
|
||||||
use App\Utils\Traits\MakesDates;
|
use App\Utils\Traits\MakesDates;
|
||||||
|
use App\Utils\Traits\MakesHash;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
|
||||||
class EmailStatementService
|
class EmailStatementService
|
||||||
{
|
{
|
||||||
@ -37,7 +38,7 @@ class EmailStatementService
|
|||||||
//Email only the selected clients
|
//Email only the selected clients
|
||||||
if (count($this->scheduler->parameters['clients']) >= 1) {
|
if (count($this->scheduler->parameters['clients']) >= 1) {
|
||||||
$query->whereIn('id', $this->transformKeys($this->scheduler->parameters['clients']));
|
$query->whereIn('id', $this->transformKeys($this->scheduler->parameters['clients']));
|
||||||
}else {
|
} else {
|
||||||
$query->where('balance', '>', 0);
|
$query->where('balance', '>', 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,7 +47,7 @@ class EmailStatementService
|
|||||||
$this->client = $_client;
|
$this->client = $_client;
|
||||||
|
|
||||||
//work out the date range
|
//work out the date range
|
||||||
$statement_properties = $this->calculateStatementProperties();
|
$statement_properties = $this->calculateStatementProperties($_client);
|
||||||
|
|
||||||
$_client->service()->statement($statement_properties, true);
|
$_client->service()->statement($statement_properties, true);
|
||||||
});
|
});
|
||||||
@ -61,16 +62,17 @@ class EmailStatementService
|
|||||||
*
|
*
|
||||||
* @return array The statement options array
|
* @return array The statement options array
|
||||||
*/
|
*/
|
||||||
private function calculateStatementProperties(): array
|
private function calculateStatementProperties(Client $client): array
|
||||||
{
|
{
|
||||||
$start_end = $this->calculateStartAndEndDates();
|
$start_end = $this->calculateStartAndEndDates($client);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'start_date' =>$start_end[0],
|
'start_date' => $start_end[0],
|
||||||
'end_date' =>$start_end[1],
|
'end_date' => $start_end[1],
|
||||||
'show_payments_table' => $this->scheduler->parameters['show_payments_table'] ?? true,
|
'show_payments_table' => $this->scheduler->parameters['show_payments_table'] ?? true,
|
||||||
'show_aging_table' => $this->scheduler->parameters['show_aging_table'] ?? true,
|
'show_aging_table' => $this->scheduler->parameters['show_aging_table'] ?? true,
|
||||||
'show_credits_table' => $this->scheduler->parameters['show_credits_table'] ?? true,
|
'show_credits_table' => $this->scheduler->parameters['show_credits_table'] ?? true,
|
||||||
|
'only_clients_with_invoices' => $this->scheduler->parameters['only_clients_with_invoices'] ?? false,
|
||||||
'status' => $this->scheduler->parameters['status']
|
'status' => $this->scheduler->parameters['status']
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@ -80,7 +82,7 @@ class EmailStatementService
|
|||||||
*
|
*
|
||||||
* @return array [$start_date, $end_date];
|
* @return array [$start_date, $end_date];
|
||||||
*/
|
*/
|
||||||
private function calculateStartAndEndDates(): array
|
private function calculateStartAndEndDates(Client $client): array
|
||||||
{
|
{
|
||||||
return match ($this->scheduler->parameters['date_range']) {
|
return match ($this->scheduler->parameters['date_range']) {
|
||||||
EmailStatement::LAST7 => [now()->startOfDay()->subDays(7)->format('Y-m-d'), now()->startOfDay()->format('Y-m-d')],
|
EmailStatement::LAST7 => [now()->startOfDay()->subDays(7)->format('Y-m-d'), now()->startOfDay()->format('Y-m-d')],
|
||||||
@ -92,6 +94,11 @@ class EmailStatementService
|
|||||||
EmailStatement::LAST_QUARTER => [now()->startOfDay()->subQuarterNoOverflow()->firstOfQuarter()->format('Y-m-d'), now()->startOfDay()->subQuarterNoOverflow()->lastOfQuarter()->format('Y-m-d')],
|
EmailStatement::LAST_QUARTER => [now()->startOfDay()->subQuarterNoOverflow()->firstOfQuarter()->format('Y-m-d'), now()->startOfDay()->subQuarterNoOverflow()->lastOfQuarter()->format('Y-m-d')],
|
||||||
EmailStatement::THIS_YEAR => [now()->startOfDay()->firstOfYear()->format('Y-m-d'), now()->startOfDay()->lastOfYear()->format('Y-m-d')],
|
EmailStatement::THIS_YEAR => [now()->startOfDay()->firstOfYear()->format('Y-m-d'), now()->startOfDay()->lastOfYear()->format('Y-m-d')],
|
||||||
EmailStatement::LAST_YEAR => [now()->startOfDay()->subYearNoOverflow()->firstOfYear()->format('Y-m-d'), now()->startOfDay()->subYearNoOverflow()->lastOfYear()->format('Y-m-d')],
|
EmailStatement::LAST_YEAR => [now()->startOfDay()->subYearNoOverflow()->firstOfYear()->format('Y-m-d'), now()->startOfDay()->subYearNoOverflow()->lastOfYear()->format('Y-m-d')],
|
||||||
|
EmailStatement::ALL_TIME => [
|
||||||
|
$client->invoices()->selectRaw('MIN(invoices.date) as start_date')->pluck('start_date')->first()
|
||||||
|
?: Carbon::now()->format('Y-m-d'),
|
||||||
|
Carbon::now()->format('Y-m-d')
|
||||||
|
],
|
||||||
EmailStatement::CUSTOM_RANGE => [$this->scheduler->parameters['start_date'], $this->scheduler->parameters['end_date']],
|
EmailStatement::CUSTOM_RANGE => [$this->scheduler->parameters['start_date'], $this->scheduler->parameters['end_date']],
|
||||||
default => [now()->startOfDay()->firstOfMonth()->format('Y-m-d'), now()->startOfDay()->lastOfMonth()->format('Y-m-d')],
|
default => [now()->startOfDay()->firstOfMonth()->format('Y-m-d'), now()->startOfDay()->lastOfMonth()->format('Y-m-d')],
|
||||||
};
|
};
|
||||||
|
@ -132,7 +132,7 @@ class TaxProvider
|
|||||||
'city' => $this->client->shipping_city,
|
'city' => $this->client->shipping_city,
|
||||||
'state' => $this->client->shipping_state,
|
'state' => $this->client->shipping_state,
|
||||||
'postal_code' => $this->client->shipping_postal_code,
|
'postal_code' => $this->client->shipping_postal_code,
|
||||||
'country' => $this->client->shipping_country->name,
|
'country' => $this->client->shipping_country()->exists() ? $this->client->shipping_country->name : $this->client->country->name,
|
||||||
];
|
];
|
||||||
|
|
||||||
$taxable_address = $this->taxShippingAddress() ? $shipping_details : $billing_details;
|
$taxable_address = $this->taxShippingAddress() ? $shipping_details : $billing_details;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoice Ninja (https://invoiceninja.com).
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
*
|
*
|
||||||
@ -11,8 +12,10 @@
|
|||||||
|
|
||||||
namespace App\Transformers;
|
namespace App\Transformers;
|
||||||
|
|
||||||
|
use App\Models\Client;
|
||||||
use App\Models\Document;
|
use App\Models\Document;
|
||||||
use App\Models\Project;
|
use App\Models\Project;
|
||||||
|
use App\Models\Task;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -30,6 +33,8 @@ class ProjectTransformer extends EntityTransformer
|
|||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $availableIncludes = [
|
protected $availableIncludes = [
|
||||||
|
'client',
|
||||||
|
'tasks',
|
||||||
];
|
];
|
||||||
|
|
||||||
public function includeDocuments(Project $project)
|
public function includeDocuments(Project $project)
|
||||||
@ -39,6 +44,20 @@ class ProjectTransformer extends EntityTransformer
|
|||||||
return $this->includeCollection($project->documents, $transformer, Document::class);
|
return $this->includeCollection($project->documents, $transformer, Document::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function includeClient(Project $project): \League\Fractal\Resource\Item
|
||||||
|
{
|
||||||
|
$transformer = new ClientTransformer($this->serializer);
|
||||||
|
|
||||||
|
return $this->includeItem($project->client, $transformer, Client::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function includeTasks(Project $project): \League\Fractal\Resource\Collection
|
||||||
|
{
|
||||||
|
$transformer = new TaskTransformer($this->serializer);
|
||||||
|
|
||||||
|
return $this->includeCollection($project->tasks, $transformer, Task::class);
|
||||||
|
}
|
||||||
|
|
||||||
public function transform(Project $project)
|
public function transform(Project $project)
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
|
@ -36,6 +36,7 @@ class TaskTransformer extends EntityTransformer
|
|||||||
'client',
|
'client',
|
||||||
'status',
|
'status',
|
||||||
'project',
|
'project',
|
||||||
|
'user',
|
||||||
];
|
];
|
||||||
|
|
||||||
public function includeDocuments(Task $task)
|
public function includeDocuments(Task $task)
|
||||||
@ -45,6 +46,18 @@ class TaskTransformer extends EntityTransformer
|
|||||||
return $this->includeCollection($task->documents, $transformer, Document::class);
|
return $this->includeCollection($task->documents, $transformer, Document::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function includeUser(Task $task): ?Item
|
||||||
|
{
|
||||||
|
$transformer = new UserTransformer($this->serializer);
|
||||||
|
|
||||||
|
if (!$task->user) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->includeItem($task->user, $transformer, User::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public function includeClient(Task $task): ?Item
|
public function includeClient(Task $task): ?Item
|
||||||
{
|
{
|
||||||
$transformer = new ClientTransformer($this->serializer);
|
$transformer = new ClientTransformer($this->serializer);
|
||||||
|
@ -356,10 +356,9 @@ class HtmlEngine
|
|||||||
$data['$credit.total'] = &$data['$credit.total'];
|
$data['$credit.total'] = &$data['$credit.total'];
|
||||||
$data['$credit.po_number'] = &$data['$invoice.po_number'];
|
$data['$credit.po_number'] = &$data['$invoice.po_number'];
|
||||||
$data['$credit.date'] = ['value' => $this->translateDate($this->entity->date, $this->client->date_format(), $this->client->locale()), 'label' => ctrans('texts.credit_date')];
|
$data['$credit.date'] = ['value' => $this->translateDate($this->entity->date, $this->client->date_format(), $this->client->locale()), 'label' => ctrans('texts.credit_date')];
|
||||||
$data['$balance'] = ['value' => Number::formatMoney($this->entity_calc->getBalance(), $this->client) ?: ' ', 'label' => ctrans('texts.balance')];
|
$data['$balance'] = ['value' => Number::formatMoney($this->getBalance(), $this->client) ?: ' ', 'label' => ctrans('texts.balance')];
|
||||||
$data['$credit.balance'] = ['value' => Number::formatMoney($this->entity_calc->getBalance(), $this->client) ?: ' ', 'label' => ctrans('texts.credit_balance')];
|
$data['$credit.balance'] = ['value' => Number::formatMoney($this->entity_calc->getBalance(), $this->client) ?: ' ', 'label' => ctrans('texts.credit_balance')];
|
||||||
|
|
||||||
|
|
||||||
$data['$invoice.balance'] = &$data['$balance'];
|
$data['$invoice.balance'] = &$data['$balance'];
|
||||||
$data['$taxes'] = ['value' => Number::formatMoney($this->entity_calc->getItemTotalTaxes(), $this->client) ?: ' ', 'label' => ctrans('texts.taxes')];
|
$data['$taxes'] = ['value' => Number::formatMoney($this->entity_calc->getItemTotalTaxes(), $this->client) ?: ' ', 'label' => ctrans('texts.taxes')];
|
||||||
$data['$invoice.taxes'] = &$data['$taxes'];
|
$data['$invoice.taxes'] = &$data['$taxes'];
|
||||||
@ -675,6 +674,15 @@ class HtmlEngine
|
|||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getBalance()
|
||||||
|
{
|
||||||
|
if($this->entity->status_id == 1){
|
||||||
|
return $this->entity->amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->entity->balance;
|
||||||
|
}
|
||||||
|
|
||||||
public function makeValues() :array
|
public function makeValues() :array
|
||||||
{
|
{
|
||||||
$data = [];
|
$data = [];
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
namespace App\Utils;
|
namespace App\Utils;
|
||||||
|
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Http;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class Ninja.
|
* Class Ninja.
|
||||||
@ -152,6 +153,23 @@ class Ninja
|
|||||||
return $translations;
|
return $translations;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function triggerForwarding(string $company_key, string $email)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$x = Http::withHeaders([
|
||||||
|
'X-API-HOSTED-SECRET' => config('ninja.ninja_hosted_secret'),
|
||||||
|
])->post(config('ninja.license_url').'/api/v1/enable_forwarding', [
|
||||||
|
'account_key' => $company_key,
|
||||||
|
'email' => $email,
|
||||||
|
]);
|
||||||
|
|
||||||
|
nlog($x->body());
|
||||||
|
}
|
||||||
|
catch (\Exception $e) {
|
||||||
|
nlog("Attempt forwarding for {$email} - {$company_key} Failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function createLicense($request)
|
public function createLicense($request)
|
||||||
{
|
{
|
||||||
// $affiliate = Affiliate::where('affiliate_key', '=', SELF_HOST_AFFILIATE_KEY)->first();
|
// $affiliate = Affiliate::where('affiliate_key', '=', SELF_HOST_AFFILIATE_KEY)->first();
|
||||||
|
@ -194,8 +194,8 @@ class Number
|
|||||||
/**
|
/**
|
||||||
* Formats a given value based on the clients currency AND country.
|
* Formats a given value based on the clients currency AND country.
|
||||||
*
|
*
|
||||||
* @param floatval $value The number to be formatted
|
* @param float $value The number to be formatted
|
||||||
* @param $entity
|
* @param mixed $entity
|
||||||
* @return string The formatted value
|
* @return string The formatted value
|
||||||
*/
|
*/
|
||||||
public static function formatMoneyNoRounding($value, $entity) :string
|
public static function formatMoneyNoRounding($value, $entity) :string
|
||||||
|
@ -278,9 +278,9 @@ class PaymentHtmlEngine
|
|||||||
/**
|
/**
|
||||||
* generateLabelsAndValues
|
* generateLabelsAndValues
|
||||||
*
|
*
|
||||||
* @return void
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function generateLabelsAndValues()
|
public function generateLabelsAndValues(): array
|
||||||
{
|
{
|
||||||
$data = [];
|
$data = [];
|
||||||
|
|
||||||
|
@ -288,11 +288,6 @@ class SystemHealth
|
|||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function checkDbConnection()
|
|
||||||
{
|
|
||||||
return DB::connection()->getPdo();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function testMailServer($request = null)
|
public static function testMailServer($request = null)
|
||||||
{
|
{
|
||||||
if ($request->driver == 'log') {
|
if ($request->driver == 'log') {
|
||||||
|
@ -102,7 +102,11 @@ class TemplateEngine
|
|||||||
} elseif (stripos($this->template, 'purchase') !== false && $purchase_order = PurchaseOrder::whereHas('invitations')->withTrashed()->company()->first()) {
|
} elseif (stripos($this->template, 'purchase') !== false && $purchase_order = PurchaseOrder::whereHas('invitations')->withTrashed()->company()->first()) {
|
||||||
$this->entity = 'purchase_order';
|
$this->entity = 'purchase_order';
|
||||||
$this->entity_obj = $purchase_order;
|
$this->entity_obj = $purchase_order;
|
||||||
} elseif ($invoice = Invoice::whereHas('invitations')->withTrashed()->company()->first()) {
|
}elseif (stripos($this->template, 'payment') !== false && $payment = Payment::withTrashed()->company()->first()) {
|
||||||
|
$this->entity = 'payment';
|
||||||
|
$this->entity_obj = $payment;
|
||||||
|
}
|
||||||
|
elseif ($invoice = Invoice::whereHas('invitations')->withTrashed()->company()->first()) {
|
||||||
$this->entity_obj = $invoice;
|
$this->entity_obj = $invoice;
|
||||||
} else {
|
} else {
|
||||||
$this->mockEntity();
|
$this->mockEntity();
|
||||||
|
@ -69,7 +69,7 @@ trait Inviteable
|
|||||||
$qr = $writer->writeString($this->getPaymentLink(), 'utf-8');
|
$qr = $writer->writeString($this->getPaymentLink(), 'utf-8');
|
||||||
|
|
||||||
return "<svg class='pqrcode' viewBox='0 0 200 200' width='200' height='200' x='0' y='0' xmlns='http://www.w3.org/2000/svg'>
|
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>";
|
<rect x='0' y='0' width='100%' height='100%' />{$qr}</svg>";
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUnsubscribeLink()
|
public function getUnsubscribeLink()
|
||||||
|
@ -116,6 +116,8 @@ trait MakesTemplateData
|
|||||||
$data['$quote_total'] = ['value' => '$20.00', 'label' => ctrans('texts.quote_total')];
|
$data['$quote_total'] = ['value' => '$20.00', 'label' => ctrans('texts.quote_total')];
|
||||||
$data['$credit_amount'] = ['value' => '$15.00', 'label' => ctrans('texts.credit_amount')];
|
$data['$credit_amount'] = ['value' => '$15.00', 'label' => ctrans('texts.credit_amount')];
|
||||||
$data['$credit_balance'] = ['value' => '$12.00', 'label' => ctrans('texts.credit_balance')];
|
$data['$credit_balance'] = ['value' => '$12.00', 'label' => ctrans('texts.credit_balance')];
|
||||||
|
$data['$invoice_references'] = ['value' => 'Invoice #2222', 'label' => ctrans('texts.invoices')];
|
||||||
|
$data['$invoice_references_subject'] = ['value' => 'Invoice #2222', 'label' => ctrans('texts.invoices')];
|
||||||
|
|
||||||
$data['$credit_number'] = &$data['$number'];
|
$data['$credit_number'] = &$data['$number'];
|
||||||
$data['$credit_no'] = &$data['$number'];
|
$data['$credit_no'] = &$data['$number'];
|
||||||
|
@ -8,6 +8,8 @@ use Imdhemy\Purchases\Events\GooglePlay\SubscriptionExpired;
|
|||||||
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionRenewed;
|
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionRenewed;
|
||||||
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionRevoked;
|
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionRevoked;
|
||||||
use Imdhemy\Purchases\Events\AppStore\DidChangeRenewalStatus;
|
use Imdhemy\Purchases\Events\AppStore\DidChangeRenewalStatus;
|
||||||
|
use Imdhemy\Purchases\Events\AppStore\InitialBuy;
|
||||||
|
use Imdhemy\Purchases\Events\AppStore\InteractiveRenewal;
|
||||||
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionCanceled;
|
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionCanceled;
|
||||||
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionPurchased;
|
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionPurchased;
|
||||||
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionRecovered;
|
use Imdhemy\Purchases\Events\GooglePlay\SubscriptionRecovered;
|
||||||
@ -118,6 +120,11 @@ return [
|
|||||||
SubscriptionPaused::class => class_exists(\Modules\Admin\Listeners\Subscription\GoogleSubscriptionPaused::class) ? [\Modules\Admin\Listeners\Subscription\GoogleSubscriptionPaused::class] : [],
|
SubscriptionPaused::class => class_exists(\Modules\Admin\Listeners\Subscription\GoogleSubscriptionPaused::class) ? [\Modules\Admin\Listeners\Subscription\GoogleSubscriptionPaused::class] : [],
|
||||||
SubscriptionRevoked::class => class_exists(\Modules\Admin\Listeners\Subscription\GoogleSubscriptionRevoked::class) ? [\Modules\Admin\Listeners\Subscription\GoogleSubscriptionRevoked::class] : [],
|
SubscriptionRevoked::class => class_exists(\Modules\Admin\Listeners\Subscription\GoogleSubscriptionRevoked::class) ? [\Modules\Admin\Listeners\Subscription\GoogleSubscriptionRevoked::class] : [],
|
||||||
SubscriptionExpired::class => class_exists(\Modules\Admin\Listeners\Subscription\GoogleSubscriptionExpired::class) ? [\Modules\Admin\Listeners\Subscription\GoogleSubscriptionExpired::class] : [],
|
SubscriptionExpired::class => class_exists(\Modules\Admin\Listeners\Subscription\GoogleSubscriptionExpired::class) ? [\Modules\Admin\Listeners\Subscription\GoogleSubscriptionExpired::class] : [],
|
||||||
|
|
||||||
|
Cancel::class => class_exists(\Modules\Admin\Listeners\Subscription\AppleCancel::class) ? [\Modules\Admin\Listeners\Subscription\AppleCancel::class] : [],
|
||||||
|
DidRecover::class => class_exists(\Modules\Admin\Listeners\Subscription\AppleRecover::class) ? [\Modules\Admin\Listeners\Subscription\AppleRecover::class] : [],
|
||||||
|
InitialBuy::class => class_exists(\Modules\Admin\Listeners\Subscription\AppleInitialBuy::class) ? [\Modules\Admin\Listeners\Subscription\AppleInitialBuy::class] : [],
|
||||||
|
InteractiveRenewal::class => class_exists(\Modules\Admin\Listeners\Subscription\AppleInteractiveRenewal::class) ? [\Modules\Admin\Listeners\Subscription\AppleInteractiveRenewal::class] : [],
|
||||||
],
|
],
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -15,8 +15,8 @@ return [
|
|||||||
'require_https' => env('REQUIRE_HTTPS', true),
|
'require_https' => env('REQUIRE_HTTPS', true),
|
||||||
'app_url' => rtrim(env('APP_URL', ''), '/'),
|
'app_url' => rtrim(env('APP_URL', ''), '/'),
|
||||||
'app_domain' => env('APP_DOMAIN', 'invoicing.co'),
|
'app_domain' => env('APP_DOMAIN', 'invoicing.co'),
|
||||||
'app_version' => '5.6.1',
|
'app_version' => '5.6.4',
|
||||||
'app_tag' => '5.6.1',
|
'app_tag' => '5.6.4',
|
||||||
'minimum_client_version' => '5.0.16',
|
'minimum_client_version' => '5.0.16',
|
||||||
'terms_version' => '1.0.1',
|
'terms_version' => '1.0.1',
|
||||||
'api_secret' => env('API_SECRET', ''),
|
'api_secret' => env('API_SECRET', ''),
|
||||||
|
@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Models\Language;
|
||||||
|
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()
|
||||||
|
{
|
||||||
|
Language::unguard();
|
||||||
|
|
||||||
|
if (!Language::find(39)) {
|
||||||
|
$hungarian = ['id' => 39, 'name' => 'Hungarian', 'locale' => 'hu'];
|
||||||
|
Language::create($hungarian);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
};
|
@ -63,6 +63,7 @@ class LanguageSeeder extends Seeder
|
|||||||
['id' => 36, 'name' => 'Bulgarian', 'locale' => 'bg'],
|
['id' => 36, 'name' => 'Bulgarian', 'locale' => 'bg'],
|
||||||
['id' => 37, 'name' => 'Hebrew', 'locale' => 'he'],
|
['id' => 37, 'name' => 'Hebrew', 'locale' => 'he'],
|
||||||
['id' => 38, 'name' => 'Khmer', 'locale' => 'km_KH'],
|
['id' => 38, 'name' => 'Khmer', 'locale' => 'km_KH'],
|
||||||
|
['id' => 39, 'name' => 'Hungarian', 'locale' => 'hu'],
|
||||||
];
|
];
|
||||||
|
|
||||||
foreach ($languages as $language) {
|
foreach ($languages as $language) {
|
||||||
|
@ -754,7 +754,7 @@ $LANG = array(
|
|||||||
'activity_7' => ':contact viewed invoice :invoice for :client',
|
'activity_7' => ':contact viewed invoice :invoice for :client',
|
||||||
'activity_8' => ':user archived invoice :invoice',
|
'activity_8' => ':user archived invoice :invoice',
|
||||||
'activity_9' => ':user deleted invoice :invoice',
|
'activity_9' => ':user deleted invoice :invoice',
|
||||||
'activity_10' => ':contact entered payment :payment for :payment_amount on invoice :invoice for :client',
|
'activity_10' => ':user entered payment :payment for :payment_amount on invoice :invoice for :client',
|
||||||
'activity_11' => ':user updated payment :payment',
|
'activity_11' => ':user updated payment :payment',
|
||||||
'activity_12' => ':user archived payment :payment',
|
'activity_12' => ':user archived payment :payment',
|
||||||
'activity_13' => ':user deleted payment :payment',
|
'activity_13' => ':user deleted payment :payment',
|
||||||
@ -2000,6 +2000,7 @@ $LANG = array(
|
|||||||
'current_quarter' => 'Current Quarter',
|
'current_quarter' => 'Current Quarter',
|
||||||
'last_quarter' => 'Last Quarter',
|
'last_quarter' => 'Last Quarter',
|
||||||
'last_year' => 'Last Year',
|
'last_year' => 'Last Year',
|
||||||
|
'all_time' => 'All Time',
|
||||||
'custom_range' => 'Custom Range',
|
'custom_range' => 'Custom Range',
|
||||||
'url' => 'URL',
|
'url' => 'URL',
|
||||||
'debug' => 'Debug',
|
'debug' => 'Debug',
|
||||||
@ -4907,6 +4908,7 @@ $LANG = array(
|
|||||||
'all_clients' => 'All Clients',
|
'all_clients' => 'All Clients',
|
||||||
'show_aging_table' => 'Show Aging Table',
|
'show_aging_table' => 'Show Aging Table',
|
||||||
'show_payments_table' => 'Show Payments Table',
|
'show_payments_table' => 'Show Payments Table',
|
||||||
|
'only_clients_with_invoices' => 'Only Clients with Invoices',
|
||||||
'email_statement' => 'Email Statement',
|
'email_statement' => 'Email Statement',
|
||||||
'once' => 'Once',
|
'once' => 'Once',
|
||||||
'schedules' => 'Schedules',
|
'schedules' => 'Schedules',
|
||||||
@ -5105,6 +5107,8 @@ $LANG = array(
|
|||||||
'gallery' => 'Gallery',
|
'gallery' => 'Gallery',
|
||||||
'project_location' => 'Project Location',
|
'project_location' => 'Project Location',
|
||||||
'add_gateway_help_message' => 'Add a payment gateway (ie. Stripe, WePay or PayPal) to accept online payments',
|
'add_gateway_help_message' => 'Add a payment gateway (ie. Stripe, WePay or PayPal) to accept online payments',
|
||||||
|
'lang_Hungarian' => 'Hungarian',
|
||||||
|
'use_mobile_to_manage_plan' => 'Use your phone subscription settings to manage your plan',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
@ -5087,6 +5087,16 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette
|
|||||||
'upload_certificate' => 'Téléverser le certificat',
|
'upload_certificate' => 'Téléverser le certificat',
|
||||||
'certificate_passphrase' => 'Passphrase du certificat',
|
'certificate_passphrase' => 'Passphrase du certificat',
|
||||||
'valid_vat_number' => 'Numéro valide de taxe',
|
'valid_vat_number' => 'Numéro valide de taxe',
|
||||||
|
'react_notification_link' => 'Lien de notifications React',
|
||||||
|
'react_notification_link_help' => 'Les courriels provenant de l\'administration contiennent des liens vers l\'application React',
|
||||||
|
'show_task_billable' => 'Afficher la facturation de tâche',
|
||||||
|
'credit_item' => 'Credit Item',
|
||||||
|
'drop_file_here' => 'Déposer le fichier ici',
|
||||||
|
'files' => 'Fichiers',
|
||||||
|
'camera' => 'Caméra',
|
||||||
|
'gallery' => 'Galerie',
|
||||||
|
'project_location' => 'Emplacement du projet',
|
||||||
|
'add_gateway_help_message' => 'Ajouter un passerelle de paiement (Stripe, WePay, ou PayPal) pour accepter les paiements en ligne',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
19
lang/hu/auth.php
Normal file
19
lang/hu/auth.php
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Authentication Language Lines
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| The following language lines are used during authentication for various
|
||||||
|
| messages that we need to display to the user. You are free to modify
|
||||||
|
| these language lines according to your application's requirements.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'failed' => 'Ovi podaci ne odgovaraju našima.',
|
||||||
|
'throttle' => 'Previše pokušaja prijave. Molim Vas pokušajte ponovno za :seconds sekundi.',
|
||||||
|
|
||||||
|
];
|
19
lang/hu/pagination.php
Normal file
19
lang/hu/pagination.php
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Pagination Language Lines
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| The following language lines are used by the paginator library to build
|
||||||
|
| the simple pagination links. You are free to change them to anything
|
||||||
|
| you want to customize your views to better match your application.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'previous' => '« Prethodna',
|
||||||
|
'next' => 'Sljedeća »',
|
||||||
|
|
||||||
|
];
|
22
lang/hu/passwords.php
Normal file
22
lang/hu/passwords.php
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Password Reminder Language Lines
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| The following language lines are the default lines which match reasons
|
||||||
|
| that are given by the password broker for a password update attempt
|
||||||
|
| has failed, such as for an invalid token or invalid new password.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'password' => 'Lozinke moraju biti duge barem 6 znakova i moraju odgovarati potvrdi.',
|
||||||
|
'reset' => 'Lozinka je postavljena!',
|
||||||
|
'sent' => 'Poveznica za ponovono postavljanje lozinke je poslana!',
|
||||||
|
'token' => 'Oznaka za ponovno postavljanje lozinke više nije važeća.',
|
||||||
|
'user' => 'Korisnik nije pronađen.',
|
||||||
|
|
||||||
|
];
|
5088
lang/hu/texts.php
Normal file
5088
lang/hu/texts.php
Normal file
File diff suppressed because it is too large
Load Diff
116
lang/hu/validation.php
Normal file
116
lang/hu/validation.php
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Validation Language Lines
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| The following language lines contain the default error messages used by
|
||||||
|
| the validator class. Some of these rules have multiple versions such
|
||||||
|
| such as the size rules. Feel free to tweak each of these messages.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'accepted' => 'Polje :attribute mora biti prihvaćeno.',
|
||||||
|
'active_url' => 'Polje :attribute nije ispravan URL.',
|
||||||
|
'after' => 'Polje :attribute mora biti datum nakon :date.',
|
||||||
|
'alpha' => 'Polje :attribute smije sadržavati samo slova.',
|
||||||
|
'alpha_dash' => 'Polje :attribute smije sadržavati samo slova, brojeve i crtice.',
|
||||||
|
'alpha_num' => 'Polje :attribute smije sadržavati samo slova i brojeve.',
|
||||||
|
'array' => 'Polje :attribute mora biti niz.',
|
||||||
|
'before' => 'Polje :attribute mora biti datum prije :date.',
|
||||||
|
'between' => [
|
||||||
|
'numeric' => 'Polje :attribute mora biti između :min - :max.',
|
||||||
|
'file' => 'Polje :attribute mora biti između :min - :max kilobajta.',
|
||||||
|
'string' => 'Polje :attribute mora biti između :min - :max znakova.',
|
||||||
|
'array' => 'Polje :attribute mora imati između :min - :max stavki.',
|
||||||
|
],
|
||||||
|
'boolean' => 'Polje :attribute mora biti false ili true.',
|
||||||
|
'confirmed' => 'Potvrda polja :attribute se ne podudara.',
|
||||||
|
'date' => 'Polje :attribute nije ispravan datum.',
|
||||||
|
'date_format' => 'Polje :attribute ne podudara s formatom :format.',
|
||||||
|
'different' => 'Polja :attribute i :other moraju biti različita.',
|
||||||
|
'digits' => 'Polje :attribute mora sadržavati :digits znamenki.',
|
||||||
|
'digits_between' => 'Polje :attribute mora imati između :min i :max znamenki.',
|
||||||
|
'dimensions' => 'The :attribute has invalid image dimensions.',
|
||||||
|
'distinct' => 'The :attribute field has a duplicate value.',
|
||||||
|
'email' => 'Polje :attribute mora biti ispravna e-mail adresa.',
|
||||||
|
'exists' => 'Odabrano polje :attribute nije ispravno.',
|
||||||
|
'filled' => 'The :attribute field is required.',
|
||||||
|
'image' => 'Polje :attribute mora biti slika.',
|
||||||
|
'in' => 'Odabrano polje :attribute nije ispravno.',
|
||||||
|
'in_array' => 'The :attribute field does not exist in :other.',
|
||||||
|
'integer' => 'Polje :attribute mora biti broj.',
|
||||||
|
'ip' => 'Polje :attribute mora biti ispravna IP adresa.',
|
||||||
|
'json' => 'The :attribute must be a valid JSON string.',
|
||||||
|
'max' => [
|
||||||
|
'numeric' => 'Polje :attribute mora biti manje od :max.',
|
||||||
|
'file' => 'Polje :attribute mora biti manje od :max kilobajta.',
|
||||||
|
'string' => 'Polje :attribute mora sadržavati manje od :max znakova.',
|
||||||
|
'array' => 'Polje :attribute ne smije imati više od :max stavki.',
|
||||||
|
],
|
||||||
|
'mimes' => 'Polje :attribute mora biti datoteka tipa: :values.',
|
||||||
|
'min' => [
|
||||||
|
'numeric' => 'Polje :attribute mora biti najmanje :min.',
|
||||||
|
'file' => 'Polje :attribute mora biti najmanje :min kilobajta.',
|
||||||
|
'string' => 'Polje :attribute mora sadržavati najmanje :min znakova.',
|
||||||
|
'array' => 'Polje :attribute mora sadržavati najmanje :min stavki.',
|
||||||
|
],
|
||||||
|
'not_in' => 'Odabrano polje :attribute nije ispravno.',
|
||||||
|
'numeric' => 'Polje :attribute mora biti broj.',
|
||||||
|
'present' => 'The :attribute field must be present.',
|
||||||
|
'regex' => 'Polje :attribute se ne podudara s formatom.',
|
||||||
|
'required' => 'Polje :attribute je obavezno.',
|
||||||
|
'required_if' => 'Polje :attribute je obavezno kada polje :other sadrži :value.',
|
||||||
|
'required_unless' => 'The :attribute field is required unless :other is in :values.',
|
||||||
|
'required_with' => 'Polje :attribute je obavezno kada postoji polje :values.',
|
||||||
|
'required_with_all' => 'Polje :attribute je obavezno kada postje polja :values.',
|
||||||
|
'required_without' => 'Polje :attribute je obavezno kada ne postoji polje :values.',
|
||||||
|
'required_without_all' => 'Polje :attribute je obavezno kada nijedno od polja :values ne postoji.',
|
||||||
|
'same' => 'Polja :attribute i :other se moraju podudarati.',
|
||||||
|
'size' => [
|
||||||
|
'numeric' => 'Polje :attribute mora biti :size.',
|
||||||
|
'file' => 'Polje :attribute mora biti :size kilobajta.',
|
||||||
|
'string' => 'Polje :attribute mora biti :size znakova.',
|
||||||
|
'array' => 'Polje :attribute mora sadržavati :size stavki.',
|
||||||
|
],
|
||||||
|
'string' => 'The :attribute must be a string.',
|
||||||
|
'timezone' => 'Polje :attribute mora biti ispravna vremenska zona.',
|
||||||
|
'unique' => 'Polje :attribute već postoji.',
|
||||||
|
'url' => 'Polje :attribute nije ispravnog formata.',
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Custom Validation Language Lines
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you may specify custom validation messages for attributes using the
|
||||||
|
| convention "attribute.rule" to name the lines. This makes it quick to
|
||||||
|
| specify a specific custom language line for a given attribute rule.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'custom' => [
|
||||||
|
'attribute-name' => [
|
||||||
|
'rule-name' => 'custom-message',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Custom Validation Attributes
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| The following language lines are used to swap attribute place-holders
|
||||||
|
| with something more reader friendly such as E-Mail Address instead
|
||||||
|
| of "email". This simply helps us make messages a little cleaner.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'attributes' => [
|
||||||
|
//
|
||||||
|
],
|
||||||
|
|
||||||
|
];
|
@ -19980,6 +19980,17 @@ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|||||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
widget_kit_plugin
|
||||||
|
|
||||||
|
Copyright 2023 Gameflow AS
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
win32
|
win32
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user