Accrual listeners
This commit is contained in:
parent
33c5b90dce
commit
6895a2c9a0
|
|
@ -12,19 +12,21 @@
|
||||||
|
|
||||||
namespace App\Jobs\Cron;
|
namespace App\Jobs\Cron;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use App\Models\Company;
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
use App\Models\Webhook;
|
use App\Models\Webhook;
|
||||||
use App\Models\Company;
|
|
||||||
use App\Models\Timezone;
|
use App\Models\Timezone;
|
||||||
use App\Libraries\MultiDB;
|
use App\Libraries\MultiDB;
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
use App\Jobs\Entity\EmailEntity;
|
use App\Jobs\Entity\EmailEntity;
|
||||||
|
use App\Models\TransactionEvent;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
use Carbon\Carbon;
|
|
||||||
use App\Listeners\Invoice\InvoiceTransactionEventEntry;
|
use App\Listeners\Invoice\InvoiceTransactionEventEntry;
|
||||||
|
use App\Listeners\Invoice\InvoiceTransactionEventEntryAccrual;
|
||||||
|
|
||||||
class InvoiceTaxSummary implements ShouldQueue
|
class InvoiceTaxSummary implements ShouldQueue
|
||||||
{
|
{
|
||||||
|
|
@ -51,7 +53,6 @@ class InvoiceTaxSummary implements ShouldQueue
|
||||||
$companies = $this->getCompaniesInTimezones($transitioningTimezones);
|
$companies = $this->getCompaniesInTimezones($transitioningTimezones);
|
||||||
|
|
||||||
foreach ($companies as $company) {
|
foreach ($companies as $company) {
|
||||||
|
|
||||||
$this->processCompanyTaxSummary($company);
|
$this->processCompanyTaxSummary($company);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -64,6 +65,7 @@ class InvoiceTaxSummary implements ShouldQueue
|
||||||
// Get all timezones from the database
|
// Get all timezones from the database
|
||||||
$timezones = app('timezones');
|
$timezones = app('timezones');
|
||||||
|
|
||||||
|
/** @var \App\Models\Timezone $timezone */
|
||||||
foreach ($timezones as $timezone) {
|
foreach ($timezones as $timezone) {
|
||||||
// Calculate the current UTC offset for this timezone (accounting for DST)
|
// Calculate the current UTC offset for this timezone (accounting for DST)
|
||||||
$currentOffset = $this->getCurrentUtcOffset($timezone->name);
|
$currentOffset = $this->getCurrentUtcOffset($timezone->name);
|
||||||
|
|
@ -152,11 +154,45 @@ class InvoiceTaxSummary implements ShouldQueue
|
||||||
->whereBetween('date', [$startDate, $endDate])
|
->whereBetween('date', [$startDate, $endDate])
|
||||||
->whereDoesntHave('transaction_events', function ($query) use ($todayStart, $todayEnd) {
|
->whereDoesntHave('transaction_events', function ($query) use ($todayStart, $todayEnd) {
|
||||||
$query->where('timestamp', '>=', $todayStart)
|
$query->where('timestamp', '>=', $todayStart)
|
||||||
->where('timestamp', '<=', $todayEnd);
|
->where('timestamp', '<=', $todayEnd)
|
||||||
|
->where('event_id', TransactionEvent::INVOICE_UPDATED);
|
||||||
})
|
})
|
||||||
->cursor()
|
->cursor()
|
||||||
->each(function (Invoice $invoice) {
|
->each(function (Invoice $invoice) {
|
||||||
(new InvoiceTransactionEventEntry())->run($invoice);
|
(new InvoiceTransactionEventEntry())->run($invoice);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Invoice::withTrashed()
|
||||||
|
->with('payments')
|
||||||
|
->where('company_id', $company->id)
|
||||||
|
->whereIn('status_id', [3,4,5]) // Paid statuses
|
||||||
|
->where('is_deleted', 0)
|
||||||
|
->whereColumn('amount', '!=', 'balance')
|
||||||
|
->whereHas('client', function ($query) {
|
||||||
|
$query->where('is_deleted', false);
|
||||||
|
})
|
||||||
|
->whereHas('company', function ($query) {
|
||||||
|
$query->where('is_disabled', 0)
|
||||||
|
->whereHas('account', function ($q) {
|
||||||
|
$q->where('is_flagged', false);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
->whereHas('payments', function ($query) use ($startDate, $endDate) {
|
||||||
|
$query->whereHas('paymentables', function ($subQuery) use ($startDate, $endDate) {
|
||||||
|
$subQuery->where('paymentable_type', Invoice::class)
|
||||||
|
->whereBetween('created_at', [$startDate . ' 00:00:00', $endDate . ' 23:59:59']);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
->whereDoesntHave('transaction_events', function ($q) use ($todayStart, $todayEnd) {
|
||||||
|
$q->where('event_id', TransactionEvent::PAYMENT_CASH)
|
||||||
|
->where('timestamp', '>=', $todayStart)
|
||||||
|
->where('timestamp', '<=', $todayEnd);
|
||||||
|
})
|
||||||
|
->cursor()
|
||||||
|
->each(function (Invoice $invoice) use ($startDate, $endDate) {
|
||||||
|
(new InvoiceTransactionEventEntryAccrual())->run($invoice, $startDate, $endDate);
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -64,7 +64,7 @@ class InvoiceTransactionEventEntry
|
||||||
'invoice_partial' => $invoice->partial ?? 0,
|
'invoice_partial' => $invoice->partial ?? 0,
|
||||||
'invoice_paid_to_date' => $invoice->paid_to_date ?? 0,
|
'invoice_paid_to_date' => $invoice->paid_to_date ?? 0,
|
||||||
'invoice_status' => $invoice->is_deleted ? 7 : $invoice->status_id,
|
'invoice_status' => $invoice->is_deleted ? 7 : $invoice->status_id,
|
||||||
'event_id' => $invoice->is_deleted ? TransactionEvent::INVOICE_DELETED : TransactionEvent::INVOICE_UPDATED,
|
'event_id' => TransactionEvent::INVOICE_UPDATED,
|
||||||
'timestamp' => now()->timestamp,
|
'timestamp' => now()->timestamp,
|
||||||
'metadata' => $this->getMetadata($invoice),
|
'metadata' => $this->getMetadata($invoice),
|
||||||
'period' => now()->endOfMonth()->format('Y-m-d'),
|
'period' => now()->endOfMonth()->format('Y-m-d'),
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,227 @@
|
||||||
|
<?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::INVOICE_UPDATED,
|
||||||
|
'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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -43,14 +43,15 @@ class PaymentTransactionEventEntry implements ShouldQueue
|
||||||
private float $paid_ratio;
|
private float $paid_ratio;
|
||||||
|
|
||||||
private Collection $payments;
|
private Collection $payments;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
public function __construct(private Payment $payment, private array $invoice_ids, private string $db)
|
public function __construct(private Payment $payment, private array $invoice_ids, private string $db, private float $invoice_adjustment = 0, private int $is_deleted = false)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
nlog("PaymentTransactionEventEntry::handle");
|
|
||||||
//payment vs refunded
|
//payment vs refunded
|
||||||
MultiDB::setDb($this->db);
|
MultiDB::setDb($this->db);
|
||||||
|
|
||||||
|
|
@ -81,6 +82,12 @@ class PaymentTransactionEventEntry implements ShouldQueue
|
||||||
|
|
||||||
$this->setPaidRatio($invoice);
|
$this->setPaidRatio($invoice);
|
||||||
|
|
||||||
|
//delete any other payment mutations here if this is a delete event, the refunds are redundant in this time period
|
||||||
|
$invoice->transaction_events()
|
||||||
|
->where('event_id', TransactionEvent::PAYMENT_REFUNDED)
|
||||||
|
->where('period', now()->endOfMonth()->format('Y-m-d'))
|
||||||
|
->delete();
|
||||||
|
|
||||||
TransactionEvent::create([
|
TransactionEvent::create([
|
||||||
'invoice_id' => $invoice->id,
|
'invoice_id' => $invoice->id,
|
||||||
'client_id' => $invoice->client_id,
|
'client_id' => $invoice->client_id,
|
||||||
|
|
@ -92,7 +99,7 @@ class PaymentTransactionEventEntry implements ShouldQueue
|
||||||
'invoice_partial' => $invoice->partial ?? 0,
|
'invoice_partial' => $invoice->partial ?? 0,
|
||||||
'invoice_paid_to_date' => $invoice->paid_to_date ?? 0,
|
'invoice_paid_to_date' => $invoice->paid_to_date ?? 0,
|
||||||
'invoice_status' => $invoice->is_deleted ? 7 : $invoice->status_id,
|
'invoice_status' => $invoice->is_deleted ? 7 : $invoice->status_id,
|
||||||
'event_id' => $this->payment->is_deleted ? TransactionEvent::PAYMENT_DELETED : TransactionEvent::PAYMENT_REFUNDED,
|
'event_id' => $this->is_deleted ? TransactionEvent::PAYMENT_DELETED : TransactionEvent::PAYMENT_REFUNDED,
|
||||||
'timestamp' => now()->timestamp,
|
'timestamp' => now()->timestamp,
|
||||||
'metadata' => $this->getMetadata($invoice),
|
'metadata' => $this->getMetadata($invoice),
|
||||||
'period' => now()->endOfMonth()->format('Y-m-d'),
|
'period' => now()->endOfMonth()->format('Y-m-d'),
|
||||||
|
|
@ -137,10 +144,14 @@ class PaymentTransactionEventEntry implements ShouldQueue
|
||||||
$taxes = array_merge($calc->getTaxMap()->merge($calc->getTotalTaxMap())->toArray());
|
$taxes = array_merge($calc->getTaxMap()->merge($calc->getTotalTaxMap())->toArray());
|
||||||
|
|
||||||
foreach ($taxes as $tax) {
|
foreach ($taxes as $tax) {
|
||||||
|
|
||||||
|
$base_amount = $tax['base_amount'] ?? $calc->getNetSubtotal();
|
||||||
|
|
||||||
|
|
||||||
$tax_detail = [
|
$tax_detail = [
|
||||||
'tax_name' => $tax['name'],
|
'tax_name' => $tax['name'],
|
||||||
'tax_rate' => $tax['tax_rate'],
|
'tax_rate' => $tax['tax_rate'],
|
||||||
'taxable_amount' => $tax['base_amount'] ?? $calc->getNetSubtotal(),
|
'taxable_amount' => $base_amount,
|
||||||
'tax_amount' => $tax['total'],
|
'tax_amount' => $tax['total'],
|
||||||
'tax_amount_paid' => $this->calculateRatio($tax['total']),
|
'tax_amount_paid' => $this->calculateRatio($tax['total']),
|
||||||
'tax_amount_remaining' => round($tax['total'] - $this->calculateRatio($tax['total']), 2),
|
'tax_amount_remaining' => round($tax['total'] - $this->calculateRatio($tax['total']), 2),
|
||||||
|
|
@ -178,14 +189,26 @@ class PaymentTransactionEventEntry implements ShouldQueue
|
||||||
$taxes = array_merge($calc->getTaxMap()->merge($calc->getTotalTaxMap())->toArray());
|
$taxes = array_merge($calc->getTaxMap()->merge($calc->getTotalTaxMap())->toArray());
|
||||||
|
|
||||||
foreach ($taxes as $tax) {
|
foreach ($taxes as $tax) {
|
||||||
|
|
||||||
|
|
||||||
|
$base_amount = $tax['base_amount'] ?? $calc->getNetSubtotal();
|
||||||
|
|
||||||
|
if($this->invoice_adjustment > 0)
|
||||||
|
$tax_amount_paid = round(($this->invoice_adjustment / ($base_amount+$tax['total'])) * $tax['total'], 2);
|
||||||
|
else {
|
||||||
|
$tax_amount_paid = $this->calculateRatio($tax['total']);
|
||||||
|
}
|
||||||
|
|
||||||
$tax_detail = [
|
$tax_detail = [
|
||||||
'tax_name' => $tax['name'],
|
'tax_name' => $tax['name'],
|
||||||
'tax_rate' => $tax['tax_rate'],
|
'tax_rate' => $tax['tax_rate'],
|
||||||
'taxable_amount' => $tax['base_amount'] ?? $calc->getNetSubtotal(),
|
'taxable_amount' => $base_amount,
|
||||||
'tax_amount' => $tax['total'],
|
'tax_amount' => $tax['total'],
|
||||||
'tax_amount_paid' => $this->calculateRatio($tax['total']),
|
'tax_amount_paid' => $tax_amount_paid,
|
||||||
'tax_amount_remaining' => 0,
|
'tax_amount_remaining' => 0,
|
||||||
|
'tax_status' => 'payment_deleted',
|
||||||
];
|
];
|
||||||
|
|
||||||
$details[] = $tax_detail;
|
$details[] = $tax_detail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -857,11 +857,15 @@ class Invoice extends BaseModel
|
||||||
|
|
||||||
$formatted_string = "<div id=\"payment-schedule\">";
|
$formatted_string = "<div id=\"payment-schedule\">";
|
||||||
|
|
||||||
foreach($schedule->parameters['schedule'] as $item){
|
$formatted_string .= "<p><span class=\"payment-schedule-title\"><b>".ctrans('texts.payment_schedule')."</b></span></p>";
|
||||||
|
|
||||||
|
foreach($schedule->parameters['schedule'] as $key => $item){
|
||||||
$amount = $item['is_amount'] ? $item['amount'] : round($this->amount * ($item['amount']/100),2);
|
$amount = $item['is_amount'] ? $item['amount'] : round($this->amount * ($item['amount']/100),2);
|
||||||
$amount = \App\Utils\Number::formatMoney($amount, $this->client);
|
$amount = \App\Utils\Number::formatMoney($amount, $this->client);
|
||||||
|
|
||||||
$formatted_string .= "<p><span class=\"payment-schedule-date\">".$this->formatDate($item['date'], $this->client->date_format()) . "</span> - <span class=\"payment-schedule-amount\"> " . $amount."</span></p>";
|
$schedule_text = ctrans('texts.payment_schedule_table', ['key' => $key+1, 'date' => $this->formatDate($item['date'], $this->client->date_format()), 'amount' => $amount]);
|
||||||
|
|
||||||
|
$formatted_string .= "<p><span class=\"payment-schedule\">".$schedule_text."</span></p>";
|
||||||
}
|
}
|
||||||
|
|
||||||
$formatted_string .= "</div>";
|
$formatted_string .= "</div>";
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ use App\DataMapper\TransactionEventMetadata;
|
||||||
* @property int $event_id
|
* @property int $event_id
|
||||||
* @property int $timestamp
|
* @property int $timestamp
|
||||||
* @property array|null $payment_request
|
* @property array|null $payment_request
|
||||||
* @property array|null $metadata
|
* @property TransactionEventMetadata|null $metadata
|
||||||
* @property string $credit_balance
|
* @property string $credit_balance
|
||||||
* @property string $credit_amount
|
* @property string $credit_amount
|
||||||
* @property int|null $credit_status
|
* @property int|null $credit_status
|
||||||
|
|
@ -65,4 +65,6 @@ class TransactionEvent extends StaticModel
|
||||||
public const PAYMENT_REFUNDED = 2;
|
public const PAYMENT_REFUNDED = 2;
|
||||||
|
|
||||||
public const PAYMENT_DELETED = 3;
|
public const PAYMENT_DELETED = 3;
|
||||||
|
|
||||||
|
public const PAYMENT_CASH = 4;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ class DeletePayment
|
||||||
|
|
||||||
if ($this->payment->invoices()->exists()) {
|
if ($this->payment->invoices()->exists()) {
|
||||||
|
|
||||||
$invoice_ids = $this->payment->invoices()->pluck('id');
|
$invoice_ids = $this->payment->invoices()->pluck('invoices.id')->toArray();
|
||||||
|
|
||||||
$this->payment->invoices()->each(function ($paymentable_invoice) {
|
$this->payment->invoices()->each(function ($paymentable_invoice) {
|
||||||
$net_deletable = $paymentable_invoice->pivot->amount - $paymentable_invoice->pivot->refunded;
|
$net_deletable = $paymentable_invoice->pivot->amount - $paymentable_invoice->pivot->refunded;
|
||||||
|
|
@ -161,10 +161,10 @@ class DeletePayment
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PaymentTransactionEventEntry::dispatch($this->payment, [$paymentable_invoice->id], $this->payment->company->db, $net_deletable, true);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
PaymentTransactionEventEntry::dispatch($this->payment, $invoice_ids, $this->payment->company->db);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//sometimes the payment is NOT created properly, this catches the payment and prevents the paid to date reducing inappropriately.
|
//sometimes the payment is NOT created properly, this catches the payment and prevents the paid to date reducing inappropriately.
|
||||||
|
|
|
||||||
|
|
@ -313,7 +313,7 @@ class RefundPayment
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PaymentTransactionEventEntry::dispatch($this->payment, array_column($this->refund_data['invoices'], 'invoice_id'), $this->payment->company->db);
|
PaymentTransactionEventEntry::dispatch($this->payment, array_column($this->refund_data['invoices'], 'invoice_id'), $this->payment->company->db, 0, false);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
//if we are refunding and no payments have been tagged, then we need to decrement the client->paid_to_date by the total refund amount.
|
//if we are refunding and no payments have been tagged, then we need to decrement the client->paid_to_date by the total refund amount.
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ use Illuminate\Database\Eloquent\Builder;
|
||||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
use App\Listeners\Invoice\InvoiceTransactionEventEntry;
|
use App\Listeners\Invoice\InvoiceTransactionEventEntry;
|
||||||
|
use App\Models\TransactionEvent;
|
||||||
|
|
||||||
class TaxReport
|
class TaxReport
|
||||||
{
|
{
|
||||||
|
|
@ -83,7 +84,7 @@ class TaxReport
|
||||||
|
|
||||||
$worksheet = $this->spreadsheet->createSheet();
|
$worksheet = $this->spreadsheet->createSheet();
|
||||||
$worksheet->setTitle(ctrans('texts.invoice')." ".ctrans('texts.cash_vs_accrual'));
|
$worksheet->setTitle(ctrans('texts.invoice')." ".ctrans('texts.cash_vs_accrual'));
|
||||||
$worksheet->fromArray($this->data['invoices'], null, 'A1');
|
$worksheet->fromArray($this->data['accrual']['invoices'], null, 'A1');
|
||||||
|
|
||||||
$worksheet->getStyle('B:B')->getNumberFormat()->setFormatCode($this->company->date_format()); // Invoice date column
|
$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('C:C')->getNumberFormat()->setFormatCode($this->currency_format); // Invoice total column
|
||||||
|
|
@ -97,13 +98,11 @@ class TaxReport
|
||||||
// All paid invoices within a time period
|
// All paid invoices within a time period
|
||||||
public function createInvoiceSummarySheetCash()
|
public function createInvoiceSummarySheetCash()
|
||||||
{
|
{
|
||||||
$cash_invoices = collect($this->data['invoices'])->filter(function($invoice){
|
|
||||||
return $invoice[3] != 0;
|
|
||||||
})->toArray();
|
|
||||||
|
|
||||||
$worksheet = $this->spreadsheet->createSheet();
|
$worksheet = $this->spreadsheet->createSheet();
|
||||||
$worksheet->setTitle(ctrans('texts.invoice')." ".ctrans('texts.cash_accounting'));
|
$worksheet->setTitle(ctrans('texts.invoice')." ".ctrans('texts.cash_accounting'));
|
||||||
$worksheet->fromArray($cash_invoices, null, 'A1');
|
|
||||||
|
$worksheet->fromArray($this->data['cash']['invoices'], null, 'A1');
|
||||||
$worksheet->getStyle('B:B')->getNumberFormat()->setFormatCode($this->company->date_format()); // Invoice date column
|
$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('C:C')->getNumberFormat()->setFormatCode($this->currency_format); // Invoice total column
|
||||||
$worksheet->getStyle('D:D')->getNumberFormat()->setFormatCode($this->currency_format); // Paid amount column
|
$worksheet->getStyle('D:D')->getNumberFormat()->setFormatCode($this->currency_format); // Paid amount column
|
||||||
|
|
@ -118,7 +117,7 @@ class TaxReport
|
||||||
|
|
||||||
$worksheet = $this->spreadsheet->createSheet();
|
$worksheet = $this->spreadsheet->createSheet();
|
||||||
$worksheet->setTitle(ctrans('texts.invoice_item')." ".ctrans('texts.cash_vs_accrual'));
|
$worksheet->setTitle(ctrans('texts.invoice_item')." ".ctrans('texts.cash_vs_accrual'));
|
||||||
$worksheet->fromArray($this->data['invoice_items'], null, 'A1');
|
$worksheet->fromArray($this->data['accrual']['invoice_items'], null, 'A1');
|
||||||
|
|
||||||
$worksheet->getStyle('B:B')->getNumberFormat()->setFormatCode($this->company->date_format()); // Invoice date column
|
$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('C:C')->getNumberFormat()->setFormatCode($this->currency_format); // Invoice total column
|
||||||
|
|
@ -135,13 +134,9 @@ class TaxReport
|
||||||
public function createInvoiceItemSummarySheetCash()
|
public function createInvoiceItemSummarySheetCash()
|
||||||
{
|
{
|
||||||
|
|
||||||
$cash_invoice_items = collect($this->data['invoice_items'])->filter(function($invoice_item){
|
|
||||||
return $invoice_item[3] != 0;
|
|
||||||
})->toArray();
|
|
||||||
|
|
||||||
$worksheet = $this->spreadsheet->createSheet();
|
$worksheet = $this->spreadsheet->createSheet();
|
||||||
$worksheet->setTitle(ctrans('texts.invoice_item')." ".ctrans('texts.cash_accounting'));
|
$worksheet->setTitle(ctrans('texts.invoice_item')." ".ctrans('texts.cash_accounting'));
|
||||||
$worksheet->fromArray($cash_invoice_items, null, 'A1');
|
$worksheet->fromArray($this->data['cash']['invoice_items'], null, 'A1');
|
||||||
|
|
||||||
$worksheet->getStyle('B:B')->getNumberFormat()->setFormatCode($this->company->date_format()); // Invoice date column
|
$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('C:C')->getNumberFormat()->setFormatCode($this->currency_format); // Invoice total column
|
||||||
|
|
@ -162,17 +157,19 @@ class TaxReport
|
||||||
$end_date_instance = Carbon::parse($this->tsr->end_date);
|
$end_date_instance = Carbon::parse($this->tsr->end_date);
|
||||||
|
|
||||||
$this->data['invoices'] = [];
|
$this->data['invoices'] = [];
|
||||||
$this->data['invoices'][] = [
|
$this->data['invoices'][] =
|
||||||
|
|
||||||
|
$invoice_headers = [
|
||||||
ctrans('texts.invoice_number'),
|
ctrans('texts.invoice_number'),
|
||||||
ctrans('texts.invoice_date'),
|
ctrans('texts.invoice_date'),
|
||||||
ctrans('texts.invoice_total'),
|
ctrans('texts.invoice_total'),
|
||||||
ctrans('texts.paid'),
|
ctrans('texts.paid'),
|
||||||
ctrans('texts.total_taxes'),
|
ctrans('texts.total_taxes'),
|
||||||
ctrans('texts.tax_paid')
|
ctrans('texts.tax_paid'),
|
||||||
|
ctrans('texts.notes')
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->data['invoice_items'] = [];
|
$invoice_item_headers = [
|
||||||
$this->data['invoice_items'][] = [
|
|
||||||
ctrans('texts.invoice_number'),
|
ctrans('texts.invoice_number'),
|
||||||
ctrans('texts.invoice_date'),
|
ctrans('texts.invoice_date'),
|
||||||
ctrans('texts.invoice_total'),
|
ctrans('texts.invoice_total'),
|
||||||
|
|
@ -185,26 +182,106 @@ class TaxReport
|
||||||
ctrans('texts.tax_nexus'),
|
ctrans('texts.tax_nexus'),
|
||||||
];
|
];
|
||||||
|
|
||||||
$offset = $this->company->timezone_offset();
|
|
||||||
|
|
||||||
/** @var Invoice $invoice */
|
$this->data['accrual']['invoices'] = [$invoice_headers];
|
||||||
foreach($this->query->cursor() as $invoice){
|
$this->data['cash']['invoices'] = [$invoice_headers];
|
||||||
|
$this->data['accrual']['invoice_items'] = [$invoice_item_headers];
|
||||||
|
$this->data['cash']['invoice_items'] = [$invoice_item_headers];
|
||||||
|
|
||||||
if($invoice->transaction_events->count() == 0){
|
|
||||||
(new InvoiceTransactionEventEntry())->run($invoice);
|
|
||||||
}
|
|
||||||
|
|
||||||
//get the invoice state as at the end of the current period.
|
Invoice::withTrashed()
|
||||||
$invoice->transaction_events->each(function($event){
|
->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()
|
||||||
|
->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)->sortByDesc('timestamp')->first();
|
||||||
|
$adjustments = $invoice->transaction_events->whereIn('event_id',[TransactionEvent::PAYMENT_REFUNDED, TransactionEvent::PAYMENT_DELETED]);
|
||||||
|
|
||||||
|
if($invoice_state->event_id == TransactionEvent::INVOICE_UPDATED){
|
||||||
|
$this->data['accrual']['invoices'][] = [
|
||||||
|
$invoice->number,
|
||||||
|
$invoice->date,
|
||||||
|
$invoice->amount,
|
||||||
|
$invoice_state->invoice_paid_to_date,
|
||||||
|
$invoice_state->metadata->tax_report->tax_summary->total_taxes,
|
||||||
|
$invoice_state->metadata->tax_report->tax_summary->total_paid,
|
||||||
|
'payable',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
elseif($invoice_state->event_id == TransactionEvent::PAYMENT_CASH){
|
||||||
|
|
||||||
|
$this->data['cash']['invoices'][] = [
|
||||||
|
$invoice->number,
|
||||||
|
$invoice->date,
|
||||||
|
$invoice->amount,
|
||||||
|
$invoice_state->invoice_paid_to_date,
|
||||||
|
$invoice_state->metadata->tax_report->tax_summary->total_taxes,
|
||||||
|
$invoice_state->metadata->tax_report->tax_summary->total_paid,
|
||||||
|
'payable',
|
||||||
|
];
|
||||||
|
|
||||||
|
}
|
||||||
|
$_adjustments = [];
|
||||||
|
|
||||||
|
foreach($adjustments as $adjustment){
|
||||||
|
$_adjustments[] = [
|
||||||
|
$invoice->number,
|
||||||
|
$invoice->date,
|
||||||
|
$invoice->amount,
|
||||||
|
$invoice_state->invoice_paid_to_date,
|
||||||
|
$invoice_state->metadata->tax_report->tax_summary->total_taxes,
|
||||||
|
$invoice_state->metadata->tax_report->tax_summary->adjustment,
|
||||||
|
'adjustment',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->data['accrual']['invoices'] = array_merge($this->data['accrual']['invoices'], $_adjustments);
|
||||||
|
$this->data['cash']['invoices'] = array_merge($this->data['cash']['invoices'], $_adjustments);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
//anything period the reporting period is considered an ADJUSTMENT
|
return $this;
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
}
|
||||||
|
// $offset = $this->company->timezone_offset();
|
||||||
|
|
||||||
|
// /** @var Invoice $invoice */
|
||||||
|
// foreach($this->query->cursor() as $invoice){
|
||||||
|
|
||||||
|
// if($invoice->transaction_events->count() == 0){
|
||||||
|
// (new InvoiceTransactionEventEntry())->run($invoice);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// //get the invoice state as at the end of the current period.
|
||||||
|
// $invoice_state =$invoice->transaction_events()
|
||||||
|
// ->where('period', Carbon::parse($invoice->date)->endOfMonth()->format('Y-m-d'))
|
||||||
|
// ->where('event_id', TransactionEvent::INVOICE_UPDATED)
|
||||||
|
// ->latest()
|
||||||
|
// ->first();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// //anything period the reporting period is considered an ADJUSTMENT
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Invoice::withTrashed()
|
||||||
|
// ->where('company_id', $this->company->id)
|
||||||
|
// ->whereHas('transaction_events', function ($query){
|
||||||
|
// return $query->where('period', Carbon::parse($invoice->date)->endOfMonth()->format('Y-m-d'))
|
||||||
|
// ->whereIn('event_id',[TransactionEvent::PAYMENT_REFUNDED, TransactionEvent::PAYMENT_DELETED]);
|
||||||
|
// });
|
||||||
|
|
||||||
|
// return $this;
|
||||||
|
// }
|
||||||
|
|
||||||
public function getXlsFile()
|
public function getXlsFile()
|
||||||
{
|
{
|
||||||
|
|
@ -214,7 +291,7 @@ class TaxReport
|
||||||
$writer = new \PhpOffice\PhpSpreadsheet\Writer\Xlsx($this->spreadsheet);
|
$writer = new \PhpOffice\PhpSpreadsheet\Writer\Xlsx($this->spreadsheet);
|
||||||
$writer->save($tempFile);
|
$writer->save($tempFile);
|
||||||
|
|
||||||
// $writer->save('/home/david/ttx.xslx');
|
$writer->save('/home/david/ttx.xlsx');
|
||||||
// Read file content
|
// Read file content
|
||||||
$fileContent = file_get_contents($tempFile);
|
$fileContent = file_get_contents($tempFile);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5607,6 +5607,7 @@ $lang = array(
|
||||||
'first_payment_date' => 'First Payment Date',
|
'first_payment_date' => 'First Payment Date',
|
||||||
'first_payment_date_help' => 'The date of the first payment',
|
'first_payment_date_help' => 'The date of the first payment',
|
||||||
'payment_schedule_interval' => 'Payment :index of :total for :amount',
|
'payment_schedule_interval' => 'Payment :index of :total for :amount',
|
||||||
|
'payment_schedule_table' => 'Payment :key on :date for :amount',
|
||||||
'auto_send' => 'Auto Send',
|
'auto_send' => 'Auto Send',
|
||||||
'auto_send_help' => 'Automatically emails the invoice to the client',
|
'auto_send_help' => 'Automatically emails the invoice to the client',
|
||||||
'include_project_tasks' => 'Include Project Tasks',
|
'include_project_tasks' => 'Include Project Tasks',
|
||||||
|
|
|
||||||
|
|
@ -11,17 +11,19 @@
|
||||||
|
|
||||||
namespace Tests\Feature\Export;
|
namespace Tests\Feature\Export;
|
||||||
|
|
||||||
use App\DataMapper\CompanySettings;
|
use Tests\TestCase;
|
||||||
use App\Factory\InvoiceItemFactory;
|
use App\Models\User;
|
||||||
use App\Models\Account;
|
|
||||||
use App\Models\Client;
|
use App\Models\Client;
|
||||||
|
use App\Models\Account;
|
||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
use App\Models\User;
|
|
||||||
use App\Services\Report\TaxSummaryReport;
|
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
|
use App\DataMapper\CompanySettings;
|
||||||
|
use App\Factory\InvoiceItemFactory;
|
||||||
|
use App\Services\Report\TaxSummaryReport;
|
||||||
use Illuminate\Routing\Middleware\ThrottleRequests;
|
use Illuminate\Routing\Middleware\ThrottleRequests;
|
||||||
use Tests\TestCase;
|
use App\Listeners\Invoice\InvoiceTransactionEventEntry;
|
||||||
|
use App\Listeners\Invoice\InvoiceTransactionEventEntryAccrual;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
|
@ -162,6 +164,34 @@ class TaxSummaryReportTest extends TestCase
|
||||||
|
|
||||||
$i = $i->calc()->getInvoice();
|
$i = $i->calc()->getInvoice();
|
||||||
|
|
||||||
|
(new InvoiceTransactionEventEntry())->run($i);
|
||||||
|
|
||||||
|
$i2 = Invoice::factory()->create([
|
||||||
|
'client_id' => $this->client->id,
|
||||||
|
'user_id' => $this->user->id,
|
||||||
|
'company_id' => $this->company->id,
|
||||||
|
'amount' => 0,
|
||||||
|
'balance' => 0,
|
||||||
|
'status_id' => 2,
|
||||||
|
'total_taxes' => 1,
|
||||||
|
'date' => now()->format('Y-m-d'),
|
||||||
|
'terms' => 'nada',
|
||||||
|
'discount' => 0,
|
||||||
|
'tax_rate1' => 10,
|
||||||
|
'tax_rate2' => 17.5,
|
||||||
|
'tax_rate3' => 5,
|
||||||
|
'tax_name1' => 'GST',
|
||||||
|
'tax_name2' => 'VAT',
|
||||||
|
'tax_name3' => 'CA Sales Tax',
|
||||||
|
'uses_inclusive_taxes' => false,
|
||||||
|
'line_items' => $this->buildLineItems(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$i2 = $i2->calc()->getInvoice();
|
||||||
|
$i2->service()->markPaid();
|
||||||
|
|
||||||
|
(new InvoiceTransactionEventEntryAccrual())->run($i2);
|
||||||
|
|
||||||
$pl = new TaxSummaryReport($this->company, $this->payload);
|
$pl = new TaxSummaryReport($this->company, $this->payload);
|
||||||
$response = $pl->run();
|
$response = $pl->run();
|
||||||
|
|
||||||
|
|
@ -206,6 +236,34 @@ class TaxSummaryReportTest extends TestCase
|
||||||
|
|
||||||
$i = $i->calc()->getInvoice();
|
$i = $i->calc()->getInvoice();
|
||||||
|
|
||||||
|
(new InvoiceTransactionEventEntry())->run($i);
|
||||||
|
|
||||||
|
$i2 = Invoice::factory()->create([
|
||||||
|
'client_id' => $this->client->id,
|
||||||
|
'user_id' => $this->user->id,
|
||||||
|
'company_id' => $this->company->id,
|
||||||
|
'amount' => 0,
|
||||||
|
'balance' => 0,
|
||||||
|
'status_id' => 2,
|
||||||
|
'total_taxes' => 1,
|
||||||
|
'date' => now()->format('Y-m-d'),
|
||||||
|
'terms' => 'nada',
|
||||||
|
'discount' => 0,
|
||||||
|
'tax_rate1' => 10,
|
||||||
|
'tax_rate2' => 17.5,
|
||||||
|
'tax_rate3' => 5,
|
||||||
|
'tax_name1' => 'GST',
|
||||||
|
'tax_name2' => 'VAT',
|
||||||
|
'tax_name3' => 'CA Sales Tax',
|
||||||
|
'uses_inclusive_taxes' => false,
|
||||||
|
'line_items' => $this->buildLineItems(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$i2 = $i2->calc()->getInvoice();
|
||||||
|
$i2->service()->markPaid();
|
||||||
|
|
||||||
|
(new InvoiceTransactionEventEntryAccrual())->run($i2, now()->subDays(30)->format('Y-m-d'), now()->addDays(30)->format('Y-m-d'));
|
||||||
|
|
||||||
$pl = new TaxSummaryReport($this->company, $this->payload);
|
$pl = new TaxSummaryReport($this->company, $this->payload);
|
||||||
|
|
||||||
$query = Invoice::query()
|
$query = Invoice::query()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue