Compare commits

..

186 Commits
3.0.0 ... 4.0.0

Author SHA1 Message Date
b6cd78ca4c update readme 2020-12-03 20:38:49 +05:30
d18116bd7d fix conflicts 2020-12-03 20:35:27 +05:30
6b30c2028b new build 400 2020-12-03 19:43:50 +05:30
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
fe8482fc71 add ability to delete file from UI 2020-12-03 17:47:16 +05:30
28217df654 add ability to delete files on update 2020-12-03 12:49:37 +05:30
3723697add restrict update if the system requirements do not match 2020-12-02 19:05:39 +05:30
b3e3839fb5 fix default seeder 2020-12-02 18:52:25 +05:30
89ee58590c build version 400 2020-12-02 17:54:08 +05:30
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
21e01bc1db remove use from EventServiceProvider 2020-12-02 12:32:13 +05:30
ed58dfaef6 remove optimized cmd 2020-12-02 12:31:16 +05:30
c2c0e2809c remove listener & add version320 migration 2020-12-02 12:23:30 +05:30
bafda5ca46 Merge branch 'master' of https://gitlab.com/mohit.panjvani/crater-web into version-230 2020-12-02 10:29:52 +05:30
a7eaf5dbe4 fix updater issue & add optimize clear cmd 2020-12-02 10:29:46 +05:30
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
61fe16cab4 new build for version230 2020-12-01 12:09:46 +05:30
33085a0e3c add v-html for description 2020-12-01 12:08:24 +05:30
2df09a20f1 fix updater issue and run production 2020-12-01 11:05:45 +05:30
a7d61b802d hideupdate button for version 4.0.0 2020-12-01 11:02:32 +05:30
88bcb1c2b4 add listener to provider 2020-11-09 17:45:05 +05:30
af194c1851 add 320 listener 2020-11-09 13:31:30 +05:30
71193727c9 new build 2020-11-09 13:20:35 +05:30
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
e379e13802 fix update validation toaster 2020-11-06 19:09:17 +05:30
4484765358 add version check validation 2020-11-05 19:02:55 +05:30
5d4ea2a308 transfer code from update controller to updater class 2020-11-03 12:19:51 +05:30
0db9f9df0c get current virsions of php and extensions 2020-10-30 16:57:39 +05:30
9301e67e3f build public files 2020-09-10 13:39:26 +05:30
a019403b1b Merge pull request #262 from Xoshbin/patch-1
Added Iraqi Dinar in currencies table
2020-09-03 14:26:25 +05:30
c99d7ee677 Added Iraqi Dinar in currencies table 2020-09-02 22:17:29 +03:00
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
73bd28aeb8 Add missing key resend_invoice in the spanish 2020-08-04 18:24:42 -05:00
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
4372195547 Add copy_pdf_url missing key in spanish 2020-08-04 06:39:55 -05:00
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
4770c27d7d Merge pull request #244 from azaricstefan/master
Serbian language support
2020-07-27 11:55:43 +05:30
f4baf308a4 merge 2020-07-26 23:15:43 +02:00
6f852ab88a merge 2020-07-26 23:11:06 +02:00
14bb6edec8 Serbian language support (latin) made better 2020-07-26 23:09:19 +02:00
b4a7c724db Serbian language support (latin) made better 2020-07-26 23:07:49 +02:00
9fb4b4dec5 Merge pull request #239 from Loosie94/master
Improved Dutch translation
2020-07-04 14:02:32 +05:30
4bbc92ccaf Merge branch 'master' of https://github.com/bytefury/crater 2020-07-01 10:44:44 +05:30
dd12662b17 change 2020-06-25 20:23:38 +02:00
c364de1b17 Cap case 2020-06-25 19:09:41 +02:00
a06e8e3039 Link 2020-06-24 00:15:56 +02:00
b9021cb664 confirm_delete 2020-06-23 23:56:38 +02:00
a2c3fa2cc5 clone string 2020-06-23 22:56:24 +02:00
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
29b4b92fab Better 2020-06-22 21:07:58 +02:00
e8f046f02e refactor factories 2020-06-22 17:07:35 +05:30
2bf6778c8a better intro 2020-06-22 12:47:16 +02:00
e11c713ce3 Typo 2020-06-22 12:19:04 +02:00
b7189595bd Merge pull request #232 from Loosie94/master
Improved Dutch version
2020-06-22 14:46:42 +05:30
c5d4a62930 Last improvements 2020-06-21 13:25:58 +02:00
378f216f6d More Dutch improvements 2020-06-21 11:58:29 +02:00
7654c30b1b Few typo's 2020-06-21 11:41:40 +02:00
f4767ffb26 json file 2020-06-20 20:35:15 +02:00
e06639daa5 Improved Dutch version 3.1.1 2020-06-20 20:29:16 +02:00
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
60f5d29570 Serbian language support (latin) made better 2020-06-12 01:11:30 +02:00
b2497e5f81 Serbian language support (latin) made better 2020-06-12 00:25:42 +02:00
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
a964f1d841 Serbian language support (latin) made better 2020-06-08 22:24:06 +02:00
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
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
5fb6797577 revert docker-compose 8080 port 2020-06-08 02:44:29 +02:00
3d0f77ab0b Added Serbian translation. Živela Srbija! 2020-06-08 02:43:33 +02:00
dbc249b6bc Added Serbian Latin translation. Živela Srbija! 2020-06-08 02:22:45 +02:00
08c6218440 Modify php and nginx to change upload file size 2020-06-06 16:16:19 -04:00
737c933b8c give the option to persist the database to the host 2020-06-06 15:44:05 -04:00
b9ab87a308 refactor due status 2020-06-03 17:45:35 +05:30
2e5cb58c39 build 311 2020-06-01 16:11:29 +05:30
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
09bbf98e61 Merge branch 'master' into refactor-new-issues 2020-05-30 21:36:49 +05:30
ca90ff2767 Merge branch 'master' 2020-05-30 21:10:43 +05:30
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
251648f53c fix email layout on mobile 2020-05-30 20:30:09 +05:30
ffa5b6b2ad refactor checkValidUrl method 2020-05-28 21:02:11 +05:30
bd9beaa343 Merge master branch 2020-05-28 19:34:47 +05:30
3e4decdfb9 update nginx port 2020-05-27 20:56:54 +05:30
165907d144 fix docker errors 2020-05-27 16:01:37 +05:30
6278417423 refactor docker setup 2020-05-27 14:18:29 +05:30
dc37f565c4 add credit to akaunting 2020-05-21 15:01:47 +05:30
532196a9b4 Merge branch 'master' of https://github.com/bytefury/crater 2020-05-21 14:53:42 +05:30
6a4009e13a add credit to akaunting 2020-05-21 14:53:27 +05:30
a8f98e51bb Update readme 2020-05-21 14:31:30 +05:30
2b03bc798e new build 310 2020-05-21 11:26:26 +05:30
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
deb525af6e build 310 2020-05-19 13:22:33 +05:30
cb2bfbb91c Add steps for update app 2020-05-19 07:50:58 +00:00
654395a175 Add steps for update app 2020-05-19 07:50:58 +00:00
e31b60bc48 Refactor Self Update Endpoints and Add Update Console Command 2020-05-17 07:04:43 +00:00
183953f4c4 Refactor Self Update Endpoints and Add Update Console Command 2020-05-17 07:04:43 +00:00
98d15143c2 refactor language problem 2020-05-13 21:16:37 +05:30
a24d8d3ebc fix updater issue 2020-05-13 16:50:45 +05:30
4ca574c581 fix migration errors 2020-05-13 12:47:06 +05:30
c7ce8c87dd new build 2020-05-13 11:31:37 +05:30
f64d546672 refactor 310 update listener 2020-05-13 11:12:33 +05:30
96187870b4 refactoe issues 2020-05-12 21:11:36 +05:30
d4a1f1a784 fix item selection and item loader 2020-05-12 13:23:06 +05:30
e07532961e reset items on selection 2020-05-12 13:11:29 +05:30
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
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
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
e7675f938e refactor estimate to invoice endpoint 2020-05-11 19:05:50 +05:30
b08138e9e0 refactor estimate to invoice endpoint 2020-05-11 18:34:20 +05:30
5df4abdc4b add aws-sdk-php package 2020-05-11 18:15:36 +05:30
a2fa8afa72 fix translation issue 2020-05-11 18:09:34 +05:30
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
8446ac2b27 refactor invoice2 2020-05-11 16:19:02 +05:30
63a80e44d5 Customer delete label 2020-05-11 14:33:11 +05:30
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
11db99da73 refactor invoice 1 style 2020-05-09 18:50:58 +05:30
050dca5a50 Add copy pdf url option 2020-05-09 14:37:22 +05:30
3c096f1386 Add Resend Email Option 2020-05-09 14:22:13 +05:30
0f3e8fce3b refactor heading text in payment 2020-05-08 20:55:00 +05:30
325f90bba5 Fix issues on invoice template 2020-05-08 18:49:02 +05:30
a739a938fc Fix estimate template issues 2020-05-08 16:52:48 +05:30
b30e3a9b11 merge with github 2020-05-08 11:11:57 +05:30
fc1a7c7438 refactor reports pdfs 2020-05-07 18:59:50 +05:30
6046113cb1 Refactor Invoice and Payment templates 2020-05-07 16:42:04 +05:30
611ffafec5 refactor sales customers pdf 2020-05-06 20:41:15 +05:30
c497b906df refactor taxt report pdf 2020-05-06 20:32:10 +05:30
c68fce19f9 refactor expenses pdf 2020-05-06 19:02:02 +05:30
f8913531b6 refactor profit loss pdfs 2020-05-06 18:09:28 +05:30
30f76e2088 Refactor Estimate templates 2020-05-06 18:02:27 +05:30
39556892cd refactor sales customers 2020-05-05 20:58:20 +05:30
2fd66bf748 refactor sales items and customer pdfs 2020-05-05 20:49:51 +05:30
d4f1428d5f refactor sales customers pdf template 2020-05-05 20:03:51 +05:30
189141c84d Refactor estimate pdf template 2020-05-05 18:21:25 +05:30
f8ccfece09 update templates 2020-05-05 13:12:26 +05:30
9a7c926d53 fix 310 update issues 2020-05-02 18:53:51 +05:30
c5c1674153 Merge branch 'master' 2020-05-02 13:37:36 +05:30
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
06c66a756c Payments and UnitItems in doubles issue fixed... 2020-04-27 18:54:24 +05:30
b66d07d21b Merge pull request #201 from rexlManu/master
Updated German Language
2020-04-27 12:14:23 +05:30
05001b6a79 Merge pull request #170 from RobinDev/patch-1
Update french language
2020-04-21 14:52:02 +05:30
f02f4ba9d3 Updated German Language 2020-04-21 07:31:33 +02:00
fbace98aac add missing translation 2020-04-20 21:12:03 +02:00
8f0af3dcd6 Merge branch 'master' of https://github.com/bytefury/crater 2020-04-20 11:23:00 +05:30
e8e44c5dc8 Merge pull request #180 from alessandrofuda/master
IT Italian translation
2020-04-18 13:38:21 +05:30
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
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
7ca725ac37 refactor line-chart 2020-04-17 19:53:08 +05:30
510a4b3dbb add listener 310 2020-04-17 19:05:10 +05:30
0f130ab1b8 Update fr langugage 2020-04-17 09:57:38 +02:00
25114009e3 remove unused components and update eslint + prettier config 2020-03-30 11:40:45 +05:30
79c16d74ce IT Italian translation 2020-03-20 18:18:27 +01:00
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
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
82d85af672 refactor and merge backend 2020-03-18 18:21:53 +05:30
4d1b267688 Merge branch 'expense-refactor' of https://gitlab.com/mohit.panjvani/crater-web into expense-refactor 2020-03-18 17:41:15 +05:30
bc99ad63a6 add user to expense 2020-03-18 17:40:03 +05:30
4bb44f8c93 add customer filter on index 2020-03-18 17:19:09 +05:30
c72265ed50 add languages 2020-03-17 19:38:59 +05:30
b8958c9eb6 add customer in expense 2020-03-17 19:20:42 +05:30
e33e314cb7 new frontend build 2020-03-09 15:20:59 +05:30
84cebee9da Merge branch 'master' of https://github.com/bytefury/crater 2020-03-09 15:19:54 +05:30
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
93d0da836a Merge pull request #172 from digitalsign/master
Change project name in composer.json
2020-02-26 14:35:21 +05:30
fd51276948 Change project name in composer.json 2020-02-26 13:31:57 +08:00
d6274854ba refactor search problem 2020-02-19 19:10:43 +05:30
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
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
be16f48f3d Merge pull request #153 from MakerLab-Dev/patch-3
Improved error handling
2020-02-09 12:00:23 +05:30
ebea1e0813 add new minor version update 3.0.1 2020-02-07 17:20:32 +05:30
cc8d08f829 Merge pull request #142 from miraro3/master
Added Kyrgyzstani som
2020-02-07 16:42:15 +05:30
aacffc22eb fix merge conflict 2020-02-03 21:15:07 +05:30
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
186004f7f8 fix merge conflicts 2020-01-31 14:28:16 +05:30
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
af189b15b6 Small fix 2020-01-30 20:48:16 +01:00
1c19be85c3 Improved error handling 2020-01-30 20:47:51 +01:00
4bb4362d23 Removed unnecessary notification
Removed unnecessary notification as the improved error handler will show it
2020-01-30 20:45:39 +01:00
f6f66b3ae6 Merge pull request #152 from mdpoulter/email-subject
More descriptive email fields.
2020-01-31 00:21:29 +05:30
b4ccecbcf1 Merge pull request #149 from proea/master
Fix for "Empty PDF rendered in Docker #69"
2020-01-31 00:11:51 +05:30
92f1f196bb Update Dockerfile 2020-01-27 22:38:47 +03:00
ee14070a7b Update Dockerfile
slight change
2020-01-27 22:37:41 +03:00
8ce7e14a02 Add name in From field. 2020-01-27 20:37:25 +02:00
3401ca049e Make viewed emails more descriptive. 2020-01-27 14:47:02 +02:00
5dcc7b9efd Add more descriptive subject lines. 2020-01-27 14:45:40 +02:00
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
f68e86e4cf Added Kyrgyzstani som 2020-01-20 22:37:03 +01:00
0990ce4678 cross-env should only be in devDependencies 2020-01-18 16:29:48 +01:00
353c2479f1 Detect if no .env file exists and add it on composer commands. 2020-01-06 10:55:34 -07:00
991 changed files with 77784 additions and 56015 deletions

View File

@ -13,8 +13,9 @@ DB_PASSWORD="crater"
BROADCAST_DRIVER=log BROADCAST_DRIVER=log
CACHE_DRIVER=file CACHE_DRIVER=file
SESSION_DRIVER=file
QUEUE_DRIVER=sync QUEUE_DRIVER=sync
SESSION_DRIVER=cookie
SESSION_LIFETIME=1440
REDIS_HOST=127.0.0.1 REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null REDIS_PASSWORD=null
@ -31,6 +32,5 @@ PUSHER_APP_ID=
PUSHER_KEY= PUSHER_KEY=
PUSHER_SECRET= PUSHER_SECRET=
PROXY_OAUTH_CLIENT_ID=2 SANCTUM_STATEFUL_DOMAINS=crater.test
PROXY_OAUTH_CLIENT_SECRET=SECRET-GENERATED-KEY-HERE SESSION_DOMAIN=crater.test
PROXY_OAUTH_GRANT_TYPE=password

View File

@ -2,3 +2,12 @@ APP_ENV=testing
APP_DEBUG=true APP_DEBUG=true
APP_KEY=base64:IdDlpLmYyWA9z4Ruj5st1FSYrhCR7lPOscLGCz2Jf4I= APP_KEY=base64:IdDlpLmYyWA9z4Ruj5st1FSYrhCR7lPOscLGCz2Jf4I=
DB_CONNECTION=sqlite 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

@ -2,9 +2,20 @@
"root": true, "root": true,
"extends": [ "extends": [
"plugin:vue/recommended", "plugin:vue/recommended",
"standard" "eslint:recommended",
"prettier/vue",
"plugin:prettier/recommended"
], ],
"rules": { "rules": {
"vue/max-attributes-per-line" : 3 "vue/max-attributes-per-line": [
"error",
{
"singleline": 20,
"multiline": {
"max": 1,
"allowFirstLine": false
}
}
]
} }
} }

3
.gitignore vendored
View File

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

5
.prettierrc.json Normal file
View File

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

View File

@ -1,52 +1,39 @@
##### STAGE 1 ##### FROM php:7.4-fpm
FROM composer as composer # Arguments defined in docker-compose.yml
ARG user
ARG uid
# Copy composer files from project root into composer container's working dir # Install system dependencies
COPY composer.* /app/ RUN apt-get update && apt-get install -y \
git \
curl \
libpng-dev \
libonig-dev \
libxml2-dev \
zip \
unzip \
libzip-dev \
libmagickwand-dev
# Copy database directory for autoloader optimization # Clear cache
COPY database /app/database RUN apt-get clean && rm -rf /var/lib/apt/lists/*
# Run composer to build dependencies in vendor folder RUN pecl install imagick \
RUN composer install --no-scripts --no-suggest --no-interaction --prefer-dist --optimize-autoloader && docker-php-ext-enable imagick
# Copy everything from project root into composer container's working dir # Install PHP extensions
COPY . /app RUN docker-php-ext-install pdo_mysql mbstring zip exif pcntl bcmath gd
RUN composer dump-autoload --optimize --classmap-authoritative # Get latest Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
##### STAGE 2 ##### # 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
FROM php:7.3.12-fpm-alpine # Set working directory
WORKDIR /var/www
# Use the default production configuration
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
RUN apk add --no-cache libpng-dev libxml2-dev oniguruma-dev libzip-dev && \
docker-php-ext-install bcmath ctype json gd mbstring pdo pdo_mysql tokenizer xml zip
# Set container's working dir
WORKDIR /app
# Copy everything from project root into php container's working dir
COPY . /app
# Copy vendor folder from composer container into php container
COPY --from=composer /app/vendor /app/vendor
RUN touch database/database.sqlite && \
cp .env.example .env && \
php artisan config:cache && \
php artisan passport:keys && \
php artisan key:generate && \
chown -R www-data:www-data . && \
chmod -R 755 . && \
chmod -R 775 storage/framework/ && \
chmod -R 775 storage/logs/ && \
chmod -R 775 bootstrap/cache/
EXPOSE 9000
CMD ["php-fpm", "--nodaemonize"]
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,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 Illuminate\Console\Command;
use Carbon\Carbon; use Carbon\Carbon;
use Crater\Estimate; use Crater\Models\Estimate;
class CheckEstimateStatus extends Command class CheckEstimateStatus extends Command
{ {

View File

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

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 * @var array
*/ */
protected $commands = [ protected $commands = [
Commands\ResetApp::class Commands\ResetApp::class,
Commands\UpdateCommand::class
]; ];
/** /**

View File

@ -1,237 +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' => 'integer',
'tax' => 'integer',
'sub_total' => 'integer',
'discount' => 'float',
'discount_val' => 'integer',
];
public static function getNextEstimateNumber($value)
{
// Get the last created order
$lastOrder = Estimate::where('estimate_number', 'LIKE', $value . '-%')
->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, "-", 1) + 1;
return substr($this->estimate_number, $position);
}
public function getEstimatePrefixAttribute()
{
$prefix = explode("-",$this->estimate_number)[0];
return $prefix;
}
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; 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\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class UpdateFinished class UpdateFinished
{ {

View File

@ -1,7 +1,7 @@
<?php <?php
namespace Crater\Exceptions; namespace Crater\Exceptions;
use Exception; use Throwable;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler; use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
class Handler extends 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. * This is a great spot to send exceptions to Sentry, Bugsnag, etc.
* *
* @param \Exception $exception * @param \Throwable $exception
* @return void * @return void
*/ */
public function report(Exception $exception) public function report(Throwable $exception)
{ {
parent::report($exception); parent::report($exception);
} }
@ -42,10 +42,10 @@ class Handler extends ExceptionHandler
* Render an exception into an HTTP response. * Render an exception into an HTTP response.
* *
* @param \Illuminate\Http\Request $request * @param \Illuminate\Http\Request $request
* @param \Exception $exception * @param \Throwable $exception
* @return \Illuminate\Http\Response * @return \Illuminate\Http\Response
*/ */
public function render($request, Exception $exception) public function render($request, Throwable $exception)
{ {
return parent::render($request, $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,367 +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
{
/**
* Retrive the Admin account.
* @return \Crater\User
*/
public function getAdmin()
{
return User::find(1);
}
/**
* Update the Admin profile.
* Includes name, email and (or) password
*
* @param \Crater\Http\Requests\ProfileRequest $request
* @return \Illuminate\Http\JsonResponse
*/
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
]);
}
/**
* Get Admin Account alongside the country from the addresses table and
* The company from companies table
*
* @return \Illuminate\Http\JsonResponse
*/
public function getAdminCompany()
{
$user = User::with(['addresses', 'addresses.country', 'company'])->find(1);
return response()->json([
'user' => $user
]);
}
/**
* Update Admin Company Details
* @param \Crater\Http\Requests\CompanyRequest $request
* @return \Illuminate\Http\JsonResponse
*/
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
]);
}
/**
* Retrieve General App Settings
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
*/
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"],
["code"=>"ar", "name" => "العربية"],
["code"=>"de", "name" => "German"],
["code"=>"pt_BR", "name" => "Brazilian Portuguese"],
];
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,
]);
}
/**
* Update General App Settings
* @param \Crater\Http\Requests\CompanySettingRequest $request
* @return \Illuminate\Http\JsonResponse
*/
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 getCustomizeSetting (Request $request)
{
$invoice_prefix = CompanySetting::getSetting('invoice_prefix', $request->header('company'));
$invoice_auto_generate = CompanySetting::getSetting('invoice_auto_generate', $request->header('company'));
$estimate_prefix = CompanySetting::getSetting('estimate_prefix', $request->header('company'));
$estimate_auto_generate = CompanySetting::getSetting('estimate_auto_generate', $request->header('company'));
$payment_prefix = CompanySetting::getSetting('payment_prefix', $request->header('company'));
$payment_auto_generate = CompanySetting::getSetting('payment_auto_generate', $request->header('company'));
return response()->json([
'invoice_prefix' => $invoice_prefix,
'invoice_auto_generate' => $invoice_auto_generate,
'estimate_prefix' => $estimate_prefix,
'estimate_auto_generate' => $estimate_auto_generate,
'payment_prefix' => $payment_prefix,
'payment_auto_generate' => $payment_auto_generate,
]);
}
public function updateCustomizeSetting (Request $request)
{
$sets = [];
if ($request->type == "PAYMENTS") {
$sets = [
'payment_prefix'
];
}
if ($request->type == "INVOICES") {
$sets = [
'invoice_prefix',
];
}
if ($request->type == "ESTIMATES") {
$sets = [
'estimate_prefix',
];
}
foreach ($sets as $key) {
CompanySetting::setSetting($key, $request->$key, $request->header('company'));
}
return response()->json([
'success' => true
]);
}
/**
* Update a specific Company Setting
* @param \Crater\Http\Requests\SettingRequest $request
* @return \Illuminate\Http\JsonResponse
*/
public function updateSetting(SettingRequest $request)
{
CompanySetting::setSetting($request->key, $request->value, $request->header('company'));
return response()->json([
'success' => true
]);
}
/**
* Retrieve Specific Company Setting
* @param \Crater\Http\Requests\SettingKeyRequest $request
* @return \Illuminate\Http\JsonResponse
*/
public function getSetting(SettingKeyRequest $request)
{
$setting = CompanySetting::getSetting($request->key, $request->header('company'));
return response()->json([
$request->key => $setting
]);
}
/**
* Retrieve App Colors
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
*/
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\JsonResponse
*/
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\JsonResponse
*/
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,238 +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\JsonResponse
*/
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\JsonResponse
*/
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\JsonResponse
*/
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\JsonResponse
*/
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\JsonResponse
*/
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();
$customer->addresses()->delete();
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 Customer along side all his/her resources (ie. Estimates, Invoices, Payments and Addresses)
*
* @param int $id
* @return \Illuminate\Http\JsonResponse
*/
public function destroy($id)
{
User::deleteCustomer($id);
return response()->json([
'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)
{
foreach ($request->id as $id) {
User::deleteCustomer($id);
}
return response()->json([
'success' => true
]);
}
}

View File

@ -1,491 +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)
{
$estimate_prefix = CompanySetting::getSetting('estimate_prefix', $request->header('company'));
$estimate_num_auto_generate = CompanySetting::getSetting('estimate_auto_generate', $request->header('company'));
$nextEstimateNumberAttribute = null;
$nextEstimateNumber = Estimate::getNextEstimateNumber($estimate_prefix);
if ($estimate_num_auto_generate == "YES") {
$nextEstimateNumberAttribute = $nextEstimateNumber;
}
$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,
'nextEstimateNumberAttribute' => $nextEstimateNumberAttribute,
'nextEstimateNumber' => $estimate_prefix.'-'.$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' => '',
'estimate_prefix' => $estimate_prefix
]);
}
public function store(EstimatesRequest $request)
{
$estimate_number = explode("-",$request->estimate_number);
$number_attributes['estimate_number'] = $estimate_number[0].'-'.sprintf('%06d', intval($estimate_number[1]));
Validator::make($number_attributes, [
'estimate_number' => 'required|unique:estimates,estimate_number'
])->validate();
$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' => $number_attributes['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 (gettype($tax['amount']) !== "NULL") {
$tax['company_id'] = $request->header('company');
$item->taxes()->create($tax);
}
}
}
}
if ($request->has('taxes')) {
foreach ($request->taxes as $tax) {
if (gettype($tax['amount']) !== "NULL") {
$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'];
if (!$email) {
return response()->json([
'error' => 'user_email_does_not_exist'
]);
}
if (!config('mail.from.name')) {
return response()->json([
'error' => 'from_email_does_not_exist'
]);
}
\Mail::to($email)->send(new EstimatePdf($data));
}
$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->getEstimateNumAttribute(),
'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),
'estimate_prefix' => $estimate->getEstimatePrefixAttribute()
]);
}
public function update(EstimatesRequest $request, $id)
{
$estimate_number = explode("-",$request->estimate_number);
$number_attributes['estimate_number'] = $estimate_number[0].'-'.sprintf('%06d', intval($estimate_number[1]));
Validator::make($number_attributes, [
'estimate_number' => 'required|unique:estimates,estimate_number'.','.$id
])->validate();
$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 = $number_attributes['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 (gettype($tax['amount']) !== "NULL") {
$tax['company_id'] = $request->header('company');
$item->taxes()->create($tax);
}
}
}
}
if ($request->has('taxes')) {
foreach ($request->taxes as $tax) {
if (gettype($tax['amount']) !== "NULL") {
$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'];
if (!$email) {
return response()->json([
'error' => 'user_email_does_not_exist'
]);
}
if (!config('mail.from.name')) {
return response()->json([
'error' => 'from_email_does_not_exist'
]);
}
\Mail::to($email)->send(new EstimatePdf($data));
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);
$invoice_prefix = CompanySetting::getSetting(
'invoice_prefix',
$request->header('company')
);
$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' => $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' => $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,274 +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\JsonResponse
*/
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\JsonResponse
*/
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\JsonResponse
*/
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\JsonResponse
*/
public function show(Expense $expense)
{
//
}
/**
* Show the form for editing the specified resource.
*
* @param $id
* @return \Illuminate\Http\JsonResponse
*/
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\JsonResponse
*/
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\JsonResponse
*/
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\JsonResponse
*/
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'
]);
}
/**
* Retrive details of an expense receipt from storage.
* @param int $id
* @return \Illuminate\Http\JsonResponse
*/
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
]);
}
/**
* Download an expense receipt from storage.
* @param int $id
* @param strig $hash
* @return \Symfony\Component\HttpFoundation\BinaryFileResponse | \Illuminate\Http\JsonResponse
*/
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,410 +0,0 @@
<?php
namespace Crater\Http\Controllers;
use Illuminate\Http\Request;
use Crater\Invoice;
use PDF;
use Crater\CompanySetting;
use Crater\Estimate;
use Crater\Payment;
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();
}
/**
*
* @return \Illuminate\Http\Response
*/
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();
}
public function getPaymentPdf($id)
{
$payment = Payment::with([
'user',
'invoice',
'paymentMethod'
])
->where('unique_hash', $id)
->first();
$company = Company::find($payment->company_id);
$companyAddress = User::with(['addresses', 'addresses.country'])->find(1);
$logo = $company->getMedia('logo')->first();
if($logo) {
$logo = $logo->getFullUrl();
}
view()->share([
'payment' => $payment,
'company_address' => $companyAddress,
'logo' => $logo ?? null
]);
$pdf = PDF::loadView('app.pdf.payment.payment');
return $pdf->stream();
}
}

View File

@ -1,581 +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\JsonResponse
*/
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\JsonResponse
*/
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'));
$invoice_prefix = CompanySetting::getSetting('invoice_prefix', $request->header('company'));
$invoice_num_auto_generate = CompanySetting::getSetting('invoice_auto_generate', $request->header('company'));
$nextInvoiceNumberAttribute = null;
$nextInvoiceNumber = Invoice::getNextInvoiceNumber($invoice_prefix);
if ($invoice_num_auto_generate == "YES") {
$nextInvoiceNumberAttribute = $nextInvoiceNumber;
}
return response()->json([
'nextInvoiceNumberAttribute' => $nextInvoiceNumberAttribute,
'nextInvoiceNumber' => $invoice_prefix.'-'.$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,
'invoice_prefix' => $invoice_prefix
]);
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function store(Requests\InvoicesRequest $request)
{
$invoice_number = explode("-",$request->invoice_number);
$number_attributes['invoice_number'] = $invoice_number[0].'-'.sprintf('%06d', intval($invoice_number[1]));
Validator::make($number_attributes, [
'invoice_number' => 'required|unique:invoices,invoice_number'
])->validate();
$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' => $number_attributes['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 (gettype($tax['amount']) !== "NULL") {
$item->taxes()->create($tax);
}
}
}
}
if ($request->has('taxes')) {
foreach ($request->taxes as $tax) {
$tax['company_id'] = $request->header('company');
if (gettype($tax['amount']) !== "NULL") {
$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);
$email = $data['user']['email'];
if (!$email) {
return response()->json([
'error' => 'user_email_does_not_exist'
]);
}
if (!config('mail.from.name')) {
return response()->json([
'error' => 'from_email_does_not_exist'
]);
}
\Mail::to($email)->send(new invoicePdf($data));
}
$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\JsonResponse
*/
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\JsonResponse
*/
public function edit(Request $request,$id)
{
$invoice = Invoice::with([
'items',
'items.taxes',
'user',
'invoiceTemplate',
'taxes.taxType'
])->find($id);
return response()->json([
'nextInvoiceNumber' => $invoice->getInvoiceNumAttribute(),
'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),
'invoice_prefix' => $invoice->getInvoicePrefixAttribute()
]);
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\JsonResponse
*/
public function update(Requests\InvoicesRequest $request, $id)
{
$invoice_number = explode("-",$request->invoice_number);
$number_attributes['invoice_number'] = $invoice_number[0].'-'.sprintf('%06d', intval($invoice_number[1]));
Validator::make($number_attributes, [
'invoice_number' => 'required|unique:invoices,invoice_number'.','.$id
])->validate();
$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 = $number_attributes['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 (gettype($tax['amount']) !== "NULL") {
$item->taxes()->create($tax);
}
}
}
}
if ($request->has('taxes')) {
foreach ($request->taxes as $tax) {
$tax['company_id'] = $request->header('company');
if (gettype($tax['amount']) !== "NULL") {
$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\JsonResponse
*/
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
]);
}
/**
* Mail a specific invoice to the correponding cusitomer's email address.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
*/
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'];
if (!$email) {
return response()->json([
'error' => 'user_email_does_not_exist'
]);
}
if (!config('mail.from.name')) {
return response()->json([
'error' => 'from_email_does_not_exist'
]);
}
\Mail::to($email)->send(new invoicePdf($data));
if ($invoice->status == Invoice::STATUS_DRAFT) {
$invoice->status = Invoice::STATUS_SENT;
$invoice->sent = true;
$invoice->save();
}
return response()->json([
'success' => true
]);
}
/**
* Mark a specific invoice as sent.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
*/
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
]);
}
/**
* Mark a specific invoice as paid.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
*/
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
]);
}
/**
* Retrive a specified user's unpaid invoices from storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\JsonResponse
*/
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
]);
}
public function cloneInvoice(Request $request)
{
$oldInvoice = Invoice::with([
'items.taxes',
'user',
'invoiceTemplate',
'taxes.taxType'
])
->find($request->id);
$date = Carbon::now();
$invoice_prefix = CompanySetting::getSetting(
'invoice_prefix',
$request->header('company')
);
$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' => $date,
'due_date' => $date,
'invoice_number' => $invoice_prefix."-".Invoice::getNextInvoiceNumber($invoice_prefix),
'reference_number' => $oldInvoice->reference_number,
'user_id' => $oldInvoice->user_id,
'company_id' => $request->header('company'),
'invoice_template_id' => 1,
'status' => Invoice::STATUS_DRAFT,
'paid_status' => Invoice::STATUS_UNPAID,
'sub_total' => $oldInvoice->sub_total,
'discount' => $oldInvoice->discount,
'discount_type' => $oldInvoice->discount_type,
'discount_val' => $oldInvoice->discount_val,
'total' => $oldInvoice->total,
'due_amount' => $oldInvoice->total,
'tax_per_item' => $oldInvoice->tax_per_item,
'discount_per_item' => $oldInvoice->discount_per_item,
'tax' => $oldInvoice->tax,
'notes' => $oldInvoice->notes,
'unique_hash' => str_random(60)
]);
$invoiceItems = $oldInvoice->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 ($oldInvoice->taxes) {
foreach ($oldInvoice->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
]);
}
}

View File

@ -1,166 +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::with(['taxes'])
->leftJoin('units', 'units.id', '=', 'items.unit_id')
->applyFilters($request->only([
'search',
'price',
'unit_id',
'orderByField',
'orderBy'
]))
->whereCompany($request->header('company'))
->select('items.*', 'units.name as unit_name')
->latest()
->paginate($limit);
return response()->json([
'items' => $items,
'taxTypes' => TaxType::latest()->get()
]);
}
public function edit(Request $request, $id)
{
$item = Item::with(['taxes', 'unit'])->find($id);
return response()->json([
'item' => $item,
'taxes' => Tax::whereCompany($request->header('company'))
->latest()
->get()
]);
}
/**
* Create Item.
*
* @param Crater\Http\Requests\ItemsRequest $request
* @return \Illuminate\Http\JsonResponse
*/
public function store(Requests\ItemsRequest $request)
{
$item = new Item();
$item->name = $request->name;
$item->unit_id = $request->unit_id;
$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
]);
}
/**
* Update an existing Item.
*
* @param Crater\Http\Requests\ItemsRequest $request
* @param int $id
* @return \Illuminate\Http\JsonResponse
*/
public function update(Requests\ItemsRequest $request, $id)
{
$item = Item::find($id);
$item->name = $request->name;
$item->unit_id = $request->unit_id;
$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
]);
}
/**
* Delete an existing Item.
*
* @param int $id
* @return \Illuminate\Http\JsonResponse
*/
public function destroy($id)
{
$data = Item::deleteItem($id);
if (!$data) {
return response()->json([
'error' => 'item_attached'
]);
}
return response()->json([
'success' => $data
]);
}
/**
* Delete a list of existing Items.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
*/
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,21 +0,0 @@
<?php
namespace Crater\Http\Controllers;
use Illuminate\Http\Request;
use Crater\Country;
class LocationController extends Controller
{
/**
* Retrive a list of Countries.
*
* @return \Illuminate\Http\JsonResponse
*/
public function getCountries()
{
return response()->json([
'countries' => Country::all()
]);
}
}

View File

@ -1,336 +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
{
/**
* Retrieve Onboarding data.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
*/
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"=>"ar", "name" => "Arabic"],
["code"=>"en", "name" => "English"],
["code"=>"fr", "name" => "French"],
["code"=>"es", "name" => "Spanish"],
["code"=>"ar", "name" => "العربية"],
["code"=>"de", "name" => "German"],
["code"=>"pt-br", "name" => "Portuguese (Brazilian)"]
];
$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()
]);
}
/**
* Setup Admin Profile.
*
* @param \Crater\Http\Requests\ProfileRequest $request
* @return \Illuminate\Http\JsonResponse
*/
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
]);
}
/**
* Setup Admin Avatar.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
*/
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
]);
}
/**
* Setup Admin Company.
*
* @param \Crater\Http\Requests\CompanyRequest $request
* @return \Illuminate\Http\JsonResponse
*/
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
]);
}
/**
* Setup Company Settings.
*
* @param \Crater\Http\Requests\CompanySettingRequest $request
* @return \Illuminate\Http\JsonResponse
*/
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
);
}
$invoices = [
'invoice_auto_generate' => 'YES',
'invoice_prefix' => 'INV'
];
foreach ($invoices as $key => $value) {
CompanySetting::setSetting(
$key,
$value,
$user->company_id
);
}
$estimates = [
'estimate_prefix' => 'EST',
'estimate_auto_generate' => 'YES'
];
foreach ($estimates as $key => $value) {
CompanySetting::setSetting(
$key,
$value,
$user->company_id
);
}
$payments = [
'payment_prefix' => 'PAY',
'payment_auto_generate' => 'YES'
];
foreach ($payments as $key => $value) {
CompanySetting::setSetting(
$key,
$value,
$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');
Artisan::call('db:seed', ['--class' => 'PaymentMethodSeeder', '--force' => true]);
Artisan::call('db:seed', ['--class' => 'UnitSeeder', '--force' => true]);
$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)
));
file_put_contents($path, str_replace(
'APP_DEBUG=true',
'APP_DEBUG=false',
file_get_contents($path)
));
}
$data['token'] = $user->createToken('password')->accessToken;
return response()->json($data);
}
}

View File

@ -1,331 +0,0 @@
<?php
namespace Crater\Http\Controllers;
use Illuminate\Http\Request;
use Crater\CompanySetting;
use Crater\Currency;
use Crater\Company;
use Crater\Invoice;
use Crater\Payment;
use Crater\PaymentMethod;
use Carbon\Carbon;
use function MongoDB\BSON\toJSON;
use Crater\User;
use Crater\Http\Requests\PaymentRequest;
use Validator;
use Crater\Mail\PaymentPdf;
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', 'paymentMethod'])
->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_method_id',
'customer_id',
'orderByField',
'orderBy'
]))
->whereCompany($request->header('company'))
->select('payments.*', 'users.name', 'invoices.invoice_number', 'payment_methods.name as payment_mode')
->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)
{
$payment_prefix = CompanySetting::getSetting('payment_prefix', $request->header('company'));
$payment_num_auto_generate = CompanySetting::getSetting('payment_auto_generate', $request->header('company'));
$nextPaymentNumberAttribute = null;
$nextPaymentNumber = Payment::getNextPaymentNumber($payment_prefix);
if ($payment_num_auto_generate == "YES") {
$nextPaymentNumberAttribute = $nextPaymentNumber;
}
return response()->json([
'customers' => User::where('role', 'customer')
->whereCompany($request->header('company'))
->get(),
'paymentMethods' => PaymentMethod::whereCompany($request->header('company'))
->latest()
->get(),
'nextPaymentNumberAttribute' => $nextPaymentNumberAttribute,
'nextPaymentNumber' => $payment_prefix.'-'.$nextPaymentNumber,
'payment_prefix' => $payment_prefix
]);
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(PaymentRequest $request)
{
$payment_number = explode("-",$request->payment_number);
$number_attributes['payment_number'] = $payment_number[0].'-'.sprintf('%06d', intval($payment_number[1]));
Validator::make($number_attributes, [
'payment_number' => 'required|unique:payments,payment_number'
])->validate();
$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' => $number_attributes['payment_number'],
'user_id' => $request->user_id,
'company_id' => $request->header('company'),
'invoice_id' => $request->invoice_id,
'payment_method_id' => $request->payment_method_id,
'amount' => $request->amount,
'notes' => $request->notes,
'unique_hash' => str_random(60)
]);
return response()->json([
'payment' => $payment,
'shareable_link' => url('/payments/pdf/'.$payment->unique_hash),
'success' => true
]);
}
/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show($id)
{
$payment = Payment::with(['user', 'invoice', 'paymentMethod'])->find($id);
return response()->json([
'payment' => $payment,
'shareable_link' => url('/payments/pdf/'.$payment->unique_hash)
]);
}
/**
* 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', 'paymentMethod'])->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(),
'paymentMethods' => PaymentMethod::whereCompany($request->header('company'))
->latest()
->get(),
'nextPaymentNumber' => $payment->getPaymentNumAttribute(),
'payment_prefix' => $payment->getPaymentPrefixAttribute(),
'shareable_link' => url('/payments/pdf/'.$payment->unique_hash),
'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_number = explode("-",$request->payment_number);
$number_attributes['payment_number'] = $payment_number[0].'-'.sprintf('%06d', intval($payment_number[1]));
Validator::make($number_attributes, [
'payment_number' => 'required|unique:payments,payment_number'.','.$id
])->validate();
$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 = $number_attributes['payment_number'];
$payment->user_id = $request->user_id;
$payment->invoice_id = $request->invoice_id;
$payment->payment_method_id = $request->payment_method_id;
$payment->amount = $request->amount;
$payment->notes = $request->notes;
$payment->save();
return response()->json([
'payment' => $payment,
'shareable_link' => url('/payments/pdf/'.$payment->unique_hash),
'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
]);
}
public function sendPayment(Request $request)
{
$payment = Payment::findOrFail($request->id);
$data['payment'] = $payment->toArray();
$userId = $data['payment']['user_id'];
$data['user'] = User::find($userId)->toArray();
$data['company'] = Company::find($payment->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 PaymentPdf($data, $notificationEmail));
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,42 +0,0 @@
<?php
namespace Crater\Http\Controllers;
use Illuminate\Http\Request;
use Crater\Setting;
use Crater\Mail\TestMail;
use Mail;
class SettingsController extends Controller
{
/**
* Retrive App Version.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function getAppVersion(Request $request)
{
$version = Setting::getSetting('version');
return response()->json([
'version' => $version,
]);
}
public function testEmailConfig(Request $request)
{
$this->validate($request, [
'to' => 'required|email',
'subject' => 'required',
'message' => 'required'
]);
Mail::to($request->to)->send(new TestMail($request->subject, $request->message));
return response()->json([
'success' => true
]);
}
}

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,86 +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\PaymentMethod;
use Crater\Unit;
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::with('taxes')->get();
$taxTypes = TaxType::latest()->get();
$paymentMethods = PaymentMethod::whereCompany($request->header('company'))
->latest()
->get();
$units = Unit::whereCompany($request->header('company'))
->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,
'paymentMethods' => $paymentMethods,
'units' => $units,
'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 <?php
namespace Crater\Http\Controllers\Auth;
namespace Crater\Http\Controllers\V1\Auth;
use Crater\Http\Controllers\Controller; use Crater\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\SendsPasswordResetEmails; use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
@ -20,16 +21,6 @@ class ForgotPasswordController extends Controller
use SendsPasswordResetEmails; use SendsPasswordResetEmails;
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
// $this->middleware('guest');
}
/** /**
* Get the response for a successful password reset link. * Get the response for a successful password reset link.
* *

View File

@ -0,0 +1,25 @@
<?php
namespace Crater\Http\Controllers\V1\Auth;
use Crater\Http\Controllers\Controller;
use Crater\Models\User;
use Illuminate\Http\Request;
class IsRegisteredController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function __invoke(Request $request)
{
if (User::whereEmail($request->email)->first()) {
return 'true';
} else {
return 'false';
}
}
}

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 <?php
namespace Crater\Http\Controllers\Auth;
namespace Crater\Http\Controllers\V1\Auth;
use Crater\Http\Controllers\Controller; use Crater\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ResetsPasswords; use Crater\Providers\RouteServiceProvider;
use Illuminate\Http\Request;
use Illuminate\Support\Str; use Illuminate\Support\Str;
use Illuminate\Auth\Events\PasswordReset; use Illuminate\Auth\Events\PasswordReset;
use Illuminate\Http\Request;
use Illuminate\Foundation\Auth\ResetsPasswords;
class ResetPasswordController extends Controller class ResetPasswordController extends Controller
{ {
@ -27,17 +29,8 @@ class ResetPasswordController extends Controller
* *
* @var string * @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. * Get the response for a successful password reset.

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,27 +1,25 @@
<?php <?php
namespace Crater\Http\Controllers; namespace Crater\Http\Controllers\V1\Dashboard;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Crater\Models\Estimate;
use Crater\Estimate; use Crater\Models\Invoice;
use Crater\Http\Requests; use Crater\Models\CompanySetting;
use Crater\Invoice; use Crater\Models\Expense;
use Crater\CompanySetting; use Crater\Models\Payment;
use Crater\Expense;
use Crater\Payment;
use Carbon\Carbon; use Carbon\Carbon;
use Crater\User; use Crater\Models\User;
use Illuminate\Support\Facades\DB; use Crater\Http\Controllers\Controller;
class DashboardController extends Controller class DashboardController extends Controller
{ {
/** /**
* Retrieve Dashboard details * Handle the incoming request.
*
* @param \Illuminate\Http\Request $request * @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse * @return \Illuminate\Http\JsonResponse
*/ */
public function index(Request $request) public function __invoke(Request $request)
{ {
$invoiceTotals = []; $invoiceTotals = [];
$expenseTotals = []; $expenseTotals = [];
@ -29,7 +27,6 @@ class DashboardController extends Controller
$netProfits = []; $netProfits = [];
$i = 0; $i = 0;
$months = []; $months = [];
$monthEnds = [];
$monthCounter = 0; $monthCounter = 0;
$fiscalYear = CompanySetting::getSetting('fiscal_year', $request->header('company')); $fiscalYear = CompanySetting::getSetting('fiscal_year', $request->header('company'));
$startDate = Carbon::now(); $startDate = Carbon::now();
@ -144,25 +141,4 @@ class DashboardController extends Controller
'netProfit' => $netProfit 'netProfit' => $netProfit
]); ]);
} }
/**
* Retrive Expense Chart data
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
*/
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 <?php
namespace Crater\Http\Controllers; namespace Crater\Http\Controllers\V1\Expense;
use Crater\ExpenseCategory; use Crater\Models\ExpenseCategory;
use Crater\Expense;
use Crater\User;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Crater\Http\Requests\ExpenseCategoryRequest; use Crater\Http\Requests\ExpenseCategoryRequest;
use Crater\Http\Controllers\Controller;
class ExpenseCategoryController extends Controller class ExpenseCategoriesController extends Controller
{ {
/** /**
* Display a listing of the resource. * Display a listing of the resource.
@ -16,23 +15,21 @@ class ExpenseCategoryController extends Controller
*/ */
public function index(Request $request) 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([ return response()->json([
'categories' => $categories '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. * Store a newly created resource in storage.
* *
@ -41,11 +38,9 @@ class ExpenseCategoryController extends Controller
*/ */
public function store(ExpenseCategoryRequest $request) public function store(ExpenseCategoryRequest $request)
{ {
$category = new ExpenseCategory(); $data = $request->validated();
$category->name = $request->name; $data['company_id'] = $request->header('company');
$category->description = $request->description; $category = ExpenseCategory::create($data);
$category->company_id = $request->header('company');
$category->save();
return response()->json([ return response()->json([
'category' => $category, 'category' => $category,
@ -56,24 +51,11 @@ class ExpenseCategoryController extends Controller
/** /**
* Display the specified resource. * Display the specified resource.
* *
* @param \Crater\ExpenseCategory $ExpenseCategory * @param \Crater\Models\ExpenseCategory $category
* @return \Illuminate\Http\Response * @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([ return response()->json([
'category' => $category 'category' => $category
]); ]);
@ -83,15 +65,12 @@ class ExpenseCategoryController extends Controller
* Update the specified resource in storage. * Update the specified resource in storage.
* *
* @param \Illuminate\Http\Request $request * @param \Illuminate\Http\Request $request
* @param \Crater\ExpenseCategory $ExpenseCategory * @param \Crater\Models\ExpenseCategory $ExpenseCategory
* @return \Illuminate\Http\Response * @return \Illuminate\Http\Response
*/ */
public function update(ExpenseCategoryRequest $request, $id) public function update(ExpenseCategoryRequest $request, ExpenseCategory $category)
{ {
$category = ExpenseCategory::findOrFail($id); $category->update($request->validated());
$category->name = $request->name;
$category->description = $request->description;
$category->save();
return response()->json([ return response()->json([
'category' => $category, 'category' => $category,
@ -102,17 +81,17 @@ class ExpenseCategoryController extends Controller
/** /**
* Remove the specified resource from storage. * Remove the specified resource from storage.
* *
* @param \Crater\ExpensesCategory $expensesCategory * @param \Crater\ExpensesCategory $category
* @return \Illuminate\Http\Response * @return \Illuminate\Http\Response
*/ */
public function destroy($id) public function destroy(ExpenseCategory $category)
{ {
$category = ExpenseCategory::find($id);
if ($category->expenses() && $category->expenses()->count() > 0) { if ($category->expenses() && $category->expenses()->count() > 0) {
return response()->json([ return response()->json([
'success' => false 'success' => false
]); ]);
} }
$category->delete(); $category->delete();
return response()->json([ 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

@ -1,12 +1,13 @@
<?php <?php
namespace Crater\Http\Controllers; namespace Crater\Http\Controllers\V1\Item;
use Crater\Unit; use Crater\Models\Unit;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Crater\Http\Requests\UnitRequest; use Crater\Http\Requests\UnitRequest;
use Crater\Http\Controllers\Controller;
class UnitController extends Controller class UnitsController extends Controller
{ {
/** /**
* Display a listing of the resource. * Display a listing of the resource.
@ -15,9 +16,14 @@ class UnitController extends Controller
*/ */
public function index(Request $request) public function index(Request $request)
{ {
$limit = $request->has('limit') ? $request->limit : 5;
$units = Unit::whereCompany($request->header('company')) $units = Unit::whereCompany($request->header('company'))
->applyFilters($request->only([
'unit_id'
]))
->latest() ->latest()
->get(); ->paginateData($limit);
return response()->json([ return response()->json([
'units' => $units 'units' => $units
@ -42,10 +48,9 @@ class UnitController extends Controller
*/ */
public function store(UnitRequest $request) public function store(UnitRequest $request)
{ {
$unit = new Unit; $data = $request->validated();
$unit->name = $request->name; $data['company_id'] = $request->header('company');
$unit->company_id = $request->header('company'); $unit = Unit::create($data);
$unit->save();
return response()->json([ return response()->json([
'unit' => $unit 'unit' => $unit
@ -55,21 +60,10 @@ class UnitController extends Controller
/** /**
* Display the specified resource. * Display the specified resource.
* *
* @param \Crater\Unit $unit * @param \Crater\Models\Unit $unit
* @return \Illuminate\Http\Response * @return \Illuminate\Http\Response
*/ */
public function show(Unit $unit) public function show(Unit $unit)
{
//
}
/**
* Show the form for editing the specified resource.
*
* @param \Crater\Unit $unit
* @return \Illuminate\Http\Response
*/
public function edit(Unit $unit)
{ {
return response()->json([ return response()->json([
'unit' => $unit 'unit' => $unit
@ -80,14 +74,12 @@ class UnitController extends Controller
* Update the specified resource in storage. * Update the specified resource in storage.
* *
* @param \Illuminate\Http\Request $request * @param \Illuminate\Http\Request $request
* @param \Crater\Unit $unit * @param \Crater\Models\Unit $unit
* @return \Illuminate\Http\Response * @return \Illuminate\Http\Response
*/ */
public function update(UnitRequest $request, Unit $unit) public function update(UnitRequest $request, Unit $unit)
{ {
$unit->name = $request->name; $unit->update($request->validated());
$unit->company_id = $request->header('company');
$unit->save();
return response()->json([ return response()->json([
'unit' => $unit 'unit' => $unit
@ -97,14 +89,12 @@ class UnitController extends Controller
/** /**
* Remove the specified resource from storage. * Remove the specified resource from storage.
* *
* @param \Crater\Unit $unit * @param \Crater\Models\Unit $unit
* @return \Illuminate\Http\Response * @return \Illuminate\Http\Response
*/ */
public function destroy(Unit $unit) public function destroy(Unit $unit)
{ {
$items = $unit->items; if ($unit->items()->exists()) {
if ($items->count() > 0) {
return response()->json([ return response()->json([
'error' => 'items_attached' 'error' => 'items_attached'
]); ]);

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,90 @@
<?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('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 <?php
namespace Crater\Http\Controllers; namespace Crater\Http\Controllers\V1\Onboarding;
use Crater\Space\PermissionsChecker; use Crater\Space\PermissionsChecker;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Crater\Http\Controllers\Controller;
class PermissionsController extends Controller class PermissionsController extends Controller
{ {

View File

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

View File

@ -1,12 +1,13 @@
<?php <?php
namespace Crater\Http\Controllers; namespace Crater\Http\Controllers\V1\Payment;
use Crater\PaymentMethod; use Crater\Models\PaymentMethod;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Crater\Http\Requests\PaymentMethodRequest; use Crater\Http\Requests\PaymentMethodRequest;
use Crater\Http\Controllers\Controller;
class PaymentMethodController extends Controller class PaymentMethodsController extends Controller
{ {
/** /**
* Display a listing of the resource. * Display a listing of the resource.
@ -15,25 +16,21 @@ class PaymentMethodController extends Controller
*/ */
public function index(Request $request) public function index(Request $request)
{ {
$limit = $request->has('limit') ? $request->limit : 5;
$paymentMethods = PaymentMethod::whereCompany($request->header('company')) $paymentMethods = PaymentMethod::whereCompany($request->header('company'))
->applyFilters($request->only([
'method_id',
'search'
]))
->latest() ->latest()
->get(); ->paginateData($limit);
return response()->json([ return response()->json([
'paymentMethods' => $paymentMethods 'paymentMethods' => $paymentMethods
]); ]);
} }
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
//
}
/** /**
* Store a newly created resource in storage. * Store a newly created resource in storage.
* *
@ -42,10 +39,7 @@ class PaymentMethodController extends Controller
*/ */
public function store(PaymentMethodRequest $request) public function store(PaymentMethodRequest $request)
{ {
$paymentMethod = new PaymentMethod; $paymentMethod = PaymentMethod::createPaymentMethod($request);
$paymentMethod->name = $request->name;
$paymentMethod->company_id = $request->header('company');
$paymentMethod->save();
return response()->json([ return response()->json([
'paymentMethod' => $paymentMethod 'paymentMethod' => $paymentMethod
@ -55,21 +49,10 @@ class PaymentMethodController extends Controller
/** /**
* Display the specified resource. * Display the specified resource.
* *
* @param \Crater\PaymentMethod $paymentMethod * @param \Crater\Models\PaymentMethod $paymentMethod
* @return \Illuminate\Http\Response * @return \Illuminate\Http\Response
*/ */
public function show(PaymentMethod $paymentMethod) public function show(PaymentMethod $paymentMethod)
{
//
}
/**
* Show the form for editing the specified resource.
*
* @param \Crater\PaymentMethod $paymentMethod
* @return \Illuminate\Http\Response
*/
public function edit(PaymentMethod $paymentMethod)
{ {
return response()->json([ return response()->json([
'paymentMethod' => $paymentMethod 'paymentMethod' => $paymentMethod
@ -80,14 +63,12 @@ class PaymentMethodController extends Controller
* Update the specified resource in storage. * Update the specified resource in storage.
* *
* @param \Illuminate\Http\Request $request * @param \Illuminate\Http\Request $request
* @param \Crater\PaymentMethod $paymentMethod * @param \Crater\Models\PaymentMethod $paymentMethod
* @return \Illuminate\Http\Response * @return \Illuminate\Http\Response
*/ */
public function update(PaymentMethodRequest $request, PaymentMethod $paymentMethod) public function update(PaymentMethodRequest $request, PaymentMethod $paymentMethod)
{ {
$paymentMethod->name = $request->name; $paymentMethod->update($request->validated());
$paymentMethod->company_id = $request->header('company');
$paymentMethod->save();
return response()->json([ return response()->json([
'paymentMethod' => $paymentMethod 'paymentMethod' => $paymentMethod
@ -97,7 +78,7 @@ class PaymentMethodController extends Controller
/** /**
* Remove the specified resource from storage. * Remove the specified resource from storage.
* *
* @param \Crater\PaymentMethod $paymentMethod * @param \Crater\Models\PaymentMethod $paymentMethod
* @return \Illuminate\Http\Response * @return \Illuminate\Http\Response
*/ */
public function destroy(PaymentMethod $paymentMethod) public function destroy(PaymentMethod $paymentMethod)

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();
}
}

View File

@ -0,0 +1,127 @@
<?php
namespace Crater\Http\Controllers\V1\Settings;
use Illuminate\Http\Request;
use Crater\Models\Company;
use Crater\Http\Requests\ProfileRequest;
use Crater\Http\Requests\CompanyRequest;
use Crater\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;
class CompanyController extends Controller
{
/**
* Retrive the Admin account.
* @return \Illuminate\Http\JsonResponse
*/
public function getUser()
{
$user = Auth::user();
$user->load([
'addresses',
'addresses.country',
'company',
'company.address',
'company.address.country'
]);
return response()->json([
'user' => $user
]);
}
/**
* Update the Admin profile.
* Includes name, email and (or) password
*
* @param \Crater\Http\Requests\ProfileRequest $request
* @return \Illuminate\Http\JsonResponse
*/
public function updateProfile(ProfileRequest $request)
{
$user = Auth::user();
$user->update($request->validated());
return response()->json([
'user' => $user,
'success' => true
]);
}
/**
* Update Admin Company Details
* @param \Crater\Http\Requests\CompanyRequest $request
* @return \Illuminate\Http\JsonResponse
*/
public function updateCompany(CompanyRequest $request)
{
$company = Auth::user()->company;
$company->update($request->only('name'));
$company->address()->updateOrCreate(['company_id' => $company->id], $request->except(['name']));
return response()->json([
'company' => $company,
'success' => true
]);
}
/**
* Upload the company logo to storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
*/
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\JsonResponse
*/
public function uploadAvatar(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

@ -0,0 +1,186 @@
<?php
namespace Crater\Http\Controllers\V1\Settings;
use Crater\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Crater\Models\FileDisk;
use Crater\Http\Requests\DiskEnvironmentRequest;
use Illuminate\Http\JsonResponse;
class DiskController extends Controller
{
/**
*
* @return JsonResponse
*/
public function index(Request $request)
{
$limit = $request->has('limit') ? $request->limit : 5;
$disks = FileDisk::applyFilters($request->all())
->latest()
->paginateData($limit);
return response()->json([
'disks' => $disks,
]);
}
/**
*
* @param DiskEnvironmentRequest $request
* @return JsonResponse
*/
public function store(DiskEnvironmentRequest $request)
{
if(!FileDisk::validateCredentials($request->credentials, $request->driver)) {
return response()->json([
'success' => false,
'error' => 'invalid_credentials'
]);
}
$disk = FileDisk::createDisk($request);
return response()->json([
'success' => true,
'disk' => $disk
]);
}
/**
*
* @param Request $request
* @param \Crater\Models\FileDisk $file_disk
* @return JsonResponse
*/
public function update(FileDisk $disk, Request $request)
{
$credentials = $request->credentials;
$driver = $request->driver;
if($credentials && $driver && $disk->type !== 'SYSTEM') {
if(!FileDisk::validateCredentials($credentials, $driver)) {
return response()->json([
'success' => false,
'error' => 'invalid_credentials'
]);
}
$disk->updateDisk($request);
} else if($request->set_as_default) {
$disk->setAsDefaultDisk();
}
return response()->json([
'success' => true,
'disk' => $disk
]);
}
/**
* @param Request $request
* @return JsonResponse
*/
public function show($disk)
{
$diskData = [];
switch ($disk) {
case 'local':
$diskData = [
'root' => config('filesystems.disks.local.root'),
];
break;
case 's3':
$diskData = [
'key' => '',
'secret' => '',
'region' => '',
'bucket' => '',
'root' => '',
];
break;
case 'doSpaces':
$diskData = [
'key' => '',
'secret' => '',
'region' => '',
'bucket' => '',
'endpoint' => '',
'root' => '',
];
break;
case 'dropbox':
$diskData = [
'token' => '',
'key' => '',
'secret' => '',
'app' => '',
'root' => '',
];
break;
}
$data = array_merge($diskData);
return response()->json($data);
}
/**
* Remove the specified resource from storage.
*
* @param \Crater\Models\FileDisk $taxType
* @return \Illuminate\Http\Response
*/
public function destroy(FileDisk $disk)
{
if ($disk->setAsDefault() && $disk->type === 'SYSTEM') {
return response()->json([
'success' => false
]);
}
$disk->delete();
return response()->json([
'success' => true
]);
}
/**
*
* @return JsonResponse
*/
public function getDiskDrivers()
{
$drivers = [
[
'name' => 'Local',
'value' => 'local'
],
[
'name' => 'Amazon S3',
'value' => 's3'
],
[
'name' => 'Digital Ocean Spaces',
'value' => 'doSpaces'
],
[
'name' => 'Dropbox',
'value' => 'dropbox'
],
];
$default = config('filesystems.default');
return response()->json([
'drivers' => $drivers,
'default' => $default
]);
}
}

View File

@ -0,0 +1,23 @@
<?php
namespace Crater\Http\Controllers\V1\Settings;
use Crater\Models\CompanySetting;
use Crater\Http\Controllers\Controller;
use Crater\Http\Requests\GetSettingsRequest;
class GetCompanySettingsController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function __invoke(GetSettingsRequest $request)
{
$settings = CompanySetting::getSettings($request->settings, $request->header('company'));
return response()->json($settings);
}
}

View File

@ -0,0 +1,23 @@
<?php
namespace Crater\Http\Controllers\V1\Settings;
use Auth;
use Crater\Http\Controllers\Controller;
use Crater\Http\Requests\GetSettingsRequest;
class GetUserSettingsController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\GetSettingsRequest $request
* @return \Illuminate\Http\JsonResponse
*/
public function __invoke(GetSettingsRequest $request)
{
$user = Auth::user();
return response()->json($user->getSettings($request->settings));
}
}

View File

@ -1,68 +1,40 @@
<?php <?php
namespace Crater\Http\Controllers; namespace Crater\Http\Controllers\V1\Settings;
use Exception; use Crater\Models\Setting;
use Validator;
use Crater\Setting;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Crater\Space\EnvironmentManager; use Crater\Space\EnvironmentManager;
use Crater\Http\Requests\DatabaseEnvironmentRequest;
use Crater\Http\Requests\MailEnvironmentRequest; use Crater\Http\Requests\MailEnvironmentRequest;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Artisan; use Crater\Http\Controllers\Controller;
use Crater\Mail\TestMail;
use Mail;
class EnvironmentController extends Controller class MailConfigurationController extends Controller
{ {
/** /**
* @var EnvironmentManager * @var EnvironmentManager
*/ */
protected $EnvironmentManager; protected $environmentManager;
/** /**
* @param EnvironmentManager $environmentManager * @param EnvironmentManager $environmentManager
*/ */
public function __construct(EnvironmentManager $environmentManager) public function __construct(EnvironmentManager $environmentManager)
{ {
$this->EnvironmentManager = $environmentManager; $this->environmentManager = $environmentManager;
} }
/** /**
* *
* @param DatabaseEnvironmentRequest $request * @param MailEnvironmentRequest $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('config:clear');
Artisan::call('cache:clear');
Artisan::call('storage:link');
Artisan::call('key:generate --force');
Artisan::call('migrate --seed --force');
Artisan::call('migrate', ['--path' => 'vendor/laravel/passport/database/migrations', '--force' => true]);
\Storage::disk('local')->put('database_created', 'database_created');
Setting::setSetting('profile_complete', 3);
}
return response()->json($results);
}
/**
*
* @param DatabaseEnvironmentRequest $request
* @return JsonResponse * @return JsonResponse
*/ */
public function saveMailEnvironment(MailEnvironmentRequest $request) public function saveMailEnvironment(MailEnvironmentRequest $request)
{ {
$setting = Setting::getSetting('profile_complete'); $setting = Setting::getSetting('profile_complete');
$results = $this->EnvironmentManager->saveMailVariables($request); $results = $this->environmentManager->saveMailVariables($request);
if ($setting !== 'COMPLETED') if ($setting !== 'COMPLETED')
{ {
@ -110,4 +82,19 @@ class EnvironmentController extends Controller
return response()->json($drivers); return response()->json($drivers);
} }
public function testEmailConfig(Request $request)
{
$this->validate($request, [
'to' => 'required|email',
'subject' => 'required',
'message' => 'required'
]);
Mail::to($request->to)->send(new TestMail($request->subject, $request->message));
return response()->json([
'success' => true
]);
}
} }

View File

@ -1,12 +1,13 @@
<?php <?php
namespace Crater\Http\Controllers;
use Crater\TaxType; namespace Crater\Http\Controllers\V1\Settings;
use Crater\User;
use Crater\Models\TaxType;
use Crater\Http\Requests\TaxTypeRequest; use Crater\Http\Requests\TaxTypeRequest;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Crater\Http\Controllers\Controller;
class TaxTypeController extends Controller class TaxTypesController extends Controller
{ {
/** /**
* Display a listing of the resource. * Display a listing of the resource.
@ -15,25 +16,23 @@ class TaxTypeController extends Controller
*/ */
public function index(Request $request) public function index(Request $request)
{ {
$limit = $request->has('limit') ? $request->limit : 5;
$taxTypes = TaxType::whereCompany($request->header('company')) $taxTypes = TaxType::whereCompany($request->header('company'))
->applyFilters($request->only([
'tax_type_id',
'search',
'orderByField',
'orderBy'
]))
->latest() ->latest()
->get(); ->paginateData($limit);
return response()->json([ return response()->json([
'taxTypes' => $taxTypes 'taxTypes' => $taxTypes
]); ]);
} }
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
//
}
/** /**
* Store a newly created resource in storage. * Store a newly created resource in storage.
* *
@ -42,15 +41,11 @@ class TaxTypeController extends Controller
*/ */
public function store(TaxTypeRequest $request) public function store(TaxTypeRequest $request)
{ {
$taxType = new TaxType(); $data = $request->validated();
$taxType->name = $request->name;
$taxType->percent = $request->percent; $data['company_id'] = $request->header('company');
$taxType->description = $request->description;
if ($request->has('compound_tax')) { $taxType = TaxType::create($data);
$taxType->compound_tax = $request->compound_tax;
}
$taxType->company_id = $request->header('company');
$taxType->save();
return response()->json([ return response()->json([
'taxType' => $taxType, 'taxType' => $taxType,
@ -60,21 +55,10 @@ class TaxTypeController extends Controller
/** /**
* Display the specified resource. * Display the specified resource.
* *
* @param \Crater\TaxType $taxType * @param \Crater\Models\TaxType $taxType
* @return \Illuminate\Http\Response * @return \Illuminate\Http\Response
*/ */
public function show(TaxType $taxType) public function show(TaxType $taxType)
{
//
}
/**
* Show the form for editing the specified resource.
*
* @param \Crater\TaxType $taxType
* @return \Illuminate\Http\Response
*/
public function edit(TaxType $taxType)
{ {
return response()->json([ return response()->json([
'taxType' => $taxType 'taxType' => $taxType
@ -85,19 +69,12 @@ class TaxTypeController extends Controller
* Update the specified resource in storage. * Update the specified resource in storage.
* *
* @param \Illuminate\Http\Request $request * @param \Illuminate\Http\Request $request
* @param \Crater\TaxType $taxType * @param \Crater\Models\TaxType $taxType
* @return \Illuminate\Http\Response * @return \Illuminate\Http\Response
*/ */
public function update(TaxTypeRequest $request, TaxType $taxType) public function update(TaxTypeRequest $request, TaxType $taxType)
{ {
$taxType->name = $request->name; $taxType->update($request->validated());
$taxType->percent = $request->percent;
$taxType->description = $request->description;
if ($request->has('collective_tax')) {
$taxType->collective_tax = $request->collective_tax;
}
$taxType->compound_tax = $request->compound_tax;
$taxType->save();
return response()->json([ return response()->json([
'taxType' => $taxType, 'taxType' => $taxType,
@ -107,7 +84,7 @@ class TaxTypeController extends Controller
/** /**
* Remove the specified resource from storage. * Remove the specified resource from storage.
* *
* @param \Crater\TaxType $taxType * @param \Crater\Models\TaxType $taxType
* @return \Illuminate\Http\Response * @return \Illuminate\Http\Response
*/ */
public function destroy(TaxType $taxType) public function destroy(TaxType $taxType)

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