diff --git a/app/Http/Controllers/BuyContractController.php b/app/Http/Controllers/BuyContractController.php new file mode 100644 index 0000000..9c0d49d --- /dev/null +++ b/app/Http/Controllers/BuyContractController.php @@ -0,0 +1,10 @@ + $car->id, 'stammnummer' => $car->stammnummer, 'vin' => $car->vin, - 'bought_at' => $car->bought_at, - 'buy_price' => $car->buy_price->format(), + 'buy_price' => $car->latestSellerContract() ? $car->latestSellerContract()->price : '', + // 'buy_price' => $car->buy_price->format(), // 'seller' => $car->seller->only('name'), // 'buyer' => $car->buyer->only('name'), 'car_model' => $car->carModel->only('name'), diff --git a/app/Http/Controllers/ContactController.php b/app/Http/Controllers/ContactController.php index 5d04137..9a4489c 100644 --- a/app/Http/Controllers/ContactController.php +++ b/app/Http/Controllers/ContactController.php @@ -19,10 +19,16 @@ class ContactController extends Controller */ public function index(Request $request) { + $sortby = $request->only('sortby') ?: 'lastname'; + $direction = $request->only('direction') ?: 'asc'; return Inertia::render('Contacts/Index', [ 'filters' => $request->all('search', 'trashed'), + 'sort' => [ + 'by' => $sortby, + 'direction' => $direction, + ], 'contacts' => Contact::filter($request->only('search', 'trashed')) - ->orderByName() + ->orderBy($sortby, $direction) ->paginate(50) ->withQueryString() ->through(fn ($contact) => [ @@ -95,23 +101,24 @@ class ContactController extends Controller 'city' => $contact->city, 'country' => $contact->country, 'deleted_at' => $contact->deleted_at, - 'bought_cars' => $contact->contracts() + 'bought_cars' => $contact->buyContracts() ->with('car') ->paginate(10) ->through(fn ($contract) => [ - 'sold_at' => $contract->sold_at, - 'sell_price' => $contract->sell_price, + 'date' => $contract->date, + 'price' => $contract->price, 'name' => $contract->car->name, 'link' => route('cars.edit', $contract->car), 'insurance_type' => InsuranceType::fromValue((int)$contract->insurance_type)->key, ]), - 'sold_cars' => $contact->soldCars() + 'sold_cars' => $contact->sellContracts() + ->with('car') ->paginate(10) - ->through(fn ($car) => [ - 'bought_at' => $car->bought_at, - 'buy_price' => $car->buy_price, - 'name' => $car->name, - 'link' => route('cars.edit', $car), + ->through(fn ($contract) => [ + 'date' => $contract->date, + 'price' => $contract->price, + 'name' => $contract->car->name, + 'link' => route('cars.edit', $contract->car), ]), ] ]); diff --git a/app/Models/BuyContract.php b/app/Models/BuyContract.php new file mode 100644 index 0000000..54a7ae4 --- /dev/null +++ b/app/Models/BuyContract.php @@ -0,0 +1,41 @@ +format('d.m.Y'); + } + + public function getPriceAttribute($price) + { + return Money::CHF($price)->format(); + } + + public function contact() + { + return $this->belongsTo(Contact::class); + } + + public function car() + { + return $this->belongsTo(Car::class); + } +} diff --git a/app/Models/Car.php b/app/Models/Car.php index d85553a..59ffb2c 100644 --- a/app/Models/Car.php +++ b/app/Models/Car.php @@ -21,9 +21,6 @@ class Car extends Model 'initial_date', 'last_check_date', 'kilometers', - 'bought_at', - 'buy_price', - 'seller_contact_id', 'car_model_id', ]; @@ -39,21 +36,10 @@ class Car extends Model return $kilometers; } - public function getStammnummerAttribute($stammnummer) - { - $out = substr($stammnummer, 0, 3); - $out .= '.'; - $out .= substr($stammnummer, 3, 3); - $out .= '.'; - $out .= substr($stammnummer, 6, 3); - - return $out; - } - - public function getBuyPriceAttribute($price) - { - return Money::CHF($price); - } + // public function getBuyPriceAttribute() + // { + // return Money::CHF($this->buyContracts()->price); + // } public function getInitialDateAttribute($initialDate) { @@ -69,41 +55,66 @@ class Car extends Model { return $this->belongsTo(CarModel::class); } - - public function seller() + + public function latestSellerContract() { - return $this->belongsTo(Contact::class, 'seller_contact_id'); + return $this->sellContracts()->latest('date')->first(); } - public function buyer() + public function latestBuyerContracts() { - return $this->hasOneThrough(Contract::class, Contact::class); + return $this->buyContracts()->latest('date')->first(); } - public function contract() + public function isUnsold() { - return $this->hasOne(Contract::class); + return $this->sellers()->count() > $this->buyers()->count(); + } + + public function isSold() + { + return $this->sellers()->count() == $this->buyers()->count(); + } + + public function sellers() + { + return $this->hasManyThrough(SellContract::class, Contact::class); + } + + public function buyers() + { + return $this->hasManyThrough(BuyContract::class, Contact::class); + } + + public function buyContracts() + { + return $this->hasMany(buyContract::class); + } + + public function sellContracts() + { + return $this->hasMany(sellContract::class); } public function carPayment() { - return $this->hasManyThrough(CarPayment::class, Contract::class); + return $this->hasManyThrough(CarPayment::class, SellContract::class); } - public function scopeSoldThisYear($query) - { - return $query->whereDate('sold_at', '>=', Carbon::today()->format('Y')); - } + // public function scopeSoldThisYear($query) + // { + // return $query->whereDate('sold_at', '>=', Carbon::today()->format('Y')); + // } - public function scopeSoldCars($query) - { - return $query->whereDate('sold_at', '>=', Carbon::today()->format('Y')); - } + // public function scopeSoldCars($query) + // { + // return $query->whereDate('sold_at', '>=', Carbon::today()->format('Y')); + // } - public function scopeUnsoldCars($query) - { - return $query->whereDate('sold_at', ); - } + // public function scopeUnsoldCars($query) + // { + // return $query->whereDate('sold_at', ); + // } public function scopeOrderByInitialDate($query) { diff --git a/app/Models/CarPayment.php b/app/Models/CarPayment.php index d828f26..bcb1e61 100644 --- a/app/Models/CarPayment.php +++ b/app/Models/CarPayment.php @@ -11,18 +11,18 @@ class CarPayment extends Model protected $fillable = [ 'amount', - 'paid_at', - 'payment_type', - 'contract_id' + 'date', + 'type', + 'sell_contract_id', ]; - public function contract() + public function sellContract() { - return $this->belongsTo(Contract::class); + return $this->belongsTo(SellContract::class); } public function car() { - return $this->hasOneThrough(Car::class, Contract::class); + return $this->hasOneThrough(Car::class, SellContract::class); } } diff --git a/app/Models/Contact.php b/app/Models/Contact.php index 1482909..d60560c 100644 --- a/app/Models/Contact.php +++ b/app/Models/Contact.php @@ -47,19 +47,24 @@ class Contact extends Model $query->orderBy('lastname')->orderBy('firstname'); } - public function contracts() + public function sellContracts() { - return $this->hasMany(Contract::class); + return $this->hasMany(SellContract::class); + } + + public function buyContracts() + { + return $this->hasMany(BuyContract::class); } public function boughtCars() { - return $this->hasManyThrough(Car::class, Contract::class); + return $this->hasManyThrough(Car::class, SellContract::class); } public function soldCars() { - return $this->hasMany(Car::class, 'seller_contact_id'); + return $this->hasManyThrough(Car::class, BuyContract::class); } public function scopeFilter($query, array $filters) diff --git a/app/Models/Contract.php b/app/Models/SellContract.php similarity index 60% rename from app/Models/Contract.php rename to app/Models/SellContract.php index dfc9f2e..22e1321 100644 --- a/app/Models/Contract.php +++ b/app/Models/SellContract.php @@ -2,22 +2,34 @@ namespace App\Models; +use Carbon\Carbon; +use Cknow\Money\Money; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; -class Contract extends Model +class SellContract extends Model { use HasFactory, softDeletes; protected $fillable = [ - 'sold_at', - 'sell_price', + 'date', + 'price', 'contact_id', 'car_id', 'insurance_type', ]; + public function getDateAttribute($date) + { + return Carbon::parse($date)->format('d.m.Y'); + } + + public function getPriceAttribute($price) + { + return Money::CHF($price)->format(); + } + public function contact() { return $this->belongsTo(Contact::class); diff --git a/database/factories/BuyContractFactory.php b/database/factories/BuyContractFactory.php new file mode 100644 index 0000000..41a15ab --- /dev/null +++ b/database/factories/BuyContractFactory.php @@ -0,0 +1,33 @@ + $this->faker->date(), + 'price' => $this->faker->numberBetween(150000, 3500000), + 'contact_id' => $this->faker->numberBetween(1, Contact::count()), + 'car_id' => $this->faker->unique()->numberBetween(1, Car::count()), + ]; + } +} diff --git a/database/factories/CarFactory.php b/database/factories/CarFactory.php index dfeee94..b849007 100644 --- a/database/factories/CarFactory.php +++ b/database/factories/CarFactory.php @@ -4,7 +4,6 @@ namespace Database\Factories; use App\Models\Car; use App\Models\CarModel; -use App\Models\Contact; use Illuminate\Database\Eloquent\Factories\Factory; class CarFactory extends Factory @@ -24,17 +23,14 @@ class CarFactory extends Factory public function definition() { return [ - 'stammnummer' => $this->faker->regexify('[0-9]{3}.[0-9]{3}.[0-9]{3}'), + 'stammnummer' => $this->faker->randomNumber(3, true) . '.' . $this->faker->randomNumber(3, true) . '.' . $this->faker->randomNumber(3, true), 'vin' => $this->faker->regexify('[A-Z]{3}ZZZ[A-Z0-9]{3}[A-Z1-9]{1}[A-Z]{1}[0-9]{6}'), 'colour' => $this->faker->safeColorName(), 'notes' => $this->faker->paragraph(), 'known_damage' => $this->faker->paragraph(), 'initial_date' => $this->faker->date(), 'last_check_date' => $this->faker->date(), - 'bought_at' => $this->faker->date(), 'kilometers' => $this->faker->numberBetween(5000, 200000), - 'buy_price' => $this->faker->numberBetween(100000, 3000000), - 'seller_contact_id' => $this->faker->numberBetween(1, Contact::count()), 'car_model_id' => $this->faker->numberBetween(1, CarModel::count()), ]; } diff --git a/database/factories/CarPaymentFactory.php b/database/factories/CarPaymentFactory.php index fd9f28a..82313ff 100644 --- a/database/factories/CarPaymentFactory.php +++ b/database/factories/CarPaymentFactory.php @@ -5,7 +5,7 @@ namespace Database\Factories; use App\Models\CarPayment; use Illuminate\Database\Eloquent\Factories\Factory; use App\Enums\PaymentType; -use App\Models\Contract; +use App\Models\SellContract; class CarPaymentFactory extends Factory { @@ -25,9 +25,9 @@ class CarPaymentFactory extends Factory { return [ 'amount' => $this->faker->numberBetween(1000, 10000), - 'paid_at' => $this->faker->date(), - 'payment_type' => (string)PaymentType::getRandomValue(), - 'contract_id' => $this->faker->numberBetween(1, Contract::count()), + 'date' => $this->faker->date(), + 'type' => (string)PaymentType::getRandomValue(), + 'sell_contract_id' => $this->faker->numberBetween(1, SellContract::count()), ]; } } diff --git a/database/factories/ContactFactory.php b/database/factories/ContactFactory.php index 285f0da..235cd60 100644 --- a/database/factories/ContactFactory.php +++ b/database/factories/ContactFactory.php @@ -33,7 +33,7 @@ class ContactFactory extends Factory 'address' => $this->faker->streetName() . ' ' . $this->faker->buildingNumber(), 'zip' => $this->faker->randomNumber(4, true), 'city' => $this->faker->city(), - 'country' => $this->faker->countryCode(), + 'country' => 'CH', 'company' => $this->faker->company(), 'notes' => $this->faker->text(), ]; diff --git a/database/factories/ContractFactory.php b/database/factories/SellContractFactory.php similarity index 65% rename from database/factories/ContractFactory.php rename to database/factories/SellContractFactory.php index c3c8f0f..d1bffff 100644 --- a/database/factories/ContractFactory.php +++ b/database/factories/SellContractFactory.php @@ -2,20 +2,20 @@ namespace Database\Factories; -use App\Models\Contract; +use App\Models\SellContract; use App\Models\Car; use App\Models\Contact; use Illuminate\Database\Eloquent\Factories\Factory; use App\Enums\InsuranceType; -class ContractFactory extends Factory +class SellContractFactory extends Factory { /** * The name of the factory's corresponding model. * * @var string */ - protected $model = Contract::class; + protected $model = SellContract::class; /** * Define the model's default state. @@ -25,10 +25,10 @@ class ContractFactory extends Factory public function definition() { return [ - 'sold_at' => $this->faker->date(), - 'sell_price' => $this->faker->numberBetween(150000, 3500000), + 'date' => $this->faker->date(), + 'price' => $this->faker->numberBetween(150000, 3500000), 'contact_id' => $this->faker->numberBetween(1, Contact::count()), - 'car_id' => $this->faker->unique()->numberBetween(1, Car::count()), + 'car_id' => $this->faker->numberBetween(1, Car::count()), 'insurance_type' => (string)InsuranceType::getRandomValue(), ]; } diff --git a/database/migrations/2021_05_10_135957_create_cars_table.php b/database/migrations/2021_05_10_135957_create_cars_table.php index 960af99..c8d1fc0 100644 --- a/database/migrations/2021_05_10_135957_create_cars_table.php +++ b/database/migrations/2021_05_10_135957_create_cars_table.php @@ -22,17 +22,13 @@ class CreateCarsTable extends Migration $table->text('known_damage')->nullable(); $table->date('initial_date'); $table->date('last_check_date'); - $table->date('bought_at'); - $table->integer('buy_price'); $table->integer('kilometers'); - $table->unsignedBigInteger('seller_contact_id'); $table->foreignId('car_model_id') ->onUpdate('cascade') ->onDelete('cascade') ->constrained('car_models'); $table->timestamps(); $table->softDeletes(); - $table->foreign('seller_contact_id')->references('id')->on('contacts'); }); } diff --git a/database/migrations/2021_05_10_144041_create_contracts_table.php b/database/migrations/2021_05_10_144041_create_sell_contracts_table.php similarity index 79% rename from database/migrations/2021_05_10_144041_create_contracts_table.php rename to database/migrations/2021_05_10_144041_create_sell_contracts_table.php index ee0001a..25c9db4 100644 --- a/database/migrations/2021_05_10_144041_create_contracts_table.php +++ b/database/migrations/2021_05_10_144041_create_sell_contracts_table.php @@ -5,7 +5,7 @@ use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; use App\Enums\InsuranceType; -class CreateContractsTable extends Migration +class CreateSellContractsTable extends Migration { /** * Run the migrations. @@ -14,10 +14,10 @@ class CreateContractsTable extends Migration */ public function up() { - Schema::create('contracts', function (Blueprint $table) { + Schema::create('sell_contracts', function (Blueprint $table) { $table->id(); - $table->date('sold_at'); - $table->integer('sell_price'); + $table->date('date'); + $table->integer('price'); $table->foreignId('contact_id') ->onUpdate('cascade') ->onDelete('cascade') @@ -40,6 +40,6 @@ class CreateContractsTable extends Migration */ public function down() { - Schema::dropIfExists('contracts'); + Schema::dropIfExists('sell_contracts'); } } diff --git a/database/migrations/2021_05_10_144704_create_car_payments_table.php b/database/migrations/2021_05_10_144704_create_car_payments_table.php index 0f9a15a..62fc409 100644 --- a/database/migrations/2021_05_10_144704_create_car_payments_table.php +++ b/database/migrations/2021_05_10_144704_create_car_payments_table.php @@ -17,13 +17,13 @@ class CreateCarPaymentsTable extends Migration Schema::create('car_payments', function (Blueprint $table) { $table->id(); $table->integer('amount'); - $table->date('paid_at'); - $table->enum('payment_type', PaymentType::getValues()) + $table->date('date'); + $table->enum('type', PaymentType::getValues()) ->default(PaymentType::Transaction); - $table->foreignId('contract_id') + $table->foreignId('sell_contract_id') ->onUpdate('cascade') ->onDelete('cascade') - ->constrained('contracts'); + ->constrained('sell_contracts'); $table->timestamps(); }); } diff --git a/database/migrations/2021_05_14_071143_create_buy_contracts_table.php b/database/migrations/2021_05_14_071143_create_buy_contracts_table.php new file mode 100644 index 0000000..6e23a8d --- /dev/null +++ b/database/migrations/2021_05_14_071143_create_buy_contracts_table.php @@ -0,0 +1,42 @@ +id(); + $table->date('date'); + $table->integer('price'); + $table->foreignId('contact_id') + ->onUpdate('cascade') + ->onDelete('cascade') + ->constrained('contacts'); + $table->foreignId('car_id') + ->onUpdate('cascade') + ->onDelete('cascade') + ->constrained('cars'); + $table->timestamps(); + $table->softDeletes(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('buy_contracts'); + } +} diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index d0fb787..3e0f6f1 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -9,7 +9,8 @@ use App\Models\Car; use App\Models\CarModel; use App\Models\Brand; use App\Models\CarPayment; -use App\Models\Contract; +use App\Models\BuyContract; +use App\Models\SellContract; use App\Models\Contact; use App\Models\Document; use Illuminate\Support\Facades\DB; @@ -26,7 +27,8 @@ class DatabaseSeeder extends Seeder DB::statement('SET FOREIGN_KEY_CHECKS=0;'); User::truncate(); CarPayment::truncate(); - Contract::truncate(); + BuyContract::truncate(); + SellContract::truncate(); Document::truncate(); Car::truncate(); Contact::truncate(); @@ -55,23 +57,28 @@ class DatabaseSeeder extends Seeder ->create(); $contacts = Contact::factory() - ->count(100) + ->count(60) ->create(); + $nOfCars = 75; $cars = Car::factory() + ->count($nOfCars) + ->create(); + + $buyContracts = BuyContract::factory() + ->count($nOfCars) + ->create(); + + $sellContracts = SellContract::factory() ->count(40) ->create(); - $contracts = Contract::factory() - ->count(20) - ->create(); - $carPayments = CarPayment::factory() - ->count(15) + ->count(60) ->create(); $documents = Document::factory() - ->count(10) + ->count(40) ->create(); } diff --git a/public/js/app.js b/public/js/app.js index f8c01cf..c35173f 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -18156,10 +18156,10 @@ __webpack_require__.r(__webpack_exports__); key: 'name', value: 'Auto' }, { - key: 'sold_at', + key: 'date', value: 'Verkaufsdatum' }, { - key: 'sell_price', + key: 'price', value: 'Verkaufspreis' }, { key: 'insurance_type', @@ -18169,10 +18169,10 @@ __webpack_require__.r(__webpack_exports__); key: 'name', value: 'Auto' }, { - key: 'bought_at', + key: 'date', value: 'Kaufdatum' }, { - key: 'buy_price', + key: 'price', value: 'Kaufpreis' }] }; @@ -18195,8 +18195,7 @@ __webpack_require__.r(__webpack_exports__); address: this.form.address, zip: this.form.zip, city: this.form.city, - country: this.form.country, - link: route('contacts.update', this.contact) + country: this.form.country }; } }, @@ -18242,6 +18241,7 @@ __webpack_require__.r(__webpack_exports__); }, props: { filters: Object, + sort: Object, contacts: Object }, data: function data() { @@ -19360,7 +19360,7 @@ var _hoisted_7 = { }; var _hoisted_8 = { key: 1, - "class": "px-4 flex items-center" + "class": "flex items-center" }; var _hoisted_9 = { key: 1, @@ -19402,7 +19402,7 @@ function render(_ctx, _cache, $props, $setup, $data, $options) { onClick: function onClick($event) { return $options.sortTable(col.key); }, - "class": "px-4 flex items-center" + "class": "flex items-center" }, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createTextVNode)((0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)(col.value) + " ", 1 /* TEXT */ ), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)("div", _hoisted_7, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)(_component_unicon, { @@ -23134,13 +23134,10 @@ function render(_ctx, _cache, $props, $setup, $data, $options) { title: $props.contacts.total + ' Kontakte', data: $props.contacts, columns: $data.columns, - defaultSort: { - by: 'name', - direction: 'asc' - } + defaultSort: $props.sort }, null, 8 /* PROPS */ - , ["title", "data", "columns"])])])]; + , ["title", "data", "columns", "defaultSort"])])])]; }), _: 1 /* STABLE */ diff --git a/resources/js/Components/SimpleTable.vue b/resources/js/Components/SimpleTable.vue index 80837ff..7a977e0 100644 --- a/resources/js/Components/SimpleTable.vue +++ b/resources/js/Components/SimpleTable.vue @@ -8,14 +8,14 @@ diff --git a/resources/js/Pages/Contacts/Edit.vue b/resources/js/Pages/Contacts/Edit.vue index 5ead086..3c568ac 100644 --- a/resources/js/Pages/Contacts/Edit.vue +++ b/resources/js/Pages/Contacts/Edit.vue @@ -159,14 +159,14 @@ export default { }), boughtCarColumns: [ {key: 'name', value: 'Auto'}, - {key: 'sold_at', value: 'Verkaufsdatum'}, - {key: 'sell_price', value: 'Verkaufspreis'}, + {key: 'date', value: 'Verkaufsdatum'}, + {key: 'price', value: 'Verkaufspreis'}, {key: 'insurance_type', value: 'Versicherungstyp'}, ], soldCarColumns: [ {key: 'name', value: 'Auto'}, - {key: 'bought_at', value: 'Kaufdatum'}, - {key: 'buy_price', value: 'Kaufpreis'}, + {key: 'date', value: 'Kaufdatum'}, + {key: 'price', value: 'Kaufpreis'}, ] } }, @@ -189,7 +189,6 @@ export default { zip: this.form.zip, city: this.form.city, country: this.form.country, - link: route('contacts.update', this.contact), } } }, diff --git a/resources/js/Pages/Contacts/Index.vue b/resources/js/Pages/Contacts/Index.vue index 844ca7f..44ceb1d 100644 --- a/resources/js/Pages/Contacts/Index.vue +++ b/resources/js/Pages/Contacts/Index.vue @@ -14,7 +14,7 @@ Kontakt erfassen - + @@ -36,6 +36,7 @@ export default { }, props: { filters: Object, + sort: Object, contacts: Object, }, data() {
- + {{ col.value }}
- + {{ col.value }}