TaxReports

This commit is contained in:
David Bomba 2025-08-06 13:20:09 +10:00
parent e204862488
commit b78ba2b1fc
8 changed files with 297 additions and 320 deletions

View File

@ -0,0 +1,83 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2025. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\Http\Controllers\Reports;
use App\Http\Controllers\BaseController;
use App\Http\Requests\Report\GenericReportRequest;
use App\Jobs\Report\PreviewReport;
use App\Jobs\Report\SendToAdmin;
use App\Services\Report\TaxPeriodReport;
use App\Utils\Traits\MakesHash;
class TaxPeriodReportController extends BaseController
{
use MakesHash;
private string $filename = 'tax_period.xlsx';
public function __construct()
{
parent::__construct();
}
/**
* @OA\Post(
* path="/api/v1/reports/tasks",
* operationId="getTaskReport",
* tags={"reports"},
* summary="Task reports",
* description="Export task reports",
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\RequestBody(
* required=true,
* @OA\JsonContent(ref="#/components/schemas/GenericReportSchema")
* ),
* @OA\Response(
* response=200,
* description="success",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
* ),
* @OA\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
*/
public function __invoke(GenericReportRequest $request)
{
/** @var \App\Models\User $user */
$user = auth()->user();
if ($request->has('send_email') && $request->get('send_email') && $request->missing('output')) {
SendToAdmin::dispatch($user->company(), $request->all(), TaxPeriodReport::class, $this->filename);
return response()->json(['message' => 'working...'], 200);
}
$hash = \Illuminate\Support\Str::uuid();
PreviewReport::dispatch($user->company(), $request->all(), TaxPeriodReport::class, $hash);
return response()->json(['message' => $hash], 200);
}
}

View File

@ -26,7 +26,7 @@ use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use App\Listeners\Invoice\InvoiceTransactionEventEntry;
use App\Listeners\Invoice\InvoiceTransactionEventEntryAccrual;
use App\Listeners\Invoice\InvoiceTransactionEventEntryCash;
class InvoiceTaxSummary implements ShouldQueue
{
@ -165,7 +165,7 @@ class InvoiceTaxSummary implements ShouldQueue
Invoice::withTrashed()
->with('payments')
->where('company_id', $company->id)
->whereIn('status_id', [3,4,5]) // Paid statuses
->whereIn('status_id', [3,4]) // Paid statuses
->where('is_deleted', 0)
->whereColumn('amount', '!=', 'balance')
->whereHas('client', function ($query) {
@ -190,7 +190,7 @@ class InvoiceTaxSummary implements ShouldQueue
})
->cursor()
->each(function (Invoice $invoice) use ($startDate, $endDate) {
(new InvoiceTransactionEventEntryAccrual())->run($invoice, $startDate, $endDate);
(new InvoiceTransactionEventEntryCash())->run($invoice, $startDate, $endDate);
});
}

View File

@ -37,10 +37,12 @@ class InvoiceTransactionEventEntry
* @param Invoice $invoice
* @return void
*/
public function run($invoice)
public function run(Invoice $invoice, ?string $force_period = null)
{
$this->setPaidRatio($invoice);
$period = $force_period ?? now()->endOfMonth()->format('Y-m-d');
$this->payments = $invoice->payments->flatMap(function ($payment) {
return $payment->invoices()->get()->map(function ($invoice) use ($payment) {
return [
@ -66,7 +68,7 @@ class InvoiceTransactionEventEntry
'event_id' => TransactionEvent::INVOICE_UPDATED,
'timestamp' => now()->timestamp,
'metadata' => $this->getMetadata($invoice),
'period' => now()->endOfMonth()->format('Y-m-d'),
'period' => $period,
]);
}

View File

@ -1,227 +0,0 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2025. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\Listeners\Invoice;
use App\Models\Invoice;
use App\Models\Activity;
use App\Models\TransactionEvent;
use Illuminate\Support\Collection;
use App\DataMapper\TaxReport\TaxDetail;
use App\DataMapper\TaxReport\TaxReport;
use App\DataMapper\TaxReport\TaxSummary;
use App\Repositories\ActivityRepository;
use Illuminate\Contracts\Queue\ShouldQueue;
use App\DataMapper\TransactionEventMetadata;
use Illuminate\Queue\Middleware\WithoutOverlapping;
class InvoiceTransactionEventEntryAccrual
{
private Collection $payments;
private float $paid_ratio;
/**
* Handle the event.
*
* @param Invoice $invoice
* @return void
*/
public function run($invoice, $start_date, $end_date)
{
$this->setPaidRatio($invoice);
$this->payments = $invoice->payments->flatMap(function ($payment) use ($start_date, $end_date) {
return $payment->invoices()->get()->map(function ($invoice) use ($payment) {
return [
'number' => $payment->number,
'amount' => $invoice->pivot->amount,
'refunded' => $invoice->pivot->refunded,
'date' => $invoice->pivot->created_at->format('Y-m-d'),
];
})->filter(function ($payment) use ($start_date, $end_date) {
// Filter payments where the pivot created_at is within the date boundaries
return \Carbon\Carbon::parse($payment['date'])->isBetween($start_date, $end_date);
});
});
TransactionEvent::create([
'invoice_id' => $invoice->id,
'client_id' => $invoice->client_id,
'client_balance' => $invoice->client->balance,
'client_paid_to_date' => $invoice->client->paid_to_date,
'client_credit_balance' => $invoice->client->credit_balance,
'invoice_balance' => $invoice->balance ?? 0,
'invoice_amount' => $invoice->amount ?? 0 ,
'invoice_partial' => $invoice->partial ?? 0,
'invoice_paid_to_date' => $invoice->paid_to_date ?? 0,
'invoice_status' => $invoice->is_deleted ? 7 : $invoice->status_id,
'event_id' => TransactionEvent::PAYMENT_CASH,
'timestamp' => now()->timestamp,
'metadata' => $this->getMetadata($invoice),
'period' => now()->endOfMonth()->format('Y-m-d'),
]);
}
private function setPaidRatio(Invoice $invoice): self
{
if ($invoice->amount == 0) {
$this->paid_ratio = 0;
return $this;
}
$this->paid_ratio = $invoice->paid_to_date / $invoice->amount;
return $this;
}
private function calculateRatio(float $amount): float
{
return round($amount * $this->paid_ratio, 2);
}
/**
* Existing tax details are not deleted, but pending taxes are set to 0
*
* @param mixed $invoice
*/
private function getCancelledMetaData($invoice)
{
$calc = $invoice->calc();
$details = [];
$taxes = array_merge($calc->getTaxMap()->merge($calc->getTotalTaxMap())->toArray());
foreach ($taxes as $tax) {
$tax_detail = [
'tax_name' => $tax['name'],
'tax_rate' => $tax['tax_rate'],
'taxable_amount' => $tax['base_amount'] ?? $calc->getNetSubtotal(),
'tax_amount' => $this->calculateRatio($tax['total']),
'tax_amount_paid' => $this->calculateRatio($tax['total']),
'tax_amount_remaining' => 0,
];
$details[] = $tax_detail;
}
return new TransactionEventMetadata([
'tax_report' => [
'tax_details' => $details,
'payment_history' => $this->payments->toArray(),
'tax_summary' => [
'total_taxes' => $invoice->total_taxes,
'total_paid' => $this->getTotalTaxPaid($invoice),
'status' => 'cancelled',
],
],
]);
}
/**
* Set all tax details to 0
*
* @param mixed $invoice
*/
private function getDeletedMetaData($invoice)
{
$calc = $invoice->calc();
$details = [];
$taxes = array_merge($calc->getTaxMap()->merge($calc->getTotalTaxMap())->toArray());
foreach ($taxes as $tax) {
$tax_detail = [
'tax_name' => $tax['name'],
'tax_rate' => $tax['tax_rate'],
'taxable_amount' => $tax['base_amount'] ?? $calc->getNetSubtotal(),
'tax_amount' => $tax['total'],
'tax_amount_paid' => $this->calculateRatio($tax['total']),
'tax_amount_remaining' => 0,
];
$details[] = $tax_detail;
}
return new TransactionEventMetadata([
'tax_report' => [
'tax_details' => $details,
'payment_history' => $this->payments->toArray(),
'tax_summary' => [
'total_taxes' => $invoice->total_taxes,
'total_paid' => $this->getTotalTaxPaid($invoice),0,
'status' => 'deleted',
],
],
]);
}
private function getMetadata($invoice)
{
// if ($invoice->status_id == Invoice::STATUS_CANCELLED) {
// return $this->getCancelledMetaData($invoice);
// } elseif ($invoice->is_deleted) {
// return $this->getDeletedMetaData($invoice);
// }
$calc = $invoice->calc();
$details = [];
$taxes = array_merge($calc->getTaxMap()->merge($calc->getTotalTaxMap())->toArray());
foreach ($taxes as $tax) {
$tax_detail = [
'tax_name' => $tax['name'],
'tax_rate' => $tax['tax_rate'],
'taxable_amount' => $tax['base_amount'] ?? $calc->getNetSubtotal(),
'tax_amount' => $tax['total'],
'tax_amount_paid' => $this->calculateRatio($tax['total']),
'tax_amount_remaining' => $tax['total'] - $this->calculateRatio($tax['total']),
];
$details[] = $tax_detail;
}
return new TransactionEventMetadata([
'tax_report' => [
'tax_details' => $details,
'payment_history' => $this->payments->toArray(),
'tax_summary' => [
'total_taxes' => $invoice->total_taxes,
'total_paid' => $this->getTotalTaxPaid($invoice),
'status' => 'updated',
],
],
]);
}
private function getTotalTaxPaid($invoice)
{
if ($invoice->amount == 0) {
return 0;
}
$total_paid = $this->payments->sum('amount') - $this->payments->sum('refunded');
return round($invoice->total_taxes * ($total_paid / $invoice->amount), 2);
}
}

View File

@ -1,21 +1,41 @@
<?php
namespace App\Services\Report\XLS;
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2025. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
use Carbon\Carbon;
namespace App\Services\Report;
use App\Models\User;
use App\Utils\Ninja;
use App\Utils\Number;
use App\Models\Client;
use League\Csv\Writer;
use App\Models\Company;
use App\Models\Invoice;
use App\Libraries\MultiDB;
use App\Export\CSV\BaseExport;
use App\Utils\Traits\MakesDates;
use Illuminate\Support\Facades\App;
use App\Services\Report\TaxSummaryReport;
use App\Services\Template\TemplateService;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Builder;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use App\Models\Invoice;
use App\Listeners\Invoice\InvoiceTransactionEventEntry;
use App\Models\TransactionEvent;
class TaxReport
class TaxPeriodReport extends BaseExport
{
use MakesDates;
private Spreadsheet $spreadsheet;
private array $data = [];
@ -24,36 +44,178 @@ class TaxReport
private string $number_format;
public function __construct(public Company $company, private string $start_date, private string $end_date)
//is_income_billed = accrual
//!is_invoice_billed = cash
/**
@param array $input
[
'date_range',
'start_date',
'end_date',
'client_id',
]
*/
public function __construct(public Company $company, public array $input)
{
}
public function run()
{
$this->start_date = Carbon::parse($this->start_date);
$this->end_date = Carbon::parse($this->end_date);
MultiDB::setDb($this->company->db);
App::forgetInstance('translator');
App::setLocale($this->company->locale());
$t = app('translator');
$t->replace(Ninja::transformTranslations($this->company->settings));
$this->spreadsheet = new Spreadsheet();
$this->buildData()
->setCurrencyFormat()
->createSummarySheet()
->createInvoiceSummarySheetAccrual()
->createInvoiceSummarySheetCash()
->createInvoiceItemSummarySheetAccrual()
->createInvoiceItemSummarySheetCash();
return $this;
$this->calculateDateRange()
->initializeData()
->buildData();
}
/**
* initializeData
*
* Ensure our dataset has the appropriate transaction events.
*
* @return self
*/
private function initializeData(): self
{
Invoice::withTrashed()
->where('company_id', $this->company->id)
->where('is_deleted', 0)
->whereIn('status_id', [2,3,4,5])
->whereBetween('date', ['1970-01-01', now()->subMonth()->endOfMonth()->format('Y-m-d')])
->whereDoesntHave('transaction_events')
->cursor()
->each(function($invoice){
if($invoice->status_id == Invoice::STATUS_SENT){
(new InvoiceTransactionEventEntry())->run($invoice, \Carbon\Carbon::parse($invoice->date)->endOfMonth()->format('Y-m-d'));
}
elseif(in_array($invoice->status_id, [Invoice::STATUS_PAID, Invoice::STATUS_PARTIAL])){
}
});
return $this;
}
private function resolveQuery()
{
$query = Invoice::query()
->withTrashed()
->with('transaction_events')
->where('company_id', $this->company->id)
->where('is_deleted', 0);
if($this->input['is_income_billed']) //acrrual
{
$query->whereIn('status_id', [2,3,4])
->whereHas('transaction_events', function($query){
$query->where('event_id', TransactionEvent::INVOICE_UPDATED)
->whereBetween('period', [$this->start_date, $this->end_date]);
});
}
else //cash
{
$query->whereIn('status_id', [3,4])
->whereHas('transaction_events', function($query){
$query->where('event_id', TransactionEvent::PAYMENT_CASH)
->whereBetween('period', [$this->start_date, $this->end_date]);
});
}
$query->orderBy('balance', 'desc');
return $query;
}
/**
* calculateDateRange
*
* We only support dates as of the end of the last month.
* @return self
*/
private function calculateDateRange(): self
{
switch ($date_range) {
case 'last7':
case 'last30':
case 'this_month':
case 'last_month':
$this->start_date = now()->startOfMonth()->subMonth()->format('Y-m-d');
$this->end_date = now()->startOfMonth()->subMonth()->endOfMonth()->format('Y-m-d');
case 'this_quarter':
$this->start_date = (new \Carbon\Carbon('0 months'))->startOfQuarter()->format('Y-m-d');
$this->end_date = (new \Carbon\Carbon('0 months'))->endOfQuarter()->format('Y-m-d');
case 'last_quarter':
$this->start_date = (new \Carbon\Carbon('-3 months'))->startOfQuarter()->format('Y-m-d');
$this->end_date = (new \Carbon\Carbon('-3 months'))->endOfQuarter()->format('Y-m-d');
case 'last365_days':
$this->start_date = now()->startOfDay()->subDays(365)->format('Y-m-d');
$this->end_date = now()->startOfDay()->format('Y-m-d');
case 'this_year':
$first_month_of_year = $this->company->first_month_of_year ?? 1;
$fin_year_start = now()->createFromDate(now()->year, $first_month_of_year, 1);
if (now()->lt($fin_year_start)) {
$fin_year_start->subYearNoOverflow();
}
$this->start_date = $fin_year_start->format('Y-m-d');
$this->end_date = $fin_year_start->copy()->addYear()->subDay()->format('Y-m-d');
case 'last_year':
$first_month_of_year = $this->company->first_month_of_year ?? 1;
$fin_year_start = now()->createFromDate(now()->year, $first_month_of_year, 1);
$fin_year_start->subYearNoOverflow();
if (now()->subYear()->lt($fin_year_start)) {
$fin_year_start->subYearNoOverflow();
}
$this->start_date = $fin_year_start->format('Y-m-d');
$this->end_date = $fin_year_start->copy()->addYear()->subDay()->format('Y-m-d');
case 'custom':
try {
$custom_start_date = Carbon::parse($this->input['start_date']);
$custom_end_date = Carbon::parse($this->input['end_date']);
} catch (\Exception $e) {
$custom_start_date = now()->startOfYear();
$custom_end_date = now();
}
$this->start_date = $custom_start_date->format('Y-m-d');
$this->end_date = $custom_end_date->format('Y-m-d');
case 'all':
default:
$this->start_date = now()->startOfYear()->format('Y-m-d');
$this->end_date = now()->format('Y-m-d');
}
return $this;
}
public function accrual()
{
}
public function cash()
{
}
public function getXlsFile()
{
}
public function setCurrencyFormat()
{
@ -82,7 +244,7 @@ class TaxReport
}
// All invoices within a time period - regardless if they are paid or not!
public function createInvoiceSummarySheetAccrual()
public function createInvoiceSummarySheet()
{
$worksheet = $this->spreadsheet->createSheet();
@ -98,24 +260,7 @@ class TaxReport
return $this;
}
// All paid invoices within a time period
public function createInvoiceSummarySheetCash()
{
$worksheet = $this->spreadsheet->createSheet();
$worksheet->setTitle(ctrans('texts.invoice')." ".ctrans('texts.cash_accounting'));
$worksheet->fromArray($this->data['cash']['invoices'], null, 'A1');
$worksheet->getStyle('B:B')->getNumberFormat()->setFormatCode($this->company->date_format()); // Invoice date column
$worksheet->getStyle('C:C')->getNumberFormat()->setFormatCode($this->currency_format); // Invoice total column
$worksheet->getStyle('D:D')->getNumberFormat()->setFormatCode($this->currency_format); // Paid amount column
$worksheet->getStyle('E:E')->getNumberFormat()->setFormatCode($this->currency_format); // Total taxes column
$worksheet->getStyle('F:F')->getNumberFormat()->setFormatCode($this->currency_format); // Tax paid column
return $this;
}
public function createInvoiceItemSummarySheetAccrual()
public function createInvoiceItemSummarySheet()
{
$worksheet = $this->spreadsheet->createSheet();
@ -134,30 +279,11 @@ class TaxReport
return $this;
}
public function createInvoiceItemSummarySheetCash()
{
$worksheet = $this->spreadsheet->createSheet();
$worksheet->setTitle(ctrans('texts.invoice_item')." ".ctrans('texts.cash_accounting'));
$worksheet->fromArray($this->data['cash']['invoice_items'], null, 'A1');
$worksheet->getStyle('B:B')->getNumberFormat()->setFormatCode($this->company->date_format()); // Invoice date column
$worksheet->getStyle('C:C')->getNumberFormat()->setFormatCode($this->currency_format); // Invoice total column
$worksheet->getStyle('D:D')->getNumberFormat()->setFormatCode($this->currency_format); // Paid amount column
$worksheet->getStyle('F:F')->getNumberFormat()->setFormatCode($this->number_format."%"); // Tax rate column
$worksheet->getStyle('G:G')->getNumberFormat()->setFormatCode($this->currency_format); // Tax amount column
$worksheet->getStyle('H:H')->getNumberFormat()->setFormatCode($this->currency_format); // Tax paid column
$worksheet->getStyle('I:I')->getNumberFormat()->setFormatCode($this->currency_format); // Taxable amount column
// Column J (tax_nexus) is text, so no special formatting needed
return $this;
}
private function buildData()
{
$start_date_instance = $this->start_date;
$end_date_instance = $this->end_date;
$query = $this->resolveQuery();
$this->data['invoices'] = [];
$this->data['invoices'][] =
@ -192,20 +318,9 @@ class TaxReport
$this->data['cash']['invoice_items'] = [$invoice_item_headers];
Invoice::withTrashed()
->with('transaction_events')
->where('company_id', $this->company->id)
->whereHas('transaction_events', function ($query){
return $query->where('period', now()->endOfMonth()->format('Y-m-d'));
})
->cursor()
$query->cursor()
->each(function($invoice){
if($invoice->transaction_events->count() == 0){
(new InvoiceTransactionEventEntry())->run($invoice);
$invoice->load('transaction_events');
}
/** @var TransactionEvent $invoice_state */
$invoice_state = $invoice->transaction_events()->where('event_id', TransactionEvent::INVOICE_UPDATED)->where('period', now()->endOfMonth()->format('Y-m-d'))->orderBy('timestamp', 'desc')->first();
$payment_state = $invoice->transaction_events()->where('event_id', TransactionEvent::PAYMENT_CASH)->where('period', now()->endOfMonth()->format('Y-m-d'))->orderBy('timestamp', 'desc')->first();
@ -281,4 +396,5 @@ class TaxReport
return $fileContent;
}
}

View File

@ -5613,6 +5613,7 @@ $lang = array(
'include_project_tasks' => 'Include Project Tasks',
'include_project_tasks_help' => 'Also invoice tasks that are part of a project',
'tax_nexus' => 'Tax Nexus',
'tax_period_report' => 'Tax Period Report',
);
return $lang;

View File

@ -116,6 +116,7 @@ use App\Http\Controllers\Reports\ARDetailReportController;
use App\Http\Controllers\Reports\DocumentReportController;
use App\Http\Controllers\Reports\ARSummaryReportController;
use App\Http\Controllers\Reports\QuoteItemReportController;
use App\Http\Controllers\Reports\TaxPeriodReportController;
use App\Http\Controllers\Reports\UserSalesReportController;
use App\Http\Controllers\Reports\TaxSummaryReportController;
use App\Http\Controllers\Support\Messages\SendingController;
@ -372,6 +373,7 @@ Route::group(['middleware' => ['throttle:api', 'token_auth', 'valid_json','local
Route::post('reports/client_balance_report', ClientBalanceReportController::class);
Route::post('reports/client_sales_report', ClientSalesReportController::class);
Route::post('reports/tax_summary_report', TaxSummaryReportController::class);
Route::post('reports/tax_period_report', TaxPeriodReportController::class);
Route::post('reports/user_sales_report', UserSalesReportController::class);
Route::post('reports/projects', ProjectReportController::class);
Route::post('reports/preview/{hash}', ReportPreviewController::class);

View File

@ -24,7 +24,7 @@ use App\Factory\InvoiceItemFactory;
use App\Services\Report\TaxSummaryReport;
use Illuminate\Routing\Middleware\ThrottleRequests;
use App\Listeners\Invoice\InvoiceTransactionEventEntry;
use App\Listeners\Invoice\InvoiceTransactionEventEntryAccrual;
use App\Listeners\Invoice\InvoiceTransactionEventEntryCash;
/**
*
@ -226,7 +226,7 @@ class TaxSummaryReportTest extends TestCase
$this->assertEquals($i3->amount, $i3->paid_to_date);
(new InvoiceTransactionEventEntryAccrual())->run($i3, now()->subDays(30)->format('Y-m-d'), now()->addDays(30)->format('Y-m-d'));
(new InvoiceTransactionEventEntryCash())->run($i3, now()->subDays(30)->format('Y-m-d'), now()->addDays(30)->format('Y-m-d'));
}
@ -268,7 +268,7 @@ class TaxSummaryReportTest extends TestCase
$i2 = $i2->fresh();
(new InvoiceTransactionEventEntryAccrual())->run($i2, now()->subDays(30)->format('Y-m-d'), now()->addDays(30)->format('Y-m-d'));
(new InvoiceTransactionEventEntryCash())->run($i2, now()->subDays(30)->format('Y-m-d'), now()->addDays(30)->format('Y-m-d'));
$payment = $i2->payments()->first();
@ -294,18 +294,18 @@ class TaxSummaryReportTest extends TestCase
$payment->refund($data);
$pl = new \App\Services\Report\XLS\TaxReport($this->company, '2025-01-01', '2025-12-31');
// $pl = new \App\Services\Report\XLS\TaxReport($this->company, '2025-01-01', '2025-12-31');
$response = $pl->run()->getXlsFile();
// $response = $pl->run()->getXlsFile();
$this->assertIsString($response);
// $this->assertIsString($response);
try{
file_put_contents('/home/david/ttx.xlsx', $response);
}
catch(\Throwable $e){
nlog($e->getMessage());
}
// try{
// file_put_contents('/home/david/ttx.xlsx', $response);
// }
// catch(\Throwable $e){
// nlog($e->getMessage());
// }
config(['queue.default' => 'redis']);
@ -376,7 +376,7 @@ class TaxSummaryReportTest extends TestCase
$i2 = $i2->calc()->getInvoice();
$i2->service()->markPaid();
(new InvoiceTransactionEventEntryAccrual())->run($i2, now()->subDays(3000)->format('Y-m-d'), now()->addDays(3000)->format('Y-m-d'));
(new InvoiceTransactionEventEntryCash())->run($i2, now()->subDays(3000)->format('Y-m-d'), now()->addDays(3000)->format('Y-m-d'));
$pl = new TaxSummaryReport($this->company, $this->payload);
$response = $pl->run();
@ -449,12 +449,12 @@ class TaxSummaryReportTest extends TestCase
$i2 = $i2->calc()->getInvoice();
$i2->service()->markPaid()->save();
(new InvoiceTransactionEventEntryAccrual())->run($i2, now()->subDays(30)->format('Y-m-d'), now()->addDays(30)->format('Y-m-d'));
(new InvoiceTransactionEventEntryCash())->run($i2, now()->subDays(30)->format('Y-m-d'), now()->addDays(30)->format('Y-m-d'));
$tr = new \App\Services\Report\XLS\TaxReport($this->company, '2025-01-01', '2025-12-31');
$response = $tr->run()->getXlsFile();
// $tr = new \App\Services\Report\XLS\TaxReport($this->company, '2025-01-01', '2025-12-31');
// $response = $tr->run()->getXlsFile();
$this->assertNotEmpty($response);
// $this->assertNotEmpty($response);
$this->assertNotNull(TransactionEvent::where('invoice_id', $i->id)->first());
$this->assertNotNull(TransactionEvent::where('invoice_id', $i2->id)->first());