dotrung > 07-08-21, 08:04 AM
ongke0711 > 07-08-21, 05:39 PM
(07-08-21, 08:04 AM)dotrung Đã viết: Tuy nhiên, Phần sửa chứng từ đã làm rồi thì dữ liệu subform không hiện ra. Nhờ anh OngKe0711 xem giúp dùm em sai chỗ nào.
Dạ form Danh sách Phiếu có 2 Query để sau kiểm tra trùng sohoadon trên tblPhieuNhapXuat và thiết lập định khoản kế toán về cho nhanh ạ,
dotrung > 07-08-21, 07:19 PM
ongke0711 > 08-08-21, 12:13 AM
(07-08-21, 07:19 PM)dotrung Đã viết: file đã up lại đây anh https://www.mediafire.com/file/k2drglr6a...accdb/file
nút sửa không hoạt động a.
DoCmd.OpenForm Loadedfrm, acNormal, , , , , OpenArgs:="Edit" & "|20" & "|" & ID
Function GetRecordset() 'Nap Du lieu
'Nap du lieu cho Mainform PhieuXuat
strSQL = "SELECT tblPhieuNhapXuat.* FROM tblPhieuNhapXuat WHERE [SoChungTu] ='" & arrArgs(2) & "'"
dotrung > 09-08-21, 09:06 PM
ongke0711 > 10-08-21, 10:10 PM
(09-08-21, 09:06 PM)dotrung Đã viết: Em đã làm được rồi, cảm ơn anh OngKe0711 nhiều, sẵn đây anh Bảo hướng dẫn code nút Sao chép luôn được không, em làm hoài mà nó không hiện ra. thank anh!
DoCmd.OpenForm "frmCapNhatPhieuNhapXuat", acNormal, , , , , OpenArgs:="Copy" & Me.txtctu
'==> sửa lại'
DoCmd.OpenForm "frmCapNhatPhieuNhapXuat", acNormal, , , , , OpenArgs:="Copy|" & Me.txtctu
INSERT INTO tblPhieunhapxuat (SoChungTu, LoaiChungTu, Makhachhang, Khoa, Sovanchuyen, Noidung, Manx, UserID, Gionhap, Macty, NgayTT, Soseri, Banle, GopHD) SELECT LaySTT('tblPhieuNhapXuat',Sochungtu,[Forms]![frmDanhSachPhieuNhapXuat]![txtloai],Day(Date()), tblPhieunhapxuat.LoaiChungTu, tblPhieunhapxuat.Makhachhang, No AS Expr1, " AS Sovanchuyen, tblPhieunhapxuat.Noidung, tblPhieunhapxuat.manx, [Forms]![frmBangDieuKhien]![use] AS Manv, Time() AS Expr4, tblPhieunhapxuat.Macty, tblPhieunhapxuat.NgayTT, tblPhieunhapxuat.Soseri, tblPhieunhapxuat.Banle, tblPhieunhapxuat.GopHDFROM tblPhieunhapxuat WHERE SOCHUNGTu='PX2021070023'
INSERT INTO tblPhieunhapxuat (SoChungTu, LoaiChungTu, Makhachhang, Khoa, Sovanchuyen, Noidung, Manx, UserID, Gionhap, Macty, NgayTT, Soseri, Banle, GopHD) SELECT " & LaySTT([Forms]![frmDanhSachPhieuNhapXuat]!Sochungtu, [Forms]![frmDanhSachPhieuNhapXuat]![txtloai],Day(Date()) & ",
tblPhieunhapxuat.LoaiChungTu,....
dotrung > 11-08-21, 12:28 PM
ongke0711 > 11-08-21, 01:45 PM
(11-08-21, 12:28 PM)dotrung Đã viết: Nút sao chép (tt)
Em đã sửa được mainform nhưng subform load vẫn ko lên được, anh OngKe0711 hướng dẫn thêm em sai chỗ nào ạ, cảm ơn anh!
file https://www.mediafire.com/file/j52rk9dj4...accdb/file
...B.ThueGTGT, '" & [Forms]![frmDanhSachPhieuNhapXuat]![txtsotiep] & "' FROM....
dotrung > 11-08-21, 02:44 PM
ketoan_it > 21-12-22, 10:04 PM
(17-03-20, 02:02 PM)ongke0711 Đã viết: Kỹ thuật huỷ lưu dữ liệu sau khi nhập liệu cho Form ở dạng Main - SubForm.E có tải file UndoSubForm_DAOTransaction, khi nhấn nút Huỷ trên form frmNhap thì bị lỗi và thoát access, e có gán bẫy lỗi thì nhận được thông báo lỗi 91-object variable or with block variable not set.
-------------------------------------------------------------------------------------------------------------------------------
Có nhiều bạn khi thiết kế Form nhập liệu vướng phải vấn đề là:
- Sau khi nhập liệu xong, sai, không muốn lưu thì làm sao? vì Access đã tự động lưu dữ liệu xuống Table khi bạn di chuyển con trỏ (nhảy) qua dòng khác.
- Khi đã nhập liệu nhiều dòng trong SubForm (dạng Datasheet hoặc Continuous) rồi, giờ muốn huỷ tất cả các dòng vừa nhập thì làm như thế nào?
Ở bài này tôi sẽ nói về Form nhập liệu ở dạng Mainform-SubForm. Nếu Form dạng Single Form thì việc "Undo" dữ liệu vừa nhập đã có nhiều bài hướng dẫn rồi. Các bạn có thể tìm kiếm trên diễn đàn, xem thêm bài của bác XuanThanh.
Link: https://thuthuataccess.com/forum/thread-5350.html
Để bàn tới các thủ thuật Huỷ (Undo) lưu dữ liệu khi nhập liệu thì các bạn phải xét tới việc thiết kế Form theo kiểu nào, dạng Unbound Form hay Bound Form vì cách thức xử lý sẽ khác nhau.
- Bound Form là Form có gắn với Record Source (Table, Query) và các control (Textbox, combo...) cũng có Control Source là tên các Field tron Table, Query tương ứng.
- Unbound Form: là Form không có có Record Source và các control trên Form cũng vậy - không có control source.
1. Bound Form:
Đây là điểm mạnh của Access. Nó hỗ trợ việc di chuyển tới lui các record, lưu , thêm, sửa xoá v.v.. rất nhanh, không tốn nhiều code để thực hiện các tác vụ trên như Unbound Form. Một điểm hay cũng là điểm bất tiện của nó là việc Lưu dữ liệu. Sau khi nhập liệu, chỉ cần di chuyển con trỏ chuột qua dòng khác là dữ liệu lưu ngay xuống Table, không cần phải code cho nút Lưu. Nhưng điểm bất tiện của tính năng này là: khi người dùng không muốn Lưu dữ liệu vừa thay đổi đó thì phải viết code để trả lại dữ liệu ban đầu. Vấn đề này sẽ phức tạp hơn nếu nhập liệu nhiều dòng trong liên tiếp như trong Form dạng Datasheet hoặc Continuous. Khi đó ta không thể chạy code của sự kiên Form_ BeforeUpdate vì Access sẽ bật thông báo hỏi có muốn Lưu hay không mỗi khi qua dòng mới, nhập liệu 1 chục dòng , bấm nút trả lời 1 chục lần. Thường thì sau khi nhập 1 lúc nhiều dòng thì người dùng mới bấm Lưu, khi đó thì dữ liệu của Subform cũng đã lưu xuống table rồi, vậy hồi lại các dòng cũ như thế nào. Các giải pháp cho trường hợp này như sau:
- Dùng Table tạm làm RecordSource cho Subform, khi nào bấm nút Lưu sẽ chạy lệnh "INSERT INTO..." ghi dữ liệu xuống Table. Hoặc
- Xoá các record vừa nhập dựa trên Khoá ngoại (Foreign Key) của dữ liệu vừa thêm vào. Thiết lập Relationship với tuỳ chọn "Cascade Delete Related Record" để khi xoá 1 dòng trong Table Cha thì nó tự động xoá luôn nhiều dòng liên quan trong Table Con thông qua khoá ngoại.
- Dùng DAO Transaction như bài bạn maidinhdan vừa chia sẻ.
2. Unbound Form:
Dùng dạng này sẽ ít tốn code cho việc bẫy lỗi khi Lưu, Huỷ lưu dữ liệu. Nhưng phải tốn code để tải dữ liệu lên Form khi Form khởi chạy (Form_Load). Tôi thì thích kiểu nàyn
Mặc dùng là Unbound Form nhưng khi thiết kế ở dạng có Subform đi kèm thì lại phải kết hợp vừa Unbound cho Main form và Bound cho Subform. Không có cách gì thiết kế nhập liệu nhiều dòng cho Subform ở dạng Unbound cả.
Tuỳ sở thích lập trình mà dev chọn kiểu Unbound hay Bound. Tôi thì thích dùng cách Unbound phối hợp như trên hơn.
Giới thiệu cơ bản với các bạn về các kiểu Form để hiểu tại sao phải có các kỹ thuật xử lý khác nhau khi muốn Huỷ lưu trên Form nhập liệu. Sau đây tôi sẽ lần lượt giới thiệu demo các cách xử lý theo từng kiểu Form.
-----------------------------------------------------------------------------------------------------------------------------------------
Phần 1: Bound Form với thiết kế có Main - Subform
- Không dùng Table tạm cho Subform.
- Dùng kỹ thuật DAO Transaction (bạn maidinhdan vừa giới thiệu cho nó nóng sốt ).
Đây là demo nhập liệu Phiếu Nhập/ Xuất cho của một chương trình bán hàng đơn giản. Tôi thiết kế theo quan điểm cá nhân là:
- Có 1 Form danh sách các phiếu nhâp/xuất để có cái nhìn tổng quát các PN/PX đã phát sinh. Đây cũng là Form tìm kiếm luôn.
- Từ Form Danh sách sẽ Xem chi tiết hoặc Sửa các PN/ PX khi double-click vào nó. Có thể thêm mới phiếu từ Form này.
- Các thức tôi code cho form này là:
+ Dùng Bound Form nhưng không gán sẳn Record Source cho Form mà chi khi Load lên mới gán bằng câu lệnh SQL.
+ Khai báo một Workspace. Khi nạp dữ liệu cho Form sẽ bắt đầu transaction: WS.BeginTrans. Khi lưu sẽ WS.CommitTrans. Khi Huỷ sẽ: WS.Rollback. Vì Workspace sẽ có tác động lên toàn bộ Recordset nào đã khai báo khi BeginTrans.
- Chú ý thứ tự code ở các events, nếu sai chút là báo lỗi tùm lùm .
Link demo: https://drive.google.com/open?id=1O0HjQ5...D1ezktg8R5
Code của frmNhap:
Mã PHP:Option Compare Database
Option Explicit
Dim arrArgs() As String
Private Sub cmdClose_Click()
Set WS = Nothing 'Phai dóng WS, neu không Access không thoát hoan toàn.
DoCmd.Close
End Sub
Private Sub cmdHuy_Click()
WS.Rollback
WS.BeginTrans
Me.Refresh 'Tránh báo lõi #name khi click nhieu lan.
End Sub
Private Sub cmdLuu_Click()
WS.CommitTrans
SetFormState False
Me.Recalc 'De AllowEdit có tác dung
'Requery các form liên quan
Select Case arrArgs(2)
Case "frmDSPhieuNhapXuat"
Forms!frmDSPhieuNhapXuat!sfmDSPhieuNX.Requery
Case Else
'do nothing
End Select
End Sub
Private Sub cmdThem_Click()
'Xu ly WS de tranh loi khi them moi.
If Me.cmdLuu.Enabled = True Then
If msgBoxUni("B" & ChrW(7841) & "n có mu" & ChrW(7889) & "n L" & ChrW(432) & "u d" & ChrW(7919) & " li" & ChrW(7879) & "u hi" & ChrW(7879) & "n t" & ChrW(7841) & "i tr" & ChrW(432) & ChrW(7899) & "c khi m" & ChrW(7903) & " phi" & ChrW(7871) & "u m" & ChrW(7899) & "i?", vbQuestion + vbYesNo, "Thông báo") = vbYes Then
WS.CommitTrans 'Phai ket thuc phiên Transaction cu, moi gan rs cho subF duoc.
Else
WS.Rollback
End If
End If
arrArgs(0) = "Add"
NapPhieuNhap
SetFormState True
End Sub
Private Sub Form_Load()
Set WS = DBEngine.Workspaces(0)
If Len(Nz(Me.OpenArgs, "")) > 0 Then
arrArgs = Split(Me.OpenArgs, "|")
Else 'Mo tu Menu
ReDim arrArgs(0 To 2) As String
arrArgs(0) = "Add"
arrArgs(1) = ""
arrArgs(2) = ""
End If
NapPhieuNhap
End Sub
Sub NapPhieuNhap()
Dim db As DAO.Database
'Dim rs As DAO.Recordset, rs2 As DAO.Recordset '-->Khai báo toàn cuc
Dim strSQL As String, strSQL2 As String
Set db = CurrentDb
Select Case arrArgs(0)
Case "Add"
strSQL = "SELECT * FROM tblNhapXuat WHERE 1=2"
strSQL2 = "SELECT 'Xóa' As Xoa,* FROM tblNhapXuat_CT WHERE 1=2"
Case "Edit"
strSQL = "SELECT * FROM tblNhapXuat WHERE ID=" & arrArgs(1)
strSQL2 = "SELECT 'Xóa' As Xoa, * FROM tblNhapXuat_CT WHERE IDPhieu=" & arrArgs(1)
End Select
Set rs = Nothing 'Tránh lõi khi gán rs moi, khi chon dòng khác - Sua
Set rs = db.OpenRecordset(strSQL, dbOpenDynaset)
Set Me.Recordset = rs
Set rs2 = Nothing
Set rs2 = db.OpenRecordset(strSQL2, dbOpenDynaset)
If rs2.BOF And rs2.EOF Then
'Bãy lôi khi mo recordset thêm moi. Chua có du lieu de MoveLast.
Else
rs2.MoveLast 'Phai activate rs2 de lay toàn bo record gán vào SubF, neu không se treo ung dung.
End If
Set Me.sfmNhapXuatCT.Form.Recordset = rs2
WS.BeginTrans
End Sub
Sub SetFormState(blnState As Boolean)
Me.cmdClose.SetFocus
Me.cmdLuu.Enabled = blnState
Me.cmdHuy.Enabled = blnState
Me.cmdThem.Enabled = blnState
Me.AllowEdits = blnState
Me.cmdThem.Enabled = Not blnState
Me.sfmNhapXuatCT.Locked = Not blnState
End Sub
----------------------------------------------------------------------------------------------------------------------------
Bài kế tiếp sẽ làm demo kỹ thuật khác cho UnBound Form với thiết kế có Main - Subform