Depuis le 1er janvier 2020, les frais de carburant doivent être ventilés par véhicule, en vue du calcul de la DNA tenant compte de différents paramètres liés aux véhicules. Nous fournissons ici un code qui s'applique aux factures du fournisseur Total. Il est basé sur un fichier Excel obtenu depuis le portail de Total, via "Mon suivi quotidien / Transactions journalières". L'écran de sélection doit être complété comme suit, en adaptant les dates en fonction de la période de facturation.
Après avoir cliqué sur le bouton "Rechercher", il faut cliquer sur le bouton pour produire le fichier Excel adéquat.
Le code fourni ci-dessous doit être placé dans un bouton de l'écran de saisie des achats en comptabilité. Il pose l'hypothèse que le numéro de carte est stocké dans la clé 3 des comptes analytiques. Son principe est le suivant :
- l'utilisateur commence une écriture d'achat et saisit le fournisseur (Total)
- il vérifie le régime en fonction de la facture qu'il encode
- Est-ce une facture nationale ? -> Normal
- Est-ce une facture étrangère ? -> Exonéré
- il saisit le montant de la facture. Dès ce moment, si le compte général par défaut est bien mentionné dans la fiche du fournisseur et si, sur ce compte général, un code TVA par défaut est bien présent, alors l'imputation en comptabilité générale s'effectue de façon automatique.
- L'utilisateur clique sur le bouton en question et cela ajoute les imputations de comptabilité analytique. Si le fichier contient des consommations dans différents pays, une boîte de dialogue permet la sélection du pays correspondant à la facture en cours d'encodage.
Le code du bouton est le suivant :
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Linq;
using MercatorApi;
using MercatorController;
using System.Windows.Forms;
using MercatorExtensions;
using MercatorDatabase;
// <CompileWithRoslyn />
namespace MercatorUi.MovableControls.ButtonsCodes
{
public static class Script
{
private const int plan = 1;
public static void Exec(MercatorUi.MovableControls.MovableButton clickedButton)
{
if (!(clickedButton.Form is MercatorUi.Forms.Booking.BookingForm bookingForm))
return;
if ((bookingForm.BookingEngine.LIGNES_C.Rows.Count == 0) || string.IsNullOrWhiteSpace(bookingForm.BookingEngine.LignesCRecords[0].COMPTE))
{
MercatorUi.Dialogs.Stop("Il faut d'abord saisir le fournisseur et la première ligne d'imputation doit être complétée !");
return;
}
string fichier = Dialogs.GetFile("Xls file (*.xls)|*.xls|All files (*.*)|*.*", _Divers.Iif_langue(Globals.Langue, "Which XLS file ?", "Welk XLS bestand ?", "Quel fichier XLS ?"), @"c:\");
if (fichier == "")
return;
var r = MercatorImporter.Importer.Import(MercatorImporter.ImporterFormats.Excel2003, fichier);
if (r == null)
return;
if (r.Result.Rows.Count == 0)
{
MercatorUi.Dialogs.Stop(Api.Iif_langue(MercatorUi.Globals.Langue, IifLangueEnum.NoRecordFound));
return;
}
string[] countries = r.Result.Rows.Cast<DataRow>().GroupBy(p => (string)p["code partenaire"]).Select(p => (string)p.First()["code partenaire"]).ToArray();
string country;
if (countries.Length == 1)
{
country = countries[0];
}
else
{
var l = new List<MercatorUi._BaseClasses.MercatorComboItem>();
foreach (string s in countries)
l.Add(new MercatorUi._BaseClasses.MercatorComboItem(s, s));
var askComboRet = MercatorUi.Dialogs.AskCombo("Pour quel pays ?", l);
if (askComboRet == null)
return;
country = askComboRet.Id;
}
string montant_col = bookingForm.BookingEngine.PiedsCRecord.REGIME == RegimesEnum.Normal ? "montant ht" : "montant ttc";
var data = r.Result.Rows.Cast<DataRow>().Where(c => c["code partenaire"].Equals(country)).GroupBy(p => (string)p["carte"]).Select(p => new KeyValuePair<string, decimal>((string)p.First()["carte"], p.Sum(dr => Convert.ToDecimal(dr[montant_col]))));
var tot_xls = Convert.ToDouble(data.Sum(kvp => kvp.Value));
if (tot_xls.CompareTo(bookingForm.BookingEngine.LignesCRecords[0].TOT_DV, 2) != 0)
{
string msg = string.Format("Différence entre le total du fichier et le montant dans l'imputation :\r\n"
+ " Imputation = {0:### ##0.00} EUR\r\n"
+ " Fichier = {1:### ##0.00} EUR\r\n"
+ "Continuer ?", bookingForm.BookingEngine.LignesCRecords[0].TOT_DV, tot_xls);
if (!MercatorUi.Dialogs.AnswerYesNo(msg))
return;
}
bookingForm.BookingEngine.LIGNES_C_ANA.Rows.Clear();
MercatorUi.Sig.Sig sigAna = MercatorUi.Sig._SigsStatic.SigByModule(Sig._SigEnum.ANA);
string reqSql = string.Format("select {0} from ANA where (a_plan={1}) and (a_cle3 in ({2}))", sigAna.FieldsListForSelectRtrimOptimBytes, plan, string.Join(",", data.Select(kvp => "'" + kvp.Key + "'")));
DataSet ds = Api.Zselect(MercatorUi.Globals.RepData, reqSql);
if (ds == null)
return;
foreach(var kvp in data)
{
var anaRecord = ds.Tables[0].RowsEnumerable().FirstOrDefault(dr => dr["a_cle3"].Equals(kvp.Key));
if (anaRecord == null)
{
MercatorUi.Dialogs.Stop($"La carte {kvp.Key} n'est pas associée à un compte analytique !");
return;
}
int n = bookingForm.BookingEngine.AppendLineAna(plan, bookingForm.BookingEngine.LignesCRecords[0].DL_ID);
if (!bookingForm.BookingEngine.InsertAnaFull(anaRecord, bookingForm.BookingEngine.LIGNES_C_ANA.Rows[n], plan))
{
MercatorUi.Dialogs.Stop($"Impossible d'insérer le compte analytique \"{anaRecord["a_id"].ToString().TrimEnd()}\" lié à la carte {kvp.Key} !");
return;
}
bookingForm.BookingEngine.LIGNES_C_ANA.Rows[n]["tot_dv"] = kvp.Value;
}
bookingForm.BookingEngine.UpdateAmounts();
MercatorUi.Dialogs.Stop("L'analytique a été appliquée !");
}
}
}
Afin d'assurer l'unicité des numéros de cartes de caburant dans la table des comptes analytiques, nous suggérons d'installer cet index :
CREATE UNIQUE NONCLUSTERED INDEX A_CLE3_UNIQUE_OR_EMPTY_IN_ANA ON dbo.ANA(A_CLE3) where a_cle3<>''