SvelteKit 2 + Svelte 4 + adapter-node, SQLite via better-sqlite3 (WAL, foreign keys on). Bilingual EN/Тоҷикӣ throughout, locale persisted in localStorage. Pages: dashboard (totals, low stock, recent movements), parts list with search and sort, part create/edit, record movement (in/out/adjust with smart unit-price and adjust-quantity prefill), suppliers list with inline add. Schema: categories, suppliers, parts (with _en/_tg name+description columns, dirams for money), stock_movements with check on movement_type. On-hand updates are done in JS inside a transaction with the movement insert. Dockerized dev: docker compose, named project, bind-mounted data/ for DB persistence. Seed contains 6 categories, 4 suppliers, 31 realistic parts (Lada / Nexia / Opel / Toyota bias). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
76 lines
2.0 KiB
Svelte
76 lines
2.0 KiB
Svelte
<script>
|
|
import { t } from '$lib/i18n/store.js';
|
|
import { enhance } from '$app/forms';
|
|
|
|
export let data;
|
|
export let form;
|
|
$: ({ suppliers } = data);
|
|
$: errors = form?.errors ?? {};
|
|
$: values = form?.values ?? {};
|
|
</script>
|
|
|
|
<h1>{$t('suppliers.title')}</h1>
|
|
|
|
{#if suppliers.length === 0}
|
|
<p class="muted">{$t('suppliers.no_suppliers')}</p>
|
|
{:else}
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>{$t('suppliers.name')}</th>
|
|
<th>{$t('suppliers.phone')}</th>
|
|
<th>{$t('suppliers.address')}</th>
|
|
<th>{$t('suppliers.notes')}</th>
|
|
<th></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{#each suppliers as s}
|
|
<tr>
|
|
<td><strong>{s.name}</strong></td>
|
|
<td>{s.phone || $t('common.none')}</td>
|
|
<td>{s.address || $t('common.none')}</td>
|
|
<td>{s.notes || $t('common.none')}</td>
|
|
<td>
|
|
<form method="POST" action="?/delete" use:enhance
|
|
on:submit={(e) => { if (!confirm($t('suppliers.delete_confirm'))) e.preventDefault(); }}>
|
|
<input type="hidden" name="id" value={s.id} />
|
|
<button class="danger" type="submit">{$t('common.delete')}</button>
|
|
</form>
|
|
</td>
|
|
</tr>
|
|
{/each}
|
|
</tbody>
|
|
</table>
|
|
{/if}
|
|
|
|
<h2>{$t('suppliers.add')}</h2>
|
|
<form class="stack" method="POST" action="?/create" use:enhance>
|
|
<label>
|
|
{$t('suppliers.name')} *
|
|
<input name="name" required value={values.name ?? ''} />
|
|
{#if errors.name}<span class="field-error">{$t(errors.name)}</span>{/if}
|
|
</label>
|
|
<div class="row">
|
|
<label>
|
|
{$t('suppliers.phone')}
|
|
<input name="phone" value={values.phone ?? ''} />
|
|
</label>
|
|
<label>
|
|
{$t('suppliers.address')}
|
|
<input name="address" value={values.address ?? ''} />
|
|
</label>
|
|
</div>
|
|
<label>
|
|
{$t('suppliers.notes')}
|
|
<textarea name="notes">{values.notes ?? ''}</textarea>
|
|
</label>
|
|
<div>
|
|
<button type="submit">{$t('common.add')}</button>
|
|
</div>
|
|
</form>
|
|
|
|
<style>
|
|
.field-error { color: #8a1f1b; font-size: 0.8rem; }
|
|
</style>
|