From dfa773d6b966585c3c3d2befe18669d7b3357711 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Thu, 21 Oct 2021 13:03:41 +1100 Subject: [PATCH] ProRata Refunds --- .../Invoice/{Refund.php => ProRata.php} | 62 ++++++++++++++++++- .../Subscription/SubscriptionCalculator.php | 48 ++++++++++++++ tests/Unit/RefundUnitTest.php | 10 +-- 3 files changed, 113 insertions(+), 7 deletions(-) rename app/Helpers/Invoice/{Refund.php => ProRata.php} (55%) create mode 100644 app/Helpers/Subscription/SubscriptionCalculator.php diff --git a/app/Helpers/Invoice/Refund.php b/app/Helpers/Invoice/ProRata.php similarity index 55% rename from app/Helpers/Invoice/Refund.php rename to app/Helpers/Invoice/ProRata.php index e4e12dd0b9..4026d41d30 100644 --- a/app/Helpers/Invoice/Refund.php +++ b/app/Helpers/Invoice/ProRata.php @@ -11,13 +11,24 @@ namespace App\Helpers\Invoice; +use App\Models\Invoice; use App\Models\RecurringInvoice; +use Carbon\Exceptions\InvalidFormatException; +use Exception; +use Illuminate\Contracts\Container\BindingResolutionException; use Illuminate\Support\Carbon; -class Refund +class ProRata { - public function proRata(float $amount, Carbon $from_date, Carbon $to_date, int $frequency) :float + /** + * @param float $amount + * @param Carbon $from_date + * @param Carbon $to_date + * @param int $frequency + * @return float + */ + public function refund(float $amount, Carbon $from_date, Carbon $to_date, int $frequency) :float { $days = $from_date->diffInDays($to_date); $days_in_frequency = $this->getDaysInFrequency($frequency); @@ -25,6 +36,53 @@ class Refund return round( (($days/$days_in_frequency) * $amount),2); } + + /** + * Prepares the line items of an invoice + * to be pro rata refunded. + * + * @param Invoice $invoice + * @param bool $is_credit + * @return array + * @throws Exception + */ + public function refundItems(Invoice $invoice, $is_credit = false) :array + { + if(!$invoice) + return []; + + $recurring_invoice = RecurringInvoice::find($invoice->recurring_id)->first(); + + if(!$recurring_invoice) + throw new \Exception("Invoice isn't attached to a recurring invoice"); + + /* depending on whether we are creating an invoice or a credit*/ + $multiplier = $is_credit ? 1 : -1; + + $start_date = Carbon::parse($invoice->date); + + $line_items = []; + + foreach($invoice->line_items as $item) + { + + if($item->product_key != ctrans('texts.refund')) + { + $item->quantity = 1; + $item->cost = $this->refund($item->cost*$multiplier, $start_date, now(), $recurring_invoice->frequency_id); + $item->product_key = ctrans('texts.refund'); + $item->notes = ctrans('texts.refund') . ": ". $item->notes; + + $line_items[] = $item; + + } + } + + return $line_items; + + } + + private function getDaysInFrequency($frequency) { diff --git a/app/Helpers/Subscription/SubscriptionCalculator.php b/app/Helpers/Subscription/SubscriptionCalculator.php new file mode 100644 index 0000000000..597f727ca6 --- /dev/null +++ b/app/Helpers/Subscription/SubscriptionCalculator.php @@ -0,0 +1,48 @@ +subscription = $subscription; + } + + /** + * Tests if the user is currently up + * to date with their payments for + * a given recurring invoice + * + * @return bool + */ + public function isPaidUp(RecurringInvoice $recurring_invoice) :bool + { + + $outstanding_invoices_exist = Invoice::whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL]) + ->where('recurring_id', $recurring_invoice->id) + ->where('balance', '>', 0) + ->exists(); + + return ! $outstanding_invoices_exist; + + } +} \ No newline at end of file diff --git a/tests/Unit/RefundUnitTest.php b/tests/Unit/RefundUnitTest.php index bfecc4b616..fe930e0a0c 100644 --- a/tests/Unit/RefundUnitTest.php +++ b/tests/Unit/RefundUnitTest.php @@ -10,7 +10,7 @@ */ namespace Tests\Unit; -use App\Helpers\Invoice\Refund; +use App\Helpers\Invoice\ProRata; use App\Models\RecurringInvoice; use App\Utils\Ninja; use Illuminate\Support\Carbon; @@ -29,8 +29,8 @@ class RefundUnitTest extends TestCase public function testProRataRefundMonthly() { - $r = new Refund(); - $refund = $r->proRata(10, Carbon::parse('2021-01-01'), Carbon::parse('2021-01-31'), RecurringInvoice::FREQUENCY_MONTHLY); + $pro_rata = new ProRata(); + $refund = $pro_rata->refund(10, Carbon::parse('2021-01-01'), Carbon::parse('2021-01-31'), RecurringInvoice::FREQUENCY_MONTHLY); $this->assertEquals(9.68, $refund); @@ -40,9 +40,9 @@ class RefundUnitTest extends TestCase public function testProRataRefundYearly() { - $r = new Refund(); + $pro_rata = new ProRata(); - $refund = $r->proRata(10, Carbon::parse('2021-01-01'), Carbon::parse('2021-01-31'), RecurringInvoice::FREQUENCY_ANNUALLY); + $refund = $pro_rata->refund(10, Carbon::parse('2021-01-01'), Carbon::parse('2021-01-31'), RecurringInvoice::FREQUENCY_ANNUALLY); $this->assertEquals(0.82, $refund); }