Compare commits
62 Commits
34793295c9
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 636daca703 | |||
| 9bf294a1f3 | |||
| 839f6de691 | |||
| 826041b07a | |||
| f87e5b9d8e | |||
| 652177862d | |||
| ac2e7f5dab | |||
| f94a108948 | |||
| d51b677f26 | |||
| 9170d8cd5a | |||
| 5f70b95589 | |||
| d2bd576277 | |||
| 23bfe1ecbe | |||
| 47a27fb54f | |||
| f61100bf25 | |||
| 25e589551b | |||
| 5ce560ce97 | |||
| b2d8fdc8a0 | |||
| c11166b365 | |||
| 7ae027633b | |||
| a975f9d02a | |||
| cd3492d625 | |||
| 816c5ebb50 | |||
| 4836ee4d01 | |||
| ea6f1bfdd0 | |||
| b53b7d3ed3 | |||
| 6f65123816 | |||
| 2c97b7302d | |||
| 2dc9480170 | |||
| 9aa12184a1 | |||
| 1d47fb1a1d | |||
| fc27b9d616 | |||
| 98099e97e7 | |||
| d526f6ed2c | |||
| 62b659246f | |||
| c5c522f69c | |||
| 758bb03a26 | |||
| 23ae3556de | |||
| 12b11cc238 | |||
| 2d13a8bd9c | |||
| 2a2c020627 | |||
| ba3c544ff8 | |||
| 5baf5bfea6 | |||
| 83e7c26133 | |||
| 1b26c515c0 | |||
| 2a4e778c31 | |||
| 5e6bd33cdd | |||
| 9a76880b1d | |||
| c53eb2dba3 | |||
| 578e445917 | |||
| a1e8f40417 | |||
| afa83895a2 | |||
| 4e61ff618e | |||
| fbe7230865 | |||
| 658496320b | |||
| 4af07fe3e8 | |||
| 6a48f203a9 | |||
| a486127ade | |||
| ad470d2166 | |||
| a68a7f594d | |||
| 58a7c359d8 | |||
| dee96b6e91 |
@@ -16,6 +16,11 @@ PORT="5002"
|
||||
DB_ROOT_PASSWORD="root_password"
|
||||
NODE_ENV="production"
|
||||
|
||||
REDIS_HOST="redis"
|
||||
REDIS_PORT="6379"
|
||||
REDIS_DB="0"
|
||||
REDIS_PASSWORD=""
|
||||
|
||||
|
||||
|
||||
ARVANCLOUD_ENDPOINT=https://s3.ir-thr-at1.arvanstorage.com
|
||||
|
||||
Vendored
+11
-3
@@ -11,13 +11,21 @@
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"editor.formatOnSave": true,
|
||||
"cSpell.words": [
|
||||
"ARVANCLOUD",
|
||||
"autoincrement",
|
||||
"Cardex",
|
||||
"consfee",
|
||||
"fkey",
|
||||
"iban",
|
||||
"MAYKET"
|
||||
]
|
||||
"indatim",
|
||||
"inno",
|
||||
"inty",
|
||||
"irtaxid",
|
||||
"MAYKET",
|
||||
"setm",
|
||||
"spro",
|
||||
"sstid"
|
||||
],
|
||||
"editor.formatOnSave": true
|
||||
}
|
||||
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
# AI Agent Specification
|
||||
|
||||
## Identity
|
||||
- Name: `consumer_api_agent`
|
||||
- Purpose: Assist with development, refactoring, migration, debugging, and data-safe operations for this repository.
|
||||
- Scope: Entire project rooted at `consumer_api`.
|
||||
|
||||
## Core Responsibilities
|
||||
- Implement and refactor backend features in NestJS modules.
|
||||
- Keep Prisma schema/migrations consistent and safe.
|
||||
- Preserve API behavior unless explicitly asked to change it.
|
||||
- Prefer minimal, focused changes over broad rewrites.
|
||||
|
||||
## Working Rules
|
||||
- Follow repository instructions in `AGENTS.md`.
|
||||
- Respect existing project conventions (naming, DTO patterns, response mapping).
|
||||
- Do not revert unrelated user changes.
|
||||
- Do not run destructive DB commands unless explicitly requested.
|
||||
- For risky DB operations, perform backup-first workflow.
|
||||
|
||||
## Code Standards
|
||||
- Keep functions small and cohesive.
|
||||
- Extract reusable logic to utilities/services when complexity grows.
|
||||
- Validate DTO inputs at boundaries.
|
||||
- Use typed response DTO aliases where possible.
|
||||
- Keep Prisma queries explicit with `select` for response control.
|
||||
|
||||
## Database Safety
|
||||
- Never run `prisma migrate reset` on important environments unless explicitly approved.
|
||||
- Treat applied migration files as immutable history.
|
||||
- Prefer forward-only migrations.
|
||||
- For data updates:
|
||||
- Use transactions.
|
||||
- Verify row counts before/after.
|
||||
- Keep operations idempotent when feasible.
|
||||
|
||||
## API Patterns
|
||||
- List endpoints: paginate + summary payload.
|
||||
- Detail endpoints: full resource shape.
|
||||
- Enum presentation: use shared translator utility (`translateEnumValue`).
|
||||
- Fiscal status fallback rule: if no fiscal record, return `NOT_SEND`.
|
||||
|
||||
## Execution Checklist
|
||||
1. Read target module/controller/service/DTO before edits.
|
||||
2. Apply minimal patch.
|
||||
3. Run typecheck (`pnpm -s tsc --noEmit`).
|
||||
4. If data logic changed, verify behavior with targeted checks.
|
||||
5. Summarize changed files and behavior impact.
|
||||
|
||||
## Useful Commands
|
||||
- Type check:
|
||||
- `pnpm -s tsc --noEmit`
|
||||
- Prisma migration status:
|
||||
- `pnpm prisma migrate status`
|
||||
- Create migration:
|
||||
- `pnpm prisma migrate dev --name <name>`
|
||||
- Apply production migrations:
|
||||
- `pnpm prisma migrate deploy`
|
||||
|
||||
## Communication Style
|
||||
- Be concise, direct, and implementation-focused.
|
||||
- Call out assumptions and risky steps before execution.
|
||||
- Provide concrete next actions after each completed task.
|
||||
@@ -0,0 +1,182 @@
|
||||
# AGENTS.md
|
||||
|
||||
## Stack
|
||||
|
||||
- NestJS
|
||||
- Prisma
|
||||
- TypeScript
|
||||
- pnpm
|
||||
- RTK enabled
|
||||
|
||||
---
|
||||
|
||||
# Core Rules
|
||||
|
||||
- Keep changes minimal.
|
||||
- Do not touch unrelated files.
|
||||
- Prefer existing patterns over new abstractions.
|
||||
- Preserve API behavior unless requested otherwise.
|
||||
- Prefer forward Prisma migrations.
|
||||
- Never edit applied migrations in shared environments.
|
||||
|
||||
---
|
||||
|
||||
# EXECUTION RULES
|
||||
|
||||
- Keep responses short.
|
||||
- Do not narrate thoughts.
|
||||
- Do not explain obvious steps.
|
||||
- Do not create plans for simple tasks.
|
||||
- Prefer implementation over exploration.
|
||||
|
||||
Avoid:
|
||||
|
||||
- “I think…”
|
||||
- “Let me check…”
|
||||
- “I should inspect…”
|
||||
- “I’m going to…”
|
||||
|
||||
---
|
||||
|
||||
# RTK Rules
|
||||
|
||||
Always prefer RTK commands.
|
||||
|
||||
Use:
|
||||
|
||||
- `rtk ls`
|
||||
- `rtk grep`
|
||||
- `rtk smart`
|
||||
- `rtk read`
|
||||
- `rtk git diff`
|
||||
- `rtk git status`
|
||||
|
||||
Avoid raw:
|
||||
|
||||
- `cat`
|
||||
- `grep`
|
||||
- `rg`
|
||||
- `git diff`
|
||||
- recursive repository scans
|
||||
|
||||
---
|
||||
|
||||
# Reading Strategy
|
||||
|
||||
1. `rtk grep`
|
||||
2. `rtk smart`
|
||||
3. `rtk read`
|
||||
|
||||
Rules:
|
||||
|
||||
- Read only necessary files.
|
||||
- Do not read sibling files unless needed.
|
||||
- Do not reread unchanged files.
|
||||
- Stop searching once target location is found.
|
||||
- Edit quickly after locating target.
|
||||
|
||||
Avoid:
|
||||
|
||||
- opening entire modules
|
||||
- multi-file chained reads
|
||||
- large diff dumps
|
||||
- exploratory scans
|
||||
|
||||
---
|
||||
|
||||
# Forbidden Paths
|
||||
|
||||
Do not inspect unless required:
|
||||
|
||||
- `node_modules/`
|
||||
- `dist/`
|
||||
- `coverage/`
|
||||
- `.prisma/`
|
||||
- `prisma/migrations/`
|
||||
|
||||
---
|
||||
|
||||
# Prisma Rules
|
||||
|
||||
- Use transactions for multi-step writes.
|
||||
- Prefer explicit `select/include`.
|
||||
- Normalize `Decimal` values with `Number(...)`.
|
||||
- Keep migrations forward-safe.
|
||||
- Use:
|
||||
- `pnpm prisma migrate dev --name <name>` for new local migrations
|
||||
- `pnpm prisma migrate deploy` for applying existing migrations
|
||||
|
||||
---
|
||||
|
||||
# NestJS Rules
|
||||
|
||||
- Keep layering:
|
||||
- controller
|
||||
- service
|
||||
- prisma/shared service
|
||||
|
||||
- Reuse shared services.
|
||||
- Keep DTO validation strict.
|
||||
- Avoid `any`.
|
||||
|
||||
---
|
||||
|
||||
# Validation
|
||||
|
||||
Typecheck before handoff:
|
||||
|
||||
```bash
|
||||
pnpm -s tsc --noEmit
|
||||
```
|
||||
|
||||
# INVESTIGATION LIMITS
|
||||
|
||||
For localized fixes:
|
||||
|
||||
- maximum 3 file reads before first edit
|
||||
- maximum 1 related-file read unless required
|
||||
- maximum 5 total file reads before implementation
|
||||
|
||||
Stop searching once the target service, controller, DTO, schema, or repository method is identified.
|
||||
|
||||
# TARGETED READ RULES
|
||||
|
||||
Do not read files larger than 300 lines unless required.
|
||||
|
||||
For known symbols:
|
||||
|
||||
1. rtk grep
|
||||
2. rtk smart
|
||||
3. read only the relevant section
|
||||
|
||||
Avoid opening entire services, modules, or controllers for localized changes.
|
||||
|
||||
Prefer symbol-level inspection.
|
||||
|
||||
# REVIEW MODE
|
||||
|
||||
During reviews:
|
||||
|
||||
- inspect changed files only
|
||||
- avoid repository-wide searches
|
||||
- avoid architecture exploration
|
||||
- avoid reading unrelated modules
|
||||
|
||||
Review only code affected by the diff.
|
||||
|
||||
# HARD TOKEN LIMITS
|
||||
|
||||
For localized fixes:
|
||||
|
||||
- Never read more than 5 files before the first edit.
|
||||
- Never read a file larger than 300 lines unless the target symbol cannot be isolated.
|
||||
- Never open an entire service, controller, or module when a symbol-level read is possible.
|
||||
- Never reread a file already summarized by `rtk smart` unless implementation details are required.
|
||||
|
||||
When a file exceeds 300 lines:
|
||||
|
||||
1. rtk grep
|
||||
2. rtk smart
|
||||
3. read only the required section
|
||||
|
||||
Avoid full-file reads.
|
||||
+21
-25
@@ -1,48 +1,44 @@
|
||||
FROM node:22-slim AS deps
|
||||
FROM node:22-slim AS base
|
||||
|
||||
WORKDIR /app
|
||||
ARG NPM_REGISTRY=https://registry.npmjs.org/
|
||||
ARG NPM_REGISTRY=https://hub.megan.ir/npm/
|
||||
ENV NPM_CONFIG_REGISTRY=${NPM_REGISTRY}
|
||||
ENV npm_config_registry=${NPM_REGISTRY}
|
||||
ENV PNPM_HOME="/pnpm"
|
||||
ENV PNPM_STORE_DIR="/pnpm/store"
|
||||
ENV PATH="${PNPM_HOME}:${PATH}"
|
||||
ENV COREPACK_NPM_REGISTRY=${NPM_REGISTRY}
|
||||
ARG PNPM_VERSION=10.17.1
|
||||
|
||||
RUN corepack enable
|
||||
RUN npm config set registry ${NPM_REGISTRY}
|
||||
RUN npm config set registry ${NPM_REGISTRY} \
|
||||
&& npm install -g pnpm@${PNPM_VERSION}
|
||||
|
||||
FROM base AS build
|
||||
|
||||
COPY package.json pnpm-lock.yaml ./
|
||||
RUN pnpm install --frozen-lockfile
|
||||
RUN --mount=type=cache,id=pnpm-store-build,sharing=locked,target=/pnpm/store \
|
||||
pnpm install --frozen-lockfile
|
||||
|
||||
|
||||
FROM node:22-slim AS build
|
||||
|
||||
WORKDIR /app
|
||||
ARG NPM_REGISTRY=https://registry.npmjs.org/
|
||||
ENV NPM_CONFIG_REGISTRY=${NPM_REGISTRY}
|
||||
ENV npm_config_registry=${NPM_REGISTRY}
|
||||
|
||||
RUN corepack enable
|
||||
RUN npm config set registry ${NPM_REGISTRY}
|
||||
|
||||
COPY --from=deps /app/node_modules ./node_modules
|
||||
COPY . .
|
||||
|
||||
ENV PRISMA_CLIENT_ENGINE_TYPE=binary
|
||||
RUN pnpm run build
|
||||
|
||||
RUN pnpm run build && pnpm prune --prod
|
||||
FROM base AS prod-deps
|
||||
|
||||
COPY package.json pnpm-lock.yaml ./
|
||||
RUN --mount=type=cache,id=pnpm-store-prod,sharing=locked,target=/pnpm/store \
|
||||
pnpm install --prod --frozen-lockfile \
|
||||
&& rm -rf /root/.npm /root/.cache
|
||||
|
||||
FROM node:22-slim AS runtime
|
||||
|
||||
WORKDIR /app
|
||||
ARG NPM_REGISTRY=https://registry.npmjs.org/
|
||||
ENV NPM_CONFIG_REGISTRY=${NPM_REGISTRY}
|
||||
ENV npm_config_registry=${NPM_REGISTRY}
|
||||
|
||||
ENV NODE_ENV=production
|
||||
|
||||
COPY --from=build /app/node_modules ./node_modules
|
||||
COPY --from=prod-deps /app/node_modules ./node_modules
|
||||
COPY --from=build /app/dist ./dist
|
||||
COPY --from=build /app/prisma ./prisma
|
||||
COPY --from=build /app/package.json ./package.json
|
||||
|
||||
USER node
|
||||
CMD ["node", "dist/src/main.js"]
|
||||
|
||||
|
||||
+1533
File diff suppressed because one or more lines are too long
+74
-5
@@ -15,7 +15,6 @@ services:
|
||||
- "${DATABASE_PORT}:3306"
|
||||
volumes:
|
||||
- db_data:/var/lib/mysql
|
||||
- ./prisma/migrations:/docker-entrypoint-initdb.d
|
||||
healthcheck:
|
||||
test: "mysqladmin ping -h 127.0.0.1 -u ${DATABASE_USER} -p'${DB_ROOT_PASSWORD}'"
|
||||
interval: 15s # Shortened interval, as MySQL is starting fast now
|
||||
@@ -26,6 +25,24 @@ services:
|
||||
networks:
|
||||
- psp_consumer_network
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
platform: ${DOCKER_PLATFORM:-linux/amd64}
|
||||
container_name: psp_consumer_api_redis
|
||||
restart: unless-stopped
|
||||
command: redis-server --appendonly yes
|
||||
ports:
|
||||
- "${REDIS_PORT:-6379}:6379"
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
networks:
|
||||
- psp_consumer_network
|
||||
|
||||
api:
|
||||
platform: ${DOCKER_PLATFORM:-linux/amd64}
|
||||
build:
|
||||
@@ -52,6 +69,8 @@ services:
|
||||
depends_on:
|
||||
database:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
NODE_ENV: ${NODE_ENV:-production}
|
||||
PORT: ${PORT}
|
||||
@@ -66,12 +85,19 @@ services:
|
||||
JWT_EXPIRES_IN: ${JWT_EXPIRES_IN}
|
||||
CORS_ORIGINS: ${CORS_ORIGINS:-http://localhost:5000,http://127.0.0.1:5000}
|
||||
OTP_STATIC_CODE: ${OTP_STATIC_CODE} # From .env
|
||||
REDIS_HOST: ${REDIS_HOST:-redis}
|
||||
REDIS_PORT: ${REDIS_PORT:-6379}
|
||||
REDIS_DB: ${REDIS_DB:-0}
|
||||
REDIS_PASSWORD: ${REDIS_PASSWORD:-}
|
||||
ports:
|
||||
- "${PORT:-5002}:5002"
|
||||
volumes:
|
||||
- ./src:/app/src
|
||||
- /app/dist
|
||||
- /app/node_modules
|
||||
read_only: true
|
||||
tmpfs:
|
||||
- /tmp
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
cap_drop:
|
||||
- ALL
|
||||
networks:
|
||||
- psp_consumer_network
|
||||
# healthcheck:
|
||||
@@ -89,9 +115,52 @@ services:
|
||||
# retries: 3
|
||||
# start_period: 10s
|
||||
|
||||
# seed:
|
||||
# platform: ${DOCKER_PLATFORM:-linux/amd64}
|
||||
# build:
|
||||
# context: .
|
||||
# dockerfile: Dockerfile
|
||||
# target: build
|
||||
# args:
|
||||
# NODE_ENV: ${NODE_ENV:-production}
|
||||
# PORT: ${PORT}
|
||||
# DATABASE_NAME: ${DATABASE_NAME}
|
||||
# DATABASE_USER: ${DATABASE_USER}
|
||||
# DATABASE_PASSWORD: ${DATABASE_PASSWORD}
|
||||
# DATABASE_PORT: ${DATABASE_PORT}
|
||||
# DATABASE_HOST: ${DATABASE_HOST}
|
||||
# DATABASE_URL: mysql://${DATABASE_USER}:${DATABASE_PASSWORD}@${DATABASE_HOST}:${DATABASE_PORT}/${DATABASE_NAME}
|
||||
# SHADOW_DATABASE_URL: mysql://${DATABASE_USER}:${DATABASE_PASSWORD}@${DATABASE_HOST}:${DATABASE_PORT}/${DATABASE_NAME}_shadow
|
||||
# JWT_SECRET: ${JWT_SECRET}
|
||||
# JWT_EXPIRES_IN: ${JWT_EXPIRES_IN}
|
||||
# OTP_STATIC_CODE: ${OTP_STATIC_CODE}
|
||||
# depends_on:
|
||||
# database:
|
||||
# condition: service_healthy
|
||||
# environment:
|
||||
# NODE_ENV: ${NODE_ENV:-production}
|
||||
# PORT: ${PORT}
|
||||
# DATABASE_NAME: ${DATABASE_NAME}
|
||||
# DATABASE_USER: ${DATABASE_USER}
|
||||
# DATABASE_PASSWORD: ${DATABASE_PASSWORD}
|
||||
# DATABASE_PORT: ${DATABASE_PORT}
|
||||
# DATABASE_HOST: ${DATABASE_HOST}
|
||||
# DATABASE_URL: mysql://${DATABASE_USER}:${DATABASE_PASSWORD}@${DATABASE_HOST}:${DATABASE_PORT}/${DATABASE_NAME}
|
||||
# SHADOW_DATABASE_URL: mysql://${DATABASE_USER}:${DATABASE_PASSWORD}@${DATABASE_HOST}:${DATABASE_PORT}/${DATABASE_NAME}_shadow
|
||||
# JWT_SECRET: ${JWT_SECRET}
|
||||
# JWT_EXPIRES_IN: ${JWT_EXPIRES_IN}
|
||||
# OTP_STATIC_CODE: ${OTP_STATIC_CODE}
|
||||
# networks:
|
||||
# - psp_consumer_network
|
||||
# profiles:
|
||||
# - tools
|
||||
# command: ["pnpm", "seed:sku"]
|
||||
|
||||
volumes:
|
||||
db_data:
|
||||
driver: local
|
||||
redis_data:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
psp_consumer_network:
|
||||
|
||||
+5
-1
@@ -9,6 +9,7 @@
|
||||
"@nestjs/platform-express": "^11.1.19",
|
||||
"@nestjs/swagger": "^11.3.2",
|
||||
"@prisma/adapter-mariadb": "^7.7.0",
|
||||
"@prisma/client": "^7.7.0",
|
||||
"@types/bcrypt": "^6.0.0",
|
||||
"@types/multer": "^2.1.0",
|
||||
"bcrypt": "^6.0.0",
|
||||
@@ -17,6 +18,7 @@
|
||||
"cookie-parser": "^1.4.7",
|
||||
"dayjs": "^1.11.20",
|
||||
"dotenv": "^17.4.2",
|
||||
"ioredis": "^5.8.2",
|
||||
"jalaliday": "^3.1.1",
|
||||
"jsonwebtoken": "^9.0.3",
|
||||
"multer": "^2.1.1",
|
||||
@@ -33,7 +35,6 @@
|
||||
"@nestjs/cli": "^11.0.21",
|
||||
"@nestjs/schematics": "^11.1.0",
|
||||
"@nestjs/testing": "^11.1.19",
|
||||
"@prisma/client": "^7.7.0",
|
||||
"@types/cookie-parser": "^1.4.10",
|
||||
"@types/express": "^5.0.6",
|
||||
"@types/jest": "^30.0.0",
|
||||
@@ -44,6 +45,7 @@
|
||||
"eslint-plugin-prettier": "^5.5.5",
|
||||
"globals": "^16.5.0",
|
||||
"jest": "^30.3.0",
|
||||
"plop": "^4.0.5",
|
||||
"prettier": "^3.8.3",
|
||||
"prettier-plugin-prisma": "^5.0.0",
|
||||
"source-map-support": "^0.5.21",
|
||||
@@ -81,8 +83,10 @@
|
||||
"db:reset": "tsx scripts/dump-triggers.ts && npx prisma migrate reset --force",
|
||||
"dump-triggers": "tsx scripts/dump-triggers.ts",
|
||||
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
|
||||
"generate": "plop",
|
||||
"generate:permissions": "tsx scripts/generate-permissions.ts",
|
||||
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
|
||||
"seed:sku": "tsx scripts/seedStockKeepingUnits.ts",
|
||||
"start": "nest start",
|
||||
"start:debug": "nest start --debug --watch",
|
||||
"start:dev": "nest start --watch",
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
import {
|
||||
Body,
|
||||
Controller,
|
||||
Delete,
|
||||
Get,
|
||||
Param,
|
||||
Patch,
|
||||
Post,
|
||||
} from '@nestjs/common';
|
||||
import { {{pascalCase name}}Service } from './{{kebabCase name}}.service';
|
||||
import { Create{{pascalCase name}}Dto } from './dto/create-{{kebabCase name}}.dto';
|
||||
import { Update{{pascalCase name}}Dto } from './dto/update-{{kebabCase name}}.dto';
|
||||
|
||||
@Controller('{{kebabCase name}}')
|
||||
export class {{pascalCase name}}Controller {
|
||||
constructor(private readonly service: {{pascalCase name}}Service) {}
|
||||
|
||||
|
||||
@Get()
|
||||
findAll() {
|
||||
return this.service.findAll();
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
findOne(@Param('id') id: string) {
|
||||
return this.service.findOne(id);
|
||||
}
|
||||
|
||||
@Post()
|
||||
create(@Body() dto: Create{{pascalCase name}}Dto) {
|
||||
return this.service.create(dto);
|
||||
}
|
||||
|
||||
@Patch(':id')
|
||||
update(
|
||||
@Param('id') id: string,
|
||||
@Body() dto: Update{{pascalCase name}}Dto,
|
||||
) {
|
||||
return this.service.update(id, dto);
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
remove(@Param('id') id: string) {
|
||||
return this.service.remove(id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import { IsString, IsNumber, IsBoolean, IsEmail } from 'class-validator';
|
||||
|
||||
export class Create{{pascalCase name}}Dto {
|
||||
{{#each parsedFields}}
|
||||
@{{validator}}()
|
||||
{{name}}: {{type}};
|
||||
|
||||
{{/each}}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { {{pascalCase name}}Service } from './{{kebabCase name}}.service';
|
||||
import { {{pascalCase name}}Controller } from './{{kebabCase name}}.controller';
|
||||
import { PrismaService } from '{{prismaImportPath modulePath name}}';
|
||||
|
||||
@Module({
|
||||
controllers: [{{pascalCase name}}Controller],
|
||||
providers: [{{pascalCase name}}Service, PrismaService],
|
||||
})
|
||||
export class {{pascalCase name}}Module {}
|
||||
@@ -0,0 +1,63 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { PrismaService } from '@/prisma/prisma.service';
|
||||
import { ResponseMapper } from '@/common/response/response-mapper'
|
||||
import { Create{{pascalCase name}}Dto } from './dto/create-{{kebabCase name}}.dto';
|
||||
import { Update{{pascalCase name}}Dto } from './dto/update-{{kebabCase name}}.dto';
|
||||
|
||||
@Injectable()
|
||||
export class {{pascalCase name}}Service {
|
||||
constructor(private readonly prisma: PrismaService) {}
|
||||
|
||||
private readonly summarySelect = {
|
||||
id: true,
|
||||
}
|
||||
|
||||
private readonly select = {
|
||||
...this.summarySelect,
|
||||
}
|
||||
|
||||
private readonly where = () => ({})
|
||||
|
||||
|
||||
async findAll() {
|
||||
const items = await this.prisma.{{camelCase name}}.findMany({
|
||||
where: this.where(),
|
||||
select: this.summarySelect,
|
||||
});
|
||||
return ResponseMapper.list(items)
|
||||
}
|
||||
|
||||
async findOne(id: string) {
|
||||
const item = this.prisma.{{camelCase name}}.findUnique({
|
||||
where: {...this.where(), id },
|
||||
select: this.select,
|
||||
});
|
||||
|
||||
return ResponseMapper.single(item)
|
||||
}
|
||||
|
||||
async create(createDto: Create{{pascalCase name}}Dto) {
|
||||
const item = this.prisma.{{camelCase name}}.create({
|
||||
data: createDto,
|
||||
select: this.select,
|
||||
});
|
||||
|
||||
return ResponseMapper.create(item)
|
||||
}
|
||||
|
||||
async update(id: string, updateDto: Update{{pascalCase name}}Dto) {
|
||||
const item = this.prisma.{{camelCase name}}.update({
|
||||
where: { id },
|
||||
data: updateDto,
|
||||
select: this.select,
|
||||
});
|
||||
|
||||
return ResponseMapper.update(item)
|
||||
}
|
||||
|
||||
async remove(id: string) {
|
||||
return this.prisma.{{camelCase name}}.delete({
|
||||
where: { id },
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
import { PartialType } from '@nestjs/swagger'
|
||||
import { Create{{pascalCase name}}Dto } from './create-{{kebabCase name}}.dto';
|
||||
|
||||
export class Update{{pascalCase name}}Dto extends PartialType(Create{{pascalCase name}}Dto) {}
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
const path = require('path')
|
||||
|
||||
module.exports = function (plop) {
|
||||
// -------------------------
|
||||
// Case helpers
|
||||
// -------------------------
|
||||
const toKebab = str =>
|
||||
str
|
||||
.replace(/([a-z])([A-Z])/g, '$1-$2')
|
||||
.replace(/\s+/g, '-')
|
||||
.toLowerCase()
|
||||
|
||||
const toPascal = str =>
|
||||
str
|
||||
.split(/[-_\s]+/)
|
||||
.map(part => part.charAt(0).toUpperCase() + part.slice(1))
|
||||
.join('')
|
||||
|
||||
const toCamel = str => {
|
||||
const pascal = toPascal(str)
|
||||
return pascal.charAt(0).toLowerCase() + pascal.slice(1)
|
||||
}
|
||||
|
||||
plop.setHelper('kebabCase', toKebab)
|
||||
plop.setHelper('pascalCase', toPascal)
|
||||
plop.setHelper('camelCase', toCamel)
|
||||
|
||||
// -------------------------
|
||||
// Dynamic relative import helper
|
||||
// -------------------------
|
||||
plop.setHelper('prismaImportPath', (modulePath, name) => {
|
||||
return '@/prisma/prisma.service'
|
||||
})
|
||||
|
||||
// -------------------------
|
||||
// Generator
|
||||
// -------------------------
|
||||
plop.setGenerator('resource', {
|
||||
description: 'Generate Nested NestJS Prisma Resource',
|
||||
prompts: [
|
||||
{
|
||||
type: 'input',
|
||||
name: 'name',
|
||||
message: 'Module name (e.g. user, blog-post):',
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
name: 'modulePath',
|
||||
message: 'Nested path inside modules (e.g. admin/users) — leave empty for root:',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
name: 'fields',
|
||||
message:
|
||||
'DTO fields (comma-separated, e.g. name:string,email:email,age:number,isActive:boolean):',
|
||||
},
|
||||
],
|
||||
actions(data) {
|
||||
// sanitize path
|
||||
data.modulePath = data.modulePath.replace(/^\/+|\/+$/g, '')
|
||||
|
||||
// Parse fields
|
||||
const rawFields = data.fields || ''
|
||||
data.parsedFields = rawFields
|
||||
.split(',')
|
||||
.filter(Boolean)
|
||||
.map(field => {
|
||||
const [name, type] = field.split(':').map(v => v.trim())
|
||||
|
||||
let validator = 'IsString'
|
||||
let finalType = 'string'
|
||||
|
||||
if (type === 'number') {
|
||||
validator = 'IsNumber'
|
||||
finalType = 'number'
|
||||
}
|
||||
|
||||
if (type === 'boolean') {
|
||||
validator = 'IsBoolean'
|
||||
finalType = 'boolean'
|
||||
}
|
||||
|
||||
if (type === 'email') {
|
||||
validator = 'IsEmail'
|
||||
finalType = 'string'
|
||||
}
|
||||
|
||||
return { name, validator, type: finalType }
|
||||
})
|
||||
|
||||
const basePath = data.modulePath
|
||||
? `src/modules/${data.modulePath}/{{kebabCase name}}`
|
||||
: `src/modules/{{kebabCase name}}`
|
||||
|
||||
return [
|
||||
{
|
||||
type: 'add',
|
||||
path: `${basePath}/{{kebabCase name}}.module.ts`,
|
||||
templateFile: 'plop-templates/module.hbs',
|
||||
},
|
||||
{
|
||||
type: 'add',
|
||||
path: `${basePath}/{{kebabCase name}}.service.ts`,
|
||||
templateFile: 'plop-templates/service.hbs',
|
||||
},
|
||||
{
|
||||
type: 'add',
|
||||
path: `${basePath}/{{kebabCase name}}.controller.ts`,
|
||||
templateFile: 'plop-templates/controller.hbs',
|
||||
},
|
||||
{
|
||||
type: 'add',
|
||||
path: `${basePath}/dto/create-{{kebabCase name}}.dto.ts`,
|
||||
templateFile: 'plop-templates/create-dto.hbs',
|
||||
},
|
||||
{
|
||||
type: 'add',
|
||||
path: `${basePath}/dto/update-{{kebabCase name}}.dto.ts`,
|
||||
templateFile: 'plop-templates/update-dto.hbs',
|
||||
},
|
||||
]
|
||||
},
|
||||
})
|
||||
}
|
||||
Generated
+562
-65
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,913 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE `admin_accounts` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
`admin_id` VARCHAR(191) NOT NULL,
|
||||
`account_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
UNIQUE INDEX `admin_accounts_account_id_key`(`account_id`),
|
||||
INDEX `admin_accounts_admin_id_fkey`(`admin_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `admins` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`mobile_number` VARCHAR(191) NOT NULL,
|
||||
`national_code` VARCHAR(191) NULL,
|
||||
`first_name` VARCHAR(191) NOT NULL,
|
||||
`last_name` VARCHAR(191) NOT NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
|
||||
UNIQUE INDEX `admins_mobile_number_key`(`mobile_number`),
|
||||
UNIQUE INDEX `admins_national_code_key`(`national_code`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `accounts` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`username` VARCHAR(191) NOT NULL,
|
||||
`password` VARCHAR(191) NOT NULL,
|
||||
`status` ENUM('ACTIVE', 'SUSPENDED') NOT NULL,
|
||||
`type` ENUM('ADMIN', 'PROVIDER', 'PARTNER', 'CONSUMER') NOT NULL,
|
||||
|
||||
UNIQUE INDEX `accounts_username_key`(`username`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `device_brands` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`name` VARCHAR(191) NOT NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `devices` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`name` VARCHAR(191) NOT NULL,
|
||||
`os_version` VARCHAR(191) NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
`brand_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
INDEX `devices_brand_id_idx`(`brand_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `license_charged_transactions` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`activation_expires_at` DATETIME(3) NOT NULL,
|
||||
`tracking_code` VARCHAR(191) NOT NULL,
|
||||
`purchased_count` INTEGER NOT NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
`partner_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
UNIQUE INDEX `license_charged_transactions_tracking_code_key`(`tracking_code`),
|
||||
INDEX `license_charged_transactions_partner_id_idx`(`partner_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `licenses` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`accounts_limit` INTEGER NOT NULL DEFAULT 2,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
`charge_transaction_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
INDEX `licenses_charge_transaction_id_idx`(`charge_transaction_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `licenses_activated` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`starts_at` DATETIME(3) NOT NULL,
|
||||
`expires_at` DATETIME(3) NOT NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
`license_id` VARCHAR(191) NOT NULL,
|
||||
`business_activity_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
UNIQUE INDEX `licenses_activated_id_key`(`id`),
|
||||
UNIQUE INDEX `licenses_activated_license_id_key`(`license_id`),
|
||||
UNIQUE INDEX `licenses_activated_business_activity_id_key`(`business_activity_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `license_renew_charge_transaction` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`activation_expires_at` DATETIME(3) NOT NULL,
|
||||
`tracking_code` VARCHAR(191) NOT NULL,
|
||||
`purchased_count` INTEGER NOT NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
`partner_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
UNIQUE INDEX `license_renew_charge_transaction_tracking_code_key`(`tracking_code`),
|
||||
INDEX `license_renew_charge_transaction_partner_id_idx`(`partner_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `license_renew` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`expires_at` DATETIME(3) NOT NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
`charge_transaction_id` VARCHAR(191) NOT NULL,
|
||||
`activation_id` VARCHAR(191) NULL,
|
||||
|
||||
INDEX `license_renew_activation_id_idx`(`activation_id`),
|
||||
INDEX `license_renew_charge_transaction_id_idx`(`charge_transaction_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `partner_account_quota_charge_transaction` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`activation_expires_at` DATETIME(3) NOT NULL,
|
||||
`tracking_code` VARCHAR(191) NOT NULL,
|
||||
`purchased_count` INTEGER NOT NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
`partner_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
UNIQUE INDEX `partner_account_quota_charge_transaction_tracking_code_key`(`tracking_code`),
|
||||
INDEX `partner_account_quota_charge_transaction_partner_id_idx`(`partner_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `partner_account_quota_credit` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
`charge_transaction_id` VARCHAR(191) NULL,
|
||||
|
||||
INDEX `partner_account_quota_credit_charge_transaction_id_idx`(`charge_transaction_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `license_account_allocation` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
`license_activation_id` VARCHAR(191) NULL,
|
||||
`account_id` VARCHAR(191) NULL,
|
||||
`credit_id` VARCHAR(191) NULL,
|
||||
|
||||
UNIQUE INDEX `license_account_allocation_account_id_key`(`account_id`),
|
||||
UNIQUE INDEX `license_account_allocation_credit_id_key`(`credit_id`),
|
||||
INDEX `license_account_allocation_license_activation_id_idx`(`license_activation_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `partner_accounts` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`role` ENUM('OWNER', 'MANAGER', 'OPERATOR') NOT NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`partner_id` VARCHAR(191) NOT NULL,
|
||||
`account_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
UNIQUE INDEX `partner_accounts_account_id_key`(`account_id`),
|
||||
INDEX `partner_accounts_partner_id_fkey`(`partner_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `partners` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`name` VARCHAR(191) NOT NULL,
|
||||
`code` VARCHAR(191) NOT NULL,
|
||||
`status` ENUM('ACTIVE', 'SUSPENDED') NOT NULL DEFAULT 'ACTIVE',
|
||||
`logo_url` VARCHAR(191) NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`tsp_provider` ENUM('NAMA', 'SUN') NOT NULL DEFAULT 'NAMA',
|
||||
|
||||
UNIQUE INDEX `partners_code_key`(`code`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `permission_consumers` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`consumer_account_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
UNIQUE INDEX `permission_consumers_consumer_account_id_key`(`consumer_account_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `permission_poses` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`role` ENUM('MANAGER', 'OPERATOR') NOT NULL,
|
||||
`pos_id` VARCHAR(191) NOT NULL,
|
||||
`permission_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
INDEX `permission_poses_pos_id_fkey`(`pos_id`),
|
||||
UNIQUE INDEX `permission_poses_permission_id_pos_id_key`(`permission_id`, `pos_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `permission_complexes` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`role` ENUM('MANAGER', 'OPERATOR') NOT NULL,
|
||||
`complex_id` VARCHAR(191) NOT NULL,
|
||||
`permission_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
INDEX `permission_complexes_complex_id_fkey`(`complex_id`),
|
||||
UNIQUE INDEX `permission_complexes_permission_id_complex_id_key`(`permission_id`, `complex_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `permission_business_activities` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`role` ENUM('MANAGER', 'OPERATOR') NOT NULL,
|
||||
`business_id` VARCHAR(191) NOT NULL,
|
||||
`permission_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
INDEX `permission_business_activities_business_id_fkey`(`business_id`),
|
||||
UNIQUE INDEX `permission_business_activities_permission_id_business_id_key`(`permission_id`, `business_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `provider_accounts` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`role` ENUM('OWNER', 'MANAGER', 'OPERATOR') NOT NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
`provider_id` VARCHAR(191) NOT NULL,
|
||||
`account_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
UNIQUE INDEX `provider_accounts_account_id_key`(`account_id`),
|
||||
INDEX `provider_accounts_provider_id_fkey`(`provider_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `providers` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`code` VARCHAR(191) NOT NULL,
|
||||
`status` ENUM('ACTIVE', 'SUSPENDED') NOT NULL DEFAULT 'ACTIVE',
|
||||
`name` VARCHAR(191) NOT NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
|
||||
UNIQUE INDEX `providers_code_key`(`code`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `consumer_account_device` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`device_id` VARCHAR(191) NOT NULL,
|
||||
`device_name` VARCHAR(191) NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
`consumer_account_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
UNIQUE INDEX `consumer_account_device_device_id_key`(`device_id`),
|
||||
UNIQUE INDEX `consumer_account_device_consumer_account_id_key`(`consumer_account_id`),
|
||||
INDEX `consumer_account_device_consumer_account_id_idx`(`consumer_account_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `application_released_info` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`version` VARCHAR(191) NOT NULL,
|
||||
`build_number` VARCHAR(191) NOT NULL,
|
||||
`is_minimum_supported` BOOLEAN NOT NULL DEFAULT false,
|
||||
`release_type` ENUM('STABLE', 'BETA', 'ALPHA') NOT NULL,
|
||||
`platform` ENUM('ANDROID', 'IOS') NOT NULL,
|
||||
`notes` JSON NULL,
|
||||
`release_date` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `consumer_accounts` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`role` ENUM('OWNER', 'MANAGER', 'OPERATOR') NOT NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
`consumer_id` VARCHAR(191) NOT NULL,
|
||||
`account_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
UNIQUE INDEX `consumer_accounts_account_id_key`(`account_id`),
|
||||
INDEX `consumer_accounts_consumer_id_fkey`(`consumer_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `consumers` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`type` ENUM('INDIVIDUAL', 'LEGAL') NOT NULL,
|
||||
`status` ENUM('ACTIVE', 'SUSPENDED') NOT NULL DEFAULT 'ACTIVE',
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `consumers_individual` (
|
||||
`first_name` VARCHAR(191) NOT NULL,
|
||||
`last_name` VARCHAR(191) NOT NULL,
|
||||
`mobile_number` VARCHAR(191) NOT NULL,
|
||||
`national_code` VARCHAR(191) NOT NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
`partner_id` VARCHAR(191) NOT NULL,
|
||||
`consumer_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
UNIQUE INDEX `consumers_individual_mobile_number_consumer_id_key`(`mobile_number`, `consumer_id`),
|
||||
UNIQUE INDEX `consumers_individual_partner_id_national_code_key`(`partner_id`, `national_code`),
|
||||
PRIMARY KEY (`consumer_id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `consumers_legal` (
|
||||
`name` VARCHAR(191) NOT NULL,
|
||||
`registration_code` VARCHAR(191) NOT NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
`partner_id` VARCHAR(191) NOT NULL,
|
||||
`consumer_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
UNIQUE INDEX `consumers_legal_partner_id_registration_code_key`(`partner_id`, `registration_code`),
|
||||
PRIMARY KEY (`consumer_id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `business_activities` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`economic_code` VARCHAR(191) NOT NULL,
|
||||
`name` VARCHAR(191) NOT NULL,
|
||||
`fiscal_id` VARCHAR(191) NOT NULL,
|
||||
`partner_token` VARCHAR(191) NOT NULL,
|
||||
`invoice_number_sequence` DECIMAL(20, 0) NOT NULL DEFAULT 1,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
`guild_id` VARCHAR(191) NOT NULL,
|
||||
`consumer_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
INDEX `business_activities_consumer_id_fkey`(`consumer_id`),
|
||||
INDEX `business_activities_guild_id_fkey`(`guild_id`),
|
||||
UNIQUE INDEX `business_activities_economic_code_consumer_id_key`(`economic_code`, `consumer_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `complexes` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`name` VARCHAR(191) NOT NULL,
|
||||
`branch_code` VARCHAR(191) NOT NULL,
|
||||
`address` VARCHAR(191) NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
`business_activity_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
INDEX `complexes_business_activity_id_fkey`(`business_activity_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `poses` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`name` VARCHAR(191) NOT NULL,
|
||||
`model` VARCHAR(191) NULL,
|
||||
`serial_number` VARCHAR(191) NULL,
|
||||
`status` ENUM('ACTIVE', 'DISABLED') NOT NULL DEFAULT 'ACTIVE',
|
||||
`pos_type` ENUM('PSP', 'MOBILE', 'WEB', 'API') NOT NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
`complex_id` VARCHAR(191) NOT NULL,
|
||||
`device_id` VARCHAR(191) NULL,
|
||||
`provider_id` VARCHAR(191) NULL,
|
||||
`account_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
UNIQUE INDEX `poses_serial_number_key`(`serial_number`),
|
||||
UNIQUE INDEX `poses_account_id_key`(`account_id`),
|
||||
INDEX `poses_complex_id_fkey`(`complex_id`),
|
||||
INDEX `poses_device_id_fkey`(`device_id`),
|
||||
INDEX `poses_provider_id_fkey`(`provider_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `consumer_account_good_favorites` (
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`consumer_account_id` VARCHAR(191) NOT NULL,
|
||||
`good_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
INDEX `consumer_account_good_favorites_good_id_idx`(`good_id`),
|
||||
INDEX `consumer_account_good_favorites_consumer_account_id_idx`(`consumer_account_id`),
|
||||
PRIMARY KEY (`consumer_account_id`, `good_id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `goods` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`name` VARCHAR(255) NOT NULL,
|
||||
`is_default_guild_good` BOOLEAN NOT NULL DEFAULT false,
|
||||
`pricing_model` ENUM('STANDARD', 'GOLD') NOT NULL,
|
||||
`description` TEXT NULL,
|
||||
`local_sku` VARCHAR(100) NULL,
|
||||
`barcode` VARCHAR(100) NULL,
|
||||
`base_sale_price` DECIMAL(15, 0) NULL DEFAULT 0,
|
||||
`image_url` VARCHAR(255) NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
`deleted_at` TIMESTAMP(0) NULL,
|
||||
`sku_id` VARCHAR(191) NOT NULL,
|
||||
`measure_unit_id` VARCHAR(191) NOT NULL,
|
||||
`category_id` VARCHAR(191) NULL,
|
||||
`business_activity_id` VARCHAR(191) NULL,
|
||||
|
||||
UNIQUE INDEX `goods_local_sku_key`(`local_sku`),
|
||||
UNIQUE INDEX `goods_barcode_key`(`barcode`),
|
||||
INDEX `goods_category_id_idx`(`category_id`),
|
||||
INDEX `goods_business_activity_id_fkey`(`business_activity_id`),
|
||||
INDEX `goods_measure_unit_id_fkey`(`measure_unit_id`),
|
||||
INDEX `goods_sku_id_fkey`(`sku_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `good_categories` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`name` VARCHAR(100) NOT NULL,
|
||||
`description` TEXT NULL,
|
||||
`image_url` VARCHAR(255) NULL,
|
||||
`complex_id` VARCHAR(191) NULL,
|
||||
`is_default_guild_good` BOOLEAN NOT NULL DEFAULT false,
|
||||
`guild_id` VARCHAR(191) NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
`deleted_at` TIMESTAMP(0) NULL,
|
||||
|
||||
INDEX `good_categories_complex_id_fkey`(`complex_id`),
|
||||
INDEX `good_categories_guild_id_fkey`(`guild_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `guilds` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`name` VARCHAR(191) NOT NULL,
|
||||
`invoice_template` ENUM('SALE', 'FX_SALE', 'GOLD_JEWELRY', 'CONTRACT', 'UTILITY', 'AIR_TICKET', 'EXPORT', 'BILL_OF_LADING', 'PETROCHEMICAL', 'COMMODITY_EXCHANGE', 'INSURANCE') NOT NULL,
|
||||
`code` VARCHAR(191) NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `measure_units` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`code` VARCHAR(191) NOT NULL,
|
||||
`name` VARCHAR(191) NOT NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
|
||||
UNIQUE INDEX `measure_units_code_key`(`code`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `stock_keeping_units` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`code` VARCHAR(191) NOT NULL,
|
||||
`name` VARCHAR(191) NOT NULL,
|
||||
`VAT` DECIMAL(5, 2) NOT NULL,
|
||||
`is_public` BOOLEAN NOT NULL DEFAULT true,
|
||||
`is_domestic` BOOLEAN NOT NULL DEFAULT false,
|
||||
`guild_id` VARCHAR(191) NOT NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
|
||||
UNIQUE INDEX `stock_keeping_units_code_key`(`code`),
|
||||
INDEX `stock_keeping_units_code_idx`(`code`),
|
||||
INDEX `stock_keeping_units_guild_id_fkey`(`guild_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `trigger_logs` (
|
||||
`id` INTEGER NOT NULL AUTO_INCREMENT,
|
||||
`message` TEXT NOT NULL,
|
||||
`createdAt` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`name` TEXT NOT NULL,
|
||||
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `customers` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`is_favorite` BOOLEAN NULL DEFAULT false,
|
||||
`type` ENUM('INDIVIDUAL', 'LEGAL', 'UNKNOWN') NOT NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
`deleted_at` TIMESTAMP(0) NULL,
|
||||
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `customer_individuals` (
|
||||
`first_name` VARCHAR(255) NOT NULL,
|
||||
`last_name` VARCHAR(255) NOT NULL,
|
||||
`national_id` CHAR(10) NOT NULL,
|
||||
`mobile_number` CHAR(15) NOT NULL,
|
||||
`postal_code` CHAR(10) NOT NULL,
|
||||
`economic_code` CHAR(10) NULL,
|
||||
`customer_id` VARCHAR(191) NOT NULL,
|
||||
`business_activity_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
INDEX `customer_individuals_business_activity_id_idx`(`business_activity_id`),
|
||||
UNIQUE INDEX `customer_individuals_business_activity_id_national_id_key`(`business_activity_id`, `national_id`),
|
||||
PRIMARY KEY (`customer_id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `customer_legal` (
|
||||
`name` VARCHAR(255) NOT NULL,
|
||||
`economic_code` CHAR(10) NOT NULL,
|
||||
`registration_number` CHAR(20) NULL,
|
||||
`postal_code` CHAR(10) NOT NULL,
|
||||
`customer_id` VARCHAR(191) NOT NULL,
|
||||
`business_activity_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
INDEX `customer_legal_business_activity_id_idx`(`business_activity_id`),
|
||||
UNIQUE INDEX `customer_legal_business_activity_id_economic_code_key`(`business_activity_id`, `economic_code`),
|
||||
PRIMARY KEY (`customer_id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `sales_invoices` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`code` VARCHAR(100) NOT NULL,
|
||||
`total_amount` DECIMAL(15, 2) NOT NULL,
|
||||
`invoice_number` INTEGER NOT NULL,
|
||||
`invoice_date` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`type` ENUM('ORIGINAL', 'CORRECTION', 'REVOKE', 'RETURN') NOT NULL,
|
||||
`tax_id` VARCHAR(32) NULL,
|
||||
`notes` TEXT NULL,
|
||||
`unknown_customer` JSON NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
`main_id` VARCHAR(50) NULL,
|
||||
`ref_id` VARCHAR(50) NULL,
|
||||
`customer_id` VARCHAR(191) NULL,
|
||||
`consumer_account_id` VARCHAR(191) NOT NULL,
|
||||
`pos_id` VARCHAR(191) NOT NULL,
|
||||
`settlement_type` ENUM('CASH', 'CREDIT', 'MIXED') NOT NULL,
|
||||
`discount_amount` DECIMAL(15, 2) NULL,
|
||||
`tax_amount` DECIMAL(15, 2) NULL,
|
||||
|
||||
UNIQUE INDEX `sales_invoices_code_key`(`code`),
|
||||
UNIQUE INDEX `sales_invoices_tax_id_key`(`tax_id`),
|
||||
UNIQUE INDEX `sales_invoices_ref_id_key`(`ref_id`),
|
||||
INDEX `sales_invoices_ref_id_idx`(`ref_id`),
|
||||
INDEX `sales_invoices_tax_id_idx`(`tax_id`),
|
||||
INDEX `sales_invoices_consumer_account_id_fkey`(`consumer_account_id`),
|
||||
INDEX `sales_invoices_customer_id_fkey`(`customer_id`),
|
||||
INDEX `sales_invoices_pos_id_fkey`(`pos_id`),
|
||||
UNIQUE INDEX `sales_invoices_invoice_number_pos_id_key`(`invoice_number`, `pos_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `sales_invoice_items` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`quantity` DECIMAL(10, 0) NOT NULL,
|
||||
`measure_unit_text` VARCHAR(50) NOT NULL,
|
||||
`measure_unit_code` VARCHAR(50) NOT NULL,
|
||||
`sku_code` VARCHAR(50) NOT NULL,
|
||||
`sku_vat` DECIMAL(15, 2) NOT NULL DEFAULT 0.00,
|
||||
`unit_price` DECIMAL(15, 2) NOT NULL DEFAULT 0.00,
|
||||
`total_amount` DECIMAL(15, 2) NOT NULL DEFAULT 0.00,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`discount` DECIMAL(15, 2) NOT NULL DEFAULT 0.00,
|
||||
`notes` TEXT NULL,
|
||||
`payload` JSON NULL,
|
||||
`good_snapshot` JSON NOT NULL,
|
||||
`invoice_id` VARCHAR(191) NOT NULL,
|
||||
`good_id` VARCHAR(191) NOT NULL,
|
||||
`service_id` VARCHAR(191) NULL,
|
||||
`discount_amount` DECIMAL(15, 2) NULL,
|
||||
`tax_amount` DECIMAL(15, 2) NULL,
|
||||
|
||||
INDEX `sales_invoice_items_invoice_id_good_id_idx`(`invoice_id`, `good_id`),
|
||||
INDEX `sales_invoice_items_good_id_fkey`(`good_id`),
|
||||
INDEX `sales_invoice_items_service_id_fkey`(`service_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `sale_invoice_tsp_attempts` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`attempt_no` INTEGER NOT NULL,
|
||||
`status` ENUM('NOT_SEND', 'QUEUED', 'FISCAL_QUEUED', 'SEND_FAILURE', 'SUCCESS', 'FAILURE') NOT NULL,
|
||||
`message` TEXT NOT NULL,
|
||||
`sent_at` TIMESTAMP(0) NULL,
|
||||
`received_at` TIMESTAMP(0) NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`invoice_id` VARCHAR(191) NOT NULL,
|
||||
`provider_request_payload` JSON NOT NULL,
|
||||
`raw_request_payload` JSON NOT NULL,
|
||||
`error_message` TEXT NULL,
|
||||
`fiscal_warnings` JSON NULL,
|
||||
`provider_response` JSON NULL,
|
||||
`validation_errors` JSON NULL,
|
||||
|
||||
INDEX `sale_invoice_tsp_attempts_status_idx`(`status`),
|
||||
INDEX `sale_invoice_tsp_attempts_invoice_id_idx`(`invoice_id`),
|
||||
UNIQUE INDEX `sale_invoice_tsp_attempts_invoice_id_attempt_no_key`(`invoice_id`, `attempt_no`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `sales_invoice_payments` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`amount` DECIMAL(15, 2) NOT NULL,
|
||||
`payment_method` ENUM('CHEQUE', 'SET_OFF', 'CASH', 'TERMINAL', 'PAYMENT_GATEWAY', 'CARD', 'BANK', 'OTHER') NOT NULL,
|
||||
`paid_at` TIMESTAMP(0) NOT NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`invoice_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
INDEX `sales_invoice_payments_invoice_id_idx`(`invoice_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `sales_invoice_payment_terminal_info` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`terminal_id` VARCHAR(191) NOT NULL,
|
||||
`stan` VARCHAR(191) NOT NULL,
|
||||
`rrn` VARCHAR(191) NOT NULL,
|
||||
`transaction_date_time` DATETIME(3) NOT NULL,
|
||||
`customer_card_no` VARCHAR(191) NULL,
|
||||
`description` VARCHAR(191) NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`payment_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
UNIQUE INDEX `sales_invoice_payment_terminal_info_payment_id_key`(`payment_id`),
|
||||
UNIQUE INDEX `sales_invoice_payment_terminal_info_terminal_id_stan_rrn_pay_key`(`terminal_id`, `stan`, `rrn`, `payment_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `services` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`name` VARCHAR(255) NOT NULL,
|
||||
`description` TEXT NULL,
|
||||
`sku` VARCHAR(100) NOT NULL,
|
||||
`local_sku` VARCHAR(100) NULL,
|
||||
`barcode` VARCHAR(100) NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
`deleted_at` TIMESTAMP(0) NULL,
|
||||
`category_id` VARCHAR(191) NULL,
|
||||
`base_sale_price` DECIMAL(15, 0) NOT NULL DEFAULT 0,
|
||||
`account_id` VARCHAR(191) NOT NULL,
|
||||
`complex_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
UNIQUE INDEX `services_sku_key`(`sku`),
|
||||
UNIQUE INDEX `services_local_sku_key`(`local_sku`),
|
||||
UNIQUE INDEX `services_barcode_key`(`barcode`),
|
||||
INDEX `services_category_id_idx`(`category_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `service_categories` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`name` VARCHAR(100) NOT NULL,
|
||||
`description` TEXT NULL,
|
||||
`image_url` VARCHAR(255) NULL,
|
||||
`account_id` VARCHAR(191) NOT NULL,
|
||||
`complex_id` VARCHAR(191) NOT NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
`deleted_at` TIMESTAMP(0) NULL,
|
||||
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `admin_accounts` ADD CONSTRAINT `admin_accounts_account_id_fkey` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `admin_accounts` ADD CONSTRAINT `admin_accounts_admin_id_fkey` FOREIGN KEY (`admin_id`) REFERENCES `admins`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `devices` ADD CONSTRAINT `devices_brand_id_fkey` FOREIGN KEY (`brand_id`) REFERENCES `device_brands`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `license_charged_transactions` ADD CONSTRAINT `license_charged_transactions_partner_id_fkey` FOREIGN KEY (`partner_id`) REFERENCES `partners`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `licenses` ADD CONSTRAINT `licenses_charge_transaction_id_fkey` FOREIGN KEY (`charge_transaction_id`) REFERENCES `license_charged_transactions`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `licenses_activated` ADD CONSTRAINT `licenses_activated_business_activity_id_fkey` FOREIGN KEY (`business_activity_id`) REFERENCES `business_activities`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `licenses_activated` ADD CONSTRAINT `licenses_activated_license_id_fkey` FOREIGN KEY (`license_id`) REFERENCES `licenses`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `license_renew_charge_transaction` ADD CONSTRAINT `license_renew_charge_transaction_partner_id_fkey` FOREIGN KEY (`partner_id`) REFERENCES `partners`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `license_renew` ADD CONSTRAINT `license_renew_activation_id_fkey` FOREIGN KEY (`activation_id`) REFERENCES `licenses_activated`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `license_renew` ADD CONSTRAINT `license_renew_charge_transaction_id_fkey` FOREIGN KEY (`charge_transaction_id`) REFERENCES `license_renew_charge_transaction`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `partner_account_quota_charge_transaction` ADD CONSTRAINT `partner_account_quota_charge_transaction_partner_id_fkey` FOREIGN KEY (`partner_id`) REFERENCES `partners`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `partner_account_quota_credit` ADD CONSTRAINT `partner_account_quota_credit_charge_transaction_id_fkey` FOREIGN KEY (`charge_transaction_id`) REFERENCES `partner_account_quota_charge_transaction`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `license_account_allocation` ADD CONSTRAINT `license_account_allocation_account_id_fkey` FOREIGN KEY (`account_id`) REFERENCES `consumer_accounts`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `license_account_allocation` ADD CONSTRAINT `license_account_allocation_credit_id_fkey` FOREIGN KEY (`credit_id`) REFERENCES `partner_account_quota_credit`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `license_account_allocation` ADD CONSTRAINT `license_account_allocation_license_activation_id_fkey` FOREIGN KEY (`license_activation_id`) REFERENCES `licenses_activated`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `partner_accounts` ADD CONSTRAINT `partner_accounts_account_id_fkey` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `partner_accounts` ADD CONSTRAINT `partner_accounts_partner_id_fkey` FOREIGN KEY (`partner_id`) REFERENCES `partners`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `permission_consumers` ADD CONSTRAINT `permission_consumers_consumer_account_id_fkey` FOREIGN KEY (`consumer_account_id`) REFERENCES `consumer_accounts`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `permission_poses` ADD CONSTRAINT `permission_poses_permission_id_fkey` FOREIGN KEY (`permission_id`) REFERENCES `permission_consumers`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `permission_poses` ADD CONSTRAINT `permission_poses_pos_id_fkey` FOREIGN KEY (`pos_id`) REFERENCES `poses`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `permission_complexes` ADD CONSTRAINT `permission_complexes_complex_id_fkey` FOREIGN KEY (`complex_id`) REFERENCES `complexes`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `permission_complexes` ADD CONSTRAINT `permission_complexes_permission_id_fkey` FOREIGN KEY (`permission_id`) REFERENCES `permission_consumers`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `permission_business_activities` ADD CONSTRAINT `permission_business_activities_business_id_fkey` FOREIGN KEY (`business_id`) REFERENCES `business_activities`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `permission_business_activities` ADD CONSTRAINT `permission_business_activities_permission_id_fkey` FOREIGN KEY (`permission_id`) REFERENCES `permission_consumers`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `provider_accounts` ADD CONSTRAINT `provider_accounts_account_id_fkey` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `provider_accounts` ADD CONSTRAINT `provider_accounts_provider_id_fkey` FOREIGN KEY (`provider_id`) REFERENCES `providers`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `consumer_account_device` ADD CONSTRAINT `consumer_account_device_consumer_account_id_fkey` FOREIGN KEY (`consumer_account_id`) REFERENCES `consumer_accounts`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `consumer_accounts` ADD CONSTRAINT `consumer_accounts_account_id_fkey` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `consumer_accounts` ADD CONSTRAINT `consumer_accounts_consumer_id_fkey` FOREIGN KEY (`consumer_id`) REFERENCES `consumers`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `consumers_individual` ADD CONSTRAINT `consumers_individual_consumer_id_fkey` FOREIGN KEY (`consumer_id`) REFERENCES `consumers`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `consumers_individual` ADD CONSTRAINT `consumers_individual_partner_id_fkey` FOREIGN KEY (`partner_id`) REFERENCES `partners`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `consumers_legal` ADD CONSTRAINT `consumers_legal_consumer_id_fkey` FOREIGN KEY (`consumer_id`) REFERENCES `consumers`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `consumers_legal` ADD CONSTRAINT `consumers_legal_partner_id_fkey` FOREIGN KEY (`partner_id`) REFERENCES `partners`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `business_activities` ADD CONSTRAINT `business_activities_consumer_id_fkey` FOREIGN KEY (`consumer_id`) REFERENCES `consumers`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `business_activities` ADD CONSTRAINT `business_activities_guild_id_fkey` FOREIGN KEY (`guild_id`) REFERENCES `guilds`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `complexes` ADD CONSTRAINT `complexes_business_activity_id_fkey` FOREIGN KEY (`business_activity_id`) REFERENCES `business_activities`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `poses` ADD CONSTRAINT `poses_account_id_fkey` FOREIGN KEY (`account_id`) REFERENCES `consumer_accounts`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `poses` ADD CONSTRAINT `poses_complex_id_fkey` FOREIGN KEY (`complex_id`) REFERENCES `complexes`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `poses` ADD CONSTRAINT `poses_device_id_fkey` FOREIGN KEY (`device_id`) REFERENCES `devices`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `poses` ADD CONSTRAINT `poses_provider_id_fkey` FOREIGN KEY (`provider_id`) REFERENCES `providers`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `consumer_account_good_favorites` ADD CONSTRAINT `consumer_account_good_favorites_consumer_account_id_fkey` FOREIGN KEY (`consumer_account_id`) REFERENCES `consumer_accounts`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `consumer_account_good_favorites` ADD CONSTRAINT `consumer_account_good_favorites_good_id_fkey` FOREIGN KEY (`good_id`) REFERENCES `goods`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `goods` ADD CONSTRAINT `goods_business_activity_id_fkey` FOREIGN KEY (`business_activity_id`) REFERENCES `business_activities`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `goods` ADD CONSTRAINT `goods_category_id_fkey` FOREIGN KEY (`category_id`) REFERENCES `good_categories`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `goods` ADD CONSTRAINT `goods_measure_unit_id_fkey` FOREIGN KEY (`measure_unit_id`) REFERENCES `measure_units`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `goods` ADD CONSTRAINT `goods_sku_id_fkey` FOREIGN KEY (`sku_id`) REFERENCES `stock_keeping_units`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `good_categories` ADD CONSTRAINT `good_categories_complex_id_fkey` FOREIGN KEY (`complex_id`) REFERENCES `complexes`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `good_categories` ADD CONSTRAINT `good_categories_guild_id_fkey` FOREIGN KEY (`guild_id`) REFERENCES `guilds`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `stock_keeping_units` ADD CONSTRAINT `stock_keeping_units_guild_id_fkey` FOREIGN KEY (`guild_id`) REFERENCES `guilds`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `customer_individuals` ADD CONSTRAINT `customer_individuals_business_activity_id_fkey` FOREIGN KEY (`business_activity_id`) REFERENCES `business_activities`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `customer_individuals` ADD CONSTRAINT `customer_individuals_customer_id_fkey` FOREIGN KEY (`customer_id`) REFERENCES `customers`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `customer_legal` ADD CONSTRAINT `customer_legal_business_activity_id_fkey` FOREIGN KEY (`business_activity_id`) REFERENCES `business_activities`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `customer_legal` ADD CONSTRAINT `customer_legal_customer_id_fkey` FOREIGN KEY (`customer_id`) REFERENCES `customers`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `sales_invoices` ADD CONSTRAINT `sales_invoices_consumer_account_id_fkey` FOREIGN KEY (`consumer_account_id`) REFERENCES `consumer_accounts`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `sales_invoices` ADD CONSTRAINT `sales_invoices_customer_id_fkey` FOREIGN KEY (`customer_id`) REFERENCES `customers`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `sales_invoices` ADD CONSTRAINT `sales_invoices_pos_id_fkey` FOREIGN KEY (`pos_id`) REFERENCES `poses`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `sales_invoices` ADD CONSTRAINT `sales_invoices_ref_id_fkey` FOREIGN KEY (`ref_id`) REFERENCES `sales_invoices`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `sales_invoice_items` ADD CONSTRAINT `sales_invoice_items_good_id_fkey` FOREIGN KEY (`good_id`) REFERENCES `goods`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `sales_invoice_items` ADD CONSTRAINT `sales_invoice_items_invoice_id_fkey` FOREIGN KEY (`invoice_id`) REFERENCES `sales_invoices`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `sales_invoice_items` ADD CONSTRAINT `sales_invoice_items_service_id_fkey` FOREIGN KEY (`service_id`) REFERENCES `services`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `sale_invoice_tsp_attempts` ADD CONSTRAINT `sale_invoice_tsp_attempts_invoice_id_fkey` FOREIGN KEY (`invoice_id`) REFERENCES `sales_invoices`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `sales_invoice_payments` ADD CONSTRAINT `sales_invoice_payments_invoice_id_fkey` FOREIGN KEY (`invoice_id`) REFERENCES `sales_invoices`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `sales_invoice_payment_terminal_info` ADD CONSTRAINT `sales_invoice_payment_terminal_info_payment_id_fkey` FOREIGN KEY (`payment_id`) REFERENCES `sales_invoice_payments`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `services` ADD CONSTRAINT `services_category_id_fkey` FOREIGN KEY (`category_id`) REFERENCES `service_categories`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
@@ -1,571 +0,0 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE `admin_accounts` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
`admin_id` VARCHAR(191) NOT NULL,
|
||||
`account_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
UNIQUE INDEX `admin_accounts_account_id_key`(`account_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `admins` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`mobile_number` VARCHAR(191) NOT NULL,
|
||||
`national_code` VARCHAR(191) NULL,
|
||||
`first_name` VARCHAR(191) NOT NULL,
|
||||
`last_name` VARCHAR(191) NOT NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
|
||||
UNIQUE INDEX `admins_mobile_number_key`(`mobile_number`),
|
||||
UNIQUE INDEX `admins_national_code_key`(`national_code`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `accounts` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`username` VARCHAR(191) NOT NULL,
|
||||
`password` VARCHAR(191) NOT NULL,
|
||||
`status` ENUM('ACTIVE', 'SUSPENDED') NOT NULL,
|
||||
`type` ENUM('ADMIN', 'PROVIDER', 'PARTNER', 'CONSUMER') NOT NULL,
|
||||
|
||||
UNIQUE INDEX `accounts_username_key`(`username`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `consumer_accounts` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`role` ENUM('OWNER', 'MANAGER', 'OPERATOR') NOT NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
`consumer_id` VARCHAR(191) NOT NULL,
|
||||
`account_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
UNIQUE INDEX `consumer_accounts_account_id_key`(`account_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `consumers` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`mobile_number` VARCHAR(191) NOT NULL,
|
||||
`first_name` VARCHAR(191) NOT NULL,
|
||||
`last_name` VARCHAR(191) NOT NULL,
|
||||
`status` ENUM('ACTIVE', 'SUSPENDED') NOT NULL DEFAULT 'ACTIVE',
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
|
||||
UNIQUE INDEX `consumers_mobile_number_key`(`mobile_number`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `business_activities` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`name` VARCHAR(191) NOT NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
`guild_id` VARCHAR(191) NOT NULL,
|
||||
`consumer_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `complexes` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`name` VARCHAR(191) NOT NULL,
|
||||
`address` VARCHAR(191) NULL,
|
||||
`tax_id` VARCHAR(191) NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
`business_activity_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `poses` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`name` VARCHAR(191) NOT NULL,
|
||||
`serial` VARCHAR(191) NOT NULL,
|
||||
`model` VARCHAR(191) NULL,
|
||||
`status` ENUM('ACTIVE', 'DISABLED') NOT NULL DEFAULT 'ACTIVE',
|
||||
`pos_type` ENUM('PSP', 'MOBILE', 'WEB', 'API') NOT NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
`complex_id` VARCHAR(191) NOT NULL,
|
||||
`device_id` VARCHAR(191) NULL,
|
||||
`provider_id` VARCHAR(191) NULL,
|
||||
|
||||
UNIQUE INDEX `poses_serial_key`(`serial`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `device_brands` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`name` VARCHAR(191) NOT NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `devices` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`name` VARCHAR(191) NOT NULL,
|
||||
`os_version` VARCHAR(191) NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
`brand_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `licenses` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`starts_at` DATETIME(3) NOT NULL,
|
||||
`expires_at` DATETIME(3) NOT NULL,
|
||||
`status` ENUM('ACTIVE', 'EXPIRED', 'SUSPENDED') NOT NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
`partner_id` VARCHAR(191) NULL,
|
||||
`consumer_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
UNIQUE INDEX `licenses_consumer_id_key`(`consumer_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `partner_accounts` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`role` ENUM('OWNER', 'MANAGER', 'OPERATOR') NOT NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`partner_id` VARCHAR(191) NOT NULL,
|
||||
`account_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
UNIQUE INDEX `partner_accounts_account_id_key`(`account_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `partners` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`name` VARCHAR(191) NOT NULL,
|
||||
`code` VARCHAR(191) NOT NULL,
|
||||
`license_quota` INTEGER NULL DEFAULT 0,
|
||||
`status` ENUM('ACTIVE', 'SUSPENDED') NOT NULL DEFAULT 'ACTIVE',
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
|
||||
UNIQUE INDEX `partners_code_key`(`code`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `permission_consumers` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`consumer_account_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
UNIQUE INDEX `permission_consumers_consumer_account_id_key`(`consumer_account_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `permission_poses` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`role` ENUM('MANAGER', 'OPERATOR') NOT NULL,
|
||||
`pos_id` VARCHAR(191) NOT NULL,
|
||||
`permission_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
UNIQUE INDEX `permission_poses_permission_id_pos_id_key`(`permission_id`, `pos_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `permission_complexes` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`role` ENUM('MANAGER', 'OPERATOR') NOT NULL,
|
||||
`complex_id` VARCHAR(191) NOT NULL,
|
||||
`permission_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
UNIQUE INDEX `permission_complexes_permission_id_complex_id_key`(`permission_id`, `complex_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `permission_business_activities` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`role` ENUM('MANAGER', 'OPERATOR') NOT NULL,
|
||||
`business_id` VARCHAR(191) NOT NULL,
|
||||
`permission_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
UNIQUE INDEX `permission_business_activities_permission_id_business_id_key`(`permission_id`, `business_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `provider_accounts` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`role` ENUM('OWNER', 'MANAGER', 'OPERATOR') NOT NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
`provider_id` VARCHAR(191) NOT NULL,
|
||||
`account_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
UNIQUE INDEX `provider_accounts_account_id_key`(`account_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `providers` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`code` VARCHAR(191) NOT NULL,
|
||||
`status` ENUM('ACTIVE', 'SUSPENDED') NOT NULL DEFAULT 'ACTIVE',
|
||||
`name` VARCHAR(191) NOT NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
|
||||
UNIQUE INDEX `providers_code_key`(`code`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `trigger_logs` (
|
||||
`id` INTEGER NOT NULL AUTO_INCREMENT,
|
||||
`message` TEXT NOT NULL,
|
||||
`createdAt` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`name` TEXT NOT NULL,
|
||||
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `user_devices` (
|
||||
`account_id` VARCHAR(255) NULL,
|
||||
`app_version` VARCHAR(20) NOT NULL,
|
||||
`build_number` VARCHAR(20) NOT NULL,
|
||||
`uuid` VARCHAR(255) NOT NULL,
|
||||
`platform` VARCHAR(100) NOT NULL,
|
||||
`brand` VARCHAR(100) NOT NULL,
|
||||
`model` VARCHAR(100) NOT NULL,
|
||||
`device` VARCHAR(100) NOT NULL,
|
||||
`os_version` VARCHAR(20) NOT NULL,
|
||||
`sdk_version` VARCHAR(20) NOT NULL,
|
||||
`release_number` VARCHAR(20) NOT NULL,
|
||||
`browser_name` VARCHAR(100) NULL,
|
||||
`fcm_token` VARCHAR(100) NULL,
|
||||
|
||||
UNIQUE INDEX `user_devices_uuid_key`(`uuid`),
|
||||
PRIMARY KEY (`uuid`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `customers` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`is_favorite` BOOLEAN NULL DEFAULT false,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
`deleted_at` TIMESTAMP(0) NULL,
|
||||
`type` ENUM('INDIVIDUAL', 'LEGAL', 'UNKNOWN') NOT NULL,
|
||||
`unknown_customer` JSON NULL,
|
||||
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `customer_individuals` (
|
||||
`first_name` VARCHAR(255) NOT NULL,
|
||||
`last_name` VARCHAR(255) NOT NULL,
|
||||
`national_id` CHAR(10) NOT NULL,
|
||||
`postal_code` CHAR(10) NOT NULL,
|
||||
`economic_code` CHAR(10) NULL,
|
||||
`customer_id` VARCHAR(191) NOT NULL,
|
||||
`complex_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
INDEX `customer_individuals_complex_id_idx`(`complex_id`),
|
||||
UNIQUE INDEX `customer_individuals_complex_id_national_id_key`(`complex_id`, `national_id`),
|
||||
PRIMARY KEY (`customer_id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `customer_legal` (
|
||||
`company_name` VARCHAR(255) NOT NULL,
|
||||
`economic_code` CHAR(10) NOT NULL,
|
||||
`registration_number` CHAR(20) NOT NULL,
|
||||
`postal_code` CHAR(10) NOT NULL,
|
||||
`customer_id` VARCHAR(191) NOT NULL,
|
||||
`complex_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
INDEX `customer_legal_complex_id_idx`(`complex_id`),
|
||||
UNIQUE INDEX `customer_legal_complex_id_registration_number_key`(`complex_id`, `registration_number`),
|
||||
PRIMARY KEY (`customer_id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `goods` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`name` VARCHAR(255) NOT NULL,
|
||||
`is_default_guild_good` BOOLEAN NOT NULL DEFAULT false,
|
||||
`sku` VARCHAR(100) NOT NULL,
|
||||
`unit_type` ENUM('COUNT', 'GRAM', 'KILOGRAM', 'MILLILITER', 'LITER', 'METER', 'HOUR') NOT NULL,
|
||||
`pricing_model` ENUM('STANDARD', 'GOLD') NOT NULL,
|
||||
`description` TEXT NULL,
|
||||
`local_sku` VARCHAR(100) NULL,
|
||||
`barcode` VARCHAR(100) NULL,
|
||||
`base_sale_price` DECIMAL(15, 0) NULL DEFAULT 0.00,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
`deleted_at` TIMESTAMP(0) NULL,
|
||||
`complex_id` VARCHAR(191) NULL,
|
||||
`category_id` VARCHAR(191) NULL,
|
||||
|
||||
UNIQUE INDEX `goods_local_sku_key`(`local_sku`),
|
||||
UNIQUE INDEX `goods_barcode_key`(`barcode`),
|
||||
INDEX `goods_category_id_idx`(`category_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `good_categories` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`name` VARCHAR(100) NOT NULL,
|
||||
`description` TEXT NULL,
|
||||
`image_url` VARCHAR(255) NULL,
|
||||
`complex_id` VARCHAR(191) NULL,
|
||||
`is_default_guild_good` BOOLEAN NOT NULL DEFAULT false,
|
||||
`guild_id` VARCHAR(191) NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
`deleted_at` TIMESTAMP(0) NULL,
|
||||
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `guilds` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`name` VARCHAR(191) NOT NULL,
|
||||
`code` VARCHAR(191) NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `sales_invoices` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`code` VARCHAR(100) NOT NULL,
|
||||
`total_amount` DECIMAL(15, 2) NOT NULL,
|
||||
`notes` TEXT NULL,
|
||||
`unknown_customer` JSON NULL,
|
||||
`invoice_date` TIMESTAMP(0) NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
`customer_id` VARCHAR(191) NULL,
|
||||
`account_id` VARCHAR(191) NOT NULL,
|
||||
`pos_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
UNIQUE INDEX `sales_invoices_code_key`(`code`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `sales_invoice_items` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`quantity` DECIMAL(10, 0) NOT NULL,
|
||||
`unit_type` ENUM('COUNT', 'GRAM', 'KILOGRAM', 'MILLILITER', 'LITER', 'METER', 'HOUR') NOT NULL,
|
||||
`unit_price` DECIMAL(15, 2) NOT NULL DEFAULT 0.00,
|
||||
`total_amount` DECIMAL(15, 2) NOT NULL DEFAULT 0.00,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`discount` DECIMAL(15, 2) NOT NULL DEFAULT 0.00,
|
||||
`notes` TEXT NULL,
|
||||
`invoice_id` VARCHAR(191) NOT NULL,
|
||||
`good_id` VARCHAR(191) NULL,
|
||||
`service_id` VARCHAR(191) NULL,
|
||||
`payload` JSON NULL,
|
||||
|
||||
INDEX `sales_invoice_items_invoice_id_good_id_idx`(`invoice_id`, `good_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `sales_invoice_payments` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`invoice_id` VARCHAR(191) NOT NULL,
|
||||
`amount` DECIMAL(15, 2) NOT NULL,
|
||||
`payment_method` ENUM('TERMINAL', 'CASH', 'SET_OFF', 'CARD', 'BANK', 'CHECK', 'OTHER') NOT NULL,
|
||||
`paid_at` DATETIME(3) NOT NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
|
||||
INDEX `sales_invoice_payments_invoice_id_idx`(`invoice_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `services` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`name` VARCHAR(255) NOT NULL,
|
||||
`description` TEXT NULL,
|
||||
`sku` VARCHAR(100) NOT NULL,
|
||||
`local_sku` VARCHAR(100) NULL,
|
||||
`barcode` VARCHAR(100) NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
`deleted_at` TIMESTAMP(0) NULL,
|
||||
`category_id` VARCHAR(191) NULL,
|
||||
`base_sale_price` DECIMAL(15, 0) NOT NULL DEFAULT 0.00,
|
||||
`account_id` VARCHAR(191) NOT NULL,
|
||||
`complex_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
UNIQUE INDEX `services_sku_key`(`sku`),
|
||||
UNIQUE INDEX `services_local_sku_key`(`local_sku`),
|
||||
UNIQUE INDEX `services_barcode_key`(`barcode`),
|
||||
INDEX `services_category_id_idx`(`category_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `service_categories` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`name` VARCHAR(100) NOT NULL,
|
||||
`description` TEXT NULL,
|
||||
`image_url` VARCHAR(255) NULL,
|
||||
`account_id` VARCHAR(191) NOT NULL,
|
||||
`complex_id` VARCHAR(191) NOT NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
`deleted_at` TIMESTAMP(0) NULL,
|
||||
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `admin_accounts` ADD CONSTRAINT `admin_accounts_admin_id_fkey` FOREIGN KEY (`admin_id`) REFERENCES `admins`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `admin_accounts` ADD CONSTRAINT `admin_accounts_account_id_fkey` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `consumer_accounts` ADD CONSTRAINT `consumer_accounts_consumer_id_fkey` FOREIGN KEY (`consumer_id`) REFERENCES `consumers`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `consumer_accounts` ADD CONSTRAINT `consumer_accounts_account_id_fkey` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `business_activities` ADD CONSTRAINT `business_activities_guild_id_fkey` FOREIGN KEY (`guild_id`) REFERENCES `guilds`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `business_activities` ADD CONSTRAINT `business_activities_consumer_id_fkey` FOREIGN KEY (`consumer_id`) REFERENCES `consumers`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `complexes` ADD CONSTRAINT `complexes_business_activity_id_fkey` FOREIGN KEY (`business_activity_id`) REFERENCES `business_activities`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `poses` ADD CONSTRAINT `poses_complex_id_fkey` FOREIGN KEY (`complex_id`) REFERENCES `complexes`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `poses` ADD CONSTRAINT `poses_device_id_fkey` FOREIGN KEY (`device_id`) REFERENCES `devices`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `poses` ADD CONSTRAINT `poses_provider_id_fkey` FOREIGN KEY (`provider_id`) REFERENCES `providers`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `devices` ADD CONSTRAINT `devices_brand_id_fkey` FOREIGN KEY (`brand_id`) REFERENCES `device_brands`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `licenses` ADD CONSTRAINT `licenses_partner_id_fkey` FOREIGN KEY (`partner_id`) REFERENCES `partners`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `licenses` ADD CONSTRAINT `licenses_consumer_id_fkey` FOREIGN KEY (`consumer_id`) REFERENCES `consumers`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `partner_accounts` ADD CONSTRAINT `partner_accounts_partner_id_fkey` FOREIGN KEY (`partner_id`) REFERENCES `partners`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `partner_accounts` ADD CONSTRAINT `partner_accounts_account_id_fkey` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `permission_consumers` ADD CONSTRAINT `permission_consumers_consumer_account_id_fkey` FOREIGN KEY (`consumer_account_id`) REFERENCES `consumer_accounts`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `permission_poses` ADD CONSTRAINT `permission_poses_pos_id_fkey` FOREIGN KEY (`pos_id`) REFERENCES `poses`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `permission_poses` ADD CONSTRAINT `permission_poses_permission_id_fkey` FOREIGN KEY (`permission_id`) REFERENCES `permission_consumers`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `permission_complexes` ADD CONSTRAINT `permission_complexes_complex_id_fkey` FOREIGN KEY (`complex_id`) REFERENCES `complexes`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `permission_complexes` ADD CONSTRAINT `permission_complexes_permission_id_fkey` FOREIGN KEY (`permission_id`) REFERENCES `permission_consumers`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `permission_business_activities` ADD CONSTRAINT `permission_business_activities_business_id_fkey` FOREIGN KEY (`business_id`) REFERENCES `business_activities`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `permission_business_activities` ADD CONSTRAINT `permission_business_activities_permission_id_fkey` FOREIGN KEY (`permission_id`) REFERENCES `permission_consumers`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `provider_accounts` ADD CONSTRAINT `provider_accounts_provider_id_fkey` FOREIGN KEY (`provider_id`) REFERENCES `providers`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `provider_accounts` ADD CONSTRAINT `provider_accounts_account_id_fkey` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `customer_individuals` ADD CONSTRAINT `customer_individuals_customer_id_fkey` FOREIGN KEY (`customer_id`) REFERENCES `customers`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `customer_individuals` ADD CONSTRAINT `customer_individuals_complex_id_fkey` FOREIGN KEY (`complex_id`) REFERENCES `complexes`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `customer_legal` ADD CONSTRAINT `customer_legal_customer_id_fkey` FOREIGN KEY (`customer_id`) REFERENCES `customers`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `customer_legal` ADD CONSTRAINT `customer_legal_complex_id_fkey` FOREIGN KEY (`complex_id`) REFERENCES `complexes`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `goods` ADD CONSTRAINT `goods_category_id_fkey` FOREIGN KEY (`category_id`) REFERENCES `good_categories`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `goods` ADD CONSTRAINT `goods_complex_id_fkey` FOREIGN KEY (`complex_id`) REFERENCES `complexes`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `good_categories` ADD CONSTRAINT `good_categories_guild_id_fkey` FOREIGN KEY (`guild_id`) REFERENCES `guilds`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `good_categories` ADD CONSTRAINT `good_categories_complex_id_fkey` FOREIGN KEY (`complex_id`) REFERENCES `complexes`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `sales_invoices` ADD CONSTRAINT `sales_invoices_customer_id_fkey` FOREIGN KEY (`customer_id`) REFERENCES `customers`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `sales_invoices` ADD CONSTRAINT `sales_invoices_pos_id_fkey` FOREIGN KEY (`pos_id`) REFERENCES `poses`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `sales_invoices` ADD CONSTRAINT `sales_invoices_account_id_fkey` FOREIGN KEY (`account_id`) REFERENCES `consumer_accounts`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `sales_invoice_items` ADD CONSTRAINT `sales_invoice_items_invoice_id_fkey` FOREIGN KEY (`invoice_id`) REFERENCES `sales_invoices`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `sales_invoice_items` ADD CONSTRAINT `sales_invoice_items_good_id_fkey` FOREIGN KEY (`good_id`) REFERENCES `goods`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `sales_invoice_items` ADD CONSTRAINT `sales_invoice_items_service_id_fkey` FOREIGN KEY (`service_id`) REFERENCES `services`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `sales_invoice_payments` ADD CONSTRAINT `sales_invoice_payments_invoice_id_fkey` FOREIGN KEY (`invoice_id`) REFERENCES `sales_invoices`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `services` ADD CONSTRAINT `services_category_id_fkey` FOREIGN KEY (`category_id`) REFERENCES `service_categories`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
@@ -1,50 +0,0 @@
|
||||
-- DropForeignKey
|
||||
ALTER TABLE `permission_business_activities` DROP FOREIGN KEY `permission_business_activities_business_id_fkey`;
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE `permission_business_activities` DROP FOREIGN KEY `permission_business_activities_permission_id_fkey`;
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE `permission_complexes` DROP FOREIGN KEY `permission_complexes_complex_id_fkey`;
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE `permission_complexes` DROP FOREIGN KEY `permission_complexes_permission_id_fkey`;
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE `permission_consumers` DROP FOREIGN KEY `permission_consumers_consumer_account_id_fkey`;
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE `permission_poses` DROP FOREIGN KEY `permission_poses_permission_id_fkey`;
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE `permission_poses` DROP FOREIGN KEY `permission_poses_pos_id_fkey`;
|
||||
|
||||
-- DropIndex
|
||||
DROP INDEX `permission_business_activities_business_id_fkey` ON `permission_business_activities`;
|
||||
|
||||
-- DropIndex
|
||||
DROP INDEX `permission_complexes_complex_id_fkey` ON `permission_complexes`;
|
||||
|
||||
-- DropIndex
|
||||
DROP INDEX `permission_poses_pos_id_fkey` ON `permission_poses`;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `permission_consumers` ADD CONSTRAINT `permission_consumers_consumer_account_id_fkey` FOREIGN KEY (`consumer_account_id`) REFERENCES `consumer_accounts`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `permission_poses` ADD CONSTRAINT `permission_poses_pos_id_fkey` FOREIGN KEY (`pos_id`) REFERENCES `poses`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `permission_poses` ADD CONSTRAINT `permission_poses_permission_id_fkey` FOREIGN KEY (`permission_id`) REFERENCES `permission_consumers`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `permission_complexes` ADD CONSTRAINT `permission_complexes_complex_id_fkey` FOREIGN KEY (`complex_id`) REFERENCES `complexes`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `permission_complexes` ADD CONSTRAINT `permission_complexes_permission_id_fkey` FOREIGN KEY (`permission_id`) REFERENCES `permission_consumers`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `permission_business_activities` ADD CONSTRAINT `permission_business_activities_business_id_fkey` FOREIGN KEY (`business_id`) REFERENCES `business_activities`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `permission_business_activities` ADD CONSTRAINT `permission_business_activities_permission_id_fkey` FOREIGN KEY (`permission_id`) REFERENCES `permission_consumers`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
@@ -1,2 +0,0 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE `goods` ADD COLUMN `image_url` VARCHAR(255) NULL;
|
||||
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the column `consumer_id` on the `licenses` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `expires_at` on the `licenses` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `starts_at` on the `licenses` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `status` on the `licenses` table. All the data in the column will be lost.
|
||||
- A unique constraint covering the columns `[activated_license_id]` on the table `consumers` will be added. If there are existing duplicate values, this will fail.
|
||||
- Added the required column `activation_expires_at` to the `licenses` table without a default value. This is not possible if the table is not empty.
|
||||
- Added the required column `charged_license_transaction_id` to the `licenses` table without a default value. This is not possible if the table is not empty.
|
||||
- Made the column `partner_id` on table `licenses` required. This step will fail if there are existing NULL values in that column.
|
||||
|
||||
*/
|
||||
-- DropForeignKey
|
||||
ALTER TABLE `licenses` DROP FOREIGN KEY `licenses_consumer_id_fkey`;
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE `licenses` DROP FOREIGN KEY `licenses_partner_id_fkey`;
|
||||
|
||||
-- DropIndex
|
||||
DROP INDEX `licenses_consumer_id_key` ON `licenses`;
|
||||
|
||||
-- DropIndex
|
||||
DROP INDEX `licenses_partner_id_fkey` ON `licenses`;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE `consumers` ADD COLUMN `activated_license_id` VARCHAR(191) NULL;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE `licenses` DROP COLUMN `consumer_id`,
|
||||
DROP COLUMN `expires_at`,
|
||||
DROP COLUMN `starts_at`,
|
||||
DROP COLUMN `status`,
|
||||
ADD COLUMN `activation_expires_at` DATETIME(3) NOT NULL,
|
||||
ADD COLUMN `charged_license_transaction_id` VARCHAR(191) NOT NULL,
|
||||
MODIFY `partner_id` VARCHAR(191) NOT NULL;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `activated_licenses` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`starts_at` DATETIME(3) NOT NULL,
|
||||
`expires_at` DATETIME(3) NOT NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
`license_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
UNIQUE INDEX `activated_licenses_id_key`(`id`),
|
||||
UNIQUE INDEX `activated_licenses_license_id_key`(`license_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `charged_license_transactions` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
`partner_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX `consumers_activated_license_id_key` ON `consumers`(`activated_license_id`);
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `consumers` ADD CONSTRAINT `consumers_activated_license_id_fkey` FOREIGN KEY (`activated_license_id`) REFERENCES `activated_licenses`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `licenses` ADD CONSTRAINT `licenses_partner_id_fkey` FOREIGN KEY (`partner_id`) REFERENCES `partners`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `licenses` ADD CONSTRAINT `licenses_charged_license_transaction_id_fkey` FOREIGN KEY (`charged_license_transaction_id`) REFERENCES `charged_license_transactions`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `activated_licenses` ADD CONSTRAINT `activated_licenses_license_id_fkey` FOREIGN KEY (`license_id`) REFERENCES `licenses`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `charged_license_transactions` ADD CONSTRAINT `charged_license_transactions_partner_id_fkey` FOREIGN KEY (`partner_id`) REFERENCES `partners`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the column `activated_license_id` on the `consumers` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `activation_expires_at` on the `licenses` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `partner_id` on the `licenses` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `license_quota` on the `partners` table. All the data in the column will be lost.
|
||||
- Added the required column `consumer_id` to the `activated_licenses` table without a default value. This is not possible if the table is not empty.
|
||||
- Added the required column `activation_expires_at` to the `charged_license_transactions` table without a default value. This is not possible if the table is not empty.
|
||||
|
||||
*/
|
||||
-- DropForeignKey
|
||||
ALTER TABLE `consumers` DROP FOREIGN KEY `consumers_activated_license_id_fkey`;
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE `licenses` DROP FOREIGN KEY `licenses_partner_id_fkey`;
|
||||
|
||||
-- DropIndex
|
||||
DROP INDEX `consumers_activated_license_id_key` ON `consumers`;
|
||||
|
||||
-- DropIndex
|
||||
DROP INDEX `licenses_partner_id_fkey` ON `licenses`;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE `activated_licenses` ADD COLUMN `consumer_id` VARCHAR(191) NOT NULL;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE `charged_license_transactions` ADD COLUMN `activation_expires_at` DATETIME(3) NOT NULL;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE `consumers` DROP COLUMN `activated_license_id`;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE `licenses` DROP COLUMN `activation_expires_at`,
|
||||
DROP COLUMN `partner_id`;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE `partners` DROP COLUMN `license_quota`;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `activated_licenses` ADD CONSTRAINT `activated_licenses_consumer_id_fkey` FOREIGN KEY (`consumer_id`) REFERENCES `consumers`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
-70
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the `user_devices` table. If the table is not empty, all the data it contains will be lost.
|
||||
- A unique constraint covering the columns `[tracking_code]` on the table `charged_license_transactions` will be added. If there are existing duplicate values, this will fail.
|
||||
- Added the required column `tracking_code` to the `charged_license_transactions` table without a default value. This is not possible if the table is not empty.
|
||||
|
||||
*/
|
||||
-- DropTable
|
||||
DROP TABLE `user_devices`;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `consumer_devices` (
|
||||
`uuid` VARCHAR(255) NOT NULL,
|
||||
`app_version` VARCHAR(20) NOT NULL,
|
||||
`build_number` VARCHAR(20) NOT NULL,
|
||||
`platform` VARCHAR(100) NOT NULL,
|
||||
`brand` VARCHAR(100) NOT NULL,
|
||||
`model` VARCHAR(100) NOT NULL,
|
||||
`device` VARCHAR(100) NOT NULL,
|
||||
`os_version` VARCHAR(20) NOT NULL,
|
||||
`sdk_version` VARCHAR(20) NOT NULL,
|
||||
`release_number` VARCHAR(20) NOT NULL,
|
||||
`browser_name` VARCHAR(100) NULL,
|
||||
`fcm_token` VARCHAR(100) NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
`consumer_id` VARCHAR(191) NOT NULL,
|
||||
UNIQUE INDEX `consumer_devices_uuid_key` (`uuid`),
|
||||
PRIMARY KEY (`uuid`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `application_released_info` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`version` VARCHAR(191) NOT NULL,
|
||||
`build_number` VARCHAR(191) NOT NULL,
|
||||
`is_stable` BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
`is_minimum_supported` BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
`type` ENUM('ANDROID', 'IOS') NOT NULL,
|
||||
`notes` JSON NULL,
|
||||
`release_date` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `consumer_devices`
|
||||
ADD CONSTRAINT `consumer_devices_consumer_id_fkey` FOREIGN KEY (`consumer_id`) REFERENCES `consumers` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
ALTER TABLE `charged_license_transactions`
|
||||
ADD COLUMN `tracking_code` VARCHAR(191) NULL;
|
||||
|
||||
UPDATE `charged_license_transactions`
|
||||
SET
|
||||
`tracking_code` = CONCAT(
|
||||
'TRX-',
|
||||
UPPER(
|
||||
REPLACE (`id`, '-', '')
|
||||
)
|
||||
)
|
||||
WHERE
|
||||
`tracking_code` IS NULL
|
||||
OR `tracking_code` = '';
|
||||
|
||||
ALTER TABLE `charged_license_transactions`
|
||||
MODIFY `tracking_code` VARCHAR(191) NOT NULL;
|
||||
|
||||
CREATE UNIQUE INDEX `charged_license_transactions_tracking_code_key` ON `charged_license_transactions` (`tracking_code`);
|
||||
@@ -1,19 +0,0 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the column `is_stable` on the `application_released_info` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `type` on the `application_released_info` table. All the data in the column will be lost.
|
||||
- Added the required column `platform` to the `application_released_info` table without a default value. This is not possible if the table is not empty.
|
||||
- Added the required column `release_type` to the `application_released_info` table without a default value. This is not possible if the table is not empty.
|
||||
- Added the required column `publisher` to the `consumer_devices` table without a default value. This is not possible if the table is not empty.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE `application_released_info` DROP COLUMN `is_stable`,
|
||||
DROP COLUMN `type`,
|
||||
ADD COLUMN `platform` ENUM('ANDROID', 'IOS') NOT NULL,
|
||||
ADD COLUMN `release_type` ENUM('STABLE', 'BETA', 'ALPHA') NOT NULL;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE `consumer_devices` ADD COLUMN `publisher` ENUM('DIRECT', 'CAFE_BAZAR', 'MAYKET') NOT NULL,
|
||||
ADD COLUMN `user_agent` VARCHAR(100) NULL;
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the column `tax_id` on the `complexes` table. All the data in the column will be lost.
|
||||
- A unique constraint covering the columns `[economic_code]` on the table `business_activities` will be added. If there are existing duplicate values, this will fail.
|
||||
- A unique constraint covering the columns `[mobile_number,national_code,partner_id]` on the table `consumers` will be added. If there are existing duplicate values, this will fail.
|
||||
- Added the required column `economic_code` to the `business_activities` table without a default value. This is not possible if the table is not empty.
|
||||
- Added the required column `national_code` to the `consumers` table without a default value. This is not possible if the table is not empty.
|
||||
- Added the required column `partner_id` to the `consumers` table without a default value. This is not possible if the table is not empty.
|
||||
|
||||
*/
|
||||
-- DropIndex
|
||||
DROP INDEX `consumers_mobile_number_key` ON `consumers`;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE `business_activities` ADD COLUMN `economic_code` VARCHAR(191) NOT NULL;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE `complexes` DROP COLUMN `tax_id`;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE `consumers` ADD COLUMN `national_code` VARCHAR(191) NOT NULL,
|
||||
ADD COLUMN `partner_id` VARCHAR(191) NOT NULL;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE `licenses` ADD COLUMN `accounts_limit` INTEGER NOT NULL DEFAULT 3;
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX `business_activities_economic_code_key` ON `business_activities`(`economic_code`);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX `consumers_mobile_number_national_code_partner_id_key` ON `consumers`(`mobile_number`, `national_code`, `partner_id`);
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `consumers` ADD CONSTRAINT `consumers_partner_id_fkey` FOREIGN KEY (`partner_id`) REFERENCES `partners`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
@@ -1,8 +0,0 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- Added the required column `branch_code` to the `complexes` table without a default value. This is not possible if the table is not empty.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE `complexes` ADD COLUMN `branch_code` VARCHAR(191) NOT NULL;
|
||||
@@ -1,151 +0,0 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the column `charged_license_transaction_id` on the `licenses` table. All the data in the column will be lost.
|
||||
- You are about to drop the `activated_licenses` table. If the table is not empty, all the data it contains will be lost.
|
||||
- You are about to drop the `charged_license_transactions` table. If the table is not empty, all the data it contains will be lost.
|
||||
- A unique constraint covering the columns `[mobile_number,partner_id]` on the table `consumers` will be added. If there are existing duplicate values, this will fail.
|
||||
- A unique constraint covering the columns `[national_code,partner_id]` on the table `consumers` will be added. If there are existing duplicate values, this will fail.
|
||||
- Added the required column `charge_transaction_id` to the `licenses` table without a default value. This is not possible if the table is not empty.
|
||||
|
||||
*/
|
||||
-- DropForeignKey
|
||||
ALTER TABLE `activated_licenses` DROP FOREIGN KEY `activated_licenses_consumer_id_fkey`;
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE `activated_licenses` DROP FOREIGN KEY `activated_licenses_license_id_fkey`;
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE `charged_license_transactions` DROP FOREIGN KEY `charged_license_transactions_partner_id_fkey`;
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE `licenses` DROP FOREIGN KEY `licenses_charged_license_transaction_id_fkey`;
|
||||
|
||||
-- DropIndex
|
||||
DROP INDEX `consumers_mobile_number_national_code_partner_id_key` ON `consumers`;
|
||||
|
||||
-- DropIndex
|
||||
DROP INDEX `licenses_charged_license_transaction_id_fkey` ON `licenses`;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE `licenses` DROP COLUMN `charged_license_transaction_id`,
|
||||
ADD COLUMN `charge_transaction_id` VARCHAR(191) NOT NULL;
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE `activated_licenses`;
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE `charged_license_transactions`;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `licenses_activated` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`starts_at` DATETIME(3) NOT NULL,
|
||||
`expires_at` DATETIME(3) NOT NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
`license_id` VARCHAR(191) NOT NULL,
|
||||
`business_activity_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
UNIQUE INDEX `licenses_activated_id_key`(`id`),
|
||||
UNIQUE INDEX `licenses_activated_license_id_key`(`license_id`),
|
||||
UNIQUE INDEX `licenses_activated_business_activity_id_key`(`business_activity_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `license_charged_transactions` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`activation_expires_at` DATETIME(3) NOT NULL,
|
||||
`tracking_code` VARCHAR(191) NOT NULL,
|
||||
`purchased_count` INTEGER NOT NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
`partner_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
UNIQUE INDEX `license_charged_transactions_tracking_code_key`(`tracking_code`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `license_renew` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
`charge_transaction_id` VARCHAR(191) NOT NULL,
|
||||
`activation_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `license_renew_charge_transaction` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`activation_expires_at` DATETIME(3) NOT NULL,
|
||||
`tracking_code` VARCHAR(191) NOT NULL,
|
||||
`purchased_count` INTEGER NOT NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
`partner_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
UNIQUE INDEX `license_renew_charge_transaction_tracking_code_key`(`tracking_code`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `partner_account_quota_charge_transaction` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`purchased_count` INTEGER NOT NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
`partner_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `partner_account_quota_allocation` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
`charge_transaction_id` VARCHAR(191) NOT NULL,
|
||||
`license_id` VARCHAR(191) NULL,
|
||||
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX `consumers_mobile_number_partner_id_key` ON `consumers`(`mobile_number`, `partner_id`);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX `consumers_national_code_partner_id_key` ON `consumers`(`national_code`, `partner_id`);
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `licenses` ADD CONSTRAINT `licenses_charge_transaction_id_fkey` FOREIGN KEY (`charge_transaction_id`) REFERENCES `license_charged_transactions`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `licenses_activated` ADD CONSTRAINT `licenses_activated_license_id_fkey` FOREIGN KEY (`license_id`) REFERENCES `licenses`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `licenses_activated` ADD CONSTRAINT `licenses_activated_business_activity_id_fkey` FOREIGN KEY (`business_activity_id`) REFERENCES `business_activities`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `license_charged_transactions` ADD CONSTRAINT `license_charged_transactions_partner_id_fkey` FOREIGN KEY (`partner_id`) REFERENCES `partners`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `license_renew` ADD CONSTRAINT `license_renew_charge_transaction_id_fkey` FOREIGN KEY (`charge_transaction_id`) REFERENCES `license_renew_charge_transaction`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `license_renew` ADD CONSTRAINT `license_renew_activation_id_fkey` FOREIGN KEY (`activation_id`) REFERENCES `licenses_activated`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `license_renew_charge_transaction` ADD CONSTRAINT `license_renew_charge_transaction_partner_id_fkey` FOREIGN KEY (`partner_id`) REFERENCES `partners`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `partner_account_quota_charge_transaction` ADD CONSTRAINT `partner_account_quota_charge_transaction_partner_id_fkey` FOREIGN KEY (`partner_id`) REFERENCES `partners`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `partner_account_quota_allocation` ADD CONSTRAINT `partner_account_quota_allocation_charge_transaction_id_fkey` FOREIGN KEY (`charge_transaction_id`) REFERENCES `partner_account_quota_charge_transaction`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `partner_account_quota_allocation` ADD CONSTRAINT `partner_account_quota_allocation_license_id_fkey` FOREIGN KEY (`license_id`) REFERENCES `licenses`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
@@ -1,18 +0,0 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- A unique constraint covering the columns `[tracking_code]` on the table `partner_account_quota_charge_transaction` will be added. If there are existing duplicate values, this will fail.
|
||||
- Added the required column `expires_at` to the `license_renew` table without a default value. This is not possible if the table is not empty.
|
||||
- Added the required column `activation_expires_at` to the `partner_account_quota_charge_transaction` table without a default value. This is not possible if the table is not empty.
|
||||
- Added the required column `tracking_code` to the `partner_account_quota_charge_transaction` table without a default value. This is not possible if the table is not empty.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE `license_renew` ADD COLUMN `expires_at` DATETIME(3) NOT NULL;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE `partner_account_quota_charge_transaction` ADD COLUMN `activation_expires_at` DATETIME(3) NOT NULL,
|
||||
ADD COLUMN `tracking_code` VARCHAR(191) NOT NULL;
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX `partner_account_quota_charge_transaction_tracking_code_key` ON `partner_account_quota_charge_transaction`(`tracking_code`);
|
||||
@@ -1,16 +0,0 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the column `serial` on the `poses` table. All the data in the column will be lost.
|
||||
- A unique constraint covering the columns `[serial_number]` on the table `poses` will be added. If there are existing duplicate values, this will fail.
|
||||
|
||||
*/
|
||||
-- DropIndex
|
||||
DROP INDEX `poses_serial_key` ON `poses`;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE `poses` DROP COLUMN `serial`,
|
||||
ADD COLUMN `serial_number` VARCHAR(191) NULL;
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX `poses_serial_number_key` ON `poses`(`serial_number`);
|
||||
@@ -1,20 +0,0 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- A unique constraint covering the columns `[account_id]` on the table `poses` will be added. If there are existing duplicate values, this will fail.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE `licenses` MODIFY `accounts_limit` INTEGER NOT NULL DEFAULT 2;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE `partners` ADD COLUMN `logo_url` VARCHAR(191) NULL;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE `poses` ADD COLUMN `account_id` VARCHAR(191) NULL;
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX `poses_account_id_key` ON `poses`(`account_id`);
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `poses` ADD CONSTRAINT `poses_account_id_fkey` FOREIGN KEY (`account_id`) REFERENCES `consumer_accounts`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the `partner_account_quota_allocation` table. If the table is not empty, all the data it contains will be lost.
|
||||
|
||||
*/
|
||||
-- DropForeignKey
|
||||
ALTER TABLE `partner_account_quota_allocation` DROP FOREIGN KEY `partner_account_quota_allocation_charge_transaction_id_fkey`;
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE `partner_account_quota_allocation` DROP FOREIGN KEY `partner_account_quota_allocation_license_id_fkey`;
|
||||
|
||||
-- DropTable
|
||||
DROP TABLE `partner_account_quota_allocation`;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `partner_account_quota_credit` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
`charge_transaction_id` VARCHAR(191) NOT NULL,
|
||||
`allocation_id` VARCHAR(191) NULL,
|
||||
|
||||
UNIQUE INDEX `partner_account_quota_credit_allocation_id_key`(`allocation_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `license_account_allocation` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`created_at` TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`updated_at` TIMESTAMP(0) NOT NULL,
|
||||
`license_activation_id` VARCHAR(191) NOT NULL,
|
||||
`account_id` VARCHAR(191) NOT NULL,
|
||||
|
||||
UNIQUE INDEX `license_account_allocation_account_id_key`(`account_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `partner_account_quota_credit` ADD CONSTRAINT `partner_account_quota_credit_charge_transaction_id_fkey` FOREIGN KEY (`charge_transaction_id`) REFERENCES `partner_account_quota_charge_transaction`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `partner_account_quota_credit` ADD CONSTRAINT `partner_account_quota_credit_allocation_id_fkey` FOREIGN KEY (`allocation_id`) REFERENCES `license_account_allocation`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `license_account_allocation` ADD CONSTRAINT `license_account_allocation_license_activation_id_fkey` FOREIGN KEY (`license_activation_id`) REFERENCES `licenses_activated`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `license_account_allocation` ADD CONSTRAINT `license_account_allocation_account_id_fkey` FOREIGN KEY (`account_id`) REFERENCES `consumer_accounts`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
@@ -1,30 +0,0 @@
|
||||
-- DropForeignKey
|
||||
ALTER TABLE `license_account_allocation` DROP FOREIGN KEY `license_account_allocation_account_id_fkey`;
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE `license_account_allocation` DROP FOREIGN KEY `license_account_allocation_license_activation_id_fkey`;
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE `partner_account_quota_credit` DROP FOREIGN KEY `partner_account_quota_credit_charge_transaction_id_fkey`;
|
||||
|
||||
-- DropIndex
|
||||
DROP INDEX `license_account_allocation_license_activation_id_fkey` ON `license_account_allocation`;
|
||||
|
||||
-- DropIndex
|
||||
DROP INDEX `partner_account_quota_credit_charge_transaction_id_fkey` ON `partner_account_quota_credit`;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE `license_account_allocation` MODIFY `license_activation_id` VARCHAR(191) NULL,
|
||||
MODIFY `account_id` VARCHAR(191) NULL;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE `partner_account_quota_credit` MODIFY `charge_transaction_id` VARCHAR(191) NULL;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `partner_account_quota_credit` ADD CONSTRAINT `partner_account_quota_credit_charge_transaction_id_fkey` FOREIGN KEY (`charge_transaction_id`) REFERENCES `partner_account_quota_charge_transaction`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `license_account_allocation` ADD CONSTRAINT `license_account_allocation_license_activation_id_fkey` FOREIGN KEY (`license_activation_id`) REFERENCES `licenses_activated`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `license_account_allocation` ADD CONSTRAINT `license_account_allocation_account_id_fkey` FOREIGN KEY (`account_id`) REFERENCES `consumer_accounts`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the column `allocation_id` on the `partner_account_quota_credit` table. All the data in the column will be lost.
|
||||
- A unique constraint covering the columns `[economic_code,consumer_id]` on the table `business_activities` will be added. If there are existing duplicate values, this will fail.
|
||||
- A unique constraint covering the columns `[credit_id]` on the table `license_account_allocation` will be added. If there are existing duplicate values, this will fail.
|
||||
- Made the column `account_id` on table `poses` required. This step will fail if there are existing NULL values in that column.
|
||||
|
||||
*/
|
||||
-- DropForeignKey
|
||||
ALTER TABLE `license_renew` DROP FOREIGN KEY `license_renew_activation_id_fkey`;
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE `partner_account_quota_credit` DROP FOREIGN KEY `partner_account_quota_credit_allocation_id_fkey`;
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE `poses` DROP FOREIGN KEY `poses_account_id_fkey`;
|
||||
|
||||
-- DropIndex
|
||||
DROP INDEX `business_activities_economic_code_key` ON `business_activities`;
|
||||
|
||||
-- DropIndex
|
||||
DROP INDEX `license_renew_activation_id_fkey` ON `license_renew`;
|
||||
|
||||
-- DropIndex
|
||||
DROP INDEX `partner_account_quota_credit_allocation_id_key` ON `partner_account_quota_credit`;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE `license_account_allocation` ADD COLUMN `credit_id` VARCHAR(191) NULL;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE `license_renew` MODIFY `activation_id` VARCHAR(191) NULL;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE `partner_account_quota_credit` DROP COLUMN `allocation_id`;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE `poses` MODIFY `account_id` VARCHAR(191) NOT NULL;
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX `business_activities_economic_code_consumer_id_key` ON `business_activities`(`economic_code`, `consumer_id`);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX `license_account_allocation_credit_id_key` ON `license_account_allocation`(`credit_id`);
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `poses` ADD CONSTRAINT `poses_account_id_fkey` FOREIGN KEY (`account_id`) REFERENCES `consumer_accounts`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `license_renew` ADD CONSTRAINT `license_renew_activation_id_fkey` FOREIGN KEY (`activation_id`) REFERENCES `licenses_activated`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `license_account_allocation` ADD CONSTRAINT `license_account_allocation_credit_id_fkey` FOREIGN KEY (`credit_id`) REFERENCES `partner_account_quota_credit`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- A unique constraint covering the columns `[business_activity_id,postal_code,national_id]` on the table `customer_individuals` will be added. If there are existing duplicate values, this will fail.
|
||||
- A unique constraint covering the columns `[business_activity_id,postal_code,registration_number]` on the table `customer_legal` will be added. If there are existing duplicate values, this will fail.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE `customer_individuals` MODIFY `first_name` VARCHAR(255) NULL,
|
||||
MODIFY `last_name` VARCHAR(255) NULL,
|
||||
MODIFY `national_id` CHAR(10) NULL,
|
||||
MODIFY `mobile_number` CHAR(15) NULL,
|
||||
MODIFY `postal_code` CHAR(10) NULL,
|
||||
MODIFY `economic_code` CHAR(14) NULL;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE `customer_legal` MODIFY `name` VARCHAR(255) NULL,
|
||||
MODIFY `economic_code` CHAR(11) NULL,
|
||||
MODIFY `postal_code` CHAR(10) NULL;
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX `customer_individuals_business_activity_id_postal_code_nation_key` ON `customer_individuals`(`business_activity_id`, `postal_code`, `national_id`);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX `customer_legal_business_activity_id_postal_code_registration_key` ON `customer_legal`(`business_activity_id`, `postal_code`, `registration_number`);
|
||||
@@ -0,0 +1,50 @@
|
||||
-- ALTER TABLE
|
||||
ALTER TABLE `sales_invoices`
|
||||
ADD COLUMN `last_attempt_no` INT NULL,
|
||||
ADD COLUMN `last_tsp_status` ENUM(
|
||||
'NOT_SEND',
|
||||
'QUEUED',
|
||||
'FISCAL_QUEUED',
|
||||
'SEND_FAILURE',
|
||||
'SUCCESS',
|
||||
'FAILURE'
|
||||
) NULL;
|
||||
|
||||
-- INDEX
|
||||
CREATE INDEX `sales_invoices_pos_id_invoice_date_idx`
|
||||
ON `sales_invoices` (`pos_id`, `invoice_date`);
|
||||
|
||||
-- BACKFILL LAST ATTEMPT
|
||||
UPDATE sales_invoices si
|
||||
JOIN (
|
||||
SELECT invoice_id, attempt_no, status
|
||||
FROM (
|
||||
SELECT
|
||||
invoice_id,
|
||||
attempt_no,
|
||||
status,
|
||||
ROW_NUMBER() OVER (
|
||||
PARTITION BY invoice_id
|
||||
ORDER BY created_at DESC
|
||||
) rn
|
||||
FROM sale_invoice_tsp_attempts
|
||||
) t
|
||||
WHERE rn = 1
|
||||
) la ON la.invoice_id = si.id
|
||||
SET
|
||||
si.last_attempt_no = la.attempt_no,
|
||||
si.last_tsp_status = la.status;
|
||||
|
||||
-- SET NOT_SEND FOR NO ATTEMPTS
|
||||
UPDATE sales_invoices si
|
||||
LEFT JOIN sale_invoice_tsp_attempts att
|
||||
ON att.invoice_id = si.id
|
||||
SET
|
||||
si.last_attempt_no = NULL,
|
||||
si.last_tsp_status = 'NOT_SEND'
|
||||
WHERE att.invoice_id IS NULL;
|
||||
|
||||
-- SAFETY FILL
|
||||
UPDATE sales_invoices
|
||||
SET last_tsp_status = 'NOT_SEND'
|
||||
WHERE last_tsp_status IS NULL;
|
||||
@@ -1,53 +1,25 @@
|
||||
model AdminAccount {
|
||||
id String @id @default(ulid())
|
||||
|
||||
id String @id @default(ulid())
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt() @db.Timestamp(0)
|
||||
|
||||
admin_id String
|
||||
admin Admin @relation(fields: [admin_id], references: [id])
|
||||
|
||||
account_id String @unique
|
||||
account Account @relation(fields: [account_id], references: [id])
|
||||
updated_at DateTime @updatedAt @db.Timestamp(0)
|
||||
admin_id String
|
||||
account_id String @unique
|
||||
account Account @relation(fields: [account_id], references: [id], onDelete: Cascade)
|
||||
admin Admin @relation(fields: [admin_id], references: [id])
|
||||
|
||||
@@index([admin_id], map: "admin_accounts_admin_id_fkey")
|
||||
@@map("admin_accounts")
|
||||
}
|
||||
|
||||
model Admin {
|
||||
id String @id @default(ulid())
|
||||
mobile_number String @unique()
|
||||
national_code String? @unique()
|
||||
id String @id @default(ulid())
|
||||
mobile_number String @unique
|
||||
national_code String? @unique
|
||||
first_name String
|
||||
last_name String
|
||||
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt() @db.Timestamp(0)
|
||||
|
||||
adminAccounts AdminAccount[]
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt @db.Timestamp(0)
|
||||
accounts AdminAccount[]
|
||||
|
||||
@@map("admins")
|
||||
}
|
||||
|
||||
// model LegalProfile {
|
||||
// user_id String @id
|
||||
// company_name String
|
||||
// register_no String @unique()
|
||||
// representative_name String?
|
||||
// representative_national_id String?
|
||||
|
||||
// // user User @relation(fields: [user_id], references: [id])
|
||||
|
||||
// @@map("legal_profiles")
|
||||
// }
|
||||
|
||||
// model IndividualProfile {
|
||||
// user_id String @id
|
||||
// national_code String @unique()
|
||||
// first_name String
|
||||
// last_name String
|
||||
// birth_date DateTime?
|
||||
// mobile_number String
|
||||
// // user User @relation(fields: [user_id], references: [id])
|
||||
|
||||
// @@map("individual_profiles")
|
||||
// }
|
||||
|
||||
@@ -1,44 +1,13 @@
|
||||
model Account {
|
||||
id String @id @default(ulid())
|
||||
username String @unique()
|
||||
password String
|
||||
status AccountStatus
|
||||
type AccountType
|
||||
|
||||
id String @id @default(ulid())
|
||||
username String @unique
|
||||
password String
|
||||
status AccountStatus
|
||||
type AccountType
|
||||
admin_account AdminAccount?
|
||||
provider_account ProviderAccount?
|
||||
partner_account PartnerAccount?
|
||||
consumer_account ConsumerAccount?
|
||||
|
||||
// tokens Token[]
|
||||
// refresh_tokens RefreshToken[]
|
||||
partner_account PartnerAccount?
|
||||
provider_account ProviderAccount?
|
||||
|
||||
@@map("accounts")
|
||||
}
|
||||
|
||||
// model Token {
|
||||
// id String @id @d @uniqueefault(ulid())
|
||||
// token String @unique
|
||||
// type TokenType
|
||||
// created_at DateTime @default(now())
|
||||
// expires_at DateTime
|
||||
|
||||
// account_id String
|
||||
// account Account @relation(fields: [account_id], references: [id])
|
||||
|
||||
// @@unique([type, account_id])
|
||||
// @@map("tokens")
|
||||
// }
|
||||
|
||||
// model VerificationCode {
|
||||
// id String @id @default(ulid())
|
||||
// code String
|
||||
// is_used Boolean @default(false)
|
||||
// created_at DateTime @default(now())
|
||||
// expires_at DateTime
|
||||
|
||||
// account_id String
|
||||
// account Account @relation(fields: [account_id], references: [id])
|
||||
|
||||
// @@map("verification_codes")
|
||||
// }
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
model ConsumerAccount {
|
||||
id String @id @default(ulid())
|
||||
role ConsumerRole
|
||||
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt() @db.Timestamp(0)
|
||||
|
||||
consumer_id String
|
||||
consumer Consumer @relation(fields: [consumer_id], references: [id])
|
||||
|
||||
account_id String @unique()
|
||||
account Account @relation(fields: [account_id], references: [id])
|
||||
|
||||
pos Pos?
|
||||
permission PermissionConsumer?
|
||||
account_allocation LicenseAccountAllocation?
|
||||
sales_invoices SalesInvoice[]
|
||||
|
||||
@@map("consumer_accounts")
|
||||
}
|
||||
|
||||
model Consumer {
|
||||
id String @id @default(ulid())
|
||||
mobile_number String
|
||||
national_code String
|
||||
first_name String
|
||||
last_name String
|
||||
status ConsumerStatus @default(ACTIVE)
|
||||
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt() @db.Timestamp(0)
|
||||
|
||||
partner_id String
|
||||
partner Partner @relation(fields: [partner_id], references: [id])
|
||||
|
||||
consumer_accounts ConsumerAccount[]
|
||||
business_activities BusinessActivity[]
|
||||
consumer_devices ConsumerDevices[]
|
||||
|
||||
@@unique([mobile_number, partner_id])
|
||||
@@unique([national_code, partner_id])
|
||||
@@map("consumers")
|
||||
}
|
||||
|
||||
model BusinessActivity {
|
||||
id String @id @default(ulid())
|
||||
economic_code String
|
||||
name String
|
||||
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt() @db.Timestamp(0)
|
||||
|
||||
guild_id String
|
||||
guild Guild @relation(fields: [guild_id], references: [id])
|
||||
|
||||
consumer_id String
|
||||
consumer Consumer @relation(fields: [consumer_id], references: [id])
|
||||
|
||||
complexes Complex[]
|
||||
permission_businesses PermissionBusiness[]
|
||||
license_activation LicenseActivation?
|
||||
|
||||
@@unique([economic_code, consumer_id])
|
||||
@@map("business_activities")
|
||||
}
|
||||
|
||||
model Complex {
|
||||
id String @id @default(ulid())
|
||||
name String
|
||||
branch_code String
|
||||
address String?
|
||||
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt() @db.Timestamp(0)
|
||||
|
||||
business_activity_id String
|
||||
|
||||
business_activity BusinessActivity @relation(fields: [business_activity_id], references: [id])
|
||||
|
||||
pos_list Pos[]
|
||||
goods Good[]
|
||||
good_categories GoodCategory[]
|
||||
permission_complexes PermissionComplex[]
|
||||
customer_individuals CustomerIndividual[]
|
||||
customer_legals CustomerLegal[]
|
||||
|
||||
@@map("complexes")
|
||||
}
|
||||
|
||||
model Pos {
|
||||
id String @id @default(ulid())
|
||||
name String
|
||||
model String?
|
||||
serial_number String? @unique()
|
||||
status POSStatus @default(ACTIVE)
|
||||
pos_type POSType
|
||||
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt() @db.Timestamp(0)
|
||||
|
||||
complex_id String
|
||||
complex Complex @relation(fields: [complex_id], references: [id])
|
||||
|
||||
device_id String?
|
||||
device Device? @relation(fields: [device_id], references: [id])
|
||||
|
||||
provider_id String?
|
||||
provider Provider? @relation(fields: [provider_id], references: [id])
|
||||
|
||||
account_id String @unique
|
||||
account ConsumerAccount @relation(fields: [account_id], references: [id])
|
||||
|
||||
permission_pos PermissionPos[]
|
||||
sales_invoices SalesInvoice[]
|
||||
|
||||
@@map("poses")
|
||||
}
|
||||
@@ -1,27 +1,23 @@
|
||||
model DeviceBrand {
|
||||
id String @id @default(ulid())
|
||||
name String
|
||||
|
||||
id String @id @default(ulid())
|
||||
name String
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt() @db.Timestamp(0)
|
||||
|
||||
devices Device[]
|
||||
updated_at DateTime @updatedAt @db.Timestamp(0)
|
||||
devices Device[]
|
||||
|
||||
@@map("device_brands")
|
||||
}
|
||||
|
||||
model Device {
|
||||
id String @id @default(ulid())
|
||||
id String @id @default(ulid())
|
||||
name String
|
||||
os_version String?
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt @db.Timestamp(0)
|
||||
brand_id String
|
||||
brand DeviceBrand @relation(fields: [brand_id], references: [id])
|
||||
poses Pos[]
|
||||
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt() @db.Timestamp(0)
|
||||
|
||||
brand_id String
|
||||
|
||||
brand DeviceBrand @relation(fields: [brand_id], references: [id])
|
||||
poses Pos[]
|
||||
|
||||
@@index([brand_id])
|
||||
@@map("devices")
|
||||
}
|
||||
|
||||
@@ -1,133 +1,115 @@
|
||||
model LicenseChargeTransaction {
|
||||
id String @id @default(ulid())
|
||||
id String @id @default(ulid())
|
||||
activation_expires_at DateTime
|
||||
tracking_code String @unique()
|
||||
tracking_code String @unique
|
||||
purchased_count Int
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt @db.Timestamp(0)
|
||||
partner_id String
|
||||
partner Partner @relation(fields: [partner_id], references: [id])
|
||||
licenses License[]
|
||||
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt() @db.Timestamp(0)
|
||||
|
||||
partner_id String
|
||||
partner Partner @relation(fields: [partner_id], references: [id])
|
||||
|
||||
licenses License[]
|
||||
|
||||
@@index([partner_id])
|
||||
@@map("license_charged_transactions")
|
||||
}
|
||||
|
||||
model License {
|
||||
id String @id @default(ulid())
|
||||
accounts_limit Int @default(2)
|
||||
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt() @db.Timestamp(0)
|
||||
|
||||
id String @id @default(ulid())
|
||||
accounts_limit Int @default(2)
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt @db.Timestamp(0)
|
||||
charge_transaction_id String
|
||||
charge_transaction LicenseChargeTransaction @relation(fields: [charge_transaction_id], references: [id])
|
||||
activation LicenseActivation?
|
||||
|
||||
activation LicenseActivation?
|
||||
|
||||
@@index([charge_transaction_id])
|
||||
@@map("licenses")
|
||||
}
|
||||
|
||||
model LicenseActivation {
|
||||
id String @id @unique() @default(ulid())
|
||||
starts_at DateTime
|
||||
expires_at DateTime
|
||||
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt() @db.Timestamp(0)
|
||||
|
||||
license_id String @unique
|
||||
license License @relation(fields: [license_id], references: [id])
|
||||
|
||||
business_activity_id String @unique
|
||||
business_activity BusinessActivity @relation(fields: [business_activity_id], references: [id])
|
||||
|
||||
license_renews LicenseRenew[]
|
||||
account_allocations LicenseAccountAllocation[]
|
||||
id String @id @unique @default(ulid())
|
||||
starts_at DateTime
|
||||
expires_at DateTime
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt @db.Timestamp(0)
|
||||
license_id String @unique
|
||||
business_activity_id String @unique
|
||||
account_allocations LicenseAccountAllocation[]
|
||||
license_renews LicenseRenew[]
|
||||
business_activity BusinessActivity @relation(fields: [business_activity_id], references: [id])
|
||||
license License @relation(fields: [license_id], references: [id])
|
||||
|
||||
@@map("licenses_activated")
|
||||
}
|
||||
|
||||
model LicenseRenewChargeTransaction {
|
||||
id String @id @default(ulid())
|
||||
id String @id @default(ulid())
|
||||
activation_expires_at DateTime
|
||||
tracking_code String @unique()
|
||||
tracking_code String @unique
|
||||
purchased_count Int
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt @db.Timestamp(0)
|
||||
partner_id String
|
||||
license_renews LicenseRenew[]
|
||||
partner Partner @relation(fields: [partner_id], references: [id])
|
||||
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt() @db.Timestamp(0)
|
||||
|
||||
partner_id String
|
||||
partner Partner @relation(fields: [partner_id], references: [id])
|
||||
|
||||
license_renews LicenseRenew[]
|
||||
|
||||
@@index([partner_id])
|
||||
@@map("license_renew_charge_transaction")
|
||||
}
|
||||
|
||||
model LicenseRenew {
|
||||
id String @id @default(ulid())
|
||||
expires_at DateTime
|
||||
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt() @db.Timestamp(0)
|
||||
|
||||
id String @id @default(ulid())
|
||||
expires_at DateTime
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt @db.Timestamp(0)
|
||||
charge_transaction_id String
|
||||
activation_id String?
|
||||
activation LicenseActivation? @relation(fields: [activation_id], references: [id])
|
||||
charge_transaction LicenseRenewChargeTransaction @relation(fields: [charge_transaction_id], references: [id])
|
||||
|
||||
activation_id String?
|
||||
activation LicenseActivation? @relation(fields: [activation_id], references: [id])
|
||||
|
||||
@@index([activation_id])
|
||||
@@index([charge_transaction_id])
|
||||
@@map("license_renew")
|
||||
}
|
||||
|
||||
model PartnerAccountQuotaChargeTransaction {
|
||||
id String @id @default(ulid())
|
||||
id String @id @default(ulid())
|
||||
activation_expires_at DateTime
|
||||
tracking_code String @unique()
|
||||
tracking_code String @unique
|
||||
purchased_count Int
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt @db.Timestamp(0)
|
||||
partner_id String
|
||||
partner Partner @relation(fields: [partner_id], references: [id])
|
||||
credits PartnerAccountQuotaCredit[]
|
||||
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt() @db.Timestamp(0)
|
||||
|
||||
partner_id String
|
||||
partner Partner @relation(fields: [partner_id], references: [id])
|
||||
|
||||
credits PartnerAccountQuotaCredit[]
|
||||
|
||||
@@index([partner_id])
|
||||
@@map("partner_account_quota_charge_transaction")
|
||||
}
|
||||
|
||||
model PartnerAccountQuotaCredit {
|
||||
id String @id @default(ulid())
|
||||
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt() @db.Timestamp(0)
|
||||
|
||||
id String @id @default(ulid())
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt @db.Timestamp(0)
|
||||
charge_transaction_id String?
|
||||
allocation LicenseAccountAllocation?
|
||||
charge_transaction PartnerAccountQuotaChargeTransaction? @relation(fields: [charge_transaction_id], references: [id])
|
||||
|
||||
allocation LicenseAccountAllocation?
|
||||
|
||||
@@index([charge_transaction_id])
|
||||
@@map("partner_account_quota_credit")
|
||||
}
|
||||
|
||||
model LicenseAccountAllocation {
|
||||
id String @id @default(ulid())
|
||||
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt() @db.Timestamp(0)
|
||||
|
||||
id String @id @default(ulid())
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt @db.Timestamp(0)
|
||||
license_activation_id String?
|
||||
license_activation LicenseActivation? @relation(fields: [license_activation_id], references: [id])
|
||||
|
||||
account_id String? @unique
|
||||
account ConsumerAccount? @relation(fields: [account_id], references: [id])
|
||||
|
||||
credit_id String? @unique
|
||||
credit PartnerAccountQuotaCredit? @relation(fields: [credit_id], references: [id])
|
||||
account_id String? @unique
|
||||
credit_id String? @unique
|
||||
account ConsumerAccount? @relation(fields: [account_id], references: [id])
|
||||
credit PartnerAccountQuotaCredit? @relation(fields: [credit_id], references: [id])
|
||||
license_activation LicenseActivation? @relation(fields: [license_activation_id], references: [id])
|
||||
|
||||
@@index([license_activation_id])
|
||||
@@map("license_account_allocation")
|
||||
}
|
||||
|
||||
@@ -1,34 +1,32 @@
|
||||
model PartnerAccount {
|
||||
id String @id @default(ulid())
|
||||
role PartnerRole
|
||||
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @default(now()) @updatedAt @db.Timestamp(0)
|
||||
|
||||
id String @id @default(ulid())
|
||||
role PartnerRole
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @default(now()) @updatedAt @db.Timestamp(0)
|
||||
partner_id String
|
||||
partner Partner @relation(fields: [partner_id], references: [id])
|
||||
|
||||
account_id String @unique
|
||||
account Account @relation(fields: [account_id], references: [id])
|
||||
account_id String @unique
|
||||
account Account @relation(fields: [account_id], references: [id], onDelete: Cascade)
|
||||
partner Partner @relation(fields: [partner_id], references: [id])
|
||||
|
||||
@@index([partner_id], map: "partner_accounts_partner_id_fkey")
|
||||
@@map("partner_accounts")
|
||||
}
|
||||
|
||||
model Partner {
|
||||
id String @id @default(ulid())
|
||||
name String
|
||||
code String @unique()
|
||||
status PartnerStatus @default(ACTIVE)
|
||||
logo_url String?
|
||||
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @default(now()) @updatedAt @db.Timestamp(0)
|
||||
|
||||
consumers Consumer[]
|
||||
partner_accounts PartnerAccount[]
|
||||
id String @id @default(ulid())
|
||||
name String
|
||||
code String @unique
|
||||
status PartnerStatus @default(ACTIVE)
|
||||
logo_url String?
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @default(now()) @updatedAt @db.Timestamp(0)
|
||||
tsp_provider TspProviderType @default(NAMA)
|
||||
consumers_individual ConsumerIndividual[]
|
||||
consumers_legal ConsumerLegal[]
|
||||
license_charge_transactions LicenseChargeTransaction[]
|
||||
account_quota_charge_transactions PartnerAccountQuotaChargeTransaction[]
|
||||
license_renew_charge_transactions LicenseRenewChargeTransaction[]
|
||||
account_quota_charge_transactions PartnerAccountQuotaChargeTransaction[]
|
||||
accounts PartnerAccount[]
|
||||
|
||||
@@map("partners")
|
||||
}
|
||||
|
||||
@@ -1,54 +1,49 @@
|
||||
model PermissionConsumer {
|
||||
id String @id @default(ulid())
|
||||
|
||||
consumer_account_id String @unique
|
||||
consumer_account ConsumerAccount @relation(fields: [consumer_account_id], references: [id], onDelete: Cascade)
|
||||
|
||||
pos_permissions PermissionPos[]
|
||||
complex_permissions PermissionComplex[]
|
||||
id String @id @default(ulid())
|
||||
consumer_account_id String @unique
|
||||
business_permissions PermissionBusiness[]
|
||||
complex_permissions PermissionComplex[]
|
||||
consumer_account ConsumerAccount @relation(fields: [consumer_account_id], references: [id], onDelete: Cascade)
|
||||
pos_permissions PermissionPos[]
|
||||
|
||||
@@map("permission_consumers")
|
||||
}
|
||||
|
||||
model PermissionPos {
|
||||
id String @id @default(ulid())
|
||||
role POSRole
|
||||
|
||||
id String @id @default(ulid())
|
||||
role POSRole
|
||||
pos_id String
|
||||
permission_id String
|
||||
|
||||
pos Pos @relation(fields: [pos_id], references: [id], onDelete: Cascade)
|
||||
permission PermissionConsumer @relation(fields: [permission_id], references: [id], onDelete: Cascade)
|
||||
permission PermissionConsumer @relation(fields: [permission_id], references: [id], onDelete: Cascade)
|
||||
pos Pos @relation(fields: [pos_id], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([permission_id, pos_id])
|
||||
@@index([pos_id], map: "permission_poses_pos_id_fkey")
|
||||
@@map("permission_poses")
|
||||
}
|
||||
|
||||
model PermissionComplex {
|
||||
id String @id @default(ulid())
|
||||
role ComplexRole
|
||||
|
||||
id String @id @default(ulid())
|
||||
role ComplexRole
|
||||
complex_id String
|
||||
permission_id String
|
||||
|
||||
complex Complex @relation(fields: [complex_id], references: [id], onDelete: Cascade)
|
||||
permission PermissionConsumer @relation(fields: [permission_id], references: [id], onDelete: Cascade)
|
||||
complex Complex @relation(fields: [complex_id], references: [id], onDelete: Cascade)
|
||||
permission PermissionConsumer @relation(fields: [permission_id], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([permission_id, complex_id])
|
||||
@@index([complex_id], map: "permission_complexes_complex_id_fkey")
|
||||
@@map("permission_complexes")
|
||||
}
|
||||
|
||||
model PermissionBusiness {
|
||||
id String @id @default(ulid())
|
||||
role BusinessRole
|
||||
|
||||
id String @id @default(ulid())
|
||||
role BusinessRole
|
||||
business_id String
|
||||
permission_id String
|
||||
|
||||
business BusinessActivity @relation(fields: [business_id], references: [id], onDelete: Cascade)
|
||||
permission PermissionConsumer @relation(fields: [permission_id], references: [id], onDelete: Cascade)
|
||||
business BusinessActivity @relation(fields: [business_id], references: [id], onDelete: Cascade)
|
||||
permission PermissionConsumer @relation(fields: [permission_id], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([permission_id, business_id])
|
||||
@@index([business_id], map: "permission_business_activities_business_id_fkey")
|
||||
@@map("permission_business_activities")
|
||||
}
|
||||
|
||||
@@ -1,30 +1,26 @@
|
||||
model ProviderAccount {
|
||||
id String @id @default(ulid())
|
||||
role ProviderRole
|
||||
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt() @db.Timestamp(0)
|
||||
|
||||
id String @id @default(ulid())
|
||||
role ProviderRole
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt @db.Timestamp(0)
|
||||
provider_id String
|
||||
provider Provider @relation(fields: [provider_id], references: [id])
|
||||
|
||||
account_id String @unique
|
||||
account Account @relation(fields: [account_id], references: [id])
|
||||
account_id String @unique
|
||||
account Account @relation(fields: [account_id], references: [id], onDelete: Cascade)
|
||||
provider Provider @relation(fields: [provider_id], references: [id])
|
||||
|
||||
@@index([provider_id], map: "provider_accounts_provider_id_fkey")
|
||||
@@map("provider_accounts")
|
||||
}
|
||||
|
||||
model Provider {
|
||||
id String @id @default(ulid())
|
||||
code String @unique()
|
||||
status PartnerStatus @default(ACTIVE)
|
||||
name String
|
||||
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt @db.Timestamp(0)
|
||||
|
||||
pos_list Pos[]
|
||||
provider_accounts ProviderAccount[]
|
||||
id String @id @default(ulid())
|
||||
code String @unique
|
||||
status PartnerStatus @default(ACTIVE)
|
||||
name String
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt @db.Timestamp(0)
|
||||
pos_list Pos[]
|
||||
accounts ProviderAccount[]
|
||||
|
||||
@@map("providers")
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
model ConsumerAccountDevice {
|
||||
id String @id @default(ulid())
|
||||
device_id String @unique
|
||||
device_name String?
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt @db.Timestamp(0)
|
||||
consumer_account_id String @unique
|
||||
consumer_account ConsumerAccount @relation(fields: [consumer_account_id], references: [id])
|
||||
|
||||
@@index([consumer_account_id])
|
||||
@@map("consumer_account_device")
|
||||
}
|
||||
@@ -1,24 +1 @@
|
||||
model ConsumerDevices {
|
||||
uuid String @id @unique() @db.VarChar(255)
|
||||
app_version String @db.VarChar(20)
|
||||
build_number String @db.VarChar(20)
|
||||
platform String @db.VarChar(100)
|
||||
brand String @db.VarChar(100)
|
||||
model String @db.VarChar(100)
|
||||
device String @db.VarChar(100)
|
||||
publisher ApplicationPublisher
|
||||
os_version String @db.VarChar(20)
|
||||
sdk_version String @db.VarChar(20)
|
||||
release_number String @db.VarChar(20)
|
||||
user_agent String? @db.VarChar(100)
|
||||
browser_name String? @db.VarChar(100)
|
||||
fcm_token String? @db.VarChar(100)
|
||||
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt() @db.Timestamp(0)
|
||||
|
||||
consumer_id String
|
||||
consumer Consumer @relation(fields: [consumer_id], references: [id])
|
||||
|
||||
@@map("consumer_devices")
|
||||
}
|
||||
|
||||
@@ -6,11 +6,9 @@ model ApplicationReleasedInfo {
|
||||
release_type ApplicationReleaseType
|
||||
platform ApplicationPlatform
|
||||
notes Json?
|
||||
|
||||
release_date DateTime @default(now()) @db.Timestamp(0)
|
||||
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt() @db.Timestamp(0)
|
||||
release_date DateTime @default(now()) @db.Timestamp(0)
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt @db.Timestamp(0)
|
||||
|
||||
@@map("application_released_info")
|
||||
}
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
model ConsumerAccount {
|
||||
id String @id @default(ulid())
|
||||
role ConsumerRole
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt @db.Timestamp(0)
|
||||
consumer_id String
|
||||
account_id String @unique
|
||||
account_device ConsumerAccountDevice?
|
||||
consumer_account_good_favorites ConsumerAccountGoodFavorite[]
|
||||
account Account @relation(fields: [account_id], references: [id])
|
||||
consumer Consumer @relation(fields: [consumer_id], references: [id])
|
||||
account_allocation LicenseAccountAllocation?
|
||||
permission PermissionConsumer?
|
||||
pos Pos?
|
||||
sales_invoices SalesInvoice[]
|
||||
|
||||
@@index([consumer_id], map: "consumer_accounts_consumer_id_fkey")
|
||||
@@map("consumer_accounts")
|
||||
}
|
||||
|
||||
model Consumer {
|
||||
id String @id @default(ulid())
|
||||
type ConsumerType
|
||||
status ConsumerStatus @default(ACTIVE)
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt @db.Timestamp(0)
|
||||
business_activities BusinessActivity[]
|
||||
accounts ConsumerAccount[]
|
||||
individual ConsumerIndividual?
|
||||
legal ConsumerLegal?
|
||||
|
||||
@@map("consumers")
|
||||
}
|
||||
|
||||
model ConsumerIndividual {
|
||||
first_name String
|
||||
last_name String
|
||||
mobile_number String
|
||||
national_code String
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt @db.Timestamp(0)
|
||||
partner_id String
|
||||
consumer_id String @id
|
||||
consumer Consumer @relation(fields: [consumer_id], references: [id], onDelete: Cascade)
|
||||
partner Partner @relation(fields: [partner_id], references: [id])
|
||||
|
||||
@@unique([mobile_number, consumer_id])
|
||||
@@unique([partner_id, national_code])
|
||||
@@map("consumers_individual")
|
||||
}
|
||||
|
||||
model ConsumerLegal {
|
||||
name String
|
||||
registration_code String
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt @db.Timestamp(0)
|
||||
partner_id String
|
||||
consumer_id String @id
|
||||
consumer Consumer @relation(fields: [consumer_id], references: [id], onDelete: Cascade)
|
||||
partner Partner @relation(fields: [partner_id], references: [id])
|
||||
|
||||
@@unique([partner_id, registration_code])
|
||||
@@map("consumers_legal")
|
||||
}
|
||||
|
||||
model BusinessActivity {
|
||||
id String @id @default(ulid())
|
||||
economic_code String
|
||||
name String
|
||||
fiscal_id String
|
||||
partner_token String
|
||||
invoice_number_sequence Decimal @default(1) @db.Decimal(20, 0)
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt @db.Timestamp(0)
|
||||
guild_id String
|
||||
consumer_id String
|
||||
consumer Consumer @relation(fields: [consumer_id], references: [id])
|
||||
guild Guild @relation(fields: [guild_id], references: [id])
|
||||
complexes Complex[]
|
||||
customer_individuals CustomerIndividual[]
|
||||
customer_legals CustomerLegal[]
|
||||
goods Good[]
|
||||
license_activation LicenseActivation?
|
||||
permission_businesses PermissionBusiness[]
|
||||
|
||||
@@unique([economic_code, consumer_id])
|
||||
@@index([consumer_id], map: "business_activities_consumer_id_fkey")
|
||||
@@index([guild_id], map: "business_activities_guild_id_fkey")
|
||||
@@map("business_activities")
|
||||
}
|
||||
|
||||
model Complex {
|
||||
id String @id @default(ulid())
|
||||
name String
|
||||
branch_code String
|
||||
address String?
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt @db.Timestamp(0)
|
||||
business_activity_id String
|
||||
business_activity BusinessActivity @relation(fields: [business_activity_id], references: [id])
|
||||
good_categories GoodCategory[]
|
||||
permission_complexes PermissionComplex[]
|
||||
pos_list Pos[]
|
||||
|
||||
@@index([business_activity_id], map: "complexes_business_activity_id_fkey")
|
||||
@@map("complexes")
|
||||
}
|
||||
|
||||
model Pos {
|
||||
id String @id @default(ulid())
|
||||
name String
|
||||
model String?
|
||||
serial_number String? @unique
|
||||
status POSStatus @default(ACTIVE)
|
||||
pos_type POSType
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt @db.Timestamp(0)
|
||||
complex_id String
|
||||
device_id String?
|
||||
provider_id String?
|
||||
account_id String @unique
|
||||
permission_pos PermissionPos[]
|
||||
account ConsumerAccount @relation(fields: [account_id], references: [id])
|
||||
complex Complex @relation(fields: [complex_id], references: [id])
|
||||
device Device? @relation(fields: [device_id], references: [id])
|
||||
provider Provider? @relation(fields: [provider_id], references: [id])
|
||||
sales_invoices SalesInvoice[]
|
||||
|
||||
@@index([complex_id], map: "poses_complex_id_fkey")
|
||||
@@index([device_id], map: "poses_device_id_fkey")
|
||||
@@index([provider_id], map: "poses_provider_id_fkey")
|
||||
@@map("poses")
|
||||
}
|
||||
|
||||
model ConsumerAccountGoodFavorite {
|
||||
created_at DateTime @default(now())
|
||||
consumer_account_id String
|
||||
good_id String
|
||||
consumer_account ConsumerAccount @relation(fields: [consumer_account_id], references: [id], onDelete: Cascade)
|
||||
good Good @relation(fields: [good_id], references: [id], onDelete: Cascade)
|
||||
|
||||
@@id([consumer_account_id, good_id])
|
||||
@@index([good_id])
|
||||
@@index([consumer_account_id])
|
||||
@@map("consumer_account_good_favorites")
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
model Good {
|
||||
id String @id @default(ulid())
|
||||
name String @db.VarChar(255)
|
||||
is_default_guild_good Boolean @default(false)
|
||||
pricing_model GoodPricingModel
|
||||
description String? @db.Text
|
||||
local_sku String? @unique @db.VarChar(100)
|
||||
barcode String? @unique @db.VarChar(100)
|
||||
base_sale_price Decimal? @default(0) @db.Decimal(15, 0)
|
||||
image_url String? @db.VarChar(255)
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt @db.Timestamp(0)
|
||||
deleted_at DateTime? @db.Timestamp(0)
|
||||
sku_id String
|
||||
measure_unit_id String
|
||||
category_id String?
|
||||
business_activity_id String?
|
||||
consumer_account_good_favorites ConsumerAccountGoodFavorite[]
|
||||
business_activity BusinessActivity? @relation(fields: [business_activity_id], references: [id])
|
||||
category GoodCategory? @relation(fields: [category_id], references: [id])
|
||||
measure_unit MeasureUnits @relation(fields: [measure_unit_id], references: [id])
|
||||
sku StockKeepingUnits @relation(fields: [sku_id], references: [id])
|
||||
sales_invoice_items SalesInvoiceItem[]
|
||||
|
||||
@@index([category_id])
|
||||
@@index([business_activity_id], map: "goods_business_activity_id_fkey")
|
||||
@@index([measure_unit_id], map: "goods_measure_unit_id_fkey")
|
||||
@@index([sku_id], map: "goods_sku_id_fkey")
|
||||
@@map("goods")
|
||||
}
|
||||
|
||||
model GoodCategory {
|
||||
id String @id @default(ulid())
|
||||
name String @db.VarChar(100)
|
||||
description String? @db.Text
|
||||
image_url String? @db.VarChar(255)
|
||||
complex_id String?
|
||||
is_default_guild_good Boolean @default(false)
|
||||
guild_id String?
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt @db.Timestamp(0)
|
||||
deleted_at DateTime? @db.Timestamp(0)
|
||||
complex Complex? @relation(fields: [complex_id], references: [id])
|
||||
guild Guild? @relation(fields: [guild_id], references: [id])
|
||||
goods Good[]
|
||||
|
||||
@@index([complex_id], map: "good_categories_complex_id_fkey")
|
||||
@@index([guild_id], map: "good_categories_guild_id_fkey")
|
||||
@@map("good_categories")
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
model Guild {
|
||||
id String @id @default(ulid())
|
||||
name String
|
||||
invoice_template InvoiceTemplateType
|
||||
code String?
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt @db.Timestamp(0)
|
||||
business_activities BusinessActivity[]
|
||||
good_categories GoodCategory[]
|
||||
stockKeepingUnits StockKeepingUnits[]
|
||||
|
||||
@@map("guilds")
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
model MeasureUnits {
|
||||
id String @id @default(ulid())
|
||||
code String @unique
|
||||
name String
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @default(now()) @updatedAt @db.Timestamp(0)
|
||||
goods Good[]
|
||||
|
||||
@@map("measure_units")
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
model StockKeepingUnits {
|
||||
id String @id @default(ulid())
|
||||
code String @unique
|
||||
name String
|
||||
VAT Decimal @db.Decimal(5, 2)
|
||||
is_public Boolean @default(true)
|
||||
is_domestic Boolean @default(false)
|
||||
guild_id String
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt @db.Timestamp(0)
|
||||
goods Good[]
|
||||
guild Guild @relation(fields: [guild_id], references: [id])
|
||||
|
||||
@@index([code])
|
||||
@@index([guild_id], map: "stock_keeping_units_guild_id_fkey")
|
||||
@@map("stock_keeping_units")
|
||||
}
|
||||
@@ -1,19 +1,8 @@
|
||||
// generator client {
|
||||
// provider = "prisma-client-js"
|
||||
// // output = "../../src/generated/prisma"
|
||||
// // moduleFormat = "cjs"
|
||||
// previewFeatures = ["views"]
|
||||
// }
|
||||
|
||||
// datasource db {
|
||||
// provider = "mysql"
|
||||
// }
|
||||
|
||||
generator client {
|
||||
provider = "prisma-client"
|
||||
output = "../../src/generated/prisma"
|
||||
moduleFormat = "cjs"
|
||||
previewFeatures = ["views"]
|
||||
moduleFormat = "cjs"
|
||||
}
|
||||
|
||||
datasource db {
|
||||
|
||||
@@ -1,51 +1,47 @@
|
||||
model Customer {
|
||||
id String @id @default(ulid())
|
||||
is_favorite Boolean? @default(false)
|
||||
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt @db.Timestamp(0)
|
||||
deleted_at DateTime? @db.Timestamp(0)
|
||||
|
||||
type CustomerType
|
||||
unknown_customer Json?
|
||||
customer_individual CustomerIndividual?
|
||||
customer_legal CustomerLegal?
|
||||
sales_invoices SalesInvoice[]
|
||||
id String @id @default(ulid())
|
||||
is_favorite Boolean? @default(false)
|
||||
type CustomerType
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt @db.Timestamp(0)
|
||||
deleted_at DateTime? @db.Timestamp(0)
|
||||
individual CustomerIndividual?
|
||||
legal CustomerLegal?
|
||||
sales_invoices SalesInvoice[]
|
||||
|
||||
@@map("customers")
|
||||
}
|
||||
|
||||
model CustomerIndividual {
|
||||
first_name String @db.VarChar(255)
|
||||
last_name String @db.VarChar(255)
|
||||
national_id String @db.Char(10)
|
||||
postal_code String @db.Char(10)
|
||||
economic_code String? @db.Char(10)
|
||||
first_name String? @db.VarChar(255)
|
||||
last_name String? @db.VarChar(255)
|
||||
national_id String? @db.Char(10)
|
||||
mobile_number String? @db.Char(15)
|
||||
postal_code String? @db.Char(10)
|
||||
economic_code String? @db.Char(14)
|
||||
customer_id String @id
|
||||
business_activity_id String
|
||||
business_activity BusinessActivity @relation(fields: [business_activity_id], references: [id])
|
||||
customer Customer @relation(fields: [customer_id], references: [id], onDelete: Cascade)
|
||||
|
||||
customer_id String @id
|
||||
customer Customer @relation(fields: [customer_id], references: [id], onDelete: Cascade)
|
||||
|
||||
complex_id String
|
||||
complex Complex @relation(fields: [complex_id], references: [id])
|
||||
|
||||
@@unique([complex_id, national_id])
|
||||
@@index([complex_id])
|
||||
@@unique([business_activity_id, national_id])
|
||||
@@unique([business_activity_id, postal_code, national_id])
|
||||
@@index([business_activity_id])
|
||||
@@map("customer_individuals")
|
||||
}
|
||||
|
||||
model CustomerLegal {
|
||||
company_name String @db.VarChar(255)
|
||||
economic_code String @db.Char(10)
|
||||
registration_number String @db.Char(20)
|
||||
postal_code String @db.Char(10)
|
||||
name String? @db.VarChar(255)
|
||||
economic_code String? @db.Char(11)
|
||||
registration_number String? @db.Char(20)
|
||||
postal_code String? @db.Char(10)
|
||||
customer_id String @id
|
||||
business_activity_id String
|
||||
business_activity BusinessActivity @relation(fields: [business_activity_id], references: [id])
|
||||
customer Customer @relation(fields: [customer_id], references: [id], onDelete: Cascade)
|
||||
|
||||
customer_id String @id
|
||||
customer Customer @relation(fields: [customer_id], references: [id], onDelete: Cascade)
|
||||
|
||||
complex_id String
|
||||
complex Complex @relation(fields: [complex_id], references: [id])
|
||||
|
||||
@@unique([complex_id, registration_number])
|
||||
@@index([complex_id])
|
||||
@@unique([business_activity_id, economic_code])
|
||||
@@unique([business_activity_id, postal_code, registration_number])
|
||||
@@index([business_activity_id])
|
||||
@@map("customer_legal")
|
||||
}
|
||||
|
||||
@@ -1,23 +1,14 @@
|
||||
enum PaymentMethodType {
|
||||
TERMINAL
|
||||
CASH
|
||||
CHEQUE
|
||||
SET_OFF
|
||||
CASH
|
||||
TERMINAL
|
||||
PAYMENT_GATEWAY
|
||||
CARD
|
||||
BANK
|
||||
CHECK
|
||||
OTHER
|
||||
}
|
||||
|
||||
enum UnitType {
|
||||
COUNT
|
||||
GRAM
|
||||
KILOGRAM
|
||||
MILLILITER
|
||||
LITER
|
||||
METER
|
||||
HOUR
|
||||
}
|
||||
|
||||
enum GoodPricingModel {
|
||||
STANDARD
|
||||
GOLD
|
||||
@@ -49,18 +40,6 @@ enum BusinessRole {
|
||||
OPERATOR
|
||||
}
|
||||
|
||||
enum LicenseType {
|
||||
BASIC
|
||||
PRO
|
||||
ENTERPRISE
|
||||
}
|
||||
|
||||
enum LicenseStatus {
|
||||
ACTIVE
|
||||
EXPIRED
|
||||
SUSPENDED
|
||||
}
|
||||
|
||||
enum POSType {
|
||||
PSP
|
||||
MOBILE
|
||||
@@ -68,11 +47,6 @@ enum POSType {
|
||||
API
|
||||
}
|
||||
|
||||
enum UserType {
|
||||
LEGAL
|
||||
INDIVIDUAL
|
||||
}
|
||||
|
||||
enum AccountType {
|
||||
ADMIN
|
||||
PROVIDER
|
||||
@@ -80,17 +54,6 @@ enum AccountType {
|
||||
CONSUMER
|
||||
}
|
||||
|
||||
enum UserStatus {
|
||||
ACTIVE
|
||||
INACTIVE
|
||||
}
|
||||
|
||||
enum AccountRole {
|
||||
OWNER
|
||||
OPERATOR
|
||||
ACCOUNTANT
|
||||
}
|
||||
|
||||
enum AccountStatus {
|
||||
ACTIVE
|
||||
SUSPENDED
|
||||
@@ -113,11 +76,6 @@ enum ProviderRole {
|
||||
OPERATOR
|
||||
}
|
||||
|
||||
enum ProviderStatus {
|
||||
ACTIVE
|
||||
SUSPENDED
|
||||
}
|
||||
|
||||
enum ConsumerRole {
|
||||
OWNER
|
||||
MANAGER
|
||||
@@ -129,11 +87,6 @@ enum ConsumerStatus {
|
||||
SUSPENDED
|
||||
}
|
||||
|
||||
enum TokenType {
|
||||
ACCESS
|
||||
REFRESH
|
||||
}
|
||||
|
||||
enum ApplicationPlatform {
|
||||
ANDROID
|
||||
IOS
|
||||
@@ -145,8 +98,48 @@ enum ApplicationReleaseType {
|
||||
ALPHA
|
||||
}
|
||||
|
||||
enum ApplicationPublisher {
|
||||
DIRECT
|
||||
CAFE_BAZAR
|
||||
MAYKET
|
||||
enum ConsumerType {
|
||||
INDIVIDUAL
|
||||
LEGAL
|
||||
}
|
||||
|
||||
enum InvoiceSettlementType {
|
||||
CASH
|
||||
CREDIT
|
||||
MIXED
|
||||
}
|
||||
|
||||
enum TspProviderType {
|
||||
NAMA
|
||||
SUN
|
||||
}
|
||||
|
||||
enum TspProviderResponseStatus {
|
||||
NOT_SEND
|
||||
QUEUED
|
||||
FISCAL_QUEUED
|
||||
SEND_FAILURE
|
||||
SUCCESS
|
||||
FAILURE
|
||||
}
|
||||
|
||||
enum TspProviderRequestType {
|
||||
ORIGINAL
|
||||
CORRECTION
|
||||
REVOKE
|
||||
RETURN
|
||||
}
|
||||
|
||||
enum InvoiceTemplateType {
|
||||
SALE
|
||||
FX_SALE
|
||||
GOLD_JEWELRY
|
||||
CONTRACT
|
||||
UTILITY
|
||||
AIR_TICKET
|
||||
EXPORT
|
||||
BILL_OF_LADING
|
||||
PETROCHEMICAL
|
||||
COMMODITY_EXCHANGE
|
||||
INSURANCE
|
||||
}
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
model Good {
|
||||
id String @id @default(ulid())
|
||||
name String @db.VarChar(255)
|
||||
is_default_guild_good Boolean @default(false)
|
||||
sku String @db.VarChar(100)
|
||||
unit_type UnitType
|
||||
pricing_model GoodPricingModel
|
||||
description String? @db.Text
|
||||
local_sku String? @unique() @db.VarChar(100)
|
||||
barcode String? @unique() @db.VarChar(100)
|
||||
base_sale_price Decimal? @default(0.00) @db.Decimal(15, 0)
|
||||
image_url String? @db.VarChar(255)
|
||||
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt @db.Timestamp(0)
|
||||
deleted_at DateTime? @db.Timestamp(0)
|
||||
|
||||
complex_id String?
|
||||
category_id String?
|
||||
|
||||
category GoodCategory? @relation(fields: [category_id], references: [id])
|
||||
complex Complex? @relation(fields: [complex_id], references: [id])
|
||||
sales_invoice_items SalesInvoiceItem[]
|
||||
|
||||
@@index([category_id])
|
||||
@@map("goods")
|
||||
}
|
||||
|
||||
model GoodCategory {
|
||||
id String @id @default(ulid())
|
||||
name String @db.VarChar(100)
|
||||
description String? @db.Text
|
||||
image_url String? @db.VarChar(255)
|
||||
complex_id String?
|
||||
is_default_guild_good Boolean @default(false)
|
||||
guild_id String?
|
||||
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt @db.Timestamp(0)
|
||||
deleted_at DateTime? @db.Timestamp(0)
|
||||
|
||||
goods Good[]
|
||||
guild Guild? @relation(fields: [guild_id], references: [id])
|
||||
complex Complex? @relation(fields: [complex_id], references: [id])
|
||||
|
||||
@@map("good_categories")
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
model Guild {
|
||||
id String @id @default(ulid())
|
||||
name String
|
||||
code String?
|
||||
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt() @db.Timestamp(0)
|
||||
|
||||
business_activities BusinessActivity[]
|
||||
good_categories GoodCategory[]
|
||||
|
||||
@@map("guilds")
|
||||
}
|
||||
@@ -1,60 +1,122 @@
|
||||
model SalesInvoice {
|
||||
id String @id @default(ulid())
|
||||
code String @unique @db.VarChar(100)
|
||||
total_amount Decimal @db.Decimal(15, 2)
|
||||
notes String? @db.Text
|
||||
unknown_customer Json? @db.Json
|
||||
invoice_date DateTime? @default(now()) @db.Timestamp(0)
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt @db.Timestamp(0)
|
||||
|
||||
customer_id String?
|
||||
account_id String
|
||||
pos_id String
|
||||
|
||||
customer Customer? @relation(fields: [customer_id], references: [id])
|
||||
pos Pos @relation(fields: [pos_id], references: [id])
|
||||
consumer_account ConsumerAccount @relation(fields: [account_id], references: [id])
|
||||
items SalesInvoiceItem[]
|
||||
payments SalesInvoicePayment[]
|
||||
id String @id @default(uuid())
|
||||
code String @unique @db.VarChar(100)
|
||||
total_amount Decimal @db.Decimal(15, 2)
|
||||
invoice_number Int
|
||||
invoice_date DateTime @default(now()) @db.Timestamp(0)
|
||||
type TspProviderRequestType
|
||||
tax_id String? @unique @db.VarChar(32)
|
||||
notes String? @db.Text
|
||||
unknown_customer Json?
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt @db.Timestamp(0)
|
||||
main_id String? @db.VarChar(50)
|
||||
ref_id String? @unique @db.VarChar(50)
|
||||
customer_id String?
|
||||
consumer_account_id String
|
||||
pos_id String
|
||||
settlement_type InvoiceSettlementType
|
||||
discount_amount Decimal? @db.Decimal(15, 2)
|
||||
tax_amount Decimal? @db.Decimal(15, 2)
|
||||
last_tsp_status TspProviderResponseStatus?
|
||||
last_attempt_no Int?
|
||||
tsp_attempts SaleInvoiceTspAttempts[]
|
||||
items SalesInvoiceItem[]
|
||||
payments SalesInvoicePayment[]
|
||||
consumer_account ConsumerAccount @relation(fields: [consumer_account_id], references: [id])
|
||||
customer Customer? @relation(fields: [customer_id], references: [id])
|
||||
pos Pos @relation(fields: [pos_id], references: [id])
|
||||
reference_invoice SalesInvoice? @relation("SalesInvoiceReference", fields: [ref_id], references: [id])
|
||||
referenced_by SalesInvoice? @relation("SalesInvoiceReference")
|
||||
|
||||
@@unique([invoice_number, pos_id])
|
||||
@@index([pos_id, invoice_date])
|
||||
@@index([ref_id])
|
||||
@@index([tax_id])
|
||||
@@index([consumer_account_id], map: "sales_invoices_consumer_account_id_fkey")
|
||||
@@index([customer_id], map: "sales_invoices_customer_id_fkey")
|
||||
@@map("sales_invoices")
|
||||
}
|
||||
|
||||
model SalesInvoiceItem {
|
||||
id String @id @default(ulid())
|
||||
quantity Decimal @db.Decimal(10, 0)
|
||||
unit_type UnitType
|
||||
unit_price Decimal @default(0.00) @db.Decimal(15, 2)
|
||||
total_amount Decimal @default(0.00) @db.Decimal(15, 2)
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
discount Decimal @default(0.00) @db.Decimal(15, 2)
|
||||
notes String? @db.Text
|
||||
|
||||
invoice_id String
|
||||
good_id String?
|
||||
service_id String?
|
||||
|
||||
payload Json?
|
||||
id String @id @default(ulid())
|
||||
quantity Decimal @db.Decimal(10, 0)
|
||||
measure_unit_text String @db.VarChar(50)
|
||||
measure_unit_code String @db.VarChar(50)
|
||||
sku_code String @db.VarChar(50)
|
||||
sku_vat Decimal @default(0.00) @db.Decimal(15, 2)
|
||||
unit_price Decimal @default(0.00) @db.Decimal(15, 2)
|
||||
total_amount Decimal @default(0.00) @db.Decimal(15, 2)
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
discount Decimal @default(0.00) @db.Decimal(15, 2)
|
||||
notes String? @db.Text
|
||||
payload Json?
|
||||
good_snapshot Json
|
||||
invoice_id String
|
||||
good_id String
|
||||
service_id String?
|
||||
discount_amount Decimal? @db.Decimal(15, 2)
|
||||
tax_amount Decimal? @db.Decimal(15, 2)
|
||||
|
||||
good Good @relation(fields: [good_id], references: [id])
|
||||
invoice SalesInvoice @relation(fields: [invoice_id], references: [id])
|
||||
good Good? @relation(fields: [good_id], references: [id])
|
||||
service Service? @relation(fields: [service_id], references: [id])
|
||||
|
||||
@@index([invoice_id, good_id])
|
||||
@@index([good_id], map: "sales_invoice_items_good_id_fkey")
|
||||
@@index([service_id], map: "sales_invoice_items_service_id_fkey")
|
||||
@@map("sales_invoice_items")
|
||||
}
|
||||
|
||||
model SalesInvoicePayment {
|
||||
id String @id @default(ulid())
|
||||
invoice_id String
|
||||
amount Decimal @db.Decimal(15, 2)
|
||||
payment_method PaymentMethodType
|
||||
paid_at DateTime
|
||||
created_at DateTime @default(now())
|
||||
model SaleInvoiceTspAttempts {
|
||||
id String @id @default(ulid())
|
||||
attempt_no Int
|
||||
status TspProviderResponseStatus
|
||||
message String @db.Text
|
||||
sent_at DateTime? @db.Timestamp(0)
|
||||
received_at DateTime? @db.Timestamp(0)
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
invoice_id String
|
||||
provider_request_payload Json
|
||||
raw_request_payload Json
|
||||
error_message String? @db.Text
|
||||
fiscal_warnings Json?
|
||||
provider_response Json?
|
||||
validation_errors Json?
|
||||
invoice SalesInvoice @relation(fields: [invoice_id], references: [id], onDelete: Cascade)
|
||||
|
||||
invoice SalesInvoice @relation(fields: [invoice_id], references: [id])
|
||||
@@unique([invoice_id, attempt_no])
|
||||
@@index([status])
|
||||
@@index([invoice_id])
|
||||
@@map("sale_invoice_tsp_attempts")
|
||||
}
|
||||
|
||||
model SalesInvoicePayment {
|
||||
id String @id @default(ulid())
|
||||
amount Decimal @db.Decimal(15, 2)
|
||||
payment_method PaymentMethodType
|
||||
paid_at DateTime @db.Timestamp(0)
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
invoice_id String
|
||||
terminal_info SalesInvoicePaymentTerminalInfo?
|
||||
invoice SalesInvoice @relation(fields: [invoice_id], references: [id])
|
||||
|
||||
@@index([invoice_id])
|
||||
@@map("sales_invoice_payments")
|
||||
}
|
||||
|
||||
model SalesInvoicePaymentTerminalInfo {
|
||||
id String @id @default(ulid())
|
||||
terminal_id String
|
||||
stan String
|
||||
rrn String
|
||||
transaction_date_time DateTime
|
||||
customer_card_no String?
|
||||
description String?
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
payment_id String @unique
|
||||
payment SalesInvoicePayment @relation(fields: [payment_id], references: [id])
|
||||
|
||||
@@unique([terminal_id, stan, rrn, payment_id])
|
||||
@@map("sales_invoice_payment_terminal_info")
|
||||
}
|
||||
|
||||
@@ -1,20 +1,19 @@
|
||||
model Service {
|
||||
id String @id @default(ulid())
|
||||
name String @db.VarChar(255)
|
||||
description String? @db.Text
|
||||
sku String @unique() @db.VarChar(100)
|
||||
local_sku String? @unique() @db.VarChar(100)
|
||||
barcode String? @unique() @db.VarChar(100)
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt @db.Timestamp(0)
|
||||
deleted_at DateTime? @db.Timestamp(0)
|
||||
category_id String?
|
||||
base_sale_price Decimal @default(0.00) @db.Decimal(15, 0)
|
||||
account_id String
|
||||
complex_id String
|
||||
|
||||
category ServiceCategory? @relation(fields: [category_id], references: [id])
|
||||
id String @id @default(ulid())
|
||||
name String @db.VarChar(255)
|
||||
description String? @db.Text
|
||||
sku String @unique @db.VarChar(100)
|
||||
local_sku String? @unique @db.VarChar(100)
|
||||
barcode String? @unique @db.VarChar(100)
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt @db.Timestamp(0)
|
||||
deleted_at DateTime? @db.Timestamp(0)
|
||||
category_id String?
|
||||
base_sale_price Decimal @default(0) @db.Decimal(15, 0)
|
||||
account_id String
|
||||
complex_id String
|
||||
sales_invoice_items SalesInvoiceItem[]
|
||||
category ServiceCategory? @relation(fields: [category_id], references: [id])
|
||||
|
||||
@@index([category_id])
|
||||
@@map("services")
|
||||
@@ -30,8 +29,7 @@ model ServiceCategory {
|
||||
created_at DateTime @default(now()) @db.Timestamp(0)
|
||||
updated_at DateTime @updatedAt @db.Timestamp(0)
|
||||
deleted_at DateTime? @db.Timestamp(0)
|
||||
|
||||
services Service[]
|
||||
services Service[]
|
||||
|
||||
@@map("service_categories")
|
||||
}
|
||||
|
||||
+563
-400
File diff suppressed because it is too large
Load Diff
@@ -1,548 +0,0 @@
|
||||
-- AUTO-GENERATED MYSQL TRIGGER DUMP
|
||||
-- Generated at: 2026-01-06T16:09:38.959Z
|
||||
|
||||
-- ------------------------------------------
|
||||
-- index: 1
|
||||
-- Trigger: trg_bank_account_transaction_after_delete
|
||||
-- Event: DELETE
|
||||
-- Table: Bank_Account_Transactions
|
||||
-- ------------------------------------------
|
||||
DROP TRIGGER IF EXISTS `trg_bank_account_transaction_after_delete`;
|
||||
CREATE DEFINER=`pos`@`%` TRIGGER `trg_bank_account_transaction_after_delete` AFTER DELETE ON `Bank_Account_Transactions` FOR EACH ROW BEGIN
|
||||
UPDATE `Bank_Account_Balance` SET balance = balance - OLD.amount WHERE `bankAccountId` = OLD.bankAccountId;
|
||||
END;
|
||||
|
||||
-- ------------------------------------------
|
||||
-- index: 2
|
||||
-- Trigger: trg_transfer_item_after_insert
|
||||
-- Event: INSERT
|
||||
-- Table: Inventory_Transfer_Items
|
||||
-- ------------------------------------------
|
||||
DROP TRIGGER IF EXISTS `trg_transfer_item_after_insert`;
|
||||
CREATE DEFINER=`pos`@`%` TRIGGER `trg_transfer_item_after_insert` AFTER INSERT ON `Inventory_Transfer_Items` FOR EACH ROW begin
|
||||
|
||||
DECLARE fromInv INT;
|
||||
DECLARE toInv INT;
|
||||
DECLARE _avgCost DECIMAL(10,2);
|
||||
DECLARE latestQuantityInOrigin DECIMAL(10,2);
|
||||
DECLARE latestQuantityInDestination DECIMAL(10,2);
|
||||
|
||||
SELECT fromInventoryId, toInventoryId INTO fromInv, toInv
|
||||
FROM Inventory_Transfers WHERE id = NEW.transferId;
|
||||
|
||||
SELECT COALESCE(avgCost, 0), COALESCE(quantity, 0) INTO _avgCost, latestQuantityInOrigin FROM Stock_Balance
|
||||
WHERE ProductId = NEW.productId AND inventoryId = fromInv LIMIT 1;
|
||||
|
||||
SELECT COALESCE(quantity, 0) INTO latestQuantityInDestination FROM Stock_Balance
|
||||
WHERE ProductId = NEW.productId AND inventoryId = toInv LIMIT 1;
|
||||
|
||||
|
||||
-- OUT from source
|
||||
INSERT INTO Stock_Movements
|
||||
(type, quantity, unitPrice, totalCost, avgCost, referenceType, referenceId, productId, inventoryId, counterInventoryId, createdAt, remainedInStock)
|
||||
VALUES
|
||||
('OUT', NEW.count, _avgCost, _avgCost*NEW.count, _avgCost, 'INVENTORY_TRANSFER', NEW.transferId, NEW.productId, fromInv, toInv, NOW(), latestQuantityInOrigin-NEW.count);
|
||||
|
||||
-- IN to destination
|
||||
INSERT INTO Stock_Movements
|
||||
(type, quantity, unitPrice, totalCost, avgCost, referenceType, referenceId, productId, inventoryId, counterInventoryId, createdAt, remainedInStock)
|
||||
VALUES
|
||||
('IN', NEW.count,_avgCost, _avgCost*NEW.count,_avgCost, 'INVENTORY_TRANSFER', NEW.transferId, NEW.productId, toInv, fromInv, NOW(), latestQuantityInOrigin-NEW.count);
|
||||
end;
|
||||
|
||||
-- ------------------------------------------
|
||||
-- index: 3
|
||||
-- Trigger: trg_order_item_after_update
|
||||
-- Event: UPDATE
|
||||
-- Table: Order_Items
|
||||
-- ------------------------------------------
|
||||
DROP TRIGGER IF EXISTS `trg_order_item_after_update`;
|
||||
CREATE DEFINER=`pos`@`%` TRIGGER `trg_order_item_after_update` AFTER UPDATE ON `Order_Items` FOR EACH ROW BEGIN
|
||||
|
||||
UPDATE Stock_Reservations
|
||||
SET quantity = quantity - OLD.quantity + NEW.quantity
|
||||
WHERE orderId = NEW.orderId AND productId = NEW.productId;
|
||||
|
||||
END;
|
||||
|
||||
-- ------------------------------------------
|
||||
-- index: 4
|
||||
-- Trigger: trg_order_item_after_delete
|
||||
-- Event: DELETE
|
||||
-- Table: Order_Items
|
||||
-- ------------------------------------------
|
||||
DROP TRIGGER IF EXISTS `trg_order_item_after_delete`;
|
||||
CREATE DEFINER=`pos`@`%` TRIGGER `trg_order_item_after_delete` AFTER DELETE ON `Order_Items` FOR EACH ROW BEGIN
|
||||
|
||||
DELETE From Stock_Reservations
|
||||
WHERE orderId = OLD.orderId AND productId = OLD.productId;
|
||||
|
||||
END;
|
||||
|
||||
-- ------------------------------------------
|
||||
-- index: 5
|
||||
-- Trigger: trg_order_after_cancel
|
||||
-- Event: UPDATE
|
||||
-- Table: Orders
|
||||
-- ------------------------------------------
|
||||
DROP TRIGGER IF EXISTS `trg_order_after_cancel`;
|
||||
CREATE DEFINER=`pos`@`%` TRIGGER `trg_order_after_cancel` AFTER UPDATE ON `Orders` FOR EACH ROW BEGIN
|
||||
IF NEW.status = 'CANCELED' OR NEW.status = 'REJECTED' OR NEW.status = 'DONE' THEN
|
||||
UPDATE Stock_Reservations sr SET quantity = 0
|
||||
WHERE sr.orderId = NEW.id;
|
||||
END IF;
|
||||
END;
|
||||
|
||||
-- ------------------------------------------
|
||||
-- index: 6
|
||||
-- Trigger: trg_purchase_receipt_item_after_insert
|
||||
-- Event: INSERT
|
||||
-- Table: Purchase_Receipt_Items
|
||||
-- ------------------------------------------
|
||||
DROP TRIGGER IF EXISTS `trg_purchase_receipt_item_after_insert`;
|
||||
CREATE DEFINER=`pos`@`%` TRIGGER `trg_purchase_receipt_item_after_insert` AFTER INSERT ON `Purchase_Receipt_Items` FOR EACH ROW BEGIN DECLARE latestQuantity DECIMAL(10, 2) DEFAULT 0;
|
||||
|
||||
DECLARE invId INT;
|
||||
DECLARE suppId INT;
|
||||
|
||||
-- Get inventory & supplier from
|
||||
SELECT inventoryId, supplierId
|
||||
INTO invId, suppId
|
||||
FROM Purchase_Receipts
|
||||
WHERE id = NEW.receiptId;
|
||||
|
||||
-- Get current stock quantity (if exists)
|
||||
SELECT COALESCE(quantity, 0)
|
||||
INTO latestQuantity
|
||||
FROM Stock_Balance sb
|
||||
WHERE sb.inventoryId = invId
|
||||
AND sb.productId = NEW.productId
|
||||
LIMIT 1;
|
||||
|
||||
-- Insert stock movement
|
||||
INSERT INTO Stock_Movements (
|
||||
type,
|
||||
quantity,
|
||||
unitPrice,
|
||||
totalCost,
|
||||
referenceType,
|
||||
referenceId,
|
||||
productId,
|
||||
inventoryId,
|
||||
avgCost,
|
||||
supplierId,
|
||||
remainedInStock,
|
||||
createdAt
|
||||
)
|
||||
VALUES (
|
||||
'IN',
|
||||
NEW.count,
|
||||
NEW.unitPrice,
|
||||
NEW.totalAmount,
|
||||
'PURCHASE',
|
||||
NEW.receiptId,
|
||||
NEW.productId,
|
||||
invId,
|
||||
CASE
|
||||
WHEN NEW.count = 0 THEN 0
|
||||
ELSE NEW.totalAmount / NEW.count
|
||||
END
|
||||
|
||||
,
|
||||
suppId,
|
||||
latestQuantity + NEW.count,
|
||||
NOW()
|
||||
);
|
||||
|
||||
END;
|
||||
|
||||
-- ------------------------------------------
|
||||
-- index: 7
|
||||
-- Trigger: trg_pr_payment_after_delete
|
||||
-- Event: DELETE
|
||||
-- Table: Purchase_Receipt_Payments
|
||||
-- ------------------------------------------
|
||||
DROP TRIGGER IF EXISTS `trg_pr_payment_after_delete`;
|
||||
CREATE DEFINER=`pos`@`%` TRIGGER `trg_pr_payment_after_delete` AFTER DELETE ON `Purchase_Receipt_Payments` FOR EACH ROW BEGIN
|
||||
DECLARE receiptTotal DECIMAL(14,2);
|
||||
DECLARE newPaid DECIMAL(14,2);
|
||||
|
||||
SELECT totalAmount, paidAmount
|
||||
INTO receiptTotal, newPaid
|
||||
FROM Purchase_Receipts
|
||||
WHERE id = OLD.receiptId
|
||||
FOR UPDATE;
|
||||
|
||||
IF OLD.type = 'PAYMENT' THEN
|
||||
SET newPaid = newPaid - OLD.amount;
|
||||
ELSE
|
||||
SET newPaid = newPaid + OLD.amount;
|
||||
END IF;
|
||||
|
||||
UPDATE Purchase_Receipts
|
||||
SET
|
||||
paidAmount = newPaid,
|
||||
status =
|
||||
CASE
|
||||
WHEN newPaid = 0 THEN 'UNPAID'
|
||||
WHEN newPaid < receiptTotal THEN 'PARTIALLY_PAID'
|
||||
ELSE 'PAID'
|
||||
END
|
||||
WHERE id = OLD.receiptId;
|
||||
END;
|
||||
|
||||
-- ------------------------------------------
|
||||
-- index: 8
|
||||
-- Trigger: trg_sales_invoice_items_before_insert
|
||||
-- Event: INSERT
|
||||
-- Table: Sales_Invoice_Items
|
||||
-- ------------------------------------------
|
||||
DROP TRIGGER IF EXISTS `trg_sales_invoice_items_before_insert`;
|
||||
CREATE DEFINER=`pos`@`%` TRIGGER `trg_sales_invoice_items_before_insert` BEFORE INSERT ON `Sales_Invoice_Items` FOR EACH ROW BEGIN
|
||||
|
||||
DECLARE current_stock DECIMAL(10, 2);
|
||||
DECLARE inventory_id INT;
|
||||
|
||||
|
||||
|
||||
SELECT pa.inventoryId INTO inventory_id
|
||||
FROM Pos_Accounts pa
|
||||
INNER JOIN Sales_Invoices si ON pa.id = si.posAccountId
|
||||
WHERE si.id = NEW.invoiceId;
|
||||
|
||||
|
||||
SELECT COALESCE(sav.availableQuantity, 0) INTO current_stock
|
||||
FROM Stock_Available_View sav
|
||||
WHERE productId = NEW.productId AND sav.inventoryId = inventory_id;
|
||||
|
||||
|
||||
|
||||
IF NEW.count > current_stock THEN
|
||||
SIGNAL SQLSTATE '45000'
|
||||
SET MESSAGE_TEXT = 'موجودی کالا در انبار کافی نیست.';
|
||||
END IF;
|
||||
end;
|
||||
|
||||
-- ------------------------------------------
|
||||
-- index: 9
|
||||
-- Trigger: trg_sales_invoice_items_after_insert
|
||||
-- Event: INSERT
|
||||
-- Table: Sales_Invoice_Items
|
||||
-- ------------------------------------------
|
||||
DROP TRIGGER IF EXISTS `trg_sales_invoice_items_after_insert`;
|
||||
CREATE DEFINER=`pos`@`%` TRIGGER `trg_sales_invoice_items_after_insert` AFTER INSERT ON `Sales_Invoice_Items` FOR EACH ROW begin DECLARE current_stock DECIMAL(10, 2);
|
||||
|
||||
DECLARE inventory_id INT;
|
||||
DECLARE customer_id INT;
|
||||
DECLARE pos_id INT;
|
||||
|
||||
|
||||
|
||||
SELECT posAccountId, customerId INTO pos_id, customer_id
|
||||
FROM Sales_Invoices si
|
||||
WHERE si.id = NEW.invoiceId
|
||||
LIMIT 1;
|
||||
INSERT INTO Trigger_Logs (name , message) VALUES ('pos_id', pos_id);
|
||||
INSERT INTO Trigger_Logs (name , message) VALUES ('customer_id', customer_id);
|
||||
|
||||
|
||||
SELECT pa.inventoryId INTO inventory_id
|
||||
FROM Pos_Accounts pa
|
||||
INNER JOIN Sales_Invoices si ON pa.id = si.posAccountId
|
||||
WHERE si.id = NEW.invoiceId;
|
||||
|
||||
|
||||
|
||||
SELECT COALESCE(quantity, 0) INTO current_stock
|
||||
FROM Stock_Balance sb
|
||||
WHERE productId = NEW.productId AND sb.inventoryId = inventory_id
|
||||
LIMIT 1;
|
||||
|
||||
|
||||
|
||||
INSERT INTO Stock_Movements (
|
||||
type,
|
||||
quantity,
|
||||
unitPrice,
|
||||
totalCost,
|
||||
referenceType,
|
||||
referenceId,
|
||||
productId,
|
||||
inventoryId,
|
||||
avgCost,
|
||||
remainedInStock,
|
||||
customerId,
|
||||
createdAt
|
||||
)
|
||||
VALUES (
|
||||
'OUT',
|
||||
NEW.count,
|
||||
NEW.unitPrice,
|
||||
NEW.totalAmount,
|
||||
'SALES',
|
||||
NEW.invoiceId,
|
||||
NEW.productId,
|
||||
inventory_id,
|
||||
|
||||
CASE
|
||||
WHEN NEW.count = 0 THEN 0
|
||||
ELSE NEW.totalAmount / NEW.count
|
||||
END,
|
||||
current_stock - NEW.count,
|
||||
customer_id,
|
||||
NOW()
|
||||
);
|
||||
|
||||
|
||||
END;
|
||||
|
||||
-- ------------------------------------------
|
||||
-- index: 10
|
||||
-- Trigger: trg_pos_account_payment_after_insert
|
||||
-- Event: INSERT
|
||||
-- Table: Sales_Invoice_Payments
|
||||
-- ------------------------------------------
|
||||
DROP TRIGGER IF EXISTS `trg_pos_account_payment_after_insert`;
|
||||
CREATE DEFINER=`pos`@`%` TRIGGER `trg_pos_account_payment_after_insert` AFTER INSERT ON `Sales_Invoice_Payments` FOR EACH ROW BEGIN
|
||||
|
||||
DECLARE _bankAccountId INT;
|
||||
|
||||
IF(NEW.paymentMethod != 'CASH') THEN
|
||||
SELECT cashBankAccountId INTO _bankAccountId
|
||||
FROM Pos_Accounts pa
|
||||
INNER JOIN Sales_Invoices si ON pa.id = si.posAccountId
|
||||
WHERE si.id = NEW.invoiceId;
|
||||
End IF;
|
||||
|
||||
INSERT INTO Bank_Account_Transactions (
|
||||
bankAccountId,
|
||||
type,
|
||||
amount,
|
||||
balanceAfter,
|
||||
referenceType,
|
||||
referenceId
|
||||
)
|
||||
VALUES(
|
||||
_bankAccountId,
|
||||
'DEPOSIT',
|
||||
NEW.amount,
|
||||
0,
|
||||
'POS_SALE',
|
||||
NEW.id
|
||||
);
|
||||
END;
|
||||
|
||||
-- ------------------------------------------
|
||||
-- index: 11
|
||||
-- Trigger: trg_sales_invoice_payment_after_insert
|
||||
-- Event: INSERT
|
||||
-- Table: Sales_Invoice_Payments
|
||||
-- ------------------------------------------
|
||||
DROP TRIGGER IF EXISTS `trg_sales_invoice_payment_after_insert`;
|
||||
CREATE DEFINER=`pos`@`%` TRIGGER `trg_sales_invoice_payment_after_insert` AFTER INSERT ON `Sales_Invoice_Payments` FOR EACH ROW BEGIN
|
||||
DECLARE currentBalance DECIMAL(15,2);
|
||||
DECLARE bankAccountId INT;
|
||||
|
||||
SELECT pa.bankAccountId INTO bankAccountId
|
||||
FROM Pos_Accounts pa
|
||||
INNER JOIN Sales_Invoices si ON pa.id = si.posAccountId
|
||||
WHERE si.id = NEW.invoiceId;
|
||||
|
||||
SELECT balance INTO currentBalance
|
||||
FROM Bank_Account_Balance
|
||||
WHERE bankAccountId = bankAccountId
|
||||
FOR UPDATE;
|
||||
|
||||
IF currentBalance IS NULL THEN
|
||||
SET currentBalance = 0;
|
||||
INSERT INTO Bank_Account_Balance (bankAccountId, balance)
|
||||
VALUES (bankAccountId, 0);
|
||||
END IF;
|
||||
|
||||
SET currentBalance = currentBalance + NEW.amount;
|
||||
|
||||
INSERT INTO Bank_Account_Transactions
|
||||
(bankAccountId, type, amount, balanceAfter, referenceType, referenceId)
|
||||
VALUES
|
||||
(bankAccountId, 'DEPOSIT', NEW.amount, currentBalance, 'POS_SALE', NEW.id);
|
||||
|
||||
UPDATE Bank_Account_Balance
|
||||
SET balance = currentBalance
|
||||
WHERE bankAccountId = bankAccountId;
|
||||
END;
|
||||
|
||||
-- ------------------------------------------
|
||||
-- index: 12
|
||||
-- Trigger: trg_stock_sale_insert
|
||||
-- Event: INSERT
|
||||
-- Table: Stock_Movements
|
||||
-- ------------------------------------------
|
||||
DROP TRIGGER IF EXISTS `trg_stock_sale_insert`;
|
||||
CREATE DEFINER=`pos`@`%` TRIGGER `trg_stock_sale_insert` AFTER INSERT ON `Stock_Movements` FOR EACH ROW BEGIN IF NEW.referenceType = 'SALES' THEN
|
||||
|
||||
INSERT INTO
|
||||
Stock_Balance (
|
||||
productId,
|
||||
quantity,
|
||||
avgCost,
|
||||
totalCost,
|
||||
inventoryId,
|
||||
updatedAt
|
||||
)
|
||||
VALUES (
|
||||
NEW.productId,
|
||||
NEW.quantity,
|
||||
NEW.unitPrice,
|
||||
NEW.totalCost,
|
||||
NEW.inventoryId,
|
||||
NOW()
|
||||
)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
quantity = quantity - NEW.quantity,
|
||||
totalCost = totalCost - NEW.totalCost,
|
||||
avgCost = totalCost / quantity;
|
||||
|
||||
END IF;
|
||||
|
||||
END;
|
||||
|
||||
-- ------------------------------------------
|
||||
-- index: 13
|
||||
-- Trigger: trg_stock_purchase_insert
|
||||
-- Event: INSERT
|
||||
-- Table: Stock_Movements
|
||||
-- ------------------------------------------
|
||||
DROP TRIGGER IF EXISTS `trg_stock_purchase_insert`;
|
||||
CREATE DEFINER=`pos`@`%` TRIGGER `trg_stock_purchase_insert` AFTER INSERT ON `Stock_Movements` FOR EACH ROW BEGIN IF NEW.referenceType = 'PURCHASE' THEN
|
||||
|
||||
INSERT INTO
|
||||
Stock_Balance (
|
||||
productId,
|
||||
quantity,
|
||||
avgCost,
|
||||
totalCost,
|
||||
inventoryId,
|
||||
updatedAt
|
||||
)
|
||||
VALUES (
|
||||
NEW.productId,
|
||||
NEW.quantity,
|
||||
NEW.unitPrice,
|
||||
NEW.totalCost,
|
||||
NEW.inventoryId,
|
||||
NOW()
|
||||
)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
quantity = quantity + NEW.quantity,
|
||||
totalCost = totalCost + NEW.totalCost,
|
||||
avgCost = totalCost / quantity;
|
||||
|
||||
END IF;
|
||||
|
||||
END;
|
||||
|
||||
-- ------------------------------------------
|
||||
-- index: 14
|
||||
-- Trigger: trg_stock_transfer
|
||||
-- Event: INSERT
|
||||
-- Table: Stock_Movements
|
||||
-- ------------------------------------------
|
||||
DROP TRIGGER IF EXISTS `trg_stock_transfer`;
|
||||
CREATE DEFINER=`pos`@`%` TRIGGER `trg_stock_transfer` AFTER INSERT ON `Stock_Movements` FOR EACH ROW BEGIN IF NEW.referenceType = 'INVENTORY_TRANSFER' THEN IF NEW.type = 'IN' THEN
|
||||
INSERT INTO
|
||||
Stock_Balance (
|
||||
productId,
|
||||
inventoryId,
|
||||
quantity,
|
||||
totalCost,
|
||||
avgCost,
|
||||
updatedAt
|
||||
)
|
||||
VALUES (
|
||||
NEW.productId,
|
||||
NEW.inventoryId,
|
||||
NEW.quantity,
|
||||
NEW.totalCost,
|
||||
CASE
|
||||
WHEN NEW.quantity = 0 THEN 0
|
||||
ELSE NEW.totalCost / NEW.quantity
|
||||
END,
|
||||
NOW()
|
||||
)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
quantity = quantity + NEW.quantity,
|
||||
totalCost = totalCost + NEW.totalCost,
|
||||
avgCost = CASE
|
||||
WHEN (quantity + NEW.quantity) = 0 THEN 0
|
||||
ELSE (totalCost + NEW.totalCost) / (quantity + NEW.quantity)
|
||||
END,
|
||||
updatedAt = NOW();
|
||||
|
||||
END IF;
|
||||
|
||||
IF NEW.type = 'OUT' THEN IF EXISTS (
|
||||
SELECT 1
|
||||
FROM Stock_Balance sb
|
||||
WHERE
|
||||
sb.productId = NEW.productId
|
||||
AND sb.inventoryId = NEW.inventoryId
|
||||
) THEN
|
||||
|
||||
UPDATE Stock_Balance sb
|
||||
SET
|
||||
sb.quantity = sb.quantity - NEW.quantity,
|
||||
sb.totalCost = sb.totalCost - (sb.avgCost * NEW.quantity),
|
||||
sb.updatedAt = NOW()
|
||||
WHERE
|
||||
sb.productId = NEW.productId
|
||||
AND sb.inventoryId = NEW.inventoryId;
|
||||
|
||||
ELSE
|
||||
INSERT INTO
|
||||
Stock_Balance (
|
||||
productId,
|
||||
inventoryId,
|
||||
quantity,
|
||||
totalCost,
|
||||
avgCost,
|
||||
updatedAt
|
||||
)
|
||||
VALUES (
|
||||
NEW.productId,
|
||||
NEW.inventoryId,
|
||||
- NEW.quantity,
|
||||
- COALESCE(NEW.unitPrice, 0) * NEW.quantity,
|
||||
COALESCE(NEW.unitPrice, 0),
|
||||
NOW()
|
||||
);
|
||||
|
||||
END IF;
|
||||
|
||||
END IF;
|
||||
|
||||
END IF;
|
||||
|
||||
END;
|
||||
|
||||
-- ------------------------------------------
|
||||
-- index: 15
|
||||
-- Trigger: trg_no_negative_available_stock
|
||||
-- Event: INSERT
|
||||
-- Table: Stock_Reservations
|
||||
-- ------------------------------------------
|
||||
DROP TRIGGER IF EXISTS `trg_no_negative_available_stock`;
|
||||
CREATE DEFINER=`pos`@`%` TRIGGER `trg_no_negative_available_stock` BEFORE INSERT ON `Stock_Reservations` FOR EACH ROW BEGIN
|
||||
DECLARE available DECIMAL(14,3);
|
||||
|
||||
SELECT availableQuantity
|
||||
INTO available
|
||||
FROM Stock_Available_View
|
||||
WHERE productId = NEW.productId
|
||||
AND inventoryId = NEW.inventoryId;
|
||||
|
||||
IF available < NEW.quantity THEN
|
||||
SIGNAL SQLSTATE '45000'
|
||||
SET MESSAGE_TEXT = 'موجودی کافی نیست';
|
||||
END IF;
|
||||
END;
|
||||
|
||||
@@ -1,825 +0,0 @@
|
||||
-- AUTO-GENERATED MYSQL TRIGGER DUMP
|
||||
-- Generated at: 2026-01-04T09:46:30.365Z
|
||||
|
||||
-- ------------------------------------------
|
||||
-- index: 1
|
||||
-- Trigger: trg_bank_account_transaction_after_insert
|
||||
-- Event: INSERT
|
||||
-- Table: Bank_Account_Transactions
|
||||
-- ------------------------------------------
|
||||
DROP TRIGGER IF EXISTS `trg_bank_account_transaction_after_insert`;
|
||||
|
||||
CREATE DEFINER=`pos`@`%` TRIGGER `trg_bank_account_transaction_after_insert` AFTER INSERT ON `Bank_Account_Transactions` FOR EACH ROW BEGIN
|
||||
IF NEW.type = 'DEPOSIT' THEN
|
||||
UPDATE Bank_Account_Balance SET balance = balance + NEW.amount WHERE bankAccountId = NEW.bankAccountId;
|
||||
ELSEIF NEW.type = 'WITHDRAWAL' THEN
|
||||
UPDATE Bank_Account_Balance SET balance = balance - NEW.amount WHERE bankAccountId = NEW.bankAccountId;
|
||||
END IF;
|
||||
END;
|
||||
|
||||
-- ------------------------------------------
|
||||
-- index: 2
|
||||
-- Trigger: trg_bank_account_transaction_after_delete
|
||||
-- Event: DELETE
|
||||
-- Table: Bank_Account_Transactions
|
||||
-- ------------------------------------------
|
||||
DROP TRIGGER IF EXISTS `trg_bank_account_transaction_after_delete`;
|
||||
|
||||
CREATE DEFINER=`pos`@`%` TRIGGER `trg_bank_account_transaction_after_delete` AFTER DELETE ON `Bank_Account_Transactions` FOR EACH ROW BEGIN
|
||||
UPDATE Bank_Accounts SET balance = balance - OLD.amount;
|
||||
END;
|
||||
|
||||
-- ------------------------------------------
|
||||
-- index: 3
|
||||
-- Trigger: trg_transfer_item_after_insert
|
||||
-- Event: INSERT
|
||||
-- Table: Inventory_Transfer_Items
|
||||
-- ------------------------------------------
|
||||
DROP TRIGGER IF EXISTS `trg_transfer_item_after_insert`;
|
||||
|
||||
CREATE DEFINER=`pos`@`%` TRIGGER `trg_transfer_item_after_insert` AFTER INSERT ON `Inventory_Transfer_Items` FOR EACH ROW begin
|
||||
|
||||
DECLARE fromInv INT;
|
||||
DECLARE toInv INT;
|
||||
DECLARE _avgCost DECIMAL(10,2);
|
||||
DECLARE latestQuantityInOrigin DECIMAL(10,2);
|
||||
DECLARE latestQuantityInDestination DECIMAL(10,2);
|
||||
|
||||
SELECT fromInventoryId, toInventoryId INTO fromInv, toInv
|
||||
FROM Inventory_Transfers WHERE id = NEW.transferId;
|
||||
|
||||
SELECT COALESCE(avgCost, 0), COALESCE(quantity, 0) INTO _avgCost, latestQuantityInOrigin FROM Stock_Balance
|
||||
WHERE ProductId = NEW.productId AND inventoryId = fromInv LIMIT 1;
|
||||
|
||||
SELECT COALESCE(quantity, 0) INTO latestQuantityInDestination FROM Stock_Balance
|
||||
WHERE ProductId = NEW.productId AND inventoryId = toInv LIMIT 1;
|
||||
|
||||
|
||||
-- OUT from source
|
||||
INSERT INTO Stock_Movements
|
||||
(type, quantity, unitPrice, totalCost, avgCost, referenceType, referenceId, productId, inventoryId, counterInventoryId, createdAt, remainedInStock)
|
||||
VALUES
|
||||
('OUT', NEW.count, _avgCost, _avgCost*NEW.count, _avgCost, 'INVENTORY_TRANSFER', NEW.transferId, NEW.productId, fromInv, toInv, NOW(), latestQuantityInOrigin-NEW.count);
|
||||
|
||||
-- IN to destination
|
||||
INSERT INTO Stock_Movements
|
||||
(type, quantity, unitPrice, totalCost, avgCost, referenceType, referenceId, productId, inventoryId, counterInventoryId, createdAt, remainedInStock)
|
||||
VALUES
|
||||
('IN', NEW.count,_avgCost, _avgCost*NEW.count,_avgCost, 'INVENTORY_TRANSFER', NEW.transferId, NEW.productId, toInv, fromInv, NOW(), latestQuantityInOrigin-NEW.count);
|
||||
end;
|
||||
|
||||
-- ------------------------------------------
|
||||
-- index: 4
|
||||
-- Trigger: trg_order_item_after_insert
|
||||
-- Event: INSERT
|
||||
-- Table: Order_Items
|
||||
-- ------------------------------------------
|
||||
DROP TRIGGER IF EXISTS `trg_order_item_after_insert`;
|
||||
|
||||
CREATE DEFINER=`pos`@`%` TRIGGER `trg_order_item_after_insert` AFTER INSERT ON `Order_Items` FOR EACH ROW BEGIN
|
||||
UPDATE Stock_Reservations SET quantity = quantity + NEW.quantity
|
||||
WHERE orderId = NEW.orderId AND productId = NEW.productId;
|
||||
END;
|
||||
|
||||
-- ------------------------------------------
|
||||
-- index: 5
|
||||
-- Trigger: trg_order_item_after_update
|
||||
-- Event: UPDATE
|
||||
-- Table: Order_Items
|
||||
-- ------------------------------------------
|
||||
DROP TRIGGER IF EXISTS `trg_order_item_after_update`;
|
||||
|
||||
CREATE DEFINER=`pos`@`%` TRIGGER `trg_order_item_after_update` AFTER UPDATE ON `Order_Items` FOR EACH ROW BEGIN
|
||||
UPDATE Stock_Reservations
|
||||
SET quantity = quantity - OLD.quantity + NEW.quantity
|
||||
WHERE orderId = NEW.orderId AND productId = NEW.productId;
|
||||
END;
|
||||
|
||||
-- ------------------------------------------
|
||||
-- index: 6
|
||||
-- Trigger: trg_order_item_after_delete
|
||||
-- Event: DELETE
|
||||
-- Table: Order_Items
|
||||
-- ------------------------------------------
|
||||
DROP TRIGGER IF EXISTS `trg_order_item_after_delete`;
|
||||
|
||||
CREATE DEFINER=`pos`@`%` TRIGGER `trg_order_item_after_delete` AFTER DELETE ON `Order_Items` FOR EACH ROW BEGIN
|
||||
UPDATE Stock_Reservations SET quantity = quantity - OLD.quantity
|
||||
WHERE orderId = OLD.orderId AND productId = OLD.productId;
|
||||
|
||||
END;
|
||||
|
||||
-- ------------------------------------------
|
||||
-- index: 7
|
||||
-- Trigger: trg_order_after_cancel
|
||||
-- Event: UPDATE
|
||||
-- Table: Orders
|
||||
-- ------------------------------------------
|
||||
DROP TRIGGER IF EXISTS `trg_order_after_cancel`;
|
||||
|
||||
CREATE DEFINER=`pos`@`%` TRIGGER `trg_order_after_cancel` AFTER UPDATE ON `Orders` FOR EACH ROW BEGIN
|
||||
IF NEW.status = 'CANCELED' OR NEW.status = 'REJECTED' OR NEW.status = 'DONE' THEN
|
||||
UPDATE Stock_Reservations sr SET quantity = 0
|
||||
WHERE sr.orderId = NEW.id;
|
||||
END IF;
|
||||
END;
|
||||
|
||||
-- ------------------------------------------
|
||||
-- index: 8
|
||||
-- Trigger: trg_purchase_receipt_item_after_insert
|
||||
-- Event: INSERT
|
||||
-- Table: Purchase_Receipt_Items
|
||||
-- ------------------------------------------
|
||||
DROP TRIGGER IF EXISTS `trg_purchase_receipt_item_after_insert`;
|
||||
|
||||
CREATE DEFINER=`pos`@`%` TRIGGER `trg_purchase_receipt_item_after_insert` AFTER INSERT ON `Purchase_Receipt_Items` FOR EACH ROW BEGIN DECLARE latestQuantity DECIMAL(10, 2) DEFAULT 0;
|
||||
|
||||
DECLARE invId INT;
|
||||
DECLARE suppId INT;
|
||||
|
||||
-- Get inventory & supplier from
|
||||
SELECT inventoryId, supplierId
|
||||
INTO invId, suppId
|
||||
FROM Purchase_Receipts
|
||||
WHERE id = NEW.receiptId;
|
||||
|
||||
-- Get current stock quantity (if exists)
|
||||
SELECT COALESCE(quantity, 0)
|
||||
INTO latestQuantity
|
||||
FROM Stock_Balance sb
|
||||
WHERE sb.inventoryId = invId
|
||||
AND sb.productId = NEW.productId
|
||||
LIMIT 1;
|
||||
|
||||
-- Insert stock movement
|
||||
INSERT INTO Stock_Movements (
|
||||
type,
|
||||
quantity,
|
||||
unitPrice,
|
||||
totalCost,
|
||||
referenceType,
|
||||
referenceId,
|
||||
productId,
|
||||
inventoryId,
|
||||
avgCost,
|
||||
supplierId,
|
||||
remainedInStock,
|
||||
createdAt
|
||||
)
|
||||
VALUES (
|
||||
'IN',
|
||||
NEW.count,
|
||||
NEW.unitPrice,
|
||||
NEW.totalAmount,
|
||||
'PURCHASE',
|
||||
NEW.receiptId,
|
||||
NEW.productId,
|
||||
invId,
|
||||
CASE
|
||||
WHEN NEW.count = 0 THEN 0
|
||||
ELSE NEW.totalAmount / NEW.count
|
||||
END
|
||||
|
||||
,
|
||||
suppId,
|
||||
latestQuantity + NEW.count,
|
||||
NOW()
|
||||
);
|
||||
|
||||
END;
|
||||
|
||||
-- ------------------------------------------
|
||||
-- index: 9
|
||||
-- Trigger: trg_pr_payment_before_insert
|
||||
-- Event: INSERT
|
||||
-- Table: Purchase_Receipt_Payments
|
||||
-- ------------------------------------------
|
||||
DROP TRIGGER IF EXISTS `trg_pr_payment_before_insert`;
|
||||
|
||||
CREATE DEFINER=`pos`@`%` TRIGGER `trg_pr_payment_before_insert` BEFORE INSERT ON `Purchase_Receipt_Payments` FOR EACH ROW BEGIN
|
||||
|
||||
|
||||
DECLARE receiptTotal DECIMAL(14,2);
|
||||
DECLARE paid DECIMAL(14,2);
|
||||
|
||||
|
||||
SELECT totalAmount, paidAmount
|
||||
INTO receiptTotal, paid
|
||||
FROM Purchase_Receipts
|
||||
WHERE id = NEW.receiptId
|
||||
FOR UPDATE;
|
||||
|
||||
IF NEW.type = 'PAYMENT' AND paid + NEW.amount > receiptTotal THEN
|
||||
SIGNAL SQLSTATE '45000'
|
||||
SET MESSAGE_TEXT = 'مجموع مبلغ پرداختی بیشتر از مبلغ فاکتور است.';
|
||||
END IF;
|
||||
END;
|
||||
|
||||
-- ------------------------------------------
|
||||
-- index: 10
|
||||
-- Trigger: trg_purchase_payment_update_receipt
|
||||
-- Event: INSERT
|
||||
-- Table: Purchase_Receipt_Payments
|
||||
-- ------------------------------------------
|
||||
DROP TRIGGER IF EXISTS `trg_purchase_payment_update_receipt`;
|
||||
|
||||
CREATE DEFINER=`pos`@`%` TRIGGER `trg_purchase_payment_update_receipt` AFTER INSERT ON `Purchase_Receipt_Payments` FOR EACH ROW BEGIN
|
||||
DECLARE paid DECIMAL(15,2);
|
||||
DECLARE total DECIMAL(15,2);
|
||||
|
||||
SELECT
|
||||
COALESCE(SUM(
|
||||
CASE WHEN type = 'PAYMENT' THEN amount ELSE -amount END
|
||||
),0)
|
||||
INTO paid
|
||||
FROM Purchase_Receipt_Payments
|
||||
WHERE receiptId = NEW.receiptId;
|
||||
|
||||
SELECT totalAmount INTO total
|
||||
FROM Purchase_Receipts
|
||||
WHERE id = NEW.receiptId;
|
||||
|
||||
UPDATE Purchase_Receipts
|
||||
SET
|
||||
paidAmount = paid,
|
||||
status = CASE
|
||||
WHEN paid = 0 THEN 'UNPAID'
|
||||
WHEN paid < total THEN 'PARTIALLY_PAID'
|
||||
ELSE 'PAID'
|
||||
END
|
||||
WHERE id = NEW.receiptId;
|
||||
END;
|
||||
|
||||
-- ------------------------------------------
|
||||
-- index: 11
|
||||
-- Trigger: trg_purchase_payment_after_insert
|
||||
-- Event: INSERT
|
||||
-- Table: Purchase_Receipt_Payments
|
||||
-- ------------------------------------------
|
||||
DROP TRIGGER IF EXISTS `trg_purchase_payment_after_insert`;
|
||||
|
||||
CREATE DEFINER=`pos`@`%` TRIGGER `trg_purchase_payment_after_insert` AFTER INSERT ON `Purchase_Receipt_Payments` FOR EACH ROW BEGIN
|
||||
|
||||
DECLARE currentBalance DECIMAL(15, 2);
|
||||
|
||||
|
||||
SELECT balance INTO currentBalance
|
||||
FROM Bank_Account_Balance
|
||||
WHERE
|
||||
bankAccountId = NEW.bankAccountId FOR
|
||||
UPDATE;
|
||||
|
||||
|
||||
IF currentBalance IS NULL THEN SET currentBalance = 0;
|
||||
|
||||
|
||||
INSERT INTO
|
||||
Bank_Account_Balance (bankAccountId, balance, updatedAt)
|
||||
VALUES (NEW.bankAccountId, 0, NOW());
|
||||
|
||||
END IF;
|
||||
|
||||
IF NEW.type = 'PAYMENT' THEN
|
||||
SET
|
||||
currentBalance = currentBalance - NEW.amount;
|
||||
|
||||
INSERT INTO
|
||||
Bank_Account_Transactions (
|
||||
bankAccountId,
|
||||
type,
|
||||
amount,
|
||||
balanceAfter,
|
||||
referenceType,
|
||||
referenceId
|
||||
)
|
||||
VALUES (
|
||||
NEW.bankAccountId,
|
||||
'WITHDRAWAL',
|
||||
NEW.amount,
|
||||
currentBalance,
|
||||
'PURCHASE_PAYMENT',
|
||||
NEW.id
|
||||
);
|
||||
|
||||
ELSE SET currentBalance = currentBalance + NEW.amount;
|
||||
|
||||
INSERT INTO
|
||||
Bank_Account_Transactions (
|
||||
bankAccountId,
|
||||
type,
|
||||
amount,
|
||||
balanceAfter,
|
||||
referenceType,
|
||||
referenceId
|
||||
)
|
||||
VALUES (
|
||||
NEW.bankAccountId,
|
||||
'DEPOSIT',
|
||||
NEW.amount,
|
||||
currentBalance,
|
||||
'PURCHASE_REFUND',
|
||||
NEW.id
|
||||
);
|
||||
|
||||
END IF;
|
||||
|
||||
UPDATE Bank_Account_Balance
|
||||
SET
|
||||
balance = currentBalance
|
||||
WHERE
|
||||
bankAccountId = NEW.bankAccountId;
|
||||
|
||||
END;
|
||||
|
||||
-- ------------------------------------------
|
||||
-- index: 12
|
||||
-- Trigger: trg_pr_payment_after_insert
|
||||
-- Event: INSERT
|
||||
-- Table: Purchase_Receipt_Payments
|
||||
-- ------------------------------------------
|
||||
DROP TRIGGER IF EXISTS `trg_pr_payment_after_insert`;
|
||||
|
||||
CREATE DEFINER=`pos`@`%` TRIGGER `trg_pr_payment_after_insert` AFTER INSERT ON `Purchase_Receipt_Payments` FOR EACH ROW BEGIN
|
||||
DECLARE receiptTotal DECIMAL(14,2) Default 0;
|
||||
DECLARE newPaid DECIMAL(14,2) Default 0;
|
||||
DECLARE _supplierId INT;
|
||||
DECLARE lastBalance DECIMAL(14,2) Default 0;
|
||||
|
||||
|
||||
-- Lock receipt row
|
||||
SELECT COALESCE(totalAmount, 0), COALESCE(paidAmount, 0), supplierId
|
||||
INTO receiptTotal, newPaid, _supplierId
|
||||
FROM Purchase_Receipts
|
||||
WHERE id = NEW.receiptId
|
||||
FOR UPDATE;
|
||||
|
||||
-- Apply payment or refund
|
||||
IF NEW.type = 'PAYMENT' THEN
|
||||
SET newPaid = newPaid + NEW.amount;
|
||||
ELSE
|
||||
SET newPaid = newPaid - NEW.amount;
|
||||
END IF;
|
||||
|
||||
-- Update receipt
|
||||
UPDATE Purchase_Receipts
|
||||
SET
|
||||
paidAmount = newPaid,
|
||||
status =
|
||||
CASE
|
||||
WHEN newPaid = 0 THEN 'UNPAID'
|
||||
WHEN newPaid < receiptTotal THEN 'PARTIALLY_PAID'
|
||||
ELSE 'PAID'
|
||||
END
|
||||
WHERE id = NEW.receiptId;
|
||||
|
||||
-- Get last supplier balance
|
||||
SELECT IFNULL(balance, 0)
|
||||
INTO lastBalance
|
||||
FROM Supplier_Ledger
|
||||
WHERE supplierId = _supplierId
|
||||
ORDER BY id DESC
|
||||
LIMIT 1;
|
||||
|
||||
|
||||
|
||||
-- Insert supplier ledger
|
||||
INSERT INTO Supplier_Ledger
|
||||
(
|
||||
supplierId,
|
||||
debit,
|
||||
credit,
|
||||
balance,
|
||||
sourceType,
|
||||
sourceId,
|
||||
createdAt
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
_supplierId,
|
||||
IF(NEW.type = 'REFUND', NEW.amount, 0),
|
||||
IF(NEW.type = 'PAYMENT', NEW.amount, 0),
|
||||
lastBalance
|
||||
+ IF(NEW.type = 'PAYMENT', NEW.amount, 0)
|
||||
- IF(NEW.type = 'REFUND', NEW.amount, 0),
|
||||
'PAYMENT',
|
||||
NEW.id,
|
||||
NOW()
|
||||
);
|
||||
END;
|
||||
|
||||
-- ------------------------------------------
|
||||
-- index: 13
|
||||
-- Trigger: trg_pr_payment_after_delete
|
||||
-- Event: DELETE
|
||||
-- Table: Purchase_Receipt_Payments
|
||||
-- ------------------------------------------
|
||||
DROP TRIGGER IF EXISTS `trg_pr_payment_after_delete`;
|
||||
|
||||
CREATE DEFINER=`pos`@`%` TRIGGER `trg_pr_payment_after_delete` AFTER DELETE ON `Purchase_Receipt_Payments` FOR EACH ROW BEGIN
|
||||
DECLARE receiptTotal DECIMAL(14,2);
|
||||
DECLARE newPaid DECIMAL(14,2);
|
||||
|
||||
SELECT totalAmount, paidAmount
|
||||
INTO receiptTotal, newPaid
|
||||
FROM Purchase_Receipts
|
||||
WHERE id = OLD.receiptId
|
||||
FOR UPDATE;
|
||||
|
||||
IF OLD.type = 'PAYMENT' THEN
|
||||
SET newPaid = newPaid - OLD.amount;
|
||||
ELSE
|
||||
SET newPaid = newPaid + OLD.amount;
|
||||
END IF;
|
||||
|
||||
UPDATE Purchase_Receipts
|
||||
SET
|
||||
paidAmount = newPaid,
|
||||
status =
|
||||
CASE
|
||||
WHEN newPaid = 0 THEN 'UNPAID'
|
||||
WHEN newPaid < receiptTotal THEN 'PARTIALLY_PAID'
|
||||
ELSE 'PAID'
|
||||
END
|
||||
WHERE id = OLD.receiptId;
|
||||
END;
|
||||
|
||||
-- ------------------------------------------
|
||||
-- index: 14
|
||||
-- Trigger: trg_purchase_receipt_after_insert
|
||||
-- Event: INSERT
|
||||
-- Table: Purchase_Receipts
|
||||
-- ------------------------------------------
|
||||
DROP TRIGGER IF EXISTS `trg_purchase_receipt_after_insert`;
|
||||
|
||||
CREATE DEFINER=`pos`@`%` TRIGGER `trg_purchase_receipt_after_insert` AFTER INSERT ON `Purchase_Receipts` FOR EACH ROW BEGIN
|
||||
DECLARE lastBalance DECIMAL(14,2) DEFAULT 0;
|
||||
|
||||
SELECT COALESCE(balance, 0)
|
||||
INTO lastBalance
|
||||
FROM Supplier_Ledger
|
||||
WHERE supplierId = NEW.supplierId
|
||||
ORDER BY id DESC
|
||||
LIMIT 1;
|
||||
|
||||
INSERT INTO Supplier_Ledger
|
||||
(
|
||||
supplierId,
|
||||
debit,
|
||||
credit,
|
||||
balance,
|
||||
sourceType,
|
||||
sourceId,
|
||||
createdAt
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
NEW.supplierId,
|
||||
NEW.totalAmount,
|
||||
0,
|
||||
lastBalance - NEW.totalAmount,
|
||||
'PURCHASE',
|
||||
NEW.id,
|
||||
NOW()
|
||||
);
|
||||
END;
|
||||
|
||||
-- ------------------------------------------
|
||||
-- index: 15
|
||||
-- Trigger: trg_sales_invoice_items_before_insert
|
||||
-- Event: INSERT
|
||||
-- Table: Sales_Invoice_Items
|
||||
-- ------------------------------------------
|
||||
DROP TRIGGER IF EXISTS `trg_sales_invoice_items_before_insert`;
|
||||
|
||||
CREATE DEFINER=`pos`@`%` TRIGGER `trg_sales_invoice_items_before_insert` BEFORE INSERT ON `Sales_Invoice_Items` FOR EACH ROW BEGIN
|
||||
|
||||
DECLARE current_stock DECIMAL(10, 2);
|
||||
DECLARE inventory_id INT;
|
||||
|
||||
|
||||
|
||||
SELECT pa.inventoryId INTO inventory_id
|
||||
FROM Pos_Accounts pa
|
||||
INNER JOIN Sales_Invoices si ON pa.id = si.posAccountId
|
||||
WHERE si.id = NEW.invoiceId;
|
||||
|
||||
|
||||
SELECT COALESCE(quantity, 0) INTO current_stock
|
||||
FROM Stock_Balance sb
|
||||
WHERE productId = NEW.productId AND sb.inventoryId = inventory_id
|
||||
LIMIT 1;
|
||||
|
||||
|
||||
|
||||
IF NEW.count > current_stock THEN
|
||||
SIGNAL SQLSTATE '45000'
|
||||
SET MESSAGE_TEXT = 'موجودی کالا در انبار کافی نیست.';
|
||||
END IF;
|
||||
end;
|
||||
|
||||
-- ------------------------------------------
|
||||
-- index: 16
|
||||
-- Trigger: trg_sales_invoice_items_after_insert
|
||||
-- Event: INSERT
|
||||
-- Table: Sales_Invoice_Items
|
||||
-- ------------------------------------------
|
||||
DROP TRIGGER IF EXISTS `trg_sales_invoice_items_after_insert`;
|
||||
|
||||
CREATE DEFINER=`pos`@`%` TRIGGER `trg_sales_invoice_items_after_insert` AFTER INSERT ON `Sales_Invoice_Items` FOR EACH ROW begin DECLARE current_stock DECIMAL(10, 2);
|
||||
|
||||
DECLARE inventory_id INT;
|
||||
DECLARE customer_id INT;
|
||||
DECLARE pos_id INT;
|
||||
|
||||
|
||||
|
||||
SELECT posAccountId, customerId INTO pos_id, customer_id
|
||||
FROM Sales_Invoices si
|
||||
WHERE si.id = NEW.invoiceId
|
||||
LIMIT 1;
|
||||
INSERT INTO Trigger_Logs (name , message) VALUES ('pos_id', pos_id);
|
||||
INSERT INTO Trigger_Logs (name , message) VALUES ('customer_id', customer_id);
|
||||
|
||||
|
||||
SELECT pa.inventoryId INTO inventory_id
|
||||
FROM Pos_Accounts pa
|
||||
INNER JOIN Sales_Invoices si ON pa.id = si.posAccountId
|
||||
WHERE si.id = NEW.invoiceId;
|
||||
|
||||
|
||||
|
||||
SELECT COALESCE(quantity, 0) INTO current_stock
|
||||
FROM Stock_Balance sb
|
||||
WHERE productId = NEW.productId AND sb.inventoryId = inventory_id
|
||||
LIMIT 1;
|
||||
|
||||
|
||||
|
||||
INSERT INTO Stock_Movements (
|
||||
type,
|
||||
quantity,
|
||||
unitPrice,
|
||||
totalCost,
|
||||
referenceType,
|
||||
referenceId,
|
||||
productId,
|
||||
inventoryId,
|
||||
avgCost,
|
||||
remainedInStock,
|
||||
customerId,
|
||||
createdAt
|
||||
)
|
||||
VALUES (
|
||||
'OUT',
|
||||
NEW.count,
|
||||
NEW.unitPrice,
|
||||
NEW.totalAmount,
|
||||
'SALES',
|
||||
NEW.invoiceId,
|
||||
NEW.productId,
|
||||
inventory_id,
|
||||
|
||||
CASE
|
||||
WHEN NEW.count = 0 THEN 0
|
||||
ELSE NEW.totalAmount / NEW.count
|
||||
END,
|
||||
current_stock - NEW.count,
|
||||
customer_id,
|
||||
NOW()
|
||||
);
|
||||
|
||||
|
||||
END;
|
||||
|
||||
-- ------------------------------------------
|
||||
-- index: 17
|
||||
-- Trigger: trg_sales_invoice_payment_after_insert
|
||||
-- Event: INSERT
|
||||
-- Table: Sales_Invoice_Payments
|
||||
-- ------------------------------------------
|
||||
DROP TRIGGER IF EXISTS `trg_sales_invoice_payment_after_insert`;
|
||||
|
||||
CREATE DEFINER=`pos`@`%` TRIGGER `trg_sales_invoice_payment_after_insert` AFTER INSERT ON `Sales_Invoice_Payments` FOR EACH ROW BEGIN
|
||||
DECLARE currentBalance DECIMAL(15,2);
|
||||
DECLARE bankAccountId INT;
|
||||
|
||||
SELECT pa.bankAccountId INTO bankAccountId
|
||||
FROM Pos_Accounts pa
|
||||
INNER JOIN Sales_Invoices si ON pa.id = si.posAccountId
|
||||
WHERE si.id = NEW.invoiceId;
|
||||
|
||||
SELECT balance INTO currentBalance
|
||||
FROM Bank_Account_Balance
|
||||
WHERE bankAccountId = bankAccountId
|
||||
FOR UPDATE;
|
||||
|
||||
IF currentBalance IS NULL THEN
|
||||
SET currentBalance = 0;
|
||||
INSERT INTO Bank_Account_Balance (bankAccountId, balance)
|
||||
VALUES (bankAccountId, 0);
|
||||
END IF;
|
||||
|
||||
SET currentBalance = currentBalance + NEW.amount;
|
||||
|
||||
INSERT INTO Bank_Account_Transactions
|
||||
(bankAccountId, type, amount, balanceAfter, referenceType, referenceId)
|
||||
VALUES
|
||||
(bankAccountId, 'DEPOSIT', NEW.amount, currentBalance, 'POS_SALE', NEW.id);
|
||||
|
||||
UPDATE Bank_Account_Balance
|
||||
SET balance = currentBalance
|
||||
WHERE bankAccountId = bankAccountId;
|
||||
END;
|
||||
|
||||
-- ------------------------------------------
|
||||
-- index: 18
|
||||
-- Trigger: trg_pos_account_payment_after_insert
|
||||
-- Event: INSERT
|
||||
-- Table: Sales_Invoice_Payments
|
||||
-- ------------------------------------------
|
||||
DROP TRIGGER IF EXISTS `trg_pos_account_payment_after_insert`;
|
||||
|
||||
CREATE DEFINER=`pos`@`%` TRIGGER `trg_pos_account_payment_after_insert` AFTER INSERT ON `Sales_Invoice_Payments` FOR EACH ROW BEGIN
|
||||
|
||||
DECLARE _bankAccountId INT;
|
||||
|
||||
IF(NEW.paymentMethod != 'CASH') THEN
|
||||
SELECT cashBankAccountId INTO _bankAccountId
|
||||
FROM Pos_Accounts pa
|
||||
INNER JOIN Sales_Invoices si ON pa.id = si.posAccountId
|
||||
WHERE si.id = NEW.invoiceId;
|
||||
End IF;
|
||||
|
||||
INSERT INTO Bank_Account_Transactions (
|
||||
bankAccountId,
|
||||
type,
|
||||
amount,
|
||||
balanceAfter,
|
||||
referenceType,
|
||||
referenceId
|
||||
)
|
||||
VALUES(
|
||||
_bankAccountId,
|
||||
'DEPOSIT',
|
||||
NEW.amount,
|
||||
0,
|
||||
'POS_SALE',
|
||||
NEW.id
|
||||
);
|
||||
END;
|
||||
|
||||
-- ------------------------------------------
|
||||
-- index: 19
|
||||
-- Trigger: trg_stock_transfer
|
||||
-- Event: INSERT
|
||||
-- Table: Stock_Movements
|
||||
-- ------------------------------------------
|
||||
DROP TRIGGER IF EXISTS `trg_stock_transfer`;
|
||||
|
||||
CREATE DEFINER=`pos`@`%` TRIGGER `trg_stock_transfer` AFTER INSERT ON `Stock_Movements` FOR EACH ROW BEGIN IF NEW.referenceType = 'INVENTORY_TRANSFER' THEN IF NEW.type = 'IN' THEN
|
||||
INSERT INTO
|
||||
Stock_Balance (
|
||||
productId,
|
||||
inventoryId,
|
||||
quantity,
|
||||
totalCost,
|
||||
avgCost,
|
||||
updatedAt
|
||||
)
|
||||
VALUES (
|
||||
NEW.productId,
|
||||
NEW.inventoryId,
|
||||
NEW.quantity,
|
||||
NEW.totalCost,
|
||||
CASE
|
||||
WHEN NEW.quantity = 0 THEN 0
|
||||
ELSE NEW.totalCost / NEW.quantity
|
||||
END,
|
||||
NOW()
|
||||
)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
quantity = quantity + NEW.quantity,
|
||||
totalCost = totalCost + NEW.totalCost,
|
||||
avgCost = CASE
|
||||
WHEN (quantity + NEW.quantity) = 0 THEN 0
|
||||
ELSE (totalCost + NEW.totalCost) / (quantity + NEW.quantity)
|
||||
END,
|
||||
updatedAt = NOW();
|
||||
|
||||
END IF;
|
||||
|
||||
IF NEW.type = 'OUT' THEN IF EXISTS (
|
||||
SELECT 1
|
||||
FROM Stock_Balance sb
|
||||
WHERE
|
||||
sb.productId = NEW.productId
|
||||
AND sb.inventoryId = NEW.inventoryId
|
||||
) THEN
|
||||
|
||||
UPDATE Stock_Balance sb
|
||||
SET
|
||||
sb.quantity = sb.quantity - NEW.quantity,
|
||||
sb.totalCost = sb.totalCost - (sb.avgCost * NEW.quantity),
|
||||
sb.updatedAt = NOW()
|
||||
WHERE
|
||||
sb.productId = NEW.productId
|
||||
AND sb.inventoryId = NEW.inventoryId;
|
||||
|
||||
ELSE
|
||||
INSERT INTO
|
||||
Stock_Balance (
|
||||
productId,
|
||||
inventoryId,
|
||||
quantity,
|
||||
totalCost,
|
||||
avgCost,
|
||||
updatedAt
|
||||
)
|
||||
VALUES (
|
||||
NEW.productId,
|
||||
NEW.inventoryId,
|
||||
- NEW.quantity,
|
||||
- COALESCE(NEW.unitPrice, 0) * NEW.quantity,
|
||||
COALESCE(NEW.unitPrice, 0),
|
||||
NOW()
|
||||
);
|
||||
|
||||
END IF;
|
||||
|
||||
END IF;
|
||||
|
||||
END IF;
|
||||
|
||||
END;
|
||||
|
||||
-- ------------------------------------------
|
||||
-- index: 20
|
||||
-- Trigger: trg_stock_purchase_insert
|
||||
-- Event: INSERT
|
||||
-- Table: Stock_Movements
|
||||
-- ------------------------------------------
|
||||
DROP TRIGGER IF EXISTS `trg_stock_purchase_insert`;
|
||||
|
||||
CREATE DEFINER=`pos`@`%` TRIGGER `trg_stock_purchase_insert` AFTER INSERT ON `Stock_Movements` FOR EACH ROW BEGIN IF NEW.referenceType = 'PURCHASE' THEN
|
||||
|
||||
INSERT INTO
|
||||
Stock_Balance (
|
||||
productId,
|
||||
quantity,
|
||||
avgCost,
|
||||
totalCost,
|
||||
inventoryId,
|
||||
updatedAt
|
||||
)
|
||||
VALUES (
|
||||
NEW.productId,
|
||||
NEW.quantity,
|
||||
NEW.unitPrice,
|
||||
NEW.totalCost,
|
||||
NEW.inventoryId,
|
||||
NOW()
|
||||
)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
quantity = quantity + NEW.quantity,
|
||||
totalCost = totalCost + NEW.totalCost,
|
||||
avgCost = totalCost / quantity;
|
||||
|
||||
END IF;
|
||||
|
||||
END;
|
||||
|
||||
-- ------------------------------------------
|
||||
-- index: 21
|
||||
-- Trigger: trg_stock_sale_insert
|
||||
-- Event: INSERT
|
||||
-- Table: Stock_Movements
|
||||
-- ------------------------------------------
|
||||
DROP TRIGGER IF EXISTS `trg_stock_sale_insert`;
|
||||
|
||||
CREATE DEFINER=`pos`@`%` TRIGGER `trg_stock_sale_insert` AFTER INSERT ON `Stock_Movements` FOR EACH ROW BEGIN IF NEW.referenceType = 'SALES' THEN
|
||||
|
||||
INSERT INTO
|
||||
Stock_Balance (
|
||||
productId,
|
||||
quantity,
|
||||
avgCost,
|
||||
totalCost,
|
||||
inventoryId,
|
||||
updatedAt
|
||||
)
|
||||
VALUES (
|
||||
NEW.productId,
|
||||
NEW.quantity,
|
||||
NEW.unitPrice,
|
||||
NEW.totalCost,
|
||||
NEW.inventoryId,
|
||||
NOW()
|
||||
)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
quantity = quantity - NEW.quantity,
|
||||
totalCost = totalCost - NEW.totalCost,
|
||||
avgCost = totalCost / quantity;
|
||||
|
||||
END IF;
|
||||
|
||||
END;
|
||||
@@ -1,657 +0,0 @@
|
||||
-- Stored Procedures equivalent to triggers
|
||||
|
||||
DELIMITER / /
|
||||
|
||||
-- Procedure for trg_bank_account_transaction_after_insert
|
||||
CREATE PROCEDURE update_bank_balance(IN p_bankAccountId INT, IN p_type VARCHAR(20), IN p_amount DECIMAL(15,2))
|
||||
BEGIN
|
||||
START TRANSACTION;
|
||||
IF p_type = 'DEPOSIT' THEN
|
||||
UPDATE Bank_Account_Balance SET balance = balance + p_amount WHERE bankAccountId = p_bankAccountId;
|
||||
ELSEIF p_type = 'WITHDRAWAL' THEN
|
||||
UPDATE Bank_Account_Balance SET balance = balance - p_amount WHERE bankAccountId = p_bankAccountId;
|
||||
END IF;
|
||||
COMMIT;
|
||||
END //
|
||||
|
||||
-- Procedure for trg_bank_account_transaction_after_delete
|
||||
CREATE PROCEDURE update_bank_balance_on_delete(IN p_bankAccountId INT, IN p_amount DECIMAL(15,2))
|
||||
BEGIN
|
||||
START TRANSACTION;
|
||||
UPDATE Bank_Accounts SET balance = balance - p_amount WHERE id = p_bankAccountId;
|
||||
COMMIT;
|
||||
END //
|
||||
|
||||
-- Procedure for trg_transfer_item_after_insert
|
||||
CREATE PROCEDURE process_transfer_item(IN p_transferId INT, IN p_productId INT, IN p_count DECIMAL(10,2))
|
||||
BEGIN
|
||||
START TRANSACTION;
|
||||
DECLARE fromInv INT;
|
||||
DECLARE toInv INT;
|
||||
DECLARE _avgCost DECIMAL(10,2);
|
||||
DECLARE latestQuantityInOrigin DECIMAL(10,2);
|
||||
DECLARE latestQuantityInDestination DECIMAL(10,2);
|
||||
|
||||
SELECT fromInventoryId, toInventoryId INTO fromInv, toInv
|
||||
FROM Inventory_Transfers WHERE id = p_transferId;
|
||||
|
||||
SELECT COALESCE(avgCost, 0), COALESCE(quantity, 0) INTO _avgCost, latestQuantityInOrigin FROM Stock_Balance
|
||||
WHERE ProductId = p_productId AND inventoryId = fromInv LIMIT 1;
|
||||
|
||||
SELECT COALESCE(quantity, 0) INTO latestQuantityInDestination FROM Stock_Balance
|
||||
WHERE ProductId = p_productId AND inventoryId = toInv LIMIT 1;
|
||||
|
||||
-- OUT from source
|
||||
INSERT INTO Stock_Movements
|
||||
(type, quantity, unitPrice, totalCost, avgCost, referenceType, referenceId, productId, inventoryId, counterInventoryId, createdAt, remainedInStock)
|
||||
VALUES
|
||||
('OUT', p_count, _avgCost, _avgCost*p_count, _avgCost, 'INVENTORY_TRANSFER', p_transferId, p_productId, fromInv, toInv, NOW(), latestQuantityInOrigin-p_count);
|
||||
|
||||
-- IN to destination
|
||||
INSERT INTO Stock_Movements
|
||||
(type, quantity, unitPrice, totalCost, avgCost, referenceType, referenceId, productId, inventoryId, counterInventoryId, createdAt, remainedInStock)
|
||||
VALUES
|
||||
('IN', p_count, _avgCost, _avgCost*p_count, _avgCost, 'INVENTORY_TRANSFER', p_transferId, p_productId, toInv, fromInv, NOW(), latestQuantityInOrigin-p_count);
|
||||
COMMIT;
|
||||
END //
|
||||
|
||||
-- Procedure for trg_order_item_after_insert
|
||||
CREATE PROCEDURE update_stock_reservation_insert(IN p_orderId INT, IN p_productId INT, IN p_quantity DECIMAL(10,2))
|
||||
BEGIN
|
||||
START TRANSACTION;
|
||||
UPDATE Stock_Reservations SET quantity = quantity + p_quantity
|
||||
WHERE orderId = p_orderId AND productId = p_productId;
|
||||
COMMIT;
|
||||
END //
|
||||
|
||||
-- Procedure for trg_order_item_after_update
|
||||
CREATE PROCEDURE update_stock_reservation_update(IN p_orderId INT, IN p_productId INT, IN p_old_quantity DECIMAL(10,2), IN p_new_quantity DECIMAL(10,2))
|
||||
BEGIN
|
||||
START TRANSACTION;
|
||||
UPDATE Stock_Reservations
|
||||
SET quantity = quantity - p_old_quantity + p_new_quantity
|
||||
WHERE orderId = p_orderId AND productId = p_productId;
|
||||
COMMIT;
|
||||
END //
|
||||
|
||||
-- Procedure for trg_order_item_after_delete
|
||||
CREATE PROCEDURE update_stock_reservation_delete(IN p_orderId INT, IN p_productId INT, IN p_quantity DECIMAL(10,2))
|
||||
BEGIN
|
||||
START TRANSACTION;
|
||||
UPDATE Stock_Reservations SET quantity = quantity - p_quantity
|
||||
WHERE orderId = p_orderId AND productId = p_productId;
|
||||
COMMIT;
|
||||
END //
|
||||
|
||||
-- Procedure for trg_order_after_cancel
|
||||
CREATE PROCEDURE cancel_order_stock(IN p_orderId INT, IN p_status VARCHAR(20))
|
||||
BEGIN
|
||||
START TRANSACTION;
|
||||
IF p_status = 'CANCELED' OR p_status = 'REJECTED' OR p_status = 'DONE' THEN
|
||||
UPDATE Stock_Reservations sr SET quantity = 0
|
||||
WHERE sr.orderId = p_orderId;
|
||||
END IF;
|
||||
COMMIT;
|
||||
END //
|
||||
|
||||
-- Procedure for trg_purchase_receipt_item_after_insert
|
||||
CREATE PROCEDURE process_purchase_item(IN p_receiptId INT, IN p_productId INT, IN p_count DECIMAL(10,2), IN p_unitPrice DECIMAL(15,2), IN p_totalAmount DECIMAL(15,2))
|
||||
BEGIN
|
||||
START TRANSACTION;
|
||||
DECLARE latestQuantity DECIMAL(10, 2) DEFAULT 0;
|
||||
DECLARE invId INT;
|
||||
DECLARE suppId INT;
|
||||
|
||||
-- Get inventory & supplier from
|
||||
SELECT inventoryId, supplierId
|
||||
INTO invId, suppId
|
||||
FROM Purchase_Receipts
|
||||
WHERE id = p_receiptId;
|
||||
|
||||
-- Get current stock quantity (if exists)
|
||||
SELECT COALESCE(quantity, 0)
|
||||
INTO latestQuantity
|
||||
FROM Stock_Balance sb
|
||||
WHERE sb.inventoryId = invId
|
||||
AND sb.productId = p_productId
|
||||
LIMIT 1;
|
||||
|
||||
-- Insert stock movement
|
||||
INSERT INTO Stock_Movements (
|
||||
type,
|
||||
quantity,
|
||||
unitPrice,
|
||||
totalCost,
|
||||
referenceType,
|
||||
referenceId,
|
||||
productId,
|
||||
inventoryId,
|
||||
avgCost,
|
||||
supplierId,
|
||||
remainedInStock,
|
||||
createdAt
|
||||
)
|
||||
VALUES (
|
||||
'IN',
|
||||
p_count,
|
||||
p_unitPrice,
|
||||
p_totalAmount,
|
||||
'PURCHASE',
|
||||
p_receiptId,
|
||||
p_productId,
|
||||
invId,
|
||||
CASE
|
||||
WHEN p_count = 0 THEN 0
|
||||
ELSE p_totalAmount / p_count
|
||||
END,
|
||||
suppId,
|
||||
latestQuantity + p_count,
|
||||
NOW()
|
||||
);
|
||||
COMMIT;
|
||||
END //
|
||||
|
||||
-- Procedure for trg_pr_payment_before_insert
|
||||
CREATE PROCEDURE validate_payment_before_insert(IN p_receiptId INT, IN p_type VARCHAR(20), IN p_amount DECIMAL(15,2))
|
||||
BEGIN
|
||||
START TRANSACTION;
|
||||
DECLARE receiptTotal DECIMAL(14,2);
|
||||
DECLARE paid DECIMAL(14,2);
|
||||
|
||||
SELECT totalAmount, paidAmount
|
||||
INTO receiptTotal, paid
|
||||
FROM Purchase_Receipts
|
||||
WHERE id = p_receiptId
|
||||
FOR UPDATE;
|
||||
|
||||
IF p_type = 'PAYMENT' AND paid + p_amount > receiptTotal THEN
|
||||
SIGNAL SQLSTATE '45000'
|
||||
SET MESSAGE_TEXT = 'مجموع مبلغ پرداختی بیشتر از مبلغ فاکتور است.';
|
||||
END IF;
|
||||
COMMIT;
|
||||
END //
|
||||
|
||||
-- Procedure for trg_purchase_payment_update_receipt
|
||||
CREATE PROCEDURE update_receipt_payment(IN p_receiptId INT)
|
||||
BEGIN
|
||||
START TRANSACTION;
|
||||
DECLARE paid DECIMAL(15,2);
|
||||
DECLARE total DECIMAL(15,2);
|
||||
|
||||
SELECT
|
||||
COALESCE(SUM(
|
||||
CASE WHEN type = 'PAYMENT' THEN amount ELSE -amount END
|
||||
),0)
|
||||
INTO paid
|
||||
FROM Purchase_Receipt_Payments
|
||||
WHERE receiptId = p_receiptId;
|
||||
|
||||
SELECT totalAmount INTO total
|
||||
FROM Purchase_Receipts
|
||||
WHERE id = p_receiptId;
|
||||
|
||||
UPDATE Purchase_Receipts
|
||||
SET
|
||||
paidAmount = paid,
|
||||
status = CASE
|
||||
WHEN paid = 0 THEN 'UNPAID'
|
||||
WHEN paid < total THEN 'PARTIALLY_PAID'
|
||||
ELSE 'PAID'
|
||||
END
|
||||
WHERE id = p_receiptId;
|
||||
COMMIT;
|
||||
END //
|
||||
|
||||
-- Procedure for trg_purchase_payment_after_insert
|
||||
CREATE PROCEDURE process_purchase_payment(IN p_bankAccountId INT, IN p_type VARCHAR(20), IN p_amount DECIMAL(15,2), IN p_id INT)
|
||||
BEGIN
|
||||
START TRANSACTION;
|
||||
DECLARE currentBalance DECIMAL(15, 2);
|
||||
|
||||
SELECT balance INTO currentBalance
|
||||
FROM Bank_Account_Balance
|
||||
WHERE bankAccountId = p_bankAccountId FOR UPDATE;
|
||||
|
||||
IF currentBalance IS NULL THEN SET currentBalance = 0;
|
||||
INSERT INTO Bank_Account_Balance (bankAccountId, balance, updatedAt)
|
||||
VALUES (p_bankAccountId, 0, NOW());
|
||||
END IF;
|
||||
|
||||
IF p_type = 'PAYMENT' THEN
|
||||
SET currentBalance = currentBalance - p_amount;
|
||||
INSERT INTO Bank_Account_Transactions (
|
||||
bankAccountId,
|
||||
type,
|
||||
amount,
|
||||
balanceAfter,
|
||||
referenceType,
|
||||
referenceId
|
||||
)
|
||||
VALUES (
|
||||
p_bankAccountId,
|
||||
'WITHDRAWAL',
|
||||
p_amount,
|
||||
currentBalance,
|
||||
'PURCHASE_PAYMENT',
|
||||
p_id
|
||||
);
|
||||
ELSE
|
||||
SET currentBalance = currentBalance + p_amount;
|
||||
INSERT INTO Bank_Account_Transactions (
|
||||
bankAccountId,
|
||||
type,
|
||||
amount,
|
||||
balanceAfter,
|
||||
referenceType,
|
||||
referenceId
|
||||
)
|
||||
VALUES (
|
||||
p_bankAccountId,
|
||||
'DEPOSIT',
|
||||
p_amount,
|
||||
currentBalance,
|
||||
'PURCHASE_REFUND',
|
||||
p_id
|
||||
);
|
||||
END IF;
|
||||
|
||||
UPDATE Bank_Account_Balance
|
||||
SET balance = currentBalance
|
||||
WHERE bankAccountId = p_bankAccountId;
|
||||
COMMIT;
|
||||
END //
|
||||
|
||||
-- Procedure for trg_pr_payment_after_insert
|
||||
CREATE PROCEDURE update_supplier_ledger(IN p_receiptId INT, IN p_type VARCHAR(20), IN p_amount DECIMAL(15,2), IN p_id INT)
|
||||
BEGIN
|
||||
START TRANSACTION;
|
||||
DECLARE receiptTotal DECIMAL(14,2) DEFAULT 0;
|
||||
DECLARE newPaid DECIMAL(14,2) DEFAULT 0;
|
||||
DECLARE _supplierId INT;
|
||||
DECLARE lastBalance DECIMAL(14,2) DEFAULT 0;
|
||||
|
||||
-- Lock receipt row
|
||||
SELECT COALESCE(totalAmount, 0), COALESCE(paidAmount, 0), supplierId
|
||||
INTO receiptTotal, newPaid, _supplierId
|
||||
FROM Purchase_Receipts
|
||||
WHERE id = p_receiptId
|
||||
FOR UPDATE;
|
||||
|
||||
-- Apply payment or refund
|
||||
IF p_type = 'PAYMENT' THEN
|
||||
SET newPaid = newPaid + p_amount;
|
||||
ELSE
|
||||
SET newPaid = newPaid - p_amount;
|
||||
END IF;
|
||||
|
||||
-- Update receipt
|
||||
UPDATE Purchase_Receipts
|
||||
SET
|
||||
paidAmount = newPaid,
|
||||
status =
|
||||
CASE
|
||||
WHEN newPaid = 0 THEN 'UNPAID'
|
||||
WHEN newPaid < receiptTotal THEN 'PARTIALLY_PAID'
|
||||
ELSE 'PAID'
|
||||
END
|
||||
WHERE id = p_receiptId;
|
||||
|
||||
-- Get last supplier balance
|
||||
SELECT IFNULL(balance, 0)
|
||||
INTO lastBalance
|
||||
FROM Supplier_Ledger
|
||||
WHERE supplierId = _supplierId
|
||||
ORDER BY id DESC
|
||||
LIMIT 1;
|
||||
|
||||
-- Insert supplier ledger
|
||||
INSERT INTO Supplier_Ledger
|
||||
(
|
||||
supplierId,
|
||||
debit,
|
||||
credit,
|
||||
balance,
|
||||
sourceType,
|
||||
sourceId,
|
||||
createdAt
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
_supplierId,
|
||||
IF(p_type = 'REFUND', p_amount, 0),
|
||||
IF(p_type = 'PAYMENT', p_amount, 0),
|
||||
lastBalance
|
||||
+ IF(p_type = 'PAYMENT', p_amount, 0)
|
||||
- IF(p_type = 'REFUND', p_amount, 0),
|
||||
'PAYMENT',
|
||||
p_id,
|
||||
NOW()
|
||||
);
|
||||
COMMIT;
|
||||
END //
|
||||
|
||||
-- Procedure for trg_pr_payment_after_delete
|
||||
CREATE PROCEDURE update_receipt_on_payment_delete(IN p_receiptId INT, IN p_type VARCHAR(20), IN p_amount DECIMAL(15,2))
|
||||
BEGIN
|
||||
DECLARE receiptTotal DECIMAL(14,2);
|
||||
DECLARE newPaid DECIMAL(14,2);
|
||||
|
||||
SELECT totalAmount, paidAmount
|
||||
INTO receiptTotal, newPaid
|
||||
FROM Purchase_Receipts
|
||||
WHERE id = p_receiptId
|
||||
FOR UPDATE;
|
||||
|
||||
IF p_type = 'PAYMENT' THEN
|
||||
SET newPaid = newPaid - p_amount;
|
||||
ELSE
|
||||
SET newPaid = newPaid + p_amount;
|
||||
END IF;
|
||||
|
||||
UPDATE Purchase_Receipts
|
||||
SET
|
||||
paidAmount = newPaid,
|
||||
status =
|
||||
CASE
|
||||
WHEN newPaid = 0 THEN 'UNPAID'
|
||||
WHEN newPaid < receiptTotal THEN 'PARTIALLY_PAID'
|
||||
ELSE 'PAID'
|
||||
END
|
||||
WHERE id = p_receiptId;
|
||||
END //
|
||||
|
||||
-- Procedure for trg_purchase_receipt_after_insert
|
||||
CREATE PROCEDURE insert_supplier_ledger_purchase(IN p_supplierId INT, IN p_totalAmount DECIMAL(15,2), IN p_id INT)
|
||||
BEGIN
|
||||
DECLARE lastBalance DECIMAL(14,2) DEFAULT 0;
|
||||
|
||||
SELECT COALESCE(balance, 0)
|
||||
INTO lastBalance
|
||||
FROM Supplier_Ledger
|
||||
WHERE supplierId = p_supplierId
|
||||
ORDER BY id DESC
|
||||
LIMIT 1;
|
||||
|
||||
INSERT INTO Supplier_Ledger
|
||||
(
|
||||
supplierId,
|
||||
debit,
|
||||
credit,
|
||||
balance,
|
||||
sourceType,
|
||||
sourceId,
|
||||
createdAt
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
p_supplierId,
|
||||
p_totalAmount,
|
||||
0,
|
||||
lastBalance - p_totalAmount,
|
||||
'PURCHASE',
|
||||
p_id,
|
||||
NOW()
|
||||
);
|
||||
END //
|
||||
|
||||
-- Procedure for trg_sales_invoice_items_before_insert
|
||||
CREATE PROCEDURE validate_stock_before_sale(IN p_invoiceId INT, IN p_productId INT, IN p_count DECIMAL(10,2))
|
||||
BEGIN
|
||||
DECLARE current_stock DECIMAL(10, 2);
|
||||
DECLARE inventory_id INT;
|
||||
|
||||
SELECT pa.inventoryId INTO inventory_id
|
||||
FROM Pos_Accounts pa
|
||||
INNER JOIN Sales_Invoices si ON pa.id = si.posAccountId
|
||||
WHERE si.id = p_invoiceId;
|
||||
|
||||
SELECT COALESCE(quantity, 0) INTO current_stock
|
||||
FROM Stock_Balance sb
|
||||
WHERE productId = p_productId AND sb.inventoryId = inventory_id
|
||||
LIMIT 1;
|
||||
|
||||
IF p_count > current_stock THEN
|
||||
SIGNAL SQLSTATE '45000'
|
||||
SET MESSAGE_TEXT = 'موجودی کالا در انبار کافی نیست.';
|
||||
END IF;
|
||||
END //
|
||||
|
||||
-- Procedure for trg_sales_invoice_items_after_insert
|
||||
CREATE PROCEDURE process_sale_item(IN p_invoiceId INT, IN p_productId INT, IN p_count DECIMAL(10,2), IN p_unitPrice DECIMAL(15,2), IN p_totalAmount DECIMAL(15,2))
|
||||
BEGIN
|
||||
DECLARE current_stock DECIMAL(10, 2);
|
||||
DECLARE inventory_id INT;
|
||||
DECLARE customer_id INT;
|
||||
DECLARE pos_id INT;
|
||||
|
||||
SELECT posAccountId, customerId INTO pos_id, customer_id
|
||||
FROM Sales_Invoices si
|
||||
WHERE si.id = p_invoiceId
|
||||
LIMIT 1;
|
||||
|
||||
SELECT pa.inventoryId INTO inventory_id
|
||||
FROM Pos_Accounts pa
|
||||
INNER JOIN Sales_Invoices si ON pa.id = si.posAccountId
|
||||
WHERE si.id = p_invoiceId;
|
||||
|
||||
SELECT COALESCE(quantity, 0) INTO current_stock
|
||||
FROM Stock_Balance sb
|
||||
WHERE productId = p_productId AND sb.inventoryId = inventory_id
|
||||
LIMIT 1;
|
||||
|
||||
INSERT INTO Stock_Movements (
|
||||
type,
|
||||
quantity,
|
||||
unitPrice,
|
||||
totalCost,
|
||||
referenceType,
|
||||
referenceId,
|
||||
productId,
|
||||
inventoryId,
|
||||
avgCost,
|
||||
remainedInStock,
|
||||
customerId,
|
||||
createdAt
|
||||
)
|
||||
VALUES (
|
||||
'OUT',
|
||||
p_count,
|
||||
p_unitPrice,
|
||||
p_totalAmount,
|
||||
'SALES',
|
||||
p_invoiceId,
|
||||
p_productId,
|
||||
inventory_id,
|
||||
CASE
|
||||
WHEN p_count = 0 THEN 0
|
||||
ELSE p_totalAmount / p_count
|
||||
END,
|
||||
current_stock - p_count,
|
||||
customer_id,
|
||||
NOW()
|
||||
);
|
||||
END //
|
||||
|
||||
-- Procedure for trg_sales_invoice_payment_after_insert
|
||||
CREATE PROCEDURE process_sale_payment(IN p_invoiceId INT, IN p_amount DECIMAL(15,2), IN p_id INT)
|
||||
BEGIN
|
||||
DECLARE currentBalance DECIMAL(15,2);
|
||||
DECLARE bankAccountId INT;
|
||||
|
||||
SELECT pa.bankAccountId INTO bankAccountId
|
||||
FROM Pos_Accounts pa
|
||||
INNER JOIN Sales_Invoices si ON pa.id = si.posAccountId
|
||||
WHERE si.id = p_invoiceId;
|
||||
|
||||
SELECT balance INTO currentBalance
|
||||
FROM Bank_Account_Balance
|
||||
WHERE bankAccountId = bankAccountId
|
||||
FOR UPDATE;
|
||||
|
||||
IF currentBalance IS NULL THEN
|
||||
SET currentBalance = 0;
|
||||
INSERT INTO Bank_Account_Balance (bankAccountId, balance, updatedAt)
|
||||
VALUES (bankAccountId, 0, NOW());
|
||||
END IF;
|
||||
|
||||
SET currentBalance = currentBalance + p_amount;
|
||||
|
||||
INSERT INTO Bank_Account_Transactions
|
||||
(bankAccountId, type, amount, balanceAfter, referenceType, referenceId)
|
||||
VALUES
|
||||
(bankAccountId, 'DEPOSIT', p_amount, currentBalance, 'POS_SALE', p_id);
|
||||
|
||||
UPDATE Bank_Account_Balance
|
||||
SET balance = currentBalance
|
||||
WHERE bankAccountId = bankAccountId;
|
||||
END //
|
||||
|
||||
-- Procedure for trg_pos_account_payment_after_insert
|
||||
CREATE PROCEDURE process_pos_payment(IN p_invoiceId INT, IN p_paymentMethod VARCHAR(20), IN p_amount DECIMAL(15,2), IN p_id INT)
|
||||
BEGIN
|
||||
DECLARE _bankAccountId INT;
|
||||
|
||||
IF(p_paymentMethod != 'CASH') THEN
|
||||
SELECT cashBankAccountId INTO _bankAccountId
|
||||
FROM Pos_Accounts pa
|
||||
INNER JOIN Sales_Invoices si ON pa.id = si.posAccountId
|
||||
WHERE si.id = p_invoiceId;
|
||||
END IF;
|
||||
|
||||
INSERT INTO Bank_Account_Transactions (
|
||||
bankAccountId,
|
||||
type,
|
||||
amount,
|
||||
balanceAfter,
|
||||
referenceType,
|
||||
referenceId
|
||||
)
|
||||
VALUES(
|
||||
_bankAccountId,
|
||||
'DEPOSIT',
|
||||
p_amount,
|
||||
0,
|
||||
'POS_SALE',
|
||||
p_id
|
||||
);
|
||||
END //
|
||||
|
||||
-- Procedure for trg_stock_transfer
|
||||
CREATE PROCEDURE update_stock_balance_transfer(IN p_productId INT, IN p_inventoryId INT, IN p_quantity DECIMAL(10,2), IN p_unitPrice DECIMAL(15,2), IN p_totalCost DECIMAL(15,2), IN p_type VARCHAR(10))
|
||||
BEGIN
|
||||
IF p_type = 'IN' THEN
|
||||
INSERT INTO Stock_Balance (
|
||||
productId,
|
||||
inventoryId,
|
||||
quantity,
|
||||
totalCost,
|
||||
avgCost,
|
||||
updatedAt
|
||||
)
|
||||
VALUES (
|
||||
p_productId,
|
||||
p_inventoryId,
|
||||
p_quantity,
|
||||
p_totalCost,
|
||||
CASE
|
||||
WHEN p_quantity = 0 THEN 0
|
||||
ELSE p_totalCost / p_quantity
|
||||
END,
|
||||
NOW()
|
||||
)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
quantity = quantity + p_quantity,
|
||||
totalCost = totalCost + p_totalCost,
|
||||
avgCost = CASE
|
||||
WHEN (quantity + p_quantity) = 0 THEN 0
|
||||
ELSE (totalCost + p_totalCost) / (quantity + p_quantity)
|
||||
END,
|
||||
updatedAt = NOW();
|
||||
END IF;
|
||||
|
||||
IF p_type = 'OUT' THEN
|
||||
IF EXISTS (
|
||||
SELECT 1
|
||||
FROM Stock_Balance sb
|
||||
WHERE sb.productId = p_productId AND sb.inventoryId = p_inventoryId
|
||||
) THEN
|
||||
UPDATE Stock_Balance sb
|
||||
SET
|
||||
sb.quantity = sb.quantity - p_quantity,
|
||||
sb.totalCost = sb.totalCost - (sb.avgCost * p_quantity),
|
||||
sb.updatedAt = NOW()
|
||||
WHERE
|
||||
sb.productId = p_productId
|
||||
AND sb.inventoryId = p_inventoryId;
|
||||
ELSE
|
||||
INSERT INTO Stock_Balance (
|
||||
productId,
|
||||
inventoryId,
|
||||
quantity,
|
||||
totalCost,
|
||||
avgCost,
|
||||
updatedAt
|
||||
)
|
||||
VALUES (
|
||||
p_productId,
|
||||
p_inventoryId,
|
||||
- p_quantity,
|
||||
- COALESCE(p_unitPrice, 0) * p_quantity,
|
||||
COALESCE(p_unitPrice, 0),
|
||||
NOW()
|
||||
);
|
||||
END IF;
|
||||
END IF;
|
||||
END //
|
||||
|
||||
-- Procedure for trg_stock_purchase_insert
|
||||
CREATE PROCEDURE update_stock_balance_purchase(IN p_productId INT, IN p_quantity DECIMAL(10,2), IN p_unitPrice DECIMAL(15,2), IN p_totalCost DECIMAL(15,2), IN p_inventoryId INT)
|
||||
BEGIN
|
||||
INSERT INTO Stock_Balance (
|
||||
productId,
|
||||
quantity,
|
||||
avgCost,
|
||||
totalCost,
|
||||
inventoryId,
|
||||
updatedAt
|
||||
)
|
||||
VALUES (
|
||||
p_productId,
|
||||
p_quantity,
|
||||
p_unitPrice,
|
||||
p_totalCost,
|
||||
p_inventoryId,
|
||||
NOW()
|
||||
)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
quantity = quantity + p_quantity,
|
||||
totalCost = totalCost + p_totalCost,
|
||||
avgCost = totalCost / quantity;
|
||||
END //
|
||||
|
||||
-- Procedure for trg_stock_sale_insert
|
||||
CREATE PROCEDURE update_stock_balance_sale(IN p_productId INT, IN p_quantity DECIMAL(10,2), IN p_unitPrice DECIMAL(15,2), IN p_totalCost DECIMAL(15,2), IN p_inventoryId INT)
|
||||
BEGIN
|
||||
INSERT INTO Stock_Balance (
|
||||
productId,
|
||||
quantity,
|
||||
avgCost,
|
||||
totalCost,
|
||||
inventoryId,
|
||||
updatedAt
|
||||
)
|
||||
VALUES (
|
||||
p_productId,
|
||||
p_quantity,
|
||||
p_unitPrice,
|
||||
p_totalCost,
|
||||
p_inventoryId,
|
||||
NOW()
|
||||
)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
quantity = quantity - p_quantity,
|
||||
totalCost = totalCost - p_totalCost,
|
||||
avgCost = totalCost / quantity;
|
||||
END //
|
||||
|
||||
DELIMITER;
|
||||
@@ -1,3 +1,5 @@
|
||||
/// <reference types="multer" />
|
||||
|
||||
import { AccessTokenPayload, IConsumerPayload, IPosPayload } from '@/common/models'
|
||||
import { IPartnerPayload } from '@/common/models/partnerPayload.model'
|
||||
|
||||
|
||||
@@ -1,66 +1,65 @@
|
||||
#!/usr/bin/env ts-node
|
||||
import * as fs from 'fs'
|
||||
import * as path from 'path'
|
||||
import { prisma } from '../src/lib/prisma'
|
||||
// #!/usr/bin/env ts-node
|
||||
// import * as fs from 'fs'
|
||||
// import * as path from 'path'
|
||||
|
||||
function findModules(dir: string): string[] {
|
||||
const results: string[] = []
|
||||
const entries = fs.readdirSync(dir, { withFileTypes: true })
|
||||
for (const e of entries) {
|
||||
const full = path.join(dir, e.name)
|
||||
if (e.isDirectory()) {
|
||||
results.push(...findModules(full))
|
||||
} else if (e.isFile() && e.name.endsWith('.module.ts')) {
|
||||
results.push(full)
|
||||
}
|
||||
}
|
||||
return results
|
||||
}
|
||||
// function findModules(dir: string): string[] {
|
||||
// const results: string[] = []
|
||||
// const entries = fs.readdirSync(dir, { withFileTypes: true })
|
||||
// for (const e of entries) {
|
||||
// const full = path.join(dir, e.name)
|
||||
// if (e.isDirectory()) {
|
||||
// results.push(...findModules(full))
|
||||
// } else if (e.isFile() && e.name.endsWith('.module.ts')) {
|
||||
// results.push(full)
|
||||
// }
|
||||
// }
|
||||
// return results
|
||||
// }
|
||||
|
||||
function moduleNameFromFile(filePath: string) {
|
||||
const name = path.basename(filePath).replace('.module.ts', '')
|
||||
return name.replace(/-module$|\.module$/i, '')
|
||||
}
|
||||
// function moduleNameFromFile(filePath: string) {
|
||||
// const name = path.basename(filePath).replace('.module.ts', '')
|
||||
// return name.replace(/-module$|\.module$/i, '')
|
||||
// }
|
||||
|
||||
function makePermissionsFor(moduleName: string) {
|
||||
const base = moduleName.replace(/\W+/g, '_').toLowerCase()
|
||||
return [`${base}:create`, `${base}:read`, `${base}:update`, `${base}:delete`]
|
||||
}
|
||||
// function makePermissionsFor(moduleName: string) {
|
||||
// const base = moduleName.replace(/\W+/g, '_').toLowerCase()
|
||||
// return [`${base}:create`, `${base}:read`, `${base}:update`, `${base}:delete`]
|
||||
// }
|
||||
|
||||
async function main() {
|
||||
// const srcDir = path.resolve(__dirname, '..', 'src')
|
||||
// const moduleFiles = findModules(srcDir)
|
||||
// const modules = moduleFiles.map(moduleNameFromFile)
|
||||
// async function main() {
|
||||
// // const srcDir = path.resolve(__dirname, '..', 'src')
|
||||
// // const moduleFiles = findModules(srcDir)
|
||||
// // const modules = moduleFiles.map(moduleNameFromFile)
|
||||
|
||||
// const permsMap: Record<string, boolean> = {}
|
||||
// for (const m of modules) {
|
||||
// for (const p of makePermissionsFor(m)) permsMap[p] = false
|
||||
// }
|
||||
// // const permsMap: Record<string, boolean> = {}
|
||||
// // for (const m of modules) {
|
||||
// // for (const p of makePermissionsFor(m)) permsMap[p] = false
|
||||
// // }
|
||||
|
||||
// // Upsert roles: ensure admin has full permissions, others get entries added
|
||||
// const roles = await prisma.role.findMany()
|
||||
// for (const r of roles) {
|
||||
// const current: Record<string, any> = (r.permissions as any) || {}
|
||||
// const merged = { ...permsMap, ...current }
|
||||
// // // Upsert roles: ensure admin has full permissions, others get entries added
|
||||
// // const roles = await prisma.role.findMany()
|
||||
// // for (const r of roles) {
|
||||
// // const current: Record<string, any> = (r.permissions as any) || {}
|
||||
// // const merged = { ...permsMap, ...current }
|
||||
|
||||
// // If role name is admin (case-insensitive), set all permissions to true
|
||||
// if (r.name && r.name.toLowerCase() === 'admin') {
|
||||
// for (const key of Object.keys(merged)) merged[key] = true
|
||||
// } else {
|
||||
// // keep existing truthy values, otherwise false
|
||||
// for (const key of Object.keys(merged)) merged[key] = merged[key] || false
|
||||
// }
|
||||
// // // If role name is admin (case-insensitive), set all permissions to true
|
||||
// // if (r.name && r.name.toLowerCase() === 'admin') {
|
||||
// // for (const key of Object.keys(merged)) merged[key] = true
|
||||
// // } else {
|
||||
// // // keep existing truthy values, otherwise false
|
||||
// // for (const key of Object.keys(merged)) merged[key] = merged[key] || false
|
||||
// // }
|
||||
|
||||
// await prisma.role.update({ where: { id: r.id }, data: { permissions: merged } })
|
||||
// console.log(
|
||||
// `Updated role ${r.name} (id=${r.id}) with ${Object.keys(merged).length} permissions`,
|
||||
// )
|
||||
// }
|
||||
// // await prisma.role.update({ where: { id: r.id }, data: { permissions: merged } })
|
||||
// // console.log(
|
||||
// // `Updated role ${r.name} (id=${r.id}) with ${Object.keys(merged).length} permissions`,
|
||||
// // )
|
||||
// // }
|
||||
|
||||
await prisma.$disconnect()
|
||||
}
|
||||
// await prisma.$disconnect()
|
||||
// }
|
||||
|
||||
main().catch(e => {
|
||||
console.error(e)
|
||||
process.exit(1)
|
||||
})
|
||||
// main().catch(e => {
|
||||
// console.error(e)
|
||||
// process.exit(1)
|
||||
// })
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
// import fs from 'node:fs'
|
||||
// import path from 'node:path'
|
||||
|
||||
// type CsvRow = {
|
||||
// ID?: string
|
||||
// DescriptionOfID?: string
|
||||
// Vat?: string
|
||||
// Type?: string
|
||||
// }
|
||||
|
||||
// function parseCsvLine(line: string): string[] {
|
||||
// const result: string[] = []
|
||||
// let current = ''
|
||||
// let inQuotes = false
|
||||
|
||||
// for (let index = 0; index < line.length; index++) {
|
||||
// const char = line[index]
|
||||
|
||||
// if (char === '"') {
|
||||
// if (inQuotes && line[index + 1] === '"') {
|
||||
// current += '"'
|
||||
// index++
|
||||
// } else {
|
||||
// inQuotes = !inQuotes
|
||||
// }
|
||||
// continue
|
||||
// }
|
||||
|
||||
// if (char === ',' && !inQuotes) {
|
||||
// result.push(current)
|
||||
// current = ''
|
||||
// continue
|
||||
// }
|
||||
|
||||
// current += char
|
||||
// }
|
||||
|
||||
// result.push(current)
|
||||
// return result.map(value => value.trim())
|
||||
// }
|
||||
|
||||
// function parseCsv(content: string): CsvRow[] {
|
||||
// const lines = content
|
||||
// .split(/\r?\n/)
|
||||
// .map(line => line.trim())
|
||||
// .filter(Boolean)
|
||||
|
||||
// if (!lines.length) return []
|
||||
|
||||
// const headers = parseCsvLine(lines[0])
|
||||
// return lines.slice(1).map(line => {
|
||||
// const cols = parseCsvLine(line)
|
||||
// const row: Record<string, string> = {}
|
||||
// for (let index = 0; index < headers.length; index++) {
|
||||
// row[headers[index]] = cols[index] || ''
|
||||
// }
|
||||
// return row
|
||||
// })
|
||||
// }
|
||||
|
||||
// function toBooleanFlags(typeValue: string) {
|
||||
// const normalized = typeValue || ''
|
||||
// const isPublic = normalized.includes('شناسه عمومی')
|
||||
// const isImported = normalized.includes('وارداتی')
|
||||
// const isDomestic = !isImported
|
||||
|
||||
// return { isPublic, isDomestic }
|
||||
// }
|
||||
|
||||
// function parseVat(vatValue: string) {
|
||||
// const parsed = Number(vatValue || '0')
|
||||
// if (!Number.isFinite(parsed)) return 0
|
||||
// return parsed
|
||||
// }
|
||||
|
||||
// async function main() {
|
||||
// const defaultPath =
|
||||
// '/Users/ahasani/Desktop/product_good_2026-05-01T11-35-57_part_1_28812448-0dd9-411c-99e1-334c28d781fe.csv'
|
||||
// const csvPath = process.argv[2] || defaultPath
|
||||
// const absolutePath = path.resolve(csvPath)
|
||||
|
||||
// if (!fs.existsSync(absolutePath)) {
|
||||
// throw new Error(`CSV file not found: ${absolutePath}`)
|
||||
// }
|
||||
|
||||
// const raw = fs.readFileSync(absolutePath, 'utf8').replace(/^\uFEFF/, '')
|
||||
// const rows = parseCsv(raw)
|
||||
|
||||
// let upserted = 0
|
||||
// let skipped = 0
|
||||
|
||||
// const guild = await prisma.guild.findFirst({})
|
||||
|
||||
// for (const row of rows) {
|
||||
// const code = (row.ID || '').trim()
|
||||
// const name = (row.DescriptionOfID || '').trim()
|
||||
// const vat = parseVat((row.Vat || '').trim())
|
||||
// const type = (row.Type || '').trim()
|
||||
// const { isPublic, isDomestic } = toBooleanFlags(type)
|
||||
|
||||
// if (!code || !name) {
|
||||
// skipped++
|
||||
// continue
|
||||
// }
|
||||
|
||||
// await prisma.stockKeepingUnits.upsert({
|
||||
// where: { code },
|
||||
// create: {
|
||||
// code,
|
||||
// name,
|
||||
// VAT: vat,
|
||||
// guild: {
|
||||
// connect: {
|
||||
// id: guild?.id,
|
||||
// },
|
||||
// },
|
||||
// is_public: isPublic,
|
||||
// is_domestic: isDomestic,
|
||||
// },
|
||||
// update: {
|
||||
// name,
|
||||
// VAT: vat,
|
||||
// guild: {
|
||||
// connect: {
|
||||
// id: guild?.id,
|
||||
// },
|
||||
// },
|
||||
// is_public: isPublic,
|
||||
// is_domestic: isDomestic,
|
||||
// },
|
||||
// })
|
||||
// upserted++
|
||||
// }
|
||||
// }
|
||||
|
||||
// main()
|
||||
// .catch(error => {
|
||||
// console.error(error)
|
||||
// process.exit(1)
|
||||
// })
|
||||
// .finally(async () => {
|
||||
// await prisma.$disconnect()
|
||||
// })
|
||||
+5
-7
@@ -7,27 +7,25 @@ import { AuthModule } from './modules/auth/auth.module'
|
||||
import { CatalogModule } from './modules/catalog/catalog.module'
|
||||
import { ConsumerModule } from './modules/consumer/consumer.module'
|
||||
import { EnumsModule } from './modules/enums/enums.module'
|
||||
import { PublicInvoicesModule } from './modules/invoices/invoices.module'
|
||||
import { PartnerModule } from './modules/partners/partners.module'
|
||||
import { PosModule } from './modules/pos/pos.module'
|
||||
import { SalesInvoiceItemsModule } from './modules/pos/sales-invoices/sales-invoice-items/sales-invoice-items.module'
|
||||
import { SalesInvoicePaymentsModule } from './modules/pos/sales-invoices/sales-invoice-payments/sales-invoice-payments.module'
|
||||
import { TriggerLogsModule } from './modules/trigger-logs/trigger-logs.module'
|
||||
import { UploaderModule } from './modules/uploader/uploader.module'
|
||||
import { PrismaModule } from './prisma/prisma.module'
|
||||
import { RedisModule } from './redis/redis.module'
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
PrismaModule,
|
||||
RedisModule,
|
||||
EnumsModule,
|
||||
AdminModule,
|
||||
AuthModule,
|
||||
CatalogModule,
|
||||
ConsumerModule,
|
||||
PosModule,
|
||||
PartnerModule,
|
||||
AuthModule,
|
||||
SalesInvoiceItemsModule,
|
||||
SalesInvoicePaymentsModule,
|
||||
TriggerLogsModule,
|
||||
PublicInvoicesModule,
|
||||
UploaderModule,
|
||||
ApplicationModule,
|
||||
],
|
||||
|
||||
@@ -1,14 +1,187 @@
|
||||
import {
|
||||
InvoiceSettlementType,
|
||||
TspProviderRequestType,
|
||||
TspProviderResponseStatus,
|
||||
} from '@/generated/prisma/enums'
|
||||
|
||||
export default {
|
||||
COUNT: 'تعداد',
|
||||
GRAM: 'گرم',
|
||||
KILO_GRAM: 'کیلوگرم',
|
||||
LITER: 'لیتر',
|
||||
MILLILITER: 'میلیلیتر',
|
||||
STANDARD: 'استاندارد',
|
||||
GOLD: 'طلا',
|
||||
ACTIVE: 'فعال',
|
||||
SUSPENDED: 'غیرفعال',
|
||||
OWNER: 'مدیر اصلی',
|
||||
MANAGER: 'مدیریت',
|
||||
OPERATOR: 'اپراتور',
|
||||
PaymentMethodType: {
|
||||
TERMINAL: 'ترمینال',
|
||||
CASH: 'نقدی',
|
||||
SET_OFF: 'تهاتر',
|
||||
CARD: 'کارت',
|
||||
BANK: 'بانکی',
|
||||
CHECK: 'چک',
|
||||
OTHER: 'سایر',
|
||||
},
|
||||
UnitType: {
|
||||
COUNT: 'تعداد',
|
||||
GRAM: 'گرم',
|
||||
KILOGRAM: 'کیلوگرم',
|
||||
LITER: 'لیتر',
|
||||
MILLILITER: 'میلیلیتر',
|
||||
METER: 'متر',
|
||||
HOUR: 'ساعت',
|
||||
},
|
||||
GoodPricingModel: {
|
||||
STANDARD: 'عمومی',
|
||||
GOLD: 'طلا',
|
||||
},
|
||||
CustomerType: {
|
||||
INDIVIDUAL: 'حقیقی',
|
||||
LEGAL: 'حقوقی',
|
||||
UNKNOWN: 'نامشخص',
|
||||
},
|
||||
POSStatus: {
|
||||
ACTIVE: 'فعال',
|
||||
DISABLED: 'غیرفعال',
|
||||
},
|
||||
POSRole: {
|
||||
MANAGER: 'مدیریت',
|
||||
OPERATOR: 'اپراتور',
|
||||
},
|
||||
LicenseType: {
|
||||
BASIC: 'پایه',
|
||||
PRO: 'حرفهای',
|
||||
ENTERPRISE: 'سازمانی',
|
||||
},
|
||||
LicenseStatus: {
|
||||
ACTIVE: 'فعال',
|
||||
EXPIRED: 'منقضی',
|
||||
SUSPENDED: 'غیرفعال',
|
||||
},
|
||||
POSType: {
|
||||
PSP: 'PSP',
|
||||
MOBILE: 'موبایل',
|
||||
WEB: 'وب',
|
||||
API: 'API',
|
||||
},
|
||||
UserType: {
|
||||
LEGAL: 'حقوقی',
|
||||
INDIVIDUAL: 'حقیقی',
|
||||
},
|
||||
AccountType: {
|
||||
ADMIN: 'مدیر سیستم',
|
||||
PROVIDER: 'ارائهدهنده خدمات',
|
||||
PARTNER: 'شریک تجاری',
|
||||
CONSUMER: 'مصرفکننده',
|
||||
},
|
||||
UserStatus: {
|
||||
ACTIVE: 'فعال',
|
||||
INACTIVE: 'غیرفعال',
|
||||
},
|
||||
AccountRole: {
|
||||
OWNER: 'مدیر اصلی',
|
||||
OPERATOR: 'اپراتور',
|
||||
ACCOUNTANT: 'حسابدار',
|
||||
},
|
||||
AccountStatus: {
|
||||
ACTIVE: 'فعال',
|
||||
SUSPENDED: 'غیرفعال',
|
||||
},
|
||||
PartnerRole: {
|
||||
OWNER: 'مدیر اصلی',
|
||||
MANAGER: 'مدیریت',
|
||||
OPERATOR: 'اپراتور',
|
||||
},
|
||||
PartnerStatus: {
|
||||
ACTIVE: 'فعال',
|
||||
SUSPENDED: 'غیرفعال',
|
||||
},
|
||||
ProviderRole: {
|
||||
OWNER: 'مدیر اصلی',
|
||||
MANAGER: 'مدیریت',
|
||||
OPERATOR: 'اپراتور',
|
||||
},
|
||||
ProviderStatus: {
|
||||
ACTIVE: 'فعال',
|
||||
SUSPENDED: 'غیرفعال',
|
||||
},
|
||||
BusinessRole: {
|
||||
MANAGER: 'مدیریت',
|
||||
OPERATOR: 'اپراتور',
|
||||
},
|
||||
ComplexRole: {
|
||||
MANAGER: 'مدیریت',
|
||||
OPERATOR: 'اپراتور',
|
||||
},
|
||||
ConsumerRole: {
|
||||
OWNER: 'مدیر اصلی',
|
||||
MANAGER: 'مدیریت',
|
||||
OPERATOR: 'اپراتور',
|
||||
},
|
||||
ConsumerStatus: {
|
||||
ACTIVE: 'فعال',
|
||||
SUSPENDED: 'غیرفعال',
|
||||
},
|
||||
ConsumerType: {
|
||||
INDIVIDUAL: 'حقیقی',
|
||||
LEGAL: 'حقوقی',
|
||||
},
|
||||
TokenType: {
|
||||
ACCESS: 'دسترسی',
|
||||
REFRESH: 'نوسازی',
|
||||
},
|
||||
ApplicationPlatform: {
|
||||
ANDROID: 'اندروید',
|
||||
IOS: 'iOS',
|
||||
},
|
||||
ApplicationReleaseType: {
|
||||
STABLE: 'پایدار',
|
||||
BETA: 'بتا',
|
||||
ALPHA: 'آلفا',
|
||||
},
|
||||
ApplicationPublisher: {
|
||||
DIRECT: 'مستقیم',
|
||||
CAFE_BAZAR: 'کافه بازار',
|
||||
MAYKET: 'مایکت',
|
||||
},
|
||||
TspProviderType: {
|
||||
NAMA: 'نما',
|
||||
SUN: 'سان',
|
||||
},
|
||||
TspProviderResponseStatus: {
|
||||
[TspProviderResponseStatus.SUCCESS]: 'تایید شده',
|
||||
[TspProviderResponseStatus.FAILURE]: 'ناموفق',
|
||||
[TspProviderResponseStatus.NOT_SEND]: 'ارسال نشده',
|
||||
[TspProviderResponseStatus.QUEUED]: 'در صف ارسال',
|
||||
[TspProviderResponseStatus.FISCAL_QUEUED]: 'در انتظار تایید سازمان',
|
||||
[TspProviderResponseStatus.SEND_FAILURE]: 'خطا در ارسال',
|
||||
},
|
||||
InvoiceSettlementType: {
|
||||
[InvoiceSettlementType.CASH]: 'نقدی',
|
||||
[InvoiceSettlementType.CREDIT]: 'نسیه',
|
||||
[InvoiceSettlementType.MIXED]: 'نقدی / نسیه',
|
||||
},
|
||||
TspProviderRequestType: {
|
||||
[TspProviderRequestType.ORIGINAL]: 'اصلی',
|
||||
[TspProviderRequestType.CORRECTION]: 'اصلاح',
|
||||
[TspProviderRequestType.REVOKE]: 'ابطال',
|
||||
[TspProviderRequestType.RETURN]: 'برگشت از فروش',
|
||||
},
|
||||
TspProviderCustomerType: {
|
||||
Unknown: 'ناشناس',
|
||||
Known: 'شناسایی شده',
|
||||
},
|
||||
SKUGuildType: {
|
||||
GOLD: 'طلا',
|
||||
},
|
||||
GoldKarat: {
|
||||
KARAT_18: '۱۸ عیار',
|
||||
KARAT_21: '۲۱ عیار',
|
||||
KARAT_24: '۲۴ عیار',
|
||||
},
|
||||
InvoiceTemplateType: {
|
||||
SALE: 'فروش',
|
||||
FX_SALE: 'فروش ارزی',
|
||||
GOLD_JEWELRY: 'طلا و جواهر',
|
||||
CONTRACT: 'پیمانکاری',
|
||||
UTILITY: 'قبوض خدماتی',
|
||||
AIR_TICKET: 'بلیط هواپیما',
|
||||
EXPORT: 'صادرات',
|
||||
BILL_OF_LADING: 'بارنامه',
|
||||
PETROCHEMICAL: 'پتروشیمی',
|
||||
COMMODITY_EXCHANGE: 'بورس کالا',
|
||||
INSURANCE: 'بیمه',
|
||||
},
|
||||
}
|
||||
|
||||
+28
-19
@@ -1,25 +1,34 @@
|
||||
export enum TokenType {
|
||||
ACCESS = 'ACCESS',
|
||||
REFRESH = 'REFRESH',
|
||||
}
|
||||
|
||||
export enum AccountType {
|
||||
PARTNER = 'PARTNER',
|
||||
BUSINESS = 'BUSINESS',
|
||||
ADMIN = 'ADMIN',
|
||||
PROVIDER = 'PROVIDER',
|
||||
POS = 'POS',
|
||||
}
|
||||
|
||||
export enum GoldKarat {
|
||||
KARAT_18 = '18',
|
||||
KARAT_21 = '21',
|
||||
KARAT_24 = '24',
|
||||
KARAT_18 = 'KARAT_18',
|
||||
KARAT_21 = 'KARAT_21',
|
||||
KARAT_24 = 'KARAT_24',
|
||||
}
|
||||
|
||||
export enum TspProviderRequestType {
|
||||
ORIGINAL = 'ORIGINAL',
|
||||
CORRECTION = 'CORRECTION',
|
||||
REVOKE = 'REVOKE',
|
||||
REMOVE = 'REMOVE',
|
||||
}
|
||||
|
||||
export const SKUGuildType = {
|
||||
GOLD: 'GOLD',
|
||||
} as const
|
||||
|
||||
export type SKUGuildType = (typeof SKUGuildType)[keyof typeof SKUGuildType]
|
||||
|
||||
export const UploadedFileTypes = {
|
||||
GOOD: 'good',
|
||||
SERVICE: 'service',
|
||||
PROFILE_AVATAR: 'profile_avatar',
|
||||
GOOD: 'GOOD',
|
||||
SERVICE: 'SERVICE',
|
||||
PROFILE_AVATAR: 'PROFILE_AVATAR',
|
||||
PARTNER_LOGO: 'PARTNER_LOGO',
|
||||
}
|
||||
export type UploadedFileTypes = (typeof UploadedFileTypes)[keyof typeof UploadedFileTypes]
|
||||
|
||||
export const TspProviderCustomerType = {
|
||||
UNKNOWN: 'UNKNOWN',
|
||||
KNOWN: 'KNOWN',
|
||||
}
|
||||
|
||||
export type TspProviderCustomerType =
|
||||
(typeof TspProviderCustomerType)[keyof typeof TspProviderCustomerType]
|
||||
|
||||
@@ -27,14 +27,14 @@ export class ConsumerGuard {
|
||||
|
||||
const consumer = await this.prisma.consumer.findFirst({
|
||||
where: {
|
||||
consumer_accounts: {
|
||||
accounts: {
|
||||
some: {
|
||||
id: tokenPayload.account_id,
|
||||
},
|
||||
},
|
||||
},
|
||||
select: {
|
||||
consumer_accounts: {
|
||||
accounts: {
|
||||
select: {
|
||||
role: true,
|
||||
},
|
||||
|
||||
@@ -23,14 +23,14 @@ export class PartnerGuard {
|
||||
|
||||
const partner = await this.prisma.partner.findFirst({
|
||||
where: {
|
||||
partner_accounts: {
|
||||
accounts: {
|
||||
some: {
|
||||
id: tokenPayload.account_id,
|
||||
},
|
||||
},
|
||||
},
|
||||
select: {
|
||||
partner_accounts: {
|
||||
accounts: {
|
||||
select: {
|
||||
role: true,
|
||||
},
|
||||
|
||||
@@ -3,6 +3,7 @@ import { ITokenPayload } from '@/modules/auth/auth.utils'
|
||||
import { PrismaService } from '@/prisma/prisma.service'
|
||||
import { ExecutionContext, ForbiddenException, Injectable } from '@nestjs/common'
|
||||
import { Request as ExpressRequest } from 'express'
|
||||
import { QUERY_CONSTANTS } from '../queryConstants'
|
||||
|
||||
@Injectable()
|
||||
export class PosGuard {
|
||||
@@ -18,7 +19,6 @@ export class PosGuard {
|
||||
throw new ForbiddenException('شما دسترسی لازم را ندارید.')
|
||||
}
|
||||
|
||||
const now = new Date()
|
||||
const cookie = req.cookies
|
||||
const { posId } = cookie
|
||||
|
||||
@@ -40,22 +40,7 @@ export class PosGuard {
|
||||
},
|
||||
],
|
||||
license_activation: {
|
||||
OR: [
|
||||
{
|
||||
expires_at: {
|
||||
gte: now,
|
||||
},
|
||||
},
|
||||
{
|
||||
license_renews: {
|
||||
some: {
|
||||
expires_at: {
|
||||
gte: now,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
...QUERY_CONSTANTS.LICENSE_ACTIVATION.activeOnDate(),
|
||||
},
|
||||
},
|
||||
})
|
||||
@@ -67,85 +52,5 @@ export class PosGuard {
|
||||
}
|
||||
|
||||
return true
|
||||
// const pos = await this.prisma.pos.findUnique({
|
||||
// where: {
|
||||
// id: posId,
|
||||
// account_id: tokenPayload.account_id,
|
||||
// },
|
||||
// select: {
|
||||
// complex: {
|
||||
// select: {
|
||||
// id: true,
|
||||
// business_activity: {
|
||||
// select: {
|
||||
// id: true,
|
||||
// license_activation: {
|
||||
// select: {
|
||||
// expires_at: true,
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// })
|
||||
|
||||
// if (!pos) {
|
||||
// throw new ForbiddenException('شما دسترسی لازم را ندارید.')
|
||||
// }
|
||||
|
||||
// if (req.method !== 'GET') {
|
||||
// if (!pos.complex.business_activity.license_activation) {
|
||||
// throw new ForbiddenException('برای کاربر شما لایسنس ایجاد نشده است.')
|
||||
// }
|
||||
// if (
|
||||
// pos.complex.business_activity.license_activation.expires_at &&
|
||||
// new Date().getTime() >
|
||||
// new Date(pos.complex.business_activity.license_activation.expires_at).getTime()
|
||||
// ) {
|
||||
// throw new ForbiddenException('لایسنس شما منقضی شده است.')
|
||||
// }
|
||||
// }
|
||||
|
||||
// const foundedAccount = await this.prisma.consumerAccount.findUnique({
|
||||
// where: {
|
||||
// id: tokenPayload.account_id,
|
||||
// },
|
||||
// select: {
|
||||
// role: true,
|
||||
// },
|
||||
// })
|
||||
|
||||
// if (foundedAccount?.role === 'OWNER') {
|
||||
// return true
|
||||
// }
|
||||
|
||||
// const accountPermissions = await this.prisma.permissionConsumer.findUnique({
|
||||
// where: {
|
||||
// consumer_account_id: tokenPayload.account_id,
|
||||
// },
|
||||
// select: {
|
||||
// pos_permissions: true,
|
||||
// business_permissions: true,
|
||||
// complex_permissions: true,
|
||||
// },
|
||||
// })
|
||||
|
||||
// if (accountPermissions?.pos_permissions.some(p => p.pos_id === posId)) {
|
||||
// return true
|
||||
// }
|
||||
// if (
|
||||
// accountPermissions?.complex_permissions.some(p => p.complex_id === pos.complex.id)
|
||||
// ) {
|
||||
// return true
|
||||
// }
|
||||
// if (
|
||||
// accountPermissions?.business_permissions.some(
|
||||
// p => p.business_id === pos.complex.business_activity.id,
|
||||
// )
|
||||
// ) {
|
||||
// return true
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
export interface FetchRequestContext {
|
||||
url: string
|
||||
init: RequestInit
|
||||
}
|
||||
|
||||
export interface FetchRequestInterceptor {
|
||||
onRequest?(
|
||||
context: FetchRequestContext,
|
||||
): Promise<FetchRequestContext> | FetchRequestContext
|
||||
onResponse?(
|
||||
context: FetchRequestContext,
|
||||
response: Response,
|
||||
): Promise<Response> | Response
|
||||
onError?(context: FetchRequestContext, error: unknown): Promise<void> | void
|
||||
}
|
||||
|
||||
function mergeHeaders(
|
||||
currentHeaders: HeadersInit | undefined,
|
||||
newHeaders: HeadersInit,
|
||||
): Headers {
|
||||
const mergedHeaders = new Headers(currentHeaders)
|
||||
const incomingHeaders = new Headers(newHeaders)
|
||||
|
||||
incomingHeaders.forEach((value, key) => {
|
||||
mergedHeaders.set(key, value)
|
||||
})
|
||||
|
||||
return mergedHeaders
|
||||
}
|
||||
|
||||
export function createHeaderRequestInterceptor(
|
||||
headers: HeadersInit,
|
||||
): FetchRequestInterceptor {
|
||||
return {
|
||||
onRequest(context) {
|
||||
return {
|
||||
...context,
|
||||
init: {
|
||||
...context.init,
|
||||
headers: mergeHeaders(context.init.headers, headers),
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export function createEnsureSuccessResponseInterceptor(): FetchRequestInterceptor {
|
||||
return {
|
||||
async onResponse(_, response) {
|
||||
if (response.ok) {
|
||||
return response
|
||||
}
|
||||
|
||||
const errorBody = await response.text().catch(() => '')
|
||||
const normalizedBody = errorBody
|
||||
return Promise.reject({
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
body: normalizedBody,
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -85,7 +85,6 @@ export class ResponseMappingInterceptor implements NestInterceptor {
|
||||
break
|
||||
case 'paginate': {
|
||||
const { items: a, ...rest } = wrapped
|
||||
console.log(rest)
|
||||
|
||||
const items = Array.isArray(wrapped.items) ? wrapped.items : []
|
||||
const total =
|
||||
@@ -96,7 +95,7 @@ export class ResponseMappingInterceptor implements NestInterceptor {
|
||||
meta = {
|
||||
totalRecords: total,
|
||||
totalPages: Math.max(1, Math.ceil(total / perPage)),
|
||||
page,
|
||||
page: parseInt(page),
|
||||
perPage,
|
||||
}
|
||||
break
|
||||
@@ -189,7 +188,7 @@ export class ResponseMappingInterceptor implements NestInterceptor {
|
||||
meta = {
|
||||
totalRecords: total,
|
||||
totalPages: Math.max(1, Math.ceil(total / perPage)),
|
||||
page,
|
||||
page: parseInt(page),
|
||||
perPage,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ export interface SaleInvoiceGoldTypePayload {
|
||||
karat: keyof typeof GoldKarat
|
||||
wages: number
|
||||
profit: number
|
||||
commission: number
|
||||
}
|
||||
export interface SaleInvoiceStandardPayload {}
|
||||
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
import { BusinessActivitySelect } from '@/generated/prisma/models'
|
||||
|
||||
export const summarySelect: BusinessActivitySelect = {
|
||||
id: true,
|
||||
name: true,
|
||||
economic_code: true,
|
||||
created_at: true,
|
||||
fiscal_id: true,
|
||||
invoice_number_sequence: true,
|
||||
partner_token: true,
|
||||
guild: {
|
||||
select: {
|
||||
id: true,
|
||||
code: true,
|
||||
name: true,
|
||||
},
|
||||
},
|
||||
license_activation: {
|
||||
select: {
|
||||
id: true,
|
||||
starts_at: true,
|
||||
expires_at: true,
|
||||
license: {
|
||||
select: {
|
||||
activation: {
|
||||
select: {
|
||||
account_allocations: {
|
||||
select: {
|
||||
id: true,
|
||||
account_id: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const select: BusinessActivitySelect = {
|
||||
...summarySelect,
|
||||
}
|
||||
|
||||
export const mappedData = (businessActivity: any) => {
|
||||
const { license_activation, ...rest } = businessActivity
|
||||
const { license, ...license_activation_rest } = license_activation
|
||||
const { account_allocations } = license.activation
|
||||
|
||||
console.log('license_activation', license_activation)
|
||||
|
||||
return {
|
||||
...rest,
|
||||
license_info: {
|
||||
...license_activation_rest,
|
||||
accounts_limit: account_allocations.length,
|
||||
allocated_account_count: account_allocations.filter(
|
||||
allocation => allocation.account_id,
|
||||
).length,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
import { ConsumerSelect, ConsumerWhereInput } from '@/generated/prisma/models'
|
||||
|
||||
const now = new Date()
|
||||
|
||||
export const infoSelect: ConsumerSelect = {
|
||||
type: true,
|
||||
legal: {
|
||||
select: {
|
||||
name: true,
|
||||
registration_code: true,
|
||||
partner: {
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
code: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
individual: {
|
||||
select: {
|
||||
first_name: true,
|
||||
last_name: true,
|
||||
mobile_number: true,
|
||||
national_code: true,
|
||||
partner: {
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
code: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const activeBusinessCount: ConsumerSelect = {
|
||||
_count: {
|
||||
select: {
|
||||
business_activities: {
|
||||
where: {
|
||||
license_activation: {
|
||||
OR: [
|
||||
{
|
||||
expires_at: {
|
||||
gt: now,
|
||||
},
|
||||
},
|
||||
{
|
||||
license_renews: {
|
||||
some: {
|
||||
expires_at: {
|
||||
gt: now,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const consumerRelatedPartner = (partner_id: string): ConsumerWhereInput => ({
|
||||
OR: [
|
||||
{
|
||||
legal: {
|
||||
is: {
|
||||
partner_id,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
individual: {
|
||||
is: {
|
||||
partner_id,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
@@ -1,5 +1,13 @@
|
||||
import * as pos from './pos'
|
||||
import * as BUSINESS_ACTIVITIES from './businessActivities'
|
||||
import * as CONSUMER from './consumer'
|
||||
import * as LICENSE_ACTIVATION from './licenseActivation'
|
||||
import * as POS from './pos'
|
||||
import * as SALE_INVOICE from './saleInvoice'
|
||||
|
||||
export const QUERY_CONSTANTS = {
|
||||
pos,
|
||||
POS,
|
||||
CONSUMER,
|
||||
LICENSE_ACTIVATION,
|
||||
SALE_INVOICE,
|
||||
BUSINESS_ACTIVITIES,
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
export const activeOnDate = (expires_at: Date = new Date()) => ({
|
||||
OR: [
|
||||
{
|
||||
expires_at: {
|
||||
gte: expires_at,
|
||||
},
|
||||
},
|
||||
{
|
||||
license_renews: {
|
||||
some: {
|
||||
expires_at: {
|
||||
gte: expires_at,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
@@ -0,0 +1,134 @@
|
||||
import { SalesInvoiceSelect } from '@/generated/prisma/models'
|
||||
|
||||
export const summarySelect: SalesInvoiceSelect = {
|
||||
id: true,
|
||||
code: true,
|
||||
invoice_date: true,
|
||||
invoice_number: true,
|
||||
main_id: true,
|
||||
total_amount: true,
|
||||
tax_id: true,
|
||||
type: true,
|
||||
notes: true,
|
||||
created_at: true,
|
||||
settlement_type: true,
|
||||
unknown_customer: true,
|
||||
last_attempt_no: true,
|
||||
last_tsp_status: true,
|
||||
customer: {
|
||||
select: {
|
||||
type: true,
|
||||
individual: {
|
||||
select: {
|
||||
first_name: true,
|
||||
last_name: true,
|
||||
mobile_number: true,
|
||||
national_id: true,
|
||||
economic_code: true,
|
||||
postal_code: true,
|
||||
},
|
||||
},
|
||||
legal: {
|
||||
select: {
|
||||
name: true,
|
||||
economic_code: true,
|
||||
registration_number: true,
|
||||
postal_code: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
reference_invoice: {
|
||||
select: {
|
||||
id: true,
|
||||
invoice_number: true,
|
||||
},
|
||||
},
|
||||
referenced_by: {
|
||||
select: {
|
||||
id: true,
|
||||
invoice_number: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const select: SalesInvoiceSelect = {
|
||||
...summarySelect,
|
||||
discount_amount: true,
|
||||
tax_amount: true,
|
||||
updated_at: true,
|
||||
unknown_customer: true,
|
||||
|
||||
pos: {
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
complex: {
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
business_activity: {
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
economic_code: true,
|
||||
guild: {
|
||||
select: {
|
||||
name: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
consumer_account: {
|
||||
select: {
|
||||
id: true,
|
||||
role: true,
|
||||
account: {
|
||||
select: {
|
||||
username: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
items: {
|
||||
select: {
|
||||
id: true,
|
||||
good_id: true,
|
||||
service_id: true,
|
||||
quantity: true,
|
||||
measure_unit_code: true,
|
||||
measure_unit_text: true,
|
||||
sku_code: true,
|
||||
unit_price: true,
|
||||
discount_amount: true,
|
||||
tax_amount: true,
|
||||
total_amount: true,
|
||||
notes: true,
|
||||
payload: true,
|
||||
good_snapshot: true,
|
||||
},
|
||||
},
|
||||
payments: {
|
||||
select: {
|
||||
id: true,
|
||||
amount: true,
|
||||
payment_method: true,
|
||||
paid_at: true,
|
||||
created_at: true,
|
||||
terminal_info: {
|
||||
select: {
|
||||
terminal_id: true,
|
||||
stan: true,
|
||||
rrn: true,
|
||||
transaction_date_time: true,
|
||||
customer_card_no: true,
|
||||
description: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import { QUERY_CONSTANTS } from '@/common/queryConstants'
|
||||
import { BusinessActivitySelect } from '@/generated/prisma/models'
|
||||
import { PrismaService } from '@/prisma/prisma.service'
|
||||
import { Injectable } from '@nestjs/common'
|
||||
|
||||
@Injectable()
|
||||
export class BusinessActivitiesQueryService {
|
||||
constructor(private readonly prisma: PrismaService) {}
|
||||
|
||||
readonly baseSelect: BusinessActivitySelect = {
|
||||
...QUERY_CONSTANTS.BUSINESS_ACTIVITIES.summarySelect,
|
||||
}
|
||||
|
||||
async findAllByConsumer(consumer_id: string, select: BusinessActivitySelect) {
|
||||
const businessActivities = await this.prisma.businessActivity.findMany({
|
||||
where: { consumer_id },
|
||||
select: this.baseSelect,
|
||||
})
|
||||
return businessActivities.map(QUERY_CONSTANTS.BUSINESS_ACTIVITIES.mappedData)
|
||||
}
|
||||
|
||||
async findOneByConsumer(
|
||||
consumer_id: string,
|
||||
id: string,
|
||||
select: BusinessActivitySelect,
|
||||
orThrow = false,
|
||||
) {
|
||||
// if (orThrow) {
|
||||
// return await this.prisma.businessActivity.findUniqueOrThrow({
|
||||
// where: { consumer_id, id },
|
||||
// select,
|
||||
// })
|
||||
// }
|
||||
|
||||
const businessActivity = await this.prisma.businessActivity.findUnique({
|
||||
where: { consumer_id, id },
|
||||
select: QUERY_CONSTANTS.BUSINESS_ACTIVITIES.select,
|
||||
})
|
||||
|
||||
return QUERY_CONSTANTS.BUSINESS_ACTIVITIES.mappedData(businessActivity)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
import { UploadedFileTypes } from '@/common/enums/enums'
|
||||
import { GoodPricingModel } from '@/generated/prisma/enums'
|
||||
import { GoodSelect } from '@/generated/prisma/models'
|
||||
import { UploaderService } from '@/modules/uploader/uploader.service'
|
||||
import { Injectable } from '@nestjs/common'
|
||||
|
||||
export interface CreateGoodDto {
|
||||
name: string
|
||||
sku_id: string
|
||||
category_id: string
|
||||
measure_unit_id: string
|
||||
pricing_model: GoodPricingModel
|
||||
description?: string
|
||||
is_default_guild_good?: boolean
|
||||
}
|
||||
|
||||
export interface UpdateGoodDto extends Partial<CreateGoodDto> {}
|
||||
|
||||
@Injectable()
|
||||
export class GoodsSharedService {
|
||||
constructor(private readonly uploaderService: UploaderService) {}
|
||||
|
||||
readonly defaultSelect: GoodSelect = {
|
||||
id: true,
|
||||
name: true,
|
||||
pricing_model: true,
|
||||
image_url: true,
|
||||
description: true,
|
||||
sku: {
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
},
|
||||
},
|
||||
measure_unit: {
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
},
|
||||
},
|
||||
category: {
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
async prepareCreateData(data: CreateGoodDto, file?: Express.Multer.File) {
|
||||
const { category_id, measure_unit_id, sku_id, ...rest } = data
|
||||
|
||||
let image_url = ''
|
||||
if (file) {
|
||||
const uploadedUrl = await this.uploaderService.uploadFile(
|
||||
file,
|
||||
UploadedFileTypes.GOOD,
|
||||
)
|
||||
image_url = uploadedUrl || ''
|
||||
}
|
||||
|
||||
return {
|
||||
...rest,
|
||||
image_url,
|
||||
sku: {
|
||||
connect: {
|
||||
id: sku_id,
|
||||
},
|
||||
},
|
||||
measure_unit: {
|
||||
connect: {
|
||||
id: measure_unit_id,
|
||||
},
|
||||
},
|
||||
category: {
|
||||
connect: {
|
||||
id: category_id,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
async prepareUpdateData(id: string, data: UpdateGoodDto, file?: Express.Multer.File) {
|
||||
const { category_id, measure_unit_id, sku_id, ...rest } = data
|
||||
|
||||
let image_url = ''
|
||||
if (file) {
|
||||
const uploadedUrl = await this.uploaderService.uploadFile(
|
||||
file,
|
||||
UploadedFileTypes.GOOD,
|
||||
)
|
||||
image_url = uploadedUrl || ''
|
||||
}
|
||||
|
||||
const updateData: any = {
|
||||
...rest,
|
||||
image_url,
|
||||
}
|
||||
|
||||
if (sku_id) {
|
||||
updateData.sku = { connect: { id: sku_id } }
|
||||
}
|
||||
if (measure_unit_id) {
|
||||
updateData.measure_unit = { connect: { id: measure_unit_id } }
|
||||
}
|
||||
if (category_id) {
|
||||
updateData.category = { connect: { id: category_id } }
|
||||
}
|
||||
|
||||
return updateData
|
||||
}
|
||||
|
||||
async handleImageUpdate(id: string, prisma: any, image_url: string) {
|
||||
if (image_url) {
|
||||
const prevImage = await prisma.good.findUnique({
|
||||
where: { id },
|
||||
select: { image_url: true },
|
||||
})
|
||||
|
||||
if (prevImage?.image_url) {
|
||||
this.uploaderService.deleteFile(prevImage.image_url, UploadedFileTypes.GOOD)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { PrismaService } from '@/prisma/prisma.service'
|
||||
import { BadRequestException, Injectable } from '@nestjs/common'
|
||||
import { ConsumerRole } from 'generated/prisma/enums'
|
||||
|
||||
@Injectable()
|
||||
export class SharedSaleInvoiceAccessService {
|
||||
constructor(private readonly prisma: PrismaService) {}
|
||||
|
||||
async getConsumerIdWithPosAccess(
|
||||
consumerAccountId: string,
|
||||
posId: string,
|
||||
): Promise<string> {
|
||||
const consumer = await this.prisma.consumerAccount.findUnique({
|
||||
where: {
|
||||
id: consumerAccountId,
|
||||
OR: [{ pos: { id: posId } }, { role: ConsumerRole.OWNER }],
|
||||
},
|
||||
select: {
|
||||
consumer_id: true,
|
||||
},
|
||||
})
|
||||
|
||||
if (!consumer) {
|
||||
throw new BadRequestException('شما دسترسی لازم برای ارسال صورتحساب را ندارید.')
|
||||
}
|
||||
|
||||
return consumer.consumer_id
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,547 @@
|
||||
import { SharedSaleInvoiceAccessService } from '@/common/services/saleInvoices/sale-invoice-access.service'
|
||||
import {
|
||||
PosCorrectionSalesInvoiceDto,
|
||||
PosReturnSalesInvoiceDto,
|
||||
} from '@/modules/pos/sales-invoices/dto/create-sales-invoice.dto'
|
||||
import { SalesInvoiceTspService } from '@/modules/tspProviders/sales-invoice-tsp.service'
|
||||
import { PrismaService } from '@/prisma/prisma.service'
|
||||
import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common'
|
||||
import {
|
||||
CustomerType,
|
||||
TspProviderRequestType,
|
||||
TspProviderResponseStatus,
|
||||
} from 'generated/prisma/enums'
|
||||
import { SharedSaleInvoiceCreateService } from './sale-invoice-create.service'
|
||||
|
||||
@Injectable()
|
||||
export class SharedSaleInvoiceActionsService {
|
||||
constructor(
|
||||
private prisma: PrismaService,
|
||||
private readonly salesInvoiceTspService: SalesInvoiceTspService,
|
||||
private readonly saleInvoiceAccessService: SharedSaleInvoiceAccessService,
|
||||
private sharedSaleInvoiceCreateService: SharedSaleInvoiceCreateService,
|
||||
) {}
|
||||
|
||||
async send(consumerAccountId: string, posId: string, invoiceId: string) {
|
||||
await this.saleInvoiceAccessService.getConsumerIdWithPosAccess(
|
||||
consumerAccountId,
|
||||
posId,
|
||||
)
|
||||
return this.salesInvoiceTspService.originalSend(posId, invoiceId)
|
||||
}
|
||||
|
||||
async retry(consumerAccountId: string, posId: string, invoiceId: string) {
|
||||
await this.saleInvoiceAccessService.getConsumerIdWithPosAccess(
|
||||
consumerAccountId,
|
||||
posId,
|
||||
)
|
||||
return this.salesInvoiceTspService.originalSend(posId, invoiceId)
|
||||
}
|
||||
|
||||
async revoke(
|
||||
consumerAccountId: string,
|
||||
posId: string,
|
||||
complexId: string,
|
||||
businessId: string,
|
||||
invoiceId: string,
|
||||
) {
|
||||
await this.saleInvoiceAccessService.getConsumerIdWithPosAccess(
|
||||
consumerAccountId,
|
||||
posId,
|
||||
)
|
||||
return this.salesInvoiceTspService.revoke(
|
||||
consumerAccountId,
|
||||
posId,
|
||||
complexId,
|
||||
businessId,
|
||||
invoiceId,
|
||||
)
|
||||
}
|
||||
|
||||
async correction(
|
||||
data: PosCorrectionSalesInvoiceDto,
|
||||
consumerAccountId: string,
|
||||
posId: string,
|
||||
complexId: string,
|
||||
businessId: string,
|
||||
invoiceId: string,
|
||||
) {
|
||||
await this.saleInvoiceAccessService.getConsumerIdWithPosAccess(
|
||||
consumerAccountId,
|
||||
posId,
|
||||
)
|
||||
|
||||
const newInvoice = await this.prisma.$transaction(async tx => {
|
||||
const relatedInvoice = await tx.salesInvoice.findUnique({
|
||||
where: {
|
||||
id: invoiceId,
|
||||
pos_id: posId,
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
invoice_date: true,
|
||||
settlement_type: true,
|
||||
customer_id: true,
|
||||
main_id: true,
|
||||
last_tsp_status: true,
|
||||
referenced_by: {
|
||||
select: {
|
||||
id: true,
|
||||
},
|
||||
},
|
||||
customer: {
|
||||
select: {
|
||||
type: true,
|
||||
},
|
||||
},
|
||||
total_amount: true,
|
||||
items: {
|
||||
select: {
|
||||
id: true,
|
||||
good_id: true,
|
||||
service_id: true,
|
||||
quantity: true,
|
||||
unit_price: true,
|
||||
total_amount: true,
|
||||
discount_amount: true,
|
||||
tax_amount: true,
|
||||
payload: true,
|
||||
notes: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
if (!relatedInvoice) {
|
||||
throw new NotFoundException('صورتحساب مورد نظر شما یافت نشد.')
|
||||
}
|
||||
|
||||
if (relatedInvoice.last_tsp_status !== TspProviderResponseStatus.SUCCESS) {
|
||||
throw new BadRequestException('امکان اصلاح این صورتحساب وجود ندارد.')
|
||||
}
|
||||
|
||||
if (relatedInvoice.referenced_by) {
|
||||
throw new BadRequestException(
|
||||
'این صورتحساب قبلا با یک صورتحساب دیگر جایگزین شده است.',
|
||||
)
|
||||
}
|
||||
|
||||
const normalizedInvoiceDate = this.normalizeInvoiceDate(data.invoice_date)
|
||||
const originalInvoiceDate = this.normalizeInvoiceDate(relatedInvoice.invoice_date)
|
||||
|
||||
const originalItemsByKey = new Map(
|
||||
relatedInvoice.items.map(item => [this.getItemKey(item), item]),
|
||||
)
|
||||
|
||||
const usedItemKeys = new Set<string>()
|
||||
const normalizedItems = data.items.map(item => {
|
||||
const itemKey = this.getItemKey(item)
|
||||
|
||||
if (!itemKey) {
|
||||
throw new BadRequestException('هر قلم باید شناسه کالا یا خدمت داشته باشد.')
|
||||
}
|
||||
|
||||
usedItemKeys.add(itemKey)
|
||||
|
||||
const originalItem = originalItemsByKey.get(itemKey)
|
||||
|
||||
if (!originalItem) {
|
||||
throw new BadRequestException(
|
||||
'فقط اقلام موجود در صورتحساب اصلی قابل اصلاح هستند.',
|
||||
)
|
||||
}
|
||||
|
||||
const originalQuantity = Number(originalItem.quantity)
|
||||
const requestedQuantity = Number(item.quantity)
|
||||
const originalUnitPrice = Number(originalItem.unit_price)
|
||||
const requestedUnitPrice = Number(item.unit_price)
|
||||
const originalTotalAmount = this.roundAmount(Number(originalItem.total_amount))
|
||||
const requestedTotalAmount = this.roundAmount(Number(item.total_amount))
|
||||
|
||||
if (requestedQuantity <= 0) {
|
||||
throw new BadRequestException(
|
||||
'تعداد/مقدار اقلام اصلاحی باید بیشتر از صفر باشد.',
|
||||
)
|
||||
}
|
||||
|
||||
// if (requestedUnitPrice < originalUnitPrice) {
|
||||
// throw new BadRequestException(
|
||||
// 'مبلغ واحد اقلام اصلاحی نمیتواند کمتر از صورتحساب اصلی باشد.',
|
||||
// )
|
||||
// }
|
||||
|
||||
return {
|
||||
invoice_id: originalItem.id,
|
||||
good_id: originalItem.good_id,
|
||||
service_id: originalItem.service_id || undefined,
|
||||
quantity: requestedQuantity,
|
||||
unit_price: requestedUnitPrice,
|
||||
total_amount: requestedTotalAmount,
|
||||
discount_amount: this.roundAmount(Number(item.discount_amount || 0)),
|
||||
tax_amount: this.roundAmount(Number(item.tax_amount || 0)),
|
||||
payload: item.payload ? JSON.parse(JSON.stringify(item.payload)) : undefined,
|
||||
notes: item.notes || undefined,
|
||||
}
|
||||
})
|
||||
|
||||
if (usedItemKeys.size !== relatedInvoice.items.length) {
|
||||
throw new BadRequestException(
|
||||
'فقط اقلام موجود در صورتحساب اصلی قابل اصلاح هستند.',
|
||||
)
|
||||
}
|
||||
|
||||
const hasChangedQuantity = normalizedItems.some(item => {
|
||||
const originalItem = relatedInvoice.items.find(
|
||||
relatedItem => this.getItemKey(relatedItem) === this.getItemKey(item),
|
||||
)
|
||||
|
||||
if (!originalItem) {
|
||||
return false
|
||||
}
|
||||
|
||||
return Number(originalItem.quantity) !== Number(item.quantity)
|
||||
})
|
||||
const hasChangedAmount = normalizedItems.some(item => {
|
||||
const originalItem = relatedInvoice.items.find(
|
||||
relatedItem => this.getItemKey(relatedItem) === this.getItemKey(item),
|
||||
)
|
||||
|
||||
if (!originalItem) {
|
||||
return false
|
||||
}
|
||||
|
||||
return (
|
||||
this.roundAmount(Number(originalItem.total_amount)) !==
|
||||
this.roundAmount(Number(item.total_amount))
|
||||
)
|
||||
})
|
||||
const hasChangedInvoiceDate = normalizedInvoiceDate !== originalInvoiceDate
|
||||
|
||||
if (!hasChangedQuantity && !hasChangedAmount && !hasChangedInvoiceDate) {
|
||||
throw new BadRequestException('مقداری تغییر نکرده است.')
|
||||
}
|
||||
|
||||
const requestedTotalAmount = this.roundAmount(Number(data.total_amount))
|
||||
const originalTotalAmount = this.roundAmount(Number(relatedInvoice.total_amount))
|
||||
const totalDiff = this.roundAmount(requestedTotalAmount - originalTotalAmount)
|
||||
const paymentsAmount = this.roundAmount(this.getPaymentsAmount(data.payments))
|
||||
|
||||
if (totalDiff > 0 && paymentsAmount !== totalDiff) {
|
||||
throw new BadRequestException(
|
||||
'جمع پرداختی باید برابر با اختلاف مبلغ صورتحساب اصلاحی و صورتحساب مرجع باشد.',
|
||||
)
|
||||
}
|
||||
|
||||
if (totalDiff === 0 && paymentsAmount !== 0) {
|
||||
throw new BadRequestException('در صورت عدم افزایش مبلغ، پرداختی نباید ثبت شود.')
|
||||
}
|
||||
|
||||
const newInvoice = await this.sharedSaleInvoiceCreateService.create({
|
||||
tx,
|
||||
data: {
|
||||
invoice_date: new Date(normalizedInvoiceDate),
|
||||
items: normalizedItems as any,
|
||||
total_amount: requestedTotalAmount,
|
||||
discount_amount: this.roundAmount(Number(data.discount_amount)),
|
||||
tax_amount: this.roundAmount(Number(data.tax_amount)),
|
||||
customer_id: relatedInvoice.customer_id || undefined,
|
||||
customer_type: relatedInvoice.customer?.type || CustomerType.UNKNOWN,
|
||||
settlement_type: relatedInvoice.settlement_type,
|
||||
payments: data.payments,
|
||||
} as any,
|
||||
businessId,
|
||||
complexId,
|
||||
posId,
|
||||
consumerAccountId,
|
||||
main_invoice_id: relatedInvoice.main_id || relatedInvoice.id,
|
||||
ref_invoice_id: relatedInvoice.id,
|
||||
type: TspProviderRequestType.CORRECTION,
|
||||
})
|
||||
|
||||
await tx.salesInvoice.update({
|
||||
where: {
|
||||
id: relatedInvoice.id,
|
||||
},
|
||||
data: {
|
||||
referenced_by: {
|
||||
connect: {
|
||||
id: newInvoice.id,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
return newInvoice
|
||||
})
|
||||
|
||||
return this.salesInvoiceTspService.correctionSend(posId, newInvoice.id)
|
||||
}
|
||||
|
||||
async return(
|
||||
data: PosReturnSalesInvoiceDto,
|
||||
consumerAccountId: string,
|
||||
pos_id: string,
|
||||
complex_id: string,
|
||||
business_id: string,
|
||||
invoiceId: string,
|
||||
) {
|
||||
await this.saleInvoiceAccessService.getConsumerIdWithPosAccess(
|
||||
consumerAccountId,
|
||||
pos_id,
|
||||
)
|
||||
|
||||
const newInvoice = await this.prisma.$transaction(async tx => {
|
||||
const relatedInvoice = await tx.salesInvoice.findUnique({
|
||||
where: {
|
||||
id: invoiceId,
|
||||
pos_id,
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
type: true,
|
||||
invoice_date: true,
|
||||
settlement_type: true,
|
||||
customer_id: true,
|
||||
main_id: true,
|
||||
last_tsp_status: true,
|
||||
referenced_by: {
|
||||
select: {
|
||||
id: true,
|
||||
},
|
||||
},
|
||||
customer: {
|
||||
select: {
|
||||
type: true,
|
||||
},
|
||||
},
|
||||
items: {
|
||||
select: {
|
||||
id: true,
|
||||
good_id: true,
|
||||
service_id: true,
|
||||
quantity: true,
|
||||
unit_price: true,
|
||||
total_amount: true,
|
||||
discount_amount: true,
|
||||
tax_amount: true,
|
||||
payload: true,
|
||||
notes: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
if (!relatedInvoice) {
|
||||
throw new NotFoundException('صورتحساب مورد نظر شما یافت نشد.')
|
||||
}
|
||||
|
||||
if (relatedInvoice.last_tsp_status !== TspProviderResponseStatus.SUCCESS) {
|
||||
throw new BadRequestException('امکان برگشت از خرید روی این صورتحساب وجود ندارد.')
|
||||
}
|
||||
|
||||
if (relatedInvoice.referenced_by) {
|
||||
throw new BadRequestException(
|
||||
'این صورتحساب قبلا با یک صورتحساب دیگر جایگزین شده است.',
|
||||
)
|
||||
}
|
||||
|
||||
const normalizedInvoiceDate = this.normalizeInvoiceDate(data.invoice_date)
|
||||
const originalInvoiceDate = this.normalizeInvoiceDate(relatedInvoice.invoice_date)
|
||||
|
||||
const originalItemsByKey = new Map(
|
||||
relatedInvoice.items.map(item => [this.getReturnItemKey(item), item]),
|
||||
)
|
||||
|
||||
const usedItemKeys = new Set<string>()
|
||||
const normalizedItems = data.items.map(item => {
|
||||
const itemKey = this.getReturnItemKey(item)
|
||||
|
||||
if (!itemKey) {
|
||||
throw new BadRequestException('هر قلم باید شناسه کالا یا خدمت داشته باشد.')
|
||||
}
|
||||
|
||||
// if (usedItemKeys.has(itemKey)) {
|
||||
// throw new BadRequestException('اقلام تکراری در صورتحساب بازگشتی مجاز نیستند.')
|
||||
// }
|
||||
|
||||
usedItemKeys.add(itemKey)
|
||||
|
||||
const originalItem = originalItemsByKey.get(itemKey)
|
||||
|
||||
if (!originalItem) {
|
||||
throw new BadRequestException(
|
||||
'فقط اقلام موجود در صورتحساب اصلی قابل بازگشت هستند.',
|
||||
)
|
||||
}
|
||||
|
||||
const originalQuantity = Number(originalItem.quantity)
|
||||
const requestedQuantity = Number(item.quantity)
|
||||
|
||||
if (requestedQuantity <= 0) {
|
||||
throw new BadRequestException(
|
||||
'تعداد/مقدار اقلام بازگشتی باید بیشتر از صفر باشد.',
|
||||
)
|
||||
}
|
||||
|
||||
if (requestedQuantity > originalQuantity) {
|
||||
throw new BadRequestException(
|
||||
'تعداد/مقدار اقلام بازگشتی نمیتواند از مقدار صورتحساب اصلی بیشتر باشد.',
|
||||
)
|
||||
}
|
||||
|
||||
const quantityRatio = requestedQuantity / originalQuantity
|
||||
|
||||
return {
|
||||
invoice_id: originalItem.id,
|
||||
good_id: originalItem.good_id,
|
||||
service_id: originalItem.service_id || undefined,
|
||||
quantity: requestedQuantity,
|
||||
unit_price: Number(originalItem.unit_price),
|
||||
total_amount: this.roundAmount(
|
||||
Number(originalItem.total_amount) * quantityRatio,
|
||||
),
|
||||
discount_amount: this.roundAmount(
|
||||
Number(originalItem.discount_amount || 0) * quantityRatio,
|
||||
),
|
||||
tax_amount: this.roundAmount(
|
||||
Number(originalItem.tax_amount || 0) * quantityRatio,
|
||||
),
|
||||
payload: originalItem.payload
|
||||
? JSON.parse(JSON.stringify(originalItem.payload))
|
||||
: undefined,
|
||||
notes: originalItem.notes || undefined,
|
||||
}
|
||||
})
|
||||
|
||||
if (!normalizedItems.length) {
|
||||
throw new BadRequestException(
|
||||
'حداقل یک قلم باید در صورتحساب بازگشتی باقی بماند.',
|
||||
)
|
||||
}
|
||||
|
||||
const hasRemovedItem = relatedInvoice.items.some(
|
||||
item => !usedItemKeys.has(this.getReturnItemKey(item)),
|
||||
)
|
||||
const hasChangedQuantity = normalizedItems.some(item => {
|
||||
const originalItem = relatedInvoice.items.find(
|
||||
relatedItem =>
|
||||
this.getReturnItemKey(relatedItem) === this.getReturnItemKey(item),
|
||||
)
|
||||
|
||||
if (!originalItem) {
|
||||
return false
|
||||
}
|
||||
|
||||
return Number(originalItem.quantity) !== Number(item.quantity)
|
||||
})
|
||||
const hasChangedInvoiceDate = normalizedInvoiceDate !== originalInvoiceDate
|
||||
|
||||
if (!hasRemovedItem && !hasChangedQuantity && !hasChangedInvoiceDate) {
|
||||
throw new BadRequestException('مقداری تغییر نکرده است.')
|
||||
}
|
||||
|
||||
const totalAmount = normalizedItems.reduce(
|
||||
(sum, item) => sum + Number(item.total_amount),
|
||||
0,
|
||||
)
|
||||
const discountAmount = normalizedItems.reduce(
|
||||
(sum, item) => sum + Number(item.discount_amount || 0),
|
||||
0,
|
||||
)
|
||||
const taxAmount = normalizedItems.reduce(
|
||||
(sum, item) => sum + Number(item.tax_amount || 0),
|
||||
0,
|
||||
)
|
||||
|
||||
const newInvoice = await this.sharedSaleInvoiceCreateService.create({
|
||||
tx,
|
||||
data: {
|
||||
invoice_date: new Date(normalizedInvoiceDate),
|
||||
items: normalizedItems as any,
|
||||
total_amount: totalAmount,
|
||||
discount_amount: discountAmount,
|
||||
tax_amount: taxAmount,
|
||||
customer_id: relatedInvoice.customer_id || undefined,
|
||||
customer_type: relatedInvoice.customer?.type || CustomerType.UNKNOWN,
|
||||
settlement_type: relatedInvoice.settlement_type,
|
||||
payments: undefined,
|
||||
} as any,
|
||||
businessId: business_id,
|
||||
complexId: complex_id,
|
||||
posId: pos_id,
|
||||
consumerAccountId,
|
||||
main_invoice_id: relatedInvoice.main_id || relatedInvoice.id,
|
||||
ref_invoice_id: relatedInvoice.id,
|
||||
type: TspProviderRequestType.RETURN,
|
||||
})
|
||||
|
||||
await tx.salesInvoice.update({
|
||||
where: {
|
||||
id: relatedInvoice.id,
|
||||
},
|
||||
data: {
|
||||
referenced_by: {
|
||||
connect: {
|
||||
id: newInvoice.id,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
return newInvoice
|
||||
})
|
||||
|
||||
return this.salesInvoiceTspService.returnFromSaleSend(
|
||||
pos_id,
|
||||
business_id,
|
||||
newInvoice.id,
|
||||
)
|
||||
}
|
||||
|
||||
private normalizeInvoiceDate(invoiceDate: Date | string) {
|
||||
return new Date(invoiceDate).toISOString()
|
||||
}
|
||||
|
||||
private getItemKey(item: { good_id?: string | null; service_id?: string | null }) {
|
||||
return item.good_id || item.service_id || ''
|
||||
}
|
||||
|
||||
private getPaymentsAmount(payments?: {
|
||||
terminals?: { amount?: number }
|
||||
cash?: number
|
||||
set_off?: number
|
||||
card?: number
|
||||
bank?: number
|
||||
check?: number
|
||||
other?: number
|
||||
}) {
|
||||
return (
|
||||
Number(payments?.terminals?.amount || 0) +
|
||||
Number(payments?.cash || 0) +
|
||||
Number(payments?.set_off || 0) +
|
||||
Number(payments?.card || 0) +
|
||||
Number(payments?.bank || 0) +
|
||||
Number(payments?.check || 0) +
|
||||
Number(payments?.other || 0)
|
||||
)
|
||||
}
|
||||
|
||||
private roundAmount(amount: number) {
|
||||
return Number(amount.toFixed(2))
|
||||
}
|
||||
|
||||
async inquiry(consumerAccountId: string, posId: string, invoiceId: string) {
|
||||
const consumerId = await this.saleInvoiceAccessService.getConsumerIdWithPosAccess(
|
||||
consumerAccountId,
|
||||
posId,
|
||||
)
|
||||
return this.salesInvoiceTspService.get(invoiceId, posId, consumerId)
|
||||
}
|
||||
|
||||
private getReturnItemKey(item: {
|
||||
good_id?: string | null
|
||||
service_id?: string | null
|
||||
}) {
|
||||
return item.good_id || item.service_id || ''
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,247 @@
|
||||
import type { SaleInvoiceType } from '@/common/interfaces/sale-invoice-payload'
|
||||
import { ApiProperty, OmitType } from '@nestjs/swagger'
|
||||
import { Type } from 'class-transformer'
|
||||
import {
|
||||
ArrayMinSize,
|
||||
IsBoolean,
|
||||
IsDate,
|
||||
IsDateString,
|
||||
IsEnum,
|
||||
IsNotEmpty,
|
||||
IsNumber,
|
||||
IsObject,
|
||||
IsOptional,
|
||||
IsString,
|
||||
Min,
|
||||
ValidateNested,
|
||||
} from 'class-validator'
|
||||
import {
|
||||
CustomerIndividual,
|
||||
CustomerLegal,
|
||||
InvoiceSettlementType,
|
||||
} from 'generated/prisma/client'
|
||||
import { CustomerType } from 'generated/prisma/enums'
|
||||
|
||||
export class SharedCreateSalesInvoiceItemDto {
|
||||
@IsNumber()
|
||||
@ApiProperty({ required: true })
|
||||
unit_price: number
|
||||
|
||||
@IsNumber()
|
||||
@ApiProperty({ required: true, default: 1 })
|
||||
quantity: number
|
||||
|
||||
@IsNumber()
|
||||
@ApiProperty({ required: true })
|
||||
discount_amount: number
|
||||
|
||||
@IsNumber()
|
||||
@ApiProperty({ required: true })
|
||||
tax_amount: number
|
||||
|
||||
@IsNumber()
|
||||
@ApiProperty({ required: true })
|
||||
total_amount: number
|
||||
|
||||
@IsString()
|
||||
@ApiProperty({ required: true })
|
||||
invoice_id: string
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@ApiProperty({ required: false })
|
||||
good_id?: string
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@ApiProperty({ required: false })
|
||||
service_id?: string
|
||||
|
||||
// @IsEnum(SalesInvoiceItemPricingModel)
|
||||
// @ApiProperty({ enum: Object.values(SalesInvoiceItemPricingModel) })
|
||||
// @IsOptional()
|
||||
// pricingModel: SalesInvoiceItemPricingModel
|
||||
|
||||
@IsOptional()
|
||||
@IsObject()
|
||||
@ApiProperty({ required: false, default: {} })
|
||||
payload: SaleInvoiceType
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@ApiProperty({ required: false, default: '' })
|
||||
notes: string
|
||||
}
|
||||
|
||||
export class SharedCreateTerminalPayment {
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
@Min(0)
|
||||
@ApiProperty({ required: false, default: 0 })
|
||||
amount?: number
|
||||
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
@ApiProperty({ required: true })
|
||||
terminal_id: string
|
||||
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
@ApiProperty({ required: true })
|
||||
stan: string
|
||||
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
@ApiProperty({ required: true })
|
||||
rrn: string
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
@ApiProperty({ required: true })
|
||||
response_code?: string
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
@ApiProperty({ required: true })
|
||||
customer_card_no?: string
|
||||
|
||||
@Type(() => Date)
|
||||
@IsDate()
|
||||
@ApiProperty({ required: true })
|
||||
transaction_date_time: Date
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@ApiProperty({ required: false })
|
||||
description?: string
|
||||
}
|
||||
|
||||
export class SharedCreateSalesInvoicePaymentsDto {
|
||||
@IsOptional()
|
||||
@ValidateNested()
|
||||
@Type(() => SharedCreateTerminalPayment)
|
||||
@ApiProperty({ required: false, type: () => SharedCreateTerminalPayment })
|
||||
terminals?: SharedCreateTerminalPayment
|
||||
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
@Min(0)
|
||||
@ApiProperty({ required: false, default: 0 })
|
||||
cash?: number
|
||||
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
@Min(0)
|
||||
@ApiProperty({ required: false, default: 0 })
|
||||
set_off?: number
|
||||
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
@Min(0)
|
||||
@ApiProperty({ required: false, default: 0 })
|
||||
card?: number
|
||||
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
@Min(0)
|
||||
@ApiProperty({ required: false, default: 0 })
|
||||
bank?: number
|
||||
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
@Min(0)
|
||||
@ApiProperty({ required: false, default: 0 })
|
||||
check?: number
|
||||
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
@Min(0)
|
||||
@ApiProperty({ required: false, default: 0 })
|
||||
other?: number
|
||||
}
|
||||
|
||||
export class SharedCreateSalesInvoiceDto {
|
||||
// @TODO: totalAmount must calculated instead of get from api
|
||||
@IsNumber()
|
||||
@ApiProperty({ required: true, default: 0 })
|
||||
total_amount: number
|
||||
|
||||
@IsNumber()
|
||||
@ApiProperty({ required: true, default: 0 })
|
||||
discount_amount: number
|
||||
|
||||
@IsNumber()
|
||||
@ApiProperty({ required: true, default: 0 })
|
||||
tax_amount: number
|
||||
|
||||
@ApiProperty({ required: true })
|
||||
@IsDateString(
|
||||
{ strict: true },
|
||||
{ message: 'invoice_date must be a valid ISO-8601 string' },
|
||||
)
|
||||
invoice_date: Date
|
||||
|
||||
@ApiProperty({ required: true, enum: InvoiceSettlementType })
|
||||
@IsEnum(InvoiceSettlementType)
|
||||
settlement_type: InvoiceSettlementType
|
||||
|
||||
@ApiProperty({ required: true })
|
||||
@IsObject()
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => SharedCreateSalesInvoicePaymentsDto)
|
||||
payments: SharedCreateSalesInvoicePaymentsDto
|
||||
|
||||
@ApiProperty()
|
||||
@ArrayMinSize(1)
|
||||
@ValidateNested({ each: true })
|
||||
items: SharedCreateSalesInvoiceItemDto[]
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
ref_invoice_id?: string
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
notes?: string
|
||||
|
||||
@ApiProperty({ required: false, default: false })
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
send_to_tsp?: boolean
|
||||
|
||||
@ApiProperty({ required: true, default: CustomerType.UNKNOWN })
|
||||
@IsEnum(CustomerType)
|
||||
customer_type: CustomerType
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@ApiProperty({ required: false })
|
||||
customer_id?: string
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
@IsOptional()
|
||||
@IsObject()
|
||||
customer?: {
|
||||
customer_individual?: Omit<CustomerIndividual, 'business_activity_id' | 'customer_id'>
|
||||
customer_legal?: Omit<CustomerLegal, 'business_activity_id' | 'customer_id'>
|
||||
customer_unknown?: {
|
||||
first_name: string
|
||||
last_name: string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class SharedCorrectionSalesInvoiceDto extends OmitType(
|
||||
SharedCreateSalesInvoiceDto,
|
||||
['customer', 'customer_id', 'customer_type', 'settlement_type'],
|
||||
) {}
|
||||
|
||||
export class SharedReturnSalesInvoiceDto extends OmitType(SharedCreateSalesInvoiceDto, [
|
||||
'customer',
|
||||
'customer_id',
|
||||
'customer_type',
|
||||
'settlement_type',
|
||||
'payments',
|
||||
]) {}
|
||||
@@ -0,0 +1,574 @@
|
||||
import { QUERY_CONSTANTS } from '@/common/queryConstants'
|
||||
import { SalesInvoiceCreateInput } from '@/generated/prisma/models'
|
||||
import { PrismaService } from '@/prisma/prisma.service'
|
||||
import { BadRequestException, Injectable } from '@nestjs/common'
|
||||
import { Prisma } from 'generated/prisma/client'
|
||||
import {
|
||||
CustomerType,
|
||||
PaymentMethodType,
|
||||
TspProviderRequestType,
|
||||
} from 'generated/prisma/enums'
|
||||
import { SharedCreateSalesInvoiceDto } from './sale-invoice-create.dto'
|
||||
|
||||
interface TerminalPaymentInfo {
|
||||
terminal_id: string
|
||||
stan: string
|
||||
rrn: string
|
||||
transaction_date_time: string | Date
|
||||
customer_card_no: string
|
||||
description?: string
|
||||
amount: number
|
||||
}
|
||||
|
||||
interface NormalizedPayment {
|
||||
method: PaymentMethodType
|
||||
amount: number
|
||||
terminalInfo?: TerminalPaymentInfo
|
||||
}
|
||||
|
||||
interface CreateSharedSaleInvoiceInput {
|
||||
tx?: Prisma.TransactionClient
|
||||
data: SharedCreateSalesInvoiceDto
|
||||
businessId: string
|
||||
complexId: string
|
||||
posId: string
|
||||
consumerAccountId: string
|
||||
type: TspProviderRequestType
|
||||
main_invoice_id?: string
|
||||
ref_invoice_id?: string
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class SharedSaleInvoiceCreateService {
|
||||
private readonly createInvoiceRetries = 3
|
||||
|
||||
constructor(private prisma: PrismaService) {}
|
||||
|
||||
async create(input: CreateSharedSaleInvoiceInput) {
|
||||
const {
|
||||
tx = this.prisma,
|
||||
data,
|
||||
businessId,
|
||||
complexId,
|
||||
posId,
|
||||
consumerAccountId,
|
||||
type,
|
||||
main_invoice_id,
|
||||
ref_invoice_id,
|
||||
} = input
|
||||
|
||||
const normalizedInvoiceDate = this.normalizeInvoiceDate(data.invoice_date)
|
||||
const payments =
|
||||
type === TspProviderRequestType.ORIGINAL || data.payments
|
||||
? this.buildPaymentsData(data.payments, data.total_amount)
|
||||
: []
|
||||
|
||||
for (let attempt = 1; attempt <= this.createInvoiceRetries; attempt++) {
|
||||
try {
|
||||
return await tx.$transaction(async $tx => {
|
||||
const invoiceNumber = await this.getNextInvoiceNumber($tx, businessId)
|
||||
const customerId = await this.resolveCustomerId($tx, data, businessId)
|
||||
const goodsById = await this.getGoodsById($tx, data)
|
||||
const salesInvoiceData = this.buildSalesInvoiceData({
|
||||
data,
|
||||
normalizedInvoiceDate,
|
||||
invoiceNumber,
|
||||
consumerAccountId,
|
||||
businessId,
|
||||
complexId,
|
||||
posId,
|
||||
goodsById,
|
||||
customerId,
|
||||
type,
|
||||
main_invoice_id,
|
||||
ref_invoice_id,
|
||||
})
|
||||
|
||||
const salesInvoice = await $tx.salesInvoice.create({
|
||||
data: salesInvoiceData,
|
||||
select: { ...QUERY_CONSTANTS.SALE_INVOICE.select },
|
||||
})
|
||||
|
||||
if (payments.length) {
|
||||
await this.createPayments(
|
||||
$tx,
|
||||
salesInvoice.id,
|
||||
payments,
|
||||
normalizedInvoiceDate,
|
||||
)
|
||||
}
|
||||
|
||||
return salesInvoice
|
||||
})
|
||||
} catch (error) {
|
||||
if (
|
||||
this.isRetryableInvoiceConflict(error) &&
|
||||
attempt < this.createInvoiceRetries
|
||||
) {
|
||||
continue
|
||||
}
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
throw new BadRequestException('ایجاد صورتحساب با خطا مواجه شد.')
|
||||
}
|
||||
|
||||
private isRetryableInvoiceConflict(error: unknown) {
|
||||
if (!(error instanceof Prisma.PrismaClientKnownRequestError)) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (error.code !== 'P2002') {
|
||||
return false
|
||||
}
|
||||
|
||||
const target = (error.meta?.target as string[]) || []
|
||||
return (
|
||||
target.includes('invoice_number') ||
|
||||
target.includes('sales_invoices_invoice_number_pos_id_key')
|
||||
)
|
||||
}
|
||||
|
||||
private normalizeInvoiceDate(invoiceDate: Date | string) {
|
||||
return new Date(invoiceDate).toISOString() as any
|
||||
}
|
||||
|
||||
private buildPaymentsData(
|
||||
paymentsData: SharedCreateSalesInvoiceDto['payments'],
|
||||
totalAmount: number,
|
||||
) {
|
||||
const paymentMethodMap: Record<string, PaymentMethodType> = {
|
||||
cash: PaymentMethodType.CASH,
|
||||
set_off: PaymentMethodType.SET_OFF,
|
||||
card: PaymentMethodType.CARD,
|
||||
payment_gateway: PaymentMethodType.PAYMENT_GATEWAY,
|
||||
bank: PaymentMethodType.BANK,
|
||||
check: PaymentMethodType.CHEQUE,
|
||||
other: PaymentMethodType.OTHER,
|
||||
terminal: PaymentMethodType.TERMINAL,
|
||||
}
|
||||
|
||||
const rawPayments = (paymentsData || {}) as Record<string, unknown>
|
||||
const terminalPayments = rawPayments.terminals as TerminalPaymentInfo[] | undefined
|
||||
|
||||
const payments: NormalizedPayment[] = Object.entries(rawPayments)
|
||||
.filter(([key, value]) => key !== 'terminals' && value && Number(value) > 0)
|
||||
.map(([key, value]) => ({
|
||||
method: paymentMethodMap[key.toLowerCase()],
|
||||
amount: typeof value === 'number' ? value : Number(value || 0),
|
||||
}))
|
||||
.filter(payment => payment.method && payment.amount > 0) as NormalizedPayment[]
|
||||
|
||||
const hasTerminalPayment = terminalPayments && terminalPayments.length
|
||||
|
||||
if (hasTerminalPayment) {
|
||||
for (const terminal of terminalPayments) {
|
||||
payments.push({
|
||||
method: PaymentMethodType.TERMINAL,
|
||||
amount: terminal.amount,
|
||||
terminalInfo: terminal,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: for correction i need to validate payments with diff of total amount and original invoice amount
|
||||
// this.validatePayments(payments, totalAmount)
|
||||
|
||||
return payments
|
||||
}
|
||||
|
||||
private validatePayments(payments: NormalizedPayment[], totalAmount: number) {
|
||||
const totalPayments = payments.reduce((sum, payment) => sum + payment.amount, 0)
|
||||
const roundedTotalPayments = Number(totalPayments.toFixed(2))
|
||||
const roundedTotalAmount = Number(Number(totalAmount).toFixed(2))
|
||||
|
||||
if (roundedTotalPayments !== roundedTotalAmount) {
|
||||
throw new BadRequestException('مبلغ پرداختی باید برابر با مبلغ کل صورتحساب باشد.')
|
||||
}
|
||||
}
|
||||
|
||||
private async resolveCustomerId(
|
||||
tx: Prisma.TransactionClient,
|
||||
data: SharedCreateSalesInvoiceDto,
|
||||
businessId: string,
|
||||
) {
|
||||
const { customer_id, customer_type, customer } = data
|
||||
|
||||
if (customer_id) {
|
||||
return customer_id
|
||||
}
|
||||
|
||||
if (customer_type === CustomerType.INDIVIDUAL && customer?.customer_individual) {
|
||||
const { national_id, postal_code, economic_code, ...rest } =
|
||||
customer.customer_individual
|
||||
|
||||
const foundedCustomer = await tx.customerIndividual.findFirst({
|
||||
where: {
|
||||
business_activity_id: businessId,
|
||||
OR: [
|
||||
{
|
||||
economic_code,
|
||||
},
|
||||
{
|
||||
postal_code,
|
||||
national_id,
|
||||
},
|
||||
],
|
||||
},
|
||||
select: {
|
||||
customer_id: true,
|
||||
},
|
||||
})
|
||||
let customerIndividualId: string | undefined = foundedCustomer?.customer_id
|
||||
|
||||
if (foundedCustomer) {
|
||||
await tx.customerIndividual.update({
|
||||
where: {
|
||||
customer_id: foundedCustomer.customer_id,
|
||||
},
|
||||
data: {
|
||||
...customer.customer_individual,
|
||||
},
|
||||
})
|
||||
} else {
|
||||
const createdCustomer = await tx.customerIndividual.create({
|
||||
data: {
|
||||
...customer.customer_individual,
|
||||
customer: {
|
||||
create: {
|
||||
type: CustomerType.INDIVIDUAL,
|
||||
},
|
||||
},
|
||||
business_activity: {
|
||||
connect: {
|
||||
id: businessId,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
customerIndividualId = createdCustomer.customer_id
|
||||
}
|
||||
|
||||
if (!customerIndividualId) {
|
||||
throw new BadRequestException('متاسفانه مشکلی در اطلاعات مشتری وجود دارد.')
|
||||
}
|
||||
|
||||
return customerIndividualId
|
||||
} else if (customer_type === CustomerType.LEGAL && customer?.customer_legal) {
|
||||
const { registration_number, economic_code, postal_code } = customer.customer_legal
|
||||
const foundedCustomer = await tx.customerLegal.findFirst({
|
||||
where: {
|
||||
business_activity_id: businessId,
|
||||
OR: [
|
||||
{
|
||||
economic_code,
|
||||
},
|
||||
{
|
||||
postal_code,
|
||||
registration_number,
|
||||
},
|
||||
],
|
||||
},
|
||||
select: {
|
||||
customer_id: true,
|
||||
},
|
||||
})
|
||||
let customerLegalId: string | undefined = foundedCustomer?.customer_id
|
||||
|
||||
if (foundedCustomer) {
|
||||
await tx.customerLegal.update({
|
||||
where: {
|
||||
customer_id: foundedCustomer.customer_id,
|
||||
},
|
||||
data: {
|
||||
...customer.customer_legal,
|
||||
},
|
||||
})
|
||||
} else {
|
||||
const createdCustomer = await tx.customerLegal.create({
|
||||
data: {
|
||||
...customer.customer_legal,
|
||||
customer: {
|
||||
create: {
|
||||
type: CustomerType.LEGAL,
|
||||
},
|
||||
},
|
||||
business_activity: {
|
||||
connect: {
|
||||
id: businessId,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
customerLegalId = createdCustomer.customer_id
|
||||
}
|
||||
|
||||
if (!customerLegalId) {
|
||||
throw new BadRequestException('متاسفانه مشکلی در اطلاعات مشتری وجود دارد.')
|
||||
}
|
||||
|
||||
return customerLegalId
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private async getGoodsById(
|
||||
tx: Prisma.TransactionClient,
|
||||
data: SharedCreateSalesInvoiceDto,
|
||||
) {
|
||||
const itemGoodIds = data.items
|
||||
.map(item => item.good_id)
|
||||
.filter((goodId): goodId is string => Boolean(goodId))
|
||||
|
||||
const goods = itemGoodIds.length
|
||||
? await tx.good.findMany({
|
||||
where: {
|
||||
id: {
|
||||
in: itemGoodIds,
|
||||
},
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
sku: {
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
code: true,
|
||||
VAT: true,
|
||||
},
|
||||
},
|
||||
local_sku: true,
|
||||
barcode: true,
|
||||
pricing_model: true,
|
||||
measure_unit: {
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
code: true,
|
||||
},
|
||||
},
|
||||
base_sale_price: true,
|
||||
image_url: true,
|
||||
category: {
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
: []
|
||||
|
||||
return new Map(goods.map(good => [good.id, good]))
|
||||
}
|
||||
|
||||
private buildSalesInvoiceData(params: {
|
||||
data: SharedCreateSalesInvoiceDto
|
||||
normalizedInvoiceDate: Date
|
||||
invoiceNumber: number
|
||||
consumerAccountId: string
|
||||
businessId: string
|
||||
complexId: string
|
||||
posId: string
|
||||
goodsById: Map<string, any>
|
||||
customerId: string | null
|
||||
type: TspProviderRequestType
|
||||
main_invoice_id?: string
|
||||
ref_invoice_id?: string
|
||||
}) {
|
||||
const {
|
||||
data,
|
||||
normalizedInvoiceDate,
|
||||
invoiceNumber,
|
||||
consumerAccountId,
|
||||
posId,
|
||||
goodsById,
|
||||
customerId,
|
||||
businessId,
|
||||
complexId,
|
||||
type,
|
||||
main_invoice_id,
|
||||
ref_invoice_id,
|
||||
} = params
|
||||
const {
|
||||
customer_id,
|
||||
customer_type,
|
||||
customer,
|
||||
payments,
|
||||
settlement_type,
|
||||
send_to_tsp,
|
||||
...invoiceData
|
||||
} = data
|
||||
|
||||
if (
|
||||
type !== TspProviderRequestType.ORIGINAL &&
|
||||
!(main_invoice_id || ref_invoice_id)
|
||||
) {
|
||||
throw new BadRequestException('متاسفانه مشکلی در اطلاعات صورتحساب وجود دارد.')
|
||||
}
|
||||
|
||||
const salesInvoiceData: SalesInvoiceCreateInput = {
|
||||
...invoiceData,
|
||||
invoice_date: normalizedInvoiceDate,
|
||||
invoice_number: invoiceNumber,
|
||||
total_amount: data.total_amount,
|
||||
discount_amount: data.items.reduce(
|
||||
(prev, curr) => (prev += curr.discount_amount),
|
||||
0,
|
||||
),
|
||||
tax_amount: data.items.reduce((prev, curr) => (prev += curr.tax_amount), 0),
|
||||
code: this.generateInvoiceCode(businessId, complexId, posId, invoiceNumber),
|
||||
type,
|
||||
settlement_type,
|
||||
items: {
|
||||
createMany: {
|
||||
data: data.items.map(item => ({
|
||||
good_id: item.good_id!,
|
||||
quantity: item.quantity,
|
||||
unit_price: item.unit_price,
|
||||
total_amount: item.total_amount,
|
||||
discount_amount: item.discount_amount,
|
||||
tax_amount: item.tax_amount,
|
||||
measure_unit_text: goodsById.get(item.good_id!)?.measure_unit.name || null,
|
||||
measure_unit_code: goodsById.get(item.good_id!)?.measure_unit.code || null,
|
||||
sku_code: goodsById.get(item.good_id!)?.sku.code || null,
|
||||
sku_vat: goodsById.get(item.good_id!)?.sku.VAT || null,
|
||||
payload: item.payload ? JSON.parse(JSON.stringify(item.payload)) : undefined,
|
||||
good_snapshot: item.good_id
|
||||
? JSON.parse(JSON.stringify(goodsById.get(item.good_id) || null))
|
||||
: undefined,
|
||||
})),
|
||||
},
|
||||
},
|
||||
unknown_customer: {},
|
||||
consumer_account: {
|
||||
connect: {
|
||||
id: consumerAccountId,
|
||||
},
|
||||
},
|
||||
pos: {
|
||||
connect: {
|
||||
id: posId,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if (customerId) {
|
||||
salesInvoiceData.customer = {
|
||||
connect: {
|
||||
id: customerId,
|
||||
},
|
||||
}
|
||||
} else if (data.customer?.customer_unknown) {
|
||||
salesInvoiceData.unknown_customer = data.customer.customer_unknown
|
||||
}
|
||||
|
||||
if (type !== TspProviderRequestType.ORIGINAL) {
|
||||
salesInvoiceData.main_id = main_invoice_id
|
||||
salesInvoiceData.reference_invoice = {
|
||||
connect: {
|
||||
id: ref_invoice_id,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return salesInvoiceData
|
||||
}
|
||||
|
||||
async getNextInvoiceNumber(tx: Prisma.TransactionClient, businessId: string) {
|
||||
const latestInvoice = await tx.salesInvoice.findFirst({
|
||||
where: {
|
||||
pos: {
|
||||
complex: {
|
||||
business_activity_id: businessId,
|
||||
},
|
||||
},
|
||||
},
|
||||
orderBy: {
|
||||
invoice_number: 'desc',
|
||||
},
|
||||
select: {
|
||||
invoice_number: true,
|
||||
pos: {
|
||||
select: {
|
||||
complex: {
|
||||
select: {
|
||||
business_activity: {
|
||||
select: {
|
||||
invoice_number_sequence: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const latestSequence =
|
||||
latestInvoice?.pos?.complex?.business_activity?.invoice_number_sequence.toNumber() ||
|
||||
0
|
||||
|
||||
return Math.max(latestInvoice?.invoice_number || 0, latestSequence) + 1
|
||||
}
|
||||
|
||||
private async createPayments(
|
||||
tx: Prisma.TransactionClient,
|
||||
invoiceId: string,
|
||||
payments: NormalizedPayment[],
|
||||
paidAt: Date,
|
||||
) {
|
||||
for (const payment of payments) {
|
||||
if (payment.amount <= 0) {
|
||||
continue
|
||||
}
|
||||
const createdPayment = await tx.salesInvoicePayment.create({
|
||||
data: {
|
||||
invoice_id: invoiceId,
|
||||
amount: payment.amount,
|
||||
payment_method: payment.method,
|
||||
paid_at: paidAt,
|
||||
},
|
||||
})
|
||||
|
||||
if (payment.method === PaymentMethodType.TERMINAL && payment.terminalInfo) {
|
||||
const {
|
||||
terminal_id,
|
||||
stan,
|
||||
rrn,
|
||||
transaction_date_time,
|
||||
customer_card_no,
|
||||
description,
|
||||
} = payment.terminalInfo
|
||||
await tx.salesInvoicePaymentTerminalInfo.create({
|
||||
data: {
|
||||
payment_id: createdPayment.id,
|
||||
terminal_id,
|
||||
stan: stan,
|
||||
rrn: rrn,
|
||||
transaction_date_time: transaction_date_time
|
||||
? new Date(transaction_date_time)
|
||||
: new Date(),
|
||||
customer_card_no: '1234567890123456',
|
||||
// customer_card_no: customer_card_no || null,
|
||||
description: description || null,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private generateInvoiceCode(
|
||||
businessId: string,
|
||||
complexId: string,
|
||||
posId: string,
|
||||
invoiceNumber: number,
|
||||
) {
|
||||
return `${businessId.substring(businessId.length - 2, businessId.length)}${complexId.substring(complexId.length - 2, complexId.length)}${posId.substring(posId.length - 2, posId.length)}${invoiceNumber.toString()}`
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
import { ApiPropertyOptional } from '@nestjs/swagger'
|
||||
import { Type } from 'class-transformer'
|
||||
import {
|
||||
IsDateString,
|
||||
IsEnum,
|
||||
IsNumber,
|
||||
IsOptional,
|
||||
IsString,
|
||||
Min,
|
||||
} from 'class-validator'
|
||||
import { TspProviderResponseStatus } from 'generated/prisma/enums'
|
||||
|
||||
export class SharedSaleInvoicesFilterDto {
|
||||
@ApiPropertyOptional({ default: 1 })
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
@IsNumber()
|
||||
@Min(1)
|
||||
page?: number
|
||||
|
||||
@ApiPropertyOptional({ default: 10 })
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
@IsNumber()
|
||||
@Min(1)
|
||||
perPage?: number
|
||||
|
||||
@ApiPropertyOptional()
|
||||
@IsOptional()
|
||||
@IsDateString()
|
||||
invoice_date_from?: string
|
||||
|
||||
@ApiPropertyOptional()
|
||||
@IsOptional()
|
||||
@IsDateString()
|
||||
invoice_date_to?: string
|
||||
|
||||
@ApiPropertyOptional()
|
||||
@IsOptional()
|
||||
@IsDateString()
|
||||
created_at_from?: string
|
||||
|
||||
@ApiPropertyOptional()
|
||||
@IsOptional()
|
||||
@IsDateString()
|
||||
created_at_to?: string
|
||||
|
||||
@ApiPropertyOptional()
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
customer_name?: string
|
||||
|
||||
@ApiPropertyOptional()
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
customer_mobile?: string
|
||||
|
||||
@ApiPropertyOptional()
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
customer_national_id?: string
|
||||
|
||||
@ApiPropertyOptional()
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
customer_economic_code?: string
|
||||
|
||||
@ApiPropertyOptional({ enum: TspProviderResponseStatus })
|
||||
@IsOptional()
|
||||
@IsEnum(TspProviderResponseStatus)
|
||||
status?: TspProviderResponseStatus
|
||||
|
||||
@ApiPropertyOptional()
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
@IsNumber()
|
||||
total_amount?: number
|
||||
|
||||
@ApiPropertyOptional()
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
@IsNumber()
|
||||
total_amount_from?: number
|
||||
|
||||
@ApiPropertyOptional()
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
@IsNumber()
|
||||
total_amount_to?: number
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
import { TspProviderResponseStatus } from '@/generated/prisma/enums'
|
||||
import { SalesInvoiceWhereInput } from '@/generated/prisma/models'
|
||||
import { Injectable } from '@nestjs/common'
|
||||
import { SharedSaleInvoicesFilterDto } from './sale-invoice-filter.dto'
|
||||
|
||||
@Injectable()
|
||||
export class SharedSaleInvoiceFilterService {
|
||||
buildWhere(filter: SharedSaleInvoicesFilterDto): SalesInvoiceWhereInput {
|
||||
const where: SalesInvoiceWhereInput = {}
|
||||
|
||||
if (filter.invoice_date_from || filter.invoice_date_to) {
|
||||
where.invoice_date = {
|
||||
...(filter.invoice_date_from ? { gte: new Date(filter.invoice_date_from) } : {}),
|
||||
...(filter.invoice_date_to ? { lte: new Date(filter.invoice_date_to) } : {}),
|
||||
}
|
||||
}
|
||||
|
||||
if (filter.created_at_from || filter.created_at_to) {
|
||||
where.created_at = {
|
||||
...(filter.created_at_from ? { gte: new Date(filter.created_at_from) } : {}),
|
||||
...(filter.created_at_to ? { lte: new Date(filter.created_at_to) } : {}),
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
filter.total_amount !== undefined ||
|
||||
filter.total_amount_from !== undefined ||
|
||||
filter.total_amount_to !== undefined
|
||||
) {
|
||||
where.total_amount = {
|
||||
...(filter.total_amount !== undefined ? { equals: filter.total_amount } : {}),
|
||||
...(filter.total_amount_from !== undefined
|
||||
? { gte: filter.total_amount_from }
|
||||
: {}),
|
||||
...(filter.total_amount_to !== undefined ? { lte: filter.total_amount_to } : {}),
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
filter.customer_name?.trim() ||
|
||||
filter.customer_mobile?.trim() ||
|
||||
filter.customer_national_id?.trim() ||
|
||||
filter.customer_economic_code?.trim()
|
||||
) {
|
||||
where.customer = {
|
||||
is: {
|
||||
OR: [
|
||||
...(filter.customer_name?.trim()
|
||||
? [
|
||||
{
|
||||
individual: {
|
||||
is: {
|
||||
OR: [
|
||||
{ first_name: { contains: filter.customer_name.trim() } },
|
||||
{ last_name: { contains: filter.customer_name.trim() } },
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
legal: {
|
||||
is: {
|
||||
name: {
|
||||
contains: filter.customer_name.trim(),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
: []),
|
||||
...(filter.customer_mobile?.trim()
|
||||
? [
|
||||
{
|
||||
individual: {
|
||||
is: {
|
||||
mobile_number: { contains: filter.customer_mobile.trim() },
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
: []),
|
||||
...(filter.customer_national_id?.trim()
|
||||
? [
|
||||
{
|
||||
individual: {
|
||||
is: {
|
||||
national_id: { contains: filter.customer_national_id.trim() },
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
: []),
|
||||
...(filter.customer_economic_code?.trim()
|
||||
? [
|
||||
{
|
||||
legal: {
|
||||
is: {
|
||||
OR: [
|
||||
{
|
||||
economic_code: {
|
||||
contains: filter.customer_economic_code.trim(),
|
||||
},
|
||||
},
|
||||
{
|
||||
registration_number: {
|
||||
contains: filter.customer_economic_code.trim(),
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
: []),
|
||||
],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if (filter.status) {
|
||||
if (filter.status === TspProviderResponseStatus.NOT_SEND) {
|
||||
where.OR = [
|
||||
{
|
||||
last_tsp_status: null,
|
||||
},
|
||||
{
|
||||
last_tsp_status: TspProviderResponseStatus.NOT_SEND,
|
||||
},
|
||||
]
|
||||
} else {
|
||||
where.last_tsp_status = filter.status
|
||||
}
|
||||
}
|
||||
|
||||
return where
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { Injectable } from '@nestjs/common'
|
||||
|
||||
@Injectable()
|
||||
export class SharedSaleInvoicePaginationService {
|
||||
normalize(
|
||||
page: number = 1,
|
||||
perPage: number = 10,
|
||||
defaultPerPage: number = 10,
|
||||
maxPerPage: number = 50,
|
||||
) {
|
||||
const normalizedPageValue = Number(page ?? 1)
|
||||
const normalizedPage = Number.isFinite(normalizedPageValue)
|
||||
? Math.max(1, Math.floor(normalizedPageValue))
|
||||
: 1
|
||||
|
||||
const requestedPerPageValue = Number(perPage ?? defaultPerPage)
|
||||
const requestedPerPage = Number.isFinite(requestedPerPageValue)
|
||||
? Math.max(1, Math.floor(requestedPerPageValue))
|
||||
: defaultPerPage
|
||||
const normalizedPerPage = Math.min(requestedPerPage, maxPerPage)
|
||||
|
||||
return {
|
||||
page: normalizedPage,
|
||||
perPage: normalizedPerPage,
|
||||
skip: (normalizedPage - 1) * normalizedPerPage,
|
||||
take: normalizedPerPage,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
import dayjs, { Dayjs } from 'dayjs'
|
||||
import 'dayjs/locale/fa'
|
||||
import relativeTime from 'dayjs/plugin/relativeTime'
|
||||
import jalaliPlugin from 'jalaliday/dayjs'
|
||||
|
||||
dayjs.extend(jalaliPlugin)
|
||||
dayjs.extend(relativeTime)
|
||||
|
||||
export function toJalali(date: string | number | Date | Dayjs): Date {
|
||||
return dayjs(date).calendar('jalali').toDate()
|
||||
}
|
||||
|
||||
export function toGregorian(date: string | number | Date | Dayjs): Date {
|
||||
return dayjs(date).calendar('gregory').toDate()
|
||||
}
|
||||
|
||||
export function getCurrentJalaliSeasonStart(
|
||||
baseDate: string | number | Date | Dayjs = dayjs(),
|
||||
): Date {
|
||||
const date = dayjs(baseDate).calendar('jalali')
|
||||
const month = date.month() + 1
|
||||
const seasonStartMonth = Math.floor((month - 1) / 3) * 3 + 1
|
||||
return date
|
||||
.month(seasonStartMonth - 1)
|
||||
.startOf('month')
|
||||
.startOf('day')
|
||||
.toDate()
|
||||
}
|
||||
|
||||
export function getCurrentJalaliSeasonEnd(
|
||||
baseDate: string | number | Date | Dayjs = dayjs(),
|
||||
): Date {
|
||||
return dayjs(getCurrentJalaliSeasonStart(baseDate))
|
||||
.add(3, 'month')
|
||||
.endOf('month')
|
||||
.endOf('day')
|
||||
.toDate()
|
||||
}
|
||||
|
||||
export function getCurrentGregorianSeasonStart(
|
||||
baseDate: string | number | Date | Dayjs = dayjs(),
|
||||
): Date {
|
||||
const date = dayjs(baseDate).calendar('gregory')
|
||||
const month = date.month() + 1
|
||||
const seasonStartMonth = Math.floor((month - 1) / 3) * 3 + 1
|
||||
return date
|
||||
.month(seasonStartMonth - 1)
|
||||
.startOf('month')
|
||||
.startOf('day')
|
||||
.toDate()
|
||||
}
|
||||
|
||||
export function getCurrentGregorianSeasonEnd(
|
||||
baseDate: string | number | Date | Dayjs = dayjs(),
|
||||
): Date {
|
||||
return dayjs(getCurrentGregorianSeasonStart(baseDate))
|
||||
.add(2, 'month')
|
||||
.endOf('month')
|
||||
.endOf('day')
|
||||
.toDate()
|
||||
}
|
||||
|
||||
export function getCurrentJalaliSeasonRange(
|
||||
baseDate: string | number | Date | Dayjs = dayjs(),
|
||||
): { start: Date; end: Date } {
|
||||
return {
|
||||
start: getCurrentJalaliSeasonStart(baseDate),
|
||||
end: getCurrentJalaliSeasonEnd(baseDate),
|
||||
}
|
||||
}
|
||||
|
||||
export function getCurrentGregorianSeasonRange(
|
||||
baseDate: string | number | Date | Dayjs = dayjs(),
|
||||
): { start: Date; end: Date } {
|
||||
return {
|
||||
start: getCurrentGregorianSeasonStart(baseDate),
|
||||
end: getCurrentGregorianSeasonEnd(baseDate),
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
toJalali,
|
||||
toGregorian,
|
||||
getCurrentJalaliSeasonStart,
|
||||
getCurrentJalaliSeasonEnd,
|
||||
getCurrentGregorianSeasonStart,
|
||||
getCurrentGregorianSeasonEnd,
|
||||
getCurrentJalaliSeasonRange,
|
||||
getCurrentGregorianSeasonRange,
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import translates from '@/common/constants/translates/translates'
|
||||
|
||||
type EnumTranslateMap = Record<string, string>
|
||||
type EnumsRegistry = Record<string, EnumTranslateMap>
|
||||
|
||||
export interface EnumTranslatedValue {
|
||||
value: string | null | undefined
|
||||
translate: string | null
|
||||
}
|
||||
|
||||
export function translateEnumValue(
|
||||
enumKey: keyof typeof translates.enums,
|
||||
value: string | null | undefined,
|
||||
): EnumTranslatedValue {
|
||||
const enumsRegistry = translates.enums as EnumsRegistry
|
||||
const enumMap = enumsRegistry[String(enumKey)]
|
||||
|
||||
if (!value) {
|
||||
return {
|
||||
value,
|
||||
translate: null,
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
value,
|
||||
translate: enumMap?.[value] ?? null,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { Matches, MinLength } from 'class-validator'
|
||||
|
||||
const MIN_LENGTH = 6
|
||||
const REGEX = /^[a-zA-Z0-9]*$/
|
||||
|
||||
export const FiscalIdFieldValidator = () =>
|
||||
function (target: object, propertyKey: string) {
|
||||
MinLength(MIN_LENGTH, {
|
||||
message: `شناسه یکتا باید حداقل ${MIN_LENGTH} کاراکتر باشد`,
|
||||
})(target, propertyKey)
|
||||
Matches(REGEX, {
|
||||
message: 'شناسه یکتا فقط میتواند شامل حروف و اعداد باشد',
|
||||
})(target, propertyKey)
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export { FiscalIdFieldValidator } from './fiscalId-validator'
|
||||
export { PasswordFieldValidator, PASSWORD_MIN_LENGTH } from './password'
|
||||
export { UsernameFieldValidator } from './username'
|
||||
@@ -0,0 +1,10 @@
|
||||
import { MinLength } from 'class-validator'
|
||||
|
||||
export const PASSWORD_MIN_LENGTH = 6
|
||||
|
||||
export const PasswordFieldValidator = () =>
|
||||
function (target: object, propertyKey: string) {
|
||||
MinLength(PASSWORD_MIN_LENGTH, {
|
||||
message: `رمز عبور باید حداقل ${PASSWORD_MIN_LENGTH} کاراکتر باشد`,
|
||||
})(target, propertyKey)
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { Matches, MinLength } from 'class-validator'
|
||||
|
||||
const USERNAME_REGEX = /^[a-zA-Z0-9_-]*$/
|
||||
const USERNAME_MIN_LENGTH = 6
|
||||
|
||||
export const UsernameFieldValidator = () =>
|
||||
function (target: object, propertyKey: string) {
|
||||
MinLength(USERNAME_MIN_LENGTH, {
|
||||
message: `نام کاربری باید حداقل ${USERNAME_MIN_LENGTH} کاراکتر باشد`,
|
||||
})(target, propertyKey)
|
||||
Matches(USERNAME_REGEX, {
|
||||
message: 'نام کاربری فقط میتواند شامل حروف، اعداد، زیرخط و خط تیره باشد',
|
||||
})(target, propertyKey)
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import {
|
||||
FetchRequestContext,
|
||||
FetchRequestInterceptor,
|
||||
} from '@/common/interceptors/fetch-request.interceptor'
|
||||
import { Injectable } from '@nestjs/common'
|
||||
|
||||
@Injectable()
|
||||
export class HttpClientUtil {
|
||||
async request(
|
||||
url: string,
|
||||
init: RequestInit = {},
|
||||
interceptors: FetchRequestInterceptor[] = [],
|
||||
): Promise<Response> {
|
||||
let context: FetchRequestContext = { url, init }
|
||||
|
||||
for (const interceptor of interceptors) {
|
||||
if (!interceptor.onRequest) {
|
||||
continue
|
||||
}
|
||||
|
||||
context = await interceptor.onRequest(context)
|
||||
}
|
||||
|
||||
try {
|
||||
let response = await fetch(context.url, context.init)
|
||||
|
||||
for (const interceptor of interceptors) {
|
||||
if (!interceptor.onResponse) {
|
||||
continue
|
||||
}
|
||||
response = await interceptor.onResponse(context, response)
|
||||
}
|
||||
|
||||
return response
|
||||
} catch (error: any) {
|
||||
for (const interceptor of interceptors) {
|
||||
if (!interceptor.onError) {
|
||||
continue
|
||||
}
|
||||
await interceptor.onError(context, error)
|
||||
}
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
export * from './date-formatter.utils'
|
||||
export * from './enum-translator.util'
|
||||
export * from './field-validator.util'
|
||||
export * from './http-client.util'
|
||||
export * from './jwt-user.util'
|
||||
export * from './mappers/consumer_mappers.util'
|
||||
export * from './password.util'
|
||||
export * from './redisKeyMaker'
|
||||
export * from './tracking-code-generator.util'
|
||||
@@ -18,13 +18,13 @@ export function checkAndDecodeJwtToken(
|
||||
token = authHeader.slice(7)
|
||||
}
|
||||
}
|
||||
if (!token) throw new UnauthorizedException('Missing accessToken cookie')
|
||||
if (!token) throw new UnauthorizedException('توکن احراز هویت ارسال نشده است')
|
||||
|
||||
try {
|
||||
const payload = jwtService.decode(token) as AccessTokenPayload
|
||||
|
||||
return payload as ITokenPayload
|
||||
} catch {
|
||||
return null
|
||||
throw new UnauthorizedException('توکن احراز هویت نامعتبر است')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
import { translateEnumValue } from '../enum-translator.util'
|
||||
|
||||
export default (consumer: any) => {
|
||||
const { legal, individual, activation, type, status, _count, ...rest } = consumer
|
||||
|
||||
const { business_activities: business_counts } = _count || { business_activities: 0 }
|
||||
const partner = legal?.partner || individual?.partner
|
||||
delete legal?.partner
|
||||
delete individual?.partner
|
||||
|
||||
const returnData = {
|
||||
...rest,
|
||||
partner,
|
||||
type: translateEnumValue('ConsumerType', type),
|
||||
status: translateEnumValue('ConsumerStatus', consumer.status),
|
||||
legal: legal ? { ...legal } : null,
|
||||
individual: individual
|
||||
? { ...individual, fullname: `${individual?.first_name} ${individual?.last_name}` }
|
||||
: null,
|
||||
name: legal ? legal.name : `${individual?.first_name} ${individual?.last_name}`,
|
||||
}
|
||||
|
||||
if (business_counts !== undefined) {
|
||||
returnData['business_counts'] = business_counts
|
||||
}
|
||||
|
||||
return returnData
|
||||
}
|
||||
|
||||
function prepareLicenseInfo(latestLicense: any) {
|
||||
if (!latestLicense) return null
|
||||
const { license, ...rest } = latestLicense
|
||||
|
||||
return {
|
||||
...rest,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
import { BadRequestException, ConflictException } from '@nestjs/common'
|
||||
import { Prisma } from 'generated/prisma/client'
|
||||
|
||||
type UniqueMessageMap = Record<string, string>
|
||||
|
||||
export class PrismaErrorUtil {
|
||||
static isKnownError(error: unknown): error is Prisma.PrismaClientKnownRequestError {
|
||||
return error instanceof Prisma.PrismaClientKnownRequestError
|
||||
}
|
||||
|
||||
static isCode(error: unknown, code: string): boolean {
|
||||
return this.isKnownError(error) && error.code === code
|
||||
}
|
||||
|
||||
static hasTarget(error: unknown, targetKey: string): boolean {
|
||||
if (!this.isKnownError(error)) {
|
||||
return false
|
||||
}
|
||||
const target = error.meta?.target as string[] | string | undefined
|
||||
if (Array.isArray(target)) {
|
||||
return target.includes(targetKey)
|
||||
}
|
||||
if (typeof target === 'string') {
|
||||
return target.includes(targetKey)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
static throwIfKnown(error: unknown, uniqueMap: UniqueMessageMap = {}) {
|
||||
if (!(error instanceof Prisma.PrismaClientKnownRequestError)) {
|
||||
throw error
|
||||
}
|
||||
|
||||
if (error.code === 'P2002') {
|
||||
const target = (error.meta?.target as string[]) || []
|
||||
for (const key of Object.keys(uniqueMap)) {
|
||||
if (target.includes(key)) {
|
||||
throw new BadRequestException(uniqueMap[key])
|
||||
}
|
||||
}
|
||||
throw new ConflictException('رکورد تکراری است.')
|
||||
}
|
||||
|
||||
if (error.code === 'P2003') {
|
||||
throw new BadRequestException('ارتباط دادهای نامعتبر است.')
|
||||
}
|
||||
|
||||
if (error.code === 'P2025') {
|
||||
throw new BadRequestException('رکورد مورد نظر یافت نشد.')
|
||||
}
|
||||
|
||||
throw error
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
export class ConsumerKeyMaker {
|
||||
static middleware(token: string): string {
|
||||
return `consumer:middleware:${token}`
|
||||
}
|
||||
|
||||
static consumerInfo(consumerId: string): string {
|
||||
return `consumers:${consumerId}:info`
|
||||
}
|
||||
|
||||
static consumerBusinessActivitiesList(consumerId: string): string {
|
||||
return `consumers:${consumerId}:business-activities:list`
|
||||
}
|
||||
|
||||
static consumerBusinessActivityInfo(
|
||||
consumerId: string,
|
||||
businessActivityId: string,
|
||||
): string {
|
||||
return `consumers:${consumerId}:business-activities:${businessActivityId}:info`
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
export class EnumKeyMaker {
|
||||
static enumsAll(buildVersion: string): string {
|
||||
return `enums:${buildVersion}:all`
|
||||
}
|
||||
|
||||
static enumsValues(buildVersion: string, enumName: string): string {
|
||||
return `enums:${buildVersion}:values:${enumName}`
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user