Skip to content

Anpassungen Zugferd, Bankkonten verwalten#563

Merged
dspangenberg merged 3 commits into
mainfrom
develop
Jul 1, 2026
Merged

Anpassungen Zugferd, Bankkonten verwalten#563
dspangenberg merged 3 commits into
mainfrom
develop

Conversation

@dspangenberg

@dspangenberg dspangenberg commented Jul 1, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • Neue Funktionen

    • Neue Einstellungsmodule für Bankkonten: Anzeige, Anlegen, Bearbeiten und Löschen.
    • Zusätzliche Aktionen in der Liste: „Als Standardkonto setzen“ sowie Bearbeitung über Tabellenzeilen.
    • UI mit konditionellen Feldern für klassische Konten (IBAN/BIC/Bankname) und PayPal-Konten (E-Mail).
    • Darstellung von Status/Flags (z. B. Standard, geschlossen) und optionale Buchhaltungszuordnung.
    • Navigation um den Bereich Bankkonten ergänzt.
  • Bug Fixes

    • Validierung und Eingabedaten an die neuen optionalen Bank-/PayPal-Details angepasst.

@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@dspangenberg, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 21 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e9d3ba50-a77b-4b6c-81f7-af5d7d164b4f

📥 Commits

Reviewing files that changed from the base of the PR and between bdda230 and bd57937.

📒 Files selected for processing (6)
  • app/Http/Controllers/App/Setting/BankAccountController.php
  • app/Models/BankAccount.php
  • app/Models/Invoice.php
  • resources/js/Pages/App/Invoice/InvoiceDetailsSide.tsx
  • resources/js/Pages/App/Setting/BankAccount/BankAccountEdit.tsx
  • resources/js/Pages/App/Setting/BankAccount/BankAccountIndexColumns.tsx

Walkthrough

Die Änderung führt Bankkonten mit neuer Datenstruktur, Validierung, Routen und Inertia-Oberflächen ein. Zusätzlich werden Typen, Schema, Formular-Hooks und Navigation an die neuen Felder und Aktionen angepasst.

Changes

Bankkonten-Feature

Layer / File(s) Summary
Datenvertrag und Schema
app/Data/BankAccountData.php, resources/js/Types/generated.d.ts, database/migrations/tenant/2026_07_01_205228_add_is_default_to_bank_accounts.php, app/Models/BankAccount.php, resources/typescript-transformer-manifest.json
BankAccountData, die generierten Typen und das Datenbankschema werden auf optionale Bankdaten, Statusflags und neue Nullable-Felder umgestellt; das Modell erhält $fillable.
Controller, Validierung und Routing
app/Http/Controllers/App/Setting/BankAccountController.php, app/Http/Requests/BankAccountRequest.php, routes/tenant/settings.php
Neuer Bankkonto-Controller mit CRUD-, Default- und Löschaktionen; die Request-Validierung schaltet zwischen Bankdaten und PayPal-Feldern um, und die Tenant-Routen werden dafür ergänzt.
Index, Spalten und Navigation
resources/js/Pages/App/Setting/BankAccount/BankAccountIndex.tsx, resources/js/Pages/App/Setting/BankAccount/BankAccountIndexColumns.tsx, resources/js/Components/AppSidebar.tsx
Neue Index-Seite mit Pagination, Toolbar und DataTable; die Spalten enthalten Standardkonto-, Link- und Aktionsdarstellung; die Sidebar erhält den Bankkonten-Eintrag.
Edit-Formular und Formular-Hooks
resources/js/Pages/App/Setting/BankAccount/BankAccountEdit.tsx, resources/js/Hooks/use-twc-ui-form.ts, resources/js/Components/twc-ui/combo-box.tsx
Neue Create/Edit-Seite mit konditionalen Feldern, typisierte Formularregistrierung und angepasste ComboBox-Exports werden hinzugefügt.
Aufräumarbeiten
app/Http/Controllers/App/ContactController.php, app/Services/ZugferdService.php, database/seeders/TenantSeeder.php
Ein Import und ein DocBlock im Contact-Controller, ein Leerraum in ZugferdService und ein nicht mehr genutzter Seeder-Import werden entfernt oder angepasst.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

  • dspangenberg/opsc#487: Betrifft dieselbe ZugferdService::generateZugferdXml()-Stelle wie die kleine Anpassung in diesem PR.
  • dspangenberg/opsc#491: Ändert ebenfalls app/Services/ZugferdService.php und berührt damit denselben Funktionsbereich.
  • dspangenberg/opsc#493: Bezieht sich wie dieser PR auf generateZugferdXml() und die Storno-/Referenzlogik.

Poem

Hopp, ein Bankkonto ist nun da,
mit IBAN, PayPal, wunderbar. 🐰
Default gesetzt, die Sidebar nickt,
der Hase froh durchs Formular hüpft.
🥕

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Der Titel nennt die beiden Hauptthemen Zugferd und Bankkonten und passt damit gut zu den geänderten Bereichen.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch develop

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

🧹 Nitpick comments (3)
resources/js/Pages/App/Setting/BankAccount/BankAccountEdit.tsx (1)

24-36: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Ungewöhnlicher Form-Bezeichner mit Tippfehler-Optik.

'form-bank-account.-edit' enthält einen Punkt gefolgt von einem Bindestrich, was wie ein Tippfehler wirkt (vermutlich 'form-bank-account-edit' gemeint). Rein kosmetisch, da der Wert nur als interner Form-Key/form.id verwendet wird, aber für Konsistenz mit anderen Formularen sollte der Bezeichner bereinigt werden.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@resources/js/Pages/App/Setting/BankAccount/BankAccountEdit.tsx` around lines
24 - 36, The form key passed to useForm in BankAccountEdit has an odd typo-like
separator sequence, so clean up the identifier to match the naming pattern used
by other forms. Update the first argument in useForm<App.Data.BankAccountData>
from the current BankAccountEdit key to a consistent, readable form name while
keeping the rest of the hook logic unchanged.
routes/tenant/settings.php (1)

68-73: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Inkonsistentes Routenmuster für die Store-Route.

.../bank-accounts/create als POST-Ziel weicht vom sonstigen Muster in dieser Datei ab: Andere Controller nutzen für den POST-Store entweder ein "/store"-Suffix (text-modules/store, offer-sections/store, letterheads/store, layouts/store, office-templates/store) oder die reine Sammlungs-URL (document-types, cost-centers). Keine Sibling-Route verwendet "/create" für POST.

As per coding guidelines: "Follow the application's existing code conventions, including naming, structure, and reuse of existing components."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@routes/tenant/settings.php` around lines 68 - 73, The BankAccountController
store route uses an inconsistent POST path by pointing to the create endpoint
instead of matching the app’s established route patterns. Update the store route
in the tenant settings routes to follow the same convention used by other
resources, either by using a /store suffix or the collection URL, and keep the
edit/create distinction aligned with the existing bank_account route names and
controller actions.

Source: Coding guidelines

app/Http/Controllers/App/Setting/BankAccountController.php (1)

35-57: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Keine Autorisierungsprüfung sichtbar.

edit, update und store prüfen nicht explizit, ob der aktuelle Benutzer Bankkonten verwalten darf (Gate/Policy). Falls der Tenant-Scope allein nicht ausreicht, sollte hier eine Policy ergänzt werden.

As per coding guidelines: "Use Laravel's built-in authentication and authorization features such as gates, policies, and Sanctum."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/Http/Controllers/App/Setting/BankAccountController.php` around lines 35 -
57, The BankAccountController actions edit, update, and store currently rely
only on tenant scoping and do not explicitly authorize bank account management.
Add Laravel authorization checks using the existing policy/gate pattern in these
methods, ideally via authorize() or a dedicated BankAccountPolicy, so only users
permitted to manage bank accounts can access BankAccountController::edit,
BankAccountController::update, and BankAccountController::store.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/Data/BankAccountData.php`:
- Around line 21-29: The generated TypeScript definition for BankAccountData is
stale: bookkeeping_account_id in BankAccountData now uses ?int in the PHP data
class while the generated d.ts still declares string | null. Update the
generation or source type mapping so the TS type matches the PHP definition, and
verify the edit form flow for account_number continues to pass a numeric value
consistently through the BankAccountData-related types.

In `@app/Http/Controllers/App/Setting/BankAccountController.php`:
- Around line 15-58: Add explicit return type declarations to every public
method in BankAccountController: index, create, and edit should return the
Inertia response type they produce, while update and store should declare the
redirect/response type returned by redirect()->route(...). Use the existing
method names in BankAccountController to update the signatures consistently
without changing behavior.
- Around line 24-33: The create() method in BankAccountController is rendering
the wrong Inertia page and building an incomplete BankAccount object. Update
create() to render the Bank Account create/edit component instead of
App/Setting/DocumentType/DocumentTypeEdit, and make sure the BankAccount
instance is initialized with all required non-null fields before passing it to
BankAccountData::from. Keep the existing bookkeeping_accounts loading, and use
the create() flow in BankAccountController to ensure the page opens without
validation/data-mapping failures.

In `@app/Http/Requests/BankAccountRequest.php`:
- Around line 9-32: The BankAccountRequest FormRequest currently defines
validation rules in rules() but is missing the required custom error messages.
Add a messages() method to BankAccountRequest and provide localized,
field-specific validation text for the existing rules so the request includes
both rules and custom messages as required by the project convention.

In
`@database/migrations/tenant/2026_07_01_205228_add_is_default_to_bank_accounts.php`:
- Around line 22-30: The down() method in the migration does not fully reverse
the schema changes made in the up path, leaving the bank_accounts table
partially modified after rollback. Update the migration’s down() logic in the
same class to not only drop the added columns but also restore the original
settings for the fields changed with ->change() (prefix, bookkeeping_account_id,
and pos), so the rollback fully returns the table to its prior state.
- Around line 15-17: The migration in the bank accounts tenant migration is
changing columns with incomplete original metadata, which can unintentionally
alter their types and defaults. Update the `change()` calls in the migration to
preserve the original column definitions for `prefix` and
`bookkeeping_account_id` by explicitly including their prior attributes when
modifying them, and verify that `bookkeeping_account_id` remains an integer if
that was the intended schema. Keep the `pos` change separate and only adjust its
default as needed.

In `@resources/js/Pages/App/Setting/BankAccount/BankAccountIndex.tsx`:
- Around line 44-57: The action bar is incomplete because the “als bestätigt
markieren” Button in BankAccountIndex’s actionBar has no click behavior and the
trailing x placeholder is leftover markup. Update the actionBar in
BankAccountIndex to either wire the Button to the intended confirmation handler
using the selectedRows state or disable/remove it if the feature is not ready,
and remove the placeholder div so the Toolbar only shows functional UI.
- Around line 26-42: The Toolbar button in BankAccountIndex is still using the
copied document-type action and label. Update handleDocumentTypeAdd, the route
target, and the Button title in BankAccountIndex so the toolbar action creates a
new bank account/bank connection instead of navigating to
app.setting.document_type.create, and make sure the displayed copy matches the
bank account context.

In `@resources/js/Pages/App/Setting/BankAccount/BankAccountIndexColumns.tsx`:
- Around line 16-24: The “Löschen” menu item in RowActions is currently
non-functional because MenuItem has no action handler and DropdownButton is not
wired to selection handling. Update RowActions in BankAccountIndexColumns to
either pass a delete callback to the MenuItem or add DropdownButton/menu
selection handling so clicking the delete entry triggers the intended delete
flow. Use the existing Row<App.Data.BankAccountData> row data to identify the
account, and hook the action into the surrounding bank account UI with
confirmation and request handling.

In `@routes/tenant/settings.php`:
- Line 72: The BankAccount store route is missing the same precognition
middleware used by other form-backed store/update routes, so a validation-only
request can still reach BankAccountController::store() and create a record.
Update the route definition for the bank-account create endpoint in
routes/tenant/settings.php to include HandlePrecognitiveRequests, matching the
other Precognition-enabled routes in this file, so Inertia form validation is
handled before the controller action runs.

---

Nitpick comments:
In `@app/Http/Controllers/App/Setting/BankAccountController.php`:
- Around line 35-57: The BankAccountController actions edit, update, and store
currently rely only on tenant scoping and do not explicitly authorize bank
account management. Add Laravel authorization checks using the existing
policy/gate pattern in these methods, ideally via authorize() or a dedicated
BankAccountPolicy, so only users permitted to manage bank accounts can access
BankAccountController::edit, BankAccountController::update, and
BankAccountController::store.

In `@resources/js/Pages/App/Setting/BankAccount/BankAccountEdit.tsx`:
- Around line 24-36: The form key passed to useForm in BankAccountEdit has an
odd typo-like separator sequence, so clean up the identifier to match the naming
pattern used by other forms. Update the first argument in
useForm<App.Data.BankAccountData> from the current BankAccountEdit key to a
consistent, readable form name while keeping the rest of the hook logic
unchanged.

In `@routes/tenant/settings.php`:
- Around line 68-73: The BankAccountController store route uses an inconsistent
POST path by pointing to the create endpoint instead of matching the app’s
established route patterns. Update the store route in the tenant settings routes
to follow the same convention used by other resources, either by using a /store
suffix or the collection URL, and keep the edit/create distinction aligned with
the existing bank_account route names and controller actions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e3e67fd2-9e5c-46e1-8d03-038f70072e02

📥 Commits

Reviewing files that changed from the base of the PR and between da2767b and 20af071.

📒 Files selected for processing (17)
  • app/Data/BankAccountData.php
  • app/Http/Controllers/App/ContactController.php
  • app/Http/Controllers/App/Setting/BankAccountController.php
  • app/Http/Requests/BankAccountRequest.php
  • app/Models/BankAccount.php
  • app/Services/ZugferdService.php
  • database/migrations/tenant/2026_07_01_205228_add_is_default_to_bank_accounts.php
  • database/seeders/TenantSeeder.php
  • resources/js/Components/AppSidebar.tsx
  • resources/js/Components/twc-ui/combo-box.tsx
  • resources/js/Hooks/use-twc-ui-form.ts
  • resources/js/Pages/App/Setting/BankAccount/BankAccountEdit.tsx
  • resources/js/Pages/App/Setting/BankAccount/BankAccountIndex.tsx
  • resources/js/Pages/App/Setting/BankAccount/BankAccountIndexColumns.tsx
  • resources/js/Types/generated.d.ts
  • resources/typescript-transformer-manifest.json
  • routes/tenant/settings.php
💤 Files with no reviewable changes (2)
  • database/seeders/TenantSeeder.php
  • app/Services/ZugferdService.php

Comment thread app/Data/BankAccountData.php Outdated
Comment thread app/Http/Controllers/App/Setting/BankAccountController.php Outdated
Comment thread app/Http/Controllers/App/Setting/BankAccountController.php Outdated
Comment thread app/Http/Requests/BankAccountRequest.php
Comment thread resources/js/Pages/App/Setting/BankAccount/BankAccountIndex.tsx
Comment thread resources/js/Pages/App/Setting/BankAccount/BankAccountIndex.tsx Outdated
Comment thread routes/tenant/settings.php Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
resources/js/Pages/App/Setting/BankAccount/BankAccountIndexColumns.tsx (1)

18-37: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

"Als Standardkonto setzen" bleibt klickbar, auch wenn das Konto bereits Default ist.

Der Menüeintrag ist unabhängig von row.original.is_default immer aktiv, was zu einem unnötigen router.put-Request führt, wenn das bereits Default-Konto erneut ausgewählt wird.

🔧 Vorschlag
 <MenuItem
   icon={CheckLineIcon}
   separator
   title="Als Standardkonto setzen"
+  isDisabled={row.original.is_default}
   onAction={() => setDefaultAccount(row.original)}
 />
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@resources/js/Pages/App/Setting/BankAccount/BankAccountIndexColumns.tsx`
around lines 18 - 37, In RowActions, the “Als Standardkonto setzen” MenuItem is
always enabled even when row.original.is_default is already true. Update the
action in BankAccountIndexColumns so the default-account entry is disabled or
omitted for the current default account, and keep setDefaultAccount from
triggering router.put for that case.
♻️ Duplicate comments (1)
app/Data/BankAccountData.php (1)

18-29: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Generierte TS-Typen (generated.d.ts) sind nach dieser Änderung veraltet – über bookkeeping_account_id hinaus.

Laut Kontext-Snippet deklariert resources/js/Types/generated.d.ts weiterhin name: string, iban: string, bic: string, pos: number, is_default: boolean, is_paypal: boolean, is_closed: boolean – alles nicht-nullable. Der PHP-Data-Constructor macht diese Felder jetzt aber (?string/?int/?bool) nullable. Das betrifft nicht nur das bereits früher gemeldete bookkeeping_account_id, sondern praktisch den gesamten Vertrag. Konsumierende TSX-Dateien (BankAccountIndexColumns.tsx) gehen von nicht-null Werten aus, was bei zukünftigem Code (z. B. String-Methoden auf name) zu Laufzeitfehlern führen kann, obwohl TS es als sicher ausweist.

Die generierten Typen sollten nach der Datenvertragsänderung neu generiert werden (z. B. via spatie/laravel-typescript-transformer).

🔧 Empfehlung

Typegenerator erneut laufen lassen, damit generated.d.ts mit app/Data/BankAccountData.php synchron ist.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/Data/BankAccountData.php` around lines 18 - 29, The BankAccountData
constructor now makes several fields nullable, so the generated TypeScript
contract is stale beyond bookkeeping_account_id. Regenerate
resources/js/Types/generated.d.ts from app/Data/BankAccountData.php so all
affected props (including name, iban, bic, pos, is_default, is_paypal, and
is_closed) reflect the new nullable types, and then update any consumers like
BankAccountIndexColumns.tsx to handle possible null values safely.
🧹 Nitpick comments (1)
resources/js/Pages/App/Setting/BankAccount/BankAccountIndex.tsx (1)

41-44: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Veralteter Kommentar aus Copy & Paste passt nicht zur Logik.

// Nur Pagination rendern, wenn cost_centers existiert bezieht sich auf cost_centers, nicht bank_accounts, und beschreibt eine Bedingung, die im Code gar nicht existiert (Pagination wird immer gerendert).

✏️ Vorschlag
   const footer = useMemo(() => {
-    // Nur Pagination rendern, wenn cost_centers existiert
     return <Pagination data={bank_accounts} />
   }, [bank_accounts])
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@resources/js/Pages/App/Setting/BankAccount/BankAccountIndex.tsx` around lines
41 - 44, The inline comment in BankAccountIndex’s footer useMemo is stale and
mentions cost_centers even though the logic renders Pagination for bank_accounts
unconditionally. Update the comment to accurately describe the current
BankAccountIndex footer behavior, or remove it if it no longer adds value, so it
matches the Pagination render in useMemo.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/Http/Controllers/App/Setting/BankAccountController.php`:
- Around line 63-79: The validated pos field is being dropped because
BankAccount::create and BankAccount::update use mass assignment but BankAccount
does not allow pos yet. Update the BankAccount model’s $fillable to include pos
so the existing store() and update() flows in BankAccountController can persist
the sort order correctly.
- Around line 56-61: The destroy() method in BankAccountController currently
deletes any BankAccount without checking whether it is the default account,
which can leave the system with no default account even when others still exist.
Update destroy() to guard against deleting a bank account when
BankAccount::is_default is true, and if deletion is allowed, ensure another
remaining account is promoted to default when needed. Use the destroy() action
and the BankAccount model’s is_default field to locate the change.
- Around line 47-54: The setDefault() flow in BankAccountController is not
atomic and can leave the default account inconsistent under concurrent requests.
Wrap the reset and assignment steps in a single database transaction, and use
row locking or another concurrency-safe approach around the affected BankAccount
records so only one account can be default at a time. Keep the logic centered in
setDefault() and the BankAccount update sequence to ensure both updates succeed
or fail together.

In `@resources/js/Pages/App/Setting/BankAccount/BankAccountIndexColumns.tsx`:
- Around line 39-48: The confirmation text in deleteBankAccount uses the wrong
German article for Bankkonto. Update the AlertDialog.call message in
BankAccountIndexColumns so it says "das Bankkonto" instead of "den Bankkonto"
while keeping the rest of the deleteBankAccount flow unchanged.

---

Outside diff comments:
In `@resources/js/Pages/App/Setting/BankAccount/BankAccountIndexColumns.tsx`:
- Around line 18-37: In RowActions, the “Als Standardkonto setzen” MenuItem is
always enabled even when row.original.is_default is already true. Update the
action in BankAccountIndexColumns so the default-account entry is disabled or
omitted for the current default account, and keep setDefaultAccount from
triggering router.put for that case.

---

Duplicate comments:
In `@app/Data/BankAccountData.php`:
- Around line 18-29: The BankAccountData constructor now makes several fields
nullable, so the generated TypeScript contract is stale beyond
bookkeeping_account_id. Regenerate resources/js/Types/generated.d.ts from
app/Data/BankAccountData.php so all affected props (including name, iban, bic,
pos, is_default, is_paypal, and is_closed) reflect the new nullable types, and
then update any consumers like BankAccountIndexColumns.tsx to handle possible
null values safely.

---

Nitpick comments:
In `@resources/js/Pages/App/Setting/BankAccount/BankAccountIndex.tsx`:
- Around line 41-44: The inline comment in BankAccountIndex’s footer useMemo is
stale and mentions cost_centers even though the logic renders Pagination for
bank_accounts unconditionally. Update the comment to accurately describe the
current BankAccountIndex footer behavior, or remove it if it no longer adds
value, so it matches the Pagination render in useMemo.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 7942072d-a050-4f53-a4e3-3ddb07889ff5

📥 Commits

Reviewing files that changed from the base of the PR and between 20af071 and bdda230.

📒 Files selected for processing (7)
  • app/Data/BankAccountData.php
  • app/Http/Controllers/App/Setting/BankAccountController.php
  • database/migrations/tenant/2026_07_01_205228_add_is_default_to_bank_accounts.php
  • resources/js/Components/AppSidebar.tsx
  • resources/js/Pages/App/Setting/BankAccount/BankAccountIndex.tsx
  • resources/js/Pages/App/Setting/BankAccount/BankAccountIndexColumns.tsx
  • routes/tenant/settings.php
🚧 Files skipped from review as they are similar to previous changes (2)
  • database/migrations/tenant/2026_07_01_205228_add_is_default_to_bank_accounts.php
  • resources/js/Components/AppSidebar.tsx

Comment thread app/Http/Controllers/App/Setting/BankAccountController.php
Comment on lines +56 to +61
public function destroy(BankAccount $bank_account): RedirectResponse
{
$bank_account->delete();

return redirect()->route('app.bookkeeping.bank-account.index');
}

@coderabbitai coderabbitai Bot Jul 1, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Löschen des Default-Kontos hinterlässt kein Default-Konto.

destroy() löscht unabhängig davon, ob $bank_account->is_default gesetzt ist. Danach existiert ggf. kein Default-Konto mehr, obwohl weitere Konten vorhanden sind.

🔧 Vorschlag
 public function destroy(BankAccount $bank_account): RedirectResponse
 {
+    $wasDefault = $bank_account->is_default;
     $bank_account->delete();
+
+    if ($wasDefault) {
+        BankAccount::query()->first()?->update(['is_default' => true]);
+    }

     return redirect()->route('app.bookkeeping.bank-account.index');
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public function destroy(BankAccount $bank_account): RedirectResponse
{
$bank_account->delete();
return redirect()->route('app.bookkeeping.bank-account.index');
}
public function destroy(BankAccount $bank_account): RedirectResponse
{
$wasDefault = $bank_account->is_default;
$bank_account->delete();
if ($wasDefault) {
BankAccount::query()->first()?->update(['is_default' => true]);
}
return redirect()->route('app.bookkeeping.bank-account.index');
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/Http/Controllers/App/Setting/BankAccountController.php` around lines 56 -
61, The destroy() method in BankAccountController currently deletes any
BankAccount without checking whether it is the default account, which can leave
the system with no default account even when others still exist. Update
destroy() to guard against deleting a bank account when BankAccount::is_default
is true, and if deletion is allowed, ensure another remaining account is
promoted to default when needed. Use the destroy() action and the BankAccount
model’s is_default field to locate the change.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Standardkonto kann in Aktualisierung nicht mehr gelöscht werden

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
fd -a BankAccountController.php | xargs cat -n

Length of output: 3394


🏁 Script executed:

#!/bin/bash
fd -a BankAccountIndexColumns.tsx | xargs cat -n

Length of output: 4117


Confirmed: no client-side or server-side guard against deleting a default bank account currently exists — destroy() (Lines 56-61) still unconditionally deletes, and BankAccountIndexColumns.tsx's RowActions shows the "Löschen" option regardless of is_default.

@dspangenberg, danke für den Hinweis, aber ich sehe die Änderung noch nicht in der aktuellen Version. In app/Http/Controllers/App/Setting/BankAccountController.php (Line 58) ruft destroy() weiterhin unbedingt $bank_account->delete() auf, und in resources/js/Pages/App/Setting/BankAccount/BankAccountIndexColumns.tsx bietet RowActions den „Löschen“-Menüpunkt unabhängig von is_default an — es gibt also weder client- noch serverseitig eine Sperre.

Falls die Änderung in einem separaten/späteren Commit erfolgt, gerne nochmal Bescheid geben, dann prüfe ich das erneut. Ansonsten könnte z. B. so eine serverseitige Sperre aussehen:

public function destroy(BankAccount $bank_account): RedirectResponse
{
    if ($bank_account->is_default) {
        return redirect()
            ->route('app.bookkeeping.bank-account.index')
            ->with('error', 'Das Standardkonto kann nicht gelöscht werden.');
    }

    $bank_account->delete();

    return redirect()->route('app.bookkeeping.bank-account.index');
}

Ergänzend könnte man den „Löschen“-Menüpunkt im Frontend für das Standardkonto deaktivieren/ausblenden, um dem Nutzer direktes Feedback zu geben.

(ᵔ◡ᵔ) neugierig, ob die Änderung noch aussteht


🧠 Learnings used
Learnt from: dspangenberg
Repo: dspangenberg/opsc PR: 337
File: routes/tenant.php:148-152
Timestamp: 2026-03-05T19:36:23.252Z
Learning: Ensure POSTAL_PUBLIC_KEY in .env is a full PEM-formatted RSA public key (BEGIN PUBLIC KEY and END PUBLIC KEY with proper newlines). Since Laravel does not preserve literal newlines in env values, store the key with real newline characters in .env (quoted) or convert on read (e.g., in config/services.php use str_replace('\n', "\n", env('POSTAL_PUBLIC_KEY'))). The key is derived from the Postal DKIM key via the p= value from postal default-dkim-record. Apply this guidance wherever the key is read in PHP (notably in Laravel config) to ensure the PEM is valid.

Learnt from: dspangenberg
Repo: dspangenberg/opsc PR: 339
File: app/Enums/InboxEntryStatus.php:7-9
Timestamp: 2026-03-05T22:26:43.349Z
Learning: Enforce enum case naming in PHP projects: use UPPER_SNAKE_CASE for enum case keys (e.g., PENDING, ACCEPTED, REJECTED). TitleCase should not be used for enum cases. This applies globally to PHP files in the repository (e.g., app/Enums/InboxEntryStatus.php and similar).

Learnt from: dspangenberg
Repo: dspangenberg/opsc PR: 532
File: app/Http/Controllers/App/DocumentController.php:188-190
Timestamp: 2026-06-27T21:21:56.106Z
Learning: When reviewing issues related to blank OCR output, ensure you check all OCR-based fulltext extraction entry points in this codebase: (1) `app/Http/Controllers/App/DocumentController.php::runOCR()`, (2) `app/Services/DocumentUploadService.php::upload()` where OCR is used as a fallback when parsed PDF text is blank, and (3) `app/Services/MultidocService.php` where `App\facades\OcrService::run()` may be called before dispatching `App\Jobs\DocumentUploadJob`. Findings about blank OCR output should be evaluated across these three paths, not just `runOCR()`.

Comment thread app/Http/Controllers/App/Setting/BankAccountController.php
@dspangenberg dspangenberg merged commit f0cf750 into main Jul 1, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant