SESI 08 : MENDESAIN NOTA KASIR #2
Assalamualaikum warahmatullohi wabarohatuh, salam sukses. Pada bagian ini
kita akan membuat atau merancang form untuk input penjualan kasir atau form
pos, untuk part atau bagian ke #2 ini kita akan membuat display nota
penjualan kasir yang kita interaktifkan dengan display ambil menu item
barang atau daftar menu barang yang dari part atau bagian #1 kemarin, adapun
video tutorialnya secara lengkap dan detailnya ada di sini:
Dalam pengaturan display nota pembayaran kasir ini kita akan membuat class
baru yaitu class PosCashier dan class PosGrid sebagai
pengontrol tampilan layarnya yang diatur dalam file kivy, berarti kita juga
membuat file kivy baru yaitu pos_cashir.kv dan pos_grid.kv, kita juga harus melakukan penyesuaian terhadap file
kivy menu.kv, pos_item.kv karena akan dipanggil juga
oleh class PosCashier ini, selain itu kita juga harus melakukan penyesuaian di
class utama yaitu class MyResto. Selain itu kita juga harus
membuat tabel baru ntuk menyimpan data data penjualannya, baik untuk rancangan
tampilan dan source scrip mengenai perubahan-perubahan secara lengkap
kita jabarkan di bawah ini.
Rancangan display nota kasir dibagi dalam 6 (enam) bagian yaitu:
01. Judul Nota |
|
02. Kop Nota |
|
03. Header Rincian Barang |
|
04. Detail Rincian Barang |
|
05. Subtotal
Penjualan |
|
06. Tombol Menu-menu |
Modul atau library python baru yang dibutuhkan adalah : import datetime yaitu untuk pengoperasian tanggal dan waktu, tapi disini nanti yang
kita butuhkan atau yang kita pakai hanyalah untuk menampilkan tanggal hari
ini.
Tabel baru yang harus dibuat untuk menyimpan data penjualan adalah
jual_nota dan jual_barang, disini kita harus merubah fungsi atau
metod buat_database menjadi:
def buat_database():
conn = sqlite3.connect("data_resto.db")
mycursor = conn.cursor()
try:
mycursor.execute("select * from barang ")
except:
queri = "CREATE TABLE IF NOT EXISTS barang("\
"kode INTEGER PRIMARY KEY AUTOINCREMENT,"\
"jenis TEXT DEFAULT '',"\
"nama TEXT DEFAULT '',"\
"harga INTEGER DEFAULT 0,"\
"gambar TEXT DEFAULT '',"\
"status TEXT DEFAULT '') "
mycursor.execute(queri)
conn.commit()
# tabel untuk rekap nota jual
jualnota = "CREATE TABLE IF NOT EXISTS jual_nota("\
"nojual TEXT DEFAULT '',"\
"tanggal TEXT DEFAULT '',"\
"meja TEXT DEFAULT '',"\
"item INTEGER DEFAULT 0,"\
"jumlah INTEGER DEFAULT 0,"\
"bayar INTEGER DEFAULT 0,"\
"sisa INTEGER DEFAULT 0,"\
"kasir TEXT DEFAULT '') "
mycursor.execute(jualnota)
conn.commit()
# tabel untuk rincian barang nota
jualbrg = "CREATE TABLE IF NOT EXISTS jual_barang("\
"nojual TEXT DEFAULT '',"\
"kode INTEGER DEFAULT 0,"\
"qty INTEGER DEFAULT 0,"\
"harga INTEGER DEFAULT 0,"\
"jumlah INTEGER DEFAULT 0 ) "
mycursor.execute(jualbrg)
conn.commit()
conn.close()
Class baru yang kita buat adalah class PosCashier source
codenya:
class PosCashier(Screen):
notajual = StringProperty ("")
def on_enter(self):
self.ids.notagrid.clear_widgets()
self.tampil_barang()
return self
def tampil_barang(self):
carinojual = '*' if self.notajual.strip()=='' else self.notajual.strip()
conn = sqlite3.connect('data_resto.db')
conn.row_factory = sqlite3.Row
cur = conn.cursor()
# baca rincian barang
sql = "SELECT x.*,y.nama "\
"FROM jual_barang x "\
"INNER JOIN barang y on x.kode=y.kode "\
"WHERE x.nojual='"+carinojual+"' "
cur.execute(sql)
jual_barang = cur.fetchall()
# baca rekap nota
sql = "SELECT * FROM jual_nota WHERE nojual='"+carinojual+"' "
cur.execute(sql)
jual_nota = cur.fetchall()
conn.commit()
conn.close()
if len(jual_nota)==0 :
bayar = 0
self.ids.notabaru.text='(*)'
self.ids.notanomor.text = ''
self.ids.notatanggal.text = ''
self.ids.notameja.text = ''
else:
bayar = jual_nota[0]['bayar']
self.ids.notabaru.text=''
self.ids.notanomor.text = jual_nota[0]['nojual']
self.ids.notatanggal.text = jual_nota[0]['tanggal']
self.ids.notameja.text = jual_nota[0]['meja']
total = 0
for record in jual_barang:
itemjual=PosGrid()
itemjual.nama = record['nama']
itemjual.harga = str(record['qty']) +" x "+ str(record['harga'])
itemjual.jumlah = str(record['jumlah'])
total = total + record['jumlah']
self.ids.notagrid.add_widget(itemjual)
sisa = 0 if total>bayar else bayar-total
self.ids.notajumlah.text = str(total)
self.ids.notabayar.text = str(bayar)
self.ids.notasisa.text = str(sisa)
return self
def additem(self):
dibayar = 0 if self.ids.notabayar.text.strip()=='' else int(self.ids.notabayar.text)
if self.ids.notanomor.text.strip()=='' or self.ids.notameja.text.strip()=='' or dibayar>0 :
tombol_no = MDFlatButton(text="canc", on_release=lambda x:self.dialog.dismiss())
self.dialog = MDDialog(title="Info",
text='Maaf Nomor jual/meja belum diisikan atau sudah dibayar ',
radius=[20, 7, 20, 7],
buttons=[tombol_no])
self.dialog.open()
else:
# kalau data baru simpan nomor jual
if self.ids.notabaru.text.strip()=='(*)':
xnojual = self.ids.notanomor.text
xtanggal= self.ids.notatanggal.text
xmeja = self.ids.notameja.text
conn = sqlite3.connect('data_resto.db')
conn.row_factory = sqlite3.Row
cur = conn.cursor()
cur.execute("INSERT INTO jual_nota (nojual,tanggal,meja) VALUES (?,?,?)",(xnojual,xtanggal,xmeja))
conn.commit()
conn.close()
PosItem.notajual=self.ids.notanomor.text
self.manager.transition.direction = 'right'
self.manager.current = 'PosItem'
def baru(self):
self.ids.notagrid.clear_widgets()
self.ids.notatanggal.text=f"{datetime.date.today()}"
self.ids.notanomor.text = ''
self.ids.notameja.text=''
self.ids.notabaru.text='(*)'
self.ids.notajumlah.text=''
self.ids.notabayar.text=''
self.ids.notasisa.text=''
# cari nomor terakhir
conn = sqlite3.connect('data_resto.db')
conn.row_factory = sqlite3.Row
cur = conn.cursor()
cur.execute("SELECT max(nojual) as nojual FROM jual_nota ")
bacamota = cur.fetchall()
conn.commit()
conn.close()
nomorakhir = bacamota[0]['nojual']
if type(nomorakhir)!=str or nomorakhir=='None' or nomorakhir.strip()=='':
self.ids.notanomor.text = '00001'
else:
nobaru = '00000' + str(int(nomorakhir)+1)
self.ids.notanomor.text = nobaru[-5:]
Adapun file kivy baru sebagai penjabaran class PosCashier
yaitu: pos_cashir.kv
<PosCashier>:
# Judul layar
MDBoxLayout:
size_hint: .9,.05
pos_hint: {"x":.05, "y": .95}
md_bg_color: rgba(0, 250, 0, 150)
MDLabel:
text:'NOTA INVOICE'
font_size: '14dp'
bold: True
size_hint: .95,1
halign: 'center'
MDIconButton:
icon: "select-group"
icon_size: "20sp"
pos_hint:{'x':.95, 'center_y':.5}
on_release:
root.manager.transition.direction='right'
root.manager.current='MenuUtama'
MDLabel:
text:'Nomor Nota'
font_size: '12dp'
size_hint: .2,.1
pos_hint: {'x':.05,'y':.88}
MDTextField:
id:notanomor
font_size: '12dp'
size_hint: .25,.1
pos_hint: {"x":.25, "y": .88}
disabled: True
MDIconButton:
icon: "text-search"
pos_hint: {"x":.4, "y": .88}
on_release: root.cari_nota()
MDLabel:
text:'Tanggal'
font_size: '12dp'
size_hint: .2,.1
pos_hint: {'x':.55,'y':.88}
MDTextField:
id:notatanggal
font_size: '12dp'
size_hint: .25,.1
pos_hint: {"x":.7, "y": .88}
disabled: True
MDLabel:
text:'Meja ( a/n )'
font_size: '12dp'
size_hint: .2,.1
pos_hint: {'x':.05,'y':.83}
MDTextField:
id:notameja
font_size: '12dp'
size_hint: .25,.1
pos_hint: {"x":.25, "y": .83}
MDLabel:
id:notabaru
text:''
font_size: '12dp'
size_hint: .1,.1
pos_hint: {'x':.55,'y':.83}
# header
MDBoxLayout:
size_hint: .9,.05
pos_hint: {"x":.05, "y": .8}
line_color: rgba(180, 190, 180, 255)
md_bg_color: rgba(0, 250, 0, 150)
orientation: 'horizontal'
padding: 5
MDLabel:
text:'Nama Barang'
font_size: '12dp'
size_hint: .5,1
MDLabel:
text:'Harga'
font_size: '12dp'
size_hint: .25,1
MDLabel:
text:'Jumlah'
font_size: '12dp'
halign: 'right'
size_hint: .2,1
# rincian item
MDBoxLayout:
size_hint: .9,.6
pos_hint: {"x":.05, "y": .2}
line_color: rgba(180, 190, 180, 255)
padding: 5
ScrollView:
size_hint_x: self.size_hint_x
size_hint_y: self.size_hint_y
do_scroll_x: False
MDGridLayout:
id:notagrid
cols: 1
row_default_height: "30dp"
row_force_default: True
adaptive_height: True
# subtotal
MDBoxLayout:
size_hint: .9,.13
pos_hint: {"x":.05, "y": .07}
orientation: 'vertical'
MDBoxLayout:
MDLabel:
text:'Total:'
font_size: '12dp'
size_hint_x: .7
halign: 'right'
TextInput:
id:notajumlah
font_size: "12dp"
size_hint: .3,1
halign: 'right'
disabled: True
disabled_foreground_color: 0,0,0,1
background_disabled_normal: ''
MDBoxLayout:
MDLabel:
text:'Bayar:'
font_size: '12dp'
size_hint_x: .7
halign: 'right'
TextInput:
id:notabayar
font_size: "12dp"
size_hint: .3,1
halign: 'right'
disabled: True
disabled_foreground_color: 0,0,0,1
background_disabled_normal: ''
MDBoxLayout:
MDLabel:
text:'Sisa:'
font_size: '12dp'
size_hint_x: .7
halign: 'right'
TextInput:
id:notasisa
font_size: "12dp"
size_hint: .3,1
halign: 'right'
disabled: True
disabled_foreground_color: 0,0,0,1
background_disabled_normal: ''
# footer layar
MDBoxLayout:
size_hint: .9,.05
pos_hint: {"x":.05, "y": .0}
md_bg_color: rgba(0, 250, 0, 255)
MDRectangleFlatIconButton:
text: 'Print'
font_size: "11sp"
text_color: 0, 0, 1, 1
md_bg_color: rgba(0, 250, 0, 150)
icon: "printer-pos"
icon_color: rgba(0, 0, 255, 255)
size_hint: .25,1
MDRectangleFlatIconButton:
text: 'Baru'
font_size: "11sp"
text_color: 1, 1, 0, 1
md_bg_color: rgba(255, 0, 0, 150)
icon: "post-outline"
icon_color: rgba(255, 255, 0, 255)
size_hint: .25,1
on_release: root.baru()
MDRectangleFlatIconButton:
text: 'Bayar'
font_size: "11sp"
text_color: 0, 0, 0, 1
md_bg_color: rgba(255, 255, 0, 150)
icon: "cash-multiple"
icon_color: rgba(0, 0, 0, 255)
size_hint: .25,1
on_release: root.posbayar()
MDRectangleFlatIconButton:
text: 'Item'
font_size: "11sp"
text_color: 1, 1, 1, 1
md_bg_color: rgba(0, 0, 255, 150)
icon: "plus-circle"
size_hint: .25,1
icon_color: rgba(255, 255, 255, 255)
on_release: root.additem()
Class baru yang kita buat adalah class PosGrid source
codenya:
class PosGrid(MDBoxLayout):
nama = StringProperty ("Nama Item Food 00001")
harga = StringProperty ('25 x 10000')
jumlah = StringProperty ("250000")
Adapun file kivy baru sebagai penjabaran class PosGrid yaitu:
pos_grid.kv
<PosGrid>:
MDLabel:
text:root.nama
font_size: '12dp'
size_hint: .5,1
MDLabel:
text:root.harga
font_size: '12dp'
size_hint: .25,1
MDLabel:
text:root.jumlah
font_size: '12dp'
halign: 'right'
size_hint: .2,1
File kivi yang harus disempurnakan yaitu file menu.kv yang diubah khusus pada
button untuk menjalankan men pos :
MDBoxLayout:
size_hint: .4,.3
pos_hint: {'x':.05,'y':.5}
md_bg_color:rgba(0, 255, 255, 150)
radius: [10,10,10,10]
line_color: rgba(0, 0, 0, 255)
orientation: 'vertical'
padding: '10dp'
FitImage:
source: 'image/menu-pos.png'
MDRectangleFlatIconButton:
icon: "cart-variant"
text:'Poin Of Sales'
text_color: rgba(0, 0, 0, 255)
user_font_size: '20dp'
md_bg_color:rgba(255, 255, 0, 255)
size_hint_x: 1
pos_hint: {"center_x": .5}
on_release:
root.manager.transition.direction= 'left'
root.manager.current= 'PosCashier'
Class yang harus disesuaikan adalah class PosItem source codenya
menjadi:
class PosItem(Screen):
notajual = StringProperty ("*")
def on_pre_enter(self):
self.ids.gridtab01.clear_widgets()
self.ids.gridtab02.clear_widgets()
self.ids.gridtab03.clear_widgets()
self.tampil_barang()
return self
def tampil_barang(self):
conn = sqlite3.connect('data_resto.db')
conn.row_factory = sqlite3.Row
cur = conn.cursor()
carinojual = '*' if self.notajual.strip()=='' else self.notajual.strip()
sql = "SELECT x.kode,x.jenis,x.nama,x.harga,x.status,x.gambar,sum(iif(y.nojual=?, y.qty, 0)) as qty "\
"FROM barang x "\
"LEFT JOIN jual_barang y on x.kode=y.kode "\
"GROUP BY x.kode,x.jenis,x.nama,x.harga,x.status,x.gambar "\
"ORDER BY x.jenis "
cur.execute(sql,(carinojual,))
daftarbarang = cur.fetchall()
conn.commit()
conn.close()
for record in daftarbarang:
item=BarangItem()
item.nojual=self.notajual
item.bawaclass = 'MenuPos'
item.iconkiri="minus-circle"
item.iconkanan="plus-circle"
item.kode=str(record['kode'])
item.jenis='0' if self.notajual.strip()=='' else str(record['qty'])
item.nama=record['nama']
item.harga=str(record['harga'])
item.gambar=record['gambar']
item.status=record['status']
if record['jenis']=='1': self.ids.gridtab01.add_widget(item)
if record['jenis']=='2': self.ids.gridtab02.add_widget(item)
if record['jenis']=='3': self.ids.gridtab03.add_widget(item)
return self
def tekantab(self,tekan):
self.ids.tab01.color=180/255, 190/255, 180/255, 255/255
self.ids.tab02.color=180/255, 190/255, 180/255, 255/255
self.ids.tab03.color=180/255, 190/255, 180/255, 255/255
self.ids.tab01.font_size='14dp'
self.ids.tab02.font_size='14dp'
self.ids.tab03.font_size='14dp'
if tekan==1:
self.ids.tab01.color=1, 1, 1, 1
self.ids.tab01.font_size='18dp'
if tekan==2:
self.ids.tab02.color=1, 1, 1, 1
self.ids.tab02.font_size='18dp'
if tekan==3:
self.ids.tab03.color=1, 1, 1, 1
self.ids.tab03.font_size='18dp'
def done(self):
PosCashier.notajual=self.notajual
self.manager.transition.direction = 'left'
self.manager.current = 'PosCashier'
File kivi penjabarannya yaitu file pos_item.kv yang diubah khusus pada
button done:
MDRectangleFlatButton:
text: "Done"
font_size: '18dp'
valign: "center"
text_color: 1, 1, 1, 1
size_hint: 1,.05
md_bg_color: rgba(0, 0, 255, 255)
pos_hint: {'center_x': .5, 'y': .0}
on_release: root.done()
Terakhir class utama yaitu class MyResto perlu penyesuaian menjadi:
class MyResto(MDApp):
def build(self):
buat_database()
sm = ScreenManager()
sm.add_widget(MenuUtama(name='MenuUtama'))
sm.add_widget(MenuBarang(name='MenuBarang'))
sm.add_widget(BarangNew(name='BarangNew'))
sm.add_widget(StokBarang(name='StokBarang'))
sm.add_widget(PosItem(name='PosItem'))
sm.add_widget(PosCashier(name='PosCashier'))
return sm
def klik_ataskanan(self,bwkelas,bwkode,bwisi,bwnojual,bwharga):
if bwkelas=='MenuBarang':
BarangNew.datanew = 'edit'
BarangNew.datakode = bwkode
self.root.current = 'BarangNew'
return bwisi
elif bwkelas=='MenuPos':
nilai=0 if bwisi.strip()=='' else int(bwisi)
bwqty=nilai + 1
self.simpan_item_jual(bwnojual,bwkode,bwqty,bwharga)
return str(bwqty)
def klik_ataskiri(self,bwkelas,bwkode,bwisi,bwnojual,bwharga):
if bwkelas=='MenuBarang':
tombol_ok = MDFlatButton(text="OK", on_release=lambda x:self.hapus_barang(bwkode))
tombol_no = MDFlatButton(text="canc", on_release=lambda x:self.dialog.dismiss())
self.dialog = MDDialog(title="Konfirmasi",
text='Apakah anda yakin hapus..?',
radius=[20, 7, 20, 7],
buttons=[tombol_ok, tombol_no])
self.dialog.open()
return bwisi
elif bwkelas=='MenuPos':
nilai=0 if bwisi.strip()=='' else int(bwisi)
bwqty=nilai-1 if nilai>0 else 0
self.simpan_item_jual(bwnojual,bwkode,bwqty,bwharga)
return str(bwqty)
def simpan_item_jual(self,bwnojual,bwkode,bwqty,bwharga):
xnojual=bwnojual.strip()
xkode=0 if bwkode.strip()=='' else int(bwkode)
xharga=0 if bwharga.strip()=='' else int(bwharga)
xqty=bwqty
xjumlah=xqty * xharga
conn = sqlite3.connect('data_resto.db')
cur = conn.cursor()
# jika tidak jadi beli
if xqty<=0:
query_sql="DELETE FROM jual_barang WHERE kode=? and nojual=? "
query_isi=(xkode,xnojual)
else:
cur.execute("SELECT kode,nojual FROM jual_barang WHERE kode=? and nojual=?",(xkode,xnojual))
jualbarang = cur.fetchall()
if len(jualbarang)==0:
# berarti belum ada barang ini
query_sql="INSERT INTO jual_barang (nojual,kode,harga,qty,jumlah) VALUES (?,?,?,?,?) "
query_isi=(xnojual,xkode,xharga,xqty,xjumlah)
else:
query_sql="UPDATE jual_barang set qty=?,jumlah=? WHERE kode=? and nojual=? "
query_isi=(xqty,xjumlah,xkode,xnojual)
cur.execute(query_sql,query_isi)
conn.commit()
conn.close()
def hapus_barang(self,kode):
self.dialog.dismiss()
conn = sqlite3.connect('data_resto.db')
cur = conn.cursor()
cur.execute("DELETE FROM barang where kode='"+kode+"'")
conn.commit()
conn.close()
self.root.current = 'MenuUtama'
self.root.current = 'MenuBarang'
def ubahstok(self,bwkode,bwstatus):
if bwstatus=='kosong':
statusbaru='Ada'
else:
statusbaru='kosong'
conn = sqlite3.connect('data_resto.db')
cur = conn.cursor()
cur.execute("UPDATE barang set status=? where kode=?",(statusbaru,bwkode))
conn.commit()
conn.close()
return statusbaru
Demikian untuk pengaturan tampilan menu struk nota kasir ini, untuk kelanjutannya silahkan buka dipostingan berikutnya atau lihat video berikutnya, semoga bermanfaat terima kasih wassalamualaikum warohmatullohi wabarohatuh.
Komentar
Posting Komentar