Extend incoming for better usage.
This commit is contained in:
17
app/Http/Controllers/Api/SupplierController.php
Normal file
17
app/Http/Controllers/Api/SupplierController.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Supplier;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
class SupplierController extends Controller
|
||||
{
|
||||
public function index(): JsonResponse
|
||||
{
|
||||
$suppliers = Supplier::orderBy('name')->get();
|
||||
return response()->json($suppliers);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -22,6 +22,19 @@ class Incomingtax extends Model
|
||||
'currency',
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that are appended with attribute getters.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $appends = [
|
||||
'gross',
|
||||
];
|
||||
|
||||
public function getGrossAttribute() {
|
||||
return number_format($this->taxable_amount + $this->amount, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the incoming invoice this tax belongs to.
|
||||
*/
|
||||
|
||||
@@ -23,5 +23,7 @@ return [
|
||||
'Existing invoices' => 'Bestehende Eingangsrechnungen',
|
||||
'Edit incoming' => 'Bestehende Eingangsrechnungen bearbeiten',
|
||||
'Incoming data' => 'Daten der Eingangsrechnung',
|
||||
'Select supplier' => 'Lieferant wählen',
|
||||
'Create incoming' => 'Neue Eingangsrechnung anlegen',
|
||||
|
||||
];
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<x-app-layout>
|
||||
<x-slot name="header">
|
||||
<h2 class="font-semibold text-xl text-gray-800 dark:text-gray-200 leading-tight">
|
||||
{{ __('incoming.Edit incoming') }}
|
||||
{{ __('incoming.Create incoming') }}
|
||||
</h2>
|
||||
</x-slot>
|
||||
|
||||
@@ -105,8 +105,18 @@
|
||||
|
||||
<form class="mt-6 space-y-6" @submit.prevent="">
|
||||
|
||||
<div class="flex flex-row">
|
||||
<x-input-label class="w-1/6" for="select_supplier" :value="__('incoming.Select supplier')"/>
|
||||
<select id="select_supplier" name="select_supplier" type="text" x-on:click="setSupplier();"
|
||||
class="border-gray-300 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-300 focus:border-indigo-500 dark:focus:border-indigo-600 focus:ring-indigo-500 dark:focus:ring-indigo-600 rounded-md shadow-sm">
|
||||
<template x-for="supplier in suppliers">
|
||||
<option :value="supplier.id" x-text="supplier.name"></option>
|
||||
</template>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row space-x-8 items-start">
|
||||
<div class="w-1/2 grid grid-cols-3 items-center">
|
||||
<div class="w-1/2 grid grid-cols-3 items-center">
|
||||
<x-input-label for="name" :value="__('common.Name')"/>
|
||||
<x-text-input id="name" name="name" type="text"
|
||||
class="mt-1 col-span-2" :value="old('name')" autofocus
|
||||
@@ -201,6 +211,7 @@
|
||||
</header>
|
||||
|
||||
<div class="flex flex-row items-end gap-2 w-full">
|
||||
<x-input-label for="invoice_item.gross" :value="__('invoice.Gross')" class="w-1/6"/>
|
||||
<x-input-label for="invoice_item.amount" :value="__('invoice.Net')" class="w-1/6"/>
|
||||
<x-input-label for="invoice_item.price" :value="__('configuration.Taxrate')" class="w-1/6"/>
|
||||
<x-input-label for="invoice_item.tax" :value="__('common.Currency code')" class="w-1/6"/>
|
||||
@@ -211,14 +222,19 @@
|
||||
<div>
|
||||
<template x-for="(tax, index) in taxes">
|
||||
<div class="flex flex-row items-end gap-2 w-full relative">
|
||||
<x-text-input id="taxes[index].gross" name="taxes[index].gross" type="number"
|
||||
class="mt-1 block w-1/6"
|
||||
autofocus x-on:blur="calculateFromGross(index);"
|
||||
x-model="taxes[index].gross" />
|
||||
|
||||
<x-text-input id="taxes[index].taxable_amount" name="taxes[index].taxable_amount" type="number"
|
||||
class="mt-1 block w-1/6"
|
||||
autofocus x-on:blur="calculateTax(index);"
|
||||
autofocus x-on:blur="calculateFromNet(index);"
|
||||
x-model="taxes[index].taxable_amount" />
|
||||
|
||||
<x-text-input id="taxes[index].percentage" name="taxes[index].percentage" type="number"
|
||||
class="mt-1 block w-1/6"
|
||||
autofocus x-on:blur="calculateTax(index);"
|
||||
autofocus x-on:blur="calculateFromNet(index);"
|
||||
x-model="taxes[index].percentage"/>
|
||||
|
||||
<x-text-input id="taxes[index].currency" name="taxes[index].currency" type="text"
|
||||
@@ -265,19 +281,46 @@
|
||||
},
|
||||
supplier: {},
|
||||
taxes: [],
|
||||
suppliers: [],
|
||||
|
||||
init() {
|
||||
this.addTax();
|
||||
this.getSuppliers();
|
||||
},
|
||||
|
||||
addTax() {
|
||||
let tax = {
|
||||
gross: 0,
|
||||
taxable_amount: 0,
|
||||
amount: 0,
|
||||
percentage: 0,
|
||||
percentage: 19,
|
||||
currency: this.incoming.currency_code
|
||||
};
|
||||
this.taxes.push(tax);
|
||||
},
|
||||
|
||||
calculateTax(index) {
|
||||
getSuppliers() {
|
||||
let vm = this;
|
||||
axios.get('/supplier')
|
||||
.then(function(response) {
|
||||
vm.suppliers = response.data;
|
||||
})
|
||||
},
|
||||
|
||||
setSupplier() {
|
||||
let id = document.querySelector('#select_supplier').value;
|
||||
let supplier_key = Object.keys(this.suppliers).find(key => (this.suppliers[key].id == id));
|
||||
this.supplier = this.suppliers[supplier_key];
|
||||
},
|
||||
|
||||
calculateFromGross(index) {
|
||||
this.taxes[index].taxable_amount = this.taxes[index].gross * 100 / (100 + parseFloat(this.taxes[index].percentage));
|
||||
this.calculateFromNet(index);
|
||||
},
|
||||
|
||||
calculateFromNet(index) {
|
||||
this.taxes[index].amount = this.taxes[index].taxable_amount * this.taxes[index].percentage / 100;
|
||||
this.taxes[index].gross = this.taxes[index].taxable_amount * (100 + parseFloat(this.taxes[index].percentage)) / 100;
|
||||
this.incoming.net = 0;
|
||||
this.incoming.gross = 0;
|
||||
this.incoming.tax = 0;
|
||||
|
||||
@@ -105,6 +105,16 @@
|
||||
|
||||
<form class="mt-6 space-y-6" @submit.prevent="">
|
||||
|
||||
<div class="flex flex-row">
|
||||
<x-input-label class="w-1/6" for="select_supplier" :value="__('incoming.Select supplier')"/>
|
||||
<select id="select_supplier" name="select_supplier" type="text" x-on:click="setSupplier();"
|
||||
class="border-gray-300 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-300 focus:border-indigo-500 dark:focus:border-indigo-600 focus:ring-indigo-500 dark:focus:ring-indigo-600 rounded-md shadow-sm">
|
||||
<template x-for="sup in suppliers">
|
||||
<option :value="sup.id" :selected="sup.id == supplier.id" x-text="sup.name"></option>
|
||||
</template>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row space-x-8 items-start">
|
||||
<div class="w-1/2 grid grid-cols-3 items-center">
|
||||
<x-input-label for="name" :value="__('common.Name')"/>
|
||||
@@ -273,7 +283,6 @@
|
||||
</template>
|
||||
</div>
|
||||
|
||||
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
@@ -290,29 +299,30 @@
|
||||
</header>
|
||||
|
||||
<div class="flex flex-row items-end gap-2 w-full">
|
||||
<x-input-label for="invoice_item.gross" :value="__('invoice.Gross')" class="w-1/6"/>
|
||||
<x-input-label for="invoice_item.amount" :value="__('invoice.Net')" class="w-1/6"/>
|
||||
<x-input-label for="invoice_item.name" :value="__('invoice.Tax')" class="w-1/6"/>
|
||||
<x-input-label for="invoice_item.price" :value="__('configuration.Taxrate')" class="w-1/6"/>
|
||||
<x-input-label for="invoice_item.tax" :value="__('common.Currency code')" class="w-1/6"/>
|
||||
<x-input-label for="invoice_item.name" :value="__('invoice.Tax')" class="w-1/6"/>
|
||||
<div class="w-1/12 relative h-10"></div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<template x-for="(tax, index) in taxes">
|
||||
<div class="flex flex-row items-end gap-2 w-full relative">
|
||||
<x-text-input id="taxes[index].gross" name="taxes[index].gross" type="number"
|
||||
class="mt-1 block w-1/6"
|
||||
autofocus x-on:blur="calculateFromGross(index);"
|
||||
x-model="taxes[index].gross"/>
|
||||
|
||||
<x-text-input id="taxes[index].taxable_amount" name="taxes[index].taxable_amount" type="number"
|
||||
class="mt-1 block w-1/6"
|
||||
autofocus
|
||||
autofocus x-on:blur="calculateFromNet(index);"
|
||||
x-model="taxes[index].taxable_amount"/>
|
||||
|
||||
<x-text-input id="taxes[index].amount" name="taxes[index].amount" type="number"
|
||||
class="mt-1 block w-1/6"
|
||||
autofocus
|
||||
x-model="taxes[index].amount"/>
|
||||
|
||||
<x-text-input id="taxes[index].percentage" name="taxes[index].percentage" type="number"
|
||||
class="mt-1 block w-1/6"
|
||||
autofocus
|
||||
autofocus x-on:blur="calculateFromNet(index);"
|
||||
x-model="taxes[index].percentage"/>
|
||||
|
||||
<x-text-input id="taxes[index].currency" name="taxes[index].currency" type="text"
|
||||
@@ -321,6 +331,11 @@
|
||||
placeholder="{{ __('invoice.Name') }}"
|
||||
x-model="taxes[index].currency"/>
|
||||
|
||||
<x-text-input id="taxes[index].amount" name="taxes[index].amount" type="number"
|
||||
class="mt-1 block w-1/6"
|
||||
autofocus disabled
|
||||
x-model="taxes[index].amount"/>
|
||||
|
||||
<div class="flex flex-row w-1/12 h-10 relative">
|
||||
<x-danger-button x-on:click="deleteTax(index);" class="absolute right-0">
|
||||
-
|
||||
@@ -347,6 +362,44 @@
|
||||
supplier: {!! $supplier !!},
|
||||
items: {!! $items !!},
|
||||
taxes: {!! $taxes !!},
|
||||
suppliers: [],
|
||||
|
||||
init() {
|
||||
let vm = this;
|
||||
axios.get('/supplier')
|
||||
.then(function(response) {
|
||||
vm.suppliers = response.data;
|
||||
})
|
||||
},
|
||||
|
||||
setSupplier() {
|
||||
let id = document.querySelector('#select_supplier').value;
|
||||
let supplier_key = Object.keys(this.suppliers).find(key => (this.suppliers[key].id == id));
|
||||
this.supplier = this.suppliers[supplier_key];
|
||||
},
|
||||
|
||||
calculateFromGross(index) {
|
||||
this.taxes[index].taxable_amount = this.taxes[index].gross * 100 / (100 + parseFloat(this.taxes[index].percentage));
|
||||
this.calculateFromNet(index);
|
||||
},
|
||||
|
||||
calculateFromNet(index) {
|
||||
this.taxes[index].amount = this.taxes[index].taxable_amount * this.taxes[index].percentage / 100;
|
||||
this.taxes[index].gross = this.taxes[index].taxable_amount * (100 + parseFloat(this.taxes[index].percentage)) / 100;
|
||||
this.incoming.net = 0;
|
||||
this.incoming.gross = 0;
|
||||
this.incoming.tax = 0;
|
||||
this.calculateSum();
|
||||
},
|
||||
|
||||
calculateSum() {
|
||||
let vm = this;
|
||||
this.taxes.forEach(function(tax) {
|
||||
vm.incoming.tax += tax.amount * 1;
|
||||
vm.incoming.net += tax.taxable_amount * 1;
|
||||
});
|
||||
vm.incoming.gross += (vm.incoming.tax + vm.incoming.net);
|
||||
},
|
||||
|
||||
addItem() {
|
||||
let item = {
|
||||
@@ -366,9 +419,10 @@
|
||||
addTax() {
|
||||
let tax = {
|
||||
incoming_id: this.incoming_id,
|
||||
gross: 0,
|
||||
taxable_amount: 0,
|
||||
amount: 0,
|
||||
percentage: 0,
|
||||
percentage: 19,
|
||||
currency: 'EUR'
|
||||
};
|
||||
this.taxes.push(tax);
|
||||
|
||||
@@ -13,6 +13,7 @@ use App\Http\Controllers\Api\MailController;
|
||||
use App\Http\Controllers\Api\OptionController;
|
||||
use App\Http\Controllers\Api\PaymentController;
|
||||
use App\Http\Controllers\Api\ProjectController;
|
||||
use App\Http\Controllers\Api\SupplierController;
|
||||
use App\Http\Controllers\Api\TaxrateController;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
@@ -51,6 +52,7 @@ Route::group(['as' => 'api.'], function () {
|
||||
Route::post('/incoming', [IncomingController::class, 'store'])->name('incoming.store');
|
||||
Route::apiResource('/project', ProjectController::class);
|
||||
Route::apiResource('/dashboard', DashboardController::class)->only(['index', 'update']);
|
||||
Route::apiResource('/supplier', SupplierController::class)->only(['index']);
|
||||
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user