c6a86719dd
feat(pos): add POS controller and service for order creation and stock retrieval refactor(pos): enhance stock and product category retrieval with pagination and mapping
148 lines
4.0 KiB
TypeScript
148 lines
4.0 KiB
TypeScript
import { Injectable } from '@nestjs/common'
|
|
import { ResponseMapper } from '../../common/response/response-mapper'
|
|
import { Prisma } from '../../generated/prisma/client'
|
|
import { PrismaService } from '../../prisma/prisma.service'
|
|
import { CreateOrderDto } from './dto/create-pos.dto'
|
|
|
|
@Injectable()
|
|
export class PosService {
|
|
constructor(private prisma: PrismaService) {}
|
|
|
|
async getDefaultInventoryId() {
|
|
const inventory = await this.prisma.inventory.findFirst({
|
|
where: { isPointOfSale: true },
|
|
select: { id: true },
|
|
})
|
|
return inventory?.id || null
|
|
}
|
|
|
|
async getInfo() {
|
|
const info = await this.prisma.inventory.findFirst({
|
|
where: { isPointOfSale: true },
|
|
select: {
|
|
id: true,
|
|
name: true,
|
|
},
|
|
})
|
|
|
|
return ResponseMapper.single({ store: info })
|
|
}
|
|
|
|
async getStock(inventoryId: number, isAvailable?: boolean, page = 1, pageSize = 50) {
|
|
const query: Prisma.StockBalanceFindManyArgs = {
|
|
where: {
|
|
inventoryId,
|
|
quantity:
|
|
isAvailable === true
|
|
? { gt: 0 }
|
|
: isAvailable === false
|
|
? { lte: 0 }
|
|
: undefined,
|
|
},
|
|
}
|
|
const [items, count] = await this.prisma.$transaction([
|
|
this.prisma.stockBalance.findMany({
|
|
where: query.where,
|
|
include: {
|
|
product: {
|
|
select: {
|
|
id: true,
|
|
name: true,
|
|
sku: true,
|
|
salePrice: true,
|
|
category: {
|
|
select: { id: true, name: true },
|
|
},
|
|
},
|
|
},
|
|
},
|
|
orderBy: {
|
|
quantity: 'desc',
|
|
},
|
|
skip: (page - 1) * pageSize,
|
|
take: pageSize,
|
|
}),
|
|
this.prisma.stockBalance.count({ where: query.where }),
|
|
])
|
|
|
|
const mapped = items.map(item => ({
|
|
id: item.id,
|
|
quantity: Number(item.quantity),
|
|
product: item.product,
|
|
}))
|
|
|
|
return ResponseMapper.paginate(mapped, count, page, pageSize)
|
|
}
|
|
|
|
async getProductCategories(inventoryId: number) {
|
|
const balances = await this.prisma.stockBalance.findMany({
|
|
where: { inventoryId },
|
|
select: {
|
|
product: { select: { id: true, category: { select: { id: true, name: true } } } },
|
|
quantity: true,
|
|
},
|
|
})
|
|
|
|
const map = new Map<
|
|
number,
|
|
{ id: number; name: string; totalQuantity: number; productCount: number }
|
|
>()
|
|
|
|
for (const b of balances) {
|
|
const product = b.product
|
|
const cat = product?.category
|
|
if (!cat) continue // skip products without category
|
|
const existing = map.get(cat.id)
|
|
if (existing) {
|
|
existing.totalQuantity += Number(b.quantity)
|
|
existing.productCount += 1
|
|
} else {
|
|
map.set(cat.id, {
|
|
id: cat.id,
|
|
name: cat.name,
|
|
totalQuantity: Number(b.quantity),
|
|
productCount: 1,
|
|
})
|
|
}
|
|
}
|
|
|
|
const categories = Array.from(map.values())
|
|
return ResponseMapper.list(categories)
|
|
}
|
|
|
|
async createOrder(data: CreateOrderDto, inventoryId: number) {
|
|
const { customerId, ...res } = data
|
|
const preparedOrder = { ...res } as any
|
|
const lastCode = await this.prisma.salesInvoice
|
|
.findFirst({
|
|
orderBy: { code: 'desc' },
|
|
select: { code: true },
|
|
})
|
|
.then(si => si?.code || '0')
|
|
|
|
preparedOrder.code = String(Number(lastCode) + 1)
|
|
|
|
preparedOrder.totalAmount = data.items.reduce(
|
|
(acc, item) => acc + Number(item.fee),
|
|
0,
|
|
)
|
|
|
|
preparedOrder.inventory = { connect: { id: inventoryId } }
|
|
preparedOrder.customer = { connect: { id: customerId } }
|
|
|
|
if (Object.prototype.hasOwnProperty.call(preparedOrder, 'items')) {
|
|
preparedOrder.items = {
|
|
create: preparedOrder.items.map((item: any) => ({
|
|
product: { connect: { id: Number(item.productId) } },
|
|
count: item.count,
|
|
fee: item.fee,
|
|
total: item.count * item.fee,
|
|
})),
|
|
}
|
|
}
|
|
|
|
const item = await this.prisma.salesInvoice.create({ data: preparedOrder })
|
|
return ResponseMapper.create(item)
|
|
}
|
|
}
|