mirror of
				https://github.com/crater-invoice/crater.git
				synced 2025-10-29 12:41:10 -04:00 
			
		
		
		
	Compare commits
	
		
			77 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 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 | |||
| 9424dc6c27 | |||
| 3692373cd2 | |||
| 7bba576dca | |||
| 05454af593 | |||
| 74fe481ed5 | |||
| 1cd654b0cc | |||
| 0c71356f59 | |||
| e539bb501d | |||
| 2fcd169270 | |||
| 14d71fedb3 | |||
| 7fe9a4c2a2 | |||
| 7b697a477e | |||
| 146cf835b9 | |||
| ec87e72547 | |||
| bf2e8c9c99 | |||
| b6096aadfa | |||
| 1cbc41c3ce | |||
| 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 | ||||||
| @ -1,15 +1,15 @@ | |||||||
| 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 | ||||||
|  | |||||||
							
								
								
									
										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. | ||||||
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -11,3 +11,5 @@ Homestead.yaml | |||||||
| .rnd | .rnd | ||||||
| /.expo | /.expo | ||||||
| /.vscode | /.vscode | ||||||
|  | docker-compose.yml | ||||||
|  | docker-compose.yaml | ||||||
|  | |||||||
							
								
								
									
										52
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,52 @@ | |||||||
|  | ##### STAGE 1 ##### | ||||||
|  |  | ||||||
|  | FROM composer as composer | ||||||
|  |  | ||||||
|  | # Copy composer files from project root into composer container's working dir | ||||||
|  | COPY composer.* /app/ | ||||||
|  |  | ||||||
|  | # Copy database directory for autoloader optimization | ||||||
|  | COPY database /app/database | ||||||
|  |  | ||||||
|  | # Run composer to build dependencies in vendor folder | ||||||
|  | RUN composer install --no-scripts --no-suggest --no-interaction --prefer-dist --optimize-autoloader  | ||||||
|  |  | ||||||
|  | # Copy everything from project root into composer container's working dir | ||||||
|  | COPY . /app | ||||||
|  |   | ||||||
|  | RUN composer dump-autoload --optimize --classmap-authoritative | ||||||
|  |  | ||||||
|  | ##### STAGE 2 ##### | ||||||
|  |  | ||||||
|  | FROM php:7.3.12-fpm-alpine | ||||||
|  |  | ||||||
|  | # Use the default production configuration | ||||||
|  | RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" | ||||||
|  |  | ||||||
|  | RUN apk add --no-cache libpng-dev libxml2-dev oniguruma-dev && \ | ||||||
|  |     docker-php-ext-install bcmath ctype json gd mbstring pdo pdo_mysql tokenizer xml | ||||||
|  |  | ||||||
|  | # Set container's working dir | ||||||
|  | WORKDIR /app | ||||||
|  |   | ||||||
|  | # Copy everything from project root into php container's working dir | ||||||
|  | COPY . /app | ||||||
|  |  | ||||||
|  | # Copy vendor folder from composer container into php container | ||||||
|  | COPY --from=composer /app/vendor /app/vendor | ||||||
|  |  | ||||||
|  | RUN touch database/database.sqlite && \ | ||||||
|  |     cp .env.example .env && \ | ||||||
|  |     php artisan config:cache && \ | ||||||
|  |     php artisan passport:keys && \ | ||||||
|  |     php artisan key:generate && \ | ||||||
|  |     chown -R www-data:www-data . && \ | ||||||
|  |     chmod -R 755 . && \ | ||||||
|  |     chmod -R 775 storage/framework/ && \ | ||||||
|  |     chmod -R 775 storage/logs/ && \ | ||||||
|  |     chmod -R 775 bootstrap/cache/   | ||||||
|  |  | ||||||
|  | EXPOSE 9000 | ||||||
|  |  | ||||||
|  | CMD ["php-fpm", "--nodaemonize"] | ||||||
|  |  | ||||||
| @ -49,15 +49,20 @@ class Estimate extends Model | |||||||
|     ]; |     ]; | ||||||
|  |  | ||||||
|     protected $casts = [ |     protected $casts = [ | ||||||
|         'total' => 'float', |         'total' => 'integer', | ||||||
|         'tax' => 'float', |         'tax' => 'integer', | ||||||
|         'sub_total' => 'float' |         'sub_total' => 'integer', | ||||||
|  |         'discount' => 'float', | ||||||
|  |         'discount_val' => 'integer', | ||||||
|     ]; |     ]; | ||||||
|  |  | ||||||
|     public static function getNextEstimateNumber() |     public static function getNextEstimateNumber($value) | ||||||
|     { |     { | ||||||
|         // Get the last created order |          // Get the last created order | ||||||
|         $lastOrder = Estimate::orderBy('created_at', 'desc')->first(); |          $lastOrder = Estimate::where('estimate_number', 'LIKE', $value . '-%') | ||||||
|  |                         ->orderBy('created_at', 'desc') | ||||||
|  |                         ->first(); | ||||||
|  |  | ||||||
|         if (!$lastOrder) { |         if (!$lastOrder) { | ||||||
|             // We get here if there is no order at all |             // 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. |             // If there is no number set it to 0, which will be 1 at the end. | ||||||
| @ -99,10 +104,16 @@ class Estimate extends Model | |||||||
|  |  | ||||||
|     public function getEstimateNumAttribute() |     public function getEstimateNumAttribute() | ||||||
|     { |     { | ||||||
|         $position = $this->strposX($this->estimate_number, "-", 2) + 1; |         $position = $this->strposX($this->estimate_number, "-", 1) + 1; | ||||||
|         return substr($this->estimate_number, $position); |         return substr($this->estimate_number, $position); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     public function getEstimatePrefixAttribute() | ||||||
|  |     { | ||||||
|  |         $prefix = explode("-",$this->estimate_number)[0]; | ||||||
|  |         return $prefix; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     private function strposX($haystack, $needle, $number) |     private function strposX($haystack, $needle, $number) | ||||||
|     { |     { | ||||||
|         if ($number == '1') { |         if ($number == '1') { | ||||||
|  | |||||||
| @ -153,6 +153,58 @@ class CompanyController extends Controller | |||||||
|         ]); |         ]); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     public function getCustomizeSetting (Request $request) | ||||||
|  |     { | ||||||
|  |         $invoice_prefix = CompanySetting::getSetting('invoice_prefix', $request->header('company')); | ||||||
|  |         $invoice_auto_generate = CompanySetting::getSetting('invoice_auto_generate', $request->header('company')); | ||||||
|  |  | ||||||
|  |         $estimate_prefix = CompanySetting::getSetting('estimate_prefix', $request->header('company')); | ||||||
|  |         $estimate_auto_generate  = CompanySetting::getSetting('estimate_auto_generate', $request->header('company')); | ||||||
|  |  | ||||||
|  |         $payment_prefix = CompanySetting::getSetting('payment_prefix', $request->header('company')); | ||||||
|  |         $payment_auto_generate = CompanySetting::getSetting('payment_auto_generate', $request->header('company')); | ||||||
|  |  | ||||||
|  |         return  response()->json([ | ||||||
|  |             'invoice_prefix' => $invoice_prefix, | ||||||
|  |             'invoice_auto_generate' => $invoice_auto_generate, | ||||||
|  |             'estimate_prefix' => $estimate_prefix, | ||||||
|  |             'estimate_auto_generate' => $estimate_auto_generate, | ||||||
|  |             'payment_prefix' => $payment_prefix, | ||||||
|  |             'payment_auto_generate' => $payment_auto_generate, | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function updateCustomizeSetting (Request $request) | ||||||
|  |     { | ||||||
|  |         $sets = []; | ||||||
|  |  | ||||||
|  |         if ($request->type == "PAYMENTS") { | ||||||
|  |             $sets = [ | ||||||
|  |                 'payment_prefix' | ||||||
|  |             ]; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if ($request->type == "INVOICES") { | ||||||
|  |             $sets = [ | ||||||
|  |                 'invoice_prefix', | ||||||
|  |             ]; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if ($request->type == "ESTIMATES") { | ||||||
|  |             $sets = [ | ||||||
|  |                 'estimate_prefix', | ||||||
|  |             ]; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         foreach ($sets as $key) { | ||||||
|  |             CompanySetting::setSetting($key, $request->$key, $request->header('company')); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return response()->json([ | ||||||
|  |             'success' => true | ||||||
|  |         ]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     public function updateSetting(SettingRequest $request) |     public function updateSetting(SettingRequest $request) | ||||||
|     { |     { | ||||||
|         CompanySetting::setSetting($request->key, $request->value, $request->header('company')); |         CompanySetting::setSetting($request->key, $request->value, $request->header('company')); | ||||||
|  | |||||||
| @ -177,6 +177,7 @@ class CustomersController extends Controller | |||||||
|         $customer->enable_portal = $request->enable_portal; |         $customer->enable_portal = $request->enable_portal; | ||||||
|         $customer->save(); |         $customer->save(); | ||||||
|  |  | ||||||
|  |         $customer->addresses()->delete(); | ||||||
|         if ($request->addresses) { |         if ($request->addresses) { | ||||||
|             foreach ($request->addresses as $address) { |             foreach ($request->addresses as $address) { | ||||||
|                 $newAddress = $customer->addresses()->firstOrNew(['type' => $address["type"]]); |                 $newAddress = $customer->addresses()->firstOrNew(['type' => $address["type"]]); | ||||||
|  | |||||||
| @ -56,25 +56,43 @@ class EstimatesController extends Controller | |||||||
|  |  | ||||||
|     public function create(Request $request) |     public function create(Request $request) | ||||||
|     { |     { | ||||||
|         $nextEstimateNumber = 'EST-'.Estimate::getNextEstimateNumber(); |         $estimate_prefix = CompanySetting::getSetting('estimate_prefix', $request->header('company')); | ||||||
|  |         $estimate_num_auto_generate = CompanySetting::getSetting('estimate_auto_generate', $request->header('company')); | ||||||
|  |  | ||||||
|  |         $nextEstimateNumberAttribute = null; | ||||||
|  |         $nextEstimateNumber = Estimate::getNextEstimateNumber($estimate_prefix); | ||||||
|  |  | ||||||
|  |         if ($estimate_num_auto_generate == "YES") { | ||||||
|  |             $nextEstimateNumberAttribute = $nextEstimateNumber; | ||||||
|  |         } | ||||||
|  |  | ||||||
|         $tax_per_item = CompanySetting::getSetting('tax_per_item', $request->header('company')); |         $tax_per_item = CompanySetting::getSetting('tax_per_item', $request->header('company')); | ||||||
|         $discount_per_item = CompanySetting::getSetting('discount_per_item', $request->header('company')); |         $discount_per_item = CompanySetting::getSetting('discount_per_item', $request->header('company')); | ||||||
|         $customers = User::where('role', 'customer')->get(); |         $customers = User::where('role', 'customer')->get(); | ||||||
|  |  | ||||||
|         return response()->json([ |         return response()->json([ | ||||||
|             'customers' => $customers, |             'customers' => $customers, | ||||||
|             'nextEstimateNumber' => $nextEstimateNumber, |             'nextEstimateNumberAttribute' => $nextEstimateNumberAttribute, | ||||||
|  |             'nextEstimateNumber' => $estimate_prefix.'-'.$nextEstimateNumber, | ||||||
|             'taxes' => Tax::whereCompany($request->header('company'))->latest()->get(), |             'taxes' => Tax::whereCompany($request->header('company'))->latest()->get(), | ||||||
|             'items' => Item::whereCompany($request->header('company'))->get(), |             'items' => Item::whereCompany($request->header('company'))->get(), | ||||||
|             'tax_per_item' => $tax_per_item, |             'tax_per_item' => $tax_per_item, | ||||||
|             'discount_per_item' => $discount_per_item, |             'discount_per_item' => $discount_per_item, | ||||||
|             'estimateTemplates' => EstimateTemplate::all(), |             'estimateTemplates' => EstimateTemplate::all(), | ||||||
|             'shareable_link' => '' |             'shareable_link' => '', | ||||||
|  |             'estimate_prefix' => $estimate_prefix | ||||||
|         ]); |         ]); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public function store(EstimatesRequest $request) |     public function store(EstimatesRequest $request) | ||||||
|     { |     { | ||||||
|  |         $estimate_number = explode("-",$request->estimate_number); | ||||||
|  |         $number_attributes['estimate_number'] = $estimate_number[0].'-'.sprintf('%06d', intval($estimate_number[1])); | ||||||
|  |  | ||||||
|  |         Validator::make($number_attributes, [ | ||||||
|  |             'estimate_number' => 'required|unique:estimates,estimate_number' | ||||||
|  |         ])->validate(); | ||||||
|  |  | ||||||
|         $estimate_date = Carbon::createFromFormat('d/m/Y', $request->estimate_date); |         $estimate_date = Carbon::createFromFormat('d/m/Y', $request->estimate_date); | ||||||
|         $expiry_date = Carbon::createFromFormat('d/m/Y', $request->expiry_date); |         $expiry_date = Carbon::createFromFormat('d/m/Y', $request->expiry_date); | ||||||
|         $status = Estimate::STATUS_DRAFT; |         $status = Estimate::STATUS_DRAFT; | ||||||
| @ -101,7 +119,7 @@ class EstimatesController extends Controller | |||||||
|         $estimate = Estimate::create([ |         $estimate = Estimate::create([ | ||||||
|             'estimate_date' => $estimate_date, |             'estimate_date' => $estimate_date, | ||||||
|             'expiry_date' => $expiry_date, |             'expiry_date' => $expiry_date, | ||||||
|             'estimate_number' => $request->estimate_number, |             'estimate_number' => $number_attributes['estimate_number'], | ||||||
|             'reference_number' => $request->reference_number, |             'reference_number' => $request->reference_number, | ||||||
|             'user_id' => $request->user_id, |             'user_id' => $request->user_id, | ||||||
|             'company_id' => $request->header('company'), |             'company_id' => $request->header('company'), | ||||||
| @ -127,7 +145,7 @@ class EstimatesController extends Controller | |||||||
|  |  | ||||||
|             if (array_key_exists('taxes', $estimateItem) && $estimateItem['taxes']) { |             if (array_key_exists('taxes', $estimateItem) && $estimateItem['taxes']) { | ||||||
|                 foreach ($estimateItem['taxes'] as $tax) { |                 foreach ($estimateItem['taxes'] as $tax) { | ||||||
|                     if ($tax['amount']) { |                     if (gettype($tax['amount']) !== "NULL") { | ||||||
|                         $tax['company_id'] = $request->header('company'); |                         $tax['company_id'] = $request->header('company'); | ||||||
|                         $item->taxes()->create($tax); |                         $item->taxes()->create($tax); | ||||||
|                     } |                     } | ||||||
| @ -137,7 +155,7 @@ class EstimatesController extends Controller | |||||||
|  |  | ||||||
|         if ($request->has('taxes')) { |         if ($request->has('taxes')) { | ||||||
|             foreach ($request->taxes as $tax) { |             foreach ($request->taxes as $tax) { | ||||||
|                 if ($tax['amount']) { |                 if (gettype($tax['amount']) !== "NULL") { | ||||||
|                     $tax['company_id'] = $request->header('company'); |                     $tax['company_id'] = $request->header('company'); | ||||||
|                     $estimate->taxes()->create($tax); |                     $estimate->taxes()->create($tax); | ||||||
|                 } |                 } | ||||||
| @ -216,26 +234,33 @@ class EstimatesController extends Controller | |||||||
|  |  | ||||||
|         return response()->json( [ |         return response()->json( [ | ||||||
|             'customers' => $customers, |             'customers' => $customers, | ||||||
|             'nextEstimateNumber' => $estimate->estimate_number, |             'nextEstimateNumber' => $estimate->getEstimateNumAttribute(), | ||||||
|             'taxes' => Tax::latest()->whereCompany($request->header('company'))->get(), |             'taxes' => Tax::latest()->whereCompany($request->header('company'))->get(), | ||||||
|             'estimate' => $estimate, |             'estimate' => $estimate, | ||||||
|             'items' => Item::whereCompany($request->header('company'))->latest()->get(), |             'items' => Item::whereCompany($request->header('company'))->latest()->get(), | ||||||
|             'estimateTemplates' => EstimateTemplate::all(), |             'estimateTemplates' => EstimateTemplate::all(), | ||||||
|             'tax_per_item' => $estimate->tax_per_item, |             'tax_per_item' => $estimate->tax_per_item, | ||||||
|             'discount_per_item' => $estimate->discount_per_item, |             'discount_per_item' => $estimate->discount_per_item, | ||||||
|             'shareable_link' => url('/estimates/pdf/'.$estimate->unique_hash) |             'shareable_link' => url('/estimates/pdf/'.$estimate->unique_hash), | ||||||
|  |             'estimate_prefix' => $estimate->getEstimatePrefixAttribute() | ||||||
|         ]); |         ]); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public function update(EstimatesRequest $request, $id) |     public function update(EstimatesRequest $request, $id) | ||||||
|     { |     { | ||||||
|  |         $estimate_number = explode("-",$request->estimate_number); | ||||||
|  |         $number_attributes['estimate_number'] = $estimate_number[0].'-'.sprintf('%06d', intval($estimate_number[1])); | ||||||
|  |         Validator::make($number_attributes, [ | ||||||
|  |             'estimate_number' => 'required|unique:estimates,estimate_number'.','.$id | ||||||
|  |         ])->validate(); | ||||||
|  |  | ||||||
|         $estimate_date = Carbon::createFromFormat('d/m/Y', $request->estimate_date); |         $estimate_date = Carbon::createFromFormat('d/m/Y', $request->estimate_date); | ||||||
|         $expiry_date = Carbon::createFromFormat('d/m/Y', $request->expiry_date); |         $expiry_date = Carbon::createFromFormat('d/m/Y', $request->expiry_date); | ||||||
|  |  | ||||||
|         $estimate = Estimate::find($id); |         $estimate = Estimate::find($id); | ||||||
|         $estimate->estimate_date = $estimate_date; |         $estimate->estimate_date = $estimate_date; | ||||||
|         $estimate->expiry_date = $expiry_date; |         $estimate->expiry_date = $expiry_date; | ||||||
|         $estimate->estimate_number = $request->estimate_number; |         $estimate->estimate_number = $number_attributes['estimate_number']; | ||||||
|         $estimate->reference_number = $request->reference_number; |         $estimate->reference_number = $request->reference_number; | ||||||
|         $estimate->user_id = $request->user_id; |         $estimate->user_id = $request->user_id; | ||||||
|         $estimate->estimate_template_id = $request->estimate_template_id; |         $estimate->estimate_template_id = $request->estimate_template_id; | ||||||
| @ -266,7 +291,7 @@ class EstimatesController extends Controller | |||||||
|  |  | ||||||
|             if (array_key_exists('taxes', $estimateItem) && $estimateItem['taxes']) { |             if (array_key_exists('taxes', $estimateItem) && $estimateItem['taxes']) { | ||||||
|                 foreach ($estimateItem['taxes'] as $tax) { |                 foreach ($estimateItem['taxes'] as $tax) { | ||||||
|                     if ($tax['amount']) { |                     if (gettype($tax['amount']) !== "NULL") { | ||||||
|                         $tax['company_id'] = $request->header('company'); |                         $tax['company_id'] = $request->header('company'); | ||||||
|                         $item->taxes()->create($tax); |                         $item->taxes()->create($tax); | ||||||
|                     } |                     } | ||||||
| @ -276,7 +301,7 @@ class EstimatesController extends Controller | |||||||
|  |  | ||||||
|         if ($request->has('taxes')) { |         if ($request->has('taxes')) { | ||||||
|             foreach ($request->taxes as $tax) { |             foreach ($request->taxes as $tax) { | ||||||
|                 if ($tax['amount']) { |                 if (gettype($tax['amount']) !== "NULL") { | ||||||
|                     $tax['company_id'] = $request->header('company'); |                     $tax['company_id'] = $request->header('company'); | ||||||
|                     $estimate->taxes()->create($tax); |                     $estimate->taxes()->create($tax); | ||||||
|                 } |                 } | ||||||
|  | |||||||
| @ -66,14 +66,24 @@ class InvoicesController extends Controller | |||||||
|     { |     { | ||||||
|         $tax_per_item = CompanySetting::getSetting('tax_per_item', $request->header('company')); |         $tax_per_item = CompanySetting::getSetting('tax_per_item', $request->header('company')); | ||||||
|         $discount_per_item = CompanySetting::getSetting('discount_per_item', $request->header('company')); |         $discount_per_item = CompanySetting::getSetting('discount_per_item', $request->header('company')); | ||||||
|         $nextInvoiceNumber = "INV-".Invoice::getNextInvoiceNumber(); |         $invoice_prefix = CompanySetting::getSetting('invoice_prefix', $request->header('company')); | ||||||
|  |         $invoice_num_auto_generate = CompanySetting::getSetting('invoice_auto_generate', $request->header('company')); | ||||||
|  |  | ||||||
|  |         $nextInvoiceNumberAttribute = null; | ||||||
|  |         $nextInvoiceNumber = Invoice::getNextInvoiceNumber($invoice_prefix); | ||||||
|  |  | ||||||
|  |         if ($invoice_num_auto_generate == "YES") { | ||||||
|  |             $nextInvoiceNumberAttribute = $nextInvoiceNumber; | ||||||
|  |         } | ||||||
|  |  | ||||||
|         return response()->json([ |         return response()->json([ | ||||||
|             'nextInvoiceNumber' => $nextInvoiceNumber, |             'nextInvoiceNumberAttribute' => $nextInvoiceNumberAttribute, | ||||||
|  |             'nextInvoiceNumber' => $invoice_prefix.'-'.$nextInvoiceNumber, | ||||||
|             'items' => Item::with('taxes')->whereCompany($request->header('company'))->get(), |             'items' => Item::with('taxes')->whereCompany($request->header('company'))->get(), | ||||||
|             'invoiceTemplates' => InvoiceTemplate::all(), |             'invoiceTemplates' => InvoiceTemplate::all(), | ||||||
|             'tax_per_item' => $tax_per_item, |             'tax_per_item' => $tax_per_item, | ||||||
|             'discount_per_item' => $discount_per_item |             'discount_per_item' => $discount_per_item, | ||||||
|  |             'invoice_prefix' => $invoice_prefix | ||||||
|         ]); |         ]); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @ -85,6 +95,13 @@ class InvoicesController extends Controller | |||||||
|      */ |      */ | ||||||
|     public function store(Requests\InvoicesRequest $request) |     public function store(Requests\InvoicesRequest $request) | ||||||
|     { |     { | ||||||
|  |         $invoice_number = explode("-",$request->invoice_number); | ||||||
|  |         $number_attributes['invoice_number'] = $invoice_number[0].'-'.sprintf('%06d', intval($invoice_number[1])); | ||||||
|  |  | ||||||
|  |         Validator::make($number_attributes, [ | ||||||
|  |             'invoice_number' => 'required|unique:invoices,invoice_number' | ||||||
|  |         ])->validate(); | ||||||
|  |  | ||||||
|         $invoice_date = Carbon::createFromFormat('d/m/Y', $request->invoice_date); |         $invoice_date = Carbon::createFromFormat('d/m/Y', $request->invoice_date); | ||||||
|         $due_date = Carbon::createFromFormat('d/m/Y', $request->due_date); |         $due_date = Carbon::createFromFormat('d/m/Y', $request->due_date); | ||||||
|         $status = Invoice::STATUS_DRAFT; |         $status = Invoice::STATUS_DRAFT; | ||||||
| @ -99,7 +116,7 @@ class InvoicesController extends Controller | |||||||
|         $invoice = Invoice::create([ |         $invoice = Invoice::create([ | ||||||
|             'invoice_date' => $invoice_date, |             'invoice_date' => $invoice_date, | ||||||
|             'due_date' => $due_date, |             'due_date' => $due_date, | ||||||
|             'invoice_number' => $request->invoice_number, |             'invoice_number' => $number_attributes['invoice_number'], | ||||||
|             'reference_number' => $request->reference_number, |             'reference_number' => $request->reference_number, | ||||||
|             'user_id' => $request->user_id, |             'user_id' => $request->user_id, | ||||||
|             'company_id' => $request->header('company'), |             'company_id' => $request->header('company'), | ||||||
| @ -128,8 +145,7 @@ class InvoicesController extends Controller | |||||||
|             if (array_key_exists('taxes', $invoiceItem) && $invoiceItem['taxes']) { |             if (array_key_exists('taxes', $invoiceItem) && $invoiceItem['taxes']) { | ||||||
|                 foreach ($invoiceItem['taxes'] as $tax) { |                 foreach ($invoiceItem['taxes'] as $tax) { | ||||||
|                     $tax['company_id'] = $request->header('company'); |                     $tax['company_id'] = $request->header('company'); | ||||||
|  |                     if (gettype($tax['amount']) !== "NULL") { | ||||||
|                     if ($tax['amount']) { |  | ||||||
|                         $item->taxes()->create($tax); |                         $item->taxes()->create($tax); | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
| @ -140,7 +156,7 @@ class InvoicesController extends Controller | |||||||
|             foreach ($request->taxes as $tax) { |             foreach ($request->taxes as $tax) { | ||||||
|                 $tax['company_id'] = $request->header('company'); |                 $tax['company_id'] = $request->header('company'); | ||||||
|  |  | ||||||
|                 if ($tax['amount']) { |                 if (gettype($tax['amount']) !== "NULL") { | ||||||
|                     $invoice->taxes()->create($tax); |                     $invoice->taxes()->create($tax); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| @ -222,12 +238,13 @@ class InvoicesController extends Controller | |||||||
|         ])->find($id); |         ])->find($id); | ||||||
|  |  | ||||||
|         return response()->json([ |         return response()->json([ | ||||||
|             'nextInvoiceNumber' => $invoice->invoice_number, |             'nextInvoiceNumber' => $invoice->getInvoiceNumAttribute(), | ||||||
|             'invoice' => $invoice, |             'invoice' => $invoice, | ||||||
|             'invoiceTemplates' => InvoiceTemplate::all(), |             'invoiceTemplates' => InvoiceTemplate::all(), | ||||||
|             'tax_per_item' => $invoice->tax_per_item, |             'tax_per_item' => $invoice->tax_per_item, | ||||||
|             'discount_per_item' => $invoice->discount_per_item, |             'discount_per_item' => $invoice->discount_per_item, | ||||||
|             'shareable_link' => url('/invoices/pdf/'.$invoice->unique_hash) |             'shareable_link' => url('/invoices/pdf/'.$invoice->unique_hash), | ||||||
|  |             'invoice_prefix' => $invoice->getInvoicePrefixAttribute() | ||||||
|         ]); |         ]); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @ -240,6 +257,13 @@ class InvoicesController extends Controller | |||||||
|      */ |      */ | ||||||
|     public function update(Requests\InvoicesRequest $request, $id) |     public function update(Requests\InvoicesRequest $request, $id) | ||||||
|     { |     { | ||||||
|  |         $invoice_number = explode("-",$request->invoice_number); | ||||||
|  |         $number_attributes['invoice_number'] = $invoice_number[0].'-'.sprintf('%06d', intval($invoice_number[1])); | ||||||
|  |  | ||||||
|  |         Validator::make($number_attributes, [ | ||||||
|  |             'invoice_number' => 'required|unique:invoices,invoice_number'.','.$id | ||||||
|  |         ])->validate(); | ||||||
|  |  | ||||||
|         $invoice_date = Carbon::createFromFormat('d/m/Y', $request->invoice_date); |         $invoice_date = Carbon::createFromFormat('d/m/Y', $request->invoice_date); | ||||||
|         $due_date = Carbon::createFromFormat('d/m/Y', $request->due_date); |         $due_date = Carbon::createFromFormat('d/m/Y', $request->due_date); | ||||||
|  |  | ||||||
| @ -268,7 +292,7 @@ class InvoicesController extends Controller | |||||||
|  |  | ||||||
|         $invoice->invoice_date = $invoice_date; |         $invoice->invoice_date = $invoice_date; | ||||||
|         $invoice->due_date = $due_date; |         $invoice->due_date = $due_date; | ||||||
|         $invoice->invoice_number = $request->invoice_number; |         $invoice->invoice_number =  $number_attributes['invoice_number']; | ||||||
|         $invoice->reference_number = $request->reference_number; |         $invoice->reference_number = $request->reference_number; | ||||||
|         $invoice->user_id = $request->user_id; |         $invoice->user_id = $request->user_id; | ||||||
|         $invoice->invoice_template_id = $request->invoice_template_id; |         $invoice->invoice_template_id = $request->invoice_template_id; | ||||||
| @ -292,7 +316,6 @@ class InvoicesController extends Controller | |||||||
|         foreach ($oldTaxes as $oldTax) { |         foreach ($oldTaxes as $oldTax) { | ||||||
|             Tax::destroy($oldTax['id']); |             Tax::destroy($oldTax['id']); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         foreach ($invoiceItems as $invoiceItem) { |         foreach ($invoiceItems as $invoiceItem) { | ||||||
|             $invoiceItem['company_id'] = $request->header('company'); |             $invoiceItem['company_id'] = $request->header('company'); | ||||||
|             $item = $invoice->items()->create($invoiceItem); |             $item = $invoice->items()->create($invoiceItem); | ||||||
| @ -300,8 +323,7 @@ class InvoicesController extends Controller | |||||||
|             if (array_key_exists('taxes', $invoiceItem) && $invoiceItem['taxes']) { |             if (array_key_exists('taxes', $invoiceItem) && $invoiceItem['taxes']) { | ||||||
|                 foreach ($invoiceItem['taxes'] as $tax) { |                 foreach ($invoiceItem['taxes'] as $tax) { | ||||||
|                     $tax['company_id'] = $request->header('company'); |                     $tax['company_id'] = $request->header('company'); | ||||||
|  |                     if (gettype($tax['amount']) !== "NULL") { | ||||||
|                     if ($tax['amount']) { |  | ||||||
|                         $item->taxes()->create($tax); |                         $item->taxes()->create($tax); | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
| @ -312,7 +334,7 @@ class InvoicesController extends Controller | |||||||
|             foreach ($request->taxes as $tax) { |             foreach ($request->taxes as $tax) { | ||||||
|                 $tax['company_id'] = $request->header('company'); |                 $tax['company_id'] = $request->header('company'); | ||||||
|  |  | ||||||
|                 if ($tax['amount']) { |                 if (gettype($tax['amount']) !== "NULL") { | ||||||
|                     $invoice->taxes()->create($tax); |                     $invoice->taxes()->create($tax); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  | |||||||
| @ -202,6 +202,45 @@ class OnboardingController extends Controller | |||||||
|             ); |             ); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         $invoices = [ | ||||||
|  |             'invoice_auto_generate' => 'YES', | ||||||
|  |             'invoice_prefix' => 'INV' | ||||||
|  |         ]; | ||||||
|  |  | ||||||
|  |         foreach ($invoices as $key => $value) { | ||||||
|  |             CompanySetting::setSetting( | ||||||
|  |                 $key, | ||||||
|  |                 $value, | ||||||
|  |                 $user->company_id | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $estimates = [ | ||||||
|  |             'estimate_prefix' => 'EST', | ||||||
|  |             'estimate_auto_generate' => 'YES' | ||||||
|  |         ]; | ||||||
|  |  | ||||||
|  |         foreach ($estimates as $key => $value) { | ||||||
|  |             CompanySetting::setSetting( | ||||||
|  |                 $key, | ||||||
|  |                 $value, | ||||||
|  |                 $user->company_id | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $payments = [ | ||||||
|  |             'payment_prefix' => 'PAY', | ||||||
|  |             'payment_auto_generate' => 'YES' | ||||||
|  |         ]; | ||||||
|  |  | ||||||
|  |         foreach ($payments as $key => $value) { | ||||||
|  |             CompanySetting::setSetting( | ||||||
|  |                 $key, | ||||||
|  |                 $value, | ||||||
|  |                 $user->company_id | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         $colors = [ |         $colors = [ | ||||||
|             'primary_text_color' => '#5851D8', |             'primary_text_color' => '#5851D8', | ||||||
|             'heading_text_color' => '#595959', |             'heading_text_color' => '#595959', | ||||||
| @ -238,7 +277,14 @@ class OnboardingController extends Controller | |||||||
|  |  | ||||||
|         if (file_exists($path)) { |         if (file_exists($path)) { | ||||||
|             file_put_contents($path, str_replace( |             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) |                 'PROXY_OAUTH_CLIENT_SECRET='.config('auth.proxy.client_secret'), | ||||||
|  |                 'PROXY_OAUTH_CLIENT_SECRET='.$client->secret, | ||||||
|  |                 file_get_contents($path) | ||||||
|  |             )); | ||||||
|  |             file_put_contents($path, str_replace( | ||||||
|  |                 'APP_DEBUG=true', | ||||||
|  |                 'APP_DEBUG=false', | ||||||
|  |                 file_get_contents($path) | ||||||
|             )); |             )); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  | |||||||
| @ -10,6 +10,7 @@ use Carbon\Carbon; | |||||||
| use function MongoDB\BSON\toJSON; | use function MongoDB\BSON\toJSON; | ||||||
| use Crater\User; | use Crater\User; | ||||||
| use Crater\Http\Requests\PaymentRequest; | use Crater\Http\Requests\PaymentRequest; | ||||||
|  | use Validator; | ||||||
|  |  | ||||||
| class PaymentController extends Controller | class PaymentController extends Controller | ||||||
| { | { | ||||||
| @ -50,13 +51,24 @@ class PaymentController extends Controller | |||||||
|      */ |      */ | ||||||
|     public function create(Request $request) |     public function create(Request $request) | ||||||
|     { |     { | ||||||
|         $nextPaymentNumber = 'PAY-'.Payment::getNextPaymentNumber(); |         $payment_prefix = CompanySetting::getSetting('payment_prefix', $request->header('company')); | ||||||
|  |         $payment_num_auto_generate = CompanySetting::getSetting('payment_auto_generate', $request->header('company')); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         $nextPaymentNumberAttribute = null; | ||||||
|  |         $nextPaymentNumber = Payment::getNextPaymentNumber($payment_prefix); | ||||||
|  |  | ||||||
|  |         if ($payment_num_auto_generate == "YES") { | ||||||
|  |             $nextPaymentNumberAttribute = $nextPaymentNumber; | ||||||
|  |         } | ||||||
|  |  | ||||||
|         return response()->json([ |         return response()->json([ | ||||||
|             'customers' => User::where('role', 'customer') |             'customers' => User::where('role', 'customer') | ||||||
|                 ->whereCompany($request->header('company')) |                 ->whereCompany($request->header('company')) | ||||||
|                 ->get(), |                 ->get(), | ||||||
|             'nextPaymentNumber' => $nextPaymentNumber |             'nextPaymentNumberAttribute' => $nextPaymentNumberAttribute, | ||||||
|  |             'nextPaymentNumber' => $payment_prefix.'-'.$nextPaymentNumber, | ||||||
|  |             'payment_prefix' => $payment_prefix | ||||||
|         ]); |         ]); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @ -68,6 +80,13 @@ class PaymentController extends Controller | |||||||
|      */ |      */ | ||||||
|     public function store(PaymentRequest $request) |     public function store(PaymentRequest $request) | ||||||
|     { |     { | ||||||
|  |         $payment_number = explode("-",$request->payment_number); | ||||||
|  |         $number_attributes['payment_number'] = $payment_number[0].'-'.sprintf('%06d', intval($payment_number[1])); | ||||||
|  |  | ||||||
|  |         Validator::make($number_attributes, [ | ||||||
|  |             'payment_number' => 'required|unique:payments,payment_number' | ||||||
|  |         ])->validate(); | ||||||
|  |  | ||||||
|         $payment_date = Carbon::createFromFormat('d/m/Y', $request->payment_date); |         $payment_date = Carbon::createFromFormat('d/m/Y', $request->payment_date); | ||||||
|  |  | ||||||
|         if ($request->has('invoice_id') && $request->invoice_id != null) { |         if ($request->has('invoice_id') && $request->invoice_id != null) { | ||||||
| @ -90,7 +109,7 @@ class PaymentController extends Controller | |||||||
|  |  | ||||||
|         $payment = Payment::create([ |         $payment = Payment::create([ | ||||||
|             'payment_date' => $payment_date, |             'payment_date' => $payment_date, | ||||||
|             'payment_number' => $request->payment_number, |             'payment_number' => $number_attributes['payment_number'], | ||||||
|             'user_id' => $request->user_id, |             'user_id' => $request->user_id, | ||||||
|             'company_id' => $request->header('company'), |             'company_id' => $request->header('company'), | ||||||
|             'invoice_id' => $request->invoice_id, |             'invoice_id' => $request->invoice_id, | ||||||
| @ -135,7 +154,8 @@ class PaymentController extends Controller | |||||||
|             'customers' => User::where('role', 'customer') |             'customers' => User::where('role', 'customer') | ||||||
|                 ->whereCompany($request->header('company')) |                 ->whereCompany($request->header('company')) | ||||||
|                 ->get(), |                 ->get(), | ||||||
|             'nextPaymentNumber' => $payment->payment_number, |             'nextPaymentNumber' => $payment->getPaymentNumAttribute(), | ||||||
|  |             'payment_prefix' => $payment->getPaymentPrefixAttribute(), | ||||||
|             'payment' => $payment, |             'payment' => $payment, | ||||||
|             'invoices' => $invoices |             'invoices' => $invoices | ||||||
|         ]); |         ]); | ||||||
| @ -150,6 +170,13 @@ class PaymentController extends Controller | |||||||
|      */ |      */ | ||||||
|     public function update(PaymentRequest $request, $id) |     public function update(PaymentRequest $request, $id) | ||||||
|     { |     { | ||||||
|  |         $payment_number = explode("-",$request->payment_number); | ||||||
|  |         $number_attributes['payment_number'] = $payment_number[0].'-'.sprintf('%06d', intval($payment_number[1])); | ||||||
|  |  | ||||||
|  |         Validator::make($number_attributes, [ | ||||||
|  |             'payment_number' => 'required|unique:payments,payment_number'.','.$id | ||||||
|  |         ])->validate(); | ||||||
|  |  | ||||||
|         $payment_date = Carbon::createFromFormat('d/m/Y', $request->payment_date); |         $payment_date = Carbon::createFromFormat('d/m/Y', $request->payment_date); | ||||||
|  |  | ||||||
|         $payment = Payment::find($id); |         $payment = Payment::find($id); | ||||||
| @ -178,7 +205,7 @@ class PaymentController extends Controller | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         $payment->payment_date = $payment_date; |         $payment->payment_date = $payment_date; | ||||||
|         $payment->payment_number = $request->payment_number; |         $payment->payment_number = $number_attributes['payment_number']; | ||||||
|         $payment->user_id = $request->user_id; |         $payment->user_id = $request->user_id; | ||||||
|         $payment->invoice_id = $request->invoice_id; |         $payment->invoice_id = $request->invoice_id; | ||||||
|         $payment->payment_mode = $request->payment_mode; |         $payment->payment_mode = $request->payment_mode; | ||||||
|  | |||||||
| @ -25,7 +25,6 @@ class EstimatesRequest extends FormRequest | |||||||
|         $rules = [ |         $rules = [ | ||||||
|             'estimate_date' => 'required', |             'estimate_date' => 'required', | ||||||
|             'expiry_date' => 'required', |             'expiry_date' => 'required', | ||||||
|             'estimate_number' => 'required|unique:estimates,estimate_number', |  | ||||||
|             'user_id' => 'required', |             'user_id' => 'required', | ||||||
|             'discount' => 'required', |             'discount' => 'required', | ||||||
|             'discount_val' => 'required', |             'discount_val' => 'required', | ||||||
| @ -41,10 +40,6 @@ class EstimatesRequest extends FormRequest | |||||||
|             'items.*.price' => 'required' |             'items.*.price' => 'required' | ||||||
|         ]; |         ]; | ||||||
|  |  | ||||||
|         if ($this->getMethod() == 'PUT') { |  | ||||||
|             $rules['estimate_number'] = $rules['estimate_number'].','.$this->get('id'); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         return $rules; |         return $rules; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -25,7 +25,6 @@ class InvoicesRequest extends FormRequest | |||||||
|         $rules = [ |         $rules = [ | ||||||
|             'invoice_date' => 'required', |             'invoice_date' => 'required', | ||||||
|             'due_date' => 'required', |             'due_date' => 'required', | ||||||
|             'invoice_number' => 'required|unique:invoices,invoice_number', |  | ||||||
|             'user_id' => 'required', |             'user_id' => 'required', | ||||||
|             'discount' => 'required', |             'discount' => 'required', | ||||||
|             'discount_val' => 'required', |             'discount_val' => 'required', | ||||||
| @ -41,10 +40,6 @@ class InvoicesRequest extends FormRequest | |||||||
|             'items.*.price' => 'required' |             'items.*.price' => 'required' | ||||||
|         ]; |         ]; | ||||||
|  |  | ||||||
|         if ($this->getMethod() == 'PUT') { |  | ||||||
|             $rules['invoice_number'] = $rules['invoice_number'].','.$this->get('id'); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         return $rules; |         return $rules; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -24,15 +24,10 @@ class PaymentRequest extends FormRequest | |||||||
|     { |     { | ||||||
|         $rules = [ |         $rules = [ | ||||||
|             'payment_date' => 'required', |             'payment_date' => 'required', | ||||||
|             'payment_number' => 'required|unique:payments,payment_number', |  | ||||||
|             'user_id' => 'required', |             'user_id' => 'required', | ||||||
|             'amount' => 'required', |             'amount' => 'required', | ||||||
|         ]; |         ]; | ||||||
|  |  | ||||||
|         if ($this->getMethod() == 'PUT') { |  | ||||||
|             $rules['payment_number'] = $rules['payment_number'].','.$this->route('payment'); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         return $rules; |         return $rules; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -30,7 +30,7 @@ class ProfileRequest extends FormRequest | |||||||
|             case 'POST': |             case 'POST': | ||||||
|                 return [ |                 return [ | ||||||
|                     'name' => 'required', |                     'name' => 'required', | ||||||
|                     'password' => 'required', |                     'password' => 'required|min:8', | ||||||
|                     'address_street_1' => 'max:255', |                     'address_street_1' => 'max:255', | ||||||
|                     'address_street_2' => 'max:255', |                     'address_street_2' => 'max:255', | ||||||
|                     'email' => [ |                     'email' => [ | ||||||
|  | |||||||
| @ -66,10 +66,14 @@ class Invoice extends Model | |||||||
|         'formattedDueDate' |         'formattedDueDate' | ||||||
|     ]; |     ]; | ||||||
|  |  | ||||||
|     public static function getNextInvoiceNumber() |     public static function getNextInvoiceNumber($value) | ||||||
|     { |     { | ||||||
|         // Get the last created order |         // Get the last created order | ||||||
|         $lastOrder = Invoice::orderBy('created_at', 'desc')->first(); |         $lastOrder = Invoice::where('invoice_number', 'LIKE', $value . '-%') | ||||||
|  |                     ->orderBy('created_at', 'desc') | ||||||
|  |                     ->first(); | ||||||
|  |  | ||||||
|  |  | ||||||
|         if (!$lastOrder) { |         if (!$lastOrder) { | ||||||
|             // We get here if there is no order at all |             // 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. |             // If there is no number set it to 0, which will be 1 at the end. | ||||||
| @ -143,10 +147,15 @@ class Invoice extends Model | |||||||
|  |  | ||||||
|     public function getInvoiceNumAttribute() |     public function getInvoiceNumAttribute() | ||||||
|     { |     { | ||||||
|         $position = $this->strposX($this->invoice_number, "-", 2) + 1; |         $position = $this->strposX($this->invoice_number, "-", 1) + 1; | ||||||
|         return substr($this->invoice_number, $position); |         return substr($this->invoice_number, $position); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     public function getInvoicePrefixAttribute () { | ||||||
|  |         $prefix = explode("-", $this->invoice_number)[0]; | ||||||
|  |         return $prefix; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     public function getFormattedCreatedAtAttribute($value) |     public function getFormattedCreatedAtAttribute($value) | ||||||
|     { |     { | ||||||
|         $dateFormat = CompanySetting::getSetting('carbon_date_format', $this->company_id); |         $dateFormat = CompanySetting::getSetting('carbon_date_format', $this->company_id); | ||||||
|  | |||||||
| @ -6,7 +6,6 @@ use Illuminate\Contracts\Queue\ShouldQueue; | |||||||
| use Illuminate\Queue\InteractsWithQueue; | use Illuminate\Queue\InteractsWithQueue; | ||||||
| use Illuminate\Database\Schema\Blueprint; | use Illuminate\Database\Schema\Blueprint; | ||||||
| use Crater\Listeners\Updates\Listener; | use Crater\Listeners\Updates\Listener; | ||||||
| use Crater\Listeners\Updates\v2\Version200; |  | ||||||
| use Crater\Events\UpdateFinished; | use Crater\Events\UpdateFinished; | ||||||
| use Crater\Setting; | use Crater\Setting; | ||||||
| use Crater\Address; | use Crater\Address; | ||||||
|  | |||||||
							
								
								
									
										40
									
								
								app/Listeners/Updates/v2/Version202.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								app/Listeners/Updates/v2/Version202.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,40 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Listeners\Updates\v2; | ||||||
|  |  | ||||||
|  | use Illuminate\Contracts\Queue\ShouldQueue; | ||||||
|  | use Illuminate\Queue\InteractsWithQueue; | ||||||
|  | use Crater\Events\UpdateFinished; | ||||||
|  | use Crater\Listeners\Updates\Listener; | ||||||
|  | use Crater\Setting; | ||||||
|  |  | ||||||
|  | class Version202 extends Listener | ||||||
|  | { | ||||||
|  |     const VERSION = '2.0.2'; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Create the event listener. | ||||||
|  |      * | ||||||
|  |      * @return void | ||||||
|  |      */ | ||||||
|  |     public function __construct() | ||||||
|  |     { | ||||||
|  |         // | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Handle the event. | ||||||
|  |      * | ||||||
|  |      * @param  object  $event | ||||||
|  |      * @return void | ||||||
|  |      */ | ||||||
|  |     public function handle(UpdateFinished $event) | ||||||
|  |     { | ||||||
|  |         if ($this->isListenerFired($event)) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Update Crater app version | ||||||
|  |         Setting::setSetting('version', static::VERSION); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										64
									
								
								app/Listeners/Updates/v2/Version210.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								app/Listeners/Updates/v2/Version210.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,64 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace Crater\Listeners\Updates\v2; | ||||||
|  |  | ||||||
|  | use Illuminate\Contracts\Queue\ShouldQueue; | ||||||
|  | use Illuminate\Queue\InteractsWithQueue; | ||||||
|  | use Crater\Events\UpdateFinished; | ||||||
|  | use Crater\Listeners\Updates\Listener; | ||||||
|  | use Crater\Setting; | ||||||
|  | use Crater\CompanySetting; | ||||||
|  |  | ||||||
|  | class Version210 extends Listener | ||||||
|  | { | ||||||
|  |     const VERSION = '2.1.0'; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Create the event listener. | ||||||
|  |      * | ||||||
|  |      * @return void | ||||||
|  |      */ | ||||||
|  |     public function __construct() | ||||||
|  |     { | ||||||
|  |         // | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Handle the event. | ||||||
|  |      * | ||||||
|  |      * @param  object  $event | ||||||
|  |      * @return void | ||||||
|  |      */ | ||||||
|  |     public function handle(UpdateFinished $event) | ||||||
|  |     { | ||||||
|  |         if ($this->isListenerFired($event)) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Add initial auto generate value | ||||||
|  |         $this->addAutoGenerateSettings(); | ||||||
|  |  | ||||||
|  |         // Update Crater app version | ||||||
|  |         Setting::setSetting('version', static::VERSION); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private function addAutoGenerateSettings() | ||||||
|  |     { | ||||||
|  |         $settings = [ | ||||||
|  |             'invoice_auto_generate' => 'YES', | ||||||
|  |             'invoice_prefix' => 'INV', | ||||||
|  |             'estimate_prefix' => 'EST', | ||||||
|  |             'estimate_auto_generate' => 'YES', | ||||||
|  |             'payment_prefix' => 'PAY', | ||||||
|  |             'payment_auto_generate' => 'YES' | ||||||
|  |         ]; | ||||||
|  |  | ||||||
|  |         foreach ($settings as $key => $value) { | ||||||
|  |             CompanySetting::setSetting( | ||||||
|  |                 $key, | ||||||
|  |                 $value, | ||||||
|  |                 auth()->user()->company->id | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -32,10 +32,34 @@ class Payment extends Model | |||||||
|         'formattedPaymentDate' |         'formattedPaymentDate' | ||||||
|     ]; |     ]; | ||||||
|  |  | ||||||
|     public static function getNextPaymentNumber() |  | ||||||
|  |     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 getPaymentNumAttribute() | ||||||
|  |     { | ||||||
|  |         $position = $this->strposX($this->payment_number, "-", 1) + 1; | ||||||
|  |         return substr($this->payment_number, $position); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public static function getNextPaymentNumber($value) | ||||||
|     { |     { | ||||||
|         // Get the last created order |         // Get the last created order | ||||||
|         $payment = Payment::orderBy('created_at', 'desc')->first(); |         $payment = Payment::where('payment_number', 'LIKE', $value . '-%') | ||||||
|  |                     ->orderBy('created_at', 'desc') | ||||||
|  |                     ->first(); | ||||||
|         if (!$payment) { |         if (!$payment) { | ||||||
|             // We get here if there is no order at all |             // 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. |             // If there is no number set it to 0, which will be 1 at the end. | ||||||
| @ -54,6 +78,13 @@ class Payment extends Model | |||||||
|         return sprintf('%06d', intval($number) + 1); |         return sprintf('%06d', intval($number) + 1); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     public function getPaymentPrefixAttribute () | ||||||
|  |     { | ||||||
|  |         $prefix= explode("-",$this->payment_number)[0]; | ||||||
|  |         return $prefix; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|     public function invoice() |     public function invoice() | ||||||
|     { |     { | ||||||
|         return $this->belongsTo(Invoice::class); |         return $this->belongsTo(Invoice::class); | ||||||
|  | |||||||
| @ -8,6 +8,8 @@ use Crater\Events\UpdateFinished; | |||||||
| use Crater\Listeners\Updates\v1\Version110; | use Crater\Listeners\Updates\v1\Version110; | ||||||
| use Crater\Listeners\Updates\v2\Version200; | use Crater\Listeners\Updates\v2\Version200; | ||||||
| use Crater\Listeners\Updates\v2\Version201; | use Crater\Listeners\Updates\v2\Version201; | ||||||
|  | use Crater\Listeners\Updates\v2\Version202; | ||||||
|  | use Crater\Listeners\Updates\v2\Version210; | ||||||
|  |  | ||||||
| class EventServiceProvider extends ServiceProvider | class EventServiceProvider extends ServiceProvider | ||||||
| { | { | ||||||
| @ -21,6 +23,8 @@ class EventServiceProvider extends ServiceProvider | |||||||
|             Version110::class, |             Version110::class, | ||||||
|             Version200::class, |             Version200::class, | ||||||
|             Version201::class, |             Version201::class, | ||||||
|  |             Version202::class, | ||||||
|  |             Version210::class, | ||||||
|         ], |         ], | ||||||
|         Registered::class => [ |         Registered::class => [ | ||||||
|             SendEmailVerificationNotification::class, |             SendEmailVerificationNotification::class, | ||||||
|  | |||||||
| @ -61,7 +61,7 @@ class EnvironmentManager | |||||||
|         } catch (Exception $e) { |         } catch (Exception $e) { | ||||||
|  |  | ||||||
|             return [ |             return [ | ||||||
|                 'error' => $e->getMessage() |                 'error_message' => $e->getMessage() | ||||||
|             ]; |             ]; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  | |||||||
| @ -41,10 +41,14 @@ function clean_slug($string) | |||||||
|  * @param $money |  * @param $money | ||||||
|  * @return formated_money |  * @return formated_money | ||||||
|  */ |  */ | ||||||
| function format_money_pdf($money) | function format_money_pdf($money, $currency = null) | ||||||
| { | { | ||||||
|     $money = $money / 100; |     $money = $money / 100; | ||||||
|     $currency = Currency::findOrFail(CompanySetting::getSetting('currency', 1)); |  | ||||||
|  |     if (!$currency) { | ||||||
|  |         $currency = Currency::findOrFail(CompanySetting::getSetting('currency', 1)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     $format_money = number_format( |     $format_money = number_format( | ||||||
|         $money, |         $money, | ||||||
|         $currency->precision, |         $currency->precision, | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
|  <?php | <?php | ||||||
|  |  | ||||||
| return [ | return [ | ||||||
|  |  | ||||||
|  | |||||||
| @ -9,6 +9,6 @@ return [ | |||||||
|     | |     | | ||||||
|     */ |     */ | ||||||
|  |  | ||||||
|     'version' => '2.0.1', |     'version' => '2.1.0', | ||||||
|  |  | ||||||
| ]; | ]; | ||||||
|  | |||||||
							
								
								
									
										244
									
								
								config/dompdf.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										244
									
								
								config/dompdf.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,244 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | return array( | ||||||
|  |  | ||||||
|  |     /* | ||||||
|  |     |-------------------------------------------------------------------------- | ||||||
|  |     | Settings | ||||||
|  |     |-------------------------------------------------------------------------- | ||||||
|  |     | | ||||||
|  |     | Set some default values. It is possible to add all defines that can be set | ||||||
|  |     | in dompdf_config.inc.php. You can also override the entire config file. | ||||||
|  |     | | ||||||
|  |     */ | ||||||
|  |     'show_warnings' => false,   // Throw an Exception on warnings from dompdf | ||||||
|  |     'orientation' => 'portrait', | ||||||
|  |     'defines' => array( | ||||||
|  |         /** | ||||||
|  |          * The location of the DOMPDF font directory | ||||||
|  |          * | ||||||
|  |          * The location of the directory where DOMPDF will store fonts and font metrics | ||||||
|  |          * Note: This directory must exist and be writable by the webserver process. | ||||||
|  |          * *Please note the trailing slash.* | ||||||
|  |          * | ||||||
|  |          * Notes regarding fonts: | ||||||
|  |          * Additional .afm font metrics can be added by executing load_font.php from command line. | ||||||
|  |          * | ||||||
|  |          * Only the original "Base 14 fonts" are present on all pdf viewers. Additional fonts must | ||||||
|  |          * be embedded in the pdf file or the PDF may not display correctly. This can significantly | ||||||
|  |          * increase file size unless font subsetting is enabled. Before embedding a font please | ||||||
|  |          * review your rights under the font license. | ||||||
|  |          * | ||||||
|  |          * Any font specification in the source HTML is translated to the closest font available | ||||||
|  |          * in the font directory. | ||||||
|  |          * | ||||||
|  |          * The pdf standard "Base 14 fonts" are: | ||||||
|  |          * Courier, Courier-Bold, Courier-BoldOblique, Courier-Oblique, | ||||||
|  |          * Helvetica, Helvetica-Bold, Helvetica-BoldOblique, Helvetica-Oblique, | ||||||
|  |          * Times-Roman, Times-Bold, Times-BoldItalic, Times-Italic, | ||||||
|  |          * Symbol, ZapfDingbats. | ||||||
|  |          */ | ||||||
|  |         "font_dir" => storage_path('fonts/'), // advised by dompdf (https://github.com/dompdf/dompdf/pull/782) | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * The location of the DOMPDF font cache directory | ||||||
|  |          * | ||||||
|  |          * This directory contains the cached font metrics for the fonts used by DOMPDF. | ||||||
|  |          * This directory can be the same as DOMPDF_FONT_DIR | ||||||
|  |          * | ||||||
|  |          * Note: This directory must exist and be writable by the webserver process. | ||||||
|  |          */ | ||||||
|  |         "font_cache" => storage_path('fonts/'), | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * The location of a temporary directory. | ||||||
|  |          * | ||||||
|  |          * The directory specified must be writeable by the webserver process. | ||||||
|  |          * The temporary directory is required to download remote images and when | ||||||
|  |          * using the PFDLib back end. | ||||||
|  |          */ | ||||||
|  |         "temp_dir" => sys_get_temp_dir(), | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * ==== IMPORTANT ==== | ||||||
|  |          * | ||||||
|  |          * dompdf's "chroot": Prevents dompdf from accessing system files or other | ||||||
|  |          * files on the webserver.  All local files opened by dompdf must be in a | ||||||
|  |          * subdirectory of this directory.  DO NOT set it to '/' since this could | ||||||
|  |          * allow an attacker to use dompdf to read any files on the server.  This | ||||||
|  |          * should be an absolute path. | ||||||
|  |          * This is only checked on command line call by dompdf.php, but not by | ||||||
|  |          * direct class use like: | ||||||
|  |          * $dompdf = new DOMPDF();	$dompdf->load_html($htmldata); $dompdf->render(); $pdfdata = $dompdf->output(); | ||||||
|  |          */ | ||||||
|  |         "chroot" => realpath(base_path()), | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Whether to enable font subsetting or not. | ||||||
|  |          */ | ||||||
|  |         "enable_font_subsetting" => false, | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * The PDF rendering backend to use | ||||||
|  |          * | ||||||
|  |          * Valid settings are 'PDFLib', 'CPDF' (the bundled R&OS PDF class), 'GD' and | ||||||
|  |          * 'auto'. 'auto' will look for PDFLib and use it if found, or if not it will | ||||||
|  |          * fall back on CPDF. 'GD' renders PDFs to graphic files. {@link | ||||||
|  |          * Canvas_Factory} ultimately determines which rendering class to instantiate | ||||||
|  |          * based on this setting. | ||||||
|  |          * | ||||||
|  |          * Both PDFLib & CPDF rendering backends provide sufficient rendering | ||||||
|  |          * capabilities for dompdf, however additional features (e.g. object, | ||||||
|  |          * image and font support, etc.) differ between backends.  Please see | ||||||
|  |          * {@link PDFLib_Adapter} for more information on the PDFLib backend | ||||||
|  |          * and {@link CPDF_Adapter} and lib/class.pdf.php for more information | ||||||
|  |          * on CPDF. Also see the documentation for each backend at the links | ||||||
|  |          * below. | ||||||
|  |          * | ||||||
|  |          * The GD rendering backend is a little different than PDFLib and | ||||||
|  |          * CPDF. Several features of CPDF and PDFLib are not supported or do | ||||||
|  |          * not make any sense when creating image files.  For example, | ||||||
|  |          * multiple pages are not supported, nor are PDF 'objects'.  Have a | ||||||
|  |          * look at {@link GD_Adapter} for more information.  GD support is | ||||||
|  |          * experimental, so use it at your own risk. | ||||||
|  |          * | ||||||
|  |          * @link http://www.pdflib.com | ||||||
|  |          * @link http://www.ros.co.nz/pdf | ||||||
|  |          * @link http://www.php.net/image | ||||||
|  |          */ | ||||||
|  |         "pdf_backend" => "CPDF", | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * PDFlib license key | ||||||
|  |          * | ||||||
|  |          * If you are using a licensed, commercial version of PDFlib, specify | ||||||
|  |          * your license key here.  If you are using PDFlib-Lite or are evaluating | ||||||
|  |          * the commercial version of PDFlib, comment out this setting. | ||||||
|  |          * | ||||||
|  |          * @link http://www.pdflib.com | ||||||
|  |          * | ||||||
|  |          * If pdflib present in web server and auto or selected explicitely above, | ||||||
|  |          * a real license code must exist! | ||||||
|  |          */ | ||||||
|  |         //"DOMPDF_PDFLIB_LICENSE" => "your license key here", | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * html target media view which should be rendered into pdf. | ||||||
|  |          * List of types and parsing rules for future extensions: | ||||||
|  |          * http://www.w3.org/TR/REC-html40/types.html | ||||||
|  |          *   screen, tty, tv, projection, handheld, print, braille, aural, all | ||||||
|  |          * Note: aural is deprecated in CSS 2.1 because it is replaced by speech in CSS 3. | ||||||
|  |          * Note, even though the generated pdf file is intended for print output, | ||||||
|  |          * the desired content might be different (e.g. screen or projection view of html file). | ||||||
|  |          * Therefore allow specification of content here. | ||||||
|  |          */ | ||||||
|  |         "default_media_type" => "screen", | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * The default paper size. | ||||||
|  |          * | ||||||
|  |          * North America standard is "letter"; other countries generally "a4" | ||||||
|  |          * | ||||||
|  |          * @see CPDF_Adapter::PAPER_SIZES for valid sizes ('letter', 'legal', 'A4', etc.) | ||||||
|  |          */ | ||||||
|  |         "default_paper_size" => "a4", | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * The default font family | ||||||
|  |          * | ||||||
|  |          * Used if no suitable fonts can be found. This must exist in the font folder. | ||||||
|  |          * @var string | ||||||
|  |          */ | ||||||
|  |         "default_font" => "DejaVu Sans", | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Image DPI setting | ||||||
|  |          * | ||||||
|  |          * This setting determines the default DPI setting for images and fonts.  The | ||||||
|  |          * DPI may be overridden for inline images by explictly setting the | ||||||
|  |          * image's width & height style attributes (i.e. if the image's native | ||||||
|  |          * width is 600 pixels and you specify the image's width as 72 points, | ||||||
|  |          * the image will have a DPI of 600 in the rendered PDF.  The DPI of | ||||||
|  |          * background images can not be overridden and is controlled entirely | ||||||
|  |          * via this parameter. | ||||||
|  |          * | ||||||
|  |          * For the purposes of DOMPDF, pixels per inch (PPI) = dots per inch (DPI). | ||||||
|  |          * If a size in html is given as px (or without unit as image size), | ||||||
|  |          * this tells the corresponding size in pt. | ||||||
|  |          * This adjusts the relative sizes to be similar to the rendering of the | ||||||
|  |          * html page in a reference browser. | ||||||
|  |          * | ||||||
|  |          * In pdf, always 1 pt = 1/72 inch | ||||||
|  |          * | ||||||
|  |          * Rendering resolution of various browsers in px per inch: | ||||||
|  |          * Windows Firefox and Internet Explorer: | ||||||
|  |          *   SystemControl->Display properties->FontResolution: Default:96, largefonts:120, custom:? | ||||||
|  |          * Linux Firefox: | ||||||
|  |          *   about:config *resolution: Default:96 | ||||||
|  |          *   (xorg screen dimension in mm and Desktop font dpi settings are ignored) | ||||||
|  |          * | ||||||
|  |          * Take care about extra font/image zoom factor of browser. | ||||||
|  |          * | ||||||
|  |          * In images, <img> size in pixel attribute, img css style, are overriding | ||||||
|  |          * the real image dimension in px for rendering. | ||||||
|  |          * | ||||||
|  |          * @var int | ||||||
|  |          */ | ||||||
|  |         "dpi" => 96, | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Enable inline PHP | ||||||
|  |          * | ||||||
|  |          * If this setting is set to true then DOMPDF will automatically evaluate | ||||||
|  |          * inline PHP contained within <script type="text/php"> ... </script> tags. | ||||||
|  |          * | ||||||
|  |          * Enabling this for documents you do not trust (e.g. arbitrary remote html | ||||||
|  |          * pages) is a security risk.  Set this option to false if you wish to process | ||||||
|  |          * untrusted documents. | ||||||
|  |          * | ||||||
|  |          * @var bool | ||||||
|  |          */ | ||||||
|  |         "enable_php" => false, | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Enable inline Javascript | ||||||
|  |          * | ||||||
|  |          * If this setting is set to true then DOMPDF will automatically insert | ||||||
|  |          * JavaScript code contained within <script type="text/javascript"> ... </script> tags. | ||||||
|  |          * | ||||||
|  |          * @var bool | ||||||
|  |          */ | ||||||
|  |         "enable_javascript" => true, | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Enable remote file access | ||||||
|  |          * | ||||||
|  |          * If this setting is set to true, DOMPDF will access remote sites for | ||||||
|  |          * images and CSS files as required. | ||||||
|  |          * This is required for part of test case www/test/image_variants.html through www/examples.php | ||||||
|  |          * | ||||||
|  |          * Attention! | ||||||
|  |          * This can be a security risk, in particular in combination with DOMPDF_ENABLE_PHP and | ||||||
|  |          * allowing remote access to dompdf.php or on allowing remote html code to be passed to | ||||||
|  |          * $dompdf = new DOMPDF(, $dompdf->load_html(..., | ||||||
|  |          * This allows anonymous users to download legally doubtful internet content which on | ||||||
|  |          * tracing back appears to being downloaded by your server, or allows malicious php code | ||||||
|  |          * in remote html pages to be executed by your server with your account privileges. | ||||||
|  |          * | ||||||
|  |          * @var bool | ||||||
|  |          */ | ||||||
|  |         "enable_remote" => true, | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * A ratio applied to the fonts height to be more like browsers' line height | ||||||
|  |          */ | ||||||
|  |         "font_height_ratio" => 1.1, | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * Use the more-than-experimental HTML5 Lib parser | ||||||
|  |          */ | ||||||
|  |         "enable_html5_parser" => true, | ||||||
|  |     ), | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ); | ||||||
| @ -20,9 +20,9 @@ class CreateMediaTable extends Migration | |||||||
|             $table->string('mime_type')->nullable(); |             $table->string('mime_type')->nullable(); | ||||||
|             $table->string('disk'); |             $table->string('disk'); | ||||||
|             $table->unsignedInteger('size'); |             $table->unsignedInteger('size'); | ||||||
|             $table->json('manipulations'); |             $table->text('manipulations'); | ||||||
|             $table->json('custom_properties'); |             $table->text('custom_properties'); | ||||||
|             $table->json('responsive_images'); |             $table->text('responsive_images'); | ||||||
|             $table->unsignedInteger('order_column')->nullable(); |             $table->unsignedInteger('order_column')->nullable(); | ||||||
|             $table->nullableTimestamps(); |             $table->nullableTimestamps(); | ||||||
|         }); |         }); | ||||||
|  | |||||||
							
								
								
									
										40
									
								
								docker-compose.yaml.example
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								docker-compose.yaml.example
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,40 @@ | |||||||
|  | version: '3.1' | ||||||
|  |  | ||||||
|  | services: | ||||||
|  |  | ||||||
|  |   web: | ||||||
|  |     image: nginx | ||||||
|  |     depends_on: | ||||||
|  |       - php | ||||||
|  |     ports: | ||||||
|  |       - 8080:80 | ||||||
|  |     volumes: | ||||||
|  |       - ./nginx.conf:/etc/nginx/nginx.conf:ro | ||||||
|  |       - app:/app | ||||||
|  |     restart: always  | ||||||
|  |      | ||||||
|  |   php: | ||||||
|  |     build: . | ||||||
|  |     depends_on: | ||||||
|  |       - db | ||||||
|  |     expose: | ||||||
|  |       - 9000 | ||||||
|  |     volumes: | ||||||
|  |       - app:/app | ||||||
|  |     restart: always | ||||||
|  |  | ||||||
|  |   db: | ||||||
|  |     image: mariadb | ||||||
|  |     restart: always | ||||||
|  |     volumes: | ||||||
|  |       - db:/var/lib/mysql | ||||||
|  |     environment: | ||||||
|  |       MYSQL_USER: crater | ||||||
|  |       MYSQL_PASSWORD: crater | ||||||
|  |       MYSQL_DATABASE: crater | ||||||
|  |       MYSQL_ROOT_PASSWORD: crater | ||||||
|  |  | ||||||
|  | volumes: | ||||||
|  |   app: | ||||||
|  |   db: | ||||||
|  |  | ||||||
							
								
								
									
										53
									
								
								nginx.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								nginx.conf
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,53 @@ | |||||||
|  | worker_processes  8; | ||||||
|  |  | ||||||
|  | error_log  /var/log/nginx/error.log warn; | ||||||
|  | pid        /var/run/nginx.pid; | ||||||
|  |  | ||||||
|  | events { | ||||||
|  |     worker_connections  4096; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | http { | ||||||
|  |     include       /etc/nginx/mime.types; | ||||||
|  |     default_type  application/octet-stream; | ||||||
|  |  | ||||||
|  |     log_format  main  '$remote_addr - $remote_user [$time_local] "$request" ' | ||||||
|  |                       '$status $body_bytes_sent "$http_referer" ' | ||||||
|  |                       '"$http_user_agent" "$http_x_forwarded_for"'; | ||||||
|  |  | ||||||
|  |     access_log  /var/log/nginx/access.log  main; | ||||||
|  |  | ||||||
|  |     sendfile        on; | ||||||
|  |  | ||||||
|  |     keepalive_timeout  65; | ||||||
|  |  | ||||||
|  |     server { | ||||||
|  |         listen 80 default_server; | ||||||
|  |  | ||||||
|  |         root /app/public; | ||||||
|  |         index index.php; | ||||||
|  |         charset utf-8; | ||||||
|  |  | ||||||
|  |         access_log off; | ||||||
|  |  | ||||||
|  |         location / { | ||||||
|  |             try_files $uri $uri/ /index.php?$query_string; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         location = /favicon.ico { access_log off; log_not_found off; } | ||||||
|  |         location = /robots.txt  { access_log off; log_not_found off; } | ||||||
|  |  | ||||||
|  |         add_header X-Content-Type-Options nosniff; | ||||||
|  |         add_header X-XSS-Protection "1; mode=block"; | ||||||
|  |         add_header X-Robots-Tag none; | ||||||
|  |         add_header Content-Security-Policy "frame-ancestors 'self'"; | ||||||
|  |  | ||||||
|  |         location ~ \.php$ { | ||||||
|  |             fastcgi_pass php:9000; | ||||||
|  |             fastcgi_index index.php; | ||||||
|  |             include fastcgi_params; | ||||||
|  |             fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; | ||||||
|  |             include /etc/nginx/fastcgi_params; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										2
									
								
								public/assets/css/crater.css
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								public/assets/css/crater.css
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										1
									
								
								public/assets/css/crater.css.map
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								public/assets/css/crater.css.map
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @ -1,4 +1,4 @@ | |||||||
| { | { | ||||||
|     "/assets/js/app.js": "/assets/js/app.js?id=2a5cfd8271e10bd501dc", |     "/assets/js/app.js": "/assets/js/app.js?id=a9f802b3fe774e87bf0c", | ||||||
|     "/assets/css/crater.css": "/assets/css/crater.css?id=108e3a8d009e7d38018c" |     "/assets/css/crater.css": "/assets/css/crater.css?id=193e5770a0e7a8604f35" | ||||||
| } | } | ||||||
|  | |||||||
| @ -29,7 +29,7 @@ Web Application is made using Laravel & VueJS while the Mobile Apps are built us | |||||||
|  |  | ||||||
| ## Mobile Apps | ## Mobile Apps | ||||||
| - [Android](https://play.google.com/store/apps/details?id=com.craterapp.app) | - [Android](https://play.google.com/store/apps/details?id=com.craterapp.app) | ||||||
| - IOS - Coming Soon | - [IOS](https://apps.apple.com/app/id1489169767) | ||||||
| - [Source](https://github.com/bytefury/crater-mobile) | - [Source](https://github.com/bytefury/crater-mobile) | ||||||
|  |  | ||||||
| ## Discord | ## Discord | ||||||
| @ -60,6 +60,10 @@ Join the Crater discord server to discuss: | |||||||
| ## Credits | ## Credits | ||||||
| Crater is a product of [Bytefury](https://bytefury.com) | Crater is a product of [Bytefury](https://bytefury.com) | ||||||
|  |  | ||||||
|  | **Special thanks to:** | ||||||
|  | * [Birkhoff Lee](https://github.com/BirkhoffLee) | ||||||
|  |  | ||||||
|  |  | ||||||
| ## Translate | ## Translate | ||||||
| Help us translate on [Transifex](https://www.transifex.com/bytefury/crater-invoice) | Help us translate on [Transifex](https://www.transifex.com/bytefury/crater-invoice) | ||||||
|  |  | ||||||
|  | |||||||
							
								
								
									
										71
									
								
								resources/assets/js/components/base/BasePrefixInput.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								resources/assets/js/components/base/BasePrefixInput.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,71 @@ | |||||||
|  | <template> | ||||||
|  |   <div class="base-prefix-input" @click="focusInput"> | ||||||
|  |     <font-awesome-icon v-if="icon" :icon="icon" class="icon" /> | ||||||
|  |     <p class="prefix-label"><span class="mr-1">{{ prefix }}</span>-</p> | ||||||
|  |     <input | ||||||
|  |       ref="basePrefixInput" | ||||||
|  |       v-model="inputValue" | ||||||
|  |       :type="type" | ||||||
|  |       class="prefix-input-field" | ||||||
|  |       @input="handleInput" | ||||||
|  |       @change="handleChange" | ||||||
|  |       @keyup="handleKeyupEnter" | ||||||
|  |       @keydown="handleKeyDownEnter" | ||||||
|  |       @blur="handleFocusOut" | ||||||
|  |     > | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | export default { | ||||||
|  |   props: { | ||||||
|  |     prefix: { | ||||||
|  |       type: String, | ||||||
|  |       default: null, | ||||||
|  |       required: true | ||||||
|  |     }, | ||||||
|  |     icon: { | ||||||
|  |       type: String, | ||||||
|  |       default: null | ||||||
|  |     }, | ||||||
|  |     value: { | ||||||
|  |       type: [String, Number, File], | ||||||
|  |       default: '' | ||||||
|  |     }, | ||||||
|  |     type: { | ||||||
|  |       type: String, | ||||||
|  |       default: 'text' | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   data () { | ||||||
|  |     return { | ||||||
|  |       inputValue: this.value | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   watch: { | ||||||
|  |     'value' () { | ||||||
|  |       this.inputValue = this.value | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     focusInput () { | ||||||
|  |       this.$refs.basePrefixInput.focus() | ||||||
|  |     }, | ||||||
|  |     handleInput (e) { | ||||||
|  |       this.$emit('input', this.inputValue) | ||||||
|  |     }, | ||||||
|  |     handleChange (e) { | ||||||
|  |       this.$emit('change', this.inputValue) | ||||||
|  |     }, | ||||||
|  |     handleKeyupEnter (e) { | ||||||
|  |       this.$emit('keyup', this.inputValue) | ||||||
|  |     }, | ||||||
|  |     handleKeyDownEnter (e) { | ||||||
|  |       this.$emit('keydown', e, this.inputValue) | ||||||
|  |     }, | ||||||
|  |     handleFocusOut (e) { | ||||||
|  |       this.$emit('blur', this.inputValue) | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
| @ -8,6 +8,7 @@ import BaseTextArea from './BaseTextArea.vue' | |||||||
| import BaseSelect from './base-select/BaseSelect.vue' | import BaseSelect from './base-select/BaseSelect.vue' | ||||||
| import BaseLoader from './BaseLoader.vue' | import BaseLoader from './BaseLoader.vue' | ||||||
| import BaseCustomerSelect from './BaseCustomerSelect.vue' | import BaseCustomerSelect from './BaseCustomerSelect.vue' | ||||||
|  | import BasePrefixInput from './BasePrefixInput.vue' | ||||||
|  |  | ||||||
| import BasePopup from './popup/BasePopup.vue' | import BasePopup from './popup/BasePopup.vue' | ||||||
| import CustomerSelectPopup from './popup/CustomerSelectPopup.vue' | import CustomerSelectPopup from './popup/CustomerSelectPopup.vue' | ||||||
| @ -23,6 +24,7 @@ Vue.component('base-input', BaseInput) | |||||||
| Vue.component('base-switch', BaseSwitch) | Vue.component('base-switch', BaseSwitch) | ||||||
| Vue.component('base-text-area', BaseTextArea) | Vue.component('base-text-area', BaseTextArea) | ||||||
| Vue.component('base-loader', BaseLoader) | Vue.component('base-loader', BaseLoader) | ||||||
|  | Vue.component('base-prefix-input', BasePrefixInput) | ||||||
|  |  | ||||||
| Vue.component('table-component', TableComponent) | Vue.component('table-component', TableComponent) | ||||||
| Vue.component('table-column', TableColumn) | Vue.component('table-column', TableColumn) | ||||||
|  | |||||||
| @ -55,6 +55,7 @@ | |||||||
|                     v-model="currency" |                     v-model="currency" | ||||||
|                     :options="currencies" |                     :options="currencies" | ||||||
|                     :searchable="true" |                     :searchable="true" | ||||||
|  |                     :allow-empty="false" | ||||||
|                     :show-labels="false" |                     :show-labels="false" | ||||||
|                     :placeholder="$t('customers.select_currency')" |                     :placeholder="$t('customers.select_currency')" | ||||||
|                     label="name" |                     label="name" | ||||||
|  | |||||||
| @ -124,7 +124,7 @@ export default { | |||||||
|       }, |       }, | ||||||
|       percent: { |       percent: { | ||||||
|         required, |         required, | ||||||
|         between: between(0.10, 100) |         between: between(0, 100) | ||||||
|       }, |       }, | ||||||
|       description: { |       description: { | ||||||
|         maxLength: maxLength(255) |         maxLength: maxLength(255) | ||||||
|  | |||||||
| @ -530,6 +530,7 @@ | |||||||
|     "menu_title": { |     "menu_title": { | ||||||
|       "account_settings": "Account Settings", |       "account_settings": "Account Settings", | ||||||
|       "company_information": "Company Information", |       "company_information": "Company Information", | ||||||
|  |       "customization": "Customization", | ||||||
|       "preferences": "Preferences", |       "preferences": "Preferences", | ||||||
|       "notifications": "Notifications", |       "notifications": "Notifications", | ||||||
|       "tax_types": "Tax Types", |       "tax_types": "Tax Types", | ||||||
| @ -598,6 +599,67 @@ | |||||||
|       "save": "Save", |       "save": "Save", | ||||||
|       "updated_message": "Company information updated successfully" |       "updated_message": "Company information updated successfully" | ||||||
|     }, |     }, | ||||||
|  |     "customization": { | ||||||
|  |         "customization": "customization", | ||||||
|  |         "save": "Save", | ||||||
|  |         "addresses": { | ||||||
|  |             "title": "Addresses", | ||||||
|  |             "section_description": "You can set Customer Billing Address and Customer Shipping Address Format (Displayed in PDF only). ", | ||||||
|  |             "customer_billing_address": "Customer Billing Address", | ||||||
|  |             "customer_shipping_address": "Customer Shipping Address", | ||||||
|  |             "company_address": "Company Address", | ||||||
|  |             "insert_fields": "Insert Fields", | ||||||
|  |             "contact": "Contact", | ||||||
|  |             "address": "Address", | ||||||
|  |             "display_name": "Display Name", | ||||||
|  |             "primary_contact_name": "Primary Contact Name", | ||||||
|  |             "email": "Email", | ||||||
|  |             "website": "Website", | ||||||
|  |             "name": "Name", | ||||||
|  |             "country": "Country", | ||||||
|  |             "state": "State", | ||||||
|  |             "city": "City", | ||||||
|  |             "company_name": "Company Name", | ||||||
|  |             "address_street_1": "Address Street 1", | ||||||
|  |             "address_street_2": "Address Street 2", | ||||||
|  |             "phone": "Phone", | ||||||
|  |             "zip_code": "Zip Code", | ||||||
|  |             "address_setting_updated": "Address Setting updated successfully" | ||||||
|  |         }, | ||||||
|  |         "updated_message": "Company information updated successfully", | ||||||
|  |  | ||||||
|  |         "invoices": { | ||||||
|  |             "title": "Invoices", | ||||||
|  |             "notes": "Notes", | ||||||
|  |             "invoice_prefix": "Invoice Prefix", | ||||||
|  |             "invoice_settings": "Invoice Settings", | ||||||
|  |             "autogenerate_invoice_number": "Autogenerate Invoice Number", | ||||||
|  |             "invoice_setting_description": "Disable this, If you don't wish to auto-generate invoice numbers each time you create a new invoice.", | ||||||
|  |             "enter_invoice_prefix": "Enter invoice prefix", | ||||||
|  |             "terms_and_conditions": "Terms and Conditions", | ||||||
|  |             "invoice_setting_updated": "Invoice Setting updated successfully" | ||||||
|  |         }, | ||||||
|  |  | ||||||
|  |         "estimates": { | ||||||
|  |             "title": "Estimates", | ||||||
|  |             "estimate_prefix": "Estimate Prefix", | ||||||
|  |             "estimate_settings": "Estimate Settings", | ||||||
|  |             "autogenerate_estimate_number": "Autogenerate Estimate Number", | ||||||
|  |             "estimate_setting_description": "Disable this, If you don't wish to auto-generate estimate numbers each time you create a new estimate.", | ||||||
|  |             "enter_estimate_prefix": "Enter estmiate prefix", | ||||||
|  |             "estimate_setting_updated": "Estimate Setting updated successfully" | ||||||
|  |         }, | ||||||
|  |  | ||||||
|  |         "payments": { | ||||||
|  |             "title": "Payments", | ||||||
|  |             "payment_prefix": "Payment Prefix", | ||||||
|  |             "payment_settings": "Payment Settings", | ||||||
|  |             "autogenerate_payment_number": "Autogenerate Payment Number", | ||||||
|  |             "payment_setting_description": "Disable this, If you don't wish to auto-generate payment numbers each time you create a new payment.", | ||||||
|  |             "enter_payment_prefix": "Enter Payment Prefix", | ||||||
|  |             "payment_setting_updated": "Payment Setting updated successfully" | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|     "account_settings": { |     "account_settings": { | ||||||
|       "profile_picture": "Profile Picture", |       "profile_picture": "Profile Picture", | ||||||
|       "name": "Name", |       "name": "Name", | ||||||
| @ -666,7 +728,7 @@ | |||||||
|       "date_format": "Date Format", |       "date_format": "Date Format", | ||||||
|       "discount_setting": "Discount Setting", |       "discount_setting": "Discount Setting", | ||||||
|       "discount_per_item": "Discount Per Item ", |       "discount_per_item": "Discount Per Item ", | ||||||
|       "discount_setting_description": "Enable this if you want to add Discount to individual invoice items. By default, Discount are added directly to the invoice.", |       "discount_setting_description": "Enable this if you want to add Discount to individual invoice items. By default, Discount is added directly to the invoice.", | ||||||
|       "save": "Save", |       "save": "Save", | ||||||
|       "preference": "Preference | Preferences", |       "preference": "Preference | Preferences", | ||||||
|       "general_settings": "Default preferences for the system.", |       "general_settings": "Default preferences for the system.", | ||||||
| @ -812,6 +874,7 @@ | |||||||
|     "maximum_options_error": "Maximum  of {max} options selected. First remove a selected option to select another.", |     "maximum_options_error": "Maximum  of {max} options selected. First remove a selected option to select another.", | ||||||
|     "notes_maxlength": "Notes should not be greater than 255 characters.", |     "notes_maxlength": "Notes should not be greater than 255 characters.", | ||||||
|     "address_maxlength": "Address should not be greater than 255 characters.", |     "address_maxlength": "Address should not be greater than 255 characters.", | ||||||
|     "ref_number_maxlength": "Ref Number should not be greater than 255 characters." |     "ref_number_maxlength": "Ref Number should not be greater than 255 characters.", | ||||||
|  |     "prefix_maxlength": "Prefix should not be greater than 5 characters." | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | |||||||
| @ -66,6 +66,7 @@ import ReportLayout from './views/reports/layout/Index.vue' | |||||||
| // Settings | // Settings | ||||||
| import SettingsLayout from './views/settings/layout/Index.vue' | import SettingsLayout from './views/settings/layout/Index.vue' | ||||||
| import CompanyInfo from './views/settings/CompanyInfo.vue' | import CompanyInfo from './views/settings/CompanyInfo.vue' | ||||||
|  | import Customization from './views/settings/Customization.vue' | ||||||
| import Notifications from './views/settings/Notifications.vue' | import Notifications from './views/settings/Notifications.vue' | ||||||
| import Preferences from './views/settings/Preferences.vue' | import Preferences from './views/settings/Preferences.vue' | ||||||
| import UserProfile from './views/settings/UserProfile.vue' | import UserProfile from './views/settings/UserProfile.vue' | ||||||
| @ -309,6 +310,11 @@ const routes = [ | |||||||
|             name: 'company.info', |             name: 'company.info', | ||||||
|             component: CompanyInfo |             component: CompanyInfo | ||||||
|           }, |           }, | ||||||
|  |           { | ||||||
|  |             path: 'customization', | ||||||
|  |             name: 'customization', | ||||||
|  |             component: Customization | ||||||
|  |           }, | ||||||
|           { |           { | ||||||
|             path: 'user-profile', |             path: 'user-profile', | ||||||
|             name: 'user.profile', |             name: 'user.profile', | ||||||
|  | |||||||
| @ -9,10 +9,11 @@ export default { | |||||||
|   bootstrap ({ commit, dispatch, state }) { |   bootstrap ({ commit, dispatch, state }) { | ||||||
|     return new Promise((resolve, reject) => { |     return new Promise((resolve, reject) => { | ||||||
|       window.axios.get('/api/bootstrap').then((response) => { |       window.axios.get('/api/bootstrap').then((response) => { | ||||||
|  |         commit('company/' + companyTypes.BOOTSTRAP_COMPANIES, response.data.companies) | ||||||
|  |         commit('company/' + companyTypes.SET_SELECTED_COMPANY, response.data.company) | ||||||
|         commit('currency/' + currencyTypes.BOOTSTRAP_CURRENCIES, response.data) |         commit('currency/' + currencyTypes.BOOTSTRAP_CURRENCIES, response.data) | ||||||
|         commit('currency/' + currencyTypes.SET_DEFAULT_CURRENCY, response.data) |         commit('currency/' + currencyTypes.SET_DEFAULT_CURRENCY, response.data) | ||||||
|         commit('user/' + userTypes.BOOTSTRAP_CURRENT_USER, response.data.user) |         commit('user/' + userTypes.BOOTSTRAP_CURRENT_USER, response.data.user) | ||||||
|         commit('company/' + companyTypes.BOOTSTRAP_COMPANIES, response.data.companies) |  | ||||||
|         commit('taxType/' + taxTypeTypes.BOOTSTRAP_TAX_TYPES, response.data.taxTypes) |         commit('taxType/' + taxTypeTypes.BOOTSTRAP_TAX_TYPES, response.data.taxTypes) | ||||||
|         commit('preferences/' + preferencesTypes.SET_MOMENT_DATE_FORMAT, response.data.moment_date_format) |         commit('preferences/' + preferencesTypes.SET_MOMENT_DATE_FORMAT, response.data.moment_date_format) | ||||||
|         commit('preferences/' + preferencesTypes.SET_LANGUAGE_FORMAT, response.data.default_language) |         commit('preferences/' + preferencesTypes.SET_LANGUAGE_FORMAT, response.data.default_language) | ||||||
|  | |||||||
| @ -1,7 +1,5 @@ | |||||||
| import * as types from './mutation-types' | import * as types from './mutation-types' | ||||||
| import Ls from '@/services/ls' |  | ||||||
|  |  | ||||||
| export const setSelectedCompany = ({ commit, dispatch, state }, data) => { | export const setSelectedCompany = ({ commit, dispatch, state }, data) => { | ||||||
|   Ls.set('selectedCompany', data.id) |  | ||||||
|   commit(types.SET_SELECTED_COMPANY, data) |   commit(types.SET_SELECTED_COMPANY, data) | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,4 +1,5 @@ | |||||||
| import * as types from './mutation-types' | import * as types from './mutation-types' | ||||||
|  | import Ls from '@/services/ls' | ||||||
|  |  | ||||||
| export default { | export default { | ||||||
|   [types.BOOTSTRAP_COMPANIES] (state, companies) { |   [types.BOOTSTRAP_COMPANIES] (state, companies) { | ||||||
| @ -6,6 +7,7 @@ export default { | |||||||
|     state.selectedCompany = companies[0] |     state.selectedCompany = companies[0] | ||||||
|   }, |   }, | ||||||
|   [types.SET_SELECTED_COMPANY] (state, company) { |   [types.SET_SELECTED_COMPANY] (state, company) { | ||||||
|  |     Ls.set('selectedCompany', company.id) | ||||||
|     state.selectedCompany = company |     state.selectedCompany = company | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | |||||||
| @ -61,6 +61,7 @@ | |||||||
|                 <base-select |                 <base-select | ||||||
|                   v-model="currency" |                   v-model="currency" | ||||||
|                   :options="currencies" |                   :options="currencies" | ||||||
|  |                   :custom-label="currencyNameWithCode" | ||||||
|                   :allow-empty="false" |                   :allow-empty="false" | ||||||
|                   :searchable="true" |                   :searchable="true" | ||||||
|                   :show-labels="false" |                   :show-labels="false" | ||||||
| @ -161,7 +162,7 @@ | |||||||
|                   :options="billingCountries" |                   :options="billingCountries" | ||||||
|                   :searchable="true" |                   :searchable="true" | ||||||
|                   :show-labels="false" |                   :show-labels="false" | ||||||
|                   :allow-empty="false" |                   :allow-empty="true" | ||||||
|                   :tabindex="8" |                   :tabindex="8" | ||||||
|                   :placeholder="$t('general.select_country')" |                   :placeholder="$t('general.select_country')" | ||||||
|                   label="name" |                   label="name" | ||||||
| @ -264,7 +265,7 @@ | |||||||
|                   :searchable="true" |                   :searchable="true" | ||||||
|                   :show-labels="false" |                   :show-labels="false" | ||||||
|                   :tabindex="16" |                   :tabindex="16" | ||||||
|                   :allow-empty="false" |                   :allow-empty="true" | ||||||
|                   :placeholder="$t('general.select_country')" |                   :placeholder="$t('general.select_country')" | ||||||
|                   label="name" |                   label="name" | ||||||
|                   track-by="id" |                   track-by="id" | ||||||
| @ -410,6 +411,36 @@ export default { | |||||||
|         return true |         return true | ||||||
|       } |       } | ||||||
|       return false |       return false | ||||||
|  |     }, | ||||||
|  |     hasBillingAdd () { | ||||||
|  |       let billing = this.billing | ||||||
|  |       if ( | ||||||
|  |         billing.name || | ||||||
|  |         billing.country_id || | ||||||
|  |         billing.state || | ||||||
|  |         billing.city || | ||||||
|  |         billing.phone || | ||||||
|  |         billing.zip || | ||||||
|  |         billing.address_street_1 || | ||||||
|  |         billing.address_street_2) { | ||||||
|  |         return true | ||||||
|  |       } | ||||||
|  |       return false | ||||||
|  |     }, | ||||||
|  |     hasShippingAdd () { | ||||||
|  |       let shipping = this.shipping | ||||||
|  |       if ( | ||||||
|  |         shipping.name || | ||||||
|  |         shipping.country_id || | ||||||
|  |         shipping.state || | ||||||
|  |         shipping.city || | ||||||
|  |         shipping.phone || | ||||||
|  |         shipping.zip || | ||||||
|  |         shipping.address_street_1 || | ||||||
|  |         shipping.address_street_2) { | ||||||
|  |         return true | ||||||
|  |       } | ||||||
|  |       return false | ||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
|   watch: { |   watch: { | ||||||
| @ -417,12 +448,16 @@ export default { | |||||||
|       if (newCountry) { |       if (newCountry) { | ||||||
|         this.billing.country_id = newCountry.id |         this.billing.country_id = newCountry.id | ||||||
|         this.isDisabledBillingState = false |         this.isDisabledBillingState = false | ||||||
|  |       } else { | ||||||
|  |         this.billing.country_id = null | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     shipping_country (newCountry) { |     shipping_country (newCountry) { | ||||||
|       if (newCountry) { |       if (newCountry) { | ||||||
|         this.shipping.country_id = newCountry.id |         this.shipping.country_id = newCountry.id | ||||||
|         return true |         return true | ||||||
|  |       } else { | ||||||
|  |         this.shipping.country_id = null | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
| @ -435,6 +470,9 @@ export default { | |||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
|   methods: { |   methods: { | ||||||
|  |     currencyNameWithCode ({name, code}) { | ||||||
|  |       return `${code} - ${name}` | ||||||
|  |     }, | ||||||
|     ...mapActions('customer', [ |     ...mapActions('customer', [ | ||||||
|       'addCustomer', |       'addCustomer', | ||||||
|       'fetchCustomer', |       'fetchCustomer', | ||||||
| @ -442,7 +480,14 @@ export default { | |||||||
|     ]), |     ]), | ||||||
|     async loadCustomer () { |     async loadCustomer () { | ||||||
|       let { data: { customer, currencies, currency } } = await this.fetchCustomer(this.$route.params.id) |       let { data: { customer, currencies, currency } } = await this.fetchCustomer(this.$route.params.id) | ||||||
|       this.formData = customer |  | ||||||
|  |       this.formData.id = customer.id | ||||||
|  |       this.formData.name = customer.name | ||||||
|  |       this.formData.contact_name = customer.contact_name | ||||||
|  |       this.formData.email = customer.email | ||||||
|  |       this.formData.phone = customer.phone | ||||||
|  |       this.formData.currency_id = customer.currency_id | ||||||
|  |       this.formData.website = customer.website | ||||||
|  |  | ||||||
|       if (customer.billing_address) { |       if (customer.billing_address) { | ||||||
|         this.billing = customer.billing_address |         this.billing = customer.billing_address | ||||||
| @ -491,7 +536,16 @@ export default { | |||||||
|       if (this.$v.$invalid) { |       if (this.$v.$invalid) { | ||||||
|         return true |         return true | ||||||
|       } |       } | ||||||
|       this.formData.addresses = [{...this.billing}, {...this.shipping}] |       if (this.hasBillingAdd && this.hasShippingAdd) { | ||||||
|  |         this.formData.addresses = [{...this.billing}, {...this.shipping}] | ||||||
|  |       } else { | ||||||
|  |         if (this.hasBillingAdd) { | ||||||
|  |           this.formData.addresses = [{...this.billing}] | ||||||
|  |         } | ||||||
|  |         if (this.hasShippingAdd) { | ||||||
|  |           this.formData.addresses = [{...this.shipping}] | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |  | ||||||
|       if (this.isEdit) { |       if (this.isEdit) { | ||||||
|         if (this.currency) { |         if (this.currency) { | ||||||
|  | |||||||
| @ -32,8 +32,8 @@ | |||||||
|             class="show-customer" |             class="show-customer" | ||||||
|           > |           > | ||||||
|             <div class="row px-2 mt-1"> |             <div class="row px-2 mt-1"> | ||||||
|               <div class="col col-6"> |               <div v-if="selectedCustomer.billing_address" class="col col-6"> | ||||||
|                 <div v-if="selectedCustomer.billing_address != null" class="row address-menu"> |                 <div class="row address-menu"> | ||||||
|                   <label class="col-sm-4 px-2 title">{{ $t('general.bill_to') }}</label> |                   <label class="col-sm-4 px-2 title">{{ $t('general.bill_to') }}</label> | ||||||
|                   <div class="col-sm p-0 px-2 content"> |                   <div class="col-sm p-0 px-2 content"> | ||||||
|                     <label v-if="selectedCustomer.billing_address.name"> |                     <label v-if="selectedCustomer.billing_address.name"> | ||||||
| @ -57,8 +57,8 @@ | |||||||
|                   </div> |                   </div> | ||||||
|                 </div> |                 </div> | ||||||
|               </div> |               </div> | ||||||
|               <div class="col col-6"> |               <div v-if="selectedCustomer.shipping_address" class="col col-6"> | ||||||
|                 <div v-if="selectedCustomer.shipping_address != null" class="row address-menu"> |                 <div class="row address-menu"> | ||||||
|                   <label class="col-sm-4 px-2 title">{{ $t('general.ship_to') }}</label> |                   <label class="col-sm-4 px-2 title">{{ $t('general.ship_to') }}</label> | ||||||
|                   <div class="col-sm p-0 px-2 content"> |                   <div class="col-sm p-0 px-2 content"> | ||||||
|                     <label v-if="selectedCustomer.shipping_address.name"> |                     <label v-if="selectedCustomer.shipping_address.name"> | ||||||
| @ -84,7 +84,7 @@ | |||||||
|               </div> |               </div> | ||||||
|             </div> |             </div> | ||||||
|             <div class="customer-content mb-1"> |             <div class="customer-content mb-1"> | ||||||
|               <label class="email">{{ selectedCustomer.email ? selectedCustomer.email : selectedCustomer.name }}</label> |               <label class="email">{{ selectedCustomer.name }}</label> | ||||||
|               <label class="action" @click="removeCustomer">{{ $t('general.remove') }}</label> |               <label class="action" @click="removeCustomer">{{ $t('general.remove') }}</label> | ||||||
|             </div> |             </div> | ||||||
|           </div> |           </div> | ||||||
| @ -127,14 +127,15 @@ | |||||||
|           <div class="row mt-4"> |           <div class="row mt-4"> | ||||||
|             <div class="col collapse-input"> |             <div class="col collapse-input"> | ||||||
|               <label>{{ $t('estimates.estimate_number') }}<span class="text-danger"> * </span></label> |               <label>{{ $t('estimates.estimate_number') }}<span class="text-danger"> * </span></label> | ||||||
|               <base-input |               <base-prefix-input | ||||||
|                 :invalid="$v.newEstimate.estimate_number.$error" |                 v-model="estimateNumAttribute" | ||||||
|                 :read-only="true" |                 :invalid="$v.estimateNumAttribute.$error" | ||||||
|                 v-model="newEstimate.estimate_number" |                 :prefix="estimatePrefix" | ||||||
|                 icon="hashtag" |                 icon="hashtag" | ||||||
|                 @input="$v.newEstimate.estimate_number.$touch()" |                 @input="$v.estimateNumAttribute.$touch()" | ||||||
|               /> |               /> | ||||||
|               <span v-show="$v.newEstimate.estimate_number.$error && !$v.newEstimate.estimate_number.required" class="text-danger mt-1"> {{ $tc('estimates.errors.required') }}  </span> |               <span v-show="$v.estimateNumAttribute.$error && !$v.estimateNumAttribute.required" class="text-danger mt-1"> {{ $tc('estimates.errors.required') }}  </span> | ||||||
|  |               <span v-show="!$v.estimateNumAttribute.numeric" class="text-danger mt-1"> {{ $tc('validation.numbers_only') }}  </span> | ||||||
|             </div> |             </div> | ||||||
|             <div class="col collapse-input"> |             <div class="col collapse-input"> | ||||||
|               <label>{{ $t('estimates.ref_number') }}</label> |               <label>{{ $t('estimates.ref_number') }}</label> | ||||||
| @ -320,7 +321,7 @@ import { validationMixin } from 'vuelidate' | |||||||
| import Guid from 'guid' | import Guid from 'guid' | ||||||
| import TaxStub from '../../stub/tax' | import TaxStub from '../../stub/tax' | ||||||
| import Tax from './EstimateTax' | import Tax from './EstimateTax' | ||||||
| const { required, between, maxLength } = require('vuelidate/lib/validators') | const { required, between, maxLength, numeric } = require('vuelidate/lib/validators') | ||||||
|  |  | ||||||
| export default { | export default { | ||||||
|   components: { |   components: { | ||||||
| @ -361,7 +362,9 @@ export default { | |||||||
|       discountPerItem: null, |       discountPerItem: null, | ||||||
|       initLoading: false, |       initLoading: false, | ||||||
|       isLoading: false, |       isLoading: false, | ||||||
|       maxDiscount: 0 |       maxDiscount: 0, | ||||||
|  |       estimatePrefix: null, | ||||||
|  |       estimateNumAttribute: null | ||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
|   validations () { |   validations () { | ||||||
| @ -373,9 +376,6 @@ export default { | |||||||
|         expiry_date: { |         expiry_date: { | ||||||
|           required |           required | ||||||
|         }, |         }, | ||||||
|         estimate_number: { |  | ||||||
|           required |  | ||||||
|         }, |  | ||||||
|         discount_val: { |         discount_val: { | ||||||
|           between: between(0, this.subtotal) |           between: between(0, this.subtotal) | ||||||
|         }, |         }, | ||||||
| @ -388,6 +388,10 @@ export default { | |||||||
|       }, |       }, | ||||||
|       selectedCustomer: { |       selectedCustomer: { | ||||||
|         required |         required | ||||||
|  |       }, | ||||||
|  |       estimateNumAttribute: { | ||||||
|  |         required, | ||||||
|  |         numeric | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
| @ -559,6 +563,8 @@ export default { | |||||||
|           this.taxPerItem = response.data.tax_per_item |           this.taxPerItem = response.data.tax_per_item | ||||||
|           this.selectedCurrency = this.defaultCurrency |           this.selectedCurrency = this.defaultCurrency | ||||||
|           this.estimateTemplates = response.data.estimateTemplates |           this.estimateTemplates = response.data.estimateTemplates | ||||||
|  |           this.estimatePrefix = response.data.estimate_prefix | ||||||
|  |           this.estimateNumAttribute = response.data.nextEstimateNumber | ||||||
|         } |         } | ||||||
|         this.initLoading = false |         this.initLoading = false | ||||||
|         return |         return | ||||||
| @ -574,8 +580,9 @@ export default { | |||||||
|         let today = new Date() |         let today = new Date() | ||||||
|         this.newEstimate.estimate_date = moment(today).toString() |         this.newEstimate.estimate_date = moment(today).toString() | ||||||
|         this.newEstimate.expiry_date = moment(today).add(7, 'days').toString() |         this.newEstimate.expiry_date = moment(today).add(7, 'days').toString() | ||||||
|         this.newEstimate.estimate_number = response.data.nextEstimateNumber |  | ||||||
|         this.itemList = response.data.items |         this.itemList = response.data.items | ||||||
|  |         this.estimatePrefix = response.data.estimate_prefix | ||||||
|  |         this.estimateNumAttribute = response.data.nextEstimateNumberAttribute | ||||||
|       } |       } | ||||||
|       this.initLoading = false |       this.initLoading = false | ||||||
|     }, |     }, | ||||||
| @ -604,6 +611,7 @@ export default { | |||||||
|       } |       } | ||||||
|  |  | ||||||
|       this.isLoading = true |       this.isLoading = true | ||||||
|  |       this.newEstimate.estimate_number = this.estimatePrefix + '-' + this.estimateNumAttribute | ||||||
|  |  | ||||||
|       let data = { |       let data = { | ||||||
|         ...this.newEstimate, |         ...this.newEstimate, | ||||||
| @ -637,7 +645,11 @@ export default { | |||||||
|         this.isLoading = false |         this.isLoading = false | ||||||
|       }).catch((err) => { |       }).catch((err) => { | ||||||
|         this.isLoading = false |         this.isLoading = false | ||||||
|         console.log(err) |         if (err.response.data.errors.estimate_number) { | ||||||
|  |           window.toastr['error'](err.response.data.errors.estimate_number) | ||||||
|  |           return true | ||||||
|  |         } | ||||||
|  |         window.toastr['error'](err.response.data.message) | ||||||
|       }) |       }) | ||||||
|     }, |     }, | ||||||
|     submitUpdate (data) { |     submitUpdate (data) { | ||||||
| @ -650,7 +662,11 @@ export default { | |||||||
|         this.isLoading = false |         this.isLoading = false | ||||||
|       }).catch((err) => { |       }).catch((err) => { | ||||||
|         this.isLoading = false |         this.isLoading = false | ||||||
|         console.log(err) |         if (err.response.data.errors.estimate_number) { | ||||||
|  |           window.toastr['error'](err.response.data.errors.estimate_number) | ||||||
|  |           return true | ||||||
|  |         } | ||||||
|  |         window.toastr['error'](err.response.data.message) | ||||||
|       }) |       }) | ||||||
|     }, |     }, | ||||||
|     checkItemsData (index, isValid) { |     checkItemsData (index, isValid) { | ||||||
|  | |||||||
| @ -151,6 +151,7 @@ export default { | |||||||
|       id: null, |       id: null, | ||||||
|       count: null, |       count: null, | ||||||
|       estimates: [], |       estimates: [], | ||||||
|  |       estimate: null, | ||||||
|       currency: null, |       currency: null, | ||||||
|       searchData: { |       searchData: { | ||||||
|         orderBy: null, |         orderBy: null, | ||||||
| @ -165,10 +166,6 @@ export default { | |||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
|   computed: { |   computed: { | ||||||
|     estimate () { |  | ||||||
|       return this.$store.getters['estimate/getEstimate'](this.$route.params.id) |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     getOrderBy () { |     getOrderBy () { | ||||||
|       if (this.searchData.orderBy === 'asc' || this.searchData.orderBy == null) { |       if (this.searchData.orderBy === 'asc' || this.searchData.orderBy == null) { | ||||||
|         return true |         return true | ||||||
| @ -180,8 +177,14 @@ export default { | |||||||
|       return `/estimates/pdf/${this.estimate.unique_hash}` |       return `/estimates/pdf/${this.estimate.unique_hash}` | ||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
|  |   watch: { | ||||||
|  |     $route (to, from) { | ||||||
|  |       this.loadEstimate() | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|   created () { |   created () { | ||||||
|     this.loadEstimates() |     this.loadEstimates() | ||||||
|  |     this.loadEstimate() | ||||||
|     this.onSearched = _.debounce(this.onSearched, 500) |     this.onSearched = _.debounce(this.onSearched, 500) | ||||||
|   }, |   }, | ||||||
|   methods: { |   methods: { | ||||||
| @ -192,7 +195,8 @@ export default { | |||||||
|       'markAsSent', |       'markAsSent', | ||||||
|       'sendEmail', |       'sendEmail', | ||||||
|       'deleteEstimate', |       'deleteEstimate', | ||||||
|       'selectEstimate' |       'selectEstimate', | ||||||
|  |       'fetchViewEstimate' | ||||||
|     ]), |     ]), | ||||||
|     async loadEstimates () { |     async loadEstimates () { | ||||||
|       let response = await this.fetchEstimates() |       let response = await this.fetchEstimates() | ||||||
| @ -200,6 +204,13 @@ export default { | |||||||
|         this.estimates = response.data.estimates.data |         this.estimates = response.data.estimates.data | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     async loadEstimate () { | ||||||
|  |       let response = await this.fetchViewEstimate(this.$route.params.id) | ||||||
|  |  | ||||||
|  |       if (response.data) { | ||||||
|  |         this.estimate = response.data.estimate | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     async onSearched () { |     async onSearched () { | ||||||
|       let data = '' |       let data = '' | ||||||
|       if (this.searchData.searchText !== '' && this.searchData.searchText !== null && this.searchData.searchText !== undefined) { |       if (this.searchData.searchText !== '' && this.searchData.searchText !== null && this.searchData.searchText !== undefined) { | ||||||
|  | |||||||
| @ -30,8 +30,8 @@ | |||||||
|           <div |           <div | ||||||
|             v-if="selectedCustomer" class="show-customer"> |             v-if="selectedCustomer" class="show-customer"> | ||||||
|             <div class="row px-2 mt-1"> |             <div class="row px-2 mt-1"> | ||||||
|               <div class="col col-6"> |               <div v-if="selectedCustomer.billing_address" class="col col-6"> | ||||||
|                 <div v-if="selectedCustomer.billing_address" class="row address-menu"> |                 <div class="row address-menu"> | ||||||
|                   <label class="col-sm-4 px-2 title">{{ $t('general.bill_to') }}</label> |                   <label class="col-sm-4 px-2 title">{{ $t('general.bill_to') }}</label> | ||||||
|                   <div class="col-sm p-0 px-2 content"> |                   <div class="col-sm p-0 px-2 content"> | ||||||
|                     <label v-if="selectedCustomer.billing_address.name"> |                     <label v-if="selectedCustomer.billing_address.name"> | ||||||
| @ -55,8 +55,8 @@ | |||||||
|                   </div> |                   </div> | ||||||
|                 </div> |                 </div> | ||||||
|               </div> |               </div> | ||||||
|               <div class="col col-6"> |               <div v-if="selectedCustomer.shipping_address" class="col col-6"> | ||||||
|                 <div v-if="selectedCustomer.shipping_address" class="row address-menu"> |                 <div class="row address-menu"> | ||||||
|                   <label class="col-sm-4 px-2 title">{{ $t('general.ship_to') }}</label> |                   <label class="col-sm-4 px-2 title">{{ $t('general.ship_to') }}</label> | ||||||
|                   <div class="col-sm p-0 px-2 content"> |                   <div class="col-sm p-0 px-2 content"> | ||||||
|                     <label v-if="selectedCustomer.shipping_address.name"> |                     <label v-if="selectedCustomer.shipping_address.name"> | ||||||
| @ -127,14 +127,15 @@ | |||||||
|           <div class="row mt-4"> |           <div class="row mt-4"> | ||||||
|             <div class="col collapse-input"> |             <div class="col collapse-input"> | ||||||
|               <label>{{ $t('invoices.invoice_number') }}<span class="text-danger"> * </span></label> |               <label>{{ $t('invoices.invoice_number') }}<span class="text-danger"> * </span></label> | ||||||
|               <base-input |               <base-prefix-input | ||||||
|                 :invalid="$v.newInvoice.invoice_number.$error" |                 v-model="invoiceNumAttribute" | ||||||
|                 :read-only="true" |                 :invalid="$v.invoiceNumAttribute.$error" | ||||||
|                 v-model="newInvoice.invoice_number" |                 :prefix="invoicePrefix" | ||||||
|                 icon="hashtag" |                 icon="hashtag" | ||||||
|                 @input="$v.newInvoice.invoice_number.$touch()" |                 @input="$v.invoiceNumAttribute.$touch()" | ||||||
|               /> |               /> | ||||||
|               <span v-show="$v.newInvoice.invoice_number.$error && !$v.newInvoice.invoice_number.required" class="text-danger mt-1"> {{ $tc('validation.required') }}  </span> |               <span v-show="$v.invoiceNumAttribute.$error && !$v.invoiceNumAttribute.required" class="text-danger mt-1"> {{ $tc('validation.required') }}  </span> | ||||||
|  |               <span v-show="!$v.invoiceNumAttribute.numeric" class="text-danger mt-1"> {{ $tc('validation.numbers_only') }}  </span> | ||||||
|             </div> |             </div> | ||||||
|             <div class="col collapse-input"> |             <div class="col collapse-input"> | ||||||
|               <label>{{ $t('invoices.ref_number') }}</label> |               <label>{{ $t('invoices.ref_number') }}</label> | ||||||
| @ -320,7 +321,7 @@ import { validationMixin } from 'vuelidate' | |||||||
| import Guid from 'guid' | import Guid from 'guid' | ||||||
| import TaxStub from '../../stub/tax' | import TaxStub from '../../stub/tax' | ||||||
| import Tax from './InvoiceTax' | import Tax from './InvoiceTax' | ||||||
| const { required, between, maxLength } = require('vuelidate/lib/validators') | const { required, between, maxLength, numeric } = require('vuelidate/lib/validators') | ||||||
|  |  | ||||||
| export default { | export default { | ||||||
|   components: { |   components: { | ||||||
| @ -361,7 +362,9 @@ export default { | |||||||
|       discountPerItem: null, |       discountPerItem: null, | ||||||
|       initLoading: false, |       initLoading: false, | ||||||
|       isLoading: false, |       isLoading: false, | ||||||
|       maxDiscount: 0 |       maxDiscount: 0, | ||||||
|  |       invoicePrefix: null, | ||||||
|  |       invoiceNumAttribute: null | ||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
|   validations () { |   validations () { | ||||||
| @ -373,9 +376,6 @@ export default { | |||||||
|         due_date: { |         due_date: { | ||||||
|           required |           required | ||||||
|         }, |         }, | ||||||
|         invoice_number: { |  | ||||||
|           required |  | ||||||
|         }, |  | ||||||
|         discount_val: { |         discount_val: { | ||||||
|           between: between(0, this.subtotal) |           between: between(0, this.subtotal) | ||||||
|         }, |         }, | ||||||
| @ -388,6 +388,10 @@ export default { | |||||||
|       }, |       }, | ||||||
|       selectedCustomer: { |       selectedCustomer: { | ||||||
|         required |         required | ||||||
|  |       }, | ||||||
|  |       invoiceNumAttribute: { | ||||||
|  |         required, | ||||||
|  |         numeric | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
| @ -559,6 +563,8 @@ export default { | |||||||
|           this.taxPerItem = response.data.tax_per_item |           this.taxPerItem = response.data.tax_per_item | ||||||
|           this.selectedCurrency = this.defaultCurrency |           this.selectedCurrency = this.defaultCurrency | ||||||
|           this.invoiceTemplates = response.data.invoiceTemplates |           this.invoiceTemplates = response.data.invoiceTemplates | ||||||
|  |           this.invoicePrefix = response.data.invoice_prefix | ||||||
|  |           this.invoiceNumAttribute = response.data.nextInvoiceNumber | ||||||
|         } |         } | ||||||
|         this.initLoading = false |         this.initLoading = false | ||||||
|         return |         return | ||||||
| @ -574,8 +580,9 @@ export default { | |||||||
|         let today = new Date() |         let today = new Date() | ||||||
|         this.newInvoice.invoice_date = moment(today).toString() |         this.newInvoice.invoice_date = moment(today).toString() | ||||||
|         this.newInvoice.due_date = moment(today).add(7, 'days').toString() |         this.newInvoice.due_date = moment(today).add(7, 'days').toString() | ||||||
|         this.newInvoice.invoice_number = response.data.nextInvoiceNumber |  | ||||||
|         this.itemList = response.data.items |         this.itemList = response.data.items | ||||||
|  |         this.invoicePrefix = response.data.invoice_prefix | ||||||
|  |         this.invoiceNumAttribute = response.data.nextInvoiceNumberAttribute | ||||||
|       } |       } | ||||||
|       this.initLoading = false |       this.initLoading = false | ||||||
|     }, |     }, | ||||||
| @ -604,6 +611,7 @@ export default { | |||||||
|       } |       } | ||||||
|  |  | ||||||
|       this.isLoading = true |       this.isLoading = true | ||||||
|  |       this.newInvoice.invoice_number = this.invoicePrefix + '-' + this.invoiceNumAttribute | ||||||
|  |  | ||||||
|       let data = { |       let data = { | ||||||
|         ...this.newInvoice, |         ...this.newInvoice, | ||||||
| @ -637,6 +645,10 @@ export default { | |||||||
|         this.isLoading = false |         this.isLoading = false | ||||||
|       }).catch((err) => { |       }).catch((err) => { | ||||||
|         this.isLoading = false |         this.isLoading = false | ||||||
|  |         if (err.response.data.errors.invoice_number) { | ||||||
|  |           window.toastr['error'](err.response.data.errors.invoice_number) | ||||||
|  |           return true | ||||||
|  |         } | ||||||
|         console.log(err) |         console.log(err) | ||||||
|       }) |       }) | ||||||
|     }, |     }, | ||||||
| @ -653,6 +665,10 @@ export default { | |||||||
|         } |         } | ||||||
|       }).catch((err) => { |       }).catch((err) => { | ||||||
|         this.isLoading = false |         this.isLoading = false | ||||||
|  |         if (err.response.data.errors.invoice_number) { | ||||||
|  |           window.toastr['error'](err.response.data.errors.invoice_number) | ||||||
|  |           return true | ||||||
|  |         } | ||||||
|         console.log(err) |         console.log(err) | ||||||
|       }) |       }) | ||||||
|     }, |     }, | ||||||
|  | |||||||
| @ -154,6 +154,7 @@ export default { | |||||||
|       id: null, |       id: null, | ||||||
|       count: null, |       count: null, | ||||||
|       invoices: [], |       invoices: [], | ||||||
|  |       invoice: null, | ||||||
|       currency: null, |       currency: null, | ||||||
|       searchData: { |       searchData: { | ||||||
|         orderBy: null, |         orderBy: null, | ||||||
| @ -167,9 +168,7 @@ export default { | |||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
|   computed: { |   computed: { | ||||||
|     invoice () { |  | ||||||
|       return this.$store.getters['invoice/getInvoice'](this.$route.params.id) |  | ||||||
|     }, |  | ||||||
|     getOrderBy () { |     getOrderBy () { | ||||||
|       if (this.searchData.orderBy === 'asc' || this.searchData.orderBy == null) { |       if (this.searchData.orderBy === 'asc' || this.searchData.orderBy == null) { | ||||||
|         return true |         return true | ||||||
| @ -180,8 +179,14 @@ export default { | |||||||
|       return `/invoices/pdf/${this.invoice.unique_hash}` |       return `/invoices/pdf/${this.invoice.unique_hash}` | ||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
|  |   watch: { | ||||||
|  |     $route (to, from) { | ||||||
|  |       this.loadInvoice() | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|   created () { |   created () { | ||||||
|     this.loadInvoices() |     this.loadInvoices() | ||||||
|  |     this.loadInvoice() | ||||||
|     this.onSearch = _.debounce(this.onSearch, 500) |     this.onSearch = _.debounce(this.onSearch, 500) | ||||||
|   }, |   }, | ||||||
|   methods: { |   methods: { | ||||||
| @ -192,7 +197,8 @@ export default { | |||||||
|       'markAsSent', |       'markAsSent', | ||||||
|       'sendEmail', |       'sendEmail', | ||||||
|       'deleteInvoice', |       'deleteInvoice', | ||||||
|       'selectInvoice' |       'selectInvoice', | ||||||
|  |       'fetchViewInvoice' | ||||||
|     ]), |     ]), | ||||||
|     async loadInvoices () { |     async loadInvoices () { | ||||||
|       let response = await this.fetchInvoices() |       let response = await this.fetchInvoices() | ||||||
| @ -200,6 +206,13 @@ export default { | |||||||
|         this.invoices = response.data.invoices.data |         this.invoices = response.data.invoices.data | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     async loadInvoice () { | ||||||
|  |       let response = await this.fetchViewInvoice(this.$route.params.id) | ||||||
|  |  | ||||||
|  |       if (response.data) { | ||||||
|  |         this.invoice = response.data.invoice | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     async onSearch () { |     async onSearch () { | ||||||
|       let data = '' |       let data = '' | ||||||
|       if (this.searchData.searchText !== '' && this.searchData.searchText !== null && this.searchData.searchText !== undefined) { |       if (this.searchData.searchText !== '' && this.searchData.searchText !== null && this.searchData.searchText !== undefined) { | ||||||
|  | |||||||
| @ -50,7 +50,7 @@ export default { | |||||||
|     Layout.set('layout-default') |     Layout.set('layout-default') | ||||||
|   }, |   }, | ||||||
|  |  | ||||||
|   created() { |   created () { | ||||||
|     this.bootstrap().then((res) => { |     this.bootstrap().then((res) => { | ||||||
|       this.setInitialCompany() |       this.setInitialCompany() | ||||||
|     }) |     }) | ||||||
| @ -59,7 +59,7 @@ export default { | |||||||
|   methods: { |   methods: { | ||||||
|     ...mapActions(['bootstrap']), |     ...mapActions(['bootstrap']), | ||||||
|     ...mapActions('company', ['setSelectedCompany']), |     ...mapActions('company', ['setSelectedCompany']), | ||||||
|     setInitialCompany() { |     setInitialCompany () { | ||||||
|       let selectedCompany = Ls.get('selectedCompany') !== null |       let selectedCompany = Ls.get('selectedCompany') !== null | ||||||
|  |  | ||||||
|       if (selectedCompany) { |       if (selectedCompany) { | ||||||
|  | |||||||
| @ -40,16 +40,15 @@ | |||||||
|             <div class="col-sm-6"> |             <div class="col-sm-6"> | ||||||
|               <div class="form-group"> |               <div class="form-group"> | ||||||
|                 <label class="form-label">{{ $t('payments.payment_number') }}</label><span class="text-danger"> *</span> |                 <label class="form-label">{{ $t('payments.payment_number') }}</label><span class="text-danger"> *</span> | ||||||
|                 <base-input |                 <base-prefix-input | ||||||
|                   :invalid="$v.formData.payment_number.$error" |                   :invalid="$v.paymentNumAttribute.$error" | ||||||
|                   v-model.trim="formData.payment_number" |                   v-model.trim="paymentNumAttribute" | ||||||
|                   read-only |                   :prefix="paymentPrefix" | ||||||
|                   type="text" |                   @input="$v.paymentNumAttribute.$touch()" | ||||||
|                   name="email" |  | ||||||
|                   @input="$v.formData.payment_number.$touch()" |  | ||||||
|                 /> |                 /> | ||||||
|                 <div v-if="$v.formData.payment_number.$error"> |                 <div v-if="$v.paymentNumAttribute.$error"> | ||||||
|                   <span v-if="!$v.formData.payment_number.required" class="text-danger">{{ $tc('validation.required') }}</span> |                   <span v-if="!$v.paymentNumAttribute.required" class="text-danger">{{ $tc('validation.required') }}</span> | ||||||
|  |                   <span v-if="!$v.paymentNumAttribute.numeric" class="text-danger">{{ $tc('validation.numbers_only') }}</span> | ||||||
|                 </div> |                 </div> | ||||||
|               </div> |               </div> | ||||||
|             </div> |             </div> | ||||||
| @ -155,7 +154,7 @@ import { mapActions, mapGetters } from 'vuex' | |||||||
| import MultiSelect from 'vue-multiselect' | import MultiSelect from 'vue-multiselect' | ||||||
| import { validationMixin } from 'vuelidate' | import { validationMixin } from 'vuelidate' | ||||||
| import moment from 'moment' | import moment from 'moment' | ||||||
| const { required, between, maxLength } = require('vuelidate/lib/validators') | const { required, between, maxLength, numeric } = require('vuelidate/lib/validators') | ||||||
|  |  | ||||||
| export default { | export default { | ||||||
|   components: { MultiSelect }, |   components: { MultiSelect }, | ||||||
| @ -184,7 +183,9 @@ export default { | |||||||
|       invoiceList: [], |       invoiceList: [], | ||||||
|       isLoading: false, |       isLoading: false, | ||||||
|       maxPayableAmount: Number.MAX_SAFE_INTEGER, |       maxPayableAmount: Number.MAX_SAFE_INTEGER, | ||||||
|       isSettingInitialData: true |       isSettingInitialData: true, | ||||||
|  |       paymentNumAttribute: null, | ||||||
|  |       paymentPrefix: '' | ||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
|   validations () { |   validations () { | ||||||
| @ -193,9 +194,6 @@ export default { | |||||||
|         required |         required | ||||||
|       }, |       }, | ||||||
|       formData: { |       formData: { | ||||||
|         payment_number: { |  | ||||||
|           required |  | ||||||
|         }, |  | ||||||
|         payment_date: { |         payment_date: { | ||||||
|           required |           required | ||||||
|         }, |         }, | ||||||
| @ -206,6 +204,10 @@ export default { | |||||||
|         notes: { |         notes: { | ||||||
|           maxLength: maxLength(255) |           maxLength: maxLength(255) | ||||||
|         } |         } | ||||||
|  |       }, | ||||||
|  |       paymentNumAttribute: { | ||||||
|  |         required, | ||||||
|  |         numeric | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
| @ -297,6 +299,8 @@ export default { | |||||||
|         this.customer = response.data.payment.user |         this.customer = response.data.payment.user | ||||||
|         this.formData.payment_date = moment(response.data.payment.payment_date, 'YYYY-MM-DD').toString() |         this.formData.payment_date = moment(response.data.payment.payment_date, 'YYYY-MM-DD').toString() | ||||||
|         this.formData.amount = parseFloat(response.data.payment.amount) |         this.formData.amount = parseFloat(response.data.payment.amount) | ||||||
|  |         this.paymentPrefix = response.data.payment_prefix | ||||||
|  |         this.paymentNumAttribute = response.data.nextPaymentNumber | ||||||
|         if (response.data.payment.invoice !== null) { |         if (response.data.payment.invoice !== null) { | ||||||
|           this.maxPayableAmount = parseInt(response.data.payment.amount) + parseInt(response.data.payment.invoice.due_amount) |           this.maxPayableAmount = parseInt(response.data.payment.amount) + parseInt(response.data.payment.invoice.due_amount) | ||||||
|           this.invoice = response.data.payment.invoice |           this.invoice = response.data.payment.invoice | ||||||
| @ -305,7 +309,8 @@ export default { | |||||||
|       } else { |       } else { | ||||||
|         let response = await this.fetchCreatePayment() |         let response = await this.fetchCreatePayment() | ||||||
|         this.customerList = response.data.customers |         this.customerList = response.data.customers | ||||||
|         this.formData.payment_number = response.data.nextPaymentNumber |         this.paymentNumAttribute = response.data.nextPaymentNumberAttribute | ||||||
|  |         this.paymentPrefix = response.data.payment_prefix | ||||||
|         this.formData.payment_date = moment(new Date()).toString() |         this.formData.payment_date = moment(new Date()).toString() | ||||||
|       } |       } | ||||||
|       return true |       return true | ||||||
| @ -332,6 +337,9 @@ export default { | |||||||
|       if (this.$v.$invalid) { |       if (this.$v.$invalid) { | ||||||
|         return true |         return true | ||||||
|       } |       } | ||||||
|  |  | ||||||
|  |       this.formData.payment_number = this.paymentPrefix + '-' + this.paymentNumAttribute | ||||||
|  |  | ||||||
|       if (this.isEdit) { |       if (this.isEdit) { | ||||||
|         let data = { |         let data = { | ||||||
|           editData: { |           editData: { | ||||||
| @ -340,35 +348,53 @@ export default { | |||||||
|           }, |           }, | ||||||
|           id: this.$route.params.id |           id: this.$route.params.id | ||||||
|         } |         } | ||||||
|         let response = await this.updatePayment(data) |         try { | ||||||
|         if (response.data.success) { |           let response = await this.updatePayment(data) | ||||||
|           window.toastr['success'](this.$t('payments.updated_message')) |           if (response.data.success) { | ||||||
|           this.$router.push('/admin/payments') |             window.toastr['success'](this.$t('payments.updated_message')) | ||||||
|           return true |             this.$router.push('/admin/payments') | ||||||
|  |             return true | ||||||
|  |           } | ||||||
|  |           if (response.data.error === 'invalid_amount') { | ||||||
|  |             window.toastr['error'](this.$t('invalid_amount_message')) | ||||||
|  |             return false | ||||||
|  |           } | ||||||
|  |           window.toastr['error'](response.data.error) | ||||||
|  |         } catch (err) { | ||||||
|  |           this.isLoading = false | ||||||
|  |           if (err.response.data.errors.payment_number) { | ||||||
|  |             window.toastr['error'](err.response.data.errors.payment_number) | ||||||
|  |             return true | ||||||
|  |           } | ||||||
|  |           window.toastr['error'](err.response.data.message) | ||||||
|         } |         } | ||||||
|         if (response.data.error === 'invalid_amount') { |  | ||||||
|           window.toastr['error'](this.$t('invalid_amount_message')) |  | ||||||
|           return false |  | ||||||
|         } |  | ||||||
|         window.toastr['error'](response.data.error) |  | ||||||
|       } else { |       } else { | ||||||
|         let data = { |         let data = { | ||||||
|           ...this.formData, |           ...this.formData, | ||||||
|           payment_date: moment(this.formData.payment_date).format('DD/MM/YYYY') |           payment_date: moment(this.formData.payment_date).format('DD/MM/YYYY') | ||||||
|         } |         } | ||||||
|         this.isLoading = true |         this.isLoading = true | ||||||
|         let response = await this.addPayment(data) |         try { | ||||||
|         if (response.data.success) { |           let response = await this.addPayment(data) | ||||||
|           window.toastr['success'](this.$t('payments.created_message')) |           if (response.data.success) { | ||||||
|           this.$router.push('/admin/payments') |             window.toastr['success'](this.$t('payments.created_message')) | ||||||
|           this.isLoading = true |             this.$router.push('/admin/payments') | ||||||
|           return true |             this.isLoading = true | ||||||
|  |             return true | ||||||
|  |           } | ||||||
|  |           if (response.data.error === 'invalid_amount') { | ||||||
|  |             window.toastr['error'](this.$t('invalid_amount_message')) | ||||||
|  |             return false | ||||||
|  |           } | ||||||
|  |           window.toastr['error'](response.data.error) | ||||||
|  |         } catch (err) { | ||||||
|  |           this.isLoading = false | ||||||
|  |           if (err.response.data.errors.payment_number) { | ||||||
|  |             window.toastr['error'](err.response.data.errors.payment_number) | ||||||
|  |             return true | ||||||
|  |           } | ||||||
|  |           window.toastr['error'](err.response.data.message) | ||||||
|         } |         } | ||||||
|         if (response.data.error === 'invalid_amount') { |  | ||||||
|           window.toastr['error'](this.$t('invalid_amount_message')) |  | ||||||
|           return false |  | ||||||
|         } |  | ||||||
|         window.toastr['error'](response.data.error) |  | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  | |||||||
							
								
								
									
										385
									
								
								resources/assets/js/views/settings/Customization.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										385
									
								
								resources/assets/js/views/settings/Customization.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,385 @@ | |||||||
|  | <template> | ||||||
|  |   <div class="setting-main-container customization"> | ||||||
|  |     <div class="card setting-card"> | ||||||
|  |       <ul class="tabs"> | ||||||
|  |         <li class="tab" @click="setActiveTab('INVOICES')"> | ||||||
|  |           <a :class="['tab-link', {'a-active': activeTab === 'INVOICES'}]" href="#">{{ $t('settings.customization.invoices.title') }}</a> | ||||||
|  |         </li> | ||||||
|  |         <li class="tab" @click="setActiveTab('ESTIMATES')"> | ||||||
|  |           <a :class="['tab-link', {'a-active': activeTab === 'ESTIMATES'}]" href="#">{{ $t('settings.customization.estimates.title') }}</a> | ||||||
|  |         </li> | ||||||
|  |         <li class="tab" @click="setActiveTab('PAYMENTS')"> | ||||||
|  |           <a :class="['tab-link', {'a-active': activeTab === 'PAYMENTS'}]" href="#">{{ $t('settings.customization.payments.title') }}</a> | ||||||
|  |         </li> | ||||||
|  |       </ul> | ||||||
|  |  | ||||||
|  |       <!-- Invoices Tab --> | ||||||
|  |       <transition name="fade-customize"> | ||||||
|  |         <div v-if="activeTab === 'INVOICES'" class="invoice-tab"> | ||||||
|  |           <form action="" class="form-section" @submit.prevent="updateInvoiceSetting"> | ||||||
|  |             <div class="row"> | ||||||
|  |               <div class="col-md-12 mb-4"> | ||||||
|  |                 <label class="input-label">{{ $t('settings.customization.invoices.invoice_prefix') }}</label> | ||||||
|  |                 <base-input | ||||||
|  |                   v-model="invoices.invoice_prefix" | ||||||
|  |                   :invalid="$v.invoices.invoice_prefix.$error" | ||||||
|  |                   class="prefix-input" | ||||||
|  |                   @input="$v.invoices.invoice_prefix.$touch()" | ||||||
|  |                   @keyup="changeToUppercase('INVOICES')" | ||||||
|  |                 /> | ||||||
|  |                 <span v-show="!$v.invoices.invoice_prefix.required" class="text-danger mt-1">{{ $t('validation.required') }}</span> | ||||||
|  |                 <span v-if="!$v.invoices.invoice_prefix.maxLength" class="text-danger">{{ $t('validation.prefix_maxlength') }}</span> | ||||||
|  |                 <span v-if="!$v.invoices.invoice_prefix.alpha" class="text-danger">{{ $t('validation.characters_only') }}</span> | ||||||
|  |               </div> | ||||||
|  |             </div> | ||||||
|  |             <div class="row mb-3"> | ||||||
|  |               <div class="col-md-12"> | ||||||
|  |                 <base-button | ||||||
|  |                   icon="save" | ||||||
|  |                   color="theme" | ||||||
|  |                   type="submit" | ||||||
|  |                 > | ||||||
|  |                   {{ $t('settings.customization.save') }} | ||||||
|  |                 </base-button> | ||||||
|  |               </div> | ||||||
|  |             </div> | ||||||
|  |             <hr> | ||||||
|  |           </form> | ||||||
|  |           <div class="col-md-12 mt-3"> | ||||||
|  |             <div class="page-header"> | ||||||
|  |               <h3 class="page-title"> | ||||||
|  |                 {{ $t('settings.customization.invoices.invoice_settings') }} | ||||||
|  |               </h3> | ||||||
|  |               <div class="flex-box"> | ||||||
|  |                 <div class="left"> | ||||||
|  |                   <base-switch | ||||||
|  |                     v-model="invoiceAutogenerate" | ||||||
|  |                     class="btn-switch" | ||||||
|  |                     @change="setInvoiceSetting" | ||||||
|  |                   /> | ||||||
|  |                 </div> | ||||||
|  |                 <div class="right ml-15"> | ||||||
|  |                   <p class="box-title">  {{ $t('settings.customization.invoices.autogenerate_invoice_number') }} </p> | ||||||
|  |                   <p class="box-desc">  {{ $t('settings.customization.invoices.invoice_setting_description') }} </p> | ||||||
|  |                 </div> | ||||||
|  |               </div> | ||||||
|  |             </div> | ||||||
|  |           </div> | ||||||
|  |         </div> | ||||||
|  |       </transition> | ||||||
|  |  | ||||||
|  |       <!-- Estimates Tab --> | ||||||
|  |       <transition name="fade-customize"> | ||||||
|  |         <div v-if="activeTab === 'ESTIMATES'" class="estimate-tab"> | ||||||
|  |           <form action="" class="form-section" @submit.prevent="updateEstimateSetting"> | ||||||
|  |             <div class="row"> | ||||||
|  |               <div class="col-md-12 mb-4"> | ||||||
|  |                 <label class="input-label">{{ $t('settings.customization.estimates.estimate_prefix') }}</label> | ||||||
|  |                 <base-input | ||||||
|  |                   v-model="estimates.estimate_prefix" | ||||||
|  |                   :invalid="$v.estimates.estimate_prefix.$error" | ||||||
|  |                   class="prefix-input" | ||||||
|  |                   @input="$v.estimates.estimate_prefix.$touch()" | ||||||
|  |                   @keyup="changeToUppercase('ESTIMATES')" | ||||||
|  |                 /> | ||||||
|  |                 <span v-show="!$v.estimates.estimate_prefix.required" class="text-danger mt-1">{{ $t('validation.required') }}</span> | ||||||
|  |                 <span v-if="!$v.estimates.estimate_prefix.maxLength" class="text-danger">{{ $t('validation.prefix_maxlength') }}</span> | ||||||
|  |                 <span v-if="!$v.estimates.estimate_prefix.alpha" class="text-danger">{{ $t('validation.characters_only') }}</span> | ||||||
|  |               </div> | ||||||
|  |             </div> | ||||||
|  |             <div class="row mb-3"> | ||||||
|  |               <div class="col-md-12"> | ||||||
|  |                 <base-button | ||||||
|  |                   icon="save" | ||||||
|  |                   color="theme" | ||||||
|  |                   type="submit" | ||||||
|  |                 > | ||||||
|  |                   {{ $t('settings.customization.save') }} | ||||||
|  |                 </base-button> | ||||||
|  |               </div> | ||||||
|  |             </div> | ||||||
|  |             <hr> | ||||||
|  |           </form> | ||||||
|  |           <div class="col-md-12 mt-3"> | ||||||
|  |             <div class="page-header"> | ||||||
|  |               <h3 class="page-title"> | ||||||
|  |                 {{ $t('settings.customization.estimates.estimate_settings') }} | ||||||
|  |               </h3> | ||||||
|  |               <div class="flex-box"> | ||||||
|  |                 <div class="left"> | ||||||
|  |                   <base-switch | ||||||
|  |                     v-model="estimateAutogenerate" | ||||||
|  |                     class="btn-switch" | ||||||
|  |                     @change="setEstimateSetting" | ||||||
|  |                   /> | ||||||
|  |                 </div> | ||||||
|  |                 <div class="right ml-15"> | ||||||
|  |                   <p class="box-title">  {{ $t('settings.customization.estimates.autogenerate_estimate_number') }} </p> | ||||||
|  |                   <p class="box-desc">  {{ $t('settings.customization.estimates.estimate_setting_description') }} </p> | ||||||
|  |                 </div> | ||||||
|  |               </div> | ||||||
|  |             </div> | ||||||
|  |           </div> | ||||||
|  |         </div> | ||||||
|  |       </transition> | ||||||
|  |  | ||||||
|  |       <!-- Payments Tab --> | ||||||
|  |       <transition name="fade-customize"> | ||||||
|  |         <div v-if="activeTab === 'PAYMENTS'" class="payment-tab"> | ||||||
|  |           <form action="" class="form-section" @submit.prevent="updatePaymentSetting"> | ||||||
|  |             <div class="row"> | ||||||
|  |               <div class="col-md-12 mb-4"> | ||||||
|  |                 <label class="input-label">{{ $t('settings.customization.payments.payment_prefix') }}</label> | ||||||
|  |                 <base-input | ||||||
|  |                   v-model="payments.payment_prefix" | ||||||
|  |                   :invalid="$v.payments.payment_prefix.$error" | ||||||
|  |                   class="prefix-input" | ||||||
|  |                   @input="$v.payments.payment_prefix.$touch()" | ||||||
|  |                   @keyup="changeToUppercase('PAYMENTS')" | ||||||
|  |                 /> | ||||||
|  |                 <span v-show="!$v.payments.payment_prefix.required" class="text-danger mt-1">{{ $t('validation.required') }}</span> | ||||||
|  |                 <span v-if="!$v.payments.payment_prefix.maxLength" class="text-danger">{{ $t('validation.prefix_maxlength') }}</span> | ||||||
|  |                 <span v-if="!$v.payments.payment_prefix.alpha" class="text-danger">{{ $t('validation.characters_only') }}</span> | ||||||
|  |               </div> | ||||||
|  |             </div> | ||||||
|  |             <div class="row mb-3"> | ||||||
|  |               <div class="col-md-12"> | ||||||
|  |                 <base-button | ||||||
|  |                   icon="save" | ||||||
|  |                   color="theme" | ||||||
|  |                   type="submit" | ||||||
|  |                 > | ||||||
|  |                   {{ $t('settings.customization.save') }} | ||||||
|  |                 </base-button> | ||||||
|  |               </div> | ||||||
|  |             </div> | ||||||
|  |           </form> | ||||||
|  |           <hr> | ||||||
|  |           <div class="col-md-12 mt-4"> | ||||||
|  |             <div class="page-header"> | ||||||
|  |               <h3 class="page-title"> | ||||||
|  |                 {{ $t('settings.customization.payments.payment_settings') }} | ||||||
|  |               </h3> | ||||||
|  |               <div class="flex-box"> | ||||||
|  |                 <div class="left"> | ||||||
|  |                   <base-switch | ||||||
|  |                     v-model="paymentAutogenerate" | ||||||
|  |                     class="btn-switch" | ||||||
|  |                     @change="setPaymentSetting" | ||||||
|  |                   /> | ||||||
|  |                 </div> | ||||||
|  |                 <div class="right ml-15"> | ||||||
|  |                   <p class="box-title">  {{ $t('settings.customization.payments.autogenerate_payment_number') }} </p> | ||||||
|  |                   <p class="box-desc">  {{ $t('settings.customization.payments.payment_setting_description') }} </p> | ||||||
|  |                 </div> | ||||||
|  |               </div> | ||||||
|  |             </div> | ||||||
|  |           </div> | ||||||
|  |         </div> | ||||||
|  |       </transition> | ||||||
|  |     </div> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  | <script> | ||||||
|  | import { validationMixin } from 'vuelidate' | ||||||
|  | const { required, maxLength, alpha } = require('vuelidate/lib/validators') | ||||||
|  | export default { | ||||||
|  |   mixins: [validationMixin], | ||||||
|  |   data () { | ||||||
|  |     return { | ||||||
|  |       activeTab: 'INVOICES', | ||||||
|  |       invoiceAutogenerate: false, | ||||||
|  |       estimateAutogenerate: false, | ||||||
|  |       paymentAutogenerate: false, | ||||||
|  |       invoices: { | ||||||
|  |         invoice_prefix: null, | ||||||
|  |         invoice_notes: null, | ||||||
|  |         invoice_terms_and_conditions: null | ||||||
|  |       }, | ||||||
|  |       estimates: { | ||||||
|  |         estimate_prefix: null, | ||||||
|  |         estimate_notes: null, | ||||||
|  |         estimate_terms_and_conditions: null | ||||||
|  |       }, | ||||||
|  |       payments: { | ||||||
|  |         payment_prefix: null | ||||||
|  |       }, | ||||||
|  |       currentData: null | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   watch: { | ||||||
|  |     activeTab () { | ||||||
|  |       this.loadData() | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   validations: { | ||||||
|  |     invoices: { | ||||||
|  |       invoice_prefix: { | ||||||
|  |         required, | ||||||
|  |         maxLength: maxLength(5), | ||||||
|  |         alpha | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     estimates: { | ||||||
|  |       estimate_prefix: { | ||||||
|  |         required, | ||||||
|  |         maxLength: maxLength(5), | ||||||
|  |         alpha | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     payments: { | ||||||
|  |       payment_prefix: { | ||||||
|  |         required, | ||||||
|  |         maxLength: maxLength(5), | ||||||
|  |         alpha | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   created () { | ||||||
|  |     this.loadData() | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     async setInvoiceSetting () { | ||||||
|  |       let data = { | ||||||
|  |         key: 'invoice_auto_generate', | ||||||
|  |         value: this.invoiceAutogenerate ? 'YES' : 'NO' | ||||||
|  |       } | ||||||
|  |       let response = await window.axios.put('/api/settings/update-setting', data) | ||||||
|  |       if (response.data) { | ||||||
|  |         window.toastr['success'](this.$t('general.setting_updated')) | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     async setEstimateSetting () { | ||||||
|  |       let data = { | ||||||
|  |         key: 'estimate_auto_generate', | ||||||
|  |         value: this.estimateAutogenerate ? 'YES' : 'NO' | ||||||
|  |       } | ||||||
|  |       let response = await window.axios.put('/api/settings/update-setting', data) | ||||||
|  |       if (response.data) { | ||||||
|  |         window.toastr['success'](this.$t('general.setting_updated')) | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     changeToUppercase (currentTab) { | ||||||
|  |       if (currentTab === 'INVOICES') { | ||||||
|  |         this.invoices.invoice_prefix = this.invoices.invoice_prefix.toUpperCase() | ||||||
|  |         return true | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       if (currentTab === 'ESTIMATES') { | ||||||
|  |         this.estimates.estimate_prefix = this.estimates.estimate_prefix.toUpperCase() | ||||||
|  |         return true | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       if (currentTab === 'PAYMENTS') { | ||||||
|  |         this.payments.payment_prefix = this.payments.payment_prefix.toUpperCase() | ||||||
|  |         return true | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     async setPaymentSetting () { | ||||||
|  |       let data = { | ||||||
|  |         key: 'payment_auto_generate', | ||||||
|  |         value: this.paymentAutogenerate ? 'YES' : 'NO' | ||||||
|  |       } | ||||||
|  |       let response = await window.axios.put('/api/settings/update-setting', data) | ||||||
|  |       if (response.data) { | ||||||
|  |         window.toastr['success'](this.$t('general.setting_updated')) | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     async loadData () { | ||||||
|  |       let res = await window.axios.get('/api/settings/get-customize-setting') | ||||||
|  |  | ||||||
|  |       if (res.data) { | ||||||
|  |         this.invoices.invoice_prefix = res.data.invoice_prefix | ||||||
|  |         this.invoices.invoice_notes = res.data.invoice_notes | ||||||
|  |         this.invoices.invoice_terms_and_conditions = res.data.invoice_terms_and_conditions | ||||||
|  |         this.estimates.estimate_prefix = res.data.estimate_prefix | ||||||
|  |         this.estimates.estimate_notes = res.data.estimate_notes | ||||||
|  |         this.estimates.estimate_terms_and_conditions = res.data.estimate_terms_and_conditions | ||||||
|  |         this.payments.payment_prefix = res.data.payment_prefix | ||||||
|  |  | ||||||
|  |         if (res.data.invoice_auto_generate === 'YES') { | ||||||
|  |           this.invoiceAutogenerate = true | ||||||
|  |         } else { | ||||||
|  |           this.invoiceAutogenerate = false | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (res.data.estimate_auto_generate === 'YES') { | ||||||
|  |           this.estimateAutogenerate = true | ||||||
|  |         } else { | ||||||
|  |           this.estimateAutogenerate = false | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (res.data.payment_auto_generate === 'YES') { | ||||||
|  |           this.paymentAutogenerate = true | ||||||
|  |         } else { | ||||||
|  |           this.paymentAutogenerate = false | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     async updateInvoiceSetting () { | ||||||
|  |       this.$v.invoices.$touch() | ||||||
|  |  | ||||||
|  |       if (this.$v.invoices.$invalid) { | ||||||
|  |         return false | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       let data = {type: 'INVOICES', ...this.invoices} | ||||||
|  |  | ||||||
|  |       if (this.updateSetting(data)) { | ||||||
|  |         window.toastr['success'](this.$t('settings.customization.invoices.invoice_setting_updated')) | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     async updateEstimateSetting () { | ||||||
|  |       this.$v.estimates.$touch() | ||||||
|  |  | ||||||
|  |       if (this.$v.estimates.$invalid) { | ||||||
|  |         return false | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       let data = {type: 'ESTIMATES', ...this.estimates} | ||||||
|  |  | ||||||
|  |       if (this.updateSetting(data)) { | ||||||
|  |         window.toastr['success'](this.$t('settings.customization.estimates.estimate_setting_updated')) | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     async updatePaymentSetting () { | ||||||
|  |       this.$v.payments.$touch() | ||||||
|  |  | ||||||
|  |       if (this.$v.payments.$invalid) { | ||||||
|  |         return false | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       let data = {type: 'PAYMENTS', ...this.payments} | ||||||
|  |  | ||||||
|  |       if (this.updateSetting(data)) { | ||||||
|  |         window.toastr['success'](this.$t('settings.customization.payments.payment_setting_updated')) | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     async updateSetting (data) { | ||||||
|  |       let res = await window.axios.put('/api/settings/update-customize-setting', data) | ||||||
|  |  | ||||||
|  |       if (res.data.success) { | ||||||
|  |         return true | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       return false | ||||||
|  |     }, | ||||||
|  |     setActiveTab (val) { | ||||||
|  |       this.activeTab = val | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  | <style> | ||||||
|  |   .fade-customize-enter-active { | ||||||
|  |     transition: opacity 0.9s; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .fade-customize-leave-active  { | ||||||
|  |     transition: opacity 0s; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .fade-customize-enter, .fade-customize-leave-to /* .fade-leave-active below version 2.1.8 */ { | ||||||
|  |     opacity: 0; | ||||||
|  |   } | ||||||
|  | </style> | ||||||
| @ -14,6 +14,7 @@ | |||||||
|             <base-select |             <base-select | ||||||
|               v-model="formData.currency" |               v-model="formData.currency" | ||||||
|               :options="currencies" |               :options="currencies" | ||||||
|  |               :custom-label="currencyNameWithCode" | ||||||
|               :class="{'error': $v.formData.currency.$error }" |               :class="{'error': $v.formData.currency.$error }" | ||||||
|               :searchable="true" |               :searchable="true" | ||||||
|               :show-labels="false" |               :show-labels="false" | ||||||
| @ -179,6 +180,9 @@ export default { | |||||||
|     this.getDiscountSettings() |     this.getDiscountSettings() | ||||||
|   }, |   }, | ||||||
|   methods: { |   methods: { | ||||||
|  |     currencyNameWithCode ({name, code}) { | ||||||
|  |       return `${code} - ${name}` | ||||||
|  |     }, | ||||||
|     ...mapActions('currency', [ |     ...mapActions('currency', [ | ||||||
|       'setDefaultCurrency' |       'setDefaultCurrency' | ||||||
|     ]), |     ]), | ||||||
|  | |||||||
| @ -45,6 +45,12 @@ export default { | |||||||
|           icon: 'building', |           icon: 'building', | ||||||
|           iconType: 'far' |           iconType: 'far' | ||||||
|         }, |         }, | ||||||
|  |         { | ||||||
|  |           link: '/admin/settings/customization', | ||||||
|  |           title: 'settings.menu_title.customization', | ||||||
|  |           icon: 'edit', | ||||||
|  |           iconType: 'fa' | ||||||
|  |         }, | ||||||
|         { |         { | ||||||
|           link: '/admin/settings/preferences', |           link: '/admin/settings/preferences', | ||||||
|           title: 'settings.menu_title.preferences', |           title: 'settings.menu_title.preferences', | ||||||
|  | |||||||
| @ -203,8 +203,10 @@ export default { | |||||||
|           this.$emit('next') |           this.$emit('next') | ||||||
|           window.toastr['success'](this.$t('wizard.success.' + response.data.success)) |           window.toastr['success'](this.$t('wizard.success.' + response.data.success)) | ||||||
|           return true |           return true | ||||||
|         } else { |         } else if (response.data.error) { | ||||||
|           window.toastr['error'](this.$t('wizard.errors.' + response.data.error)) |           window.toastr['error'](this.$t('wizard.errors.' + response.data.error)) | ||||||
|  |         } else if (response.data.error_message) { | ||||||
|  |           window.toastr['error'](response.data.error_message) | ||||||
|         } |         } | ||||||
|       } catch (e) { |       } catch (e) { | ||||||
|         window.toastr['error'](e.response.data.message) |         window.toastr['error'](e.response.data.message) | ||||||
|  | |||||||
| @ -11,6 +11,7 @@ | |||||||
|             v-model="settingData.currency" |             v-model="settingData.currency" | ||||||
|             :class="{'error': $v.settingData.currency.$error }" |             :class="{'error': $v.settingData.currency.$error }" | ||||||
|             :options="currencies" |             :options="currencies" | ||||||
|  |             :custom-label="currencyNameWithCode" | ||||||
|             :searchable="true" |             :searchable="true" | ||||||
|             :show-labels="false" |             :show-labels="false" | ||||||
|             :placeholder="$t('settings.currencies.select_currency')" |             :placeholder="$t('settings.currencies.select_currency')" | ||||||
| @ -150,6 +151,9 @@ export default { | |||||||
|     this.getOnboardingData() |     this.getOnboardingData() | ||||||
|   }, |   }, | ||||||
|   methods: { |   methods: { | ||||||
|  |     currencyNameWithCode ({name, code}) { | ||||||
|  |       return `${code} - ${name}` | ||||||
|  |     }, | ||||||
|     ...mapActions('auth', [ |     ...mapActions('auth', [ | ||||||
|       'loginOnBoardingUser' |       'loginOnBoardingUser' | ||||||
|     ]), |     ]), | ||||||
|  | |||||||
| @ -18,7 +18,7 @@ | |||||||
|           </div> |           </div> | ||||||
|         </div> |         </div> | ||||||
|         <avatar-cropper |         <avatar-cropper | ||||||
|           :labels="{ submit: 'submit', cancel: 'Cancle'}" |           :labels="{ submit: 'submit', cancel: 'Cancel'}" | ||||||
|           :cropper-options="cropperOptions" |           :cropper-options="cropperOptions" | ||||||
|           :output-options="cropperOutputOptions" |           :output-options="cropperOutputOptions" | ||||||
|           :output-quality="0.8" |           :output-quality="0.8" | ||||||
| @ -54,7 +54,7 @@ | |||||||
|           /> |           /> | ||||||
|           <div v-if="$v.profileData.email.$error"> |           <div v-if="$v.profileData.email.$error"> | ||||||
|             <span v-if="!$v.profileData.email.required" class="text-danger">{{ $tc('validation.required') }}</span> |             <span v-if="!$v.profileData.email.required" class="text-danger">{{ $tc('validation.required') }}</span> | ||||||
|             <span v-if="!$v.profileData.email.email" class="text-danger">{{ $tc('validation.required') }}</span> |             <span v-if="!$v.profileData.email.email" class="text-danger">{{ $tc('validation.email_incorrect') }}</span> | ||||||
|           </div> |           </div> | ||||||
|         </div> |         </div> | ||||||
|       </div> |       </div> | ||||||
| @ -145,7 +145,7 @@ export default { | |||||||
|       }, |       }, | ||||||
|       password: { |       password: { | ||||||
|         required, |         required, | ||||||
|         minLength: minLength(5) |         minLength: minLength(8) | ||||||
|       }, |       }, | ||||||
|       confirm_password: { |       confirm_password: { | ||||||
|         required: requiredIf('isRequired'), |         required: requiredIf('isRequired'), | ||||||
|  | |||||||
							
								
								
									
										54
									
								
								resources/assets/sass/components/base/base-prefix-input.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								resources/assets/sass/components/base/base-prefix-input.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,54 @@ | |||||||
|  | .base-prefix-input { | ||||||
|  |     display: flex; | ||||||
|  |     position: relative; | ||||||
|  |     width: 100%; | ||||||
|  |     height: 40px; | ||||||
|  |     padding: 2px 2px; | ||||||
|  |     flex-direction: row; | ||||||
|  |     background: #FFFFFF; | ||||||
|  |     border: 1px solid $ls-color-gray--light; | ||||||
|  |     border-radius: 5px; | ||||||
|  |  | ||||||
|  |     .icon { | ||||||
|  |         width: 13px; | ||||||
|  |         height: 18px; | ||||||
|  |         color: $ls-color-gray; | ||||||
|  |         font-style: normal; | ||||||
|  |         font-weight: 900; | ||||||
|  |         font-size: 14px; | ||||||
|  |         line-height: 16px; | ||||||
|  |         margin-top: 17px; | ||||||
|  |         margin-left: 20px; | ||||||
|  |         z-index: 1; | ||||||
|  |         transform: translate(-50%,-50%); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     p { | ||||||
|  |         padding: 0 0 0 0; | ||||||
|  |         margin: 0 0 0 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .prefix-label { | ||||||
|  |         display: flex; | ||||||
|  |         height: 18px; | ||||||
|  |         color: #55547A; | ||||||
|  |         font-weight: 500; | ||||||
|  |         font-size: 14px; | ||||||
|  |         line-height: 16px; | ||||||
|  |         padding: 9px 2px 9px 10px; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .prefix-input-field { | ||||||
|  |         width: 100%; | ||||||
|  |         padding: 8px 13px; | ||||||
|  |         padding-left: 1px; | ||||||
|  |         text-align: left; | ||||||
|  |         background: #FFFFFF; | ||||||
|  |         border: none; | ||||||
|  |         font-style: normal; | ||||||
|  |         font-weight: 400; | ||||||
|  |         font-size: 14px; | ||||||
|  |         line-height: 21px; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										2
									
								
								resources/assets/sass/crater.scss
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								resources/assets/sass/crater.scss
									
									
									
									
										vendored
									
									
								
							| @ -48,6 +48,7 @@ | |||||||
| @import 'components/base/base-text-area'; | @import 'components/base/base-text-area'; | ||||||
| @import "components/base/base-switch"; | @import "components/base/base-switch"; | ||||||
| @import 'components/base/base-loader/index'; | @import 'components/base/base-loader/index'; | ||||||
|  | @import 'components/base/base-prefix-input'; | ||||||
|  |  | ||||||
|  |  | ||||||
| // Components | // Components | ||||||
| @ -91,6 +92,7 @@ | |||||||
| @import 'pages/login'; | @import 'pages/login'; | ||||||
| @import 'pages/login-3'; | @import 'pages/login-3'; | ||||||
| @import 'pages/404'; | @import 'pages/404'; | ||||||
|  | @import 'pages/customization'; | ||||||
| @import 'pages/settings'; | @import 'pages/settings'; | ||||||
| @import 'pages/invoices/create'; | @import 'pages/invoices/create'; | ||||||
| @import 'pages/invoices/view'; | @import 'pages/invoices/view'; | ||||||
|  | |||||||
							
								
								
									
										39
									
								
								resources/assets/sass/pages/customization.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								resources/assets/sass/pages/customization.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,39 @@ | |||||||
|  | .customization { | ||||||
|  |  | ||||||
|  |     .prefix-input { | ||||||
|  |         max-width: 30%; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .form-section { | ||||||
|  |         padding: 8px 15px; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .invoice-customization-card { | ||||||
|  |         border: 1px solid #EBF1FA;border-radius: 5px; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @media (max-width: $x-small-breakpoint) { | ||||||
|  |         .address-customization-card { | ||||||
|  |  | ||||||
|  |             .address-fields-container { | ||||||
|  |                 display: flex; | ||||||
|  |                 flex-wrap: wrap; | ||||||
|  |  | ||||||
|  |                 .fields-list { | ||||||
|  |                     border-right: 0px; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .tabs { | ||||||
|  |  | ||||||
|  |             .tab { | ||||||
|  |                 padding: 10px 10px; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
| @ -3,9 +3,11 @@ | |||||||
| <head> | <head> | ||||||
|     <title>Estimate</title> |     <title>Estimate</title> | ||||||
|     {{-- <link href="https://fonts.googleapis.com/css?family=Poppins&display=swap" rel="stylesheet"> --}} |     {{-- <link href="https://fonts.googleapis.com/css?family=Poppins&display=swap" rel="stylesheet"> --}} | ||||||
|  |     <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> | ||||||
|  |  | ||||||
|     <style type="text/css"> |     <style type="text/css"> | ||||||
|         body { |         body { | ||||||
|             font-family: 'Roboto', sans-serif; |             font-family: "DejaVu Sans"; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         html { |         html { | ||||||
| @ -58,13 +60,11 @@ | |||||||
|             margin-left:160px; |             margin-left:160px; | ||||||
|         } |         } | ||||||
|         .header { |         .header { | ||||||
|             font-family: 'Roboto', sans-serif; |  | ||||||
|             font-size: 20px; |             font-size: 20px; | ||||||
|             color: rgba(0, 0, 0, 0.7); |             color: rgba(0, 0, 0, 0.7); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         .TextColor1 { |         .TextColor1 { | ||||||
|             font-family: 'Roboto', sans-serif; |  | ||||||
|             font-size: 16px; |             font-size: 16px; | ||||||
|             color: rgba(0, 0, 0, 0.5); |             color: rgba(0, 0, 0, 0.5); | ||||||
|         } |         } | ||||||
| @ -339,7 +339,6 @@ | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         .notes { |         .notes { | ||||||
|             font-family: 'Roboto', sans-serif; |  | ||||||
|             font-style: normal; |             font-style: normal; | ||||||
|             font-weight: 300; |             font-weight: 300; | ||||||
|             font-size: 12px; |             font-size: 12px; | ||||||
| @ -352,7 +351,6 @@ | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         .notes-label { |         .notes-label { | ||||||
|             font-family: 'Roboto', sans-serif; |  | ||||||
|             font-style: normal; |             font-style: normal; | ||||||
|             font-weight: normal; |             font-weight: normal; | ||||||
|             font-size: 15px; |             font-size: 15px; | ||||||
| @ -410,7 +408,7 @@ | |||||||
|             <div class="bill-address-container"> |             <div class="bill-address-container"> | ||||||
|                 @include('app.pdf.estimate.partials.billing-address') |                 @include('app.pdf.estimate.partials.billing-address') | ||||||
|             </div> |             </div> | ||||||
|             @if($estimate->user->billingaddress->name || $estimate->user->billingaddress->address_street_1 || $estimate->user->billingaddress->address_street_2 || $estimate->user->billingaddress->country || $estimate->user->billingaddress->state || $estimate->user->billingaddress->city || $estimate->user->billingaddress->zip || $estimate->user->billingaddress->phone) |             @if($estimate->user->billingaddress) | ||||||
|                 <div class="ship-address-container"> |                 <div class="ship-address-container"> | ||||||
|             @else |             @else | ||||||
|                 <div class="ship-address-container " style="float:left;padding-left:0px;"> |                 <div class="ship-address-container " style="float:left;padding-left:0px;"> | ||||||
|  | |||||||
| @ -3,9 +3,11 @@ | |||||||
| <head> | <head> | ||||||
|     <title>Estimate</title> |     <title>Estimate</title> | ||||||
|     {{-- <link href="https://fonts.googleapis.com/css?family=Poppins&display=swap" rel="stylesheet"> --}} |     {{-- <link href="https://fonts.googleapis.com/css?family=Poppins&display=swap" rel="stylesheet"> --}} | ||||||
|  |     <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> | ||||||
|  |  | ||||||
|     <style type="text/css"> |     <style type="text/css"> | ||||||
|         body { |         body { | ||||||
|             font-family: 'Roboto', sans-serif; |             font-family: "DejaVu Sans"; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         html { |         html { | ||||||
| @ -62,13 +64,11 @@ | |||||||
|             margin-left:160px; |             margin-left:160px; | ||||||
|         } |         } | ||||||
|         .header { |         .header { | ||||||
|             font-family: 'Roboto', sans-serif; |  | ||||||
|             font-size: 20px; |             font-size: 20px; | ||||||
|             color: rgba(0, 0, 0, 0.7); |             color: rgba(0, 0, 0, 0.7); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         .TextColor1 { |         .TextColor1 { | ||||||
|             font-family: 'Roboto', sans-serif; |  | ||||||
|             font-size: 16px; |             font-size: 16px; | ||||||
|             color: rgba(0, 0, 0, 0.5); |             color: rgba(0, 0, 0, 0.5); | ||||||
|         } |         } | ||||||
| @ -364,7 +364,6 @@ | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         .notes { |         .notes { | ||||||
|             font-family: 'Roboto', sans-serif; |  | ||||||
|             font-style: normal; |             font-style: normal; | ||||||
|             font-weight: 300; |             font-weight: 300; | ||||||
|             font-size: 12px; |             font-size: 12px; | ||||||
| @ -377,7 +376,6 @@ | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         .notes-label { |         .notes-label { | ||||||
|             font-family: 'Roboto', sans-serif; |  | ||||||
|             font-style: normal; |             font-style: normal; | ||||||
|             font-weight: normal; |             font-weight: normal; | ||||||
|             font-size: 15px; |             font-size: 15px; | ||||||
| @ -421,7 +419,7 @@ | |||||||
|             <div class="ship-address-container"> |             <div class="ship-address-container"> | ||||||
|                 @include('app.pdf.estimate.partials.shipping-address') |                 @include('app.pdf.estimate.partials.shipping-address') | ||||||
|             </div> |             </div> | ||||||
|             @if($estimate->user->shippingaddress->name || $estimate->user->shippingaddress->address_street_1 || $estimate->user->shippingaddress->address_street_2 || $estimate->user->shippingaddress->country || $estimate->user->shippingaddress->state || $estimate->user->shippingaddress->city || $estimate->user->shippingaddress->zip || $estimate->user->phone) |             @if($estimate->user->shippingaddress) | ||||||
|                 <div class="bill-address-container"> |                 <div class="bill-address-container"> | ||||||
|             @else |             @else | ||||||
|                 <div class="bill-address-container" style="float:right;padding-right:0px;"> |                 <div class="bill-address-container" style="float:right;padding-right:0px;"> | ||||||
|  | |||||||
| @ -3,9 +3,11 @@ | |||||||
| <head> | <head> | ||||||
|     <title>Estimate</title> |     <title>Estimate</title> | ||||||
|     {{-- <link href="https://fonts.googleapis.com/css?family=Poppins&display=swap" rel="stylesheet"> --}} |     {{-- <link href="https://fonts.googleapis.com/css?family=Poppins&display=swap" rel="stylesheet"> --}} | ||||||
|  |     <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> | ||||||
|  |  | ||||||
|     <style type="text/css"> |     <style type="text/css"> | ||||||
|         body { |         body { | ||||||
|             font-family: 'Roboto', sans-serif; |             font-family: "DejaVu Sans"; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         html { |         html { | ||||||
| @ -64,13 +66,11 @@ | |||||||
|             margin-left:160px; |             margin-left:160px; | ||||||
|         } |         } | ||||||
|         .header { |         .header { | ||||||
|             font-family: 'Roboto', sans-serif; |  | ||||||
|             font-size: 20px; |             font-size: 20px; | ||||||
|             color: rgba(0, 0, 0, 0.7); |             color: rgba(0, 0, 0, 0.7); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         .TextColor1 { |         .TextColor1 { | ||||||
|             font-family: 'Roboto', sans-serif; |  | ||||||
|             font-size: 16px; |             font-size: 16px; | ||||||
|             color: rgba(0, 0, 0, 0.5); |             color: rgba(0, 0, 0, 0.5); | ||||||
|         } |         } | ||||||
| @ -372,7 +372,6 @@ | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         .notes { |         .notes { | ||||||
|             font-family: 'Roboto', sans-serif; |  | ||||||
|             font-style: normal; |             font-style: normal; | ||||||
|             font-weight: 300; |             font-weight: 300; | ||||||
|             font-size: 12px; |             font-size: 12px; | ||||||
| @ -385,7 +384,6 @@ | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         .notes-label { |         .notes-label { | ||||||
|             font-family: 'Roboto', sans-serif; |  | ||||||
|             font-style: normal; |             font-style: normal; | ||||||
|             font-weight: normal; |             font-weight: normal; | ||||||
|             font-size: 15px; |             font-size: 15px; | ||||||
| @ -426,7 +424,7 @@ | |||||||
|                 <div style="float:left;"> |                 <div style="float:left;"> | ||||||
|                     @include('app.pdf.estimate.partials.billing-address') |                     @include('app.pdf.estimate.partials.billing-address') | ||||||
|                 </div> |                 </div> | ||||||
|                 @if($estimate->user->billingaddress->name || $estimate->user->billingaddress->address_street_1 || $estimate->user->billingaddress->address_street_2 || $estimate->user->billingaddress->country || $estimate->user->billingaddress->state || $estimate->user->billingaddress->city || $estimate->user->billingaddress->zip || $estimate->user->billingaddress->phone) |                @if($estimate->user->billingaddress) | ||||||
|                     <div style="float:right;"> |                     <div style="float:right;"> | ||||||
|                 @else |                 @else | ||||||
|                     <div style="float:left;"> |                     <div style="float:left;"> | ||||||
|  | |||||||
| @ -1,7 +1,5 @@ | |||||||
| @if($estimate->user->billingaddress) | @if($estimate->user->billingaddress) | ||||||
|     @if($estimate->user->billingaddress->name || $estimate->user->billingaddress->address_street_1 || $estimate->user->billingaddress->address_street_2 || $estimate->user->billingaddress->country || $estimate->user->billingaddress->state || $estimate->user->billingaddress->city || $estimate->user->billingaddress->zip || $estimate->user->billingaddress->phone) |     <p class="bill-to">Bill To,</p> | ||||||
|         <p class="bill-to">Bill To,</p> |  | ||||||
|     @endif |  | ||||||
|     @if($estimate->user->billingaddress->name) |     @if($estimate->user->billingaddress->name) | ||||||
|         <p class="bill-user-name"> |         <p class="bill-user-name"> | ||||||
|             {{$estimate->user->billingaddress->name}} |             {{$estimate->user->billingaddress->name}} | ||||||
| @ -16,11 +14,11 @@ | |||||||
|             {{$estimate->user->billingaddress->address_street_2}}<br> |             {{$estimate->user->billingaddress->address_street_2}}<br> | ||||||
|         @endif |         @endif | ||||||
|  |  | ||||||
|         @if($estimate->user->billingaddress->city && $estimate->user->billingaddress->city) |         @if($estimate->user->billingaddress->city) | ||||||
|             {{$estimate->user->billingaddress->city}}, |             {{$estimate->user->billingaddress->city}}, | ||||||
|         @endif |         @endif | ||||||
|  |  | ||||||
|         @if($estimate->user->billingaddress->state && $estimate->user->billingaddress->state) |         @if($estimate->user->billingaddress->state) | ||||||
|             {{$estimate->user->billingaddress->state}}. |             {{$estimate->user->billingaddress->state}}. | ||||||
|         @endif |         @endif | ||||||
|  |  | ||||||
|  | |||||||
| @ -1,7 +1,5 @@ | |||||||
| @if($estimate->user->shippingaddress) | @if($estimate->user->shippingaddress) | ||||||
|     @if($estimate->user->shippingaddress->name || $estimate->user->shippingaddress->address_street_1 || $estimate->user->shippingaddress->address_street_2 || $estimate->user->shippingaddress->country || $estimate->user->shippingaddress->state || $estimate->user->shippingaddress->city || $estimate->user->shippingaddress->zip || $estimate->user->phone) |     <p class="ship-to">Ship To,</p> | ||||||
|         <p class="ship-to">Ship To,</p> |  | ||||||
|     @endif |  | ||||||
|     @if($estimate->user->shippingaddress->name) |     @if($estimate->user->shippingaddress->name) | ||||||
|         <p class="ship-user-name"> |         <p class="ship-user-name"> | ||||||
|             {{$estimate->user->shippingaddress->name}} |             {{$estimate->user->shippingaddress->name}} | ||||||
|  | |||||||
| @ -18,24 +18,48 @@ | |||||||
|     @endphp |     @endphp | ||||||
|     @foreach ($estimate->items as $item) |     @foreach ($estimate->items as $item) | ||||||
|         <tr class="item-details"> |         <tr class="item-details"> | ||||||
|             <td class="inv-item items" style="text-align: right; color: #040405; padding-right: 20px; vertical-align: top;">{{$index}}</td> |             <td | ||||||
|             <td class="inv-item items" style="text-align: left; color: #040405;padding-left: 0px"> |                 class="inv-item items" | ||||||
|                 <span>{{ $item->name }}</span><br> |                 style="text-align: right; color: #040405; padding-right: 20px; vertical-align: top;" | ||||||
|                 <span style="text-align: left; color: #595959; font-size: 9px; font-weight:300; line-height: 12px;">{{ $item->description }}</span> |             > | ||||||
|  |                 {{$index}} | ||||||
|  |             </td> | ||||||
|  |             <td | ||||||
|  |                 class="inv-item items" | ||||||
|  |                 style="text-align: left; color: #040405;padding-left: 0px" | ||||||
|  |             > | ||||||
|  |                 <span>{{ $item->name }}</span><br> | ||||||
|  |                 <span | ||||||
|  |                     style="text-align: left; color: #595959; font-size: 9px; font-weight:300; line-height: 12px;" | ||||||
|  |                 > | ||||||
|  |                     {{ $item->description }} | ||||||
|  |                 </span> | ||||||
|  |             </td> | ||||||
|  |             <td | ||||||
|  |                 class="inv-item items" | ||||||
|  |                 style="text-align: right; color: #040405; padding-right: 20px" | ||||||
|  |             > | ||||||
|  |                 {{$item->quantity}} | ||||||
|  |             </td> | ||||||
|  |             <td | ||||||
|  |                 class="inv-item items" | ||||||
|  |                 style="text-align: right; color: #040405; padding-right: 40px" | ||||||
|  |             > | ||||||
|  |                 {!! format_money_pdf($item->price, $estimate->user->currency) !!} | ||||||
|             </td> |             </td> | ||||||
|             <td class="inv-item items" style="text-align: right; color: #040405; padding-right: 20px">{{$item->quantity}}</td> |  | ||||||
|             <td class="inv-item items" style="text-align: right; color: #040405; padding-right: 40px">{{$item->price/100}}</td> |  | ||||||
|             @if($estimate->discount_per_item === 'YES') |             @if($estimate->discount_per_item === 'YES') | ||||||
|                 <td class="inv-item items" style="text-align: right; color: #040405; padding-left: 10px"> |                 <td class="inv-item items" style="text-align: right; color: #040405; padding-left: 10px"> | ||||||
|                     @if($item->discount_type === 'fixed') |                     @if($item->discount_type === 'fixed') | ||||||
|                         {{$item->discount_val/100}} |                         {!! format_money_pdf($item->discount_val, $estimate->user->currency) !!} | ||||||
|                     @endif |                     @endif | ||||||
|                     @if($item->discount_type === 'percentage') |                     @if($item->discount_type === 'percentage') | ||||||
|                         {{$item->discount}}% |                         {{$item->discount}}% | ||||||
|                     @endif |                     @endif | ||||||
|                 </td> |                 </td> | ||||||
|             @endif |             @endif | ||||||
|             <td class="inv-item items" style="text-align: right; color: #040405;">{{$item->total/100}}</td> |             <td class="inv-item items" style="text-align: right; color: #040405;"> | ||||||
|  |                 {!! format_money_pdf($item->total, $estimate->user->currency) !!} | ||||||
|  |             </td> | ||||||
|         </tr> |         </tr> | ||||||
|         @php |         @php | ||||||
|             $index += 1 |             $index += 1 | ||||||
| @ -47,7 +71,7 @@ | |||||||
|     <tr> |     <tr> | ||||||
|         <td class="no-borde" style="color: #55547A; padding-left:10px;  font-size:12px;">Subtotal</td> |         <td class="no-borde" style="color: #55547A; padding-left:10px;  font-size:12px;">Subtotal</td> | ||||||
|         <td class="no-border items" |         <td class="no-border items" | ||||||
|             style="padding-right:10px; text-align: right;  font-size:12px; color: #040405; font-weight: 500;">{!! format_money_pdf($estimate->sub_total) !!}</td> |             style="padding-right:10px; text-align: right;  font-size:12px; color: #040405; font-weight: 500;">{!! format_money_pdf($estimate->sub_total, $estimate->user->currency) !!}</td> | ||||||
|     </tr> |     </tr> | ||||||
|  |  | ||||||
|     @if ($estimate->tax_per_item === 'YES') |     @if ($estimate->tax_per_item === 'YES') | ||||||
| @ -57,7 +81,7 @@ | |||||||
|                     {{$labels[$i]}} |                     {{$labels[$i]}} | ||||||
|                 </td> |                 </td> | ||||||
|                 <td class="no-border items padd2" style="padding-right:10px; font-weight: 500; text-align: right; font-size:12px;  color: #040405"> |                 <td class="no-border items padd2" style="padding-right:10px; font-weight: 500; text-align: right; font-size:12px;  color: #040405"> | ||||||
|                     {!! format_money_pdf($taxes[$i]) !!} |                     {!! format_money_pdf($taxes[$i], $estimate->user->currency) !!} | ||||||
|                 </td> |                 </td> | ||||||
|             </tr> |             </tr> | ||||||
|         @endfor |         @endfor | ||||||
| @ -68,7 +92,7 @@ | |||||||
|                     {{$tax->name.' ('.$tax->percent.'%)'}} |                     {{$tax->name.' ('.$tax->percent.'%)'}} | ||||||
|                 </td> |                 </td> | ||||||
|                 <td class="no-border items padd2" style="padding-right:10px; font-weight: 500; text-align: right; font-size:12px;  color: #040405"> |                 <td class="no-border items padd2" style="padding-right:10px; font-weight: 500; text-align: right; font-size:12px;  color: #040405"> | ||||||
|                     {!! format_money_pdf($tax->amount) !!} |                     {!! format_money_pdf($tax->amount, $estimate->user->currency) !!} | ||||||
|                 </td> |                 </td> | ||||||
|             </tr> |             </tr> | ||||||
|         @endforeach |         @endforeach | ||||||
| @ -77,14 +101,19 @@ | |||||||
|     @if ($estimate->discount_per_item === 'NO') |     @if ($estimate->discount_per_item === 'NO') | ||||||
|         <tr> |         <tr> | ||||||
|             <td class="no-border" style="padding-left:10px; text-align:left; font-size:12px; color: #55547A;"> |             <td class="no-border" style="padding-left:10px; text-align:left; font-size:12px; color: #55547A;"> | ||||||
|                 Discount ({{$estimate->discount}}%) |                 @if($estimate->discount_type === 'fixed') | ||||||
|  |                     Discount | ||||||
|  |                 @endif | ||||||
|  |                 @if($estimate->discount_type === 'percentage') | ||||||
|  |                     Discount ({{$estimate->discount}}%) | ||||||
|  |                 @endif | ||||||
|             </td> |             </td> | ||||||
|             <td class="no-border items padd2" style="padding-right:10px; font-weight: 500; text-align: right; font-size:12px;  color: #040405"> |             <td class="no-border items padd2" style="padding-right:10px; font-weight: 500; text-align: right; font-size:12px;  color: #040405"> | ||||||
|                 @if($estimate->discount_type === 'fixed') |                 @if($estimate->discount_type === 'fixed') | ||||||
|                     {!! format_money_pdf($estimate->discount_val) !!} |                     {!! format_money_pdf($estimate->discount_val, $estimate->user->currency) !!} | ||||||
|                 @endif |                 @endif | ||||||
|                 @if($estimate->discount_type === 'percentage') |                 @if($estimate->discount_type === 'percentage') | ||||||
|                     {!! format_money_pdf($estimate->discount_val) !!} |                     {!! format_money_pdf($estimate->discount_val, $estimate->user->currency) !!} | ||||||
|                 @endif |                 @endif | ||||||
|             </td> |             </td> | ||||||
|         </tr> |         </tr> | ||||||
| @ -103,7 +132,7 @@ | |||||||
|             class="no-border total-border-right items padd8" |             class="no-border total-border-right items padd8" | ||||||
|             style="padding-right:10px; font-weight: 500; text-align: right; font-size:12px;  padding-top:20px; color: #5851DB" |             style="padding-right:10px; font-weight: 500; text-align: right; font-size:12px;  padding-top:20px; color: #5851DB" | ||||||
|         > |         > | ||||||
|             {!! format_money_pdf($estimate->total)!!} |             {!! format_money_pdf($estimate->total, $estimate->user->currency)!!} | ||||||
|         </td> |         </td> | ||||||
|     </tr> |     </tr> | ||||||
| </table> | </table> | ||||||
|  | |||||||
| @ -3,9 +3,11 @@ | |||||||
| <head> | <head> | ||||||
|     <title>Invoice</title> |     <title>Invoice</title> | ||||||
|     {{-- <link href="https://fonts.googleapis.com/css?family=Poppins&display=swap" rel="stylesheet"> --}} |     {{-- <link href="https://fonts.googleapis.com/css?family=Poppins&display=swap" rel="stylesheet"> --}} | ||||||
|  |     <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> | ||||||
|  |  | ||||||
|     <style type="text/css"> |     <style type="text/css"> | ||||||
|         body { |         body { | ||||||
|             font-family: 'Roboto', sans-serif; |             font-family: "DejaVu Sans"; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         html { |         html { | ||||||
| @ -59,13 +61,11 @@ | |||||||
|             margin-left:160px; |             margin-left:160px; | ||||||
|         } |         } | ||||||
|         .header { |         .header { | ||||||
|             font-family: 'Roboto', sans-serif; |  | ||||||
|             font-size: 20px; |             font-size: 20px; | ||||||
|             color: rgba(0, 0, 0, 0.7); |             color: rgba(0, 0, 0, 0.7); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         .TextColor1 { |         .TextColor1 { | ||||||
|             font-family: 'Roboto', sans-serif; |  | ||||||
|             font-size: 16px; |             font-size: 16px; | ||||||
|             color: rgba(0, 0, 0, 0.5); |             color: rgba(0, 0, 0, 0.5); | ||||||
|         } |         } | ||||||
| @ -346,7 +346,6 @@ | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         .notes { |         .notes { | ||||||
|             font-family: 'Roboto', sans-serif; |  | ||||||
|             font-style: normal; |             font-style: normal; | ||||||
|             font-weight: 300; |             font-weight: 300; | ||||||
|             font-size: 12px; |             font-size: 12px; | ||||||
| @ -359,7 +358,6 @@ | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         .notes-label { |         .notes-label { | ||||||
|             font-family: 'Roboto', sans-serif; |  | ||||||
|             font-style: normal; |             font-style: normal; | ||||||
|             font-weight: normal; |             font-weight: normal; | ||||||
|             font-size: 15px; |             font-size: 15px; | ||||||
| @ -416,9 +414,8 @@ | |||||||
|         <div class="bill-add"> |         <div class="bill-add"> | ||||||
|             <div class="bill-address-container"> |             <div class="bill-address-container"> | ||||||
|                     @include('app.pdf.invoice.partials.billing-address') |                     @include('app.pdf.invoice.partials.billing-address') | ||||||
|  |  | ||||||
|             </div> |             </div> | ||||||
|             @if($invoice->user->billingaddress->name || $invoice->user->billingaddress->address_street_1 || $invoice->user->billingaddress->address_street_2 || $invoice->user->billingaddress->country || $invoice->user->billingaddress->state || $invoice->user->billingaddress->city || $invoice->user->billingaddress->zip || $invoice->user->billingaddress->phone) |             @if($invoice->user->billingaddress) | ||||||
|                 <div class="ship-address-container"> |                 <div class="ship-address-container"> | ||||||
|             @else |             @else | ||||||
|                 <div class="ship-address-container " style="float:left;padding-left:0px;"> |                 <div class="ship-address-container " style="float:left;padding-left:0px;"> | ||||||
|  | |||||||
| @ -3,9 +3,10 @@ | |||||||
| <head> | <head> | ||||||
|     <title>Invoice</title> |     <title>Invoice</title> | ||||||
|     {{-- <link href="https://fonts.googleapis.com/css?family=Poppins&display=swap" rel="stylesheet"> --}} |     {{-- <link href="https://fonts.googleapis.com/css?family=Poppins&display=swap" rel="stylesheet"> --}} | ||||||
|  |     <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> | ||||||
|     <style type="text/css"> |     <style type="text/css"> | ||||||
|         body { |         body { | ||||||
|             font-family: 'Roboto', sans-serif; |             font-family: "DejaVu Sans"; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         html { |         html { | ||||||
| @ -61,13 +62,11 @@ | |||||||
|             margin-left:160px; |             margin-left:160px; | ||||||
|         } |         } | ||||||
|         .header { |         .header { | ||||||
|             font-family: 'Roboto', sans-serif; |  | ||||||
|             font-size: 20px; |             font-size: 20px; | ||||||
|             color: rgba(0, 0, 0, 0.7); |             color: rgba(0, 0, 0, 0.7); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         .TextColor1 { |         .TextColor1 { | ||||||
|             font-family: 'Roboto', sans-serif; |  | ||||||
|             font-size: 16px; |             font-size: 16px; | ||||||
|             color: rgba(0, 0, 0, 0.5); |             color: rgba(0, 0, 0, 0.5); | ||||||
|         } |         } | ||||||
| @ -373,7 +372,6 @@ | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         .notes { |         .notes { | ||||||
|             font-family: 'Roboto', sans-serif; |  | ||||||
|             font-style: normal; |             font-style: normal; | ||||||
|             font-weight: 300; |             font-weight: 300; | ||||||
|             font-size: 12px; |             font-size: 12px; | ||||||
| @ -386,7 +384,6 @@ | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         .notes-label { |         .notes-label { | ||||||
|             font-family: 'Roboto', sans-serif; |  | ||||||
|             font-style: normal; |             font-style: normal; | ||||||
|             font-weight: normal; |             font-weight: normal; | ||||||
|             font-size: 15px; |             font-size: 15px; | ||||||
| @ -431,7 +428,7 @@ | |||||||
|             <div class="ship-address-container"> |             <div class="ship-address-container"> | ||||||
|                 @include('app.pdf.invoice.partials.shipping-address') |                 @include('app.pdf.invoice.partials.shipping-address') | ||||||
|             </div> |             </div> | ||||||
|             @if($invoice->user->shippingaddress->name || $invoice->user->shippingaddress->address_street_1 || $invoice->user->shippingaddress->address_street_2 || $invoice->user->shippingaddress->country || $invoice->user->shippingaddress->state || $invoice->user->shippingaddress->city || $invoice->user->shippingaddress->zip || $invoice->user->phone) |             @if($invoice->user->shippingaddress) | ||||||
|                 <div class="bill-address-container"> |                 <div class="bill-address-container"> | ||||||
|             @else |             @else | ||||||
|                 <div class="bill-address-container" style="float:right;padding-right:0px;"> |                 <div class="bill-address-container" style="float:right;padding-right:0px;"> | ||||||
|  | |||||||
| @ -3,9 +3,11 @@ | |||||||
| <head> | <head> | ||||||
|     <title>Invoice</title> |     <title>Invoice</title> | ||||||
|     {{-- <link href="https://fonts.googleapis.com/css?family=Poppins&display=swap" rel="stylesheet"> --}} |     {{-- <link href="https://fonts.googleapis.com/css?family=Poppins&display=swap" rel="stylesheet"> --}} | ||||||
|  |     <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> | ||||||
|  |  | ||||||
|     <style type="text/css"> |     <style type="text/css"> | ||||||
|         body { |         body { | ||||||
|             font-family: 'Roboto', sans-serif; |             font-family: "DejaVu Sans"; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         html { |         html { | ||||||
| @ -64,13 +66,11 @@ | |||||||
|             margin-left:160px; |             margin-left:160px; | ||||||
|         } |         } | ||||||
|         .header { |         .header { | ||||||
|             font-family: 'Roboto', sans-serif; |  | ||||||
|             font-size: 20px; |             font-size: 20px; | ||||||
|             color: rgba(0, 0, 0, 0.7); |             color: rgba(0, 0, 0, 0.7); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         .TextColor1 { |         .TextColor1 { | ||||||
|             font-family: 'Roboto', sans-serif; |  | ||||||
|             font-size: 16px; |             font-size: 16px; | ||||||
|             color: rgba(0, 0, 0, 0.5); |             color: rgba(0, 0, 0, 0.5); | ||||||
|         } |         } | ||||||
| @ -382,7 +382,6 @@ | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         .notes { |         .notes { | ||||||
|             font-family: 'Roboto', sans-serif; |  | ||||||
|             font-style: normal; |             font-style: normal; | ||||||
|             font-weight: 300; |             font-weight: 300; | ||||||
|             font-size: 12px; |             font-size: 12px; | ||||||
| @ -395,7 +394,6 @@ | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         .notes-label { |         .notes-label { | ||||||
|             font-family: 'Roboto', sans-serif; |  | ||||||
|             font-style: normal; |             font-style: normal; | ||||||
|             font-weight: normal; |             font-weight: normal; | ||||||
|             font-size: 15px; |             font-size: 15px; | ||||||
| @ -436,7 +434,7 @@ | |||||||
|                 <div style="float:left;"> |                 <div style="float:left;"> | ||||||
|                     @include('app.pdf.invoice.partials.billing-address') |                     @include('app.pdf.invoice.partials.billing-address') | ||||||
|                 </div> |                 </div> | ||||||
|                 @if($invoice->user->billingaddress->name || $invoice->user->billingaddress->address_street_1 || $invoice->user->billingaddress->address_street_2 || $invoice->user->billingaddress->country || $invoice->user->billingaddress->state || $invoice->user->billingaddress->city || $invoice->user->billingaddress->zip || $invoice->user->billingaddress->phone) |                 @if($invoice->user->billingaddress) | ||||||
|                     <div style="float:right;"> |                     <div style="float:right;"> | ||||||
|                 @else |                 @else | ||||||
|                     <div style="float:left;"> |                     <div style="float:left;"> | ||||||
|  | |||||||
| @ -1,7 +1,5 @@ | |||||||
| @if($invoice->user->billingaddress) | @if($invoice->user->billingaddress) | ||||||
|     @if($invoice->user->billingaddress->name || $invoice->user->billingaddress->address_street_1 || $invoice->user->billingaddress->address_street_2 || $invoice->user->billingaddress->country || $invoice->user->billingaddress->state || $invoice->user->billingaddress->city || $invoice->user->billingaddress->zip || $invoice->user->billingaddress->phone) |     <p class="bill-to">Bill To,</p> | ||||||
|         <p class="bill-to">Bill To,</p> |  | ||||||
|     @endif |  | ||||||
|     @if($invoice->user->billingaddress->name) |     @if($invoice->user->billingaddress->name) | ||||||
|         <p class="bill-user-name"> |         <p class="bill-user-name"> | ||||||
|             {{$invoice->user->billingaddress->name}} |             {{$invoice->user->billingaddress->name}} | ||||||
|  | |||||||
| @ -3,6 +3,6 @@ | |||||||
|         <div class="notes-label"> |         <div class="notes-label"> | ||||||
|             Notes |             Notes | ||||||
|         </div> |         </div> | ||||||
|         {{$invoice->notes}} |         {!! $invoice->notes !!} | ||||||
|     </div> |     </div> | ||||||
| @endif | @endif | ||||||
|  | |||||||
| @ -1,7 +1,5 @@ | |||||||
| @if($invoice->user->shippingaddress) | @if($invoice->user->shippingaddress) | ||||||
|     @if($invoice->user->shippingaddress->name || $invoice->user->shippingaddress->address_street_1 || $invoice->user->shippingaddress->address_street_2 || $invoice->user->shippingaddress->country || $invoice->user->shippingaddress->state || $invoice->user->shippingaddress->city || $invoice->user->shippingaddress->zip || $invoice->user->phone) |     <p class="ship-to">Ship To,</p> | ||||||
|         <p class="ship-to">Ship To,</p> |  | ||||||
|     @endif |  | ||||||
|     @if($invoice->user->shippingaddress->name) |     @if($invoice->user->shippingaddress->name) | ||||||
|         <p class="ship-user-name"> |         <p class="ship-user-name"> | ||||||
|             {{$invoice->user->shippingaddress->name}} |             {{$invoice->user->shippingaddress->name}} | ||||||
|  | |||||||
| @ -18,24 +18,47 @@ | |||||||
|     @endphp |     @endphp | ||||||
|     @foreach ($invoice->items as $item) |     @foreach ($invoice->items as $item) | ||||||
|         <tr class="item-details"> |         <tr class="item-details"> | ||||||
|             <td class="inv-item items" style="text-align: right; color: #040405; padding-right: 20px; vertical-align: top;">{{$index}}</td> |             <td | ||||||
|             <td class="inv-item items" style="text-align: left; color: #040405;padding-left: 0px"> |                 class="inv-item items" | ||||||
|  |                 style="text-align: right; color: #040405; padding-right: 20px; vertical-align: top;" | ||||||
|  |             > | ||||||
|  |                 {{$index}} | ||||||
|  |             </td> | ||||||
|  |             <td | ||||||
|  |                 class="inv-item items" | ||||||
|  |                 style="text-align: left; color: #040405;padding-left: 0px" | ||||||
|  |             > | ||||||
|                 <span>{{ $item->name }}</span><br> |                 <span>{{ $item->name }}</span><br> | ||||||
|                 <span style="text-align: left; color: #595959; font-size: 9px; font-weight:300; line-height: 12px;">{{ $item->description }}</span> |                 <span style="text-align: left; color: #595959; font-size: 9px; font-weight:300; line-height: 12px;">{{ $item->description }}</span> | ||||||
|             </td> |             </td> | ||||||
|             <td class="inv-item items" style="text-align: right; color: #040405; padding-right: 20px">{{$item->quantity}}</td> |             <td | ||||||
|             <td class="inv-item items" style="text-align: right; color: #040405; padding-right: 40px">{{$item->price/100}}</td> |                 class="inv-item items" | ||||||
|  |                 style="text-align: right; color: #040405; padding-right: 20px" | ||||||
|  |             > | ||||||
|  |                 {{$item->quantity}} | ||||||
|  |             </td> | ||||||
|  |             <td | ||||||
|  |                 class="inv-item items" | ||||||
|  |                 style="text-align: right; color: #040405; padding-right: 40px" | ||||||
|  |             > | ||||||
|  |                 {!! format_money_pdf($item->price, $invoice->user->currency) !!} | ||||||
|  |             </td> | ||||||
|             @if($invoice->discount_per_item === 'YES') |             @if($invoice->discount_per_item === 'YES') | ||||||
|                 <td class="inv-item items" style="text-align: right; color: #040405; padding-left: 10px"> |                 <td class="inv-item items" style="text-align: right; color: #040405; padding-left: 10px"> | ||||||
|                     @if($item->discount_type === 'fixed') |                     @if($item->discount_type === 'fixed') | ||||||
|                         {{$item->discount_val/100}} |                         {!! format_money_pdf($item->discount_val, $invoice->user->currency) !!} | ||||||
|                     @endif |                     @endif | ||||||
|                     @if($item->discount_type === 'percentage') |                     @if($item->discount_type === 'percentage') | ||||||
|                         {{$item->discount}}% |                         {{$item->discount}}% | ||||||
|                     @endif |                     @endif | ||||||
|                 </td> |                 </td> | ||||||
|             @endif |             @endif | ||||||
|             <td class="inv-item items" style="text-align: right; color: #040405;">{{$item->total/100}}</td> |             <td | ||||||
|  |                 class="inv-item items" | ||||||
|  |                 style="text-align: right; color: #040405;" | ||||||
|  |             > | ||||||
|  |                 {!! format_money_pdf($item->total, $invoice->user->currency) !!} | ||||||
|  |             </td> | ||||||
|         </tr> |         </tr> | ||||||
|         @php |         @php | ||||||
|             $index += 1 |             $index += 1 | ||||||
| @ -47,7 +70,7 @@ | |||||||
|     <tr> |     <tr> | ||||||
|         <td class="no-borde" style="color: #55547A; padding-left:10px;  font-size:12px;">Subtotal</td> |         <td class="no-borde" style="color: #55547A; padding-left:10px;  font-size:12px;">Subtotal</td> | ||||||
|         <td class="no-border items" |         <td class="no-border items" | ||||||
|             style="padding-right:10px; text-align: right;  font-size:12px; color: #040405; font-weight: 500;">{!! format_money_pdf($invoice->sub_total) !!}</td> |             style="padding-right:10px; text-align: right;  font-size:12px; color: #040405; font-weight: 500;">{!! format_money_pdf($invoice->sub_total, $invoice->user->currency) !!}</td> | ||||||
|     </tr> |     </tr> | ||||||
|  |  | ||||||
|     @if ($invoice->tax_per_item === 'YES') |     @if ($invoice->tax_per_item === 'YES') | ||||||
| @ -57,7 +80,7 @@ | |||||||
|                     {{$labels[$i]}} |                     {{$labels[$i]}} | ||||||
|                 </td> |                 </td> | ||||||
|                 <td class="no-border items padd2" style="padding-right:10px; font-weight: 500; text-align: right; font-size:12px;  color: #040405"> |                 <td class="no-border items padd2" style="padding-right:10px; font-weight: 500; text-align: right; font-size:12px;  color: #040405"> | ||||||
|                     {!! format_money_pdf($taxes[$i]) !!} |                     {!! format_money_pdf($taxes[$i], $invoice->user->currency) !!} | ||||||
|                 </td> |                 </td> | ||||||
|             </tr> |             </tr> | ||||||
|         @endfor |         @endfor | ||||||
| @ -68,7 +91,7 @@ | |||||||
|                     {{$tax->name.' ('.$tax->percent.'%)'}} |                     {{$tax->name.' ('.$tax->percent.'%)'}} | ||||||
|                 </td> |                 </td> | ||||||
|                 <td class="no-border items padd2" style="padding-right:10px; font-weight: 500; text-align: right; font-size:12px;  color: #040405"> |                 <td class="no-border items padd2" style="padding-right:10px; font-weight: 500; text-align: right; font-size:12px;  color: #040405"> | ||||||
|                     {!! format_money_pdf($tax->amount) !!} |                     {!! format_money_pdf($tax->amount, $invoice->user->currency) !!} | ||||||
|                 </td> |                 </td> | ||||||
|             </tr> |             </tr> | ||||||
|         @endforeach |         @endforeach | ||||||
| @ -77,14 +100,19 @@ | |||||||
|     @if ($invoice->discount_per_item === 'NO') |     @if ($invoice->discount_per_item === 'NO') | ||||||
|         <tr> |         <tr> | ||||||
|             <td class="no-border" style="padding-left:10px; text-align:left; font-size:12px; color: #55547A;"> |             <td class="no-border" style="padding-left:10px; text-align:left; font-size:12px; color: #55547A;"> | ||||||
|                 Discount ({{$invoice->discount}}%) |                 @if($invoice->discount_type === 'fixed') | ||||||
|  |                     Discount | ||||||
|  |                 @endif | ||||||
|  |                 @if($invoice->discount_type === 'percentage') | ||||||
|  |                     Discount ({{$invoice->discount}}%) | ||||||
|  |                 @endif | ||||||
|             </td> |             </td> | ||||||
|             <td class="no-border items padd2" style="padding-right:10px; font-weight: 500; text-align: right; font-size:12px;  color: #040405"> |             <td class="no-border items padd2" style="padding-right:10px; font-weight: 500; text-align: right; font-size:12px;  color: #040405"> | ||||||
|                 @if($invoice->discount_type === 'fixed') |                 @if($invoice->discount_type === 'fixed') | ||||||
|                     {!! format_money_pdf($invoice->discount_val) !!} |                     {!! format_money_pdf($invoice->discount_val, $invoice->user->currency) !!} | ||||||
|                 @endif |                 @endif | ||||||
|                 @if($invoice->discount_type === 'percentage') |                 @if($invoice->discount_type === 'percentage') | ||||||
|                     {!! format_money_pdf($invoice->discount_val) !!} |                     {!! format_money_pdf($invoice->discount_val, $invoice->user->currency) !!} | ||||||
|                 @endif |                 @endif | ||||||
|             </td> |             </td> | ||||||
|         </tr> |         </tr> | ||||||
| @ -103,7 +131,7 @@ | |||||||
|             class="no-border total-border-right items padd8" |             class="no-border total-border-right items padd8" | ||||||
|             style="padding-right:10px; font-weight: 500; text-align: right; font-size:12px;  padding-top:20px; color: #5851DB" |             style="padding-right:10px; font-weight: 500; text-align: right; font-size:12px;  padding-top:20px; color: #5851DB" | ||||||
|         > |         > | ||||||
|             {!! format_money_pdf($invoice->total)!!} |             {!! format_money_pdf($invoice->total, $invoice->user->currency)!!} | ||||||
|         </td> |         </td> | ||||||
|     </tr> |     </tr> | ||||||
| </table> | </table> | ||||||
|  | |||||||
| @ -5,7 +5,7 @@ | |||||||
|     {{-- <link href="https://fonts.googleapis.com/css?family=Poppins&display=swap" rel="stylesheet"> --}} |     {{-- <link href="https://fonts.googleapis.com/css?family=Poppins&display=swap" rel="stylesheet"> --}} | ||||||
|     <style type="text/css"> |     <style type="text/css"> | ||||||
|         body { |         body { | ||||||
|             font-family: 'Roboto', sans-serif; |             font-family: "DejaVu Sans"; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         /* html { |         /* html { | ||||||
| @ -181,10 +181,14 @@ | |||||||
|                     @foreach ($expenseCategories as $expenseCategory) |                     @foreach ($expenseCategories as $expenseCategory) | ||||||
|                         <tr> |                         <tr> | ||||||
|                             <td> |                             <td> | ||||||
|                                 <p class="expense-title">{{ $expenseCategory->category->name }}</p> |                                 <p class="expense-title"> | ||||||
|  |                                     {{ $expenseCategory->category->name }} | ||||||
|  |                                 </p> | ||||||
|                             </td> |                             </td> | ||||||
|                             <td> |                             <td> | ||||||
|                                 <p class="expense-money">{!! format_money_pdf($expenseCategory->total_amount) !!}</p> |                                 <p class="expense-money"> | ||||||
|  |                                     {!! format_money_pdf($expenseCategory->total_amount) !!} | ||||||
|  |                                 </p> | ||||||
|                             </td> |                             </td> | ||||||
|                         </tr> |                         </tr> | ||||||
|                     @endforeach |                     @endforeach | ||||||
|  | |||||||
| @ -5,7 +5,7 @@ | |||||||
|     {{-- <link href="https://fonts.googleapis.com/css?family=Poppins&display=swap" rel="stylesheet"> --}} |     {{-- <link href="https://fonts.googleapis.com/css?family=Poppins&display=swap" rel="stylesheet"> --}} | ||||||
|     <style type="text/css"> |     <style type="text/css"> | ||||||
|         body { |         body { | ||||||
|             font-family: 'Roboto', sans-serif; |             font-family: "DejaVu Sans"; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         html { |         html { | ||||||
| @ -220,10 +220,14 @@ | |||||||
|                     @foreach ($expenseCategories as $expenseCategory) |                     @foreach ($expenseCategories as $expenseCategory) | ||||||
|                         <tr> |                         <tr> | ||||||
|                             <td> |                             <td> | ||||||
|                                 <p class="expense-title">{{ $expenseCategory->category->name }}</p> |                                 <p class="expense-title"> | ||||||
|  |                                     {{ $expenseCategory->category->name }} | ||||||
|  |                                 </p> | ||||||
|                             </td> |                             </td> | ||||||
|                             <td> |                             <td> | ||||||
|                                 <p class="expense-money">{!! format_money_pdf($expenseCategory->total_amount) !!}</p> |                                 <p class="expense-money"> | ||||||
|  |                                     {!! format_money_pdf($expenseCategory->total_amount) !!} | ||||||
|  |                                 </p> | ||||||
|                             </td> |                             </td> | ||||||
|                         </tr> |                         </tr> | ||||||
|                     @endforeach |                     @endforeach | ||||||
|  | |||||||
| @ -5,7 +5,7 @@ | |||||||
|     {{-- <link href="https://fonts.googleapis.com/css?family=Poppins&display=swap" rel="stylesheet"> --}} |     {{-- <link href="https://fonts.googleapis.com/css?family=Poppins&display=swap" rel="stylesheet"> --}} | ||||||
|     <style type="text/css"> |     <style type="text/css"> | ||||||
|         body { |         body { | ||||||
|             font-family: 'Roboto', sans-serif; |             font-family: "DejaVu Sans"; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         /* html { |         /* html { | ||||||
| @ -223,10 +223,14 @@ | |||||||
|                         @foreach ($customer->invoices as $invoice) |                         @foreach ($customer->invoices as $invoice) | ||||||
|                             <tr> |                             <tr> | ||||||
|                                 <td> |                                 <td> | ||||||
|                                     <p class="expense-title">{{ $invoice->formattedInvoiceDate }} ({{ $invoice->invoice_number }})</p> |                                     <p class="expense-title"> | ||||||
|  |                                         {{ $invoice->formattedInvoiceDate }} ({{ $invoice->invoice_number }}) | ||||||
|  |                                     </p> | ||||||
|                                 </td> |                                 </td> | ||||||
|                                 <td> |                                 <td> | ||||||
|                                     <p class="expense-money">{!! format_money_pdf($invoice->total) !!}</p> |                                     <p class="expense-money"> | ||||||
|  |                                         {!! format_money_pdf($invoice->total) !!} | ||||||
|  |                                     </p> | ||||||
|                                 </td> |                                 </td> | ||||||
|                             </tr> |                             </tr> | ||||||
|                         @endforeach |                         @endforeach | ||||||
| @ -235,7 +239,9 @@ | |||||||
|                 <table class="expense-total-table"> |                 <table class="expense-total-table"> | ||||||
|                     <tr> |                     <tr> | ||||||
|                         <td class="expense-total-cell"> |                         <td class="expense-total-cell"> | ||||||
|                             <p class="expense-total">{!! format_money_pdf($customer->totalAmount) !!}</p> |                             <p class="expense-total"> | ||||||
|  |                                 {!! format_money_pdf($customer->totalAmount) !!} | ||||||
|  |                             </p> | ||||||
|                         </td> |                         </td> | ||||||
|                     </tr> |                     </tr> | ||||||
|                 </table> |                 </table> | ||||||
| @ -249,7 +255,9 @@ | |||||||
|                     <p class="profit-title">TOTAL SALES</p> |                     <p class="profit-title">TOTAL SALES</p> | ||||||
|                 </td> |                 </td> | ||||||
|                 <td> |                 <td> | ||||||
|                     <p class="profit-money">{!! format_money_pdf($totalAmount) !!}</p> |                     <p class="profit-money"> | ||||||
|  |                         {!! format_money_pdf($totalAmount) !!} | ||||||
|  |                     </p> | ||||||
|                 </td> |                 </td> | ||||||
|             </tr> |             </tr> | ||||||
|         </table> |         </table> | ||||||
|  | |||||||
| @ -5,7 +5,7 @@ | |||||||
|     {{-- <link href="https://fonts.googleapis.com/css?family=Poppins&display=swap" rel="stylesheet"> --}} |     {{-- <link href="https://fonts.googleapis.com/css?family=Poppins&display=swap" rel="stylesheet"> --}} | ||||||
|     <style type="text/css"> |     <style type="text/css"> | ||||||
|         body { |         body { | ||||||
|             font-family: 'Roboto', sans-serif; |             font-family: "DejaVu Sans"; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         /* html { |         /* html { | ||||||
| @ -222,10 +222,14 @@ | |||||||
|                     <table class="expenses-table"> |                     <table class="expenses-table"> | ||||||
|                         <tr> |                         <tr> | ||||||
|                             <td> |                             <td> | ||||||
|                                 <p class="expense-title">{{ $item->name }}</p> |                                 <p class="expense-title"> | ||||||
|  |                                     {{ $item->name }} | ||||||
|  |                                 </p> | ||||||
|                             </td> |                             </td> | ||||||
|                             <td> |                             <td> | ||||||
|                                 <p class="expense-money">{!! format_money_pdf($item->total_amount) !!}</p> |                                 <p class="expense-money"> | ||||||
|  |                                     {!! format_money_pdf($item->total_amount) !!} | ||||||
|  |                                 </p> | ||||||
|                             </td> |                             </td> | ||||||
|                         </tr> |                         </tr> | ||||||
|                     </table> |                     </table> | ||||||
| @ -235,7 +239,9 @@ | |||||||
|                 <table class="expense-total-table"> |                 <table class="expense-total-table"> | ||||||
|                     <tr> |                     <tr> | ||||||
|                         <td class="expense-total-cell"> |                         <td class="expense-total-cell"> | ||||||
|                             <p class="expense-total">{!! format_money_pdf($totalAmount) !!}</p> |                             <p class="expense-total"> | ||||||
|  |                                 {!! format_money_pdf($totalAmount) !!} | ||||||
|  |                             </p> | ||||||
|                         </td> |                         </td> | ||||||
|                     </tr> |                     </tr> | ||||||
|                 </table> |                 </table> | ||||||
| @ -248,7 +254,9 @@ | |||||||
|                     <p class="profit-title">TOTAL SALES</p> |                     <p class="profit-title">TOTAL SALES</p> | ||||||
|                 </td> |                 </td> | ||||||
|                 <td> |                 <td> | ||||||
|                     <p class="profit-money">{!! format_money_pdf($totalAmount) !!}</p> |                     <p class="profit-money"> | ||||||
|  |                         {!! format_money_pdf($totalAmount) !!} | ||||||
|  |                     </p> | ||||||
|                 </td> |                 </td> | ||||||
|             </tr> |             </tr> | ||||||
|         </table> |         </table> | ||||||
|  | |||||||
| @ -5,7 +5,7 @@ | |||||||
|     {{-- <link href="https://fonts.googleapis.com/css?family=Poppins&display=swap" rel="stylesheet"> --}} |     {{-- <link href="https://fonts.googleapis.com/css?family=Poppins&display=swap" rel="stylesheet"> --}} | ||||||
|     <style type="text/css"> |     <style type="text/css"> | ||||||
|         body { |         body { | ||||||
|             font-family: 'Roboto', sans-serif; |             font-family: "DejaVu Sans"; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         /* html { |         /* html { | ||||||
| @ -174,10 +174,14 @@ | |||||||
|             <table class="header"> |             <table class="header"> | ||||||
|                 <tr> |                 <tr> | ||||||
|                     <td> |                     <td> | ||||||
|                         <p class="heading-text">{{ $company->name }}</p> |                         <p class="heading-text"> | ||||||
|  |                             {{ $company->name }} | ||||||
|  |                         </p> | ||||||
|                     </td> |                     </td> | ||||||
|                     <td> |                     <td> | ||||||
|                         <p class="heading-date-range">{{ $from_date }} - {{ $to_date }}</p> |                         <p class="heading-date-range"> | ||||||
|  |                             {{ $from_date }} - {{ $to_date }} | ||||||
|  |                         </p> | ||||||
|                     </td> |                     </td> | ||||||
|                 </tr> |                 </tr> | ||||||
|                 <tr> |                 <tr> | ||||||
| @ -192,10 +196,14 @@ | |||||||
|                     @foreach ($taxTypes as $tax) |                     @foreach ($taxTypes as $tax) | ||||||
|                         <tr> |                         <tr> | ||||||
|                             <td> |                             <td> | ||||||
|                                 <p class="tax-title">{{ $tax->taxType->name }}</p> |                                 <p class="tax-title"> | ||||||
|  |                                     {{ $tax->taxType->name }} | ||||||
|  |                                 </p> | ||||||
|                             </td> |                             </td> | ||||||
|                             <td> |                             <td> | ||||||
|                                 <p class="tax-money">{!! format_money_pdf($tax->total_tax_amount) !!}</p> |                                 <p class="tax-money"> | ||||||
|  |                                     {!! format_money_pdf($tax->total_tax_amount) !!} | ||||||
|  |                                 </p> | ||||||
|                             </td> |                             </td> | ||||||
|                         </tr> |                         </tr> | ||||||
|                     @endforeach |                     @endforeach | ||||||
| @ -207,7 +215,9 @@ | |||||||
|         <table class="tax-total-table"> |         <table class="tax-total-table"> | ||||||
|             <tr> |             <tr> | ||||||
|                 <td class="tax-total-cell"> |                 <td class="tax-total-cell"> | ||||||
|                     <p class="tax-total">{!! format_money_pdf($totalTaxAmount) !!}</p> |                     <p class="tax-total"> | ||||||
|  |                         {!! format_money_pdf($totalTaxAmount) !!} | ||||||
|  |                     </p> | ||||||
|                 </td> |                 </td> | ||||||
|             </tr> |             </tr> | ||||||
|         </table> |         </table> | ||||||
| @ -217,7 +227,9 @@ | |||||||
|                     <p class="total-tax-title">TOTAL TAX</p> |                     <p class="total-tax-title">TOTAL TAX</p> | ||||||
|                 </td> |                 </td> | ||||||
|                 <td> |                 <td> | ||||||
|                     <p class="total-tax-money">{!! format_money_pdf($totalTaxAmount) !!}</p> |                     <p class="total-tax-money"> | ||||||
|  |                         {!! format_money_pdf($totalTaxAmount) !!} | ||||||
|  |                     </p> | ||||||
|                 </td> |                 </td> | ||||||
|             </tr> |             </tr> | ||||||
|         </table> |         </table> | ||||||
|  | |||||||
| @ -46,16 +46,6 @@ Route::get('/countries', [ | |||||||
|     'uses' => 'LocationController@getCountries' |     'uses' => 'LocationController@getCountries' | ||||||
| ]); | ]); | ||||||
|  |  | ||||||
| Route::get('/states/{id}', [ |  | ||||||
|     'as' => 'states', |  | ||||||
|     'uses' => 'LocationController@getStates' |  | ||||||
| ]); |  | ||||||
|  |  | ||||||
| Route::get('/cities/{id}', [ |  | ||||||
|     'as' => 'cities', |  | ||||||
|     'uses' => 'LocationController@getCities' |  | ||||||
| ]); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| // Onboarding | // Onboarding | ||||||
| //---------------------------------- | //---------------------------------- | ||||||
| @ -358,6 +348,16 @@ Route::group(['middleware' => 'api'], function () { | |||||||
|                 'uses' => 'CompanyController@updateSetting' |                 'uses' => 'CompanyController@updateSetting' | ||||||
|             ]); |             ]); | ||||||
|  |  | ||||||
|  |             Route::get('/get-customize-setting', [ | ||||||
|  |                 'as' => 'admin.get.customize.setting', | ||||||
|  |                 'uses' => 'CompanyController@getCustomizeSetting' | ||||||
|  |             ]); | ||||||
|  |  | ||||||
|  |             Route::put('/update-customize-setting', [ | ||||||
|  |                 'as' => 'admin.update.customize.setting', | ||||||
|  |                 'uses' => 'CompanyController@updateCustomizeSetting' | ||||||
|  |             ]); | ||||||
|  |  | ||||||
|             Route::get('/environment/mail', [ |             Route::get('/environment/mail', [ | ||||||
|                 'as' => 'admin.environment.mail', |                 'as' => 'admin.environment.mail', | ||||||
|                 'uses' => 'EnvironmentController@getMailDrivers' |                 'uses' => 'EnvironmentController@getMailDrivers' | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	