diff --git a/app/Export/CSV/BaseExport.php b/app/Export/CSV/BaseExport.php index d9283ac3d38f..3188ad2a8557 100644 --- a/app/Export/CSV/BaseExport.php +++ b/app/Export/CSV/BaseExport.php @@ -64,4 +64,17 @@ class BaseExport } + protected function buildHeader() :array + { + + $header = []; + + foreach($this->input['report_keys'] as $value){ + $key = array_search ($value, $this->entity_keys); + + $header[] = ctrans("texts.{$key}"); + } + + return $header; + } } \ No newline at end of file diff --git a/app/Export/CSV/ClientExport.php b/app/Export/CSV/ClientExport.php index 43f1de6bcc02..da4f0011c404 100644 --- a/app/Export/CSV/ClientExport.php +++ b/app/Export/CSV/ClientExport.php @@ -37,7 +37,7 @@ class ClientExport extends BaseExport protected string $date_key = 'created_at'; - private array $entity_keys = [ + protected array $entity_keys = [ 'address1' => 'client.address1', 'address2' => 'client.address2', 'balance' => 'client.balance', @@ -125,17 +125,6 @@ class ClientExport extends BaseExport } - private function buildHeader() :array - { - - $header = []; - - foreach(array_keys($this->input['report_keys']) as $key) - $header[] = ctrans("texts.{$key}"); - - return $header; - } - private function buildRow(Client $client) :array { diff --git a/app/Export/CSV/ContactExport.php b/app/Export/CSV/ContactExport.php index e9dba9704135..d3f95822b998 100644 --- a/app/Export/CSV/ContactExport.php +++ b/app/Export/CSV/ContactExport.php @@ -33,7 +33,7 @@ class ContactExport extends BaseExport protected string $date_key = 'created_at'; - private array $entity_keys = [ + protected array $entity_keys = [ 'address1' => 'client.address1', 'address2' => 'client.address2', 'balance' => 'client.balance', @@ -120,17 +120,6 @@ class ContactExport extends BaseExport } - private function buildHeader() :array - { - - $header = []; - - foreach(array_keys($this->input['report_keys']) as $key) - $header[] = ctrans("texts.{$key}"); - - return $header; - } - private function buildRow(ClientContact $contact) :array { diff --git a/app/Export/CSV/CreditExport.php b/app/Export/CSV/CreditExport.php index 5cb151f9d8de..13ab31ca71da 100644 --- a/app/Export/CSV/CreditExport.php +++ b/app/Export/CSV/CreditExport.php @@ -30,7 +30,7 @@ class CreditExport extends BaseExport protected string $date_key = 'created_at'; - private array $entity_keys = [ + protected array $entity_keys = [ 'amount' => 'amount', 'balance' => 'balance', 'client' => 'client_id', @@ -115,17 +115,6 @@ class CreditExport extends BaseExport } - private function buildHeader() :array - { - - $header = []; - - foreach(array_keys($this->input['report_keys']) as $key) - $header[] = ctrans("texts.{$key}"); - - return $header; - } - private function buildRow(Credit $credit) :array { diff --git a/app/Export/CSV/DocumentExport.php b/app/Export/CSV/DocumentExport.php index 9716d1946bb4..74bb8149d571 100644 --- a/app/Export/CSV/DocumentExport.php +++ b/app/Export/CSV/DocumentExport.php @@ -31,7 +31,7 @@ class DocumentExport extends BaseExport protected $date_key = 'created_at'; - private array $entity_keys = [ + protected array $entity_keys = [ 'record_type' => 'record_type', 'record_name' => 'record_name', 'name' => 'name', @@ -80,17 +80,6 @@ class DocumentExport extends BaseExport } - private function buildHeader() :array - { - - $header = []; - - foreach(array_keys($this->input['report_keys']) as $key) - $header[] = ctrans("texts.{$key}"); - - return $header; - } - private function buildRow(Document $document) :array { diff --git a/app/Export/CSV/ExpenseExport.php b/app/Export/CSV/ExpenseExport.php index 863a0d3a130f..c7b0bb36179a 100644 --- a/app/Export/CSV/ExpenseExport.php +++ b/app/Export/CSV/ExpenseExport.php @@ -30,7 +30,7 @@ class ExpenseExport extends BaseExport protected $date_key = 'date'; - private array $entity_keys = [ + protected array $entity_keys = [ 'amount' => 'amount', 'category' => 'category_id', 'client' => 'client_id', @@ -115,17 +115,6 @@ class ExpenseExport extends BaseExport } - private function buildHeader() :array - { - - $header = []; - - foreach(array_keys($this->input['report_keys']) as $key) - $header[] = ctrans("texts.{$key}"); - - return $header; - } - private function buildRow(Expense $expense) :array { diff --git a/app/Export/CSV/InvoiceExport.php b/app/Export/CSV/InvoiceExport.php index c3f745a88fca..9ee104dee8d6 100644 --- a/app/Export/CSV/InvoiceExport.php +++ b/app/Export/CSV/InvoiceExport.php @@ -30,7 +30,7 @@ class InvoiceExport extends BaseExport protected string $date_key = 'date'; - private array $entity_keys = [ + protected array $entity_keys = [ 'amount' => 'amount', 'balance' => 'balance', 'client' => 'client_id', @@ -113,17 +113,6 @@ class InvoiceExport extends BaseExport } - private function buildHeader() :array - { - - $header = []; - - foreach(array_keys($this->input['report_keys']) as $key) - $header[] = ctrans("texts.{$key}"); - - return $header; - } - private function buildRow(Invoice $invoice) :array { diff --git a/app/Export/CSV/InvoiceItemExport.php b/app/Export/CSV/InvoiceItemExport.php index 6028d5359647..6c060788a9d2 100644 --- a/app/Export/CSV/InvoiceItemExport.php +++ b/app/Export/CSV/InvoiceItemExport.php @@ -30,7 +30,7 @@ class InvoiceItemExport extends BaseExport protected string $date_key = 'date'; - private array $entity_keys = [ + protected array $entity_keys = [ 'amount' => 'amount', 'balance' => 'balance', 'client' => 'client_id', @@ -129,17 +129,6 @@ class InvoiceItemExport extends BaseExport } - private function buildHeader() :array - { - - $header = []; - - foreach(array_keys($this->input['report_keys']) as $key) - $header[] = ctrans("texts.{$key}"); - - return $header; - } - private function iterateItems(Invoice $invoice) { $transformed_invoice = $this->buildRow($invoice); diff --git a/app/Export/CSV/PaymentExport.php b/app/Export/CSV/PaymentExport.php new file mode 100644 index 000000000000..3b675d14f762 --- /dev/null +++ b/app/Export/CSV/PaymentExport.php @@ -0,0 +1,148 @@ + 'amount', + 'applied' => 'applied', + 'client' => 'client_id', + 'currency' => 'currency_id', + 'custom_value1' => 'custom_value1', + 'custom_value2' => 'custom_value2', + 'custom_value3' => 'custom_value3', + 'custom_value4' => 'custom_value4', + 'date' => 'date', + 'exchange_currency' => 'exchange_currency_id', + 'gateway_type' => 'gateway_type_id', + 'number' => 'number', + 'private_notes' => 'private_notes', + 'project' => 'project_id', + 'refunded' => 'refunded', + 'status' => 'status_id', + 'transaction_reference' => 'transaction_reference', + 'type' => 'type_id', + 'vendor' => 'vendor_id', + ]; + + private array $decorate_keys = [ + 'vendor', + 'status', + 'project', + 'client', + 'currency', + 'exchange_currency', + 'type', + ]; + + public function __construct(Company $company, array $input) + { + $this->company = $company; + $this->input = $input; + $this->entity_transformer = new PaymentTransformer(); + } + + 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 = Payment::query()->where('company_id', $this->company->id); + + $query = $this->addDateRange($query); + + $query->cursor() + ->each(function ($entity){ + + $this->csv->insertOne($this->buildRow($entity)); + + }); + + return $this->csv->toString(); + + } + + private function buildRow(Payment $payment) :array + { + + $transformed_entity = $this->entity_transformer->transform($payment); + + $entity = []; + + foreach(array_values($this->input['report_keys']) as $key){ + + $entity[$key] = $transformed_entity[$key]; + + } + + return $this->decorateAdvancedFields($payment, $entity); + + } + + private function decorateAdvancedFields(Payment $payment, array $entity) :array + { + + if(array_key_exists('status_id', $entity)) + $entity['status_id'] = $payment->stringStatus($payment->status_id); + + if(array_key_exists('vendor_id', $entity)) + $entity['vendor_id'] = $payment->vendor()->exists() ? $payment->vendor->name : ''; + + if(array_key_exists('project_id', $entity)) + $entity['project_id'] = $payment->project()->exists() ? $payment->project->name : ''; + + if(array_key_exists('currency_id', $entity)) + $entity['currency_id'] = $payment->currency()->exists() ? $payment->currency->code : ''; + + if(array_key_exists('exchange_currency_id', $entity)) + $entity['exchange_currency_id'] = $payment->exchange_currency()->exists() ? $payment->exchange_currency->code : ''; + + if(array_key_exists('client_id', $entity)) + $entity['client_id'] = $payment->client->present()->name(); + + if(array_key_exists('type_id', $entity)) + $entity['type_id'] = $payment->translatedType(); + + return $entity; + } + +} diff --git a/app/Export/CSV/QuoteExport.php b/app/Export/CSV/QuoteExport.php index 71a179b6a993..71eaec9e593c 100644 --- a/app/Export/CSV/QuoteExport.php +++ b/app/Export/CSV/QuoteExport.php @@ -30,7 +30,7 @@ class QuoteExport extends BaseExport protected string $date_key = 'date'; - private array $entity_keys = [ + protected array $entity_keys = [ 'amount' => 'amount', 'balance' => 'balance', 'client' => 'client_id', @@ -113,17 +113,6 @@ class QuoteExport extends BaseExport } - private function buildHeader() :array - { - - $header = []; - - foreach(array_keys($this->input['report_keys']) as $key) - $header[] = ctrans("texts.{$key}"); - - return $header; - } - private function buildRow(Quote $quote) :array { diff --git a/app/Export/CSV/RecurringInvoiceExport.php b/app/Export/CSV/RecurringInvoiceExport.php index 551a5ea72772..09e5b1ff142b 100644 --- a/app/Export/CSV/RecurringInvoiceExport.php +++ b/app/Export/CSV/RecurringInvoiceExport.php @@ -30,7 +30,7 @@ class RecurringInvoiceExport extends BaseExport protected string $date_key = 'date'; - private array $entity_keys = [ + protected array $entity_keys = [ 'amount' => 'amount', 'balance' => 'balance', 'client' => 'client_id', @@ -117,17 +117,6 @@ class RecurringInvoiceExport extends BaseExport } - 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 { diff --git a/app/Http/Controllers/Reports/ClientContactReportController.php b/app/Http/Controllers/Reports/ClientContactReportController.php index f4e8ad07c8da..5b3a20683b58 100644 --- a/app/Http/Controllers/Reports/ClientContactReportController.php +++ b/app/Http/Controllers/Reports/ClientContactReportController.php @@ -13,7 +13,7 @@ namespace App\Http\Controllers\Reports; use App\Export\CSV\ContactExport; use App\Http\Controllers\BaseController; -use App\Http\Requests\Report\GenericReportSchema; +use App\Http\Requests\Report\GenericReportRequest; use App\Utils\Traits\MakesHash; use Illuminate\Http\Response; @@ -60,7 +60,7 @@ class ClientContactReportController extends BaseController * ), * ) */ - public function __invoke(GenericReportSchema $request) + public function __invoke(GenericReportRequest $request) { // expect a list of visible fields, or use the default diff --git a/app/Http/Controllers/Reports/ClientReportController.php b/app/Http/Controllers/Reports/ClientReportController.php index 879de532c4e4..e65a59b5cb10 100644 --- a/app/Http/Controllers/Reports/ClientReportController.php +++ b/app/Http/Controllers/Reports/ClientReportController.php @@ -40,7 +40,7 @@ class ClientReportController extends BaseController * @OA\Parameter(ref="#/components/parameters/X-Requested-With"), * @OA\RequestBody( * required=true, - * @OA\JsonContent(ref="#/components/schemas/ClientReportSchema") + * @OA\JsonContent(ref="#/components/schemas/GenericReportSchema") * ), * @OA\Response( * response=200, diff --git a/app/Http/Controllers/Reports/DocumentReportController.php b/app/Http/Controllers/Reports/DocumentReportController.php index 6ca4264caf8a..d0f4d3801715 100644 --- a/app/Http/Controllers/Reports/DocumentReportController.php +++ b/app/Http/Controllers/Reports/DocumentReportController.php @@ -13,7 +13,7 @@ namespace App\Http\Controllers\Reports; use App\Export\CSV\DocumentExport; use App\Http\Controllers\BaseController; -use App\Http\Requests\Report\ClientContactReportRequest; +use App\Http\Requests\Report\GenericReportRequest; use App\Utils\Traits\MakesHash; use Illuminate\Http\Response; @@ -60,7 +60,7 @@ class DocumentReportController extends BaseController * ), * ) */ - public function __invoke(ClientContactReportRequest $request) + public function __invoke(GenericReportRequest $request) { // expect a list of visible fields, or use the default diff --git a/app/Http/Controllers/Reports/PaymentReportController.php b/app/Http/Controllers/Reports/PaymentReportController.php new file mode 100644 index 000000000000..35e83bf60322 --- /dev/null +++ b/app/Http/Controllers/Reports/PaymentReportController.php @@ -0,0 +1,85 @@ +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/Payment.php b/app/Models/Payment.php index 873a54140e56..3e5e3fab974e 100644 --- a/app/Models/Payment.php +++ b/app/Models/Payment.php @@ -150,6 +150,26 @@ class Payment extends BaseModel return $this->belongsTo(PaymentType::class); } + public function currency() + { + return $this->belongsTo(Currency::class); + } + + public function exchange_currency() + { + return $this->belongsTo(Currency::class, 'exchange_currency_id', 'id'); + } + + public function vendor() + { + return $this->belongsTo(Vendor::class); + } + + public function project() + { + return $this->belongsTo(Project::class); + } + public function translatedType() { if(!$this->type) @@ -212,6 +232,34 @@ class Payment extends BaseModel } } + public static function stringStatus(int $status) + { + switch ($status) { + case self::STATUS_PENDING: + return ctrans('texts.payment_status_1'); + break; + case self::STATUS_CANCELLED: + return ctrans('texts.payment_status_2'); + break; + case self::STATUS_FAILED: + return ctrans('texts.payment_status_3'); + break; + case self::STATUS_COMPLETED: + return ctrans('texts.payment_status_4'); + break; + case self::STATUS_PARTIALLY_REFUNDED: + return ctrans('texts.payment_status_5'); + break; + case self::STATUS_REFUNDED: + return ctrans('texts.payment_status_6'); + break; + default: + return ''; + break; + } + } + + public function ledger() { return new LedgerService($this); diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php index 0070c05368a0..9b946d9ae1ae 100644 --- a/resources/lang/en/texts.php +++ b/resources/lang/en/texts.php @@ -4567,6 +4567,7 @@ $LANG = array( 'restore_company_gateway' => 'Restore payment gateway', 'archive_company_gateway' => 'Archive payment gateway', 'delete_company_gateway' => 'Delete payment gateway', + 'exchange_currency' => 'Exchange currency', ); return $LANG; diff --git a/routes/api.php b/routes/api.php index 36be817dfb5d..5681dae0a930 100644 --- a/routes/api.php +++ b/routes/api.php @@ -163,6 +163,7 @@ Route::group(['middleware' => ['throttle:300,1', 'api_db', 'token_auth', 'locale Route::post('reports/invoice_items', 'Reports\InvoiceItemReportController'); Route::post('reports/quotes', 'Reports\QuoteReportController'); Route::post('reports/recurring_invoices', 'Reports\RecurringInvoiceReportController'); + Route::post('reports/payments', 'Reports\PaymentReportController'); Route::get('scheduler', 'SchedulerController@index');