CluPilotCloud/resources/views/livewire/admin/finance.blade.php

175 lines
11 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>
<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>
{{-- Where copies go. As many as somebody wants, because the reason for
having a second is that the first can fail. --}}
<div class="overflow-hidden rounded-lg border border-line bg-surface shadow-xs animate-rise [animation-delay:75ms]">
<div class="flex flex-wrap items-start justify-between gap-4 border-b border-line p-6">
<div class="min-w-0">
<h2 class="font-semibold text-ink">{{ __('finance.targets_title') }}</h2>
<p class="mt-1 max-w-2xl text-sm text-muted">{{ __('finance.targets_sub') }}</p>
</div>
<x-ui.button variant="secondary"
x-on:click="$dispatch('openModal', { component: 'admin.edit-export-target' })">
<x-ui.icon name="plus" class="size-4" />{{ __('finance.targets_add') }}
</x-ui.button>
</div>
@if ($targets->isEmpty())
<p class="p-8 text-center text-sm text-muted">{{ __('finance.targets_empty') }}</p>
@else
<ul class="divide-y divide-line">
@foreach ($targets as $row)
<li wire:key="target-{{ $row['model']->uuid }}" class="flex flex-wrap items-center justify-between gap-3 px-6 py-4">
<div class="min-w-0">
<p class="flex flex-wrap items-center gap-2 text-sm font-medium text-body">
{{ $row['model']->name }}
<span class="rounded-pill border border-line-strong bg-surface-2 px-2 py-0.5 text-xs font-medium text-muted">{{ strtoupper($row['model']->driver) }}</span>
@unless ($row['model']->active)
<span class="rounded-pill border border-line-strong bg-surface-2 px-2 py-0.5 text-xs font-medium text-muted">{{ __('finance.targets_inactive') }}</span>
@endunless
</p>
<p class="mt-0.5 font-mono text-xs text-muted">{{ $row['model']->describe() }}</p>
<p class="mt-1 text-xs {{ $row['failed'] > 0 ? 'text-danger' : 'text-muted' }}">
@if ($row['failed'] > 0)
{{ __('finance.archive_failed', ['n' => $row['failed']]) }}
@elseif ($row['pending'] > 0)
{{ __('finance.archive_pending', ['n' => $row['pending']]) }}
@else
{{ __('finance.archive_clear') }}
@endif
</p>
</div>
<x-ui.button variant="secondary"
x-on:click="$dispatch('openModal', { component: 'admin.edit-export-target', arguments: { uuid: '{{ $row['model']->uuid }}' } })">
{{ __('finance.series.edit') }}
</x-ui.button>
</li>
@endforeach
</ul>
@endif
</div>
{{-- 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>