mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-06-23 20:00:33 -04:00
commit
21785f6395
@ -1 +1 @@
|
||||
5.7.6
|
||||
5.7.7
|
@ -549,7 +549,7 @@ class CheckData extends Command
|
||||
|
||||
private function clientPaidToDateQuery()
|
||||
{
|
||||
$results = \DB::select(\DB::raw("
|
||||
$results = \DB::select("
|
||||
SELECT
|
||||
clients.id as client_id,
|
||||
clients.paid_to_date as client_paid_to_date,
|
||||
@ -564,14 +564,14 @@ class CheckData extends Command
|
||||
GROUP BY clients.id
|
||||
HAVING payments_applied != client_paid_to_date
|
||||
ORDER BY clients.id;
|
||||
")->getValue(DB::connection()->getQueryGrammar()));
|
||||
");
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
private function clientCreditPaymentables($client)
|
||||
{
|
||||
$results = \DB::select(\DB::raw("
|
||||
$results = \DB::select("
|
||||
SELECT
|
||||
SUM(paymentables.amount - paymentables.refunded) as credit_payment
|
||||
FROM payments
|
||||
@ -583,7 +583,7 @@ class CheckData extends Command
|
||||
AND paymentables.amount > 0
|
||||
AND payments.is_deleted = 0
|
||||
AND payments.client_id = ?;
|
||||
")->getValue(DB::connection()->getQueryGrammar()), [App\Models\Credit::class, $client->id]);
|
||||
", [App\Models\Credit::class, $client->id]);
|
||||
|
||||
return $results;
|
||||
}
|
||||
@ -619,110 +619,11 @@ class CheckData extends Command
|
||||
}
|
||||
|
||||
$this->logMessage("{$this->wrong_paid_to_dates} clients with incorrect paid to dates");
|
||||
}
|
||||
|
||||
private function checkPaidToDates()
|
||||
{
|
||||
$this->wrong_paid_to_dates = 0;
|
||||
$credit_total_applied = 0;
|
||||
|
||||
$clients = DB::table('clients')
|
||||
->leftJoin('payments', function ($join) {
|
||||
$join->on('payments.client_id', '=', 'clients.id')
|
||||
->where('payments.is_deleted', 0)
|
||||
->whereIn('payments.status_id', [Payment::STATUS_COMPLETED, Payment::STATUS_PENDING, Payment::STATUS_PARTIALLY_REFUNDED, Payment::STATUS_REFUNDED]);
|
||||
})
|
||||
->where('clients.is_deleted', 0)
|
||||
->where('clients.updated_at', '>', now()->subDays(2))
|
||||
->groupBy('clients.id')
|
||||
->havingRaw('clients.paid_to_date != sum(coalesce(payments.amount - payments.refunded, 0))')
|
||||
->get(['clients.id', 'clients.paid_to_date', DB::raw('sum(coalesce(payments.amount - payments.refunded, 0)) as amount')->getValue(DB::connection()->getQueryGrammar())]);
|
||||
|
||||
/* Due to accounting differences we need to perform a second loop here to ensure there actually is an issue */
|
||||
$clients->each(function ($client_record) use ($credit_total_applied) {
|
||||
$client = Client::withTrashed()->find($client_record->id);
|
||||
|
||||
$total_invoice_payments = 0;
|
||||
|
||||
foreach ($client->invoices()->where('is_deleted', false)->where('status_id', '>', 1)->get() as $invoice) {
|
||||
$total_invoice_payments += $invoice->payments()
|
||||
->where('is_deleted', false)->whereIn('status_id', [Payment::STATUS_COMPLETED, Payment::STATUS_PENDING, Payment::STATUS_PARTIALLY_REFUNDED, Payment::STATUS_REFUNDED])
|
||||
->selectRaw('sum(paymentables.amount - paymentables.refunded) as p')
|
||||
->pluck('p')
|
||||
->first();
|
||||
}
|
||||
|
||||
//commented IN 27/06/2021 - sums ALL client payments AND the unapplied amounts to match the client paid to date
|
||||
$p = Payment::where('client_id', $client->id)
|
||||
->where('is_deleted', 0)
|
||||
->whereIn('status_id', [Payment::STATUS_COMPLETED, Payment::STATUS_PENDING, Payment::STATUS_PARTIALLY_REFUNDED, Payment::STATUS_REFUNDED])
|
||||
// ->sum(DB::Raw('amount - applied')->getValue(DB::connection()->getQueryGrammar()));
|
||||
->selectRaw('SUM(payments.amount - payments.applied) as amount')->first()->amount ?? 0;
|
||||
$total_invoice_payments += $p;
|
||||
|
||||
// 10/02/21
|
||||
foreach ($client->payments as $payment) {
|
||||
$credit_total_applied += $payment->paymentables()
|
||||
->where('paymentable_type', App\Models\Credit::class)
|
||||
->selectRaw('sum(paymentables.amount - paymentables.refunded) as p')
|
||||
->pluck('p')
|
||||
->first();
|
||||
}
|
||||
|
||||
if ($credit_total_applied < 0) {
|
||||
$total_invoice_payments += $credit_total_applied;
|
||||
}
|
||||
|
||||
if (round($total_invoice_payments, 2) != round($client->paid_to_date, 2)) {
|
||||
$this->wrong_paid_to_dates++;
|
||||
|
||||
$this->logMessage($client->present()->name().' id = # '.$client->id." - Paid to date does not match Client Paid To Date = {$client->paid_to_date} - Invoice Payments = {$total_invoice_payments}");
|
||||
|
||||
$this->isValid = false;
|
||||
|
||||
if ($this->option('paid_to_date')) {
|
||||
$this->logMessage("# {$client->id} " . $client->present()->name().' - '.$client->number." Fixing {$client->paid_to_date} to {$total_invoice_payments}");
|
||||
$client->paid_to_date = $total_invoice_payments;
|
||||
$client->save();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$this->logMessage("{$this->wrong_paid_to_dates} clients with incorrect paid to dates");
|
||||
}
|
||||
|
||||
private function checkInvoicePayments()
|
||||
{
|
||||
$this->wrong_balances = 0;
|
||||
|
||||
Client::query()->cursor()->where('is_deleted', 0)->where('clients.updated_at', '>', now()->subDays(2))->each(function ($client) {
|
||||
$client->invoices->where('is_deleted', false)->whereIn('status_id', '!=', Invoice::STATUS_DRAFT)->each(function ($invoice) use ($client) {
|
||||
$total_paid = $invoice->payments()
|
||||
->where('is_deleted', false)->whereIn('status_id', [Payment::STATUS_COMPLETED, Payment::STATUS_PENDING, Payment::STATUS_PARTIALLY_REFUNDED, Payment::STATUS_REFUNDED])
|
||||
->selectRaw('sum(paymentables.amount - paymentables.refunded) as p')
|
||||
->pluck('p')
|
||||
->first();
|
||||
|
||||
$total_credit = $invoice->credits()->get()->sum('amount');
|
||||
|
||||
$calculated_paid_amount = $invoice->amount - $invoice->balance - $total_credit;
|
||||
|
||||
if ((string)$total_paid != (string)($invoice->amount - $invoice->balance - $total_credit)) {
|
||||
$this->wrong_balances++;
|
||||
|
||||
$this->logMessage($client->present()->name().' - '.$client->id." - Total Paid = {$total_paid} != Calculated Total = {$calculated_paid_amount}");
|
||||
|
||||
$this->isValid = false;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$this->logMessage("{$this->wrong_balances} clients with incorrect invoice balances");
|
||||
}
|
||||
}
|
||||
|
||||
private function clientBalanceQuery()
|
||||
{
|
||||
$results = \DB::select(\DB::raw("
|
||||
$results = \DB::select("
|
||||
SELECT
|
||||
SUM(invoices.balance) as invoice_balance,
|
||||
clients.id as client_id,
|
||||
@ -736,7 +637,7 @@ class CheckData extends Command
|
||||
GROUP BY clients.id
|
||||
HAVING invoice_balance != clients.balance
|
||||
ORDER BY clients.id;
|
||||
")->getValue(DB::connection()->getQueryGrammar()));
|
||||
");
|
||||
|
||||
return $results;
|
||||
}
|
||||
@ -813,7 +714,7 @@ class CheckData extends Command
|
||||
|
||||
private function invoiceBalanceQuery()
|
||||
{
|
||||
$results = \DB::select(\DB::raw("
|
||||
$results = \DB::select("
|
||||
SELECT
|
||||
clients.id,
|
||||
clients.balance,
|
||||
@ -827,7 +728,7 @@ class CheckData extends Command
|
||||
GROUP BY clients.id
|
||||
HAVING(invoices_balance != clients.balance)
|
||||
ORDER BY clients.id;
|
||||
")->getValue(DB::connection()->getQueryGrammar()));
|
||||
");
|
||||
|
||||
return $results;
|
||||
}
|
||||
@ -961,7 +862,7 @@ class CheckData extends Command
|
||||
}
|
||||
$records = DB::table($table)
|
||||
->join($tableName, "{$tableName}.id", '=', "{$table}.{$field}_id")
|
||||
->where("{$table}.{$company_id}", '!=', DB::raw("{$tableName}.company_id")->getValue(DB::connection()->getQueryGrammar()))
|
||||
->where("{$table}.{$company_id}", '!=', "{$tableName}.company_id")
|
||||
->get(["{$table}.id"]);
|
||||
|
||||
if ($records->count()) {
|
||||
@ -971,11 +872,6 @@ class CheckData extends Command
|
||||
}
|
||||
}
|
||||
|
||||
// foreach(User::cursor() as $user) {
|
||||
|
||||
// $records = Company::where('account_id',)
|
||||
|
||||
// }
|
||||
}
|
||||
|
||||
public function pluralizeEntityType($type)
|
||||
|
@ -15,7 +15,10 @@ class SchedulerController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
if (auth()->user()->company()->account->latest_version == '0.0.0') {
|
||||
/** @var \App\Models\User $user */
|
||||
$user = auth()->user();
|
||||
|
||||
if ($user->company()->account->latest_version == '0.0.0') {
|
||||
return response()->json(['message' => ctrans('texts.scheduler_has_never_run')], 400);
|
||||
} else {
|
||||
return response()->json(['message' => ctrans('texts.scheduler_has_run')], 200);
|
||||
|
190
app/Http/Controllers/SearchController.php
Normal file
190
app/Http/Controllers/SearchController.php
Normal file
@ -0,0 +1,190 @@
|
||||
<?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\Controllers;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Models\Client;
|
||||
use App\Models\ClientContact;
|
||||
use App\Http\Requests\Search\GenericSearchRequest;
|
||||
use App\Models\Invoice;
|
||||
|
||||
class SearchController extends Controller
|
||||
{
|
||||
public function __invoke(GenericSearchRequest $request)
|
||||
{
|
||||
/** @var \App\Models\User $user */
|
||||
$user = auth()->user();
|
||||
|
||||
return response()->json([
|
||||
'clients' => $this->clientMap($user),
|
||||
'client_contacts' => $this->clientContactMap($user),
|
||||
'invoices' => $this->invoiceMap($user),
|
||||
'settings' => $this->settingsMap(),
|
||||
], 200);
|
||||
|
||||
}
|
||||
|
||||
private function clientMap(User $user) {
|
||||
|
||||
return Client::query()
|
||||
->company()
|
||||
->when($user->cannot('view_all') || $user->cannot('view_client'), function ($query) use($user) {
|
||||
$query->where('user_id', $user->id);
|
||||
})
|
||||
->cursor()
|
||||
->map(function ($client){
|
||||
return [
|
||||
'name' => $client->present()->name(),
|
||||
'type' => '/client',
|
||||
'id' => $client->hashed_id,
|
||||
'path' => "/clients/{$client->hashed_id}/edit"
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
private function clientContactMap(User $user) {
|
||||
|
||||
return ClientContact::query()
|
||||
->company()
|
||||
->with('client')
|
||||
->when($user->cannot('view_all') || $user->cannot('view_client'), function ($query) use($user) {
|
||||
$query->where('user_id', $user->id);
|
||||
})
|
||||
->cursor()
|
||||
->map(function ($contact){
|
||||
return [
|
||||
'name' => $contact->present()->search_display(),
|
||||
'type' => '/client_contact',
|
||||
'id' => $contact->client->hashed_id,
|
||||
'path' => "/clients/{$contact->client->hashed_id}"
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
private function invoiceMap(User $user) {
|
||||
|
||||
return Invoice::query()
|
||||
->company()
|
||||
->with('client')
|
||||
->when($user->cannot('view_all') || $user->cannot('view_invoice'), function ($query) use($user) {
|
||||
$query->where('user_id', $user->id);
|
||||
})
|
||||
->cursor()
|
||||
->map(function ($invoice){
|
||||
return [
|
||||
'name' => $invoice->client->present()->name() . ' - ' . $invoice->number,
|
||||
'type' => '/invoice',
|
||||
'id' => $invoice->hashed_id,
|
||||
'path' => "/clients/{$invoice->hashed_id}/edit"
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
private function settingsMap() {
|
||||
|
||||
$paths = [
|
||||
'user_details' => '/settings/user_details',
|
||||
'password' => '/settings/user_details/password',
|
||||
'connect' => '/settings/user_details/connect',
|
||||
'accent_color' => '/settings/user_details/accent_color',
|
||||
'notifications' => '/settings/user_details/notifications',
|
||||
'enable_two_factor' => '/settings/user_details/enable_two_factor',
|
||||
'custom_fields' => '/settings/user_details/custom_fields',
|
||||
'preferences' => '/settings/user_details/preferences',
|
||||
'company_details' => '/settings/company_details',
|
||||
'company_details,details' => '/settings/company_details/details',
|
||||
'company_details,address' => '/settings/company_details/address',
|
||||
'company_details,logo' => '/settings/company_details/logo',
|
||||
'company_details,defaults' => '/settings/company_details/defaults',
|
||||
'company_details,documents' => '/settings/company_details/documents',
|
||||
'company_details,custom_fields' => '/settings/company_details/custom_fields',
|
||||
'localization' => '/settings/localization',
|
||||
'localization,custom_labels' => '/settings/localization/custom_labels',
|
||||
'online_payments' => '/settings/online_payments',
|
||||
'tax_settings' => '/settings/tax_settings',
|
||||
'product_settings' => '/settings/product_settings',
|
||||
'task_settings' => '/settings/task_settings',
|
||||
'expense_settings' => '/settings/expense_settings',
|
||||
'workflow_settings' => '/settings/workflow_settings',
|
||||
'import_export' => '/settings/import_export',
|
||||
'account_management' => '/settings/account_management',
|
||||
'account_management,overview' => '/settings/account_management/overview',
|
||||
'account_management,enabled_modules' => '/settings/account_management/enabled_modules',
|
||||
'account_management,integrations' => '/settings/account_management/integrations',
|
||||
'account_management,security_settings' => '/settings/account_management/security_settings',
|
||||
'account_management,danger_zone' => '/settings/account_management/danger_zone',
|
||||
'backup_restore' => '/settings/backup_restore',
|
||||
'backup_restore,restore' => '/settings/backup_restore/restore',
|
||||
'backup_restore,backup' => '/settings/backup_restore/backup',
|
||||
'custom_fields' => '/settings/custom_fields',
|
||||
'custom_fields,company' => '/settings/custom_fields/company',
|
||||
'custom_fields,clients' => '/settings/custom_fields/clients',
|
||||
'custom_fields,products' => '/settings/custom_fields/products',
|
||||
'custom_fields,invoices' => '/settings/custom_fields/invoices',
|
||||
'custom_fields,payments' => '/settings/custom_fields/payments',
|
||||
'custom_fields,projects' => '/settings/custom_fields/projects',
|
||||
'custom_fields,tasks' => '/settings/custom_fields/tasks',
|
||||
'custom_fields,vendors' => '/settings/custom_fields/vendors',
|
||||
'custom_fields,expenses' => '/settings/custom_fields/expenses',
|
||||
'custom_fields,users' => '/settings/custom_fields/users',
|
||||
'custom_fields,quotes' => '/settings/custom_fields/quotes',
|
||||
'custom_fields,credits' => '/settings/custom_fields/credits',
|
||||
'generated_numbers' => '/settings/generated_numbers',
|
||||
'client_portal' => '/settings/client_portal',
|
||||
'email_settings' => '/settings/email_settings',
|
||||
'templates_and_reminders' => '/settings/templates_and_reminders',
|
||||
'bank_accounts' => '/settings/bank_accounts',
|
||||
'group_settings' => '/settings/group_settings',
|
||||
'subscriptions' => '/settings/subscriptions',
|
||||
'schedules' => '/settings/schedules',
|
||||
'users' => '/settings/users',
|
||||
'system_logs' => '/settings/system_logs',
|
||||
'payment_terms' => '/settings/payment_terms',
|
||||
'tax_rates' => '/settings/tax_rates',
|
||||
'task_statuses' => '/settings/task_statuses',
|
||||
'expense_categories' => '/settings/expense_categories',
|
||||
'integrations' => '/settings/integrations',
|
||||
'integrations,api_tokens' => '/settings/integrations/api_tokens',
|
||||
'integrations,api_webhooks' => '/settings/integrations/api_webhooks',
|
||||
'integrations,analytics' => '/settings/integrations/analytics',
|
||||
'gateways' => '/settings/gateways',
|
||||
'gateways,create' => '/settings/gateways/create',
|
||||
'bank_accounts,transaction_rules' => '/settings/bank_accounts/transaction_rules',
|
||||
'bank_accounts,transaction_rules/create' => '/settings/bank_accounts/transaction_rules/create',
|
||||
];
|
||||
|
||||
$data = [];
|
||||
|
||||
foreach($paths as $key => $value) {
|
||||
|
||||
$translation = '';
|
||||
|
||||
foreach(explode(",", $key) as $transkey) {
|
||||
$translation .= ctrans("texts.{$transkey}")." ";
|
||||
}
|
||||
|
||||
$translation = rtrim($translation, " ");
|
||||
|
||||
$data[] = [
|
||||
'id' => $translation,
|
||||
'path' => $value,
|
||||
'type' => $transkey,
|
||||
'name' => $translation,
|
||||
];
|
||||
}
|
||||
|
||||
ksort($data);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
}
|
@ -31,8 +31,11 @@ class BulkClientRequest extends Request
|
||||
|
||||
public function rules()
|
||||
{
|
||||
/** @var \App\Models\User $user */
|
||||
$user = auth()->user();
|
||||
|
||||
return [
|
||||
'ids' => ['required','bail','array',Rule::exists('clients', 'id')->where('company_id', auth()->user()->company()->id)],
|
||||
'ids' => ['required','bail','array',Rule::exists('clients', 'id')->where('company_id', $user->company()->id)],
|
||||
'action' => 'in:archive,restore,delete'
|
||||
];
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ class Request extends FormRequest
|
||||
use MakesHash;
|
||||
use RuntimeFormRequest;
|
||||
|
||||
protected $file_validation = 'sometimes|file|mimes:png,ai,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx,webp,xml,zip|max:100000';
|
||||
protected $file_validation = 'sometimes|file|mimes:png,ai,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx,webp,xml,zip,csv|max:100000';
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
|
43
app/Http/Requests/Search/GenericSearchRequest.php
Normal file
43
app/Http/Requests/Search/GenericSearchRequest.php
Normal file
@ -0,0 +1,43 @@
|
||||
<?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\Search;
|
||||
|
||||
use App\Http\Requests\Request;
|
||||
|
||||
class GenericSearchRequest extends Request
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize() : bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function rules()
|
||||
{
|
||||
$rules = [
|
||||
'search' => 'bail|sometimes|string'
|
||||
];
|
||||
|
||||
return $rules;
|
||||
}
|
||||
|
||||
public function prepareForValidation()
|
||||
{
|
||||
$input = $this->all();
|
||||
|
||||
$this->replace($input);
|
||||
}
|
||||
}
|
@ -746,12 +746,7 @@ class BaseImport
|
||||
if($user)
|
||||
return $user->id;
|
||||
|
||||
$user = User::where('account_id', $this->company->account->id)
|
||||
->where(
|
||||
\DB::raw('CONCAT_WS(" ", first_name, last_name)')->getValue(\DB::connection()->getQueryGrammar()),
|
||||
'like',
|
||||
'%'.$user_hash.'%'
|
||||
)
|
||||
$user = User::whereRaw("account_id = ? AND CONCAT_WS(' ', first_name, last_name) like ?", [$this->company->account_id, '%'.$user_hash.'%'])
|
||||
->first();
|
||||
|
||||
if ($user) {
|
||||
|
@ -248,19 +248,6 @@ class CheckCompanyData implements ShouldQueue
|
||||
$this->is_valid = false;
|
||||
}
|
||||
|
||||
// if ($this->option('fix') == 'true') {
|
||||
// foreach ($clients as $client) {
|
||||
// $contact = new ClientContact();
|
||||
// $contact->company_id = $client->company_id;
|
||||
// $contact->user_id = $client->user_id;
|
||||
// $contact->client_id = $client->id;
|
||||
// $contact->is_primary = true;
|
||||
// $contact->send_invoice = true;
|
||||
// $contact->contact_key = str_random(config('ninja.key_length'));
|
||||
// $contact->save();
|
||||
// }
|
||||
// }
|
||||
|
||||
// check for more than one primary contact
|
||||
$clients = DB::table('clients')
|
||||
->where('clients.company_id', $this->company->id)
|
||||
@ -272,11 +259,7 @@ class CheckCompanyData implements ShouldQueue
|
||||
->groupBy('clients.id')
|
||||
->havingRaw('count(client_contacts.id) != 1');
|
||||
|
||||
// if ($this->option('client_id')) {
|
||||
// $clients->where('clients.id', '=', $this->option('client_id'));
|
||||
// }
|
||||
|
||||
$clients = $clients->get(['clients.id', DB::raw('count(client_contacts.id)')->getValue(DB::connection()->getQueryGrammar())]);
|
||||
$clients = $clients->get(['clients.id', DB::raw('count(client_contacts.id)')]);
|
||||
$this->company_data[] = $clients->count().' clients without a single primary contact';
|
||||
|
||||
if ($clients->count() > 0) {
|
||||
@ -315,7 +298,7 @@ class CheckCompanyData implements ShouldQueue
|
||||
}
|
||||
$records = DB::table($table)
|
||||
->join($tableName, "{$tableName}.id", '=', "{$table}.{$field}_id")
|
||||
->where("{$table}.{$company_id}", '!=', DB::raw("{$tableName}.company_id")->getValue(DB::connection()->getQueryGrammar()))
|
||||
->where("{$table}.{$company_id}", '!=', "{$tableName}.company_id")
|
||||
->get(["{$table}.id"]);
|
||||
|
||||
if ($records->count()) {
|
||||
|
@ -302,7 +302,7 @@ class Import implements ShouldQueue
|
||||
|
||||
// 10/02/21
|
||||
foreach ($client->payments as $payment) {
|
||||
$credit_total_applied += $payment->paymentables()->where('paymentable_type', \App\Models\Credit::class)->get()->sum(\DB::raw('amount')->getValue(DB::connection()->getQueryGrammar()));
|
||||
$credit_total_applied += $payment->paymentables()->where('paymentable_type', \App\Models\Credit::class)->get()->sum('amount');
|
||||
}
|
||||
|
||||
if ($credit_total_applied < 0) {
|
||||
|
@ -32,11 +32,16 @@ class ClientContactPresenter extends EntityPresenter
|
||||
|
||||
public function first_name()
|
||||
{
|
||||
return $this->entity->first_name ?: '';
|
||||
return $this->entity->first_name ?? '';
|
||||
}
|
||||
|
||||
public function last_name()
|
||||
{
|
||||
return $this->entity->last_name ?: '';
|
||||
return $this->entity->last_name ?? '';
|
||||
}
|
||||
|
||||
public function search_display()
|
||||
{
|
||||
return $this->name().' <'.$this->entity->email.'>' ?? '';
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ trait ChartQueries
|
||||
{
|
||||
$user_filter = $this->is_admin ? '' : 'AND expenses.user_id = '.$this->user->id;
|
||||
|
||||
return DB::select(DB::raw("
|
||||
return DB::select("
|
||||
SELECT sum(expenses.amount) as amount,
|
||||
IFNULL(expenses.currency_id, :company_currency) as currency_id
|
||||
FROM expenses
|
||||
@ -34,7 +34,7 @@ trait ChartQueries
|
||||
AND (expenses.date BETWEEN :start_date AND :end_date)
|
||||
{$user_filter}
|
||||
GROUP BY currency_id
|
||||
")->getValue(DB::connection()->getQueryGrammar()), ['company_currency' => $this->company->settings->currency_id, 'company_id' => $this->company->id, 'start_date' => $start_date, 'end_date' => $end_date]);
|
||||
", ['company_currency' => $this->company->settings->currency_id, 'company_id' => $this->company->id, 'start_date' => $start_date, 'end_date' => $end_date]);
|
||||
}
|
||||
|
||||
public function getExpenseChartQuery($start_date, $end_date, $currency_id)
|
||||
@ -42,7 +42,7 @@ trait ChartQueries
|
||||
|
||||
$user_filter = $this->is_admin ? '' : 'AND expenses.user_id = '.$this->user->id;
|
||||
|
||||
return DB::select(DB::raw("
|
||||
return DB::select("
|
||||
SELECT
|
||||
sum(expenses.amount) as total,
|
||||
expenses.date,
|
||||
@ -54,7 +54,7 @@ trait ChartQueries
|
||||
{$user_filter}
|
||||
GROUP BY expenses.date
|
||||
HAVING currency_id = :currency_id
|
||||
")->getValue(DB::connection()->getQueryGrammar()), [
|
||||
", [
|
||||
'company_currency' => $this->company->settings->currency_id,
|
||||
'currency_id' => $currency_id,
|
||||
'company_id' => $this->company->id,
|
||||
@ -71,7 +71,7 @@ trait ChartQueries
|
||||
|
||||
$user_filter = $this->is_admin ? '' : 'AND payments.user_id = '.$this->user->id;
|
||||
|
||||
return DB::select(DB::raw("
|
||||
return DB::select("
|
||||
SELECT sum(payments.amount) as amount,
|
||||
IFNULL(payments.currency_id, :company_currency) as currency_id
|
||||
FROM payments
|
||||
@ -80,7 +80,7 @@ trait ChartQueries
|
||||
AND payments.company_id = :company_id
|
||||
AND (payments.date BETWEEN :start_date AND :end_date)
|
||||
GROUP BY currency_id
|
||||
")->getValue(DB::connection()->getQueryGrammar()), [
|
||||
", [
|
||||
'company_currency' => $this->company->settings->currency_id,
|
||||
'company_id' => $this->company->id,
|
||||
'start_date' => $start_date,
|
||||
@ -93,7 +93,7 @@ trait ChartQueries
|
||||
|
||||
$user_filter = $this->is_admin ? '' : 'AND payments.user_id = '.$this->user->id;
|
||||
|
||||
return DB::select(DB::raw("
|
||||
return DB::select("
|
||||
SELECT
|
||||
sum(payments.amount - payments.refunded) as total,
|
||||
payments.date,
|
||||
@ -106,7 +106,7 @@ trait ChartQueries
|
||||
AND (payments.date BETWEEN :start_date AND :end_date)
|
||||
GROUP BY payments.date
|
||||
HAVING currency_id = :currency_id
|
||||
")->getValue(DB::connection()->getQueryGrammar()), [
|
||||
", [
|
||||
'company_currency' => $this->company->settings->currency_id,
|
||||
'currency_id' => $currency_id,
|
||||
'company_id' => $this->company->id,
|
||||
@ -123,7 +123,7 @@ trait ChartQueries
|
||||
|
||||
$user_filter = $this->is_admin ? '' : 'AND clients.user_id = '.$this->user->id;
|
||||
|
||||
return DB::select(DB::raw("
|
||||
return DB::select("
|
||||
SELECT
|
||||
sum(invoices.balance) as amount,
|
||||
COUNT(*) as outstanding_count,
|
||||
@ -139,14 +139,14 @@ trait ChartQueries
|
||||
AND invoices.balance > 0
|
||||
AND (invoices.date BETWEEN :start_date AND :end_date)
|
||||
GROUP BY currency_id
|
||||
")->getValue(DB::connection()->getQueryGrammar()), ['company_currency' => $this->company->settings->currency_id, 'company_id' => $this->company->id, 'start_date' => $start_date, 'end_date' => $end_date]);
|
||||
", ['company_currency' => $this->company->settings->currency_id, 'company_id' => $this->company->id, 'start_date' => $start_date, 'end_date' => $end_date]);
|
||||
}
|
||||
|
||||
public function getRevenueQueryX($start_date, $end_date)
|
||||
{
|
||||
$user_filter = $this->is_admin ? '' : 'AND clients.user_id = '.$this->user->id;
|
||||
|
||||
return DB::select(DB::raw("
|
||||
return DB::select("
|
||||
SELECT
|
||||
sum(invoices.paid_to_date) as paid_to_date,
|
||||
IFNULL(CAST(JSON_UNQUOTE(JSON_EXTRACT( clients.settings, '$.currency_id' )) AS SIGNED), :company_currency) AS currency_id
|
||||
@ -161,14 +161,14 @@ trait ChartQueries
|
||||
AND invoices.status_id IN (3,4)
|
||||
AND (invoices.date BETWEEN :start_date AND :end_date)
|
||||
GROUP BY currency_id
|
||||
")->getValue(DB::connection()->getQueryGrammar()), ['company_currency' => $this->company->settings->currency_id, 'company_id' => $this->company->id, 'start_date' => $start_date, 'end_date' => $end_date]);
|
||||
", ['company_currency' => $this->company->settings->currency_id, 'company_id' => $this->company->id, 'start_date' => $start_date, 'end_date' => $end_date]);
|
||||
}
|
||||
|
||||
public function getRevenueQuery($start_date, $end_date)
|
||||
{
|
||||
$user_filter = $this->is_admin ? '' : 'AND payments.user_id = '.$this->user->id;
|
||||
|
||||
return DB::select(DB::raw("
|
||||
return DB::select("
|
||||
SELECT
|
||||
sum(payments.amount - payments.refunded) as paid_to_date,
|
||||
payments.currency_id AS currency_id
|
||||
@ -179,14 +179,14 @@ trait ChartQueries
|
||||
AND payments.status_id IN (1,4,5,6)
|
||||
AND (payments.date BETWEEN :start_date AND :end_date)
|
||||
GROUP BY payments.currency_id
|
||||
")->getValue(DB::connection()->getQueryGrammar()), ['company_id' => $this->company->id, 'start_date' => $start_date, 'end_date' => $end_date]);
|
||||
", ['company_id' => $this->company->id, 'start_date' => $start_date, 'end_date' => $end_date]);
|
||||
}
|
||||
|
||||
public function getInvoicesQuery($start_date, $end_date)
|
||||
{
|
||||
$user_filter = $this->is_admin ? '' : 'AND clients.user_id = '.$this->user->id;
|
||||
|
||||
return DB::select(DB::raw("
|
||||
return DB::select("
|
||||
SELECT
|
||||
sum(invoices.amount) as invoiced_amount,
|
||||
IFNULL(CAST(JSON_UNQUOTE(JSON_EXTRACT( clients.settings, '$.currency_id' )) AS SIGNED), :company_currency) AS currency_id
|
||||
@ -201,14 +201,14 @@ trait ChartQueries
|
||||
AND invoices.is_deleted = 0
|
||||
AND (invoices.date BETWEEN :start_date AND :end_date)
|
||||
GROUP BY currency_id
|
||||
")->getValue(DB::connection()->getQueryGrammar()), ['company_currency' => $this->company->settings->currency_id, 'company_id' => $this->company->id, 'start_date' => $start_date, 'end_date' => $end_date]);
|
||||
", ['company_currency' => $this->company->settings->currency_id, 'company_id' => $this->company->id, 'start_date' => $start_date, 'end_date' => $end_date]);
|
||||
}
|
||||
|
||||
public function getOutstandingChartQuery($start_date, $end_date, $currency_id)
|
||||
{
|
||||
$user_filter = $this->is_admin ? '' : 'AND clients.user_id = '.$this->user->id;
|
||||
|
||||
return DB::select(DB::raw("
|
||||
return DB::select("
|
||||
SELECT
|
||||
sum(invoices.balance) as total,
|
||||
invoices.date,
|
||||
@ -224,7 +224,7 @@ trait ChartQueries
|
||||
AND (invoices.date BETWEEN :start_date AND :end_date)
|
||||
GROUP BY invoices.date
|
||||
HAVING currency_id = :currency_id
|
||||
")->getValue(DB::connection()->getQueryGrammar()), [
|
||||
", [
|
||||
'company_currency' => (int) $this->company->settings->currency_id,
|
||||
'currency_id' => $currency_id,
|
||||
'company_id' => $this->company->id,
|
||||
@ -238,7 +238,7 @@ trait ChartQueries
|
||||
{
|
||||
$user_filter = $this->is_admin ? '' : 'AND clients.user_id = '.$this->user->id;
|
||||
|
||||
return DB::select(DB::raw("
|
||||
return DB::select("
|
||||
SELECT
|
||||
sum(invoices.amount) as total,
|
||||
invoices.date,
|
||||
@ -254,7 +254,7 @@ trait ChartQueries
|
||||
AND (invoices.date BETWEEN :start_date AND :end_date)
|
||||
GROUP BY invoices.date
|
||||
HAVING currency_id = :currency_id
|
||||
")->getValue(DB::connection()->getQueryGrammar()), [
|
||||
", [
|
||||
'company_currency' => (int) $this->company->settings->currency_id,
|
||||
'currency_id' => $currency_id,
|
||||
'company_id' => $this->company->id,
|
||||
|
@ -24,7 +24,7 @@ trait ChartQueriesLegacy
|
||||
public function getExpenseQuery($start_date, $end_date)
|
||||
{
|
||||
|
||||
return DB::select(DB::raw('
|
||||
return DB::select('
|
||||
SELECT sum(expenses.amount) as amount,
|
||||
IFNULL(expenses.currency_id, :company_currency) as currency_id
|
||||
FROM expenses
|
||||
@ -32,12 +32,12 @@ trait ChartQueriesLegacy
|
||||
AND expenses.company_id = :company_id
|
||||
AND (expenses.date BETWEEN :start_date AND :end_date)
|
||||
GROUP BY currency_id
|
||||
')->getValue(DB::connection()->getQueryGrammar()), ['company_currency' => $this->company->settings->currency_id, 'company_id' => $this->company->id, 'start_date' => $start_date, 'end_date' => $end_date]);
|
||||
', ['company_currency' => $this->company->settings->currency_id, 'company_id' => $this->company->id, 'start_date' => $start_date, 'end_date' => $end_date]);
|
||||
}
|
||||
|
||||
public function getExpenseChartQuery($start_date, $end_date, $currency_id)
|
||||
{
|
||||
return DB::select(DB::raw('
|
||||
return DB::select('
|
||||
SELECT
|
||||
sum(expenses.amount) as total,
|
||||
expenses.date,
|
||||
@ -48,7 +48,7 @@ trait ChartQueriesLegacy
|
||||
AND expenses.is_deleted = 0
|
||||
GROUP BY expenses.date
|
||||
HAVING currency_id = :currency_id
|
||||
')->getValue(DB::connection()->getQueryGrammar()), [
|
||||
', [
|
||||
'company_currency' => $this->company->settings->currency_id,
|
||||
'currency_id' => $currency_id,
|
||||
'company_id' => $this->company->id,
|
||||
@ -62,7 +62,7 @@ trait ChartQueriesLegacy
|
||||
*/
|
||||
public function getPaymentQuery($start_date, $end_date)
|
||||
{
|
||||
return DB::select(DB::raw('
|
||||
return DB::select('
|
||||
SELECT sum(payments.amount) as amount,
|
||||
IFNULL(payments.currency_id, :company_currency) as currency_id
|
||||
FROM payments
|
||||
@ -70,7 +70,7 @@ trait ChartQueriesLegacy
|
||||
AND payments.company_id = :company_id
|
||||
AND (payments.date BETWEEN :start_date AND :end_date)
|
||||
GROUP BY currency_id
|
||||
')->getValue(DB::connection()->getQueryGrammar()), [
|
||||
', [
|
||||
'company_currency' => $this->company->settings->currency_id,
|
||||
'company_id' => $this->company->id,
|
||||
'start_date' => $start_date,
|
||||
@ -80,7 +80,7 @@ trait ChartQueriesLegacy
|
||||
|
||||
public function getPaymentChartQuery($start_date, $end_date, $currency_id)
|
||||
{
|
||||
return DB::select(DB::raw('
|
||||
return DB::select('
|
||||
SELECT
|
||||
sum(payments.amount - payments.refunded) as total,
|
||||
payments.date,
|
||||
@ -92,7 +92,7 @@ trait ChartQueriesLegacy
|
||||
AND payments.is_deleted = 0
|
||||
GROUP BY payments.date
|
||||
HAVING currency_id = :currency_id
|
||||
')->getValue(DB::connection()->getQueryGrammar()), [
|
||||
', [
|
||||
'company_currency' => $this->company->settings->currency_id,
|
||||
'currency_id' => $currency_id,
|
||||
'company_id' => $this->company->id,
|
||||
@ -106,7 +106,7 @@ trait ChartQueriesLegacy
|
||||
*/
|
||||
public function getOutstandingQuery($start_date, $end_date)
|
||||
{
|
||||
return DB::select(DB::raw("
|
||||
return DB::select("
|
||||
SELECT
|
||||
sum(invoices.balance) as amount,
|
||||
IFNULL(JSON_EXTRACT( settings, '$.currency_id' ), :company_currency) AS currency_id
|
||||
@ -120,12 +120,12 @@ trait ChartQueriesLegacy
|
||||
AND invoices.is_deleted = 0
|
||||
AND (invoices.date BETWEEN :start_date AND :end_date)
|
||||
GROUP BY currency_id
|
||||
")->getValue(DB::connection()->getQueryGrammar()), ['company_currency' => $this->company->settings->currency_id, 'company_id' => $this->company->id, 'start_date' => $start_date, 'end_date' => $end_date]);
|
||||
", ['company_currency' => $this->company->settings->currency_id, 'company_id' => $this->company->id, 'start_date' => $start_date, 'end_date' => $end_date]);
|
||||
}
|
||||
|
||||
public function getRevenueQuery($start_date, $end_date)
|
||||
{
|
||||
return DB::select(DB::raw("
|
||||
return DB::select("
|
||||
SELECT
|
||||
sum(invoices.paid_to_date) as paid_to_date,
|
||||
IFNULL(JSON_EXTRACT( settings, '$.currency_id' ), :company_currency) AS currency_id
|
||||
@ -139,12 +139,12 @@ trait ChartQueriesLegacy
|
||||
AND invoices.is_deleted = 0
|
||||
AND (invoices.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' => $start_date, 'end_date' => $end_date]);
|
||||
", ['company_currency' => $this->company->settings->currency_id, 'company_id' => $this->company->id, 'start_date' => $start_date, 'end_date' => $end_date]);
|
||||
}
|
||||
|
||||
public function getInvoiceChartQuery($start_date, $end_date, $currency_id)
|
||||
{
|
||||
return DB::select(DB::raw("
|
||||
return DB::select("
|
||||
SELECT
|
||||
sum(invoices.amount) as total,
|
||||
invoices.date,
|
||||
@ -159,7 +159,7 @@ trait ChartQueriesLegacy
|
||||
AND invoices.is_deleted = 0
|
||||
GROUP BY invoices.date
|
||||
HAVING currency_id = :currency_id
|
||||
")->getValue(DB::connection()->getQueryGrammar()), [
|
||||
", [
|
||||
'company_currency' => (int) $this->company->settings->currency_id,
|
||||
'currency_id' => $currency_id,
|
||||
'company_id' => $this->company->id,
|
||||
|
@ -15,6 +15,7 @@ use App\Models\Client;
|
||||
use App\Models\Company;
|
||||
use App\Models\Expense;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use App\Services\Chart\ChartQueriesLegacy;
|
||||
|
||||
class ChartServiceLegacy
|
||||
{
|
||||
|
@ -82,7 +82,6 @@ class ClientService
|
||||
->where('is_deleted', 0)
|
||||
->whereIn('status_id', [Payment::STATUS_COMPLETED, Payment::STATUS_PENDING, Payment::STATUS_PARTIALLY_REFUNDED, Payment::STATUS_REFUNDED])
|
||||
->selectRaw('SUM(payments.amount - payments.applied) as amount')->first()->amount ?? 0;
|
||||
// ->sum(DB::Raw('amount - applied')->getValue(DB::connection()->getQueryGrammar()));
|
||||
|
||||
DB::connection(config('database.default'))->transaction(function () use ($amount) {
|
||||
$this->client = Client::withTrashed()->where('id', $this->client->id)->lockForUpdate()->first();
|
||||
|
@ -96,17 +96,17 @@ class HandleRestore extends AbstractService
|
||||
$this->adjustment_amount += $payment->paymentables
|
||||
->where('paymentable_type', '=', 'invoices')
|
||||
->where('paymentable_id', $this->invoice->id)
|
||||
->sum(DB::raw('amount')->getValue(DB::connection()->getQueryGrammar()));
|
||||
|
||||
->sum('amount');
|
||||
$this->adjustment_amount += $payment->paymentables
|
||||
->where('paymentable_type', '=', 'invoices')
|
||||
->where('paymentable_id', $this->invoice->id)
|
||||
->sum(DB::raw('refunded')->getValue(DB::connection()->getQueryGrammar()));
|
||||
->sum('amount');
|
||||
|
||||
//14/07/2023 - do not include credits in the payment amount
|
||||
$this->adjustment_amount -= $payment->paymentables
|
||||
->where('paymentable_type', '=', 'App\Models\Credit')
|
||||
->sum(DB::raw('amount')->getValue(DB::connection()->getQueryGrammar()));
|
||||
->sum('amount');
|
||||
|
||||
}
|
||||
|
||||
@ -129,16 +129,16 @@ class HandleRestore extends AbstractService
|
||||
$payment_adjustment = $payment->paymentables
|
||||
->where('paymentable_type', '=', 'invoices')
|
||||
->where('paymentable_id', $this->invoice->id)
|
||||
->sum(DB::raw('amount')->getValue(DB::connection()->getQueryGrammar()));
|
||||
->sum('amount');
|
||||
|
||||
$payment_adjustment -= $payment->paymentables
|
||||
->where('paymentable_type', '=', 'invoices')
|
||||
->where('paymentable_id', $this->invoice->id)
|
||||
->sum(DB::raw('refunded')->getValue(DB::connection()->getQueryGrammar()));
|
||||
->sum('refunded');
|
||||
|
||||
$payment_adjustment -= $payment->paymentables
|
||||
->where('paymentable_type', '=', 'App\Models\Credit')
|
||||
->sum(DB::raw('amount')->getValue(DB::connection()->getQueryGrammar()));
|
||||
->sum('amount');
|
||||
|
||||
$payment->amount += $payment_adjustment;
|
||||
$payment->applied += $payment_adjustment;
|
||||
|
@ -88,17 +88,17 @@ class MarkInvoiceDeleted extends AbstractService
|
||||
$payment_adjustment = $payment->paymentables
|
||||
->where('paymentable_type', '=', 'invoices')
|
||||
->where('paymentable_id', $this->invoice->id)
|
||||
->sum(DB::raw('amount')->getValue(DB::connection()->getQueryGrammar()));
|
||||
->sum('amount');
|
||||
|
||||
$payment_adjustment -= $payment->paymentables
|
||||
->where('paymentable_type', '=', 'invoices')
|
||||
->where('paymentable_id', $this->invoice->id)
|
||||
->sum(DB::raw('refunded')->getValue(DB::connection()->getQueryGrammar()));
|
||||
->sum('refunded');
|
||||
|
||||
//14-07-2023 - Do not include credits in the payment adjustment.
|
||||
$payment_adjustment -= $payment->paymentables
|
||||
->where('paymentable_type', '=', 'App\Models\Credit')
|
||||
->sum(DB::raw('amount')->getValue(DB::connection()->getQueryGrammar()));
|
||||
->sum('amount');
|
||||
|
||||
$payment->amount -= $payment_adjustment;
|
||||
$payment->applied -= $payment_adjustment;
|
||||
@ -121,12 +121,12 @@ class MarkInvoiceDeleted extends AbstractService
|
||||
$this->adjustment_amount += $payment->paymentables
|
||||
->where('paymentable_type', '=', 'invoices')
|
||||
->where('paymentable_id', $this->invoice->id)
|
||||
->sum(DB::raw('amount')->getValue(DB::connection()->getQueryGrammar()));
|
||||
->sum('amount');
|
||||
|
||||
$this->adjustment_amount -= $payment->paymentables
|
||||
->where('paymentable_type', '=', 'invoices')
|
||||
->where('paymentable_id', $this->invoice->id)
|
||||
->sum(DB::raw('refunded')->getValue(DB::connection()->getQueryGrammar()));
|
||||
->sum('refunded');
|
||||
}
|
||||
|
||||
$this->total_payments = $this->invoice->payments->sum('amount') - $this->invoice->payments->sum('refunded');
|
||||
|
@ -178,17 +178,6 @@ class ProfitLoss
|
||||
$this->credit_taxes += $map->tax_amount_credit_converted;
|
||||
}
|
||||
|
||||
// $invoices = $this->invoicePaymentIncome();
|
||||
|
||||
// $this->income = 0;
|
||||
// $this->income_taxes = 0;
|
||||
// $this->income_map = $invoices;
|
||||
|
||||
// foreach($invoices as $invoice){
|
||||
// $this->income += $invoice->net_converted_amount;
|
||||
// $this->income_taxes += $invoice->net_converted_taxes;
|
||||
// }
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@ -232,7 +221,7 @@ class ProfitLoss
|
||||
*/
|
||||
private function invoiceIncome()
|
||||
{
|
||||
return \DB::select(\DB::raw("
|
||||
return \DB::select("
|
||||
SELECT
|
||||
sum(invoices.amount) as amount,
|
||||
sum(invoices.total_taxes) as total_taxes,
|
||||
@ -250,7 +239,7 @@ class ProfitLoss
|
||||
AND invoices.is_deleted = 0
|
||||
AND (invoices.date BETWEEN :start_date AND :end_date)
|
||||
GROUP BY currency_id
|
||||
")->getValue(\DB::connection()->getQueryGrammar()), ['company_currency' => $this->company->settings->currency_id, 'company_id' => $this->company->id, 'start_date' => $this->start_date, 'end_date' => $this->end_date]);
|
||||
", ['company_currency' => $this->company->settings->currency_id, 'company_id' => $this->company->id, 'start_date' => $this->start_date, 'end_date' => $this->end_date]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -402,28 +391,6 @@ class ProfitLoss
|
||||
return $csv->toString();
|
||||
}
|
||||
|
||||
private function invoicePaymentIncome()
|
||||
{
|
||||
return \DB::select(\DB::raw("
|
||||
SELECT
|
||||
sum(invoices.amount - invoices.balance) as amount,
|
||||
sum(invoices.total_taxes) * ((sum(invoices.amount - invoices.balance)/invoices.amount)) as total_taxes,
|
||||
(sum(invoices.amount - invoices.balance) / IFNULL(invoices.exchange_rate, 1)) AS net_converted_amount,
|
||||
(sum(invoices.total_taxes) * ((sum(invoices.amount - invoices.balance)/invoices.amount)) / IFNULL(invoices.exchange_rate, 1)) AS net_converted_taxes,
|
||||
IFNULL(JSON_EXTRACT( settings, '$.currency_id' ), :company_currency) AS currency_id
|
||||
FROM clients
|
||||
JOIN invoices
|
||||
on invoices.client_id = clients.id
|
||||
WHERE invoices.status_id IN (3,4)
|
||||
AND invoices.company_id = :company_id
|
||||
AND invoices.amount > 0
|
||||
AND clients.is_deleted = 0
|
||||
AND invoices.is_deleted = 0
|
||||
AND (invoices.date BETWEEN :start_date AND :end_date)
|
||||
GROUP BY currency_id
|
||||
")->getValue(\DB::connection()->getQueryGrammar()), ['company_currency' => $this->company->settings->currency_id, 'company_id' => $this->company->id, 'start_date' => $this->start_date, 'end_date' => $this->end_date]);
|
||||
}
|
||||
|
||||
/**
|
||||
+"payments": "12260.870000",
|
||||
+"payments_converted": "12260.870000000000",
|
||||
@ -431,7 +398,7 @@ class ProfitLoss
|
||||
*/
|
||||
private function paymentIncome()
|
||||
{
|
||||
return \DB::select(\DB::raw('
|
||||
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,
|
||||
@ -447,7 +414,7 @@ class ProfitLoss
|
||||
AND (payments.date BETWEEN :start_date AND :end_date)
|
||||
GROUP BY currency_id
|
||||
ORDER BY currency_id;
|
||||
')->getValue(\DB::connection()->getQueryGrammar()), ['company_id' => $this->company->id, 'start_date' => $this->start_date, 'end_date' => $this->end_date]);
|
||||
', ['company_id' => $this->company->id, 'start_date' => $this->start_date, 'end_date' => $this->end_date]);
|
||||
}
|
||||
|
||||
private function expenseData()
|
||||
@ -545,7 +512,7 @@ class ProfitLoss
|
||||
|
||||
private function expenseCalcWithTax()
|
||||
{
|
||||
return \DB::select(\DB::raw('
|
||||
return \DB::select('
|
||||
SELECT sum(expenses.amount) as amount,
|
||||
IFNULL(expenses.currency_id, :company_currency) as currency_id
|
||||
FROM expenses
|
||||
@ -553,7 +520,7 @@ class ProfitLoss
|
||||
AND expenses.company_id = :company_id
|
||||
AND (expenses.date BETWEEN :start_date AND :end_date)
|
||||
GROUP BY currency_id
|
||||
')->getValue(\DB::connection()->getQueryGrammar()), ['company_currency' => $this->company->settings->currency_id, 'company_id' => $this->company->id, 'start_date' => $this->start_date, 'end_date' => $this->end_date]);
|
||||
', ['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()
|
||||
|
@ -75,8 +75,6 @@ class TaxSummaryReport extends BaseExport
|
||||
$this->input['report_keys'] = $this->report_keys;
|
||||
}
|
||||
|
||||
$this->csv->insertOne($this->buildHeader());
|
||||
|
||||
$query = Invoice::query()
|
||||
->withTrashed()
|
||||
->whereIn('status_id', [2,3,4])
|
||||
@ -109,18 +107,18 @@ class TaxSummaryReport extends BaseExport
|
||||
$accrual_map[$key]['tax_amount'] += $tax['total'];
|
||||
|
||||
//cash
|
||||
$key = $tax['name'];
|
||||
|
||||
if(!isset($cash_map[$key])) {
|
||||
$cash_map[$key]['tax_amount'] = 0;
|
||||
}
|
||||
|
||||
if(in_array($invoice->status_id, [Invoice::STATUS_PARTIAL,Invoice::STATUS_PAID])){
|
||||
|
||||
$key = $tax['name'];
|
||||
|
||||
if(!isset($cash_map[$key])) {
|
||||
$cash_map[$key]['tax_amount'] = 0;
|
||||
}
|
||||
|
||||
if($invoice->status_id == Invoice::STATUS_PAID)
|
||||
$cash_map[$key]['tax_amount'] += $tax['total'];
|
||||
else
|
||||
$cash_map[$key]['tax_amount'] += (($invoice->amount - $invoice->balance) / $invoice->balance) * $tax['total'] ?? 0;
|
||||
if($invoice->status_id == Invoice::STATUS_PAID)
|
||||
$cash_map[$key]['tax_amount'] += $tax['total'];
|
||||
else
|
||||
$cash_map[$key]['tax_amount'] += (($invoice->amount - $invoice->balance) / $invoice->balance) * $tax['total'] ?? 0;
|
||||
|
||||
}
|
||||
}
|
||||
@ -129,6 +127,8 @@ class TaxSummaryReport extends BaseExport
|
||||
|
||||
$this->csv->insertOne([]);
|
||||
$this->csv->insertOne([ctrans('texts.cash_vs_accrual')]);
|
||||
$this->csv->insertOne($this->buildHeader());
|
||||
|
||||
|
||||
foreach($accrual_map as $key => $value)
|
||||
{
|
||||
@ -137,6 +137,7 @@ class TaxSummaryReport extends BaseExport
|
||||
|
||||
$this->csv->insertOne([]);
|
||||
$this->csv->insertOne([ctrans('texts.cash_accounting')]);
|
||||
$this->csv->insertOne($this->buildHeader());
|
||||
|
||||
foreach($cash_map as $key => $value) {
|
||||
$this->csv->insertOne([$key, Number::formatMoney($value['tax_amount'], $this->company)]);
|
||||
|
@ -19,11 +19,11 @@ class PurchaseOrderHistoryTransformer extends EntityTransformer
|
||||
{
|
||||
use MakesHash;
|
||||
|
||||
protected $defaultIncludes = [
|
||||
protected array $defaultIncludes = [
|
||||
// 'activity',
|
||||
];
|
||||
|
||||
protected $availableIncludes = [
|
||||
protected array $availableIncludes = [
|
||||
'activity',
|
||||
];
|
||||
|
||||
|
@ -43,7 +43,7 @@ class Ninja
|
||||
|
||||
public static function getDebugInfo()
|
||||
{
|
||||
$mysql_version = DB::select(DB::raw('select version() as version')->getValue(DB::connection()->getQueryGrammar()))[0]->version;
|
||||
$mysql_version = DB::select('select version() as version')[0]->version;
|
||||
|
||||
$version = request()->input('version', 'No Version Supplied.');
|
||||
|
||||
|
@ -15,8 +15,8 @@ return [
|
||||
'require_https' => env('REQUIRE_HTTPS', true),
|
||||
'app_url' => rtrim(env('APP_URL', ''), '/'),
|
||||
'app_domain' => env('APP_DOMAIN', 'invoicing.co'),
|
||||
'app_version' => env('APP_VERSION','5.7.6'),
|
||||
'app_tag' => env('APP_TAG','5.7.6'),
|
||||
'app_version' => env('APP_VERSION','5.7.7'),
|
||||
'app_tag' => env('APP_TAG','5.7.7'),
|
||||
'minimum_client_version' => '5.0.16',
|
||||
'terms_version' => '1.0.1',
|
||||
'api_secret' => env('API_SECRET', ''),
|
||||
@ -39,7 +39,7 @@ return [
|
||||
'trusted_proxies' => env('TRUSTED_PROXIES', false),
|
||||
'is_docker' => env('IS_DOCKER', false),
|
||||
'local_download' => env('LOCAL_DOWNLOAD', false),
|
||||
'sentry_dsn' => env('SENTRY_LARAVEL_DSN', null),
|
||||
'sentry_dsn' => env('SENTRY_LARAVEL_DSN', "https://39389664f3f14969b4c43dadda00a40b@sentry2.invoicing.co/5"),
|
||||
'environment' => env('NINJA_ENVIRONMENT', 'selfhost'), // 'hosted', 'development', 'selfhost', 'reseller'
|
||||
'preconfigured_install' => env('PRECONFIGURED_INSTALL', false),
|
||||
'update_secret' => env('UPDATE_SECRET', ''),
|
||||
|
@ -111,6 +111,7 @@ use App\Http\Controllers\Reports\ClientContactReportController;
|
||||
use App\Http\Controllers\Reports\PurchaseOrderReportController;
|
||||
use App\Http\Controllers\Reports\RecurringInvoiceReportController;
|
||||
use App\Http\Controllers\Reports\PurchaseOrderItemReportController;
|
||||
use App\Http\Controllers\SearchController;
|
||||
|
||||
Route::group(['middleware' => ['throttle:api', 'api_secret_check']], function () {
|
||||
Route::post('api/v1/signup', [AccountController::class, 'store'])->name('signup.submit');
|
||||
@ -317,7 +318,7 @@ Route::group(['middleware' => ['throttle:api', 'api_db', 'token_auth', 'locale']
|
||||
Route::post('reports/tax_summary_report', TaxSummaryReportController::class);
|
||||
Route::post('reports/user_sales_report', UserSalesReportController::class);
|
||||
Route::post('reports/preview/{hash}', ReportPreviewController::class);
|
||||
|
||||
Route::post('search', SearchController::class);
|
||||
|
||||
Route::resource('task_schedulers', TaskSchedulerController::class);
|
||||
Route::post('task_schedulers/bulk', [TaskSchedulerController::class, 'bulk'])->name('task_schedulers.bulk');
|
||||
|
61
tests/Feature/Search/SearchApiTest.php
Normal file
61
tests/Feature/Search/SearchApiTest.php
Normal file
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace Tests\Feature\Search;
|
||||
|
||||
use Tests\TestCase;
|
||||
use Tests\MockAccountData;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Illuminate\Routing\Middleware\ThrottleRequests;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @covers App\Http\Controllers\ActivityController
|
||||
*/
|
||||
class SearchApiTest extends TestCase
|
||||
{
|
||||
use DatabaseTransactions;
|
||||
use MockAccountData;
|
||||
|
||||
protected function setUp() :void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->makeTestData();
|
||||
|
||||
$this->withoutMiddleware(
|
||||
ThrottleRequests::class
|
||||
);
|
||||
|
||||
$this->withoutExceptionHandling();
|
||||
|
||||
}
|
||||
|
||||
public function testActivityEntity()
|
||||
{
|
||||
|
||||
$response = false;
|
||||
|
||||
$data = [];
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->postJson('/api/v1/search', $data);
|
||||
|
||||
$response->assertStatus(200);
|
||||
|
||||
nlog($response->json());
|
||||
|
||||
}
|
||||
|
||||
}
|
285
tests/Unit/CheckDataTest.php
Normal file
285
tests/Unit/CheckDataTest.php
Normal file
@ -0,0 +1,285 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace Tests\Unit;
|
||||
|
||||
use Tests\TestCase;
|
||||
use App\Models\User;
|
||||
use App\Utils\Ninja;
|
||||
use App\Models\Client;
|
||||
use App\Models\Account;
|
||||
use App\Models\Company;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
use App\Models\Paymentable;
|
||||
use Illuminate\Support\Str;
|
||||
use App\Models\CompanyToken;
|
||||
use App\Models\ClientContact;
|
||||
use App\DataMapper\CompanySettings;
|
||||
use App\Factory\CompanyUserFactory;
|
||||
use Illuminate\Routing\Middleware\ThrottleRequests;
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
class CheckDataTest extends TestCase
|
||||
{
|
||||
protected $account;
|
||||
protected $user;
|
||||
protected $company;
|
||||
protected $cu;
|
||||
protected $token;
|
||||
protected $client;
|
||||
protected $faker;
|
||||
/**
|
||||
* Important consideration with Base64
|
||||
* encoding checks.
|
||||
*
|
||||
* No method can guarantee against false positives.
|
||||
*/
|
||||
protected function setUp() :void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->faker = \Faker\Factory::create();
|
||||
|
||||
$this->withoutMiddleware(
|
||||
ThrottleRequests::class
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
private function buildData()
|
||||
{
|
||||
$this->account = Account::factory()->create([
|
||||
'hosted_client_count' => 1000,
|
||||
'hosted_company_count' => 1000,
|
||||
]);
|
||||
|
||||
$this->account->num_users = 3;
|
||||
$this->account->save();
|
||||
|
||||
$this->user = User::factory()->create([
|
||||
'account_id' => $this->account->id,
|
||||
'confirmation_code' => 'xyz123',
|
||||
'email' => $this->faker->unique()->safeEmail(),
|
||||
]);
|
||||
|
||||
$settings = CompanySettings::defaults();
|
||||
$settings->client_online_payment_notification = false;
|
||||
$settings->client_manual_payment_notification = false;
|
||||
|
||||
$this->company = Company::factory()->create([
|
||||
'account_id' => $this->account->id,
|
||||
'settings' => $settings,
|
||||
]);
|
||||
|
||||
$this->company->settings = $settings;
|
||||
$this->company->save();
|
||||
|
||||
$this->cu = CompanyUserFactory::create($this->user->id, $this->company->id, $this->account->id);
|
||||
$this->cu->is_owner = true;
|
||||
$this->cu->is_admin = true;
|
||||
$this->cu->is_locked = false;
|
||||
$this->cu->save();
|
||||
|
||||
$this->token = \Illuminate\Support\Str::random(64);
|
||||
|
||||
$company_token = new CompanyToken;
|
||||
$company_token->user_id = $this->user->id;
|
||||
$company_token->company_id = $this->company->id;
|
||||
$company_token->account_id = $this->account->id;
|
||||
$company_token->name = 'test token';
|
||||
$company_token->token = $this->token;
|
||||
$company_token->is_system = true;
|
||||
|
||||
$company_token->save();
|
||||
|
||||
$this->client = Client::factory()->create([
|
||||
'user_id' => $this->user->id,
|
||||
'company_id' => $this->company->id,
|
||||
'is_deleted' => 0,
|
||||
'name' => 'bob',
|
||||
'address1' => '1234',
|
||||
'balance' => 100,
|
||||
'paid_to_date' => 50,
|
||||
]);
|
||||
|
||||
ClientContact::factory()->create([
|
||||
'user_id' => $this->user->id,
|
||||
'client_id' => $this->client->id,
|
||||
'company_id' => $this->company->id,
|
||||
'is_primary' => 1,
|
||||
'first_name' => 'john',
|
||||
'last_name' => 'doe',
|
||||
'email' => 'john@doe.com'
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
public function testDbQueriesRaw5()
|
||||
{
|
||||
$this->buildData();
|
||||
|
||||
$i = Invoice::factory()->count(5)->create([
|
||||
'user_id' => $this->user->id,
|
||||
'client_id' => $this->client->id,
|
||||
'company_id' => $this->company->id,
|
||||
]);
|
||||
|
||||
Invoice::where('status_id', 2)->cursor()->each(function ($i) {
|
||||
|
||||
$i->service()->markPaid()->save();
|
||||
|
||||
});
|
||||
|
||||
Payment::with('paymentables')->cursor()->each(function($payment){
|
||||
$this->assertNotNull($payment->paymentables()->where('paymentable_type', \App\Models\Credit::class)->get()
|
||||
->sum(\DB::raw('amount')->getValue(\DB::connection()->getQueryGrammar())));
|
||||
});
|
||||
|
||||
Payment::with('paymentables')->cursor()->each(function ($payment) {
|
||||
$this->assertNotNull($payment->paymentables()->where('paymentable_type', \App\Models\Credit::class)->get()
|
||||
->sum('amount'));
|
||||
});
|
||||
|
||||
$amount = Paymentable::first()->payment->paymentables()->where('paymentable_type', 'invnoices')->get()->sum('amount');
|
||||
|
||||
$this->assertNotNull($amount);
|
||||
|
||||
}
|
||||
|
||||
public function testDbQueriesRaw4()
|
||||
{
|
||||
$this->buildData();
|
||||
|
||||
ClientContact::factory()->count(10)->create([
|
||||
'user_id' => $this->user->id,
|
||||
'client_id' => $this->client->id,
|
||||
'company_id' => $this->company->id,
|
||||
]);
|
||||
|
||||
$clients_refactor = \DB::table('clients')
|
||||
->leftJoin('client_contacts', function ($join){
|
||||
$join->on('client_contacts.client_id', '=', 'clients.id');
|
||||
})
|
||||
->get(['clients.id', \DB::raw('count(client_contacts.id) as contact_count')]);
|
||||
|
||||
// $this->assertNotNull($clients);
|
||||
$this->assertNotNull($clients_refactor);
|
||||
|
||||
}
|
||||
|
||||
public function testDbQueriesRaw3()
|
||||
{
|
||||
$this->buildData();
|
||||
|
||||
User::factory()->create([
|
||||
'account_id' => $this->account->id,
|
||||
'email' => $this->faker->unique()->safeEmail(),
|
||||
]);
|
||||
|
||||
User::factory()->create([
|
||||
'account_id' => $this->account->id,
|
||||
'email' => $this->faker->unique()->safeEmail(),
|
||||
]);
|
||||
|
||||
$user_hash = 'a';
|
||||
|
||||
$user_count = User::where('account_id', $this->company->account->id)
|
||||
->where(
|
||||
\DB::raw('CONCAT_WS(" ", first_name, last_name)'),
|
||||
'like',
|
||||
'%'.$user_hash.'%'
|
||||
)
|
||||
->get();
|
||||
|
||||
$user_count_refactor = User::whereRaw("account_id = ? AND CONCAT_WS(' ', first_name, last_name) like ?", [$this->company->account_id, '%'.$user_hash.'%'])
|
||||
->get();
|
||||
|
||||
|
||||
$this->assertEquals($user_count_refactor->count(), $user_count->count());
|
||||
}
|
||||
|
||||
public function testDbRawQueries1()
|
||||
{
|
||||
$this->buildData();
|
||||
|
||||
$results = \DB::select(\DB::raw("
|
||||
SELECT count(clients.id) as count
|
||||
FROM clients
|
||||
")->getValue(\DB::connection()->getQueryGrammar()));
|
||||
|
||||
|
||||
$refactored = \DB::select("
|
||||
SELECT count(clients.id) as count
|
||||
FROM clients
|
||||
");
|
||||
|
||||
$this->assertEquals($refactored[0]->count, $results[0]->count);
|
||||
|
||||
}
|
||||
|
||||
public function testDbRawQueries2()
|
||||
{
|
||||
$this->buildData();
|
||||
|
||||
Payment::factory()->count(5)->create([
|
||||
'client_id' => $this->client->id,
|
||||
'company_id' => $this->company->id,
|
||||
'user_id' => $this->user->id,
|
||||
]);
|
||||
|
||||
Invoice::factory()->count(5)->create([
|
||||
'client_id' => $this->client->id,
|
||||
'company_id' => $this->company->id,
|
||||
'user_id' => $this->user->id,
|
||||
]);
|
||||
|
||||
Invoice::where('status_id', 2)->cursor()->each(function ($i) {
|
||||
|
||||
$i->service()->markPaid()->save();
|
||||
|
||||
});
|
||||
|
||||
$results = \DB::select(\DB::raw("
|
||||
SELECT
|
||||
SUM(payments.amount) as amount
|
||||
FROM payments
|
||||
LEFT JOIN paymentables
|
||||
ON
|
||||
payments.id = paymentables.payment_id
|
||||
WHERE paymentable_type = ?
|
||||
AND paymentables.deleted_at is NULL
|
||||
AND paymentables.amount > 0
|
||||
AND payments.is_deleted = 0
|
||||
AND payments.client_id = ?;
|
||||
")->getValue(\DB::connection()->getQueryGrammar()), ['invoices', $this->client->id]);
|
||||
|
||||
$refactored = \DB::select("
|
||||
SELECT
|
||||
SUM(payments.amount) as amount
|
||||
FROM payments
|
||||
LEFT JOIN paymentables
|
||||
ON
|
||||
payments.id = paymentables.payment_id
|
||||
WHERE paymentable_type = ?
|
||||
AND paymentables.deleted_at is NULL
|
||||
AND paymentables.amount > 0
|
||||
AND payments.is_deleted = 0
|
||||
AND payments.client_id = ?;
|
||||
", ['invoices', $this->client->id]);
|
||||
|
||||
$this->assertEquals($refactored[0]->amount, $results[0]->amount);
|
||||
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user