development #100
|
@ -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
Binary file not shown.
After Width: | Height: | Size: 504 KiB |
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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',
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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',
|
||||
}
|
|
@ -1 +1,2 @@
|
|||
export const PAGINATION_RESPONSE = 'PAGINATION_RESPONSE';
|
||||
export const GATE_RESPONSE = 'GATE_RESPONSE';
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()],
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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"`,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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"`,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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"`,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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"`,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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"`,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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"`);
|
||||
}
|
||||
}
|
|
@ -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`,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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"`);
|
||||
}
|
||||
}
|
|
@ -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"`);
|
||||
}
|
||||
}
|
|
@ -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"`,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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"`);
|
||||
}
|
||||
}
|
|
@ -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`,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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"`);
|
||||
}
|
||||
}
|
|
@ -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"`);
|
||||
}
|
||||
}
|
|
@ -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"`,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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"`,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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 {}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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',
|
||||
});
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 {}
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
import { IEvent } from 'src/core/strings/constants/interface.constants';
|
||||
|
||||
export class LogUserLoginEvent {
|
||||
constructor(public readonly data: IEvent) {}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -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 {}
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
export interface GateScanEntity {
|
||||
gate_id: string;
|
||||
type: string;
|
||||
uuid: string;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
export interface GateResponseEntity {
|
||||
code: number;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface GateMasterEntity {
|
||||
codes: string[];
|
||||
}
|
|
@ -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 {}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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 {}
|
|
@ -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[];
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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',
|
||||
};
|
|
@ -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: [],
|
||||
};
|
|
@ -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,
|
||||
];
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
],
|
||||
};
|
|
@ -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',
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
],
|
||||
};
|
|
@ -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,
|
||||
];
|
||||
|
|
|
@ -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[];
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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`,
|
||||
];
|
||||
}
|
||||
}
|
|
@ -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`,
|
||||
];
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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`,
|
||||
|
|
|
@ -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],
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue