mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-06-23 20:00:33 -04:00
Merge branches 'feature-inbound-email-expenses' and 'feature-inbound-email-expenses' of https://github.com/paulwer/invoiceninja; branch 'v5-develop' of https://github.com/invoiceninja/invoiceninja into feature-inbound-email-expenses
This commit is contained in:
commit
36745bfabc
2
.github/workflows/react_release.yml
vendored
2
.github/workflows/react_release.yml
vendored
@ -48,7 +48,7 @@ jobs:
|
||||
npm i
|
||||
npm run build
|
||||
cp -r dist/* ../public/
|
||||
cp dist/index.html ../resources/views/react/index.blade.php
|
||||
mv dist/index.html ../resources/views/react/index.blade.php
|
||||
|
||||
- name: Prepare JS/CSS assets
|
||||
run: |
|
||||
|
@ -207,6 +207,14 @@ class Rule extends BaseRule implements RuleInterface
|
||||
*/
|
||||
public function override($item): self
|
||||
{
|
||||
|
||||
$this->tax_rate1 = $item->tax_rate1;
|
||||
$this->tax_name1 = $item->tax_name1;
|
||||
$this->tax_rate2 = $item->tax_rate2;
|
||||
$this->tax_name2 = $item->tax_name2;
|
||||
$this->tax_rate3 = $item->tax_rate3;
|
||||
$this->tax_name3 = $item->tax_name3;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -241,7 +241,7 @@ class CreditExport extends BaseExport
|
||||
}
|
||||
|
||||
if (in_array('credit.user_id', $this->input['report_keys'])) {
|
||||
$entity['credit.user_id'] = $credit->user ? $credit->user->present()->name() : '';
|
||||
$entity['credit.user_id'] = $credit->user ? $credit->user->present()->name() : ''; //@phpstan-ignore-line
|
||||
}
|
||||
|
||||
return $entity;
|
||||
|
@ -85,7 +85,7 @@ class ExpenseExport extends BaseExport
|
||||
->where('company_id', $this->company->id);
|
||||
|
||||
|
||||
if(!$this->input['include_deleted'] ?? false) {
|
||||
if(!$this->input['include_deleted'] ?? false) { // @phpstan-ignore-line
|
||||
$query->where('is_deleted', 0);
|
||||
}
|
||||
|
||||
@ -259,10 +259,17 @@ class ExpenseExport extends BaseExport
|
||||
{
|
||||
$precision = $expense->currency->precision ?? 2;
|
||||
|
||||
$entity['expense.net_amount'] = round($expense->amount, $precision);
|
||||
|
||||
if($expense->calculate_tax_by_amount) {
|
||||
|
||||
$total_tax_amount = round($expense->tax_amount1 + $expense->tax_amount2 + $expense->tax_amount3, $precision);
|
||||
|
||||
if($expense->uses_inclusive_taxes) {
|
||||
$entity['expense.net_amount'] = round($expense->amount, $precision) - $total_tax_amount;
|
||||
}
|
||||
else {
|
||||
$entity['expense.net_amount'] = round($expense->amount, $precision);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if($expense->uses_inclusive_taxes) {
|
||||
|
@ -63,7 +63,7 @@ class InvoiceExport extends BaseExport
|
||||
->where('company_id', $this->company->id);
|
||||
|
||||
|
||||
if(!$this->input['include_deleted'] ?? false) {
|
||||
if(!$this->input['include_deleted'] ?? false) {// @phpstan-ignore-line
|
||||
$query->where('is_deleted', 0);
|
||||
}
|
||||
|
||||
@ -166,7 +166,8 @@ class InvoiceExport extends BaseExport
|
||||
}
|
||||
|
||||
if (in_array('invoice.user_id', $this->input['report_keys'])) {
|
||||
$entity['invoice.user_id'] = $invoice->user ? $invoice->user->present()->name() : '';
|
||||
$entity['invoice.user_id'] = $invoice->user ? $invoice->user->present()->name() : ''; // @phpstan-ignore-line
|
||||
|
||||
}
|
||||
|
||||
return $entity;
|
||||
|
@ -75,7 +75,7 @@ class InvoiceItemExport extends BaseExport
|
||||
})
|
||||
->where('company_id', $this->company->id);
|
||||
|
||||
if(!$this->input['include_deleted'] ?? false) {
|
||||
if(!$this->input['include_deleted'] ?? false) {// @phpstan-ignore-line
|
||||
$query->where('is_deleted', 0);
|
||||
}
|
||||
|
||||
@ -258,7 +258,7 @@ class InvoiceItemExport extends BaseExport
|
||||
}
|
||||
|
||||
if (in_array('invoice.user_id', $this->input['report_keys'])) {
|
||||
$entity['invoice.user_id'] = $invoice->user ? $invoice->user->present()->name() : '';
|
||||
$entity['invoice.user_id'] = $invoice->user ? $invoice->user->present()->name() : '';// @phpstan-ignore-line
|
||||
}
|
||||
|
||||
return $entity;
|
||||
|
@ -63,7 +63,7 @@ class PurchaseOrderExport extends BaseExport
|
||||
})
|
||||
->where('company_id', $this->company->id);
|
||||
|
||||
if(!$this->input['include_deleted'] ?? false) {
|
||||
if(!$this->input['include_deleted'] ?? false) { // @phpstan-ignore-line
|
||||
$query->where('is_deleted', 0);
|
||||
}
|
||||
|
||||
@ -167,7 +167,8 @@ class PurchaseOrderExport extends BaseExport
|
||||
}
|
||||
|
||||
if (in_array('purchase_order.user_id', $this->input['report_keys'])) {
|
||||
$entity['purchase_order.user_id'] = $purchase_order->user ? $purchase_order->user->present()->name() : '';
|
||||
$entity['purchase_order.user_id'] = $purchase_order->user ? $purchase_order->user->present()->name() : ''; // @phpstan-ignore-line
|
||||
|
||||
}
|
||||
|
||||
if (in_array('purchase_order.assigned_user_id', $this->input['report_keys'])) {
|
||||
|
@ -152,22 +152,22 @@ class InvoiceFilters extends QueryFilters
|
||||
{
|
||||
|
||||
return $this->builder->where(function ($query) {
|
||||
$query->whereIn('status_id', [Invoice::STATUS_PARTIAL, Invoice::STATUS_SENT])
|
||||
->where('is_deleted', 0)
|
||||
->where('balance', '>', 0)
|
||||
->where(function ($query) {
|
||||
$query->whereIn('invoices.status_id', [Invoice::STATUS_PARTIAL, Invoice::STATUS_SENT])
|
||||
->where('invoices.is_deleted', 0)
|
||||
->where('invoices.balance', '>', 0)
|
||||
->orWhere(function ($query) {
|
||||
|
||||
$query->whereNull('due_date')
|
||||
$query->whereNull('invoices.due_date')
|
||||
->orWhere(function ($q) {
|
||||
$q->where('due_date', '>=', now()->startOfDay()->subSecond())->where('partial', 0);
|
||||
$q->where('invoices.due_date', '>=', now()->startOfDay()->subSecond())->where('invoices.partial', 0);
|
||||
})
|
||||
->orWhere(function ($q) {
|
||||
$q->where('partial_due_date', '>=', now()->startOfDay()->subSecond())->where('partial', '>', 0);
|
||||
$q->where('invoices.partial_due_date', '>=', now()->startOfDay()->subSecond())->where('invoices.partial', '>', 0);
|
||||
});
|
||||
|
||||
})
|
||||
->orderByRaw('ISNULL(due_date), due_date ' . 'desc')
|
||||
->orderByRaw('ISNULL(partial_due_date), partial_due_date ' . 'desc');
|
||||
->orderByRaw('ISNULL(invoices.due_date), invoices.due_date ' . 'desc')
|
||||
->orderByRaw('ISNULL(invoices.partial_due_date), invoices.partial_due_date ' . 'desc');
|
||||
});
|
||||
|
||||
}
|
||||
@ -337,10 +337,10 @@ class InvoiceFilters extends QueryFilters
|
||||
// return $this->builder->orderByRaw('CAST(number AS UNSIGNED), number ' . $dir);
|
||||
// return $this->builder->orderByRaw("number REGEXP '^[A-Za-z]+$',CAST(number as SIGNED INTEGER),CAST(REPLACE(number,'-','')AS SIGNED INTEGER) ,number");
|
||||
// return $this->builder->orderByRaw('ABS(number) ' . $dir);
|
||||
return $this->builder->orderByRaw("REGEXP_REPLACE(number,'[^0-9]+','')+0 " . $dir);
|
||||
return $this->builder->orderByRaw("REGEXP_REPLACE(invoices.number,'[^0-9]+','')+0 " . $dir);
|
||||
}
|
||||
|
||||
return $this->builder->orderBy($sort_col[0], $dir);
|
||||
return $this->builder->orderBy("{$this->builder->getQuery()->from}.".$sort_col[0], $dir);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -937,7 +937,9 @@ class BaseController extends Controller
|
||||
} elseif (in_array($this->entity_type, [Design::class, GroupSetting::class, PaymentTerm::class, TaskStatus::class])) {
|
||||
// nlog($this->entity_type);
|
||||
} else {
|
||||
$query->where('user_id', '=', $user->id)->orWhere('assigned_user_id', $user->id);
|
||||
$query->where(function ($q) use ($user){ //grouping these together improves query performance significantly)
|
||||
$q->where('user_id', '=', $user->id)->orWhere('assigned_user_id', $user->id);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,8 +11,9 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Requests\Chart\ShowChartRequest;
|
||||
use App\Services\Chart\ChartService;
|
||||
use App\Http\Requests\Chart\ShowChartRequest;
|
||||
use App\Http\Requests\Chart\ShowCalculatedFieldRequest;
|
||||
|
||||
class ChartController extends BaseController
|
||||
{
|
||||
@ -65,5 +66,15 @@ class ChartController extends BaseController
|
||||
return response()->json($cs->chart_summary($request->input('start_date'), $request->input('end_date')), 200);
|
||||
}
|
||||
|
||||
public function calculatedField(ShowCalculatedFieldRequest $request)
|
||||
{
|
||||
|
||||
/** @var \App\Models\User auth()->user() */
|
||||
$user = auth()->user();
|
||||
$cs = new ChartService($user->company(), $user, $user->isAdmin());
|
||||
$result = $cs->getCalculatedField($request->all());
|
||||
|
||||
return response()->json($result, 200);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -429,7 +429,7 @@ class ClientController extends BaseController
|
||||
/** @var ?\Postmark\Models\DynamicResponseModel $response */
|
||||
$response = $postmark->activateBounce((int)$bounce_id);
|
||||
|
||||
if($response && $response?->Message == 'OK' && !$response->Bounce->Inactive && $response->Bounce->Email) {
|
||||
if($response && $response?->Message == 'OK' && !$response->Bounce->Inactive && $response->Bounce->Email) { // @phpstan-ignore-line
|
||||
|
||||
$email = $response->Bounce->Email;
|
||||
//remove email from quarantine. //@TODO
|
||||
|
@ -57,8 +57,9 @@ class ContactHashLoginController extends Controller
|
||||
return render('generic.error', [
|
||||
'title' => session()->get('title'),
|
||||
'notification' => session()->get('notification'),
|
||||
'account' => auth()->guard('contact')?->user()?->user?->account,
|
||||
'company' => auth()->guard('contact')?->user()?->user?->company
|
||||
'account' => auth()->guard('contact')?->user()?->user?->account,// @phpstan-ignore-line
|
||||
'company' => auth()->guard('contact')?->user()?->user?->company // @phpstan-ignore-line
|
||||
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -36,21 +36,16 @@ class ReportExportController extends BaseController
|
||||
return response()->json(['message' => 'Still working.....'], 409);
|
||||
}
|
||||
|
||||
if($report) {
|
||||
Cache::forget($hash);
|
||||
|
||||
Cache::forget($hash);
|
||||
|
||||
$headers = [
|
||||
'Content-Disposition' => 'attachment',
|
||||
'Content-Type' => 'text/csv',
|
||||
];
|
||||
|
||||
return response()->streamDownload(function () use ($report) {
|
||||
echo $report;
|
||||
}, $this->filename, $headers);
|
||||
|
||||
}
|
||||
$headers = [
|
||||
'Content-Disposition' => 'attachment',
|
||||
'Content-Type' => 'text/csv',
|
||||
];
|
||||
|
||||
return response()->streamDownload(function () use ($report) {
|
||||
echo $report;
|
||||
}, $this->filename, $headers);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -34,12 +34,9 @@ class ReportPreviewController extends BaseController
|
||||
return response()->json(['message' => 'Still working.....'], 409);
|
||||
}
|
||||
|
||||
if($report) {
|
||||
Cache::forget($hash);
|
||||
|
||||
Cache::forget($hash);
|
||||
|
||||
return response()->json($report, 200);
|
||||
}
|
||||
return response()->json($report, 200);
|
||||
|
||||
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ class SelfUpdateController extends BaseController
|
||||
'bootstrap/cache/services.php',
|
||||
'bootstrap/cache/routes-v7.php',
|
||||
'bootstrap/cache/livewire-components.php',
|
||||
'public/index.html',
|
||||
];
|
||||
|
||||
public function __construct()
|
||||
@ -114,33 +115,33 @@ class SelfUpdateController extends BaseController
|
||||
Artisan::call('config:clear');
|
||||
Artisan::call('cache:clear');
|
||||
|
||||
$this->runModelChecks();
|
||||
// $this->runModelChecks();
|
||||
|
||||
nlog('Called Artisan commands');
|
||||
|
||||
return response()->json(['message' => 'Update completed'], 200);
|
||||
}
|
||||
|
||||
private function runModelChecks()
|
||||
{
|
||||
Company::query()
|
||||
->cursor()
|
||||
->each(function ($company) {
|
||||
// private function runModelChecks()
|
||||
// {
|
||||
// Company::query()
|
||||
// ->cursor()
|
||||
// ->each(function ($company) {
|
||||
|
||||
$settings = $company->settings;
|
||||
// $settings = $company->settings;
|
||||
|
||||
if(property_exists($settings->pdf_variables, 'purchase_order_details')) {
|
||||
return;
|
||||
}
|
||||
// if(property_exists($settings->pdf_variables, 'purchase_order_details')) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
$pdf_variables = $settings->pdf_variables;
|
||||
$pdf_variables->purchase_order_details = [];
|
||||
$settings->pdf_variables = $pdf_variables;
|
||||
$company->settings = $settings;
|
||||
$company->save();
|
||||
// $pdf_variables = $settings->pdf_variables;
|
||||
// $pdf_variables->purchase_order_details = [];
|
||||
// $settings->pdf_variables = $pdf_variables;
|
||||
// $company->settings = $settings;
|
||||
// $company->save();
|
||||
|
||||
});
|
||||
}
|
||||
// });
|
||||
// }
|
||||
|
||||
private function clearCacheDir()
|
||||
{
|
||||
@ -159,7 +160,7 @@ class SelfUpdateController extends BaseController
|
||||
$directoryIterator = new \RecursiveDirectoryIterator(base_path(), \RecursiveDirectoryIterator::SKIP_DOTS);
|
||||
|
||||
foreach (new \RecursiveIteratorIterator($directoryIterator) as $file) {
|
||||
if (strpos($file->getPathname(), '.git') !== false) {
|
||||
if (strpos($file->getPathname(), '.git') !== false || strpos($file->getPathname(), 'vendor/') !== false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -164,7 +164,7 @@ class TwilioController extends BaseController
|
||||
return response()->json(['message' => 'Please update your first and/or last name in the User Details before verifying your number.'], 400);
|
||||
}
|
||||
|
||||
if (!$user->phone || $user->phone == '') {
|
||||
if (!$user->phone || empty($user->phone)) {
|
||||
return response()->json(['message' => 'User found, but no valid phone number on file, please contact support.'], 400);
|
||||
}
|
||||
|
||||
|
@ -56,7 +56,8 @@ class SetDomainNameDb
|
||||
return response()->json($error, 403);
|
||||
} else {
|
||||
MultiDB::setDb('db-ninja-01');
|
||||
nlog('I could not set the DB - defaulting to DB1');
|
||||
nlog('SetDomainNameDb:: I could not set the DB - defaulting to DB1');
|
||||
$request->session()->invalidate();
|
||||
//abort(400, 'Domain not found');
|
||||
}
|
||||
}
|
||||
@ -73,7 +74,8 @@ class SetDomainNameDb
|
||||
return response()->json($error, 403);
|
||||
} else {
|
||||
MultiDB::setDb('db-ninja-01');
|
||||
nlog('I could not set the DB - defaulting to DB1');
|
||||
nlog('SetDomainNameDb:: I could not set the DB - defaulting to DB1');
|
||||
$request->session()->invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
78
app/Http/Requests/Chart/ShowCalculatedFieldRequest.php
Normal file
78
app/Http/Requests/Chart/ShowCalculatedFieldRequest.php
Normal file
@ -0,0 +1,78 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2024. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Http\Requests\Chart;
|
||||
|
||||
use App\Http\Requests\Request;
|
||||
use App\Utils\Traits\MakesDates;
|
||||
|
||||
class ShowCalculatedFieldRequest extends Request
|
||||
{
|
||||
use MakesDates;
|
||||
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
/**@var \App\Models\User auth()->user */
|
||||
$user = auth()->user();
|
||||
|
||||
return $user->isAdmin() || $user->hasPermission('view_dashboard');
|
||||
}
|
||||
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'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',
|
||||
'start_date' => 'bail|sometimes|date',
|
||||
'end_date' => 'bail|sometimes|date',
|
||||
'field' => 'required|bail|in:active_invoices, outstanding_invoices, completed_payments, refunded_payments, active_quotes, unapproved_quotes, logged_tasks, invoiced_tasks, paid_tasks, logged_expenses, pending_expenses, invoiced_expenses, invoice_paid_expenses',
|
||||
'calculation' => 'required|bail|in:sum,avg,count',
|
||||
'period' => 'required|bail|in:current,previous,total',
|
||||
'format' => 'sometimes|bail|in:time,money',
|
||||
];
|
||||
}
|
||||
|
||||
public function prepareForValidation()
|
||||
{
|
||||
|
||||
/**@var \App\Models\User auth()->user */
|
||||
$user = auth()->user();
|
||||
|
||||
$input = $this->all();
|
||||
|
||||
if(isset($input['date_range'])) {
|
||||
$dates = $this->calculateStartAndEndDates($input, $user->company());
|
||||
$input['start_date'] = $dates[0];
|
||||
$input['end_date'] = $dates[1];
|
||||
}
|
||||
|
||||
if (! isset($input['start_date'])) {
|
||||
$input['start_date'] = now()->subDays(20)->format('Y-m-d');
|
||||
}
|
||||
|
||||
if (! isset($input['end_date'])) {
|
||||
$input['end_date'] = now()->format('Y-m-d');
|
||||
}
|
||||
|
||||
if(isset($input['period']) && $input['period'] == 'previous')
|
||||
{
|
||||
$dates = $this->calculatePreviousPeriodStartAndEndDates($input, $user->company());
|
||||
$input['start_date'] = $dates[0];
|
||||
$input['end_date'] = $dates[1];
|
||||
}
|
||||
|
||||
$this->replace($input);
|
||||
}
|
||||
}
|
@ -170,7 +170,7 @@ class UpdateClientRequest extends Request
|
||||
* down to the free plan setting properties which
|
||||
* are saveable
|
||||
*
|
||||
* @param \stdClass $settings
|
||||
* @param mixed $settings
|
||||
* @return \stdClass $settings
|
||||
*/
|
||||
private function filterSaveableSettings($settings)
|
||||
|
@ -18,7 +18,6 @@ class ClientEmailHistoryRequest extends Request
|
||||
{
|
||||
use MakesHash;
|
||||
|
||||
private string $error_message = '';
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
|
@ -20,7 +20,6 @@ class EntityEmailHistoryRequest extends Request
|
||||
{
|
||||
use MakesHash;
|
||||
|
||||
private string $error_message = '';
|
||||
private string $entity_plural = '';
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
|
@ -126,7 +126,7 @@ class UpdateRecurringInvoiceRequest extends Request
|
||||
}
|
||||
|
||||
if (isset($input['line_items'])) {
|
||||
$input['line_items'] = isset($input['line_items']) ? $this->cleanItems($input['line_items']) : [];
|
||||
$input['line_items'] = $this->cleanItems($input['line_items']);
|
||||
$input['amount'] = $this->entityTotalAmount($input['line_items']);
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,6 @@ use Illuminate\Auth\Access\AuthorizationException;
|
||||
|
||||
class GenericReportRequest extends Request
|
||||
{
|
||||
private string $error_message = '';
|
||||
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
|
@ -77,7 +77,7 @@ class UpdateUserRequest extends Request
|
||||
unset($input['oauth_user_token']);
|
||||
}
|
||||
|
||||
if(isset($input['password']) && strlen($input['password'] ?? '') > 1)
|
||||
if(isset($input['password']) && is_string($input['password']))
|
||||
{
|
||||
$input['password'] = trim($input['password']);
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ class HasValidPhoneNumber implements Rule
|
||||
|
||||
$twilio = new \Twilio\Rest\Client($sid, $token);
|
||||
|
||||
$country = auth()->user()->account?->companies()?->first()?->country();
|
||||
$country = auth()->user()->account?->companies()?->first()?->country(); //@phpstan-ignore-line
|
||||
|
||||
if (!$country || strlen(auth()->user()->phone) < 2) {
|
||||
return true;
|
||||
|
@ -47,7 +47,7 @@ class InvoiceTransformer extends BaseTransformer
|
||||
'due_date' => isset($invoice_data['Due Date']) ? $this->parseDate($invoice_data['Due Date']) : null,
|
||||
'po_number' => $this->getString($invoice_data, 'PurchaseOrder'),
|
||||
'public_notes' => $this->getString($invoice_data, 'Notes'),
|
||||
'currency_id' => $this->getCurrencyByCode($invoice_data, 'Currency'),
|
||||
// 'currency_id' => $this->getCurrencyByCode($invoice_data, 'Currency'),
|
||||
'amount' => $this->getFloat($invoice_data, 'Total'),
|
||||
'balance' => $this->getFloat($invoice_data, 'Balance'),
|
||||
'status_id' => $invoiceStatusMap[$status =
|
||||
|
@ -86,6 +86,9 @@ class UpdateCalculatedFields
|
||||
|
||||
foreach(json_decode($task->time_log) as $log) {
|
||||
|
||||
if(!is_array($log))
|
||||
continue;
|
||||
|
||||
$start_time = $log[0];
|
||||
$end_time = $log[1] == 0 ? time() : $log[1];
|
||||
|
||||
|
@ -71,7 +71,7 @@ class ReminderJob implements ShouldQueue
|
||||
->whereHas('company', function ($query) {
|
||||
$query->where('is_disabled', 0);
|
||||
})
|
||||
->with('invitations')->chunk(50, function ($invoices) {
|
||||
->with('invitations')->chunk(200, function ($invoices) {
|
||||
foreach ($invoices as $invoice) {
|
||||
$this->sendReminderForInvoice($invoice);
|
||||
}
|
||||
@ -99,7 +99,7 @@ class ReminderJob implements ShouldQueue
|
||||
->whereHas('company', function ($query) {
|
||||
$query->where('is_disabled', 0);
|
||||
})
|
||||
->with('invitations')->chunk(50, function ($invoices) {
|
||||
->with('invitations')->chunk(200, function ($invoices) {
|
||||
|
||||
foreach ($invoices as $invoice) {
|
||||
$this->sendReminderForInvoice($invoice);
|
||||
|
@ -129,7 +129,7 @@ class BaseModel extends Model
|
||||
/** @var \App\Models\User $user */
|
||||
$user = auth()->user();
|
||||
|
||||
$query->where('company_id', $user->companyId());
|
||||
$query->where("{$query->getQuery()->from}.company_id", $user->companyId());
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
@ -107,7 +107,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\Backup> $history
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\QuoteInvitation> $invitations
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|BaseModel company()
|
||||
* @mixin \Eloquent
|
||||
* @mixin \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
|
@ -186,7 +186,7 @@ class Task extends BaseModel
|
||||
}
|
||||
|
||||
if($this->status) {
|
||||
return '<h5><span class="badge badge-primary">' . $this->status?->name ?? '';
|
||||
return '<h5><span class="badge badge-primary">' . $this->status?->name ?? ''; //@phpstan-ignore-line
|
||||
}
|
||||
|
||||
return '';
|
||||
|
@ -136,16 +136,16 @@ class EntityViewedNotification extends Notification
|
||||
// return $data;
|
||||
// }
|
||||
|
||||
private function buildSubject()
|
||||
{
|
||||
$subject = ctrans(
|
||||
"texts.notification_{$this->entity_name}_viewed_subject",
|
||||
[
|
||||
'client' => $this->contact->present()->name(),
|
||||
$this->entity_name => $this->entity->number,
|
||||
]
|
||||
);
|
||||
// private function buildSubject()
|
||||
// {
|
||||
// $subject = ctrans(
|
||||
// "texts.notification_{$this->entity_name}_viewed_subject",
|
||||
// [
|
||||
// 'client' => $this->contact->present()->name(),
|
||||
// $this->entity_name => $this->entity->number,
|
||||
// ]
|
||||
// );
|
||||
|
||||
return $subject;
|
||||
}
|
||||
// return $subject;
|
||||
// }
|
||||
}
|
||||
|
@ -559,7 +559,7 @@ class BaseDriver extends AbstractPaymentDriver
|
||||
$error = 'Payment Aborted';
|
||||
}
|
||||
|
||||
if (! is_null($this->payment_hash)) {
|
||||
if (! is_null($this->payment_hash)) { //@phpstan-ignore-line
|
||||
$this->unWindGatewayFees($this->payment_hash);
|
||||
}
|
||||
|
||||
@ -830,7 +830,7 @@ class BaseDriver extends AbstractPaymentDriver
|
||||
}
|
||||
|
||||
$invoices_string = \implode(', ', collect($this->payment_hash->invoices())->pluck('invoice_number')->toArray()) ?: null;
|
||||
$amount = Number::formatMoney($this->payment_hash?->amount_with_fee() ?? 0, $this->client);
|
||||
$amount = Number::formatMoney($this->payment_hash?->amount_with_fee() ?? 0, $this->client); // @phpstan-ignore-line
|
||||
|
||||
if($abbreviated && $invoices_string) {
|
||||
return $invoices_string;
|
||||
|
@ -40,7 +40,7 @@ class Webhook
|
||||
$error_details = $e->error_details;
|
||||
nlog($error_details);
|
||||
|
||||
$http_status_code = isset($e->http_metadata) ? $e->http_metadata->getStatusCode() : null;
|
||||
$http_status_code = isset($e->http_metadata) ? $e->http_metadata->getStatusCode() : null; //@phpstan-ignore-line
|
||||
} catch (CheckoutAuthorizationException $e) {
|
||||
// Bad Invalid authorization
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ class CreditCard
|
||||
|
||||
$this->logResponse($response);
|
||||
|
||||
throw new PaymentFailed($response_status['message'] ?? 'Unknown response from gateway, please contact you merchant.', 400);
|
||||
throw new PaymentFailed($response_status['message'] ?? 'Unknown response from gateway, please contact you merchant.', 400); //@phpstan-ignore-line
|
||||
}
|
||||
|
||||
//success
|
||||
@ -135,7 +135,7 @@ class CreditCard
|
||||
$invoice_numbers = '';
|
||||
|
||||
if ($this->eway_driver->payment_hash->data) {
|
||||
$invoice_numbers = collect($this->eway_driver->payment_hash->data->invoices)->pluck('invoice_number')->implode(',');
|
||||
$invoice_numbers = collect($this->eway_driver->payment_hash->data->invoices)->pluck('invoice_number')->implode(','); //@phpstan-ignore-line
|
||||
}
|
||||
|
||||
$amount = array_sum(array_column($this->eway_driver->payment_hash->invoices(), 'amount')) + $this->eway_driver->payment_hash->fee_total;
|
||||
|
@ -173,7 +173,7 @@ class ACH implements MethodInterface
|
||||
$description = "Amount {$request->amount} from client {$this->go_cardless->client->present()->name()}";
|
||||
}
|
||||
|
||||
$amount = $this->go_cardless->convertToGoCardlessAmount($this->go_cardless->payment_hash?->amount_with_fee(), $this->go_cardless->client->currency()->precision);
|
||||
$amount = $this->go_cardless->convertToGoCardlessAmount($this->go_cardless->payment_hash?->amount_with_fee(), $this->go_cardless->client->currency()->precision); //@phpstan-ignore-line
|
||||
|
||||
try {
|
||||
$payment = $this->go_cardless->gateway->payments()->create([
|
||||
|
@ -156,7 +156,7 @@ class MolliePaymentDriver extends BaseDriver
|
||||
return [
|
||||
'transaction_reference' => $refund->id,
|
||||
'transaction_response' => json_encode($refund),
|
||||
'success' => $refund->status === 'refunded' ? true : false,
|
||||
'success' => $refund->status === 'refunded' ? true : false, //@phpstan-ignore-line
|
||||
'description' => $refund->description,
|
||||
'code' => 200,
|
||||
];
|
||||
|
@ -489,7 +489,7 @@ class StripePaymentDriver extends BaseDriver
|
||||
{
|
||||
$customer = Customer::retrieve($customer_id, $this->stripe_connect_auth);
|
||||
|
||||
return $customer ?? null;
|
||||
return $customer ?? null; // @phpstan-ignore-line
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -261,7 +261,7 @@ class TaskRepository extends BaseRepository
|
||||
|
||||
public function roundTimeLog(int $start_time, int $end_time): int
|
||||
{
|
||||
if($this->task_round_to_nearest == 1 || $end_time == 0) {
|
||||
if(in_array($this->task_round_to_nearest, [0,1]) || $end_time == 0) {
|
||||
return $end_time;
|
||||
}
|
||||
|
||||
|
173
app/Services/Chart/ChartCalculations.php
Normal file
173
app/Services/Chart/ChartCalculations.php
Normal file
@ -0,0 +1,173 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2024. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Services\Chart;
|
||||
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
use App\Models\Quote;
|
||||
|
||||
/**
|
||||
* Class ChartCalculations.
|
||||
*/
|
||||
trait ChartCalculations
|
||||
{
|
||||
|
||||
public function getActiveInvoices($data): int|float
|
||||
{
|
||||
$result = 0;
|
||||
|
||||
$q = Invoice::query()
|
||||
->withTrashed()
|
||||
->where('company_id', $this->company->id)
|
||||
->where('is_deleted', 0)
|
||||
->whereIn('status_id', [2,3,4]);
|
||||
|
||||
if(in_array($data['period'],['current,previous']))
|
||||
$q->whereBetween('date', [$data['start_date'], $data['end_date']]);
|
||||
|
||||
match ($data['calculation']) {
|
||||
'sum' => $result = $q->sum('amount'),
|
||||
'avg' => $result = $q->avg('amount'),
|
||||
'count' => $result = $q->count(),
|
||||
default => $result = 0,
|
||||
};
|
||||
|
||||
return $result;
|
||||
|
||||
}
|
||||
|
||||
public function getOutstandingInvoices($data): int|float
|
||||
{
|
||||
$result = 0;
|
||||
|
||||
$q = Invoice::query()
|
||||
->withTrashed()
|
||||
->where('company_id', $this->company->id)
|
||||
->where('is_deleted', 0)
|
||||
->whereIn('status_id', [2,3]);
|
||||
|
||||
if(in_array($data['period'],['current,previous']))
|
||||
$q->whereBetween('date', [$data['start_date'], $data['end_date']]);
|
||||
|
||||
match ($data['calculation']) {
|
||||
'sum' => $result = $q->sum('balance'),
|
||||
'avg' => $result = $q->avg('balance'),
|
||||
'count' => $result = $q->count(),
|
||||
default => $result = 0,
|
||||
};
|
||||
|
||||
return $result;
|
||||
|
||||
}
|
||||
|
||||
public function getCompletedPayments($data): int|float
|
||||
{
|
||||
$result = 0;
|
||||
|
||||
$q = Payment::query()
|
||||
->withTrashed()
|
||||
->where('company_id', $this->company->id)
|
||||
->where('is_deleted', 0)
|
||||
->where('status_id', 4);
|
||||
|
||||
if(in_array($data['period'],['current,previous']))
|
||||
$q->whereBetween('date', [$data['start_date'], $data['end_date']]);
|
||||
|
||||
match ($data['calculation']) {
|
||||
'sum' => $result = $q->sum('amount'),
|
||||
'avg' => $result = $q->avg('amount'),
|
||||
'count' => $result = $q->count(),
|
||||
default => $result = 0,
|
||||
};
|
||||
|
||||
return $result;
|
||||
|
||||
}
|
||||
|
||||
public function getRefundedPayments($data): int|float
|
||||
{
|
||||
$result = 0;
|
||||
|
||||
$q = Payment::query()
|
||||
->withTrashed()
|
||||
->where('company_id', $this->company->id)
|
||||
->where('is_deleted', 0)
|
||||
->whereIn('status_id', [5,6]);
|
||||
|
||||
if(in_array($data['period'],['current,previous']))
|
||||
$q->whereBetween('date', [$data['start_date'], $data['end_date']]);
|
||||
|
||||
match ($data['calculation']) {
|
||||
'sum' => $result = $q->sum('refunded'),
|
||||
'avg' => $result = $q->avg('refunded'),
|
||||
'count' => $result = $q->count(),
|
||||
default => $result = 0,
|
||||
};
|
||||
|
||||
return $result;
|
||||
|
||||
}
|
||||
|
||||
public function getActiveQuotes($data): int|float
|
||||
{
|
||||
$result = 0;
|
||||
|
||||
$q = Quote::query()
|
||||
->withTrashed()
|
||||
->where('company_id', $this->company->id)
|
||||
->where('is_deleted', 0)
|
||||
->whereIn('status_id', [2,3])
|
||||
->where(function ($qq){
|
||||
$qq->where('due_date', '>=', now()->toDateString())->orWhereNull('due_date');
|
||||
});
|
||||
|
||||
if(in_array($data['period'],['current,previous']))
|
||||
$q->whereBetween('date', [$data['start_date'], $data['end_date']]);
|
||||
|
||||
match ($data['calculation']) {
|
||||
'sum' => $result = $q->sum('refunded'),
|
||||
'avg' => $result = $q->avg('refunded'),
|
||||
'count' => $result = $q->count(),
|
||||
default => $result = 0,
|
||||
};
|
||||
|
||||
return $result;
|
||||
|
||||
}
|
||||
|
||||
public function getUnapprovedQuotes($data): int|float
|
||||
{
|
||||
$result = 0;
|
||||
|
||||
$q = Quote::query()
|
||||
->withTrashed()
|
||||
->where('company_id', $this->company->id)
|
||||
->where('is_deleted', 0)
|
||||
->whereIn('status_id', [2])
|
||||
->where(function ($qq){
|
||||
$qq->where('due_date', '>=', now()->toDateString())->orWhereNull('due_date');
|
||||
});
|
||||
|
||||
if(in_array($data['period'],['current,previous']))
|
||||
$q->whereBetween('date', [$data['start_date'], $data['end_date']]);
|
||||
|
||||
match ($data['calculation']) {
|
||||
'sum' => $result = $q->sum('refunded'),
|
||||
'avg' => $result = $q->avg('refunded'),
|
||||
'count' => $result = $q->count(),
|
||||
default => $result = 0,
|
||||
};
|
||||
|
||||
return $result;
|
||||
|
||||
}
|
||||
}
|
@ -14,12 +14,17 @@ namespace App\Services\Chart;
|
||||
use App\Models\Client;
|
||||
use App\Models\Company;
|
||||
use App\Models\Expense;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
use App\Models\Quote;
|
||||
use App\Models\Task;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class ChartService
|
||||
{
|
||||
use ChartQueries;
|
||||
use ChartCalculations;
|
||||
|
||||
public function __construct(public Company $company, private User $user, private bool $is_admin)
|
||||
{
|
||||
@ -71,7 +76,7 @@ class ChartService
|
||||
|
||||
return $final_currencies;
|
||||
}
|
||||
|
||||
|
||||
/* Chart Data */
|
||||
public function chart_summary($start_date, $end_date): array
|
||||
{
|
||||
@ -207,4 +212,44 @@ class ChartService
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* calculatedField
|
||||
*
|
||||
* @param array $data -
|
||||
*
|
||||
* field - list of fields for calculation
|
||||
* period - current/previous
|
||||
* calculation - sum/count/avg
|
||||
*
|
||||
* date_range - this_month
|
||||
* or
|
||||
* start_date - end_date
|
||||
*/
|
||||
public function getCalculatedField(array $data)
|
||||
{
|
||||
$results = 0;
|
||||
|
||||
match($data['field']){
|
||||
'active_invoices' => $results = $this->getActiveInvoices($data),
|
||||
'outstanding_invoices' => $results = 0,
|
||||
'completed_payments' => $results = 0,
|
||||
'refunded_payments' => $results = 0,
|
||||
'active_quotes' => $results = 0,
|
||||
'unapproved_quotes' => $results = 0,
|
||||
'logged_tasks' => $results = 0,
|
||||
'invoiced_tasks' => $results = 0,
|
||||
'paid_tasks' => $results = 0,
|
||||
'logged_expenses' => $results = 0,
|
||||
'pending_expenses' => $results = 0,
|
||||
'invoiced_expenses' => $results = 0,
|
||||
'invoice_paid_expenses' => $results = 0,
|
||||
default => $results = 0,
|
||||
};
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -52,8 +52,9 @@ class ZugferdEDocument extends AbstractService
|
||||
$this->document->getDocumentInformation($documentno, $documenttypecode, $documentdate, $invoiceCurrency, $taxCurrency, $documentname, $documentlanguage, $effectiveSpecifiedPeriod);
|
||||
$this->document->getDocumentSummation($grandTotalAmount, $duePayableAmount, $lineTotalAmount, $chargeTotalAmount, $allowanceTotalAmount, $taxBasisTotalAmount, $taxTotalAmount, $roundingAmount, $totalPrepaidAmount);
|
||||
|
||||
$expense = Expense::where('amount', $grandTotalAmount)->where("transaction_reference", $documentno)->whereDate("date", $documentdate)->first();
|
||||
if (empty($expense)) {
|
||||
/** @var \App\Models\Expense $expense */
|
||||
$expense = Expense::where("company_id", $user->company()->id)->where('amount', $grandTotalAmount)->where("transaction_reference", $documentno)->whereDate("date", $documentdate)->first();
|
||||
if (!$expense) {
|
||||
// The document does not exist as an expense
|
||||
// Handle accordingly
|
||||
$visualizer = new ZugferdVisualizer($this->document);
|
||||
@ -65,8 +66,6 @@ class ZugferdEDocument extends AbstractService
|
||||
|
||||
$expense = ExpenseFactory::create($user->company()->id, $user->id);
|
||||
$expense->date = $documentdate;
|
||||
$expense->user_id = $user->id;
|
||||
$expense->company_id = $user->company->id;
|
||||
$expense->public_notes = $documentno;
|
||||
$expense->currency_id = Currency::whereCode($invoiceCurrency)->first()?->id || $user->company->settings->currency_id;
|
||||
$expense->save();
|
||||
@ -75,7 +74,7 @@ class ZugferdEDocument extends AbstractService
|
||||
if ($this->file->getExtension() == "xml")
|
||||
array_push($documents, TempFile::UploadedFileFromRaw($visualizer->renderPdf(), $documentno . "_visualiser.pdf", "application/pdf"));
|
||||
$this->saveDocuments($documents, $expense);
|
||||
$expense->saveQuietly();
|
||||
$expense->save();
|
||||
|
||||
if ($taxCurrency && $taxCurrency != $invoiceCurrency) {
|
||||
$expense->private_notes = ctrans("texts.tax_currency_mismatch");
|
||||
|
@ -44,7 +44,7 @@ use CleverIt\UBL\Invoice\FatturaPA\common\FatturaElettronicaHeader;
|
||||
*/
|
||||
class FatturaPA extends AbstractService
|
||||
{
|
||||
private $xml;
|
||||
// private $xml;
|
||||
|
||||
//urn:cen.eu:en16931:2017#compliant#urn:fatturapa.gov.it:CIUS-IT:2.0.0
|
||||
//<cbc:EndpointID schemeID=" 0201 ">UFF001</cbc:EndpointID>
|
||||
|
@ -205,7 +205,7 @@ class AdminEmail implements ShouldQueue
|
||||
$this->entityEmailFailed($message);
|
||||
|
||||
/* Don't send postmark failures to Sentry */
|
||||
if (Ninja::isHosted() && (!$e instanceof ClientException)) {
|
||||
if (Ninja::isHosted() && (!$e instanceof ClientException)) { //@phpstan-ignore-line
|
||||
app('sentry')->captureException($e);
|
||||
}
|
||||
}
|
||||
|
@ -33,9 +33,6 @@ class RefundPayment
|
||||
|
||||
public function __construct(public Payment $payment, public array $refund_data)
|
||||
{
|
||||
$this->gateway_refund_status = false;
|
||||
|
||||
$this->activity_repository = new ActivityRepository();
|
||||
}
|
||||
|
||||
public function run()
|
||||
|
@ -1665,7 +1665,7 @@ class PdfBuilder
|
||||
if ($child['element'] !== 'script') {
|
||||
if ($this->service->company->markdown_enabled && array_key_exists('content', $child)) {
|
||||
$child['content'] = str_replace('<br>', "\r", ($child['content'] ?? ''));
|
||||
$child['content'] = $this->commonmark->convert($child['content'] ?? '');
|
||||
$child['content'] = $this->commonmark->convert($child['content'] ?? ''); //@phpstan-ignore-line
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -469,7 +469,7 @@ class PdfMock
|
||||
'$country_2' => 'AF',
|
||||
'$firstName' => 'Benedict',
|
||||
'$user.name' => 'Derrick Monahan DDS Erna Wunsch',
|
||||
'$font_name' => isset($this->settings?->primary_font) ? $this->settings?->primary_font : 'Roboto',
|
||||
'$font_name' => isset($this->settings?->primary_font) ? $this->settings?->primary_font : 'Roboto', //@phpstan-ignore-line
|
||||
'$auto_bill' => 'This invoice will automatically be billed to your credit card on file on the due date.',
|
||||
'$payments' => '',
|
||||
'$task.tax' => '',
|
||||
|
@ -287,7 +287,7 @@ class Design extends BaseDesign
|
||||
{
|
||||
$elements = [];
|
||||
|
||||
if (!$this->client) {
|
||||
if (!$this->client) {//@phpstan-ignore-line
|
||||
return $elements;
|
||||
}
|
||||
|
||||
@ -359,7 +359,7 @@ class Design extends BaseDesign
|
||||
$variables = $this->context['pdf_variables']['credit_details'];
|
||||
}
|
||||
|
||||
if ($this->vendor) {
|
||||
if ($this->vendor) { //@phpstan-ignore-line
|
||||
$variables = $this->context['pdf_variables']['purchase_order_details'];
|
||||
}
|
||||
|
||||
|
@ -64,9 +64,9 @@ trait DesignHelpers
|
||||
|
||||
$this->document();
|
||||
|
||||
$this->settings_object = $this->vendor ? $this->vendor->company : $this->client;
|
||||
$this->settings_object = $this->vendor ? $this->vendor->company : $this->client; //@phpstan-ignore-line
|
||||
|
||||
$this->company = $this->vendor ? $this->vendor->company : $this->client->company;
|
||||
$this->company = $this->vendor ? $this->vendor->company : $this->client->company; //@phpstan-ignore-line
|
||||
|
||||
return $this;
|
||||
}
|
||||
@ -387,7 +387,7 @@ trait DesignHelpers
|
||||
return '';
|
||||
}
|
||||
|
||||
if ($this->client->company->custom_fields && ! property_exists($this->client->company->custom_fields, $field)) {
|
||||
if ($this->client->company->custom_fields && ! property_exists($this->client->company->custom_fields, $field)) { //@phpstan-ignore-line
|
||||
return '';
|
||||
}
|
||||
|
||||
|
@ -27,16 +27,6 @@ class PdfMaker
|
||||
|
||||
public $document;
|
||||
|
||||
private $xpath;
|
||||
|
||||
private $filters = [
|
||||
'<![CDATA[' => '',
|
||||
'<![CDATA[<![CDATA[' => '',
|
||||
']]]]><![CDATA[>]]>' => '',
|
||||
']]>' => '',
|
||||
'<?xml version="1.0" encoding="utf-8" standalone="yes"??>' => '',
|
||||
];
|
||||
|
||||
private $options;
|
||||
|
||||
/** @var CommonMarkConverter */
|
||||
|
@ -94,7 +94,7 @@ trait PdfMakerUtilities
|
||||
if ($child['element'] !== 'script') {
|
||||
if (array_key_exists('process_markdown', $this->data) && array_key_exists('content', $child) && $this->data['process_markdown']) {
|
||||
$child['content'] = str_replace('<br>', "\r", ($child['content'] ?? ''));
|
||||
$child['content'] = $this->commonmark->convert($child['content'] ?? '');
|
||||
$child['content'] = $this->commonmark->convert($child['content'] ?? ''); //@phpstan-ignore-line
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,7 +41,11 @@ class CreateInvitations extends AbstractService
|
||||
|
||||
public function run()
|
||||
{
|
||||
$contacts = $this->purchase_order?->vendor?->contacts()->get();
|
||||
|
||||
if(!$this->purchase_order->vendor)
|
||||
return $this->purchase_order;
|
||||
|
||||
$contacts = $this->purchase_order->vendor->contacts()->get();
|
||||
|
||||
if ($contacts->count() == 0) {
|
||||
$this->createBlankContact();
|
||||
|
@ -11,19 +11,15 @@
|
||||
|
||||
namespace App\Services\PurchaseOrder;
|
||||
|
||||
use App\Models\PurchaseOrder;
|
||||
use App\Models\Vendor;
|
||||
use App\Models\Webhook;
|
||||
use App\Models\PurchaseOrder;
|
||||
|
||||
class MarkSent
|
||||
{
|
||||
private $vendor;
|
||||
|
||||
private $purchase_order;
|
||||
|
||||
public function __construct($vendor, $purchase_order)
|
||||
|
||||
public function __construct(public Vendor $vendor, public PurchaseOrder $purchase_order)
|
||||
{
|
||||
$this->vendor = $vendor;
|
||||
$this->purchase_order = $purchase_order;
|
||||
}
|
||||
|
||||
public function run()
|
||||
|
@ -1,40 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2024. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Services\Quote;
|
||||
|
||||
use App\Events\Quote\QuoteWasMarkedApproved;
|
||||
use App\Models\Quote;
|
||||
use App\Utils\Ninja;
|
||||
|
||||
class MarkApproved
|
||||
{
|
||||
private $client;
|
||||
|
||||
public function __construct($client)
|
||||
{
|
||||
$this->client = $client;
|
||||
}
|
||||
|
||||
public function run($quote)
|
||||
{
|
||||
/* Return immediately if status is not draft */
|
||||
if ($quote->status_id != Quote::STATUS_SENT) {
|
||||
return $quote;
|
||||
}
|
||||
|
||||
$quote->service()->setStatus(Quote::STATUS_APPROVED)->applyNumber()->save();
|
||||
|
||||
event(new QuoteWasMarkedApproved($quote, $quote->company, Ninja::eventVars()));
|
||||
|
||||
return $quote;
|
||||
}
|
||||
}
|
@ -171,39 +171,39 @@ class UpdateReminder extends AbstractService
|
||||
return $this->quote;
|
||||
}
|
||||
|
||||
private function addTimeInterval($date, $endless_reminder_frequency_id): ?Carbon
|
||||
{
|
||||
if (! $date) {
|
||||
return null;
|
||||
}
|
||||
// private function addTimeInterval($date, $endless_reminder_frequency_id): ?Carbon
|
||||
// {
|
||||
// if (! $date) {
|
||||
// return null;
|
||||
// }
|
||||
|
||||
switch ($endless_reminder_frequency_id) {
|
||||
case RecurringInvoice::FREQUENCY_DAILY:
|
||||
return Carbon::parse($date)->addDay()->startOfDay();
|
||||
case RecurringInvoice::FREQUENCY_WEEKLY:
|
||||
return Carbon::parse($date)->addWeek()->startOfDay();
|
||||
case RecurringInvoice::FREQUENCY_TWO_WEEKS:
|
||||
return Carbon::parse($date)->addWeeks(2)->startOfDay();
|
||||
case RecurringInvoice::FREQUENCY_FOUR_WEEKS:
|
||||
return Carbon::parse($date)->addWeeks(4)->startOfDay();
|
||||
case RecurringInvoice::FREQUENCY_MONTHLY:
|
||||
return Carbon::parse($date)->addMonthNoOverflow()->startOfDay();
|
||||
case RecurringInvoice::FREQUENCY_TWO_MONTHS:
|
||||
return Carbon::parse($date)->addMonthsNoOverflow(2)->startOfDay();
|
||||
case RecurringInvoice::FREQUENCY_THREE_MONTHS:
|
||||
return Carbon::parse($date)->addMonthsNoOverflow(3)->startOfDay();
|
||||
case RecurringInvoice::FREQUENCY_FOUR_MONTHS:
|
||||
return Carbon::parse($date)->addMonthsNoOverflow(4)->startOfDay();
|
||||
case RecurringInvoice::FREQUENCY_SIX_MONTHS:
|
||||
return Carbon::parse($date)->addMonthsNoOverflow(6)->startOfDay();
|
||||
case RecurringInvoice::FREQUENCY_ANNUALLY:
|
||||
return Carbon::parse($date)->addYear()->startOfDay();
|
||||
case RecurringInvoice::FREQUENCY_TWO_YEARS:
|
||||
return Carbon::parse($date)->addYears(2)->startOfDay();
|
||||
case RecurringInvoice::FREQUENCY_THREE_YEARS:
|
||||
return Carbon::parse($date)->addYears(3)->startOfDay();
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
// switch ($endless_reminder_frequency_id) {
|
||||
// case RecurringInvoice::FREQUENCY_DAILY:
|
||||
// return Carbon::parse($date)->addDay()->startOfDay();
|
||||
// case RecurringInvoice::FREQUENCY_WEEKLY:
|
||||
// return Carbon::parse($date)->addWeek()->startOfDay();
|
||||
// case RecurringInvoice::FREQUENCY_TWO_WEEKS:
|
||||
// return Carbon::parse($date)->addWeeks(2)->startOfDay();
|
||||
// case RecurringInvoice::FREQUENCY_FOUR_WEEKS:
|
||||
// return Carbon::parse($date)->addWeeks(4)->startOfDay();
|
||||
// case RecurringInvoice::FREQUENCY_MONTHLY:
|
||||
// return Carbon::parse($date)->addMonthNoOverflow()->startOfDay();
|
||||
// case RecurringInvoice::FREQUENCY_TWO_MONTHS:
|
||||
// return Carbon::parse($date)->addMonthsNoOverflow(2)->startOfDay();
|
||||
// case RecurringInvoice::FREQUENCY_THREE_MONTHS:
|
||||
// return Carbon::parse($date)->addMonthsNoOverflow(3)->startOfDay();
|
||||
// case RecurringInvoice::FREQUENCY_FOUR_MONTHS:
|
||||
// return Carbon::parse($date)->addMonthsNoOverflow(4)->startOfDay();
|
||||
// case RecurringInvoice::FREQUENCY_SIX_MONTHS:
|
||||
// return Carbon::parse($date)->addMonthsNoOverflow(6)->startOfDay();
|
||||
// case RecurringInvoice::FREQUENCY_ANNUALLY:
|
||||
// return Carbon::parse($date)->addYear()->startOfDay();
|
||||
// case RecurringInvoice::FREQUENCY_TWO_YEARS:
|
||||
// return Carbon::parse($date)->addYears(2)->startOfDay();
|
||||
// case RecurringInvoice::FREQUENCY_THREE_YEARS:
|
||||
// return Carbon::parse($date)->addYears(3)->startOfDay();
|
||||
// default:
|
||||
// return null;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ class UpdatePrice extends AbstractService
|
||||
->where('is_deleted', 0)
|
||||
->first();
|
||||
|
||||
if ($product) {
|
||||
if ($product) { //@phpstan-ignore-line
|
||||
$line_items[$key]->cost = floatval($product->price);
|
||||
}
|
||||
}
|
||||
|
@ -183,17 +183,17 @@ class ProfitLoss
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function getForeignIncome(): array
|
||||
{
|
||||
return $this->foreign_income;
|
||||
}
|
||||
// private function getForeignIncome(): array
|
||||
// {
|
||||
// return $this->foreign_income;
|
||||
// }
|
||||
|
||||
private function filterPaymentIncome()
|
||||
{
|
||||
$payments = $this->paymentIncome();
|
||||
// private function filterPaymentIncome()
|
||||
// {
|
||||
// $payments = $this->paymentIncome();
|
||||
|
||||
return $this;
|
||||
}
|
||||
// return $this;
|
||||
// }
|
||||
|
||||
/*
|
||||
//returns an array of objects
|
||||
@ -427,26 +427,26 @@ class ProfitLoss
|
||||
+"payments_converted": "12260.870000000000",
|
||||
+"currency_id": 1,
|
||||
*/
|
||||
private function paymentIncome()
|
||||
{
|
||||
return \DB::select('
|
||||
SELECT
|
||||
SUM(coalesce(payments.amount - payments.refunded,0)) as payments,
|
||||
SUM(coalesce(payments.amount - payments.refunded,0)) * IFNULL(payments.exchange_rate ,1) as payments_converted,
|
||||
payments.currency_id as currency_id
|
||||
FROM clients
|
||||
INNER JOIN
|
||||
payments ON
|
||||
clients.id=payments.client_id
|
||||
WHERE payments.status_id IN (1,4,5,6)
|
||||
AND clients.is_deleted = false
|
||||
AND payments.is_deleted = false
|
||||
AND payments.company_id = :company_id
|
||||
AND (payments.date BETWEEN :start_date AND :end_date)
|
||||
GROUP BY currency_id
|
||||
ORDER BY currency_id;
|
||||
', ['company_id' => $this->company->id, 'start_date' => $this->start_date, 'end_date' => $this->end_date]);
|
||||
}
|
||||
// private function paymentIncome()
|
||||
// {
|
||||
// return \DB::select('
|
||||
// SELECT
|
||||
// SUM(coalesce(payments.amount - payments.refunded,0)) as payments,
|
||||
// SUM(coalesce(payments.amount - payments.refunded,0)) * IFNULL(payments.exchange_rate ,1) as payments_converted,
|
||||
// payments.currency_id as currency_id
|
||||
// FROM clients
|
||||
// INNER JOIN
|
||||
// payments ON
|
||||
// clients.id=payments.client_id
|
||||
// WHERE payments.status_id IN (1,4,5,6)
|
||||
// AND clients.is_deleted = false
|
||||
// AND payments.is_deleted = false
|
||||
// AND payments.company_id = :company_id
|
||||
// AND (payments.date BETWEEN :start_date AND :end_date)
|
||||
// GROUP BY currency_id
|
||||
// ORDER BY currency_id;
|
||||
// ', ['company_id' => $this->company->id, 'start_date' => $this->start_date, 'end_date' => $this->end_date]);
|
||||
// }
|
||||
|
||||
private function expenseData()
|
||||
{
|
||||
@ -544,18 +544,18 @@ class ProfitLoss
|
||||
return round(($amount * $exchange_rate), 2);
|
||||
}
|
||||
|
||||
private function expenseCalcWithTax()
|
||||
{
|
||||
return \DB::select('
|
||||
SELECT sum(expenses.amount) as amount,
|
||||
IFNULL(expenses.currency_id, :company_currency) as currency_id
|
||||
FROM expenses
|
||||
WHERE expenses.is_deleted = 0
|
||||
AND expenses.company_id = :company_id
|
||||
AND (expenses.date BETWEEN :start_date AND :end_date)
|
||||
GROUP BY currency_id
|
||||
', ['company_currency' => $this->company->settings->currency_id, 'company_id' => $this->company->id, 'start_date' => $this->start_date, 'end_date' => $this->end_date]);
|
||||
}
|
||||
// private function expenseCalcWithTax()
|
||||
// {
|
||||
// return \DB::select('
|
||||
// SELECT sum(expenses.amount) as amount,
|
||||
// IFNULL(expenses.currency_id, :company_currency) as currency_id
|
||||
// FROM expenses
|
||||
// WHERE expenses.is_deleted = 0
|
||||
// AND expenses.company_id = :company_id
|
||||
// AND (expenses.date BETWEEN :start_date AND :end_date)
|
||||
// GROUP BY currency_id
|
||||
// ', ['company_currency' => $this->company->settings->currency_id, 'company_id' => $this->company->id, 'start_date' => $this->start_date, 'end_date' => $this->end_date]);
|
||||
// }
|
||||
|
||||
private function setBillingReportType()
|
||||
{
|
||||
|
@ -23,8 +23,6 @@ class EmailStatementService
|
||||
use MakesHash;
|
||||
use MakesDates;
|
||||
|
||||
private Client $client;
|
||||
|
||||
public function __construct(public Scheduler $scheduler)
|
||||
{
|
||||
}
|
||||
@ -45,9 +43,6 @@ class EmailStatementService
|
||||
$query->cursor()
|
||||
->each(function ($_client) {
|
||||
|
||||
/**@var \App\Models\Client $_client */
|
||||
$this->client = $_client;
|
||||
|
||||
//work out the date range
|
||||
$statement_properties = $this->calculateStatementProperties($_client);
|
||||
|
||||
|
@ -102,7 +102,7 @@ class SubscriptionCalculator
|
||||
$line_item->quantity = (float) $item['quantity'];
|
||||
$line_item->cost = (float) $item['product']['price'];
|
||||
$line_item->notes = $item['product']['notes'];
|
||||
$line_item->tax_id = (string)$item['product']['tax_id'] ?? '1';
|
||||
$line_item->tax_id = (string)$item['product']['tax_id'] ?? '1'; //@phpstan-ignore-line
|
||||
$items[] = $line_item;
|
||||
|
||||
}
|
||||
|
@ -145,7 +145,7 @@ class SubscriptionService
|
||||
|
||||
/* 06-04-2022 */
|
||||
/* We may not be in a state where the user is present */
|
||||
if (auth()->guard('contact')) {
|
||||
if (auth()->guard('contact')->user()) {
|
||||
return $this->handleRedirect('/client/invoices/'.$this->encodePrimaryKey($payment_hash->fee_invoice_id));
|
||||
}
|
||||
}
|
||||
@ -200,7 +200,7 @@ class SubscriptionService
|
||||
$license->first_name = $contact ? $contact->first_name : ' ';
|
||||
$license->last_name = $contact ? $contact->last_name : ' ';
|
||||
$license->is_claimed = 1;
|
||||
$license->transaction_reference = $payment_hash?->payment?->transaction_reference ?: ' ';
|
||||
$license->transaction_reference = $payment_hash?->payment?->transaction_reference ?: ' '; //@phpstan-ignore-line
|
||||
$license->product_id = self::WHITE_LABEL;
|
||||
$license->recurring_invoice_id = $recurring_invoice->id;
|
||||
|
||||
|
@ -1327,6 +1327,7 @@ class TemplateService
|
||||
{
|
||||
$entity_string = '';
|
||||
|
||||
//@phpstan-ignore-next-line
|
||||
match($this->entity) {
|
||||
($this->entity instanceof Invoice) => $entity_string = 'invoice',
|
||||
($this->entity instanceof Quote) => $entity_string = 'quote',
|
||||
|
@ -85,6 +85,7 @@ class SystemHealth
|
||||
'file_permissions' => (string) self::checkFileSystem(),
|
||||
'exchange_rate_api_not_configured' => (bool)self::checkCurrencySanity(),
|
||||
'api_version' => (string) config('ninja.app_version'),
|
||||
'is_docker' => (bool) config('ninja.is_docker'),
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -146,7 +146,6 @@ trait MakesDates
|
||||
|
||||
}
|
||||
|
||||
|
||||
return match ($data['date_range']) {
|
||||
EmailStatement::LAST7 => [now()->startOfDay()->subDays(7)->format('Y-m-d'), now()->startOfDay()->format('Y-m-d')],
|
||||
EmailStatement::LAST30 => [now()->startOfDay()->subDays(30)->format('Y-m-d'), now()->startOfDay()->format('Y-m-d')],
|
||||
@ -162,4 +161,37 @@ trait MakesDates
|
||||
};
|
||||
}
|
||||
|
||||
public function calculatePreviousPeriodStartAndEndDates(array $data, ?Company $company = null): array
|
||||
{
|
||||
|
||||
//override for financial years
|
||||
if($data['date_range'] == 'this_year') {
|
||||
|
||||
$first_month_of_year = $company ? $company?->first_month_of_year : 1;
|
||||
$fin_year_start = now()->createFromDate(now()->year, $first_month_of_year, 1);
|
||||
|
||||
$fin_year_start->subYearNoOverflow();
|
||||
|
||||
if(now()->subYear()->lt($fin_year_start)) {
|
||||
$fin_year_start->subYearNoOverflow();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return match ($data['date_range']) {
|
||||
EmailStatement::LAST7 => [now()->startOfDay()->subDays(14)->format('Y-m-d'), now()->subDays(7)->startOfDay()->format('Y-m-d')],
|
||||
EmailStatement::LAST30 => [now()->startOfDay()->subDays(60)->format('Y-m-d'), now()->subDays(30)->startOfDay()->format('Y-m-d')],
|
||||
EmailStatement::LAST365 => [now()->startOfDay()->subDays(739)->format('Y-m-d'), now()->subDays(365)->startOfDay()->format('Y-m-d')],
|
||||
EmailStatement::THIS_MONTH => [now()->startOfDay()->subMonthNoOverflow()->firstOfMonth()->format('Y-m-d'), now()->startOfDay()->subMonthNoOverflow()->lastOfMonth()->format('Y-m-d')],
|
||||
EmailStatement::LAST_MONTH => [now()->startOfDay()->subMonthsNoOverflow(2)->firstOfMonth()->format('Y-m-d'), now()->startOfDay()->subMonthNoOverflow()->lastOfMonth()->format('Y-m-d')],
|
||||
EmailStatement::THIS_QUARTER => [now()->startOfDay()->subQuarterNoOverflow()->startOfQuarter()->format('Y-m-d'), now()->startOfDay()->subQuarterNoOverflow()->endOfQuarter()->format('Y-m-d')],
|
||||
EmailStatement::LAST_QUARTER => [now()->startOfDay()->subQuartersNoOverflow(2)->startOfQuarter()->format('Y-m-d'), now()->startOfDay()->subQuartersNoOverflow(2)->endOfQuarter()->format('Y-m-d')],
|
||||
EmailStatement::THIS_YEAR => [$fin_year_start->subYear()->format('Y-m-d'), $fin_year_start->copy()->subDay()->format('Y-m-d')],
|
||||
EmailStatement::LAST_YEAR => [$fin_year_start->subYear(2)->format('Y-m-d'), $fin_year_start->copy()->subYear()->subDay()->format('Y-m-d')],
|
||||
EmailStatement::CUSTOM_RANGE => [$data['start_date'], $data['end_date']],
|
||||
default => [now()->startOfDay()->firstOfMonth()->format('Y-m-d'), now()->startOfDay()->lastOfMonth()->format('Y-m-d')],
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
46
composer.lock
generated
46
composer.lock
generated
@ -535,16 +535,16 @@
|
||||
},
|
||||
{
|
||||
"name": "aws/aws-sdk-php",
|
||||
"version": "3.315.0",
|
||||
"version": "3.315.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/aws/aws-sdk-php.git",
|
||||
"reference": "a7f6026f00771025c32548dac321541face0dedc"
|
||||
"reference": "13871330833e167d098240dab74b8b069b9b07e3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/a7f6026f00771025c32548dac321541face0dedc",
|
||||
"reference": "a7f6026f00771025c32548dac321541face0dedc",
|
||||
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/13871330833e167d098240dab74b8b069b9b07e3",
|
||||
"reference": "13871330833e167d098240dab74b8b069b9b07e3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -624,9 +624,9 @@
|
||||
"support": {
|
||||
"forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
|
||||
"issues": "https://github.com/aws/aws-sdk-php/issues",
|
||||
"source": "https://github.com/aws/aws-sdk-php/tree/3.315.0"
|
||||
"source": "https://github.com/aws/aws-sdk-php/tree/3.315.1"
|
||||
},
|
||||
"time": "2024-06-26T18:08:22+00:00"
|
||||
"time": "2024-06-27T18:03:53+00:00"
|
||||
},
|
||||
{
|
||||
"name": "bacon/bacon-qr-code",
|
||||
@ -4609,16 +4609,16 @@
|
||||
},
|
||||
{
|
||||
"name": "laravel/framework",
|
||||
"version": "v11.12.0",
|
||||
"version": "v11.13.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel/framework.git",
|
||||
"reference": "9a6d9cea83cfa6b9e8eda05c89741d0411d8ebe8"
|
||||
"reference": "92deaa4f037ff100e36809443811301819a8cf84"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel/framework/zipball/9a6d9cea83cfa6b9e8eda05c89741d0411d8ebe8",
|
||||
"reference": "9a6d9cea83cfa6b9e8eda05c89741d0411d8ebe8",
|
||||
"url": "https://api.github.com/repos/laravel/framework/zipball/92deaa4f037ff100e36809443811301819a8cf84",
|
||||
"reference": "92deaa4f037ff100e36809443811301819a8cf84",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -4810,7 +4810,7 @@
|
||||
"issues": "https://github.com/laravel/framework/issues",
|
||||
"source": "https://github.com/laravel/framework"
|
||||
},
|
||||
"time": "2024-06-25T19:33:56+00:00"
|
||||
"time": "2024-06-27T09:04:50+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/pint",
|
||||
@ -11242,16 +11242,16 @@
|
||||
},
|
||||
{
|
||||
"name": "sprain/swiss-qr-bill",
|
||||
"version": "v4.12.1",
|
||||
"version": "v4.13",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sprain/php-swiss-qr-bill.git",
|
||||
"reference": "3728cd1366ac631a0587c0997a4878c37923e55b"
|
||||
"reference": "5490e9139c4050d18533440cd9ff51a64955c035"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sprain/php-swiss-qr-bill/zipball/3728cd1366ac631a0587c0997a4878c37923e55b",
|
||||
"reference": "3728cd1366ac631a0587c0997a4878c37923e55b",
|
||||
"url": "https://api.github.com/repos/sprain/php-swiss-qr-bill/zipball/5490e9139c4050d18533440cd9ff51a64955c035",
|
||||
"reference": "5490e9139c4050d18533440cd9ff51a64955c035",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -11299,7 +11299,7 @@
|
||||
"description": "A PHP library to create Swiss QR bills",
|
||||
"support": {
|
||||
"issues": "https://github.com/sprain/php-swiss-qr-bill/issues",
|
||||
"source": "https://github.com/sprain/php-swiss-qr-bill/tree/v4.12.1"
|
||||
"source": "https://github.com/sprain/php-swiss-qr-bill/tree/v4.13"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -11307,7 +11307,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2024-05-16T07:19:59+00:00"
|
||||
"time": "2024-06-27T11:17:56+00:00"
|
||||
},
|
||||
{
|
||||
"name": "square/square",
|
||||
@ -19238,16 +19238,16 @@
|
||||
},
|
||||
{
|
||||
"name": "spatie/error-solutions",
|
||||
"version": "1.0.2",
|
||||
"version": "1.0.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/spatie/error-solutions.git",
|
||||
"reference": "9782ba6e25cb026cc653619e01ca695d428b3f03"
|
||||
"reference": "55ea4117e0fde89d520883734ab9b71064c48876"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/spatie/error-solutions/zipball/9782ba6e25cb026cc653619e01ca695d428b3f03",
|
||||
"reference": "9782ba6e25cb026cc653619e01ca695d428b3f03",
|
||||
"url": "https://api.github.com/repos/spatie/error-solutions/zipball/55ea4117e0fde89d520883734ab9b71064c48876",
|
||||
"reference": "55ea4117e0fde89d520883734ab9b71064c48876",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -19300,7 +19300,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/spatie/error-solutions/issues",
|
||||
"source": "https://github.com/spatie/error-solutions/tree/1.0.2"
|
||||
"source": "https://github.com/spatie/error-solutions/tree/1.0.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -19308,7 +19308,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2024-06-26T13:09:17+00:00"
|
||||
"time": "2024-06-27T12:22:48+00:00"
|
||||
},
|
||||
{
|
||||
"name": "spatie/flare-client-php",
|
||||
|
@ -392,7 +392,7 @@ $lang = array(
|
||||
'payment_cvv' => 'Dette er det 3-4 cifrede nummer på bagsiden af dit kort',
|
||||
'payment_footer1' => '*Fakturaadressen skal matche den der er tilknyttet kortet.',
|
||||
'payment_footer2' => '*Klik kun på "Betal Nu" én gang - transaktionen kan tage helt op til 1 minut inden den er færdig.',
|
||||
'id_number' => 'CVR/SE-nummer',
|
||||
'id_number' => 'ID Nummer',
|
||||
'white_label_link' => 'Hvidmærket',
|
||||
'white_label_header' => 'Hvidmærket',
|
||||
'bought_white_label' => 'Hvidmærket licens accepteret',
|
||||
@ -2363,7 +2363,7 @@ $lang = array(
|
||||
'currency_gold_troy_ounce' => 'Guld Troy Ounce',
|
||||
'currency_nicaraguan_córdoba' => 'Nicaraguanske Córdoba',
|
||||
'currency_malagasy_ariary' => 'Madagaskars ariary',
|
||||
"currency_tongan_pa_anga" => "tonganske paanga",
|
||||
"currency_tongan_paanga" => "Tongan Pa'anga",
|
||||
|
||||
'review_app_help' => 'Vi håber, du nyder at bruge appen.<br/> Hvis du ville overveje :link ville vi sætte stor pris på det!',
|
||||
'writing_a_review' => 'skrive en anmeldelse',
|
||||
@ -2879,19 +2879,6 @@ $lang = array(
|
||||
'refunded' => 'Refunderet',
|
||||
'marked_quote_as_sent' => 'Succesfuldt markeret tilbud som sendt',
|
||||
'custom_module_settings' => 'Speciel Modul Indstillinger',
|
||||
'ticket' => 'Sag',
|
||||
'tickets' => 'Sager',
|
||||
'ticket_number' => 'Sag #',
|
||||
'new_ticket' => 'Ny sag',
|
||||
'edit_ticket' => 'Redigér sag',
|
||||
'view_ticket' => 'Vis sag',
|
||||
'archive_ticket' => 'Arkivér sag',
|
||||
'restore_ticket' => 'Genskab sag',
|
||||
'delete_ticket' => 'Slet sag',
|
||||
'archived_ticket' => 'Sag blev arkiveret',
|
||||
'archived_tickets' => 'Sager blev arkiveret',
|
||||
'restored_ticket' => 'Sag blev genskabt',
|
||||
'deleted_ticket' => 'Sag blev slettet',
|
||||
'open' => 'Åben',
|
||||
'new' => 'Ny',
|
||||
'closed' => 'Lukket',
|
||||
@ -2908,14 +2895,6 @@ $lang = array(
|
||||
'assigned_to' => 'Tildelt',
|
||||
'reply' => 'Svar',
|
||||
'awaiting_reply' => 'Afventer svar',
|
||||
'ticket_close' => 'Luk sag',
|
||||
'ticket_reopen' => 'Genåbn sag',
|
||||
'ticket_open' => 'Åbn sag',
|
||||
'ticket_split' => 'Opdel sag',
|
||||
'ticket_merge' => 'Sammenflet sag',
|
||||
'ticket_update' => 'Opdatér sag',
|
||||
'ticket_settings' => 'Sagsindstillinger',
|
||||
'updated_ticket' => 'Sag blev opdateret',
|
||||
'mark_spam' => 'Marker som spam',
|
||||
'local_part' => 'Lokal del',
|
||||
'local_part_unavailable' => 'Navn taget',
|
||||
@ -2933,31 +2912,23 @@ $lang = array(
|
||||
'mime_types' => 'Mime typer',
|
||||
'mime_types_placeholder' => '. PDF , .docx, .jpg',
|
||||
'mime_types_help' => 'Kommasepareret liste over tilladte mime-typer, lad tom for alle',
|
||||
'ticket_number_start_help' => 'Ticket number must be greater than the current ticket number',
|
||||
'new_ticket_template_id' => 'New ticket',
|
||||
'new_ticket_autoresponder_help' => 'Selecting a template will send an auto response to a client/contact when a new ticket is created',
|
||||
'update_ticket_template_id' => 'Updated ticket',
|
||||
'update_ticket_autoresponder_help' => 'Selecting a template will send an auto response to a client/contact when a ticket is updated',
|
||||
'close_ticket_template_id' => 'Closed ticket',
|
||||
'close_ticket_autoresponder_help' => 'Selecting a template will send an auto response to a client/contact when a ticket is closed',
|
||||
'default_priority' => 'Standardprioritet',
|
||||
'alert_new_comment_id' => 'Ny kommentar',
|
||||
'alert_comment_ticket_help' => 'Hvis du vælger en skabelon, sendes der en meddelelse (til agent), når der kommer en kommentar.',
|
||||
'alert_comment_ticket_email_help' => 'Kommaseparerede e-mails til bcc ved ny kommentar.',
|
||||
'new_ticket_notification_list' => 'Yderligere nye Sag -meddelelser',
|
||||
'update_ticket_notification_list' => 'Yderligere meddelelser om nye kommentarer',
|
||||
'comma_separated_values' => 'admin@example.com, supervisor@example.com',
|
||||
'alert_ticket_assign_agent_id' => 'Tildeling af sag',
|
||||
'alert_ticket_assign_agent_id_hel' => 'Valg af en skabelon vil sende en meddelelse (til agent), når en Sag er tildelt.',
|
||||
'alert_ticket_assign_agent_id_notifications' => 'Yderligere Sag tildelte meddelelser',
|
||||
'alert_ticket_assign_agent_id_help' => 'Kommaseparerede e-mails til bcc på Sag opgave.',
|
||||
'alert_ticket_transfer_email_help' => 'Kommaseparerede e-mails til bcc ved Sag overførsel.',
|
||||
'alert_ticket_overdue_agent_id' => 'Sag er forfalden',
|
||||
'alert_ticket_overdue_email' => 'Yderligere forfaldne Sag -meddelelser',
|
||||
'alert_ticket_overdue_email_help' => 'Kommaseparerede e-mails til bcc på Sag forsinket.',
|
||||
'alert_ticket_overdue_agent_id_help' => 'Valg af en skabelon vil sende en meddelelse (til agent), når en Sag bliver forsinket.',
|
||||
'default_agent' => 'Standardagent',
|
||||
'default_agent_help' => 'Hvis valgt vil det automatisk blive tildelt alle indgående billetter',
|
||||
'show_agent_details' => 'Vis agentoplysninger om svar',
|
||||
'avatar' => 'Avatar',
|
||||
'remove_avatar' => 'Fjern avatar',
|
||||
'ticket_not_found' => 'Sag blev ikke fundet',
|
||||
'add_template' => 'Tilføj skabelon',
|
||||
'updated_ticket_template' => 'Sagsskabelon blev opdateret',
|
||||
'created_ticket_template' => 'Sagsskabelon blev oprettet',
|
||||
'archive_ticket_template' => 'Arkiv skabelon',
|
||||
'restore_ticket_template' => 'Genskab skabelon',
|
||||
'archived_ticket_template' => 'Succesfuldt arkiveret skabelon',
|
||||
@ -3130,7 +3101,7 @@ $lang = array(
|
||||
'sign_up_with_google' => 'Tilmeld dig med Google',
|
||||
'long_press_multiselect' => 'Tryk længe på Multiselect',
|
||||
'migrate_to_next_version' => 'Migrer til den næste version af Faktura Ninja',
|
||||
'migrate_intro_text' => 'Vi har arbejdet på næste version af Faktura Ninja. Klik på knappen nedenfor for at starte migreringen.',
|
||||
'migrate_intro_text' => 'Vi har arbejdet på næste version af Invoice Ninja. Klik på knappen nedenfor for at starte migreringen.',
|
||||
'start_the_migration' => 'Start migreringen',
|
||||
'migration' => 'Migration',
|
||||
'welcome_to_the_new_version' => 'Velkommen til den nye version af Faktura Ninja',
|
||||
@ -4504,7 +4475,7 @@ $lang = array(
|
||||
'view_purchase_order' => 'Vis Indkøbsordre',
|
||||
'purchase_orders_backup_subject' => 'Dine indkøbsordrer er klar til download',
|
||||
'notification_purchase_order_viewed_subject' => 'Indkøbsordre :invoice blev set af :client',
|
||||
'notification_purchase_order_viewed' => 'Følgende Sælger :client har set Indkøbsordre :invoice for :amount .',
|
||||
'notification_purchase_order_viewed' => 'Følgende leverandør :client har set Indkøbsordre :invoice for :amount .',
|
||||
'purchase_order_date' => 'Dato for købsordre',
|
||||
'purchase_orders' => 'Indkøbsordre',
|
||||
'purchase_order_number_placeholder' => 'Indkøbsordre nr. :purchase_order',
|
||||
@ -5302,6 +5273,19 @@ $lang = array(
|
||||
'currency_bhutan_ngultrum' => 'Bhutan Ngultrum',
|
||||
'end_of_month' => 'End Of Month',
|
||||
'merge_e_invoice_to_pdf' => 'Merge E-Invoice and PDF',
|
||||
'task_assigned_subject' => 'New task assignment [Task :task] [ :date ]',
|
||||
'task_assigned_body' => 'You have been assigned task :task <br><br> Description: :description <br><br> Client: :client',
|
||||
'activity_141' => 'User :user entered note: :notes',
|
||||
'quote_reminder_subject' => 'Reminder: Quote :quote from :company',
|
||||
'quote_reminder_message' => 'Reminder for quote :number for :amount',
|
||||
'quote_reminder1' => 'First Quote Reminder',
|
||||
'before_valid_until_date' => 'Before the valid until date',
|
||||
'after_valid_until_date' => 'After the valid until date',
|
||||
'after_quote_date' => 'After the quote date',
|
||||
'remind_quote' => 'Remind Quote',
|
||||
'end_of_month' => 'End Of Month',
|
||||
'tax_currency_mismatch' => 'Tax currency is different from invoice currency',
|
||||
'edocument_import_already_exists' => '\nThe invoice has already been imported on :date'
|
||||
);
|
||||
|
||||
return $lang;
|
||||
return $lang;
|
||||
|
@ -5288,7 +5288,16 @@ $lang = array(
|
||||
'remind_quote' => 'Remind Quote',
|
||||
'end_of_month' => 'End Of Month',
|
||||
'tax_currency_mismatch' => 'Tax currency is different from invoice currency',
|
||||
'edocument_import_already_exists' => '\nThe invoice has already been imported on :date'
|
||||
'edocument_import_already_exists' => '\nThe invoice has already been imported on :date',
|
||||
'before_valid_until' => 'Before the valid until',
|
||||
'after_valid_until' => 'After the valid until',
|
||||
'task_assigned_notification' => 'Task Assigned Notification',
|
||||
'task_assigned_notification_help' => 'Send an email when a task is assigned',
|
||||
'invoices_locked_end_of_month' => 'Invoices are locked at the end of the month',
|
||||
'referral_url' => 'Referral URL',
|
||||
'add_comment' => 'Add Comment',
|
||||
'added_comment' => 'Successfully saved comment',
|
||||
'tickets' => 'Tickets',
|
||||
);
|
||||
|
||||
return $lang;
|
||||
|
@ -2361,7 +2361,7 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette
|
||||
'currency_gold_troy_ounce' => 'Once troy d\'or',
|
||||
'currency_nicaraguan_córdoba' => 'Cordoba nicaraguayen',
|
||||
'currency_malagasy_ariary' => 'Ariary malgache',
|
||||
"currency_tongan_pa_anga" => "Pa'anga tongien",
|
||||
"currency_tongan_paanga" => "Pa'anga tongien",
|
||||
|
||||
'review_app_help' => 'Nous espérons que votre utilisation de cette application vous est agréable.<br/>Un commentaire de votre part serait grandement apprécié!',
|
||||
'writing_a_review' => 'rédiger un commentaire',
|
||||
@ -2877,19 +2877,6 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette
|
||||
'refunded' => 'Remboursé',
|
||||
'marked_quote_as_sent' => 'La soumission a été marquée comme envoyée',
|
||||
'custom_module_settings' => 'Paramètres personnalisés de modules',
|
||||
'ticket' => 'Billet',
|
||||
'tickets' => 'Billets',
|
||||
'ticket_number' => 'Billet #',
|
||||
'new_ticket' => 'Nouveau billet',
|
||||
'edit_ticket' => 'Éditer le billet',
|
||||
'view_ticket' => 'Voir le billet',
|
||||
'archive_ticket' => 'Archiver le billet',
|
||||
'restore_ticket' => 'Restaurer le billet',
|
||||
'delete_ticket' => 'Supprimer le billet',
|
||||
'archived_ticket' => 'Le billet a été archivé',
|
||||
'archived_tickets' => 'Les billets ont été archivés',
|
||||
'restored_ticket' => 'Le billet a été restauré',
|
||||
'deleted_ticket' => 'Le billet a été supprimé',
|
||||
'open' => 'Ouvert',
|
||||
'new' => 'Nouveau',
|
||||
'closed' => 'Désactivé',
|
||||
@ -2906,14 +2893,6 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette
|
||||
'assigned_to' => 'Assigné à',
|
||||
'reply' => 'Répondre',
|
||||
'awaiting_reply' => 'En attente de réponse',
|
||||
'ticket_close' => 'Fermer le billet',
|
||||
'ticket_reopen' => 'Réouvrir le billet',
|
||||
'ticket_open' => 'Ouvrir le billet',
|
||||
'ticket_split' => 'Scinder le billet',
|
||||
'ticket_merge' => 'Fusionner le billet',
|
||||
'ticket_update' => 'Mettre à jour le billet',
|
||||
'ticket_settings' => 'Paramètres des billets',
|
||||
'updated_ticket' => 'Billet mis à jour',
|
||||
'mark_spam' => 'Marquer comme pourriel',
|
||||
'local_part' => 'Partie locale',
|
||||
'local_part_unavailable' => 'Nom déjà pris',
|
||||
@ -2931,31 +2910,23 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette
|
||||
'mime_types' => 'Type MIME',
|
||||
'mime_types_placeholder' => '.pdf , .docx, .jpg',
|
||||
'mime_types_help' => 'Liste séparée par une virgule pour les types MIME autorisés. Laissant vide pour tout autoriser',
|
||||
'ticket_number_start_help' => 'Le numéro du billet doit être supérieur au numéro de billet actuel.',
|
||||
'new_ticket_template_id' => 'Nouveau billet',
|
||||
'new_ticket_autoresponder_help' => 'La sélection d\'un modèle enverra automatiquement une réponse automatique à un client/contact lors de la création d\'un nouveau billet.',
|
||||
'update_ticket_template_id' => 'Le billet a été mis à jour',
|
||||
'update_ticket_autoresponder_help' => 'La sélection d\'un modèle déclenchera automatiquement l\'envoi d\'une réponse automatique à un client/contact lors de la mise à jour d\'un billet.',
|
||||
'close_ticket_template_id' => 'Le billet a ét fermé',
|
||||
'close_ticket_autoresponder_help' => 'La sélection d\'un modèle enverra automatiquement une réponse automatique à un client/contact lors de la fermeture d\'un billet.',
|
||||
'default_priority' => 'Priorité par défaut',
|
||||
'alert_new_comment_id' => 'Nouveau commentaire',
|
||||
'alert_comment_ticket_help' => 'En sélectionnant un modèle, une notification (à l\'agent) sera envoyée lorsqu\'un commentaire est fait',
|
||||
'alert_comment_ticket_email_help' => 'Courriels séparés par une virgule pour Cci sur un nouveau commentaire.',
|
||||
'new_ticket_notification_list' => 'Notifications de nouveaux billets additionnels',
|
||||
'update_ticket_notification_list' => 'Notifications de nouveaux commentaires additionnels',
|
||||
'comma_separated_values' => 'admin@exemple.com, supervisor@exemple.com',
|
||||
'alert_ticket_assign_agent_id' => 'Assignation de billet',
|
||||
'alert_ticket_assign_agent_id_hel' => 'En sélectionnant un modèle, une notification (à l\'agent) sera envoyée lorsqu\'un billet est assigné.',
|
||||
'alert_ticket_assign_agent_id_notifications' => 'Notifications de billets assignés additionnels',
|
||||
'alert_ticket_assign_agent_id_help' => 'Courriels séparés par une virgule pour Cci pour un billet assigné.',
|
||||
'alert_ticket_transfer_email_help' => 'Courriels séparés par une virgule pour Cci sur un billet transféré.',
|
||||
'alert_ticket_overdue_agent_id' => 'Billet en retard',
|
||||
'alert_ticket_overdue_email' => 'Notifications de billets en retard additionnels',
|
||||
'alert_ticket_overdue_email_help' => 'Courriels séparés par une virgule pour Cci sur un billet en retard.',
|
||||
'alert_ticket_overdue_agent_id_help' => 'En sélectionnant un modèle, une notification (à l\'agent) sera envoyée lorsqu\'un billet est en retard.',
|
||||
'default_agent' => 'Agent par défaut',
|
||||
'default_agent_help' => 'Cette sélection va automatiquement être assignée à tous les courriels entrants',
|
||||
'show_agent_details' => 'Afficher les informations de l\'agent dans les réponses',
|
||||
'avatar' => 'Avatar',
|
||||
'remove_avatar' => 'Retirer l\'avatar',
|
||||
'ticket_not_found' => 'Billet introuvable',
|
||||
'add_template' => 'Ajouter un modèle',
|
||||
'updated_ticket_template' => 'Modèle de billets mise à jour',
|
||||
'created_ticket_template' => 'Modèle de billet créés',
|
||||
'archive_ticket_template' => 'Archiver le modèle',
|
||||
'restore_ticket_template' => 'Restaurer le modèle',
|
||||
'archived_ticket_template' => 'Le modèle a été archivé',
|
||||
@ -5300,6 +5271,19 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette
|
||||
'currency_bhutan_ngultrum' => 'Ngultrum Bhoutan',
|
||||
'end_of_month' => 'Fin de mois',
|
||||
'merge_e_invoice_to_pdf' => 'Fusionner E-Facture et PDF',
|
||||
'task_assigned_subject' => 'Nouvelle tâche assignée [Tâche:task] [ :date ]',
|
||||
'task_assigned_body' => 'Vous avez été assigné à la tâche :task <br><br> Description: :description <br><br> Client: :client',
|
||||
'activity_141' => 'L\'utilisateur:user a saisi la note: :notes',
|
||||
'quote_reminder_subject' => 'Rappel: Soumission:quote de :company',
|
||||
'quote_reminder_message' => 'Rappel pour la soumission :number de :amount',
|
||||
'quote_reminder1' => 'Rappel pour la première soumission',
|
||||
'before_valid_until_date' => 'Avant la date Valide jusqu\'au',
|
||||
'after_valid_until_date' => 'Après la date Valide jusqu\'au',
|
||||
'after_quote_date' => 'Après al date de soumission',
|
||||
'remind_quote' => 'Rappel de soumission',
|
||||
'end_of_month' => 'Fin de mois',
|
||||
'tax_currency_mismatch' => 'La devise de la taxe est différente de la devise de la facture.',
|
||||
'edocument_import_already_exists' => '\nLa facture a déjà été importée le :date'
|
||||
);
|
||||
|
||||
return $lang;
|
||||
return $lang;
|
||||
|
@ -31,4 +31,10 @@ parameters:
|
||||
- '#Access to protected property#'
|
||||
- '#Call to undefined method .*#'
|
||||
- '#Argument of an invalid type stdClass supplied for foreach, only iterables are supported.#'
|
||||
- '#Comparison operation ">=" between int<1, max> and 1 is always true#'
|
||||
- '#Comparison operation ">=" between int<1, max> and 1 is always true#'
|
||||
- '#Negated boolean expression is always#'
|
||||
- '#Ternary operator condition#'
|
||||
- '#Expression on left side of ?? is not nullable.#'
|
||||
- '#Left side of && is always true.#'
|
||||
- '#Right side of && is always true.#'
|
||||
|
6
public/flutter_service_worker.js
vendored
6
public/flutter_service_worker.js
vendored
@ -16,9 +16,9 @@ const RESOURCES = {"icons/Icon-512.png": "0f9aff01367f0a0c69773d25ca16ef35",
|
||||
"canvaskit/canvaskit.js": "c86fbd9e7b17accae76e5ad116583dc4",
|
||||
"canvaskit/canvaskit.wasm": "3d2a2d663e8c5111ac61a46367f751ac",
|
||||
"canvaskit/skwasm.wasm": "e42815763c5d05bba43f9d0337fa7d84",
|
||||
"version.json": "1592dbbd49cf08963e29ab3a85640d96",
|
||||
"version.json": "f789e711f61e122f41a7eda7522a1fba",
|
||||
"favicon.png": "dca91c54388f52eded692718d5a98b8b",
|
||||
"main.dart.js": "0512d8a34cb5c2d5d565a27c3666d9f9",
|
||||
"main.dart.js": "bb6cfbe200a5c6a0d8857eaffd21b759",
|
||||
"assets/NOTICES": "412b336cf9e33e70058d612857effae1",
|
||||
"assets/AssetManifest.bin": "bf3be26e7055ad9a32f66b3a56138224",
|
||||
"assets/assets/images/logo_light.png": "e5f46d5a78e226e7a9553d4ca6f69219",
|
||||
@ -307,7 +307,7 @@ const RESOURCES = {"icons/Icon-512.png": "0f9aff01367f0a0c69773d25ca16ef35",
|
||||
"assets/FontManifest.json": "087fb858dc3cbfbf6baf6a30004922f1",
|
||||
"assets/fonts/MaterialIcons-Regular.otf": "a57618538ab8b4c4081d4491870ac333",
|
||||
"assets/AssetManifest.json": "759f9ef9973f7e26c2a51450b55bb9fa",
|
||||
"/": "a53ace1edfc2ce12fc50cbbade610be3",
|
||||
"/": "e847f898173e2b358dcf6efc58032f91",
|
||||
"favicon.ico": "51636d3a390451561744c42188ccd628",
|
||||
"manifest.json": "ef43d90e57aa7682d7e2cfba2f484a40"};
|
||||
// The application shell files that are downloaded before a service worker can
|
||||
|
271459
public/main.dart.js
vendored
271459
public/main.dart.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
269785
public/main.foss.dart.js
vendored
269785
public/main.foss.dart.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
17671
public/main.profile.dart.js
vendored
17671
public/main.profile.dart.js
vendored
File diff suppressed because one or more lines are too long
@ -1 +1 @@
|
||||
{"app_name":"invoiceninja_flutter","version":"5.0.160","build_number":"160","package_name":"invoiceninja_flutter"}
|
||||
{"app_name":"invoiceninja_flutter","version":"5.0.161","build_number":"161","package_name":"invoiceninja_flutter"}
|
@ -81,7 +81,7 @@
|
||||
name="country_id">
|
||||
<option value="none"></option>
|
||||
@foreach(App\Utils\TranslationHelper::getCountries() as $country)
|
||||
<option
|
||||
<option value="{{ $country->id }}">
|
||||
{{ $country->iso_3166_2 }}
|
||||
({{ $country->name }})
|
||||
</option>
|
||||
|
@ -1,4 +1,4 @@
|
||||
@extends('portal.ninja2020.layout.payments', ['gateway_title' => ctrans('texts.payment_type_credit_card'), 'card_title' => ''])
|
||||
@extends('portal.ninja2020.layout.payments', ['gateway_title' => ctrans('texts.paypal'), 'card_title' => ''])
|
||||
|
||||
@section('gateway_head')
|
||||
|
||||
|
@ -11,7 +11,9 @@
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Models\Client;
|
||||
use App\Models\CompanyGateway;
|
||||
use App\Models\Invoice;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
use Tests\MockAccountData;
|
||||
use Tests\TestCase;
|
||||
@ -44,6 +46,122 @@ class ClientModelTest extends TestCase
|
||||
|
||||
}
|
||||
|
||||
public function testNewWithoutAndDeletedClientFilters()
|
||||
{
|
||||
|
||||
$this->invoice->amount = 10;
|
||||
$this->invoice->balance = 10;
|
||||
$this->invoice->status_id=2;
|
||||
$this->invoice->date = now()->subDays(2);
|
||||
$this->invoice->due_date = now()->addDays(2);
|
||||
$this->invoice->save();
|
||||
|
||||
$cd = Client::factory()->create([
|
||||
'company_id' => $this->company->id,
|
||||
'user_id' => $this->user->id,
|
||||
]);
|
||||
|
||||
|
||||
$cd2 = Client::factory()->create([
|
||||
'company_id' => $this->company->id,
|
||||
'user_id' => $this->user->id,
|
||||
]);
|
||||
|
||||
$invoice_count = Invoice::where('company_id', $this->company->id)->count();
|
||||
|
||||
$this->assertGreaterThan(0, $invoice_count);
|
||||
|
||||
$i = Invoice::factory()->create([
|
||||
'client_id' => $cd->id,
|
||||
'user_id' => $this->user->id,
|
||||
'company_id' => $this->company->id,
|
||||
'status_id' => 2,
|
||||
'amount' => 10,
|
||||
'balance' => 10,
|
||||
'date' => now()->subDays(2)->format('Y-m-d'),
|
||||
'due_date' => now()->addDays(5)->format('Y-m-d'),
|
||||
]);
|
||||
|
||||
|
||||
$i2 = Invoice::factory()->create([
|
||||
'client_id' => $cd2->id,
|
||||
'user_id' => $this->user->id,
|
||||
'company_id' => $this->company->id,
|
||||
'status_id' => 2,
|
||||
'amount' => 10,
|
||||
'balance' => 10,
|
||||
'date' => now()->subDays(2)->format('Y-m-d'),
|
||||
'due_date' => now()->addDays(5)->format('Y-m-d'),
|
||||
]);
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->get('/api/v1/invoices?status=active');
|
||||
|
||||
$response->assertStatus(200);
|
||||
$arr = $response->json();
|
||||
|
||||
$this->assertEquals($invoice_count+2, count($arr['data']));
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->get('/api/v1/invoices?upcoming=true&status=active&include=client');
|
||||
|
||||
$response->assertStatus(200);
|
||||
$arr = $response->json();
|
||||
|
||||
$this->assertEquals($invoice_count + 2, count($arr['data']));
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->get('/api/v1/invoices?upcoming=true&status=active&without_deleted_clients=true');
|
||||
|
||||
$response->assertStatus(200);
|
||||
$arr = $response->json();
|
||||
|
||||
$this->assertEquals($invoice_count + 2, count($arr['data']));
|
||||
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->get('/api/v1/invoices?upcoming=true&status=active&filter_deleted_clients=true');
|
||||
|
||||
$response->assertStatus(200);
|
||||
$arr = $response->json();
|
||||
|
||||
$this->assertEquals($invoice_count + 2, count($arr['data']));
|
||||
|
||||
$cd2->is_deleted = true;
|
||||
$cd2->save();
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->get('/api/v1/invoices?upcoming=true&status=active&without_deleted_clients=true');
|
||||
|
||||
$response->assertStatus(200);
|
||||
$arr = $response->json();
|
||||
|
||||
$this->assertEquals($invoice_count + 1, count($arr['data']));
|
||||
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->get('/api/v1/invoices?upcoming=true&status=active&filter_deleted_clients=true');
|
||||
|
||||
$response->assertStatus(200);
|
||||
$arr = $response->json();
|
||||
|
||||
$this->assertEquals($invoice_count + 1, count($arr['data']));
|
||||
|
||||
|
||||
}
|
||||
|
||||
public function testPaymentMethodsWithCreditsEnforced()
|
||||
{
|
||||
|
||||
@ -51,6 +169,6 @@ class ClientModelTest extends TestCase
|
||||
|
||||
$this->assertGreaterThan(0, CompanyGateway::count());
|
||||
|
||||
$this->assertEquals(1, count($payment_methods));
|
||||
$this->assertEquals(2, count($payment_methods));
|
||||
}
|
||||
}
|
||||
|
@ -189,6 +189,22 @@ class TaskApiTest extends TestCase
|
||||
|
||||
}
|
||||
|
||||
public function testTaskDivisionByZero()
|
||||
{
|
||||
$data = [
|
||||
"rate" => 0,
|
||||
"time_log" => '[[1719350900,1719352700,"",true]]',
|
||||
];
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->postJson("/api/v1/tasks", $data);
|
||||
|
||||
$response->assertStatus(200);
|
||||
|
||||
}
|
||||
|
||||
public function testRequestRuleParsing()
|
||||
{
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user