where('account_id', $account->id) ->orderByDesc('installment_at') ->get(['id', 'amount', 'balance_before', 'currency', 'reference', 'installment_at', 'created_at']) ->map(function (Installment $i) { return [ 'id' => $i->id, 'amount' => (float) $i->amount, 'balance_before' => (float) ($i->balance_before ?? 0), 'currency' => $i->currency, 'reference' => $i->reference, 'installment_at' => optional($i->installment_at)?->toDateString(), 'created_at' => optional($i->created_at)?->toDateTimeString(), ]; }); return response()->json([ 'account' => [ 'id' => $account->id, 'balance_amount' => $account->balance_amount, ], 'installments' => $installments, ]); } public function store(StoreInstallmentRequest $request, Account $account): RedirectResponse { $validated = $request->validated(); $amountCents = (int) round(((float) $validated['amount']) * 100); $settings = InstallmentSetting::query()->first(); $defaultCurrency = strtoupper($settings->default_currency ?? 'EUR'); $installment = Installment::query()->create([ 'account_id' => $account->id, 'balance_before' => (float) ($account->balance_amount ?? 0), 'amount' => (float) $validated['amount'], 'currency' => strtoupper($validated['currency'] ?? $defaultCurrency), 'reference' => $validated['reference'] ?? null, 'installment_at' => $validated['installment_at'] ?? now(), 'meta' => $validated['meta'] ?? null, 'created_by' => $request->user()?->id, ]); // Debit booking — increases the account balance Booking::query()->create([ 'account_id' => $account->id, 'payment_id' => null, 'amount_cents' => $amountCents, 'type' => 'debit', 'description' => $installment->reference ? ('Obremenitev '.$installment->reference) : 'Obremenitev', 'booked_at' => $installment->installment_at ?? now(), ]); if ($settings && ($settings->create_activity_on_installment ?? false)) { $note = $settings->activity_note_template ?? 'Dodan obrok'; $note = str_replace(['{amount}', '{currency}'], [number_format($amountCents / 100, 2, ',', '.'), $installment->currency], $note); $account->refresh(); $beforeStr = number_format((float) ($installment->balance_before ?? 0), 2, ',', '.').' '.$installment->currency; $afterStr = number_format((float) ($account->balance_amount ?? 0), 2, ',', '.').' '.$installment->currency; $note .= " (Stanje pred: {$beforeStr}, Stanje po: {$afterStr}; Izvor: obrok)"; $account->loadMissing('contract'); $clientCaseId = $account->contract?->client_case_id; if ($clientCaseId) { $activity = Activity::query()->create([ 'due_date' => null, 'amount' => $amountCents / 100, 'note' => $note, 'action_id' => $settings->default_action_id, 'decision_id' => $settings->default_decision_id, 'client_case_id' => $clientCaseId, 'contract_id' => $account->contract_id, ]); $installment->update(['activity_id' => $activity->id]); } } return back()->with('success', 'Installment created.'); } public function destroy(Account $account, Installment $installment): RedirectResponse|JsonResponse { if ($installment->account_id !== $account->id) { abort(404); } // Delete related debit booking(s) to revert balance via model events Booking::query() ->where('account_id', $account->id) ->where('type', 'debit') ->whereDate('booked_at', optional($installment->installment_at)?->toDateString()) ->where('amount_cents', (int) round(((float) $installment->amount) * 100)) ->whereNull('payment_id') ->get() ->each->delete(); if ($installment->activity_id) { $activity = Activity::query()->find($installment->activity_id); if ($activity) { $activity->delete(); } } $installment->delete(); if (request()->wantsJson()) { return response()->json(['success' => true]); } return back()->with('success', 'Installment deleted.'); } }