feat: Add A-Z filter for clients/suppliers in Telegram bot
- Add A-Z alphabetical filter keyboard for clients and suppliers lists (same pattern as company selection, without emoji) - Increase clients/suppliers list pagination from 10 to 20 items per page - Remove emoji from company A-Z filter button for consistency - Add 6 new callback handlers: clients_alpha_menu, clients_alpha:LETTER, clients_alpha_page:PAGE:LETTER, and supplier equivalents - Dashboard service and models updates - Telegram bot: email handlers, auth, DB operations, internal API improvements - Frontend: dashboard cards updates (CashFlow, Clienti, Furnizori, Treasury) - Frontend: SolduriCompactCard and CollapsibleCard improvements - DashboardView enhancements - start.sh and run-with-restart.sh script updates - IIS web.config and service worker updates Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
<div class="solduri-compact-card__content">
|
||||
<span class="solduri-compact-card__label">{{ label }}</span>
|
||||
<span class="solduri-compact-card__value" :class="valueColorClass">
|
||||
{{ formatCurrency(total) }}
|
||||
{{ formatAmount(total) }}
|
||||
</span>
|
||||
</div>
|
||||
<i
|
||||
@@ -25,7 +25,7 @@
|
||||
<!-- Casa Total -->
|
||||
<div class="solduri-compact-card__breakdown-item">
|
||||
<span class="solduri-compact-card__breakdown-label">Casa</span>
|
||||
<span class="solduri-compact-card__breakdown-value">{{ formatCurrency(casaTotal) }}</span>
|
||||
<span class="solduri-compact-card__breakdown-value">{{ formatAmount(casaTotal) }}</span>
|
||||
</div>
|
||||
<!-- Sub-conturi Casa (imediat sub Casa) -->
|
||||
<template v-if="breakdown?.casa?.items?.length">
|
||||
@@ -37,13 +37,13 @@
|
||||
<span class="solduri-compact-card__breakdown-sublabel">
|
||||
{{ item.nume || `Cont ${item.cont}` }}
|
||||
</span>
|
||||
<span class="solduri-compact-card__breakdown-subvalue">{{ formatCurrency(item.sold) }}</span>
|
||||
<span class="solduri-compact-card__breakdown-subvalue">{{ formatAmount(item.sold) }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<!-- Bancă Total -->
|
||||
<div class="solduri-compact-card__breakdown-item">
|
||||
<span class="solduri-compact-card__breakdown-label">Bancă</span>
|
||||
<span class="solduri-compact-card__breakdown-value">{{ formatCurrency(bancaTotal) }}</span>
|
||||
<span class="solduri-compact-card__breakdown-value">{{ formatAmount(bancaTotal) }}</span>
|
||||
</div>
|
||||
<!-- Sub-conturi Bancă (imediat sub Bancă) -->
|
||||
<template v-if="breakdown?.banca?.items?.length">
|
||||
@@ -55,7 +55,7 @@
|
||||
<span class="solduri-compact-card__breakdown-sublabel">
|
||||
{{ item.nume || `Cont ${item.cont}` }}
|
||||
</span>
|
||||
<span class="solduri-compact-card__breakdown-subvalue">{{ formatCurrency(item.sold) }}</span>
|
||||
<span class="solduri-compact-card__breakdown-subvalue">{{ formatAmount(item.sold) }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
@@ -65,13 +65,13 @@
|
||||
<div class="solduri-compact-card__breakdown-item">
|
||||
<span class="solduri-compact-card__breakdown-label">În termen</span>
|
||||
<span class="solduri-compact-card__breakdown-value">
|
||||
{{ formatCurrency(breakdown?.in_termen?.total || 0) }}
|
||||
{{ formatAmount(breakdown?.in_termen?.total || 0) }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="solduri-compact-card__breakdown-item">
|
||||
<span class="solduri-compact-card__breakdown-label">Restant</span>
|
||||
<span class="solduri-compact-card__breakdown-value solduri-compact-card__breakdown-value--warning">
|
||||
{{ formatCurrency(breakdown?.restant?.total || 0) }}
|
||||
{{ formatAmount(breakdown?.restant?.total || 0) }}
|
||||
</span>
|
||||
</div>
|
||||
<!-- Perioade restante -->
|
||||
@@ -82,24 +82,50 @@
|
||||
class="solduri-compact-card__breakdown-subitem"
|
||||
>
|
||||
<span class="solduri-compact-card__breakdown-sublabel">{{ formatPeriodLabel(key) }}</span>
|
||||
<span class="solduri-compact-card__breakdown-subvalue">{{ formatCurrency(value) }}</span>
|
||||
<span class="solduri-compact-card__breakdown-subvalue">{{ formatAmount(value) }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<!-- TVA: Simple display (no breakdown needed) -->
|
||||
<!-- TVA / Datorii Buget: Breakdown pe grupe (TVA/BASS/CAM) cu sub-conturi -->
|
||||
<template v-else-if="type === 'tva'">
|
||||
<div class="solduri-compact-card__breakdown-item">
|
||||
<span class="solduri-compact-card__breakdown-label">
|
||||
{{ total >= 0 ? 'TVA de recuperat' : 'TVA de plată' }}
|
||||
</span>
|
||||
<span
|
||||
class="solduri-compact-card__breakdown-value"
|
||||
:class="total >= 0 ? 'solduri-compact-card__breakdown-value--success' : 'solduri-compact-card__breakdown-value--danger'"
|
||||
>
|
||||
{{ formatCurrency(Math.abs(total)) }}
|
||||
</span>
|
||||
</div>
|
||||
<template v-if="Array.isArray(breakdown) && (breakdown as any[]).length">
|
||||
<div v-for="group in (breakdown as any[])" :key="group.key">
|
||||
<!-- Rând grup -->
|
||||
<div
|
||||
class="solduri-compact-card__breakdown-item solduri-compact-card__breakdown-group"
|
||||
@click.stop="toggleGroup(group.key)"
|
||||
>
|
||||
<span class="solduri-compact-card__breakdown-label solduri-compact-card__group-label">
|
||||
<i class="pi pi-chevron-right solduri-compact-card__group-toggle"
|
||||
:class="{ 'solduri-compact-card__group-toggle--expanded': expandedGroups.has(group.key) }"></i>
|
||||
{{ group.label }}
|
||||
</span>
|
||||
<span class="solduri-compact-card__breakdown-value">
|
||||
{{ group.precedent !== 0 ? formatAmount(group.precedent) : '-' }}
|
||||
</span>
|
||||
</div>
|
||||
<!-- Sub-conturi -->
|
||||
<div v-show="expandedGroups.has(group.key)">
|
||||
<div
|
||||
v-for="acc in group.sub_accounts"
|
||||
:key="acc.cont"
|
||||
class="solduri-compact-card__breakdown-subitem"
|
||||
>
|
||||
<span class="solduri-compact-card__breakdown-sublabel">{{ acc.label }}</span>
|
||||
<span class="solduri-compact-card__breakdown-subvalue">
|
||||
{{ acc.precedent !== 0 ? formatAmount(acc.precedent) : '-' }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="solduri-compact-card__breakdown-item">
|
||||
<span class="solduri-compact-card__breakdown-label">Fără date</span>
|
||||
<span class="solduri-compact-card__breakdown-value">-</span>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
@@ -144,6 +170,15 @@ const props = defineProps<{
|
||||
|
||||
// State
|
||||
const isExpanded = ref(false)
|
||||
const expandedGroups = ref(new Set<string>())
|
||||
const toggleGroup = (key: string) => {
|
||||
if (expandedGroups.value.has(key)) {
|
||||
expandedGroups.value.delete(key)
|
||||
} else {
|
||||
expandedGroups.value.add(key)
|
||||
}
|
||||
expandedGroups.value = new Set(expandedGroups.value)
|
||||
}
|
||||
|
||||
// Computed: Label based on type
|
||||
const label = computed(() => {
|
||||
@@ -151,7 +186,7 @@ const label = computed(() => {
|
||||
trezorerie: 'TREZORERIE',
|
||||
clienti: 'CLIENȚI',
|
||||
furnizori: 'FURNIZORI',
|
||||
tva: 'TVA'
|
||||
tva: 'DATORII BUGET'
|
||||
}
|
||||
return labels[props.type] || props.type.toUpperCase()
|
||||
})
|
||||
@@ -159,9 +194,11 @@ const label = computed(() => {
|
||||
// Computed: Value color class based on type and value
|
||||
const valueColorClass = computed(() => {
|
||||
if (props.type === 'tva') {
|
||||
return props.total >= 0
|
||||
? 'solduri-compact-card__value--success'
|
||||
: 'solduri-compact-card__value--danger'
|
||||
// total = tvaPreviousMonthNet = plata - recuperat
|
||||
// pozitiv = datorie la buget (roșu), zero/negativ = fără datorie (verde)
|
||||
return props.total > 0
|
||||
? 'solduri-compact-card__value--danger'
|
||||
: 'solduri-compact-card__value--success'
|
||||
}
|
||||
return ''
|
||||
})
|
||||
@@ -175,7 +212,7 @@ const hasBreakdown = computed(() => {
|
||||
return props.breakdown !== null && props.breakdown !== undefined
|
||||
}
|
||||
if (props.type === 'tva') {
|
||||
return true // TVA always shows status
|
||||
return props.breakdown !== null && props.breakdown !== undefined
|
||||
}
|
||||
return false
|
||||
})
|
||||
@@ -187,11 +224,10 @@ const toggleExpanded = () => {
|
||||
}
|
||||
}
|
||||
|
||||
const formatCurrency = (amount: number | undefined | null): string => {
|
||||
if (amount === undefined || amount === null) return '0 RON'
|
||||
const formatAmount = (amount: number | undefined | null): string => {
|
||||
if (amount === undefined || amount === null) return '0'
|
||||
return new Intl.NumberFormat('ro-RO', {
|
||||
style: 'currency',
|
||||
currency: 'RON',
|
||||
style: 'decimal',
|
||||
minimumFractionDigits: 0,
|
||||
maximumFractionDigits: 0
|
||||
}).format(amount)
|
||||
@@ -304,13 +340,13 @@ const formatPeriodLabel = (key: string): string => {
|
||||
}
|
||||
|
||||
.solduri-compact-card__breakdown-label {
|
||||
font-size: var(--text-base);
|
||||
font-size: var(--text-sm);
|
||||
color: var(--color-text-secondary);
|
||||
font-weight: var(--font-medium);
|
||||
}
|
||||
|
||||
.solduri-compact-card__breakdown-value {
|
||||
font-size: var(--text-base);
|
||||
font-size: var(--text-sm);
|
||||
font-weight: var(--font-semibold);
|
||||
color: var(--color-text);
|
||||
font-family: var(--font-mono, monospace);
|
||||
@@ -349,6 +385,26 @@ const formatPeriodLabel = (key: string): string => {
|
||||
font-family: var(--font-mono, monospace);
|
||||
}
|
||||
|
||||
/* TVA grup toggle */
|
||||
.solduri-compact-card__breakdown-group {
|
||||
cursor: pointer;
|
||||
font-weight: var(--font-semibold);
|
||||
}
|
||||
.solduri-compact-card__breakdown-group:hover { background: var(--surface-hover); }
|
||||
|
||||
.solduri-compact-card__group-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-xs);
|
||||
}
|
||||
|
||||
.solduri-compact-card__group-toggle {
|
||||
font-size: var(--text-xs);
|
||||
color: var(--color-text-secondary);
|
||||
transition: transform var(--transition-fast);
|
||||
}
|
||||
.solduri-compact-card__group-toggle--expanded { transform: rotate(90deg); }
|
||||
|
||||
/* Responsive - Mobile */
|
||||
@media (max-width: 768px) {
|
||||
.solduri-compact-card {
|
||||
|
||||
Reference in New Issue
Block a user