init
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { ShopSettingsModule } from '../shopSettings/ShopSettingsModule';
|
||||
import { SimplexModule } from '../simplex/SimplexModule';
|
||||
import { NotificationService } from './services/NotificationService';
|
||||
|
||||
@Module({
|
||||
imports: [SimplexModule, ShopSettingsModule],
|
||||
providers: [NotificationService],
|
||||
exports: [NotificationService]
|
||||
})
|
||||
export class NotificationsModule {}
|
||||
@@ -0,0 +1,74 @@
|
||||
import { Logger } from '@nestjs/common';
|
||||
import type { ShopSettingsService } from '../../shopSettings/services/ShopSettingsService';
|
||||
import type { SimplexChatClient } from '../../simplex/services/SimplexChatClient';
|
||||
import { NotificationService } from './NotificationService';
|
||||
|
||||
describe('NotificationService', () => {
|
||||
let service: NotificationService;
|
||||
let shopSettingsService: {
|
||||
findSettings: jest.Mock;
|
||||
};
|
||||
let simplexChatClient: {
|
||||
sendText: jest.Mock;
|
||||
};
|
||||
let warnSpy: jest.SpiedFunction<typeof Logger.prototype.warn>;
|
||||
|
||||
beforeEach(() => {
|
||||
warnSpy = jest.spyOn(Logger.prototype, 'warn').mockImplementation(() => undefined);
|
||||
|
||||
shopSettingsService = {
|
||||
findSettings: jest.fn().mockResolvedValue({
|
||||
notificationsEnabled: true,
|
||||
simplexNotificationContactId: 42,
|
||||
notifyOnNewOrder: true,
|
||||
notifyOnOrderMessage: false
|
||||
})
|
||||
};
|
||||
|
||||
simplexChatClient = {
|
||||
sendText: jest.fn().mockResolvedValue(undefined)
|
||||
};
|
||||
|
||||
service = new NotificationService(
|
||||
shopSettingsService as unknown as ShopSettingsService,
|
||||
simplexChatClient as unknown as SimplexChatClient
|
||||
);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
warnSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('does nothing when notifications are disabled', async () => {
|
||||
shopSettingsService.findSettings.mockResolvedValue({
|
||||
notificationsEnabled: false,
|
||||
simplexNotificationContactId: 42,
|
||||
notifyOnNewOrder: true,
|
||||
notifyOnOrderMessage: true
|
||||
});
|
||||
|
||||
await service.sendNotification('order-1234-abcd', 'newOrder');
|
||||
|
||||
expect(simplexChatClient.sendText).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does nothing when the notification type is disabled', async () => {
|
||||
await service.sendNotification('order-1234-abcd', 'newBuyerMessage');
|
||||
|
||||
expect(simplexChatClient.sendText).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('sends a new order notification when enabled', async () => {
|
||||
await service.sendNotification('order-1234-abcd', 'newOrder');
|
||||
|
||||
expect(simplexChatClient.sendText).toHaveBeenCalledWith(42, 'New order #orde — open CMS Orders.');
|
||||
});
|
||||
|
||||
it('logs a warning when sending fails without throwing', async () => {
|
||||
simplexChatClient.sendText.mockRejectedValue(new Error('simplex down'));
|
||||
|
||||
await expect(service.sendNotification('order-1234-abcd', 'newOrder')).resolves.toBeUndefined();
|
||||
|
||||
expect(warnSpy).toHaveBeenCalledWith('Failed to send newOrder notification: simplex down');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,42 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { getErrorMessage } from '../../../utils/getErrorMessage';
|
||||
import { formatShortOrderId } from '../../../utils/order/formatShortOrderId';
|
||||
import { ShopSettingsService } from '../../shopSettings/services/ShopSettingsService';
|
||||
import { SimplexChatClient } from '../../simplex/services/SimplexChatClient';
|
||||
|
||||
@Injectable()
|
||||
export class NotificationService {
|
||||
private readonly logger = new Logger(NotificationService.name);
|
||||
|
||||
constructor(
|
||||
private readonly shopSettingsService: ShopSettingsService,
|
||||
private readonly simplexChatClient: SimplexChatClient
|
||||
) {}
|
||||
|
||||
async sendNotification(orderId: string, type: 'newOrder' | 'newBuyerMessage'): Promise<void> {
|
||||
try {
|
||||
const settings = await this.shopSettingsService.findSettings();
|
||||
|
||||
if (!settings.notificationsEnabled || settings.simplexNotificationContactId === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const enabled = type === 'newOrder' ? settings.notifyOnNewOrder : settings.notifyOnOrderMessage;
|
||||
|
||||
if (!enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
const shortId = formatShortOrderId(orderId);
|
||||
|
||||
const message =
|
||||
type === 'newOrder'
|
||||
? `New order ${shortId} — open CMS Orders.`
|
||||
: `New message on order ${shortId}.`;
|
||||
|
||||
await this.simplexChatClient.sendText(settings.simplexNotificationContactId, message);
|
||||
} catch (error) {
|
||||
this.logger.warn(`Failed to send ${type} notification: ${getErrorMessage(error)}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user