Compare commits

...

95 Commits

Author SHA1 Message Date
irfan 48a48e6e7a Merge pull request 'development' (#100) from development into production
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #100
2024-09-21 16:08:58 +00:00
shancheas 22f4e732db fix: transaction NaN without discount
continuous-integration/drone/push Build is passing Details
2024-09-21 23:04:59 +07:00
shancheas 34ae5964c4 Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into development
continuous-integration/drone/push Build is passing Details
2024-09-21 07:24:34 +07:00
shancheas f2fef65f20 fix: change total price to net price 2024-09-21 07:24:16 +07:00
firmanr 039531de3b Merge pull request 'feat: move tipe item' (#99) from feat/adjustment-report into development
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #99
2024-09-20 12:01:57 +00:00
Firman Ramdhani 0b8bb72392 feat: move tipe item
continuous-integration/drone/push Build is passing Details
2024-09-20 19:01:18 +07:00
firmanr 256c8f38bd Merge pull request 'feat: update report' (#98) from feat/adjustment-report into development
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #98
2024-09-20 11:36:16 +00:00
Firman Ramdhani 109898b076 Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into feat/adjustment-report
continuous-integration/drone/push Build is passing Details
2024-09-20 18:34:58 +07:00
shancheas b2be2e0160 Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into development
continuous-integration/drone/push Build is passing Details
2024-09-20 18:33:11 +07:00
shancheas b4266d5d68 fix: add discount to calculator 2024-09-20 18:32:52 +07:00
Firman Ramdhani f23a9f3510 feat: update report
continuous-integration/drone/push Build is passing Details
2024-09-20 18:32:17 +07:00
firmanr 91370940d7 Merge pull request 'feat: fix filter report' (#97) from feat/adjustment-report into development
continuous-integration/drone/push Build is passing Details
Reviewed-on: #97
2024-09-20 10:51:25 +00:00
Firman Ramdhani c15b4d8079 feat: fix filter report
continuous-integration/drone/push Build is passing Details
2024-09-20 17:25:28 +07:00
shancheas b16edb73e3 fix: report wrong non bundling profit share key
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-09-20 13:01:38 +07:00
firmanr ea58096287 Merge pull request 'feat/adjustment-report' (#96) from feat/adjustment-report into development
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #96
2024-09-20 04:50:52 +00:00
Firman Ramdhani 1dfcaf7b15 feat(SPG-969): feat set default payment_date_bank
continuous-integration/drone/push Build is passing Details
2024-09-20 11:50:34 +07:00
Firman Ramdhani 8b58598955 feat(SPG-969): feat set default payment_date_bank
continuous-integration/drone/push Build is passing Details
2024-09-20 11:49:58 +07:00
firmanr 5eb50c952f Merge pull request 'feat/adjustment-report' (#95) from feat/adjustment-report into development
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #95
2024-09-20 04:33:19 +00:00
Firman Ramdhani aaa0ca6f76 feat: fix report bug and create report tax
continuous-integration/drone/push Build is passing Details
2024-09-20 11:32:48 +07:00
irfan 3de7bfbbe5 Merge pull request 'fix/price-calculator' (#94) from fix/price-calculator into development
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #94
2024-09-20 04:07:24 +00:00
shancheas 60c03fefa0 Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into fix/price-calculator
continuous-integration/drone/push Build is passing Details
2024-09-20 11:06:31 +07:00
shancheas b34d54e7d0 fix: item bundling replace when edit 2024-09-20 11:06:09 +07:00
Firman Ramdhani 3fd97b8879 Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into feat/adjustment-report
continuous-integration/drone/push Build is passing Details
2024-09-20 09:46:25 +07:00
irfan 93c822f34e Merge pull request 'fix/price-calculator' (#93) from fix/price-calculator into development
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #93
2024-09-19 12:34:03 +00:00
shancheas e09c76309e fix: formula calculation
continuous-integration/drone/push Build is passing Details
2024-09-19 19:33:28 +07:00
Firman Ramdhani 43deb04d92 feat(SPG-966): fix report income
continuous-integration/drone/push Build is passing Details
2024-09-19 18:22:19 +07:00
shancheas 23043fb7f9 feat: change logic to save formula 2024-09-19 17:52:50 +07:00
Firman Ramdhani 1d377b574c feat(SPG-966): fix report income
continuous-integration/drone/push Build is passing Details
2024-09-19 17:50:11 +07:00
Firman Ramdhani 7d9f619858 feat(SPG-966): fix report income 2024-09-19 17:49:35 +07:00
shancheas c06a2a0a2b Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into fix/price-calculator 2024-09-19 14:07:37 +07:00
shancheas cc71814648 fix: bulk transaction action
continuous-integration/drone/push Build is passing Details
2024-09-18 17:25:07 +07:00
irfan 004dfc9de5 Merge pull request 'feat/adjustment-report' (#92) from feat/adjustment-report into development
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #92
2024-09-18 10:14:59 +00:00
Firman Ramdhani 09d6dbaab2 feat: remove console on auth
continuous-integration/drone/push Build is passing Details
2024-09-18 16:30:23 +07:00
Firman Ramdhani c76594d767 Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into feat/adjustment-report
continuous-integration/drone/push Build is passing Details
2024-09-18 16:25:39 +07:00
Firman Ramdhani f4cf5178b8 feat: change auth concept
continuous-integration/drone/push Build is passing Details
2024-09-18 16:25:29 +07:00
shancheas ffbbf6e140 Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into development
continuous-integration/drone/push Build is passing Details
2024-09-18 13:55:57 +07:00
shancheas 614a9346fb feat: price calculator 2024-09-18 13:55:47 +07:00
irfan f7c49d27d5 Merge pull request 'fix/income-report' (#91) from fix/income-report into development
continuous-integration/drone/push Build was killed Details
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #91
2024-09-13 10:39:52 +00:00
irfan 2ee96a617f fix: income item breakdown report
continuous-integration/drone/push Build was killed Details
2024-09-13 10:39:04 +00:00
irfan 10049abc55 fix: income item report
continuous-integration/drone/push Build is passing Details
2024-09-13 10:38:32 +00:00
irfan 01fbedab77 fix: income report
continuous-integration/drone/push Build is passing Details
2024-09-13 10:37:15 +00:00
irfan b2659def9a ci: rollback to yarn, NPM is s*ck
continuous-integration/drone/push Build is passing Details
2024-09-13 03:55:52 +00:00
firmanr d597734467 Merge pull request 'feat: exclude privilege logout' (#90) from feat/adjustment-report into development
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is failing Details
Reviewed-on: #90
2024-09-13 03:49:40 +00:00
Firman Ramdhani 27a0c56af7 feat: exclude privilege logout
continuous-integration/drone/push Build is passing Details
2024-09-13 10:48:45 +07:00
irfan 50ac2d97a4 ci: update Docker file use NPM instead of Yarn
continuous-integration/drone/push Build is passing Details
2024-09-13 03:27:14 +00:00
firmanr d788a9f1a1 Merge pull request 'feat(SPG-953): penyesuaian API Create dan Update pengguna baru dengan menambahkan opsi admin antrian' (#89) from feat/adjustment-report into development
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #89
2024-09-12 12:19:09 +00:00
Firman Ramdhani c897e4fcde feat(SPG-885): add validation login admin queue
continuous-integration/drone/push Build is passing Details
2024-09-12 19:17:46 +07:00
Firman Ramdhani 14dd2880bc feat(SPG-885): add api get item queue
continuous-integration/drone/push Build is passing Details
2024-09-12 17:54:48 +07:00
Firman Ramdhani 3e920755bd feat: create feature log user login and create auth admin queue
continuous-integration/drone/push Build is passing Details
2024-09-12 17:16:56 +07:00
Firman Ramdhani 88b4c66139 feat: adjustment column dpp and total pajak at income item master
continuous-integration/drone/push Build is passing Details
2024-09-11 18:15:16 +07:00
Firman Ramdhani 52c82a9a41 feat(SPG-953): penyesuaian API Create dan Update pengguna baru dengan menambahkan opsi admin antrian
continuous-integration/drone/push Build is passing Details
2024-09-11 16:43:03 +07:00
shancheas 19494b3328 Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into development 2024-09-11 16:12:36 +07:00
shancheas e1f2cdfa4d wip: calculate share item 2024-09-11 16:12:22 +07:00
firmanr 918055beb9 Merge pull request 'feat: add enum queue admin' (#88) from feat/adjustment-report into development
continuous-integration/drone/push Build is passing Details
Reviewed-on: #88
2024-09-11 07:57:35 +00:00
Firman Ramdhani 283b783007 feat: add enum queue admin
continuous-integration/drone/push Build is passing Details
2024-09-11 14:56:55 +07:00
firmanr a2be2bb331 Merge pull request 'feat/adjustment-report' (#87) from feat/adjustment-report into development
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #87
2024-09-11 05:44:29 +00:00
Firman Ramdhani d708ef9eee feat: add column pos name
continuous-integration/drone/push Build is passing Details
2024-09-11 12:42:09 +07:00
Firman Ramdhani 9709c4719b feat: add column pos name
continuous-integration/drone/push Build is passing Details
2024-09-11 12:38:16 +07:00
firmanr d2db62339f Merge pull request 'feat: penyesuaian error validasi create items' (#86) from feat/adjustment-report into development
continuous-integration/drone/push Build is passing Details
Reviewed-on: #86
2024-09-11 04:05:56 +00:00
Firman Ramdhani 07d1cc78e2 feat: penyesuaian error validasi create items
continuous-integration/drone/push Build is passing Details
2024-09-11 11:05:36 +07:00
firmanr 8f430574ed Merge pull request 'feat: rename label button email template midtrans' (#85) from feat/adjustment-report into development
continuous-integration/drone/push Build is passing Details
Reviewed-on: #85
2024-09-11 03:58:36 +00:00
Firman Ramdhani f7198010d3 feat: rename label button email template midtrans
continuous-integration/drone/push Build is passing Details
2024-09-11 10:57:25 +07:00
firmanr a1641504f1 Merge pull request 'feat/adjustment-report' (#84) from feat/adjustment-report into development
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #84
2024-09-11 03:52:02 +00:00
Firman Ramdhani 6c5019f814 feat: adjustment dpp and total pajak di report icom per transaction
continuous-integration/drone/push Build is passing Details
2024-09-11 10:51:10 +07:00
Firman Ramdhani ff0ef28783 feat: create report tenant
continuous-integration/drone/push Build is passing Details
2024-09-11 10:40:44 +07:00
firmanr 40aafaf571 Merge pull request 'feat: ignore sync delete data from POS data' (#83) from feat/adjustment-report into development
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #83
2024-09-10 10:26:19 +00:00
Firman Ramdhani 6fbb2e33b2 feat: ignore sync delete data from POS data
continuous-integration/drone/push Build is passing Details
2024-09-10 17:25:59 +07:00
firmanr b20385dacc Merge pull request 'feat/adjustment-report' (#82) from feat/adjustment-report into development
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is failing Details
Reviewed-on: #82
2024-09-10 10:17:42 +00:00
Firman Ramdhani 6e5b19380b feat(SPG-935): add column payment_date_bank
continuous-integration/drone/push Build is passing Details
2024-09-10 17:15:52 +07:00
Firman Ramdhani ab9ec4ac0e feat(SPG-935): add column payment_date_bank
continuous-integration/drone/push Build is passing Details
2024-09-10 17:11:20 +07:00
firmanr 0457fc9e1d Merge pull request 'feat/adjustment-report' (#81) from feat/adjustment-report into development
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #81
2024-09-10 04:49:35 +00:00
Firman Ramdhani 3658ae4cdf feat: adjustment filter pos no
continuous-integration/drone/push Build is passing Details
2024-09-10 11:48:44 +07:00
Firman Ramdhani d1b20e6b96 feat: create report tenant
continuous-integration/drone/push Build is passing Details
2024-09-10 11:38:46 +07:00
Firman Ramdhani f4ecbf0e66 feat: add net pedapatan di report rekonsiliasi
continuous-integration/drone/push Build is passing Details
2024-09-10 10:55:13 +07:00
Firman Ramdhani 7da22277f1 feat: remove MDR column on income
continuous-integration/drone/push Build is passing Details
2024-09-10 10:37:48 +07:00
Firman Ramdhani bf73cb6b43 feat: adjustment to measure at column income report
continuous-integration/drone/push Build is passing Details
2024-09-10 10:29:31 +07:00
Firman Ramdhani 6fb582204a Merge branch 'feat/fix-couch-transaction' of ssh://git.eigen.co.id:2222/eigen/pos-be into feat/adjustment-report
continuous-integration/drone/push Build is passing Details
2024-09-09 14:30:53 +07:00
Firman Ramdhani d283caa898 feat: rename label header
continuous-integration/drone/push Build is passing Details
2024-09-09 14:26:49 +07:00
Firman Ramdhani 1320492bf1 Merge branch 'production' of ssh://git.eigen.co.id:2222/eigen/pos-be into feat/adjustment-report
continuous-integration/drone/push Build is passing Details
2024-09-09 11:26:48 +07:00
irfan a6b1e5f49f Update Dockerfile
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2024-09-06 11:05:32 +00:00
firmanr ac3ee266b9 Merge pull request 'feat: open guard cancel recap recon and add new logic for recap recon cancel handler and change logic recap handler' (#80) from feat/reconciliation into development
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
Reviewed-on: #80
2024-09-06 10:58:46 +00:00
Firman Ramdhani 7fb2995f38 feat: update query report income and merge with development branch
continuous-integration/drone/push Build is passing Details
2024-09-04 18:26:40 +07:00
Firman Ramdhani 07e7b86cd4 feat: update query report income and merge with development branch
continuous-integration/drone/push Build is passing Details
2024-09-04 18:21:08 +07:00
Firman Ramdhani db57b1973e Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into feat/fix-couch-transaction 2024-09-04 18:20:13 +07:00
Firman Ramdhani 92d60d4496 feat: update query report income
continuous-integration/drone/push Build is passing Details
2024-09-04 18:19:42 +07:00
firmanr b716c75a2c Merge pull request 'feat/fix-couch-transaction' (#78) from feat/fix-couch-transaction into development
continuous-integration/drone/push Build is passing Details
Reviewed-on: #78
2024-09-04 10:26:33 +00:00
Firman Ramdhani 45306dde57 feat: update import couch module
continuous-integration/drone/push Build is passing Details
2024-09-04 15:22:42 +07:00
shancheas 1a2a37d185 chore: add label to APM 2024-09-03 18:44:04 +07:00
shancheas 665eacd39f feat: add reject QR gate
continuous-integration/drone/tag Build is passing Details
2024-09-03 10:23:02 +07:00
shancheas 9d98003a2d feat: add detail formula api getter
continuous-integration/drone/tag Build is passing Details
2024-09-03 09:45:23 +07:00
shancheas 45c4bde838 feat: add gate scanner module
continuous-integration/drone/tag Build is passing Details
2024-09-02 13:59:19 +07:00
shancheas b9927da0c4 Merge branch 'development' of ssh://git.eigen.co.id:2222/eigen/pos-be into development
continuous-integration/drone/tag Build is passing Details
2024-09-02 13:07:38 +07:00
Firman Ramdhani d523009acd feat: add report income per item master
continuous-integration/drone/tag Build is failing Details
2024-08-30 19:32:03 +07:00
Firman Ramdhani 457ce30cc1 feat: update email template
continuous-integration/drone/tag Build is passing Details
2024-08-30 15:27:24 +07:00
shancheas e7a7ffb2bc feat: add variable config to formula 2024-08-29 17:19:24 +07:00
146 changed files with 19179 additions and 364 deletions

View File

@ -5,11 +5,11 @@ COPY . .
RUN yarn install
RUN yarn build
FROM node:18.17-alpine
# ARG env_target
ARG env_target
WORKDIR /app
# RUN echo ${env_target}
# COPY env/$env_target /app/.env
# COPY --from=builder /app/env/$env_target .env
RUN echo ${env_target}
COPY env/$env_target /app/.env
COPY --from=builder /app/env/$env_target .env
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/assets ./assets

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

BIN
assets/image/we.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 504 KiB

View File

@ -45,8 +45,10 @@ import { GoogleCalendarModule } from './modules/configuration/google-calendar/go
import { TransactionModule } from './modules/transaction/transaction/transaction.module';
import { TransactionModel } from './modules/transaction/transaction/data/models/transaction.model';
import {
TransactionBreakdownTaxModel,
TransactionItemBreakdownModel,
TransactionItemModel,
TransactionItemTaxModel,
} from './modules/transaction/transaction/data/models/transaction-item.model';
import { TransactionTaxModel } from './modules/transaction/transaction/data/models/transaction-tax.model';
import { ReconciliationModule } from './modules/transaction/reconciliation/reconciliation.module';
@ -76,6 +78,10 @@ import { PosLogModel } from './modules/configuration/log/data/models/pos-log.mod
import { ExportModule } from './modules/configuration/export/export.module';
import { TransactionDemographyModel } from './modules/transaction/transaction/data/models/transaction-demography.model';
import { SupersetModule } from './modules/configuration/superset/superset.module';
import { GateScanModule } from './modules/gates/gate.module';
import { UserLoginModel } from './modules/user-related/user/data/models/user-login.model';
import { LogUserLoginModel } from './modules/configuration/log/data/models/log-user-login.model';
import { AuthService } from './core/guards/domain/services/auth.service';
@Module({
imports: [
@ -101,6 +107,7 @@ import { SupersetModule } from './modules/configuration/superset/superset.module
ItemCategoryModel,
ItemRateModel,
LogModel,
LogUserLoginModel,
NewsModel,
PaymentMethodModel,
PosLogModel,
@ -116,7 +123,11 @@ import { SupersetModule } from './modules/configuration/superset/superset.module
TransactionTaxModel,
TransactionDemographyModel,
TransactionItemBreakdownModel,
TransactionItemTaxModel,
TransactionBreakdownTaxModel,
UserModel,
UserLoginModel,
VipCategoryModel,
VipCodeModel,
@ -178,9 +189,12 @@ import { SupersetModule } from './modules/configuration/superset/superset.module
// superset
SupersetModule,
GateScanModule,
],
controllers: [],
providers: [
AuthService,
PrivilegeService,
/**
* By default all request from client will protect by JWT

View File

@ -7,10 +7,10 @@ import {
UnauthorizedException,
} from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { Observable } from 'rxjs';
import { SessionService, UsersSession } from 'src/core/sessions';
import { UNPROTECTED_URL } from '../constants';
import { PrivilegeService } from './services/privilege.service';
import { AuthService } from './services/auth.service';
@Injectable({ scope: Scope.REQUEST })
export class JWTGuard implements CanActivate {
@ -18,14 +18,13 @@ export class JWTGuard implements CanActivate {
protected readonly session: SessionService,
protected readonly reflector: Reflector,
protected readonly privilege: PrivilegeService,
protected readonly authService: AuthService,
) {}
protected isPublic = false;
protected userSession: UsersSession;
canActivate(
context: ExecutionContext,
): boolean | Promise<boolean> | Observable<boolean> {
async canActivate(context: ExecutionContext) {
/**
* Check if access url is protected or not
* By default `isUnprotected` equals `false`
@ -61,9 +60,29 @@ export class JWTGuard implements CanActivate {
*/
try {
this.userSession = this.session.verifyToken(token);
await this.authService.verifyRegisteredLoginToken(token);
Logger.log(`Access from ${this.userSession.name}`, 'AuthGuard');
return true;
} catch (error) {
const expiredError = error.message;
if (expiredError === 'jwt expired') {
const [, body] = token.split('.');
const bodyToken = JSON.parse(atob(body));
const user = {
role: bodyToken.role,
user_id: bodyToken.id,
username: bodyToken.username,
user_privilege_id: bodyToken.user_privilege_id,
item_id: bodyToken.item_id,
item_name: bodyToken.item_name,
source: bodyToken.source,
};
this.authService.logoutUser(user, token);
}
throw new UnauthorizedException({
code: 10001,
message:

View File

@ -9,7 +9,7 @@ import { MAIN_MENU } from '../constants';
@Injectable()
export class RolesGuard extends JWTGuard {
async canActivate(context: ExecutionContext): Promise<boolean> {
super.canActivate(context);
await super.canActivate(context);
// jika endpoint tersebut bukan public, maka lakukan check lanjutan
if (!this.isPublic) {

View File

@ -0,0 +1,78 @@
import {
HttpStatus,
Injectable,
Scope,
UnauthorizedException,
} from '@nestjs/common';
import { InjectDataSource } from '@nestjs/typeorm';
import {
CONNECTION_NAME,
OPERATION,
} from 'src/core/strings/constants/base.constants';
import { DataSource } from 'typeorm';
import { UserRole } from 'src/modules/user-related/user/constants';
import { UserModel } from 'src/modules/user-related/user/data/models/user.model';
import { AppSource, LogUserType } from 'src/core/helpers/constant';
import { EventBus } from '@nestjs/cqrs';
import { LogUserLoginEvent } from 'src/modules/configuration/log/domain/entities/log-user-login.event';
import { UserLoginModel } from 'src/modules/user-related/user/data/models/user-login.model';
interface UserEntity {
user_id: string;
username: string;
role: UserRole;
user_privilege_id: string;
item_id: string;
item_name: string;
source: AppSource;
}
@Injectable({ scope: Scope.REQUEST })
export class AuthService {
constructor(
@InjectDataSource(CONNECTION_NAME.DEFAULT)
protected readonly dataSource: DataSource,
private eventBus: EventBus,
) {}
get repository() {
return this.dataSource.getRepository(UserLoginModel);
}
async logoutUser(user: UserEntity, token: string) {
await this.repository.delete({ login_token: token });
const userLogout = {
type: LogUserType.logout,
created_at: new Date().getTime(),
name: user.username,
user_privilege_id: user.user_privilege_id,
...user,
};
this.eventBus.publish(
new LogUserLoginEvent({
id: user.user_id,
old: null,
data: userLogout,
user: userLogout as any,
description: 'Logout',
module: UserModel.name,
op: OPERATION.UPDATE,
}),
);
}
async verifyRegisteredLoginToken(token: string) {
const data = await this.repository.findOneBy({ login_token: token });
if (!data) {
throw new UnauthorizedException({
statusCode: HttpStatus.UNAUTHORIZED,
message: `Invalid token`,
error: 'Unauthorized',
});
}
}
}

View File

@ -0,0 +1,11 @@
export enum LogUserType {
login = 'login',
logout = 'logout',
}
export enum AppSource {
POS_ADMIN = 'POS_ADMIN',
POS_COUNTER = 'POS_COUNTER',
QUEUE_ADMIN = 'QUEUE_ADMIN',
QUEUE_CUSTOMER = 'QUEUE_CUSTOMER',
}

View File

@ -1 +1,2 @@
export const PAGINATION_RESPONSE = 'PAGINATION_RESPONSE';
export const GATE_RESPONSE = 'GATE_RESPONSE';

View File

@ -1,5 +1,5 @@
import { SetMetadata } from '@nestjs/common';
import { PAGINATION_RESPONSE } from '../../constants';
import { GATE_RESPONSE, PAGINATION_RESPONSE } from '../../constants';
/**
* This decorator will tell the response,
@ -7,3 +7,5 @@ import { PAGINATION_RESPONSE } from '../../constants';
*/
export const Pagination = (isPagination = true) =>
SetMetadata(PAGINATION_RESPONSE, isPagination);
export const Gate = () => SetMetadata(GATE_RESPONSE, true);

View File

@ -8,13 +8,20 @@ import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { Request } from 'express';
import { Reflector } from '@nestjs/core';
import { PAGINATION_RESPONSE } from '../constants';
import { GATE_RESPONSE, PAGINATION_RESPONSE } from '../constants';
import { createPaginationResponse } from './utils/pagination-meta.helper';
@Injectable()
export class TransformInterceptor implements NestInterceptor {
constructor(protected readonly reflector: Reflector) {}
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
const isGate = this.reflector.getAllAndOverride<boolean>(GATE_RESPONSE, [
context.getHandler(),
context.getClass(),
]);
if (isGate) return next.handle();
const isPagination = this.reflector.getAllAndOverride<boolean>(
PAGINATION_RESPONSE,
[context.getHandler(), context.getClass()],

View File

@ -1,8 +1,10 @@
import { AppSource } from 'src/core/helpers/constant';
import { UserRole } from 'src/modules/user-related/user/constants';
export interface UsersSession {
id: number;
name: string;
role: UserRole;
source?: AppSource;
user_privilege_id: string;
}

View File

@ -23,4 +23,9 @@ export class UserProvider {
const [, token] = this.request.headers['authorization'].split(' ');
return this.session.verifyToken(token);
}
get token(): string {
const [, token] = this.request.headers['authorization'].split(' ');
return token;
}
}

View File

@ -22,8 +22,12 @@ export enum TABLE_NAME {
TRANSACTION_ITEM = 'transaction_items',
TRANSACTION_ITEM_BREAKDOWN = 'transaction_item_breakdowns',
TRANSACTION_TAX = 'transaction_taxes',
TRANSACTION_ITEM_TAX = 'transaction_item_taxes',
TRANSACTION_ITEM_BREAKDOWN_TAX = 't_breakdown_item_taxes',
TRANSACTION_DEMOGRAPHY = 'transaction_demographies',
USER = 'users',
USER_LOGIN = 'users_login',
LOG_USER_LOGIN = 'log_users_login',
USER_PRIVILEGE = 'user_privileges',
USER_PRIVILEGE_CONFIGURATION = 'user_privilege_configurations',
VIP_CATEGORY = 'vip_categories',

View File

@ -0,0 +1,19 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
export class AddValueVariableFormula1724926316235
implements MigrationInterface
{
name = 'AddValueVariableFormula1724926316235';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "price_formulas" ADD "value_for" character varying NOT NULL DEFAULT 'dpp'`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "price_formulas" DROP COLUMN "value_for"`,
);
}
}

View File

@ -0,0 +1,19 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
export class AddPaymentDateBankColumnAtTransaction1725962197762
implements MigrationInterface
{
name = 'AddPaymentDateBankColumnAtTransaction1725962197762';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "transactions" ADD "payment_date_bank" date`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "transactions" DROP COLUMN "payment_date_bank"`,
);
}
}

View File

@ -0,0 +1,21 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
export class AddPosNameColumn1726033041774 implements MigrationInterface {
name = 'AddPosNameColumn1726033041774';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "transactions" ADD "creator_counter_name" character varying`,
);
await queryRunner.query(
`ALTER TABLE "logs_pos" ADD "pos_name" character varying`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "logs_pos" DROP COLUMN "pos_name"`);
await queryRunner.query(
`ALTER TABLE "transactions" DROP COLUMN "creator_counter_name"`,
);
}
}

View File

@ -0,0 +1,43 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
export class AddFlagRoleQueue1726041175749 implements MigrationInterface {
name = 'AddFlagRoleQueue1726041175749';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TYPE "public"."users_role_enum" RENAME TO "users_role_enum_old"`,
);
await queryRunner.query(
`CREATE TYPE "public"."users_role_enum" AS ENUM('superadmin', 'staff', 'tenant', 'queue_admin')`,
);
await queryRunner.query(
`ALTER TABLE "users" ALTER COLUMN "role" DROP DEFAULT`,
);
await queryRunner.query(
`ALTER TABLE "users" ALTER COLUMN "role" TYPE "public"."users_role_enum" USING "role"::"text"::"public"."users_role_enum"`,
);
await queryRunner.query(
`ALTER TABLE "users" ALTER COLUMN "role" SET DEFAULT 'staff'`,
);
await queryRunner.query(`DROP TYPE "public"."users_role_enum_old"`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`CREATE TYPE "public"."users_role_enum_old" AS ENUM('superadmin', 'staff', 'tenant')`,
);
await queryRunner.query(
`ALTER TABLE "users" ALTER COLUMN "role" DROP DEFAULT`,
);
await queryRunner.query(
`ALTER TABLE "users" ALTER COLUMN "role" TYPE "public"."users_role_enum_old" USING "role"::"text"::"public"."users_role_enum_old"`,
);
await queryRunner.query(
`ALTER TABLE "users" ALTER COLUMN "role" SET DEFAULT 'staff'`,
);
await queryRunner.query(`DROP TYPE "public"."users_role_enum"`);
await queryRunner.query(
`ALTER TYPE "public"."users_role_enum_old" RENAME TO "users_role_enum"`,
);
}
}

View File

@ -0,0 +1,73 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
export class AddTaxItemTransaction1726045820711 implements MigrationInterface {
name = 'AddTaxItemTransaction1726045820711';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`CREATE TABLE "transaction_item_taxes" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "tax_id" character varying, "tax_name" character varying, "taxt_value" numeric, "tax_total_value" numeric, "transaction_id" uuid, CONSTRAINT "PK_fc5f6da61b24eb5bfdd503b0a0d" PRIMARY KEY ("id"))`,
);
await queryRunner.query(
`CREATE TABLE "t_breakdown_item_taxes" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "tax_id" character varying, "tax_name" character varying, "taxt_value" numeric, "tax_total_value" numeric, "transaction_id" uuid, CONSTRAINT "PK_a1ef08d2c68169a50102aa70eca" PRIMARY KEY ("id"))`,
);
await queryRunner.query(
`ALTER TABLE "transaction_items" ADD "total_profit_share" numeric`,
);
await queryRunner.query(
`ALTER TABLE "transaction_item_breakdowns" ADD "total_profit_share" numeric`,
);
await queryRunner.query(
`ALTER TABLE "transaction_item_taxes" ADD CONSTRAINT "FK_f5c4966a381d903899cafb4b5ba" FOREIGN KEY ("transaction_id") REFERENCES "transaction_items"("id") ON DELETE CASCADE ON UPDATE CASCADE`,
);
await queryRunner.query(
`ALTER TABLE "t_breakdown_item_taxes" ADD CONSTRAINT "FK_74bedce7e94f6707ddf26ef0c0f" FOREIGN KEY ("transaction_id") REFERENCES "transaction_item_breakdowns"("id") ON DELETE CASCADE ON UPDATE CASCADE`,
);
await queryRunner.query(
`ALTER TABLE "transaction_items" ADD "payment_total_dpp" numeric`,
);
await queryRunner.query(
`ALTER TABLE "transaction_item_breakdowns" ADD "payment_total_dpp" numeric`,
);
await queryRunner.query(
`ALTER TABLE "transaction_items" ADD "payment_total_tax" numeric`,
);
await queryRunner.query(
`ALTER TABLE "transaction_item_breakdowns" ADD "payment_total_tax" numeric`,
);
await queryRunner.query(
`ALTER TABLE "transaction_item_breakdowns" ADD "total_share_tenant" numeric`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "t_breakdown_item_taxes" DROP CONSTRAINT "FK_74bedce7e94f6707ddf26ef0c0f"`,
);
await queryRunner.query(
`ALTER TABLE "transaction_item_taxes" DROP CONSTRAINT "FK_f5c4966a381d903899cafb4b5ba"`,
);
await queryRunner.query(
`ALTER TABLE "transaction_item_breakdowns" DROP COLUMN "total_profit_share"`,
);
await queryRunner.query(
`ALTER TABLE "transaction_items" DROP COLUMN "total_profit_share"`,
);
await queryRunner.query(`DROP TABLE "t_breakdown_item_taxes"`);
await queryRunner.query(`DROP TABLE "transaction_item_taxes"`);
await queryRunner.query(
`ALTER TABLE "transaction_item_breakdowns" DROP COLUMN "payment_total_dpp"`,
);
await queryRunner.query(
`ALTER TABLE "transaction_items" DROP COLUMN "payment_total_dpp"`,
);
await queryRunner.query(
`ALTER TABLE "transaction_item_breakdowns" DROP COLUMN "payment_total_tax"`,
);
await queryRunner.query(
`ALTER TABLE "transaction_items" DROP COLUMN "payment_total_tax"`,
);
await queryRunner.query(
`ALTER TABLE "transaction_item_breakdowns" DROP COLUMN "total_share_tenant"`,
);
}
}

View File

@ -0,0 +1,21 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
export class AddTableUserLogin1726115025759 implements MigrationInterface {
name = 'AddTableUserLogin1726115025759';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`CREATE TABLE "users_login" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "login_date" bigint NOT NULL, "login_token" character varying, "user_id" uuid, CONSTRAINT "REL_2a80a213b51423ce5b8211f058" UNIQUE ("user_id"), CONSTRAINT "PK_e564194a9a22f8c623354284f75" PRIMARY KEY ("id"))`,
);
await queryRunner.query(
`ALTER TABLE "users_login" ADD CONSTRAINT "FK_2a80a213b51423ce5b8211f0584" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "users_login" DROP CONSTRAINT "FK_2a80a213b51423ce5b8211f0584"`,
);
await queryRunner.query(`DROP TABLE "users_login"`);
}
}

View File

@ -0,0 +1,23 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
export class UpdateTableUserLogin1726122619596 implements MigrationInterface {
name = 'UpdateTableUserLogin1726122619596';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "users_login" DROP CONSTRAINT "FK_2a80a213b51423ce5b8211f0584"`,
);
await queryRunner.query(
`ALTER TABLE "users_login" ADD CONSTRAINT "FK_2a80a213b51423ce5b8211f0584" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "users_login" DROP CONSTRAINT "FK_2a80a213b51423ce5b8211f0584"`,
);
await queryRunner.query(
`ALTER TABLE "users_login" ADD CONSTRAINT "FK_2a80a213b51423ce5b8211f0584" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`,
);
}
}

View File

@ -0,0 +1,23 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
export class AddTableLogUserLogin1726123955427 implements MigrationInterface {
name = 'AddTableLogUserLogin1726123955427';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`CREATE TYPE "public"."log_users_login_type_enum" AS ENUM('login', 'logout')`,
);
await queryRunner.query(
`CREATE TYPE "public"."log_users_login_role_enum" AS ENUM('superadmin', 'staff', 'tenant', 'queue_admin')`,
);
await queryRunner.query(
`CREATE TABLE "log_users_login" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "type" "public"."log_users_login_type_enum", "role" "public"."log_users_login_role_enum", "user_id" uuid, "username" character varying, "created_at" bigint, CONSTRAINT "PK_75141588aa6ee560504f7d3adce" PRIMARY KEY ("id"))`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`DROP TABLE "log_users_login"`);
await queryRunner.query(`DROP TYPE "public"."log_users_login_role_enum"`);
await queryRunner.query(`DROP TYPE "public"."log_users_login_type_enum"`);
}
}

View File

@ -0,0 +1,17 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
export class AddColumnItemId1726139426994 implements MigrationInterface {
name = 'AddColumnItemId1726139426994';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "users_login" ADD "item_id" uuid`);
await queryRunner.query(`ALTER TABLE "log_users_login" ADD "item_id" uuid`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "log_users_login" DROP COLUMN "item_id"`,
);
await queryRunner.query(`ALTER TABLE "users_login" DROP COLUMN "item_id"`);
}
}

View File

@ -0,0 +1,23 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
export class AddColumnItemName1726141393404 implements MigrationInterface {
name = 'AddColumnItemName1726141393404';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "users_login" ADD "item_name" character varying`,
);
await queryRunner.query(
`ALTER TABLE "log_users_login" ADD "item_name" character varying`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "log_users_login" DROP COLUMN "item_name"`,
);
await queryRunner.query(
`ALTER TABLE "users_login" DROP COLUMN "item_name"`,
);
}
}

View File

@ -0,0 +1,17 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
export class AddFormulaToTax1726365023179 implements MigrationInterface {
name = 'AddFormulaToTax1726365023179';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "taxes" ADD "formula_render" json`);
await queryRunner.query(
`ALTER TABLE "taxes" ADD "formula_string" character varying`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "taxes" DROP COLUMN "formula_string"`);
await queryRunner.query(`ALTER TABLE "taxes" DROP COLUMN "formula_render"`);
}
}

View File

@ -0,0 +1,35 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
export class ChangeUserLoginRelation1726642119207
implements MigrationInterface
{
name = 'ChangeUserLoginRelation1726642119207';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "users" DROP COLUMN "refresh_token"`);
await queryRunner.query(
`ALTER TABLE "users_login" DROP CONSTRAINT "FK_2a80a213b51423ce5b8211f0584"`,
);
await queryRunner.query(
`ALTER TABLE "users_login" DROP CONSTRAINT "REL_2a80a213b51423ce5b8211f058"`,
);
await queryRunner.query(
`ALTER TABLE "users_login" ADD CONSTRAINT "FK_2a80a213b51423ce5b8211f0584" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "users_login" DROP CONSTRAINT "FK_2a80a213b51423ce5b8211f0584"`,
);
await queryRunner.query(
`ALTER TABLE "users_login" ADD CONSTRAINT "REL_2a80a213b51423ce5b8211f058" UNIQUE ("user_id")`,
);
await queryRunner.query(
`ALTER TABLE "users_login" ADD CONSTRAINT "FK_2a80a213b51423ce5b8211f0584" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE`,
);
await queryRunner.query(
`ALTER TABLE "users" ADD "refresh_token" character varying`,
);
}
}

View File

@ -0,0 +1,29 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
export class AddColumnSourceAtUserLogin1726642499135
implements MigrationInterface
{
name = 'AddColumnSourceAtUserLogin1726642499135';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`CREATE TYPE "public"."users_login_role_enum" AS ENUM('superadmin', 'staff', 'tenant', 'queue_admin')`,
);
await queryRunner.query(
`ALTER TABLE "users_login" ADD "role" "public"."users_login_role_enum"`,
);
await queryRunner.query(
`CREATE TYPE "public"."users_login_source_enum" AS ENUM('POS_ADMIN', 'POS_COUNTER', 'QUEUE_ADMIN', 'QUEUE_CUSTOMER')`,
);
await queryRunner.query(
`ALTER TABLE "users_login" ADD "source" "public"."users_login_source_enum"`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "users_login" DROP COLUMN "source"`);
await queryRunner.query(`DROP TYPE "public"."users_login_source_enum"`);
await queryRunner.query(`ALTER TABLE "users_login" DROP COLUMN "role"`);
await queryRunner.query(`DROP TYPE "public"."users_login_role_enum"`);
}
}

View File

@ -0,0 +1,21 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
export class AddSourceOnLogLogin1726647442006 implements MigrationInterface {
name = 'AddSourceOnLogLogin1726647442006';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`CREATE TYPE "public"."log_users_login_source_enum" AS ENUM('POS_ADMIN', 'POS_COUNTER', 'QUEUE_ADMIN', 'QUEUE_CUSTOMER')`,
);
await queryRunner.query(
`ALTER TABLE "log_users_login" ADD "source" "public"."log_users_login_source_enum"`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "log_users_login" DROP COLUMN "source"`,
);
await queryRunner.query(`DROP TYPE "public"."log_users_login_source_enum"`);
}
}

View File

@ -0,0 +1,43 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
export class AddDiscountForItemTransaction1726824289989
implements MigrationInterface
{
name = 'AddDiscountForItemTransaction1726824289989';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "transaction_items" ADD "subtotal" numeric`,
);
await queryRunner.query(
`ALTER TABLE "transaction_items" ADD "discount_value" numeric`,
);
await queryRunner.query(
`ALTER TABLE "transaction_item_breakdowns" ADD "subtotal" numeric`,
);
await queryRunner.query(
`ALTER TABLE "transaction_item_breakdowns" ADD "discount_value" numeric`,
);
await queryRunner.query(
`ALTER TABLE "transaction_item_breakdowns" ADD "total_price" numeric`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "transaction_item_breakdowns" DROP COLUMN "total_price"`,
);
await queryRunner.query(
`ALTER TABLE "transaction_item_breakdowns" DROP COLUMN "discount_value"`,
);
await queryRunner.query(
`ALTER TABLE "transaction_item_breakdowns" DROP COLUMN "subtotal"`,
);
await queryRunner.query(
`ALTER TABLE "transaction_items" DROP COLUMN "discount_value"`,
);
await queryRunner.query(
`ALTER TABLE "transaction_items" DROP COLUMN "subtotal"`,
);
}
}

View File

@ -0,0 +1,23 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
export class ChangeColumnName1726830293878 implements MigrationInterface {
name = 'ChangeColumnName1726830293878';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "transaction_items" RENAME COLUMN "subtotal" TO "total_net_price"`,
);
await queryRunner.query(
`ALTER TABLE "transaction_item_breakdowns" RENAME COLUMN "subtotal" TO "total_net_price"`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "transaction_item_breakdowns" RENAME COLUMN "total_net_price" TO "subtotal"`,
);
await queryRunner.query(
`ALTER TABLE "transaction_items" RENAME COLUMN "total_net_price" TO "subtotal"`,
);
}
}

View File

@ -9,14 +9,32 @@ import { CqrsModule } from '@nestjs/cqrs';
import { UserModel } from 'src/modules/user-related/user/data/models/user.model';
import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants';
import { UserDataService } from 'src/modules/user-related/user/data/services/user-data.service';
import { AuthAdminQueueController } from './infrastructure/auth-admin-queue.controller';
import { AuthAdminQueueOrchestrator } from './domain/auth-admin-queue.orchestrator';
import { LoginAdminQueueManager } from './domain/managers/admin-queue/login-admin-queue.manager';
import { LogoutAdminQueueManager } from './domain/managers/admin-queue/logout-admin-queue.manager';
import { UserLoginModel } from 'src/modules/user-related/user/data/models/user-login.model';
@Module({
imports: [
ConfigModule.forRoot(),
TypeOrmModule.forFeature([UserModel], CONNECTION_NAME.DEFAULT),
TypeOrmModule.forFeature(
[UserModel, UserLoginModel],
CONNECTION_NAME.DEFAULT,
),
CqrsModule,
],
controllers: [AuthController],
providers: [LoginManager, LogoutManager, UserDataService, AuthOrchestrator],
controllers: [AuthController, AuthAdminQueueController],
providers: [
LoginManager,
LogoutManager,
UserDataService,
AuthOrchestrator,
// ADMIN QUEUE
AuthAdminQueueOrchestrator,
LoginAdminQueueManager,
LogoutAdminQueueManager,
],
})
export class AuthModule {}

View File

@ -0,0 +1,32 @@
import { Injectable } from '@nestjs/common';
import { LoginAdminQueueManager } from './managers/admin-queue/login-admin-queue.manager';
import { LogoutAdminQueueManager } from './managers/admin-queue/logout-admin-queue.manager';
import { TABLE_NAME } from 'src/core/strings/constants/table.constants';
import { UserDataService } from 'src/modules/user-related/user/data/services/user-data.service';
@Injectable()
export class AuthAdminQueueOrchestrator {
constructor(
private loginManager: LoginAdminQueueManager,
private logoutManager: LogoutAdminQueueManager,
private serviceData: UserDataService,
) {}
async login(data): Promise<any> {
this.loginManager.setData(data);
this.loginManager.setService(this.serviceData, TABLE_NAME.USER);
await this.loginManager.execute();
return this.loginManager.getResult();
}
async logout(userId?: string): Promise<any> {
if (userId) this.logoutManager.setData({ user_id: userId });
this.logoutManager.setService(this.serviceData, TABLE_NAME.USER);
await this.logoutManager.execute();
return this.logoutManager.getResult();
}
async forceLogout(token): Promise<any> {
return this.serviceData.forceLogout(token);
}
}

View File

@ -24,4 +24,8 @@ export class AuthOrchestrator {
await this.logoutManager.execute();
return this.logoutManager.getResult();
}
async forceLogout(token): Promise<any> {
return this.serviceData.forceLogout(token);
}
}

View File

@ -0,0 +1,167 @@
import {
HttpStatus,
Inject,
Injectable,
Logger,
UnauthorizedException,
} from '@nestjs/common';
import { validatePassword } from 'src/core/helpers/password/bcrypt.helpers';
import { BaseCustomManager } from 'src/core/modules/domain/usecase/managers/base-custom.manager';
import { SessionService } from 'src/core/sessions';
import { STATUS } from 'src/core/strings/constants/base.constants';
import { EventTopics } from 'src/core/strings/constants/interface.constants';
import { UserModel } from 'src/modules/user-related/user/data/models/user.model';
import { UserEntity } from 'src/modules/user-related/user/domain/entities/user.entity';
import { In } from 'typeorm';
import { UserRole } from 'src/modules/user-related/user/constants';
import { AppSource, LogUserType } from 'src/core/helpers/constant';
import { LogUserLoginEvent } from 'src/modules/configuration/log/domain/entities/log-user-login.event';
import { UserLoginEntity } from 'src/modules/user-related/user/domain/entities/user-login.entity';
@Injectable()
export class LoginAdminQueueManager extends BaseCustomManager<UserEntity> {
@Inject()
protected session: SessionService;
protected token;
protected userLogin;
async validateProcess(): Promise<void> {
return;
}
async beforeProcess(): Promise<void> {
return;
}
async process(): Promise<void> {
const itemLogin = await this.dataService.getLoginUserByItem(
this.data.item_id,
);
// get user active by username
this.userLogin = await this.dataService.getOneByOptions({
where: {
username: this.data.username,
status: STATUS.ACTIVE,
role: In([UserRole.QUEUE_ADMIN, UserRole.SUPERADMIN]),
},
relations: ['user_login'],
});
if (!this.userLogin) this.throwError();
// validasi password
const valid = await validatePassword(
this.data.password,
this.userLogin?.password,
);
if (!valid) this.throwError();
const userLoginItem = await this.dataService.getOneByOptions({
where: {
id: itemLogin?.user_id,
},
});
const hasLoginAsQueue = this.userLogin?.user_login?.find(
(item) => item.source === AppSource.QUEUE_ADMIN,
);
if (hasLoginAsQueue && hasLoginAsQueue?.item_id !== this.data.item_id) {
throw new UnauthorizedException({
statusCode: HttpStatus.UNAUTHORIZED,
message: `Akun anda sudah login di item "${hasLoginAsQueue?.item_name}"`,
error: 'Unauthorized',
});
} else if (itemLogin && itemLogin.user_id !== this.userLogin.id) {
throw new UnauthorizedException({
statusCode: HttpStatus.UNAUTHORIZED,
message: `"${userLoginItem.name}" masih login sebagai admin antrian `,
error: 'Unauthorized',
});
}
// * Disini untuk isi token
const tokenData = {
id: this.userLogin.id,
name: this.userLogin.name,
username: this.userLogin.username,
role: this.userLogin.role,
user_privilege_id: this.userLogin.user_privilege_id,
item_id: this.data.item_id,
item_name: this.data.item_name,
source: AppSource.QUEUE_ADMIN,
};
Logger.debug('Sign Token Admin Queue', 'LoginAdminQueueManager');
this.token = this.session.createAccessToken(tokenData);
Logger.debug('Save Login Token', 'LoginManager');
const userLoginData: UserLoginEntity = {
user_id: this.userLogin.id,
login_token: this.token,
login_date: new Date().getTime(),
source: AppSource.QUEUE_ADMIN,
role: this.userLogin.role,
item_id: this.data.item_id,
item_name: this.data.item_name,
};
if (hasLoginAsQueue?.item_id === this.data.item_id) {
Object.assign(userLoginData, { id: hasLoginAsQueue.id });
}
// Update refresh token
await this.dataService.saveUserLogin(userLoginData);
await this.publishEvents();
Logger.debug('Process Login Admin Queue Done', 'LoginAdminQueueManager');
return;
}
async afterProcess(): Promise<void> {
return;
}
getResult() {
return {
id: this.userLogin.id,
name: this.userLogin.name,
username: this.userLogin.username,
role: this.userLogin.role,
token: this.token,
item_id: this.data.item_id,
item_name: this.data.item_name,
};
}
get entityTarget(): any {
return UserModel;
}
get eventTopics(): EventTopics[] {
return [
{
topic: LogUserLoginEvent,
data: {
type: LogUserType.login,
role: this.userLogin.role,
user_id: this.userLogin.id,
username: this.userLogin.username,
created_at: new Date().getTime(),
item_id: this.data.item_id,
item_name: this.data.item_name,
source: AppSource.QUEUE_ADMIN,
},
},
];
}
// !throw errornya akan sama, untuk security
throwError() {
throw new UnauthorizedException({
statusCode: HttpStatus.UNAUTHORIZED,
message: `Gagal! username atau password tidak sesuai`,
error: 'Unauthorized',
});
}
}

View File

@ -0,0 +1,62 @@
import { AppSource, LogUserType } from 'src/core/helpers/constant';
import { BaseCustomManager } from 'src/core/modules/domain/usecase/managers/base-custom.manager';
import { EventTopics } from 'src/core/strings/constants/interface.constants';
import { LogUserLoginEvent } from 'src/modules/configuration/log/domain/entities/log-user-login.event';
import { UserModel } from 'src/modules/user-related/user/data/models/user.model';
import { UserEntity } from 'src/modules/user-related/user/domain/entities/user.entity';
export class LogoutAdminQueueManager extends BaseCustomManager<UserEntity> {
protected userLogin;
async validateProcess(): Promise<void> {
return;
}
async beforeProcess(): Promise<void> {
return;
}
async process(): Promise<void> {
const id = this.data?.user_id ?? this.user.id;
this.userLogin = await this.dataService.getOneByOptions({
where: { id },
});
await this.dataService.removeUserLogin({
user_id: id,
source: AppSource.QUEUE_ADMIN,
});
await this.publishEvents();
return;
}
async afterProcess(): Promise<void> {
return;
}
getResult() {
return `Success Logout User`;
}
get entityTarget(): any {
return UserModel;
}
get eventTopics(): EventTopics[] {
return [
{
topic: LogUserLoginEvent,
data: {
type: LogUserType.logout,
role: this.userLogin.role,
user_id: this.userLogin.id,
username: this.userLogin.name,
created_at: new Date().getTime(),
source: AppSource.QUEUE_ADMIN,
},
},
];
}
}

View File

@ -12,7 +12,11 @@ import { STATUS } from 'src/core/strings/constants/base.constants';
import { EventTopics } from 'src/core/strings/constants/interface.constants';
import { UserModel } from 'src/modules/user-related/user/data/models/user.model';
import { UserEntity } from 'src/modules/user-related/user/domain/entities/user.entity';
import { UserLoginEvent } from '../entities/login.event';
import { Not } from 'typeorm';
import { UserRole } from 'src/modules/user-related/user/constants';
import { AppSource, LogUserType } from 'src/core/helpers/constant';
import { LogUserLoginEvent } from 'src/modules/configuration/log/domain/entities/log-user-login.event';
import { UserLoginEntity } from 'src/modules/user-related/user/domain/entities/user-login.entity';
@Injectable()
export class LoginManager extends BaseCustomManager<UserEntity> {
@ -36,6 +40,7 @@ export class LoginManager extends BaseCustomManager<UserEntity> {
where: {
username: this.data.username,
status: STATUS.ACTIVE,
role: Not(UserRole.QUEUE_ADMIN),
},
relations: [
'user_privilege',
@ -58,25 +63,27 @@ export class LoginManager extends BaseCustomManager<UserEntity> {
username: this.userLogin.username,
role: this.userLogin.role,
user_privilege_id: this.userLogin.user_privilege_id,
source: AppSource.POS_ADMIN,
};
Logger.debug('Sign Token', 'LoginManager');
this.token = this.session.createAccessToken(tokenData);
Logger.debug('refreshToken', 'LoginManager');
const refreshToken = this.session.createAccessToken(tokenData);
Logger.debug('Save Login Token', 'LoginManager');
const userLoginData: UserLoginEntity = {
user_id: this.userLogin.id,
login_token: this.token,
login_date: new Date().getTime(),
source: AppSource.POS_ADMIN,
role: this.userLogin.role,
item_id: null,
item_name: null,
};
Logger.debug('Update Refresh Token', 'LoginManager');
// Update refresh token
await this.dataService.update(
this.queryRunner,
this.entityTarget,
{ id: this.userLogin.id },
{
refresh_token: refreshToken,
},
);
await this.dataService.saveUserLogin(userLoginData);
await this.publishEvents();
Logger.debug('Process Login Done', 'LoginManager');
return;
}
@ -119,11 +126,14 @@ export class LoginManager extends BaseCustomManager<UserEntity> {
get eventTopics(): EventTopics[] {
return [
{
topic: UserLoginEvent,
topic: LogUserLoginEvent,
data: {
id: this.userLogin.id,
type: 'login',
timestamp: new Date().getTime(),
type: LogUserType.login,
role: this.userLogin.role,
user_id: this.userLogin.id,
username: this.userLogin.username,
created_at: new Date().getTime(),
source: AppSource.POS_ADMIN,
},
},
];

View File

@ -2,7 +2,8 @@ import { BaseCustomManager } from 'src/core/modules/domain/usecase/managers/base
import { EventTopics } from 'src/core/strings/constants/interface.constants';
import { UserModel } from 'src/modules/user-related/user/data/models/user.model';
import { UserEntity } from 'src/modules/user-related/user/domain/entities/user.entity';
import { UserLogoutEvent } from '../entities/logout.event';
import { AppSource, LogUserType } from 'src/core/helpers/constant';
import { LogUserLoginEvent } from 'src/modules/configuration/log/domain/entities/log-user-login.event';
export class LogoutManager extends BaseCustomManager<UserEntity> {
async validateProcess(): Promise<void> {
@ -14,15 +15,12 @@ export class LogoutManager extends BaseCustomManager<UserEntity> {
}
async process(): Promise<void> {
await this.dataService.update(
this.queryRunner,
this.entityTarget,
{ id: this.user.id },
{
refresh_token: null,
},
);
await this.dataService.removeUserLogin({
user_id: this.user.id,
login_token: this.userProvider.token,
source: AppSource.POS_ADMIN,
});
await this.publishEvents();
return;
}
@ -41,11 +39,14 @@ export class LogoutManager extends BaseCustomManager<UserEntity> {
get eventTopics(): EventTopics[] {
return [
{
topic: UserLogoutEvent,
topic: LogUserLoginEvent,
data: {
id: this.user.id,
type: 'logout',
timestamp: new Date().getTime(),
type: LogUserType.logout,
role: this.user.role,
user_id: this.user.id,
username: this.user.name,
created_at: new Date().getTime(),
source: AppSource.POS_ADMIN,
},
},
];

View File

@ -0,0 +1,35 @@
import { Body, Controller, Delete, Param, Post, Put } from '@nestjs/common';
import { ExcludePrivilege, Public } from 'src/core/guards';
import { ApiBearerAuth } from '@nestjs/swagger';
import { ForceLogoutDto, LoginQueueDto } from './dto/login.dto';
import { AuthAdminQueueOrchestrator } from '../domain/auth-admin-queue.orchestrator';
@Controller('v1/auth/queue')
export class AuthAdminQueueController {
constructor(private orchestrator: AuthAdminQueueOrchestrator) {}
@Post()
@Public(true)
async login(@Body() body: LoginQueueDto) {
return await this.orchestrator.login(body);
}
@ApiBearerAuth('JWT')
@Public(false)
@ExcludePrivilege()
@Delete('logout')
async logout() {
return await this.orchestrator.logout();
}
@Put(':user_id/logout')
async logoutQueueAdmin(@Param('user_id') userId: string) {
return await this.orchestrator.logout(userId);
}
@Post('force-logout')
@Public(true)
async forceLogout(@Body() body: ForceLogoutDto) {
return await this.orchestrator.forceLogout(body.token);
}
}

View File

@ -1,8 +1,8 @@
import { Body, Controller, Delete, Post } from '@nestjs/common';
import { Public } from 'src/core/guards';
import { ExcludePrivilege, Public } from 'src/core/guards';
import { AuthOrchestrator } from '../domain/auth.orchestrator';
import { ApiBearerAuth } from '@nestjs/swagger';
import { LoginDto } from './dto/login.dto';
import { ForceLogoutDto, LoginDto } from './dto/login.dto';
@Controller('v1/auth')
export class AuthController {
@ -16,8 +16,15 @@ export class AuthController {
@ApiBearerAuth('JWT')
@Public(false)
@ExcludePrivilege()
@Delete('logout')
async logoout() {
async logout() {
return await this.orchestrator.logout();
}
@Post('force-logout')
@Public(true)
async forceLogout(@Body() body: ForceLogoutDto) {
return await this.orchestrator.forceLogout(body.token);
}
}

View File

@ -11,3 +11,27 @@ export class LoginDto implements LoginRequest {
@IsString()
password: string;
}
export class LoginQueueDto implements LoginRequest {
@ApiProperty({ name: 'username', required: true, default: 'superadmin' })
@IsString()
username: string;
@ApiProperty({ name: 'password', required: true, default: 'Eigen123!' })
@IsString()
password: string;
@ApiProperty({ name: 'item_id', required: true, default: 'string' })
@IsString()
item_id: string;
@ApiProperty({ name: 'item_name', required: true, default: 'string' })
@IsString()
item_name: string;
}
export class ForceLogoutDto {
@ApiProperty({ required: true })
@IsString()
token: string;
}

View File

@ -51,6 +51,7 @@ import {
import { SeasonPeriodDataService } from 'src/modules/season-related/season-period/data/services/season-period-data.service';
import { SeasonPeriodModel } from 'src/modules/season-related/season-period/data/models/season-period.model';
import { TransactionDemographyModel } from 'src/modules/transaction/transaction/data/models/transaction-demography.model';
import { UserLoginModel } from 'src/modules/user-related/user/data/models/user-login.model';
@Module({
imports: [
@ -61,6 +62,7 @@ import { TransactionDemographyModel } from 'src/modules/transaction/transaction/
ItemRateModel,
SeasonPeriodModel,
UserModel,
UserLoginModel,
TransactionModel,
TransactionTaxModel,
TransactionItemModel,
@ -100,5 +102,6 @@ import { TransactionDemographyModel } from 'src/modules/transaction/transaction/
ItemDataService,
CouchService,
],
exports: [CouchService],
})
export class CouchModule {}

View File

@ -23,13 +23,14 @@ export class CouchService {
for (const database of DatabaseListen) {
const db = nano.db.use(database);
db.changesReader.start({ includeDocs: true }).on('change', (change) => {
Logger.log(
Logger.verbose(
`Receive Data from ${database}: ${change?.id}`,
'CouchService',
);
this.changeDoc(change, database);
});
// transaction
Logger.log(`start listen database ${database}`, 'CouchService');
}
}

View File

@ -0,0 +1,37 @@
import { TABLE_NAME } from 'src/core/strings/constants/table.constants';
import { UserEntity } from '../../../../user-related/user/domain/entities/user.entity';
import { Column, Entity } from 'typeorm';
import { BaseCoreModel } from 'src/core/modules/data/model/base-core.model';
import { LogUserLoginEntity } from '../../domain/entities/log-user-login.entity';
import { UserRole } from '../../../../user-related/user/constants';
import { AppSource, LogUserType } from 'src/core/helpers/constant';
@Entity(TABLE_NAME.LOG_USER_LOGIN)
export class LogUserLoginModel
extends BaseCoreModel<UserEntity>
implements LogUserLoginEntity
{
@Column({ type: 'enum', enum: LogUserType, nullable: true })
type: LogUserType;
@Column({ type: 'enum', enum: UserRole, nullable: true })
role: UserRole;
@Column({ type: 'uuid', nullable: true })
user_id: string;
@Column({ type: 'uuid', nullable: true })
item_id: string;
@Column({ type: 'varchar', nullable: true })
item_name: string;
@Column({ type: 'varchar', nullable: true })
username: string;
@Column({ type: 'bigint', nullable: true })
created_at: number;
@Column({ type: 'enum', enum: AppSource, nullable: true })
source: AppSource;
}

View File

@ -14,6 +14,9 @@ export class PosLogModel
@Column('bigint', { name: 'pos_number', nullable: true })
pos_number: number;
@Column('varchar', { name: 'pos_name', nullable: true })
pos_name: string;
@Column('decimal', { name: 'total_balance', nullable: true })
total_balance: number;

View File

@ -0,0 +1,21 @@
import { BaseDataService } from 'src/core/modules/data/service/base-data.service';
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants';
import { LogUserLoginEntity } from '../../domain/entities/log-user-login.entity';
import { LogUserLoginModel } from '../models/log-user-login.model';
@Injectable()
export class LogUserLoginService extends BaseDataService<LogUserLoginEntity> {
constructor(
@InjectRepository(LogUserLoginModel, CONNECTION_NAME.DEFAULT)
private repo: Repository<LogUserLoginModel>,
) {
super(repo);
}
async saveData(data) {
this.repo.save(data);
}
}

View File

@ -0,0 +1,13 @@
import { LogUserType } from 'src/core/helpers/constant';
import { UserRole } from '../../../../user-related/user/constants';
import { BaseCoreEntity } from 'src/core/modules/domain/entities/base-core.entity';
export interface LogUserLoginEntity extends BaseCoreEntity {
type: LogUserType;
role: UserRole;
user_id: string;
item_id: string;
item_name: string;
username: string;
created_at: number;
}

View File

@ -0,0 +1,5 @@
import { IEvent } from 'src/core/strings/constants/interface.constants';
export class LogUserLoginEvent {
constructor(public readonly data: IEvent) {}
}

View File

@ -3,6 +3,7 @@ import { BaseCoreEntity } from 'src/core/modules/domain/entities/base-core.entit
export interface PosLogEntity extends BaseCoreEntity {
type: PosLogType;
pos_number: number;
pos_name: string;
total_balance: number;
created_at: number;
creator_name: string;

View File

@ -0,0 +1,14 @@
import { EventsHandler, IEventHandler } from '@nestjs/cqrs';
import { LogUserLoginEvent } from '../entities/log-user-login.event';
import { LogUserLoginService } from '../../data/services/log-user-login.service';
@EventsHandler(LogUserLoginEvent)
export class LogUserLoginHandler implements IEventHandler<LogUserLoginEvent> {
constructor(private service: LogUserLoginService) {}
async handle(event: LogUserLoginEvent) {
const data = event.data.data;
await this.service.saveData(data);
}
}

View File

@ -26,6 +26,7 @@ export class RecordPosLogHandler implements IEventHandler<ChangeDocEvent> {
type: PosLogType[data.type],
total_balance: data.withdrawal_cash ?? data.opening_cash_balance,
pos_number: data.pos_number,
pos_name: data.pos_name,
creator_id: data.pos_admin?.id,
creator_name: data.pos_admin?.name ?? data.pos_admin?.username,
drawn_by_id: data.withdraw_user?.id,

View File

@ -12,12 +12,15 @@ import { LogService } from './data/services/log.service';
import { PosLogModel } from './data/models/pos-log.model';
import { PosLogService } from './data/services/pos-log.service';
import { RecordPosLogHandler } from './domain/handlers/pos-log.handler';
import { LogUserLoginModel } from './data/models/log-user-login.model';
import { LogUserLoginService } from './data/services/log-user-login.service';
import { LogUserLoginHandler } from './domain/handlers/log-user-login.handler';
@Module({
imports: [
ConfigModule.forRoot(),
TypeOrmModule.forFeature(
[LogModel, ErrorLogModel, PosLogModel],
[LogModel, ErrorLogModel, PosLogModel, LogUserLoginModel],
CONNECTION_NAME.DEFAULT,
),
CqrsModule,
@ -27,10 +30,12 @@ import { RecordPosLogHandler } from './domain/handlers/pos-log.handler';
RecordLogHandler,
RecordPosLogHandler,
RecordErrorLogHandler,
LogUserLoginHandler,
LogService,
PosLogService,
ErrorLogService,
LogUserLoginService,
],
})
export class LogModule {}

View File

@ -32,7 +32,6 @@ export class PaymentTransactionHandler
const current_data = event.data.data;
const data_id = current_data.transaction_id ?? event.data.id;
const from_refund = event.data.module == TABLE_NAME.REFUND;
console.log('payment handlet', { data_id });
const payments = await this.paymentService.getManyByOptions({
where: {
@ -106,6 +105,15 @@ export class PaymentTransactionHandler
`;
})}
</ul>`,
refund_items_data: transaction?.['refund']?.refund_items
?.filter((item) => Number(item.qty_refund) > 0)
.map((item) => {
return {
qty_refund: item.qty_refund,
item_name: item.transaction_item.item_name,
};
}),
});
}

View File

@ -17,7 +17,7 @@ export async function sendEmail(receivers, invoiceType, attachment?) {
for (const receiver of receivers) {
try {
const templateName = getTemplate(receiver.payment_type, invoiceType);
const templatePath = `./assets/email-template/${templateName}.html`;
const templatePath = `./assets/email-template/redesign/${templateName}.html`;
const templateSource = fs.readFileSync(templatePath, 'utf8');
const template = handlebars.compile(templateSource);

View File

@ -0,0 +1,5 @@
export interface GateScanEntity {
gate_id: string;
type: string;
uuid: string;
}

View File

@ -0,0 +1,8 @@
export interface GateResponseEntity {
code: number;
message: string;
}
export interface GateMasterEntity {
codes: string[];
}

View File

@ -0,0 +1,17 @@
import { Global, Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { GateController } from './infrastructure/gate.controller';
@Global()
@Module({
imports: [
ConfigModule.forRoot(),
// TypeOrmModule.forFeature(
// [],
// CONNECTION_NAME.DEFAULT,
// ),
],
controllers: [GateController],
providers: [],
})
export class GateScanModule {}

View File

@ -0,0 +1,94 @@
import { Body, Controller, Get, Param, Post, Res } from '@nestjs/common';
import { Response } from 'express';
import { ApiTags } from '@nestjs/swagger';
import { Public } from 'src/core/guards';
import { GateScanEntity } from '../domain/entity/gate-request.entity';
import {
GateMasterEntity,
GateResponseEntity,
} from '../domain/entity/gate-response.entity';
import { Gate } from 'src/core/response';
const masterGates = [
'319b6d3e-b661-4d19-8695-0dd6fb76465e',
'9afdb79d-7162-43e6-8ac6-f1941adea7ba',
'7e4c0281-8cf2-420e-aba1-c8ff834de450',
'19318ac8-caa0-47e4-8a41-2aac238d3665',
'495bc25f-42c4-4007-8e79-3747fa1054b6',
'b90fc9a9-efd9-4216-a8af-7ed120b141de',
'4399e93c-a839-4802-a49d-f933c72b1433',
'970673a7-6370-444a-931a-9784220dd35d',
'151ab50e-4e54-4252-b3ab-f5c0817b27a0',
'4c0e6924-baf5-47fb-a15b-fd1cd0958cc0',
];
const failedGates = [
'b3c3ae7b-daf5-4340-998b-ee35ed41323d',
'be157609-92b8-4989-920d-a81769bcb05a',
];
const gateResponses = [
{
statusCode: 200,
code: 1,
message: 'Berhasil Check In',
},
{
statusCode: 403,
code: 2,
message: 'Gagal melakukan Check In. Karena tiket telah kadaluarsa',
},
{
statusCode: 403,
code: 3,
message: 'Gagal melakukan Check In. Tiket tidak tersedia',
},
];
@ApiTags(`Gate - read`)
@Controller(`v1/gate`)
@Public(true)
@Gate()
export class GateController {
@Post('scan')
async scan(
@Body() data: GateScanEntity,
@Res({ passthrough: true }) res: Response,
): Promise<GateResponseEntity> {
console.log(data);
if (masterGates.includes(data.uuid)) {
res.status(200);
return gateResponses[0];
}
if (failedGates.includes(data.uuid)) {
res.status(403);
return gateResponses[2];
}
const response = Math.floor(Math.random() * 3);
const responseValue = gateResponses[response];
res.status(responseValue.statusCode);
return responseValue;
}
@Get(':id/master')
async detail(@Param('id') id: string): Promise<GateMasterEntity> {
if (id == '1') return { codes: masterGates };
return {
codes: this.createRandomStringArray(masterGates),
};
}
createRandomStringArray(inputArray: string[]): string[] {
const randomLength = Math.floor(Math.random() * 4) + 2; // Random length between 2 and 5
const outputArray: string[] = [];
while (outputArray.length < randomLength) {
const randomIndex = Math.floor(Math.random() * inputArray.length);
outputArray.push(inputArray[randomIndex]);
}
return outputArray;
}
}

View File

@ -10,11 +10,13 @@ import { ItemRateReadService } from 'src/modules/item-related/item-rate/data/ser
import { FilterItemRateDto } from 'src/modules/item-related/item-rate/infrastructure/dto/filter-item-rate.dto';
import { ItemRateEntity } from 'src/modules/item-related/item-rate/domain/entities/item-rate.entity';
import { IndexItemRatesManager } from './managers/index-item-rates.manager';
import { IndexItemQueueManager } from './managers/index-queue-item.manager';
@Injectable()
export class ItemReadOrchestrator extends BaseReadOrchestrator<ItemEntity> {
constructor(
private indexManager: IndexItemManager,
private indexQueueManager: IndexItemQueueManager,
private detailManager: DetailItemManager,
private indexRateManager: IndexItemRatesManager,
private serviceData: ItemReadService,
@ -30,6 +32,13 @@ export class ItemReadOrchestrator extends BaseReadOrchestrator<ItemEntity> {
return this.indexManager.getResult();
}
async indexQueue(params): Promise<PaginationResponse<ItemEntity>> {
this.indexQueueManager.setFilterParam(params);
this.indexQueueManager.setService(this.serviceData, TABLE_NAME.ITEM);
await this.indexQueueManager.execute();
return this.indexQueueManager.getResult();
}
async detail(dataId: string): Promise<ItemEntity> {
this.detailManager.setData(dataId);
this.detailManager.setService(this.serviceData, TABLE_NAME.ITEM);

View File

@ -0,0 +1,68 @@
import { Injectable } from '@nestjs/common';
import { BaseIndexManager } from 'src/core/modules/domain/usecase/managers/base-index.manager';
import { ItemEntity } from '../../entities/item.entity';
import { SelectQueryBuilder } from 'typeorm';
import {
Param,
RelationParam,
} from 'src/core/modules/domain/entities/base-filter.entity';
import { STATUS } from 'src/core/strings/constants/base.constants';
@Injectable()
export class IndexItemQueueManager extends BaseIndexManager<ItemEntity> {
async prepareData(): Promise<void> {
return;
}
async beforeProcess(): Promise<void> {
return;
}
async afterProcess(): Promise<void> {
return;
}
get relations(): RelationParam {
return {
// relation only join (for query purpose)
joinRelations: [],
// relation join and select (relasi yang ingin ditampilkan),
selectRelations: [],
// relation yang hanya ingin dihitung (akan return number)
countRelations: [],
};
}
get selects(): string[] {
return [
`${this.tableName}.id`,
`${this.tableName}.created_at`,
`${this.tableName}.name`,
];
}
get specificFilter(): Param[] {
return [
{
cols: `${this.tableName}.name`,
data: this.filterParam.names,
},
];
}
setQueryFilter(
queryBuilder: SelectQueryBuilder<ItemEntity>,
): SelectQueryBuilder<ItemEntity> {
queryBuilder.andWhere(`${this.tableName}.status = :status`, {
status: STATUS.ACTIVE,
});
queryBuilder.andWhere(`${this.tableName}.use_queue = :queue`, {
queue: true,
});
return queryBuilder;
}
}

View File

@ -0,0 +1,6 @@
import { BaseFilterDto } from 'src/core/modules/infrastructure/dto/base-filter.dto';
import { BaseFilterEntity } from 'src/core/modules/domain/entities/base-filter.entity';
export class FilterItemQueueDto
extends BaseFilterDto
implements BaseFilterEntity {}

View File

@ -134,7 +134,15 @@ export class ItemDto extends BaseStatusDto implements ItemEntity {
},
],
})
@IsArray()
@IsArray({
message: (body) => {
const value = body.value;
if (!value || value?.length === 0) {
return 'Product bundling tidak boleh kosong.';
}
return 'Product bundling tidak sesuai.';
},
})
@ValidateIf((body) => body.item_type.toLowerCase() == ItemType.BUNDLING)
bundling_items: ItemEntity[];
}

View File

@ -6,7 +6,7 @@ import { ItemEntity } from '../domain/entities/item.entity';
import { ItemReadOrchestrator } from '../domain/usecases/item-read.orchestrator';
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
import { MODULE_NAME } from 'src/core/strings/constants/module.constants';
import { Public } from 'src/core/guards';
import { ExcludePrivilege, Public } from 'src/core/guards';
import { ItemRateEntity } from '../../item-rate/domain/entities/item-rate.entity';
import { FilterItemRateDto } from '../../item-rate/infrastructure/dto/filter-item-rate.dto';
@ -40,3 +40,19 @@ export class ItemReadController {
return await this.orchestrator.indexRate(params);
}
}
@ApiTags(`Item Queue - Read`)
@Controller(`v1/item-queue`)
@Public(true)
export class ItemReadQueueController {
constructor(private orchestrator: ItemReadOrchestrator) {}
@Get()
@Pagination()
@ExcludePrivilege()
async indexQueue(
@Query() params: FilterItemDto,
): Promise<PaginationResponse<ItemEntity>> {
return await this.orchestrator.indexQueue(params);
}
}

View File

@ -4,7 +4,10 @@ import { TypeOrmModule } from '@nestjs/typeorm';
import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants';
import { ItemDataService } from './data/services/item-data.service';
import { ItemReadService } from './data/services/item-read.service';
import { ItemReadController } from './infrastructure/item-read.controller';
import {
ItemReadController,
ItemReadQueueController,
} from './infrastructure/item-read.controller';
import { ItemReadOrchestrator } from './domain/usecases/item-read.orchestrator';
import { ItemDataController } from './infrastructure/item-data.controller';
import { ItemDataOrchestrator } from './domain/usecases/item-data.orchestrator';
@ -26,6 +29,7 @@ import { ItemRateModel } from '../item-rate/data/models/item-rate.model';
import { ItemRateReadService } from '../item-rate/data/services/item-rate-read.service';
import { IndexItemRatesManager } from './domain/usecases/managers/index-item-rates.manager';
import { UpdateItemRatePriceManager } from './domain/usecases/managers/update-item-rate-price.manager';
import { IndexItemQueueManager } from './domain/usecases/managers/index-queue-item.manager';
@Global()
@Module({
@ -37,9 +41,14 @@ import { UpdateItemRatePriceManager } from './domain/usecases/managers/update-it
),
CqrsModule,
],
controllers: [ItemDataController, ItemReadController],
controllers: [
ItemDataController,
ItemReadController,
ItemReadQueueController,
],
providers: [
IndexItemManager,
IndexItemQueueManager,
IndexItemRatesManager,
DetailItemManager,
CreateItemManager,
@ -63,6 +72,7 @@ import { UpdateItemRatePriceManager } from './domain/usecases/managers/update-it
],
exports: [
IndexItemManager,
IndexItemQueueManager,
IndexItemRatesManager,
DetailItemManager,
CreateItemManager,

View File

@ -99,7 +99,6 @@ export class ReportService extends BaseReportService {
const builder = new ReportQueryBuilder(reportConfig, queryModel);
const SQL = builder.getSql();
const queryResult = await this.dataSource.query(SQL);
const realData = [];
const configColumns = reportConfig.column_configs;

View File

@ -0,0 +1,10 @@
import { REPORT_GROUP } from '../../../constant';
import { ReportConfigEntity } from '../../../entities/report-config.entity';
import IncomeReportPerItemMaster from '../../transaction-report/configs/income-per-item-master';
export default <ReportConfigEntity>{
...IncomeReportPerItemMaster,
group_name: REPORT_GROUP.tenant_report,
unique_name: `${REPORT_GROUP.tenant_report}__income_per_item_master`,
label: 'Pendapatan',
};

View File

@ -1,39 +0,0 @@
import { DATA_FORMAT, DATA_TYPE, REPORT_GROUP } from '../../../constant';
import { ReportConfigEntity } from '../../../entities/report-config.entity';
export default <ReportConfigEntity>{
group_name: REPORT_GROUP.tenant_report,
unique_name: `${REPORT_GROUP.tenant_report}__sample`,
label: 'Sample Tenant Report',
table_schema: 'season_types main',
main_table_alias: 'main',
defaultOrderBy: [],
lowLevelOrderBy: [],
filter_period_config: {
hidden: true,
},
column_configs: [
{
column: 'main__created_at',
query: 'main.created_at',
label: 'Created Date',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.DATE_EPOCH,
},
{
column: 'main__updated_at',
query: 'main.updated_at',
label: 'Updated Date',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.DATE_EPOCH,
},
{
column: 'main__name',
query: 'main.name',
label: 'Name',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
],
filter_configs: [],
};

View File

@ -1,6 +1,6 @@
import { ReportConfigEntity } from '../../entities/report-config.entity';
import SampleReport from './configs/sample.report';
import IncomeReportPerItemMaster from './configs/income-per-item-master';
export const TenantReportConfig: ReportConfigEntity[] = [
// SampleReport
IncomeReportPerItemMaster,
];

View File

@ -39,17 +39,16 @@ export default <ReportConfigEntity>{
},
{
column: 'main__booking_date',
query: 'main.booking_date',
query: `to_char(main.booking_date, 'DD-MM-YYYY')`,
label: 'Tgl. Booking',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.DATE_TIMESTAMP,
date_format: 'DD/MM/YYYY',
format: DATA_FORMAT.TEXT,
},
{
column: 'main__no_of_group',
query: 'main.no_of_group',
query: 'main.no_of_group::NUMERIC',
label: '#Visitor',
type: DATA_TYPE.DIMENSION,
type: DATA_TYPE.MEASURE,
format: DATA_FORMAT.NUMBER,
},
{
@ -111,11 +110,10 @@ export default <ReportConfigEntity>{
{
column: 'main__invoice_date',
query: 'main.invoice_date',
query: `to_char(main.invoice_date, 'DD-MM-YYYY')`,
label: 'Tgl. Invoice',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.DATE_TIMESTAMP,
date_format: 'DD/MM/YYYY',
format: DATA_FORMAT.TEXT,
},
{
column: 'main__invoice_code',
@ -126,19 +124,17 @@ export default <ReportConfigEntity>{
},
{
column: 'main__settlement_date',
query: 'main.settlement_date',
query: `to_char(main.settlement_date, 'DD-MM-YYYY')`,
label: 'Tgl Settlement',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.DATE_TIMESTAMP,
date_format: 'DD/MM/YYYY',
format: DATA_FORMAT.TEXT,
},
{
column: 'refund__request_date',
query: 'refund.request_date',
query: `to_char(refund.request_date, 'DD-MM-YYYY')`,
label: 'Request Refund',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.DATE_TIMESTAMP,
date_format: 'DD/MM/YYYY',
format: DATA_FORMAT.TEXT,
},
{
column: 'refund__code',
@ -149,13 +145,11 @@ export default <ReportConfigEntity>{
},
{
column: 'refund__refund_date',
query: 'refund.refund_date',
query: `to_char(refund.refund_date, 'DD-MM-YYYY')`,
label: 'Tgl. Refund',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.DATE_TIMESTAMP,
date_format: 'DD/MM/YYYY',
format: DATA_FORMAT.TEXT,
},
{
column: 'main__creator_name',
query: 'main.creator_name',
@ -190,6 +184,7 @@ export default <ReportConfigEntity>{
filter_column: 'main__booking_date',
field_type: FILTER_FIELD_TYPE.date_range_picker,
filter_type: FILTER_TYPE.DATE_IN_RANGE_TIMESTAMP,
date_format: 'DD-MM-YYYY',
},
{
filed_label: 'Sumber',
@ -231,6 +226,7 @@ export default <ReportConfigEntity>{
filter_column: 'main__invoice_date',
field_type: FILTER_FIELD_TYPE.date_range_picker,
filter_type: FILTER_TYPE.DATE_IN_RANGE_TIMESTAMP,
date_format: 'DD-MM-YYYY',
},
{
filed_label: 'Kode Invoice',
@ -243,12 +239,14 @@ export default <ReportConfigEntity>{
filter_column: 'main__settlement_date',
field_type: FILTER_FIELD_TYPE.date_range_picker,
filter_type: FILTER_TYPE.DATE_IN_RANGE_TIMESTAMP,
date_format: 'DD-MM-YYYY',
},
{
filed_label: 'Request Refund',
filter_column: 'refund__request_date',
field_type: FILTER_FIELD_TYPE.date_range_picker,
filter_type: FILTER_TYPE.DATE_IN_RANGE_TIMESTAMP,
date_format: 'DD-MM-YYYY',
},
{
filed_label: 'Kode Refund',
@ -261,6 +259,7 @@ export default <ReportConfigEntity>{
filter_column: 'refund__refund_date',
field_type: FILTER_FIELD_TYPE.date_range_picker,
filter_type: FILTER_TYPE.DATE_IN_RANGE_TIMESTAMP,
date_format: 'DD-MM-YYYY',
},
{
filed_label: 'Dibuat Oleh',

View File

@ -26,14 +26,16 @@ export default <ReportConfigEntity>{
values: [PosLogType.cash_witdrawal],
},
],
whereCondition(filterModel) {
return [`main.created_at is not null`];
},
column_configs: [
{
column: 'main__date',
query: 'main.created_at',
query: `to_char(cast(to_timestamp(main.created_at/1000) as date),'DD-MM-YYYY')`,
label: 'Tanggal',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.DATE_EPOCH,
date_format: 'DD-MM-YYYY',
format: DATA_FORMAT.TEXT,
},
{
column: 'main__time',
@ -64,6 +66,13 @@ export default <ReportConfigEntity>{
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'main__pos_name',
query: 'main.pos_name',
label: 'Nama PoS',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'main__total_balance',
query: 'main.total_balance',
@ -77,7 +86,8 @@ export default <ReportConfigEntity>{
filed_label: 'Tanggal',
filter_column: 'main__date',
field_type: FILTER_FIELD_TYPE.date_range_picker,
filter_type: FILTER_TYPE.DATE_IN_RANGE_EPOCH,
filter_type: FILTER_TYPE.DATE_IN_RANGE_TIMESTAMP,
date_format: 'DD-MM-YYYY',
},
{
filed_label: 'Nama Penarik',
@ -94,8 +104,8 @@ export default <ReportConfigEntity>{
{
filed_label: 'No. PoS',
filter_column: 'main__pos_number',
field_type: FILTER_FIELD_TYPE.input_tag,
filter_type: FILTER_TYPE.TEXT_MULTIPLE_CONTAINS,
field_type: FILTER_FIELD_TYPE.input_number,
filter_type: FILTER_TYPE.NUMBER_EQUAL,
},
],
};

View File

@ -26,14 +26,16 @@ export default <ReportConfigEntity>{
values: [PosLogType.login, PosLogType.logout],
},
],
whereCondition(filterModel) {
return [`main.creator_name is not null`];
},
column_configs: [
{
column: 'main__date',
query: 'main.created_at',
query: `to_char(cast(to_timestamp(main.created_at/1000) as date),'DD-MM-YYYY')`,
label: 'Tanggal',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.DATE_EPOCH,
date_format: 'DD-MM-YYYY',
format: DATA_FORMAT.TEXT,
},
{
column: 'main__time',
@ -64,13 +66,21 @@ export default <ReportConfigEntity>{
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'main__pos_name',
query: 'main.pos_name',
label: 'Nama PoS',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
],
filter_configs: [
{
filed_label: 'Tanggal',
filter_column: 'main__date',
field_type: FILTER_FIELD_TYPE.date_range_picker,
filter_type: FILTER_TYPE.DATE_IN_RANGE_EPOCH,
filter_type: FILTER_TYPE.DATE_IN_RANGE_TIMESTAMP,
date_format: 'DD-MM-YYYY',
},
{
filed_label: 'Tipe',
@ -85,5 +95,11 @@ export default <ReportConfigEntity>{
field_type: FILTER_FIELD_TYPE.input_tag,
filter_type: FILTER_TYPE.TEXT_MULTIPLE_CONTAINS,
},
{
filed_label: 'No. PoS',
filter_column: 'main__pos_number',
field_type: FILTER_FIELD_TYPE.input_number,
filter_type: FILTER_TYPE.NUMBER_EQUAL,
},
],
};

View File

@ -31,7 +31,17 @@ export default <ReportConfigEntity>{
filter_type: FILTER_TYPE.TEXT_IN_MEMBER,
values: [TransactionType.COUNTER],
},
{
column: 'main.is_recap_transaction',
filter_type: FILTER_TYPE.TEXT_EQUAL,
values: [false],
},
],
whereCondition(filterModel) {
return [
`main.discount_percentage is not null or main.discount_value is not null`,
];
},
defaultOrderBy: [],
lowLevelOrderBy: [],
filter_period_config: {
@ -40,12 +50,11 @@ export default <ReportConfigEntity>{
column_configs: [
{
column: 'main__settlement_date',
query: 'main.settlement_date',
label: 'Tanggal Transaksi',
column: 'main__payment_date',
query: `to_char(main.payment_date, 'DD-MM-YYYY')`,
label: 'Tgl. Transaksi',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.DATE_TIMESTAMP,
date_format: 'DD/MM/YYYY',
format: DATA_FORMAT.TEXT,
},
{
column: 's_period_type__name',
@ -56,14 +65,21 @@ export default <ReportConfigEntity>{
},
{
column: 'main__invoice_code',
query: 'main.invoice_code',
label: 'Kode Transaksi',
query: `CASE WHEN main.type != 'counter' THEN main.invoice_code ELSE null END`,
label: 'Kode Booking',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'main__payment_total_profit',
query: 'main.payment_total_profit',
column: 'main__payment_code',
query: `CASE WHEN main.type = 'counter' THEN main.invoice_code ELSE main.payment_code END`,
label: 'Kode Pembayaran',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'main__payment_sub_total',
query: 'main.payment_sub_total',
label: 'Total Transaksi',
type: DATA_TYPE.MEASURE,
format: DATA_FORMAT.CURRENCY,
@ -117,6 +133,13 @@ export default <ReportConfigEntity>{
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'main__creator_counter_name',
query: 'main.creator_counter_name',
label: 'Nama PoS',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'main__customer_name',
query: 'main.customer_name',
@ -141,10 +164,11 @@ export default <ReportConfigEntity>{
],
filter_configs: [
{
filed_label: 'Tanggal Transaksi',
filter_column: 'main__settlement_date',
filed_label: 'Tgl. Transaksi',
filter_column: 'main__payment_date',
field_type: FILTER_FIELD_TYPE.date_range_picker,
filter_type: FILTER_TYPE.DATE_IN_RANGE_TIMESTAMP,
date_format: 'DD-MM-YYYY',
},
{
filed_label: 'Tipe Rate',
@ -173,8 +197,8 @@ export default <ReportConfigEntity>{
{
filed_label: 'No. Pos',
filter_column: 'main__creator_counter_no',
field_type: FILTER_FIELD_TYPE.input_tag,
filter_type: FILTER_TYPE.TEXT_MULTIPLE_CONTAINS,
field_type: FILTER_FIELD_TYPE.input_number,
filter_type: FILTER_TYPE.NUMBER_EQUAL,
},
{
filed_label: 'Nama Pelanggan',

View File

@ -0,0 +1,382 @@
import {
DATA_FORMAT,
DATA_TYPE,
FILTER_FIELD_TYPE,
FILTER_TYPE,
REPORT_GROUP,
} from '../../../constant';
import { ReportConfigEntity } from '../../../entities/report-config.entity';
import { TransactionType } from 'src/modules/transaction/transaction/constants';
import { STATUS } from 'src/core/strings/constants/base.constants';
export default <ReportConfigEntity>{
group_name: REPORT_GROUP.transaction_report,
unique_name: `${REPORT_GROUP.transaction_report}__income_per_item_master`,
label: 'Pendapatan Per Item Master',
table_schema: `transactions main
LEFT JOIN transaction_items tr_item ON tr_item.transaction_id::text = main.id::text
LEFT JOIN transaction_item_breakdowns tr_item_bundling ON tr_item_bundling.transaction_item_id::text = tr_item.id::text
LEFT JOIN refunds refund ON refund.transaction_id = main.id
LEFT JOIN items item ON item.id::text = tr_item.item_id::text
LEFT JOIN users tenant ON tenant.id::text = item.tenant_id::text
LEFT JOIN refund_items refund_item ON refund_item.refund_item_id::text = tr_item.item_id::text`,
main_table_alias: 'main',
whereDefaultConditions: [
{
column: 'main.status',
filter_type: FILTER_TYPE.TEXT_IN_MEMBER,
values: [STATUS.SETTLED, STATUS.REFUNDED, STATUS.PROCESS_REFUND],
},
{
column: 'main.is_recap_transaction',
filter_type: FILTER_TYPE.TEXT_EQUAL,
values: [false],
},
],
defaultOrderBy: [],
lowLevelOrderBy: [],
filter_period_config: {
hidden: true,
},
column_configs: [
{
column: 'main__payment_date',
query: `to_char(main.payment_date, 'DD-MM-YYYY')`,
label: 'Tgl. Pendapatan',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'main__status',
query: 'main.status',
label: 'Status',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.STATUS,
},
{
column: 'item_owner',
query: `CASE WHEN tenant.name is not null THEN tenant.name ELSE 'Company' END`,
label: 'Kepemilikan',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'main__type',
query: 'main.type',
label: 'Sumber',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'main__invoice_code',
query: `CASE WHEN main.type != 'counter' THEN main.invoice_code ELSE null END`,
label: 'Kode Booking',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'main__payment_code',
query: `CASE WHEN main.type = 'counter' THEN main.invoice_code ELSE main.payment_code END`,
label: 'Kode Pembayaran',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'tr_item__item_category_name',
query: 'tr_item.item_category_name',
label: 'Kategori Item',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'tr_item__item_type',
query: 'tr_item.item_type',
label: 'Tipe Item',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'tr_item_bundling__item_name',
query: `CASE WHEN tr_item.item_type = 'bundling' THEN tr_item.item_name ELSE tr_item_bundling.item_name END`,
label: 'Nama Item Bundling',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'tr_item__item_name',
query: `CASE WHEN tr_item.item_type = 'bundling' THEN tr_item_bundling.item_name ELSE tr_item.item_name END`,
label: 'Nama Item ',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'main__customer_type',
query: 'main.customer_type',
label: 'Tipe Pelanggan',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'main__creator_counter_no',
query: 'main.creator_counter_no',
label: 'No.PoS',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'main__creator_counter_name',
query: 'main.creator_counter_name',
label: 'Nama PoS',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'tr_item__qty',
query: 'tr_item.qty',
label: 'Qty',
type: DATA_TYPE.MEASURE,
format: DATA_FORMAT.NUMBER,
},
{
column: 'tr_item_bundling__hpp',
// query: 'tr_item_bundling.hpp',
query: `CASE WHEN tr_item.item_type != 'bundling' THEN tr_item.total_hpp ELSE tr_item_bundling.hpp END`,
label: 'Total HPP',
type: DATA_TYPE.MEASURE,
format: DATA_FORMAT.CURRENCY,
},
{
column: 'tr_item_bundling__total_price',
// query: 'tr_item_bundling.total_price',
query: `CASE WHEN tr_item.item_type != 'bundling' THEN tr_item.total_price ELSE tr_item_bundling.total_price END`,
label: 'Subtotal',
type: DATA_TYPE.MEASURE,
format: DATA_FORMAT.CURRENCY,
},
{
column: 'tr_item_bundling__discount_value',
// query: 'tr_item_bundling.discount_value',
query: `CASE WHEN tr_item.item_type != 'bundling' THEN tr_item.discount_value ELSE tr_item_bundling.discount_value END`,
label: 'Diskon (IDR)',
type: DATA_TYPE.MEASURE,
format: DATA_FORMAT.CURRENCY,
},
{
column: 'tr_item_bundling__total_net_price',
// query: 'tr_item_bundling.total_net_price',
query: `CASE WHEN tr_item.item_type != 'bundling' THEN tr_item.total_net_price ELSE tr_item_bundling.total_net_price END`,
label: 'Total Penjualan',
type: DATA_TYPE.MEASURE,
format: DATA_FORMAT.CURRENCY,
},
{
column: 'tr_item_bundling__payment_total_dpp',
// query: 'tr_item_bundling.payment_total_dpp',
query: `CASE WHEN tr_item.item_type != 'bundling' THEN tr_item.payment_total_dpp ELSE tr_item_bundling.payment_total_dpp END`,
label: 'DPP',
type: DATA_TYPE.MEASURE,
format: DATA_FORMAT.CURRENCY,
},
{
column: 'tr_item_bundling__payment_total_tax',
// query: 'tr_item_bundling.payment_total_tax',
query: `CASE WHEN tr_item.item_type != 'bundling' THEN tr_item.payment_total_tax ELSE tr_item_bundling.payment_total_tax END`,
label: 'Total Pajak',
type: DATA_TYPE.MEASURE,
format: DATA_FORMAT.CURRENCY,
},
{
column: 'tr_item_bundling__total_profit_share',
// query: 'tr_item_bundling.total_profit_share',
query: `CASE WHEN tr_item.item_type != 'bundling' THEN tr_item.total_profit_share ELSE tr_item_bundling.total_profit_share END`,
label: 'Profit Share',
type: DATA_TYPE.MEASURE,
format: DATA_FORMAT.CURRENCY,
},
{
column: 'tr_item_bundling__total_share_tenant',
// query: 'tr_item_bundling.total_share_tenant',
query: `CASE WHEN tr_item.item_type != 'bundling' THEN tr_item.total_share_tenant ELSE tr_item_bundling.total_share_tenant END`,
label: 'Tenant Share',
type: DATA_TYPE.MEASURE,
format: DATA_FORMAT.CURRENCY,
},
{
column: 'refund__refund_date',
query: `to_char(refund.refund_date, 'DD-MM-YYYY')`,
label: 'Tgl. Pengembalian',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'refund__status',
query: 'refund.status',
label: 'Status Pengembalian',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'refund__code',
query: 'refund.code',
label: 'Kode Pengembalian',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'refund_item__qty_refund',
query: 'refund_item.qty_refund',
label: 'Qty Pengembalian',
type: DATA_TYPE.MEASURE,
format: DATA_FORMAT.NUMBER,
},
{
column: 'main__customer_name',
query: 'main.customer_name',
label: 'Nama Pelanggan',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'main__customer_description',
query: 'main.customer_description',
label: 'Deskripsi',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'main__customer_phone',
query: 'main.customer_phone',
label: 'Telepon',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'main__creator_name',
query: 'main.creator_name',
label: 'Dibuat Oleh',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
],
whereCondition(filterModel) {
const queryFilter = [];
const breakdown = filterModel.tr_item__breakdown_bundling;
if (breakdown) {
const value = breakdown.filter.map((item) => {
return item === 'Yes' ? true : false;
});
queryFilter.push(`tr_item.breakdown_bundling in (${value.join()})`);
}
return queryFilter;
},
ignore_filter_keys: ['tr_item__breakdown_bundling'],
filter_configs: [
{
filed_label: 'Tgl. Pendapatan',
filter_column: 'main__payment_date',
field_type: FILTER_FIELD_TYPE.date_range_picker,
filter_type: FILTER_TYPE.DATE_IN_RANGE_TIMESTAMP,
date_format: 'DD-MM-YYYY',
},
{
filed_label: 'Kepemilikan',
filter_column: 'item_owner',
field_type: FILTER_FIELD_TYPE.input_tag,
filter_type: FILTER_TYPE.TEXT_MULTIPLE_CONTAINS,
},
{
filed_label: 'Sumber',
filter_column: 'main__type',
field_type: FILTER_FIELD_TYPE.select,
filter_type: FILTER_TYPE.TEXT_IN_MEMBER,
select_custom_options: [...Object.values(TransactionType)],
},
{
filed_label: 'Kode Booking',
filter_column: 'main__invoice_code',
field_type: FILTER_FIELD_TYPE.input_tag,
filter_type: FILTER_TYPE.TEXT_MULTIPLE_CONTAINS,
},
{
filed_label: 'Kode Pembayaran',
filter_column: 'main__payment_code',
field_type: FILTER_FIELD_TYPE.input_tag,
filter_type: FILTER_TYPE.TEXT_MULTIPLE_CONTAINS,
},
{
filed_label: 'Kategori Item',
filter_column: 'tr_item__item_category_name',
field_type: FILTER_FIELD_TYPE.input_tag,
filter_type: FILTER_TYPE.TEXT_MULTIPLE_CONTAINS,
},
{
filed_label: 'Nama Item',
filter_column: 'tr_item__item_name',
field_type: FILTER_FIELD_TYPE.input_tag,
filter_type: FILTER_TYPE.TEXT_MULTIPLE_CONTAINS,
},
{
filed_label: 'Tipe Item',
filter_column: 'tr_item__item_type',
field_type: FILTER_FIELD_TYPE.input_tag,
filter_type: FILTER_TYPE.TEXT_MULTIPLE_CONTAINS,
},
{
filed_label: 'Nama Item Bundling',
filter_column: 'tr_item_bundling__item_name',
field_type: FILTER_FIELD_TYPE.input_tag,
filter_type: FILTER_TYPE.TEXT_MULTIPLE_CONTAINS,
},
{
filed_label: 'Tipe Pelanggan',
filter_column: 'main__customer_type',
field_type: FILTER_FIELD_TYPE.input_tag,
filter_type: FILTER_TYPE.TEXT_MULTIPLE_CONTAINS,
},
{
filed_label: 'No. PoS',
filter_column: 'main__creator_counter_no',
field_type: FILTER_FIELD_TYPE.input_number,
filter_type: FILTER_TYPE.NUMBER_EQUAL,
},
{
filed_label: 'Nama PoS',
filter_column: 'main__creator_counter_name',
field_type: FILTER_FIELD_TYPE.input_tag,
filter_type: FILTER_TYPE.TEXT_MULTIPLE_CONTAINS,
},
{
filed_label: 'Tgl. Pengembalian',
filter_column: 'refund__refund_date',
field_type: FILTER_FIELD_TYPE.date_range_picker,
filter_type: FILTER_TYPE.DATE_IN_RANGE_TIMESTAMP,
date_format: 'DD-MM-YYYY',
},
{
filed_label: 'Kode Pengembalian',
filter_column: 'refund__code',
field_type: FILTER_FIELD_TYPE.input_tag,
filter_type: FILTER_TYPE.TEXT_MULTIPLE_CONTAINS,
},
{
filed_label: 'Nama Pelanggan',
filter_column: 'main__customer_name',
field_type: FILTER_FIELD_TYPE.input_tag,
filter_type: FILTER_TYPE.TEXT_MULTIPLE_CONTAINS,
},
{
filed_label: 'Bank/Issuer',
filter_column: 'main__payment_type_method_name',
field_type: FILTER_FIELD_TYPE.input_tag,
filter_type: FILTER_TYPE.TEXT_MULTIPLE_CONTAINS,
},
{
filed_label: 'Dibuat Oleh',
filter_column: 'main__creator_name',
field_type: FILTER_FIELD_TYPE.input_tag,
filter_type: FILTER_TYPE.TEXT_MULTIPLE_CONTAINS,
},
],
};

View File

@ -26,6 +26,11 @@ export default <ReportConfigEntity>{
filter_type: FILTER_TYPE.TEXT_IN_MEMBER,
values: [STATUS.SETTLED, STATUS.REFUNDED, STATUS.PROCESS_REFUND],
},
{
column: 'main.is_recap_transaction',
filter_type: FILTER_TYPE.TEXT_EQUAL,
values: [false],
},
],
defaultOrderBy: [],
lowLevelOrderBy: [],
@ -35,12 +40,18 @@ export default <ReportConfigEntity>{
column_configs: [
{
column: 'main__settlement_date',
query: 'main.settlement_date',
label: 'Tanggal Pendapatan',
column: 'main__payment_date',
query: `to_char(main.payment_date, 'DD-MM-YYYY')`,
label: 'Tgl. Pendapatan',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.DATE_TIMESTAMP,
date_format: 'DD/MM/YYYY',
format: DATA_FORMAT.TEXT,
},
{
column: 'main__status',
query: 'main.status',
label: 'Status',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.STATUS,
},
{
column: 'item_owner',
@ -58,14 +69,14 @@ export default <ReportConfigEntity>{
},
{
column: 'main__invoice_code',
query: 'main.invoice_code',
query: `CASE WHEN main.type != 'counter' THEN main.invoice_code ELSE null END`,
label: 'Kode Booking',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'main__payment_code',
query: 'main.payment_code',
query: `CASE WHEN main.type = 'counter' THEN main.invoice_code ELSE main.payment_code END`,
label: 'Kode Pembayaran',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
@ -77,6 +88,13 @@ export default <ReportConfigEntity>{
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'tr_item__item_type',
query: 'tr_item.item_type',
label: 'Tipe Item',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'tr_item__item_name',
query: 'tr_item.item_name',
@ -98,11 +116,18 @@ export default <ReportConfigEntity>{
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'main__creator_counter_name',
query: 'main.creator_counter_name',
label: 'Nama PoS',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'tr_item__qty',
query: 'tr_item.qty',
label: 'Qty',
type: DATA_TYPE.DIMENSION,
type: DATA_TYPE.MEASURE,
format: DATA_FORMAT.NUMBER,
},
{
@ -112,22 +137,61 @@ export default <ReportConfigEntity>{
type: DATA_TYPE.MEASURE,
format: DATA_FORMAT.CURRENCY,
},
// TODO => tambahkan total dpp per item
// TODO => tambahkan total tax
{
column: 'tr_item__total_price',
query: 'tr_item.total_price',
label: 'Subtotal',
type: DATA_TYPE.MEASURE,
format: DATA_FORMAT.CURRENCY,
},
{
column: 'tr_item__discount_value',
query: 'tr_item.discount_value',
label: 'Diskon (IDR)',
type: DATA_TYPE.MEASURE,
format: DATA_FORMAT.CURRENCY,
},
{
column: 'tr_item__total_net_price',
query: 'tr_item.total_net_price',
label: 'Total Penjualan',
type: DATA_TYPE.MEASURE,
format: DATA_FORMAT.CURRENCY,
},
{
column: 'tr_item__payment_total_dpp',
query: 'tr_item.payment_total_dpp',
label: 'DPP',
type: DATA_TYPE.MEASURE,
format: DATA_FORMAT.CURRENCY,
},
{
column: 'tr_item__payment_total_tax',
query: 'tr_item.payment_total_tax',
label: 'Total Pajak',
type: DATA_TYPE.MEASURE,
format: DATA_FORMAT.CURRENCY,
},
{
column: 'tr_item__total_profit_share',
query: 'tr_item.total_profit_share',
label: 'Profit Share',
type: DATA_TYPE.MEASURE,
format: DATA_FORMAT.CURRENCY,
},
{
column: 'tr_item__total_share_tenant',
query: 'tr_item.total_share_tenant',
label: 'Tenant Share',
type: DATA_TYPE.MEASURE,
format: DATA_FORMAT.CURRENCY,
},
{
column: 'refund__refund_date',
query: 'refund.refund_date',
label: 'Tanggal Pengembalian',
query: `to_char(refund.refund_date, 'DD-MM-YYYY')`,
label: 'Tgl. Pengembalian',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.DATE_TIMESTAMP,
date_format: 'DD/MM/YYYY',
format: DATA_FORMAT.TEXT,
},
{
column: 'refund__status',
@ -147,39 +211,9 @@ export default <ReportConfigEntity>{
column: 'refund_item__qty_refund',
query: 'refund_item.qty_refund',
label: 'Qty Pengembalian',
type: DATA_TYPE.DIMENSION,
type: DATA_TYPE.MEASURE,
format: DATA_FORMAT.NUMBER,
},
{
column: 'refund_item__refund_total',
query: '(refund_item.refund_total * -1)',
label: 'Total Pengembalian',
type: DATA_TYPE.MEASURE,
format: DATA_FORMAT.CURRENCY,
},
{
column: 'transaction_balance',
query: `CASE WHEN refund.id is null THEN tr_item.total_price ELSE tr_item.total_price - refund_item.refund_total END`,
label: 'Balance',
type: DATA_TYPE.MEASURE,
format: DATA_FORMAT.CURRENCY,
},
{
column: 'tr_item__item_tenant_share_margin',
query: 'tr_item.item_tenant_share_margin',
label: 'Profile Share (IDR)',
type: DATA_TYPE.MEASURE,
format: DATA_FORMAT.CURRENCY,
},
{
column: 'tenant_income',
query: 'tr_item.total_price - tr_item.item_tenant_share_margin',
label: 'Pendapatan Tenant',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.CURRENCY,
},
{
column: 'main__customer_name',
query: 'main.customer_name',
@ -211,10 +245,11 @@ export default <ReportConfigEntity>{
],
filter_configs: [
{
filed_label: 'Tanggal Pendapatan',
filter_column: 'main__settlement_date',
filed_label: 'Tgl. Pendapatan',
filter_column: 'main__payment_date',
field_type: FILTER_FIELD_TYPE.date_range_picker,
filter_type: FILTER_TYPE.DATE_IN_RANGE_TIMESTAMP,
date_format: 'DD-MM-YYYY',
},
{
filed_label: 'Kepemilikan',
@ -262,14 +297,21 @@ export default <ReportConfigEntity>{
{
filed_label: 'No. PoS',
filter_column: 'main__creator_counter_no',
field_type: FILTER_FIELD_TYPE.input_number,
filter_type: FILTER_TYPE.NUMBER_EQUAL,
},
{
filed_label: 'Nama PoS',
filter_column: 'main__creator_counter_name',
field_type: FILTER_FIELD_TYPE.input_tag,
filter_type: FILTER_TYPE.TEXT_MULTIPLE_CONTAINS,
},
{
filed_label: 'Tanggal Pengembalian',
filed_label: 'Tgl. Pengembalian',
filter_column: 'refund__refund_date',
field_type: FILTER_FIELD_TYPE.date_range_picker,
filter_type: FILTER_TYPE.DATE_IN_RANGE_TIMESTAMP,
date_format: 'DD-MM-YYYY',
},
{
filed_label: 'Kode Pengembalian',

View File

@ -29,6 +29,11 @@ export default <ReportConfigEntity>{
filter_type: FILTER_TYPE.TEXT_IN_MEMBER,
values: [STATUS.SETTLED, STATUS.REFUNDED, STATUS.PROCESS_REFUND],
},
{
column: 'main.is_recap_transaction',
filter_type: FILTER_TYPE.TEXT_EQUAL,
values: [false],
},
],
defaultOrderBy: [],
lowLevelOrderBy: [],
@ -38,12 +43,18 @@ export default <ReportConfigEntity>{
column_configs: [
{
column: 'main__settlement_date',
query: 'main.settlement_date',
label: 'Tanggal Pendapatan',
column: 'main__payment_date',
query: `to_char(main.payment_date, 'DD-MM-YYYY')`,
label: 'Tgl. Pendapatan',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.DATE_TIMESTAMP,
date_format: 'DD/MM/YYYY',
format: DATA_FORMAT.TEXT,
},
{
column: 'main__status',
query: 'main.status',
label: 'Status',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.STATUS,
},
{
column: 'main__type',
@ -61,14 +72,14 @@ export default <ReportConfigEntity>{
},
{
column: 'main__invoice_code',
query: 'main.invoice_code',
query: `CASE WHEN main.type != 'counter' THEN main.invoice_code ELSE null END`,
label: 'Kode Booking',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'main__payment_code',
query: 'main.payment_code',
query: `CASE WHEN main.type = 'counter' THEN main.invoice_code ELSE main.payment_code END`,
label: 'Kode Pembayaran',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
@ -88,12 +99,19 @@ export default <ReportConfigEntity>{
format: DATA_FORMAT.TEXT,
},
{
column: 'main__no_of_group',
query: 'main.no_of_group',
label: '#Visitor',
column: 'main__creator_counter_name',
query: 'main.creator_counter_name',
label: 'Nama PoS',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'main__no_of_group',
query: 'main.no_of_group::NUMERIC',
label: '#Visitor',
type: DATA_TYPE.MEASURE,
format: DATA_FORMAT.NUMBER,
},
{
column: 'item__total_hpp_item',
query: 'item.total_hpp_item',
@ -102,9 +120,30 @@ export default <ReportConfigEntity>{
format: DATA_FORMAT.CURRENCY,
},
{
column: 'main__reconciliation_mdr',
query: 'main.reconciliation_mdr',
label: 'MDR',
column: 'main__payment_sub_total',
query: 'main.payment_sub_total',
label: 'Subtotal',
type: DATA_TYPE.MEASURE,
format: DATA_FORMAT.CURRENCY,
},
{
column: 'main__discount_percentage',
query: 'main.discount_percentage',
label: 'Diskon (%)',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.NUMBER,
},
{
column: 'main__discount_value',
query: 'main.discount_value',
label: 'Diskon (IDR)',
type: DATA_TYPE.MEASURE,
format: DATA_FORMAT.CURRENCY,
},
{
column: 'main__payment_total',
query: 'main.payment_total',
label: 'Total Penjualan',
type: DATA_TYPE.MEASURE,
format: DATA_FORMAT.CURRENCY,
},
@ -123,33 +162,18 @@ export default <ReportConfigEntity>{
format: DATA_FORMAT.CURRENCY,
},
{
column: 'main__discount_percentage',
query: 'main.discount_percentage',
label: 'Diskon (%)',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.NUMBER,
},
{
column: 'main__discount_value',
query: 'main.discount_value',
label: 'Diskon (IDR)',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.CURRENCY,
},
{
column: 'main__payment_total',
query: 'main.payment_total',
label: 'Total Penjualan',
type: DATA_TYPE.DIMENSION,
column: 'main__payment_total_share',
query: 'main.payment_total_share',
label: 'Profit Share',
type: DATA_TYPE.MEASURE,
format: DATA_FORMAT.CURRENCY,
},
{
column: 'refund__refund_date',
query: 'refund.refund_date',
label: 'Tanggal Pengembalian',
query: `to_char(refund.refund_date, 'DD-MM-YYYY')`,
label: 'Tgl. Pengembalian',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.DATE_TIMESTAMP,
date_format: 'DD/MM/YYYY',
format: DATA_FORMAT.TEXT,
},
{
column: 'refund__status',
@ -165,20 +189,20 @@ export default <ReportConfigEntity>{
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'refund__refund_total',
query: '(refund.refund_total * -1)',
label: 'Total Pengembalian',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.CURRENCY,
},
{
column: 'transaction_balance',
query: `CASE WHEN refund.id is null THEN main.payment_total ELSE main.payment_total - refund.refund_total END`,
label: 'Balance',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.CURRENCY,
},
// {
// column: 'refund__refund_total',
// query: '(refund.refund_total * -1)',
// label: 'Total Pengembalian',
// type: DATA_TYPE.MEASURE,
// format: DATA_FORMAT.CURRENCY,
// },
// {
// column: 'transaction_balance',
// query: `CASE WHEN refund.id is null THEN main.payment_total ELSE main.payment_total - refund.refund_total END`,
// label: 'Balance',
// type: DATA_TYPE.MEASURE,
// format: DATA_FORMAT.CURRENCY,
// },
{
column: 'main__discount_code',
query: 'main.discount_code',
@ -252,11 +276,13 @@ export default <ReportConfigEntity>{
],
filter_configs: [
{
filed_label: 'Tanggal Pendapatan',
filter_column: 'main__settlement_date',
filed_label: 'Tgl. Pendapatan',
filter_column: 'main__payment_date',
field_type: FILTER_FIELD_TYPE.date_range_picker,
filter_type: FILTER_TYPE.DATE_IN_RANGE_TIMESTAMP,
date_format: 'DD-MM-YYYY',
},
{
filed_label: 'Sumber',
filter_column: 'main__type',
@ -291,14 +317,21 @@ export default <ReportConfigEntity>{
{
filed_label: 'No. PoS',
filter_column: 'main__creator_counter_no',
field_type: FILTER_FIELD_TYPE.input_number,
filter_type: FILTER_TYPE.NUMBER_EQUAL,
},
{
filed_label: 'Nama PoS',
filter_column: 'main__creator_counter_name',
field_type: FILTER_FIELD_TYPE.input_tag,
filter_type: FILTER_TYPE.TEXT_MULTIPLE_CONTAINS,
},
{
filed_label: 'Tanggal Pengembalian',
filed_label: 'Tgl. Pengembalian',
filter_column: 'refund__refund_date',
field_type: FILTER_FIELD_TYPE.date_range_picker,
filter_type: FILTER_TYPE.DATE_IN_RANGE_TIMESTAMP,
date_format: 'DD-MM-YYYY',
},
{
filed_label: 'Kode Pengembalian',

View File

@ -37,20 +37,25 @@ export default <ReportConfigEntity>{
format: DATA_FORMAT.TEXT,
},
{
column: 'main__settlement_date',
query: 'main.settlement_date',
label: 'Tgl. Pendapatan',
column: 'main__payment_date',
query: `CASE WHEN main.payment_date is not null THEN to_char(main.payment_date, 'DD-MM-YYYY') ELSE null END`,
label: 'Tgl. Transaksi',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.DATE_TIMESTAMP,
date_format: 'DD/MM/YYYY',
format: DATA_FORMAT.TEXT,
},
{
column: 'main__payment_date_bank',
query: `CASE WHEN main.payment_date_bank is not null THEN to_char(main.payment_date_bank, 'DD-MM-YYYY') ELSE null END`,
label: 'Tgl. Transaksi Bank',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'main__reconciliation_confirm_date',
query: 'main.reconciliation_confirm_date',
query: `CASE WHEN main.reconciliation_confirm_date is not null THEN to_char(cast(to_timestamp(COALESCE(main.reconciliation_confirm_date::NUMERIC)/1000) as date),'DD-MM-YYYY') ELSE null END`,
label: 'Tgl. Konfirmasi',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.DATE_TIMESTAMP,
date_format: 'DD/MM/YYYY',
format: DATA_FORMAT.TEXT,
},
{
column: 'main__payment_code_reference',
@ -94,6 +99,13 @@ export default <ReportConfigEntity>{
type: DATA_TYPE.MEASURE,
format: DATA_FORMAT.CURRENCY,
},
{
column: 'main__payment_total_net_profit',
query: 'main.payment_total_net_profit',
label: 'Net Pendapatan',
type: DATA_TYPE.MEASURE,
format: DATA_FORMAT.CURRENCY,
},
{
column: 'cashier',
query: `CASE WHEN main.type = 'counter' THEN main.creator_name END`,
@ -129,16 +141,25 @@ export default <ReportConfigEntity>{
select_custom_options: [...Object.values(TransactionType)],
},
{
filed_label: 'Tgl. Pendapatan',
filter_column: 'main__settlement_date',
filed_label: 'Tgl. Transaksi',
filter_column: 'main__payment_date',
field_type: FILTER_FIELD_TYPE.date_range_picker,
filter_type: FILTER_TYPE.DATE_IN_RANGE_TIMESTAMP,
date_format: 'DD-MM-YYYY',
},
{
filed_label: 'Tgl. Transaksi Bank',
filter_column: 'main__payment_date_bank',
field_type: FILTER_FIELD_TYPE.date_range_picker,
filter_type: FILTER_TYPE.DATE_IN_RANGE_TIMESTAMP,
date_format: 'DD-MM-YYYY',
},
{
filed_label: 'Tgl. Konfirmasi',
filter_column: 'main__reconciliation_confirm_date',
field_type: FILTER_FIELD_TYPE.date_range_picker,
filter_type: FILTER_TYPE.DATE_IN_RANGE_TIMESTAMP,
date_format: 'DD-MM-YYYY',
},
{
filed_label: 'Referensi',

View File

@ -46,19 +46,17 @@ export default <ReportConfigEntity>{
},
{
column: 'main__request_date',
query: 'main.request_date',
query: `to_char(main.request_date, 'DD-MM-YYYY')`,
label: 'Tgl. Permintaan',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.DATE_TIMESTAMP,
date_format: 'DD/MM/YYYY',
format: DATA_FORMAT.TEXT,
},
{
column: 'main__refund_date',
query: 'main.refund_date',
query: `to_char(main.refund_date, 'DD-MM-YYYY')`,
label: 'Tgl. Refund',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.DATE_TIMESTAMP,
date_format: 'DD/MM/YYYY',
format: DATA_FORMAT.TEXT,
},
{
column: 'tr__payment_code',
@ -69,11 +67,10 @@ export default <ReportConfigEntity>{
},
{
column: 'tr__settlement_date',
query: 'tr.settlement_date',
query: `to_char(tr.settlement_date, 'DD-MM-YYYY')`,
label: 'Tgl. Settlement',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.DATE_EPOCH,
date_format: 'DD/MM/YYYY',
format: DATA_FORMAT.TEXT,
},
{
column: 'tr__payment_total',
@ -185,12 +182,14 @@ export default <ReportConfigEntity>{
filter_column: 'main__request_date',
field_type: FILTER_FIELD_TYPE.date_range_picker,
filter_type: FILTER_TYPE.DATE_IN_RANGE_TIMESTAMP,
date_format: 'DD-MM-YYYY',
},
{
filed_label: 'Tgl. Refund',
filter_column: 'main__refund_date',
field_type: FILTER_FIELD_TYPE.date_range_picker,
filter_type: FILTER_TYPE.DATE_IN_RANGE_TIMESTAMP,
date_format: 'DD-MM-YYYY',
},
{
filed_label: 'Kode Settlement',
@ -203,6 +202,7 @@ export default <ReportConfigEntity>{
filter_column: 'tr__settlement_date',
field_type: FILTER_FIELD_TYPE.date_range_picker,
filter_type: FILTER_TYPE.DATE_IN_RANGE_TIMESTAMP,
date_format: 'DD-MM-YYYY',
},
{
filed_label: 'Bank Tujuan',

View File

@ -0,0 +1,136 @@
import {
DATA_FORMAT,
DATA_TYPE,
FILTER_FIELD_TYPE,
FILTER_TYPE,
REPORT_GROUP,
} from '../../../constant';
import { ReportConfigEntity } from '../../../entities/report-config.entity';
import { TransactionType } from 'src/modules/transaction/transaction/constants';
import { STATUS } from 'src/core/strings/constants/base.constants';
export default <ReportConfigEntity>{
group_name: REPORT_GROUP.transaction_report,
unique_name: `${REPORT_GROUP.transaction_report}__tax`,
label: 'Tax Pendapatan',
table_schema: `transactions main
left join transaction_taxes tr_taxes on tr_taxes.transaction_id = main.id`,
main_table_alias: 'main',
whereDefaultConditions: [
{
column: 'main.status',
filter_type: FILTER_TYPE.TEXT_IN_MEMBER,
values: [STATUS.SETTLED, STATUS.REFUNDED, STATUS.PROCESS_REFUND],
},
{
column: 'main.is_recap_transaction',
filter_type: FILTER_TYPE.TEXT_EQUAL,
values: [false],
},
],
defaultOrderBy: [],
lowLevelOrderBy: [],
filter_period_config: {
hidden: true,
},
column_configs: [
{
column: 'main__payment_date',
query: `to_char(main.payment_date, 'DD-MM-YYYY')`,
label: 'Tgl. Transaksi',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'main__status',
query: 'main.status',
label: 'Status',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.STATUS,
},
{
column: 'main__type',
query: 'main.type',
label: 'Sumber',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'main__invoice_code',
query: `CASE WHEN main.type != 'counter' THEN main.invoice_code ELSE null END`,
label: 'Kode Booking',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'main__payment_code',
query: `CASE WHEN main.type = 'counter' THEN main.invoice_code ELSE main.payment_code END`,
label: 'Kode Pembayaran',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'main__payment_total',
query: 'main.payment_total',
label: 'Total Penjualan',
type: DATA_TYPE.MEASURE,
format: DATA_FORMAT.CURRENCY,
},
{
column: 'main__payment_total_dpp',
query: 'main.payment_total_dpp',
label: 'DPP',
type: DATA_TYPE.MEASURE,
format: DATA_FORMAT.CURRENCY,
},
{
column: 'tr_taxes__tax_name',
query: 'tr_taxes.tax_name',
label: 'Tipe Tax',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'tr_taxes__tax_total_value',
query: 'tr_taxes.tax_total_value',
label: 'Value Tax',
type: DATA_TYPE.MEASURE,
format: DATA_FORMAT.CURRENCY,
},
],
filter_configs: [
{
filed_label: 'Tgl. Transaksi',
filter_column: 'main__payment_date',
field_type: FILTER_FIELD_TYPE.date_range_picker,
filter_type: FILTER_TYPE.DATE_IN_RANGE_TIMESTAMP,
date_format: 'DD-MM-YYYY',
},
{
filed_label: 'Sumber',
filter_column: 'main__type',
field_type: FILTER_FIELD_TYPE.select,
filter_type: FILTER_TYPE.TEXT_IN_MEMBER,
select_custom_options: [...Object.values(TransactionType)],
},
{
filed_label: 'Kode Booking',
filter_column: 'main__invoice_code',
field_type: FILTER_FIELD_TYPE.input_tag,
filter_type: FILTER_TYPE.TEXT_MULTIPLE_CONTAINS,
},
{
filed_label: 'Kode Pembayaran',
filter_column: 'main__payment_code',
field_type: FILTER_FIELD_TYPE.input_tag,
filter_type: FILTER_TYPE.TEXT_MULTIPLE_CONTAINS,
},
{
filed_label: 'Tipe Tax',
filter_column: 'tr_taxes__tax_name',
field_type: FILTER_FIELD_TYPE.input_tag,
filter_type: FILTER_TYPE.TEXT_MULTIPLE_CONTAINS,
},
],
};

View File

@ -2,6 +2,7 @@ import { ReportConfigEntity } from '../../entities/report-config.entity';
import IncomeReport from './configs/income';
import IncomeReportPerItem from './configs/income-per-item';
import IncomeReportPerItemMaster from './configs/income-per-item-master';
import GivingDiscount from './configs/giving-discounts';
import VisitorsPerRideReport from './configs/visitors-per-ride';
import TimePerRideReport from './configs/time-per-ride';
@ -10,10 +11,12 @@ import RefundsReport from './configs/refunds';
import CashierLogReport from './configs/cashier-log';
import CashWithdrawalsReport from './configs/cash-withdrawals';
import ReconciliationReport from './configs/reconciliation';
import TaxReport from './configs/tax';
export const TransactionReportConfig: ReportConfigEntity[] = [
IncomeReport,
IncomeReportPerItem,
IncomeReportPerItemMaster,
GivingDiscount,
// VisitorsPerRideReport,
// TimePerRideReport,
@ -22,4 +25,5 @@ export const TransactionReportConfig: ReportConfigEntity[] = [
CashierLogReport,
CashWithdrawalsReport,
ReconciliationReport,
TaxReport,
];

View File

@ -12,7 +12,7 @@ export interface ReportColumnConfigEntity {
export interface FilterConfigEntity {
filter_column: string;
filter_type: FILTER_TYPE;
date_format?: string;
filed_label: string;
field_type: string;
hide_field?: boolean;
@ -46,7 +46,7 @@ export interface ReportConfigEntity {
whereDefaultConditions?: {
column: string;
filter_type: FILTER_TYPE;
values: string[];
values: string[] | boolean[] | number[];
}[];
defaultOrderBy?: string[];
lowLevelOrderBy?: string[];

View File

@ -331,7 +331,11 @@ export class ReportQueryBuilder {
groupKeys.forEach(function (key, index) {
const colName = rowGroupCols[index].field;
// whereParts.push(colName + ' = "' + key + '"');
whereParts.push(`${thisSelf.findQueryConfig(colName)} = '${key}'`);
if (!key) {
whereParts.push(`${thisSelf.findQueryConfig(colName)} is null`);
} else {
whereParts.push(`${thisSelf.findQueryConfig(colName)} = '${key}'`);
}
});
}
@ -363,6 +367,7 @@ export class ReportQueryBuilder {
const tableWhereConditions = [...whereCondition, ...whereParts].filter(
Boolean,
);
const defaultWhereConditions = defaultWhereOptions.filter(Boolean);
if (tableWhereConditions.length > 0) {

View File

@ -0,0 +1,56 @@
import { Injectable } from '@nestjs/common';
import {
Param,
RelationParam,
} from 'src/core/modules/domain/entities/base-filter.entity';
import { SalesPriceFormulaEntity } from 'src/modules/transaction/sales-price-formula/domain/entities/sales-price-formula.entity';
import { BaseIndexManager } from 'src/core/modules/domain/usecase/managers/base-index.manager';
import { SelectQueryBuilder } from 'typeorm';
@Injectable()
export class IndexProfitShareFormulaManager extends BaseIndexManager<SalesPriceFormulaEntity> {
setQueryFilter(
queryBuilder: SelectQueryBuilder<SalesPriceFormulaEntity>,
): SelectQueryBuilder<SalesPriceFormulaEntity> {
return queryBuilder;
}
get specificFilter(): Param[] {
return [];
}
async prepareData(): Promise<void> {
return;
}
async beforeProcess(): Promise<void> {
return;
}
async afterProcess(): Promise<void> {
return;
}
get relations(): RelationParam {
return {
// relation only join (for query purpose)
joinRelations: [],
// relation join and select (relasi yang ingin ditampilkan),
selectRelations: [],
// relation yang hanya ingin dihitung (akan return number)
countRelations: [],
};
}
get selects(): string[] {
// return [];
return [
`${this.tableName}.id`,
`${this.tableName}.formula_render`,
`${this.tableName}.formula_string`,
`${this.tableName}.value_for`,
];
}
}

View File

@ -0,0 +1,62 @@
import { Injectable } from '@nestjs/common';
import {
Param,
RelationParam,
} from 'src/core/modules/domain/entities/base-filter.entity';
import { BaseIndexManager } from 'src/core/modules/domain/usecase/managers/base-index.manager';
import { SelectQueryBuilder } from 'typeorm';
import { TaxEntity } from 'src/modules/transaction/tax/domain/entities/tax.entity';
@Injectable()
export class IndexTaxFormulaManager extends BaseIndexManager<TaxEntity> {
setQueryFilter(
queryBuilder: SelectQueryBuilder<TaxEntity>,
): SelectQueryBuilder<TaxEntity> {
return queryBuilder;
}
get specificFilter(): Param[] {
return [
{
cols: `${this.tableName}.status::text`,
isStatus: true,
data: [`'active'`],
},
];
}
async prepareData(): Promise<void> {
return;
}
async beforeProcess(): Promise<void> {
return;
}
async afterProcess(): Promise<void> {
return;
}
get relations(): RelationParam {
return {
// relation only join (for query purpose)
joinRelations: [],
// relation join and select (relasi yang ingin ditampilkan),
selectRelations: [],
// relation yang hanya ingin dihitung (akan return number)
countRelations: [],
};
}
get selects(): string[] {
// return [];
return [
`${this.tableName}.id`,
`${this.tableName}.formula_render`,
`${this.tableName}.formula_string`,
`${this.tableName}.name`,
];
}
}

View File

@ -8,20 +8,21 @@ import {
import { SalesPriceFormulaModel } from 'src/modules/transaction/sales-price-formula/data/models/sales-price-formula.model';
import { ProfitShareFormulaUpdatedEvent } from '../../entities/event/profit-share-formula-updated.event';
import { SalesPriceFormulaEntity } from 'src/modules/transaction/sales-price-formula/domain/entities/sales-price-formula.entity';
import { In } from 'typeorm';
import { STATUS } from 'src/core/strings/constants/base.constants';
import { calculateProfitFormula } from 'src/modules/transaction/sales-price-formula/domain/usecases/managers/helpers/calculation-formula.helper';
// import { In } from 'typeorm';
// import { STATUS } from 'src/core/strings/constants/base.constants';
// import { calculateProfitFormula } from 'src/modules/transaction/sales-price-formula/domain/usecases/managers/helpers/calculation-formula.helper';
@Injectable()
export class UpdateProfitShareFormulaManager extends BaseUpdateManager<SalesPriceFormulaEntity> {
async validateProcess(): Promise<void> {
const taxes = await this.dataServiceFirstOpt.getManyByOptions({
where: {
status: In([STATUS.ACTIVE]),
},
});
// const taxes = await this.dataServiceFirstOpt.getManyByOptions({
// where: {
// status: In([STATUS.ACTIVE]),
// },
// });
calculateProfitFormula(this.data.formula_string, taxes, 10000, 50, true);
// TODO: Save Validation
// calculateProfitFormula(this.data.formula_string, taxes, 10000, 50, true);
return;
}
@ -30,6 +31,10 @@ export class UpdateProfitShareFormulaManager extends BaseUpdateManager<SalesPric
}
async afterProcess(): Promise<void> {
const additionalFormula = this.data.additional;
const taxFormula = this.data.taxes;
this.dataService.create(null, null, additionalFormula);
this.dataServiceFirstOpt.create(null, null, taxFormula);
return;
}

View File

@ -17,7 +17,7 @@ export class ProfitShareFormulaDataOrchestrator {
async update(data): Promise<SalesPriceFormulaEntity> {
const formula = await this.serviceData.getOneByOptions({
where: {
type: FormulaType.PROFIT_SHARE,
type: FormulaType.SALES_PRICE,
},
});

View File

@ -3,14 +3,41 @@ import { DetailProfitShareFormulaManager } from './managers/detail-profit-share-
import { TABLE_NAME } from 'src/core/strings/constants/table.constants';
import { SalesPriceFormulaReadService } from 'src/modules/transaction/sales-price-formula/data/services/sales-price-formula-read.service';
import { SalesPriceFormulaEntity } from 'src/modules/transaction/sales-price-formula/domain/entities/sales-price-formula.entity';
import { IndexProfitShareFormulaManager } from './managers/index-profit-share-formula.manager';
import { IndexTaxFormulaManager } from './managers/tax-formula.manager';
import { TaxReadService } from 'src/modules/transaction/tax/data/services/tax-read.service';
@Injectable()
export class ProfitShareFormulaReadOrchestrator {
constructor(
private detailManager: DetailProfitShareFormulaManager,
private indexManager: IndexProfitShareFormulaManager,
private taxManager: IndexTaxFormulaManager,
private serviceData: SalesPriceFormulaReadService,
private taxServiceData: TaxReadService,
) {}
async index(): Promise<SalesPriceFormulaEntity[]> {
this.indexManager.setFilterParam({});
this.indexManager.setService(this.serviceData, TABLE_NAME.PRICE_FORMULA);
await this.indexManager.execute();
const { data } = this.indexManager.getResult();
return data;
}
async tax(): Promise<Partial<SalesPriceFormulaEntity>[]> {
this.taxManager.setFilterParam({});
this.taxManager.setService(this.taxServiceData, TABLE_NAME.TAX);
await this.taxManager.execute();
const { data } = this.taxManager.getResult();
return data.map((tax) => {
return {
...tax,
value_for: tax.name,
};
});
}
async detail(): Promise<SalesPriceFormulaEntity> {
this.detailManager.setData('');
this.detailManager.setService(this.serviceData, TABLE_NAME.PRICE_FORMULA);

View File

@ -1,4 +1,4 @@
import { Controller, Get, Param } from '@nestjs/common';
import { Controller, Get } from '@nestjs/common';
import { ProfitShareFormulaReadOrchestrator } from '../domain/usecases/profit-share-formula-read.orchestrator';
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
import { Public } from 'src/core/guards';
@ -15,4 +15,14 @@ export class ProfitShareFormulaReadController {
async detail(): Promise<SalesPriceFormulaEntity> {
return await this.orchestrator.detail();
}
@Get('detail')
async breakdown(): Promise<SalesPriceFormulaEntity[]> {
return await this.orchestrator.index();
}
@Get('tax')
async tax(): Promise<Partial<SalesPriceFormulaEntity>[]> {
return await this.orchestrator.tax();
}
}

View File

@ -12,6 +12,9 @@ import { DetailProfitShareFormulaManager } from './domain/usecases/managers/deta
import { SalesPriceFormulaModel } from '../sales-price-formula/data/models/sales-price-formula.model';
import { TaxDataService } from '../tax/data/services/tax-data.service';
import { TaxModel } from '../tax/data/models/tax.model';
import { IndexProfitShareFormulaManager } from './domain/usecases/managers/index-profit-share-formula.manager';
import { IndexTaxFormulaManager } from './domain/usecases/managers/tax-formula.manager';
import { TaxReadService } from '../tax/data/services/tax-read.service';
@Module({
imports: [
@ -29,11 +32,14 @@ import { TaxModel } from '../tax/data/models/tax.model';
providers: [
DetailProfitShareFormulaManager,
UpdateProfitShareFormulaManager,
IndexProfitShareFormulaManager,
IndexTaxFormulaManager,
ProfitShareFormulaDataOrchestrator,
ProfitShareFormulaReadOrchestrator,
TaxDataService,
TaxReadService,
],
})
export class ProfitShareFormulaModule {}

View File

@ -20,6 +20,7 @@ export class BatchConfirmReconciliationManager extends BaseBatchUpdateStatusMana
status: STATUS.SETTLED,
reconciliation_status: this.dataStatus,
payment_code: await generateInvoiceCodeHelper(this.dataService, 'PMY'),
payment_date_bank: data.payment_date_bank ?? new Date(),
});
return;
}

View File

@ -31,6 +31,7 @@ export class ConfirmReconciliationManager extends BaseUpdateStatusManager<Transa
this.dataStatus === STATUS.CONFIRMED
? this.data.payment_date
: this.data.settlement_date,
payment_date_bank: this.data.payment_date_bank ?? new Date(),
});
return;

View File

@ -43,6 +43,7 @@ export class DetailReconciliationManager extends BaseDetailManager<TransactionEn
`${this.tableName}.payment_code_reference`,
`${this.tableName}.payment_code`,
`${this.tableName}.payment_date`,
`${this.tableName}.payment_date_bank`,
`${this.tableName}.payment_total`,
`${this.tableName}.payment_total_net_profit`,

View File

@ -47,6 +47,7 @@ export class IndexReconciliationManager extends BaseIndexManager<TransactionEnti
`${this.tableName}.customer_name`,
`${this.tableName}.creator_counter_no`,
`${this.tableName}.creator_counter_name`,
`${this.tableName}.invoice_code`,
`${this.tableName}.booking_date`,
@ -58,6 +59,7 @@ export class IndexReconciliationManager extends BaseIndexManager<TransactionEnti
`${this.tableName}.payment_code_reference`,
`${this.tableName}.payment_code`,
`${this.tableName}.payment_date`,
`${this.tableName}.payment_date_bank`,
`${this.tableName}.payment_total`,
`${this.tableName}.payment_total_net_profit`,
@ -110,11 +112,20 @@ export class IndexReconciliationManager extends BaseIndexManager<TransactionEnti
});
}
if (this.filterParam.couner_no) {
if (this.filterParam.counter_no) {
queryBuilder.andWhere(
`${this.tableName}.creator_counter_no In (:...counters)`,
{
counters: [this.filterParam.couner_no],
counters: [this.filterParam.counter_no],
},
);
}
if (this.filterParam.counter_name) {
queryBuilder.andWhere(
`${this.tableName}.creator_counter_name In (:...counterNames)`,
{
counterNames: [this.filterParam.counter_name],
},
);
}

View File

@ -146,6 +146,7 @@ export class RecapReconciliationManager extends BaseCustomManager<TransactionEnt
booking_date: payment_date,
payment_date: payment_date,
creator_counter_no: first_transaction.creator_counter_no,
creator_counter_name: first_transaction.creator_counter_name,
payment_type: first_transaction.payment_type_counter,
payment_type_counter: first_transaction.payment_type_counter,
payment_type_method_id: first_transaction.payment_type_method_id,

View File

@ -25,6 +25,7 @@ export class UpdateReconciliationManager extends BaseUpdateManager<TransactionEn
reconciliation_mdr: this.data.reconciliation_mdr ?? null,
payment_total_net_profit: net_profit,
payment_date: this.data.payment_date ?? this.oldData.payment_date,
payment_date_bank: this.data.payment_date_bank ?? null,
});
return;

View File

@ -22,6 +22,9 @@ export class SalesPriceFormulaModel
@Column('varchar', { name: 'formula_string', nullable: true })
formula_string: string;
@Column('varchar', { default: 'dpp' })
value_for: string;
@Column('varchar', { name: 'example_formula', nullable: true })
example_formula: string;

Some files were not shown because too many files have changed in this diff Show More