Add expenses.uncategorized and pdf_expense_group_total_label; use the new key
in the grouped expense template; document View|Response instead of JsonResponse.
Made-with: Cursor
Add scopeWhereCompany() to User model using whereHas through the
user_company pivot table. Apply it in UsersController::index() and
SearchController so users only see members of their current company.
Previously, the users page showed ALL users across all companies.
Ref #574
Verify the source record belongs to the current company before cloning.
Previously, users could clone invoices/estimates from other companies,
leaking sensitive data (amounts, customer details, items, taxes, notes).
The view policy already includes hasCompany() check, so authorizing
view on the source record gates both ability and company ownership.
Ref #574
Bulk delete: filter IDs through whereCompany() before deleting in all
controllers (Invoices, Payments, Items, Expenses, Estimates, Recurring
Invoices). Previously, any user could delete records from other companies
by providing cross-company IDs.
Transfer ownership: fix inverted hasCompany() check that allowed
transferring company ownership to users who do NOT belong to the company,
while blocking users who DO belong.
Ref #567
* Fix CustomerPolicy missing hasCompany() check (cross-company IDOR)
Add $user->hasCompany($customer->company_id) check to view, update,
delete, restore, and forceDelete methods in CustomerPolicy, matching
the pattern used by all other policies (InvoicePolicy, PaymentPolicy,
EstimatePolicy, etc.).
Without this check, a user in Company A with view-customer ability
could access customers belonging to Company B by providing the target
customer's ID.
Add cross-company authorization tests to verify the fix.
Closes#565
* Scope bulk delete to current company to prevent cross-company deletion
Filter customer IDs through whereCompany() before passing to
deleteCustomers(), ensuring users cannot delete customers belonging
to other companies via the bulk delete endpoint.
* docs: add CLAUDE.md for Claude Code guidance
* fix: handle missing settings table in installation middlewares
RedirectIfInstalled crashed with "no such table: settings" when the
database_created marker file existed but the database was empty.
Changed to use isDbCreated() which verifies actual tables, and added
try-catch around Setting queries in both middlewares.
* feat: pre-select database driver from env in installation wizard
The database step now reads DB_CONNECTION from the environment and
pre-selects the matching driver on load, including correct defaults
for hostname and port.
* feat: pre-select mail driver and config from env in installation wizard
The email step now fetches the current mail configuration on load
instead of hardcoding the driver to 'mail'. SMTP fields fall back
to Laravel config values from the environment.
* refactor: remove file-based DB marker in favor of direct DB checks
The database_created marker file was a second source of truth that
could drift out of sync with the actual database. InstallUtils now
checks the database directly via Schema::hasTable which is cached
per-request and handles all error cases gracefully.
Three bugs prevented backups stored on remote disks (Dropbox, S3, etc.)
from ever appearing in the Settings > Backup listing:
1. Typo in BackupSetting.vue: `filed_disk_id` was sent to the API
instead of `file_disk_id`, so the backend never received the selected
disk ID and always fell back to the local filesystem.
2. Wrong default disk selection in loadDisksData(): `set_as_default == 0`
selected the first disk that is NOT default (local_public), instead of
the disk that IS default. Changed to `set_as_default == 1` with a
fallback to the first disk.
3. BackupsController::index() did not call setConfig() on the FileDisk
before querying backups, so even when the correct file_disk_id arrived
it still read from the default local filesystem. Added the same disk
bootstrap logic already present in CreateBackupJob and destroy().
Made-with: Cursor
* Update CustomersController.php
Fix: replace GROUP BY + SUM join with withSum() to avoid ONLY_FULL_GROUP_BY; no API changes (same aliases)
* Update CustomersController.php
style: apply Laravel Pint formatting
* Upgrade the mail configuration
* Update mail configuration to match Laravel 12
* Update mail configuration to properly set none or null
* Pint code
* Upgrade Symfony Mailers
Previously, the customer chart used the total/amount fields to calculate net profits/expenses/etc.
If the currency the expense (for example) was created in differed from the base currency of the company, the chart would display wrong amounts.
This change addresses the issue by always using the base currency field.
* feat: Tax included
* Added a toggle switch in tax settings to enable the feature.
* Database migration adding tax_included field into estimates, invoices
and recurring invoices table.
* Toggle switch to enable and store the tax_included by estimates,
invoices and recurring invoices.
* In case of tax included enabled, total taxes will be recalculated and
the invoices, estimates and recurring invoices total won't be sum with
taxes.
* Apply tax included when discount_per_item/tax_per_item item is enabled.
* Custom component to show the net total when tax included is enabled.
* Update invoice and estimates pdfs with net total.
* chore: Tax included by default
A switch button inside the tax settings to enable the tax included by
default in invoices, estimates and recurring invoices.
* Possibility to set a fixed amount on tax types settings
* Pint and manage flat taxes on items
* Fix display errors and handle global taxes
* Tests
* Pint with PHP 8.2 cause with PHP 8.3 version it cause workflow error
* Merging percent and fixed amount into one column
* Now display the currency on SelectTaxPopup on fixed taxes
As reported on issue #357, the aws ses configuration was not able to
store because of the missing `ses` service config. Additionally was
added a `AWS Region` field to be used by the `ses`.
closes#357
* feat: default notes
* feat: include default invoice note in recurring invoice
* feat: use default export in tw config
* fix: test and naming
* fix: consistent ui for switch in note modal
* feat: little text improvements
* Add utility class for managing templates
* Register custom pdf template views location
* Update the make:template command to make use of PdfTemplateUtils
* Update PDF invoice/estimate template controllers
* Register pdf_templates filesystem disk
* Remove unused leftovers
* Reformat with pint
* Clone estimates
* Clone estimate test feature
* Resolve namespace
* Fix string to int for Carbon
* Fix homes routes and default queue key
* Move dropdown item below View and use the propper translation key