113 Commits

Author SHA1 Message Date
mchev
7e8f9e65fb Merge pull request #580 from InvoiceShelf/translations
New Crowdin updates
2026-03-24 12:27:36 +01:00
mchev
67739750ca Merge pull request #582 from mchev/master
Hot fix  #280
2026-03-24 12:26:27 +01:00
mchev
5f6a7b92bf Merge pull request #581 from swiffer/master
Import File facade in UpdateCommand
2026-03-24 12:26:00 +01:00
mchev
ff3cab570a Hot fix #280 2026-03-24 12:13:40 +01:00
Darko Gjorgjijoski
11024ddc38 Update source file en.json 2026-03-24 09:30:45 +01:00
Matthias Wirtz
71303a1050 Import File facade in UpdateCommand
Added use statement for File facade.
2026-03-24 08:03:53 +01:00
Darko Gjorgjijoski
3af0e83d26 New translations en.json (Serbian (Latin)) 2026-03-24 07:44:53 +01:00
Darko Gjorgjijoski
a866a26e9f New translations en.json (Swahili) 2026-03-24 07:44:52 +01:00
Darko Gjorgjijoski
154a4dc076 New translations en.json (Malay) 2026-03-24 07:44:51 +01:00
Darko Gjorgjijoski
7900e020f5 New translations en.json (Hindi) 2026-03-24 07:44:50 +01:00
Darko Gjorgjijoski
974efb36da New translations en.json (Latvian) 2026-03-24 07:44:49 +01:00
Darko Gjorgjijoski
45d84b8b3c New translations en.json (Estonian) 2026-03-24 07:44:48 +01:00
Darko Gjorgjijoski
fdfb46ed79 New translations en.json (Croatian) 2026-03-24 07:44:46 +01:00
Darko Gjorgjijoski
ddcef0fb2c New translations en.json (Thai) 2026-03-24 07:44:45 +01:00
Darko Gjorgjijoski
0254b16556 New translations en.json (Bengali) 2026-03-24 07:44:44 +01:00
Darko Gjorgjijoski
a9a52ca85f New translations en.json (Persian) 2026-03-24 07:44:43 +01:00
Darko Gjorgjijoski
708d880b52 New translations en.json (Indonesian) 2026-03-24 07:44:42 +01:00
Darko Gjorgjijoski
57406989d4 New translations en.json (Portuguese, Brazilian) 2026-03-24 07:44:41 +01:00
Darko Gjorgjijoski
5d7e46b026 New translations en.json (Vietnamese) 2026-03-24 07:44:39 +01:00
Darko Gjorgjijoski
8e034e59f8 New translations en.json (Urdu (Pakistan)) 2026-03-24 07:44:38 +01:00
Darko Gjorgjijoski
43951d4542 New translations en.json (Chinese Traditional) 2026-03-24 07:44:37 +01:00
Darko Gjorgjijoski
3cc0f41d8c New translations en.json (Chinese Simplified) 2026-03-24 07:44:36 +01:00
Darko Gjorgjijoski
5f34ae558c New translations en.json (Ukrainian) 2026-03-24 07:44:35 +01:00
Darko Gjorgjijoski
70d51d580d New translations en.json (Turkish) 2026-03-24 07:44:34 +01:00
Darko Gjorgjijoski
b7929672fb New translations en.json (Swedish) 2026-03-24 07:44:32 +01:00
Darko Gjorgjijoski
bd28849a9f New translations en.json (Albanian) 2026-03-24 07:44:31 +01:00
Darko Gjorgjijoski
4d21aadcd4 New translations en.json (Slovenian) 2026-03-24 07:44:30 +01:00
Darko Gjorgjijoski
373a824fdb New translations en.json (Slovak) 2026-03-24 07:44:29 +01:00
Darko Gjorgjijoski
a5d9a60d5c New translations en.json (Russian) 2026-03-24 07:44:28 +01:00
Darko Gjorgjijoski
2537b53506 New translations en.json (Portuguese) 2026-03-24 07:44:27 +01:00
Darko Gjorgjijoski
bbc2d2088a New translations en.json (Polish) 2026-03-24 07:44:25 +01:00
Darko Gjorgjijoski
5734a06ab3 New translations en.json (Norwegian) 2026-03-24 07:44:24 +01:00
Darko Gjorgjijoski
75a1038245 New translations en.json (Dutch) 2026-03-24 07:44:23 +01:00
Darko Gjorgjijoski
017691b7b1 New translations en.json (Macedonian) 2026-03-24 07:44:22 +01:00
Darko Gjorgjijoski
d4f8a40982 New translations en.json (Lithuanian) 2026-03-24 07:44:21 +01:00
Darko Gjorgjijoski
ebdee1e3f0 New translations en.json (Georgian) 2026-03-24 07:44:20 +01:00
Darko Gjorgjijoski
ce97a474f9 New translations en.json (Japanese) 2026-03-24 07:44:18 +01:00
Darko Gjorgjijoski
4ee3d0d129 New translations en.json (Italian) 2026-03-24 07:44:17 +01:00
Darko Gjorgjijoski
bd5abdec0e New translations en.json (Hungarian) 2026-03-24 07:44:16 +01:00
Darko Gjorgjijoski
995533974e New translations en.json (Hebrew) 2026-03-24 07:44:15 +01:00
Darko Gjorgjijoski
156e94f931 New translations en.json (Finnish) 2026-03-24 07:44:14 +01:00
Darko Gjorgjijoski
e38c4963ef New translations en.json (Greek) 2026-03-24 07:44:13 +01:00
Darko Gjorgjijoski
d7efbb5c47 New translations en.json (German) 2026-03-24 07:44:11 +01:00
Darko Gjorgjijoski
3cd219e7b3 New translations en.json (Danish) 2026-03-24 07:44:10 +01:00
Darko Gjorgjijoski
3d65a09038 New translations en.json (Czech) 2026-03-24 07:44:09 +01:00
Darko Gjorgjijoski
f52c376a49 New translations en.json (Catalan) 2026-03-24 07:44:08 +01:00
Darko Gjorgjijoski
5a7c1363ee New translations en.json (Bulgarian) 2026-03-24 07:44:07 +01:00
Darko Gjorgjijoski
2c40c2ef06 New translations en.json (Arabic) 2026-03-24 07:44:06 +01:00
Darko Gjorgjijoski
b5ff16c318 New translations en.json (Spanish) 2026-03-24 07:44:04 +01:00
Darko Gjorgjijoski
4d7b818d23 New translations en.json (French) 2026-03-24 07:44:03 +01:00
Darko Gjorgjijoski
b314ebc07f New translations en.json (Romanian) 2026-03-24 07:44:02 +01:00
mchev
254ed5ade0 Merge pull request #579 from mchev/upgrade_requirements
PHP8.4 requirement
2026-03-24 07:15:33 +01:00
mchev
40e4ea931e PHP8.4 requirement 2026-03-24 07:07:41 +01: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
28fedead6c Merge pull request #566 from InvoiceShelf/translations
New Crowdin updates
2026-03-24 06:14:11 +01:00
mchev
14ccce1934 Merge pull request #572 from klittle81/payment-pdf-invoice-details
Update receipt PDF to include Invoice Total, Balance Due, and Invoice Status
2026-03-24 06:13:15 +01:00
mchev
2d808f17bb Merge pull request #573 from csalzano/fix/dropbox-file-disk-creation
Bug fix in Dropbox file disk creation. Applies disk path.
2026-03-24 05:32:44 +01:00
mchev
6d227fa368 Merge pull request #554 from csalzano/fix/paginated-table-stale-response
Fix wrong customer names on invoice list page 2+
2026-03-23 20:18:26 +01:00
mchev
07757e747e Addresses SSRF risk 2026-03-21 19:14:51 +01:00
mchev
d4e19646ee fix(ci): install deps on PHP 8.4 (Symfony 8 requires >=8.4) 2026-03-21 19:03:37 +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
Darko Gjorgjijoski
c7485930a8 New translations en.json (Romanian) 2026-03-15 18:17:11 +01:00
Darko Gjorgjijoski
c7d06671d6 New translations en.json (Romanian) 2026-03-15 17:11:09 +01:00
Corey Salzano
b35bd0880a Bug fix in Dropbox file disk creation. Applies disk path. 2026-03-03 11:47:55 -05:00
klittle81
c70e2abf8a Apply suggestion from @klittle81
remove the <br> at end as its not needed
2026-02-27 22:43:40 -05: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
Rihards Simanovičs
48abd9020d docs(SECURITY.md): revise security vulnerability reporting instructions
Updated contact information to include GWS security email and added Discord outreach option for reporting vulnerabilities.
2026-02-27 16:35:06 +00:00
Darko Gjorgjijoski
9afd4011a6 New translations en.json (Hindi) 2026-02-25 12:16:09 +01:00
Corey Salzano
01528d9ebe Fix wrong customer names on invoice list page 2+
On the invoices list, when viewing page 2 or later, customer names in the
table could be wrong—opening an invoice showed a different customer than
the one displayed in that row.

Ensure we only apply API responses that match the currently requested page.
This prevents stale or out-of-order responses from overwriting the displayed
data. Also use row id as v-for key for correct Vue reconciliation.
2026-02-16 11:57:36 -05:00
Darko Gjorgjijoski
d20f1aa105 New Crowdin updates (#539)
* Update source file en.json

* New translations en.json (Slovak)

* New translations en.json (Romanian)

* New translations en.json (French)

* New translations en.json (Spanish)

* New translations en.json (Arabic)

* New translations en.json (Bulgarian)

* New translations en.json (Catalan)

* New translations en.json (Czech)

* New translations en.json (Danish)

* New translations en.json (German)

* New translations en.json (Greek)

* New translations en.json (Finnish)

* New translations en.json (Hebrew)

* New translations en.json (Hungarian)

* New translations en.json (Italian)

* New translations en.json (Japanese)

* New translations en.json (Georgian)

* New translations en.json (Lithuanian)

* New translations en.json (Macedonian)

* New translations en.json (Dutch)

* New translations en.json (Norwegian)

* New translations en.json (Polish)

* New translations en.json (Portuguese)

* New translations en.json (Russian)

* New translations en.json (Slovenian)

* New translations en.json (Albanian)

* New translations en.json (Swedish)

* New translations en.json (Turkish)

* New translations en.json (Ukrainian)

* New translations en.json (Chinese Simplified)

* New translations en.json (Chinese Traditional)

* New translations en.json (Urdu (Pakistan))

* New translations en.json (Vietnamese)

* New translations en.json (Portuguese, Brazilian)

* New translations en.json (Indonesian)

* New translations en.json (Persian)

* New translations en.json (Bengali)

* New translations en.json (Thai)

* New translations en.json (Croatian)

* New translations en.json (Estonian)

* New translations en.json (Latvian)

* New translations en.json (Hindi)

* New translations en.json (Malay)

* New translations en.json (Swahili)

* New translations en.json (Serbian (Latin))

* Update source file en.json
2026-02-08 17:34:06 +01: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
796f6f364a New Crowdin updates (#481)
* New translations en.json (Norwegian)

* New translations en.json (Croatian)

* New translations en.json (French)

* New translations en.json (Arabic)

* New translations en.json (Dutch)

* New translations en.json (Dutch)

* New translations en.json (Dutch)

* New translations en.json (Chinese Simplified)

* New translations en.json (Dutch)

* New translations en.json (Spanish)

* New translations en.json (German)

* New translations en.json (German)

* New translations en.json (Romanian)

* New translations en.json (Dutch)

* New translations en.json (Romanian)

* New translations en.json (Romanian)

* New translations en.json (Swedish)

* New translations en.json (Bulgarian)

* New translations en.json (Bulgarian)

* New translations en.json (Bulgarian)

* New translations en.json (Bulgarian)

* New translations en.json (Slovenian)

* New translations en.json (Slovenian)

* New translations en.json (Italian)

* New translations en.json (Bengali)

* New translations en.json (Slovak)
2026-02-06 01:53:49 +01:00
Radoš
61b345d473 chore: lang - cs.json (#490)
Wrong translation for tax_id
2026-02-06 01:44:03 +01:00
Darko Gjorgjijoski
a30b2e751b Pin PHP version to 8.4 in development Dockerfile 2026-02-06 00:57:13 +01:00
Devstack
af205acb75 Fix aggregates for customers using withSum() (SQL-portable, no DB mode tweaks) (#486)
* 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
2026-01-01 22:43:52 +01:00
Ahmed Ashraf
24546aea3c New currency: Qatari Riyal (#476)
* add qatari riyal currency to migration and seeder

* run pint
2026-01-01 17:50:31 +01:00
Darko
935fe06f9e Bump version 2025-09-19 15:50:54 +02: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
Darko Gjorgjijoski
3da86965e1 New Crowdin updates (#454)
* New translations en.json (French)

* New translations en.json (Norwegian)

* New translations en.json (Norwegian)

* New translations en.json (Norwegian)

* New translations en.json (Norwegian)

* New translations en.json (Norwegian)

* New translations en.json (Norwegian)

* New translations en.json (Italian)

* New translations en.json (Romanian)

* New translations en.json (French)

* New translations en.json (Spanish)

* New translations en.json (Arabic)

* New translations en.json (Bulgarian)

* New translations en.json (Catalan)

* New translations en.json (Czech)

* New translations en.json (German)

* New translations en.json (Greek)

* New translations en.json (Finnish)

* New translations en.json (Japanese)

* New translations en.json (Lithuanian)

* New translations en.json (Macedonian)

* New translations en.json (Dutch)

* New translations en.json (Norwegian)

* New translations en.json (Danish)

* New translations en.json (Hebrew)

* New translations en.json (Hungarian)

* New translations en.json (Georgian)

* New translations en.json (Polish)

* New translations en.json (Russian)

* New translations en.json (Slovak)

* New translations en.json (Slovenian)

* New translations en.json (Swedish)

* New translations en.json (Turkish)

* New translations en.json (Ukrainian)

* New translations en.json (Chinese Simplified)

* New translations en.json (Chinese Traditional)

* New translations en.json (Vietnamese)

* New translations en.json (Portuguese, Brazilian)

* New translations en.json (Indonesian)

* New translations en.json (Persian)

* New translations en.json (Thai)

* New translations en.json (Croatian)

* New translations en.json (Latvian)

* New translations en.json (Hindi)

* New translations en.json (Serbian (Latin))

* New translations en.json (Urdu (Pakistan))

* New translations en.json (Bengali)

* New translations en.json (Estonian)

* New translations en.json (Malay)

* New translations en.json (Swahili)

* New translations en.json (Portuguese)

* New translations en.json (Albanian)

* Update source file en.json
2025-09-13 16:42:20 +02:00
Darko Gjorgjijoski
5aa54dbd86 Fix docker asset url (#472) 2025-09-08 17:52:33 +02:00
Darko Gjorgjijoski
58b262fe32 Fix path to sqlite.empty.db in setup script 2025-09-08 14:19:59 +02:00
lupus
f8c4e63b3f Fix: broken file links for development files (#469)
* FIx broken file links for development files

* Fix: Compose Files Context / Paths / Networks
2025-09-07 14:16:39 +02:00
Darko Gjorgjijoski
78dfdbe162 Devenv subcommands for test / format (#462)
* Add devenv subcommands for test / format

* Rename dev-env-config to devenvconfig for consitency sake
2025-09-02 03:32:21 +02:00
Darko Gjorgjijoski
770da45dbf Production docker improvements (#463)
* Update production dockerfiles for testing

* Add bash, nano and remove unecessary sqlite3 alpine package
2025-09-02 03:27:26 +02:00
Christos Yiakoumettis
3e96297699 Add expense number at Expenses (#406)
* add expense number at expenses

* Re-order expense fields

* Rename expense_number migration

* Add expense_number to tests

---------

Co-authored-by: Darko Gjorgjijoski <dg@darkog.com>
2025-09-02 03:20:27 +02:00
Rihards Simanovičs
f3e49d3044 Temperately hide modules tab while Module Management is developed (#443)
* fix(navigation): temperately hide modules tab while Module Management is developed

* chore run pint
2025-09-02 01:30:53 +02:00
Darko Gjorgjijoski
05ab78942c Update JS dependencies 2025-09-01 20:58:43 +02:00
Rihards Simanovičs
827436af15 chore: Ignore devcontainer dir (#460) 2025-09-01 13:00:38 +02:00
Darko Gjorgjijoski
233d3cb989 Update readme.md 2025-09-01 12:07:15 +02:00
Darko Gjorgjijoski
8842d6a626 Development Environment (#459)
* Fix SQLite docker build related issues

* Add devenv for development
2025-09-01 11:47:58 +02:00
Darko Gjorgjijoski
f1635bcef8 Fix SQLite docker build related issues (#458) 2025-09-01 02:42:07 +02:00
Darko Gjorgjijoski
3d327a1735 Add SQLite command line utility to docker images 2025-08-31 21:35:15 +02:00
Darko Gjorgjijoski
a6ce294497 Update sqlite path 2025-08-31 20:57:45 +02:00
Darko Gjorgjijoski
1998d15b25 Fix repository name 2025-08-31 16:18:29 +02:00
Darko Gjorgjijoski
f47b6d51f2 GitHub Actions Tweaks (#457)
* Remove PHP 8.2 from tests

* Fix docker hub repository name

* Improve action labels

* Ignore .github folder from check CI
2025-08-31 16:13:18 +02:00
Darko Gjorgjijoski
23f6b1877f 🚢 Simplified docker builds (#456)
* Simplify docker builds

* Ignore docker and frontend scripts from PHP related checks

* Update docker development setup
2025-08-31 15:07:22 +02:00
Darko Gjorgjijoski
3ed91545d1 Bump version 2025-08-31 03:27:33 +02:00
Calcen
c035c834d4 Fix: Weird gap in invoice items description (#439)
- Ensure invoice item display is block for better layout. 
- Gets rid of the weird extra gap between last line and the line above it.
2025-08-31 03:23:58 +02:00
lupus
4f34ca783b Fix: Actually display company currency symbol / total receipts for customer charts (#453)
* Fix: Actually display company currency symbol for customer charts

Related to draft #403.
The mentioned pull request was incomplete, the current state would show amounts in base currency but not use the base/company currency symbols/notation. This change addresses the issue.

* Fix: Use totalReceipts for "Receipts" value
2025-08-31 03:13:16 +02:00
Darko Gjorgjijoski
bae8dbe083 Upgrade mail configuration (#455)
* 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
2025-08-31 03:04:31 +02:00
Tim van Osch
d1bca362de chore: Improve .dev dockerfile for development and production (#183)
* chore: update dockerfile and dev env

* chore(dockerfile): fix user/group id args

* chore(docker): use php-fpm w/ separate nginx

* chore(docker): add nginx image w/ static files

* chore(docker): build vite resources only once, bump vite minor version,
add watch yarn command.
By using --buildplatform tag in the dockerfile we can have the vite step
be built only on the host platform, which significantly speeds it up.
This is possible since the build assets aren't platform dependant.

* Move dockerfiles to .dev
2025-08-31 00:46:56 +02:00
lupus
d5137e393d Fix: Use amounts in base currency for customer charts (#403)
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.
2025-08-30 12:30:49 +02:00
Darko Gjorgjijoski
20caf7ef5b Add missing mailgun-mailer package for Mailgun email driver (#452) 2025-08-30 12:14:20 +02:00
Fabio Ribeiro
e8e01a706e Fix: Create item with tax (ItemModal) (#385)
The issue was found during an Item creation inside the Invoice,
Estimates or Recurring Invoice, the same fix that was applied into the
Item creation view, now is needed into ItemModal. The root cause is that
price + tax returns an amount as float making the database fail.

Relates #377
2025-08-30 11:38:04 +02:00
Darko Gjorgjijoski
2f8c98003d Fix language file conflicts (#451) 2025-08-30 01:36:13 +02:00
Darko Gjorgjijoski
02701db815 New Crowdin updates (#368)
* New translations en.json (Romanian)

* New translations en.json (French)

* New translations en.json (Spanish)

* New translations en.json (Turkish)

* New translations en.json (Indonesian)

* New translations en.json (Russian)

* New translations en.json (Arabic)

* New translations en.json (Bulgarian)

* New translations en.json (Czech)

* New translations en.json (German)

* New translations en.json (Greek)

* New translations en.json (Finnish)

* New translations en.json (Italian)

* New translations en.json (Japanese)

* New translations en.json (Lithuanian)

* New translations en.json (Macedonian)

* New translations en.json (Dutch)

* New translations en.json (Polish)

* New translations en.json (Slovak)

* New translations en.json (Slovenian)

* New translations en.json (Swedish)

* New translations en.json (Ukrainian)

* New translations en.json (Chinese Traditional)

* New translations en.json (Vietnamese)

* New translations en.json (Portuguese, Brazilian)

* New translations en.json (Persian)

* New translations en.json (Thai)

* New translations en.json (Croatian)

* New translations en.json (Latvian)

* New translations en.json (Hindi)

* New translations en.json (Serbian (Latin))

* New translations en.json (Indonesian)

* New translations en.json (Catalan)

* New translations en.json (Chinese Simplified)

* New translations en.json (Chinese Simplified)

* New translations en.json (Chinese Simplified)

* New translations en.json (French)

* New translations en.json (Spanish)

* New translations en.json (German)

* New translations en.json (Persian)

* New translations en.json (Persian)

* New translations en.json (Persian)

* New translations en.json (Slovak)

* New translations en.json (Portuguese, Brazilian)

* New translations en.json (Indonesian)

* New translations en.json (Indonesian)

* New translations en.json (Indonesian)

* New translations en.json (Indonesian)

* New translations en.json (Indonesian)

* New translations en.json (German)

* New translations en.json (Portuguese, Brazilian)

* New translations en.json (Arabic)

* New translations en.json (German)

* New translations en.json (Portuguese, Brazilian)

* New translations en.json (Hindi)

* New translations en.json (Hindi)

* New translations en.json (Slovenian)

* New translations en.json (Italian)

* New translations en.json (German)

* New translations en.json (German)

* New translations en.json (Italian)

* New translations en.json (Italian)

* New translations en.json (Italian)

* New translations en.json (Romanian)

* New translations en.json (French)

* New translations en.json (Spanish)

* New translations en.json (Arabic)

* New translations en.json (Bulgarian)

* New translations en.json (Catalan)

* New translations en.json (Czech)

* New translations en.json (German)

* New translations en.json (Greek)

* New translations en.json (Finnish)

* New translations en.json (Japanese)

* New translations en.json (Lithuanian)

* New translations en.json (Macedonian)

* New translations en.json (Dutch)

* New translations en.json (Polish)

* New translations en.json (Russian)

* New translations en.json (Slovak)

* New translations en.json (Slovenian)

* New translations en.json (Swedish)

* New translations en.json (Turkish)

* New translations en.json (Ukrainian)

* New translations en.json (Chinese Simplified)

* New translations en.json (Chinese Traditional)

* New translations en.json (Vietnamese)

* New translations en.json (Portuguese, Brazilian)

* New translations en.json (Indonesian)

* New translations en.json (Persian)

* New translations en.json (Thai)

* New translations en.json (Croatian)

* New translations en.json (Latvian)

* New translations en.json (Hindi)

* New translations en.json (Serbian (Latin))

* Update source file en.json

* New translations en.json (Czech)

* New translations en.json (German)

* New translations en.json (Norwegian)

* New translations en.json (Croatian)

* New translations en.json (Danish)

* New translations en.json (Hebrew)

* New translations en.json (Hungarian)

* New translations en.json (Georgian)

* New translations en.json (Urdu (Pakistan))

* New translations en.json (Bengali)

* New translations en.json (Estonian)

* New translations en.json (Malay)

* New translations en.json (Swahili)

* New translations en.json (Portuguese, Brazilian)

* New translations en.json (Portuguese, Brazilian)

* New translations en.json (Portuguese)

* New translations en.json (Albanian)

* New translations en.json (Chinese Simplified)

* New translations en.json (Chinese Traditional)

* New translations en.json (Portuguese, Brazilian)

* New translations en.json (Portuguese)

* New translations en.json (Chinese Simplified)
2025-08-30 01:24:36 +02:00
Darko Gjorgjijoski
b7f17f2d14 Add common languages (#448)
* Update languages

* Update language list
2025-08-28 15:35:10 +02:00
Honza Raclavský
cf1d5e7324 Fix deprecated i18n api (#398) 2025-08-28 15:28:42 +02:00
Darko Gjorgjijoski
a40bf5840d Dynamically load language files (#446) 2025-08-28 15:19:51 +02:00
Darko Gjorgjijoski
32f7bc053a New currencies: Paraguayan Guaraní, Algerian Dinar (#447)
* feat(currency): add Algerian Dinar (DZD) support (#395)

* Add Paraguayan Guarany (PYG) currency  (#434)

* Adding Paraguayan currency, closes #404

* Adding the currency to the seeder too

* If the data was already seeded, don't add the entry

* Pint

---------

Co-authored-by: Darko Gjorgjijoski <5760249+gdarko@users.noreply.github.com>

* Add DZD currency to the currencies seeder

---------

Co-authored-by: Polat İnceler <inceler.polat@gmail.com>
Co-authored-by: mchev <martin.chevignard@gmail.com>
2025-08-28 14:13:03 +02:00
Honza Raclavský
a006b07be5 fixed czech translates (#399) 2025-08-28 13:10:48 +02:00
Yes-Sebastian
a44303a370 Update de.json (#414)
Grammar in the German language is a bit tricky. The past tense has been corrected here.
2025-08-28 13:10:02 +02:00
632 changed files with 36651 additions and 9196 deletions

11
.cursor/mcp.json Normal file
View File

@@ -0,0 +1,11 @@
{
"mcpServers": {
"laravel-boost": {
"command": "php",
"args": [
"artisan",
"boost:mcp"
]
}
}
}

View File

@@ -0,0 +1,106 @@
---
name: medialibrary-development
description: Build and work with spatie/laravel-medialibrary features including associating files with Eloquent models, defining media collections and conversions, generating responsive images, and retrieving media URLs and paths.
license: MIT
metadata:
author: Spatie
---
# Media Library Development
## Overview
Use spatie/laravel-medialibrary to associate files with Eloquent models. Supports image/video conversions, responsive images, multiple collections, and various storage disks.
## When to Activate
- Activate when working with file uploads, media attachments, or image processing in Laravel.
- Activate when code references `HasMedia`, `InteractsWithMedia`, the `Media` model, or media collections/conversions.
- Activate when the user wants to add, retrieve, convert, or manage files attached to Eloquent models.
## Scope
- In scope: media uploads, collections, conversions, responsive images, custom properties, file retrieval, path/URL generation.
- Out of scope: general file storage without Eloquent association, non-Laravel frameworks.
## Workflow
1. Identify the task (model setup, adding media, defining conversions, retrieving files, etc.).
2. Read `references/medialibrary-guide.md` and focus on the relevant section.
3. Apply the patterns from the reference, keeping code minimal and Laravel-native.
## Core Concepts
### Model Setup
Every model that should have media must implement `HasMedia` and use the `InteractsWithMedia` trait:
```php
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;
class BlogPost extends Model implements HasMedia
{
use InteractsWithMedia;
}
```
### Adding Media
```php
$blogPost->addMedia($file)->toMediaCollection('images');
$blogPost->addMediaFromUrl($url)->toMediaCollection('images');
$blogPost->addMediaFromRequest('file')->toMediaCollection('images');
```
### Defining Collections
```php
public function registerMediaCollections(): void
{
$this->addMediaCollection('avatar')->singleFile();
$this->addMediaCollection('downloads')->useDisk('s3');
}
```
### Defining Conversions
```php
use Spatie\MediaLibrary\MediaCollections\Models\Media;
use Spatie\Image\Enums\Fit;
public function registerMediaConversions(?Media $media = null): void
{
$this->addMediaConversion('thumb')
->fit(Fit::Contain, 300, 300)
->nonQueued();
}
```
### Retrieving Media
```php
$url = $model->getFirstMediaUrl('images');
$thumbUrl = $model->getFirstMediaUrl('images', 'thumb');
$allMedia = $model->getMedia('images');
```
## Do and Don't
Do:
- Always implement the `HasMedia` interface alongside the `InteractsWithMedia` trait.
- Use `?Media $media = null` as the parameter for `registerMediaConversions()`.
- Call `->toMediaCollection()` to finalize adding media.
- Use `->nonQueued()` for conversions that should run synchronously.
- Use `->singleFile()` on collections that should only hold one file.
- Use `Spatie\Image\Enums\Fit` enum values for fit methods.
Don't:
- Don't forget to run `php artisan vendor:publish --provider="Spatie\MediaLibrary\MediaLibraryServiceProvider" --tag="medialibrary-migrations"` before migrating.
- Don't use `env()` for disk configuration; use `config()` or set it in `config/media-library.php`.
- Don't call `addMedia()` without calling `toMediaCollection()` — the media won't be saved.
- Don't reference conversion names that aren't registered in `registerMediaConversions()`.
## References
- `references/medialibrary-guide.md`

View File

@@ -0,0 +1,577 @@
# Laravel Media Library Reference
Complete reference for `spatie/laravel-medialibrary`. Full documentation: https://spatie.be/docs/laravel-medialibrary
## Model Setup
Implement `HasMedia` and use `InteractsWithMedia`:
```php
use Illuminate\Database\Eloquent\Model;
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;
class BlogPost extends Model implements HasMedia
{
use InteractsWithMedia;
public function registerMediaCollections(): void
{
$this->addMediaCollection('images');
}
public function registerMediaConversions(?Media $media = null): void
{
$this->addMediaConversion('thumb')
->fit(Fit::Contain, 300, 300);
}
}
```
## Adding Media
### From uploaded file
```php
$model->addMedia($request->file('image'))->toMediaCollection('images');
```
### From request (shorthand)
```php
$model->addMediaFromRequest('image')->toMediaCollection('images');
```
### From URL
```php
$model->addMediaFromUrl('https://example.com/image.jpg')->toMediaCollection('images');
```
### From string content
```php
$model->addMediaFromString('raw content')->usingFileName('file.txt')->toMediaCollection('files');
```
### From base64
```php
$model->addMediaFromBase64($base64Data)->usingFileName('photo.jpg')->toMediaCollection('images');
```
### From stream
```php
$model->addMediaFromStream($stream)->usingFileName('file.pdf')->toMediaCollection('files');
```
### From existing disk
```php
$model->addMediaFromDisk('path/to/file.jpg', 's3')->toMediaCollection('images');
```
### Multiple files from request
```php
$model->addMultipleMediaFromRequest(['images'])->each(function ($fileAdder) {
$fileAdder->toMediaCollection('images');
});
$model->addAllMediaFromRequest()->each(function ($fileAdder) {
$fileAdder->toMediaCollection('images');
});
```
### Copy instead of move
```php
$model->copyMedia($pathToFile)->toMediaCollection('images');
// or
$model->addMedia($pathToFile)->preservingOriginal()->toMediaCollection('images');
```
## FileAdder Options
All methods are chainable before calling `toMediaCollection()`:
```php
$model->addMedia($file)
->usingName('Custom Name') // display name
->usingFileName('custom-name.jpg') // filename on disk
->setOrder(3) // order within collection
->withCustomProperties(['alt' => 'A landscape photo'])
->withManipulations(['thumb' => ['filter' => 'greyscale']])
->withResponsiveImages() // generate responsive variants
->storingConversionsOnDisk('s3') // put conversions on different disk
->addCustomHeaders(['CacheControl' => 'max-age=31536000'])
->toMediaCollection('images');
```
### Store on cloud disk
```php
$model->addMedia($file)->toMediaCollectionOnCloudDisk('images');
```
## Media Collections
Define in `registerMediaCollections()`:
```php
public function registerMediaCollections(): void
{
// Basic collection
$this->addMediaCollection('images');
// Single file (replacing previous on new upload)
$this->addMediaCollection('avatar')
->singleFile();
// Keep only latest N items
$this->addMediaCollection('recent_photos')
->onlyKeepLatest(5);
// Specific disk
$this->addMediaCollection('downloads')
->useDisk('s3');
// With conversions disk
$this->addMediaCollection('photos')
->useDisk('s3')
->storeConversionsOnDisk('s3-thumbnails');
// MIME type restriction
$this->addMediaCollection('documents')
->acceptsMimeTypes(['application/pdf', 'application/zip']);
// Custom validation
$this->addMediaCollection('images')
->acceptsFile(function ($file) {
return $file->mimeType === 'image/jpeg';
});
// Fallback URL/path when collection is empty
$this->addMediaCollection('avatar')
->singleFile()
->useFallbackUrl('/images/default-avatar.jpg')
->useFallbackPath(public_path('/images/default-avatar.jpg'));
// Enable responsive images for entire collection
$this->addMediaCollection('hero_images')
->withResponsiveImages();
// Collection-specific conversions
$this->addMediaCollection('photos')
->registerMediaConversions(function () {
$this->addMediaConversion('card')
->fit(Fit::Crop, 400, 400);
});
}
```
## Media Conversions
Define in `registerMediaConversions()`:
```php
use Spatie\MediaLibrary\MediaCollections\Models\Media;
use Spatie\Image\Enums\Fit;
public function registerMediaConversions(?Media $media = null): void
{
$this->addMediaConversion('thumb')
->fit(Fit::Contain, 300, 300)
->nonQueued();
$this->addMediaConversion('preview')
->fit(Fit::Crop, 500, 500)
->withResponsiveImages()
->queued();
$this->addMediaConversion('banner')
->fit(Fit::Max, 1200, 630)
->performOnCollections('images', 'headers')
->nonQueued()
->sharpen(10);
// Conditional conversion based on media properties
if ($media?->mime_type === 'image/png') {
$this->addMediaConversion('png-thumb')
->fit(Fit::Contain, 150, 150);
}
// Keep original format instead of converting to jpg
$this->addMediaConversion('web')
->fit(Fit::Max, 800, 800)
->keepOriginalImageFormat();
// PDF page rendering
$this->addMediaConversion('pdf-preview')
->pdfPageNumber(1)
->fit(Fit::Contain, 400, 400);
// Video frame extraction
$this->addMediaConversion('video-thumb')
->extractVideoFrameAtSecond(5)
->fit(Fit::Crop, 300, 300);
}
```
### Image Manipulation Methods (via spatie/image)
Resizing and fitting:
- `width(int)`, `height(int)` — constrain dimensions
- `fit(Fit, int, int)` — fit within bounds using `Fit::Contain`, `Fit::Max`, `Fit::Fill`, `Fit::Stretch`, `Fit::Crop`
- `crop(int, int)` — crop to exact dimensions
Effects:
- `sharpen(int)`, `blur(int)`, `pixelate(int)`
- `greyscale()`, `sepia()`
- `brightness(int)`, `contrast(int)`, `colorize(int, int, int)`
Orientation:
- `orientation(int)`, `flip(string)`, `rotate(int)`
Format:
- `format(string)``'jpg'`, `'png'`, `'webp'`, `'avif'`
- `quality(int)` — 1-100
Other:
- `border(int, string, string)`, `watermark(string)`
- `optimize()`, `nonOptimized()`
### Conversion Configuration
- `performOnCollections('col1', 'col2')` — limit to specific collections
- `queued()` / `nonQueued()` — run async or sync
- `withResponsiveImages()` — also generate responsive variants for this conversion
- `keepOriginalImageFormat()` — preserve png/webp/gif instead of converting to jpg
- `pdfPageNumber(int)` — which PDF page to render
- `extractVideoFrameAtSecond(int)` — video thumbnail timing
## Retrieving Media
### Getting media items
```php
$media = $model->getMedia('images'); // all in collection
$first = $model->getFirstMedia('images'); // first item
$last = $model->getLastMedia('images'); // last item
$has = $model->hasMedia('images'); // boolean check
```
### Getting URLs
```php
$url = $model->getFirstMediaUrl('images'); // original URL
$thumbUrl = $model->getFirstMediaUrl('images', 'thumb'); // conversion URL
$lastUrl = $model->getLastMediaUrl('images', 'thumb');
```
### Getting paths
```php
$path = $model->getFirstMediaPath('images');
$thumbPath = $model->getFirstMediaPath('images', 'thumb');
```
### Temporary URLs (S3)
```php
$tempUrl = $model->getFirstTemporaryUrl(
now()->addMinutes(30),
'images',
'thumb'
);
```
### Fallback URLs
```php
$url = $model->getFallbackMediaUrl('avatar');
```
### From the Media model
```php
$media = $model->getFirstMedia('images');
$media->getUrl(); // original URL
$media->getUrl('thumb'); // conversion URL
$media->getPath(); // disk path
$media->getFullUrl(); // full URL with domain
$media->getTemporaryUrl(now()->addMinutes(30));
$media->hasGeneratedConversion('thumb'); // check if conversion exists
```
### Filtering media
```php
$media = $model->getMedia('images', function (Media $media) {
return $media->getCustomProperty('featured') === true;
});
$media = $model->getMedia('images', ['mime_type' => 'image/jpeg']);
```
## Custom Properties
Store arbitrary metadata on media items:
```php
// When adding
$model->addMedia($file)
->withCustomProperties([
'alt' => 'Descriptive text',
'credits' => 'Photographer Name',
])
->toMediaCollection('images');
// Get/set on existing media
$media->setCustomProperty('alt', 'Updated text');
$media->save();
$alt = $media->getCustomProperty('alt');
$has = $media->hasCustomProperty('alt');
$media->forgetCustomProperty('alt');
$media->save();
```
## Responsive Images
Generate multiple sizes for optimal loading:
```php
// On the FileAdder
$model->addMedia($file)
->withResponsiveImages()
->toMediaCollection('images');
// On a conversion
$this->addMediaConversion('hero')
->fit(Fit::Max, 1200, 800)
->withResponsiveImages();
// On a collection
$this->addMediaCollection('photos')
->withResponsiveImages();
```
### Using in Blade
```blade
{{-- Renders img tag with srcset --}}
{{ $media->toHtml() }}
{{-- With attributes --}}
{{ $media->img()->attributes(['class' => 'w-full', 'alt' => 'Photo']) }}
{{-- Get srcset string --}}
<img src="{{ $media->getUrl() }}" srcset="{{ $media->getSrcset() }}" />
{{-- Responsive conversion --}}
<img src="{{ $media->getUrl('hero') }}" srcset="{{ $media->getSrcset('hero') }}" />
```
### Placeholder SVG
```php
$svg = $media->responsiveImages()->getPlaceholderSvg(); // tiny blurred base64 placeholder
```
## Managing Media
### Clear a collection
```php
$model->clearMediaCollection('images');
```
### Clear except specific items
```php
$model->clearMediaCollectionExcept('images', $mediaToKeep);
```
### Delete specific media
```php
$model->deleteMedia($mediaId);
```
### Delete all media
```php
$model->deleteAllMedia();
```
### Delete model but keep media files
```php
$model->deletePreservingMedia();
```
### Reorder media
```php
Media::setNewOrder([3, 1, 2]); // media IDs in desired order
```
### Move/copy media between models
```php
$media->move($otherModel, 'images');
$media->copy($otherModel, 'images');
```
## Events
```php
use Spatie\MediaLibrary\MediaCollections\Events\MediaHasBeenAddedEvent;
use Spatie\MediaLibrary\Conversions\Events\ConversionWillStartEvent;
use Spatie\MediaLibrary\Conversions\Events\ConversionHasBeenCompletedEvent;
use Spatie\MediaLibrary\MediaCollections\Events\CollectionHasBeenClearedEvent;
```
Listen to these events to hook into the media lifecycle:
```php
Event::listen(MediaHasBeenAddedEvent::class, function ($event) {
$event->media; // the added Media model
});
Event::listen(ConversionHasBeenCompletedEvent::class, function ($event) {
$event->media;
$event->conversion;
});
```
## Configuration
Key `config/media-library.php` options:
```php
return [
'disk_name' => 'public', // default disk
'max_file_size' => 1024 * 1024 * 10, // 10MB
'queue_connection_name' => '', // queue connection
'queue_name' => '', // queue name
'queue_conversions_by_default' => true, // queue conversions
'media_model' => Spatie\MediaLibrary\MediaCollections\Models\Media::class,
'file_namer' => Spatie\MediaLibrary\Support\FileNamer\DefaultFileNamer::class,
'path_generator' => Spatie\MediaLibrary\Support\PathGenerator\DefaultPathGenerator::class,
'url_generator' => Spatie\MediaLibrary\Support\UrlGenerator\DefaultUrlGenerator::class,
'image_driver' => 'gd', // 'gd', 'imagick', or 'vips'
'image_optimizers' => [/* optimizer config */],
'version_urls' => true, // cache busting
'default_loading_attribute_value' => null, // 'lazy' for lazy loading
];
```
### Custom Path Generator
```php
use Spatie\MediaLibrary\Support\PathGenerator\PathGenerator;
class CustomPathGenerator implements PathGenerator
{
public function getPath(Media $media): string
{
return md5($media->id) . '/';
}
public function getPathForConversions(Media $media): string
{
return $this->getPath($media) . 'conversions/';
}
public function getPathForResponsiveImages(Media $media): string
{
return $this->getPath($media) . 'responsive/';
}
}
```
### Custom File Namer
```php
use Spatie\MediaLibrary\Support\FileNamer\FileNamer;
class CustomFileNamer extends FileNamer
{
public function originalFileName(string $fileName): string
{
return Str::slug(pathinfo($fileName, PATHINFO_FILENAME));
}
public function conversionFileName(string $fileName, Conversion $conversion): string
{
return $this->originalFileName($fileName) . '-' . $conversion->getName();
}
public function responsiveFileName(string $fileName): string
{
return pathinfo($fileName, PATHINFO_FILENAME);
}
}
```
### Custom Media Model
```php
use Spatie\MediaLibrary\MediaCollections\Models\Media as BaseMedia;
class Media extends BaseMedia
{
// Add custom methods, scopes, or override behavior
}
```
Register in config: `'media_model' => App\Models\Media::class`
## Downloading Media
### Single file
```php
return $media->toResponse($request); // download
return $media->toInlineResponse($request); // display inline
return $media->stream(); // stream
```
### ZIP download of collection
```php
use Spatie\MediaLibrary\Support\MediaStream;
return MediaStream::create('photos.zip')
->addMedia($model->getMedia('images'));
```
## Using with API Resources
```php
class PostResource extends JsonResource
{
public function toArray($request): array
{
return [
'id' => $this->id,
'title' => $this->title,
'image' => $this->getFirstMediaUrl('images'),
'thumb' => $this->getFirstMediaUrl('images', 'thumb'),
'media' => $this->getMedia('images')->map(function ($media) {
return [
'id' => $media->id,
'url' => $media->getUrl(),
'thumb' => $media->getUrl('thumb'),
'name' => $media->name,
'size' => $media->size,
'type' => $media->mime_type,
];
}),
];
}
}
```

View File

@@ -0,0 +1,157 @@
---
name: pest-testing
description: "Use this skill for Pest PHP testing in Laravel projects only. Trigger whenever any test is being written, edited, fixed, or refactored — including fixing tests that broke after a code change, adding assertions, converting PHPUnit to Pest, adding datasets, and TDD workflows. Always activate when the user asks how to write something in Pest, mentions test files or directories (tests/Feature, tests/Unit, tests/Browser), or needs browser testing, smoke testing multiple pages for JS errors, or architecture tests. Covers: it()/expect() syntax, datasets, mocking, browser testing (visit/click/fill), smoke testing, arch(), Livewire component tests, RefreshDatabase, and all Pest 4 features. Do not use for factories, seeders, migrations, controllers, models, or non-test PHP code."
license: MIT
metadata:
author: laravel
---
# Pest Testing 4
## Documentation
Use `search-docs` for detailed Pest 4 patterns and documentation.
## Basic Usage
### Creating Tests
All tests must be written using Pest. Use `php artisan make:test --pest {name}`.
### Test Organization
- Unit/Feature tests: `tests/Feature` and `tests/Unit` directories.
- Browser tests: `tests/Browser/` directory.
- Do NOT remove tests without approval - these are core application code.
### Basic Test Structure
<!-- Basic Pest Test Example -->
```php
it('is true', function () {
expect(true)->toBeTrue();
});
```
### Running Tests
- Run minimal tests with filter before finalizing: `php artisan test --compact --filter=testName`.
- Run all tests: `php artisan test --compact`.
- Run file: `php artisan test --compact tests/Feature/ExampleTest.php`.
## Assertions
Use specific assertions (`assertSuccessful()`, `assertNotFound()`) instead of `assertStatus()`:
<!-- Pest Response Assertion -->
```php
it('returns all', function () {
$this->postJson('/api/docs', [])->assertSuccessful();
});
```
| Use | Instead of |
|-----|------------|
| `assertSuccessful()` | `assertStatus(200)` |
| `assertNotFound()` | `assertStatus(404)` |
| `assertForbidden()` | `assertStatus(403)` |
## Mocking
Import mock function before use: `use function Pest\Laravel\mock;`
## Datasets
Use datasets for repetitive tests (validation rules, etc.):
<!-- Pest Dataset Example -->
```php
it('has emails', function (string $email) {
expect($email)->not->toBeEmpty();
})->with([
'james' => 'james@laravel.com',
'taylor' => 'taylor@laravel.com',
]);
```
## Pest 4 Features
| Feature | Purpose |
|---------|---------|
| Browser Testing | Full integration tests in real browsers |
| Smoke Testing | Validate multiple pages quickly |
| Visual Regression | Compare screenshots for visual changes |
| Test Sharding | Parallel CI runs |
| Architecture Testing | Enforce code conventions |
### Browser Test Example
Browser tests run in real browsers for full integration testing:
- Browser tests live in `tests/Browser/`.
- Use Laravel features like `Event::fake()`, `assertAuthenticated()`, and model factories.
- Use `RefreshDatabase` for clean state per test.
- Interact with page: click, type, scroll, select, submit, drag-and-drop, touch gestures.
- Test on multiple browsers (Chrome, Firefox, Safari) if requested.
- Test on different devices/viewports (iPhone 14 Pro, tablets) if requested.
- Switch color schemes (light/dark mode) when appropriate.
- Take screenshots or pause tests for debugging.
<!-- Pest Browser Test Example -->
```php
it('may reset the password', function () {
Notification::fake();
$this->actingAs(User::factory()->create());
$page = visit('/sign-in');
$page->assertSee('Sign In')
->assertNoJavaScriptErrors()
->click('Forgot Password?')
->fill('email', 'nuno@laravel.com')
->click('Send Reset Link')
->assertSee('We have emailed your password reset link!');
Notification::assertSent(ResetPassword::class);
});
```
### Smoke Testing
Quickly validate multiple pages have no JavaScript errors:
<!-- Pest Smoke Testing Example -->
```php
$pages = visit(['/', '/about', '/contact']);
$pages->assertNoJavaScriptErrors()->assertNoConsoleLogs();
```
### Visual Regression Testing
Capture and compare screenshots to detect visual changes.
### Test Sharding
Split tests across parallel processes for faster CI runs.
### Architecture Testing
Pest 4 includes architecture testing (from Pest 3):
<!-- Architecture Test Example -->
```php
arch('controllers')
->expect('App\Http\Controllers')
->toExtendNothing()
->toHaveSuffix('Controller');
```
## Common Pitfalls
- Not importing `use function Pest\Laravel\mock;` before using mock
- Using `assertStatus(200)` instead of `assertSuccessful()`
- Forgetting datasets for repetitive validation tests
- Deleting tests without approval
- Forgetting `assertNoJavaScriptErrors()` in browser tests

View File

@@ -0,0 +1,91 @@
---
name: tailwindcss-development
description: "Always invoke when the user's message includes 'tailwind' in any form. Also invoke for: building responsive grid layouts (multi-column card grids, product grids), flex/grid page structures (dashboards with sidebars, fixed topbars, mobile-toggle navs), styling UI components (cards, tables, navbars, pricing sections, forms, inputs, badges), adding dark mode variants, fixing spacing or typography, and Tailwind v3/v4 work. The core use case: writing or fixing Tailwind utility classes in HTML templates (Blade, JSX, Vue). Skip for backend PHP logic, database queries, API routes, JavaScript with no HTML/CSS component, CSS file audits, build tool configuration, and vanilla CSS."
license: MIT
metadata:
author: laravel
---
# Tailwind CSS Development
## Documentation
Use `search-docs` for detailed Tailwind CSS v3 patterns and documentation.
## Basic Usage
- Use Tailwind CSS classes to style HTML. Check and follow existing Tailwind conventions in the project before introducing new patterns.
- Offer to extract repeated patterns into components that match the project's conventions (e.g., Blade, JSX, Vue).
- Consider class placement, order, priority, and defaults. Remove redundant classes, add classes to parent or child elements carefully to reduce repetition, and group elements logically.
## Tailwind CSS v3 Specifics
- Always use Tailwind CSS v3 and verify you're using only classes it supports.
- Configuration is done in the `tailwind.config.js` file.
- Import using `@tailwind` directives:
<!-- v3 Import Syntax -->
```css
@tailwind base;
@tailwind components;
@tailwind utilities;
```
## Spacing
When listing items, use gap utilities for spacing; don't use margins.
<!-- Gap Utilities -->
```html
<div class="flex gap-8">
<div>Item 1</div>
<div>Item 2</div>
</div>
```
## Dark Mode
If existing pages and components support dark mode, new pages and components must support it the same way, typically using the `dark:` variant:
<!-- Dark Mode -->
```html
<div class="bg-white dark:bg-gray-900 text-gray-900 dark:text-white">
Content adapts to color scheme
</div>
```
## Common Patterns
### Flexbox Layout
<!-- Flexbox Layout -->
```html
<div class="flex items-center justify-between gap-4">
<div>Left content</div>
<div>Right content</div>
</div>
```
### Grid Layout
<!-- Grid Layout -->
```html
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<div>Card 1</div>
<div>Card 2</div>
<div>Card 3</div>
</div>
```
## Verification
1. Check browser for visual rendering
2. Test responsive breakpoints
3. Verify dark mode if project uses it
## Common Pitfalls
- Using margins for spacing between siblings instead of gap utilities
- Forgetting to add dark mode variants when the project uses dark mode
- Not checking existing project conventions before adding new utilities
- Overusing inline styles when Tailwind classes would suffice

View File

@@ -1,22 +0,0 @@
server {
listen 80;
root /home/invoiceshelf/app/public;
index index.php;
error_log /var/log/nginx/dev-error.log;
access_log /var/log/nginx/dev-access.log;
server_name invoiceshelf.test;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass php-fpm:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}
}

View File

@@ -1,64 +0,0 @@
FROM php:8.3-fpm-bookworm
ARG UID
ARG GID
ENV UID=${UID}
ENV GID=${GID}
USER root
# Create user/group
RUN addgroup --gid ${GID} --system invoiceshelf && \
adduser --gid ${GID} --system --disabled-password --shell /bin/sh -u ${UID} --home /home/invoiceshelf invoiceshelf && \
sed -i "s/user = www-data/user = invoiceshelf/g" /usr/local/etc/php-fpm.d/www.conf && \
sed -i "s/group = www-data/group = invoiceshelf/g" /usr/local/etc/php-fpm.d/www.conf
# Install composer & npm
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer && \
curl -sL https://deb.nodesource.com/setup_20.x | bash - && \
apt install -y nodejs
# install dependencies
RUN apt update && apt install -y \
libpng-dev \
zlib1g-dev \
libxml2-dev \
libzip-dev \
libonig-dev \
libpq-dev \
sqlite3 \
postgresql-client \
mariadb-client \
zip \
curl \
unzip \
webp \
&& docker-php-ext-configure gd \
&& docker-php-ext-install -j$(nproc) gd \
&& docker-php-ext-install bcmath \
&& docker-php-ext-install mbstring \
&& docker-php-ext-install mysqli \
&& docker-php-ext-install pdo_mysql \
&& docker-php-ext-configure pgsql -with-pgsql=/usr/local/pgsql \
&& docker-php-ext-install pgsql \
&& docker-php-ext-install pdo_pgsql \
&& docker-php-ext-install zip \
&& docker-php-ext-install xml \
&& docker-php-ext-install exif \
&& docker-php-source delete
# Clear cache
RUN apt-get clean && rm -rf /var/lib/apt/lists/*
# Set workdir
WORKDIR /home/invoiceshelf/app
# Copy Files
COPY entrypoint.sh /entrypoint.sh
# Entrypoint
ENTRYPOINT ["/entrypoint.sh"]
# Launch php-fpm
CMD ["php-fpm"]

View File

@@ -1,44 +0,0 @@
#!/bin/bash
echo "############################################"
echo "### InvoiceShelf Development Environment ###"
echo "############################################"
cd /home/invoiceshelf/app
# Composer build
if [ ! -d vendor ]; then
composer install
fi
# Empty sqlite database
if [ ! -f database/database.sqlite ]; then
cp database/stubs/sqlite.empty.db database/database.sqlite
fi
# .env file set up
if [ ! -f .env ]; then
cp .env.example .env
php artisan key:generate --force
fi
# NPM build
if [ ! -d node_modules ]; then
npm install
npm run build
fi
# Storage symlink
php artisan storage:link
# Permissions
chmod 775 storage/framework
chmod 775 storage/logs
chmod 775 bootstrap/cache
chown -R ${UID}:${GID} /home/invoiceshelf/app
chmod +x artisan
echo "Entrypoint complete."
exec $@

File diff suppressed because it is too large Load Diff

45
.dockerignore Normal file
View File

@@ -0,0 +1,45 @@
.idea/
.git/
.github/
docker/
!docker/production/entrypoint.d
!docker/production/inject.sh
node_modules/
database/*.sqlite
storage/app/*
!storage/app/templates*
storage/fonts/*
storage/framework/cache/data/*
storage/framework/sessions/*
storage/framework/views/*
storage/logs/*
tests/
vendor/
.dockerignore
.devenvconfig
.editorconfig
.env
.env.testing
.eslintrc.mjs
.gitattributes
.gitignore
.prettierrc.json
devenv
CODE_OF_CONDUCT.md
Dockerfile
*.Dockerfile
LICENSE
Makefile
SECURITY.md
_ide_helper.php
crowdin.yml
invoiceshelf.code-workspace
package-lock.json
phpunit.xml
readme.md

View File

@@ -1,19 +1,11 @@
APP_ENV=production
APP_DEBUG=false
APP_KEY=base64:kgk/4DW1vEVy7aEvet5FPp5un6PIGe/so8H0mvoUtW0=
APP_DEBUG=true
APP_NAME="InvoiceShelf"
APP_LOG_LEVEL=debug
APP_TIMEZONE=UTC
APP_URL=
APP_LOCALE=en
APP_FALLBACK_LOCALE=en
APP_FAKER_LOCALE=en_US
APP_MAINTENANCE_DRIVER=file
APP_MAINTENANCE_STORE=database
BCRYPT_ROUNDS=12
DB_CONNECTION=sqlite
DB_HOST=
@@ -22,38 +14,10 @@ DB_DATABASE=
DB_USERNAME=
DB_PASSWORD=
BROADCAST_CONNECTION=log
CACHE_STORE=file
QUEUE_CONNECTION=sync
SESSION_DRIVER=file
SESSION_LIFETIME=1440
SESSION_ENCRYPT=false
SESSION_PATH=/
SESSION_DOMAIN=null
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_DRIVER=smtp
MAIL_HOST=
MAIL_PORT=
MAIL_USERNAME=
MAIL_PASSWORD=
MAIL_ENCRYPTION=
MAIL_FROM_NAME=
MAIL_FROM_ADDRESS=
PUSHER_APP_ID=
PUSHER_KEY=
PUSHER_SECRET=
SANCTUM_STATEFUL_DOMAIN=
TRUSTED_PROXIES="*"
CRON_JOB_AUTH_TOKEN=""
LOG_STACK=single
PDF_DRIVER=dompdf
GOTENBERG_HOST=
GOTENBERG_PAPERSIZE=
# Dompdf: keep false so untrusted HTML in PDF notes cannot trigger outbound requests (SSRF).
# Set true only if you fully trust all PDF HTML and need remote images/CSS.
DOMPDF_ENABLE_REMOTE=false

View File

@@ -3,7 +3,7 @@ APP_DEBUG=true
APP_KEY=base64:IdDlpLmYyWA9z4Ruj5st1FSYrhCR7lPOscLGCz2Jf4I=
DB_CONNECTION=sqlite
MAIL_DRIVER=smtp
MAIL_MAILER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=587
MAIL_USERNAME=ff538f0e1037f4

View File

@@ -2,7 +2,7 @@
Thank you for investing your time in contributing to our project! :sparkles:.
Read our [Code of Conduct](./CODE_OF_CONDUCT.md) to keep our community approachable and respectable.
Read our [Code of Conduct](../CODE_OF_CONDUCT.md) to keep our community approachable and respectable.
In this guide you will get an overview of the contribution workflow from opening an issue, creating a PR, reviewing, and merging the PR.
@@ -39,7 +39,7 @@ Scan through our [existing issues](https://github.com/InvoiceShelf/InvoiceShelf/
- Using the command line:
- [Fork the repo](https://docs.github.com/en/get-started/quickstart/fork-a-repo) so that you can make your changes without affecting the original project until you're ready to merge them.
2. Install or update to **Node.js**, at the version specified in `.node-version`. For more information, see [the development guide](../contributing/development.md).
2. Install or update to **Node.js**, at the version specified in `.node-version`. For more information, see [the development guide](../docker/development/README.md).
3. Create a working branch and start with your changes!

View File

@@ -4,17 +4,22 @@ name: Check
on:
push:
paths-ignore:
- '.github/**/*'
- '**/*.md'
- 'public/build/*.js'
- 'public/build/**/*.js'
branches-ignore:
- 'docker/**/*'
- 'resources/scripts/**/*'
tags-ignore:
- "*"
branches-ignore:
- 'translations'
pull_request:
paths-ignore:
- '**/*.md'
- 'public/build/*.js'
- 'public/build/**/*.js'
branches-ignore:
branches-ignore:
- 'translations'
# Allow manually triggering the workflow.
workflow_dispatch:
@@ -40,7 +45,7 @@ jobs:
- name: Set up PHP
uses: shivammathur/setup-php@v2
with:
php-version: 8.3
php-version: 8.4
- name: Checkout code
uses: actions/checkout@v4
@@ -59,8 +64,6 @@ jobs:
strategy:
matrix:
php-version:
- 8.2
- 8.3
- 8.4
env:
extensions: bcmath, curl, dom, gd, imagick, json, libxml, mbstring, pcntl, pdo, pdo_mysql, zip
@@ -93,52 +96,3 @@ jobs:
- name: Apply tests ${{ matrix.php-version }}
run: php artisan test
createReleaseFile:
name: 3⃣ Build / Upload - Release File
if: github.ref_type == 'tag'
needs:
- tests
runs-on: ubuntu-latest
env:
extensions: bcmath, curl, dom, gd, imagick, json, libxml, mbstring, pcntl, pdo, pdo_mysql, zip
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: 8.2
extensions: ${{ env.extensions }}
coverage: none
- name: Install Composer dependencies
uses: ramsey/composer-install@v2
with:
composer-options: --no-dev
- name: Use Node.js 20
uses: actions/setup-node@v4
with:
node-version: 20
- name: Install
run: npm install
- name: Compile Front-end
run: npm run build
- name: Build Dist
run: |
make clean dist
- name: Upload package
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ github.token }}
file: InvoiceShelf.zip
asset_name: InvoiceShelf.zip
tag: ${{ github.ref }}
overwrite: true

259
.github/workflows/docker.yaml vendored Normal file
View File

@@ -0,0 +1,259 @@
name: Docker Build and Push
on:
release:
types: [published]
schedule:
# Run nightly at 2 AM UTC
- cron: '0 2 * * *'
workflow_dispatch:
inputs:
tag:
description: 'Docker tag'
required: true
default: 'latest'
jobs:
php_syntax_errors:
name: 1⃣ PHP Code Style errors
if: github.event_name == 'release'
runs-on: ubuntu-latest
steps:
- name: Set up PHP
uses: shivammathur/setup-php@v2
with:
php-version: 8.4
- name: Checkout code
uses: actions/checkout@v4
- name: Install dependencies
uses: ramsey/composer-install@v2
- name: Check source code for syntax errors
run: ./vendor/bin/pint --test
tests:
name: 2⃣ PHP Tests
if: github.event_name == 'release'
needs:
- php_syntax_errors
runs-on: ubuntu-latest
strategy:
matrix:
php-version:
- 8.4
env:
extensions: bcmath, curl, dom, gd, imagick, json, libxml, mbstring, pcntl, pdo, pdo_mysql, zip
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup PHP Action
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-version }}
extensions: ${{ env.extensions }}
coverage: xdebug
tools: pecl, composer
- name: Install Composer dependencies
uses: ramsey/composer-install@v2
- name: Use Node.js 20
uses: actions/setup-node@v4
with:
node-version: 20
- name: Install
run: npm install
- name: Compile Front-end
run: npm run build
- name: Apply tests ${{ matrix.php-version }}
run: php artisan test
release_artifact_build:
name: 🏗️ Build / Upload - Release File
if: github.event_name == 'release'
needs:
- tests
runs-on: ubuntu-latest
env:
extensions: bcmath, curl, dom, gd, imagick, json, libxml, mbstring, pcntl, pdo, pdo_mysql, zip
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: 8.4
extensions: ${{ env.extensions }}
coverage: none
- name: Install Composer dependencies
uses: ramsey/composer-install@v2
with:
composer-options: --no-dev
- name: Use Node.js 20
uses: actions/setup-node@v4
with:
node-version: 20
- name: Install
run: npm install
- name: Compile Front-end
run: npm run build
- name: Build Dist
run: |
make clean dist
- name: Upload package
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ github.token }}
file: InvoiceShelf.zip
asset_name: InvoiceShelf.zip
tag: ${{ github.ref }}
overwrite: true
release_docker_build:
name: 🐳 Release Docker Build
if: github.event_name == 'release'
needs:
- tests
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: invoiceshelf/invoiceshelf
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
file: docker/production/Dockerfile
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
manual_docker_build:
name: 🛠️ Manual Docker Build
if: github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_TOKEN }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
file: docker/production/Dockerfile
platforms: linux/amd64,linux/arm64
push: true
tags: invoiceshelf/invoiceshelf:${{ github.event.inputs.tag }}
cache-from: type=gha
cache-to: type=gha,mode=max
nightly_build:
name: 🌙 Nightly Docker Build
if: github.event_name == 'schedule'
runs-on: ubuntu-latest
strategy:
matrix:
branch: [master, develop]
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
ref: ${{ matrix.branch }}
fetch-depth: 2
- name: Check for recent changes
id: changes
run: |
# Check if there are commits in the last 24 hours
RECENT_COMMITS=$(git log --since="24 hours ago" --oneline | wc -l)
echo "recent_commits=$RECENT_COMMITS" >> $GITHUB_OUTPUT
if [ "$RECENT_COMMITS" -gt 0 ]; then
echo "has_changes=true" >> $GITHUB_OUTPUT
else
echo "has_changes=false" >> $GITHUB_OUTPUT
fi
- name: Set up Docker Buildx
if: steps.changes.outputs.has_changes == 'true'
uses: docker/setup-buildx-action@v3
- name: Log in to Docker Hub
if: steps.changes.outputs.has_changes == 'true'
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_TOKEN }}
- name: Set Docker tag
if: steps.changes.outputs.has_changes == 'true'
id: tag
run: |
if [ "${{ matrix.branch }}" = "master" ]; then
echo "tag=nightly" >> $GITHUB_OUTPUT
elif [ "${{ matrix.branch }}" = "develop" ]; then
echo "tag=alpha" >> $GITHUB_OUTPUT
fi
- name: Build and push Docker image
if: steps.changes.outputs.has_changes == 'true'
uses: docker/build-push-action@v5
with:
context: .
file: docker/production/Dockerfile
platforms: linux/amd64,linux/arm64
push: true
tags: invoiceshelf/invoiceshelf:${{ steps.tag.outputs.tag }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: No changes detected
if: steps.changes.outputs.has_changes == 'false'
run: |
echo "No commits found in the last 24 hours for ${{ matrix.branch }} branch. Skipping build."

7
.gitignore vendored
View File

@@ -14,13 +14,16 @@ Homestead.yaml
.rnd
/.expo
/.vscode
/.devcontainer
.gitkeep
/public/docs
/.scribe
!storage/fonts/.gitkeep
.DS_Store
.php-cs-fixer.cache
.devenvconfig
/storage/fonts*
package-lock.json
/.dev/docker-compose.yml
/.dev/docker-compose.yaml
/docker/development/docker-compose.yml
/docker/production/docker-compose.yml
/docker-compose.yaml

234
AGENTS.md Normal file
View File

@@ -0,0 +1,234 @@
<laravel-boost-guidelines>
=== foundation rules ===
# Laravel Boost Guidelines
The Laravel Boost guidelines are specifically curated by Laravel maintainers for this application. These guidelines should be followed closely to ensure the best experience when building Laravel applications.
## Foundational Context
This application is a Laravel application and its main Laravel ecosystems package & versions are below. You are an expert with them all. Ensure you abide by these specific packages & versions.
- php - 8.4
- laravel/framework (LARAVEL) - v13
- laravel/prompts (PROMPTS) - v0
- laravel/sanctum (SANCTUM) - v4
- phpunit/phpunit (PHPUNIT) - v12
- laravel/boost (BOOST) - v2
- laravel/mcp (MCP) - v0
- laravel/pint (PINT) - v1
- laravel/sail (SAIL) - v1
- pestphp/pest (PEST) - v4
- vue (VUE) - v3
- eslint (ESLINT) - v9
- prettier (PRETTIER) - v3
- tailwindcss (TAILWINDCSS) - v3
## Skills Activation
This project has domain-specific skills available. You MUST activate the relevant skill whenever you work in that domain—don't wait until you're stuck.
- `pest-testing` — Use this skill for Pest PHP testing in Laravel projects only. Trigger whenever any test is being written, edited, fixed, or refactored — including fixing tests that broke after a code change, adding assertions, converting PHPUnit to Pest, adding datasets, and TDD workflows. Always activate when the user asks how to write something in Pest, mentions test files or directories (tests/Feature, tests/Unit, tests/Browser), or needs browser testing, smoke testing multiple pages for JS errors, or architecture tests. Covers: it()/expect() syntax, datasets, mocking, browser testing (visit/click/fill), smoke testing, arch(), Livewire component tests, RefreshDatabase, and all Pest 4 features. Do not use for factories, seeders, migrations, controllers, models, or non-test PHP code.
- `tailwindcss-development` — Always invoke when the user's message includes 'tailwind' in any form. Also invoke for: building responsive grid layouts (multi-column card grids, product grids), flex/grid page structures (dashboards with sidebars, fixed topbars, mobile-toggle navs), styling UI components (cards, tables, navbars, pricing sections, forms, inputs, badges), adding dark mode variants, fixing spacing or typography, and Tailwind v3/v4 work. The core use case: writing or fixing Tailwind utility classes in HTML templates (Blade, JSX, Vue). Skip for backend PHP logic, database queries, API routes, JavaScript with no HTML/CSS component, CSS file audits, build tool configuration, and vanilla CSS.
- `medialibrary-development` — Build and work with spatie/laravel-medialibrary features including associating files with Eloquent models, defining media collections and conversions, generating responsive images, and retrieving media URLs and paths.
## Conventions
- You must follow all existing code conventions used in this application. When creating or editing a file, check sibling files for the correct structure, approach, and naming.
- Use descriptive names for variables and methods. For example, `isRegisteredForDiscounts`, not `discount()`.
- Check for existing components to reuse before writing a new one.
## Verification Scripts
- Do not create verification scripts or tinker when tests cover that functionality and prove they work. Unit and feature tests are more important.
## Application Structure & Architecture
- Stick to existing directory structure; don't create new base folders without approval.
- Do not change the application's dependencies without approval.
## Frontend Bundling
- If the user doesn't see a frontend change reflected in the UI, it could mean they need to run `npm run build`, `npm run dev`, or `composer run dev`. Ask them.
## Documentation Files
- You must only create documentation files if explicitly requested by the user.
## Replies
- Be concise in your explanations - focus on what's important rather than explaining obvious details.
=== boost rules ===
# Laravel Boost
- Laravel Boost is an MCP server that comes with powerful tools designed specifically for this application. Use them.
## Artisan Commands
- Run Artisan commands directly via the command line (e.g., `php artisan route:list`, `php artisan tinker --execute "..."`).
- Use `php artisan list` to discover available commands and `php artisan [command] --help` to check parameters.
## URLs
- Whenever you share a project URL with the user, you should use the `get-absolute-url` tool to ensure you're using the correct scheme, domain/IP, and port.
## Debugging
- Use the `database-query` tool when you only need to read from the database.
- Use the `database-schema` tool to inspect table structure before writing migrations or models.
- To execute PHP code for debugging, run `php artisan tinker --execute "your code here"` directly.
- To read configuration values, read the config files directly or run `php artisan config:show [key]`.
- To inspect routes, run `php artisan route:list` directly.
- To check environment variables, read the `.env` file directly.
## Reading Browser Logs With the `browser-logs` Tool
- You can read browser logs, errors, and exceptions using the `browser-logs` tool from Boost.
- Only recent browser logs will be useful - ignore old logs.
## Searching Documentation (Critically Important)
- Boost comes with a powerful `search-docs` tool you should use before trying other approaches when working with Laravel or Laravel ecosystem packages. This tool automatically passes a list of installed packages and their versions to the remote Boost API, so it returns only version-specific documentation for the user's circumstance. You should pass an array of packages to filter on if you know you need docs for particular packages.
- Search the documentation before making code changes to ensure we are taking the correct approach.
- Use multiple, broad, simple, topic-based queries at once. For example: `['rate limiting', 'routing rate limiting', 'routing']`. The most relevant results will be returned first.
- Do not add package names to queries; package information is already shared. For example, use `test resource table`, not `filament 4 test resource table`.
### Available Search Syntax
1. Simple Word Searches with auto-stemming - query=authentication - finds 'authenticate' and 'auth'.
2. Multiple Words (AND Logic) - query=rate limit - finds knowledge containing both "rate" AND "limit".
3. Quoted Phrases (Exact Position) - query="infinite scroll" - words must be adjacent and in that order.
4. Mixed Queries - query=middleware "rate limit" - "middleware" AND exact phrase "rate limit".
5. Multiple Queries - queries=["authentication", "middleware"] - ANY of these terms.
=== php rules ===
# PHP
- Always use curly braces for control structures, even for single-line bodies.
## Constructors
- Use PHP 8 constructor property promotion in `__construct()`.
- `public function __construct(public GitHub $github) { }`
- Do not allow empty `__construct()` methods with zero parameters unless the constructor is private.
## Type Declarations
- Always use explicit return type declarations for methods and functions.
- Use appropriate PHP type hints for method parameters.
<!-- Explicit Return Types and Method Params -->
```php
protected function isAccessible(User $user, ?string $path = null): bool
{
...
}
```
## Enums
- Typically, keys in an Enum should be TitleCase. For example: `FavoritePerson`, `BestLake`, `Monthly`.
## Comments
- Prefer PHPDoc blocks over inline comments. Never use comments within the code itself unless the logic is exceptionally complex.
## PHPDoc Blocks
- Add useful array shape type definitions when appropriate.
=== herd rules ===
# Laravel Herd
- The application is served by Laravel Herd and will be available at: `https?://[kebab-case-project-dir].test`. Use the `get-absolute-url` tool to generate valid URLs for the user.
- You must not run any commands to make the site available via HTTP(S). It is always available through Laravel Herd.
=== tests rules ===
# Test Enforcement
- Every change must be programmatically tested. Write a new test or update an existing test, then run the affected tests to make sure they pass.
- Run the minimum number of tests needed to ensure code quality and speed. Use `php artisan test --compact` with a specific filename or filter.
=== laravel/core rules ===
# Do Things the Laravel Way
- Use `php artisan make:` commands to create new files (i.e. migrations, controllers, models, etc.). You can list available Artisan commands using `php artisan list` and check their parameters with `php artisan [command] --help`.
- If you're creating a generic PHP class, use `php artisan make:class`.
- Pass `--no-interaction` to all Artisan commands to ensure they work without user input. You should also pass the correct `--options` to ensure correct behavior.
## Database
- Always use proper Eloquent relationship methods with return type hints. Prefer relationship methods over raw queries or manual joins.
- Use Eloquent models and relationships before suggesting raw database queries.
- Avoid `DB::`; prefer `Model::query()`. Generate code that leverages Laravel's ORM capabilities rather than bypassing them.
- Generate code that prevents N+1 query problems by using eager loading.
- Use Laravel's query builder for very complex database operations.
### Model Creation
- When creating new models, create useful factories and seeders for them too. Ask the user if they need any other things, using `php artisan make:model --help` to check the available options.
### APIs & Eloquent Resources
- For APIs, default to using Eloquent API Resources and API versioning unless existing API routes do not, then you should follow existing application convention.
## Controllers & Validation
- Always create Form Request classes for validation rather than inline validation in controllers. Include both validation rules and custom error messages.
- Check sibling Form Requests to see if the application uses array or string based validation rules.
## Authentication & Authorization
- Use Laravel's built-in authentication and authorization features (gates, policies, Sanctum, etc.).
## URL Generation
- When generating links to other pages, prefer named routes and the `route()` function.
## Queues
- Use queued jobs for time-consuming operations with the `ShouldQueue` interface.
## Configuration
- Use environment variables only in configuration files - never use the `env()` function directly outside of config files. Always use `config('app.name')`, not `env('APP_NAME')`.
## Testing
- When creating models for tests, use the factories for the models. Check if the factory has custom states that can be used before manually setting up the model.
- Faker: Use methods such as `$this->faker->word()` or `fake()->randomDigit()`. Follow existing conventions whether to use `$this->faker` or `fake()`.
- When creating tests, make use of `php artisan make:test [options] {name}` to create a feature test, and pass `--unit` to create a unit test. Most tests should be feature tests.
## Vite Error
- If you receive an "Illuminate\Foundation\ViteException: Unable to locate file in Vite manifest" error, you can run `npm run build` or ask the user to run `npm run dev` or `composer run dev`.
=== pint/core rules ===
# Laravel Pint Code Formatter
- If you have modified any PHP files, you must run `vendor/bin/pint --dirty --format agent` before finalizing changes to ensure your code matches the project's expected style.
- Do not run `vendor/bin/pint --test --format agent`, simply run `vendor/bin/pint --format agent` to fix any formatting issues.
=== pest/core rules ===
## Pest
- This project uses Pest for testing. Create tests: `php artisan make:test --pest {name}`.
- Run tests: `php artisan test --compact` or filter: `php artisan test --compact --filter=testName`.
- Do NOT delete tests without approval.
=== spatie/laravel-medialibrary rules ===
## Media Library
- `spatie/laravel-medialibrary` associates files with Eloquent models, with support for collections, conversions, and responsive images.
- Always activate the `medialibrary-development` skill when working with media uploads, conversions, collections, responsive images, or any code that uses the `HasMedia` interface or `InteractsWithMedia` trait.
</laravel-boost-guidelines>

View File

@@ -2,4 +2,6 @@
## Reporting a Vulnerability
Please email security@invoiceshelf.com to report any security vulnerabilities. We will acknowledge receipt of your vulnerability and strive to send you regular updates about our progress. If you're curious about the status of your disclosure please feel free to email us again.
Please email **security@invoiceshelf.com** and cc **security@griffin-web.studio** to report any security vulnerabilities. In the unlikely event that you havent heard back, try reaching out on Discord to one of our moderators.
We will acknowledge receipt of your report and strive to provide regular updates on our progress. If you're curious about the status of your disclosure, please feel free to email us again.

View File

@@ -24310,157 +24310,6 @@ namespace Spatie\SignalAwareCommand\Facades {
}
}
namespace Vinkla\Hashids\Facades {
/**
*
*
* @method static string encode(mixed ...$numbers)
* @method static array decode(string $hash)
* @method static string encodeHex(string $str)
* @method static string decodeHex(string $hash)
*/
class Hashids {
/**
*
*
* @static
*/
public static function getFactory()
{
/** @var \Vinkla\Hashids\HashidsManager $instance */
return $instance->getFactory();
}
/**
* Get a connection instance.
*
* @param string|null $name
* @throws \InvalidArgumentException
* @return object
* @static
*/
public static function connection($name = null)
{
//Method inherited from \GrahamCampbell\Manager\AbstractManager
/** @var \Vinkla\Hashids\HashidsManager $instance */
return $instance->connection($name);
}
/**
* Reconnect to the given connection.
*
* @param string|null $name
* @throws \InvalidArgumentException
* @return object
* @static
*/
public static function reconnect($name = null)
{
//Method inherited from \GrahamCampbell\Manager\AbstractManager
/** @var \Vinkla\Hashids\HashidsManager $instance */
return $instance->reconnect($name);
}
/**
* Disconnect from the given connection.
*
* @param string|null $name
* @return void
* @static
*/
public static function disconnect($name = null)
{
//Method inherited from \GrahamCampbell\Manager\AbstractManager
/** @var \Vinkla\Hashids\HashidsManager $instance */
$instance->disconnect($name);
}
/**
* Get the configuration for a connection.
*
* @param string|null $name
* @throws \InvalidArgumentException
* @return array
* @static
*/
public static function getConnectionConfig($name = null)
{
//Method inherited from \GrahamCampbell\Manager\AbstractManager
/** @var \Vinkla\Hashids\HashidsManager $instance */
return $instance->getConnectionConfig($name);
}
/**
* Get the default connection name.
*
* @return string
* @static
*/
public static function getDefaultConnection()
{
//Method inherited from \GrahamCampbell\Manager\AbstractManager
/** @var \Vinkla\Hashids\HashidsManager $instance */
return $instance->getDefaultConnection();
}
/**
* Set the default connection name.
*
* @param string $name
* @return void
* @static
*/
public static function setDefaultConnection($name)
{
//Method inherited from \GrahamCampbell\Manager\AbstractManager
/** @var \Vinkla\Hashids\HashidsManager $instance */
$instance->setDefaultConnection($name);
}
/**
* Register an extension connection resolver.
*
* @param string $name
* @param callable $resolver
* @return void
* @static
*/
public static function extend($name, $resolver)
{
//Method inherited from \GrahamCampbell\Manager\AbstractManager
/** @var \Vinkla\Hashids\HashidsManager $instance */
$instance->extend($name, $resolver);
}
/**
* Return all of the created connections.
*
* @return array<string,object>
* @static
*/
public static function getConnections()
{
//Method inherited from \GrahamCampbell\Manager\AbstractManager
/** @var \Vinkla\Hashids\HashidsManager $instance */
return $instance->getConnections();
}
/**
* Get the config instance.
*
* @return \Illuminate\Contracts\Config\Repository
* @static
*/
public static function getConfig()
{
//Method inherited from \GrahamCampbell\Manager\AbstractManager
/** @var \Vinkla\Hashids\HashidsManager $instance */
return $instance->getConfig();
}
}
}
namespace Illuminate\Http {
/**
*
@@ -28936,7 +28785,7 @@ namespace {
class Bouncer extends \Silber\Bouncer\BouncerFacade {}
class Flare extends \Spatie\LaravelIgnition\Facades\Flare {}
class Signal extends \Spatie\SignalAwareCommand\Facades\Signal {}
class Hashids extends \Vinkla\Hashids\Facades\Hashids {}
class Hashids extends \App\Facades\Hashids {}
}

View File

@@ -4,6 +4,7 @@ namespace App\Console\Commands;
use App\Space\Updater;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\File;
// Implementation taken from Akaunting - https://github.com/akaunting/akaunting
class UpdateCommand extends Command

22
app/Facades/Hashids.php Normal file
View File

@@ -0,0 +1,22 @@
<?php
declare(strict_types=1);
namespace App\Facades;
use Illuminate\Support\Facades\Facade;
/**
* @method static string encode(mixed ...$numbers)
* @method static array decode(string $hash)
* @method static string encodeHex(string $str)
* @method static string decodeHex(string $hash)
* @method static \Hashids\Hashids connection(string|null $name = null)
*/
class Hashids extends Facade
{
protected static function getFacadeAccessor(): string
{
return 'hashids';
}
}

View File

@@ -0,0 +1,35 @@
<?php
declare(strict_types=1);
namespace App\Hashids;
use Hashids\Hashids;
use Illuminate\Support\Arr;
class HashidsFactory
{
public function make(array $config): Hashids
{
$config = $this->getConfig($config);
return $this->getClient($config);
}
/**
* @return array{salt: string, length: int, alphabet: string}
*/
protected function getConfig(array $config): array
{
return [
'salt' => Arr::get($config, 'salt', ''),
'length' => Arr::get($config, 'length', 0),
'alphabet' => Arr::get($config, 'alphabet', 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'),
];
}
protected function getClient(array $config): Hashids
{
return new Hashids($config['salt'], $config['length'], $config['alphabet']);
}
}

View File

@@ -0,0 +1,72 @@
<?php
declare(strict_types=1);
namespace App\Hashids;
use Hashids\Hashids;
use Illuminate\Contracts\Config\Repository;
use InvalidArgumentException;
/**
* Resolves named Hashids clients from config/hashids.php (one "connection" per model class).
*
* @method string encode(mixed ...$numbers)
* @method array decode(string $hash)
* @method string encodeHex(string $str)
* @method string decodeHex(string $hash)
*/
class HashidsManager
{
/**
* @var array<string, Hashids>
*/
protected array $connections = [];
public function __construct(
protected Repository $config,
protected HashidsFactory $factory
) {}
public function connection(?string $name = null): Hashids
{
$name = $name ?? $this->getDefaultConnection();
if (! isset($this->connections[$name])) {
$this->connections[$name] = $this->factory->make(
$this->getConnectionConfig($name)
);
}
return $this->connections[$name];
}
public function getDefaultConnection(): string
{
return (string) $this->config->get('hashids.default');
}
public function getFactory(): HashidsFactory
{
return $this->factory;
}
/**
* @return array<string, mixed>
*/
protected function getConnectionConfig(string $name): array
{
$connections = $this->config->get('hashids.connections', []);
if (! is_array($connections) || ! isset($connections[$name])) {
throw new InvalidArgumentException("Hashids connection [{$name}] not configured.");
}
return $connections[$name];
}
public function __call(string $method, array $parameters): mixed
{
return $this->connection()->$method(...$parameters);
}
}

View File

@@ -0,0 +1,45 @@
<?php
declare(strict_types=1);
namespace App\Hashids;
use Hashids\Hashids as HashidsClient;
use Illuminate\Contracts\Container\Container;
use Illuminate\Support\ServiceProvider;
class HashidsServiceProvider extends ServiceProvider
{
public function register(): void
{
$this->app->singleton('hashids.factory', function () {
return new HashidsFactory;
});
$this->app->alias('hashids.factory', HashidsFactory::class);
$this->app->singleton('hashids', function (Container $app) {
return new HashidsManager($app['config'], $app['hashids.factory']);
});
$this->app->alias('hashids', HashidsManager::class);
$this->app->bind('hashids.connection', function (Container $app) {
return $app['hashids']->connection();
});
$this->app->alias('hashids.connection', HashidsClient::class);
}
/**
* @return list<string>
*/
public function provides(): array
{
return [
'hashids',
'hashids.factory',
'hashids.connection',
];
}
}

View File

@@ -3,6 +3,7 @@
namespace App\Http\Controllers;
use App\Models\Setting;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\File;
@@ -11,7 +12,7 @@ class AppVersionController extends Controller
/**
* Handle the incoming request.
*
* @return \Illuminate\Http\JsonResponse
* @return JsonResponse
*/
public function __invoke(Request $request)
{

View File

@@ -4,6 +4,8 @@ namespace App\Http\Controllers\V1\Admin\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class ForgotPasswordController extends Controller
@@ -25,7 +27,7 @@ class ForgotPasswordController extends Controller
* Get the response for a successful password reset link.
*
* @param string $response
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse
* @return RedirectResponse|JsonResponse
*/
protected function sendResetLinkResponse(Request $request, $response)
{
@@ -39,7 +41,7 @@ class ForgotPasswordController extends Controller
* Get the response for a failed password reset link.
*
* @param string $response
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse
* @return RedirectResponse|JsonResponse
*/
protected function sendResetLinkFailedResponse(Request $request, $response)
{

View File

@@ -5,7 +5,10 @@ namespace App\Http\Controllers\V1\Admin\Auth;
use App\Http\Controllers\Controller;
use App\Providers\AppServiceProvider;
use Illuminate\Auth\Events\PasswordReset;
use Illuminate\Contracts\Auth\CanResetPassword;
use Illuminate\Foundation\Auth\ResetsPasswords;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
@@ -35,7 +38,7 @@ class ResetPasswordController extends Controller
* Get the response for a successful password reset.
*
* @param string $response
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse
* @return RedirectResponse|JsonResponse
*/
protected function sendResetResponse(Request $request, $response)
{
@@ -47,7 +50,7 @@ class ResetPasswordController extends Controller
/**
* Reset the given user's password.
*
* @param \Illuminate\Contracts\Auth\CanResetPassword $user
* @param CanResetPassword $user
* @param string $password
* @return void
*/
@@ -66,7 +69,7 @@ class ResetPasswordController extends Controller
* Get the response for a failed password reset.
*
* @param string $response
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse
* @return RedirectResponse|JsonResponse
*/
protected function sendResetFailedResponse(Request $request, $response)
{

View File

@@ -2,6 +2,7 @@
namespace App\Http\Controllers\V1\Admin\Company;
use App\Facades\Hashids;
use App\Http\Controllers\Controller;
use App\Http\Requests\CompaniesRequest;
use App\Http\Resources\CompanyResource;
@@ -9,7 +10,6 @@ use App\Models\Company;
use App\Models\User;
use Illuminate\Http\Request;
use Silber\Bouncer\BouncerFacade;
use Vinkla\Hashids\Facades\Hashids;
class CompaniesController extends Controller
{

View File

@@ -6,13 +6,14 @@ use App\Http\Controllers\Controller;
use App\Http\Resources\CompanyResource;
use App\Models\Company;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class CompanyController extends Controller
{
/**
* Handle the incoming request.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function __invoke(Request $request)
{

View File

@@ -4,13 +4,14 @@ namespace App\Http\Controllers\V1\Admin\Config;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class FiscalYearsController extends Controller
{
/**
* Handle the incoming request.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function __invoke(Request $request)
{

View File

@@ -4,13 +4,14 @@ namespace App\Http\Controllers\V1\Admin\Config;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class LanguagesController extends Controller
{
/**
* Handle the incoming request.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function __invoke(Request $request)
{

View File

@@ -4,13 +4,14 @@ namespace App\Http\Controllers\V1\Admin\Config;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class RetrospectiveEditsController extends Controller
{
/**
* Handle the incoming request.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function __invoke(Request $request)
{

View File

@@ -7,13 +7,14 @@ use App\Http\Requests\CustomFieldRequest;
use App\Http\Resources\CustomFieldResource;
use App\Models\CustomField;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class CustomFieldsController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function index(Request $request)
{
@@ -33,7 +34,7 @@ class CustomFieldsController extends Controller
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\CustomFieldRequest $request
* @return \Illuminate\Http\Response
* @return Response
*/
public function store(CustomFieldRequest $request)
{
@@ -48,7 +49,7 @@ class CustomFieldsController extends Controller
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
* @return Response
*/
public function show(CustomField $customField)
{
@@ -60,9 +61,9 @@ class CustomFieldsController extends Controller
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param Request $request
* @param int $id
* @return \Illuminate\Http\Response
* @return Response
*/
public function update(CustomFieldRequest $request, CustomField $customField)
{
@@ -77,7 +78,7 @@ class CustomFieldsController extends Controller
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
* @return Response
*/
public function destroy(CustomField $customField)
{

View File

@@ -11,13 +11,14 @@ use App\Models\Invoice;
use App\Models\Payment;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class CustomerStatsController extends Controller
{
/**
* Handle the incoming request.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function __invoke(Request $request, Customer $customer)
{
@@ -61,7 +62,7 @@ class CustomerStatsController extends Controller
)
->whereCompany()
->whereCustomer($customer->id)
->sum('total') ?? 0
->sum('base_total') ?? 0
);
array_push(
$expenseTotals,
@@ -71,7 +72,7 @@ class CustomerStatsController extends Controller
)
->whereCompany()
->whereUser($customer->id)
->sum('amount') ?? 0
->sum('base_amount') ?? 0
);
array_push(
$receiptTotals,
@@ -81,7 +82,7 @@ class CustomerStatsController extends Controller
)
->whereCompany()
->whereCustomer($customer->id)
->sum('amount') ?? 0
->sum('base_amount') ?? 0
);
array_push(
$netProfits,
@@ -103,21 +104,21 @@ class CustomerStatsController extends Controller
)
->whereCompany()
->whereCustomer($customer->id)
->sum('total');
->sum('base_total');
$totalReceipts = Payment::whereBetween(
'payment_date',
[$startDate->format('Y-m-d'), $start->format('Y-m-d')]
)
->whereCompany()
->whereCustomer($customer->id)
->sum('amount');
->sum('base_amount');
$totalExpenses = Expense::whereBetween(
'expense_date',
[$startDate->format('Y-m-d'), $start->format('Y-m-d')]
)
->whereCompany()
->whereUser($customer->id)
->sum('amount');
->sum('base_amount');
$netProfit = (int) $totalReceipts - (int) $totalExpenses;
$chartData = [

View File

@@ -7,15 +7,15 @@ use App\Http\Requests;
use App\Http\Requests\DeleteCustomersRequest;
use App\Http\Resources\CustomerResource;
use App\Models\Customer;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class CustomersController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\JsonResponse
* @return JsonResponse
*/
public function index(Request $request)
{
@@ -26,13 +26,8 @@ class CustomersController extends Controller
$customers = Customer::with('creator')
->whereCompany()
->applyFilters($request->all())
->select(
'customers.*',
DB::raw('sum(invoices.base_due_amount) as base_due_amount'),
DB::raw('sum(invoices.due_amount) as due_amount'),
)
->groupBy('customers.id')
->leftJoin('invoices', 'customers.id', '=', 'invoices.customer_id')
->withSum('invoices as base_due_amount', 'base_due_amount')
->withSum('invoices as due_amount', 'due_amount')
->paginateData($limit);
return CustomerResource::collection($customers)
@@ -44,8 +39,8 @@ class CustomersController extends Controller
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
* @param Request $request
* @return JsonResponse
*/
public function store(Requests\CustomerRequest $request)
{
@@ -59,7 +54,7 @@ class CustomersController extends Controller
/**
* Display the specified resource.
*
* @return \Illuminate\Http\JsonResponse
* @return JsonResponse
*/
public function show(Customer $customer)
{
@@ -71,8 +66,8 @@ class CustomersController extends Controller
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
* @param Request $request
* @return JsonResponse
*/
public function update(Requests\CustomerRequest $request, Customer $customer)
{
@@ -90,8 +85,8 @@ class CustomersController extends Controller
/**
* Remove a list of Customers along side all their resources (ie. Estimates, Invoices, Payments and Addresses)
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
* @param Request $request
* @return JsonResponse
*/
public function delete(DeleteCustomersRequest $request)
{

View File

@@ -11,6 +11,7 @@ use App\Models\Expense;
use App\Models\Invoice;
use App\Models\Payment;
use Carbon\Carbon;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Silber\Bouncer\BouncerFacade;
@@ -19,7 +20,7 @@ class DashboardController extends Controller
/**
* Handle the incoming request.
*
* @return \Illuminate\Http\JsonResponse
* @return JsonResponse
*/
public function __invoke(Request $request)
{

View File

@@ -5,13 +5,14 @@ namespace App\Http\Controllers\V1\Admin\Estimate;
use App\Http\Controllers\Controller;
use App\Models\Estimate;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class ChangeEstimateStatusController extends Controller
{
/**
* Handle the incoming request.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function __invoke(Request $request, Estimate $estimate)
{

View File

@@ -2,21 +2,22 @@
namespace App\Http\Controllers\V1\Admin\Estimate;
use App\Facades\Hashids;
use App\Http\Controllers\Controller;
use App\Http\Resources\EstimateResource;
use App\Models\CompanySetting;
use App\Models\Estimate;
use App\Services\SerialNumberFormatter;
use Carbon\Carbon;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Vinkla\Hashids\Facades\Hashids;
class CloneEstimateController extends Controller
{
/**
* Mail a specific invoice to the corresponding customer's email address.
*
* @return \Illuminate\Http\JsonResponse
* @return JsonResponse
*/
public function __invoke(Request $request, Estimate $estimate)
{

View File

@@ -2,6 +2,7 @@
namespace App\Http\Controllers\V1\Admin\Estimate;
use App\Facades\Hashids;
use App\Http\Controllers\Controller;
use App\Http\Resources\InvoiceResource;
use App\Models\CompanySetting;
@@ -10,15 +11,15 @@ use App\Models\Invoice;
use App\Services\SerialNumberFormatter;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Auth;
use Vinkla\Hashids\Facades\Hashids;
class ConvertEstimateController extends Controller
{
/**
* Handle the incoming request.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function __invoke(Request $request, Estimate $estimate, Invoice $invoice)
{

View File

@@ -5,13 +5,14 @@ namespace App\Http\Controllers\V1\Admin\Estimate;
use App\Http\Controllers\Controller;
use App\Http\Requests\SendEstimatesRequest;
use App\Models\Estimate;
use Illuminate\Http\JsonResponse;
class SendEstimateController extends Controller
{
/**
* Handle the incoming request.
*
* @return \Illuminate\Http\JsonResponse
* @return JsonResponse
*/
public function __invoke(SendEstimatesRequest $request, Estimate $estimate)
{

View File

@@ -5,6 +5,7 @@ namespace App\Http\Controllers\V1\Admin\Estimate;
use App\Http\Controllers\Controller;
use App\Http\Requests\SendEstimatesRequest;
use App\Models\Estimate;
use Illuminate\Http\JsonResponse;
use Illuminate\Mail\Markdown;
class SendEstimatePreviewController extends Controller
@@ -12,7 +13,7 @@ class SendEstimatePreviewController extends Controller
/**
* Handle the incoming request.
*
* @return \Illuminate\Http\JsonResponse
* @return JsonResponse
*/
public function __invoke(SendEstimatesRequest $request, Estimate $estimate)
{

View File

@@ -7,13 +7,14 @@ use App\Http\Requests\ExchangeRateProviderRequest;
use App\Http\Resources\ExchangeRateProviderResource;
use App\Models\ExchangeRateProvider;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class ExchangeRateProviderController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function index(Request $request)
{
@@ -29,8 +30,8 @@ class ExchangeRateProviderController extends Controller
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
* @param Request $request
* @return Response
*/
public function store(ExchangeRateProviderRequest $request)
{
@@ -56,7 +57,7 @@ class ExchangeRateProviderController extends Controller
/**
* Display the specified resource.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function show(ExchangeRateProvider $exchangeRateProvider)
{
@@ -68,8 +69,8 @@ class ExchangeRateProviderController extends Controller
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
* @param Request $request
* @return Response
*/
public function update(ExchangeRateProviderRequest $request, ExchangeRateProvider $exchangeRateProvider)
{
@@ -95,7 +96,7 @@ class ExchangeRateProviderController extends Controller
/**
* Remove the specified resource from storage.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function destroy(ExchangeRateProvider $exchangeRateProvider)
{

View File

@@ -6,13 +6,14 @@ use App\Http\Controllers\Controller;
use App\Models\Currency;
use App\Models\ExchangeRateProvider;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class GetActiveProviderController extends Controller
{
/**
* Handle the incoming request.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function __invoke(Request $request, Currency $currency)
{

View File

@@ -9,6 +9,7 @@ use App\Models\ExchangeRateLog;
use App\Models\ExchangeRateProvider;
use App\Traits\ExchangeRateProvidersTrait;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Arr;
class GetExchangeRateController extends Controller
@@ -18,7 +19,7 @@ class GetExchangeRateController extends Controller
/**
* Handle the incoming request.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function __invoke(Request $request, Currency $currency)
{

View File

@@ -6,6 +6,7 @@ use App\Http\Controllers\Controller;
use App\Models\ExchangeRateProvider;
use App\Traits\ExchangeRateProvidersTrait;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class GetSupportedCurrenciesController extends Controller
{
@@ -14,7 +15,7 @@ class GetSupportedCurrenciesController extends Controller
/**
* Handle the incoming request.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function __invoke(Request $request)
{

View File

@@ -5,13 +5,14 @@ namespace App\Http\Controllers\V1\Admin\ExchangeRate;
use App\Http\Controllers\Controller;
use App\Models\ExchangeRateProvider;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class GetUsedCurrenciesController extends Controller
{
/**
* Handle the incoming request.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function __invoke(Request $request)
{

View File

@@ -2,18 +2,20 @@
namespace App\Http\Controllers\V1\Admin\Expense;
use App\ExpensesCategory;
use App\Http\Controllers\Controller;
use App\Http\Requests\ExpenseCategoryRequest;
use App\Http\Resources\ExpenseCategoryResource;
use App\Models\ExpenseCategory;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class ExpenseCategoriesController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function index(Request $request)
{
@@ -32,8 +34,8 @@ class ExpenseCategoriesController extends Controller
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
* @param Request $request
* @return Response
*/
public function store(ExpenseCategoryRequest $request)
{
@@ -47,7 +49,7 @@ class ExpenseCategoriesController extends Controller
/**
* Display the specified resource.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function show(ExpenseCategory $category)
{
@@ -59,9 +61,9 @@ class ExpenseCategoriesController extends Controller
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param \App\Models\ExpenseCategory $ExpenseCategory
* @return \Illuminate\Http\Response
* @param Request $request
* @param ExpenseCategory $ExpenseCategory
* @return Response
*/
public function update(ExpenseCategoryRequest $request, ExpenseCategory $category)
{
@@ -75,8 +77,8 @@ class ExpenseCategoriesController extends Controller
/**
* Remove the specified resource from storage.
*
* @param \App\ExpensesCategory $category
* @return \Illuminate\Http\Response
* @param ExpensesCategory $category
* @return Response
*/
public function destroy(ExpenseCategory $category)
{

View File

@@ -7,6 +7,7 @@ use App\Http\Requests\DeleteExpensesRequest;
use App\Http\Requests\ExpenseRequest;
use App\Http\Resources\ExpenseResource;
use App\Models\Expense;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class ExpensesController extends Controller
@@ -14,7 +15,7 @@ class ExpensesController extends Controller
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\JsonResponse
* @return JsonResponse
*/
public function index(Request $request)
{
@@ -39,7 +40,7 @@ class ExpensesController extends Controller
/**
* Store a newly created resource in storage.
*
* @return \Illuminate\Http\JsonResponse
* @return JsonResponse
*/
public function store(ExpenseRequest $request)
{
@@ -53,7 +54,7 @@ class ExpensesController extends Controller
/**
* Display the specified resource.
*
* @return \Illuminate\Http\JsonResponse
* @return JsonResponse
*/
public function show(Expense $expense)
{
@@ -65,7 +66,7 @@ class ExpensesController extends Controller
/**
* Update the specified resource in storage.
*
* @return \Illuminate\Http\JsonResponse
* @return JsonResponse
*/
public function update(ExpenseRequest $request, Expense $expense)
{

View File

@@ -4,13 +4,14 @@ namespace App\Http\Controllers\V1\Admin\Expense;
use App\Http\Controllers\Controller;
use App\Models\Expense;
use Illuminate\Http\JsonResponse;
class ShowReceiptController extends Controller
{
/**
* Retrieve details of an expense receipt from storage.
*
* @return \Illuminate\Http\JsonResponse
* @return JsonResponse
*/
public function __invoke(Expense $expense)
{

View File

@@ -3,16 +3,18 @@
namespace App\Http\Controllers\V1\Admin\Expense;
use App\Http\Controllers\Controller;
use App\Http\Requests\ExpenseRequest;
use App\Http\Requests\UploadExpenseReceiptRequest;
use App\Models\Expense;
use Illuminate\Http\JsonResponse;
class UploadReceiptController extends Controller
{
/**
* Upload the expense receipts to storage.
*
* @param \App\Http\Requests\ExpenseRequest $request
* @return \Illuminate\Http\JsonResponse
* @param ExpenseRequest $request
* @return JsonResponse
*/
public function __invoke(UploadExpenseReceiptRequest $request, Expense $expense)
{

View File

@@ -11,6 +11,7 @@ use App\Models\Currency;
use App\Models\Module;
use App\Models\Setting;
use App\Traits\GeneratesMenuTrait;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Silber\Bouncer\BouncerFacade;
@@ -21,7 +22,7 @@ class BootstrapController extends Controller
/**
* Handle the incoming request.
*
* @return \Illuminate\Http\JsonResponse
* @return JsonResponse
*/
public function __invoke(Request $request)
{

View File

@@ -9,14 +9,16 @@ use App\Models\Estimate;
use App\Models\Invoice;
use App\Models\Payment;
use App\Models\Tax;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class BulkExchangeRateController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
* @param Request $request
* @return Response
*/
public function __invoke(BulkExchangeRateRequest $request)
{

View File

@@ -4,13 +4,14 @@ namespace App\Http\Controllers\V1\Admin\General;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class ConfigController extends Controller
{
/**
* Handle the incoming request.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function __invoke(Request $request)
{

View File

@@ -5,6 +5,7 @@ namespace App\Http\Controllers\V1\Admin\General;
use App\Http\Controllers\Controller;
use App\Http\Resources\CountryResource;
use App\Models\Country;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class CountriesController extends Controller
@@ -12,7 +13,7 @@ class CountriesController extends Controller
/**
* Handle the incoming request.
*
* @return \Illuminate\Http\JsonResponse
* @return JsonResponse
*/
public function __invoke(Request $request)
{

View File

@@ -6,13 +6,14 @@ use App\Http\Controllers\Controller;
use App\Http\Resources\CurrencyResource;
use App\Models\Currency;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class CurrenciesController extends Controller
{
/**
* Handle the incoming request.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function __invoke(Request $request)
{

View File

@@ -5,13 +5,14 @@ namespace App\Http\Controllers\V1\Admin\General;
use App\Http\Controllers\Controller;
use App\Space\DateFormatter;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class DateFormatsController extends Controller
{
/**
* Handle the incoming request.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function __invoke(Request $request)
{

View File

@@ -9,13 +9,14 @@ use App\Models\Invoice;
use App\Models\Payment;
use App\Models\Tax;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class GetAllUsedCurrenciesController extends Controller
{
/**
* Handle the incoming request.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function __invoke(Request $request)
{

View File

@@ -8,13 +8,14 @@ use App\Models\Invoice;
use App\Models\Payment;
use App\Services\SerialNumberFormatter;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class NextNumberController extends Controller
{
/**
* Handle the incoming request.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function __invoke(Request $request, Invoice $invoice, Estimate $estimate, Payment $payment)
{

View File

@@ -7,13 +7,14 @@ use App\Http\Requests\NotesRequest;
use App\Http\Resources\NoteResource;
use App\Models\Note;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class NotesController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function index(Request $request)
{
@@ -32,8 +33,8 @@ class NotesController extends Controller
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
* @param Request $request
* @return Response
*/
public function store(NotesRequest $request)
{
@@ -56,7 +57,7 @@ class NotesController extends Controller
/**
* Display the specified resource.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function show(Note $note)
{
@@ -68,8 +69,8 @@ class NotesController extends Controller
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
* @param Request $request
* @return Response
*/
public function update(NotesRequest $request, Note $note)
{
@@ -92,7 +93,7 @@ class NotesController extends Controller
/**
* Remove the specified resource from storage.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function destroy(Note $note)
{

View File

@@ -5,13 +5,14 @@ namespace App\Http\Controllers\V1\Admin\General;
use App\Http\Controllers\Controller;
use App\Services\SerialNumberFormatter;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class NumberPlaceholdersController extends Controller
{
/**
* Handle the incoming request.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function __invoke(Request $request)
{

View File

@@ -6,13 +6,14 @@ use App\Http\Controllers\Controller;
use App\Models\Customer;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class SearchController extends Controller
{
/**
* Handle the incoming request.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function __invoke(Request $request)
{

View File

@@ -5,13 +5,14 @@ namespace App\Http\Controllers\V1\Admin\General;
use App\Http\Controllers\Controller;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class SearchUsersController extends Controller
{
/**
* Handle the incoming request.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function __invoke(Request $request)
{

View File

@@ -5,13 +5,14 @@ namespace App\Http\Controllers\V1\Admin\General;
use App\Http\Controllers\Controller;
use App\Space\TimeFormatter;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class TimeFormatsController extends Controller
{
/**
* Handle the incoming request.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function __invoke(Request $request)
{

View File

@@ -5,13 +5,14 @@ namespace App\Http\Controllers\V1\Admin\General;
use App\Http\Controllers\Controller;
use App\Space\TimeZones;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class TimezonesController extends Controller
{
/**
* Handle the incoming request.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function __invoke(Request $request)
{

View File

@@ -4,6 +4,7 @@ namespace App\Http\Controllers\V1\Admin\Invoice;
use App\Http\Controllers\Controller;
use App\Models\Invoice;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class ChangeInvoiceStatusController extends Controller
@@ -11,7 +12,7 @@ class ChangeInvoiceStatusController extends Controller
/**
* Handle the incoming request.
*
* @return \Illuminate\Http\JsonResponse
* @return JsonResponse
*/
public function __invoke(Request $request, Invoice $invoice)
{

View File

@@ -2,21 +2,22 @@
namespace App\Http\Controllers\V1\Admin\Invoice;
use App\Facades\Hashids;
use App\Http\Controllers\Controller;
use App\Http\Resources\InvoiceResource;
use App\Models\CompanySetting;
use App\Models\Invoice;
use App\Services\SerialNumberFormatter;
use Carbon\Carbon;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Vinkla\Hashids\Facades\Hashids;
class CloneInvoiceController extends Controller
{
/**
* Mail a specific invoice to the corresponding customer's email address.
*
* @return \Illuminate\Http\JsonResponse
* @return JsonResponse
*/
public function __invoke(Request $request, Invoice $invoice)
{

View File

@@ -8,6 +8,7 @@ use App\Http\Requests\DeleteInvoiceRequest;
use App\Http\Resources\InvoiceResource;
use App\Jobs\GenerateInvoicePdfJob;
use App\Models\Invoice;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class InvoicesController extends Controller
@@ -15,7 +16,7 @@ class InvoicesController extends Controller
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\JsonResponse
* @return JsonResponse
*/
public function index(Request $request)
{
@@ -38,8 +39,8 @@ class InvoicesController extends Controller
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
* @param Request $request
* @return JsonResponse
*/
public function store(Requests\InvoicesRequest $request)
{
@@ -59,7 +60,7 @@ class InvoicesController extends Controller
/**
* Display the specified resource.
*
* @return \Illuminate\Http\JsonResponse
* @return JsonResponse
*/
public function show(Request $request, Invoice $invoice)
{
@@ -71,8 +72,8 @@ class InvoicesController extends Controller
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
* @param Request $request
* @return JsonResponse
*/
public function update(Requests\InvoicesRequest $request, Invoice $invoice)
{
@@ -92,8 +93,8 @@ class InvoicesController extends Controller
/**
* delete the specified resources in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
* @param Request $request
* @return JsonResponse
*/
public function delete(DeleteInvoiceRequest $request)
{

View File

@@ -5,14 +5,16 @@ namespace App\Http\Controllers\V1\Admin\Invoice;
use App\Http\Controllers\Controller;
use App\Http\Requests\SendInvoiceRequest;
use App\Models\Invoice;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class SendInvoiceController extends Controller
{
/**
* Mail a specific invoice to the corresponding customer's email address.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
* @param Request $request
* @return JsonResponse
*/
public function __invoke(SendInvoiceRequest $request, Invoice $invoice)
{

View File

@@ -5,6 +5,8 @@ namespace App\Http\Controllers\V1\Admin\Invoice;
use App\Http\Controllers\Controller;
use App\Http\Requests\SendInvoiceRequest;
use App\Models\Invoice;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Mail\Markdown;
class SendInvoicePreviewController extends Controller
@@ -12,8 +14,8 @@ class SendInvoicePreviewController extends Controller
/**
* Mail a specific invoice to the corresponding customer's email address.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
* @param Request $request
* @return JsonResponse
*/
public function __invoke(SendInvoiceRequest $request, Invoice $invoice)
{

View File

@@ -8,6 +8,7 @@ use App\Http\Requests\DeleteItemsRequest;
use App\Http\Resources\ItemResource;
use App\Models\Item;
use App\Models\TaxType;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class ItemsController extends Controller
@@ -15,7 +16,7 @@ class ItemsController extends Controller
/**
* Retrieve a list of existing Items.
*
* @return \Illuminate\Http\JsonResponse
* @return JsonResponse
*/
public function index(Request $request)
{
@@ -41,7 +42,7 @@ class ItemsController extends Controller
* Create Item.
*
* @param App\Http\Requests\ItemsRequest $request
* @return \Illuminate\Http\JsonResponse
* @return JsonResponse
*/
public function store(Requests\ItemsRequest $request)
{
@@ -55,7 +56,7 @@ class ItemsController extends Controller
/**
* get an existing Item.
*
* @return \Illuminate\Http\JsonResponse
* @return JsonResponse
*/
public function show(Item $item)
{
@@ -68,7 +69,7 @@ class ItemsController extends Controller
* Update an existing Item.
*
* @param App\Http\Requests\ItemsRequest $request
* @return \Illuminate\Http\JsonResponse
* @return JsonResponse
*/
public function update(Requests\ItemsRequest $request, Item $item)
{
@@ -82,8 +83,8 @@ class ItemsController extends Controller
/**
* Delete a list of existing Items.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
* @param Request $request
* @return JsonResponse
*/
public function delete(DeleteItemsRequest $request)
{

View File

@@ -7,13 +7,14 @@ use App\Http\Requests\UnitRequest;
use App\Http\Resources\UnitResource;
use App\Models\Unit;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class UnitsController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function index(Request $request)
{
@@ -32,8 +33,8 @@ class UnitsController extends Controller
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
* @param Request $request
* @return Response
*/
public function store(UnitRequest $request)
{
@@ -47,7 +48,7 @@ class UnitsController extends Controller
/**
* Display the specified resource.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function show(Unit $unit)
{
@@ -59,8 +60,8 @@ class UnitsController extends Controller
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
* @param Request $request
* @return Response
*/
public function update(UnitRequest $request, Unit $unit)
{
@@ -74,7 +75,7 @@ class UnitsController extends Controller
/**
* Remove the specified resource from storage.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function destroy(Unit $unit)
{

View File

@@ -5,13 +5,14 @@ namespace App\Http\Controllers\V1\Admin\Modules;
use App\Http\Controllers\Controller;
use App\Space\ModuleInstaller;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class ApiTokenController extends Controller
{
/**
* Handle the incoming request.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function __invoke(Request $request)
{

View File

@@ -5,13 +5,14 @@ namespace App\Http\Controllers\V1\Admin\Modules;
use App\Http\Controllers\Controller;
use App\Space\ModuleInstaller;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class CompleteModuleInstallationController extends Controller
{
/**
* Handle the incoming request.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function __invoke(Request $request)
{

View File

@@ -5,13 +5,14 @@ namespace App\Http\Controllers\V1\Admin\Modules;
use App\Http\Controllers\Controller;
use App\Space\ModuleInstaller;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class CopyModuleController extends Controller
{
/**
* Handle the incoming request.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function __invoke(Request $request)
{

View File

@@ -6,6 +6,7 @@ use App\Events\ModuleDisabledEvent;
use App\Http\Controllers\Controller;
use App\Models\Module as ModelsModule;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Nwidart\Modules\Facades\Module;
class DisableModuleController extends Controller
@@ -13,7 +14,7 @@ class DisableModuleController extends Controller
/**
* Handle the incoming request.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function __invoke(Request $request, string $module)
{

View File

@@ -5,13 +5,14 @@ namespace App\Http\Controllers\V1\Admin\Modules;
use App\Http\Controllers\Controller;
use App\Space\ModuleInstaller;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class DownloadModuleController extends Controller
{
/**
* Handle the incoming request.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function __invoke(Request $request)
{

View File

@@ -6,6 +6,7 @@ use App\Events\ModuleEnabledEvent;
use App\Http\Controllers\Controller;
use App\Models\Module as ModelsModule;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Nwidart\Modules\Facades\Module;
class EnableModuleController extends Controller
@@ -13,7 +14,7 @@ class EnableModuleController extends Controller
/**
* Handle the incoming request.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function __invoke(Request $request, string $module)
{

View File

@@ -6,13 +6,14 @@ use App\Http\Controllers\Controller;
use App\Http\Resources\ModuleResource;
use App\Space\ModuleInstaller;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class ModuleController extends Controller
{
/**
* Handle the incoming request.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function __invoke(Request $request, string $module)
{

View File

@@ -5,13 +5,14 @@ namespace App\Http\Controllers\V1\Admin\Modules;
use App\Http\Controllers\Controller;
use App\Space\ModuleInstaller;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class ModulesController extends Controller
{
/**
* Handle the incoming request.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function __invoke(Request $request)
{

View File

@@ -5,13 +5,14 @@ namespace App\Http\Controllers\V1\Admin\Modules;
use App\Http\Controllers\Controller;
use App\Http\Requests\UnzipUpdateRequest;
use App\Space\ModuleInstaller;
use Illuminate\Http\Response;
class UnzipModuleController extends Controller
{
/**
* Handle the incoming request.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function __invoke(UnzipUpdateRequest $request)
{

View File

@@ -5,13 +5,14 @@ namespace App\Http\Controllers\V1\Admin\Modules;
use App\Http\Controllers\Controller;
use App\Http\Requests\UploadModuleRequest;
use App\Space\ModuleInstaller;
use Illuminate\Http\Response;
class UploadModuleController extends Controller
{
/**
* Handle the incoming request.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function __invoke(UploadModuleRequest $request)
{

View File

@@ -7,13 +7,14 @@ use App\Http\Requests\PaymentMethodRequest;
use App\Http\Resources\PaymentMethodResource;
use App\Models\PaymentMethod;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class PaymentMethodsController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function index(Request $request)
{
@@ -33,8 +34,8 @@ class PaymentMethodsController extends Controller
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
* @param Request $request
* @return Response
*/
public function store(PaymentMethodRequest $request)
{
@@ -48,7 +49,7 @@ class PaymentMethodsController extends Controller
/**
* Display the specified resource.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function show(PaymentMethod $paymentMethod)
{
@@ -60,8 +61,8 @@ class PaymentMethodsController extends Controller
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
* @param Request $request
* @return Response
*/
public function update(PaymentMethodRequest $request, PaymentMethod $paymentMethod)
{
@@ -75,7 +76,7 @@ class PaymentMethodsController extends Controller
/**
* Remove the specified resource from storage.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function destroy(PaymentMethod $paymentMethod)
{

View File

@@ -8,13 +8,14 @@ use App\Http\Requests\PaymentRequest;
use App\Http\Resources\PaymentResource;
use App\Models\Payment;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class PaymentsController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function index(Request $request)
{
@@ -40,8 +41,8 @@ class PaymentsController extends Controller
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
* @param Request $request
* @return Response
*/
public function store(PaymentRequest $request)
{

View File

@@ -5,14 +5,16 @@ namespace App\Http\Controllers\V1\Admin\Payment;
use App\Http\Controllers\Controller;
use App\Http\Requests\SendPaymentRequest;
use App\Models\Payment;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class SendPaymentController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
* @param Request $request
* @return JsonResponse
*/
public function __invoke(SendPaymentRequest $request, Payment $payment)
{

View File

@@ -5,6 +5,7 @@ namespace App\Http\Controllers\V1\Admin\Payment;
use App\Http\Controllers\Controller;
use App\Models\Payment;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Mail\Markdown;
class SendPaymentPreviewController extends Controller
@@ -12,7 +13,7 @@ class SendPaymentPreviewController extends Controller
/**
* Handle the incoming request.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function __invoke(Request $request, Payment $payment)
{

View File

@@ -7,13 +7,14 @@ use App\Http\Requests\RecurringInvoiceRequest;
use App\Http\Resources\RecurringInvoiceResource;
use App\Models\RecurringInvoice;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class RecurringInvoiceController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function index(Request $request)
{
@@ -34,8 +35,8 @@ class RecurringInvoiceController extends Controller
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
* @param Request $request
* @return Response
*/
public function store(RecurringInvoiceRequest $request)
{
@@ -49,7 +50,7 @@ class RecurringInvoiceController extends Controller
/**
* Display the specified resource.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function show(RecurringInvoice $recurringInvoice)
{
@@ -61,8 +62,8 @@ class RecurringInvoiceController extends Controller
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
* @param Request $request
* @return Response
*/
public function update(RecurringInvoiceRequest $request, RecurringInvoice $recurringInvoice)
{
@@ -76,8 +77,8 @@ class RecurringInvoiceController extends Controller
/**
* Remove the specified resource from storage.
*
* @param \App\Models\RecurringInvoice $recurringInvoice
* @return \Illuminate\Http\Response
* @param RecurringInvoice $recurringInvoice
* @return Response
*/
public function delete(Request $request)
{

View File

@@ -8,6 +8,7 @@ use App\Models\CompanySetting;
use App\Models\Currency;
use App\Models\Customer;
use Carbon\Carbon;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
use PDF;
@@ -18,7 +19,7 @@ class CustomerSalesReportController extends Controller
* Handle the incoming request.
*
* @param string $hash
* @return \Illuminate\Http\JsonResponse
* @return JsonResponse
*/
public function __invoke(Request $request, $hash)
{

View File

@@ -8,6 +8,7 @@ use App\Models\CompanySetting;
use App\Models\Currency;
use App\Models\Expense;
use Carbon\Carbon;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
use PDF;
@@ -18,7 +19,7 @@ class ExpensesReportController extends Controller
* Handle the incoming request.
*
* @param string $hash
* @return \Illuminate\Http\JsonResponse
* @return JsonResponse
*/
public function __invoke(Request $request, $hash)
{

View File

@@ -8,6 +8,7 @@ use App\Models\CompanySetting;
use App\Models\Currency;
use App\Models\InvoiceItem;
use Carbon\Carbon;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
use PDF;
@@ -18,7 +19,7 @@ class ItemSalesReportController extends Controller
* Handle the incoming request.
*
* @param string $hash
* @return \Illuminate\Http\JsonResponse
* @return JsonResponse
*/
public function __invoke(Request $request, $hash)
{

View File

@@ -9,6 +9,7 @@ use App\Models\Currency;
use App\Models\Expense;
use App\Models\Payment;
use Carbon\Carbon;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
use PDF;
@@ -19,7 +20,7 @@ class ProfitLossReportController extends Controller
* Handle the incoming request.
*
* @param string $hash
* @return \Illuminate\Http\JsonResponse
* @return JsonResponse
*/
public function __invoke(Request $request, $hash)
{

View File

@@ -8,6 +8,7 @@ use App\Models\CompanySetting;
use App\Models\Currency;
use App\Models\Tax;
use Carbon\Carbon;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
use PDF;
@@ -18,7 +19,7 @@ class TaxSummaryReportController extends Controller
* Handle the incoming request.
*
* @param string $hash
* @return \Illuminate\Http\JsonResponse
* @return JsonResponse
*/
public function __invoke(Request $request, $hash)
{

View File

@@ -4,13 +4,14 @@ namespace App\Http\Controllers\V1\Admin\Role;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class AbilitiesController extends Controller
{
/**
* Handle the incoming request.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function __invoke(Request $request)
{

View File

@@ -7,6 +7,7 @@ use App\Http\Requests\RoleRequest;
use App\Http\Resources\RoleResource;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Silber\Bouncer\BouncerFacade;
use Silber\Bouncer\Database\Role;
@@ -15,7 +16,7 @@ class RolesController extends Controller
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function index(Request $request)
{
@@ -35,8 +36,8 @@ class RolesController extends Controller
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
* @param Request $request
* @return Response
*/
public function store(RoleRequest $request)
{
@@ -53,7 +54,7 @@ class RolesController extends Controller
* Display the specified resource.
*
* @param \Spatie\Permission\Models\Role $role
* @return \Illuminate\Http\Response
* @return Response
*/
public function show(Role $role)
{
@@ -65,9 +66,9 @@ class RolesController extends Controller
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param Request $request
* @param \Spatie\Permission\Models\Role $role
* @return \Illuminate\Http\Response
* @return Response
*/
public function update(RoleRequest $request, Role $role)
{
@@ -84,7 +85,7 @@ class RolesController extends Controller
* Remove the specified resource from storage.
*
* @param \Spatie\Permission\Models\Role $role
* @return \Illuminate\Http\Response
* @return Response
*/
public function destroy(Role $role)
{

View File

@@ -10,6 +10,7 @@ use App\Http\Requests\ProfileRequest;
use App\Http\Resources\CompanyResource;
use App\Http\Resources\UserResource;
use App\Models\Company;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class CompanyController extends Controller
@@ -17,7 +18,7 @@ class CompanyController extends Controller
/**
* Retrive the Admin account.
*
* @return \Illuminate\Http\JsonResponse
* @return JsonResponse
*/
public function getUser(Request $request)
{
@@ -28,7 +29,7 @@ class CompanyController extends Controller
* Update the Admin profile.
* Includes name, email and (or) password
*
* @return \Illuminate\Http\JsonResponse
* @return JsonResponse
*/
public function updateProfile(ProfileRequest $request)
{
@@ -42,7 +43,7 @@ class CompanyController extends Controller
/**
* Update Admin Company Details
*
* @return \Illuminate\Http\JsonResponse
* @return JsonResponse
*/
public function updateCompany(CompanyRequest $request)
{
@@ -60,7 +61,7 @@ class CompanyController extends Controller
/**
* Upload the company logo to storage.
*
* @return \Illuminate\Http\JsonResponse
* @return JsonResponse
*/
public function uploadCompanyLogo(CompanyLogoRequest $request)
{
@@ -93,7 +94,7 @@ class CompanyController extends Controller
/**
* Upload the Admin Avatar to public storage.
*
* @return \Illuminate\Http\JsonResponse
* @return JsonResponse
*/
public function uploadAvatar(AvatarRequest $request)
{

View File

@@ -5,13 +5,14 @@ namespace App\Http\Controllers\V1\Admin\Settings;
use App\Http\Controllers\Controller;
use App\Models\Company;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class CompanyCurrencyCheckTransactionsController extends Controller
{
/**
* Handle the incoming request.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function __invoke(Request $request)
{

View File

@@ -8,6 +8,7 @@ use App\Http\Resources\FileDiskResource;
use App\Models\FileDisk;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class DiskController extends Controller
{
@@ -43,7 +44,7 @@ class DiskController extends Controller
}
/**
* @param \App\Models\FileDisk $file_disk
* @param FileDisk $file_disk
* @return JsonResponse
*/
public function update(FileDisk $disk, Request $request)
@@ -136,8 +137,8 @@ class DiskController extends Controller
/**
* Remove the specified resource from storage.
*
* @param \App\Models\FileDisk $taxType
* @return \Illuminate\Http\Response
* @param FileDisk $taxType
* @return Response
*/
public function destroy(FileDisk $disk)
{

View File

@@ -4,13 +4,14 @@ namespace App\Http\Controllers\V1\Admin\Settings;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class GetCompanyMailConfigurationController extends Controller
{
/**
* Handle the incoming request.
*
* @return \Illuminate\Http\Response
* @return Response
*/
public function __invoke(Request $request)
{

View File

@@ -5,18 +5,20 @@ namespace App\Http\Controllers\V1\Admin\Settings;
use App\Http\Controllers\Controller;
use App\Http\Requests\GetSettingsRequest;
use App\Models\CompanySetting;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class GetCompanySettingsController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
* @param Request $request
* @return JsonResponse
*/
public function __invoke(GetSettingsRequest $request)
{
$settings = CompanySetting::getSettings($request->settings, $request->header('company'));
$settings = CompanySetting::getSettings((array) $request->settings, $request->header('company'));
return response()->json($settings);
}

View File

@@ -6,14 +6,15 @@ use App\Http\Controllers\Controller;
use App\Http\Requests\GetSettingRequest;
use App\Models\Setting;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class GetSettingsController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
* @param Request $request
* @return Response
*/
public function __invoke(GetSettingRequest $request)
{

Some files were not shown because too many files have changed in this diff Show More