- add excel export for history transaction
This commit is contained in:
		
							
								
								
									
										8
									
								
								src/transaction/dto/export-transaction.dto.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/transaction/dto/export-transaction.dto.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| import { IsNotEmpty, IsOptional } from 'class-validator'; | ||||
|  | ||||
| export class ExportTransactionDto { | ||||
|  | ||||
|     @IsNotEmpty() | ||||
|     dateStart: string; | ||||
|  | ||||
| } | ||||
							
								
								
									
										36
									
								
								src/transaction/excel.controller.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								src/transaction/excel.controller.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| import { | ||||
|   Controller, | ||||
|   Get, | ||||
|   Res, | ||||
|   Header, | ||||
|   Post, | ||||
|   Body, | ||||
|   Request, Param, ParseUUIDPipe, | ||||
| } from '@nestjs/common'; | ||||
| import { Response } from 'express'; | ||||
| import { TransactionService } from './transaction.service'; | ||||
| import { ExportTransactionDto } from './dto/export-transaction.dto'; | ||||
|  | ||||
| @Controller({ | ||||
|   path: 'excel', | ||||
|   version: '1', | ||||
| }) | ||||
| export class ExcelController { | ||||
|   constructor(private transactionService: TransactionService) {} | ||||
|  | ||||
|   @Post('history-user/export/:id') | ||||
|   @Header('Content-Type', 'text/xlsx') | ||||
|   async exportTransactionHistory( | ||||
|     @Param('id', ParseUUIDPipe) id: string, | ||||
|     @Body() exportTransactionDto: ExportTransactionDto, | ||||
|     @Request() req, | ||||
|     @Res() res: Response, | ||||
|   ) { | ||||
|     const result = await this.transactionService.exportDataExcel( | ||||
|       exportTransactionDto.dateStart, | ||||
|       id, | ||||
|     ); | ||||
|  | ||||
|     res.download(`${result}`); | ||||
|   } | ||||
| } | ||||
| @@ -1,9 +1,22 @@ | ||||
| import { Body, Controller, Get, HttpStatus, Param, ParseUUIDPipe, Post, Put, Query, Request } from '@nestjs/common'; | ||||
| import { | ||||
|   Body, | ||||
|   Controller, | ||||
|   Get, | ||||
|   Header, | ||||
|   HttpStatus, | ||||
|   Param, | ||||
|   ParseUUIDPipe, | ||||
|   Post, | ||||
|   Put, | ||||
|   Query, | ||||
|   Request, Res | ||||
| } from '@nestjs/common'; | ||||
| import { TransactionService } from './transaction.service'; | ||||
| import { DistributeTransactionDto } from './dto/distribute-transaction.dto'; | ||||
| import { OrderTransactionDto } from './dto/order-transaction.dto'; | ||||
| import { AddSaldoSupplier } from './dto/add-saldo-supplier.dto'; | ||||
| import { DepositReturnDto } from './dto/deposit_return.dto'; | ||||
| import { ExportTransactionDto } from './dto/export-transaction.dto'; | ||||
|  | ||||
| @Controller({ | ||||
|   path: 'transaction', | ||||
|   | ||||
| @@ -14,6 +14,7 @@ import { CheckBillHistory } from './entities/check-bill-history.entity'; | ||||
| import { CallbackPartner } from './entities/callback-partner.entity'; | ||||
| import { ProductHistoryPrice } from '../product/entities/product-history-price.entity'; | ||||
| import { ProductHistoryStatus } from '../product/entities/product-history-status.entity'; | ||||
| import { ExcelController } from './excel.controller'; | ||||
|  | ||||
| @Module({ | ||||
|   imports: [ | ||||
| @@ -28,9 +29,11 @@ import { ProductHistoryStatus } from '../product/entities/product-history-status | ||||
|     ]), | ||||
|     ProductModule, | ||||
|     ConfigurableModule, | ||||
|     forwardRef(() => UsersModule), | ||||
|     forwardRef(() => { | ||||
|       return UsersModule; | ||||
|     }), | ||||
|   ], | ||||
|   controllers: [TransactionController, PpobCallbackController], | ||||
|   controllers: [TransactionController, PpobCallbackController, ExcelController], | ||||
|   providers: [TransactionService, CoaService], | ||||
|   exports: [CoaService], | ||||
| }) | ||||
|   | ||||
| @@ -1,4 +1,11 @@ | ||||
| import { HttpException, HttpStatus, Injectable, Logger } from '@nestjs/common'; | ||||
| import { | ||||
|   BadRequestException, | ||||
|   HttpException, | ||||
|   HttpStatus, | ||||
|   Injectable, | ||||
|   Logger, | ||||
|   NotFoundException, | ||||
| } from '@nestjs/common'; | ||||
| import { DistributeTransactionDto } from './dto/distribute-transaction.dto'; | ||||
| import { OrderTransactionDto } from './dto/order-transaction.dto'; | ||||
| import { InjectRepository } from '@nestjs/typeorm'; | ||||
| @@ -38,6 +45,7 @@ import { CheckBillHistory } from './entities/check-bill-history.entity'; | ||||
| import { CallbackPartner } from './entities/callback-partner.entity'; | ||||
| import { doAuthorizeHemat } from '../helper/sihemat-authorization'; | ||||
| import { ProductHistoryStatusService } from '../product/history-status/history-status.service'; | ||||
| import { Workbook } from 'exceljs'; | ||||
|  | ||||
| @Injectable() | ||||
| export class TransactionService { | ||||
| @@ -2123,6 +2131,201 @@ export class TransactionService { | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   async exportDataExcel(startDate, user: any) { | ||||
|     const userData = await this.userService.findExist(user); | ||||
|  | ||||
|     let userBySupperior = []; | ||||
|  | ||||
|     if ( | ||||
|       userData.roles.id != 'e4dfb6a3-2338-464a-8fb8-5cbc089d4209' && | ||||
|       userData.roles.id != '21dceea2-416e-4b55-b74c-12605e1f8d1b' | ||||
|     ) { | ||||
|       let roleNumber; | ||||
|  | ||||
|       if (userData.roles.id == '3196cdf4-ae5f-4677-9bcd-98be35c72321') { | ||||
|         roleNumber = 3; | ||||
|       } else if (userData.roles.id == '3196cdf4-ae5f-4677-9bcd-98be35c72322') { | ||||
|         roleNumber = 2; | ||||
|       } else if (userData.roles.id == 'e4dfb6a3-2348-464a-8fb8-5cbc089d4209') { | ||||
|         roleNumber = 1; | ||||
|       } | ||||
|  | ||||
|       const listUser = await this.userService.findAllSubordinate( | ||||
|         userData.id, | ||||
|         roleNumber, | ||||
|       ); | ||||
|  | ||||
|       if (listUser.length < 1) { | ||||
|         userBySupperior.push(userData.id); | ||||
|       } else { | ||||
|         userBySupperior = listUser; | ||||
|       } | ||||
|     } else { | ||||
|       userBySupperior.push(userData.id); | ||||
|     } | ||||
|  | ||||
|     const baseQuery = this.transactionRepository | ||||
|       .createQueryBuilder('transaction') | ||||
|       .select('transaction.id', 'id') | ||||
|       .addSelect('transaction.created_at', 'created_at') | ||||
|         .where('transaction.user IN (:...id) and transaction.type = 1', { | ||||
|         id: userBySupperior, | ||||
|       }) | ||||
|  | ||||
|  | ||||
|         .leftJoinAndMapOne( | ||||
|             'transaction.userData', | ||||
|         UserDetail, | ||||
|             'userData', | ||||
|             'userData.user = transaction.user', | ||||
|         ).select(['userData.user']) | ||||
|         .leftJoin('transaction.product_price', 'product_price') | ||||
|         .leftJoin('product_price.product', 'product') | ||||
|         .leftJoin('product.supplier', 'supplier') | ||||
|  | ||||
|         .addSelect('product.name', 'product_name') | ||||
|         .addSelect('product.code', 'product_code') | ||||
|         .addSelect('transaction.amount', 'price') | ||||
|         .addSelect('transaction.balance_remaining', 'balance_remaining') | ||||
|         .addSelect('userData.name', 'buyer') | ||||
|         .addSelect('transaction.destination', 'destination') | ||||
|         .addSelect('transaction.supplier_trx_id', 'transaction_code') | ||||
|         .addSelect(`CASE | ||||
|                         WHEN "transaction"."status" = 1 THEN 'Success' | ||||
|                         WHEN "transaction"."status" = 2 THEN 'Failed' | ||||
|                         ELSE 'Pending' | ||||
|                     END`, 'status') | ||||
|         .addSelect('transaction.seri_number', 'serial_number') | ||||
|         .addSelect('transaction.partner_trx_id', 'partner_trx_id') | ||||
|         .addSelect(`to_char(transaction.created_at, 'MM-dd-yyyy HH:mm:ss')`, 'transaction_date') | ||||
|         .addSelect('transaction.failed_reason', 'failed_reason') | ||||
|  | ||||
|         .orderBy('transaction.created_at', 'DESC'); | ||||
|  | ||||
|     if (startDate) { | ||||
|       baseQuery.andWhere( | ||||
|           'transaction.created_at between :startDate and :enDate', | ||||
|           { | ||||
|             startDate: `${startDate} 00:00:00`, | ||||
|             enDate: `${startDate} 23:59:59`, | ||||
|           }, | ||||
|       ); | ||||
|     } | ||||
|  | ||||
|     const data = await baseQuery.getRawMany(); | ||||
|  | ||||
|     // return { | ||||
|     //   data, | ||||
|     // }; | ||||
|  | ||||
|  | ||||
|  | ||||
|     if (!data) { | ||||
|       return { | ||||
|         statusCode: HttpStatus.NOT_FOUND, | ||||
|         message: 'No data to export' | ||||
|       }; | ||||
|     } else { | ||||
|       let rows = []; | ||||
|  | ||||
|       // First create the array of keys/net_total so that we can sort it: | ||||
|       var sort_array = []; | ||||
|       for (var key in data) { | ||||
|         sort_array.push({key: key, product_name: data[key].product_name}); | ||||
|       } | ||||
|  | ||||
|       // Now sort it: | ||||
|       sort_array.sort((x, y) => { | ||||
|         return x.product_name - y.product_name; | ||||
|       }); | ||||
|  | ||||
|       let dataSorted = []; | ||||
|  | ||||
|       // Now process that object with it: | ||||
|       for (var i = 0; i < sort_array.length; i++) { | ||||
|         var item = data[sort_array[i].key]; | ||||
|  | ||||
|         // now do stuff with each item | ||||
|         dataSorted.push({ | ||||
|           product_name: item.product_name, | ||||
|           product_code: item.product_code, | ||||
|           price: item.price, | ||||
|           balance_remaining: item.balance_remaining, | ||||
|           buyer: item.buyer, | ||||
|           destination: item.destination, | ||||
|           transaction_code: item.transaction_code, | ||||
|           status: item.status, | ||||
|           serial_number: item.serial_number, | ||||
|           partner_trx_id: item.partner_trx_id, | ||||
|           transaction_date: item.transaction_date, | ||||
|           failed_reason: item.failed_reason, | ||||
|         }); | ||||
|       } | ||||
|  | ||||
|       dataSorted.forEach((doc) => { | ||||
|         rows.push(Object.values(doc)); | ||||
|       }); | ||||
|  | ||||
|       //creating a workbook | ||||
|       let book = new Workbook(); | ||||
|  | ||||
|       //adding a worksheet to workbook | ||||
|       let sheet = book.addWorksheet('Mutasi Transaksi'); | ||||
|  | ||||
|       //add the header | ||||
|       rows.unshift(Object.keys(dataSorted[0])); | ||||
|  | ||||
|  | ||||
|       //adding multiple rows in the sheet | ||||
|       sheet.addRows(rows); | ||||
|  | ||||
|       //customize column | ||||
|       sheet.columns = [ | ||||
|         {header: 'Nama Produk', key: 'product_name'}, | ||||
|         {header: 'Kode Produk', key: 'product_code'}, | ||||
|         {header: 'Harga', key: 'price'}, | ||||
|         {header: 'Sisa Saldo', key: 'balance_remaining'}, | ||||
|         {header: 'Pembeli', key: 'buyer'}, | ||||
|         {header: 'Tujuan', key: 'destination'}, | ||||
|         {header: 'Kode Transaksi', key: 'transaction_code'}, | ||||
|         {header: 'Status', key: 'status'}, | ||||
|         {header: 'No Seri', key: 'serial_number'}, | ||||
|         {header: 'IDTrx Mitra', key: 'partner_trx_id'}, | ||||
|         {header: 'Tanggal Transaksi', key: 'transaction_date'}, | ||||
|         {header: 'Alasan Gagal', key: 'failed_reason'}, | ||||
|       ]; | ||||
|  | ||||
|       const tmp = require('tmp'); | ||||
|  | ||||
|       let File = await new Promise((resolve, reject) => { | ||||
|         tmp.file( | ||||
|             { | ||||
|               discardDescriptor: true, | ||||
|               prefix: `Mutasi Transaksi ${userData?.partner.name} ${startDate}`, | ||||
|               postfix: '.xlsx', | ||||
|               mode: parseInt('0600', 8), | ||||
|             }, | ||||
|             async (err, file) => { | ||||
|               if (err) throw new BadRequestException(err); | ||||
|  | ||||
|               //writing temporary file | ||||
|               book.xlsx | ||||
|                   .writeFile(file) | ||||
|                   .then((_) => { | ||||
|                     resolve(file); | ||||
|                   }) | ||||
|                   .catch((err) => { | ||||
|                     throw new BadRequestException(err); | ||||
|                   }); | ||||
|             }, | ||||
|         ); | ||||
|       }); | ||||
|  | ||||
|       //returning the path of file | ||||
|       return File; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   async getTotalSell(currentUser) { | ||||
|     const baseQuery = this.transactionRepository | ||||
|         .createQueryBuilder('transactions') | ||||
|   | ||||
		Reference in New Issue
	
	Block a user