Hằng số
| Trường | Chi tiết |
|---|---|
| Tệp nguồn | packages/core/src/common/constants.ts (294 dòng) |
| Import | import { <ClassName> } from '@nx/core'; |
| Mẫu thiết kế | Hằng số lớp tĩnh với xác thực dựa trên Set |
| Tổng số lớp | 14 |
Tổng quan
Tất cả hằng số toàn ứng dụng được tập trung trong một tệp duy nhất (src/common/constants.ts) bên trong gói @nx/core. Mọi gói khác import từ @nx/core thay vì tự định nghĩa các chuỗi cố định riêng.
Mỗi lớp hằng số tuân theo một mẫu nhất quán:
- Trường static readonly -- các giá trị hằng số thực tế.
SCHEME_SET/TYPE_SET-- mộtSetchứa tất cả giá trị hợp lệ, dùng cho kiểm tra thành viên O(1).- Phương thức
isValid()-- phương thức tĩnh ủy quyền cho Set.
import { <ClassName> } from '@nx/core';
// Use a constant
const schema = PostgresSchemas.PUBLIC;
// Validate input
if (!PostgresSchemas.isValid(userInput)) {
throw new Error('Invalid schema');
}1. Hạ tầng
RedisModes
Bộ chọn chế độ kết nối Redis. Xác định ứng dụng kết nối đến một instance Redis đơn lẻ hay Redis Cluster.
| Tên | Giá trị | Mô tả |
|---|---|---|
SINGLE | 'single' | Instance Redis đơn lẻ (standalone) |
CLUSTER | 'cluster' | Redis Cluster (đa node) |
INFO
RedisModes không bao gồm SCHEME_SET hoặc phương thức isValid(). Việc xác thực được xử lý ở tầng cấu hình.
Cách sử dụng
import { RedisModes } from '@nx/core';
const redisMode = applicationEnvironment.get<string>('APP_ENV_WEBSOCKET_REDIS_MODE')
?? RedisModes.SINGLE;
if (redisMode === RedisModes.CLUSTER) {
// Initialize cluster connection
}PostgresSchemas
Định danh cho bảy schema PostgreSQL được sử dụng trên toàn bộ cơ sở dữ liệu.
| Tên | Giá trị | Mô tả |
|---|---|---|
PUBLIC | 'public' | Người dùng, vai trò, sản phẩm, merchant, organizer, cấu hình |
PRICING | 'pricing' | Giá vé, quy tắc giá, chi phí, thuế |
ALLOCATION | 'allocation' | Bố trí chỗ ngồi sự kiện và sơ đồ địa điểm |
SALE | 'sale' | Đơn hàng và mục đơn hàng |
INVENTORY | 'inventory' | Quản lý kho và tồn kho |
FINANCE | 'finance' | Ví, giao dịch, danh mục |
PAYMENT | 'payment' | Cấu hình webhook |
Phương thức Hỗ trợ
| Phương thức | Chữ ký | Mô tả |
|---|---|---|
isValid | isValid(input: string): boolean | Trả về true nếu input là thành viên của SCHEME_SET |
Cách sử dụng
import { PostgresSchemas } from '@nx/core';
import { pgSchema } from 'drizzle-orm/pg-core';
// Define a table in the pricing schema
const pricingSchema = pgSchema(PostgresSchemas.PRICING);
const Fare = pricingSchema.table('Fare', { /* columns */ });
// Validate schema name
if (!PostgresSchemas.isValid(input)) {
throw new Error(`Unknown schema: ${input}`);
}
// Use in migration config
const schemaFilter = [
PostgresSchemas.PUBLIC,
PostgresSchemas.ALLOCATION,
PostgresSchemas.PRICING,
];2. Bảng / Giao diện
TableConst
Giá trị mặc định cho các thành phần bảng dữ liệu và lưới được sử dụng bởi cả phân trang backend và giao diện frontend.
| Tên | Giá trị | Mô tả |
|---|---|---|
DEFAULT_NAME | 'System' | Tên hiển thị mặc định của hệ thống |
DEFAULT_PAGINATION | { pageIndex: 0, pageSize: 50 } | Trang bắt đầu và kích thước trang |
DEFAULT_ROWS_PER_PAGE_OPTIONS | [25, 50, 75, 100] | Các tùy chọn bộ chọn kích thước trang |
DEFAULT_SORTING | [{ id: 'createdAt', desc: true }] | Sắp xếp mặc định: mới nhất trước |
DEFAULT_FILTER | {} | Đối tượng bộ lọc rỗng |
DEFAULT_SIZE | 180 | Chiều rộng cột mặc định theo pixel |
INFO
TableConst không bao gồm SCHEME_SET hoặc phương thức isValid() vì nó chứa các đối tượng cấu hình mặc định, không phải giá trị liệt kê.
Cách sử dụng
import { TableConst } from '@nx/core';
async findAll(opts?: PaginationOptions) {
const pagination = opts?.pagination ?? TableConst.DEFAULT_PAGINATION;
const sorting = opts?.sorting ?? TableConst.DEFAULT_SORTING;
return this.find({
limit: pagination.pageSize,
offset: pagination.pageIndex * pagination.pageSize,
orderBy: sorting.map(s => ({ [s.id]: s.desc ? 'desc' : 'asc' })),
});
}TableConfigurations
Các khóa để lưu trữ cấu hình hiển thị bảng theo từng người dùng (hiển thị cột, thứ tự, kích thước). Mỗi khóa tương ứng với một bảng trên màn hình quản trị.
| Tên | Giá trị |
|---|---|
TABLE_ORGANIZER | 'TABLE_ORGANIZER' |
TABLE_MERCHANT | 'TABLE_MERCHANT' |
TABLE_CATEGORY | 'TABLE_CATEGORY' |
TABLE_PRODUCT | 'TABLE_PRODUCT' |
TABLE_USER | 'TABLE_USER' |
TABLE_CATEGORY_TEMPLATE | 'TABLE_CATEGORY_TEMPLATE' |
TABLE_MERCHANT_TYPE | 'TABLE_MERCHANT_TYPE' |
TABLE_EMPLOYEE | 'TABLE_EMPLOYEE' |
TABLE_SALE_CHANNEL | 'TABLE_SALE_CHANNEL' |
TABLE_DEVICE | 'TABLE_DEVICE' |
TABLE_ROLE | 'TABLE_ROLE' |
TABLE_TRANSACTION | 'TABLE_TRANSACTION' |
TABLE_REVENUE_REPORT | 'TABLE_REVENUE_REPORT' |
TABLE_ORDER_REPORT | 'TABLE_ORDER_REPORT' |
TABLE_CUSTOMER | 'TABLE_CUSTOMER' |
TABLE_INVOICE | 'TABLE_INVOICE' |
TABLE_TERMINAL | 'TABLE_TERMINAL' |
TABLE_VENDOR | 'TABLE_VENDOR' |
TABLE_INVENTORY_TRACKING | 'TABLE_INVENTORY_TRACKING' |
TABLE_SALE_ORDER | 'TABLE_SALE_ORDER' |
TABLE_INVENTORY | 'TABLE_INVENTORY' |
TABLE_FINANCE_TRANSACTION | 'TABLE_FINANCE_TRANSACTION' |
TABLE_FINANCE_CATEGORY | 'TABLE_FINANCE_CATEGORY' |
TABLE_FINANCE_WALLET | 'TABLE_FINANCE_WALLET' |
TABLE_PURCHASE_ORDER | 'TABLE_PURCHASE_ORDER' |
Cách sử dụng
import { TableConfigurations } from '@nx/core';
// Save user's table configuration
await configurationRepository.upsert({
userId: currentUser.id,
code: TableConfigurations.TABLE_PRODUCT,
value: JSON.stringify({ columns: ['name', 'price', 'status'], pageSize: 25 }),
});UserConfigurationCodes
Các khóa để lưu trữ dữ liệu tùy chọn cấp người dùng.
| Tên | Giá trị | Mô tả |
|---|---|---|
USER_PREFERENCES | 'PREFERENCES' | Tùy chọn chung của người dùng (ngôn ngữ, giao diện, v.v.) |
Cách sử dụng
import { UserConfigurationCodes } from '@nx/core';
const prefs = await configurationRepository.findOne({
where: {
userId: currentUser.id,
code: UserConfigurationCodes.USER_PREFERENCES,
},
});3. Hệ thống
SystemConfigurations
Xác định các mục cấu hình cấp hệ thống được lưu trong bảng Configuration của cơ sở dữ liệu. Hiện tại được dùng để lưu thông tin xác thực nhà cung cấp thanh toán.
| Tên | Giá trị | Mô tả |
|---|---|---|
VNPAY_QR_MMS | 'VNPAY_QR_MMS' | Cấu hình nhà cung cấp VNPAY QR MMS |
VNPAY_PHONE_POS | 'VNPAY_PHONE_POS' | Cấu hình nhà cung cấp VNPAY PhonePOS |
Phương thức Hỗ trợ
| Phương thức | Chữ ký | Mô tả |
|---|---|---|
isValid | isValid(input: string): boolean | Trả về true nếu input là thành viên của SCHEME_SET |
Cách sử dụng
import { SystemConfigurations } from '@nx/core';
// Load payment configuration from the database
const config = await configurationRepository.findOne({
where: { code: SystemConfigurations.VNPAY_QR_MMS },
});
// Validate configuration code
if (!SystemConfigurations.isValid(configCode)) {
throw new Error(`Unknown system configuration: ${configCode}`);
}4. Nghiệp vụ
MerchantTypes
Phân loại loại hình kinh doanh quyết định bố cục giao diện POS và tập tính năng.
| Tên | Giá trị | Mô tả |
|---|---|---|
DEFAULT | '000_DEFAULT' | Merchant tiêu chuẩn / đa mục đích |
TICKET | '100_POS_UI_TICKET' | POS bán vé (sự kiện, vận chuyển) |
FNB | '200_POS_UI_FNB' | POS Thực phẩm & Đồ uống |
THEATER | '300_POS_UI_THEATER' | POS Rạp chiếu phim/rạp hát với phân bổ chỗ ngồi |
INFO
MerchantTypes không bao gồm SCHEME_SET hoặc phương thức isValid(). Việc xác thực được thực hiện ở tầng dịch vụ.
Cách sử dụng
import { MerchantTypes } from '@nx/core';
// Create a merchant
await merchantRepository.create({
data: {
name: 'Cinema Central',
type: MerchantTypes.THEATER,
organizerId,
},
});
// Conditional UI rendering (frontend)
switch (merchant.type) {
case MerchantTypes.TICKET:
return <TicketPOSUI />;
case MerchantTypes.FNB:
return <FnBPOSUI />;
case MerchantTypes.THEATER:
return <TheaterPOSUI />;
default:
return <DefaultPOSUI />;
}FixedUserRoles
Định danh vai trò được định nghĩa trước với phân cấp ưu tiên số. Mã ưu tiên cao hơn cấp quyền truy cập rộng hơn.
Định danh Vai trò
| Tên | Giá trị | Mô tả |
|---|---|---|
SUPER_ADMIN | '999-super-admin' | Toàn quyền kiểm soát hệ thống |
ADMIN | '998-admin' | Quyền quản trị |
OPERATOR | '997-operator' | Quản lý vận hành |
ORGANIZER_OWNER | '899-organizer-owner' | Chủ sở hữu thực thể organizer |
EMPLOYEE | '898-employee' | Quyền cấp nhân viên |
Mã Ưu tiên
| Khóa | Mã | Cấp độ |
|---|---|---|
SUPER_ADMIN | 999 | Hệ thống |
ADMIN | 998 | Hệ thống |
OPERATOR | 997 | Hệ thống |
ORGANIZER_OWNER | 899 | Tổ chức |
EMPLOYEE | 898 | Tổ chức |
Tập hợp Đặc biệt
| Tên | Nội dung | Mô tả |
|---|---|---|
ALWAYS_ALLOW_ROLES | SUPER_ADMIN, ADMIN | Các vai trò bỏ qua kiểm tra quyền |
Phân cấp Vai trò
Cách sử dụng
import { FixedUserRoles } from '@nx/core';
// Check admin bypass
if (FixedUserRoles.ALWAYS_ALLOW_ROLES.has(currentRole)) {
return true; // Skip permission check
}
// Compare priority
const userPriority = FixedUserRoles.PRIORITY_CODE.ORGANIZER_OWNER; // 899
const requiredPriority = FixedUserRoles.PRIORITY_CODE.ADMIN; // 998
if (userPriority < requiredPriority) {
throw new ForbiddenError('Insufficient privileges');
}CompanyRegistrationTypes
Phân loại thực thể pháp lý cho đăng ký organizer. Hiện tại chỉ các loại dành riêng cho Việt Nam đang hoạt động; các loại quốc tế được định nghĩa trong mã nguồn nhưng đã bị comment để mở rộng trong tương lai.
Loại Đang Hoạt động (Việt Nam)
| Tên | Giá trị | Tên Tiếng Việt |
|---|---|---|
VN_HOUSEHOLD_BUSINESS | '300_VN_HOUSEHOLD_BUSINESS' | Ho kinh doanh |
VN_PRIVATE_ENTERPRISE | '301_VN_PRIVATE_ENTERPRISE' | Doanh nghiep tu nhan |
VN_LIMITED_LIABILITY_ONE | '302_VN_LIMITED_LIABILITY_ONE' | Cong ty TNHH mot thanh vien |
VN_LIMITED_LIABILITY_TWO_PLUS | '303_VN_LIMITED_LIABILITY_TWO_PLUS' | Cong ty TNHH hai thanh vien tro len |
VN_JOINT_STOCK | '304_VN_JOINT_STOCK' | Cong ty co phan |
Loại Đã Comment (Sử dụng Trong Tương lai)
Tệp nguồn chứa các định nghĩa đã comment cho các loại quốc tế có thể được kích hoạt trong tương lai:
| Danh mục | Mã | Ví dụ |
|---|---|---|
| Cá nhân | 001, 002 | INDIVIDUAL, SOLE_PROPRIETORSHIP |
| Hợp danh | 100, 101 | GENERAL_PARTNERSHIP, LIMITED_PARTNERSHIP |
| Công ty | 200, 201, 202 | PRIVATE_LIMITED_COMPANY, PUBLIC_LIMITED_COMPANY, JOINT_STOCK_COMPANY |
| Phi lợi nhuận & Đặc biệt | 800, 801, 802, 999 | NON_PROFIT, COOPERATIVE, GOVERNMENT_ENTITY, OTHER |
Phương thức Hỗ trợ
| Phương thức | Chữ ký | Mô tả |
|---|---|---|
isValid | isValid(type: string): boolean | Trả về true nếu type là thành viên của TYPE_SET (chỉ các loại đang hoạt động) |
Cách sử dụng
import { CompanyRegistrationTypes } from '@nx/core';
// Validate registration type
if (!CompanyRegistrationTypes.isValid(input.registrationType)) {
throw new ValidationError('Invalid company registration type');
}
// Create organizer
await organizerRepository.create({
data: {
name: 'ABC Ltd.',
registrationType: CompanyRegistrationTypes.VN_LIMITED_LIABILITY_ONE,
},
});DeviceTypes
Phân loại thiết bị POS và phần cứng được sử dụng cho đăng ký và quản lý thiết bị.
| Tên | Giá trị | Danh mục | Mô tả |
|---|---|---|---|
POS_TERMINAL | '100_POS_TERMINAL' | POS cố định | POS quầy truyền thống |
POS_WORKSTATION | '101_POS_WORKSTATION' | POS cố định | POS máy tính để bàn với hệ điều hành đầy đủ |
MOBILE_POS | '200_MOBILE_POS' | POS di động | Ứng dụng POS trên điện thoại/máy tính bảng |
TABLET | '400_TABLET' | Chuyên dụng | Thiết bị máy tính bảng chung |
BARCODE_SCANNER | '401_BARCODE_SCANNER' | Chuyên dụng | Máy quét mã vạch độc lập |
OTHER | '999_OTHER' | Khác | Thiết bị chưa phân loại |
Phương thức Hỗ trợ
| Phương thức | Chữ ký | Mô tả |
|---|---|---|
isValid | isValid(type: string): boolean | Trả về true nếu type là thành viên của TYPE_SET |
Cách sử dụng
import { DeviceTypes } from '@nx/core';
// Validate device type
if (!DeviceTypes.isValid(input.deviceType)) {
throw new ValidationError('Invalid device type');
}
// Create device
await deviceRepository.create({
data: {
name: 'Checkout Terminal 1',
type: DeviceTypes.POS_TERMINAL,
merchantId,
},
});5. Thanh toán
MQPayProviders
Định danh nhà cung cấp thanh toán được sử dụng bởi hệ thống con MQ-Pay. Bao gồm một nhà cung cấp nội bộ (SYSTEM) và sáu nhà cung cấp bên thứ ba.
| Tên | Giá trị | Danh mục | Mô tả |
|---|---|---|---|
SYSTEM | 'SYSTEM' | Nội bộ | Thanh toán thủ công (tiền mặt, chuyển khoản) |
VNPAY_QR_MMS | 'VNPAY_QR_MMS' | VNPAY | Thanh toán mã QR động |
VNPAY_PHONE_POS | 'VNPAY_PHONE_POS' | VNPAY | Thanh toán thẻ NFC qua PhonePOS |
VNPAY_SMART_POS | 'VNPAY_SMART_POS' | VNPAY | QR + thẻ kết hợp qua SmartPOS |
MOMO | 'MOMO' | Bên thứ ba | Ví điện tử MoMo |
ZALOPAY | 'ZALOPAY' | Bên thứ ba | Ví điện tử ZaloPay |
VIETQR | 'VIETQR' | Bên thứ ba | Chuyển khoản ngân hàng VietQR |
Tập hợp
| Tên | Nội dung | Mô tả |
|---|---|---|
SCHEME_SET | Tất cả 7 nhà cung cấp | Tập hợp đầy đủ nhà cung cấp |
THIRD_PARTY_SCHEME_SET | Tất cả trừ SYSTEM | Chỉ nhà cung cấp thanh toán bên ngoài |
Phương thức Hỗ trợ
| Phương thức | Chữ ký | Mô tả |
|---|---|---|
isValid | isValid(scheme: string): boolean | Trả về true nếu scheme là bất kỳ nhà cung cấp nào đã biết |
isThirdPartyProvider | isThirdPartyProvider(opts: { provider: string }): boolean | Trả về true nếu opts.provider là nhà cung cấp bên thứ ba (không phải SYSTEM) |
Cách sử dụng
import { MQPayProviders } from '@nx/core';
// Check if provider requires external API calls
if (MQPayProviders.isThirdPartyProvider({ provider: paymentProvider })) {
// Load credentials and call external payment gateway
} else {
// Handle as manual/system payment
}
// Validate provider
if (!MQPayProviders.isValid(input.provider)) {
throw new ValidationError('Unknown payment provider');
}MQPayCredentialActions
Các hành động yêu cầu tập thông tin xác thực cụ thể khi giao tiếp với nhà cung cấp thanh toán. Mỗi hành động ánh xạ đến một thao tác API riêng biệt.
| Tên | Giá trị | Mô tả |
|---|---|---|
CREATE_PAYMENT | 'CREATE_PAYMENT' | Khởi tạo giao dịch thanh toán mới |
VERIFY_IPN | 'VERIFY_IPN' | Xác minh Thông báo Thanh toán Tức thì (IPN) |
CHECK_TRANSACTION | 'CHECK_TRANSACTION' | Truy vấn trạng thái giao dịch từ nhà cung cấp |
CANCEL_PAYMENT | 'CANCEL_PAYMENT' | Hủy thanh toán đang xử lý |
REFUND | 'REFUND' | Hoàn tiền thanh toán đã thanh toán |
Phương thức Hỗ trợ
| Phương thức | Chữ ký | Mô tả |
|---|---|---|
isValid | isValid(scheme: string): boolean | Trả về true nếu scheme là thành viên của SCHEME_SET |
Cách sử dụng
import { MQPayCredentialActions } from '@nx/core';
// Load credentials for a specific action
const credentials = await paymentConfigService.getCredentials({
provider: MQPayProviders.VNPAY_QR_MMS,
action: MQPayCredentialActions.CREATE_PAYMENT,
});MQPayCredentialTypes
Phân loại dữ liệu thông tin xác thực theo hướng giao tiếp.
| Tên | Giá trị | Mô tả |
|---|---|---|
REQUEST | 'request' | Thông tin xác thực cho yêu cầu gửi đi đến nhà cung cấp |
RESPONSE | 'response' | Thông tin xác thực để xác thực phản hồi từ nhà cung cấp |
IPN | 'ipn' | Thông tin xác thực để xác minh Thông báo Thanh toán Tức thì |
Phương thức Hỗ trợ
| Phương thức | Chữ ký | Mô tả |
|---|---|---|
isValid | isValid(scheme: string): boolean | Trả về true nếu scheme là thành viên của SCHEME_SET |
Cách sử dụng
import { MQPayCredentialTypes } from '@nx/core';
// Retrieve request-specific credentials
const requestCreds = credentials.filter(
c => c.type === MQPayCredentialTypes.REQUEST
);
// Retrieve IPN verification credentials
const ipnCreds = credentials.filter(
c => c.type === MQPayCredentialTypes.IPN
);6. Trạng thái
WebhookConfigStatuses
Trạng thái vòng đời cho các mục cấu hình webhook. Các giá trị được tái xuất từ lớp Statuses của framework IGNIS.
| Tên | Hằng số Nguồn | Giá trị | Mô tả |
|---|---|---|---|
ACTIVATED | Statuses.ACTIVATED | '201_ACTIVATED' | Webhook đang hoạt động và sẽ nhận sự kiện |
DEACTIVATED | Statuses.DEACTIVATED | '401_DEACTIVATED' | Webhook tạm dừng, không gửi sự kiện |
ARCHIVED | Statuses.ARCHIVED | '405_ARCHIVED' | Webhook được lưu trữ để lưu hồ sơ |
Statuses của IGNIS
WebhookConfigStatuses ủy quyền cho Statuses từ @venizia/ignis. Để tham khảo đầy đủ mã trạng thái, xem tài liệu IGNIS Statuses.
Xuất Kiểu
export type TWebhookConfigStatus = TConstValue<typeof WebhookConfigStatuses>;
// Resolves to: '201_ACTIVATED' | '401_DEACTIVATED' | '405_ARCHIVED'Phương thức Hỗ trợ
| Phương thức | Chữ ký | Mô tả |
|---|---|---|
isValid | isValid(status: string): boolean | Trả về true nếu status là thành viên của SCHEME_SET |
Cách sử dụng
import { WebhookConfigStatuses } from '@nx/core';
import type { TWebhookConfigStatus } from '@nx/core';
// Create a webhook config
await webhookConfigRepository.create({
data: {
name: 'Order Notifications',
url: 'https://example.com/webhook',
eventTypes: ['order.created', 'order.completed'],
status: WebhookConfigStatuses.ACTIVATED,
},
});
// Deactivate a webhook
await webhookConfigRepository.updateById({
id: webhookId,
data: { status: WebhookConfigStatuses.DEACTIVATED },
});
// Type-safe status parameter
function setWebhookStatus(id: string, status: TWebhookConfigStatus) {
return webhookConfigRepository.updateById({ id, data: { status } });
}Thực hành Tốt nhất
1. Luôn Sử dụng Hằng số -- Không Dùng Chuỗi Cố định
// Good -- type-safe and refactorable
if (device.type === DeviceTypes.POS_TERMINAL) { /* ... */ }
// Bad -- magic string, prone to typos
if (device.type === '100_POS_TERMINAL') { /* ... */ }2. Xác thực Đầu vào với isValid()
// Good -- explicit validation using the Set
if (!DeviceTypes.isValid(input.type)) {
throw new ValidationError('Invalid device type');
}
// Bad -- manual inline check
if (!['100_POS_TERMINAL', '101_POS_WORKSTATION'].includes(input.type)) { /* ... */ }3. Ưu tiên SCHEME_SET / TYPE_SET cho Kiểm tra Hàng loạt
// Good -- O(1) lookup
if (MQPayProviders.THIRD_PARTY_SCHEME_SET.has(provider)) { /* ... */ }
// Bad -- O(n) array search
if (['VNPAY_QR_MMS', 'VNPAY_PHONE_POS', /* ... */].includes(provider)) { /* ... */ }4. Mở rộng Hằng số trong Gói Downstream
Khi gói downstream cần thêm giá trị, hãy mở rộng lớp cơ sở thay vì sao chép:
export class ExtendedDeviceTypes extends DeviceTypes {
static readonly SELF_CHECKOUT_KIOSK = '500_SELF_CHECKOUT_KIOSK';
static override TYPE_SET = new Set([
...DeviceTypes.TYPE_SET,
this.SELF_CHECKOUT_KIOSK,
]);
}