thongkorn โพสต์ 2023-7-31 20:28:33

[VB.NET] การคิดค่าบริการทั้งแบบ Service Charge และ None Service Charge ในรายการเดียว

http://www.g2gsoft.com/webboard/images/VBNet/ServiceCharge.png


โค้ด VB .NET (2010) กับการคิดค่าบริการ (Service Charge) และคำนวณหาภาษีทั้งแบบไม่คิดภาษี แบบรวมภาษี และแบบแยกภาษี ... อันนี้ไม่ใช่ดราม่านะครับ แต่เป็นการคิดคำนวณ Service Charge เพราะจริงๆแล้วตามโรงแรมต่างๆ หรือร้านอาหารใหญ่ๆ เขาไม่ได้คิดไปหมดทุกรายการ หลักๆก็จะเป็นค่าอาหาร ส่วนพวกห้องพัก หรือห้องคาราโอเกะพวกนี้จะไม่คิด ดังนั้นการคำนวณก็จะต้องแยกออกจากกัน เช่น ตัวอย่างรายการแรกคิด Service Charge เพียงค่าเดียว ก็จะเอาค่า 1,000 บาท (ไม่ใช่รวมหมด 3,000) มาหา 10% ของ Service Charge = 100 ก็จะได้ค่ารวม 1,100 บาท จากนั้นก็จะนำไปรวมกับค่าที่ไม่คิดอีก 2,000 ค่าที่ได้ทั้ง 2 มารวมกันเพื่อนำไปคำนวณหาภาษีอีกทีครับ ซึ่งปกติจะคิดแบบแยกภาษี (ภาระของผู้บริโภคนั่นเอง)

ในงานจริงเราจะต้องกำหนดสินค้า/บริการมาไว้ก่อนล่วงหน้าแล้ว ว่าอันไหนคิดหรือไม่คิด Service Charge สำหรับโค้ดชุดนี้ผมเลยนำเสนอวิธีการควบคุม #DataGridView ด้วยการเขียนโค้ดทั้งหมดล้วนๆ หรือที่เรียกกันว่า Run Time (สั่งรันถึงจะเห็นผลลัพธ์) ไว้ให้สำหรับชาว VB ได้ศึกษากัน

มาดูโค้ดกันเถอะ ...
Public Class frmServiceChargeVat

    ' / --------------------------------------------------------------------------------
    '/ Don't forget to set Form has KeyPreview = True
    Private Sub frmServiceChargeVat_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyDown
      '/ การกดฟังค์ชั่นคีย์
      Select Case e.KeyCode
            Case Keys.F7
                '/ Add Row
                Call btnAddRow_Click(sender, e)
            Case Keys.F8
                '/ Remove Row
                Call btnRemoveRow_Click(sender, e)
      End Select
    End Sub

    ' / --------------------------------------------------------------------------------
    Private Sub frmServiceChargeVat_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
      Me.KeyPreview = True'/ สามารถกดปุ่มฟังค์ชั่นคีย์ลงในฟอร์มได้
      With cmbTax
            .Items.Add("None Vat")
            .Items.Add("Include Vat")
            .Items.Add("Exclude Vat")
      End With
      cmbTax.SelectedIndex = 2
      '//
      Call InitializeGrid()
      Call FillDataSample()   '/ ตัวอย่างสมมุติ
      Call CalSumTotal()'/ รวมจำนวนเงิน
      '//
      Label7.Anchor = AnchorStyles.Bottom + AnchorStyles.Left
      cmbTax.Anchor = AnchorStyles.Bottom + AnchorStyles.Left
    End Sub

    ' / --------------------------------------------------------------------------------
    ' / การตั้งค่า DataGridView แบบ @Run Time หรือ Dynamically.
    Private Sub InitializeGrid()
      With dgvData
            .RowHeadersVisible = False
            .AllowUserToAddRows = False
            .AllowUserToDeleteRows = False
            .AllowUserToResizeRows = False
            .MultiSelect = False
            .ReadOnly = False
            .RowTemplate.MinimumHeight = 27
            .RowTemplate.Height = 27
            .Font = New Font("Tahoma", 10)
            '/ Columns Specified
            '/ Index = 0
            .Columns.Add("PK", "Primary Key")
            With .Columns("PK")
                .ReadOnly = True
                .DefaultCellStyle.BackColor = Color.LightGoldenrodYellow
                .Visible = True 'False '/ ปกติหลัก Primary Key จะต้องถูกซ่อนไว้
            End With
            .Columns.Add("ProductID", "Product ID") '/ Index = 1
            .Columns.Add("ProductName", "Product Name") '/ Index = 2
            '/ Read Only
            .Columns(1).ReadOnly = True '/ รหัสสินค้า
            .Columns(2).ReadOnly = True '/ ชื่อสินค้า
            '/
            .Columns.Add("Quantity", "Quantity") '/ Index = 3
            .Columns("Quantity").ValueType = GetType(Integer)
            .Columns.Add("UnitPrice", "Unit Price") '/ Index = 4
            .Columns("UnitPrice").ValueType = GetType(Double)
            '/ Index = 5 (CheckBox) ... เลือกว่าคิด Service Charge หรือไม่
            Dim chkServiceCharge As New DataGridViewCheckBoxColumn
            .Columns.Add(chkServiceCharge)
            chkServiceCharge.HeaderText = "Service Charge"
            chkServiceCharge.Name = "chkServiceCharge"
            '/ Index = 6 ... Total = (จำนวน x ราคา)
            .Columns.Add("Total", "Total")
            .Columns("Total").ValueType = GetType(Double)
            '/ Total Column
            With .Columns("Total")
                .ReadOnly = True
                .DefaultCellStyle.BackColor = Color.LightGoldenrodYellow
                .DefaultCellStyle.ForeColor = Color.Blue
                .DefaultCellStyle.Font = New Font(dgvData.Font, FontStyle.Bold)
            End With
            '/ Alignment MiddleRight only columns 3, 4 and 6
            For i As Byte = 3 To 6
                If i <> 5 Then
                  .Columns(i).HeaderCell.Style.Alignment = DataGridViewContentAlignment.MiddleRight
                  .Columns(i).DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight
                  '// กรณีหลัก 5 เป็น CheckBox ให้จัดตำแหน่งตรงกึ่งกลางของเซลล์
                Else
                  .Columns(i).HeaderCell.Style.Alignment = DataGridViewContentAlignment.MiddleCenter
                  .Columns(i).DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter
                End If
            Next
            '/ Auto size column width of each main by sorting the field.
            .AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill
            '/ Adjust Header Styles
            With .ColumnHeadersDefaultCellStyle
                .BackColor = Color.Crimson
                .ForeColor = Color.White
                .Font = New Font("Tahoma", 10, FontStyle.Bold)
            End With
            .ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing
            .ColumnHeadersHeight = 36
            '/ กำหนดให้ EnableHeadersVisualStyles = False เพื่อให้ยอมรับการเปลี่ยนแปลงสีพื้นหลังของ Header
            .EnableHeadersVisualStyles = False
      End With

    End Sub

    ' / --------------------------------------------------------------------------------
    ' / DATA SAMPLE ... ทำตัวอย่างให้ง่ายต่อการคำนวณ
    Private Sub FillDataSample()
      Try
            '/ Primary Key, Product ID, Product Name, Quantity, UnitPrice, ServiceCharge, Total
            Dim row As String() = New String() _
                {"1", "PRO00001", "Product 1", "1", "1000.00", CBool(1), "0.00"}
            dgvData.Rows.Add(row)
            row = New String() _
                {"2", "PRO00002", "Product 2", "1", "1000.00", CBool(0), "0.00"}
            dgvData.Rows.Add(row)
            row = New String() _
                {"3", "PRO00003", "Product 3", "1", "1000.00", CBool(0), "0.00"}
            dgvData.Rows.Add(row)
      Catch ex As Exception
            MessageBox.Show(ex.Message)
      End Try
    End Sub

    ' / --------------------------------------------------------------------------------
    ' / Add new row
    Private Sub btnAddRow_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAdd.Click
      Dim Position As Integer = dgvData.Rows.Count - 1
      Dim PK As Integer = 1   '/ Initialize value if without rows.
      '/ Get value at the last row
      Dim LastRow As New DataGridViewRow
      '/ ตรวจสอบค่าแถวสุดท้ายว่ามีค่า Primary Key เท่าไหร่ก็ให้บวก 1 (เป็นการจำลองการทำงาน โดยไม่ติดต่อกับ DataBase)
      '/ กรณีใช้ฐานข้อมูลจริงๆ ให้ตัดส่วนนี้ทิ้งแล้วใช้ Primary Key ของสินค้าจากฐานข้อมูลแทน
      If Position >= 0 Then
            '/ ไปแถวสุดท้าย
            LastRow = dgvData.Rows.OfType(Of DataGridViewRow).Last()
            '/ จากนั้นให้เพิ่มค่าขึ้น +1 (Column Index = 0)
            PK = LastRow.Cells(0).Value + 1
      End If
      Dim RandomClass As New Random()
      '/ Sample data
      '/ Primary Key, Product ID, Product Name, Quantity, UnitPrice, ServiceCharge, Total
      Dim row As String() = New String() {PK, "PRO0000" & PK, "Product " & PK, "1", Format(RandomClass.Next(100, 2000), "0.00"), RandomClass.Next(2) = 0, "0.00"}
      dgvData.Rows.Add(row)
      '/ โฟกัสไปที่ Column(3) หรือ Quantity (จำนวน)
      dgvData.CurrentCell = dgvData.Rows(dgvData.RowCount - 1).Cells(3)
      dgvData.Focus()

      '/ ไปคำนวณหาค่าผลรวม
      Call CalSumTotal()
    End Sub

    ' / --------------------------------------------------------------------------------
    ' / Remove select row
    Private Sub btnRemoveRow_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnRemove.Click
      If dgvData.RowCount = 0 Then Exit Sub
      '/
      dgvData.Rows.Remove(dgvData.CurrentRow)
      dgvData.Refresh()
      '/ เมื่อแถวรายการถูกลบออกไป และยังคงมีแถวรายการอยู่ ต้องไปคำนวณหาค่าผลรวมใหม่
      If dgvData.RowCount > 0 Then Call CalSumTotal()
    End Sub

    ' / --------------------------------------------------------------------------------
    ' / Calcualte sum of Total (Column Index = 6)
    ' / ทำทุกครั้งที่มีการเพิ่มหรือลบแถวรายการ และมีการเปลี่ยนแปลงค่าในเซลล์ Quantity, UnitPrice และ Service Charge
    Private Sub CalSumTotal()
      Dim ServiceCharge As Double = 0
      Dim NoneServiceCharge As Double = 0
      'txtTotal.Text = "0.00"
      'txtVat.Text = "0.00"
      'txtNetTotal.Text = "0.00"
      'txtServiceCharge.Text = "0.00"
      'txtServiceChargeSum.Text = "0.00"
      'txtNonServiceCharge.Text = "0.00"

      '// Set all TextBox Control to Zero.
      For Each tb As TextBox In Me.Controls.OfType(Of TextBox)()
            tb.Text = "0.00"
      Next
      '/ วนรอบตามจำนวนแถวที่มีอยู่ปัจจุบัน
      For nRow As Integer = 0 To dgvData.RowCount - 1
            '// หากติ๊กเครื่องหมายถูกหลักที่ 6 (Index = 5) จะคำนวณหาส่วนของสินค้า/บริการที่คิด Service Charge
            If CBool(dgvData.Rows(nRow).Cells(5).Value) Then
                '// [จำนวน x ราคา]
                ServiceCharge = Format(dgvData.Rows(nRow).Cells(3).Value * dgvData.Rows(nRow).Cells(4).Value, "#,##0.00")
                '// รวมราคาที่คิด Service Charge เป็นค่าที่ยังไม่ได้คิด 10%
                txtServiceCharge.Text = Format(CDbl(txtServiceCharge.Text) + ServiceCharge, "#,##0.00")
                '// คิด Service Charge 10% ของราคา
                ServiceCharge = ServiceCharge + (ServiceCharge * 10 / 100)
                '// รวมจำนวนราคาและ Service Charge 10%
                txtServiceChargeSum.Text = Format(CDbl(txtServiceChargeSum.Text) + ServiceCharge, "#,##0.00")

                '// None Service Charge
            Else
                NoneServiceCharge = Format(dgvData.Rows(nRow).Cells(3).Value * dgvData.Rows(nRow).Cells(4).Value, "#,##0.00")
                txtNonServiceCharge.Text = Format(CDbl(txtNonServiceCharge.Text) + NoneServiceCharge, "#,##0.00")
            End If
            '/ หลักสุดท้ายของตารางกริด = [จำนวน x ราคา]
            dgvData.Rows(nRow).Cells(6).Value = Format(dgvData.Rows(nRow).Cells(3).Value * dgvData.Rows(nRow).Cells(4).Value, "#,##0.00")
      Next

      '// รวมราคาสินค้า/บริการ = Service Charge + None Service Charge
      Dim SumPrice As Double = Format(CDbl(txtServiceChargeSum.Text) + CDbl(txtNonServiceCharge.Text), "#,##0.00")
      '// TAX - การคิดภาษี
      Select Case cmbTax.SelectedIndex
            '// ไม่คิดภาษี
            Case 0
                txtTotal.Text = Format(SumPrice, "#,##0.00")
                txtVat.Text = "0.00"
                '// รวมจำนวนเงินทั้งหมด
                txtNetTotal.Text = Format(CDbl(txtTotal.Text) + CDbl(txtVat.Text), "#,##0.00")
                '// หรือ txtNetTotal.Text = Format(SumPrice, "#,##0.00")
                lblTotal.Text = "Total (1+2) :"
                lblVat.Text = "None Vat : "
                lblNetTotal.Text = "Net Total (Total) :"

                '// รวมภาษี (Include Tax)
            Case 1
                '// คิดภาษี 7% (Include VAT)
                txtVat.Text = Format(SumPrice - (SumPrice / 1.07), "#,##0.00")
                '// หาราคาสินค้าที่แท้จริง ... ราคาสินค้าทั้งหมดลบออกจากภาษี
                txtTotal.Text = Format(SumPrice - CDbl(txtVat.Text), "#,##0.00")
                '// รวมจำนวนเงินทั้งหมด
                txtNetTotal.Text = Format(SumPrice, "#,##0.00")
                lblTotal.Text = "Total (1+2-Vat) :"
                lblVat.Text = "Include Vat (7%) : "
                lblNetTotal.Text = "Net Total (Total+Vat) :"

                '// แยกภาษี (Exclude Tax)
            Case 2
                txtTotal.Text = Format(SumPrice, "#,##0.00")
                '// คิดแยกภาษี 7% (Exclude VAT)
                txtVat.Text = Format(CDbl(txtTotal.Text) * 7 / 100, "#,##0.00")
                '// รวมจำนวนเงินทั้งหมด
                txtNetTotal.Text = Format(CDbl(txtTotal.Text) + CDbl(txtVat.Text), "#,##0.00")
                lblTotal.Text = "Total (1+2) :"
                lblVat.Text = "Exclude Vat (7%) : "
                lblNetTotal.Text = "Net Total (Total+Vat) :"
      End Select
    End Sub

    ' / --------------------------------------------------------------------------------
    ' / หลังจากการแก้ไขค่าในเซลล์และเกิดการกด Enter
    Private Sub dgvData_CellEndEdit(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles dgvData.CellEndEdit
      '/ เกิดการเปลี่ยนแปลงค่าในหลัก Index ที่ 3 หรือ 4
      Select Case e.ColumnIndex
            Case 3, 4 '/ Column Index = 3 (Quantity), Column Index = 4 (UnitPrice)
                '/ Quantity
                '/ การดัก Error กรณีมีค่า Null Value ให้ใส่ค่า 0 ลงไปแทน
                If IsDBNull(dgvData.Rows(e.RowIndex).Cells(3).Value) Then dgvData.Rows(e.RowIndex).Cells(3).Value = "0"
                Dim Quantity As Integer = dgvData.Rows(e.RowIndex).Cells(3).Value

                '/ UnitPrice
                '/ If Null Value
                If IsDBNull(dgvData.Rows(e.RowIndex).Cells(4).Value) Then dgvData.Rows(e.RowIndex).Cells(4).Value = "0.00"
                dgvData.Rows(e.RowIndex).Cells(4).Value = Format(CDbl(dgvData.Rows(e.RowIndex).Cells(4).Value), "0.00")
                Dim UnitPrice As Double = dgvData.Rows(e.RowIndex).Cells(4).Value
                '/ Quantity x UnitPrice ในหลักที่ 7 (Index = 6)
                dgvData.Rows(e.RowIndex).Cells(6).Value = (Quantity * UnitPrice).ToString("#,##0.00")
                '/ Calculate Summary
                Call CalSumTotal()
      End Select
    End Sub

    ' / --------------------------------------------------------------------------------
    ' / Validate Cell ... Quantity = Integer, UnitPrice = Double
    Private Sub dgvData_EditingControlShowing(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewEditingControlShowingEventArgs) Handles dgvData.EditingControlShowing
      Select Case dgvData.Columns(dgvData.CurrentCell.ColumnIndex).Name
            ' / Can use both Colume Index or Field Name
            Case "Quantity", "UnitPrice"
                '/ Stop and Start event handler
                RemoveHandler e.Control.KeyPress, AddressOf ValidKeyPress
                AddHandler e.Control.KeyPress, AddressOf ValidKeyPress
      End Select
    End Sub

    ' / --------------------------------------------------------------------------------
    Private Sub ValidKeyPress(ByVal sender As System.Object, ByVal e As System.Windows.Forms.KeyPressEventArgs)
      Dim tb As TextBox = sender
      Select Case dgvData.CurrentCell.ColumnIndex
            Case 3' Quantity is Integer
                Select Case e.KeyChar
                  Case "0" To "9"   ' digits 0 - 9 allowed
                  Case ChrW(Keys.Back)    ' backspace allowed for deleting (Delete key automatically overrides)

                  Case Else ' everything else ....
                        ' True = CPU cancel the KeyPress event
                        e.Handled = True ' and it's just like you never pressed a key at all
                End Select

            Case 4' UnitPrice is Double
                Select Case e.KeyChar
                  Case "0" To "9"
                        ' Allowed "."
                  Case "."
                        ' can present "." only one
                        If InStr(tb.Text, ".") Then e.Handled = True

                  Case ChrW(Keys.Back)
                        '/ Return False is Default value

                  Case Else
                        e.Handled = True

                End Select
      End Select
    End Sub

    ' / --------------------------------------------------------------------------------
    '// เหตุการณ์ในการคลิ๊กเมาส์ลงในเซลล์ของหลักที่ 6 (Index = 5)
    Private Sub dgvData_CellContentClick(sender As Object, e As System.Windows.Forms.DataGridViewCellEventArgs) Handles dgvData.CellContentClick
      '// Column Index = 5
      If dgvData.Columns(e.ColumnIndex).Name = "chkServiceCharge" Then
            Dim isChecked As Boolean = dgvData.Rows(e.RowIndex).Cells(e.ColumnIndex).Value
            If isChecked = False Then
                dgvData.Rows(e.RowIndex).Cells(e.ColumnIndex).Value = True
            Else
                dgvData.Rows(e.RowIndex).Cells(e.ColumnIndex).Value = False
            End If
      End If
      '//
      '// คำนวณหาราคาใหม่
      Call CalSumTotal()
    End Sub

    Private Sub cmbTax_SelectedIndexChanged(sender As System.Object, e As System.EventArgs) Handles cmbTax.SelectedIndexChanged
      Call CalSumTotal()
    End Sub

    Private Sub frmServiceChargeVat_FormClosed(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
      Me.Dispose()
      GC.SuppressFinalize(Me)
      Application.Exit()
    End Sub

End Class


ดาวน์โหลดโค้ดฉบับเต็ม VB.NET (2010) ได้ที่นี่ ...
หน้า: [1]
ดูในรูปแบบกติ: [VB.NET] การคิดค่าบริการทั้งแบบ Service Charge และ None Service Charge ในรายการเดียว