diff --git a/app/Export/CSV/RecurringInvoiceExport.php b/app/Export/CSV/RecurringInvoiceExport.php new file mode 100644 index 000000000000..551a5ea72772 --- /dev/null +++ b/app/Export/CSV/RecurringInvoiceExport.php @@ -0,0 +1,167 @@ + 'amount', + 'balance' => 'balance', + 'client' => 'client_id', + 'custom_surcharge1' => 'custom_surcharge1', + 'custom_surcharge2' => 'custom_surcharge2', + 'custom_surcharge3' => 'custom_surcharge3', + 'custom_surcharge4' => 'custom_surcharge4', + 'custom_value1' => 'custom_value1', + 'custom_value2' => 'custom_value2', + 'custom_value3' => 'custom_value3', + 'custom_value4' => 'custom_value4', + 'date' => 'date', + 'discount' => 'discount', + 'due_date' => 'due_date', + 'exchange_rate' => 'exchange_rate', + 'footer' => 'footer', + 'number' => 'number', + 'paid_to_date' => 'paid_to_date', + 'partial' => 'partial', + 'partial_due_date' => 'partial_due_date', + 'po_number' => 'po_number', + 'private_notes' => 'private_notes', + 'public_notes' => 'public_notes', + 'status' => 'status_id', + 'tax_name1' => 'tax_name1', + 'tax_name2' => 'tax_name2', + 'tax_name3' => 'tax_name3', + 'tax_rate1' => 'tax_rate1', + 'tax_rate2' => 'tax_rate2', + 'tax_rate3' => 'tax_rate3', + 'terms' => 'terms', + 'total_taxes' => 'total_taxes', + 'currency' => 'client_id', + 'vendor' => 'vendor_id', + 'project' => 'project_id', + ]; + + private array $decorate_keys = [ + 'country', + 'client', + 'currency', + 'status', + 'vendor', + 'project' + ]; + + public function __construct(Company $company, array $input) + { + $this->company = $company; + $this->input = $input; + $this->invoice_transformer = new RecurringInvoiceTransformer(); + } + + public function run() + { + + MultiDB::setDb($this->company->db); + App::forgetInstance('translator'); + App::setLocale($this->company->locale()); + $t = app('translator'); + $t->replace(Ninja::transformTranslations($this->company->settings)); + + //load the CSV document from a string + $this->csv = Writer::createFromString(); + + //insert the header + $this->csv->insertOne($this->buildHeader()); + + $query = RecurringInvoice::query() + ->withTrashed() + ->with('client')->where('company_id', $this->company->id) + ->where('is_deleted',0); + + $query = $this->addDateRange($query); + + $query->cursor() + ->each(function ($invoice){ + + $this->csv->insertOne($this->buildRow($invoice)); + + }); + + return $this->csv->toString(); + + } + + private function buildHeader() :array + { + + $header = []; + + foreach(array_keys($this->input['report_keys']) as $key) + $header[] = ctrans("texts.{$key}"); + + return $header; + } + + private function buildRow(RecurringInvoice $invoice) :array + { + + $transformed_invoice = $this->invoice_transformer->transform($invoice); + + $entity = []; + + foreach(array_values($this->input['report_keys']) as $key){ + + $entity[$key] = $transformed_invoice[$key]; + } + + return $this->decorateAdvancedFields($invoice, $entity); + + } + + private function decorateAdvancedFields(RecurringInvoice $invoice, array $entity) :array + { + if(array_key_exists('currency', $entity)) + $entity['currency'] = $invoice->client->currency()->code; + + if(array_key_exists('client_id', $entity)) + $entity['client_id'] = $invoice->client->present()->name(); + + if(array_key_exists('status_id', $entity)) + $entity['status_id'] = $invoice->stringStatus($invoice->status_id); + + if(array_key_exists('vendor_id', $entity)) + $entity['vendor_id'] = $invoice->vendor()->exists() ? $invoice->vendor->name : ''; + + if(array_key_exists('project_id', $entity)) + $entity['project'] = $invoice->project()->exists() ? $invoice->project->name : ''; + + return $entity; + } + +} diff --git a/app/Http/Controllers/Reports/RecurringInvoiceReportController.php b/app/Http/Controllers/Reports/RecurringInvoiceReportController.php new file mode 100644 index 000000000000..bfafa677ecfe --- /dev/null +++ b/app/Http/Controllers/Reports/RecurringInvoiceReportController.php @@ -0,0 +1,84 @@ +user()->company(), $request->all()); + + $csv = $export->run(); + + $headers = array( + 'Content-Disposition' => 'attachment', + 'Content-Type' => 'text/csv', + ); + + return response()->streamDownload(function () use ($csv) { + echo $csv; + }, $this->filename, $headers); + + } + + + +} diff --git a/app/Models/RecurringInvoice.php b/app/Models/RecurringInvoice.php index 9e614d39d522..7f6317f26bac 100644 --- a/app/Models/RecurringInvoice.php +++ b/app/Models/RecurringInvoice.php @@ -347,6 +347,31 @@ class RecurringInvoice extends BaseModel } } + public static function stringStatus(int $status) + { + switch ($status) { + case self::STATUS_DRAFT: + return ctrans('texts.draft'); + break; + case self::STATUS_PENDING: + return ctrans('texts.pending'); + break; + case self::STATUS_ACTIVE: + return ctrans('texts.active'); + break; + case self::STATUS_COMPLETED: + return ctrans('texts.status_completed'); + break; + case self::STATUS_PAUSED: + return ctrans('texts.paused'); + break; + default: + // code... + break; + } + } + + public static function frequencyForKey(int $frequency_id) :string { switch ($frequency_id) { diff --git a/routes/api.php b/routes/api.php index 9d5f2f392f07..36be817dfb5d 100644 --- a/routes/api.php +++ b/routes/api.php @@ -162,6 +162,7 @@ Route::group(['middleware' => ['throttle:300,1', 'api_db', 'token_auth', 'locale Route::post('reports/invoices', 'Reports\InvoiceReportController'); Route::post('reports/invoice_items', 'Reports\InvoiceItemReportController'); Route::post('reports/quotes', 'Reports\QuoteReportController'); + Route::post('reports/recurring_invoices', 'Reports\RecurringInvoiceReportController'); Route::get('scheduler', 'SchedulerController@index');