Calculer somme

Bonjour,

Un de mes clients me rapporte le problème suivant : ses clients paient parfois par un seul versement plusieurs factures. Il aimerait que je lui fasse une mécanique qui sélectionne automatiquement les factures concernées.

Alors je devrais sélectionner d’une chaine de chiffres (par exemple 150, 280, 1470, 478, 123, 758) les bonnes, afin de créer la somme souhaitée (par exemple 881). Dans cet exemple 280 + 478 + 123 = 881.

La chaine de chiffres peut avoir n’importe quelle longueur et toutes les combines sont possibles afin de créer la somme souhaitée. Comme dans l’exemple 123 + 758 = 881.

A mon avis c’est un problème sans solutions parce que le nombre de combinations augmente exponentiellement avec la longueur de la chaine de chiffres.

Mais peut être je ne vois pas la bonne solution ?

Olivier

O,

Ça ressemble au mécanisme de lettrage automatique dans ma comptabilité.

Bonjour.

Un dialogue avec une liste box de 4 colonnes.
Boîte à cocher, total ttc, client, num facture.

L’utilisateur clique les factures à régler avec le paiement .
Un bouton valider qui va affecter la quote part du règlement à chaque facture cochée.
Un log qui garde la trace de l’affectation.

HTH

C’est ce que j’ai voulu proposer comme solution, mais le client aimerait la boîte automatique…

Je comprends son point de vue, de premier vue ça paraît simple… mais effectivement ça devient très compliqué et je ne pense pas qu’il y a une solution magique.

Ton problème n’est pas faisable ; il suffit que tu aies 2 factures avec le même montant, dans ce cas impossible de déterminer de quelle facture il s’agit (si qu’une des 2 doit être utilisée).

L’inverse est simple, l’utilisateur choisit ses factures à régler tu génères un règlement qui solde la facture (ajout d’un n° de lot sur chaque règlement).

Sinon avec un fifo :
En utilisant le champ du montant payé .
Tu le décrémentes et affecte pour chaque factures triées par date ou par montant à payer.
Tu arrêtes quand tu arrives à zéro.

C’est pas une reconnaissance automatique
Mais c’est qui se fait…

: Olivier FLURY

A mon avis c’est un problème sans solutions parce que le nombre de
combinations augmente exponentiellement avec la longueur de la chaine
de chiffres.
Bonjour Olivier,
mon tout premier programme (je suis ému…) était similaire : d’un coté des masses moléculaires, de l’autre une masse totale, trouver quelles combinaisons additionnés peuvent donner le total. Dans ton cas, avant de tomber sur “trop” de solutions, il faudrait un nombre assez colossal de factures.

Il y a tellement de critères subjectifs pour payer des factures, date d’échéance, priorité qu’on donne à tel ou tel fournisseur, etc…

Et https://fr.wikipedia.org/wiki/Lettrage_comptablele lettrage> ne doit pas être une roulette russe, il faut lettrer les bonnes factures, pas au pif…

Propose lui la boite semi-automatique… :lol: :mrgreen:

Tu automatises les cas simples, et tu le laisses faire pour les cas complexes.

car en plus rien ne dit que le montant initial de règlement correspond à un montant qui tombe juste
(ex: Si on règle partiellement une facture)

Je pense que je vais lui proposer une solution manuelle. S’il insiste sur la boîte automatique je vais chiffrer une “solution” afin que la gravitation de la réalité fasse son effet correctif. :mrgreen:

Olivier,

Je pense que la méthode https://forums.4d.com/4DBB_Main/x_User/4018/files/29245791.zip ci-dessous fait ce que tu souhaites :

  • on lui passe un montant à payer
  • des montants à rapprocher
  • elle cherche la combinaison de n parmi m qui correspond au montant à payer.
    Ca fait un moment que je ne l’ai pas utilisée mais elle fonctionnait sans problème observé de temps de réponse en interprété.

<code 4D>
//UTI_Combinatoire_Chercher
//________________________________________________________________________________
//DESCRIPTION FONCTIONNELLE
//Cette méthode recherche :
//- dans le tableau de valeurs passé en paramètre 2
//- la combinaison dont le total est égal au montant passé en paramètre 1
//- le tableau en 3e paramètre contient les ID d’enregistrement ; en les effaçant, on indique à la méthode appelante les valeurs retenues.

//La recherche des combinaisons se fait :
//- en représentant une combinaison par un nombre binaire (matrice) dont chaque bit correspond à une des valeurs à combiner
//- si un bit est à 1, cela signifie que l’élément correspondant est retenu pour calculer la somme
//- on est certain de balayer toutes les combinaisons si on teste toutes les valeurs de la matrice de 1 à 2^n.

//Ex : tableau de 3 éléments
//Il faut tester une matrice prenant les valeurs de 000 à 111, c’est à dire de 0 (1-1) à 7 (2^3-1).
//La variable de boucle doit prendre les valeurs de 1 à 2^n et la matrice est la variable de boucle diminuée de 1.

//
//________________________________________________________________________________
//AMELIORATIONS A APPORTER
//On élimine au préalable les montants supérieurs à la somme cherchée.
//Protéger les limites
//
//________________________________________________________________________________
//CREATION par Super_Utilisateur
//•1• 27/09/2003
//•3• 31/07/2004
//•4• 06/01/2007 16:36:00
//•5• 08/11/2007 23:04:21 optimisation matrice
//•6• 22/08/2009 16:55:07
//•7• 06/08/2015 17:51:08 C_TEXTE(
//
//________________________________________________________________________________
//COMPOSANT
//
//________________________________________________________________________________
//PARAMETRES
C_REAL($1) //nombre à chercher
C_POINTER($2) //tableau de valeurs
C_POINTER($3) //tableau de booléens
//
//________________________________________________________________________________
//TYPAGE DES VARIABLES LOCALES
C_TEXT($va31_Nom_Objet)
C_BOOLEAN($OK_b)
C_LONGINT($i)
C_LONGINT($j)
C_LONGINT($vl_Limite_Boucle)
C_LONGINT($vl_Nb_El)
C_LONGINT($vl_Nombre_Essais)
C_REAL($vr_Montant_à_rapprocher)
C_REAL($vr_Montant_Calculé)
C_REAL($vr_Montant_total)
C_TEXT($vt_Matrice)
C_TEXT($vt_Message)
ARRAY REAL($tr_Montant;0)
C_POINTER($p_Tableau)
ARRAY LONGINT($tl_ID;0)
//
//TYPAGE DES VARIABLES à reclasser dans les COMPILER_XXX </TVG> //TYPAGE DES VARIABLES INTERPROCESS à reclasser <TVI>
//________________________________________________________________________________
//INITIALISATION DES VARIABLES LOCALES
$OK_b:=True
//
//________________________________________________________________________________
//INITIALISATION DES VARIABLES GLOBALES
//
//________________________________________________________________________________
//CONTROLE DES PARAMETRES
//contrôler que le premier paramètre est un entier ou réel
If (Count parameters<3)
$OK_b:=False
$vt_Message:=“Il n’y a pas assez de paramètres”
End if
//Le premier paramètre est un réel ou un entier (long)
If (Type($1)#Is real) & (Type($1)#Is integer) & (Type($1)#Is longint)
$OK_b:=False
$vt_Message:=“Le premier paramètre n’est pas un nombre”
End if
//Le deuxième paramètre est un tableau réel ou d’entiers (longs)
If (Type($2)#Is pointer)
$OK_b:=False
$vt_Message:=$vt_Message+<>CR+“Le deuxième paramètre n’est pas un pointeur”
Else
If (Type($2->)#Real array) & (Type($2->)#Integer array) & (Type($2->)#LongInt array)
$OK_b:=False
$vt_Message:=$vt_Message+<>CR+“Le deuxième paramètre n’est pas un pointeur sur un tableau de nombres”
Else
COPY ARRAY($2->;$tr_Montant)
End if
End if
//Le troisième paramètre est un tableau booléen
$p_Tableau:=$3
If (Type($3)#Is pointer)
$OK_b:=False
$vt_Message:=$vt_Message+<>CR+“Le troisième paramètre n’est pas un pointeur”
Else
If (Type($p_Tableau->)#LongInt array)
$OK_b:=False
$vt_Message:=$vt_Message+<>CR+“Le troisième paramètre n’est pas un pointeur sur un tableau entier long”
Else
COPY ARRAY($3->;$tl_ID)
End if
End if
//
//________________________________________________________________________________
//EXECUTION
If ($OK_b)
$vr_Montant_à_rapprocher:=$1

  //Elimination des montants supérieurs au montant à chercher
For ($i;Size of array($tr_Montant);1;-1)
	If ($tr_Montant{$i}>$vr_Montant_à_rapprocher)
		DELETE FROM ARRAY($tr_Montant;$i)
		DELETE FROM ARRAY($tl_ID;$i)
	End if 
End for 
$vl_Nb_El:=Size of array($tr_Montant)

  //Calcul du montant total, après suppression
For ($i;1;Size of array($tr_Montant))
	$vr_Montant_total:=$vr_Montant_total+$tr_Montant{$i}
End for 

  //Le point de départ est le nombre à chercher augmenté de la déviation maximale ???
$vl_Limite_Boucle:=2^($vl_Nb_El)

  //Si le montant total est inférieur au double du montant à chercher, on décrit la boucle à partir de la limite
If ($vr_Montant_à_rapprocher>($vr_Montant_total/2))
	For ($i;1;$vl_Limite_Boucle)
		$vt_Matrice:=CHR_ft_Convertir_Long_en_Binair ($i-1;$vl_Nb_El;True)
		$vr_Montant_Calculé:=0
		If ($i=85)
			
		End if 
		For ($j;1;$vl_Nb_El)
			If ($vt_Matrice[$j]="1")
				$vr_Montant_Calculé:=$vr_Montant_Calculé+$tr_Montant{$j}
			End if 
			Case of 
				: ($vr_Montant_Calculé=$vr_Montant_à_rapprocher)
					$vl_Nombre_Essais:=$i
					$i:=MAXLONG-1
					$j:=MAXLONG-1
					  //: ($vr_Montant_Calculé<$vr_Montant_à_rapprocher) & ($j=Taille tableau($tr_Montant))
					  //$j:=MAXLONG -1
			End case 
		End for 
	End for 
Else 
	For ($i;$vl_Limite_Boucle;1;-1)
		$vt_Matrice:=CHR_ft_Convertir_Long_en_Binair ($i-1;$vl_Nb_El;True)
		$vr_Montant_Calculé:=0
		For ($j;1;Size of array($tr_Montant))
			If ($vt_Matrice[$j]="1")
				$vr_Montant_Calculé:=$vr_Montant_Calculé+$tr_Montant{$j}
			End if 
		End for 
		Case of 
			: ($vr_Montant_Calculé=$vr_Montant_à_rapprocher)
				$vl_Nombre_Essais:=$i
				$i:=0
		End case 
	End for 
End if 

If ($vl_Nombre_Essais>=1)
	  //Sélectionner les enregistrements trouvés par le tableau de booléens associé aux montants
	For ($i;1;$vl_Nb_El)
		If ($vt_Matrice[$i]="0")
			$tl_ID{$i}:=0
		End if 
	End for 
Else 
	  //On n'a pas trouvé, on remet les drapeaux de sélection à Faux
	For ($i;1;$vl_Nb_El)
		$tl_ID{$i}:=0
	End for 
End if 

COPY ARRAY($tl_ID;$3->)

End if
//

</code 4D>

Olivier,

Je t’ai donné une réponse directe à ton problème, tu l’as testée ?

Bonjour Olivier,

il ya deja eut bcp de solutions proposées. Comme Manuel le dis, le risque est de la double facture du meme client, sinon, c’est faisable automatiquement.

J’ai fait un algorithme pour le moteur de recherche qui peut etre transposable :

Le principe est le suivant ;
creer 2 tableau 2D de N factures (ensemble de mots dans mon cas)
A) le tableau 1 c’est le nom de tes combinaisons (1, 12, 123, 125…12567) ca marche de 0 a 9… j’ai pas été plus loin…
B) le tableau 2 contient les valeurs
Les 2 sont synchronisés
faire les calculs par combinaisons ligne1 colone1+colone2 (c’est un ensemble), ensuite le resultats (col1+col2) avec colone3, ensuite 123 avec la colonne 4 etc… Tu n’a pas besoin de faire col4 + col1+col2 car tu as deja fait col1+2 … EN réalité, le nombre de combinaisons possible est bien plus faible quel’on pense.

Et dans le cas de nombre, tu peux éliminer toutes les factures dépassant le montant rechercher, et stopper dans ta boucle dès que le montant est dépassé; ex 123 = 400€ et la 4 est de 600€. La valeur de 1234 étant égale a 1000€, , donc au dessus des 800€, c’est inutile de tester 1234+5 …6…7…

J’espere que c’est compréhensible. Moi j’additionne des scores (valeurs) de mots(des ensembles en réalité), et c’est urltra rapide (moins de 1 milliseconde pour tous les calculs - env 200 combinaisons) , et plutot efficace en attendant de l’IA …

Tu poses une question qui relève plutôt du process métier que de l’algorithme.

Si tu demandes à l’algorithme de trouver 64 parmi 14, 5 , 27, 45, 12 , 14, il fera son boulot en te proposant 14, 5, 45.
Il y a deux montants 14 : il faut être clair sur la raison du rapprochement.
Je lui demande par exemple pour un rapprochement comptable de me présenter les pièces parmi les plus anciennes et d’afficher les pièces choisies à l’écran afin de corriger si nécessaire.

Mais l’algo fonctionne et répond à la question demandée…
Ton principe est en gros le même mais tu mobilises de la mémoire inutilement ; et tu ne décris pas l’algo…

On aimerait bien avoir le code pour notre culture…

: Herve LE MARCHAND

On aimerait bien avoir le code pour notre culture.

Il y est : https://forums.4d.com/Post/FR/29218361/1/29277556#29245802 !
Bon, il manque un utilitaire ; le voici https://forums.4d.com/4DBB_Main/x_User/4018/files/29288076.zip

Bonjour Bernard,

Désolé pour le retard, j’étais occupé avec d’autres chantiers…

Je viens de tester: wow! c’est magique, ça fonctionne parfaitement, merci beaucoup!

J’aime ce forum!

Olivier