This commit is contained in:
Phuoc Nguyen
2025-10-10 16:15:22 +07:00
parent 6203e8c2ec
commit d13d7c4dcb
11 changed files with 22 additions and 22 deletions

View File

@@ -28,10 +28,10 @@ export class PaginationDto {
limit?: number = 20; limit?: number = 20;
get skip(): number { get skip(): number {
return (this.page - 1) * this.limit; return ((this.page || 1) - 1) * (this.limit || 20);
} }
get take(): number { get take(): number {
return this.limit; return this.limit || 20;
} }
} }

View File

@@ -8,7 +8,7 @@ import {
import { Observable, of } from 'rxjs'; import { Observable, of } from 'rxjs';
import { tap } from 'rxjs/operators'; import { tap } from 'rxjs/operators';
import { CACHE_MANAGER } from '@nestjs/cache-manager'; import { CACHE_MANAGER } from '@nestjs/cache-manager';
import { Cache } from 'cache-manager'; import type { Cache } from 'cache-manager';
@Injectable() @Injectable()
export class CustomCacheInterceptor implements NestInterceptor { export class CustomCacheInterceptor implements NestInterceptor {

View File

@@ -1,7 +1,7 @@
import { registerAs } from '@nestjs/config'; import { registerAs } from '@nestjs/config';
export default registerAs('app', () => ({ export default registerAs('app', () => ({
port: parseInt(process.env.PORT, 10) || 3000, port: parseInt(process.env.PORT || '', 10) || 3000,
environment: process.env.NODE_ENV || 'development', environment: process.env.NODE_ENV || 'development',
apiPrefix: process.env.API_PREFIX || 'api', apiPrefix: process.env.API_PREFIX || 'api',

View File

@@ -11,7 +11,7 @@ export default registerAs(
(): TypeOrmModuleOptions => ({ (): TypeOrmModuleOptions => ({
type: 'postgres', type: 'postgres',
host: process.env.DB_HOST || 'localhost', host: process.env.DB_HOST || 'localhost',
port: parseInt(process.env.DB_PORT, 10) || 5432, port: parseInt(process.env.DB_PORT || '', 10) || 5432,
username: process.env.DB_USERNAME || 'postgres', username: process.env.DB_USERNAME || 'postgres',
password: process.env.DB_PASSWORD || 'postgres', password: process.env.DB_PASSWORD || 'postgres',
database: process.env.DB_DATABASE || 'retail_pos', database: process.env.DB_DATABASE || 'retail_pos',
@@ -20,9 +20,6 @@ export default registerAs(
logging: process.env.NODE_ENV === 'development', logging: process.env.NODE_ENV === 'development',
migrations: ['dist/database/migrations/*.js'], migrations: ['dist/database/migrations/*.js'],
migrationsRun: false, // Run migrations manually migrationsRun: false, // Run migrations manually
ssl: ssl: process.env.DB_SSL === 'true' ? { rejectUnauthorized: false } : false,
process.env.NODE_ENV === 'production'
? { rejectUnauthorized: false }
: false,
}), }),
); );

View File

@@ -2,10 +2,10 @@ import { registerAs } from '@nestjs/config';
export default registerAs('redis', () => ({ export default registerAs('redis', () => ({
host: process.env.REDIS_HOST || 'localhost', host: process.env.REDIS_HOST || 'localhost',
port: parseInt(process.env.REDIS_PORT, 10) || 6379, port: parseInt(process.env.REDIS_PORT || '', 10) || 6379,
password: process.env.REDIS_PASSWORD || undefined, password: process.env.REDIS_PASSWORD || undefined,
ttl: parseInt(process.env.CACHE_TTL, 10) || 300, // 5 minutes default ttl: parseInt(process.env.CACHE_TTL || '', 10) || 300, // 5 minutes default
max: parseInt(process.env.CACHE_MAX_ITEMS, 10) || 1000, max: parseInt(process.env.CACHE_MAX_ITEMS || '', 10) || 1000,
// Cache strategy // Cache strategy
cache: { cache: {

View File

@@ -12,7 +12,7 @@ config();
export const dataSourceOptions: DataSourceOptions = { export const dataSourceOptions: DataSourceOptions = {
type: 'postgres', type: 'postgres',
host: process.env.DB_HOST || 'localhost', host: process.env.DB_HOST || 'localhost',
port: parseInt(process.env.DB_PORT, 10) || 5432, port: parseInt(process.env.DB_PORT || '', 10) || 5432,
username: process.env.DB_USERNAME || 'postgres', username: process.env.DB_USERNAME || 'postgres',
password: process.env.DB_PASSWORD || 'postgres', password: process.env.DB_PASSWORD || 'postgres',
database: process.env.DB_DATABASE || 'retail_pos', database: process.env.DB_DATABASE || 'retail_pos',

View File

@@ -14,7 +14,7 @@ export class JwtStrategy extends PassportStrategy(Strategy) {
super({ super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false, ignoreExpiration: false,
secretOrKey: configService.get<string>('JWT_SECRET'), secretOrKey: configService.get<string>('JWT_SECRET') || 'fallback-secret',
}); });
} }

View File

@@ -38,7 +38,7 @@ export class CategoriesRepository {
return this.repository.findOne({ where: { name } }); return this.repository.findOne({ where: { name } });
} }
async update(id: string, updateCategoryDto: UpdateCategoryDto): Promise<Category> { async update(id: string, updateCategoryDto: UpdateCategoryDto): Promise<Category | null> {
await this.repository.update(id, updateCategoryDto); await this.repository.update(id, updateCategoryDto);
return this.findOne(id); return this.findOne(id);
} }

View File

@@ -72,18 +72,21 @@ export class CategoriesService {
const total = category.products.length; const total = category.products.length;
const products = category.products.slice(skip, skip + take); const products = category.products.slice(skip, skip + take);
const limit = paginationDto.limit || 20;
const page = paginationDto.page || 1;
return { return {
...plainToClass(CategoryResponseDto, category, { ...plainToClass(CategoryResponseDto, category, {
excludeExtraneousValues: false, excludeExtraneousValues: false,
}), }),
products, products,
meta: { meta: {
page: paginationDto.page, page,
limit: paginationDto.limit, limit,
total, total,
totalPages: Math.ceil(total / paginationDto.limit), totalPages: Math.ceil(total / limit),
hasPreviousPage: paginationDto.page > 1, hasPreviousPage: page > 1,
hasNextPage: paginationDto.page < Math.ceil(total / paginationDto.limit), hasNextPage: page < Math.ceil(total / limit),
}, },
}; };
} }

View File

@@ -13,7 +13,7 @@ import { Category } from '../../categories/entities/category.entity';
import { TransactionItem } from '../../transactions/entities/transaction-item.entity'; import { TransactionItem } from '../../transactions/entities/transaction-item.entity';
@Entity('products') @Entity('products')
@Index(['name', 'categoryId'], { name: 'idx_products_name_category' }) @Index('idx_products_name_category', ['name', 'categoryId'])
export class Product { export class Product {
@PrimaryGeneratedColumn('uuid') @PrimaryGeneratedColumn('uuid')
id: string; id: string;

View File

@@ -31,7 +31,7 @@ export class UsersRepository {
return this.repository.findOne({ where: { email } }); return this.repository.findOne({ where: { email } });
} }
async update(id: string, updateUserDto: UpdateUserDto): Promise<User> { async update(id: string, updateUserDto: UpdateUserDto): Promise<User | null> {
await this.repository.update(id, updateUserDto); await this.repository.update(id, updateUserDto);
return this.findOne(id); return this.findOne(id);
} }