Oracle Magazine March 2013

Oracle Magazine March 2013

Cloud Documentaries | In this issue of Oracle Magazine, real organizations use Oracle public and private cloud solutions—including Oracle Cloud, Oracle Database, and Oracle Enterprise Manager 12c—to put their own customers first, integrate cloud and legacy information systems, move their standards-based cloud solutions between different cloud service providers, deploy solutions in Oracle Cloud and private cloud environments, and more. See “Utility Computing in the Cloud” (page 24) and “Banking on a Private Cloud” (page 30) in this issue to learn more about how three organizations use and benefit from Oracle cloud solutions.

The Oracle Cloud and Oracle private cloud solutions featured in this issue also rely on Oracle engineered systems, including Oracle Exadata and Oracle Exalogic. And because these are real-world stories, no mainframes of any kind were used in the successful deployment of and access

In movies and television shows, information technology is often scaled down to fit the story. That magically computed result, that missing electronic file, and that unknown password that will stop something bad or start something good can go from nonexistent to resolved in one brief scene. And for historical reasons, I suppose, the significant computing power in most screen fiction seems to come from a vintage mainframe— rather than a modern supercomputer or engineered system.

I haven’t seen too many references to cloud computing in movies or on television, but those that I have seen seem limited to the idea that a treasured file or information the hero or villain may be looking for is safe from local mayhem because it is safely stored “in the cloud.” Fortunately, the fact that a movie or television show delivers a very narrow definition of cloud computing as internet-located storage isn’t likely to break the on-screen story or reduce the entertainment value of a production.

Cloud Business Stories

At the same time, the fact that enterprise cloud computing is much bigger than internet storage isn’t guaranteed to give cloud a bigger or more detailed definition on the big and small screens. To start, enterprise cloud computing is about the infrastructure, platform, and application services deployed in public, private, and hybrid clouds that support the business. That big beginning could also be part of why it’s easier in a movie plot to point to the internet and call it the cloud.

But if a movie wanted to show what enterprise cloud computing means for business, it would have to go big. A comprehensive look at cloud would have to include the aforementioned themes of infrastructure, platform, and application services along with cloud management, security, integration, development, social computing, mobility, business intelligence, big data, and more. And a discussion about potential cloud challenges would include siloed information, control and visibility, data privacy and regulatory compliance, proprietary architectures, and vendor lock-in.

Download Magazine Here.

Oracle Magazine January 2013

Oracle Magazine January 2013

This issue of Oracle Magazine presents and celebrates the winners in all of the 2012 Oracle Excellence Awards programs, including the Oracle Excellence Awards for CIO of the Year, Technologist of the Year, and Database Administrator of the Year.

Managing nominations, judging, trophy design and delivery, events, publicity, and more across 12 awards programs is no small collection of responsibilities. Oracle Global Customer Programs oversees the 12 Oracle Excellence Awards programs, coordinates many of these activities, and deserves much congratulations and thanks for all of its efforts. The judging processes vary across the different awards categories, but several programs — including Technologist of the Year — use Oracle user group leaders as judges. Thanks to these community leaders for volunteering their time and expertise. Thanks also to the nominators, designers, and everyone else who worked behind the scenes.

Finally, on behalf of Oracle Magazine, congratulations and thanks to all of the Oracle Excellence Awards winners.

Download magazine here.

Heartbleed for Dummies

Pojok Programmer Heartbleed OpenSSL for Dummies  infographics

Security | Beberapa hari terakhir banyak dunia IT diramaikan oleh bug Heartbleed. Bagi yang kurang memahami security, atau bagia yang belum bersentuhan dengan dunia security mungkin agak bingung, sebenarnya ada problem apa dengan bug ini.  Saya bukan ahli dalam hal security atau keamanan jaringan, tapi mudah-mudahan penjelasan dalam artikel ini cukup mudah dimengerti untuk memahami bagaimana cara kerja bug heartbleed.

Bug heartbleed bersarang di dalam implementasi OpenSSL untuk TLS heartbeat. Secara umum, tujuan dari heartbeat ini adalah untuk memverifikasi bahwa koneksi ke sebuah server masih terhubung atau tidak dengan cara mengirimkan sebuah pesan dan mengharapkan respon respon yang sama. Ketika sebuah paket TLS heartbeat dikirim , di dalam paket tersebut berisikan beberapa potongan penting dari informasi dan sebarang data, atau payload. Server yang menerima paket payload ini harus mengirimkan ulang isinya untuk memverifikasi sambungan masih hidup atau tidak. Di dalam paket TLS heartbeat itu juga tersimpan informasi panjang payload, kita sebut saja sebagai len_payload. Dan ukuran maksimum payload adalah sebesar 1 byte atau 2^16 = 64kB data.

Yang dilakukan oleh OpenSSL saat menerima paket payload heartbeat adalah, 

  • Mengalokasikan variable respon, dengan menggunakan len_payload sebagai ukuran payload balasan
  • memcpy() len_payload byte dari payload ke dalam respon.
  • Kirim respon heartbeat (dengan semua len_payload bytes) kembali ke pengirim asli.

Problem muncul karena OpenSSL tidak pernah repot-repot untuk memeriksa apakah len_payload yang benar-benar sesuai dengan panjang payload yang diterima. Jadi, orang attacker bisa mengirim permintaan heartbeat yang menunjukkan panjang payload (len_payload) hingga 2^16 (65536) , namun payload sebenarnya jauh lebih pendek. Sehingga yang terjadi adalah bahwa memcpy menyalin data di memory ke luar batas payload ke dalam variable respon, memberikan hingga 64k isi memori OpenSSL ke attacker. Koq bisa tidak terjadi segmentation fault? hal tersebut terjadi karena OpenSSL memiliki implementasi custom tersendiri sehingga tidak menimbulkan segmentation fault di level OS.

Lalu, apa keuntungannya? 

Apa yang ada di memori 64k ekstra ini? Itu tergantung…. Anda bisa mendapatkan apa pun yang berguna pada satu paket heartbeat palsu. Dan tidak ada yang bisa menghentikan Anda dari mengirim paket heartbeat palsu seperti itu sebanyak yang kita inginkan. Banyak yang telah menunjukkan bahwa mereka bisa mendapatkan informasi yang tidak terenkripsi berupa username, password, private security keys, dan hal-hal lain yang dibutuhkan untuk kepentingan keamanan di dunia maya.

Happy Understanding! ðŸ˜€

Terjemahan bebas dari Pertanyaan di Quora.

Heartbleed Infographics

Pojok Programmer Heartbleed OpenSSL for Dummies  infographics

Sumber gambar: http://www.bankinfosecurity.com/heartbleed….

How Heartbleed Works

Pojok Programmer Heartbleed OpenSSL for Dummies  infographics How Heartbleed Works

Sumber gambar: http://xkcd.com/1354/

Hello World Versi OOP Menggunakan VB.net

Hello World Versi OOP Menggunakan VB.net

Pemrograman | Pemrograman Berorientasi Obyek (PBO) atau Object Oriented Programming (OOP) adalah salah satu paradigma pemrograman yang berusaha menyederhanakan problem yang diselesaikan sebagai kumpulan dari obyek-obyek. Selain paradigma OOP, masih ada beberapa paradigma pemrograman lainnya, seperti Pemrograman ImperativePemrograman ProceduralPemrograman Functional, dan lain-lain. Namun artikel ini tidak akan membahas semua paradigma tersebut. Artikel ini akan mencoba menjelaskan secara ringkas beberapa konsep penting dalam OOP dan menerapkan konsep tersebut menjadi sebuah program Hello World sederhana.

UPDATE: Karena ada permintaan program Hello World dalam versi PHP, silakan buka spoiler di bagian akhir dari artikel ini

Interface

Interface sering digunakan untuk mendefinisikan sebuah tipe abstrak yang tidak berisi data, dan memaparkan perilaku obyek dalam bentuk kumpulan function  atau method. Sebuah class yang memiliki semua function atau method yang sama dikatakan mengimplementasikan interface tersebut. Selain itu, class dapat mengimplementasikan beberapa interface sekaligus. Contoh Interface dalam sebuah code VB.net adalah sebagai berikut

''' Interface Printer
''' Mendifinisikan behavior printer
Public Interface Printer
    Sub PrintOut(ByVal message As String)
End Interface

Class

Class adalah template atau pola yang digunakan untuk membuat objek, biasanya berisikan sejumlah nilai awal untuk variable dan implementasi perilaku (behavior) dari sebuah interface. Berikut ini contoh implementasi sebuah Interface Printer dan contoh Class Message yang akan kita gunakan untuk menyimpan pesan yang ingin kita cetak ke printer dalam sebuah code VB.net adalah sebagai berikut,

''' implementasi interface Printer
''' class untuk mencetak ke console
Public Class SystemOutPrinter
    Implements Printer
    Public Sub PrintOut(message As String) Implements Printer.PrintOut
        Console.WriteLine(message)
    End Sub
End Class

''' Class berisi pesan yang ingin ditampilkan
Public Class Message
    Private message As String
    ' constructor
    Public Sub New(ByVal message As String)
        Me.message = message
    End Sub
    ' fungsi untuk menampilkan pesan
    Public Sub PrintOut(printer As Printer)
        printer.PrintOut(Me.ToString())
    End Sub
    ' fungsi untuk mengubah pesan menjadi string
    Public Overrides Function ToString() As String
        Return Me.message
    End Function
End Class

Inheritance

Inheritance adalah ketika suatu obyek atau kelas didasarkan pada objek atau class lain. Inheritance adalah sebuah mekanisme penggunaan kembali kode (code reuse). Hubungan inheritance menimbulkan sebuah hubungan hirarki antara parent class dengan child class, dengan child class akan mewariskan semua property/variable dan method yang ada di parent class. Contoh penerapan abstract class dan inheritance menggunakan VB.net adalah sebagai berikut,

''' contoh class abstract
''' harus dibuat object inheritance kalau mau pake
Public MustInherit Class AbstractPrinterFactory
    Public Shared Function GetFactory() As AbstractPrinterFactory
        ' return default printer factory
        Return New SystemOutPrinterFactory()
    End Function
    Public MustOverride Function GetPrinter() As Printer
End Class

''' hasil turunan abstract class
Public Class SystemOutPrinterFactory
    Inherits AbstractPrinterFactory
    Public Overrides Function GetPrinter() As Printer
        Return New SystemOutPrinter()
    End Function
End Class

Abstract Class vs. Interface

Jika kita perhatikan di atas, Inheritance dapat berupa extend/inherits class lain, atau implements sebuah interface. Keduanya sama-sama mewariskan semua method ke child class. Namun ada perbedaan yang perlu diperhatikan. Sebuah class hanya bisa extend/inherits dari satu class saja, sedangkan sebuah class bisa implements banyak Interface. Untuk memudahkannya. Inherits menggambarkan hubungan “adalah”, artinya Class Tiger inherits Animals, sama artinya Tiger adalah Animals, Sedangkan Implements artinya “bisa melakukan sesuatu”, misalkan Tiger Implements Running, Swimming. Artinya Tiger bisa Running dan Swimming.

Hello World!

Akhirnya setelah semua siap, sekarang kita buatkan method Main untuk memanggil Hello World kita, seperti di bawah ini

''' module utama
Module HelloWorld
    Public Sub Main()
        Dim message As New Message("Hello World!")
        Dim factory As AbstractPrinterFactory
        Dim printer As Printer
        ' create printer
        factory = SystemOutPrinterFactory.GetFactory()
        printer = factory.GetPrinter()
        ' display message 
        ' menggunakan printer yang di buat di atas
        message.PrintOut(printer)
    End Sub
End Module

Dan hasil tampilannya seperti dibawah ini

Hello World Versi OOP Menggunakan VB.net

Source code lengkap menggunakan Visual Studio 2012 silakan unduh di sini.

[collapsed title=Source Code Lengkap versi VB.net]

''' 

”’ Class berisi pesan yang ingin ditampilkan ”’

Public Class Message Private message As String ‘ constructor Public Sub New(ByVal message As String) Me.message = message End Sub ‘ fungsi untuk menampilkan pesan Public Sub PrintOut(printer As Printer) printer.PrintOut(Me.ToString()) End Sub ‘ fungsi untuk mengubah pesan menjadi string Public Overrides Function ToString() As String Return Me.message End Function End Class ”’

”’ Interface Printer ”’

Public Interface Printer Sub PrintOut(ByVal message As String) End Interface ”’

”’ implementasi interface Printer ”’

Public Class SystemOutPrinter Implements Printer Public Sub PrintOut(message As String) Implements Printer.PrintOut Console.WriteLine(message) End Sub End Class ”’

”’ contoh class abstract ”’ harus dibuat object inheritance kalau mau pake ”’

Public MustInherit Class AbstractPrinterFactory Public Shared Function GetFactory() As AbstractPrinterFactory ‘ return default printer factory Return New SystemOutPrinterFactory() End Function Public MustOverride Function GetPrinter() As Printer End Class ”’

”’ hasil turunan abstract class ”’

Public Class SystemOutPrinterFactory Inherits AbstractPrinterFactory Public Overrides Function GetPrinter() As Printer Return New SystemOutPrinter() End Function End Class ”’

”’ module utama ”’

Module HelloWorld Public Sub Main() Dim message As New Message(“Hello World!”) Dim factory As AbstractPrinterFactory Dim printer As Printer ‘ create printer factory = SystemOutPrinterFactory.GetFactory() printer = factory.GetPrinter() ‘ display message ‘ menggunakan printer yang di buat di atas message.PrintOut(printer) Console.ReadLine() End Sub End Module

[/collapsed]

 

Versi PHP

 

UPDATE: Karena ada permintaan program Hello World dalam versi PHP, silakan buka spoiler di bawah ini untuk lebih jelasnya

 

[collapsed title=Source Code Lengkap versi PHP]

 

/*
 * contoh interface
 */
interface Printer 
{ 
	public function printOut($message); 
} 

/*
 * class Message 
 * berisi pesan string yang ingin ditampilkan
 */
class Message 
{ 
	private $message; 

	public function __construct($message) { 
		$this->message = $message; 
	} 

	public function printOut($printer) { 
		$printer->printOut($this->toString()); 
	} 

	public function toString() { 
		return $this->message; 
	} 
} 

/*
 * contoh class abstract
 * harus dibuat object inheritance kalau mau pake
 */
abstract class AbstractPrinterFactory 
{ 
	public static function getFactory(){ 
		return new SystemOutPrinterFactory(); 
	} 

	public abstract function getPrinter(); 
} 

/*
 * contoh inheritance dari class abstract
 */
class SystemOutPrinterFactory extends AbstractPrinterFactory 
{ 
	public function getPrinter() { 
		return new SystemOutPrinter(); 
	} 
} 

/*
 * contoh implementasi interface
 */
class SystemOutPrinter implements Printer 
{ 
	public function printOut($message) { 
		print $message; 
	} 
} 

/*
 * program utama :)
 */
class HelloWorld 
{ 
	public static function run($arg) 
	{ 
		$message = new Message($arg); 
		$factory = AbstractPrinterFactory::getFactory(); 
		$printer = $factory->getPrinter(); 
		$message->printOut($printer); 
	} 
}


/*
 * Sekarang jalankan aplikasi
 */
HelloWorld::run("Hello, World!");

 

[/collapsed]

 

Selamat Belajar!

 

Hello World Versi OOP Menggunakan VB.net

 

10 Artikel Populer Maret 2014

Pojok Programmer Top Articles Stories Artikel Populer

Pojok Programmer | Berikut ini adalah artikel populer berdasarkan kunjungan para pecinta situs Pojok Programmer selama periode bulan Maret 2014. Untuk bulan Maret ini tutorial tentang Crystal Report menjadi jawaranya, dan artikel serial Aplikasi Inventory menjadi juara umum karena 5 (lima) artikel membahas tentang serial Aplikasi Inventory ini. Berikut ini daftar 10 (sepuluh) artikel tersebut. 

  1. Membuat Laporan Master Detail Menggunakan Crystal Report (1.092 views). Berupa tutorial pembuatan laporan Crystal Report menggnuakan metoda push (push method) menggunakan DataSet dengan contoh kasus print-out Purchase Order.
  2. Pengenalan BPMN (907 views). Artikel perkenalan tentang Pemodelan Proses menggunakan notasi BPMN yang merupakan pengembangan dari UML Activity Diagram.
  3. Aplikasi Inventory Sederhana (682 views). Merupakan artikel summary langkah demi langkah membuat Aplikasi Inventory Sederhana emnggunakan VB.net.
  4. Aplikasi Inventory Sederhana, Analisa dan Desain Database (602 views). Penjelasan lebih detail tentang desain database dengan mengikuti kaidah normalisasi.
  5. Aplikasi Inventory Sederhana, Desain User Interface (540 views). Penjelasan tentang konsep Visual Inheritance untuk membangun sebuah user interface yang konsisten.
  6. Aplikasi Inventory Sederhana, Analisa dan Desain Aplikasi (528 views). Berupa contoh penggunaan UML untuk menentukan ruang lingkup project.
  7. Dasar-Dasar Stored Procedure di SQL Server 2005 (503 views). Artikel sederhana tentang dasar-dasar membuat sebuah Stored Procedure di SQL Server.
  8. Membuat Combobox dengan Data dari Database (474 views). Cara mudah mengisi Combobox dengan data dari database menggunakan data-binding
  9. Membuat Combobox Berantai (467 views). Bahasa kerennya adalah Chained Dropdown Combobox atau Combobox Berantai, juga menggunakan metode data-binding.
  10. Aplikasi Inventory Sederhana, Penggunaan Trigger untuk Tracking Status Stock (453 views). Penjelasan penggunaan trigger untuk mempermudah pengembangan Aplikasi Inventory ini.

Semoga artikel-artikel di Pojok Programmer bisa menjadi inspirasi bagi para pembacanya. Dan yang berminat untuk menjadi kontributor situs ini, silakan menghubungi saya melalui PM di Facebook.

Salam Pojok Programmer.

Pojok Programmer Artikel Populer Top Articles Stories

Aplikasi Inventory Sederhana – Desain User Interface

Aplikasi Inventory Sederhana Desain User Interface Visual Inheritance BiruniLabs

Desain User Interface | Untuk memudahkan penggunaan aplikasi atau program yang kita buat, makan user interface atau antarmuka pengguna haruslah cukup intuitif dan konsisten. Misalkan sebuah aplikasi inventory pastinya akan mempunya form untuk menampilkan daftar gudang, daftar barang, daftar transaksi barang dan sebagainya. Form-form yang memiliki tujuan serupa harus memiliki layout yang sama, dalam artian memiliki posisi button yang sama, posisi grid juga sama, dan sebagainya. Untuk itu kita bisa saja membuat beberapa form dan menambahkan control ke dalamnya satu persatu, kemudian kita ulangi kembali langkah2 tersebut untuk semua form yang diperlukan…. Sungguh kerja keras yang luar biasa 🙂 …. Namun sebagai programmer kita harus juga kerja cerdas. Di sinilah Visual Inheritance akan membantu kita mempermudah hal tersebut.

Artikel ini adalah lanjutan dari artikel berseri tentang Tutorial Membuat Aplikasi Inventory Sederhana Menggunakan VB.net dan Database MySQL

Masih ingat dengan konsep Inheritance di OOP? Dengan menggunakan inheritance kita bisa membuat sebuah class yang merupakan turunan dari class yang lain dengan class hasil turunannya mewariskan (inherit) semua sifat (properties dan methods) dari superclass-nya. Dan kalau kita perhatikan Form juga adalah sebuah class, artinya kita juga bisa membuat sebuah class turunannya. Di sinilah istilah Visual Inheritance menjadi relevan, karena seluruh tampilan visual, berupa layout dan posisi control, seperti Button, Panel, Label, dan sebagainya otomatis akan diwariskan kepada Form turunannya, sehingga keinginan kita membuat sebuah User Interface yang konsisten bisa dicapai dengan coding seminimal mungkin.

Untuk Aplikasi Inventory Sederhana yang sedang kita buat ini, kita memerlukan 2 (dua) buah form dengan tampilan layout Button yang konsisten, untuk mempermudah pengguna, yaitu

  • Pertama, form untuk melihat daftar barang dan daftar transaksi
  • Kedua, form untuk proses tambah atau edit barang dan transaksi

Sesuai desain aplikasi yang sudah kita buat sebelumnya, desain form untuk menampilkan daftar barang dan daftar transaksi harus memiliki sejumlah Button untuk proses Tambah, Ubah, dan Hapus. Action tambahan lainnya adalah Button untuk Refresh dan Cetak Data. Maka desainnya kita buat seperti ini.

[collapsed title=Spoiler: Desain Form List] Aplikasi Inventory Sederhana Desain User Interface Visual Inheritance BiruniLabs [/collapsed]

Sedangkan form untuk proses penambahan dan pengubahan data cukup memiliki Button untuk Simpan saja, seperti ini.

[collapsed title=Spoiler: Desain Form Edit Data] Aplikasi Inventory Sederhana Desain User Interface Visual Inheritance BiruniLabs [/collapsed]

Seluruh control dalam template tersebut harus kita set property Modifer sebagai Protected, agar kita bisa mengubah property masing-masing control tersebut di dalam form turunannya.

[collapsed title=Spoiler: Ubah Modifier Semua Control] Aplikasi Inventory Sederhana Desain User Interface Visual Inheritance BiruniLabs [/collapsed]

Untuk menambahkan form turunan dari template yang sudah kita buat di atas maka, maka silakan buka Form Dialog Add New Item, dan pilih Inherited Form seperti gambar di bawah ini, kemudian berikan nama form turunan dan klik tombol [Add]

[collapsed title=Spoiler: Add New Item Dialog] Aplikasi Inventory Sederhana Desain User Interface Visual Inheritance BiruniLabs [/collapsed]

Berikutnya akan muncul Dialog Box yang meminta kita untuk memilih Form superclass, atau Form template layout yang akan kita pakai sebagai parent, seperti tampak pada gambar di bawah ini.

[collapsed title=Spoiler: Select Parent Form] Aplikasi Inventory Sederhana Desain User Interface Visual Inheritance BiruniLabs [/collapsed]

Jika kita kita buka file frmItemList.Designer.vb, maka ada kata kunci penting yang menandakan bahwa frmItemList adalah turunan (inherit) dari frmList. Seperti terlihat di gambar ini.

[collapsed title=Spoiler: Inheritance – Designer Code] Aplikasi Inventory Sederhana Desain User Interface Visual Inheritance BiruniLabs [/collapsed]

Tambahkan semua form yang kita perlukan, meliputi Form Daftar Barang, Form Edit Barang, Form Daftar Barang Masuk, Form Edit Barang Masuk, dan seterusnya, sehingga keseluruhan Solution kita menjadi seperti gambar di bawah ini.

[collapsed title=Spoiler: Struktur File Solution] Aplikasi Inventory Sederhana Desain User Interface Visual Inheritance BiruniLabs [/collapsed]

Setelah selesai, maka kita dapat mengubah dan menambahkan control yang kita inginkan ke Form Turunannya, misalkan contoh untuk Form Entry Data Master Barang seperti gambar di bawah ini.

[collapsed title=Spoiler: Contoh Desain Form Edit Barang] Aplikasi Inventory Sederhana Desain User Interface Visual Inheritance BiruniLabs [/collapsed]

Mudah-mudahan penjelasan tentang Visual Inheritance dapat dipahami dengan mudah, dan silakan kunjungi link di bawah ini untuk mengunduh source-code sementara.

[collapsed title=Spoiler: Download Source Code Di Sini] Dibuat menggunakan Visual Studio 2013, Silakan Download Source Code Di Sini [/collapsed]

Salam PojokProgrammer ^_^

 

.

Mudah Membuat Chained Drop Down Combo Box

Chained Dropdown List, atau Chained Combo Box, atau Chained Select, atau jika di Indonesiakan menjadi Select Bertingkat atau Combo Box Bertingkat

Belajar Programming | Chained Dropdown List, atau Chained Combo Box, atau Chained Select, atau jika di Indonesiakan menjadi Select Bertingkat atau Combo Box Bertingkat, adalah salah satu teknik yang sering ditanyakan di forum-forum pemrograman. Dengan teknik ini, kita membuat seolah-olah beberapa dropdown list atau combobox saling berhubungan, misalkan combobox nama-nama kota akan terisi otomatis sesuai dengan pilihan negara di combobox lainnya. Atau combobox list pegawai akan berubah sesuai dengan departemen yang dipilih. Teknik ini sebenarnya sangatlah sederhana, namun memerlukan pemahaman yang cukup komprehensif mengenai mengenai beberapa hal, seperti cara mengambil data dari database, cara mengisi data ke combobox atau dropdown list, dan cara mengambil pilihan pengguna sebagai referensi untuk mengisi combobox lainnya.

(more…)

Aplikasi Inventory Sederhana – Penggunaan Trigger untuk Tracking Stock Barang

Aplikasi Inventory Sederhana - Penggunaan Trigger untuk Tracking Stock Barang

Trigger bagaikan pisau bermata dua. Salah penggunaan bisa berakibat fatal, dan tidak sedikit developer software antipati dengan trigger karena sering terjadi hal-hal yang tidak disangka-sangka dan bahkan di luar nalar, berhari-hari melakukan debugging, pada akhirnya problem ditemukan karena adanya sebuat trigger yang tidak terdokumentasi dengan baik. Walaupun sebuah pisau bisa membunuh kita, bukan berarti kita harus membuangnya jauh-jauh dan tidak mau menggunakannya lagi, karena penggunaan yang benar tentunya akan sangat membantu mempermudah dan meningkatkan kualitas hidup kita 🙂

Dalam artikel ini, akan kita mempelajari cara penggunaan trigger yang benar, dalam rangka membantu mempermudah kita membuat sebuah Aplikasi Inventory Sederhana Aplikasi Stok Barang ini. Trigger akan kita gunakan untuk melakukan update status kuantitas stok barang setiap kali terjadi transaksi penambahan dan pengurangan barang, atau transaksi barang masuk atau barang keluar. Jika kita sederhanakan sampai level database, maka akan ada perintah SQL INSERT, UPDATE, dan DELETE di table transaksi yang secara otomatis, mengubah status stok barang bersangkutan.

Desain database sudah kita buat pada langkah analisa dan desain database pada artikel sebelumnya. Maka langkah selanjutnya adalah membuat trigger untuk setiap jenis SQL DML. Trigger akan kita tempelkan ke table transaction_details, karena di table itulah informasi ID dan jumlah kuantitas barang tersedia. Untuk detail sintaks CREATE TRIGGER dapat mengacu ke dokumentasi MySQL CREATE TRIGGER di sini.

Referensi Data

Untuk tutorial ini, diasumsikan sudah tersedia data untuk transaction_types dan items seperti berikut ini,

mysql> -- -----------------------------
mysql> -- data jenis transaksi
mysql> -- -----------------------------
mysql> select * from transaction_types ;
+----+------+---------------+
| id | code | name          |
+----+------+---------------+
|  1 | IN   | BARANG MASUK  |
|  2 | OUT  | BARANG KELUAR |
+----+------+---------------+
2 rows in set (0.00 sec)

mysql> -- -----------------------------
mysql> -- data master barang
mysql> -- -----------------------------
mysql> select * from items ;
+----+--------+-------------------------+------------------+---------+
| id | code   | name                    | quantity_on_hand | remarks |
+----+--------+-------------------------+------------------+---------+
|  1 | PC.001 | PC Jangkrik Tipe 1      |             0.00 | NULL    |
|  2 | PC.002 | PC Jangkrik Tipe 2      |             0.00 | NULL    |
|  3 | SV.001 | Server Rainer Tipe 1    |             0.00 | NULL    |
|  4 | SV.002 | Server Rainer Rackmount |             0.00 | NULL    |
+----+--------+-------------------------+------------------+---------+
4 rows in set (0.00 sec)

INSERT Data Transaksi

Untuk proses INSERT ini akan kita set berjalan setiap kali ada sebuah row dimasukkan ke dalam database, diindikasikan dengan keywork FOR EACH ROW, dan setiap row yang baru masuk bisa kita ketahui di variable NEW. Logikanya adalah seperti ini,

  • Setiap kali ada transaksi barang masuk, maka field stok barang di table items akan kita tambahkan,
  • Sebaliknya, setiap kali ada transaksi barang keluar, maka field stok barang di table items akan kita kurangi,

maka trigger INSERT akan seperti ini.

mysql> delimiter $$

mysql> drop trigger if exists trg_transaction_details_after_insert$$
Query OK, 0 rows affected (0.00 sec)

mysql> -- -----------------------------
mysql> -- after insert trigger
mysql> -- -----------------------------
mysql> create trigger trg_transaction_details_after_insert
    -> after insert on transaction_details
    -> for each row
    -> begin
    ->   -- -----------------------------
    ->   -- ambil jenis transaksi
    ->   -- -----------------------------
    ->   declare tipe varchar(20);
    ->   set tipe = (
    ->     select tt.code
    ->       from transactions tr
    ->       join transaction_types tt on tr.type_id=tt.id
    ->       where tr.id=new.trans_id
    ->   ) ;
    ->   -- -----------------------------
    ->   -- update sesuai jenis transaksi
    ->   -- -----------------------------
    ->   update items
    ->     set quantity_on_hand
    ->         = quantity_on_hand
    ->         + case when tipe='IN' then new.quantity
    ->                when tipe='OUT' then -new.quantity
    ->                else 0 end
    ->     where items.id=new.item_id ;
    -> end$$
Query OK, 0 rows affected (0.12 sec)

mysql> delimiter ;
mysql>

[collapsed title=Spoiler: Hasil Test INSERT Transaksi Barang Masuk dan Barang Keluar]

Test INSERT data transaksi barang masuk.

mysql> -----------------------------
mysql> -- insert header transaksi barang masuk
mysql> -----------------------------
mysql> insert into transactions (type_id, trans_code, trans_date, remarks)
    -> values (1, 'BM.00001/2014', '2014-01-10', 'Penerimaan Barang') ;
Query OK, 1 row affected (0.05 sec)

mysql> -----------------------------
mysql> -- lihat data transaksi
mysql> -- pastikan data sudah masuk
mysql> -----------------------------
mysql> select * from transactions;
+----+---------+---------------+------------+-------------------+
| id | type_id | trans_code    | trans_date | remarks           |
+----+---------+---------------+------------+-------------------+
|  1 |       1 | BM.00001/2014 | 2014-01-10 | Penerimaan Barang |
+----+---------+---------------+------------+-------------------+
1 row in set (0.00 sec)

mysql> -----------------------------
mysql> -- insert detail transaksi barang masuk
mysql> -----------------------------
mysql> insert into transaction_details (trans_id, item_id, quantity, remarks)
    -> values (1, 1, 20, 'Penerimaan Barang 1')
    ->      , (1, 2, 30, 'Penerimaan Barang 2')
    ->      , (1, 3, 10, 'Penerimaan Barang 3')
    ->      , (1, 4, 15, 'Penerimaan Barang 4') ;
Query OK, 4 rows affected (0.07 sec)
Records: 4  Duplicates: 0  Warnings: 0

mysql> -----------------------------
mysql> -- lihat detail transaksi
mysql> -- pastikan data sudah masuk
mysql> -----------------------------
mysql> select * from transaction_details where trans_id=1 ;
+----+----------+---------+----------+---------------------+
| id | trans_id | item_id | quantity | remarks             |
+----+----------+---------+----------+---------------------+
| 22 |        1 |       1 |       20 | Penerimaan Barang 1 |
| 23 |        1 |       2 |       30 | Penerimaan Barang 2 |
| 24 |        1 |       3 |       10 | Penerimaan Barang 3 |
| 25 |        1 |       4 |       15 | Penerimaan Barang 4 |
+----+----------+---------+----------+---------------------+
4 rows in set (0.00 sec)

mysql> -----------------------------
mysql> -- dengan asumsi awal semua stok barang masih kosong
mysql> -- maka saat ini quantity on hand pasti sudah berubah
mysql> -----------------------------
mysql> select * from items ;
+----+--------+-------------------------+------------------+---------+
| id | code   | name                    | quantity_on_hand | remarks |
+----+--------+-------------------------+------------------+---------+
|  1 | PC.001 | PC Jangkrik Tipe 1      |            20.00 | NULL    |
|  2 | PC.002 | PC Jangkrik Tipe 2      |            30.00 | NULL    |
|  3 | SV.001 | Server Rainer Tipe 1    |            10.00 | NULL    |
|  4 | SV.002 | Server Rainer Rackmount |            15.00 | NULL    |
+----+--------+-------------------------+------------------+---------+
4 rows in set (0.00 sec)

mysql> -----------------------------
mysql> -- YAY!!! Berhasil!!!
mysql> -----------------------------
mysql> 

Test INSERT data transaksi barang keluar.

mysql> -----------------------------
mysql> -- insert header transaksi barang keluar
mysql> -----------------------------
mysql> insert into transactions (type_id, trans_code, trans_date, remarks)
    -> values (2, 'BK.00001/2014', '2014-01-11', 'Pengeluaran Barang') ;
Query OK, 1 row affected (0.05 sec)

mysql> -----------------------------
mysql> -- lihat data transaksi
mysql> -- pastikan data sudah masuk
mysql> -----------------------------
mysql> select * from transactions ;
+----+---------+---------------+------------+--------------------+
| id | type_id | trans_code    | trans_date | remarks            |
+----+---------+---------------+------------+--------------------+
|  1 |       1 | BM.00001/2014 | 2014-01-10 | Penerimaan Barang  |
|  2 |       2 | BK.00001/2014 | 2014-01-11 | Pengeluaran Barang |
+----+---------+---------------+------------+--------------------+
2 rows in set (0.00 sec)

mysql> -----------------------------
mysql> -- insert detail transaksi barang keluar
mysql> -----------------------------
mysql> insert into transaction_details (trans_id, item_id, quantity, remarks)
    -> values (2, 1, 4, 'Pengeluaran Barang 1')
    ->      , (2, 4, 5, 'Pengeluaran Barang 4') ;
Query OK, 2 rows affected (0.07 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> -----------------------------
mysql> -- lihat detail transaksi
mysql> -- pastikan data sudah masuk
mysql> -----------------------------
mysql> select * from transaction_details where trans_id=2 ;
+----+----------+---------+----------+----------------------+
| id | trans_id | item_id | quantity | remarks              |
+----+----------+---------+----------+----------------------+
| 29 |        2 |       1 |        4 | Pengeluaran Barang 1 |
| 30 |        2 |       4 |        5 | Pengeluaran Barang 4 |
+----+----------+---------+----------+----------------------+
2 rows in set (0.00 sec)

mysql> -----------------------------
mysql> -- dengan asumsi awal semua stok barang masih kosong
mysql> -- maka saat ini quantity on hand pasti sudah berubah
mysql> -- item_id=1 yang semula 20, dikurangi 4 menjadi 16
mysql> -- item_id=4 yang semula 15, dikurangi 5 menjadi 10
mysql> -----------------------------
mysql> select * from items ;
+----+--------+-------------------------+------------------+---------+
| id | code   | name                    | quantity_on_hand | remarks |
+----+--------+-------------------------+------------------+---------+
|  1 | PC.001 | PC Jangkrik Tipe 1      |            16.00 | NULL    |
|  2 | PC.002 | PC Jangkrik Tipe 2      |            30.00 | NULL    |
|  3 | SV.001 | Server Rainer Tipe 1    |            10.00 | NULL    |
|  4 | SV.002 | Server Rainer Rackmount |            10.00 | NULL    |
+----+--------+-------------------------+------------------+---------+
4 rows in set (0.00 sec)

mysql> -----------------------------
mysql> -- YAY!!! Berhasil Lagi!!!
mysql> -----------------------------
mysql>

[/collapsed]

UPDATE (Edit) Data Transaksi

Untuk proses UPDATE, sama seperti proses INSERT dan DELETE, trigger akan berjalan FOR EACH ROW, namun sedikit lebih rumit, row ebelum proses update, atau data original tersimpan di variable OLD, dan row yang baru tersimpan di variable NEW. Logikanya adalah seperti ini,
  • Setiap kali ada update data transaksi barang masuk, maka field stok barang di table items akan kita kurangi dengan kuantitas lama kemudian kita tambahkan dengan kuantitas yang baru
  • Sebaliknya, setiap kali ada update data transaksi barang keluar, maka field stok barang di table items akan kita tambahkan dengan kuantitas lama kemudian kita kurangi dengan kuantitas yang baru,

maka trigger UPDATE akan seperti ini,

mysql> delimiter $$
mysql>

mysql> drop trigger if exists trg_transaction_details_after_update$$
Query OK, 0 rows affected (0.06 sec)

mysql> -- -----------------------------
mysql> -- after update trigger
mysql> -- -----------------------------
mysql> create trigger trg_transaction_details_after_update
    -> after update on transaction_details
    -> for each row
    -> begin
    ->   -- -----------------------------
    ->   -- ambil jenis transaksi
    ->   -- -----------------------------
    ->   declare tipe varchar(20);
    ->   set tipe = (
    ->     select tt.code
    ->       from transactions tr
    ->       join transaction_types tt on tr.type_id=tt.id
    ->       where tr.id=old.trans_id
    ->   ) ;
    ->   -- -----------------------------
    ->   -- update sesuai jenis transaksi
    ->   -- => kurangi dengan old quantity
    ->   -- -----------------------------
    ->   update items
    ->     set quantity_on_hand
    ->         = quantity_on_hand
    ->         + case when tipe='IN' then -old.quantity
    ->                when tipe='OUT' then old.quantity
    ->                else 0 end
    ->     where items.id=old.item_id ;
    ->   -- -----------------------------
    ->   -- update sesuai jenis transaksi
    ->   -- => tambahkan dengan new quantity
    ->   -- -----------------------------
    ->   update items
    ->     set quantity_on_hand
    ->         = quantity_on_hand
    ->         + case when tipe='IN' then new.quantity
    ->                when tipe='OUT' then -new.quantity
    ->                else 0 end
    ->     where items.id=new.item_id ;
    -> end$$
Query OK, 0 rows affected (0.14 sec)

mysql> delimiter ;
mysql>

[collapsed title=Spoiler: Hasil Test UPDATE Transaksi Barang Masuk dan Barang Keluar]

Status data sebelum Test UPDATE.

mysql> -----------------------------
mysql> -- status stok 
mysql> -- sebelum proses UPDATE
mysql> -----------------------------
mysql> select * from items;
+----+--------+-------------------------+------------------+---------+
| id | code   | name                    | quantity_on_hand | remarks |
+----+--------+-------------------------+------------------+---------+
|  1 | PC.001 | PC Jangkrik Tipe 1      |            16.00 | NULL    |
|  2 | PC.002 | PC Jangkrik Tipe 2      |            30.00 | NULL    |
|  3 | SV.001 | Server Rainer Tipe 1    |            10.00 | NULL    |
|  4 | SV.002 | Server Rainer Rackmount |            10.00 | NULL    |
+----+--------+-------------------------+------------------+---------+
4 rows in set (0.00 sec)

mysql> -----------------------------
mysql> -- status detil transaksi
mysql> -- sebelum proses UPDATE
mysql> -----------------------------
mysql> select * from transaction_details ;
+----+----------+---------+----------+----------------------+
| id | trans_id | item_id | quantity | remarks              |
+----+----------+---------+----------+----------------------+
| 22 |        1 |       1 |       20 | Penerimaan Barang 1  |
| 23 |        1 |       2 |       30 | Penerimaan Barang 2  |
| 24 |        1 |       3 |       10 | Penerimaan Barang 3  |
| 25 |        1 |       4 |       15 | Penerimaan Barang 4  |
| 29 |        2 |       1 |        4 | Pengeluaran Barang 1 |
| 30 |        2 |       4 |        5 | Pengeluaran Barang 4 |
+----+----------+---------+----------+----------------------+
6 rows in set (0.00 sec)

Test UPDATE data transaksi barang masuk.

mysql> -----------------------------
mysql> -- ubah detil transaksi masuk
mysql> -- untuk id transaksi 22,
mysql> -- dari quantity awal 20 menjadi 50
mysql> -----------------------------
mysql> update transaction_details
    -> set quantity = 50
    -> where id = 22 ;
Query OK, 1 row affected (0.07 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> -----------------------------
mysql> -- maka untuk item_id 1 (dari transaction detail id 22)
mysql> -- ada update quantity dari 20 menjadi 50 ada selisih +30
mysql> -- maka stok barang berubah, 16 -20 +30 = 46
mysql> -----------------------------
mysql> select * from items ;
+----+--------+-------------------------+------------------+---------+
| id | code   | name                    | quantity_on_hand | remarks |
+----+--------+-------------------------+------------------+---------+
|  1 | PC.001 | PC Jangkrik Tipe 1      |            46.00 | NULL    |
|  2 | PC.002 | PC Jangkrik Tipe 2      |            30.00 | NULL    |
|  3 | SV.001 | Server Rainer Tipe 1    |            10.00 | NULL    |
|  4 | SV.002 | Server Rainer Rackmount |            10.00 | NULL    |
+----+--------+-------------------------+------------------+---------+
4 rows in set (0.00 sec)
Query OK, 0 rows affected (0.04 sec)

mysql> -----------------------------
mysql> -- YAY!!! Sukses!!!
mysql> -----------------------------
mysql> 

Test UPDATE data transaksi barang keluar.

mysql> -----------------------------
mysql> -- ubah detil transaksi keluar
mysql> -- untuk id transaksi 29,
mysql> -- dari quantity awal 4 menjadi 25
mysql> -----------------------------
mysql> update transaction_details
    -> set quantity = 25
    -> where id = 29 ;
Query OK, 1 row affected (0.07 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> -----------------------------
mysql> -- maka untuk item_id 1 (dari transaction detail id 29)
mysql> -- ada update quantity keluar dari 4 menjadi 25 ada selisih 21
mysql> -- dari transaksi sebelumnya saldo akhir item_id 1 adalah 46
mysql> -- maka saldo stok barang berubah, 46 +4 -25 = 25
mysql> -----------------------------
mysql> select * from items ;
+----+--------+-------------------------+------------------+---------+
| id | code   | name                    | quantity_on_hand | remarks |
+----+--------+-------------------------+------------------+---------+
|  1 | PC.001 | PC Jangkrik Tipe 1      |            25.00 | NULL    |
|  2 | PC.002 | PC Jangkrik Tipe 2      |            30.00 | NULL    |
|  3 | SV.001 | Server Rainer Tipe 1    |            10.00 | NULL    |
|  4 | SV.002 | Server Rainer Rackmount |            10.00 | NULL    |
+----+--------+-------------------------+------------------+---------+
4 rows in set (0.00 sec)

mysql> -----------------------------
mysql> -- YAY!!! Awesome!!!
mysql> -----------------------------
mysql> 

[/collapsed]

DELETE Data Transaksi

Untuk proses DELETE, sama seperti proses INSERT, trigger akan berjalan FOR EACH ROW, namun row yang sedang kita hapus ada di variable OLD. Logikanya adalah seperti ini,
  • Setiap kali ada penghapusan data transaksi barang masuk, maka field stok barang di table items akan kita kurangi
  • Sebaliknya, setiap kali ada penghapusan data transaksi barang keluar, maka field stok barang di table items akan kita tambahkan,

maka trigger DELETE akan seperti ini,

mysql> delimiter $$

mysql> drop trigger if exists trg_transaction_details_after_delete$$
Query OK, 0 rows affected (0.06 sec)

mysql> -- -----------------------------
mysql> -- after delete trigger
mysql> -- -----------------------------
mysql> create trigger trg_transaction_details_after_delete
    -> after delete on transaction_details
    -> for each row
    -> begin
    ->   -- -----------------------------
    ->   -- ambil jenis transaksi
    ->   -- -----------------------------
    ->   declare tipe varchar(20);
    ->   set tipe = (
    ->     select tt.code
    ->       from transactions tr
    ->       join transaction_types tt on tr.type_id=tt.id
    ->       where tr.id=old.trans_id
    ->   ) ;
    ->   -- -----------------------------
    ->   -- update sesuai jenis transaksi
    ->   -- -----------------------------
    ->   update items
    ->     set quantity_on_hand
    ->         = quantity_on_hand
    ->         + case when tipe='IN' then -old.quantity
    ->                when tipe='OUT' then old.quantity
    ->                else 0 end
    ->     where items.id=old.item_id ;
    -> end$$
Query OK, 0 rows affected (0.23 sec)

mysql> delimiter ;
mysql>

[collapsed title=Spoiler: Hasil Test DELETE Transaksi Barang Masuk dan Barang Keluar]

Status database sebelum proses DELETE.

mysql> ----------------------------
mysql> -- status stok 
mysql> -- sebelum proses DELETE
mysql> -----------------------------
mysql> select * from items ;
+----+--------+-------------------------+------------------+---------+
| id | code   | name                    | quantity_on_hand | remarks |
+----+--------+-------------------------+------------------+---------+
|  1 | PC.001 | PC Jangkrik Tipe 1      |            25.00 | NULL    |
|  2 | PC.002 | PC Jangkrik Tipe 2      |            30.00 | NULL    |
|  3 | SV.001 | Server Rainer Tipe 1    |            10.00 | NULL    |
|  4 | SV.002 | Server Rainer Rackmount |            10.00 | NULL    |
+----+--------+-------------------------+------------------+---------+
4 rows in set (0.00 sec)

mysql> -----------------------------
mysql> -- status detil transaksi
mysql> -- sebelum proses DELETE
mysql> -----------------------------
mysql> select * from transaction_details;
+----+----------+---------+----------+----------------------+
| id | trans_id | item_id | quantity | remarks              |
+----+----------+---------+----------+----------------------+
| 22 |        1 |       1 |       50 | Penerimaan Barang 1  |
| 23 |        1 |       2 |       30 | Penerimaan Barang 2  |
| 24 |        1 |       3 |       10 | Penerimaan Barang 3  |
| 25 |        1 |       4 |       15 | Penerimaan Barang 4  |
| 29 |        2 |       1 |       25 | Pengeluaran Barang 1 |
| 30 |        2 |       4 |        5 | Pengeluaran Barang 4 |
+----+----------+---------+----------+----------------------+
6 rows in set (0.00 sec)

Test DELETE data transaksi.

Untuk test delete, kita lakukan sederhanan saja, yaitu hapus semua data transactions_details sehingga seluruh data transaksi akaterhapus, maka status stok seharusnya berubah menjadi seperti awal lagi yaitu seluruh saldo stok bernilai 0 (nol)

mysql> -----------------------------
mysql> -- hapus detil transaksi
mysql> -----------------------------
mysql> delete from transaction_details ;
Query OK, 4 rows affected (0.03 sec)

mysql> -----------------------------
mysql> -- pastikan table detil transaksi kososng
mysql> -----------------------------
mysql> select * from transaction_details;
Empty set (0.00 sec)

mysql> -----------------------------
mysql> -- status saldo stok kembali nol
mysql> -----------------------------
mysql> select * from items;
+----+--------+-------------------------+------------------+---------+
| id | code   | name                    | quantity_on_hand | remarks |
+----+--------+-------------------------+------------------+---------+
|  1 | PC.001 | PC Jangkrik Tipe 1      |             0.00 | NULL    |
|  2 | PC.002 | PC Jangkrik Tipe 2      |             0.00 | NULL    |
|  3 | SV.001 | Server Rainer Tipe 1    |             0.00 | NULL    |
|  4 | SV.002 | Server Rainer Rackmount |             0.00 | NULL    |
+----+--------+-------------------------+------------------+---------+
4 rows in set (0.00 sec)

mysql> -----------------------------
mysql> -- YAY!!! I'm Invincible!!!
mysql> -----------------------------
mysql> 

[/collapsed]

[collapsed title=Spoiler: Source Code Trigger Lengkap]

delimiter $$

drop trigger if exists trg_transaction_details_after_insert$$
-- -----------------------------
-- after insert trigger
-- -----------------------------
create trigger trg_transaction_details_after_insert
after insert on transaction_details
for each row
begin
  -- -----------------------------
  -- ambil jenis transaksi
  -- -----------------------------
  declare tipe varchar(20);
  set tipe = (
    select tt.code
      from transactions tr
      join transaction_types tt on tr.type_id=tt.id
      where tr.id=new.trans_id
  ) ;
  -- -----------------------------
  -- update sesuai jenis transaksi
  -- -----------------------------
  update items
    set quantity_on_hand
        = quantity_on_hand
        + case when tipe='IN' then new.quantity
               when tipe='OUT' then -new.quantity
               else 0 end
    where items.id=new.item_id ;
end$$
 
drop trigger if exists trg_transaction_details_after_update$$
-- -----------------------------
-- after update trigger
-- -----------------------------
create trigger trg_transaction_details_after_update
after update on transaction_details
for each row
begin
  -- -----------------------------
  -- ambil jenis transaksi
  -- -----------------------------
  declare tipe varchar(20);
  set tipe = (
    select tt.code
      from transactions tr
      join transaction_types tt on tr.type_id=tt.id
      where tr.id=old.trans_id
  ) ;
  -- -----------------------------
  -- update sesuai jenis transaksi
  -- => kurangi dengan old quantity
  -- -----------------------------
  update items
    set quantity_on_hand
        = quantity_on_hand
        + case when tipe='IN' then -old.quantity
               when tipe='OUT' then old.quantity
               else 0 end
    where items.id=old.item_id ;
  -- -----------------------------
  -- update sesuai jenis transaksi
  -- => tambahkan dengan new quantity
  -- -----------------------------
  update items
    set quantity_on_hand
        = quantity_on_hand
        + case when tipe='IN' then new.quantity
               when tipe='OUT' then -new.quantity
               else 0 end
    where items.id=new.item_id ;
end$$
 
drop trigger if exists trg_transaction_details_after_delete$$
-- -----------------------------
-- after delete trigger
-- -----------------------------
create trigger trg_transaction_details_after_delete
after delete on transaction_details
for each row
begin
  -- -----------------------------
  -- ambil jenis transaksi
  -- -----------------------------
  declare tipe varchar(20);
  set tipe = (
    select tt.code
      from transactions tr
      join transaction_types tt on tr.type_id=tt.id
      where tr.id=old.trans_id
  ) ;
  -- -----------------------------
  -- update sesuai jenis transaksi
  -- -----------------------------
  update items
    set quantity_on_hand
        = quantity_on_hand
        + case when tipe='IN' then -old.quantity
               when tipe='OUT' then old.quantity
               else 0 end
    where items.id=old.item_id ;
end$$
 
delimiter ;

[/collapsed]

Simpulan

Setelah kita perhatikan hasil test di atas, maka proses pengerjaan coding di aplikasi akan jauh lebih mudah karena tidak perlu lagi memikirkan code untuk mengubah status stok barang, karena perubahan status stok barang seluruhnya sudah ditangani oleh trigger yang kita buat ini.

Salam PojokProgrammer

^_^

Belajar SQL: Perhitungan Stok dan Harga Rata-Rata Barang untuk Aplikasi Inventory

Perhitungan Stok dan Harga Rata-Rata Barang untuk Aplikasi Inventory Satu Perintah Single SQL Statement

Belajar SQL | Semua programmer atau software developer aplikasi perkantoran pasti pernah menggunakan SQL. minimal untuk proses CRUD (Create, Read, Update, Delete) sederhana. Namun hanya sedikit yang memanfaatkan SQL untuk proses perhitungan rumit seperti penggajian, perhitungan average harga barang, status inventory, dan sebagainya hanya dengan menggunakan Single SQL Statement, alias dengan satu perintah SQL saja. Beberapa waktu lalu saat diskusi online dengan kawan-kawan di Facebook, saya tergelitik untuk membuat contoh SQL beraksi untuk menghitung nilai stok dan harga rata-rata barang setelah terjadi proses keluar masuk barang pada bulan tertentu. Contoh kasusnya adalah seperti ini…..

Di Ketahui ;

QOB := 1.670,28 Kg ( Opening Balance )
vOB := Rp. 8.397.476,7 ( Value Opening Balance 

Akumulasi selama 1 bulan dari pembelian ( Harus Proses seluruh transaksi masuk )
SQB := 1.600,Kg ( Supply quantity Barang )
vSQB := Rp. 8.825.600 ( Value Quantity Barang )

Akumulasi pemakain material selam 1 bulan ( Harus Proses seluruh Transaksi Keluar )
uQB := 973,83 ( Used Quantity Balance )

Di Tanya ;

vuQB : …..?? ( Value used Quatity Balance )
SAB : …… ( Saldo akhir balance )
vSAB : ……..( Value saldo akhir balance )

Jawab ;

Average Bahan Baku := (( vSQB+vOB) / (QOB+SQB) )
vuQB := uQB * average bahan baku 
SAB := (( QOB+SQB)-UQB)
vSAB := SAB * average bahan baku

Ketika kita berinteraksi dengan database, maka ada Golden Rule yang harus selalu dipegang. Golden Rule ini disampaikan oleh Tom Kyte, Evangelist Oracle, dalam salah satu artikel di blog-nya

  1. Sebisa mungkin, selalu gunakan satu perintah SQL.
  2. Jika tidak bisa dalam satu perintah SQL, maka gunakan Stored Procedure
  3. Jika tidak bisa menggunakan Stored Procedure, lakukan di aplikasi kita
  4. Jika masih tidak bisa juga, mungkin kita perlu memikirkan masak-masak, sebenarnya perlu gak sih kita lakukan hal ini? 🙂

Untuk itu saya akan coba menyelesaikan problem di atas hanya menggunakan satu perintah SQL saja. Namun saya akan jelaskan langkah-demi-langkah dalam membangun "satu perintah SQL" tersebut, agar teman-teman bisa memahami algoritma dan logika yang ada di dalamnya. Untuk kasus ini saya akan menggunakan PostgreSQL untuk menyelesaikannya, namun hasil akhir adalah perintah SQL standar yang bisa digunakan di RDBMS lain. Mari kita mulai dengan membuka command line PostgreSQL ………………..

C:\Program Files\PostgreSQL\9.3\bin>psql -U postgres -d inventory
psql (9.3.1)
WARNING: Console code page (850) differs from Windows code page (1252)
         8-bit characters might not work correctly. See psql reference
         page "Notes for Windows users" for details.
Type "help" for help.

Untuk menyelesaikan kasus di atas kita memerlukan beberapa buah table, yaitu

  • table items untuk menampung data master barang.
  • table item_balances untuk menampung data saldo awal bulanan tiap-tiap barang.
  • table transactions untuk mencatat transaksi harian, keluar dan masuk barang.

Pertama-tama kita buat struktur table items.

inventory=# -- -----------------------
inventory=# -- buat table items
inventory=# -- -----------------------
inventory=# create table items (
inventory(#   id serial primary key,
inventory(#   code varchar(20) not null,
inventory(#   name varchar(200) null
inventory(# ) ;
CREATE TABLE

Kemudian isikan beberapa data menggunakan perintah insert into. dan tampilkan hasilnya untuk memastikan.

inventory=# -- -----------------------
inventory=# -- masukkan beberapa data
inventory=# -- -----------------------
inventory=# insert into items (code, name)
inventory-# select 'ITEM01', 'Barang Pertama' union all
inventory-# select 'ITEM02', 'Barang Kedua' union all
inventory-# select 'ITEM03', 'Barang Ketiga' 
inventory-# ;
INSERT 0 3

inventory=# -- -----------------------
inventory=# -- lihat hasilnya
inventory=# -- -----------------------
inventory=# select * from items 
inventory-# ;

 id |  code  |      name
----+--------+----------------
  1 | ITEM01 | Barang Pertama
  2 | ITEM02 | Barang Kedua
  3 | ITEM03 | Barang Ketiga
(3 rows)

Berikutnya kita siapkan table item_balances yang digunakan untuk menyimpan saldo awal dan harga barang setiap bulannya. untuk itu perlu field periode untuk identifikasi bulan.

inventory=# -- -----------------------
inventory=# -- buat table balance
inventory=# -- -----------------------
inventory=# create table item_balances (
inventory(#   id serial primary key,
inventory(#   item_id integer not null,
inventory(#   period date not null,
inventory(#   quantity numeric(15,2),
inventory(#   unit_price numeric(15,2),
inventory(#   foreign key (item_id) references items(id)
inventory(# ) ;
CREATE TABLE

Kemudian isikan beberapa data menggunakan perintah insert into. dan tampilkan hasilnya untuk memastikan.

inventory=# -- -----------------------
inventory=# -- masukkan beberapa data
inventory=# -- -----------------------
inventory=# insert into item_balances (item_id, period, quantity, unit_price)
inventory-# select 1, to_date('2013-12-01','YYYY-MM-DD'), 1600, 23125 union all
inventory-# select 2, to_date('2013-12-01','YYYY-MM-DD'), 1250, 13100 union all
inventory-# select 3, to_date('2013-12-01','YYYY-MM-DD'), 3250, 3100 
inventory-# ;
INSERT 0 3

inventory=# -- -----------------------
inventory=# -- lihat hasilnya
inventory=# -- -----------------------
inventory=# select * from item_balances 
inventory-# ;

 id | item_id |   period   | quantity | unit_price
----+---------+------------+----------+------------
  1 |       1 | 2013-12-01 |  1600.00 |   23125.00
  2 |       2 | 2013-12-01 |  1250.00 |   13100.00
  3 |       3 | 2013-12-01 |  3250.00 |    3100.00
(3 rows)

Karena desain database kita sudah mengikuti kaidah normalisasi, maka yang tersimpan di table item_balances hanya id barang saja, Untuk mengetahui nama barang bersangkutan, kita gunakan klausa JOIN seperti di bawah ini…

inventory=# -- -----------------------
inventory=# -- tambahkan klausa JOIN
inventory=# -- -----------------------
inventory=# select a.*, b.period, b.quantity, b.unit_price
inventory-# , b.quantity*b.unit_price as item_value
inventory-# from items a join item_balances b on a.id=b.item_id 
inventory-# ;

 id |  code  |      name      |   period   | quantity | unit_price |  item_value
----+--------+----------------+------------+----------+------------+---------------
  1 | ITEM01 | Barang Pertama | 2013-12-01 |  1600.00 |   23125.00 | 37000000.00
  2 | ITEM02 | Barang Kedua   | 2013-12-01 |  1250.00 |   13100.00 | 16375000.00
  3 | ITEM03 | Barang Ketiga  | 2013-12-01 |  3250.00 |    3100.00 | 10075000.00
(3 rows)

Sekarang buatkan table transactions untuk menampung data transaksi harian, meliputi transaksi masuk dan keluar. Untuk membedakan transaksi masuk atau keluar, kita sediakan satu field tx_type untuk membedakannya.

inventory=# -- -----------------------
inventory=# -- buat table transaksi
inventory=# -- -----------------------
inventory=# create table transactions (
inventory(#   id serial primary key,
inventory(#   item_id integer not null,
inventory(#   tx_date date not null,
inventory(#   tx_type varchar(10) not null,
inventory(#   quantity numeric(15,2),
inventory(#   unit_price numeric(15,2),
inventory(#   foreign key (item_id) references items(id)
inventory(# ) ;
CREATE TABLE

Kemudian isikan beberapa data menggunakan perintah insert into. dan tampilkan hasilnya untuk memastikan. Kita tambahkan klausa JOIN untuk mengetahui informasi lebih jelas tentang barang yang terlibat dalam transaksi yang kita masukkan

inventory=# -- -----------------------
inventory=# -- masukkan beberapa data
inventory=# -- -----------------------
inventory=# insert into transactions (item_id, tx_date, tx_type, quantity, unit_price)
inventory-# select 1, to_date('2013-12-10','YYYY-MM-DD'), 'IN', 100, 24125 union all
inventory-# select 1, to_date('2013-12-20','YYYY-MM-DD'), 'IN', 200, 25125 union all
inventory-# select 1, to_date('2013-12-05','YYYY-MM-DD'), 'OUT', 100, 0 union all
inventory-# select 1, to_date('2013-12-08','YYYY-MM-DD'), 'OUT', 200, 0 union all
inventory-# select 1, to_date('2013-12-18','YYYY-MM-DD'), 'OUT', 400, 0 union all
inventory-# select 2, to_date('2013-12-02','YYYY-MM-DD'), 'IN', 1000, 15125 union all
inventory-# select 2, to_date('2013-12-23','YYYY-MM-DD'), 'IN', 2000, 14100 union all
inventory-# select 2, to_date('2013-12-04','YYYY-MM-DD'), 'OUT', 1100, 0 union all
inventory-# select 2, to_date('2013-12-05','YYYY-MM-DD'), 'OUT', 1200, 0 union all
inventory-# select 2, to_date('2013-12-15','YYYY-MM-DD'), 'OUT', 400, 0 union all
inventory-# select 3, to_date('2013-12-12','YYYY-MM-DD'), 'IN', 1000, 3500 union all
inventory-# select 3, to_date('2013-12-24','YYYY-MM-DD'), 'IN', 2000, 3700 union all
inventory-# select 3, to_date('2013-12-04','YYYY-MM-DD'), 'OUT', 1100, 0 union all
inventory-# select 3, to_date('2013-12-15','YYYY-MM-DD'), 'OUT', 1200, 0 union all
inventory-# select 3, to_date('2013-12-25','YYYY-MM-DD'), 'OUT', 2400, 0 
inventory-# ;
INSERT 0 15

inventory=# -- -----------------------
inventory=# -- lihat hasilnya, pakai JOIN
inventory=# -- -----------------------
inventory=# select a.*, b.code, b.name
inventory-# from transactions a
inventory-# join items b on a.item_id=b.id
inventory-# order by tx_date, tx_type 
inventory-# ;

 id | item_id |  tx_date   | tx_type | quantity | unit_price |  code  |      name
----+---------+------------+---------+----------+------------+--------+----------------
  6 |       2 | 2013-12-02 | IN      |  1000.00 |   15125.00 | ITEM02 | Barang Kedua
  8 |       2 | 2013-12-04 | OUT     |  1100.00 |       0.00 | ITEM02 | Barang Kedua
 13 |       3 | 2013-12-04 | OUT     |  1100.00 |       0.00 | ITEM03 | Barang Ketiga
  3 |       1 | 2013-12-05 | OUT     |   100.00 |       0.00 | ITEM01 | Barang Pertama
  9 |       2 | 2013-12-05 | OUT     |  1200.00 |       0.00 | ITEM02 | Barang Kedua
  4 |       1 | 2013-12-08 | OUT     |   200.00 |       0.00 | ITEM01 | Barang Pertama
  1 |       1 | 2013-12-10 | IN      |   100.00 |   24125.00 | ITEM01 | Barang Pertama
 11 |       3 | 2013-12-12 | IN      |  1000.00 |    3500.00 | ITEM03 | Barang Ketiga
 14 |       3 | 2013-12-15 | OUT     |  1200.00 |       0.00 | ITEM03 | Barang Ketiga
 10 |       2 | 2013-12-15 | OUT     |   400.00 |       0.00 | ITEM02 | Barang Kedua
  5 |       1 | 2013-12-18 | OUT     |   400.00 |       0.00 | ITEM01 | Barang Pertama
  2 |       1 | 2013-12-20 | IN      |   200.00 |   25125.00 | ITEM01 | Barang Pertama
  7 |       2 | 2013-12-23 | IN      |  2000.00 |   14100.00 | ITEM02 | Barang Kedua
 12 |       3 | 2013-12-24 | IN      |  2000.00 |    3700.00 | ITEM03 | Barang Ketiga
 15 |       3 | 2013-12-25 | OUT     |  2400.00 |       0.00 | ITEM03 | Barang Ketiga
(15 rows)

Langkah berikutnya adalah membuat query untuk emnghitung summary transaksi. Kita akan menggunakan teknik crosstab untuk memindahkan row transaksi IN dan OUT menjadi kolom.

inventory=# -- -----------------------
inventory=# -- crosstab data transaksi
inventory=# -- -----------------------
inventory=# select item_id
inventory-# , date_trunc('month',tx_date) tx_date
inventory-# , sum(case when tx_type='IN' then quantity else 0 end) qty_in
inventory-# , sum(case when tx_type='IN' then quantity*unit_price else 0 end) value_in
inventory-# , sum(case when tx_type='OUT' then quantity else 0 end) qty_out
inventory-# from transactions
inventory-# group by item_id
inventory-# , date_trunc('month',tx_date) ;

 item_id |        tx_date         | qty_in  |   value_in    | qty_out
---------+------------------------+---------+---------------+---------
       2 | 2013-12-01 00:00:00+07 | 3000.00 | 43325000.0000 | 2700.00
       1 | 2013-12-01 00:00:00+07 |  300.00 |  7437500.0000 |  700.00
       3 | 2013-12-01 00:00:00+07 | 3000.00 | 10900000.0000 | 4700.00
(3 rows)

Terakhir…… lakukan JOIN terhadal table items, item_balance dan hasil crosstab transactions untuk proses perhitungan sesuai dengan rumus yang diberikan di bagian awal artikel ini.

inventory=# -- -----------------------
inventory=# -- perhitungan akhir
inventory=# -- -----------------------
inventory=# select it.id, it.code, it.name
inventory-# , bl.period, bl.quantity QOB, bl.unit_price Avg1
inventory-# , ( bl.quantity *bl.unit_price ) vOB
inventory-# , tx.qty_in SQB, tx.value_in vSQB, tx.qty_out uQB
inventory-# , ( (tx.value_in +bl.quantity *bl.unit_price) / (bl.quantity +tx.qty_in) ) Avg2
inventory-# , tx.qty_out
inventory-# * ( (tx.value_in+bl.quantity*bl.unit_price) / (bl.quantity +tx.qty_in) ) vuQB
inventory-# , ( bl.quantity +tx.qty_in ) -tx.qty_out SAB
inventory-# , ( (bl.quantity +tx.qty_in) -tx.qty_out )
inventory-# * ( (tx.value_in +bl.quantity *bl.unit_price) / (bl.quantity +tx.qty_in) ) vSAB
inventory-# from items it
inventory-# join item_balances bl on it.id = bl.item_id
inventory-# left join (
inventory(#   select item_id
inventory(#   , date_trunc('month',tx_date) tx_date
inventory(#   , sum(case when tx_type='IN' then quantity else 0 end) qty_in
inventory(#   , sum(case when tx_type='IN' then quantity*unit_price else 0 end) value_in
inventory(#   , sum(case when tx_type='OUT' then quantity else 0 end) qty_out
inventory(#   from transactions
inventory(#   group by item_id
inventory(#   , date_trunc('month',tx_date)
inventory(# ) tx
inventory-# on bl.item_id = tx.item_id
inventory-# and bl.period = tx.tx_date
inventory-# ;

 id |  code  |      name      |   period   |   qob   |   avg1   |     vob     |   sqb   |     vsqb    |   uqb   |   avg2   |    vuqb     |   sab   |   vsab
----+--------+----------------+------------+---------+----------+-------------+---------+-------------+---------+----------+-------------+---------+-------------
  1 | ITEM01 | Barang Pertama | 2013-12-01 | 1600.00 | 23125.00 | 37000000.00 |  300.00 |  7437500.00 |  700.00 | 23388.16 | 16371712.00 | 1200.00 | 28065792.00
  2 | ITEM02 | Barang Kedua   | 2013-12-01 | 1250.00 | 13100.00 | 16375000.00 | 3000.00 | 43325000.00 | 2700.00 | 14047.06 | 37927062.00 | 1550.00 | 21772943.00
  3 | ITEM03 | Barang Ketiga  | 2013-12-01 | 3250.00 |  3100.00 | 10075000.00 | 3000.00 | 10900000.00 | 4700.00 |  3356.00 | 15773200.00 | 1550.00 |  5201800.00
(3 rows)

BERHASIL!!!!!!

Kita berhasil membuat satu perintah SQL untuk perhitungan status stok akhir bulan dan menghitung harga rata-ratanya. hasil dari perintah SQL ini sudah matang, sehingga aplikasi kita – PHP atau VB.net atau lainnya – bisa langsung menampilkan hasilnya tanpa perlu melakukan proses perhitungan lagi……..

Semoga berguna….

^_^