diff --git a/app/Export/CSV/BaseExport.php b/app/Export/CSV/BaseExport.php index 1c0a0294e42e..65b3bd50b363 100644 --- a/app/Export/CSV/BaseExport.php +++ b/app/Export/CSV/BaseExport.php @@ -12,8 +12,10 @@ namespace App\Export\CSV; use App\Models\Client; -use App\Utils\Traits\MakesHash; +use App\Models\Invoice; use Illuminate\Support\Carbon; +use App\Utils\Traits\MakesHash; +use Illuminate\Database\Eloquent\Builder; class BaseExport { @@ -46,6 +48,60 @@ class BaseExport 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) { $date_range = $this->input['date_range']; diff --git a/app/Export/CSV/InvoiceExport.php b/app/Export/CSV/InvoiceExport.php index 750cbd5f60e8..2141358fa134 100644 --- a/app/Export/CSV/InvoiceExport.php +++ b/app/Export/CSV/InvoiceExport.php @@ -11,13 +11,15 @@ 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\Invoice; -use App\Transformers\InvoiceTransformer; -use App\Utils\Ninja; +use App\Libraries\MultiDB; +use App\Export\CSV\BaseExport; use Illuminate\Support\Facades\App; -use League\Csv\Writer; +use App\Transformers\InvoiceTransformer; class InvoiceExport extends BaseExport { @@ -63,6 +65,10 @@ class InvoiceExport extends BaseExport 'terms' => 'terms', 'total_taxes' => 'total_taxes', 'currency_id' => 'currency_id', + 'payment_number' => 'payment_number', + 'payment_date' => 'payment_date', + 'payment_amount' => 'payment_amount', + 'method' => 'method', ]; private array $decorate_keys = [ @@ -107,6 +113,10 @@ class InvoiceExport extends BaseExport $query = $this->addDateRange($query); + if(isset($this->input['status'])){ + $query = $this->addInvoiceStatusFilter($query, $this->input['status']); + } + $query->cursor() ->each(function ($invoice) { $this->csv->insertOne($this->buildRow($invoice)); @@ -151,7 +161,17 @@ class InvoiceExport extends BaseExport if (in_array('status_id', $this->input['report_keys'])) { $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; } } diff --git a/app/Http/Requests/Report/GenericReportRequest.php b/app/Http/Requests/Report/GenericReportRequest.php index 63837aa41341..3e95479d23b5 100644 --- a/app/Http/Requests/Report/GenericReportRequest.php +++ b/app/Http/Requests/Report/GenericReportRequest.php @@ -33,6 +33,7 @@ class GenericReportRequest extends Request 'start_date' => 'bail|required_if:date_range,custom|nullable|date', 'report_keys' => 'present|array', 'send_email' => 'required|bool', + 'status' => 'sometimes|string|nullable|in:all,draft,sent,viewed,paid,unpaid,overdue', ]; } diff --git a/tests/Feature/Export/ReportApiTest.php b/tests/Feature/Export/ReportApiTest.php new file mode 100644 index 000000000000..14fd1f57297b --- /dev/null +++ b/tests/Feature/Export/ReportApiTest.php @@ -0,0 +1,145 @@ +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); + + } + + +} \ No newline at end of file