mirror of
				https://github.com/crater-invoice/crater.git
				synced 2025-10-27 19:51:09 -04:00 
			
		
		
		
	Refactor Customization Page
This commit is contained in:
		| @ -54,10 +54,13 @@ class Estimate extends Model | ||||
|         'sub_total' => 'float' | ||||
|     ]; | ||||
|  | ||||
|     public static function getNextEstimateNumber() | ||||
|     public static function getNextEstimateNumber($value) | ||||
|     { | ||||
|          // 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) { | ||||
|             // 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. | ||||
| @ -99,10 +102,16 @@ class Estimate extends Model | ||||
|  | ||||
|     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); | ||||
|     } | ||||
|  | ||||
|     public function getEstimatePrefixAttribute() | ||||
|     { | ||||
|         $prefix = explode("-",$this->estimate_number)[0]; | ||||
|         return $prefix; | ||||
|     } | ||||
|  | ||||
|     private function strposX($haystack, $needle, $number) | ||||
|     { | ||||
|         if ($number == '1') { | ||||
|  | ||||
| @ -157,12 +157,8 @@ class CompanyController extends Controller | ||||
|     { | ||||
|         $invoice_prefix = CompanySetting::getSetting('invoice_prefix', $request->header('company')); | ||||
|         $invoice_auto_generate = CompanySetting::getSetting('invoice_auto_generate', $request->header('company')); | ||||
|         $invoice_notes = CompanySetting::getSetting('invoice_notes',  $request->header('company'), true); | ||||
|         $invoice_terms_and_conditions = CompanySetting::getSetting('invoice_terms_and_conditions', $request->header('company'), true); | ||||
|  | ||||
|         $estimate_prefix = CompanySetting::getSetting('estimate_prefix', $request->header('company')); | ||||
|         $estimate_notes = CompanySetting::getSetting('estimate_notes', $request->header('company'), true); | ||||
|         $estimate_terms_and_conditions = CompanySetting::getSetting('estimate_terms_and_conditions', $request->header('company'), true); | ||||
|         $estimate_auto_generate  = CompanySetting::getSetting('estimate_auto_generate', $request->header('company')); | ||||
|  | ||||
|         $payment_prefix = CompanySetting::getSetting('payment_prefix', $request->header('company')); | ||||
| @ -175,12 +171,8 @@ class CompanyController extends Controller | ||||
|         return  response()->json([ | ||||
|             'invoice_prefix' => $invoice_prefix, | ||||
|             'invoice_auto_generate' => $invoice_auto_generate, | ||||
|             'invoice_notes' => $invoice_notes, | ||||
|             'invoice_terms_and_conditions' => $invoice_terms_and_conditions, | ||||
|             'estimate_prefix' => $estimate_prefix, | ||||
|             'estimate_auto_generate' => $estimate_auto_generate, | ||||
|             'estimate_notes' => $estimate_notes, | ||||
|             'estimate_terms_and_conditions' => $estimate_terms_and_conditions, | ||||
|             'payment_prefix' => $payment_prefix, | ||||
|             'payment_auto_generate' => $payment_auto_generate, | ||||
|             'billing_address_format' => $billing_address_format, | ||||
| @ -200,14 +192,10 @@ class CompanyController extends Controller | ||||
|         } elseif ($request->type == "INVOICES") { | ||||
|             $sets = [ | ||||
|                 'invoice_prefix', | ||||
|                 'invoice_notes', | ||||
|                 'invoice_terms_and_conditions' | ||||
|             ]; | ||||
|         } elseif ($request->type == "ESTIMATES") { | ||||
|             $sets = [ | ||||
|                 'estimate_prefix', | ||||
|                 'estimate_notes', | ||||
|                 'estimate_terms_and_conditions' | ||||
|             ]; | ||||
|         } else { | ||||
|             $sets = [ | ||||
|  | ||||
| @ -56,25 +56,41 @@ class EstimatesController extends Controller | ||||
|  | ||||
|     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; | ||||
|  | ||||
|         if ($estimate_num_auto_generate == "YES") { | ||||
|             $nextEstimateNumberAttribute = Estimate::getNextEstimateNumber($estimate_prefix); | ||||
|         } | ||||
|  | ||||
|         $tax_per_item = CompanySetting::getSetting('tax_per_item', $request->header('company')); | ||||
|         $discount_per_item = CompanySetting::getSetting('discount_per_item', $request->header('company')); | ||||
|         $customers = User::where('role', 'customer')->get(); | ||||
|  | ||||
|         return response()->json([ | ||||
|             'customers' => $customers, | ||||
|             'nextEstimateNumber' => $nextEstimateNumber, | ||||
|             'nextEstimateNumber' =>  $nextEstimateNumberAttribute, | ||||
|             'taxes' => Tax::whereCompany($request->header('company'))->latest()->get(), | ||||
|             'items' => Item::whereCompany($request->header('company'))->get(), | ||||
|             'tax_per_item' => $tax_per_item, | ||||
|             'discount_per_item' => $discount_per_item, | ||||
|             'estimateTemplates' => EstimateTemplate::all(), | ||||
|             'shareable_link' => '' | ||||
|             'shareable_link' => '', | ||||
|             'estimate_prefix' => $estimate_prefix | ||||
|         ]); | ||||
|     } | ||||
|  | ||||
|     public function store(EstimatesRequest $request) | ||||
|     { | ||||
|         $estimate_number = explode("-",$request->estimate_number); | ||||
|         $number_attributes['estimate_number'] = $estimate_number[0].'-'.sprintf('%06d', intval($estimate_number[1])); | ||||
|  | ||||
|         Validator::make($number_attributes, [ | ||||
|             'estimate_number' => 'required|unique:estimates,estimate_number' | ||||
|         ])->validate(); | ||||
|  | ||||
|         $estimate_date = Carbon::createFromFormat('d/m/Y', $request->estimate_date); | ||||
|         $expiry_date = Carbon::createFromFormat('d/m/Y', $request->expiry_date); | ||||
|         $status = Estimate::STATUS_DRAFT; | ||||
| @ -101,7 +117,7 @@ class EstimatesController extends Controller | ||||
|         $estimate = Estimate::create([ | ||||
|             'estimate_date' => $estimate_date, | ||||
|             'expiry_date' => $expiry_date, | ||||
|             'estimate_number' => $request->estimate_number, | ||||
|             'estimate_number' => $number_attributes['estimate_number'], | ||||
|             'reference_number' => $request->reference_number, | ||||
|             'user_id' => $request->user_id, | ||||
|             'company_id' => $request->header('company'), | ||||
| @ -216,26 +232,33 @@ class EstimatesController extends Controller | ||||
|  | ||||
|         return response()->json( [ | ||||
|             'customers' => $customers, | ||||
|             'nextEstimateNumber' => $estimate->estimate_number, | ||||
|             'nextEstimateNumber' => $estimate->getEstimateNumAttribute(), | ||||
|             'taxes' => Tax::latest()->whereCompany($request->header('company'))->get(), | ||||
|             'estimate' => $estimate, | ||||
|             'items' => Item::whereCompany($request->header('company'))->latest()->get(), | ||||
|             'estimateTemplates' => EstimateTemplate::all(), | ||||
|             'tax_per_item' => $estimate->tax_per_item, | ||||
|             'discount_per_item' => $estimate->discount_per_item, | ||||
|             'shareable_link' => url('/estimates/pdf/'.$estimate->unique_hash) | ||||
|             'shareable_link' => url('/estimates/pdf/'.$estimate->unique_hash), | ||||
|             'estimate_prefix' => $estimate->getEstimatePrefixAttribute() | ||||
|         ]); | ||||
|     } | ||||
|  | ||||
|     public function update(EstimatesRequest $request, $id) | ||||
|     { | ||||
|         $estimate_number = explode("-",$request->estimate_number); | ||||
|         $number_attributes['estimate_number'] = $estimate_number[0].'-'.sprintf('%06d', intval($estimate_number[1])); | ||||
|         Validator::make($number_attributes, [ | ||||
|             'estimate_number' => 'required|unique:estimates,estimate_number'.','.$id | ||||
|         ])->validate(); | ||||
|  | ||||
|         $estimate_date = Carbon::createFromFormat('d/m/Y', $request->estimate_date); | ||||
|         $expiry_date = Carbon::createFromFormat('d/m/Y', $request->expiry_date); | ||||
|  | ||||
|         $estimate = Estimate::find($id); | ||||
|         $estimate->estimate_date = $estimate_date; | ||||
|         $estimate->expiry_date = $expiry_date; | ||||
|         $estimate->estimate_number = $request->estimate_number; | ||||
|         $estimate->estimate_number = $number_attributes['estimate_number']; | ||||
|         $estimate->reference_number = $request->reference_number; | ||||
|         $estimate->user_id = $request->user_id; | ||||
|         $estimate->estimate_template_id = $request->estimate_template_id; | ||||
|  | ||||
| @ -66,14 +66,22 @@ class InvoicesController extends Controller | ||||
|     { | ||||
|         $tax_per_item = CompanySetting::getSetting('tax_per_item', $request->header('company')); | ||||
|         $discount_per_item = CompanySetting::getSetting('discount_per_item', $request->header('company')); | ||||
|         $nextInvoiceNumber = "INV-".Invoice::getNextInvoiceNumber(); | ||||
|         $invoice_prefix = CompanySetting::getSetting('invoice_prefix', $request->header('company')); | ||||
|         $invoice_num_auto_generate = CompanySetting::getSetting('invoice_auto_generate', $request->header('company')); | ||||
|  | ||||
|         $nextInvoiceNumberAttribute = null; | ||||
|  | ||||
|         if ($invoice_num_auto_generate == "YES") { | ||||
|             $nextInvoiceNumberAttribute = Invoice::getNextInvoiceNumber($invoice_prefix); | ||||
|         } | ||||
|  | ||||
|         return response()->json([ | ||||
|             'nextInvoiceNumber' => $nextInvoiceNumber, | ||||
|             'nextInvoiceNumber' => $nextInvoiceNumberAttribute, | ||||
|             'items' => Item::with('taxes')->whereCompany($request->header('company'))->get(), | ||||
|             'invoiceTemplates' => InvoiceTemplate::all(), | ||||
|             'tax_per_item' => $tax_per_item, | ||||
|             'discount_per_item' => $discount_per_item | ||||
|             'discount_per_item' => $discount_per_item, | ||||
|             'invoice_prefix' => $invoice_prefix | ||||
|         ]); | ||||
|     } | ||||
|  | ||||
| @ -85,6 +93,13 @@ class InvoicesController extends Controller | ||||
|      */ | ||||
|     public function store(Requests\InvoicesRequest $request) | ||||
|     { | ||||
|         $invoice_number = explode("-",$request->invoice_number); | ||||
|         $number_attributes['invoice_number'] = $invoice_number[0].'-'.sprintf('%06d', intval($invoice_number[1])); | ||||
|  | ||||
|         Validator::make($number_attributes, [ | ||||
|             'invoice_number' => 'required|unique:invoices,invoice_number' | ||||
|         ])->validate(); | ||||
|  | ||||
|         $invoice_date = Carbon::createFromFormat('d/m/Y', $request->invoice_date); | ||||
|         $due_date = Carbon::createFromFormat('d/m/Y', $request->due_date); | ||||
|         $status = Invoice::STATUS_DRAFT; | ||||
| @ -99,7 +114,7 @@ class InvoicesController extends Controller | ||||
|         $invoice = Invoice::create([ | ||||
|             'invoice_date' => $invoice_date, | ||||
|             'due_date' => $due_date, | ||||
|             'invoice_number' => $request->invoice_number, | ||||
|             'invoice_number' => $number_attributes['invoice_number'], | ||||
|             'reference_number' => $request->reference_number, | ||||
|             'user_id' => $request->user_id, | ||||
|             'company_id' => $request->header('company'), | ||||
| @ -222,12 +237,13 @@ class InvoicesController extends Controller | ||||
|         ])->find($id); | ||||
|  | ||||
|         return response()->json([ | ||||
|             'nextInvoiceNumber' => $invoice->invoice_number, | ||||
|             'nextInvoiceNumber' => $invoice->getInvoiceNumAttribute(), | ||||
|             'invoice' => $invoice, | ||||
|             'invoiceTemplates' => InvoiceTemplate::all(), | ||||
|             'tax_per_item' => $invoice->tax_per_item, | ||||
|             'discount_per_item' => $invoice->discount_per_item, | ||||
|             'shareable_link' => url('/invoices/pdf/'.$invoice->unique_hash) | ||||
|             'shareable_link' => url('/invoices/pdf/'.$invoice->unique_hash), | ||||
|             'invoice_prefix' => $invoice->getInvoicePrefixAttribute() | ||||
|         ]); | ||||
|     } | ||||
|  | ||||
| @ -240,6 +256,13 @@ class InvoicesController extends Controller | ||||
|      */ | ||||
|     public function update(Requests\InvoicesRequest $request, $id) | ||||
|     { | ||||
|         $invoice_number = explode("-",$request->invoice_number); | ||||
|         $number_attributes['invoice_number'] = $invoice_number[0].'-'.sprintf('%06d', intval($invoice_number[1])); | ||||
|  | ||||
|         Validator::make($number_attributes, [ | ||||
|             'invoice_number' => 'required|unique:invoices,invoice_number'.','.$id | ||||
|         ])->validate(); | ||||
|  | ||||
|         $invoice_date = Carbon::createFromFormat('d/m/Y', $request->invoice_date); | ||||
|         $due_date = Carbon::createFromFormat('d/m/Y', $request->due_date); | ||||
|  | ||||
| @ -268,7 +291,7 @@ class InvoicesController extends Controller | ||||
|  | ||||
|         $invoice->invoice_date = $invoice_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->user_id = $request->user_id; | ||||
|         $invoice->invoice_template_id = $request->invoice_template_id; | ||||
|  | ||||
| @ -10,6 +10,7 @@ use Carbon\Carbon; | ||||
| use function MongoDB\BSON\toJSON; | ||||
| use Crater\User; | ||||
| use Crater\Http\Requests\PaymentRequest; | ||||
| use Validator; | ||||
|  | ||||
| class PaymentController extends Controller | ||||
| { | ||||
| @ -50,13 +51,22 @@ class PaymentController extends Controller | ||||
|      */ | ||||
|     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; | ||||
|  | ||||
|         if ($payment_num_auto_generate == "YES") { | ||||
|             $nextPaymentNumberAttribute = Payment::getNextPaymentNumber($payment_prefix); | ||||
|         } | ||||
|  | ||||
|         return response()->json([ | ||||
|             'customers' => User::where('role', 'customer') | ||||
|                 ->whereCompany($request->header('company')) | ||||
|                 ->get(), | ||||
|             'nextPaymentNumber' => $nextPaymentNumber | ||||
|             'nextPaymentNumber' => $nextPaymentNumberAttribute, | ||||
|             'payment_prefix' => $payment_prefix | ||||
|         ]); | ||||
|     } | ||||
|  | ||||
| @ -68,6 +78,13 @@ class PaymentController extends Controller | ||||
|      */ | ||||
|     public function store(PaymentRequest $request) | ||||
|     { | ||||
|         $payment_number = explode("-",$request->payment_number); | ||||
|         $number_attributes['payment_number'] = $payment_number[0].'-'.sprintf('%06d', intval($payment_number[1])); | ||||
|  | ||||
|         Validator::make($number_attributes, [ | ||||
|             'payment_number' => 'required|unique:payments,payment_number' | ||||
|         ])->validate(); | ||||
|  | ||||
|         $payment_date = Carbon::createFromFormat('d/m/Y', $request->payment_date); | ||||
|  | ||||
|         if ($request->has('invoice_id') && $request->invoice_id != null) { | ||||
| @ -90,7 +107,7 @@ class PaymentController extends Controller | ||||
|  | ||||
|         $payment = Payment::create([ | ||||
|             'payment_date' => $payment_date, | ||||
|             'payment_number' => $request->payment_number, | ||||
|             'payment_number' => $number_attributes['payment_number'], | ||||
|             'user_id' => $request->user_id, | ||||
|             'company_id' => $request->header('company'), | ||||
|             'invoice_id' => $request->invoice_id, | ||||
| @ -135,7 +152,8 @@ class PaymentController extends Controller | ||||
|             'customers' => User::where('role', 'customer') | ||||
|                 ->whereCompany($request->header('company')) | ||||
|                 ->get(), | ||||
|             'nextPaymentNumber' => $payment->payment_number, | ||||
|             'nextPaymentNumber' => $payment->getPaymentNumAttribute(), | ||||
|             'payment_prefix' => $payment->getPaymentPrefixAttribute(), | ||||
|             'payment' => $payment, | ||||
|             'invoices' => $invoices | ||||
|         ]); | ||||
| @ -150,6 +168,13 @@ class PaymentController extends Controller | ||||
|      */ | ||||
|     public function update(PaymentRequest $request, $id) | ||||
|     { | ||||
|         $payment_number = explode("-",$request->payment_number); | ||||
|         $number_attributes['payment_number'] = $payment_number[0].'-'.sprintf('%06d', intval($payment_number[1])); | ||||
|  | ||||
|         Validator::make($number_attributes, [ | ||||
|             'payment_number' => 'required|unique:payments,payment_number'.','.$id | ||||
|         ])->validate(); | ||||
|  | ||||
|         $payment_date = Carbon::createFromFormat('d/m/Y', $request->payment_date); | ||||
|  | ||||
|         $payment = Payment::find($id); | ||||
| @ -178,7 +203,7 @@ class PaymentController extends Controller | ||||
|         } | ||||
|  | ||||
|         $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->invoice_id = $request->invoice_id; | ||||
|         $payment->payment_mode = $request->payment_mode; | ||||
|  | ||||
| @ -66,10 +66,14 @@ class Invoice extends Model | ||||
|         'formattedDueDate' | ||||
|     ]; | ||||
|  | ||||
|     public static function getNextInvoiceNumber() | ||||
|     public static function getNextInvoiceNumber($value) | ||||
|     { | ||||
|         // 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) { | ||||
|             // 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. | ||||
| @ -143,10 +147,15 @@ class Invoice extends Model | ||||
|  | ||||
|     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); | ||||
|     } | ||||
|  | ||||
|     public function getInvoicePrefixAttribute () { | ||||
|         $prefix = explode("-", $this->invoice_number)[0]; | ||||
|         return $prefix; | ||||
|     } | ||||
|  | ||||
|     public function getFormattedCreatedAtAttribute($value) | ||||
|     { | ||||
|         $dateFormat = CompanySetting::getSetting('carbon_date_format', $this->company_id); | ||||
|  | ||||
| @ -32,10 +32,34 @@ class Payment extends Model | ||||
|         '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 | ||||
|         $payment = Payment::orderBy('created_at', 'desc')->first(); | ||||
|         $payment = Payment::where('payment_number', 'LIKE', $value . '-%') | ||||
|                     ->orderBy('created_at', 'desc') | ||||
|                     ->first(); | ||||
|         if (!$payment) { | ||||
|             // 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. | ||||
| @ -54,6 +78,13 @@ class Payment extends Model | ||||
|         return sprintf('%06d', intval($number) + 1); | ||||
|     } | ||||
|  | ||||
|     public function getPaymentPrefixAttribute () | ||||
|     { | ||||
|         $prefix= explode("-",$this->payment_number)[0]; | ||||
|         return $prefix; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     public function invoice() | ||||
|     { | ||||
|         return $this->belongsTo(Invoice::class); | ||||
|  | ||||
							
								
								
									
										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 BaseLoader from './BaseLoader.vue' | ||||
| import BaseCustomerSelect from './BaseCustomerSelect.vue' | ||||
| import BasePrefixInput from './BasePrefixInput.vue' | ||||
|  | ||||
| import BasePopup from './popup/BasePopup.vue' | ||||
| import CustomerSelectPopup from './popup/CustomerSelectPopup.vue' | ||||
| @ -23,6 +24,7 @@ Vue.component('base-input', BaseInput) | ||||
| Vue.component('base-switch', BaseSwitch) | ||||
| Vue.component('base-text-area', BaseTextArea) | ||||
| Vue.component('base-loader', BaseLoader) | ||||
| Vue.component('base-prefix-input', BasePrefixInput) | ||||
|  | ||||
| Vue.component('table-component', TableComponent) | ||||
| Vue.component('table-column', TableColumn) | ||||
|  | ||||
| @ -124,7 +124,7 @@ export default { | ||||
|       }, | ||||
|       percent: { | ||||
|         required, | ||||
|         between: between(0.10, 100) | ||||
|         between: between(-1, 100) | ||||
|       }, | ||||
|       description: { | ||||
|         maxLength: maxLength(255) | ||||
|  | ||||
| @ -127,14 +127,15 @@ | ||||
|           <div class="row mt-4"> | ||||
|             <div class="col collapse-input"> | ||||
|               <label>{{ $t('estimates.estimate_number') }}<span class="text-danger"> * </span></label> | ||||
|               <base-input | ||||
|                 :invalid="$v.newEstimate.estimate_number.$error" | ||||
|                 :read-only="true" | ||||
|                 v-model="newEstimate.estimate_number" | ||||
|               <base-prefix-input | ||||
|                 v-model="estimateNumAttribute" | ||||
|                 :invalid="$v.estimateNumAttribute.$error" | ||||
|                 :prefix="estimatePrefix" | ||||
|                 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 class="col collapse-input"> | ||||
|               <label>{{ $t('estimates.ref_number') }}</label> | ||||
| @ -320,7 +321,7 @@ import { validationMixin } from 'vuelidate' | ||||
| import Guid from 'guid' | ||||
| import TaxStub from '../../stub/tax' | ||||
| import Tax from './EstimateTax' | ||||
| const { required, between, maxLength } = require('vuelidate/lib/validators') | ||||
| const { required, between, maxLength, numeric } = require('vuelidate/lib/validators') | ||||
|  | ||||
| export default { | ||||
|   components: { | ||||
| @ -361,7 +362,9 @@ export default { | ||||
|       discountPerItem: null, | ||||
|       initLoading: false, | ||||
|       isLoading: false, | ||||
|       maxDiscount: 0 | ||||
|       maxDiscount: 0, | ||||
|       estimatePrefix: null, | ||||
|       estimateNumAttribute: null | ||||
|     } | ||||
|   }, | ||||
|   validations () { | ||||
| @ -373,9 +376,6 @@ export default { | ||||
|         expiry_date: { | ||||
|           required | ||||
|         }, | ||||
|         estimate_number: { | ||||
|           required | ||||
|         }, | ||||
|         discount_val: { | ||||
|           between: between(0, this.subtotal) | ||||
|         }, | ||||
| @ -388,6 +388,10 @@ export default { | ||||
|       }, | ||||
|       selectedCustomer: { | ||||
|         required | ||||
|       }, | ||||
|       estimateNumAttribute: { | ||||
|         required, | ||||
|         numeric | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
| @ -559,6 +563,8 @@ export default { | ||||
|           this.taxPerItem = response.data.tax_per_item | ||||
|           this.selectedCurrency = this.defaultCurrency | ||||
|           this.estimateTemplates = response.data.estimateTemplates | ||||
|           this.estimatePrefix = response.data.estimate_prefix | ||||
|           this.estimateNumAttribute = response.data.nextEstimateNumber | ||||
|         } | ||||
|         this.initLoading = false | ||||
|         return | ||||
| @ -574,8 +580,9 @@ export default { | ||||
|         let today = new Date() | ||||
|         this.newEstimate.estimate_date = moment(today).toString() | ||||
|         this.newEstimate.expiry_date = moment(today).add(7, 'days').toString() | ||||
|         this.newEstimate.estimate_number = response.data.nextEstimateNumber | ||||
|         this.itemList = response.data.items | ||||
|         this.estimatePrefix = response.data.estimate_prefix | ||||
|         this.estimateNumAttribute = response.data.nextEstimateNumber | ||||
|       } | ||||
|       this.initLoading = false | ||||
|     }, | ||||
| @ -604,6 +611,7 @@ export default { | ||||
|       } | ||||
|  | ||||
|       this.isLoading = true | ||||
|       this.newEstimate.estimate_number = this.estimatePrefix + '-' + this.estimateNumAttribute | ||||
|  | ||||
|       let data = { | ||||
|         ...this.newEstimate, | ||||
| @ -637,7 +645,11 @@ export default { | ||||
|         this.isLoading = false | ||||
|       }).catch((err) => { | ||||
|         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) { | ||||
| @ -650,7 +662,11 @@ export default { | ||||
|         this.isLoading = false | ||||
|       }).catch((err) => { | ||||
|         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) { | ||||
|  | ||||
| @ -127,14 +127,15 @@ | ||||
|           <div class="row mt-4"> | ||||
|             <div class="col collapse-input"> | ||||
|               <label>{{ $t('invoices.invoice_number') }}<span class="text-danger"> * </span></label> | ||||
|               <base-input | ||||
|                 :invalid="$v.newInvoice.invoice_number.$error" | ||||
|                 :read-only="true" | ||||
|                 v-model="newInvoice.invoice_number" | ||||
|               <base-prefix-input | ||||
|                 v-model="invoiceNumAttribute" | ||||
|                 :invalid="$v.invoiceNumAttribute.$error" | ||||
|                 :prefix="invoicePrefix" | ||||
|                 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 class="col collapse-input"> | ||||
|               <label>{{ $t('invoices.ref_number') }}</label> | ||||
| @ -320,7 +321,7 @@ import { validationMixin } from 'vuelidate' | ||||
| import Guid from 'guid' | ||||
| import TaxStub from '../../stub/tax' | ||||
| import Tax from './InvoiceTax' | ||||
| const { required, between, maxLength } = require('vuelidate/lib/validators') | ||||
| const { required, between, maxLength, numeric } = require('vuelidate/lib/validators') | ||||
|  | ||||
| export default { | ||||
|   components: { | ||||
| @ -361,7 +362,9 @@ export default { | ||||
|       discountPerItem: null, | ||||
|       initLoading: false, | ||||
|       isLoading: false, | ||||
|       maxDiscount: 0 | ||||
|       maxDiscount: 0, | ||||
|       invoicePrefix: null, | ||||
|       invoiceNumAttribute: null | ||||
|     } | ||||
|   }, | ||||
|   validations () { | ||||
| @ -373,9 +376,6 @@ export default { | ||||
|         due_date: { | ||||
|           required | ||||
|         }, | ||||
|         invoice_number: { | ||||
|           required | ||||
|         }, | ||||
|         discount_val: { | ||||
|           between: between(0, this.subtotal) | ||||
|         }, | ||||
| @ -388,6 +388,10 @@ export default { | ||||
|       }, | ||||
|       selectedCustomer: { | ||||
|         required | ||||
|       }, | ||||
|       invoiceNumAttribute: { | ||||
|         required, | ||||
|         numeric | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
| @ -559,6 +563,8 @@ export default { | ||||
|           this.taxPerItem = response.data.tax_per_item | ||||
|           this.selectedCurrency = this.defaultCurrency | ||||
|           this.invoiceTemplates = response.data.invoiceTemplates | ||||
|           this.invoicePrefix = response.data.invoice_prefix | ||||
|           this.invoiceNumAttribute = response.data.nextInvoiceNumber | ||||
|         } | ||||
|         this.initLoading = false | ||||
|         return | ||||
| @ -574,8 +580,9 @@ export default { | ||||
|         let today = new Date() | ||||
|         this.newInvoice.invoice_date = moment(today).toString() | ||||
|         this.newInvoice.due_date = moment(today).add(7, 'days').toString() | ||||
|         this.newInvoice.invoice_number = response.data.nextInvoiceNumber | ||||
|         this.itemList = response.data.items | ||||
|         this.invoicePrefix = response.data.invoice_prefix | ||||
|         this.invoiceNumAttribute = response.data.nextInvoiceNumber | ||||
|       } | ||||
|       this.initLoading = false | ||||
|     }, | ||||
| @ -604,6 +611,7 @@ export default { | ||||
|       } | ||||
|  | ||||
|       this.isLoading = true | ||||
|       this.newInvoice.invoice_number = this.invoicePrefix + '-' + this.invoiceNumAttribute | ||||
|  | ||||
|       let data = { | ||||
|         ...this.newInvoice, | ||||
| @ -637,6 +645,10 @@ export default { | ||||
|         this.isLoading = false | ||||
|       }).catch((err) => { | ||||
|         this.isLoading = false | ||||
|         if (err.response.data.errors.invoice_number) { | ||||
|           window.toastr['error'](err.response.data.errors.invoice_number) | ||||
|           return true | ||||
|         } | ||||
|         console.log(err) | ||||
|       }) | ||||
|     }, | ||||
| @ -653,6 +665,10 @@ export default { | ||||
|         } | ||||
|       }).catch((err) => { | ||||
|         this.isLoading = false | ||||
|         if (err.response.data.errors.invoice_number) { | ||||
|           window.toastr['error'](err.response.data.errors.invoice_number) | ||||
|           return true | ||||
|         } | ||||
|         console.log(err) | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
| @ -40,16 +40,15 @@ | ||||
|             <div class="col-sm-6"> | ||||
|               <div class="form-group"> | ||||
|                 <label class="form-label">{{ $t('payments.payment_number') }}</label><span class="text-danger"> *</span> | ||||
|                 <base-input | ||||
|                   :invalid="$v.formData.payment_number.$error" | ||||
|                   v-model.trim="formData.payment_number" | ||||
|                   read-only | ||||
|                   type="text" | ||||
|                   name="email" | ||||
|                   @input="$v.formData.payment_number.$touch()" | ||||
|                 <base-prefix-input | ||||
|                   :invalid="$v.paymentNumAttribute.$error" | ||||
|                   v-model.trim="paymentNumAttribute" | ||||
|                   :prefix="paymentPrefix" | ||||
|                   @input="$v.paymentNumAttribute.$touch()" | ||||
|                 /> | ||||
|                 <div v-if="$v.formData.payment_number.$error"> | ||||
|                   <span v-if="!$v.formData.payment_number.required" class="text-danger">{{ $tc('validation.required') }}</span> | ||||
|                 <div v-if="$v.paymentNumAttribute.$error"> | ||||
|                   <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> | ||||
| @ -155,7 +154,7 @@ import { mapActions, mapGetters } from 'vuex' | ||||
| import MultiSelect from 'vue-multiselect' | ||||
| import { validationMixin } from 'vuelidate' | ||||
| import moment from 'moment' | ||||
| const { required, between, maxLength } = require('vuelidate/lib/validators') | ||||
| const { required, between, maxLength, numeric } = require('vuelidate/lib/validators') | ||||
|  | ||||
| export default { | ||||
|   components: { MultiSelect }, | ||||
| @ -184,7 +183,9 @@ export default { | ||||
|       invoiceList: [], | ||||
|       isLoading: false, | ||||
|       maxPayableAmount: Number.MAX_SAFE_INTEGER, | ||||
|       isSettingInitialData: true | ||||
|       isSettingInitialData: true, | ||||
|       paymentNumAttribute: null, | ||||
|       paymentPrefix: '' | ||||
|     } | ||||
|   }, | ||||
|   validations () { | ||||
| @ -193,9 +194,6 @@ export default { | ||||
|         required | ||||
|       }, | ||||
|       formData: { | ||||
|         payment_number: { | ||||
|           required | ||||
|         }, | ||||
|         payment_date: { | ||||
|           required | ||||
|         }, | ||||
| @ -206,6 +204,10 @@ export default { | ||||
|         notes: { | ||||
|           maxLength: maxLength(255) | ||||
|         } | ||||
|       }, | ||||
|       paymentNumAttribute: { | ||||
|         required, | ||||
|         numeric | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
| @ -297,6 +299,8 @@ export default { | ||||
|         this.customer = response.data.payment.user | ||||
|         this.formData.payment_date = moment(response.data.payment.payment_date, 'YYYY-MM-DD').toString() | ||||
|         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) { | ||||
|           this.maxPayableAmount = parseInt(response.data.payment.amount) + parseInt(response.data.payment.invoice.due_amount) | ||||
|           this.invoice = response.data.payment.invoice | ||||
| @ -305,7 +309,8 @@ export default { | ||||
|       } else { | ||||
|         let response = await this.fetchCreatePayment() | ||||
|         this.customerList = response.data.customers | ||||
|         this.formData.payment_number = response.data.nextPaymentNumber | ||||
|         this.paymentNumAttribute = response.data.nextPaymentNumber | ||||
|         this.paymentPrefix = response.data.payment_prefix | ||||
|         this.formData.payment_date = moment(new Date()).toString() | ||||
|       } | ||||
|       return true | ||||
| @ -332,6 +337,9 @@ export default { | ||||
|       if (this.$v.$invalid) { | ||||
|         return true | ||||
|       } | ||||
|  | ||||
|       this.formData.payment_number = this.paymentPrefix + '-' + this.paymentNumAttribute | ||||
|  | ||||
|       if (this.isEdit) { | ||||
|         let data = { | ||||
|           editData: { | ||||
| @ -340,6 +348,7 @@ export default { | ||||
|           }, | ||||
|           id: this.$route.params.id | ||||
|         } | ||||
|         try { | ||||
|           let response = await this.updatePayment(data) | ||||
|           if (response.data.success) { | ||||
|             window.toastr['success'](this.$t('payments.updated_message')) | ||||
| @ -351,12 +360,21 @@ export default { | ||||
|             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) | ||||
|         } | ||||
|       } else { | ||||
|         let data = { | ||||
|           ...this.formData, | ||||
|           payment_date: moment(this.formData.payment_date).format('DD/MM/YYYY') | ||||
|         } | ||||
|         this.isLoading = true | ||||
|         try { | ||||
|           let response = await this.addPayment(data) | ||||
|           if (response.data.success) { | ||||
|             window.toastr['success'](this.$t('payments.created_message')) | ||||
| @ -369,6 +387,14 @@ export default { | ||||
|             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) | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
| @ -14,7 +14,7 @@ | ||||
|       </ul> | ||||
|  | ||||
|       <!-- Invoices Tab --> | ||||
|       <transition name="fade"> | ||||
|       <transition name="fade-customize"> | ||||
|         <div v-if="activeTab === 'INVOICES'" class="invoice-tab"> | ||||
|           <form action="" class="form-section" @submit.prevent="updateInvoiceSetting"> | ||||
|             <div class="row"> | ||||
| @ -69,7 +69,7 @@ | ||||
|       </transition> | ||||
|  | ||||
|       <!-- Estimates Tab --> | ||||
|       <transition name="fade"> | ||||
|       <transition name="fade-customize"> | ||||
|         <div v-if="activeTab === 'ESTIMATES'" class="estimate-tab"> | ||||
|           <form action="" class="form-section" @submit.prevent="updateEstimateSetting"> | ||||
|             <div class="row"> | ||||
| @ -124,7 +124,7 @@ | ||||
|       </transition> | ||||
|  | ||||
|       <!-- Payments Tab --> | ||||
|       <transition name="fade"> | ||||
|       <transition name="fade-customize"> | ||||
|         <div v-if="activeTab === 'PAYMENTS'" class="payment-tab"> | ||||
|           <form action="" class="form-section" @submit.prevent="updatePaymentSetting"> | ||||
|             <div class="row"> | ||||
| @ -208,6 +208,9 @@ export default { | ||||
|     } | ||||
|   }, | ||||
|   watch: { | ||||
|     activeTab () { | ||||
|       this.loadData() | ||||
|     } | ||||
|   }, | ||||
|   validations: { | ||||
|     invoices: { | ||||
| @ -373,3 +376,16 @@ export default { | ||||
|   } | ||||
| } | ||||
| </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> | ||||
|  | ||||
							
								
								
									
										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; | ||||
|     } | ||||
| } | ||||
|  | ||||
							
								
								
									
										1
									
								
								resources/assets/sass/crater.scss
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								resources/assets/sass/crater.scss
									
									
									
									
										vendored
									
									
								
							| @ -48,6 +48,7 @@ | ||||
| @import 'components/base/base-text-area'; | ||||
| @import "components/base/base-switch"; | ||||
| @import 'components/base/base-loader/index'; | ||||
| @import 'components/base/base-prefix-input'; | ||||
|  | ||||
|  | ||||
| // Components | ||||
|  | ||||
		Reference in New Issue
	
	Block a user