diff --git a/app/Estimate.php b/app/Estimate.php index 08fd7aaf..4caf953b 100644 --- a/app/Estimate.php +++ b/app/Estimate.php @@ -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(); + // Get the last created order + $lastOrder = Estimate::where('estimate_number', 'LIKE', $value . '-%') + ->orderBy('created_at', 'desc') + ->first(); + if (!$lastOrder) { // We get here if there is no order at all // If there is no number set it to 0, which will be 1 at the end. @@ -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') { diff --git a/app/Http/Controllers/CompanyController.php b/app/Http/Controllers/CompanyController.php index ffefaf6e..845e8cad 100644 --- a/app/Http/Controllers/CompanyController.php +++ b/app/Http/Controllers/CompanyController.php @@ -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 = [ diff --git a/app/Http/Controllers/EstimatesController.php b/app/Http/Controllers/EstimatesController.php index 3312842d..1dec2420 100644 --- a/app/Http/Controllers/EstimatesController.php +++ b/app/Http/Controllers/EstimatesController.php @@ -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; diff --git a/app/Http/Controllers/InvoicesController.php b/app/Http/Controllers/InvoicesController.php index da97751f..b22eb111 100644 --- a/app/Http/Controllers/InvoicesController.php +++ b/app/Http/Controllers/InvoicesController.php @@ -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; diff --git a/app/Http/Controllers/PaymentController.php b/app/Http/Controllers/PaymentController.php index cf7f1377..ffe3582c 100644 --- a/app/Http/Controllers/PaymentController.php +++ b/app/Http/Controllers/PaymentController.php @@ -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; diff --git a/app/Invoice.php b/app/Invoice.php index ac578015..3c01cea3 100644 --- a/app/Invoice.php +++ b/app/Invoice.php @@ -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); diff --git a/app/Payment.php b/app/Payment.php index 18acae84..64cd7799 100644 --- a/app/Payment.php +++ b/app/Payment.php @@ -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); diff --git a/resources/assets/js/components/base/BasePrefixInput.vue b/resources/assets/js/components/base/BasePrefixInput.vue new file mode 100644 index 00000000..bb323e52 --- /dev/null +++ b/resources/assets/js/components/base/BasePrefixInput.vue @@ -0,0 +1,71 @@ + + + diff --git a/resources/assets/js/components/base/index.js b/resources/assets/js/components/base/index.js index 06ec517f..f185d564 100644 --- a/resources/assets/js/components/base/index.js +++ b/resources/assets/js/components/base/index.js @@ -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) diff --git a/resources/assets/js/components/base/modal/TaxTypeModal.vue b/resources/assets/js/components/base/modal/TaxTypeModal.vue index 587139f1..7461cee9 100644 --- a/resources/assets/js/components/base/modal/TaxTypeModal.vue +++ b/resources/assets/js/components/base/modal/TaxTypeModal.vue @@ -124,7 +124,7 @@ export default { }, percent: { required, - between: between(0.10, 100) + between: between(-1, 100) }, description: { maxLength: maxLength(255) diff --git a/resources/assets/js/views/estimates/Create.vue b/resources/assets/js/views/estimates/Create.vue index 1e8e84bd..a8cbfddf 100644 --- a/resources/assets/js/views/estimates/Create.vue +++ b/resources/assets/js/views/estimates/Create.vue @@ -127,14 +127,15 @@
- - {{ $tc('estimates.errors.required') }} + {{ $tc('estimates.errors.required') }} + {{ $tc('validation.numbers_only') }}
@@ -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) { diff --git a/resources/assets/js/views/invoices/Create.vue b/resources/assets/js/views/invoices/Create.vue index efa95891..05368043 100644 --- a/resources/assets/js/views/invoices/Create.vue +++ b/resources/assets/js/views/invoices/Create.vue @@ -127,14 +127,15 @@
- - {{ $tc('validation.required') }} + {{ $tc('validation.required') }} + {{ $tc('validation.numbers_only') }}
@@ -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) }) }, diff --git a/resources/assets/js/views/payments/Create.vue b/resources/assets/js/views/payments/Create.vue index cfcd1599..8140ea23 100644 --- a/resources/assets/js/views/payments/Create.vue +++ b/resources/assets/js/views/payments/Create.vue @@ -40,16 +40,15 @@
* - -
- {{ $tc('validation.required') }} +
+ {{ $tc('validation.required') }} + {{ $tc('validation.numbers_only') }}
@@ -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,35 +348,53 @@ export default { }, id: this.$route.params.id } - let response = await this.updatePayment(data) - if (response.data.success) { - window.toastr['success'](this.$t('payments.updated_message')) - this.$router.push('/admin/payments') - return true + try { + let response = await this.updatePayment(data) + if (response.data.success) { + window.toastr['success'](this.$t('payments.updated_message')) + 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 { let data = { ...this.formData, payment_date: moment(this.formData.payment_date).format('DD/MM/YYYY') } this.isLoading = true - let response = await this.addPayment(data) - if (response.data.success) { - window.toastr['success'](this.$t('payments.created_message')) - this.$router.push('/admin/payments') - this.isLoading = true - return true + try { + let response = await this.addPayment(data) + if (response.data.success) { + window.toastr['success'](this.$t('payments.created_message')) + this.$router.push('/admin/payments') + 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) } } } diff --git a/resources/assets/js/views/settings/Customization.vue b/resources/assets/js/views/settings/Customization.vue index cb8f55b8..6cca942a 100644 --- a/resources/assets/js/views/settings/Customization.vue +++ b/resources/assets/js/views/settings/Customization.vue @@ -14,7 +14,7 @@ - +
@@ -69,7 +69,7 @@ - +
@@ -124,7 +124,7 @@ - +
@@ -208,6 +208,9 @@ export default { } }, watch: { + activeTab () { + this.loadData() + } }, validations: { invoices: { @@ -373,3 +376,16 @@ export default { } } + diff --git a/resources/assets/sass/components/base/base-prefix-input.scss b/resources/assets/sass/components/base/base-prefix-input.scss new file mode 100644 index 00000000..5bf55aae --- /dev/null +++ b/resources/assets/sass/components/base/base-prefix-input.scss @@ -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; + } +} + diff --git a/resources/assets/sass/crater.scss b/resources/assets/sass/crater.scss index cd4645a9..034912fe 100644 --- a/resources/assets/sass/crater.scss +++ b/resources/assets/sass/crater.scss @@ -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