CANIAS: Dinamik İskonto Yapısı — Uygulama ve Deneyimler
Merhaba, CANIAS’ta dinamik iskonto yapısını oldukça kullanışlı buluyorum. Aşağıda bir müşteride kurduğum çözümü adım adım anlattım — hem mimari hem de pratik kullanım açısından. Blogda paylaşmak için sadeleştirdim; isteyenler kendi ihtiyaçlarına göre genişletebilir.
Temel fikir
Müşterileri ve malzemeleri “iskonto türüne” göre sınıflandırıp, sistemin dinamik iskonto tablolarına (IASDYNAMICP ve IASDYNAMICPCR) otomatik kayıt üretecek şekilde bir tasarım yaptım. Böylece: hangi müşteri türü hangi malzeme türünde hangi iskonto tipini alacak — bu kurala göre her gece veya manuel tetikleme ile sisteme gerekli kayıtlar yazılıyor.
Veritabanı ve tablolar
Aşağıdaki temel değişiklikleri ve yeni tabloları tanımladım:
- IASDYNAMICP tablosuna yeni alan:
MALZEMEISKONTOTIPI - MALZEMEMUSTERIISKONTO tablosu — müşteri tipi, malzeme tipi ve uygulanacak iskonto tipi kaydı.
- MALZEMEISKONTOSCRIPT tablosu — hangi kurallara göre malzemelere iskonto tipi atanacağı burada tanımlanıyor.
MALZEMEMUSTERIISKONTO
-- Tanımların saklandığı tablo
[CLIENT] [varchar](2) NOT NULL,
[COMPANY] [varchar](3) NOT NULL,
[MUSTERIISKONTOTIPI] [varchar](2) NOT NULL,
[MALZEMEISKONTOTIPI] [varchar](2) NOT NULL,
[ISKONTOKODU] [varchar](3) NOT NULL,
[CREATEDBY] [nvarchar](30) NULL,
[CREATEDAT] [datetime] NULL,
[CHANGEDBY] [nvarchar](30) NULL,
[CHANGEDAT] [datetime] NULL
MALZEMEISKONTOSCRIPT
-- Kuralların saklandığı tablo
[CLIENT] [varchar](2) NOT NULL,
[COMPANY] [varchar](3) NOT NULL,
[ALAN1] [varchar](80) NULL,
[OPERATOR1] [varchar](10) NULL,
[DEGER1] [nvarchar](80) NULL,
[ALAN2] [varchar](80) NULL,
[OPERATOR2] [varchar](10) NULL,
[DEGER2] [nvarchar](80) NULL,
[MALZEMEISKONTOTIPI] [varchar](2) NOT NULL,
[CREATEDBY] [nvarchar](30) NULL,
[CREATEDAT] [datetime] NULL,
[CHANGEDBY] [nvarchar](30) NULL,
[CHANGEDAT] [datetime] NULL
UI — Yönetim ekranı
Yönetim için dört sekmeli bir ekran geliştirdim. Ekran şu işleri yapıyor:
- Sekme 1 — Müşteri İskonto Tip Ataması: Müşterilere/müşteri tiplerine iskonto tipleri atanıyor. Buradan manuel tetikleme de yapılabilir.
- Sekme 2 — Malzeme Kural Tanımları: Malzemelere hangi kurallarla iskonto tipi atanacağı tanımlanıyor (MALZEMEISKONTOSCRIPT). Buradan manuel güncelleme de başlatılabilir.
- Sekme 3 — İskonto Tanımlarını Görüntüleme: Oluşan eşleşmeler ve atanan iskontolar listeleniyor.
- Sekme 4 — Malzemeleri Listeleme: Sistemdeki malzemeler, tanımlanan iskonto kriterlerine göre filtrelenip listelenebiliyor.
Stored Procedures (SP) ve otomasyon
İki ana SP yazdım. Bunlar günlük olarak çalışıyor ancak istenirse yönetim ekranından manuel de tetiklenebiliyor:
1) PRC_ERP_MALZEMEISKONTOTIPIAYARLA.sql
Tanımı: MALZEMEISKONTOSCRIPT tablosundaki kurallara göre malzemelere iskonto tipi atayan SP.
Bu prosedür kuralları okur, malzeme setlerini çıkarır ve MALZEMEMUSTERIISKONTO tablosunu günceller.
create PROCEDURE [dbo].[PRC_ERP_MALZEMEISKONTOTIPIAYARLA]
AS
BEGIN
DECLARE @sql NVARCHAR(MAX),
@whereClause NVARCHAR(MAX);
DECLARE script_cursor CURSOR FOR
SELECT COMPANY
, ALAN1
, OPERATOR1
, DEGER1
, ALAN2
, OPERATOR2
, DEGER2
, MALZEMEISKONTOTIPI
FROM MALZEMEISKONTOSCRIPT
WHERE CLIENT = '00'
ORDER BY COMPANY, CREATEDAT;
DECLARE @company VARCHAR(50),
@alan1 VARCHAR(80),
@operator1 VARCHAR(10),
@deger1 nVARCHAR(80),
@alan2 VARCHAR(80),
@operator2 VARCHAR(10),
@deger2 nVARCHAR(80),
@iskontotipi VARCHAR(2);
OPEN script_cursor
FETCH NEXT FROM script_cursor INTO @company, @alan1, @operator1, @deger1, @alan2, @operator2, @deger2, @iskontotipi
WHILE @@FETCH_STATUS = 0
BEGIN
SET @whereClause = @alan1 + ' ' + @operator1 + ' N''' + @deger1 + ''''
IF ISNULL(@deger2, '') != ''
SET @whereClause = @whereClause + ' AND ' + @alan2 + ' ' + @operator2 + ' N''' + @deger2 + ''''
SET @sql = 'UPDATE IASMATMOP SET CHANGEDBY = ''IT-MLZ-DISC-TYPE'', CHANGEDAT = GETDATE(),
MALZEMEISKONTOKODU = ''' + @iskontotipi + '''
WHERE CLIENT = ''00'' AND COMPANY = ''' + @company + '''
AND MALZEMEISKONTOKODU <> ''' + @iskontotipi + '''
AND ' + @whereClause
-- PRINT @sql;
EXEC sp_executesql @sql
FETCH NEXT FROM script_cursor INTO @company, @alan1, @operator1, @deger1, @alan2, @operator2, @deger2, @iskontotipi
END;
CLOSE script_cursor;
DEALLOCATE script_cursor;
END;
2) PRC_ERP_DYNAMICPISKONTOAYARLA.sql
Tanımı: Sistemde iskontosu tanımlı müşteri ve malzemelere göre IASDYNAMICP ve
IASDYNAMICPCR tablolarına CANIAS’a uygun dinamik iskonto kayıtlarını oluşturur.
Mevcut iskontolar kontrol edilir; varsa ve değişmişse silinip yeniden oluşturur. Hiç yoksa sıfırdan oluşturur.
create PROCEDURE [dbo].[PRC_ERP_DYNAMICPISKONTOAYARLA]
@FirmaKodu VARCHAR(3),
@MusteriNo VARCHAR(30)
AS BEGIN
DECLARE @MusteriIskontoTanimAdedi INT,
@MusteriIskontoMevcutAdet INT,
@musteri_fetch_status INT,
@iskonto_fetch_status INT,
@MalzemeIskontoTipi VARCHAR(2),
@MusteriIskontoTipi VARCHAR(2),
@IskontoKodu VARCHAR(3),
@sonDynamicRelKey VARCHAR(15),
@yeniDynamicRelKey VARCHAR(15),
@yeniRelDesc VARCHAR(80),
@yeniCriteriaText NVARCHAR(MAX);
DECLARE musteri_cursor CURSOR FOR
SELECT DISTINCT c.CUSTOMER
, c.MUSTERIISKONTOTIPI
FROM IASCUSTOMER c WITH (NOLOCK)
INNER JOIN MALZEMEMUSTERIISKONTO b WITH (NOLOCK) ON b.CLIENT = '00'
AND b.COMPANY = @FirmaKodu
AND b.MUSTERIISKONTOTIPI = c.MUSTERIISKONTOTIPI
WHERE c.CLIENT = '00'
AND c.COMPANY = @FirmaKodu
AND c.ISLOCKED = 0
AND c.ISDELETE = 0
AND c.CUSTOMER LIKE @MusteriNo
AND c.ISCUSTORVEND = 3
AND ISNULL(c.MUSTERIISKONTOTIPI, '') <> '';
OPEN musteri_cursor
FETCH NEXT FROM musteri_cursor INTO @MusteriNo, @MusteriIskontoTipi;
SET @musteri_fetch_status = @@FETCH_STATUS;
WHILE @musteri_fetch_status = 0
BEGIN
PRINT 'Musteri: ' + @MusteriNo;
SELECT @MusteriIskontoTanimAdedi = COUNT(*)
FROM IASCUSTOMER c WITH (NOLOCK)
INNER JOIN MUSTERIISKONTOTIPI b WITH (NOLOCK) ON b.CLIENT = '00'
AND b.COMPANY = @FirmaKodu
AND b.MUSTERIISKONTOTIPI = c.MUSTERIISKONTOTIPI
WHERE c.CLIENT = '00'
AND c.COMPANY = @FirmaKodu
AND c.CUSTOMER = @MusteriNo;
SELECT @MusteriIskontoMevcutAdet = COUNT(*)
FROM IASDYNAMICP p WITH (NOLOCK)
INNER JOIN MUSTERIISKONTOTIPI b WITH (NOLOCK) ON b.CLIENT = '00'
AND b.COMPANY = @FirmaKodu
AND b.MALZEMEISKONTOTIPI = p.MALZEMEISKONTOKODU
AND b.ISKONTOKODU = p.DISCKEY1
WHERE p.CLIENT = '00'
AND p.COMPANY = @FirmaKodu
AND p.CUSTOMER = @MusteriNo
AND p.ISDELETE = 0
AND ISNULL(p.ARACGRUBU, '') = ''
AND ISNULL(p.GOBEKKODU, '') = ''
AND ISNULL(p.MALZEMEISKONTOKODU, '') <> '';
IF @MusteriIskontoTanimAdedi = @MusteriIskontoMevcutAdet BEGIN
PRINT N'Her sey esitse bir isleme gerek yok.';
END;
ELSE BEGIN
PRINT N'Herhangi bir esitsizlik soz konusu ise hepsini sil yeniden olustur en temizi...';
-- Once [IASDYNAMICP]
DELETE p
FROM IASDYNAMICP p
WHERE p.CLIENT = 'RR'
AND p.COMPANY = @FirmaKodu
AND p.CUSTOMER = @MusteriNo
AND p.ISDELETE = 0
AND ISNULL(p.MALZEMEISKONTOKODU, '') <> '';
PRINT N' Silinen IASDYNAMICP kayit sayisi: ' + CAST(@@ROWCOUNT AS VARCHAR(10));
UPDATE p SET p.CLIENT = 'RR', p.CHANGEDBY = 'IT-AUTO-DISC', p.CHANGEDAT = GETDATE()
FROM IASDYNAMICP p
WHERE p.CLIENT = '00'
AND p.COMPANY = @FirmaKodu
AND p.CUSTOMER = @MusteriNo
AND p.ISDELETE = 0
AND ISNULL(p.MALZEMEISKONTOKODU, '') <> '';
PRINT N' Guncellenen IASDYNAMICP kayit sayisi: ' + CAST(@@ROWCOUNT AS VARCHAR(10));
-- Sonra [IASDYNAMICPCR]
DELETE pcr
FROM IASDYNAMICP p
INNER JOIN IASDYNAMICPCR pcr ON pcr.CLIENT = 'RR'
AND pcr.COMPANY = @FirmaKodu
AND pcr.DYNAMICRELKEY = p.DYNAMICRELKEY
WHERE p.CLIENT = 'RR'
AND p.COMPANY = @FirmaKodu
AND p.CUSTOMER = @MusteriNo
AND p.ISDELETE = 0
AND ISNULL(p.MALZEMEISKONTOKODU, '') <> '';
PRINT N' Silinen IASDYNAMICPCR kayit sayisi: ' + CAST(@@ROWCOUNT AS VARCHAR(10));
UPDATE pcr SET pcr.CLIENT = 'RR', pcr.CHANGEDBY = 'IT-AUTO-DISC', pcr.CHANGEDAT = GETDATE()
FROM IASDYNAMICP p
INNER JOIN IASDYNAMICPCR pcr ON pcr.CLIENT = '00'
AND pcr.COMPANY = @FirmaKodu
AND pcr.DYNAMICRELKEY = p.DYNAMICRELKEY
WHERE p.CLIENT = 'RR'
AND p.COMPANY = @FirmaKodu
AND p.CUSTOMER = @MusteriNo
AND p.ISDELETE = 0
AND ISNULL(p.MALZEMEISKONTOKODU, '') <> '';
PRINT N' Guncellenen IASDYNAMICPCR kayit sayisi: ' + CAST(@@ROWCOUNT AS VARCHAR(10));
DECLARE iskonto_cursor CURSOR FOR
SELECT b.MALZEMEISKONTOTIPI
, b.ISKONTOKODU
FROM MUSTERIISKONTOTIPI b
WHERE b.CLIENT = '00'
AND b.COMPANY = @FirmaKodu
AND b.MUSTERIISKONTOTIPI = @MusteriIskontoTipi;
OPEN iskonto_cursor
FETCH NEXT FROM iskonto_cursor INTO @MalzemeIskontoTipi, @IskontoKodu;
SET @iskonto_fetch_status = @@FETCH_STATUS;
WHILE @iskonto_fetch_status = 0
BEGIN
PRINT ' -> Iskonto: ' + @MalzemeIskontoTipi + ' - ' + @IskontoKodu;
SET @yeniRelDesc = @MusteriNo + '[' + 'MlzIskTp:' + @MalzemeIskontoTipi + ']';
SET @yeniCriteriaText = ' IASSALHEAD_CUSTOMER == ''' + @MusteriNo + ''' && IASSALITEM_MALZEMEISKONTOKODU == ''' + @MalzemeIskontoTipi + '''';
SELECT TOP 1 @sonDynamicRelKey = DYNAMICRELKEY
FROM IASDYNAMICP
WHERE CLIENT = '00'
AND COMPANY = @FirmaKodu
AND CUSTOMER = @MusteriNo
ORDER BY DYNAMICRELKEY DESC;
IF @sonDynamicRelKey IS NULL
SET @yeniDynamicRelKey = @MusteriNo + '0001'
ELSE
SET @yeniDynamicRelKey = @MusteriNo + RIGHT('0000' + CAST(CAST(RIGHT(@sonDynamicRelKey, 4) AS INT) + 1 AS VARCHAR), 4);
-- Once [IASDYNAMICP]
INSERT INTO [dbo].[IASDYNAMICP]
([CLIENT]
,[COMPANY]
,[VALIDFROM]
,[VALIDUNTIL]
,[CREATEDBY]
,[CHANGEDBY]
,[CREATEDAT]
,[CHANGEDAT]
,[ISDELETE]
,[QUANTITY1]
,[QUANTITY2]
,[QUANTITY3]
,[QUANTITY4]
,[QUANTITY5]
,[QUANTITY6]
,[PRICE1]
,[PRICE2]
,[PRICE3]
,[PRICE4]
,[PRICE5]
,[PRICE6]
,[DISCKEY1]
,[DISCKEY2]
,[DISCKEY3]
,[DISCKEY4]
,[DISCKEY5]
,[ISVATINCLUSIVE]
,[SALPUNIT]
,[RELPRIO]
,[ISBONUS]
,[BONUSSCALE1]
,[BONUSSCALE2]
,[BONUSSCALE3]
,[BONUSSCALE4]
,[BONUSSCALE5]
,[BONUSSCALE6]
,[BONUSQUAN1]
,[BONUSQUAN2]
,[BONUSQUAN3]
,[BONUSQUAN4]
,[BONUSQUAN5]
,[BONUSQUAN6]
,[BONUSRATE1]
,[BONUSRATE2]
,[BONUSRATE3]
,[BONUSRATE4]
,[BONUSRATE5]
,[BONUSRATE6]
,[ISPRICEDISC]
,[TYPERATE]
,[DYNAMICRELKEY]
,[RELDESC]
,[CRITERIATEXT]
,[ISRUNCODE]
,[CODE]
,[CUSTOMER]
,[MATERIAL]
,[MALZEMEISKONTOKODU])
VALUES
('00'
,@FirmaKodu
,'1975-01-01'
,'2030-01-01'
,'IT-AUTO-DISC'
,'IT-AUTO-DISC'
,GETDATE()
,GETDATE()
,0.0
,0.0
,0.0
,0.0
,0.0
,0.0
,0.0
,0.00
,0.00
,0.00
,0.00
,0.00
,0.00
,@IskontoKodu
,''
,''
,''
,''
,0
,1
,2
,0
,0.00
,0.00
,0.00
,0.00
,0.00
,0.00
,0.0
,0.0
,0.0
,0.0
,0.0
,0.0
,0.00
,0.00
,0.00
,0.00
,0.00
,0.00
,0
,0
,@yeniDynamicRelKey
,@yeniRelDesc
,@yeniCriteriaText
,0
,''
,@MusteriNo
,''
,@MalzemeIskontoTipi);
-- Sonra [IASDYNAMICPCR]
INSERT INTO [dbo].[IASDYNAMICPCR]
([CLIENT]
,[COMPANY]
,[DYNAMICRELKEY]
,[LOGIC]
,[PREFIX]
,[FIELDNAME]
,[OPERATOR]
,[VALUE]
,[SUFFIX]
,[ISACTIVE]
,[CRITERIANUM]
,[ISHEAD]
,[FIELDTYPE]
,[ISVARIANT]
,[VARIANTKEY]
,[VOPTIONS]
,[ZOOMTBL]
,[OPERATORVAR]
,[VALIDFROM]
,[VALIDUNTIL]
,[CREATEDBY]
,[CREATEDAT]
,[CHANGEDBY]
,[CHANGEDAT])
VALUES
('00'
,@FirmaKodu
,@yeniDynamicRelKey
,0
,0
,'CUSTOMER'
,0
,@MusteriNo
,0
,1
,10
,1
,'STRING'
,0
,''
,''
,''
,0
,'1975-01-01'
,'2030-01-01'
,'IT-AUTO-DISC'
,GETDATE()
,'IT-AUTO-DISC'
,GETDATE());
INSERT INTO [dbo].[IASDYNAMICPCR]
([CLIENT]
,[COMPANY]
,[DYNAMICRELKEY]
,[LOGIC]
,[PREFIX]
,[FIELDNAME]
,[OPERATOR]
,[VALUE]
,[SUFFIX]
,[ISACTIVE]
,[CRITERIANUM]
,[ISHEAD]
,[FIELDTYPE]
,[ISVARIANT]
,[VARIANTKEY]
,[VOPTIONS]
,[ZOOMTBL]
,[OPERATORVAR]
,[VALIDFROM]
,[VALIDUNTIL]
,[CREATEDBY]
,[CREATEDAT]
,[CHANGEDBY]
,[CHANGEDAT])
VALUES
('00'
,@FirmaKodu
,@yeniDynamicRelKey
,2
,0
,'MALZEMEISKONTOKODU'
,0
,@MalzemeIskontoTipi
,0
,1
,20
,0
,'STRING'
,0
,''
,''
,''
,0
,'1975-01-01'
,'2030-01-01'
,'IT-AUTO-DISC'
,GETDATE()
,'IT-AUTO-DISC'
,GETDATE());
FETCH NEXT FROM iskonto_cursor INTO @MalzemeIskontoTipi, @IskontoKodu;
SET @iskonto_fetch_status = @@FETCH_STATUS;
END
CLOSE iskonto_cursor;
DEALLOCATE iskonto_cursor;
END;
FETCH NEXT FROM musteri_cursor INTO @MusteriNo, @MusteriIskontoTipi;
SET @musteri_fetch_status = @@FETCH_STATUS;
END;
CLOSE musteri_cursor;
DEALLOCATE musteri_cursor;
END;
Çalışma şekli — Zamanlama ve tetikleme
– Günlük otomasyon: Her gece bir job PRC_ERP_MALZEMEISKONTOTIPIAYARLA prosedürünü çalıştırır, malzeme
iskonto tipi atamalarını yapar. Ardından PRC_ERP_DYNAMICPISKONTOAYARLA çalışarak IASDYNAMICP kayıtlarını üretir.
Bu yapı CANIAS’ta dinamik ve kontrol edilebilir ve daha esnek bir iskonto yönetimi sağladı.
Selamlar…





