Merge pull request 'development' (#48) from development into feat/pdf-generator

Reviewed-on: #48
feat/pdf-generator
aswin 2024-08-02 06:32:20 +00:00
commit d1892e7aa5
13 changed files with 223 additions and 88 deletions

View File

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

View File

@ -25,4 +25,10 @@ export class PosLogModel
@Column('varchar', { name: 'creator_id', nullable: true }) @Column('varchar', { name: 'creator_id', nullable: true })
creator_id: string; creator_id: string;
@Column('varchar', { name: 'drawn_by_name', nullable: true })
drawn_by_name: string;
@Column('varchar', { name: 'drawn_by_id', nullable: true })
drawn_by_id: string;
} }

View File

@ -27,7 +27,9 @@ export class RecordPosLogHandler implements IEventHandler<ChangeDocEvent> {
total_balance: data.withdrawal_cash ?? data.opening_cash_balance, total_balance: data.withdrawal_cash ?? data.opening_cash_balance,
pos_number: data.pos_number, pos_number: data.pos_number,
creator_id: data.pos_admin?.id, creator_id: data.pos_admin?.id,
creator_name: data.pos_admin?.name, creator_name: data.pos_admin?.name ?? data.pos_admin?.username,
drawn_by_id: data.withdraw_user?.id,
drawn_by_name: data.withdraw_user?.name ?? data.withdraw_user?.username,
created_at: data.created_at, created_at: data.created_at,
}); });

View File

@ -16,6 +16,13 @@ export default <ReportConfigEntity>{
table_schema: `transactions AS main table_schema: `transactions AS main
LEFT JOIN refunds refund ON refund.transaction_id = main.id`, LEFT JOIN refunds refund ON refund.transaction_id = main.id`,
main_table_alias: 'main', main_table_alias: 'main',
whereDefaultConditions: [
{
column: 'main.type',
filter_type: FILTER_TYPE.TEXT_IN_MEMBER,
values: [TransactionType.ADMIN, TransactionType.ONLINE],
},
],
defaultOrderBy: [], defaultOrderBy: [],
lowLevelOrderBy: [], lowLevelOrderBy: [],
filter_period_config: { filter_period_config: {
@ -41,7 +48,7 @@ export default <ReportConfigEntity>{
{ {
column: 'main__no_of_group', column: 'main__no_of_group',
query: 'main.no_of_group', query: 'main.no_of_group',
label: 'Total Group', label: '#Visitor',
type: DATA_TYPE.DIMENSION, type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.NUMBER, format: DATA_FORMAT.NUMBER,
}, },

View File

@ -1,40 +1,87 @@
import { DATA_FORMAT, DATA_TYPE, REPORT_GROUP } from '../../../constant'; import { PosLogType } from 'src/modules/configuration/log/domain/entities/pos-log.entity';
import {
DATA_FORMAT,
DATA_TYPE,
FILTER_FIELD_TYPE,
FILTER_TYPE,
REPORT_GROUP,
} from '../../../constant';
import { ReportConfigEntity } from '../../../entities/report-config.entity'; import { ReportConfigEntity } from '../../../entities/report-config.entity';
export default <ReportConfigEntity>{ export default <ReportConfigEntity>{
group_name: REPORT_GROUP.transaction_report, group_name: REPORT_GROUP.transaction_report,
unique_name: `${REPORT_GROUP.transaction_report}__cash_withdrawals`, unique_name: `${REPORT_GROUP.transaction_report}__cash_withdrawals`,
label: 'Penarikan Kas', label: 'Penarikan Kas',
table_schema: 'season_types main', table_schema: 'logs_pos main',
main_table_alias: 'main', main_table_alias: 'main',
defaultOrderBy: [], defaultOrderBy: [],
lowLevelOrderBy: [], lowLevelOrderBy: [],
filter_period_config: { filter_period_config: {
hidden: true, hidden: true,
}, },
whereDefaultConditions: [
{
column: 'main.type',
filter_type: FILTER_TYPE.TEXT_IN_MEMBER,
values: [PosLogType.cash_witdrawal],
},
],
column_configs: [ column_configs: [
{ {
column: 'main__created_at', column: 'main__date',
query: 'main.created_at', query: `TO_CHAR(to_timestamp(main.created_at::double precision / 1000), 'DD-MM-YYYY')`,
label: 'Created Date', label: 'Tanggal',
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, type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT, format: DATA_FORMAT.TEXT,
}, },
{
column: 'main__time',
query: `TO_CHAR(to_timestamp(main.created_at::double precision / 1000), 'HH24:MI')`,
label: 'Jam',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'main__drawn_by_name',
query: 'main.drawn_by_name',
label: 'Nama Penarik',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'main__creator_name',
query: 'main.creator_name',
label: 'Nama Kasir',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'main__pos_number',
query: 'main.pos_number',
label: 'No. PoS',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'main__total_balance',
query: 'main.total_balance',
label: 'Total Penarikan',
type: DATA_TYPE.MEASURE,
format: DATA_FORMAT.CURRENCY,
},
],
filter_configs: [
{
filed_label: 'Nama Penarik',
filter_column: 'main__drawn_by_name',
field_type: FILTER_FIELD_TYPE.input_tag,
filter_type: FILTER_TYPE.TEXT_MULTIPLE_CONTAINS,
},
{
filed_label: 'Nama Kasir',
filter_column: 'main__creator_name',
field_type: FILTER_FIELD_TYPE.input_tag,
filter_type: FILTER_TYPE.TEXT_MULTIPLE_CONTAINS,
},
], ],
filter_configs: [],
}; };

View File

@ -1,40 +1,81 @@
import { DATA_FORMAT, DATA_TYPE, REPORT_GROUP } from '../../../constant'; import { PosLogType } from 'src/modules/configuration/log/domain/entities/pos-log.entity';
import {
DATA_FORMAT,
DATA_TYPE,
FILTER_FIELD_TYPE,
FILTER_TYPE,
REPORT_GROUP,
} from '../../../constant';
import { ReportConfigEntity } from '../../../entities/report-config.entity'; import { ReportConfigEntity } from '../../../entities/report-config.entity';
export default <ReportConfigEntity>{ export default <ReportConfigEntity>{
group_name: REPORT_GROUP.transaction_report, group_name: REPORT_GROUP.transaction_report,
unique_name: `${REPORT_GROUP.transaction_report}__cashier_log`, unique_name: `${REPORT_GROUP.transaction_report}__cashier_log`,
label: 'Kasir Log', label: 'Kasir Log',
table_schema: 'season_types main', table_schema: 'logs_pos main',
main_table_alias: 'main', main_table_alias: 'main',
defaultOrderBy: [], defaultOrderBy: [],
lowLevelOrderBy: [], lowLevelOrderBy: [],
filter_period_config: { filter_period_config: {
hidden: true, hidden: true,
}, },
whereDefaultConditions: [
{
column: 'main.type',
filter_type: FILTER_TYPE.TEXT_IN_MEMBER,
values: [PosLogType.login, PosLogType.logout],
},
],
column_configs: [ column_configs: [
{ {
column: 'main__created_at', column: 'main__date',
query: 'main.created_at', query: `TO_CHAR(to_timestamp(main.created_at::double precision / 1000), 'DD-MM-YYYY')`,
label: 'Created Date', label: 'Tanggal',
type: DATA_TYPE.DIMENSION, type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.DATE_EPOCH, format: DATA_FORMAT.TEXT,
}, },
{ {
column: 'main__updated_at', column: 'main__time',
query: 'main.updated_at', query: `TO_CHAR(to_timestamp(main.created_at::double precision / 1000), 'HH24:MI')`,
label: 'Updated Date', label: 'Jam',
type: DATA_TYPE.DIMENSION, type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.DATE_EPOCH, format: DATA_FORMAT.TEXT,
}, },
{ {
column: 'main__name', column: 'main__type',
query: 'main.name', query: 'main.type',
label: 'Name', label: 'Tipe',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'main__creator_name',
query: 'main.creator_name',
label: 'Nama Staff',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT,
},
{
column: 'main__pos_number',
query: 'main.pos_number',
label: 'No. PoS',
type: DATA_TYPE.DIMENSION, type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.TEXT, format: DATA_FORMAT.TEXT,
}, },
], ],
filter_configs: [], filter_configs: [
{
filed_label: 'Tipe',
filter_column: 'main__type',
field_type: FILTER_FIELD_TYPE.select,
filter_type: FILTER_TYPE.TEXT_IN_MEMBER,
select_custom_options: [PosLogType.login, PosLogType.logout],
},
{
filed_label: 'Nama Staff',
filter_column: 'main__creator_name',
field_type: FILTER_FIELD_TYPE.input_tag,
filter_type: FILTER_TYPE.TEXT_MULTIPLE_CONTAINS,
},
],
}; };

View File

@ -18,6 +18,6 @@ export const TransactionReportConfig: ReportConfigEntity[] = [
// TimePerRideReport, // TimePerRideReport,
BookingReport, BookingReport,
RefundsReport, RefundsReport,
// CashierLogReport, CashierLogReport,
// CashWithdrawalsReport, CashWithdrawalsReport,
]; ];

View File

@ -37,11 +37,11 @@ export interface ReportConfigEntity {
table_schema: string; table_schema: string;
main_table_alias?: string; main_table_alias?: string;
customVirtualTableSchema?( // customVirtualTableSchema?(
filterModel: any, // filterModel: any,
findQueryConfig: (column: string) => string, // findQueryConfig: (column: string) => string,
createFilterSql: (key: string, item: any) => string, // createFilterSql: (key: string, item: any) => string,
): string; // ): string;
whereCondition?(filterModel: any): string[]; whereCondition?(filterModel: any): string[];
whereDefaultConditions?: { whereDefaultConditions?: {
column: string; column: string;

View File

@ -23,10 +23,13 @@ export class BatchCancelReconciliationManager extends BaseBatchUpdateStatusManag
}, },
}); });
if ([STATUS.SETTLED, STATUS.WAITING].includes(transaction.status)) { if (
![STATUS.SETTLED, STATUS.WAITING].includes(transaction.status) &&
!data.is_recap_transaction
) {
throw new UnprocessableEntityException({ throw new UnprocessableEntityException({
statusCode: HttpStatus.UNPROCESSABLE_ENTITY, statusCode: HttpStatus.UNPROCESSABLE_ENTITY,
message: `Gagal! tidak bisa batalkan, karena status transaksi tidak settled`, message: `Gagal! tidak bisa batalkan, karena status transaksi tidak settled atau waiting`,
error: 'Unprocessable Entity', error: 'Unprocessable Entity',
}); });
} }

View File

@ -27,10 +27,13 @@ export class CancelReconciliationManager extends BaseUpdateStatusManager<Transac
}, },
}); });
if ([STATUS.SETTLED, STATUS.WAITING].includes(transaction.status)) { if (
![STATUS.SETTLED, STATUS.WAITING].includes(transaction.status) &&
!this.data.is_recap_transaction
) {
throw new UnprocessableEntityException({ throw new UnprocessableEntityException({
statusCode: HttpStatus.UNPROCESSABLE_ENTITY, statusCode: HttpStatus.UNPROCESSABLE_ENTITY,
message: `Gagal! tidak bisa batalkan, karena status transaksi tidak settled`, message: `Gagal! tidak bisa batalkan, karena status transaksi tidak settled atau waiting`,
error: 'Unprocessable Entity', error: 'Unprocessable Entity',
}); });
} else if (this.data.is_recap_transaction) { } else if (this.data.is_recap_transaction) {

View File

@ -48,6 +48,7 @@ export class IndexReconciliationManager extends BaseIndexManager<TransactionEnti
`${this.tableName}.customer_name`, `${this.tableName}.customer_name`,
`${this.tableName}.creator_counter_no`, `${this.tableName}.creator_counter_no`,
`${this.tableName}.invoice_code`,
`${this.tableName}.booking_date`, `${this.tableName}.booking_date`,
`${this.tableName}.payment_type`, `${this.tableName}.payment_type`,
`${this.tableName}.payment_type_method_id`, `${this.tableName}.payment_type_method_id`,

View File

@ -72,16 +72,22 @@ export class RecapReconciliationManager extends BaseCustomManager<TransactionEnt
const { creator_counter_no, payment_type, payment_type_method_id } = const { creator_counter_no, payment_type, payment_type_method_id } =
first_transaction; first_transaction;
const exist = await this.dataService.getOneByOptions({ let query = {
where: {
is_recap_transaction: true, is_recap_transaction: true,
created_at: Between(this.startOfDay, this.endOfDay), created_at: Between(this.startOfDay, this.endOfDay),
creator_counter_no: creator_counter_no, creator_counter_no: creator_counter_no,
payment_type: payment_type, payment_type: payment_type,
payment_type_method_id: payment_type_method_id ?? EMPTY_UUID, };
},
if (payment_type != 'cash')
query['payment_type_method_id'] = payment_type_method_id ?? EMPTY_UUID;
const exist = await this.dataService.getOneByOptions({
where: query,
}); });
if (payment_type == 'cash') console.log(exist, 'das', query);
const new_recap = new TransactionModel(); const new_recap = new TransactionModel();
const total = _.sumBy(this.recapTransactions[recap], (recap) => const total = _.sumBy(this.recapTransactions[recap], (recap) =>
parseFloat(recap.payment_total), parseFloat(recap.payment_total),
@ -89,9 +95,8 @@ export class RecapReconciliationManager extends BaseCustomManager<TransactionEnt
if (exist) { if (exist) {
Object.assign(exist, { Object.assign(exist, {
payment_total: Number(exist.payment_total) + total, payment_total: total,
payment_total_net_profit: payment_total_net_profit: total,
Number(exist.payment_total_net_profit) + total,
editor_id: this.user.id, editor_id: this.user.id,
editor_name: this.user.name, editor_name: this.user.name,
updated_at: new Date().getTime(), updated_at: new Date().getTime(),

View File

@ -4,22 +4,18 @@ import { TransactionDataService } from '../../../data/services/transaction-data.
import { OPERATION, STATUS } from 'src/core/strings/constants/base.constants'; import { OPERATION, STATUS } from 'src/core/strings/constants/base.constants';
import { TransactionModel } from '../../../data/models/transaction.model'; import { TransactionModel } from '../../../data/models/transaction.model';
import { RefundDeletedEvent } from 'src/modules/transaction/refund/domain/entities/event/refund-deleted.event'; import { RefundDeletedEvent } from 'src/modules/transaction/refund/domain/entities/event/refund-deleted.event';
import { RefundCreatedEvent } from 'src/modules/transaction/refund/domain/entities/event/refund-created.event';
@EventsHandler(RefundChangeStatusEvent, RefundDeletedEvent) @EventsHandler(RefundChangeStatusEvent, RefundDeletedEvent, RefundCreatedEvent)
export class RefundUpdatedHandler export class RefundUpdatedHandler
implements IEventHandler<RefundChangeStatusEvent> implements IEventHandler<RefundChangeStatusEvent>
{ {
constructor(private dataService: TransactionDataService) {} constructor(private dataService: TransactionDataService) {}
async handle(event: RefundChangeStatusEvent) { async handle(event: RefundChangeStatusEvent) {
const old_data = event.data.old;
const current_data = event.data.data; const current_data = event.data.data;
let status: STATUS; let status: STATUS;
if (
old_data.status != current_data.data ||
(event.data.op == OPERATION.DELETE && current_data.status != STATUS.DRAFT)
) {
const queryRunner = this.dataService const queryRunner = this.dataService
.getRepository() .getRepository()
.manager.connection.createQueryRunner(); .manager.connection.createQueryRunner();
@ -29,14 +25,18 @@ export class RefundUpdatedHandler
Number(current_data.refund_total ?? 0) == Number(current_data.refund_total ?? 0) ==
Number(current_data.transaction?.payment_total); Number(current_data.transaction?.payment_total);
if (event.data.op == OPERATION.DELETE) status = STATUS.SETTLED; if (
else if (current_data.status == STATUS.PENDING) event.data.op == OPERATION.DELETE ||
status = STATUS.PROCESS_REFUND; current_data.status == STATUS.CANCEL
else if (current_data.status == STATUS.REFUNDED && if_full_refund) )
status = STATUS.SETTLED;
else {
if (current_data.status == STATUS.REFUNDED && if_full_refund)
status = STATUS.REFUNDED; status = STATUS.REFUNDED;
else if (current_data.status == STATUS.REFUNDED && !if_full_refund) else if (current_data.status == STATUS.REFUNDED && !if_full_refund)
status = STATUS.PARTIAL_REFUND; status = STATUS.PARTIAL_REFUND;
else if (current_data.status == STATUS.CANCEL) status = STATUS.SETTLED; else status = STATUS.PROCESS_REFUND;
}
await this.dataService.update( await this.dataService.update(
queryRunner, queryRunner,
@ -49,4 +49,3 @@ export class RefundUpdatedHandler
); );
} }
} }
}