145 lines
9.4 KiB
PHP
145 lines
9.4 KiB
PHP
<div class="space-y-5">
|
|
<div class="animate-rise">
|
|
<h1 class="text-2xl font-bold tracking-tight text-ink">{{ __('finance.title') }}</h1>
|
|
<p class="mt-1 text-sm text-muted">{{ __('finance.subtitle') }}</p>
|
|
</div>
|
|
|
|
{{-- What is still missing before anything may be issued. An invoice without
|
|
a name, an address or a VAT number is not a valid invoice, and issuing
|
|
one is worse than refusing to. --}}
|
|
@if ($missing !== [])
|
|
<x-ui.alert variant="warning" class="animate-rise">
|
|
{{ __('finance.incomplete', ['fields' => collect($missing)->map(fn ($f) => __('finance.field.'.$f))->join(', ')]) }}
|
|
</x-ui.alert>
|
|
@endif
|
|
|
|
<form wire:submit="saveCompany" class="space-y-5 rounded-lg border border-line bg-surface p-6 shadow-xs animate-rise [animation-delay:60ms]">
|
|
<div>
|
|
<h2 class="font-semibold text-ink">{{ __('finance.company_title') }}</h2>
|
|
<p class="mt-1 max-w-2xl text-sm text-muted">{{ __('finance.company_sub') }}</p>
|
|
</div>
|
|
|
|
<div class="grid gap-4 sm:grid-cols-2">
|
|
<x-ui.input name="company.name" wire:model="company.name" :label="__('finance.field.name')" class="sm:col-span-2" />
|
|
<x-ui.input name="company.address" wire:model="company.address" :label="__('finance.field.address')" class="sm:col-span-2" />
|
|
<x-ui.input name="company.postcode" wire:model="company.postcode" :label="__('finance.field.postcode')" />
|
|
<x-ui.input name="company.city" wire:model="company.city" :label="__('finance.field.city')" />
|
|
<x-ui.input name="company.country" wire:model="company.country" :label="__('finance.field.country')" />
|
|
<x-ui.input name="company.phone" wire:model="company.phone" :label="__('finance.field.phone')" />
|
|
<x-ui.input name="company.email" wire:model="company.email" :label="__('finance.field.email')" />
|
|
<x-ui.input name="company.website" wire:model="company.website" :label="__('finance.field.website')" />
|
|
</div>
|
|
|
|
<div class="grid gap-4 border-t border-line pt-5 sm:grid-cols-2">
|
|
<x-ui.input name="company.vat_id" wire:model="company.vat_id" :label="__('finance.field.vat_id')" :hint="__('finance.hint.vat_id')" placeholder="ATU12345678" />
|
|
<x-ui.input name="company.register_number" wire:model="company.register_number" :label="__('finance.field.register_number')" placeholder="FN 123456a" />
|
|
<x-ui.input name="company.register_court" wire:model="company.register_court" :label="__('finance.field.register_court')" placeholder="Handelsgericht Wien" />
|
|
<div>
|
|
<label class="text-sm font-medium text-body" for="tax-rate">{{ __('finance.field.tax_rate') }}</label>
|
|
<input id="tax-rate" type="number" step="0.1" min="0" max="100" wire:model="taxRate"
|
|
class="mt-1.5 w-full rounded-md border border-line-strong bg-surface px-3 py-2 font-mono text-sm text-ink" />
|
|
<p class="mt-1 text-xs text-muted">{{ __('finance.hint.tax_rate') }}</p>
|
|
@error('taxRate')<p class="mt-1 text-xs text-danger">{{ $message }}</p>@enderror
|
|
</div>
|
|
</div>
|
|
|
|
<div class="grid gap-4 border-t border-line pt-5 sm:grid-cols-3">
|
|
<x-ui.input name="company.bank_name" wire:model="company.bank_name" :label="__('finance.field.bank_name')" />
|
|
<x-ui.input name="company.iban" wire:model="company.iban" :label="__('finance.field.iban')" />
|
|
<x-ui.input name="company.bic" wire:model="company.bic" :label="__('finance.field.bic')" />
|
|
</div>
|
|
|
|
<div class="grid gap-4 border-t border-line pt-5 sm:grid-cols-3">
|
|
<x-ui.input name="company.payment_days" wire:model="company.payment_days" type="number" :label="__('finance.field.payment_days')" />
|
|
<x-ui.input name="company.payment_terms" wire:model="company.payment_terms" :label="__('finance.field.payment_terms')" class="sm:col-span-2" />
|
|
</div>
|
|
|
|
{{-- The logo. Replaceable, because a company changes its mark and every
|
|
invoice rendered after that has to carry the new one — while every
|
|
invoice already issued keeps the one it was issued with, because
|
|
the path is copied into the document at issue. --}}
|
|
<div class="border-t border-line pt-5">
|
|
<label class="text-sm font-medium text-body">{{ __('finance.field.logo') }}</label>
|
|
<div class="mt-2 flex flex-wrap items-center gap-4">
|
|
<div class="grid size-20 place-items-center overflow-hidden rounded-lg border border-line bg-surface-2">
|
|
@if ($logo)
|
|
<img src="{{ $logo->temporaryUrl() }}" alt="" class="max-h-16 max-w-16 object-contain" />
|
|
@elseif ($logoPath)
|
|
<img src="{{ Storage::disk('public')->url($logoPath) }}" alt="" class="max-h-16 max-w-16 object-contain" />
|
|
@else
|
|
<x-ui.icon name="receipt" class="size-6 text-muted" />
|
|
@endif
|
|
</div>
|
|
<div class="min-w-0">
|
|
<input type="file" wire:model="logo" accept="image/png,image/webp"
|
|
class="block w-full text-sm text-body file:mr-3 file:rounded-md file:border file:border-line-strong file:bg-surface-2 file:px-3 file:py-1.5 file:text-sm file:text-body" />
|
|
<p class="mt-1 text-xs text-muted">{{ __('finance.hint.logo') }}</p>
|
|
@error('logo')<p class="mt-1 text-xs text-danger">{{ $message }}</p>@enderror
|
|
@if ($logoPath)
|
|
<button type="button" wire:click="removeLogo" class="mt-2 text-xs font-medium text-danger underline">{{ __('finance.logo_remove') }}</button>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- The archive. A directory, nothing more: the mount behind it is the
|
|
operator's business, and keeping it that way means the target can
|
|
change without a line of code changing with it. --}}
|
|
<div class="border-t border-line pt-5">
|
|
<x-ui.input name="archivePath" wire:model="archivePath" :label="__('finance.field.archive_path')"
|
|
:hint="__('finance.hint.archive_path')" placeholder="/mnt/rechnungen" />
|
|
@if ($archivePath !== '')
|
|
<p class="mt-2 text-xs {{ $exportFailures > 0 ? 'text-danger' : 'text-muted' }}">
|
|
@if ($exportFailures > 0)
|
|
{{ __('finance.archive_failed', ['n' => $exportFailures]) }}
|
|
@elseif ($unexported > 0)
|
|
{{ __('finance.archive_pending', ['n' => $unexported]) }}
|
|
@else
|
|
{{ __('finance.archive_clear') }}
|
|
@endif
|
|
</p>
|
|
@endif
|
|
</div>
|
|
|
|
<div class="flex justify-end border-t border-line pt-5">
|
|
<x-ui.button variant="primary" type="submit" wire:loading.attr="disabled">{{ __('finance.save') }}</x-ui.button>
|
|
</div>
|
|
</form>
|
|
|
|
{{-- The Rechnungskreise. Each has its own prefix and its own gapless
|
|
counter — a credit note is not an invoice with a minus sign. --}}
|
|
<div class="overflow-hidden rounded-lg border border-line bg-surface shadow-xs animate-rise [animation-delay:90ms]">
|
|
<div class="border-b border-line p-6">
|
|
<h2 class="font-semibold text-ink">{{ __('finance.series_title') }}</h2>
|
|
<p class="mt-1 max-w-2xl text-sm text-muted">{{ __('finance.series_sub') }}</p>
|
|
</div>
|
|
<table class="w-full text-sm">
|
|
<thead>
|
|
<tr class="border-b border-line bg-surface-2 text-left text-xs font-semibold text-muted">
|
|
<th class="px-4 py-3 font-semibold">{{ __('finance.series.name') }}</th>
|
|
<th class="px-4 py-3 font-semibold">{{ __('finance.series.prefix') }}</th>
|
|
<th class="px-4 py-3 font-semibold">{{ __('finance.series.next') }}</th>
|
|
<th class="px-4 py-3 font-semibold">{{ __('finance.series.reset') }}</th>
|
|
<th class="px-4 py-3 text-right font-semibold">{{ __('finance.series.actions') }}</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@foreach ($series as $row)
|
|
<tr wire:key="series-{{ $row->uuid }}" class="border-b border-line last:border-0">
|
|
<td class="px-4 py-3 text-body">{{ $row->name }}</td>
|
|
<td class="px-4 py-3 font-mono font-semibold text-ink">{{ $row->prefix }}</td>
|
|
<td class="px-4 py-3 font-mono text-xs text-muted">{{ str_pad((string) $row->next_number, $row->digits, '0', STR_PAD_LEFT) }}</td>
|
|
<td class="px-4 py-3 text-xs text-muted">{{ $row->yearly_reset ? __('finance.series.reset_yearly') : __('finance.series.reset_never') }}</td>
|
|
<td class="px-4 py-3 text-right">
|
|
<x-ui.button variant="secondary"
|
|
x-on:click="$dispatch('openModal', { component: 'admin.edit-invoice-series', arguments: { uuid: '{{ $row->uuid }}' } })">
|
|
{{ __('finance.series.edit') }}
|
|
</x-ui.button>
|
|
</td>
|
|
</tr>
|
|
@endforeach
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|