Arif

WFN Üye
Konular
638
Mesajlar
638
Çözüm
0
Ticaret Puanı
0
Üyelik
23 Gün
Konum
Bilecik
Web Sitesi
Var
Alanı
SEO Uzmanı
1/1
Konu sahibi
Satış faturası kaydedilirken stok miktarını düşürmenin güvenli yolu, fatura başlık ve kalemlerini kaydetmekle stok hareketini aynı veritabanı işlemi içinde yürütmektir. Her fatura kalemindeki miktarı ilgili stok kaydından azaltın; işlem sırasında hata oluşursa fatura ve stok değişikliği birlikte geri alınsın. Böylece fatura kaydedilmiş görünüp stok düşmemesi veya stok düşüp fatura oluşmaması gibi tutarsızlıklar önlenir.

Stok düşümü hangi bilgiye göre yapılır?​


Stok düşümü, faturanın genel toplamından değil, fatura kalemlerinden yapılır. Her kalemde en az şu bilgiler bulunmalıdır:
  • Stok kartının benzersiz kimliği veya stok kodu
  • Satılan miktar
  • Varsa birim bilgisi ve birim dönüşüm katsayısı
  • Faturanın satış faturası olduğunu belirten işlem türü
Örneğin fatura kaleminde 3 adet ürün satılıyorsa stok miktarı 3 azaltılır. Ürün kilogramla satılıyor ve stok kartındaki temel birim gram ise doğrudan 2 g düşmek yerine, kullanılan birim dönüşümü uygulanmalıdır. Bu ayrım yapılmazsa fatura tutarı doğru olsa bile stok miktarı yanlış kalır.

Stok miktarını yalnızca ekrandaki mevcut değer üzerinden hesaplayıp tekrar yazmak yerine, veritabanında miktarı doğrudan azaltan bir güncelleme kullanmak daha güvenlidir. Böylece aynı ürünü aynı anda kaydeden iki işlemde, bir işlemin diğerinin sonucunu ezme riski azalır.

Fatura ve stok hareketi aynı işlemde kaydedilmeli​


Delphi’de kullandığınız veri erişim bileşeni FireDAC, dbExpress veya başka bir katman olabilir; temel yaklaşım değişmez. Önce veritabanı bağlantısı üzerinden transaction başlatılır. Fatura başlığı ve kalemleri eklenir, her kalem için stok miktarı azaltılır, bütün adımlar başarılıysa commit yapılır. Herhangi bir adım hata verirse rollback çağrılır.

Aşağıdaki örnek, FireDAC ve SQL parametreleri kullanan varsayımsal bir yapıdır. Tablo ve alan adlarını kendi ERP veritabanınızdaki isimlerle değiştirmeniz gerekir. Örnekte STOK tablosunda STOK_ID ve MIKTAR, fatura kalemlerinde ise FATURA_ID, STOK_ID ve MIKTAR alanları bulunduğu varsayılmıştır.

Ön koşulları kontrol edin​


Kaydetme işleminden önce fatura kalemlerinin boş olmadığını, miktarların sıfırdan büyük olduğunu ve stok kartlarının geçerli olduğunu kontrol edin. Negatif stok kullanımına izin vermiyorsanız mevcut miktarın satış miktarından büyük veya eşit olması gerekir.

Bu kontrolü yalnızca Delphi tarafında yapmak yeterli değildir. İki kullanıcı aynı ürünü aynı anda satarsa, her iki ekran da eski stok miktarını görebilir. Asıl güvence, stok güncellemesinin koşullu yapılmasıdır:

Kod:
UPDATE STOK
SET MIKTAR = MIKTAR - :MIKTAR
WHERE STOK_ID = :STOK_ID
  AND MIKTAR >= :MIKTAR

Bu sorgu çalıştıktan sonra etkilenen satır sayısı 1 değilse stok güncellenmemiş demektir. Bunun anlamı genellikle stok kartının bulunmaması veya mevcut miktarın satış miktarını karşılamamasıdır. Bu durumda faturayı commit etmeyip transaction'ı geri almanız gerekir.

Transaction ile kaydetme sırası​


Aşağıdaki kod, satış faturası kaydının ana akışını gösterir. FaturaID değerinin veritabanında otomatik üretildiği varsayılmıştır. FireDAC sürücüsüne ve veritabanına göre yeni kimliği alma yöntemi değişebileceği için bu bölümde örnek bir değer üretme yöntemi yerine, elde edilen kimliğin FaturaID değişkenine atanması gösterilmiştir.

Kod:
procedure TFaturaForm.SatisFaturasiniKaydet;
var
  FaturaID: Integer;
  Kalem: TFaturaKalemi;
  EtkilenenSatir: Integer;
begin
  if FaturaKalemleri.Count = 0 then
    raise Exception.Create('Faturada en az bir kalem bulunmalıdır.');

  FDConnection1.StartTransaction;
  try
    FDQuery1.SQL.Text :=
      'INSERT INTO FATURA (TARIH, CARI_ID, TUR) ' +
      'VALUES (:TARIH, :CARI_ID, :TUR)';
    FDQuery1.ParamByName('TARIH').AsDateTime := Now;
    FDQuery1.ParamByName('CARI_ID').AsInteger := CariID;
    FDQuery1.ParamByName('TUR').AsString := 'SATIS';
    FDQuery1.ExecSQL;

    { Kullanılan veritabanına göre yeni FATURA_ID değerini alın. }
    FaturaID := YeniFaturaIDAl;

    for Kalem in FaturaKalemleri do
    begin
      if Kalem.Miktar <= 0 then
        raise Exception.Create('Fatura miktarı sıfırdan büyük olmalıdır.');

      FDQuery1.SQL.Text :=
        'INSERT INTO FATURA_KALEM ' +
        '(FATURA_ID, STOK_ID, MIKTAR, BIRIM_FIYAT) ' +
        'VALUES (:FATURA_ID, :STOK_ID, :MIKTAR, :BIRIM_FIYAT)';
      FDQuery1.ParamByName('FATURA_ID').AsInteger := FaturaID;
      FDQuery1.ParamByName('STOK_ID').AsInteger := Kalem.StokID;
      FDQuery1.ParamByName('MIKTAR').AsFloat := Kalem.Miktar;
      FDQuery1.ParamByName('BIRIM_FIYAT').AsCurrency := Kalem.BirimFiyati;
      FDQuery1.ExecSQL;

      FDQuery1.SQL.Text :=
        'UPDATE STOK ' +
        'SET MIKTAR = MIKTAR - :MIKTAR ' +
        'WHERE STOK_ID = :STOK_ID ' +
        'AND MIKTAR >= :MIKTAR';
      FDQuery1.ParamByName('STOK_ID').AsInteger := Kalem.StokID;
      FDQuery1.ParamByName('MIKTAR').AsFloat := Kalem.Miktar;
      FDQuery1.ExecSQL;

      EtkilenenSatir := FDQuery1.RowsAffected;
      if EtkilenenSatir <> 1 then
        raise Exception.CreateFmt(
          'Stok yetersiz veya stok kartı bulunamadı. Stok ID: %d',
          [Kalem.StokID]);
    end;

    FDConnection1.Commit;
  except
    FDConnection1.Rollback;
    raise;
  end;
end;

Kodda kullanılan YeniFaturaIDAl yordamı, kullandığınız veritabanına göre uygulanmalıdır. Bazı veritabanlarında ekleme sonrası üretilen kimlik geri döndürülür, bazılarında bunun için özel bir sorgu veya sürücü özelliği kullanılır. Bu kimliği tahmin ederek veya son eklenen kaydı yalnızca tarihe göre arayarak almak güvenilir değildir; aynı anda kayıt yapan başka kullanıcılar yanlış faturanın kimliğinin alınmasına yol açabilir.

Ayrıca aynı FDQuery1 bileşenini sırayla kullanmak zorunlu değildir. Fatura ekleme, kalem ekleme ve stok güncelleme için ayrı sorgu bileşenleri kullanabilirsiniz. Önemli olan bütün sorguların aynı bağlantının transaction'ı içinde çalışmasıdır. Farklı bağlantılar kullanılırsa bir sorgu commit edilirken diğerinin geri alınması mümkün olmayabilir.

Stok güncellemesinin sonucunu nasıl yorumlamalısınız?​


Stok düşümü sonrasında yalnızca ekranda görünen yeni miktara bakmak yeterli değildir. Kaydetme işleminin hangi sonuçla tamamlandığını ayırmanız gerekir.
SonuçAnlamıSonraki işlem
Transaction commit edildiFatura, fatura kalemleri ve stok azaltımı birlikte kalıcı hâle geldi.Fatura numarasını ve ilgili stok kartının yeni miktarını gösterin.
Stok güncellemesi 0 satır etkilediStok kartı bulunamadı veya mevcut miktar satılan miktarı karşılamadı.Rollback yapın; stok kodu, mevcut miktar ve satılan miktarı kullanıcıya bildirin.
Exception oluştuİşlemin en az bir adımı başarısız oldu; commit yapılmadıysa değişiklikler geri alınmalıdır.Hata ayrıntısını kaydedin ve faturanın gerçekten oluşup oluşmadığını transaction sonucuna göre belirleyin.
Fatura var, stok değişmemişFatura ve stok işlemleri aynı transaction içinde yürütülmemiş veya stok güncellemesi sonradan başarısız olmuştur.Eksik stok hareketini rastgele elle düzeltmeyin; fatura, kalem ve hareket kayıtlarını birlikte inceleyin.
Commit başarılıysa stok miktarını yeniden sorgulayarak ekrandaki değeri yenileyin. Yenileme, işlemin başarılı olduğunu kanıtlayan asıl unsur değildir; yalnızca veritabanında commit edilmiş son değeri görmenizi sağlar. Asıl kontrol, stok güncelleme sorgusunun beklenen satırı etkilemesi ve transaction'ın commit edilmesidir.

Bir satış faturası iptal ediliyor veya daha önce kaydedilmiş bir fatura düzeltiliyorsa aynı yöntemi ters yönde uygulamak gerekir. İptal edilen satışın stok miktarı artırılır; ancak bu işlem yeni bir satış kaydı gibi değil, açıkça tanımlanmış bir iade veya iptal stok hareketi olarak tutulmalıdır. Faturayı doğrudan silmek, stokta hangi değişikliğin neden yapıldığını izlemeyi zorlaştırır.

Stok hareketi tablosu kullanmak ne zaman daha doğru olur?​


Sadece STOK.MIKTAR alanını azaltmak basit uygulamalarda yeterli olabilir; fakat ERP uygulamalarında stok hareketlerini ayrıca kaydetmek daha sağlıklıdır. Örneğin STOK_HAREKET tablosunda stok kimliği, hareket türü, miktar, belge türü, belge kimliği, tarih ve kullanıcı bilgileri tutulabilir. Satışta miktar negatif, alışta pozitif hareket yazılır.

Bu yapı sayesinde mevcut stok miktarı ile hareket geçmişi birlikte izlenir. Bir stok farkı oluştuğunda hangi faturanın hangi miktarı düşürdüğü görülebilir. Ancak hareket tablosu kullanmanız transaction gereksinimini ortadan kaldırmaz. Fatura kalemi, stok bakiyesi ve stok hareketi aynı transaction içinde kaydedilmelidir.

Örneğin 10 adet stoktan 3 adet satış yapıldığında beklenen sonuç şöyledir:
  • Fatura kaleminde 3 adet satış bulunur.
  • Stok bakiyesi 10'dan 7'ye düşer.
  • Stok hareketinde satış türünde 3 adetlik çıkış kaydı oluşur.
Bu üç sonuçtan yalnızca biri oluşmuşsa işlem tamamlanmış sayılmaz. Fatura kalemi oluşup stok bakiyesi 10 kalmışsa stok güncellemesi eksiktir. Stok 7'ye düşüp hareket kaydı yoksa miktar değişmiş olsa da denetim izi eksiktir. Bu nedenle kontrol ekranı, yalnız güncel miktarı değil, son stok hareketini ve kaynak fatura numarasını da gösterebilir.

Dikkat edilmesi gereken iki uygulama hatası​


İlk hata, stok miktarını önce SELECT ile okuyup daha sonra Delphi içinde azaltarak tekrar yazmaktır. Bu yöntem eşzamanlı satışlarda kayıp güncellemeye neden olabilir. Mümkünse azaltma işlemini SET MIKTAR = MIKTAR - :MIKTAR biçiminde tek SQL güncellemesiyle yapın ve koşullu güncellemenin etkilenen satır sayısını kontrol edin.

İkinci hata, stok yetersizliğini bildirdikten sonra faturayı yine de kaydetmektir. Kullanıcıya uyarı gösterilecekse transaction rollback edilmeli ve fatura kalemleri kalıcı hâle getirilmemelidir. Kullanıcı miktarı düzelttikten sonra işlem baştan ve yeni koşullarla yürütülmelidir.

Bu yapıyı uyguladığınızda satış faturası kaydı; fatura başlığını, kalemleri, stok azaltımını ve varsa stok hareketini tek bir bütün olarak tamamlar. Kaydetme sonunda commit başarılıysa yeni stok miktarı güvenilir biçimde kullanılabilir; stok güncellemesi başarısızsa fatura da kalıcı hâle getirilmeden nedeni açıkça raporlanır.

Sık sorulan sorular​

Stokta eksi miktara izin veriliyorsa koşullu güncelleme kaldırılmalı mı?​

İş kuralınız negatif stoka izin veriyorsa AND MIKTAR >= :MIKTAR koşulunu kaldırabilirsiniz. Yine de güncellemenin etkilenen satır sayısını kontrol etmeniz gerekir; 0 satır etkilenmesi stok kartının bulunamadığını gösterebilir. Negatif stok kullanılıyorsa kullanıcıya bunun satış anında eksi bakiyeye yol açacağını açıkça belirtin.

Aynı üründen faturada iki ayrı kalem varsa ne yapılmalı?​

Kalemleri kaydetmeden önce aynı stok kimliğine sahip satırları birleştirmek veya her satırı ayrı hareket olarak işlemek gerekir. Her satırı ayrı işliyorsanız transaction içinde iki azaltma yapılır ve toplam miktar kadar stok düşer. Ancak bir kalem başarısız olduğunda bütün transaction geri alınmalıdır.

Kullanıcı faturayı değiştirdiğinde stok nasıl düzeltilir?​

Daha önce commit edilmiş faturayı doğrudan yeniden kaydetmek yerine eski kalemin stok etkisini tersine çevirip yeni kalemin etkisini uygulayın. Örneğin eski miktar 3, yeni miktar 5 ise stoktan yalnızca ek 2 adet düşülür; eski miktar 5, yeni miktar 3 ise 2 adet stok geri eklenir. Bu değişiklikler de fatura güncellemesiyle aynı transaction içinde yapılmalıdır.

Fatura kaydetme sırasında hata oldu; stok düşmüş olabilir mi?​

Transaction ve rollback doğru kullanıldıysa hata sonrasında stok azaltımı kalıcı olmamalıdır. Emin olmak için fatura kimliği, stok kimliği ve işlem zamanı ile hem fatura kalemini hem de stok hareketini sorgulayın. Fatura oluşmuş fakat stok hareketi eksikse işlemler aynı transaction içinde değildir veya hata sonrasında kısmi commit yapılmıştır; bu durumda düzeltme, ilgili belge ve hareket kayıtları birlikte incelenerek yapılmalıdır.
 

Sende şimdi bize katılmak ister misin?

Kayıt ol

Bize katılım kolay ve ücretsizdir!

Foruma git ?

Bu konuyu görüntüleyen kullanıcılar

Bu konuyu şu anda görüntüleyen üye bulunmuyor.
Robotlar:
  • Anthropic