Add Company VAT-ID and Tax-ID (#54)

* add company vat_id & tax_id field

* add tax & vat id field in company settings

* fix vat & tax id validation

* add german vat & tax id translation

* add translations for pdf

* add vat_id and tax_id field before timestamps

* make fields nullable and fix code style
This commit is contained in:
Timo
2024-04-20 23:08:32 +02:00
committed by GitHub
parent dc8a85538f
commit 8c83df558c
8 changed files with 94 additions and 26 deletions

View File

@@ -69,6 +69,8 @@ class CompaniesRequest extends FormRequest
return collect($this->validated())
->only([
'name',
'vat_id',
'tax_id',
])
->merge([
'owner_id' => $this->user()->id,

View File

@@ -29,6 +29,12 @@ class CompanyRequest extends FormRequest
'required',
Rule::unique('companies')->ignore($this->header('company'), 'id'),
],
'vat_id' => [
'nullable',
],
'tax_id' => [
'nullable',
],
'slug' => [
'nullable',
],
@@ -44,6 +50,8 @@ class CompanyRequest extends FormRequest
->only([
'name',
'slug',
'vat_id',
'tax_id',
])
->toArray();
}

View File

@@ -17,6 +17,8 @@ class CompanyResource extends JsonResource
return [
'id' => $this->id,
'name' => $this->name,
'vat_id' => $this->vat_id,
'tax_id' => $this->tax_id,
'logo' => $this->logo,
'logo_path' => $this->logo_path,
'unique_hash' => $this->unique_hash,

View File

@@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('companies', function (Blueprint $table) {
$table->after('unique_hash', function (Blueprint $table) {
$table->string('vat_id')->nullable();
$table->string('tax_id')->nullable();
});
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('companies', function (Blueprint $table) {
$table->dropColumn('vat_id');
$table->dropColumn('tax_id');
});
}
};

View File

@@ -863,6 +863,8 @@
"company_info": {
"company_info": "Firmeninfo",
"company_name": "Name des Unternehmens",
"vat_id": "Umsatzsteuer-Identifikationsnummer",
"tax_id": "Steuernummer",
"company_logo": "Firmenlogo",
"section_description": "Informationen zu Ihrem Unternehmen, die auf Rechnungen, Angeboten und anderen von InvoiceShelf erstellten Dokumenten angezeigt werden.",
"phone": "Telefon",
@@ -1528,5 +1530,7 @@
"pdf_bill_to": "Rechnungsanschrift",
"pdf_ship_to": "Lieferanschrift",
"pdf_received_from": "Erhalten von:",
"pdf_tax_label": "Steuer"
"pdf_tax_label": "Steuer",
"pdf_tax_id": "Steuer-Nr.",
"pdf_vat_id": "USt.-ID"
}

View File

@@ -863,6 +863,8 @@
"company_info": {
"company_info": "Company info",
"company_name": "Company Name",
"tax_id": "Tax Identification Number",
"vat_id": "VAT Identification Number",
"company_logo": "Company Logo",
"section_description": "Information about your company that will be displayed on invoices, estimates and other documents created by InvoiceShelf.",
"phone": "Phone",
@@ -1528,5 +1530,7 @@
"pdf_bill_to": "Bill to,",
"pdf_ship_to": "Ship to,",
"pdf_received_from": "Received from:",
"pdf_tax_label": "Tax"
"pdf_tax_label": "Tax",
"pdf_tax_id": "Tax-ID",
"pdf_vat_id": "VAT-ID"
}

View File

@@ -131,6 +131,25 @@
/>
</BaseInputGroup>
</div>
<BaseInputGroup :label="$t('settings.company_info.tax_id')">
<BaseInput
v-model.trim="companyForm.tax_id"
type="text"
name="tax_id"
/>
</BaseInputGroup>
<BaseInputGroup
:label="$t('settings.company_info.vat_id')"
class="mt-4"
>
<BaseInput
v-model.trim="companyForm.vat_id"
type="text"
name="vat_id"
/>
</BaseInputGroup>
</div>
<BaseButton :loading="isSaving" :disabled="isSaving" class="mt-4">
@@ -162,6 +181,8 @@ let logoFileName = ref(null)
const companyForm = reactive({
name: null,
tax_id: null,
vat_id: null,
address: {
address_street_1: '',
address_street_2: '',
@@ -200,13 +221,13 @@ const rules = {
address_street_1: {
maxLength: helpers.withMessage(
t('validation.address_maxlength', { count: 255 }),
maxLength(255)
maxLength(255),
),
},
address_street_2: {
maxLength: helpers.withMessage(
t('validation.address_maxlength', { count: 255 }),
maxLength(255)
maxLength(255),
),
},
},
@@ -241,7 +262,7 @@ async function next() {
JSON.stringify({
name: logoFileName.value,
data: logoFileBlob.value,
})
}),
)
await companyStore.updateCompanyLogo(logoData)
}

View File

@@ -84,6 +84,16 @@
class="mt-2"
/>
</div>
<div class="space-y-6">
<BaseInputGroup :label="$t('settings.company_info.tax_id')">
<BaseInput v-model="companyForm.tax_id" type="text" />
</BaseInputGroup>
<BaseInputGroup :label="$t('settings.company_info.vat_id')">
<BaseInput v-model="companyForm.vat_id" type="text" />
</BaseInputGroup>
</div>
</BaseInputGrid>
<BaseButton
@@ -111,24 +121,7 @@
<div class="mt-5">
<button
type="button"
class="
inline-flex
items-center
justify-center
px-4
py-2
border border-transparent
font-medium
rounded-md
text-red-700
bg-red-100
hover:bg-red-200
focus:outline-none
focus:ring-2
focus:ring-offset-2
focus:ring-red-500
sm:text-sm
"
class="inline-flex items-center justify-center px-4 py-2 border border-transparent font-medium rounded-md text-red-700 bg-red-100 hover:bg-red-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:text-sm"
@click="removeCompany"
>
{{ $t('general.delete') }}
@@ -161,6 +154,8 @@ let isSaving = ref(false)
const companyForm = reactive({
name: null,
logo: null,
tax_id: null,
vat_id: null,
address: {
address_street_1: '',
address_street_2: '',
@@ -194,7 +189,7 @@ const rules = computed(() => {
required: helpers.withMessage(t('validation.required'), required),
minLength: helpers.withMessage(
t('validation.name_min_length'),
minLength(3)
minLength(3),
),
},
address: {
@@ -207,7 +202,7 @@ const rules = computed(() => {
const v$ = useVuelidate(
rules,
computed(() => companyForm)
computed(() => companyForm),
)
globalStore.fetchCountries()
@@ -243,7 +238,7 @@ async function updateCompanyData() {
JSON.stringify({
name: logoFileName.value,
data: logoFileBlob.value,
})
}),
)
}
logoData.append('is_company_logo_removed', isCompanyLogoRemoved.value)