วันอังคารที่ 7 กรกฎาคม พ.ศ. 2552

java.lang.NullPointerException at org.compiere.model.MOrderLine.(MOrderLine.java:134)

===========> MTable.getPO: (id) - Table=C_OrderLine,Class=class org.compiere.model.MOrderLine [11]java.lang.NullPointerException at org.compiere.model.MOrderLine.(MOrderLine.java:134) at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27) at java.lang.reflect.Constructor.newInstance(Constructor.java:494) at org.compiere.model.MTable.getPO(MTable.java:517) at org.compiere.model.GridTable.dataSavePO(GridTable.java:1735) at org.compiere.model.GridTable.dataSave(GridTable.java:1166) at org.compiere.model.GridTab.dataSave(GridTab.java:864) at org.compiere.apps.APanel.cmd_save(APanel.java:1927) at org.compiere.apps.APanel.actionPerformed(APanel.java:1583) at org.compiere.apps.AppsAction.actionPerformed(AppsAction.java:281) at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1849) at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2169) at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:420) at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:258) at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:236) at java.awt.AWTEventMulticaster.mouseReleased(AWTEventMulticaster.java:231) at java.awt.Component.processMouseEvent(Component.java:5517) at javax.swing.JComponent.processMouseEvent(JComponent.java:3135)


แก้ไข: ที่ source code ไปดูที่ MOrderLine.java บรรทัดที่ 134 ว่า NullPointerException เพราะเหตุใด
เมื่อไปดูจะพบ
setDateOrdered (m_parent.getDateOrdered());

สาเหตุน่าจะมาจาก m_parent มีค่าเป็น null ณ ขณะที่ถูกเรียกใช้

ให้ทำการแก้ไข code โดย comment code เดิมไว้ และแก้ไขเป็นดังนี้
// Fixed: NullPointerException 090702 Sureeraya.
// setDateOrdered (m_parent.getDateOrdered());
setDateOrdered (getParent().getDateOrdered());

หน้าจอ [MK-SO-02] รายการราคาไม่แสดง เลือกไม่ได้ ทั้งๆ ที่กำหนดรายการราคาไว้มากมาย

Window [MK-SO-02] , Tab Sale Order, Field M_PriceList_ID can not select any PriceList

Fixed: In Table C_Order, Column M_PriceList_ID. It has reference to M_PriceList and dynamic reference is 'M_PriceList is SO/PO'

M_PriceList is SO/PO
From:
M_PriceList.IsSOPriceList = '@IsSOTrx@' and M_PriceList.AD_Org_ID=@AD_Org_ID@

To:
M_PriceList.IsSOPriceList = '@IsSOTrx@' and (M_PriceList.AD_Org_ID=@AD_Org_ID@ or M_PriceList.AD_Org_ID=0)

สาเหตุที่หน้าจอ Sale Order [MK-SO-02] นี้ไม่เป็นรายการราคา สำหรับบาง Organization นั่นก็เนื่องมาจาก เดิม M_PriceList is SO/PO นั้นได้มีการสร้างเงื่อนไขไว้ว่า PriceList ที่จะแสดงได้ต้องมีค่า IsSOTrx ตามหน้าจอ เช่นที่หน้าจอ ซื้อ ก็จะแสดงแต่ PriceList ที่เป็น 'ซื้อ' หรือ ที่หน้าจอขาย ก็จะแสดงเฉพาะที่ PriceList ขาย นั่นเอง ต่อมาก็จะไปเจอเงื่อนไขว่าและต้องเป็น PriceList ของ Organization นั้นๆ ด้วย จึงจะแสดง สำหรับเงื่อนไขนี้ถามว่ากำหนดค่าไว้ในตอนแรกผิดมั๊ย คำตอบคือ ไม่ผิดค่ะ
แล้วทำอย่างไรให้รายการราคาที่กำหนดไว้มาแสดง สามารถทำได้ง่ายๆ ก็คือ ที่หน้าจอ PriceList ที่ฟิลด์หน่วยงาน แทนที่จะกำหนดเป็น * ให้กำหนดเป็น ค่าของหน่วงงานแต่ละหน่วยงานไป ผลก็คือ หน่วยงานหนึ่งๆ จะต้องมีอย่างน้อย 1 PriceList

ส่วนที่แก้ไปสามารถอธิบายได้ง่ายๆ คือ ให้เช็คเพิ่มด้วยว่า ถ้าเป็น PriceList ทีกำหนดให้เป็นของ * ให้แสดงด้วย เนื่องจากการกำหนดค่าใดๆ ในระบบหากกำหนดที่หน่วยงานให้เป็นระดับ * แสดงว่าเราต้องการแชร์ข้อมูล คือให้ข้อมูลเป็นข้อมูลระดับ Client ไม่ได้เป็นของหน่วยงานใดหน่วยงานหนึ่ง และต้องการให้ทุกหน่วยงานเห็นข้อมูลนี้

คำถามถัดมา อาจมีคนสงสัยต่ออีกว่าแล้วระบบรู้ได้ไง ว่าหน้าจอนี้เป็นหน้าจอซื้อ หรือหน้าจอขาย มีตรงไหนระบุไว้หรือ
คำตอบก็คือ มีค่ะ ถ้าคนที่ศึกษา Adempiere หรือ Compiere มาระดับหนึ่ง จะต้องรู้จัก Application Dictionary อย่างแน่นอน
ที่นี่เป็นที่รวบรวมการกำหนดค่าต่างๆ ของระบบไว้ทั้งหมด ทั้งที่เกี่ยวข้องกับฐานข้อมูล และหน้าจอ รายงาน .... (เริ่มนอกเรื่อง) ในส่วนของ Window, Tab and Field จะมีให้กำหนดว่า หน้าจอที่เราสร้างขึ้นนี้เป็นหน้าจอ แบบไหน เป็นหน้าจอเกี่ยวกับการขายหรือไม่ คือว่าง่ายๆ ที่นี่จะมีการกำหนดค่าให้กับตัวแปร IsSOTrx ถ้าเป็น 'Y' ก็แสดงว่าหน้าจอนี้ฉันจะให้เป็นหน้าจอที่ทำรายการเกี่ยวกับการขายนะจ๊ะ แค่นี้ค่ะ

FIFO: cwtprod_test: cwtprod_090702

1. กำหนดโครงสร้างบัญชี Accounting Schema, set cost method to 'Last PO Price'














2. กำหนดค่าที่กลุ่มสินค้าที่จะทดสอบ Product Category Account, set Cost Method 'FIFO', Costing Level BLANK















3. กำหนดค่า สินค้า Product ที่จะทำการทดสอบ กำหนดกลุ่มสินค้า เป็นกลุ่มสินค้าที่เลือก
กำหนดราคาให้กับสินค้านี้ในแท็บ PriceList ระบุ PriceList Version ที่ต้องการกำหนดราคา



ขั้นตอนการทดสอบ
1. เปิดใบสั่งซื้อ PO ที่หน้าจอ Purchase Order
ตรวจสอบสินค้า W03-0009 ไม่มีสินค้าอยู่ในคลังสินค้า เพื่อให้ง่ายในการตรวจสอบการบันทึกต้นทุนสินค้า

ครั้งที่ 1 เปิดใบสั่งซื้อ PO0907-001 ซื้อสินค้า W03-0009 จำนวน 100 ชิ้น ราคาชิ้นละ 8 บาท
ครั้งที่ 2 เปิดใบสั่งซื้อ PO0907-002 ซื้อสินค้า W03-0009 จำนวน 50 ชิ้น ราคาชิ้นละ 10 บาท

หมายเหตุ ให้สมบูรณ์เอกสาร หลังทำรายการเรียบร้อยทุกครั้ง




2. ทำการรับสินค้า MM Receipt ที่หน้าจอ รับเข้า/คืนสินค้า (ผู้จำหน่าย)

ครั้งที่ 1 ทำการรับสินค้า MM0907-001 รับสินค้าตาม PO0907-001
ครั้งที่ 2 ทำการรับสินค้า MM0907-002 รับสินค้าตาม PO0907-002

หมายเหตุ ให้สมบูรณ์เอกสาร หลังทำรายการเรียบร้อยทุกครั้ง


3. ทำการบันทึกบัญชี เพื่อผ่านรายการไปยังบัญชีแยกประเภท