Add invoice/estimate/payment number length setting (#425)

* Add invoice/estimate/payment number length setting
This commit is contained in:
Florian Gareis
2021-03-26 08:31:43 +01:00
committed by GitHub
parent 3f7db2793f
commit bfd9850bf6
15 changed files with 209 additions and 24 deletions

View File

@ -78,6 +78,10 @@ class Estimate extends Model implements HasMedia
->orderBy('estimate_number', 'desc') ->orderBy('estimate_number', 'desc')
->first(); ->first();
// Get number length config
$numberLength = CompanySetting::getSetting('estimate_number_length', request()->header('company'));
$numberLengthText = "%0{$numberLength}d";
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.
@ -94,7 +98,7 @@ class Estimate extends Model implements HasMedia
// the %05d part makes sure that there are always 6 numbers in the string. // the %05d part makes sure that there are always 6 numbers in the string.
// so it adds the missing zero's when needed. // so it adds the missing zero's when needed.
return sprintf('%06d', intval($number) + 1); return sprintf($numberLengthText, intval($number) + 1);
} }
public function emailLogs() public function emailLogs()

View File

@ -82,6 +82,9 @@ class Invoice extends Model implements HasMedia
->orderBy('invoice_number', 'desc') ->orderBy('invoice_number', 'desc')
->first(); ->first();
// Get number length config
$numberLength = CompanySetting::getSetting('invoice_number_length', request()->header('company'));
$numberLengthText = "%0{$numberLength}d";
if (!$lastOrder) { if (!$lastOrder) {
// We get here if there is no order at all // We get here if there is no order at all
@ -98,7 +101,7 @@ class Invoice extends Model implements HasMedia
// the %06d part makes sure that there are always 6 numbers in the string. // the %06d part makes sure that there are always 6 numbers in the string.
// so it adds the missing zero's when needed. // so it adds the missing zero's when needed.
return sprintf('%06d', intval($number) + 1); return sprintf($numberLengthText, intval($number) + 1);
} }
public function emailLogs() public function emailLogs()

View File

@ -271,6 +271,11 @@ class Payment extends Model implements HasMedia
$payment = Payment::where('payment_number', 'LIKE', $value . '-%') $payment = Payment::where('payment_number', 'LIKE', $value . '-%')
->orderBy('payment_number', 'desc') ->orderBy('payment_number', 'desc')
->first(); ->first();
// Get number length config
$numberLength = CompanySetting::getSetting('payment_number_length', request()->header('company'));
$numberLengthText = "%0{$numberLength}d";
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.
@ -286,7 +291,7 @@ class Payment extends Model implements HasMedia
// the %05d part makes sure that there are always 6 numbers in the string. // the %05d part makes sure that there are always 6 numbers in the string.
// so it adds the missing zero's when needed. // so it adds the missing zero's when needed.
return sprintf('%06d', intval($number) + 1); return sprintf($numberLengthText, intval($number) + 1);
} }
public function scopeWhereSearch($query, $search) public function scopeWhereSearch($query, $search)

View File

@ -0,0 +1,45 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Crater\Models\CompanySetting;
use Crater\Models\User;
class AddNumberLengthSetting extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
$user = User::where('role', 'super admin')->first();
if ($user) {
$invoice_number_length = CompanySetting::getSetting('invoice_number_length', $user->company_id);
if(empty($invoice_number_length)) {
CompanySetting::setSetting('invoice_number_length', '6', $user->company_id);
}
$estimate_number_length = CompanySetting::getSetting('estimate_number_length', $user->company_id);
if(empty($estimate_number_length)) {
CompanySetting::setSetting('estimate_number_length', '6', $user->company_id);
}
$payment_number_length = CompanySetting::getSetting('payment_number_length', $user->company_id);
if(empty($payment_number_length)) {
CompanySetting::setSetting('payment_number_length', '6', $user->company_id);
}
}
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
//
}
}

View File

@ -53,16 +53,19 @@ class DefaultSettingsSeeder extends Seeder
'notify_estimate_viewed' => 'NO', 'notify_estimate_viewed' => 'NO',
'tax_per_item' => 'NO', 'tax_per_item' => 'NO',
'discount_per_item' => 'NO', 'discount_per_item' => 'NO',
'invoice_auto_generate' => 'YES',
'invoice_prefix' => 'INV', 'invoice_prefix' => 'INV',
'invoice_auto_generate' => 'YES',
'invoice_number_length' => 6,
'invoice_email_attachment' => 'NO',
'estimate_prefix' => 'EST', 'estimate_prefix' => 'EST',
'estimate_auto_generate' => 'YES', 'estimate_auto_generate' => 'YES',
'estimate_number_length' => 6,
'estimate_email_attachment' => 'NO',
'payment_prefix' => 'PAY', 'payment_prefix' => 'PAY',
'payment_auto_generate' => 'YES', 'payment_auto_generate' => 'YES',
'save_pdf_to_disk' => 'NO', 'payment_number_length' => 6,
'invoice_email_attachment' => 'NO',
'estimate_email_attachment' => 'NO',
'payment_email_attachment' => 'NO', 'payment_email_attachment' => 'NO',
'save_pdf_to_disk' => 'NO',
]; ];
CompanySetting::setSettings($settings, $user->company_id); CompanySetting::setSettings($settings, $user->company_id);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,24 +1,24 @@
/*! /*!
* tiptap v1.29.6 * tiptap v1.30.0
* (c) 2020 überdosis GbR (limited liability) * (c) 2021 überdosis GbR (limited liability)
* @license MIT * @license MIT
*/ */
/*! /*!
* tiptap-commands v1.14.6 * tiptap-commands v1.15.0
* (c) 2020 überdosis GbR (limited liability) * (c) 2021 überdosis GbR (limited liability)
* @license MIT * @license MIT
*/ */
/*! /*!
* tiptap-extensions v1.33.1 * tiptap-extensions v1.33.2
* (c) 2020 überdosis GbR (limited liability) * (c) 2021 überdosis GbR (limited liability)
* @license MIT * @license MIT
*/ */
/*! /*!
* tiptap-utils v1.10.4 * tiptap-utils v1.11.0
* (c) 2020 überdosis GbR (limited liability) * (c) 2021 überdosis GbR (limited liability)
* @license MIT * @license MIT
*/ */

View File

@ -1,4 +1,4 @@
{ {
"/assets/js/app.js": "/assets/js/app.js?id=a1b33d55e1412b350c40", "/assets/js/app.js": "/assets/js/app.js?id=3dcc26feaf31d92ede7e",
"/assets/css/crater.css": "/assets/css/crater.css?id=d2ff90e64c851af08712" "/assets/css/crater.css": "/assets/css/crater.css?id=7a822f915d7e413148f6"
} }

View File

@ -750,6 +750,7 @@
"title": "Rechnungen", "title": "Rechnungen",
"notes": "Hinweise", "notes": "Hinweise",
"invoice_prefix": "Rechnung Präfix", "invoice_prefix": "Rechnung Präfix",
"invoice_number_length": "Rechnungsnummerlänge",
"default_invoice_email_body": "Standard Rechnung E-Mail Inhalt", "default_invoice_email_body": "Standard Rechnung E-Mail Inhalt",
"invoice_settings": "Rechnungseinstellungen", "invoice_settings": "Rechnungseinstellungen",
"autogenerate_invoice_number": "Rechnungsnummer automatisch generieren", "autogenerate_invoice_number": "Rechnungsnummer automatisch generieren",
@ -764,6 +765,7 @@
"estimates": { "estimates": {
"title": "Kostenvoranschläge", "title": "Kostenvoranschläge",
"estimate_prefix": "Kostenvoranschlag Präfix", "estimate_prefix": "Kostenvoranschlag Präfix",
"estimate_number_length": "Angebotsnummerlänge",
"default_estimate_email_body": "Rechnung - E-Mail Text", "default_estimate_email_body": "Rechnung - E-Mail Text",
"estimate_settings": "Einstellungen Kostenvoranschlag", "estimate_settings": "Einstellungen Kostenvoranschlag",
"autogenerate_estimate_number": "Kostenvoranschlagsnummer automatisch generieren", "autogenerate_estimate_number": "Kostenvoranschlagsnummer automatisch generieren",
@ -778,6 +780,7 @@
"title": "Zahlungen", "title": "Zahlungen",
"description": "Transaktionsmodi für Zahlungen", "description": "Transaktionsmodi für Zahlungen",
"payment_prefix": "Zahlung Präfix", "payment_prefix": "Zahlung Präfix",
"payment_number_length": "Zahlungsnummerlänge",
"default_payment_email_body": "Zahlung - E-Mail Text", "default_payment_email_body": "Zahlung - E-Mail Text",
"payment_settings": "Zahlung Einstellungen", "payment_settings": "Zahlung Einstellungen",
"autogenerate_payment_number": "Zahlungsnummer automatisch generieren", "autogenerate_payment_number": "Zahlungsnummer automatisch generieren",
@ -1139,7 +1142,8 @@
"address_maxlength": "Die Adresse sollte nicht länger als 255 Zeichen sein.", "address_maxlength": "Die Adresse sollte nicht länger als 255 Zeichen sein.",
"ref_number_maxlength": "Ref Number sollte nicht länger als 255 Zeichen sein.", "ref_number_maxlength": "Ref Number sollte nicht länger als 255 Zeichen sein.",
"prefix_maxlength": "Das Präfix sollte nicht länger als 5 Zeichen sein.", "prefix_maxlength": "Das Präfix sollte nicht länger als 5 Zeichen sein.",
"something_went_wrong": "Da ist etwas schief gelaufen" "something_went_wrong": "Da ist etwas schief gelaufen",
"number_length_minvalue": "Nummernlänge sollte größer als 0 sein"
}, },
"pdf_estimate_label": "Kostenvoranschlag", "pdf_estimate_label": "Kostenvoranschlag",
"pdf_estimate_number": "Kostenvoran. Nummer", "pdf_estimate_number": "Kostenvoran. Nummer",

View File

@ -751,6 +751,7 @@
"title": "Invoices", "title": "Invoices",
"notes": "Notes", "notes": "Notes",
"invoice_prefix": "Invoice Prefix", "invoice_prefix": "Invoice Prefix",
"invoice_number_length": "Invoice number length",
"default_invoice_email_body": "Default Invoice Email Body", "default_invoice_email_body": "Default Invoice Email Body",
"invoice_settings": "Invoice Settings", "invoice_settings": "Invoice Settings",
"autogenerate_invoice_number": "Auto-generate Invoice Number", "autogenerate_invoice_number": "Auto-generate Invoice Number",
@ -767,6 +768,7 @@
"estimates": { "estimates": {
"title": "Estimates", "title": "Estimates",
"estimate_prefix": "Estimate Prefix", "estimate_prefix": "Estimate Prefix",
"estimate_number_length": "Estimate number length",
"default_estimate_email_body": "Default Estimate Email Body", "default_estimate_email_body": "Default Estimate Email Body",
"estimate_settings": "Estimate Settings", "estimate_settings": "Estimate Settings",
"autogenerate_estimate_number": "Auto-generate Estimate Number", "autogenerate_estimate_number": "Auto-generate Estimate Number",
@ -783,6 +785,7 @@
"title": "Payments", "title": "Payments",
"description": "Modes of transaction for payments", "description": "Modes of transaction for payments",
"payment_prefix": "Payment Prefix", "payment_prefix": "Payment Prefix",
"payment_number_length": "Payment number lenght",
"default_payment_email_body": "Default Payment Email Body", "default_payment_email_body": "Default Payment Email Body",
"payment_settings": "Payment Settings", "payment_settings": "Payment Settings",
"autogenerate_payment_number": "Auto-generate Payment Number", "autogenerate_payment_number": "Auto-generate Payment Number",
@ -1148,7 +1151,8 @@
"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.", "prefix_maxlength": "Prefix should not be greater than 5 characters.",
"something_went_wrong": "something went wrong" "something_went_wrong": "something went wrong",
"number_length_minvalue": "Number lenght should be greater than 0"
}, },
"pdf_estimate_label": "Estimate", "pdf_estimate_label": "Estimate",
"pdf_estimate_number": "Estimate Number", "pdf_estimate_number": "Estimate Number",

View File

@ -61,14 +61,17 @@ export default {
'payment_auto_generate', 'payment_auto_generate',
'payment_email_attachment', 'payment_email_attachment',
'payment_prefix', 'payment_prefix',
'payment_number_length',
'payment_mail_body', 'payment_mail_body',
'invoice_auto_generate', 'invoice_auto_generate',
'invoice_email_attachment', 'invoice_email_attachment',
'invoice_prefix', 'invoice_prefix',
'invoice_number_length',
'invoice_mail_body', 'invoice_mail_body',
'estimate_auto_generate', 'estimate_auto_generate',
'estimate_email_attachment', 'estimate_email_attachment',
'estimate_prefix', 'estimate_prefix',
'estimate_number_length',
'estimate_mail_body', 'estimate_mail_body',
'invoice_billing_address_format', 'invoice_billing_address_format',
'invoice_shipping_address_format', 'invoice_shipping_address_format',

View File

@ -14,6 +14,19 @@
/> />
</sw-input-group> </sw-input-group>
<sw-input-group
:label="$t('settings.customization.estimates.estimate_number_length')"
:error="estimateNumberLengthError"
class="mt-6 mb-4"
>
<sw-input
v-model="estimates.estimate_number_length"
:invalid="$v.estimates.estimate_number_length.$error"
type="number"
style="max-width: 60px"
/>
</sw-input-group>
<sw-input-group <sw-input-group
:label=" :label="
$t('settings.customization.estimates.default_estimate_email_body') $t('settings.customization.estimates.default_estimate_email_body')
@ -127,7 +140,7 @@
<script> <script>
import { mapActions, mapGetters } from 'vuex' import { mapActions, mapGetters } from 'vuex'
const { required, maxLength, alpha } = require('vuelidate/lib/validators') const { required, maxLength, minValue, alpha, numeric } = require('vuelidate/lib/validators')
export default { export default {
props: { props: {
@ -145,6 +158,7 @@ export default {
estimates: { estimates: {
estimate_prefix: null, estimate_prefix: null,
estimate_number_length: null,
estimate_mail_body: null, estimate_mail_body: null,
estimate_terms_and_conditions: null, estimate_terms_and_conditions: null,
company_address_format: null, company_address_format: null,
@ -193,6 +207,23 @@ export default {
return this.$t('validation.characters_only') return this.$t('validation.characters_only')
} }
}, },
estimateNumberLengthError() {
if (!this.$v.estimates.estimate_number_length.$error) {
return ''
}
if (!this.$v.estimates.estimate_number_length.required) {
return this.$t('validation.required')
}
if (!this.$v.estimates.estimate_number_length.minValue) {
return this.$t('validation.number_length_minvalue')
}
if (!this.$v.estimates.estimate_number_length.numeric) {
return this.$t('validation.numbers_only')
}
},
}, },
validations: { validations: {
@ -202,12 +233,18 @@ export default {
maxLength: maxLength(5), maxLength: maxLength(5),
alpha, alpha,
}, },
estimate_number_length: {
required,
minValue: minValue(1),
numeric
},
}, },
}, },
watch: { watch: {
settings(val) { settings(val) {
this.estimates.estimate_prefix = val ? val.estimate_prefix : '' this.estimates.estimate_prefix = val ? val.estimate_prefix : ''
this.estimates.estimate_number_length = val ? val.estimate_number_length : ''
this.estimates.estimate_mail_body = val ? val.estimate_mail_body : '' this.estimates.estimate_mail_body = val ? val.estimate_mail_body : ''
this.estimates.company_address_format = val this.estimates.company_address_format = val
@ -275,6 +312,7 @@ export default {
let data = { let data = {
settings: { settings: {
estimate_prefix: this.estimates.estimate_prefix, estimate_prefix: this.estimates.estimate_prefix,
estimate_number_length: this.estimates.estimate_number_length,
estimate_mail_body: this.estimates.estimate_mail_body, estimate_mail_body: this.estimates.estimate_mail_body,
estimate_company_address_format: this.estimates estimate_company_address_format: this.estimates
.company_address_format, .company_address_format,

View File

@ -14,6 +14,19 @@
/> />
</sw-input-group> </sw-input-group>
<sw-input-group
:label="$t('settings.customization.invoices.invoice_number_length')"
:error="invoicenumberLengthError"
class="mt-6 mb-4"
>
<sw-input
v-model="invoices.invoice_number_length"
:invalid="$v.invoices.invoice_number_length.$error"
type="number"
style="max-width: 60px"
/>
</sw-input-group>
<sw-input-group <sw-input-group
:label=" :label="
$t('settings.customization.invoices.default_invoice_email_body') $t('settings.customization.invoices.default_invoice_email_body')
@ -132,7 +145,7 @@
</template> </template>
<script> <script>
const { required, maxLength, alpha } = require('vuelidate/lib/validators') const { required, maxLength, minValue, alpha, numeric } = require('vuelidate/lib/validators')
import { mapActions, mapGetters } from 'vuex' import { mapActions, mapGetters } from 'vuex'
export default { export default {
@ -151,6 +164,7 @@ export default {
invoices: { invoices: {
invoice_prefix: null, invoice_prefix: null,
invoice_number_length: null,
invoice_mail_body: null, invoice_mail_body: null,
company_address_format: null, company_address_format: null,
shipping_address_format: null, shipping_address_format: null,
@ -193,11 +207,29 @@ export default {
return this.$t('validation.characters_only') return this.$t('validation.characters_only')
} }
}, },
invoicenumberLengthError() {
if (!this.$v.invoices.invoice_number_length.$error) {
return ''
}
if (!this.$v.invoices.invoice_number_length.required) {
return this.$t('validation.required')
}
if (!this.$v.invoices.invoice_number_length.minValue) {
return this.$t('validation.number_length_minvalue')
}
if (!this.$v.invoices.invoice_number_length.numeric) {
return this.$t('validation.numbers_only')
}
},
}, },
watch: { watch: {
settings(val) { settings(val) {
this.invoices.invoice_prefix = val ? val.invoice_prefix : '' this.invoices.invoice_prefix = val ? val.invoice_prefix : ''
this.invoices.invoice_number_length = val ? val.invoice_number_length : ''
this.invoices.invoice_mail_body = val ? val.invoice_mail_body : null this.invoices.invoice_mail_body = val ? val.invoice_mail_body : null
this.invoices.company_address_format = val this.invoices.company_address_format = val
@ -235,6 +267,11 @@ export default {
maxLength: maxLength(5), maxLength: maxLength(5),
alpha, alpha,
}, },
invoice_number_length: {
required,
minValue: minValue(1),
numeric
},
}, },
}, },
@ -274,6 +311,7 @@ export default {
let data = { let data = {
settings: { settings: {
invoice_prefix: this.invoices.invoice_prefix, invoice_prefix: this.invoices.invoice_prefix,
invoice_number_length: this.invoices.invoice_number_length,
invoice_mail_body: this.invoices.invoice_mail_body, invoice_mail_body: this.invoices.invoice_mail_body,
invoice_company_address_format: this.invoices.company_address_format, invoice_company_address_format: this.invoices.company_address_format,
invoice_billing_address_format: this.invoices.billing_address_format, invoice_billing_address_format: this.invoices.billing_address_format,

View File

@ -15,6 +15,19 @@
/> />
</sw-input-group> </sw-input-group>
<sw-input-group
:label="$t('settings.customization.payments.payment_number_length')"
:error="paymentnumberLengthError"
class="mt-6 mb-4"
>
<sw-input
v-model="payments.payment_number_length"
:invalid="$v.payments.payment_number_length.$error"
type="number"
style="max-width: 60px"
/>
</sw-input-group>
<sw-input-group <sw-input-group
:label=" :label="
$t('settings.customization.payments.default_payment_email_body') $t('settings.customization.payments.default_payment_email_body')
@ -121,7 +134,7 @@
</template> </template>
<script> <script>
import { mapActions, mapGetters } from 'vuex' import { mapActions, mapGetters } from 'vuex'
const { required, maxLength, alpha } = require('vuelidate/lib/validators') const { required, maxLength, minValue, alpha, numeric } = require('vuelidate/lib/validators')
export default { export default {
props: { props: {
@ -139,6 +152,7 @@ export default {
payments: { payments: {
payment_prefix: null, payment_prefix: null,
payment_number_length: null,
payment_mail_body: null, payment_mail_body: null,
from_customer_address_format: null, from_customer_address_format: null,
company_address_format: null, company_address_format: null,
@ -179,6 +193,23 @@ export default {
return this.$t('validation.characters_only') return this.$t('validation.characters_only')
} }
}, },
paymentnumberLengthError() {
if (!this.$v.payments.payment_number_length.$error) {
return ''
}
if (!this.$v.payments.payment_number_length.required) {
return this.$t('validation.required')
}
if (!this.$v.payments.payment_number_length.minValue) {
return this.$t('validation.number_length_minvalue')
}
if (!this.$v.payments.payment_number_length.numeric) {
return this.$t('validation.numbers_only')
}
},
}, },
validations: { validations: {
@ -188,12 +219,18 @@ export default {
maxLength: maxLength(5), maxLength: maxLength(5),
alpha, alpha,
}, },
payment_number_length: {
required,
minValue: minValue(1),
numeric
},
}, },
}, },
watch: { watch: {
settings(val) { settings(val) {
this.payments.payment_prefix = val ? val.payment_prefix : '' this.payments.payment_prefix = val ? val.payment_prefix : ''
this.payments.payment_number_length = val ? val.payment_number_length : ''
this.payments.payment_mail_body = val ? val.payment_mail_body : '' this.payments.payment_mail_body = val ? val.payment_mail_body : ''
@ -258,6 +295,7 @@ export default {
let data = { let data = {
settings: { settings: {
payment_prefix: this.payments.payment_prefix, payment_prefix: this.payments.payment_prefix,
payment_number_length: this.payments.payment_number_length,
payment_mail_body: this.payments.payment_mail_body, payment_mail_body: this.payments.payment_mail_body,
payment_company_address_format: this.payments.company_address_format, payment_company_address_format: this.payments.company_address_format,
payment_from_customer_address_format: this.payments payment_from_customer_address_format: this.payments