Tokiva-backend-Node / src /controllers /ops.controller.ts
anoderb
feat: implement chatbot service, active shift logic corrections, audit logs, and void transaction tool
48013ee
Raw
History Blame Contribute Delete
6.73 kB
import { Request, Response, NextFunction } from 'express';
import { OpsService } from '../services/ops.service';
import { sukses } from '../utils/response';
import { AuthenticatedRequest } from '../middlewares/auth.middleware';
export class OpsController {
// Shift Kasir
static async getActiveShift(req: AuthenticatedRequest, res: Response, next: NextFunction) {
try {
const userId = req.user.id;
const shift = await OpsService.getActiveShift(userId);
if (!shift) {
return sukses(res, null, 'Tidak ada shift aktif untuk kasir saat ini');
}
return sukses(res, shift, 'Shift aktif berhasil dimuat');
} catch (error) {
next(error);
}
}
static async openShift(req: AuthenticatedRequest, res: Response, next: NextFunction) {
try {
const actorId = req.user.id;
const ip = (req.ip || req.socket.remoteAddress || 'unknown').replace('::ffff:', '');
const userAgent = (req.headers['user-agent'] || 'unknown') as string;
const { modal_awal, catatan } = req.body;
const shift = await OpsService.bukaShift(modal_awal, catatan, actorId, ip, userAgent);
return sukses(res, shift, 'Shift berhasil dibuka');
} catch (error) {
next(error);
}
}
static async closeShift(req: AuthenticatedRequest, res: Response, next: NextFunction) {
try {
const actorId = req.user.id;
const ip = (req.ip || req.socket.remoteAddress || 'unknown').replace('::ffff:', '');
const userAgent = (req.headers['user-agent'] || 'unknown') as string;
const { modal_akhir_fisik, catatan } = req.body;
const shift = await OpsService.tutupShift(modal_akhir_fisik, catatan, actorId, ip, userAgent);
return sukses(res, shift, 'Shift kasir ditutup, selisih kas fisik berhasil dicatat');
} catch (error) {
next(error);
}
}
// Dashboard & Laporan
static async getDashboardSummary(req: AuthenticatedRequest, res: Response, next: NextFunction) {
try {
const summary = await OpsService.getDashboardSummary();
return sukses(res, summary, 'Dashboard summary berhasil dimuat');
} catch (error) {
next(error);
}
}
static async getSalesReport(req: AuthenticatedRequest, res: Response, next: NextFunction) {
try {
const tglMulai = new Date(req.query.tgl_mulai as string);
const tglSelesai = new Date(req.query.tgl_selesai as string);
const report = await OpsService.buatLaporanPenjualan(tglMulai, tglSelesai);
return sukses(res, report, 'Laporan penjualan berhasil dibuat');
} catch (error) {
next(error);
}
}
static async getProfitLossReport(req: AuthenticatedRequest, res: Response, next: NextFunction) {
try {
const tglMulai = new Date(req.query.tgl_mulai as string);
const tglSelesai = new Date(req.query.tgl_selesai as string);
const report = await OpsService.buatLaporanLabaRugi(tglMulai, tglSelesai);
return sukses(res, report, 'Laporan laba rugi berhasil dibuat');
} catch (error) {
next(error);
}
}
static async eksporLaporan(req: AuthenticatedRequest, res: Response, next: NextFunction) {
try {
const jenis = req.query.jenis as any;
const format = req.query.format as any;
const tglMulai = new Date(req.query.tgl_mulai as string);
const tglSelesai = new Date(req.query.tgl_selesai as string);
if (!['penjualan', 'laba-rugi', 'mutasi-stok'].includes(jenis)) {
throw new Error('Jenis laporan tidak valid');
}
if (!['csv', 'excel', 'pdf'].includes(format)) {
throw new Error('Format laporan tidak valid. Harus csv, excel, atau pdf');
}
const fileInfo = await OpsService.eksporLaporan({
jenis,
format,
tglMulai,
tglSelesai,
});
return sukses(res, fileInfo, 'Laporan berhasil diekspor');
} catch (error: any) {
res.status(400).json({ sukses: false, pesan: error.message || 'Gagal mengekspor laporan' });
}
}
// Settings/Pengaturan
static async getSettings(req: Request, res: Response, next: NextFunction) {
try {
const settings = await OpsService.getSettings();
return sukses(res, settings, 'Pengaturan toko berhasil dimuat');
} catch (error) {
next(error);
}
}
static async getSettingByKey(req: Request, res: Response, next: NextFunction) {
try {
const { kunci } = req.params;
const value = await OpsService.getSettingByKey(kunci);
return sukses(res, { kunci, nilai: value }, `Pengaturan '${kunci}' berhasil dimuat`);
} catch (error) {
next(error);
}
}
static async updateSetting(req: AuthenticatedRequest, res: Response, next: NextFunction) {
try {
const { kunci } = req.params;
const actorId = req.user.id;
const ip = (req.ip || req.socket.remoteAddress || 'unknown').replace('::ffff:', '');
const userAgent = (req.headers['user-agent'] || 'unknown') as string;
await OpsService.updateSetting(kunci, req.body, actorId, ip, userAgent);
const value = await OpsService.getSettingByKey(kunci);
return sukses(res, { kunci, nilai: value }, 'Pengaturan berhasil diperbarui');
} catch (error) {
next(error);
}
}
// Notifikasi
static async listNotifications(req: Request, res: Response, next: NextFunction) {
try {
const skip = parseInt(req.query.skip as string) || 0;
const limit = parseInt(req.query.limit as string) || 20;
const dibaca = req.query.dibaca !== undefined ? parseInt(req.query.dibaca as string) : undefined;
const notifs = await OpsService.getNotifications(skip, limit, dibaca);
return sukses(res, notifs, 'Notifikasi berhasil dimuat');
} catch (error) {
next(error);
}
}
static async readAllNotifications(req: Request, res: Response, next: NextFunction) {
try {
const affected = await OpsService.markAllNotifAsRead();
return sukses(res, { jumlah_diubah: affected }, 'Semua notifikasi ditandai dibaca');
} catch (error) {
next(error);
}
}
static async readNotification(req: Request, res: Response, next: NextFunction) {
try {
const notifId = parseInt(req.params.notif_id);
const notif = await OpsService.markNotifAsRead(notifId);
return sukses(res, notif, 'Notifikasi ditandai dibaca');
} catch (error) {
next(error);
}
}
static async getUnreadNotificationCount(req: Request, res: Response, next: NextFunction) {
try {
const count = await OpsService.getUnreadNotifCount();
return sukses(res, { unread_count: count }, 'Jumlah notifikasi belum dibaca berhasil dihitung');
} catch (error) {
next(error);
}
}
}