In het artikelinformatiebestand een som berekenen op basis van de tabel van de verbonden artikels

0000002039     -      29-03-2019

Deze programmering is bedoeld om in de Mercator-interface de som te berekenen van S_PRIX_HT * Q voor de verbonden artikels die voorkomen in het verbindingsrooster van het actieve artikel. Deze berekening zal interactief verlopen; dit betekent dat iedere wijziging in het rooster ArtLiens automatisch zal worden overgenomen in het veld met dit berekende totaal. In ons voorbeeld wordt het totaal opgeslagen in het veld S_PRIX_HT van het actieve (moeder)artikel. De code zal makkelijk kunnen worden gewijzigd om hiervan af te wijken.

Deze problematiek zou kunnen worden opgelost via een SQL-verwerking, hetzij via trigger, hetzij bij validatie van de fiche, maar in dat geval is er geen sprake van interactiviteit, want de berekening van dit totaal zou pas bij de validatie worden uitgevoerd. Deze programmering werd bedacht om het totaal te laten herberekenen bij iedere nieuwe input in een fiche. Het is mogelijk dat het totaal moet worden gewijzigd als bijvoorbeeld de prijs van een artikel is gewijzigd. Het is dan ook normaal dat Mercator bij het verlaten van deze fiche voorstelt om de wijzigingen op te slaan, ook al heeft de gebruiker niets gewijzigd. Is daarentegen de prijs van een onderliggend artikel gewijzigd en gaat de gebruiker niet via de fiche van het moederartikel, dan zal dit totaal niet worden herberekend (dit zou uitgevoerd kunnen worden via een SQL-trigger, maar dat behoort niet tot het kader van deze informatie).

De hier geïllustreerde programmering wordt gerealiseerd op basis van een SigStock-customizer die de volgende interfaces implementeert:

en maakt gebruik van het event TotalUpdated van ArtLiens, waarmee een code gelanceerd kan worden wanneer Mercator het totaal onder het rooster van de verbonden artikels herberekent. Aangezien onze programmering enkel het totaal berekent voor de lijnen waarvoor het vakje "V" is aangevinkt, maken we bovendien ook gebruik van het event CheckBoxValueChanged van datzelfde rooster om de wijzigingen in deze kolom te detecteren.

In Mercator wordt de inhoud van een rooster standaard pas berekend als dat rooster zichtbaar is (dit om prestatieredenen, om te vermijden dat Mercator, bijvoorbeeld bij het overschakelen van de ene naar de andere fiche, te veel tijd zou spenderen aan het vernieuwen van onzichtbare roosters). In ons geval is het echter van essentieel belang dat de gegevens van het rooster altijd aanwezig zijn, ongeacht of het rooster al dan niet zichtbaar is. Dat wordt verzekerd via de methode FillWithData van het rooster, die wordt opgeroepen in het event AfterRead.

De code van deze customizer ziet er als volgt uit:

Zoom
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(); // We gaan een unieke SQL-opdracht creëren voor alle artikels van het rooster 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) // Het rooster bevat geen enkel artikel waarvoor het vakje "V" is aangevinkt.
                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 voert de vervanging pas effectief uit als de waarde verschilt.
        }

        void artLiens_CheckBoxValueChanged(object sender, MercatorUi.Forms.Sig.SigGrids.ArtLiens.CheckBoxValueChangedEventArgs e)
        {
            if (e.ColumnName == "ven") // Aangevinkt / Afgevinkt
                artLiens_TotalUpdated(sender, null);
        }

    }
}