Hello, xin chào quý anh chị và các bạn đam mê AppSheet. Hôm nay mình quay trở lại với một cái mẹo nhỏ nhưng rất hữu ích: làm sao để khóa một đơn hàng lại, sao cho khi đơn hàng đã khóa thì phần đơn hàng chi tiết (bảng con của đơn hàng) cũng tự động không cho thêm, sửa, xóa dữ liệu nữa – mà không cần tạo slice để lọc dữ liệu.
Mục lục.
Trong bài này mình sẽ đi qua:
- Thiết kế dữ liệu mẫu gồm Đơn hàng và Đơn hàng chi tiết
- Vì sao cách ẩn nút Add bằng slice hoặc bằng behavior thông thường lại không ăn thua với dữ liệu con
- Cách khóa “tận gốc” ngay trong chính dữ liệu, bằng vài công thức đơn giản
- Tạo action để khóa/mở đơn hàng bằng một nút bấm
Video :Mẹo AppSheet: khóa dòng dữ liệu – không cho thêm, sửa, xóa trong đơn hàng chi tiết
Lưu ý: ngay phút 11:07 mình có nói nhầm ký tự rỗng ” ” là 0, mọi người để ý sửa lại dùm mình hén.
Vì sao ẩn nút Add kiểu thông thường không đủ
Trong AppSheet, đơn hàng chi tiết thường là bảng con (child table) của đơn hàng chính, liên kết với nhau qua cột tham chiếu (Ref). Nhiều người hay dùng cách ẩn nút Add của hệ thống bằng slice, tức là tạo một slice lọc dữ liệu rồi không cho add/delete trong slice đó. Cách này tốn khá nhiều thời gian và hơi phức tạp: phải tạo thêm slice, thêm view mới để gọi dữ liệu ra, rồi mới ẩn add/delete trên view đó.
Ngoài ra, nếu chỉ đặt điều kiện ẩn nút Add theo CONTEXT("View") (ví dụ ẩn khi đang ở view dạng Form), thì nút Add vẫn có thể hiện ra ở những view khác như Detail, nên người dùng vẫn thêm được dữ liệu bình thường. Nói cách khác, ẩn nút chỉ là ẩn trên giao diện, không thật sự khóa được dữ liệu.
Vì vậy, hôm nay mình sẽ đi theo hướng khác: khóa ngay trong chính dữ liệu bằng một số công thức, để dù người dùng vào bất kỳ view nào cũng không thêm/sửa/xóa được.
Thiết kế bảng dữ liệu mẫu
Trước tiên mình tạo một file Google Sheet gồm hai bảng.
Bảng Đơn hàng (bảng cha), gồm các cột:
- ID – khóa chính của đơn hàng
- Tên khách hàng
- Tình trạng – kiểu Enum, gồm 2 giá trị:
Đang mởvàĐã khóa
Bảng Đơn hàng chi tiết (bảng con), gồm các cột:
- ID – khóa chính, kiểu Unique ID
- ID đơn hàng – Ref tham chiếu qua bảng Đơn hàng, đây là cột giúp Đơn hàng chi tiết trở thành “đơn con” (child record) của Đơn hàng
- Sản phẩm
- Số lượng
Sau khi có hai bảng, mình vào AppSheet tạo ứng dụng mới từ chính Google Sheet này, khai báo lại kiểu dữ liệu cho từng cột cho đúng: cột Tình trạng khai báo là Enum với hai giá trị Đang mở và Đã khóa, cột ID đơn hàng bên bảng Đơn hàng chi tiết khai báo là Ref trỏ về bảng Đơn hàng.
Với bảng Đơn hàng chi tiết, mình đặt luôn giá trị khởi tạo (Initial Value) cho cột Tình trạng – thật ra ở đây tình trạng nằm trên bảng Đơn hàng, còn Đơn hàng chi tiết chỉ cần tham chiếu qua để biết đơn hàng cha đang ở trạng thái nào.
Không cho sửa trạng thái trực tiếp trên form
Bình thường nếu để người dùng tự do sửa cột Tình trạng ngay trên form nhập liệu thì rất dễ bị đổi lộn xộn. Vì vậy, mình đặt điều kiện Editable_If cho cột Tình trạng của bảng Đơn hàng như sau:
CONTEXT("View") <> "Form"
Nghĩa là cột Tình trạng sẽ không cho sửa khi đang ở trong giao diện Form (thêm mới hoặc chỉnh sửa). Mặc định giá trị này sẽ luôn là Đang mở khi tạo đơn hàng mới, và chỉ được đổi thành Đã khóa thông qua một action riêng – mình sẽ tạo action đó ở phần sau.
Tạo action để khóa đơn hàng
Tiếp theo mình tạo một action tên là Khóa đơn hàng trên bảng Đơn hàng, dùng loại Data: set the values of some columns in this row. Action này chỉ làm một việc: gán giá trị cột Tình trạng thành Đã khóa.
Mình đặt điều kiện hiển thị (Only if this condition is true) cho action này là:
[Tình trạng] = "Đang mở"
Như vậy nút Khóa đơn hàng chỉ hiện ra khi đơn hàng đang ở trạng thái mở. Sau khi bấm khóa, đơn hàng chuyển sang Đã khóa và nút này tự động biến mất, vì điều kiện hiển thị không còn đúng nữa.
Chặn thêm dòng mới vào đơn hàng chi tiết khi đơn hàng đã khóa
Đây là phần mấu chốt của cả bài. Bình thường cột ID của Đơn hàng chi tiết được AppSheet tự sinh mã ngẫu nhiên bằng hàm UNIQUEID() mỗi khi thêm dòng mới. Mình sẽ thay công thức Initial Value của cột ID này bằng một công thức có điều kiện, kiểm tra tình trạng của đơn hàng cha trước khi sinh mã:
IF([ID đơn hàng].[Tình trạng] = "Đã khóa"," ", UNIQUEID())
Ý nghĩa: nếu đơn hàng cha (được tham chiếu qua cột ID đơn hàng) đang ở tình trạng Đã khóa, thì cột ID của dòng chi tiết mới sẽ được gán giá trị là ký tự rỗng: (" ")<== trong video mình nói lộn thành 0 nhưng nó là rỗng mới đúng nha thay vì sinh mã ngẫu nhiên. Vì ” ” <= (ký tự rỗng) là một giá trị khóa chính không hợp lệ (trùng nếu có nhiều dòng cùng bị chặn), AppSheet sẽ không cho lưu dòng dữ liệu này – người dùng bấm thêm sản phẩm vào một đơn hàng đã khóa sẽ bị báo lỗi thiếu khóa chính hợp lệ, và không thêm được.
Ngược lại, nếu đơn hàng cha vẫn đang Đang mở, công thức sẽ chạy UNIQUEID() để sinh mã như bình thường, mọi thứ hoạt động y hệt lúc chưa khóa.
Ngoài ra, mình đặt cột ID đơn hàng (Ref) là bắt buộc nhập (Required), ẩn cột ID đi để người dùng không đụng vào, và không cho sửa (Editable_If = FALSE) vì giá trị này gắn liền với đơn hàng cha, không nên bị đổi tùy tiện.
Chặn sửa và xóa dòng chi tiết khi đơn hàng đã khóa
Thêm dữ liệu mới bị chặn rồi, nhưng nếu đơn hàng đã có sẵn vài dòng chi tiết từ trước khi khóa thì sao? Mình cần chặn luôn cả việc sửa và xóa những dòng đó.
Cách làm là vào action Edit và action Delete mặc định của bảng Đơn hàng chi tiết, đặt lại điều kiện hiển thị (Only if this condition is true) như sau:
[ID đơn hàng].[Tình trạng] = "Đang mở"
Với điều kiện này, hai action Edit và Delete chỉ hiện ra khi đơn hàng cha còn đang mở. Ngay khi đơn hàng chuyển sang Đã khóa, cả hai nút sửa và xóa trên từng dòng chi tiết đều biến mất, người dùng chỉ có thể xem chứ không thao tác được gì thêm.
Kiểm tra kết quả
Sau khi hoàn tất, mình thử lại toàn bộ luồng:
- Với đơn hàng đang
Đang mở: thêm sản phẩm bình thường, sửa xóa dòng chi tiết bình thường. - Bấm nút Khóa đơn hàng: đơn hàng chuyển sang
Đã khóa, nút khóa biến mất. - Thử thêm sản phẩm mới vào đơn hàng vừa khóa: AppSheet báo lỗi vì cột ID bị gán về ” “<== rỗng, không lưu được.
- Các dòng chi tiết đã có sẵn: không còn thấy nút sửa hay xóa nữa, chỉ xem được thông tin.
Một lưu ý nhỏ: cách khóa này chỉ tác động tới các thao tác thêm/sửa/xóa từ phía người dùng qua giao diện, còn dữ liệu vẫn hiển thị đầy đủ để xem báo cáo, thống kê bình thường – đúng với mục đích ban đầu là khóa đơn hàng chứ không phải ẩn dữ liệu.
Tổng kết
Trong bài này mình đã đi qua cách khóa đơn hàng và khóa luôn cả đơn hàng chi tiết mà không cần dùng slice để lọc dữ liệu:
- Đặt
Editable_Ifcho cột Tình trạng để không cho sửa trực tiếp trên form - Dùng action riêng để chuyển tình trạng đơn hàng từ
Đang mởsangĐã khóa - Thay công thức Initial Value của cột ID trong bảng chi tiết, gán về ” “ <= ký tự rỗng nha bà con, khi đơn hàng cha đã khóa để chặn thêm dòng mới
- Đặt điều kiện cho action Edit và Delete của bảng chi tiết dựa theo tình trạng đơn hàng cha, để chặn sửa/xóa dòng đã có
Cách này gọn hơn nhiều so với việc tạo slice và view riêng, lại áp dụng được ở mọi giao diện chứ không chỉ riêng Form.
Hẹn gặp lại quý anh chị và các bạn trong những mẹo AppSheet tiếp theo. Chúc mọi người thành công!
#appsheettutorial #appsheet #nocode #googlesheet #quanlydonhang #khoadulieu