contract create view

shift-build-2464
Nadim Salloum 2021-06-04 18:51:04 +03:00
parent ef36a3df5e
commit db4f29d0f7
24 changed files with 2337 additions and 1055 deletions

View File

@ -15,7 +15,19 @@ class BrandController extends Controller
*/ */
public function index() public function index()
{ {
// return Brand::all()->map(function ($brand) {
return [
'id' => $brand->id,
'name' => $brand->name,
'models' => $brand->carModels()->get()
->map(function ($carModel) {
return [
'id' => $carModel->id,
'name' => $carModel->name,
];
}),
];
});
} }
/** /**

View File

@ -184,21 +184,44 @@ class CarController extends Controller
public function store(Request $request) public function store(Request $request)
{ {
$car = Car::create( $car = Car::create(
$request->validate([ $request->validate($this->getValidationRules())
'stammnummer' => ['required', 'unique:cars', 'string', 'size:11', 'regex:/[0-9]{3}[.][0-9]{3}[.][0-9]{3}/i'],
'vin' => ['required', 'unique:cars', 'string', 'size:17'],
'initial_date' => ['required', 'date'],
'last_check_date' => ['required', 'date'],
'colour' => ['nullable', 'max:75'],
'car_model_id' => ['required', 'exists:App\Models\CarModel,id'],
'kilometers' => ['required', 'max:75'],
'known_damage' => ['nullable'],
'notes' => ['nullable'],
])
); );
session()->flash('flash.banner', 'Auto erstellt.');
return Redirect::route('cars.show', $car); return Redirect::route('cars.show', $car);
}
public function storeForContract(Request $request)
{
$car = Car::create(
$request->validate($this->getValidationRules())
);
return response()->json([
'id' => $car->id,
'stammnummer' => $car->stammnummer,
'vin' => $car->vin,
'name' => $car->name,
'colour' => $car->colour,
'last_check_date' => $car->last_check_date_formatted,
'kilometers' => $car->kilometers,
'initial_date' => $car->initial_date_formatted,
]);
}
private function getValidationRules()
{
return [
'stammnummer' => ['required', 'unique:cars', 'string', 'size:11', 'regex:/[0-9]{3}[.][0-9]{3}[.][0-9]{3}/i'],
'vin' => ['required', 'unique:cars', 'string', 'size:17'],
'initial_date' => ['required', 'date'],
'last_check_date' => ['required', 'date'],
'colour' => ['nullable', 'max:75'],
'car_model_id' => ['required', 'exists:App\Models\CarModel,id'],
'kilometers' => ['required', 'max:75'],
'known_damage' => ['nullable'],
'notes' => ['nullable'],
];
} }
public function show(Car $car) public function show(Car $car)
@ -280,18 +303,21 @@ class CarController extends Controller
]) ])
); );
return Redirect::route('cars.show', $car)->with('success', 'Auto geändert.'); session()->flash('flash.banner', 'Auto geändert.');
return Redirect::route('cars.show', $car);
} }
public function destroy(Car $car) public function destroy(Car $car)
{ {
$car->delete(); $car->delete();
return Redirect::route('cars.show', $car)->with('success', 'Auto gelöscht.'); session()->flash('flash.banner', 'Auto gelöscht.');
return Redirect::route('cars.show', $car);
} }
public function restore(Car $car) public function restore(Car $car)
{ {
$car->restore(); $car->restore();
return Redirect::route('cars.show', $car)->with('success', 'Auto wiederhergestellt.'); session()->flash('flash.banner', 'Auto wiederhergestellt.');
return Redirect::route('cars.show', $car);
} }
} }

View File

@ -89,23 +89,35 @@ class ContactController extends Controller
public function store(Request $request) public function store(Request $request)
{ {
$contact = Contact::create( $contact = Contact::create(
$request->validate([ $request->validate($this->getValidationRules())
'firstname' => ['max:75'],
'lastname' => ['max:75'],
'email' => ['nullable', 'max:75', 'email'],
'phone' => ['required', 'max:75'],
'address' => ['nullable', 'max:150'],
'zip' => ['nullable', 'max:6'],
'city' => ['nullable', 'max:75'],
'country' => ['nullable', 'max:2'],
'company' => ['nullable', 'max:75'],
'notes' => ['nullable'],
])
); );
session()->flash('flash.banner', 'Kontakt erstellt.');
return Redirect::route('contacts.show', $contact); return Redirect::route('contacts.show', $contact);
} }
public function storeForContract(Request $request)
{
$contact = Contact::create(
$request->validate($this->getValidationRules())
);
return response()->json([
'id' => $contact->id,
'title' => $contact->full_title,
'name' => $contact->name,
'firstname' => $contact->firstname,
'lastname' => $contact->lastname,
'phone' => $contact->phone,
'address' => $contact->address,
'zip' => $contact->zip,
'city' => $contact->city,
'country' => $contact->country,
'company' => $contact->company,
'email' => $contact->email,
]);
}
public function edit(Contact $contact) public function edit(Contact $contact)
{ {
return Inertia::render('Contacts/Edit', [ return Inertia::render('Contacts/Edit', [
@ -188,33 +200,40 @@ class ContactController extends Controller
public function update(Request $request, Contact $contact) public function update(Request $request, Contact $contact)
{ {
$contact->update( $contact->update(
$request->validate([ $request->validate($this->getValidationRules())
'firstname' => ['max:75'],
'lastname' => ['max:75'],
'email' => ['nullable', 'max:75', 'email'],
'phone' => ['max:75'],
'address' => ['nullable', 'max:150'],
'zip' => ['nullable', 'max:6'],
'city' => ['nullable', 'max:75'],
'country' => ['nullable', 'max:2'],
'company' => ['nullable', 'max:75'],
'notes' => ['nullable'],
])
); );
return Redirect::route('contacts.show', $contact)->with('success', 'Kontakt geändert.'); session()->flash('flash.banner', 'Kontakt geändert.');
return Redirect::route('contacts.show', $contact);
}
private function getValidationRules()
{
return [
'firstname' => ['max:75'],
'lastname' => ['max:75'],
'email' => ['nullable', 'max:75', 'email'],
'phone' => ['required', 'max:75'],
'address' => ['nullable', 'max:150'],
'zip' => ['nullable', 'max:6'],
'city' => ['nullable', 'max:75'],
'country' => ['nullable', 'max:2'],
'company' => ['nullable', 'max:75'],
'notes' => ['nullable'],
];
} }
public function destroy(Contact $contact) public function destroy(Contact $contact)
{ {
$contact->delete(); $contact->delete();
return Redirect::back()->with('success', 'Kontakt gelöscht.'); session()->flash('flash.banner', 'Kontakt gelöscht.');
return Redirect::back();
} }
public function restore(Contact $contact) public function restore(Contact $contact)
{ {
$contact->restore(); $contact->restore();
session()->flash('flash.banner', 'Kontakt wiederhergestellt.');
return Redirect::back()->with('success', 'Kontakt wiederhergestellt.'); return Redirect::back();
} }
} }

View File

@ -2,11 +2,12 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\Enums\ContractType;
use App\Models\Car; use App\Models\Car;
use Inertia\Inertia; use Inertia\Inertia;
use App\Models\Brand;
use App\Models\Contact; use App\Models\Contact;
use App\Models\Contract; use App\Models\Contract;
use App\Enums\ContractType;
use App\Enums\InsuranceType; use App\Enums\InsuranceType;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Redirect; use Illuminate\Support\Facades\Redirect;
@ -43,37 +44,49 @@ class ContractController extends Controller
return []; return [];
} }
public function create(Request $request, Car $car, Contact $contact) public function create(Request $request, int $type, Car $car, Contact $contact)
{ {
return Inertia::render('Contracts/Create', [ return Inertia::render('Contracts/Create', [
'car' => $this->getCarFields($car), 'car' => $this->getCarFields($car),
'contact' => $this->getContactFields($contact), 'contact' => $this->getContactFields($contact),
'type' => (string)ContractType::BuyContract, 'type' => ContractType::coerce($type)->key,
'car_first' => $request->query('carFirst'),
]); ]);
} }
public function createFromCar(Request $request, Car $car) public function createFromCar(Request $request, int $type, Car $car)
{ {
return Inertia::render('Contracts/CreateFromCar', [ return Inertia::render('Contracts/CreateFromCar', [
'car' => $this->getCarFields($car), 'car' => $this->getCarFields($car),
'type' => ContractType::coerce($type)->key,
'contacts' => Contact::all()->map(function ($contact) { 'contacts' => Contact::all()->map(function ($contact) {
return [ return $this->getContactFields($contact);
'id' => $contact->id,
'name' => $contact->name,
];
}), }),
]); ]);
} }
public function createFromContact(Request $request, Contact $contact) public function createFromContact(Request $request, int $type, Contact $contact)
{ {
$contractType = ContractType::coerce($type);
$cars = $contractType->value == ContractType::SellContract ? Car::unsoldOnly() : Car::soldOnly();
return Inertia::render('Contracts/CreateFromContact', [ return Inertia::render('Contracts/CreateFromContact', [
'contact' => $this->getContactFields($contact), 'contact' => $this->getContactFields($contact),
'cars' => Car::all()->map(function ($car) { 'type' => $contractType->key,
'cars' => $cars->get()->map(function ($car) {
return $this->getCarFields($car);
}),
'brands' => Brand::all()->map(function ($brand) {
return [ return [
'id' => $car->id, 'id' => $brand->id,
'name' => $car->name, 'name' => $brand->name,
'stammnummer' => $car->stammnummer, 'models' => $brand->carModels()->get()
->map(function ($carModel) {
return [
'id' => $carModel->id,
'name' => $carModel->name,
];
}),
]; ];
}), }),
]); ]);
@ -101,6 +114,7 @@ class ContractController extends Controller
} }
return [ return [
'id' => $contact->id, 'id' => $contact->id,
'title' => $contact->full_title,
'name' => $contact->name, 'name' => $contact->name,
'firstname' => $contact->firstname, 'firstname' => $contact->firstname,
'lastname' => $contact->lastname, 'lastname' => $contact->lastname,
@ -126,6 +140,7 @@ class ContractController extends Controller
]) ])
); );
session()->flash('flash.banner', 'Vertrag erstellt.');
return Redirect::route('contracts.show', $contract); return Redirect::route('contracts.show', $contract);
} }
@ -158,7 +173,8 @@ class ContractController extends Controller
]) ])
); );
return Redirect::route('contracts.show', $contract)->with('success', 'Vertrag angepasst.'); session()->flash('flash.banner', 'Vertrag geändert.');
return Redirect::route('contracts.show', $contract);
} }
@ -215,12 +231,14 @@ class ContractController extends Controller
public function destroy(Contract $contract) public function destroy(Contract $contract)
{ {
$contract->delete(); $contract->delete();
return Redirect::route('contracts.show', $contract)->with('success', 'Vertrag gelöscht.'); session()->flash('flash.banner', 'Vertrag gelöscht.');
return Redirect::route('contracts.show', $contract);
} }
public function restore(Contract $contract) public function restore(Contract $contract)
{ {
$contract->restore(); $contract->restore();
return Redirect::route('contracts.show', $contract)->with('success', 'Vertrag wiederhergestellt.'); session()->flash('flash.banner', 'Vertrag wiederhergestellt.');
return Redirect::route('contracts.show', $contract);
} }
} }

View File

@ -38,6 +38,11 @@ class Contact extends Model
return $this->name; return $this->name;
} }
public function getFullTitleAttribute()
{
return implode(', ', array_filter([$this->company, $this->name]));
}
public function getFullCityAttribute() public function getFullCityAttribute()
{ {
return $this->zip . ' ' . $this->city; return $this->zip . ' ' . $this->city;

2231
public/js/app.js vendored

File diff suppressed because it is too large Load Diff

View File

@ -28,10 +28,10 @@
</tr> </tr>
<tr v-for="row in data.data" :key="row.link" class="hover:bg-gray-100 focus-within:bg-gray-100"> <tr v-for="row in data.data" :key="row.link" class="hover:bg-gray-100 focus-within:bg-gray-100">
<td v-for="col in columns" :key="col.key" class="border-t"> <td v-for="col in columns" :key="col.key" class="border-t">
<inertia-link v-if="row.link" class="px-6 py-4 flex items-center focus:text-blue-200" :href="row.link"> <inertia-link v-if="row.link" class="px-6 py-4 flex items-center" :href="row.link">
{{ resolve(col.key, row) }} {{ resolve(col.key, row) }}
</inertia-link> </inertia-link>
<span v-else class="px-6 py-4 flex items-center focus:text-blue-200"> <span v-else class="px-6 py-4 flex items-center">
{{ resolve(col.key, row) }} {{ resolve(col.key, row) }}
</span> </span>
</td> </td>

View File

@ -1,7 +1,7 @@
<template> <template>
<div> <div>
<div :class="{ 'bg-indigo-500': style == 'success', 'bg-red-700': style == 'danger' }" v-if="show && message"> <div :class="{ 'bg-indigo-500': style == 'success', 'bg-red-700': style == 'danger' }" v-if="show && message">
<div class="max-w-screen-xl mx-auto py-2 px-3 sm:px-6 lg:px-8"> <div class="w-full py-2 px-12">
<div class="flex items-center justify-between flex-wrap"> <div class="flex items-center justify-between flex-wrap">
<div class="w-0 flex-1 flex items-center min-w-0"> <div class="w-0 flex-1 flex items-center min-w-0">
<span class="flex p-2 rounded-lg" :class="{ 'bg-indigo-600': style == 'success', 'bg-red-600': style == 'danger' }"> <span class="flex p-2 rounded-lg" :class="{ 'bg-indigo-600': style == 'success', 'bg-red-600': style == 'danger' }">

View File

@ -7,8 +7,7 @@
<div class="mt-5 md:mt-0 md:col-span-2"> <div class="mt-5 md:mt-0 md:col-span-2">
<form @submit.prevent="$emit('submitted')"> <form @submit.prevent="$emit('submitted')">
<div class="px-4 py-5 bg-white sm:p-6 shadow" <div :class="classnames">
:class="hasActions ? 'sm:rounded-tl-md sm:rounded-tr-md' : 'sm:rounded-md'">
<div class="grid grid-cols-6 gap-6"> <div class="grid grid-cols-6 gap-6">
<slot name="form"></slot> <slot name="form"></slot>
</div> </div>
@ -28,6 +27,13 @@
export default { export default {
emits: ['submitted'], emits: ['submitted'],
props: {
emptyBg: {
type: Boolean,
default: false,
},
},
components: { components: {
JetSectionTitle, JetSectionTitle,
}, },
@ -35,7 +41,12 @@
computed: { computed: {
hasActions() { hasActions() {
return !! this.$slots.actions return !! this.$slots.actions
} },
classnames() {
let classnames = !this.emptyBg ? 'px-4 py-5 bg-white sm:p-6 shadow ' :"";
classnames += this.hasActions ? 'sm:rounded-tl-md sm:rounded-tr-md' : 'sm:rounded-md';
return classnames;
},
} }
} }
</script> </script>

View File

@ -8,7 +8,8 @@
<slot name="header"></slot> <slot name="header"></slot>
</h2> </h2>
</Navbar> </Navbar>
<div class="p-12 bg-gray-100 mb-20"> <jet-banner class="sticky top-20 z-40" />
<div class="pt-12 px-12 bg-gray-100 mb-20">
<main> <main>
<slot></slot> <slot></slot>
</main> </main>
@ -22,6 +23,7 @@
import { mapState } from 'vuex' import { mapState } from 'vuex'
import Sidebar from "@/Components/Sidebar" import Sidebar from "@/Components/Sidebar"
import Navbar from "@/Components/Navbar" import Navbar from "@/Components/Navbar"
import JetBanner from '@/Jetstream/Banner'
export default { export default {
computed: { computed: {
@ -30,6 +32,7 @@ export default {
components: { components: {
Sidebar, Sidebar,
Navbar, Navbar,
JetBanner,
} }
} }
</script> </script>

View File

@ -10,85 +10,7 @@
</template> </template>
<template #form> <template #form>
<div class="col-span-6 sm:col-span-4"> <car-form-fields :form="form" :brands="brands" :brand="brand" :car_model="car_model" />
<jet-label for="brand" value="Marke" />
<multiselect v-model="brandSelection" @SearchChange="updateBrandSearch" @select="updateBrand" label="name" track-by="id" :options="brands" class="mt-1 block w-full" placeholder="Marke auswählen">
<template v-slot:noResult>
<span @click="addBrand">
<b>{{ brandSearch }}</b> als neue Marke speichern?
</span>
</template>
</multiselect>
</div>
<div v-if="brandSelection" class="col-span-6 sm:col-span-4">
<jet-label for="model" value="Modell" />
<multiselect v-model="car_modelSelection" @SearchChange="updateCarModelSearch" @select="updateCarModel" label="name" track-by="id" :options="carModels" class="mt-1 block w-full" placeholder="Modell auswählen">
<template v-slot:noResult>
<span @click="addCarModel">
<b>{{ modelSearch }}</b> als neues {{ brand.name }}-Modell speichern?
</span>
</template>
</multiselect>
<jet-input-error :message="form.errors.car_model_id" class="mt-2" />
</div>
<div class="col-span-6 sm:col-span-4">
<div class="grid grid-cols-12 gap-6">
<div class="col-span-12 sm:col-span-5">
<jet-label for="stammnummer" value="Stammnummer" />
<jet-input id="stammnummer" type="text" class="mt-1 block w-full" v-model="form.stammnummer" ref="stammnummer" autocomplete="stammnummer" />
<jet-input-error :message="form.errors.stammnummer" class="mt-2" />
</div>
<div class="col-span-12 sm:col-span-7">
<jet-label for="vin" value="Chassisnummer" />
<jet-input id="vin" type="text" class="mt-1 block w-full" v-model="form.vin" ref="vin" autocomplete="vin" />
<jet-input-error :message="form.errors.vin" class="mt-2" />
</div>
</div>
</div>
<div class="col-span-6 sm:col-span-4">
<div class="grid grid-cols-12 gap-6">
<div class="col-span-6 sm:col-span-6">
<jet-label for="initial_date" value="Inverkehrssetzung" />
<jet-input id="initial_date" type="text" class="mt-1 block w-full" v-model="form.initial_date" ref="initial_date" autocomplete="initial_date" />
<jet-input-error :message="form.errors.initial_date" class="mt-2" />
</div>
<div class="col-span-6 sm:col-span-6">
<jet-label for="last_check_date" value="Letzte Prüfung" />
<jet-input id="last_check_date" type="text" class="mt-1 block w-full" v-model="form.last_check_date" ref="last_check_date" autocomplete="last_check_date" />
<jet-input-error :message="form.errors.last_check_date" class="mt-2" />
</div>
</div>
</div>
<div class="col-span-6 sm:col-span-4">
<jet-label for="kilometers" value="Kilometerstand" />
<jet-input id="kilometers" type="text" class="mt-1 block w-full" v-model="form.kilometers" ref="kilometers" autocomplete="kilometers" />
<jet-input-error :message="form.errors.kilometers" class="mt-2" />
</div>
<div class="col-span-6 sm:col-span-4">
<jet-label for="colour" value="Farbe" />
<jet-input id="colour" type="text" class="mt-1 block w-full" v-model="form.colour" ref="colour" autocomplete="colour" />
<jet-input-error :message="form.errors.colour" class="mt-2" />
</div>
<div class="col-span-6 sm:col-span-4">
<jet-label for="known_damage" value="Bekannter Schaden" />
<textarea class="mt-1 block w-full border-gray-300 focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50 rounded-md shadow-sm" v-model="form.known_damage" ref="input">
</textarea>
<jet-input-error :message="form.errors.known_damage" class="mt-2" />
</div>
<div class="col-span-6 sm:col-span-4">
<jet-label for="notes" value="Bemerkungen" />
<textarea class="mt-1 block w-full border-gray-300 focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50 rounded-md shadow-sm" v-model="form.notes" ref="input">
</textarea>
<jet-input-error :message="form.errors.notes" class="mt-2" />
</div>
</template> </template>
<template #actions> <template #actions>
@ -106,25 +28,17 @@
<script> <script>
import JetButton from '@/Jetstream/Button' import JetButton from '@/Jetstream/Button'
import JetLabel from '@/Jetstream/Label.vue'
import JetInput from '@/Jetstream/Input.vue'
import Modal from '@/Jetstream/Modal.vue'
import JetActionMessage from '@/Jetstream/ActionMessage' import JetActionMessage from '@/Jetstream/ActionMessage'
import JetInputError from '@/Jetstream/InputError'
import JetFormSection from '@/Jetstream/FormSection' import JetFormSection from '@/Jetstream/FormSection'
import Multiselect from 'vue-multiselect' import CarFormFields from '@/Pages/Cars/Components/CarFormFields.vue'
import { useForm } from '@inertiajs/inertia-vue3' import { useForm } from '@inertiajs/inertia-vue3'
export default { export default {
components: { components: {
JetButton, JetButton,
JetFormSection, JetFormSection,
JetLabel,
Modal,
JetInput,
JetInputError,
JetActionMessage, JetActionMessage,
Multiselect, CarFormFields,
}, },
props: { props: {
data: Object, data: Object,
@ -135,11 +49,6 @@ export default {
}, },
data() { data() {
return { return {
brandSearch: null,
modelSearch: null,
carModels: [],
brandSelection: this.brand,
car_modelSelection: this.car_model,
form: useForm(this.meta.form_name, this.data), form: useForm(this.meta.form_name, this.data),
} }
}, },
@ -147,68 +56,6 @@ export default {
submitForm() { submitForm() {
this.form.submit(this.meta.method, this.meta.route); this.form.submit(this.meta.method, this.meta.route);
}, },
updateBrand(brand) { }
if (brand) {
this.brand.id = brand.id;
this.brand.name = brand.name;
this.brand.models = brand.models;
} else {
this.brand.id = null;
this.brand.name = null;
this.brand.models = [];
}
this.updateCarModelsList(brand);
},
updateCarModel(car_model) {
if (car_model) {
this.car_model.id = car_model.id;
this.car_model.name = car_model.name;
this.form.car_model_id = car_model.id;
} else {
this.car_model.id = null;
this.car_model.name = null;
this.form.car_model_id = null;
}
},
updateCarModelsList(brand) {
this.carModels = brand.models ?? [];
this.car_modelSelection = null;
this.updateCarModel(null);
},
updateBrandSearch(searchQuery, id) {
this.brandSearch = searchQuery
},
addBrand() {
axios.post(this.route('brands.store'), {
name: this.brandSearch,
}).then((response) => {
this.brandSelection = response.data;
this.brands.push(this.brandSelection);
this.updateBrand(this.brandSelection);
});
},
updateCarModelSearch(searchQuery, id) {
this.modelSearch = searchQuery
},
addCarModel() {
axios.post(this.route('models.store'), {
name: this.modelSearch,
brand_id: this.brand.id,
}).then((response) => {
this.car_modelSelection = response.data;
this.carModels.push(this.car_modelSelection);
this.updateCarModel(this.car_modelSelection);
});
},
},
mounted: function () {
this.$nextTick(function () {
this.brandSelection = this.brands.find(x => x.id === this.brand.id);
if (this.brandSelection) {
this.carModels = this.brandSelection.models ?? [];
}
})
},
} }
</script> </script>
<style src="vue-multiselect/dist/vue-multiselect.css"></style>

View File

@ -0,0 +1,178 @@
<template>
<div class="col-span-6 sm:col-span-4">
<jet-label for="brand" value="Marke" />
<multiselect v-model="brandSelection" @SearchChange="updateBrandSearch" @select="updateBrand" label="name" track-by="id" :options="brands" class="mt-1 block w-full" placeholder="Marke auswählen">
<template v-slot:noResult>
<span @click="addBrand">
<b>{{ brandSearch }}</b> als neue Marke speichern?
</span>
</template>
</multiselect>
</div>
<div v-if="brandSelection" class="col-span-6 sm:col-span-4">
<jet-label for="model" value="Modell" />
<multiselect v-model="car_modelSelection" @SearchChange="updateCarModelSearch" @select="updateCarModel" label="name" track-by="id" :options="carModels" class="mt-1 block w-full" placeholder="Modell auswählen">
<template v-slot:noResult>
<span @click="addCarModel">
<b>{{ modelSearch }}</b> als neues {{ brand.name }}-Modell speichern?
</span>
</template>
</multiselect>
<jet-input-error :message="form.errors.car_model_id" class="mt-2" />
</div>
<div class="col-span-6 sm:col-span-4">
<div class="grid grid-cols-12 gap-6">
<div class="col-span-12 sm:col-span-5">
<jet-label for="stammnummer" value="Stammnummer" />
<jet-input id="stammnummer" type="text" class="mt-1 block w-full" v-model="form.stammnummer" ref="stammnummer" autocomplete="stammnummer" />
<jet-input-error :message="form.errors.stammnummer" class="mt-2" />
</div>
<div class="col-span-12 sm:col-span-7">
<jet-label for="vin" value="Chassisnummer" />
<jet-input id="vin" type="text" class="mt-1 block w-full" v-model="form.vin" ref="vin" autocomplete="vin" />
<jet-input-error :message="form.errors.vin" class="mt-2" />
</div>
</div>
</div>
<div class="col-span-6 sm:col-span-4">
<div class="grid grid-cols-12 gap-6">
<div class="col-span-6 sm:col-span-6">
<jet-label for="initial_date" value="Inverkehrssetzung" />
<jet-input id="initial_date" type="text" class="mt-1 block w-full" v-model="form.initial_date" ref="initial_date" autocomplete="initial_date" />
<jet-input-error :message="form.errors.initial_date" class="mt-2" />
</div>
<div class="col-span-6 sm:col-span-6">
<jet-label for="last_check_date" value="Letzte Prüfung" />
<jet-input id="last_check_date" type="text" class="mt-1 block w-full" v-model="form.last_check_date" ref="last_check_date" autocomplete="last_check_date" />
<jet-input-error :message="form.errors.last_check_date" class="mt-2" />
</div>
</div>
</div>
<div class="col-span-6 sm:col-span-4">
<jet-label for="kilometers" value="Kilometerstand" />
<jet-input id="kilometers" type="text" class="mt-1 block w-full" v-model="form.kilometers" ref="kilometers" autocomplete="kilometers" />
<jet-input-error :message="form.errors.kilometers" class="mt-2" />
</div>
<div class="col-span-6 sm:col-span-4">
<jet-label for="colour" value="Farbe" />
<jet-input id="colour" type="text" class="mt-1 block w-full" v-model="form.colour" ref="colour" autocomplete="colour" />
<jet-input-error :message="form.errors.colour" class="mt-2" />
</div>
<div class="col-span-6 sm:col-span-4">
<jet-label for="known_damage" value="Bekannter Schaden" />
<textarea class="mt-1 block w-full border-gray-300 focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50 rounded-md shadow-sm" v-model="form.known_damage" ref="input">
</textarea>
<jet-input-error :message="form.errors.known_damage" class="mt-2" />
</div>
<div class="col-span-6 sm:col-span-4">
<jet-label for="notes" value="Bemerkungen" />
<textarea class="mt-1 block w-full border-gray-300 focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50 rounded-md shadow-sm" v-model="form.notes" ref="input">
</textarea>
<jet-input-error :message="form.errors.notes" class="mt-2" />
</div>
</template>
<script>
import JetLabel from '@/Jetstream/Label.vue'
import JetInput from '@/Jetstream/Input.vue'
import JetActionMessage from '@/Jetstream/ActionMessage'
import JetInputError from '@/Jetstream/InputError'
import Multiselect from 'vue-multiselect'
export default {
components: {
JetLabel,
JetInput,
JetInputError,
JetActionMessage,
Multiselect,
},
props: {
form: Object,
brands: Array,
brand: Object,
car_model: Object,
},
data() {
return {
brandSearch: null,
modelSearch: null,
carModels: [],
brandSelection: this.brand,
car_modelSelection: this.car_model,
}
},
methods: {
updateBrand(brand) {
if (brand) {
this.brand.id = brand.id;
this.brand.name = brand.name;
this.brand.models = brand.models;
} else {
this.brand.id = null;
this.brand.name = null;
this.brand.models = [];
}
this.updateCarModelsList(brand);
},
updateCarModel(car_model) {
if (car_model) {
this.car_model.id = car_model.id;
this.car_model.name = car_model.name;
this.form.car_model_id = car_model.id;
} else {
this.car_model.id = null;
this.car_model.name = null;
this.form.car_model_id = null;
}
},
updateCarModelsList(brand) {
this.carModels = brand.models ?? [];
this.car_modelSelection = null;
this.updateCarModel(null);
},
updateBrandSearch(searchQuery, id) {
this.brandSearch = searchQuery
},
addBrand() {
axios.post(this.route('brands.store'), {
name: this.brandSearch,
}).then((response) => {
this.brandSelection = response.data;
this.brands.push(this.brandSelection);
this.updateBrand(this.brandSelection);
});
},
updateCarModelSearch(searchQuery, id) {
this.modelSearch = searchQuery
},
addCarModel() {
axios.post(this.route('models.store'), {
name: this.modelSearch,
brand_id: this.brand.id,
}).then((response) => {
this.car_modelSelection = response.data;
this.carModels.push(this.car_modelSelection);
this.updateCarModel(this.car_modelSelection);
});
},
},
mounted: function () {
this.$nextTick(function () {
this.brandSelection = this.brands.find(x => x.id === this.brand.id);
if (this.brandSelection) {
this.carModels = this.brandSelection.models ?? [];
}
})
},
}
</script>
<style src="vue-multiselect/dist/vue-multiselect.css"></style>

View File

@ -10,7 +10,7 @@
<div> <div>
<car-form :data="data" :meta="meta" :car_model="car_model" :brand="brand" :brands="brands"> <car-form :data="data" :meta="meta" :car_model="car_model" :brand="brand" :brands="brands">
<template #title>Neues Auto erfassen</template> <template #title>Neues Auto erfassen</template>
<template #description>...</template> <template #description>Daten für ein neues Auto eingeben und speichern</template>
</car-form> </car-form>
</div> </div>
</layout> </layout>

View File

@ -3,7 +3,8 @@
<template #header> <template #header>
<h2 class="font-semibold text-xl text-gray-800 leading-tight"> <h2 class="font-semibold text-xl text-gray-800 leading-tight">
<bread-crumb text="Autos" :href="route('cars')" /> <bread-crumb text="Autos" :href="route('cars')" />
{{ name }} <bread-crumb :text="name" :href="route('cars.show', car.id)" />
bearbeiten
</h2> </h2>
</template> </template>
<div> <div>

View File

@ -26,7 +26,7 @@
<buy-contract-card :contract="contract"/> <buy-contract-card :contract="contract"/>
</div> </div>
<div v-if="!car.deleted_at && car.buy_contracts.total <= car.sell_contracts.total"> <div v-if="!car.deleted_at && car.buy_contracts.total <= car.sell_contracts.total">
<inertia-link :href="route('contracts.create_from_car', car.id)" class="w-full py-6 mt-12 inline-flex items-center px-4 bg-green-800 border border-transparent rounded-md font-semibold justify-center text-md text-white uppercase tracking-widest hover:bg-green-700 focus:outline-none focus:border-green-900 focus:ring focus:ring-green-300 disabled:opacity-25 transition" > <inertia-link :href="route('contracts.create_from_car', [0, car.id])" class="w-full py-6 mt-12 inline-flex items-center px-4 bg-green-800 border border-transparent rounded-md font-semibold justify-center text-md text-white uppercase tracking-widest hover:bg-green-700 focus:outline-none focus:border-green-900 focus:ring focus:ring-green-300 disabled:opacity-25 transition" >
<unicon fill="white" class="mr-1" height="22" width="22" name="plus-circle"></unicon> <unicon fill="white" class="mr-1" height="22" width="22" name="plus-circle"></unicon>
Neuer Ankaufsvertrag Neuer Ankaufsvertrag
</inertia-link> </inertia-link>
@ -40,7 +40,7 @@
<sell-contract-card :contract="contract"/> <sell-contract-card :contract="contract"/>
</div> </div>
<div v-if="!car.deleted_at && car.buy_contracts.total > car.sell_contracts.total"> <div v-if="!car.deleted_at && car.buy_contracts.total > car.sell_contracts.total">
<inertia-link :href="route('contracts.create_from_car', car.id)" class="py-6 w-full mt-12 inline-flex items-center px-4 bg-green-800 border border-transparent rounded-md font-semibold justify-center text-md text-white uppercase tracking-widest hover:bg-green-700 focus:outline-none focus:border-green-900 focus:ring focus:ring-green-300 disabled:opacity-25 transition" > <inertia-link :href="route('contracts.create_from_car', [1, car.id])" class="py-6 w-full mt-12 inline-flex items-center px-4 bg-green-800 border border-transparent rounded-md font-semibold justify-center text-md text-white uppercase tracking-widest hover:bg-green-700 focus:outline-none focus:border-green-900 focus:ring focus:ring-green-300 disabled:opacity-25 transition" >
<unicon fill="white" class="mr-1" height="22" width="22" name="plus-circle"></unicon> <unicon fill="white" class="mr-1" height="22" width="22" name="plus-circle"></unicon>
Neuer Verkaufssvertrag Neuer Verkaufssvertrag
</inertia-link> </inertia-link>

View File

@ -10,74 +10,7 @@
</template> </template>
<template #form> <template #form>
<div class="col-span-6 sm:col-span-4"> <contact-form-fields :form="form" />
<div class="grid grid-cols-6 gap-6">
<div class="col-span-6 sm:col-span-3">
<jet-label for="firstname" value="Vorname" />
<jet-input id="firstname" type="text" class="mt-1 block w-full" v-model="form.firstname" ref="firstname" autocomplete="firstname" />
<jet-input-error :message="form.errors.firstname" class="mt-2" />
</div>
<div class="col-span-6 sm:col-span-3">
<jet-label for="lastname" value="Nachname" />
<jet-input id="lastname" type="text" class="mt-1 block w-full" v-model="form.lastname" ref="lastname" autocomplete="lastname" />
<jet-input-error :message="form.errors.lastname" class="mt-2" />
</div>
</div>
</div>
<div class="col-span-6 sm:col-span-4">
<jet-label for="company" value="Firma" />
<jet-input id="company" type="text" class="mt-1 block w-full" v-model="form.company" ref="company" autocomplete="company" />
<jet-input-error :message="form.errors.company" class="mt-2" />
</div>
<div class="col-span-6 sm:col-span-4">
<jet-label for="address" value="Strasse" />
<jet-input id="address" type="text" class="mt-1 block w-full" v-model="form.address" ref="address" autocomplete="address" />
<jet-input-error :message="form.errors.address" class="mt-2" />
</div>
<div class="col-span-6 sm:col-span-4">
<div class="grid grid-cols-6 gap-6">
<div class="col-span-6 sm:col-span-2">
<jet-label for="zip" value="PLZ" />
<jet-input id="zip" type="text" class="mt-1 block w-full" v-model="form.zip" ref="zip" autocomplete="zip" />
<jet-input-error :message="form.errors.zip" class="mt-2" />
</div>
<div class="col-span-6 sm:col-span-3">
<jet-label for="city" value="Ort" />
<jet-input id="city" type="text" class="mt-1 block w-full" v-model="form.city" ref="city" autocomplete="city" />
<jet-input-error :message="form.errors.city" class="mt-2" />
</div>
<div class="col-span-6 sm:col-span-1">
<jet-label for="country" value="Land" />
<jet-input id="country" type="text" class="mt-1 block w-full" v-model="form.country" ref="country" autocomplete="country" />
<jet-input-error :message="form.errors.country" class="mt-2" />
</div>
</div>
</div>
<div class="col-span-6 sm:col-span-4">
<div class="grid grid-cols-6 gap-6">
<div class="col-span-6 sm:col-span-3">
<jet-label for="email" value="E-Mail" />
<jet-input id="email" type="email" class="mt-1 block w-full" v-model="form.email" ref="email" autocomplete="email" />
<jet-input-error :message="form.errors.email" class="mt-2" />
</div>
<div class="col-span-6 sm:col-span-3">
<jet-label for="phone" value="Telefon" />
<jet-input id="phone" type="text" class="mt-1 block w-full" v-model="form.phone" ref="phone" autocomplete="phone" />
<jet-input-error :message="form.errors.phone" class="mt-2" />
</div>
</div>
</div>
<div class="col-span-6 sm:col-span-4">
<jet-label for="notes" value="Bemerkungen" />
<textarea class="mt-1 block w-full border-gray-300 focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50 rounded-md shadow-sm" v-model="form.notes" ref="input">
</textarea>
<jet-input-error :message="form.errors.notes" class="mt-2" />
</div>
</template> </template>
<template #actions> <template #actions>
@ -95,21 +28,17 @@
<script> <script>
import JetButton from '@/Jetstream/Button' import JetButton from '@/Jetstream/Button'
import JetLabel from '@/Jetstream/Label.vue'
import JetInput from '@/Jetstream/Input.vue'
import JetActionMessage from '@/Jetstream/ActionMessage' import JetActionMessage from '@/Jetstream/ActionMessage'
import JetInputError from '@/Jetstream/InputError'
import JetFormSection from '@/Jetstream/FormSection' import JetFormSection from '@/Jetstream/FormSection'
import ContactFormFields from './ContactFormFields'
import { useForm } from '@inertiajs/inertia-vue3' import { useForm } from '@inertiajs/inertia-vue3'
export default { export default {
components: { components: {
JetButton, JetButton,
JetFormSection, JetFormSection,
JetLabel,
JetInput,
JetInputError,
JetActionMessage, JetActionMessage,
ContactFormFields,
}, },
props: { props: {
data: Object, data: Object,

View File

@ -0,0 +1,87 @@
<template>
<div class="col-span-6 sm:col-span-4">
<div class="grid grid-cols-6 gap-6">
<div class="col-span-6 sm:col-span-3">
<jet-label for="firstname" value="Vorname" />
<jet-input id="firstname" type="text" class="mt-1 block w-full" v-model="form.firstname" ref="firstname" autocomplete="firstname" />
<jet-input-error :message="form.errors.firstname" class="mt-2" />
</div>
<div class="col-span-6 sm:col-span-3">
<jet-label for="lastname" value="Nachname" />
<jet-input id="lastname" type="text" class="mt-1 block w-full" v-model="form.lastname" ref="lastname" autocomplete="lastname" />
<jet-input-error :message="form.errors.lastname" class="mt-2" />
</div>
</div>
</div>
<div class="col-span-6 sm:col-span-4">
<jet-label for="company" value="Firma" />
<jet-input id="company" type="text" class="mt-1 block w-full" v-model="form.company" ref="company" autocomplete="company" />
<jet-input-error :message="form.errors.company" class="mt-2" />
</div>
<div class="col-span-6 sm:col-span-4">
<jet-label for="address" value="Strasse" />
<jet-input id="address" type="text" class="mt-1 block w-full" v-model="form.address" ref="address" autocomplete="address" />
<jet-input-error :message="form.errors.address" class="mt-2" />
</div>
<div class="col-span-6 sm:col-span-4">
<div class="grid grid-cols-6 gap-6">
<div class="col-span-6 sm:col-span-2">
<jet-label for="zip" value="PLZ" />
<jet-input id="zip" type="text" class="mt-1 block w-full" v-model="form.zip" ref="zip" autocomplete="zip" />
<jet-input-error :message="form.errors.zip" class="mt-2" />
</div>
<div class="col-span-6 sm:col-span-3">
<jet-label for="city" value="Ort" />
<jet-input id="city" type="text" class="mt-1 block w-full" v-model="form.city" ref="city" autocomplete="city" />
<jet-input-error :message="form.errors.city" class="mt-2" />
</div>
<div class="col-span-6 sm:col-span-1">
<jet-label for="country" value="Land" />
<jet-input id="country" type="text" class="mt-1 block w-full" v-model="form.country" ref="country" autocomplete="country" />
<jet-input-error :message="form.errors.country" class="mt-2" />
</div>
</div>
</div>
<div class="col-span-6 sm:col-span-4">
<div class="grid grid-cols-6 gap-6">
<div class="col-span-6 sm:col-span-3">
<jet-label for="email" value="E-Mail" />
<jet-input id="email" type="email" class="mt-1 block w-full" v-model="form.email" ref="email" autocomplete="email" />
<jet-input-error :message="form.errors.email" class="mt-2" />
</div>
<div class="col-span-6 sm:col-span-3">
<jet-label for="phone" value="Telefon" />
<jet-input id="phone" type="text" class="mt-1 block w-full" v-model="form.phone" ref="phone" autocomplete="phone" />
<jet-input-error :message="form.errors.phone" class="mt-2" />
</div>
</div>
</div>
<div class="col-span-6 sm:col-span-4">
<jet-label for="notes" value="Bemerkungen" />
<textarea class="mt-1 block w-full border-gray-300 focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50 rounded-md shadow-sm" v-model="form.notes" ref="input">
</textarea>
<jet-input-error :message="form.errors.notes" class="mt-2" />
</div>
</template>
<script>
import JetLabel from '@/Jetstream/Label.vue'
import JetInput from '@/Jetstream/Input.vue'
import JetInputError from '@/Jetstream/InputError'
export default {
components: {
JetLabel,
JetInput,
JetInputError,
},
props: {
form: Object,
},
}
</script>

View File

@ -3,7 +3,8 @@
<template #header> <template #header>
<h2 class="font-semibold text-xl text-gray-800 leading-tight"> <h2 class="font-semibold text-xl text-gray-800 leading-tight">
<bread-crumb text="Kontakte" :href="route('contacts')" /> <bread-crumb text="Kontakte" :href="route('contacts')" />
{{ title }} <bread-crumb :text="title" :href="route('contacts.show', contact.id)" />
bearbeiten
</h2> </h2>
</template> </template>

View File

@ -29,7 +29,7 @@
<buy-contract-card :contract="contract"/> <buy-contract-card :contract="contract"/>
</div> </div>
<div v-if="!contact.deleted_at"> <div v-if="!contact.deleted_at">
<inertia-link :href="route('contracts.create_from_contact', contact.id)" class="w-full py-6 mt-12 inline-flex items-center px-4 bg-green-800 border border-transparent rounded-md font-semibold justify-center text-md text-white uppercase tracking-widest hover:bg-green-700 focus:outline-none focus:border-green-900 focus:ring focus:ring-green-300 disabled:opacity-25 transition" > <inertia-link :href="route('contracts.create_from_contact', [0, contact.id])" class="w-full py-6 mt-12 inline-flex items-center px-4 bg-green-800 border border-transparent rounded-md font-semibold justify-center text-md text-white uppercase tracking-widest hover:bg-green-700 focus:outline-none focus:border-green-900 focus:ring focus:ring-green-300 disabled:opacity-25 transition" >
<unicon fill="white" class="mr-1" height="22" width="22" name="plus-circle"></unicon> <unicon fill="white" class="mr-1" height="22" width="22" name="plus-circle"></unicon>
Neuer Ankaufsvertrag Neuer Ankaufsvertrag
</inertia-link> </inertia-link>
@ -43,7 +43,7 @@
<sell-contract-card :contract="contract"/> <sell-contract-card :contract="contract"/>
</div> </div>
<div v-if="!contact.deleted_at"> <div v-if="!contact.deleted_at">
<inertia-link :href="route('contracts.create_from_contact', contact.id)" class="py-6 w-full mt-12 inline-flex items-center px-4 bg-green-800 border border-transparent rounded-md font-semibold justify-center text-md text-white uppercase tracking-widest hover:bg-green-700 focus:outline-none focus:border-green-900 focus:ring focus:ring-green-300 disabled:opacity-25 transition" > <inertia-link :href="route('contracts.create_from_contact', [1, contact.id])" class="py-6 w-full mt-12 inline-flex items-center px-4 bg-green-800 border border-transparent rounded-md font-semibold justify-center text-md text-white uppercase tracking-widest hover:bg-green-700 focus:outline-none focus:border-green-900 focus:ring focus:ring-green-300 disabled:opacity-25 transition" >
<unicon fill="white" class="mr-1" height="22" width="22" name="plus-circle"></unicon> <unicon fill="white" class="mr-1" height="22" width="22" name="plus-circle"></unicon>
Neuer Verkaufssvertrag Neuer Verkaufssvertrag
</inertia-link> </inertia-link>

View File

@ -10,23 +10,26 @@
</template> </template>
<template #form> <template #form>
<div class="col-span-6 sm:col-span-4"> <div class="col-span-3 grid grid-cols-6 gap-3">
<jet-label for="date" value="Datum" /> <div class="col-span-6 sm:col-span-4">
<jet-input id="date" type="text" class="mt-1 block w-full" v-model="form.date" ref="date" autocomplete="date" /> <jet-label for="date" value="Datum" />
<jet-input-error :message="form.errors.date" class="mt-2" /> <jet-input id="date" type="text" class="mt-1 block w-full" v-model="form.date" ref="date" autocomplete="date" />
</div> <jet-input-error :message="form.errors.date" class="mt-2" />
</div>
<div class="col-span-6 sm:col-span-4"> <div class="col-span-6 sm:col-span-4">
<jet-label for="price" value="Betrag" /> <jet-label for="price" value="Betrag" />
<jet-input id="price" type="text" class="mt-1 block w-full" v-model="form.price" ref="price" autocomplete="price" /> <jet-input id="price" type="text" class="mt-1 block w-full" v-model="form.price" ref="price" autocomplete="price" />
<jet-input-error :message="form.errors.price" class="mt-2" /> <jet-input-error :message="form.errors.price" class="mt-2" />
</div> </div>
<div v-if="form.is_sell_contract" class="col-span-6 sm:col-span-4"> <div v-if="form.is_sell_contract" class="col-span-6 sm:col-span-4">
<jet-label for="insurance_type" value="Versicherung" /> <jet-label for="insurance_type" value="Versicherung" />
<multiselect class="mt-1 block w-full" @select="updateInsuranceSelection" v-model="insuranceSelection" deselect-label="Kann nicht entfernt werden" track-by="key" label="label" placeholder="Versicherung auswählen" :options="insurances" :searchable="false" :allow-empty="false" /> <multiselect class="mt-1 block w-full" @select="updateInsuranceSelection" v-model="insuranceSelection" deselect-label="Kann nicht entfernt werden" track-by="key" label="label" placeholder="Versicherung auswählen" :options="insurances" :searchable="false" :allow-empty="false" />
<jet-input-error :message="form.errors.insurance_type" class="mt-2" /> <jet-input-error :message="form.errors.insurance_type" class="mt-2" />
</div>
</div> </div>
</template> </template>
<template #actions> <template #actions>

View File

@ -2,37 +2,50 @@
<layout> <layout>
<template #header> <template #header>
<h2 class="font-semibold text-xl text-gray-800 leading-tight"> <h2 class="font-semibold text-xl text-gray-800 leading-tight">
<bread-crumb text="Autos" :href="route('cars')" /> <bread-crumb v-if="car_first" text="Autos" :href="route('cars')" />
Neuen Vertrag erstellen <bread-crumb v-else text="Kontakte" :href="route('contacts')" />
<bread-crumb v-if="car_first" :text="car.name" :href="route('cars.show', car.id)" />
<bread-crumb :text="contact.name" :href="route('contacts.show', contact.id)" />
<bread-crumb v-if="!car_first" :text="car.name" :href="route('cars.show', car.id)" />
Neuen {{ contractType }} erstellen
</h2> </h2>
</template> </template>
<div> <div>
<jet-form-section class="max-w-7xl pb-5 sm:px-6 lg:px-8"> <jet-form-section v-if="!car_first" emptyBg="true" class="max-w-7xl mb-5">
<template #title>
{{ contactType }}
</template>
<template #description>
Ausgewählter {{ contactType }} für diesen {{ contractType }}
</template>
<template #form>
<contact-card class="col-span-12" :contact="contact" />
</template>
</jet-form-section>
<jet-form-section class="max-w-7xl" emptyBg="true">
<template #title> <template #title>
Auto Auto
</template> </template>
<template #description> <template #description>
Ausgewähltes Auto für diesen Vertrag Ausgewähltes Auto für diesen {{ contractType }}
</template> </template>
<template #form> <template #form>
<car-card class="col-span-12" :car="car" /> <car-card class="col-span-12" :car="car" />
</template> </template>
</jet-form-section> </jet-form-section>
<jet-form-section class="max-w-7xl py-5 sm:px-6 lg:px-8"> <jet-form-section v-if="car_first" emptyBg="true" class="max-w-7xl mt-5">
<template #title> <template #title>
Kontakt {{ contactType }}
</template> </template>
<template #description> <template #description>
Ausgewählter Kontakt für diesen Vertrag Ausgewählter {{ contactType }} für diesen {{ contractType }}
</template> </template>
<template #form> <template #form>
<contact-card class="col-span-4" :contact="contact" /> <contact-card class="col-span-12" :contact="contact" />
</template> </template>
</jet-form-section> </jet-form-section>
<contract-form :data="data" :meta="meta"> <contract-form class="mt-5" :data="data" :meta="meta">
<template #title>Vertragsinformationen erfassen</template> <template #title>Vertragsinformationen erfassen</template>
<template #description>Der Vertrag kann anschliessend gespeichert werden.</template> <template #description>Der Vertrag kann anschliessend gespeichert werden.</template>
</contract-form> </contract-form>
@ -61,6 +74,7 @@ export default {
car: Object, car: Object,
contact: Object, contact: Object,
type: String, type: String,
car_first: Boolean,
}, },
data() { data() {
return { return {
@ -79,9 +93,19 @@ export default {
insurance_type: '0', insurance_type: '0',
car_id: this.car.id, car_id: this.car.id,
contact_id: this.contact.id, contact_id: this.contact.id,
}, },
} }
}, },
computed: {
contractType: function () {
return this.isSellContract ? "Verkaufsvertrag" : "Ankaufsvertrag";
},
contactType: function () {
return this.isSellContract ? "Käufer" : "Verkäufer";
},
isSellContract: function () {
return this.type == "SellContract";
},
}
} }
</script> </script>

View File

@ -3,41 +3,63 @@
<template #header> <template #header>
<h2 class="font-semibold text-xl text-gray-800 leading-tight"> <h2 class="font-semibold text-xl text-gray-800 leading-tight">
<bread-crumb text="Autos" :href="route('cars')" /> <bread-crumb text="Autos" :href="route('cars')" />
Neuen Vertrag erstellen <bread-crumb :text="car.name" :href="route('cars.show', car.id)" />
Neuen {{ contractType }} erstellen
</h2> </h2>
</template> </template>
<div> <div>
<jet-form-section class="max-w-7xl"> <jet-form-section class="max-w-7xl" emptyBg="true">
<template #title> <template #title>
Auto Auto
</template> </template>
<template #description> <template #description>
Ausgewähltes Auto für diesen Vertrag Ausgewähltes Auto für diesen {{ contractType }}
</template> </template>
<template #form> <template #form>
<car-card class="col-span-12" :car="car" /> <car-card class="col-span-12" :car="car" />
</template> </template>
</jet-form-section> </jet-form-section>
<jet-form-section class="max-w-7xl py-5 sm:px-6 lg:px-8"> <jet-form-section class="max-w-7xl mt-5">
<template #title> <template #title>
Kontakt {{ contactType }}
</template> </template>
<template #description> <template #description>
Kontakt auswählen oder neu erfassen {{ contactType }} auswählen oder neu erfassen
<contact-card v-if="contact.firstname || contact.company" class="col-span-4" :contact="contact" />
</template> </template>
<template #form> <template #form>
<div class="col-span-3"> <div class="col-span-3">
<jet-label for="contact" value="Marke" /> <jet-label for="contact" :value="contactType" />
<jet-input id="contact" type="text" class="mt-1 block w-full" v-model="contact.id" ref="contact" autocomplete="contact" /> <multiselect :disabled="createContact" v-model="contact" label="title" track-by="id" :options="contactsChoice" class="mt-1 block w-full" placeholder="Vertragspartner auswählen" />
<!-- <jet-input-error :message="form.errors.contact" class="mt-2" /> --> </div>
<div class="col-span-6">
<contact-card v-if="contact.id" class="mt-3 col-span-4" :contact="contact" />
</div> </div>
<div class="col-span-6"> <div class="col-span-6">
oder oder
</div> </div>
<div class="col-span-6"> <div v-if="!createContact" class="col-span-6">
<standard-button class="" href="" colour="gray">Neu erfassen</standard-button> <button @click="openContactForm" class="bg-gray-800 hover:bg-gray-700 active:bg-gray-900 focus:border-gray-900 focus:ring-gray-300 justify-center inline-flex items-center px-4 py-2 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest focus:outline-none focus:ring disabled:opacity-25 transition">
Neu erfassen
</button>
</div> </div>
<div v-else class="col-span-6">
<p class="w-full mb-1 font-bold">Neuen Kontakt erfassen:</p>
<form @submit="submitCreateContactForm">
<div class="grid grid-cols-6 gap-6">
<contact-form-fields :form="contact" />
<div class="col-span-6 sm:col-span-4 flex items-center justify-end text-right">
<jet-button>
Kontakt speichern
</jet-button>
</div>
</div>
</form>
</div>
</template>
<template #actions>
<jet-button :disabled="!contact.id" @click="nextPage">
Nächster Schritt
</jet-button>
</template> </template>
</jet-form-section> </jet-form-section>
</div> </div>
@ -47,11 +69,14 @@
<script> <script>
import Layout from '@/Layouts/Layout' import Layout from '@/Layouts/Layout'
import BreadCrumb from '@/Components/BreadCrumb.vue' import BreadCrumb from '@/Components/BreadCrumb.vue'
import ContactForm from '@/Pages/Contacts/Components/ContactForm.vue' import ContactFormFields from '@/Pages/Contacts/Components/ContactFormFields.vue'
import CarCard from '@/Components/CarCard.vue' import CarCard from '@/Components/CarCard.vue'
import ContactCard from '@/Components/ContactCard.vue' import ContactCard from '@/Components/ContactCard.vue'
import JetFormSection from '@/Jetstream/FormSection' import JetFormSection from '@/Jetstream/FormSection'
import StandardButton from '@/Components/Buttons/StandardButton.vue' import Multiselect from 'vue-multiselect'
import JetLabel from '@/Jetstream/Label.vue'
import JetButton from '@/Jetstream/Button'
import JetActionMessage from '@/Jetstream/ActionMessage'
export default { export default {
components: { components: {
@ -60,8 +85,11 @@ export default {
CarCard, CarCard,
ContactCard, ContactCard,
JetFormSection, JetFormSection,
ContactForm, ContactFormFields,
StandardButton, Multiselect,
JetLabel,
JetButton,
JetActionMessage,
}, },
props: { props: {
car: Object, car: Object,
@ -70,11 +98,7 @@ export default {
}, },
data() { data() {
return { return {
meta: { contactsChoice: this.contacts,
link: 'contacts.store',
button_text: 'Kontakt speichern',
on_success: 'Kontakt gespeichert',
},
contact: { contact: {
id: null, id: null,
firstname: null, firstname: null,
@ -87,15 +111,70 @@ export default {
city: null, city: null,
country: null, country: null,
notes: null, notes: null,
errors: {},
}, },
meta: { createContact: false,
form_name: 'CreateContractFromCar',
// route: this.route('contracts.create', this.car.id, this.contact.id),
method: 'post',
button_text: 'Vertrag speichern',
on_success: 'Vertrag gespeichert',
},
} }
}, },
computed: {
contractType: function () {
return this.isSellContract ? "Verkaufsvertrag" : "Ankaufsvertrag";
},
contactType: function () {
return this.isSellContract ? "Käufer" : "Verkäufer";
},
isSellContract: function () {
return this.type == "SellContract";
},
emptyContact: function() {
return {
id: null,
firstname: null,
lastname: null,
company: null,
email: null,
phone: null,
address: null,
zip: null,
city: null,
country: null,
notes: null,
errors: {},
};
},
},
methods: {
nextPage() {
this.$inertia.get(route('contracts.create', {
type: this.isSellContract ? 1 : 0,
car: this.car.id,
contact: this.contact.id,
}), { preserveScroll: true, carFirst: true, });
},
openContactForm() {
this.createContact = true;
this.contact = this.emptyContact;
},
submitCreateContactForm(e) {
e.preventDefault();
axios.post(this.route('contacts.store_for_contract'), this.contact)
.then(res => {
this.contactsChoice.push(res.data);
this.contact = res.data;
this.createContact = false;
}).catch(err => {
if (err.response) {
let errors = err.response.data.errors;
Object.keys(errors).map(function(key, index) {
errors[key] = errors[key].join(' ');
});
this.contact.errors = errors;
}
});
},
},
} }
</script> </script>
<style src="vue-multiselect/dist/vue-multiselect.css"></style>

View File

@ -0,0 +1,181 @@
<template>
<layout>
<template #header>
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
<bread-crumb text="Kontakte" :href="route('contacts')" />
<bread-crumb :text="contact.name" :href="route('contacts.show', contact.id)" />
Neuen {{ contractType }} erstellen
</h2>
</template>
<div>
<jet-form-section class="max-w-7xl" emptyBg="true">
<template #title>
{{ contactType }}
</template>
<template #description>
Ausgewählter {{ contactType }} für diesen {{ contractType }}
</template>
<template #form>
<contact-card class="col-span-12" :contact="contact" />
</template>
</jet-form-section>
<jet-form-section class="max-w-7xl mt-5">
<template #title>
Auto
</template>
<template #description>
Auto auswählen oder neu erfassen
</template>
<template #form>
<div class="col-span-3">
<jet-label for="car" value="Auto" />
<multiselect :disabled="createCar" v-model="car" label="name" track-by="id" :options="carsChoice" class="mt-1 block w-full" placeholder="Auto auswählen" />
</div>
<div class="col-span-6">
<car-card v-if="car.id" class="mt-3 col-span-6" :car="car" />
</div>
<div class="col-span-6">
oder
</div>
<div v-if="!createCar" class="col-span-6">
<button @click="openCarForm" class="bg-gray-800 hover:bg-gray-700 active:bg-gray-900 focus:border-gray-900 focus:ring-gray-300 justify-center inline-flex items-center px-4 py-2 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest focus:outline-none focus:ring disabled:opacity-25 transition">
Neu erfassen
</button>
</div>
<div v-else class="col-span-6">
<p class="w-full mb-1 font-bold">Neues Auto erfassen:</p>
<form @submit="submitCreateCarForm">
<div class="grid grid-cols-6 gap-6">
<car-form-fields :form="car" :car_model="car_model" :brand="brand" :brands="brands" />
<div class="col-span-6 sm:col-span-4 flex items-center justify-end text-right">
<jet-button>
Auto speichern
</jet-button>
</div>
</div>
</form>
</div>
</template>
<template #actions>
<jet-button :disabled="!car.id" @click="nextPage">
Nächster Schritt
</jet-button>
</template>
</jet-form-section>
</div>
</layout>
</template>
<script>
import Layout from '@/Layouts/Layout'
import BreadCrumb from '@/Components/BreadCrumb.vue'
import CarFormFields from '@/Pages/Cars/Components/CarFormFields.vue'
import CarCard from '@/Components/CarCard.vue'
import ContactCard from '@/Components/ContactCard.vue'
import JetFormSection from '@/Jetstream/FormSection'
import Multiselect from 'vue-multiselect'
import JetLabel from '@/Jetstream/Label.vue'
import JetButton from '@/Jetstream/Button'
import JetActionMessage from '@/Jetstream/ActionMessage'
export default {
components: {
Layout,
BreadCrumb,
CarCard,
ContactCard,
CarFormFields,
JetFormSection,
Multiselect,
JetLabel,
JetButton,
JetActionMessage,
},
props: {
contact: Object,
cars: Object,
brands: Object,
type: String,
},
data() {
return {
carsChoice: this.cars,
car: {
id: null,
stammnummer: null,
vin: null,
colour: null,
car_model_id: null,
initial_date: null,
last_check_date: null,
kilometers: null,
known_damage: null,
notes: null,
errors: {},
},
brand: {id: null, name: null},
car_model: {id: null, name: null},
createCar: false,
}
},
computed: {
contractType: function () {
return this.isSellContract ? "Verkaufsvertrag" : "Ankaufsvertrag";
},
contactType: function () {
return this.isSellContract ? "Käufer" : "Verkäufer";
},
isSellContract: function () {
return this.type == "SellContract";
},
emptyCar: function() {
return {
id: null,
stammnummer: null,
vin: null,
colour: null,
car_model_id: null,
initial_date: null,
last_check_date: null,
kilometers: null,
known_damage: null,
notes: null,
errors: {},
};
},
},
methods: {
nextPage() {
this.$inertia.get(route('contracts.create', {
type: this.isSellContract ? 1 : 0,
car: this.car.id,
contact: this.contact.id,
}), { preserveScroll: true });
},
openCarForm() {
this.createCar = true;
this.car = this.emptyCar;
},
submitCreateCarForm(e) {
e.preventDefault();
axios.post(this.route('cars.store_for_contract'), this.car)
.then(res => {
this.carsChoice.push(res.data);
this.car = res.data;
this.createCar = false;
}).catch(err => {
if (err.response) {
let errors = err.response.data.errors;
Object.keys(errors).map(function(key, index) {
errors[key] = errors[key].join(' ');
});
this.car.errors = errors;
}
});
},
},
}
</script>
<style src="vue-multiselect/dist/vue-multiselect.css"></style>

View File

@ -53,6 +53,10 @@ Route::post('contacts', [ContactController::class, 'store'])
->name('contacts.store') ->name('contacts.store')
->middleware(['auth:sanctum', 'verified']); ->middleware(['auth:sanctum', 'verified']);
Route::post('contacts/store_for_contract', [ContactController::class, 'storeForContract'])
->name('contacts.store_for_contract')
->middleware(['auth:sanctum', 'verified']);
Route::get('contacts/{contact}/edit', [ContactController::class, 'edit']) Route::get('contacts/{contact}/edit', [ContactController::class, 'edit'])
->name('contacts.edit') ->name('contacts.edit')
->middleware(['auth:sanctum', 'verified']); ->middleware(['auth:sanctum', 'verified']);
@ -113,6 +117,10 @@ Route::post('cars', [CarController::class, 'store'])
->name('cars.store') ->name('cars.store')
->middleware(['auth:sanctum', 'verified']); ->middleware(['auth:sanctum', 'verified']);
Route::post('cars/store_for_contract', [CarController::class, 'storeForContract'])
->name('cars.store_for_contract')
->middleware(['auth:sanctum', 'verified']);
Route::post('brands', [BrandController::class, 'store']) Route::post('brands', [BrandController::class, 'store'])
->name('brands.store') ->name('brands.store')
->middleware(['auth:sanctum', 'verified']); ->middleware(['auth:sanctum', 'verified']);
@ -129,15 +137,18 @@ Route::get('contracts/{contract}/print', [ContractController::class, 'print'])
->name('contracts.print') ->name('contracts.print')
->middleware(['auth:sanctum', 'verified']); ->middleware(['auth:sanctum', 'verified']);
Route::get('contracts/create/car/{car}/contact/{contact}', [ContractController::class, 'create']) Route::get('contracts/create/{type}/car/{car}/contact/{contact}', [ContractController::class, 'create'])
->where('type', '0|1')
->name('contracts.create') ->name('contracts.create')
->middleware(['auth:sanctum', 'verified']); ->middleware(['auth:sanctum', 'verified']);
Route::get('contracts/create/car/{car}', [ContractController::class, 'createFromCar']) Route::get('contracts/create/{type}/car/{car}', [ContractController::class, 'createFromCar'])
->where('type', '0|1')
->name('contracts.create_from_car') ->name('contracts.create_from_car')
->middleware(['auth:sanctum', 'verified']); ->middleware(['auth:sanctum', 'verified']);
Route::get('contracts/create/contact/{contact}', [ContractController::class, 'createFromContact']) Route::get('contracts/create/{type}/contact/{contact}', [ContractController::class, 'createFromContact'])
->where('type', '0|1')
->name('contracts.create_from_contact') ->name('contracts.create_from_contact')
->middleware(['auth:sanctum', 'verified']); ->middleware(['auth:sanctum', 'verified']);