diff --git a/app/Factory/RecurringInvoiceFactory.php b/app/Factory/RecurringInvoiceFactory.php index e246d5cea30a..54fbbc354272 100644 --- a/app/Factory/RecurringInvoiceFactory.php +++ b/app/Factory/RecurringInvoiceFactory.php @@ -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; diff --git a/app/Factory/RecurringInvoiceToInvoiceFactory.php b/app/Factory/RecurringInvoiceToInvoiceFactory.php index 3692e458c62e..63b5fa024bec 100644 --- a/app/Factory/RecurringInvoiceToInvoiceFactory.php +++ b/app/Factory/RecurringInvoiceToInvoiceFactory.php @@ -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; diff --git a/app/Http/Controllers/ClientPortal/PrePaymentController.php b/app/Http/Controllers/ClientPortal/PrePaymentController.php index 9c8070e572d4..8e3f37777804 100644 --- a/app/Http/Controllers/ClientPortal/PrePaymentController.php +++ b/app/Http/Controllers/ClientPortal/PrePaymentController.php @@ -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, ]; diff --git a/app/Http/ViewComposers/PortalComposer.php b/app/Http/ViewComposers/PortalComposer.php index 747cc9572adb..3e796d110b5b 100644 --- a/app/Http/ViewComposers/PortalComposer.php +++ b/app/Http/ViewComposers/PortalComposer.php @@ -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; } diff --git a/app/Services/ClientPortal/InstantPayment.php b/app/Services/ClientPortal/InstantPayment.php index 6dcae4a17921..3cdc656e15c6 100644 --- a/app/Services/ClientPortal/InstantPayment.php +++ b/app/Services/ClientPortal/InstantPayment.php @@ -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')); diff --git a/app/Services/Invoice/ApplyNumber.php b/app/Services/Invoice/ApplyNumber.php index ee4368f557b3..93c5adb187b5 100644 --- a/app/Services/Invoice/ApplyNumber.php +++ b/app/Services/Invoice/ApplyNumber.php @@ -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(); diff --git a/app/Services/Invoice/AutoBillInvoice.php b/app/Services/Invoice/AutoBillInvoice.php index cb40857bcabb..d60a14fa0953 100644 --- a/app/Services/Invoice/AutoBillInvoice.php +++ b/app/Services/Invoice/AutoBillInvoice.php @@ -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, ]); diff --git a/app/Services/Payment/UpdateInvoicePayment.php b/app/Services/Payment/UpdateInvoicePayment.php index 0fe1a9001edc..7f6b0372e8c0 100644 --- a/app/Services/Payment/UpdateInvoicePayment.php +++ b/app/Services/Payment/UpdateInvoicePayment.php @@ -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 = ''; diff --git a/app/Services/Subscription/SubscriptionService.php b/app/Services/Subscription/SubscriptionService.php index 2bc4060aadb0..49f44eca53ad 100644 --- a/app/Services/Subscription/SubscriptionService.php +++ b/app/Services/Subscription/SubscriptionService.php @@ -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; diff --git a/database/migrations/2023_03_17_012309_add_proforma_flag_for_recurring_invoices.php b/database/migrations/2023_03_17_012309_add_proforma_flag_for_recurring_invoices.php new file mode 100644 index 000000000000..afdbcb3faa72 --- /dev/null +++ b/database/migrations/2023_03_17_012309_add_proforma_flag_for_recurring_invoices.php @@ -0,0 +1,31 @@ +boolean('is_proforma')->default(false); + }); + + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +}; diff --git a/lang/en/texts.php b/lang/en/texts.php index 19230f5b0211..a76a4df9b1c7 100644 --- a/lang/en/texts.php +++ b/lang/en/texts.php @@ -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', ); diff --git a/resources/views/portal/ninja2020/invoices/payment.blade.php b/resources/views/portal/ninja2020/invoices/payment.blade.php index adc7b32c90b6..bc476baca7ed 100644 --- a/resources/views/portal/ninja2020/invoices/payment.blade.php +++ b/resources/views/portal/ninja2020/invoices/payment.blade.php @@ -14,6 +14,9 @@ + + +