L'objet de cette programmation est de calculer, dans l'interface de Mercator, la somme des S_PRIX_HT * Q pour les articles liés présents dans la grille de liaisons de l'article en cours. Ce calcul sera fait de façon interactive : cela signifie que toute modification apportée dans la grille ArtLiens sera automatiquement répercutée dans le champ contenant ce total calculé. Dans notre exemple, ce total sera sauvegardé dans le champ S_PRIX_HT de l'article (parent) en cours. Le code pourra être facilement adapté pour déroger à cela.
Une même problématique pourrait être résolue par un traitement SQL, soit par trigger, soit à la validation de la fiche, mais dans ce cas, il n'y aurait aucune interactivité puisque le calcul de ce total ne serait effectué que lors de la validation. Cette programmation a été conçue pour que, lors de l'arrivée dans une fiche, le total soit recalculé. Il est possible que si le prix d'un article a changé par exemple, ce total doivent être modifié. Il est donc normal qu'à la sortie de cette fiche, même si l'utilisateur n'y a rien modifié, Mercator propose de sauvegarder les modifications. Par contre, si le prix d'un article enfant a été modifié et que l'utilisateur ne repasse pas par la fiche de l'article parent, alors ce total ne sera pas recalculé. (Ceci pourrait être effectué par un trigger SQL, mais cela sort du cadre de la présente information)
La programmation illustrée ici est réalisée sur base d'un customizer SigStock qui implémente les interfaces suivantes :
et elle exploite l'évènement TotalUpdated de ArtLiens qui permet de lancer un code quand Mercator recalcule le total affiché sous la grille des articles liés. Par ailleurs, comme notre programmation n'effectue le total que pour les lignes pour lesquelles la case "V" est cochée, nous exploitons l'évènement CheckBoxValueChanged de cette même grille, pour détecter les modifications dans cette colonne.
Dans Mercator, par défaut, le contenu d'une grille n'est calculé que si cette grille est visible. (Ceci pour des raisons de performance afin d'éviter que, par exemple, lors du passage de fiche en fiche, Mercator ne passe un temps important à rafraîchir des grilles invisibles.) Dans notre cas, par contre, il est essentiel que les données de la grille soient toujours présentes, que la grille soit visible ou non. Ceci est est assuré par la méthode FillWithData de la grille, appelé dans l'évènement AfterRead.
Le code de ce customizer s'établit comme suit :
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Windows.Forms;
using MercatorApi;
using MercatorUi;
namespace SigStock
{
public class Customizer : MercatorUi.ICustomizers.IFormLoadCustomizer, MercatorUi.ICustomizers.IFormClosedCustomizer
{
public void FormLoadCustomize(Form form)
{
MercatorUi.Forms.Sig.SigForm sigForm = (MercatorUi.Forms.Sig.SigForm)form;
List<Control> l = sigForm.FindMovableControlsByType(typeof(MercatorUi.Forms.Sig.SigGrids.ArtLiens));
if (l.Count == 0)
return;
MercatorUi.Forms.Sig.SigGrids.ArtLiens artLiens = (MercatorUi.Forms.Sig.SigGrids.ArtLiens)l[0];
artLiens.AfterRead += new MercatorUi.MovableControls.MovableGrid.AfterReadHandler(artLiens_AfterRead);
artLiens.TotalUpdated += new EventHandler(artLiens_TotalUpdated);
artLiens.CheckBoxValueChanged += new MercatorUi.Forms.Sig.SigGrids.ArtLiens.CheckBoxValueChangedEventHandler(artLiens_CheckBoxValueChanged);
}
public void FormClosedCustomize(Form form)
{
MercatorUi.Forms.Sig.SigForm sigForm = (MercatorUi.Forms.Sig.SigForm)form;
List<Control> l = sigForm.FindMovableControlsByType(typeof(MercatorUi.Forms.Sig.SigGrids.ArtLiens));
if (l.Count == 0)
return;
MercatorUi.Forms.Sig.SigGrids.ArtLiens artLiens = (MercatorUi.Forms.Sig.SigGrids.ArtLiens)l[0];
artLiens.AfterRead -= new MercatorUi.MovableControls.MovableGrid.AfterReadHandler(artLiens_AfterRead);
artLiens.TotalUpdated -= new EventHandler(artLiens_TotalUpdated);
artLiens.CheckBoxValueChanged -= new MercatorUi.Forms.Sig.SigGrids.ArtLiens.CheckBoxValueChangedEventHandler(artLiens_CheckBoxValueChanged);
}
void artLiens_AfterRead(object sender, EventArgs e)
{
MercatorUi.Forms.Sig.SigGrids.ArtLiens artLiens = (MercatorUi.Forms.Sig.SigGrids.ArtLiens)sender;
MercatorUi.Forms.Sig.SigForm sigForm = (MercatorUi.Forms.Sig.SigForm)artLiens.Form;
string currentId = sigForm.DataSourceRow["S_ID"].ToString();
if (artLiens.LastIdFilled != currentId)
artLiens.FillWithData();
}
void artLiens_TotalUpdated(object sender, EventArgs e)
{
MercatorUi.Forms.Sig.SigGrids.ArtLiens artLiens = (MercatorUi.Forms.Sig.SigGrids.ArtLiens)sender;
MercatorUi.Forms.Sig.SigForm sigForm = (MercatorUi.Forms.Sig.SigForm)artLiens.Form;
if (sigForm.IsFiltring || (artLiens.Grid == null) || (artLiens.Grid.DataSource == null) || (artLiens.Grid.Rows.Count == 0))
return;
StringBuilder sbReqSql = new StringBuilder(); // on va construire une requête SQL unique pour l'ensemble des articles de la grille ArtLiens
foreach (DataGridViewRow dgr in artLiens.Grid.Rows)
{
string id_lien = dgr.Cells["id_lien"].Value.ToString();
if ((id_lien != "") && Convert.ToBoolean(dgr.Cells["ven"].Value))
{
if (sbReqSql.Length == 0)
sbReqSql.AppendFormat("(s_id='{0}')", Api.UnquoteSql(id_lien));
else
sbReqSql.AppendFormat(" or (s_id='{0}')", Api.UnquoteSql(id_lien));
}
}
if (sbReqSql.Length == 0) // la grille ne contient aucun article pour lequel on a coché "V"
return;
DataSet ds = Api.Zselect(Globals.RepData, "select s_id,s_prix_ht from stock where " + sbReqSql.ToString());
if (ds == null)
return;
double d = 0;
foreach (DataGridViewRow dgr in artLiens.Grid.Rows)
{
string id_lien = dgr.Cells["id_lien"].Value.ToString();
if ((id_lien != "") && Convert.ToBoolean(dgr.Cells["ven"].Value))
{
DataRow[] rowsStock = ds.Tables[0].Select(string.Format("s_id='{0}'", Api.UnquoteSql(dgr.Cells["id_lien"].Value.ToString())));
if (rowsStock.Length > 0)
d += Convert.ToDouble(dgr.Cells["q"].Value) * Convert.ToDouble(rowsStock[0]["s_prix_ht"]);
}
}
Api.SmartReplace(sigForm.DataSourceRow, "S_PRIX_HT", Math.Round(d, MercatorUi.Globals.DEC_DEV_B)); // SmartReplace ne fait réellement le remplacement qui si la valeur est différente
}
void artLiens_CheckBoxValueChanged(object sender, MercatorUi.Forms.Sig.SigGrids.ArtLiens.CheckBoxValueChangedEventArgs e)
{
if (e.ColumnName == "ven") // on a coché / déc
artLiens_TotalUpdated(sender, null);
}
}
}