Merge branch 'master' into 'devops-production'
Master See merge request empatnusabangsa/ppob/ppob-backend!182
This commit is contained in:
commit
234ae2918f
7633
package-lock.json
generated
Normal file
7633
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
|
@ -6,13 +6,24 @@ const irs_pin = '04JFGC';
|
|||
const irs_user = 'D10BD0';
|
||||
const irs_pass = '6251F3';
|
||||
|
||||
export const doTransaction = async (productCode, destination, idtrx) => {
|
||||
export const doTransaction = async (
|
||||
productCode,
|
||||
destination,
|
||||
idtrx,
|
||||
supplier,
|
||||
) => {
|
||||
try {
|
||||
if(supplier.code == 'IRS'){
|
||||
const res = await axios.get(
|
||||
`${irs_url}?id=${irs_id}&pin=${irs_pin}&user=${irs_user}&pass=${irs_pass}&kodeproduk=${productCode}&tujuan=${destination}&counter=1&idtrx=${idtrx}`,
|
||||
);
|
||||
|
||||
return res.data;
|
||||
} else {
|
||||
const res = await axios.get(
|
||||
`${supplier.url}?memberID=${supplier.irs_id}&pin=${supplier.irs_pin}&password=${supplier.irs_pass}&product=${productCode}&dest=${destination}&counter=1&refID=${idtrx}`,
|
||||
);
|
||||
return res.data;
|
||||
}
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
|
|
|
@ -11,6 +11,9 @@ export class UpdatePriceProductDto {
|
|||
@IsNotEmpty()
|
||||
type: productType;
|
||||
|
||||
@IsNotEmpty()
|
||||
productType: string;
|
||||
|
||||
startDate: Date;
|
||||
|
||||
endDate: Date;
|
||||
|
|
|
@ -32,4 +32,14 @@ export class ProductHistoryPrice extends BaseModel {
|
|||
|
||||
@Column('text')
|
||||
type: productType;
|
||||
|
||||
@Column({
|
||||
default: 0,
|
||||
})
|
||||
admin_price: number;
|
||||
|
||||
@Column({
|
||||
default: 0,
|
||||
})
|
||||
partner_fee: number;
|
||||
}
|
||||
|
|
|
@ -28,6 +28,11 @@ export class Product extends BaseModel {
|
|||
})
|
||||
basePrice: number;
|
||||
|
||||
@Column({
|
||||
default: 'prepaid',
|
||||
})
|
||||
type: string;
|
||||
|
||||
@ManyToOne(
|
||||
() => {
|
||||
return ProductSubCategories;
|
||||
|
|
|
@ -55,6 +55,7 @@ export class ProductService {
|
|||
const supplierData = await this.supplierService.findByCode(supplierCode);
|
||||
|
||||
const data = await parsingFile(uploadFile);
|
||||
|
||||
data.shift();
|
||||
await mapSeries(data, async (it) => {
|
||||
let dataHistoryPrice;
|
||||
|
@ -71,6 +72,7 @@ export class ProductService {
|
|||
code: it[0],
|
||||
supplier: supplierData,
|
||||
});
|
||||
|
||||
if (productData) {
|
||||
//TODO : Handle Update Product
|
||||
productData.name = it[1];
|
||||
|
@ -108,18 +110,23 @@ export class ProductService {
|
|||
type: productType.NORMAL,
|
||||
startDate: new Date(),
|
||||
partner: it[6] != '-' ? partnerData : null,
|
||||
admin_price: it[8],
|
||||
partner_fee: it[9],
|
||||
});
|
||||
} else {
|
||||
let partnerData;
|
||||
|
||||
if (it[6] != '-' && it[6] != '') {
|
||||
partnerData = await this.partnerService.findOne(it[6]);
|
||||
}
|
||||
|
||||
const savedProduct = await this.productRepository.insert({
|
||||
name: it[1],
|
||||
code: it[0],
|
||||
status: it[5] == 'active' ? 'ACTIVE' : 'NOT ACTIVE',
|
||||
sub_categories: subCategories,
|
||||
supplier: supplierData,
|
||||
type: it[7] == 'postpaid' ? 'postpaid' : 'prepaid',
|
||||
});
|
||||
|
||||
return await this.productHistoryPrice.insert({
|
||||
|
@ -130,6 +137,8 @@ export class ProductService {
|
|||
startDate: new Date(),
|
||||
endDate: null,
|
||||
partner: partnerData,
|
||||
admin_price: it[8],
|
||||
partner_fee: it[9],
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -167,7 +176,7 @@ export class ProductService {
|
|||
'product.currentPrice',
|
||||
'product.priceHistory',
|
||||
'current_price',
|
||||
'current_price.partner_id is null and current_price.end_date is NULL',
|
||||
'current_price.end_date is NULL',
|
||||
)
|
||||
.select(['product.id'])
|
||||
.addSelect([
|
||||
|
@ -178,7 +187,9 @@ export class ProductService {
|
|||
'category.name',
|
||||
'product.status',
|
||||
])
|
||||
.addSelect('current_price.price')
|
||||
.addSelect('current_price.price', 'price')
|
||||
.addSelect('current_price.partner_fee', 'partner_fee')
|
||||
.addSelect('current_price.admin_price', 'admin_price')
|
||||
.addSelect(
|
||||
'(current_price.price + current_price.mark_up_price) as mark_up_price',
|
||||
)
|
||||
|
@ -291,18 +302,34 @@ export class ProductService {
|
|||
subCategories: string,
|
||||
username: string,
|
||||
) {
|
||||
let filterSubCategories;
|
||||
const user = await this.usersService.findOneByUsername(username);
|
||||
const supplier = await this.supplierService.findByActive();
|
||||
|
||||
const baseQuery = this.productRepository
|
||||
if (subCategories) {
|
||||
filterSubCategories = subCategories.split(',').map((data) => {
|
||||
return data.trim();
|
||||
});
|
||||
}
|
||||
|
||||
if (user.partner === null) {
|
||||
throw new HttpException(
|
||||
{
|
||||
statusCode: HttpStatus.NOT_FOUND,
|
||||
error: 'Partner id not found',
|
||||
},
|
||||
HttpStatus.NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
const baseQuery = await this.productRepository
|
||||
.createQueryBuilder('product')
|
||||
.leftJoin('product.sub_categories', 'sub_categories')
|
||||
.where(
|
||||
`product.supplier_id = :supplier_id and product.status = 'ACTIVE'`,
|
||||
{
|
||||
supplier_id: supplier.id,
|
||||
},
|
||||
.leftJoinAndSelect(
|
||||
'product.supplier',
|
||||
'supplier',
|
||||
'supplier.status = true',
|
||||
)
|
||||
.where(`product.status = 'ACTIVE'`)
|
||||
.innerJoinAndMapOne(
|
||||
'product.currentPrice',
|
||||
'product.priceHistory',
|
||||
|
@ -313,26 +340,64 @@ export class ProductService {
|
|||
},
|
||||
)
|
||||
.select(['product.id'])
|
||||
.addSelect(['product.name', 'product.code', 'sub_categories.name'])
|
||||
.addSelect(
|
||||
'(current_price.price + current_price.mark_up_price) as price',
|
||||
);
|
||||
.addSelect([
|
||||
'product.name',
|
||||
'product.code',
|
||||
'product.type',
|
||||
'product.status',
|
||||
'sub_categories.name',
|
||||
'current_price.admin_price as admin_price',
|
||||
'current_price.mark_up_price as markup_price',
|
||||
'current_price.partner_fee as partner_fee',
|
||||
'current_price.price as price',
|
||||
])
|
||||
// .addSelect(
|
||||
// '(current_price.price + current_price.mark_up_price) as price',
|
||||
// );
|
||||
|
||||
if (
|
||||
subCategories != 'null' &&
|
||||
subCategories &&
|
||||
subCategories != 'undefined'
|
||||
) {
|
||||
baseQuery.where('product.sub_categories_id = :id', {
|
||||
id: subCategories,
|
||||
});
|
||||
// if (
|
||||
// subCategories != 'null' &&
|
||||
// subCategories &&
|
||||
// subCategories != 'undefined'
|
||||
// ) {
|
||||
// baseQuery.where('product.sub_categories_id = :id', {
|
||||
// id: subCategories,
|
||||
// });
|
||||
// }
|
||||
|
||||
|
||||
if (subCategories && filterSubCategories.length > 0) {
|
||||
baseQuery.where('product.sub_categories_id IN (:...subCategoryId)', {
|
||||
subCategoryId: filterSubCategories,
|
||||
}).andWhere(`product.status = 'ACTIVE'`)
|
||||
}
|
||||
|
||||
const newData = []
|
||||
|
||||
const data = await baseQuery
|
||||
.offset(page * pageSize)
|
||||
.limit(pageSize)
|
||||
.getRawMany();
|
||||
|
||||
data.map((dataa) => {
|
||||
let actualPrice = 0
|
||||
|
||||
if (dataa.product_type === 'prepaid') {
|
||||
actualPrice = Number(dataa['price']) + Number(dataa['markup_price'])
|
||||
}
|
||||
|
||||
if (dataa.product_type === 'postpaid') {
|
||||
actualPrice = Number(dataa['admin_price'])- (Number(dataa['partner_fee']) + Number(dataa['markup_price']))
|
||||
}
|
||||
|
||||
dataa.price = actualPrice
|
||||
|
||||
newData.push({
|
||||
...dataa
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
const totalData = await baseQuery.getCount();
|
||||
|
||||
return {
|
||||
|
@ -341,7 +406,7 @@ export class ProductService {
|
|||
};
|
||||
}
|
||||
|
||||
async findOne(code: string) {
|
||||
async findOne(code: string, type: string) {
|
||||
try {
|
||||
return await this.productRepository.findOneOrFail({
|
||||
relations: ['supplier'],
|
||||
|
@ -422,7 +487,7 @@ export class ProductService {
|
|||
code: string,
|
||||
updatePriceProductDto: UpdatePriceProductDto,
|
||||
) {
|
||||
const product = await this.findOne(code);
|
||||
const product = await this.findOne(code, updatePriceProductDto.productType);
|
||||
|
||||
await this.productHistoryPrice.insert({
|
||||
product: product,
|
||||
|
|
|
@ -9,4 +9,7 @@ export class OrderTransactionDto {
|
|||
|
||||
@IsOptional()
|
||||
trx_id: string;
|
||||
|
||||
@IsOptional()
|
||||
bill_trx_id: string;
|
||||
}
|
||||
|
|
51
src/transaction/entities/check-bill-history.entity.ts
Normal file
51
src/transaction/entities/check-bill-history.entity.ts
Normal file
|
@ -0,0 +1,51 @@
|
|||
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;
|
||||
|
||||
@Column()
|
||||
status: string;
|
||||
|
||||
@ManyToOne(() => ProductHistoryPrice, (product) => product.id)
|
||||
product_price: ProductHistoryPrice;
|
||||
}
|
|
@ -16,6 +16,11 @@ export class Transactions extends BaseModel {
|
|||
@Column()
|
||||
type: typeTransaction;
|
||||
|
||||
@Column({
|
||||
nullable: true,
|
||||
})
|
||||
check_bill: string;
|
||||
|
||||
@Column({
|
||||
type: 'uuid',
|
||||
nullable: true,
|
||||
|
|
|
@ -24,14 +24,84 @@ export class PpobCallbackController {
|
|||
response['clientid'],
|
||||
response,
|
||||
);
|
||||
} else {
|
||||
|
||||
return {
|
||||
updateTransaction,
|
||||
statusCode: HttpStatus.BAD_REQUEST,
|
||||
message: 'failed to proccess',
|
||||
};
|
||||
}
|
||||
|
||||
//TODO: UPDATE BERHASIL
|
||||
const updateTransaction =
|
||||
await this.transactionService.callbackOrderSuccess(
|
||||
response['clientid'],
|
||||
response,
|
||||
);
|
||||
|
||||
return {
|
||||
updateTransaction,
|
||||
statusCode: HttpStatus.OK,
|
||||
message: 'success',
|
||||
};
|
||||
}
|
||||
|
||||
@Public()
|
||||
@Get('/metro')
|
||||
async getMetro(@Req() request: FastifyRequest) {
|
||||
const response = request.query;
|
||||
|
||||
if (response['message'].toLowerCase().includes('cek tagihan')) {
|
||||
if (response['status'] != 20) {
|
||||
//TODO: UPDATE GAGAL
|
||||
await this.transactionService.updateBill(
|
||||
response['refid'],
|
||||
null,
|
||||
null,
|
||||
false,
|
||||
response['message'],
|
||||
);
|
||||
|
||||
return {
|
||||
statusCode: HttpStatus.OK,
|
||||
message: 'success',
|
||||
};
|
||||
}
|
||||
|
||||
const splitMessage = response['message'].split('"');
|
||||
//TODO: UPDATE BERHASIL
|
||||
await this.transactionService.updateBill(
|
||||
response['refid'],
|
||||
Number(splitMessage[21].replace(/^\D+/g, '')),
|
||||
Number(splitMessage[17].replace(/^\D+/g, '')),
|
||||
true,
|
||||
response['message'],
|
||||
);
|
||||
//
|
||||
} else {
|
||||
if (response['status'].toString() != '20') {
|
||||
//TODO: UPDATE GAGAL
|
||||
const updateTransaction =
|
||||
await this.transactionService.callbackOrderFailed(
|
||||
response['refid'],
|
||||
response,
|
||||
);
|
||||
|
||||
return {
|
||||
updateTransaction,
|
||||
statusCode: HttpStatus.BAD_REQUEST,
|
||||
message: 'failed to proccess',
|
||||
};
|
||||
}
|
||||
|
||||
//TODO: UPDATE BERHASIL
|
||||
const updateTransaction =
|
||||
await this.transactionService.callbackOrderSuccess(
|
||||
response['refid'],
|
||||
response,
|
||||
);
|
||||
}
|
||||
|
||||
this.logger.log({
|
||||
requestQuery: request.query,
|
||||
});
|
||||
|
|
|
@ -87,6 +87,36 @@ export class TransactionController {
|
|||
};
|
||||
}
|
||||
|
||||
@Post('order-bill-prod')
|
||||
async orderTransactioBillnProd(
|
||||
@Body() orderTransactionDto: OrderTransactionDto,
|
||||
@Request() req,
|
||||
) {
|
||||
return {
|
||||
data: await this.transactionService.orderTransactionBillProd(
|
||||
orderTransactionDto,
|
||||
req.user,
|
||||
),
|
||||
statusCode: HttpStatus.CREATED,
|
||||
message: 'success',
|
||||
};
|
||||
}
|
||||
|
||||
@Post('check-bill')
|
||||
async checkBill(
|
||||
@Body() orderTransactionDto: OrderTransactionDto,
|
||||
@Request() req,
|
||||
) {
|
||||
return {
|
||||
data: await this.transactionService.checkBill(
|
||||
orderTransactionDto,
|
||||
req.user,
|
||||
),
|
||||
statusCode: HttpStatus.CREATED,
|
||||
message: 'success',
|
||||
};
|
||||
}
|
||||
|
||||
@Post('deposit-return')
|
||||
async depositReturn(
|
||||
@Body() depositReturnDto: DepositReturnDto,
|
||||
|
@ -125,6 +155,27 @@ export class TransactionController {
|
|||
};
|
||||
}
|
||||
|
||||
@Get('check-bill-history')
|
||||
async getCheckBillHistory(
|
||||
@Param('id') id: string,
|
||||
@Query('page') page: number,
|
||||
@Query('pageSize') pageSize: number,
|
||||
@Request() req,
|
||||
) {
|
||||
const [data, count] = await this.transactionService.findAll(
|
||||
req.user.userId,
|
||||
page,
|
||||
pageSize,
|
||||
);
|
||||
|
||||
return {
|
||||
data,
|
||||
count,
|
||||
statusCode: HttpStatus.OK,
|
||||
message: 'success',
|
||||
};
|
||||
}
|
||||
|
||||
@Get('history-user/:id')
|
||||
async getHistoryTransactionUserByParam(
|
||||
@Query('page') page: number,
|
||||
|
|
|
@ -10,10 +10,16 @@ import { CoaService } from './coa.service';
|
|||
import { ProductModule } from '../product/product.module';
|
||||
import { UsersModule } from 'src/users/users.module';
|
||||
import { ConfigurableModule } from '../configurable/configurable.module';
|
||||
import { CheckBillHistory } from './entities/check-bill-history.entity';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
TypeOrmModule.forFeature([COA, TransactionJournal, Transactions]),
|
||||
TypeOrmModule.forFeature([
|
||||
COA,
|
||||
TransactionJournal,
|
||||
Transactions,
|
||||
CheckBillHistory,
|
||||
]),
|
||||
ProductModule,
|
||||
ConfigurableModule,
|
||||
forwardRef(() => UsersModule),
|
||||
|
|
|
@ -27,6 +27,8 @@ import { DepositReturnDto } from './dto/deposit_return.dto';
|
|||
import { UserDetail } from '../users/entities/user_detail.entity';
|
||||
import { doTransaction } from '../helper/irs-api';
|
||||
import { ProductHistoryPrice } from '../product/entities/product-history-price.entity';
|
||||
import axios from 'axios';
|
||||
import { CheckBillHistory } from './entities/check-bill-history.entity';
|
||||
|
||||
@Injectable()
|
||||
export class TransactionService {
|
||||
|
@ -39,6 +41,8 @@ export class TransactionService {
|
|||
private transactionJournalRepository: Repository<TransactionJournal>,
|
||||
@InjectRepository(COA)
|
||||
private coaRepository: Repository<COA>,
|
||||
@InjectRepository(CheckBillHistory)
|
||||
private checkBillHistoryRepository: Repository<CheckBillHistory>,
|
||||
private coaService: CoaService,
|
||||
private productService: ProductService,
|
||||
private productHistoryPriceService: ProductHistoryPriceService,
|
||||
|
@ -312,6 +316,7 @@ export class TransactionService {
|
|||
//GET PRODUCT
|
||||
const product = await this.productService.findOne(
|
||||
orderTransactionDto.productCode,
|
||||
'prepaid'
|
||||
);
|
||||
|
||||
const product_price = await this.productHistoryPriceService.findOne(
|
||||
|
@ -446,6 +451,230 @@ export class TransactionService {
|
|||
//GET PRODUCT AND PRICE
|
||||
const product = await this.productService.findOne(
|
||||
orderTransactionDto.productCode,
|
||||
'prepaid',
|
||||
);
|
||||
|
||||
const supplier = await this.supplierService.findByCode(
|
||||
product.supplier.code,
|
||||
);
|
||||
|
||||
let product_price = await this.productHistoryPriceService.findOne(
|
||||
product.id,
|
||||
userData.partner?.id,
|
||||
);
|
||||
|
||||
//GET COA
|
||||
const coaAccount = await this.coaService.findByUser(
|
||||
userData.id,
|
||||
coaType.WALLET,
|
||||
);
|
||||
|
||||
const coaInventory = await this.coaService.findByName(
|
||||
`${coaType[coaType.INVENTORY]}-${product.supplier.code}`,
|
||||
);
|
||||
|
||||
const coaCostOfSales = await this.coaService.findByName(
|
||||
`${coaType[coaType.COST_OF_SALES]}-${product.supplier.code}`,
|
||||
);
|
||||
|
||||
const coaSales = await this.coaService.findByName(
|
||||
`${coaType[coaType.SALES]}-SYSTEM`,
|
||||
);
|
||||
|
||||
if (orderTransactionDto.bill_trx_id) {
|
||||
try {
|
||||
const billId = await this.checkBillHistoryRepository.findOneOrFail({
|
||||
where: {
|
||||
trx_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) {
|
||||
throw new HttpException(
|
||||
{
|
||||
statusCode: HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
error: `Transaction Failed because saldo not enough`,
|
||||
},
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
|
||||
//HIT API SUPPLIER
|
||||
const trxId = Array(6)
|
||||
.fill(null)
|
||||
.map(() => {
|
||||
return Math.round(Math.random() * 16).toString(16);
|
||||
})
|
||||
.join('');
|
||||
|
||||
let hitSupplier = await doTransaction(
|
||||
orderTransactionDto.productCode,
|
||||
orderTransactionDto.destination,
|
||||
trxId,
|
||||
supplier,
|
||||
);
|
||||
// let hitSupplier;
|
||||
|
||||
if (supplier.code != 'IRS') {
|
||||
const parsingResponse = hitSupplier.split(' ');
|
||||
console.log
|
||||
const newHitSupplier = {
|
||||
success: hitSupplier.includes('diproses'),
|
||||
harga: parseInt(
|
||||
parsingResponse[parsingResponse.length - 2].replace(/\./g,' '),
|
||||
),
|
||||
msg: hitSupplier,
|
||||
};
|
||||
hitSupplier = newHitSupplier;
|
||||
if(orderTransactionDto.bill_trx_id !== null){
|
||||
hitSupplier.harga = product_price.price;
|
||||
}
|
||||
}
|
||||
// const hitSupplier = {
|
||||
// harga: 2000,
|
||||
// success: true,
|
||||
// msg: 'Berhasil',
|
||||
// };
|
||||
|
||||
this.logger.log({
|
||||
responseAPISupplier: hitSupplier,
|
||||
});
|
||||
|
||||
let costInventory = product_price.price;
|
||||
|
||||
if (hitSupplier.harga != product_price.price) {
|
||||
product_price.endDate = new Date();
|
||||
costInventory = hitSupplier.harga;
|
||||
const listActivePrice =
|
||||
await this.productHistoryPriceService.getAllActivePriceByProduct(
|
||||
product.id,
|
||||
);
|
||||
|
||||
await this.productHistoryPriceService.updateEndDate(product.id);
|
||||
|
||||
listActivePrice.map(async (x) => {
|
||||
const newProductPrice = new ProductHistoryPrice();
|
||||
|
||||
newProductPrice.id = uuid.v4();
|
||||
newProductPrice.type = x.type;
|
||||
newProductPrice.price = hitSupplier.harga;
|
||||
newProductPrice.mark_up_price = x.mark_up_price;
|
||||
newProductPrice.startDate = new Date();
|
||||
newProductPrice.product = product;
|
||||
newProductPrice.partner = x.partner;
|
||||
await this.productHistoryPriceService.create(newProductPrice);
|
||||
|
||||
product_price = newProductPrice;
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
//TRANSACTION DATA
|
||||
await this.connection.transaction(async (manager) => {
|
||||
const transactionData = new Transactions();
|
||||
|
||||
transactionData.id = uuid.v4();
|
||||
transactionData.amount =
|
||||
product_price.mark_up_price + product_price.price;
|
||||
transactionData.user = userData.id;
|
||||
transactionData.type = typeTransaction.ORDER;
|
||||
transactionData.product_price = product_price;
|
||||
transactionData.destination = orderTransactionDto.destination;
|
||||
transactionData.partner_trx_id = orderTransactionDto.trx_id;
|
||||
transactionData.supplier_trx_id = trxId;
|
||||
transactionData.check_bill = orderTransactionDto.bill_trx_id;
|
||||
|
||||
if (!hitSupplier.success) {
|
||||
transactionData.status = statusTransaction.FAILED;
|
||||
status = statusTransaction[transactionData.status];
|
||||
await this.transactionRepository.insert(transactionData);
|
||||
throw new HttpException(
|
||||
{
|
||||
statusCode: HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
error: hitSupplier.msg,
|
||||
},
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
} else {
|
||||
transactionData.status = statusTransaction.PENDING;
|
||||
status = statusTransaction[transactionData.status];
|
||||
}
|
||||
|
||||
await manager.insert(Transactions, transactionData);
|
||||
|
||||
await this.accountingTransaction({
|
||||
createTransaction: false,
|
||||
transactionalEntityManager: manager,
|
||||
transaction: transactionData,
|
||||
amount: transactionData.amount,
|
||||
journals: [
|
||||
{
|
||||
coa_id: coaInventory.id,
|
||||
credit: costInventory,
|
||||
},
|
||||
{
|
||||
coa_id: coaCostOfSales.id,
|
||||
debit: costInventory,
|
||||
},
|
||||
{
|
||||
coa_id: coaAccount.id,
|
||||
debit: product_price.mark_up_price + costInventory,
|
||||
},
|
||||
{
|
||||
// eslint-disable-next-line camelcase
|
||||
coa_id: coaSales.id,
|
||||
credit: product_price.mark_up_price + costInventory,
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
} catch (e) {
|
||||
throw e;
|
||||
}
|
||||
|
||||
return {
|
||||
trx_id: trxId,
|
||||
client_trx_id: orderTransactionDto.trx_id,
|
||||
product: orderTransactionDto.productCode,
|
||||
amount: product_price.mark_up_price + product_price.price,
|
||||
status: status,
|
||||
};
|
||||
}
|
||||
|
||||
async orderTransactionBillProd(
|
||||
orderTransactionDto: OrderTransactionDto,
|
||||
currentUser: any,
|
||||
) {
|
||||
let status;
|
||||
const amount = 0;
|
||||
//GET USER DATA
|
||||
const userData = await this.userService.findByUsername(
|
||||
currentUser.username,
|
||||
);
|
||||
|
||||
//GET PRODUCT AND PRICE
|
||||
const product = await this.productService.findOne(
|
||||
orderTransactionDto.productCode,
|
||||
'postpaid',
|
||||
);
|
||||
|
||||
const supplier = await this.supplierService.findByCode(
|
||||
product.supplier.code,
|
||||
);
|
||||
|
||||
let product_price = await this.productHistoryPriceService.findOne(
|
||||
|
@ -489,12 +718,23 @@ export class TransactionService {
|
|||
})
|
||||
.join('');
|
||||
|
||||
const hitSupplier = await doTransaction(
|
||||
let hitSupplier = await doTransaction(
|
||||
orderTransactionDto.productCode,
|
||||
orderTransactionDto.destination,
|
||||
trxId,
|
||||
supplier,
|
||||
);
|
||||
|
||||
if (supplier.code != 'IRS') {
|
||||
const parsingResponse = hitSupplier.split(' ');
|
||||
hitSupplier = {
|
||||
success: hitSupplier.includes('diproses'),
|
||||
harga: parseInt(
|
||||
parsingResponse[parsingResponse.length - 2].replaceAll('.', ''),
|
||||
),
|
||||
msg: hitSupplier,
|
||||
};
|
||||
}
|
||||
// const hitSupplier = {
|
||||
// harga: 2000,
|
||||
// success: true,
|
||||
|
@ -510,27 +750,6 @@ export class TransactionService {
|
|||
if (hitSupplier.harga != product_price.price) {
|
||||
product_price.endDate = new Date();
|
||||
costInventory = hitSupplier.harga;
|
||||
const listActivePrice =
|
||||
await this.productHistoryPriceService.getAllActivePriceByProduct(
|
||||
product.id,
|
||||
);
|
||||
|
||||
await this.productHistoryPriceService.updateEndDate(product.id);
|
||||
|
||||
listActivePrice.map(async (x) => {
|
||||
const newProductPrice = new ProductHistoryPrice();
|
||||
|
||||
newProductPrice.id = uuid.v4();
|
||||
newProductPrice.type = x.type;
|
||||
newProductPrice.price = hitSupplier.harga;
|
||||
newProductPrice.mark_up_price = x.mark_up_price;
|
||||
newProductPrice.startDate = new Date();
|
||||
newProductPrice.product = product;
|
||||
newProductPrice.partner = x.partner;
|
||||
await this.productHistoryPriceService.create(newProductPrice);
|
||||
|
||||
product_price = newProductPrice;
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -605,6 +824,84 @@ export class TransactionService {
|
|||
};
|
||||
}
|
||||
|
||||
async checkBill(orderTransactionDto: OrderTransactionDto, currentUser: any) {
|
||||
//GET USER DATA
|
||||
const userData = await this.userService.findByUsername(
|
||||
currentUser.username,
|
||||
);
|
||||
|
||||
//GET PRODUCT AND PRICE
|
||||
const product = await this.productService.findOne(
|
||||
orderTransactionDto.productCode,
|
||||
'postpaid',
|
||||
);
|
||||
|
||||
const supplier = await this.supplierService.findByCode(
|
||||
product.supplier.code,
|
||||
);
|
||||
|
||||
let product_price = await this.productHistoryPriceService.findOne(
|
||||
product.id,
|
||||
userData.partner?.id,
|
||||
);
|
||||
//HIT API SUPPLIER
|
||||
const trxId = Array(6)
|
||||
.fill(null)
|
||||
.map(() => {
|
||||
return Math.round(Math.random() * 16).toString(16);
|
||||
})
|
||||
.join('');
|
||||
|
||||
let status;
|
||||
|
||||
try {
|
||||
let hitSupplier = await doTransaction(
|
||||
'CEK' + orderTransactionDto.productCode.slice(3),
|
||||
orderTransactionDto.destination,
|
||||
trxId,
|
||||
supplier,
|
||||
);
|
||||
const parsingResponse = hitSupplier.split(' ');
|
||||
hitSupplier = {
|
||||
success: hitSupplier.includes('diproses'),
|
||||
msg: hitSupplier,
|
||||
};
|
||||
|
||||
if (!hitSupplier.success) {
|
||||
status = statusTransaction[statusTransaction.FAILED];
|
||||
throw new HttpException(
|
||||
{
|
||||
statusCode: HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
error: hitSupplier.msg,
|
||||
},
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
} else {
|
||||
status = statusTransaction[statusTransaction.SUCCESS];
|
||||
|
||||
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,
|
||||
product_price: product_price,
|
||||
status: 'PENDING',
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
throw e;
|
||||
}
|
||||
|
||||
return {
|
||||
trx_id: trxId,
|
||||
client_trx_id: orderTransactionDto.trx_id,
|
||||
product: orderTransactionDto.productCode,
|
||||
status: status,
|
||||
};
|
||||
}
|
||||
|
||||
async createDepositReturn(currentUser, depositReturnDto: DepositReturnDto) {
|
||||
const userData = await this.userService.findByUsername(
|
||||
currentUser.username,
|
||||
|
@ -834,6 +1131,20 @@ export class TransactionService {
|
|||
} catch (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) {
|
||||
|
@ -866,8 +1177,7 @@ export class TransactionService {
|
|||
const coaExpense = await this.coaService.findByName(
|
||||
`${coaType[coaType.EXPENSE]}-SYSTEM`,
|
||||
);
|
||||
|
||||
if (!userData.partner) {
|
||||
if (userData.partner != null) {
|
||||
//GET SALES
|
||||
supervisorData = await this.calculateCommission(
|
||||
supervisorData,
|
||||
|
@ -905,6 +1215,36 @@ export class TransactionService {
|
|||
} catch (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) {
|
||||
|
@ -1041,6 +1381,58 @@ export class TransactionService {
|
|||
};
|
||||
}
|
||||
|
||||
async findOne(user: string, id: string) {
|
||||
try {
|
||||
return this.checkBillHistoryRepository.findOneOrFail({
|
||||
where: {
|
||||
trx_id: id,
|
||||
user: user,
|
||||
},
|
||||
});
|
||||
} catch (e) {
|
||||
throw new HttpException(
|
||||
{
|
||||
statusCode: HttpStatus.NOT_FOUND,
|
||||
error: 'Billing not found',
|
||||
},
|
||||
HttpStatus.NOT_FOUND,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async findAll(user: string, page, pageSize?) {
|
||||
try {
|
||||
return await this.checkBillHistoryRepository.findAndCount({
|
||||
where: {
|
||||
user: user,
|
||||
},
|
||||
select: [
|
||||
'amount',
|
||||
'admin_price',
|
||||
'product_code',
|
||||
'destination',
|
||||
'trx_id',
|
||||
'partner_trx_id',
|
||||
'status',
|
||||
'createdAt',
|
||||
],
|
||||
skip: page * (pageSize || 10),
|
||||
take: pageSize || 10,
|
||||
order: {
|
||||
createdAt: 'DESC',
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
throw new HttpException(
|
||||
{
|
||||
statusCode: HttpStatus.NOT_FOUND,
|
||||
error: 'Billing not found',
|
||||
},
|
||||
HttpStatus.NOT_FOUND,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async topUpHistoryByUser(
|
||||
page: number,
|
||||
user: string,
|
||||
|
@ -1449,4 +1841,79 @@ export class TransactionService {
|
|||
|
||||
return transaction;
|
||||
}
|
||||
|
||||
async updateBill(
|
||||
trxId: string,
|
||||
amount: number,
|
||||
admin: number,
|
||||
status: boolean,
|
||||
message: string,
|
||||
) {
|
||||
const billData = await this.findOneBillById(trxId);
|
||||
console.log(billData,"ini dia")
|
||||
const userData = await this.userService.findExist(billData.user);
|
||||
|
||||
const product_price = await this.productHistoryPriceService.findById(
|
||||
billData.product_price.id,
|
||||
);
|
||||
|
||||
await this.checkBillHistoryRepository.update(
|
||||
{
|
||||
trx_id: trxId,
|
||||
},
|
||||
{
|
||||
amount: status
|
||||
? amount -
|
||||
admin +
|
||||
product_price.partner_fee +
|
||||
product_price.mark_up_price
|
||||
: 0,
|
||||
admin_price: admin,
|
||||
status: status ? 'SUCCESS' : 'FAILED',
|
||||
callback_json: JSON.stringify(message),
|
||||
},
|
||||
);
|
||||
|
||||
if (userData.partner) {
|
||||
const message = status
|
||||
? `Bill dari ${billData.destination} adalah ${
|
||||
amount + product_price.partner_fee + product_price.mark_up_price
|
||||
}.`
|
||||
: '';
|
||||
const statusResponse = status ? 'berhasil' : 'gagal';
|
||||
this.callbackToPartner(
|
||||
userData.id,
|
||||
message,
|
||||
billData.partner_trx_id,
|
||||
amount + product_price.partner_fee + product_price.mark_up_price,
|
||||
billData.product_code,
|
||||
billData.destination,
|
||||
'-',
|
||||
statusResponse,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async findOneBillById(trxId: string) {
|
||||
try {
|
||||
return await this.checkBillHistoryRepository.findOneOrFail({
|
||||
relations: ['product_price'],
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,4 +6,19 @@ export class CreateSupplierDto {
|
|||
|
||||
@IsNotEmpty()
|
||||
code: string;
|
||||
|
||||
@IsNotEmpty()
|
||||
url: string;
|
||||
|
||||
@IsNotEmpty()
|
||||
irs_id: string;
|
||||
|
||||
@IsNotEmpty()
|
||||
irs_pin: string;
|
||||
|
||||
@IsNotEmpty()
|
||||
irs_user: string;
|
||||
|
||||
@IsNotEmpty()
|
||||
irs_pass: string;
|
||||
}
|
||||
|
|
|
@ -27,4 +27,9 @@ export class Partner extends BaseModel {
|
|||
|
||||
@Column({ default: true })
|
||||
status: boolean;
|
||||
|
||||
@Column({
|
||||
default: '',
|
||||
})
|
||||
callback_url: string;
|
||||
}
|
||||
|
|
|
@ -16,6 +16,31 @@ export class Supplier extends BaseModel {
|
|||
@Column()
|
||||
status: boolean;
|
||||
|
||||
@Column({
|
||||
nullable: true
|
||||
})
|
||||
url: string;
|
||||
|
||||
@Column({
|
||||
nullable: true
|
||||
})
|
||||
irs_id: string;
|
||||
|
||||
@Column({
|
||||
nullable: true
|
||||
})
|
||||
irs_pin: string;
|
||||
|
||||
@Column({
|
||||
nullable: true
|
||||
})
|
||||
irs_user: string;
|
||||
|
||||
@Column({
|
||||
nullable: true
|
||||
})
|
||||
irs_pass: string;
|
||||
|
||||
coa: COA;
|
||||
|
||||
coa_undistribute: COA;
|
||||
|
|
|
@ -22,7 +22,7 @@ export class SupplierService {
|
|||
)
|
||||
private coaService: CoaService,
|
||||
private connection: Connection,
|
||||
) {}
|
||||
) { }
|
||||
|
||||
async create(createSupplierDto: CreateSupplierDto) {
|
||||
const check = await this.supplierRepository.findOne({
|
||||
|
@ -43,6 +43,11 @@ export class SupplierService {
|
|||
supplierData.id = uuid.v4();
|
||||
supplierData.name = createSupplierDto.name;
|
||||
supplierData.code = createSupplierDto.code;
|
||||
supplierData.url = createSupplierDto.url;
|
||||
supplierData.irs_id = createSupplierDto.irs_id;
|
||||
supplierData.irs_pin = createSupplierDto.irs_pin;
|
||||
supplierData.irs_user = createSupplierDto.irs_user;
|
||||
supplierData.irs_pass = createSupplierDto.irs_pass;
|
||||
supplierData.status = false;
|
||||
|
||||
await this.connection.transaction(async (manager) => {
|
||||
|
@ -99,6 +104,11 @@ export class SupplierService {
|
|||
const supplierData = new Supplier();
|
||||
|
||||
supplierData.name = updateSupplierDto.name;
|
||||
supplierData.url = updateSupplierDto.url;
|
||||
supplierData.irs_id = updateSupplierDto.irs_id;
|
||||
supplierData.irs_pin = updateSupplierDto.irs_pin;
|
||||
supplierData.irs_user = updateSupplierDto.irs_user;
|
||||
supplierData.irs_pass = updateSupplierDto.irs_pass;
|
||||
supplierData.status = true;
|
||||
|
||||
await this.connection.transaction(async (manager) => {
|
||||
|
|
|
@ -20,12 +20,15 @@ import * as uuid from 'uuid';
|
|||
import { UserDetail } from './entities/user_detail.entity';
|
||||
import { COA } from '../transaction/entities/coa.entity';
|
||||
import { mapSeries } from 'bluebird';
|
||||
import { Partner } from './entities/partner.entity';
|
||||
|
||||
@Injectable()
|
||||
export class UsersService {
|
||||
constructor(
|
||||
@InjectRepository(User)
|
||||
private usersRepository: Repository<User>,
|
||||
@InjectRepository(Partner)
|
||||
private partnerRepository: Repository<Partner>,
|
||||
@InjectRepository(UserDetail)
|
||||
private userDetailRepository: Repository<UserDetail>,
|
||||
@Inject(
|
||||
|
@ -410,6 +413,7 @@ export class UsersService {
|
|||
.leftJoinAndSelect('users.roles', 'roles')
|
||||
.leftJoinAndSelect('users.superior', 'superior')
|
||||
.leftJoinAndSelect('users.userDetail', 'userDetail')
|
||||
.leftJoinAndSelect('users.partner', 'partner')
|
||||
.where('users.id = :id', {
|
||||
id: id,
|
||||
})
|
||||
|
@ -429,6 +433,14 @@ export class UsersService {
|
|||
'userDetail.identity_number',
|
||||
'userDetail.image_identity',
|
||||
'userDetail.image_store',
|
||||
'partner.id',
|
||||
'partner.name',
|
||||
'partner.code',
|
||||
'partner.npwp',
|
||||
'partner.address',
|
||||
'partner.phone_number',
|
||||
'partner.callback_url'
|
||||
|
||||
])
|
||||
.getOne();
|
||||
const coa = await this.coaService.findByUser(id, coaType.WALLET);
|
||||
|
@ -676,4 +688,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user