Hướng dẫn tạo và sửa sản phẩm trong CMS
Quản lý sản phẩm theo loại, giá, VAT, giảm giá, đơn vị quy đổi, hình ảnh, thuộc tính và các quan hệ sản phẩm.
Màn hình sản phẩm dùng để làm gì?
Sản phẩm là nơi tạo và quản lý thông tin mặt hàng/dịch vụ trên website: mã, tên, nhóm, loại, giá, VAT, đơn vị, giảm giá, nội dung giới thiệu, hình ảnh, thuộc tính và liên kết. Người dùng được quản lý dữ liệu sản phẩm theo quyền được cấp. Màn hình CMS không thay thế quy trình nhập/xuất kho hoặc hóa đơn ở ứng dụng nghiệp vụ khác.
Giao diện danh sách sản phẩm
Tên hoặc mã: Nhập mã để tìm chính xác hơn, hoặc một phần tên sản phẩm. Kiểm tra cả nhóm và trạng thái nếu không có kết quả.
Nhóm sản phẩm: Tất cả hoặc một danh mục PRO trong cây. Các nhãn như thương hiệu là dữ liệu doanh nghiệp cấu hình, không phải loại sản phẩm cố định.
Loại sản phẩm: Tất cả hoặc một trong 7 loại bên dưới. Lọc loại nghiệp vụ, không thay nhóm sản phẩm.
Trạng thái: Tất cả: cả hai trạng thái; Hoạt động: đang bật; Không hoạt động: đang tắt. Chọn trong bộ lọc không đổi trạng thái của sản phẩm.
Hiển thị: 10, 20, 50 hoặc 100 bản ghi/trang trên bản khảo sát. Chỉ thay lượng bản ghi đang xem, không đổi dữ liệu sản phẩm.
Bảy lựa chọn Loại sản phẩm
Hàng hóa: Hàng mua/bán như một mặt hàng thương mại.
Dịch vụ: Công việc hoặc dịch vụ cung cấp cho khách; không phải mô tả hàng vật chất.
Thành phẩm: Sản phẩm đã hoàn tất quá trình sản xuất.
Bán thành phẩm: Sản phẩm trung gian chưa ở trạng thái thành phẩm cuối cùng.
Công cụ dụng cụ: Đối tượng được phân loại là công cụ/dụng cụ; khối giá chính bị ẩn theo điều kiện giao diện.
Nguyên vật liệu: Vật liệu đầu vào cho hoạt động sản xuất/sử dụng.
Tài sản cố định: Đối tượng thuộc nhóm tài sản cố định; khối giá chính bị ẩn theo điều kiện giao diện.
Chọn theo nghiệp vụ đã được đơn vị xác định. Đổi loại tại trang sửa gửi API riêng ngay và có thể ẩn/hiện nhóm trường giá; không đồng nghĩa xóa sản phẩm hoặc tự hoàn tất nghiệp vụ kế toán cho loại đó.
Giao diện Thêm sản phẩm
- Tại danh sách bấm Thêm để mở hộp Thêm sản phẩm.
- Nhập Mã sản phẩm nếu có, Tên sản phẩm, Nhóm sản phẩm và Loại. Tên, nhóm và đơn vị tính được kiểm tra bắt buộc trong handler.
- Nhập giá, VAT và Đơn vị tính. Nút + cạnh nhóm mở tạo danh mục; nút + cạnh đơn vị thêm dòng đơn vị quy đổi, yêu cầu đã nhập đơn vị cơ bản.
- Bấm Thêm sản phẩm. CMS dùng API nghiệp vụ kho để tạo bản ghi và chuyển tới trang chi tiết nếu thành công. Đóng sẽ bỏ model đang nhập.
- Tại trang chi tiết mới hoàn thiện mô tả, SEO, giảm giá, tag, hình và thuộc tính. Không tìm tất cả các trường này trong hộp thêm nhanh.
Giá và các lựa chọn VAT
Phương pháp GTGT được đặt trong Thông tin web. Với Trực tiếp, form dùng Giá bán và chỉ hiện Không kê khai, Không chịu thuế, 0%. Với Khấu trừ, form có Giá bán trước thuế và Giá bán sau thuế, đồng thời cho chọn thêm 5%, 8%, 10%. Không có một bộ VAT cố định cho mọi doanh nghiệp.
Không kê khai (-2): Trạng thái phân loại VAT không kê khai của phần mềm; không phải mức -2%. Code tính phần thuế số học bằng 0 khi giá trị VAT không dương.
Không chịu thuế (-1): Trạng thái phân loại không chịu thuế, khác với thuế suất 0%. Không phải mức -1%; chọn đúng phân loại nghiệp vụ đã xác định.
0%: Thuế suất bằng 0 trong dữ liệu sản phẩm. Giá trước/sau thuế bằng nhau theo phép tính của form.
5%, 8%, 10%: Các thuế suất dương được phần mềm cho chọn ở phương pháp Khấu trừ. Giá sau = giá trước × (1 + VAT/100); sửa giá sau sẽ tính ngược giá trước.
Ví dụ tính toán của giao diện: giá trước 100.000, VAT 10% cho giá sau 110.000. Nhập giá sau 110.000 sẽ tính giá trước 100.000. Đây là ví dụ sử dụng trường giá, không quyết định mức thuế áp dụng cho một mặt hàng. Khi phương pháp thay đổi, VAT ngoài danh sách hợp lệ có thể được chuẩn hóa về Không kê khai khi tải chi tiết; kiểm tra trước khi Lưu.
Giao diện Sửa sản phẩm
Tiêu đề / Mã sản phẩm: Tên hiển thị và mã nhận diện sản phẩm. Lưu chính; API kiểm tra mã trùng khi đổi mã.
Danh mục: Nhóm PRO chứa sản phẩm. Đổi ngay sẽ xóa giá trị thuộc tính cũ, xem phần xử lý phía code bên dưới.
Giá / VAT / Đơn vị tính: Giá gốc, phân loại thuế, đơn vị cơ bản. Lưu chính; dòng đơn vị phụ có nút Lưu riêng.
Mô tả ngắn / Mô tả chi tiết: Tóm tắt và nội dung đầy đủ giới thiệu mặt hàng. Lưu chính lấy HTML của editor.
Thứ tự hiển thị: Giá trị sắp xếp khi website sử dụng thứ tự sản phẩm. Trang sửa cần Lưu chính. Ở danh sách hiện tại là ô số, thay đổi gửi cập nhật riêng; không phải mọi màn hình đều có nút +/−.
Hoạt động: Bật cho phép hiển thị, tắt tạm ẩn sản phẩm. Gửi API ngay; không chờ Lưu chính.
Tags: Từ khóa phân loại sản phẩm. Thêm/bỏ trên form rồi Lưu chính.
Hình / Hình chi tiết: Ảnh đại diện và bộ ảnh bổ sung là hai phần riêng. Ảnh đại diện gắn với Lưu chính; bộ ảnh chi tiết có xử lý riêng, không mặc định cùng thời điểm lưu.
Ba lựa chọn giảm giá đang được cung cấp
Không giảm: Không áp dụng giảm giá theo trường này.
Phần trăm: Hiện ô Giảm, nhập tỷ lệ; Còn = Giá − Giá × tỷ lệ/100. Ví dụ 200.000 giảm 10% còn 180.000 trước các xử lý khác.
Giảm tiền: Hiện ô Giảm, nhập số tiền; Còn = Giá − số tiền giảm. Ví dụ 200.000 giảm 30.000 còn 170.000.
Chọn loại và nhập giá trị rồi Lưu sản phẩm. Có nhánh code xử lý DiscountType = 3 với nhãn Giá bán, nhưng DataSource.DiscountTypes hiện không đưa giá trị 3 vào lựa chọn. Vì vậy đây là nhánh ẩn/di sản, không hướng dẫn người dùng chọn một mục không có trên dropdown. Kiểm tra kết quả tính; không nhập số tiền vào ô tỷ lệ hoặc ngược lại.
Đơn vị quy đổi
Đơn vị cơ bản dùng cho giá chính. Đơn vị phụ mô tả cách quy đổi về đơn vị cơ bản, ví dụ Hộp = 10 Cái thì hệ số là 10. Mỗi dòng có tên đơn vị, hệ số, giá và ở chế độ Khấu trừ có giá sau thuế. Không mặc định hệ số sẽ tự nhân ra giá bán mong muốn: kiểm tra và nhập giá của đơn vị phụ. Trong hộp tạo, các dòng được gửi cùng yêu cầu tạo. Trong trang sửa, Lưu/Xóa từng dòng gọi API riêng ngay; dấu + thêm dòng tạm với hệ số mặc định 1. Xóa dòng đơn vị không phải xóa toàn sản phẩm.
Sản phẩm kèm theo và sản phẩm liên quan
Sản phẩm liên quan dùng giới thiệu các sản phẩm có liên hệ để người xem tham khảo. Sản phẩm kèm theo còn có số lượng, giá và đơn vị cho quan hệ đi kèm. Bấm Thêm ở đúng khối để mở danh sách chọn; chọn sản phẩm là thao tác tạo quan hệ ngay tại trang sửa. Hệ thống chặn chọn chính sản phẩm đang sửa và chặn quan hệ trùng.
- Với sản phẩm kèm theo, sau khi chọn kiểm tra số lượng mặc định 1 và giá được lấy từ sản phẩm được chọn.
- Chọn đơn vị nếu có nhiều đơn vị. Code đổi giá theo đơn vị trong dòng đang sửa; bấm Lưu của dòng để ghi số lượng, giá, đơn vị.
- Dùng Xóa trong khối quan hệ để gỡ quan hệ; không xóa bản ghi sản phẩm gốc.
- Mở lại trang và kiểm tra website có module/skin sử dụng các quan hệ này hay không.
Nhân bản và các tác động cần biết
Nhân bản gọi API tạo ngay, không phải mở một bản nháp chưa lưu. Code tạo mã sản phẩm ngẫu nhiên chưa trùng, tiêu đề mỗi ngôn ngữ thêm “(Clone)”, thứ tự 50, lượt xem 0 và trạng thái bật. Dữ liệu cơ bản như danh mục, giá, VAT, loại, giảm giá, nội dung theo ngôn ngữ và thuộc tính được sao chép theo nhánh repository. Không coi tag, SEO, bộ ảnh chi tiết, sản phẩm kèm theo và liên quan là chắc chắn được nhân bản: chúng không được sao chép đầy đủ trong nhánh này. Có nhánh sao chép đơn vị nếu collection đã được tải, nhưng truy vấn không Include Units, nên phải kiểm tra kết quả thực tế.
Sau nhân bản, CMS mở sản phẩm mới. Kiểm tra trạng thái ngay trước khi biên tập tiếp vì mặc định code đã bật; sửa tiêu đề, mã, hình và giá cho đúng. Không dùng Nhân bản chỉ để xem thử, vì nút này ghi dữ liệu.
Kiểm tra sau lưu
- Chờ thông báo thành công của đúng khối vừa lưu; nếu có lỗi thì xử lý lỗi trước khi rời trang.
- Ghi lại phần còn đang soạn, sau đó mở lại bản ghi để đối chiếu giá trị đã lưu. Không coi ô nhập đang hiển thị là bằng chứng máy chủ đã ghi dữ liệu.
- Kiểm tra trang website tương ứng: đúng ngôn ngữ, đúng vị trí, hình ảnh và liên kết hoạt động. Nếu website vẫn dùng dữ liệu cũ, kiểm tra cơ chế cache và cấu hình hiển thị; không xóa rồi tạo lại nội dung để xử lý lỗi cache.
Hệ thống xử lý gì khi đổi danh mục và nhập thuộc tính?
Đổi danh mục: lưu ngay và xóa giá trị thuộc tính cũ
Đổi danh mục của nội dung đã tồn tại có tác động ngay đến dữ liệu đã lưu. Hệ thống không chỉ thay tên nhóm trên màn hình: API kiểm tra danh mục, xóa các bản ghi giá trị thuộc tính của nội dung, cập nhật danh mục rồi lưu cơ sở dữ liệu. Không có bước bấm Lưu chung để xác nhận lại thay đổi này.
- Trước khi đổi, ghi lại các giá trị cần giữ trong Thông tin khác và Tìm kiếm, ở từng ngôn ngữ đang sử dụng. Lưu hoặc sao chép riêng các phần đang soạn để không nhầm chúng với dữ liệu đã lưu.
- Chọn đúng danh mục đích. Chỉ thực hiện khi đã quyết định chuyển nội dung; không dùng danh sách này để thử xem danh mục khác có những trường nào.
- Chờ thông báo thành công. Khi API thành công, màn hình nhận danh mục mới và hai khối thuộc tính tải lại. Nếu có lỗi, kiểm tra thông báo và dữ liệu sau khi mở lại trang, không tiếp tục nhập thuộc tính theo một danh mục chưa được lưu thành công.
- Nhập lại các giá trị phù hợp với bộ thuộc tính mới. Thuộc tính có nút Lưu cần lưu từng trường; công tắc, ô chọn và nút chọn một giá trị gửi cập nhật ngay.
- Mở lại nội dung và kiểm tra từng ngôn ngữ. Chọn lại danh mục cũ không khôi phục các giá trị đã bị xóa.
Phạm vi bị xóa: xử lý phía máy chủ lọc theo mã nội dung, không lọc theo ngôn ngữ hay nhóm thuộc tính. Vì vậy, toàn bộ giá trị thuộc tính đã lưu của nội dung ở các ngôn ngữ đều nằm trong phạm vi xóa; ngay cả thuộc tính xuất hiện ở cả danh mục cũ và mới cũng không được giữ lại theo cách xử lý này. Thao tác này không xóa định nghĩa thuộc tính dùng chung trong phần cấu hình. Không diễn giải việc mất giá trị thuộc tính là xóa bài viết, sản phẩm hoặc tệp nội dung.
Ví dụ minh họa: một nội dung đang có thuộc tính “Tác giả” ở danh mục A. Chuyển sang danh mục B có cùng thuộc tính “Tác giả” vẫn cần nhập lại giá trị đã ghi trước đó. Nếu B không có thuộc tính này, ô nhập sẽ không còn xuất hiện. Đây là ví dụ về quy tắc xử lý, không phải mô tả một bản ghi đã được thử chuyển trong dữ liệu thật.
Vì sao bộ thuộc tính thay đổi hoặc một khối không có ô nhập?
Hệ thống lấy thuộc tính theo nội dung, danh mục hiện tại, ngôn ngữ đang chọn và nhóm mục đích. Các thuộc tính được cấu hình cho danh mục hiện tại hoặc các danh mục cha có thể được đưa vào, theo ngôn ngữ tương ứng. Các trường được sắp theo độ ưu tiên của định nghĩa thuộc tính. Khối Thông tin khác dùng nhóm thông tin; khối Tìm kiếm dùng nhóm bộ lọc. Cách trình bày trên website còn phụ thuộc template có sử dụng các trường này hay không.
Khi một trong các thông tin nhận diện trên thay đổi, component xóa danh sách đang hiển thị và gọi API tải lại. Nếu có nhiều yêu cầu tải nối tiếp, phản hồi cũ không được ghi đè kết quả của lần tải mới hơn. Một khối trống có thể do chưa cấu hình thuộc tính cho danh mục/ngôn ngữ đó; nếu tải lỗi, hệ thống có thông báo lỗi, không nên hiểu là chắc chắn không có thuộc tính.
Lưu giá trị thuộc tính như thế nào?
Văn bản, văn bản nhiều dòng, số, ngày, màu: Nhập hoặc chọn giá trị, rồi bấm Lưu cạnh chính trường đó. Chỉ trường đó được gửi cập nhật. Nút Lưu của nội dung không thay thế các nút này.
Hình ảnh thuộc tính: Chọn tệp ảnh, sau đó bấm Lưu của trường. Chọn tệp mới chỉ chuẩn bị dữ liệu. Khi lưu, máy chủ xử lý ảnh và lưu đường dẫn; sau thành công, component tải lại danh sách thuộc tính. Do đó nên lưu các trường khác đang sửa trước khi lưu ảnh thuộc tính.
Công tắc đúng/sai: Bật hoặc tắt. Gửi giá trị ngay. Công tắc thuộc tính chỉ có ý nghĩa theo tên thuộc tính; không tự đồng nghĩa với trạng thái xuất bản của nội dung.
Chọn nhiều giá trị: Đánh dấu hoặc bỏ đánh dấu từng ô. Mỗi lần thay đổi gửi lại tập giá trị đã chọn. Code lưu các lựa chọn dưới dạng chuỗi phân cách bằng dấu phẩy.
Chọn một giá trị: Bấm nút tròn cạnh lựa chọn. Gửi lựa chọn ngay; chỉ một giá trị được chọn trong trường đó.
Máy chủ kiểm tra thuộc tính có thuộc danh mục hiện tại hoặc danh mục cha của nội dung, đúng ngôn ngữ và thuộc nhóm được phép hay không. Nếu nội dung đã bị chuyển danh mục ở một tab khác, lưu một ô thuộc tính cũ có thể bị từ chối với thông báo Thuộc tính không thuộc danh mục nội dung hiện tại. Khi đó cần ghi lại phần đang nhập và mở lại trang để làm việc với bộ trường đúng.
Luôn đọc thông báo của từng lần lưu. Giá trị còn hiện trong ô sau một lỗi không chứng minh rằng máy chủ đã lưu thành công.
Đối chiếu: Web.Api/Repositories/ItemRepository.cs — UpdateProductCategory; Web.Api/Controllers/ContentsController.cs — GetAttributes, UpdateAttribute; Web.CMS/Pages/Content/Components/ItemAttributes.razor. Các tác động ghi/xóa dữ liệu ở mục này được xác định từ mã nguồn; không thử chuyển danh mục trên dữ liệu thật để chụp minh họa.
Bộ ảnh chi tiết lưu ngay khi chọn tệp
Trong khối Hình chi tiết, chọn tệp gọi API thêm ảnh ngay và tải lại danh sách sau thành công. Nút × trên một ảnh gọi xóa riêng ngay, không có hộp xác nhận trong component này. Đây là bộ ảnh bổ sung, khác ảnh đại diện Hình cần Lưu sản phẩm. Không bấm × để đóng ảnh xem trước nếu chưa có ý định xóa ảnh khỏi bộ ảnh sản phẩm.