Merge branch 'development' into 'devops-staging'

Development

See merge request empatnusabangsa/ppob/ppob-backend!16
This commit is contained in:
ilham dwi pratama 2021-12-13 04:42:55 +00:00
commit 97873e9c91
35 changed files with 696 additions and 108 deletions

View File

@ -28,6 +28,7 @@ export class AuthService {
username: user.username, username: user.username,
sub: user.id, sub: user.id,
role: user.roles.name, role: user.roles.name,
partner: user.partner.id,
}; };
return { return {

View File

@ -0,0 +1,48 @@
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import { EntityNotFoundError, Repository } from 'typeorm';
import { Roles } from './entities/roles.entity';
import { InjectRepository } from '@nestjs/typeorm';
import { UpdateUserDto } from '../users/dto/update-user.dto';
import { CommissionSetting } from './entities/commission_setting.entity';
@Injectable()
export class CommissionService {
constructor(
@InjectRepository(CommissionSetting)
private commissionRepository: Repository<CommissionSetting>,
) {}
findAllRoles(page) {
return this.commissionRepository.findAndCount({
skip: page * 10,
take: 10,
order: {
version: 'DESC',
},
});
}
async updateCommission(id: string, request) {
try {
await this.commissionRepository.findOneOrFail(id);
} catch (e) {
if (e instanceof EntityNotFoundError) {
throw new HttpException(
{
statusCode: HttpStatus.NOT_FOUND,
error: 'Data not found',
},
HttpStatus.NOT_FOUND,
);
} else {
throw e;
}
}
const result = await this.commissionRepository.update(id, {
commission: request.value,
});
return this.commissionRepository.findOneOrFail(id);
}
}

View File

@ -11,13 +11,17 @@ import {
Query, Query,
} from '@nestjs/common'; } from '@nestjs/common';
import { RoleService } from './roles.service'; import { RoleService } from './roles.service';
import { CommissionService } from './commission.service';
@Controller({ @Controller({
path: 'config', path: 'config',
version: '1', version: '1',
}) })
export class ConfigurableController { export class ConfigurableController {
constructor(private readonly roleService: RoleService) {} constructor(
private readonly roleService: RoleService,
private readonly commissionService: CommissionService,
) {}
@Get('/roles') @Get('/roles')
async findAll(@Query('page') page: number) { async findAll(@Query('page') page: number) {
@ -31,6 +35,18 @@ export class ConfigurableController {
}; };
} }
@Get('/commission')
async findCommission(@Query('page') page: number) {
const [data, count] = await this.commissionService.findAllRoles(page);
return {
data,
count,
statusCode: HttpStatus.OK,
message: 'success',
};
}
@Get(':id') @Get(':id')
async findOne(@Param('id', ParseUUIDPipe) id: string) { async findOne(@Param('id', ParseUUIDPipe) id: string) {
return { return {
@ -39,4 +55,16 @@ export class ConfigurableController {
message: 'success', message: 'success',
}; };
} }
@Put('/commission/:id')
async updateCommission(
@Param('id', ParseUUIDPipe) id: string,
@Body() request,
) {
return {
data: await this.commissionService.updateCommission(id, request),
statusCode: HttpStatus.OK,
message: 'success',
};
}
} }

View File

@ -3,11 +3,13 @@ import { TypeOrmModule } from '@nestjs/typeorm';
import { Roles } from './entities/roles.entity'; import { Roles } from './entities/roles.entity';
import { ConfigurableController } from './configurable.controller'; import { ConfigurableController } from './configurable.controller';
import { RoleService } from './roles.service'; import { RoleService } from './roles.service';
import { CommissionService } from './commission.service';
import { CommissionSetting } from './entities/commission_setting.entity';
@Module({ @Module({
imports: [TypeOrmModule.forFeature([Roles])], imports: [TypeOrmModule.forFeature([Roles, CommissionSetting])],
controllers: [ConfigurableController], controllers: [ConfigurableController],
providers: [RoleService], providers: [RoleService, CommissionService],
exports: [RoleService] exports: [RoleService],
}) })
export class ConfigurableModule {} export class ConfigurableModule {}

View File

@ -0,0 +1,16 @@
import { Entity, Column, OneToOne, JoinColumn } from 'typeorm';
import { BaseModel } from '../../config/basemodel.entity';
import { Roles } from './roles.entity';
@Entity()
export class CommissionSetting extends BaseModel {
@Column()
name: string;
@Column()
commission: number;
@OneToOne(() => Roles)
@JoinColumn()
role: Roles;
}

View File

@ -28,7 +28,7 @@ export class RoleService {
throw new HttpException( throw new HttpException(
{ {
statusCode: HttpStatus.NOT_FOUND, statusCode: HttpStatus.NOT_FOUND,
error: 'Data not found', error: 'Data Role not found',
}, },
HttpStatus.NOT_FOUND, HttpStatus.NOT_FOUND,
); );

View File

@ -24,10 +24,17 @@ export enum coaType {
BANK, BANK,
EXPENSE, EXPENSE,
ACCOUNT_RECEIVABLE, ACCOUNT_RECEIVABLE,
ACCOUNT_PAYABLE ACCOUNT_PAYABLE,
BUDGET,
CONTRA_BUDGET,
} }
export enum balanceType { export enum balanceType {
DEBIT, DEBIT,
CREDIT, CREDIT,
} }
export enum accountType {
PARTNER,
CUSTOMER,
}

View File

@ -18,4 +18,7 @@ export class CreateProductDto {
@IsUUID() @IsUUID()
subCategoriesId: string; subCategoriesId: string;
@IsUUID()
supplierId: string;
} }

View File

@ -2,6 +2,7 @@ import { Entity, Column, PrimaryGeneratedColumn, ManyToOne } from 'typeorm';
import { Product } from './product.entity'; import { Product } from './product.entity';
import { BaseModel } from '../../config/basemodel.entity'; import { BaseModel } from '../../config/basemodel.entity';
import { productType } from '../../helper/enum-list'; import { productType } from '../../helper/enum-list';
import { User } from '../../users/entities/user.entity';
@Entity() @Entity()
export class ProductHistoryPrice extends BaseModel { export class ProductHistoryPrice extends BaseModel {
@ -11,6 +12,9 @@ export class ProductHistoryPrice extends BaseModel {
@ManyToOne(() => Product, (product) => product.id) @ManyToOne(() => Product, (product) => product.id)
product: Product; product: Product;
@ManyToOne(() => User, (user) => user.id)
user: User;
@Column() @Column()
price: number; price: number;

View File

@ -11,6 +11,7 @@ import {
} from 'typeorm'; } from 'typeorm';
import { ProductSubCategories } from './product-sub-category.entity'; import { ProductSubCategories } from './product-sub-category.entity';
import { BaseModel } from '../../config/basemodel.entity'; import { BaseModel } from '../../config/basemodel.entity';
import { Supplier } from '../../users/entities/supplier.entity';
@Entity() @Entity()
export class Product extends BaseModel { export class Product extends BaseModel {
@ -43,4 +44,14 @@ export class Product extends BaseModel {
}, },
) )
sub_categories: ProductSubCategories; sub_categories: ProductSubCategories;
@ManyToOne(
() => {
return Supplier;
},
(partner) => {
return partner.id;
},
)
supplier: Supplier;
} }

View File

@ -1,4 +1,10 @@
import { forwardRef, HttpException, HttpStatus, Inject, Injectable } from '@nestjs/common'; import {
forwardRef,
HttpException,
HttpStatus,
Inject,
Injectable,
} from '@nestjs/common';
import { EntityNotFoundError, Repository } from 'typeorm'; import { EntityNotFoundError, Repository } from 'typeorm';
import { InjectRepository } from '@nestjs/typeorm'; import { InjectRepository } from '@nestjs/typeorm';
import { COA } from './entities/coa.entity'; import { COA } from './entities/coa.entity';
@ -10,24 +16,40 @@ export class CoaService {
constructor( constructor(
@InjectRepository(COA) @InjectRepository(COA)
private coaRepository: Repository<COA>, private coaRepository: Repository<COA>,
@Inject(forwardRef(() => UsersService)) @Inject(
forwardRef(() => {
return UsersService;
}),
)
private userService: UsersService, private userService: UsersService,
) {} ) {}
async create(inputCoaDto: InputCoaDto) { async create(inputCoaDto: InputCoaDto) {
const user = inputCoaDto.user const coaData = new COA();
let coaData = new COA(); let name = '';
coaData.user = user.id; if (inputCoaDto.user) {
coaData.name = coaType[inputCoaDto.type] + '-' + user.username; coaData.user = inputCoaDto.user.id;
name = inputCoaDto.user.username;
}
if (inputCoaDto.supplier) {
coaData.supplier = inputCoaDto.supplier.id;
name = inputCoaDto.supplier.code;
}
coaData.name = `${coaType[inputCoaDto.type]}-${name}`;
coaData.balanceType = inputCoaDto.balanceType; coaData.balanceType = inputCoaDto.balanceType;
coaData.type = inputCoaDto.type; coaData.type = inputCoaDto.type;
coaData.amount = 0; coaData.amount = 0;
const result = await inputCoaDto.coaEntityManager.insert(COA,coaData); const result = await inputCoaDto.coaEntityManager.insert(COA, coaData);
if(inputCoaDto.type == coaType.ACCOUNT_RECEIVABLE || inputCoaDto.type == coaType.ACCOUNT_PAYABLE){ if (
inputCoaDto.type == coaType.ACCOUNT_RECEIVABLE ||
inputCoaDto.type == coaType.ACCOUNT_PAYABLE
) {
coaData.relatedUser = inputCoaDto.relatedUserId; coaData.relatedUser = inputCoaDto.relatedUserId;
await inputCoaDto.coaEntityManager.save(coaData) await inputCoaDto.coaEntityManager.save(coaData);
} }
return coaData; return coaData;
@ -35,7 +57,10 @@ export class CoaService {
async findByUser(id: string, typeOfCoa: coaType) { async findByUser(id: string, typeOfCoa: coaType) {
try { try {
return await this.coaRepository.findOneOrFail({ user: id, type: typeOfCoa }); return await this.coaRepository.findOneOrFail({
user: id,
type: typeOfCoa,
});
} catch (e) { } catch (e) {
if (e instanceof EntityNotFoundError) { if (e instanceof EntityNotFoundError) {
throw new HttpException( throw new HttpException(
@ -51,9 +76,17 @@ export class CoaService {
} }
} }
async findByUserWithRelated(id: string, relatedId: string, typeOfCoa: coaType) { async findByUserWithRelated(
id: string,
relatedId: string,
typeOfCoa: coaType,
) {
try { try {
return await this.coaRepository.findOneOrFail({ user: id, type: typeOfCoa, relatedUser:relatedId }); return await this.coaRepository.findOneOrFail({
user: id,
type: typeOfCoa,
relatedUser: relatedId,
});
} catch (e) { } catch (e) {
if (e instanceof EntityNotFoundError) { if (e instanceof EntityNotFoundError) {
throw new HttpException( throw new HttpException(

View File

@ -1,12 +1,16 @@
import { IsNotEmpty, IsUUID } from 'class-validator'; import { IsNotEmpty, IsUUID } from 'class-validator';
import { balanceType, coaType, statusTransaction, typeTransaction } from 'src/helper/enum-list'; import {
balanceType,
coaType,
statusTransaction,
typeTransaction,
} from 'src/helper/enum-list';
import { EntityManager } from 'typeorm'; import { EntityManager } from 'typeorm';
export class AddSaldoSupplier { export class AddSaldoSupplier {
@IsNotEmpty() @IsNotEmpty()
supplier?: string; supplier: string;
@IsNotEmpty() @IsNotEmpty()
amount?: number; amount: number;
} }

View File

@ -6,4 +6,7 @@ export class DistributeTransactionDto {
@IsNotEmpty() @IsNotEmpty()
destination: string; destination: string;
@IsNotEmpty()
supplier: string;
} }

View File

@ -2,6 +2,7 @@ import { IsNotEmpty, IsUUID } from 'class-validator';
import { balanceType, coaType } from 'src/helper/enum-list'; import { balanceType, coaType } from 'src/helper/enum-list';
import { User } from 'src/users/entities/user.entity'; import { User } from 'src/users/entities/user.entity';
import { EntityManager } from 'typeorm'; import { EntityManager } from 'typeorm';
import { Supplier } from '../../users/entities/supplier.entity';
export class InputCoaDto { export class InputCoaDto {
@IsUUID() @IsUUID()
@ -16,6 +17,9 @@ export class InputCoaDto {
@IsUUID() @IsUUID()
relatedUserId: string; relatedUserId: string;
@IsUUID()
supplier: Supplier;
@IsNotEmpty() @IsNotEmpty()
coaEntityManager: EntityManager; coaEntityManager: EntityManager;
} }

View File

@ -1,7 +1,4 @@
import { import { Entity, Column } from 'typeorm';
Entity,
Column,
} from 'typeorm';
import { BaseModel } from '../../config/basemodel.entity'; import { BaseModel } from '../../config/basemodel.entity';
import { coaType, balanceType } from '../../helper/enum-list'; import { coaType, balanceType } from '../../helper/enum-list';
@ -19,11 +16,18 @@ export class COA extends BaseModel {
@Column() @Column()
amount: number; amount: number;
@Column() @Column({
nullable: true,
})
user: string; user: string;
@Column({ @Column({
nullable:true nullable: true,
}) })
relatedUser: string; relatedUser: string;
@Column({
nullable: true,
})
supplier: string;
} }

View File

@ -9,7 +9,6 @@ import {
import { BaseModel } from '../../config/basemodel.entity'; import { BaseModel } from '../../config/basemodel.entity';
import { COA } from './coa.entity'; import { COA } from './coa.entity';
import { Transactions } from './transactions.entity'; import { Transactions } from './transactions.entity';
import { TransactionType } from './transaction-type.entity';
import { balanceType } from '../../helper/enum-list'; import { balanceType } from '../../helper/enum-list';
@Entity() @Entity()
@ -20,15 +19,15 @@ export class TransactionJournal extends BaseModel {
@Column() @Column()
amount: number; amount: number;
@OneToOne( @ManyToOne(
() => { () => {
return Transactions; return Transactions;
}, },
(trans) => { (transaction) => {
return trans.id; return transaction.id;
}, },
) )
transaction: Transactions; transaction_head: Transactions;
@ManyToOne( @ManyToOne(
() => { () => {

View File

@ -1,11 +0,0 @@
import {
Entity,
Column,
} from 'typeorm';
import { BaseModel } from '../../config/basemodel.entity';
@Entity()
export class TransactionType extends BaseModel {
@Column()
name: string;
}

View File

@ -54,7 +54,7 @@ export class TransactionController {
@Request() req, @Request() req,
) { ) {
return { return {
data: await this.transactionService.addIRSWallet( data: await this.transactionService.addPartnerSaldo(
addSaldoSupplier, addSaldoSupplier,
req.user, req.user,
), ),

View File

@ -4,7 +4,6 @@ import { TransactionController } from './transaction.controller';
import { PpobCallbackController } from './ppob_callback.controller'; import { PpobCallbackController } from './ppob_callback.controller';
import { TypeOrmModule } from '@nestjs/typeorm'; import { TypeOrmModule } from '@nestjs/typeorm';
import { COA } from './entities/coa.entity'; import { COA } from './entities/coa.entity';
import { TransactionType } from './entities/transaction-type.entity';
import { TransactionJournal } from './entities/transaction-journal.entity'; import { TransactionJournal } from './entities/transaction-journal.entity';
import { Transactions } from './entities/transactions.entity'; import { Transactions } from './entities/transactions.entity';
import { CoaService } from './coa.service'; import { CoaService } from './coa.service';
@ -13,17 +12,12 @@ import { UsersModule } from 'src/users/users.module';
@Module({ @Module({
imports: [ imports: [
TypeOrmModule.forFeature([ TypeOrmModule.forFeature([COA, TransactionJournal, Transactions]),
TransactionType,
COA,
TransactionJournal,
Transactions,
]),
ProductModule, ProductModule,
forwardRef(() => UsersModule), forwardRef(() => UsersModule),
], ],
controllers: [TransactionController, PpobCallbackController], controllers: [TransactionController, PpobCallbackController],
providers: [TransactionService, CoaService], providers: [TransactionService, CoaService],
exports:[CoaService] exports: [CoaService],
}) })
export class TransactionModule {} export class TransactionModule {}

View File

@ -5,7 +5,6 @@ import { InjectRepository } from '@nestjs/typeorm';
import { Transactions } from './entities/transactions.entity'; import { Transactions } from './entities/transactions.entity';
import { Connection, EntityManager, Repository } from 'typeorm'; import { Connection, EntityManager, Repository } from 'typeorm';
import { COA } from './entities/coa.entity'; import { COA } from './entities/coa.entity';
import { TransactionType } from './entities/transaction-type.entity';
import { TransactionJournal } from './entities/transaction-journal.entity'; import { TransactionJournal } from './entities/transaction-journal.entity';
import { CoaService } from './coa.service'; import { CoaService } from './coa.service';
import * as uuid from 'uuid'; import * as uuid from 'uuid';
@ -22,6 +21,7 @@ import * as irsService from '../helper/irs-service';
import { CreateJournalDto } from './dto/create-journal.dto'; import { CreateJournalDto } from './dto/create-journal.dto';
import { UsersService } from 'src/users/users.service'; import { UsersService } from 'src/users/users.service';
import { AddSaldoSupplier } from './dto/add-saldo-supplier.dto'; import { AddSaldoSupplier } from './dto/add-saldo-supplier.dto';
import { SupplierService } from '../users/supplier/supplier.service';
interface JournalEntry { interface JournalEntry {
coa_id: string; coa_id: string;
@ -34,8 +34,6 @@ export class TransactionService {
constructor( constructor(
@InjectRepository(Transactions) @InjectRepository(Transactions)
private transactionRepository: Repository<Transactions>, private transactionRepository: Repository<Transactions>,
@InjectRepository(TransactionType)
private transactionTypeRepository: Repository<TransactionType>,
@InjectRepository(TransactionJournal) @InjectRepository(TransactionJournal)
private transactionJournalRepository: Repository<TransactionJournal>, private transactionJournalRepository: Repository<TransactionJournal>,
@InjectRepository(COA) @InjectRepository(COA)
@ -43,17 +41,29 @@ export class TransactionService {
private coaService: CoaService, private coaService: CoaService,
private productService: ProductService, private productService: ProductService,
private userService: UsersService, private userService: UsersService,
private supplierService: SupplierService,
private connection: Connection, private connection: Connection,
) {} ) {}
async addIRSWallet(addSaldoSupplier: AddSaldoSupplier, currentUser: any) { async addPartnerSaldo(addSaldoSupplier: AddSaldoSupplier, currentUser: any) {
const supplier = await this.supplierService.findByCode(
addSaldoSupplier.supplier,
);
// GET COA // GET COA
const coaBank = await this.coaService.findByName( const coaBank = await this.coaService.findByName(
`${coaType[coaType.BANK]}-SYSTEM`, `${coaType[coaType.BANK]}-SYSTEM`,
); );
const coaInventory = await this.coaService.findByName( const coaInventory = await this.coaService.findByName(
`${coaType[coaType.INVENTORY]}-${addSaldoSupplier.supplier}`, `${coaType[coaType.INVENTORY]}-${supplier.code}`,
);
const coaBudget = await this.coaService.findByName(
`${coaType[coaType.BUDGET]}-${supplier.code}`,
);
const coaContraBudget = await this.coaService.findByName(
`${coaType[coaType.CONTRA_BUDGET]}-${supplier.code}`,
); );
//GET USER //GET USER
@ -81,10 +91,18 @@ export class TransactionService {
journals: [ journals: [
{ {
coa_id: coaBank.id, coa_id: coaBank.id,
debit: transactionData.amount, credit: transactionData.amount,
}, },
{ {
coa_id: coaInventory.id, coa_id: coaInventory.id,
debit: transactionData.amount,
},
{
coa_id: coaBudget.id,
debit: transactionData.amount,
},
{
coa_id: coaContraBudget.id,
credit: transactionData.amount, credit: transactionData.amount,
}, },
], ],
@ -98,6 +116,25 @@ export class TransactionService {
distributeTransactionDto: DistributeTransactionDto, distributeTransactionDto: DistributeTransactionDto,
currentUser: any, currentUser: any,
) { ) {
//GET USER
const userData = await this.userService.findByUsername(
currentUser.username,
);
if (userData.roles.name != 'Admin') {
throw new HttpException(
{
statusCode: HttpStatus.NOT_ACCEPTABLE,
error: 'Roles Not Admin',
},
HttpStatus.NOT_ACCEPTABLE,
);
}
//GET Supplier
const supplier = await this.supplierService.findByCode(
distributeTransactionDto.supplier,
);
// GET COA // GET COA
const coaAR = await this.coaService.findByUser( const coaAR = await this.coaService.findByUser(
distributeTransactionDto.destination, distributeTransactionDto.destination,
@ -107,10 +144,12 @@ export class TransactionService {
distributeTransactionDto.destination, distributeTransactionDto.destination,
coaType.WALLET, coaType.WALLET,
); );
const coaBudget = await this.coaService.findByName(
`${coaType[coaType.BUDGET]}-${supplier.code}`,
);
//GET USER const coaContraBudget = await this.coaService.findByName(
const userData = await this.userService.findByUsername( `${coaType[coaType.CONTRA_BUDGET]}-${supplier.code}`,
currentUser.username,
); );
await this.connection.transaction(async (manager) => { await this.connection.transaction(async (manager) => {
@ -139,6 +178,14 @@ export class TransactionService {
coa_id: coaWallet.id, coa_id: coaWallet.id,
credit: transactionData.amount, credit: transactionData.amount,
}, },
{
coa_id: coaBudget.id,
credit: transactionData.amount,
},
{
coa_id: coaContraBudget.id,
debit: transactionData.amount,
},
], ],
}); });
}); });
@ -394,9 +441,9 @@ export class TransactionService {
? balanceType.DEBIT ? balanceType.DEBIT
: balanceType.CREDIT; : balanceType.CREDIT;
journalEntry.amount = journal.debit ? journal.debit : journal.credit; journalEntry.amount = journal.debit ? journal.debit : journal.credit;
journalEntry.transaction = transaction; journalEntry.transaction_head = transaction;
return this.transactionJournalRepository.save(journalEntry); return createJournalDto.transactionalEntityManager.save(journalEntry);
}), }),
); );
@ -432,15 +479,12 @@ export class TransactionService {
); );
let balance = new Decimal(coa.amount); let balance = new Decimal(coa.amount);
if (coa.balanceType == balanceType.DEBIT) {
if (coa.balanceType === balanceType.DEBIT) {
balance = balance.plus(debitSum.minus(creditSum)); balance = balance.plus(debitSum.minus(creditSum));
} else if (coa.balanceType === balanceType.CREDIT) { } else if (coa.balanceType == balanceType.CREDIT) {
balance = balance.plus(creditSum.minus(debitSum)); balance = balance.plus(creditSum.minus(debitSum));
} }
const diff = balance.minus(new Decimal(coa.amount)); const diff = balance.minus(new Decimal(coa.amount));
return createJournalDto.transactionalEntityManager return createJournalDto.transactionalEntityManager
.createQueryBuilder() .createQueryBuilder()
.update(COA) .update(COA)

View File

@ -0,0 +1,18 @@
import { IsNotEmpty } from 'class-validator';
export class CreatePartnerDto {
@IsNotEmpty()
name: string;
@IsNotEmpty()
address: string;
@IsNotEmpty()
owner: string;
@IsNotEmpty()
npwp: string;
@IsNotEmpty()
password_account: string;
}

View File

@ -0,0 +1,9 @@
import { IsNotEmpty } from 'class-validator';
export class CreateSupplierDto {
@IsNotEmpty()
name: string;
@IsNotEmpty()
code: string;
}

View File

@ -1,4 +1,5 @@
import { IsNotEmpty, IsOptional, IsUUID, ValidateIf } from 'class-validator'; import { IsNotEmpty, IsOptional, IsUUID, ValidateIf } from 'class-validator';
import { Partner } from '../entities/partner.entity';
export class CreateUserDto { export class CreateUserDto {
@IsNotEmpty() @IsNotEmpty()
@ -13,6 +14,7 @@ export class CreateUserDto {
@IsNotEmpty() @IsNotEmpty()
superior: boolean; superior: boolean;
partner: Partner;
// @ValidateIf((o) => { // @ValidateIf((o) => {
// return !!o.superior; // return !!o.superior;
// }) // })

View File

@ -0,0 +1,22 @@
import { Roles } from 'src/configurable/entities/roles.entity';
import { Entity, Column, PrimaryGeneratedColumn, ManyToOne } from 'typeorm';
import { BaseModel } from '../../config/basemodel.entity';
import { hashPassword } from '../../helper/hash_password';
@Entity()
export class Partner extends BaseModel {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column()
name: string;
@Column()
npwp: string;
@Column()
address: string;
@Column({ default: true })
status: boolean;
}

View File

@ -0,0 +1,19 @@
import { Roles } from 'src/configurable/entities/roles.entity';
import { Entity, Column, PrimaryGeneratedColumn, ManyToOne } from 'typeorm';
import { BaseModel } from '../../config/basemodel.entity';
import { hashPassword } from '../../helper/hash_password';
@Entity()
export class Supplier extends BaseModel {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column()
name: string;
@Column()
code: string;
@Column()
status: boolean;
}

View File

@ -2,6 +2,7 @@ import { Roles } from 'src/configurable/entities/roles.entity';
import { Entity, Column, PrimaryGeneratedColumn, ManyToOne } from 'typeorm'; import { Entity, Column, PrimaryGeneratedColumn, ManyToOne } from 'typeorm';
import { BaseModel } from '../../config/basemodel.entity'; import { BaseModel } from '../../config/basemodel.entity';
import { hashPassword } from '../../helper/hash_password'; import { hashPassword } from '../../helper/hash_password';
import { Partner } from './partner.entity';
@Entity() @Entity()
export class User extends BaseModel { export class User extends BaseModel {
@ -39,4 +40,14 @@ export class User extends BaseModel {
}, },
) )
roles: Roles; roles: Roles;
@ManyToOne(
() => {
return Partner;
},
(partner) => {
return partner.id;
},
)
partner: Partner;
} }

View File

@ -1,18 +0,0 @@
import {
Entity,
Column,
PrimaryGeneratedColumn,
UpdateDateColumn,
DeleteDateColumn,
VersionColumn,
CreateDateColumn,
} from 'typeorm';
@Entity()
export class User {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column()
firstName: string;
}

View File

@ -0,0 +1,22 @@
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
import { accountType } from '../../helper/enum-list';
@Entity()
export class UserDetail {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column()
name: string;
@Column()
first_name: string;
@Column()
phone_number: string;
@Column({
nullable: true,
})
type: accountType;
}

View File

@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { PartnerService } from './partner.service';
describe('PartnerService', () => {
let service: PartnerService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [PartnerService],
}).compile();
service = module.get<PartnerService>(PartnerService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});

View File

@ -0,0 +1,79 @@
import {
forwardRef,
HttpException,
HttpStatus,
Inject,
Injectable,
} from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Connection, EntityNotFoundError, Repository } from 'typeorm';
import { CoaService } from '../../transaction/coa.service';
import { CreatePartnerDto } from '../dto/create-partner.dto';
import { Partner } from '../entities/partner.entity';
import * as uuid from 'uuid';
import { UsersService } from '../users.service';
import { CreateUserDto } from '../dto/create-user.dto';
@Injectable()
export class PartnerService {
constructor(
@InjectRepository(Partner)
private partnerRepository: Repository<Partner>,
@Inject(
forwardRef(() => {
return CoaService;
}),
)
private coaService: CoaService,
private userService: UsersService,
private connection: Connection,
) {}
async create(createPartnerDto: CreatePartnerDto, currentUser: any) {
const check = await this.partnerRepository.findOne({
npwp: createPartnerDto.npwp,
});
if (check) {
throw new HttpException(
{
statusCode: HttpStatus.NOT_ACCEPTABLE,
error: 'N Already Exist',
},
HttpStatus.NOT_FOUND,
);
}
const partnerData = new Partner();
partnerData.id = uuid.v4();
partnerData.name = createPartnerDto.name;
partnerData.npwp = createPartnerDto.npwp;
partnerData.address = createPartnerDto.address;
partnerData.status = true;
await this.connection.transaction(async (manager) => {
const result = await manager.insert(Partner, partnerData);
});
const dataUser = new CreateUserDto();
dataUser.username = `admin_${partnerData.name}`;
dataUser.roleId = '21dceea2-416e-4b55-b74c-12605e1f8d1b';
dataUser.superior = false;
dataUser.partner = partnerData;
dataUser.password = createPartnerDto.password_account;
await this.userService.create(dataUser, currentUser);
return partnerData;
}
findAllPartner(page) {
return this.partnerRepository.findAndCount({
skip: page * 10,
take: 10,
order: {
version: 'DESC',
},
});
}
}

View File

@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { SupplierService } from './supplier.service';
describe('PartnerService', () => {
let service: SupplierService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [SupplierService],
}).compile();
service = module.get<SupplierService>(SupplierService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});

View File

@ -0,0 +1,116 @@
import {
forwardRef,
HttpException,
HttpStatus,
Inject,
Injectable,
} from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Connection, EntityNotFoundError, Repository } from 'typeorm';
import { Supplier } from '../entities/supplier.entity';
import { InputCoaDto } from '../../transaction/dto/input-coa.dto';
import { balanceType, coaType } from '../../helper/enum-list';
import { CreateSupplierDto } from '../dto/create-supplier.dto';
import { CoaService } from '../../transaction/coa.service';
import * as uuid from 'uuid';
@Injectable()
export class SupplierService {
constructor(
@InjectRepository(Supplier)
private supplierRepository: Repository<Supplier>,
@Inject(
forwardRef(() => {
return CoaService;
}),
)
private coaService: CoaService,
private connection: Connection,
) {}
async create(createSupplierDto: CreateSupplierDto) {
const check = await this.supplierRepository.findOne({
code: createSupplierDto.code,
});
if (check) {
throw new HttpException(
{
statusCode: HttpStatus.NOT_ACCEPTABLE,
error: 'Supplier Already Exist',
},
HttpStatus.NOT_FOUND,
);
}
const supplierData = new Supplier();
supplierData.id = uuid.v4();
supplierData.name = createSupplierDto.name;
supplierData.code = createSupplierDto.code;
supplierData.status = true;
await this.connection.transaction(async (manager) => {
const result = await manager.insert(Supplier, supplierData);
const dataCoaInventory = new InputCoaDto();
dataCoaInventory.supplier = supplierData;
dataCoaInventory.balanceType = balanceType.DEBIT;
dataCoaInventory.type = coaType.INVENTORY;
dataCoaInventory.coaEntityManager = manager;
await this.coaService.create(dataCoaInventory);
const dataCoaCostOfSales = new InputCoaDto();
dataCoaCostOfSales.supplier = supplierData;
dataCoaCostOfSales.balanceType = balanceType.DEBIT;
dataCoaCostOfSales.type = coaType.COST_OF_SALES;
dataCoaCostOfSales.coaEntityManager = manager;
await this.coaService.create(dataCoaCostOfSales);
const dataCoaBudget = new InputCoaDto();
dataCoaBudget.supplier = supplierData;
dataCoaBudget.balanceType = balanceType.DEBIT;
dataCoaBudget.type = coaType.BUDGET;
dataCoaBudget.coaEntityManager = manager;
await this.coaService.create(dataCoaBudget);
const dataCoaContraBudget = new InputCoaDto();
dataCoaContraBudget.supplier = supplierData;
dataCoaContraBudget.balanceType = balanceType.CREDIT;
dataCoaContraBudget.type = coaType.CONTRA_BUDGET;
dataCoaContraBudget.coaEntityManager = manager;
await this.coaService.create(dataCoaContraBudget);
});
return supplierData;
}
findAllSupplier(page) {
return this.supplierRepository.findAndCount({
skip: page * 10,
take: 10,
order: {
version: 'DESC',
},
});
}
async findByCode(code: string) {
try {
return await this.supplierRepository.findOneOrFail({
code: code,
});
} catch (e) {
if (e instanceof EntityNotFoundError) {
throw new HttpException(
{
statusCode: HttpStatus.NOT_FOUND,
error: 'Data not found',
},
HttpStatus.NOT_FOUND,
);
} else {
throw e;
}
}
}
}

View File

@ -15,13 +15,21 @@ import { UsersService } from './users.service';
import { CreateUserDto } from './dto/create-user.dto'; import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto'; import { UpdateUserDto } from './dto/update-user.dto';
import { Public } from '../auth/public.decorator'; import { Public } from '../auth/public.decorator';
import { CreateSupplierDto } from './dto/create-supplier.dto';
import { SupplierService } from './supplier/supplier.service';
import { PartnerService } from './partner/partner.service';
import { CreatePartnerDto } from './dto/create-partner.dto';
@Controller({ @Controller({
path: 'users', path: 'users',
version: '1', version: '1',
}) })
export class UsersController { export class UsersController {
constructor(private readonly usersService: UsersService) {} constructor(
private readonly usersService: UsersService,
private readonly supplierService: SupplierService,
private readonly partnerService: PartnerService,
) {}
@Post() @Post()
async create(@Request() req, @Body() createUserDto: CreateUserDto) { async create(@Request() req, @Body() createUserDto: CreateUserDto) {
@ -32,10 +40,58 @@ export class UsersController {
}; };
} }
@Public() @Post('supplier')
async createSupplier(@Body() createPartnerDto: CreateSupplierDto) {
return {
data: await this.supplierService.create(createPartnerDto),
statusCode: HttpStatus.CREATED,
message: 'success',
};
}
@Post('partner')
async createPartner(
@Request() req,
@Body() createPartnerDto: CreatePartnerDto,
) {
return {
data: await this.partnerService.create(createPartnerDto, req.user),
statusCode: HttpStatus.CREATED,
message: 'success',
};
}
@Get() @Get()
async findAll(@Query('page') page: number) { async findAll(@Request() req, @Query('page') page: number) {
const [data, count] = await this.usersService.findAll(page); const [data, count] = await this.usersService.findAll(
page,
req.user.userId,
);
return {
data,
count,
statusCode: HttpStatus.OK,
message: 'success',
};
}
@Public()
@Get('supplier')
async findAllSupplier(@Query('page') page: number) {
const [data, count] = await this.supplierService.findAllSupplier(page);
return {
data,
count,
statusCode: HttpStatus.OK,
message: 'success',
};
}
@Get('partner')
async findAllPartner(@Query('page') page: number) {
const [data, count] = await this.partnerService.findAllPartner(page);
return { return {
data, data,
@ -51,6 +107,7 @@ export class UsersController {
req.user.userId, req.user.userId,
page, page,
); );
return { return {
data, data,
count, count,
@ -65,6 +122,7 @@ export class UsersController {
@Query('page') page: number, @Query('page') page: number,
) { ) {
const [data, count] = await this.usersService.findByRoles(id, page); const [data, count] = await this.usersService.findByRoles(id, page);
return { return {
data, data,
count, count,

View File

@ -5,11 +5,19 @@ import { UsersController } from './users.controller';
import { User } from './entities/user.entity'; import { User } from './entities/user.entity';
import { TransactionModule } from 'src/transaction/transaction.module'; import { TransactionModule } from 'src/transaction/transaction.module';
import { ConfigurableModule } from 'src/configurable/configurable.module'; import { ConfigurableModule } from 'src/configurable/configurable.module';
import { SupplierService } from './supplier/supplier.service';
import { Supplier } from './entities/supplier.entity';
import { Partner } from './entities/partner.entity';
import { PartnerService } from './partner/partner.service';
@Module({ @Module({
imports: [TypeOrmModule.forFeature([User]), forwardRef(() => TransactionModule), ConfigurableModule], imports: [
TypeOrmModule.forFeature([User, Supplier, Partner]),
forwardRef(() => TransactionModule),
ConfigurableModule,
],
controllers: [UsersController], controllers: [UsersController],
providers: [UsersService], providers: [UsersService, SupplierService, PartnerService],
exports: [UsersService], exports: [UsersService, SupplierService],
}) })
export class UsersModule {} export class UsersModule {}

View File

@ -7,7 +7,13 @@ import {
} from '@nestjs/common'; } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto'; import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto'; import { UpdateUserDto } from './dto/update-user.dto';
import { Connection, EntityNotFoundError, Repository } from 'typeorm'; import {
Connection,
EntityNotFoundError,
Equal,
Not,
Repository,
} from 'typeorm';
import { User } from './entities/user.entity'; import { User } from './entities/user.entity';
import { InjectRepository } from '@nestjs/typeorm'; import { InjectRepository } from '@nestjs/typeorm';
import { randomStringGenerator } from '@nestjs/common/utils/random-string-generator.util'; import { randomStringGenerator } from '@nestjs/common/utils/random-string-generator.util';
@ -59,53 +65,56 @@ export class UsersService {
userData.username = createUserDto.username; userData.username = createUserDto.username;
userData.password = await hashPassword(createUserDto.password, salt); userData.password = await hashPassword(createUserDto.password, salt);
userData.salt = salt; userData.salt = salt;
userData.superior = superior; if (createUserDto.superior) {
userData.superior = superior;
} else {
userData.superior = null;
userData.partner = createUserDto.partner;
}
userData.roles = roles; userData.roles = roles;
await this.connection.transaction(async (manager) => { await this.connection.transaction(async (manager) => {
const result = await manager.insert(User, userData); const result = await manager.insert(User, userData);
const dataCoaWallet = new InputCoaDto(); const dataCoaWallet = new InputCoaDto();
dataCoaWallet.user = userData; dataCoaWallet.user = userData;
dataCoaWallet.balanceType = balanceType.CREDIT; dataCoaWallet.balanceType = balanceType.CREDIT;
dataCoaWallet.type = coaType.WALLET; dataCoaWallet.type = coaType.WALLET;
dataCoaWallet.coaEntityManager = manager; dataCoaWallet.coaEntityManager = manager;
await this.coaService.create(dataCoaWallet);
if (createUserDto.superior) { if (createUserDto.superior) {
const dataCoaAP = new InputCoaDto(); const dataCoaAP = new InputCoaDto();
dataCoaAP.user = userData; dataCoaAP.user = userData;
dataCoaAP.balanceType = balanceType.CREDIT; dataCoaAP.balanceType = balanceType.CREDIT;
dataCoaAP.relatedUserId = superior.id; dataCoaAP.relatedUserId = superior.id;
dataCoaAP.type = coaType.ACCOUNT_PAYABLE; dataCoaAP.type = coaType.ACCOUNT_PAYABLE;
dataCoaAP.coaEntityManager = manager; dataCoaAP.coaEntityManager = manager;
await this.coaService.create(dataCoaAP);
const dataCoaAR = new InputCoaDto(); const dataCoaAR = new InputCoaDto();
dataCoaAR.user = userData; dataCoaAR.user = userData;
dataCoaAR.balanceType = balanceType.DEBIT; dataCoaAR.balanceType = balanceType.DEBIT;
dataCoaAR.relatedUserId = superior.id; dataCoaAR.relatedUserId = superior.id;
dataCoaAR.type = coaType.ACCOUNT_RECEIVABLE; dataCoaAR.type = coaType.ACCOUNT_RECEIVABLE;
dataCoaAR.coaEntityManager = manager; dataCoaAR.coaEntityManager = manager;
await this.coaService.create(dataCoaAP);
await this.coaService.create(dataCoaAR); await this.coaService.create(dataCoaAR);
} }
await this.coaService.create(dataCoaWallet);
}); });
return userData; return userData;
} }
findAll(page: number) { findAll(page: number, id: string) {
return this.usersRepository.findAndCount({ return this.usersRepository.findAndCount({
skip: page * 10, skip: page * 10,
take: 10, take: 10,
order: { order: {
version: 'DESC', version: 'DESC',
}, },
where: {
id: Not(Equal(id)),
},
}); });
} }
@ -157,7 +166,10 @@ export class UsersService {
async findByUsername(username: string) { async findByUsername(username: string) {
try { try {
return await this.usersRepository.findOneOrFail({ return await this.usersRepository.findOneOrFail({
username: username, where: {
username: username,
},
relations: ['roles'],
}); });
} catch (e) { } catch (e) {
if (e instanceof EntityNotFoundError) { if (e instanceof EntityNotFoundError) {