add sms quantity

This commit is contained in:
2026-07-01 20:41:27 +03:30
parent d2838f0976
commit 816fa7a7fc
9 changed files with 91 additions and 6 deletions
@@ -0,0 +1,38 @@
import { Migration } from '@mikro-orm/migrations';
export class Migration20260701180000_addRestaurantCredit extends Migration {
override async up(): Promise<void> {
this.addSql(`alter table "restaurants" add column "credit" numeric(10,0) not null default 0;`);
this.addSql(`
create table "restaurant_credit_transactions" (
"id" char(26) not null,
"created_at" timestamptz not null default now(),
"updated_at" timestamptz not null default now(),
"deleted_at" timestamptz null,
"restaurant_id" char(26) not null,
"amount" numeric(10,0) not null,
"balance" numeric(10,0) not null,
"type" text check ("type" in ('credit', 'debit')) not null,
"reason" text check ("reason" in ('sms_send', 'deposit', 'adjustment')) not null,
constraint "restaurant_credit_transactions_pkey" primary key ("id")
);
`);
this.addSql(`create index "restaurant_credit_transactions_created_at_index" on "restaurant_credit_transactions" ("created_at");`);
this.addSql(`create index "restaurant_credit_transactions_deleted_at_index" on "restaurant_credit_transactions" ("deleted_at");`);
this.addSql(`create index "restaurant_credit_transactions_restaurant_id_index" on "restaurant_credit_transactions" ("restaurant_id");`);
this.addSql(`
alter table "restaurant_credit_transactions"
add constraint "restaurant_credit_transactions_restaurant_id_foreign"
foreign key ("restaurant_id") references "restaurants" ("id") on update cascade;
`);
}
override async down(): Promise<void> {
this.addSql(`alter table "restaurant_credit_transactions" drop constraint if exists "restaurant_credit_transactions_restaurant_id_foreign";`);
this.addSql(`drop table if exists "restaurant_credit_transactions" cascade;`);
this.addSql(`alter table "restaurants" drop column if exists "credit";`);
}
}
@@ -2,6 +2,7 @@ export class SmsSentEvent {
constructor(
public readonly phoneNumber: string,
public readonly restaurantId: string,
public readonly quantity: number = 1,
) {}
}
@@ -12,6 +12,8 @@ export interface DirectSmsQueueJob {
templateId: string;
params?: Record<string, unknown>;
restaurantId?: string;
/** Number of SMS units billed (1 for short templates, 34 for long ones). Defaults to 1. */
quantity?: number;
}
export interface PushNotificationQueueJob {
title: string;
@@ -33,15 +33,16 @@ export class SmsListeners {
return;
}
const quantity = event.quantity ?? 1;
let smsLog = await this.em.findOne(SmsLog, { restaurant: event.restaurantId });
if (smsLog) {
smsLog.count += 1;
smsLog.count += quantity;
} else {
smsLog = this.em.create(SmsLog, {
restaurant,
count: 1,
createdAt: new Date(),
count: quantity,
});
}
@@ -19,7 +19,7 @@ export class DirectSmsProcessor extends WorkerHost {
}
async process(job: Job<DirectSmsQueueJob>) {
const { phone, templateId, params, restaurantId } = job.data;
const { phone, templateId, params, restaurantId, quantity = 1 } = job.data;
this.logger.log(`Processing direct SMS - phone: ${phone}, templateId: ${templateId}`);
@@ -33,7 +33,10 @@ export class DirectSmsProcessor extends WorkerHost {
this.logger.log(`Direct SMS sent successfully to ${phone}`);
if (restaurantId) {
this.eventEmitter.emit(SmsSentEvent.name, new SmsSentEvent(phone, restaurantId));
this.eventEmitter.emit(
SmsSentEvent.name,
new SmsSentEvent(phone, restaurantId, quantity),
);
}
return { success: true };
@@ -0,0 +1,26 @@
import { Entity, Enum, Index, ManyToOne, Property } from '@mikro-orm/core';
import { BaseEntity } from '../../../common/entities/base.entity';
import { Restaurant } from './restaurant.entity';
import {
RestaurantCreditTransactionReason,
RestaurantCreditTransactionType,
} from '../interface/restaurant-credit-transaction.interface';
@Entity({ tableName: 'restaurant_credit_transactions' })
@Index({ properties: ['restaurant'] })
export class RestaurantCreditTransaction extends BaseEntity {
@ManyToOne(() => Restaurant)
restaurant!: Restaurant;
@Property({ type: 'decimal', precision: 10, scale: 0 })
amount!: number;
@Property({ type: 'decimal', precision: 10, scale: 0 })
balance!: number;
@Enum(() => RestaurantCreditTransactionType)
type!: RestaurantCreditTransactionType;
@Enum(() => RestaurantCreditTransactionReason)
reason!: RestaurantCreditTransactionReason;
}
@@ -77,6 +77,9 @@ export class Restaurant extends BaseEntity {
@Property({ type: 'decimal', default: 0 })
vat?: number = 0;
@Property({ type: 'decimal', precision: 10, scale: 0, default: 0 })
credit?: number = 0;
@Property()
domain!: string;
@@ -0,0 +1,10 @@
export enum RestaurantCreditTransactionType {
CREDIT = 'credit',
DEBIT = 'debit',
}
export enum RestaurantCreditTransactionReason {
SMS_SEND = 'sms_send',
DEPOSIT = 'deposit',
ADJUSTMENT = 'adjustment',
}
@@ -14,11 +14,12 @@ import { AuthModule } from '../auth/auth.module';
import { UtilsModule } from '../utils/utils.module';
import { Background } from './entities/background.entity';
import { BackgroundRepository } from './repositories/background.repository';
import { RestaurantCreditTransaction } from './entities/restaurant-credit-transaction.entity';
@Module({
controllers: [RestaurantsController, ScheduleController],
providers: [RestaurantsService, RestRepository, ScheduleRepository, ScheduleService, RestaurantCrone, BackgroundRepository],
imports: [MikroOrmModule.forFeature([Restaurant, Schedule, Background]),
imports: [MikroOrmModule.forFeature([Restaurant, Schedule, Background, RestaurantCreditTransaction]),
JwtModule, forwardRef(() => AuthModule), UtilsModule],
exports: [RestRepository, ScheduleRepository, ScheduleService, RestaurantsService],
})