1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-10 05:02:36 +01:00

Additions for Invoice Report

This commit is contained in:
David Bomba 2023-04-24 14:55:56 +10:00
parent f470d10f96
commit b5fd275dcd
4 changed files with 227 additions and 5 deletions

View File

@ -12,8 +12,10 @@
namespace App\Export\CSV; namespace App\Export\CSV;
use App\Models\Client; use App\Models\Client;
use App\Utils\Traits\MakesHash; use App\Models\Invoice;
use Illuminate\Support\Carbon; use Illuminate\Support\Carbon;
use App\Utils\Traits\MakesHash;
use Illuminate\Database\Eloquent\Builder;
class BaseExport class BaseExport
{ {
@ -46,6 +48,60 @@ class BaseExport
return $query; return $query;
} }
protected function addInvoiceStatusFilter($query, $status): Builder
{
$status_parameters = explode(',', $status);
if(in_array('all', $status_parameters))
return $query;
$query->where(function ($nested) use ($status_parameters) {
$invoice_filters = [];
if (in_array('draft', $status_parameters)) {
$invoice_filters[] = Invoice::STATUS_DRAFT;
}
if (in_array('sent', $status_parameters)) {
$invoice_filters[] = Invoice::STATUS_SENT;
}
if (in_array('paid', $status_parameters)) {
$invoice_filters[] = Invoice::STATUS_PAID;
}
if (in_array('unpaid', $status_parameters)) {
$invoice_filters[] = Invoice::STATUS_SENT;
$invoice_filters[] = Invoice::STATUS_PARTIAL;
}
if (count($invoice_filters) > 0) {
$nested->whereIn('status_id', $invoice_filters);
}
if (in_array('overdue', $status_parameters)) {
$nested->orWhereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL])
->where('due_date', '<', Carbon::now())
->orWhere('partial_due_date', '<', Carbon::now());
}
if(in_array('viewed', $status_parameters)){
$nested->whereHas('invitations', function ($q){
$q->whereNotNull('viewed_date')->whereNotNull('deleted_at');
});
}
});
return $query;
}
protected function addDateRange($query) protected function addDateRange($query)
{ {
$date_range = $this->input['date_range']; $date_range = $this->input['date_range'];

View File

@ -11,13 +11,15 @@
namespace App\Export\CSV; namespace App\Export\CSV;
use App\Libraries\MultiDB; use App\Utils\Ninja;
use App\Utils\Number;
use League\Csv\Writer;
use App\Models\Company; use App\Models\Company;
use App\Models\Invoice; use App\Models\Invoice;
use App\Transformers\InvoiceTransformer; use App\Libraries\MultiDB;
use App\Utils\Ninja; use App\Export\CSV\BaseExport;
use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\App;
use League\Csv\Writer; use App\Transformers\InvoiceTransformer;
class InvoiceExport extends BaseExport class InvoiceExport extends BaseExport
{ {
@ -63,6 +65,10 @@ class InvoiceExport extends BaseExport
'terms' => 'terms', 'terms' => 'terms',
'total_taxes' => 'total_taxes', 'total_taxes' => 'total_taxes',
'currency_id' => 'currency_id', 'currency_id' => 'currency_id',
'payment_number' => 'payment_number',
'payment_date' => 'payment_date',
'payment_amount' => 'payment_amount',
'method' => 'method',
]; ];
private array $decorate_keys = [ private array $decorate_keys = [
@ -107,6 +113,10 @@ class InvoiceExport extends BaseExport
$query = $this->addDateRange($query); $query = $this->addDateRange($query);
if(isset($this->input['status'])){
$query = $this->addInvoiceStatusFilter($query, $this->input['status']);
}
$query->cursor() $query->cursor()
->each(function ($invoice) { ->each(function ($invoice) {
$this->csv->insertOne($this->buildRow($invoice)); $this->csv->insertOne($this->buildRow($invoice));
@ -151,7 +161,17 @@ class InvoiceExport extends BaseExport
if (in_array('status_id', $this->input['report_keys'])) { if (in_array('status_id', $this->input['report_keys'])) {
$entity['status'] = $invoice->stringStatus($invoice->status_id); $entity['status'] = $invoice->stringStatus($invoice->status_id);
} }
$payment_exists = $invoice->payments()->exists();
$entity['payment_number'] = $payment_exists ? $invoice->payments()->pluck('number')->implode(',') : '';
$entity['payment_date'] = $payment_exists ? $invoice->payments()->pluck('date')->implode(',') : '';
$entity['payment_amount'] = $payment_exists ? Number::formatMoney($invoice->payments()->sum('paymentables.amount'), $invoice->company) : ctrans('texts.unpaid');
$entity['method'] = $payment_exists ? $invoice->payments()->first()->translatedType() : "";
return $entity; return $entity;
} }
} }

View File

@ -33,6 +33,7 @@ class GenericReportRequest extends Request
'start_date' => 'bail|required_if:date_range,custom|nullable|date', 'start_date' => 'bail|required_if:date_range,custom|nullable|date',
'report_keys' => 'present|array', 'report_keys' => 'present|array',
'send_email' => 'required|bool', 'send_email' => 'required|bool',
'status' => 'sometimes|string|nullable|in:all,draft,sent,viewed,paid,unpaid,overdue',
]; ];
} }

View File

@ -0,0 +1,145 @@
<?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\Export;
use App\Utils\Traits\MakesHash;
use Illuminate\Routing\Middleware\ThrottleRequests;
use Tests\MockAccountData;
use Tests\TestCase;
/**
* @test
*/
class ReportApiTest extends TestCase
{
use MakesHash;
use MockAccountData;
public $faker;
protected function setUp() :void
{
parent::setUp();
$this->faker = \Faker\Factory::create();
$this->withoutMiddleware(
ThrottleRequests::class
);
$this->withoutExceptionHandling();
$this->makeTestData();
}
public function testUserSalesReportApiRoute()
{
$data = [
'send_email' => false,
'date_range' => 'all',
'report_keys' => [],
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->postJson('/api/v1/reports/user_sales_report', $data)
->assertStatus(200);
}
public function testTaxSummaryReportApiRoute()
{
$data = [
'send_email' => false,
'date_range' => 'all',
'report_keys' => [],
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->postJson('/api/v1/reports/tax_summary_report', $data)
->assertStatus(200);
}
public function testClientSalesReportApiRoute()
{
$data = [
'send_email' => false,
'date_range' => 'all',
'report_keys' => [],
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->postJson('/api/v1/reports/client_sales_report', $data)
->assertStatus(200);
}
public function testArDetailReportApiRoute()
{
$data = [
'send_email' => false,
'date_range' => 'all',
'report_keys' => [],
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->postJson('/api/v1/reports/ar_detail_report', $data)
->assertStatus(200);
}
public function testArSummaryReportApiRoute()
{
$data = [
'send_email' => false,
'date_range' => 'all',
'report_keys' => [],
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->postJson('/api/v1/reports/ar_summary_report', $data)
->assertStatus(200);
}
public function testClientBalanceReportApiRoute()
{
$data = [
'send_email' => false,
'date_range' => 'all',
'report_keys' => [],
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->postJson('/api/v1/reports/client_balance_report', $data)
->assertStatus(200);
}
}