From c2990a21d07093b54701f87d66b3a58a396c5cd2 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Wed, 14 Apr 2021 16:48:32 +1000 Subject: [PATCH 01/11] Fixes for tests --- app/Console/Commands/CreateSingleAccount.php | 4 ++-- .../SubscriptionPlanSwitchController.php | 1 - app/Http/Livewire/SubscriptionPlanSwitch.php | 1 + .../Subscription/UpdateSubscriptionRequest.php | 2 +- tests/Feature/SubscriptionApiTest.php | 12 +++++++++--- 5 files changed, 13 insertions(+), 7 deletions(-) diff --git a/app/Console/Commands/CreateSingleAccount.php b/app/Console/Commands/CreateSingleAccount.php index 2a4dab445893..ab850b11aa1d 100644 --- a/app/Console/Commands/CreateSingleAccount.php +++ b/app/Console/Commands/CreateSingleAccount.php @@ -229,8 +229,8 @@ class CreateSingleAccount extends Command 'company_id' => $company->id, 'product_key' => 'enterprise_plan', 'notes' => 'The Enterprise Plan', - 'cost' => 10, - 'price' => 10, + 'cost' => 14, + 'price' => 14, 'quantity' => 1, ]); diff --git a/app/Http/Controllers/ClientPortal/SubscriptionPlanSwitchController.php b/app/Http/Controllers/ClientPortal/SubscriptionPlanSwitchController.php index 7adf172baa1a..a6cb764d0516 100644 --- a/app/Http/Controllers/ClientPortal/SubscriptionPlanSwitchController.php +++ b/app/Http/Controllers/ClientPortal/SubscriptionPlanSwitchController.php @@ -35,7 +35,6 @@ class SubscriptionPlanSwitchController extends Controller $amount = $recurring_invoice->subscription ->service() ->calculateUpgradePrice($recurring_invoice, $target); - /** * * Null value here is a proxy for diff --git a/app/Http/Livewire/SubscriptionPlanSwitch.php b/app/Http/Livewire/SubscriptionPlanSwitch.php index 078096ab7f61..ba77c857f6a4 100644 --- a/app/Http/Livewire/SubscriptionPlanSwitch.php +++ b/app/Http/Livewire/SubscriptionPlanSwitch.php @@ -82,6 +82,7 @@ class SubscriptionPlanSwitch extends Component public function handleBeforePaymentEvents(): void { + $this->state['show_loading_bar'] = true; $this->state['invoice'] = $this->target->service()->createChangePlanInvoice([ diff --git a/app/Http/Requests/Subscription/UpdateSubscriptionRequest.php b/app/Http/Requests/Subscription/UpdateSubscriptionRequest.php index fdf72b188633..99d33048a5f0 100644 --- a/app/Http/Requests/Subscription/UpdateSubscriptionRequest.php +++ b/app/Http/Requests/Subscription/UpdateSubscriptionRequest.php @@ -56,7 +56,7 @@ class UpdateSubscriptionRequest extends Request 'allow_plan_changes' => ['sometimes'], 'refund_period' => ['sometimes'], 'webhook_configuration' => ['array'], - 'name' => ['required', Rule::unique('subscriptions')->where('company_id', auth()->user()->company()->id)->ignore($this->subscription->id)] + 'name' => ['sometimes', Rule::unique('subscriptions')->where('company_id', auth()->user()->company()->id)->ignore($this->subscription->id)] ]; return $this->globalRules($rules); diff --git a/tests/Feature/SubscriptionApiTest.php b/tests/Feature/SubscriptionApiTest.php index 2ef470bbe649..a81bd8c21099 100644 --- a/tests/Feature/SubscriptionApiTest.php +++ b/tests/Feature/SubscriptionApiTest.php @@ -21,6 +21,7 @@ use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Support\Facades\Session; use Illuminate\Support\Str; +use Illuminate\Validation\ValidationException; use Tests\MockAccountData; use Tests\TestCase; @@ -40,6 +41,8 @@ class SubscriptionApiTest extends TestCase $this->makeTestData(); + $this->withoutExceptionHandling(); + Session::start(); $this->faker = \Faker\Factory::create(); @@ -92,20 +95,23 @@ class SubscriptionApiTest extends TestCase $product = Product::factory()->create([ 'company_id' => $this->company->id, 'user_id' => $this->user->id, - 'frequency_id' => RecurringInvoice::FREQUENCY_MONTHLY, ]); $response1 = $this ->withHeaders(['X-API-SECRET' => config('ninja.api_secret'),'X-API-TOKEN' => $this->token]) - ->post('/api/v1/subscriptions', ['product_ids' => $product->id, 'name' => Str::random(5)]) + ->post('/api/v1/subscriptions', ['product_ids' => $product->id, 'name' => Str::random(5)]) ->assertStatus(200) ->json(); - $response2 = $this + // try { + $response2 = $this ->withHeaders(['X-API-SECRET' => config('ninja.api_secret'),'X-API-TOKEN' => $this->token]) ->put('/api/v1/subscriptions/' . $response1['data']['id'], ['allow_cancellation' => true]) ->assertStatus(200) ->json(); + // }catch(ValidationException $e) { + // nlog($e->validator->getMessageBag()); + // } $this->assertNotEquals($response1['data']['allow_cancellation'], $response2['data']['allow_cancellation']); } From 2a4457483b10f5a1a9d2fbf8debff42d3b2274a4 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Wed, 14 Apr 2021 17:06:07 +1000 Subject: [PATCH 02/11] Fixes for tests --- tests/Feature/SubscriptionApiTest.php | 9 --------- 1 file changed, 9 deletions(-) diff --git a/tests/Feature/SubscriptionApiTest.php b/tests/Feature/SubscriptionApiTest.php index a81bd8c21099..cff411c33c4f 100644 --- a/tests/Feature/SubscriptionApiTest.php +++ b/tests/Feature/SubscriptionApiTest.php @@ -116,15 +116,6 @@ class SubscriptionApiTest extends TestCase $this->assertNotEquals($response1['data']['allow_cancellation'], $response2['data']['allow_cancellation']); } - /* - TypeError : Argument 1 passed to App\Transformers\SubscriptionTransformer::transform() must be an instance of App\Models\Subscription, bool given, called in /var/www/html/vendor/league/fractal/src/Scope.php on line 407 - /var/www/html/app/Transformers/SubscriptionTransformer.php:35 - /var/www/html/vendor/league/fractal/src/Scope.php:407 - /var/www/html/vendor/league/fractal/src/Scope.php:349 - /var/www/html/vendor/league/fractal/src/Scope.php:235 - /var/www/html/app/Http/Controllers/BaseController.php:395 - /var/www/html/app/Http/Controllers/SubscriptionController.php:408 - */ public function testSubscriptionDeleted() { From d0cb09d09409134271f580e54b503e5b7547fd33 Mon Sep 17 00:00:00 2001 From: = Date: Wed, 14 Apr 2021 19:55:43 +1000 Subject: [PATCH 03/11] Minor fixes for task controller --- app/Http/Controllers/SelfUpdateController.php | 2 +- app/Http/Controllers/TaskController.php | 4 +- .../Subscription/SubscriptionService.php | 48 +++++++++++-------- 3 files changed, 32 insertions(+), 22 deletions(-) diff --git a/app/Http/Controllers/SelfUpdateController.php b/app/Http/Controllers/SelfUpdateController.php index bbe4926ca739..cd77546c5d7d 100644 --- a/app/Http/Controllers/SelfUpdateController.php +++ b/app/Http/Controllers/SelfUpdateController.php @@ -85,7 +85,7 @@ class SelfUpdateController extends BaseController Artisan::call('clear-compiled'); Artisan::call('cache:clear'); - Artisan::call('debugbar:clear'); + // Artisan::call('debugbar:clear'); Artisan::call('route:clear'); Artisan::call('view:clear'); Artisan::call('config:clear'); diff --git a/app/Http/Controllers/TaskController.php b/app/Http/Controllers/TaskController.php index 54383b06ede0..28efb452caf1 100644 --- a/app/Http/Controllers/TaskController.php +++ b/app/Http/Controllers/TaskController.php @@ -279,8 +279,8 @@ class TaskController extends BaseController $task = $this->task_repo->save($request->all(), $task); - // if($task->status_order != $old_task->status_order) - // $this->task_repo->sortStatuses($old_task, $task); + if($task->status_order != $old_task->status_order) + $this->task_repo->sortStatuses($old_task, $task); event(new TaskWasUpdated($task, $task->company, Ninja::eventVars(auth()->user()->id))); diff --git a/app/Services/Subscription/SubscriptionService.php b/app/Services/Subscription/SubscriptionService.php index 7c02d9aa6347..5ec1da41ea4b 100644 --- a/app/Services/Subscription/SubscriptionService.php +++ b/app/Services/Subscription/SubscriptionService.php @@ -130,7 +130,7 @@ class SubscriptionService ]; $response = $this->triggerWebhook($context); - nlog($response); + // nlog($response); return $response; } @@ -198,15 +198,18 @@ class SubscriptionService $outstanding_amounts = $outstanding->sum('balance'); // $outstanding_invoices = $outstanding->get(); - $outstanding_invoices = $outstanding; + $outstanding_invoice = Invoice::where('subscription_id', $this->subscription->id) + ->where('is_deleted', 0) + ->orderBy('id', 'desc') + ->first(); if ($outstanding->count() == 0){ //nothing outstanding - return $target->price; + return $target->price - $this->calculateProRataRefund($outstanding_invoice); } elseif ($outstanding->count() == 1){ //user has multiple amounts outstanding - return $target->price - $this->calculateProRataRefund($outstanding->first()); + return $target->price - $this->calculateProRataRefund($outstanding_invoice); } elseif ($outstanding->count() > 1) { //user is changing plan mid frequency cycle @@ -237,6 +240,9 @@ class SubscriptionService $pro_rata_refund = round((($days_in_frequency - $days_to_refund)/$days_in_frequency) * $invoice->amount ,2); + nlog("days_to_refund = {$days_to_refund} days in frequency {$days_in_frequency} invoice amount = {$invoice->amount}"); + nlog("pro rata refund = {$pro_rata_refund}"); + return $pro_rata_refund; } @@ -253,13 +259,17 @@ class SubscriptionService $current_date = now(); - $days_to_refund = $start_date->diffInDays($current_date); + $days_to_charge = $start_date->diffInDays($current_date); $days_in_frequency = $this->getDaysInFrequency(); - $pro_rata_refund = round(($days_to_refund/$days_in_frequency) * $invoice->amount ,2); +nlog("days to charge = {$days_to_charge} fays in frequency = {$days_in_frequency}"); + + $pro_rata_charge = round(($days_to_charge/$days_in_frequency) * $invoice->amount ,2); - return $pro_rata_refund; + nlog("pro rata charge = {$pro_rata_charge}"); + + return $pro_rata_charge; } public function createChangePlanInvoice($data) @@ -549,29 +559,29 @@ class SubscriptionService { switch ($this->subscription->frequency_id) { - case self::FREQUENCY_DAILY: + case RecurringInvoice::FREQUENCY_DAILY: return 1; - case self::FREQUENCY_WEEKLY: + case RecurringInvoice::FREQUENCY_WEEKLY: return 7; - case self::FREQUENCY_TWO_WEEKS: + case RecurringInvoice::FREQUENCY_TWO_WEEKS: return 14; - case self::FREQUENCY_FOUR_WEEKS: + case RecurringInvoice::FREQUENCY_FOUR_WEEKS: return now()->diffInDays(now()->addWeeks(4)); - case self::FREQUENCY_MONTHLY: + case RecurringInvoice::FREQUENCY_MONTHLY: return now()->diffInDays(now()->addMonthNoOverflow()); - case self::FREQUENCY_TWO_MONTHS: + case RecurringInvoice::FREQUENCY_TWO_MONTHS: return now()->diffInDays(now()->addMonthNoOverflow(2)); - case self::FREQUENCY_THREE_MONTHS: + case RecurringInvoice::FREQUENCY_THREE_MONTHS: return now()->diffInDays(now()->addMonthNoOverflow(3)); - case self::FREQUENCY_FOUR_MONTHS: + case RecurringInvoice::FREQUENCY_FOUR_MONTHS: return now()->diffInDays(now()->addMonthNoOverflow(4)); - case self::FREQUENCY_SIX_MONTHS: + case RecurringInvoice::FREQUENCY_SIX_MONTHS: return now()->diffInDays(now()->addMonthNoOverflow(6)); - case self::FREQUENCY_ANNUALLY: + case RecurringInvoice::FREQUENCY_ANNUALLY: return now()->diffInDays(now()->addYear()); - case self::FREQUENCY_TWO_YEARS: + case RecurringInvoice::FREQUENCY_TWO_YEARS: return now()->diffInDays(now()->addYears(2)); - case self::FREQUENCY_THREE_YEARS: + case RecurringInvoice::FREQUENCY_THREE_YEARS: return now()->diffInDays(now()->addYears(3)); default: return 0; From 4cd83ba27a32eacc41394e9bdf23f37d740ae1f4 Mon Sep 17 00:00:00 2001 From: = Date: Wed, 14 Apr 2021 21:26:45 +1000 Subject: [PATCH 04/11] Working on subscriptions --- .../Subscription/SubscriptionService.php | 71 ++++++++----------- 1 file changed, 29 insertions(+), 42 deletions(-) diff --git a/app/Services/Subscription/SubscriptionService.php b/app/Services/Subscription/SubscriptionService.php index 5ec1da41ea4b..e566bc6fd96f 100644 --- a/app/Services/Subscription/SubscriptionService.php +++ b/app/Services/Subscription/SubscriptionService.php @@ -199,6 +199,7 @@ class SubscriptionService $outstanding_amounts = $outstanding->sum('balance'); // $outstanding_invoices = $outstanding->get(); $outstanding_invoice = Invoice::where('subscription_id', $this->subscription->id) + ->where('client_id', $recurring_invoice->client_id) ->where('is_deleted', 0) ->orderBy('id', 'desc') ->first(); @@ -234,16 +235,19 @@ class SubscriptionService $current_date = now(); - $days_to_refund = $start_date->diffInDays($current_date); + $days_of_subscription_used = $start_date->diffInDays($current_date); $days_in_frequency = $this->getDaysInFrequency(); - $pro_rata_refund = round((($days_in_frequency - $days_to_refund)/$days_in_frequency) * $invoice->amount ,2); + $pro_rata_refund = round((($days_in_frequency - $days_of_subscription_used)/$days_in_frequency) * $invoice->amount ,2); - nlog("days_to_refund = {$days_to_refund} days in frequency {$days_in_frequency} invoice amount = {$invoice->amount}"); + nlog("{$days_in_frequency} - {$days_of_subscription_used} / {$days_in_frequency}"); + + nlog("days_to_refund = {$days_of_subscription_used} days in frequency {$days_in_frequency} invoice amount = {$invoice->amount}"); nlog("pro rata refund = {$pro_rata_refund}"); return $pro_rata_refund; + } /** @@ -275,67 +279,42 @@ nlog("days to charge = {$days_to_charge} fays in frequency = {$days_in_frequency public function createChangePlanInvoice($data) { $recurring_invoice = $data['recurring_invoice']; - //Data array structure - /** - * [ - * 'recurring_invoice' => RecurringInvoice::class, - * 'subscription' => Subscription::class, - * 'target' => Subscription::class - * ] - */ - - // $outstanding_invoice = $recurring_invoice->invoices() - // ->where('is_deleted', 0) - // ->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL]) - // ->where('balance', '>', 0) - // ->first(); $pro_rata_charge_amount = 0; $pro_rata_refund_amount = 0; - // // We calculate the pro rata charge for this invoice. - // if($outstanding_invoice) - // { - // } - - $last_invoice = $recurring_invoice->invoices() + $last_invoice = Invoice::where('subscription_id', $this->subscription->id) + ->where('client_id', $recurring_invoice->client_id) ->where('is_deleted', 0) ->orderBy('id', 'desc') ->first(); - //$last_invoice may not be here! - - if(!$last_invoice) { - $data = [ - 'client_id' => $recurring_invoice->client_id, - 'coupon' => '', - ]; - - return $this->createInvoice($data)->service()->markSent()->fillDefaults()->save(); - - } - else if($last_invoice->balance > 0) + if($last_invoice->balance > 0) { $pro_rata_charge_amount = $this->calculateProRataCharge($last_invoice); + nlog("pro rata charge = {$pro_rata_charge_amount}"); } else { $pro_rata_refund_amount = $this->calculateProRataRefund($last_invoice) * -1; + nlog("pro rata refund = {$pro_rata_refund_amount}"); } $total_payable = $pro_rata_refund_amount + $pro_rata_charge_amount + $this->subscription->price; + nlog("total payable = {$total_payable}"); + if($total_payable > 0) { - return $this->proRataInvoice($pro_rata_refund_amount, $data['subscription'], $data['target']); + return $this->proRataInvoice($pro_rata_refund_amount, $last_invoice, $data['target']); } else { //create credit } - - return Invoice::where('status_id', Invoice::STATUS_SENT)->first(); +dd("no"); + // return Invoice::where('status_id', Invoice::STATUS_SENT)->first(); } /** @@ -398,27 +377,35 @@ nlog("days to charge = {$days_to_charge} fays in frequency = {$days_in_frequency 'coupon' => '', 'quantity' => 1, */ - private function proRataInvoice($refund_amount, $subscription, $target) + private function proRataInvoice($refund_amount, $last_invoice, $target) { $subscription_repo = new SubscriptionRepository(); $invoice_repo = new InvoiceRepository(); + $invoice = InvoiceFactory::create($this->subscription->company_id, $this->subscription->user_id); + $invoice->date = now()->format('Y-m-d'); + $invoice->subscription_id = $this->subscription->id; + $line_items = $subscription_repo->generateLineItems($target); $item = new InvoiceItem; $item->quantity = 1; $item->product_key = ctrans('texts.refund'); - $item->notes = ctrans('texts.refund') . ":" .$subscription->name; + $item->notes = ctrans('texts.refund') . ":" .$this->subscription->name; $item->cost = $refund_amount; $line_items[] = $item; - + $invoice->line_items = $line_items; + $data = [ - 'client_id' => $subscription->client_id, + 'client_id' => $last_invoice->client_id, 'quantity' => 1, 'date' => now()->format('Y-m-d'), ]; + // $invoice = $invoice_repo->save($data, $invoice); + // dd($invoice); + return $invoice_repo->save($data, $invoice)->service()->markSent()->fillDefaults()->save(); } From 218aa6de733289e667ca3a590970067152eb6ee7 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Thu, 15 Apr 2021 08:09:36 +1000 Subject: [PATCH 05/11] Checks for partial/deposit greater than amount/balance --- app/Http/Requests/Invoice/StoreInvoiceRequest.php | 2 +- app/Repositories/BaseRepository.php | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/app/Http/Requests/Invoice/StoreInvoiceRequest.php b/app/Http/Requests/Invoice/StoreInvoiceRequest.php index 2da8e72603a6..9090badcb699 100644 --- a/app/Http/Requests/Invoice/StoreInvoiceRequest.php +++ b/app/Http/Requests/Invoice/StoreInvoiceRequest.php @@ -51,7 +51,7 @@ class StoreInvoiceRequest extends Request $rules['invitations.*.client_contact_id'] = 'distinct'; - $rules['number'] = ['nullable',Rule::unique('invoices')->where('company_id', auth()->user()->company()->id)]; + $rules['number'] = ['nullable', Rule::unique('invoices')->where('company_id', auth()->user()->company()->id)]; $rules['project_id'] = ['bail', 'sometimes', new ValidProjectForClient($this->all())]; diff --git a/app/Repositories/BaseRepository.php b/app/Repositories/BaseRepository.php index ddf2645d9051..9942698ef7f6 100644 --- a/app/Repositories/BaseRepository.php +++ b/app/Repositories/BaseRepository.php @@ -291,6 +291,10 @@ class BaseRepository /* Apply entity number */ $model = $model->service()->applyNumber()->save(); + /* Handle attempts where the deposit is greater than the amount/balance of the invoice */ + if((int)$model->balance != 0 && $model->partial > $model->amount) + $model->partial = min($model->amount, $model->balance); + /* Update product details if necessary */ if ($model->company->update_products) UpdateOrCreateProduct::dispatch($model->line_items, $model, $model->company); From bc56112d10bd2c14c210266e9a631c4e8030365f Mon Sep 17 00:00:00 2001 From: David Bomba Date: Thu, 15 Apr 2021 11:03:12 +1000 Subject: [PATCH 06/11] Subscriptions upgrade and downgrade --- .../Subscription/SubscriptionService.php | 71 ++++++++++++++----- 1 file changed, 52 insertions(+), 19 deletions(-) diff --git a/app/Services/Subscription/SubscriptionService.php b/app/Services/Subscription/SubscriptionService.php index e566bc6fd96f..991b0572330d 100644 --- a/app/Services/Subscription/SubscriptionService.php +++ b/app/Services/Subscription/SubscriptionService.php @@ -240,16 +240,49 @@ class SubscriptionService $days_in_frequency = $this->getDaysInFrequency(); $pro_rata_refund = round((($days_in_frequency - $days_of_subscription_used)/$days_in_frequency) * $invoice->amount ,2); - - nlog("{$days_in_frequency} - {$days_of_subscription_used} / {$days_in_frequency}"); - - nlog("days_to_refund = {$days_of_subscription_used} days in frequency {$days_in_frequency} invoice amount = {$invoice->amount}"); - nlog("pro rata refund = {$pro_rata_refund}"); return $pro_rata_refund; } + private function calculateProRataRefundItems($invoice) :array + { + + $start_date = Carbon::parse($invoice->date); + + $current_date = now(); + + $days_of_subscription_used = $start_date->diffInDays($current_date); + + $days_in_frequency = $this->getDaysInFrequency(); + + //$pro_rata_refund = round(((c * $invoice->amount ,2); + + $ratio = ($days_in_frequency - $days_of_subscription_used)/$days_in_frequency; + + $line_items = []; + + foreach($invoice->line_items as $item) + { + + if($item->product_key != ctrans('texts.refund')) + { + + $item->cost = ($item->cost*$ratio*-1); + $item->product_key = ctrans('texts.refund'); + $item->notes = ctrans('texts.refund') . ": ". $item->notes; + + + $line_items[] = $item; + + } + } + + return $line_items; + + } + + /** * We only charge for the used days * @@ -279,24 +312,26 @@ nlog("days to charge = {$days_to_charge} fays in frequency = {$days_in_frequency public function createChangePlanInvoice($data) { $recurring_invoice = $data['recurring_invoice']; + $old_subscription = $data['subscription']; $pro_rata_charge_amount = 0; $pro_rata_refund_amount = 0; - $last_invoice = Invoice::where('subscription_id', $this->subscription->id) + $last_invoice = Invoice::where('subscription_id', $recurring_invoice->subscription_id) ->where('client_id', $recurring_invoice->client_id) ->where('is_deleted', 0) + ->withTrashed() ->orderBy('id', 'desc') ->first(); - +// dd($); if($last_invoice->balance > 0) { - $pro_rata_charge_amount = $this->calculateProRataCharge($last_invoice); + $pro_rata_charge_amount = $this->calculateProRataCharge($last_invoice, $old_subscription); nlog("pro rata charge = {$pro_rata_charge_amount}"); } else { - $pro_rata_refund_amount = $this->calculateProRataRefund($last_invoice) * -1; + $pro_rata_refund_amount = $this->calculateProRataRefund($last_invoice, $old_subscription) * -1; nlog("pro rata refund = {$pro_rata_refund_amount}"); } @@ -306,14 +341,13 @@ nlog("days to charge = {$days_to_charge} fays in frequency = {$days_in_frequency if($total_payable > 0) { - return $this->proRataInvoice($pro_rata_refund_amount, $last_invoice, $data['target']); + return $this->proRataInvoice($pro_rata_refund_amount, $last_invoice, $data['target'], $old_subscription); } else { //create credit } -dd("no"); // return Invoice::where('status_id', Invoice::STATUS_SENT)->first(); } @@ -377,7 +411,7 @@ dd("no"); 'coupon' => '', 'quantity' => 1, */ - private function proRataInvoice($refund_amount, $last_invoice, $target) + private function proRataInvoice($refund_amount, $last_invoice, $target, $old_subscription) { $subscription_repo = new SubscriptionRepository(); $invoice_repo = new InvoiceRepository(); @@ -388,14 +422,13 @@ dd("no"); $line_items = $subscription_repo->generateLineItems($target); - $item = new InvoiceItem; - $item->quantity = 1; - $item->product_key = ctrans('texts.refund'); - $item->notes = ctrans('texts.refund') . ":" .$this->subscription->name; - $item->cost = $refund_amount; + // $item = new InvoiceItem; + // $item->quantity = 1; + // $item->product_key = ctrans('texts.refund'); + // $item->notes = ctrans('texts.refund') . ": " .$$old_subscription->name; + // $item->cost = $refund_amount; - $line_items[] = $item; - $invoice->line_items = $line_items; + $invoice->line_items = array_merge($line_items, $this->calculateProRataRefundItems($last_invoice)); $data = [ 'client_id' => $last_invoice->client_id, From bb6a1c6b2734cc41460a2d5c53ab2dd1f5502994 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Thu, 15 Apr 2021 12:28:31 +1000 Subject: [PATCH 07/11] Working on downgrading subscriptions --- app/Http/Livewire/SubscriptionPlanSwitch.php | 31 ++++-- .../Subscription/SubscriptionService.php | 95 ++++++++++++++----- .../subscription-plan-switch.blade.php | 9 +- 3 files changed, 104 insertions(+), 31 deletions(-) diff --git a/app/Http/Livewire/SubscriptionPlanSwitch.php b/app/Http/Livewire/SubscriptionPlanSwitch.php index ba77c857f6a4..53d5b489b015 100644 --- a/app/Http/Livewire/SubscriptionPlanSwitch.php +++ b/app/Http/Livewire/SubscriptionPlanSwitch.php @@ -85,12 +85,26 @@ class SubscriptionPlanSwitch extends Component $this->state['show_loading_bar'] = true; - $this->state['invoice'] = $this->target->service()->createChangePlanInvoice([ - 'recurring_invoice' => $this->recurring_invoice, - 'subscription' => $this->subscription, - 'target' => $this->target, - 'hash' => $this->hash, - ]); + $change_cost = $this->target->service()->calculateUpgradePrice($this->recurring_invoice, $this->target); + + if($change_cost > 0) + { + $this->state['invoice'] = $this->target->service()->createChangePlanInvoice([ + 'recurring_invoice' => $this->recurring_invoice, + 'subscription' => $this->subscription, + 'target' => $this->target, + 'hash' => $this->hash, + ]); + } + else + { + $this->state['credit'] = $this->target->service()->createChangePlanCredit([ + 'recurring_invoice' => $this->recurring_invoice, + 'subscription' => $this->subscription, + 'target' => $this->target, + 'hash' => $this->hash, + ]); + } Cache::put($this->hash, [ 'subscription_id' => $this->target->id, @@ -122,6 +136,11 @@ class SubscriptionPlanSwitch extends Component $this->handleBeforePaymentEvents(); } + public function handlePaymentNotRequired() + { + + } + public function render() { return render('components.livewire.subscription-plan-switch'); diff --git a/app/Services/Subscription/SubscriptionService.php b/app/Services/Subscription/SubscriptionService.php index 991b0572330d..1f366f913765 100644 --- a/app/Services/Subscription/SubscriptionService.php +++ b/app/Services/Subscription/SubscriptionService.php @@ -12,6 +12,7 @@ namespace App\Services\Subscription; use App\DataMapper\InvoiceItem; +use App\Factory\CreditFactory; use App\Factory\InvoiceFactory; use App\Factory\InvoiceToRecurringInvoiceFactory; use App\Factory\RecurringInvoiceFactory; @@ -26,6 +27,7 @@ use App\Models\Product; use App\Models\RecurringInvoice; use App\Models\Subscription; use App\Models\SystemLog; +use App\Repositories\CreditRepository; use App\Repositories\InvoiceRepository; use App\Repositories\RecurringInvoiceRepository; use App\Repositories\SubscriptionRepository; @@ -177,11 +179,7 @@ class SubscriptionService //execute any webhooks $response = $this->triggerWebhook($context); - if(array_key_exists('return_url', $this->subscription->webhook_configuration) && strlen($this->subscription->webhook_configuration['return_url']) >=1){ - return redirect($this->subscription->webhook_configuration['return_url']); - } - - return redirect('/client/recurring_invoices/'.$recurring_invoice->hashed_id); + return $this->handleRedirect('/client/recurring_invoices/'.$recurring_invoice->hashed_id); } public function calculateUpgradePrice(RecurringInvoice $recurring_invoice, Subscription $target) :?float @@ -245,6 +243,13 @@ class SubscriptionService } + /** + * Returns refundable set of line items + * transformed for direct injection into + * the invoice + * @param Invoice $invoice + * @return array + */ private function calculateProRataRefundItems($invoice) :array { @@ -256,8 +261,6 @@ class SubscriptionService $days_in_frequency = $this->getDaysInFrequency(); - //$pro_rata_refund = round(((c * $invoice->amount ,2); - $ratio = ($days_in_frequency - $days_of_subscription_used)/$days_in_frequency; $line_items = []; @@ -300,7 +303,7 @@ class SubscriptionService $days_in_frequency = $this->getDaysInFrequency(); -nlog("days to charge = {$days_to_charge} fays in frequency = {$days_in_frequency}"); + nlog("days to charge = {$days_to_charge} fays in frequency = {$days_in_frequency}"); $pro_rata_charge = round(($days_to_charge/$days_in_frequency) * $invoice->amount ,2); @@ -309,11 +312,12 @@ nlog("days to charge = {$days_to_charge} fays in frequency = {$days_in_frequency return $pro_rata_charge; } - public function createChangePlanInvoice($data) + public function createChangePlanCredit($data) { $recurring_invoice = $data['recurring_invoice']; $old_subscription = $data['subscription']; - + $target_subscription = $data['target']; + $pro_rata_charge_amount = 0; $pro_rata_refund_amount = 0; @@ -323,7 +327,7 @@ nlog("days to charge = {$days_to_charge} fays in frequency = {$days_in_frequency ->withTrashed() ->orderBy('id', 'desc') ->first(); -// dd($); + if($last_invoice->balance > 0) { $pro_rata_charge_amount = $this->calculateProRataCharge($last_invoice, $old_subscription); @@ -339,16 +343,45 @@ nlog("days to charge = {$days_to_charge} fays in frequency = {$days_in_frequency nlog("total payable = {$total_payable}"); - if($total_payable > 0) + return $this->createCredit($pro_rata_refund_amount, $last_invoice, $target_subscription, $old_subscription); + + + } + + public function createChangePlanInvoice($data) + { + $recurring_invoice = $data['recurring_invoice']; + $old_subscription = $data['subscription']; + $target_subscription = $data['target']; + + $pro_rata_charge_amount = 0; + $pro_rata_refund_amount = 0; + + $last_invoice = Invoice::where('subscription_id', $recurring_invoice->subscription_id) + ->where('client_id', $recurring_invoice->client_id) + ->where('is_deleted', 0) + ->withTrashed() + ->orderBy('id', 'desc') + ->first(); + + if($last_invoice->balance > 0) { - return $this->proRataInvoice($pro_rata_refund_amount, $last_invoice, $data['target'], $old_subscription); + $pro_rata_charge_amount = $this->calculateProRataCharge($last_invoice, $old_subscription); + nlog("pro rata charge = {$pro_rata_charge_amount}"); } else { - //create credit + $pro_rata_refund_amount = $this->calculateProRataRefund($last_invoice, $old_subscription) * -1; + nlog("pro rata refund = {$pro_rata_refund_amount}"); } - // return Invoice::where('status_id', Invoice::STATUS_SENT)->first(); + $total_payable = $pro_rata_refund_amount + $pro_rata_charge_amount + $this->subscription->price; + + nlog("total payable = {$total_payable}"); + + + return $this->proRataInvoice($pro_rata_refund_amount, $last_invoice, $target_subscription, $old_subscription); + } /** @@ -403,6 +436,29 @@ nlog("days to charge = {$days_to_charge} fays in frequency = {$days_in_frequency } + private function createCredit($refund_amount, $last_invoice, $target, $old_subscription) + { + + $subscription_repo = new SubscriptionRepository(); + $credit_repo = new CreditRepository(); + + $credit = CreditFactory::create($this->subscription->company_id, $this->subscription->user_id); + $credit->date = now()->format('Y-m-d'); + $credit->subscription_id = $this->subscription->id; + + $line_items = $subscription_repo->generateLineItems($target); + + $credit->line_items = array_merge($line_items, $this->calculateProRataRefundItems($last_invoice)); + + $data = [ + 'client_id' => $last_invoice->client_id, + 'quantity' => 1, + 'date' => now()->format('Y-m-d'), + ]; + + return $credit_repo->save($data, $credit)->service()->markSent()->fillDefaults()->save(); + + } /** * 'client_id' => 2, 'date' => '2021-04-13', @@ -422,12 +478,6 @@ nlog("days to charge = {$days_to_charge} fays in frequency = {$days_in_frequency $line_items = $subscription_repo->generateLineItems($target); - // $item = new InvoiceItem; - // $item->quantity = 1; - // $item->product_key = ctrans('texts.refund'); - // $item->notes = ctrans('texts.refund') . ": " .$$old_subscription->name; - // $item->cost = $refund_amount; - $invoice->line_items = array_merge($line_items, $this->calculateProRataRefundItems($last_invoice)); $data = [ @@ -436,9 +486,6 @@ nlog("days to charge = {$days_to_charge} fays in frequency = {$days_in_frequency 'date' => now()->format('Y-m-d'), ]; - // $invoice = $invoice_repo->save($data, $invoice); - // dd($invoice); - return $invoice_repo->save($data, $invoice)->service()->markSent()->fillDefaults()->save(); } diff --git a/resources/views/portal/ninja2020/components/livewire/subscription-plan-switch.blade.php b/resources/views/portal/ninja2020/components/livewire/subscription-plan-switch.blade.php index ff43981e9128..01730dcf3956 100644 --- a/resources/views/portal/ninja2020/components/livewire/subscription-plan-switch.blade.php +++ b/resources/views/portal/ninja2020/components/livewire/subscription-plan-switch.blade.php @@ -32,7 +32,14 @@ - @endif + @elseif($state['credit']) +
+ @csrf + +
+ @endif
From 7c8bf53951ee1966c533acba6a7383dfb0ad305f Mon Sep 17 00:00:00 2001 From: David Bomba Date: Thu, 15 Apr 2021 13:40:03 +1000 Subject: [PATCH 08/11] updgrade and downgrade --- app/Http/Livewire/SubscriptionPlanSwitch.php | 21 ++--- .../Subscription/SubscriptionService.php | 87 ++++++++++++++++--- .../subscription-plan-switch.blade.php | 17 ++-- 3 files changed, 92 insertions(+), 33 deletions(-) diff --git a/app/Http/Livewire/SubscriptionPlanSwitch.php b/app/Http/Livewire/SubscriptionPlanSwitch.php index 53d5b489b015..9ad9f35dc672 100644 --- a/app/Http/Livewire/SubscriptionPlanSwitch.php +++ b/app/Http/Livewire/SubscriptionPlanSwitch.php @@ -85,26 +85,12 @@ class SubscriptionPlanSwitch extends Component $this->state['show_loading_bar'] = true; - $change_cost = $this->target->service()->calculateUpgradePrice($this->recurring_invoice, $this->target); - - if($change_cost > 0) - { $this->state['invoice'] = $this->target->service()->createChangePlanInvoice([ 'recurring_invoice' => $this->recurring_invoice, 'subscription' => $this->subscription, 'target' => $this->target, 'hash' => $this->hash, ]); - } - else - { - $this->state['credit'] = $this->target->service()->createChangePlanCredit([ - 'recurring_invoice' => $this->recurring_invoice, - 'subscription' => $this->subscription, - 'target' => $this->target, - 'hash' => $this->hash, - ]); - } Cache::put($this->hash, [ 'subscription_id' => $this->target->id, @@ -139,6 +125,13 @@ class SubscriptionPlanSwitch extends Component public function handlePaymentNotRequired() { + return $this->target->service()->createChangePlanCredit([ + 'recurring_invoice' => $this->recurring_invoice, + 'subscription' => $this->subscription, + 'target' => $this->target, + 'hash' => $this->hash, + ]); + } public function render() diff --git a/app/Services/Subscription/SubscriptionService.php b/app/Services/Subscription/SubscriptionService.php index 1f366f913765..f26bdf42f736 100644 --- a/app/Services/Subscription/SubscriptionService.php +++ b/app/Services/Subscription/SubscriptionService.php @@ -250,9 +250,11 @@ class SubscriptionService * @param Invoice $invoice * @return array */ - private function calculateProRataRefundItems($invoice) :array + private function calculateProRataRefundItems($invoice, $is_credit = false) :array { - + /* depending on whether we are creating an invoice or a credit*/ + $multiplier = $is_credit ? 1 : -1; + $start_date = Carbon::parse($invoice->date); $current_date = now(); @@ -271,7 +273,7 @@ class SubscriptionService if($item->product_key != ctrans('texts.refund')) { - $item->cost = ($item->cost*$ratio*-1); + $item->cost = ($item->cost*$ratio*$multiplier); $item->product_key = ctrans('texts.refund'); $item->notes = ctrans('texts.refund') . ": ". $item->notes; @@ -343,8 +345,40 @@ class SubscriptionService nlog("total payable = {$total_payable}"); - return $this->createCredit($pro_rata_refund_amount, $last_invoice, $target_subscription, $old_subscription); + $credit = $this->createCredit($pro_rata_refund_amount, $last_invoice, $target_subscription, $old_subscription); +/////////////////////////// + $old_subscription_recurring_invoice = $recurring_invoice; + $old_subscription_recurring_invoice->service()->stop()->save(); + + $recurring_invoice_repo = new RecurringInvoiceRepository(); + $recurring_invoice_repo->archive($old_subscription_recurring_invoice); + + $recurring_invoice = $this->convertInvoiceToRecurring($recurring_invoice->client_id); + $recurring_invoice = $recurring_invoice_repo->save([], $recurring_invoice); + $recurring_invoice->next_send_date = now(); + $recurring_invoice->next_send_date = $recurring_invoice->nextSendDate(); + + /* Start the recurring service */ + $recurring_invoice->service() + ->start() + ->save(); +//////////////////////////// + + $context = [ + 'context' => 'change_plan', + 'recurring_invoice' => $recurring_invoice->hashed_id, + 'credit' => $credit->hashed_id, + 'client' => $recurring_invoice->client->hashed_id, + 'subscription' => $target_subscription->hashed_id, + 'contact' => auth('contact')->user()->hashed_id, + ]; + + $response = $this->triggerWebhook($context); + + nlog($response); + + return $this->handleRedirect('/client/credits/'.$credit->hashed_id); } @@ -424,16 +458,49 @@ class SubscriptionService nlog($response); - if(array_key_exists('post_purchase_url', $this->subscription->webhook_configuration) && strlen($this->subscription->webhook_configuration['post_purchase_url']) >=1) - return redirect($this->subscription->webhook_configuration['post_purchase_url']); - - return redirect('/client/recurring_invoices/'.$recurring_invoice->hashed_id); + return $this->handleRedirect('/client/recurring_invoices/'.$recurring_invoice->hashed_id); } - public function handlePlanChangeNoPayment() + public function handlePlanChangeNoPayment($data) { + /* + 'recurring_invoice' => $this->recurring_invoice, + 'subscription' => $this->subscription, + 'target' => $this->target, + 'hash' => $this->hash, + */ + + $old_subscription_recurring_invoice = $data['recurring_invoice']; + $old_subscription_recurring_invoice->service()->stop()->save(); + $recurring_invoice_repo = new RecurringInvoiceRepository(); + $recurring_invoice_repo->archive($old_subscription_recurring_invoice); + + $recurring_invoice = $this->convertInvoiceToRecurring($old_subscription_recurring_invoice->client_id); + $recurring_invoice = $recurring_invoice_repo->save([], $recurring_invoice); + $recurring_invoice->next_send_date = now(); + $recurring_invoice->next_send_date = $recurring_invoice->nextSendDate(); + + /* Start the recurring service */ + $recurring_invoice->service() + ->start() + ->save(); + + $context = [ + 'context' => 'change_plan', + 'recurring_invoice' => $recurring_invoice->hashed_id, + 'invoice' => $this->encodePrimaryKey($payment_hash->fee_invoice_id), + 'client' => $recurring_invoice->client->hashed_id, + 'subscription' => $this->subscription->hashed_id, + 'contact' => auth('contact')->user()->hashed_id, + ]; + + $response = $this->triggerWebhook($context); + + nlog($response); + + return $this->handleRedirect('/client/recurring_invoices/'.$recurring_invoice->hashed_id); } private function createCredit($refund_amount, $last_invoice, $target, $old_subscription) @@ -448,7 +515,7 @@ class SubscriptionService $line_items = $subscription_repo->generateLineItems($target); - $credit->line_items = array_merge($line_items, $this->calculateProRataRefundItems($last_invoice)); + $credit->line_items = array_merge($line_items, $this->calculateProRataRefundItems($last_invoice, true)); $data = [ 'client_id' => $last_invoice->client_id, diff --git a/resources/views/portal/ninja2020/components/livewire/subscription-plan-switch.blade.php b/resources/views/portal/ninja2020/components/livewire/subscription-plan-switch.blade.php index 01730dcf3956..47cf8f129928 100644 --- a/resources/views/portal/ninja2020/components/livewire/subscription-plan-switch.blade.php +++ b/resources/views/portal/ninja2020/components/livewire/subscription-plan-switch.blade.php @@ -1,6 +1,9 @@
+ + @if(isset($state['invoice'])) +
@@ -15,7 +18,6 @@
- @if($state['invoice'])
@csrf @@ -32,14 +34,6 @@
- @elseif($state['credit']) -
- @csrf - -
- @endif
@@ -68,5 +62,10 @@ @endif
+ @elseif($amount < 0) + + @endif
From 0b1569d6d98460fd4b11d1a0c70aeea95059edef Mon Sep 17 00:00:00 2001 From: David Bomba Date: Thu, 15 Apr 2021 15:36:50 +1000 Subject: [PATCH 09/11] refund subscriptions in cancellation window --- app/Http/Controllers/PaymentController.php | 2 + .../Livewire/RecurringInvoiceCancellation.php | 2 +- .../Subscription/SubscriptionService.php | 137 +++++++++++------- 3 files changed, 85 insertions(+), 56 deletions(-) diff --git a/app/Http/Controllers/PaymentController.php b/app/Http/Controllers/PaymentController.php index 480a0816ee43..82224dd1a383 100644 --- a/app/Http/Controllers/PaymentController.php +++ b/app/Http/Controllers/PaymentController.php @@ -671,6 +671,8 @@ class PaymentController extends BaseController { $payment = $request->payment(); +// nlog($request->all()); + $payment = $payment->refund($request->all()); return $this->itemResponse($payment); diff --git a/app/Http/Livewire/RecurringInvoiceCancellation.php b/app/Http/Livewire/RecurringInvoiceCancellation.php index 4e03e3b09745..d3904c874330 100644 --- a/app/Http/Livewire/RecurringInvoiceCancellation.php +++ b/app/Http/Livewire/RecurringInvoiceCancellation.php @@ -25,7 +25,7 @@ class RecurringInvoiceCancellation extends Component public function processCancellation() { if ($this->invoice->subscription) { - return $this->invoice->subscription->service()->handleCancellation(); + return $this->invoice->subscription->service()->handleCancellation($this->invoice); } return redirect()->route('client.recurring_invoices.request_cancellation', ['recurring_invoice' => $this->invoice->hashed_id]); diff --git a/app/Services/Subscription/SubscriptionService.php b/app/Services/Subscription/SubscriptionService.php index f26bdf42f736..ccabe124506f 100644 --- a/app/Services/Subscription/SubscriptionService.php +++ b/app/Services/Subscription/SubscriptionService.php @@ -347,29 +347,13 @@ class SubscriptionService $credit = $this->createCredit($pro_rata_refund_amount, $last_invoice, $target_subscription, $old_subscription); -/////////////////////////// - $old_subscription_recurring_invoice = $recurring_invoice; - $old_subscription_recurring_invoice->service()->stop()->save(); - - $recurring_invoice_repo = new RecurringInvoiceRepository(); - $recurring_invoice_repo->archive($old_subscription_recurring_invoice); - - $recurring_invoice = $this->convertInvoiceToRecurring($recurring_invoice->client_id); - $recurring_invoice = $recurring_invoice_repo->save([], $recurring_invoice); - $recurring_invoice->next_send_date = now(); - $recurring_invoice->next_send_date = $recurring_invoice->nextSendDate(); - - /* Start the recurring service */ - $recurring_invoice->service() - ->start() - ->save(); -//////////////////////////// + $new_recurring_invoice = $this->createNewRecurringInvoice($recurring_invoice); $context = [ 'context' => 'change_plan', - 'recurring_invoice' => $recurring_invoice->hashed_id, + 'recurring_invoice' => $new_recurring_invoice->hashed_id, 'credit' => $credit->hashed_id, - 'client' => $recurring_invoice->client->hashed_id, + 'client' => $new_recurring_invoice->client->hashed_id, 'subscription' => $target_subscription->hashed_id, 'contact' => auth('contact')->user()->hashed_id, ]; @@ -424,26 +408,10 @@ class SubscriptionService */ private function handlePlanChange($payment_hash) { - - //payment has been made. - // - //new subscription starts today - delete old recurring invoice. - $old_subscription_recurring_invoice = RecurringInvoice::find($payment_hash->data->billing_context->recurring_invoice); - $old_subscription_recurring_invoice->service()->stop()->save(); + $old_recurring_invoice = RecurringInvoice::find($payment_hash->data->billing_context->recurring_invoice); - $recurring_invoice_repo = new RecurringInvoiceRepository(); - $recurring_invoice_repo->archive($old_subscription_recurring_invoice); - - $recurring_invoice = $this->convertInvoiceToRecurring($payment_hash->payment->client_id); - $recurring_invoice = $recurring_invoice_repo->save([], $recurring_invoice); - $recurring_invoice->next_send_date = now(); - $recurring_invoice->next_send_date = $recurring_invoice->nextSendDate(); - - /* Start the recurring service */ - $recurring_invoice->service() - ->start() - ->save(); + $recurring_invoice = $this->createNewRecurringInvoice($old_recurring_invoice); $context = [ 'context' => 'change_plan', @@ -462,6 +430,28 @@ class SubscriptionService } + private function createNewRecurringInvoice($old_recurring_invoice) :RecurringInvoice + { + + $old_recurring_invoice->service()->stop()->save(); + + $recurring_invoice_repo = new RecurringInvoiceRepository(); + $recurring_invoice_repo->archive($$old_recurring_invoice); + + $recurring_invoice = $this->convertInvoiceToRecurring($old_recurring_invoice->client_id); + $recurring_invoice = $recurring_invoice_repo->save([], $recurring_invoice); + $recurring_invoice->next_send_date = now(); + $recurring_invoice->next_send_date = $recurring_invoice->nextSendDate(); + + /* Start the recurring service */ + $recurring_invoice->service() + ->start() + ->save(); + + return $recurring_invoice; + + } + public function handlePlanChangeNoPayment($data) { /* @@ -471,21 +461,7 @@ class SubscriptionService 'hash' => $this->hash, */ - $old_subscription_recurring_invoice = $data['recurring_invoice']; - $old_subscription_recurring_invoice->service()->stop()->save(); - - $recurring_invoice_repo = new RecurringInvoiceRepository(); - $recurring_invoice_repo->archive($old_subscription_recurring_invoice); - - $recurring_invoice = $this->convertInvoiceToRecurring($old_subscription_recurring_invoice->client_id); - $recurring_invoice = $recurring_invoice_repo->save([], $recurring_invoice); - $recurring_invoice->next_send_date = now(); - $recurring_invoice->next_send_date = $recurring_invoice->nextSendDate(); - - /* Start the recurring service */ - $recurring_invoice->service() - ->start() - ->save(); + $recurring_invoice = $this->createNewRecurringInvoice($data['recurring_invoice']); $context = [ 'context' => 'change_plan', @@ -682,11 +658,62 @@ class SubscriptionService ->get(); } - public function handleCancellation() + public function handleCancellation(RecurringInvoice $recurring_invoice) { - dd('Cancelling using SubscriptionService'); + //only allow cancellation of services that are paid up to date. + + // $last_invoice = + + //only refund if they are in the refund window. + $outstanding_invoice = Invoice::where('subscription_id', $this->subscription->id) + ->where('client_id', $recurring_invoice->client_id) + ->where('is_deleted', 0) + ->orderBy('id', 'desc') + ->first(); + + $invoice_start_date = Carbon::parse($outstanding_invoice->date); + $refund_end_date = $invoice_start_date->addSeconds($this->subscription->refund_period); + + /* Stop the recurring invoice and archive */ + $recurring_invoice->service()->stop()->save(); + $recurring_invoice_repo = new RecurringInvoiceRepository(); + $recurring_invoice_repo->archive($$old_recurring_invoice); + + if($refund_end_date->greaterThan(now()) && (int)$outstanding_invoice->balance == 0) + { + //we are in the refund window. + // + //$outstanding_invoice + if($outstanding_invoice->payments()->exists()) + { + $payment = $outstanding_invoice->payments()->first(); + + $data = [ + 'id' => $payment->id, + 'gateway_refund' => true, + 'send_email' => true, + 'invoices' => [ + ['invoice_id' => $outstanding_invoice->id, 'amount' => $outstanding_invoice->amount], + ], + + ]; + + $payment->refundPayment($data); + } + } + + $context = [ + 'context' => 'cancellation', + 'subscription' => $this->subscription->hashed_id, + 'recurring_invoice' => $recurring_invoice->hashed_id, + 'client' => $recurring_invoice->client->hashed_id, + 'contact' => auth('contact')->user()->hashed_id, + ]; + + $this->triggerWebhook($context); + + return $this->handleRedirect('client/subscriptions'); - // .. } private function getDaysInFrequency() From cac80568329d22901c5fb611738016c10584faaf Mon Sep 17 00:00:00 2001 From: David Bomba Date: Thu, 15 Apr 2021 15:46:50 +1000 Subject: [PATCH 10/11] Refund subscriptions --- app/Http/Livewire/BillingPortalPurchase.php | 4 ++-- app/Services/Subscription/SubscriptionService.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/Http/Livewire/BillingPortalPurchase.php b/app/Http/Livewire/BillingPortalPurchase.php index c864cc666f3d..a1614a3cc65d 100644 --- a/app/Http/Livewire/BillingPortalPurchase.php +++ b/app/Http/Livewire/BillingPortalPurchase.php @@ -330,9 +330,9 @@ class BillingPortalPurchase extends Component $is_eligible = $this->subscription->service()->isEligible($this->contact); - if (is_array($is_eligible)) { + if ($is_eligible['exception']['message'] != 'Success') { $this->steps['not_eligible'] = true; - $this->steps['not_eligible_message'] = $is_eligible['exception']; + $this->steps['not_eligible_message'] = $is_eligible['exception']['message']; $this->steps['show_loading_bar'] = false; return; diff --git a/app/Services/Subscription/SubscriptionService.php b/app/Services/Subscription/SubscriptionService.php index ccabe124506f..a75e9d0f0c75 100644 --- a/app/Services/Subscription/SubscriptionService.php +++ b/app/Services/Subscription/SubscriptionService.php @@ -677,7 +677,7 @@ class SubscriptionService /* Stop the recurring invoice and archive */ $recurring_invoice->service()->stop()->save(); $recurring_invoice_repo = new RecurringInvoiceRepository(); - $recurring_invoice_repo->archive($$old_recurring_invoice); + $recurring_invoice_repo->archive($recurring_invoice); if($refund_end_date->greaterThan(now()) && (int)$outstanding_invoice->balance == 0) { @@ -698,7 +698,7 @@ class SubscriptionService ]; - $payment->refundPayment($data); + $payment->refund($data); } } From 0426b6c9416fd6402eb4d4191e6d2ed3f9e3b41d Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 16 Apr 2021 07:58:34 +1000 Subject: [PATCH 11/11] Add payment notification on manual payment creation --- app/Http/Controllers/PaymentController.php | 20 ++++++++++++++---- .../Company/CreateCompanyTaskStatuses.php | 8 +++---- app/Models/Webhook.php | 21 +++++++++++++++++-- app/Repositories/PaymentRepository.php | 6 +++++- 4 files changed, 44 insertions(+), 11 deletions(-) diff --git a/app/Http/Controllers/PaymentController.php b/app/Http/Controllers/PaymentController.php index 82224dd1a383..c1463151d9aa 100644 --- a/app/Http/Controllers/PaymentController.php +++ b/app/Http/Controllers/PaymentController.php @@ -592,7 +592,7 @@ class PaymentController extends BaseController $this->payment_repo->restore($payment); if (! $bulk) { - return $this->listResponse($payment); + return $this->itemResponse($payment); } break; @@ -600,7 +600,7 @@ class PaymentController extends BaseController $this->payment_repo->archive($payment); if (! $bulk) { - return $this->listResponse($payment); + return $this->itemResponse($payment); } // code... break; @@ -608,14 +608,26 @@ class PaymentController extends BaseController $this->payment_repo->delete($payment); if (! $bulk) { - return $this->listResponse($payment); + return $this->itemResponse($payment); } // code... break; case 'email': //dispatch email to queue - break; + $this->payment->service()->sendEmail(); + if (! $bulk) { + return $this->itemResponse($payment); + } + break; + case 'email_receipt': + $this->payment->service()->sendEmail(); + + if (! $bulk) { + return $this->itemResponse($payment); + } + break; + default: // code... break; diff --git a/app/Jobs/Company/CreateCompanyTaskStatuses.php b/app/Jobs/Company/CreateCompanyTaskStatuses.php index 3eec3f7203bd..99ec5658855d 100644 --- a/app/Jobs/Company/CreateCompanyTaskStatuses.php +++ b/app/Jobs/Company/CreateCompanyTaskStatuses.php @@ -45,10 +45,10 @@ class CreateCompanyTaskStatuses public function handle() { $task_statuses = [ - ['name' => ctrans('texts.backlog'), 'company_id' => $this->company->id, 'user_id' => $this->user->id, 'created_at' => now(), 'updated_at' => now()], - ['name' => ctrans('texts.ready_to_do'), 'company_id' => $this->company->id, 'user_id' => $this->user->id, 'created_at' => now(), 'updated_at' => now()], - ['name' => ctrans('texts.in_progress'), 'company_id' => $this->company->id, 'user_id' => $this->user->id, 'created_at' => now(), 'updated_at' => now()], - ['name' => ctrans('texts.done'), 'company_id' => $this->company->id, 'user_id' => $this->user->id, 'created_at' => now(), 'updated_at' => now()], + ['name' => ctrans('texts.backlog'), 'company_id' => $this->company->id, 'user_id' => $this->user->id, 'created_at' => now(), 'updated_at' => now(), 'status_order' => 1], + ['name' => ctrans('texts.ready_to_do'), 'company_id' => $this->company->id, 'user_id' => $this->user->id, 'created_at' => now(), 'updated_at' => now(), 'status_order' => 2], + ['name' => ctrans('texts.in_progress'), 'company_id' => $this->company->id, 'user_id' => $this->user->id, 'created_at' => now(), 'updated_at' => now(), 'status_order' => 3], + ['name' => ctrans('texts.done'), 'company_id' => $this->company->id, 'user_id' => $this->user->id, 'created_at' => now(), 'updated_at' => now(), 'status_order' => 4], ]; diff --git a/app/Models/Webhook.php b/app/Models/Webhook.php index 1372bf03e92c..c6adaa44139b 100644 --- a/app/Models/Webhook.php +++ b/app/Models/Webhook.php @@ -45,12 +45,29 @@ class Webhook extends BaseModel public static $valid_events = [ self::EVENT_CREATE_CLIENT, - self::EVENT_CREATE_PAYMENT, - self::EVENT_CREATE_QUOTE, self::EVENT_CREATE_INVOICE, + self::EVENT_CREATE_QUOTE, + self::EVENT_CREATE_PAYMENT, self::EVENT_CREATE_VENDOR, + self::EVENT_UPDATE_QUOTE, + self::EVENT_DELETE_QUOTE, + self::EVENT_UPDATE_INVOICE, + self::EVENT_DELETE_INVOICE, + self::EVENT_UPDATE_CLIENT, + self::EVENT_DELETE_CLIENT, + self::EVENT_DELETE_PAYMENT, + self::EVENT_UPDATE_VENDOR, + self::EVENT_DELETE_VENDOR, self::EVENT_CREATE_EXPENSE, + self::EVENT_UPDATE_EXPENSE, + self::EVENT_DELETE_EXPENSE, self::EVENT_CREATE_TASK, + self::EVENT_UPDATE_TASK, + self::EVENT_DELETE_TASK, + self::EVENT_APPROVE_QUOTE, + self::EVENT_LATE_INVOICE, + self::EVENT_EXPIRED_QUOTE, + self::EVENT_REMIND_INVOICE, ]; protected $fillable = [ diff --git a/app/Repositories/PaymentRepository.php b/app/Repositories/PaymentRepository.php index ae9f7733b37c..43235573e257 100644 --- a/app/Repositories/PaymentRepository.php +++ b/app/Repositories/PaymentRepository.php @@ -155,7 +155,11 @@ class PaymentRepository extends BaseRepository { } if ( ! $is_existing_payment && ! $this->import_mode ) { - event( new PaymentWasCreated( $payment, $payment->company, Ninja::eventVars(auth()->user()->id) ) ); + + if ($payment->client->getSetting('client_manual_payment_notification')) + $payment->service()->sendEmail(); + + event( new PaymentWasCreated( $payment, $payment->company, Ninja::eventVars(auth()->user()->id) ) ); } nlog("payment amount = {$payment->amount}");