Compare commits

...

493 Commits

Author SHA1 Message Date
Mohit Panjwani
db1b0db461 update dompdf version 2021-03-23 13:14:34 +05:30
Florian Gareis
17c00c322d Add test ci 2021-03-22 16:52:01 +01:00
Mohit Panjwani
331b8ea44e Merge pull request #426 from TheZoker/fix-invoice-address-capitalize
Don't capitalize address on invoice
2021-03-22 19:20:05 +05:30
Florian Gareis
428be640c3 Don't capitalize address on invoice 2021-03-22 14:49:31 +01:00
Mouad ZIANI
51f79433b9 feat: Added MAD (Moroccan dirham) currency (#355)
Add MAD (Moroccan dirham) currency
2021-03-22 17:33:36 +05:30
Mohit Panjwani
8008ed0527 Merge pull request #423 from TheZoker/add-more-translation
Add more translation
2021-03-22 14:59:04 +05:30
Florian Gareis
57b302666a Address review comments 2021-03-22 10:17:01 +01:00
Mohit Panjwani
ee1d1ccff4 update readme and fix formatting on utilities 2021-03-22 13:05:02 +05:30
Mohit Panjwani
81e7109ad1 new build 2021-03-22 13:02:17 +05:30
Mohit Panjwani
784bf39df5 fix max-discount issue on estimates and generate new public files 2021-03-22 12:57:46 +05:30
Mohit Panjwani
f66755c4aa Merge pull request #365 from DjKhireddine/patch-1
Update Item.vue
2021-03-22 12:56:37 +05:30
Mohit Panjwani
b4e1e99d37 Merge pull request #354 from habibhaidari1/master
Fixed small typo that caused wrong breadcrumb
2021-03-22 12:42:33 +05:30
Mohit Panjwani
d8aa3dc8a6 Merge pull request #336 from romanobarassi/barassi-crater-fix1
Update composer.json
2021-03-22 12:32:45 +05:30
Mohit Panjwani
9af51660cb Merge pull request #405 from itsaboutcode/show_field_min_length
Showing length error for Payment, Note and ItemUnit Model Views
2021-03-22 12:26:41 +05:30
Mohit Panjwani
38d0da9618 Merge pull request #419 from TheZoker/translate-pdf-title
Translate PDF titles
2021-03-22 12:22:41 +05:30
Mohit Panjwani
761c0143ec Merge pull request #420 from TheZoker/adjust-money-format
Adjust money format to respect swap_currency_symbol
2021-03-22 12:12:13 +05:30
Mohit Panjwani
fdc4de5093 Merge pull request #407 from sebastiancretu/send_inv_est_pay_as_attachment
Send invoices, estimates and payments as attachments
2021-03-22 12:06:06 +05:30
Florian Gareis
f8591f96a9 Write € symbol after amount 2021-03-21 13:05:49 +01:00
Florian Gareis
e47cb01ce2 Translate badges 2021-03-21 00:45:43 +01:00
Florian Gareis
454ad3091a Add some missing translations 2021-03-21 00:45:37 +01:00
Florian Gareis
cc73a8a842 Adjust money format to respect swap_currency_symbol 2021-03-20 17:49:57 +01:00
Florian Gareis
cea8405ace Translate PDF titles 2021-03-20 14:35:22 +01:00
Mohit Panjwani
49a6e03e9d Merge pull request #408 from sebastiancretu/fix_unit_name_in_emails
fix(items): added unit name after quantity in the pdf templates
2021-03-15 16:18:54 +05:30
Sebastian Cretu
f9d6e8b0cc fix(items): added unit name after quantity in the pdf templates 2021-03-03 17:09:05 +01:00
Sebastian Cretu
2b78aacc83 feat(emails): implemented sending invoice, estimates and payments as attachements 2021-03-02 21:49:03 +01:00
Sebastian Cretu
1932c5a75e a 2021-03-02 21:19:16 +01:00
itsaboutcode
449968ae88 Showing length error for Payment, Note and ItemUnit Model Views 2021-03-02 10:50:27 +05:00
Mohit Panjwani
02a2db4417 Merge pull request #372 from makakken/master
Fixes #371
2021-02-24 15:40:34 +05:30
Mohit Panjwani
a53582f916 Merge pull request #398 from renzocastillo/master
added new currency: peruvian soles
2021-02-24 15:40:10 +05:30
Renzo Castillo
340bf3be06 added new currency: peruvian soles 2021-02-22 11:34:25 -05:00
Mohit Panjwani
7f0da9dc36 fix conflict 2021-02-12 13:19:56 +05:30
Mohit Panjwani
c4ace76275 Merge branch 'master' of gitlab.com:mohit.panjvani/crater-web 2021-02-12 13:18:03 +05:30
Mohit Panjwani
553bcc053b Merge pull request #375 from sebastiancretu/fix_payment_receipt_currency
fix(payments): display the currency in receipts
2021-02-12 11:54:19 +05:30
Sebastian Cretu
375a59a504 fix(payments): display the currency in receipts 2021-02-08 20:42:10 +01:00
Sebastian Cretu
cfc0a1ef75 Regenerated assets 2021-02-05 20:53:34 +01:00
Sebastian Cretu
392f6f469b Send Invoices/Estimates/Payments as email attachments 2021-02-05 20:24:56 +01:00
makakken
6cb8d30915 Update invoice3.blade.php
Fix Exception: 'box_sizing' is not a recognized CSS property.
2021-02-04 11:02:59 +01:00
makakken
9b55e84724 Update invoice2.blade.php
Fix Exception: 'box_sizing' is not a recognized CSS property.
2021-02-04 11:02:32 +01:00
makakken
cf5da7684b Update invoice1.blade.php
fix box_sizing DOMPDF Bug
2021-02-04 11:01:57 +01:00
Mohit Panjwani
f47029ca78 fix payment invalid-number issue 2021-02-03 14:25:05 +05:30
Mohit Panjwani
761df2ffac Merge branch 'mail-name-issue' into 'master'
invoice mail name issue fix

See merge request mohit.panjvani/crater-web!669
2021-02-03 07:19:32 +00:00
brijraj_04
8fbc257b23 payment from mail name 2021-02-03 12:24:28 +05:30
brijraj_04
baebfedf37 invoice and estimate from mail name issue 2021-02-03 12:21:03 +05:30
Mohit Panjwani
9321eb9d86 Merge branch 'payment_issue' into 'master'
fix payment currency issue

See merge request mohit.panjvani/crater-web!668
2021-02-03 06:31:23 +00:00
brijraj_04
70bed01e7b invoice mail name issue fix 2021-02-03 11:38:59 +05:30
Dj KHIREDDINE
739efcce79 Update Item.vue
There is an error in calculating maxDiscount. 
maxDiscount = item.price * item.quantity
2021-02-02 19:23:32 +01:00
brijraj_04
3695e7d075 fix payment currency issue 2021-02-02 17:22:44 +05:30
Habib Haidari
8f2033f621 Fixed small type that caused wrong breadcrumb 2021-01-23 19:29:26 +01:00
Mohit Panjwani
7b95ccb5fc fix company logo issue 2021-01-22 19:00:37 +05:30
Mohit Panjwani
b7370ed85c update version on migration 2021-01-22 14:49:05 +05:30
Mohit Panjwani
818f2fbaf7 build 404 2021-01-22 14:27:30 +05:30
Mohit Panjwani
91a1dbf91c new build 2021-01-22 14:17:08 +05:30
Mohit Panjwani
a4d556f41e fix tax rounding issues 2021-01-22 14:15:44 +05:30
Mohit Panjwani
83de1c47ee fix tax rounding errors and styling issues 2021-01-22 13:44:59 +05:30
Mohit Panjwani
678ace744a fix purgecss issue and insert-note z-index 2021-01-22 12:00:10 +05:30
Mohit Panjwani
9e26fee1b0 upgrade tailwind 2021-01-21 18:31:11 +05:30
Mohit Panjwani
e455c3de50 Merge branch 'date-issue' into 'master'
solve date issue

See merge request mohit.panjvani/crater-web!665
2021-01-15 10:17:51 +00:00
Mohit Panjwani
c4db50d3f0 Merge branch 'logo-issue' into 'master'
fix logo display issue

See merge request mohit.panjvani/crater-web!664
2021-01-15 10:16:28 +00:00
jayvirsinh_gohil
411ee57946 solve date issue 2021-01-15 14:26:35 +05:30
raishvaria
9c5e9e56f5 fix logo display issue 2021-01-15 14:22:42 +05:30
Mohit Panjwani
8eeafd3fed fix tailwind-v2 issues 2021-01-06 21:12:22 +05:30
Mohit Panjwani
ed978d0174 upgrade tailwind version and laravel-mix 2021-01-06 14:18:41 +05:30
Mohit Panjwani
607b1795bb Merge branch 'discount-issue' into 'master'
fix total discount issue

See merge request mohit.panjvani/crater-web!655
2021-01-06 06:58:07 +00:00
romanobarassi
a6c3c815b5 Update composer.json 2021-01-04 18:59:07 +01:00
Mohit Panjwani
ead0ebb012 fix note button z-index issue 2021-01-04 11:43:00 +05:30
Mohit Panjwani
d4550e62f8 add 403 migration 2020-12-31 15:39:01 +05:30
Mohit Panjwani
ff3846137e fix translations & build 403 2020-12-31 12:33:56 +05:30
Mohit Panjwani
b55f8e5391 fix floating errors 2020-12-31 12:16:04 +05:30
Mohit Panjwani
0f1d7627ea fix next number issue on estimate & invoice 2020-12-31 11:52:42 +05:30
Mohit Panjwani
1be462ef82 fix eslint and prettier config 2020-12-31 11:52:10 +05:30
spvarma
8b04e94446 fix total discount issue 2020-12-24 13:43:29 +05:30
Mohit Panjwani
fa512629d9 build 402 2020-12-23 11:43:31 +05:30
Mohit Panjwani
0f99be6cf1 change template button and note-button styles 2020-12-23 11:41:23 +05:30
Mohit Panjwani
fae3af2592 fix infinite-looping issue 2020-12-22 17:48:21 +05:30
Mohit Panjwani
d1e70c8989 Merge branch 'template-refactor' into 'master'
Template Refactor

See merge request mohit.panjvani/crater-web!653
2020-12-22 08:16:47 +00:00
Mohit Panjwani
63094e8112 re-style template selection modals 2020-12-22 13:46:15 +05:30
Jay_Makwana
1b46bddf56 Merge branch 'master' of https://gitlab.com/mohit.panjvani/crater-web into template-refactor 2020-12-22 13:15:55 +05:30
Jay_Makwana
422bf74600 refactor template 2020-12-22 13:15:09 +05:30
Mohit Panjwani
d003e61d41 Merge branch 'master' 2020-12-22 13:07:06 +05:30
Mohit Panjwani
09f74eb37c Merge branch 'master-date-refactor' into 'master'
Refactor Date Issue

See merge request mohit.panjvani/crater-web!652
2020-12-22 07:24:03 +00:00
Jay_Makwana
9227973a7a refactor date issue 2020-12-22 12:51:44 +05:30
Mohit Panjwani
5011543198 Merge branch 'master' 2020-12-22 12:15:27 +05:30
Mohit Panjwani
d07b63c365 Merge branch 'fix-user-issue' into 'master'
fix isLoading issue

See merge request mohit.panjvani/crater-web!646
2020-12-22 06:43:23 +00:00
Mohit Panjwani
c12e27dbfe remove unnecessary comment 2020-12-22 12:12:58 +05:30
Mohit Panjwani
4ea32b94ed Merge branch fix-amount issue on payment 2020-12-22 12:00:28 +05:30
Mohit Panjwani
fe93d5236c Merge branch 'fix-price-issue' into 'master'
fix amount int issue

See merge request mohit.panjvani/crater-web!648
2020-12-22 06:29:44 +00:00
Mohit Panjwani
5992394bca remove change emit from BaseDatePicker 2020-12-22 11:55:59 +05:30
Mohit Panjwani
6c9f5800e5 Sync language files from crowdin 2020-12-22 11:55:47 +05:30
Mohit Panjwani
227cebcb0b update license readme 2020-12-19 14:57:50 +05:30
Mohit Panjwani
6fd4cc6b3f Merge branch 'master' of https://github.com/bytefury/crater 2020-12-19 14:55:57 +05:30
Mohit Panjwani
594c8965c1 Merge pull request #311 from artfuld/master
Swedish locale
2020-12-18 14:03:03 +05:30
Joakim Andersson
2241145a17 Merge branch 'master' into master 2020-12-18 09:31:40 +01:00
Mohit Panjwani
34f252b1c9 fix reset-app 2020-12-15 21:02:22 +05:30
Joakim Andersson
89e1d7bc84 no message 2020-12-14 19:21:24 +01:00
Joakim Andersson
f0368deda2 no message 2020-12-14 19:20:42 +01:00
Joakim Andersson
4028551fd8 no message 2020-12-14 19:07:31 +01:00
Joakim Andersson
06f385a28e More corrections after using the program 2020-12-14 19:05:11 +01:00
spvarma
44aeff425b fix amount int issue 2020-12-14 19:17:54 +05:30
Mohit Panjwani
35a38d719c Merge pull request #314 from azaricstefan/SerbianLang
update code for SR
2020-12-14 10:03:32 +05:30
Joakim Andersson
f6ba81e8b7 Some more changes after using the translation 2020-12-12 12:25:53 +01:00
Joakim Andersson
64cb55fd5d Skatt => Moms
Fixed a misspelling
2020-12-12 12:23:26 +01:00
Mohit Panjwani
13fe38517c Merge pull request #307 from azaricstefan/SerbianLang
Serbian lang
2020-12-12 16:06:42 +05:30
Stefan Azaric
3bdb501d1d update code for SR 2020-12-12 11:21:08 +01:00
Mohit Panjwani
b8adbf4b07 Merge pull request #306 from edevrob/master
PDF templates fix
2020-12-11 20:11:25 +05:30
Joakim Andersson
aa85a9950c no message 2020-12-11 11:31:17 +01:00
Joakim Andersson
8e63efee1b Fullständig översättning till svenska 2020-12-11 11:17:03 +01:00
spvarma
ea98f03aeb fix isLoading issue 2020-12-11 14:23:04 +05:30
Joakim Andersson
90cd6226be Snart klar med översättningen 2020-12-11 01:38:23 +01:00
Stefan Azaric
9d2df64b2e yarn run production 2020-12-10 23:42:35 +01:00
Stefan Azaric
bade86a24f yarn run dev 2020-12-09 23:35:05 +01:00
Stefan Azaric
c3b57b4888 Adapt Serbian language to 4.0.1 2020-12-09 23:22:05 +01:00
Stefan Azaric
fcfedc5414 Adapt Serbian language to 4.0.1 2020-12-09 23:21:51 +01:00
edevrob
8dee0da434 PDF templates fix
DomPDF font-weight problems fix
2020-12-09 21:13:56 +02:00
Joakim Andersson
e4ab024422 Svenska 2020-12-09 12:04:42 +01:00
Mohit Panjwani
2bd01c4014 update readme and fix #303 2020-12-09 15:10:13 +05:30
Mohit Panjwani
034c7e385c fix translation issues & formatting 2020-12-09 11:36:14 +05:30
Mohit Panjwani
c9086747a3 remove delete_files validation on update 2020-12-08 20:32:41 +05:30
Mohit Panjwani
ab1ed269fd fix update-app description style 2020-12-08 20:27:05 +05:30
Mohit Panjwani
f7a823e9bc fix reset pass validation message and add 401 migration 2020-12-08 19:52:32 +05:30
Mohit Panjwani
b6301b08f8 new build 4.0.1 2020-12-08 19:00:49 +05:30
Mohit Panjwani
265c219fdc Merge branch 'localhost-img-issue' into 'master'
fix localhost img display issue

See merge request mohit.panjvani/crater-web!638
2020-12-08 12:15:57 +00:00
Mohit Panjwani
729db694a3 Merge branch 'timezone' into 'master'
Fix Timezone issue

See merge request mohit.panjvani/crater-web!642
2020-12-08 12:03:36 +00:00
raishvaria
e2e6415cb6 fix timezone issue 2020-12-08 16:31:44 +05:30
raishvaria
419104a4ec check system using file disk type 2020-12-08 15:07:57 +05:30
raishvaria
f18eac2001 replace env with config 2020-12-08 14:43:21 +05:30
Mohit Panjwani
7bffbe59ed Merge branch 'change-datatype' into 'master'
change notes & description column type

See merge request mohit.panjvani/crater-web!639
2020-12-08 09:07:59 +00:00
Mohit Panjwani
bf53b4f5eb Merge branch 'fix-toastr' into 'master'
remove multiple toastr call

See merge request mohit.panjvani/crater-web!640
2020-12-08 09:07:12 +00:00
Mohit Panjwani
21440230f3 Merge branch 'pdf-ext' into 'master'
fix pdf extenstion issue

See merge request mohit.panjvani/crater-web!641
2020-12-08 09:06:43 +00:00
raishvaria
99c27ba8ef fix pdf extenstion issue 2020-12-08 14:14:52 +05:30
raishvaria
cb7a925cd0 remove multiple toastr call 2020-12-08 13:19:06 +05:30
raishvaria
d2e11bd7df change notes & description column type 2020-12-08 12:55:28 +05:30
raishvaria
1b74a3720e fix localhost img display issue 2020-12-08 11:39:47 +05:30
Mohit Panjwani
e222af335e Merge branch 'date-range' into 'master'
fix date range issue in reports

See merge request mohit.panjvani/crater-web!635
2020-12-07 12:52:58 +00:00
raishvaria
599e6270e8 fix date range issue in reports 2020-12-07 12:34:12 +05:30
Mohit Panjwani
da7ddcd4f1 Merge branch 'fix-reset-pass-layout' into 'master'
fix layout issue

See merge request mohit.panjvani/crater-web!632
2020-12-07 06:43:07 +00:00
Mohit Panjwani
bd01039fb8 Merge branch 'reset-password' into 'master'
Fix reset password

See merge request mohit.panjvani/crater-web!634
2020-12-07 06:42:32 +00:00
Mohit Panjwani
718f01ccd4 Merge branch 'unique-hash' into 'master'
Unique hash

See merge request mohit.panjvani/crater-web!633
2020-12-07 06:42:26 +00:00
raishvaria
fd3742b926 fix reset password issue 2020-12-07 10:34:22 +05:30
raishvaria
e8b954d1bd generate unique hash ids 2020-12-05 17:06:22 +05:30
spvarma
58042decd5 fix layout issue 2020-12-05 15:43:35 +05:30
raishvaria
fa500b3865 add cmd for app key generate 2020-12-05 13:35:46 +05:30
Mohit Panjwani
e03924fe9d Merge branch 'master' of https://github.com/bytefury/crater 2020-12-04 11:46:49 +05:30
Mohit Panjwani
3f308a2d3b update composer file 2020-12-04 11:46:32 +05:30
Mohit Panjwani
6cdd93bab0 Merge pull request #288 from MakerLab-Dev/master
Password reset update
2020-12-04 11:43:02 +05:30
MakerLab-Dev
69c6c883c2 Password reset update 2020-12-03 19:04:50 +01:00
MakerLab-Dev
69dcf1299b More descriptive errors 2020-12-03 18:00:09 +01:00
Mohit Panjwani
b6cd78ca4c update readme 2020-12-03 20:38:49 +05:30
Mohit Panjwani
d18116bd7d fix conflicts 2020-12-03 20:35:27 +05:30
Mohit Panjwani
6b30c2028b new build 400 2020-12-03 19:43:50 +05:30
Mohit Panjwani
8c4a358072 Merge branch 'delete-file-ability' into 'master'
add ability to delete file from UI

See merge request mohit.panjvani/crater-web!629
2020-12-03 14:06:16 +00:00
raishvaria
fe8482fc71 add ability to delete file from UI 2020-12-03 17:47:16 +05:30
Mohit Panjwani
28217df654 add ability to delete files on update 2020-12-03 12:49:37 +05:30
Mohit Panjwani
3723697add restrict update if the system requirements do not match 2020-12-02 19:05:39 +05:30
Mohit Panjwani
b3e3839fb5 fix default seeder 2020-12-02 18:52:25 +05:30
Mohit Panjwani
89ee58590c build version 400 2020-12-02 17:54:08 +05:30
Mohit Panjwani
326508e567 Merge branch 'version-320' into 'master'
Version 320

See merge request mohit.panjvani/crater-web!623
2020-12-02 07:31:01 +00:00
raishvaria
21e01bc1db remove use from EventServiceProvider 2020-12-02 12:32:13 +05:30
raishvaria
ed58dfaef6 remove optimized cmd 2020-12-02 12:31:16 +05:30
raishvaria
c2c0e2809c remove listener & add version320 migration 2020-12-02 12:23:30 +05:30
raishvaria
bafda5ca46 Merge branch 'master' of https://gitlab.com/mohit.panjvani/crater-web into version-230 2020-12-02 10:29:52 +05:30
raishvaria
a7eaf5dbe4 fix updater issue & add optimize clear cmd 2020-12-02 10:29:46 +05:30
Mohit Panjwani
805a287129 Merge branch 'version-230' into 'master'
Version 230

See merge request mohit.panjvani/crater-web!620
2020-12-01 06:44:00 +00:00
raishvaria
61fe16cab4 new build for version230 2020-12-01 12:09:46 +05:30
raishvaria
33085a0e3c add v-html for description 2020-12-01 12:08:24 +05:30
raishvaria
2df09a20f1 fix updater issue and run production 2020-12-01 11:05:45 +05:30
raishvaria
a7d61b802d hideupdate button for version 4.0.0 2020-12-01 11:02:32 +05:30
Mohit Panjwani
88bcb1c2b4 add listener to provider 2020-11-09 17:45:05 +05:30
Mohit Panjwani
af194c1851 add 320 listener 2020-11-09 13:31:30 +05:30
Mohit Panjwani
71193727c9 new build 2020-11-09 13:20:35 +05:30
Mohit Panjwani
bc7571832a Merge branch 'virsion-check' into 'master'
Version check

See merge request mohit.panjvani/crater-web!470
2020-11-09 07:48:24 +00:00
yogesh_gohil
e379e13802 fix update validation toaster 2020-11-06 19:09:17 +05:30
yogesh_gohil
4484765358 add version check validation 2020-11-05 19:02:55 +05:30
jayvirsinh_gohil
5d4ea2a308 transfer code from update controller to updater class 2020-11-03 12:19:51 +05:30
jayvirsinh_gohil
0db9f9df0c get current virsions of php and extensions 2020-10-30 16:57:39 +05:30
Mohit Panjwani
9301e67e3f build public files 2020-09-10 13:39:26 +05:30
Mohit Panjwani
a019403b1b Merge pull request #262 from Xoshbin/patch-1
Added Iraqi Dinar in currencies table
2020-09-03 14:26:25 +05:30
Khoshbin Ali Ahmed
c99d7ee677 Added Iraqi Dinar in currencies table 2020-09-02 22:17:29 +03:00
Mohit Panjwani
94a2306b7f Merge pull request #253 from loduis/patch-2
Add missing key resend_invoice in the spanish
2020-08-05 07:57:48 +05:30
Loduis Madariaga Barrios
73bd28aeb8 Add missing key resend_invoice in the spanish 2020-08-04 18:24:42 -05:00
Mohit Panjwani
904f2641c5 Merge pull request #250 from loduis/patch-1
Add copy_pdf_url missing key in spanish
2020-08-04 18:09:29 +05:30
Loduis Madariaga Barrios
4372195547 Add copy_pdf_url missing key in spanish 2020-08-04 06:39:55 -05:00
Mohit Panjwani
14f8094a9d Merge branch 'invoice-refactor' into 'master'
Refactor DUE status

See merge request mohit.panjvani/crater-web!251
2020-08-01 08:24:35 +00:00
Mohit Panjwani
4770c27d7d Merge pull request #244 from azaricstefan/master
Serbian language support
2020-07-27 11:55:43 +05:30
Stefan Azaric
f4baf308a4 merge 2020-07-26 23:15:43 +02:00
Stefan Azaric
6f852ab88a merge 2020-07-26 23:11:06 +02:00
Stefan Azaric
14bb6edec8 Serbian language support (latin) made better 2020-07-26 23:09:19 +02:00
Stefan Azaric
b4a7c724db Serbian language support (latin) made better 2020-07-26 23:07:49 +02:00
Mohit Panjwani
9fb4b4dec5 Merge pull request #239 from Loosie94/master
Improved Dutch translation
2020-07-04 14:02:32 +05:30
Mohit Panjwani
4bbc92ccaf Merge branch 'master' of https://github.com/bytefury/crater 2020-07-01 10:44:44 +05:30
René Loos
dd12662b17 change 2020-06-25 20:23:38 +02:00
René Loos
c364de1b17 Cap case 2020-06-25 19:09:41 +02:00
René Loos
a06e8e3039 Link 2020-06-24 00:15:56 +02:00
René Loos
b9021cb664 confirm_delete 2020-06-23 23:56:38 +02:00
René Loos
a2c3fa2cc5 clone string 2020-06-23 22:56:24 +02:00
Mohit Panjwani
517f3bd1b8 Merge branch 'table-factory' into 'master'
refactor factories

See merge request mohit.panjvani/crater-web!259
2020-06-23 08:49:07 +00:00
René Loos
29b4b92fab Better 2020-06-22 21:07:58 +02:00
radhu587
e8f046f02e refactor factories 2020-06-22 17:07:35 +05:30
René Loos
2bf6778c8a better intro 2020-06-22 12:47:16 +02:00
René Loos
e11c713ce3 Typo 2020-06-22 12:19:04 +02:00
Mohit Panjwani
b7189595bd Merge pull request #232 from Loosie94/master
Improved Dutch version
2020-06-22 14:46:42 +05:30
René Loos
c5d4a62930 Last improvements 2020-06-21 13:25:58 +02:00
René Loos
378f216f6d More Dutch improvements 2020-06-21 11:58:29 +02:00
René Loos
7654c30b1b Few typo's 2020-06-21 11:41:40 +02:00
René Loos
f4767ffb26 json file 2020-06-20 20:35:15 +02:00
René Loos
e06639daa5 Improved Dutch version 3.1.1 2020-06-20 20:29:16 +02:00
Mohit Panjwani
9bd23ffac8 Merge pull request #225 from jpmurray/correct-gitingore
Added last slash so it ignores everything in the folder
2020-06-19 14:03:47 +05:30
Stefan Azaric
60f5d29570 Serbian language support (latin) made better 2020-06-12 01:11:30 +02:00
Stefan Azaric
b2497e5f81 Serbian language support (latin) made better 2020-06-12 00:25:42 +02:00
Jean-Philippe Murray
771a447e2c Added last slash so it ignores everything in the folder
.gitignore's magic still eludes me it seems!
2020-06-09 09:34:56 -04:00
Stefan Azaric
a964f1d841 Serbian language support (latin) made better 2020-06-08 22:24:06 +02:00
Mohit Panjwani
57d5356bfe Merge pull request #221 from jpmurray/persis-database
[Docker] Dive the direction to persist database on the host rather than a volume if desired
2020-06-08 18:12:44 +05:30
Mohit Panjwani
fd29487121 Merge pull request #222 from jpmurray/php-upload
[Docker] Modify php and nginx config to change upload file size
2020-06-08 17:40:52 +05:30
Stefan Azaric
5fb6797577 revert docker-compose 8080 port 2020-06-08 02:44:29 +02:00
Stefan Azaric
3d0f77ab0b Added Serbian translation. Živela Srbija! 2020-06-08 02:43:33 +02:00
Stefan Azaric
dbc249b6bc Added Serbian Latin translation. Živela Srbija! 2020-06-08 02:22:45 +02:00
Jean-Philippe Murray
08c6218440 Modify php and nginx to change upload file size 2020-06-06 16:16:19 -04:00
Jean-Philippe Murray
737c933b8c give the option to persist the database to the host 2020-06-06 15:44:05 -04:00
Jay Makwana
b9ab87a308 refactor due status 2020-06-03 17:45:35 +05:30
Mohit Panjwani
2e5cb58c39 build 311 2020-06-01 16:11:29 +05:30
Mohit Panjwani
db622e7458 Merge branch 'refactor-new-issues' into 'master'
Refactor issues

See merge request mohit.panjvani/crater-web!241
2020-05-30 16:07:53 +00:00
Mohit Panjwani
09bbf98e61 Merge branch 'master' into refactor-new-issues 2020-05-30 21:36:49 +05:30
Mohit Panjwani
ca90ff2767 Merge branch 'master' 2020-05-30 21:10:43 +05:30
Mohit Panjwani
368dd16c9b Merge branch 'wizard-refactor' into 'master'
refactor checkValidUrl method

See merge request mohit.panjvani/crater-web!248
2020-05-30 15:39:31 +00:00
Mohit Panjwani
251648f53c fix email layout on mobile 2020-05-30 20:30:09 +05:30
Jay Makwana
ffa5b6b2ad refactor checkValidUrl method 2020-05-28 21:02:11 +05:30
Jay Makwana
bd9beaa343 Merge master branch 2020-05-28 19:34:47 +05:30
Mohit Panjwani
3e4decdfb9 update nginx port 2020-05-27 20:56:54 +05:30
Mohit Panjwani
165907d144 fix docker errors 2020-05-27 16:01:37 +05:30
Mohit Panjwani
6278417423 refactor docker setup 2020-05-27 14:18:29 +05:30
Mohit Panjwani
dc37f565c4 add credit to akaunting 2020-05-21 15:01:47 +05:30
Mohit Panjwani
532196a9b4 Merge branch 'master' of https://github.com/bytefury/crater 2020-05-21 14:53:42 +05:30
Mohit Panjwani
6a4009e13a add credit to akaunting 2020-05-21 14:53:27 +05:30
Mohit Panjwani
a8f98e51bb Update readme 2020-05-21 14:31:30 +05:30
Mohit Panjwani
2b03bc798e new build 310 2020-05-21 11:26:26 +05:30
Mohit Panjwani
482556d378 Merge branch 'resend-email' into 'master'
Add Resend Email Option

See merge request mohit.panjvani/crater-web!236
2020-05-21 05:51:36 +00:00
Mohit Panjwani
deb525af6e build 310 2020-05-19 13:22:33 +05:30
Mohit Panjwani
cb2bfbb91c Add steps for update app 2020-05-19 07:50:58 +00:00
Jay Makwana
654395a175 Add steps for update app 2020-05-19 07:50:58 +00:00
Mohit Panjwani
e31b60bc48 Refactor Self Update Endpoints and Add Update Console Command 2020-05-17 07:04:43 +00:00
gohil jayvirsinh
183953f4c4 Refactor Self Update Endpoints and Add Update Console Command 2020-05-17 07:04:43 +00:00
Jay Makwana
98d15143c2 refactor language problem 2020-05-13 21:16:37 +05:30
Mohit Panjwani
a24d8d3ebc fix updater issue 2020-05-13 16:50:45 +05:30
Mohit Panjwani
4ca574c581 fix migration errors 2020-05-13 12:47:06 +05:30
Mohit Panjwani
c7ce8c87dd new build 2020-05-13 11:31:37 +05:30
Mohit Panjwani
f64d546672 refactor 310 update listener 2020-05-13 11:12:33 +05:30
Jay Makwana
96187870b4 refactoe issues 2020-05-12 21:11:36 +05:30
Mohit Panjwani
d4a1f1a784 fix item selection and item loader 2020-05-12 13:23:06 +05:30
Mohit Panjwani
e07532961e reset items on selection 2020-05-12 13:11:29 +05:30
Mohit Panjwani
450c265ded Merge branch 'refactor-report-pdfs' into 'master'
Refactor report pdfs

See merge request mohit.panjvani/crater-web!233
2020-05-11 15:48:49 +00:00
Mohit Panjwani
f8502c3ca8 Merge branch 'customer-delete' into 'master'
Customer delete label

See merge request mohit.panjvani/crater-web!237
2020-05-11 15:47:33 +00:00
Mohit Panjwani
899da6990d Merge branch 'new-issues' into 'master'
New issues

See merge request mohit.panjvani/crater-web!239
2020-05-11 15:47:03 +00:00
jayvirsinh_gohil
e7675f938e refactor estimate to invoice endpoint 2020-05-11 19:05:50 +05:30
jayvirsinh_gohil
b08138e9e0 refactor estimate to invoice endpoint 2020-05-11 18:34:20 +05:30
jayvirsinh_gohil
5df4abdc4b add aws-sdk-php package 2020-05-11 18:15:36 +05:30
radhu587
a2fa8afa72 fix translation issue 2020-05-11 18:09:34 +05:30
Mohit Panjwani
7670cd67dc Merge branch 'template-refactor' into 'master'
refactor invoice2

See merge request mohit.panjvani/crater-web!238
2020-05-11 12:24:22 +00:00
Jay Makwana
8446ac2b27 refactor invoice2 2020-05-11 16:19:02 +05:30
radhu587
63a80e44d5 Customer delete label 2020-05-11 14:33:11 +05:30
Mohit Panjwani
076df75322 Merge branch 'template-refactor' into 'master'
Template refactor

See merge request mohit.panjvani/crater-web!232
2020-05-11 07:03:45 +00:00
Jay Makwana
11db99da73 refactor invoice 1 style 2020-05-09 18:50:58 +05:30
radhu587
050dca5a50 Add copy pdf url option 2020-05-09 14:37:22 +05:30
radhu587
3c096f1386 Add Resend Email Option 2020-05-09 14:22:13 +05:30
Jay Makwana
0f3e8fce3b refactor heading text in payment 2020-05-08 20:55:00 +05:30
radhu587
325f90bba5 Fix issues on invoice template 2020-05-08 18:49:02 +05:30
radhu587
a739a938fc Fix estimate template issues 2020-05-08 16:52:48 +05:30
Mohit Panjwani
b30e3a9b11 merge with github 2020-05-08 11:11:57 +05:30
Jay Makwana
fc1a7c7438 refactor reports pdfs 2020-05-07 18:59:50 +05:30
radhu587
6046113cb1 Refactor Invoice and Payment templates 2020-05-07 16:42:04 +05:30
Jay Makwana
611ffafec5 refactor sales customers pdf 2020-05-06 20:41:15 +05:30
Jay Makwana
c497b906df refactor taxt report pdf 2020-05-06 20:32:10 +05:30
Jay Makwana
c68fce19f9 refactor expenses pdf 2020-05-06 19:02:02 +05:30
Jay Makwana
f8913531b6 refactor profit loss pdfs 2020-05-06 18:09:28 +05:30
radhu587
30f76e2088 Refactor Estimate templates 2020-05-06 18:02:27 +05:30
Jay Makwana
39556892cd refactor sales customers 2020-05-05 20:58:20 +05:30
Jay Makwana
2fd66bf748 refactor sales items and customer pdfs 2020-05-05 20:49:51 +05:30
Jay Makwana
d4f1428d5f refactor sales customers pdf template 2020-05-05 20:03:51 +05:30
radhu587
189141c84d Refactor estimate pdf template 2020-05-05 18:21:25 +05:30
Mohit Panjwani
f8ccfece09 update templates 2020-05-05 13:12:26 +05:30
Mohit Panjwani
9a7c926d53 fix 310 update issues 2020-05-02 18:53:51 +05:30
Mohit Panjwani
c5c1674153 Merge branch 'master' 2020-05-02 13:37:36 +05:30
Mohit Panjwani
8562ee5414 Merge branch 'settings-customization-payments' into 'master'
Payments and UnitItems in doubles issue fixed...

See merge request mohit.panjvani/crater-web!218
2020-04-27 16:09:25 +00:00
satyaprakash10
06c66a756c Payments and UnitItems in doubles issue fixed... 2020-04-27 18:54:24 +05:30
Mohit Panjwani
b66d07d21b Merge pull request #201 from rexlManu/master
Updated German Language
2020-04-27 12:14:23 +05:30
Mohit Panjwani
05001b6a79 Merge pull request #170 from RobinDev/patch-1
Update french language
2020-04-21 14:52:02 +05:30
Emmanuel Lampe
f02f4ba9d3 Updated German Language 2020-04-21 07:31:33 +02:00
Robin
fbace98aac add missing translation 2020-04-20 21:12:03 +02:00
Mohit Panjwani
8f0af3dcd6 Merge branch 'master' of https://github.com/bytefury/crater 2020-04-20 11:23:00 +05:30
Mohit Panjwani
e8e44c5dc8 Merge pull request #180 from alessandrofuda/master
IT Italian translation
2020-04-18 13:38:21 +05:30
Mohit Panjwani
ac33164342 Merge branch '3.1.0' into 'master'
add listener 310

See merge request mohit.panjvani/crater-web!202
2020-04-18 07:29:08 +00:00
Mohit Panjwani
5c7c0d84ea Merge branch 'refactor-crater-3.0.0' into 'master'
Refactor line-chart

See merge request mohit.panjvani/crater-web!203
2020-04-18 07:15:52 +00:00
Jay Makwana
7ca725ac37 refactor line-chart 2020-04-17 19:53:08 +05:30
jayvirsinh_gohil
510a4b3dbb add listener 310 2020-04-17 19:05:10 +05:30
Robin Delattre
0f130ab1b8 Update fr langugage 2020-04-17 09:57:38 +02:00
Mohit Panjwani
25114009e3 remove unused components and update eslint + prettier config 2020-03-30 11:40:45 +05:30
alessandrofuda
79c16d74ce IT Italian translation 2020-03-20 18:18:27 +01:00
Mohit Panjwani
742e1e445a Merge branch 'expense-refactor' into 'master'
add customer in expense

See merge request mohit.panjvani/crater-web!172
2020-03-20 07:12:39 +00:00
Mohit Panjwani
386f96d60e Merge branch 'version301' into 'master'
add new minor version update 3.0.1

See merge request mohit.panjvani/crater-web!169
2020-03-20 07:12:27 +00:00
Jay Makwana
82d85af672 refactor and merge backend 2020-03-18 18:21:53 +05:30
jayvirsinh_gohil
4d1b267688 Merge branch 'expense-refactor' of https://gitlab.com/mohit.panjvani/crater-web into expense-refactor 2020-03-18 17:41:15 +05:30
jayvirsinh_gohil
bc99ad63a6 add user to expense 2020-03-18 17:40:03 +05:30
Jay Makwana
4bb44f8c93 add customer filter on index 2020-03-18 17:19:09 +05:30
Jay Makwana
c72265ed50 add languages 2020-03-17 19:38:59 +05:30
Jay Makwana
b8958c9eb6 add customer in expense 2020-03-17 19:20:42 +05:30
Mohit Panjwani
e33e314cb7 new frontend build 2020-03-09 15:20:59 +05:30
Mohit Panjwani
84cebee9da Merge branch 'master' of https://github.com/bytefury/crater 2020-03-09 15:19:54 +05:30
Mohit Panjwani
34d3cf7ae8 Merge branch 'item-refactor' into 'master'
refactor item search problem

See merge request mohit.panjvani/crater-web!171
2020-03-09 09:49:26 +00:00
Mohit Panjwani
93d0da836a Merge pull request #172 from digitalsign/master
Change project name in composer.json
2020-02-26 14:35:21 +05:30
Xiaohui Lam
fd51276948 Change project name in composer.json 2020-02-26 13:31:57 +08:00
Jay Makwana
d6274854ba refactor search problem 2020-02-19 19:10:43 +05:30
Mohit Panjwani
ea4bd1a31d Merge pull request #154 from lukasmu/bugfix/expenses-note
Fixed small bug that might occur when an expense is updated
2020-02-09 12:01:43 +05:30
Mohit Panjwani
286e047963 Merge pull request #129 from deanhouseholder/master
Detect if no .env file exists and add it on composer commands.
2020-02-09 12:01:25 +05:30
Mohit Panjwani
be16f48f3d Merge pull request #153 from MakerLab-Dev/patch-3
Improved error handling
2020-02-09 12:00:23 +05:30
jayvirsinh_gohil
ebea1e0813 add new minor version update 3.0.1 2020-02-07 17:20:32 +05:30
Mohit Panjwani
cc8d08f829 Merge pull request #142 from miraro3/master
Added Kyrgyzstani som
2020-02-07 16:42:15 +05:30
Mohit Panjwani
aacffc22eb fix merge conflict 2020-02-03 21:15:07 +05:30
Lukas Müller
d71ca4ffb9 Fixed small bug that might occur when an expense is updated
Previoulsy a string with contents "null" is transmitted and saved to the database when updating an expense with an empty note. This fix prevents that.
Please note that this fix still needs to be compiled with npm.
2020-02-01 14:52:07 +01:00
Mohit Panjwani
186004f7f8 fix merge conflicts 2020-01-31 14:28:16 +05:30
Mohit Panjwani
c2eb22d666 Merge pull request #137 from MakerLab-Dev/patch-1
cross-env should only be in devDependencies
2020-01-31 01:26:32 +05:30
MakerLab-Dev
af189b15b6 Small fix 2020-01-30 20:48:16 +01:00
MakerLab-Dev
1c19be85c3 Improved error handling 2020-01-30 20:47:51 +01:00
MakerLab
4bb4362d23 Removed unnecessary notification
Removed unnecessary notification as the improved error handler will show it
2020-01-30 20:45:39 +01:00
Mohit Panjwani
f6f66b3ae6 Merge pull request #152 from mdpoulter/email-subject
More descriptive email fields.
2020-01-31 00:21:29 +05:30
Mohit Panjwani
b4ccecbcf1 Merge pull request #149 from proea/master
Fix for "Empty PDF rendered in Docker #69"
2020-01-31 00:11:51 +05:30
Evgenij
92f1f196bb Update Dockerfile 2020-01-27 22:38:47 +03:00
Evgenij
ee14070a7b Update Dockerfile
slight change
2020-01-27 22:37:41 +03:00
mdpoulter
8ce7e14a02 Add name in From field. 2020-01-27 20:37:25 +02:00
mdpoulter
3401ca049e Make viewed emails more descriptive. 2020-01-27 14:47:02 +02:00
mdpoulter
5dcc7b9efd Add more descriptive subject lines. 2020-01-27 14:45:40 +02:00
Mohit Panjwani
06a538bb81 Merge branch 'build-version300' into 'master'
Build version300

See merge request mohit.panjvani/crater-web!162
2020-01-27 09:26:58 +00:00
raishvaria
7ab0419f27 build version300 2020-01-27 14:47:45 +05:30
raishvaria
a7275aaa42 fix report download & payments delete issue 2020-01-27 14:46:40 +05:30
raishvaria
bc4e6a05ea fix Surround DB_PASSWORD with quotes #104 issue 2020-01-27 14:22:21 +05:30
raishvaria
ca170f5a87 fix dashbord & using FROM_MAIL_ADDRESS issues 2020-01-27 13:43:48 +05:30
raishvaria
22e7e96dfa fix new lines in address field issue 2020-01-27 11:57:47 +05:30
raishvaria
fcfd1ddb7a build 300 2020-01-27 11:19:22 +05:30
raishvaria
daf8c9265b fix tab & language issue 2020-01-27 11:18:11 +05:30
Evgenij
406d098172 Update Dockerfile
Generation does not work due to:
iconv(): Wrong charset, conversion from `UTF-8' to `UTF-8//IGNORE' is not allowed

Installing the library gnu-libiconv will solve the problem
2020-01-26 23:18:15 +03:00
Mohit Panjwani
824d2e3e8d update app version 2020-01-26 12:32:57 +05:30
Mohit Panjwani
3cd975dbbd new build 2020-01-25 13:33:50 +05:30
Mohit Panjwani
8e50c36a71 Merge branch 'master' 2020-01-25 13:12:39 +05:30
Mohit Panjwani
b499741ab4 change button style of primary actions on view pages 2020-01-25 13:12:20 +05:30
Mohit Panjwani
b409cdb913 Merge branch 'auto-update' into 'master'
fix auto update issue in dev

See merge request mohit.panjvani/crater-web!160
2020-01-22 16:10:36 +00:00
raishvaria
13e56105e3 fix auto update issue in dev 2020-01-22 13:39:59 +05:30
benjamin.vansteelandt@student.howest.be
f68e86e4cf Added Kyrgyzstani som 2020-01-20 22:37:03 +01:00
Mohit Panjwani
da996c1f33 Merge branch 'master' of https://github.com/bytefury/crater 2020-01-19 11:49:35 +05:30
MakerLab
0990ce4678 cross-env should only be in devDependencies 2020-01-18 16:29:48 +01:00
Mohit Panjwani
bb6fb2f49d Merge pull request #131 from jjoseba/master
Spanish corrections
2020-01-08 15:39:16 +05:30
Joseba S
400296575e Updated Spanish translation 2020-01-08 10:58:26 +01:00
Mohit Panjwani
d58c790b1f Merge branch 'build-300' into 'master'
fix mailgun config issue & build 300

See merge request mohit.panjvani/crater-web!153
2020-01-07 08:32:04 +00:00
raishvaria
c674c2ab9e build verison 300 2020-01-07 13:10:55 +05:30
bansarishukla
d79692cf3b mail configuration issue 2020-01-07 12:33:03 +05:30
Dean Householder
353c2479f1 Detect if no .env file exists and add it on composer commands. 2020-01-06 10:55:34 -07:00
Mohit Panjwani
0176a854b8 Merge branch 'refactor-master' into 'master'
refactor payment view and mutation

See merge request mohit.panjvani/crater-web!151
2020-01-06 16:08:53 +00:00
Jay_Makwana
00548ea908 refactor payment view 2020-01-06 19:03:08 +05:30
Mohit Panjwani
09e335a8a7 fix conflicts 2020-01-06 14:48:08 +05:30
Mohit Panjwani
53e2ed253f Merge branch 'master' 2020-01-06 14:47:06 +05:30
Mohit Panjwani
06b035d9ac Merge branch 'build-300' into 'master'
fix payment issue & build version 300

See merge request mohit.panjvani/crater-web!150
2020-01-06 09:16:49 +00:00
Mohit Panjwani
5c88cbcc42 Merge branch 'master' 2020-01-06 14:45:09 +05:30
raishvaria
d9b175a676 fix payment issue & build version 300 2020-01-06 14:08:29 +05:30
Mohit Panjwani
f5b9bc95c6 Merge branch 'build-300' into 'master'
build version 300

See merge request mohit.panjvani/crater-web!149
2020-01-06 06:47:08 +00:00
raishvaria
586dcdea0d build version 300 2020-01-06 12:02:12 +05:30
Mohit Panjwani
50957fc179 Merge pull request #127 from hypnodev/typo-fix-crop-popup
Typo fix crop popup
2020-01-05 23:41:51 +05:30
Cristian Cosenza
c725e4744b Compiled assets 2020-01-05 19:00:29 +01:00
Cristian Cosenza
7479ce237e Typo fix #126 2020-01-05 18:57:46 +01:00
Cristian Cosenza
84420441c0 Merge pull request #2 from bytefury/master
Merge pull request #2 from bytefury/master
2020-01-05 14:03:26 +01:00
Mohit Panjwani
ac96721e87 build 220 2020-01-05 13:50:08 +05:30
Mohit Panjwani
db4c7f5e32 fix merge conflicts 2020-01-05 13:45:10 +05:30
Mohit Panjwani
87dc78eea0 Merge pull request #115 from hypnodev/add-available-lang-to-onboarding
Added available languages to Onboarding
2020-01-05 13:39:02 +05:30
Mohit Panjwani
e9c2898056 Merge pull request #119 from hypnodev/fix-http-mixed-request
Fix http mixed request
2020-01-05 13:37:27 +05:30
Mohit Panjwani
b9c4570137 Merge pull request #121 from MakerLab-Dev/translations-updates
Translations Updates
2020-01-05 13:35:01 +05:30
Mohit Panjwani
8e2525cc6c new build 220 2020-01-05 13:34:01 +05:30
Mohit Panjwani
8862a93f23 fix border-left jump on active selection 2020-01-05 13:08:42 +05:30
Mohit Panjwani
82efd88920 Merge branch 'sidebar-view' into 'master'
sidebar-view modified

See merge request mohit.panjvani/crater-web!132
2020-01-05 07:24:12 +00:00
Mohit Panjwani
0ef528d296 Merge branch 'payment_receipt' into 'master' 2020-01-05 07:22:36 +00:00
Jay Makwana
4c33a5d88c Fix Invoice/Estimate template issues and Add Payment Receipt, Custom Payment Modes and Item units 2020-01-05 07:22:36 +00:00
MakerLab-Dev
d64d06181b Translations Updates
Spanish translation: 100%
Removed a blank space in English translation
Changed the copyright year to 2020 in all translations
2020-01-03 17:21:43 +01:00
Cristian Cosenza
ef9cf2db22 Fix mixed content when use endpoint for categories list 2020-01-03 00:14:05 +01:00
Cristian Cosenza
96c295a003 Added available languages to Onboarding 2019-12-31 10:20:13 +01:00
Cristian Cosenza
22528f5b66 Merge pull request #1 from bytefury/master
Same as bytefury/crater
2019-12-31 10:15:17 +01:00
Mohit Panjwani
1cd9c72537 Merge pull request #108 from hypnodev/fix-postgresql-case-sensitiive-bug
Fix case sensitive PostgreSQL bug
2019-12-31 09:26:46 +05:30
Cristian Cosenza
7253b43eb4 Fix case sensitive PostgreSQL bug 2019-12-29 14:50:03 +01:00
Mohit Panjwani
181964cf03 Merge pull request #105 from PHClement/patch-1
Update fr.json
2019-12-28 21:13:42 +05:30
Mohit Panjwani
5914245ae4 Merge pull request #106 from cilas/feature/translate-app-to-portuguese
Feature/translate app to portuguese
2019-12-28 21:11:32 +05:30
Clément de Louvencourt
1bf3d28d4e Update fr.json
Correct some mistake, please approve it, thank you ;)
2019-12-28 01:45:25 +01:00
cilas
dbcbd93ace Translate to Brazilian Portuguese Complete 2019-12-27 21:45:15 -03:00
Cilas Amos
1729c6a308 Translated partial wizard section 2019-12-27 17:42:54 -03:00
Cilas Amos
019493cbfa Translated settings section 2019-12-27 15:55:34 -03:00
Cilas Amos
60540ba966 Translated reports section 2019-12-27 13:14:53 -03:00
Cilas Amos
601ad419ec Translated login section 2019-12-27 12:54:21 -03:00
Cilas Amos
80e7bab891 Translated expenses section 2019-12-27 12:50:37 -03:00
Cilas Amos
f5c8befbf0 Translated payments section 2019-12-27 12:33:56 -03:00
Cilas Amos
09c984baa7 Translated credit_notes section 2019-12-27 12:27:42 -03:00
Cilas Amos
0d93260672 Translated invoice section 2019-12-27 12:24:59 -03:00
cilas
3e9e217f92 Translate estimate session 2019-12-27 00:53:16 -03:00
cilas
3cd8859c62 add Brazilian Portuguese language to CompanyController 2019-12-27 00:14:57 -03:00
cilas
4493b4a419 add language pt_BR to plugins 2019-12-27 00:11:41 -03:00
cilas
79e3e70bd6 add pt_BR language option 2019-12-26 22:47:09 -03:00
Mohit Panjwani
56a955befd delete yarnlock file 2019-12-25 19:29:22 +05:30
Mohit Panjwani
496c28f80d remove transifex from readme 2019-12-25 19:27:41 +05:30
Jay_Makwana
7a59f3fe0c refactor variable in estimate view scss 2019-12-23 21:05:48 +05:30
Jay_Makwana
3d6875a532 refactor css variables 2019-12-23 21:00:26 +05:30
Mohit Panjwani
15bf380f4f Merge pull request #93 from surajjdhv/master
Fixed incorrectly named language (ar.json) file
2019-12-23 12:54:04 +05:30
Suraj Jadhav
0b910db039 Fixed incorrectly named language (ar.json) file 2019-12-22 21:47:30 +05:30
Mohit Panjwani
0e5e8f602f update error message for db file permission issue 2019-12-21 23:02:05 +05:30
Mohit Panjwani
d9db0f9401 Merge pull request #80 from eboye/master
Add Serbian Dinar currency
2019-12-21 14:08:10 +05:30
Mohit Panjwani
c0da7c7339 Merge pull request #89 from claretnnamocha/master
Docs
2019-12-20 19:15:16 +05:30
Claret Nnamocha
7e7599b4a7 Merge branch 'master' into master 2019-12-20 09:35:03 +01:00
Claret Nnamocha
99cd88e6c6 Revert "Update CompanyController.php"
This reverts commit 053a06229c.
2019-12-20 09:32:29 +01:00
Claret Nnamocha
053a06229c Update CompanyController.php 2019-12-20 09:30:15 +01:00
Mohit Panjwani
1a6e8280a8 update readme 2019-12-18 20:58:44 +05:30
Mohit Panjwani
125e8be83c Merge pull request #87 from hsnapps/master
Added the Arabic language localization
2019-12-18 20:56:06 +05:30
Hassan Ali
4d89ca2101 Added the Arabic language localization 2019-12-18 10:18:04 +03:00
Vasilj Milošević
e8aee3bb32 Add Serbian Dinar currency 2019-12-17 11:32:58 +01:00
Claret Nnamocha
d3c7ca75f0 Documenting web routes 2019-12-16 20:41:59 +01:00
Claret Nnamocha
694d5f56d5 Documenting Controllers 2019-12-16 20:17:43 +01:00
Mohit Panjwani
a48439785c Merge pull request #68 from BirkhoffLee/master
Docker: fix update functionality
2019-12-14 21:23:24 +05:30
Birkhoff Lee
7c9bd84f00 Docker: fix update functionality
Added php zip extension
2019-12-14 15:43:01 +00:00
Mohit Panjwani
bd5a93d81c Merge branch 'master' of https://github.com/bytefury/crater 2019-12-14 19:56:24 +05:30
Mohit Panjwani
858e10953b fix grammar 2019-12-14 19:13:59 +05:30
Mohit Panjwani
3617032735 Merge branch 'build210' into 'master'
fix installation issue & build 210

See merge request mohit.panjvani/crater-web!143
2019-12-14 13:27:26 +00:00
raishvaria
75ddc51b1e fix installation issue & build 210 2019-12-14 18:50:13 +05:30
Mohit Panjwani
1dfa36e396 Merge branch 'build210' into 'master'
fix estimate & invoice tax issue

See merge request mohit.panjvani/crater-web!142
2019-12-14 13:06:38 +00:00
raishvaria
d9e9a5a540 fix estimate & invoice tax issue 2019-12-14 18:29:46 +05:30
Mohit Panjwani
ea6e11c324 Merge branch 'build210' into 'master'
fix version update issue

See merge request mohit.panjvani/crater-web!141
2019-12-14 12:48:37 +00:00
raishvaria
f55dfe0b46 fix version update issue 2019-12-14 17:12:47 +05:30
Mohit Panjwani
3eac3b8af5 Merge branch 'build210' into 'master'
fix auto auto generate issue & build210

See merge request mohit.panjvani/crater-web!140
2019-12-14 11:20:01 +00:00
raishvaria
2b2bd4351a fix auto auto generate issue & build210 2019-12-14 15:45:26 +05:30
Mohit Panjwani
b9c32bbdc1 Merge branch 'build-version210' into 'master'
Build version210

See merge request mohit.panjvani/crater-web!139
2019-12-14 09:49:21 +00:00
raishvaria
bceffbf6a0 build version210 2019-12-14 14:43:55 +05:30
raishvaria
7c6a40374d fix tax percent & pdf money format issue 2019-12-14 14:42:34 +05:30
raishvaria
d04e142a3e build version210 2019-12-14 13:59:59 +05:30
raishvaria
f11436736b add settings use in Update listener 2019-12-14 13:57:18 +05:30
raishvaria
9271ceba45 Merge branch 'master' of https://gitlab.com/mohit.panjvani/crater-web into build-version210 2019-12-14 13:55:26 +05:30
raishvaria
c88eb24265 fix pdf & installation issue 2019-12-14 13:54:35 +05:30
Mohit Panjwani
5eb0a04378 Update issue templates 2019-12-14 13:03:42 +05:30
Mohit Panjwani
d926073095 add ios link to readme 2019-12-14 12:55:08 +05:30
Mohit Panjwani
a691969025 Merge branch 'master' of https://github.com/bytefury/crater 2019-12-14 12:35:40 +05:30
Mohit Panjwani
7df06fb005 fix invoice number validation 2019-12-14 12:35:32 +05:30
Mohit Panjwani
45db850025 Merge pull request #59 from vkiranmaniya/master
Removed JSON SQL datatype, Replaced with TEXT Type
2019-12-14 12:32:31 +05:30
Kiran Maniya
18a50315ba Removed json SQL datatype, Replaced with text
The JSON SQL datatype is not supported in some of SQL server(i.e. 5.6.44). Replaced it with text datatype.
2019-12-13 17:24:07 +05:30
raishvaria
bce1b4bb3e build 210 2019-12-13 17:03:55 +05:30
raishvaria
ddd204105f fix installation issue 2019-12-13 17:03:44 +05:30
Mohit Panjwani
e030d4b9d0 Merge branch 'build-210' into 'master'
build version210

See merge request mohit.panjvani/crater-web!138
2019-12-13 10:48:54 +00:00
raishvaria
302968225a build version210 2019-12-13 15:22:37 +05:30
Mohit Panjwani
e59bf288ce Merge branch 'pdf-issues' into 'master'
Fix PDF issues

See merge request mohit.panjvani/crater-web!137
2019-12-13 09:43:32 +00:00
raishvaria
b1fcd90b62 refactor format_money_pdf helpers 2019-12-13 14:40:17 +05:30
raishvaria
ddb0ff1b8a fix pdf currency display issue 2019-12-13 14:34:21 +05:30
radhu587
ce99fa3d82 Fix PDF issues 2019-12-13 13:31:26 +05:30
Mohit Panjwani
e28c89085d Merge branch 'master' 2019-12-12 20:42:17 +05:30
Mohit Panjwani
34f7e33abc Merge branch 'master' of https://github.com/bytefury/crater 2019-12-12 20:31:57 +05:30
Mohit Panjwani
80be7a492d Merge pull request #50 from nhedger/master
Add missing currency code to customer create/edit form
2019-12-12 20:27:45 +05:30
Mohit Panjwani
387cb4490d Merge branch 'add-customization' into 'master'
update invoice, estimate & payment vars

See merge request mohit.panjvani/crater-web!135
2019-12-12 14:56:10 +00:00
Mohit Panjwani
09829a559e Merge branch 'pdf-issue' into 'master'
fix Pdf issue

See merge request mohit.panjvani/crater-web!136
2019-12-12 14:55:04 +00:00
Nicolas Hedger
b06fc5f0b9 Add missing currency code to customer create form 2019-12-12 14:37:16 +01:00
raishvaria
5f7401f622 update invoice, estimate & payment vars 2019-12-12 16:04:12 +05:30
Mohit Panjwani
4f6dae919b Merge branch 'add-customization' into 'master'
Add customization

See merge request mohit.panjvani/crater-web!134
2019-12-12 10:05:16 +00:00
radhu587
36be395579 Remove unwanted code 2019-12-12 14:59:54 +05:30
raishvaria
79e77f9e16 fix pdf lang issue 2019-12-12 14:20:31 +05:30
radhu587
cbf0af2120 Refactor Customization Page 2019-12-12 13:46:09 +05:30
Mohit Panjwani
92f754e888 Merge pull request #43 from nhedger/master
Prepend currency code to label to allow searching by currency code
2019-12-12 13:25:21 +05:30
raishvaria
a6896eaa01 Merge branch 'master' of https://gitlab.com/mohit.panjvani/crater-web into pdf-issue 2019-12-12 13:17:52 +05:30
raishvaria
01f3646869 add meta tag 2019-12-12 11:50:25 +05:30
Mohit Panjwani
b2918e9dbb Merge pull request #44 from JaxWilko/fix-incorrect-headers-sent
Removed a space that forced apache to send the wrong headers
2019-12-12 08:59:00 +05:30
Jack Wilkinson
0a064ec5ba Removed a space that forced apache to send the wrong headers 2019-12-12 00:50:45 +00:00
Nicolas Hedger
5f0b4b3496 Prepend currency code to selector label. 2019-12-11 20:36:46 +01:00
Mohit Panjwani
17b59f0d19 Merge branch 'master' 2019-12-11 20:16:23 +05:30
Mohit Panjwani
283b910cc3 remove state & city routes from api.php and fix cancel spelling mistake 2019-12-11 20:16:11 +05:30
radhu587
81739827c0 Add customization 2019-12-11 17:02:28 +05:30
Mohit Panjwani
90edc3a85e Merge branch 'dashboard-initial-loading' into 'master'
refactor initial data loading in dashboard

See merge request mohit.panjvani/crater-web!133
2019-12-11 10:18:58 +00:00
Mohit Panjwani
655c2a7849 Merge branch 'master' of https://github.com/bytefury/crater 2019-12-11 13:35:32 +05:30
Mohit Panjwani
ca833d174e update readme 2019-12-11 13:35:13 +05:30
Mohit Panjwani
33e8381fc4 Merge pull request #8 from BirkhoffLee/master
Initial Docker support
2019-12-11 13:04:43 +05:30
Birkhoff Lee
9b5125d440 Merge branch 'master' of https://github.com/bytefury/crater 2019-12-11 12:45:03 +08:00
Birkhoff Lee
2899021804 Update example env in accordance w/ Docker setup 2019-12-10 23:53:28 +08:00
Birkhoff Lee
d8f6d03d1e Docker: rename nginx container name 2019-12-10 23:52:23 +08:00
Birkhoff Lee
c474e98925 Docker: copy example env file when building 2019-12-10 23:40:59 +08:00
satyaprakash10
799d212d9b refactor classes on invoice and estimate view page 2019-12-10 11:15:49 +05:30
yogesh_gohil
9424dc6c27 refactor initial data loading in dashboard 2019-12-09 19:27:21 +05:30
satyaprakash10
fa15502ce7 refactor primary color-var 2019-12-09 19:20:11 +05:30
satyaprakash10
1f4d3bf784 sidebar-view modified 2019-12-09 18:58:53 +05:30
Birkhoff Lee
3692373cd2 Docker: switch from passport:install to passport:keys during build 2019-12-09 19:25:57 +08:00
Birkhoff Lee
0c71356f59 Docker: remove migration instruction 2019-12-04 18:31:06 +08:00
Birkhoff Lee
e539bb501d Docker: persistant database storage in example docker-compose.yaml 2019-12-04 17:22:59 +08:00
Birkhoff Lee
2fcd169270 Downgrade Docker image php version to 7.3.12 2019-12-04 17:19:16 +08:00
Birkhoff Lee
14d71fedb3 Rename docker-compose.yml.example -> docker-compose.yaml.example 2019-12-04 14:54:28 +08:00
Birkhoff Lee
7fe9a4c2a2 Fix Dockerfile and docker-compose.yml
1. Generate a testing SQLite db on build
2. Optimize image layer caching
3. Fix permissions
4. Simplify nginx configuration
5. Fix nginx infinite redirect loop (couldn't access app folder)
2019-12-04 14:49:57 +08:00
Birkhoff Lee
7b697a477e Fix MariaDB config in Docker compose
by specifying a root password.
2019-12-04 11:20:50 +08:00
Birkhoff Lee
146cf835b9 Fix composer install in Dockerfile 2019-12-04 08:59:01 +08:00
Birkhoff Lee
ec87e72547 Add .dockerignore file
This excludes unnecessary files for production use on Docker image
build.
2019-12-04 08:26:31 +08:00
Birkhoff Lee
bf2e8c9c99 Use multi-stage build for Docker image
1. Allows to build the composer dependencies with official composer img
2. php-fpm --nodaemonize: Force to stay in foreground and ignore daemo-
   nize option from configuration file
2019-12-04 08:23:11 +08:00
Birkhoff Lee
b6096aadfa Add MariaDB to docker-compose example
1. Gives an example set up of a MySQL database in docker-compose
2. `php` now depends on `db`, and `nginx` depends on `php`. This
ensures the integrity of the stack.
2019-12-03 21:31:56 +08:00
Birkhoff Lee
1cbc41c3ce Simplify docker-ext-install in Dockerfile 2019-12-03 20:24:54 +08:00
Birkhoff Lee
8bc5ea2d5e Initial Docker support
This commit adds:
1. A Dockerfile that runs PHP 7.2 FPM on Alpine Linux
2. A example docker-compose file that simplifies deployment
2019-11-21 12:54:22 +08:00
1000 changed files with 79410 additions and 66522 deletions

10
.dockerignore Normal file
View File

@@ -0,0 +1,10 @@
.dockerignore
.gitignore
*.md
.git/
.idea/
.DS_Store/
docker-compose.*
LICENSE
nginx.conf
yarn.lock

View File

@@ -1,20 +1,21 @@
APP_ENV=production
APP_KEY=base64:kgk/4DW1vEVy7aEvet5FPp5un6PIGe/so8H0mvoUtW0=
APP_DEBUG=false
APP_DEBUG=true
APP_LOG_LEVEL=debug
APP_URL=http://crater.test
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_HOST=db
DB_PORT=3306
DB_DATABASE=crater
DB_USERNAME=root
DB_PASSWORD=bytefury
DB_USERNAME=crater
DB_PASSWORD="crater"
BROADCAST_DRIVER=log
CACHE_DRIVER=file
SESSION_DRIVER=file
QUEUE_DRIVER=sync
SESSION_DRIVER=cookie
SESSION_LIFETIME=1440
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
@@ -31,6 +32,5 @@ PUSHER_APP_ID=
PUSHER_KEY=
PUSHER_SECRET=
PROXY_OAUTH_CLIENT_ID=2
PROXY_OAUTH_CLIENT_SECRET=SECRET-GENERATED-KEY-HERE
PROXY_OAUTH_GRANT_TYPE=password
SANCTUM_STATEFUL_DOMAINS=crater.test
SESSION_DOMAIN=crater.test

View File

@@ -2,3 +2,12 @@ APP_ENV=testing
APP_DEBUG=true
APP_KEY=base64:IdDlpLmYyWA9z4Ruj5st1FSYrhCR7lPOscLGCz2Jf4I=
DB_CONNECTION=sqlite
MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=587
MAIL_USERNAME=ff538f0e1037f4
MAIL_PASSWORD=c04c81145fcb73
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS="admin@crater.com"
MAIL_FROM_NAME="John Doe"

View File

@@ -1,10 +0,0 @@
{
"root": true,
"extends": [
"plugin:vue/recommended",
"standard"
],
"rules": {
"vue/max-attributes-per-line" : 3
}
}

20
.eslintrc.js Normal file
View File

@@ -0,0 +1,20 @@
module.exports = {
root: true,
env: {
node: true,
},
extends: [
'plugin:vue/recommended',
'eslint:recommended',
'prettier/vue',
'plugin:prettier/recommended',
],
parserOptions: {
parser: 'babel-eslint',
},
plugins: ['prettier'],
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
},
}

26
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,26 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Please complete the following information:**
- Crater version:
- PHP version:
- Database type and version:
**Optional info**
- OS: [e.g. Ubuntu]
- Browser: [e.g. chrome, safari]

View File

@@ -0,0 +1,17 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.

34
.github/workflows/ci.yaml vendored Normal file
View File

@@ -0,0 +1,34 @@
name: CI
on: [push, pull_request]
jobs:
build-test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
php: ['7.4', '8.0']
name: PHP ${{ matrix.php }}
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Install dependencies
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: exif
- name: Install PHP 7 dependencies
run: composer update --no-interaction --no-progress
if: "matrix.php < 8"
- name: Install PHP 8 dependencies
run: composer update --ignore-platform-req=php --no-interaction --no-progress
if: "matrix.php >= 8"
- name: Unit Tests
run: php ./vendor/bin/pest

1
.gitignore vendored
View File

@@ -11,3 +11,4 @@ Homestead.yaml
.rnd
/.expo
/.vscode
/docker-compose/db/data/

5
.prettierrc.json Normal file
View File

@@ -0,0 +1,5 @@
{
"semi": false,
"singleQuote": true,
"tabWidth": 2
}

39
Dockerfile Normal file
View File

@@ -0,0 +1,39 @@
FROM php:7.4-fpm
# Arguments defined in docker-compose.yml
ARG user
ARG uid
# Install system dependencies
RUN apt-get update && apt-get install -y \
git \
curl \
libpng-dev \
libonig-dev \
libxml2-dev \
zip \
unzip \
libzip-dev \
libmagickwand-dev
# Clear cache
RUN apt-get clean && rm -rf /var/lib/apt/lists/*
RUN pecl install imagick \
&& docker-php-ext-enable imagick
# Install PHP extensions
RUN docker-php-ext-install pdo_mysql mbstring zip exif pcntl bcmath gd
# Get latest Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
# Create system user to run Composer and Artisan Commands
RUN useradd -G www-data,root -u $uid -d /home/$user $user
RUN mkdir -p /home/$user/.composer && \
chown -R $user:$user /home/$user
# Set working directory
WORKDIR /var/www
USER $user

View File

@@ -1,36 +0,0 @@
<?php
namespace Crater;
use Illuminate\Database\Eloquent\Model;
use Crater\User;
use Crater\Country;
class Address extends Model
{
const BILLING_TYPE = 'BILLING';
const SHIPPING_TYPE = 'SHIPPING';
protected $fillable = [
'name',
'address_street_1',
'address_street_2',
'city',
'state',
'country_id',
'zip',
'phone',
'fax',
'type',
'user_id'
];
public function user()
{
return $this->belongsTo(User::class);
}
public function country()
{
return $this->belongsTo(Country::class);
}
}

View File

@@ -1,36 +0,0 @@
<?php
namespace Crater;
use Illuminate\Database\Eloquent\Model;
use Crater\User;
use Crater\CompanySetting;
use Spatie\MediaLibrary\HasMedia\HasMedia;
use Spatie\MediaLibrary\HasMedia\HasMediaTrait;
class Company extends Model implements HasMedia
{
use HasMediaTrait;
protected $fillable = ['name', 'logo', 'unique_hash'];
protected $appends=['logo'];
public function getLogoAttribute()
{
$logo = $this->getMedia('logo')->first();
if ($logo) {
return asset($logo->getUrl());
}
return ;
}
public function user()
{
return $this->hasOne(User::class);
}
public function settings()
{
return $this->hasMany(CompanySetting::class);
}
}

View File

@@ -1,47 +0,0 @@
<?php
namespace Crater;
use Illuminate\Database\Eloquent\Model;
class CompanySetting extends Model
{
protected $fillable = ['company_id', 'option', 'value'];
public function company()
{
return $this->belongsTo(Company::class);
}
public static function setSetting($key, $setting, $company_id)
{
$old = self::whereOption($key)->whereCompany($company_id)->first();
if ($old) {
$old->value = $setting;
$old->save();
return;
}
$set = new CompanySetting();
$set->option = $key;
$set->value = $setting;
$set->company_id = $company_id;
$set->save();
}
public static function getSetting($key, $company_id)
{
$setting = static::whereOption($key)->whereCompany($company_id)->first();
if ($setting) {
return $setting->value;
} else {
return null;
}
}
public function scopeWhereCompany($query, $company_id)
{
$query->where('company_id', $company_id);
}
}

View File

@@ -3,7 +3,7 @@ namespace Crater\Console\Commands;
use Illuminate\Console\Command;
use Carbon\Carbon;
use Crater\Estimate;
use Crater\Models\Estimate;
class CheckEstimateStatus extends Command
{

View File

@@ -3,7 +3,7 @@ namespace Crater\Console\Commands;
use Illuminate\Console\Command;
use Carbon\Carbon;
use Crater\Invoice;
use Crater\Models\Invoice;
class CheckInvoiceStatus extends Command
{

View File

@@ -0,0 +1,69 @@
<?php
namespace Crater\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Console\ConfirmableTrait;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Filesystem\Filesystem;
class ResetApp extends Command
{
use ConfirmableTrait;
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'reset:app {--force}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Clean database, database_created and public/storage folder';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
if (!$this->confirmToProceed()) {
return;
}
$this->info('Running migrate:fresh');
Artisan::call('migrate:fresh --seed --force');
$this->info('Seeding database');
Artisan::call('db:seed', ['--class' => 'DemoSeeder', '--force' => true]);
$path = base_path('.env');
if (file_exists($path)) {
file_put_contents($path, str_replace(
'APP_DEBUG=true',
'APP_DEBUG=false',
file_get_contents($path)
));
}
$this->info('App has been reset successfully');
}
}

View File

@@ -0,0 +1,240 @@
<?php
namespace Crater\Console\Commands;
use Illuminate\Console\Command;
use Crater\Space\Updater;
use Crater\Models\Setting;
// Implementation taken from Akaunting - https://github.com/akaunting/akaunting
class UpdateCommand extends Command
{
public $installed;
public $version;
public $response;
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'crater:update';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Automatically update your crater app';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*/
public function handle()
{
set_time_limit(3600); // 1 hour
$this->installed = $this->getInstalledVersion();
$this->response = $this->getLatestVersionResponse();
$this->version = ($this->response) ? $this->response->version : false;
if ($this->response == 'extension_required') {
$this->info('Sorry! Your system does not meet the minimum requirements for this update.');
$this->info('Please retry after installing the required version/extensions.');
return;
}
if (!$this->version) {
$this->info('No Update Available! You are already on the latest version.');
return;
}
if (!$this->confirm("Do you wish to update to {$this->version}?")) {
return;
}
if (!$path = $this->download()) {
return;
}
if (!$path = $this->unzip($path)) {
return;
}
if (!$this->copyFiles($path)) {
return;
}
if(isset($this->response->deleted_files) && !empty($this->response->deleted_files)) {
if (!$this->deleteFiles($this->response->deleted_files)) {
return;
}
}
if (!$this->migrateUpdate()) {
return;
}
if (!$this->finish()) {
return;
}
$this->info('Successfully updated to ' . $this->version);
}
public function getInstalledVersion()
{
return Setting::getSetting('version');
}
public function getLatestVersionResponse()
{
$this->info('Your currently installed version is ' . $this->installed);
$this->line('');
$this->info('Checking for update...');
try {
$response = Updater::checkForUpdate($this->installed);
if ($response->success) {
$extensions = $response->version->extensions;
$is_required = false;
foreach ($extensions as $key => $extension) {
if(!$extension) {
$is_required = true;
$this->info('❌ '.$key);
}
$this->info('✅ '.$key);
}
if($is_required) {
return 'extension_required';
}
return $response->version;
}
return false;
} catch (\Exception $e) {
$this->error($e->getMessage());
return false;
}
}
public function download()
{
$this->info('Downloading update...');
try {
$path = Updater::download($this->version, 1);
if (!is_string($path)) {
$this->error('Download exception');
return false;
}
} catch (\Exception $e) {
$this->error($e->getMessage());
return false;
}
return $path;
}
public function unzip($path)
{
$this->info('Unzipping update package...');
try {
$path = Updater::unzip($path);
if (!is_string($path)) {
$this->error('Unzipping exception');
return false;
}
} catch (\Exception $e) {
$this->error($e->getMessage());
return false;
}
return $path;
}
public function copyFiles($path)
{
$this->info('Copying update files...');
try {
Updater::copyFiles($path);
} catch (\Exception $e) {
$this->error($e->getMessage());
return false;
}
return true;
}
public function deleteFiles($files)
{
$this->info('Deleting unused old files...');
try {
Updater::deleteFiles($files);
} catch (\Exception $e) {
$this->error($e->getMessage());
return false;
}
return true;
}
public function migrateUpdate()
{
$this->info('Running Migrations...');
try {
Updater::migrateUpdate();
} catch (\Exception $e) {
$this->error($e->getMessage());
return false;
}
return true;
}
public function finish()
{
$this->info('Finishing update...');
try {
Updater::finishUpdate($this->installed, $this->version);
} catch (\Exception $e) {
$this->error($e->getMessage());
return false;
}
return true;
}
}

View File

@@ -12,7 +12,8 @@ class Kernel extends ConsoleKernel
* @var array
*/
protected $commands = [
Commands\ResetApp::class,
Commands\UpdateCommand::class
];
/**

View File

@@ -1,226 +0,0 @@
<?php
namespace Crater;
use Illuminate\Database\Eloquent\Model;
use Crater\CompanySetting;
use Carbon\Carbon;
class Estimate extends Model
{
const STATUS_DRAFT = 'DRAFT';
const STATUS_SENT = 'SENT';
const STATUS_VIEWED = 'VIEWED';
const STATUS_EXPIRED = 'EXPIRED';
const STATUS_ACCEPTED = 'ACCEPTED';
const STATUS_REJECTED = 'REJECTED';
protected $dates = [
'created_at',
'updated_at',
'deleted_at',
'estimate_date',
'expiry_date'
];
protected $appends = [
'formattedExpiryDate',
'formattedEstimateDate'
];
protected $fillable = [
'estimate_date',
'expiry_date',
'estimate_number',
'user_id',
'company_id',
'reference_number',
'estimate_template_id',
'discount',
'discount_type',
'discount_val',
'status',
'sub_total',
'tax_per_item',
'discount_per_item',
'total',
'tax',
'notes',
'unique_hash'
];
protected $casts = [
'total' => 'float',
'tax' => 'float',
'sub_total' => 'float'
];
public static function getNextEstimateNumber()
{
// Get the last created order
$lastOrder = Estimate::orderBy('created_at', 'desc')->first();
if (!$lastOrder) {
// We get here if there is no order at all
// If there is no number set it to 0, which will be 1 at the end.
$number = 0;
} else {
$number = explode("-",$lastOrder->estimate_number);
$number = $number[1];
}
// If we have ORD000001 in the database then we only want the number
// So the substr returns this 000001
// Add the string in front and higher up the number.
// the %05d part makes sure that there are always 6 numbers in the string.
// so it adds the missing zero's when needed.
return sprintf('%06d', intval($number) + 1);
}
public function items()
{
return $this->hasMany('Crater\EstimateItem');
}
public function user()
{
return $this->belongsTo('Crater\User');
}
public function taxes()
{
return $this->hasMany(Tax::class);
}
public function estimateTemplate()
{
return $this->belongsTo('Crater\EstimateTemplate');
}
public function getEstimateNumAttribute()
{
$position = $this->strposX($this->estimate_number, "-", 2) + 1;
return substr($this->estimate_number, $position);
}
private function strposX($haystack, $needle, $number)
{
if ($number == '1') {
return strpos($haystack, $needle);
} elseif ($number > '1') {
return strpos(
$haystack,
$needle,
$this->strposX($haystack, $needle, $number - 1) + strlen($needle)
);
} else {
return error_log('Error: Value for parameter $number is out of range');
}
}
public function getFormattedExpiryDateAttribute($value)
{
$dateFormat = CompanySetting::getSetting('carbon_date_format', $this->company_id);
return Carbon::parse($this->expiry_date)->format($dateFormat);
}
public function getFormattedEstimateDateAttribute($value)
{
$dateFormat = CompanySetting::getSetting('carbon_date_format', $this->company_id);
return Carbon::parse($this->estimate_date)->format($dateFormat);
}
public function scopeEstimatesBetween($query, $start, $end)
{
return $query->whereBetween(
'estimates.estimate_date',
[$start->format('Y-m-d'), $end->format('Y-m-d')]
);
}
public function scopeWhereStatus($query, $status)
{
return $query->where('estimates.status', $status);
}
public function scopeWhereEstimateNumber($query, $estimateNumber)
{
return $query->where('estimates.estimate_number', $estimateNumber);
}
public function scopeWhereSearch($query, $search)
{
foreach (explode(' ', $search) as $term) {
$query->whereHas('user', function ($query) use ($term) {
$query->where('name', 'LIKE', '%'.$term.'%')
->orWhere('contact_name', 'LIKE', '%'.$term.'%')
->orWhere('company_name', 'LIKE', '%'.$term.'%');
});
}
}
public function scopeApplyFilters($query, array $filters)
{
$filters = collect($filters);
if ($filters->get('search')) {
$query->whereSearch($filters->get('search'));
}
if ($filters->get('estimate_number')) {
$query->whereEstimateNumber($filters->get('estimate_number'));
}
if ($filters->get('status')) {
$query->whereStatus($filters->get('status'));
}
if ($filters->get('from_date') && $filters->get('to_date')) {
$start = Carbon::createFromFormat('d/m/Y', $filters->get('from_date'));
$end = Carbon::createFromFormat('d/m/Y', $filters->get('to_date'));
$query->estimatesBetween($start, $end);
}
if ($filters->get('customer_id')) {
$query->whereCustomer($filters->get('customer_id'));
}
if ($filters->get('orderByField') || $filters->get('orderBy')) {
$field = $filters->get('orderByField') ? $filters->get('orderByField') : 'estimate_number';
$orderBy = $filters->get('orderBy') ? $filters->get('orderBy') : 'asc';
$query->whereOrder($field, $orderBy);
}
}
public function scopeWhereOrder($query, $orderByField, $orderBy)
{
$query->orderBy($orderByField, $orderBy);
}
public function scopeWhereCompany($query, $company_id)
{
$query->where('estimates.company_id', $company_id);
}
public function scopeWhereCustomer($query, $customer_id)
{
$query->where('estimates.user_id', $customer_id);
}
public static function deleteEstimate($id)
{
$estimate = Estimate::find($id);
if ($estimate->items()->exists()) {
$estimate->items()->delete();
}
if ($estimate->taxes()->exists()) {
$estimate->taxes()->delete();
}
$estimate->delete();
return true;
}
}

View File

@@ -2,13 +2,7 @@
namespace Crater\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Foundation\Events\Dispatchable;
class UpdateFinished
{
@@ -25,7 +19,7 @@ class UpdateFinished
*/
public function __construct($old, $new)
{
$this->old = $old;
$this->new = $new;
$this->old = $old;
$this->new = $new;
}
}

View File

@@ -1,7 +1,7 @@
<?php
namespace Crater\Exceptions;
use Exception;
use Throwable;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
class Handler extends ExceptionHandler
@@ -30,10 +30,10 @@ class Handler extends ExceptionHandler
*
* This is a great spot to send exceptions to Sentry, Bugsnag, etc.
*
* @param \Exception $exception
* @param \Throwable $exception
* @return void
*/
public function report(Exception $exception)
public function report(Throwable $exception)
{
parent::report($exception);
}
@@ -42,10 +42,10 @@ class Handler extends ExceptionHandler
* Render an exception into an HTTP response.
*
* @param \Illuminate\Http\Request $request
* @param \Exception $exception
* @param \Throwable $exception
* @return \Illuminate\Http\Response
*/
public function render($request, Exception $exception)
public function render($request, Throwable $exception)
{
return parent::render($request, $exception);
}

View File

@@ -1,39 +0,0 @@
<?php
namespace Crater;
use Illuminate\Database\Eloquent\Model;
use Crater\Expense;
use Carbon\Carbon;
class ExpenseCategory extends Model
{
protected $fillable = ['name', 'company_id', 'description'];
/**
* The accessors to append to the model's array form.
*
* @var array
*/
protected $appends = ['amount', 'formattedCreatedAt'];
public function expenses()
{
return $this->hasMany(Expense::class);
}
public function getFormattedCreatedAtAttribute($value)
{
$dateFormat = CompanySetting::getSetting('carbon_date_format', $this->company_id);
return Carbon::parse($this->created_at)->format($dateFormat);
}
public function getAmountAttribute()
{
return $this->expenses()->sum('amount');
}
public function scopeWhereCompany($query, $company_id)
{
$query->where('company_id', $company_id);
}
}

View File

@@ -0,0 +1,50 @@
<?php
namespace Crater\Generators;
use Crater\Models\Estimate;
use Crater\Models\Invoice;
use Crater\Models\Payment;
use Spatie\MediaLibrary\MediaCollections\Models\Media;
use Spatie\MediaLibrary\Support\PathGenerator\PathGenerator;
class CustomPathGenerator implements PathGenerator
{
public function getPath(Media $media): string
{
return $this->getBasePath($media) . '/';
}
public function getPathForConversions(Media $media): string
{
return $this->getBasePath($media) . '/conversations/';
}
public function getPathForResponsiveImages(Media $media): string
{
return $this->getBasePath($media) . '/responsive-images/';
}
/*
* Get a unique base path for the given media.
*/
protected function getBasePath(Media $media): string
{
$folderName = null;
if ($media->model_type == Invoice::class) {
$folderName = 'Invoices';
} elseif ($media->model_type == Estimate::class) {
$folderName = 'Estimates';
} elseif ($media->model_type == Payment::class) {
$folderName = 'Payments';
} else {
$folderName = $media->getKey();
}
return $folderName;
}
}

View File

@@ -0,0 +1,24 @@
<?php
namespace Crater\Http\Controllers;
use Crater\Models\Setting;
use Illuminate\Http\Request;
class AppVersionController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function __invoke(Request $request)
{
$version = Setting::getSetting('version');
return response()->json([
'version' => $version,
]);
}
}

View File

@@ -1,194 +0,0 @@
<?php
namespace Crater\Http\Controllers\Auth;
use Crater\Proxy\HttpKernelProxy;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Validation\ValidationException;
use Illuminate\Foundation\Auth\ThrottlesLogins;
use Validator;
use Hash;
use Crater\User;
use Auth;
use Crater\Http\Controllers\Controller;
class AccessTokensController extends Controller
{
use ThrottlesLogins;
/**
* A tool for proxying requests to the existing application.
*
* @var HttpKernelProxy
*/
protected $proxy;
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct(HttpKernelProxy $proxy)
{
$this->middleware('api')->except(['store', 'update']);
$this->proxy = $proxy;
}
/**
* Get the login username to be used by the controller.
*
* @return string
*/
public function username()
{
return 'email';
}
/**
* Generate a new access token.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
$request->validate([
'username' => 'required|email',
'password' => 'required|string|min:8',
]);
if ($this->hasTooManyLoginAttempts($request)) {
$this->fireLockoutEvent($request);
return $this->sendLockoutResponse($request);
}
return $this->requestPasswordGrant($request);
}
/**
* Refresh an access token.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function update(Request $request)
{
$token = $request->cookie('refresh_token');
if (!$token) {
throw ValidationException::withMessages([
'refresh_token' => trans('oauth.missing_refresh_token')
]);
}
$response = $this->proxy->postJson('oauth/token', [
'client_id' => config('auth.proxy.client_id'),
'client_secret' => config('auth.proxy.client_secret'),
'grant_type' => 'refresh_token',
'refresh_token' => $token,
'scopes' => '[*]',
]);
if ($response->isSuccessful()) {
return $this->sendSuccessResponse($response);
}
return response($response->getContent(), $response->getStatusCode());
}
/**
* Get the guard to be used during authentication.
*
* @return \Illuminate\Contracts\Auth\StatefulGuard
*/
protected function guard()
{
return Auth::guard('api');
}
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function destroy(Request $request)
{
$accessToken = Auth::user()->token();
\DB::table('oauth_refresh_tokens')
->where('access_token_id', $accessToken->id)
->update([
'revoked' => true
]);
$accessToken->revoke();
return response()->json(null, 200);
}
/**
* Create a new access token from a password grant client.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function requestPasswordGrant(Request $request)
{
$response = $this->proxy->postJson('oauth/token', [
'client_id' => config('auth.proxy.client_id'),
'client_secret' => config('auth.proxy.client_secret'),
'grant_type' => config('auth.proxy.grant_type'),
'username' => $request->username,
'password' => $request->password,
'scopes' => '[*]'
]);
$user = User::where('email', $request->username)->first();
if ($response->isSuccessful()) {
$this->clearLoginAttempts($request);
return $this->sendSuccessResponse($response, $user);
}
$this->incrementLoginAttempts($request);
return response($response->getContent(), $response->getStatusCode());
}
/**
* Return a successful response for requesting an api token.
*
* @param \Illuminate\Http\Response $response
* @return \Illuminate\Http\Response
*/
public function sendSuccessResponse(Response $response, $user)
{
$data = json_decode($response->getContent());
$content = [
'access_token' => $data->access_token,
'expires_in' => $data->expires_in,
];
return response($content, $response->getStatusCode())->cookie(
'refresh_token',
$data->refresh_token,
10 * 24 * 60,
"",
"",
true,
true
);
}
public function isRegistered(Request $request)
{
if (User::whereEmail($request->email)->first()) {
return 'true';
} else {
return 'false';
}
}
}

View File

@@ -1,258 +0,0 @@
<?php
namespace Crater\Http\Controllers;
use Illuminate\Http\Request;
use Crater\User;
use Crater\Setting;
use Crater\Company;
use Crater\Address;
use Crater\Http\Requests\SettingRequest;
use Crater\Http\Requests\SettingKeyRequest;
use Crater\Http\Requests\ProfileRequest;
use Crater\Http\Requests\CompanyRequest;
use Crater\Http\Requests\CompanySettingRequest;
use Crater\Http\Requests\NotificationSettingsRequest;
use Crater\Space\CurrencyFormatter;
use Crater\Space\DateFormatter;
use Crater\Space\TimeZones;
use Crater\Currency;
use Crater\CompanySetting;
class CompanyController extends Controller
{
public function getAdmin()
{
return User::find(1);
}
public function updateAdminProfile(ProfileRequest $request)
{
$verifyEmail = User::where('email', $request->email)->first();
$user = auth()->user();
if ($verifyEmail) {
if ($verifyEmail->id !== $user->id) {
return response()->json([
'error' => 'Email already in use'
]);
}
}
$user->name = $request->name;
$user->email = $request->email;
if ($request->has('password')) {
$user->password = bcrypt($request->password);
}
$user->save();
return response()->json([
'user' => $user,
'success' => true
]);
}
public function getAdminCompany()
{
$user = User::with(['addresses', 'addresses.country', 'company'])->find(1);
return response()->json([
'user' => $user
]);
}
public function updateAdminCompany(CompanyRequest $request)
{
$user = User::find(1);
$company = $user->company;
$company->name = $request->name;
$company->save();
if ($request->has('logo')) {
$company->clearMediaCollection('logo');
$company->addMediaFromRequest('logo')->toMediaCollection('logo');
}
$fields = $request->only(['address_street_1', 'address_street_2', 'city', 'state', 'country_id', 'zip', 'phone']);
$address = Address::updateOrCreate(['user_id' => 1], $fields);
$user = User::with(['addresses', 'addresses.country', 'company'])->find(1);
return response()->json([
'user' => $user,
'success' => true
]);
}
public function getGeneralSettings(Request $request)
{
$date_formats = DateFormatter::get_list();
$time_zones = TimeZones::get_list();
$fiscal_years = [
['key' => 'january-december' , 'value' => '1-12'],
['key' => 'february-january' , 'value' => '2-1'],
['key' => 'march-february' , 'value' => '3-2'],
['key' => 'april-march' , 'value' => '4-3'],
['key' => 'may-april' , 'value' => '5-4'],
['key' => 'june-may' , 'value' => '6-5'],
['key' => 'july-june' , 'value' => '7-6'],
['key' => 'august-july' , 'value' => '8-7'],
['key' => 'september-august' , 'value' => '9-8'],
['key' => 'october-september', 'value' => '10-9'],
['key' => 'november-october' , 'value' => '11-10'],
['key' => 'december-november', 'value' => '12-11'],
];
$language = CompanySetting::getSetting('language', $request->header('company'));
$carbon_date_format = CompanySetting::getSetting('carbon_date_format', $request->header('company'));
$moment_date_format = CompanySetting::getSetting('moment_date_format', $request->header('company'));
$time_zone = CompanySetting::getSetting('time_zone', $request->header('company'));
$currency = CompanySetting::getSetting('currency', $request->header('company'));
$fiscal_year = CompanySetting::getSetting('fiscal_year', $request->header('company'));
$languages = [
["code"=>"en", "name" => "English"],
["code"=>"fr", "name" => "French"],
["code"=>"es", "name" => "Spanish"]
];
return response()->json([
'languages' => $languages,
'date_formats' => $date_formats,
'time_zones' => $time_zones,
'time_zone' => $time_zone,
'currencies' => Currency::all(),
'fiscal_years' => $fiscal_years,
'fiscal_year' => $fiscal_year,
'selectedLanguage' => $language,
'selectedCurrency' => $currency,
'carbon_date_format' => $carbon_date_format,
'moment_date_format' => $moment_date_format,
]);
}
public function updateGeneralSettings(CompanySettingRequest $request)
{
$sets = [
'currency',
'time_zone',
'language',
'carbon_date_format',
'fiscal_year',
'moment_date_format'
];
foreach ($sets as $key) {
CompanySetting::setSetting($key, $request->$key, $request->header('company'));
}
return response()->json([
'success' => true
]);
}
public function updateSetting(SettingRequest $request)
{
CompanySetting::setSetting($request->key, $request->value, $request->header('company'));
return response()->json([
'success' => true
]);
}
public function getSetting(SettingKeyRequest $request)
{
$setting = CompanySetting::getSetting($request->key, $request->header('company'));
return response()->json([
$request->key => $setting
]);
}
public function getColors(Request $request)
{
$colors = [
'invoice_primary_color',
'invoice_column_heading',
'invoice_field_label',
'invoice_field_value',
'invoice_body_text',
'invoice_description_text',
'invoice_border_color',
'primary_text_color',
'heading_text_color',
'section_heading_text_color',
'border_color',
'body_text_color',
'footer_text_color',
'footer_total_color',
'footer_bg_color',
'date_text_color'
];
$colorSettings = CompanySetting::whereIn('option', $colors)
->whereCompany($request->header('company'))
->get();
return response()->json([
'colorSettings' => $colorSettings
]);
}
/**
* Upload the company logo to storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function uploadCompanyLogo(Request $request)
{
$data = json_decode($request->company_logo);
if($data) {
$company = Company::find($request->header('company'));
if($company) {
$company->clearMediaCollection('logo');
$company->addMediaFromBase64($data->data)
->usingFileName($data->name)
->toMediaCollection('logo');
}
}
return response()->json([
'success' => true
]);
}
/**
* Upload the Admin Avatar to public storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function uploadAdminAvatar(Request $request)
{
$data = json_decode($request->admin_avatar);
if($data) {
$user = auth()->user();
if($user) {
$user->clearMediaCollection('admin_avatar');
$user->addMediaFromBase64($data->data)
->usingFileName($data->name)
->toMediaCollection('admin_avatar');
}
}
return response()->json([
'user' => $user,
'success' => true
]);
}
}

View File

@@ -1,230 +0,0 @@
<?php
namespace Crater\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Crater\Conversation;
use Crater\Group;
use Crater\Http\Requests;
use Crater\Notifications\CustomerAdded;
use Crater\User;
use Illuminate\Support\Facades\Hash;
use Crater\Currency;
use Crater\CompanySetting;
use Crater\Address;
use Illuminate\Support\Facades\DB;
class CustomersController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index(Request $request)
{
$limit = $request->has('limit') ? $request->limit : 10;
$customers = User::customer()
->applyFilters($request->only([
'search',
'contact_name',
'display_name',
'phone',
'orderByField',
'orderBy'
]))
->whereCompany($request->header('company'))
->select('users.*',
DB::raw('sum(invoices.due_amount) as due_amount')
)
->groupBy('users.id')
->leftJoin('invoices', 'users.id', '=', 'invoices.user_id')
->paginate($limit);
$siteData = [
'customers' => $customers
];
return response()->json($siteData);
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Requests\CustomerRequest $request)
{
$verifyEmail = User::where('email', $request->email)->first();
$customer = new User();
$customer->name = $request->name;
$customer->currency_id = $request->currency_id;
$customer->company_id = $request->header('company');
$customer->email = $request->email;
$customer->phone = $request->phone;
$customer->company_name = $request->company_name;
$customer->contact_name = $request->contact_name;
$customer->website = $request->website;
$customer->enable_portal = $request->enable_portal;
$customer->role = 'customer';
$customer->password = Hash::make($request->password);
$customer->save();
if ($request->addresses) {
foreach ($request->addresses as $address) {
$newAddress = new Address();
$newAddress->name = $address["name"];
$newAddress->address_street_1 = $address["address_street_1"];
$newAddress->address_street_2 = $address["address_street_2"];
$newAddress->city = $address["city"];
$newAddress->state = $address["state"];
$newAddress->country_id = $address["country_id"];
$newAddress->zip = $address["zip"];
$newAddress->phone = $address["phone"];
$newAddress->type = $address["type"];
$newAddress->user_id = $customer->id;
$newAddress->save();
$customer->addresses()->save($newAddress);
}
}
$customer = User::with('billingAddress', 'shippingAddress')->find($customer->id);
return response()->json([
'customer' => $customer,
'success' => true
]);
}
/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show($id)
{
$customer = User::with([
'billingAddress',
'shippingAddress',
'billingAddress.country',
'shippingAddress.country',
])->find($id);
return response()->json([
'customer' => $customer
]);
}
/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function edit($id)
{
$customer = User::with('billingAddress', 'shippingAddress')->findOrFail($id);
$currency = $customer->currency;
$currencies = Currency::all();
return response()->json([
'customer' => $customer,
'currencies' => $currencies,
'currency' => $currency
]);
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update($id, Requests\CustomerRequest $request)
{
$customer = User::find($id);
if ($request->email != null) {
$verifyEmail = User::where('email', $request->email)->first();
if ($verifyEmail) {
if ($verifyEmail->id !== $customer->id) {
return response()->json([
'success' => false,
'error' => 'Email already in use'
]);
}
}
}
if ($request->has('password')) {
$customer->password = Hash::make($request->password);
}
$customer->name = $request->name;
$customer->currency_id = $request->currency_id;
$customer->email = $request->email;
$customer->phone = $request->phone;
$customer->company_name = $request->company_name;
$customer->contact_name = $request->contact_name;
$customer->website = $request->website;
$customer->enable_portal = $request->enable_portal;
$customer->save();
if ($request->addresses) {
foreach ($request->addresses as $address) {
$newAddress = $customer->addresses()->firstOrNew(['type' => $address["type"]]);
$newAddress->name = $address["name"];
$newAddress->address_street_1 = $address["address_street_1"];
$newAddress->address_street_2 = $address["address_street_2"];
$newAddress->city = $address["city"];
$newAddress->state = $address["state"];
$newAddress->country_id = $address["country_id"];
$newAddress->zip = $address["zip"];
$newAddress->phone = $address["phone"];
$newAddress->type = $address["type"];
$newAddress->user_id = $customer->id;
$newAddress->save();
}
}
$customer = User::with('billingAddress', 'shippingAddress')->find($customer->id);
return response()->json([
'customer' => $customer,
'success' => true
]);
}
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function destroy($id)
{
User::deleteCustomer($id);
return response()->json([
'success' => true
]);
}
public function delete(Request $request)
{
foreach ($request->id as $id) {
User::deleteCustomer($id);
}
return response()->json([
'success' => true
]);
}
}

View File

@@ -1,470 +0,0 @@
<?php
namespace Crater\Http\Controllers;
use Illuminate\Http\Request;
use Crater\Estimate;
use Crater\EstimateItem;
use Crater\EstimateTemplate;
use Carbon\Carbon;
use Crater\Http\Requests\EstimatesRequest;
use Crater\Invoice;
use Crater\Currency;
use Crater\User;
use Crater\Item;
use Validator;
use Crater\CompanySetting;
use Crater\Company;
use Crater\Mail\EstimatePdf;
use Crater\TaxType;
use Crater\Tax;
class EstimatesController extends Controller
{
public function index(Request $request)
{
$limit = $request->has('limit') ? $request->limit : 10;
$estimates = Estimate::with([
'items',
'user',
'estimateTemplate',
'taxes'
])
->join('users', 'users.id', '=', 'estimates.user_id')
->applyFilters($request->only([
'status',
'customer_id',
'estimate_number',
'from_date',
'to_date',
'search',
'orderByField',
'orderBy'
]))
->whereCompany($request->header('company'))
->select('estimates.*', 'users.name')
->latest()
->paginate($limit);
$siteData = [
'estimates' => $estimates,
'estimateTotalCount' => Estimate::count()
];
return response()->json($siteData);
}
public function create(Request $request)
{
$nextEstimateNumber = 'EST-'.Estimate::getNextEstimateNumber();
$tax_per_item = CompanySetting::getSetting('tax_per_item', $request->header('company'));
$discount_per_item = CompanySetting::getSetting('discount_per_item', $request->header('company'));
$customers = User::where('role', 'customer')->get();
return response()->json([
'customers' => $customers,
'nextEstimateNumber' => $nextEstimateNumber,
'taxes' => Tax::whereCompany($request->header('company'))->latest()->get(),
'items' => Item::whereCompany($request->header('company'))->get(),
'tax_per_item' => $tax_per_item,
'discount_per_item' => $discount_per_item,
'estimateTemplates' => EstimateTemplate::all(),
'shareable_link' => ''
]);
}
public function store(EstimatesRequest $request)
{
$estimate_date = Carbon::createFromFormat('d/m/Y', $request->estimate_date);
$expiry_date = Carbon::createFromFormat('d/m/Y', $request->expiry_date);
$status = Estimate::STATUS_DRAFT;
$tax_per_item = CompanySetting::getSetting(
'tax_per_item',
$request->header('company')
) ? CompanySetting::getSetting(
'tax_per_item',
$request->header('company')
) : 'NO';
if ($request->has('estimateSend')) {
$status = Estimate::STATUS_SENT;
}
$discount_per_item = CompanySetting::getSetting(
'discount_per_item',
$request->header('company')
) ? CompanySetting::getSetting(
'discount_per_item',
$request->header('company')
) : 'NO';
$estimate = Estimate::create([
'estimate_date' => $estimate_date,
'expiry_date' => $expiry_date,
'estimate_number' => $request->estimate_number,
'reference_number' => $request->reference_number,
'user_id' => $request->user_id,
'company_id' => $request->header('company'),
'estimate_template_id' => $request->estimate_template_id,
'status' => $status,
'discount' => $request->discount,
'discount_type' => $request->discount_type,
'discount_val' => $request->discount_val,
'sub_total' => $request->sub_total,
'total' => $request->total,
'tax_per_item' => $tax_per_item,
'discount_per_item' => $discount_per_item,
'tax' => $request->tax,
'notes' => $request->notes,
'unique_hash' => str_random(60)
]);
$estimateItems = $request->items;
foreach ($estimateItems as $estimateItem) {
$estimateItem['company_id'] = $request->header('company');
$item = $estimate->items()->create($estimateItem);
if (array_key_exists('taxes', $estimateItem) && $estimateItem['taxes']) {
foreach ($estimateItem['taxes'] as $tax) {
if ($tax['amount']) {
$tax['company_id'] = $request->header('company');
$item->taxes()->create($tax);
}
}
}
}
if ($request->has('taxes')) {
foreach ($request->taxes as $tax) {
if ($tax['amount']) {
$tax['company_id'] = $request->header('company');
$estimate->taxes()->create($tax);
}
}
}
if ($request->has('estimateSend')) {
$data['estimate'] = $estimate->toArray();
$userId = $data['estimate']['user_id'];
$data['user'] = User::find($userId)->toArray();
$data['company'] = Company::find($estimate->company_id);
$email = $data['user']['email'];
$notificationEmail = CompanySetting::getSetting(
'notification_email',
$request->header('company')
);
if (!$email) {
return response()->json([
'error' => 'user_email_does_not_exist'
]);
}
if (!$notificationEmail) {
return response()->json([
'error' => 'notification_email_does_not_exist'
]);
}
\Mail::to($email)->send(new EstimatePdf($data, $notificationEmail));
}
$estimate = Estimate::with([
'items',
'user',
'estimateTemplate',
'taxes'
])->find($estimate->id);
return response()->json([
'estimate' => $estimate,
'url' => url('/estimates/pdf/'.$estimate->unique_hash),
]);
}
public function show(Request $request, $id)
{
$estimate = Estimate::with([
'items',
'items.taxes',
'user',
'estimateTemplate',
'taxes',
'taxes.taxType'
])->find($id);
$siteData = [
'estimate' => $estimate,
'shareable_link' => url('/estimates/pdf/'.$estimate->unique_hash)
];
return response()->json($siteData);
}
public function edit(Request $request,$id)
{
$estimate = Estimate::with([
'items',
'items.taxes',
'user',
'estimateTemplate',
'taxes',
'taxes.taxType'
])->find($id);
$customers = User::where('role', 'customer')->get();
return response()->json( [
'customers' => $customers,
'nextEstimateNumber' => $estimate->estimate_number,
'taxes' => Tax::latest()->whereCompany($request->header('company'))->get(),
'estimate' => $estimate,
'items' => Item::whereCompany($request->header('company'))->latest()->get(),
'estimateTemplates' => EstimateTemplate::all(),
'tax_per_item' => $estimate->tax_per_item,
'discount_per_item' => $estimate->discount_per_item,
'shareable_link' => url('/estimates/pdf/'.$estimate->unique_hash)
]);
}
public function update(EstimatesRequest $request, $id)
{
$estimate_date = Carbon::createFromFormat('d/m/Y', $request->estimate_date);
$expiry_date = Carbon::createFromFormat('d/m/Y', $request->expiry_date);
$estimate = Estimate::find($id);
$estimate->estimate_date = $estimate_date;
$estimate->expiry_date = $expiry_date;
$estimate->estimate_number = $request->estimate_number;
$estimate->reference_number = $request->reference_number;
$estimate->user_id = $request->user_id;
$estimate->estimate_template_id = $request->estimate_template_id;
$estimate->discount = $request->discount;
$estimate->discount_type = $request->discount_type;
$estimate->discount_val = $request->discount_val;
$estimate->sub_total = $request->sub_total;
$estimate->total = $request->total;
$estimate->tax = $request->tax;
$estimate->notes = $request->notes;
$estimate->save();
$oldItems = $estimate->items->toArray();
$oldTaxes = $estimate->taxes->toArray();
$estimateItems = $request->items;
foreach ($oldItems as $oldItem) {
EstimateItem::destroy($oldItem['id']);
}
foreach ($oldTaxes as $oldTax) {
Tax::destroy($oldTax['id']);
}
foreach ($estimateItems as $estimateItem) {
$estimateItem['company_id'] = $request->header('company');
$item = $estimate->items()->create($estimateItem);
if (array_key_exists('taxes', $estimateItem) && $estimateItem['taxes']) {
foreach ($estimateItem['taxes'] as $tax) {
if ($tax['amount']) {
$tax['company_id'] = $request->header('company');
$item->taxes()->create($tax);
}
}
}
}
if ($request->has('taxes')) {
foreach ($request->taxes as $tax) {
if ($tax['amount']) {
$tax['company_id'] = $request->header('company');
$estimate->taxes()->create($tax);
}
}
}
$estimate = Estimate::with([
'items',
'user',
'estimateTemplate',
'taxes'
])->find($estimate->id);
return response()->json([
'estimate' => $estimate,
'url' => url('/estimates/pdf/'.$estimate->unique_hash),
]);
}
public function destroy($id)
{
Estimate::deleteEstimate($id);
return response()->json([
'success' => true
]);
}
public function sendEstimate(Request $request)
{
$estimate = Estimate::findOrFail($request->id);
$data['estimate'] = $estimate->toArray();
$userId = $data['estimate']['user_id'];
$data['user'] = User::find($userId)->toArray();
$data['company'] = Company::find($estimate->company_id);
$email = $data['user']['email'];
$notificationEmail = CompanySetting::getSetting(
'notification_email',
$request->header('company')
);
if (!$email) {
return response()->json([
'error' => 'user_email_does_not_exist'
]);
}
if (!$notificationEmail) {
return response()->json([
'error' => 'notification_email_does_not_exist'
]);
}
\Mail::to($email)->send(new EstimatePdf($data, $notificationEmail));
if ($estimate->status == Estimate::STATUS_DRAFT) {
$estimate->status = Estimate::STATUS_SENT;
$estimate->save();
}
return response()->json([
'success' => true
]);
}
public function markEstimateAccepted(Request $request)
{
$estimate = Estimate::find($request->id);
$estimate->status = Estimate::STATUS_ACCEPTED;
$estimate->save();
return response()->json([
'success' => true
]);
}
public function markEstimateRejected(Request $request)
{
$estimate = Estimate::find($request->id);
$estimate->status = Estimate::STATUS_REJECTED;
$estimate->save();
return response()->json([
'success' => true
]);
}
public function markEstimateSent(Request $request)
{
$estimate = Estimate::find($request->id);
$estimate->status = Estimate::STATUS_SENT;
$estimate->save();
return response()->json([
'success' => true
]);
}
public function estimateToInvoice(Request $request, $id)
{
$estimate = Estimate::with(['items', 'items.taxes', 'user', 'estimateTemplate', 'taxes'])->find($id);
$invoice_date = Carbon::parse($estimate->estimate_date);
$due_date = Carbon::parse($estimate->estimate_date)->addDays(7);
$tax_per_item = CompanySetting::getSetting(
'tax_per_item',
$request->header('company')
) ? CompanySetting::getSetting(
'tax_per_item',
$request->header('company')
) : 'NO';
$discount_per_item = CompanySetting::getSetting(
'discount_per_item',
$request->header('company')
) ? CompanySetting::getSetting(
'discount_per_item',
$request->header('company')
) : 'NO';
$invoice = Invoice::create([
'invoice_date' => $invoice_date,
'due_date' => $due_date,
'invoice_number' => "INV-".Invoice::getNextInvoiceNumber(),
'reference_number' => $estimate->reference_number,
'user_id' => $estimate->user_id,
'company_id' => $request->header('company'),
'invoice_template_id' => 1,
'status' => Invoice::STATUS_DRAFT,
'paid_status' => Invoice::STATUS_UNPAID,
'sub_total' => $estimate->sub_total,
'discount' => $estimate->discount,
'discount_type' => $estimate->discount_type,
'discount_val' => $estimate->discount_val,
'total' => $estimate->total,
'due_amount' => $estimate->total,
'tax_per_item' => $tax_per_item,
'discount_per_item' => $discount_per_item,
'tax' => $estimate->tax,
'notes' => $estimate->notes,
'unique_hash' => str_random(60)
]);
$invoiceItems = $estimate->items->toArray();
foreach ($invoiceItems as $invoiceItem) {
$invoiceItem['company_id'] = $request->header('company');
$invoiceItem['name'] = $invoiceItem['name'];
$item = $invoice->items()->create($invoiceItem);
if (array_key_exists('taxes', $invoiceItem) && $invoiceItem['taxes']) {
foreach ($invoiceItem['taxes'] as $tax) {
$tax['company_id'] = $request->header('company');
if ($tax['amount']) {
$item->taxes()->create($tax);
}
}
}
}
if ($estimate->taxes) {
foreach ($estimate->taxes->toArray() as $tax) {
$tax['company_id'] = $request->header('company');
$invoice->taxes()->create($tax);
}
}
$invoice = Invoice::with([
'items',
'user',
'invoiceTemplate',
'taxes'
])->find($invoice->id);
return response()->json([
'invoice' => $invoice
]);
}
public function delete(Request $request)
{
foreach ($request->id as $id) {
Estimate::deleteEstimate($id);
}
return response()->json([
'success' => true
]);
}
}

View File

@@ -1,260 +0,0 @@
<?php
namespace Crater\Http\Controllers;
use Crater\Expense;
use Crater\User;
use Crater\Currency;
use Crater\Company;
use Crater\CompanySetting;
use Illuminate\Http\Request;
use Crater\ExpenseCategory;
use Crater\Http\Requests\ExpenseRequest;
use Carbon\Carbon;
use Intervention\Image\Facades\Image;
class ExpensesController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index(Request $request)
{
$limit = $request->has('limit') ? $request->limit : 10;
$expenses = Expense::with('category')
->join('expense_categories', 'expense_categories.id', '=', 'expenses.expense_category_id')
->applyFilters($request->only([
'expense_category_id',
'search',
'from_date',
'to_date',
'orderByField',
'orderBy'
]))
->whereCompany($request->header('company'))
->select('expenses.*', 'expense_categories.name')
->paginate($limit);
return response()->json([
'expenses' => $expenses,
'currency' => Currency::findOrFail(
CompanySetting::getSetting('currency', $request->header('company'))
)
]);
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create(Request $request)
{
$categories = ExpenseCategory::whereCompany($request->header('company'))->get();
return response()->json([
'categories' => $categories
]);
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(ExpenseRequest $request)
{
$expense_date = Carbon::createFromFormat('d/m/Y', $request->expense_date);
$expense = new Expense();
$expense->notes = $request->notes;
$expense->expense_category_id = $request->expense_category_id;
$expense->amount = $request->amount;
$expense->company_id = $request->header('company');
$expense->expense_date = $expense_date;
$expense->save();
if ($request->hasFile('attachment_receipt')) {
$expense->addMediaFromRequest('attachment_receipt')->toMediaCollection('receipts', 'local');
}
return response()->json([
'expense' => $expense,
'success' => true
]);
}
/**
* Display the specified resource.
*
* @param \Crater\Expense $expense
* @return \Illuminate\Http\Response
*/
public function show(Expense $expense)
{
//
}
/**
* Show the form for editing the specified resource.
*
* @param $id
* @return \Illuminate\Http\Response
*/
public function edit(Request $request,$id)
{
$categories = ExpenseCategory::whereCompany($request->header('company'))->get();
$customers = User::where('role', 'customer')->whereCompany($request->header('company'))->get();
$expense = Expense::with('category')->where('id', $id)->first();
return response()->json([
'categories' => $categories,
'customers' => $customers,
'expense' => $expense
]);
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param \Crater\Expense $expense
* @return \Illuminate\Http\Response
*/
public function update(ExpenseRequest $request, Expense $expense)
{
$expense_date = Carbon::createFromFormat('d/m/Y', $request->expense_date);
$expense = Expense::findOrFail($expense->id);
$expense->notes = $request->notes;
$expense->expense_category_id = $request->expense_category_id;
$expense->amount = $request->amount;
$expense->expense_date = $expense_date;
$expense->save();
if ($request->hasFile('attachment_receipt')) {
$expense->clearMediaCollection('receipts');
$expense->addMediaFromRequest('attachment_receipt')->toMediaCollection('receipts', 'local');
}
return response()->json([
'expense' => $expense,
'success' => true
]);
}
/**
* Remove the specified resource from storage.
*
* @param \Crater\Expense $expense
* @return \Illuminate\Http\Response
*/
public function destroy(Expense $expense)
{
$expense->delete();
return response()->json([
'success' => true
]);
}
public function delete(Request $request)
{
Expense::destroy($request->id);
return response()->json([
'success' => true
]);
}
/**
* Upload the expense receipts to storage.
*
* @param \Illuminate\Http\Request $request
* @param $id
* @return \Illuminate\Http\Response
*/
public function uploadReceipts(Request $request, $id)
{
$data = json_decode($request->attachment_receipt);
if($data) {
$expense = Expense::find($id);
if($expense) {
if($request->type === 'edit') {
$expense->clearMediaCollection('receipts');
}
$expense->addMediaFromBase64($data->data)
->usingFileName($data->name)
->toMediaCollection('receipts', 'local');
}
}
return response()->json([
'success' => 'Expense receipts uploaded successfully'
]);
}
public function showReceipt($id)
{
$expense = Expense::find($id);
$imagePath = null;
if($expense) {
$media = $expense->getFirstMedia('receipts');
if($media) {
$imagePath = $media->getPath();
} else {
return response()->json([
'error' => 'receipt_does_not_exist'
]);
}
}
$type = \File::mimeType($imagePath);
$image = 'data:'.$type.';base64,'.base64_encode(file_get_contents($imagePath));
return response()->json([
'image' => $image,
'type' => $type
]);
}
public function downloadReceipt($id, $hash)
{
$company = Company::where('unique_hash', $hash)->first();
$expense = Expense::whereCompany($company->id)
->where('id', $id)
->first();
$imagePath = null;
if($expense) {
$media = $expense->getFirstMedia('receipts');
if($media) {
$imagePath = $media->getPath();
$filename = $media->getPath();
$type = \File::mimeType($imagePath);
$headers = array(
'Content-Type' => $type,
);
$response = \Response::download($imagePath, $media->file_name);
ob_end_clean();
return $response;
}
}
return response()->json([
'error' => 'receipt_not_found'
]);
}
}

View File

@@ -1,374 +0,0 @@
<?php
namespace Crater\Http\Controllers;
use Illuminate\Http\Request;
use Crater\Invoice;
use PDF;
use Crater\CompanySetting;
use Crater\Estimate;
use Crater\User;
use Crater\Company;
use Crater\InvoiceTemplate;
use Crater\EstimateTemplate;
use Crater\Mail\EstimateViewed;
use Crater\Mail\InvoiceViewed;
class FrontendController extends Controller
{
public function home()
{
return view('front.index');
}
public function getCustomerEstimatePdf($id)
{
$estimate = Estimate::with(
'user',
'items',
'user.billingAddress',
'user.shippingAddress'
)
->where('unique_hash', $id)
->first();
$taxTypes = [];
$taxes = [];
$labels = [];
if ($estimate->tax_per_item === 'YES') {
foreach ($estimate->items as $item) {
foreach ($item->taxes as $tax) {
if (!in_array($tax->name, $taxTypes)) {
array_push($taxTypes, $tax->name);
array_push($labels, $tax->name.' ('.$tax->percent.'%)');
}
}
}
foreach ($taxTypes as $taxType) {
$total = 0;
foreach ($estimate->items as $item) {
foreach ($item->taxes as $tax) {
if($tax->name == $taxType) {
$total += $tax->amount;
}
}
}
array_push($taxes, $total);
}
}
$estimateTemplate = EstimateTemplate::find($estimate->estimate_template_id);
$company = Company::find($estimate->company_id);
$logo = $company->getMedia('logo')->first();
if($logo) {
$logo = $logo->getFullUrl();
}
if ($estimate && ($estimate->status == Estimate::STATUS_SENT || $estimate->status == Estimate::STATUS_DRAFT)) {
$estimate->status = Estimate::STATUS_VIEWED;
$estimate->save();
$notifyEstimateViewed = CompanySetting::getSetting(
'notify_estimate_viewed',
$estimate->company_id
);
if ($notifyEstimateViewed == 'YES') {
$data['estimate'] = Estimate::findOrFail($estimate->id)->toArray();
$data['user'] = User::find($estimate->user_id)->toArray();
$notificationEmail = CompanySetting::getSetting(
'notification_email',
$estimate->company_id
);
\Mail::to($notificationEmail)->send(new EstimateViewed($data));
}
}
$companyAddress = User::with(['addresses', 'addresses.country'])->find(1);
$colors = [
'invoice_primary_color',
'invoice_column_heading',
'invoice_field_label',
'invoice_field_value',
'invoice_body_text',
'invoice_description_text',
'invoice_border_color'
];
$colorSettings = CompanySetting::whereIn('option', $colors)
->whereCompany($estimate->company_id)
->get();
view()->share([
'estimate' => $estimate,
'logo' => $logo ?? null,
'company_address' => $companyAddress,
'colors' => $colorSettings,
'labels' => $labels,
'taxes' => $taxes
]);
$pdf = PDF::loadView('app.pdf.estimate.'.$estimateTemplate->view);
return $pdf->stream();
}
public function getCustomerInvoicePdf($id)
{
$invoice = Invoice::with([
'items',
'items.taxes',
'user',
'invoiceTemplate',
'taxes'
])
->where('unique_hash', $id)
->first();
$taxTypes = [];
$taxes = [];
$labels = [];
if ($invoice->tax_per_item === 'YES') {
foreach ($invoice->items as $item) {
foreach ($item->taxes as $tax) {
if (!in_array($tax->name, $labels)) {
array_push($taxTypes, $tax->name);
array_push($labels, $tax->name.' ('.$tax->percent.'%)');
}
}
}
foreach ($taxTypes as $taxType) {
$total = 0;
foreach ($invoice->items as $item) {
foreach ($item->taxes as $tax) {
if($tax->name == $taxType) {
$total += $tax->amount;
}
}
}
array_push($taxes, $total);
}
}
$invoiceTemplate = InvoiceTemplate::find($invoice->invoice_template_id);
$company = Company::find($invoice->company_id);
$logo = $company->getMedia('logo')->first();
if($logo) {
$logo = $logo->getFullUrl();
}
if ($invoice && ($invoice->status == Invoice::STATUS_SENT || $invoice->status == Invoice::STATUS_DRAFT)) {
$invoice->status = Invoice::STATUS_VIEWED;
$invoice->viewed = true;
$invoice->save();
$notifyInvoiceViewed = CompanySetting::getSetting(
'notify_invoice_viewed',
$invoice->company_id
);
if ($notifyInvoiceViewed == 'YES') {
$data['invoice'] = Invoice::findOrFail($invoice->id)->toArray();
$data['user'] = User::find($invoice->user_id)->toArray();
$notificationEmail = CompanySetting::getSetting(
'notification_email',
$invoice->company_id
);
\Mail::to($notificationEmail)->send(new InvoiceViewed($data));
}
}
$companyAddress = User::with(['addresses', 'addresses.country'])->find(1);
$colors = [
'invoice_primary_color',
'invoice_column_heading',
'invoice_field_label',
'invoice_field_value',
'invoice_body_text',
'invoice_description_text',
'invoice_border_color'
];
$colorSettings = CompanySetting::whereIn('option', $colors)
->whereCompany($invoice->company_id)
->get();
view()->share([
'invoice' => $invoice,
'colors' => $colorSettings,
'company_address' => $companyAddress,
'logo' => $logo ?? null,
'labels' => $labels,
'taxes' => $taxes
]);
$pdf = PDF::loadView('app.pdf.invoice.'.$invoiceTemplate->view);
return $pdf->stream();
}
public function getEstimatePdf($id)
{
$estimate = Estimate::with([
'items',
'items.taxes',
'user',
'estimateTemplate',
'taxes',
'taxes.taxType'
])
->where('unique_hash', $id)
->first();
$taxTypes = [];
$taxes = [];
$labels = [];
if ($estimate->tax_per_item === 'YES') {
foreach ($estimate->items as $item) {
foreach ($item->taxes as $tax) {
if (!in_array($tax->name, $taxTypes)) {
array_push($taxTypes, $tax->name);
array_push($labels, $tax->name.' ('.$tax->percent.'%)');
}
}
}
foreach ($taxTypes as $taxType) {
$total = 0;
foreach ($estimate->items as $item) {
foreach ($item->taxes as $tax) {
if($tax->name == $taxType) {
$total += $tax->amount;
}
}
}
array_push($taxes, $total);
}
}
$estimateTemplate = EstimateTemplate::find($estimate->estimate_template_id);
$company = Company::find($estimate->company_id);
$companyAddress = User::with(['addresses', 'addresses.country'])->find(1);
$logo = $company->getMedia('logo')->first();
if($logo) {
$logo = $logo->getFullUrl();
}
$colors = [
'invoice_primary_color',
'invoice_column_heading',
'invoice_field_label',
'invoice_field_value',
'invoice_body_text',
'invoice_description_text',
'invoice_border_color'
];
$colorSettings = CompanySetting::whereIn('option', $colors)
->whereCompany($estimate->company_id)
->get();
view()->share([
'estimate' => $estimate,
'logo' => $logo ?? null,
'company_address' => $companyAddress,
'colors' => $colorSettings,
'labels' => $labels,
'taxes' => $taxes
]);
$pdf = PDF::loadView('app.pdf.estimate.'.$estimateTemplate->view);
return $pdf->stream();
}
public function getInvoicePdf($id)
{
$invoice = Invoice::with([
'items',
'items.taxes',
'user',
'invoiceTemplate',
'taxes'
])
->where('unique_hash', $id)
->first();
$taxTypes = [];
$taxes = [];
$labels = [];
if ($invoice->tax_per_item === 'YES') {
foreach ($invoice->items as $item) {
foreach ($item->taxes as $tax) {
if (!in_array($tax->name, $taxTypes)) {
array_push($taxTypes, $tax->name);
array_push($labels, $tax->name.' ('.$tax->percent.'%)');
}
}
}
foreach ($taxTypes as $taxType) {
$total = 0;
foreach ($invoice->items as $item) {
foreach ($item->taxes as $tax) {
if($tax->name == $taxType) {
$total += $tax->amount;
}
}
}
array_push($taxes, $total);
}
}
$invoiceTemplate = InvoiceTemplate::find($invoice->invoice_template_id);
$company = Company::find($invoice->company_id);
$companyAddress = User::with(['addresses', 'addresses.country'])->find(1);
$logo = $company->getMedia('logo')->first();
if($logo) {
$logo = $logo->getFullUrl();
}
$colors = [
'invoice_primary_color',
'invoice_column_heading',
'invoice_field_label',
'invoice_field_value',
'invoice_body_text',
'invoice_description_text',
'invoice_border_color'
];
$colorSettings = CompanySetting::whereIn('option', $colors)
->whereCompany($invoice->company_id)
->get();
view()->share([
'invoice' => $invoice,
'company_address' => $companyAddress,
'logo' => $logo ?? null,
'colors' => $colorSettings,
'labels' => $labels,
'taxes' => $taxes
]);
$pdf = PDF::loadView('app.pdf.invoice.'.$invoiceTemplate->view);
return $pdf->stream();
}
}

View File

@@ -1,448 +0,0 @@
<?php
namespace Crater\Http\Controllers;
use Illuminate\Http\Request;
use Crater\CompanySetting;
use Crater\Company;
use Illuminate\Support\Collection;
use Crater\Currency;
use Crater\InvoiceTemplate;
use Crater\Http\Requests;
use Crater\Invoice;
use Crater\InvoiceItem;
use Carbon\Carbon;
use Crater\Item;
use Crater\Mail\invoicePdf;
use function MongoDB\BSON\toJSON;
use Illuminate\Support\Facades\Log;
use Crater\User;
use Mailgun\Mailgun;
use PDF;
use Validator;
use Crater\TaxType;
use Crater\Tax;
class InvoicesController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index(Request $request)
{
$limit = $request->has('limit') ? $request->limit : 10;
$invoices = Invoice::with(['items', 'user', 'invoiceTemplate', 'taxes'])
->join('users', 'users.id', '=', 'invoices.user_id')
->applyFilters($request->only([
'status',
'paid_status',
'customer_id',
'invoice_number',
'from_date',
'to_date',
'orderByField',
'orderBy',
'search',
]))
->whereCompany($request->header('company'))
->select('invoices.*', 'users.name')
->latest()
->paginate($limit);
return response()->json([
'invoices' => $invoices,
'invoiceTotalCount' => Invoice::count()
]);
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create(Request $request)
{
$tax_per_item = CompanySetting::getSetting('tax_per_item', $request->header('company'));
$discount_per_item = CompanySetting::getSetting('discount_per_item', $request->header('company'));
$nextInvoiceNumber = "INV-".Invoice::getNextInvoiceNumber();
return response()->json([
'nextInvoiceNumber' => $nextInvoiceNumber,
'items' => Item::with('taxes')->whereCompany($request->header('company'))->get(),
'invoiceTemplates' => InvoiceTemplate::all(),
'tax_per_item' => $tax_per_item,
'discount_per_item' => $discount_per_item
]);
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Requests\InvoicesRequest $request)
{
$invoice_date = Carbon::createFromFormat('d/m/Y', $request->invoice_date);
$due_date = Carbon::createFromFormat('d/m/Y', $request->due_date);
$status = Invoice::STATUS_DRAFT;
$tax_per_item = CompanySetting::getSetting('tax_per_item', $request->header('company')) ?? 'NO';
$discount_per_item = CompanySetting::getSetting('discount_per_item', $request->header('company')) ?? 'NO';
if ($request->has('invoiceSend')) {
$status = Invoice::STATUS_SENT;
}
$invoice = Invoice::create([
'invoice_date' => $invoice_date,
'due_date' => $due_date,
'invoice_number' => $request->invoice_number,
'reference_number' => $request->reference_number,
'user_id' => $request->user_id,
'company_id' => $request->header('company'),
'invoice_template_id' => $request->invoice_template_id,
'status' => $status,
'paid_status' => Invoice::STATUS_UNPAID,
'sub_total' => $request->sub_total,
'discount' => $request->discount,
'discount_type' => $request->discount_type,
'discount_val' => $request->discount_val,
'total' => $request->total,
'due_amount' => $request->total,
'tax_per_item' => $tax_per_item,
'discount_per_item' => $discount_per_item,
'tax' => $request->tax,
'notes' => $request->notes,
'unique_hash' => str_random(60)
]);
$invoiceItems = $request->items;
foreach ($invoiceItems as $invoiceItem) {
$invoiceItem['company_id'] = $request->header('company');
$item = $invoice->items()->create($invoiceItem);
if (array_key_exists('taxes', $invoiceItem) && $invoiceItem['taxes']) {
foreach ($invoiceItem['taxes'] as $tax) {
$tax['company_id'] = $request->header('company');
if ($tax['amount']) {
$item->taxes()->create($tax);
}
}
}
}
if ($request->has('taxes')) {
foreach ($request->taxes as $tax) {
$tax['company_id'] = $request->header('company');
if ($tax['amount']) {
$invoice->taxes()->create($tax);
}
}
}
if ($request->has('invoiceSend')) {
$data['invoice'] = Invoice::findOrFail($invoice->id)->toArray();
$data['user'] = User::find($request->user_id)->toArray();
$data['company'] = Company::find($invoice->company_id);
$notificationEmail = CompanySetting::getSetting(
'notification_email',
$request->header('company')
);
$email = $data['user']['email'];
if (!$email) {
return response()->json([
'error' => 'user_email_does_not_exist'
]);
}
if (!$notificationEmail) {
return response()->json([
'error' => 'notification_email_does_not_exist'
]);
}
\Mail::to($email)->send(new invoicePdf($data, $notificationEmail));
}
$invoice = Invoice::with(['items', 'user', 'invoiceTemplate', 'taxes'])->find($invoice->id);
return response()->json([
'url' => url('/invoices/pdf/'.$invoice->unique_hash),
'invoice' => $invoice
]);
}
/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show(Request $request, $id)
{
$invoice = Invoice::with([
'items',
'items.taxes',
'user',
'invoiceTemplate',
'taxes.taxType'
])->find($id);
$siteData = [
'invoice' => $invoice,
'shareable_link' => url('/invoices/pdf/' . $invoice->unique_hash)
];
return response()->json($siteData);
}
/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function edit(Request $request,$id)
{
$invoice = Invoice::with([
'items',
'items.taxes',
'user',
'invoiceTemplate',
'taxes.taxType'
])->find($id);
return response()->json([
'nextInvoiceNumber' => $invoice->invoice_number,
'invoice' => $invoice,
'invoiceTemplates' => InvoiceTemplate::all(),
'tax_per_item' => $invoice->tax_per_item,
'discount_per_item' => $invoice->discount_per_item,
'shareable_link' => url('/invoices/pdf/'.$invoice->unique_hash)
]);
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(Requests\InvoicesRequest $request, $id)
{
$invoice_date = Carbon::createFromFormat('d/m/Y', $request->invoice_date);
$due_date = Carbon::createFromFormat('d/m/Y', $request->due_date);
$invoice = Invoice::find($id);
$oldAmount = $invoice->total;
if ($oldAmount != $request->total) {
$oldAmount = (int)round($request->total) - (int)$oldAmount;
} else {
$oldAmount = 0;
}
$invoice->due_amount = ($invoice->due_amount + $oldAmount);
if ($invoice->due_amount == 0 && $invoice->paid_status != Invoice::STATUS_PAID) {
$invoice->status = Invoice::STATUS_COMPLETED;
$invoice->paid_status = Invoice::STATUS_PAID;
} elseif ($invoice->due_amount < 0 && $invoice->paid_status != Invoice::STATUS_UNPAID) {
return response()->json([
'error' => 'invalid_due_amount'
]);
} elseif ($invoice->due_amount != 0 && $invoice->paid_status == Invoice::STATUS_PAID) {
$invoice->status = $invoice->getPreviousStatus();
$invoice->paid_status = Invoice::STATUS_PARTIALLY_PAID;
}
$invoice->invoice_date = $invoice_date;
$invoice->due_date = $due_date;
$invoice->invoice_number = $request->invoice_number;
$invoice->reference_number = $request->reference_number;
$invoice->user_id = $request->user_id;
$invoice->invoice_template_id = $request->invoice_template_id;
$invoice->sub_total = $request->sub_total;
$invoice->total = $request->total;
$invoice->discount = $request->discount;
$invoice->discount_type = $request->discount_type;
$invoice->discount_val = $request->discount_val;
$invoice->tax = $request->tax;
$invoice->notes = $request->notes;
$invoice->save();
$oldItems = $invoice->items->toArray();
$oldTaxes = $invoice->taxes->toArray();
$invoiceItems = $request->items;
foreach ($oldItems as $oldItem) {
InvoiceItem::destroy($oldItem['id']);
}
foreach ($oldTaxes as $oldTax) {
Tax::destroy($oldTax['id']);
}
foreach ($invoiceItems as $invoiceItem) {
$invoiceItem['company_id'] = $request->header('company');
$item = $invoice->items()->create($invoiceItem);
if (array_key_exists('taxes', $invoiceItem) && $invoiceItem['taxes']) {
foreach ($invoiceItem['taxes'] as $tax) {
$tax['company_id'] = $request->header('company');
if ($tax['amount']) {
$item->taxes()->create($tax);
}
}
}
}
if ($request->has('taxes')) {
foreach ($request->taxes as $tax) {
$tax['company_id'] = $request->header('company');
if ($tax['amount']) {
$invoice->taxes()->create($tax);
}
}
}
$invoice = Invoice::with(['items', 'user', 'invoiceTemplate', 'taxes'])->find($invoice->id);
return response()->json([
'url' => url('/invoices/pdf/' . $invoice->unique_hash),
'invoice' => $invoice,
'success' => true
]);
}
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function destroy($id)
{
$invoice = Invoice::find($id);
if ($invoice->payments()->exists() && $invoice->payments()->count() > 0) {
return response()->json([
'error' => 'payment_attached'
]);
}
$invoice = Invoice::destroy($id);
return response()->json([
'success' => true
]);
}
public function delete(Request $request)
{
foreach ($request->id as $id) {
$invoice = Invoice::find($id);
if ($invoice->payments()->exists() && $invoice->payments()->count() > 0) {
return response()->json([
'error' => 'payment_attached'
]);
}
}
$invoice = Invoice::destroy($request->id);
return response()->json([
'success' => true
]);
}
public function sendInvoice(Request $request)
{
$invoice = Invoice::findOrFail($request->id);
$data['invoice'] = $invoice->toArray();
$userId = $data['invoice']['user_id'];
$data['user'] = User::find($userId)->toArray();
$data['company'] = Company::find($invoice->company_id);
$email = $data['user']['email'];
$notificationEmail = CompanySetting::getSetting(
'notification_email',
$request->header('company')
);
if (!$email) {
return response()->json([
'error' => 'user_email_does_not_exist'
]);
}
if (!$notificationEmail) {
return response()->json([
'error' => 'notification_email_does_not_exist'
]);
}
\Mail::to($email)->send(new invoicePdf($data, $notificationEmail));
if ($invoice->status == Invoice::STATUS_DRAFT) {
$invoice->status = Invoice::STATUS_SENT;
$invoice->sent = true;
$invoice->save();
}
return response()->json([
'success' => true
]);
}
public function markAsSent(Request $request)
{
$invoice = Invoice::findOrFail($request->id);
$invoice->status = Invoice::STATUS_SENT;
$invoice->sent = true;
$invoice->save();
return response()->json([
'success' => true
]);
}
public function markAsPaid(Request $request)
{
$invoice = Invoice::findOrFail($request->id);
$invoice->status = Invoice::STATUS_COMPLETED;
$invoice->paid_status = Invoice::STATUS_PAID;
$invoice->due_amount = 0;
$invoice->save();
return response()->json([
'success' => true
]);
}
public function getCustomersUnpaidInvoices(Request $request, $id)
{
$invoices = Invoice::where('paid_status', '<>', Invoice::STATUS_PAID)
->where('user_id', $id)->where('due_amount', '>', 0)
->whereCompany($request->header('company'))
->get();
return response()->json([
'invoices' => $invoices
]);
}
}

View File

@@ -1,134 +0,0 @@
<?php
namespace Crater\Http\Controllers;
use Illuminate\Http\Request;
use Crater\Http\Requests;
use Crater\Item;
use Crater\TaxType;
use Crater\Tax;
use Crater\User;
class ItemsController extends Controller
{
public function index(Request $request)
{
$limit = $request->has('limit') ? $request->limit : 10;
$items = Item::applyFilters($request->only([
'search',
'price',
'unit',
'orderByField',
'orderBy'
]))
->whereCompany($request->header('company'))
->latest()
->paginate($limit);
return response()->json([
'items' => $items,
'taxTypes' => TaxType::latest()->get()
]);
}
public function edit(Request $request, $id)
{
$item = Item::with('taxes')->find($id);
return response()->json([
'item' => $item,
'taxes' => Tax::whereCompany($request->header('company'))
->latest()
->get()
]);
}
public function store(Requests\ItemsRequest $request)
{
$item = new Item();
$item->name = $request->name;
$item->unit = $request->unit;
$item->description = $request->description;
$item->company_id = $request->header('company');
$item->price = $request->price;
$item->save();
if ($request->has('taxes')) {
foreach ($request->taxes as $tax) {
$tax['company_id'] = $request->header('company');
$item->taxes()->create($tax);
}
}
$item = Item::with('taxes')->find($item->id);
return response()->json([
'item' => $item
]);
}
public function update(Requests\ItemsRequest $request, $id)
{
$item = Item::find($id);
$item->name = $request->name;
$item->unit = $request->unit;
$item->description = $request->description;
$item->price = $request->price;
$item->save();
$oldTaxes = $item->taxes->toArray();
foreach ($oldTaxes as $oldTax) {
Tax::destroy($oldTax['id']);
}
if ($request->has('taxes')) {
foreach ($request->taxes as $tax) {
$tax['company_id'] = $request->header('company');
$item->taxes()->create($tax);
}
}
$item = Item::with('taxes')->find($item->id);
return response()->json([
'item' => $item
]);
}
public function destroy($id)
{
$data = Item::deleteItem($id);
if (!$data) {
return response()->json([
'error' => 'item_attached'
]);
}
return response()->json([
'success' => $data
]);
}
public function delete(Request $request)
{
$items = [];
foreach ($request->id as $id) {
$item = Item::deleteItem($id);
if (!$item) {
array_push($items, $id);
}
}
if (empty($items)) {
return response()->json([
'success' => true
]);
}
return response()->json([
'items' => $items
]);
}
}

View File

@@ -1,15 +0,0 @@
<?php
namespace Crater\Http\Controllers;
use Illuminate\Http\Request;
use Crater\Country;
class LocationController extends Controller
{
public function getCountries()
{
return response()->json([
'countries' => Country::all()
]);
}
}

View File

@@ -1,249 +0,0 @@
<?php
namespace Crater\Http\Controllers;
use Illuminate\Http\Request;
use Crater\User;
use Crater\Company;
use Crater\Address;
use Crater\Http\Requests\ProfileRequest;
use Crater\Http\Requests\CompanyRequest;
use Crater\Http\Requests\CompanySettingRequest;
use Crater\Space\DateFormatter;
use Crater\Space\TimeZones;
use Crater\Currency;
use Crater\Setting;
use Crater\CompanySetting;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Artisan;
class OnboardingController extends Controller
{
public function getOnboardingData(Request $request)
{
if (!\Storage::disk('local')->has('database_created')) {
return response()->json([
'profile_complete' => '0'
]);
}
$setting = Setting::getSetting('profile_complete');
if ($setting !== 'COMPLETED' && $setting < 4){
return response()->json([
'profile_complete' => $setting
]);
}
$date_formats = DateFormatter::get_list();
$time_zones = TimeZones::get_list();
$languages = [
["code"=>"en", "name" => "English"],
["code"=>"fr", "name" => "French"],
["code"=>"es", "name" => "Spanish"]
];
$fiscal_years = [
['key' => 'january-december' , 'value' => '1-12'],
['key' => 'february-january' , 'value' => '2-1'],
['key' => 'march-february' , 'value' => '3-2'],
['key' => 'april-march' , 'value' => '4-3'],
['key' => 'may-april' , 'value' => '5-4'],
['key' => 'june-may' , 'value' => '6-5'],
['key' => 'july-june' , 'value' => '7-6'],
['key' => 'august-july' , 'value' => '8-7'],
['key' => 'september-august' , 'value' => '9-8'],
['key' => 'october-september', 'value' => '10-9'],
['key' => 'november-october' , 'value' => '11-10'],
['key' => 'december-november', 'value' => '12-11'],
];
$user = User::with([
'addresses',
'addresses.country',
'company'
])->find(1);
return response()->json([
'user' => $user,
'profile_complete' => $setting,
'languages' => $languages,
'date_formats' => $date_formats,
'time_zones' => $time_zones,
'fiscal_years' => $fiscal_years,
'currencies' => Currency::all()
]);
}
public function adminProfile(ProfileRequest $request)
{
$setting = Setting::getSetting('profile_complete');
if ($setting == '1' || $setting == 'COMPLETED') {
return response()->json(['error' => 'Profile already created.']);
} else {
Setting::setSetting('profile_complete', 5);
}
$user = User::find(1);
$user->name = $request->name;
$user->email = $request->email;
if ($request->has('password')) {
$user->password = bcrypt($request->password);
}
$user->save();
return response()->json([
'user' => $user
]);
}
public function uploadAdminAvatar(Request $request)
{
$setting = Setting::getSetting('profile_complete');
if ($setting == '1' || $setting == 'COMPLETED') {
return response()->json(['error' => 'Profile already created.']);
}
$data = json_decode($request->admin_avatar);
if($data) {
$user = User::find($data->id);
if($user) {
$user->clearMediaCollection('admin_avatar');
$user->addMediaFromBase64($data->data)
->usingFileName($data->name)
->toMediaCollection('admin_avatar');
}
}
return response()->json([
'user' => $user,
'success' => true
]);
}
public function adminCompany(CompanyRequest $request)
{
$setting = Setting::getSetting('profile_complete');
if ($setting == '6' || $setting == 'COMPLETED') {
return response()->json(['error' => 'Company already created.']);
} else {
Setting::setSetting('profile_complete', 6);
}
$user = User::find(1);
$company = $user->company;
if (!$company) {
$company = new Company();
}
$company->name = $request->name;
$company->unique_hash = str_random(60);
$company->save();
$user->company()->associate($company);
$user->save();
if ($request->has('logo') && $request->logo !== null && $request->logo !== 'undefined' ) {
$company->addMediaFromRequest('logo')->toMediaCollection('logo');
}
$fields = $request->only([
'address_street_1',
'address_street_2',
'city',
'state',
'country_id',
'zip',
'phone'
]);
$address = Address::updateOrCreate(['user_id' => 1], $fields);
$user = User::with('addresses', 'company')->find(1);
CompanySetting::setSetting(
'notification_email',
$user->email,
$company->id
);
return response()->json([
'user' => $user
]);
}
public function companySettings(CompanySettingRequest $request)
{
$setting = Setting::getSetting('profile_complete');
if($setting == 'COMPLETED') {
return response()->json(['error' => 'Settings already saved.']);
} else {
Setting::setSetting('profile_complete', 'COMPLETED');
}
$user = User::find(1);
$sets = ['currency',
'time_zone',
'language',
'carbon_date_format',
'moment_date_format',
'fiscal_year'
];
foreach ($sets as $key) {
CompanySetting::setSetting(
$key,
$request->$key,
$user->company_id
);
}
$colors = [
'primary_text_color' => '#5851D8',
'heading_text_color' => '#595959',
'section_heading_text_color' => '#040405',
'border_color' => '#EAF1FB',
'body_text_color' => '#595959',
'footer_text_color' => '#595959',
'footer_total_color' => '#5851D8',
'footer_bg_color' => '#F9FBFF',
'date_text_color' => '#A5ACC1',
'invoice_primary_color' => '#5851D8',
'invoice_column_heading' => '#55547A',
'invoice_field_label' => '#55547A',
'invoice_field_value' => '#040405',
'invoice_body_text' => '#040405',
'invoice_description_text' => '#595959',
'invoice_border_color' => '#EAF1FB'
];
foreach ($colors as $key => $value) {
CompanySetting::setSetting(
$key,
$value,
$user->company_id
);
}
Setting::setSetting('version', config('crater.version'));
Artisan::call('passport:install --force');
$client = DB::table('oauth_clients')->find(2);
$path = base_path('.env');
if (file_exists($path)) {
file_put_contents($path, str_replace(
'PROXY_OAUTH_CLIENT_SECRET='.config('auth.proxy.client_secret'), 'PROXY_OAUTH_CLIENT_SECRET='.$client->secret, file_get_contents($path)
));
}
$data['token'] = $user->createToken('password')->accessToken;
return response()->json($data);
}
}

View File

@@ -1,252 +0,0 @@
<?php
namespace Crater\Http\Controllers;
use Illuminate\Http\Request;
use Crater\CompanySetting;
use Crater\Currency;
use Crater\Invoice;
use Crater\Payment;
use Carbon\Carbon;
use function MongoDB\BSON\toJSON;
use Crater\User;
use Crater\Http\Requests\PaymentRequest;
class PaymentController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index(Request $request)
{
$limit = $request->has('limit') ? $request->limit : 10;
$payments = Payment::with('user', 'invoice')
->join('users', 'users.id', '=', 'payments.user_id')
->leftJoin('invoices', 'invoices.id', '=', 'payments.invoice_id')
->applyFilters($request->only([
'search',
'payment_number',
'payment_mode',
'customer_id',
'orderByField',
'orderBy'
]))
->whereCompany($request->header('company'))
->select('payments.*', 'users.name', 'invoices.invoice_number')
->latest()
->paginate($limit);
return response()->json([
'payments' => $payments
]);
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create(Request $request)
{
$nextPaymentNumber = 'PAY-'.Payment::getNextPaymentNumber();
return response()->json([
'customers' => User::where('role', 'customer')
->whereCompany($request->header('company'))
->get(),
'nextPaymentNumber' => $nextPaymentNumber
]);
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(PaymentRequest $request)
{
$payment_date = Carbon::createFromFormat('d/m/Y', $request->payment_date);
if ($request->has('invoice_id') && $request->invoice_id != null) {
$invoice = Invoice::find($request->invoice_id);
if ($invoice && $invoice->due_amount == $request->amount) {
$invoice->status = Invoice::STATUS_COMPLETED;
$invoice->paid_status = Invoice::STATUS_PAID;
$invoice->due_amount = 0;
} elseif ($invoice && $invoice->due_amount != $request->amount) {
$invoice->due_amount = (int)$invoice->due_amount - (int)$request->amount;
if ($invoice->due_amount < 0) {
return response()->json([
'error' => 'invalid_amount'
]);
}
$invoice->paid_status = Invoice::STATUS_PARTIALLY_PAID;
}
$invoice->save();
}
$payment = Payment::create([
'payment_date' => $payment_date,
'payment_number' => $request->payment_number,
'user_id' => $request->user_id,
'company_id' => $request->header('company'),
'invoice_id' => $request->invoice_id,
'payment_mode' => $request->payment_mode,
'amount' => $request->amount,
'notes' => $request->notes,
]);
return response()->json([
'payment' => $payment,
'success' => true
]);
}
/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show($id)
{
//
}
/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function edit(Request $request, $id)
{
$payment = Payment::with('user', 'invoice')->find($id);
$invoices = Invoice::where('paid_status', '<>', Invoice::STATUS_PAID)
->where('user_id', $payment->user_id)->where('due_amount', '>', 0)
->whereCompany($request->header('company'))
->get();
return response()->json([
'customers' => User::where('role', 'customer')
->whereCompany($request->header('company'))
->get(),
'nextPaymentNumber' => $payment->payment_number,
'payment' => $payment,
'invoices' => $invoices
]);
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(PaymentRequest $request, $id)
{
$payment_date = Carbon::createFromFormat('d/m/Y', $request->payment_date);
$payment = Payment::find($id);
$oldAmount = $payment->amount;
if ($request->has('invoice_id') && $request->invoice_id && ($oldAmount != $request->amount)) {
$amount = (int)$request->amount - (int)$oldAmount;
$invoice = Invoice::find($request->invoice_id);
$invoice->due_amount = (int)$invoice->due_amount - (int)$amount;
if ($invoice->due_amount < 0) {
return response()->json([
'error' => 'invalid_amount'
]);
}
if ($invoice->due_amount == 0) {
$invoice->status = Invoice::STATUS_COMPLETED;
$invoice->paid_status = Invoice::STATUS_PAID;
} else {
$invoice->status = $invoice->getPreviousStatus();
$invoice->paid_status = Invoice::STATUS_PARTIALLY_PAID;
}
$invoice->save();
}
$payment->payment_date = $payment_date;
$payment->payment_number = $request->payment_number;
$payment->user_id = $request->user_id;
$payment->invoice_id = $request->invoice_id;
$payment->payment_mode = $request->payment_mode;
$payment->amount = $request->amount;
$payment->notes = $request->notes;
$payment->save();
return response()->json([
'payment' => $payment,
'success' => true
]);
}
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function destroy($id)
{
$payment = Payment::find($id);
if ($payment->invoice_id != null) {
$invoice = Invoice::find($payment->invoice_id);
$invoice->due_amount = ((int)$invoice->due_amount + (int)$payment->amount);
if ($invoice->due_amount == $invoice->total) {
$invoice->paid_status = Invoice::STATUS_UNPAID;
} else {
$invoice->paid_status = Invoice::STATUS_PARTIALLY_PAID;
}
$invoice->status = $invoice->getPreviousStatus();
$invoice->save();
}
$payment->delete();
return response()->json([
'success' => true
]);
}
public function delete(Request $request)
{
foreach ($request->id as $id) {
$payment = Payment::find($id);
if ($payment->invoice_id != null) {
$invoice = Invoice::find($payment->invoice_id);
$invoice->due_amount = ((int)$invoice->due_amount + (int)$payment->amount);
if ($invoice->due_amount == $invoice->total) {
$invoice->paid_status = Invoice::STATUS_UNPAID;
} else {
$invoice->paid_status = Invoice::STATUS_PARTIALLY_PAID;
}
$invoice->status = $invoice->getPreviousStatus();
$invoice->save();
}
$payment->delete();
}
return response()->json([
'success' => true
]);
}
}

View File

@@ -1,293 +0,0 @@
<?php
namespace Crater\Http\Controllers;
use Illuminate\Http\Request;
use Crater\User;
use Crater\Invoice;
use Crater\Company;
use Crater\InvoiceItem;
use Crater\Expense;
use Crater\CompanySetting;
use Crater\Tax;
use PDF;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Builder;
class ReportController extends Controller
{
public function customersSalesReport($hash, Request $request)
{
$company = Company::where('unique_hash', $hash)->first();
$start = Carbon::createFromFormat('d/m/Y', $request->from_date);
$end = Carbon::createFromFormat('d/m/Y', $request->to_date);
$customers = User::with(['invoices' => function ($query) use ($start, $end) {
$query->whereBetween(
'invoice_date',
[$start->format('Y-m-d'), $end->format('Y-m-d')]
);
}])
->customer()
->whereCompany($company->id)
->applyInvoiceFilters($request->only(['from_date', 'to_date']))
->get();
$totalAmount = 0;
foreach ($customers as $customer) {
$customerTotalAmount = 0;
foreach ($customer->invoices as $invoice) {
$customerTotalAmount += $invoice->total;
}
$customer->totalAmount = $customerTotalAmount;
$totalAmount += $customerTotalAmount;
}
$dateFormat = CompanySetting::getSetting('carbon_date_format', $company->id);
$from_date = Carbon::createFromFormat('d/m/Y', $request->from_date)->format($dateFormat);
$to_date = Carbon::createFromFormat('d/m/Y', $request->to_date)->format($dateFormat);
$colors = [
'primary_text_color',
'heading_text_color',
'section_heading_text_color',
'border_color',
'body_text_color',
'footer_text_color',
'footer_total_color',
'footer_bg_color',
'date_text_color'
];
$colorSettings = CompanySetting::whereIn('option', $colors)
->whereCompany($company->id)
->get();
view()->share([
'customers' => $customers,
'totalAmount' => $totalAmount,
'colorSettings' => $colorSettings,
'company' => $company,
'from_date' => $from_date,
'to_date' => $to_date
]);
$pdf = PDF::loadView('app.pdf.reports.sales-customers');
if ($request->has('download')) {
return $pdf->download();
}
return $pdf->stream();
}
public function itemsSalesReport($hash, Request $request)
{
$company = Company::where('unique_hash', $hash)->first();
$items = InvoiceItem::whereCompany($company->id)
->applyInvoiceFilters($request->only(['from_date', 'to_date']))
->itemAttributes()
->get();
$totalAmount = 0;
foreach ($items as $item) {
$totalAmount += $item->total_amount;
}
$dateFormat = CompanySetting::getSetting('carbon_date_format', $company->id);
$from_date = Carbon::createFromFormat('d/m/Y', $request->from_date)->format($dateFormat);
$to_date = Carbon::createFromFormat('d/m/Y', $request->to_date)->format($dateFormat);
$colors = [
'primary_text_color',
'heading_text_color',
'section_heading_text_color',
'border_color',
'body_text_color',
'footer_text_color',
'footer_total_color',
'footer_bg_color',
'date_text_color'
];
$colorSettings = CompanySetting::whereIn('option', $colors)
->whereCompany($company->id)
->get();
view()->share([
'items' => $items,
'colorSettings' => $colorSettings,
'totalAmount' => $totalAmount,
'company' => $company,
'from_date' => $from_date,
'to_date' => $to_date
]);
$pdf = PDF::loadView('app.pdf.reports.sales-items');
if ($request->has('download')) {
return $pdf->download();
}
return $pdf->stream();
}
public function expensesReport($hash, Request $request)
{
$company = Company::where('unique_hash', $hash)->first();
$expenseCategories = Expense::with('category')
->whereCompany($company->id)
->applyFilters($request->only(['from_date', 'to_date']))
->expensesAttributes()
->get();
$totalAmount = 0;
foreach ($expenseCategories as $category) {
$totalAmount += $category->total_amount;
}
$dateFormat = CompanySetting::getSetting('carbon_date_format', $company->id);
$from_date = Carbon::createFromFormat('d/m/Y', $request->from_date)->format($dateFormat);
$to_date = Carbon::createFromFormat('d/m/Y', $request->to_date)->format($dateFormat);
$colors = [
'primary_text_color',
'heading_text_color',
'section_heading_text_color',
'border_color',
'body_text_color',
'footer_text_color',
'footer_total_color',
'footer_bg_color',
'date_text_color'
];
$colorSettings = CompanySetting::whereIn('option', $colors)
->whereCompany($company->id)
->get();
view()->share([
'expenseCategories' => $expenseCategories,
'colorSettings' => $colorSettings,
'totalExpense' => $totalAmount,
'company' => $company,
'from_date' => $from_date,
'to_date' => $to_date
]);
$pdf = PDF::loadView('app.pdf.reports.expenses');
if ($request->has('download')) {
return $pdf->download();
}
return $pdf->stream();
}
public function taxSummery($hash, Request $request)
{
$company = Company::where('unique_hash', $hash)->first();
$taxTypes = Tax::with('taxType', 'invoice', 'invoiceItem')
->whereCompany($company->id)
->whereInvoicesFilters($request->only(['from_date', 'to_date']))
->taxAttributes()
->get();
$totalAmount = 0;
foreach ($taxTypes as $taxType) {
$totalAmount += $taxType->total_tax_amount;
}
$dateFormat = CompanySetting::getSetting('carbon_date_format', $company->id);
$from_date = Carbon::createFromFormat('d/m/Y', $request->from_date)->format($dateFormat);
$to_date = Carbon::createFromFormat('d/m/Y', $request->to_date)->format($dateFormat);
$colors = [
'primary_text_color',
'heading_text_color',
'section_heading_text_color',
'border_color',
'body_text_color',
'footer_text_color',
'footer_total_color',
'footer_bg_color',
'date_text_color'
];
$colorSettings = CompanySetting::whereIn('option', $colors)
->whereCompany($company->id)
->get();
view()->share([
'taxTypes' => $taxTypes,
'totalTaxAmount' => $totalAmount,
'colorSettings' => $colorSettings,
'company' => $company,
'from_date' => $from_date,
'to_date' => $to_date
]);
$pdf = PDF::loadView('app.pdf.reports.tax-summary');
if ($request->has('download')) {
return $pdf->download();
}
return $pdf->stream();
}
public function profitLossReport($hash, Request $request)
{
$company = Company::where('unique_hash', $hash)->first();
$invoicesAmount = Invoice::whereCompany($company->id)
->applyFilters($request->only(['from_date', 'to_date']))
->wherePaidStatus(Invoice::STATUS_PAID)
->sum('total');
$expenseCategories = Expense::with('category')
->whereCompany($company->id)
->applyFilters($request->only(['from_date', 'to_date']))
->expensesAttributes()
->get();
$totalAmount = 0;
foreach ($expenseCategories as $category) {
$totalAmount += $category->total_amount;
}
$dateFormat = CompanySetting::getSetting('carbon_date_format', $company->id);
$from_date = Carbon::createFromFormat('d/m/Y', $request->from_date)->format($dateFormat);
$to_date = Carbon::createFromFormat('d/m/Y', $request->to_date)->format($dateFormat);
$colors = [
'primary_text_color',
'heading_text_color',
'section_heading_text_color',
'border_color',
'body_text_color',
'footer_text_color',
'footer_total_color',
'footer_bg_color',
'date_text_color'
];
$colorSettings = CompanySetting::whereIn('option', $colors)
->whereCompany($company->id)
->get();
view()->share([
'company' => $company,
'income' => $invoicesAmount,
'expenseCategories' => $expenseCategories,
'totalExpense' => $totalAmount,
'colorSettings' => $colorSettings,
'company' => $company,
'from_date' => $from_date,
'to_date' => $to_date
]);
$pdf = PDF::loadView('app.pdf.reports.profit-loss');
if ($request->has('download')) {
return $pdf->download();
}
return $pdf->stream();
}
}

View File

@@ -1,19 +0,0 @@
<?php
namespace Crater\Http\Controllers;
use Illuminate\Http\Request;
use Crater\Setting;
class SettingsController extends Controller
{
public function getAppVersion(Request $request)
{
$version = Setting::getSetting('version');
return response()->json([
'version' => $version,
]);
}
}

View File

@@ -1,35 +0,0 @@
<?php
namespace Crater\Http\Controllers;
use Illuminate\Http\Request;
use Crater\Space\Updater;
use Crater\Space\SiteApi;
class UpdateController extends Controller
{
public function update(Request $request)
{
set_time_limit(600); // 10 minutes
$json = Updater::update($request->installed, $request->version);
return response()->json($json);
}
public function finishUpdate(Request $request)
{
$json = Updater::finishUpdate($request->installed, $request->version);
return response()->json($json);
}
public function checkLatestVersion(Request $request)
{
set_time_limit(600); // 10 minutes
$json = Updater::checkForUpdate();
return response()->json($json);
}
}

View File

@@ -1,74 +0,0 @@
<?php
namespace Crater\Http\Controllers;
use Illuminate\Http\Request;
use Crater\Http\Requests;
use Crater\User;
use Crater\Currency;
use Crater\Setting;
use Crater\Item;
use Crater\TaxType;
use DB;
use Carbon\Carbon;
use Auth;
use Crater\Company;
use Crater\CompanySetting;
class UsersController extends Controller
{
public function getBootstrap(Request $request)
{
$user = Auth::user();
$company = $request->header('company') ?? 1;
$customers = User::with('billingAddress', 'shippingAddress')
->customer()
->whereCompany($company)
->latest()
->get();
$currencies = Currency::latest()->get();
$default_language = CompanySetting::getSetting('language', $company);
$default_currency = Currency::findOrFail(
CompanySetting::getSetting('currency', $company)
);
$moment_date_format = CompanySetting::getSetting(
'moment_date_format',
$request->header('company')
);
$fiscal_year = CompanySetting::getSetting(
'fiscal_year',
$request->header('company')
);
$items = Item::all();
$taxTypes = TaxType::latest()->get();
return response()->json([
'user' => $user,
'customers' => $customers,
'currencies' => $currencies,
'default_currency' => $default_currency,
'default_language' => $default_language,
'company' => $user->company,
'companies' => Company::all(),
'items' => $items,
'taxTypes' => $taxTypes,
'moment_date_format' => $moment_date_format,
'fiscal_year' => $fiscal_year,
]);
}
public function ping()
{
return response()->json([
'success' => 'crater-self-hosted'
]);
}
}

View File

@@ -0,0 +1,40 @@
<?php
namespace Crater\Http\Controllers\V1\Auth;
use Crater\Http\Controllers\Controller;
use Crater\Providers\RouteServiceProvider;
use Illuminate\Foundation\Auth\ConfirmsPasswords;
class ConfirmPasswordController extends Controller
{
/*
|--------------------------------------------------------------------------
| Confirm Password Controller
|--------------------------------------------------------------------------
|
| This controller is responsible for handling password confirmations and
| uses a simple trait to include the behavior. You're free to explore
| this trait and override any functions that require customization.
|
*/
use ConfirmsPasswords;
/**
* Where to redirect users when the intended url fails.
*
* @var string
*/
protected $redirectTo = RouteServiceProvider::HOME;
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
}

View File

@@ -1,5 +1,6 @@
<?php
namespace Crater\Http\Controllers\Auth;
namespace Crater\Http\Controllers\V1\Auth;
use Crater\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
@@ -20,16 +21,6 @@ class ForgotPasswordController extends Controller
use SendsPasswordResetEmails;
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
// $this->middleware('guest');
}
/**
* Get the response for a successful password reset link.
*

View File

@@ -0,0 +1,40 @@
<?php
namespace Crater\Http\Controllers\V1\Auth;
use Crater\Http\Controllers\Controller;
use Crater\Providers\RouteServiceProvider;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
class LoginController extends Controller
{
/*
|--------------------------------------------------------------------------
| Login Controller
|--------------------------------------------------------------------------
|
| This controller handles authenticating users for the application and
| redirecting them to your home screen. The controller uses a trait
| to conveniently provide its functionality to your applications.
|
*/
use AuthenticatesUsers;
/**
* Where to redirect users after login.
*
* @var string
*/
protected $redirectTo = RouteServiceProvider::HOME;
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest')->except('logout');
}
}

View File

@@ -0,0 +1,73 @@
<?php
namespace Crater\Http\Controllers\V1\Auth;
use Crater\Http\Controllers\Controller;
use Crater\Providers\RouteServiceProvider;
use Crater\Models\User;
use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
class RegisterController extends Controller
{
/*
|--------------------------------------------------------------------------
| Register Controller
|--------------------------------------------------------------------------
|
| This controller handles the registration of new users as well as their
| validation and creation. By default this controller uses a trait to
| provide this functionality without requiring any additional code.
|
*/
use RegistersUsers;
/**
* Where to redirect users after registration.
*
* @var string
*/
protected $redirectTo = RouteServiceProvider::HOME;
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest');
}
/**
* Get a validator for an incoming registration request.
*
* @param array $data
* @return \Illuminate\Contracts\Validation\Validator
*/
protected function validator(array $data)
{
return Validator::make($data, [
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
'password' => ['required', 'string', 'min:8', 'confirmed'],
]);
}
/**
* Create a new user instance after a valid registration.
*
* @param array $data
* @return \App\User
*/
protected function create(array $data)
{
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => $data['password']
]);
}
}

View File

@@ -1,11 +1,13 @@
<?php
namespace Crater\Http\Controllers\Auth;
namespace Crater\Http\Controllers\V1\Auth;
use Crater\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ResetsPasswords;
use Illuminate\Http\Request;
use Crater\Providers\RouteServiceProvider;
use Illuminate\Support\Str;
use Illuminate\Auth\Events\PasswordReset;
use Illuminate\Http\Request;
use Illuminate\Foundation\Auth\ResetsPasswords;
class ResetPasswordController extends Controller
{
@@ -27,17 +29,8 @@ class ResetPasswordController extends Controller
*
* @var string
*/
protected $redirectTo = '/';
protected $redirectTo = RouteServiceProvider::HOME;
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
// $this->middleware('guest');
}
/**
* Get the response for a successful password reset.
@@ -62,7 +55,7 @@ class ResetPasswordController extends Controller
*/
protected function resetPassword($user, $password)
{
$user->password = \Hash::make($password);
$user->password = $password;
$user->setRememberToken(Str::random(60));

View File

@@ -0,0 +1,42 @@
<?php
namespace Crater\Http\Controllers\V1\Auth;
use Crater\Http\Controllers\Controller;
use Crater\Providers\RouteServiceProvider;
use Illuminate\Foundation\Auth\VerifiesEmails;
class VerificationController extends Controller
{
/*
|--------------------------------------------------------------------------
| Email Verification Controller
|--------------------------------------------------------------------------
|
| This controller is responsible for handling email verification for any
| user that recently registered with the application. Emails may also
| be re-sent if the user didn't receive the original email message.
|
*/
use VerifiesEmails;
/**
* Where to redirect users after verification.
*
* @var string
*/
protected $redirectTo = RouteServiceProvider::HOME;
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
$this->middleware('signed')->only('verify');
$this->middleware('throttle:6,1')->only('verify', 'resend');
}
}

View File

@@ -0,0 +1,23 @@
<?php
// Implementation taken from nova-backup-tool - https://github.com/spatie/nova-backup-tool/
namespace Crater\Http\Controllers\V1\Backup;
use Crater\Http\Controllers\Controller;
use Illuminate\Http\JsonResponse;
class ApiController extends Controller
{
/**
*
* @return JsonResponse
*/
public function respondSuccess(): JsonResponse
{
return response()->json([
'success' => true
]);
}
}

View File

@@ -0,0 +1,93 @@
<?php
// Implementation taken from nova-backup-tool - https://github.com/spatie/nova-backup-tool/
namespace Crater\Http\Controllers\V1\Backup;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Spatie\Backup\BackupDestination\Backup;
use Spatie\Backup\BackupDestination\BackupDestination;
use Spatie\Backup\Helpers\Format;
use Crater\Jobs\CreateBackupJob;
use Crater\Rules\Backup\BackupDisk;
use Crater\Rules\Backup\PathToZip;
use Illuminate\Http\JsonResponse;
class BackupsController extends ApiController
{
/**
* Display a listing of the resource.
*
* @return JsonResponse
*/
public function index(Request $request)
{
$configuredBackupDisks = config('backup.backup.destination.disks');
try {
$backupDestination = BackupDestination::create(config('filesystems.default'), config('backup.backup.name'));
$backups = Cache::remember("backups-{$request->file_disk_id}", now()->addSeconds(4), function () use ($backupDestination) {
return $backupDestination
->backups()
->map(function (Backup $backup) {
return [
'path' => $backup->path(),
'created_at' => $backup->date()->format('Y-m-d H:i:s'),
'size' => Format::humanReadableSize($backup->size()),
];
})
->toArray();
});
return response()->json([
'backups' => $backups,
'disks' => $configuredBackupDisks
]);
} catch (\Exception $e) {
return response()->json([
'backups' => [],
'error' => 'invalid_disk_credentials',
'error_message' => $e->getMessage(),
'disks' => $configuredBackupDisks
]);
}
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return JsonResponse
*/
public function store(Request $request)
{
dispatch(new CreateBackupJob($request->all()))->onQueue(config('backup.queue.name'));
return $this->respondSuccess();
}
/**
* Remove the specified resource from storage.
*
* @param \Illuminate\Http\Request $request
* @return JsonResponse
*/
public function destroy($disk, Request $request)
{
$validated = $request->validate([
'path' => ['required', new PathToZip()],
]);
$backupDestination = BackupDestination::create(config('filesystems.default'), config('backup.backup.name'));
$backupDestination
->backups()
->first(function (Backup $backup) use ($validated) {
return $backup->path() === $validated['path'];
})
->delete();
return $this->respondSuccess();
}
}

View File

@@ -0,0 +1,58 @@
<?php
// Implementation taken from nova-backup-tool - https://github.com/spatie/nova-backup-tool/
namespace Crater\Http\Controllers\V1\Backup;
use Crater\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Spatie\Backup\BackupDestination\Backup;
use Spatie\Backup\BackupDestination\BackupDestination;
use Crater\Rules\Backup\BackupDisk;
use Crater\Rules\Backup\PathToZip;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\StreamedResponse;
class DownloadBackupController extends ApiController
{
public function __invoke(Request $request)
{
$validated = $request->validate([
'path' => ['required', new PathToZip()],
]);
$backupDestination = BackupDestination::create(config('filesystems.default'), config('backup.backup.name'));
$backup = $backupDestination->backups()->first(function (Backup $backup) use ($validated) {
return $backup->path() === $validated['path'];
});
if (! $backup) {
return response('Backup not found', Response::HTTP_UNPROCESSABLE_ENTITY);
}
return $this->respondWithBackupStream($backup);
}
public function respondWithBackupStream(Backup $backup): StreamedResponse
{
$fileName = pathinfo($backup->path(), PATHINFO_BASENAME);
$downloadHeaders = [
'Cache-Control' => 'must-revalidate, post-check=0, pre-check=0',
'Content-Type' => 'application/zip',
'Content-Length' => $backup->size(),
'Content-Disposition' => 'attachment; filename="'.$fileName.'"',
'Pragma' => 'public',
];
return response()->stream(function () use ($backup) {
$stream = $backup->stream();
fpassthru($stream);
if (is_resource($stream)) {
fclose($stream);
}
}, 200, $downloadHeaders);
}
}

View File

@@ -0,0 +1,102 @@
<?php
namespace Crater\Http\Controllers\V1\CustomField;
use Crater\Models\CustomField;
use Crater\Http\Controllers\Controller;
use Crater\Http\Requests\CustomFieldRequest;
use Illuminate\Http\Request;
class CustomFieldsController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index(Request $request)
{
$limit = $request->has('limit') ? $request->limit : 5;
$customFields = CustomField::whereCompany($request->header('company'))
->applyFilters($request->only([
'type',
'search'
]))
->latest()
->paginateData($limit);
return response()->json([
'customFields' => $customFields
]);
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\CustomFieldRequest $request
* @return \Illuminate\Http\Response
*/
public function store(CustomFieldRequest $request)
{
$customField = CustomField::createCustomField($request);
return response()->json([
'customField' => $customField,
'success' => true
]);
}
/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show(CustomField $customField)
{
return response()->json([
'customField' => $customField,
'success' => true
]);
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(CustomFieldRequest $request, CustomField $customField)
{
$customField->updateCustomField($request);
return response()->json([
'customField' => $customField,
'success' => true
]);
}
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function destroy(CustomField $customField)
{
if ($customField->customFieldValue()->exists()) {
return response()->json([
'error' => 'values_attached'
]);
}
$customField->delete();
return response()->json([
'success' => true
]);
}
}

View File

@@ -0,0 +1,146 @@
<?php
namespace Crater\Http\Controllers\V1\Customer;
use Crater\Http\Controllers\Controller;
use Crater\Models\Invoice;
use Crater\Models\Expense;
use Crater\Models\Payment;
use Crater\Models\User;
use Crater\Models\CompanySetting;
use Carbon\Carbon;
use Illuminate\Http\Request;
class CustomerStatsController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function __invoke(Request $request, User $customer)
{
$i = 0;
$months = [];
$invoiceTotals = [];
$expenseTotals = [];
$receiptTotals = [];
$netProfits = [];
$monthCounter = 0;
$fiscalYear = CompanySetting::getSetting('fiscal_year', $request->header('company'));
$startDate = Carbon::now();
$start = Carbon::now();
$end = Carbon::now();
$terms = explode('-', $fiscalYear);
if ($terms[0] <= $start->month) {
$startDate->month($terms[0])->startOfMonth();
$start->month($terms[0])->startOfMonth();
$end->month($terms[0])->endOfMonth();
} else {
$startDate->subYear()->month($terms[0])->startOfMonth();
$start->subYear()->month($terms[0])->startOfMonth();
$end->subYear()->month($terms[0])->endOfMonth();
}
if ($request->has('previous_year')) {
$startDate->subYear()->startOfMonth();
$start->subYear()->startOfMonth();
$end->subYear()->endOfMonth();
}
while ($monthCounter < 12) {
array_push(
$invoiceTotals,
Invoice::whereBetween(
'invoice_date',
[$start->format('Y-m-d'), $end->format('Y-m-d')]
)
->whereCompany($request->header('company'))
->whereCustomer($customer->id)
->sum('total') ?? 0
);
array_push(
$expenseTotals,
Expense::whereBetween(
'expense_date',
[$start->format('Y-m-d'), $end->format('Y-m-d')]
)
->whereCompany($request->header('company'))
->whereUser($customer->id)
->sum('amount') ?? 0
);
array_push(
$receiptTotals,
Payment::whereBetween(
'payment_date',
[$start->format('Y-m-d'), $end->format('Y-m-d')]
)
->whereCompany($request->header('company'))
->whereCustomer($customer->id)
->sum('amount') ?? 0
);
array_push(
$netProfits,
($receiptTotals[$i] - $expenseTotals[$i])
);
$i++;
array_push($months, $start->format('M'));
$monthCounter++;
$end->startOfMonth();
$start->addMonth()->startOfMonth();
$end->addMonth()->endOfMonth();
}
$start->subMonth()->endOfMonth();
$salesTotal = Invoice::whereCompany($request->header('company'))
->whereBetween(
'invoice_date',
[$startDate->format('Y-m-d'), $start->format('Y-m-d')]
)
->whereCustomer($customer->id)
->sum('total');
$totalReceipts = Payment::whereCompany($request->header('company'))
->whereBetween(
'payment_date',
[$startDate->format('Y-m-d'), $start->format('Y-m-d')]
)
->whereCustomer($customer->id)
->sum('amount');
$totalExpenses = Expense::whereCompany($request->header('company'))
->whereBetween(
'expense_date',
[$startDate->format('Y-m-d'), $start->format('Y-m-d')]
)
->whereUser($customer->id)
->sum('amount');
$netProfit = (int) $totalReceipts - (int) $totalExpenses;
$chartData = [
'months' => $months,
'invoiceTotals' => $invoiceTotals,
'expenseTotals' => $expenseTotals,
'receiptTotals' => $receiptTotals,
'netProfit' => $netProfit,
'netProfits' => $netProfits,
'salesTotal' => $salesTotal,
'totalReceipts' => $totalReceipts,
'totalExpenses' => $totalExpenses
];
$customer = User::with([
'billingAddress',
'shippingAddress',
'billingAddress.country',
'shippingAddress.country',
'currency',
'fields.customField'
])->find($customer->id);
return response()->json([
'customer' => $customer,
'chartData' => $chartData,
]);
}
}

View File

@@ -0,0 +1,122 @@
<?php
namespace Crater\Http\Controllers\V1\Customer;
use Illuminate\Http\Request;
use Crater\Http\Requests;
use Crater\Models\User;
use Crater\Http\Controllers\Controller;
use Illuminate\Support\Facades\DB;
class CustomersController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\JsonResponse
*/
public function index(Request $request)
{
$limit = $request->has('limit') ? $request->limit : 10;
$customers = User::with('creator')
->customer()
->applyFilters($request->only([
'search',
'contact_name',
'display_name',
'phone',
'customer_id',
'orderByField',
'orderBy'
]))
->whereCompany($request->header('company'))
->select(
'users.*',
DB::raw('sum(invoices.due_amount) as due_amount')
)
->groupBy('users.id')
->leftJoin('invoices', 'users.id', '=', 'invoices.user_id')
->paginateData($limit);
return response()->json([
'customers' => $customers,
'customerTotalCount' => User::whereRole('customer')->count()
]);
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function store(Requests\CustomerRequest $request)
{
$customer = User::createCustomer($request);
return response()->json([
'customer' => $customer,
'success' => true
]);
}
/**
* Display the specified resource.
*
* @param User $customer
* @return \Illuminate\Http\JsonResponse
*/
public function show(User $customer)
{
$customer->load([
'billingAddress.country',
'shippingAddress.country',
'fields.customField',
'creator'
]);
$currency = $customer->currency;
return response()->json([
'customer' => $customer,
'currency' => $currency,
]);
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param \Crater\Models\User $customer
* @return \Illuminate\Http\JsonResponse
*/
public function update(Requests\CustomerRequest $request, User $customer)
{
$customer = User::updateCustomer($request, $customer);
$customer = User::with('billingAddress', 'shippingAddress', 'fields')->find($customer->id);
return response()->json([
'customer' => $customer,
'success' => true
]);
}
/**
* 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
*/
public function delete(Request $request)
{
User::deleteCustomers($request->ids);
return response()->json([
'success' => true
]);
}
}

View File

@@ -0,0 +1,32 @@
<?php
namespace Crater\Http\Controllers\V1\Dashboard;
use Crater\Models\Expense;
use Crater\Http\Controllers\Controller;
use Illuminate\Http\Request;
class DashboardChartController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function __invoke(Request $request)
{
$expensesCategories = Expense::with('category')
->whereCompany($request->header('company'))
->expensesAttributes()
->get();
$amounts = $expensesCategories->pluck('total_amount');
$names = $expensesCategories->pluck('category.name');
return response()->json([
'amounts' => $amounts,
'categories' => $names,
]);
}
}

View File

@@ -1,21 +1,25 @@
<?php
namespace Crater\Http\Controllers;
namespace Crater\Http\Controllers\V1\Dashboard;
use Illuminate\Http\Request;
use Crater\Estimate;
use Crater\Http\Requests;
use Crater\Invoice;
use Crater\CompanySetting;
use Crater\Expense;
use Crater\Payment;
use Crater\Models\Estimate;
use Crater\Models\Invoice;
use Crater\Models\CompanySetting;
use Crater\Models\Expense;
use Crater\Models\Payment;
use Carbon\Carbon;
use Crater\User;
use Illuminate\Support\Facades\DB;
use Crater\Models\User;
use Crater\Http\Controllers\Controller;
class DashboardController extends Controller
{
public function index(Request $request)
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function __invoke(Request $request)
{
$invoiceTotals = [];
$expenseTotals = [];
@@ -23,14 +27,14 @@ class DashboardController extends Controller
$netProfits = [];
$i = 0;
$months = [];
$monthEnds = [];
$monthCounter = 0;
$fiscalYear = CompanySetting::getSetting('fiscal_year', $request->header('company'));
$startDate = Carbon::now();
$start = Carbon::now();
$end = Carbon::now();
$terms = explode('-', $fiscalYear);
if ($terms[0] < $start->month) {
if ($terms[0] <= $start->month) {
$startDate->month($terms[0])->startOfMonth();
$start->month($terms[0])->startOfMonth();
$end->month($terms[0])->endOfMonth();
@@ -87,6 +91,7 @@ class DashboardController extends Controller
}
$start->subMonth()->endOfMonth();
$salesTotal = Invoice::whereCompany($request->header('company'))
->whereBetween(
'invoice_date',
@@ -136,20 +141,4 @@ class DashboardController extends Controller
'netProfit' => $netProfit
]);
}
public function getExpenseChartData(Request $request)
{
$expensesCategories = Expense::with('category')
->whereCompany($request->header('company'))
->expensesAttributes()
->get();
$amounts = $expensesCategories->pluck('total_amount');
$names = $expensesCategories->pluck('category.name');
return response()->json([
'amounts' => $amounts,
'categories' => $names,
]);
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace Crater\Http\Controllers\V1\Estimate;
use Illuminate\Http\Request;
use Crater\Http\Controllers\Controller;
use Crater\Models\Estimate;
class ChangeEstimateStatusController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @param Estimate $estimate
* @return \Illuminate\Http\Response
*/
public function __invoke(Request $request, Estimate $estimate)
{
$estimate->update($request->only('status'));
return response()->json([
'success' => true
]);
}
}

View File

@@ -0,0 +1,95 @@
<?php
namespace Crater\Http\Controllers\V1\Estimate;
use Illuminate\Http\Request;
use Crater\Http\Controllers\Controller;
use Crater\Models\Estimate;
use Crater\Models\Invoice;
use Carbon\Carbon;
use Crater\Models\CompanySetting;
use Illuminate\Support\Facades\Auth;
class ConvertEstimateController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Crater\Models\Estimate $estimate
* @return \Illuminate\Http\Response
*/
public function __invoke(Request $request, Estimate $estimate)
{
$estimate->load(['items', 'items.taxes', 'user', 'estimateTemplate', 'taxes']);
$invoice_date = Carbon::now();
$due_date = Carbon::now()->addDays(7);
$invoice_prefix = CompanySetting::getSetting(
'invoice_prefix',
$request->header('company')
);
$invoice = Invoice::create([
'creator_id' => Auth::id(),
'invoice_date' => $invoice_date->format('Y-m-d'),
'due_date' => $due_date->format('Y-m-d'),
'invoice_number' => $invoice_prefix . "-" . Invoice::getNextInvoiceNumber($invoice_prefix),
'reference_number' => $estimate->reference_number,
'user_id' => $estimate->user_id,
'company_id' => $request->header('company'),
'invoice_template_id' => 1,
'status' => Invoice::STATUS_DRAFT,
'paid_status' => Invoice::STATUS_UNPAID,
'sub_total' => $estimate->sub_total,
'discount' => $estimate->discount,
'discount_type' => $estimate->discount_type,
'discount_val' => $estimate->discount_val,
'total' => $estimate->total,
'due_amount' => $estimate->total,
'tax_per_item' => $estimate->tax_per_item,
'discount_per_item' => $estimate->discount_per_item,
'tax' => $estimate->tax,
'notes' => $estimate->notes,
'unique_hash' => str_random(60)
]);
$invoiceItems = $estimate->items->toArray();
foreach ($invoiceItems as $invoiceItem) {
$invoiceItem['company_id'] = $request->header('company');
$invoiceItem['name'] = $invoiceItem['name'];
$item = $invoice->items()->create($invoiceItem);
if (array_key_exists('taxes', $invoiceItem) && $invoiceItem['taxes']) {
foreach ($invoiceItem['taxes'] as $tax) {
$tax['company_id'] = $request->header('company');
if ($tax['amount']) {
$item->taxes()->create($tax);
}
}
}
}
if ($estimate->taxes) {
foreach ($estimate->taxes->toArray() as $tax) {
$tax['company_id'] = $request->header('company');
unset($tax['estimate_id']);
$invoice->taxes()->create($tax);
}
}
$invoice = Invoice::with([
'items',
'user',
'invoiceTemplate',
'taxes'
])->find($invoice->id);
return response()->json([
'invoice' => $invoice
]);
}
}

View File

@@ -0,0 +1,20 @@
<?php
namespace Crater\Http\Controllers\V1\Estimate;
use Crater\Models\Estimate;
use Crater\Http\Controllers\Controller;
class EstimatePdfController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function __invoke(Estimate $estimate)
{
return $estimate->getGeneratedPDFOrStream('estimate');
}
}

View File

@@ -0,0 +1,23 @@
<?php
namespace Crater\Http\Controllers\V1\Estimate;
use Crater\Models\EstimateTemplate;
use Crater\Http\Controllers\Controller;
use Illuminate\Http\Request;
class EstimateTemplatesController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function __invoke(Request $request)
{
return response()->json([
'templates' => EstimateTemplate::all()
]);
}
}

View File

@@ -0,0 +1,104 @@
<?php
namespace Crater\Http\Controllers\V1\Estimate;
use Illuminate\Http\Request;
use Crater\Models\Estimate;
use Crater\Http\Requests\EstimatesRequest;
use Crater\Http\Controllers\Controller;
use Crater\Http\Requests\DeleteEstimatesRequest;
use Crater\Jobs\GenerateEstimatePdfJob;
class EstimatesController extends Controller
{
public function index(Request $request)
{
$limit = $request->has('limit') ? $request->limit : 10;
$estimates = Estimate::with([
'items',
'user',
'estimateTemplate',
'taxes',
'creator'
])
->join('users', 'users.id', '=', 'estimates.user_id')
->applyFilters($request->only([
'status',
'customer_id',
'estimate_id',
'estimate_number',
'from_date',
'to_date',
'search',
'orderByField',
'orderBy'
]))
->whereCompany($request->header('company'))
->select('estimates.*', 'users.name')
->latest()
->paginateData($limit);
$siteData = [
'estimates' => $estimates,
'estimateTotalCount' => Estimate::count()
];
return response()->json($siteData);
}
public function store(EstimatesRequest $request)
{
$estimate = Estimate::createEstimate($request);
if ($request->has('estimateSend')) {
$estimate->send($request->title, $request->body);
}
GenerateEstimatePdfJob::dispatch($estimate);
return response()->json([
'estimate' => $estimate
]);
}
public function show(Request $request, Estimate $estimate)
{
$estimate->load([
'items',
'items.taxes',
'user',
'estimateTemplate',
'creator',
'taxes',
'taxes.taxType',
'fields.customField'
]);
return response()->json([
'estimate' => $estimate,
'nextEstimateNumber' => $estimate->getEstimateNumAttribute(),
'estimatePrefix' => $estimate->getEstimatePrefixAttribute(),
]);
}
public function update(EstimatesRequest $request, Estimate $estimate)
{
$estimate = $estimate->updateEstimate($request);
GenerateEstimatePdfJob::dispatch($estimate, true);
return response()->json([
'estimate' => $estimate
]);
}
public function delete(DeleteEstimatesRequest $request)
{
Estimate::destroy($request->ids);
return response()->json([
'success' => true
]);
}
}

View File

@@ -0,0 +1,23 @@
<?php
namespace Crater\Http\Controllers\V1\Estimate;
use Crater\Http\Controllers\Controller;
use Crater\Models\Estimate;
use Crater\Http\Requests\SendEstimatesRequest;
class SendEstimateController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Crater\Http\Requests\SendEstimatesRequest $request
* @return \Illuminate\Http\JsonResponse
*/
public function __invoke(SendEstimatesRequest $request, Estimate $estimate)
{
$response = $estimate->send($request->all());
return response()->json($response);
}
}

View File

@@ -0,0 +1,34 @@
<?php
namespace Crater\Http\Controllers\V1\Expense;
use Crater\Models\Expense;
use Crater\Http\Controllers\Controller;
class DownloadReceiptController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @param Expense $expense
* @param string $hash
* @return \Illuminate\Http\Response
*/
public function __invoke(Expense $expense)
{
if ($expense) {
$media = $expense->getFirstMedia('receipts');
if ($media) {
$imagePath = $media->getPath();
$response = \Response::download($imagePath, $media->file_name);
ob_end_clean();
return $response;
}
}
return response()->json([
'error' => 'receipt_not_found'
]);
}
}

View File

@@ -1,13 +1,12 @@
<?php
namespace Crater\Http\Controllers;
namespace Crater\Http\Controllers\V1\Expense;
use Crater\ExpenseCategory;
use Crater\Expense;
use Crater\User;
use Crater\Models\ExpenseCategory;
use Illuminate\Http\Request;
use Crater\Http\Requests\ExpenseCategoryRequest;
use Crater\Http\Controllers\Controller;
class ExpenseCategoryController extends Controller
class ExpenseCategoriesController extends Controller
{
/**
* Display a listing of the resource.
@@ -16,23 +15,21 @@ class ExpenseCategoryController extends Controller
*/
public function index(Request $request)
{
$categories = ExpenseCategory::whereCompany($request->header('company'))->get();
$limit = $request->has('limit') ? $request->limit : 5;
$categories = ExpenseCategory::whereCompany($request->header('company'))
->applyFilters($request->only([
'category_id',
'search'
]))
->latest()
->paginateData($limit);
return response()->json([
'categories' => $categories
]);
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
// return view('app.categories.create');
}
/**
* Store a newly created resource in storage.
*
@@ -41,11 +38,9 @@ class ExpenseCategoryController extends Controller
*/
public function store(ExpenseCategoryRequest $request)
{
$category = new ExpenseCategory();
$category->name = $request->name;
$category->description = $request->description;
$category->company_id = $request->header('company');
$category->save();
$data = $request->validated();
$data['company_id'] = $request->header('company');
$category = ExpenseCategory::create($data);
return response()->json([
'category' => $category,
@@ -56,24 +51,11 @@ class ExpenseCategoryController extends Controller
/**
* Display the specified resource.
*
* @param \Crater\ExpenseCategory $ExpenseCategory
* @param \Crater\Models\ExpenseCategory $category
* @return \Illuminate\Http\Response
*/
public function show(ExpenseCategory $ExpenseCategory)
public function show(ExpenseCategory $category)
{
//
}
/**
* Show the form for editing the specified resource.
*
* @param \Crater\ExpensesCategory $ExpensesCategory
* @return \Illuminate\Http\Response
*/
public function edit($id)
{
$category = ExpenseCategory::findOrFail($id);
return response()->json([
'category' => $category
]);
@@ -83,15 +65,12 @@ class ExpenseCategoryController extends Controller
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param \Crater\ExpenseCategory $ExpenseCategory
* @param \Crater\Models\ExpenseCategory $ExpenseCategory
* @return \Illuminate\Http\Response
*/
public function update(ExpenseCategoryRequest $request, $id)
public function update(ExpenseCategoryRequest $request, ExpenseCategory $category)
{
$category = ExpenseCategory::findOrFail($id);
$category->name = $request->name;
$category->description = $request->description;
$category->save();
$category->update($request->validated());
return response()->json([
'category' => $category,
@@ -102,17 +81,17 @@ class ExpenseCategoryController extends Controller
/**
* Remove the specified resource from storage.
*
* @param \Crater\ExpensesCategory $expensesCategory
* @param \Crater\ExpensesCategory $category
* @return \Illuminate\Http\Response
*/
public function destroy($id)
public function destroy(ExpenseCategory $category)
{
$category = ExpenseCategory::find($id);
if ($category->expenses() && $category->expenses()->count() > 0) {
return response()->json([
'success' => false
]);
}
$category->delete();
return response()->json([

View File

@@ -0,0 +1,101 @@
<?php
namespace Crater\Http\Controllers\V1\Expense;
use Crater\Models\Expense;
use Illuminate\Http\Request;
use Crater\Http\Requests\ExpenseRequest;
use Crater\Http\Controllers\Controller;
use Crater\Http\Requests\DeleteExpensesRequest;
class ExpensesController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\JsonResponse
*/
public function index(Request $request)
{
$limit = $request->has('limit') ? $request->limit : 10;
$expenses = Expense::with('category', 'creator', 'fields')
->leftJoin('users', 'users.id', '=', 'expenses.user_id')
->join('expense_categories', 'expense_categories.id', '=', 'expenses.expense_category_id')
->applyFilters($request->only([
'expense_category_id',
'user_id',
'expense_id',
'search',
'from_date',
'to_date',
'orderByField',
'orderBy'
]))
->whereCompany($request->header('company'))
->select('expenses.*', 'expense_categories.name', 'users.name as user_name')
->paginateData($limit);
return response()->json([
'expenses' => $expenses,
'expenseTotalCount' => Expense::count()
]);
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function store(ExpenseRequest $request)
{
$expense = Expense::createExpense($request);
return response()->json([
'expense' => $expense,
'success' => true
]);
}
/**
* Display the specified resource.
*
* @param \Crater\Models\Expense $expense
* @return \Illuminate\Http\JsonResponse
*/
public function show(Expense $expense)
{
$expense->load('creator', 'fields.customField');
return response()->json([
'expense' => $expense
]);
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param \Crater\Models\Expense $expense
* @return \Illuminate\Http\JsonResponse
*/
public function update(ExpenseRequest $request, Expense $expense)
{
$expense->updateExpense($request);
return response()->json([
'expense' => $expense,
'success' => true
]);
}
public function delete(DeleteExpensesRequest $request)
{
Expense::destroy($request->ids);
return response()->json([
'success' => true
]);
}
}

View File

@@ -0,0 +1,40 @@
<?php
namespace Crater\Http\Controllers\V1\Expense;
use Crater\Models\Expense;
use Crater\Http\Controllers\Controller;
class ShowReceiptController extends Controller
{
/**
* Retrieve details of an expense receipt from storage.
*
* @param \Crater\Models\Expense $expense
* @return \Illuminate\Http\JsonResponse
*/
public function __invoke(Expense $expense)
{
$imagePath = null;
if ($expense) {
$media = $expense->getFirstMedia('receipts');
if ($media) {
$imagePath = $media->getPath();
} else {
return response()->json([
'error' => 'receipt_does_not_exist'
]);
}
}
$type = \File::mimeType($imagePath);
$image = 'data:' . $type . ';base64,' . base64_encode(file_get_contents($imagePath));
return response()->json([
'image' => $image,
'type' => $type
]);
}
}

View File

@@ -0,0 +1,36 @@
<?php
namespace Crater\Http\Controllers\V1\Expense;
use Crater\Models\Expense;
use Crater\Http\Controllers\Controller;
use Illuminate\Http\Request;
class UploadReceiptController extends Controller
{
/**
* Upload the expense receipts to storage.
*
* @param \Illuminate\Http\Request $request
* @param Expense $expense
* @return \Illuminate\Http\JsonResponse
*/
public function __invoke(Request $request, Expense $expense)
{
$data = json_decode($request->attachment_receipt);
if ($data) {
if ($request->type === 'edit') {
$expense->clearMediaCollection('receipts');
}
$expense->addMediaFromBase64($data->data)
->usingFileName($data->name)
->toMediaCollection('receipts', 'local');
}
return response()->json([
'success' => 'Expense receipts uploaded successfully'
]);
}
}

View File

@@ -0,0 +1,52 @@
<?php
namespace Crater\Http\Controllers\V1\General;
use Crater\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Crater\Models\Currency;
use Crater\Models\Country;
use Auth;
use Crater\Models\CompanySetting;
use Crater\Models\CustomField;
class BootstrapController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function __invoke(Request $request)
{
$user = Auth::user();
$default_language = $user->getSettings(['language'])['language'];
$settings = [
'moment_date_format',
'carbon_date_format',
'fiscal_year',
'time_zone',
'currency'
];
$settings = CompanySetting::getSettings($settings, $user->company_id);
$default_currency = Currency::findOrFail($settings['currency']);
return response()->json([
'user' => $user,
'company' => $user->company,
'currencies' => Currency::all(),
'countries' => Country::all(),
'default_currency' => $default_currency,
'default_language' => $default_language,
'moment_date_format' => $settings['moment_date_format'],
'carbon_date_format' => $settings['carbon_date_format'],
'fiscal_year' => $settings['fiscal_year'],
'time_zone' => $settings['time_zone']
]);
}
}

View File

@@ -0,0 +1,23 @@
<?php
namespace Crater\Http\Controllers\V1\General;
use Crater\Models\Country;
use Crater\Http\Controllers\Controller;
use Illuminate\Http\Request;
class CountriesController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function __invoke(Request $request)
{
return response()->json([
'countries' => Country::all()
]);
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace Crater\Http\Controllers\V1\General;
use Crater\Models\Currency;
use Crater\Http\Controllers\Controller;
use Illuminate\Http\Request;
class CurrenciesController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function __invoke(Request $request)
{
$currencies = Currency::latest()->get();
return response()->json([
'currencies' => $currencies
]);
}
}

View File

@@ -0,0 +1,23 @@
<?php
namespace Crater\Http\Controllers\V1\General;
use Crater\Http\Controllers\Controller;
use Crater\Space\DateFormatter;
use Illuminate\Http\Request;
class DateFormatsController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function __invoke(Request $request)
{
return response()->json([
'date_formats' => DateFormatter::get_list()
]);
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace Crater\Http\Controllers\V1\General;
use Crater\Http\Controllers\Controller;
use Illuminate\Http\Request;
class FiscalYearsController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function __invoke(Request $request)
{
return response()->json([
'fiscal_years' => config('crater.fiscal_years')
]);
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace Crater\Http\Controllers\V1\General;
use Crater\Http\Controllers\Controller;
use Illuminate\Http\Request;
class LanguagesController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function __invoke(Request $request)
{
return response()->json([
'languages' => config('crater.languages')
]);
}
}

View File

@@ -0,0 +1,55 @@
<?php
namespace Crater\Http\Controllers\V1\General;
use Crater\Models\Invoice;
use Crater\Models\Estimate;
use Crater\Models\Payment;
use Crater\Models\CompanySetting;
use Crater\Http\Controllers\Controller;
use Illuminate\Http\Request;
class NextNumberController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function __invoke(Request $request)
{
$key = $request->key;
$val = $key . '_prefix';
$prefix = CompanySetting::getSetting(
$val,
$request->header('company')
);
$nextNumber = null;
switch ($key) {
case 'invoice':
$nextNumber = Invoice::getNextInvoiceNumber($prefix);
break;
case 'estimate':
$nextNumber = Estimate::getNextEstimateNumber($prefix);
break;
case 'payment':
$nextNumber = Payment::getNextPaymentNumber($prefix);
break;
default:
return;
}
return response()->json([
'nextNumber' => $nextNumber,
'prefix' => $prefix
]);
}
}

View File

@@ -0,0 +1,88 @@
<?php
namespace Crater\Http\Controllers\V1\General;
use Crater\Http\Controllers\Controller;
use Crater\Http\Requests\NotesRequest;
use Crater\Models\Note;
use Illuminate\Http\Request;
class NotesController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index(Request $request)
{
$limit = $request->limit ?? 10;
$notes = Note::latest()
->applyFilters($request->only(['type', 'search']))
->paginate($limit);
return response()->json([
'notes' => $notes
]);
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(NotesRequest $request)
{
$note = Note::create($request->validated());
return response()->json([
'note' => $note
]);
}
/**
* Display the specified resource.
*
* @param \Crater\Models\Note $note
* @return \Illuminate\Http\Response
*/
public function show(Note $note)
{
return response()->json([
'note' => $note
]);
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param \Crater\Models\Note $note
* @return \Illuminate\Http\Response
*/
public function update(NotesRequest $request, Note $note)
{
$note->update($request->validated());
return response()->json([
'note' => $note
]);
}
/**
* Remove the specified resource from storage.
*
* @param \Crater\Models\Note $note
* @return \Illuminate\Http\Response
*/
public function destroy(Note $note)
{
$note->delete();
return response()->json([
'success' => true
]);
}
}

View File

@@ -0,0 +1,37 @@
<?php
namespace Crater\Http\Controllers\V1\General;
use Crater\Http\Controllers\Controller;
use Crater\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class SearchController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function __invoke(Request $request)
{
$customers = User::where('role', 'customer')
->applyFilters($request->only(['search']))
->latest()
->paginate(10);
if (Auth::user()->role == 'super admin') {
$users = User::where('role', 'admin')
->applyFilters($request->only(['search']))
->latest()
->paginate(10);
}
return response()->json([
'customers' => $customers,
'users' => $users ?? []
]);
}
}

View File

@@ -0,0 +1,23 @@
<?php
namespace Crater\Http\Controllers\V1\General;
use Crater\Http\Controllers\Controller;
use Crater\Space\TimeZones;
use Illuminate\Http\Request;
class TimezonesController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function __invoke(Request $request)
{
return response()->json([
'time_zones' => TimeZones::get_list()
]);
}
}

View File

@@ -0,0 +1,34 @@
<?php
namespace Crater\Http\Controllers\V1\Invoice;
use Illuminate\Http\Request;
use Crater\Http\Controllers\Controller;
use Crater\Models\Invoice;
class ChangeInvoiceStatusController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function __invoke(Request $request, Invoice $invoice)
{
if ($request->status == Invoice::STATUS_SENT) {
$invoice->status = Invoice::STATUS_SENT;
$invoice->sent = true;
$invoice->save();
} elseif ($request->status == Invoice::STATUS_COMPLETED) {
$invoice->status = Invoice::STATUS_COMPLETED;
$invoice->paid_status = Invoice::STATUS_PAID;
$invoice->due_amount = 0;
$invoice->save();
}
return response()->json([
'success' => true
]);
}
}

View File

@@ -0,0 +1,91 @@
<?php
namespace Crater\Http\Controllers\V1\Invoice;
use Illuminate\Http\Request;
use Crater\Http\Controllers\Controller;
use Crater\Models\Invoice;
use Carbon\Carbon;
use Crater\Models\CompanySetting;
class CloneInvoiceController extends Controller
{
/**
* Mail a specific invoice to the corresponding customer's email address.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function __invoke(Request $request, Invoice $invoice)
{
$date = Carbon::now();
$invoice_prefix = CompanySetting::getSetting(
'invoice_prefix',
$request->header('company')
);
$newInvoice = Invoice::create([
'invoice_date' => $date->format('Y-m-d'),
'due_date' => $date->format('Y-m-d'),
'invoice_number' => $invoice_prefix . "-" . Invoice::getNextInvoiceNumber($invoice_prefix),
'reference_number' => $invoice->reference_number,
'user_id' => $invoice->user_id,
'company_id' => $request->header('company'),
'invoice_template_id' => 1,
'status' => Invoice::STATUS_DRAFT,
'paid_status' => Invoice::STATUS_UNPAID,
'sub_total' => $invoice->sub_total,
'discount' => $invoice->discount,
'discount_type' => $invoice->discount_type,
'discount_val' => $invoice->discount_val,
'total' => $invoice->total,
'due_amount' => $invoice->total,
'tax_per_item' => $invoice->tax_per_item,
'discount_per_item' => $invoice->discount_per_item,
'tax' => $invoice->tax,
'notes' => $invoice->notes,
'unique_hash' => str_random(60)
]);
$invoice->load('items.taxes');
$invoiceItems = $invoice->items->toArray();
foreach ($invoiceItems as $invoiceItem) {
$invoiceItem['company_id'] = $request->header('company');
$invoiceItem['name'] = $invoiceItem['name'];
$item = $newInvoice->items()->create($invoiceItem);
if (array_key_exists('taxes', $invoiceItem) && $invoiceItem['taxes']) {
foreach ($invoiceItem['taxes'] as $tax) {
$tax['company_id'] = $request->header('company');
if ($tax['amount']) {
$item->taxes()->create($tax);
}
}
}
}
if ($invoice->taxes) {
foreach ($invoice->taxes->toArray() as $tax) {
$tax['company_id'] = $request->header('company');
$newInvoice->taxes()->create($tax);
}
}
$newInvoice = Invoice::with([
'items',
'user',
'invoiceTemplate',
'taxes'
])
->find($newInvoice->id);
return response()->json([
'invoice' => $newInvoice,
'success' => true
]);
}
}

View File

@@ -0,0 +1,20 @@
<?php
namespace Crater\Http\Controllers\V1\Invoice;
use Crater\Http\Controllers\Controller;
use Crater\Models\Invoice;
class InvoicePdfController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function __invoke(Invoice $invoice)
{
return $invoice->getGeneratedPDFOrStream('invoice');
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace Crater\Http\Controllers\V1\Invoice;
use Crater\Http\Controllers\Controller;
use Crater\Models\InvoiceTemplate;
use Illuminate\Http\Request;
class InvoiceTemplatesController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function __invoke(Request $request)
{
$invoiceTemplates = InvoiceTemplate::all();
return response()->json([
'invoiceTemplates' => $invoiceTemplates
]);
}
}

View File

@@ -0,0 +1,128 @@
<?php
namespace Crater\Http\Controllers\V1\Invoice;
use Illuminate\Http\Request;
use Crater\Http\Requests;
use Crater\Models\Invoice;
use Crater\Http\Controllers\Controller;
use Crater\Http\Requests\DeleteInvoiceRequest;
use Crater\Jobs\GenerateInvoicePdfJob;
class InvoicesController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\JsonResponse
*/
public function index(Request $request)
{
$limit = $request->has('limit') ? $request->limit : 10;
$invoices = Invoice::with(['items', 'user', 'creator', 'invoiceTemplate', 'taxes'])
->join('users', 'users.id', '=', 'invoices.user_id')
->applyFilters($request->only([
'status',
'paid_status',
'customer_id',
'invoice_id',
'invoice_number',
'from_date',
'to_date',
'orderByField',
'orderBy',
'search',
]))
->whereCompany($request->header('company'))
->select('invoices.*', 'users.name')
->latest()
->paginateData($limit);
return response()->json([
'invoices' => $invoices,
'invoiceTotalCount' => Invoice::count()
]);
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function store(Requests\InvoicesRequest $request)
{
$invoice = Invoice::createInvoice($request);
if ($request->has('invoiceSend')) {
$invoice->send($request->subject, $request->body);
}
GenerateInvoicePdfJob::dispatch($invoice);
return response()->json([
'invoice' => $invoice
]);
}
/**
* Display the specified resource.
*
* @param \Crater\Models\Invoice $invoice
* @return \Illuminate\Http\JsonResponse
*/
public function show(Invoice $invoice)
{
$invoice->load([
'items',
'items.taxes',
'user',
'invoiceTemplate',
'taxes.taxType',
'fields.customField'
]);
$siteData = [
'invoice' => $invoice,
'nextInvoiceNumber' => $invoice->getInvoiceNumAttribute(),
'invoicePrefix' => $invoice->getInvoicePrefixAttribute(),
];
return response()->json($siteData);
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param Invoice $invoice
* @return \Illuminate\Http\JsonResponse
*/
public function update(Requests\InvoicesRequest $request, Invoice $invoice)
{
$invoice = $invoice->updateInvoice($request);
GenerateInvoicePdfJob::dispatch($invoice, true);
return response()->json([
'invoice' => $invoice,
'success' => true
]);
}
/**
* delete the specified resources in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function delete(DeleteInvoiceRequest $request)
{
Invoice::destroy($request->ids);
return response()->json([
'success' => true
]);
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace Crater\Http\Controllers\V1\Invoice;
use Crater\Http\Controllers\Controller;
use Crater\Models\Invoice;
use Crater\Http\Requests\SendInvoiceRequest;
class SendInvoiceController extends Controller
{
/**
* Mail a specific invoice to the corresponding customer's email address.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function __invoke(SendInvoiceRequest $request, Invoice $invoice)
{
$invoice->send($request->all());
return response()->json([
'success' => true
]);
}
}

View File

@@ -0,0 +1,106 @@
<?php
namespace Crater\Http\Controllers\V1\Item;
use Crater\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Crater\Http\Requests;
use Crater\Http\Requests\DeleteItemsRequest;
use Crater\Models\Item;
use Crater\Models\TaxType;
class ItemsController extends Controller
{
/**
* Retrieve a list of existing Items.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function index(Request $request)
{
$limit = $request->has('limit') ? $request->limit : 10;
$items = Item::with(['taxes', 'creator'])
->leftJoin('units', 'units.id', '=', 'items.unit_id')
->applyFilters($request->only([
'search',
'price',
'unit_id',
'item_id',
'orderByField',
'orderBy'
]))
->whereCompany($request->header('company'))
->select('items.*', 'units.name as unit_name')
->latest()
->paginateData($limit);
return response()->json([
'items' => $items,
'taxTypes' => TaxType::latest()->get(),
'itemTotalCount' => Item::count()
]);
}
/**
* Create Item.
*
* @param Crater\Http\Requests\ItemsRequest $request
* @return \Illuminate\Http\JsonResponse
*/
public function store(Requests\ItemsRequest $request)
{
$item = Item::createItem($request);
return response()->json([
'item' => $item
]);
}
/**
* get an existing Item.
*
* @param Item $item
* @return \Illuminate\Http\JsonResponse
*/
public function show(Item $item)
{
$item->load('taxes');
return response()->json([
'item' => $item
]);
}
/**
* Update an existing Item.
*
* @param Crater\Http\Requests\ItemsRequest $request
* @param \Crater\Models\Item $item
* @return \Illuminate\Http\JsonResponse
*/
public function update(Requests\ItemsRequest $request, Item $item)
{
$item = $item->updateItem($request);
return response()->json([
'item' => $item
]);
}
/**
* Delete a list of existing Items.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function delete(DeleteItemsRequest $request)
{
Item::destroy($request->ids);
return response()->json([
'success' => true
]);
}
}

View File

@@ -0,0 +1,109 @@
<?php
namespace Crater\Http\Controllers\V1\Item;
use Crater\Models\Unit;
use Illuminate\Http\Request;
use Crater\Http\Requests\UnitRequest;
use Crater\Http\Controllers\Controller;
class UnitsController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index(Request $request)
{
$limit = $request->has('limit') ? $request->limit : 5;
$units = Unit::whereCompany($request->header('company'))
->applyFilters($request->only([
'unit_id'
]))
->latest()
->paginateData($limit);
return response()->json([
'units' => $units
]);
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(UnitRequest $request)
{
$data = $request->validated();
$data['company_id'] = $request->header('company');
$unit = Unit::create($data);
return response()->json([
'unit' => $unit
]);
}
/**
* Display the specified resource.
*
* @param \Crater\Models\Unit $unit
* @return \Illuminate\Http\Response
*/
public function show(Unit $unit)
{
return response()->json([
'unit' => $unit
]);
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param \Crater\Models\Unit $unit
* @return \Illuminate\Http\Response
*/
public function update(UnitRequest $request, Unit $unit)
{
$unit->update($request->validated());
return response()->json([
'unit' => $unit
]);
}
/**
* Remove the specified resource from storage.
*
* @param \Crater\Models\Unit $unit
* @return \Illuminate\Http\Response
*/
public function destroy(Unit $unit)
{
if ($unit->items()->exists()) {
return response()->json([
'error' => 'items_attached'
]);
}
$unit->delete();
return response()->json([
'success' => 'Unit deleted successfully'
]);
}
}

View File

@@ -0,0 +1,43 @@
<?php
namespace Crater\Http\Controllers\V1\Mobile;
use Crater\Http\Controllers\Controller;
use Crater\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\ValidationException;
class AuthController extends Controller
{
public function login(Request $request)
{
$request->validate([
'username' => 'required|email',
'password' => 'required',
'device_name' => 'required',
]);
$user = User::where('email', $request->username)->first();
if (! $user || ! Hash::check($request->password, $user->password)) {
throw ValidationException::withMessages([
'email' => ['The provided credentials are incorrect.'],
]);
}
return response()->json([
'type' => 'Bearer',
'token' => $user->createToken($request->device_name)->plainTextToken
]);
}
public function logout(Request $request)
{
$request->user()->currentAccessToken()->delete();
return response()->json([
'success' => true
]);
}
}

View File

@@ -0,0 +1,46 @@
<?php
namespace Crater\Http\Controllers\V1\Mobile\Customer;
use Barryvdh\DomPDF\PDF;
use Crater\Models\Company;
use Crater\Models\CompanySetting;
use Crater\Models\Estimate;
use Crater\Models\EstimateTemplate;
use Crater\Http\Controllers\Controller;
use Crater\Mail\EstimateViewedMail;
use Crater\Models\User;
class EstimatePdfController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function __invoke(Estimate $estimate)
{
if ($estimate && ($estimate->status == Estimate::STATUS_SENT || $estimate->status == Estimate::STATUS_DRAFT)) {
$estimate->status = Estimate::STATUS_VIEWED;
$estimate->save();
$notifyEstimateViewed = CompanySetting::getSetting(
'notify_estimate_viewed',
$estimate->company_id
);
if ($notifyEstimateViewed == 'YES') {
$data['estimate'] = Estimate::findOrFail($estimate->id)->toArray();
$data['user'] = User::find($estimate->user_id)->toArray();
$notificationEmail = CompanySetting::getSetting(
'notification_email',
$estimate->company_id
);
\Mail::to($notificationEmail)->send(new EstimateViewedMail($data));
}
}
return $estimate->getGeneratedPDFOrStream('estimate');
}
}

View File

@@ -0,0 +1,47 @@
<?php
namespace Crater\Http\Controllers\V1\Mobile\Customer;
use Barryvdh\DomPDF\PDF;
use Crater\Models\Company;
use Crater\Models\CompanySetting;
use Crater\Http\Controllers\Controller;
use Crater\Models\Invoice;
use Crater\Models\InvoiceTemplate;
use Crater\Mail\InvoiceViewedMail;
use Crater\Models\User;
class InvoicePdfController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function __invoke(Invoice $invoice)
{
if ($invoice && ($invoice->status == Invoice::STATUS_SENT || $invoice->status == Invoice::STATUS_DRAFT)) {
$invoice->status = Invoice::STATUS_VIEWED;
$invoice->viewed = true;
$invoice->save();
$notifyInvoiceViewed = CompanySetting::getSetting(
'notify_invoice_viewed',
$invoice->company_id
);
if ($notifyInvoiceViewed == 'YES') {
$data['invoice'] = Invoice::findOrFail($invoice->id)->toArray();
$data['user'] = User::find($invoice->user_id)->toArray();
$notificationEmail = CompanySetting::getSetting(
'notification_email',
$invoice->company_id
);
\Mail::to($notificationEmail)->send(new InvoiceViewedMail($data));
}
}
return $invoice->getGeneratedPDFOrStream('invoice');
}
}

View File

@@ -0,0 +1,91 @@
<?php
namespace Crater\Http\Controllers\V1\Onboarding;
use Crater\Http\Controllers\Controller;
use Crater\Space\EnvironmentManager;
use Crater\Http\Requests\DatabaseEnvironmentRequest;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Http\Request;
class DatabaseConfigurationController extends Controller
{
/**
* @var EnvironmentManager
*/
protected $EnvironmentManager;
/**
* @param EnvironmentManager $environmentManager
*/
public function __construct(EnvironmentManager $environmentManager)
{
$this->environmentManager = $environmentManager;
}
/**
*
* @param DatabaseEnvironmentRequest $request
*/
public function saveDatabaseEnvironment(DatabaseEnvironmentRequest $request)
{
Artisan::call('config:clear');
Artisan::call('cache:clear');
$results = $this->environmentManager->saveDatabaseVariables($request);
if (array_key_exists("success", $results)) {
Artisan::call('key:generate --force');
Artisan::call('config:clear');
Artisan::call('cache:clear');
Artisan::call('storage:link');
Artisan::call('migrate --seed --force');
}
return response()->json($results);
}
public function getDatabaseEnvironment(Request $request)
{
$databaseData = [];
switch ($request->connection) {
case 'sqlite':
$databaseData = [
'database_connection' => 'sqlite',
'database_name' => database_path('database.sqlite'),
];
break;
case 'pgsql':
$databaseData = [
'database_connection' => 'pgsql',
'database_host' => '127.0.0.1',
'database_port' => 5432,
];
break;
case 'mysql':
$databaseData = [
'database_connection' => 'mysql',
'database_host' => '127.0.0.1',
'database_port' => 3306,
];
break;
case 'sqlsrv':
$databaseData = [
'driver' => 'sqlsrv',
'host' => '127.0.0.1',
'port' => 1433,
];
break;
}
return response()->json([
'config' => $databaseData,
'success' => true
]);
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace Crater\Http\Controllers\V1\Onboarding;
use Crater\Http\Controllers\Controller;
use Crater\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class FinishController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function __invoke(Request $request)
{
\Storage::disk('local')->put('database_created', 'database_created');
$user = User::where('role', 'super admin')->first();
Auth::login($user);
}
}

View File

@@ -0,0 +1,47 @@
<?php
namespace Crater\Http\Controllers\V1\Onboarding;
use Crater\Http\Controllers\Controller;
use Crater\Models\Setting;
use Illuminate\Http\Request;
class OnboardingWizardController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function getStep(Request $request)
{
if (!\Storage::disk('local')->has('database_created')) {
return response()->json([
'profile_complete' => 0
]);
}
return response()->json([
'profile_complete' => Setting::getSetting('profile_complete')
]);
}
public function updateStep(Request $request)
{
$setting = Setting::getSetting('profile_complete');
if ($setting === 'COMPLETED') {
return response()->json([
'profile_complete' => $setting
]);
}
Setting::setSetting('profile_complete', $request->profile_complete);
return response()->json([
'profile_complete' => Setting::getSetting('profile_complete')
]);
}
}

View File

@@ -1,9 +1,10 @@
<?php
namespace Crater\Http\Controllers;
namespace Crater\Http\Controllers\V1\Onboarding;
use Crater\Space\PermissionsChecker;
use Illuminate\Http\JsonResponse;
use Crater\Http\Controllers\Controller;
class PermissionsController extends Controller
{

View File

@@ -1,9 +1,10 @@
<?php
namespace Crater\Http\Controllers;
namespace Crater\Http\Controllers\V1\Onboarding;
use Crater\Space\RequirementsChecker;
use Illuminate\Http\JsonResponse;
use Crater\Http\Controllers\Controller;
class RequirementsController extends Controller
{

View File

@@ -0,0 +1,100 @@
<?php
namespace Crater\Http\Controllers\V1\Payment;
use Crater\Models\PaymentMethod;
use Illuminate\Http\Request;
use Crater\Http\Requests\PaymentMethodRequest;
use Crater\Http\Controllers\Controller;
class PaymentMethodsController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index(Request $request)
{
$limit = $request->has('limit') ? $request->limit : 5;
$paymentMethods = PaymentMethod::whereCompany($request->header('company'))
->applyFilters($request->only([
'method_id',
'search'
]))
->latest()
->paginateData($limit);
return response()->json([
'paymentMethods' => $paymentMethods
]);
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(PaymentMethodRequest $request)
{
$paymentMethod = PaymentMethod::createPaymentMethod($request);
return response()->json([
'paymentMethod' => $paymentMethod
]);
}
/**
* Display the specified resource.
*
* @param \Crater\Models\PaymentMethod $paymentMethod
* @return \Illuminate\Http\Response
*/
public function show(PaymentMethod $paymentMethod)
{
return response()->json([
'paymentMethod' => $paymentMethod
]);
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param \Crater\Models\PaymentMethod $paymentMethod
* @return \Illuminate\Http\Response
*/
public function update(PaymentMethodRequest $request, PaymentMethod $paymentMethod)
{
$paymentMethod->update($request->validated());
return response()->json([
'paymentMethod' => $paymentMethod
]);
}
/**
* Remove the specified resource from storage.
*
* @param \Crater\Models\PaymentMethod $paymentMethod
* @return \Illuminate\Http\Response
*/
public function destroy(PaymentMethod $paymentMethod)
{
$payments = $paymentMethod->payments;
if ($payments->count() > 0) {
return response()->json([
'error' => 'payments_attached'
]);
}
$paymentMethod->delete();
return response()->json([
'success' => 'Payment method deleted successfully'
]);
}
}

View File

@@ -0,0 +1,20 @@
<?php
namespace Crater\Http\Controllers\V1\Payment;
use Crater\Http\Controllers\Controller;
use Crater\Models\Payment;
class PaymentPdfController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function __invoke(Payment $payment)
{
return $payment->getGeneratedPDFOrStream('payment');
}
}

View File

@@ -0,0 +1,96 @@
<?php
namespace Crater\Http\Controllers\V1\Payment;
use Illuminate\Http\Request;
use Crater\Models\Payment;
use Crater\Http\Requests\DeletePaymentsRequest;
use Crater\Http\Requests\PaymentRequest;
use Crater\Http\Controllers\Controller;
class PaymentsController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index(Request $request)
{
$limit = $request->has('limit') ? $request->limit : 10;
$payments = Payment::with(['user', 'invoice', 'paymentMethod', 'creator'])
->join('users', 'users.id', '=', 'payments.user_id')
->leftJoin('invoices', 'invoices.id', '=', 'payments.invoice_id')
->leftJoin('payment_methods', 'payment_methods.id', '=', 'payments.payment_method_id')
->applyFilters($request->only([
'search',
'payment_number',
'payment_id',
'payment_method_id',
'customer_id',
'orderByField',
'orderBy'
]))
->whereCompany($request->header('company'))
->select('payments.*', 'users.name', 'invoices.invoice_number', 'payment_methods.name as payment_mode')
->latest()
->paginateData($limit);
return response()->json([
'payments' => $payments,
'paymentTotalCount' => Payment::count()
]);
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(PaymentRequest $request)
{
$payment = Payment::createPayment($request);
return response()->json([
'payment' => $payment,
'success' => true
]);
}
public function show(Request $request, Payment $payment)
{
$payment->load([
'user',
'invoice',
'paymentMethod',
'fields.customField'
]);
return response()->json([
'nextPaymentNumber' => $payment->getPaymentNumAttribute(),
'payment_prefix' => $payment->getPaymentPrefixAttribute(),
'payment' => $payment,
]);
}
public function update(PaymentRequest $request, Payment $payment)
{
$payment = $payment->updatePayment($request);
return response()->json([
'payment' => $payment,
'success' => true
]);
}
public function delete(DeletePaymentsRequest $request)
{
Payment::deletePayments($request->ids);
return response()->json([
'success' => true
]);
}
}

View File

@@ -0,0 +1,23 @@
<?php
namespace Crater\Http\Controllers\V1\Payment;
use Crater\Http\Controllers\Controller;
use Crater\Models\Payment;
use Crater\Http\Requests\SendPaymentRequest;
class SendPaymentController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function __invoke(SendPaymentRequest $request, Payment $payment)
{
$response = $payment->send($request->all());
return response()->json($response);
}
}

View File

@@ -0,0 +1,92 @@
<?php
namespace Crater\Http\Controllers\V1\Report;
use Illuminate\Support\Facades\App;
use Illuminate\Http\Request;
use Crater\Models\Company;
use PDF;
use Carbon\Carbon;
use Crater\Models\User;
use Crater\Models\CompanySetting;
use Crater\Http\Controllers\Controller;
class CustomerSalesReportController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @param string $hash
* @return \Illuminate\Http\JsonResponse
*/
public function __invoke(Request $request, $hash)
{
$company = Company::where('unique_hash', $hash)->first();
$locale = CompanySetting::getSetting('language', $company->id);
App::setLocale($locale);
$start = Carbon::createFromFormat('Y-m-d', $request->from_date);
$end = Carbon::createFromFormat('Y-m-d', $request->to_date);
$customers = User::with(['invoices' => function ($query) use ($start, $end) {
$query->whereBetween(
'invoice_date',
[$start->format('Y-m-d'), $end->format('Y-m-d')]
);
}])
->customer()
->whereCompany($company->id)
->applyInvoiceFilters($request->only(['from_date', 'to_date']))
->get();
$totalAmount = 0;
foreach ($customers as $customer) {
$customerTotalAmount = 0;
foreach ($customer->invoices as $invoice) {
$customerTotalAmount += $invoice->total;
}
$customer->totalAmount = $customerTotalAmount;
$totalAmount += $customerTotalAmount;
}
$dateFormat = CompanySetting::getSetting('carbon_date_format', $company->id);
$from_date = Carbon::createFromFormat('Y-m-d', $request->from_date)->format($dateFormat);
$to_date = Carbon::createFromFormat('Y-m-d', $request->to_date)->format($dateFormat);
$colors = [
'primary_text_color',
'heading_text_color',
'section_heading_text_color',
'border_color',
'body_text_color',
'footer_text_color',
'footer_total_color',
'footer_bg_color',
'date_text_color'
];
$colorSettings = CompanySetting::whereIn('option', $colors)
->whereCompany($company->id)
->get();
view()->share([
'customers' => $customers,
'totalAmount' => $totalAmount,
'colorSettings' => $colorSettings,
'company' => $company,
'from_date' => $from_date,
'to_date' => $to_date
]);
$pdf = PDF::loadView('app.pdf.reports.sales-customers');
if ($request->has('download')) {
return $pdf->download();
}
return $pdf->stream();
}
}

View File

@@ -0,0 +1,77 @@
<?php
namespace Crater\Http\Controllers\V1\Report;
use Illuminate\Http\Request;
use Crater\Models\Company;
use PDF;
use Carbon\Carbon;
use Crater\Models\Expense;
use Crater\Models\CompanySetting;
use Crater\Http\Controllers\Controller;
use Illuminate\Support\Facades\App;
class ExpensesReportController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @param string $hash
* @return \Illuminate\Http\JsonResponse
*/
public function __invoke(Request $request, $hash)
{
$company = Company::where('unique_hash', $hash)->first();
$locale = CompanySetting::getSetting('language', $company->id);
App::setLocale($locale);
$expenseCategories = Expense::with('category')
->whereCompany($company->id)
->applyFilters($request->only(['from_date', 'to_date']))
->expensesAttributes()
->get();
$totalAmount = 0;
foreach ($expenseCategories as $category) {
$totalAmount += $category->total_amount;
}
$dateFormat = CompanySetting::getSetting('carbon_date_format', $company->id);
$from_date = Carbon::createFromFormat('Y-m-d', $request->from_date)->format($dateFormat);
$to_date = Carbon::createFromFormat('Y-m-d', $request->to_date)->format($dateFormat);
$colors = [
'primary_text_color',
'heading_text_color',
'section_heading_text_color',
'border_color',
'body_text_color',
'footer_text_color',
'footer_total_color',
'footer_bg_color',
'date_text_color'
];
$colorSettings = CompanySetting::whereIn('option', $colors)
->whereCompany($company->id)
->get();
view()->share([
'expenseCategories' => $expenseCategories,
'colorSettings' => $colorSettings,
'totalExpense' => $totalAmount,
'company' => $company,
'from_date' => $from_date,
'to_date' => $to_date
]);
$pdf = PDF::loadView('app.pdf.reports.expenses');
if ($request->has('download')) {
return $pdf->download();
}
return $pdf->stream();
}
}

View File

@@ -0,0 +1,76 @@
<?php
namespace Crater\Http\Controllers\V1\Report;
use Illuminate\Http\Request;
use Crater\Models\Company;
use PDF;
use Carbon\Carbon;
use Crater\Models\InvoiceItem;
use Crater\Models\CompanySetting;
use Crater\Http\Controllers\Controller;
use Illuminate\Support\Facades\App;
class ItemSalesReportController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @param string $hash
* @return \Illuminate\Http\JsonResponse
*/
public function __invoke(Request $request, $hash)
{
$company = Company::where('unique_hash', $hash)->first();
$locale = CompanySetting::getSetting('language', $company->id);
App::setLocale($locale);
$items = InvoiceItem::whereCompany($company->id)
->applyInvoiceFilters($request->only(['from_date', 'to_date']))
->itemAttributes()
->get();
$totalAmount = 0;
foreach ($items as $item) {
$totalAmount += $item->total_amount;
}
$dateFormat = CompanySetting::getSetting('carbon_date_format', $company->id);
$from_date = Carbon::createFromFormat('Y-m-d', $request->from_date)->format($dateFormat);
$to_date = Carbon::createFromFormat('Y-m-d', $request->to_date)->format($dateFormat);
$colors = [
'primary_text_color',
'heading_text_color',
'section_heading_text_color',
'border_color',
'body_text_color',
'footer_text_color',
'footer_total_color',
'footer_bg_color',
'date_text_color'
];
$colorSettings = CompanySetting::whereIn('option', $colors)
->whereCompany($company->id)
->get();
view()->share([
'items' => $items,
'colorSettings' => $colorSettings,
'totalAmount' => $totalAmount,
'company' => $company,
'from_date' => $from_date,
'to_date' => $to_date
]);
$pdf = PDF::loadView('app.pdf.reports.sales-items');
if ($request->has('download')) {
return $pdf->download();
}
return $pdf->stream();
}
}

View File

@@ -0,0 +1,85 @@
<?php
namespace Crater\Http\Controllers\V1\Report;
use Illuminate\Http\Request;
use Crater\Models\Company;
use PDF;
use Carbon\Carbon;
use Crater\Models\Invoice;
use Crater\Models\Expense;
use Crater\Models\CompanySetting;
use Crater\Http\Controllers\Controller;
use Illuminate\Support\Facades\App;
class ProfitLossReportController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @param string $hash
* @return \Illuminate\Http\JsonResponse
*/
public function __invoke(Request $request, $hash)
{
$company = Company::where('unique_hash', $hash)->first();
$locale = CompanySetting::getSetting('language', $company->id);
App::setLocale($locale);
$invoicesAmount = Invoice::whereCompany($company->id)
->applyFilters($request->only(['from_date', 'to_date']))
->wherePaidStatus(Invoice::STATUS_PAID)
->sum('total');
$expenseCategories = Expense::with('category')
->whereCompany($company->id)
->applyFilters($request->only(['from_date', 'to_date']))
->expensesAttributes()
->get();
$totalAmount = 0;
foreach ($expenseCategories as $category) {
$totalAmount += $category->total_amount;
}
$dateFormat = CompanySetting::getSetting('carbon_date_format', $company->id);
$from_date = Carbon::createFromFormat('Y-m-d', $request->from_date)->format($dateFormat);
$to_date = Carbon::createFromFormat('Y-m-d', $request->to_date)->format($dateFormat);
$colors = [
'primary_text_color',
'heading_text_color',
'section_heading_text_color',
'border_color',
'body_text_color',
'footer_text_color',
'footer_total_color',
'footer_bg_color',
'date_text_color'
];
$colorSettings = CompanySetting::whereIn('option', $colors)
->whereCompany($company->id)
->get();
view()->share([
'company' => $company,
'income' => $invoicesAmount,
'expenseCategories' => $expenseCategories,
'totalExpense' => $totalAmount,
'colorSettings' => $colorSettings,
'company' => $company,
'from_date' => $from_date,
'to_date' => $to_date
]);
$pdf = PDF::loadView('app.pdf.reports.profit-loss');
if ($request->has('download')) {
return $pdf->download();
}
return $pdf->stream();
}
}

View File

@@ -0,0 +1,79 @@
<?php
namespace Crater\Http\Controllers\V1\Report;
use Illuminate\Http\Request;
use Crater\Models\Company;
use PDF;
use Carbon\Carbon;
use Crater\Models\Tax;
use Crater\Models\CompanySetting;
use Crater\Http\Controllers\Controller;
use Illuminate\Support\Facades\App;
class TaxSummaryReportController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @param string $hash
* @return \Illuminate\Http\JsonResponse
*/
public function __invoke(Request $request, $hash)
{
$company = Company::where('unique_hash', $hash)->first();
$locale = CompanySetting::getSetting('language', $company->id);
App::setLocale($locale);
$taxTypes = Tax::with('taxType', 'invoice', 'invoiceItem')
->whereCompany($company->id)
->whereInvoicesFilters($request->only(['from_date', 'to_date']))
->taxAttributes()
->get();
$totalAmount = 0;
foreach ($taxTypes as $taxType) {
$totalAmount += $taxType->total_tax_amount;
}
$dateFormat = CompanySetting::getSetting('carbon_date_format', $company->id);
$from_date = Carbon::createFromFormat('Y-m-d', $request->from_date)->format($dateFormat);
$to_date = Carbon::createFromFormat('Y-m-d', $request->to_date)->format($dateFormat);
$colors = [
'primary_text_color',
'heading_text_color',
'section_heading_text_color',
'border_color',
'body_text_color',
'footer_text_color',
'footer_total_color',
'footer_bg_color',
'date_text_color'
];
$colorSettings = CompanySetting::whereIn('option', $colors)
->whereCompany($company->id)
->get();
view()->share([
'taxTypes' => $taxTypes,
'totalTaxAmount' => $totalAmount,
'colorSettings' => $colorSettings,
'company' => $company,
'from_date' => $from_date,
'to_date' => $to_date
]);
$pdf = PDF::loadView('app.pdf.reports.tax-summary');
if ($request->has('download')) {
return $pdf->download();
}
return $pdf->stream();
}
}

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