0% ont trouvé ce document utile (0 vote)
8 vues49 pages

Extrait de Code

Ce document décrit une interface utilisateur pour la recherche de comptes par prix, incluant des filtres pour le prix minimum, le prix maximum et le type de montant (débit, crédit ou les deux). Il présente également une table pour afficher les résultats, avec des options pour modifier et enregistrer les lignes, ainsi qu'une pagination pour naviguer entre les pages de résultats. Enfin, il gère les écritures non équilibrées et permet de charger les données via des requêtes API.

Transféré par

fenoantra akasia
Copyright
© All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
8 vues49 pages

Extrait de Code

Ce document décrit une interface utilisateur pour la recherche de comptes par prix, incluant des filtres pour le prix minimum, le prix maximum et le type de montant (débit, crédit ou les deux). Il présente également une table pour afficher les résultats, avec des options pour modifier et enregistrer les lignes, ainsi qu'une pagination pour naviguer entre les pages de résultats. Enfin, il gère les écritures non équilibrées et permet de charger les données via des requêtes API.

Transféré par

fenoantra akasia
Copyright
© All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

​<template>

<div class="container">
<div style="text-align: center;">
<h1 class="page-title" style="color: green;">
<BookOpen class="icon" />
Recherche de Comptes par Prix
</h1>
</div>

<form @[Link]="chargerDonnees" class="filter-form">


<label>
Prix Min :
<input type="number" [Link]="prixMin" />
</label>
<label>
Prix Max :
<input type="number" [Link]="prixMax" />
</label>
<label>
Type :
<select v-model="typeMontant">
<option value="debit">Débit</option>
<option value="credit">Crédit</option>
<option value="both">Les deux</option>
</select>
</label>

<button type="submit">Rechercher</button>
</form>

<table v-if="[Link]" class="ledger-table">


<thead>
<tr>
<th>Date</th>
<th>Référence</th>
<th>Journal</th>
<th>Compte</th>
<th>Débit</th>
<th>Crédit</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr v-for="(ligne, index) in donnees" :key="index">
<td>{{ new Date([Link]).toLocaleDateString() }}</td>
<td>{{ [Link] }}</td>
<td>{{ [Link] }}</td>
<td>{{ [Link] }}</td>
<td>
<div v-if="[Link]">
<input type="number" [Link]="[Link]" />
</div>
<div v-else>
{{ formatMontant([Link]) }}
</div>
</td>
<td>
<div v-if="[Link]">
<input type="number" [Link]="[Link]" />
</div>
<div v-else>
{{ formatMontant([Link]) }}
</div>
</td>
<td>
<div v-if="[Link]">
<button @click="enregistrerLigne(index)">Enregistrer</button>
<button @click="annulerEdition(index)">Annuler</button>
</div>
<div v-else>
<button @click="modifierLigne(index)">Modifier</button>
</div>
</td>
</tr>
</tbody>

</table>

<p v-if="![Link] && dejaCharge">Aucun résultat trouvé.</p>

<div v-if="totalPages > 1" class="pagination">


<button @click="pagePrecedente" :disabled="page === 1">Précédent</button>
<span>Page {{ page }} / {{ totalPages }}</span>
<button @click="pageSuivante" :disabled="page === totalPages">Suivant</button>
</div>

<h2 v-if="[Link]" style="color: red; margin-top: 2rem;">


Écritures Non Équilibrées
</h2>

<table v-if="[Link]" class="ledger-table">


<thead>
<tr>
<th>Date</th>
<th>Référence</th>
<th>Journal</th>
<th>Compte</th>
<th>Débit</th>
<th>Crédit</th>
</tr>
</thead>
<tbody>
<tr v-for="(ligne, index) in lignesNonEquilibrees" :key="'neq-' + index">
<td>{{ new Date([Link]).toLocaleDateString() }}</td>
<td>{{ [Link] }}</td>
<td>{{ [Link] }}</td>
<td>{{ [Link] }}</td>
<td>{{ formatMontant([Link]) }}</td>
<td>{{ formatMontant([Link]) }}</td>
</tr>
</tbody>
</table>
</div>
</template>

<script setup>
import { ref, watch } from 'vue'
import { BookOpen } from 'lucide-vue-next'
import { useRoute } from 'vue-router'
import axios from 'axios'
import { getToken } from '../services/Token'

const FACT_ACCT_ENDPOINT = '/api/v1/models/Fact_Acct'


const JOURNAL_LINE_ENDPOINT = '/api/v1/models/GL_JournalLine'
const JOURNAL_ENDPOINT = '/api/v1/models/GL_Journal'
const GL_JOURNALLINE_TABLE_ID = 224

const prixMin = ref(null)


const prixMax = ref(null)
const typeMontant = ref('both')
const libelle = ref('')
const donnees = ref([])
const lignesNonEquilibrees = ref([])
const dejaCharge = ref(false)
const page = ref(1)
const pageSize = 100
const totalRecords = ref(0)
const totalPages = ref(1)

const route = useRoute()


const accountIdFromRoute = [Link]?.accountId || null
async function fetchGrandLivre({ prixMin, prixMax, typeMontant, accountValue, libelle, skip, top }) {
try {
const token = await getToken()
const filters = []
// if (accountValue) [Link](`Account_ID eq ${accountValue}`)
const filterString = [Link] > 0 ? [Link](' and ') : undefined

const response = await [Link](FACT_ACCT_ENDPOINT, {


headers: { Authorization: `Bearer ${token}` },
params: {
$filter: filterString,
$orderby: 'DateAcct asc',
$expand: 'Account_ID,AD_Table_ID',
$top: top,
$skip: skip,
$count: true,
},
})
[Link]('Response data:', [Link])

[Link] = [Link]['@[Link]'] || 0
[Link] = [Link]([Link] / pageSize)
const lignes = [Link] || []

const result = await [Link](


[Link](async (ligne) => {
let reference = [Link] || ''
let journalCode = ''
let compteNom = ligne.Account_ID?.Name || ''
let journalId = null

if (ligne.AD_Table_ID?.id === GL_JOURNALLINE_TABLE_ID) {


const recordId = ligne.Record_ID
try {
const journalLineRes = await [Link](`${JOURNAL_LINE_ENDPOINT}/${recordId}`, {
headers: { Authorization: `Bearer ${token}` },
})
const journalLine = [Link]
journalId = journalLine?.GL_Journal_ID?.id || null

if (journalId) {
const journalRes = await [Link](`${JOURNAL_ENDPOINT}/${journalId}`, {
headers: { Authorization: `Bearer ${token}` },
})
const journal = [Link]
reference = journal?.DocumentNo || reference
journalCode = journal?.DocumentStatus || 'OD'
}
} catch (err) {
[Link]('Erreur récupération journal:', [Link])
}
}

return {
id: [Link], // ID réel de Fact_Acct
journalId,
date: [Link],
reference,
journal: journalCode,
compte: ligne.Account_ID?.Value || '',
compteNom,
description: [Link] || '',
debit: Number([Link] || 0),
credit: Number([Link] || 0),
editing: false,
recordId: ligne.Record_ID, // 👈 Clé importante ici
}
})
)

const referencesFiltrees = new Set()

[Link]((item) => {
const montant = [Link]([Link], [Link])
if (typeMontant === 'debit' && (prixMin === null || [Link] >= prixMin) && (prixMax === null || [Link] <=
prixMax)) {
[Link]([Link])
} else if (typeMontant === 'credit' && (prixMin === null || [Link] >= prixMin) && (prixMax === null || [Link]
<= prixMax)) {
[Link]([Link])
} else if (typeMontant === 'both' && (prixMin === null || montant >= prixMin) && (prixMax === null || montant <=
prixMax)) {
[Link]([Link])
}
})

const lignesFiltrees = [Link]((item) => [Link]([Link]))

if (libelle) {
const recherche = [Link]()
return [Link](
(item) =>
[Link]?.toLowerCase().includes(recherche) ||
[Link]?.toLowerCase().includes(recherche) ||
[Link]?.toLowerCase().includes(recherche) ||
[Link]?.toLowerCase().includes(recherche)
)
}

return lignesFiltrees
} catch (err) {
[Link]('Erreur chargement grand livre:', [Link]?.data || [Link])
throw new Error('Echec du chargement du grand livre')
}
}

async function chargerDonnees() {


[Link] = false
try {
const skip = ([Link] - 1) * pageSize
const data = await fetchGrandLivre({
prixMin: [Link],
prixMax: [Link],
typeMontant: [Link],
accountValue: accountIdFromRoute,
libelle: [Link],
skip,
top: pageSize,
})
[Link] = data

const groupes = [Link]((acc, ligne) => {


if (!acc[[Link]]) acc[[Link]] = []
acc[[Link]].push(ligne)
return acc
}, {})

[Link] = [Link](groupes).filter(groupe => {


const totalDebit = [Link]((sum, l) => sum + [Link], 0)
const totalCredit = [Link]((sum, l) => sum + [Link], 0)
return totalDebit !== totalCredit
}).flat()

} catch {
alert('Erreur lors du chargement des données')
}
[Link] = true
}

function pageSuivante() {
if ([Link] < [Link]) {
[Link]++
}
}

function pagePrecedente() {
if ([Link] > 1) {
[Link]--
}
}

function modifierLigne(index) {
[Link][index].editing = true
}

function annulerEdition(index) {
[Link][index].editing = false
chargerDonnees()
}

async function enregistrerLigne(index) {


const ligne = [Link][index]

const token = await getToken()

try {
[Link]('Enregistrement ligne:', ligne);
if ([Link] == null) {
throw new Error("recordId manquant ou invalide — impossible de mettre à jour.")
}
await [Link](`${FACT_ACCT_ENDPOINT}/${[Link]}`, {
headers: { Authorization: `Bearer ${token}` }
});

const factAcctPayload = {
DateAcct: [Link],
DateTrx: [Link],
Account_ID: { identifier: [Link] },
AmtAcctDr: parseFloat([Link] || 0),
AmtAcctCr: parseFloat([Link] || 0),
Description: [Link],
AD_Client_ID: 11,
AD_Org_ID: 11,
IsActive: 'Y',
C_Period_ID: 155,
C_AcctSchema_ID: 101,
AD_Table_ID: 224,
Record_ID: [Link], // Utilisation de recordId pour la mise à jour
PostingType: 'A',
C_Currency_ID: 108
};
[Link]("Envoi de la requête PUT avec payload:", factAcctPayload);

await [Link](FACT_ACCT_ENDPOINT, factAcctPayload, {


headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json'
}
});

[Link] = false
alert('Montant mis à jour avec succès.')
} catch (err) {
[Link]('Erreur mise à jour :', [Link]?.data || [Link])
alert('Erreur lors de la mise à jour : ' + ([Link]?.data?.detail || [Link]))
}
}

const formatMontant = (montant) => Number(montant).toFixed(2)

watch(page, chargerDonnees)
</script>

<style scoped>
.container {
max-width: 900px;
margin: 2rem auto;
font-family: Arial, sans-serif;
color: #222;
}
.page-title {
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 1.8rem;
margin-bottom: 1rem;
}
.icon {
width: 1.5rem;
height: 1.5rem;
color: #3182ce;
}
.filter-form {
display: flex;
flex-wrap: wrap;
gap: 1rem;
justify-content: center;
margin-bottom: 1rem;
}
.filter-form label {
font-weight: 600;
font-size: 1rem;
display: flex;
flex-direction: column;
color: #4a5568;
}
.filter-form input {
padding: 0.3rem 0.5rem;
border: 1px solid #cbd5e0;
border-radius: 4px;
margin-top: 0.3rem;
}
.filter-form button {
padding: 0.4rem 1.2rem;
background-color: #2b6cb0;
border: none;
color: white;
border-radius: 4px;
font-weight: 600;
cursor: pointer;
}
.filter-form button:hover {
background-color: #2c5282;
}
.ledger-table {
width: 100%;
border-collapse: collapse;
margin-top: 1rem;
}
.ledger-table th,
.ledger-table td {
padding: 0.5rem;
border: 1px solid #e2e8f0;
text-align: center;
}
.ledger-table th {
background-color: #f7fafc;
font-weight: bold;
}
.pagination {
margin-top: 1rem;
display: flex;
justify-content: center;
align-items: center;
gap: 1rem;
}
.pagination button {
padding: 0.3rem 0.8rem;
font-weight: 600;
border-radius: 4px;
border: 1px solid #2b6cb0;
background-color: white;
color: #2b6cb0;
cursor: pointer;
}
.pagination button:disabled {
opacity: 0.5;
cursor: not-allowed;
}
</style>

async function enregistrerLigne(index) {


const ligne = [Link][index]
const token = await getToken()

try {
if (!ligne.Record_ID) {
throw new Error("recordId manquant ou invalide — impossible de mettre à jour.")
}
const factAcctPayload = {
DateAcct: date,
DateTrx: date,
Account_ID: { identifier: [Link] },
AmtAcctDr: parseFloat([Link] || 0),
AmtAcctCr: parseFloat([Link] || 0),
Description: [Link],
AD_Client_ID: 11,
AD_Org_ID: 11,
IsActive: 'Y',
C_Period_ID: 155,
C_AcctSchema_ID: 101,
AD_Table_ID: 224,
Record_ID: journalId,
PostingType: 'A',
C_Currency_ID: 108
};
await [Link](`${FACT_ACCT_ENDPOINT}/${[Link]}`, {
factAcctPayload
}, {
headers: {
Authorization: `Bearer ${token}`,
},
})

[Link] = false
alert('Montant mis à jour avec succès.')
} catch (err) {
[Link]('Erreur mise à jour :', [Link]?.data || [Link])
alert('Erreur lors de la mise à jour : ' + ([Link]?.data?.detail || [Link]))
}
}

<template>
<div class="container">
<center>
<h1 class="page-title" style="color: green;">
<BookOpen class="icon" />
Recherche de Comptes par Prix
</h1>
</center>

<form @[Link]="chargerDonnees" class="filter-form">


<label>
Prix Min :
<input type="number" [Link]="prixMin" />
</label>
<label>
Prix Max :
<input type="number" [Link]="prixMax" />
</label>
<label>
Type :
<select v-model="typeMontant">
<option value="debit">Débit</option>
<option value="credit">Crédit</option>
<option value="both">Les deux</option>
</select>
</label>

<button type="submit">Rechercher</button>
</form>
<table v-if="[Link]" class="ledger-table">
<thead>
<tr>
<th>Date</th>
<th>Référence</th>
<th>Journal</th>
<th>Compte</th>
<th>Débit</th>
<th>Crédit</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr v-for="(ligne, index) in donnees" :key="index">
<td>{{ new Date([Link]).toLocaleDateString() }}</td>
<td>{{ [Link] }}</td>
<td>{{ [Link] }}</td>
<td>{{ [Link] }}</td>
<td>
<div v-if="[Link]">
<input type="number" [Link]="[Link]" />
</div>
<div v-else>
{{ formatMontant([Link]) }}
</div>
</td>
<td>
<div v-if="[Link]">
<input type="number" [Link]="[Link]" />
</div>
<div v-else>
{{ formatMontant([Link]) }}
</div>
</td>
<td>
<div v-if="[Link]">
<button @click="enregistrerLigne(index)">Enregistrer</button>
<button @click="annulerEdition(index)">Annuler</button>
</div>
<div v-else>
<button @click="modifierLigne(index)">Modifier</button>
</div>
</td>
</tr>
</tbody>

</table>
<p v-if="![Link] && dejaCharge">Aucun résultat trouvé.</p>

<div v-if="totalPages > 1" class="pagination">


<button @click="pagePrecedente" :disabled="page === 1">Précédent</button>
<span>Page {{ page }} / {{ totalPages }}</span>
<button @click="pageSuivante" :disabled="page === totalPages">Suivant</button>
</div>

<h2 v-if="[Link]" style="color: red; margin-top: 2rem;">


Écritures Non Équilibrées
</h2>

<table v-if="[Link]" class="ledger-table">


<thead>
<tr>
<th>Date</th>
<th>Référence</th>
<th>Journal</th>
<th>Compte</th>
<th>Débit</th>
<th>Crédit</th>
</tr>
</thead>
<tbody>
<tr v-for="(ligne, index) in lignesNonEquilibrees" :key="'neq-' + index">
<td>{{ new Date([Link]).toLocaleDateString() }}</td>
<td>{{ [Link] }}</td>
<td>{{ [Link] }}</td>
<td>{{ [Link] }}</td>
<td>{{ formatMontant([Link]) }}</td>
<td>{{ formatMontant([Link]) }}</td>
</tr>
</tbody>
</table>
</div>
</template>

<script setup>
import { ref, watch } from 'vue'
import { BookOpen } from 'lucide-vue-next'
import { useRoute } from 'vue-router'
import axios from 'axios'
import { getToken } from '../services/Token'

const FACT_ACCT_ENDPOINT = '/api/v1/models/Fact_Acct'


const JOURNAL_LINE_ENDPOINT = '/api/v1/models/GL_JournalLine'
const JOURNAL_ENDPOINT = '/api/v1/models/GL_Journal'
const GL_JOURNALLINE_TABLE_ID = 224

const prixMin = ref(null)


const prixMax = ref(null)
const typeMontant = ref('both')
const libelle = ref('')
const donnees = ref([])
const lignesNonEquilibrees = ref([])
const dejaCharge = ref(false)
const page = ref(1)
const pageSize = 100
const totalRecords = ref(0)
const totalPages = ref(1)

const route = useRoute()


const accountIdFromRoute = [Link]?.accountId || null

async function fetchGrandLivre({ prixMin, prixMax, typeMontant, accountValue, libelle, skip, top }) {
try {
const token = await getToken()
const filters = []
if (accountValue) [Link](`Account_ID eq ${accountValue}`)
const filterString = [Link] > 0 ? [Link](' and ') : undefined

const response = await [Link](FACT_ACCT_ENDPOINT, {


headers: { Authorization: `Bearer ${token}` },
params: {
$filter: filterString,
$orderby: 'DateAcct asc',
$expand: 'Account_ID,AD_Table_ID',
$top: top,
$skip: skip,
$count: true,
},
})

[Link] = [Link]['@[Link]'] || 0
[Link] = [Link]([Link] / pageSize)
const lignes = [Link] || []

const result = await [Link](


[Link](async (ligne) => {
let reference = [Link] || ''
let journalCode = ''
let compteNom = ligne.Account_ID?.Name || ''
let journalId = null
if (ligne.AD_Table_ID?.id === GL_JOURNALLINE_TABLE_ID) {
const recordId = ligne.Record_ID
try {
const journalLineRes = await [Link](`${JOURNAL_LINE_ENDPOINT}/${recordId}`, {
headers: { Authorization: `Bearer ${token}` },
})
const journalLine = [Link]
journalId = journalLine?.GL_Journal_ID?.id || null

if (journalId) {
const journalRes = await [Link](`${JOURNAL_ENDPOINT}/${journalId}`, {
headers: { Authorization: `Bearer ${token}` },
})
const journal = [Link]
reference = journal?.DocumentNo || reference
journalCode = journal?.DocumentStatus || 'OD'
}
} catch (err) {
[Link]('Erreur récupération journal:', [Link])
}
}

return {
id: [Link], // ID réel de Fact_Acct
journalId,
date: [Link],
reference,
journal: journalCode,
compte: ligne.Account_ID?.Value || '',
compteNom,
description: [Link] || '',
debit: Number([Link] || 0),
credit: Number([Link] || 0),
editing: false,
recordId: [Link], // 👈 Clé importante ici
}
})
)

const referencesFiltrees = new Set()

[Link]((item) => {
const montant = [Link]([Link], [Link])
if (typeMontant === 'debit' && (prixMin === null || [Link] >= prixMin) && (prixMax === null || [Link] <=
prixMax)) {
[Link]([Link])
} else if (typeMontant === 'credit' && (prixMin === null || [Link] >= prixMin) && (prixMax === null || [Link]
<= prixMax)) {
[Link]([Link])
} else if (typeMontant === 'both' && (prixMin === null || montant >= prixMin) && (prixMax === null || montant <=
prixMax)) {
[Link]([Link])
}
})

const lignesFiltrees = [Link]((item) => [Link]([Link]))

if (libelle) {
const recherche = [Link]()
return [Link](
(item) =>
[Link]?.toLowerCase().includes(recherche) ||
[Link]?.toLowerCase().includes(recherche) ||
[Link]?.toLowerCase().includes(recherche) ||
[Link]?.toLowerCase().includes(recherche)
)
}

return lignesFiltrees
} catch (err) {
[Link]('Erreur chargement grand livre:', [Link]?.data || [Link])
throw new Error('Echec du chargement du grand livre')
}
}

async function chargerDonnees() {


[Link] = false
try {
const skip = ([Link] - 1) * pageSize
const data = await fetchGrandLivre({
prixMin: [Link],
prixMax: [Link],
typeMontant: [Link],
accountValue: accountIdFromRoute,
libelle: [Link],
skip,
top: pageSize,
})
[Link] = data

const groupes = [Link]((acc, ligne) => {


if (!acc[[Link]]) acc[[Link]] = []
acc[[Link]].push(ligne)
return acc
}, {})

[Link] = [Link](groupes).filter(groupe => {


const totalDebit = [Link]((sum, l) => sum + [Link], 0)
const totalCredit = [Link]((sum, l) => sum + [Link], 0)
return totalDebit !== totalCredit
}).flat()

} catch {
alert('Erreur lors du chargement des données')
}
[Link] = true
}

function pageSuivante() {
if ([Link] < [Link]) {
[Link]++
}
}

function pagePrecedente() {
if ([Link] > 1) {
[Link]--
}
}

function modifierLigne(index) {
[Link][index].editing = true
}

function annulerEdition(index) {
[Link][index].editing = false
chargerDonnees()
}

async function enregistrerLigne(index) {


const ligne = [Link][index]
const token = await getToken()

try {
if (![Link]) {
throw new Error("recordId manquant ou invalide — impossible de mettre à jour.")
}

await [Link](`${FACT_ACCT_ENDPOINT}/${[Link]}`, {
AmtAcctDr: [Link],
AmtAcctCr: [Link],
}, {
headers: {
Authorization: `Bearer ${token}`,
},
})

[Link] = false
alert('Montant mis à jour avec succès.')
} catch (err) {
[Link]('Erreur mise à jour :', [Link]?.data || [Link])
alert('Erreur lors de la mise à jour : ' + ([Link]?.data?.detail || [Link]))
}
}

const formatMontant = (montant) => Number(montant).toFixed(2)

watch(page, chargerDonnees)
</script>

<style scoped>
.container {
max-width: 900px;
margin: 2rem auto;
font-family: Arial, sans-serif;
color: #222;
}
.page-title {
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 1.8rem;
margin-bottom: 1rem;
}
.icon {
width: 1.5rem;
height: 1.5rem;
color: #3182ce;
}
.filter-form {
display: flex;
flex-wrap: wrap;
gap: 1rem;
justify-content: center;
margin-bottom: 1rem;
}
.filter-form label {
font-weight: 600;
font-size: 1rem;
display: flex;
flex-direction: column;
color: #4a5568;
}
.filter-form input {
padding: 0.3rem 0.5rem;
border: 1px solid #cbd5e0;
border-radius: 4px;
margin-top: 0.3rem;
}
.filter-form button {
padding: 0.4rem 1.2rem;
background-color: #2b6cb0;
border: none;
color: white;
border-radius: 4px;
font-weight: 600;
cursor: pointer;
}
.filter-form button:hover {
background-color: #2c5282;
}
.ledger-table {
width: 100%;
border-collapse: collapse;
margin-top: 1rem;
}
.ledger-table th,
.ledger-table td {
padding: 0.5rem;
border: 1px solid #e2e8f0;
text-align: center;
}
.ledger-table th {
background-color: #f7fafc;
font-
weight: bold;
}
.pagination {
margin-top: 1rem;
display: flex;
justify-content: center;
align-items: center;
gap: 1rem;
}
.pagination button {
padding: 0.3rem 0.8rem;
font-weight: 600;
border-radius: 4px;
border: 1px solid #2b6cb0;
background-color: white;
color: #2b6cb0;
cursor: pointer;
}
.pagination button:disabled {
opacity: 0.5;
cursor: not-allowed;

}
</style>

[10/06/2025 13:24] fenoantramanana: <template>


<div class="container">
<center>
<h1 class="page-title" style="color: green;">
<BookOpen class="icon" />
Grand Livre
</h1>
</center>

<form @[Link]="chargerDonnees" class="filter-form">


<label>
Du :
<input type="date" v-model="dateDebut" />
</label>
<label>
Au :
<input type="date" v-model="dateFin" />
</label>
<label>
Libellé :
<input type="text" v-model="libelle" placeholder="Référence ou numéro de compte" />
</label>
<button type="submit">Rechercher</button>
</form>

<table v-if="[Link]" class="ledger-table">


<thead>
<tr>
<th>Date</th>
<th>Référence</th>
<th>Journal</th>
<th>Compte</th>
<th>Débit</th>
<th>Crédit</th>
<th>Solde courant</th>
</tr>
</thead>
<tbody>
<tr v-for="(ligne, index) in donnees" :key="index">
<td>{{ new Date([Link]).toLocaleDateString() }}</td>
<td>{{ [Link] }}</td>
<td>{{ [Link] }}</td>
<td>{{ [Link] }}</td>
<td>{{ formatMontant([Link]) }}</td>
<td>{{ formatMontant([Link]) }}</td>
<td :class="{ positif: [Link] >= 0, negatif: [Link] < 0 }">
{{ formatMontant([Link]) }}
</td>
</tr>
</tbody>
</table>

<p v-if="![Link] && dejaCharge">Aucun résultat trouvé.</p>

<div v-if="totalPages > 1" class="pagination">


<button @click="pagePrecedente" :disabled="page === 1">Précédent</button>
<span>Page {{ page }} / {{ totalPages }}</span>
<button @click="pageSuivante" :disabled="page === totalPages">Suivant</button>
</div>
</div>
</template>

<script setup>
import { ref, watch, onMounted } from 'vue'
import { BookOpen } from 'lucide-vue-next'
import { useRoute } from 'vue-router'
import axios from 'axios'
import { getToken } from '../services/Token'

const FACT_ACCT_ENDPOINT = '/api/v1/models/Fact_Acct'


const JOURNAL_LINE_ENDPOINT = '/api/v1/models/GL_JournalLine'
const JOURNAL_ENDPOINT = '/api/v1/models/GL_Journal'
const GL_JOURNALLINE_TABLE_ID = 224

const dateDebut = ref('')


const dateFin = ref('')
const libelle = ref('')
const donnees = ref([])
const dejaCharge = ref(false)
const page = ref(1)
const pageSize = 100
const totalRecords = ref(0)
const totalPages = ref(1)

const route = useRoute()


const accountIdFromRoute = [Link]?.accountId || null

async function fetchGrandLivre({ dateDebut, dateFin, accountValue, libelle, skip, top }) {


try {
const token = await getToken()
const filters = []

if (accountValue !== null && accountValue !== undefined && accountValue !== '' && accountValue != 0) {
[Link](Account_ID eq ${accountValue})
}

if (dateDebut) [Link](DateAcct ge '${dateDebut}')


if (dateFin) [Link](DateAcct le '${dateFin}')

const filterString = [Link] > 0 ? [Link](' and ') : undefined

const response = await [Link](FACT_ACCT_ENDPOINT, {


headers: { Authorization: Bearer ${token} },
params: {
$filter: filterString,
$orderby: 'DateAcct asc',
$expand: 'Account_ID,AD_Table_ID',
$top: top,
$skip: skip,
$count: true,
},
})

[Link] = [Link]['@[Link]'] || 0
[Link] = [Link]([Link] / pageSize)
const lignes = [Link] || []

const result = await [Link](


[Link](async (ligne) => {
let reference = [Link] || ''
let journalCode = ''
let compteNom = ligne.Account_ID?.Name || '' // ✅ récupération du nom du compte
if (ligne.AD_Table_ID?.id === GL_JOURNALLINE_TABLE_ID) {
try {
const journalLineRes = await [Link](${JOURNAL_LINE_ENDPOINT}/${ligne.Record_ID}, {
headers: { Authorization: Bearer ${token} },
})
const journalLine = [Link]

if (journalLine?.GL_Journal_ID?.id) {
const journalRes = await [Link](${JOURNAL_ENDPOINT}/${journalLine.GL_Journal_ID.id}, {
headers: { Authorization: Bearer ${token} },
})
const journal = [Link]
reference = journal?.DocumentNo || reference
journalCode = journal?.DocumentStatus || 'OD'
}
} catch (err) {
[Link]('Erreur récupération journal:', [Link])
}
}

return {
date: [Link],
reference,
journal: journalCode,
compte: ligne.Account_ID?.Value || '',
compteNom, // ✅ ajouté
description: [Link] || '',
debit: Number([Link] || 0),
credit: Number([Link] || 0),
}
})
)

// ✅ Ajout du filtre sur le nom du compte (compteNom)


let filtered = result
if (libelle) {
const recherche = [Link]()
filtered = [Link](
(item) =>
([Link] && [Link]().includes(recherche)) ||
([Link] && [Link]().includes(recherche)) ||
([Link] && [Link]().includes(recherche)) ||
([Link] && [Link]().includes(recherche))
)
}

let soldeCumul = 0
[Link]((ligne) => {
soldeCumul = [Link] - [Link]
[Link] = soldeCumul
})

return filtered
} catch (err) {
[Link]('Erreur chargement grand livre:', [Link]?.data || [Link])
throw new Error('Échec du chargement du grand livre')
}
}

async function chargerDonnees() {


[Link] = false
try {
const skip = ([Link] - 1) * pageSize
const data = await fetchGrandLivre({
dateDebut: [Link] || null,
dateFin: [Link] || null,
accountValue: accountIdFromRoute,
libelle: [Link] || null,
skip,
top: pageSize,
})
[Link] = data
} catch {
alert('Erreur lors du chargement du grand livre')
}
[Link] = true
}

function pageSuivante() {
if ([Link] < [Link]) {
[Link]++
}
}

function pagePrecedente() {
if ([Link] > 1) {
[Link]--
}
}

watch(page, () => {
chargerDonnees()
})
onMounted(() => {
chargerDonnees()
})

const formatMontant = (montant) => Number(montant).toFixed(2)


</script>

<style scoped>

.container {
max-width: 900px;
margin: 2rem auto;
font-family: Arial, sans-serif;
color: #222;
}

.page-title {
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 1.8rem;
color: #2d3748;
margin-bottom: 1rem;
text-align: center;
}

.icon {
width: 1.5rem;
height: 1.5rem;
color: #3182ce;
}

.filter-form {
display: flex;
flex-wrap: wrap;
gap: 1rem;
justify-content: center;
margin-bottom: 1rem;
}

.filter-form label {
font-weight: 600;
font-size: 1rem;
display: flex;
flex-direction: column;
color: #4a5568;
}

.filter-form input {
padding: 0.3rem 0.5rem;
border: 1px solid #cbd5e0;
border-radius: 4px;
margin-top: 0.3rem;
}

.filter-form button {
padding: 0.4rem 1.2rem;
background-color: #2b6cb0;
border: none;
color: white;
border-radius: 4px;
font-weight: 600;
cursor: pointer;
}

.filter-form button:hover {
background-color: #2c5282;
}

.ledger-table {
width: 100%;
border-collapse: collapse;
margin-top: 1rem;
}

.ledger-table th,
.ledger-table td {
padding: 0.5rem;
border: 1px solid #e2e8f0;
text-align: center;
}

.ledger-table th {
background-color: #f7fafc;
font-weight: bold;
}

.positif {
color: green;
font-weight: 600;
}
.negatif {
color: red;
font-weight: 600;
}

.pagination {
margin-top: 1rem;
display: flex;
justify-content: center;
align-items: center;
gap: 1rem;
}

.pagination button {
padding: 0.3rem 0.8rem;
font-weight: 600;
border-radius: 4px;
border: 1px solid #2b6cb0;
background-color: white;
color: #2b6cb0;
cursor: pointer;
}

.pagination button:disabled {
opacity: 0.5;
cursor: not-allowed;
}
</style> peut tu mettre un colone ou il y a des boutons ou on peu supprimer une ligne , modifier et un autre bouton ajouter
en haut du tableau pour ajouter une nouvelle ligne
[10/06/2025 13:29] fenoantramanana: <template>
<div class="container">
<center>
<h1 class="page-title" style="color: green;">
<BookOpen class="icon" />
Grand Livre
</h1>
</center>

<form @[Link]="chargerDonnees" class="filter-form">


<label>
Du :
<input type="date" v-model="dateDebut" />
</label>
<label>
Au :
<input type="date" v-model="dateFin" />
</label>
<label>
Libellé :
<input type="text" v-model="libelle" placeholder="Référence ou numéro de compte" />
</label>
<button type="submit">Rechercher</button>
</form>

<div v-if="[Link]" style="text-align: right; margin-bottom: 1rem;">


<button @click="ajouterLigne"> ➕ Ajouter une ligne</button>
</div>

<table v-if="[Link]" class="ledger-table">


<thead>
<tr>
<th>Date</th>
<th>Référence</th>
<th>Journal</th>
<th>Compte</th>
<th>Débit</th>
<th>Crédit</th>
<th>Solde courant</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr v-for="(ligne, index) in donnees" :key="index">
<td>{{ new Date([Link]).toLocaleDateString() }}</td>
<td>{{ [Link] }}</td>
<td>{{ [Link] }}</td>
<td>{{ [Link] }}</td>
<td>{{ formatMontant([Link]) }}</td>
<td>{{ formatMontant([Link]) }}</td>
<td :class="{ positif: [Link] >= 0, negatif: [Link] < 0 }">
{{ formatMontant([Link]) }}
</td>
<td>
<button @click="modifierLigne(index)">Modifier</button>
<button @click="supprimerLigne(index)">Supprimer</button>
</td>
</tr>
</tbody>
</table>

<p v-if="![Link] && dejaCharge">Aucun résultat trouvé.</p>

<div v-if="totalPages > 1" class="pagination">


<button @click="pagePrecedente" :disabled="page === 1">Précédent</button>
<span>Page {{ page }} / {{ totalPages }}</span>
<button @click="pageSuivante" :disabled="page === totalPages">Suivant</button>
</div>
</div>
</template>

<script setup>
import { ref, watch, onMounted } from 'vue'
import { BookOpen } from 'lucide-vue-next'
import { useRoute } from 'vue-router'
import axios from 'axios'
import { getToken } from '../services/Token'

const FACT_ACCT_ENDPOINT = '/api/v1/models/Fact_Acct'


const JOURNAL_LINE_ENDPOINT = '/api/v1/models/GL_JournalLine'
const JOURNAL_ENDPOINT = '/api/v1/models/GL_Journal'
const GL_JOURNALLINE_TABLE_ID = 224

const dateDebut = ref('')


const dateFin = ref('')
const libelle = ref('')
const donnees = ref([])
const dejaCharge = ref(false)
const page = ref(1)
const pageSize = 100
const totalRecords = ref(0)
const totalPages = ref(1)

const route = useRoute()


const accountIdFromRoute = [Link]?.accountId || null

async function fetchGrandLivre({ dateDebut, dateFin, accountValue, libelle, skip, top }) {


try {
const token = await getToken()
const filters = []

if (accountValue) {
[Link](`Account_ID eq ${accountValue}`)
}
if (dateDebut) [Link](`DateAcct ge '${dateDebut}'`)
if (dateFin) [Link](`DateAcct le '${dateFin}'`)

const filterString = [Link] ? [Link](' and ') : undefined

const response = await [Link](FACT_ACCT_ENDPOINT, {


headers: { Authorization: `Bearer ${token}` },
params: {
$filter: filterString,
$orderby: 'DateAcct asc',
$expand: 'Account_ID,AD_Table_ID',
$top: top,
$skip: skip,
$count: true,
},
})

[Link] = [Link]['@[Link]'] || 0
[Link] = [Link]([Link] / pageSize)
const lignes = [Link] || []

const result = await [Link](


[Link](async (ligne) => {
let reference = [Link] || ''
let journalCode = ''
let compteNom = ligne.Account_ID?.Name || ''

if (ligne.AD_Table_ID?.id === GL_JOURNALLINE_TABLE_ID) {


try {
const journalLineRes = await [Link](`${JOURNAL_LINE_ENDPOINT}/${ligne.Record_ID}`, {
headers: { Authorization: `Bearer ${token}` },
})
const journalLine = [Link]

if (journalLine?.GL_Journal_ID?.id) {
const journalRes = await [Link](`${JOURNAL_ENDPOINT}/${journalLine.GL_Journal_ID.id}`, {
headers: { Authorization: `Bearer ${token}` },
})
const journal = [Link]
reference = journal?.DocumentNo || reference
journalCode = journal?.DocumentStatus || 'OD'
}
} catch (err) {
[Link]('Erreur récupération journal:', [Link])
}
}

return {
date: [Link],
reference,
journal: journalCode,
compte: ligne.Account_ID?.Value || '',
compteNom,
description: [Link] || '',
debit: Number([Link] || 0),
credit: Number([Link] || 0),
}
})
)

let filtered = result


if (libelle) {
const recherche = [Link]()
filtered = [Link](
(item) =>
([Link] && [Link]().includes(recherche)) ||
([Link] && [Link]().includes(recherche)) ||
([Link] && [Link]().includes(recherche)) ||
([Link] && [Link]().includes(recherche))
)
}

let soldeCumul = 0
[Link]((ligne) => {
soldeCumul += [Link] - [Link]
[Link] = soldeCumul
})

return filtered
} catch (err) {
[Link]('Erreur chargement grand livre:', [Link]?.data || [Link])
throw new Error('Échec du chargement du grand livre')
}
}

async function chargerDonnees() {


[Link] = false
try {
const skip = ([Link] - 1) * pageSize
const data = await fetchGrandLivre({
dateDebut: [Link] || null,
dateFin: [Link] || null,
accountValue: accountIdFromRoute,
libelle: [Link] || null,
skip,
top: pageSize,
})
[Link] = data
} catch {
alert('Erreur lors du chargement du grand livre')
}
[Link] = true
}

function pageSuivante() {
if ([Link] < [Link]) [Link]++
}

function pagePrecedente() {
if ([Link] > 1) [Link]--
}

function formatMontant(montant) {
return Number(montant).toFixed(2)
}

// ✅ Fonctions ajout/modif/suppression de ligne


function ajouterLigne() {
[Link]({
date: new Date().toISOString().split('T')[0],
reference: 'Nouveau',
journal: '',
compte: '',
debit: 0,
credit: 0,
solde: 0,
})
}

function modifierLigne(index) {
alert(`Modifier la ligne ${index + 1} – fonctionnalité à implémenter`)
}

function supprimerLigne(index) {
if (confirm('Supprimer cette ligne ?')) {
[Link](index, 1)
}
}

watch(page, () => {
chargerDonnees()
})

onMounted(() => {
chargerDonnees()
})
</script>
<style scoped>
.container {
max-width: 900px;
margin: 2rem auto;
font-family: Arial, sans-serif;
color: #222;
}

.page-title {
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 1.8rem;
color
[10/06/2025 13:56] Mon Amour ❤️🥺: <script setup>
import { ref, onMounted, computed } from 'vue'
import axios from 'axios'
import { getToken } from '../services/authService'
import { Calendar, ArrowDown } from 'lucide-vue-next'
import ApexChart from 'vue3-apexcharts'
import Header from './components/[Link]'

const selectedYear = ref('')


const years = ref([])
const rawData = ref([])
const monthlyData = ref([])

// Préparer les données pour le graphe


const chartSeries = computed(() => [
{
name: 'Chiffre d’affaires',
data: [Link](m => [Link])
},
{
name: 'Charges',
data: [Link](m => [Link])
},
{
name: 'Résultat Net',
data: [Link](m => [Link])
}
])

const chartOptions = computed(() => ({


chart: {
toolbar: { show: false },
zoom: { enabled: false }
},
colors: ['#3aad40', '#74b1d7', '#a6d842'],
stroke: { curve: 'straight', width: 3 },
xaxis: {
categories: [Link](m => [Link]),
labels: { rotate: -45 }
},
markers: { size: 3, hover: { size: 7 } },
legend: { position: 'top', horizontalAlign: 'left' },
tooltip: { shared: true, intersect: false }
}))

const fetchRawData = async () => {


try {
const token = await getToken()
const res = await [Link]('/api/v1/models/Fact_Acct', {
headers: { Authorization: `Bearer ${token}` },
params: {
'$select': 'AmtAcctDr, AmtAcctCr, DateAcct, Account_ID',
'$expand': 'Account_ID',
'$top': 1000
}
})

[Link] = [Link](record => ({


debit: Number([Link] || 0),
credit: Number([Link] || 0),
date: new Date([Link]),
account: record.Account_ID?.Value || ''
}))

[Link](rawData);

const uniqueYears = [...new Set([Link](r => [Link]()))].sort((a, b) => a - b)


[Link] = uniqueYears

// Sélection automatique de l'année la plus ancienne


[Link] = uniqueYears[0] || ''
filterByYear()
} catch (err) {
[Link](err)
alert("Erreur lors du chargement des données.")
}
}
const filterByYear = () => {
const year = Number([Link])
const dataByMonth = [Link]({ length: 12 }, (_, i) => ({
month: new Date(0, i).toLocaleString('fr-FR', { month: 'long' }),
revenue: 0,
expense: 0,
net: 0
}))

[Link](entry => {
if ([Link]() === year) {
const idx = [Link]()
if ([Link]('6')) {
dataByMonth[idx].expense += [Link] // Charges : comptes 6, au débit
}

if ([Link]('7')) {
dataByMonth[idx].revenue += [Link] // Produits : comptes 7, au crédit
}
}
})

[Link](m => { [Link] = [Link] - [Link] })


[Link] = dataByMonth
}

onMounted(fetchRawData)
</script>

<template>
<Header />
<main class="main-content">

<div class="table-container">
<form @[Link]="filterByYear" class="filter-form">
<label>
<!-- Année : -->
<select v-model="selectedYear">
<option v-for="year in years" :key="year" :value="year">
{{ year }}
</option>
</select>
</label>
<button type="submit">
<!-- <ArrowDown class="icon" /> -->
Filtrer
</button>
</form>

<!-- Graphe de l'évolution -->


<div class="chart-container" v-if="[Link]">
<ApexChart
type="line"
:options="chartOptions"
:series="chartSeries"
height="350"
/>
</div>

<!-- Tableau mensuel -->


<table v-if="[Link]" class="custom-table">
<thead>
<tr>
<th>Mois</th>
<th>Chiffre d’affaires (€)</th>
<th>Charges (€)</th>
<th>Résultat Net (€)</th>
</tr>
</thead>
<tbody>
<tr v-for="row in monthlyData" :key="[Link]">
<td>{{ [Link] }}</td>
<td class="revenue">{{ [Link](2) }}</td>
<td class="expense">{{ [Link](2) }}</td>
<td :class="{ positive: [Link] >= 0, negative: [Link] < 0 }">
{{ [Link](2) }}
</td>
</tr>
</tbody>
</table>
<p v-else>Aucune donnée disponible.</p>
</div>

</main>
</template>

<style scoped>
@import url('[Link]

.container {
margin: 2rem auto;
padding: 1rem;
font-family: 'Inter', sans-serif;
color: #2d3748;
background-color: #f7fafc;
border-radius: 12px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
}

.table-container {
background-color: white;
border-radius: 8px;
padding: 2rem;
box-shadow: 0 0 12px rgba(0, 0, 0, 0.05);
border: 1px solid #e5e7eb;
}

.main-content {
margin-left: 250px; /* décalage = largeur de la sidebar fixée */
padding: 2rem;
background-color: #f7f7fa;
min-height: 100vh;
width: 82%;
margin-top: -10px;
}

h1 {
text-align: center;
font-size: 1.8rem;
margin-bottom: 1.5rem;
color: #2b6cb0;
}

.filter-form {
display: flex;
gap: 1rem;
align-items: center;
justify-content: center;
margin-bottom: 1.5rem;
}

.filter-form label {
display: flex;
align-items: center;
gap: 0.5rem;
font-weight: 600;
color: #4a5568;
}

select {
padding: 0.4rem 0.6rem;
border: 1px solid #cbd5e0;
border-radius: 6px;
background-color: #fff;
cursor: pointer;
}

button {
display: flex;
align-items: center;
gap: 0.4rem;
padding: 0.45rem 1rem;
background-color: #3182ce;
border: none;
color: white;
font-weight: 600;
border-radius: 6px;
cursor: pointer;
transition: background-color 0.3s ease;
}

button:hover { background-color: #2b6cb0 }

.icon { width: 1rem; height: 1rem }

.chart-container {
margin: 2rem 0;
background: white;
padding: 1rem;
border-radius: 8px;
/* box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); */
}

.custom-table {
width: 100%;
border-collapse: collapse;
}

.custom-table th,
.custom-table td {
padding: 12px 16px;
text-align: left;
border-bottom: 1px solid #e0e0e0;
}

.custom-table th {
color: #3498db;
background-color: #edf8ff;
font-weight: 600;
}

.custom-table tbody tr:hover {


background-color: #f2f2f2;
}
.revenue { color: #2b6cb0 }
.expense { color: #2b6cb0 }
.positive { color: #2b6cb0; font-weight: bold }
.negative { color: #ff0000; font-weight: bold }
</style>
[10/06/2025 14:08] Mon Amour ❤️🥺: <script setup>
import { ref, onMounted, computed } from 'vue'
import axios from 'axios'
import { getToken } from '../services/authService'
import { Calendar, ArrowDown } from 'lucide-vue-next'
import ApexChart from 'vue3-apexcharts'
import Header from './components/[Link]'

const selectedYear = ref('')


const years = ref([])
const rawData = ref([])
const monthlyData = ref([])

// Préparer les données pour le graphe


const chartSeries = computed(() => [
{
name: 'Chiffre d’affaires',
data: [Link](m => [Link])
},
{
name: 'Charges',
data: [Link](m => [Link])
},
{
name: 'Résultat Net',
data: [Link](m => [Link])
}
])

const chartOptions = computed(() => ({


chart: {
toolbar: { show: false },
zoom: { enabled: false }
},
colors: ['#3aad40', '#74b1d7', '#a6d842'],
stroke: { curve: 'straight', width: 3 },
xaxis: {
categories: [Link](m => [Link]),
labels: { rotate: -45 }
},
markers: { size: 3, hover: { size: 7 } },
legend: { position: 'top', horizontalAlign: 'left' },
tooltip: { shared: true, intersect: false }
}))

const fetchRawData = async () => {


try {
const token = await getToken()
const res = await [Link]('/api/v1/models/Fact_Acct', {
headers: { Authorization: `Bearer ${token}` },
params: {
'$select': 'AmtAcctDr, AmtAcctCr, DateAcct, Account_ID',
'$expand': 'Account_ID',
'$top': 1000
}
})

[Link] = [Link](record => ({


debit: Number([Link] || 0),
credit: Number([Link] || 0),
date: new Date([Link]),
account: record.Account_ID?.Value || ''
}))

[Link](rawData);

const uniqueYears = [...new Set([Link](r => [Link]()))].sort((a, b) => a - b)


[Link] = uniqueYears

// Sélection automatique de l'année la plus ancienne


[Link] = uniqueYears[0] || ''
filterByYear()
} catch (err) {
[Link](err)
alert("Erreur lors du chargement des données.")
}
}

const filterByYear = () => {


const year = Number([Link])
const dataByMonth = [Link]({ length: 12 }, (_, i) => ({
month: new Date(0, i).toLocaleString('fr-FR', { month: 'long' }),
revenue: 0,
expense: 0,
net: 0
}))

[Link](entry => {
if ([Link]() === year) {
const idx = [Link]()
if ([Link]('6')) {
dataByMonth[idx].expense += [Link] // Charges : comptes 6, au débit

if ([Link]('7')) {
dataByMonth[idx].revenue += [Link] // Produits : comptes 7, au crédit
[Link](`Débit pour ${[Link]}: ${[Link]} €`);
}
}
})

[Link](m => { [Link] = [Link] - [Link] })


[Link] = dataByMonth
}

onMounted(fetchRawData)
</script>
[18/06/2025 08:46] Mon Amour ❤️🥺: import heapq
import networkx as nx
import [Link] as plt

def dijkstra(graph, start, end):


heap = [(0, start, [])]
visited = set()

while heap:
cost, node, path = [Link](heap)

if node in visited:
continue
[Link](node)
path = path + [node]

if node == end:
return cost, path
for neighbor, weight in [Link](node, {}).items():
if neighbor not in visited:
[Link](heap, (cost + weight, neighbor, path))

return float('inf'), []

# Graphe sous forme de dictionnaire


graph_dict = {
'A': {'B': 3, 'C': 4},
'B': {'C': 2, 'D': 5},
'C': {'D': 1, 'E': 7},
'D': {'E': 3},
}

# Création du graphe NetworkX


G = [Link]()
for node in graph_dict:
for neighbor, weight in graph_dict[node].items():
G.add_edge(node, neighbor, weight=weight)

# Recherche du chemin le plus rapide


start, end = 'A', 'E'
cost, path = dijkstra(graph_dict, start, end)

# Affichage du graphe
pos = nx.spring_layout(G) # positions des noeuds

# Tous les noeuds et arêtes


[Link](G, pos, with_labels=True, node_color='lightblue', edge_color='gray', node_size=1000, font_weight='bold')
edge_labels = nx.get_edge_attributes(G, 'weight')
nx.draw_networkx_edge_labels(G, pos, edge_labels=edge_labels)

# Mettre en rouge les arêtes du chemin le plus court


path_edges = list(zip(path, path[1:]))
nx.draw_networkx_edges(G, pos, edgelist=path_edges, edge_color='red', width=2)

[Link](f"Chemin le plus rapide de {start} à {end} (Coût = {cost})")


[Link]()
[18/06/2025 08:47] Mon Amour ❤️🥺: import heapq
def dijkstra(graph, start, end):
heap = [(0, start, [])] # (coût total, noeud courant, chemin)
visited = set()

while heap:
cost, node, path = [Link](heap)
if node in visited:
continue

[Link](node)
path = path + [node]

if node == end:
return cost, path

for neighbor, weight in [Link](node, {}).items():


if neighbor not in visited:
[Link](heap, (cost + weight, neighbor, path))

return float('inf'), []

# Définition du graphe
graph = {
'A': {'B': 3, 'C': 4},
'B': {'C': 2, 'D': 5},
'C': {'D': 1, 'E': 7},
'D': {'E': 3},
}

# Recherche du chemin le plus rapide de A à E


start = 'A'
end = 'E'
cost, path = dijkstra(graph, start, end)

# Résultat
print(f"Chemin le plus rapide de {start} à {end} : {' -> '.join(path)}")
print(f"Coût total : {cost}")

[07/04/2025 17:33] Mon Amour ❤️🥺: const commandeData = {


socid: socid,
date: date,
lines: [Link](item => ({
id: [Link],
ref: [Link],
qty: [Link],
price: [Link],
tva_tx: item.tva_tx,
desc: [Link],
label: [Link],
product_type: 0,
subprice: [Link],
vat_src_code: '',
localtax1_tx: 0,
localtax2_tx: 0,
remise_percent: 0,
info_bits: 0,
special_code: 0,
array_options: [],
fk_product: null, // Ajouté à null, ou ID produit si nécessaire
fk_remise_except: null, // Ajouté à null si pas de remise
date_start: null, // Ajouté à null
date_end: null, // Ajouté à null
rang: 0, // Ajouté à 0, ou un rang si nécessaire
fk_fournprice: null, // Ajouté à null
pa_ht: 0, // Ajouté à 0 pour le prix HT
fk_unit: null // Ajouté à null pour l'unité
}))
};
[05/06/2025 11:39] fenoantramanana: <template>
<div class="container">
<h1>Balance Comptable</h1>

<form @[Link]="filterBalance" class="filter-form">


<label>
Du :
<input type="date" v-model="fromDate" />
</label>
<label>
Au :
<input type="date" v-model="toDate" />
</label>
<button type="submit">Filtrer</button>
</form>

<table v-if="[Link]" class="balance-table">


<thead>
<tr>
<th>Compte N°</th>
<th>Nom du compte</th>
<th>Libellé</th>
<th>Date</th>
<th>Total Débit</th>
<th>Total Crédit</th>
<th>Solde</th>
</tr>
</thead>
<tbody>
<tr v-for="item in paginatedData" :key="[Link]">
<td>
<router-link :to="`/grand-livre/${[Link]}`" style="color: #2b6cb0; text-decoration: underline;">
{{ [Link] }}
</router-link>
</td>
<td>{{ [Link] }}</td>
<td>{{ [Link] }}</td>
<td>{{ new Date([Link]).toLocaleDateString() }}</td>
<td>{{ [Link](2) }}</td>
<td>{{ [Link](2) }}</td>
<td :class="{ positive: [Link] - [Link] >= 0, negative: [Link] - [Link] < 0 }">
{{ ([Link] - [Link]).toFixed(2) }}
</td>
</tr>
</tbody>
</table>

<p v-if="[Link] === 0">Aucun résultat trouvé.</p>

<div class="pagination-controls" v-if="[Link] > itemsPerPage">


<button @click="prevPage" :disabled="currentPage === 1">← Précédent</button>
<span>Page {{ currentPage }}</span>
<button @click="nextPage" :disabled="currentPage * itemsPerPage >= [Link]">Suivant →</button>
</div>
</div>
</template>

<script setup>
import { ref, computed, onMounted } from 'vue'
import axios from 'axios'
import { getToken } from '../services/Token'

const fromDate = ref('')


const toDate = ref('')
const grouped = ref([])
const currentPage = ref(1)
const itemsPerPage = 50

const paginatedData = computed(() => {


const start = ([Link] - 1) * itemsPerPage
const end = start + itemsPerPage
return [Link](start, end)
})

const nextPage = () => {


if ([Link] * itemsPerPage < [Link]) [Link]++
}

const prevPage = () => {


if ([Link] > 1) [Link]--
}

const fetchBalance = async () => {


try {
const token = await getToken()
const res = await [Link]('/api/v1/models/Fact_Acct', {
headers: { Authorization: `Bearer ${token}` },
params: {
'$select': 'Account_ID, AmtAcctDr, AmtAcctCr, Description, DateAcct',
'$top': 1000
}
})

const tempGrouped = {}
for (const record of [Link]) {
const id = record.Account_ID.id
if (!tempGrouped[id]) {
tempGrouped[id] = {
accountId: id,
totalDebit: 0,
totalCredit: 0,
description: [Link] || '',
dateAcct: [Link]
}
}
tempGrouped[id].totalDebit += Number([Link] || 0)
tempGrouped[id].totalCredit += Number([Link] || 0)
}

const promises = [Link](tempGrouped).map(async id => {


const res = await [Link](`/api/v1/models/C_ElementValue/${id}`, {
headers: { Authorization: `Bearer ${token}` }
})
tempGrouped[id].accountCode = [Link]
tempGrouped[id].accountName = [Link]
})

await [Link](promises)
[Link] = [Link](tempGrouped)
} catch (err) {
[Link](err)
alert("Erreur lors de la récupération de la balance")
}
}

const filterBalance = async () => {


await fetchBalance()

if ([Link] || [Link]) {
const from = [Link] ? new Date([Link]) : null
const to = [Link] ? new Date([Link]) : null

[Link] = [Link](item => {


const date = new Date([Link])
return (!from || date >= from) && (!to || date <= to)
})
}
}

onMounted(() => {
fetchBalance()
})
</script>

<style scoped>
.container {
max-width: 900px;
margin: 2rem auto;
padding: 0 1rem;
font-family: Arial, sans-serif;
color: #222;
}

h1 {
text-align: center;
margin-bottom: 1.5rem;
color: #1a202c;
}

.filter-form {
display: flex;
gap: 1rem;
justify-content: center;
margin-bottom: 1.5rem;
}

.filter-form label {
font-weight: 600;
font-size: 1rem;
display: flex;
flex-direction: column;
color: #4a5568;
}
.filter-form input {
padding: 0.3rem 0.5rem;
border: 1px solid #cbd5e0;
border-radius: 4px;
margin-top: 0.3rem;
}

.filter-form button {
padding: 0.4rem 1rem;
background-color: #2b6cb0;
border: none;
color: white;
border-radius: 4px;
cursor: pointer;
align-self: flex-end;
font-weight: 600;
transition: background-color 0.3s ease;
}

.filter-form button:hover {
background-color: #2c5282;
}

.balance-table {
width: 100%;
border-collapse: collapse;
text-align: center;
}

.balance-table th,
.balance-table td {
border: 1px solid #e2e8f0;
padding: 0.5rem;
}

.balance-table th {
background-color: #edf2f7;
font-weight: 700;
}

.positive {
color: green;
font-weight: 600;
}

.negative {
color: red;
font-weight: 600;
}

.pagination-controls {
display: flex;
justify-content: center;
margin-top: 1rem;
gap: 1rem;
align-items: center;
}

.pagination-controls button {
padding: 0.3rem 0.8rem;
background: #4a5568;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
</style>

Vous aimerez peut-être aussi