diff --git a/.gitignore b/.gitignore index 39498b28e145..04ca0e2494a5 100644 --- a/.gitignore +++ b/.gitignore @@ -17,7 +17,7 @@ local_version.txt /resources/assets/bower /public/logo - +/storage/* .env.dusk.local /public/vendors/* *.log diff --git a/app/Helpers/Invoice/InvoiceSumInclusive.php b/app/Helpers/Invoice/InvoiceSumInclusive.php index 8f63230335bf..2356f7612bd0 100644 --- a/app/Helpers/Invoice/InvoiceSumInclusive.php +++ b/app/Helpers/Invoice/InvoiceSumInclusive.php @@ -230,14 +230,16 @@ class InvoiceSumInclusive private function setCalculatedAttributes() { /* If amount != balance then some money has been paid on the invoice, need to subtract this difference from the total to set the new balance */ - if ($this->invoice->amount != $this->invoice->balance) { - $paid_to_date = $this->invoice->amount - $this->invoice->balance; + if ($this->invoice->status_id != Invoice::STATUS_DRAFT) { + if ($this->invoice->amount != $this->invoice->balance) { + $paid_to_date = $this->invoice->amount - $this->invoice->balance; - $this->invoice->balance = $this->formatValue($this->getTotal(), $this->invoice->client->currency()->precision) - $paid_to_date; - } else { - $this->invoice->balance = $this->formatValue($this->getTotal(), $this->invoice->client->currency()->precision); + $this->invoice->balance = $this->formatValue($this->getTotal(), $this->invoice->client->currency()->precision) - $paid_to_date; + } else { + $this->invoice->balance = $this->formatValue($this->getTotal(), $this->invoice->client->currency()->precision); + } } - + /* Set new calculated total */ $this->invoice->amount = $this->formatValue($this->getTotal(), $this->invoice->client->currency()->precision); diff --git a/app/Http/Controllers/InvoiceController.php b/app/Http/Controllers/InvoiceController.php index b45b9a3c26f2..8ee5573f0d2d 100644 --- a/app/Http/Controllers/InvoiceController.php +++ b/app/Http/Controllers/InvoiceController.php @@ -102,7 +102,6 @@ class InvoiceController extends BaseController * response=422, * description="Validation error", * @OA\JsonContent(ref="#/components/schemas/ValidationError"), - * ), * @OA\Response( * response="default", @@ -691,7 +690,7 @@ class InvoiceController extends BaseController break; case 'delete': //need to make sure the invoice is cancelled first!! - $invoice->service()->handleCancellation()->save(); + //$invoice->service()->handleCancellation()->save(); $this->invoice_repo->delete($invoice); diff --git a/app/Jobs/Entity/CreateEntityPdf.php b/app/Jobs/Entity/CreateEntityPdf.php index 9b9027fef718..5c05c6e35846 100644 --- a/app/Jobs/Entity/CreateEntityPdf.php +++ b/app/Jobs/Entity/CreateEntityPdf.php @@ -146,7 +146,7 @@ class CreateEntityPdf implements ShouldQueue ->build(); //todo - move this to the client creation stage so we don't keep hitting this unnecessarily - Storage::makeDirectory($path, 0775); + // Storage::makeDirectory($path, 0775); $pdf = null; diff --git a/app/Mail/BouncedEmail.php b/app/Mail/BouncedEmail.php index 7aaedccff532..a1fe1ca162fe 100644 --- a/app/Mail/BouncedEmail.php +++ b/app/Mail/BouncedEmail.php @@ -45,7 +45,7 @@ class BouncedEmail extends Mailable implements ShouldQueue $subject = ctrans("texts.notification_{$entity_type}_bounced_subject", ['invoice' => $invoice->number]); return - $this->from(config('mail.from.name'), config('mail.from.address')) + $this->from(config('mail.from.address'), config('mail.from.name')) ->text() ->subject($subject); diff --git a/app/Mail/DownloadInvoices.php b/app/Mail/DownloadInvoices.php index 55859e1d72dc..d65322b2980e 100644 --- a/app/Mail/DownloadInvoices.php +++ b/app/Mail/DownloadInvoices.php @@ -30,7 +30,9 @@ class DownloadInvoices extends Mailable */ public function build() { - return $this->from(config('mail.from.name'), config('mail.from.address')) + + return $this->from(config('mail.from.address'), config('mail.from.name')) + ->subject(ctrans('texts.download_files')) ->markdown( 'email.admin.download_files', diff --git a/app/Mail/ExistingMigration.php b/app/Mail/ExistingMigration.php index a050fcb988de..bf2b9e29a2d5 100644 --- a/app/Mail/ExistingMigration.php +++ b/app/Mail/ExistingMigration.php @@ -27,7 +27,9 @@ class ExistingMigration extends Mailable */ public function build() { - return $this->from(config('mail.from.name'), config('mail.from.address')) + + return $this->from(config('mail.from.address'), config('mail.from.name')) + ->view('email.migration.existing'); } } diff --git a/app/Mail/MigrationCompleted.php b/app/Mail/MigrationCompleted.php index 358a15a6c3bc..301b91c60ca3 100644 --- a/app/Mail/MigrationCompleted.php +++ b/app/Mail/MigrationCompleted.php @@ -29,7 +29,7 @@ class MigrationCompleted extends Mailable { $data['settings'] = auth()->user()->company()->settings; - return $this->from(config('mail.from.name'), config('mail.from.address')) + return $this->from(config('mail.from.address'), config('mail.from.name')) ->view('email.migration.completed', $data); } } diff --git a/app/Mail/MigrationFailed.php b/app/Mail/MigrationFailed.php index e4bf4ef371b5..cf11729546fb 100644 --- a/app/Mail/MigrationFailed.php +++ b/app/Mail/MigrationFailed.php @@ -31,7 +31,9 @@ class MigrationFailed extends Mailable */ public function build() { - return $this->from(config('mail.from.name'), config('mail.from.address')) + + return $this->from(config('mail.from.address'), config('mail.from.name')) + ->view('email.migration.failed'); } } diff --git a/app/PaymentDrivers/BaseDriver.php b/app/PaymentDrivers/BaseDriver.php index 6730c1ea947d..7e097c704b53 100644 --- a/app/PaymentDrivers/BaseDriver.php +++ b/app/PaymentDrivers/BaseDriver.php @@ -33,6 +33,7 @@ use Checkout\Library\Exceptions\CheckoutHttpException; use Exception; use Illuminate\Http\Request; use Illuminate\Support\Carbon; +use Illuminate\Support\Str; /** * Class BaseDriver. diff --git a/app/Repositories/InvoiceRepository.php b/app/Repositories/InvoiceRepository.php index 40b5e6af9f83..a491b4c8c2f5 100644 --- a/app/Repositories/InvoiceRepository.php +++ b/app/Repositories/InvoiceRepository.php @@ -69,13 +69,38 @@ class InvoiceRepository extends BaseRepository return $invoice; } - $invoice->service()->markDeleted()->handleCancellation()->save(); +// $invoice->service()->markDeleted()->handleCancellation()->save(); + $invoice = $invoice->service()->markDeleted()->save(); parent::delete($invoice); return $invoice; } + /** + * Handles the restoration on a deleted invoice. + * + * @param [type] $invoice [description] + * @return [type] [description] + */ + public function restore($invoice) :Invoice + { + //if we have just archived, only perform a soft restore + if(!$invoice->is_deleted) { + + parent::restore($invoice); + + return $invoice; + } + + // reversed delete invoice actions + $invoice = $invoice->service()->handleRestore()->save(); + + parent::restore($invoice); + + return $invoice; + } + public function reverse() { } diff --git a/app/Services/Credit/MarkSent.php b/app/Services/Credit/MarkSent.php index fdd6e1d891bf..1591feb095cb 100644 --- a/app/Services/Credit/MarkSent.php +++ b/app/Services/Credit/MarkSent.php @@ -43,6 +43,7 @@ class MarkSent ->service() ->setStatus(Credit::STATUS_SENT) ->applyNumber() + ->adjustBalance($this->credit->amount) ->save(); diff --git a/app/Services/Invoice/HandleRestore.php b/app/Services/Invoice/HandleRestore.php new file mode 100644 index 000000000000..d647767355bc --- /dev/null +++ b/app/Services/Invoice/HandleRestore.php @@ -0,0 +1,111 @@ +invoice = $invoice; + } + + public function run() + { + + if(!$this->invoice->is_deleted) + return $this->invoice; + + //determine whether we need to un-delete payments OR just modify the payment amount /applied balances. + + foreach($this->invoice->payments as $payment) + { + + $payment->restore(); + + $payment->paymentables() + ->where('paymentable_type', '=', 'invoices') + ->where('paymentable_id', $this->invoice->id) + ->restore(); + + $payment_amount = $payment->paymentables() + ->where('paymentable_type', '=', 'invoices') + ->where('paymentable_id', $this->invoice->id) + ->sum(\DB::raw('amount')); + + info($payment->amount . " == " . $payment_amount); + + if($payment->amount == $payment_amount) { + + $payment->is_deleted = false; + $payment->save(); + + } + else { + + $payment->is_deleted = false; + $payment->amount += $this->payment_total; + $payment->applied += $this->payment_total; + $payment->save(); + } + + $this->payment_total += $payment_amount; + + } + + + + + //adjust ledger balance + $this->invoice->ledger()->updateInvoiceBalance($this->invoice->balance, 'Restored invoice {$this->invoice->number}')->save(); + + //adjust paid to dates + $this->invoice->client->service()->updatePaidToDate($this->payment_total)->save(); + + $this->invoice->client->service()->updateBalance($this->invoice->balance)->save(); + + $this->invoice->ledger()->updatePaymentBalance($this->payment_total, 'Restored payment for invoice {$this->invoice->number}')->save(); + + $this->windBackInvoiceNumber(); + + return $this->invoice; + } + + + private function windBackInvoiceNumber() + { + + $findme = '_' . ctrans('texts.deleted'); + + $pos = strpos($this->invoice->number, $findme); + + $new_invoice_number = substr($this->invoice->number, 0, $pos); + + try { + $this->invoice->number = $new_invoice_number; + $this->invoice->save(); + } + catch(\Exception $e){ + info("I could not wind back the invoice number"); + } + + } +} + diff --git a/app/Services/Invoice/InvoiceService.php b/app/Services/Invoice/InvoiceService.php index 2015fad59cb5..ed0c19c3af2b 100644 --- a/app/Services/Invoice/InvoiceService.php +++ b/app/Services/Invoice/InvoiceService.php @@ -164,6 +164,13 @@ class InvoiceService return $this; } + public function handleRestore() + { + $this->invoice = (new HandleRestore($this->invoice))->run(); + + return $this; + } + public function reverseCancellation() { $this->invoice = (new HandleCancellation($this->invoice))->reverse(); diff --git a/app/Services/Invoice/MarkInvoiceDeleted.php b/app/Services/Invoice/MarkInvoiceDeleted.php index cc830756a21c..137bce5bb924 100644 --- a/app/Services/Invoice/MarkInvoiceDeleted.php +++ b/app/Services/Invoice/MarkInvoiceDeleted.php @@ -14,6 +14,7 @@ namespace App\Services\Invoice; use App\Models\Invoice; use App\Services\AbstractService; use App\Utils\Traits\GeneratesCounter; +use Illuminate\Support\Facades\DB; class MarkInvoiceDeleted extends AbstractService { @@ -21,6 +22,10 @@ class MarkInvoiceDeleted extends AbstractService private $invoice; + private $adjustment_amount = 0; + + private $total_payments = 0; + public function __construct(Invoice $invoice) { $this->invoice = $invoice; @@ -28,7 +33,94 @@ class MarkInvoiceDeleted extends AbstractService public function run() { + if($this->invoice->is_deleted) + return $this->invoice; + + // if(in_array($this->invoice->status_id, ['currencies', 'industries', 'languages', 'countries', 'banks'])) + // return $this-> + + $this->cleanup() + ->setAdjustmentAmount() + ->deletePaymentables() + ->adjustPayments() + ->adjustPaidToDate() + ->adjustBalance() + ->adjustLedger(); + + return $this->invoice; + } + + private function adjustLedger() + { + $this->invoice->ledger()->updatePaymentBalance($this->adjustment_amount * -1); + + return $this; + } + + private function adjustPaidToDate() + { + $this->invoice->client->service()->updatePaidToDate($this->adjustment_amount * -1)->save(); + + return $this; + } + + private function adjustBalance() + { + $this->invoice->client->service()->updateBalance($this->invoice->balance * -1)->save(); + + return $this; + } + + private function adjustPayments() + { + //if total payments = adjustment amount - that means we need to delete the payments as well. + + if($this->adjustment_amount == $this->total_payments) { + + $this->invoice->payments()->update(['payments.deleted_at' => now(), 'payments.is_deleted' => true]); + + } + else { + //adjust payments down by the amount applied to the invoice payment. + + $this->invoice->payments->each(function ($payment){ + + $payment_adjustment = $payment->paymentables + ->where('paymentable_type', '=', 'invoices') + ->where('paymentable_id', $this->invoice->id) + ->sum(DB::raw('amount')); + + $payment->amount -= $payment_adjustment; + $payment->applied -= $payment_adjustment; + $payment->save(); + + }); + } + + return $this; + } + + private function setAdjustmentAmount() + { + + foreach ($this->invoice->payments as $payment) { + $this->adjustment_amount += $payment->paymentables + ->where('paymentable_type', '=', 'invoices') + ->where('paymentable_id', $this->invoice->id) + ->sum(DB::raw('amount')); + } + + + $this->total_payments = $this->invoice->payments->sum('amount'); + + return $this; + } + + private function cleanup() + { + $check = false; + $x=0; do { @@ -43,10 +135,10 @@ class MarkInvoiceDeleted extends AbstractService $this->invoice->tasks()->update(['invoice_id' => null]); $this->invoice->expenses()->update(['invoice_id' => null]); - return $this->invoice; + return $this; + } - private function calcNumber($x) { if ($x==0) { @@ -57,4 +149,19 @@ class MarkInvoiceDeleted extends AbstractService return $number; } + + + private function deletePaymentables() + { + + $this->invoice->payments->each(function ($payment){ + $payment->paymentables() + ->where('paymentable_type', '=', 'invoices') + ->where('paymentable_id', $this->invoice->id) + ->update(['deleted_at' => now()]); + }); + + + return $this; + } }