Merge pull request 'fix/data' (#36) from fix/data into development
continuous-integration/drone/tag Build is passing Details

Reviewed-on: #36
pull/35/head devel_10.6.23
aswin 2024-07-22 11:34:52 +00:00
commit d81eaac4f6
16 changed files with 215 additions and 41 deletions

View File

@ -45,6 +45,7 @@
"dotenv": "^16.4.5",
"elastic-apm-node": "^4.5.4",
"exceljs": "^4.4.0",
"fs-extra": "^11.2.0",
"googleapis": "^140.0.0",
"handlebars": "^4.7.8",
"mathjs": "^13.0.2",

View File

@ -1,39 +1,28 @@
import * as fs from 'fs';
import * as fs from 'fs-extra';
import * as path from 'path';
export function MoveFilePathHelper() {}
export async function MoveFilePathHelper(data) {
const imagePath = data['qr_image'] ?? data['image_url'];
const sourcePath = path.join(__dirname, '../../../../uploads/', imagePath);
const movePath =
'data/' +
imagePath
.split('/')
.filter((item) => !['uploads', 'tmp'].includes(item))
.join('/');
const destinationPath = path.join(
__dirname,
'../../../../uploads/',
movePath,
);
// export class MoveFileToDirIdHelper {
// public srcDir: string;
// public fileName: string;
try {
await fs.move(sourcePath, destinationPath);
// constructor(private file_url: string = null) {}
// execute(): string {
// try {
// this.getSrcDir();
// this.getFileName();
// const copyFile = `${this.fileName}-copy`;
// fs.mkdirSync(`./uploads/${this.srcDir}`, { recursive: true });
// fs.copyFileSync(
// this.file_url,
// `./uploads/${this.srcDir}/${this.fileName}`,
// );
// fs.unlinkSync(`${this.file_url}`);
// this.file_url = `uploads/${this.srcDir}/${this.fileName}`;
// } catch (error) {
// console.error('Error moving file:', error);
// }
// return this.file_url;
// }
// private getSrcDir(): void {
// this.srcDir = this.file_url.split('/').slice(2, -1).join('/');
// }
// private getFileName(): void {
// this.fileName = this.file_url.split('/').slice(-1).join('/');
// }
// }
Object.assign(data, {
image_url: movePath,
});
} catch (error) {
console.log(`Failed! Error move file data`);
}
}

View File

@ -6,6 +6,7 @@ import {
columnUniques,
validateRelations,
} from 'src/core/strings/constants/interface.constants';
import { MoveFilePathHelper } from 'src/core/helpers/path/move-file-path.helper';
export abstract class BaseCreateManager<Entity> extends BaseManager {
protected result: Entity;
@ -43,6 +44,15 @@ export abstract class BaseCreateManager<Entity> extends BaseManager {
}
async process(): Promise<void> {
const keys = Object.keys(this.data);
if (
(keys.includes('qr_image') || keys.includes('image_url')) &&
(this.data['image_url']?.includes('tmp') ||
this.data['qr_image']?.includes('tmp'))
) {
await MoveFilePathHelper(this.data);
}
this.result = await this.dataService.create(
this.queryRunner,
this.entityTarget,

View File

@ -5,7 +5,7 @@ export abstract class BaseCustomManager<Entity> extends BaseManager {
protected result: any;
abstract get entityTarget(): any;
setData(entity: Entity): void {
setData(entity: any): void {
this.data = entity;
}

View File

@ -0,0 +1,17 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
export class UpdateImageColumnItem1721647955446 implements MigrationInterface {
name = 'UpdateImageColumnItem1721647955446';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "items" RENAME COLUMN "image" TO "image_url"`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "items" RENAME COLUMN "image_url" TO "image"`,
);
}
}

View File

@ -25,8 +25,8 @@ export class ItemModel
@Column('varchar', { name: 'name' })
name: string;
@Column('varchar', { name: 'image', nullable: true })
image: string;
@Column('varchar', { name: 'image_url', nullable: true })
image_url: string;
@Column('enum', {
name: 'item_type',

View File

@ -5,7 +5,7 @@ import { LimitType } from '../../constants';
export interface ItemEntity extends BaseStatusEntity {
name: string;
item_type: ItemType;
image: string;
image_url: string;
hpp: number;
sales_margin: number;

View File

@ -15,6 +15,8 @@ import { BatchInactiveItemManager } from './managers/batch-inactive-item.manager
import { BatchActiveItemManager } from './managers/batch-active-item.manager';
import { BatchDeleteItemManager } from './managers/batch-delete-item.manager';
import { TABLE_NAME } from 'src/core/strings/constants/table.constants';
import { UpdateItemRatePriceManager } from './managers/update-item-rate-price.manager';
import { ItemRateReadService } from 'src/modules/item-related/item-rate/data/services/item-rate-read.service';
@Injectable()
export class ItemDataOrchestrator extends BaseDataTransactionOrchestrator<ItemEntity> {
@ -28,8 +30,10 @@ export class ItemDataOrchestrator extends BaseDataTransactionOrchestrator<ItemEn
private batchDeleteManager: BatchDeleteItemManager,
private batchActiveManager: BatchActiveItemManager,
private batchConfirmManager: BatchConfirmItemManager,
private updatePriceManager: UpdateItemRatePriceManager,
private batchInactiveManager: BatchInactiveItemManager,
private serviceData: ItemDataService,
private serviceRateData: ItemRateReadService,
) {
super();
}
@ -60,6 +64,13 @@ export class ItemDataOrchestrator extends BaseDataTransactionOrchestrator<ItemEn
return this.updateManager.getResult();
}
async updatePrice(data): Promise<any[]> {
this.updatePriceManager.setData(data);
this.updatePriceManager.setService(this.serviceRateData, TABLE_NAME.ITEM);
await this.updatePriceManager.execute();
return this.updatePriceManager.getResult();
}
async delete(dataId, tenantId?: string): Promise<string> {
this.deleteManager.setData(dataId);
this.deleteManager.setService(this.serviceData, TABLE_NAME.ITEM);

View File

@ -33,6 +33,7 @@ export class DetailItemManager extends BaseDetailManager<ItemEntity> {
get selects(): string[] {
return [
`${this.tableName}.id`,
`${this.tableName}.image_url`,
`${this.tableName}.created_at`,
`${this.tableName}.status`,
`${this.tableName}.item_type`,

View File

@ -0,0 +1,72 @@
import { Injectable } from '@nestjs/common';
import { BaseCustomManager } from 'src/core/modules/domain/usecase/managers/base-custom.manager';
import { ItemEntity } from '../../entities/item.entity';
import { EventTopics } from 'src/core/strings/constants/interface.constants';
import { ItemModel } from '../../../data/models/item.model';
import { In, LessThanOrEqual, MoreThanOrEqual } from 'typeorm';
@Injectable()
export class UpdateItemRatePriceManager extends BaseCustomManager<ItemEntity> {
protected rates = [];
get entityTarget(): any {
return ItemModel;
}
get eventTopics(): EventTopics[] {
return [];
}
async validateProcess(): Promise<void> {
return;
}
async beforeProcess(): Promise<void> {
let query;
const item_ids = this.data.items.map((item) => {
return item.item.id;
});
if (this.data.season_period_id) {
query = {
item_id: In(item_ids),
season_period: {
id: this.data.season_period_id,
},
};
} else {
query = {
item_id: In(item_ids),
season_period: {
start_date: MoreThanOrEqual(this.data.booking_date),
end_date: LessThanOrEqual(this.data.booking_date),
},
};
}
this.rates = await this.dataService.getManyByOptions({
where: query,
});
return;
}
async process(): Promise<void> {
this.data.items.map((item) => {
const current_price = this.rates.find(
(rate) => rate.item_id == item.item.id,
);
Object.assign(item, {
total_price: current_price?.price ?? item.item.base_price,
});
});
return;
}
async afterProcess(): Promise<void> {
return;
}
async getResult() {
return this.data.items;
}
}

View File

@ -29,7 +29,7 @@ export class ItemDto extends BaseStatusDto implements ItemEntity {
})
@IsString()
@ValidateIf((body) => body.image)
image: string;
image_url: string;
@ApiProperty({
type: 'string',

View File

@ -0,0 +1,43 @@
import { ApiProperty } from '@nestjs/swagger';
export class UpdateItemPriceDto {
@ApiProperty({
type: [Object],
required: true,
example: [
{
item: {
id: 'bee5c493-fb35-4ceb-b7a1-7bc3edb3c63b',
name: 'TEnant 2 wahana air',
item_type: 'wahana',
base_price: '100000',
hpp: '0',
tenant: {
id: 'e19a4637-d4db-48cc-89ce-501913d07cdd',
name: 'e19a4637-d4db-48cc-89ce-501913d07cdd',
share_margin: null,
},
item_category: {
id: '88633772-ec34-4645-bc04-6cfdce6af0cf',
name: 'Wahana Air',
},
},
qty: 1,
total_price: '100000',
},
],
})
items: Object[];
@ApiProperty({
type: String,
example: 'uuid',
})
season_period_id: string;
@ApiProperty({
type: Date,
example: '2024-08-17',
})
booking_date: Date;
}

View File

@ -15,6 +15,7 @@ import { ItemEntity } from '../domain/entities/item.entity';
import { BatchResult } from 'src/core/response/domain/ok-response.interface';
import { BatchIdsDto } from 'src/core/modules/infrastructure/dto/base-batch.dto';
import { Public } from 'src/core/guards';
import { UpdateItemPriceDto } from './dto/update-item-price.dto';
@ApiTags(`${MODULE_NAME.ITEM.split('-').join(' ')} - data`)
@Controller(`v1/${MODULE_NAME.ITEM}`)
@ -28,6 +29,11 @@ export class ItemDataController {
return await this.orchestrator.create(data);
}
@Post('update-price')
async updatePrice(@Body() body: UpdateItemPriceDto): Promise<any> {
return await this.orchestrator.updatePrice(body);
}
@Put('/batch-delete')
async batchDeleted(@Body() body: BatchIdsDto): Promise<BatchResult> {
return await this.orchestrator.batchDelete(body.ids);

View File

@ -25,6 +25,7 @@ import { ItemModel } from './data/models/item.model';
import { ItemRateModel } from '../item-rate/data/models/item-rate.model';
import { ItemRateReadService } from '../item-rate/data/services/item-rate-read.service';
import { IndexItemRatesManager } from './domain/usecases/managers/index-item-rates.manager';
import { UpdateItemRatePriceManager } from './domain/usecases/managers/update-item-rate-price.manager';
@Global()
@Module({
@ -51,6 +52,7 @@ import { IndexItemRatesManager } from './domain/usecases/managers/index-item-rat
BatchActiveItemManager,
BatchConfirmItemManager,
BatchInactiveItemManager,
UpdateItemRatePriceManager,
ItemDataService,
ItemReadService,

View File

@ -30,6 +30,19 @@ export class CreateRefundManager extends BaseCreateManager<RefundEntity> {
refund_items: refund_items,
});
const exist = await this.dataService.getOneByOptions({
where: {
transaction_id: this.data.transaction.id,
},
});
if (exist) {
throw new UnprocessableEntityException({
statusCode: HttpStatus.UNPROCESSABLE_ENTITY,
message: `Failed! refund transaction with invoice ${this.data.transaction.invoice_code} already exist`,
error: 'Unprocessable Entity',
});
}
const transaction = await this.dataServiceFirstOpt.getOneByOptions({
where: {
id: this.data.transaction.id,

View File

@ -3423,6 +3423,15 @@ fs-extra@^10.0.0:
jsonfile "^6.0.1"
universalify "^2.0.0"
fs-extra@^11.2.0:
version "11.2.0"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.2.0.tgz#e70e17dfad64232287d01929399e0ea7c86b0e5b"
integrity sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==
dependencies:
graceful-fs "^4.2.0"
jsonfile "^6.0.1"
universalify "^2.0.0"
fs-minipass@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb"