feat: implement POS order management system

- Added CreateOrderDto and CreateOrderItemDto for order creation.
- Developed PosOrdersController to handle order-related endpoints.
- Created PosOrdersService for business logic related to orders.
- Implemented PosOrdersWorkflow for order processing workflows.
- Established Prisma integration for database operations in orders.
- Introduced SalesInvoicesModule and related DTOs for sales invoice management.
- Enhanced SalesInvoicesService and SalesInvoicesWorkflow for invoice processing.
This commit is contained in:
2026-01-07 15:25:59 +03:30
parent b05048e62f
commit 5fd6611aca
37 changed files with 1974 additions and 291 deletions
@@ -0,0 +1,20 @@
import { Type } from 'class-transformer'
import { IsInt, IsNumber, IsOptional, IsString } from 'class-validator'
export class CreateSalesInvoiceDto {
@IsString()
code: string
@Type(() => Number)
@IsNumber()
totalAmount: number
@IsOptional()
@IsString()
description?: string
@IsOptional()
@Type(() => Number)
@IsInt()
customerId?: number
}
@@ -0,0 +1,22 @@
import { Type } from 'class-transformer'
import { IsInt, IsNumber, IsOptional, IsString } from 'class-validator'
export class UpdateSalesInvoiceDto {
@IsOptional()
@IsString()
code?: string
@IsOptional()
@Type(() => Number)
@IsNumber()
totalAmount?: number
@IsOptional()
@IsString()
description?: string
@IsOptional()
@Type(() => Number)
@IsInt()
customerId?: number | null
}
@@ -0,0 +1,32 @@
import { Controller, Delete, Get, Param } from '@nestjs/common'
import { SalesInvoicesService } from './sales-invoices.service'
@Controller('sales-invoices')
export class SalesInvoicesController {
constructor(private readonly service: SalesInvoicesService) {}
// @Post()
// create(@Body() dto: CreateSalesInvoiceDto) {
// return this.service.create(dto)
// }
@Get()
findAll() {
return this.service.findAll()
}
@Get(':id')
findOne(@Param('id') id: string) {
return this.service.findOne(Number(id))
}
// @Patch(':id')
// update(@Param('id') id: string, @Body() dto: UpdateSalesInvoiceDto) {
// return this.service.update(Number(id), dto)
// }
@Delete(':id')
remove(@Param('id') id: string) {
return this.service.remove(Number(id))
}
}
@@ -0,0 +1,13 @@
import { Module } from '@nestjs/common'
import { PrismaModule } from '../../prisma/prisma.module'
import { SalesInvoicesController } from './sales-invoices.controller'
import { SalesInvoicesService } from './sales-invoices.service'
import { SalesInvoicesWorkflow } from './sales-invoices.workflow'
@Module({
imports: [PrismaModule],
controllers: [SalesInvoicesController],
providers: [SalesInvoicesService, SalesInvoicesWorkflow],
exports: [SalesInvoicesWorkflow],
})
export class SalesInvoicesModule {}
@@ -0,0 +1,49 @@
import { Injectable } from '@nestjs/common'
import { ResponseMapper } from '../../common/response/response-mapper'
import { PrismaService } from '../../prisma/prisma.service'
@Injectable()
export class SalesInvoicesService {
constructor(private prisma: PrismaService) {}
// async create(dto: CreateSalesInvoiceDto) {
// const payload: any = { ...dto }
// if (Object.prototype.hasOwnProperty.call(payload, 'customerId')) {
// payload.customer = { connect: { id: Number(payload.customerId) } }
// delete payload.customerId
// }
// const item = await this.prisma.salesInvoice.create({ data: payload })
// return ResponseMapper.create(item)
// }
async findAll() {
const items = await this.prisma.salesInvoice.findMany({ include: { customer: true } })
return ResponseMapper.list(items)
}
async findOne(id: number) {
const item = await this.prisma.salesInvoice.findUnique({
where: { id },
include: { items: true, customer: true },
})
if (!item) return null
return ResponseMapper.single(item)
}
// async update(id: number, data: any) {
// const payload: any = { ...data }
// if (Object.prototype.hasOwnProperty.call(payload, 'customerId')) {
// if (payload.customerId === null) payload.customer = { disconnect: true }
// else payload.customer = { connect: { id: Number(payload.customerId) } }
// delete payload.customerId
// }
// const item = await this.prisma.salesInvoice.update({ where: { id }, data: payload })
// return ResponseMapper.update(item)
// }
async remove(id: number) {
const item = await this.prisma.salesInvoice.delete({ where: { id } })
return ResponseMapper.single(item)
}
}
@@ -0,0 +1,38 @@
import {
MovementReferenceType,
MovementType,
Prisma,
} from '../../generated/prisma/client'
export class SalesInvoicesWorkflow {
constructor() {}
async onCreateByOrder(tx: Prisma.TransactionClient, orderId: number) {
const { posAccount } = await tx.order.findUniqueOrThrow({
where: { id: orderId },
select: { posAccount: { select: { inventoryId: true, id: true } } },
})
const posInventoryId = posAccount.inventoryId
const orderItems = await tx.orderItem.findMany({
where: {
orderId,
},
})
await tx.stockMovement.createMany({
data: orderItems.map(item => ({
productId: item.productId,
orderId,
type: MovementType.OUT,
referenceType: MovementReferenceType.SALES,
referenceId: String(orderId),
quantity: item.quantity,
inventoryId: posInventoryId,
unitPrice: item.unitPrice,
totalCost: item.totalAmount,
avgCost: item.unitPrice,
})),
})
}
}