feat: complete admin backend controllers and services

- AdminPlansController & Service (CRUD, reorder)
- AdminPaymentMethodsController & Service (CRUD, reorder)
- AdminPaymentsController & Service (verify, reject, pending count)
- AdminUsersController & Service (search, suspend, grant pro access, stats)
- AdminConfigController & Service (dynamic config management)
- Wire all controllers into AdminModule
- Import AdminModule in AppModule

Admin API Routes:
- GET/POST/PUT/DELETE /admin/plans
- GET/POST/PUT/DELETE /admin/payment-methods
- GET /admin/payments (with status filter)
- POST /admin/payments/:id/verify
- POST /admin/payments/:id/reject
- GET /admin/users (with search)
- POST /admin/users/:id/grant-pro
- GET/POST/DELETE /admin/config

All routes protected by AuthGuard + AdminGuard
This commit is contained in:
dwindown
2025-10-11 14:32:45 +07:00
parent 9b789b333f
commit 12850ab12d
53 changed files with 3098 additions and 34 deletions

View File

@@ -128,9 +128,16 @@ Tabungin is a personal finance SaaS with unique differentiators:
**Current:**
- [ ] Phase 1: Admin Dashboard
- [ ] Schema migration
- [ ] Seeder
- [ ] Backend
- [x] Schema migration
- [x] Seeder
- [ ] Backend (IN PROGRESS)
- [x] Admin Guard
- [x] JWT Role Support
- [ ] Plans CRUD
- [ ] Payment Methods CRUD
- [ ] Payments Verification
- [ ] Users Management
- [ ] App Config
- [ ] Frontend
**Next:**

View File

@@ -0,0 +1,60 @@
import { AdminConfigService } from './admin-config.service';
interface RequestWithUser {
user: {
userId: string;
};
}
export declare class AdminConfigController {
private readonly service;
constructor(service: AdminConfigService);
findAll(category?: string): Promise<{
id: string;
key: string;
value: string;
category: string;
label: string;
description: string | null;
type: string;
isSecret: boolean;
updatedAt: Date;
updatedBy: string | null;
}[]>;
getByCategory(): Promise<Record<string, any[]>>;
findOne(key: string): Promise<{
id: string;
key: string;
value: string;
category: string;
label: string;
description: string | null;
type: string;
isSecret: boolean;
updatedAt: Date;
updatedBy: string | null;
} | null>;
upsert(key: string, data: any, req: RequestWithUser): Promise<{
id: string;
key: string;
value: string;
category: string;
label: string;
description: string | null;
type: string;
isSecret: boolean;
updatedAt: Date;
updatedBy: string | null;
}>;
delete(key: string): Promise<{
id: string;
key: string;
value: string;
category: string;
label: string;
description: string | null;
type: string;
isSecret: boolean;
updatedAt: Date;
updatedBy: string | null;
}>;
}
export {};

View File

@@ -0,0 +1,83 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AdminConfigController = void 0;
const common_1 = require("@nestjs/common");
const auth_guard_1 = require("../auth/auth.guard");
const admin_guard_1 = require("./guards/admin.guard");
const admin_config_service_1 = require("./admin-config.service");
let AdminConfigController = class AdminConfigController {
service;
constructor(service) {
this.service = service;
}
findAll(category) {
return this.service.findAll(category);
}
getByCategory() {
return this.service.getByCategory();
}
findOne(key) {
return this.service.findOne(key);
}
upsert(key, data, req) {
return this.service.upsert(key, data, req.user.userId);
}
delete(key) {
return this.service.delete(key);
}
};
exports.AdminConfigController = AdminConfigController;
__decorate([
(0, common_1.Get)(),
__param(0, (0, common_1.Query)('category')),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String]),
__metadata("design:returntype", void 0)
], AdminConfigController.prototype, "findAll", null);
__decorate([
(0, common_1.Get)('by-category'),
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", void 0)
], AdminConfigController.prototype, "getByCategory", null);
__decorate([
(0, common_1.Get)(':key'),
__param(0, (0, common_1.Param)('key')),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String]),
__metadata("design:returntype", void 0)
], AdminConfigController.prototype, "findOne", null);
__decorate([
(0, common_1.Post)(':key'),
__param(0, (0, common_1.Param)('key')),
__param(1, (0, common_1.Body)()),
__param(2, (0, common_1.Req)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String, Object, Object]),
__metadata("design:returntype", void 0)
], AdminConfigController.prototype, "upsert", null);
__decorate([
(0, common_1.Delete)(':key'),
__param(0, (0, common_1.Param)('key')),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String]),
__metadata("design:returntype", void 0)
], AdminConfigController.prototype, "delete", null);
exports.AdminConfigController = AdminConfigController = __decorate([
(0, common_1.Controller)('admin/config'),
(0, common_1.UseGuards)(auth_guard_1.AuthGuard, admin_guard_1.AdminGuard),
__metadata("design:paramtypes", [admin_config_service_1.AdminConfigService])
], AdminConfigController);
//# sourceMappingURL=admin-config.controller.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"admin-config.controller.js","sourceRoot":"","sources":["../../src/admin/admin-config.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAUwB;AACxB,mDAA+C;AAC/C,sDAAkD;AAClD,iEAA4D;AAUrD,IAAM,qBAAqB,GAA3B,MAAM,qBAAqB;IACH;IAA7B,YAA6B,OAA2B;QAA3B,YAAO,GAAP,OAAO,CAAoB;IAAG,CAAC;IAG5D,OAAO,CAAoB,QAAiB;QAC1C,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACxC,CAAC;IAGD,aAAa;QACX,OAAO,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC;IACtC,CAAC;IAGD,OAAO,CAAe,GAAW;QAC/B,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACnC,CAAC;IAGD,MAAM,CACU,GAAW,EACjB,IAAS,EACV,GAAoB;QAE3B,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACzD,CAAC;IAGD,MAAM,CAAe,GAAW;QAC9B,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAClC,CAAC;CACF,CAAA;AA/BY,sDAAqB;AAIhC;IADC,IAAA,YAAG,GAAE;IACG,WAAA,IAAA,cAAK,EAAC,UAAU,CAAC,CAAA;;;;oDAEzB;AAGD;IADC,IAAA,YAAG,EAAC,aAAa,CAAC;;;;0DAGlB;AAGD;IADC,IAAA,YAAG,EAAC,MAAM,CAAC;IACH,WAAA,IAAA,cAAK,EAAC,KAAK,CAAC,CAAA;;;;oDAEpB;AAGD;IADC,IAAA,aAAI,EAAC,MAAM,CAAC;IAEV,WAAA,IAAA,cAAK,EAAC,KAAK,CAAC,CAAA;IACZ,WAAA,IAAA,aAAI,GAAE,CAAA;IACN,WAAA,IAAA,YAAG,GAAE,CAAA;;;;mDAGP;AAGD;IADC,IAAA,eAAM,EAAC,MAAM,CAAC;IACP,WAAA,IAAA,cAAK,EAAC,KAAK,CAAC,CAAA;;;;mDAEnB;gCA9BU,qBAAqB;IAFjC,IAAA,mBAAU,EAAC,cAAc,CAAC;IAC1B,IAAA,kBAAS,EAAC,sBAAS,EAAE,wBAAU,CAAC;qCAEO,yCAAkB;GAD7C,qBAAqB,CA+BjC"}

View File

@@ -0,0 +1,54 @@
import { PrismaService } from '../prisma/prisma.service';
export declare class AdminConfigService {
private readonly prisma;
constructor(prisma: PrismaService);
findAll(category?: string): Promise<{
id: string;
key: string;
value: string;
category: string;
label: string;
description: string | null;
type: string;
isSecret: boolean;
updatedAt: Date;
updatedBy: string | null;
}[]>;
findOne(key: string): Promise<{
id: string;
key: string;
value: string;
category: string;
label: string;
description: string | null;
type: string;
isSecret: boolean;
updatedAt: Date;
updatedBy: string | null;
} | null>;
upsert(key: string, data: any, updatedBy: string): Promise<{
id: string;
key: string;
value: string;
category: string;
label: string;
description: string | null;
type: string;
isSecret: boolean;
updatedAt: Date;
updatedBy: string | null;
}>;
delete(key: string): Promise<{
id: string;
key: string;
value: string;
category: string;
label: string;
description: string | null;
type: string;
isSecret: boolean;
updatedAt: Date;
updatedBy: string | null;
}>;
getByCategory(): Promise<Record<string, any[]>>;
}

View File

@@ -0,0 +1,68 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AdminConfigService = void 0;
const common_1 = require("@nestjs/common");
const prisma_service_1 = require("../prisma/prisma.service");
let AdminConfigService = class AdminConfigService {
prisma;
constructor(prisma) {
this.prisma = prisma;
}
async findAll(category) {
return this.prisma.appConfig.findMany({
where: category ? { category } : undefined,
orderBy: { category: 'asc' },
});
}
async findOne(key) {
return this.prisma.appConfig.findUnique({
where: { key },
});
}
async upsert(key, data, updatedBy) {
return this.prisma.appConfig.upsert({
where: { key },
update: {
...data,
updatedBy,
updatedAt: new Date(),
},
create: {
key,
...data,
updatedBy,
},
});
}
async delete(key) {
return this.prisma.appConfig.delete({
where: { key },
});
}
async getByCategory() {
const configs = await this.prisma.appConfig.findMany();
const grouped = configs.reduce((acc, config) => {
if (!acc[config.category]) {
acc[config.category] = [];
}
acc[config.category].push(config);
return acc;
}, {});
return grouped;
}
};
exports.AdminConfigService = AdminConfigService;
exports.AdminConfigService = AdminConfigService = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [prisma_service_1.PrismaService])
], AdminConfigService);
//# sourceMappingURL=admin-config.service.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"admin-config.service.js","sourceRoot":"","sources":["../../src/admin/admin-config.service.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAA4C;AAC5C,6DAAyD;AAGlD,IAAM,kBAAkB,GAAxB,MAAM,kBAAkB;IACA;IAA7B,YAA6B,MAAqB;QAArB,WAAM,GAAN,MAAM,CAAe;IAAG,CAAC;IAEtD,KAAK,CAAC,OAAO,CAAC,QAAiB;QAC7B,OAAO,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC;YACpC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,SAAS;YAC1C,OAAO,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE;SAC7B,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,GAAW;QACvB,OAAO,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC;YACtC,KAAK,EAAE,EAAE,GAAG,EAAE;SACf,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,GAAW,EAAE,IAAS,EAAE,SAAiB;QACpD,OAAO,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC;YAClC,KAAK,EAAE,EAAE,GAAG,EAAE;YACd,MAAM,EAAE;gBACN,GAAG,IAAI;gBACP,SAAS;gBACT,SAAS,EAAE,IAAI,IAAI,EAAE;aACtB;YACD,MAAM,EAAE;gBACN,GAAG;gBACH,GAAG,IAAI;gBACP,SAAS;aACV;SACF,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,GAAW;QACtB,OAAO,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC;YAClC,KAAK,EAAE,EAAE,GAAG,EAAE;SACf,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,aAAa;QACjB,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC;QAGvD,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE;YAC7C,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC1B,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC;YAC5B,CAAC;YACD,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAClC,OAAO,GAAG,CAAC;QACb,CAAC,EAAE,EAA2B,CAAC,CAAC;QAEhC,OAAO,OAAO,CAAC;IACjB,CAAC;CACF,CAAA;AApDY,gDAAkB;6BAAlB,kBAAkB;IAD9B,IAAA,mBAAU,GAAE;qCAE0B,8BAAa;GADvC,kBAAkB,CAoD9B"}

View File

@@ -0,0 +1,80 @@
import { AdminPaymentMethodsService } from './admin-payment-methods.service';
export declare class AdminPaymentMethodsController {
private readonly service;
constructor(service: AdminPaymentMethodsService);
findAll(): Promise<{
id: string;
type: string;
provider: string;
accountName: string;
accountNumber: string;
displayName: string;
logoUrl: string | null;
instructions: string | null;
isActive: boolean;
sortOrder: number;
createdAt: Date;
updatedAt: Date;
}[]>;
findOne(id: string): Promise<{
id: string;
type: string;
provider: string;
accountName: string;
accountNumber: string;
displayName: string;
logoUrl: string | null;
instructions: string | null;
isActive: boolean;
sortOrder: number;
createdAt: Date;
updatedAt: Date;
} | null>;
create(data: any): Promise<{
id: string;
type: string;
provider: string;
accountName: string;
accountNumber: string;
displayName: string;
logoUrl: string | null;
instructions: string | null;
isActive: boolean;
sortOrder: number;
createdAt: Date;
updatedAt: Date;
}>;
update(id: string, data: any): Promise<{
id: string;
type: string;
provider: string;
accountName: string;
accountNumber: string;
displayName: string;
logoUrl: string | null;
instructions: string | null;
isActive: boolean;
sortOrder: number;
createdAt: Date;
updatedAt: Date;
}>;
delete(id: string): Promise<{
id: string;
type: string;
provider: string;
accountName: string;
accountNumber: string;
displayName: string;
logoUrl: string | null;
instructions: string | null;
isActive: boolean;
sortOrder: number;
createdAt: Date;
updatedAt: Date;
}>;
reorder(body: {
methodIds: string[];
}): Promise<{
success: boolean;
}>;
}

View File

@@ -0,0 +1,92 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AdminPaymentMethodsController = void 0;
const common_1 = require("@nestjs/common");
const auth_guard_1 = require("../auth/auth.guard");
const admin_guard_1 = require("./guards/admin.guard");
const admin_payment_methods_service_1 = require("./admin-payment-methods.service");
let AdminPaymentMethodsController = class AdminPaymentMethodsController {
service;
constructor(service) {
this.service = service;
}
findAll() {
return this.service.findAll();
}
findOne(id) {
return this.service.findOne(id);
}
create(data) {
return this.service.create(data);
}
update(id, data) {
return this.service.update(id, data);
}
delete(id) {
return this.service.delete(id);
}
reorder(body) {
return this.service.reorder(body.methodIds);
}
};
exports.AdminPaymentMethodsController = AdminPaymentMethodsController;
__decorate([
(0, common_1.Get)(),
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", void 0)
], AdminPaymentMethodsController.prototype, "findAll", null);
__decorate([
(0, common_1.Get)(':id'),
__param(0, (0, common_1.Param)('id')),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String]),
__metadata("design:returntype", void 0)
], AdminPaymentMethodsController.prototype, "findOne", null);
__decorate([
(0, common_1.Post)(),
__param(0, (0, common_1.Body)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object]),
__metadata("design:returntype", void 0)
], AdminPaymentMethodsController.prototype, "create", null);
__decorate([
(0, common_1.Put)(':id'),
__param(0, (0, common_1.Param)('id')),
__param(1, (0, common_1.Body)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String, Object]),
__metadata("design:returntype", void 0)
], AdminPaymentMethodsController.prototype, "update", null);
__decorate([
(0, common_1.Delete)(':id'),
__param(0, (0, common_1.Param)('id')),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String]),
__metadata("design:returntype", void 0)
], AdminPaymentMethodsController.prototype, "delete", null);
__decorate([
(0, common_1.Post)('reorder'),
__param(0, (0, common_1.Body)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object]),
__metadata("design:returntype", void 0)
], AdminPaymentMethodsController.prototype, "reorder", null);
exports.AdminPaymentMethodsController = AdminPaymentMethodsController = __decorate([
(0, common_1.Controller)('admin/payment-methods'),
(0, common_1.UseGuards)(auth_guard_1.AuthGuard, admin_guard_1.AdminGuard),
__metadata("design:paramtypes", [admin_payment_methods_service_1.AdminPaymentMethodsService])
], AdminPaymentMethodsController);
//# sourceMappingURL=admin-payment-methods.controller.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"admin-payment-methods.controller.js","sourceRoot":"","sources":["../../src/admin/admin-payment-methods.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CASwB;AACxB,mDAA+C;AAC/C,sDAAkD;AAClD,mFAA6E;AAItE,IAAM,6BAA6B,GAAnC,MAAM,6BAA6B;IACX;IAA7B,YAA6B,OAAmC;QAAnC,YAAO,GAAP,OAAO,CAA4B;IAAG,CAAC;IAGpE,OAAO;QACL,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;IAChC,CAAC;IAGD,OAAO,CAAc,EAAU;QAC7B,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAClC,CAAC;IAGD,MAAM,CAAS,IAAS;QACtB,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACnC,CAAC;IAGD,MAAM,CAAc,EAAU,EAAU,IAAS;QAC/C,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IACvC,CAAC;IAGD,MAAM,CAAc,EAAU;QAC5B,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACjC,CAAC;IAGD,OAAO,CAAS,IAA6B;QAC3C,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC9C,CAAC;CACF,CAAA;AAhCY,sEAA6B;AAIxC;IADC,IAAA,YAAG,GAAE;;;;4DAGL;AAGD;IADC,IAAA,YAAG,EAAC,KAAK,CAAC;IACF,WAAA,IAAA,cAAK,EAAC,IAAI,CAAC,CAAA;;;;4DAEnB;AAGD;IADC,IAAA,aAAI,GAAE;IACC,WAAA,IAAA,aAAI,GAAE,CAAA;;;;2DAEb;AAGD;IADC,IAAA,YAAG,EAAC,KAAK,CAAC;IACH,WAAA,IAAA,cAAK,EAAC,IAAI,CAAC,CAAA;IAAc,WAAA,IAAA,aAAI,GAAE,CAAA;;;;2DAEtC;AAGD;IADC,IAAA,eAAM,EAAC,KAAK,CAAC;IACN,WAAA,IAAA,cAAK,EAAC,IAAI,CAAC,CAAA;;;;2DAElB;AAGD;IADC,IAAA,aAAI,EAAC,SAAS,CAAC;IACP,WAAA,IAAA,aAAI,GAAE,CAAA;;;;4DAEd;wCA/BU,6BAA6B;IAFzC,IAAA,mBAAU,EAAC,uBAAuB,CAAC;IACnC,IAAA,kBAAS,EAAC,sBAAS,EAAE,wBAAU,CAAC;qCAEO,0DAA0B;GADrD,6BAA6B,CAgCzC"}

View File

@@ -0,0 +1,78 @@
import { PrismaService } from '../prisma/prisma.service';
export declare class AdminPaymentMethodsService {
private readonly prisma;
constructor(prisma: PrismaService);
findAll(): Promise<{
id: string;
type: string;
provider: string;
accountName: string;
accountNumber: string;
displayName: string;
logoUrl: string | null;
instructions: string | null;
isActive: boolean;
sortOrder: number;
createdAt: Date;
updatedAt: Date;
}[]>;
findOne(id: string): Promise<{
id: string;
type: string;
provider: string;
accountName: string;
accountNumber: string;
displayName: string;
logoUrl: string | null;
instructions: string | null;
isActive: boolean;
sortOrder: number;
createdAt: Date;
updatedAt: Date;
} | null>;
create(data: any): Promise<{
id: string;
type: string;
provider: string;
accountName: string;
accountNumber: string;
displayName: string;
logoUrl: string | null;
instructions: string | null;
isActive: boolean;
sortOrder: number;
createdAt: Date;
updatedAt: Date;
}>;
update(id: string, data: any): Promise<{
id: string;
type: string;
provider: string;
accountName: string;
accountNumber: string;
displayName: string;
logoUrl: string | null;
instructions: string | null;
isActive: boolean;
sortOrder: number;
createdAt: Date;
updatedAt: Date;
}>;
delete(id: string): Promise<{
id: string;
type: string;
provider: string;
accountName: string;
accountNumber: string;
displayName: string;
logoUrl: string | null;
instructions: string | null;
isActive: boolean;
sortOrder: number;
createdAt: Date;
updatedAt: Date;
}>;
reorder(methodIds: string[]): Promise<{
success: boolean;
}>;
}

View File

@@ -0,0 +1,60 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AdminPaymentMethodsService = void 0;
const common_1 = require("@nestjs/common");
const prisma_service_1 = require("../prisma/prisma.service");
let AdminPaymentMethodsService = class AdminPaymentMethodsService {
prisma;
constructor(prisma) {
this.prisma = prisma;
}
async findAll() {
return this.prisma.paymentMethod.findMany({
orderBy: { sortOrder: 'asc' },
});
}
async findOne(id) {
return this.prisma.paymentMethod.findUnique({
where: { id },
});
}
async create(data) {
return this.prisma.paymentMethod.create({
data,
});
}
async update(id, data) {
return this.prisma.paymentMethod.update({
where: { id },
data,
});
}
async delete(id) {
return this.prisma.paymentMethod.delete({
where: { id },
});
}
async reorder(methodIds) {
const updates = methodIds.map((id, index) => this.prisma.paymentMethod.update({
where: { id },
data: { sortOrder: index + 1 },
}));
await this.prisma.$transaction(updates);
return { success: true };
}
};
exports.AdminPaymentMethodsService = AdminPaymentMethodsService;
exports.AdminPaymentMethodsService = AdminPaymentMethodsService = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [prisma_service_1.PrismaService])
], AdminPaymentMethodsService);
//# sourceMappingURL=admin-payment-methods.service.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"admin-payment-methods.service.js","sourceRoot":"","sources":["../../src/admin/admin-payment-methods.service.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAA4C;AAC5C,6DAAyD;AAGlD,IAAM,0BAA0B,GAAhC,MAAM,0BAA0B;IACR;IAA7B,YAA6B,MAAqB;QAArB,WAAM,GAAN,MAAM,CAAe;IAAG,CAAC;IAEtD,KAAK,CAAC,OAAO;QACX,OAAO,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC;YACxC,OAAO,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE;SAC9B,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,EAAU;QACtB,OAAO,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,UAAU,CAAC;YAC1C,KAAK,EAAE,EAAE,EAAE,EAAE;SACd,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,IAAS;QACpB,OAAO,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC;YACtC,IAAI;SACL,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,EAAU,EAAE,IAAS;QAChC,OAAO,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC;YACtC,KAAK,EAAE,EAAE,EAAE,EAAE;YACb,IAAI;SACL,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,EAAU;QACrB,OAAO,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC;YACtC,KAAK,EAAE,EAAE,EAAE,EAAE;SACd,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,SAAmB;QAC/B,MAAM,OAAO,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE,CAC1C,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC;YAC/B,KAAK,EAAE,EAAE,EAAE,EAAE;YACb,IAAI,EAAE,EAAE,SAAS,EAAE,KAAK,GAAG,CAAC,EAAE;SAC/B,CAAC,CACH,CAAC;QAEF,MAAM,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;QACxC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC3B,CAAC;CACF,CAAA;AA7CY,gEAA0B;qCAA1B,0BAA0B;IADtC,IAAA,mBAAU,GAAE;qCAE0B,8BAAa;GADvC,0BAA0B,CA6CtC"}

View File

@@ -0,0 +1,220 @@
import { AdminPaymentsService } from './admin-payments.service';
interface RequestWithUser {
user: {
userId: string;
};
}
export declare class AdminPaymentsController {
private readonly service;
constructor(service: AdminPaymentsService);
findAll(status?: string): Promise<({
user: {
id: string;
email: string;
name: string | null;
};
subscription: ({
plan: {
id: string;
currency: string;
createdAt: Date;
updatedAt: Date;
name: string;
slug: string;
description: string | null;
price: import("@prisma/client/runtime/library").Decimal;
durationType: string;
durationDays: number | null;
trialDays: number;
features: import("@prisma/client/runtime/library").JsonValue;
badge: string | null;
badgeColor: string | null;
highlightColor: string | null;
sortOrder: number;
isActive: boolean;
isVisible: boolean;
isFeatured: boolean;
maxWallets: number | null;
maxGoals: number | null;
maxTeamMembers: number | null;
apiEnabled: boolean;
apiRateLimit: number | null;
};
} & {
id: string;
userId: string;
status: string;
createdAt: Date;
updatedAt: Date;
planId: string;
startDate: Date;
endDate: Date;
isTrialUsed: boolean;
trialEndDate: Date | null;
cancelledAt: Date | null;
cancellationReason: string | null;
}) | null;
} & {
id: string;
userId: string;
subscriptionId: string | null;
invoiceNumber: string;
amount: import("@prisma/client/runtime/library").Decimal;
currency: string;
method: string;
tripayReference: string | null;
tripayFee: import("@prisma/client/runtime/library").Decimal | null;
totalAmount: import("@prisma/client/runtime/library").Decimal;
paymentChannel: string | null;
paymentUrl: string | null;
qrUrl: string | null;
status: string;
proofImageUrl: string | null;
transferDate: Date | null;
verifiedBy: string | null;
verifiedAt: Date | null;
rejectionReason: string | null;
couponId: string | null;
discountAmount: import("@prisma/client/runtime/library").Decimal | null;
notes: string | null;
expiresAt: Date | null;
paidAt: Date | null;
createdAt: Date;
updatedAt: Date;
})[]>;
getPendingCount(): Promise<number>;
findOne(id: string): Promise<({
user: {
id: string;
email: string;
name: string | null;
};
subscription: ({
plan: {
id: string;
currency: string;
createdAt: Date;
updatedAt: Date;
name: string;
slug: string;
description: string | null;
price: import("@prisma/client/runtime/library").Decimal;
durationType: string;
durationDays: number | null;
trialDays: number;
features: import("@prisma/client/runtime/library").JsonValue;
badge: string | null;
badgeColor: string | null;
highlightColor: string | null;
sortOrder: number;
isActive: boolean;
isVisible: boolean;
isFeatured: boolean;
maxWallets: number | null;
maxGoals: number | null;
maxTeamMembers: number | null;
apiEnabled: boolean;
apiRateLimit: number | null;
};
} & {
id: string;
userId: string;
status: string;
createdAt: Date;
updatedAt: Date;
planId: string;
startDate: Date;
endDate: Date;
isTrialUsed: boolean;
trialEndDate: Date | null;
cancelledAt: Date | null;
cancellationReason: string | null;
}) | null;
} & {
id: string;
userId: string;
subscriptionId: string | null;
invoiceNumber: string;
amount: import("@prisma/client/runtime/library").Decimal;
currency: string;
method: string;
tripayReference: string | null;
tripayFee: import("@prisma/client/runtime/library").Decimal | null;
totalAmount: import("@prisma/client/runtime/library").Decimal;
paymentChannel: string | null;
paymentUrl: string | null;
qrUrl: string | null;
status: string;
proofImageUrl: string | null;
transferDate: Date | null;
verifiedBy: string | null;
verifiedAt: Date | null;
rejectionReason: string | null;
couponId: string | null;
discountAmount: import("@prisma/client/runtime/library").Decimal | null;
notes: string | null;
expiresAt: Date | null;
paidAt: Date | null;
createdAt: Date;
updatedAt: Date;
}) | null>;
verify(id: string, req: RequestWithUser): Promise<{
id: string;
userId: string;
subscriptionId: string | null;
invoiceNumber: string;
amount: import("@prisma/client/runtime/library").Decimal;
currency: string;
method: string;
tripayReference: string | null;
tripayFee: import("@prisma/client/runtime/library").Decimal | null;
totalAmount: import("@prisma/client/runtime/library").Decimal;
paymentChannel: string | null;
paymentUrl: string | null;
qrUrl: string | null;
status: string;
proofImageUrl: string | null;
transferDate: Date | null;
verifiedBy: string | null;
verifiedAt: Date | null;
rejectionReason: string | null;
couponId: string | null;
discountAmount: import("@prisma/client/runtime/library").Decimal | null;
notes: string | null;
expiresAt: Date | null;
paidAt: Date | null;
createdAt: Date;
updatedAt: Date;
}>;
reject(id: string, req: RequestWithUser, body: {
reason: string;
}): Promise<{
id: string;
userId: string;
subscriptionId: string | null;
invoiceNumber: string;
amount: import("@prisma/client/runtime/library").Decimal;
currency: string;
method: string;
tripayReference: string | null;
tripayFee: import("@prisma/client/runtime/library").Decimal | null;
totalAmount: import("@prisma/client/runtime/library").Decimal;
paymentChannel: string | null;
paymentUrl: string | null;
qrUrl: string | null;
status: string;
proofImageUrl: string | null;
transferDate: Date | null;
verifiedBy: string | null;
verifiedAt: Date | null;
rejectionReason: string | null;
couponId: string | null;
discountAmount: import("@prisma/client/runtime/library").Decimal | null;
notes: string | null;
expiresAt: Date | null;
paidAt: Date | null;
createdAt: Date;
updatedAt: Date;
}>;
}
export {};

View File

@@ -0,0 +1,84 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AdminPaymentsController = void 0;
const common_1 = require("@nestjs/common");
const auth_guard_1 = require("../auth/auth.guard");
const admin_guard_1 = require("./guards/admin.guard");
const admin_payments_service_1 = require("./admin-payments.service");
let AdminPaymentsController = class AdminPaymentsController {
service;
constructor(service) {
this.service = service;
}
findAll(status) {
return this.service.findAll(status);
}
getPendingCount() {
return this.service.getPendingCount();
}
findOne(id) {
return this.service.findOne(id);
}
verify(id, req) {
return this.service.verify(id, req.user.userId);
}
reject(id, req, body) {
return this.service.reject(id, req.user.userId, body.reason);
}
};
exports.AdminPaymentsController = AdminPaymentsController;
__decorate([
(0, common_1.Get)(),
__param(0, (0, common_1.Query)('status')),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String]),
__metadata("design:returntype", void 0)
], AdminPaymentsController.prototype, "findAll", null);
__decorate([
(0, common_1.Get)('pending/count'),
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", void 0)
], AdminPaymentsController.prototype, "getPendingCount", null);
__decorate([
(0, common_1.Get)(':id'),
__param(0, (0, common_1.Param)('id')),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String]),
__metadata("design:returntype", void 0)
], AdminPaymentsController.prototype, "findOne", null);
__decorate([
(0, common_1.Post)(':id/verify'),
__param(0, (0, common_1.Param)('id')),
__param(1, (0, common_1.Req)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String, Object]),
__metadata("design:returntype", void 0)
], AdminPaymentsController.prototype, "verify", null);
__decorate([
(0, common_1.Post)(':id/reject'),
__param(0, (0, common_1.Param)('id')),
__param(1, (0, common_1.Req)()),
__param(2, (0, common_1.Body)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String, Object, Object]),
__metadata("design:returntype", void 0)
], AdminPaymentsController.prototype, "reject", null);
exports.AdminPaymentsController = AdminPaymentsController = __decorate([
(0, common_1.Controller)('admin/payments'),
(0, common_1.UseGuards)(auth_guard_1.AuthGuard, admin_guard_1.AdminGuard),
__metadata("design:paramtypes", [admin_payments_service_1.AdminPaymentsService])
], AdminPaymentsController);
//# sourceMappingURL=admin-payments.controller.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"admin-payments.controller.js","sourceRoot":"","sources":["../../src/admin/admin-payments.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CASwB;AACxB,mDAA+C;AAC/C,sDAAkD;AAClD,qEAAgE;AAUzD,IAAM,uBAAuB,GAA7B,MAAM,uBAAuB;IACL;IAA7B,YAA6B,OAA6B;QAA7B,YAAO,GAAP,OAAO,CAAsB;IAAG,CAAC;IAG9D,OAAO,CAAkB,MAAe;QACtC,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACtC,CAAC;IAGD,eAAe;QACb,OAAO,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,CAAC;IACxC,CAAC;IAGD,OAAO,CAAc,EAAU;QAC7B,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAClC,CAAC;IAGD,MAAM,CAAc,EAAU,EAAS,GAAoB;QACzD,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAClD,CAAC;IAGD,MAAM,CACS,EAAU,EAChB,GAAoB,EACnB,IAAwB;QAEhC,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IAC/D,CAAC;CACF,CAAA;AA/BY,0DAAuB;AAIlC;IADC,IAAA,YAAG,GAAE;IACG,WAAA,IAAA,cAAK,EAAC,QAAQ,CAAC,CAAA;;;;sDAEvB;AAGD;IADC,IAAA,YAAG,EAAC,eAAe,CAAC;;;;8DAGpB;AAGD;IADC,IAAA,YAAG,EAAC,KAAK,CAAC;IACF,WAAA,IAAA,cAAK,EAAC,IAAI,CAAC,CAAA;;;;sDAEnB;AAGD;IADC,IAAA,aAAI,EAAC,YAAY,CAAC;IACX,WAAA,IAAA,cAAK,EAAC,IAAI,CAAC,CAAA;IAAc,WAAA,IAAA,YAAG,GAAE,CAAA;;;;qDAErC;AAGD;IADC,IAAA,aAAI,EAAC,YAAY,CAAC;IAEhB,WAAA,IAAA,cAAK,EAAC,IAAI,CAAC,CAAA;IACX,WAAA,IAAA,YAAG,GAAE,CAAA;IACL,WAAA,IAAA,aAAI,GAAE,CAAA;;;;qDAGR;kCA9BU,uBAAuB;IAFnC,IAAA,mBAAU,EAAC,gBAAgB,CAAC;IAC5B,IAAA,kBAAS,EAAC,sBAAS,EAAE,wBAAU,CAAC;qCAEO,6CAAoB;GAD/C,uBAAuB,CA+BnC"}

View File

@@ -0,0 +1,212 @@
import { PrismaService } from '../prisma/prisma.service';
export declare class AdminPaymentsService {
private readonly prisma;
constructor(prisma: PrismaService);
findAll(status?: string): Promise<({
user: {
id: string;
email: string;
name: string | null;
};
subscription: ({
plan: {
id: string;
currency: string;
createdAt: Date;
updatedAt: Date;
name: string;
slug: string;
description: string | null;
price: import("@prisma/client/runtime/library").Decimal;
durationType: string;
durationDays: number | null;
trialDays: number;
features: import("@prisma/client/runtime/library").JsonValue;
badge: string | null;
badgeColor: string | null;
highlightColor: string | null;
sortOrder: number;
isActive: boolean;
isVisible: boolean;
isFeatured: boolean;
maxWallets: number | null;
maxGoals: number | null;
maxTeamMembers: number | null;
apiEnabled: boolean;
apiRateLimit: number | null;
};
} & {
id: string;
userId: string;
status: string;
createdAt: Date;
updatedAt: Date;
planId: string;
startDate: Date;
endDate: Date;
isTrialUsed: boolean;
trialEndDate: Date | null;
cancelledAt: Date | null;
cancellationReason: string | null;
}) | null;
} & {
id: string;
userId: string;
subscriptionId: string | null;
invoiceNumber: string;
amount: import("@prisma/client/runtime/library").Decimal;
currency: string;
method: string;
tripayReference: string | null;
tripayFee: import("@prisma/client/runtime/library").Decimal | null;
totalAmount: import("@prisma/client/runtime/library").Decimal;
paymentChannel: string | null;
paymentUrl: string | null;
qrUrl: string | null;
status: string;
proofImageUrl: string | null;
transferDate: Date | null;
verifiedBy: string | null;
verifiedAt: Date | null;
rejectionReason: string | null;
couponId: string | null;
discountAmount: import("@prisma/client/runtime/library").Decimal | null;
notes: string | null;
expiresAt: Date | null;
paidAt: Date | null;
createdAt: Date;
updatedAt: Date;
})[]>;
findOne(id: string): Promise<({
user: {
id: string;
email: string;
name: string | null;
};
subscription: ({
plan: {
id: string;
currency: string;
createdAt: Date;
updatedAt: Date;
name: string;
slug: string;
description: string | null;
price: import("@prisma/client/runtime/library").Decimal;
durationType: string;
durationDays: number | null;
trialDays: number;
features: import("@prisma/client/runtime/library").JsonValue;
badge: string | null;
badgeColor: string | null;
highlightColor: string | null;
sortOrder: number;
isActive: boolean;
isVisible: boolean;
isFeatured: boolean;
maxWallets: number | null;
maxGoals: number | null;
maxTeamMembers: number | null;
apiEnabled: boolean;
apiRateLimit: number | null;
};
} & {
id: string;
userId: string;
status: string;
createdAt: Date;
updatedAt: Date;
planId: string;
startDate: Date;
endDate: Date;
isTrialUsed: boolean;
trialEndDate: Date | null;
cancelledAt: Date | null;
cancellationReason: string | null;
}) | null;
} & {
id: string;
userId: string;
subscriptionId: string | null;
invoiceNumber: string;
amount: import("@prisma/client/runtime/library").Decimal;
currency: string;
method: string;
tripayReference: string | null;
tripayFee: import("@prisma/client/runtime/library").Decimal | null;
totalAmount: import("@prisma/client/runtime/library").Decimal;
paymentChannel: string | null;
paymentUrl: string | null;
qrUrl: string | null;
status: string;
proofImageUrl: string | null;
transferDate: Date | null;
verifiedBy: string | null;
verifiedAt: Date | null;
rejectionReason: string | null;
couponId: string | null;
discountAmount: import("@prisma/client/runtime/library").Decimal | null;
notes: string | null;
expiresAt: Date | null;
paidAt: Date | null;
createdAt: Date;
updatedAt: Date;
}) | null>;
verify(id: string, adminUserId: string): Promise<{
id: string;
userId: string;
subscriptionId: string | null;
invoiceNumber: string;
amount: import("@prisma/client/runtime/library").Decimal;
currency: string;
method: string;
tripayReference: string | null;
tripayFee: import("@prisma/client/runtime/library").Decimal | null;
totalAmount: import("@prisma/client/runtime/library").Decimal;
paymentChannel: string | null;
paymentUrl: string | null;
qrUrl: string | null;
status: string;
proofImageUrl: string | null;
transferDate: Date | null;
verifiedBy: string | null;
verifiedAt: Date | null;
rejectionReason: string | null;
couponId: string | null;
discountAmount: import("@prisma/client/runtime/library").Decimal | null;
notes: string | null;
expiresAt: Date | null;
paidAt: Date | null;
createdAt: Date;
updatedAt: Date;
}>;
reject(id: string, adminUserId: string, reason: string): Promise<{
id: string;
userId: string;
subscriptionId: string | null;
invoiceNumber: string;
amount: import("@prisma/client/runtime/library").Decimal;
currency: string;
method: string;
tripayReference: string | null;
tripayFee: import("@prisma/client/runtime/library").Decimal | null;
totalAmount: import("@prisma/client/runtime/library").Decimal;
paymentChannel: string | null;
paymentUrl: string | null;
qrUrl: string | null;
status: string;
proofImageUrl: string | null;
transferDate: Date | null;
verifiedBy: string | null;
verifiedAt: Date | null;
rejectionReason: string | null;
couponId: string | null;
discountAmount: import("@prisma/client/runtime/library").Decimal | null;
notes: string | null;
expiresAt: Date | null;
paidAt: Date | null;
createdAt: Date;
updatedAt: Date;
}>;
getPendingCount(): Promise<number>;
}

View File

@@ -0,0 +1,116 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AdminPaymentsService = void 0;
const common_1 = require("@nestjs/common");
const prisma_service_1 = require("../prisma/prisma.service");
let AdminPaymentsService = class AdminPaymentsService {
prisma;
constructor(prisma) {
this.prisma = prisma;
}
async findAll(status) {
return this.prisma.payment.findMany({
where: status ? { status } : undefined,
include: {
user: {
select: {
id: true,
email: true,
name: true,
},
},
subscription: {
include: {
plan: true,
},
},
},
orderBy: { createdAt: 'desc' },
});
}
async findOne(id) {
return this.prisma.payment.findUnique({
where: { id },
include: {
user: {
select: {
id: true,
email: true,
name: true,
},
},
subscription: {
include: {
plan: true,
},
},
},
});
}
async verify(id, adminUserId) {
const payment = await this.prisma.payment.findUnique({
where: { id },
include: { subscription: { include: { plan: true } } },
});
if (!payment) {
throw new Error('Payment not found');
}
const updatedPayment = await this.prisma.payment.update({
where: { id },
data: {
status: 'paid',
verifiedBy: adminUserId,
verifiedAt: new Date(),
paidAt: new Date(),
},
});
if (payment.subscriptionId && payment.subscription) {
const plan = payment.subscription.plan;
const now = new Date();
const endDate = new Date(now);
if (plan.durationDays) {
endDate.setDate(endDate.getDate() + plan.durationDays);
}
await this.prisma.subscription.update({
where: { id: payment.subscriptionId },
data: {
status: 'active',
startDate: now,
endDate: plan.durationType === 'lifetime' ? new Date('2099-12-31') : endDate,
},
});
}
return updatedPayment;
}
async reject(id, adminUserId, reason) {
return this.prisma.payment.update({
where: { id },
data: {
status: 'rejected',
verifiedBy: adminUserId,
verifiedAt: new Date(),
rejectionReason: reason,
},
});
}
async getPendingCount() {
return this.prisma.payment.count({
where: { status: 'pending' },
});
}
};
exports.AdminPaymentsService = AdminPaymentsService;
exports.AdminPaymentsService = AdminPaymentsService = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [prisma_service_1.PrismaService])
], AdminPaymentsService);
//# sourceMappingURL=admin-payments.service.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"admin-payments.service.js","sourceRoot":"","sources":["../../src/admin/admin-payments.service.ts"],"names":[],"mappings":"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"}

View File

@@ -1 +1,148 @@
export {};
import { AdminPlansService } from './admin-plans.service';
export declare class AdminPlansController {
private readonly plansService;
constructor(plansService: AdminPlansService);
findAll(): Promise<({
_count: {
subscriptions: number;
};
} & {
id: string;
name: string;
slug: string;
description: string | null;
price: import("@prisma/client/runtime/library").Decimal;
currency: string;
durationType: string;
durationDays: number | null;
trialDays: number;
features: import("@prisma/client/runtime/library").JsonValue;
badge: string | null;
badgeColor: string | null;
highlightColor: string | null;
sortOrder: number;
isActive: boolean;
isVisible: boolean;
isFeatured: boolean;
maxWallets: number | null;
maxGoals: number | null;
maxTeamMembers: number | null;
apiEnabled: boolean;
apiRateLimit: number | null;
createdAt: Date;
updatedAt: Date;
})[]>;
findOne(id: string): Promise<({
_count: {
subscriptions: number;
};
} & {
id: string;
name: string;
slug: string;
description: string | null;
price: import("@prisma/client/runtime/library").Decimal;
currency: string;
durationType: string;
durationDays: number | null;
trialDays: number;
features: import("@prisma/client/runtime/library").JsonValue;
badge: string | null;
badgeColor: string | null;
highlightColor: string | null;
sortOrder: number;
isActive: boolean;
isVisible: boolean;
isFeatured: boolean;
maxWallets: number | null;
maxGoals: number | null;
maxTeamMembers: number | null;
apiEnabled: boolean;
apiRateLimit: number | null;
createdAt: Date;
updatedAt: Date;
}) | null>;
create(data: any): Promise<{
id: string;
name: string;
slug: string;
description: string | null;
price: import("@prisma/client/runtime/library").Decimal;
currency: string;
durationType: string;
durationDays: number | null;
trialDays: number;
features: import("@prisma/client/runtime/library").JsonValue;
badge: string | null;
badgeColor: string | null;
highlightColor: string | null;
sortOrder: number;
isActive: boolean;
isVisible: boolean;
isFeatured: boolean;
maxWallets: number | null;
maxGoals: number | null;
maxTeamMembers: number | null;
apiEnabled: boolean;
apiRateLimit: number | null;
createdAt: Date;
updatedAt: Date;
}>;
update(id: string, data: any): Promise<{
id: string;
name: string;
slug: string;
description: string | null;
price: import("@prisma/client/runtime/library").Decimal;
currency: string;
durationType: string;
durationDays: number | null;
trialDays: number;
features: import("@prisma/client/runtime/library").JsonValue;
badge: string | null;
badgeColor: string | null;
highlightColor: string | null;
sortOrder: number;
isActive: boolean;
isVisible: boolean;
isFeatured: boolean;
maxWallets: number | null;
maxGoals: number | null;
maxTeamMembers: number | null;
apiEnabled: boolean;
apiRateLimit: number | null;
createdAt: Date;
updatedAt: Date;
}>;
delete(id: string): Promise<{
id: string;
name: string;
slug: string;
description: string | null;
price: import("@prisma/client/runtime/library").Decimal;
currency: string;
durationType: string;
durationDays: number | null;
trialDays: number;
features: import("@prisma/client/runtime/library").JsonValue;
badge: string | null;
badgeColor: string | null;
highlightColor: string | null;
sortOrder: number;
isActive: boolean;
isVisible: boolean;
isFeatured: boolean;
maxWallets: number | null;
maxGoals: number | null;
maxTeamMembers: number | null;
apiEnabled: boolean;
apiRateLimit: number | null;
createdAt: Date;
updatedAt: Date;
}>;
reorder(body: {
planIds: string[];
}): Promise<{
success: boolean;
}>;
}

View File

@@ -1,3 +1,92 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AdminPlansController = void 0;
const common_1 = require("@nestjs/common");
const auth_guard_1 = require("../auth/auth.guard");
const admin_guard_1 = require("./guards/admin.guard");
const admin_plans_service_1 = require("./admin-plans.service");
let AdminPlansController = class AdminPlansController {
plansService;
constructor(plansService) {
this.plansService = plansService;
}
findAll() {
return this.plansService.findAll();
}
findOne(id) {
return this.plansService.findOne(id);
}
create(data) {
return this.plansService.create(data);
}
update(id, data) {
return this.plansService.update(id, data);
}
delete(id) {
return this.plansService.delete(id);
}
reorder(body) {
return this.plansService.reorder(body.planIds);
}
};
exports.AdminPlansController = AdminPlansController;
__decorate([
(0, common_1.Get)(),
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", void 0)
], AdminPlansController.prototype, "findAll", null);
__decorate([
(0, common_1.Get)(':id'),
__param(0, (0, common_1.Param)('id')),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String]),
__metadata("design:returntype", void 0)
], AdminPlansController.prototype, "findOne", null);
__decorate([
(0, common_1.Post)(),
__param(0, (0, common_1.Body)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object]),
__metadata("design:returntype", void 0)
], AdminPlansController.prototype, "create", null);
__decorate([
(0, common_1.Put)(':id'),
__param(0, (0, common_1.Param)('id')),
__param(1, (0, common_1.Body)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String, Object]),
__metadata("design:returntype", void 0)
], AdminPlansController.prototype, "update", null);
__decorate([
(0, common_1.Delete)(':id'),
__param(0, (0, common_1.Param)('id')),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String]),
__metadata("design:returntype", void 0)
], AdminPlansController.prototype, "delete", null);
__decorate([
(0, common_1.Post)('reorder'),
__param(0, (0, common_1.Body)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object]),
__metadata("design:returntype", void 0)
], AdminPlansController.prototype, "reorder", null);
exports.AdminPlansController = AdminPlansController = __decorate([
(0, common_1.Controller)('admin/plans'),
(0, common_1.UseGuards)(auth_guard_1.AuthGuard, admin_guard_1.AdminGuard),
__metadata("design:paramtypes", [admin_plans_service_1.AdminPlansService])
], AdminPlansController);
//# sourceMappingURL=admin-plans.controller.js.map

View File

@@ -1 +1 @@
{"version":3,"file":"admin-plans.controller.js","sourceRoot":"","sources":["../../src/admin/admin-plans.controller.ts"],"names":[],"mappings":""}
{"version":3,"file":"admin-plans.controller.js","sourceRoot":"","sources":["../../src/admin/admin-plans.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CASwB;AACxB,mDAA+C;AAC/C,sDAAkD;AAClD,+DAA0D;AAInD,IAAM,oBAAoB,GAA1B,MAAM,oBAAoB;IACF;IAA7B,YAA6B,YAA+B;QAA/B,iBAAY,GAAZ,YAAY,CAAmB;IAAG,CAAC;IAGhE,OAAO;QACL,OAAO,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,CAAC;IACrC,CAAC;IAGD,OAAO,CAAc,EAAU;QAC7B,OAAO,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACvC,CAAC;IAGD,MAAM,CAAS,IAAS;QACtB,OAAO,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IAGD,MAAM,CAAc,EAAU,EAAU,IAAS;QAC/C,OAAO,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IAC5C,CAAC;IAGD,MAAM,CAAc,EAAU;QAC5B,OAAO,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACtC,CAAC;IAGD,OAAO,CAAS,IAA2B;QACzC,OAAO,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACjD,CAAC;CACF,CAAA;AAhCY,oDAAoB;AAI/B;IADC,IAAA,YAAG,GAAE;;;;mDAGL;AAGD;IADC,IAAA,YAAG,EAAC,KAAK,CAAC;IACF,WAAA,IAAA,cAAK,EAAC,IAAI,CAAC,CAAA;;;;mDAEnB;AAGD;IADC,IAAA,aAAI,GAAE;IACC,WAAA,IAAA,aAAI,GAAE,CAAA;;;;kDAEb;AAGD;IADC,IAAA,YAAG,EAAC,KAAK,CAAC;IACH,WAAA,IAAA,cAAK,EAAC,IAAI,CAAC,CAAA;IAAc,WAAA,IAAA,aAAI,GAAE,CAAA;;;;kDAEtC;AAGD;IADC,IAAA,eAAM,EAAC,KAAK,CAAC;IACN,WAAA,IAAA,cAAK,EAAC,IAAI,CAAC,CAAA;;;;kDAElB;AAGD;IADC,IAAA,aAAI,EAAC,SAAS,CAAC;IACP,WAAA,IAAA,aAAI,GAAE,CAAA;;;;mDAEd;+BA/BU,oBAAoB;IAFhC,IAAA,mBAAU,EAAC,aAAa,CAAC;IACzB,IAAA,kBAAS,EAAC,sBAAS,EAAE,wBAAU,CAAC;qCAEY,uCAAiB;GADjD,oBAAoB,CAgChC"}

View File

@@ -1 +1,146 @@
export {};
import { PrismaService } from '../prisma/prisma.service';
export declare class AdminPlansService {
private readonly prisma;
constructor(prisma: PrismaService);
findAll(): Promise<({
_count: {
subscriptions: number;
};
} & {
id: string;
name: string;
slug: string;
description: string | null;
price: import("@prisma/client/runtime/library").Decimal;
currency: string;
durationType: string;
durationDays: number | null;
trialDays: number;
features: import("@prisma/client/runtime/library").JsonValue;
badge: string | null;
badgeColor: string | null;
highlightColor: string | null;
sortOrder: number;
isActive: boolean;
isVisible: boolean;
isFeatured: boolean;
maxWallets: number | null;
maxGoals: number | null;
maxTeamMembers: number | null;
apiEnabled: boolean;
apiRateLimit: number | null;
createdAt: Date;
updatedAt: Date;
})[]>;
findOne(id: string): Promise<({
_count: {
subscriptions: number;
};
} & {
id: string;
name: string;
slug: string;
description: string | null;
price: import("@prisma/client/runtime/library").Decimal;
currency: string;
durationType: string;
durationDays: number | null;
trialDays: number;
features: import("@prisma/client/runtime/library").JsonValue;
badge: string | null;
badgeColor: string | null;
highlightColor: string | null;
sortOrder: number;
isActive: boolean;
isVisible: boolean;
isFeatured: boolean;
maxWallets: number | null;
maxGoals: number | null;
maxTeamMembers: number | null;
apiEnabled: boolean;
apiRateLimit: number | null;
createdAt: Date;
updatedAt: Date;
}) | null>;
create(data: any): Promise<{
id: string;
name: string;
slug: string;
description: string | null;
price: import("@prisma/client/runtime/library").Decimal;
currency: string;
durationType: string;
durationDays: number | null;
trialDays: number;
features: import("@prisma/client/runtime/library").JsonValue;
badge: string | null;
badgeColor: string | null;
highlightColor: string | null;
sortOrder: number;
isActive: boolean;
isVisible: boolean;
isFeatured: boolean;
maxWallets: number | null;
maxGoals: number | null;
maxTeamMembers: number | null;
apiEnabled: boolean;
apiRateLimit: number | null;
createdAt: Date;
updatedAt: Date;
}>;
update(id: string, data: any): Promise<{
id: string;
name: string;
slug: string;
description: string | null;
price: import("@prisma/client/runtime/library").Decimal;
currency: string;
durationType: string;
durationDays: number | null;
trialDays: number;
features: import("@prisma/client/runtime/library").JsonValue;
badge: string | null;
badgeColor: string | null;
highlightColor: string | null;
sortOrder: number;
isActive: boolean;
isVisible: boolean;
isFeatured: boolean;
maxWallets: number | null;
maxGoals: number | null;
maxTeamMembers: number | null;
apiEnabled: boolean;
apiRateLimit: number | null;
createdAt: Date;
updatedAt: Date;
}>;
delete(id: string): Promise<{
id: string;
name: string;
slug: string;
description: string | null;
price: import("@prisma/client/runtime/library").Decimal;
currency: string;
durationType: string;
durationDays: number | null;
trialDays: number;
features: import("@prisma/client/runtime/library").JsonValue;
badge: string | null;
badgeColor: string | null;
highlightColor: string | null;
sortOrder: number;
isActive: boolean;
isVisible: boolean;
isFeatured: boolean;
maxWallets: number | null;
maxGoals: number | null;
maxTeamMembers: number | null;
apiEnabled: boolean;
apiRateLimit: number | null;
createdAt: Date;
updatedAt: Date;
}>;
reorder(planIds: string[]): Promise<{
success: boolean;
}>;
}

View File

@@ -1,3 +1,71 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AdminPlansService = void 0;
const common_1 = require("@nestjs/common");
const prisma_service_1 = require("../prisma/prisma.service");
let AdminPlansService = class AdminPlansService {
prisma;
constructor(prisma) {
this.prisma = prisma;
}
async findAll() {
return this.prisma.plan.findMany({
orderBy: { sortOrder: 'asc' },
include: {
_count: {
select: { subscriptions: true },
},
},
});
}
async findOne(id) {
return this.prisma.plan.findUnique({
where: { id },
include: {
_count: {
select: { subscriptions: true },
},
},
});
}
async create(data) {
return this.prisma.plan.create({
data,
});
}
async update(id, data) {
return this.prisma.plan.update({
where: { id },
data,
});
}
async delete(id) {
return this.prisma.plan.update({
where: { id },
data: { isActive: false, isVisible: false },
});
}
async reorder(planIds) {
const updates = planIds.map((id, index) => this.prisma.plan.update({
where: { id },
data: { sortOrder: index + 1 },
}));
await this.prisma.$transaction(updates);
return { success: true };
}
};
exports.AdminPlansService = AdminPlansService;
exports.AdminPlansService = AdminPlansService = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [prisma_service_1.PrismaService])
], AdminPlansService);
//# sourceMappingURL=admin-plans.service.js.map

View File

@@ -1 +1 @@
{"version":3,"file":"admin-plans.service.js","sourceRoot":"","sources":["../../src/admin/admin-plans.service.ts"],"names":[],"mappings":""}
{"version":3,"file":"admin-plans.service.js","sourceRoot":"","sources":["../../src/admin/admin-plans.service.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAA4C;AAC5C,6DAAyD;AAGlD,IAAM,iBAAiB,GAAvB,MAAM,iBAAiB;IACC;IAA7B,YAA6B,MAAqB;QAArB,WAAM,GAAN,MAAM,CAAe;IAAG,CAAC;IAEtD,KAAK,CAAC,OAAO;QACX,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC;YAC/B,OAAO,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE;YAC7B,OAAO,EAAE;gBACP,MAAM,EAAE;oBACN,MAAM,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE;iBAChC;aACF;SACF,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,EAAU;QACtB,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC;YACjC,KAAK,EAAE,EAAE,EAAE,EAAE;YACb,OAAO,EAAE;gBACP,MAAM,EAAE;oBACN,MAAM,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE;iBAChC;aACF;SACF,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,IAAS;QACpB,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;YAC7B,IAAI;SACL,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,EAAU,EAAE,IAAS;QAChC,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;YAC7B,KAAK,EAAE,EAAE,EAAE,EAAE;YACb,IAAI;SACL,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,EAAU;QAErB,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;YAC7B,KAAK,EAAE,EAAE,EAAE,EAAE;YACb,IAAI,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE;SAC5C,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,OAAiB;QAE7B,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE,CACxC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;YACtB,KAAK,EAAE,EAAE,EAAE,EAAE;YACb,IAAI,EAAE,EAAE,SAAS,EAAE,KAAK,GAAG,CAAC,EAAE;SAC/B,CAAC,CACH,CAAC;QAEF,MAAM,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;QACxC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC3B,CAAC;CACF,CAAA;AA1DY,8CAAiB;4BAAjB,iBAAiB;IAD7B,IAAA,mBAAU,GAAE;qCAE0B,8BAAa;GADvC,iBAAiB,CA0D7B"}

View File

@@ -0,0 +1,180 @@
import { AdminUsersService } from './admin-users.service';
export declare class AdminUsersController {
private readonly service;
constructor(service: AdminUsersService);
findAll(search?: string): Promise<{
id: string;
createdAt: Date;
email: string;
emailVerified: boolean;
name: string | null;
role: string;
suspendedAt: Date | null;
lastLoginAt: Date | null;
_count: {
transactions: number;
wallets: number;
};
}[]>;
getStats(): Promise<{
totalUsers: number;
activeSubscriptions: number;
suspendedUsers: number;
}>;
findOne(id: string): Promise<({
subscriptions: ({
plan: {
id: string;
createdAt: Date;
updatedAt: Date;
name: string;
slug: string;
description: string | null;
price: import("@prisma/client/runtime/library").Decimal;
currency: string;
durationType: string;
durationDays: number | null;
trialDays: number;
features: import("@prisma/client/runtime/library").JsonValue;
badge: string | null;
badgeColor: string | null;
highlightColor: string | null;
sortOrder: number;
isActive: boolean;
isVisible: boolean;
isFeatured: boolean;
maxWallets: number | null;
maxGoals: number | null;
maxTeamMembers: number | null;
apiEnabled: boolean;
apiRateLimit: number | null;
};
} & {
id: string;
createdAt: Date;
updatedAt: Date;
status: string;
userId: string;
planId: string;
startDate: Date;
endDate: Date;
isTrialUsed: boolean;
trialEndDate: Date | null;
cancelledAt: Date | null;
cancellationReason: string | null;
})[];
_count: {
transactions: number;
wallets: number;
payments: number;
};
} & {
id: string;
createdAt: Date;
updatedAt: Date;
status: string;
email: string;
emailVerified: boolean;
passwordHash: string | null;
name: string | null;
avatarUrl: string | null;
phone: string | null;
defaultCurrency: string | null;
timeZone: string | null;
otpEmailEnabled: boolean;
otpWhatsappEnabled: boolean;
otpTotpEnabled: boolean;
otpTotpSecret: string | null;
role: string;
suspendedAt: Date | null;
suspendedReason: string | null;
lastLoginAt: Date | null;
}) | null>;
updateRole(id: string, body: {
role: string;
}): Promise<{
id: string;
createdAt: Date;
updatedAt: Date;
status: string;
email: string;
emailVerified: boolean;
passwordHash: string | null;
name: string | null;
avatarUrl: string | null;
phone: string | null;
defaultCurrency: string | null;
timeZone: string | null;
otpEmailEnabled: boolean;
otpWhatsappEnabled: boolean;
otpTotpEnabled: boolean;
otpTotpSecret: string | null;
role: string;
suspendedAt: Date | null;
suspendedReason: string | null;
lastLoginAt: Date | null;
}>;
suspend(id: string, body: {
reason: string;
}): Promise<{
id: string;
createdAt: Date;
updatedAt: Date;
status: string;
email: string;
emailVerified: boolean;
passwordHash: string | null;
name: string | null;
avatarUrl: string | null;
phone: string | null;
defaultCurrency: string | null;
timeZone: string | null;
otpEmailEnabled: boolean;
otpWhatsappEnabled: boolean;
otpTotpEnabled: boolean;
otpTotpSecret: string | null;
role: string;
suspendedAt: Date | null;
suspendedReason: string | null;
lastLoginAt: Date | null;
}>;
unsuspend(id: string): Promise<{
id: string;
createdAt: Date;
updatedAt: Date;
status: string;
email: string;
emailVerified: boolean;
passwordHash: string | null;
name: string | null;
avatarUrl: string | null;
phone: string | null;
defaultCurrency: string | null;
timeZone: string | null;
otpEmailEnabled: boolean;
otpWhatsappEnabled: boolean;
otpTotpEnabled: boolean;
otpTotpSecret: string | null;
role: string;
suspendedAt: Date | null;
suspendedReason: string | null;
lastLoginAt: Date | null;
}>;
grantProAccess(id: string, body: {
planSlug: string;
durationDays: number;
}): Promise<{
id: string;
createdAt: Date;
updatedAt: Date;
status: string;
userId: string;
planId: string;
startDate: Date;
endDate: Date;
isTrialUsed: boolean;
trialEndDate: Date | null;
cancelledAt: Date | null;
cancellationReason: string | null;
}>;
}

View File

@@ -0,0 +1,104 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AdminUsersController = void 0;
const common_1 = require("@nestjs/common");
const auth_guard_1 = require("../auth/auth.guard");
const admin_guard_1 = require("./guards/admin.guard");
const admin_users_service_1 = require("./admin-users.service");
let AdminUsersController = class AdminUsersController {
service;
constructor(service) {
this.service = service;
}
findAll(search) {
return this.service.findAll(search);
}
getStats() {
return this.service.getStats();
}
findOne(id) {
return this.service.findOne(id);
}
updateRole(id, body) {
return this.service.updateRole(id, body.role);
}
suspend(id, body) {
return this.service.suspend(id, body.reason);
}
unsuspend(id) {
return this.service.unsuspend(id);
}
grantProAccess(id, body) {
return this.service.grantProAccess(id, body.planSlug, body.durationDays);
}
};
exports.AdminUsersController = AdminUsersController;
__decorate([
(0, common_1.Get)(),
__param(0, (0, common_1.Query)('search')),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String]),
__metadata("design:returntype", void 0)
], AdminUsersController.prototype, "findAll", null);
__decorate([
(0, common_1.Get)('stats'),
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", void 0)
], AdminUsersController.prototype, "getStats", null);
__decorate([
(0, common_1.Get)(':id'),
__param(0, (0, common_1.Param)('id')),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String]),
__metadata("design:returntype", void 0)
], AdminUsersController.prototype, "findOne", null);
__decorate([
(0, common_1.Put)(':id/role'),
__param(0, (0, common_1.Param)('id')),
__param(1, (0, common_1.Body)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String, Object]),
__metadata("design:returntype", void 0)
], AdminUsersController.prototype, "updateRole", null);
__decorate([
(0, common_1.Post)(':id/suspend'),
__param(0, (0, common_1.Param)('id')),
__param(1, (0, common_1.Body)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String, Object]),
__metadata("design:returntype", void 0)
], AdminUsersController.prototype, "suspend", null);
__decorate([
(0, common_1.Post)(':id/unsuspend'),
__param(0, (0, common_1.Param)('id')),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String]),
__metadata("design:returntype", void 0)
], AdminUsersController.prototype, "unsuspend", null);
__decorate([
(0, common_1.Post)(':id/grant-pro'),
__param(0, (0, common_1.Param)('id')),
__param(1, (0, common_1.Body)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String, Object]),
__metadata("design:returntype", void 0)
], AdminUsersController.prototype, "grantProAccess", null);
exports.AdminUsersController = AdminUsersController = __decorate([
(0, common_1.Controller)('admin/users'),
(0, common_1.UseGuards)(auth_guard_1.AuthGuard, admin_guard_1.AdminGuard),
__metadata("design:paramtypes", [admin_users_service_1.AdminUsersService])
], AdminUsersController);
//# sourceMappingURL=admin-users.controller.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"admin-users.controller.js","sourceRoot":"","sources":["../../src/admin/admin-users.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CASwB;AACxB,mDAA+C;AAC/C,sDAAkD;AAClD,+DAA0D;AAInD,IAAM,oBAAoB,GAA1B,MAAM,oBAAoB;IACF;IAA7B,YAA6B,OAA0B;QAA1B,YAAO,GAAP,OAAO,CAAmB;IAAG,CAAC;IAG3D,OAAO,CAAkB,MAAe;QACtC,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACtC,CAAC;IAGD,QAAQ;QACN,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;IACjC,CAAC;IAGD,OAAO,CAAc,EAAU;QAC7B,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAClC,CAAC;IAGD,UAAU,CAAc,EAAU,EAAU,IAAsB;QAChE,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IAChD,CAAC;IAGD,OAAO,CAAc,EAAU,EAAU,IAAwB;QAC/D,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IAC/C,CAAC;IAGD,SAAS,CAAc,EAAU;QAC/B,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IACpC,CAAC;IAGD,cAAc,CACC,EAAU,EACf,IAAgD;QAExD,OAAO,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;IAC3E,CAAC;CACF,CAAA;AAxCY,oDAAoB;AAI/B;IADC,IAAA,YAAG,GAAE;IACG,WAAA,IAAA,cAAK,EAAC,QAAQ,CAAC,CAAA;;;;mDAEvB;AAGD;IADC,IAAA,YAAG,EAAC,OAAO,CAAC;;;;oDAGZ;AAGD;IADC,IAAA,YAAG,EAAC,KAAK,CAAC;IACF,WAAA,IAAA,cAAK,EAAC,IAAI,CAAC,CAAA;;;;mDAEnB;AAGD;IADC,IAAA,YAAG,EAAC,UAAU,CAAC;IACJ,WAAA,IAAA,cAAK,EAAC,IAAI,CAAC,CAAA;IAAc,WAAA,IAAA,aAAI,GAAE,CAAA;;;;sDAE1C;AAGD;IADC,IAAA,aAAI,EAAC,aAAa,CAAC;IACX,WAAA,IAAA,cAAK,EAAC,IAAI,CAAC,CAAA;IAAc,WAAA,IAAA,aAAI,GAAE,CAAA;;;;mDAEvC;AAGD;IADC,IAAA,aAAI,EAAC,eAAe,CAAC;IACX,WAAA,IAAA,cAAK,EAAC,IAAI,CAAC,CAAA;;;;qDAErB;AAGD;IADC,IAAA,aAAI,EAAC,eAAe,CAAC;IAEnB,WAAA,IAAA,cAAK,EAAC,IAAI,CAAC,CAAA;IACX,WAAA,IAAA,aAAI,GAAE,CAAA;;;;0DAGR;+BAvCU,oBAAoB;IAFhC,IAAA,mBAAU,EAAC,aAAa,CAAC;IACzB,IAAA,kBAAS,EAAC,sBAAS,EAAE,wBAAU,CAAC;qCAEO,uCAAiB;GAD5C,oBAAoB,CAwChC"}

View File

@@ -0,0 +1,173 @@
import { PrismaService } from '../prisma/prisma.service';
export declare class AdminUsersService {
private readonly prisma;
constructor(prisma: PrismaService);
findAll(search?: string): Promise<{
id: string;
createdAt: Date;
email: string;
emailVerified: boolean;
name: string | null;
role: string;
suspendedAt: Date | null;
lastLoginAt: Date | null;
_count: {
transactions: number;
wallets: number;
};
}[]>;
findOne(id: string): Promise<({
subscriptions: ({
plan: {
id: string;
createdAt: Date;
updatedAt: Date;
name: string;
slug: string;
description: string | null;
price: import("@prisma/client/runtime/library").Decimal;
currency: string;
durationType: string;
durationDays: number | null;
trialDays: number;
features: import("@prisma/client/runtime/library").JsonValue;
badge: string | null;
badgeColor: string | null;
highlightColor: string | null;
sortOrder: number;
isActive: boolean;
isVisible: boolean;
isFeatured: boolean;
maxWallets: number | null;
maxGoals: number | null;
maxTeamMembers: number | null;
apiEnabled: boolean;
apiRateLimit: number | null;
};
} & {
id: string;
createdAt: Date;
updatedAt: Date;
status: string;
userId: string;
planId: string;
startDate: Date;
endDate: Date;
isTrialUsed: boolean;
trialEndDate: Date | null;
cancelledAt: Date | null;
cancellationReason: string | null;
})[];
_count: {
transactions: number;
wallets: number;
payments: number;
};
} & {
id: string;
createdAt: Date;
updatedAt: Date;
status: string;
email: string;
emailVerified: boolean;
passwordHash: string | null;
name: string | null;
avatarUrl: string | null;
phone: string | null;
defaultCurrency: string | null;
timeZone: string | null;
otpEmailEnabled: boolean;
otpWhatsappEnabled: boolean;
otpTotpEnabled: boolean;
otpTotpSecret: string | null;
role: string;
suspendedAt: Date | null;
suspendedReason: string | null;
lastLoginAt: Date | null;
}) | null>;
updateRole(id: string, role: string): Promise<{
id: string;
createdAt: Date;
updatedAt: Date;
status: string;
email: string;
emailVerified: boolean;
passwordHash: string | null;
name: string | null;
avatarUrl: string | null;
phone: string | null;
defaultCurrency: string | null;
timeZone: string | null;
otpEmailEnabled: boolean;
otpWhatsappEnabled: boolean;
otpTotpEnabled: boolean;
otpTotpSecret: string | null;
role: string;
suspendedAt: Date | null;
suspendedReason: string | null;
lastLoginAt: Date | null;
}>;
suspend(id: string, reason: string): Promise<{
id: string;
createdAt: Date;
updatedAt: Date;
status: string;
email: string;
emailVerified: boolean;
passwordHash: string | null;
name: string | null;
avatarUrl: string | null;
phone: string | null;
defaultCurrency: string | null;
timeZone: string | null;
otpEmailEnabled: boolean;
otpWhatsappEnabled: boolean;
otpTotpEnabled: boolean;
otpTotpSecret: string | null;
role: string;
suspendedAt: Date | null;
suspendedReason: string | null;
lastLoginAt: Date | null;
}>;
unsuspend(id: string): Promise<{
id: string;
createdAt: Date;
updatedAt: Date;
status: string;
email: string;
emailVerified: boolean;
passwordHash: string | null;
name: string | null;
avatarUrl: string | null;
phone: string | null;
defaultCurrency: string | null;
timeZone: string | null;
otpEmailEnabled: boolean;
otpWhatsappEnabled: boolean;
otpTotpEnabled: boolean;
otpTotpSecret: string | null;
role: string;
suspendedAt: Date | null;
suspendedReason: string | null;
lastLoginAt: Date | null;
}>;
grantProAccess(userId: string, planSlug: string, durationDays: number): Promise<{
id: string;
createdAt: Date;
updatedAt: Date;
status: string;
userId: string;
planId: string;
startDate: Date;
endDate: Date;
isTrialUsed: boolean;
trialEndDate: Date | null;
cancelledAt: Date | null;
cancellationReason: string | null;
}>;
getStats(): Promise<{
totalUsers: number;
activeSubscriptions: number;
suspendedUsers: number;
}>;
}

View File

@@ -0,0 +1,148 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AdminUsersService = void 0;
const common_1 = require("@nestjs/common");
const prisma_service_1 = require("../prisma/prisma.service");
let AdminUsersService = class AdminUsersService {
prisma;
constructor(prisma) {
this.prisma = prisma;
}
async findAll(search) {
return this.prisma.user.findMany({
where: search
? {
OR: [
{ email: { contains: search, mode: 'insensitive' } },
{ name: { contains: search, mode: 'insensitive' } },
],
}
: undefined,
select: {
id: true,
email: true,
name: true,
role: true,
emailVerified: true,
createdAt: true,
lastLoginAt: true,
suspendedAt: true,
_count: {
select: {
wallets: true,
transactions: true,
},
},
},
orderBy: { createdAt: 'desc' },
});
}
async findOne(id) {
return this.prisma.user.findUnique({
where: { id },
include: {
subscriptions: {
include: {
plan: true,
},
},
_count: {
select: {
wallets: true,
transactions: true,
payments: true,
},
},
},
});
}
async updateRole(id, role) {
return this.prisma.user.update({
where: { id },
data: { role },
});
}
async suspend(id, reason) {
return this.prisma.user.update({
where: { id },
data: {
suspendedAt: new Date(),
suspendedReason: reason,
},
});
}
async unsuspend(id) {
return this.prisma.user.update({
where: { id },
data: {
suspendedAt: null,
suspendedReason: null,
},
});
}
async grantProAccess(userId, planSlug, durationDays) {
const plan = await this.prisma.plan.findUnique({
where: { slug: planSlug },
});
if (!plan) {
throw new Error('Plan not found');
}
const now = new Date();
const endDate = new Date(now);
endDate.setDate(endDate.getDate() + durationDays);
const existing = await this.prisma.subscription.findUnique({
where: { userId },
});
if (existing) {
return this.prisma.subscription.update({
where: { userId },
data: {
planId: plan.id,
status: 'active',
startDate: now,
endDate,
},
});
}
else {
return this.prisma.subscription.create({
data: {
userId,
planId: plan.id,
status: 'active',
startDate: now,
endDate,
},
});
}
}
async getStats() {
const totalUsers = await this.prisma.user.count();
const activeSubscriptions = await this.prisma.subscription.count({
where: { status: 'active' },
});
const suspendedUsers = await this.prisma.user.count({
where: { suspendedAt: { not: null } },
});
return {
totalUsers,
activeSubscriptions,
suspendedUsers,
};
}
};
exports.AdminUsersService = AdminUsersService;
exports.AdminUsersService = AdminUsersService = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [prisma_service_1.PrismaService])
], AdminUsersService);
//# sourceMappingURL=admin-users.service.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"admin-users.service.js","sourceRoot":"","sources":["../../src/admin/admin-users.service.ts"],"names":[],"mappings":"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"}

View File

@@ -1 +1,2 @@
export {};
export declare class AdminModule {
}

View File

@@ -1,3 +1,54 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AdminModule = void 0;
const common_1 = require("@nestjs/common");
const prisma_module_1 = require("../prisma/prisma.module");
const admin_guard_1 = require("./guards/admin.guard");
const admin_plans_controller_1 = require("./admin-plans.controller");
const admin_payment_methods_controller_1 = require("./admin-payment-methods.controller");
const admin_payments_controller_1 = require("./admin-payments.controller");
const admin_users_controller_1 = require("./admin-users.controller");
const admin_config_controller_1 = require("./admin-config.controller");
const admin_plans_service_1 = require("./admin-plans.service");
const admin_payment_methods_service_1 = require("./admin-payment-methods.service");
const admin_payments_service_1 = require("./admin-payments.service");
const admin_users_service_1 = require("./admin-users.service");
const admin_config_service_1 = require("./admin-config.service");
let AdminModule = class AdminModule {
};
exports.AdminModule = AdminModule;
exports.AdminModule = AdminModule = __decorate([
(0, common_1.Module)({
imports: [prisma_module_1.PrismaModule],
controllers: [
admin_plans_controller_1.AdminPlansController,
admin_payment_methods_controller_1.AdminPaymentMethodsController,
admin_payments_controller_1.AdminPaymentsController,
admin_users_controller_1.AdminUsersController,
admin_config_controller_1.AdminConfigController,
],
providers: [
admin_guard_1.AdminGuard,
admin_plans_service_1.AdminPlansService,
admin_payment_methods_service_1.AdminPaymentMethodsService,
admin_payments_service_1.AdminPaymentsService,
admin_users_service_1.AdminUsersService,
admin_config_service_1.AdminConfigService,
],
exports: [
admin_guard_1.AdminGuard,
admin_plans_service_1.AdminPlansService,
admin_payment_methods_service_1.AdminPaymentMethodsService,
admin_payments_service_1.AdminPaymentsService,
admin_users_service_1.AdminUsersService,
admin_config_service_1.AdminConfigService,
],
})
], AdminModule);
//# sourceMappingURL=admin.module.js.map

View File

@@ -1 +1 @@
{"version":3,"file":"admin.module.js","sourceRoot":"","sources":["../../src/admin/admin.module.ts"],"names":[],"mappings":""}
{"version":3,"file":"admin.module.js","sourceRoot":"","sources":["../../src/admin/admin.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,2DAAuD;AACvD,sDAAkD;AAGlD,qEAAgE;AAChE,yFAAmF;AACnF,2EAAsE;AACtE,qEAAgE;AAChE,uEAAkE;AAGlE,+DAA0D;AAC1D,mFAA6E;AAC7E,qEAAgE;AAChE,+DAA0D;AAC1D,iEAA4D;AA4BrD,IAAM,WAAW,GAAjB,MAAM,WAAW;CAAG,CAAA;AAAd,kCAAW;sBAAX,WAAW;IA1BvB,IAAA,eAAM,EAAC;QACN,OAAO,EAAE,CAAC,4BAAY,CAAC;QACvB,WAAW,EAAE;YACX,6CAAoB;YACpB,gEAA6B;YAC7B,mDAAuB;YACvB,6CAAoB;YACpB,+CAAqB;SACtB;QACD,SAAS,EAAE;YACT,wBAAU;YACV,uCAAiB;YACjB,0DAA0B;YAC1B,6CAAoB;YACpB,uCAAiB;YACjB,yCAAkB;SACnB;QACD,OAAO,EAAE;YACP,wBAAU;YACV,uCAAiB;YACjB,0DAA0B;YAC1B,6CAAoB;YACpB,uCAAiB;YACjB,yCAAkB;SACnB;KACF,CAAC;GACW,WAAW,CAAG"}

View File

@@ -51,6 +51,7 @@ const wallets_module_1 = require("./wallets/wallets.module");
const transactions_module_1 = require("./transactions/transactions.module");
const categories_module_1 = require("./categories/categories.module");
const otp_module_1 = require("./otp/otp.module");
const admin_module_1 = require("./admin/admin.module");
let AppModule = class AppModule {
};
exports.AppModule = AppModule;
@@ -71,6 +72,7 @@ exports.AppModule = AppModule = __decorate([
transactions_module_1.TransactionsModule,
categories_module_1.CategoriesModule,
otp_module_1.OtpModule,
admin_module_1.AdminModule,
],
controllers: [health_controller_1.HealthController],
providers: [],

View File

@@ -1 +1 @@
{"version":3,"file":"app.module.js","sourceRoot":"","sources":["../src/app.module.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,2CAAwC;AACxC,2CAA8C;AAC9C,2CAA6B;AAC7B,0DAAsD;AACtD,oDAAgD;AAChD,kEAA8D;AAC9D,uDAAmD;AACnD,6DAAyD;AACzD,4EAAwE;AACxE,sEAAkE;AAClE,iDAA6C;AAsBtC,IAAM,SAAS,GAAf,MAAM,SAAS;CAAG,CAAA;AAAZ,8BAAS;oBAAT,SAAS;IApBrB,IAAA,eAAM,EAAC;QACN,OAAO,EAAE;YACP,qBAAY,CAAC,OAAO,CAAC;gBACnB,QAAQ,EAAE,IAAI;gBACd,WAAW,EAAE;oBACX,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC;oBACnC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,YAAY,CAAC;iBAC1C;aACF,CAAC;YACF,4BAAY;YACZ,wBAAU;YACV,0BAAW;YACX,8BAAa;YACb,wCAAkB;YAClB,oCAAgB;YAChB,sBAAS;SACV;QACD,WAAW,EAAE,CAAC,oCAAgB,CAAC;QAC/B,SAAS,EAAE,EAAE;KACd,CAAC;GACW,SAAS,CAAG"}
{"version":3,"file":"app.module.js","sourceRoot":"","sources":["../src/app.module.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,2CAAwC;AACxC,2CAA8C;AAC9C,2CAA6B;AAC7B,0DAAsD;AACtD,oDAAgD;AAChD,kEAA8D;AAC9D,uDAAmD;AACnD,6DAAyD;AACzD,4EAAwE;AACxE,sEAAkE;AAClE,iDAA6C;AAC7C,uDAAmD;AAuB5C,IAAM,SAAS,GAAf,MAAM,SAAS;CAAG,CAAA;AAAZ,8BAAS;oBAAT,SAAS;IArBrB,IAAA,eAAM,EAAC;QACN,OAAO,EAAE;YACP,qBAAY,CAAC,OAAO,CAAC;gBACnB,QAAQ,EAAE,IAAI;gBACd,WAAW,EAAE;oBACX,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC;oBACnC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,YAAY,CAAC;iBAC1C;aACF,CAAC;YACF,4BAAY;YACZ,wBAAU;YACV,0BAAW;YACX,8BAAa;YACb,wCAAkB;YAClB,oCAAgB;YAChB,sBAAS;YACT,0BAAW;SACZ;QACD,WAAW,EAAE,CAAC,oCAAgB,CAAC;QAC/B,SAAS,EAAE,EAAE;KACd,CAAC;GACW,SAAS,CAAG"}

View File

@@ -6,7 +6,7 @@ export interface JwtPayload {
iat?: number;
exp?: number;
}
declare const JwtStrategy_base: new (...args: [opt: import("passport-jwt").StrategyOptionsWithoutRequest] | [opt: import("passport-jwt").StrategyOptionsWithRequest]) => Strategy & {
declare const JwtStrategy_base: new (...args: [opt: import("passport-jwt").StrategyOptionsWithRequest] | [opt: import("passport-jwt").StrategyOptionsWithoutRequest]) => Strategy & {
validate(...args: any[]): unknown;
};
export declare class JwtStrategy extends JwtStrategy_base {

View File

@@ -13,11 +13,11 @@ export declare class TransactionsController {
id: string;
createdAt: Date;
userId: string;
walletId: string;
date: Date;
amount: import("@prisma/client/runtime/library").Decimal;
direction: string;
date: Date;
memo: string | null;
walletId: string;
recurrenceId: string | null;
}[]>;
create(req: RequestWithUser, walletId: string, body: {
@@ -31,11 +31,11 @@ export declare class TransactionsController {
id: string;
createdAt: Date;
userId: string;
walletId: string;
date: Date;
amount: import("@prisma/client/runtime/library").Decimal;
direction: string;
date: Date;
memo: string | null;
walletId: string;
recurrenceId: string | null;
}>;
exportCsv(req: RequestWithUser, walletId: string, from: string | undefined, to: string | undefined, category: string | undefined, direction: 'in' | 'out' | undefined, res: Response): Promise<void>;
@@ -44,11 +44,11 @@ export declare class TransactionsController {
id: string;
createdAt: Date;
userId: string;
walletId: string;
date: Date;
amount: import("@prisma/client/runtime/library").Decimal;
direction: string;
date: Date;
memo: string | null;
walletId: string;
recurrenceId: string | null;
}>;
delete(req: RequestWithUser, walletId: string, id: string): Promise<{
@@ -56,11 +56,11 @@ export declare class TransactionsController {
id: string;
createdAt: Date;
userId: string;
walletId: string;
date: Date;
amount: import("@prisma/client/runtime/library").Decimal;
direction: string;
date: Date;
memo: string | null;
walletId: string;
recurrenceId: string | null;
}>;
}

View File

@@ -9,11 +9,11 @@ export declare class TransactionsService {
id: string;
createdAt: Date;
userId: string;
walletId: string;
date: Date;
amount: Prisma.Decimal;
direction: string;
date: Date;
memo: string | null;
walletId: string;
recurrenceId: string | null;
}[]>;
listAll(userId: string): Prisma.PrismaPromise<{
@@ -21,11 +21,11 @@ export declare class TransactionsService {
id: string;
createdAt: Date;
userId: string;
walletId: string;
date: Date;
amount: Prisma.Decimal;
direction: string;
date: Date;
memo: string | null;
walletId: string;
recurrenceId: string | null;
}[]>;
listWithFilters(userId: string, walletId: string, filters: {
@@ -38,11 +38,11 @@ export declare class TransactionsService {
id: string;
createdAt: Date;
userId: string;
walletId: string;
date: Date;
amount: Prisma.Decimal;
direction: string;
date: Date;
memo: string | null;
walletId: string;
recurrenceId: string | null;
}[]>;
create(userId: string, walletId: string, input: {
@@ -56,11 +56,11 @@ export declare class TransactionsService {
id: string;
createdAt: Date;
userId: string;
walletId: string;
date: Date;
amount: Prisma.Decimal;
direction: string;
date: Date;
memo: string | null;
walletId: string;
recurrenceId: string | null;
}>;
update(userId: string, walletId: string, id: string, dto: TransactionUpdateDto): Promise<{
@@ -68,11 +68,11 @@ export declare class TransactionsService {
id: string;
createdAt: Date;
userId: string;
walletId: string;
date: Date;
amount: Prisma.Decimal;
direction: string;
date: Date;
memo: string | null;
walletId: string;
recurrenceId: string | null;
}>;
delete(userId: string, walletId: string, id: string): Promise<{
@@ -80,11 +80,11 @@ export declare class TransactionsService {
id: string;
createdAt: Date;
userId: string;
walletId: string;
date: Date;
amount: Prisma.Decimal;
direction: string;
date: Date;
memo: string | null;
walletId: string;
recurrenceId: string | null;
}>;
}

File diff suppressed because one or more lines are too long

View File

@@ -27,11 +27,11 @@ export declare class WalletsController {
id: string;
createdAt: Date;
userId: string;
walletId: string;
date: Date;
amount: import("@prisma/client/runtime/library").Decimal;
direction: string;
date: Date;
memo: string | null;
walletId: string;
recurrenceId: string | null;
}[]>;
create(req: RequestWithUser, body: {

View File

@@ -0,0 +1,55 @@
import {
Controller,
Get,
Post,
Delete,
Body,
Param,
Query,
UseGuards,
Req,
} from '@nestjs/common';
import { AuthGuard } from '../auth/auth.guard';
import { AdminGuard } from './guards/admin.guard';
import { AdminConfigService } from './admin-config.service';
interface RequestWithUser {
user: {
userId: string;
};
}
@Controller('admin/config')
@UseGuards(AuthGuard, AdminGuard)
export class AdminConfigController {
constructor(private readonly service: AdminConfigService) {}
@Get()
findAll(@Query('category') category?: string) {
return this.service.findAll(category);
}
@Get('by-category')
getByCategory() {
return this.service.getByCategory();
}
@Get(':key')
findOne(@Param('key') key: string) {
return this.service.findOne(key);
}
@Post(':key')
upsert(
@Param('key') key: string,
@Body() data: any,
@Req() req: RequestWithUser,
) {
return this.service.upsert(key, data, req.user.userId);
}
@Delete(':key')
delete(@Param('key') key: string) {
return this.service.delete(key);
}
}

View File

@@ -0,0 +1,57 @@
import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
@Injectable()
export class AdminConfigService {
constructor(private readonly prisma: PrismaService) {}
async findAll(category?: string) {
return this.prisma.appConfig.findMany({
where: category ? { category } : undefined,
orderBy: { category: 'asc' },
});
}
async findOne(key: string) {
return this.prisma.appConfig.findUnique({
where: { key },
});
}
async upsert(key: string, data: any, updatedBy: string) {
return this.prisma.appConfig.upsert({
where: { key },
update: {
...data,
updatedBy,
updatedAt: new Date(),
},
create: {
key,
...data,
updatedBy,
},
});
}
async delete(key: string) {
return this.prisma.appConfig.delete({
where: { key },
});
}
async getByCategory() {
const configs = await this.prisma.appConfig.findMany();
// Group by category
const grouped = configs.reduce((acc, config) => {
if (!acc[config.category]) {
acc[config.category] = [];
}
acc[config.category].push(config);
return acc;
}, {} as Record<string, any[]>);
return grouped;
}
}

View File

@@ -0,0 +1,49 @@
import {
Controller,
Get,
Post,
Put,
Delete,
Body,
Param,
UseGuards,
} from '@nestjs/common';
import { AuthGuard } from '../auth/auth.guard';
import { AdminGuard } from './guards/admin.guard';
import { AdminPaymentMethodsService } from './admin-payment-methods.service';
@Controller('admin/payment-methods')
@UseGuards(AuthGuard, AdminGuard)
export class AdminPaymentMethodsController {
constructor(private readonly service: AdminPaymentMethodsService) {}
@Get()
findAll() {
return this.service.findAll();
}
@Get(':id')
findOne(@Param('id') id: string) {
return this.service.findOne(id);
}
@Post()
create(@Body() data: any) {
return this.service.create(data);
}
@Put(':id')
update(@Param('id') id: string, @Body() data: any) {
return this.service.update(id, data);
}
@Delete(':id')
delete(@Param('id') id: string) {
return this.service.delete(id);
}
@Post('reorder')
reorder(@Body() body: { methodIds: string[] }) {
return this.service.reorder(body.methodIds);
}
}

View File

@@ -0,0 +1,50 @@
import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
@Injectable()
export class AdminPaymentMethodsService {
constructor(private readonly prisma: PrismaService) {}
async findAll() {
return this.prisma.paymentMethod.findMany({
orderBy: { sortOrder: 'asc' },
});
}
async findOne(id: string) {
return this.prisma.paymentMethod.findUnique({
where: { id },
});
}
async create(data: any) {
return this.prisma.paymentMethod.create({
data,
});
}
async update(id: string, data: any) {
return this.prisma.paymentMethod.update({
where: { id },
data,
});
}
async delete(id: string) {
return this.prisma.paymentMethod.delete({
where: { id },
});
}
async reorder(methodIds: string[]) {
const updates = methodIds.map((id, index) =>
this.prisma.paymentMethod.update({
where: { id },
data: { sortOrder: index + 1 },
})
);
await this.prisma.$transaction(updates);
return { success: true };
}
}

View File

@@ -0,0 +1,54 @@
import {
Controller,
Get,
Post,
Body,
Param,
Query,
UseGuards,
Req,
} from '@nestjs/common';
import { AuthGuard } from '../auth/auth.guard';
import { AdminGuard } from './guards/admin.guard';
import { AdminPaymentsService } from './admin-payments.service';
interface RequestWithUser {
user: {
userId: string;
};
}
@Controller('admin/payments')
@UseGuards(AuthGuard, AdminGuard)
export class AdminPaymentsController {
constructor(private readonly service: AdminPaymentsService) {}
@Get()
findAll(@Query('status') status?: string) {
return this.service.findAll(status);
}
@Get('pending/count')
getPendingCount() {
return this.service.getPendingCount();
}
@Get(':id')
findOne(@Param('id') id: string) {
return this.service.findOne(id);
}
@Post(':id/verify')
verify(@Param('id') id: string, @Req() req: RequestWithUser) {
return this.service.verify(id, req.user.userId);
}
@Post(':id/reject')
reject(
@Param('id') id: string,
@Req() req: RequestWithUser,
@Body() body: { reason: string },
) {
return this.service.reject(id, req.user.userId, body.reason);
}
}

View File

@@ -0,0 +1,110 @@
import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
@Injectable()
export class AdminPaymentsService {
constructor(private readonly prisma: PrismaService) {}
async findAll(status?: string) {
return this.prisma.payment.findMany({
where: status ? { status } : undefined,
include: {
user: {
select: {
id: true,
email: true,
name: true,
},
},
subscription: {
include: {
plan: true,
},
},
},
orderBy: { createdAt: 'desc' },
});
}
async findOne(id: string) {
return this.prisma.payment.findUnique({
where: { id },
include: {
user: {
select: {
id: true,
email: true,
name: true,
},
},
subscription: {
include: {
plan: true,
},
},
},
});
}
async verify(id: string, adminUserId: string) {
const payment = await this.prisma.payment.findUnique({
where: { id },
include: { subscription: { include: { plan: true } } },
});
if (!payment) {
throw new Error('Payment not found');
}
// Update payment status
const updatedPayment = await this.prisma.payment.update({
where: { id },
data: {
status: 'paid',
verifiedBy: adminUserId,
verifiedAt: new Date(),
paidAt: new Date(),
},
});
// Activate or extend subscription
if (payment.subscriptionId && payment.subscription) {
const plan = payment.subscription.plan;
const now = new Date();
const endDate = new Date(now);
if (plan.durationDays) {
endDate.setDate(endDate.getDate() + plan.durationDays);
}
await this.prisma.subscription.update({
where: { id: payment.subscriptionId },
data: {
status: 'active',
startDate: now,
endDate: plan.durationType === 'lifetime' ? new Date('2099-12-31') : endDate,
},
});
}
return updatedPayment;
}
async reject(id: string, adminUserId: string, reason: string) {
return this.prisma.payment.update({
where: { id },
data: {
status: 'rejected',
verifiedBy: adminUserId,
verifiedAt: new Date(),
rejectionReason: reason,
},
});
}
async getPendingCount() {
return this.prisma.payment.count({
where: { status: 'pending' },
});
}
}

View File

@@ -0,0 +1,49 @@
import {
Controller,
Get,
Post,
Put,
Delete,
Body,
Param,
UseGuards,
} from '@nestjs/common';
import { AuthGuard } from '../auth/auth.guard';
import { AdminGuard } from './guards/admin.guard';
import { AdminPlansService } from './admin-plans.service';
@Controller('admin/plans')
@UseGuards(AuthGuard, AdminGuard)
export class AdminPlansController {
constructor(private readonly plansService: AdminPlansService) {}
@Get()
findAll() {
return this.plansService.findAll();
}
@Get(':id')
findOne(@Param('id') id: string) {
return this.plansService.findOne(id);
}
@Post()
create(@Body() data: any) {
return this.plansService.create(data);
}
@Put(':id')
update(@Param('id') id: string, @Body() data: any) {
return this.plansService.update(id, data);
}
@Delete(':id')
delete(@Param('id') id: string) {
return this.plansService.delete(id);
}
@Post('reorder')
reorder(@Body() body: { planIds: string[] }) {
return this.plansService.reorder(body.planIds);
}
}

View File

@@ -0,0 +1,63 @@
import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
@Injectable()
export class AdminPlansService {
constructor(private readonly prisma: PrismaService) {}
async findAll() {
return this.prisma.plan.findMany({
orderBy: { sortOrder: 'asc' },
include: {
_count: {
select: { subscriptions: true },
},
},
});
}
async findOne(id: string) {
return this.prisma.plan.findUnique({
where: { id },
include: {
_count: {
select: { subscriptions: true },
},
},
});
}
async create(data: any) {
return this.prisma.plan.create({
data,
});
}
async update(id: string, data: any) {
return this.prisma.plan.update({
where: { id },
data,
});
}
async delete(id: string) {
// Soft delete - just deactivate
return this.prisma.plan.update({
where: { id },
data: { isActive: false, isVisible: false },
});
}
async reorder(planIds: string[]) {
// Update sort order for multiple plans
const updates = planIds.map((id, index) =>
this.prisma.plan.update({
where: { id },
data: { sortOrder: index + 1 },
})
);
await this.prisma.$transaction(updates);
return { success: true };
}
}

View File

@@ -0,0 +1,57 @@
import {
Controller,
Get,
Post,
Put,
Body,
Param,
Query,
UseGuards,
} from '@nestjs/common';
import { AuthGuard } from '../auth/auth.guard';
import { AdminGuard } from './guards/admin.guard';
import { AdminUsersService } from './admin-users.service';
@Controller('admin/users')
@UseGuards(AuthGuard, AdminGuard)
export class AdminUsersController {
constructor(private readonly service: AdminUsersService) {}
@Get()
findAll(@Query('search') search?: string) {
return this.service.findAll(search);
}
@Get('stats')
getStats() {
return this.service.getStats();
}
@Get(':id')
findOne(@Param('id') id: string) {
return this.service.findOne(id);
}
@Put(':id/role')
updateRole(@Param('id') id: string, @Body() body: { role: string }) {
return this.service.updateRole(id, body.role);
}
@Post(':id/suspend')
suspend(@Param('id') id: string, @Body() body: { reason: string }) {
return this.service.suspend(id, body.reason);
}
@Post(':id/unsuspend')
unsuspend(@Param('id') id: string) {
return this.service.unsuspend(id);
}
@Post(':id/grant-pro')
grantProAccess(
@Param('id') id: string,
@Body() body: { planSlug: string; durationDays: number },
) {
return this.service.grantProAccess(id, body.planSlug, body.durationDays);
}
}

View File

@@ -0,0 +1,143 @@
import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
@Injectable()
export class AdminUsersService {
constructor(private readonly prisma: PrismaService) {}
async findAll(search?: string) {
return this.prisma.user.findMany({
where: search
? {
OR: [
{ email: { contains: search, mode: 'insensitive' } },
{ name: { contains: search, mode: 'insensitive' } },
],
}
: undefined,
select: {
id: true,
email: true,
name: true,
role: true,
emailVerified: true,
createdAt: true,
lastLoginAt: true,
suspendedAt: true,
_count: {
select: {
wallets: true,
transactions: true,
},
},
},
orderBy: { createdAt: 'desc' },
});
}
async findOne(id: string) {
return this.prisma.user.findUnique({
where: { id },
include: {
subscriptions: {
include: {
plan: true,
},
},
_count: {
select: {
wallets: true,
transactions: true,
payments: true,
},
},
},
});
}
async updateRole(id: string, role: string) {
return this.prisma.user.update({
where: { id },
data: { role },
});
}
async suspend(id: string, reason: string) {
return this.prisma.user.update({
where: { id },
data: {
suspendedAt: new Date(),
suspendedReason: reason,
},
});
}
async unsuspend(id: string) {
return this.prisma.user.update({
where: { id },
data: {
suspendedAt: null,
suspendedReason: null,
},
});
}
async grantProAccess(userId: string, planSlug: string, durationDays: number) {
const plan = await this.prisma.plan.findUnique({
where: { slug: planSlug },
});
if (!plan) {
throw new Error('Plan not found');
}
const now = new Date();
const endDate = new Date(now);
endDate.setDate(endDate.getDate() + durationDays);
// Check if user already has a subscription
const existing = await this.prisma.subscription.findUnique({
where: { userId },
});
if (existing) {
// Update existing subscription
return this.prisma.subscription.update({
where: { userId },
data: {
planId: plan.id,
status: 'active',
startDate: now,
endDate,
},
});
} else {
// Create new subscription
return this.prisma.subscription.create({
data: {
userId,
planId: plan.id,
status: 'active',
startDate: now,
endDate,
},
});
}
}
async getStats() {
const totalUsers = await this.prisma.user.count();
const activeSubscriptions = await this.prisma.subscription.count({
where: { status: 'active' },
});
const suspendedUsers = await this.prisma.user.count({
where: { suspendedAt: { not: null } },
});
return {
totalUsers,
activeSubscriptions,
suspendedUsers,
};
}
}

View File

@@ -0,0 +1,45 @@
import { Module } from '@nestjs/common';
import { PrismaModule } from '../prisma/prisma.module';
import { AdminGuard } from './guards/admin.guard';
// Controllers
import { AdminPlansController } from './admin-plans.controller';
import { AdminPaymentMethodsController } from './admin-payment-methods.controller';
import { AdminPaymentsController } from './admin-payments.controller';
import { AdminUsersController } from './admin-users.controller';
import { AdminConfigController } from './admin-config.controller';
// Services
import { AdminPlansService } from './admin-plans.service';
import { AdminPaymentMethodsService } from './admin-payment-methods.service';
import { AdminPaymentsService } from './admin-payments.service';
import { AdminUsersService } from './admin-users.service';
import { AdminConfigService } from './admin-config.service';
@Module({
imports: [PrismaModule],
controllers: [
AdminPlansController,
AdminPaymentMethodsController,
AdminPaymentsController,
AdminUsersController,
AdminConfigController,
],
providers: [
AdminGuard,
AdminPlansService,
AdminPaymentMethodsService,
AdminPaymentsService,
AdminUsersService,
AdminConfigService,
],
exports: [
AdminGuard,
AdminPlansService,
AdminPaymentMethodsService,
AdminPaymentsService,
AdminUsersService,
AdminConfigService,
],
})
export class AdminModule {}

View File

@@ -9,6 +9,7 @@ import { WalletsModule } from './wallets/wallets.module';
import { TransactionsModule } from './transactions/transactions.module';
import { CategoriesModule } from './categories/categories.module';
import { OtpModule } from './otp/otp.module';
import { AdminModule } from './admin/admin.module';
@Module({
imports: [
@@ -26,6 +27,7 @@ import { OtpModule } from './otp/otp.module';
TransactionsModule,
CategoriesModule,
OtpModule,
AdminModule,
],
controllers: [HealthController],
providers: [],