feat: fix parsing
This commit is contained in:
@@ -128,9 +128,10 @@
|
||||
>
|
||||
<div class="space-y-2">
|
||||
<OperationCard
|
||||
v-for="(cat, idx) in data.data?.recapitulatif_operations"
|
||||
v-for="(group, idx) in operationsGroupedByCategory"
|
||||
:key="idx"
|
||||
:category="cat"
|
||||
:categorie="group.categorie"
|
||||
:operations="group.operations"
|
||||
/>
|
||||
</div>
|
||||
</DataSection>
|
||||
@@ -140,7 +141,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from 'vue'
|
||||
import { ref, reactive, computed } from 'vue'
|
||||
import DataSection from './DataSection.vue'
|
||||
import DataCard from './DataCard.vue'
|
||||
import DataRow from './DataRow.vue'
|
||||
@@ -158,6 +159,27 @@ const props = defineProps({
|
||||
}
|
||||
})
|
||||
|
||||
// Grouper les operations par categorie pour l'affichage
|
||||
const operationsGroupedByCategory = computed(() => {
|
||||
const operations = props.data?.data?.recapitulatif_operations
|
||||
if (!operations || !Array.isArray(operations)) return []
|
||||
|
||||
// Grouper par categorie en preservant l'ordre d'apparition
|
||||
const groups = []
|
||||
const categoryIndex = {}
|
||||
|
||||
for (const op of operations) {
|
||||
const cat = op.categorie || 'AUTRES'
|
||||
if (!(cat in categoryIndex)) {
|
||||
categoryIndex[cat] = groups.length
|
||||
groups.push({ categorie: cat, operations: [] })
|
||||
}
|
||||
groups[categoryIndex[cat]].operations.push(op)
|
||||
}
|
||||
|
||||
return groups
|
||||
})
|
||||
|
||||
const copyLabel = ref('Copier')
|
||||
const expandedSections = reactive({
|
||||
metadata: true,
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
|
||||
</svg>
|
||||
<span class="font-medium text-gray-800 text-sm">{{ category.categorie }}</span>
|
||||
<span class="font-medium text-gray-800 text-sm">{{ formatCategorie(categorie) }}</span>
|
||||
<span class="text-xs bg-gray-100 text-gray-600 px-2 py-0.5 rounded-full">
|
||||
{{ category.operations?.length || 0 }} operations
|
||||
{{ operations.length }} operation{{ operations.length > 1 ? 's' : '' }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="text-sm font-semibold text-gray-700">
|
||||
@@ -29,18 +29,23 @@
|
||||
<div v-show="expanded" class="border-t border-gray-100 bg-gray-50">
|
||||
<div class="divide-y divide-gray-100">
|
||||
<div
|
||||
v-for="(op, idx) in category.operations"
|
||||
v-for="(op, idx) in operations"
|
||||
:key="idx"
|
||||
class="px-3 py-2 bg-white text-xs"
|
||||
>
|
||||
<div class="flex items-start justify-between gap-2">
|
||||
<div class="flex-1 min-w-0">
|
||||
<div v-if="op.sous_categorie" class="text-gray-400 text-xs mb-0.5">
|
||||
{{ op.sous_categorie }}
|
||||
</div>
|
||||
<div v-if="op.fournisseur" class="font-medium text-gray-800 truncate">
|
||||
{{ op.fournisseur }}
|
||||
</div>
|
||||
<div class="text-gray-500 truncate">{{ op.description || op.type_operation || '-' }}</div>
|
||||
<div v-if="op.lot_concerne" class="text-gray-400 text-xs mt-0.5">
|
||||
Lot: {{ op.lot_concerne }}
|
||||
<div class="text-gray-500 truncate">{{ op.description || '-' }}</div>
|
||||
<div v-if="op.lot_numero || op.lot_concerne" class="text-blue-500 text-xs mt-0.5">
|
||||
<span v-if="op.lot_numero" class="font-medium">Lot {{ op.lot_numero }}</span>
|
||||
<span v-if="op.lot_numero && op.lot_concerne"> - </span>
|
||||
<span v-if="op.lot_concerne">{{ op.lot_concerne }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-right flex-shrink-0">
|
||||
@@ -48,10 +53,27 @@
|
||||
<div v-if="op.montants?.tva" class="text-gray-400">
|
||||
TVA: {{ formatCurrency(op.montants.tva) }}
|
||||
</div>
|
||||
<div v-if="op.montants?.locatif" class="text-green-600 text-xs">
|
||||
Locatif: {{ formatCurrency(op.montants.locatif) }}
|
||||
</div>
|
||||
<div v-if="op.montants?.deductible" class="text-orange-600 text-xs">
|
||||
Deductible: {{ formatCurrency(op.montants.deductible) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Totaux de la categorie -->
|
||||
<div class="px-3 py-2 bg-gray-100 border-t border-gray-200 text-xs">
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="font-medium text-gray-600">Total {{ formatCategorie(categorie) }}</span>
|
||||
<div class="text-right">
|
||||
<span class="font-semibold text-gray-800">{{ formatCurrency(totalDebit) }}</span>
|
||||
<span v-if="totalTva > 0" class="text-gray-500 ml-2">(TVA: {{ formatCurrency(totalTva) }})</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -60,8 +82,12 @@
|
||||
import { ref, computed } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
category: {
|
||||
type: Object,
|
||||
categorie: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
operations: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
})
|
||||
@@ -69,10 +95,22 @@ const props = defineProps({
|
||||
const expanded = ref(false)
|
||||
|
||||
const totalDebit = computed(() => {
|
||||
if (!props.category.operations) return 0
|
||||
return props.category.operations.reduce((sum, op) => sum + (op.montants?.debit || 0), 0)
|
||||
return props.operations.reduce((sum, op) => sum + (op.montants?.debit || 0), 0)
|
||||
})
|
||||
|
||||
const totalTva = computed(() => {
|
||||
return props.operations.reduce((sum, op) => sum + (op.montants?.tva || 0), 0)
|
||||
})
|
||||
|
||||
function formatCategorie(cat) {
|
||||
if (!cat) return '-'
|
||||
// Convertir DEPENSES_LOCATIVES -> Depenses locatives
|
||||
return cat
|
||||
.replace(/_/g, ' ')
|
||||
.toLowerCase()
|
||||
.replace(/^\w/, c => c.toUpperCase())
|
||||
}
|
||||
|
||||
function formatCurrency(value) {
|
||||
if (value === null || value === undefined) return '-'
|
||||
return new Intl.NumberFormat('fr-FR', { style: 'currency', currency: 'EUR' }).format(value)
|
||||
|
||||
Reference in New Issue
Block a user