Merge pull request #3287 from CihanSenturk/fix-tax-summary-report-issue

Fix tax summary report issue
This commit is contained in:
Cihan Şentürk 2025-04-28 20:59:40 +03:00 committed by GitHub
commit b07c5dc62d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 137 additions and 14 deletions

View File

@ -304,6 +304,9 @@ abstract class Show extends Component
/** @var bool */
public $hideRecurringMessage;
/** @var bool */
public $hideConnectMessage;
/** @var bool */
public $hideCreated;
@ -335,7 +338,7 @@ abstract class Show extends Component
string $routeDocumentShow = '', string $routeTransactionShow = '', string $textButtonAddNew = '',
bool $hideSchedule = false, bool $hideChildren = false, bool $hideConnect = false, bool $hideTransfer = false, bool $hideAttachment = false, $attachment = [],
array $connectTranslations = [], string $textRecurringType = '', bool $hideRecurringMessage = false, bool $hideCreated = false
array $connectTranslations = [], string $textRecurringType = '', bool $hideRecurringMessage = false, $hideConnectMessage = false, bool $hideCreated = false
) {
$this->type = $type;
$this->transaction = $transaction;
@ -472,6 +475,7 @@ abstract class Show extends Component
// Connect translations
$this->connectTranslations = $this->getTranslationsForConnect($type);
$this->hideConnectMessage = $hideConnectMessage;
$this->textRecurringType = $this->getTextRecurringType($type, $textRecurringType);
$this->hideRecurringMessage = $hideRecurringMessage;

View File

@ -39,7 +39,7 @@ class Transactions extends Controller
{
$this->setActiveTabForTransactions();
$transactions = Transaction::with('account', 'category', 'contact')->collect(['paid_at'=> 'desc']);
$transactions = Transaction::with('account', 'category', 'contact', 'taxes')->collect(['paid_at'=> 'desc']);
$total_transactions = Transaction::count();
@ -395,7 +395,7 @@ class Transactions extends Controller
$translations = collect($this->getTranslationsForConnect($transaction->type));
$data = [
'transaction' => $transaction->load(['account', 'category'])->toJson(),
'transaction' => $transaction->load(['account', 'category', 'taxes'])->toJson(),
'currency' => $transaction->currency->toJson(),
'documents' => $documents,
'translations' => $translations->toJson(),

View File

@ -5,12 +5,13 @@ namespace App\Models\Banking;
use App\Abstracts\Model;
use App\Models\Banking\Transaction;
use App\Traits\Currencies;
use App\Traits\Transactions;
use Bkwld\Cloner\Cloneable;
use Illuminate\Database\Eloquent\Builder;
class TransactionTax extends Model
{
use Cloneable, Currencies;
use Cloneable, Currencies, Transactions;
protected $table = 'transaction_taxes';
@ -31,34 +32,92 @@ class TransactionTax extends Model
return $this->belongsTo('App\Models\Banking\Transaction')->withDefault(['name' => trans('general.na')]);
}
public function scopeType(Builder $query, string $type)
public function scopeType(Builder $query, $types): Builder
{
return $query->where($this->qualifyColumn('type'), '=', $type);
if (empty($types)) {
return $query;
}
return $query->whereIn($this->qualifyColumn('type'), (array) $types);
}
public function scopeIncome(Builder $query)
{
return $query->where($this->qualifyColumn('type'), '=', Transaction::INCOME_TYPE);
return $query->whereIn($this->qualifyColumn('type'), (array) $this->getIncomeTypes());
}
public function scopeIncomeTransfer(Builder $query): Builder
{
return $query->where($this->qualifyColumn('type'), '=', Transaction::INCOME_TRANSFER_TYPE);
}
public function scopeIncomeRecurring(Builder $query): Builder
{
return $query->where($this->qualifyColumn('type'), '=', Transaction::INCOME_RECURRING_TYPE)
->whereHas('document.recurring', function (Builder $query) {
$query->whereNull('deleted_at');
});
->whereHas('transaction.recurring', function (Builder $query) {
$query->whereNull('deleted_at');
});
}
public function scopeExpense(Builder $query)
{
return $query->where($this->qualifyColumn('type'), '=', Transaction::EXPENSE_TYPE);
return $query->whereIn($this->qualifyColumn('type'), (array) $this->getExpenseTypes());
}
public function scopeExpenseTransfer(Builder $query): Builder
{
return $query->where($this->qualifyColumn('type'), '=', Transaction::EXPENSE_TRANSFER_TYPE);
}
public function scopeExpenseRecurring(Builder $query): Builder
{
return $query->where($this->qualifyColumn('type'), '=', Transaction::EXPENSE_RECURRING_TYPE)
->whereHas('document.recurring', function (Builder $query) {
$query->whereNull('deleted_at');
});
->whereHas('transaction.recurring', function (Builder $query) {
$query->whereNull('deleted_at');
});
}
public function scopeIsTransfer(Builder $query): Builder
{
return $query->where($this->qualifyColumn('type'), 'like', '%-transfer');
}
public function scopeIsNotTransfer(Builder $query): Builder
{
return $query->where($this->qualifyColumn('type'), 'not like', '%-transfer');
}
public function scopeIsRecurring(Builder $query): Builder
{
return $query->where($this->qualifyColumn('type'), 'like', '%-recurring');
}
public function scopeIsNotRecurring(Builder $query): Builder
{
return $query->where($this->qualifyColumn('type'), 'not like', '%-recurring');
}
public function scopeIsSplit(Builder $query): Builder
{
return $query->where($this->qualifyColumn('type'), 'like', '%-split');
}
public function scopeIsNotSplit(Builder $query): Builder
{
return $query->where($this->qualifyColumn('type'), 'not like', '%-split');
}
public function scopeIsDocument(Builder $query): Builder
{
return $query->whereHas('transaction', function ($q) {
$q->whereNotNull('document_id');
});
}
public function scopeIsNotDocument(Builder $query): Builder
{
return $query->whereHas('transaction', function ($q) {
$q->whereNull('document_id');
});
}
}

View File

@ -4,6 +4,7 @@ namespace App\Reports;
use App\Abstracts\Report;
use App\Models\Banking\Transaction;
use App\Models\Banking\TransactionTax;
use App\Models\Document\Document;
use App\Models\Setting\Tax;
use App\Traits\Currencies;
@ -68,6 +69,14 @@ class TaxSummary extends Report
break;
}
// Incomes
$incomes = $this->applyFilters(Transaction::with('taxes')->income()->isNotDocument()->isNotTransfer(), ['date_field' => 'paid_at'])->get();
$this->setTotals($incomes, 'paid_at');
// Expenses
$expenses = $this->applyFilters(Transaction::with('taxes')->expense()->isNotDocument()->isNotTransfer(), ['date_field' => 'paid_at'])->get();
$this->setTotals($expenses, 'paid_at');
}
public function setTotals($items, $date_field, $check_type = false, $table = 'default', $with_tax = true)
@ -78,6 +87,11 @@ class TaxSummary extends Report
$type = ($item->type === Document::INVOICE_TYPE || $item->type === 'income') ? 'income' : 'expense';
if ($item instanceof Transaction && empty($item->document_id)) {
$this->setTransactionTaxTotal($item, $type, $date_field);
continue;
}
$date = $this->getFormattedDate(Date::parse($item->$date_field));
if ($date_field == 'paid_at') {
@ -122,6 +136,36 @@ class TaxSummary extends Report
}
}
public function setTransactionTaxTotal($item, $type, $date_field)
{
if (empty($item->taxes)) {
return;
}
$date = $this->getFormattedDate(Date::parse($item->$date_field));
foreach ($item->taxes as $tax) {
if (
!isset($this->row_values[$tax->name][$type][$date])
|| !isset($this->footer_totals[$tax->name][$date])
) {
continue;
}
$amount = $this->convertToDefault($tax->amount, $item->currency_code, $item->currency_rate);
if ($type == 'income') {
$this->row_values[$tax->name][$type][$date] += $amount;
$this->footer_totals[$tax->name][$date] += $amount;
} else {
$this->row_values[$tax->name][$type][$date] -= $amount;
$this->footer_totals[$tax->name][$date] -= $amount;
}
}
}
public function getFields()
{
return [

View File

@ -192,6 +192,7 @@ trait Transactions
'add_an' => trans('general.form.add_an', ['field' => trans_choice('general.' . Str::plural($document_type), 1)]),
'transaction' => trans_choice('general.' . Str::plural($type), 1),
'difference' => trans('general.difference'),
'connect_tax' => trans('messages.warning.connect_tax', ['type' => $type]),
];
}

View File

@ -21,6 +21,11 @@
</button>
</slot>
</div>
<div v-if="transaction && transaction.taxes.length" class="rounded-xl px-5 py-3 mt-4 bg-orange-100">
<p class="text-sm mb-0 text-orange-600">
{{ translations.connect_tax }}
</p>
</div>
</div>
<slot name="modal-body">

View File

@ -46,6 +46,7 @@ return [
'disable_code' => 'Warning: You are not allowed to disable or change the currency of <b>:name</b> because it has :text related.',
'payment_cancel' => 'Warning: You have cancelled your recent :method payment!',
'missing_transfer' => 'Warning: The transfer related to this transaction is missing. You should consider deleting this transaction.',
'connect_tax' => 'Warning: This :type has a tax amount. Taxes added to the :type can not be connected, so the tax will be added to the total and calculated accordingly.',
],
];

View File

@ -12,6 +12,7 @@ return [
'recurring_expense' => 'Recurring Expense',
'included_tax' => 'Included tax amount',
'connected' => 'Connected',
'connect_message' => 'Taxes for this :type were not calculated during the connection process. Taxes can not be connected.',
'form_description' => [
'general' => 'Here you can enter the general information of transaction such as date, amount, account, description, etc.',

View File

@ -28,6 +28,14 @@
@stack('recurring_message_end')
@stack('connect_message_start')
@if (! $hideConnectMessage && $transaction->isSplitTransaction() && $transaction->taxes->count())
<x-documents.show.message type="connect" background-color="bg-orange-100" text-color="text-orange-600" message="{{ trans('transactions.connect_message', ['type' => Str::plural($type), 1]) }}" />
@endif
@stack('connect_message_end')
@stack('row_create_start')
@if (! $hideCreated)
<x-transactions.show.create