development #48

Merged
aswin merged 13 commits from development into feat/pdf-generator 2024-08-02 06:32:20 +00:00
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 })
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,
pos_number: data.pos_number,
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,
});

View File

@ -16,6 +16,13 @@ export default <ReportConfigEntity>{
table_schema: `transactions AS main
LEFT JOIN refunds refund ON refund.transaction_id = main.id`,
main_table_alias: 'main',
whereDefaultConditions: [
{
column: 'main.type',
filter_type: FILTER_TYPE.TEXT_IN_MEMBER,
values: [TransactionType.ADMIN, TransactionType.ONLINE],
},
],
defaultOrderBy: [],
lowLevelOrderBy: [],
filter_period_config: {
@ -41,7 +48,7 @@ export default <ReportConfigEntity>{
{
column: 'main__no_of_group',
query: 'main.no_of_group',
label: 'Total Group',
label: '#Visitor',
type: DATA_TYPE.DIMENSION,
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';
export default <ReportConfigEntity>{
group_name: REPORT_GROUP.transaction_report,
unique_name: `${REPORT_GROUP.transaction_report}__cash_withdrawals`,
label: 'Penarikan Kas',
table_schema: 'season_types main',
table_schema: 'logs_pos main',
main_table_alias: 'main',
defaultOrderBy: [],
lowLevelOrderBy: [],
filter_period_config: {
hidden: true,
},
whereDefaultConditions: [
{
column: 'main.type',
filter_type: FILTER_TYPE.TEXT_IN_MEMBER,
values: [PosLogType.cash_witdrawal],
},
],
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',
column: 'main__date',
query: `TO_CHAR(to_timestamp(main.created_at::double precision / 1000), 'DD-MM-YYYY')`,
label: 'Tanggal',
type: DATA_TYPE.DIMENSION,
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';
export default <ReportConfigEntity>{
group_name: REPORT_GROUP.transaction_report,
unique_name: `${REPORT_GROUP.transaction_report}__cashier_log`,
label: 'Kasir Log',
table_schema: 'season_types main',
table_schema: 'logs_pos main',
main_table_alias: 'main',
defaultOrderBy: [],
lowLevelOrderBy: [],
filter_period_config: {
hidden: true,
},
whereDefaultConditions: [
{
column: 'main.type',
filter_type: FILTER_TYPE.TEXT_IN_MEMBER,
values: [PosLogType.login, PosLogType.logout],
},
],
column_configs: [
{
column: 'main__created_at',
query: 'main.created_at',
label: 'Created Date',
column: 'main__date',
query: `TO_CHAR(to_timestamp(main.created_at::double precision / 1000), 'DD-MM-YYYY')`,
label: 'Tanggal',
type: DATA_TYPE.DIMENSION,
format: DATA_FORMAT.DATE_EPOCH,
format: DATA_FORMAT.TEXT,
},
{
column: 'main__updated_at',
query: 'main.updated_at',
label: 'Updated Date',
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.DATE_EPOCH,
format: DATA_FORMAT.TEXT,
},
{
column: 'main__name',
query: 'main.name',
label: 'Name',
column: 'main__type',
query: 'main.type',
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,
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,
BookingReport,
RefundsReport,
// CashierLogReport,
// CashWithdrawalsReport,
CashierLogReport,
CashWithdrawalsReport,
];

View File

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

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

View File

@ -4,49 +4,48 @@ import { TransactionDataService } from '../../../data/services/transaction-data.
import { OPERATION, STATUS } from 'src/core/strings/constants/base.constants';
import { TransactionModel } from '../../../data/models/transaction.model';
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
implements IEventHandler<RefundChangeStatusEvent>
{
constructor(private dataService: TransactionDataService) {}
async handle(event: RefundChangeStatusEvent) {
const old_data = event.data.old;
const current_data = event.data.data;
let status: STATUS;
const queryRunner = this.dataService
.getRepository()
.manager.connection.createQueryRunner();
const data = new TransactionModel();
const if_full_refund =
Number(current_data.refund_total ?? 0) ==
Number(current_data.transaction?.payment_total);
if (
old_data.status != current_data.data ||
(event.data.op == OPERATION.DELETE && current_data.status != STATUS.DRAFT)
) {
const queryRunner = this.dataService
.getRepository()
.manager.connection.createQueryRunner();
const data = new TransactionModel();
const if_full_refund =
Number(current_data.refund_total ?? 0) ==
Number(current_data.transaction?.payment_total);
if (event.data.op == OPERATION.DELETE) status = STATUS.SETTLED;
else if (current_data.status == STATUS.PENDING)
status = STATUS.PROCESS_REFUND;
else if (current_data.status == STATUS.REFUNDED && if_full_refund)
event.data.op == OPERATION.DELETE ||
current_data.status == STATUS.CANCEL
)
status = STATUS.SETTLED;
else {
if (current_data.status == STATUS.REFUNDED && if_full_refund)
status = STATUS.REFUNDED;
else if (current_data.status == STATUS.REFUNDED && !if_full_refund)
status = STATUS.PARTIAL_REFUND;
else if (current_data.status == STATUS.CANCEL) status = STATUS.SETTLED;
await this.dataService.update(
queryRunner,
TransactionModel,
{ id: current_data.transaction_id },
{
...data,
status: status,
},
);
else status = STATUS.PROCESS_REFUND;
}
await this.dataService.update(
queryRunner,
TransactionModel,
{ id: current_data.transaction_id },
{
...data,
status: status,
},
);
}
}