الانتقال إلى المحتوى
View in the app

A better way to browse. Learn more.

مجموعة مستخدمي أوراكل العربية

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

مشكلة فاتورة المبيعات و التأثير على رصيد الصنف بالمخزن

Featured Replies

بتاريخ:
  • كاتب الموضوع

ارجو من الاخوة التطرق الي صلب الموضوع في المشاركة ال 20
و جزيتم عنا خير الجزاء

  • الردود 46
  • المشاهدات 14.3k
  • البداية
  • اخر رد

أكثر المشاركين في هذا الموضوع

Most Popular Posts

  • السلام عليكم جزاكم الله خيرا اخواني احمد زين و احمد فرغلي الان انا فهمت ان حل موضوع الرصيد يأتي بحليين الحل الاول: هو عن طريق الفورم الحل الثاني : عن طريق الـ database trigger(جاري دراسته ) فبدأت ا

الصور المنشورة

بتاريخ:

السلام عليكم ورحمة الله وبركاته

اخي الكريم

بخصوص


فكيف احدد عملية التأثير على المخزن في حالة اختلاف نوع الفاتورة؟
يعني هناك حالات اضافة و هناك حالات صرف
الان هناك كثر من عملية حركة (اضافة او صرف )

هل ممكن تطوير database trigger ليحدد نوع عملية التأثير على المخزن في حالة اختلاف نوع الفاتورة



راجع الرابط التالي


http://www.araboug.org/ib/index.php?showtopic=17317


حيث الرابط السابق يحتوي علي كود يقوم بتغطية عدة احتمالات

حيث تحتاج لكتابة كود بنفس فكرته


جزاك الله كل خير
بتاريخ:
  • كاتب الموضوع

ربنا يكرمك اخي جمال
ان شاء الله
جاري فتح الرابط و محاولة فهم الكود و تطبيقة و من ثم اخباركم بالنتيجة

تم تعديل بواسطة Wise

بتاريخ:

السلام عليكم ورحمة الله وبركاته
اخي فالله
بالنسبة لتحديد شرط ان الكمية لاتقل عن المخزون انا مع طريقة الاخ جمال
واحنا عاملنها كده فالشغل عندنا

السلام عليكم ورحمة الله وبركاته

اخي الكريم

من خلال الفورم وعلي حقل الكمية استخدم الكود التالي لمراقبة الكمية المباعة بحث لا تزيد عن الكمية المتوفرة في المخزون



SQL كود
WHEN-VALIDATE-ITEM

DECLARE
aa number ;
begin select qty into aa from inventory
where inventory.invt_no = :inv_sal.invt_no ;
IF :inv_sal.qty > aa THEN
MESSAGE('الكمية المباعة أكبر من الكمية الموجودة في المخزون');
MESSAGE('الكمية المباعة أكبر من الكمية الموجودة في المخزون');
RAISE Form_Trigger_Failure;
ELSIF :inv_sal.qty <= 0 THEN
MESSAGE('يوجد خطأ في إدخال الكمية المباعة');
MESSAGE('يوجد خطأ في إدخال الكمية المباعة');
RAISE Form_Trigger_Failure;
END IF ;
END ;


اما بالنسبة الى وضع شرط لحركة معينة في شرط فال TRIGGER بيعمله WHEN
مثال كما فالكود التالي

CREATE OR REPLACE TRIGGER test_trigger
  BEFORE DELETE OR INSERT OR UPDATE ON yuor_table
  REFERENCING NEW AS NEW OLD AS OLD
  FOR EACH ROW
  WHEN (bank_id IN (1, 2))
DECLARE
BEGIN your_code
EXCEPTION
  WHEN OTHERS
  THEN
     null;
END TEST;
/

بتاريخ:
  • كاتب الموضوع

اخي الكرم احمد زين
جربت كود الاخ جمال ولكن لم ينجح معي و حاولت تطوير الكود
حيث هناك اكثر من نوع للحركة
حركة اضافة و حركة صرف
فاظن ان كود الاخ جمال ينفع فقط في حالة الاضافة اما في حالة الصرف يجب اضع شروط اخرى

و الله اعلم

بالنسبة للكود الخاص بوضع شروط في database trigger لمرفة ان الحركة على تفاصيل الفاتورة صرف ام اضافة قمت بعمل الكود التالي


create or replace  trigger UP_STORE_4_SALES
  before insert or delete or update  of qty on INV_DETAIL for each row
DECLARE
 D_TYPE NUMBER ;
 CURSOR DOC_TYPE IS
 SELECT INV_TYPE FROM INV_DETAIL; begin OPEN DOC_TYPE;
 LOOP
 FETCH DOC_TYPE INTO D_type; exit when doc_type%found;
end loop;
close doc_type;

 IF D_TYPE = '2' then
 if  inserting  then
   update ITEMS set qty = items.qty - :new.qty
       where items.item_id  = :NEW.item_id
      ;
 elsif  deleting  then
   update items set qty = items.qty +  :old.qty
   where items.item_id  = :OLD.item_id;
 else update  items  set
   qty =  items.qty - ( :new.qty - :old.qty )
   where items.item_id  = :OLD.item_id;
 end if  ;
end if;
end ;
/

بتاريخ:

السلام عليكم ورحمة الله وبركاته

اخي الكريم

ما هي الارقام التي تعتمدها للحقل inv_type وما هي مسمياتها

اي هل هي كما يلي

1 مشتريات
2 مبيعات
3 مردودات مبيعات
.....الخ

اكتبها لنا حتي احوال كتابة trigger يغطي جميع الاحتمالات التي تحتاجها

مع ملاحظة

أنه تم استخدام الـ CURSOR في الكود السابق وقد لا تحتاج لإستخدمه

إذا استخدمت


:NEW.INV_TYPE  = 1 THEN




جزاك الله كل خير

بتاريخ:
  • كاتب الموضوع

السلام عليكم جميعا
الاحتمالات الخاصة بال inv_type هي كالاتي

مشتريات 1 (حركة اضافة)
مردودات مبيعات 2 (حركة اضافة)
مبيعات 3 (حركة صرف)
مردودات مشتريات 4 (حركة صرف)

و جزيت عنا خيرا اخي جمال

تم تعديل بواسطة Wise

بتاريخ:
  • كاتب الموضوع

السلام عليكم
حولت انفذ ما اخبرتموني به

و لكن التريجر لم يؤثر على حركة صرف صنف في حالة الحذف و كان يعمب فقط بنجاح مع الاضافة و التحديث

ارجو المساعدة في الكود التالي

create or replace  trigger UP_STORE_4_SALES
  before insert or delete or update  of qty on INV_DETAIL for each row
when ( new.inv_type in (3,4))
begin if :new.inv_type = 3 or :new.inv_type =4 then
 if  inserting  then
   update ITEMS set qty = items.qty - :new.qty
       where items.item_c  = :NEW.item_c    ;
 end if;
 if updating then
   update  items  set   qty =  items.qty - ( :new.qty - :old.qty )
   where items.item_c  = :OLD.item_c;
 end if  ;
if deleting then
   update items set qty = items.qty +  :old.qty
   where items.item_c  = :OLD.item_c;
end if;
end if;
end ;
/


و جزاكم الله خير

بتاريخ:

السلام عليكم ورحمة الله وبركاته
بعد التحية
اخي فالله
انت كاتب فاول الزناد
if :new.inv_type = 3 or :new.inv_type =4 then
وفي حالة الحذف لم يتحقق هذا
فام تقوم بتغيرها الى old بدلا من new
او تقوم بعمل جزء خاص لل delete
اي تقوم بعمل التالي

create or replace trigger UP_STORE_4_SALES
before insert or delete or update of qty on INV_DETAIL for each row
when ( new.inv_type in (3,4))
begin if :new.inv_type = 3 or :new.inv_type =4 then
if inserting then
update ITEMS set qty = items.qty - :new.qty
where items.item_c = :NEW.item_c ;
end if;
if updating then
update items set qty = items.qty - ( :new.qty - :old.qty )
where items.item_c = :OLD.item_c;
end if ;
end if;
if :old.inv_type = 3 or :old.inv_type =4 then
if deleting then
update items set qty = items.qty + :old.qty
where items.item_c = :OLD.item_c;
end if;
end if;
end ;
/


وفقك الله الى ماتحب وترضي
لاتنسانا من صالح الدعاء

بتاريخ:
  • كاتب الموضوع

جزاك الله خيرا اخي فعلا اشتغلت معي
و لكن اخي احمد في حالة كون
inv_type=1,2,3,4 اي
when new.inv_type in(1,2,3,4)
حيث 1و2 هي عبارة عن حركة الاضافة (مشتريات ،مردودات مبيعات) التأثير هنا بالزيادة في رصيد الصنف بالمخزن
و 3و4 هي عبارة عن حركة الصرف (مبيعات ، مردودات المشتريات) التأثير هنا بالنقص من رصيد الصنف بالمخزن

فكيف سوف يكون الـ trigger databse يحيث يشمل كل الطرق الممكنة؟

بتاريخ:

السلام عليكم ورحمة الله وبركاته
بعد التحية
اخي فالله
يمكن حذف السطر الخاص بال when
وضع if statment للنوعين الاخرين بنفس الطريقة الاولي
او عمل trigger تاني نفس الاول ولكن بالنوعين الاخرين

بتاريخ:
  • كاتب الموضوع

السلام عليكم اخي احمد

و هل الافضل عمل تريجر 1 لجميع الحالات ام الافضل عمل 2 تريجر
تريجر خاص بحالات الاصافة
تريجر خاص بحالات الصرف

جزيت عنا خير

بتاريخ:

السلام عليكم ورحمة الله وبركاته
بعد التحية
اخي فالله
اعتقد ان الامر سيان ولكن الافضل ان يكون كل شئ مستقل وعلى حدا حتي يسهل عليك عملية الصيانةوالتطوير والتعديل في المشروع
وفقك الله الى ماتحب وترضي
ولاتنسانا من صالح الدعاء

بتاريخ:

السلام عليكم ورحمة الله وبركاته

الجداول التي تم تطبيق الـ Teriggersعليها


create  table  inv (  
inv_no      number(10) ,  /*رقم المستند*/
inv_date   date ,               /*تاريخ المستند*/
inv_type   number(1) ,   /*نوع المستند 1مشتريات_3مبيعات_2مردودات مبيعات_4مردودات مشتريات*/
dealer_id  number(1) ,    /*المتعامل معه مورد أو زبون*/ 
constraint  inv_pk   primary  key ( inv_no , inv_date , inv_type ) ) ;


create  table  items ( 
item_id    number(10) ,
qty            number(10) ,
descrp      varchar2(100) ,
sup_co      number(10) ,
constraint  items_pk   primary  key ( item_id ) ) ;


create  table  inv_detail (
inv_no      number(10) ,    /*رقم المستند*/
inv_date   date ,                 /*تاريخ المستند*/
inv_type   number(1) ,      /*نوع المستند 1مشتريات_3مبيعات_2مردودات مبيعات_4مردودات مشتريات*/
item_id     number(10) ,    /*رقم الصنف*/
qty            number(10) ,    /*الكمية*/
price         number(10,3) , /*سعر الصنف*/
constraint  inv_detail_pk   primary  key ( inv_no , inv_date , inv_type , item_id ) ,
/*constraint  inv_datail1_fk   foreign key ( inv_no , inv_date , inv_type ) references  inv ( inv_no , inv_date , inv_type ) ,*/
constraint  inv_datail2_fk   foreign key ( item_id ) references  items ( item_id )) ;




الـ Trigger التالي يقوم بتعديل الـ inv_type في جدول inv_detail عندما يتم تعديل الـ inv_type في جدول inv
وتم استخدام before في الـ trigger التالي حتى يسبق هذا الـ trigger في تنفيذه الـ Trigger الذي يليه


create or replace  trigger  t_invoice_type  before  update  of  inv_type on inv  for  each  row
begin update  inv_detail  set inv_type = :new.inv_type  
where inv_detail.inv_no = :old.inv_no and inv_detail.inv_date = :old.inv_date and inv_detail.inv_type = :old.inv_type ;
end ;



هذا الـ trigger يقوم بتعديل الكمية في جدول الـ Items عند الإدخال أو الحذف أو التعديل (علي الكمية أو النوع أو رقم الصنف )
في جدول inv_detail


create or replace trigger UP_STORE_4_SALES  after insert or delete or update of qty , inv_type , item_id on INV_DETAIL for each row
begin if inserting then
IF     :new.inv_type = 1 or :new.inv_type = 2  then
update items set qty = nvl(items.qty,0) + :new.qty where items.item_id = :new.item_id;
Elsif :new.inv_type = 3 or :new.inv_type = 4  then
update items set qty = nvl(items.qty,0) - :new.qty where items.item_id = :new.item_id;
end if ;
elsif deleting then
if       :old.inv_type = 1 or :old.inv_type = 2  then
update items set qty = items.qty - :old.qty where items.item_id = :old.item_id;
Elsif :old.inv_type = 3 or :old.inv_type = 4  then
update items set qty = items.qty + :old.qty where items.item_id = :old.item_id;
end if ;
elsif  updating  then
if        :new.inv_type = :old.inv_type and :old.item_id = :new.item_id and :new.inv_type = 3 or :new.inv_type = :old.inv_type and :old.item_id = :new.item_id and :new.inv_type = 4 then
update items set qty = items.qty - ( :new.qty - :old.qty ) where items.item_id = :new.item_id ;
elsif   :new.inv_type = :old.inv_type and :old.item_id = :new.item_id and :new.inv_type = 1 or :new.inv_type = :old.inv_type and :old.item_id = :new.item_id and :new.inv_type = 2 then
update items set qty = items.qty - ( :old.qty - :new.qty ) where items.item_id = :new.item_id ;
elsif   :old.item_id = :new.item_id and :new.inv_type = 1 and :old.inv_type = 3 or :old.item_id = :new.item_id and :new.inv_type = 1 and :old.inv_type = 4 or :old.item_id = :new.item_id and :new.inv_type = 2 and :old.inv_type = 3 or :old.item_id = :new.item_id and :new.inv_type = 2 and :old.inv_type = 4 then
update items set qty = ((items.qty + :old.qty) + :new.qty ) 
where items.item_id = :new.item_id ;
elsif  :old.item_id = :new.item_id and :new.inv_type = 3 and :old.inv_type = 1 or :old.item_id = :new.item_id and :new.inv_type = 3 and :old.inv_type = 2 or :old.item_id = :new.item_id and :new.inv_type = 4 and :old.inv_type = 1 or :old.item_id = :new.item_id and :new.inv_type = 4 and :old.inv_type = 2 then
update items set qty = ((items.qty - :old.qty) - :new.qty ) 
where items.item_id = :new.item_id ;
elsif   :old.item_id <> :new.item_id and :new.inv_type = :old.inv_type and :new.inv_type = 1 or :old.item_id <> :new.item_id and :new.inv_type = :old.inv_type and :new.inv_type = 2 then
update items set qty = items.qty - :old.qty   where items.item_id = :old.item_id;
update items set qty = items.qty + :new.qty where items.item_id = :new.item_id;
elsif   :old.item_id <> :new.item_id and :new.inv_type = :old.inv_type and :new.inv_type = 3 or :old.item_id <> :new.item_id and :new.inv_type = :old.inv_type and :new.inv_type = 4 then
update items set qty = items.qty + :old.qty   where items.item_id = :old.item_id;
update items set qty = items.qty - :new.qty where items.item_id = :new.item_id;
elsif   :old.item_id <> :new.item_id and :new.inv_type = 1 and :old.inv_type = 3 or :old.item_id <> :new.item_id and :new.inv_type = 1 and :old.inv_type = 4 or :old.item_id <> :new.item_id and :new.inv_type = 2 and :old.inv_type = 3 or :old.item_id <> :new.item_id and :new.inv_type = 2 and :old.inv_type = 4  then
update items set qty = items.qty + :old.qty   where items.item_id = :old.item_id;
update items set qty = items.qty + :new.qty where items.item_id = :new.item_id;
elsif  :old.item_id <> :new.item_id and :new.inv_type = 3 and :old.inv_type = 1 or :old.item_id <> :new.item_id and :new.inv_type = 3 and :old.inv_type = 2 or :old.item_id <> :new.item_id and :new.inv_type = 4 and :old.inv_type = 1 or :old.item_id <> :new.item_id and :new.inv_type = 4 and :old.inv_type = 2 then
update items set qty = items.qty - :old.qty   where items.item_id = :old.item_id;
update items set qty = items.qty - :new.qty where items.item_id = :new.item_id;
end if ;
end if ;
end ;



يمكن استبدال IN بدل OR في الـ trigger السابق أو تكرار elsif لكل احتمال وإلغاء OR

ولا اعرف أيهما سوف يكون أسرع في تنفيذ الكود


جزاكم الله كل خير

invoice.zip

بتاريخ:
  • كاتب الموضوع

جزاك الله خيرا

بتاريخ:
  • كاتب الموضوع

السلام عليكم و رحمة الله و بركاته
معذرة المرة السابقة كنت على وشك الرحيل الي المنزل فلم استطع الرد بطريقة كافيه
و لم استطع تشغيل الملف الخاص بالاخ جمال لكوني اعمل على developer 6i

لي استفسار على الكود التالي

create or replace trigger UP_STORE_4_SALES after insert or delete or update of qty , inv_type , item_id on INV_DETAIL for each row


لماذا وضعنا item_id هنا ؟ اليس كافيا ان يكون على نوع المستند و الكمية فقط؟

و هناك ابضا بعض الملاحظات ارجو تفسيرها لي

اولا :متى استخدم before او after في ال database trigger؟
ثانيا : الاخ احمد زين نصح تقسيم التريجر الي عدة اجزاء حتى يسهل علي تطويرها و صيانتها (وهذا الحل اميل اليه) و اكن هل هذا له تأثير سلبي على قوة الكود ؟
ثالثا : هل الافضل الاعتماد بدرجة كبيرة على database triggers بدلا من كتابة الاكواد في الفورمة

ارجو التوضيح حيث الان بصدد التركيز على database triggers
و الفضل يرجع اولا الي الله العلي القدير
ثانيا الي الاخ احمد زين لكون بطريقة عفويه كان بيشرح بعض النقاط في ال database trigger
و كذلك الي الاخ الجليل جمال الذي لم يبخل على بعله و كان يستقطع من وقته الثمين ليكتب كود كامل لحل مشاكلي

منتظر منكم التوضيح
اخوكم محمود

تم تعديل بواسطة Wise

بتاريخ:

السلام عليكم ورحمة الله وبركاته

اخي الكريم

تم استخدام item_id في الكود وذلك لـ

هناك حالة اخرى في حالة التعديل على اذن بيع
فمثلا هناك الصنف رقم 282 و هو مسجل بجدول sales details و قمنا بتعديل الصنف الي رقم 143 و هذا معناه
اننا اولا حذفنا الصنف 282 ثم عملنا حركة اضافة صنف جديد هو الصنف رقم 143
(نلاحظ ان هذه الحالة مركبة حيث انها عبارة عن حركة حذف صنف من جدول ال sales details و حركة اضافة الى جدول الـ sales details)


اما بالنسبة لـ

اولا :متى استخدم before او after في ال database trigger؟


انظر ملف الـ word


 وقت الزناد :
1. قبل before : هنا يتم تنفيذ الزناد قبل حدوث عملية معالجة البيانات وتستخدم
 عند الحاجة للتأكد من أن جملة معالجة البيانات المسببة لحدث إطلاق الزناد كاملة أم لا بمعني أن نتأكد قبل الشروع بعملية الإدخال أو
التعديل أو الحذف بأنها تحقق جميع شروط إجراء العملية وذلك بتنفيذ جسم الزناد قبل تنفيذ جملة معالجة البيانات وهذا يقلل من احتمالية حدوث تراجع عن جملة معالجة البيانات ( rollback )
 من أجل اشتقاق قيم بعض الأعمدة قبل تنفيذ جملة معالجة البيانات
2. بعد after : هنا يتم تنفيذ جسم الزناد بعد حدوث عملية معالجة البيانات وتستخدم
 عند الحاجة لتنفيذ جملة معالجة البيانات كليا قبل إجراء عملية أخري من خلال الزناد
 في حل وجود زناد ( قبل ) فإنه يمكن استخدام زناد ( بعد ) لتنفيذ عمل أخر علي نفس جملة معالجة البيانات


جزاك الله كل خير
بتاريخ:
  • كاتب الموضوع

جزاك الله خيرا اخي جمالي
استفدت الكثير منك

الان هل في INV_DETAIL BLOCK هل الافضل حفظ كل سجل (صنف) في ال DETAIL BLOCK ام اقوم بحفظ الاذن مرة واحدة

حيث تحدث بعض المشاكل الغريبة مثل :

RECORD HAS BEEN UPDATE BY ANOTHER USER ,
RE-QUERY TO SEE CHANGE
بالرغم من اني مش فاتح SQL PLUS ولا اي SESSION غير فومة واحدة التي يحدث فيها الخطأ!! ارجو توضيح سبب هذه المشكلة و اخبار بالسبب؟

و بالنسبة لعم VALIDATION على الصنف بيحث لا يمكن تسجيل نفس الصنف اكثر من مرة في نفس الاذن؟
حيث اخي انت قمت بعمل PK لهذه النقطة كما يلي

constraint inv_detail_pk primary key ( inv_no , inv_date , inv_type , item_id ) ,



و من جهتي حولت عمل كود تحقق على مستوى الفورم كما يلي و لكن يعمل فقط في حالة حفظ كل عملية ادخال صنف

و الكود على مستوى WHEN-VALIDATE-ITEM :

declare
aa number;	
begin if :inv_detail.inv_no is not null then
select item_c into aa from inv_detail
where inv_no    = :inv_detail.inv_no and inv_type  = '3' and inv_date   = :inv_detail.inv_date and item_c    =  :item_c;

	IF AA IS NOT NULL THEN 
  :ITEM_DESC := '';
    :BALANCE   :='';
   :qty       :='';
   :uom       :='';
		MESSAGE ('ONLY 1 ITEM ALLOWED IN THIS INVOICE');

		Raise form_trigger_failure;		
	END IF;

	end if;
exception when no_data_found then
null;	
end;



و ايضا من محاولاتي قمت بعمل هذا التريجر على مستوى الداتابيس

create or replace  trigger  t_valid_item  before  insert  OF ITEM_C on inv_detail  
declare
aa number;
begin select item_c into aa from inv_detail
where inv_no    = :new.inv_no and inv_type  = :new.inv_type and item_c    = :new.item_c and inv_date  = :new.inv_date;
	IF AA IS NOT NULL THEN 
	  raise_application_error(-20500,' only one item allowed in this document. ') ;
	END IF;

end ;



و جزاكك الله خيرا اخي جمال

FIRST_PROJECT.zip

تم تعديل بواسطة Wise

بتاريخ:
  • كاتب الموضوع

up

بتاريخ:
  • كاتب الموضوع

up

بتاريخ:
  • كاتب الموضوع

اخواني الكرام ارجو الرد قدر المستطاع

بتاريخ:
  • كاتب الموضوع

up

انضم إلى المناقشة

يمكنك المشاركة الآن والتسجيل لاحقاً. إذا كان لديك حساب, سجل دخولك الآن لتقوم بالمشاركة من خلال حسابك.

زائر
أضف رد على هذا الموضوع...

برجاء الإنتباه

بإستخدامك للموقع فأنت تتعهد بالموافقة على هذه البنود: سياسة الخصوصية

Account

Navigation

البحث

إعداد إشعارات المتصفح الفورية

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.