feat: change email template + add list of items
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { Prisma } from '@prisma/client';
|
||||
import { DevicesService } from './devices.service';
|
||||
|
||||
type Snapshot = { tabId: string; customerName: string; version: number; totalInCents: number; itemCount: number };
|
||||
@@ -101,3 +102,26 @@ describe('DevicesService.sync live update signals', () => {
|
||||
expect(realtime.notify).toHaveBeenCalledWith('v1', 'device');
|
||||
});
|
||||
});
|
||||
|
||||
describe('DevicesService.sync tab lines', () => {
|
||||
const base = { id: 't1', customerName: 'Bram', version: 4, totalInCents: 2500, itemCount: 10 };
|
||||
|
||||
it('stores the lines a terminal reports', async () => {
|
||||
const { service, tx } = createService();
|
||||
const items = [{ productName: 'Cola', quantity: 10, unitPriceInCents: 250 }];
|
||||
|
||||
await service.sync(device, { deviceId: 'd1', openTabs: [{ ...base, items }] });
|
||||
|
||||
const { create, update } = tx.openTabSnapshot.upsert.mock.calls[0][0];
|
||||
expect(create.items).toEqual(items);
|
||||
expect(update.items).toEqual(items);
|
||||
});
|
||||
|
||||
it('stores no lines for app versions that do not report them', async () => {
|
||||
const { service, tx } = createService();
|
||||
|
||||
await service.sync(device, { deviceId: 'd1', openTabs: [base] });
|
||||
|
||||
expect(tx.openTabSnapshot.upsert.mock.calls[0][0].update.items).toBe(Prisma.JsonNull);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -9,7 +9,8 @@ import { PrismaService } from '../prisma/prisma.service';
|
||||
import { AuditService } from '../audit/audit.service';
|
||||
import { RealtimeService, RealtimeTopic } from '../realtime/realtime.service';
|
||||
import { DEVICE_ONLINE_THRESHOLD_MS } from '@kooltap/shared';
|
||||
import { SyncDto } from './dto/sync.dto';
|
||||
import { Prisma } from '@prisma/client';
|
||||
import { OpenTabDto, SyncDto } from './dto/sync.dto';
|
||||
import { AckCommandDto } from './dto/ack-command.dto';
|
||||
|
||||
@Injectable()
|
||||
@@ -82,6 +83,7 @@ export class DevicesService {
|
||||
version: tab.version,
|
||||
totalInCents: tab.totalInCents,
|
||||
itemCount: tab.itemCount,
|
||||
items: snapshotItems(tab),
|
||||
reportedAt: now,
|
||||
},
|
||||
update: {
|
||||
@@ -89,6 +91,7 @@ export class DevicesService {
|
||||
version: tab.version,
|
||||
totalInCents: tab.totalInCents,
|
||||
itemCount: tab.itemCount,
|
||||
items: snapshotItems(tab),
|
||||
reportedAt: now,
|
||||
},
|
||||
});
|
||||
@@ -274,4 +277,10 @@ export class DevicesService {
|
||||
|
||||
return { ok: true };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** The tab's lines in the stored shape, or JSON null when the terminal didn't report them. */
|
||||
function snapshotItems(tab: OpenTabDto) {
|
||||
if (!tab.items) return Prisma.JsonNull;
|
||||
return tab.items.map(({ productName, quantity, unitPriceInCents }) => ({ productName, quantity, unitPriceInCents }));
|
||||
}
|
||||
|
||||
@@ -1,8 +1,26 @@
|
||||
import { IsString, IsOptional, IsArray, IsInt, Min, IsUUID, ValidateNested, ArrayMaxSize, IsNotEmpty } from 'class-validator';
|
||||
import { IsString, IsOptional, IsArray, IsInt, Min, IsUUID, ValidateNested, ArrayMaxSize, IsNotEmpty, MaxLength } from 'class-validator';
|
||||
import { Type } from 'class-transformer';
|
||||
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||||
|
||||
class OpenTabDto {
|
||||
export class OpenTabItemDto {
|
||||
@ApiProperty({ example: 'Cola' })
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
@MaxLength(200)
|
||||
productName: string;
|
||||
|
||||
@ApiProperty({ example: 10 })
|
||||
@IsInt()
|
||||
@Min(0)
|
||||
quantity: number;
|
||||
|
||||
@ApiProperty({ example: 250 })
|
||||
@IsInt()
|
||||
@Min(0)
|
||||
unitPriceInCents: number;
|
||||
}
|
||||
|
||||
export class OpenTabDto {
|
||||
@ApiProperty({ example: 'local-tab-uuid' })
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
@@ -26,6 +44,14 @@ class OpenTabDto {
|
||||
@IsInt()
|
||||
@Min(0)
|
||||
itemCount: number;
|
||||
|
||||
@ApiPropertyOptional({ type: [OpenTabItemDto], description: 'Lines on the tab; omitted by older app versions' })
|
||||
@IsOptional()
|
||||
@IsArray()
|
||||
@ArrayMaxSize(500)
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => OpenTabItemDto)
|
||||
items?: OpenTabItemDto[];
|
||||
}
|
||||
|
||||
export class SyncDto {
|
||||
|
||||
Reference in New Issue
Block a user