Add recurring options to ivnoice

This commit is contained in:
David Bomba 2023-03-17 12:49:08 +11:00
parent a10f06796a
commit f14de42684
13 changed files with 110 additions and 17 deletions

View File

@ -53,6 +53,7 @@ class RecurringInvoiceFactory
$invoice->remaining_cycles = -1;
$invoice->paid_to_date = 0;
$invoice->auto_bill_enabled = false;
$invoice->is_proforma = false;
$invoice->auto_bill = 'off';
return $invoice;

View File

@ -46,6 +46,7 @@ class RecurringInvoiceToInvoiceFactory
$invoice->custom_value4 = $recurring_invoice->custom_value4;
$invoice->amount = $recurring_invoice->amount;
$invoice->uses_inclusive_taxes = $recurring_invoice->uses_inclusive_taxes;
$invoice->is_proforma = $recurring_invoice->is_proforma;
$invoice->custom_surcharge1 = $recurring_invoice->custom_surcharge1;
$invoice->custom_surcharge2 = $recurring_invoice->custom_surcharge2;

View File

@ -80,6 +80,7 @@ class PrePaymentController extends Controller
$invoice = $invoice_repo->save($data, $invoice)
->service()
->markSent()
->applyNumber()
->fillDefaults()
->save();
@ -107,6 +108,9 @@ class PrePaymentController extends Controller
'hashed_ids' => $invoices->pluck('hashed_id'),
'total' => $total,
'pre_payment' => true,
'frequency_id' => $request->frequency_id,
'remaining_cycles' => $request->remaining_cycles,
'is_recurring' => $request->is_recurring,
];

View File

@ -138,9 +138,9 @@ class PortalComposer
$data[] = ['title' => ctrans('texts.subscriptions'), 'url' => 'client.subscriptions.index', 'icon' => 'calendar'];
}
if(property_exists($this->settings, 'client_initiated_payments') && $this->settings->client_initiated_payments) {
// if(property_exists($this->settings, 'client_initiated_payments') && $this->settings->client_initiated_payments) {
$data[] = ['title' => ctrans('texts.pre_payment'), 'url' => 'client.pre_payments.index', 'icon' => 'dollar-sign'];
}
// }
return $data;
}

View File

@ -34,6 +34,7 @@ class InstantPayment
use MakesHash;
use MakesDates;
/** $request mixed */
public Request $request;
public function __construct(Request $request)
@ -214,7 +215,16 @@ class InstantPayment
$credit_totals = 0;
}
$hash_data = ['invoices' => $payable_invoices->toArray(), 'credits' => $credit_totals, 'amount_with_fee' => max(0, (($invoice_totals + $fee_totals) - $credit_totals)), 'pre_payment' => $this->request->pre_payment];
/** $hash_data = mixed[] */
$hash_data = [
'invoices' => $payable_invoices->toArray(),
'credits' => $credit_totals,
'amount_with_fee' => max(0, (($invoice_totals + $fee_totals) - $credit_totals)),
'pre_payment' => $this->request->pre_payment,
'frequency_id' => $this->request->frequency_id,
'remaining_cycles' => $this->request->remaining_cycles,
'is_recurring' => $this->request->is_recurring,
];
if ($this->request->query('hash')) {
$hash_data['billing_context'] = Cache::get($this->request->query('hash'));

View File

@ -40,6 +40,13 @@ class ApplyNumber extends AbstractService
return $this->invoice;
}
/** Do no give pro forma invoices a proper invoice number */
if($this->invoice->is_proforma) {
$this->invoice->number = ctrans('texts.pre_payment') . " " . now()->format('Y-m-d : H:i:s');
$this->invoice->saveQuietly();
return $this->invoice;
}
switch ($this->client->getSetting('counter_number_applied')) {
case 'when_saved':
$this->trySaving();

View File

@ -121,7 +121,17 @@ class AutoBillInvoice extends AbstractService
$payment_hash = PaymentHash::create([
'hash' => Str::random(64),
'data' => ['amount_with_fee' => $amount + $fee, 'invoices' => [['invoice_id' => $this->invoice->hashed_id, 'amount' => $amount, 'invoice_number' => $this->invoice->number]]],
'data' => [
'amount_with_fee' => $amount + $fee,
'invoices' => [
[
'invoice_id' => $this->invoice->hashed_id,
'amount' => $amount,
'invoice_number' => $this->invoice->number,
'pre_payment' => $this->invoice->is_proforma,
],
],
],
'fee_total' => $fee,
'fee_invoice_id' => $this->invoice->id,
]);

View File

@ -11,12 +11,14 @@
namespace App\Services\Payment;
use App\Events\Invoice\InvoiceWasUpdated;
use App\Utils\Ninja;
use App\Models\Invoice;
use App\Models\Payment;
use App\Models\PaymentHash;
use App\Utils\Ninja;
use App\Utils\Traits\MakesHash;
use App\Models\RecurringInvoice;
use App\Factory\RecurringInvoiceFactory;
use App\Events\Invoice\InvoiceWasUpdated;
class UpdateInvoicePayment
{
@ -93,9 +95,31 @@ class UpdateInvoicePayment
$invoice->is_deleted = true;
$invoice->deleted_at = now();
$invoice->saveQuietly();
if (property_exists($this->payment_hash->data, 'is_recurring') && $this->payment_hash->data->is_recurring == "1") {
$recurring_invoice = RecurringInvoiceFactory::create($invoice->company_id, $invoice->user_id);
$recurring_invoice->client_id = $invoice->client_id;
$recurring_invoice->line_items = $invoice->line_items;
$recurring_invoice->frequency_id = $this->payment_hash->data->is_recurring ?: RecurringInvoice::FREQUENCY_MONTHLY;
$recurring_invoice->date = now();
$recurring_invoice->remaining_cycles = $this->payment_hash->data->remaining_cycles;
$recurring_invoice->auto_bill = 'always';
$recurring_invoice->auto_bill_enabled = true;
$recurring_invoice->due_date_days = 'on_receipt';
$recurring_invoice->next_send_date = now()->format('Y-m-d');
$recurring_invoice->next_send_date_client = now()->format('Y-m-d');
$recurring_invoice->saveQuietly();
$recurring_invoice->next_send_date = $recurring_invoice->nextSendDate();
$recurring_invoice->next_send_date_client = $recurring_invoice->nextSendDateClient();
$recurring_invoice->saveQuietly();
}
return;
}
if (strlen($invoice->number) > 1 && str_starts_with($invoice->number, "####"))
$invoice->number = '';

View File

@ -1087,7 +1087,7 @@ class SubscriptionService
}
private function setAutoBillFlag($auto_bill)
private function setAutoBillFlag($auto_bill): bool
{
if ($auto_bill == 'always' || $auto_bill == 'optout') {
return true;

View File

@ -0,0 +1,31 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('recurring_invoices', function (Blueprint $table) {
$table->boolean('is_proforma')->default(false);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
//
}
};

View File

@ -5021,7 +5021,9 @@ $LANG = array(
'payment_type_Klarna' => 'Klarna',
'payment_type_Interac E Transfer' => 'Interac E Transfer',
'pre_payment' => 'Pre Payment',
'client_remaining_cycles_helper' => 'The number of times this invoice will be generated',
'number_of_payments' => 'Number of payments',
'number_of_payments_helper' => 'The number of times this payment will be made',
'pre_payment_indefinitely' => 'Continue until cancelled',
);

View File

@ -14,6 +14,9 @@
<input type="hidden" name="payment_method_id" id="payment_method_id">
<input type="hidden" name="signature">
<input type="hidden" name="pre_payment" value="{{ isset($pre_payment) ? $pre_payment : false }}">
<input type="hidden" name="is_recurring" value="{{ isset($is_recurring) ? $is_recurring : false }}">
<input type="hidden" name="frequency_id" value="{{ isset($frequency_id) ? $frequency_id : false }}">
<input type="hidden" name="remaining_cycles" value="{{ isset($remaining_cycles) ? $remaining_cycles : false }}">
<div class="container mx-auto">
<div class="grid grid-cols-6 gap-4">

View File

@ -56,15 +56,15 @@
@endcomponent
<div x-cloak x-show="show">
@component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.cycles_remaining')])
@component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.number_of_payments')])
<select name="remaining_cycles" class="form-select input w-full bg-white">
<option value="-1" selected>{{ ctrans('texts.freq_indefinitely')}}</option>
<option value="-1" selected>{{ ctrans('texts.pre_payment_indefinitely')}}</option>
@for($i = 1; $i < 60; $i++)
<option value={{$i}}>{{$i}}</option>
@endfor
</select>
<span class="py-2">
<label for="remaining_cycles" class="col-form-label text-center col-lg-3 text-gray-900">{{ ctrans ('texts.client_remaining_cycles_helper')}}</label>
<label for="remaining_cycles" class="col-form-label text-center col-lg-3 text-gray-900">{{ ctrans ('texts.number_of_payments_helper')}}</label>
</span>
@endcomponent
@component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.frequency')])
@ -73,14 +73,14 @@
<option value="2">{{ ctrans('texts.freq_weekly') }}</option>
<option value="3">{{ ctrans('texts.freq_two_weeks') }}</option>
<option value="4">{{ ctrans('texts.freq_four_weeks') }}</option>
<option value="5">{{ ctrans('texts.freq_monthly') }}</option>
<option value="5" selected>{{ ctrans('texts.freq_monthly') }}</option>
<option value="6">{{ ctrans('texts.freq_two_months') }}</option>
<option value="7">{{ ctrans('texts.freq_three_months') }}</option>
<option value="8">{{ ctrans('texts.') }}</option>
<option value="9">{{ ctrans('texts.') }}</option>
<option value="10">{{ ctrans('texts.') }}</option>
<option value="11">{{ ctrans('texts.') }}</option>
<option value="12">{{ ctrans('texts.') }}</option>
<option value="8">{{ ctrans('texts.freq_four_months') }}</option>
<option value="9">{{ ctrans('texts.freq_six_months') }}</option>
<option value="10">{{ ctrans('texts.freq_annually') }}</option>
<option value="11">{{ ctrans('texts.freq_two_years') }}</option>
<option value="12">{{ ctrans('texts.freq_three_years') }}</option>
</select>
@endcomponent
</div>