Thử sức cùng nhập xuất tồn

Mật vụ FBI

Yêu THVBA
Kính gửi tất cả anh em THVBA

Hôm nay mình góp vui 1 đề tài nhỏ về NXT để cùng nhau giải nhé!

* Cấu trúc file
- Mỗi dòng 1ID
- Các dòng có cùng ID1 là đã phát sinh nhập xuất.
- Date nhập xuất
- Số lượng nhập xuất

Đề bài đưa ra là:


Anh chị hãy tìm các ID1 có phát sinh nhập xuất tồn theo tháng cần xem.

VD: muốn xem NXT tháng 8/2021 thì những ID1 nào có xuất hiện trong tháng 8/2021 là dc điền "8/2021" vào dòng đó, k xuất hiện thì bỏ trống. NXT bao gồm: Tồn đầu, nhập, xuất, tồn cuối.

VD: ID1 là xxxxxx có date nhập là 15/7/2021 và date xuất là 20/09/2021 thì nó xuất hiện ở tháng 8/2021 là tồn đầu và tồn cuối, tháng 7/2021 là nhập và tồn cuối, tháng 9/2021 là tồn đầu và xuất.

* Đây là thử sức chứ k phải lợi dụng để xin code nhé! mình đã có lời giải rồi!


Mọi người cùng tham gia vui nhé! (đã cập nhật có KQ)
 
Sửa lần cuối:

CRV

SMod
Thành viên BQT
Chào @Mật vụ FBI
Ít nhất bạn cũng phải đính kèm thêm kết quả mẫu để mọi người có thể so sánh chứ.
Các điều kiện lọc bố trí ở đâu, mẫu form kết quả như thế nào?
 

CRV

SMod
Thành viên BQT
@Mật vụ FBI form mẫu và kết quả mẫu ở đâu bạn nhỉ, mình tải file theo link dưới về không thấy?
 

Mật vụ FBI

Yêu THVBA
kết quả nằm cột I, dòng nào trống là k xuất hiện trong tháng đó! kết quả đang là tháng 8/2021. những dòng chứa tháng 8/2021 là nó xuất hiện trong nhập xuất tồn tháng 8/2021

Không viết tắt bạn nhé, cũng không cần trích dẫn bài viết (nếu không cần thiết)
 
Sửa lần cuối bởi điều hành viên:

Mật vụ FBI

Yêu THVBA
@Mật vụ FBI Nếu vậy đâu phải là đề NXT (nhập - xuất - tồn) như bạn diễn tả, chỉ đơn giản là lọc từ ngày đến ngày ?
cái này chỉ là bước đầu của NXT, lọc được này rồi sẽ xuất ra file NXT. đại khái cũng góp vui cho ai có nhả hứng thôi nên cũng k chi tiết cụ thể lắm!
 

CRV

SMod
Thành viên BQT
Vậy theo kết quả mẫu của bạn mình góp vui, file đính kèm bạn tạo thêm 1 sheet rồi đặt tên là "Result" rồi chạy thử đoạn code sau:
Mã:
Option Explicit
Sub Loc()
    With CreateObject("ADODB.Connection")
        .Open ("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & ThisWorkbook.FullName & ";Extended Properties=""Excel 12.0;HDR=No""")
        Sheets("Result").Range("A1").CopyFromRecordset .Execute("Select * From [DATABASE$] Where F7 Between #8/1/2021# And #8/31/2021#")
    End With
End Sub
 

Mật vụ FBI

Yêu THVBA
Vậy theo kết quả mẫu của bạn mình góp vui, file đính kèm bạn tạo thêm 1 sheet rồi đặt tên là "Result" rồi chạy thử đoạn code sau:
Mã:
Option Explicit
Sub Loc()
    With CreateObject("ADODB.Connection")
        .Open ("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & ThisWorkbook.FullName & ";Extended Properties=""Excel 12.0;HDR=No""")
        Sheets("Result").Range("A1").CopyFromRecordset .Execute("Select * From [DATABASE$] Where F7 Between #8/1/2021# And #8/31/2021#")
    End With
End Sub
Không đơn giản như thế đâu bạn! kết quả bạn ra đâu có đúng đâu! vì 1 số hàng với loại nhập có date tháng 7/2021 nhưng chưa xuất nó dc nằm trong NXT tháng 8/2021 chứ!
 
  • Haha
Reactions: CRV

CRV

SMod
Thành viên BQT
Ồ thì ra là vậy xin lỗi mình không để ý kỹ, văn viết đôi khi khó hiểu sau khi kèm theo dữ liệu mẫu và giải thích thêm thì bây giờ mình đã hiểu.
Cũng khoai phết, mình dùng 2 vòng lặp i và Dic nhé. Bạn có code hay cho mình tham khảo.
Mã:
Option Explicit

Sub Dung_La_Trai_Dat_Tron_aHihi()

    Dim dict As Object
    Dim Data As Variant, Result As Variant
    Dim sKey As String, sID As String
    Dim i As Long, j As Long, k As Long
    Dim issueDate As Date
   
    Const startDate As Date = #8/1/2021#
    Const endDate As Date = #8/31/2021#

    Data = ThisWorkbook.Worksheets("DATABASE").Range("A1").CurrentRegion.Value
    If Not IsArray(Data) Then Exit Sub
   
    ReDim Result(1 To UBound(Data, 1), 1 To UBound(Data, 2))
    Set dict = CreateObject("Scripting.Dictionary")
    k = 1
    '//Tieu de
    For j = LBound(Data, 2) To UBound(Data, 2)
        Result(k, j) = Data(1, j)
    Next j
   
    '//Kiem tra nhap-xuat den thoi diem tinh den startDate
    For i = 2 To UBound(Data, 1)
        sID = Data(i, 2)
        issueDate = Data(i, 7)
        If issueDate < startDate Then
            If Not dict.Exists(sID) Then dict.Add sID, issueDate
            sKey = sID & "|" & Data(i, 6)
            If Not dict.Exists(sKey) Then dict.Add sKey, issueDate
        End If
    Next i
   
    For i = 2 To UBound(Data, 1)
        sID = Data(i, 2)
        issueDate = Data(i, 7)
        '// Xet trong khoang startDate den endDate
        If (issueDate >= startDate) And (issueDate <= endDate) Then
            k = k + 1
            For j = LBound(Data, 2) To UBound(Data, 2)
                Result(k, j) = Data(i, j)
            Next j
        ElseIf (issueDate <= endDate) Then
            If dict.Exists(sID) Then
                sKey = sID & "|X"
                '// Neu co nhap ma chua co xuat
                If Not dict.Exists(sKey) Then
                    k = k + 1
                    For j = LBound(Data, 2) To UBound(Data, 2)
                        Result(k, j) = Data(i, j)
                    Next j
                End If
            End If
        End If
    Next i
   
    ThisWorkbook.Worksheets("Result").Range("A1").Resize(k, UBound(Result, 2)).Value = Result
   
    MsgBox k
   
End Sub
 

Mật vụ FBI

Yêu THVBA
Ồ thì ra là vậy xin lỗi mình không để ý kỹ, văn viết đôi khi khó hiểu sau khi kèm theo dữ liệu mẫu và giải thích thêm thì bây giờ mình đã hiểu.
Cũng khoai phết, mình dùng 2 vòng lặp i và Dic nhé. Bạn có code hay cho mình tham khảo.
Mã:
Option Explicit

Sub Dung_La_Trai_Dat_Tron_aHihi()

    Dim dict As Object
    Dim Data As Variant, Result As Variant
    Dim sKey As String, sID As String
    Dim i As Long, j As Long, k As Long
    Dim issueDate As Date
  
    Const startDate As Date = #8/1/2021#
    Const endDate As Date = #8/31/2021#

    Data = ThisWorkbook.Worksheets("DATABASE").Range("A1").CurrentRegion.Value
    If Not IsArray(Data) Then Exit Sub
  
    ReDim Result(1 To UBound(Data, 1), 1 To UBound(Data, 2))
    Set dict = CreateObject("Scripting.Dictionary")
    k = 1
    '//Tieu de
    For j = LBound(Data, 2) To UBound(Data, 2)
        Result(k, j) = Data(1, j)
    Next j
  
    '//Kiem tra nhap-xuat den thoi diem tinh den startDate
    For i = 2 To UBound(Data, 1)
        sID = Data(i, 2)
        issueDate = Data(i, 7)
        If issueDate < startDate Then
            If Not dict.Exists(sID) Then dict.Add sID, issueDate
            sKey = sID & "|" & Data(i, 6)
            If Not dict.Exists(sKey) Then dict.Add sKey, issueDate
        End If
    Next i
  
    For i = 2 To UBound(Data, 1)
        sID = Data(i, 2)
        issueDate = Data(i, 7)
        '// Xet trong khoang startDate den endDate
        If (issueDate >= startDate) And (issueDate <= endDate) Then
            k = k + 1
            For j = LBound(Data, 2) To UBound(Data, 2)
                Result(k, j) = Data(i, j)
            Next j
        ElseIf (issueDate <= endDate) Then
            If dict.Exists(sID) Then
                sKey = sID & "|X"
                '// Neu co nhap ma chua co xuat
                If Not dict.Exists(sKey) Then
                    k = k + 1
                    For j = LBound(Data, 2) To UBound(Data, 2)
                        Result(k, j) = Data(i, j)
                    Next j
                End If
            End If
        End If
    Next i
  
    ThisWorkbook.Worksheets("Result").Range("A1").Resize(k, UBound(Result, 2)).Value = Result
  
    MsgBox k
  
End Sub
Code pro đấy.

Code của mình lặp tìm có phát sinh NXT rồi lấy mã đó gán tháng vô thôi
 
  • Haha
Reactions: CRV

Mật vụ FBI

Yêu THVBA
PHP:
For i = LBound(Arr_ID1_First, 1) To UBound(Arr_ID1_First, 1)
        For j = LBound(Arr_DATA, 1) To UBound(Arr_DATA, 1)
            If Arr_DATA(j, 2) = Arr_ID1_First(i, 1) Then
                If Arr_DATA(j, 25) = "N" And Arr_DATA(j, 10) < Start_Date Then
                    iTon_DauN = iTon_DauN + Arr_DATA(j, 12)
                End If
                If Arr_DATA(j, 25) = "X" And Arr_DATA(j, 10) < Start_Date Then
                    iTon_DauX = iTon_DauX + Arr_DATA(j, 12)
                End If
                If Arr_DATA(j, 25) = "N" And Arr_DATA(j, 10) >= Start_Date And Arr_DATA(j, 10) <= End_Date Then
                    iNhap = iNhap + Arr_DATA(j, 12)
                End If
                If Arr_DATA(j, 25) = "X" And Arr_DATA(j, 10) >= Start_Date And Arr_DATA(j, 10) <= End_Date Then
                    iXuat = iXuat + Arr_DATA(j, 12)
                End If
            End If
        Next j
        If (iTon_DauN - iTon_DauX) + iNhap + iXuat > 0 Then
            Arr_ID1_Last(UBound(Arr_ID1_Last)) = Arr_ID1_First(i, 1)
            ReDim Preserve Arr_ID1_Last(UBound(Arr_ID1_Last) + 1) As Variant
            iTon_DauN = 0
            iTon_DauX = 0
            iNhap = 0
            iXuat = 0
        End If
    Next i
mình chạy check như thế này! nhìn kém trình quá, mà code chạy nặng hơn nữa!
 
  • Love
Reactions: CRV

Mật vụ FBI

Yêu THVBA
Ồ thì ra là vậy xin lỗi mình không để ý kỹ, văn viết đôi khi khó hiểu sau khi kèm theo dữ liệu mẫu và giải thích thêm thì bây giờ mình đã hiểu.
Cũng khoai phết, mình dùng 2 vòng lặp i và Dic nhé. Bạn có code hay cho mình tham khảo.
Mã:
Option Explicit

Sub Dung_La_Trai_Dat_Tron_aHihi()

    Dim dict As Object
    Dim Data As Variant, Result As Variant
    Dim sKey As String, sID As String
    Dim i As Long, j As Long, k As Long
    Dim issueDate As Date
  
    Const startDate As Date = #8/1/2021#
    Const endDate As Date = #8/31/2021#

    Data = ThisWorkbook.Worksheets("DATABASE").Range("A1").CurrentRegion.Value
    If Not IsArray(Data) Then Exit Sub
  
    ReDim Result(1 To UBound(Data, 1), 1 To UBound(Data, 2))
    Set dict = CreateObject("Scripting.Dictionary")
    k = 1
    '//Tieu de
    For j = LBound(Data, 2) To UBound(Data, 2)
        Result(k, j) = Data(1, j)
    Next j
  
    '//Kiem tra nhap-xuat den thoi diem tinh den startDate
    For i = 2 To UBound(Data, 1)
        sID = Data(i, 2)
        issueDate = Data(i, 7)
        If issueDate < startDate Then
            If Not dict.Exists(sID) Then dict.Add sID, issueDate
            sKey = sID & "|" & Data(i, 6)
            If Not dict.Exists(sKey) Then dict.Add sKey, issueDate
        End If
    Next i
  
    For i = 2 To UBound(Data, 1)
        sID = Data(i, 2)
        issueDate = Data(i, 7)
        '// Xet trong khoang startDate den endDate
        If (issueDate >= startDate) And (issueDate <= endDate) Then
            k = k + 1
            For j = LBound(Data, 2) To UBound(Data, 2)
                Result(k, j) = Data(i, j)
            Next j
        ElseIf (issueDate <= endDate) Then
            If dict.Exists(sID) Then
                sKey = sID & "|X"
                '// Neu co nhap ma chua co xuat
                If Not dict.Exists(sKey) Then
                    k = k + 1
                    For j = LBound(Data, 2) To UBound(Data, 2)
                        Result(k, j) = Data(i, j)
                    Next j
                End If
            End If
        End If
    Next i
  
    ThisWorkbook.Worksheets("Result").Range("A1").Resize(k, UBound(Result, 2)).Value = Result
  
    MsgBox k
  
End Sub

Mà code này hình như chạy được với khi số lượng nhập xuất bằng nhau! còn nếu nhập nhiều hơn xuất (phần dư) sẽ không áp dụng được code này

VD: nhập 25/7/2021 2010ctns, xuất 31/7/2021 2000ctns. Theo code này sẽ không bắt được dòng này! đúng ra dòng này vẫn hiện vào NXT 8/2021 vì nó còn dư 10ctns.
 

tuhocvba

Administrator
Thành viên BQT
Đây là một topic có nội dung code, nhưng được đưa vào Box Trà Đá Vỉa Hè để nhằm tránh kiểm duyệt. Tuy nhiên Box Trà Đá Vỉa Hè vẫn xuất hiện trên bảng tin của diễn đàn, sau khi xem xét topic này, tôi xếp nó vào topic chứa code, và nội dung trình bày trong topic này chưa đạt yêu cầu về tính "Dễ Hiểu", do đó tôi di chuyển vào Box Hướng Dẫn Nhau Viết Bài Cho Dễ Hiểu.

Đây cũng là lần nhắc nhở đầu tiên. Các hành vi cố ý lách luật vẫn tạo ra hệ quả là các bài viết chất lượng thấp đập vào mắt tôi.
 

Mật vụ FBI

Yêu THVBA
Đây là một topic có nội dung code, nhưng được đưa vào Box Trà Đá Vỉa Hè để nhằm tránh kiểm duyệt. Tuy nhiên Box Trà Đá Vỉa Hè vẫn xuất hiện trên bảng tin của diễn đàn, sau khi xem xét topic này, tôi xếp nó vào topic chứa code, và nội dung trình bày trong topic này chưa đạt yêu cầu về tính "Dễ Hiểu", do đó tôi di chuyển vào Box Hướng Dẫn Nhau Viết Bài Cho Dễ Hiểu.

Đây cũng là lần nhắc nhở đầu tiên. Các hành vi cố ý lách luật vẫn tạo ra hệ quả là các bài viết chất lượng thấp đập vào mắt tôi.
Xóa ngay nick cho lành nhé. Diễn đàn đầy tính chất phát xít
 

CRV

SMod
Thành viên BQT
Sao bạn dễ nóng nảy vậy @Mật vụ FBI, nếu BQT không nghiêm khắc thì diễn đàn đâu có được các bài viết chất lượng tốt như ngày hôm nay.
Bạn đưa vấn đề muốn mọi người tham gia thì cũng nên giải thích để mọi người cùng hiểu, ai có khả năng và hứng thú thì tham gia.
Nếu mình không xác nhận lại các thông tin thì không biết đề tài của bạn đến bao giờ mới có người tham gia.
-----
Code bài 10 là mình xử lý theo dữ liệu mẫu bạn gửi, nếu bạn nêu đầy đủ và rõ ràng từ đầu có lẽ chúng ta không mất thời gian mà còn vui vẻ.
Mình cũng viết lại, viết luôn ra cả dữ liệu bao gồm đầu kỳ/nhập/xuất/tồn và cả dữ liệu chi tiết phát sinh trong kỳ.
Không biết có đúng ý bạn không nhưng mình vẫn đưa lên mọi người cùng tham khảo, nhưng dù đúng hay dù sai mình kết thúc vấn đề này ở đây.
Mã:
Option Explicit

Public Const THVBA As String = "https://tuhocvba.net/threads/thu-suc-cung-nhap-xuat-ton.1646/"

Public Sub Inventory()

    Dim Data As Variant, Result As Variant, aInventory As Variant
    Dim Total(1 To 1, 1 To 4)
    Dim sKey As String, sItemCode As String, sInOut As String
    Dim Quantity As Double, Tmr As Double
    Dim i As Long, j As Long, k As Long, n As Long, c As Long, r As Long
    Dim issueDate As Date
    Dim shResult As Worksheet
  
    On Error Resume Next
    Set shResult = ThisWorkbook.Worksheets("Result")
    If (Err.Number <> 0) Then
        MsgBox "Not found sheet name ""Result"" in thisWorkbook.", vbCritical, THVBA
        Exit Sub
    End If
    On Error GoTo 0
  
    Const startDate As Date = #8/1/2021#    '<<--- Ngay bat dau
    Const endDate As Date = #8/31/2021#     '<<--- Ngay ket thuc
    Const sReceived As String = "N"
    Const Delim As String = "|"
  
    Tmr = Timer()
  
    Data = ThisWorkbook.Worksheets("DATABASE").Range("A1").CurrentRegion.Value
    If Not IsArray(Data) Then Exit Sub
  
    r = UBound(Data, 1)
    c = UBound(Data, 2)
    ReDim Result(1 To r, 1 To c)
    ReDim aInventory(1 To r, 1 To 6)
  
    Dim dict As New Scripting.Dictionary
  
    k = 1 '//Tieu de
    aInventory(k, 1) = "STT"
    aInventory(k, 2) = "ID"
    aInventory(k, 3) = "DAU KY"
    aInventory(k, 4) = "NHAP KHO"
    aInventory(k, 5) = "XUAT KHO"
    aInventory(k, 6) = "TON KHO"
  
    k = 2 '// Total
    aInventory(k, 2) = "SUM:"
  
    For i = 2 To r
  
        sItemCode = Data(i, 2)
        sInOut = Data(i, 6)
        issueDate = Data(i, 7)
        Quantity = Data(i, 8)
      
        If (issueDate <= endDate) Then
            If Not dict.Exists(sItemCode) Then
                k = k + 1
                dict.Add sItemCode, k
                aInventory(k, 1) = k - 2
                aInventory(k, 2) = sItemCode
              
                If (issueDate < startDate) Then
                    If sInOut = sReceived Then '// Nhap
                        aInventory(k, 3) = aInventory(k, 3) + Quantity '// Cong dau ky
                    Else '// Xuat
                        aInventory(k, 3) = aInventory(k, 3) - Quantity '// Tru dau ky
                        sKey = sItemCode & Delim & sInOut '// Kiem tra phat sinh nhap xuat
                        If Not dict.Exists(sKey) Then dict.Add sKey, issueDate
                    End If
                Else '// Phat sinh trong khoang startDate den endDate
                    If sInOut = sReceived Then '// Nhap
                        aInventory(k, 4) = aInventory(k, 4) + Quantity '// Nhap kho
                    Else '// Xuat
                        aInventory(k, 5) = aInventory(k, 5) + Quantity '// Xuat kho
                    End If
                End If
            Else
                n = dict.Item(sItemCode)
                If (issueDate < startDate) Then
                    If sInOut = sReceived Then '// Nhap
                        aInventory(n, 3) = aInventory(n, 3) + Quantity '// Cong dau ky
                    Else '// Xuat
                        aInventory(n, 3) = aInventory(n, 3) - Quantity '// Tru dau ky
                        sKey = sItemCode & Delim & sInOut '// Kiem tra phat sinh nhap xuat
                        If Not dict.Exists(sKey) Then dict.Add sKey, issueDate
                    End If
                Else '// Phat sinh trong khoang startDate den endDate
                    If sInOut = sReceived Then '// Nhap
                        aInventory(n, 4) = aInventory(n, 4) + Quantity '// Nhap kho
                    Else '// Xuat
                        aInventory(n, 5) = aInventory(n, 5) + Quantity '// Xuat kho
                    End If
                End If
            End If
        End If
    Next i
    For i = 3 To k '// TON KHO
        aInventory(i, 6) = aInventory(i, 3) + aInventory(i, 4) - aInventory(i, 5)
        For j = 3 To 6
            Total(1, j - 2) = Total(1, j - 2) + aInventory(i, j)
        Next j
    Next i
    '---------------------> Phat sinh trong ky <-------------------------------
    n = 1
    '//Tieu de
    For j = LBound(Data, 2) To UBound(Data, 2)
        Result(n, j) = Data(1, j)
    Next j
    For i = 2 To r
        sItemCode = Data(i, 2)
        If sItemCode = "25" Then
            Debug.Print
        End If
        sInOut = Data(i, 6)
        issueDate = Data(i, 7)
        If dict.Exists(sItemCode) Then Quantity = aInventory(dict.Item(sItemCode), 6)
        sKey = sItemCode & Delim & "X" '// Kiem tra phat sinh nhap xuat
        If (Not dict.Exists(sKey)) Or (Quantity > 0) Or (issueDate >= startDate And issueDate <= endDate) Then
            n = n + 1
            For j = 1 To c
                Result(n, j) = Data(i, j)
            Next j
        End If
    Next i
  
    shResult.Cells.ClearContents
    shResult.Range("A1").Resize(k, UBound(aInventory, 2)).Value = aInventory
    shResult.Range("C2").Resize(, UBound(Total, 2)).Value = Total
    shResult.Range("I1").Resize(n, UBound(Result, 2)).Value = Result
  
    MsgBox "Successful ending,waiting time is: " & Round(Timer() - Tmr, 2) & " second", vbInformation, THVBA

End Sub
Các bạn có thể tham khảo và trao đổi chủ đề này:

BR
 
Sửa lần cuối:

PTHhn

Yêu THVBA như điếu đổ
Trước đây bác mật vụ này cũng có topic trình bày cẩu thả, em có góp ý rồi, mà bác này coi ý kiến người khác như cỏ rác, không tiếp thu, có ý đổ lỗi.
Ngay từ đầu bác ấy nói là bác ấy có lời giải rồi, cái topic này lập ra chẳng qua để xem trình độ code của mọi người tới đâu.
Thông tin yêu cầu thì lắt nhắt, xong rồi output không ra như ý muốn thì phản hồi như sếp, em thấy bác CRV là cũng mát tính đấy. Chứ em năm nay hơn 40 tuổi mà em chưa gặp trường hợp nào nó như thế này cả.
 
  • Haha
Reactions: CRV
Top