You are on page 1of 60

DEVELOPMENT OF A WEB-BASED BOOK APPLICATION

MIBOOK STORE

NGUYEN THUY HANG


NGUYEN NGOC KIM CHI

OPEN UNIVERSITY MALAYSIA


2023
DEVELOPMENT OF A WEB-BASED BOOK APPLICATION
MIBOOK STORE

NGUYEN THUY HANG


NGUYEN NGOC KIM CHI

A Final Year Project submitted in fulfilment of the requirements


for the degree of
Bachelor of Information Technology with Honors

Faculty of Technology and Applied Sciences


Open University Malaysia

2023
DECLARATION

Name:

Matric number:

I hereby declare that this final year project is the result of my own work, except for quotations
and summaries which have been duly acknowledged.

Signature: Date:
ABSTRACT

This thesis presents the design and implementation of an online bookstore system called
MiBook. The system aims to provide a convenient platform for customers to purchase books
online.
The system is built using a 3-tier architecture: presentation tier, business logic tier, and data
tier. The front-end is developed using React framework and the back end uses Express
framework and MySQL database.
Key features of MiBook include:
 User management: Customers can register for an account and log in. Their
information is stored in the database.
 Catalog management: Admins can add/edit/delete book information. Books are
categorized by genres.
 Search and filter books: Customers can search for books by keywords, filter by price
range, etc.
 Shopping cart: Customers can add/remove books to cart, specify quantity, apply
coupons if available.
 Checkout process: Customers can provide shipping address, choose shipping method,
and make payment.
 Order management: Admins can view, update order status. Customers can track order
status.
The system is tested extensively to ensure functionality and usability. Future work includes
adding more payment options, recommendation system, etc. to enhance customers' shopping
experience.
In conclusion, the MiBook system demonstrates the competency in applying software
engineering concepts and web development skills to build a fully functional online bookstore.
The system delivers benefits for both customers and business owners.
Keywords: online bookstore, ecommerce, website design, React, Express, MySQL
ACKNOWLEDGEMENT

I would like to take this opportunity to express my gratitude and appreciation to my


supervisor, XXXXXXXXXXXXX guidance, patience, and invaluable advice throughout this
project.

I also would like to express my appreciation to my family and friends for their endless
support whenever I face problems. Without the mentioned parties, it is impossible for me to
complete this project report successfully.

THANK YOU.

22 Dec 2023
TABLE OF CONTENTS

DECLARATION..........................................................................................................................................
ABSTRACT.................................................................................................................................................
ACKNOWLEDGEMENT..............................................................................................................................
TABLE OF CONTENTS................................................................................................................................
LIST OF TABLES.........................................................................................................................................
LIST OF FIGURES.......................................................................................................................................
LIST OF ABBREVIATIONS...........................................................................................................................
CHAPTER 1 INTRODUCTION...................................................................................................................1
1.1 Background to the Study..............................................................................................................1
1.2 Problem Statement......................................................................................................................1
1.3 Objectives of the Study.................................................................................................................1
1.4 Scope and Limitations...................................................................................................................2
1.5 Implementation Plan....................................................................................................................2
CHAPTER 2..............................................................................................................................................4
LITERATURE REVIEW..............................................................................................................................4
2.1 Overview of Ecommerce and Online Shopping Trends.................................................................4
2.2 Digital Books and Reading Trends................................................................................................5
2.3 Online Bookstores and Buying Behaviors.....................................................................................5
2.4 User Experience Design for Ecommerce.......................................................................................6
2.5 Payments, Logistics, and Infrastructure Factors...........................................................................7
2.6 Related Works on Emerging Markets and Localization................................................................7
CHAPTER 3..............................................................................................................................................9
SYSTEM ANALYSIS AND DESIGN.............................................................................................................9
3.1 Feasibility Studies.........................................................................................................................9
3.2 Requirement Methods...............................................................................................................10
3.3 System Development Methods..................................................................................................12
3.4 Data and Process Modelling Diagrams.......................................................................................12
CHAPTER 4............................................................................................................................................18
SYSTEM IMPLEMENTATION AND TESTING...........................................................................................18
4.1 System Manual...........................................................................................................................18
4.2 Installation Manual.....................................................................................................................23
4.3 Testing Plan................................................................................................................................23
4.4 Main Function Codes..................................................................................................................23
CHAPTER 5............................................................................................................................................30
SUMMARY AND CONCLUSION..............................................................................................................30
5.1 Summary of Main Findings.........................................................................................................30
5.2 Discussion and Implications........................................................................................................30
5.3 Limitations of The System..........................................................................................................31
5.4 Future Development..................................................................................................................31
REFERENCES.........................................................................................................................................32
APPENDICES.........................................................................................................................................32
Appendix A.......................................................................................................................................32
Appendix B.......................................................................................................................................34
Appendix C.......................................................................................................................................35
Appendix D.......................................................................................................................................38
Appendix E.......................................................................................................................................40
Appendix F........................................................................................................................................43
LIST OF TABLES
LIST OF FIGURES

Figure 3.1: Context Level Diagram


Figure 3.2: Data Flow Diagram
Figure 3.3: Entity Relationship Diagram
Figure 3.4: Unified Modeling Language
Figure 3.5: Sequence Diagram of Update Cart
Figure 3.6: Use case diagram of Guest and Customer
Figure 3.7: Use case diagram of Admin and System
Figure 4.1: Main Page
Figure 4.2: Store
Figure 4.3: Book Detail
Figure 4.4: Checkout
Figure 4.5: Register page
Figure 4.6: Login page
Figure 4.7: Forgot password
Figure 4.8: Change password
Figure 4.9: Profile
Figure 4.10: Order
LIST OF ABBREVIATIONS

UX - User Experience
UI - User Interface
CHAPTER 1
INTRODUCTION

1.1 Background to the Study


The emergence of digital platforms and mobile devices has transformed the way people
purchase and read books. Print book sales have declined in many countries, while eBook sales
have exploded in growth over the last decade (Smith, 2022). Platforms like Amazon Kindle
have made eBooks more accessible to mainstream consumers. The COVID-19 pandemic has
also accelerated the adoption of digital books, as traditional bookstores were closed, and more
people stayed home (Lee, 2021).

In Vietnam, online book shopping is still an emerging market compared to more mature
ecommerce sectors like fashion and electronics. Local online bookstores have not gained
significant traction, especially among avid readers and book collectors who still prefer
physical bookstores. However, the young, tech-savvy demographic is an ideal target for
mobile-first online bookstores. Developing a user-friendly ecommerce platform tailored for
Vietnamese readers could help unlock the potential of this market.

Previous research has identified key features desired by online book buyers, including
competitive pricing, free shipping, robust search and filtering, and secure payment options
(Moody & Fowler, 2021). However, there is a lack of studies examining the specific needs
and behaviors of Vietnamese online book shoppers. Localization is important to gain user
trust and engagement in Vietnam's unique ecommerce landscape.

Therefore, this study aims to address this gap by designing and developing an online
bookstore tailored for Vietnamese customers. The system will implement commonly
requested features like discounts and promotions, user reviews, wish lists, etc. User
experience testing will be conducted to evaluate the platform's usability and value
proposition. The goal is to provide empirical insights into Vietnamese online book buying
preferences to aid future development in this market.

1
1.2 Problem Statement
The consumption of books in Vietnam remains heavily concentrated in physical formats. Print
books account for over 90% of book sales according to market surveys (Nguyen, 2021).
While eBook adoption is accelerating globally, it has lagged in Vietnam due to limited title
availability and lack of affordable reading devices.

At the same time, the number of smartphone users in Vietnam has exploded to over 50
million, representing over half of the population (Vu, 2022). This demonstrates a huge
opportunity for online bookstores that focus on mobile-friendly experiences. However,
existing ecommerce sites have not gained dominance for book shopping specifically. Local
online bookstores often have limited selections and inadequate shipping options.

Therefore, the key problem is the lack of a purpose-built online bookstore tailored to the
needs of Vietnamese readers. There is a gap in understanding Vietnamese preferences
regarding content, pricing, promotions, and user experience for book ecommerce platforms.
Without addressing these user requirements, the growth of digital book consumption in
Vietnam will not reach its full potential.

This research aims to tackle this problem by designing, developing, and testing an online
bookstore focused on the Vietnamese market. The system will implement a customized
catalog, predictive search, engaging user interface, and integrated logistics for nationwide
delivery. The goal is to validate an effective model for digitizing book retail in Vietnam given
the unique characteristics of this market.

1.3 Objectives of the Study


The objectives of this research are:

 To analyze behavior and preferences of Vietnamese online book buyers through


surveys and interviews.
 To design and develop an online bookstore web/mobile application tailored for the
Vietnamese market.
 To implement features identified as highly desirable by Vietnamese users, including
personalization, promotions, payment options, reviews etc.
 To curate a catalog of over 5,000 book titles across fiction/non-fiction, languages,
genres, formats etc.
 To optimize search, filter, and recommendation functions to enable book discovery.
 To test the system through user experience evaluation with 50 participants.

1
 To gather feedback on user satisfaction, usability and buying intent through
questionnaires.
 To refine the system by incorporating user testing insights to improve market fit.
 To assess the viability of the system as a model for emerging online book retail in
Vietnam.

The overarching goal is to validate an effective solution for digitizing book consumption in
Vietnam through empirical research and user-centric design.

1.4 Scope and Limitations


1.4.1 Scope

 This study focuses exclusively on the online book buying behavior and preferences of
consumers in Vietnam.
 The proposed system will cover eBooks, print books, audiobooks, but not educational
textbooks which require a separate distribution model.
 The testing and evaluation will be limited to sample groups in major cities like Hanoi
and Ho Chi Minh City and may not represent all regions.
 System design will prioritize mobile user experience but also enable desktop access.
 Security, privacy, and payments will integrate with existing solutions rather than
developing from scratch.

1.4.2 Limitations

 The testing sample size of 50 users may not capture all possible consumer behaviors
and preferences.
 The curated catalog will be limited in scope and may not cover niche genres.
 The study duration may not allow for longer-term validation of key metrics like user
retention.
 Access constraints may limit the ability to test varied demographic groups.
 Rapidly evolving technologies could quickly make some system elements outdated.

The scope focuses the research on key elements while acknowledging constraints. Limitations
will be considered when drawing conclusions from the study findings.

1.5 Implementation Plan


1.5.1 Planning Phase

2
 Conduct literature review on ecommerce and online bookstore best practices.
 Survey existing platforms and case studies.
 Define research questions, objectives, and scope.
 Develop data collection tools like surveys, interview guides, prototypes.

1.5.2 Execution Phase

 Recruit participants and conduct user research.


 Analyze results to inform system requirements and specifications.
 Design system architecture, database schema, interfaces.
 Implement core functionality based on staged development plan.
 Curate initial book catalog by acquiring digital rights and metadata.

1.5.3 Evaluation Phase

 Develop test plans and scripts for system testing.


 Conduct user experience testing with focus groups.
 Collect user feedback through questionnaires and interviews.
 Analyze results to identify areas for improvement.
 Refine system design and features based on test findings.
 Assess performance against original objectives.

3
CHAPTER 2

LITERATURE REVIEW

2.1 Overview of Ecommerce and Online Shopping Trends


Ecommerce has experienced tremendous growth over the past decade, driven by
advancements in technology, infrastructure, and changing consumer behaviors. According to
Smith (2021), global retail ecommerce sales reached $4.28 trillion in 2020, reflecting a 27.6%
growth from the prior year. This trajectory is expected to continue as more commerce shifts
online, with projections estimating $5.4 trillion in worldwide ecommerce sales by 2022
(Juniper Research, 2021).

Several key trends have catalyzed the rapid adoption of online shopping globally (Ritz et al.,
2019). Ubiquitous smartphone ownership and mobile broadband enable consumers to shop
anytime, anywhere. Improvements in logistics networks offer faster and cheaper delivery.
Digital payment systems provide seamless checkout experiences. Personalization and
recommendation algorithms create more engaging experiences. While electronics and fashion
represent the largest ecommerce segments, new product categories continue to emerge,
including groceries, luxury goods, and digital services.

Across regions, Chinese consumers lead global ecommerce adoption, but categories like
clothing and accessories dominate in Europe, while Americans spend heavily on pet products
online (Bloomberg, 2021). This highlights the nuances in consumer behaviors based on
cultural and geographic factors. As ecommerce permeates globally, understanding these
market differences will be critical for retailers hoping to expand their reach.

The Covid-19 pandemic has accelerated ecommerce growth further by necessitating digital
alternatives during lockdowns and social distancing protocols (UNCTAD, 2020). Experts
predict much of this shift will persist in a post-pandemic landscape as people maintain new

4
digital habits. However, significant gaps remain in access and infrastructure across emerging
economies, representing untapped potential.

5
2.2 Digital Books and Reading Trend
The book industry has undergone major transformations due to the emergence of eBooks and
digital reading technology. According to the International Publishers Association, global trade
eBook revenues reached $7.4 billion in 2020, accounting for 11% of trade book sales (IPA,
2021). While eBooks initially faced resistance, adoption has accelerated with the popularity
of dedicated readers like Amazon Kindle and multifunction devices like tablets.
Several studies have examined consumer preferences for print books versus eBooks. A survey
by Lee (2019) found that convenience, portability, and cost were the major motivators for
eBook adoption, while print books were preferred for more immersive reading. Some genres
like romance and sci-fi tend to have higher digital penetration compared to literary fiction
(Scholastic, 2017). Digital books also enable innovations like embedded multimedia,
interactive components, and accessibility features.

Audiobooks have also gained significant traction, especially among multitasking listeners.
Audiobook revenues topped $1 billion in 2020, with Amazon's Audible platform
commanding the largest market share (Ingram, 2021). New subscription models from
companies like Scribd and Kobo provide unlimited eBook and audiobook access. These
developments provide more affordable and flexible options for consumers while generating
new revenue streams for publishers.

Experts predict eBooks will continue growing as a proportion of book sales, though print will
remain relevant for many readers. Understanding evolving preferences around digital reading
and leveraging interactive capabilities will be key for the book industry going forward. More
user research is needed, especially in emerging markets where digital book adoption lags
traditional formats.

2.3 Online Bookstores and Buying Behaviors


The emergence of online bookstores has significantly influenced how people purchase and
consume books. Amazon captured the early lead, evolving from an online bookseller to the
dominant player in global ecommerce. Research shows competitive pricing, vast selection,
and reliability are major factors in Amazon's success (Ritala et al., 2014). Amazon has also
leveraged data and personalization to drive recommendations and loyalty.

Other studies reveal key purchasing drivers for online book buyers beyond price, including
breadth of selection, convenience, delivery speed, and smooth ordering and returns (Li et al.,

6
2012). Website usability and community features like reviews and forums also influence
purchasing decisions. Comparing across genres, more impulsive behaviors are observed for
fiction book buying compared to deliberate, planned purchases for specialty non-fiction books
(Degeratu et al., 2000).

However, there are notable gaps in research on online book buying in emerging economies.
Factors like local payment systems, logistics networks, and cultural nuances around digital
versus print may diverge from Western markets. An analysis of India's youth market revealed
preferences for local language content, cash on delivery, and bundled mobile data plans to
drive engagement with digital books (BCG, 2021). Further research is needed on user
behaviors in Vietnam and other underserved markets.

By leveraging data and designing experiences catered to local buyer needs, online bookstores
in emerging regions can overcome barriers to adoption and unlock significant growth
potential. More user-centric studies are critical to inform effective models.

2.4 User Experience Design for Ecommerce


Creating engaging user experiences is critical for online business success. Researchers have
identified several strategies for optimizing ecommerce UX. Personalization can leverage user
data and algorithms to provide tailored recommendations and custom interfaces (Kumar et al.,
2018). Predictive analytics facilitates preemptive customer service and intelligent promotions
planning. Conversational interfaces via chatbots improve self-service capabilities.

Streamlining product discovery and evaluation is another priority. Features like guided
navigation, faceted filters, and predictive search enhance findability. Virtual try-on, 3D
models, and augmented reality allow customers to digitally “experience” products.
Community elements like user-generated reviews and discussion forums drive trust and
engagement.

UX design also needs to optimize conversion funnels by minimizing friction during checkout.
Pre-filling forms, offering guest checkout, and integrating preferred payment methods
accelerate completion. Clear calls-to-action, progress trackers, and displaying security
seals/policies increase confidence. Post-purchase, order tracking and status updates provide
reassurance and brand touchpoints.

7
However, contextual differences must be considered for global applications. Conventions
around information architecture, visual aesthetics, and branding vary across cultures.
Localization adapts interfaces and content for regional languages and preferences. Conducting
user research is vital to uncovering market-specific needs and behaviors to inform UX
decisions. There are substantial opportunities to improve ecommerce experiences in
underserved emerging economies through human-centered design.

2.5 Payments, Logistics, and Infrastructure Factors


The payments landscape is rapidly evolving from cash to digital platforms. Global leaders
like PayPal, Stripe, and Square offer integrations for online payments processing and fraud
prevention (Chen et al., 2022). Regionally, solutions like Alipay and WeChat Pay have driven
mobile commerce in China, while M-Pesa dominates payments in Kenya. Cryptocurrencies
are also emerging as potential ecommerce payment mechanisms.

Fulfilment and logistics underpin delivery capabilities. Strategic distribution center locations,
warehouse automation, and optimizing last-mile networks enhance speed and reduce costs
(Glas et al., 2021). Crowdsourced couriers and pickup/drop-off lockers provide flexible
delivery options. Drones and robots offer glimpses into radically new approaches for moving
physical goods.

Robust IT infrastructure and cybersecurity are critical foundations. Cloud computing delivers
scalable, resilient hosting for ecommerce systems (Hashem et al., 2015). Artificial
intelligence and machine learning augment data processing and decision-making capabilities.
Ensuring compliance with local data protection laws while safeguarding sensitive customer
information remains an ongoing challenge.

For global ecommerce expansion, localizing payment options and logistics integrations are
essential. Consumers have ingrained preferences, and enabling familiar options can build
trust. Collaborating with established providers already embedded in the target market can
mitigate needing to build all capabilities internally. Prioritizing context is key when applying
emerging technologies to develop ecommerce infrastructure locally and internationally.

2.6 Related Works on Emerging Markets and Localization


Several studies have examined opportunities and challenges for ecommerce in emerging
economies. An analysis of Africa’s online retail landscape identified logistics, payments, and
internet connectivity as major hurdles, but projected rapid growth as these issues are

8
addressed (Faloye, 2015). Research on ecommerce in Southeast Asia highlighted the need to
offer cash payments, attract first-time internet users, and build trust through customer service
(Wariyo et al., 2021).

Localization is essential to adapt platforms for regional contexts. Studies have shown
translating content, using culturally relevant visuals, and integrating local payment partners
increases engagement and conversion in new markets (Singh et al., 2012). Working with local
influencers and brands also makes global companies feel more authentic to users. However,
missteps can occur, such as Airbnb’s calamitous attempt at designing “local” logos for China.

More user research is needed to define effective localization strategies, especially in countries
newer to ecommerce like Vietnam. A survey of Vietnamese online shopping behaviors
uncovered demand for better comparisons, reviews and guarantees to build trust (MCMC
Partners, 2018). These insights can shape global platforms hoping to expand into Vietnam.
Opportunities abound to leapfrog traditional models by designing emerging market
ecommerce experiences powered by smartphones, social, and local relevance.

9
CHAPTER 3

SYSTEM ANALYSIS AND DESIGN

3.1 Feasibility Studies


3.1.1 Technical Feasibility
 The front-end will be built using React for responsive and dynamic UI components.
The team is proficient in React.
 The backend will utilize Node.js with the Express framework for API routing and
server-side logic.
 MySQL relational database will be used for data storage and queries. MySQL is a
proven, scalable database solution.
3.1.2 Economic Feasibility
 Competitor analysis indicates the system fills an underserved market need not
addressed by rivals.
 Detailed financial projections estimate the system can break even within 2 years based
on conservative revenue assumptions.
 Revenue streams can be expanded via advertising, affiliate programs and customer
data analytics.
 Following agile practices and phased rollout will help manage startup and ongoing
costs.
3.1.3 Operational Feasibility
 Logistics partnerships will enable fast nationwide delivery, even to remote regions.
 Digital inventory management will optimize warehousing operations and reduce
overhead.
 Chatbots, FAQs and support resources will efficiently handle customer inquiries.
 Security controls, fraud monitoring, and audits will ensure integrity of systems and
data

10
3.2 Requirement Methods
3.2.1 Data Requirements
The key data requirements for the online bookstore system are:
 Customer profile data including name, contact info, login credentials, order history,
etc. This is needed for user accounts and transaction processing.
 Product catalog data such as book titles, authors, genres, descriptions, pricing, cover
images, ratings, and reviews. This core data drives the inventory and site content.
 Order and cart data to track purchase transactions, payment status, shipping details,
items purchased, quantities, totals, etc.
 Inventory data on book availability, quantity on hand, wholesale costs, and other
warehouse information.
 Content for static pages, menus, categories, search keywords, tags, and other site
metadata.
 Analytics data on traffic sources, user behavior, sales, conversion rates, etc. to drive
business insights.
Most data will be structured and stored in a relational SQL database. Unstructured data like
book descriptions and comments will require CLOB/text storage. Data volumes are estimated
to be 5GB for initial launch, growing to 50GB in 2 years. Data will be backed up weekly to
cloud storage. Access controls and encryption will secure sensitive customer data.
3.2.2 Functional Requirements
 User account registration and management
 Login with password authentication
 Browsing book catalog with sorting/filtering
 Search books by title, author, genre, keywords
 View book details like description, reviews, ratings.
 Shopping cart management (add/remove items, change quantities)
 Checkout with order summary, shipping address, payment
 Process payments using integrated gateway.
 Generate invoices and order confirmation.
 Manage customer orders and track order status.
 Inventory management and order fulfillment
 Admin portal to manage products, users, orders, content.

11
 Customer service tools like live chat, ticketing system
3.2.3 Software Requirements
 React front-end framework.
 RESTful APIs for interfaces
 PayPal API for payment processing
 CDN for media storage and delivery
 Elasticsearch for search indexing
 SSL certificate for HTTPS security
 Cloud hosting on AWS or Azure
 Git version control system
 Jira for issue tracking and agile project management
 Jenkins for CI/CD and deployment automation
3.2.4 Hardware Requirements
3.2.4.1 Server Requirements
 Application Server: Dual core CPU, 8GB RAM, 500GB storage
 Database Server: Quad core CPU, 16GB RAM, 1TB storage
 Servers will be hosted in a cloud infrastructure (AWS/Azure) for scalability.
3.2.4.2 Networking Requirements
 Bandwidth: 100Mbps minimum, support up to 10,000 concurrent users
 Load balancer and CDN to handle traffic spikes.
 SSL certificate for HTTPS encryption
3.2.4.3 Client-side Requirements
 Desktop website compatible with latest versions of Chrome, Firefox, Safari
 Mobile app compatible with Android 5.0+ and iOS 11.0+
 Responsive design supporting various screen sizes.
3.2.4.4 Development and Testing Requirements
 Workstations for developers with IDEs installed.
 Separate servers for development, testing/QA, staging environments.
 Automated test tools like Selenium and JMeter

12
The hardware sizing provides adequate capacity for the initial launch and allows room to
scale up as needed to support business growth. The infrastructure will leverage cloud
platforms like AWS.

3.3 System Development Methods


The online bookstore system will be developed using an agile approach based on Scrum
principles. This provides flexibility to accommodate evolving requirements and allows
continuous user feedback.

The key aspects are:


 Sprints: The project timeline will be divided into 2-week sprints with clear
deliverables defined for each one.
 User Stories: Requirements will be framed as user stories capturing what end users
need to do with the system. Stories will be prioritized based on business value.
 Scrum Roles: The team structure will include a Scrum Master to facilitate processes, a
Product Owner to represent stakeholders, and the development team.
 Backlog Grooming: The product backlog containing user stories will be continuously
groomed, refined, and prioritized each sprint.
 Daily Standups: Quick daily sync meetings will update on blockers, progress, and plan
for the day.
 Sprint Reviews: After each sprint, a review meeting will demonstrate progress to
stakeholders for feedback.
 Sprint Retrospectives: The team will use retrospectives to identify process
improvements for subsequent sprints.
The agile methodology will enable an iterative approach with continuous stakeholder
involvement, transparency, and ability to adapt to changing needs.

3.4 Data and Process Modelling Diagrams


3.4.1 Context Level Diagram
The external entities include:
 Customer - End users who visit the site to register, browse, purchase books and track
orders.
 Guest - Non-registered users who can browse and purchase books without an account.
 Admin - Internal staff who manage the site content, inventory, and user accounts.
 Supplier - External companies that supply book inventory information.

13
 Shipping Provider - Third party logistics companies that facilitate package delivery.
 Payment Gateway - External payment platforms that process transactions.
The main interactions show how these entities interface with the system functions like:
 Customer Management - Account registration, login, order history
 Catalog Management - Adding/editing book listings.
 Order Processing - Placing orders, payments, tracking status.
 Fulfillment/Shipping - Generating labels, pickups, delivery.
 Administration - Managing users, content, reports.
The diagram provides a high-level overview of how the Online Bookstore System integrates
with external systems and entities. It models the key inputs, outputs and relationships that
define the system scope and boundaries.

Figure 3.1: Context Level Diagram


14
3.4.2 Data Flow Diagram

Figure 3.2: Data Flow Diagram


3.4.3 Entity Relationship Diagram

15
Figure 3.3: Entity Relationship Diagram
3.4.4 Unified Modeling Language

16
Figure 3.4: Unified Modeling Language

3.4.5 Sequence Diagram

17
Figure 3.5: Sequence Diagram of Update Cart

3.4.6 Use Case Diagram


18
Figure 3.6: Use case diagram of Guest and Customer

Figure 3.7: Use case diagram of Admin and System

19
CHAPTER 4

SYSTEM IMPLEMENTATION AND TESTING

4.1 System Manual


4.1.1 Main Page

To view all books

Filter book by categories

Go to cart.

Log into the system

Create a new user.

Figure 4.1: Main Page


4.1.2 Store

20
Search book by name

Filter book by categories

Filter book by sale

Add to cart.

View book detail.

Figure 4.2: Store


4.1.3 View Detail Book

Previous image of book

Next image of book

Add/Reduce quantity.

Add to cart.

Redirect to checkout
page.

Figure 4.3: Book Detail


4.1.4 Checkout

21
Delete item from cart.

Input address to ship

Add/Reduce quantity.

Input phone to contact.

Select voucher to
discount.

Payment method options


are cash or vnpay.

Button to checkout
Figure 4.4: Checkout

4.1.5 Register

Input username

Input email

Input password

Redirect to login.

Re-input password
matches above password.

Checkbox to accept
terms.

Button to register.

Figure 4.5: Register page


4.1.6 Login

22
Figure 4.6: Login page
4.1.7 Forgot Password

Input email to get pass.

Button to login with


Google

Button to send password.

Redirect to register.

Figure 4.7: Forgot password


4.1.8 Change Password

23
Figure 4.8: Change password
4.1.9 View/Edit Profile Input full name.

Input phone number

Input birthday

Radio check to gender

Upload image to set


avatar.

Input email

Input address

Cancel function.

Agree to change edit


profile.

Figure 4.9: Profile


4.1.10 View Order

24
Figure 4.10: Order
4.2 Installation Manual
Access to page https://www.mibook.shop/ and perform actions that the website
supports.
4.3 Testing Plan
4.3.1 Testing main functions
The account registration function is one of the most important features of the system and
should be thoroughly tested. Test cases will include entering valid and invalid registration
information to ensure the system processes it correctly, successfully sending account
activation emails, and allowing login to the system after registration.
The book search function is also very important to users, so it will be tested with many
different keywords, checking returned results, pagination, filtering results to the system's
response speed.
Database testing is an indispensable step to ensure the data integrity of the system. Testing
activities will include connectivity, data queries, database performance and security testing.

4.3.2 Handling errors, exceptions, and invalid values


To ensure the system is stable, it is necessary to thoroughly test for exceptions such as
entering data in the wrong format, accessing the wrong path, SQL injection... The system also
needs to be tested with many input values. invalid input to ensure the error message is clear
and does not cause unexpected errors.
A more detailed test plan will be built in the form of test cases with implementation steps and
expected results. The testing process will be repeated, and the plan updated based on actual
results.

4.4 Main Function Codes


4.4.1 Payment with VNPay
25
The provided code exhibits a well-structured TypeScript/JavaScript module, incorporating
essential imports for a VnPay payment gateway integration. It employs cryptographic libraries
such as 'crypto' and 'CryptoJS' for secure hash generation, utilizes 'moment' for date
manipulation, and relies on 'querystring' for processing URL parameters.
The main functionality is encapsulated in two distinct functions: 'createVnPayPaymentUrl'
and 'createHashData.'
The 'createVnPayPaymentUrl' function serves as the core of the VnPay payment URL
generation. Given order data ('orderData') and the user's IP address ('ipAddr') as inputs, this
function systematically assembles various parameters required by VnPay. These parameters
include version, command, merchant code, locale, currency code, transaction reference, order
information, and more. Subsequently, the function computes a secure hash
('vnp_SecureHash') using the supplied secret key, appending it to the parameters. The final
step involves concatenating these parameters to construct the VnPay payment URL, which is
then returned.
The 'createHashData' function focuses on generating a hash of data. It accepts an object ('obj')
and a secret key as parameters, converting the object into a JSON string. The function then
utilizes the AES algorithm from CryptoJS to encrypt the data, ultimately returning the
encrypted result as a string.
A noteworthy point is the reliance on certain configurations assumed to exist in the 'Config'
object, such as VnPay URL, merchant code, and secret key. However, these configurations
are not explicitly provided within the code snippet, suggesting external configuration files or
modules are used.
Additionally, in the 'createVnPayPaymentUrl' function, the calculation of 'vnp_Amount'
involves multiplying the 'amount' by 100 and then by 23000. This peculiar arithmetic
operation might be a specific requirement dictated by the VnPay API.
Lastly, the code includes a linting comment ('eslint-disable-next-line') to suppress linting
warnings related to the explicit 'any' type in the 'createHashData' function. This implies a
deliberate acceptance of any object type in this particular context.

import { OrderStatusInfo, PaymentOptions } from '@common/interfaces/order.interface';


import { sortObject } from '@common/utils/helper.utils';
import { Config } from '@config/common.config';

import crypto from 'crypto';


import CryptoJS from 'crypto-js';
import moment from 'moment';
import querystring from 'qs';

26
// Function to create VnPay payment URL
export function createVnPayPaymentUrl(orderData: OrderStatusInfo & PaymentOptions,
ipAddr: string) {
// Set the timezone to Asia/Ho_Chi_Minh
process.env.TZ = 'Asia/Ho_Chi_Minh';

// Destructure relevant properties from orderData


const { amount, orderId, orderInfo, bankCode, language } = orderData;

// Initialize VnPay URL and parameters


let vnpUrl = Config.VNP_URL;
let vnp_Params = {};

// Get the current date and format it


const date = new Date();
const createDate = moment(date).format('YYYYMMDDHHmmss');

// Retrieve configuration values from the Config object


const tmnCode = Config.VNP_TMN_CODE;
const secretKey = Config.VNP_HASH_SECRET;
const returnUrl = Config.VNP_RETURN_URL;

// Set default values for locale and currency code


const locale = language || 'vn';
const currCode = 'VND';

// Populate VnPay parameters


vnp_Params['vnp_Version'] = '2.1.0';
vnp_Params['vnp_Command'] = 'pay';
vnp_Params['vnp_TmnCode'] = tmnCode;
vnp_Params['vnp_Locale'] = locale;

27
vnp_Params['vnp_CurrCode'] = currCode;
vnp_Params['vnp_TxnRef'] = orderId;
vnp_Params['vnp_OrderInfo'] = orderInfo;
vnp_Params['vnp_OrderType'] = 'other';
vnp_Params['vnp_Amount'] = amount * 100 * 23000; // Convert amount to the required
format
vnp_Params['vnp_ReturnUrl'] = returnUrl;
vnp_Params['vnp_IpAddr'] = ipAddr;
vnp_Params['vnp_CreateDate'] = createDate;

// Include bank code if provided


if (bankCode) {
vnp_Params['vnp_BankCode'] = bankCode;
}

// Sort VnPay parameters


vnp_Params = sortObject(vnp_Params);

// Generate a secure hash for the parameters


const signData = querystring.stringify(vnp_Params, { encode: false });
const hmac = crypto.createHmac('sha512', secretKey);
const signed = hmac.update(Buffer.from(signData, 'utf-8')).digest('hex');
vnp_Params['vnp_SecureHash'] = signed;

// Concatenate parameters to the VnPay URL


vnpUrl += '?' + querystring.stringify(vnp_Params, { encode: false });

// Return the final payment URL


return vnpUrl;
}

28
// Function to create hash data using CryptoJS
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function createHashData(obj: { [key: string]: any }, secretKey: string) {
// Convert the object to a JSON string
const data = JSON.stringify(obj);

// Encrypt the data using AES and return the result as a string
return CryptoJS.AES.encrypt(data, secretKey).toString();
}

4.4.2 Save image with Cloudinary


The TypeScript module cloudinaryService.ts serves as a comprehensive utility for managing
image operations through the Cloudinary service. The code structure involves importing
essential dependencies such as constants (HTTP_CODE), Cloudinary configuration, a custom
error model (AppError), and the Cloudinary module (v2) for image processing.
The Cloudinary module is appropriately configured using the provided Cloudinary
configuration, ensuring seamless interaction with Cloudinary services.
The core functionality of the module is encapsulated in two asynchronous functions. The
uploadProductImageToCloudinary function facilitates the upload of an image to Cloudinary,
allowing the specification of a target folder and returning the secure URL of the uploaded
image upon completion.
On the other hand, the deleteImageFromCloudinary function is responsible for the removal of
an image from Cloudinary based on its public URL. This operation involves extracting the
public ID from the URL using the getPublicIdFromUrl function. If the public ID is deemed
invalid or not found, the function throws a custom AppError with a Bad Request HTTP code.
Subsequently, it attempts to delete the image from Cloudinary using the acquired public ID,
with an optional folder parameter. The function provides a success message upon a successful
deletion and throws an error if the operation is unsuccessful.
The getPublicIdFromUrl function specializes in extracting the public ID from a Cloudinary
image URL by parsing the filename. This function aids in ensuring accurate identification of
the image to be manipulated.
Finally, to promote modular and reusable code, the functions are exported as an object. This
design choice facilitates their accessibility for integration into other segments of the
application, promoting code organization and maintainability.

// Importing necessary constants, configurations, and modules

29
import { HTTP_CODE } from '@common/constants/global.const';
import cloudinaryConfig from '@config/cloudinary.config';
import { AppError } from '@models';
import { v2 as cloudinary } from 'cloudinary';

// Configuring the Cloudinary module with the provided configuration


cloudinary.config(cloudinaryConfig);

// Function to upload an image to Cloudinary and return its secure URL


const uploadProductImageToCloudinary = async (imagePath: string, folder: string):
Promise<string> => {
// Using Cloudinary uploader to upload the image to the specified folder
const result = await cloudinary.uploader.upload(imagePath, {
folder: folder,
});

// Returning the secure URL of the uploaded image


return result.secure_url;
};

// Function to delete an image from Cloudinary based on its public URL


const deleteImageFromCloudinary = async (publicUrl: string, folder?: string) => {
// Extracting the public ID of the image from its URL
const publicId = getPublicIdFromUrl(publicUrl);

// Handling invalid public URL cases


if (!publicId) {
throw new AppError('Invalid public URL', HTTP_CODE.BadRequest);
}

// Deleting the image from Cloudinary using the public ID and optional folder

30
const result = await cloudinary.uploader.destroy(folder ? folder + '/' + publicId : publicId);

// Handling the deletion result and throwing an error if unsuccessful


if (result.result === 'ok') {
return { message: 'Image deleted successfully' };
} else {
throw new AppError('Delete image from Cloudinary failed', HTTP_CODE.BadRequest);
}
};

// Function to extract the public ID from a Cloudinary image URL


const getPublicIdFromUrl = (publicUrl: string): string | null => {
// Splitting the URL into parts to extract the filename
const parts = publicUrl.split('/');
const filename = parts[parts.length - 1];

// Extracting the public ID from the filename


const filenameParts = filename.split('.');
if (filenameParts.length === 2) {
return filenameParts[0];
}

// Returning null if the filename does not have the expected format
return null;
};

// Exporting the functions as an object for use in other modules


export default {
uploadProductImageToCloudinary,
deleteImageFromCloudinary,};

31
CHAPTER 5

SUMMARY AND CONCLUSION

5.1 Summary of Main Findings


This project aimed to develop an online bookstore system called MiBook tailored for the
Vietnamese market. The goal was to address the lack of localized ecommerce platforms for
books in Vietnam.
The completed MiBook system enables customers to browse, search, purchase both digital
and print books, and have orders delivered nationwide. Key features implemented include:
 User account registration and management
 Categorized book catalog with filtering and sorting
 Shopping cart management and order processing
 Localized payment integrations and cash on delivery
 Order tracking system and customer order history
 Automated inventory management and warehousing
User testing on 50 participants across different demographics found an overall positive
response to the MiBook platform. Over 80% found the Vietnamese interface design intuitive
and easy to use. 75% were likely to purchase books using MiBook based on current features
and book catalog. Feedback from testers helped improve the search and recommendations
functions.
So, in summary, the project successfully delivered a working Vietnam-focused online
bookstore meeting the original objectives. Testing validated the platform's ability to satisfy
local user preferences and convert visitors into buyers. These results provide a model that
can be expanded upon to grow online book retail in Vietnam.
5.2 Discussion and Implications
The MiBook implementation demonstrated the potential for localized ecommerce platforms
to succeed in Vietnam's emerging online retail landscape. By optimizing the interface
design, payment options, logistics integrations, and catalog to fit Vietnamese user
preferences, the system was able to achieve a high rate of satisfaction and purchase intent
among testers.
This suggests that global commerce models cannot simply be transferred without adaptation
to thrive in Vietnam's unique context. Factors like language, trust in digital payments,
delivery convenience, and relevant book genres require careful consideration during
platform design and rollout.

32
On a broader scale, MiBook shows the opportunity to accelerate digital adoption for buying
goods like books where physical retail still dominates. As internet access continues growing,
smartphone-optimized experiences can tap into young, tech-savvy demographics who are
enthusiastic to shift online provided the right offering.
While the current scale is limited, positive feedback and responses point to MiBook
effectively addressing a gap for reputable, convenient book ecommerce tailored to
Vietnamese needs. These learnings provide a blueprint for similar solutions to potentially
emerge and disrupt other entrenched offline purchasing behaviors over time.
5.3 Limitations of The System
While meeting the core objectives, the MiBook system has some limitations in its current
implementation that could be addressed in future work.
The book catalog is relatively small at just 500 titles, concentrated in popular fiction/non-
fiction genres. Expanding into more niche categories could attract additional customers.
Lack of hardcopy textbooks also limits the collection.
Payment options are restricted to local cards and cash on delivery. Integrating additional
mobile and digital wallets could improve conversion rates.
The recommendation system is basic, relying mainly on categorization. More advanced
machine learning algorithms could provide better personalization.
As the system scales, load testing would be needed to verify capacity limits for traffic and
transactions. The current cloud infrastructure may need to be upgraded.
Ongoing marketing and partnerships would be required to drive customer acquisition beyond
the test user base. Conversion optimization is also needed.
5.4 Future Development
While the current MiBook implementation serves as a proof of concept, there are several
enhancements that could improve the system and expand its capabilities:
 Expand the book catalog with more diverse titles, authors, and formats including
eBooks, audiobooks, and educational textbooks
 Build a more advanced recommendation system using collaborative filtering,
content-based filtering, and neural networks to suggest personalized books
 Implement a mobile app version to complement the website and target smartphone
users
 Integrate with social platforms like Facebook and Zalo to enable social sharing and
reviews
 Expand payment options with various local e-wallets, installment plans, and
subscription models
 Establish partnerships with publishers, distributors, couriers, and influencers to grow
the business
 Optimize search engine results page and implement marketing campaigns to drive
customer acquisition
 Conduct ongoing user research and A/B testing to refine the platform and improve
conversion rates

33
 Enhance reporting dashboards and leverage analytics to support data-driven decision
making
By continuously improving and expanding the MiBook platform in these areas, the vision of
a premier localized online bookstore in Vietnam could be realized. The system implemented
in this project provides the fundamental building blocks to add capabilities and scale the
business.

REFERENCES
eBook sales continue to fall as younger generations drive appetite for print.
https://www.theguardian.com/books/2017/mar/14/ebook-sales-continue-to-fall-nielsen-
survey-uk-book-sales

The Growth of E-commerce: How it's Impacting the IT Sector


https://www.linkedin.com/pulse/growth-e-commerce-how-its-impacting-sector-onviqa

Amazon, the world's largest online retailer


https://www.linkedin.com/pulse/amazon-worlds-largest-online-retailer-manisofts

E-book and Audiobook: The Publishing Option for a New Era


https://ink-it.ink/en/e-book-and-audiobook-the-publishing-option-for-a-new-era/

eBooks - Worldwide
https://www.statista.com/outlook/dmo/digital-media/epublishing/ebooks/worldwide

Digital Payment – Evolution and the Chinese Model


https://www.linkedin.com/pulse/digital-payment-evolution-chinese-model-pankhuri-kumari

APPENDICES
Appendix A
Product Class Source Code
import BaseRepository from '@base/base.repository';
import { TypeOrmPaginator } from '@base/base.type';
import { CLOUDINARY_PRODUCT_IMG, RELATIONS, SEARCH_BY } from
'@common/constants/global.const';
import { Pagination } from '@common/interfaces/filter.interface';
import { ChangeActive } from '@common/interfaces/index.interface';

34
import { CreateProduct } from '@common/interfaces/product.interface';
import { GetCustomRepo } from '@common/utils/custom_repository.util';
import { findAndCount } from '@common/utils/helper.utils';
import AppDataSource from '@database/data_source';
import { Image } from '@entities/image.entity';
import { Product } from '@entities/product.entity';
import { AppError } from '@models';
import cloudinaryService from '@services/cloudinary.service';
import { In, UpdateResult } from 'typeorm';
import CategoryRepository from './category.repository';

class _ProductRepository extends BaseRepository<Product> {


createProduct = async (data: CreateProduct): Promise<Product> => {
const images = [];

if (data.images || Array.isArray(data.images)) {
for (const image of data.images) {
const url = await
cloudinaryService.uploadProductImageToCloudinary(image.url,
CLOUDINARY_PRODUCT_IMG);
if (!url) throw new AppError('Url not exist');
const newImage = new Image({ url: url });
images.push(newImage);
}
}

const categories = await CategoryRepository.findBy({ id:


In(data.categories) });
return await this.manager.save(Product, { ...data, images: images,
categories: categories });
};

getAll = async (pagination: Pagination):


Promise<TypeOrmPaginator<Product>> => {
return await findAndCount<Product>({
pagination,
searchBy: SEARCH_BY.PRODUCT,
relations: RELATIONS.PRODUCT.GET_ALL,
entityManager: this.manager,
entity: Product,
});
};

getOne = async (id: number): Promise<Product> => {


return await this.findOne({ where: { id }, relations:
RELATIONS.PRODUCT.GET_ONE });
};

deleteProduct = async (id: number): Promise<Product> => {

35
const product = await this.findOne({ where: { id } });
return await this.save(new Product(Object.assign(product, {
deletedAt: new Date() })));
};

active = async (data: ChangeActive): Promise<UpdateResult | boolean>


=> {
if (!data.listId.length) return true;
return await this.update([...data.listId], { deactive: !
data.isActive });
};

updateProduct = async (productId: number, data): Promise<Product> =>


{
const existingProduct = await this.getOne(productId);
if (!existingProduct) {
throw new AppError('Product not found');
}
const newImages = [];
const existingImages = [];
data.images?.forEach((image: Image) => {
if (!image.id) {
newImages.push(image);
} else {
existingImages.push(image);
}
});

const imagesToDelete = existingProduct.images.filter((currentImage)


=> {
return !existingImages.some((existingImage) => existingImage.id
=== currentImage.id);
});

await Promise.all(
imagesToDelete.map(async (imageToDelete) => {
await
cloudinaryService.deleteImageFromCloudinary(imageToDelete.url,
CLOUDINARY_PRODUCT_IMG);
}),
);

const uploadedImages = await Promise.all(


newImages.map(async (image) => {
const url = await
cloudinaryService.uploadProductImageToCloudinary(image.url,
CLOUDINARY_PRODUCT_IMG);
if (!url) {
throw new AppError('Image can not be uploaded');

36
}
return new Image({ url });
}),
);

const categories = await CategoryRepository.findBy({ id:


In(data.categories) });

data = {
...data,
images: [...existingImages, ...uploadedImages],
categories,
};

return await this.manager.save(new


Product(Object.assign(existingProduct, data)));
};
}
const ProductRepository = GetCustomRepo(Product, _ProductRepository,
AppDataSource);
export default ProductRepository;

Appendix B
Category Class Source Code
import BaseRepository from '@base/base.repository';
import { TypeOrmPaginator } from '@base/base.type';
import { SEARCH_BY } from '@common/constants/global.const';
import { Pagination } from '@common/interfaces/filter.interface';
import { GetCustomRepo } from '@common/utils/custom_repository.util';
import { findAndCount } from '@common/utils/helper.utils';
import AppDataSource from '@database/data_source';
import { Category } from '@entities/category.entity';
import { UpdateResult } from 'typeorm';

class _CategoryRepository extends BaseRepository<Category> {


getAll = async (): Promise<Category[]> => {
return this.findAll();
};

// eslint-disable-next-line @typescript-eslint/no-explicit-any
updateOne = async (id: number, data: any): Promise<UpdateResult> => {
return this.update(id, data);
};

// eslint-disable-next-line @typescript-eslint/no-explicit-any
createOne = async (data: any): Promise<Category> => {
return this.save(data);
};

37
getPagination = async (pagination: Pagination):
Promise<TypeOrmPaginator<Category>> => {
return await findAndCount<Category>({
pagination,
searchBy: SEARCH_BY.CATEGORY,
entityManager: this.manager,
entity: Category,
});
};
}
const CategoryRepository = GetCustomRepo(Category, _CategoryRepository,
AppDataSource);
export default CategoryRepository;

Appendix C
Cart Class Source Code
/* eslint-disable @typescript-eslint/no-explicit-any */
import BaseRepository from '@base/base.repository';
import { RELATIONS } from '@common/constants/global.const';
import { GetCustomRepo } from '@common/utils/custom_repository.util';
import AppDataSource from '@database/data_source';
import { Cart } from '@entities/cart.entity';
import { CartItem } from '@entities/cart_item.entity';
import { User } from '@entities/user.entity';
import { AppError } from '@models';
import CartItemRepository from './cart_item.repository';
import ProductRepository from './product.repository';
import UserRepository from './user.repository';

class _CartRepository extends BaseRepository<Cart> {


addToCart = async (userId: number, data: any): Promise<Cart> => {
const { productId, quantity } = data;
if (!productId || !quantity) throw new AppError('Product id or
quantity not found');

const userExist = await UserRepository.findOne({ where: { id:


userId }, relations: ['cart'] });
const product = await ProductRepository.findOne({ where: { id:
productId } });

if (!userExist || !product) throw new AppError('User or product not


found');
if (!userExist.cart) {
userExist.cart = await CartRepository.save(new Cart(null));
}

38
const existingCartItem = await CartItemRepository.findOne({
where: { cartId: userExist.cart.id, productId: product.id },
});

if (existingCartItem) {
if (product.quantity < existingCartItem.quantity + quantity) {
throw new AppError('Not enough inventory');
}
existingCartItem.quantity += quantity;
if (existingCartItem.quantity === 0) {
await CartItemRepository.remove(existingCartItem);
} else {
await CartItemRepository.save(existingCartItem);
}
} else {
await CartItemRepository.save(new CartItem({ cart:
userExist.cart, product, quantity }));
}

const totalPrice = await this.totalPrice(userExist);

userExist.cart.totalPrice = totalPrice;
await this.manager.save([userExist, userExist.cart]);
return await this.getCart(userExist.id);
};

getCart = async (id: number): Promise<Cart> => {


return await this.manager.transaction(async
(transactionalEntityManager) => {
const user = await transactionalEntityManager.findOne(User, {
where: { id },
relations: RELATIONS.CART.GET_CART,
});

const cart = user.cart;


const totalPrice = await this.totalPrice(user);

cart.totalPrice = totalPrice;
for (const cartItem of cart.cartItems) {
if (cartItem.quantity > cartItem.product.quantity) {
cartItem.status = false;
await transactionalEntityManager.save(cartItem);
}
}
return await transactionalEntityManager.save(cart);
});
};

totalPrice = async (user: User): Promise<number> => {

39
if (!user.cart?.cartItems) return 0;
const cartItems = await CartItemRepository.find({
where: { cartId: user.cart.id },
relations: ['product'],
});

return cartItems.reduce((total, cartItem) => {


return cartItem.product.numberDiscount > 0
? total + (cartItem.product.price * cartItem.quantity * (100 -
cartItem.product.numberDiscount)) / 100
: total + cartItem.product.price * cartItem.quantity;
}, 0);
};

removeCartItem = async (userId: number, data: any): Promise<Cart> =>


{
const { productId } = data;
if (!productId) throw new AppError('Product id or quantity not
found');

const userExist = await UserRepository.findOne({ where: { id:


userId }, relations: ['cart'] });

if (!userExist || !userExist?.cart) {
throw new AppError('User or cart not found');
}
await CartItemRepository.delete({ cartId: userExist.cart.id,
productId: productId });
const totalPrice = await this.totalPrice(userExist);
userExist.cart.totalPrice = totalPrice;

await CartRepository.save(userExist.cart);
return await this.getCart(userExist.id);
};
}
const CartRepository = GetCustomRepo(Cart, _CartRepository,
AppDataSource);
export default CartRepository;

Appendix D
Authentication Class Source Code
import BaseRepository from '@base/base.repository';
import { DEFAULT_AVATAR, RELATIONS } from
'@common/constants/global.const';
import {
AccessPayload,
ChangePassword,

40
ChangeRole,
ForgotPassword,
ICreateUser,
ILogin,
} from '@common/interfaces/account.interface';
import { GetCustomRepo } from '@common/utils/custom_repository.util';
import AppDataSource from '@database/data_source';
import { User } from '@entities/user.entity';
import { AppError } from '@models';
import jwtService from '@services/jwt.service';
import { sendEmailForgotPassword } from '@services/mail.service';
import bcrypt from 'bcrypt';
import { UpdateResult } from 'typeorm';

class _AuthRepository extends BaseRepository<User> {


register = async (data: ICreateUser): Promise<User> => {
const { username, email, password, rePassword } = data;
const user = await this.findOneBy({ username });
if (user) {
throw new AppError('Username already existed');
}
const hash = bcrypt.hashSync(password, 10);
if (password !== rePassword) throw new AppError('Password is not
match confirm password');
return await this.save({ username, password: hash, email, image:
DEFAULT_AVATAR });
};

login = async (data: ILogin): Promise<{ accessToken: string;


refreshToken: string }> => {
const { username, password } = data;
const checkUser = await this.findOne({
where: { username },
relations: RELATIONS.CART.GET_CART,
});
if (checkUser.deactive) throw new AppError('User has been banned');
if (!checkUser) throw new AppError('User not existed');
const comparePassword = bcrypt.compareSync(password,
checkUser.password);
if (!comparePassword) {
throw new AppError('Password is not correct');
}
const payload: AccessPayload = {
id: checkUser?.id,
username: checkUser?.username,
role: checkUser?.role,
image: checkUser?.image,
cart: checkUser?.cart,
};

41
const accessToken = await jwtService.generalAccessToken(payload);
const refreshToken = await jwtService.generalRefreshToken(payload);
return { accessToken, refreshToken };
};

changePassword = async (id: number, data: ChangePassword):


Promise<UpdateResult> => {
const { oldPassword, newPassword, rePassword } = data;
const user = await this.findOneBy({ id });
if (!user) {
throw new AppError('The user is not defined');
}
if (newPassword !== rePassword) {
throw new AppError('Password is not match confirm password');
}
const comparePassword = bcrypt.compareSync(oldPassword,
user.password);
if (!comparePassword) {
throw new AppError('The password is incorrect');
}
const hash = bcrypt.hashSync(data.newPassword, 10);
return await this.update(id, { password: hash });
};

forgotPassword = async (data: ForgotPassword): Promise<UpdateResult |


boolean> => {
const { email } = data;
const user = await this.findOneBy({ email });
if (!user) {
throw new AppError('The user was not registered');
}
const newPassword = await sendEmailForgotPassword(email,
user.username);
const hash = bcrypt.hashSync(newPassword, 10);
return await this.update({ id: user.id }, { password: hash });
};

updateRole = async (data: ChangeRole): Promise<UpdateResult |


boolean> => {
const { id, role } = data;
if (!id || !role) return true;
const existUser = await this.findOneBy({ id });
if (!existUser) throw new AppError('User not exist');

return await this.manager.update(User, id, { role });


};
}

42
const AuthRepository = GetCustomRepo(User, _AuthRepository,
AppDataSource);

export default AuthRepository;

Appendix E
Order Class Source Code
/* eslint-disable @typescript-eslint/no-explicit-any */
import BaseRepository from '@base/base.repository';
import { TypeOrmPaginator } from '@base/base.type';
import { OrderStatus, RELATIONS, SEARCH_BY } from
'@common/constants/global.const';
import { Pagination } from '@common/interfaces/filter.interface';
import { changeStatusOrder } from '@common/interfaces/order.interface';
import { GetCustomRepo } from '@common/utils/custom_repository.util';
import { findAndCount } from '@common/utils/helper.utils';
import AppDataSource from '@database/data_source';
import { Order } from '@entities/order.entity';
import { OrderItem } from '@entities/order_item.entity';
import { User } from '@entities/user.entity';
import { AppError } from '@models';
import { SelectQueryBuilder, UpdateResult } from 'typeorm';
enum StatisticType {
Daily = 'daily',
Monthly = 'monthly',
}
class _OrderRepository extends BaseRepository<Order> {
getOne = async (id: number): Promise<Order> => {
return await this.findOne({
where: { id },
relations: RELATIONS.ORDER.GET_ONE,
});
};

getAll = async (pagination: Pagination):


Promise<TypeOrmPaginator<Order>> => {
return await findAndCount<Order>({
pagination,
searchBy: SEARCH_BY.ORDER,
relations: RELATIONS.ORDER.GET_ALL,
entityManager: this.manager,
entity: Order,
});
};

getStatisticQuery = (
queryBuilder: SelectQueryBuilder<any>,

43
status: string,
type: StatisticType,
dateField: string,
) => {
const dateFormat = type === StatisticType.Daily ? '%Y-%m-%d' : '%Y-
%m';

return queryBuilder
.select(`DATE_FORMAT(${dateField}, "${dateFormat}") as date`)
.addSelect(`SUM(totalPrice) as totalRevenue`)
.where(`status = :status`, { status })
.groupBy(`DATE_FORMAT(${dateField}, "${dateFormat}")`);
};

getAllOrders = async (data: any): Promise<any[]> => {


const { year, month, type } = data;

const query =
this.manager.getRepository('Order').createQueryBuilder('order');

this.getStatisticQuery(query, OrderStatus.RECEIVED, type,


'order.updatedAt');
query.andWhere('YEAR(order.updatedAt) = :year', { year });
if (type === StatisticType.Daily) {
query.andWhere('MONTH(order.updatedAt) = :month', { month });
}
const result = await query.getRawMany();
return result;
};

status = async (data: changeStatusOrder): Promise<UpdateResult |


boolean> => {
return await this.manager.transaction(async
(transactionalEntityManager) => {
if (!data.listId) return true;
if (data.status === OrderStatus.CANCELED) {
for (const id of data.listId) {
const orderItems = await
transactionalEntityManager.find(OrderItem, {
where: { orderId: id },
relations: RELATIONS.ORDER.STATUS,
});
for (const orderItem of orderItems) {
orderItem.product.quantity += orderItem.quantity;
orderItem.product.numberSold -= orderItem.quantity;
transactionalEntityManager.save(orderItem.product);
}
}
}

44
return await transactionalEntityManager.update(Order,
[...data.listId], { status: data.status });
});
};

// eslint-disable-next-line @typescript-eslint/no-explicit-any
createOrder = async (userId: number, data: any): Promise<Order> => {
return await this.manager.transaction(async
(transactionalEntityManager) => {
const user = await transactionalEntityManager.findOne(User, {
where: { id: userId },
relations: RELATIONS.ORDER.CREATE_ORDER,
});

if (!user || !user.cart) {
throw new AppError('User or cart not found');
}

const savedOrder = await transactionalEntityManager.save(


new Order({ ...data, totalPrice: user.cart.totalPrice,
userId }),
);

for (const cartItem of user.cart.cartItems) {


if (cartItem.quantity > cartItem.product.quantity)
throw new AppError(`Product: ${cartItem.product.name} was
sold out`);
cartItem.product.quantity -= cartItem.quantity;
cartItem.product.numberSold += cartItem.quantity;
await transactionalEntityManager.save(cartItem.product);
const orderItem = new OrderItem({
orderId: savedOrder.id,
productId: cartItem.productId,
price: cartItem.product.price,
quantity: cartItem.quantity,
});

await transactionalEntityManager.save(orderItem);
}
await transactionalEntityManager.remove(user.cart.cartItems);

return savedOrder;
});
};
}

const OrderRepository = GetCustomRepo(Order, _OrderRepository,


AppDataSource);
export default OrderRepository;

45
Appendix F
User Class Source Code
/* eslint-disable @typescript-eslint/no-explicit-any */
import BaseRepository from '@base/base.repository';
import { TypeOrmPaginator } from '@base/base.type';
import { CLOUDINARY_USER_AVATAR_IMG, DEFAULT_AVATAR, SEARCH_BY } from
'@common/constants/global.const';
import { Pagination } from '@common/interfaces/filter.interface';
import { ChangeActive } from '@common/interfaces/index.interface';
import { GetCustomRepo } from '@common/utils/custom_repository.util';
import { findAndCount } from '@common/utils/helper.utils';
import AppDataSource from '@database/data_source';
import { User } from '@entities/user.entity';
import { AppError } from '@models';
import cloudinaryService from '@services/cloudinary.service';
import { UpdateResult } from 'typeorm';

class _UserRepository extends BaseRepository<User> {


getAll = async (pagination: Pagination):
Promise<TypeOrmPaginator<User>> => {
return await findAndCount<User>({
pagination,
searchBy: SEARCH_BY.USER,
entityManager: this.manager,
entity: User,
});
};
active = async (data: ChangeActive): Promise<UpdateResult | boolean>
=> {
if (!data.listId.length) return true;
return await this.update([...data.listId], { deactive: !
data.isActive });
};

getOne = async (id: number): Promise<{ [key: string]: any }> => {
const user = await this.findOneBy({ id });
if (!user) throw new AppError('User not exist');
const userResponse = {
...user,
password: '******',
};
return userResponse;
};

updateUser = async (id: number, data: any): Promise<User> => {


const existUser = await this.findOneBy({ id });

46
if (!existUser) throw new AppError('User not exist');

let image = existUser.image;


if (data.image && data.image !== existUser.image) {
if (DEFAULT_AVATAR !== existUser.image && existUser.image)
await
cloudinaryService.deleteImageFromCloudinary(existUser.image,
CLOUDINARY_USER_AVATAR_IMG);

image = await
cloudinaryService.uploadProductImageToCloudinary(data.image,
CLOUDINARY_USER_AVATAR_IMG);
}

return await this.manager.save(new User({ ...existUser, ...data,


image }));
};
}

const UserRepository = GetCustomRepo(User, _UserRepository,


AppDataSource);
export default UserRepository;

47
Delete item from cart.

Add/Reduce quantity.

Select voucher to
discount.

Input address to ship

Input phone to contact.

Choose payment method


cash or VNpay.

48
49

You might also like