Files
Umbrella/frontend/src/routes/document/View.svelte
Stephan Richter dba2657894
All checks were successful
Build Docker Image / Docker-Build (push) Successful in 2m23s
Build Docker Image / Clean-Registry (push) Successful in -11s
improved time selector in document editor
Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
2026-03-26 10:52:22 +01:00

249 lines
8.9 KiB
Svelte
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script>
import { onMount } from 'svelte';
import { useTinyRouter } from 'svelte-tiny-router';
import { api, post } from '../../urls.svelte.js';
import { error, yikes } from '../../warn.svelte';
import { t } from '../../translations.svelte.js';
import { user } from '../../user.svelte.js';
import LineEditor from '../../Components/LineEditor.svelte';
import MarkdownEditor from '../../Components/MarkdownEditor.svelte';
import MultilineEditor from '../../Components/MultilineEditor.svelte';
import Notes from '../notes/RelatedNotes.svelte';
import PositionList from './PositionList.svelte';
import StateSelector from './StateSelector.svelte';
import Tags from '../tags/TagList.svelte';
import TemplateSelector from './TemplateSelector.svelte';
import TypeSelector from './TypeSelector.svelte';
let doc = $state(null);
let editable = $derived(doc.state == 1);
let { id } = $props();
let pdfDisabled = $state(false);
let position_select = $state(false);
const router = useTinyRouter();
let sndDisabled = $state(false);
async function changeState(newVal){
let success = false;
if (doc.state == 1 || confirm(t('confirm_state'))){
success = await update('state',newVal);
}
if (success) {
doc.state = newVal;
} else {
const dummy = doc.state;
doc.state = null; // we need to alter in between,
doc.state = dummy; // otherwise the state will not be re-set
}
}
async function createSuccessorDoc(type){
const url = api(`document/${id}/clone`);
const res = await fetch(url,{
credentials :'include',
method : 'POST',
body : type
});
if (res.ok) {
yikes();
let json = await res.json();
router.navigate(`/document/${json.id}/view`);
loadDoc();
} else {
error(res);
}
}
async function loadDoc(){
const url = api(`document/${id}`);
const resp = await fetch(url,{credentials:'include'});
if (resp.ok){
doc = await resp.json();
yikes();
} else {
error(resp);
}
}
async function render(ev){
pdfDisabled = true;
const url = api(`document/${doc.id}/pdf`);
const resp = await fetch(url,{credentials:'include'});
if (resp.ok){
yikes();
const blob = await resp.blob();
const parts = resp.headers.get("Content-disposition").split(";");
const filename = parts[1].split('=')[1].split('"').join('');
var fileLink = document.createElement('a');
fileLink.href = URL.createObjectURL(blob);
fileLink.download = filename;
fileLink.click();
} else {
error(resp);
}
pdfDisabled = false;
}
async function update(path,newValue){
const parts = path.split('.');
if (parts.length<1) return false;
let data = newValue;
while (parts.length > 0){
const inner = data;
data = {};
data[parts.pop()] = inner;
}
try {
const url = api(`document/${doc.id}`);
const resp = await fetch(url,{
credentials : 'include',
method : 'PATCH',
body : JSON.stringify(data)
});
return resp.ok;
} catch (err){
return false;
}
}
onMount(loadDoc);
</script>
<svelte:head>
<title>Umbrella {t('document')} {doc?.number}</title>
</svelte:head>
{#if doc}
<fieldset class="customer">
<legend>{t('customer')}</legend>
<table>
<tbody>
<tr>
<td colspan="2">
<MultilineEditor bind:value={doc.customer.name} editable={editable} onSet={(val) => update('customer.name',val)} />
</td>
</tr>
<tr>
<th>{t('customer_id')}:</th>
<td>
<LineEditor bind:value={doc.customer.id} editable={editable} onSet={(val) => update('customer.id',val)} />
</td>
</tr>
<tr>
<th>{t('tax_id')}:</th>
<td>
<LineEditor bind:value={doc.customer.tax_id} editable={editable} onSet={(val) => update('customer.tax_id',val)} />
</td>
</tr>
<tr>
<th>{t('email')}:</th>
<td>
<LineEditor bind:value={doc.customer.email} editable={editable} onSet={(val) => update('customer.email',val)} />
</td>
</tr>
</tbody>
</table>
</fieldset>
<fieldset class="sender">
<legend>{t('sender')}</legend>
<table>
<tbody>
<tr>
<td colspan="2">
<MultilineEditor bind:value={doc.sender.name} editable={editable} onSet={(val) => update('sender.name',val)} />
</td>
</tr>
<tr>
<th>{t('local_court')}:</th>
<td>
<LineEditor bind:value={doc.sender.court} editable={editable} onSet={(val) => update('sender.court',val)} />
</td>
</tr>
<tr>
<th>{t('tax_id')}:</th>
<td>
<LineEditor bind:value={doc.sender.tax_id} editable={editable} onSet={(val) => update('sender.tax_id',val)} />
</td>
</tr>
<tr>
<th>{t('bank_account')}:</th>
<td>
<MultilineEditor bind:value={doc.sender.bank_account} editable={editable} onSet={(val) => update('sender.bank_account',val)} />
</td>
</tr>
</tbody>
</table>
</fieldset>
<fieldset class="invoice_data">
<legend>{t('type_'+doc.type)}</legend>
<table>
<tbody>
<tr>
<th>{t('number')}:</th>
<td><LineEditor bind:value={doc.number} editable={editable} onSet={(val) => update('number',val)} /></td>
</tr>
<tr>
<th>{t('state')}:</th>
<StateSelector selected={doc.state} onchange={changeState} onSet={(val) => update('state',val)} />
</tr>
<tr>
<th>{t('date')}:</th>
<LineEditor bind:value={doc.date} editable={editable} onSet={(val) => update('date',val)} />
</tr>
<tr>
<th>{t('delivery_date')}:</th>
<LineEditor bind:value={doc.delivery} editable={editable} onSet={(val) => update('delivery',val)} />
</tr>
<tr>
<th>{t('template')}:</th>
<td>
{#if editable}
<TemplateSelector company={doc.company.id} bind:value={doc.template} onchange={() => update('template',doc.template)} />
{:else}
{doc.template}
{/if}
</td>
</tr>
<tr>
<th>{t('create_new_object',{object:t('succeeding_document')})}:</th>
<td>
<TypeSelector caption={t('choose_type')} onSelect={createSuccessorDoc} />
</td>
</tr>
</tbody>
</table>
</fieldset>
<fieldset class="clear">
<legend>{t('head')}</legend>
<MarkdownEditor bind:value={doc.head} editable={editable} onSet={(val) => update('head',val)} />
</fieldset>
<fieldset>
<PositionList bind:document={doc} submit={update} />
</fieldset>
<fieldset>
<legend>{t('footer')}</legend>
<MarkdownEditor bind:value={doc.footer} editable={editable} onSet={(val) => update('footer',val)} />
</fieldset>
<fieldset>
<legend>{t('tags')}</legend>
<Tags module="document" {id} user_list={[+user.id]} />
</fieldset>
<fieldset>
<legend>{t('actions')}</legend>
<button onclick={render} disabled={pdfDisabled}>{t('create_pdf')}</button>
<button onclick={() => router.navigate(`/document/${doc.id}/send`)} >{t('send_document')}</button>
</fieldset>
{/if}
<div class="notes">
<h3>{t('notes')}</h3>
<Notes module="document" entity_id={id} />
</div>