Commit Graph

117 Commits

Author SHA1 Message Date
Darko Gjorgjijoski
2af31d0e5f Rename local_public disk back to public and store avatars/logos on public disk
The public disk was accidentally removed during the Laravel 11 upgrade
and re-added as local_public in the FileDisk refactor. Restoring the
standard Laravel name avoids breaking Spatie MediaLibrary expectations
and simplifies the v2-to-v3 upgrade path.

User avatars and company logos now explicitly use the public disk via
registerMediaCollections(), keeping them web-accessible while the default
media disk remains private for sensitive documents like PDFs and receipts.

The v3 upgrade migration renames the system disk entry and any alpha media
records from local_public back to public.
2026-04-10 15:56:31 +02:00
Darko Gjorgjijoski
42ce99eeba Show common currencies first in dropdowns and default to USD in install wizard
Currency dropdowns now display the most-traded currencies (USD, EUR, GBP,
JPY, CAD, AUD, CHF, CNY, INR, BRL) at the top, followed by the rest
alphabetically. The install wizard defaults to USD instead of EUR and
formats currency names as "USD - US Dollar" for consistency with the
rest of the app.
2026-04-10 15:55:46 +02:00
Darko Gjorgjijoski
20085cab5d Refactor FileDisk system with per-disk unique names and disk assignments UI
Major changes to the file disk subsystem:

- Each FileDisk now gets a unique Laravel disk name (disk_{id}) instead
  of temp_{driver}, fixing the bug where multiple local disks with
  different roots overwrote each other's config.

- Move disk registration logic from FileDisk model to FileDiskService
  (registerDisk, getDiskName). Model keeps only getDecodedCredentials
  and a deprecated setConfig() wrapper.

- Add Disk Assignments admin UI (File Disk tab) with three purpose
  dropdowns: Media Storage, PDF Storage, Backup Storage. Stored as
  settings (media_disk_id, pdf_disk_id, backup_disk_id).

- Backup tab now uses the assigned backup disk instead of a per-backup
  dropdown. BackupsController refactored to use BackupService which
  centralizes disk resolution. Removed stale 4-second cache.

- Add local_public disk to config/filesystems.php so system disks
  are properly defined.

- Local disk roots stored relative to storage/app/ with hint text
  in the admin modal explaining the convention.

- Fix BaseModal watchEffect -> watch to prevent infinite request
  loops on the File Disk page.

- Fix string/number comparison for disk purpose IDs from settings.

- Add safeguards: prevent deleting disks with files, warn on
  purpose change, prevent deleting system disks.
2026-04-07 02:04:57 +02:00
Darko Gjorgjijoski
67268ac2b7 Secure expense receipts by wiring Media Library to FileDisk
Spatie Media Library now uses the default FileDisk (local_private) for
new uploads instead of the public disk. Expense receipts are no longer
directly web-accessible.

- AppServiceProvider configures media-library disk from FileDisk on boot
- Change media-library fallback from 'public' to 'local'
- Expense receipt URL accessor returns authenticated route instead of
  direct file URL
- Add registerMediaCollections() to Expense model
- Prevent deleting FileDisk that contains files or is a system disk
- Add media:secure command to migrate existing receipts to private disk

Fixes #187
2026-04-07 01:01:59 +02:00
Darko Gjorgjijoski
631d838834 Fix recurring invoices using wrong date in non-UTC timezones
Pass the app's configured timezone to CronExpression::getNextRunDate()
so the next invoice date is calculated in the correct timezone instead
of defaulting to UTC.

Fixes #491
2026-04-06 23:38:55 +02:00
Darko Gjorgjijoski
9ca998e64a Add Convert to Estimate feature for invoices
New backend endpoint POST /invoices/{id}/convert-to-estimate that
creates a draft estimate from an invoice, copying items, taxes,
custom fields, and financial data. Frontend wired with dropdown
action, store method, and API service call.
2026-04-06 22:57:03 +02:00
Darko Gjorgjijoski
74b4b2df4e Finalize Typescript restructure 2026-04-06 17:59:15 +02:00
Darko Gjorgjijoski
afbc6c1db3 Handle no-company user in ScopeBouncer middleware and User model
Skip bouncer scoping when user has no companies instead of crashing
on null. Fall back to Y-m-d date format in getFormattedCreatedAtAttribute
when no company settings are available.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 00:12:00 +02:00
Darko Gjorgjijoski
92a1baced4 Add company invitation system (backend)
New feature allowing company owners/admins to invite users by email with
a specific company-scoped role.

Database:
- New company_invitations table (company_id, email, role_id, token,
  status, invited_by, expires_at)

Backend:
- CompanyInvitation model with pending/forUser scopes
- InvitationService: invite, accept, decline, getPendingForUser
- CompanyInvitationMail with markdown email template
- InvitationController (company-scoped): list, send, cancel invitations
- InvitationResponseController (user-scoped): pending, accept, decline
- BootstrapController returns pending_invitations in response
- CompanyMiddleware handles zero-company users gracefully

Tests: 9 feature tests covering invite, accept, decline, cancel, expire,
duplicate prevention, and bootstrap integration.
2026-04-03 22:58:55 +02:00
Darko Gjorgjijoski
e9ee74cd01 Add return types and typed parameters to remaining 10 models
Complete the type modernization across all models. Adds Builder-typed
$query parameters and return types to all scope methods, typed parameters
on accessors, and PHPDoc on scopePaginateData/scopeApplyFilters.

Models updated: Address, EstimateItem, Expense, ExpenseCategory,
InvoiceItem, Item, Note, Tax, TaxType, Unit.

5 models needed no changes (Country, Currency, ImpersonationLog,
Module, UserSetting) as they had no untyped public methods.
2026-04-03 20:53:41 +02:00
Darko Gjorgjijoski
0fa1aac748 Add return types, typed parameters, and PHPDoc to all model methods
Modernize all 16 models with missing type declarations:
- Return types on ~87 methods (string, bool, void, array, mixed, etc.)
- Typed parameters where missing
- PHPDoc blocks on non-obvious methods explaining their purpose

Models updated: Invoice, Estimate, Payment, User, Company, Customer,
RecurringInvoice, Setting, CompanySetting, FileDisk, Transaction,
EmailLog, ExchangeRateLog, PaymentMethod, CustomField, CustomFieldValue.
2026-04-03 20:46:26 +02:00
Darko Gjorgjijoski
c794f92932 Remove unused model constants
- Company: COMPANY_LEVEL, CUSTOMER_LEVEL (never referenced)
- Payment: all 5 PAYMENT_MODE_* constants (never referenced)
- Transaction: PENDING (never referenced)

RecurringInvoice constants (ACTIVE, ON_HOLD, NONE, COUNT, DATE) are kept
as they are used via hardcoded strings in services, factories, and migrations.
2026-04-03 20:39:21 +02:00
Darko Gjorgjijoski
c90dd1f2ac Remove dead model methods now handled by services
Remove createItem/updateItem from Item, createTransaction/
completeTransaction/failedTransaction from Transaction,
createCustomField/updateCustomField from CustomField, all business
methods from ExchangeRateProvider (CRUD + API checks + URL helpers),
and validateCredentials/createDisk/updateDisk/updateDefaultDisks/
setAsDefaultDisk from FileDisk.

All logic now lives in their respective service classes.
2026-04-03 20:32:02 +02:00
Darko Gjorgjijoski
0ce88ab817 Remove app/Space folder and extract model business logic into services
Relocate all 14 files from the catch-all app/Space namespace into proper
locations: data providers to Support/Formatters, installation utilities to
Services/Installation, PDF utils to Services/Pdf, module/update classes to
Services/Module and Services/Update, SiteApi trait to Traits, and helpers
to Support.

Extract ~1,400 lines of business logic from 8 fat models (Invoice, Payment,
Estimate, RecurringInvoice, Company, Customer, Expense, User) into 9 new
service classes with constructor injection. Controllers now depend on
services instead of calling static model methods. Shared item/tax creation
logic consolidated into DocumentItemService.
2026-04-03 15:37:22 +02:00
Darko Gjorgjijoski
23ff69026e Merge branch 'master' into v3.0 2026-04-03 14:36:24 +02:00
Darko Gjorgjijoski
7d9fdb79cc Scope users listing and search to current company (#607)
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
2026-04-03 14:34:33 +02:00
Darko Gjorgjijoski
c469f64c79 Remove unused CompanySetting defaults from company setup
Remove invoice_auto_generate, payment_auto_generate, estimate_auto_generate
(defined but never read anywhere in the codebase) and duplicate save_pdf_to_disk
entries (now a global Setting, not per-company).
2026-04-03 10:36:48 +02:00
Darko Gjorgjijoski
9432da467e Add super-admin Administration section and restructure global vs company settings
- Add Administration sidebar section (super-admin only) with Companies, Users, and Global Settings pages
- Add super-admin middleware, controllers, and API routes under /api/v1/super-admin/
- Allow super-admins to manage all companies and users across tenants
- Add user impersonation with short-lived tokens, audit logging, and UI banner
- Move system-level settings (Mail, PDF, Backup, Update, File Disk) from per-company to Administration > Global Settings
- Convert save_pdf_to_disk from CompanySetting to global Setting
- Add per-company mail configuration overrides (optional, falls back to global)
- Add CompanyMailConfigService to apply company mail config before sending emails
2026-04-03 10:35:40 +02:00
mchev
030c13b67a Merge pull request #578 from mchev/updates
Laravel 13 upgrade, security updates and fixes
2026-03-24 06:36:47 +01:00
mchev
07757e747e Addresses SSRF risk 2026-03-21 19:14:51 +01:00
mchev
c901114fc0 Pint 2026-03-21 18:59:53 +01:00
mchev
186ab35fd4 Laravel 13 upgrade, updates and fixes 2026-03-21 18:53:33 +01:00
klittle81
fc05cf61fa Patch to update reciept PDF generated by payment.blade.php to include Invoice Total, Balance Due, and Invoice Status 2026-02-27 22:06:27 -05:00
Abdulrazzaq Alhendi
65d1fdd3f0 feat(mail): add CC and BCC fields to email requests and forms (#466)
* feat(mail): add CC and BCC fields to email requests and forms

* chore: fmt
2026-02-06 01:59:38 +01:00
Darko Gjorgjijoski
18d63a3375 Configurations cleanup & database configurations for mail and pdfs (#479)
* Move Mail, PDF configuration to Database, standardize configurations

* Set default currency to USD on install

* Pint code
2025-09-19 15:42:53 +02:00
Fabio Ribeiro
73d4ac1eb1 fix: Payment confirmation error (#376)
Error caused when using Payments module, when try Stripe redirects back
to InvoiceShelf, and the module calls the InvoiceShelf `generatePayment`.

Relates #369
2025-06-11 22:56:56 +02:00
mchev
bf5b544ca3 Adding Flat Tax support with fixed amount (#253)
* 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
2025-05-04 02:24:56 +02:00
Darko Gjorgjijoski
546f75d3a6 Pint updated files (#367) 2025-05-04 02:23:51 +02:00
Tim van Osch
bf40f792c2 Feat(Gotenberg): Opt-in alternative pdf generation for modern CSS (#184)
* WIP(gotenberg): add pdf generation abstraction and UI

* feat(pdf): settings validate(clien+server) & save

* fix(gotenberg): Use correct default papersize
chore(gotengberg): Remove unused GOTENBERG_MARGINS env from .env

* style(gotenberg): fix linter/styling issues

* fix(pdf): use pdf config policy

* fix: revert accidental capitalization in mail config vue

* Update composer, remove whitespace typo

* Fix small typos

* fix cookie/env issue

* Add gotenberg to .dev, move admin menu item up
2025-05-04 02:10:15 +02:00
Darko Gjorgjijoski
d862ee05e9 Refactor Custom Invoice/Estimate PDF Templates (#277)
* 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
2025-01-13 01:20:13 +01:00
Darko Gjorgjijoski
e9e52c60a7 Reformat with pint 2025-01-12 18:37:08 +01:00
Darko Gjorgjijoski
c617f7d169 Fix: PDF Template command (#272)
* Fix `make:template` command

* Fix issue related to Vite assets

* Reformat code

---------

Co-authored-by: Steven Rombauts <steven@kotuha.be>
2025-01-12 16:19:54 +01:00
Darko Gjorgjijoski
f52b73f517 Invoice time support (#269)
* Changed invoice date to datetime

* Fixed code style errors

* Update TimeFormatsController.php

* Update TimeFormatter.php

* Update TimeFormatsController namespace

* Fix missing comma in language file

* Fix formatting

---------

Co-authored-by: troky <troky2001@yahoo.com>
2025-01-12 13:32:47 +01:00
OniriCorpe
a32bbb6268 Fixes receipt view (#234)
The #185 modifications were also necessary here
2024-12-03 15:26:05 +01:00
mchev
967c225df9 Merge pull request #198 from mchev/invoice_cancellation
Support for Zero and Negative Item Quantities on Invoices
2024-11-02 12:20:55 +01:00
mchev
134c99369e Merge pull request #186 from mchev/issue_181
Fix table data not refreshing properly (keys)
2024-11-02 10:28:12 +01:00
mchev
33c2949a7b Fix carbon int val (#185) 2024-10-15 20:51:17 +02:00
Martin Chevignard
59b43fa258 Public Invoice View fix 2024-10-15 17:55:56 +02:00
Martin Chevignard
168b741936 Upadate filters with laravel best practices 2024-10-15 16:20:04 +02:00
Darko Gjorgjijoski
50613fcff0 Remove unecessary debug calls 2024-08-04 19:50:14 +02:00
Darko Gjorgjijoski
468aec6bc1 Fix partially paid status appearing after invoice update 2024-08-04 19:45:08 +02:00
mchev
9fcf3792c7 Translate recurring invoice subject (#110)
* Translate recurring invoice subject
2024-06-25 19:44:23 +02:00
agencetwogether
3b61440e1f Complete dashboard translations & small UI improvements (#69)
* fix dropdown action Estimate Dashboard and fix translating full Dasboard page

* Update app.php

* fix locale in app.php config

* Wizard install with translation, customer portal with translation, and fixing hardcoding strings to get translation

* fixes asked to review

* fixes pint

---------

Co-authored-by: Max <contact@agencetwogether.fr>
Co-authored-by: Darko Gjorgjijoski <5760249+gdarko@users.noreply.github.com>
2024-06-05 12:07:46 +02:00
mchev
3259173066 Laravel 11 (#84)
* Convert string references to `::class`

PHP 5.5.9 adds the new static `class` property which provides the fully qualified class name. This is preferred over using strings for class names since the `class` property references are checked by PHP.

* Use Faker methods

Accessing Faker properties was deprecated in Faker 1.14.

* Convert route options to fluent methods

Laravel 8 adopts the tuple syntax for controller actions. Since the old options array is incompatible with this syntax, Shift converted them to use modern, fluent methods.

* Adopt class based routes

* Remove default `app` files

* Shift core files

* Streamline config files

* Set new `ENV` variables

* Default new `bootstrap/app.php`

* Re-register HTTP middleware

* Consolidate service providers

* Re-register service providers

* Re-register routes

* Re-register scheduled commands

* Bump Composer dependencies

* Use `<env>` tags for configuration

`<env>` tags have a lower precedence than system environment variables making it easier to overwrite PHPUnit configuration values in additional environments, such a CI.

Review this blog post for more details on configuration precedence when testing Laravel: https://jasonmccreary.me/articles/laravel-testing-configuration-precedence/

* Adopt anonymous migrations

* Rename `password_resets` table

* Convert `$casts` property to method

* Adopt Laravel type hints

* Mark base controller as `abstract`

* Remove `CreatesApplication` testing trait

* Shift cleanup

* Fix shift first issues

* Updating Rules for laravel 11, sanctum config and pint

* Fix Carbon issue on dashboard

* Temporary fix for tests while migration is issue fixed on laravel side

* Carbon needs numerical values, not strings

* Minimum php version

* Fix domain installation step not fetching the correct company_id

* Fix Role Policy wasn't properly registered

---------
2024-06-05 11:33:52 +02:00
Darko Gjorgjijoski
36424bbf05 Update code style 2024-02-08 03:37:17 +01:00
Darko Gjorgjijoski
e14a248f24 Fix: Status set incorrectly after updating invoice
Issue: https://github.com/crater-invoice/crater/issues/955, #23
2024-02-08 03:09:56 +01:00
gdarko
4ab92473e9 Setup pint & run code style fix 2024-01-29 04:46:01 -06:00
gdarko
cd63aa507a Fix payment note Amount field display
Pull: https://github.com/crater-invoice/crater/pull/1151 / Issue: https://github.com/crater-invoice/crater/issues/1127
2024-01-29 02:23:36 -06:00
Darko Gjorgjijoski
cd9df54c5b Upgrade to Laravel 10, Vite 5+ 2024-01-28 17:17:32 +01:00
Darko Gjorgjijoski
650644df0a Update other old references 2024-01-28 00:35:15 +01:00