Langsung ke konten utama

BELAJAR PYTHON : MENDESAIN NOTA KASIR #3 | APLIKASI KASIR POS ANDROID IOS MUDAH

 

SESI 09 : PEMBAYARAN NOTA KASIR #3

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 #3 ini kita akan membuat display pembayaran nota kasir dan pesanan, adapun video tutorialnya secara lengkap dan detailnya ada di sini:




Dalam pengaturan layar pembaaran nota kasir ini kita akan membuat class baru yaitu class PosBayar dan class PosList dengan jenis class popup, dan file kivy baru sebagai pengontrol tampilan layarnya yaitu pos_bayar.kv dan pos_list.kv, kita juga harus melakukan penyesuaian di class PosCashier dan file kivynya yaitu pos_cashier.kv, baik untuk rancangan tampilan dan source scrip mengenai  perubahan-perubahan secara lengkap kita jabarkan di bawah ini.

Class baru yang kita buat adalah class PosBayar source codenya: 

class PosBayar(Popup):
    bawajumlah = StringProperty ("")
    bawabayar = StringProperty ("")
    bawasisa = StringProperty ("")

    def on_pre_open(self):
        self.ids.nilaijual.text = self.bawajumlah
        self.ids.bayarjual.text = self.bawabayar
        self.ids.sisajual.text = self.bawasisa
    
    def bayar_batal(self):
        PosCashier.notabayar = ''
        PosCashier.notasisa =''
        self.dismiss()
    
    def bayar_simpan(self,bayar,sisa):
        PosCashier.notabayar = bayar
        PosCashier.notasisa = sisa
        self.dismiss() 
    
    def bayar_sisa(self):
        xnilai = 0 if self.ids.nilaijual.text.strip()=='' else int(self.ids.nilaijual.text.strip())
        xbayar = 0 if self.ids.bayarjual.text.strip()=='' else int(self.ids.bayarjual.text.strip())
        xsisa = 0 if xnilai>xbayar else xbayar-xnilai
        self.ids.sisajual.text = str(xsisa)


Adapun file kivy baru sebagai penjabaran class PosBayar yaitu: pos_bayar.kv :

<PosBayar>:
    title: "PEMBAYARAN"
    size_hint: .8, .5
    separator_color: 1, 1, 0, 1
    background_color: 0,0,1,1
    
    MDFloatLayout:
        size_hint: 1, .9
        pos_hint: {'center_x':.5, 'y':.05}
        md_bg_color: rgba(255,255,255,255)

        MDLabel:
            text: 'Nilai Transaksi'
            font_size: '12dp'
            size_hint: .3, .05
            pos_hint: {"x":.1, "y": .85}
        TextInput:
            id: nilaijual
            font_size: '12sp'
            size_hint: .4,.15
            pos_hint: {"x":.4, "y": .8}
            halign: 'right'
            disabled: True
        
        MDLabel:
            text: 'Jumlah Bayar'
            font_size: '12dp'
            size_hint: .3, .05
            pos_hint: {"x":.1, "y": .65}
        TextInput:
            id: bayarjual
            input_filter: "int"
            font_size: '12sp'
            size_hint: .4,.15
            pos_hint: {"x":.4, "y": .6}
            halign: 'right'
            on_text: root.bayar_sisa()
        
        MDLabel:
            text: 'Kembalian'
            font_size: '12dp'
            size_hint: .3, .05
            pos_hint: {"x":.1, "y": .45}
        TextInput:
            id: sisajual
            font_size: '12sp'
            size_hint: .4,.15
            pos_hint: {"x":.4, "y": .4}
            halign: 'right'
            disabled: True
        
        MDRectangleFlatButton:
            text: "Batal"
            text_color: rgba(0, 0, 0, 255)
            md_bg_color: rgba(0, 255, 0, 150)
            size_hint: .3,.05
            pos_hint: {"x":.1, "y": .1}
            on_release: root.bayar_batal()
        
        MDRectangleFlatButton:
            text: "Simpan"
            text_color: rgba(0, 0, 0, 255)
            md_bg_color: rgba(0, 255, 0, 150)
            size_hint: .3,.05
            pos_hint: {"x":.4, "y": .1} 
            on_release: root.bayar_simpan(bayarjual.text,sisajual.text)


Class baru yang kedua adalah class PosList source codenya: 

class PosList(Popup):
    def on_pre_open(self):
        conn = sqlite3.connect('data_resto.db')
        conn.row_factory = sqlite3.Row 
        cur = conn.cursor()
        cur.execute("SELECT * FROM jual_nota ORDER BY tanggal DESC,nojual DESC " )
        daftarjual = cur.fetchall()
        conn.commit()
        conn.close()

        for record in daftarjual:
            xnota = record['nojual']
            xtanggal = record['tanggal']
            xmeja = record['meja']
            xjumlah=str(record['jumlah'])
            xbayar=" (Belum Bayar)" if record['bayar']==0 else " (Lunas)"
            self.ids.datapostlist.add_widget(
                ThreeLineListItem(text=xnota,
                                  secondary_text=xmeja +"  ("+xtanggal+")",
                                  tertiary_text="Rp."+xjumlah+xbayar,
                                  on_press=self.hasil_clik))
    
    def hasil_clik(self,value): 
        PosCashier.notajual=value.text
        self.dismiss() 

Serta file kivy sebagai penjabaran class PosList  yairu : pos_list.kv :

<PosList>:
    title: "Daftar Penjualan"
    size_hint: .8, .8
    separator_color: 1, 1, 0, 1
    background_color: 0,0,1,1

    MDBoxLayout:
        size_hint: 1,1
        md_bg_color: rgba(255, 255, 255, 255)
        MDScrollView:
            MDList:
                id: datapostlist


File kivy yang harus disempurnakan yaitu file pos_cashir.kv yaitu menambah buton baru untuk list data, serta memberikan perintah khusus pada button bayar selengkapnya :

<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()


Sedangkan class yang harus di sesuaikan atau disempurnakan adalah class PosCashier dimana ada tambahan fungsi baru yaitu cari_nota, hasil clik, posbayar dan hasil_bayar, selengkapnya sbb:

class PosCashier(Screen):
    notajual = StringProperty ("")
    notabayar= StringProperty ("")
    notasisa=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 cari_nota(self):
        popup = PosList()
        popup.bind(on_dismiss=self.hasil_list)
        popup.open()
   
    def hasil_list(self, obj):
        self.on_enter()
   
    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:]
   
    def posbayar(self):
        popup = PosBayar()
        popup.bawajumlah = self.ids.notajumlah.text
        popup.bawabayar = self.ids.notabayar.text
        popup.bawasisa = self.ids.notasisa.text
        popup.bind(on_dismiss=self.hasil_bayar)
        popup.open()

    def hasil_bayar(self, obj):
        if self.notabayar.strip()!='':
            self.ids.notabayar.text=self.notabayar
            self.ids.notasisa.text=self.notasisa
            xnojual = self.ids.notanomor.text.strip()
            xtanggal= self.ids.notatanggal.text
            xmeja = self.ids.notameja.text
            xjumlah = 0 if self.ids.notajumlah.text.strip()=='' else int(self.ids.notajumlah.text)
            xbayar = 0 if self.ids.notabayar.text.strip()=='' else int(self.ids.notabayar.text)
            xsisa = 0 if self.ids.notasisa.text.strip()=='' else int(self.ids.notasisa.text)

            conn = sqlite3.connect('data_resto.db')
            conn.row_factory = sqlite3.Row
            cur = conn.cursor()
            cur.execute("UPDATE jual_nota SET tanggal=?,meja=?,jumlah=?,bayar=?,sisa=? WHERE nojual=? ",(xtanggal,xmeja,xjumlah,xbayar,xsisa,xnojual))
            conn.commit()
            conn.close()



Demikian untuk pengaturan pembayaran nota kasir dan bayar pesanan ini, untuk kelanjutannya silahkan buka dipostingan berikutnya atau lihat video berikutnya, semoga bermanfaat terima kasih wassalamualaikum warohmatullohi wabarohatuh.


Komentar

  1. bang psoting buat print out nota nya bang biar bisa cetak nota. makasih

    BalasHapus

Posting Komentar

...