mirror of
				https://github.com/crater-invoice/crater.git
				synced 2025-10-29 12:41:10 -04:00 
			
		
		
		
	Compare commits
	
		
			582 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 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 | |||
| 2e5cb58c39 | |||
| db622e7458 | |||
| 09bbf98e61 | |||
| ca90ff2767 | |||
| 368dd16c9b | |||
| 251648f53c | |||
| ffa5b6b2ad | |||
| bd9beaa343 | |||
| 3e4decdfb9 | |||
| 165907d144 | |||
| 6278417423 | |||
| dc37f565c4 | |||
| 532196a9b4 | |||
| 6a4009e13a | |||
| a8f98e51bb | |||
| 2b03bc798e | |||
| 482556d378 | |||
| deb525af6e | |||
| cb2bfbb91c | |||
| 654395a175 | |||
| e31b60bc48 | |||
| 183953f4c4 | |||
| 98d15143c2 | |||
| a24d8d3ebc | |||
| 4ca574c581 | |||
| c7ce8c87dd | |||
| f64d546672 | |||
| 96187870b4 | |||
| d4a1f1a784 | |||
| e07532961e | |||
| 450c265ded | |||
| f8502c3ca8 | |||
| 899da6990d | |||
| e7675f938e | |||
| b08138e9e0 | |||
| 5df4abdc4b | |||
| a2fa8afa72 | |||
| 7670cd67dc | |||
| 8446ac2b27 | |||
| 63a80e44d5 | |||
| 076df75322 | |||
| 11db99da73 | |||
| 050dca5a50 | |||
| 3c096f1386 | |||
| 0f3e8fce3b | |||
| 325f90bba5 | |||
| a739a938fc | |||
| b30e3a9b11 | |||
| fc1a7c7438 | |||
| 6046113cb1 | |||
| 611ffafec5 | |||
| c497b906df | |||
| c68fce19f9 | |||
| f8913531b6 | |||
| 30f76e2088 | |||
| 39556892cd | |||
| 2fd66bf748 | |||
| d4f1428d5f | |||
| 189141c84d | |||
| f8ccfece09 | |||
| 9a7c926d53 | |||
| c5c1674153 | |||
| 8562ee5414 | |||
| 06c66a756c | |||
| b66d07d21b | |||
| 05001b6a79 | |||
| f02f4ba9d3 | |||
| fbace98aac | |||
| 8f0af3dcd6 | |||
| e8e44c5dc8 | |||
| ac33164342 | |||
| 5c7c0d84ea | |||
| 7ca725ac37 | |||
| 510a4b3dbb | |||
| 0f130ab1b8 | |||
| 25114009e3 | |||
| 79c16d74ce | |||
| 742e1e445a | |||
| 386f96d60e | |||
| 82d85af672 | |||
| 4d1b267688 | |||
| bc99ad63a6 | |||
| 4bb44f8c93 | |||
| c72265ed50 | |||
| b8958c9eb6 | |||
| e33e314cb7 | |||
| 84cebee9da | |||
| 34d3cf7ae8 | |||
| 93d0da836a | |||
| fd51276948 | |||
| d6274854ba | |||
| ea4bd1a31d | |||
| 286e047963 | |||
| be16f48f3d | |||
| ebea1e0813 | |||
| cc8d08f829 | |||
| aacffc22eb | |||
| d71ca4ffb9 | |||
| 186004f7f8 | |||
| c2eb22d666 | |||
| af189b15b6 | |||
| 1c19be85c3 | |||
| 4bb4362d23 | |||
| f6f66b3ae6 | |||
| b4ccecbcf1 | |||
| 92f1f196bb | |||
| ee14070a7b | |||
| 8ce7e14a02 | |||
| 3401ca049e | |||
| 5dcc7b9efd | |||
| 06a538bb81 | |||
| 7ab0419f27 | |||
| a7275aaa42 | |||
| bc4e6a05ea | |||
| ca170f5a87 | |||
| 22e7e96dfa | |||
| fcfd1ddb7a | |||
| daf8c9265b | |||
| 406d098172 | |||
| 824d2e3e8d | |||
| 3cd975dbbd | |||
| 8e50c36a71 | |||
| b499741ab4 | |||
| b409cdb913 | |||
| 13e56105e3 | |||
| f68e86e4cf | |||
| da996c1f33 | |||
| 0990ce4678 | |||
| bb6fb2f49d | |||
| 400296575e | |||
| d58c790b1f | |||
| c674c2ab9e | |||
| d79692cf3b | |||
| 353c2479f1 | |||
| 0176a854b8 | |||
| 00548ea908 | |||
| 09e335a8a7 | |||
| 53e2ed253f | |||
| 06b035d9ac | |||
| 5c88cbcc42 | |||
| d9b175a676 | |||
| f5b9bc95c6 | |||
| 586dcdea0d | |||
| 50957fc179 | |||
| c725e4744b | |||
| 7479ce237e | |||
| 84420441c0 | |||
| ac96721e87 | |||
| db4c7f5e32 | |||
| 87dc78eea0 | |||
| e9c2898056 | |||
| b9c4570137 | |||
| 8e2525cc6c | |||
| 8862a93f23 | |||
| 82efd88920 | |||
| 0ef528d296 | |||
| 4c33a5d88c | |||
| d64d06181b | |||
| ef9cf2db22 | |||
| 96c295a003 | |||
| 22528f5b66 | |||
| 1cd9c72537 | |||
| 7253b43eb4 | |||
| 181964cf03 | |||
| 5914245ae4 | |||
| 1bf3d28d4e | |||
| dbcbd93ace | |||
| 1729c6a308 | |||
| 019493cbfa | |||
| 60540ba966 | |||
| 601ad419ec | |||
| 80e7bab891 | |||
| f5c8befbf0 | |||
| 09c984baa7 | |||
| 0d93260672 | |||
| 3e9e217f92 | |||
| 3cd8859c62 | |||
| 4493b4a419 | |||
| 79e3e70bd6 | |||
| 56a955befd | |||
| 496c28f80d | |||
| 7a59f3fe0c | |||
| 3d6875a532 | |||
| 15bf380f4f | |||
| 0b910db039 | |||
| 0e5e8f602f | |||
| d9db0f9401 | |||
| c0da7c7339 | |||
| 7e7599b4a7 | |||
| 99cd88e6c6 | |||
| 053a06229c | |||
| 1a6e8280a8 | |||
| 125e8be83c | |||
| 4d89ca2101 | |||
| e8aee3bb32 | |||
| d3c7ca75f0 | |||
| 694d5f56d5 | |||
| a48439785c | |||
| 7c9bd84f00 | |||
| bd5a93d81c | |||
| 858e10953b | |||
| 3617032735 | |||
| 75ddc51b1e | |||
| 1dfa36e396 | |||
| d9e9a5a540 | |||
| ea6e11c324 | |||
| f55dfe0b46 | |||
| 3eac3b8af5 | |||
| 2b2bd4351a | |||
| b9c32bbdc1 | |||
| bceffbf6a0 | |||
| 7c6a40374d | |||
| d04e142a3e | |||
| f11436736b | |||
| 9271ceba45 | |||
| c88eb24265 | |||
| 5eb0a04378 | |||
| d926073095 | |||
| a691969025 | |||
| 7df06fb005 | |||
| 45db850025 | |||
| 18a50315ba | |||
| bce1b4bb3e | |||
| ddd204105f | |||
| e030d4b9d0 | |||
| 302968225a | |||
| e59bf288ce | |||
| b1fcd90b62 | |||
| ddb0ff1b8a | |||
| ce99fa3d82 | |||
| e28c89085d | |||
| 34f7e33abc | |||
| 80be7a492d | |||
| 387cb4490d | |||
| 09829a559e | |||
| b06fc5f0b9 | |||
| 5f7401f622 | |||
| 4f6dae919b | |||
| 36be395579 | |||
| 79e77f9e16 | |||
| cbf0af2120 | |||
| 92f754e888 | |||
| a6896eaa01 | |||
| 01f3646869 | |||
| b2918e9dbb | |||
| 0a064ec5ba | |||
| 5f0b4b3496 | |||
| 17b59f0d19 | |||
| 283b910cc3 | |||
| 81739827c0 | |||
| 90edc3a85e | |||
| 655c2a7849 | |||
| ca833d174e | |||
| 33e8381fc4 | |||
| 9b5125d440 | |||
| 2899021804 | |||
| d8f6d03d1e | |||
| c474e98925 | |||
| 799d212d9b | |||
| 9424dc6c27 | |||
| fa15502ce7 | |||
| 1f4d3bf784 | |||
| 3692373cd2 | |||
| 7bba576dca | |||
| 05454af593 | |||
| 74fe481ed5 | |||
| 1cd654b0cc | |||
| f4a4c05b61 | |||
| 24637bff4a | |||
| 887ad9a73d | |||
| 339099bd34 | |||
| 9b9761aa5a | |||
| 0c71356f59 | |||
| e539bb501d | |||
| 2fcd169270 | |||
| 00c917853c | |||
| 122c4f478f | |||
| edc0e115e4 | |||
| b388e7a237 | |||
| 6e3ed9b4f6 | |||
| 338dbb26a1 | |||
| f10e5e9d11 | |||
| 3a046b638c | |||
| 36242c516a | |||
| 14d71fedb3 | |||
| c8843eb544 | |||
| 7fe9a4c2a2 | |||
| 37f2b6dfc7 | |||
| c90c14312a | |||
| b5b861bb36 | |||
| ab041743a2 | |||
| 9bcec9bd75 | |||
| 7b697a477e | |||
| 146cf835b9 | |||
| ec87e72547 | |||
| bf2e8c9c99 | |||
| b6096aadfa | |||
| 1cbc41c3ce | |||
| f4ca6d4b73 | |||
| 66649590e5 | |||
| 1e8cc475ca | |||
| 98d76a2f92 | |||
| 7b50148c43 | |||
| aef6da8b7b | |||
| 0fb14afc08 | |||
| dad71b04dd | |||
| 80014b02b5 | |||
| 7c2a6700eb | |||
| 7e81013b15 | |||
| f0107129fb | |||
| 04cce64859 | |||
| 3b7637f3cf | |||
| 7333746948 | |||
| 0fa6049298 | |||
| 64be6ce957 | |||
| 0e075c03d8 | |||
| 5de195b56b | |||
| cd60f1b096 | |||
| 8058f9b022 | |||
| a484506029 | |||
| a69f99dc61 | |||
| c3583c98be | |||
| 813e574425 | |||
| ac431ca815 | |||
| dbc5950294 | |||
| 8bc5ea2d5e | 
							
								
								
									
										10
									
								
								.dockerignore
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								.dockerignore
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | |||||||
|  | .dockerignore | ||||||
|  | .gitignore | ||||||
|  | *.md | ||||||
|  | .git/ | ||||||
|  | .idea/ | ||||||
|  | .DS_Store/ | ||||||
|  | docker-compose.* | ||||||
|  | LICENSE | ||||||
|  | nginx.conf | ||||||
|  | yarn.lock | ||||||
							
								
								
									
										16
									
								
								.env.example
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								.env.example
									
									
									
									
									
								
							| @ -1,20 +1,21 @@ | |||||||
| APP_ENV=production | APP_ENV=production | ||||||
| APP_KEY=base64:kgk/4DW1vEVy7aEvet5FPp5un6PIGe/so8H0mvoUtW0= | APP_KEY=base64:kgk/4DW1vEVy7aEvet5FPp5un6PIGe/so8H0mvoUtW0= | ||||||
| APP_DEBUG=false | APP_DEBUG=true | ||||||
| APP_LOG_LEVEL=debug | APP_LOG_LEVEL=debug | ||||||
| APP_URL=http://crater.test | APP_URL=http://crater.test | ||||||
|  |  | ||||||
| DB_CONNECTION=mysql | DB_CONNECTION=mysql | ||||||
| DB_HOST=127.0.0.1 | DB_HOST=db | ||||||
| DB_PORT=3306 | DB_PORT=3306 | ||||||
| DB_DATABASE=crater | DB_DATABASE=crater | ||||||
| DB_USERNAME=root | DB_USERNAME=crater | ||||||
| DB_PASSWORD=bytefury | DB_PASSWORD="crater" | ||||||
|  |  | ||||||
| BROADCAST_DRIVER=log | BROADCAST_DRIVER=log | ||||||
| CACHE_DRIVER=file | CACHE_DRIVER=file | ||||||
| SESSION_DRIVER=file |  | ||||||
| QUEUE_DRIVER=sync | QUEUE_DRIVER=sync | ||||||
|  | SESSION_DRIVER=cookie | ||||||
|  | SESSION_LIFETIME=1440 | ||||||
|  |  | ||||||
| REDIS_HOST=127.0.0.1 | REDIS_HOST=127.0.0.1 | ||||||
| REDIS_PASSWORD=null | REDIS_PASSWORD=null | ||||||
| @ -31,6 +32,5 @@ PUSHER_APP_ID= | |||||||
| PUSHER_KEY= | PUSHER_KEY= | ||||||
| PUSHER_SECRET= | PUSHER_SECRET= | ||||||
|  |  | ||||||
| PROXY_OAUTH_CLIENT_ID=2 | SANCTUM_STATEFUL_DOMAINS=crater.test | ||||||
| PROXY_OAUTH_CLIENT_SECRET=SECRET-GENERATED-KEY-HERE | SESSION_DOMAIN=crater.test | ||||||
| PROXY_OAUTH_GRANT_TYPE=password |  | ||||||
|  | |||||||
| @ -2,3 +2,12 @@ APP_ENV=testing | |||||||
| APP_DEBUG=true | APP_DEBUG=true | ||||||
| APP_KEY=base64:IdDlpLmYyWA9z4Ruj5st1FSYrhCR7lPOscLGCz2Jf4I= | APP_KEY=base64:IdDlpLmYyWA9z4Ruj5st1FSYrhCR7lPOscLGCz2Jf4I= | ||||||
| DB_CONNECTION=sqlite | DB_CONNECTION=sqlite | ||||||
|  |  | ||||||
|  | MAIL_DRIVER=smtp | ||||||
|  | MAIL_HOST=smtp.mailtrap.io | ||||||
|  | MAIL_PORT=587 | ||||||
|  | MAIL_USERNAME=ff538f0e1037f4 | ||||||
|  | MAIL_PASSWORD=c04c81145fcb73 | ||||||
|  | MAIL_ENCRYPTION=tls | ||||||
|  | MAIL_FROM_ADDRESS="admin@crater.com" | ||||||
|  | MAIL_FROM_NAME="John Doe" | ||||||
|  | |||||||
							
								
								
									
										10
									
								
								.eslintrc
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								.eslintrc
									
									
									
									
									
								
							| @ -1,10 +0,0 @@ | |||||||
| { |  | ||||||
|   "root": true, |  | ||||||
|   "extends": [ |  | ||||||
|     "plugin:vue/recommended", |  | ||||||
|     "standard" |  | ||||||
|   ], |  | ||||||
|   "rules": { |  | ||||||
|     "vue/max-attributes-per-line" : 3 |  | ||||||
|   } |  | ||||||
| } |  | ||||||
							
								
								
									
										20
									
								
								.eslintrc.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								.eslintrc.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | |||||||
|  | module.exports = { | ||||||
|  |   root: true, | ||||||
|  |   env: { | ||||||
|  |     node: true, | ||||||
|  |   }, | ||||||
|  |   extends: [ | ||||||
|  |     'plugin:vue/recommended', | ||||||
|  |     'eslint:recommended', | ||||||
|  |     'prettier/vue', | ||||||
|  |     'plugin:prettier/recommended', | ||||||
|  |   ], | ||||||
|  |   parserOptions: { | ||||||
|  |     parser: 'babel-eslint', | ||||||
|  |   }, | ||||||
|  |   plugins: ['prettier'], | ||||||
|  |   rules: { | ||||||
|  |     'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off', | ||||||
|  |     'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', | ||||||
|  |   }, | ||||||
|  | } | ||||||
							
								
								
									
										26
									
								
								.github/ISSUE_TEMPLATE/bug_report.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								.github/ISSUE_TEMPLATE/bug_report.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,26 @@ | |||||||
|  | --- | ||||||
|  | name: Bug report | ||||||
|  | about: Create a report to help us improve | ||||||
|  | title: '' | ||||||
|  | labels: '' | ||||||
|  | assignees: '' | ||||||
|  |  | ||||||
|  | --- | ||||||
|  |  | ||||||
|  | **Describe the bug** | ||||||
|  | A clear and concise description of what the bug is. | ||||||
|  |  | ||||||
|  | **Expected behavior** | ||||||
|  | A clear and concise description of what you expected to happen. | ||||||
|  |  | ||||||
|  | **Screenshots** | ||||||
|  | If applicable, add screenshots to help explain your problem. | ||||||
|  |  | ||||||
|  | **Please complete the following information:** | ||||||
|  | - Crater version:  | ||||||
|  | - PHP version:  | ||||||
|  | - Database type and version:  | ||||||
|  |  | ||||||
|  | **Optional info** | ||||||
|  | - OS:  [e.g. Ubuntu] | ||||||
|  | - Browser: [e.g. chrome, safari] | ||||||
							
								
								
									
										17
									
								
								.github/ISSUE_TEMPLATE/feature_request.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								.github/ISSUE_TEMPLATE/feature_request.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | |||||||
|  | --- | ||||||
|  | name: Feature request | ||||||
|  | about: Suggest an idea for this project | ||||||
|  | title: '' | ||||||
|  | labels: '' | ||||||
|  | assignees: '' | ||||||
|  |  | ||||||
|  | --- | ||||||
|  |  | ||||||
|  | **Is your feature request related to a problem? Please describe.** | ||||||
|  | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] | ||||||
|  |  | ||||||
|  | **Describe the solution you'd like** | ||||||
|  | A clear and concise description of what you want to happen. | ||||||
|  |  | ||||||
|  | **Describe alternatives you've considered** | ||||||
|  | A clear and concise description of any alternative solutions or features you've considered. | ||||||
							
								
								
									
										34
									
								
								.github/workflows/ci.yaml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								.github/workflows/ci.yaml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | |||||||
|  | name: CI | ||||||
|  |  | ||||||
|  | on: [push, pull_request] | ||||||
|  |  | ||||||
|  | jobs: | ||||||
|  |   build-test: | ||||||
|  |     runs-on: ubuntu-latest | ||||||
|  |     strategy: | ||||||
|  |       fail-fast: false | ||||||
|  |       matrix: | ||||||
|  |         php: ['7.4', '8.0'] | ||||||
|  |  | ||||||
|  |     name: PHP ${{ matrix.php }} | ||||||
|  |  | ||||||
|  |     steps: | ||||||
|  |     - name: Checkout | ||||||
|  |       uses: actions/checkout@v2 | ||||||
|  |  | ||||||
|  |     - name: Install dependencies | ||||||
|  |       uses: shivammathur/setup-php@v2 | ||||||
|  |       with: | ||||||
|  |         php-version: ${{ matrix.php }} | ||||||
|  |         extensions: exif | ||||||
|  |  | ||||||
|  |     - name: Install PHP 7 dependencies | ||||||
|  |       run: composer update --no-interaction --no-progress | ||||||
|  |       if: "matrix.php < 8" | ||||||
|  |  | ||||||
|  |     - name: Install PHP 8 dependencies | ||||||
|  |       run: composer update --ignore-platform-req=php --no-interaction --no-progress | ||||||
|  |       if: "matrix.php >= 8" | ||||||
|  |  | ||||||
|  |     - name: Unit Tests | ||||||
|  |       run: php ./vendor/bin/pest | ||||||
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -11,3 +11,4 @@ Homestead.yaml | |||||||
| .rnd | .rnd | ||||||
| /.expo | /.expo | ||||||
| /.vscode | /.vscode | ||||||
|  | /docker-compose/db/data/ | ||||||
							
								
								
									
										5
									
								
								.prettierrc.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								.prettierrc.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | |||||||
|  | { | ||||||
|  |   "semi": false, | ||||||
|  |   "singleQuote": true, | ||||||
|  |   "tabWidth": 2 | ||||||
|  | } | ||||||
							
								
								
									
										39
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,39 @@ | |||||||
|  | FROM php:7.4-fpm | ||||||
|  |  | ||||||
|  | # Arguments defined in docker-compose.yml | ||||||
|  | ARG user | ||||||
|  | ARG uid | ||||||
|  |  | ||||||
|  | # Install system dependencies | ||||||
|  | RUN apt-get update && apt-get install -y \ | ||||||
|  |     git \ | ||||||
|  |     curl \ | ||||||
|  |     libpng-dev \ | ||||||
|  |     libonig-dev \ | ||||||
|  |     libxml2-dev \ | ||||||
|  |     zip \ | ||||||
|  |     unzip \  | ||||||
|  |     libzip-dev \  | ||||||
|  |     libmagickwand-dev | ||||||
|  |  | ||||||
|  | # Clear cache | ||||||
|  | RUN apt-get clean && rm -rf /var/lib/apt/lists/* | ||||||
|  |  | ||||||
|  | RUN pecl install imagick \  | ||||||
|  |     && docker-php-ext-enable imagick | ||||||
|  |  | ||||||
|  | # Install PHP extensions | ||||||
|  | RUN docker-php-ext-install pdo_mysql mbstring zip exif pcntl bcmath gd  | ||||||
|  |  | ||||||
|  | # Get latest Composer | ||||||
|  | COPY --from=composer:latest /usr/bin/composer /usr/bin/composer | ||||||
|  |  | ||||||
|  | # Create system user to run Composer and Artisan Commands | ||||||
|  | RUN useradd -G www-data,root -u $uid -d /home/$user $user | ||||||
|  | RUN mkdir -p /home/$user/.composer && \ | ||||||
|  |     chown -R $user:$user /home/$user | ||||||
|  |  | ||||||
|  | # Set working directory | ||||||
|  | WORKDIR /var/www | ||||||
|  |  | ||||||
|  | USER $user | ||||||
| @ -1,48 +0,0 @@ | |||||||
| <?php |  | ||||||
| namespace Crater; |  | ||||||
|  |  | ||||||
| use Illuminate\Database\Eloquent\Model; |  | ||||||
| use Crater\User; |  | ||||||
| use Crater\Country; |  | ||||||
| use Crater\State; |  | ||||||
| use Crater\City; |  | ||||||
|  |  | ||||||
| class Address extends Model |  | ||||||
| { |  | ||||||
|     const BILLING_TYPE = 'BILLING'; |  | ||||||
|     const SHIPPING_TYPE = 'SHIPPING'; |  | ||||||
|  |  | ||||||
|     protected $fillable = [ |  | ||||||
|         'name', |  | ||||||
|         'address_street_1', |  | ||||||
|         'address_street_2', |  | ||||||
|         'city_id', |  | ||||||
|         'state_id', |  | ||||||
|         'country_id', |  | ||||||
|         'zip', |  | ||||||
|         'phone', |  | ||||||
|         'fax', |  | ||||||
|         'type', |  | ||||||
|         'user_id' |  | ||||||
|     ]; |  | ||||||
|  |  | ||||||
|     public function user() |  | ||||||
|     { |  | ||||||
|         return $this->belongsTo(User::class); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function country() |  | ||||||
|     { |  | ||||||
|         return $this->belongsTo(Country::class); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function state() |  | ||||||
|     { |  | ||||||
|         return $this->belongsTo(State::class); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function city() |  | ||||||
|     { |  | ||||||
|         return $this->belongsTo(City::class); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
							
								
								
									
										18
									
								
								app/City.php
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								app/City.php
									
									
									
									
									
								
							| @ -1,18 +0,0 @@ | |||||||
| <?php |  | ||||||
| namespace Crater; |  | ||||||
|  |  | ||||||
| use Illuminate\Database\Eloquent\Model; |  | ||||||
| use Crater\State; |  | ||||||
|  |  | ||||||
| class City extends Model |  | ||||||
| { |  | ||||||
|     public function state() |  | ||||||
|     { |  | ||||||
|         return $this->belongsTo(State::class); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function address() |  | ||||||
|     { |  | ||||||
|         return $this->hasMany(Address::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); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -3,7 +3,7 @@ namespace Crater\Console\Commands; | |||||||
|  |  | ||||||
| use Illuminate\Console\Command; | use Illuminate\Console\Command; | ||||||
| use Carbon\Carbon; | use Carbon\Carbon; | ||||||
| use Crater\Estimate; | use Crater\Models\Estimate; | ||||||
|  |  | ||||||
| class CheckEstimateStatus extends Command | class CheckEstimateStatus extends Command | ||||||
| { | { | ||||||
|  | |||||||
| @ -3,7 +3,7 @@ namespace Crater\Console\Commands; | |||||||
|  |  | ||||||
| use Illuminate\Console\Command; | use Illuminate\Console\Command; | ||||||
| use Carbon\Carbon; | use Carbon\Carbon; | ||||||
| use Crater\Invoice; | use Crater\Models\Invoice; | ||||||
|  |  | ||||||
| class CheckInvoiceStatus extends Command | class CheckInvoiceStatus extends Command | ||||||
| { | { | ||||||
|  | |||||||
							
								
								
									
										69
									
								
								app/Console/Commands/ResetApp.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								app/Console/Commands/ResetApp.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,69 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Console\Commands; | ||||||
|  |  | ||||||
|  | use Illuminate\Console\Command; | ||||||
|  | use Illuminate\Console\ConfirmableTrait; | ||||||
|  | use Illuminate\Support\Facades\Artisan; | ||||||
|  | use Illuminate\Filesystem\Filesystem; | ||||||
|  |  | ||||||
|  | class ResetApp extends Command | ||||||
|  | { | ||||||
|  |     use ConfirmableTrait; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The name and signature of the console command. | ||||||
|  |      * | ||||||
|  |      * @var string | ||||||
|  |      */ | ||||||
|  |     protected $signature = 'reset:app {--force}'; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The console command description. | ||||||
|  |      * | ||||||
|  |      * @var string | ||||||
|  |      */ | ||||||
|  |     protected $description = 'Clean database, database_created and public/storage folder'; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Create a new command instance. | ||||||
|  |      * | ||||||
|  |      * @return void | ||||||
|  |      */ | ||||||
|  |     public function __construct() | ||||||
|  |     { | ||||||
|  |         parent::__construct(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Execute the console command. | ||||||
|  |      * | ||||||
|  |      * @return mixed | ||||||
|  |      */ | ||||||
|  |     public function handle() | ||||||
|  |     { | ||||||
|  |         if (!$this->confirmToProceed()) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $this->info('Running migrate:fresh'); | ||||||
|  |  | ||||||
|  |         Artisan::call('migrate:fresh --seed --force'); | ||||||
|  |  | ||||||
|  |         $this->info('Seeding database'); | ||||||
|  |  | ||||||
|  |         Artisan::call('db:seed', ['--class' => 'DemoSeeder', '--force' => true]); | ||||||
|  |  | ||||||
|  |         $path = base_path('.env'); | ||||||
|  |  | ||||||
|  |         if (file_exists($path)) { | ||||||
|  |             file_put_contents($path, str_replace( | ||||||
|  |                 'APP_DEBUG=true', | ||||||
|  |                 'APP_DEBUG=false', | ||||||
|  |                 file_get_contents($path) | ||||||
|  |             )); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $this->info('App has been reset successfully'); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										240
									
								
								app/Console/Commands/UpdateCommand.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										240
									
								
								app/Console/Commands/UpdateCommand.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,240 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Console\Commands; | ||||||
|  |  | ||||||
|  | use Illuminate\Console\Command; | ||||||
|  | use Crater\Space\Updater; | ||||||
|  | use Crater\Models\Setting; | ||||||
|  |  | ||||||
|  | // Implementation taken from Akaunting - https://github.com/akaunting/akaunting | ||||||
|  | class UpdateCommand extends Command | ||||||
|  | { | ||||||
|  |     public $installed; | ||||||
|  |  | ||||||
|  |     public $version; | ||||||
|  |  | ||||||
|  |     public $response; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The name and signature of the console command. | ||||||
|  |      * | ||||||
|  |      * @var string | ||||||
|  |      */ | ||||||
|  |     protected $signature = 'crater:update'; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The console command description. | ||||||
|  |      * | ||||||
|  |      * @var string | ||||||
|  |      */ | ||||||
|  |     protected $description = 'Automatically update your crater app'; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Create a new command instance. | ||||||
|  |      * | ||||||
|  |      * @return void | ||||||
|  |      */ | ||||||
|  |     public function __construct() | ||||||
|  |     { | ||||||
|  |         parent::__construct(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Execute the console command. | ||||||
|  |      */ | ||||||
|  |     public function handle() | ||||||
|  |     { | ||||||
|  |         set_time_limit(3600); // 1 hour | ||||||
|  |  | ||||||
|  |         $this->installed = $this->getInstalledVersion(); | ||||||
|  |         $this->response = $this->getLatestVersionResponse(); | ||||||
|  |         $this->version = ($this->response) ? $this->response->version : false; | ||||||
|  |  | ||||||
|  |         if ($this->response == 'extension_required') { | ||||||
|  |             $this->info('Sorry! Your system does not meet the minimum requirements for this update.'); | ||||||
|  |             $this->info('Please retry after installing the required version/extensions.'); | ||||||
|  |  | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (!$this->version) { | ||||||
|  |             $this->info('No Update Available! You are already on the latest version.'); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (!$this->confirm("Do you wish to update to {$this->version}?")) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (!$path = $this->download()) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (!$path = $this->unzip($path)) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (!$this->copyFiles($path)) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if(isset($this->response->deleted_files) && !empty($this->response->deleted_files)) { | ||||||
|  |             if (!$this->deleteFiles($this->response->deleted_files)) { | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (!$this->migrateUpdate()) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (!$this->finish()) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $this->info('Successfully updated to ' . $this->version); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getInstalledVersion() | ||||||
|  |     { | ||||||
|  |         return Setting::getSetting('version'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getLatestVersionResponse() | ||||||
|  |     { | ||||||
|  |         $this->info('Your currently installed version is ' . $this->installed); | ||||||
|  |         $this->line(''); | ||||||
|  |         $this->info('Checking for update...'); | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             $response = Updater::checkForUpdate($this->installed); | ||||||
|  |  | ||||||
|  |             if ($response->success) { | ||||||
|  |  | ||||||
|  |                 $extensions = $response->version->extensions; | ||||||
|  |  | ||||||
|  |                 $is_required = false; | ||||||
|  |  | ||||||
|  |                 foreach ($extensions as $key => $extension) { | ||||||
|  |  | ||||||
|  |                     if(!$extension) { | ||||||
|  |                         $is_required = true; | ||||||
|  |                         $this->info('❌ '.$key); | ||||||
|  |                     } | ||||||
|  |  | ||||||
|  |                     $this->info('✅ '.$key); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 if($is_required) { | ||||||
|  |                     return 'extension_required'; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 return $response->version; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return false; | ||||||
|  |         } catch (\Exception $e) { | ||||||
|  |             $this->error($e->getMessage()); | ||||||
|  |  | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function download() | ||||||
|  |     { | ||||||
|  |         $this->info('Downloading update...'); | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             $path = Updater::download($this->version, 1); | ||||||
|  |             if (!is_string($path)) { | ||||||
|  |                 $this->error('Download exception'); | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |         } catch (\Exception $e) { | ||||||
|  |             $this->error($e->getMessage()); | ||||||
|  |  | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $path; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function unzip($path) | ||||||
|  |     { | ||||||
|  |         $this->info('Unzipping update package...'); | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             $path = Updater::unzip($path); | ||||||
|  |             if (!is_string($path)) { | ||||||
|  |                 $this->error('Unzipping exception'); | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |         } catch (\Exception $e) { | ||||||
|  |             $this->error($e->getMessage()); | ||||||
|  |  | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $path; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function copyFiles($path) | ||||||
|  |     { | ||||||
|  |         $this->info('Copying update files...'); | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             Updater::copyFiles($path); | ||||||
|  |         } catch (\Exception $e) { | ||||||
|  |             $this->error($e->getMessage()); | ||||||
|  |  | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function deleteFiles($files) | ||||||
|  |     { | ||||||
|  |         $this->info('Deleting unused old files...'); | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             Updater::deleteFiles($files); | ||||||
|  |         } catch (\Exception $e) { | ||||||
|  |             $this->error($e->getMessage()); | ||||||
|  |  | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function migrateUpdate() | ||||||
|  |     { | ||||||
|  |         $this->info('Running Migrations...'); | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             Updater::migrateUpdate(); | ||||||
|  |         } catch (\Exception $e) { | ||||||
|  |             $this->error($e->getMessage()); | ||||||
|  |  | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function finish() | ||||||
|  |     { | ||||||
|  |         $this->info('Finishing update...'); | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             Updater::finishUpdate($this->installed, $this->version); | ||||||
|  |         } catch (\Exception $e) { | ||||||
|  |             $this->error($e->getMessage()); | ||||||
|  |  | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -12,7 +12,8 @@ class Kernel extends ConsoleKernel | |||||||
|      * @var array |      * @var array | ||||||
|      */ |      */ | ||||||
|     protected $commands = [ |     protected $commands = [ | ||||||
|  |         Commands\ResetApp::class, | ||||||
|  |         Commands\UpdateCommand::class | ||||||
|     ]; |     ]; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|  | |||||||
							
								
								
									
										226
									
								
								app/Estimate.php
									
									
									
									
									
								
							
							
						
						
									
										226
									
								
								app/Estimate.php
									
									
									
									
									
								
							| @ -1,226 +0,0 @@ | |||||||
| <?php |  | ||||||
| namespace Crater; |  | ||||||
|  |  | ||||||
| use Illuminate\Database\Eloquent\Model; |  | ||||||
| use Crater\CompanySetting; |  | ||||||
| use Carbon\Carbon; |  | ||||||
|  |  | ||||||
| class Estimate extends Model |  | ||||||
| { |  | ||||||
|     const STATUS_DRAFT = 'DRAFT'; |  | ||||||
|     const STATUS_SENT = 'SENT'; |  | ||||||
|     const STATUS_VIEWED = 'VIEWED'; |  | ||||||
|     const STATUS_EXPIRED = 'EXPIRED'; |  | ||||||
|     const STATUS_ACCEPTED = 'ACCEPTED'; |  | ||||||
|     const STATUS_REJECTED = 'REJECTED'; |  | ||||||
|  |  | ||||||
|     protected $dates = [ |  | ||||||
|         'created_at', |  | ||||||
|         'updated_at', |  | ||||||
|         'deleted_at', |  | ||||||
|         'estimate_date', |  | ||||||
|         'expiry_date' |  | ||||||
|     ]; |  | ||||||
|  |  | ||||||
|     protected $appends = [ |  | ||||||
|         'formattedExpiryDate', |  | ||||||
|         'formattedEstimateDate' |  | ||||||
|     ]; |  | ||||||
|  |  | ||||||
|     protected $fillable = [ |  | ||||||
|         'estimate_date', |  | ||||||
|         'expiry_date', |  | ||||||
|         'estimate_number', |  | ||||||
|         'user_id', |  | ||||||
|         'company_id', |  | ||||||
|         'reference_number', |  | ||||||
|         'estimate_template_id', |  | ||||||
|         'discount', |  | ||||||
|         'discount_type', |  | ||||||
|         'discount_val', |  | ||||||
|         'status', |  | ||||||
|         'sub_total', |  | ||||||
|         'tax_per_item', |  | ||||||
|         'discount_per_item', |  | ||||||
|         'total', |  | ||||||
|         'tax', |  | ||||||
|         'notes', |  | ||||||
|         'unique_hash' |  | ||||||
|     ]; |  | ||||||
|  |  | ||||||
|     protected $casts = [ |  | ||||||
|         'total' => 'float', |  | ||||||
|         'tax' => 'float', |  | ||||||
|         'sub_total' => 'float' |  | ||||||
|     ]; |  | ||||||
|  |  | ||||||
|     public static function getNextEstimateNumber() |  | ||||||
|     { |  | ||||||
|         // Get the last created order |  | ||||||
|         $lastOrder = Estimate::orderBy('created_at', 'desc')->first(); |  | ||||||
|         if (!$lastOrder) { |  | ||||||
|             // We get here if there is no order at all |  | ||||||
|             // If there is no number set it to 0, which will be 1 at the end. |  | ||||||
|             $number = 0; |  | ||||||
|         } else { |  | ||||||
|             $number = explode("-",$lastOrder->estimate_number); |  | ||||||
|             $number = $number[1]; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         // If we have ORD000001 in the database then we only want the number |  | ||||||
|         // So the substr returns this 000001 |  | ||||||
|  |  | ||||||
|         // Add the string in front and higher up the number. |  | ||||||
|         // the %05d part makes sure that there are always 6 numbers in the string. |  | ||||||
|         // so it adds the missing zero's when needed. |  | ||||||
|  |  | ||||||
|         return sprintf('%06d', intval($number) + 1); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function items() |  | ||||||
|     { |  | ||||||
|         return $this->hasMany('Crater\EstimateItem'); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function user() |  | ||||||
|     { |  | ||||||
|         return $this->belongsTo('Crater\User'); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function taxes() |  | ||||||
|     { |  | ||||||
|         return $this->hasMany(Tax::class); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function estimateTemplate() |  | ||||||
|     { |  | ||||||
|         return $this->belongsTo('Crater\EstimateTemplate'); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function getEstimateNumAttribute() |  | ||||||
|     { |  | ||||||
|         $position = $this->strposX($this->estimate_number, "-", 2) + 1; |  | ||||||
|         return substr($this->estimate_number, $position); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private function strposX($haystack, $needle, $number) |  | ||||||
|     { |  | ||||||
|         if ($number == '1') { |  | ||||||
|             return strpos($haystack, $needle); |  | ||||||
|         } elseif ($number > '1') { |  | ||||||
|             return strpos( |  | ||||||
|                 $haystack, |  | ||||||
|                 $needle, |  | ||||||
|                 $this->strposX($haystack, $needle, $number - 1) + strlen($needle) |  | ||||||
|             ); |  | ||||||
|         } else { |  | ||||||
|             return error_log('Error: Value for parameter $number is out of range'); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function getFormattedExpiryDateAttribute($value) |  | ||||||
|     { |  | ||||||
|         $dateFormat = CompanySetting::getSetting('carbon_date_format', $this->company_id); |  | ||||||
|         return Carbon::parse($this->expiry_date)->format($dateFormat); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function getFormattedEstimateDateAttribute($value) |  | ||||||
|     { |  | ||||||
|         $dateFormat = CompanySetting::getSetting('carbon_date_format', $this->company_id); |  | ||||||
|         return Carbon::parse($this->estimate_date)->format($dateFormat); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function scopeEstimatesBetween($query, $start, $end) |  | ||||||
|     { |  | ||||||
|         return $query->whereBetween( |  | ||||||
|             'estimates.estimate_date', |  | ||||||
|             [$start->format('Y-m-d'), $end->format('Y-m-d')] |  | ||||||
|         ); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function scopeWhereStatus($query, $status) |  | ||||||
|     { |  | ||||||
|         return $query->where('estimates.status', $status); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function scopeWhereEstimateNumber($query, $estimateNumber) |  | ||||||
|     { |  | ||||||
|         return $query->where('estimates.estimate_number', $estimateNumber); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function scopeWhereSearch($query, $search) |  | ||||||
|     { |  | ||||||
|         foreach (explode(' ', $search) as $term) { |  | ||||||
|             $query->whereHas('user', function ($query) use ($term) { |  | ||||||
|                 $query->where('name', 'LIKE', '%'.$term.'%') |  | ||||||
|                     ->orWhere('contact_name', 'LIKE', '%'.$term.'%') |  | ||||||
|                     ->orWhere('company_name', 'LIKE', '%'.$term.'%'); |  | ||||||
|             }); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function scopeApplyFilters($query, array $filters) |  | ||||||
|     { |  | ||||||
|         $filters = collect($filters); |  | ||||||
|  |  | ||||||
|         if ($filters->get('search')) { |  | ||||||
|             $query->whereSearch($filters->get('search')); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if ($filters->get('estimate_number')) { |  | ||||||
|             $query->whereEstimateNumber($filters->get('estimate_number')); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if ($filters->get('status')) { |  | ||||||
|             $query->whereStatus($filters->get('status')); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if ($filters->get('from_date') && $filters->get('to_date')) { |  | ||||||
|             $start = Carbon::createFromFormat('d/m/Y', $filters->get('from_date')); |  | ||||||
|             $end = Carbon::createFromFormat('d/m/Y', $filters->get('to_date')); |  | ||||||
|             $query->estimatesBetween($start, $end); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if ($filters->get('customer_id')) { |  | ||||||
|             $query->whereCustomer($filters->get('customer_id')); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if ($filters->get('orderByField') || $filters->get('orderBy')) { |  | ||||||
|             $field = $filters->get('orderByField') ? $filters->get('orderByField') : 'estimate_number'; |  | ||||||
|             $orderBy = $filters->get('orderBy') ? $filters->get('orderBy') : 'asc'; |  | ||||||
|             $query->whereOrder($field, $orderBy); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function scopeWhereOrder($query, $orderByField, $orderBy) |  | ||||||
|     { |  | ||||||
|         $query->orderBy($orderByField, $orderBy); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function scopeWhereCompany($query, $company_id) |  | ||||||
|     { |  | ||||||
|         $query->where('estimates.company_id', $company_id); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function scopeWhereCustomer($query, $customer_id) |  | ||||||
|     { |  | ||||||
|         $query->where('estimates.user_id', $customer_id); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public static function deleteEstimate($id) |  | ||||||
|     { |  | ||||||
|         $estimate = Estimate::find($id); |  | ||||||
|  |  | ||||||
|         if ($estimate->items()->exists()) { |  | ||||||
|             $estimate->items()->delete(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if ($estimate->taxes()->exists()) { |  | ||||||
|             $estimate->taxes()->delete(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         $estimate->delete(); |  | ||||||
|  |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -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 | ||||||
| { | { | ||||||
| @ -25,7 +19,7 @@ class UpdateFinished | |||||||
|      */ |      */ | ||||||
|     public function __construct($old, $new) |     public function __construct($old, $new) | ||||||
|     { |     { | ||||||
|         $this->old   = $old; |         $this->old = $old; | ||||||
|         $this->new   = $new; |         $this->new = $new; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| <?php | <?php | ||||||
| namespace Crater\Exceptions; | namespace Crater\Exceptions; | ||||||
|  |  | ||||||
| use Exception; | use Throwable; | ||||||
| use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler; | use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler; | ||||||
|  |  | ||||||
| class Handler extends ExceptionHandler | class Handler extends ExceptionHandler | ||||||
| @ -30,10 +30,10 @@ class Handler extends ExceptionHandler | |||||||
|      * |      * | ||||||
|      * This is a great spot to send exceptions to Sentry, Bugsnag, etc. |      * This is a great spot to send exceptions to Sentry, Bugsnag, etc. | ||||||
|      * |      * | ||||||
|      * @param  \Exception  $exception |      * @param  \Throwable $exception | ||||||
|      * @return void |      * @return void | ||||||
|      */ |      */ | ||||||
|     public function report(Exception $exception) |     public function report(Throwable $exception) | ||||||
|     { |     { | ||||||
|         parent::report($exception); |         parent::report($exception); | ||||||
|     } |     } | ||||||
| @ -42,10 +42,10 @@ class Handler extends ExceptionHandler | |||||||
|      * Render an exception into an HTTP response. |      * Render an exception into an HTTP response. | ||||||
|      * |      * | ||||||
|      * @param  \Illuminate\Http\Request  $request |      * @param  \Illuminate\Http\Request  $request | ||||||
|      * @param  \Exception  $exception |      * @param  \Throwable  $exception | ||||||
|      * @return \Illuminate\Http\Response |      * @return \Illuminate\Http\Response | ||||||
|      */ |      */ | ||||||
|     public function render($request, Exception $exception) |     public function render($request, Throwable $exception) | ||||||
|     { |     { | ||||||
|         return parent::render($request, $exception); |         return parent::render($request, $exception); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -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); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
							
								
								
									
										50
									
								
								app/Generators/CustomPathGenerator.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								app/Generators/CustomPathGenerator.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,50 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  |  | ||||||
|  | namespace Crater\Generators; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | use Crater\Models\Estimate; | ||||||
|  | use Crater\Models\Invoice; | ||||||
|  | use Crater\Models\Payment; | ||||||
|  | use Spatie\MediaLibrary\MediaCollections\Models\Media; | ||||||
|  | use Spatie\MediaLibrary\Support\PathGenerator\PathGenerator; | ||||||
|  |  | ||||||
|  | class CustomPathGenerator implements PathGenerator | ||||||
|  | { | ||||||
|  |  | ||||||
|  |     public function getPath(Media $media): string | ||||||
|  |     { | ||||||
|  |         return $this->getBasePath($media) . '/'; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getPathForConversions(Media $media): string | ||||||
|  |     { | ||||||
|  |         return $this->getBasePath($media) . '/conversations/'; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getPathForResponsiveImages(Media $media): string | ||||||
|  |     { | ||||||
|  |         return $this->getBasePath($media) . '/responsive-images/'; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* | ||||||
|  |      * Get a unique base path for the given media. | ||||||
|  |      */ | ||||||
|  |     protected function getBasePath(Media $media): string | ||||||
|  |     { | ||||||
|  |         $folderName = null; | ||||||
|  |  | ||||||
|  |         if ($media->model_type == Invoice::class) { | ||||||
|  |             $folderName = 'Invoices'; | ||||||
|  |         } elseif ($media->model_type == Estimate::class) { | ||||||
|  |             $folderName = 'Estimates'; | ||||||
|  |         } elseif ($media->model_type == Payment::class) { | ||||||
|  |             $folderName = 'Payments'; | ||||||
|  |         } else { | ||||||
|  |             $folderName = $media->getKey(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $folderName; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										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,258 +0,0 @@ | |||||||
| <?php |  | ||||||
| namespace Crater\Http\Controllers; |  | ||||||
|  |  | ||||||
| use Illuminate\Http\Request; |  | ||||||
| use Crater\User; |  | ||||||
| use Crater\Setting; |  | ||||||
| use Crater\Company; |  | ||||||
| use Crater\Address; |  | ||||||
| use Crater\Http\Requests\SettingRequest; |  | ||||||
| use Crater\Http\Requests\SettingKeyRequest; |  | ||||||
| use Crater\Http\Requests\ProfileRequest; |  | ||||||
| use Crater\Http\Requests\CompanyRequest; |  | ||||||
| use Crater\Http\Requests\CompanySettingRequest; |  | ||||||
| use Crater\Http\Requests\NotificationSettingsRequest; |  | ||||||
| use Crater\Space\CurrencyFormatter; |  | ||||||
| use Crater\Space\DateFormatter; |  | ||||||
| use Crater\Space\TimeZones; |  | ||||||
| use Crater\Currency; |  | ||||||
| use Crater\CompanySetting; |  | ||||||
|  |  | ||||||
| class CompanyController extends Controller |  | ||||||
| { |  | ||||||
|     public function getAdmin() |  | ||||||
|     { |  | ||||||
|         return User::find(1); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function updateAdminProfile(ProfileRequest $request) |  | ||||||
|     { |  | ||||||
|         $verifyEmail = User::where('email', $request->email)->first(); |  | ||||||
|  |  | ||||||
|         $user = auth()->user(); |  | ||||||
|  |  | ||||||
|         if ($verifyEmail) { |  | ||||||
|             if ($verifyEmail->id !== $user->id) { |  | ||||||
|                 return response()->json([ |  | ||||||
|                     'error' => 'Email already in use' |  | ||||||
|                 ]); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         $user->name = $request->name; |  | ||||||
|         $user->email = $request->email; |  | ||||||
|  |  | ||||||
|         if ($request->has('password')) { |  | ||||||
|             $user->password = bcrypt($request->password); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         $user->save(); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'user' => $user, |  | ||||||
|             'success' => true |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function getAdminCompany() |  | ||||||
|     { |  | ||||||
|         $user = User::with(['addresses', 'addresses.country', 'addresses.state', 'addresses.city', 'company'])->find(1); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'user' => $user |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function updateAdminCompany(CompanyRequest $request) |  | ||||||
|     { |  | ||||||
|         $user = User::find(1); |  | ||||||
|         $company = $user->company; |  | ||||||
|         $company->name = $request->name; |  | ||||||
|         $company->save(); |  | ||||||
|  |  | ||||||
|         if ($request->has('logo')) { |  | ||||||
|             $company->clearMediaCollection('logo'); |  | ||||||
|             $company->addMediaFromRequest('logo')->toMediaCollection('logo'); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         $fields = $request->only(['address_street_1', 'address_street_2', 'city_id', 'state_id', 'country_id', 'zip', 'phone']); |  | ||||||
|         $address = Address::updateOrCreate(['user_id' => 1], $fields); |  | ||||||
|         $user = User::with(['addresses', 'addresses.country', 'addresses.state', 'addresses.city', 'company'])->find(1); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'user' => $user, |  | ||||||
|             'success' => true |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function getGeneralSettings(Request $request) |  | ||||||
|     { |  | ||||||
|         $date_formats = DateFormatter::get_list(); |  | ||||||
|  |  | ||||||
|         $time_zones = TimeZones::get_list(); |  | ||||||
|         $fiscal_years = [ |  | ||||||
|             ['key' => 'january-december' , 'value' => '1-12'], |  | ||||||
|             ['key' => 'february-january' , 'value' => '2-1'], |  | ||||||
|             ['key' => 'march-february'   , 'value' => '3-2'], |  | ||||||
|             ['key' => 'april-march'      , 'value' => '4-3'], |  | ||||||
|             ['key' => 'may-april'        , 'value' => '5-4'], |  | ||||||
|             ['key' => 'june-may'         , 'value' => '6-5'], |  | ||||||
|             ['key' => 'july-june'        , 'value' => '7-6'], |  | ||||||
|             ['key' => 'august-july'      , 'value' => '8-7'], |  | ||||||
|             ['key' => 'september-august' , 'value' => '9-8'], |  | ||||||
|             ['key' => 'october-september', 'value' => '10-9'], |  | ||||||
|             ['key' => 'november-october' , 'value' => '11-10'], |  | ||||||
|             ['key' => 'december-november', 'value' => '12-11'], |  | ||||||
|         ]; |  | ||||||
|  |  | ||||||
|         $language = CompanySetting::getSetting('language', $request->header('company')); |  | ||||||
|         $carbon_date_format = CompanySetting::getSetting('carbon_date_format', $request->header('company')); |  | ||||||
|         $moment_date_format = CompanySetting::getSetting('moment_date_format', $request->header('company')); |  | ||||||
|         $time_zone = CompanySetting::getSetting('time_zone', $request->header('company')); |  | ||||||
|         $currency = CompanySetting::getSetting('currency', $request->header('company')); |  | ||||||
|         $fiscal_year = CompanySetting::getSetting('fiscal_year', $request->header('company')); |  | ||||||
|  |  | ||||||
|         $languages = [ |  | ||||||
|             ["code"=>"en", "name" => "English"], |  | ||||||
|             ["code"=>"fr", "name" => "French"], |  | ||||||
|             ["code"=>"es", "name" => "Spanish"] |  | ||||||
|         ]; |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'languages' => $languages, |  | ||||||
|             'date_formats' => $date_formats, |  | ||||||
|             'time_zones' => $time_zones, |  | ||||||
|             'time_zone' => $time_zone, |  | ||||||
|             'currencies' => Currency::all(), |  | ||||||
|             'fiscal_years' => $fiscal_years, |  | ||||||
|             'fiscal_year' => $fiscal_year, |  | ||||||
|             'selectedLanguage' => $language, |  | ||||||
|             'selectedCurrency' => $currency, |  | ||||||
|             'carbon_date_format' => $carbon_date_format, |  | ||||||
|             'moment_date_format' => $moment_date_format, |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function updateGeneralSettings(CompanySettingRequest $request) |  | ||||||
|     { |  | ||||||
|         $sets = [ |  | ||||||
|             'currency', |  | ||||||
|             'time_zone', |  | ||||||
|             'language', |  | ||||||
|             'carbon_date_format', |  | ||||||
|             'fiscal_year', |  | ||||||
|             'moment_date_format' |  | ||||||
|         ]; |  | ||||||
|  |  | ||||||
|         foreach ($sets as $key) { |  | ||||||
|             CompanySetting::setSetting($key, $request->$key, $request->header('company')); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'success' => true |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function updateSetting(SettingRequest $request) |  | ||||||
|     { |  | ||||||
|         CompanySetting::setSetting($request->key, $request->value, $request->header('company')); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'success' => true |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function getSetting(SettingKeyRequest $request) |  | ||||||
|     { |  | ||||||
|         $setting = CompanySetting::getSetting($request->key, $request->header('company')); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             $request->key => $setting |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function getColors(Request $request) |  | ||||||
|     { |  | ||||||
|         $colors = [ |  | ||||||
|             'invoice_primary_color', |  | ||||||
|             'invoice_column_heading', |  | ||||||
|             'invoice_field_label', |  | ||||||
|             'invoice_field_value', |  | ||||||
|             'invoice_body_text', |  | ||||||
|             'invoice_description_text', |  | ||||||
|             'invoice_border_color', |  | ||||||
|             'primary_text_color', |  | ||||||
|             'heading_text_color', |  | ||||||
|             'section_heading_text_color', |  | ||||||
|             'border_color', |  | ||||||
|             'body_text_color', |  | ||||||
|             'footer_text_color', |  | ||||||
|             'footer_total_color', |  | ||||||
|             'footer_bg_color', |  | ||||||
|             'date_text_color' |  | ||||||
|         ]; |  | ||||||
|  |  | ||||||
|         $colorSettings = CompanySetting::whereIn('option', $colors) |  | ||||||
|             ->whereCompany($request->header('company')) |  | ||||||
|             ->get(); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'colorSettings' => $colorSettings |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Upload the company logo to storage. |  | ||||||
|      * |  | ||||||
|      * @param  \Illuminate\Http\Request $request |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function uploadCompanyLogo(Request $request) |  | ||||||
|     { |  | ||||||
|         $data = json_decode($request->company_logo); |  | ||||||
|  |  | ||||||
|         if($data) { |  | ||||||
|             $company = Company::find($request->header('company')); |  | ||||||
|  |  | ||||||
|             if($company) { |  | ||||||
|                 $company->clearMediaCollection('logo'); |  | ||||||
|  |  | ||||||
|                 $company->addMediaFromBase64($data->data) |  | ||||||
|                     ->usingFileName($data->name) |  | ||||||
|                     ->toMediaCollection('logo'); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'success' => true |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Upload the Admin Avatar to public storage. |  | ||||||
|      * |  | ||||||
|      * @param  \Illuminate\Http\Request $request |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function uploadAdminAvatar(Request $request) |  | ||||||
|     { |  | ||||||
|         $data = json_decode($request->admin_avatar); |  | ||||||
|  |  | ||||||
|         if($data) { |  | ||||||
|             $user = auth()->user(); |  | ||||||
|  |  | ||||||
|             if($user) { |  | ||||||
|                 $user->clearMediaCollection('admin_avatar'); |  | ||||||
|  |  | ||||||
|                 $user->addMediaFromBase64($data->data) |  | ||||||
|                     ->usingFileName($data->name) |  | ||||||
|                     ->toMediaCollection('admin_avatar'); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'user' => $user, |  | ||||||
|             'success' => true |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,234 +0,0 @@ | |||||||
| <?php |  | ||||||
| namespace Crater\Http\Controllers; |  | ||||||
|  |  | ||||||
| use Illuminate\Http\Request; |  | ||||||
| use Illuminate\Support\Facades\Auth; |  | ||||||
| use Crater\Conversation; |  | ||||||
| use Crater\Group; |  | ||||||
| use Crater\Http\Requests; |  | ||||||
| use Crater\Notifications\CustomerAdded; |  | ||||||
| use Crater\User; |  | ||||||
| use Illuminate\Support\Facades\Hash; |  | ||||||
| use Crater\Currency; |  | ||||||
| use Crater\CompanySetting; |  | ||||||
| use Crater\Address; |  | ||||||
| use Illuminate\Support\Facades\DB; |  | ||||||
|  |  | ||||||
| class CustomersController extends Controller |  | ||||||
| { |  | ||||||
|     /** |  | ||||||
|      * Display a listing of the resource. |  | ||||||
|      * |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function index(Request $request) |  | ||||||
|     { |  | ||||||
|         $limit = $request->has('limit') ? $request->limit : 10; |  | ||||||
|  |  | ||||||
|         $customers = User::customer() |  | ||||||
|             ->applyFilters($request->only([ |  | ||||||
|                 'search', |  | ||||||
|                 'contact_name', |  | ||||||
|                 'display_name', |  | ||||||
|                 'phone', |  | ||||||
|                 'orderByField', |  | ||||||
|                 'orderBy' |  | ||||||
|             ])) |  | ||||||
|             ->whereCompany($request->header('company')) |  | ||||||
|             ->select('users.*', |  | ||||||
|                 DB::raw('sum(invoices.due_amount) as due_amount') |  | ||||||
|             ) |  | ||||||
|             ->groupBy('users.id') |  | ||||||
|             ->leftJoin('invoices', 'users.id', '=', 'invoices.user_id') |  | ||||||
|             ->paginate($limit); |  | ||||||
|  |  | ||||||
|         $siteData = [ |  | ||||||
|             'customers' => $customers |  | ||||||
|         ]; |  | ||||||
|  |  | ||||||
|         return response()->json($siteData); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Store a newly created resource in storage. |  | ||||||
|      * |  | ||||||
|      * @param  \Illuminate\Http\Request  $request |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function store(Requests\CustomerRequest $request) |  | ||||||
|     { |  | ||||||
|         $verifyEmail = User::where('email', $request->email)->first(); |  | ||||||
|  |  | ||||||
|  |  | ||||||
|         $customer = new User(); |  | ||||||
|         $customer->name = $request->name; |  | ||||||
|         $customer->currency_id = $request->currency_id; |  | ||||||
|         $customer->company_id = $request->header('company'); |  | ||||||
|         $customer->email = $request->email; |  | ||||||
|         $customer->phone = $request->phone; |  | ||||||
|         $customer->company_name = $request->company_name; |  | ||||||
|         $customer->contact_name = $request->contact_name; |  | ||||||
|         $customer->website = $request->website; |  | ||||||
|         $customer->enable_portal = $request->enable_portal; |  | ||||||
|         $customer->role = 'customer'; |  | ||||||
|         $customer->password = Hash::make($request->password); |  | ||||||
|         $customer->save(); |  | ||||||
|  |  | ||||||
|         if ($request->addresses) { |  | ||||||
|             foreach ($request->addresses as $address) { |  | ||||||
|                 $newAddress = new Address(); |  | ||||||
|                 $newAddress->name = $address["name"]; |  | ||||||
|                 $newAddress->address_street_1 = $address["address_street_1"]; |  | ||||||
|                 $newAddress->address_street_2 = $address["address_street_2"]; |  | ||||||
|                 $newAddress->city_id = $address["city_id"]; |  | ||||||
|                 $newAddress->state_id = $address["state_id"]; |  | ||||||
|                 $newAddress->country_id = $address["country_id"]; |  | ||||||
|                 $newAddress->zip = $address["zip"]; |  | ||||||
|                 $newAddress->phone = $address["phone"]; |  | ||||||
|                 $newAddress->type = $address["type"]; |  | ||||||
|                 $newAddress->user_id = $customer->id; |  | ||||||
|                 $newAddress->save(); |  | ||||||
|                 $customer->addresses()->save($newAddress); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         $customer = User::with('billingAddress', 'shippingAddress')->find($customer->id); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'customer' => $customer, |  | ||||||
|             'success' => true |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Display the specified resource. |  | ||||||
|      * |  | ||||||
|      * @param  int  $id |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function show($id) |  | ||||||
|     { |  | ||||||
|         $customer = User::with([ |  | ||||||
|             'billingAddress', |  | ||||||
|             'shippingAddress', |  | ||||||
|             'billingAddress.country', |  | ||||||
|             'billingAddress.state', |  | ||||||
|             'billingAddress.city', |  | ||||||
|             'shippingAddress.country', |  | ||||||
|             'shippingAddress.state', |  | ||||||
|             'shippingAddress.city', |  | ||||||
|         ])->find($id); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'customer' => $customer |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Show the form for editing the specified resource. |  | ||||||
|      * |  | ||||||
|      * @param  int  $id |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function edit($id) |  | ||||||
|     { |  | ||||||
|         $customer = User::with('billingAddress', 'shippingAddress')->findOrFail($id); |  | ||||||
|         $currency = $customer->currency; |  | ||||||
|         $currencies = Currency::all(); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'customer' => $customer, |  | ||||||
|             'currencies' => $currencies, |  | ||||||
|             'currency' => $currency |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Update the specified resource in storage. |  | ||||||
|      * |  | ||||||
|      * @param  \Illuminate\Http\Request  $request |  | ||||||
|      * @param  int  $id |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function update($id, Requests\CustomerRequest $request) |  | ||||||
|     { |  | ||||||
|         $customer = User::find($id); |  | ||||||
|  |  | ||||||
|         if ($request->email != null) { |  | ||||||
|             $verifyEmail = User::where('email', $request->email)->first(); |  | ||||||
|  |  | ||||||
|             if ($verifyEmail) { |  | ||||||
|                 if ($verifyEmail->id !== $customer->id) { |  | ||||||
|                     return response()->json([ |  | ||||||
|                         'success' => false, |  | ||||||
|                         'error' => 'Email already in use' |  | ||||||
|                     ]); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if ($request->has('password')) { |  | ||||||
|             $customer->password = Hash::make($request->password); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         $customer->name = $request->name; |  | ||||||
|         $customer->currency_id = $request->currency_id; |  | ||||||
|         $customer->email = $request->email; |  | ||||||
|         $customer->phone = $request->phone; |  | ||||||
|         $customer->company_name = $request->company_name; |  | ||||||
|         $customer->contact_name = $request->contact_name; |  | ||||||
|         $customer->website = $request->website; |  | ||||||
|         $customer->enable_portal = $request->enable_portal; |  | ||||||
|         $customer->save(); |  | ||||||
|  |  | ||||||
|         if ($request->addresses) { |  | ||||||
|             foreach ($request->addresses as $address) { |  | ||||||
|                 $newAddress = $customer->addresses()->firstOrNew(['type' => $address["type"]]); |  | ||||||
|                 $newAddress->name = $address["name"]; |  | ||||||
|                 $newAddress->address_street_1 = $address["address_street_1"]; |  | ||||||
|                 $newAddress->address_street_2 = $address["address_street_2"]; |  | ||||||
|                 $newAddress->city_id = $address["city_id"]; |  | ||||||
|                 $newAddress->state_id = $address["state_id"]; |  | ||||||
|                 $newAddress->country_id = $address["country_id"]; |  | ||||||
|                 $newAddress->zip = $address["zip"]; |  | ||||||
|                 $newAddress->phone = $address["phone"]; |  | ||||||
|                 $newAddress->type = $address["type"]; |  | ||||||
|                 $newAddress->user_id = $customer->id; |  | ||||||
|                 $newAddress->save(); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         $customer = User::with('billingAddress', 'shippingAddress')->find($customer->id); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'customer' => $customer, |  | ||||||
|             'success' => true |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Remove the specified resource from storage. |  | ||||||
|      * |  | ||||||
|      * @param  int  $id |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function destroy($id) |  | ||||||
|     { |  | ||||||
|         User::deleteCustomer($id); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'success' => true |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function delete(Request $request) |  | ||||||
|     { |  | ||||||
|         foreach ($request->id as $id) { |  | ||||||
|             User::deleteCustomer($id); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'success' => true |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,470 +0,0 @@ | |||||||
| <?php |  | ||||||
| namespace Crater\Http\Controllers; |  | ||||||
|  |  | ||||||
| use Illuminate\Http\Request; |  | ||||||
| use Crater\Estimate; |  | ||||||
| use Crater\EstimateItem; |  | ||||||
| use Crater\EstimateTemplate; |  | ||||||
| use Carbon\Carbon; |  | ||||||
| use Crater\Http\Requests\EstimatesRequest; |  | ||||||
| use Crater\Invoice; |  | ||||||
| use Crater\Currency; |  | ||||||
| use Crater\User; |  | ||||||
| use Crater\Item; |  | ||||||
| use Validator; |  | ||||||
| use Crater\CompanySetting; |  | ||||||
| use Crater\Company; |  | ||||||
| use Crater\Mail\EstimatePdf; |  | ||||||
| use Crater\TaxType; |  | ||||||
| use Crater\Tax; |  | ||||||
|  |  | ||||||
| class EstimatesController extends Controller |  | ||||||
| { |  | ||||||
|     public function index(Request $request) |  | ||||||
|     { |  | ||||||
|         $limit = $request->has('limit') ? $request->limit : 10; |  | ||||||
|  |  | ||||||
|         $estimates = Estimate::with([ |  | ||||||
|                 'items', |  | ||||||
|                 'user', |  | ||||||
|                 'estimateTemplate', |  | ||||||
|                 'taxes' |  | ||||||
|             ]) |  | ||||||
|             ->join('users', 'users.id', '=', 'estimates.user_id') |  | ||||||
|             ->applyFilters($request->only([ |  | ||||||
|                 'status', |  | ||||||
|                 'customer_id', |  | ||||||
|                 'estimate_number', |  | ||||||
|                 'from_date', |  | ||||||
|                 'to_date', |  | ||||||
|                 'search', |  | ||||||
|                 'orderByField', |  | ||||||
|                 'orderBy' |  | ||||||
|             ])) |  | ||||||
|             ->whereCompany($request->header('company')) |  | ||||||
|             ->select('estimates.*', 'users.name') |  | ||||||
|             ->latest() |  | ||||||
|             ->paginate($limit); |  | ||||||
|  |  | ||||||
|         $siteData = [ |  | ||||||
|             'estimates' => $estimates, |  | ||||||
|             'estimateTotalCount' => Estimate::count() |  | ||||||
|         ]; |  | ||||||
|  |  | ||||||
|         return response()->json($siteData); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function create(Request $request) |  | ||||||
|     { |  | ||||||
|         $nextEstimateNumber = 'EST-'.Estimate::getNextEstimateNumber(); |  | ||||||
|         $tax_per_item = CompanySetting::getSetting('tax_per_item', $request->header('company')); |  | ||||||
|         $discount_per_item = CompanySetting::getSetting('discount_per_item', $request->header('company')); |  | ||||||
|         $customers = User::where('role', 'customer')->get(); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'customers' => $customers, |  | ||||||
|             'nextEstimateNumber' => $nextEstimateNumber, |  | ||||||
|             'taxes' => Tax::whereCompany($request->header('company'))->latest()->get(), |  | ||||||
|             'items' => Item::whereCompany($request->header('company'))->get(), |  | ||||||
|             'tax_per_item' => $tax_per_item, |  | ||||||
|             'discount_per_item' => $discount_per_item, |  | ||||||
|             'estimateTemplates' => EstimateTemplate::all(), |  | ||||||
|             'shareable_link' => '' |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function store(EstimatesRequest $request) |  | ||||||
|     { |  | ||||||
|         $estimate_date = Carbon::createFromFormat('d/m/Y', $request->estimate_date); |  | ||||||
|         $expiry_date = Carbon::createFromFormat('d/m/Y', $request->expiry_date); |  | ||||||
|         $status = Estimate::STATUS_DRAFT; |  | ||||||
|         $tax_per_item = CompanySetting::getSetting( |  | ||||||
|             'tax_per_item', |  | ||||||
|             $request->header('company') |  | ||||||
|         ) ? CompanySetting::getSetting( |  | ||||||
|             'tax_per_item', |  | ||||||
|             $request->header('company') |  | ||||||
|         ) : 'NO'; |  | ||||||
|  |  | ||||||
|         if ($request->has('estimateSend')) { |  | ||||||
|             $status = Estimate::STATUS_SENT; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         $discount_per_item = CompanySetting::getSetting( |  | ||||||
|             'discount_per_item', |  | ||||||
|             $request->header('company') |  | ||||||
|         ) ? CompanySetting::getSetting( |  | ||||||
|             'discount_per_item', |  | ||||||
|             $request->header('company') |  | ||||||
|         ) : 'NO'; |  | ||||||
|  |  | ||||||
|         $estimate = Estimate::create([ |  | ||||||
|             'estimate_date' => $estimate_date, |  | ||||||
|             'expiry_date' => $expiry_date, |  | ||||||
|             'estimate_number' => $request->estimate_number, |  | ||||||
|             'reference_number' => $request->reference_number, |  | ||||||
|             'user_id' => $request->user_id, |  | ||||||
|             'company_id' => $request->header('company'), |  | ||||||
|             'estimate_template_id' => $request->estimate_template_id, |  | ||||||
|             'status' => $status, |  | ||||||
|             'discount' => $request->discount, |  | ||||||
|             'discount_type' => $request->discount_type, |  | ||||||
|             'discount_val' => $request->discount_val, |  | ||||||
|             'sub_total' => $request->sub_total, |  | ||||||
|             'total' => $request->total, |  | ||||||
|             'tax_per_item' => $tax_per_item, |  | ||||||
|             'discount_per_item' => $discount_per_item, |  | ||||||
|             'tax' => $request->tax, |  | ||||||
|             'notes' => $request->notes, |  | ||||||
|             'unique_hash' => str_random(60) |  | ||||||
|         ]); |  | ||||||
|  |  | ||||||
|         $estimateItems = $request->items; |  | ||||||
|  |  | ||||||
|         foreach ($estimateItems as $estimateItem) { |  | ||||||
|             $estimateItem['company_id'] = $request->header('company'); |  | ||||||
|             $item = $estimate->items()->create($estimateItem); |  | ||||||
|  |  | ||||||
|             if (array_key_exists('taxes', $estimateItem) && $estimateItem['taxes']) { |  | ||||||
|                 foreach ($estimateItem['taxes'] as $tax) { |  | ||||||
|                     if ($tax['amount']) { |  | ||||||
|                         $tax['company_id'] = $request->header('company'); |  | ||||||
|                         $item->taxes()->create($tax); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if ($request->has('taxes')) { |  | ||||||
|             foreach ($request->taxes as $tax) { |  | ||||||
|                 if ($tax['amount']) { |  | ||||||
|                     $tax['company_id'] = $request->header('company'); |  | ||||||
|                     $estimate->taxes()->create($tax); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if ($request->has('estimateSend')) { |  | ||||||
|             $data['estimate'] = $estimate->toArray(); |  | ||||||
|             $userId = $data['estimate']['user_id']; |  | ||||||
|             $data['user'] = User::find($userId)->toArray(); |  | ||||||
|             $data['company'] = Company::find($estimate->company_id); |  | ||||||
|             $email = $data['user']['email']; |  | ||||||
|             $notificationEmail = CompanySetting::getSetting( |  | ||||||
|                 'notification_email', |  | ||||||
|                 $request->header('company') |  | ||||||
|             ); |  | ||||||
|  |  | ||||||
|             if (!$email) { |  | ||||||
|                 return response()->json([ |  | ||||||
|                     'error' => 'user_email_does_not_exist' |  | ||||||
|                 ]); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             if (!$notificationEmail) { |  | ||||||
|                 return response()->json([ |  | ||||||
|                     'error' => 'notification_email_does_not_exist' |  | ||||||
|                 ]); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             \Mail::to($email)->send(new EstimatePdf($data, $notificationEmail)); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         $estimate = Estimate::with([ |  | ||||||
|             'items', |  | ||||||
|             'user', |  | ||||||
|             'estimateTemplate', |  | ||||||
|             'taxes' |  | ||||||
|         ])->find($estimate->id); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'estimate' => $estimate, |  | ||||||
|             'url' => url('/estimates/pdf/'.$estimate->unique_hash), |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function show(Request $request, $id) |  | ||||||
|     { |  | ||||||
|         $estimate = Estimate::with([ |  | ||||||
|             'items', |  | ||||||
|             'items.taxes', |  | ||||||
|             'user', |  | ||||||
|             'estimateTemplate', |  | ||||||
|             'taxes', |  | ||||||
|             'taxes.taxType' |  | ||||||
|         ])->find($id); |  | ||||||
|  |  | ||||||
|         $siteData = [ |  | ||||||
|             'estimate' => $estimate, |  | ||||||
|             'shareable_link' => url('/estimates/pdf/'.$estimate->unique_hash) |  | ||||||
|         ]; |  | ||||||
|  |  | ||||||
|         return response()->json($siteData); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function edit(Request $request,$id) |  | ||||||
|     { |  | ||||||
|         $estimate = Estimate::with([ |  | ||||||
|             'items', |  | ||||||
|             'items.taxes', |  | ||||||
|             'user', |  | ||||||
|             'estimateTemplate', |  | ||||||
|             'taxes', |  | ||||||
|             'taxes.taxType' |  | ||||||
|         ])->find($id); |  | ||||||
|         $customers = User::where('role', 'customer')->get(); |  | ||||||
|  |  | ||||||
|         return response()->json( [ |  | ||||||
|             'customers' => $customers, |  | ||||||
|             'nextEstimateNumber' => $estimate->estimate_number, |  | ||||||
|             'taxes' => Tax::latest()->whereCompany($request->header('company'))->get(), |  | ||||||
|             'estimate' => $estimate, |  | ||||||
|             'items' => Item::whereCompany($request->header('company'))->latest()->get(), |  | ||||||
|             'estimateTemplates' => EstimateTemplate::all(), |  | ||||||
|             'tax_per_item' => $estimate->tax_per_item, |  | ||||||
|             'discount_per_item' => $estimate->discount_per_item, |  | ||||||
|             'shareable_link' => url('/estimates/pdf/'.$estimate->unique_hash) |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function update(EstimatesRequest $request, $id) |  | ||||||
|     { |  | ||||||
|         $estimate_date = Carbon::createFromFormat('d/m/Y', $request->estimate_date); |  | ||||||
|         $expiry_date = Carbon::createFromFormat('d/m/Y', $request->expiry_date); |  | ||||||
|  |  | ||||||
|         $estimate = Estimate::find($id); |  | ||||||
|         $estimate->estimate_date = $estimate_date; |  | ||||||
|         $estimate->expiry_date = $expiry_date; |  | ||||||
|         $estimate->estimate_number = $request->estimate_number; |  | ||||||
|         $estimate->reference_number = $request->reference_number; |  | ||||||
|         $estimate->user_id = $request->user_id; |  | ||||||
|         $estimate->estimate_template_id = $request->estimate_template_id; |  | ||||||
|         $estimate->discount = $request->discount; |  | ||||||
|         $estimate->discount_type = $request->discount_type; |  | ||||||
|         $estimate->discount_val = $request->discount_val; |  | ||||||
|         $estimate->sub_total = $request->sub_total; |  | ||||||
|         $estimate->total = $request->total; |  | ||||||
|         $estimate->tax = $request->tax; |  | ||||||
|         $estimate->notes = $request->notes; |  | ||||||
|         $estimate->save(); |  | ||||||
|  |  | ||||||
|         $oldItems = $estimate->items->toArray(); |  | ||||||
|         $oldTaxes = $estimate->taxes->toArray(); |  | ||||||
|         $estimateItems = $request->items; |  | ||||||
|  |  | ||||||
|         foreach ($oldItems as $oldItem) { |  | ||||||
|             EstimateItem::destroy($oldItem['id']); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         foreach ($oldTaxes as $oldTax) { |  | ||||||
|             Tax::destroy($oldTax['id']); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         foreach ($estimateItems as $estimateItem) { |  | ||||||
|             $estimateItem['company_id'] = $request->header('company'); |  | ||||||
|             $item = $estimate->items()->create($estimateItem); |  | ||||||
|  |  | ||||||
|             if (array_key_exists('taxes', $estimateItem) && $estimateItem['taxes']) { |  | ||||||
|                 foreach ($estimateItem['taxes'] as $tax) { |  | ||||||
|                     if ($tax['amount']) { |  | ||||||
|                         $tax['company_id'] = $request->header('company'); |  | ||||||
|                         $item->taxes()->create($tax); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if ($request->has('taxes')) { |  | ||||||
|             foreach ($request->taxes as $tax) { |  | ||||||
|                 if ($tax['amount']) { |  | ||||||
|                     $tax['company_id'] = $request->header('company'); |  | ||||||
|                     $estimate->taxes()->create($tax); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         $estimate = Estimate::with([ |  | ||||||
|             'items', |  | ||||||
|             'user', |  | ||||||
|             'estimateTemplate', |  | ||||||
|             'taxes' |  | ||||||
|         ])->find($estimate->id); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'estimate' => $estimate, |  | ||||||
|             'url' => url('/estimates/pdf/'.$estimate->unique_hash), |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function destroy($id) |  | ||||||
|     { |  | ||||||
|         Estimate::deleteEstimate($id); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'success' => true |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function sendEstimate(Request $request) |  | ||||||
|     { |  | ||||||
|         $estimate = Estimate::findOrFail($request->id); |  | ||||||
|  |  | ||||||
|         $data['estimate'] = $estimate->toArray(); |  | ||||||
|         $userId = $data['estimate']['user_id']; |  | ||||||
|         $data['user'] = User::find($userId)->toArray(); |  | ||||||
|         $data['company'] = Company::find($estimate->company_id); |  | ||||||
|  |  | ||||||
|         $email = $data['user']['email']; |  | ||||||
|         $notificationEmail = CompanySetting::getSetting( |  | ||||||
|             'notification_email', |  | ||||||
|             $request->header('company') |  | ||||||
|         ); |  | ||||||
|  |  | ||||||
|         if (!$email) { |  | ||||||
|             return response()->json([ |  | ||||||
|                 'error' => 'user_email_does_not_exist' |  | ||||||
|             ]); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (!$notificationEmail) { |  | ||||||
|             return response()->json([ |  | ||||||
|                 'error' => 'notification_email_does_not_exist' |  | ||||||
|             ]); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         \Mail::to($email)->send(new EstimatePdf($data, $notificationEmail)); |  | ||||||
|  |  | ||||||
|         if ($estimate->status == Estimate::STATUS_DRAFT) { |  | ||||||
|             $estimate->status = Estimate::STATUS_SENT; |  | ||||||
|             $estimate->save(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'success' => true |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function markEstimateAccepted(Request $request) |  | ||||||
|     { |  | ||||||
|         $estimate = Estimate::find($request->id); |  | ||||||
|         $estimate->status = Estimate::STATUS_ACCEPTED; |  | ||||||
|         $estimate->save(); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'success' => true |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function markEstimateRejected(Request $request) |  | ||||||
|     { |  | ||||||
|         $estimate = Estimate::find($request->id); |  | ||||||
|         $estimate->status = Estimate::STATUS_REJECTED; |  | ||||||
|         $estimate->save(); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'success' => true |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function markEstimateSent(Request $request) |  | ||||||
|     { |  | ||||||
|         $estimate = Estimate::find($request->id); |  | ||||||
|         $estimate->status = Estimate::STATUS_SENT; |  | ||||||
|         $estimate->save(); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'success' => true |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function estimateToInvoice(Request $request, $id) |  | ||||||
|     { |  | ||||||
|         $estimate = Estimate::with(['items', 'items.taxes', 'user', 'estimateTemplate', 'taxes'])->find($id); |  | ||||||
|         $invoice_date = Carbon::parse($estimate->estimate_date); |  | ||||||
|         $due_date = Carbon::parse($estimate->estimate_date)->addDays(7); |  | ||||||
|         $tax_per_item = CompanySetting::getSetting( |  | ||||||
|                 'tax_per_item', |  | ||||||
|                 $request->header('company') |  | ||||||
|             ) ? CompanySetting::getSetting( |  | ||||||
|                 'tax_per_item', |  | ||||||
|                 $request->header('company') |  | ||||||
|             ) : 'NO'; |  | ||||||
|         $discount_per_item = CompanySetting::getSetting( |  | ||||||
|                 'discount_per_item', |  | ||||||
|                 $request->header('company') |  | ||||||
|             ) ? CompanySetting::getSetting( |  | ||||||
|                 'discount_per_item', |  | ||||||
|                 $request->header('company') |  | ||||||
|             ) : 'NO'; |  | ||||||
|  |  | ||||||
|         $invoice = Invoice::create([ |  | ||||||
|             'invoice_date' => $invoice_date, |  | ||||||
|             'due_date' => $due_date, |  | ||||||
|             'invoice_number' => "INV-".Invoice::getNextInvoiceNumber(), |  | ||||||
|             'reference_number' => $estimate->reference_number, |  | ||||||
|             'user_id' => $estimate->user_id, |  | ||||||
|             'company_id' => $request->header('company'), |  | ||||||
|             'invoice_template_id' => 1, |  | ||||||
|             'status' => Invoice::STATUS_DRAFT, |  | ||||||
|             'paid_status' => Invoice::STATUS_UNPAID, |  | ||||||
|             'sub_total' => $estimate->sub_total, |  | ||||||
|             'discount' => $estimate->discount, |  | ||||||
|             'discount_type' => $estimate->discount_type, |  | ||||||
|             'discount_val' => $estimate->discount_val, |  | ||||||
|             'total' => $estimate->total, |  | ||||||
|             'due_amount' => $estimate->total, |  | ||||||
|             'tax_per_item' => $tax_per_item, |  | ||||||
|             'discount_per_item' => $discount_per_item, |  | ||||||
|             'tax' => $estimate->tax, |  | ||||||
|             'notes' => $estimate->notes, |  | ||||||
|             'unique_hash' => str_random(60) |  | ||||||
|         ]); |  | ||||||
|  |  | ||||||
|         $invoiceItems = $estimate->items->toArray(); |  | ||||||
|  |  | ||||||
|         foreach ($invoiceItems as $invoiceItem) { |  | ||||||
|             $invoiceItem['company_id'] = $request->header('company'); |  | ||||||
|             $invoiceItem['name'] = $invoiceItem['name']; |  | ||||||
|             $item = $invoice->items()->create($invoiceItem); |  | ||||||
|  |  | ||||||
|             if (array_key_exists('taxes', $invoiceItem) && $invoiceItem['taxes']) { |  | ||||||
|                 foreach ($invoiceItem['taxes'] as $tax) { |  | ||||||
|                     $tax['company_id'] = $request->header('company'); |  | ||||||
|  |  | ||||||
|                     if ($tax['amount']) { |  | ||||||
|                         $item->taxes()->create($tax); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if ($estimate->taxes) { |  | ||||||
|             foreach ($estimate->taxes->toArray() as $tax) { |  | ||||||
|                 $tax['company_id'] = $request->header('company'); |  | ||||||
|                 $invoice->taxes()->create($tax); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         $invoice = Invoice::with([ |  | ||||||
|             'items', |  | ||||||
|             'user', |  | ||||||
|             'invoiceTemplate', |  | ||||||
|             'taxes' |  | ||||||
|         ])->find($invoice->id); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'invoice' => $invoice |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function delete(Request $request) |  | ||||||
|     { |  | ||||||
|         foreach ($request->id as $id) { |  | ||||||
|             Estimate::deleteEstimate($id); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'success' => true |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,260 +0,0 @@ | |||||||
| <?php |  | ||||||
| namespace Crater\Http\Controllers; |  | ||||||
|  |  | ||||||
| use Crater\Expense; |  | ||||||
| use Crater\User; |  | ||||||
| use Crater\Currency; |  | ||||||
| use Crater\Company; |  | ||||||
| use Crater\CompanySetting; |  | ||||||
| use Illuminate\Http\Request; |  | ||||||
| use Crater\ExpenseCategory; |  | ||||||
| use Crater\Http\Requests\ExpenseRequest; |  | ||||||
| use Carbon\Carbon; |  | ||||||
| use Intervention\Image\Facades\Image; |  | ||||||
|  |  | ||||||
| class ExpensesController extends Controller |  | ||||||
| { |  | ||||||
|     /** |  | ||||||
|      * Display a listing of the resource. |  | ||||||
|      * |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function index(Request $request) |  | ||||||
|     { |  | ||||||
|         $limit = $request->has('limit') ? $request->limit : 10; |  | ||||||
|  |  | ||||||
|         $expenses = Expense::with('category') |  | ||||||
|             ->join('expense_categories', 'expense_categories.id', '=', 'expenses.expense_category_id') |  | ||||||
|             ->applyFilters($request->only([ |  | ||||||
|                 'expense_category_id', |  | ||||||
|                 'search', |  | ||||||
|                 'from_date', |  | ||||||
|                 'to_date', |  | ||||||
|                 'orderByField', |  | ||||||
|                 'orderBy' |  | ||||||
|             ])) |  | ||||||
|             ->whereCompany($request->header('company')) |  | ||||||
|             ->select('expenses.*', 'expense_categories.name') |  | ||||||
|             ->paginate($limit); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'expenses' => $expenses, |  | ||||||
|             'currency' => Currency::findOrFail( |  | ||||||
|                 CompanySetting::getSetting('currency', $request->header('company')) |  | ||||||
|             ) |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Show the form for creating a new resource. |  | ||||||
|      * |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function create(Request $request) |  | ||||||
|     { |  | ||||||
|         $categories = ExpenseCategory::whereCompany($request->header('company'))->get(); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'categories' => $categories |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Store a newly created resource in storage. |  | ||||||
|      * |  | ||||||
|      * @param  \Illuminate\Http\Request $request |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function store(ExpenseRequest $request) |  | ||||||
|     { |  | ||||||
|         $expense_date = Carbon::createFromFormat('d/m/Y', $request->expense_date); |  | ||||||
|  |  | ||||||
|         $expense = new Expense(); |  | ||||||
|         $expense->notes = $request->notes; |  | ||||||
|         $expense->expense_category_id = $request->expense_category_id; |  | ||||||
|         $expense->amount = $request->amount; |  | ||||||
|         $expense->company_id = $request->header('company'); |  | ||||||
|         $expense->expense_date = $expense_date; |  | ||||||
|         $expense->save(); |  | ||||||
|  |  | ||||||
|         if ($request->hasFile('attachment_receipt')) { |  | ||||||
|             $expense->addMediaFromRequest('attachment_receipt')->toMediaCollection('receipts', 'local'); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'expense' => $expense, |  | ||||||
|             'success' => true |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Display the specified resource. |  | ||||||
|      * |  | ||||||
|      * @param  \Crater\Expense $expense |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function show(Expense $expense) |  | ||||||
|     { |  | ||||||
|         // |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Show the form for editing the specified resource. |  | ||||||
|      * |  | ||||||
|      * @param  $id |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function edit(Request $request,$id) |  | ||||||
|     { |  | ||||||
|         $categories = ExpenseCategory::whereCompany($request->header('company'))->get(); |  | ||||||
|         $customers = User::where('role', 'customer')->whereCompany($request->header('company'))->get(); |  | ||||||
|         $expense = Expense::with('category')->where('id', $id)->first(); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'categories' => $categories, |  | ||||||
|             'customers' => $customers, |  | ||||||
|             'expense' => $expense |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Update the specified resource in storage. |  | ||||||
|      * |  | ||||||
|      * @param  \Illuminate\Http\Request $request |  | ||||||
|      * @param  \Crater\Expense $expense |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function update(ExpenseRequest $request, Expense $expense) |  | ||||||
|     { |  | ||||||
|         $expense_date = Carbon::createFromFormat('d/m/Y', $request->expense_date); |  | ||||||
|  |  | ||||||
|         $expense = Expense::findOrFail($expense->id); |  | ||||||
|         $expense->notes = $request->notes; |  | ||||||
|         $expense->expense_category_id = $request->expense_category_id; |  | ||||||
|         $expense->amount = $request->amount; |  | ||||||
|         $expense->expense_date = $expense_date; |  | ||||||
|         $expense->save(); |  | ||||||
|  |  | ||||||
|         if ($request->hasFile('attachment_receipt')) { |  | ||||||
|             $expense->clearMediaCollection('receipts'); |  | ||||||
|             $expense->addMediaFromRequest('attachment_receipt')->toMediaCollection('receipts', 'local'); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'expense' => $expense, |  | ||||||
|             'success' => true |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Remove the specified resource from storage. |  | ||||||
|      * |  | ||||||
|      * @param  \Crater\Expense $expense |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function destroy(Expense $expense) |  | ||||||
|     { |  | ||||||
|         $expense->delete(); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'success' => true |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function delete(Request $request) |  | ||||||
|     { |  | ||||||
|         Expense::destroy($request->id); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'success' => true |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Upload the expense receipts to storage. |  | ||||||
|      * |  | ||||||
|      * @param  \Illuminate\Http\Request $request |  | ||||||
|      * @param   $id |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function uploadReceipts(Request $request, $id) |  | ||||||
|     { |  | ||||||
|         $data = json_decode($request->attachment_receipt); |  | ||||||
|  |  | ||||||
|         if($data) { |  | ||||||
|             $expense = Expense::find($id); |  | ||||||
|  |  | ||||||
|             if($expense) { |  | ||||||
|                 if($request->type === 'edit') { |  | ||||||
|                     $expense->clearMediaCollection('receipts'); |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 $expense->addMediaFromBase64($data->data) |  | ||||||
|                     ->usingFileName($data->name) |  | ||||||
|                     ->toMediaCollection('receipts', 'local'); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'success' => 'Expense receipts uploaded successfully' |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function showReceipt($id) |  | ||||||
|     { |  | ||||||
|         $expense = Expense::find($id); |  | ||||||
|         $imagePath  = null; |  | ||||||
|  |  | ||||||
|         if($expense) { |  | ||||||
|             $media = $expense->getFirstMedia('receipts'); |  | ||||||
|             if($media) { |  | ||||||
|                 $imagePath = $media->getPath(); |  | ||||||
|             } else { |  | ||||||
|                 return response()->json([ |  | ||||||
|                     'error' => 'receipt_does_not_exist' |  | ||||||
|                 ]); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         $type = \File::mimeType($imagePath); |  | ||||||
|  |  | ||||||
|         $image = 'data:'.$type.';base64,'.base64_encode(file_get_contents($imagePath)); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'image' => $image, |  | ||||||
|             'type' => $type |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function downloadReceipt($id, $hash) |  | ||||||
|     { |  | ||||||
|         $company = Company::where('unique_hash', $hash)->first(); |  | ||||||
|  |  | ||||||
|         $expense = Expense::whereCompany($company->id) |  | ||||||
|             ->where('id', $id) |  | ||||||
|             ->first(); |  | ||||||
|         $imagePath  = null; |  | ||||||
|  |  | ||||||
|         if($expense) { |  | ||||||
|             $media = $expense->getFirstMedia('receipts'); |  | ||||||
|             if($media) { |  | ||||||
|                 $imagePath = $media->getPath(); |  | ||||||
|                 $filename = $media->getPath(); |  | ||||||
|                 $type = \File::mimeType($imagePath); |  | ||||||
|  |  | ||||||
|                 $headers = array( |  | ||||||
|                     'Content-Type' => $type, |  | ||||||
|                 ); |  | ||||||
|  |  | ||||||
|                 $response = \Response::download($imagePath, $media->file_name); |  | ||||||
|                 ob_end_clean(); |  | ||||||
|                 return $response; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'error' => 'receipt_not_found' |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| @ -1,374 +0,0 @@ | |||||||
| <?php |  | ||||||
| namespace Crater\Http\Controllers; |  | ||||||
|  |  | ||||||
| use Illuminate\Http\Request; |  | ||||||
| use Crater\Invoice; |  | ||||||
| use PDF; |  | ||||||
| use Crater\CompanySetting; |  | ||||||
| use Crater\Estimate; |  | ||||||
| use Crater\User; |  | ||||||
| use Crater\Company; |  | ||||||
| use Crater\InvoiceTemplate; |  | ||||||
| use Crater\EstimateTemplate; |  | ||||||
| use Crater\Mail\EstimateViewed; |  | ||||||
| use Crater\Mail\InvoiceViewed; |  | ||||||
|  |  | ||||||
| class FrontendController extends Controller |  | ||||||
| { |  | ||||||
|     public function home() |  | ||||||
|     { |  | ||||||
|         return view('front.index'); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function getCustomerEstimatePdf($id) |  | ||||||
|     { |  | ||||||
|         $estimate = Estimate::with( |  | ||||||
|                 'user', |  | ||||||
|                 'items', |  | ||||||
|                 'user.billingAddress', |  | ||||||
|                 'user.shippingAddress' |  | ||||||
|             ) |  | ||||||
|             ->where('unique_hash', $id) |  | ||||||
|             ->first(); |  | ||||||
|  |  | ||||||
|         $taxTypes = []; |  | ||||||
|         $taxes = []; |  | ||||||
|         $labels = []; |  | ||||||
|  |  | ||||||
|         if ($estimate->tax_per_item === 'YES') { |  | ||||||
|             foreach ($estimate->items as $item) { |  | ||||||
|                 foreach ($item->taxes as $tax) { |  | ||||||
|                     if (!in_array($tax->name, $taxTypes)) { |  | ||||||
|                         array_push($taxTypes, $tax->name); |  | ||||||
|                         array_push($labels, $tax->name.' ('.$tax->percent.'%)'); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             foreach ($taxTypes as $taxType) { |  | ||||||
|                 $total = 0; |  | ||||||
|  |  | ||||||
|                 foreach ($estimate->items as $item) { |  | ||||||
|                     foreach ($item->taxes as $tax) { |  | ||||||
|                         if($tax->name == $taxType) { |  | ||||||
|                             $total += $tax->amount; |  | ||||||
|                         } |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 array_push($taxes, $total); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         $estimateTemplate = EstimateTemplate::find($estimate->estimate_template_id); |  | ||||||
|  |  | ||||||
|         $company = Company::find($estimate->company_id); |  | ||||||
|  |  | ||||||
|         $logo = $company->getMedia('logo')->first(); |  | ||||||
|  |  | ||||||
|         if($logo) { |  | ||||||
|             $logo = $logo->getFullUrl(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if ($estimate && ($estimate->status == Estimate::STATUS_SENT || $estimate->status == Estimate::STATUS_DRAFT)) { |  | ||||||
|             $estimate->status = Estimate::STATUS_VIEWED; |  | ||||||
|             $estimate->save(); |  | ||||||
|             $notifyEstimateViewed = CompanySetting::getSetting( |  | ||||||
|                 'notify_estimate_viewed', |  | ||||||
|                 $estimate->company_id |  | ||||||
|             ); |  | ||||||
|  |  | ||||||
|             if ($notifyEstimateViewed == 'YES') { |  | ||||||
|                 $data['estimate'] = Estimate::findOrFail($estimate->id)->toArray(); |  | ||||||
|                 $data['user'] = User::find($estimate->user_id)->toArray(); |  | ||||||
|                 $notificationEmail = CompanySetting::getSetting( |  | ||||||
|                     'notification_email', |  | ||||||
|                     $estimate->company_id |  | ||||||
|                 ); |  | ||||||
|  |  | ||||||
|                 \Mail::to($notificationEmail)->send(new EstimateViewed($data)); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         $companyAddress = User::with(['addresses', 'addresses.country', 'addresses.state', 'addresses.city'])->find(1); |  | ||||||
|  |  | ||||||
|         $colors = [ |  | ||||||
|             'invoice_primary_color', |  | ||||||
|             'invoice_column_heading', |  | ||||||
|             'invoice_field_label', |  | ||||||
|             'invoice_field_value', |  | ||||||
|             'invoice_body_text', |  | ||||||
|             'invoice_description_text', |  | ||||||
|             'invoice_border_color' |  | ||||||
|         ]; |  | ||||||
|         $colorSettings = CompanySetting::whereIn('option', $colors) |  | ||||||
|             ->whereCompany($estimate->company_id) |  | ||||||
|             ->get(); |  | ||||||
|  |  | ||||||
|         view()->share([ |  | ||||||
|             'estimate' => $estimate, |  | ||||||
|             'logo' => $logo ?? null, |  | ||||||
|             'company_address' => $companyAddress, |  | ||||||
|             'colors' => $colorSettings, |  | ||||||
|             'labels' => $labels, |  | ||||||
|             'taxes' => $taxes |  | ||||||
|         ]); |  | ||||||
|         $pdf = PDF::loadView('app.pdf.estimate.'.$estimateTemplate->view); |  | ||||||
|  |  | ||||||
|         return $pdf->stream(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function getCustomerInvoicePdf($id) |  | ||||||
|     { |  | ||||||
|         $invoice = Invoice::with([ |  | ||||||
|                 'items', |  | ||||||
|                 'items.taxes', |  | ||||||
|                 'user', |  | ||||||
|                 'invoiceTemplate', |  | ||||||
|                 'taxes' |  | ||||||
|             ]) |  | ||||||
|             ->where('unique_hash', $id) |  | ||||||
|             ->first(); |  | ||||||
|  |  | ||||||
|         $taxTypes = []; |  | ||||||
|         $taxes = []; |  | ||||||
|         $labels = []; |  | ||||||
|  |  | ||||||
|         if ($invoice->tax_per_item === 'YES') { |  | ||||||
|             foreach ($invoice->items as $item) { |  | ||||||
|                 foreach ($item->taxes as $tax) { |  | ||||||
|                     if (!in_array($tax->name, $labels)) { |  | ||||||
|                         array_push($taxTypes, $tax->name); |  | ||||||
|                         array_push($labels, $tax->name.' ('.$tax->percent.'%)'); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             foreach ($taxTypes as $taxType) { |  | ||||||
|                 $total = 0; |  | ||||||
|  |  | ||||||
|                 foreach ($invoice->items as $item) { |  | ||||||
|                     foreach ($item->taxes as $tax) { |  | ||||||
|                         if($tax->name == $taxType) { |  | ||||||
|                             $total += $tax->amount; |  | ||||||
|                         } |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 array_push($taxes, $total); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         $invoiceTemplate = InvoiceTemplate::find($invoice->invoice_template_id); |  | ||||||
|  |  | ||||||
|         $company = Company::find($invoice->company_id); |  | ||||||
|         $logo = $company->getMedia('logo')->first(); |  | ||||||
|  |  | ||||||
|         if($logo) { |  | ||||||
|             $logo = $logo->getFullUrl(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if ($invoice && ($invoice->status == Invoice::STATUS_SENT || $invoice->status == Invoice::STATUS_DRAFT)) { |  | ||||||
|             $invoice->status = Invoice::STATUS_VIEWED; |  | ||||||
|             $invoice->viewed = true; |  | ||||||
|             $invoice->save(); |  | ||||||
|             $notifyInvoiceViewed = CompanySetting::getSetting( |  | ||||||
|                 'notify_invoice_viewed', |  | ||||||
|                 $invoice->company_id |  | ||||||
|             ); |  | ||||||
|  |  | ||||||
|             if ($notifyInvoiceViewed == 'YES') { |  | ||||||
|                 $data['invoice'] = Invoice::findOrFail($invoice->id)->toArray(); |  | ||||||
|                 $data['user'] = User::find($invoice->user_id)->toArray(); |  | ||||||
|                 $notificationEmail = CompanySetting::getSetting( |  | ||||||
|                     'notification_email', |  | ||||||
|                     $invoice->company_id |  | ||||||
|                 ); |  | ||||||
|  |  | ||||||
|                 \Mail::to($notificationEmail)->send(new InvoiceViewed($data)); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         $companyAddress = User::with(['addresses', 'addresses.country', 'addresses.state', 'addresses.city'])->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', 'addresses.state', 'addresses.city'])->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', 'addresses.state', 'addresses.city'])->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(); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,448 +0,0 @@ | |||||||
| <?php |  | ||||||
| namespace Crater\Http\Controllers; |  | ||||||
|  |  | ||||||
| use Illuminate\Http\Request; |  | ||||||
| use Crater\CompanySetting; |  | ||||||
| use Crater\Company; |  | ||||||
| use Illuminate\Support\Collection; |  | ||||||
| use Crater\Currency; |  | ||||||
| use Crater\InvoiceTemplate; |  | ||||||
| use Crater\Http\Requests; |  | ||||||
| use Crater\Invoice; |  | ||||||
| use Crater\InvoiceItem; |  | ||||||
| use Carbon\Carbon; |  | ||||||
| use Crater\Item; |  | ||||||
| use Crater\Mail\invoicePdf; |  | ||||||
| use function MongoDB\BSON\toJSON; |  | ||||||
| use Illuminate\Support\Facades\Log; |  | ||||||
| use Crater\User; |  | ||||||
| use Mailgun\Mailgun; |  | ||||||
| use PDF; |  | ||||||
| use Validator; |  | ||||||
| use Crater\TaxType; |  | ||||||
| use Crater\Tax; |  | ||||||
|  |  | ||||||
| class InvoicesController extends Controller |  | ||||||
| { |  | ||||||
|     /** |  | ||||||
|      * Display a listing of the resource. |  | ||||||
|      * |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function index(Request $request) |  | ||||||
|     { |  | ||||||
|         $limit = $request->has('limit') ? $request->limit : 10; |  | ||||||
|  |  | ||||||
|         $invoices = Invoice::with(['items', 'user', 'invoiceTemplate', 'taxes']) |  | ||||||
|             ->join('users', 'users.id', '=', 'invoices.user_id') |  | ||||||
|             ->applyFilters($request->only([ |  | ||||||
|                 'status', |  | ||||||
|                 'paid_status', |  | ||||||
|                 'customer_id', |  | ||||||
|                 'invoice_number', |  | ||||||
|                 'from_date', |  | ||||||
|                 'to_date', |  | ||||||
|                 'orderByField', |  | ||||||
|                 'orderBy', |  | ||||||
|                 'search', |  | ||||||
|             ])) |  | ||||||
|             ->whereCompany($request->header('company')) |  | ||||||
|             ->select('invoices.*', 'users.name') |  | ||||||
|             ->latest() |  | ||||||
|             ->paginate($limit); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'invoices' => $invoices, |  | ||||||
|             'invoiceTotalCount' => Invoice::count() |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Show the form for creating a new resource. |  | ||||||
|      * |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function create(Request $request) |  | ||||||
|     { |  | ||||||
|         $tax_per_item = CompanySetting::getSetting('tax_per_item', $request->header('company')); |  | ||||||
|         $discount_per_item = CompanySetting::getSetting('discount_per_item', $request->header('company')); |  | ||||||
|         $nextInvoiceNumber = "INV-".Invoice::getNextInvoiceNumber(); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'nextInvoiceNumber' => $nextInvoiceNumber, |  | ||||||
|             'items' => Item::with('taxes')->whereCompany($request->header('company'))->get(), |  | ||||||
|             'invoiceTemplates' => InvoiceTemplate::all(), |  | ||||||
|             'tax_per_item' => $tax_per_item, |  | ||||||
|             'discount_per_item' => $discount_per_item |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Store a newly created resource in storage. |  | ||||||
|      * |  | ||||||
|      * @param  \Illuminate\Http\Request $request |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function store(Requests\InvoicesRequest $request) |  | ||||||
|     { |  | ||||||
|         $invoice_date = Carbon::createFromFormat('d/m/Y', $request->invoice_date); |  | ||||||
|         $due_date = Carbon::createFromFormat('d/m/Y', $request->due_date); |  | ||||||
|         $status = Invoice::STATUS_DRAFT; |  | ||||||
|  |  | ||||||
|         $tax_per_item = CompanySetting::getSetting('tax_per_item', $request->header('company')) ?? 'NO'; |  | ||||||
|         $discount_per_item = CompanySetting::getSetting('discount_per_item', $request->header('company')) ?? 'NO'; |  | ||||||
|  |  | ||||||
|         if ($request->has('invoiceSend')) { |  | ||||||
|             $status = Invoice::STATUS_SENT; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         $invoice = Invoice::create([ |  | ||||||
|             'invoice_date' => $invoice_date, |  | ||||||
|             'due_date' => $due_date, |  | ||||||
|             'invoice_number' => $request->invoice_number, |  | ||||||
|             'reference_number' => $request->reference_number, |  | ||||||
|             'user_id' => $request->user_id, |  | ||||||
|             'company_id' => $request->header('company'), |  | ||||||
|             'invoice_template_id' => $request->invoice_template_id, |  | ||||||
|             'status' => $status, |  | ||||||
|             'paid_status' => Invoice::STATUS_UNPAID, |  | ||||||
|             'sub_total' => $request->sub_total, |  | ||||||
|             'discount' => $request->discount, |  | ||||||
|             'discount_type' => $request->discount_type, |  | ||||||
|             'discount_val' => $request->discount_val, |  | ||||||
|             'total' => $request->total, |  | ||||||
|             'due_amount' => $request->total, |  | ||||||
|             'tax_per_item' => $tax_per_item, |  | ||||||
|             'discount_per_item' => $discount_per_item, |  | ||||||
|             'tax' => $request->tax, |  | ||||||
|             'notes' => $request->notes, |  | ||||||
|             'unique_hash' => str_random(60) |  | ||||||
|         ]); |  | ||||||
|  |  | ||||||
|         $invoiceItems = $request->items; |  | ||||||
|  |  | ||||||
|         foreach ($invoiceItems as $invoiceItem) { |  | ||||||
|             $invoiceItem['company_id'] = $request->header('company'); |  | ||||||
|             $item = $invoice->items()->create($invoiceItem); |  | ||||||
|  |  | ||||||
|             if (array_key_exists('taxes', $invoiceItem) && $invoiceItem['taxes']) { |  | ||||||
|                 foreach ($invoiceItem['taxes'] as $tax) { |  | ||||||
|                     $tax['company_id'] = $request->header('company'); |  | ||||||
|  |  | ||||||
|                     if ($tax['amount']) { |  | ||||||
|                         $item->taxes()->create($tax); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if ($request->has('taxes')) { |  | ||||||
|             foreach ($request->taxes as $tax) { |  | ||||||
|                 $tax['company_id'] = $request->header('company'); |  | ||||||
|  |  | ||||||
|                 if ($tax['amount']) { |  | ||||||
|                     $invoice->taxes()->create($tax); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if ($request->has('invoiceSend')) { |  | ||||||
|             $data['invoice'] = Invoice::findOrFail($invoice->id)->toArray(); |  | ||||||
|             $data['user'] = User::find($request->user_id)->toArray(); |  | ||||||
|             $data['company'] = Company::find($invoice->company_id); |  | ||||||
|  |  | ||||||
|             $notificationEmail = CompanySetting::getSetting( |  | ||||||
|                 'notification_email', |  | ||||||
|                 $request->header('company') |  | ||||||
|             ); |  | ||||||
|  |  | ||||||
|             $email = $data['user']['email']; |  | ||||||
|  |  | ||||||
|             if (!$email) { |  | ||||||
|                 return response()->json([ |  | ||||||
|                     'error' => 'user_email_does_not_exist' |  | ||||||
|                 ]); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             if (!$notificationEmail) { |  | ||||||
|                 return response()->json([ |  | ||||||
|                     'error' => 'notification_email_does_not_exist' |  | ||||||
|                 ]); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             \Mail::to($email)->send(new invoicePdf($data, $notificationEmail)); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         $invoice = Invoice::with(['items', 'user', 'invoiceTemplate', 'taxes'])->find($invoice->id); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'url' => url('/invoices/pdf/'.$invoice->unique_hash), |  | ||||||
|             'invoice' => $invoice |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Display the specified resource. |  | ||||||
|      * |  | ||||||
|      * @param  int $id |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function show(Request $request, $id) |  | ||||||
|     { |  | ||||||
|         $invoice = Invoice::with([ |  | ||||||
|             'items', |  | ||||||
|             'items.taxes', |  | ||||||
|             'user', |  | ||||||
|             'invoiceTemplate', |  | ||||||
|             'taxes.taxType' |  | ||||||
|         ])->find($id); |  | ||||||
|  |  | ||||||
|         $siteData = [ |  | ||||||
|             'invoice' => $invoice, |  | ||||||
|             'shareable_link' => url('/invoices/pdf/' . $invoice->unique_hash) |  | ||||||
|         ]; |  | ||||||
|  |  | ||||||
|         return response()->json($siteData); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Show the form for editing the specified resource. |  | ||||||
|      * |  | ||||||
|      * @param  int $id |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function edit(Request $request,$id) |  | ||||||
|     { |  | ||||||
|         $invoice = Invoice::with([ |  | ||||||
|             'items', |  | ||||||
|             'items.taxes', |  | ||||||
|             'user', |  | ||||||
|             'invoiceTemplate', |  | ||||||
|             'taxes.taxType' |  | ||||||
|         ])->find($id); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'nextInvoiceNumber' => $invoice->invoice_number, |  | ||||||
|             'invoice' => $invoice, |  | ||||||
|             'invoiceTemplates' => InvoiceTemplate::all(), |  | ||||||
|             'tax_per_item' => $invoice->tax_per_item, |  | ||||||
|             'discount_per_item' => $invoice->discount_per_item, |  | ||||||
|             'shareable_link' => url('/invoices/pdf/'.$invoice->unique_hash) |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Update the specified resource in storage. |  | ||||||
|      * |  | ||||||
|      * @param  \Illuminate\Http\Request $request |  | ||||||
|      * @param  int $id |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function update(Requests\InvoicesRequest $request, $id) |  | ||||||
|     { |  | ||||||
|         $invoice_date = Carbon::createFromFormat('d/m/Y', $request->invoice_date); |  | ||||||
|         $due_date = Carbon::createFromFormat('d/m/Y', $request->due_date); |  | ||||||
|  |  | ||||||
|         $invoice = Invoice::find($id); |  | ||||||
|         $oldAmount = $invoice->total; |  | ||||||
|  |  | ||||||
|         if ($oldAmount != $request->total) { |  | ||||||
|             $oldAmount = (int)round($request->total) - (int)$oldAmount; |  | ||||||
|         } else { |  | ||||||
|             $oldAmount = 0; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         $invoice->due_amount = ($invoice->due_amount + $oldAmount); |  | ||||||
|  |  | ||||||
|         if ($invoice->due_amount == 0 && $invoice->paid_status != Invoice::STATUS_PAID) { |  | ||||||
|             $invoice->status = Invoice::STATUS_COMPLETED; |  | ||||||
|             $invoice->paid_status = Invoice::STATUS_PAID; |  | ||||||
|         } elseif ($invoice->due_amount < 0 && $invoice->paid_status != Invoice::STATUS_UNPAID) { |  | ||||||
|             return response()->json([ |  | ||||||
|                 'error' => 'invalid_due_amount' |  | ||||||
|             ]); |  | ||||||
|         } elseif ($invoice->due_amount != 0 && $invoice->paid_status == Invoice::STATUS_PAID) { |  | ||||||
|             $invoice->status = $invoice->getPreviousStatus(); |  | ||||||
|             $invoice->paid_status = Invoice::STATUS_PARTIALLY_PAID; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         $invoice->invoice_date = $invoice_date; |  | ||||||
|         $invoice->due_date = $due_date; |  | ||||||
|         $invoice->invoice_number = $request->invoice_number; |  | ||||||
|         $invoice->reference_number = $request->reference_number; |  | ||||||
|         $invoice->user_id = $request->user_id; |  | ||||||
|         $invoice->invoice_template_id = $request->invoice_template_id; |  | ||||||
|         $invoice->sub_total = $request->sub_total; |  | ||||||
|         $invoice->total = $request->total; |  | ||||||
|         $invoice->discount = $request->discount; |  | ||||||
|         $invoice->discount_type = $request->discount_type; |  | ||||||
|         $invoice->discount_val = $request->discount_val; |  | ||||||
|         $invoice->tax = $request->tax; |  | ||||||
|         $invoice->notes = $request->notes; |  | ||||||
|         $invoice->save(); |  | ||||||
|  |  | ||||||
|         $oldItems = $invoice->items->toArray(); |  | ||||||
|         $oldTaxes = $invoice->taxes->toArray(); |  | ||||||
|         $invoiceItems = $request->items; |  | ||||||
|  |  | ||||||
|         foreach ($oldItems as $oldItem) { |  | ||||||
|             InvoiceItem::destroy($oldItem['id']); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         foreach ($oldTaxes as $oldTax) { |  | ||||||
|             Tax::destroy($oldTax['id']); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         foreach ($invoiceItems as $invoiceItem) { |  | ||||||
|             $invoiceItem['company_id'] = $request->header('company'); |  | ||||||
|             $item = $invoice->items()->create($invoiceItem); |  | ||||||
|  |  | ||||||
|             if (array_key_exists('taxes', $invoiceItem) && $invoiceItem['taxes']) { |  | ||||||
|                 foreach ($invoiceItem['taxes'] as $tax) { |  | ||||||
|                     $tax['company_id'] = $request->header('company'); |  | ||||||
|  |  | ||||||
|                     if ($tax['amount']) { |  | ||||||
|                         $item->taxes()->create($tax); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if ($request->has('taxes')) { |  | ||||||
|             foreach ($request->taxes as $tax) { |  | ||||||
|                 $tax['company_id'] = $request->header('company'); |  | ||||||
|  |  | ||||||
|                 if ($tax['amount']) { |  | ||||||
|                     $invoice->taxes()->create($tax); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         $invoice = Invoice::with(['items', 'user', 'invoiceTemplate', 'taxes'])->find($invoice->id); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'url' => url('/invoices/pdf/' . $invoice->unique_hash), |  | ||||||
|             'invoice' => $invoice, |  | ||||||
|             'success' => true |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Remove the specified resource from storage. |  | ||||||
|      * |  | ||||||
|      * @param  int $id |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function destroy($id) |  | ||||||
|     { |  | ||||||
|         $invoice = Invoice::find($id); |  | ||||||
|  |  | ||||||
|         if ($invoice->payments()->exists() && $invoice->payments()->count() > 0) { |  | ||||||
|             return response()->json([ |  | ||||||
|                 'error' => 'payment_attached' |  | ||||||
|             ]); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         $invoice = Invoice::destroy($id); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'success' => true |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function delete(Request $request) |  | ||||||
|     { |  | ||||||
|         foreach ($request->id as $id) { |  | ||||||
|             $invoice = Invoice::find($id); |  | ||||||
|  |  | ||||||
|             if ($invoice->payments()->exists() && $invoice->payments()->count() > 0) { |  | ||||||
|                 return response()->json([ |  | ||||||
|                     'error' => 'payment_attached' |  | ||||||
|                 ]); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         $invoice = Invoice::destroy($request->id); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'success' => true |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function sendInvoice(Request $request) |  | ||||||
|     { |  | ||||||
|         $invoice = Invoice::findOrFail($request->id); |  | ||||||
|  |  | ||||||
|         $data['invoice'] = $invoice->toArray(); |  | ||||||
|         $userId = $data['invoice']['user_id']; |  | ||||||
|         $data['user'] = User::find($userId)->toArray(); |  | ||||||
|         $data['company'] = Company::find($invoice->company_id); |  | ||||||
|         $email = $data['user']['email']; |  | ||||||
|         $notificationEmail = CompanySetting::getSetting( |  | ||||||
|             'notification_email', |  | ||||||
|             $request->header('company') |  | ||||||
|         ); |  | ||||||
|  |  | ||||||
|         if (!$email) { |  | ||||||
|             return response()->json([ |  | ||||||
|                 'error' => 'user_email_does_not_exist' |  | ||||||
|             ]); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (!$notificationEmail) { |  | ||||||
|             return response()->json([ |  | ||||||
|                 'error' => 'notification_email_does_not_exist' |  | ||||||
|             ]); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         \Mail::to($email)->send(new invoicePdf($data, $notificationEmail)); |  | ||||||
|  |  | ||||||
|         if ($invoice->status == Invoice::STATUS_DRAFT) { |  | ||||||
|             $invoice->status = Invoice::STATUS_SENT; |  | ||||||
|             $invoice->sent = true; |  | ||||||
|             $invoice->save(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'success' => true |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function markAsSent(Request $request) |  | ||||||
|     { |  | ||||||
|         $invoice = Invoice::findOrFail($request->id); |  | ||||||
|         $invoice->status = Invoice::STATUS_SENT; |  | ||||||
|         $invoice->sent = true; |  | ||||||
|         $invoice->save(); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'success' => true |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function markAsPaid(Request $request) |  | ||||||
|     { |  | ||||||
|         $invoice = Invoice::findOrFail($request->id); |  | ||||||
|         $invoice->status = Invoice::STATUS_COMPLETED; |  | ||||||
|         $invoice->paid_status = Invoice::STATUS_PAID; |  | ||||||
|         $invoice->due_amount = 0; |  | ||||||
|         $invoice->save(); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'success' => true |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function getCustomersUnpaidInvoices(Request $request, $id) |  | ||||||
|     { |  | ||||||
|         $invoices = Invoice::where('paid_status', '<>', Invoice::STATUS_PAID) |  | ||||||
|             ->where('user_id', $id)->where('due_amount', '>', 0) |  | ||||||
|             ->whereCompany($request->header('company')) |  | ||||||
|             ->get(); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'invoices' => $invoices |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,134 +0,0 @@ | |||||||
| <?php |  | ||||||
| namespace Crater\Http\Controllers; |  | ||||||
|  |  | ||||||
| use Illuminate\Http\Request; |  | ||||||
| use Crater\Http\Requests; |  | ||||||
| use Crater\Item; |  | ||||||
| use Crater\TaxType; |  | ||||||
| use Crater\Tax; |  | ||||||
| use Crater\User; |  | ||||||
|  |  | ||||||
| class ItemsController extends Controller |  | ||||||
| { |  | ||||||
|     public function index(Request $request) |  | ||||||
|     { |  | ||||||
|         $limit = $request->has('limit') ? $request->limit : 10; |  | ||||||
|  |  | ||||||
|         $items = Item::applyFilters($request->only([ |  | ||||||
|                 'search', |  | ||||||
|                 'price', |  | ||||||
|                 'unit', |  | ||||||
|                 'orderByField', |  | ||||||
|                 'orderBy' |  | ||||||
|             ])) |  | ||||||
|             ->whereCompany($request->header('company')) |  | ||||||
|             ->latest() |  | ||||||
|             ->paginate($limit); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'items' => $items, |  | ||||||
|             'taxTypes' => TaxType::latest()->get() |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function edit(Request $request, $id) |  | ||||||
|     { |  | ||||||
|         $item = Item::with('taxes')->find($id); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'item' => $item, |  | ||||||
|             'taxes' => Tax::whereCompany($request->header('company')) |  | ||||||
|                 ->latest() |  | ||||||
|                 ->get() |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function store(Requests\ItemsRequest $request) |  | ||||||
|     { |  | ||||||
|         $item = new Item(); |  | ||||||
|         $item->name = $request->name; |  | ||||||
|         $item->unit = $request->unit; |  | ||||||
|         $item->description = $request->description; |  | ||||||
|         $item->company_id = $request->header('company'); |  | ||||||
|         $item->price = $request->price; |  | ||||||
|         $item->save(); |  | ||||||
|  |  | ||||||
|         if ($request->has('taxes')) { |  | ||||||
|             foreach ($request->taxes as $tax) { |  | ||||||
|                 $tax['company_id'] = $request->header('company'); |  | ||||||
|                 $item->taxes()->create($tax); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         $item = Item::with('taxes')->find($item->id); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'item' => $item |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function update(Requests\ItemsRequest $request, $id) |  | ||||||
|     { |  | ||||||
|         $item = Item::find($id); |  | ||||||
|         $item->name = $request->name; |  | ||||||
|         $item->unit = $request->unit; |  | ||||||
|         $item->description = $request->description; |  | ||||||
|         $item->price = $request->price; |  | ||||||
|         $item->save(); |  | ||||||
|  |  | ||||||
|         $oldTaxes = $item->taxes->toArray(); |  | ||||||
|  |  | ||||||
|         foreach ($oldTaxes as $oldTax) { |  | ||||||
|             Tax::destroy($oldTax['id']); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if ($request->has('taxes')) { |  | ||||||
|             foreach ($request->taxes as $tax) { |  | ||||||
|                 $tax['company_id'] = $request->header('company'); |  | ||||||
|                 $item->taxes()->create($tax); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         $item = Item::with('taxes')->find($item->id); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'item' => $item |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function destroy($id) |  | ||||||
|     { |  | ||||||
|         $data = Item::deleteItem($id); |  | ||||||
|  |  | ||||||
|         if (!$data) { |  | ||||||
|             return response()->json([ |  | ||||||
|                 'error' => 'item_attached' |  | ||||||
|             ]); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'success' => $data |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function delete(Request $request) |  | ||||||
|     { |  | ||||||
|         $items = []; |  | ||||||
|         foreach ($request->id as $id) { |  | ||||||
|             $item = Item::deleteItem($id); |  | ||||||
|             if (!$item) { |  | ||||||
|                 array_push($items, $id); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (empty($items)) { |  | ||||||
|             return response()->json([ |  | ||||||
|                 'success' => true |  | ||||||
|             ]); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'items' => $items |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,31 +0,0 @@ | |||||||
| <?php |  | ||||||
| namespace Crater\Http\Controllers; |  | ||||||
|  |  | ||||||
| use Illuminate\Http\Request; |  | ||||||
| use Crater\Country; |  | ||||||
| use Crater\State; |  | ||||||
| use Crater\City; |  | ||||||
|  |  | ||||||
| class LocationController extends Controller |  | ||||||
| { |  | ||||||
|     public function getCountries() |  | ||||||
|     { |  | ||||||
|         return response()->json([ |  | ||||||
|             'countries' => Country::all() |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function getStates($id) |  | ||||||
|     { |  | ||||||
|         return response()->json([ |  | ||||||
|             'states' => Country::find($id)->states |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function getCities($id) |  | ||||||
|     { |  | ||||||
|         return response()->json([ |  | ||||||
|             'cities' => State::find($id)->cities |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,251 +0,0 @@ | |||||||
| <?php |  | ||||||
| namespace Crater\Http\Controllers; |  | ||||||
|  |  | ||||||
| use Illuminate\Http\Request; |  | ||||||
| use Crater\User; |  | ||||||
| use Crater\Company; |  | ||||||
| use Crater\Address; |  | ||||||
| use Crater\Http\Requests\ProfileRequest; |  | ||||||
| use Crater\Http\Requests\CompanyRequest; |  | ||||||
| use Crater\Http\Requests\CompanySettingRequest; |  | ||||||
| use Crater\Space\DateFormatter; |  | ||||||
| use Crater\Space\TimeZones; |  | ||||||
| use Crater\Currency; |  | ||||||
| use Crater\Setting; |  | ||||||
| use Crater\CompanySetting; |  | ||||||
| use Illuminate\Support\Facades\DB; |  | ||||||
| use Illuminate\Support\Facades\Artisan; |  | ||||||
|  |  | ||||||
| class OnboardingController extends Controller |  | ||||||
| { |  | ||||||
|     public function getOnboardingData(Request $request) |  | ||||||
|     { |  | ||||||
|         if (!\Storage::disk('local')->has('database_created')) { |  | ||||||
|             return response()->json([ |  | ||||||
|                 'profile_complete' => '0' |  | ||||||
|             ]); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         $setting = Setting::getSetting('profile_complete'); |  | ||||||
|  |  | ||||||
|         if ($setting !== 'COMPLETED' && $setting < 4){ |  | ||||||
|             return response()->json([ |  | ||||||
|                 'profile_complete' => $setting |  | ||||||
|             ]); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         $date_formats = DateFormatter::get_list(); |  | ||||||
|         $time_zones = TimeZones::get_list(); |  | ||||||
|         $languages = [ |  | ||||||
|             ["code"=>"en", "name" => "English"], |  | ||||||
|             ["code"=>"fr", "name" => "French"], |  | ||||||
|             ["code"=>"es", "name" => "Spanish"] |  | ||||||
|         ]; |  | ||||||
|         $fiscal_years = [ |  | ||||||
|             ['key' => 'january-december' , 'value' => '1-12'], |  | ||||||
|             ['key' => 'february-january' , 'value' => '2-1'], |  | ||||||
|             ['key' => 'march-february'   , 'value' => '3-2'], |  | ||||||
|             ['key' => 'april-march'      , 'value' => '4-3'], |  | ||||||
|             ['key' => 'may-april'        , 'value' => '5-4'], |  | ||||||
|             ['key' => 'june-may'         , 'value' => '6-5'], |  | ||||||
|             ['key' => 'july-june'        , 'value' => '7-6'], |  | ||||||
|             ['key' => 'august-july'      , 'value' => '8-7'], |  | ||||||
|             ['key' => 'september-august' , 'value' => '9-8'], |  | ||||||
|             ['key' => 'october-september', 'value' => '10-9'], |  | ||||||
|             ['key' => 'november-october' , 'value' => '11-10'], |  | ||||||
|             ['key' => 'december-november', 'value' => '12-11'], |  | ||||||
|         ]; |  | ||||||
|         $user = User::with([ |  | ||||||
|             'addresses', |  | ||||||
|             'addresses.country', |  | ||||||
|             'addresses.state', |  | ||||||
|             'addresses.city', |  | ||||||
|             'company' |  | ||||||
|         ])->find(1); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'user' => $user, |  | ||||||
|             'profile_complete' => $setting, |  | ||||||
|             'languages' => $languages, |  | ||||||
|             'date_formats' => $date_formats, |  | ||||||
|             'time_zones' => $time_zones, |  | ||||||
|             'fiscal_years' => $fiscal_years, |  | ||||||
|             'currencies' => Currency::all() |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function adminProfile(ProfileRequest $request) |  | ||||||
|     { |  | ||||||
|         $setting = Setting::getSetting('profile_complete'); |  | ||||||
|  |  | ||||||
|         if ($setting == '1' || $setting == 'COMPLETED') { |  | ||||||
|             return response()->json(['error' => 'Profile already created.']); |  | ||||||
|         } else { |  | ||||||
|             Setting::setSetting('profile_complete', 5); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         $user = User::find(1); |  | ||||||
|         $user->name = $request->name; |  | ||||||
|         $user->email = $request->email; |  | ||||||
|  |  | ||||||
|         if ($request->has('password')) { |  | ||||||
|             $user->password = bcrypt($request->password); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         $user->save(); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'user' => $user |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function uploadAdminAvatar(Request $request) |  | ||||||
|     { |  | ||||||
|         $setting = Setting::getSetting('profile_complete'); |  | ||||||
|  |  | ||||||
|         if ($setting == '1' || $setting == 'COMPLETED') { |  | ||||||
|             return response()->json(['error' => 'Profile already created.']); |  | ||||||
|         } |  | ||||||
|         $data = json_decode($request->admin_avatar); |  | ||||||
|  |  | ||||||
|         if($data) { |  | ||||||
|             $user = User::find($data->id); |  | ||||||
|             if($user) { |  | ||||||
|                 $user->clearMediaCollection('admin_avatar'); |  | ||||||
|  |  | ||||||
|                 $user->addMediaFromBase64($data->data) |  | ||||||
|                     ->usingFileName($data->name) |  | ||||||
|                     ->toMediaCollection('admin_avatar'); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'user' => $user, |  | ||||||
|             'success' => true |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function adminCompany(CompanyRequest $request) |  | ||||||
|     { |  | ||||||
|         $setting = Setting::getSetting('profile_complete'); |  | ||||||
|  |  | ||||||
|         if ($setting == '6' || $setting == 'COMPLETED') { |  | ||||||
|             return response()->json(['error' => 'Company already created.']); |  | ||||||
|         } else { |  | ||||||
|             Setting::setSetting('profile_complete', 6); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         $user = User::find(1); |  | ||||||
|         $company = $user->company; |  | ||||||
|  |  | ||||||
|         if (!$company) { |  | ||||||
|             $company = new Company(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         $company->name = $request->name; |  | ||||||
|         $company->unique_hash = str_random(60); |  | ||||||
|         $company->save(); |  | ||||||
|         $user->company()->associate($company); |  | ||||||
|         $user->save(); |  | ||||||
|  |  | ||||||
|         if ($request->has('logo') && $request->logo !== null && $request->logo !== 'undefined' ) { |  | ||||||
|             $company->addMediaFromRequest('logo')->toMediaCollection('logo'); |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         $fields = $request->only([ |  | ||||||
|             'address_street_1', |  | ||||||
|             'address_street_2', |  | ||||||
|             'city_id', |  | ||||||
|             'state_id', |  | ||||||
|             'country_id', |  | ||||||
|             'zip', |  | ||||||
|             'phone' |  | ||||||
|         ]); |  | ||||||
|         $address = Address::updateOrCreate(['user_id' => 1], $fields); |  | ||||||
|         $user = User::with('addresses', 'company')->find(1); |  | ||||||
|  |  | ||||||
|         CompanySetting::setSetting( |  | ||||||
|             'notification_email', |  | ||||||
|             $user->email, |  | ||||||
|             $company->id |  | ||||||
|         ); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'user' => $user |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function companySettings(CompanySettingRequest $request) |  | ||||||
|     { |  | ||||||
|         $setting = Setting::getSetting('profile_complete'); |  | ||||||
|  |  | ||||||
|         if($setting == 'COMPLETED') { |  | ||||||
|             return response()->json(['error' => 'Settings already saved.']); |  | ||||||
|         } else { |  | ||||||
|             Setting::setSetting('profile_complete', 'COMPLETED'); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         $user = User::find(1); |  | ||||||
|  |  | ||||||
|         $sets = ['currency', |  | ||||||
|             'time_zone', |  | ||||||
|             'language', |  | ||||||
|             'carbon_date_format', |  | ||||||
|             'moment_date_format', |  | ||||||
|             'fiscal_year' |  | ||||||
|         ]; |  | ||||||
|  |  | ||||||
|         foreach ($sets as $key) { |  | ||||||
|             CompanySetting::setSetting( |  | ||||||
|                 $key, |  | ||||||
|                 $request->$key, |  | ||||||
|                 $user->company_id |  | ||||||
|             ); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         $colors = [ |  | ||||||
|             'primary_text_color' => '#5851D8', |  | ||||||
|             'heading_text_color' => '#595959', |  | ||||||
|             'section_heading_text_color' => '#040405', |  | ||||||
|             'border_color' => '#EAF1FB', |  | ||||||
|             'body_text_color' => '#595959', |  | ||||||
|             'footer_text_color' => '#595959', |  | ||||||
|             'footer_total_color' => '#5851D8', |  | ||||||
|             'footer_bg_color' => '#F9FBFF', |  | ||||||
|             'date_text_color' => '#A5ACC1', |  | ||||||
|             'invoice_primary_color' => '#5851D8', |  | ||||||
|             'invoice_column_heading' => '#55547A', |  | ||||||
|             'invoice_field_label' => '#55547A', |  | ||||||
|             'invoice_field_value' => '#040405', |  | ||||||
|             'invoice_body_text' => '#040405', |  | ||||||
|             'invoice_description_text' => '#595959', |  | ||||||
|             'invoice_border_color' => '#EAF1FB' |  | ||||||
|         ]; |  | ||||||
|         foreach ($colors as $key => $value) { |  | ||||||
|             CompanySetting::setSetting( |  | ||||||
|                 $key, |  | ||||||
|                 $value, |  | ||||||
|                 $user->company_id |  | ||||||
|             ); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         Setting::setSetting('version', config('crater.version')); |  | ||||||
|  |  | ||||||
|         Artisan::call('passport:install --force'); |  | ||||||
|  |  | ||||||
|         $client = DB::table('oauth_clients')->find(2); |  | ||||||
|  |  | ||||||
|         $path = base_path('.env'); |  | ||||||
|  |  | ||||||
|         if (file_exists($path)) { |  | ||||||
|             file_put_contents($path, str_replace( |  | ||||||
|                 'PROXY_OAUTH_CLIENT_SECRET='.config('auth.proxy.client_secret'), 'PROXY_OAUTH_CLIENT_SECRET='.$client->secret, file_get_contents($path) |  | ||||||
|             )); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         $data['token'] = $user->createToken('password')->accessToken; |  | ||||||
|  |  | ||||||
|         return response()->json($data); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,252 +0,0 @@ | |||||||
| <?php |  | ||||||
| namespace Crater\Http\Controllers; |  | ||||||
|  |  | ||||||
| use Illuminate\Http\Request; |  | ||||||
| use Crater\CompanySetting; |  | ||||||
| use Crater\Currency; |  | ||||||
| use Crater\Invoice; |  | ||||||
| use Crater\Payment; |  | ||||||
| use Carbon\Carbon; |  | ||||||
| use function MongoDB\BSON\toJSON; |  | ||||||
| use Crater\User; |  | ||||||
| use Crater\Http\Requests\PaymentRequest; |  | ||||||
|  |  | ||||||
| class PaymentController extends Controller |  | ||||||
| { |  | ||||||
|     /** |  | ||||||
|      * Display a listing of the resource. |  | ||||||
|      * |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function index(Request $request) |  | ||||||
|     { |  | ||||||
|         $limit = $request->has('limit') ? $request->limit : 10; |  | ||||||
|  |  | ||||||
|         $payments = Payment::with('user', 'invoice') |  | ||||||
|             ->join('users', 'users.id', '=', 'payments.user_id') |  | ||||||
|             ->leftJoin('invoices', 'invoices.id', '=', 'payments.invoice_id') |  | ||||||
|             ->applyFilters($request->only([ |  | ||||||
|                 'search', |  | ||||||
|                 'payment_number', |  | ||||||
|                 'payment_mode', |  | ||||||
|                 'customer_id', |  | ||||||
|                 'orderByField', |  | ||||||
|                 'orderBy' |  | ||||||
|             ])) |  | ||||||
|             ->whereCompany($request->header('company')) |  | ||||||
|             ->select('payments.*', 'users.name', 'invoices.invoice_number') |  | ||||||
|             ->latest() |  | ||||||
|             ->paginate($limit); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'payments' => $payments |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Show the form for creating a new resource. |  | ||||||
|      * |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function create(Request $request) |  | ||||||
|     { |  | ||||||
|         $nextPaymentNumber = 'PAY-'.Payment::getNextPaymentNumber(); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'customers' => User::where('role', 'customer') |  | ||||||
|                 ->whereCompany($request->header('company')) |  | ||||||
|                 ->get(), |  | ||||||
|             'nextPaymentNumber' => $nextPaymentNumber |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Store a newly created resource in storage. |  | ||||||
|      * |  | ||||||
|      * @param  \Illuminate\Http\Request  $request |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function store(PaymentRequest $request) |  | ||||||
|     { |  | ||||||
|         $payment_date = Carbon::createFromFormat('d/m/Y', $request->payment_date); |  | ||||||
|  |  | ||||||
|         if ($request->has('invoice_id') && $request->invoice_id != null) { |  | ||||||
|             $invoice = Invoice::find($request->invoice_id); |  | ||||||
|             if ($invoice && $invoice->due_amount == $request->amount) { |  | ||||||
|                 $invoice->status = Invoice::STATUS_COMPLETED; |  | ||||||
|                 $invoice->paid_status = Invoice::STATUS_PAID; |  | ||||||
|                 $invoice->due_amount = 0; |  | ||||||
|             } elseif ($invoice && $invoice->due_amount != $request->amount) { |  | ||||||
|                 $invoice->due_amount = (int)$invoice->due_amount - (int)$request->amount; |  | ||||||
|                 if ($invoice->due_amount < 0) { |  | ||||||
|                     return response()->json([ |  | ||||||
|                         'error' => 'invalid_amount' |  | ||||||
|                     ]); |  | ||||||
|                 } |  | ||||||
|                 $invoice->paid_status = Invoice::STATUS_PARTIALLY_PAID; |  | ||||||
|             } |  | ||||||
|             $invoice->save(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         $payment = Payment::create([ |  | ||||||
|             'payment_date' => $payment_date, |  | ||||||
|             'payment_number' => $request->payment_number, |  | ||||||
|             'user_id' => $request->user_id, |  | ||||||
|             'company_id' => $request->header('company'), |  | ||||||
|             'invoice_id' => $request->invoice_id, |  | ||||||
|             'payment_mode' => $request->payment_mode, |  | ||||||
|             'amount' => $request->amount, |  | ||||||
|             'notes' => $request->notes, |  | ||||||
|         ]); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'payment' => $payment, |  | ||||||
|             'success' => true |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Display the specified resource. |  | ||||||
|      * |  | ||||||
|      * @param  int  $id |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function show($id) |  | ||||||
|     { |  | ||||||
|         // |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Show the form for editing the specified resource. |  | ||||||
|      * |  | ||||||
|      * @param  int  $id |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function edit(Request $request, $id) |  | ||||||
|     { |  | ||||||
|         $payment = Payment::with('user', 'invoice')->find($id); |  | ||||||
|  |  | ||||||
|         $invoices = Invoice::where('paid_status', '<>', Invoice::STATUS_PAID) |  | ||||||
|             ->where('user_id', $payment->user_id)->where('due_amount', '>', 0) |  | ||||||
|             ->whereCompany($request->header('company')) |  | ||||||
|             ->get(); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'customers' => User::where('role', 'customer') |  | ||||||
|                 ->whereCompany($request->header('company')) |  | ||||||
|                 ->get(), |  | ||||||
|             'nextPaymentNumber' => $payment->payment_number, |  | ||||||
|             'payment' => $payment, |  | ||||||
|             'invoices' => $invoices |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Update the specified resource in storage. |  | ||||||
|      * |  | ||||||
|      * @param  \Illuminate\Http\Request  $request |  | ||||||
|      * @param  int  $id |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function update(PaymentRequest $request, $id) |  | ||||||
|     { |  | ||||||
|         $payment_date = Carbon::createFromFormat('d/m/Y', $request->payment_date); |  | ||||||
|  |  | ||||||
|         $payment = Payment::find($id); |  | ||||||
|         $oldAmount = $payment->amount; |  | ||||||
|  |  | ||||||
|         if ($request->has('invoice_id') && $request->invoice_id && ($oldAmount != $request->amount)) { |  | ||||||
|             $amount = (int)$request->amount - (int)$oldAmount; |  | ||||||
|             $invoice = Invoice::find($request->invoice_id); |  | ||||||
|             $invoice->due_amount = (int)$invoice->due_amount - (int)$amount; |  | ||||||
|  |  | ||||||
|             if ($invoice->due_amount < 0) { |  | ||||||
|                 return response()->json([ |  | ||||||
|                     'error' => 'invalid_amount' |  | ||||||
|                 ]); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             if ($invoice->due_amount == 0) { |  | ||||||
|                 $invoice->status = Invoice::STATUS_COMPLETED; |  | ||||||
|                 $invoice->paid_status = Invoice::STATUS_PAID; |  | ||||||
|             } else { |  | ||||||
|                 $invoice->status = $invoice->getPreviousStatus(); |  | ||||||
|                 $invoice->paid_status = Invoice::STATUS_PARTIALLY_PAID; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             $invoice->save(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         $payment->payment_date = $payment_date; |  | ||||||
|         $payment->payment_number = $request->payment_number; |  | ||||||
|         $payment->user_id = $request->user_id; |  | ||||||
|         $payment->invoice_id = $request->invoice_id; |  | ||||||
|         $payment->payment_mode = $request->payment_mode; |  | ||||||
|         $payment->amount = $request->amount; |  | ||||||
|         $payment->notes = $request->notes; |  | ||||||
|         $payment->save(); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'payment' => $payment, |  | ||||||
|             'success' => true |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Remove the specified resource from storage. |  | ||||||
|      * |  | ||||||
|      * @param  int  $id |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function destroy($id) |  | ||||||
|     { |  | ||||||
|         $payment = Payment::find($id); |  | ||||||
|  |  | ||||||
|         if ($payment->invoice_id != null) { |  | ||||||
|             $invoice = Invoice::find($payment->invoice_id); |  | ||||||
|             $invoice->due_amount = ((int)$invoice->due_amount + (int)$payment->amount); |  | ||||||
|  |  | ||||||
|             if ($invoice->due_amount == $invoice->total) { |  | ||||||
|                 $invoice->paid_status = Invoice::STATUS_UNPAID; |  | ||||||
|             } else { |  | ||||||
|                 $invoice->paid_status = Invoice::STATUS_PARTIALLY_PAID; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             $invoice->status = $invoice->getPreviousStatus(); |  | ||||||
|             $invoice->save(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         $payment->delete(); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'success' => true |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function delete(Request $request) |  | ||||||
|     { |  | ||||||
|         foreach ($request->id as $id) { |  | ||||||
|             $payment = Payment::find($id); |  | ||||||
|  |  | ||||||
|             if ($payment->invoice_id != null) { |  | ||||||
|                 $invoice = Invoice::find($payment->invoice_id); |  | ||||||
|                 $invoice->due_amount = ((int)$invoice->due_amount + (int)$payment->amount); |  | ||||||
|  |  | ||||||
|                 if ($invoice->due_amount == $invoice->total) { |  | ||||||
|                     $invoice->paid_status = Invoice::STATUS_UNPAID; |  | ||||||
|                 } else { |  | ||||||
|                     $invoice->paid_status = Invoice::STATUS_PARTIALLY_PAID; |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 $invoice->status = $invoice->getPreviousStatus(); |  | ||||||
|                 $invoice->save(); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             $payment->delete(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'success' => true |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -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,19 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
| namespace Crater\Http\Controllers; |  | ||||||
|  |  | ||||||
| use Illuminate\Http\Request; |  | ||||||
| use Crater\Setting; |  | ||||||
|  |  | ||||||
| class SettingsController extends Controller |  | ||||||
| { |  | ||||||
|     public function getAppVersion(Request $request) |  | ||||||
|     { |  | ||||||
|         $version = Setting::getSetting('version'); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'version' => $version, |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @ -1,35 +0,0 @@ | |||||||
| <?php |  | ||||||
|  |  | ||||||
| namespace Crater\Http\Controllers; |  | ||||||
|  |  | ||||||
| use Illuminate\Http\Request; |  | ||||||
| use Crater\Space\Updater; |  | ||||||
| use Crater\Space\SiteApi; |  | ||||||
|  |  | ||||||
| class UpdateController extends Controller |  | ||||||
| { |  | ||||||
|     public function update(Request $request) |  | ||||||
|     { |  | ||||||
|         set_time_limit(600); // 10 minutes |  | ||||||
|  |  | ||||||
|         $json = Updater::update($request->installed, $request->version); |  | ||||||
|  |  | ||||||
|         return response()->json($json); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function finishUpdate(Request $request) |  | ||||||
|     { |  | ||||||
|         $json = Updater::finishUpdate($request->installed, $request->version); |  | ||||||
|  |  | ||||||
|         return response()->json($json); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function checkLatestVersion(Request $request) |  | ||||||
|     { |  | ||||||
|         set_time_limit(600); // 10 minutes |  | ||||||
|  |  | ||||||
|         $json = Updater::checkForUpdate(); |  | ||||||
|  |  | ||||||
|         return response()->json($json); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,74 +0,0 @@ | |||||||
| <?php |  | ||||||
| namespace Crater\Http\Controllers; |  | ||||||
|  |  | ||||||
| use Illuminate\Http\Request; |  | ||||||
| use Crater\Http\Requests; |  | ||||||
| use Crater\User; |  | ||||||
| use Crater\Currency; |  | ||||||
| use Crater\Setting; |  | ||||||
| use Crater\Item; |  | ||||||
| use Crater\TaxType; |  | ||||||
| use DB; |  | ||||||
| use Carbon\Carbon; |  | ||||||
| use Auth; |  | ||||||
| use Crater\Company; |  | ||||||
| use Crater\CompanySetting; |  | ||||||
|  |  | ||||||
| class UsersController extends Controller |  | ||||||
| { |  | ||||||
|     public function getBootstrap(Request $request) |  | ||||||
|     { |  | ||||||
|         $user = Auth::user(); |  | ||||||
|  |  | ||||||
|         $company = $request->header('company') ?? 1; |  | ||||||
|  |  | ||||||
|         $customers = User::with('billingAddress', 'shippingAddress') |  | ||||||
|             ->customer() |  | ||||||
|             ->whereCompany($company) |  | ||||||
|             ->latest() |  | ||||||
|             ->get(); |  | ||||||
|  |  | ||||||
|         $currencies = Currency::latest()->get(); |  | ||||||
|  |  | ||||||
|         $default_language = CompanySetting::getSetting('language', $company); |  | ||||||
|  |  | ||||||
|         $default_currency = Currency::findOrFail( |  | ||||||
|             CompanySetting::getSetting('currency', $company) |  | ||||||
|         ); |  | ||||||
|  |  | ||||||
|         $moment_date_format = CompanySetting::getSetting( |  | ||||||
|             'moment_date_format', |  | ||||||
|             $request->header('company') |  | ||||||
|         ); |  | ||||||
|  |  | ||||||
|         $fiscal_year = CompanySetting::getSetting( |  | ||||||
|             'fiscal_year', |  | ||||||
|             $request->header('company') |  | ||||||
|         ); |  | ||||||
|  |  | ||||||
|         $items = Item::all(); |  | ||||||
|  |  | ||||||
|         $taxTypes = TaxType::latest()->get(); |  | ||||||
|  |  | ||||||
|         return response()->json([ |  | ||||||
|             'user' => $user, |  | ||||||
|             'customers' => $customers, |  | ||||||
|             'currencies' => $currencies, |  | ||||||
|             'default_currency' => $default_currency, |  | ||||||
|             'default_language' => $default_language, |  | ||||||
|             'company' => $user->company, |  | ||||||
|             'companies' => Company::all(), |  | ||||||
|             'items' => $items, |  | ||||||
|             'taxTypes' => $taxTypes, |  | ||||||
|             'moment_date_format' => $moment_date_format, |  | ||||||
|             'fiscal_year' => $fiscal_year, |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public function ping() |  | ||||||
|     { |  | ||||||
|         return response()->json([ |  | ||||||
|             'success' => 'crater-self-hosted' |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
							
								
								
									
										40
									
								
								app/Http/Controllers/V1/Auth/ConfirmPasswordController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								app/Http/Controllers/V1/Auth/ConfirmPasswordController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,40 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Auth; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Providers\RouteServiceProvider; | ||||||
|  | use Illuminate\Foundation\Auth\ConfirmsPasswords; | ||||||
|  |  | ||||||
|  | class ConfirmPasswordController extends Controller | ||||||
|  | { | ||||||
|  |     /* | ||||||
|  |     |-------------------------------------------------------------------------- | ||||||
|  |     | Confirm Password Controller | ||||||
|  |     |-------------------------------------------------------------------------- | ||||||
|  |     | | ||||||
|  |     | This controller is responsible for handling password confirmations and | ||||||
|  |     | uses a simple trait to include the behavior. You're free to explore | ||||||
|  |     | this trait and override any functions that require customization. | ||||||
|  |     | | ||||||
|  |     */ | ||||||
|  |  | ||||||
|  |     use ConfirmsPasswords; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Where to redirect users when the intended url fails. | ||||||
|  |      * | ||||||
|  |      * @var string | ||||||
|  |      */ | ||||||
|  |     protected $redirectTo = RouteServiceProvider::HOME; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Create a new controller instance. | ||||||
|  |      * | ||||||
|  |      * @return void | ||||||
|  |      */ | ||||||
|  |     public function __construct() | ||||||
|  |     { | ||||||
|  |         $this->middleware('auth'); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -1,5 +1,6 @@ | |||||||
| <?php | <?php | ||||||
| namespace Crater\Http\Controllers\Auth; | 
 | ||||||
|  | namespace Crater\Http\Controllers\V1\Auth; | ||||||
| 
 | 
 | ||||||
| use Crater\Http\Controllers\Controller; | use Crater\Http\Controllers\Controller; | ||||||
| use Illuminate\Foundation\Auth\SendsPasswordResetEmails; | use Illuminate\Foundation\Auth\SendsPasswordResetEmails; | ||||||
| @ -20,16 +21,6 @@ class ForgotPasswordController extends Controller | |||||||
| 
 | 
 | ||||||
|     use SendsPasswordResetEmails; |     use SendsPasswordResetEmails; | ||||||
| 
 | 
 | ||||||
|     /** |  | ||||||
|      * Create a new controller instance. |  | ||||||
|      * |  | ||||||
|      * @return void |  | ||||||
|      */ |  | ||||||
|     public function __construct() |  | ||||||
|     { |  | ||||||
|         // $this->middleware('guest');
 |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |     /** | ||||||
|      * Get the response for a successful password reset link. |      * Get the response for a successful password reset link. | ||||||
|      * |      * | ||||||
							
								
								
									
										40
									
								
								app/Http/Controllers/V1/Auth/LoginController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								app/Http/Controllers/V1/Auth/LoginController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,40 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Auth; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Providers\RouteServiceProvider; | ||||||
|  | use Illuminate\Foundation\Auth\AuthenticatesUsers; | ||||||
|  |  | ||||||
|  | class LoginController extends Controller | ||||||
|  | { | ||||||
|  |     /* | ||||||
|  |     |-------------------------------------------------------------------------- | ||||||
|  |     | Login Controller | ||||||
|  |     |-------------------------------------------------------------------------- | ||||||
|  |     | | ||||||
|  |     | This controller handles authenticating users for the application and | ||||||
|  |     | redirecting them to your home screen. The controller uses a trait | ||||||
|  |     | to conveniently provide its functionality to your applications. | ||||||
|  |     | | ||||||
|  |     */ | ||||||
|  |  | ||||||
|  |     use AuthenticatesUsers; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Where to redirect users after login. | ||||||
|  |      * | ||||||
|  |      * @var string | ||||||
|  |      */ | ||||||
|  |     protected $redirectTo = RouteServiceProvider::HOME; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Create a new controller instance. | ||||||
|  |      * | ||||||
|  |      * @return void | ||||||
|  |      */ | ||||||
|  |     public function __construct() | ||||||
|  |     { | ||||||
|  |         $this->middleware('guest')->except('logout'); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										73
									
								
								app/Http/Controllers/V1/Auth/RegisterController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								app/Http/Controllers/V1/Auth/RegisterController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,73 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Auth; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Providers\RouteServiceProvider; | ||||||
|  | use Crater\Models\User; | ||||||
|  | use Illuminate\Foundation\Auth\RegistersUsers; | ||||||
|  | use Illuminate\Support\Facades\Hash; | ||||||
|  | use Illuminate\Support\Facades\Validator; | ||||||
|  |  | ||||||
|  | class RegisterController extends Controller | ||||||
|  | { | ||||||
|  |     /* | ||||||
|  |     |-------------------------------------------------------------------------- | ||||||
|  |     | Register Controller | ||||||
|  |     |-------------------------------------------------------------------------- | ||||||
|  |     | | ||||||
|  |     | This controller handles the registration of new users as well as their | ||||||
|  |     | validation and creation. By default this controller uses a trait to | ||||||
|  |     | provide this functionality without requiring any additional code. | ||||||
|  |     | | ||||||
|  |     */ | ||||||
|  |  | ||||||
|  |     use RegistersUsers; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Where to redirect users after registration. | ||||||
|  |      * | ||||||
|  |      * @var string | ||||||
|  |      */ | ||||||
|  |     protected $redirectTo = RouteServiceProvider::HOME; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Create a new controller instance. | ||||||
|  |      * | ||||||
|  |      * @return void | ||||||
|  |      */ | ||||||
|  |     public function __construct() | ||||||
|  |     { | ||||||
|  |         $this->middleware('guest'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Get a validator for an incoming registration request. | ||||||
|  |      * | ||||||
|  |      * @param  array  $data | ||||||
|  |      * @return \Illuminate\Contracts\Validation\Validator | ||||||
|  |      */ | ||||||
|  |     protected function validator(array $data) | ||||||
|  |     { | ||||||
|  |         return Validator::make($data, [ | ||||||
|  |             'name' => ['required', 'string', 'max:255'], | ||||||
|  |             'email' => ['required', 'string', 'email', 'max:255', 'unique:users'], | ||||||
|  |             'password' => ['required', 'string', 'min:8', 'confirmed'], | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Create a new user instance after a valid registration. | ||||||
|  |      * | ||||||
|  |      * @param  array  $data | ||||||
|  |      * @return \App\User | ||||||
|  |      */ | ||||||
|  |     protected function create(array $data) | ||||||
|  |     { | ||||||
|  |         return User::create([ | ||||||
|  |             'name' => $data['name'], | ||||||
|  |             'email' => $data['email'], | ||||||
|  |             'password' => $data['password'] | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -1,11 +1,13 @@ | |||||||
| <?php | <?php | ||||||
| namespace Crater\Http\Controllers\Auth; | 
 | ||||||
|  | namespace Crater\Http\Controllers\V1\Auth; | ||||||
| 
 | 
 | ||||||
| use Crater\Http\Controllers\Controller; | use Crater\Http\Controllers\Controller; | ||||||
| use Illuminate\Foundation\Auth\ResetsPasswords; | use Crater\Providers\RouteServiceProvider; | ||||||
| use Illuminate\Http\Request; |  | ||||||
| use Illuminate\Support\Str; | use Illuminate\Support\Str; | ||||||
| use Illuminate\Auth\Events\PasswordReset; | use Illuminate\Auth\Events\PasswordReset; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  | use Illuminate\Foundation\Auth\ResetsPasswords; | ||||||
| 
 | 
 | ||||||
| class ResetPasswordController extends Controller | class ResetPasswordController extends Controller | ||||||
| { | { | ||||||
| @ -27,17 +29,8 @@ class ResetPasswordController extends Controller | |||||||
|      * |      * | ||||||
|      * @var string |      * @var string | ||||||
|      */ |      */ | ||||||
|     protected $redirectTo = '/'; |     protected $redirectTo = RouteServiceProvider::HOME; | ||||||
| 
 | 
 | ||||||
|     /** |  | ||||||
|      * Create a new controller instance. |  | ||||||
|      * |  | ||||||
|      * @return void |  | ||||||
|      */ |  | ||||||
|     public function __construct() |  | ||||||
|     { |  | ||||||
|         // $this->middleware('guest');
 |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * Get the response for a successful password reset. |      * Get the response for a successful password reset. | ||||||
| @ -62,7 +55,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)); | ||||||
| 
 | 
 | ||||||
							
								
								
									
										42
									
								
								app/Http/Controllers/V1/Auth/VerificationController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								app/Http/Controllers/V1/Auth/VerificationController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,42 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Auth; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Providers\RouteServiceProvider; | ||||||
|  | use Illuminate\Foundation\Auth\VerifiesEmails; | ||||||
|  |  | ||||||
|  | class VerificationController extends Controller | ||||||
|  | { | ||||||
|  |     /* | ||||||
|  |     |-------------------------------------------------------------------------- | ||||||
|  |     | Email Verification Controller | ||||||
|  |     |-------------------------------------------------------------------------- | ||||||
|  |     | | ||||||
|  |     | This controller is responsible for handling email verification for any | ||||||
|  |     | user that recently registered with the application. Emails may also | ||||||
|  |     | be re-sent if the user didn't receive the original email message. | ||||||
|  |     | | ||||||
|  |     */ | ||||||
|  |  | ||||||
|  |     use VerifiesEmails; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Where to redirect users after verification. | ||||||
|  |      * | ||||||
|  |      * @var string | ||||||
|  |      */ | ||||||
|  |     protected $redirectTo = RouteServiceProvider::HOME; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Create a new controller instance. | ||||||
|  |      * | ||||||
|  |      * @return void | ||||||
|  |      */ | ||||||
|  |     public function __construct() | ||||||
|  |     { | ||||||
|  |         $this->middleware('auth'); | ||||||
|  |         $this->middleware('signed')->only('verify'); | ||||||
|  |         $this->middleware('throttle:6,1')->only('verify', 'resend'); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										23
									
								
								app/Http/Controllers/V1/Backup/ApiController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								app/Http/Controllers/V1/Backup/ApiController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,23 @@ | |||||||
|  | <?php | ||||||
|  | // Implementation taken from nova-backup-tool - https://github.com/spatie/nova-backup-tool/ | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Backup; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Illuminate\Http\JsonResponse; | ||||||
|  |  | ||||||
|  | class ApiController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * | ||||||
|  |      * @return JsonResponse | ||||||
|  |      */ | ||||||
|  |  | ||||||
|  |     public function respondSuccess(): JsonResponse | ||||||
|  |     { | ||||||
|  |         return response()->json([ | ||||||
|  |             'success' => true | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										93
									
								
								app/Http/Controllers/V1/Backup/BackupsController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								app/Http/Controllers/V1/Backup/BackupsController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,93 @@ | |||||||
|  | <?php | ||||||
|  | // Implementation taken from nova-backup-tool - https://github.com/spatie/nova-backup-tool/ | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Backup; | ||||||
|  |  | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  | use Illuminate\Support\Facades\Cache; | ||||||
|  | use Spatie\Backup\BackupDestination\Backup; | ||||||
|  | use Spatie\Backup\BackupDestination\BackupDestination; | ||||||
|  | use Spatie\Backup\Helpers\Format; | ||||||
|  | use Crater\Jobs\CreateBackupJob; | ||||||
|  | use Crater\Rules\Backup\BackupDisk; | ||||||
|  | use Crater\Rules\Backup\PathToZip; | ||||||
|  | use Illuminate\Http\JsonResponse; | ||||||
|  |  | ||||||
|  | class BackupsController extends ApiController | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Display a listing of the resource. | ||||||
|  |      * | ||||||
|  |      * @return JsonResponse | ||||||
|  |      */ | ||||||
|  |     public function index(Request $request) | ||||||
|  |     { | ||||||
|  |         $configuredBackupDisks = config('backup.backup.destination.disks'); | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             $backupDestination = BackupDestination::create(config('filesystems.default'), config('backup.backup.name')); | ||||||
|  |  | ||||||
|  |             $backups = Cache::remember("backups-{$request->file_disk_id}", now()->addSeconds(4), function () use ($backupDestination) { | ||||||
|  |                 return $backupDestination | ||||||
|  |                     ->backups() | ||||||
|  |                     ->map(function (Backup $backup) { | ||||||
|  |                         return [ | ||||||
|  |                             'path' => $backup->path(), | ||||||
|  |                             'created_at' => $backup->date()->format('Y-m-d H:i:s'), | ||||||
|  |                             'size' => Format::humanReadableSize($backup->size()), | ||||||
|  |                         ]; | ||||||
|  |                     }) | ||||||
|  |                     ->toArray(); | ||||||
|  |             }); | ||||||
|  |  | ||||||
|  |             return response()->json([ | ||||||
|  |                 'backups' => $backups, | ||||||
|  |                 'disks' => $configuredBackupDisks | ||||||
|  |             ]); | ||||||
|  |         } catch (\Exception $e) { | ||||||
|  |             return response()->json([ | ||||||
|  |                 'backups' => [], | ||||||
|  |                 'error' => 'invalid_disk_credentials', | ||||||
|  |                 'error_message' => $e->getMessage(), | ||||||
|  |                 'disks' => $configuredBackupDisks | ||||||
|  |             ]); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Store a newly created resource in storage. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @return JsonResponse | ||||||
|  |      */ | ||||||
|  |     public function store(Request $request) | ||||||
|  |     { | ||||||
|  |         dispatch(new CreateBackupJob($request->all()))->onQueue(config('backup.queue.name')); | ||||||
|  |  | ||||||
|  |         return $this->respondSuccess(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Remove the specified resource from storage. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @return JsonResponse | ||||||
|  |      */ | ||||||
|  |     public function destroy($disk, Request $request) | ||||||
|  |     { | ||||||
|  |         $validated = $request->validate([ | ||||||
|  |             'path' => ['required', new PathToZip()], | ||||||
|  |         ]); | ||||||
|  |  | ||||||
|  |         $backupDestination = BackupDestination::create(config('filesystems.default'), config('backup.backup.name')); | ||||||
|  |  | ||||||
|  |         $backupDestination | ||||||
|  |             ->backups() | ||||||
|  |             ->first(function (Backup $backup) use ($validated) { | ||||||
|  |                 return $backup->path() === $validated['path']; | ||||||
|  |             }) | ||||||
|  |             ->delete(); | ||||||
|  |  | ||||||
|  |         return $this->respondSuccess(); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										58
									
								
								app/Http/Controllers/V1/Backup/DownloadBackupController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								app/Http/Controllers/V1/Backup/DownloadBackupController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,58 @@ | |||||||
|  | <?php | ||||||
|  | // Implementation taken from nova-backup-tool - https://github.com/spatie/nova-backup-tool/ | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Backup; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  | use Spatie\Backup\BackupDestination\Backup; | ||||||
|  | use Spatie\Backup\BackupDestination\BackupDestination; | ||||||
|  | use Crater\Rules\Backup\BackupDisk; | ||||||
|  | use Crater\Rules\Backup\PathToZip; | ||||||
|  | use Symfony\Component\HttpFoundation\Response; | ||||||
|  | use Symfony\Component\HttpFoundation\StreamedResponse; | ||||||
|  |  | ||||||
|  | class DownloadBackupController extends ApiController | ||||||
|  | { | ||||||
|  |     public function __invoke(Request $request) | ||||||
|  |     { | ||||||
|  |         $validated = $request->validate([ | ||||||
|  |             'path' => ['required', new PathToZip()], | ||||||
|  |         ]); | ||||||
|  |  | ||||||
|  |         $backupDestination = BackupDestination::create(config('filesystems.default'), config('backup.backup.name')); | ||||||
|  |  | ||||||
|  |         $backup = $backupDestination->backups()->first(function (Backup $backup) use ($validated) { | ||||||
|  |             return $backup->path() === $validated['path']; | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         if (! $backup) { | ||||||
|  |             return response('Backup not found', Response::HTTP_UNPROCESSABLE_ENTITY); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $this->respondWithBackupStream($backup); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function respondWithBackupStream(Backup $backup): StreamedResponse | ||||||
|  |     { | ||||||
|  |         $fileName = pathinfo($backup->path(), PATHINFO_BASENAME); | ||||||
|  |  | ||||||
|  |         $downloadHeaders = [ | ||||||
|  |             'Cache-Control' => 'must-revalidate, post-check=0, pre-check=0', | ||||||
|  |             'Content-Type' => 'application/zip', | ||||||
|  |             'Content-Length' => $backup->size(), | ||||||
|  |             'Content-Disposition' => 'attachment; filename="'.$fileName.'"', | ||||||
|  |             'Pragma' => 'public', | ||||||
|  |         ]; | ||||||
|  |  | ||||||
|  |         return response()->stream(function () use ($backup) { | ||||||
|  |             $stream = $backup->stream(); | ||||||
|  |  | ||||||
|  |             fpassthru($stream); | ||||||
|  |  | ||||||
|  |             if (is_resource($stream)) { | ||||||
|  |                 fclose($stream); | ||||||
|  |             } | ||||||
|  |         }, 200, $downloadHeaders); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										102
									
								
								app/Http/Controllers/V1/CustomField/CustomFieldsController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								app/Http/Controllers/V1/CustomField/CustomFieldsController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,102 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\CustomField; | ||||||
|  |  | ||||||
|  | use Crater\Models\CustomField; | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Http\Requests\CustomFieldRequest; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  |  | ||||||
|  | class CustomFieldsController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Display a listing of the resource. | ||||||
|  |      * | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function index(Request $request) | ||||||
|  |     { | ||||||
|  |       $limit = $request->has('limit') ? $request->limit : 5; | ||||||
|  |  | ||||||
|  |       $customFields = CustomField::whereCompany($request->header('company')) | ||||||
|  |             ->applyFilters($request->only([ | ||||||
|  |                 'type', | ||||||
|  |                 'search' | ||||||
|  |             ])) | ||||||
|  |             ->latest() | ||||||
|  |             ->paginateData($limit); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'customFields' => $customFields | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Store a newly created resource in storage. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\CustomFieldRequest  $request | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function store(CustomFieldRequest $request) | ||||||
|  |     { | ||||||
|  |         $customField = CustomField::createCustomField($request); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'customField' => $customField, | ||||||
|  |             'success' => true | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Display the specified resource. | ||||||
|  |      * | ||||||
|  |      * @param  int  $id | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function show(CustomField $customField) | ||||||
|  |     { | ||||||
|  |         return response()->json([ | ||||||
|  |             'customField' => $customField, | ||||||
|  |             'success' => true | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Update the specified resource in storage. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @param  int  $id | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function update(CustomFieldRequest $request, CustomField $customField) | ||||||
|  |     { | ||||||
|  |         $customField->updateCustomField($request); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'customField' => $customField, | ||||||
|  |             'success' => true | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Remove the specified resource from storage. | ||||||
|  |      * | ||||||
|  |      * @param  int  $id | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function destroy(CustomField $customField) | ||||||
|  |     { | ||||||
|  |         if ($customField->customFieldValue()->exists()) { | ||||||
|  |             return response()->json([ | ||||||
|  |                 'error' => 'values_attached' | ||||||
|  |             ]); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $customField->delete(); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'success' => true | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										146
									
								
								app/Http/Controllers/V1/Customer/CustomerStatsController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								app/Http/Controllers/V1/Customer/CustomerStatsController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,146 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Customer; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Models\Invoice; | ||||||
|  | use Crater\Models\Expense; | ||||||
|  | use Crater\Models\Payment; | ||||||
|  | use Crater\Models\User; | ||||||
|  | use Crater\Models\CompanySetting; | ||||||
|  | use Carbon\Carbon; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  |  | ||||||
|  | class CustomerStatsController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Handle the incoming request. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function __invoke(Request $request, User $customer) | ||||||
|  |     { | ||||||
|  |         $i = 0; | ||||||
|  |         $months = []; | ||||||
|  |         $invoiceTotals = []; | ||||||
|  |         $expenseTotals = []; | ||||||
|  |         $receiptTotals = []; | ||||||
|  |         $netProfits = []; | ||||||
|  |         $monthCounter = 0; | ||||||
|  |         $fiscalYear = CompanySetting::getSetting('fiscal_year', $request->header('company')); | ||||||
|  |         $startDate = Carbon::now(); | ||||||
|  |         $start = Carbon::now(); | ||||||
|  |         $end = Carbon::now(); | ||||||
|  |         $terms = explode('-', $fiscalYear); | ||||||
|  |  | ||||||
|  |         if ($terms[0] <= $start->month) { | ||||||
|  |             $startDate->month($terms[0])->startOfMonth(); | ||||||
|  |             $start->month($terms[0])->startOfMonth(); | ||||||
|  |             $end->month($terms[0])->endOfMonth(); | ||||||
|  |         } else { | ||||||
|  |             $startDate->subYear()->month($terms[0])->startOfMonth(); | ||||||
|  |             $start->subYear()->month($terms[0])->startOfMonth(); | ||||||
|  |             $end->subYear()->month($terms[0])->endOfMonth(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if ($request->has('previous_year')) { | ||||||
|  |             $startDate->subYear()->startOfMonth(); | ||||||
|  |             $start->subYear()->startOfMonth(); | ||||||
|  |             $end->subYear()->endOfMonth(); | ||||||
|  |         } | ||||||
|  |         while ($monthCounter < 12) { | ||||||
|  |             array_push( | ||||||
|  |                 $invoiceTotals, | ||||||
|  |                 Invoice::whereBetween( | ||||||
|  |                     'invoice_date', | ||||||
|  |                     [$start->format('Y-m-d'), $end->format('Y-m-d')] | ||||||
|  |                 ) | ||||||
|  |                     ->whereCompany($request->header('company')) | ||||||
|  |                     ->whereCustomer($customer->id) | ||||||
|  |                     ->sum('total') ?? 0 | ||||||
|  |             ); | ||||||
|  |             array_push( | ||||||
|  |                 $expenseTotals, | ||||||
|  |                 Expense::whereBetween( | ||||||
|  |                     'expense_date', | ||||||
|  |                     [$start->format('Y-m-d'), $end->format('Y-m-d')] | ||||||
|  |                 ) | ||||||
|  |                     ->whereCompany($request->header('company')) | ||||||
|  |                     ->whereUser($customer->id) | ||||||
|  |                     ->sum('amount') ?? 0 | ||||||
|  |             ); | ||||||
|  |             array_push( | ||||||
|  |                 $receiptTotals, | ||||||
|  |                 Payment::whereBetween( | ||||||
|  |                     'payment_date', | ||||||
|  |                     [$start->format('Y-m-d'), $end->format('Y-m-d')] | ||||||
|  |                 ) | ||||||
|  |                     ->whereCompany($request->header('company')) | ||||||
|  |                     ->whereCustomer($customer->id) | ||||||
|  |                     ->sum('amount') ?? 0 | ||||||
|  |             ); | ||||||
|  |             array_push( | ||||||
|  |                 $netProfits, | ||||||
|  |                 ($receiptTotals[$i] - $expenseTotals[$i]) | ||||||
|  |             ); | ||||||
|  |             $i++; | ||||||
|  |             array_push($months, $start->format('M')); | ||||||
|  |             $monthCounter++; | ||||||
|  |             $end->startOfMonth(); | ||||||
|  |             $start->addMonth()->startOfMonth(); | ||||||
|  |             $end->addMonth()->endOfMonth(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $start->subMonth()->endOfMonth(); | ||||||
|  |  | ||||||
|  |         $salesTotal = Invoice::whereCompany($request->header('company')) | ||||||
|  |             ->whereBetween( | ||||||
|  |                 'invoice_date', | ||||||
|  |                 [$startDate->format('Y-m-d'), $start->format('Y-m-d')] | ||||||
|  |             ) | ||||||
|  |             ->whereCustomer($customer->id) | ||||||
|  |             ->sum('total'); | ||||||
|  |         $totalReceipts = Payment::whereCompany($request->header('company')) | ||||||
|  |             ->whereBetween( | ||||||
|  |                 'payment_date', | ||||||
|  |                 [$startDate->format('Y-m-d'), $start->format('Y-m-d')] | ||||||
|  |             ) | ||||||
|  |             ->whereCustomer($customer->id) | ||||||
|  |             ->sum('amount'); | ||||||
|  |         $totalExpenses = Expense::whereCompany($request->header('company')) | ||||||
|  |             ->whereBetween( | ||||||
|  |                 'expense_date', | ||||||
|  |                 [$startDate->format('Y-m-d'), $start->format('Y-m-d')] | ||||||
|  |             ) | ||||||
|  |             ->whereUser($customer->id) | ||||||
|  |             ->sum('amount'); | ||||||
|  |         $netProfit = (int) $totalReceipts - (int) $totalExpenses; | ||||||
|  |  | ||||||
|  |         $chartData = [ | ||||||
|  |             'months'        => $months, | ||||||
|  |             'invoiceTotals' => $invoiceTotals, | ||||||
|  |             'expenseTotals' => $expenseTotals, | ||||||
|  |             'receiptTotals' => $receiptTotals, | ||||||
|  |             'netProfit'     => $netProfit, | ||||||
|  |             'netProfits'     => $netProfits, | ||||||
|  |             'salesTotal'    => $salesTotal, | ||||||
|  |             'totalReceipts' => $totalReceipts, | ||||||
|  |             'totalExpenses' => $totalExpenses | ||||||
|  |         ]; | ||||||
|  |  | ||||||
|  |         $customer = User::with([ | ||||||
|  |             'billingAddress', | ||||||
|  |             'shippingAddress', | ||||||
|  |             'billingAddress.country', | ||||||
|  |             'shippingAddress.country', | ||||||
|  |             'currency', | ||||||
|  |             'fields.customField' | ||||||
|  |         ])->find($customer->id); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'customer' => $customer, | ||||||
|  |             'chartData' => $chartData, | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										122
									
								
								app/Http/Controllers/V1/Customer/CustomersController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								app/Http/Controllers/V1/Customer/CustomersController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,122 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Customer; | ||||||
|  |  | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  | use Crater\Http\Requests; | ||||||
|  | use Crater\Models\User; | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Illuminate\Support\Facades\DB; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class CustomersController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Display a listing of the resource. | ||||||
|  |      * | ||||||
|  |      * @return \Illuminate\Http\JsonResponse | ||||||
|  |      */ | ||||||
|  |     public function index(Request $request) | ||||||
|  |     { | ||||||
|  |         $limit = $request->has('limit') ? $request->limit : 10; | ||||||
|  |  | ||||||
|  |         $customers = User::with('creator') | ||||||
|  |             ->customer() | ||||||
|  |             ->applyFilters($request->only([ | ||||||
|  |                 'search', | ||||||
|  |                 'contact_name', | ||||||
|  |                 'display_name', | ||||||
|  |                 'phone', | ||||||
|  |                 'customer_id', | ||||||
|  |                 'orderByField', | ||||||
|  |                 'orderBy' | ||||||
|  |             ])) | ||||||
|  |             ->whereCompany($request->header('company')) | ||||||
|  |             ->select( | ||||||
|  |                 'users.*', | ||||||
|  |                 DB::raw('sum(invoices.due_amount) as due_amount') | ||||||
|  |             ) | ||||||
|  |             ->groupBy('users.id') | ||||||
|  |             ->leftJoin('invoices', 'users.id', '=', 'invoices.user_id') | ||||||
|  |             ->paginateData($limit); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'customers' => $customers, | ||||||
|  |             'customerTotalCount' => User::whereRole('customer')->count() | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Store a newly created resource in storage. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @return \Illuminate\Http\JsonResponse | ||||||
|  |      */ | ||||||
|  |     public function store(Requests\CustomerRequest $request) | ||||||
|  |     { | ||||||
|  |         $customer = User::createCustomer($request); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'customer' => $customer, | ||||||
|  |             'success' => true | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Display the specified resource. | ||||||
|  |      * | ||||||
|  |      * @param  User $customer | ||||||
|  |      * @return \Illuminate\Http\JsonResponse | ||||||
|  |      */ | ||||||
|  |     public function show(User $customer) | ||||||
|  |     { | ||||||
|  |         $customer->load([ | ||||||
|  |             'billingAddress.country', | ||||||
|  |             'shippingAddress.country', | ||||||
|  |             'fields.customField', | ||||||
|  |             'creator' | ||||||
|  |         ]); | ||||||
|  |  | ||||||
|  |         $currency = $customer->currency; | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'customer' => $customer, | ||||||
|  |             'currency' => $currency, | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Update the specified resource in storage. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request $request | ||||||
|  |      * @param  \Crater\Models\User $customer | ||||||
|  |      * @return \Illuminate\Http\JsonResponse | ||||||
|  |      */ | ||||||
|  |     public function update(Requests\CustomerRequest $request, User $customer) | ||||||
|  |     { | ||||||
|  |         $customer = User::updateCustomer($request, $customer); | ||||||
|  |  | ||||||
|  |         $customer = User::with('billingAddress', 'shippingAddress', 'fields')->find($customer->id); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'customer' => $customer, | ||||||
|  |             'success' => true | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Remove a list of Customers along side all their resources (ie. Estimates, Invoices, Payments and Addresses) | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request $request | ||||||
|  |      * @return \Illuminate\Http\JsonResponse | ||||||
|  |      */ | ||||||
|  |     public function delete(Request $request) | ||||||
|  |     { | ||||||
|  |         User::deleteCustomers($request->ids); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'success' => true | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,32 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Dashboard; | ||||||
|  |  | ||||||
|  | use Crater\Models\Expense; | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  |  | ||||||
|  | class DashboardChartController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Handle the incoming request. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @return \Illuminate\Http\JsonResponse | ||||||
|  |      */ | ||||||
|  |     public function __invoke(Request $request) | ||||||
|  |     { | ||||||
|  |         $expensesCategories = Expense::with('category') | ||||||
|  |             ->whereCompany($request->header('company')) | ||||||
|  |             ->expensesAttributes() | ||||||
|  |             ->get(); | ||||||
|  |  | ||||||
|  |         $amounts = $expensesCategories->pluck('total_amount'); | ||||||
|  |         $names = $expensesCategories->pluck('category.name'); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'amounts' => $amounts, | ||||||
|  |             'categories' => $names, | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -1,21 +1,25 @@ | |||||||
| <?php | <?php | ||||||
| namespace Crater\Http\Controllers; | namespace Crater\Http\Controllers\V1\Dashboard; | ||||||
| 
 | 
 | ||||||
| use Illuminate\Http\Request; | use Illuminate\Http\Request; | ||||||
| 
 | use Crater\Models\Estimate; | ||||||
| use Crater\Estimate; | use Crater\Models\Invoice; | ||||||
| use Crater\Http\Requests; | use Crater\Models\CompanySetting; | ||||||
| use Crater\Invoice; | use Crater\Models\Expense; | ||||||
| use Crater\CompanySetting; | use Crater\Models\Payment; | ||||||
| use Crater\Expense; |  | ||||||
| use Crater\Payment; |  | ||||||
| use Carbon\Carbon; | use Carbon\Carbon; | ||||||
| use Crater\User; | use Crater\Models\User; | ||||||
| use Illuminate\Support\Facades\DB; | use Crater\Http\Controllers\Controller; | ||||||
| 
 | 
 | ||||||
| class DashboardController extends Controller | class DashboardController extends Controller | ||||||
| { | { | ||||||
|     public function index(Request $request) |     /** | ||||||
|  |      * Handle the incoming request. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @return \Illuminate\Http\JsonResponse | ||||||
|  |      */ | ||||||
|  |     public function __invoke(Request $request) | ||||||
|     { |     { | ||||||
|         $invoiceTotals = []; |         $invoiceTotals = []; | ||||||
|         $expenseTotals = []; |         $expenseTotals = []; | ||||||
| @ -23,14 +27,14 @@ class DashboardController extends Controller | |||||||
|         $netProfits = []; |         $netProfits = []; | ||||||
|         $i = 0; |         $i = 0; | ||||||
|         $months = []; |         $months = []; | ||||||
|         $monthEnds = []; |  | ||||||
|         $monthCounter = 0; |         $monthCounter = 0; | ||||||
|         $fiscalYear = CompanySetting::getSetting('fiscal_year', $request->header('company')); |         $fiscalYear = CompanySetting::getSetting('fiscal_year', $request->header('company')); | ||||||
|         $startDate = Carbon::now(); |         $startDate = Carbon::now(); | ||||||
|         $start = Carbon::now(); |         $start = Carbon::now(); | ||||||
|         $end = Carbon::now(); |         $end = Carbon::now(); | ||||||
|         $terms = explode('-', $fiscalYear); |         $terms = explode('-', $fiscalYear); | ||||||
|         if ($terms[0] < $start->month) { | 
 | ||||||
|  |         if ($terms[0] <= $start->month) { | ||||||
|             $startDate->month($terms[0])->startOfMonth(); |             $startDate->month($terms[0])->startOfMonth(); | ||||||
|             $start->month($terms[0])->startOfMonth(); |             $start->month($terms[0])->startOfMonth(); | ||||||
|             $end->month($terms[0])->endOfMonth(); |             $end->month($terms[0])->endOfMonth(); | ||||||
| @ -87,6 +91,7 @@ class DashboardController extends Controller | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         $start->subMonth()->endOfMonth(); |         $start->subMonth()->endOfMonth(); | ||||||
|  | 
 | ||||||
|         $salesTotal = Invoice::whereCompany($request->header('company')) |         $salesTotal = Invoice::whereCompany($request->header('company')) | ||||||
|             ->whereBetween( |             ->whereBetween( | ||||||
|                 'invoice_date', |                 'invoice_date', | ||||||
| @ -136,20 +141,4 @@ class DashboardController extends Controller | |||||||
|             'netProfit' => $netProfit |             'netProfit' => $netProfit | ||||||
|         ]); |         ]); | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
|     public function getExpenseChartData(Request $request) |  | ||||||
|     { |  | ||||||
|         $expensesCategories = Expense::with('category') |  | ||||||
|             ->whereCompany($request->header('company')) |  | ||||||
|             ->expensesAttributes() |  | ||||||
|             ->get(); |  | ||||||
| 
 |  | ||||||
|         $amounts = $expensesCategories->pluck('total_amount'); |  | ||||||
|         $names = $expensesCategories->pluck('category.name'); |  | ||||||
| 
 |  | ||||||
|         return response()->json([ |  | ||||||
|             'amounts' => $amounts, |  | ||||||
|             'categories' => $names, |  | ||||||
|         ]); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
| @ -0,0 +1,26 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Estimate; | ||||||
|  |  | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Models\Estimate; | ||||||
|  |  | ||||||
|  | class ChangeEstimateStatusController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |     * Handle the incoming request. | ||||||
|  |     * | ||||||
|  |     * @param  \Illuminate\Http\Request  $request | ||||||
|  |     * @param  Estimate $estimate | ||||||
|  |     * @return \Illuminate\Http\Response | ||||||
|  |     */ | ||||||
|  |    public function __invoke(Request $request, Estimate $estimate) | ||||||
|  |    { | ||||||
|  |         $estimate->update($request->only('status')); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'success' => true | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,95 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Estimate; | ||||||
|  |  | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Models\Estimate; | ||||||
|  | use Crater\Models\Invoice; | ||||||
|  | use Carbon\Carbon; | ||||||
|  | use Crater\Models\CompanySetting; | ||||||
|  | use Illuminate\Support\Facades\Auth; | ||||||
|  |  | ||||||
|  | class ConvertEstimateController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |     * Handle the incoming request. | ||||||
|  |     * | ||||||
|  |     * @param  \Illuminate\Http\Request  $request | ||||||
|  |     * @param  \Crater\Models\Estimate $estimate | ||||||
|  |     * @return \Illuminate\Http\Response | ||||||
|  |     */ | ||||||
|  |     public function __invoke(Request $request, Estimate $estimate) | ||||||
|  |     { | ||||||
|  |         $estimate->load(['items', 'items.taxes', 'user', 'estimateTemplate', 'taxes']); | ||||||
|  |  | ||||||
|  |         $invoice_date = Carbon::now(); | ||||||
|  |         $due_date = Carbon::now()->addDays(7); | ||||||
|  |  | ||||||
|  |         $invoice_prefix = CompanySetting::getSetting( | ||||||
|  |             'invoice_prefix', | ||||||
|  |             $request->header('company') | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         $invoice = Invoice::create([ | ||||||
|  |             'creator_id' => Auth::id(), | ||||||
|  |             'invoice_date' => $invoice_date->format('Y-m-d'), | ||||||
|  |             'due_date' => $due_date->format('Y-m-d'), | ||||||
|  |             'invoice_number' => $invoice_prefix . "-" . Invoice::getNextInvoiceNumber($invoice_prefix), | ||||||
|  |             'reference_number' => $estimate->reference_number, | ||||||
|  |             'user_id' => $estimate->user_id, | ||||||
|  |             'company_id' => $request->header('company'), | ||||||
|  |             'invoice_template_id' => 1, | ||||||
|  |             'status' => Invoice::STATUS_DRAFT, | ||||||
|  |             'paid_status' => Invoice::STATUS_UNPAID, | ||||||
|  |             'sub_total' => $estimate->sub_total, | ||||||
|  |             'discount' => $estimate->discount, | ||||||
|  |             'discount_type' => $estimate->discount_type, | ||||||
|  |             'discount_val' => $estimate->discount_val, | ||||||
|  |             'total' => $estimate->total, | ||||||
|  |             'due_amount' => $estimate->total, | ||||||
|  |             'tax_per_item' => $estimate->tax_per_item, | ||||||
|  |             'discount_per_item' => $estimate->discount_per_item, | ||||||
|  |             'tax' => $estimate->tax, | ||||||
|  |             'notes' => $estimate->notes, | ||||||
|  |             'unique_hash' => str_random(60) | ||||||
|  |         ]); | ||||||
|  |  | ||||||
|  |         $invoiceItems = $estimate->items->toArray(); | ||||||
|  |  | ||||||
|  |         foreach ($invoiceItems as $invoiceItem) { | ||||||
|  |             $invoiceItem['company_id'] = $request->header('company'); | ||||||
|  |             $invoiceItem['name'] = $invoiceItem['name']; | ||||||
|  |             $item = $invoice->items()->create($invoiceItem); | ||||||
|  |  | ||||||
|  |             if (array_key_exists('taxes', $invoiceItem) && $invoiceItem['taxes']) { | ||||||
|  |                 foreach ($invoiceItem['taxes'] as $tax) { | ||||||
|  |                     $tax['company_id'] = $request->header('company'); | ||||||
|  |  | ||||||
|  |                     if ($tax['amount']) { | ||||||
|  |                         $item->taxes()->create($tax); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if ($estimate->taxes) { | ||||||
|  |             foreach ($estimate->taxes->toArray() as $tax) { | ||||||
|  |                 $tax['company_id'] = $request->header('company'); | ||||||
|  |                 unset($tax['estimate_id']); | ||||||
|  |                 $invoice->taxes()->create($tax); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $invoice = Invoice::with([ | ||||||
|  |             'items', | ||||||
|  |             'user', | ||||||
|  |             'invoiceTemplate', | ||||||
|  |             'taxes' | ||||||
|  |         ])->find($invoice->id); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'invoice' => $invoice | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										20
									
								
								app/Http/Controllers/V1/Estimate/EstimatePdfController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								app/Http/Controllers/V1/Estimate/EstimatePdfController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Estimate; | ||||||
|  |  | ||||||
|  | use Crater\Models\Estimate;  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  |  | ||||||
|  | class EstimatePdfController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Handle the incoming request. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function __invoke(Estimate $estimate) | ||||||
|  |     { | ||||||
|  |         return $estimate->getGeneratedPDFOrStream('estimate'); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,23 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Estimate; | ||||||
|  |  | ||||||
|  | use Crater\Models\EstimateTemplate; | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  |  | ||||||
|  | class EstimateTemplatesController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Handle the incoming request. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function __invoke(Request $request) | ||||||
|  |     { | ||||||
|  |         return response()->json([ | ||||||
|  |             'templates' => EstimateTemplate::all() | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										104
									
								
								app/Http/Controllers/V1/Estimate/EstimatesController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								app/Http/Controllers/V1/Estimate/EstimatesController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,104 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Estimate; | ||||||
|  |  | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  | use Crater\Models\Estimate; | ||||||
|  | use Crater\Http\Requests\EstimatesRequest; | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Http\Requests\DeleteEstimatesRequest; | ||||||
|  | use Crater\Jobs\GenerateEstimatePdfJob; | ||||||
|  |  | ||||||
|  | class EstimatesController extends Controller | ||||||
|  | { | ||||||
|  |     public function index(Request $request) | ||||||
|  |     { | ||||||
|  |         $limit = $request->has('limit') ? $request->limit : 10; | ||||||
|  |  | ||||||
|  |         $estimates = Estimate::with([ | ||||||
|  |                 'items', | ||||||
|  |                 'user', | ||||||
|  |                 'estimateTemplate', | ||||||
|  |                 'taxes', | ||||||
|  |                 'creator' | ||||||
|  |             ]) | ||||||
|  |             ->join('users', 'users.id', '=', 'estimates.user_id') | ||||||
|  |             ->applyFilters($request->only([ | ||||||
|  |                 'status', | ||||||
|  |                 'customer_id', | ||||||
|  |                 'estimate_id', | ||||||
|  |                 'estimate_number', | ||||||
|  |                 'from_date', | ||||||
|  |                 'to_date', | ||||||
|  |                 'search', | ||||||
|  |                 'orderByField', | ||||||
|  |                 'orderBy' | ||||||
|  |             ])) | ||||||
|  |             ->whereCompany($request->header('company')) | ||||||
|  |             ->select('estimates.*', 'users.name') | ||||||
|  |             ->latest() | ||||||
|  |             ->paginateData($limit); | ||||||
|  |  | ||||||
|  |         $siteData = [ | ||||||
|  |             'estimates' => $estimates, | ||||||
|  |             'estimateTotalCount' => Estimate::count() | ||||||
|  |         ]; | ||||||
|  |  | ||||||
|  |         return response()->json($siteData); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function store(EstimatesRequest $request) | ||||||
|  |     { | ||||||
|  |         $estimate = Estimate::createEstimate($request); | ||||||
|  |  | ||||||
|  |         if ($request->has('estimateSend')) { | ||||||
|  |             $estimate->send($request->title, $request->body); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         GenerateEstimatePdfJob::dispatch($estimate); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'estimate' => $estimate | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function show(Request $request, Estimate $estimate) | ||||||
|  |     { | ||||||
|  |         $estimate->load([ | ||||||
|  |             'items', | ||||||
|  |             'items.taxes', | ||||||
|  |             'user', | ||||||
|  |             'estimateTemplate', | ||||||
|  |             'creator', | ||||||
|  |             'taxes', | ||||||
|  |             'taxes.taxType', | ||||||
|  |             'fields.customField' | ||||||
|  |         ]); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'estimate' => $estimate, | ||||||
|  |             'nextEstimateNumber' => $estimate->getEstimateNumAttribute(), | ||||||
|  |             'estimatePrefix' => $estimate->getEstimatePrefixAttribute(), | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function update(EstimatesRequest $request, Estimate $estimate) | ||||||
|  |     { | ||||||
|  |         $estimate = $estimate->updateEstimate($request); | ||||||
|  |  | ||||||
|  |         GenerateEstimatePdfJob::dispatch($estimate, true); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'estimate' => $estimate | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function delete(DeleteEstimatesRequest $request) | ||||||
|  |     { | ||||||
|  |         Estimate::destroy($request->ids); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'success' => true | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										23
									
								
								app/Http/Controllers/V1/Estimate/SendEstimateController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								app/Http/Controllers/V1/Estimate/SendEstimateController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,23 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Estimate; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Models\Estimate; | ||||||
|  | use Crater\Http\Requests\SendEstimatesRequest; | ||||||
|  |  | ||||||
|  | class SendEstimateController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |     * Handle the incoming request. | ||||||
|  |     * | ||||||
|  |     * @param  \Crater\Http\Requests\SendEstimatesRequest  $request | ||||||
|  |     * @return \Illuminate\Http\JsonResponse | ||||||
|  |     */ | ||||||
|  |     public function __invoke(SendEstimatesRequest $request, Estimate $estimate) | ||||||
|  |     { | ||||||
|  |         $response = $estimate->send($request->all()); | ||||||
|  |  | ||||||
|  |         return response()->json($response); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,34 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Expense; | ||||||
|  |  | ||||||
|  | use Crater\Models\Expense; | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  |  | ||||||
|  | class DownloadReceiptController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Handle the incoming request. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @param  Expense $expense | ||||||
|  |      * @param   string $hash | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function __invoke(Expense $expense) | ||||||
|  |     { | ||||||
|  |         if ($expense) { | ||||||
|  |             $media = $expense->getFirstMedia('receipts'); | ||||||
|  |             if ($media) { | ||||||
|  |                 $imagePath = $media->getPath(); | ||||||
|  |                 $response = \Response::download($imagePath, $media->file_name); | ||||||
|  |                 ob_end_clean(); | ||||||
|  |                 return $response; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'error' => 'receipt_not_found' | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -1,13 +1,12 @@ | |||||||
| <?php | <?php | ||||||
| namespace Crater\Http\Controllers; | namespace Crater\Http\Controllers\V1\Expense; | ||||||
| 
 | 
 | ||||||
| use Crater\ExpenseCategory; | use Crater\Models\ExpenseCategory; | ||||||
| use Crater\Expense; |  | ||||||
| use Crater\User; |  | ||||||
| use Illuminate\Http\Request; | use Illuminate\Http\Request; | ||||||
| use Crater\Http\Requests\ExpenseCategoryRequest; | use Crater\Http\Requests\ExpenseCategoryRequest; | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
| 
 | 
 | ||||||
| class ExpenseCategoryController extends Controller | class ExpenseCategoriesController extends Controller | ||||||
| { | { | ||||||
|     /** |     /** | ||||||
|      * Display a listing of the resource. |      * Display a listing of the resource. | ||||||
| @ -16,23 +15,21 @@ class ExpenseCategoryController extends Controller | |||||||
|      */ |      */ | ||||||
|     public function index(Request $request) |     public function index(Request $request) | ||||||
|     { |     { | ||||||
|         $categories = ExpenseCategory::whereCompany($request->header('company'))->get(); |         $limit = $request->has('limit') ? $request->limit : 5; | ||||||
|  | 
 | ||||||
|  |         $categories = ExpenseCategory::whereCompany($request->header('company')) | ||||||
|  |             ->applyFilters($request->only([ | ||||||
|  |                 'category_id', | ||||||
|  |                 'search' | ||||||
|  |             ])) | ||||||
|  |             ->latest() | ||||||
|  |             ->paginateData($limit); | ||||||
| 
 | 
 | ||||||
|         return response()->json([ |         return response()->json([ | ||||||
|             'categories' => $categories |             'categories' => $categories | ||||||
|         ]); |         ]); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |  | ||||||
|      * Show the form for creating a new resource. |  | ||||||
|      * |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function create() |  | ||||||
|     { |  | ||||||
|         // return view('app.categories.create');
 |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |     /** | ||||||
|      * Store a newly created resource in storage. |      * Store a newly created resource in storage. | ||||||
|      * |      * | ||||||
| @ -41,11 +38,9 @@ class ExpenseCategoryController extends Controller | |||||||
|      */ |      */ | ||||||
|     public function store(ExpenseCategoryRequest $request) |     public function store(ExpenseCategoryRequest $request) | ||||||
|     { |     { | ||||||
|         $category = new ExpenseCategory(); |         $data = $request->validated(); | ||||||
|         $category->name = $request->name; |         $data['company_id'] = $request->header('company'); | ||||||
|         $category->description = $request->description; |         $category = ExpenseCategory::create($data); | ||||||
|         $category->company_id = $request->header('company'); |  | ||||||
|         $category->save(); |  | ||||||
| 
 | 
 | ||||||
|         return response()->json([ |         return response()->json([ | ||||||
|             'category' => $category, |             'category' => $category, | ||||||
| @ -56,24 +51,11 @@ class ExpenseCategoryController extends Controller | |||||||
|     /** |     /** | ||||||
|      * Display the specified resource. |      * Display the specified resource. | ||||||
|      * |      * | ||||||
|      * @param  \Crater\ExpenseCategory $ExpenseCategory |      * @param  \Crater\Models\ExpenseCategory $category | ||||||
|      * @return \Illuminate\Http\Response |      * @return \Illuminate\Http\Response | ||||||
|      */ |      */ | ||||||
|     public function show(ExpenseCategory $ExpenseCategory) |     public function show(ExpenseCategory $category) | ||||||
|     { |     { | ||||||
|         //
 |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * Show the form for editing the specified resource. |  | ||||||
|      * |  | ||||||
|      * @param  \Crater\ExpensesCategory $ExpensesCategory |  | ||||||
|      * @return \Illuminate\Http\Response |  | ||||||
|      */ |  | ||||||
|     public function edit($id) |  | ||||||
|     { |  | ||||||
|         $category = ExpenseCategory::findOrFail($id); |  | ||||||
| 
 |  | ||||||
|         return response()->json([ |         return response()->json([ | ||||||
|             'category' => $category |             'category' => $category | ||||||
|         ]); |         ]); | ||||||
| @ -83,15 +65,12 @@ class ExpenseCategoryController extends Controller | |||||||
|      * Update the specified resource in storage. |      * Update the specified resource in storage. | ||||||
|      * |      * | ||||||
|      * @param  \Illuminate\Http\Request $request |      * @param  \Illuminate\Http\Request $request | ||||||
|      * @param  \Crater\ExpenseCategory $ExpenseCategory |      * @param  \Crater\Models\ExpenseCategory $ExpenseCategory | ||||||
|      * @return \Illuminate\Http\Response |      * @return \Illuminate\Http\Response | ||||||
|      */ |      */ | ||||||
|     public function update(ExpenseCategoryRequest $request, $id) |     public function update(ExpenseCategoryRequest $request, ExpenseCategory $category) | ||||||
|     { |     { | ||||||
|         $category = ExpenseCategory::findOrFail($id); |         $category->update($request->validated()); | ||||||
|         $category->name = $request->name; |  | ||||||
|         $category->description = $request->description; |  | ||||||
|         $category->save(); |  | ||||||
| 
 | 
 | ||||||
|         return response()->json([ |         return response()->json([ | ||||||
|             'category' => $category, |             'category' => $category, | ||||||
| @ -102,17 +81,17 @@ class ExpenseCategoryController extends Controller | |||||||
|     /** |     /** | ||||||
|      * Remove the specified resource from storage. |      * Remove the specified resource from storage. | ||||||
|      * |      * | ||||||
|      * @param  \Crater\ExpensesCategory $expensesCategory |      * @param  \Crater\ExpensesCategory $category | ||||||
|      * @return \Illuminate\Http\Response |      * @return \Illuminate\Http\Response | ||||||
|      */ |      */ | ||||||
|     public function destroy($id) |     public function destroy(ExpenseCategory $category) | ||||||
|     { |     { | ||||||
|         $category = ExpenseCategory::find($id); |  | ||||||
|         if ($category->expenses() && $category->expenses()->count() > 0) { |         if ($category->expenses() && $category->expenses()->count() > 0) { | ||||||
|             return response()->json([ |             return response()->json([ | ||||||
|                 'success' => false |                 'success' => false | ||||||
|             ]); |             ]); | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|         $category->delete(); |         $category->delete(); | ||||||
| 
 | 
 | ||||||
|         return response()->json([ |         return response()->json([ | ||||||
							
								
								
									
										101
									
								
								app/Http/Controllers/V1/Expense/ExpensesController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								app/Http/Controllers/V1/Expense/ExpensesController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,101 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Expense; | ||||||
|  |  | ||||||
|  | use Crater\Models\Expense; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  | use Crater\Http\Requests\ExpenseRequest; | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Http\Requests\DeleteExpensesRequest; | ||||||
|  |  | ||||||
|  | class ExpensesController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Display a listing of the resource. | ||||||
|  |      * | ||||||
|  |      * @return \Illuminate\Http\JsonResponse | ||||||
|  |      */ | ||||||
|  |     public function index(Request $request) | ||||||
|  |     { | ||||||
|  |         $limit = $request->has('limit') ? $request->limit : 10; | ||||||
|  |  | ||||||
|  |         $expenses = Expense::with('category', 'creator', 'fields') | ||||||
|  |             ->leftJoin('users', 'users.id', '=', 'expenses.user_id') | ||||||
|  |             ->join('expense_categories', 'expense_categories.id', '=', 'expenses.expense_category_id') | ||||||
|  |             ->applyFilters($request->only([ | ||||||
|  |                 'expense_category_id', | ||||||
|  |                 'user_id', | ||||||
|  |                 'expense_id', | ||||||
|  |                 'search', | ||||||
|  |                 'from_date', | ||||||
|  |                 'to_date', | ||||||
|  |                 'orderByField', | ||||||
|  |                 'orderBy' | ||||||
|  |             ])) | ||||||
|  |             ->whereCompany($request->header('company')) | ||||||
|  |             ->select('expenses.*', 'expense_categories.name', 'users.name as user_name') | ||||||
|  |             ->paginateData($limit); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'expenses' => $expenses, | ||||||
|  |             'expenseTotalCount' => Expense::count() | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Store a newly created resource in storage. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request $request | ||||||
|  |      * @return \Illuminate\Http\JsonResponse | ||||||
|  |      */ | ||||||
|  |     public function store(ExpenseRequest $request) | ||||||
|  |     { | ||||||
|  |         $expense = Expense::createExpense($request); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'expense' => $expense, | ||||||
|  |             'success' => true | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Display the specified resource. | ||||||
|  |      * | ||||||
|  |      * @param  \Crater\Models\Expense $expense | ||||||
|  |      * @return \Illuminate\Http\JsonResponse | ||||||
|  |      */ | ||||||
|  |     public function show(Expense $expense) | ||||||
|  |     { | ||||||
|  |         $expense->load('creator', 'fields.customField'); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'expense' => $expense | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Update the specified resource in storage. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request $request | ||||||
|  |      * @param  \Crater\Models\Expense $expense | ||||||
|  |      * @return \Illuminate\Http\JsonResponse | ||||||
|  |      */ | ||||||
|  |     public function update(ExpenseRequest $request, Expense $expense) | ||||||
|  |     { | ||||||
|  |         $expense->updateExpense($request); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'expense' => $expense, | ||||||
|  |             'success' => true | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function delete(DeleteExpensesRequest $request) | ||||||
|  |     { | ||||||
|  |         Expense::destroy($request->ids); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'success' => true | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										40
									
								
								app/Http/Controllers/V1/Expense/ShowReceiptController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								app/Http/Controllers/V1/Expense/ShowReceiptController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,40 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Expense; | ||||||
|  |  | ||||||
|  | use Crater\Models\Expense; | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  |  | ||||||
|  | class ShowReceiptController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Retrieve details of an expense receipt from storage. | ||||||
|  |      * | ||||||
|  |      * @param   \Crater\Models\Expense $expense | ||||||
|  |      * @return  \Illuminate\Http\JsonResponse | ||||||
|  |      */ | ||||||
|  |     public function __invoke(Expense $expense) | ||||||
|  |     { | ||||||
|  |         $imagePath  = null; | ||||||
|  |  | ||||||
|  |         if ($expense) { | ||||||
|  |             $media = $expense->getFirstMedia('receipts'); | ||||||
|  |             if ($media) { | ||||||
|  |                 $imagePath = $media->getPath(); | ||||||
|  |             } else { | ||||||
|  |                 return response()->json([ | ||||||
|  |                     'error' => 'receipt_does_not_exist' | ||||||
|  |                 ]); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $type = \File::mimeType($imagePath); | ||||||
|  |  | ||||||
|  |         $image = 'data:' . $type . ';base64,' . base64_encode(file_get_contents($imagePath)); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'image' => $image, | ||||||
|  |             'type' => $type | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										36
									
								
								app/Http/Controllers/V1/Expense/UploadReceiptController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								app/Http/Controllers/V1/Expense/UploadReceiptController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,36 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Expense; | ||||||
|  |  | ||||||
|  | use Crater\Models\Expense; | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  |  | ||||||
|  | class UploadReceiptController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Upload the expense receipts to storage. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request $request | ||||||
|  |      * @param  Expense $expense | ||||||
|  |      * @return \Illuminate\Http\JsonResponse | ||||||
|  |      */ | ||||||
|  |     public function __invoke(Request $request, Expense $expense) | ||||||
|  |     { | ||||||
|  |         $data = json_decode($request->attachment_receipt); | ||||||
|  |  | ||||||
|  |         if ($data) { | ||||||
|  |             if ($request->type === 'edit') { | ||||||
|  |                 $expense->clearMediaCollection('receipts'); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             $expense->addMediaFromBase64($data->data) | ||||||
|  |                 ->usingFileName($data->name) | ||||||
|  |                 ->toMediaCollection('receipts', 'local'); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'success' => 'Expense receipts uploaded successfully' | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										52
									
								
								app/Http/Controllers/V1/General/BootstrapController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								app/Http/Controllers/V1/General/BootstrapController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,52 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\General; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  | use Crater\Models\Currency; | ||||||
|  | use Crater\Models\Country; | ||||||
|  | use Auth; | ||||||
|  | use Crater\Models\CompanySetting; | ||||||
|  | use Crater\Models\CustomField; | ||||||
|  |  | ||||||
|  | class BootstrapController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Handle the incoming request. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @return \Illuminate\Http\JsonResponse | ||||||
|  |      */ | ||||||
|  |     public function __invoke(Request $request) | ||||||
|  |     { | ||||||
|  |         $user = Auth::user(); | ||||||
|  |  | ||||||
|  |         $default_language = $user->getSettings(['language'])['language']; | ||||||
|  |  | ||||||
|  |         $settings = [ | ||||||
|  |             'moment_date_format', | ||||||
|  |             'carbon_date_format', | ||||||
|  |             'fiscal_year', | ||||||
|  |             'time_zone', | ||||||
|  |             'currency' | ||||||
|  |         ]; | ||||||
|  |  | ||||||
|  |         $settings = CompanySetting::getSettings($settings, $user->company_id); | ||||||
|  |  | ||||||
|  |         $default_currency = Currency::findOrFail($settings['currency']); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'user' => $user, | ||||||
|  |             'company' => $user->company, | ||||||
|  |             'currencies' => Currency::all(), | ||||||
|  |             'countries' => Country::all(), | ||||||
|  |             'default_currency' => $default_currency, | ||||||
|  |             'default_language' => $default_language, | ||||||
|  |             'moment_date_format' => $settings['moment_date_format'], | ||||||
|  |             'carbon_date_format' => $settings['carbon_date_format'], | ||||||
|  |             'fiscal_year' => $settings['fiscal_year'], | ||||||
|  |             'time_zone' => $settings['time_zone'] | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										23
									
								
								app/Http/Controllers/V1/General/CountriesController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								app/Http/Controllers/V1/General/CountriesController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,23 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\General; | ||||||
|  |  | ||||||
|  | use Crater\Models\Country; | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  |  | ||||||
|  | class CountriesController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Handle the incoming request. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @return \Illuminate\Http\JsonResponse | ||||||
|  |      */ | ||||||
|  |     public function __invoke(Request $request) | ||||||
|  |     { | ||||||
|  |         return response()->json([ | ||||||
|  |             'countries' => Country::all() | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										25
									
								
								app/Http/Controllers/V1/General/CurrenciesController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								app/Http/Controllers/V1/General/CurrenciesController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\General; | ||||||
|  |  | ||||||
|  | use Crater\Models\Currency; | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  |  | ||||||
|  | class CurrenciesController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Handle the incoming request. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function __invoke(Request $request) | ||||||
|  |     { | ||||||
|  |         $currencies = Currency::latest()->get(); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'currencies' => $currencies | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										23
									
								
								app/Http/Controllers/V1/General/DateFormatsController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								app/Http/Controllers/V1/General/DateFormatsController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,23 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\General; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Space\DateFormatter; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  |  | ||||||
|  | class DateFormatsController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Handle the incoming request. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function __invoke(Request $request) | ||||||
|  |     { | ||||||
|  |         return response()->json([ | ||||||
|  |             'date_formats' => DateFormatter::get_list() | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										22
									
								
								app/Http/Controllers/V1/General/FiscalYearsController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								app/Http/Controllers/V1/General/FiscalYearsController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\General; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  |  | ||||||
|  | class FiscalYearsController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Handle the incoming request. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function __invoke(Request $request) | ||||||
|  |     { | ||||||
|  |         return response()->json([ | ||||||
|  |             'fiscal_years' => config('crater.fiscal_years') | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										22
									
								
								app/Http/Controllers/V1/General/LanguagesController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								app/Http/Controllers/V1/General/LanguagesController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\General; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  |  | ||||||
|  | class LanguagesController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Handle the incoming request. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function __invoke(Request $request) | ||||||
|  |     { | ||||||
|  |         return response()->json([ | ||||||
|  |             'languages' => config('crater.languages') | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										55
									
								
								app/Http/Controllers/V1/General/NextNumberController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								app/Http/Controllers/V1/General/NextNumberController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,55 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\General; | ||||||
|  |  | ||||||
|  | use Crater\Models\Invoice; | ||||||
|  | use Crater\Models\Estimate; | ||||||
|  | use Crater\Models\Payment; | ||||||
|  | use Crater\Models\CompanySetting; | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  |  | ||||||
|  | class NextNumberController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Handle the incoming request. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function __invoke(Request $request) | ||||||
|  |     { | ||||||
|  |         $key = $request->key; | ||||||
|  |  | ||||||
|  |         $val = $key . '_prefix'; | ||||||
|  |  | ||||||
|  |         $prefix = CompanySetting::getSetting( | ||||||
|  |             $val, | ||||||
|  |             $request->header('company') | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         $nextNumber = null; | ||||||
|  |  | ||||||
|  |         switch ($key) { | ||||||
|  |             case 'invoice': | ||||||
|  |                 $nextNumber = Invoice::getNextInvoiceNumber($prefix); | ||||||
|  |                 break; | ||||||
|  |  | ||||||
|  |             case 'estimate': | ||||||
|  |                 $nextNumber = Estimate::getNextEstimateNumber($prefix); | ||||||
|  |                 break; | ||||||
|  |  | ||||||
|  |             case 'payment': | ||||||
|  |                 $nextNumber = Payment::getNextPaymentNumber($prefix); | ||||||
|  |                 break; | ||||||
|  |  | ||||||
|  |             default: | ||||||
|  |                 return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'nextNumber' => $nextNumber, | ||||||
|  |             'prefix' => $prefix | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										88
									
								
								app/Http/Controllers/V1/General/NotesController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								app/Http/Controllers/V1/General/NotesController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,88 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\General; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Http\Requests\NotesRequest; | ||||||
|  | use Crater\Models\Note; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  |  | ||||||
|  | class NotesController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Display a listing of the resource. | ||||||
|  |      * | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function index(Request $request) | ||||||
|  |     { | ||||||
|  |         $limit = $request->limit ?? 10; | ||||||
|  |  | ||||||
|  |         $notes = Note::latest() | ||||||
|  |             ->applyFilters($request->only(['type', 'search'])) | ||||||
|  |             ->paginate($limit); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'notes' => $notes | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Store a newly created resource in storage. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function store(NotesRequest $request) | ||||||
|  |     { | ||||||
|  |         $note = Note::create($request->validated()); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'note' => $note | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Display the specified resource. | ||||||
|  |      * | ||||||
|  |      * @param  \Crater\Models\Note  $note | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function show(Note $note) | ||||||
|  |     { | ||||||
|  |         return response()->json([ | ||||||
|  |             'note' => $note | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Update the specified resource in storage. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @param  \Crater\Models\Note  $note | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function update(NotesRequest $request, Note $note) | ||||||
|  |     { | ||||||
|  |         $note->update($request->validated()); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'note' => $note | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Remove the specified resource from storage. | ||||||
|  |      * | ||||||
|  |      * @param  \Crater\Models\Note  $note | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function destroy(Note $note) | ||||||
|  |     { | ||||||
|  |         $note->delete(); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'success' => true | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										37
									
								
								app/Http/Controllers/V1/General/SearchController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								app/Http/Controllers/V1/General/SearchController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,37 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\General; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Models\User; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  | use Illuminate\Support\Facades\Auth; | ||||||
|  |  | ||||||
|  | class SearchController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Handle the incoming request. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function __invoke(Request $request) | ||||||
|  |     { | ||||||
|  |         $customers = User::where('role', 'customer') | ||||||
|  |             ->applyFilters($request->only(['search'])) | ||||||
|  |             ->latest() | ||||||
|  |             ->paginate(10); | ||||||
|  |  | ||||||
|  |         if (Auth::user()->role == 'super admin') { | ||||||
|  |             $users = User::where('role', 'admin') | ||||||
|  |                 ->applyFilters($request->only(['search'])) | ||||||
|  |                 ->latest() | ||||||
|  |                 ->paginate(10); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'customers' => $customers, | ||||||
|  |             'users' => $users ?? [] | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										23
									
								
								app/Http/Controllers/V1/General/TimezonesController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								app/Http/Controllers/V1/General/TimezonesController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,23 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\General; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Space\TimeZones; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  |  | ||||||
|  | class TimezonesController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Handle the incoming request. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function __invoke(Request $request) | ||||||
|  |     { | ||||||
|  |         return response()->json([ | ||||||
|  |             'time_zones' => TimeZones::get_list() | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,34 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Invoice; | ||||||
|  |  | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Models\Invoice; | ||||||
|  |  | ||||||
|  | class ChangeInvoiceStatusController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |     * Handle the incoming request. | ||||||
|  |     * | ||||||
|  |     * @param  \Illuminate\Http\Request  $request | ||||||
|  |     * @return \Illuminate\Http\JsonResponse | ||||||
|  |     */ | ||||||
|  |    public function __invoke(Request $request, Invoice $invoice) | ||||||
|  |    { | ||||||
|  |         if ($request->status == Invoice::STATUS_SENT) { | ||||||
|  |             $invoice->status = Invoice::STATUS_SENT; | ||||||
|  |             $invoice->sent = true; | ||||||
|  |             $invoice->save(); | ||||||
|  |         } elseif ($request->status == Invoice::STATUS_COMPLETED) { | ||||||
|  |             $invoice->status = Invoice::STATUS_COMPLETED; | ||||||
|  |             $invoice->paid_status = Invoice::STATUS_PAID; | ||||||
|  |             $invoice->due_amount = 0; | ||||||
|  |             $invoice->save(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'success' => true | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										91
									
								
								app/Http/Controllers/V1/Invoice/CloneInvoiceController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								app/Http/Controllers/V1/Invoice/CloneInvoiceController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,91 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Invoice; | ||||||
|  |  | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Models\Invoice; | ||||||
|  | use Carbon\Carbon; | ||||||
|  | use Crater\Models\CompanySetting; | ||||||
|  |  | ||||||
|  | class CloneInvoiceController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Mail a specific invoice to the corresponding customer's email address. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request $request | ||||||
|  |      * @return \Illuminate\Http\JsonResponse | ||||||
|  |      */ | ||||||
|  |     public function __invoke(Request $request, Invoice $invoice) | ||||||
|  |     { | ||||||
|  |         $date = Carbon::now(); | ||||||
|  |  | ||||||
|  |         $invoice_prefix = CompanySetting::getSetting( | ||||||
|  |             'invoice_prefix', | ||||||
|  |             $request->header('company') | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         $newInvoice = Invoice::create([ | ||||||
|  |             'invoice_date' => $date->format('Y-m-d'), | ||||||
|  |             'due_date' => $date->format('Y-m-d'), | ||||||
|  |             'invoice_number' => $invoice_prefix . "-" . Invoice::getNextInvoiceNumber($invoice_prefix), | ||||||
|  |             'reference_number' => $invoice->reference_number, | ||||||
|  |             'user_id' => $invoice->user_id, | ||||||
|  |             'company_id' => $request->header('company'), | ||||||
|  |             'invoice_template_id' => 1, | ||||||
|  |             'status' => Invoice::STATUS_DRAFT, | ||||||
|  |             'paid_status' => Invoice::STATUS_UNPAID, | ||||||
|  |             'sub_total' => $invoice->sub_total, | ||||||
|  |             'discount' => $invoice->discount, | ||||||
|  |             'discount_type' => $invoice->discount_type, | ||||||
|  |             'discount_val' => $invoice->discount_val, | ||||||
|  |             'total' => $invoice->total, | ||||||
|  |             'due_amount' => $invoice->total, | ||||||
|  |             'tax_per_item' => $invoice->tax_per_item, | ||||||
|  |             'discount_per_item' => $invoice->discount_per_item, | ||||||
|  |             'tax' => $invoice->tax, | ||||||
|  |             'notes' => $invoice->notes, | ||||||
|  |             'unique_hash' => str_random(60) | ||||||
|  |         ]); | ||||||
|  |  | ||||||
|  |         $invoice->load('items.taxes'); | ||||||
|  |  | ||||||
|  |         $invoiceItems = $invoice->items->toArray(); | ||||||
|  |  | ||||||
|  |         foreach ($invoiceItems as $invoiceItem) { | ||||||
|  |             $invoiceItem['company_id'] = $request->header('company'); | ||||||
|  |             $invoiceItem['name'] = $invoiceItem['name']; | ||||||
|  |             $item = $newInvoice->items()->create($invoiceItem); | ||||||
|  |  | ||||||
|  |             if (array_key_exists('taxes', $invoiceItem) && $invoiceItem['taxes']) { | ||||||
|  |                 foreach ($invoiceItem['taxes'] as $tax) { | ||||||
|  |                     $tax['company_id'] = $request->header('company'); | ||||||
|  |  | ||||||
|  |                     if ($tax['amount']) { | ||||||
|  |                         $item->taxes()->create($tax); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if ($invoice->taxes) { | ||||||
|  |             foreach ($invoice->taxes->toArray() as $tax) { | ||||||
|  |                 $tax['company_id'] = $request->header('company'); | ||||||
|  |                 $newInvoice->taxes()->create($tax); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $newInvoice = Invoice::with([ | ||||||
|  |                 'items', | ||||||
|  |                 'user', | ||||||
|  |                 'invoiceTemplate', | ||||||
|  |                 'taxes' | ||||||
|  |             ]) | ||||||
|  |             ->find($newInvoice->id); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'invoice' => $newInvoice, | ||||||
|  |             'success' => true | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										20
									
								
								app/Http/Controllers/V1/Invoice/InvoicePdfController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								app/Http/Controllers/V1/Invoice/InvoicePdfController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Invoice; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Models\Invoice; | ||||||
|  |  | ||||||
|  | class InvoicePdfController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Handle the incoming request. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function __invoke(Invoice $invoice) | ||||||
|  |     { | ||||||
|  |         return $invoice->getGeneratedPDFOrStream('invoice'); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,25 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Invoice; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Models\InvoiceTemplate; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  |  | ||||||
|  | class InvoiceTemplatesController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Handle the incoming request. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function __invoke(Request $request) | ||||||
|  |     { | ||||||
|  |         $invoiceTemplates = InvoiceTemplate::all(); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'invoiceTemplates' => $invoiceTemplates | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										128
									
								
								app/Http/Controllers/V1/Invoice/InvoicesController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								app/Http/Controllers/V1/Invoice/InvoicesController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,128 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Invoice; | ||||||
|  |  | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  | use Crater\Http\Requests; | ||||||
|  | use Crater\Models\Invoice; | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Http\Requests\DeleteInvoiceRequest; | ||||||
|  | use Crater\Jobs\GenerateInvoicePdfJob; | ||||||
|  |  | ||||||
|  | class InvoicesController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Display a listing of the resource. | ||||||
|  |      * | ||||||
|  |      * @return \Illuminate\Http\JsonResponse | ||||||
|  |      */ | ||||||
|  |     public function index(Request $request) | ||||||
|  |     { | ||||||
|  |         $limit = $request->has('limit') ? $request->limit : 10; | ||||||
|  |  | ||||||
|  |         $invoices = Invoice::with(['items', 'user', 'creator', 'invoiceTemplate', 'taxes']) | ||||||
|  |             ->join('users', 'users.id', '=', 'invoices.user_id') | ||||||
|  |             ->applyFilters($request->only([ | ||||||
|  |                 'status', | ||||||
|  |                 'paid_status', | ||||||
|  |                 'customer_id', | ||||||
|  |                 'invoice_id', | ||||||
|  |                 'invoice_number', | ||||||
|  |                 'from_date', | ||||||
|  |                 'to_date', | ||||||
|  |                 'orderByField', | ||||||
|  |                 'orderBy', | ||||||
|  |                 'search', | ||||||
|  |             ])) | ||||||
|  |             ->whereCompany($request->header('company')) | ||||||
|  |             ->select('invoices.*', 'users.name') | ||||||
|  |             ->latest() | ||||||
|  |             ->paginateData($limit); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'invoices' => $invoices, | ||||||
|  |             'invoiceTotalCount' => Invoice::count() | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Store a newly created resource in storage. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request $request | ||||||
|  |      * @return \Illuminate\Http\JsonResponse | ||||||
|  |      */ | ||||||
|  |     public function store(Requests\InvoicesRequest $request) | ||||||
|  |     { | ||||||
|  |         $invoice = Invoice::createInvoice($request); | ||||||
|  |  | ||||||
|  |         if ($request->has('invoiceSend')) { | ||||||
|  |             $invoice->send($request->subject, $request->body); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         GenerateInvoicePdfJob::dispatch($invoice); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'invoice' => $invoice | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Display the specified resource. | ||||||
|  |      * | ||||||
|  |      * @param  \Crater\Models\Invoice $invoice | ||||||
|  |      * @return \Illuminate\Http\JsonResponse | ||||||
|  |      */ | ||||||
|  |     public function show(Invoice $invoice) | ||||||
|  |     { | ||||||
|  |         $invoice->load([ | ||||||
|  |             'items', | ||||||
|  |             'items.taxes', | ||||||
|  |             'user', | ||||||
|  |             'invoiceTemplate', | ||||||
|  |             'taxes.taxType', | ||||||
|  |             'fields.customField' | ||||||
|  |         ]); | ||||||
|  |  | ||||||
|  |         $siteData = [ | ||||||
|  |             'invoice' => $invoice, | ||||||
|  |             'nextInvoiceNumber' => $invoice->getInvoiceNumAttribute(), | ||||||
|  |             'invoicePrefix' => $invoice->getInvoicePrefixAttribute(), | ||||||
|  |         ]; | ||||||
|  |  | ||||||
|  |         return response()->json($siteData); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Update the specified resource in storage. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request $request | ||||||
|  |      * @param  Invoice $invoice | ||||||
|  |      * @return \Illuminate\Http\JsonResponse | ||||||
|  |      */ | ||||||
|  |     public function update(Requests\InvoicesRequest $request, Invoice $invoice) | ||||||
|  |     { | ||||||
|  |         $invoice = $invoice->updateInvoice($request); | ||||||
|  |  | ||||||
|  |         GenerateInvoicePdfJob::dispatch($invoice, true); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'invoice' => $invoice, | ||||||
|  |             'success' => true | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * delete the specified resources in storage. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request $request | ||||||
|  |      * @return \Illuminate\Http\JsonResponse | ||||||
|  |      */ | ||||||
|  |     public function delete(DeleteInvoiceRequest $request) | ||||||
|  |     { | ||||||
|  |         Invoice::destroy($request->ids); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'success' => true | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										25
									
								
								app/Http/Controllers/V1/Invoice/SendInvoiceController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								app/Http/Controllers/V1/Invoice/SendInvoiceController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Invoice; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Models\Invoice; | ||||||
|  | use Crater\Http\Requests\SendInvoiceRequest; | ||||||
|  |  | ||||||
|  | class SendInvoiceController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Mail a specific invoice to the corresponding customer's email address. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request $request | ||||||
|  |      * @return \Illuminate\Http\JsonResponse | ||||||
|  |      */ | ||||||
|  |     public function __invoke(SendInvoiceRequest $request, Invoice $invoice) | ||||||
|  |     { | ||||||
|  |         $invoice->send($request->all()); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'success' => true | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										106
									
								
								app/Http/Controllers/V1/Item/ItemsController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								app/Http/Controllers/V1/Item/ItemsController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,106 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Item; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  | use Crater\Http\Requests; | ||||||
|  | use Crater\Http\Requests\DeleteItemsRequest; | ||||||
|  | use Crater\Models\Item; | ||||||
|  | use Crater\Models\TaxType; | ||||||
|  |  | ||||||
|  | class ItemsController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Retrieve a list of existing Items. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request $request | ||||||
|  |      * @return \Illuminate\Http\JsonResponse | ||||||
|  |      */ | ||||||
|  |     public function index(Request $request) | ||||||
|  |     { | ||||||
|  |         $limit = $request->has('limit') ? $request->limit : 10; | ||||||
|  |  | ||||||
|  |         $items = Item::with(['taxes', 'creator']) | ||||||
|  |             ->leftJoin('units', 'units.id', '=', 'items.unit_id') | ||||||
|  |             ->applyFilters($request->only([ | ||||||
|  |                 'search', | ||||||
|  |                 'price', | ||||||
|  |                 'unit_id', | ||||||
|  |                 'item_id', | ||||||
|  |                 'orderByField', | ||||||
|  |                 'orderBy' | ||||||
|  |             ])) | ||||||
|  |             ->whereCompany($request->header('company')) | ||||||
|  |             ->select('items.*', 'units.name as unit_name') | ||||||
|  |             ->latest() | ||||||
|  |             ->paginateData($limit); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'items' => $items, | ||||||
|  |             'taxTypes' => TaxType::latest()->get(), | ||||||
|  |             'itemTotalCount' => Item::count() | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Create Item. | ||||||
|  |      * | ||||||
|  |      * @param  Crater\Http\Requests\ItemsRequest $request | ||||||
|  |      * @return \Illuminate\Http\JsonResponse | ||||||
|  |      */ | ||||||
|  |     public function store(Requests\ItemsRequest $request) | ||||||
|  |     { | ||||||
|  |         $item = Item::createItem($request); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'item' => $item | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * get an existing Item. | ||||||
|  |      * | ||||||
|  |      * @param  Item $item | ||||||
|  |      * @return \Illuminate\Http\JsonResponse | ||||||
|  |      */ | ||||||
|  |     public function show(Item $item) | ||||||
|  |     { | ||||||
|  |         $item->load('taxes'); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'item' => $item | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Update an existing Item. | ||||||
|  |      * | ||||||
|  |      * @param  Crater\Http\Requests\ItemsRequest $request | ||||||
|  |      * @param  \Crater\Models\Item $item | ||||||
|  |      * @return \Illuminate\Http\JsonResponse | ||||||
|  |      */ | ||||||
|  |     public function update(Requests\ItemsRequest $request, Item $item) | ||||||
|  |     { | ||||||
|  |         $item = $item->updateItem($request); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'item' => $item | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Delete a list of existing Items. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request $request | ||||||
|  |      * @return \Illuminate\Http\JsonResponse | ||||||
|  |      */ | ||||||
|  |     public function delete(DeleteItemsRequest $request) | ||||||
|  |     { | ||||||
|  |         Item::destroy($request->ids); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'success' => true | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										109
									
								
								app/Http/Controllers/V1/Item/UnitsController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								app/Http/Controllers/V1/Item/UnitsController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,109 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Item; | ||||||
|  |  | ||||||
|  | use Crater\Models\Unit; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  | use Crater\Http\Requests\UnitRequest; | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  |  | ||||||
|  | class UnitsController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Display a listing of the resource. | ||||||
|  |      * | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function index(Request $request) | ||||||
|  |     { | ||||||
|  |         $limit = $request->has('limit') ? $request->limit : 5; | ||||||
|  |  | ||||||
|  |         $units = Unit::whereCompany($request->header('company')) | ||||||
|  |             ->applyFilters($request->only([ | ||||||
|  |                 'unit_id' | ||||||
|  |             ])) | ||||||
|  |             ->latest() | ||||||
|  |             ->paginateData($limit); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'units' => $units | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Show the form for creating a new resource. | ||||||
|  |      * | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function create() | ||||||
|  |     { | ||||||
|  |         // | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Store a newly created resource in storage. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function store(UnitRequest $request) | ||||||
|  |     { | ||||||
|  |         $data = $request->validated(); | ||||||
|  |         $data['company_id'] = $request->header('company'); | ||||||
|  |         $unit = Unit::create($data); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'unit' => $unit | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Display the specified resource. | ||||||
|  |      * | ||||||
|  |      * @param  \Crater\Models\Unit  $unit | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function show(Unit $unit) | ||||||
|  |     { | ||||||
|  |         return response()->json([ | ||||||
|  |             'unit' => $unit | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Update the specified resource in storage. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @param  \Crater\Models\Unit  $unit | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function update(UnitRequest $request, Unit $unit) | ||||||
|  |     { | ||||||
|  |         $unit->update($request->validated()); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'unit' => $unit | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Remove the specified resource from storage. | ||||||
|  |      * | ||||||
|  |      * @param  \Crater\Models\Unit  $unit | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function destroy(Unit $unit) | ||||||
|  |     { | ||||||
|  |         if ($unit->items()->exists()) { | ||||||
|  |             return response()->json([ | ||||||
|  |                 'error' => 'items_attached' | ||||||
|  |             ]); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $unit->delete(); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'success' => 'Unit deleted successfully' | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										43
									
								
								app/Http/Controllers/V1/Mobile/AuthController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								app/Http/Controllers/V1/Mobile/AuthController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,43 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Mobile; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Models\User; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  | use Illuminate\Support\Facades\Hash; | ||||||
|  | use Illuminate\Validation\ValidationException; | ||||||
|  |  | ||||||
|  | class AuthController extends Controller | ||||||
|  | { | ||||||
|  |     public function login(Request $request) | ||||||
|  |     { | ||||||
|  |         $request->validate([ | ||||||
|  |             'username' => 'required|email', | ||||||
|  |             'password' => 'required', | ||||||
|  |             'device_name' => 'required', | ||||||
|  |         ]); | ||||||
|  |  | ||||||
|  |         $user = User::where('email', $request->username)->first(); | ||||||
|  |  | ||||||
|  |         if (! $user || ! Hash::check($request->password, $user->password)) { | ||||||
|  |             throw ValidationException::withMessages([ | ||||||
|  |                 'email' => ['The provided credentials are incorrect.'], | ||||||
|  |             ]); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'type' => 'Bearer', | ||||||
|  |             'token' => $user->createToken($request->device_name)->plainTextToken | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function logout(Request $request) | ||||||
|  |     { | ||||||
|  |         $request->user()->currentAccessToken()->delete(); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'success' => true | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,46 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Mobile\Customer; | ||||||
|  |  | ||||||
|  | use Barryvdh\DomPDF\PDF; | ||||||
|  | use Crater\Models\Company; | ||||||
|  | use Crater\Models\CompanySetting; | ||||||
|  | use Crater\Models\Estimate; | ||||||
|  | use Crater\Models\EstimateTemplate; | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Mail\EstimateViewedMail; | ||||||
|  | use Crater\Models\User; | ||||||
|  |  | ||||||
|  | class EstimatePdfController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Handle the incoming request. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function __invoke(Estimate $estimate) | ||||||
|  |     { | ||||||
|  |         if ($estimate && ($estimate->status == Estimate::STATUS_SENT || $estimate->status == Estimate::STATUS_DRAFT)) { | ||||||
|  |             $estimate->status = Estimate::STATUS_VIEWED; | ||||||
|  |             $estimate->save(); | ||||||
|  |             $notifyEstimateViewed = CompanySetting::getSetting( | ||||||
|  |                 'notify_estimate_viewed', | ||||||
|  |                 $estimate->company_id | ||||||
|  |             ); | ||||||
|  |  | ||||||
|  |             if ($notifyEstimateViewed == 'YES') { | ||||||
|  |                 $data['estimate'] = Estimate::findOrFail($estimate->id)->toArray(); | ||||||
|  |                 $data['user'] = User::find($estimate->user_id)->toArray(); | ||||||
|  |                 $notificationEmail = CompanySetting::getSetting( | ||||||
|  |                     'notification_email', | ||||||
|  |                     $estimate->company_id | ||||||
|  |                 ); | ||||||
|  |  | ||||||
|  |                 \Mail::to($notificationEmail)->send(new EstimateViewedMail($data)); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $estimate->getGeneratedPDFOrStream('estimate'); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,47 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Mobile\Customer; | ||||||
|  |  | ||||||
|  | use Barryvdh\DomPDF\PDF; | ||||||
|  | use Crater\Models\Company; | ||||||
|  | use Crater\Models\CompanySetting; | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Models\Invoice; | ||||||
|  | use Crater\Models\InvoiceTemplate; | ||||||
|  | use Crater\Mail\InvoiceViewedMail; | ||||||
|  | use Crater\Models\User; | ||||||
|  |  | ||||||
|  | class InvoicePdfController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Handle the incoming request. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function __invoke(Invoice $invoice) | ||||||
|  |     { | ||||||
|  |         if ($invoice && ($invoice->status == Invoice::STATUS_SENT || $invoice->status == Invoice::STATUS_DRAFT)) { | ||||||
|  |             $invoice->status = Invoice::STATUS_VIEWED; | ||||||
|  |             $invoice->viewed = true; | ||||||
|  |             $invoice->save(); | ||||||
|  |             $notifyInvoiceViewed = CompanySetting::getSetting( | ||||||
|  |                 'notify_invoice_viewed', | ||||||
|  |                 $invoice->company_id | ||||||
|  |             ); | ||||||
|  |  | ||||||
|  |             if ($notifyInvoiceViewed == 'YES') { | ||||||
|  |                 $data['invoice'] = Invoice::findOrFail($invoice->id)->toArray(); | ||||||
|  |                 $data['user'] = User::find($invoice->user_id)->toArray(); | ||||||
|  |                 $notificationEmail = CompanySetting::getSetting( | ||||||
|  |                     'notification_email', | ||||||
|  |                     $invoice->company_id | ||||||
|  |                 ); | ||||||
|  |  | ||||||
|  |                 \Mail::to($notificationEmail)->send(new InvoiceViewedMail($data)); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $invoice->getGeneratedPDFOrStream('invoice'); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,91 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Onboarding; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Space\EnvironmentManager; | ||||||
|  | use Crater\Http\Requests\DatabaseEnvironmentRequest; | ||||||
|  | use Illuminate\Support\Facades\Artisan; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  |  | ||||||
|  | class DatabaseConfigurationController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * @var EnvironmentManager | ||||||
|  |      */ | ||||||
|  |     protected $EnvironmentManager; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param EnvironmentManager $environmentManager | ||||||
|  |      */ | ||||||
|  |     public function __construct(EnvironmentManager $environmentManager) | ||||||
|  |     { | ||||||
|  |         $this->environmentManager = $environmentManager; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * | ||||||
|  |      * @param DatabaseEnvironmentRequest $request | ||||||
|  |      */ | ||||||
|  |     public function saveDatabaseEnvironment(DatabaseEnvironmentRequest $request) | ||||||
|  |     { | ||||||
|  |         Artisan::call('config:clear'); | ||||||
|  |         Artisan::call('cache:clear'); | ||||||
|  |  | ||||||
|  |         $results = $this->environmentManager->saveDatabaseVariables($request); | ||||||
|  |  | ||||||
|  |         if (array_key_exists("success", $results)) { | ||||||
|  |             Artisan::call('key:generate --force'); | ||||||
|  |             Artisan::call('config:clear'); | ||||||
|  |             Artisan::call('cache:clear'); | ||||||
|  |             Artisan::call('storage:link'); | ||||||
|  |             Artisan::call('migrate --seed --force'); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return response()->json($results); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getDatabaseEnvironment(Request $request) | ||||||
|  |     { | ||||||
|  |         $databaseData = []; | ||||||
|  |  | ||||||
|  |         switch ($request->connection) { | ||||||
|  |             case 'sqlite': | ||||||
|  |                 $databaseData = [ | ||||||
|  |                     'database_connection' => 'sqlite', | ||||||
|  |                     'database_name' => database_path('database.sqlite'), | ||||||
|  |                 ]; | ||||||
|  |                 break; | ||||||
|  |  | ||||||
|  |             case 'pgsql': | ||||||
|  |                 $databaseData = [ | ||||||
|  |                     'database_connection' => 'pgsql', | ||||||
|  |                     'database_host' => '127.0.0.1', | ||||||
|  |                     'database_port' => 5432, | ||||||
|  |                 ]; | ||||||
|  |                 break; | ||||||
|  |  | ||||||
|  |             case 'mysql': | ||||||
|  |                 $databaseData = [ | ||||||
|  |                     'database_connection' => 'mysql', | ||||||
|  |                     'database_host' => '127.0.0.1', | ||||||
|  |                     'database_port' => 3306, | ||||||
|  |                 ]; | ||||||
|  |                 break; | ||||||
|  |  | ||||||
|  |             case 'sqlsrv': | ||||||
|  |                 $databaseData = [ | ||||||
|  |                     'driver' => 'sqlsrv', | ||||||
|  |                     'host' => '127.0.0.1', | ||||||
|  |                     'port' => 1433, | ||||||
|  |                 ]; | ||||||
|  |                 break; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'config' => $databaseData, | ||||||
|  |             'success' => true | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										25
									
								
								app/Http/Controllers/V1/Onboarding/FinishController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								app/Http/Controllers/V1/Onboarding/FinishController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Onboarding; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Models\User; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  | use Illuminate\Support\Facades\Auth; | ||||||
|  |  | ||||||
|  | class FinishController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Handle the incoming request. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function __invoke(Request $request) | ||||||
|  |     { | ||||||
|  |         \Storage::disk('local')->put('database_created', 'database_created'); | ||||||
|  |  | ||||||
|  |         $user = User::where('role', 'super admin')->first(); | ||||||
|  |         Auth::login($user); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,47 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Onboarding; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Models\Setting; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  |  | ||||||
|  | class OnboardingWizardController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Handle the incoming request. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function getStep(Request $request) | ||||||
|  |     { | ||||||
|  |         if (!\Storage::disk('local')->has('database_created')) { | ||||||
|  |  | ||||||
|  |             return response()->json([ | ||||||
|  |                 'profile_complete' => 0 | ||||||
|  |             ]); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'profile_complete' => Setting::getSetting('profile_complete') | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function updateStep(Request $request) | ||||||
|  |     { | ||||||
|  |         $setting = Setting::getSetting('profile_complete'); | ||||||
|  |  | ||||||
|  |         if ($setting === 'COMPLETED') { | ||||||
|  |             return response()->json([ | ||||||
|  |                 'profile_complete' => $setting | ||||||
|  |             ]); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         Setting::setSetting('profile_complete', $request->profile_complete); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'profile_complete' => Setting::getSetting('profile_complete') | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -1,9 +1,10 @@ | |||||||
| <?php | <?php | ||||||
| 
 | 
 | ||||||
| namespace Crater\Http\Controllers; | namespace Crater\Http\Controllers\V1\Onboarding; | ||||||
| 
 | 
 | ||||||
| use Crater\Space\PermissionsChecker; | use Crater\Space\PermissionsChecker; | ||||||
| use Illuminate\Http\JsonResponse; | use Illuminate\Http\JsonResponse; | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
| 
 | 
 | ||||||
| class PermissionsController extends Controller | class PermissionsController extends Controller | ||||||
| { | { | ||||||
| @ -1,9 +1,10 @@ | |||||||
| <?php | <?php | ||||||
| 
 | 
 | ||||||
| namespace Crater\Http\Controllers; | namespace Crater\Http\Controllers\V1\Onboarding; | ||||||
| 
 | 
 | ||||||
| use Crater\Space\RequirementsChecker; | use Crater\Space\RequirementsChecker; | ||||||
| use Illuminate\Http\JsonResponse; | use Illuminate\Http\JsonResponse; | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
| 
 | 
 | ||||||
| class RequirementsController extends Controller | class RequirementsController extends Controller | ||||||
| { | { | ||||||
							
								
								
									
										100
									
								
								app/Http/Controllers/V1/Payment/PaymentMethodsController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								app/Http/Controllers/V1/Payment/PaymentMethodsController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,100 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Payment; | ||||||
|  |  | ||||||
|  | use Crater\Models\PaymentMethod; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  | use Crater\Http\Requests\PaymentMethodRequest; | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  |  | ||||||
|  | class PaymentMethodsController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Display a listing of the resource. | ||||||
|  |      * | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function index(Request $request) | ||||||
|  |     { | ||||||
|  |         $limit = $request->has('limit') ? $request->limit : 5; | ||||||
|  |  | ||||||
|  |         $paymentMethods = PaymentMethod::whereCompany($request->header('company')) | ||||||
|  |             ->applyFilters($request->only([ | ||||||
|  |                 'method_id', | ||||||
|  |                 'search' | ||||||
|  |             ])) | ||||||
|  |             ->latest() | ||||||
|  |             ->paginateData($limit); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'paymentMethods' => $paymentMethods | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Store a newly created resource in storage. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function store(PaymentMethodRequest $request) | ||||||
|  |     { | ||||||
|  |         $paymentMethod = PaymentMethod::createPaymentMethod($request); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'paymentMethod' => $paymentMethod | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Display the specified resource. | ||||||
|  |      * | ||||||
|  |      * @param  \Crater\Models\PaymentMethod  $paymentMethod | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function show(PaymentMethod $paymentMethod) | ||||||
|  |     { | ||||||
|  |         return response()->json([ | ||||||
|  |             'paymentMethod' => $paymentMethod | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Update the specified resource in storage. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @param  \Crater\Models\PaymentMethod  $paymentMethod | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function update(PaymentMethodRequest $request, PaymentMethod $paymentMethod) | ||||||
|  |     { | ||||||
|  |         $paymentMethod->update($request->validated()); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'paymentMethod' => $paymentMethod | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Remove the specified resource from storage. | ||||||
|  |      * | ||||||
|  |      * @param  \Crater\Models\PaymentMethod  $paymentMethod | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function destroy(PaymentMethod $paymentMethod) | ||||||
|  |     { | ||||||
|  |         $payments = $paymentMethod->payments; | ||||||
|  |  | ||||||
|  |         if ($payments->count() > 0) { | ||||||
|  |             return response()->json([ | ||||||
|  |                 'error' => 'payments_attached' | ||||||
|  |             ]); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $paymentMethod->delete(); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'success' => 'Payment method deleted successfully' | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										20
									
								
								app/Http/Controllers/V1/Payment/PaymentPdfController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								app/Http/Controllers/V1/Payment/PaymentPdfController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Payment; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Models\Payment; | ||||||
|  |  | ||||||
|  | class PaymentPdfController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Handle the incoming request. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function __invoke(Payment $payment) | ||||||
|  |     { | ||||||
|  |         return $payment->getGeneratedPDFOrStream('payment'); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										96
									
								
								app/Http/Controllers/V1/Payment/PaymentsController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								app/Http/Controllers/V1/Payment/PaymentsController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,96 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Payment; | ||||||
|  |  | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  | use Crater\Models\Payment; | ||||||
|  | use Crater\Http\Requests\DeletePaymentsRequest; | ||||||
|  | use Crater\Http\Requests\PaymentRequest; | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  |  | ||||||
|  | class PaymentsController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Display a listing of the resource. | ||||||
|  |      * | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function index(Request $request) | ||||||
|  |     { | ||||||
|  |         $limit = $request->has('limit') ? $request->limit : 10; | ||||||
|  |  | ||||||
|  |         $payments = Payment::with(['user', 'invoice', 'paymentMethod', 'creator']) | ||||||
|  |             ->join('users', 'users.id', '=', 'payments.user_id') | ||||||
|  |             ->leftJoin('invoices', 'invoices.id', '=', 'payments.invoice_id') | ||||||
|  |             ->leftJoin('payment_methods', 'payment_methods.id', '=', 'payments.payment_method_id') | ||||||
|  |             ->applyFilters($request->only([ | ||||||
|  |                 'search', | ||||||
|  |                 'payment_number', | ||||||
|  |                 'payment_id', | ||||||
|  |                 'payment_method_id', | ||||||
|  |                 'customer_id', | ||||||
|  |                 'orderByField', | ||||||
|  |                 'orderBy' | ||||||
|  |             ])) | ||||||
|  |             ->whereCompany($request->header('company')) | ||||||
|  |             ->select('payments.*', 'users.name', 'invoices.invoice_number', 'payment_methods.name as payment_mode') | ||||||
|  |             ->latest() | ||||||
|  |             ->paginateData($limit); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'payments' => $payments, | ||||||
|  |             'paymentTotalCount' => Payment::count() | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Store a newly created resource in storage. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @return \Illuminate\Http\Response | ||||||
|  |      */ | ||||||
|  |     public function store(PaymentRequest $request) | ||||||
|  |     { | ||||||
|  |         $payment = Payment::createPayment($request); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'payment' => $payment, | ||||||
|  |             'success' => true | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function show(Request $request, Payment $payment) | ||||||
|  |     { | ||||||
|  |         $payment->load([ | ||||||
|  |             'user', | ||||||
|  |             'invoice', | ||||||
|  |             'paymentMethod', | ||||||
|  |             'fields.customField' | ||||||
|  |         ]); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'nextPaymentNumber' => $payment->getPaymentNumAttribute(), | ||||||
|  |             'payment_prefix' => $payment->getPaymentPrefixAttribute(), | ||||||
|  |             'payment' => $payment, | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function update(PaymentRequest $request, Payment $payment) | ||||||
|  |     { | ||||||
|  |         $payment = $payment->updatePayment($request); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'payment' => $payment, | ||||||
|  |             'success' => true | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function delete(DeletePaymentsRequest $request) | ||||||
|  |     { | ||||||
|  |         Payment::deletePayments($request->ids); | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'success' => true | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										23
									
								
								app/Http/Controllers/V1/Payment/SendPaymentController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								app/Http/Controllers/V1/Payment/SendPaymentController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,23 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Payment; | ||||||
|  |  | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Crater\Models\Payment; | ||||||
|  | use Crater\Http\Requests\SendPaymentRequest; | ||||||
|  |  | ||||||
|  | class SendPaymentController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Handle the incoming request. | ||||||
|  |      * | ||||||
|  |      * @param  \Illuminate\Http\Request  $request | ||||||
|  |      * @return \Illuminate\Http\JsonResponse | ||||||
|  |      */ | ||||||
|  |     public function __invoke(SendPaymentRequest $request, Payment $payment) | ||||||
|  |     { | ||||||
|  |         $response = $payment->send($request->all()); | ||||||
|  |  | ||||||
|  |         return response()->json($response); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,92 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Report; | ||||||
|  |  | ||||||
|  | use Illuminate\Support\Facades\App; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  | use Crater\Models\Company; | ||||||
|  | use PDF; | ||||||
|  | use Carbon\Carbon; | ||||||
|  | use Crater\Models\User; | ||||||
|  | use Crater\Models\CompanySetting; | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  |  | ||||||
|  | class CustomerSalesReportController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |     * Handle the incoming request. | ||||||
|  |     * | ||||||
|  |     * @param  \Illuminate\Http\Request  $request | ||||||
|  |     * @param  string  $hash | ||||||
|  |     * @return \Illuminate\Http\JsonResponse | ||||||
|  |     */ | ||||||
|  |     public function __invoke(Request $request, $hash) | ||||||
|  |     { | ||||||
|  |         $company = Company::where('unique_hash', $hash)->first(); | ||||||
|  |  | ||||||
|  |         $locale = CompanySetting::getSetting('language',  $company->id); | ||||||
|  |  | ||||||
|  |         App::setLocale($locale); | ||||||
|  |  | ||||||
|  |         $start = Carbon::createFromFormat('Y-m-d', $request->from_date); | ||||||
|  |         $end = Carbon::createFromFormat('Y-m-d', $request->to_date); | ||||||
|  |  | ||||||
|  |         $customers = User::with(['invoices' => function ($query) use ($start, $end) { | ||||||
|  |                 $query->whereBetween( | ||||||
|  |                     'invoice_date', | ||||||
|  |                     [$start->format('Y-m-d'), $end->format('Y-m-d')] | ||||||
|  |                 ); | ||||||
|  |             }]) | ||||||
|  |             ->customer() | ||||||
|  |             ->whereCompany($company->id) | ||||||
|  |             ->applyInvoiceFilters($request->only(['from_date', 'to_date'])) | ||||||
|  |             ->get(); | ||||||
|  |  | ||||||
|  |         $totalAmount = 0; | ||||||
|  |         foreach ($customers as $customer) { | ||||||
|  |             $customerTotalAmount = 0; | ||||||
|  |             foreach ($customer->invoices as $invoice) { | ||||||
|  |                 $customerTotalAmount += $invoice->total; | ||||||
|  |             } | ||||||
|  |             $customer->totalAmount = $customerTotalAmount; | ||||||
|  |             $totalAmount += $customerTotalAmount; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $dateFormat = CompanySetting::getSetting('carbon_date_format', $company->id); | ||||||
|  |         $from_date = Carbon::createFromFormat('Y-m-d', $request->from_date)->format($dateFormat); | ||||||
|  |         $to_date = Carbon::createFromFormat('Y-m-d', $request->to_date)->format($dateFormat); | ||||||
|  |  | ||||||
|  |         $colors = [ | ||||||
|  |             'primary_text_color', | ||||||
|  |             'heading_text_color', | ||||||
|  |             'section_heading_text_color', | ||||||
|  |             'border_color', | ||||||
|  |             'body_text_color', | ||||||
|  |             'footer_text_color', | ||||||
|  |             'footer_total_color', | ||||||
|  |             'footer_bg_color', | ||||||
|  |             'date_text_color' | ||||||
|  |         ]; | ||||||
|  |  | ||||||
|  |         $colorSettings = CompanySetting::whereIn('option', $colors) | ||||||
|  |             ->whereCompany($company->id) | ||||||
|  |             ->get(); | ||||||
|  |  | ||||||
|  |         view()->share([ | ||||||
|  |             'customers' => $customers, | ||||||
|  |             'totalAmount' => $totalAmount, | ||||||
|  |             'colorSettings' => $colorSettings, | ||||||
|  |             'company' => $company, | ||||||
|  |             'from_date' => $from_date, | ||||||
|  |             'to_date' => $to_date | ||||||
|  |         ]); | ||||||
|  |  | ||||||
|  |         $pdf = PDF::loadView('app.pdf.reports.sales-customers'); | ||||||
|  |  | ||||||
|  |         if ($request->has('download')) { | ||||||
|  |             return $pdf->download(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $pdf->stream(); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										77
									
								
								app/Http/Controllers/V1/Report/ExpensesReportController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								app/Http/Controllers/V1/Report/ExpensesReportController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,77 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Report; | ||||||
|  |  | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  | use Crater\Models\Company; | ||||||
|  | use PDF; | ||||||
|  | use Carbon\Carbon; | ||||||
|  | use Crater\Models\Expense; | ||||||
|  | use Crater\Models\CompanySetting; | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Illuminate\Support\Facades\App; | ||||||
|  |  | ||||||
|  | class ExpensesReportController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |     * Handle the incoming request. | ||||||
|  |     * | ||||||
|  |     * @param  \Illuminate\Http\Request  $request | ||||||
|  |     * @param  string  $hash | ||||||
|  |     * @return \Illuminate\Http\JsonResponse | ||||||
|  |     */ | ||||||
|  |     public function __invoke(Request $request, $hash) | ||||||
|  |     { | ||||||
|  |         $company = Company::where('unique_hash', $hash)->first(); | ||||||
|  |  | ||||||
|  |         $locale = CompanySetting::getSetting('language',  $company->id); | ||||||
|  |  | ||||||
|  |         App::setLocale($locale); | ||||||
|  |  | ||||||
|  |         $expenseCategories = Expense::with('category') | ||||||
|  |         ->whereCompany($company->id) | ||||||
|  |             ->applyFilters($request->only(['from_date', 'to_date'])) | ||||||
|  |             ->expensesAttributes() | ||||||
|  |             ->get(); | ||||||
|  |  | ||||||
|  |         $totalAmount = 0; | ||||||
|  |         foreach ($expenseCategories as $category) { | ||||||
|  |             $totalAmount += $category->total_amount; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $dateFormat = CompanySetting::getSetting('carbon_date_format', $company->id); | ||||||
|  |         $from_date = Carbon::createFromFormat('Y-m-d', $request->from_date)->format($dateFormat); | ||||||
|  |         $to_date = Carbon::createFromFormat('Y-m-d', $request->to_date)->format($dateFormat); | ||||||
|  |  | ||||||
|  |         $colors = [ | ||||||
|  |             'primary_text_color', | ||||||
|  |             'heading_text_color', | ||||||
|  |             'section_heading_text_color', | ||||||
|  |             'border_color', | ||||||
|  |             'body_text_color', | ||||||
|  |             'footer_text_color', | ||||||
|  |             'footer_total_color', | ||||||
|  |             'footer_bg_color', | ||||||
|  |             'date_text_color' | ||||||
|  |         ]; | ||||||
|  |         $colorSettings = CompanySetting::whereIn('option', $colors) | ||||||
|  |             ->whereCompany($company->id) | ||||||
|  |             ->get(); | ||||||
|  |  | ||||||
|  |         view()->share([ | ||||||
|  |             'expenseCategories' => $expenseCategories, | ||||||
|  |             'colorSettings' => $colorSettings, | ||||||
|  |             'totalExpense' => $totalAmount, | ||||||
|  |             'company' => $company, | ||||||
|  |             'from_date' => $from_date, | ||||||
|  |             'to_date' => $to_date | ||||||
|  |         ]); | ||||||
|  |         $pdf = PDF::loadView('app.pdf.reports.expenses'); | ||||||
|  |  | ||||||
|  |         if ($request->has('download')) { | ||||||
|  |             return $pdf->download(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $pdf->stream(); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										76
									
								
								app/Http/Controllers/V1/Report/ItemSalesReportController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								app/Http/Controllers/V1/Report/ItemSalesReportController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,76 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Report; | ||||||
|  |  | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  | use Crater\Models\Company; | ||||||
|  | use PDF; | ||||||
|  | use Carbon\Carbon; | ||||||
|  | use Crater\Models\InvoiceItem; | ||||||
|  | use Crater\Models\CompanySetting; | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Illuminate\Support\Facades\App; | ||||||
|  |  | ||||||
|  | class ItemSalesReportController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |     * Handle the incoming request. | ||||||
|  |     * | ||||||
|  |     * @param  \Illuminate\Http\Request  $request | ||||||
|  |     * @param  string  $hash | ||||||
|  |     * @return \Illuminate\Http\JsonResponse | ||||||
|  |     */ | ||||||
|  |     public function __invoke(Request $request, $hash) | ||||||
|  |     { | ||||||
|  |         $company = Company::where('unique_hash', $hash)->first(); | ||||||
|  |  | ||||||
|  |         $locale = CompanySetting::getSetting('language',  $company->id); | ||||||
|  |  | ||||||
|  |         App::setLocale($locale); | ||||||
|  |  | ||||||
|  |         $items = InvoiceItem::whereCompany($company->id) | ||||||
|  |             ->applyInvoiceFilters($request->only(['from_date', 'to_date'])) | ||||||
|  |             ->itemAttributes() | ||||||
|  |             ->get(); | ||||||
|  |  | ||||||
|  |         $totalAmount = 0; | ||||||
|  |         foreach ($items as $item) { | ||||||
|  |             $totalAmount += $item->total_amount; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $dateFormat = CompanySetting::getSetting('carbon_date_format', $company->id); | ||||||
|  |         $from_date = Carbon::createFromFormat('Y-m-d', $request->from_date)->format($dateFormat); | ||||||
|  |         $to_date = Carbon::createFromFormat('Y-m-d', $request->to_date)->format($dateFormat); | ||||||
|  |  | ||||||
|  |         $colors = [ | ||||||
|  |             'primary_text_color', | ||||||
|  |             'heading_text_color', | ||||||
|  |             'section_heading_text_color', | ||||||
|  |             'border_color', | ||||||
|  |             'body_text_color', | ||||||
|  |             'footer_text_color', | ||||||
|  |             'footer_total_color', | ||||||
|  |             'footer_bg_color', | ||||||
|  |             'date_text_color' | ||||||
|  |         ]; | ||||||
|  |         $colorSettings = CompanySetting::whereIn('option', $colors) | ||||||
|  |             ->whereCompany($company->id) | ||||||
|  |             ->get(); | ||||||
|  |  | ||||||
|  |         view()->share([ | ||||||
|  |             'items' => $items, | ||||||
|  |             'colorSettings' => $colorSettings, | ||||||
|  |             'totalAmount' => $totalAmount, | ||||||
|  |             'company' => $company, | ||||||
|  |             'from_date' => $from_date, | ||||||
|  |             'to_date' => $to_date | ||||||
|  |         ]); | ||||||
|  |         $pdf = PDF::loadView('app.pdf.reports.sales-items'); | ||||||
|  |  | ||||||
|  |         if ($request->has('download')) { | ||||||
|  |             return $pdf->download(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $pdf->stream(); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,85 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Http\Controllers\V1\Report; | ||||||
|  |  | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  | use Crater\Models\Company; | ||||||
|  | use PDF; | ||||||
|  | use Carbon\Carbon; | ||||||
|  | use Crater\Models\Invoice; | ||||||
|  | use Crater\Models\Expense; | ||||||
|  | use Crater\Models\CompanySetting; | ||||||
|  | use Crater\Http\Controllers\Controller; | ||||||
|  | use Illuminate\Support\Facades\App; | ||||||
|  |  | ||||||
|  | class ProfitLossReportController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |     * Handle the incoming request. | ||||||
|  |     * | ||||||
|  |     * @param  \Illuminate\Http\Request  $request | ||||||
|  |     * @param  string  $hash | ||||||
|  |     * @return \Illuminate\Http\JsonResponse | ||||||
|  |     */ | ||||||
|  |     public function __invoke(Request $request, $hash) | ||||||
|  |     { | ||||||
|  |         $company = Company::where('unique_hash', $hash)->first(); | ||||||
|  |  | ||||||
|  |         $locale = CompanySetting::getSetting('language',  $company->id); | ||||||
|  |  | ||||||
|  |         App::setLocale($locale); | ||||||
|  |  | ||||||
|  |         $invoicesAmount = Invoice::whereCompany($company->id) | ||||||
|  |             ->applyFilters($request->only(['from_date', 'to_date'])) | ||||||
|  |             ->wherePaidStatus(Invoice::STATUS_PAID) | ||||||
|  |             ->sum('total'); | ||||||
|  |  | ||||||
|  |         $expenseCategories = Expense::with('category') | ||||||
|  |         ->whereCompany($company->id) | ||||||
|  |             ->applyFilters($request->only(['from_date', 'to_date'])) | ||||||
|  |             ->expensesAttributes() | ||||||
|  |             ->get(); | ||||||
|  |  | ||||||
|  |         $totalAmount = 0; | ||||||
|  |         foreach ($expenseCategories as $category) { | ||||||
|  |             $totalAmount += $category->total_amount; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $dateFormat = CompanySetting::getSetting('carbon_date_format', $company->id); | ||||||
|  |         $from_date = Carbon::createFromFormat('Y-m-d', $request->from_date)->format($dateFormat); | ||||||
|  |         $to_date = Carbon::createFromFormat('Y-m-d', $request->to_date)->format($dateFormat); | ||||||
|  |  | ||||||
|  |         $colors = [ | ||||||
|  |             'primary_text_color', | ||||||
|  |             'heading_text_color', | ||||||
|  |             'section_heading_text_color', | ||||||
|  |             'border_color', | ||||||
|  |             'body_text_color', | ||||||
|  |             'footer_text_color', | ||||||
|  |             'footer_total_color', | ||||||
|  |             'footer_bg_color', | ||||||
|  |             'date_text_color' | ||||||
|  |         ]; | ||||||
|  |         $colorSettings = CompanySetting::whereIn('option', $colors) | ||||||
|  |             ->whereCompany($company->id) | ||||||
|  |             ->get(); | ||||||
|  |  | ||||||
|  |         view()->share([ | ||||||
|  |             'company' => $company, | ||||||
|  |             'income' => $invoicesAmount, | ||||||
|  |             'expenseCategories' => $expenseCategories, | ||||||
|  |             'totalExpense' => $totalAmount, | ||||||
|  |             'colorSettings' => $colorSettings, | ||||||
|  |             'company' => $company, | ||||||
|  |             'from_date' => $from_date, | ||||||
|  |             'to_date' => $to_date | ||||||
|  |         ]); | ||||||
|  |         $pdf = PDF::loadView('app.pdf.reports.profit-loss'); | ||||||
|  |  | ||||||
|  |         if ($request->has('download')) { | ||||||
|  |             return $pdf->download(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $pdf->stream(); | ||||||
|  |     } | ||||||
|  | } | ||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user
	