Dùng các phương thức Find của Recordset

phatnq2002

Tích cực giảm cân...
Hội viên mới
Trong bài này, tôi sẽ nói việc sử dụng các phương thức Find của một đối tượng Recordset thuộc thư viện DAO.

Trước tiên, xin lưu ý trong thư viện ADO cũng có đối tượng Recordset, nhưng phương thức Find của đối tượng này sẽ khác với phương thức Find của DAO.Recordset.

Có bốn phương thức Find của DAO.Recordset:
- FindFirst: khi gọi phương thức này, con trỏ record sẽ nhảy ngay về record đầu tiên và tiến hành việc tìm kiếm record đầu tiên thỏa điều kiện tìm. Trong trường hợp recordset không có record nào (RecordCount = 0) thì phương thức này sẽ gây ra một lỗi khi gọi nó.
- FindNext: khi gọi phương thức này, việc tìm kiếm sẽ thực hiện bắt đầu từ vị trí record mà con trỏ record đang đứng đến record cuối cùng. Cũng tương tự như FindFirst, Trong trường hợp recordset không có record nào (RecordCount = 0) thì phương thức này sẽ gây ra một lỗi khi gọi nó. Ngoài ra nếu khi đã con trỏ record duyệt tới record EOF (End of File) mà phương thức này được gọi thì sẽ xảy ra một lỗi.
- FindPrevious: khi gọi phương thức này, việc tìm kiếm sẽ thực hiện bắt đầu từ vị trí record mà con trỏ record đang đứng trở về record đầu tiên. Cũng tương tự như FindFirst, Trong trường hợp recordset không có record nào (RecordCount = 0) thì phương thức này sẽ gây ra một lỗi khi gọi nó. Ngoài ra nếu khi đã con trỏ record duyệt tới record BOF (Begin of File) mà phương thức này được gọi thì sẽ xảy ra một lỗi.
- FindLast: khi gọi phương thức này, con trỏ record sẽ nhảy ngay về record cuối cùng và tiến hành việc tìm kiếm record đầu tiên thỏa điều kiện tìm nhưng ngược từ dưới lên. Trong trường hợp recordset không có record nào (RecordCount = 0) thì phương thức này sẽ gây ra một lỗi khi gọi nó.

Cách gọi phương thức:
đối_tượng_recordset.FindFirst điều_kiện
đối_tượng_recordset.FindNext điều_kiện
đối_tượng_recordset.FindPreviuos điều_kiện
đối_tượng_recordset.FindLast điều_kiện

Trong đó điều_kiện là chuỗi thể hiện nội dung tìm kiếm.

Để minh họa cho cách sử dụng các phương thức trên, chúng ta đặt ra một bài toán sau:
Giả sử chúng ta thiết kế một form nhập liệu danh sách khách hàng (makh, tenkh, diachi). Trong form này có một nút Tìm (cmdFind). Khi nhấn nút này sẽ cho hiện ra một form khác để người sử dụng nhập vào tên khách hàng cần tìm (textbox tenkh) và 3 nút: Thi hành (cmdFind), Tìm tiếp (cmdFindNext) và Thôi (cmdClose).
Khi nhấn nút Thi hành sẽ cho thực hiện một thủ tục, trong đó tìm kiếm xem có khách hàng nào thỏa mãn điều kiện tìm không. Nếu có thì cho hiển thị thông tin của khách hàng đó ở form KhachHang. Nếu không thì báo là không tìm thấy.
Khi nhấn nút Tiếp, sẽ cho thực hiện một thủ tục xem có khách hàng nào còn thỏa mãn điều kiện tìm không. Nếu có thì cho hiển thị thông tin của khách hàng đó ở form KhachHang. Nếu không thì báo là không còn tìm thấy.
Nút Thôi chủ yếu là đóng form Tim lại mà thôi.

Bây giờ vào code đây:

Bước 1: ở form KhachHang, thiết lập thủ tục sự kiện Click cho nút lệnh cmdFind như sau:
DoCmd.OpenForm "TIM" ' Để cho hiển thị form Tim

Bước 2: Ở form Tim, trong khu vực Declaration (tức là dưới dòng lệnh Option Explicit và/hoặc Option Compare Database), cho dòng lệnh khai báo sau:
Dim st As String, rs As DAO.Recordset

Thiết lập các thủ tục sự kiện sau:

Private Sub Form_Load ()
Set rs = Forms("KHACHHANG").RecordsetClone ' gán dữ liệu nguồn của form KhachHang vào recordset
End Sub

Private Sub cmdFind_Click ()
st = "tenkh LIKE '*" & tenkh & "*'" 'dùng toán tử LIKE để tìm kiếm tương đối
On Error GoTo loi_Find
rs.FindFirst st
If rs.NoMatch Then ' nếu không tìm thấy
MsgBox "Không tìm thấy."
Else
Forms("KHACHHANG").Bookmark = rs.Bookmark 'cho hiển thị lên form KhachHang thông tin khách đã tìm thấy
End If
thoat_Find:
Exit Sub
loi_Find:
MsgBox "Lỗi. Có thể danh sách khách hàng đang trống."
Resume thoat_Find
End Sub

Private Sub cmdFindNext_Click ()
On Error GoTo loi_FindNext
rs.FindNext st
If rs.NoMatch Then ' nếu không tìm thấy nữa
MsgBox "Không còn tìm thấy."
Else
Forms("KHACHHANG").Bookmark = rs.Bookmark 'cho hiển thị lên form KhachHang thông tin khách đã tìm thấy
End If
thoat_FindNext:
Exit Sub
loi_FindNext:
MsgBox "Lỗi. Có thể danh sách khách hàng đang trống."
Resume thoat_FindNext
End Sub

Private Sub cmdClose_Click ()
DoCmd.Close acForm, Me.Name
End Sub


Trên chỉ là những đoạn code chính, các bạn có thể thêm mắm muối vào cho hợp ý mình.

Thấy hay thì vỗ tay, còn dỡ thỉ chê ít ít thôi cho đỡ quê !!!
 
Phatnq2002 ơi bạn có thể gởi vd đính kèm không? Mình thử làm nhưng không được.
 
Phat oi ban có thể giúp tôi phân biệt giửa "Seek" và "Find" không? mình thắc mắc lâu rồi và cũng đã hỏi bạn 1 lần nhưng chưa thấy hồi âm.

Còn về Vd của bạn mình thấy không cần dùng đến Find method mà chì cần làm một form với source là 1 query, ờ cột mã khách hàng mình đặt điều kiện là like * Name và kết hợp với thuộc tính afterupdate là xong


Các bạn có thể tham khảo vd về dan mục khách hàng qua ví dụ đính kẻm của mình

danhmuckhachhangxy6.jpg


Download : Tại đây
 
Cám ơn Phatnq2002, Bài viết của bạn có hệ thống và hay quá. Mình không hiểu bookmark là gì bạn có thể hướng dẫn mình cách sử dụng không?

Mã:
Forms("KHACHHANG").Bookmark = rs.Bookmark
 
Bạn Simon mến:
Bạn dùng Seek khi bạn mở recordset theo mode table, nghĩa là:
Dim rs = CurrentDB.OpenRecordset("source", dbOpenTable)
và đồng thời bạn mở kèm chỉ mục:
rs.Index = "index_name"
Khi đó phương thức Seek sẽ mặc định dò tìm trên các trường thuộc khóa Index mà bạn đang mở cho Recordset. Nói tóm lại, Seek là phương thức tìm kiếm theo chỉ mục.
Còn Find là phương thức tìm kiếm dựa theo điều kiện tìm kiếm bất kỳ trên recordset mở theo bất kỳ mode nào.
Vấn đề thứ hai, đó cũng là một cách giải quyết tốt. Tuy nhiên, mục đích ví dụ của tôi chủ yếu để minh họa thôi.

Bạn bichtram mến:
Cái ví dụ tôi đưa là do tôi "tự chế", nên không có source gốc. :D bạn thông cảm nhé.

Bạn binhnt mến:
Bookmark là một thuộc tính của recordset trả về một giá trị chuỗi định vị một record. Mỗi record có một bookmark riêng, không trùng lặp.
Ngoài ra bạn có thể tham khảo thuộc tính AbsolutePosition (trả về dữ liệu kiểu số) chỉ ra số thứ tự vật lý của record. Record đầu tiên có AbsolutePosition bằng 0.
 
Cám ơn Phát nhiều ( Không biết tên bạn có phải không). Nhưng mình cung chưa hiểu rõ phương thức seek này lắm. Mình đọc sách thấy Index = primarykey, vậy index và seek liên hệ như thế nào?

Hình như seek có thể có nhiều điều kiện , bạn có thể cho mình một vd không?

Thanks trước nhé
 
Seek là một phương thức tìm kiếm dựa trên một chỉ mục được mở cho recordset hiện hành mà bạn đang làm việc với nó.

Cú pháp của Seek:
recordset.Seek comparison, key1, key2...key13

Trong đó:
comparison: là một trong những toán tử so sánh sử dụng trong việc dò tìm: <, <=, >=, >
key1, key2, ..., key13: các giá trị tương ứng với các field của index được mở được sử dụng như giá trị tìm kiếm.

Dưới đây là ví dụ lấy từ Help của Microsoft để bạn tham khảo.
Thủ tục dưới đây mở table Products theo chế độ Table, đồng thời mở chỉ mục đi kèm là chỉ mục khóa chính (Primary key) - có thể hiểu là sẽ tìm kiếm trên field ProductID. Sau đó cho người dùng nhập vào một mã số ID, nếu tìm thấy thì hiển thị thông tin của Prodcut đó, nếu không thì thông báo không tìm thấy. Nếu người dùng không nhập thì chấm dứt tìm.

Sub SeekX()
Dim dbsNorthwind As Database
Dim rstProducts As Recordset
Dim intFirst As Integer
Dim intLast As Integer
Dim strMessage As String
Dim strSeek As String
Dim varBookmark As Variant
Set dbsNorthwind = OpenDatabase("Northwind.mdb")
' You must open a table-type Recordset to use an index,
' and hence the Seek method.
Set rstProducts = _
dbsNorthwind.OpenRecordset("Products", dbOpenTable)
With rstProducts
' Set the index.
.Index = "PrimaryKey"
' Get the lowest and highest product IDs.
.MoveLast
intLast = !ProductID
.MoveFirst
intFirst = !ProductID
Do While True
' Display current record information and ask user
' for ID number.
strMessage = "Product ID: " & !ProductID & vbCr & _
"Name: " & !ProductName & vbCr & vbCr & _
"Enter a product ID between " & intFirst & _
" and " & intLast & "."
strSeek = InputBox(strMessage)
If strSeek = "" Then Exit Do
' Store current bookmark in case the Seek fails.
varBookmark = .Bookmark
.Seek "=", Val(strSeek)
' Return to the current record if the Seek fails.
If .NoMatch Then
MsgBox "ID not found!"
.Bookmark = varBookmark
End If
Loop
.Close
End With
dbsNorthwind.Close
End Sub
 
Ðề: Dùng các phương thức Find của Recordset

Các bạn cần hiểu rõ bạn chất của SEEK và FINDFIRST để tận dụng khả năng làm việc với CSDL lớn:
SEEK là phép tìm kiếm trên trường đã được SORT cho nên thời gian tìm kiếm sẽ nhanh hơn. Ví dụ Table "Nhanvien" có trường "Hoten" được sắp xếp, và ta muốn tìm với nội dung "Lê". Khi chương trình tìm tới vần "M" mà không thấy sẽ dừng tìm kiếm và ra thông báo "Không thấy". Như vậy muốn sử dụng SEEK bạn phải có khai báo .INDEX=....
Nhưng FINDFIRST thì nó cứ ngó ngẩn tìm hoài cho đến cùng nếu nó không tìm thấy cái nó cần.
 
Ðề: Dùng các phương thức Find của Recordset

Các bạn cần hiểu rõ bạn chất của SEEK và FINDFIRST để tận dụng khả năng làm việc với CSDL lớn:
SEEK là phép tìm kiếm trên trường đã được SORT cho nên thời gian tìm kiếm sẽ nhanh hơn. Ví dụ Table "Nhanvien" có trường "Hoten" được sắp xếp, và ta muốn tìm với nội dung "Lê". Khi chương trình tìm tới vần "M" mà không thấy sẽ dừng tìm kiếm và ra thông báo "Không thấy". Như vậy muốn sử dụng SEEK bạn phải có khai báo .INDEX=....
Nhưng FINDFIRST thì nó cứ ngó ngẩn tìm hoài cho đến cùng nếu nó không tìm thấy cái nó cần.

Mỗi phương thức tìm có những ưu điểm và nhược điểm của nó.
Nếu một table có chứa dữ liệu mà có thể tạo ra nhiều truy vấn tìm kiếm thì không lẽ chúng ta phải tạo sẵn tất cả các chỉ mục?
Và liệu rằng từng ấy chỉ mục bạn tạo sẵn đã đáp ứng nhu cầu của người dùng.
Trường hợp khác nếu bạn tạo ra một dạng "tìm kiếm động", cón nghĩa là biểu thức điều kiện tìm kiếm sẽ tùy biến theo ý người sử dụng dựa trên một số field mà bạn đề nghị (VD dùng 4 field để tạo nội dung tìm kiếm) thì bạn cần có sẵn 1 x 2 x 3 x 4 = 24 chỉ mục tạo sẵn. Bạn có đủ can đảm làm điều đó không?
Một vấn đề khác, khi bạn mở một recordset có từ khóa ORDER BY thì có khác gì đâu giữa SEEK và Find ? Bởi nếu tìm không thấy nó cũng nhảy đến EOF cơ mà? Có lẽ chỗ này bạn nhầm chăng?
Tôi không có tham vọng áp đặt các bạn phải dùng theo kiểu của tôi mà tôi chỉ muốn rằng những kinh nghiệm mà tôi đã làm sẽ có ích cho các bạn thôi.
 
Ðề: Dùng các phương thức Find của Recordset

Sau khi thực hành xong thấy cũng ổn nhưng còn một số vấn đề sau :
- Nếu tìm thấy 1 người, xong thoát về form chính thì không vấn đề gì, nhưng nếu đến người thứ 2 trở lên thì bất tiện ở chổ sẽ không biết người thứ nhất là ai? (vì bị cái form "Tim" che mất). giải pháp là phải làm cái form "tìm" thật nhỏ. Nếu mình muốn hiện Msgbox báo cho mình biết đã tìm thấy tên gì và một số chi tiết khác thì làm cách nào?
-Tôi muốn tìm chính xác họ tên, không dùng LIKE thì phải code như thế nảo
- muốn cho form luôn nằm ở góc trái, phía trên màn hình thì phải làm sao? (để khỏi che mất form chính)
Kính mong các bác giải đáp giúp !!!
 
Sửa lần cuối:
Ðề: Dùng các phương thức Find của Recordset

Sau khi thực hành xong thấy cũng ổn nhưng còn một số vấn đề sau :
- Nếu tìm thấy 1 người, xong thoát về form chính thì không vấn đề gì, nhưng nếu đến người thứ 2 trở lên thì bất tiện ở chổ sẽ không biết người thứ nhất là ai? (vì bị cái form "Tim" che mất). giải pháp là phải làm cái form "tìm" thật nhỏ. Nếu mình muốn hiện Msgbox báo cho mình biết đã tìm thấy tên gì và một số chi tiết khác thì làm cách nào?
-Tôi muốn tìm chính xác họ tên, không dùng LIKE thì phải code như thế nảo
- muốn cho form luôn nằm ở góc trái, phía trên màn hình thì phải làm sao? (để khỏi che mất form chính)
Kính mong các bác giải đáp giúp !!!

Giả sử form chính của bạn có tên là frmMAIN, thì ở form tìm, khi tìm ra và nhảy đến record đó xong thì bạn cho một cái mesage đại loại như sau:
MsgBox ("Mã số: " & Forms("frmMAIN").maso & chr(13) & "Họ và tên: " & Forms("frmMAIN").hoten)

Trong đó Chr(13) là ký tự xuống dòng.

Muốn form luôn nằm góc trái trên thì đừng chọn thuộc AutoCenter = Yes nữa.
 
Ðề: Dùng các phương thức Find của Recordset

Bạn Simon mến:
Bạn dùng Seek khi bạn mở recordset theo mode table, nghĩa là:
Dim rs = CurrentDB.OpenRecordset("source", dbOpenTable)
và đồng thời bạn mở kèm chỉ mục:
rs.Index = "index_name"
Khi đó phương thức Seek sẽ mặc định dò tìm trên các trường thuộc khóa Index mà bạn đang mở cho Recordset. Nói tóm lại, Seek là phương thức tìm kiếm theo chỉ mục.
Còn Find là phương thức tìm kiếm dựa theo điều kiện tìm kiếm bất kỳ trên recordset mở theo bất kỳ mode nào.
Vấn đề thứ hai, đó cũng là một cách giải quyết tốt. Tuy nhiên, mục đích ví dụ của tôi chủ yếu để minh họa thôi.

Bạn bichtram mến:
Cái ví dụ tôi đưa là do tôi "tự chế", nên không có source gốc. :D bạn thông cảm nhé.

Bạn binhnt mến:
Bookmark là một thuộc tính của recordset trả về một giá trị chuỗi định vị một record. Mỗi record có một bookmark riêng, không trùng lặp.
Ngoài ra bạn có thể tham khảo thuộc tính AbsolutePosition (trả về dữ liệu kiểu số) chỉ ra số thứ tự vật lý của record. Record đầu tiên có AbsolutePosition bằng 0.

Bạn cho mình hỏi khi dùng:
Dim rs = CurrentDB.OpenRecordset("source", dbOpenTable)
thì trên file mdb chạy tốt. Nhưng khi dùng lệnh Tools\Database Utilities\database splitter để tách file database ra thì thông báo lỗi Runtime-error "3219". Xin bạn chỉ dẫn, cảm ơn nhiều.
 
Ðề: Dùng các phương thức Find của Recordset

Tôi muốn thiết kế một form lọc dữ liệu như sau:
form mẹ có một textbox, một command button và một form con
form con là một danh sách bao gồm các trường: Mã số, Họ tên, địa chỉ
Khi đánh vào textbox họ tên một người hoặc một phần họ tên thì form con chỉ còn lại danh sách người có họ tên giống như textbox hoặc người có họ tên có phần giống như trong textbox. Tôi phải làm như thế nào, mong các bạn giúp đỡ.
 
Ðề: Dùng các phương thức Find của Recordset

Tôi muốn thiết kế một form lọc dữ liệu như sau:
form mẹ có một textbox, một command button và một form con
form con là một danh sách bao gồm các trường: Mã số, Họ tên, địa chỉ
Khi đánh vào textbox họ tên một người hoặc một phần họ tên thì form con chỉ còn lại danh sách người có họ tên giống như textbox hoặc người có họ tên có phần giống như trong textbox. Tôi phải làm như thế nào, mong các bạn giúp đỡ.

Giả sử bạn đã thiết kế:
1. Form con: tên frmDanhsach
RecordSource là table chứa các field maso, hoten, diachi (vd tên table là tblDanhsach)
Default view: Datasheet
từ field list kéo vào 3 field: maso, hoten, diachi.
2. Form chính:
Textbox có tên là txtFilter,
Command button có tên là cmdFilter,
Một subform: tên subFilter
Source Object: frmDanhsach

Bây giờ bạn làm cái thủ tục event cho nút lệnh như sau:

Private Sub cmdFilter_Click ()
Dim st As String
If IsNull(txtFilter) Then
st = "SELECT * FROM tblDanhsach"​
Else
st = "SELECT * FROM tblDanhSach WHERE hoten LIKE '*" & Trim(txtFilter) & "*'"​
Endif
subCT.Form.RecordSource = st
subCT.Form.Requery
End Sub
 
Ðề: Dùng các phương thức Find của Recordset

Giả sử bạn đã thiết kế:
1. Form con: tên frmDanhsach
RecordSource là table chứa các field maso, hoten, diachi (vd tên table là tblDanhsach)
Default view: Datasheet
từ field list kéo vào 3 field: maso, hoten, diachi.
2. Form chính:
Textbox có tên là txtFilter,
Command button có tên là cmdFilter,
Một subform: tên subFilter
Source Object: frmDanhsach

Bây giờ bạn làm cái thủ tục event cho nút lệnh như sau:

Private Sub cmdFilter_Click ()
Dim st As String
If IsNull(txtFilter) Then
st = "SELECT * FROM tblDanhsach"​
Else
st = "SELECT * FROM tblDanhSach WHERE hoten LIKE '*" & Trim(txtFilter) & "*'"​
Endif
subCT.Form.RecordSource = st
subCT.Form.Requery
End Sub

Tôi cũng tao form như ban hướng dẫn nhưng bị lỗi:

subCT.Form.RecordSource = st
subCT.Form.Requery


Xin bạn hướng dẫn cách xử lý lỗi!
-----------------------------------------------------------------------------------------
Tôi đã xử ly được rồi! Cam ơn!
 
Sửa lần cuối:
Ðề: Dùng các phương thức Find của Recordset

Bước 1: ở form KhachHang, thiết lập thủ tục sự kiện Click cho nút lệnh cmdFind như sau:
DoCmd.OpenForm "TIM" ' Để cho hiển thị form Tim

Bước 2: Ở form Tim, trong khu vực Declaration (tức là dưới dòng lệnh Option Explicit và/hoặc Option Compare Database), cho dòng lệnh khai báo sau:
Dim st As String, rs As DAO.Recordset

Thiết lập các thủ tục sự kiện sau:

Private Sub Form_Load ()
Set rs = Forms("KHACHHANG").RecordsetClone ' gán dữ liệu nguồn của form KhachHang vào recordset
End Sub

Private Sub cmdFind_Click ()
st = "tenkh LIKE '*" & tenkh & "*'" 'dùng toán tử LIKE để tìm kiếm tương đối
On Error GoTo loi_Find
rs.FindFirst st
If rs.NoMatch Then ' nếu không tìm thấy
MsgBox "Không tìm thấy."
Else
Forms("KHACHHANG").Bookmark = rs.Bookmark 'cho hiển thị lên form KhachHang thông tin khách đã tìm thấy
End If
thoat_Find:
Exit Sub
loi_Find:
MsgBox "Lỗi. Có thể danh sách khách hàng đang trống."
Resume thoat_Find
End Sub

Private Sub cmdFindNext_Click ()
On Error GoTo loi_FindNext
rs.FindNext st
If rs.NoMatch Then ' nếu không tìm thấy nữa
MsgBox "Không còn tìm thấy."
Else
Forms("KHACHHANG").Bookmark = rs.Bookmark 'cho hiển thị lên form KhachHang thông tin khách đã tìm thấy
End If
thoat_FindNext:
Exit Sub
loi_FindNext:
MsgBox "Lỗi. Có thể danh sách khách hàng đang trống."
Resume thoat_FindNext
End Sub

Private Sub cmdClose_Click ()
DoCmd.Close acForm, Me.Name
End Sub


Trên chỉ là những đoạn code chính, các bạn có thể thêm mắm muối vào cho hợp ý mình.

Thấy hay thì vỗ tay, còn dỡ thỉ chê ít ít thôi cho đỡ quê !!!



Mình xin vỗ tay nhiệt liệt cho những bài viết như thế này. Thax bạn nhìu. Nhưng cho minh hỏi tại sao khi mình viết đoạn mã load form: Set rs = Forms("KHACHHANG").RecordsetClone thì bị báo lỗi không tìm thấy Forms, mặc dù mình đã tạo Form đó rồi. Mong được sự giúp đỡ sơm từ bạn. Bạn có thể xem File này và sửa hộ mình với http://www.mediafire.com/file/idgttmnfklv/db5.rar
 
Ðề: Dùng các phương thức Find của Recordset

Mình xin vỗ tay nhiệt liệt cho những bài viết như thế này. Thax bạn nhìu. Nhưng cho minh hỏi tại sao khi mình viết đoạn mã load form: Set rs = Forms("KHACHHANG").RecordsetClone thì bị báo lỗi không tìm thấy Forms, mặc dù mình đã tạo Form đó rồi. Mong được sự giúp đỡ sơm từ bạn. Bạn có thể xem File này và sửa hộ mình với http://www.mediafire.com/file/idgttmnfklv/db5.rar

Cái form KHACHHANG phải đang mở thì mới sử dụng được cú pháp đó.
Bởi trong Access, Forms là một collection các form đang mở ra, không phải là tất cả các form có trong database Access.
 
Ðề: Dùng các phương thức Find của Recordset

cam on. dung vay. nhung khi minh tim thi ko dc. no cu bao danh sach trong
 
Ðề: Dùng các phương thức Find của Recordset

Bác Phat ơi em hỏi chút !
Có cách nào bôi đen từ vừa tìm kiếm được không bác.
Thanks bác.
 

CẨM NANG KẾ TOÁN TRƯỞNG


Liên hệ: 090.6969.247

KÊNH YOUTUBE DKT

Cách làm file Excel quản lý lãi vay

Đăng ký kênh nhé cả nhà

SÁCH QUYẾT TOÁN THUẾ


Liên hệ: 090.6969.247

Top