CHƯƠNG 3 : PHÂN TÍCH THIẾT KẾ ỨNG DỤNG
Q trình thanh tốn với Paypal từ website thương mại
Thuộc tính Mơ tả
cmd Cho biết ta đang sử dụng trang paypal ở chế độ gì. Ví dụ như khi cmd có giá trị _xclick tức là ta đang sử dụng Paypal ở chế độ thanh toán (Pay now) . Như vậy trong hệ thống siêu thị trực tuyến này với chức năng checkout ta sẽ gán giá trị _xclick cho tham số cmd của checkout
upload Với giá trị là 1 cho tham số upload cho biết ta sử dụng giỏ hàng của hệ thống chứ khơng dùng giỏ hàng tích hợp của Paypal
business Địa chỉ thư xác định tài khoản business với Paypal của ta. Đây chính là tài khoản dùng để nhận thanh tốn từ giao dịch của khách hàng. Với hệ thống tài khoản này là :
dangti_1273804062_biz@yahoo.com
item_name Đây là chuỗi mô tả đơn đặt hàng mà khách hàng sẽ thanh tốn ví dụ như Oder #01
item_number Con số hay chuỗi số xác định cho một đơn đặt hàng
amount Số tiền mà khách hàng phải trả theo tiền của một nước nào đó được chỉ định bằng mã tiền (currency_code) , định dạng tiền phải ở dạng như sau 33.88
Việc tích hợp thanh tốn với Paypay cho hệ thống siêu thị trực tuyến là không quá phức tạp chỉ cần tạo ra một form HTML với các tham số tương ứng và điều hướng khách hàng từ website thương mại tới trang thanh toán với paypal.
<form id="Paypal" name="Paypal" action="<%=
GlobalStoreSection.Current.Commerce.PayPalServer %>" method="post"> <input type="hidden" name="cmd" value="_cart" />
<input type="hidden" name="upload" value="1" /> <input type="hidden" name="business" value="<%=
GlobalStoreSection.Current.Commerce.PayPalAccount %>" /> <input type="hidden" name="shipping" value="<%=
ViewData.Model.ShippingPrice.ToString("N2") %>" />
<input type="hidden" name="amount" value="<%= ViewData.Model.Total.ToString("N2") %>" />
<% int count = 1; %>
<% foreach(ShoppingCartItem shoppingCartItem in ViewData.Model) { %>
<%=Html.Hidden("amount_" + count, shoppingCartItem.SalePrice.ToString("N2"))%> <%=Html.Hidden("item_name_" + count, shoppingCartItem.Title) %>
<%=Html.Hidden("item_number_" + count, shoppingCartItem.Product.ProductID) %> <%=Html.Hidden("quantity_" + count, shoppingCartItem.Quantity) %>
<%count++;%> <% } %>
<button type="submit" id="paypal-checkout-button" value="PayPal" >Checkout</button> </form>
3.4. Các bảng dữ liệu của module
Module thương mại có tất cả 5 bảng sản phẩm, bảng gian hàng (Deparments) , bảng phương thức vận chuyển (ShippingMethods), bảng đơn đặt hàng (Oders), bảng các mặt hàng trong đơn đặt hàng (OderItems) .
Trong đó quan hệ giữa 2 bảng gian hàng và sản phẩm được thiết lập thơng qua khóa ngoại là DepartmentID với updates và deletes là kiểu do đó khi xóa một gian hàng thì các sản phẩm có trong gian hàng cũng bị xóa.
Tương tự thì có mối quan hệ giữa bảng đơn đặt hàng và bảng các mặt hàng trong đơn đặt hàng được thiết lập bởi khóa ngoại là OderID với updates và delete cũng là kiểu cascade.
Hình 3.8 Sơ đồ quan hệ các bảng dữ liệu trong module thương mại
3.5. Lớp thiết lập cấu hình cho module thương mại
Lớp CommerceElement này dùng thiết lập các cấu hình thanh tốn với Paypal được sử dụng để tạo các thuộc tính sau cho việc thanh tốn
Thuộc tính Mơ tả
PayPalServer Đây chính là máy chủ Paypal mà khách hàng gửi yêu cầu tới đó có thể là máy chủ Sandbox dành cho thử nghiệm có địa chỉ (https://www.sandbox.paypal.com/cgi-bin/webscr) hoặc là máy chủ thực (https://www.paypal.com/cgi-bin/webscr) PayPalAccount Đây là ID của PayPal của k hoặc là một địa chỉ thư điện tử
tương ứng với tài khoản PayPal. Thư điện tử này cần được xác nhận lại với PayPal trước khi có thể dùng đại diện cho tài khoản đó
PayPalIdentityToken Đây là thẻ token được PayPal sử dụng để xác nhận một tài khoản nào đó. Nó có thể có được thơng qua site của Paypal ở mục các tùy chọn trong tài khoản PayPal
Vì lí do bảo mật thì token này khơng được gửi tới chủ tài khoản PayPal tuy nhiên khi chủ tài khoản sử dụng Token này thì nó sẽ xuất hiện ở phía dưới các nút bật tắt kiểu radio của phần truyền dữ liệu thanh toán trên trang tùy chọn phương thức thanh toán.
3.6. Model
Model của module này được chia làm 2 phần . Phần thứ 1 là các lớp thực thể LINQ-to-SQL được tạo tự động từ năm bảng DL trên.
Phương thức hành động Bảo mật Các tham số
Index ---- ----
ViewDepartment ---- int departmentId
ViewProduct ---- int productId
ViewShoppingCart ---- int? shippingMethod
AddShoppingCartItem ---- int productId, int? quantity
DeleteShoppingCartItem ---- int id
CompleteOder ---- string tx, decimal amt
ShoppingSummary ---- ----
ManageStore StoreKeeper ----
ManageDepartment StoreKeeper ----
CreateDepartment StoreKeeper ----
CreateDepartment_OnPost StoreKeeper string title, string imageUrl, string description, int? important
EditDepartment StoreKeeper int departmentId
EditDepartment_OnPost StoreKeeper int id, string title, string imageUrl, string description, int? important
DeleteDepartment StoreKeeper int id
ManageProduct StoreKeeper int id
CreateProduct StoreKeeper int id
CreateProduct_OnPost StoreKeeper int? departmentId, string title, string Phần thứ 2 là các lớp thực thể ta xây dựng thêm hỗ trợ cho việc thực hiện một số chức năng của module ví dụ như phần chức năng với giỏ hàng. Lớp ShoppingCart được sử dụng bởi lớp trừu tượng Profile nhằm duy trì trạng thái giỏ hàng của một người dùng ngay cả khi người dùng này thốt khỏi hệ thống.
Ngồi ra cịn có lớp ShoppingCartItem và lớp tĩnh CommerceQueries chứa các phương thức mở rộng cho lớp Department, Products, và ShippingMethods
Hình 3.10 – Các lớp xây dựng thêm hỗ trợ cho module
3.7. Controller
Lớp controller xử lí tồn bộ các logic nghiệp vụ ứng với các use case của module và chứa các phương thức hành động như sau
Tên trang Đặc tả Đường dẫn ảo
Index.aspx Trang này hiển thị
các gian hàng và đóng vai trị là cổng dành cho việc duyệt các sản phẩm store
ViewDepartment.aspx Trang này được dùng để hiển thị tất cả các sản phẩm trong một gian hàng
store/deparments/{deparmentId}
ViewProduct.aspx Trang này dùng hiển thị một sản phẩm
store/product/{productId}
ViewShoppingCart.aspx Trang này ngoài việc hiển thị chi tiết việc mua hàng của khách hàng thì nó cịn cung cấp một số chức năng như xóa mặt hàng,
store/cart
description, string sku, decimal? unit Price, int? discountPercentage, int? untisInStock, string smallImageUrl, string fullImageUrl
EditProduct StoreKeeper int productId
EditProduct_OnPost StoreKeeper int? departmentId, string title, string description, string sku, decimal? unit Price, int? discountPercentage, int? untisInStock, string smallImageUrl, string fullImageUrl
DeleteProduct StoreKeeper int id
ManageOders StoreKeeper int id
OderDetails StoreKeeper int id, string trackingId
ManageShipping StoreKeeper int id, string trackingId CreateShipping StoreKeeper string title, decimal price
DeleteShipping StoreKeeper int id
3.8. View
Đây là một trong số các module có nhiều view nhất trong hệ thống . Gồm có các view dành cho người dùng với vai trị StoreKeeper và các view dành cho người dùng với các vai trò còn lại. Đây là danh sách các view của module
hàng đã hồn tất việc thanh tốn qua PayPal
TransactionError.aspx Trong trường hợp có lỗi xảy ra trong q trình giao dịch
Trang này khơng chứa đường dẫn ảo . Đường dẫn được định nghĩa bởi hệ thống sẽ được sử dụng để đưa ra thông báo lỗi
ManageStore.aspx Trang này hiển thị tất cả các mục trong module cần được quản lí bởi storekeeper
storekeeper/store
ManageDepartment.aspx Trang này hiển thị tất cả các gian hàng mà storekeeper tạo ra , cho phép storekeeper này có thể xóa, hay thực hiện những thay đổi storekeeper/store/departments
CreateDeparment.aspx Trang này cho phép storekeeper tạo mới gian hàng và thay đổi lại thông tin về gian hàng
storekeeper/store/departments/create storekeeper/store/departments/edit/ {departmentId}
ManageProducts.aspx Trang này
storekeeper dùng để thêm sản phẩm mới, thay đổi lại thơng tin sản phẩm hiện có
storekeeper/store/products/create storekeeper/store/products/edit/ {productId}
MangeOder.aspx Trang này liệt kê tất cả các đơn đặt hàng của hệ thống
storekeeper/store/oders
OderDetail.aspx Trang này cho
phép storekeeper xem chi tiết của đơn đặt hàng
storekeeper/store/oders/{oderId}
ManageShipping.aspx Trang này hiển thị tất cả các tùy chọn trong phương thức vận chuyển và cho phép storekeeper thêm mới hay xóa phương thức vận chuyển
3.9. Sử dụng JavaScript
Mã lệnh javascript xử lí các sự kiện bất đồng bộ dành cho module này nằm trong các tệp commerece.js , manage-product.js, manage-deparment.js
manage-department.js được sử dụng để đảm bảo các trường trong form quản lí gian hàng có được sinh ra như u cầu hay không:
$("#title").focus(function () { ShowMessage(this, "Enter the title for your
department."); });
$("#importance").focus(function() { ShowMessage(this, "(optional) Enter the order of
importance that you want the departments shown in."); });
$("#imageUrl").focus(function() { ShowMessage(this, "The relative web path of an
image you want to be shown with products in this department."); });
$("#description").focus(function() { ShowMessage(this, "Enter a short description of
the department to display to your users."); });
function ValidateTitle() {
return VerifyRequiredField("#title", "required"); }
function ValidateImageUrl() {
return VerifyRequiredField("#imageUrl", "required"); }
function ValidateDescription() {
return VerifyRequiredField("#description", "required"); }
function ValidateDepartment() { var validTitle = ValidateTitle(); var validImage = ValidateImageUrl();
var validDescription = ValidateDescription();
return validTitle && validImage && validDescription; }
$("form.department-create").validate(ValidateDepartment);
Tương tự thì tệp manage-product được sử dụng để đảm bảo các trường thông tin trong form tạo sản phẩm được điền vào đúng theo yêu cầu ..
/*********************************************************************************** * Product
***********************************************************************************/
$("#title").focus(function() { ShowMessage(this, "Enter your product name here."); });
$("#sku").focus(function() { ShowMessage(this, "Enter your SKU number here."); }); $("#unitPrice").focus(function() { ShowMessage(this, "Enter the unit price of this
product."); });
$("#discountPercentage").focus(function() { ShowMessage(this, "Enter the percent off
function ValidateTitle() {
return VerifyRequiredField("#title", "required"); }
function ValidateDescription() {
return VerifyRequiredField("#description", "required"); } function ValidateProduct() { return ValidateTitle() && ValidateDescription(); } $("form.product-create").validate(ValidateProduct); /*********************************************************************************** * Rich Text Editor
***********************************************************************************/
var bodyEditor;
$(document).ready(function() {
bodyEditor = new tinymce.Editor("description", __editorConfig); bodyEditor.onChange.add(function(ed) { bodyEditor.save(); });
bodyEditor.onClick.add(function(ed) { ShowMessage("#description", "Enter the
description of your product here."); });
bodyEditor.render(); });
// clears the message from the description when another input gets focus
$(":input")
.focus(function() { HideMessage("#description"); }) .blur(function() { HideMessage("#description"); });
Trong tệp commerece.js có các đoạn mã lệnh cho cả quản lí gian hàng, quản lí sản phẩm ,…
Đoạn code thực hiện xóa gian hàng khơng tạo ra việc Post back toàn bộ: $(".delete-department-button").click(function() {
var departmentId = $(this).attr("meta:id"); $.post( "/Commerce/DeleteDepartment", { id: departmentId }, function(data) { $("#department-" + data.object.id).remove(); $("#admin-" + data.object.id).remove(); $("#spacer-" + data.object.id).remove(); }, "json" ); return false; });
Đoạn code thực hiện việc xóa sản phẩm khỏi gian hàng khơng tạo ra việc postback toàn bộ:
$(".delete-product-button").click(function () { var productID = $(this).attr("meta:id"); $.post(
"/Commerce/DeleteProduct", { id: productID }, function (data) { $("#product-" + data.object.id).remove(); $("#admin-" + data.object.id).remove(); $("#spacer-" + data.object.id).remove(); }, "json" ); return false; });
Đoạn code thực hiện việc các phương thức ứng với cách thức vận chuyển (như xóa cách thức vận chuyển, thêm cách thức vận chuyển ..) mà không tạo ra Post back toàn bộ:
$(".delete-shipping-method-button").live("click", function() { var shippingMethodId = $(this).attr("meta:id");
$.post( "/Commerce/DeleteShipping", { id: shippingMethodId }, function(data) { $("#shipping-method-" + data.object.id).remove(); }, "json" ); return false; }); $("#add-shipping-method-button").click(function() { var title = $("#title").val();
var price = $("#price").val(); $.post(
"/Commerce/CreateShipping",
{ title: title, price: price }, function(data) {
var html = '<tr id="shipping-method-' + data.object.id + '">'; html += '<td align="center">' + title + '</td>';
html += '<td align="center">' + price + '</td>';
html += '<td align="center"><a href="#" class="delete-shipping-
method-button" meta:id="' + data.object.id + '"><img border="0" alt="Delete Role" src="/content/images/DeleteSymbol.png" title="Delete Role"
align="middle"/></a></td>'; html += '</tr>'; $("#shipping-table tbody").append(html); $("#title").val(""); $("#price").val(""); }, "json" ); return false; });
{ id: productId }, function (data) {
$("#item-" + data.object.id).remove();
//Reload whole page
location.reload(form); }, "json" ); return false; }); 3.10. Cấu hình định tuyến
Định tuyến dành cho các view của người dùng có vai trị là storekeeper: routes.MapRoute(
"CommerceManageStore", "storekeeper/store",
new { controller = "Commerce", action = "ManageStore" } );
routes.MapRoute(
"CommerceManageDepartments", "storekeeper/store/departments",
new { controller = "Commerce", action = "ManageDepartments" } );
routes.MapRoute(
"CommerceCreateDepartment",
"storekeeper/store/departments/create",
new { controller = "Commerce", action = "CreateDepartment" } );
routes.MapRoute(
"CommerceEditDepartment",
"storekeeper/store/departments/edit/{departmentId}",
new { controller = "Commerce", action = "EditDepartment", departmentId = (int?)null }
);
routes.MapRoute(
"CommerceManageProducts", "storekeeper/store/products",
new { controller = "Commerce", action = "ManageProducts" } );
routes.MapRoute(
"CommerceCreateProduct",
"storekeeper/store/products/create",
new { controller = "Commerce", action = "CreateProduct" } );
routes.MapRoute(
"CommerceEditProduct",
"storekeeper/store/products/edit/{productId}",
new { controller = "Commerce", action = "EditProduct", productId = (int?)null }
);
routes.MapRoute(
"CommerceManageOrders", "storekeeper/store/orders",
new { controller = "Commerce", action = "ManageOrders" } );
routes.MapRoute(
"CommerceOrderDetail",
"storekeeper/store/orders/{orderId}",
new { controller = "Commerce", action = "OrderDetail", orderId = (int?)null }
);
routes.MapRoute(
"CommerceManageShipping", "storekeeper/store/shipping",
new { controller = "Commerce", action = "ManageShipping" } );
Định tuyến dành cho những người dùng còn lại: routes.MapRoute(
"CommerceIndex", "",
new { controller = "Commerce", action = "Index" } );
routes.MapRoute(
"CommerceDepartment",
"store/departments/{departmentId}",
new { controller = "Commerce", action = "ViewDepartment", departmentId = (int?)null }
);
routes.MapRoute(
"CommerceProduct",
"store/products/{productId}",
new { controller = "Commerce", action = "ViewProduct", productId = (int?)null }
);
routes.MapRoute(
"CommerceCart", "store/cart",
new { controller = "Commerce", action = "ViewShoppingCart" } );
routes.MapRoute(
"CommerceCompleted", "store/order/completed",
new { controller = "Commerce", action = "CompleteOrder" } );
4. MODULE GỬI THƯ 4.1. Tổng quan về module
Hệ thống ln có những nội dung cập nhật mới như bài báo , diễn đàn, thông tin sản phẩm mới … để tạo sự chú ý cho những người dùng là khách hàng thì hệ thống có module gửi thư thơng báo khách hàng biết có những thơng tin mới đó để rồi khách hàng sẽ quay trở lại sử dụng hệ thống trong trường hợp khách hàng đăng kí nhận thư từ hệ thống.
4.2. Các vấn đề cần quan tâm khi xây dựng module:
Để lưu trữ thơng tin đăng kí nhận thư của người dùng ta chỉ cần lưu các thông tin như địa chỉ thư điện tử của người dùng, tên, họ, định dạng thư nhận. Tất cả các thơng tin này có trong các bảng của module hồ sơ và thành viên ta hồn tồn có thể tận dụng.
Việc tạo và gửi thư điện tử của người dùng với vai trị là nhà quản trị có thể được xây dựng sử dụng namespace System.Net.Mail (namespace này được định nghĩa trong thư viện System.dll) . Các lớp chính cho việc tạo và gửi thư là lớp
MailMessage, và lớp SmtpClient cung cấp các phương thức tạo và gửi thư bằng việc kết nối với máy chủ SMTP đã được cấu hình.
Với lớp MailMessage ta có thể tạo tồn bộ thơng tin đầy đủ của một thư điện tử như sau:
// create the message
MailMessage mail = new MailMessage(); // set the sender's address and display name
mail.From = new MailAddress("dangtienloc@gmail.com", "Loc Dang"); // add a first recipient by specifying only her address
mail.To.Add("doangquangminh@gmail.com");
// add a second recipient by specifying his address and display name
mail.To.Add(new MailAddress("nguyenducdan@gmail.com", "Dan nguyen")); // add a third recipient, but to the CC field this time
mail.CC.Add("mainga@gmail.com"); // set the mail's subject and HTML body mail.Subject = "Sample Mail";
mail.Body = "Hello, <b>my friend</b>!<br />How are you?"; mail.IsBodyHtml = true;
// set the mail’s priority to high mail.Priority = MailPriority.High; // add a couple of attachments mail.Attachments.Add(
new Attachment(@"c:\demo.zip", MediaTypeNames.Application.Octet)); mail.Attachments.Add(
Khi đối tượng MailMessage đã được tạo ta có thể gửi nó bằng phương thức Send của lớp SmtpClient.
SmtpClient smtpClient = new SmtpClient(); smtpClient.Send(mail);
Trước khi có thể gọi phương thức Send ta cần thiết lập các thơng tin cấu hình cho hệ thống để phương thức này có thể thực hiện được như địa chỉ của máy chủ SMTP (thuộc tính SmtpClient Host) , cổng (thuộc tính port) và giấy chứng thực của máy chủ này (thuộc tính credentials) , kết nối được mã hóa với SSL (thuộc tính EnableSsl) và thời gian duy trì từ lúc bắt đầu cho tới khi kết thúc của việc gửi thư ( thuộc tính TimeOut , giá trị mặc định là 100 giây) . Một thuộc tính quan trọng là DeliveryMethod (đây là thuộc tính liệt kê của kiểu dữ liệu SmtpDeliveryMethod. Nó có thể nhận một trong các giá trị sau:
Network: Thư được gửi thông qua kết nối trực tiếp tới một máy chủ Smtp cụ thể PickupDirectoryFromIs: Thư điện tử này được chuẩn bị và tệp thư này được lưu
vào thư mục mặc định là <drive>:\Inetpub\mailroot\Queue. IIS sẽ lấy thư này từ hàng đợi thư để gửi.
SpecifedPickupDirectory: Các tệp EML với thư điện tử sẽ được gửi được lưu
vào thư mục được chỉ định cho thuộc tính này của đối tượng SmtpClient. Thiết lập này sẽ hữu ích khi ta có một ứng dụng ngồi (khơng phải IIS) xử lí việc chọn thư và gửi
Cấu hình phần gửi thư của hệ thống thương mại trực tuyến <system.net>
<mailSettings>
<smtp deliveryMethod="Network" from="dangtienloc@gmail.com">
<network defaultCredentials="true" host="MailServer" port="25"/> </smtp>
</mailSettings> </system.net>
Vấn đề thời gian trong xử lí gửi thư có thể là rất lâu khiến người dùng có thể nghĩ hệ thống có lỗi. Việc gửi thư tới hàng ngàn khách hàng đăng kí nhận thư
(subscribers) thường phải mất hàng phút trong khi để xử lí một yêu cầu theo tiêu chuẩn chỉ nên trong vài giây.
Một giải pháp được đưa ra trong hệ thống đó là khi người dùng nhấn nút submit (tương đương với hành động gửi thư) thì ở phía máy chủ sẽ sinh ra một tiến trình xử lí nhiệm vụ gửi thư mất nhiều thời gian đó ở chế độ nền (backgroudn running mode) và chuyển hướng người dùng về trang quản lí thư . Và ở trang đó người dùng có thể thấy được trạng thái của tất cả các thư đã gửi trong đó có cả thư mới tạo gần nhất và đang được gửi .