1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-05 18:52:44 +01:00

Refactor - moving away from jobs. (#3279)

* Implement Services

* implement service pattern

* Service patterns

* Refactoring invoice paid

* refactoring invoice

* Refactor jobs

* Refactor - remove jobs

* Refactor jobs

* Refactoring jobs

* Refactoring away from jobs

* Refactoring jobs

* Add Credits to test data
This commit is contained in:
David Bomba 2020-02-03 21:33:07 +11:00 committed by GitHub
parent 84461858f2
commit c25de936ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 910 additions and 678 deletions

View File

@ -15,6 +15,7 @@ use App\Jobs\Company\UpdateCompanyLedgerWithInvoice;
use App\Jobs\Invoice\CreateInvoiceInvitations;
use App\Jobs\Invoice\UpdateInvoicePayment;
use App\Jobs\Quote\CreateQuoteInvitations;
use App\Listeners\Credit\CreateCreditInvitation;
use App\Listeners\Invoice\CreateInvoiceInvitation;
use App\Models\CompanyToken;
use App\Models\Payment;
@ -136,6 +137,9 @@ class CreateTestData extends Command
$this->info('creating invoice for client #'.$client->id);
$this->createInvoice($client);
$this->info('creating credit for client #'.$client->id);
$this->createCredit($client);
$this->info('creating quote for client #'.$client->id);
$this->createQuote($client);
@ -221,6 +225,12 @@ class CreateTestData extends Command
for($i=0; $i<$this->count; $i++)
$this->createInvoice($client);
$this->info('creating credit for client #'.$client->id);
for($i=0; $i<$this->count; $i++)
$this->createCredit($client);
$this->info('creating quote for client #'.$client->id);
for($i=0; $i<$this->count; $i++)
@ -312,6 +322,9 @@ class CreateTestData extends Command
$this->info('creating invoice for client #'.$client->id);
$this->createInvoice($client);
$this->info('creating credit for client #'.$client->id);
$this->createCredit($client);
$this->info('creating quote for client #'.$client->id);
$this->createQuote($client);
@ -472,6 +485,48 @@ class CreateTestData extends Command
}
}
private function createCredit($client)
{
$faker = \Faker\Factory::create();
$credit = factory(\App\Models\Credit::class)->create(['user_id' => $client->user->id, 'company_id' => $client->company->id, 'client_id' => $client->id]);
//$invoice = InvoiceFactory::create($client->company->id, $client->user->id);//stub the company and user_id
//$invoice->client_id = $client->id;
// $invoice->date = $faker->date();
$dateable = Carbon::now()->subDays(rand(0,90));
$credit->date = $dateable;
$credit->line_items = $this->buildLineItems(rand(1,10));
$credit->uses_inclusive_taxes = false;
if (rand(0, 1)) {
$credit->tax_name1 = 'GST';
$credit->tax_rate1 = 10.00;
}
if (rand(0, 1)) {
$credit->tax_name2 = 'VAT';
$credit->tax_rate2 = 17.50;
}
if (rand(0, 1)) {
$credit->tax_name3 = 'CA Sales Tax';
$credit->tax_rate3 = 5;
}
$credit->save();
$invoice_calc = new InvoiceSum($credit);
$invoice_calc->build();
$credit = $invoice_calc->getInvoice();
$credit->save();
event(new CreateCreditInvitation($credit));
}
private function createQuote($client)
{

View File

@ -71,6 +71,7 @@ class CompanySettings extends BaseSettings
public $counter_number_applied = 'when_saved'; // when_saved , when_sent , when_paid
public $quote_number_applied = 'when_saved'; // when_saved , when_sent
/* Counters */
public $invoice_number_pattern = '';
public $invoice_number_counter = 1;

View File

@ -142,7 +142,7 @@ class CreditController extends BaseController
if ($credit->balance < 0 || $credit->status_id == Credit::STATUS_PAID || $credit->is_deleted === true) {
return $this->errorResponse(['message' => 'Credit cannot be marked as paid'], 400);
}
//@todo fix and replace
$credit = MarkInvoicePaid::dispatchNow($credit, $credit->company);
if (!$bulk) {

View File

@ -618,7 +618,7 @@ class InvoiceController extends BaseController
return $this->errorResponse(['message' => 'Invoice cannot be marked as paid'], 400);
}
$invoice = MarkInvoicePaid::dispatchNow($invoice, $invoice->company);
$invoice = $invoice->markPaid();
if (!$bulk) {
return $this->itemResponse($invoice);

View File

@ -77,6 +77,8 @@ class StorePaymentRequest extends Request
$input['amount'] = $invoices_total - $credits_total;
}
$input['is_manual'] = true;
$this->replace($input);
}

View File

@ -1,54 +0,0 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com)
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Jobs\Client;
use App\Libraries\MultiDB;
use App\Models\Client;
use App\Models\Company;
use Illuminate\Foundation\Bus\Dispatchable;
class UpdateClientBalance
{
use Dispatchable;
protected $amount;
protected $client;
private $company;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct(Client $client, $amount, Company $company)
{
$this->amount = $amount;
$this->client = $client;
$this->company = $company;
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
MultiDB::setDB($this->company->db);
$this->client->balance += $this->amount;
$this->client->save();
}
}

View File

@ -1,53 +0,0 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com)
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Jobs\Client;
use App\Libraries\MultiDB;
use App\Models\Client;
use App\Models\Company;
use Illuminate\Foundation\Bus\Dispatchable;
class UpdateClientPaidToDate
{
use Dispatchable;
protected $amount;
protected $client;
private $company;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct(Client $client, $amount, Company $company)
{
$this->amount = $amount;
$this->client = $client;
$this->company = $company;
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
MultiDB::setDB($this->company->db);
$this->client->paid_to_date += $this->amount;
$this->client->save();
}
}

View File

@ -13,8 +13,6 @@ namespace App\Jobs\Credit;
use App\Events\Payment\PaymentWasCreated;
use App\Factory\PaymentFactory;
use App\Jobs\Client\UpdateClientBalance;
use App\Jobs\Client\UpdateClientPaidToDate;
use App\Jobs\Company\UpdateCompanyLedgerWithPayment;
use App\Jobs\Credit\ApplyPaymentToCredit;
use App\Libraries\MultiDB;

View File

@ -14,8 +14,6 @@ namespace App\Jobs\Invoice;
use App\Events\Payment\PaymentWasCreated;
use App\Factory\CreditFactory;
use App\Factory\PaymentFactory;
use App\Jobs\Client\UpdateClientBalance;
use App\Jobs\Client\UpdateClientPaidToDate;
use App\Jobs\Company\UpdateCompanyLedgerWithPayment;
use App\Libraries\MultiDB;
use App\Models\Company;
@ -77,8 +75,6 @@ class MarkCreditPaid implements ShouldQueue
event(new PaymentWasCreated($payment, $payment->company));
// UpdateCompanyLedgerWithPayment::dispatchNow($payment, ($payment->amount*-1), $this->company);
// UpdateClientBalance::dispatchNow($payment->client, $payment->amount*-1, $this->company);
// UpdateClientPaidToDate::dispatchNow($payment->client, $payment->amount, $this->company);
return $this->credit;
}

View File

@ -1,65 +0,0 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com)
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Jobs\Invoice;
use App\Events\Payment\PaymentWasCreated;
use App\Factory\PaymentFactory;
use App\Jobs\Client\UpdateClientBalance;
use App\Jobs\Client\UpdateClientPaidToDate;
use App\Jobs\Company\UpdateCompanyLedgerWithPayment;
use App\Jobs\Invoice\ApplyPaymentToInvoice;
use App\Libraries\MultiDB;
use App\Models\Company;
use App\Models\Invoice;
use App\Models\Payment;
use App\Repositories\InvoiceRepository;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class ApplyClientPayment implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $payment;
private $company;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct(Payment $payment, Company $company)
{
$this->payment = $payment;
$this->company = $company;
}
/**
* Execute the job.
*
*
* @return void
*/
public function handle()
{
MultiDB::setDB($this->company->db);
$client = $this->payment->client;
$client->credit_balance += $this->payment->amount;
$client->paid_to_date += $this->payment->amount;
$client->save();
}
}

View File

@ -1,86 +0,0 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com)
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Jobs\Invoice;
use App\Libraries\MultiDB;
use App\Models\Invoice;
use App\Models\Payment;
use App\Models\PaymentTerm;
use App\Repositories\InvoiceRepository;
use App\Utils\Traits\GeneratesCounter;
use App\Utils\Traits\NumberFormatter;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Carbon;
class ApplyInvoiceNumber implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, NumberFormatter, GeneratesCounter;
public $invoice;
public $settings;
private $company;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct(Invoice $invoice, $settings, $company)
{
$this->invoice = $invoice;
$this->settings = $settings;
$this->company = $company;
}
/**
* Execute the job.
*
*
* @return void
*/
public function handle()
{
MultiDB::setDB($this->company->db);
//return early
if ($this->invoice->number != '') {
return $this->invoice;
}
switch ($this->settings->counter_number_applied) {
case 'when_saved':
$this->invoice->number = $this->getNextInvoiceNumber($this->invoice->client);
break;
case 'when_sent':
if ($this->invoice->status_id == Invoice::STATUS_SENT) {
$this->invoice->number = $this->getNextInvoiceNumber($this->invoice->client);
}
break;
default:
# code...
break;
}
$this->invoice->save();
return $this->invoice;
}
}

View File

@ -1,110 +0,0 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com)
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Jobs\Invoice;
use App\Events\Payment\PaymentWasCreated;
use App\Factory\PaymentFactory;
use App\Jobs\Client\UpdateClientBalance;
use App\Jobs\Client\UpdateClientPaidToDate;
use App\Jobs\Company\UpdateCompanyLedgerWithPayment;
use App\Jobs\Invoice\ApplyPaymentToInvoice;
use App\Libraries\MultiDB;
use App\Models\Company;
use App\Models\Invoice;
use App\Models\Payment;
use App\Repositories\InvoiceRepository;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class ApplyInvoicePayment implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $invoice;
public $payment;
public $amount;
private $company;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct(Invoice $invoice, Payment $payment, float $amount, Company $company)
{
$this->invoice = $invoice;
$this->payment = $payment;
$this->amount = $amount;
$this->company = $company;
}
/**
* Execute the job.
*
*
* @return void
*/
public function handle()
{
MultiDB::setDB($this->company->db);
UpdateCompanyLedgerWithPayment::dispatchNow($this->payment, ($this->amount*-1), $this->company);
UpdateClientBalance::dispatchNow($this->payment->client, $this->amount*-1, $this->company);
//UpdateClientPaidToDate::dispatchNow($this->payment->client, $this->amount, $this->company);
/* Update Pivot Record amount */
$this->payment->invoices->each(function ($inv) {
if ($inv->id == $this->invoice->id) {
$inv->pivot->amount = $this->amount;
$inv->pivot->save();
}
});
if ($this->invoice->hasPartial()) {
//is partial and amount is exactly the partial amount
if ($this->invoice->partial == $this->amount) {
$this->invoice->clearPartial();
$this->invoice->setDueDate();
$this->invoice->setStatus(Invoice::STATUS_PARTIAL);
$this->invoice->updateBalance($this->amount*-1);
} elseif ($this->invoice->partial > 0 && $this->invoice->partial > $this->amount) { //partial amount exists, but the amount is less than the partial amount
$this->invoice->partial -= $this->amount;
$this->invoice->updateBalance($this->amount*-1);
} elseif ($this->invoice->partial > 0 && $this->invoice->partial < $this->amount) { //partial exists and the amount paid is GREATER than the partial amount
$this->invoice->clearPartial();
$this->invoice->setDueDate();
$this->invoice->setStatus(Invoice::STATUS_PARTIAL);
$this->invoice->updateBalance($this->amount*-1);
}
} elseif ($this->amount == $this->invoice->balance) { //total invoice paid.
$this->invoice->clearPartial();
//$this->invoice->setDueDate();
$this->invoice->setStatus(Invoice::STATUS_PAID);
$this->invoice->updateBalance($this->amount*-1);
} elseif($this->amount < $this->invoice->balance) { //partial invoice payment made
$this->invoice->clearPartial();
$this->invoice->updateBalance($this->amount*-1);
}
/* Update Payment Applied Amount*/
// $this->payment->applied += $this->amount;
// $this->payment->save();
}
}

View File

@ -12,7 +12,6 @@
namespace App\Jobs\Invoice;
use App\Events\Invoice\InvoiceWasPaid;
use App\Jobs\Invoice\ApplyInvoiceNumber;
use App\Libraries\MultiDB;
use App\Models\Company;
use App\Models\Invoice;
@ -38,6 +37,7 @@ class ApplyPaymentToInvoice implements ShouldQueue
private $company;
/**
* @deprecated confirm to be deleted
* Create a new job instance.
*
* @return void
@ -113,7 +113,7 @@ class ApplyPaymentToInvoice implements ShouldQueue
$this->invoice->save();
$this->invoice = ApplyInvoiceNumber::dispatchNow($this->invoice, $invoice->client->getMergedSettings(), $this->invoice->company);
$this->invoice = $this->invoice->applyNumber()->save();
return $this->invoice;
}

View File

@ -1,87 +0,0 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com)
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Jobs\Invoice;
use App\Events\Payment\PaymentWasCreated;
use App\Factory\PaymentFactory;
use App\Jobs\Client\UpdateClientBalance;
use App\Jobs\Client\UpdateClientPaidToDate;
use App\Jobs\Company\UpdateCompanyLedgerWithPayment;
use App\Jobs\Invoice\ApplyPaymentToInvoice;
use App\Libraries\MultiDB;
use App\Models\Company;
use App\Models\Invoice;
use App\Models\Payment;
use App\Repositories\InvoiceRepository;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class MarkInvoicePaid implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $invoice;
private $company;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct(Invoice $invoice, Company $company)
{
$this->invoice = $invoice;
$this->company = $company;
}
/**
* Execute the job.
*
*
* @return void
*/
public function handle()
{
MultiDB::setDB($this->company->db);
if($this->invoice->status_id == Invoice::STATUS_DRAFT)
$this->invoice->markSent();
/* Create Payment */
$payment = PaymentFactory::create($this->invoice->company_id, $this->invoice->user_id);
$payment->amount = $this->invoice->balance;
$payment->status_id = Payment::STATUS_COMPLETED;
$payment->client_id = $this->invoice->client_id;
$payment->transaction_reference = ctrans('texts.manual_entry');
/* Create a payment relationship to the invoice entity */
$payment->save();
$payment->invoices()->attach($this->invoice->id, [
'amount' => $payment->amount
]);
$this->invoice->updateBalance($payment->amount*-1);
/* Update Invoice balance */
event(new PaymentWasCreated($payment, $payment->company));
UpdateCompanyLedgerWithPayment::dispatchNow($payment, ($payment->amount*-1), $this->company);
UpdateClientBalance::dispatchNow($payment->client, $payment->amount*-1, $this->company);
UpdateClientPaidToDate::dispatchNow($payment->client, $payment->amount, $this->company);
return $this->invoice;
}
}

View File

@ -11,8 +11,6 @@
namespace App\Jobs\Invoice;
use App\Jobs\Client\UpdateClientBalance;
use App\Jobs\Client\UpdateClientPaidToDate;
use App\Jobs\Company\UpdateCompanyLedgerWithInvoice;
use App\Jobs\Company\UpdateCompanyLedgerWithPayment;
use App\Jobs\Util\SystemLogger;
@ -70,8 +68,9 @@ class ReverseInvoicePayment implements ShouldQueue
UpdateCompanyLedgerWithPayment::dispatchNow($this->payment, ($this->payment->amount), $this->company);
UpdateClientBalance::dispatchNow($client, $this->payment->amount, $this->company);
$client->updateBalance($this->payment->amount)
->updatePaidToDate($this->payment->amount*-1)
->save();
UpdateClientPaidToDate::dispatchNow($client, $this->payment->amount*-1, $this->company);
}
}

View File

@ -11,8 +11,6 @@
namespace App\Jobs\Invoice;
use App\Jobs\Client\UpdateClientBalance;
use App\Jobs\Client\UpdateClientPaidToDate;
use App\Jobs\Company\UpdateCompanyLedgerWithInvoice;
use App\Jobs\Company\UpdateCompanyLedgerWithPayment;
use App\Jobs\Util\SystemLogger;
@ -36,6 +34,7 @@ class UpdateInvoicePayment implements ShouldQueue
private $company;
/**
* @deprecated we only use this in test data creation. shouldn't be used in production
* Create the event listener.
*
* @return void
@ -64,14 +63,18 @@ class UpdateInvoicePayment implements ShouldQueue
if (strval($invoices_total) === strval($this->payment->amount)) {
$invoices->each(function ($invoice) {
UpdateCompanyLedgerWithPayment::dispatchNow($this->payment, ($invoice->balance*-1), $this->company);
UpdateClientBalance::dispatchNow($this->payment->client, $invoice->balance*-1, $this->company);
UpdateClientPaidToDate::dispatchNow($this->payment->client, $invoice->balance, $this->company);
$this->payment->client
->updateBalance($invoice->balance*-1)
->updatePaidToDate($invoice->balance)
->save();
$invoice->pivot->amount = $invoice->balance;
$invoice->pivot->save();
$invoice->clearPartial();
$invoice->updateBalance($invoice->balance*-1);
$invoice->clearPartial()
->updateBalance($invoice->balance*-1)
->save();
});
}
/*Combination of partials and full invoices are being paid*/
@ -92,25 +95,30 @@ class UpdateInvoicePayment implements ShouldQueue
$invoices->each(function ($invoice) {
if ($invoice->hasPartial()) {
UpdateCompanyLedgerWithPayment::dispatchNow($this->payment, ($invoice->partial*-1), $this->company);
UpdateClientBalance::dispatchNow($this->payment->client, $invoice->partial*-1, $this->company);
UpdateClientPaidToDate::dispatchNow($this->payment->client, $invoice->partial, $this->company);
$this->payment->client->updateBalance($invoice->partial*-1)
->updatePaidToDate($invoice->partial)
->save();
$invoice->pivot->amount = $invoice->partial;
$invoice->pivot->save();
$invoice->updateBalance($invoice->partial*-1);
$invoice->clearPartial();
$invoice->setDueDate();
$invoice->setStatus(Invoice::STATUS_PARTIAL);
$invoice->updateBalance($invoice->partial*-1)
->clearPartial()
->setDueDate()
->setStatus(Invoice::STATUS_PARTIAL)
->save();
} else {
UpdateCompanyLedgerWithPayment::dispatchNow($this->payment, ($invoice->balance*-1), $this->company);
UpdateClientBalance::dispatchNow($this->payment->client, $invoice->balance*-1, $this->company);
UpdateClientPaidToDate::dispatchNow($this->payment->client, $invoice->balance, $this->company);
$this->payment->client->updateBalance($invoice->balance*-1)
->updatePaidToDate($invoice->balance)
->save();
$invoice->pivot->amount = $invoice->balance;
$invoice->pivot->save();
$invoice->clearPartial();
$invoice->updateBalance($invoice->balance*-1);
$invoice->clearPartial()->updateBalance($invoice->balance*-1)->save();
}
});
} else {
@ -138,25 +146,3 @@ class UpdateInvoicePayment implements ShouldQueue
}
}
}
/*
$this->payment = $event->payment;
$invoice = $this->payment->invoice;
$adjustment = $this->payment->amount * -1;
$partial = max(0, $invoice->partial - $this->payment->amount);
$invoice->updateBalances($adjustment, $partial);
$invoice->updatePaidStatus(true);
// store a backup of the invoice
$activity = Activity::wherePaymentId($this->payment->id)
->whereActivityTypeId(ACTIVITY_TYPE_CREATE_PAYMENT)
->first();
$activity->json_backup = $invoice->hidePrivateFields()->toJSON();
$activity->save();
if ($invoice->balance == 0 && $this->payment->account->auto_archive_invoice) {
$invoiceRepo = app('App\Ninja\Repositories\InvoiceRepository');
$invoiceRepo->archive($invoice);
}
*/

View File

@ -0,0 +1,56 @@
<?php
/**
* Invoice Ninja (https://creditninja.com)
*
* @link https://github.com/creditninja/creditninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://creditninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Listeners\Credit;
use App\Factory\CreditInvitationFactory;
use App\Factory\InvoiceInvitationFactory;
use App\Models\InvoiceInvitation;
use App\Utils\Traits\MakesHash;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Spatie\Browsershot\Browsershot;
use Symfony\Component\Debug\Exception\FatalThrowableError;
class CreateCreditInvitation implements ShouldQueue
{
/**
* Handle the event.
*
* @param object $event
* @return void
*/
public function handle($event)
{
$credit = $event->credit;
$contacts = $credit->client->contacts;
$contacts->each(function ($contact) use ($credit) {
$invitation = InvoiceInvitation::whereCompanyId($credit->company_id)
->whereClientContactId($contact->id)
->whereCreditId($credit->id)
->first();
if (!$invitation && $contact->send_credit) {
$ii = CreditInvitationFactory::create($credit->company_id, $credit->user_id);
$ii->credit_id = $credit->id;
$ii->client_contact_id = $contact->id;
$ii->save();
} elseif ($invitation && !$contact->send_credit) {
$invitation->delete();
}
});
}
}

View File

@ -26,6 +26,7 @@ use App\Models\GroupSetting;
use App\Models\Language;
use App\Models\Timezone;
use App\Models\User;
use App\Services\Client\ClientService;
use App\Utils\Traits\CompanyGatewaySettings;
use App\Utils\Traits\GeneratesCounter;
use App\Utils\Traits\MakesDates;
@ -206,6 +207,36 @@ class Client extends BaseModel
})->first();
}
public function service() :ClientService
{
return new ClientService($this);
}
public function updatePaidToDate($amount) :ClientService
{
return $this->service()->updatePaidToDate($amount);
}
public function updateBalance($amount) :ClientService
{
return $this->service()->updateBalance($amount);
}
/**
* Adjusts client "balances" when a client
* makes a payment that goes on file, but does
* not effect the client.balance record
*
* @param float $amount Adjustment amount
* @return Client
*/
public function processUnappliedPayment($amount) :Client
{
return $this->service()->updatePaidToDate($amount)
->adjustCreditBalance($amount)
->save();
}
/**
*
* Returns the entire filtered set

View File

@ -18,11 +18,11 @@ use App\Helpers\Invoice\InvoiceSum;
use App\Helpers\Invoice\InvoiceSumInclusive;
use App\Jobs\Client\UpdateClientBalance;
use App\Jobs\Company\UpdateCompanyLedgerWithInvoice;
use App\Jobs\Invoice\ApplyInvoiceNumber;
use App\Jobs\Invoice\CreateInvoicePdf;
use App\Models\Currency;
use App\Models\Filterable;
use App\Models\PaymentTerm;
use App\Services\Invoice\InvoiceService;
use App\Utils\Number;
use App\Utils\Traits\InvoiceEmailBuilder;
use App\Utils\Traits\MakesDates;
@ -115,22 +115,6 @@ class Invoice extends BaseModel
const STATUS_UNPAID = -2;
const STATUS_REVERSED = -3;
public function getStatusAttribute()
{
if ($this->status_id == Invoice::STATUS_SENT && $this->due_date > Carbon::now()) {
return Invoice::STATUS_UNPAID;
} elseif ($this->status_id == Invoice::STATUS_PARTIAL && $this->partial_due_date > Carbon::now()) {
return Invoice::STATUS_UNPAID;
} elseif ($this->status_id == Invoice::STATUS_SENT && $this->due_date < Carbon::now()) {
return Invoice::STATUS_OVERDUE;
} elseif ($this->status_id == Invoice::STATUS_PARTIAL && $this->partial_due_date < Carbon::now()) {
return Invoice::STATUS_OVERDUE;
} else {
return $this->status_id;
}
}
public function company()
{
return $this->belongsTo(Company::class);
@ -176,11 +160,83 @@ class Invoice extends BaseModel
return $this->belongsToMany(Credit::class)->using(Paymentable::class)->withPivot('amount','refunded')->withTimestamps();;
}
/**
* Service entry points
*/
public function service() :InvoiceService
{
return new InvoiceService($this);
}
public function markPaid() :InvoiceService
{
return $this->service()->markPaid();
}
public function applyNumber() :InvoiceService
{
return $this->service()->applyNumber();
}
public function applyPayment($payment, $payment_amount) :InvoiceService
{
return $this->service()->applyPayment($payment, $payment_amount);
}
public function updateBalance($balance_adjustment) :InvoiceService
{
return $this->service()->updateBalance($balance_adjustment);
}
public function setDueDate() :InvoiceService
{
return $this->service->setDueDate();
}
public function setStatus($status) :InvoiceService
{
return $this->service()->setStatus($status);
}
public function clearPartial() :InvoiceService
{
return $this->service()->clearPartial();
}
public function updatePartial($amount) :InvoiceService
{
return $this->service()->updatePartial($amount);
}
public function markSent() :InvoiceService
{
return $this->service()->markSent();
}
public function markViewed() :InvoiceService
{
return $this->service()->markViewed();
}
/* ---------------- */
/* Settings getters */
/* ---------------- */
public function getStatusAttribute()
{
if ($this->status_id == Invoice::STATUS_SENT && $this->due_date > Carbon::now()) {
return Invoice::STATUS_UNPAID;
} elseif ($this->status_id == Invoice::STATUS_PARTIAL && $this->partial_due_date > Carbon::now()) {
return Invoice::STATUS_UNPAID;
} elseif ($this->status_id == Invoice::STATUS_SENT && $this->due_date < Carbon::now()) {
return Invoice::STATUS_OVERDUE;
} elseif ($this->status_id == Invoice::STATUS_PARTIAL && $this->partial_due_date < Carbon::now()) {
return Invoice::STATUS_OVERDUE;
} else {
return $this->status_id;
}
}
/**
* If True, prevents an invoice from being
* modified once it has been marked as sent
@ -192,30 +248,6 @@ class Invoice extends BaseModel
return $this->client->getSetting('lock_sent_invoices');
}
// /**
// * Determines if invoice overdue.
// *
// * @param float $balance The balance
// * @param date. $due_date The due date
// *
// * @return boolean True if overdue, False otherwise.
// */
// public static function isOverdue($balance, $due_date)
// {
// if (! $this->formatValue($balance,2) > 0 || ! $due_date) {
// return false;
// }
//
// // it isn't considered overdue until the end of the day
// return strtotime($this->createClientDate(date(), $this->client->timezone()->name)) > (strtotime($due_date) + (60 * 60 * 24));
// }
public function markViewed() :void
{
$this->last_viewed = Carbon::now()->format('Y-m-d H:i');
$this->save();
}
public function isPayable() : bool
{
if ($this->status_id == Invoice::STATUS_SENT && $this->is_deleted == false) {
@ -244,6 +276,22 @@ class Invoice extends BaseModel
}
/**
* @return bool
*/
public function isPartial() : bool
{
return $this->status_id >= self::STATUS_PARTIAL;
}
/**
* @return bool
*/
public function hasPartial() : bool
{
return ($this->partial && $this->partial > 0) === true;
}
public static function badgeForStatus(int $status)
{
switch ($status) {
@ -368,122 +416,12 @@ class Invoice extends BaseModel
return $storage_path;
}
/**
* @param bool $save
*/
public function updatePaidStatus($paid = false, $save = true) : bool
{
$status_id = false;
if ($paid && $this->balance == 0) {
$status_id = self::STATUS_PAID;
} elseif ($paid && $this->balance > 0 && $this->balance < $this->amount) {
$status_id = self::STATUS_PARTIAL;
} elseif ($this->hasPartial() && $this->balance > 0) {
$status_id = ($this->balance == $this->amount ? self::STATUS_SENT : self::STATUS_PARTIAL);
}
if ($status_id && $status_id != $this->status_id) {
$this->status_id = $status_id;
if ($save) {
$this->save();
}
}
}
/**
* @return bool
*/
public function hasPartial() : bool
{
return ($this->partial && $this->partial > 0) === true;
}
/**
* @return bool
*/
public function isPartial() : bool
{
return $this->status_id >= self::STATUS_PARTIAL;
}
/**
* Clear partial fields
* @return void
*/
public function clearPartial() : void
{
$this->partial = null;
$this->partial_due_date = null;
$this->save();
}
/**
* @param float $balance_adjustment
*/
public function updateBalance($balance_adjustment)
{
if ($this->is_deleted) {
return;
}
$balance_adjustment = floatval($balance_adjustment);
$this->balance = $this->balance + $balance_adjustment;
if ($this->balance == 0) {
$this->status_id = self::STATUS_PAID;
$this->save();
event(new InvoiceWasPaid($this, $this->company));
return;
}
$this->save();
}
public function setDueDate()
{
$this->due_date = Carbon::now()->addDays($this->client->getSetting('payment_terms'));
$this->save();
}
public function setStatus($status)
{
$this->status_id = $status;
$this->save();
}
public function markSent()
{
/* Return immediately if status is not draft */
if ($this->status_id != Invoice::STATUS_DRAFT) {
return $this;
}
$this->status_id = Invoice::STATUS_SENT;
$this->markInvitationsSent();
$this->setReminder();
event(new InvoiceWasMarkedSent($this, $this->company));
UpdateClientBalance::dispatchNow($this->client, $this->balance, $this->company);
ApplyInvoiceNumber::dispatchNow($this, $this->client->getMergedSettings(), $this->company);
UpdateCompanyLedgerWithInvoice::dispatchNow($this, $this->balance, $this->company);
$this->save();
return $this;
}
/**
* Updates Invites to SENT
*
*/
private function markInvitationsSent()
public function markInvitationsSent()
{
$this->invitations->each(function ($invitation) {
if (!isset($invitation->sent_date)) {
@ -492,4 +430,52 @@ class Invoice extends BaseModel
}
});
}
/* Graveyard */
// /**
// * Determines if invoice overdue.
// *
// * @param float $balance The balance
// * @param date. $due_date The due date
// *
// * @return boolean True if overdue, False otherwise.
// */
// public static function isOverdue($balance, $due_date)
// {
// if (! $this->formatValue($balance,2) > 0 || ! $due_date) {
// return false;
// }
//
// // it isn't considered overdue until the end of the day
// return strtotime($this->createClientDate(date(), $this->client->timezone()->name)) > (strtotime($due_date) + (60 * 60 * 24));
// }
/**
* @param bool $save
*
* Has this been dragged from V1?
*/
// public function updatePaidStatus($paid = false, $save = true) : bool
// {
// $status_id = false;
// if ($paid && $this->balance == 0) {
// $status_id = self::STATUS_PAID;
// } elseif ($paid && $this->balance > 0 && $this->balance < $this->amount) {
// $status_id = self::STATUS_PARTIAL;
// } elseif ($this->hasPartial() && $this->balance > 0) {
// $status_id = ($this->balance == $this->amount ? self::STATUS_SENT : self::STATUS_PARTIAL);
// }
// if ($status_id && $status_id != $this->status_id) {
// $this->status_id = $status_id;
// if ($save) {
// $this->save();
// }
// }
// }
}

View File

@ -59,7 +59,8 @@ class Payment extends BaseModel
'amount',
'date',
'transaction_reference',
'number'
'number',
'is_manual'
];
protected $casts = [

View File

@ -16,7 +16,6 @@ use App\Events\Invoice\InvoiceWasUpdated;
use App\Factory\InvoiceInvitationFactory;
use App\Helpers\Invoice\InvoiceSum;
use App\Jobs\Company\UpdateCompanyLedgerWithInvoice;
use App\Jobs\Invoice\ApplyInvoiceNumber;
use App\Jobs\Invoice\CreateInvoiceInvitations;
use App\Jobs\Product\UpdateOrCreateProduct;
use App\Listeners\Invoice\CreateInvoiceInvitation;
@ -115,7 +114,7 @@ class InvoiceRepository extends BaseRepository
UpdateCompanyLedgerWithInvoice::dispatchNow($invoice, ($finished_amount - $starting_amount), $invoice->company);
}
$invoice = ApplyInvoiceNumber::dispatchNow($invoice, $invoice->client->getMergedSettings(), $invoice->company);
$invoice = $invoice->applyNumber()->save();
if ($invoice->company->update_products !== false) {
UpdateOrCreateProduct::dispatch($invoice->line_items, $invoice, $invoice->company);
@ -133,6 +132,6 @@ class InvoiceRepository extends BaseRepository
*/
public function markSent(Invoice $invoice) : ?Invoice
{
return $invoice->markSent();
return $invoice->markSent()->save();
}
}

View File

@ -13,11 +13,8 @@ namespace App\Repositories;
use App\Events\Payment\PaymentWasCreated;
use App\Factory\CreditFactory;
use App\Jobs\Client\UpdateClientPaidToDate;
use App\Jobs\Company\UpdateCompanyLedgerWithPayment;
use App\Jobs\Credit\ApplyCreditPayment;
use App\Jobs\Invoice\ApplyClientPayment;
use App\Jobs\Invoice\ApplyInvoicePayment;
use App\Jobs\Invoice\UpdateInvoicePayment;
use App\Models\Credit;
use App\Models\Invoice;
@ -80,8 +77,7 @@ class PaymentRepository extends BaseRepository
if (!$payment->number)
$payment->number = $payment->client->getNextPaymentNumber($payment->client);
//we only ever update the ACTUAL amount of money transferred
UpdateClientPaidToDate::dispatchNow($payment->client, $payment->amount, $payment->company);
$payment->client->updatePaidToDate($payment->amount)->save();
$invoice_totals = 0;
$credit_totals = 0;
@ -98,12 +94,12 @@ class PaymentRepository extends BaseRepository
$invoice = Invoice::whereId($paid_invoice['invoice_id'])->first();
if ($invoice) {
ApplyInvoicePayment::dispatchNow($invoice, $payment, $paid_invoice['amount'], $invoice->company);
$invoice->applyPayment($payment, $paid_invoice['amount'])->save();
}
}
} else {
//payment is made, but not to any invoice, therefore we are applying the payment to the clients credit
ApplyClientPayment::dispatchNow($payment, $payment->company);
$payment->client->processUnappliedPayment($payment->amount);
}
if (array_key_exists('credits', $data) && is_array($data['credits'])) {

View File

@ -0,0 +1,53 @@
<?php
/**
* client Ninja (https://clientninja.com)
*
* @link https://github.com/clientninja/clientninja source repository
*
* @copyright Copyright (c) 2020. client Ninja LLC (https://clientninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Services\Client;
use App\Models\Client;
class ClientService
{
private $client;
public function __construct(Client $client)
{
$this->client = $client;
}
public function updateBalance(float $amount)
{
$this->client->balance += $amount;
return $this;
}
public function updatePaidToDate(float $amount)
{
$this->client->paid_to_date += $amount;
return $this;
}
public function adjustCreditBalance(float $amount)
{
$this->client->credit_balance += $amount;
return $this;
}
public function save() :Client
{
$this->client->save();
return $this->client;
}
}

View File

@ -0,0 +1,57 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com)
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Services\Invoice;
use App\Events\Payment\PaymentWasCreated;
use App\Factory\PaymentFactory;
use App\Jobs\Company\UpdateCompanyLedgerWithPayment;
use App\Models\Invoice;
use App\Models\Payment;
use App\Services\Client\ClientService;
use App\Services\Payment\PaymentService;
use App\Utils\Traits\GeneratesCounter;
class ApplyNumber
{
use GeneratesCounter;
private $client;
public function __construct($client)
{
$this->client = $client;
}
public function __invoke($invoice)
{
if ($invoice->number != '')
return $invoice;
switch ($this->client->getSetting('counter_number_applied')) {
case 'when_saved':
$invoice->number = $this->getNextInvoiceNumber($this->client);
break;
case 'when_sent':
if ($invoice->status_id == Invoice::STATUS_SENT) {
$invoice->number = $this->getNextInvoiceNumber($this->client);
}
break;
default:
# code...
break;
}
return $invoice;
}
}

View File

@ -0,0 +1,61 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com)
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Services\Invoice;
use App\Jobs\Company\UpdateCompanyLedgerWithPayment;
use App\Models\Invoice;
use App\Models\Payment;
use App\Services\Client\ClientService;
class ApplyPayment
{
private $invoice;
public function __construct($invoice)
{
$this->invoice = $invoice;
}
public function __invoke($payment, $payment_amount)
{
UpdateCompanyLedgerWithPayment::dispatchNow($payment, ($payment_amount*-1), $payment->company);
$payment->client->updateBalance($payment_amount*-1)->save();
/* Update Pivot Record amount */
$payment->invoices->each(function ($inv) use($payment_amount){
if ($inv->id == $this->invoice->id) {
$inv->pivot->amount = $payment_amount;
$inv->pivot->save();
}
});
if ($this->invoice->hasPartial()) {
//is partial and amount is exactly the partial amount
if ($this->invoice->partial == $payment_amount) {
$this->invoice->clearPartial()->setDueDate()->setStatus(Invoice::STATUS_PARTIAL)->updateBalance($payment_amount*-1);
} elseif ($this->invoice->partial > 0 && $this->invoice->partial > $payment_amount) { //partial amount exists, but the amount is less than the partial amount
$this->invoice->updatePartial($payment_amount*-1)->updateBalance($payment_amount*-1);
} elseif ($this->invoice->partial > 0 && $this->invoice->partial < $payment_amount) { //partial exists and the amount paid is GREATER than the partial amount
$this->invoice->clearPartial()->setDueDate()->setStatus(Invoice::STATUS_PARTIAL)->updateBalance($payment_amount*-1);
}
} elseif ($payment_amount == $this->invoice->balance) { //total invoice paid.
$this->invoice->clearPartial()->setStatus(Invoice::STATUS_PAID)->updateBalance($payment_amount*-1);
} elseif($payment_amount < $this->invoice->balance) { //partial invoice payment made
$this->invoice->clearPartial()->updateBalance($payment_amount*-1);
}
return $this->invoice;
}
}

View File

@ -0,0 +1,165 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com)
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Services\Invoice;
use App\Models\Invoice;
use App\Models\Payment;
use App\Services\Client\ClientService;
use App\Services\Invoice\ApplyNumber;
use App\Services\Invoice\MarkInvoicePaid;
use App\Services\Invoice\MarkSent;
use App\Services\Invoice\UpdateBalance;
use Illuminate\Support\Carbon;
class InvoiceService
{
private $invoice;
protected $client_service;
public function __construct($invoice)
{
$this->invoice = $invoice;
$this->client_service = new ClientService($invoice->client);
}
/**
* Marks as invoice as paid
* and executes child sub functions
* @return $this InvoiceService object
*/
public function markPaid()
{
$mark_invoice_paid = new MarkPaid($this->client_service);
$this->invoice = $mark_invoice_paid($this->invoice);
return $this;
}
/**
* Applies the invoice number
* @return $this InvoiceService object
*/
public function applyNumber()
{
$apply_number = new ApplyNumber($this->invoice->client);
$this->invoice = $apply_number($this->invoice);
return $this;
}
/**
* Apply a payment amount to an invoice.
* @param Payment $payment The Payment
* @param float $payment_amount The Payment amount
* @return InvoiceService Parent class object
*/
public function applyPayment(Payment $payment, float $payment_amount)
{
$apply_payment = new ApplyPayment($this->invoice);
$this->invoice = $apply_payment($payment, $payment_amount);
return $this;
}
/**
* Update an invoice balance
* @param float $balance_adjustment The amount to adjust the invoice by
* a negative amount will REDUCE the invoice balance, a positive amount will INCREASE
* the invoice balance
* @return InvoiceService Parent class object
*/
public function updateBalance($balance_adjustment)
{
$update_balance = new UpdateBalance($this->invoice);
$this->invoice = $update_balance($balance_adjustment);
return $this;
}
public function markSent()
{
$mark_sent = new MarkSent($this->invoice->client);
$this->invoice = $mark_sent($this->invoice);
return $this;
}
public function markViewed()
{
$this->invoice->last_viewed = Carbon::now()->format('Y-m-d H:i');
return $this;
}
/* One liners */
public function setDueDate()
{
$this->invoice->due_date = Carbon::now()->addDays($this->invoice->client->getSetting('payment_terms'));
return $this;
}
public function setStatus($status)
{
$this->invoice->status_id = $status;
return $this;
}
public function clearPartial()
{
$this->invoice->partial = null;
$this->invoice->partial_due_date = null;
return $this;
}
public function updatePartial($amount)
{
$this->invoice->partial += $amount;
return $this;
}
/**
* Saves the invoice
* @return Invoice object
*/
public function save() :?Invoice
{
$this->invoice->save();
return $this->invoice;
}
}

View File

@ -0,0 +1,67 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com)
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Services\Invoice;
use App\Events\Payment\PaymentWasCreated;
use App\Factory\PaymentFactory;
use App\Jobs\Company\UpdateCompanyLedgerWithPayment;
use App\Models\Invoice;
use App\Models\Payment;
use App\Services\Client\ClientService;
use App\Services\Payment\PaymentService;
class MarkPaid
{
private $client_service;
public function __construct($client_service)
{
$this->client_service = $client_service;
}
public function __invoke($invoice)
{
if($invoice->status_id == Invoice::STATUS_DRAFT)
$invoice->markSent();
/* Create Payment */
$payment = PaymentFactory::create($invoice->company_id, $invoice->user_id);
$payment->amount = $invoice->balance;
$payment->status_id = Payment::STATUS_COMPLETED;
$payment->client_id = $invoice->client_id;
$payment->transaction_reference = ctrans('texts.manual_entry');
/* Create a payment relationship to the invoice entity */
$payment->save();
$payment->invoices()->attach($invoice->id, [
'amount' => $payment->amount
]);
$invoice->updateBalance($payment->amount*-1)->save();
/* Update Invoice balance */
event(new PaymentWasCreated($payment, $payment->company));
UpdateCompanyLedgerWithPayment::dispatchNow($payment, ($payment->amount*-1), $payment->company);
$this->client_service
->updateBalance($payment->amount*-1)
->updatePaidToDate($payment->amount)
->save();
return $invoice;
}
}

View File

@ -0,0 +1,53 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com)
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Services\Invoice;
use App\Events\Invoice\InvoiceWasMarkedSent;
use App\Jobs\Company\UpdateCompanyLedgerWithInvoice;
use App\Models\Invoice;
class MarkSent
{
private $client;
public function __construct($client)
{
$this->client = $client;
}
public function __invoke($invoice)
{
/* Return immediately if status is not draft */
if ($invoice->status_id != Invoice::STATUS_DRAFT) {
return $invoice;
}
$invoice->status_id = Invoice::STATUS_SENT;
$invoice->markInvitationsSent();
$invoice->setReminder();
event(new InvoiceWasMarkedSent($invoice, $invoice->company));
$this->client->updateBalance($invoice->balance)->save();
$invoice->applyNumber()->save();
UpdateCompanyLedgerWithInvoice::dispatchNow($invoice, $invoice->balance, $invoice->company);
return $invoice;
}
}

View File

@ -0,0 +1,47 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com)
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Services\Invoice;
use App\Models\Invoice;
class UpdateBalance
{
private $invoice;
public function __construct($invoice)
{
$this->invoice = $invoice;
}
public function __invoke($balance_adjustment)
{
if ($this->invoice->is_deleted) {
return;
}
$balance_adjustment = floatval($balance_adjustment);
$this->invoice->balance += $balance_adjustment;
if ($this->invoice->balance == 0) {
$this->status_id = Invoice::STATUS_PAID;
// $this->save();
// event(new InvoiceWasPaid($this, $this->company));
}
return $this->invoice;
}
}

View File

@ -0,0 +1,45 @@
<?php
/**
* payment Ninja (https://paymentninja.com)
*
* @link https://github.com/paymentninja/paymentninja source repository
*
* @copyright Copyright (c) 2020. payment Ninja LLC (https://paymentninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Services\Payment;
use App\Factory\PaymentFactory;
use App\Models\Payment;
class PaymentService
{
private $payment;
public function __construct($payment)
{
$this->payment = $payment;
}
public function manualPayment($invoice) :?Payment
{
/* Create Payment */
$payment = PaymentFactory::create($invoice->company_id, $invoice->user_id);
$payment->amount = $invoice->balance;
$payment->status_id = Payment::STATUS_COMPLETED;
$payment->client_id = $invoice->client_id;
$payment->transaction_reference = ctrans('texts.manual_entry');
/* Create a payment relationship to the invoice entity */
$payment->save();
$payment->invoices()->attach($invoice->id, [
'amount' => $payment->amount
]);
return $payment;
}
}

View File

@ -225,7 +225,7 @@ trait Refundable
{
$invoice = Invoice::find($refunded_invoice['invoice_id']);
$invoice->updateBalance($refunded_invoice['amount']);
$invoice->updateBalance($refunded_invoice['amount'])->save();
if($invoice->amount == $invoice->balance)
$invoice->setStatus(Invoice::STATUS_SENT);

View File

@ -10,12 +10,14 @@ use App\Helpers\Invoice\InvoiceSum;
use App\Helpers\Invoice\InvoiceSumInclusive;
use App\Jobs\Company\UpdateCompanyLedgerWithInvoice;
use App\Jobs\Invoice\UpdateInvoicePayment;
use App\Listeners\Credit\CreateCreditInvitation;
use App\Listeners\Invoice\CreateInvoiceInvitation;
use App\Models\Account;
use App\Models\Client;
use App\Models\ClientContact;
use App\Models\CompanyGateway;
use App\Models\CompanyToken;
use App\Models\Credit;
use App\Models\GatewayType;
use App\Models\GroupSetting;
use App\Models\Invoice;
@ -23,6 +25,7 @@ use App\Models\Payment;
use App\Models\PaymentType;
use App\Models\User;
use App\Models\UserAccount;
use App\Repositories\CreditRepository;
use App\Repositories\InvoiceRepository;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\Cache;
@ -163,7 +166,7 @@ class RandomDataSeeder extends Seeder
UpdateCompanyLedgerWithInvoice::dispatchNow($invoice, $invoice->balance, $invoice->company);
$invoice_repo->markSent($invoice);
$invoice->markSent()->save();
event(new InvoiceWasMarkedSent($invoice, $company));
@ -188,6 +191,31 @@ class RandomDataSeeder extends Seeder
});
/*Credits*/
factory(\App\Models\Credit::class,20)->create(['user_id' => $user->id, 'company_id' => $company->id, 'client_id' => $client->id]);
$credits = Credit::cursor();
$credit_repo = new CreditRepository();
$credits->each(function ($credit) use($credit_repo, $user, $company, $client){
$credit_calc = null;
if($credit->uses_inclusive_taxes)
$credit_calc = new InvoiceSumInclusive($credit);
else
$credit_calc = new InvoiceSum($credit);
$credit = $credit_calc->build()->getInvoice();
$credit->save();
event(new CreateCreditInvitation($credit));
//$invoice->markSent()->save();
});
/** Recurring Invoice Factory */
factory(\App\Models\RecurringInvoice::class,10)->create(['user_id' => $user->id, 'company_id' => $company->id, 'client_id' => $client->id]);

View File

@ -15,7 +15,7 @@ use Tests\TestCase;
/**
* @test
* @covers App\Jobs\Invoice\MarkInvoicePaid
* @covers App\Services\Invoice\MarkInvoicePaid
*/
class MarkInvoicePaidTest extends TestCase
{
@ -37,9 +37,15 @@ class MarkInvoicePaidTest extends TestCase
public function testMarkInvoicePaidInvoice()
{
MarkInvoicePaid::dispatchNow($this->invoice, $this->company);
$invoice = Invoice::find($this->invoice->id);
$invoice_balance = $invoice->balance;
$client = $invoice->client;
$client_balance = $client->balance;
$this->invoice->markPaid();
$invoice = Invoice::find($this->invoice->id);
$client = $invoice->client;
$this->assertEquals(0.00, $invoice->balance);
@ -52,7 +58,7 @@ class MarkInvoicePaidTest extends TestCase
//events are not firing which makes this impossible to control.
$this->assertEquals(0.00, $invoice->balance);
$this->assertEquals(($client_balance - $invoice_balance), $client->balance);
}
}

View File

@ -37,8 +37,7 @@ class UpdateCompanyLedgerTest extends TestCase
public function testPaymentIsPresentInLedger()
{
$invoice = MarkInvoicePaid::dispatchNow($this->invoice, $this->company);
$invoice = $this->invoice->markPaid()->save();
$ledger = CompanyLedger::whereClientId($invoice->client_id)
->whereCompanyId($invoice->company_id)