Merge branch 'development' into 'devops-staging'
Development See merge request empatnusabangsa/ppob/ppob-backend!161
This commit is contained in:
		| @@ -9,4 +9,7 @@ export class OrderTransactionDto { | |||||||
|  |  | ||||||
|   @IsOptional() |   @IsOptional() | ||||||
|   trx_id: string; |   trx_id: string; | ||||||
|  |  | ||||||
|  |   @IsOptional() | ||||||
|  |   bill_trx_id: string; | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										45
									
								
								src/transaction/entities/check-bill-history.entity.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/transaction/entities/check-bill-history.entity.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | |||||||
|  | import { Column, Entity, ManyToOne, OneToMany } from 'typeorm'; | ||||||
|  | import { BaseModel } from '../../config/basemodel.entity'; | ||||||
|  | import { statusTransaction, typeTransaction } from '../../helper/enum-list'; | ||||||
|  | import { ProductHistoryPrice } from '../../product/entities/product-history-price.entity'; | ||||||
|  | import { UserDetail } from '../../users/entities/user_detail.entity'; | ||||||
|  | import { TransactionJournal } from './transaction-journal.entity'; | ||||||
|  |  | ||||||
|  | @Entity() | ||||||
|  | export class CheckBillHistory extends BaseModel { | ||||||
|  |   @Column() | ||||||
|  |   trx_id: string; | ||||||
|  |  | ||||||
|  |   @Column() | ||||||
|  |   partner_trx_id: string; | ||||||
|  |  | ||||||
|  |   @Column({ nullable: true }) | ||||||
|  |   amount: number; | ||||||
|  |  | ||||||
|  |   @Column({ nullable: true }) | ||||||
|  |   admin_price: number; | ||||||
|  |  | ||||||
|  |   @Column({ | ||||||
|  |     type: 'uuid', | ||||||
|  |     nullable: true, | ||||||
|  |   }) | ||||||
|  |   user: string; | ||||||
|  |  | ||||||
|  |   @Column({ | ||||||
|  |     nullable: true, | ||||||
|  |   }) | ||||||
|  |   destination: string; | ||||||
|  |  | ||||||
|  |   @Column({ | ||||||
|  |     nullable: true, | ||||||
|  |   }) | ||||||
|  |   request_json: string; | ||||||
|  |  | ||||||
|  |   @Column({ | ||||||
|  |     nullable: true, | ||||||
|  |   }) | ||||||
|  |   callback_json: string; | ||||||
|  |  | ||||||
|  |   @Column() | ||||||
|  |   product_code: string; | ||||||
|  | } | ||||||
| @@ -16,6 +16,11 @@ export class Transactions extends BaseModel { | |||||||
|   @Column() |   @Column() | ||||||
|   type: typeTransaction; |   type: typeTransaction; | ||||||
|  |  | ||||||
|  |   @Column({ | ||||||
|  |     nullable: true, | ||||||
|  |   }) | ||||||
|  |   check_bill: string; | ||||||
|  |  | ||||||
|   @Column({ |   @Column({ | ||||||
|     type: 'uuid', |     type: 'uuid', | ||||||
|     nullable: true, |     nullable: true, | ||||||
|   | |||||||
| @@ -51,10 +51,27 @@ export class PpobCallbackController { | |||||||
|   async getMetro(@Req() request: FastifyRequest) { |   async getMetro(@Req() request: FastifyRequest) { | ||||||
|     const response = request.query; |     const response = request.query; | ||||||
|  |  | ||||||
|     console.log(response, "INI DIA") |     if (response['message'].includes('CEK TAGIHAN')) { | ||||||
|  |       if (response['status'] != 20) { | ||||||
|  |         //TODO: UPDATE GAGAL | ||||||
|  |         await this.transactionService.updateBill( | ||||||
|  |           response['refid'], | ||||||
|  |           null, | ||||||
|  |           null, | ||||||
|  |           false, | ||||||
|  |         ); | ||||||
|  |       } | ||||||
|  |  | ||||||
|     if (response['message'].include('CEK TAGIHAN')) { |       const splitMessage = response['message'].split('","'); | ||||||
|       console.log("messagenya tuh",response['message']) |  | ||||||
|  |       //TODO: UPDATE BERHASIL | ||||||
|  |       await this.transactionService.updateBill( | ||||||
|  |         response['refid'], | ||||||
|  |         splitMessage[3].replace(/^\D+/g, ''), | ||||||
|  |         splitMessage[4].replace(/^\D+/g, ''), | ||||||
|  |         true | ||||||
|  |       ); | ||||||
|  |       // | ||||||
|     } else { |     } else { | ||||||
|       if (response['status'] != 20) { |       if (response['status'] != 20) { | ||||||
|         //TODO: UPDATE GAGAL |         //TODO: UPDATE GAGAL | ||||||
|   | |||||||
| @@ -10,10 +10,16 @@ import { CoaService } from './coa.service'; | |||||||
| import { ProductModule } from '../product/product.module'; | import { ProductModule } from '../product/product.module'; | ||||||
| import { UsersModule } from 'src/users/users.module'; | import { UsersModule } from 'src/users/users.module'; | ||||||
| import { ConfigurableModule } from '../configurable/configurable.module'; | import { ConfigurableModule } from '../configurable/configurable.module'; | ||||||
|  | import { CheckBillHistory } from './entities/check-bill-history.entity'; | ||||||
|  |  | ||||||
| @Module({ | @Module({ | ||||||
|   imports: [ |   imports: [ | ||||||
|     TypeOrmModule.forFeature([COA, TransactionJournal, Transactions]), |     TypeOrmModule.forFeature([ | ||||||
|  |       COA, | ||||||
|  |       TransactionJournal, | ||||||
|  |       Transactions, | ||||||
|  |       CheckBillHistory, | ||||||
|  |     ]), | ||||||
|     ProductModule, |     ProductModule, | ||||||
|     ConfigurableModule, |     ConfigurableModule, | ||||||
|     forwardRef(() => UsersModule), |     forwardRef(() => UsersModule), | ||||||
|   | |||||||
| @@ -27,6 +27,8 @@ import { DepositReturnDto } from './dto/deposit_return.dto'; | |||||||
| import { UserDetail } from '../users/entities/user_detail.entity'; | import { UserDetail } from '../users/entities/user_detail.entity'; | ||||||
| import { doTransaction } from '../helper/irs-api'; | import { doTransaction } from '../helper/irs-api'; | ||||||
| import { ProductHistoryPrice } from '../product/entities/product-history-price.entity'; | import { ProductHistoryPrice } from '../product/entities/product-history-price.entity'; | ||||||
|  | import axios from 'axios'; | ||||||
|  | import { CheckBillHistory } from './entities/check-bill-history.entity'; | ||||||
|  |  | ||||||
| @Injectable() | @Injectable() | ||||||
| export class TransactionService { | export class TransactionService { | ||||||
| @@ -39,6 +41,8 @@ export class TransactionService { | |||||||
|     private transactionJournalRepository: Repository<TransactionJournal>, |     private transactionJournalRepository: Repository<TransactionJournal>, | ||||||
|     @InjectRepository(COA) |     @InjectRepository(COA) | ||||||
|     private coaRepository: Repository<COA>, |     private coaRepository: Repository<COA>, | ||||||
|  |     @InjectRepository(CheckBillHistory) | ||||||
|  |     private checkBillHistoryRepository: Repository<CheckBillHistory>, | ||||||
|     private coaService: CoaService, |     private coaService: CoaService, | ||||||
|     private productService: ProductService, |     private productService: ProductService, | ||||||
|     private productHistoryPriceService: ProductHistoryPriceService, |     private productHistoryPriceService: ProductHistoryPriceService, | ||||||
| @@ -477,6 +481,30 @@ export class TransactionService { | |||||||
|       `${coaType[coaType.SALES]}-SYSTEM`, |       `${coaType[coaType.SALES]}-SYSTEM`, | ||||||
|     ); |     ); | ||||||
|  |  | ||||||
|  |     if (orderTransactionDto.bill_trx_id !== null) { | ||||||
|  |       try { | ||||||
|  |         const billId = await this.checkBillHistoryRepository.findOneOrFail({ | ||||||
|  |           where: { | ||||||
|  |             id: orderTransactionDto.bill_trx_id | ||||||
|  |           }, | ||||||
|  |         }); | ||||||
|  |         product_price.price = billId.amount; | ||||||
|  |       } catch (e) { | ||||||
|  |         if (e instanceof EntityNotFoundError) { | ||||||
|  |           throw new HttpException( | ||||||
|  |             { | ||||||
|  |               statusCode: HttpStatus.NOT_FOUND, | ||||||
|  |               error: 'Bill not found', | ||||||
|  |             }, | ||||||
|  |             HttpStatus.NOT_FOUND, | ||||||
|  |           ); | ||||||
|  |         } else { | ||||||
|  |           throw e; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|     if (coaAccount.amount < product_price.mark_up_price + product_price.price) { |     if (coaAccount.amount < product_price.mark_up_price + product_price.price) { | ||||||
|       throw new HttpException( |       throw new HttpException( | ||||||
|         { |         { | ||||||
| @@ -505,7 +533,7 @@ export class TransactionService { | |||||||
|     if (supplier.code != 'IRS') { |     if (supplier.code != 'IRS') { | ||||||
|       const parsingResponse = hitSupplier.split(' '); |       const parsingResponse = hitSupplier.split(' '); | ||||||
|       hitSupplier = { |       hitSupplier = { | ||||||
|         success: hitSupplier.include('diproses'), |         success: hitSupplier.includes('diproses'), | ||||||
|         harga: parseInt( |         harga: parseInt( | ||||||
|           parsingResponse[parsingResponse.length - 2].replaceAll('.', ''), |           parsingResponse[parsingResponse.length - 2].replaceAll('.', ''), | ||||||
|         ), |         ), | ||||||
| @@ -564,6 +592,7 @@ export class TransactionService { | |||||||
|         transactionData.destination = orderTransactionDto.destination; |         transactionData.destination = orderTransactionDto.destination; | ||||||
|         transactionData.partner_trx_id = orderTransactionDto.trx_id; |         transactionData.partner_trx_id = orderTransactionDto.trx_id; | ||||||
|         transactionData.supplier_trx_id = trxId; |         transactionData.supplier_trx_id = trxId; | ||||||
|  |         transactionData.check_bill = orderTransactionDto.bill_trx_id; | ||||||
|  |  | ||||||
|         if (!hitSupplier.success) { |         if (!hitSupplier.success) { | ||||||
|           transactionData.status = statusTransaction.FAILED; |           transactionData.status = statusTransaction.FAILED; | ||||||
| @@ -694,7 +723,7 @@ export class TransactionService { | |||||||
|     if (supplier.code != 'IRS') { |     if (supplier.code != 'IRS') { | ||||||
|       const parsingResponse = hitSupplier.split(' '); |       const parsingResponse = hitSupplier.split(' '); | ||||||
|       hitSupplier = { |       hitSupplier = { | ||||||
|         success: hitSupplier.include('diproses'), |         success: hitSupplier.includes('diproses'), | ||||||
|         harga: parseInt( |         harga: parseInt( | ||||||
|           parsingResponse[parsingResponse.length - 2].replaceAll('.', ''), |           parsingResponse[parsingResponse.length - 2].replaceAll('.', ''), | ||||||
|         ), |         ), | ||||||
| @@ -814,21 +843,53 @@ export class TransactionService { | |||||||
|       }) |       }) | ||||||
|       .join(''); |       .join(''); | ||||||
|  |  | ||||||
|  |     let status; | ||||||
|  |  | ||||||
|  |     try { | ||||||
|       let hitSupplier = await doTransaction( |       let hitSupplier = await doTransaction( | ||||||
|         'CEK' + orderTransactionDto.productCode.slice(3), |         'CEK' + orderTransactionDto.productCode.slice(3), | ||||||
|         orderTransactionDto.destination, |         orderTransactionDto.destination, | ||||||
|         trxId, |         trxId, | ||||||
|         supplier, |         supplier, | ||||||
|       ); |       ); | ||||||
|  |       const parsingResponse = hitSupplier.split(' '); | ||||||
|  |       console.log(hitSupplier,"ini dia") | ||||||
|  |       hitSupplier = { | ||||||
|  |         success: hitSupplier.includes('diproses'), | ||||||
|  |         msg: hitSupplier, | ||||||
|  |       }; | ||||||
|  |  | ||||||
|     // let hitSupplier = await doTransaction( |       if (!hitSupplier.success) { | ||||||
|     //   'CEKXL1', |         status = statusTransaction[statusTransaction.FAILED]; | ||||||
|     //   orderTransactionDto.destination, |         throw new HttpException( | ||||||
|     //   trxId, |           { | ||||||
|     //   supplier, |             statusCode: HttpStatus.INTERNAL_SERVER_ERROR, | ||||||
|     // ); |             error: hitSupplier.msg, | ||||||
|  |           }, | ||||||
|  |           HttpStatus.INTERNAL_SERVER_ERROR, | ||||||
|  |         ); | ||||||
|  |       } else { | ||||||
|  |         status = statusTransaction[statusTransaction.SUCCESS]; | ||||||
|  |  | ||||||
|     return hitSupplier; |         await this.checkBillHistoryRepository.insert({ | ||||||
|  |           trx_id: trxId, | ||||||
|  |           user: userData.id, | ||||||
|  |           callback_json: JSON.stringify(hitSupplier), | ||||||
|  |           destination: orderTransactionDto.destination, | ||||||
|  |           product_code: orderTransactionDto.productCode, | ||||||
|  |           partner_trx_id: orderTransactionDto.trx_id, | ||||||
|  |         }); | ||||||
|  |       } | ||||||
|  |     } catch (e) { | ||||||
|  |       throw e; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return { | ||||||
|  |       trx_id: trxId, | ||||||
|  |       client_trx_id: orderTransactionDto.trx_id, | ||||||
|  |       product: orderTransactionDto.productCode, | ||||||
|  |       status: status, | ||||||
|  |     }; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   async createDepositReturn(currentUser, depositReturnDto: DepositReturnDto) { |   async createDepositReturn(currentUser, depositReturnDto: DepositReturnDto) { | ||||||
| @@ -1060,6 +1121,20 @@ export class TransactionService { | |||||||
|     } catch (e) { |     } catch (e) { | ||||||
|       throw e; |       throw e; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     if (userData.partner) { | ||||||
|  |       const message = `Transaksi ${product.code} dengan tujuan ${dataTransaction.destination} telah gagal.`; | ||||||
|  |       this.callbackToPartner( | ||||||
|  |         userData.id, | ||||||
|  |         message, | ||||||
|  |         dataTransaction.partner_trx_id, | ||||||
|  |         dataTransaction.amount, | ||||||
|  |         product.code, | ||||||
|  |         dataTransaction.destination, | ||||||
|  |         '-', | ||||||
|  |         'gagal', | ||||||
|  |       ); | ||||||
|  |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   async callbackOrderSuccess(supplier_trx_id: string, callback: any) { |   async callbackOrderSuccess(supplier_trx_id: string, callback: any) { | ||||||
| @@ -1131,6 +1206,36 @@ export class TransactionService { | |||||||
|     } catch (e) { |     } catch (e) { | ||||||
|       throw e; |       throw e; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     if (userData.partner) { | ||||||
|  |       const message = `Transaksi ${product.code} dengan tujuan ${dataTransaction.destination} telah berhasil.`; | ||||||
|  |       this.callbackToPartner( | ||||||
|  |         userData.id, | ||||||
|  |         message, | ||||||
|  |         dataTransaction.partner_trx_id, | ||||||
|  |         dataTransaction.amount, | ||||||
|  |         product.code, | ||||||
|  |         dataTransaction.destination, | ||||||
|  |         dataTransaction.seri_number, | ||||||
|  |         'berhasil', | ||||||
|  |       ); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   async callbackToPartner( | ||||||
|  |     partnerId: string, | ||||||
|  |     message: string, | ||||||
|  |     trxId: string, | ||||||
|  |     harga: number, | ||||||
|  |     productCode: string, | ||||||
|  |     destination: string, | ||||||
|  |     seriNumber: string, | ||||||
|  |     status: string, | ||||||
|  |   ) { | ||||||
|  |     const partnerData = await this.userService.findPartner(partnerId); | ||||||
|  |     const res = await axios.get( | ||||||
|  |       `${partnerData.callback_url}?status=${status}&memberID=${partnerData.code}&trxid=${trxId}&harga=${harga}&product=${productCode}&dest=${destination}&seriNumber=${seriNumber}&message=${message}`, | ||||||
|  |     ); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   async withdrawBenefit(user) { |   async withdrawBenefit(user) { | ||||||
| @@ -1675,4 +1780,63 @@ export class TransactionService { | |||||||
|  |  | ||||||
|     return transaction; |     return transaction; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   async updateBill( | ||||||
|  |     trxId: string, | ||||||
|  |     amount: number, | ||||||
|  |     admin: number, | ||||||
|  |     status: boolean, | ||||||
|  |   ) { | ||||||
|  |     const billData = await this.findOneBillById(trxId); | ||||||
|  |  | ||||||
|  |     await this.checkBillHistoryRepository.update( | ||||||
|  |       { | ||||||
|  |         trx_id: trxId, | ||||||
|  |       }, | ||||||
|  |       { | ||||||
|  |         amount: amount, | ||||||
|  |         admin_price: admin, | ||||||
|  |       }, | ||||||
|  |     ); | ||||||
|  |     const userData = await this.userService.findExist(billData.user); | ||||||
|  |  | ||||||
|  |     if (userData.partner) { | ||||||
|  |       const message = status | ||||||
|  |         ? `Bill dari ${billData.destination} adalah ${amount}.` | ||||||
|  |         : ''; | ||||||
|  |       const statusResponse = status ? 'berhasil' : 'gagal'; | ||||||
|  |       this.callbackToPartner( | ||||||
|  |         userData.id, | ||||||
|  |         message, | ||||||
|  |         billData.partner_trx_id, | ||||||
|  |         amount, | ||||||
|  |         billData.product_code, | ||||||
|  |         billData.destination, | ||||||
|  |         '-', | ||||||
|  |         statusResponse, | ||||||
|  |       ); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   async findOneBillById(trxId: string) { | ||||||
|  |     try { | ||||||
|  |       return await this.checkBillHistoryRepository.findOneOrFail({ | ||||||
|  |         where:{ | ||||||
|  |           trx_id: trxId, | ||||||
|  |         }, | ||||||
|  |       }); | ||||||
|  |     } catch (e) { | ||||||
|  |       if (e instanceof EntityNotFoundError) { | ||||||
|  |         throw new HttpException( | ||||||
|  |           { | ||||||
|  |             statusCode: HttpStatus.NOT_FOUND, | ||||||
|  |             error: 'Bill not found', | ||||||
|  |           }, | ||||||
|  |           HttpStatus.NOT_FOUND, | ||||||
|  |         ); | ||||||
|  |       } else { | ||||||
|  |         throw e; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -27,4 +27,9 @@ export class Partner extends BaseModel { | |||||||
|  |  | ||||||
|   @Column({ default: true }) |   @Column({ default: true }) | ||||||
|   status: boolean; |   status: boolean; | ||||||
|  |  | ||||||
|  |   @Column({ | ||||||
|  |     default: '', | ||||||
|  |   }) | ||||||
|  |   callback_url: string; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -20,12 +20,15 @@ import * as uuid from 'uuid'; | |||||||
| import { UserDetail } from './entities/user_detail.entity'; | import { UserDetail } from './entities/user_detail.entity'; | ||||||
| import { COA } from '../transaction/entities/coa.entity'; | import { COA } from '../transaction/entities/coa.entity'; | ||||||
| import { mapSeries } from 'bluebird'; | import { mapSeries } from 'bluebird'; | ||||||
|  | import { Partner } from './entities/partner.entity'; | ||||||
|  |  | ||||||
| @Injectable() | @Injectable() | ||||||
| export class UsersService { | export class UsersService { | ||||||
|   constructor( |   constructor( | ||||||
|     @InjectRepository(User) |     @InjectRepository(User) | ||||||
|     private usersRepository: Repository<User>, |     private usersRepository: Repository<User>, | ||||||
|  |     @InjectRepository(Partner) | ||||||
|  |     private partnerRepository: Repository<Partner>, | ||||||
|     @InjectRepository(UserDetail) |     @InjectRepository(UserDetail) | ||||||
|     private userDetailRepository: Repository<UserDetail>, |     private userDetailRepository: Repository<UserDetail>, | ||||||
|     @Inject( |     @Inject( | ||||||
| @@ -676,4 +679,26 @@ export class UsersService { | |||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   async findPartner(partnerId: string) { | ||||||
|  |     try { | ||||||
|  |       return this.partnerRepository.findOneOrFail({ | ||||||
|  |         where: { | ||||||
|  |           id: partnerId, | ||||||
|  |         }, | ||||||
|  |       }); | ||||||
|  |     } catch (e) { | ||||||
|  |       if (e instanceof EntityNotFoundError) { | ||||||
|  |         throw new HttpException( | ||||||
|  |           { | ||||||
|  |             statusCode: HttpStatus.NOT_FOUND, | ||||||
|  |             error: 'Partner not found', | ||||||
|  |           }, | ||||||
|  |           HttpStatus.NOT_FOUND, | ||||||
|  |         ); | ||||||
|  |       } else { | ||||||
|  |         throw e; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user