renew dkala subscription

This commit is contained in:
2026-02-15 14:39:02 +03:30
parent 28283d4362
commit 6f7a95bd18
5 changed files with 59 additions and 29 deletions
+9 -9
View File
@@ -3,7 +3,7 @@ import { ApiBearerAuth, ApiOperation, ApiParam, ApiQuery, ApiTags } from "@nestj
import { DContactService } from "./providers/contact.service"; import { DContactService } from "./providers/contact.service";
import { DkalaIconsService } from "./providers/icons.service"; import { DkalaIconsService } from "./providers/icons.service";
import { ShopService } from "./providers/shop.service"; import { DkalaService } from "./providers/dkala.service";
import { CreateIconDto } from "./DTO/create-icon.dto"; import { CreateIconDto } from "./DTO/create-icon.dto";
import { UpdateIconDto } from "./DTO/update-icon.dto"; import { UpdateIconDto } from "./DTO/update-icon.dto";
import { CreateGroupDto } from "./DTO/create-group.dto"; import { CreateGroupDto } from "./DTO/create-group.dto";
@@ -26,7 +26,7 @@ export class DkalaController {
constructor( constructor(
private readonly iconsService: DkalaIconsService, private readonly iconsService: DkalaIconsService,
private readonly contactService: DContactService, private readonly contactService: DContactService,
private readonly shopService: ShopService, private readonly shopService: DkalaService,
) { } ) { }
// Icon endpoints // Icon endpoints
@@ -145,7 +145,7 @@ export class DkalaController {
) { ) {
const parsedPage = page ? parseInt(page.toString(), 10) : 1; const parsedPage = page ? parseInt(page.toString(), 10) : 1;
const parsedLimit = limit ? parseInt(limit.toString(), 10) : 10; const parsedLimit = limit ? parseInt(limit.toString(), 10) : 10;
return await this.shopService.getSmsCountByRestaurant(parsedPage, parsedLimit); return await this.shopService.getSmsCounts(parsedPage, parsedLimit);
} }
@PermissionsDec(PermissionEnum.DKALA) @PermissionsDec(PermissionEnum.DKALA)
@@ -153,7 +153,7 @@ export class DkalaController {
@ApiOperation({ summary: "Update restaurant" }) @ApiOperation({ summary: "Update restaurant" })
@ApiParam({ name: "id", required: true, type: String }) @ApiParam({ name: "id", required: true, type: String })
updateRestaurant(@Param("id") id: string, @Body() dto: UpdateShopDto) { updateRestaurant(@Param("id") id: string, @Body() dto: UpdateShopDto) {
return this.shopService.updateRestaurant(id, dto); return this.shopService.updateShop(id, dto);
} }
@PermissionsDec(PermissionEnum.DKALA) @PermissionsDec(PermissionEnum.DKALA)
@@ -176,7 +176,7 @@ export class DkalaController {
@ApiOperation({ summary: "Get restaurant admins" }) @ApiOperation({ summary: "Get restaurant admins" })
@ApiParam({ name: "restaurantId", required: true, type: String }) @ApiParam({ name: "restaurantId", required: true, type: String })
getRestaurantAdmins(@Param("restaurantId") restaurantId: string) { getRestaurantAdmins(@Param("restaurantId") restaurantId: string) {
return this.shopService.getRestaurantAdmins(restaurantId); return this.shopService.getAdminsByShop(restaurantId);
} }
@PermissionsDec(PermissionEnum.DKALA) @PermissionsDec(PermissionEnum.DKALA)
@@ -184,7 +184,7 @@ export class DkalaController {
@ApiOperation({ summary: "Assign admin to restaurant" }) @ApiOperation({ summary: "Assign admin to restaurant" })
@ApiParam({ name: "restaurantId", required: true, type: String }) @ApiParam({ name: "restaurantId", required: true, type: String })
assignRestaurantAdmin(@Param("restaurantId") restaurantId: string, @Body() dto: CreateMyShopAdminDto) { assignRestaurantAdmin(@Param("restaurantId") restaurantId: string, @Body() dto: CreateMyShopAdminDto) {
return this.shopService.assignRestaurantAdmin(restaurantId, dto); return this.shopService.assignShopAdmin(restaurantId, dto);
} }
@PermissionsDec(PermissionEnum.DKALA) @PermissionsDec(PermissionEnum.DKALA)
@@ -193,21 +193,21 @@ export class DkalaController {
@ApiParam({ name: "restaurantId", required: true, type: String }) @ApiParam({ name: "restaurantId", required: true, type: String })
@ApiParam({ name: "adminId", required: true, type: String }) @ApiParam({ name: "adminId", required: true, type: String })
revokeRestaurantAdmin(@Param("restaurantId") restaurantId: string, @Param("adminId") adminId: string) { revokeRestaurantAdmin(@Param("restaurantId") restaurantId: string, @Param("adminId") adminId: string) {
return this.shopService.revokeRestaurantAdmin(restaurantId, adminId); return this.shopService.revokeShopAdmin(restaurantId, adminId);
} }
//***User Endpoints*** //***User Endpoints***
@Post('dkala/shops') @Post('dkala/shops')
@ApiOperation({ summary: "Create restaurant" }) @ApiOperation({ summary: "Create restaurant" })
createRestaurant(@Body() dto: SetupShopDto, @UserDec("id") userId: string) { createRestaurant(@Body() dto: SetupShopDto, @UserDec("id") userId: string) {
return this.shopService.createRestaurant(dto, userId); return this.shopService.createShop(dto, userId);
} }
@Get('dkala/shops/subscription/:subscriptionId') @Get('dkala/shops/subscription/:subscriptionId')
@ApiOperation({ summary: "Get restaurant subscription by subscription ID" }) @ApiOperation({ summary: "Get restaurant subscription by subscription ID" })
@ApiParam({ name: "subscriptionId", required: true, type: String }) @ApiParam({ name: "subscriptionId", required: true, type: String })
getRestaurantSubscription(@Param("subscriptionId") subscriptionId: string) { getRestaurantSubscription(@Param("subscriptionId") subscriptionId: string) {
return this.shopService.getRestaurantSubscription(subscriptionId); return this.shopService.getShopBySubscriptionId(subscriptionId);
} }
@Post('dkala/auth/direct-login/:userSubscriptionId') @Post('dkala/auth/direct-login/:userSubscriptionId')
+3 -3
View File
@@ -4,7 +4,7 @@ import { DKALA_CONFIG } from "./constants";
import { DkalaController } from "./dkala.controller"; import { DkalaController } from "./dkala.controller";
import { DContactService } from "./providers/contact.service"; import { DContactService } from "./providers/contact.service";
import { DkalaIconsService } from "./providers/icons.service"; import { DkalaIconsService } from "./providers/icons.service";
import { ShopService } from "./providers/shop.service"; import { DkalaService } from "./providers/dkala.service";
import { SubscriptionsModule } from "../subscriptions/subscriptions.module"; import { SubscriptionsModule } from "../subscriptions/subscriptions.module";
import { UsersModule } from "../users/users.module"; import { UsersModule } from "../users/users.module";
import { dkalaConfig } from "../../configs/dkala.config"; import { dkalaConfig } from "../../configs/dkala.config";
@@ -19,13 +19,13 @@ import { dkalaConfig } from "../../configs/dkala.config";
providers: [ providers: [
DkalaIconsService, DkalaIconsService,
DContactService, DContactService,
ShopService, DkalaService,
{ {
provide: DKALA_CONFIG, provide: DKALA_CONFIG,
useFactory: dkalaConfig().useFactory, useFactory: dkalaConfig().useFactory,
inject: dkalaConfig().inject, inject: dkalaConfig().inject,
}, },
], ],
exports: [ShopService], exports: [DkalaService],
}) })
export class DkalaModule {} export class DkalaModule {}
@@ -17,8 +17,8 @@ import { IDkalaConfig } from "../../../configs/dkala.config";
@Injectable() @Injectable()
export class ShopService { export class DkalaService {
private readonly logger = new Logger(ShopService.name); private readonly logger = new Logger(DkalaService.name);
constructor( constructor(
@Inject(DKALA_CONFIG) private readonly config: IDkalaConfig, @Inject(DKALA_CONFIG) private readonly config: IDkalaConfig,
@@ -114,7 +114,7 @@ export class ShopService {
} }
} }
async createRestaurant(dto: SetupShopDto, userId: string) { async createShop(dto: SetupShopDto, userId: string) {
const { userSubscription } = await this.subscriptionService.getUserSubscriptionById(dto.userSubscriptionId, userId); const { userSubscription } = await this.subscriptionService.getUserSubscriptionById(dto.userSubscriptionId, userId);
if (!userSubscription) { if (!userSubscription) {
throw new BadRequestException(SubscriptionMessage.USER_SUBS_NOT_FOUND); throw new BadRequestException(SubscriptionMessage.USER_SUBS_NOT_FOUND);
@@ -165,7 +165,7 @@ export class ShopService {
} }
} }
async updateRestaurant(id: string, dto: UpdateShopDto) { async updateShop(id: string, dto: UpdateShopDto) {
try { try {
const { data } = await firstValueFrom( const { data } = await firstValueFrom(
this.httpService this.httpService
@@ -194,7 +194,7 @@ export class ShopService {
} }
} }
async getRestaurantSubscription(subscriptionId: string) { async getShopBySubscriptionId(subscriptionId: string) {
try { try {
console.log('subscriptionId', subscriptionId) console.log('subscriptionId', subscriptionId)
const { data } = await firstValueFrom( const { data } = await firstValueFrom(
@@ -225,13 +225,13 @@ export class ShopService {
} }
} }
async getSmsCountByRestaurant(page: number, limit: number) { async getSmsCounts(page: number, limit: number) {
try { try {
const { data } = await firstValueFrom( const { data } = await firstValueFrom(
this.httpService this.httpService
.get(this.config.baseUrl + "/super-admin/notifications/sms-count", { .get(this.config.baseUrl + "/super-admin/notifications/sms-count", {
params: { page, limit}, params: { page, limit },
headers: this.getHeaders() headers: this.getHeaders()
}) })
.pipe( .pipe(
catchError((err: AxiosError) => { catchError((err: AxiosError) => {
@@ -285,11 +285,11 @@ export class ShopService {
} }
} }
async getRestaurantAdmins(restaurantId: string) { async getAdminsByShop(shopId: string) {
try { try {
const { data } = await firstValueFrom( const { data } = await firstValueFrom(
this.httpService this.httpService
.get(`${this.config.baseUrl}/super-admin/shops/${restaurantId}/admins`, { .get(`${this.config.baseUrl}/super-admin/shops/${shopId}/admins`, {
headers: this.getHeaders(), headers: this.getHeaders(),
}) })
.pipe( .pipe(
@@ -314,11 +314,11 @@ export class ShopService {
} }
} }
async revokeRestaurantAdmin(restaurantId: string, adminId: string) { async revokeShopAdmin(shopId: string, adminId: string) {
try { try {
const { data } = await firstValueFrom( const { data } = await firstValueFrom(
this.httpService this.httpService
.delete(`${this.config.baseUrl}/super-admin/shops/${restaurantId}/admins/${adminId}`, { .delete(`${this.config.baseUrl}/super-admin/shops/${shopId}/admins/${adminId}`, {
headers: this.getHeaders(), headers: this.getHeaders(),
data: {}, data: {},
}) })
@@ -344,12 +344,12 @@ export class ShopService {
} }
} }
async assignRestaurantAdmin(restaurantId: string, dto: CreateMyShopAdminDto) { async assignShopAdmin(shopId: string, dto: CreateMyShopAdminDto) {
try { try {
const { data } = await firstValueFrom( const { data } = await firstValueFrom(
this.httpService this.httpService
.post(`${this.config.baseUrl}/super-admin/shops/${restaurantId}/admins`, dto, { .post(`${this.config.baseUrl}/super-admin/shops/${shopId}/admins`, dto, {
headers: this.getHeaders(), headers: this.getHeaders(),
}) })
.pipe( .pipe(
@@ -377,12 +377,11 @@ export class ShopService {
} }
} }
async upgradeSubscription(subscriptionId: string, newPlan: 'base' | 'premium', subscriptionEndDate: Date) { async upgradeSubscription(subscriptionId: string, subscriptionEndDate: Date) {
try { try {
const { data } = await firstValueFrom( const { data } = await firstValueFrom(
this.httpService this.httpService
.patch(`${this.config.baseUrl}/super-admin/shops/subscription/${subscriptionId}/upgrade`, { .patch(`${this.config.baseUrl}/super-admin/shops/subscription/${subscriptionId}/upgrade`, {
newPlan,
subscriptionEndDate subscriptionEndDate
}, { }, {
headers: this.getHeaders(), headers: this.getHeaders(),
@@ -454,7 +453,7 @@ export class ShopService {
} }
// 3. Get restaurant by subscription id // 3. Get restaurant by subscription id
const restaurant = await this.getRestaurantSubscription(userSubscriptionId); const restaurant = await this.getShopBySubscriptionId(userSubscriptionId);
// 4. Get slug from restaurant // 4. Get slug from restaurant
const slug = restaurant.data.slug; const slug = restaurant.data.slug;
+2
View File
@@ -22,6 +22,7 @@ import { PaymentsModule } from "../payments/payments.module";
import { UsersModule } from "../users/users.module"; import { UsersModule } from "../users/users.module";
import { UtilsModule } from "../utils/utils.module"; import { UtilsModule } from "../utils/utils.module";
import { WalletsModule } from "../wallets/wallets.module"; import { WalletsModule } from "../wallets/wallets.module";
import { DkalaModule } from "../dkala/dkala.module";
@Module({ @Module({
imports: [ imports: [
LoggerModule, LoggerModule,
@@ -48,6 +49,7 @@ import { WalletsModule } from "../wallets/wallets.module";
PaymentsModule, PaymentsModule,
AccessLogsModule, AccessLogsModule,
forwardRef(() => DmenuModule), forwardRef(() => DmenuModule),
forwardRef(() => DkalaModule),
], ],
providers: [InvoicesService, InvoicesRepository, InvoiceItemsRepository, DiscountRepository, UsageDiscountRepository, InvoiceProcessor], providers: [InvoicesService, InvoicesRepository, InvoiceItemsRepository, DiscountRepository, UsageDiscountRepository, InvoiceProcessor],
controllers: [InvoicesController], controllers: [InvoicesController],
@@ -38,6 +38,7 @@ import { InvoiceStatus } from "../enums/invoice-status.enum";
import { IExternalInvoiceJob, InvoicePurpose } from "../interfaces/external-invoice.interface"; import { IExternalInvoiceJob, InvoicePurpose } from "../interfaces/external-invoice.interface";
import { InvoiceItemsRepository } from "../repositories/invoice-items.repository"; import { InvoiceItemsRepository } from "../repositories/invoice-items.repository";
import { InvoicesRepository } from "../repositories/invoices.repository"; import { InvoicesRepository } from "../repositories/invoices.repository";
import { DkalaService } from "../../dkala/providers/dkala.service";
@Injectable() @Injectable()
export class InvoicesService { export class InvoicesService {
private readonly logger = new Logger(InvoicesService.name); private readonly logger = new Logger(InvoicesService.name);
@@ -55,6 +56,7 @@ export class InvoicesService {
private readonly dataSource: DataSource, private readonly dataSource: DataSource,
private readonly accessLogService: AccessLogService, private readonly accessLogService: AccessLogService,
private readonly restaurantService: RestaurantService, private readonly restaurantService: RestaurantService,
private readonly dkalaService: DkalaService,
) { } ) { }
///********************************** */ ///********************************** */
@@ -833,6 +835,19 @@ export class InvoicesService {
// Don't fail the transaction if external API call fails // Don't fail the transaction if external API call fails
} }
} }
else if (upgradePlan.service.slug?.toLowerCase().includes('dkala')) {
try {
this.logger.log(`Calling external API for dkala upgrade: subscription ${userSubscription.id}`);
await this.dkalaService.upgradeSubscription(
userSubscription.id,
userSubscription.endDate
);
this.logger.log(`External API call completed for dkala upgrade: subscription ${userSubscription.id}`);
} catch (error) {
this.logger.error(`Failed to call external API for dkala upgrade: ${error instanceof Error ? error.message : 'Unknown error'}`);
// Don't fail the transaction if external API call fails
}
}
} else if (purpose == InvoicePurpose.RENEW) { } else if (purpose == InvoicePurpose.RENEW) {
if (userSubscription.status == SubscriptionStatus.ACTIVE) { if (userSubscription.status == SubscriptionStatus.ACTIVE) {
@@ -866,6 +881,20 @@ export class InvoicesService {
} }
} }
else if (userSubscription.plan.service.slug?.toLowerCase().includes('dkala')) {
try {
this.logger.log(`Calling external API for dkala renew: subscription ${userSubscription.id}`);
await this.dkalaService.upgradeSubscription(
userSubscription.id,
userSubscription.endDate
);
this.logger.log(`External API call completed for dkala renew: subscription ${userSubscription.id}`);
} catch (error) {
this.logger.error(`Failed to call external API for dkala renew: ${error instanceof Error ? error.message : 'Unknown error'}`);
// Don't fail the transaction if external API call fails
}
}
} else if (purpose == InvoicePurpose.NEW) { } else if (purpose == InvoicePurpose.NEW) {
userSubscription.status = SubscriptionStatus.ACTIVE; userSubscription.status = SubscriptionStatus.ACTIVE;
await this.scheduleNextRenewalJob(userSubscription); await this.scheduleNextRenewalJob(userSubscription);