mirror of
				https://github.com/crater-invoice/crater.git
				synced 2025-10-29 04:31:08 -04:00 
			
		
		
		
	Compare commits
	
		
			400 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| ed6268aa7b | |||
| 8a7ea53ffb | |||
| aba0a340a4 | |||
| 423e30b16e | |||
| 0cafe8c4b8 | |||
| 2a1b1ff7b7 | |||
| e498740466 | |||
| 9b66bb2b5a | |||
| 5321871cda | |||
| 4438d54401 | |||
| 8cd384d5ac | |||
| 6022e8997d | |||
| 236759ed5c | |||
| 3934025d67 | |||
| 468eb40949 | |||
| 658e125555 | |||
| 5b50dadd91 | |||
| 04fbbe7b2a | |||
| cd68d7e2ab | |||
| cb2b5f0ca3 | |||
| 887d5d0685 | |||
| 6bdd0f9477 | |||
| f99b8b4a1c | |||
| 7a45ed0982 | |||
| d066efd3ce | |||
| a6654c4519 | |||
| 90b5a1f906 | |||
| 0545cdbe6f | |||
| a4becbbc96 | |||
| faf8c804a9 | |||
| 6c1fc8e514 | |||
| 618d644c14 | |||
| deaab665dd | |||
| aa6553233a | |||
| d839962292 | |||
| 4d14b1552f | |||
| e1ef208073 | |||
| 40f3415e28 | |||
| 5c39525a2b | |||
| 3a5901c70d | |||
| d978557366 | |||
| f97868d98a | |||
| 91e369ddcc | |||
| 8806fe76ad | |||
| cfc7e2231c | |||
| 64326dd5f3 | |||
| dee14455bb | |||
| 9403fe265e | |||
| e30b99a730 | |||
| c1fb29bdbf | |||
| 6ea74a79bb | |||
| 8d94f4efbe | |||
| cc52cde16c | |||
| e16e4c6d52 | |||
| e22f60ff16 | |||
| 88bfb38b56 | |||
| f57fa41640 | |||
| 0f99568eaf | |||
| f3dad8d48b | |||
| 9629771d22 | |||
| 082d5cacf2 | |||
| d332712c22 | |||
| f434c3e0d1 | |||
| c810ad5246 | |||
| 29705662e3 | |||
| 31bfaadfad | |||
| e2299794ad | |||
| 7d71cc1607 | |||
| 40d9ecfe02 | |||
| 3d3d7d0ec0 | |||
| 63b1ee5849 | |||
| bfe13ef79d | |||
| 010c7b02ed | |||
| 81739d4db7 | |||
| 05110526a7 | |||
| 15bff7cd3f | |||
| 37470fe7a2 | |||
| 1a50aca26d | |||
| 8219d19222 | |||
| 8fa0252779 | |||
| 6bfab30f14 | |||
| d972279adc | |||
| 900a18c479 | |||
| 433c6a7c44 | |||
| 9f673d7eb3 | |||
| d3a745605e | |||
| b004e7e379 | |||
| 9893108539 | |||
| 2b80082996 | |||
| 8d596f5c19 | |||
| ce4335d8fa | |||
| 5eaea3ad59 | |||
| 375d4d428e | |||
| 2ec87baa6f | |||
| 18a2e83348 | |||
| d53e227b08 | |||
| 7721bf6f93 | |||
| 76977c3d2a | |||
| 512983deee | |||
| f5c23b33da | |||
| a0898a1fa0 | |||
| 236db087ba | |||
| 4772079d13 | |||
| 0e0ef1d99e | |||
| 3d9a73f9ec | |||
| b452c3f173 | |||
| 87667be90c | |||
| 31481739f1 | |||
| da43797d9c | |||
| e1fcf0695c | |||
| a52d5bc582 | |||
| e7bf86f9c0 | |||
| fca7d164a6 | |||
| 4b603f8823 | |||
| 4552138787 | |||
| d1dd704cdf | |||
| 00961bcae1 | |||
| 98ba17e56a | |||
| 8eb47b553e | |||
| 2fb46a4ab3 | |||
| 6fcddd6feb | |||
| 43c871f374 | |||
| 4ec9b2e817 | |||
| f2c6e06c54 | |||
| f95b292717 | |||
| 6ecd9728d4 | |||
| b2d4b7212b | |||
| b4956d38f7 | |||
| ed966b02eb | |||
| bcbffdcf30 | |||
| 3cf70135f3 | |||
| 90bb90cd99 | |||
| ebad76c8d7 | |||
| c35b00493c | |||
| e5ae937a88 | |||
| 736df5fcae | |||
| 89c264c6a9 | |||
| 1837bf3f3e | |||
| 83234cfac3 | |||
| 5ccc9eba4c | |||
| 3f0008ec95 | |||
| 9e98a96d61 | |||
| 27bc89bf76 | |||
| e4c2b44da5 | |||
| 633cad9b89 | |||
| f5bbe68a4b | |||
| 1fac9c9dde | |||
| 1208d3a924 | |||
| 3257b18d58 | |||
| 16a941f787 | |||
| 4f5cd9fba1 | |||
| 80e6a3c757 | |||
| d4e7420640 | |||
| ac30ba599b | |||
| 6dd0ccce8b | |||
| 2f32ff4d5b | |||
| 54a5ca83f8 | |||
| eede2fc17f | |||
| e586adde26 | |||
| 1ffb1b2eec | |||
| 55d838371a | |||
| cdaa1ff103 | |||
| 63f7cdec82 | |||
| fadba7fa3a | |||
| d0f6e207ee | |||
| 845f01f170 | |||
| 7f9938c80d | |||
| 16e4212300 | |||
| 109de237b1 | |||
| 82cf63f200 | |||
| 03fc0fd659 | |||
| c3d3e5e35f | |||
| 909e4f93e4 | |||
| bfd9850bf6 | |||
| 3f7db2793f | |||
| 8693672b09 | |||
| a9b0d62cd6 | |||
| 9f57a4200f | |||
| 9e130b3db8 | |||
| 7c9a846090 | |||
| b2e08dda7f | |||
| a2026fbc8b | |||
| db1b0db461 | |||
| 17c00c322d | |||
| 331b8ea44e | |||
| 428be640c3 | |||
| 51f79433b9 | |||
| 8008ed0527 | |||
| 57b302666a | |||
| ee1d1ccff4 | |||
| 81e7109ad1 | |||
| 784bf39df5 | |||
| f66755c4aa | |||
| b4e1e99d37 | |||
| d8aa3dc8a6 | |||
| 9af51660cb | |||
| 38d0da9618 | |||
| 761c0143ec | |||
| fdc4de5093 | |||
| f8591f96a9 | |||
| e47cb01ce2 | |||
| 454ad3091a | |||
| cc73a8a842 | |||
| cea8405ace | |||
| 49a6e03e9d | |||
| f9d6e8b0cc | |||
| 2b78aacc83 | |||
| 1932c5a75e | |||
| 449968ae88 | |||
| 02a2db4417 | |||
| a53582f916 | |||
| 340bf3be06 | |||
| 7f0da9dc36 | |||
| c4ace76275 | |||
| 553bcc053b | |||
| 375a59a504 | |||
| cfc0a1ef75 | |||
| 392f6f469b | |||
| 6cb8d30915 | |||
| 9b55e84724 | |||
| cf5da7684b | |||
| f47029ca78 | |||
| 761df2ffac | |||
| 8fbc257b23 | |||
| baebfedf37 | |||
| 9321eb9d86 | |||
| 70bed01e7b | |||
| 739efcce79 | |||
| 3695e7d075 | |||
| 8f2033f621 | |||
| 7b95ccb5fc | |||
| b7370ed85c | |||
| 818f2fbaf7 | |||
| 91a1dbf91c | |||
| a4d556f41e | |||
| 83de1c47ee | |||
| 678ace744a | |||
| 9e26fee1b0 | |||
| e455c3de50 | |||
| c4db50d3f0 | |||
| 411ee57946 | |||
| 9c5e9e56f5 | |||
| 8eeafd3fed | |||
| ed978d0174 | |||
| 607b1795bb | |||
| a6c3c815b5 | |||
| ead0ebb012 | |||
| d4550e62f8 | |||
| ff3846137e | |||
| b55f8e5391 | |||
| 0f1d7627ea | |||
| 1be462ef82 | |||
| 8b04e94446 | |||
| fa512629d9 | |||
| 0f99be6cf1 | |||
| fae3af2592 | |||
| d1e70c8989 | |||
| 63094e8112 | |||
| 1b46bddf56 | |||
| 422bf74600 | |||
| d003e61d41 | |||
| 09f74eb37c | |||
| 9227973a7a | |||
| 5011543198 | |||
| d07b63c365 | |||
| c12e27dbfe | |||
| 4ea32b94ed | |||
| fe93d5236c | |||
| 5992394bca | |||
| 6c9f5800e5 | |||
| 227cebcb0b | |||
| 6fd4cc6b3f | |||
| 594c8965c1 | |||
| 2241145a17 | |||
| 34f252b1c9 | |||
| 89e1d7bc84 | |||
| f0368deda2 | |||
| 4028551fd8 | |||
| 06f385a28e | |||
| 44aeff425b | |||
| 35a38d719c | |||
| f6ba81e8b7 | |||
| 64cb55fd5d | |||
| 13fe38517c | |||
| 3bdb501d1d | |||
| b8adbf4b07 | |||
| aa85a9950c | |||
| 8e63efee1b | |||
| ea98f03aeb | |||
| 90cd6226be | |||
| 9d2df64b2e | |||
| bade86a24f | |||
| c3b57b4888 | |||
| fcfedc5414 | |||
| 8dee0da434 | |||
| e4ab024422 | |||
| 2bd01c4014 | |||
| 034c7e385c | |||
| c9086747a3 | |||
| ab1ed269fd | |||
| f7a823e9bc | |||
| b6301b08f8 | |||
| 265c219fdc | |||
| 729db694a3 | |||
| e2e6415cb6 | |||
| 419104a4ec | |||
| f18eac2001 | |||
| 7bffbe59ed | |||
| bf53b4f5eb | |||
| 21440230f3 | |||
| 99c27ba8ef | |||
| cb7a925cd0 | |||
| d2e11bd7df | |||
| 1b74a3720e | |||
| e222af335e | |||
| 599e6270e8 | |||
| da7ddcd4f1 | |||
| bd01039fb8 | |||
| 718f01ccd4 | |||
| fd3742b926 | |||
| e8b954d1bd | |||
| 58042decd5 | |||
| fa500b3865 | |||
| e03924fe9d | |||
| 3f308a2d3b | |||
| 6cdd93bab0 | |||
| 69c6c883c2 | |||
| 69dcf1299b | |||
| b6cd78ca4c | |||
| d18116bd7d | |||
| 6b30c2028b | |||
| 8c4a358072 | |||
| fe8482fc71 | |||
| 28217df654 | |||
| 3723697add | |||
| b3e3839fb5 | |||
| 89ee58590c | |||
| 326508e567 | |||
| 21e01bc1db | |||
| ed58dfaef6 | |||
| c2c0e2809c | |||
| bafda5ca46 | |||
| a7eaf5dbe4 | |||
| 805a287129 | |||
| 61fe16cab4 | |||
| 33085a0e3c | |||
| 2df09a20f1 | |||
| a7d61b802d | |||
| 88bcb1c2b4 | |||
| af194c1851 | |||
| 71193727c9 | |||
| bc7571832a | |||
| e379e13802 | |||
| 4484765358 | |||
| 5d4ea2a308 | |||
| 0db9f9df0c | |||
| 9301e67e3f | |||
| a019403b1b | |||
| c99d7ee677 | |||
| 94a2306b7f | |||
| 73bd28aeb8 | |||
| 904f2641c5 | |||
| 4372195547 | |||
| 14f8094a9d | |||
| 4770c27d7d | |||
| f4baf308a4 | |||
| 6f852ab88a | |||
| 14bb6edec8 | |||
| b4a7c724db | |||
| 9fb4b4dec5 | |||
| 4bbc92ccaf | |||
| dd12662b17 | |||
| c364de1b17 | |||
| a06e8e3039 | |||
| b9021cb664 | |||
| a2c3fa2cc5 | |||
| 517f3bd1b8 | |||
| 29b4b92fab | |||
| e8f046f02e | |||
| 2bf6778c8a | |||
| e11c713ce3 | |||
| b7189595bd | |||
| c5d4a62930 | |||
| 378f216f6d | |||
| 7654c30b1b | |||
| f4767ffb26 | |||
| e06639daa5 | |||
| 9bd23ffac8 | |||
| 60f5d29570 | |||
| b2497e5f81 | |||
| 771a447e2c | |||
| a964f1d841 | |||
| 57d5356bfe | |||
| fd29487121 | |||
| 5fb6797577 | |||
| 3d0f77ab0b | |||
| dbc249b6bc | |||
| 08c6218440 | |||
| 737c933b8c | |||
| b9ab87a308 | 
| @ -20,3 +20,6 @@ indent_size = 2 | |||||||
|  |  | ||||||
| [*.js] | [*.js] | ||||||
| indent_size = 2 | indent_size = 2 | ||||||
|  |  | ||||||
|  | [*.json] | ||||||
|  | indent_size = 2 | ||||||
|  | |||||||
							
								
								
									
										10
									
								
								.env.example
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								.env.example
									
									
									
									
									
								
							| @ -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,7 @@ 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 |  | ||||||
|  | TRUSTED_PROXIES="*" | ||||||
|  | |||||||
| @ -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@craterapp.com" | ||||||
|  | MAIL_FROM_NAME="John Doe" | ||||||
|  | |||||||
							
								
								
									
										18
									
								
								.eslintrc
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								.eslintrc
									
									
									
									
									
								
							| @ -1,18 +0,0 @@ | |||||||
| { |  | ||||||
|   "root": true, |  | ||||||
|   "extends": [ |  | ||||||
|     "plugin:vue/recommended", |  | ||||||
|     "eslint:recommended", |  | ||||||
|     "prettier/vue", |  | ||||||
|     "plugin:prettier/recommended" |  | ||||||
|   ], |  | ||||||
|   "rules": { |  | ||||||
|     "vue/max-attributes-per-line": ["error", { |  | ||||||
|       "singleline": 10, |  | ||||||
|       "multiline": { |  | ||||||
|         "max": 1, |  | ||||||
|         "allowFirstLine": false |  | ||||||
|       } |  | ||||||
|     }]     |  | ||||||
|   } |  | ||||||
| } |  | ||||||
							
								
								
									
										14
									
								
								.eslintrc.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								.eslintrc.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,14 @@ | |||||||
|  | // .eslintrc.js | ||||||
|  |  | ||||||
|  | module.exports = { | ||||||
|  |   extends: [ | ||||||
|  |     // add more generic rulesets here, such as: | ||||||
|  |     // 'eslint:recommended', | ||||||
|  |     "plugin:vue/vue3-recommended", | ||||||
|  |     "prettier", | ||||||
|  |   ], | ||||||
|  |   rules: { | ||||||
|  |     // override/add rules settings here, such as: | ||||||
|  |     // 'vue/no-unused-vars': 'error' | ||||||
|  |   }, | ||||||
|  | }; | ||||||
							
								
								
									
										37
									
								
								.github/workflows/ci.yaml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								.github/workflows/ci.yaml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,37 @@ | |||||||
|  | name: CI | ||||||
|  |  | ||||||
|  | on: [push, pull_request] | ||||||
|  |  | ||||||
|  | jobs: | ||||||
|  |   build-test: | ||||||
|  |     runs-on: ubuntu-latest | ||||||
|  |     strategy: | ||||||
|  |       fail-fast: false | ||||||
|  |       matrix: | ||||||
|  |         php: ['7.4', '8.0'] | ||||||
|  |  | ||||||
|  |     name: PHP ${{ matrix.php }} | ||||||
|  |  | ||||||
|  |     steps: | ||||||
|  |     - name: Checkout | ||||||
|  |       uses: actions/checkout@v2 | ||||||
|  |  | ||||||
|  |     - name: Install dependencies | ||||||
|  |       uses: shivammathur/setup-php@v2 | ||||||
|  |       with: | ||||||
|  |         php-version: ${{ matrix.php }} | ||||||
|  |         extensions: exif | ||||||
|  |  | ||||||
|  |     - name: Install PHP 7 dependencies | ||||||
|  |       run: composer update --no-interaction --no-progress | ||||||
|  |       if: "matrix.php < 8" | ||||||
|  |  | ||||||
|  |     - name: Install PHP 8 dependencies | ||||||
|  |       run: composer update --ignore-platform-req=php --no-interaction --no-progress | ||||||
|  |       if: "matrix.php >= 8" | ||||||
|  |  | ||||||
|  |     - name: Check coding style | ||||||
|  |       run: ./vendor/bin/php-cs-fixer fix -v --dry-run --using-cache=no --config=.php-cs-fixer.dist.php | ||||||
|  |  | ||||||
|  |     - name: Unit Tests | ||||||
|  |       run: php ./vendor/bin/pest | ||||||
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -11,3 +11,4 @@ Homestead.yaml | |||||||
| .rnd | .rnd | ||||||
| /.expo | /.expo | ||||||
| /.vscode | /.vscode | ||||||
|  | /docker-compose/db/data/ | ||||||
|  | |||||||
							
								
								
									
										42
									
								
								.php-cs-fixer.dist.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								.php-cs-fixer.dist.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,42 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | $finder = PhpCsFixer\Finder::create() | ||||||
|  |     ->in(__DIR__) | ||||||
|  |     ->exclude(['bootstrap', 'storage', 'vendor']) | ||||||
|  |     ->name('*.php') | ||||||
|  |     ->name('_ide_helper') | ||||||
|  |     ->notName('*.blade.php') | ||||||
|  |     ->ignoreDotFiles(true) | ||||||
|  |     ->ignoreVCS(true); | ||||||
|  |  | ||||||
|  | $rules = [ | ||||||
|  |     '@PSR12' => true, | ||||||
|  |     'array_syntax' => ['syntax' => 'short'], | ||||||
|  |     'ordered_imports' => ['sort_algorithm' => 'alpha'], | ||||||
|  |     'concat_space' => true, | ||||||
|  |     'no_unused_imports' => true, | ||||||
|  |     'not_operator_with_successor_space' => true, | ||||||
|  |     'phpdoc_scalar' => true, | ||||||
|  |     'unary_operator_spaces' => true, | ||||||
|  |     'binary_operator_spaces' => true, | ||||||
|  |     'blank_line_before_statement' => [ | ||||||
|  |         'statements' => ['break', 'continue', 'declare', 'return', 'throw', 'try'], | ||||||
|  |     ], | ||||||
|  |     'phpdoc_single_line_var_spacing' => true, | ||||||
|  |     'phpdoc_var_without_name' => true, | ||||||
|  |     'class_attributes_separation' => [ | ||||||
|  |         'elements' => [ | ||||||
|  |             'method' => 'one', | ||||||
|  |             'property' => 'one', | ||||||
|  |         ], | ||||||
|  |     ], | ||||||
|  |     'method_argument_space' => [ | ||||||
|  |         'on_multiline' => 'ensure_fully_multiline', | ||||||
|  |         'keep_multiple_spaces_after_comma' => true, | ||||||
|  |     ], | ||||||
|  | ]; | ||||||
|  |  | ||||||
|  | return (new PhpCsFixer\Config()) | ||||||
|  |     ->setUsingCache(true) | ||||||
|  |     ->setRules($rules) | ||||||
|  |     ->setFinder($finder); | ||||||
| @ -14,7 +14,8 @@ RUN apt-get update && apt-get install -y \ | |||||||
|     zip \ |     zip \ | ||||||
|     unzip \ |     unzip \ | ||||||
|     libzip-dev \ |     libzip-dev \ | ||||||
|     libmagickwand-dev |     libmagickwand-dev \ | ||||||
|  |     mariadb-client | ||||||
|  |  | ||||||
| # Clear cache | # Clear cache | ||||||
| RUN apt-get clean && rm -rf /var/lib/apt/lists/* | RUN apt-get clean && rm -rf /var/lib/apt/lists/* | ||||||
|  | |||||||
							
								
								
									
										702
									
								
								LICENSE
									
									
									
									
									
								
							
							
						
						
									
										702
									
								
								LICENSE
									
									
									
									
									
								
							| @ -1,47 +1,661 @@ | |||||||
| Copyright (c) 2019 by Bytefury |                     GNU AFFERO GENERAL PUBLIC LICENSE | ||||||
| Crater Invoice * https://www.craterapp.com |                        Version 3, 19 November 2007 | ||||||
| "Easy Invoicing" |  | ||||||
|  |  | ||||||
| All Rights Reserved |  Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> | ||||||
| ATTRIBUTION ASSURANCE LICENSE (adapted from the original BSD license) |  Everyone is permitted to copy and distribute verbatim copies | ||||||
| Redistribution and use in source and binary forms, with or without |  of this license document, but changing it is not allowed. | ||||||
| modification, are permitted provided that the conditions below are met. |  | ||||||
| These conditions require a modest attribution to CraterApp.com (the |  | ||||||
| "Author"), who hopes that its promotional value may help justify the |  | ||||||
| thousands of dollars in otherwise billable time invested in writing |  | ||||||
| this and other freely available, open-source software. |  | ||||||
|  |  | ||||||
| 1. Redistributions of source code, in whole or part and with or without |                             Preamble | ||||||
| modification (the "Code"), must prominently display this GPG-signed |  | ||||||
| text in verifiable form. |  | ||||||
| 2. Redistributions of the Code in binary form must be accompanied by |  | ||||||
| this GPG-signed text in any documentation and, each time the resulting |  | ||||||
| executable program or a program dependent thereon is launched, a |  | ||||||
| prominent display (e.g., splash screen or banner text) of the Author's |  | ||||||
| attribution information, which includes: |  | ||||||
| (a) Name ("Bytefury"), |  | ||||||
| (b) Professional identification ("Crater Invoice"), and |  | ||||||
| (c) URL ("https://www.craterapp.com"). |  | ||||||
| 3. Neither the name nor any trademark of the Author may be used to |  | ||||||
| endorse or promote products derived from this software without specific |  | ||||||
| prior written permission. |  | ||||||
| 4. Users are entirely responsible, to the exclusion of the Author and |  | ||||||
| any other persons, for compliance with (1) regulations set by owners or |  | ||||||
| administrators of employed equipment, (2) licensing terms of any other |  | ||||||
| software, and (3) local regulations regarding use, including those |  | ||||||
| regarding import, export, and use of encryption software. |  | ||||||
|  |  | ||||||
| THIS FREE SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND |   The GNU Affero General Public License is a free, copyleft license for | ||||||
| ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | software and other kinds of works, specifically designed to ensure | ||||||
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND | cooperation with the community in the case of network server software. | ||||||
| FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO |  | ||||||
| EVENT SHALL THE AUTHOR OR ANY CONTRIBUTOR BE LIABLE FOR |   The licenses for most software and other practical works are designed | ||||||
| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | to take away your freedom to share and change the works.  By contrast, | ||||||
| CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | our General Public Licenses are intended to guarantee your freedom to | ||||||
| EFFECTS OF UNAUTHORIZED OR MALICIOUS NETWORK ACCESS; | share and change all versions of a program--to make sure it remains free | ||||||
| PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | software for all its users. | ||||||
| DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |  | ||||||
| AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |   When we speak of free software, we are referring to freedom, not | ||||||
| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | price.  Our General Public Licenses are designed to make sure that you | ||||||
| ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN | have the freedom to distribute copies of free software (and charge for | ||||||
| IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | them if you wish), that you receive source code or can get it if you | ||||||
|  | want it, that you can change the software or use pieces of it in new | ||||||
|  | free programs, and that you know you can do these things. | ||||||
|  |  | ||||||
|  |   Developers that use our General Public Licenses protect your rights | ||||||
|  | with two steps: (1) assert copyright on the software, and (2) offer | ||||||
|  | you this License which gives you legal permission to copy, distribute | ||||||
|  | and/or modify the software. | ||||||
|  |  | ||||||
|  |   A secondary benefit of defending all users' freedom is that | ||||||
|  | improvements made in alternate versions of the program, if they | ||||||
|  | receive widespread use, become available for other developers to | ||||||
|  | incorporate.  Many developers of free software are heartened and | ||||||
|  | encouraged by the resulting cooperation.  However, in the case of | ||||||
|  | software used on network servers, this result may fail to come about. | ||||||
|  | The GNU General Public License permits making a modified version and | ||||||
|  | letting the public access it on a server without ever releasing its | ||||||
|  | source code to the public. | ||||||
|  |  | ||||||
|  |   The GNU Affero General Public License is designed specifically to | ||||||
|  | ensure that, in such cases, the modified source code becomes available | ||||||
|  | to the community.  It requires the operator of a network server to | ||||||
|  | provide the source code of the modified version running there to the | ||||||
|  | users of that server.  Therefore, public use of a modified version, on | ||||||
|  | a publicly accessible server, gives the public access to the source | ||||||
|  | code of the modified version. | ||||||
|  |  | ||||||
|  |   An older license, called the Affero General Public License and | ||||||
|  | published by Affero, was designed to accomplish similar goals.  This is | ||||||
|  | a different license, not a version of the Affero GPL, but Affero has | ||||||
|  | released a new version of the Affero GPL which permits relicensing under | ||||||
|  | this license. | ||||||
|  |  | ||||||
|  |   The precise terms and conditions for copying, distribution and | ||||||
|  | modification follow. | ||||||
|  |  | ||||||
|  |                        TERMS AND CONDITIONS | ||||||
|  |  | ||||||
|  |   0. Definitions. | ||||||
|  |  | ||||||
|  |   "This License" refers to version 3 of the GNU Affero General Public License. | ||||||
|  |  | ||||||
|  |   "Copyright" also means copyright-like laws that apply to other kinds of | ||||||
|  | works, such as semiconductor masks. | ||||||
|  |  | ||||||
|  |   "The Program" refers to any copyrightable work licensed under this | ||||||
|  | License.  Each licensee is addressed as "you".  "Licensees" and | ||||||
|  | "recipients" may be individuals or organizations. | ||||||
|  |  | ||||||
|  |   To "modify" a work means to copy from or adapt all or part of the work | ||||||
|  | in a fashion requiring copyright permission, other than the making of an | ||||||
|  | exact copy.  The resulting work is called a "modified version" of the | ||||||
|  | earlier work or a work "based on" the earlier work. | ||||||
|  |  | ||||||
|  |   A "covered work" means either the unmodified Program or a work based | ||||||
|  | on the Program. | ||||||
|  |  | ||||||
|  |   To "propagate" a work means to do anything with it that, without | ||||||
|  | permission, would make you directly or secondarily liable for | ||||||
|  | infringement under applicable copyright law, except executing it on a | ||||||
|  | computer or modifying a private copy.  Propagation includes copying, | ||||||
|  | distribution (with or without modification), making available to the | ||||||
|  | public, and in some countries other activities as well. | ||||||
|  |  | ||||||
|  |   To "convey" a work means any kind of propagation that enables other | ||||||
|  | parties to make or receive copies.  Mere interaction with a user through | ||||||
|  | a computer network, with no transfer of a copy, is not conveying. | ||||||
|  |  | ||||||
|  |   An interactive user interface displays "Appropriate Legal Notices" | ||||||
|  | to the extent that it includes a convenient and prominently visible | ||||||
|  | feature that (1) displays an appropriate copyright notice, and (2) | ||||||
|  | tells the user that there is no warranty for the work (except to the | ||||||
|  | extent that warranties are provided), that licensees may convey the | ||||||
|  | work under this License, and how to view a copy of this License.  If | ||||||
|  | the interface presents a list of user commands or options, such as a | ||||||
|  | menu, a prominent item in the list meets this criterion. | ||||||
|  |  | ||||||
|  |   1. Source Code. | ||||||
|  |  | ||||||
|  |   The "source code" for a work means the preferred form of the work | ||||||
|  | for making modifications to it.  "Object code" means any non-source | ||||||
|  | form of a work. | ||||||
|  |  | ||||||
|  |   A "Standard Interface" means an interface that either is an official | ||||||
|  | standard defined by a recognized standards body, or, in the case of | ||||||
|  | interfaces specified for a particular programming language, one that | ||||||
|  | is widely used among developers working in that language. | ||||||
|  |  | ||||||
|  |   The "System Libraries" of an executable work include anything, other | ||||||
|  | than the work as a whole, that (a) is included in the normal form of | ||||||
|  | packaging a Major Component, but which is not part of that Major | ||||||
|  | Component, and (b) serves only to enable use of the work with that | ||||||
|  | Major Component, or to implement a Standard Interface for which an | ||||||
|  | implementation is available to the public in source code form.  A | ||||||
|  | "Major Component", in this context, means a major essential component | ||||||
|  | (kernel, window system, and so on) of the specific operating system | ||||||
|  | (if any) on which the executable work runs, or a compiler used to | ||||||
|  | produce the work, or an object code interpreter used to run it. | ||||||
|  |  | ||||||
|  |   The "Corresponding Source" for a work in object code form means all | ||||||
|  | the source code needed to generate, install, and (for an executable | ||||||
|  | work) run the object code and to modify the work, including scripts to | ||||||
|  | control those activities.  However, it does not include the work's | ||||||
|  | System Libraries, or general-purpose tools or generally available free | ||||||
|  | programs which are used unmodified in performing those activities but | ||||||
|  | which are not part of the work.  For example, Corresponding Source | ||||||
|  | includes interface definition files associated with source files for | ||||||
|  | the work, and the source code for shared libraries and dynamically | ||||||
|  | linked subprograms that the work is specifically designed to require, | ||||||
|  | such as by intimate data communication or control flow between those | ||||||
|  | subprograms and other parts of the work. | ||||||
|  |  | ||||||
|  |   The Corresponding Source need not include anything that users | ||||||
|  | can regenerate automatically from other parts of the Corresponding | ||||||
|  | Source. | ||||||
|  |  | ||||||
|  |   The Corresponding Source for a work in source code form is that | ||||||
|  | same work. | ||||||
|  |  | ||||||
|  |   2. Basic Permissions. | ||||||
|  |  | ||||||
|  |   All rights granted under this License are granted for the term of | ||||||
|  | copyright on the Program, and are irrevocable provided the stated | ||||||
|  | conditions are met.  This License explicitly affirms your unlimited | ||||||
|  | permission to run the unmodified Program.  The output from running a | ||||||
|  | covered work is covered by this License only if the output, given its | ||||||
|  | content, constitutes a covered work.  This License acknowledges your | ||||||
|  | rights of fair use or other equivalent, as provided by copyright law. | ||||||
|  |  | ||||||
|  |   You may make, run and propagate covered works that you do not | ||||||
|  | convey, without conditions so long as your license otherwise remains | ||||||
|  | in force.  You may convey covered works to others for the sole purpose | ||||||
|  | of having them make modifications exclusively for you, or provide you | ||||||
|  | with facilities for running those works, provided that you comply with | ||||||
|  | the terms of this License in conveying all material for which you do | ||||||
|  | not control copyright.  Those thus making or running the covered works | ||||||
|  | for you must do so exclusively on your behalf, under your direction | ||||||
|  | and control, on terms that prohibit them from making any copies of | ||||||
|  | your copyrighted material outside their relationship with you. | ||||||
|  |  | ||||||
|  |   Conveying under any other circumstances is permitted solely under | ||||||
|  | the conditions stated below.  Sublicensing is not allowed; section 10 | ||||||
|  | makes it unnecessary. | ||||||
|  |  | ||||||
|  |   3. Protecting Users' Legal Rights From Anti-Circumvention Law. | ||||||
|  |  | ||||||
|  |   No covered work shall be deemed part of an effective technological | ||||||
|  | measure under any applicable law fulfilling obligations under article | ||||||
|  | 11 of the WIPO copyright treaty adopted on 20 December 1996, or | ||||||
|  | similar laws prohibiting or restricting circumvention of such | ||||||
|  | measures. | ||||||
|  |  | ||||||
|  |   When you convey a covered work, you waive any legal power to forbid | ||||||
|  | circumvention of technological measures to the extent such circumvention | ||||||
|  | is effected by exercising rights under this License with respect to | ||||||
|  | the covered work, and you disclaim any intention to limit operation or | ||||||
|  | modification of the work as a means of enforcing, against the work's | ||||||
|  | users, your or third parties' legal rights to forbid circumvention of | ||||||
|  | technological measures. | ||||||
|  |  | ||||||
|  |   4. Conveying Verbatim Copies. | ||||||
|  |  | ||||||
|  |   You may convey verbatim copies of the Program's source code as you | ||||||
|  | receive it, in any medium, provided that you conspicuously and | ||||||
|  | appropriately publish on each copy an appropriate copyright notice; | ||||||
|  | keep intact all notices stating that this License and any | ||||||
|  | non-permissive terms added in accord with section 7 apply to the code; | ||||||
|  | keep intact all notices of the absence of any warranty; and give all | ||||||
|  | recipients a copy of this License along with the Program. | ||||||
|  |  | ||||||
|  |   You may charge any price or no price for each copy that you convey, | ||||||
|  | and you may offer support or warranty protection for a fee. | ||||||
|  |  | ||||||
|  |   5. Conveying Modified Source Versions. | ||||||
|  |  | ||||||
|  |   You may convey a work based on the Program, or the modifications to | ||||||
|  | produce it from the Program, in the form of source code under the | ||||||
|  | terms of section 4, provided that you also meet all of these conditions: | ||||||
|  |  | ||||||
|  |     a) The work must carry prominent notices stating that you modified | ||||||
|  |     it, and giving a relevant date. | ||||||
|  |  | ||||||
|  |     b) The work must carry prominent notices stating that it is | ||||||
|  |     released under this License and any conditions added under section | ||||||
|  |     7.  This requirement modifies the requirement in section 4 to | ||||||
|  |     "keep intact all notices". | ||||||
|  |  | ||||||
|  |     c) You must license the entire work, as a whole, under this | ||||||
|  |     License to anyone who comes into possession of a copy.  This | ||||||
|  |     License will therefore apply, along with any applicable section 7 | ||||||
|  |     additional terms, to the whole of the work, and all its parts, | ||||||
|  |     regardless of how they are packaged.  This License gives no | ||||||
|  |     permission to license the work in any other way, but it does not | ||||||
|  |     invalidate such permission if you have separately received it. | ||||||
|  |  | ||||||
|  |     d) If the work has interactive user interfaces, each must display | ||||||
|  |     Appropriate Legal Notices; however, if the Program has interactive | ||||||
|  |     interfaces that do not display Appropriate Legal Notices, your | ||||||
|  |     work need not make them do so. | ||||||
|  |  | ||||||
|  |   A compilation of a covered work with other separate and independent | ||||||
|  | works, which are not by their nature extensions of the covered work, | ||||||
|  | and which are not combined with it such as to form a larger program, | ||||||
|  | in or on a volume of a storage or distribution medium, is called an | ||||||
|  | "aggregate" if the compilation and its resulting copyright are not | ||||||
|  | used to limit the access or legal rights of the compilation's users | ||||||
|  | beyond what the individual works permit.  Inclusion of a covered work | ||||||
|  | in an aggregate does not cause this License to apply to the other | ||||||
|  | parts of the aggregate. | ||||||
|  |  | ||||||
|  |   6. Conveying Non-Source Forms. | ||||||
|  |  | ||||||
|  |   You may convey a covered work in object code form under the terms | ||||||
|  | of sections 4 and 5, provided that you also convey the | ||||||
|  | machine-readable Corresponding Source under the terms of this License, | ||||||
|  | in one of these ways: | ||||||
|  |  | ||||||
|  |     a) Convey the object code in, or embodied in, a physical product | ||||||
|  |     (including a physical distribution medium), accompanied by the | ||||||
|  |     Corresponding Source fixed on a durable physical medium | ||||||
|  |     customarily used for software interchange. | ||||||
|  |  | ||||||
|  |     b) Convey the object code in, or embodied in, a physical product | ||||||
|  |     (including a physical distribution medium), accompanied by a | ||||||
|  |     written offer, valid for at least three years and valid for as | ||||||
|  |     long as you offer spare parts or customer support for that product | ||||||
|  |     model, to give anyone who possesses the object code either (1) a | ||||||
|  |     copy of the Corresponding Source for all the software in the | ||||||
|  |     product that is covered by this License, on a durable physical | ||||||
|  |     medium customarily used for software interchange, for a price no | ||||||
|  |     more than your reasonable cost of physically performing this | ||||||
|  |     conveying of source, or (2) access to copy the | ||||||
|  |     Corresponding Source from a network server at no charge. | ||||||
|  |  | ||||||
|  |     c) Convey individual copies of the object code with a copy of the | ||||||
|  |     written offer to provide the Corresponding Source.  This | ||||||
|  |     alternative is allowed only occasionally and noncommercially, and | ||||||
|  |     only if you received the object code with such an offer, in accord | ||||||
|  |     with subsection 6b. | ||||||
|  |  | ||||||
|  |     d) Convey the object code by offering access from a designated | ||||||
|  |     place (gratis or for a charge), and offer equivalent access to the | ||||||
|  |     Corresponding Source in the same way through the same place at no | ||||||
|  |     further charge.  You need not require recipients to copy the | ||||||
|  |     Corresponding Source along with the object code.  If the place to | ||||||
|  |     copy the object code is a network server, the Corresponding Source | ||||||
|  |     may be on a different server (operated by you or a third party) | ||||||
|  |     that supports equivalent copying facilities, provided you maintain | ||||||
|  |     clear directions next to the object code saying where to find the | ||||||
|  |     Corresponding Source.  Regardless of what server hosts the | ||||||
|  |     Corresponding Source, you remain obligated to ensure that it is | ||||||
|  |     available for as long as needed to satisfy these requirements. | ||||||
|  |  | ||||||
|  |     e) Convey the object code using peer-to-peer transmission, provided | ||||||
|  |     you inform other peers where the object code and Corresponding | ||||||
|  |     Source of the work are being offered to the general public at no | ||||||
|  |     charge under subsection 6d. | ||||||
|  |  | ||||||
|  |   A separable portion of the object code, whose source code is excluded | ||||||
|  | from the Corresponding Source as a System Library, need not be | ||||||
|  | included in conveying the object code work. | ||||||
|  |  | ||||||
|  |   A "User Product" is either (1) a "consumer product", which means any | ||||||
|  | tangible personal property which is normally used for personal, family, | ||||||
|  | or household purposes, or (2) anything designed or sold for incorporation | ||||||
|  | into a dwelling.  In determining whether a product is a consumer product, | ||||||
|  | doubtful cases shall be resolved in favor of coverage.  For a particular | ||||||
|  | product received by a particular user, "normally used" refers to a | ||||||
|  | typical or common use of that class of product, regardless of the status | ||||||
|  | of the particular user or of the way in which the particular user | ||||||
|  | actually uses, or expects or is expected to use, the product.  A product | ||||||
|  | is a consumer product regardless of whether the product has substantial | ||||||
|  | commercial, industrial or non-consumer uses, unless such uses represent | ||||||
|  | the only significant mode of use of the product. | ||||||
|  |  | ||||||
|  |   "Installation Information" for a User Product means any methods, | ||||||
|  | procedures, authorization keys, or other information required to install | ||||||
|  | and execute modified versions of a covered work in that User Product from | ||||||
|  | a modified version of its Corresponding Source.  The information must | ||||||
|  | suffice to ensure that the continued functioning of the modified object | ||||||
|  | code is in no case prevented or interfered with solely because | ||||||
|  | modification has been made. | ||||||
|  |  | ||||||
|  |   If you convey an object code work under this section in, or with, or | ||||||
|  | specifically for use in, a User Product, and the conveying occurs as | ||||||
|  | part of a transaction in which the right of possession and use of the | ||||||
|  | User Product is transferred to the recipient in perpetuity or for a | ||||||
|  | fixed term (regardless of how the transaction is characterized), the | ||||||
|  | Corresponding Source conveyed under this section must be accompanied | ||||||
|  | by the Installation Information.  But this requirement does not apply | ||||||
|  | if neither you nor any third party retains the ability to install | ||||||
|  | modified object code on the User Product (for example, the work has | ||||||
|  | been installed in ROM). | ||||||
|  |  | ||||||
|  |   The requirement to provide Installation Information does not include a | ||||||
|  | requirement to continue to provide support service, warranty, or updates | ||||||
|  | for a work that has been modified or installed by the recipient, or for | ||||||
|  | the User Product in which it has been modified or installed.  Access to a | ||||||
|  | network may be denied when the modification itself materially and | ||||||
|  | adversely affects the operation of the network or violates the rules and | ||||||
|  | protocols for communication across the network. | ||||||
|  |  | ||||||
|  |   Corresponding Source conveyed, and Installation Information provided, | ||||||
|  | in accord with this section must be in a format that is publicly | ||||||
|  | documented (and with an implementation available to the public in | ||||||
|  | source code form), and must require no special password or key for | ||||||
|  | unpacking, reading or copying. | ||||||
|  |  | ||||||
|  |   7. Additional Terms. | ||||||
|  |  | ||||||
|  |   "Additional permissions" are terms that supplement the terms of this | ||||||
|  | License by making exceptions from one or more of its conditions. | ||||||
|  | Additional permissions that are applicable to the entire Program shall | ||||||
|  | be treated as though they were included in this License, to the extent | ||||||
|  | that they are valid under applicable law.  If additional permissions | ||||||
|  | apply only to part of the Program, that part may be used separately | ||||||
|  | under those permissions, but the entire Program remains governed by | ||||||
|  | this License without regard to the additional permissions. | ||||||
|  |  | ||||||
|  |   When you convey a copy of a covered work, you may at your option | ||||||
|  | remove any additional permissions from that copy, or from any part of | ||||||
|  | it.  (Additional permissions may be written to require their own | ||||||
|  | removal in certain cases when you modify the work.)  You may place | ||||||
|  | additional permissions on material, added by you to a covered work, | ||||||
|  | for which you have or can give appropriate copyright permission. | ||||||
|  |  | ||||||
|  |   Notwithstanding any other provision of this License, for material you | ||||||
|  | add to a covered work, you may (if authorized by the copyright holders of | ||||||
|  | that material) supplement the terms of this License with terms: | ||||||
|  |  | ||||||
|  |     a) Disclaiming warranty or limiting liability differently from the | ||||||
|  |     terms of sections 15 and 16 of this License; or | ||||||
|  |  | ||||||
|  |     b) Requiring preservation of specified reasonable legal notices or | ||||||
|  |     author attributions in that material or in the Appropriate Legal | ||||||
|  |     Notices displayed by works containing it; or | ||||||
|  |  | ||||||
|  |     c) Prohibiting misrepresentation of the origin of that material, or | ||||||
|  |     requiring that modified versions of such material be marked in | ||||||
|  |     reasonable ways as different from the original version; or | ||||||
|  |  | ||||||
|  |     d) Limiting the use for publicity purposes of names of licensors or | ||||||
|  |     authors of the material; or | ||||||
|  |  | ||||||
|  |     e) Declining to grant rights under trademark law for use of some | ||||||
|  |     trade names, trademarks, or service marks; or | ||||||
|  |  | ||||||
|  |     f) Requiring indemnification of licensors and authors of that | ||||||
|  |     material by anyone who conveys the material (or modified versions of | ||||||
|  |     it) with contractual assumptions of liability to the recipient, for | ||||||
|  |     any liability that these contractual assumptions directly impose on | ||||||
|  |     those licensors and authors. | ||||||
|  |  | ||||||
|  |   All other non-permissive additional terms are considered "further | ||||||
|  | restrictions" within the meaning of section 10.  If the Program as you | ||||||
|  | received it, or any part of it, contains a notice stating that it is | ||||||
|  | governed by this License along with a term that is a further | ||||||
|  | restriction, you may remove that term.  If a license document contains | ||||||
|  | a further restriction but permits relicensing or conveying under this | ||||||
|  | License, you may add to a covered work material governed by the terms | ||||||
|  | of that license document, provided that the further restriction does | ||||||
|  | not survive such relicensing or conveying. | ||||||
|  |  | ||||||
|  |   If you add terms to a covered work in accord with this section, you | ||||||
|  | must place, in the relevant source files, a statement of the | ||||||
|  | additional terms that apply to those files, or a notice indicating | ||||||
|  | where to find the applicable terms. | ||||||
|  |  | ||||||
|  |   Additional terms, permissive or non-permissive, may be stated in the | ||||||
|  | form of a separately written license, or stated as exceptions; | ||||||
|  | the above requirements apply either way. | ||||||
|  |  | ||||||
|  |   8. Termination. | ||||||
|  |  | ||||||
|  |   You may not propagate or modify a covered work except as expressly | ||||||
|  | provided under this License.  Any attempt otherwise to propagate or | ||||||
|  | modify it is void, and will automatically terminate your rights under | ||||||
|  | this License (including any patent licenses granted under the third | ||||||
|  | paragraph of section 11). | ||||||
|  |  | ||||||
|  |   However, if you cease all violation of this License, then your | ||||||
|  | license from a particular copyright holder is reinstated (a) | ||||||
|  | provisionally, unless and until the copyright holder explicitly and | ||||||
|  | finally terminates your license, and (b) permanently, if the copyright | ||||||
|  | holder fails to notify you of the violation by some reasonable means | ||||||
|  | prior to 60 days after the cessation. | ||||||
|  |  | ||||||
|  |   Moreover, your license from a particular copyright holder is | ||||||
|  | reinstated permanently if the copyright holder notifies you of the | ||||||
|  | violation by some reasonable means, this is the first time you have | ||||||
|  | received notice of violation of this License (for any work) from that | ||||||
|  | copyright holder, and you cure the violation prior to 30 days after | ||||||
|  | your receipt of the notice. | ||||||
|  |  | ||||||
|  |   Termination of your rights under this section does not terminate the | ||||||
|  | licenses of parties who have received copies or rights from you under | ||||||
|  | this License.  If your rights have been terminated and not permanently | ||||||
|  | reinstated, you do not qualify to receive new licenses for the same | ||||||
|  | material under section 10. | ||||||
|  |  | ||||||
|  |   9. Acceptance Not Required for Having Copies. | ||||||
|  |  | ||||||
|  |   You are not required to accept this License in order to receive or | ||||||
|  | run a copy of the Program.  Ancillary propagation of a covered work | ||||||
|  | occurring solely as a consequence of using peer-to-peer transmission | ||||||
|  | to receive a copy likewise does not require acceptance.  However, | ||||||
|  | nothing other than this License grants you permission to propagate or | ||||||
|  | modify any covered work.  These actions infringe copyright if you do | ||||||
|  | not accept this License.  Therefore, by modifying or propagating a | ||||||
|  | covered work, you indicate your acceptance of this License to do so. | ||||||
|  |  | ||||||
|  |   10. Automatic Licensing of Downstream Recipients. | ||||||
|  |  | ||||||
|  |   Each time you convey a covered work, the recipient automatically | ||||||
|  | receives a license from the original licensors, to run, modify and | ||||||
|  | propagate that work, subject to this License.  You are not responsible | ||||||
|  | for enforcing compliance by third parties with this License. | ||||||
|  |  | ||||||
|  |   An "entity transaction" is a transaction transferring control of an | ||||||
|  | organization, or substantially all assets of one, or subdividing an | ||||||
|  | organization, or merging organizations.  If propagation of a covered | ||||||
|  | work results from an entity transaction, each party to that | ||||||
|  | transaction who receives a copy of the work also receives whatever | ||||||
|  | licenses to the work the party's predecessor in interest had or could | ||||||
|  | give under the previous paragraph, plus a right to possession of the | ||||||
|  | Corresponding Source of the work from the predecessor in interest, if | ||||||
|  | the predecessor has it or can get it with reasonable efforts. | ||||||
|  |  | ||||||
|  |   You may not impose any further restrictions on the exercise of the | ||||||
|  | rights granted or affirmed under this License.  For example, you may | ||||||
|  | not impose a license fee, royalty, or other charge for exercise of | ||||||
|  | rights granted under this License, and you may not initiate litigation | ||||||
|  | (including a cross-claim or counterclaim in a lawsuit) alleging that | ||||||
|  | any patent claim is infringed by making, using, selling, offering for | ||||||
|  | sale, or importing the Program or any portion of it. | ||||||
|  |  | ||||||
|  |   11. Patents. | ||||||
|  |  | ||||||
|  |   A "contributor" is a copyright holder who authorizes use under this | ||||||
|  | License of the Program or a work on which the Program is based.  The | ||||||
|  | work thus licensed is called the contributor's "contributor version". | ||||||
|  |  | ||||||
|  |   A contributor's "essential patent claims" are all patent claims | ||||||
|  | owned or controlled by the contributor, whether already acquired or | ||||||
|  | hereafter acquired, that would be infringed by some manner, permitted | ||||||
|  | by this License, of making, using, or selling its contributor version, | ||||||
|  | but do not include claims that would be infringed only as a | ||||||
|  | consequence of further modification of the contributor version.  For | ||||||
|  | purposes of this definition, "control" includes the right to grant | ||||||
|  | patent sublicenses in a manner consistent with the requirements of | ||||||
|  | this License. | ||||||
|  |  | ||||||
|  |   Each contributor grants you a non-exclusive, worldwide, royalty-free | ||||||
|  | patent license under the contributor's essential patent claims, to | ||||||
|  | make, use, sell, offer for sale, import and otherwise run, modify and | ||||||
|  | propagate the contents of its contributor version. | ||||||
|  |  | ||||||
|  |   In the following three paragraphs, a "patent license" is any express | ||||||
|  | agreement or commitment, however denominated, not to enforce a patent | ||||||
|  | (such as an express permission to practice a patent or covenant not to | ||||||
|  | sue for patent infringement).  To "grant" such a patent license to a | ||||||
|  | party means to make such an agreement or commitment not to enforce a | ||||||
|  | patent against the party. | ||||||
|  |  | ||||||
|  |   If you convey a covered work, knowingly relying on a patent license, | ||||||
|  | and the Corresponding Source of the work is not available for anyone | ||||||
|  | to copy, free of charge and under the terms of this License, through a | ||||||
|  | publicly available network server or other readily accessible means, | ||||||
|  | then you must either (1) cause the Corresponding Source to be so | ||||||
|  | available, or (2) arrange to deprive yourself of the benefit of the | ||||||
|  | patent license for this particular work, or (3) arrange, in a manner | ||||||
|  | consistent with the requirements of this License, to extend the patent | ||||||
|  | license to downstream recipients.  "Knowingly relying" means you have | ||||||
|  | actual knowledge that, but for the patent license, your conveying the | ||||||
|  | covered work in a country, or your recipient's use of the covered work | ||||||
|  | in a country, would infringe one or more identifiable patents in that | ||||||
|  | country that you have reason to believe are valid. | ||||||
|  |  | ||||||
|  |   If, pursuant to or in connection with a single transaction or | ||||||
|  | arrangement, you convey, or propagate by procuring conveyance of, a | ||||||
|  | covered work, and grant a patent license to some of the parties | ||||||
|  | receiving the covered work authorizing them to use, propagate, modify | ||||||
|  | or convey a specific copy of the covered work, then the patent license | ||||||
|  | you grant is automatically extended to all recipients of the covered | ||||||
|  | work and works based on it. | ||||||
|  |  | ||||||
|  |   A patent license is "discriminatory" if it does not include within | ||||||
|  | the scope of its coverage, prohibits the exercise of, or is | ||||||
|  | conditioned on the non-exercise of one or more of the rights that are | ||||||
|  | specifically granted under this License.  You may not convey a covered | ||||||
|  | work if you are a party to an arrangement with a third party that is | ||||||
|  | in the business of distributing software, under which you make payment | ||||||
|  | to the third party based on the extent of your activity of conveying | ||||||
|  | the work, and under which the third party grants, to any of the | ||||||
|  | parties who would receive the covered work from you, a discriminatory | ||||||
|  | patent license (a) in connection with copies of the covered work | ||||||
|  | conveyed by you (or copies made from those copies), or (b) primarily | ||||||
|  | for and in connection with specific products or compilations that | ||||||
|  | contain the covered work, unless you entered into that arrangement, | ||||||
|  | or that patent license was granted, prior to 28 March 2007. | ||||||
|  |  | ||||||
|  |   Nothing in this License shall be construed as excluding or limiting | ||||||
|  | any implied license or other defenses to infringement that may | ||||||
|  | otherwise be available to you under applicable patent law. | ||||||
|  |  | ||||||
|  |   12. No Surrender of Others' Freedom. | ||||||
|  |  | ||||||
|  |   If conditions are imposed on you (whether by court order, agreement or | ||||||
|  | otherwise) that contradict the conditions of this License, they do not | ||||||
|  | excuse you from the conditions of this License.  If you cannot convey a | ||||||
|  | covered work so as to satisfy simultaneously your obligations under this | ||||||
|  | License and any other pertinent obligations, then as a consequence you may | ||||||
|  | not convey it at all.  For example, if you agree to terms that obligate you | ||||||
|  | to collect a royalty for further conveying from those to whom you convey | ||||||
|  | the Program, the only way you could satisfy both those terms and this | ||||||
|  | License would be to refrain entirely from conveying the Program. | ||||||
|  |  | ||||||
|  |   13. Remote Network Interaction; Use with the GNU General Public License. | ||||||
|  |  | ||||||
|  |   Notwithstanding any other provision of this License, if you modify the | ||||||
|  | Program, your modified version must prominently offer all users | ||||||
|  | interacting with it remotely through a computer network (if your version | ||||||
|  | supports such interaction) an opportunity to receive the Corresponding | ||||||
|  | Source of your version by providing access to the Corresponding Source | ||||||
|  | from a network server at no charge, through some standard or customary | ||||||
|  | means of facilitating copying of software.  This Corresponding Source | ||||||
|  | shall include the Corresponding Source for any work covered by version 3 | ||||||
|  | of the GNU General Public License that is incorporated pursuant to the | ||||||
|  | following paragraph. | ||||||
|  |  | ||||||
|  |   Notwithstanding any other provision of this License, you have | ||||||
|  | permission to link or combine any covered work with a work licensed | ||||||
|  | under version 3 of the GNU General Public License into a single | ||||||
|  | combined work, and to convey the resulting work.  The terms of this | ||||||
|  | License will continue to apply to the part which is the covered work, | ||||||
|  | but the work with which it is combined will remain governed by version | ||||||
|  | 3 of the GNU General Public License. | ||||||
|  |  | ||||||
|  |   14. Revised Versions of this License. | ||||||
|  |  | ||||||
|  |   The Free Software Foundation may publish revised and/or new versions of | ||||||
|  | the GNU Affero General Public License from time to time.  Such new versions | ||||||
|  | will be similar in spirit to the present version, but may differ in detail to | ||||||
|  | address new problems or concerns. | ||||||
|  |  | ||||||
|  |   Each version is given a distinguishing version number.  If the | ||||||
|  | Program specifies that a certain numbered version of the GNU Affero General | ||||||
|  | Public License "or any later version" applies to it, you have the | ||||||
|  | option of following the terms and conditions either of that numbered | ||||||
|  | version or of any later version published by the Free Software | ||||||
|  | Foundation.  If the Program does not specify a version number of the | ||||||
|  | GNU Affero General Public License, you may choose any version ever published | ||||||
|  | by the Free Software Foundation. | ||||||
|  |  | ||||||
|  |   If the Program specifies that a proxy can decide which future | ||||||
|  | versions of the GNU Affero General Public License can be used, that proxy's | ||||||
|  | public statement of acceptance of a version permanently authorizes you | ||||||
|  | to choose that version for the Program. | ||||||
|  |  | ||||||
|  |   Later license versions may give you additional or different | ||||||
|  | permissions.  However, no additional obligations are imposed on any | ||||||
|  | author or copyright holder as a result of your choosing to follow a | ||||||
|  | later version. | ||||||
|  |  | ||||||
|  |   15. Disclaimer of Warranty. | ||||||
|  |  | ||||||
|  |   THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY | ||||||
|  | APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT | ||||||
|  | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY | ||||||
|  | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, | ||||||
|  | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | ||||||
|  | PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM | ||||||
|  | IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF | ||||||
|  | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. | ||||||
|  |  | ||||||
|  |   16. Limitation of Liability. | ||||||
|  |  | ||||||
|  |   IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING | ||||||
|  | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS | ||||||
|  | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY | ||||||
|  | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE | ||||||
|  | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF | ||||||
|  | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD | ||||||
|  | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), | ||||||
|  | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF | ||||||
|  | SUCH DAMAGES. | ||||||
|  |  | ||||||
|  |   17. Interpretation of Sections 15 and 16. | ||||||
|  |  | ||||||
|  |   If the disclaimer of warranty and limitation of liability provided | ||||||
|  | above cannot be given local legal effect according to their terms, | ||||||
|  | reviewing courts shall apply local law that most closely approximates | ||||||
|  | an absolute waiver of all civil liability in connection with the | ||||||
|  | Program, unless a warranty or assumption of liability accompanies a | ||||||
|  | copy of the Program in return for a fee. | ||||||
|  |  | ||||||
|  |                      END OF TERMS AND CONDITIONS | ||||||
|  |  | ||||||
|  |             How to Apply These Terms to Your New Programs | ||||||
|  |  | ||||||
|  |   If you develop a new program, and you want it to be of the greatest | ||||||
|  | possible use to the public, the best way to achieve this is to make it | ||||||
|  | free software which everyone can redistribute and change under these terms. | ||||||
|  |  | ||||||
|  |   To do so, attach the following notices to the program.  It is safest | ||||||
|  | to attach them to the start of each source file to most effectively | ||||||
|  | state the exclusion of warranty; and each file should have at least | ||||||
|  | the "copyright" line and a pointer to where the full notice is found. | ||||||
|  |  | ||||||
|  |     <one line to give the program's name and a brief idea of what it does.> | ||||||
|  |     Copyright (C) <year>  <name of author> | ||||||
|  |  | ||||||
|  |     This program is free software: you can redistribute it and/or modify | ||||||
|  |     it under the terms of the GNU Affero General Public License as published | ||||||
|  |     by the Free Software Foundation, either version 3 of the License, or | ||||||
|  |     (at your option) any later version. | ||||||
|  |  | ||||||
|  |     This program is distributed in the hope that it will be useful, | ||||||
|  |     but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||||
|  |     GNU Affero General Public License for more details. | ||||||
|  |  | ||||||
|  |     You should have received a copy of the GNU Affero General Public License | ||||||
|  |     along with this program.  If not, see <https://www.gnu.org/licenses/>. | ||||||
|  |  | ||||||
|  | Also add information on how to contact you by electronic and paper mail. | ||||||
|  |  | ||||||
|  |   If your software can interact with users remotely through a computer | ||||||
|  | network, you should also make sure that it provides a way for users to | ||||||
|  | get its source.  For example, if your program is a web application, its | ||||||
|  | interface could display a "Source" link that leads users to an archive | ||||||
|  | of the code.  There are many ways you could offer source, and different | ||||||
|  | solutions will be better for different programs; see section 13 for the | ||||||
|  | specific requirements. | ||||||
|  |  | ||||||
|  |   You should also get your employer (if you work as a programmer) or school, | ||||||
|  | if any, to sign a "copyright disclaimer" for the program, if necessary. | ||||||
|  | For more information on this, and how to apply and follow the GNU AGPL, see | ||||||
|  | <https://www.gnu.org/licenses/>. | ||||||
|  | |||||||
							
								
								
									
										3274
									
								
								_ide_helper.php
									
									
									
									
									
								
							
							
						
						
									
										3274
									
								
								_ide_helper.php
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -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); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,36 +0,0 @@ | |||||||
| <?php |  | ||||||
| namespace Crater; |  | ||||||
|  |  | ||||||
| use Illuminate\Database\Eloquent\Model; |  | ||||||
| use Crater\User; |  | ||||||
| use Crater\CompanySetting; |  | ||||||
| use Spatie\MediaLibrary\HasMedia\HasMedia; |  | ||||||
| use Spatie\MediaLibrary\HasMedia\HasMediaTrait; |  | ||||||
|  |  | ||||||
| class Company extends Model implements HasMedia |  | ||||||
| { |  | ||||||
|     use HasMediaTrait; |  | ||||||
|  |  | ||||||
|     protected $fillable = ['name', 'logo', 'unique_hash']; |  | ||||||
|  |  | ||||||
|     protected $appends=['logo']; |  | ||||||
|  |  | ||||||
|     public function getLogoAttribute() |  | ||||||
|     { |  | ||||||
|         $logo = $this->getMedia('logo')->first(); |  | ||||||
|         if ($logo) { |  | ||||||
|             return  asset($logo->getUrl()); |  | ||||||
|         } |  | ||||||
|         return ; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function user() |  | ||||||
|     { |  | ||||||
|         return $this->hasOne(User::class); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function settings() |  | ||||||
|     { |  | ||||||
|         return $this->hasMany(CompanySetting::class); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -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); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,9 +1,10 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| namespace Crater\Console\Commands; | namespace Crater\Console\Commands; | ||||||
|  |  | ||||||
| use Illuminate\Console\Command; |  | ||||||
| use Carbon\Carbon; | use Carbon\Carbon; | ||||||
| use Crater\Estimate; | use Crater\Models\Estimate; | ||||||
|  | use Illuminate\Console\Command; | ||||||
|  |  | ||||||
| class CheckEstimateStatus extends Command | class CheckEstimateStatus extends Command | ||||||
| { | { | ||||||
| @ -39,7 +40,7 @@ class CheckEstimateStatus extends Command | |||||||
|     public function handle() |     public function handle() | ||||||
|     { |     { | ||||||
|         $date = Carbon::now(); |         $date = Carbon::now(); | ||||||
|         $status = array(Estimate::STATUS_ACCEPTED, Estimate::STATUS_REJECTED, Estimate::STATUS_EXPIRED); |         $status = [Estimate::STATUS_ACCEPTED, Estimate::STATUS_REJECTED, Estimate::STATUS_EXPIRED]; | ||||||
|         $estimates = Estimate::whereNotIn('status', $status)->whereDate('expiry_date', '<', $date)->get(); |         $estimates = Estimate::whereNotIn('status', $status)->whereDate('expiry_date', '<', $date)->get(); | ||||||
|  |  | ||||||
|         foreach ($estimates as $estimate) { |         foreach ($estimates as $estimate) { | ||||||
|  | |||||||
| @ -1,9 +1,10 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| namespace Crater\Console\Commands; | namespace Crater\Console\Commands; | ||||||
|  |  | ||||||
| use Illuminate\Console\Command; |  | ||||||
| use Carbon\Carbon; | use Carbon\Carbon; | ||||||
| use Crater\Invoice; | use Crater\Models\Invoice; | ||||||
|  | use Illuminate\Console\Command; | ||||||
|  |  | ||||||
| class CheckInvoiceStatus extends Command | class CheckInvoiceStatus extends Command | ||||||
| { | { | ||||||
|  | |||||||
							
								
								
									
										64
									
								
								app/Console/Commands/CreateTemplateCommand.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								app/Console/Commands/CreateTemplateCommand.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,64 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Console\Commands; | ||||||
|  |  | ||||||
|  | use Illuminate\Console\Command; | ||||||
|  | use Illuminate\Support\Facades\Storage; | ||||||
|  |  | ||||||
|  | class CreateTemplateCommand extends Command | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * The name and signature of the console command. | ||||||
|  |      * | ||||||
|  |      * @var string | ||||||
|  |      */ | ||||||
|  |     protected $signature = 'make:template {name} {--type=}'; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The console command description. | ||||||
|  |      * | ||||||
|  |      * @var string | ||||||
|  |      */ | ||||||
|  |     protected $description = 'Create estimate or invoice pdf template.                               '; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Create a new command instance. | ||||||
|  |      * | ||||||
|  |      * @return void | ||||||
|  |      */ | ||||||
|  |     public function __construct() | ||||||
|  |     { | ||||||
|  |         parent::__construct(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Execute the console command. | ||||||
|  |      * | ||||||
|  |      * @return int | ||||||
|  |      */ | ||||||
|  |     public function handle() | ||||||
|  |     { | ||||||
|  |         $templateName = $this->argument('name'); | ||||||
|  |         $type = $this->option('type'); | ||||||
|  |  | ||||||
|  |         if (! $type) { | ||||||
|  |             $type = $this->choice('Create a template for?', ['invoice', 'estimate']); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (Storage::disk('views')->exists("/app/pdf/{$type}/{$templateName}.blade.php")) { | ||||||
|  |             $this->info("Template with given name already exists."); | ||||||
|  |  | ||||||
|  |             return 0; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         Storage::disk('views')->copy("/app/pdf/{$type}/{$type}1.blade.php", "/app/pdf/{$type}/{$templateName}.blade.php"); | ||||||
|  |         copy(public_path("/build/img/PDF/{$type}1.png"), public_path("/build/img/PDF/{$templateName}.png")); | ||||||
|  |         copy(resource_path("/static/img/PDF/{$type}1.png"), resource_path("/static/img/PDF/{$templateName}.png")); | ||||||
|  |  | ||||||
|  |         $path = resource_path("app/pdf/{$type}/{$templateName}.blade.php"); | ||||||
|  |         $type = ucfirst($type); | ||||||
|  |         $this->info("{$type} Template created successfully at ".$path); | ||||||
|  |  | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -3,17 +3,19 @@ | |||||||
| namespace Crater\Console\Commands; | namespace Crater\Console\Commands; | ||||||
|  |  | ||||||
| use Illuminate\Console\Command; | use Illuminate\Console\Command; | ||||||
|  | use Illuminate\Console\ConfirmableTrait; | ||||||
| use Illuminate\Support\Facades\Artisan; | use Illuminate\Support\Facades\Artisan; | ||||||
| use Illuminate\Filesystem\Filesystem; |  | ||||||
|  |  | ||||||
| class ResetApp extends Command | class ResetApp extends Command | ||||||
| { | { | ||||||
|  |     use ConfirmableTrait; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * The name and signature of the console command. |      * The name and signature of the console command. | ||||||
|      * |      * | ||||||
|      * @var string |      * @var string | ||||||
|      */ |      */ | ||||||
|     protected $signature = 'reset:app'; |     protected $signature = 'reset:app {--force}'; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * The console command description. |      * The console command description. | ||||||
| @ -39,13 +41,28 @@ class ResetApp extends Command | |||||||
|      */ |      */ | ||||||
|     public function handle() |     public function handle() | ||||||
|     { |     { | ||||||
|         if ($this->confirm('Do you wish to continue? This will delete your tables')) { |         if (! $this->confirmToProceed()) { | ||||||
|             Artisan::call('migrate:reset --force'); |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|             \Storage::disk('local')->delete('database_created'); |         $this->info('Running migrate:fresh'); | ||||||
|  |  | ||||||
|             // $file = new Filesystem; |         Artisan::call('migrate:fresh --seed --force'); | ||||||
|             // $file->cleanDirectory('public/storage'); |  | ||||||
|         } |         $this->info('Seeding database'); | ||||||
|  |  | ||||||
|  |         Artisan::call('db:seed', ['--class' => 'DemoSeeder', '--force' => true]); | ||||||
|  |  | ||||||
|  |         $path = base_path('.env'); | ||||||
|  |  | ||||||
|  |         if (file_exists($path)) { | ||||||
|  |             file_put_contents($path, str_replace( | ||||||
|  |                 'APP_DEBUG=true', | ||||||
|  |                 'APP_DEBUG=false', | ||||||
|  |                 file_get_contents($path) | ||||||
|  |             )); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $this->info('App has been reset successfully'); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -2,9 +2,9 @@ | |||||||
|  |  | ||||||
| namespace Crater\Console\Commands; | namespace Crater\Console\Commands; | ||||||
|  |  | ||||||
| use Illuminate\Console\Command; | use Crater\Models\Setting; | ||||||
| use Crater\Space\Updater; | use Crater\Space\Updater; | ||||||
| use Crater\Setting; | use Illuminate\Console\Command; | ||||||
|  |  | ||||||
| // Implementation taken from Akaunting - https://github.com/akaunting/akaunting | // Implementation taken from Akaunting - https://github.com/akaunting/akaunting | ||||||
| class UpdateCommand extends Command | class UpdateCommand extends Command | ||||||
| @ -13,6 +13,8 @@ class UpdateCommand extends Command | |||||||
|  |  | ||||||
|     public $version; |     public $version; | ||||||
|  |  | ||||||
|  |     public $response; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * The name and signature of the console command. |      * The name and signature of the console command. | ||||||
|      * |      * | ||||||
| @ -45,10 +47,19 @@ class UpdateCommand extends Command | |||||||
|         set_time_limit(3600); // 1 hour |         set_time_limit(3600); // 1 hour | ||||||
|  |  | ||||||
|         $this->installed = $this->getInstalledVersion(); |         $this->installed = $this->getInstalledVersion(); | ||||||
|         $this->version = $this->getLatestVersion(); |         $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) { |         if (! $this->version) { | ||||||
|             $this->info('No Update Available! You are already on the latest version.'); |             $this->info('No Update Available! You are already on the latest version.'); | ||||||
|  |  | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @ -68,6 +79,12 @@ class UpdateCommand extends Command | |||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         if (isset($this->response->deleted_files) && ! empty($this->response->deleted_files)) { | ||||||
|  |             if (! $this->deleteFiles($this->response->deleted_files)) { | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|         if (! $this->migrateUpdate()) { |         if (! $this->migrateUpdate()) { | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| @ -84,7 +101,7 @@ class UpdateCommand extends Command | |||||||
|         return Setting::getSetting('version'); |         return Setting::getSetting('version'); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public function getLatestVersion() |     public function getLatestVersionResponse() | ||||||
|     { |     { | ||||||
|         $this->info('Your currently installed version is '.$this->installed); |         $this->info('Your currently installed version is '.$this->installed); | ||||||
|         $this->line(''); |         $this->line(''); | ||||||
| @ -94,7 +111,24 @@ class UpdateCommand extends Command | |||||||
|             $response = Updater::checkForUpdate($this->installed); |             $response = Updater::checkForUpdate($this->installed); | ||||||
|  |  | ||||||
|             if ($response->success) { |             if ($response->success) { | ||||||
|                 return $response->version->version; |                 $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; |             return false; | ||||||
| @ -110,9 +144,10 @@ class UpdateCommand extends Command | |||||||
|         $this->info('Downloading update...'); |         $this->info('Downloading update...'); | ||||||
|  |  | ||||||
|         try { |         try { | ||||||
|             $path = Updater::download($this->version); |             $path = Updater::download($this->version, 1); | ||||||
|             if (! is_string($path)) { |             if (! is_string($path)) { | ||||||
|                 $this->error('Download exception'); |                 $this->error('Download exception'); | ||||||
|  |  | ||||||
|                 return false; |                 return false; | ||||||
|             } |             } | ||||||
|         } catch (\Exception $e) { |         } catch (\Exception $e) { | ||||||
| @ -132,6 +167,7 @@ class UpdateCommand extends Command | |||||||
|             $path = Updater::unzip($path); |             $path = Updater::unzip($path); | ||||||
|             if (! is_string($path)) { |             if (! is_string($path)) { | ||||||
|                 $this->error('Unzipping exception'); |                 $this->error('Unzipping exception'); | ||||||
|  |  | ||||||
|                 return false; |                 return false; | ||||||
|             } |             } | ||||||
|         } catch (\Exception $e) { |         } catch (\Exception $e) { | ||||||
| @ -158,6 +194,21 @@ class UpdateCommand extends Command | |||||||
|         return true; |         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() |     public function migrateUpdate() | ||||||
|     { |     { | ||||||
|         $this->info('Running Migrations...'); |         $this->info('Running Migrations...'); | ||||||
|  | |||||||
| @ -1,6 +1,8 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| namespace Crater\Console; | namespace Crater\Console; | ||||||
|  |  | ||||||
|  | use Crater\Models\RecurringInvoice; | ||||||
| use Illuminate\Console\Scheduling\Schedule; | use Illuminate\Console\Scheduling\Schedule; | ||||||
| use Illuminate\Foundation\Console\Kernel as ConsoleKernel; | use Illuminate\Foundation\Console\Kernel as ConsoleKernel; | ||||||
|  |  | ||||||
| @ -13,7 +15,8 @@ class Kernel extends ConsoleKernel | |||||||
|      */ |      */ | ||||||
|     protected $commands = [ |     protected $commands = [ | ||||||
|         Commands\ResetApp::class, |         Commands\ResetApp::class, | ||||||
|         Commands\UpdateCommand::class |         Commands\UpdateCommand::class, | ||||||
|  |         Commands\CreateTemplateCommand::class | ||||||
|     ]; |     ]; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @ -24,11 +27,20 @@ class Kernel extends ConsoleKernel | |||||||
|      */ |      */ | ||||||
|     protected function schedule(Schedule $schedule) |     protected function schedule(Schedule $schedule) | ||||||
|     { |     { | ||||||
|  |         if (\Storage::disk('local')->has('database_created')) { | ||||||
|             $schedule->command('check:invoices:status') |             $schedule->command('check:invoices:status') | ||||||
|             ->daily(); |             ->daily(); | ||||||
|  |  | ||||||
|             $schedule->command('check:estimates:status') |             $schedule->command('check:estimates:status') | ||||||
|             ->daily(); |             ->daily(); | ||||||
|  |  | ||||||
|  |             $recurringInvoices = RecurringInvoice::where('status', 'ACTIVE')->get(); | ||||||
|  |             foreach ($recurringInvoices as $recurringInvoice) { | ||||||
|  |                 $schedule->call(function () use ($recurringInvoice) { | ||||||
|  |                     $recurringInvoice->generateInvoice(); | ||||||
|  |                 })->cron($recurringInvoice->frequency); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|  | |||||||
| @ -1,17 +0,0 @@ | |||||||
| <?php |  | ||||||
| namespace Crater; |  | ||||||
|  |  | ||||||
| use Illuminate\Database\Eloquent\Model; |  | ||||||
|  |  | ||||||
| class Currency extends Model |  | ||||||
| { |  | ||||||
|     protected $fillable = [ |  | ||||||
|         'name', |  | ||||||
|         'code', |  | ||||||
|         'symbol', |  | ||||||
|         'precision', |  | ||||||
|         'thousand_separator', |  | ||||||
|         'decimal_separator', |  | ||||||
|         'position' |  | ||||||
|     ]; |  | ||||||
| } |  | ||||||
							
								
								
									
										237
									
								
								app/Estimate.php
									
									
									
									
									
								
							
							
						
						
									
										237
									
								
								app/Estimate.php
									
									
									
									
									
								
							| @ -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; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,20 +0,0 @@ | |||||||
| <?php |  | ||||||
| namespace Crater; |  | ||||||
|  |  | ||||||
| use Illuminate\Database\Eloquent\Model; |  | ||||||
| use Crater\Estimate; |  | ||||||
|  |  | ||||||
| class EstimateTemplate extends Model |  | ||||||
| { |  | ||||||
|     protected $fillable = ['path', 'view', 'name']; |  | ||||||
|  |  | ||||||
|     public function estimates() |  | ||||||
|     { |  | ||||||
|         return $this->hasMany(Estimate::class); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function getPathAttribute($value) |  | ||||||
|     { |  | ||||||
|         return url($value); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -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 | ||||||
| { | { | ||||||
|  | |||||||
| @ -1,8 +1,9 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| namespace Crater\Exceptions; | namespace Crater\Exceptions; | ||||||
|  |  | ||||||
| use Exception; |  | ||||||
| use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler; | use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler; | ||||||
|  | use Throwable; | ||||||
|  |  | ||||||
| class Handler extends ExceptionHandler | class Handler extends ExceptionHandler | ||||||
| { | { | ||||||
| @ -30,10 +31,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 +43,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); | ||||||
|     } |     } | ||||||
|  | |||||||
							
								
								
									
										156
									
								
								app/Expense.php
									
									
									
									
									
								
							
							
						
						
									
										156
									
								
								app/Expense.php
									
									
									
									
									
								
							| @ -1,156 +0,0 @@ | |||||||
| <?php |  | ||||||
| namespace Crater; |  | ||||||
|  |  | ||||||
| use Illuminate\Database\Eloquent\Model; |  | ||||||
| use Spatie\MediaLibrary\HasMedia\HasMedia; |  | ||||||
| use Spatie\MediaLibrary\HasMedia\HasMediaTrait; |  | ||||||
| use Crater\ExpenseCategory; |  | ||||||
| use Crater\User; |  | ||||||
| use Carbon\Carbon; |  | ||||||
| use Illuminate\Support\Facades\DB; |  | ||||||
|  |  | ||||||
| class Expense extends Model implements HasMedia |  | ||||||
| { |  | ||||||
|     use HasMediaTrait; |  | ||||||
|  |  | ||||||
|     protected $fillable = [ |  | ||||||
|         'expense_category_id', |  | ||||||
|         'amount', |  | ||||||
|         'company_id', |  | ||||||
|         'user_id', |  | ||||||
|         'expense_date', |  | ||||||
|         'notes', |  | ||||||
|         'attachment_receipt' |  | ||||||
|     ]; |  | ||||||
|  |  | ||||||
|     protected $appends = [ |  | ||||||
|         'formattedExpenseDate', |  | ||||||
|         'formattedCreatedAt', |  | ||||||
|         'receipt' |  | ||||||
|     ]; |  | ||||||
|  |  | ||||||
|     public function category() |  | ||||||
|     { |  | ||||||
|         return $this->belongsTo(ExpenseCategory::class, 'expense_category_id'); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function user() |  | ||||||
|     { |  | ||||||
|         return $this->belongsTo(User::class); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function getFormattedExpenseDateAttribute($value) |  | ||||||
|     { |  | ||||||
|         $dateFormat = CompanySetting::getSetting('carbon_date_format', $this->company_id); |  | ||||||
|         return Carbon::parse($this->expense_date)->format($dateFormat); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function getFormattedCreatedAtAttribute($value) |  | ||||||
|     { |  | ||||||
|         $dateFormat = CompanySetting::getSetting('carbon_date_format', $this->company_id); |  | ||||||
|         return Carbon::parse($this->created_at)->format($dateFormat); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function getReceiptAttribute($value) |  | ||||||
|     { |  | ||||||
|         $media = $this->getFirstMedia('receipts'); |  | ||||||
|         if($media) { |  | ||||||
|             return $media->getPath(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         return null; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function scopeExpensesBetween($query, $start, $end) |  | ||||||
|     { |  | ||||||
|         return $query->whereBetween( |  | ||||||
|             'expenses.expense_date', |  | ||||||
|             [$start->format('Y-m-d'), $end->format('Y-m-d')] |  | ||||||
|         ); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function scopeWhereCategoryName($query, $search) |  | ||||||
|     { |  | ||||||
|         foreach (explode(' ', $search) as $term) { |  | ||||||
|             $query->whereHas('category', function ($query) use ($term) { |  | ||||||
|                 $query->where('name', 'LIKE', '%'.$term.'%'); |  | ||||||
|             }); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function scopeWhereNotes($query, $search) |  | ||||||
|     { |  | ||||||
|         $query->where('notes', 'LIKE', '%'.$search.'%'); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function scopeWhereCategory($query, $categoryId) |  | ||||||
|     { |  | ||||||
|         return $query->where('expenses.expense_category_id', $categoryId); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function scopeWhereUser($query, $user_id) |  | ||||||
|     { |  | ||||||
|         return $query->where('expenses.user_id', $user_id); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function scopeApplyFilters($query, array $filters) |  | ||||||
|     { |  | ||||||
|         $filters = collect($filters); |  | ||||||
|  |  | ||||||
|         if ($filters->get('expense_category_id')) { |  | ||||||
|             $query->whereCategory($filters->get('expense_category_id')); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if ($filters->get('user_id')) { |  | ||||||
|             $query->whereUser($filters->get('user_id')); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         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->expensesBetween($start, $end); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if ($filters->get('orderByField') || $filters->get('orderBy')) { |  | ||||||
|             $field = $filters->get('orderByField') ? $filters->get('orderByField') : 'expense_date'; |  | ||||||
|             $orderBy = $filters->get('orderBy') ? $filters->get('orderBy') : 'asc'; |  | ||||||
|             $query->whereOrder($field, $orderBy); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if ($filters->get('search')) { |  | ||||||
|             $query->whereSearch($filters->get('search')); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function scopeWhereSearch($query, $search) |  | ||||||
|     { |  | ||||||
|         foreach (explode(' ', $search) as $term) { |  | ||||||
|             $query->whereHas('category', function ($query) use ($term) { |  | ||||||
|                 $query->where('name', 'LIKE', '%'.$term.'%'); |  | ||||||
|             }) |  | ||||||
|             ->orWhere('notes', 'LIKE', '%'.$term.'%'); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function scopeWhereOrder($query, $orderByField, $orderBy) |  | ||||||
|     { |  | ||||||
|         $query->orderBy($orderByField, $orderBy); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function scopeWhereCompany($query, $company_id) |  | ||||||
|     { |  | ||||||
|         $query->where('expenses.company_id', $company_id); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function scopeExpensesAttributes($query) |  | ||||||
|     { |  | ||||||
|         $query->select( |  | ||||||
|             DB::raw(' |  | ||||||
|                 count(*) as expenses_count, |  | ||||||
|                 sum(amount) as total_amount, |  | ||||||
|                 expense_category_id' |  | ||||||
|             ) |  | ||||||
|         ) |  | ||||||
|         ->groupBy('expense_category_id'); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -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); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
							
								
								
									
										47
									
								
								app/Generators/CustomPathGenerator.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								app/Generators/CustomPathGenerator.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,47 @@ | |||||||
|  | <?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; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										24
									
								
								app/Http/Controllers/AppVersionController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								app/Http/Controllers/AppVersionController.php
									
									
									
									
									
										Normal 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, | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -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'; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,368 +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 = [  // alphabetical order |  | ||||||
|             ["code"=>"pt_BR", "name" => "Brazilian Portuguese"], |  | ||||||
|             ["code"=>"en", "name" => "English"], |  | ||||||
|             ["code"=>"fr", "name" => "French"], |  | ||||||
|             ["code"=>"de", "name" => "German"], |  | ||||||
|             ["code"=>"it", "name" => "Italian"], |  | ||||||
|             ["code"=>"es", "name" => "Spanish"], |  | ||||||
|             ["code"=>"ar", "name" => "العربية"], |  | ||||||
|         ]; |  | ||||||
|  |  | ||||||
|         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 |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,12 +1,15 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| namespace Crater\Http\Controllers; | namespace Crater\Http\Controllers; | ||||||
|  |  | ||||||
| use Illuminate\Foundation\Bus\DispatchesJobs; |  | ||||||
| use Illuminate\Routing\Controller as BaseController; |  | ||||||
| use Illuminate\Foundation\Validation\ValidatesRequests; |  | ||||||
| use Illuminate\Foundation\Auth\Access\AuthorizesRequests; | use Illuminate\Foundation\Auth\Access\AuthorizesRequests; | ||||||
|  | use Illuminate\Foundation\Bus\DispatchesJobs; | ||||||
|  | use Illuminate\Foundation\Validation\ValidatesRequests; | ||||||
|  | use Illuminate\Routing\Controller as BaseController; | ||||||
|  |  | ||||||
| class Controller extends BaseController | class Controller extends BaseController | ||||||
| { | { | ||||||
|     use AuthorizesRequests, DispatchesJobs, ValidatesRequests; |     use AuthorizesRequests; | ||||||
|  |     use DispatchesJobs; | ||||||
|  |     use ValidatesRequests; | ||||||
| } | } | ||||||
|  | |||||||
| @ -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 |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,168 +0,0 @@ | |||||||
| <?php |  | ||||||
| namespace Crater\Http\Controllers; |  | ||||||
|  |  | ||||||
| use Illuminate\Http\Request; |  | ||||||
|  |  | ||||||
| use Crater\Estimate; |  | ||||||
| use Crater\Http\Requests; |  | ||||||
| use Crater\Invoice; |  | ||||||
| use Crater\CompanySetting; |  | ||||||
| use Crater\Expense; |  | ||||||
| use Crater\Payment; |  | ||||||
| use Carbon\Carbon; |  | ||||||
| use Crater\User; |  | ||||||
| use Illuminate\Support\Facades\DB; |  | ||||||
|  |  | ||||||
| class DashboardController extends Controller |  | ||||||
| { |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Retrieve Dashboard details |  | ||||||
|      * @param \Illuminate\Http\Request $request |  | ||||||
|      * @return \Illuminate\Http\JsonResponse |  | ||||||
|      */ |  | ||||||
|     public function index(Request $request) |  | ||||||
|     { |  | ||||||
|         $invoiceTotals = []; |  | ||||||
|         $expenseTotals = []; |  | ||||||
|         $receiptTotals = []; |  | ||||||
|         $netProfits = []; |  | ||||||
|         $i = 0; |  | ||||||
|         $months = []; |  | ||||||
|         $monthEnds = []; |  | ||||||
|         $monthCounter = 0; |  | ||||||
|         $fiscalYear = CompanySetting::getSetting('fiscal_year', $request->header('company')); |  | ||||||
|         $startDate = Carbon::now(); |  | ||||||
|         $start = Carbon::now(); |  | ||||||
|         $end = Carbon::now(); |  | ||||||
|         $terms = explode('-', $fiscalYear); |  | ||||||
|  |  | ||||||
|         if ($terms[0] <= $start->month) { |  | ||||||
|             $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')) |  | ||||||
|                 ->sum('total') |  | ||||||
|             ); |  | ||||||
|             array_push( |  | ||||||
|                 $expenseTotals, |  | ||||||
|                 Expense::whereBetween( |  | ||||||
|                     'expense_date', |  | ||||||
|                     [$start->format('Y-m-d'), $end->format('Y-m-d')] |  | ||||||
|                 ) |  | ||||||
|                 ->whereCompany($request->header('company')) |  | ||||||
|                 ->sum('amount') |  | ||||||
|             ); |  | ||||||
|             array_push( |  | ||||||
|                 $receiptTotals, |  | ||||||
|                 Payment::whereBetween( |  | ||||||
|                     'payment_date', |  | ||||||
|                     [$start->format('Y-m-d'), $end->format('Y-m-d')] |  | ||||||
|                 ) |  | ||||||
|                 ->whereCompany($request->header('company')) |  | ||||||
|                 ->sum('amount') |  | ||||||
|             ); |  | ||||||
|             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')] |  | ||||||
|             ) |  | ||||||
|             ->sum('total'); |  | ||||||
|         $totalReceipts = Payment::whereCompany($request->header('company')) |  | ||||||
|             ->whereBetween( |  | ||||||
|                 'payment_date', |  | ||||||
|                 [$startDate->format('Y-m-d'), $start->format('Y-m-d')] |  | ||||||
|             ) |  | ||||||
|             ->sum('amount'); |  | ||||||
|         $totalExpenses = Expense::whereCompany($request->header('company')) |  | ||||||
|             ->whereBetween( |  | ||||||
|                 'expense_date', |  | ||||||
|                 [$startDate->format('Y-m-d'), $start->format('Y-m-d')] |  | ||||||
|             ) |  | ||||||
|             ->sum('amount'); |  | ||||||
|         $netProfit = (int)$totalReceipts - (int)$totalExpenses; |  | ||||||
|  |  | ||||||
|         $chartData = [ |  | ||||||
|             'months'        => $months, |  | ||||||
|             'invoiceTotals' => $invoiceTotals, |  | ||||||
|             'expenseTotals' => $expenseTotals, |  | ||||||
|             'receiptTotals' => $receiptTotals, |  | ||||||
|             'netProfits'    => $netProfits |  | ||||||
|         ]; |  | ||||||
|  |  | ||||||
|         $customersCount = User::customer()->whereCompany($request->header('company'))->get()->count(); |  | ||||||
|         $invoicesCount = Invoice::whereCompany($request->header('company'))->get()->count(); |  | ||||||
|         $estimatesCount = Estimate::whereCompany($request->header('company'))->get()->count(); |  | ||||||
|         $totalDueAmount = Invoice::whereCompany($request->header('company'))->sum('due_amount'); |  | ||||||
|         $dueInvoices = Invoice::with('user')->whereCompany($request->header('company'))->where('due_amount', '>', 0)->take(5)->latest()->get(); |  | ||||||
|         $estimates = Estimate::with('user')->whereCompany($request->header('company'))->take(5)->latest()->get(); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'dueInvoices' => $dueInvoices, |  | ||||||
|             'estimates' => $estimates, |  | ||||||
|             'estimatesCount' => $estimatesCount, |  | ||||||
|             'totalDueAmount' => $totalDueAmount, |  | ||||||
|             'invoicesCount' => $invoicesCount, |  | ||||||
|             'customersCount' => $customersCount, |  | ||||||
|             'chartData' => $chartData, |  | ||||||
|             'salesTotal' => $salesTotal, |  | ||||||
|             'totalReceipts' => $totalReceipts, |  | ||||||
|             'totalExpenses' => $totalExpenses, |  | ||||||
|             '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, |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,479 +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' |  | ||||||
|                 ]); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             \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' |  | ||||||
|             ]); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         \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::now(); |  | ||||||
|         $invoice_prefix = CompanySetting::getSetting( |  | ||||||
|             'invoice_prefix', |  | ||||||
|             $request->header('company') |  | ||||||
|         ); |  | ||||||
|         $due_date = Carbon::now()->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 |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,122 +0,0 @@ | |||||||
| <?php |  | ||||||
| namespace Crater\Http\Controllers; |  | ||||||
|  |  | ||||||
| use Crater\ExpenseCategory; |  | ||||||
| use Crater\Expense; |  | ||||||
| use Crater\User; |  | ||||||
| use Illuminate\Http\Request; |  | ||||||
| use Crater\Http\Requests\ExpenseCategoryRequest; |  | ||||||
|  |  | ||||||
| class ExpenseCategoryController extends Controller |  | ||||||
| { |  | ||||||
|     /** |  | ||||||
|      * Display a listing of the resource. |  | ||||||
|      * |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function index(Request $request) |  | ||||||
|     { |  | ||||||
|         $categories = ExpenseCategory::whereCompany($request->header('company'))->get(); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'categories' => $categories |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Show the form for creating a new resource. |  | ||||||
|      * |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function create() |  | ||||||
|     { |  | ||||||
|         // return view('app.categories.create'); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Store a newly created resource in storage. |  | ||||||
|      * |  | ||||||
|      * @param  \Illuminate\Http\Request $request |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function store(ExpenseCategoryRequest $request) |  | ||||||
|     { |  | ||||||
|         $category = new ExpenseCategory(); |  | ||||||
|         $category->name = $request->name; |  | ||||||
|         $category->description = $request->description; |  | ||||||
|         $category->company_id = $request->header('company'); |  | ||||||
|         $category->save(); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'category' => $category, |  | ||||||
|             'success' => true |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Display the specified resource. |  | ||||||
|      * |  | ||||||
|      * @param  \Crater\ExpenseCategory $ExpenseCategory |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function show(ExpenseCategory $ExpenseCategory) |  | ||||||
|     { |  | ||||||
|         // |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Show the form for editing the specified resource. |  | ||||||
|      * |  | ||||||
|      * @param  \Crater\ExpensesCategory $ExpensesCategory |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function edit($id) |  | ||||||
|     { |  | ||||||
|         $category = ExpenseCategory::findOrFail($id); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'category' => $category |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Update the specified resource in storage. |  | ||||||
|      * |  | ||||||
|      * @param  \Illuminate\Http\Request $request |  | ||||||
|      * @param  \Crater\ExpenseCategory $ExpenseCategory |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function update(ExpenseCategoryRequest $request, $id) |  | ||||||
|     { |  | ||||||
|         $category = ExpenseCategory::findOrFail($id); |  | ||||||
|         $category->name = $request->name; |  | ||||||
|         $category->description = $request->description; |  | ||||||
|         $category->save(); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'category' => $category, |  | ||||||
|             'success' => true |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Remove the specified resource from storage. |  | ||||||
|      * |  | ||||||
|      * @param  \Crater\ExpensesCategory $expensesCategory |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function destroy($id) |  | ||||||
|     { |  | ||||||
|         $category = ExpenseCategory::find($id); |  | ||||||
|         if ($category->expenses() && $category->expenses()->count() > 0) { |  | ||||||
|             return response()->json([ |  | ||||||
|                 'success' => false |  | ||||||
|             ]); |  | ||||||
|         } |  | ||||||
|         $category->delete(); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'success' => true |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,282 +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') |  | ||||||
|             ->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', |  | ||||||
|                 'search', |  | ||||||
|                 'from_date', |  | ||||||
|                 'to_date', |  | ||||||
|                 'orderByField', |  | ||||||
|                 'orderBy' |  | ||||||
|             ])) |  | ||||||
|             ->whereCompany($request->header('company')) |  | ||||||
|             ->select('expenses.*', 'expense_categories.name', 'users.name as user_name') |  | ||||||
|             ->paginate($limit); |  | ||||||
|  |  | ||||||
|         $customers = User::customer() |  | ||||||
|             ->whereCompany($request->header('company')) |  | ||||||
|             ->get(); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'expenses' => $expenses, |  | ||||||
|             'customers' => $customers, |  | ||||||
|             '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(); |  | ||||||
|         $customers = User::customer() |  | ||||||
|             ->whereCompany($request->header('company')) |  | ||||||
|             ->get(); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'categories' => $categories, |  | ||||||
|             'customers' => $customers |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 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->user_id = $request->user_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::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->user_id = $request->user_id; |  | ||||||
|         $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(); |  | ||||||
|                 $response = \Response::download($imagePath, $media->file_name); |  | ||||||
|                 ob_end_clean(); |  | ||||||
|                 return $response; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'error' => 'receipt_not_found' |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -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(); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,569 +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' |  | ||||||
|                 ]); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             \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' |  | ||||||
|             ]); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         \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 |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -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 |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -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() |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,337 +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)"], |  | ||||||
|             ["code"=>"it", "name" => "Italian"], |  | ||||||
|         ]; |  | ||||||
|         $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); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,321 +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']; |  | ||||||
|  |  | ||||||
|         if (!$email) { |  | ||||||
|             return response()->json([ |  | ||||||
|                 'error' => 'user_email_does_not_exist' |  | ||||||
|             ]); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         \Mail::to($email)->send(new PaymentPdf($data)); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'success' => true |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,119 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
| namespace Crater\Http\Controllers; |  | ||||||
|  |  | ||||||
| use Crater\PaymentMethod; |  | ||||||
| use Illuminate\Http\Request; |  | ||||||
| use Crater\Http\Requests\PaymentMethodRequest; |  | ||||||
|  |  | ||||||
| class PaymentMethodController extends Controller |  | ||||||
| { |  | ||||||
|     /** |  | ||||||
|      * Display a listing of the resource. |  | ||||||
|      * |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function index(Request $request) |  | ||||||
|     { |  | ||||||
|         $paymentMethods = PaymentMethod::whereCompany($request->header('company')) |  | ||||||
|             ->latest() |  | ||||||
|             ->get(); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'paymentMethods' => $paymentMethods |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Show the form for creating a new resource. |  | ||||||
|      * |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function create() |  | ||||||
|     { |  | ||||||
|         // |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Store a newly created resource in storage. |  | ||||||
|      * |  | ||||||
|      * @param  \Illuminate\Http\Request  $request |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function store(PaymentMethodRequest $request) |  | ||||||
|     { |  | ||||||
|         $paymentMethod = new PaymentMethod; |  | ||||||
|         $paymentMethod->name = $request->name; |  | ||||||
|         $paymentMethod->company_id = $request->header('company'); |  | ||||||
|         $paymentMethod->save(); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'paymentMethod' => $paymentMethod |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Display the specified resource. |  | ||||||
|      * |  | ||||||
|      * @param  \Crater\PaymentMethod  $paymentMethod |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     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([ |  | ||||||
|             'paymentMethod' => $paymentMethod |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Update the specified resource in storage. |  | ||||||
|      * |  | ||||||
|      * @param  \Illuminate\Http\Request  $request |  | ||||||
|      * @param  \Crater\PaymentMethod  $paymentMethod |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function update(PaymentMethodRequest $request, PaymentMethod $paymentMethod) |  | ||||||
|     { |  | ||||||
|         $paymentMethod->name = $request->name; |  | ||||||
|         $paymentMethod->company_id = $request->header('company'); |  | ||||||
|         $paymentMethod->save(); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'paymentMethod' => $paymentMethod |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Remove the specified resource from storage. |  | ||||||
|      * |  | ||||||
|      * @param  \Crater\PaymentMethod  $paymentMethod |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function destroy(PaymentMethod $paymentMethod) |  | ||||||
|     { |  | ||||||
|         $payments = $paymentMethod->payments; |  | ||||||
|  |  | ||||||
|         if ($payments->count() > 0) { |  | ||||||
|             return response()->json([ |  | ||||||
|                 'error' => 'payments_attached' |  | ||||||
|             ]); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         $paymentMethod->delete(); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'success' => 'Payment method deleted successfully' |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -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(); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -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 |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,126 +0,0 @@ | |||||||
| <?php |  | ||||||
| namespace Crater\Http\Controllers; |  | ||||||
|  |  | ||||||
| use Crater\TaxType; |  | ||||||
| use Crater\User; |  | ||||||
| use Crater\Http\Requests\TaxTypeRequest; |  | ||||||
| use Illuminate\Http\Request; |  | ||||||
|  |  | ||||||
| class TaxTypeController extends Controller |  | ||||||
| { |  | ||||||
|     /** |  | ||||||
|      * Display a listing of the resource. |  | ||||||
|      * |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function index(Request $request) |  | ||||||
|     { |  | ||||||
|         $taxTypes = TaxType::whereCompany($request->header('company')) |  | ||||||
|             ->latest() |  | ||||||
|             ->get(); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'taxTypes' => $taxTypes |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Show the form for creating a new resource. |  | ||||||
|      * |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function create() |  | ||||||
|     { |  | ||||||
|         // |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Store a newly created resource in storage. |  | ||||||
|      * |  | ||||||
|      * @param  \Illuminate\Http\Request  $request |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function store(TaxTypeRequest $request) |  | ||||||
|     { |  | ||||||
|         $taxType = new TaxType(); |  | ||||||
|         $taxType->name = $request->name; |  | ||||||
|         $taxType->percent = $request->percent; |  | ||||||
|         $taxType->description = $request->description; |  | ||||||
|         if ($request->has('compound_tax')) { |  | ||||||
|             $taxType->compound_tax = $request->compound_tax; |  | ||||||
|         } |  | ||||||
|         $taxType->company_id = $request->header('company'); |  | ||||||
|         $taxType->save(); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'taxType' => $taxType, |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Display the specified resource. |  | ||||||
|      * |  | ||||||
|      * @param  \Crater\TaxType  $taxType |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     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([ |  | ||||||
|             'taxType' => $taxType |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Update the specified resource in storage. |  | ||||||
|      * |  | ||||||
|      * @param  \Illuminate\Http\Request  $request |  | ||||||
|      * @param  \Crater\TaxType  $taxType |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function update(TaxTypeRequest $request, TaxType $taxType) |  | ||||||
|     { |  | ||||||
|         $taxType->name = $request->name; |  | ||||||
|         $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([ |  | ||||||
|             'taxType' => $taxType, |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Remove the specified resource from storage. |  | ||||||
|      * |  | ||||||
|      * @param  \Crater\TaxType  $taxType |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function destroy(TaxType $taxType) |  | ||||||
|     { |  | ||||||
|         if ($taxType->taxes() && $taxType->taxes()->count() > 0) { |  | ||||||
|             return response()->json([ |  | ||||||
|                 'success' => false |  | ||||||
|             ]); |  | ||||||
|         } |  | ||||||
|         $taxType->delete(); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'success' => true |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,119 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
| namespace Crater\Http\Controllers; |  | ||||||
|  |  | ||||||
| use Crater\Unit; |  | ||||||
| use Illuminate\Http\Request; |  | ||||||
| use Crater\Http\Requests\UnitRequest; |  | ||||||
|  |  | ||||||
| class UnitController extends Controller |  | ||||||
| { |  | ||||||
|     /** |  | ||||||
|      * Display a listing of the resource. |  | ||||||
|      * |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function index(Request $request) |  | ||||||
|     { |  | ||||||
|         $units = Unit::whereCompany($request->header('company')) |  | ||||||
|             ->latest() |  | ||||||
|             ->get(); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'units' => $units |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Show the form for creating a new resource. |  | ||||||
|      * |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function create() |  | ||||||
|     { |  | ||||||
|         // |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Store a newly created resource in storage. |  | ||||||
|      * |  | ||||||
|      * @param  \Illuminate\Http\Request  $request |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function store(UnitRequest $request) |  | ||||||
|     { |  | ||||||
|         $unit = new Unit; |  | ||||||
|         $unit->name = $request->name; |  | ||||||
|         $unit->company_id = $request->header('company'); |  | ||||||
|         $unit->save(); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'unit' => $unit |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Display the specified resource. |  | ||||||
|      * |  | ||||||
|      * @param  \Crater\Unit  $unit |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     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([ |  | ||||||
|             'unit' => $unit |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Update the specified resource in storage. |  | ||||||
|      * |  | ||||||
|      * @param  \Illuminate\Http\Request  $request |  | ||||||
|      * @param  \Crater\Unit  $unit |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function update(UnitRequest $request, Unit $unit) |  | ||||||
|     { |  | ||||||
|         $unit->name = $request->name; |  | ||||||
|         $unit->company_id = $request->header('company'); |  | ||||||
|         $unit->save(); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'unit' => $unit |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Remove the specified resource from storage. |  | ||||||
|      * |  | ||||||
|      * @param  \Crater\Unit  $unit |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function destroy(Unit $unit) |  | ||||||
|     { |  | ||||||
|         $items = $unit->items; |  | ||||||
|  |  | ||||||
|         if ($items->count() > 0) { |  | ||||||
|             return response()->json([ |  | ||||||
|                 'error' => 'items_attached' |  | ||||||
|             ]); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         $unit->delete(); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'success' => 'Unit deleted successfully' |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -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' |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -0,0 +1,40 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\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'); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -1,5 +1,6 @@ | |||||||
| <?php | <?php | ||||||
| namespace Crater\Http\Controllers\Auth; | 
 | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\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. | ||||||
|      * |      * | ||||||
| @ -54,6 +45,8 @@ class ForgotPasswordController extends Controller | |||||||
|      */ |      */ | ||||||
|     protected function sendResetLinkFailedResponse(Request $request, $response) |     protected function sendResetLinkFailedResponse(Request $request, $response) | ||||||
|     { |     { | ||||||
|         return response('Email could not be sent to this email address.', 403); |         return response()->json([ | ||||||
|  |             'error' => 'Email could not be sent to this email address.' | ||||||
|  |         ], 403); | ||||||
|     } |     } | ||||||
| } | } | ||||||
							
								
								
									
										40
									
								
								app/Http/Controllers/V1/Admin/Auth/LoginController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								app/Http/Controllers/V1/Admin/Auth/LoginController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,40 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\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'); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										72
									
								
								app/Http/Controllers/V1/Admin/Auth/RegisterController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								app/Http/Controllers/V1/Admin/Auth/RegisterController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,72 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\Auth; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Models\User; | ||||||
|  | use Crater\Providers\RouteServiceProvider; | ||||||
|  | use Illuminate\Foundation\Auth\RegistersUsers; | ||||||
|  | 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'], | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -1,11 +1,13 @@ | |||||||
| <?php | <?php | ||||||
| namespace Crater\Http\Controllers\Auth; | 
 | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\Auth; | ||||||
| 
 | 
 | ||||||
| use Crater\Http\Controllers\Controller; | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Providers\RouteServiceProvider; | ||||||
|  | use Illuminate\Auth\Events\PasswordReset; | ||||||
| use Illuminate\Foundation\Auth\ResetsPasswords; | use Illuminate\Foundation\Auth\ResetsPasswords; | ||||||
| use Illuminate\Http\Request; | use Illuminate\Http\Request; | ||||||
| use Illuminate\Support\Str; | use Illuminate\Support\Str; | ||||||
| use Illuminate\Auth\Events\PasswordReset; |  | ||||||
| 
 | 
 | ||||||
| class ResetPasswordController extends Controller | class ResetPasswordController extends Controller | ||||||
| { | { | ||||||
| @ -27,17 +29,7 @@ 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. | ||||||
| @ -49,7 +41,7 @@ class ResetPasswordController extends Controller | |||||||
|     protected function sendResetResponse(Request $request, $response) |     protected function sendResetResponse(Request $request, $response) | ||||||
|     { |     { | ||||||
|         return response()->json([ |         return response()->json([ | ||||||
|             'message' => 'Password reset successfully.' |             'message' => 'Password reset successfully.', | ||||||
|         ]); |         ]); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -62,7 +54,7 @@ class ResetPasswordController extends Controller | |||||||
|      */ |      */ | ||||||
|     protected function resetPassword($user, $password) |     protected function resetPassword($user, $password) | ||||||
|     { |     { | ||||||
|         $user->password = \Hash::make($password); |         $user->password = $password; | ||||||
| 
 | 
 | ||||||
|         $user->setRememberToken(Str::random(60)); |         $user->setRememberToken(Str::random(60)); | ||||||
| 
 | 
 | ||||||
| @ -0,0 +1,42 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\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'); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										22
									
								
								app/Http/Controllers/V1/Admin/Backup/ApiController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								app/Http/Controllers/V1/Admin/Backup/ApiController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | // Implementation taken from nova-backup-tool - https://github.com/spatie/nova-backup-tool/ | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\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, | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										99
									
								
								app/Http/Controllers/V1/Admin/Backup/BackupsController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								app/Http/Controllers/V1/Admin/Backup/BackupsController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,99 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | // Implementation taken from nova-backup-tool - https://github.com/spatie/nova-backup-tool/ | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\Backup; | ||||||
|  |  | ||||||
|  | use Crater\Jobs\CreateBackupJob; | ||||||
|  | use Crater\Rules\Backup\PathToZip; | ||||||
|  | use Illuminate\Http\JsonResponse; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  | use Illuminate\Support\Facades\Cache; | ||||||
|  | use Spatie\Backup\BackupDestination\Backup; | ||||||
|  | use Spatie\Backup\BackupDestination\BackupDestination; | ||||||
|  | use Spatie\Backup\Helpers\Format; | ||||||
|  |  | ||||||
|  | class BackupsController extends ApiController | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Display a listing of the resource. | ||||||
|  |      * | ||||||
|  |      * @return JsonResponse | ||||||
|  |      */ | ||||||
|  |     public function index(Request $request) | ||||||
|  |     { | ||||||
|  |         $this->authorize('manage backups'); | ||||||
|  |  | ||||||
|  |         $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) | ||||||
|  |     { | ||||||
|  |         $this->authorize('manage backups'); | ||||||
|  |  | ||||||
|  |         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) | ||||||
|  |     { | ||||||
|  |         $this->authorize('manage backups'); | ||||||
|  |  | ||||||
|  |         $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(); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,59 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | // Implementation taken from nova-backup-tool - https://github.com/spatie/nova-backup-tool/ | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\Backup; | ||||||
|  |  | ||||||
|  | use Crater\Rules\Backup\PathToZip; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  | use Spatie\Backup\BackupDestination\Backup; | ||||||
|  | use Spatie\Backup\BackupDestination\BackupDestination; | ||||||
|  | use Symfony\Component\HttpFoundation\Response; | ||||||
|  | use Symfony\Component\HttpFoundation\StreamedResponse; | ||||||
|  |  | ||||||
|  | class DownloadBackupController extends ApiController | ||||||
|  | { | ||||||
|  |     public function __invoke(Request $request) | ||||||
|  |     { | ||||||
|  |         $this->authorize('manage backups'); | ||||||
|  |  | ||||||
|  |         $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); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,85 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\Company; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Http\Requests\CompaniesRequest; | ||||||
|  | use Crater\Http\Resources\CompanyResource; | ||||||
|  | use Crater\Models\Company; | ||||||
|  | use Crater\Models\User; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  | use Silber\Bouncer\BouncerFacade; | ||||||
|  | use Vinkla\Hashids\Facades\Hashids; | ||||||
|  |  | ||||||
|  | class CompaniesController extends Controller | ||||||
|  | { | ||||||
|  |     public function store(CompaniesRequest $request) | ||||||
|  |     { | ||||||
|  |         $this->authorize('create company'); | ||||||
|  |  | ||||||
|  |         $user = $request->user(); | ||||||
|  |  | ||||||
|  |         $company = Company::create($request->getCompanyPayload()); | ||||||
|  |         $company->unique_hash = Hashids::connection(Company::class)->encode($company->id); | ||||||
|  |         $company->save(); | ||||||
|  |         $company->setupDefaultData(); | ||||||
|  |         $user->companies()->attach($company->id); | ||||||
|  |         $user->assign('super admin'); | ||||||
|  |  | ||||||
|  |         if ($request->address) { | ||||||
|  |             $company->address()->create($request->address); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return new CompanyResource($company); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function destroy(Request $request) | ||||||
|  |     { | ||||||
|  |         $company = Company::find($request->header('company')); | ||||||
|  |  | ||||||
|  |         $this->authorize('delete company', $company); | ||||||
|  |  | ||||||
|  |         $user = $request->user(); | ||||||
|  |  | ||||||
|  |         if ($request->name !== $company->name) { | ||||||
|  |             return respondJson('company_name_must_match_with_given_name', 'Company name must match with given name'); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if ($user->loadCount('companies')->companies_count <= 1) { | ||||||
|  |             return respondJson('You_cannot_delete_all_companies', 'You cannot delete all companies'); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $company->deleteCompany($user); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'success' => true | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function transferOwnership(Request $request, User $user) | ||||||
|  |     { | ||||||
|  |         $company = Company::find($request->header('company')); | ||||||
|  |         $this->authorize('transfer company ownership', $company); | ||||||
|  |  | ||||||
|  |         if ($user->hasCompany($company->id)) { | ||||||
|  |             return response()->json([ | ||||||
|  |                 'success' => false, | ||||||
|  |                 'message' => 'User does not belongs to this company.' | ||||||
|  |             ]); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $company->update(['owner_id' => $user->id]); | ||||||
|  |         BouncerFacade::sync($user)->roles(['super admin']); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'success' => true | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getUserCompanies(Request $request) | ||||||
|  |     { | ||||||
|  |         $companies = $request->user()->companies; | ||||||
|  |  | ||||||
|  |         return CompanyResource::collection($companies); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										24
									
								
								app/Http/Controllers/V1/Admin/Company/CompanyController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								app/Http/Controllers/V1/Admin/Company/CompanyController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,24 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\Company; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Http\Resources\CompanyResource; | ||||||
|  | use Crater\Models\Company; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  |  | ||||||
|  | class CompanyController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Handle the incoming request. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function __invoke(Request $request) | ||||||
|  |     { | ||||||
|  |         $company = Company::find($request->header('company')); | ||||||
|  |  | ||||||
|  |         return new CompanyResource($company); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,22 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\Config; | ||||||
|  |  | ||||||
|  | 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'), | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										22
									
								
								app/Http/Controllers/V1/Admin/Config/LanguagesController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								app/Http/Controllers/V1/Admin/Config/LanguagesController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\Config; | ||||||
|  |  | ||||||
|  | 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'), | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,22 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\Config; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  |  | ||||||
|  | class RetrospectiveEditsController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Handle the incoming request. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function __invoke(Request $request) | ||||||
|  |     { | ||||||
|  |         return response()->json([ | ||||||
|  |             'retrospective_edits' => config('crater.retrospective_edits'), | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,96 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\CustomField; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Http\Requests\CustomFieldRequest; | ||||||
|  | use Crater\Http\Resources\CustomFieldResource; | ||||||
|  | use Crater\Models\CustomField; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  |  | ||||||
|  | class CustomFieldsController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Display a listing of the resource. | ||||||
|  |      * | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function index(Request $request) | ||||||
|  |     { | ||||||
|  |         $this->authorize('viewAny', CustomField::class); | ||||||
|  |  | ||||||
|  |         $limit = $request->has('limit') ? $request->limit : 5; | ||||||
|  |  | ||||||
|  |         $customFields = CustomField::applyFilters($request->all()) | ||||||
|  |             ->whereCompany() | ||||||
|  |             ->latest() | ||||||
|  |             ->paginateData($limit); | ||||||
|  |  | ||||||
|  |         return CustomFieldResource::collection($customFields); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Store a newly created resource in storage. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\CustomFieldRequest  $request | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function store(CustomFieldRequest $request) | ||||||
|  |     { | ||||||
|  |         $this->authorize('create', CustomField::class); | ||||||
|  |  | ||||||
|  |         $customField = CustomField::createCustomField($request); | ||||||
|  |  | ||||||
|  |         return new CustomFieldResource($customField); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Display the specified resource. | ||||||
|  |      * | ||||||
|  |      * @param  int  $id | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function show(CustomField $customField) | ||||||
|  |     { | ||||||
|  |         $this->authorize('view', $customField); | ||||||
|  |  | ||||||
|  |         return new CustomFieldResource($customField); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 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) | ||||||
|  |     { | ||||||
|  |         $this->authorize('update', $customField); | ||||||
|  |  | ||||||
|  |         $customField->updateCustomField($request); | ||||||
|  |  | ||||||
|  |         return new CustomFieldResource($customField); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Remove the specified resource from storage. | ||||||
|  |      * | ||||||
|  |      * @param  int  $id | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function destroy(CustomField $customField) | ||||||
|  |     { | ||||||
|  |         $this->authorize('delete', $customField); | ||||||
|  |  | ||||||
|  |         if ($customField->customFieldValues()->exists()) { | ||||||
|  |             $customField->customFieldValues()->delete(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $customField->forceDelete(); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'success' => true, | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,142 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\Customer; | ||||||
|  |  | ||||||
|  | use Carbon\Carbon; | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Http\Resources\CustomerResource; | ||||||
|  | use Crater\Models\CompanySetting; | ||||||
|  | use Crater\Models\Customer; | ||||||
|  | use Crater\Models\Expense; | ||||||
|  | use Crater\Models\Invoice; | ||||||
|  | use Crater\Models\Payment; | ||||||
|  | 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, Customer $customer) | ||||||
|  |     { | ||||||
|  |         $this->authorize('view', $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() | ||||||
|  |                     ->whereCustomer($customer->id) | ||||||
|  |                     ->sum('total') ?? 0 | ||||||
|  |             ); | ||||||
|  |             array_push( | ||||||
|  |                 $expenseTotals, | ||||||
|  |                 Expense::whereBetween( | ||||||
|  |                     'expense_date', | ||||||
|  |                     [$start->format('Y-m-d'), $end->format('Y-m-d')] | ||||||
|  |                 ) | ||||||
|  |                     ->whereCompany() | ||||||
|  |                     ->whereUser($customer->id) | ||||||
|  |                     ->sum('amount') ?? 0 | ||||||
|  |             ); | ||||||
|  |             array_push( | ||||||
|  |                 $receiptTotals, | ||||||
|  |                 Payment::whereBetween( | ||||||
|  |                     'payment_date', | ||||||
|  |                     [$start->format('Y-m-d'), $end->format('Y-m-d')] | ||||||
|  |                 ) | ||||||
|  |                     ->whereCompany() | ||||||
|  |                     ->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::whereBetween( | ||||||
|  |             'invoice_date', | ||||||
|  |             [$startDate->format('Y-m-d'), $start->format('Y-m-d')] | ||||||
|  |         ) | ||||||
|  |             ->whereCompany() | ||||||
|  |             ->whereCustomer($customer->id) | ||||||
|  |             ->sum('total'); | ||||||
|  |         $totalReceipts = Payment::whereBetween( | ||||||
|  |             'payment_date', | ||||||
|  |             [$startDate->format('Y-m-d'), $start->format('Y-m-d')] | ||||||
|  |         ) | ||||||
|  |             ->whereCompany() | ||||||
|  |             ->whereCustomer($customer->id) | ||||||
|  |             ->sum('amount'); | ||||||
|  |         $totalExpenses = Expense::whereBetween( | ||||||
|  |             'expense_date', | ||||||
|  |             [$startDate->format('Y-m-d'), $start->format('Y-m-d')] | ||||||
|  |         ) | ||||||
|  |             ->whereCompany() | ||||||
|  |             ->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 = Customer::find($customer->id); | ||||||
|  |  | ||||||
|  |         return (new CustomerResource($customer)) | ||||||
|  |             ->additional(['meta' => [ | ||||||
|  |                 'chartData' => $chartData | ||||||
|  |             ]]); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										108
									
								
								app/Http/Controllers/V1/Admin/Customer/CustomersController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								app/Http/Controllers/V1/Admin/Customer/CustomersController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,108 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\Customer; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Http\Requests; | ||||||
|  | use Crater\Http\Requests\DeleteCustomersRequest; | ||||||
|  | use Crater\Http\Resources\CustomerResource; | ||||||
|  | use Crater\Models\Customer; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  | use Illuminate\Support\Facades\DB; | ||||||
|  |  | ||||||
|  | class CustomersController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Display a listing of the resource. | ||||||
|  |      * | ||||||
|  |      * @return \Illuminate\Http\JsonResponse | ||||||
|  |      */ | ||||||
|  |     public function index(Request $request) | ||||||
|  |     { | ||||||
|  |         $this->authorize('viewAny', Customer::class); | ||||||
|  |  | ||||||
|  |         $limit = $request->has('limit') ? $request->limit : 10; | ||||||
|  |  | ||||||
|  |         $customers = Customer::with('creator') | ||||||
|  |             ->whereCompany() | ||||||
|  |             ->applyFilters($request->all()) | ||||||
|  |             ->select( | ||||||
|  |                 'customers.*', | ||||||
|  |                 DB::raw('sum(invoices.base_due_amount) as base_due_amount'), | ||||||
|  |                 DB::raw('sum(invoices.due_amount) as due_amount'), | ||||||
|  |             ) | ||||||
|  |             ->groupBy('customers.id') | ||||||
|  |             ->leftJoin('invoices', 'customers.id', '=', 'invoices.customer_id') | ||||||
|  |             ->paginateData($limit); | ||||||
|  |  | ||||||
|  |         return (CustomerResource::collection($customers)) | ||||||
|  |             ->additional(['meta' => [ | ||||||
|  |                 'customer_total_count' => Customer::whereCompany()->count(), | ||||||
|  |             ]]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Store a newly created resource in storage. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @return \Illuminate\Http\JsonResponse | ||||||
|  |      */ | ||||||
|  |     public function store(Requests\CustomerRequest $request) | ||||||
|  |     { | ||||||
|  |         $this->authorize('create', Customer::class); | ||||||
|  |  | ||||||
|  |         $customer = Customer::createCustomer($request); | ||||||
|  |  | ||||||
|  |         return new CustomerResource($customer); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Display the specified resource. | ||||||
|  |      * | ||||||
|  |      * @param  Customer $customer | ||||||
|  |      * @return \Illuminate\Http\JsonResponse | ||||||
|  |      */ | ||||||
|  |     public function show(Customer $customer) | ||||||
|  |     { | ||||||
|  |         $this->authorize('view', $customer); | ||||||
|  |  | ||||||
|  |         return new CustomerResource($customer); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Update the specified resource in storage. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request $request | ||||||
|  |      * @param  \Crater\Models\Customer $customer | ||||||
|  |      * @return \Illuminate\Http\JsonResponse | ||||||
|  |      */ | ||||||
|  |     public function update(Requests\CustomerRequest $request, Customer $customer) | ||||||
|  |     { | ||||||
|  |         $this->authorize('update', $customer); | ||||||
|  |  | ||||||
|  |         $customer = Customer::updateCustomer($request, $customer); | ||||||
|  |  | ||||||
|  |         if (is_string($customer)) { | ||||||
|  |             return respondJson('you_cannot_edit_currency', 'Cannot change currency once transactions created'); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return new CustomerResource($customer); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 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(DeleteCustomersRequest $request) | ||||||
|  |     { | ||||||
|  |         $this->authorize('delete multiple customers'); | ||||||
|  |  | ||||||
|  |         Customer::deleteCustomers($request->ids); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'success' => true, | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										165
									
								
								app/Http/Controllers/V1/Admin/Dashboard/DashboardController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										165
									
								
								app/Http/Controllers/V1/Admin/Dashboard/DashboardController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,165 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\Dashboard; | ||||||
|  |  | ||||||
|  | use Carbon\Carbon; | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Models\Company; | ||||||
|  | use Crater\Models\CompanySetting; | ||||||
|  | use Crater\Models\Customer; | ||||||
|  | use Crater\Models\Estimate; | ||||||
|  | use Crater\Models\Expense; | ||||||
|  | use Crater\Models\Invoice; | ||||||
|  | use Crater\Models\Payment; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  |  | ||||||
|  | class DashboardController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Handle the incoming request. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @return \Illuminate\Http\JsonResponse | ||||||
|  |      */ | ||||||
|  |     public function __invoke(Request $request) | ||||||
|  |     { | ||||||
|  |         $company = Company::find($request->header('company')); | ||||||
|  |  | ||||||
|  |         $this->authorize('view dashboard', $company); | ||||||
|  |  | ||||||
|  |         $invoice_totals = []; | ||||||
|  |         $expense_totals = []; | ||||||
|  |         $receipt_totals = []; | ||||||
|  |         $net_income_totals = []; | ||||||
|  |  | ||||||
|  |         $i = 0; | ||||||
|  |         $months = []; | ||||||
|  |         $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( | ||||||
|  |                 $invoice_totals, | ||||||
|  |                 Invoice::whereBetween( | ||||||
|  |                     'invoice_date', | ||||||
|  |                     [$start->format('Y-m-d'), $end->format('Y-m-d')] | ||||||
|  |                 ) | ||||||
|  |                 ->whereCompany() | ||||||
|  |                 ->sum('base_total') | ||||||
|  |             ); | ||||||
|  |             array_push( | ||||||
|  |                 $expense_totals, | ||||||
|  |                 Expense::whereBetween( | ||||||
|  |                     'expense_date', | ||||||
|  |                     [$start->format('Y-m-d'), $end->format('Y-m-d')] | ||||||
|  |                 ) | ||||||
|  |                 ->whereCompany() | ||||||
|  |                 ->sum('base_amount') | ||||||
|  |             ); | ||||||
|  |             array_push( | ||||||
|  |                 $receipt_totals, | ||||||
|  |                 Payment::whereBetween( | ||||||
|  |                     'payment_date', | ||||||
|  |                     [$start->format('Y-m-d'), $end->format('Y-m-d')] | ||||||
|  |                 ) | ||||||
|  |                 ->whereCompany() | ||||||
|  |                 ->sum('base_amount') | ||||||
|  |             ); | ||||||
|  |             array_push( | ||||||
|  |                 $net_income_totals, | ||||||
|  |                 ($receipt_totals[$i] - $expense_totals[$i]) | ||||||
|  |             ); | ||||||
|  |             $i++; | ||||||
|  |             array_push($months, $start->format('M')); | ||||||
|  |             $monthCounter++; | ||||||
|  |             $end->startOfMonth(); | ||||||
|  |             $start->addMonth()->startOfMonth(); | ||||||
|  |             $end->addMonth()->endOfMonth(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $start->subMonth()->endOfMonth(); | ||||||
|  |  | ||||||
|  |         $total_sales = Invoice::whereBetween( | ||||||
|  |             'invoice_date', | ||||||
|  |             [$startDate->format('Y-m-d'), $start->format('Y-m-d')] | ||||||
|  |         ) | ||||||
|  |             ->whereCompany() | ||||||
|  |             ->sum('base_total'); | ||||||
|  |  | ||||||
|  |         $total_receipts = Payment::whereBetween( | ||||||
|  |             'payment_date', | ||||||
|  |             [$startDate->format('Y-m-d'), $start->format('Y-m-d')] | ||||||
|  |         ) | ||||||
|  |             ->whereCompany() | ||||||
|  |             ->sum('base_amount'); | ||||||
|  |  | ||||||
|  |         $total_expenses = Expense::whereBetween( | ||||||
|  |             'expense_date', | ||||||
|  |             [$startDate->format('Y-m-d'), $start->format('Y-m-d')] | ||||||
|  |         ) | ||||||
|  |             ->whereCompany() | ||||||
|  |             ->sum('base_amount'); | ||||||
|  |  | ||||||
|  |         $total_net_income = (int)$total_receipts - (int)$total_expenses; | ||||||
|  |  | ||||||
|  |         $chart_data = [ | ||||||
|  |             'months' => $months, | ||||||
|  |             'invoice_totals' => $invoice_totals, | ||||||
|  |             'expense_totals' => $expense_totals, | ||||||
|  |             'receipt_totals' => $receipt_totals, | ||||||
|  |             'net_income_totals' => $net_income_totals, | ||||||
|  |         ]; | ||||||
|  |  | ||||||
|  |         $total_customer_count = Customer::whereCompany()->count(); | ||||||
|  |         $total_invoice_count = Invoice::whereCompany() | ||||||
|  |             ->count(); | ||||||
|  |         $total_estimate_count = Estimate::whereCompany()->count(); | ||||||
|  |         $total_amount_due = Invoice::whereCompany() | ||||||
|  |             ->sum('base_due_amount'); | ||||||
|  |  | ||||||
|  |         $recent_due_invoices = Invoice::with('customer') | ||||||
|  |             ->whereCompany() | ||||||
|  |             ->where('base_due_amount', '>', 0) | ||||||
|  |             ->take(5) | ||||||
|  |             ->latest() | ||||||
|  |             ->get(); | ||||||
|  |         $recent_estimates = Estimate::with('customer')->whereCompany()->take(5)->latest()->get(); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'total_amount_due' => $total_amount_due, | ||||||
|  |             'total_customer_count' => $total_customer_count, | ||||||
|  |             'total_invoice_count' => $total_invoice_count, | ||||||
|  |             'total_estimate_count' => $total_estimate_count, | ||||||
|  |  | ||||||
|  |             'recent_due_invoices' => $recent_due_invoices, | ||||||
|  |             'recent_estimates' => $recent_estimates, | ||||||
|  |  | ||||||
|  |             'chart_data' => $chart_data, | ||||||
|  |  | ||||||
|  |             'total_sales' => $total_sales, | ||||||
|  |             'total_receipts' => $total_receipts, | ||||||
|  |             'total_expenses' => $total_expenses, | ||||||
|  |             'total_net_income' => $total_net_income, | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,28 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\Estimate; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Models\Estimate; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  |  | ||||||
|  | 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) | ||||||
|  |     { | ||||||
|  |         $this->authorize('send estimate', $estimate); | ||||||
|  |  | ||||||
|  |         $estimate->update($request->only('status')); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'success' => true, | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,132 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\Estimate; | ||||||
|  |  | ||||||
|  | use Carbon\Carbon; | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Http\Resources\InvoiceResource; | ||||||
|  | use Crater\Models\CompanySetting; | ||||||
|  | use Crater\Models\Estimate; | ||||||
|  | use Crater\Models\Invoice; | ||||||
|  | use Crater\Services\SerialNumberFormatter; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  | use Illuminate\Support\Facades\Auth; | ||||||
|  | use Vinkla\Hashids\Facades\Hashids; | ||||||
|  |  | ||||||
|  | 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, Invoice $invoice) | ||||||
|  |     { | ||||||
|  |         $this->authorize('create', Invoice::class); | ||||||
|  |  | ||||||
|  |         $estimate->load(['items', 'items.taxes', 'customer', 'taxes']); | ||||||
|  |  | ||||||
|  |         $invoice_date = Carbon::now(); | ||||||
|  |         $due_date = null; | ||||||
|  |  | ||||||
|  |         $dueDateEnabled = CompanySetting::getSetting( | ||||||
|  |             'invoice_set_due_date_automatically', | ||||||
|  |             $request->header('company') | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         if ($dueDateEnabled === 'YES') { | ||||||
|  |             $dueDateDays = CompanySetting::getSetting( | ||||||
|  |                 'invoice_due_date_days', | ||||||
|  |                 $request->header('company') | ||||||
|  |             ); | ||||||
|  |             $due_date = Carbon::now()->addDays($dueDateDays)->format('Y-m-d'); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $serial = (new SerialNumberFormatter()) | ||||||
|  |             ->setModel($invoice) | ||||||
|  |             ->setCompany($estimate->company_id) | ||||||
|  |             ->setCustomer($estimate->customer_id) | ||||||
|  |             ->setNextNumbers(); | ||||||
|  |  | ||||||
|  |         $templateName = $estimate->getInvoiceTemplateName(); | ||||||
|  |  | ||||||
|  |         $exchange_rate = $estimate->exchange_rate; | ||||||
|  |  | ||||||
|  |         $invoice = Invoice::create([ | ||||||
|  |             'creator_id' => Auth::id(), | ||||||
|  |             'invoice_date' => $invoice_date->format('Y-m-d'), | ||||||
|  |             'due_date' => $due_date, | ||||||
|  |             'invoice_number' => $serial->getNextNumber(), | ||||||
|  |             'sequence_number' => $serial->nextSequenceNumber, | ||||||
|  |             'customer_sequence_number' => $serial->nextCustomerSequenceNumber, | ||||||
|  |             'reference_number' => $serial->getNextNumber(), | ||||||
|  |             'customer_id' => $estimate->customer_id, | ||||||
|  |             'company_id' => $request->header('company'), | ||||||
|  |             'template_name' => $templateName, | ||||||
|  |             '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, | ||||||
|  |             'exchange_rate' => $exchange_rate, | ||||||
|  |             'base_discount_val' => $estimate->discount_val * $exchange_rate, | ||||||
|  |             'base_sub_total' => $estimate->sub_total * $exchange_rate, | ||||||
|  |             'base_total' => $estimate->total * $exchange_rate, | ||||||
|  |             'base_tax' => $estimate->tax * $exchange_rate, | ||||||
|  |             'currency_id' => $estimate->currency_id, | ||||||
|  |         ]); | ||||||
|  |  | ||||||
|  |         $invoice->unique_hash = Hashids::connection(Invoice::class)->encode($invoice->id); | ||||||
|  |         $invoice->save(); | ||||||
|  |         $invoiceItems = $estimate->items->toArray(); | ||||||
|  |  | ||||||
|  |         foreach ($invoiceItems as $invoiceItem) { | ||||||
|  |             $invoiceItem['company_id'] = $request->header('company'); | ||||||
|  |             $invoiceItem['name'] = $invoiceItem['name']; | ||||||
|  |             $estimateItem['exchange_rate'] = $exchange_rate; | ||||||
|  |             $estimateItem['base_price'] = $invoiceItem['price'] * $exchange_rate; | ||||||
|  |             $estimateItem['base_discount_val'] = $invoiceItem['discount_val'] * $exchange_rate; | ||||||
|  |             $estimateItem['base_tax'] = $invoiceItem['tax'] * $exchange_rate; | ||||||
|  |             $estimateItem['base_total'] = $invoiceItem['total'] * $exchange_rate; | ||||||
|  |  | ||||||
|  |             $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'); | ||||||
|  |                 $tax['exchange_rate'] = $exchange_rate; | ||||||
|  |                 $tax['base_amount'] = $tax['amount'] * $exchange_rate; | ||||||
|  |                 $tax['currency_id'] = $estimate->currency_id; | ||||||
|  |                 unset($tax['estimate_id']); | ||||||
|  |  | ||||||
|  |                 $invoice->taxes()->create($tax); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $estimate->checkForEstimateConvertAction(); | ||||||
|  |  | ||||||
|  |         $invoice = Invoice::find($invoice->id); | ||||||
|  |  | ||||||
|  |         return new InvoiceResource($invoice); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,27 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\Estimate; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Models\Estimate; | ||||||
|  | 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) | ||||||
|  |     { | ||||||
|  |         $this->authorize('viewAny', Estimate::class); | ||||||
|  |  | ||||||
|  |         $estimateTemplates = Estimate::estimateTemplates(); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'estimateTemplates' => $estimateTemplates | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,77 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\Estimate; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Http\Requests\DeleteEstimatesRequest; | ||||||
|  | use Crater\Http\Requests\EstimatesRequest; | ||||||
|  | use Crater\Http\Resources\EstimateResource; | ||||||
|  | use Crater\Jobs\GenerateEstimatePdfJob; | ||||||
|  | use Crater\Models\Estimate; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  |  | ||||||
|  | class EstimatesController extends Controller | ||||||
|  | { | ||||||
|  |     public function index(Request $request) | ||||||
|  |     { | ||||||
|  |         $this->authorize('viewAny', Estimate::class); | ||||||
|  |  | ||||||
|  |         $limit = $request->has('limit') ? $request->limit : 10; | ||||||
|  |  | ||||||
|  |         $estimates = Estimate::whereCompany() | ||||||
|  |             ->join('customers', 'customers.id', '=', 'estimates.customer_id') | ||||||
|  |             ->applyFilters($request->all()) | ||||||
|  |             ->select('estimates.*', 'customers.name') | ||||||
|  |             ->latest() | ||||||
|  |             ->paginateData($limit); | ||||||
|  |  | ||||||
|  |         return (EstimateResource::collection($estimates)) | ||||||
|  |             ->additional(['meta' => [ | ||||||
|  |                 'estimate_total_count' => Estimate::whereCompany()->count(), | ||||||
|  |             ]]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function store(EstimatesRequest $request) | ||||||
|  |     { | ||||||
|  |         $this->authorize('create', Estimate::class); | ||||||
|  |  | ||||||
|  |         $estimate = Estimate::createEstimate($request); | ||||||
|  |  | ||||||
|  |         if ($request->has('estimateSend')) { | ||||||
|  |             $estimate->send($request->title, $request->body); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         GenerateEstimatePdfJob::dispatch($estimate); | ||||||
|  |  | ||||||
|  |         return new EstimateResource($estimate); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function show(Request $request, Estimate $estimate) | ||||||
|  |     { | ||||||
|  |         $this->authorize('view', $estimate); | ||||||
|  |  | ||||||
|  |         return new EstimateResource($estimate); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function update(EstimatesRequest $request, Estimate $estimate) | ||||||
|  |     { | ||||||
|  |         $this->authorize('update', $estimate); | ||||||
|  |  | ||||||
|  |         $estimate = $estimate->updateEstimate($request); | ||||||
|  |  | ||||||
|  |         GenerateEstimatePdfJob::dispatch($estimate, true); | ||||||
|  |  | ||||||
|  |         return new EstimateResource($estimate); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function delete(DeleteEstimatesRequest $request) | ||||||
|  |     { | ||||||
|  |         $this->authorize('delete multiple estimates'); | ||||||
|  |  | ||||||
|  |         Estimate::destroy($request->ids); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'success' => true, | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,25 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\Estimate; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Http\Requests\SendEstimatesRequest; | ||||||
|  | use Crater\Models\Estimate; | ||||||
|  |  | ||||||
|  | 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) | ||||||
|  |     { | ||||||
|  |         $this->authorize('send estimate', $estimate); | ||||||
|  |  | ||||||
|  |         $response = $estimate->send($request->all()); | ||||||
|  |  | ||||||
|  |         return response()->json($response); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,26 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\Estimate; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Http\Requests\SendEstimatesRequest; | ||||||
|  | use Crater\Models\Estimate; | ||||||
|  | use Illuminate\Mail\Markdown; | ||||||
|  |  | ||||||
|  | class SendEstimatePreviewController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |     * Handle the incoming request. | ||||||
|  |     * | ||||||
|  |     * @param  \Crater\Http\Requests\SendEstimatesRequest  $request | ||||||
|  |     * @return \Illuminate\Http\JsonResponse | ||||||
|  |     */ | ||||||
|  |     public function __invoke(SendEstimatesRequest $request, Estimate $estimate) | ||||||
|  |     { | ||||||
|  |         $this->authorize('send estimate', $estimate); | ||||||
|  |  | ||||||
|  |         $markdown = new Markdown(view(), config('mail.markdown')); | ||||||
|  |  | ||||||
|  |         return $markdown->render('emails.send.estimate', ['data' => $estimate->sendEstimateData($request->all())]); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,117 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\ExchangeRate; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Http\Requests\ExchangeRateProviderRequest; | ||||||
|  | use Crater\Http\Resources\ExchangeRateProviderResource; | ||||||
|  | use Crater\Models\ExchangeRateProvider; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  |  | ||||||
|  | class ExchangeRateProviderController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Display a listing of the resource. | ||||||
|  |      * | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function index(Request $request) | ||||||
|  |     { | ||||||
|  |         $this->authorize('viewAny', ExchangeRateProvider::class); | ||||||
|  |  | ||||||
|  |         $limit = $request->has('limit') ? $request->limit : 5; | ||||||
|  |  | ||||||
|  |         $exchangeRateProviders = ExchangeRateProvider::whereCompany()->paginate($limit); | ||||||
|  |  | ||||||
|  |         return ExchangeRateProviderResource::collection($exchangeRateProviders); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Store a newly created resource in storage. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function store(ExchangeRateProviderRequest $request) | ||||||
|  |     { | ||||||
|  |         $this->authorize('create', ExchangeRateProvider::class); | ||||||
|  |  | ||||||
|  |         $query = ExchangeRateProvider::checkActiveCurrencies($request); | ||||||
|  |  | ||||||
|  |         if (count($query) !== 0) { | ||||||
|  |             return respondJson('currency_used', 'Currency used.'); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $checkConverterApi = ExchangeRateProvider::checkExchangeRateProviderStatus($request); | ||||||
|  |  | ||||||
|  |         if ($checkConverterApi->status() == 200) { | ||||||
|  |             $exchangeRateProvider = ExchangeRateProvider::createFromRequest($request); | ||||||
|  |  | ||||||
|  |             return new ExchangeRateProviderResource($exchangeRateProvider); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $checkConverterApi; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Display the specified resource. | ||||||
|  |      * | ||||||
|  |      * @param  \Crater\Models\ExchangeRateProvider  $exchangeRateProvider | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function show(ExchangeRateProvider $exchangeRateProvider) | ||||||
|  |     { | ||||||
|  |         $this->authorize('view', $exchangeRateProvider); | ||||||
|  |  | ||||||
|  |         return new ExchangeRateProviderResource($exchangeRateProvider); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Update the specified resource in storage. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @param  \Crater\Models\ExchangeRateProvider  $exchangeRateProvider | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function update(ExchangeRateProviderRequest $request, ExchangeRateProvider $exchangeRateProvider) | ||||||
|  |     { | ||||||
|  |         $this->authorize('update', $exchangeRateProvider); | ||||||
|  |  | ||||||
|  |         $query = $exchangeRateProvider->checkUpdateActiveCurrencies($request); | ||||||
|  |  | ||||||
|  |         if (count($query) !== 0) { | ||||||
|  |             return respondJson('currency_used', 'Currency used.'); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $checkConverterApi = ExchangeRateProvider::checkExchangeRateProviderStatus($request); | ||||||
|  |  | ||||||
|  |         if ($checkConverterApi->status() == 200) { | ||||||
|  |             $exchangeRateProvider->updateFromRequest($request); | ||||||
|  |  | ||||||
|  |             return new ExchangeRateProviderResource($exchangeRateProvider); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $checkConverterApi; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Remove the specified resource from storage. | ||||||
|  |      * | ||||||
|  |      * @param  \Crater\Models\ExchangeRateProvider  $exchangeRateProvider | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function destroy(ExchangeRateProvider $exchangeRateProvider) | ||||||
|  |     { | ||||||
|  |         $this->authorize('delete', $exchangeRateProvider); | ||||||
|  |  | ||||||
|  |         if ($exchangeRateProvider->active == true) { | ||||||
|  |             return respondJson('provider_active', 'Provider Active.'); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $exchangeRateProvider->delete(); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'success' => true, | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,35 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\ExchangeRate; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Models\Currency; | ||||||
|  | use Crater\Models\ExchangeRateProvider; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  |  | ||||||
|  | class GetActiveProviderController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Handle the incoming request. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function __invoke(Request $request, Currency $currency) | ||||||
|  |     { | ||||||
|  |         $query = ExchangeRateProvider::whereCompany()->whereJsonContains('currencies', $currency->code) | ||||||
|  |                 ->where('active', true) | ||||||
|  |                 ->get(); | ||||||
|  |  | ||||||
|  |         if (count($query) !== 0) { | ||||||
|  |             return response()->json([ | ||||||
|  |                 'success' => true, | ||||||
|  |                 'message' => 'provider_active', | ||||||
|  |             ], 200); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'error' => 'no_active_provider', | ||||||
|  |         ], 200); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,57 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\ExchangeRate; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Models\CompanySetting; | ||||||
|  | use Crater\Models\Currency; | ||||||
|  | use Crater\Models\ExchangeRateLog; | ||||||
|  | use Crater\Models\ExchangeRateProvider; | ||||||
|  | use Crater\Traits\ExchangeRateProvidersTrait; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  | use Illuminate\Support\Arr; | ||||||
|  |  | ||||||
|  | class GetExchangeRateController extends Controller | ||||||
|  | { | ||||||
|  |     use ExchangeRateProvidersTrait; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Handle the incoming request. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function __invoke(Request $request, Currency $currency) | ||||||
|  |     { | ||||||
|  |         $settings = CompanySetting::getSettings(['currency'], $request->header('company')); | ||||||
|  |         $baseCurrency = Currency::findOrFail($settings['currency']); | ||||||
|  |  | ||||||
|  |         $query = ExchangeRateProvider::whereJsonContains('currencies', $currency->code) | ||||||
|  |                 ->where('active', true) | ||||||
|  |                 ->get() | ||||||
|  |                 ->toArray(); | ||||||
|  |  | ||||||
|  |         $exchange_rate = ExchangeRateLog::where('base_currency_id', $currency->id) | ||||||
|  |                 ->where('currency_id', $baseCurrency->id) | ||||||
|  |                 ->orderBy('created_at', 'desc') | ||||||
|  |                 ->value('exchange_rate'); | ||||||
|  |  | ||||||
|  |         if ($query) { | ||||||
|  |             $filter = Arr::only($query[0], ['key', 'driver', 'driver_config']); | ||||||
|  |             $exchange_rate_value = $this->getExchangeRate($filter, $currency->code, $baseCurrency->code); | ||||||
|  |  | ||||||
|  |             if ($exchange_rate_value->status() == 200) { | ||||||
|  |                 return $exchange_rate_value; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         if ($exchange_rate) { | ||||||
|  |             return response()->json([ | ||||||
|  |                 'exchangeRate' => [$exchange_rate], | ||||||
|  |             ], 200); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'error' => 'no_exchange_rate_available', | ||||||
|  |         ], 200); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,26 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\ExchangeRate; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Models\ExchangeRateProvider; | ||||||
|  | use Crater\Traits\ExchangeRateProvidersTrait; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  |  | ||||||
|  | class GetSupportedCurrenciesController extends Controller | ||||||
|  | { | ||||||
|  |     use ExchangeRateProvidersTrait; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Handle the incoming request. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function __invoke(Request $request) | ||||||
|  |     { | ||||||
|  |         $this->authorize('viewAny', ExchangeRateProvider::class); | ||||||
|  |  | ||||||
|  |         return $this->getSupportedCurrencies($request); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,55 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\ExchangeRate; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Models\ExchangeRateProvider; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  |  | ||||||
|  | class GetUsedCurrenciesController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Handle the incoming request. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function __invoke(Request $request) | ||||||
|  |     { | ||||||
|  |         $this->authorize('viewAny', ExchangeRateProvider::class); | ||||||
|  |  | ||||||
|  |         $providerId = $request->provider_id; | ||||||
|  |  | ||||||
|  |         $activeExchangeRateProviders = ExchangeRateProvider::where('active', true) | ||||||
|  |             ->whereCompany() | ||||||
|  |             ->when($providerId, function ($query) use ($providerId) { | ||||||
|  |                 return $query->where('id', '<>', $providerId); | ||||||
|  |             }) | ||||||
|  |             ->pluck('currencies'); | ||||||
|  |         $activeExchangeRateProvider = []; | ||||||
|  |  | ||||||
|  |         foreach ($activeExchangeRateProviders as $data) { | ||||||
|  |             if (is_array($data)) { | ||||||
|  |                 for ($limit = 0; $limit < count($data); $limit++) { | ||||||
|  |                     $activeExchangeRateProvider[] = $data[$limit]; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $allExchangeRateProviders = ExchangeRateProvider::whereCompany()->pluck('currencies'); | ||||||
|  |         $allExchangeRateProvider = []; | ||||||
|  |  | ||||||
|  |         foreach ($allExchangeRateProviders as $data) { | ||||||
|  |             if (is_array($data)) { | ||||||
|  |                 for ($limit = 0; $limit < count($data); $limit++) { | ||||||
|  |                     $allExchangeRateProvider[] = $data[$limit]; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'allUsedCurrencies' => $allExchangeRateProvider ? $allExchangeRateProvider : [], | ||||||
|  |             'activeUsedCurrencies' => $activeExchangeRateProvider ? $activeExchangeRateProvider : [], | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,96 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\Expense; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Http\Requests\ExpenseCategoryRequest; | ||||||
|  | use Crater\Http\Resources\ExpenseCategoryResource; | ||||||
|  | use Crater\Models\ExpenseCategory; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  |  | ||||||
|  | class ExpenseCategoriesController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Display a listing of the resource. | ||||||
|  |      * | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function index(Request $request) | ||||||
|  |     { | ||||||
|  |         $this->authorize('viewAny', ExpenseCategory::class); | ||||||
|  |  | ||||||
|  |         $limit = $request->has('limit') ? $request->limit : 5; | ||||||
|  |  | ||||||
|  |         $categories = ExpenseCategory::applyFilters($request->all()) | ||||||
|  |             ->whereCompany() | ||||||
|  |             ->latest() | ||||||
|  |             ->paginateData($limit); | ||||||
|  |  | ||||||
|  |         return ExpenseCategoryResource::collection($categories); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Store a newly created resource in storage. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request $request | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function store(ExpenseCategoryRequest $request) | ||||||
|  |     { | ||||||
|  |         $this->authorize('create', ExpenseCategory::class); | ||||||
|  |  | ||||||
|  |         $category = ExpenseCategory::create($request->getExpenseCategoryPayload()); | ||||||
|  |  | ||||||
|  |         return new ExpenseCategoryResource($category); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Display the specified resource. | ||||||
|  |      * | ||||||
|  |      * @param  \Crater\Models\ExpenseCategory $category | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function show(ExpenseCategory $category) | ||||||
|  |     { | ||||||
|  |         $this->authorize('view', $category); | ||||||
|  |  | ||||||
|  |         return new ExpenseCategoryResource($category); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Update the specified resource in storage. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request $request | ||||||
|  |      * @param  \Crater\Models\ExpenseCategory $ExpenseCategory | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function update(ExpenseCategoryRequest $request, ExpenseCategory $category) | ||||||
|  |     { | ||||||
|  |         $this->authorize('update', $category); | ||||||
|  |  | ||||||
|  |         $category->update($request->getExpenseCategoryPayload()); | ||||||
|  |  | ||||||
|  |         return new ExpenseCategoryResource($category); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Remove the specified resource from storage. | ||||||
|  |      * | ||||||
|  |      * @param  \Crater\ExpensesCategory $category | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function destroy(ExpenseCategory $category) | ||||||
|  |     { | ||||||
|  |         $this->authorize('delete', $category); | ||||||
|  |  | ||||||
|  |         if ($category->expenses() && $category->expenses()->count() > 0) { | ||||||
|  |             return respondJson('expense_attached', 'Expense Attached'); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $category->delete(); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'success' => true, | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										93
									
								
								app/Http/Controllers/V1/Admin/Expense/ExpensesController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								app/Http/Controllers/V1/Admin/Expense/ExpensesController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,93 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\Expense; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Http\Requests\DeleteExpensesRequest; | ||||||
|  | use Crater\Http\Requests\ExpenseRequest; | ||||||
|  | use Crater\Http\Resources\ExpenseResource; | ||||||
|  | use Crater\Models\Expense; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  |  | ||||||
|  | class ExpensesController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Display a listing of the resource. | ||||||
|  |      * | ||||||
|  |      * @return \Illuminate\Http\JsonResponse | ||||||
|  |      */ | ||||||
|  |     public function index(Request $request) | ||||||
|  |     { | ||||||
|  |         $this->authorize('viewAny', Expense::class); | ||||||
|  |  | ||||||
|  |         $limit = $request->has('limit') ? $request->limit : 10; | ||||||
|  |  | ||||||
|  |         $expenses = Expense::with('category', 'creator', 'fields') | ||||||
|  |             ->whereCompany() | ||||||
|  |             ->leftJoin('customers', 'customers.id', '=', 'expenses.customer_id') | ||||||
|  |             ->join('expense_categories', 'expense_categories.id', '=', 'expenses.expense_category_id') | ||||||
|  |             ->applyFilters($request->all()) | ||||||
|  |             ->select('expenses.*', 'expense_categories.name', 'customers.name as user_name') | ||||||
|  |             ->paginateData($limit); | ||||||
|  |  | ||||||
|  |         return (ExpenseResource::collection($expenses)) | ||||||
|  |             ->additional(['meta' => [ | ||||||
|  |                 'expense_total_count' => Expense::whereCompany()->count(), | ||||||
|  |             ]]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Store a newly created resource in storage. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request $request | ||||||
|  |      * @return \Illuminate\Http\JsonResponse | ||||||
|  |      */ | ||||||
|  |     public function store(ExpenseRequest $request) | ||||||
|  |     { | ||||||
|  |         $this->authorize('create', Expense::class); | ||||||
|  |  | ||||||
|  |         $expense = Expense::createExpense($request); | ||||||
|  |  | ||||||
|  |         return new ExpenseResource($expense); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Display the specified resource. | ||||||
|  |      * | ||||||
|  |      * @param  \Crater\Models\Expense $expense | ||||||
|  |      * @return \Illuminate\Http\JsonResponse | ||||||
|  |      */ | ||||||
|  |     public function show(Expense $expense) | ||||||
|  |     { | ||||||
|  |         $this->authorize('view', $expense); | ||||||
|  |  | ||||||
|  |         return new ExpenseResource($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) | ||||||
|  |     { | ||||||
|  |         $this->authorize('update', $expense); | ||||||
|  |  | ||||||
|  |         $expense->updateExpense($request); | ||||||
|  |  | ||||||
|  |         return new ExpenseResource($expense); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function delete(DeleteExpensesRequest $request) | ||||||
|  |     { | ||||||
|  |         $this->authorize('delete multiple expenses'); | ||||||
|  |  | ||||||
|  |         Expense::destroy($request->ids); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'success' => true, | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,30 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\Expense; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Models\Expense; | ||||||
|  |  | ||||||
|  | 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) | ||||||
|  |     { | ||||||
|  |         $this->authorize('view', $expense); | ||||||
|  |  | ||||||
|  |         if ($expense) { | ||||||
|  |             $media = $expense->getFirstMedia('receipts'); | ||||||
|  |  | ||||||
|  |             if ($media) { | ||||||
|  |                 return response()->file($media->getPath()); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return respondJson('receipt_does_not_exist', 'Receipt does not exist.'); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,38 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\Expense; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Models\Expense; | ||||||
|  | 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) | ||||||
|  |     { | ||||||
|  |         $this->authorize('update', $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'); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'success' => 'Expense receipts uploaded successfully', | ||||||
|  |         ], 200); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,63 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\General; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Http\Resources\CompanyResource; | ||||||
|  | use Crater\Http\Resources\UserResource; | ||||||
|  | use Crater\Models\Company; | ||||||
|  | use Crater\Models\CompanySetting; | ||||||
|  | use Crater\Models\Currency; | ||||||
|  | use Crater\Traits\GeneratesMenuTrait; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  | use Silber\Bouncer\BouncerFacade; | ||||||
|  |  | ||||||
|  | class BootstrapController extends Controller | ||||||
|  | { | ||||||
|  |     use GeneratesMenuTrait; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Handle the incoming request. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @return \Illuminate\Http\JsonResponse | ||||||
|  |      */ | ||||||
|  |     public function __invoke(Request $request) | ||||||
|  |     { | ||||||
|  |         $current_user = $request->user(); | ||||||
|  |         $current_user_settings = $current_user->getAllSettings(); | ||||||
|  |  | ||||||
|  |         $main_menu = $this->generateMenu('main_menu', $current_user); | ||||||
|  |  | ||||||
|  |         $setting_menu = $this->generateMenu('setting_menu', $current_user); | ||||||
|  |  | ||||||
|  |         $companies = $current_user->companies; | ||||||
|  |  | ||||||
|  |         $current_company = Company::find($request->header('company')); | ||||||
|  |  | ||||||
|  |         if ((! $current_company) || ($current_company && ! $current_user->hasCompany($current_company->id))) { | ||||||
|  |             $current_company = $current_user->companies()->first(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $current_company_settings = CompanySetting::getAllSettings($current_company->id); | ||||||
|  |  | ||||||
|  |         $current_company_currency = $current_company_settings->has('currency') | ||||||
|  |             ? Currency::find($current_company_settings->get('currency')) | ||||||
|  |             : Currency::first(); | ||||||
|  |  | ||||||
|  |         BouncerFacade::refreshFor($current_user); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'current_user' => new UserResource($current_user), | ||||||
|  |             'current_user_settings' => $current_user_settings, | ||||||
|  |             'current_user_abilities' => $current_user->getAbilities(), | ||||||
|  |             'companies' => CompanyResource::collection($companies), | ||||||
|  |             'current_company' => new CompanyResource($current_company), | ||||||
|  |             'current_company_settings' => $current_company_settings, | ||||||
|  |             'current_company_currency' => $current_company_currency, | ||||||
|  |             'config' => config('crater'), | ||||||
|  |             'main_menu' => $main_menu, | ||||||
|  |             'setting_menu' => $setting_menu, | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,128 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\General; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Http\Requests\BulkExchangeRateRequest; | ||||||
|  | use Crater\Models\CompanySetting; | ||||||
|  | use Crater\Models\Estimate; | ||||||
|  | use Crater\Models\Invoice; | ||||||
|  | use Crater\Models\Payment; | ||||||
|  | use Crater\Models\Tax; | ||||||
|  |  | ||||||
|  | class BulkExchangeRateController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Handle the incoming request. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function __invoke(BulkExchangeRateRequest $request) | ||||||
|  |     { | ||||||
|  |         $bulkExchangeRate = CompanySetting::getSetting('bulk_exchange_rate_configured', $request->header('company')); | ||||||
|  |  | ||||||
|  |         if ($bulkExchangeRate == 'NO') { | ||||||
|  |             if ($request->currencies) { | ||||||
|  |                 foreach ($request->currencies as $currency) { | ||||||
|  |                     $currency['exchange_rate'] = $currency['exchange_rate'] ?? 1; | ||||||
|  |  | ||||||
|  |                     $invoices = Invoice::where('currency_id', $currency['id'])->get(); | ||||||
|  |  | ||||||
|  |                     if ($invoices) { | ||||||
|  |                         foreach ($invoices as $invoice) { | ||||||
|  |                             $invoice->update([ | ||||||
|  |                                 'exchange_rate' => $currency['exchange_rate'], | ||||||
|  |                                 'base_discount_val' => $invoice->sub_total * $currency['exchange_rate'], | ||||||
|  |                                 'base_sub_total' => $invoice->sub_total * $currency['exchange_rate'], | ||||||
|  |                                 'base_total' => $invoice->total * $currency['exchange_rate'], | ||||||
|  |                                 'base_tax' => $invoice->tax * $currency['exchange_rate'], | ||||||
|  |                                 'base_due_amount' => $invoice->due_amount * $currency['exchange_rate'] | ||||||
|  |                             ]); | ||||||
|  |  | ||||||
|  |                             $this->items($invoice); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |  | ||||||
|  |                     $estimates = Estimate::where('currency_id', $currency['id'])->get(); | ||||||
|  |  | ||||||
|  |                     if ($estimates) { | ||||||
|  |                         foreach ($estimates as $estimate) { | ||||||
|  |                             $estimate->update([ | ||||||
|  |                                 'exchange_rate' => $currency['exchange_rate'], | ||||||
|  |                                 'base_discount_val' => $estimate->sub_total * $currency['exchange_rate'], | ||||||
|  |                                 'base_sub_total' => $estimate->sub_total * $currency['exchange_rate'], | ||||||
|  |                                 'base_total' => $estimate->total * $currency['exchange_rate'], | ||||||
|  |                                 'base_tax' => $estimate->tax * $currency['exchange_rate'] | ||||||
|  |                             ]); | ||||||
|  |  | ||||||
|  |                             $this->items($estimate); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |  | ||||||
|  |                     $taxes = Tax::where('currency_id', $currency['id'])->get(); | ||||||
|  |  | ||||||
|  |                     if ($taxes) { | ||||||
|  |                         foreach ($taxes as $tax) { | ||||||
|  |                             $tax->base_amount = $tax->base_amount * $currency['exchange_rate']; | ||||||
|  |                             $tax->save(); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |  | ||||||
|  |                     $payments = Payment::where('currency_id', $currency['id'])->get(); | ||||||
|  |  | ||||||
|  |                     if ($payments) { | ||||||
|  |                         foreach ($payments as $payment) { | ||||||
|  |                             $payment->exchange_rate = $currency['exchange_rate']; | ||||||
|  |                             $payment->base_amount = $payment->amount * $currency['exchange_rate']; | ||||||
|  |                             $payment->save(); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             $settings = [ | ||||||
|  |                 'bulk_exchange_rate_configured' => 'YES' | ||||||
|  |             ]; | ||||||
|  |  | ||||||
|  |             CompanySetting::setSettings($settings, $request->header('company')); | ||||||
|  |  | ||||||
|  |             return response()->json([ | ||||||
|  |                 'success' => true | ||||||
|  |             ]); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'error' => false | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function items($model) | ||||||
|  |     { | ||||||
|  |         foreach ($model->items as $item) { | ||||||
|  |             $item->update([ | ||||||
|  |                 'exchange_rate' => $model->exchange_rate, | ||||||
|  |                 'base_discount_val' => $item->discount_val * $model->exchange_rate, | ||||||
|  |                 'base_price' => $item->price * $model->exchange_rate, | ||||||
|  |                 'base_tax' => $item->tax * $model->exchange_rate, | ||||||
|  |                 'base_total' => $item->total * $model->exchange_rate | ||||||
|  |             ]); | ||||||
|  |  | ||||||
|  |             $this->taxes($item); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $this->taxes($model); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function taxes($model) | ||||||
|  |     { | ||||||
|  |         if ($model->taxes()->exists()) { | ||||||
|  |             $model->taxes->map(function ($tax) use ($model) { | ||||||
|  |                 $tax->update([ | ||||||
|  |                     'exchange_rate' => $model->exchange_rate, | ||||||
|  |                     'base_amount' => $tax->amount * $model->exchange_rate, | ||||||
|  |                 ]); | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										22
									
								
								app/Http/Controllers/V1/Admin/General/ConfigController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								app/Http/Controllers/V1/Admin/General/ConfigController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\General; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  |  | ||||||
|  | class ConfigController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Handle the incoming request. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function __invoke(Request $request) | ||||||
|  |     { | ||||||
|  |         return response()->json([ | ||||||
|  |             $request->key => config('crater.'.$request->key), | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,24 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\General; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Http\Resources\CountryResource; | ||||||
|  | use Crater\Models\Country; | ||||||
|  | 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) | ||||||
|  |     { | ||||||
|  |         $countries = Country::all(); | ||||||
|  |  | ||||||
|  |         return CountryResource::collection($countries); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,24 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\General; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Http\Resources\CurrencyResource; | ||||||
|  | use Crater\Models\Currency; | ||||||
|  | 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 CurrencyResource::collection($currencies); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,23 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\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(), | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,37 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\General; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Models\Currency; | ||||||
|  | use Crater\Models\Estimate; | ||||||
|  | use Crater\Models\Invoice; | ||||||
|  | use Crater\Models\Payment; | ||||||
|  | use Crater\Models\Tax; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  |  | ||||||
|  | class GetAllUsedCurrenciesController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Handle the incoming request. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function __invoke(Request $request) | ||||||
|  |     { | ||||||
|  |         $invoices = Invoice::where('exchange_rate', null)->pluck('currency_id')->toArray(); | ||||||
|  |  | ||||||
|  |         $taxes = Tax::where('exchange_rate', null)->pluck('currency_id')->toArray(); | ||||||
|  |  | ||||||
|  |         $estimates = Estimate::where('exchange_rate', null)->pluck('currency_id')->toArray(); | ||||||
|  |  | ||||||
|  |         $payments = Payment::where('exchange_rate', null)->pluck('currency_id')->toArray(); | ||||||
|  |  | ||||||
|  |         $currencies = array_merge($invoices, $taxes, $estimates, $payments); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'currencies' => Currency::whereIn('id', $currencies)->get() | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,66 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\General; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Models\Estimate; | ||||||
|  | use Crater\Models\Invoice; | ||||||
|  | use Crater\Models\Payment; | ||||||
|  | use Crater\Services\SerialNumberFormatter; | ||||||
|  | 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, Invoice $invoice, Estimate $estimate, Payment $payment) | ||||||
|  |     { | ||||||
|  |         $key = $request->key; | ||||||
|  |         $nextNumber = null; | ||||||
|  |         $serial = (new SerialNumberFormatter()) | ||||||
|  |             ->setCompany($request->header('company')) | ||||||
|  |             ->setCustomer($request->userId); | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             switch ($key) { | ||||||
|  |                 case 'invoice': | ||||||
|  |                     $nextNumber = $serial->setModel($invoice) | ||||||
|  |                         ->setModelObject($request->model_id) | ||||||
|  |                         ->getNextNumber(); | ||||||
|  |  | ||||||
|  |                     break; | ||||||
|  |  | ||||||
|  |                 case 'estimate': | ||||||
|  |                     $nextNumber = $serial->setModel($estimate) | ||||||
|  |                         ->setModelObject($request->model_id) | ||||||
|  |                         ->getNextNumber(); | ||||||
|  |  | ||||||
|  |                     break; | ||||||
|  |  | ||||||
|  |                 case 'payment': | ||||||
|  |                     $nextNumber = $serial->setModel($payment) | ||||||
|  |                         ->setModelObject($request->model_id) | ||||||
|  |                         ->getNextNumber(); | ||||||
|  |  | ||||||
|  |                     break; | ||||||
|  |  | ||||||
|  |                 default: | ||||||
|  |                     return; | ||||||
|  |             } | ||||||
|  |         } catch (\Exception $exception) { | ||||||
|  |             return response()->json([ | ||||||
|  |                 'success' => false, | ||||||
|  |                 'message' => $exception->getMessage() | ||||||
|  |             ]); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'success' => true, | ||||||
|  |             'nextNumber' => $nextNumber, | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										92
									
								
								app/Http/Controllers/V1/Admin/General/NotesController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								app/Http/Controllers/V1/Admin/General/NotesController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,92 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\General; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Http\Requests\NotesRequest; | ||||||
|  | use Crater\Http\Resources\NoteResource; | ||||||
|  | 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) | ||||||
|  |     { | ||||||
|  |         $this->authorize('view notes'); | ||||||
|  |  | ||||||
|  |         $limit = $request->limit ?? 10; | ||||||
|  |  | ||||||
|  |         $notes = Note::latest() | ||||||
|  |             ->whereCompany() | ||||||
|  |             ->applyFilters($request->all()) | ||||||
|  |             ->paginate($limit); | ||||||
|  |  | ||||||
|  |         return NoteResource::collection($notes); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Store a newly created resource in storage. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function store(NotesRequest $request) | ||||||
|  |     { | ||||||
|  |         $this->authorize('manage notes'); | ||||||
|  |  | ||||||
|  |         $note = Note::create($request->getNotesPayload()); | ||||||
|  |  | ||||||
|  |         return new NoteResource($note); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Display the specified resource. | ||||||
|  |      * | ||||||
|  |      * @param  \Crater\Models\Note  $note | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function show(Note $note) | ||||||
|  |     { | ||||||
|  |         $this->authorize('view notes'); | ||||||
|  |  | ||||||
|  |         return new NoteResource($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) | ||||||
|  |     { | ||||||
|  |         $this->authorize('manage notes'); | ||||||
|  |  | ||||||
|  |         $note->update($request->getNotesPayload()); | ||||||
|  |  | ||||||
|  |         return new NoteResource($note); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Remove the specified resource from storage. | ||||||
|  |      * | ||||||
|  |      * @param  \Crater\Models\Note  $note | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function destroy(Note $note) | ||||||
|  |     { | ||||||
|  |         $this->authorize('manage notes'); | ||||||
|  |  | ||||||
|  |         $note->delete(); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'success' => true, | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,30 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\General; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Services\SerialNumberFormatter; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  |  | ||||||
|  | class NumberPlaceholdersController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Handle the incoming request. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function __invoke(Request $request) | ||||||
|  |     { | ||||||
|  |         if ($request->format) { | ||||||
|  |             $placeholders = SerialNumberFormatter::getPlaceholders($request->format); | ||||||
|  |         } else { | ||||||
|  |             $placeholders = []; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'success' => true, | ||||||
|  |             'placeholders' => $placeholders, | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										37
									
								
								app/Http/Controllers/V1/Admin/General/SearchController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								app/Http/Controllers/V1/Admin/General/SearchController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,37 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\General; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Models\Customer; | ||||||
|  | use Crater\Models\User; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  |  | ||||||
|  | class SearchController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Handle the incoming request. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function __invoke(Request $request) | ||||||
|  |     { | ||||||
|  |         $user = $request->user(); | ||||||
|  |  | ||||||
|  |         $customers = Customer::applyFilters($request->only(['search'])) | ||||||
|  |             ->latest() | ||||||
|  |             ->paginate(10); | ||||||
|  |  | ||||||
|  |         if ($user->isOwner()) { | ||||||
|  |             $users = User::applyFilters($request->only(['search'])) | ||||||
|  |                 ->latest() | ||||||
|  |                 ->paginate(10); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'customers' => $customers, | ||||||
|  |             'users' => $users ?? [], | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,27 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\General; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Models\User; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  |  | ||||||
|  | class SearchUsersController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Handle the incoming request. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function __invoke(Request $request) | ||||||
|  |     { | ||||||
|  |         $this->authorize('create', User::class); | ||||||
|  |  | ||||||
|  |         $users = User::whereEmail($request->email) | ||||||
|  |             ->latest() | ||||||
|  |             ->paginate(10); | ||||||
|  |  | ||||||
|  |         return response()->json(['users' => $users]); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,23 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\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(), | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,36 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\Invoice; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Models\Invoice; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  |  | ||||||
|  | class ChangeInvoiceStatusController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |     * Handle the incoming request. | ||||||
|  |     * | ||||||
|  |     * @param  \Illuminate\Http\Request  $request | ||||||
|  |     * @return \Illuminate\Http\JsonResponse | ||||||
|  |     */ | ||||||
|  |     public function __invoke(Request $request, Invoice $invoice) | ||||||
|  |     { | ||||||
|  |         $this->authorize('send 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, | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										131
									
								
								app/Http/Controllers/V1/Admin/Invoice/CloneInvoiceController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										131
									
								
								app/Http/Controllers/V1/Admin/Invoice/CloneInvoiceController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,131 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\Invoice; | ||||||
|  |  | ||||||
|  | use Carbon\Carbon; | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Http\Resources\InvoiceResource; | ||||||
|  | use Crater\Models\CompanySetting; | ||||||
|  | use Crater\Models\Invoice; | ||||||
|  | use Crater\Services\SerialNumberFormatter; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  | use Vinkla\Hashids\Facades\Hashids; | ||||||
|  |  | ||||||
|  | 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) | ||||||
|  |     { | ||||||
|  |         $this->authorize('create', Invoice::class); | ||||||
|  |  | ||||||
|  |         $date = Carbon::now(); | ||||||
|  |  | ||||||
|  |         $serial = (new SerialNumberFormatter()) | ||||||
|  |             ->setModel($invoice) | ||||||
|  |             ->setCompany($invoice->company_id) | ||||||
|  |             ->setCustomer($invoice->customer_id) | ||||||
|  |             ->setNextNumbers(); | ||||||
|  |  | ||||||
|  |         $due_date = null; | ||||||
|  |         $dueDateEnabled = CompanySetting::getSetting( | ||||||
|  |             'invoice_set_due_date_automatically', | ||||||
|  |             $request->header('company') | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         if ($dueDateEnabled === 'YES') { | ||||||
|  |             $dueDateDays = CompanySetting::getSetting( | ||||||
|  |                 'invoice_due_date_days', | ||||||
|  |                 $request->header('company') | ||||||
|  |             ); | ||||||
|  |             $due_date = Carbon::now()->addDays($dueDateDays)->format('Y-m-d'); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $exchange_rate = $invoice->exchange_rate; | ||||||
|  |  | ||||||
|  |         $newInvoice = Invoice::create([ | ||||||
|  |             'invoice_date' => $date->format('Y-m-d'), | ||||||
|  |             'due_date' => $due_date, | ||||||
|  |             'invoice_number' => $serial->getNextNumber(), | ||||||
|  |             'sequence_number' => $serial->nextSequenceNumber, | ||||||
|  |             'customer_sequence_number' => $serial->nextCustomerSequenceNumber, | ||||||
|  |             'reference_number' => $invoice->reference_number, | ||||||
|  |             'customer_id' => $invoice->customer_id, | ||||||
|  |             'company_id' => $request->header('company'), | ||||||
|  |             'template_name' => $invoice->template_name, | ||||||
|  |             '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, | ||||||
|  |             'exchange_rate' => $exchange_rate, | ||||||
|  |             'base_total' => $invoice->total * $exchange_rate, | ||||||
|  |             'base_discount_val' => $invoice->discount_val * $exchange_rate, | ||||||
|  |             'base_sub_total' => $invoice->sub_total * $exchange_rate, | ||||||
|  |             'base_tax' => $invoice->tax * $exchange_rate, | ||||||
|  |             'base_due_amount' => $invoice->total * $exchange_rate, | ||||||
|  |             'currency_id' => $invoice->currency_id, | ||||||
|  |         ]); | ||||||
|  |  | ||||||
|  |         $newInvoice->unique_hash = Hashids::connection(Invoice::class)->encode($newInvoice->id); | ||||||
|  |         $newInvoice->save(); | ||||||
|  |         $invoice->load('items.taxes'); | ||||||
|  |  | ||||||
|  |         $invoiceItems = $invoice->items->toArray(); | ||||||
|  |  | ||||||
|  |         foreach ($invoiceItems as $invoiceItem) { | ||||||
|  |             $invoiceItem['company_id'] = $request->header('company'); | ||||||
|  |             $invoiceItem['name'] = $invoiceItem['name']; | ||||||
|  |             $invoiceItem['exchange_rate'] = $exchange_rate; | ||||||
|  |             $invoiceItem['base_price'] = $invoiceItem['price'] * $exchange_rate; | ||||||
|  |             $invoiceItem['base_discount_val'] = $invoiceItem['discount_val'] * $exchange_rate; | ||||||
|  |             $invoiceItem['base_tax'] = $invoiceItem['tax'] * $exchange_rate; | ||||||
|  |             $invoiceItem['base_total'] = $invoiceItem['total'] * $exchange_rate; | ||||||
|  |  | ||||||
|  |             $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); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if ($invoice->fields()->exists()) { | ||||||
|  |             $customFields = []; | ||||||
|  |  | ||||||
|  |             foreach ($invoice->fields as $data) { | ||||||
|  |                 $customFields[] = [ | ||||||
|  |                     'id' => $data->custom_field_id, | ||||||
|  |                     'value' => $data->defaultAnswer | ||||||
|  |                 ]; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             $newInvoice->addCustomFields($customFields); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return new InvoiceResource($newInvoice); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,27 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\Invoice; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Models\Invoice; | ||||||
|  | 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) | ||||||
|  |     { | ||||||
|  |         $this->authorize('viewAny', Invoice::class); | ||||||
|  |  | ||||||
|  |         $invoiceTemplates = Invoice::invoiceTemplates(); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'invoiceTemplates' => $invoiceTemplates, | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										111
									
								
								app/Http/Controllers/V1/Admin/Invoice/InvoicesController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								app/Http/Controllers/V1/Admin/Invoice/InvoicesController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,111 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\Invoice; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Http\Requests; | ||||||
|  | use Crater\Http\Requests\DeleteInvoiceRequest; | ||||||
|  | use Crater\Http\Resources\InvoiceResource; | ||||||
|  | use Crater\Jobs\GenerateInvoicePdfJob; | ||||||
|  | use Crater\Models\Invoice; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  |  | ||||||
|  | class InvoicesController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Display a listing of the resource. | ||||||
|  |      * | ||||||
|  |      * @return \Illuminate\Http\JsonResponse | ||||||
|  |      */ | ||||||
|  |     public function index(Request $request) | ||||||
|  |     { | ||||||
|  |         $this->authorize('viewAny', Invoice::class); | ||||||
|  |  | ||||||
|  |         $limit = $request->has('limit') ? $request->limit : 10; | ||||||
|  |  | ||||||
|  |         $invoices = Invoice::whereCompany() | ||||||
|  |             ->join('customers', 'customers.id', '=', 'invoices.customer_id') | ||||||
|  |             ->applyFilters($request->all()) | ||||||
|  |             ->select('invoices.*', 'customers.name') | ||||||
|  |             ->latest() | ||||||
|  |             ->paginateData($limit); | ||||||
|  |  | ||||||
|  |         return (InvoiceResource::collection($invoices)) | ||||||
|  |             ->additional(['meta' => [ | ||||||
|  |                 'invoice_total_count' => Invoice::whereCompany()->count(), | ||||||
|  |             ]]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Store a newly created resource in storage. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request $request | ||||||
|  |      * @return \Illuminate\Http\JsonResponse | ||||||
|  |      */ | ||||||
|  |     public function store(Requests\InvoicesRequest $request) | ||||||
|  |     { | ||||||
|  |         $this->authorize('create', Invoice::class); | ||||||
|  |  | ||||||
|  |         $invoice = Invoice::createInvoice($request); | ||||||
|  |  | ||||||
|  |         if ($request->has('invoiceSend')) { | ||||||
|  |             $invoice->send($request->subject, $request->body); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         GenerateInvoicePdfJob::dispatch($invoice); | ||||||
|  |  | ||||||
|  |         return new InvoiceResource($invoice); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Display the specified resource. | ||||||
|  |      * | ||||||
|  |      * @param  \Crater\Models\Invoice $invoice | ||||||
|  |      * @return \Illuminate\Http\JsonResponse | ||||||
|  |      */ | ||||||
|  |     public function show(Request $request, Invoice $invoice) | ||||||
|  |     { | ||||||
|  |         $this->authorize('view', $invoice); | ||||||
|  |  | ||||||
|  |         return new InvoiceResource($invoice); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 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) | ||||||
|  |     { | ||||||
|  |         $this->authorize('update', $invoice); | ||||||
|  |  | ||||||
|  |         $invoice = $invoice->updateInvoice($request); | ||||||
|  |  | ||||||
|  |         if (is_string($invoice)) { | ||||||
|  |             return respondJson($invoice, $invoice); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         GenerateInvoicePdfJob::dispatch($invoice, true); | ||||||
|  |  | ||||||
|  |         return new InvoiceResource($invoice); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * delete the specified resources in storage. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request $request | ||||||
|  |      * @return \Illuminate\Http\JsonResponse | ||||||
|  |      */ | ||||||
|  |     public function delete(DeleteInvoiceRequest $request) | ||||||
|  |     { | ||||||
|  |         $this->authorize('delete multiple invoices'); | ||||||
|  |  | ||||||
|  |         Invoice::destroy($request->ids); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'success' => true, | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,27 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Admin\Invoice; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Http\Requests\SendInvoiceRequest; | ||||||
|  | use Crater\Models\Invoice; | ||||||
|  |  | ||||||
|  | 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) | ||||||
|  |     { | ||||||
|  |         $this->authorize('send invoice', $invoice); | ||||||
|  |  | ||||||
|  |         $invoice->send($request->all()); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'success' => true, | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user
	