Compare commits

..

6 Commits

Author SHA1 Message Date
ahasani 2c97b7302d feat(statistics): implement statistics module with controller and service for POS invoices 2026-05-23 18:09:41 +03:30
ahasani 2dc9480170 feat(invoices): add public invoices module with controller and service
refactor: remove unused trigger logs module and related files
refactor: simplify good snapshot handling in sale invoice creation
2026-05-21 21:35:36 +03:30
ahasani 9aa12184a1 refactor: streamline Redis caching logic across services
- Implemented a unified `getAndSet` method in RedisService to handle caching for single, list, and paginated responses.
- Removed redundant cache checks and writes in various services, simplifying the code and improving readability.
- Updated GoodsService, StockKeepingUnitsService, PartnerActivatedLicensesService, and others to utilize the new caching mechanism.
- Adjusted Prisma connection limit for better resource management.
2026-05-21 17:27:37 +03:30
ahasani 1d47fb1a1d refactor(goods): streamline goods service and controller, remove favorites module
- Removed the PosGoodFavorite module, controller, and service to simplify the codebase.
- Updated goods service to handle cache invalidation directly.
- Refactored goods controller to remove commented-out code and improve clarity.
- Introduced OwnedGoods module for better organization of owned goods functionality.
- Updated DTOs to extend from existing structures for consistency.
- Enhanced cache invalidation logic in goods service and owned goods service.
2026-05-20 20:22:00 +03:30
ahasani fc27b9d616 feat(pos): add favorite functionality for goods
- Implemented PosGoodFavoriteController to handle attaching and detaching favorites for goods.
- Created PosGoodFavoriteService to manage the business logic for favorites, including database operations and cache invalidation.
- Added PosGoodFavoriteModule to encapsulate the controller and service.
2026-05-20 11:42:59 +03:30
ahasani 98099e97e7 feat: add field validators for username and password, and integrate them into DTOs 2026-05-19 20:34:05 +03:30
90 changed files with 4418 additions and 2363 deletions
+158 -1
View File
@@ -1,17 +1,162 @@
# AGENT.md
# GapCode Agent Instructions
# AGENTS.md
Operational guide for AI/coding agents working in `consumer_api`.
---
# ⚡ RTK LOW-TOKEN EXECUTION POLICY (MANDATORY)
This repository uses **RTK (Rust Token Killer)**.
All shell interactions MUST prefer RTK wrappers to reduce token usage.
If an RTK equivalent exists, **never use the raw command**.
This repository can be large; uncontrolled shell output will quickly exhaust model context.
---
# ✅ COMMAND REWRITE RULES (STRICT)
Always rewrite commands using RTK:
git status → rtk git status
git diff → rtk git diff
git log → rtk git log
ls → rtk ls
tree → rtk ls
cat <file> → rtk read <file>
grep <pattern> → rtk grep <pattern>
rg <pattern> → rtk grep <pattern>
find → rtk find
Never run:
- raw git commands for inspection
- raw cat
- raw grep
- raw ls
- raw tree
---
# 📂 CODE NAVIGATION WORKFLOW (MANDATORY)
When working in this repository follow this order:
1️⃣ Discover structure
rtk ls
2️⃣ Search before opening files
rtk grep <symbol | class | function | DTO | service>
3️⃣ Read only the necessary files
rtk read <file>
4️⃣ For large files (>300 lines)
rtk read <file> -l aggressive
5️⃣ For quick understanding
rtk smart <file>
Never open many files blindly.
Never read entire modules without searching first.
---
# 🧠 DIFF INSPECTION RULES
For reviewing repository changes:
Use:
rtk git diff
For large diffs:
rtk git diff -l aggressive
Never run raw `git diff`.
---
# 📁 FORBIDDEN PATHS
Never inspect or read these directories unless explicitly required:
node_modules/
dist/
build/
coverage/
.prisma/
prisma/migrations/
These folders produce extremely large outputs and waste tokens.
---
# 📄 FILE READING POLICY
Preferred:
rtk read file.ts
Large file:
rtk read file.ts -l aggressive
Quick overview:
rtk smart file.ts
Never use `cat` for source code inspection.
---
# 🔎 SEARCH POLICY
Always search before opening files.
Use:
rtk grep <pattern>
Avoid raw recursive searches.
---
# 🎯 TOKEN SAFETY RULES
- Never scan the entire repository.
- Never dump full logs.
- Never output entire large files.
- Prefer targeted inspection.
Token preservation is mandatory for this project.
---
## Scope
- Applies to the whole repository.
- Stack: NestJS + Prisma + TypeScript.
## Primary Goals
- Deliver minimal, safe, and focused changes.
- Preserve existing API behavior unless explicitly requested.
- Keep Prisma schema/data operations forward-safe.
## Project Conventions
- Keep module layering consistent: `controller -> service -> prisma/shared service`.
- Reuse shared services for cross-module business logic (for example, sales invoice create flow).
- Keep DTO validation at API boundaries; avoid unchecked `any` in new code.
@@ -19,6 +164,7 @@ Operational guide for AI/coding agents working in `consumer_api`.
- Prefer explicit Prisma `select`/`include` to control payload shape.
## Sales Invoice / TSP Rules
- `originalSend`, `correctionSend`, and `revoke` flows should be consistent and auditable.
- For correction/revoke creation, prepare data from the related invoice when required.
- Persist attempt records with clear status transitions (`QUEUED` -> final status).
@@ -26,6 +172,7 @@ Operational guide for AI/coding agents working in `consumer_api`.
- Avoid changing fiscal/tax status semantics without explicit approval.
## Prisma and Migration Safety
- Treat committed migrations as immutable history.
- Prefer forward migrations; avoid destructive resets unless explicitly requested.
- For data-affecting changes:
@@ -34,12 +181,14 @@ Operational guide for AI/coding agents working in `consumer_api`.
- keep logic idempotent where possible.
## Editing Principles
- Do not modify unrelated files.
- Do not revert user changes unless asked.
- Keep functions cohesive; extract shared logic when duplication appears.
- Remove debug leftovers (`console.log`, dead code) before finishing unless explicitly needed.
## Validation Checklist (before handoff)
1. Read target module/service/DTO end-to-end before edits.
2. Apply minimal patch with consistent naming.
3. Run typecheck: `pnpm -s tsc --noEmit`.
@@ -47,12 +196,14 @@ Operational guide for AI/coding agents working in `consumer_api`.
5. Summarize changed files and behavior impact clearly.
## Useful Commands
- Typecheck: `pnpm -s tsc --noEmit`
- Migration status: `pnpm prisma migrate status`
- Create migration: `pnpm prisma migrate dev --name <name>`
- Deploy migrations: `pnpm prisma migrate deploy`
## Communication Style
- Be concise and implementation-focused.
- Call out assumptions/risk before risky steps.
- Provide practical next actions after task completion.
@@ -60,6 +211,7 @@ Operational guide for AI/coding agents working in `consumer_api`.
## Do / Don't (Repo-Specific)
### Do
- Do derive correction/revoke invoice creation data from `relatedInvoice` when the flow requires historical consistency.
- Do keep TSP attempt lifecycle explicit (`QUEUED`, then update with provider result and timestamps).
- Do use shared invoice-creation service instead of duplicating create logic across modules.
@@ -67,6 +219,7 @@ Operational guide for AI/coding agents working in `consumer_api`.
- Do keep Prisma queries tight with `select`/`include` only for fields you actually use.
### Don't
- Don't pass undefined/out-of-scope variables in TSP flows (common regressions: `invoice_id`, `attemptId`, `pos_id` mismatches).
- Don't leave placeholder query blocks (for example empty `select: {}`) in production code.
- Don't mix method semantics (`send` vs `originalSend`) across services without verifying signatures.
@@ -74,12 +227,14 @@ Operational guide for AI/coding agents working in `consumer_api`.
- Don't change invoice type semantics (`ORIGINAL`, `CORRECTION`, `REVOKE`) implicitly.
### Common Pitfalls To Recheck
- Incorrect relation field names (`tax_id` on wrong model, missing relation selects).
- Building payloads from the wrong invoice (must match the expected new/ref invoice in each flow).
- Creating attempts without persisting request payload and final response payload.
- Mismatch between DTO shapes and shared service input contracts.
## Thread Notes (May 2026)
- Shared sale-invoice creation was introduced and must be injected/exported correctly in consuming modules (example failure: `UnknownDependenciesException` for `SharedSaleInvoiceCreateService`).
- In `SalesInvoiceTspService.revoke`, prepare all creation/update data from `relatedInvoice` (no external `dataToUpdate` argument expected).
- Prisma client is generated to `src/generated/prisma` via:
@@ -94,6 +249,7 @@ Operational guide for AI/coding agents working in `consumer_api`.
- For heavy license provisioning (100+), request path should not synchronously insert all licenses; queue/background + batching is required.
## Migration Drift Playbook (Prisma/MySQL)
- If Prisma reports `modified after applied`, never edit an already-applied migration in-place for shared environments; create a new forward migration instead.
- If migration history and DB drift mismatch:
1. Verify local migration folders are complete and ordered.
@@ -104,6 +260,7 @@ Operational guide for AI/coding agents working in `consumer_api`.
- `prisma migrate status` may show up-to-date while `migrate dev` still detects drift (shadow DB/application history issue); treat `migrate dev` output as source of truth for fixing local history.
## Redis Cache Conventions (May 2026)
- Use `RedisKeyMaker` in `src/common/utils/redis-key-maker.util.ts` for all cache keys and wildcard patterns; do not inline key strings in services.
- Keep invalidation domain-based (for example `src/modules/admin/guilds/cache/*`, `src/modules/admin/partners/cache/*`, `src/modules/pos/cache/*`) and avoid duplicating delete logic across modules.
- For list APIs that are expensive or frequently read, prefer read-through cache with TTL and invalidation on every related write path.
+5 -3
View File
@@ -8,8 +8,8 @@
"@nestjs/jwt": "^11.0.2",
"@nestjs/platform-express": "^11.1.19",
"@nestjs/swagger": "^11.3.2",
"@prisma/client": "^7.7.0",
"@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",
@@ -18,13 +18,13 @@
"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",
"mysql2": "^3.22.2",
"prisma": "^7.7.0",
"reflect-metadata": "^0.2.2",
"ioredis": "^5.8.2",
"rxjs": "^7.8.2",
"uuid": "^13.0.0"
},
@@ -45,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",
@@ -82,9 +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",
"seed:sku": "tsx scripts/seedStockKeepingUnits.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",
+46
View File
@@ -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);
}
}
+9
View File
@@ -0,0 +1,9 @@
import { IsString, IsNumber, IsBoolean, IsEmail } from 'class-validator';
export class Create{{pascalCase name}}Dto {
{{#each parsedFields}}
@{{validator}}()
{{name}}: {{type}};
{{/each}}
}
+10
View File
@@ -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 {}
+63
View File
@@ -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 },
});
}
}
+4
View File
@@ -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
View File
@@ -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',
},
]
},
})
}
+429 -1
View File
@@ -132,6 +132,9 @@ importers:
jest:
specifier: ^30.3.0
version: 30.3.0(@types/node@22.19.17)(ts-node@10.9.2(@types/node@22.19.17)(typescript@5.9.3))
plop:
specifier: ^4.0.5
version: 4.0.5(@types/node@22.19.17)
prettier:
specifier: ^3.8.3
version: 3.8.3
@@ -1605,12 +1608,18 @@ packages:
'@types/express@5.0.6':
resolution: {integrity: sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==}
'@types/fined@1.1.5':
resolution: {integrity: sha512-2N93vadEGDFhASTIRbizbl4bNqpMOId5zZfj6hHqYZfEzEfO9onnU4Im8xvzo8uudySDveDHBOOSlTWf38ErfQ==, tarball: https://hub.megan.ir/repository/npm/@types/fined/-/fined-1.1.5.tgz}
'@types/geojson@7946.0.16':
resolution: {integrity: sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==}
'@types/http-errors@2.0.5':
resolution: {integrity: sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==}
'@types/inquirer@9.0.9':
resolution: {integrity: sha512-/mWx5136gts2Z2e5izdoRCo46lPp5TMs9R15GTSsgg/XnZyxDWVqoVU3R9lWnccKpqwsJLvRoxbCjoJtZB7DSw==, tarball: https://hub.megan.ir/repository/npm/@types/inquirer/-/inquirer-9.0.9.tgz}
'@types/istanbul-lib-coverage@2.0.6':
resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==}
@@ -1629,6 +1638,9 @@ packages:
'@types/jsonwebtoken@9.0.10':
resolution: {integrity: sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==}
'@types/liftoff@4.0.3':
resolution: {integrity: sha512-UgbL2kR5pLrWICvr8+fuSg0u43LY250q7ZMkC+XKC3E+rs/YBDEnQIzsnhU5dYsLlwMi3R75UvCL87pObP1sxw==, tarball: https://hub.megan.ir/repository/npm/@types/liftoff/-/liftoff-4.0.3.tgz}
'@types/methods@1.1.4':
resolution: {integrity: sha512-ymXWVrDiCxTBE3+RIrrP533E70eA+9qu7zdWoHuOmGujkYtzf4HQF96b8nwHLqhuf4ykX61IGRIB38CC6/sImQ==}
@@ -1644,6 +1656,9 @@ packages:
'@types/node@24.12.2':
resolution: {integrity: sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g==}
'@types/picomatch@4.0.3':
resolution: {integrity: sha512-iG0T6+nYJ9FAPmx9SsUlnwcq1ZVRuCXcVEvWnntoPlrOpwtSTKNDC9uVAxTsC3PUvJ+99n4RpAcNgBbHX3JSnQ==, tarball: https://hub.megan.ir/repository/npm/@types/picomatch/-/picomatch-4.0.3.tgz}
'@types/qs@6.15.0':
resolution: {integrity: sha512-JawvT8iBVWpzTrz3EGw9BTQFg3BQNmwERdKE22vlTxawwtbyUSlMppvZYKLZzB5zgACXdXxbD3m1bXaMqP/9ow==}
@@ -1668,6 +1683,9 @@ packages:
'@types/supertest@6.0.3':
resolution: {integrity: sha512-8WzXq62EXFhJ7QsH3Ocb/iKQ/Ty9ZVWnVzoTKc9tyyFRRF3a74Tk2+TLFgaFFw364Ere+npzHKEJ6ga2LzIL7w==}
'@types/through@0.0.33':
resolution: {integrity: sha512-HsJ+z3QuETzP3cswwtzt2vEIiHBk/dCcHGhbmG5X3ecnwFD/lPrMpliGXxSCg03L9AhrdwA4Oz/qfspkDW+xGQ==, tarball: https://hub.megan.ir/repository/npm/@types/through/-/through-0.0.33.tgz}
'@types/validator@13.15.10':
resolution: {integrity: sha512-T8L6i7wCuyoK8A/ZeLYt1+q0ty3Zb9+qbSSvrIVitzT3YjZqkTZ40IbRsPanlB4h1QB3JVL1SYCdR6ngtFYcuA==}
@@ -1997,6 +2015,14 @@ packages:
argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
array-each@1.0.1:
resolution: {integrity: sha512-zHjL5SZa68hkKHBFBK6DJCTtr9sfTCPCaph/L7tMSLcTFgy+zX7E+6q5UArbtOtMBCtxdICpfTCspRse+ywyXA==, tarball: https://hub.megan.ir/repository/npm/array-each/-/array-each-1.0.1.tgz}
engines: {node: '>=0.10.0'}
array-slice@1.1.0:
resolution: {integrity: sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==, tarball: https://hub.megan.ir/repository/npm/array-slice/-/array-slice-1.1.0.tgz}
engines: {node: '>=0.10.0'}
array-timsort@1.0.3:
resolution: {integrity: sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==}
@@ -2145,6 +2171,9 @@ packages:
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
engines: {node: '>=10'}
change-case@5.4.4:
resolution: {integrity: sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==, tarball: https://hub.megan.ir/repository/npm/change-case/-/change-case-5.4.4.tgz}
char-regex@1.0.2:
resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==}
engines: {node: '>=10'}
@@ -2361,6 +2390,10 @@ packages:
destr@2.0.5:
resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==}
detect-file@1.0.0:
resolution: {integrity: sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==, tarball: https://hub.megan.ir/repository/npm/detect-file/-/detect-file-1.0.0.tgz}
engines: {node: '>=0.10.0'}
detect-newline@3.1.0:
resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==}
engines: {node: '>=8'}
@@ -2372,6 +2405,9 @@ packages:
resolution: {integrity: sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==}
engines: {node: '>=0.3.1'}
dlv@1.1.3:
resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==, tarball: https://hub.megan.ir/repository/npm/dlv/-/dlv-1.1.3.tgz}
dotenv-expand@12.0.3:
resolution: {integrity: sha512-uc47g4b+4k/M/SeaW1y4OApx+mtLWl92l5LMPP0GNXctZqELk+YGgOPIIC5elYmUH4OuoK3JLhuRUYegeySiFA==}
engines: {node: '>=12'}
@@ -2570,6 +2606,10 @@ packages:
resolution: {integrity: sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==}
engines: {node: '>= 0.8.0'}
expand-tilde@2.0.2:
resolution: {integrity: sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==, tarball: https://hub.megan.ir/repository/npm/expand-tilde/-/expand-tilde-2.0.2.tgz}
engines: {node: '>=0.10.0'}
expect@30.3.0:
resolution: {integrity: sha512-1zQrciTiQfRdo7qJM1uG4navm8DayFa2TgCSRlzUyNkhcJ6XUZF3hjnpkyr3VhAqPH7i/9GkG7Tv5abz6fqz0Q==}
engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0}
@@ -2581,6 +2621,9 @@ packages:
exsolve@1.0.8:
resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==}
extend@3.0.2:
resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==, tarball: https://hub.megan.ir/repository/npm/extend/-/extend-3.0.2.tgz}
fast-check@3.23.2:
resolution: {integrity: sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==}
engines: {node: '>=8.0.0'}
@@ -2646,6 +2689,18 @@ packages:
resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
engines: {node: '>=10'}
findup-sync@5.0.0:
resolution: {integrity: sha512-MzwXju70AuyflbgeOhzvQWAvvQdo1XL0A9bVvlXsYcFEBM87WR4OakL4OfZq+QRmr+duJubio+UtNQCPsVESzQ==, tarball: https://hub.megan.ir/repository/npm/findup-sync/-/findup-sync-5.0.0.tgz}
engines: {node: '>= 10.13.0'}
fined@2.0.0:
resolution: {integrity: sha512-OFRzsL6ZMHz5s0JrsEr+TpdGNCtrVtnuG3x1yzGNiQHT0yaDnXAj8V/lWcpJVrnoDpcwXcASxAZYbuXda2Y82A==, tarball: https://hub.megan.ir/repository/npm/fined/-/fined-2.0.0.tgz}
engines: {node: '>= 10.13.0'}
flagged-respawn@2.0.0:
resolution: {integrity: sha512-Gq/a6YCi8zexmGHMuJwahTGzXlAZAOsbCVKduWXC6TlLCjjFRlExMJc4GC2NYPYZ0r/brw9P7CpRgQmlPVeOoA==, tarball: https://hub.megan.ir/repository/npm/flagged-respawn/-/flagged-respawn-2.0.0.tgz}
engines: {node: '>= 10.13.0'}
flat-cache@4.0.1:
resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==}
engines: {node: '>=16'}
@@ -2653,6 +2708,14 @@ packages:
flatted@3.4.2:
resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==}
for-in@1.0.2:
resolution: {integrity: sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==, tarball: https://hub.megan.ir/repository/npm/for-in/-/for-in-1.0.2.tgz}
engines: {node: '>=0.10.0'}
for-own@1.0.0:
resolution: {integrity: sha512-0OABksIGrxKK8K4kynWkQ7y1zounQxP+CWnyclVwj81KW3vlLlGUx57DKGcP/LH216GzqnstnPocF16Nxs0Ycg==, tarball: https://hub.megan.ir/repository/npm/for-own/-/for-own-1.0.0.tgz}
engines: {node: '>=0.10.0'}
foreground-child@3.3.1:
resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==}
engines: {node: '>=14'}
@@ -2755,6 +2818,14 @@ packages:
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
global-modules@1.0.0:
resolution: {integrity: sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==, tarball: https://hub.megan.ir/repository/npm/global-modules/-/global-modules-1.0.0.tgz}
engines: {node: '>=0.10.0'}
global-prefix@1.0.2:
resolution: {integrity: sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==, tarball: https://hub.megan.ir/repository/npm/global-prefix/-/global-prefix-1.0.2.tgz}
engines: {node: '>=0.10.0'}
globals@14.0.0:
resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==}
engines: {node: '>=18'}
@@ -2797,6 +2868,10 @@ packages:
resolution: {integrity: sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==}
engines: {node: '>= 0.4'}
homedir-polyfill@1.0.3:
resolution: {integrity: sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==, tarball: https://hub.megan.ir/repository/npm/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz}
engines: {node: '>=0.10.0'}
hono@4.12.14:
resolution: {integrity: sha512-am5zfg3yu6sqn5yjKBNqhnTX7Cv+m00ox+7jbaKkrLMRJ4rAdldd1xPd/JzbBWspqaQv6RSTrgFN95EsfhC+7w==}
engines: {node: '>=16.9.0'}
@@ -2854,6 +2929,17 @@ packages:
inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
ini@1.3.8:
resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==, tarball: https://hub.megan.ir/repository/npm/ini/-/ini-1.3.8.tgz}
inquirer@9.3.8:
resolution: {integrity: sha512-pFGGdaHrmRKMh4WoDDSowddgjT1Vkl90atobmTeSmcPGdYiwikch/m/Ef5wRaiamHejtw0cUUMMerzDUXCci2w==, tarball: https://hub.megan.ir/repository/npm/inquirer/-/inquirer-9.3.8.tgz}
engines: {node: '>=18'}
interpret@3.1.1:
resolution: {integrity: sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==, tarball: https://hub.megan.ir/repository/npm/interpret/-/interpret-3.1.1.tgz}
engines: {node: '>=10.13.0'}
ioredis@5.10.1:
resolution: {integrity: sha512-HuEDBTI70aYdx1v6U97SbNx9F1+svQKBDo30o0b9fw055LMepzpOOd0Ccg9Q6tbqmBSJaMuY0fB7yw9/vjBYCA==, tarball: https://hub.megan.ir/repository/npm/ioredis/-/ioredis-5.10.1.tgz}
engines: {node: '>=12.22.0'}
@@ -2862,9 +2948,17 @@ packages:
resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
engines: {node: '>= 0.10'}
is-absolute@1.0.0:
resolution: {integrity: sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==, tarball: https://hub.megan.ir/repository/npm/is-absolute/-/is-absolute-1.0.0.tgz}
engines: {node: '>=0.10.0'}
is-arrayish@0.2.1:
resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
is-core-module@2.16.2:
resolution: {integrity: sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==, tarball: https://hub.megan.ir/repository/npm/is-core-module/-/is-core-module-2.16.2.tgz}
engines: {node: '>= 0.4'}
is-extglob@2.1.1:
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
engines: {node: '>=0.10.0'}
@@ -2889,23 +2983,47 @@ packages:
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
engines: {node: '>=0.12.0'}
is-plain-object@5.0.0:
resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==, tarball: https://hub.megan.ir/repository/npm/is-plain-object/-/is-plain-object-5.0.0.tgz}
engines: {node: '>=0.10.0'}
is-promise@4.0.0:
resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==}
is-property@1.0.2:
resolution: {integrity: sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==}
is-relative@1.0.0:
resolution: {integrity: sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==, tarball: https://hub.megan.ir/repository/npm/is-relative/-/is-relative-1.0.0.tgz}
engines: {node: '>=0.10.0'}
is-stream@2.0.1:
resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
engines: {node: '>=8'}
is-unc-path@1.0.0:
resolution: {integrity: sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==, tarball: https://hub.megan.ir/repository/npm/is-unc-path/-/is-unc-path-1.0.0.tgz}
engines: {node: '>=0.10.0'}
is-unicode-supported@0.1.0:
resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==}
engines: {node: '>=10'}
is-windows@1.0.2:
resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==, tarball: https://hub.megan.ir/repository/npm/is-windows/-/is-windows-1.0.2.tgz}
engines: {node: '>=0.10.0'}
isbinaryfile@5.0.7:
resolution: {integrity: sha512-gnWD14Jh3FzS3CPhF0AxNOJ8CxqeblPTADzI38r0wt8ZyQl5edpy75myt08EG2oKvpyiqSqsx+Wkz9vtkbTqYQ==, tarball: https://hub.megan.ir/repository/npm/isbinaryfile/-/isbinaryfile-5.0.7.tgz}
engines: {node: '>= 18.0.0'}
isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
isobject@3.0.1:
resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==, tarball: https://hub.megan.ir/repository/npm/isobject/-/isobject-3.0.1.tgz}
engines: {node: '>=0.10.0'}
istanbul-lib-coverage@3.2.2:
resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==}
engines: {node: '>=8'}
@@ -3140,6 +3258,10 @@ packages:
libphonenumber-js@1.12.41:
resolution: {integrity: sha512-lsmMmGXBxXIK/VMLEj0kL6MtUs1kBGj1nTCzi6zgQoG1DEwqwt2DQyHxcLykceIxAnfE3hya7NuIh6PpC6S3fA==}
liftoff@5.0.1:
resolution: {integrity: sha512-wwLXMbuxSF8gMvubFcFRp56lkFV69twvbU5vDPbaw+Q+/rF8j0HKjGbIdlSi+LuJm9jf7k9PB+nTxnsLMPcv2Q==, tarball: https://hub.megan.ir/repository/npm/liftoff/-/liftoff-5.0.1.tgz}
engines: {node: '>=10.13.0'}
lines-and-columns@1.2.4:
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
@@ -3229,6 +3351,10 @@ packages:
makeerror@1.0.12:
resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==}
map-cache@0.2.2:
resolution: {integrity: sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==, tarball: https://hub.megan.ir/repository/npm/map-cache/-/map-cache-0.2.2.tgz}
engines: {node: '>=0.10.0'}
mariadb@3.4.5:
resolution: {integrity: sha512-gThTYkhIS5rRqkVr+Y0cIdzr+GRqJ9sA2Q34e0yzmyhMCwyApf3OKAC1jnF23aSlIOqJuyaUFUcj7O1qZslmmQ==}
engines: {node: '>= 14'}
@@ -3314,6 +3440,10 @@ packages:
resolution: {integrity: sha512-mo+QTzKlx8R7E5ylSXxWzGoXoZbOsRMpyitcht8By2KHvMbf3tjwosZ/Mu/XYU6UuJ3VZnODIrak5ZrPiPyB6A==}
engines: {node: '>= 10.16.0'}
mute-stream@1.0.0:
resolution: {integrity: sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==, tarball: https://hub.megan.ir/repository/npm/mute-stream/-/mute-stream-1.0.0.tgz}
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
mute-stream@2.0.0:
resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==}
engines: {node: ^18.17.0 || >=20.5.0}
@@ -3332,6 +3462,9 @@ packages:
resolution: {integrity: sha512-Tz09sEL2EEuv5fFowm419c1+a/jSMiBjI9gHxVLrVdbUkkNUUfjsVYs9pVZu5oCon/kmRh9TfLEObFtkVxmY0w==}
engines: {node: '>=8.0.0'}
nanospinner@1.2.2:
resolution: {integrity: sha512-Zt/AmG6qRU3e+WnzGGLuMCEAO/dAu45stNbHY223tUxldaDAeE+FxSPsd9Q+j+paejmm0ZbrNVs5Sraqy3dRxA==, tarball: https://hub.megan.ir/repository/npm/nanospinner/-/nanospinner-1.2.2.tgz}
napi-postinstall@0.3.4:
resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==}
engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
@@ -3367,6 +3500,10 @@ packages:
node-int64@0.4.0:
resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==}
node-plop@0.32.3:
resolution: {integrity: sha512-tn+OxutdqhvoByKJ7p84FZBSUDfUB76bcvj0ugLBvgE9V52LFcnz8cauCDKi6otnctvFCqa9XkrU35pBY5Baig==, tarball: https://hub.megan.ir/repository/npm/node-plop/-/node-plop-0.32.3.tgz}
engines: {node: '>=18'}
node-releases@2.0.37:
resolution: {integrity: sha512-1h5gKZCF+pO/o3Iqt5Jp7wc9rH3eJJ0+nh/CIoiRwjRxde/hAHyLPXYN4V3CqKAbiZPSeJFSWHmJsbkicta0Eg==}
@@ -3391,6 +3528,14 @@ packages:
resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==}
engines: {node: '>= 0.4'}
object.defaults@1.1.0:
resolution: {integrity: sha512-c/K0mw/F11k4dEUBMW8naXUuBuhxRCfG7W+yFy8EcijU/rSmazOUd1XAEEe6bC0OuXY4HUKjTJv7xbxIMqdxrA==, tarball: https://hub.megan.ir/repository/npm/object.defaults/-/object.defaults-1.1.0.tgz}
engines: {node: '>=0.10.0'}
object.pick@1.3.0:
resolution: {integrity: sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==, tarball: https://hub.megan.ir/repository/npm/object.pick/-/object.pick-1.3.0.tgz}
engines: {node: '>=0.10.0'}
ohash@2.0.11:
resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==}
@@ -3440,10 +3585,18 @@ packages:
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
engines: {node: '>=6'}
parse-filepath@1.0.2:
resolution: {integrity: sha512-FwdRXKCohSVeXqwtYonZTXtbGJKrn+HNyWDYVcp5yuJlesTwNH4rsmRZ+GrKAPJ5bLpRxESMeS+Rl0VCHRvB2Q==, tarball: https://hub.megan.ir/repository/npm/parse-filepath/-/parse-filepath-1.0.2.tgz}
engines: {node: '>=0.8'}
parse-json@5.2.0:
resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
engines: {node: '>=8'}
parse-passwd@1.0.0:
resolution: {integrity: sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==, tarball: https://hub.megan.ir/repository/npm/parse-passwd/-/parse-passwd-1.0.0.tgz}
engines: {node: '>=0.10.0'}
parseurl@1.3.3:
resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
engines: {node: '>= 0.8'}
@@ -3464,6 +3617,17 @@ packages:
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
engines: {node: '>=8'}
path-parse@1.0.7:
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==, tarball: https://hub.megan.ir/repository/npm/path-parse/-/path-parse-1.0.7.tgz}
path-root-regex@0.1.2:
resolution: {integrity: sha512-4GlJ6rZDhQZFE0DPVKh0e9jmZ5egZfxTkp7bcRDuPlJXbAwhxcl2dINPUAsjLdejqaLsCeg8axcLjIbvBjN4pQ==, tarball: https://hub.megan.ir/repository/npm/path-root-regex/-/path-root-regex-0.1.2.tgz}
engines: {node: '>=0.10.0'}
path-root@0.1.1:
resolution: {integrity: sha512-QLcPegTHF11axjfojBIoDygmS2E3Lf+8+jI6wOVmNVenrKSo3mFdSGiIgdSHenczw3wPtlVMQaFVwGmM7BJdtg==, tarball: https://hub.megan.ir/repository/npm/path-root/-/path-root-0.1.1.tgz}
engines: {node: '>=0.10.0'}
path-scurry@1.11.1:
resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==}
engines: {node: '>=16 || 14 >=14.18'}
@@ -3486,7 +3650,7 @@ packages:
resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==}
picocolors@1.1.1:
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==, tarball: https://hub.megan.ir/repository/npm/picocolors/-/picocolors-1.1.1.tgz}
picomatch@2.3.2:
resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==}
@@ -3507,6 +3671,11 @@ packages:
pkg-types@2.3.0:
resolution: {integrity: sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==}
plop@4.0.5:
resolution: {integrity: sha512-pJz6oWC9LyBp5mBrRp8AUV2RNiuGW+t/HOs4zwN+b/3YxoObZOOFvjn1mJMpAeKi2pbXADMFOOVQVTVXEdDHDw==, tarball: https://hub.megan.ir/repository/npm/plop/-/plop-4.0.5.tgz}
engines: {node: '>=18'}
hasBin: true
pluralize@8.0.0:
resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==}
engines: {node: '>=4'}
@@ -3603,6 +3772,10 @@ packages:
resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==}
engines: {node: '>= 14.18.0'}
rechoir@0.8.0:
resolution: {integrity: sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==, tarball: https://hub.megan.ir/repository/npm/rechoir/-/rechoir-0.8.0.tgz}
engines: {node: '>= 10.13.0'}
redis-errors@1.2.0:
resolution: {integrity: sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==, tarball: https://hub.megan.ir/repository/npm/redis-errors/-/redis-errors-1.2.0.tgz}
engines: {node: '>=4'}
@@ -3629,6 +3802,10 @@ packages:
resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==}
engines: {node: '>=8'}
resolve-dir@1.0.1:
resolution: {integrity: sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==, tarball: https://hub.megan.ir/repository/npm/resolve-dir/-/resolve-dir-1.0.1.tgz}
engines: {node: '>=0.10.0'}
resolve-from@4.0.0:
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
engines: {node: '>=4'}
@@ -3640,6 +3817,11 @@ packages:
resolve-pkg-maps@1.0.0:
resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
resolve@1.22.12:
resolution: {integrity: sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==, tarball: https://hub.megan.ir/repository/npm/resolve/-/resolve-1.22.12.tgz}
engines: {node: '>= 0.4'}
hasBin: true
restore-cursor@3.1.0:
resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==}
engines: {node: '>=8'}
@@ -3652,6 +3834,10 @@ packages:
resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==}
engines: {node: '>= 18'}
run-async@3.0.0:
resolution: {integrity: sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==, tarball: https://hub.megan.ir/repository/npm/run-async/-/run-async-3.0.0.tgz}
engines: {node: '>=0.12.0'}
rxjs@7.8.1:
resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==}
@@ -3842,6 +4028,10 @@ packages:
resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==}
engines: {node: '>=10'}
supports-preserve-symlinks-flag@1.0.0:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==, tarball: https://hub.megan.ir/repository/npm/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz}
engines: {node: '>= 0.4'}
swagger-ui-dist@5.32.4:
resolution: {integrity: sha512-0AADFFQNJzExEN49SrD/34Nn9cxNxVLiydYl2MBwSZFPVXNkVwC/EFAjoezGGqE8oDegiDC+p47t8lKObCinMQ==}
@@ -3890,6 +4080,9 @@ packages:
resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==}
engines: {node: '>=12.0.0'}
title-case@4.3.2:
resolution: {integrity: sha512-I/nkcBo73mO42Idfv08jhInV61IMb61OdIFxk+B4Gu1oBjWBPOLmhZdsli+oJCVaD+86pYQA93cJfFt224ZFAA==, tarball: https://hub.megan.ir/repository/npm/title-case/-/title-case-4.3.2.tgz}
tmpl@1.0.5:
resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==}
@@ -4027,6 +4220,10 @@ packages:
resolution: {integrity: sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==}
engines: {node: '>=18'}
unc-path-regex@0.1.2:
resolution: {integrity: sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==, tarball: https://hub.megan.ir/repository/npm/unc-path-regex/-/unc-path-regex-0.1.2.tgz}
engines: {node: '>=0.10.0'}
undici-types@6.21.0:
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
@@ -4067,6 +4264,10 @@ packages:
resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==}
engines: {node: '>=10.12.0'}
v8flags@4.0.1:
resolution: {integrity: sha512-fcRLaS4H/hrZk9hYwbdRM35D0U8IYMfEClhXxCivOojl+yTRAZH3Zy2sSy6qVCiGbV9YAtPssP6jaChqC9vPCg==, tarball: https://hub.megan.ir/repository/npm/v8flags/-/v8flags-4.0.1.tgz}
engines: {node: '>= 10.13.0'}
valibot@1.2.0:
resolution: {integrity: sha512-mm1rxUsmOxzrwnX5arGS+U4T25RdvpPjPN4yR0u9pUBov9+zGVtO84tif1eY4r6zWxVxu3KzIyknJy3rxfRZZg==}
peerDependencies:
@@ -4111,6 +4312,10 @@ packages:
webpack-cli:
optional: true
which@1.3.1:
resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==, tarball: https://hub.megan.ir/repository/npm/which/-/which-1.3.1.tgz}
hasBin: true
which@2.0.2:
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
engines: {node: '>= 8'}
@@ -6126,10 +6331,17 @@ snapshots:
'@types/express-serve-static-core': 5.1.1
'@types/serve-static': 2.2.0
'@types/fined@1.1.5': {}
'@types/geojson@7946.0.16': {}
'@types/http-errors@2.0.5': {}
'@types/inquirer@9.0.9':
dependencies:
'@types/through': 0.0.33
rxjs: 7.8.2
'@types/istanbul-lib-coverage@2.0.6': {}
'@types/istanbul-lib-report@3.0.3':
@@ -6152,6 +6364,11 @@ snapshots:
'@types/ms': 2.1.0
'@types/node': 22.19.17
'@types/liftoff@4.0.3':
dependencies:
'@types/fined': 1.1.5
'@types/node': 22.19.17
'@types/methods@1.1.4': {}
'@types/ms@2.1.0': {}
@@ -6168,6 +6385,8 @@ snapshots:
dependencies:
undici-types: 7.16.0
'@types/picomatch@4.0.3': {}
'@types/qs@6.15.0': {}
'@types/range-parser@1.2.7': {}
@@ -6199,6 +6418,10 @@ snapshots:
'@types/methods': 1.1.4
'@types/superagent': 8.1.9
'@types/through@0.0.33':
dependencies:
'@types/node': 22.19.17
'@types/validator@13.15.10': {}
'@types/yargs-parser@21.0.3': {}
@@ -6524,6 +6747,10 @@ snapshots:
argparse@2.0.1: {}
array-each@1.0.1: {}
array-slice@1.1.0: {}
array-timsort@1.0.3: {}
asap@2.0.6: {}
@@ -6707,6 +6934,8 @@ snapshots:
ansi-styles: 4.3.0
supports-color: 7.2.0
change-case@5.4.4: {}
char-regex@1.0.2: {}
chardet@2.1.1: {}
@@ -6872,6 +7101,8 @@ snapshots:
destr@2.0.5: {}
detect-file@1.0.0: {}
detect-newline@3.1.0: {}
dezalgo@1.0.4:
@@ -6881,6 +7112,8 @@ snapshots:
diff@4.0.4: {}
dlv@1.1.3: {}
dotenv-expand@12.0.3:
dependencies:
dotenv: 16.6.1
@@ -7098,6 +7331,10 @@ snapshots:
exit-x@0.2.2: {}
expand-tilde@2.0.2:
dependencies:
homedir-polyfill: 1.0.3
expect@30.3.0:
dependencies:
'@jest/expect-utils': 30.3.0
@@ -7142,6 +7379,8 @@ snapshots:
exsolve@1.0.8: {}
extend@3.0.2: {}
fast-check@3.23.2:
dependencies:
pure-rand: 6.1.0
@@ -7214,6 +7453,23 @@ snapshots:
locate-path: 6.0.0
path-exists: 4.0.0
findup-sync@5.0.0:
dependencies:
detect-file: 1.0.0
is-glob: 4.0.3
micromatch: 4.0.8
resolve-dir: 1.0.1
fined@2.0.0:
dependencies:
expand-tilde: 2.0.2
is-plain-object: 5.0.0
object.defaults: 1.1.0
object.pick: 1.3.0
parse-filepath: 1.0.2
flagged-respawn@2.0.0: {}
flat-cache@4.0.1:
dependencies:
flatted: 3.4.2
@@ -7221,6 +7477,12 @@ snapshots:
flatted@3.4.2: {}
for-in@1.0.2: {}
for-own@1.0.0:
dependencies:
for-in: 1.0.2
foreground-child@3.3.1:
dependencies:
cross-spawn: 7.0.6
@@ -7351,6 +7613,20 @@ snapshots:
once: 1.4.0
path-is-absolute: 1.0.1
global-modules@1.0.0:
dependencies:
global-prefix: 1.0.2
is-windows: 1.0.2
resolve-dir: 1.0.1
global-prefix@1.0.2:
dependencies:
expand-tilde: 2.0.2
homedir-polyfill: 1.0.3
ini: 1.3.8
is-windows: 1.0.2
which: 1.3.1
globals@14.0.0: {}
globals@16.5.0: {}
@@ -7384,6 +7660,10 @@ snapshots:
dependencies:
function-bind: 1.1.2
homedir-polyfill@1.0.3:
dependencies:
parse-passwd: 1.0.0
hono@4.12.14: {}
html-escaper@2.0.2: {}
@@ -7433,6 +7713,27 @@ snapshots:
inherits@2.0.4: {}
ini@1.3.8: {}
inquirer@9.3.8(@types/node@22.19.17):
dependencies:
'@inquirer/external-editor': 1.0.3(@types/node@22.19.17)
'@inquirer/figures': 1.0.15
ansi-escapes: 4.3.2
cli-width: 4.1.0
mute-stream: 1.0.0
ora: 5.4.1
run-async: 3.0.0
rxjs: 7.8.2
string-width: 4.2.3
strip-ansi: 6.0.1
wrap-ansi: 6.2.0
yoctocolors-cjs: 2.1.3
transitivePeerDependencies:
- '@types/node'
interpret@3.1.1: {}
ioredis@5.10.1:
dependencies:
'@ioredis/commands': 1.5.1
@@ -7449,8 +7750,17 @@ snapshots:
ipaddr.js@1.9.1: {}
is-absolute@1.0.0:
dependencies:
is-relative: 1.0.0
is-windows: 1.0.2
is-arrayish@0.2.1: {}
is-core-module@2.16.2:
dependencies:
hasown: 2.0.3
is-extglob@2.1.1: {}
is-fullwidth-code-point@3.0.0: {}
@@ -7465,16 +7775,32 @@ snapshots:
is-number@7.0.0: {}
is-plain-object@5.0.0: {}
is-promise@4.0.0: {}
is-property@1.0.2: {}
is-relative@1.0.0:
dependencies:
is-unc-path: 1.0.0
is-stream@2.0.1: {}
is-unc-path@1.0.0:
dependencies:
unc-path-regex: 0.1.2
is-unicode-supported@0.1.0: {}
is-windows@1.0.2: {}
isbinaryfile@5.0.7: {}
isexe@2.0.0: {}
isobject@3.0.1: {}
istanbul-lib-coverage@3.2.2: {}
istanbul-lib-instrument@6.0.3:
@@ -7907,6 +8233,16 @@ snapshots:
libphonenumber-js@1.12.41: {}
liftoff@5.0.1:
dependencies:
extend: 3.0.2
findup-sync: 5.0.0
fined: 2.0.0
flagged-respawn: 2.0.0
is-plain-object: 5.0.0
rechoir: 0.8.0
resolve: 1.22.12
lines-and-columns@1.2.4: {}
load-esm@1.0.3: {}
@@ -7976,6 +8312,8 @@ snapshots:
dependencies:
tmpl: 1.0.5
map-cache@0.2.2: {}
mariadb@3.4.5:
dependencies:
'@types/geojson': 7946.0.16
@@ -8046,6 +8384,8 @@ snapshots:
concat-stream: 2.0.0
type-is: 1.6.18
mute-stream@1.0.0: {}
mute-stream@2.0.0: {}
mysql2@3.15.3:
@@ -8076,6 +8416,10 @@ snapshots:
dependencies:
lru.min: 1.1.4
nanospinner@1.2.2:
dependencies:
picocolors: 1.1.1
napi-postinstall@0.3.4: {}
natural-compare@1.4.0: {}
@@ -8098,6 +8442,21 @@ snapshots:
node-int64@0.4.0: {}
node-plop@0.32.3(@types/node@22.19.17):
dependencies:
'@types/inquirer': 9.0.9
'@types/picomatch': 4.0.3
change-case: 5.4.4
dlv: 1.1.3
handlebars: 4.7.9
inquirer: 9.3.8(@types/node@22.19.17)
isbinaryfile: 5.0.7
resolve: 1.22.12
tinyglobby: 0.2.16
title-case: 4.3.2
transitivePeerDependencies:
- '@types/node'
node-releases@2.0.37: {}
normalize-path@3.0.0: {}
@@ -8116,6 +8475,17 @@ snapshots:
object-inspect@1.13.4: {}
object.defaults@1.1.0:
dependencies:
array-each: 1.0.1
array-slice: 1.1.0
for-own: 1.0.0
isobject: 3.0.1
object.pick@1.3.0:
dependencies:
isobject: 3.0.1
ohash@2.0.11: {}
on-finished@2.4.1:
@@ -8175,6 +8545,12 @@ snapshots:
dependencies:
callsites: 3.1.0
parse-filepath@1.0.2:
dependencies:
is-absolute: 1.0.0
map-cache: 0.2.2
path-root: 0.1.1
parse-json@5.2.0:
dependencies:
'@babel/code-frame': 7.29.0
@@ -8182,6 +8558,8 @@ snapshots:
json-parse-even-better-errors: 2.3.1
lines-and-columns: 1.2.4
parse-passwd@1.0.0: {}
parseurl@1.3.3: {}
path-exists@4.0.0: {}
@@ -8192,6 +8570,14 @@ snapshots:
path-key@3.1.1: {}
path-parse@1.0.7: {}
path-root-regex@0.1.2: {}
path-root@0.1.1:
dependencies:
path-root-regex: 0.1.2
path-scurry@1.11.1:
dependencies:
lru-cache: 10.4.3
@@ -8228,6 +8614,18 @@ snapshots:
exsolve: 1.0.8
pathe: 2.0.3
plop@4.0.5(@types/node@22.19.17):
dependencies:
'@types/liftoff': 4.0.3
interpret: 3.1.1
liftoff: 5.0.1
nanospinner: 1.2.2
node-plop: 0.32.3(@types/node@22.19.17)
picocolors: 1.1.1
v8flags: 4.0.1
transitivePeerDependencies:
- '@types/node'
pluralize@8.0.0: {}
postgres@3.4.7: {}
@@ -8320,6 +8718,10 @@ snapshots:
readdirp@4.1.2: {}
rechoir@0.8.0:
dependencies:
resolve: 1.22.12
redis-errors@1.2.0: {}
redis-parser@3.0.0:
@@ -8338,12 +8740,24 @@ snapshots:
dependencies:
resolve-from: 5.0.0
resolve-dir@1.0.1:
dependencies:
expand-tilde: 2.0.2
global-modules: 1.0.0
resolve-from@4.0.0: {}
resolve-from@5.0.0: {}
resolve-pkg-maps@1.0.0: {}
resolve@1.22.12:
dependencies:
es-errors: 1.3.0
is-core-module: 2.16.2
path-parse: 1.0.7
supports-preserve-symlinks-flag: 1.0.0
restore-cursor@3.1.0:
dependencies:
onetime: 5.1.2
@@ -8361,6 +8775,8 @@ snapshots:
transitivePeerDependencies:
- supports-color
run-async@3.0.0: {}
rxjs@7.8.1:
dependencies:
tslib: 2.8.1
@@ -8568,6 +8984,8 @@ snapshots:
dependencies:
has-flag: 4.0.0
supports-preserve-symlinks-flag@1.0.0: {}
swagger-ui-dist@5.32.4:
dependencies:
'@scarf/scarf': 1.4.0
@@ -8608,6 +9026,8 @@ snapshots:
fdir: 6.5.0(picomatch@4.0.4)
picomatch: 4.0.4
title-case@4.3.2: {}
tmpl@1.0.5: {}
to-regex-range@5.0.1:
@@ -8741,6 +9161,8 @@ snapshots:
uint8array-extras@1.5.0: {}
unc-path-regex@0.1.2: {}
undici-types@6.21.0: {}
undici-types@7.16.0: {}
@@ -8795,6 +9217,8 @@ snapshots:
'@types/istanbul-lib-coverage': 2.0.6
convert-source-map: 2.0.0
v8flags@4.0.1: {}
valibot@1.2.0(typescript@5.9.3):
optionalDependencies:
typescript: 5.9.3
@@ -8852,6 +9276,10 @@ snapshots:
- esbuild
- uglify-js
which@1.3.1:
dependencies:
isexe: 2.0.0
which@2.0.2:
dependencies:
isexe: 2.0.0
@@ -0,0 +1,16 @@
-- CreateTable
CREATE TABLE `consumer_account_goods_favorites` (
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`consumer_account_id` VARCHAR(191) NOT NULL,
`goods_id` VARCHAR(191) NOT NULL,
INDEX `consumer_account_goods_favorites_goods_id_idx`(`goods_id`),
INDEX `consumer_account_goods_favorites_consumer_account_id_idx`(`consumer_account_id`),
PRIMARY KEY (`consumer_account_id`, `goods_id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- AddForeignKey
ALTER TABLE `consumer_account_goods_favorites` ADD CONSTRAINT `consumer_account_goods_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_goods_favorites` ADD CONSTRAINT `consumer_account_goods_favorites_goods_id_fkey` FOREIGN KEY (`goods_id`) REFERENCES `goods`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
@@ -0,0 +1,31 @@
/*
Warnings:
- You are about to drop the `consumer_account_goods_favorites` table. If the table is not empty, all the data it contains will be lost.
*/
-- DropForeignKey
ALTER TABLE `consumer_account_goods_favorites` DROP FOREIGN KEY `consumer_account_goods_favorites_consumer_account_id_fkey`;
-- DropForeignKey
ALTER TABLE `consumer_account_goods_favorites` DROP FOREIGN KEY `consumer_account_goods_favorites_goods_id_fkey`;
-- DropTable
DROP TABLE `consumer_account_goods_favorites`;
-- 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;
-- 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;
+17 -1
View File
@@ -14,8 +14,9 @@ model ConsumerAccount {
pos Pos?
permission PermissionConsumer?
account_allocation LicenseAccountAllocation?
sales_invoices SalesInvoice[]
account_device ConsumerAccountDevice?
sales_invoices SalesInvoice[]
consumer_account_good_favorites ConsumerAccountGoodFavorite[]
@@map("consumer_accounts")
}
@@ -150,3 +151,18 @@ model Pos {
@@map("poses")
}
model ConsumerAccountGoodFavorite {
created_at DateTime @default(now())
consumer_account_id String
consumer_account ConsumerAccount @relation(fields: [consumer_account_id], references: [id], onDelete: Cascade)
good_id String
good Good @relation(fields: [good_id], references: [id], onDelete: Cascade)
@@id([consumer_account_id, good_id]) // unique pair
@@index([good_id])
@@index([consumer_account_id])
@@map("consumer_account_good_favorites")
}
+1
View File
@@ -26,6 +26,7 @@ model Good {
business_activity BusinessActivity? @relation(fields: [business_activity_id], references: [id])
sales_invoice_items SalesInvoiceItem[]
consumer_account_good_favorites ConsumerAccountGoodFavorite[]
@@index([category_id])
@@map("goods")
File diff suppressed because it is too large Load Diff
+2 -4
View File
@@ -7,10 +7,9 @@ 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 { 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'
@@ -26,8 +25,7 @@ import { RedisModule } from './redis/redis.module'
ConsumerModule,
PosModule,
PartnerModule,
SalesInvoicePaymentsModule,
TriggerLogsModule,
PublicInvoicesModule,
UploaderModule,
ApplicationModule,
],
-80
View File
@@ -52,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
// }
}
}
-8
View File
@@ -98,14 +98,6 @@ export const select: SalesInvoiceSelect = {
notes: true,
payload: true,
good_snapshot: true,
good: {
select: {
name: true,
barcode: true,
image_url: true,
category: true,
},
},
},
},
payments: {
@@ -411,11 +411,7 @@ export class SharedSaleInvoiceCreateService {
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({
good: goodsById.get(item.good_id) || null,
}),
)
? JSON.parse(JSON.stringify(goodsById.get(item.good_id) || null))
: undefined,
})),
},
+82
View File
@@ -0,0 +1,82 @@
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(2, '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,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)
}
+2
View File
@@ -1,4 +1,6 @@
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'
+6 -3
View File
@@ -3,6 +3,7 @@ import { EnumKeyMaker } from './enum'
import { GuildKeyMaker } from './guild'
import { PartnerKeyMaker } from './partner'
import { PosKeyMaker } from './pos'
import { PublicSaleInvoiceKeyMaker } from './publicSaleInvoice'
// Keep backward-compatible static methods while separating key builders by domain.
export class RedisKeyMaker extends PartnerKeyMaker {
@@ -19,12 +20,14 @@ export class RedisKeyMaker extends PartnerKeyMaker {
static guildStockKeepingUnitsList = GuildKeyMaker.guildStockKeepingUnitsList
static guildGoodsList = GuildKeyMaker.guildGoodsList
static posInfo = PosKeyMaker.posInfo
static posMe = PosKeyMaker.posMe
static posGoodsList = PosKeyMaker.posGoodsList
static posInfo = PosKeyMaker.info
static posMe = PosKeyMaker.me
static posGoodsList = PosKeyMaker.goodList
static enumsAll = EnumKeyMaker.enumsAll
static enumsValues = EnumKeyMaker.enumsValues
static publicSaleInvoice = PublicSaleInvoiceKeyMaker.invoice
}
export { ConsumerKeyMaker, EnumKeyMaker, GuildKeyMaker, PartnerKeyMaker, PosKeyMaker }
+54 -4
View File
@@ -1,13 +1,63 @@
export class PosKeyMaker {
static posInfo(posId: string): string {
static info(posId: string): string {
return `pos:${posId}:info`
}
static posMe(accountId: string, posId: string): string {
static me(accountId: string, posId: string): string {
return `pos:${posId}:me:${accountId}`
}
static posGoodsList(businessActivityId: string, guildId: string): string {
return `pos:ba:${businessActivityId}:guild:${guildId}:goods:list`
static goodList(guildId: string, businessActivityId: string): string {
return `pos:goods:list:guildId:${guildId}:ba:${businessActivityId}`
}
static goodListByGuildPattern(guildId: string): string {
return `pos:goods:list:guildId:${guildId}:ba:*`
}
static statisticInvoicesPattern(businessActivityId: string): string {
return `pos:statistics:invoices:ba:${businessActivityId}:*`
}
static statisticInvoices(
businessActivityId: string,
posId: string,
from: string,
): string {
return `pos:statistics:invoices:ba:${businessActivityId}:pos:${posId}:from:${from}:all`
}
static statisticInvoicesNotSent(
businessActivityId: string,
posId: string,
from: string,
): string {
return `pos:statistics:invoices:ba:${businessActivityId}:pos:${posId}:from:${from}:not-sent`
}
static statisticInvoicesSuccess(
businessActivityId: string,
posId: string,
from: string,
): string {
return `pos:statistics:invoices:ba:${businessActivityId}:pos:${posId}:from:${from}:success`
}
static statisticInvoicesFailure(
businessActivityId: string,
posId: string,
from: string,
): string {
return `pos:statistics:invoices:ba:${businessActivityId}:pos:${posId}:from:${from}:failure`
}
static statisticInvoicesPending(
businessActivityId: string,
posId: string,
from: string,
): string {
return `pos:statistics:invoices:ba:${businessActivityId}:pos:${posId}:from:${from}:pending`
}
static statisticInvoicesCredit(
businessActivityId: string,
posId: string,
from: string,
): string {
return `pos:statistics:invoices:ba:${businessActivityId}:pos:${posId}:from:${from}:credit`
}
}
@@ -0,0 +1,5 @@
export class PublicSaleInvoiceKeyMaker {
static invoice(id: string): string {
return `publicSaleInvoices:${id}`
}
}
+5
View File
@@ -167,6 +167,11 @@ export type Complex = Prisma.ComplexModel
*
*/
export type Pos = Prisma.PosModel
/**
* Model ConsumerAccountGoodFavorite
*
*/
export type ConsumerAccountGoodFavorite = Prisma.ConsumerAccountGoodFavoriteModel
/**
* Model Good
*
+5
View File
@@ -189,6 +189,11 @@ export type Complex = Prisma.ComplexModel
*
*/
export type Pos = Prisma.PosModel
/**
* Model ConsumerAccountGoodFavorite
*
*/
export type ConsumerAccountGoodFavorite = Prisma.ConsumerAccountGoodFavoriteModel
/**
* Model Good
*
File diff suppressed because one or more lines are too long
@@ -414,6 +414,7 @@ export const ModelName = {
BusinessActivity: 'BusinessActivity',
Complex: 'Complex',
Pos: 'Pos',
ConsumerAccountGoodFavorite: 'ConsumerAccountGoodFavorite',
Good: 'Good',
GoodCategory: 'GoodCategory',
Guild: 'Guild',
@@ -445,7 +446,7 @@ export type TypeMap<ExtArgs extends runtime.Types.Extensions.InternalArgs = runt
omit: GlobalOmitOptions
}
meta: {
modelProps: "adminAccount" | "admin" | "account" | "deviceBrand" | "device" | "licenseChargeTransaction" | "license" | "licenseActivation" | "licenseRenewChargeTransaction" | "licenseRenew" | "partnerAccountQuotaChargeTransaction" | "partnerAccountQuotaCredit" | "licenseAccountAllocation" | "partnerAccount" | "partner" | "permissionConsumer" | "permissionPos" | "permissionComplex" | "permissionBusiness" | "providerAccount" | "provider" | "consumerAccountDevice" | "applicationReleasedInfo" | "consumerAccount" | "consumer" | "consumerIndividual" | "consumerLegal" | "businessActivity" | "complex" | "pos" | "good" | "goodCategory" | "guild" | "measureUnits" | "stockKeepingUnits" | "triggerLog" | "customer" | "customerIndividual" | "customerLegal" | "salesInvoice" | "salesInvoiceItem" | "saleInvoiceTspAttempts" | "salesInvoicePayment" | "salesInvoicePaymentTerminalInfo" | "service" | "serviceCategory"
modelProps: "adminAccount" | "admin" | "account" | "deviceBrand" | "device" | "licenseChargeTransaction" | "license" | "licenseActivation" | "licenseRenewChargeTransaction" | "licenseRenew" | "partnerAccountQuotaChargeTransaction" | "partnerAccountQuotaCredit" | "licenseAccountAllocation" | "partnerAccount" | "partner" | "permissionConsumer" | "permissionPos" | "permissionComplex" | "permissionBusiness" | "providerAccount" | "provider" | "consumerAccountDevice" | "applicationReleasedInfo" | "consumerAccount" | "consumer" | "consumerIndividual" | "consumerLegal" | "businessActivity" | "complex" | "pos" | "consumerAccountGoodFavorite" | "good" | "goodCategory" | "guild" | "measureUnits" | "stockKeepingUnits" | "triggerLog" | "customer" | "customerIndividual" | "customerLegal" | "salesInvoice" | "salesInvoiceItem" | "saleInvoiceTspAttempts" | "salesInvoicePayment" | "salesInvoicePaymentTerminalInfo" | "service" | "serviceCategory"
txIsolationLevel: TransactionIsolationLevel
}
model: {
@@ -2429,6 +2430,72 @@ export type TypeMap<ExtArgs extends runtime.Types.Extensions.InternalArgs = runt
}
}
}
ConsumerAccountGoodFavorite: {
payload: Prisma.$ConsumerAccountGoodFavoritePayload<ExtArgs>
fields: Prisma.ConsumerAccountGoodFavoriteFieldRefs
operations: {
findUnique: {
args: Prisma.ConsumerAccountGoodFavoriteFindUniqueArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$ConsumerAccountGoodFavoritePayload> | null
}
findUniqueOrThrow: {
args: Prisma.ConsumerAccountGoodFavoriteFindUniqueOrThrowArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$ConsumerAccountGoodFavoritePayload>
}
findFirst: {
args: Prisma.ConsumerAccountGoodFavoriteFindFirstArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$ConsumerAccountGoodFavoritePayload> | null
}
findFirstOrThrow: {
args: Prisma.ConsumerAccountGoodFavoriteFindFirstOrThrowArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$ConsumerAccountGoodFavoritePayload>
}
findMany: {
args: Prisma.ConsumerAccountGoodFavoriteFindManyArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$ConsumerAccountGoodFavoritePayload>[]
}
create: {
args: Prisma.ConsumerAccountGoodFavoriteCreateArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$ConsumerAccountGoodFavoritePayload>
}
createMany: {
args: Prisma.ConsumerAccountGoodFavoriteCreateManyArgs<ExtArgs>
result: BatchPayload
}
delete: {
args: Prisma.ConsumerAccountGoodFavoriteDeleteArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$ConsumerAccountGoodFavoritePayload>
}
update: {
args: Prisma.ConsumerAccountGoodFavoriteUpdateArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$ConsumerAccountGoodFavoritePayload>
}
deleteMany: {
args: Prisma.ConsumerAccountGoodFavoriteDeleteManyArgs<ExtArgs>
result: BatchPayload
}
updateMany: {
args: Prisma.ConsumerAccountGoodFavoriteUpdateManyArgs<ExtArgs>
result: BatchPayload
}
upsert: {
args: Prisma.ConsumerAccountGoodFavoriteUpsertArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$ConsumerAccountGoodFavoritePayload>
}
aggregate: {
args: Prisma.ConsumerAccountGoodFavoriteAggregateArgs<ExtArgs>
result: runtime.Types.Utils.Optional<Prisma.AggregateConsumerAccountGoodFavorite>
}
groupBy: {
args: Prisma.ConsumerAccountGoodFavoriteGroupByArgs<ExtArgs>
result: runtime.Types.Utils.Optional<Prisma.ConsumerAccountGoodFavoriteGroupByOutputType>[]
}
count: {
args: Prisma.ConsumerAccountGoodFavoriteCountArgs<ExtArgs>
result: runtime.Types.Utils.Optional<Prisma.ConsumerAccountGoodFavoriteCountAggregateOutputType> | number
}
}
}
Good: {
payload: Prisma.$GoodPayload<ExtArgs>
fields: Prisma.GoodFieldRefs
@@ -3890,6 +3957,15 @@ export const PosScalarFieldEnum = {
export type PosScalarFieldEnum = (typeof PosScalarFieldEnum)[keyof typeof PosScalarFieldEnum]
export const ConsumerAccountGoodFavoriteScalarFieldEnum = {
created_at: 'created_at',
consumer_account_id: 'consumer_account_id',
good_id: 'good_id'
} as const
export type ConsumerAccountGoodFavoriteScalarFieldEnum = (typeof ConsumerAccountGoodFavoriteScalarFieldEnum)[keyof typeof ConsumerAccountGoodFavoriteScalarFieldEnum]
export const GoodScalarFieldEnum = {
id: 'id',
name: 'name',
@@ -4469,6 +4545,14 @@ export const PosOrderByRelevanceFieldEnum = {
export type PosOrderByRelevanceFieldEnum = (typeof PosOrderByRelevanceFieldEnum)[keyof typeof PosOrderByRelevanceFieldEnum]
export const ConsumerAccountGoodFavoriteOrderByRelevanceFieldEnum = {
consumer_account_id: 'consumer_account_id',
good_id: 'good_id'
} as const
export type ConsumerAccountGoodFavoriteOrderByRelevanceFieldEnum = (typeof ConsumerAccountGoodFavoriteOrderByRelevanceFieldEnum)[keyof typeof ConsumerAccountGoodFavoriteOrderByRelevanceFieldEnum]
export const GoodOrderByRelevanceFieldEnum = {
id: 'id',
name: 'name',
@@ -4992,6 +5076,7 @@ export type GlobalOmitConfig = {
businessActivity?: Prisma.BusinessActivityOmit
complex?: Prisma.ComplexOmit
pos?: Prisma.PosOmit
consumerAccountGoodFavorite?: Prisma.ConsumerAccountGoodFavoriteOmit
good?: Prisma.GoodOmit
goodCategory?: Prisma.GoodCategoryOmit
guild?: Prisma.GuildOmit
@@ -81,6 +81,7 @@ export const ModelName = {
BusinessActivity: 'BusinessActivity',
Complex: 'Complex',
Pos: 'Pos',
ConsumerAccountGoodFavorite: 'ConsumerAccountGoodFavorite',
Good: 'Good',
GoodCategory: 'GoodCategory',
Guild: 'Guild',
@@ -481,6 +482,15 @@ export const PosScalarFieldEnum = {
export type PosScalarFieldEnum = (typeof PosScalarFieldEnum)[keyof typeof PosScalarFieldEnum]
export const ConsumerAccountGoodFavoriteScalarFieldEnum = {
created_at: 'created_at',
consumer_account_id: 'consumer_account_id',
good_id: 'good_id'
} as const
export type ConsumerAccountGoodFavoriteScalarFieldEnum = (typeof ConsumerAccountGoodFavoriteScalarFieldEnum)[keyof typeof ConsumerAccountGoodFavoriteScalarFieldEnum]
export const GoodScalarFieldEnum = {
id: 'id',
name: 'name',
@@ -1060,6 +1070,14 @@ export const PosOrderByRelevanceFieldEnum = {
export type PosOrderByRelevanceFieldEnum = (typeof PosOrderByRelevanceFieldEnum)[keyof typeof PosOrderByRelevanceFieldEnum]
export const ConsumerAccountGoodFavoriteOrderByRelevanceFieldEnum = {
consumer_account_id: 'consumer_account_id',
good_id: 'good_id'
} as const
export type ConsumerAccountGoodFavoriteOrderByRelevanceFieldEnum = (typeof ConsumerAccountGoodFavoriteOrderByRelevanceFieldEnum)[keyof typeof ConsumerAccountGoodFavoriteOrderByRelevanceFieldEnum]
export const GoodOrderByRelevanceFieldEnum = {
id: 'id',
name: 'name',
+1
View File
@@ -38,6 +38,7 @@ export type * from './models/ConsumerLegal.js'
export type * from './models/BusinessActivity.js'
export type * from './models/Complex.js'
export type * from './models/Pos.js'
export type * from './models/ConsumerAccountGoodFavorite.js'
export type * from './models/Good.js'
export type * from './models/GoodCategory.js'
export type * from './models/Guild.js'
+197 -39
View File
@@ -195,8 +195,9 @@ export type ConsumerAccountWhereInput = {
pos?: Prisma.XOR<Prisma.PosNullableScalarRelationFilter, Prisma.PosWhereInput> | null
permission?: Prisma.XOR<Prisma.PermissionConsumerNullableScalarRelationFilter, Prisma.PermissionConsumerWhereInput> | null
account_allocation?: Prisma.XOR<Prisma.LicenseAccountAllocationNullableScalarRelationFilter, Prisma.LicenseAccountAllocationWhereInput> | null
sales_invoices?: Prisma.SalesInvoiceListRelationFilter
account_device?: Prisma.XOR<Prisma.ConsumerAccountDeviceNullableScalarRelationFilter, Prisma.ConsumerAccountDeviceWhereInput> | null
sales_invoices?: Prisma.SalesInvoiceListRelationFilter
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteListRelationFilter
}
export type ConsumerAccountOrderByWithRelationInput = {
@@ -211,8 +212,9 @@ export type ConsumerAccountOrderByWithRelationInput = {
pos?: Prisma.PosOrderByWithRelationInput
permission?: Prisma.PermissionConsumerOrderByWithRelationInput
account_allocation?: Prisma.LicenseAccountAllocationOrderByWithRelationInput
sales_invoices?: Prisma.SalesInvoiceOrderByRelationAggregateInput
account_device?: Prisma.ConsumerAccountDeviceOrderByWithRelationInput
sales_invoices?: Prisma.SalesInvoiceOrderByRelationAggregateInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteOrderByRelationAggregateInput
_relevance?: Prisma.ConsumerAccountOrderByRelevanceInput
}
@@ -231,8 +233,9 @@ export type ConsumerAccountWhereUniqueInput = Prisma.AtLeast<{
pos?: Prisma.XOR<Prisma.PosNullableScalarRelationFilter, Prisma.PosWhereInput> | null
permission?: Prisma.XOR<Prisma.PermissionConsumerNullableScalarRelationFilter, Prisma.PermissionConsumerWhereInput> | null
account_allocation?: Prisma.XOR<Prisma.LicenseAccountAllocationNullableScalarRelationFilter, Prisma.LicenseAccountAllocationWhereInput> | null
sales_invoices?: Prisma.SalesInvoiceListRelationFilter
account_device?: Prisma.XOR<Prisma.ConsumerAccountDeviceNullableScalarRelationFilter, Prisma.ConsumerAccountDeviceWhereInput> | null
sales_invoices?: Prisma.SalesInvoiceListRelationFilter
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteListRelationFilter
}, "id" | "account_id">
export type ConsumerAccountOrderByWithAggregationInput = {
@@ -269,8 +272,9 @@ export type ConsumerAccountCreateInput = {
pos?: Prisma.PosCreateNestedOneWithoutAccountInput
permission?: Prisma.PermissionConsumerCreateNestedOneWithoutConsumer_accountInput
account_allocation?: Prisma.LicenseAccountAllocationCreateNestedOneWithoutAccountInput
sales_invoices?: Prisma.SalesInvoiceCreateNestedManyWithoutConsumer_accountInput
account_device?: Prisma.ConsumerAccountDeviceCreateNestedOneWithoutConsumer_accountInput
sales_invoices?: Prisma.SalesInvoiceCreateNestedManyWithoutConsumer_accountInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteCreateNestedManyWithoutConsumer_accountInput
}
export type ConsumerAccountUncheckedCreateInput = {
@@ -283,8 +287,9 @@ export type ConsumerAccountUncheckedCreateInput = {
pos?: Prisma.PosUncheckedCreateNestedOneWithoutAccountInput
permission?: Prisma.PermissionConsumerUncheckedCreateNestedOneWithoutConsumer_accountInput
account_allocation?: Prisma.LicenseAccountAllocationUncheckedCreateNestedOneWithoutAccountInput
sales_invoices?: Prisma.SalesInvoiceUncheckedCreateNestedManyWithoutConsumer_accountInput
account_device?: Prisma.ConsumerAccountDeviceUncheckedCreateNestedOneWithoutConsumer_accountInput
sales_invoices?: Prisma.SalesInvoiceUncheckedCreateNestedManyWithoutConsumer_accountInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteUncheckedCreateNestedManyWithoutConsumer_accountInput
}
export type ConsumerAccountUpdateInput = {
@@ -297,8 +302,9 @@ export type ConsumerAccountUpdateInput = {
pos?: Prisma.PosUpdateOneWithoutAccountNestedInput
permission?: Prisma.PermissionConsumerUpdateOneWithoutConsumer_accountNestedInput
account_allocation?: Prisma.LicenseAccountAllocationUpdateOneWithoutAccountNestedInput
sales_invoices?: Prisma.SalesInvoiceUpdateManyWithoutConsumer_accountNestedInput
account_device?: Prisma.ConsumerAccountDeviceUpdateOneWithoutConsumer_accountNestedInput
sales_invoices?: Prisma.SalesInvoiceUpdateManyWithoutConsumer_accountNestedInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteUpdateManyWithoutConsumer_accountNestedInput
}
export type ConsumerAccountUncheckedUpdateInput = {
@@ -311,8 +317,9 @@ export type ConsumerAccountUncheckedUpdateInput = {
pos?: Prisma.PosUncheckedUpdateOneWithoutAccountNestedInput
permission?: Prisma.PermissionConsumerUncheckedUpdateOneWithoutConsumer_accountNestedInput
account_allocation?: Prisma.LicenseAccountAllocationUncheckedUpdateOneWithoutAccountNestedInput
sales_invoices?: Prisma.SalesInvoiceUncheckedUpdateManyWithoutConsumer_accountNestedInput
account_device?: Prisma.ConsumerAccountDeviceUncheckedUpdateOneWithoutConsumer_accountNestedInput
sales_invoices?: Prisma.SalesInvoiceUncheckedUpdateManyWithoutConsumer_accountNestedInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteUncheckedUpdateManyWithoutConsumer_accountNestedInput
}
export type ConsumerAccountCreateManyInput = {
@@ -529,6 +536,20 @@ export type ConsumerAccountUpdateOneRequiredWithoutPosNestedInput = {
update?: Prisma.XOR<Prisma.XOR<Prisma.ConsumerAccountUpdateToOneWithWhereWithoutPosInput, Prisma.ConsumerAccountUpdateWithoutPosInput>, Prisma.ConsumerAccountUncheckedUpdateWithoutPosInput>
}
export type ConsumerAccountCreateNestedOneWithoutConsumer_account_good_favoritesInput = {
create?: Prisma.XOR<Prisma.ConsumerAccountCreateWithoutConsumer_account_good_favoritesInput, Prisma.ConsumerAccountUncheckedCreateWithoutConsumer_account_good_favoritesInput>
connectOrCreate?: Prisma.ConsumerAccountCreateOrConnectWithoutConsumer_account_good_favoritesInput
connect?: Prisma.ConsumerAccountWhereUniqueInput
}
export type ConsumerAccountUpdateOneRequiredWithoutConsumer_account_good_favoritesNestedInput = {
create?: Prisma.XOR<Prisma.ConsumerAccountCreateWithoutConsumer_account_good_favoritesInput, Prisma.ConsumerAccountUncheckedCreateWithoutConsumer_account_good_favoritesInput>
connectOrCreate?: Prisma.ConsumerAccountCreateOrConnectWithoutConsumer_account_good_favoritesInput
upsert?: Prisma.ConsumerAccountUpsertWithoutConsumer_account_good_favoritesInput
connect?: Prisma.ConsumerAccountWhereUniqueInput
update?: Prisma.XOR<Prisma.XOR<Prisma.ConsumerAccountUpdateToOneWithWhereWithoutConsumer_account_good_favoritesInput, Prisma.ConsumerAccountUpdateWithoutConsumer_account_good_favoritesInput>, Prisma.ConsumerAccountUncheckedUpdateWithoutConsumer_account_good_favoritesInput>
}
export type ConsumerAccountCreateNestedOneWithoutSales_invoicesInput = {
create?: Prisma.XOR<Prisma.ConsumerAccountCreateWithoutSales_invoicesInput, Prisma.ConsumerAccountUncheckedCreateWithoutSales_invoicesInput>
connectOrCreate?: Prisma.ConsumerAccountCreateOrConnectWithoutSales_invoicesInput
@@ -552,8 +573,9 @@ export type ConsumerAccountCreateWithoutAccountInput = {
pos?: Prisma.PosCreateNestedOneWithoutAccountInput
permission?: Prisma.PermissionConsumerCreateNestedOneWithoutConsumer_accountInput
account_allocation?: Prisma.LicenseAccountAllocationCreateNestedOneWithoutAccountInput
sales_invoices?: Prisma.SalesInvoiceCreateNestedManyWithoutConsumer_accountInput
account_device?: Prisma.ConsumerAccountDeviceCreateNestedOneWithoutConsumer_accountInput
sales_invoices?: Prisma.SalesInvoiceCreateNestedManyWithoutConsumer_accountInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteCreateNestedManyWithoutConsumer_accountInput
}
export type ConsumerAccountUncheckedCreateWithoutAccountInput = {
@@ -565,8 +587,9 @@ export type ConsumerAccountUncheckedCreateWithoutAccountInput = {
pos?: Prisma.PosUncheckedCreateNestedOneWithoutAccountInput
permission?: Prisma.PermissionConsumerUncheckedCreateNestedOneWithoutConsumer_accountInput
account_allocation?: Prisma.LicenseAccountAllocationUncheckedCreateNestedOneWithoutAccountInput
sales_invoices?: Prisma.SalesInvoiceUncheckedCreateNestedManyWithoutConsumer_accountInput
account_device?: Prisma.ConsumerAccountDeviceUncheckedCreateNestedOneWithoutConsumer_accountInput
sales_invoices?: Prisma.SalesInvoiceUncheckedCreateNestedManyWithoutConsumer_accountInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteUncheckedCreateNestedManyWithoutConsumer_accountInput
}
export type ConsumerAccountCreateOrConnectWithoutAccountInput = {
@@ -594,8 +617,9 @@ export type ConsumerAccountUpdateWithoutAccountInput = {
pos?: Prisma.PosUpdateOneWithoutAccountNestedInput
permission?: Prisma.PermissionConsumerUpdateOneWithoutConsumer_accountNestedInput
account_allocation?: Prisma.LicenseAccountAllocationUpdateOneWithoutAccountNestedInput
sales_invoices?: Prisma.SalesInvoiceUpdateManyWithoutConsumer_accountNestedInput
account_device?: Prisma.ConsumerAccountDeviceUpdateOneWithoutConsumer_accountNestedInput
sales_invoices?: Prisma.SalesInvoiceUpdateManyWithoutConsumer_accountNestedInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteUpdateManyWithoutConsumer_accountNestedInput
}
export type ConsumerAccountUncheckedUpdateWithoutAccountInput = {
@@ -607,8 +631,9 @@ export type ConsumerAccountUncheckedUpdateWithoutAccountInput = {
pos?: Prisma.PosUncheckedUpdateOneWithoutAccountNestedInput
permission?: Prisma.PermissionConsumerUncheckedUpdateOneWithoutConsumer_accountNestedInput
account_allocation?: Prisma.LicenseAccountAllocationUncheckedUpdateOneWithoutAccountNestedInput
sales_invoices?: Prisma.SalesInvoiceUncheckedUpdateManyWithoutConsumer_accountNestedInput
account_device?: Prisma.ConsumerAccountDeviceUncheckedUpdateOneWithoutConsumer_accountNestedInput
sales_invoices?: Prisma.SalesInvoiceUncheckedUpdateManyWithoutConsumer_accountNestedInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteUncheckedUpdateManyWithoutConsumer_accountNestedInput
}
export type ConsumerAccountCreateWithoutAccount_allocationInput = {
@@ -620,8 +645,9 @@ export type ConsumerAccountCreateWithoutAccount_allocationInput = {
account: Prisma.AccountCreateNestedOneWithoutConsumer_accountInput
pos?: Prisma.PosCreateNestedOneWithoutAccountInput
permission?: Prisma.PermissionConsumerCreateNestedOneWithoutConsumer_accountInput
sales_invoices?: Prisma.SalesInvoiceCreateNestedManyWithoutConsumer_accountInput
account_device?: Prisma.ConsumerAccountDeviceCreateNestedOneWithoutConsumer_accountInput
sales_invoices?: Prisma.SalesInvoiceCreateNestedManyWithoutConsumer_accountInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteCreateNestedManyWithoutConsumer_accountInput
}
export type ConsumerAccountUncheckedCreateWithoutAccount_allocationInput = {
@@ -633,8 +659,9 @@ export type ConsumerAccountUncheckedCreateWithoutAccount_allocationInput = {
account_id: string
pos?: Prisma.PosUncheckedCreateNestedOneWithoutAccountInput
permission?: Prisma.PermissionConsumerUncheckedCreateNestedOneWithoutConsumer_accountInput
sales_invoices?: Prisma.SalesInvoiceUncheckedCreateNestedManyWithoutConsumer_accountInput
account_device?: Prisma.ConsumerAccountDeviceUncheckedCreateNestedOneWithoutConsumer_accountInput
sales_invoices?: Prisma.SalesInvoiceUncheckedCreateNestedManyWithoutConsumer_accountInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteUncheckedCreateNestedManyWithoutConsumer_accountInput
}
export type ConsumerAccountCreateOrConnectWithoutAccount_allocationInput = {
@@ -662,8 +689,9 @@ export type ConsumerAccountUpdateWithoutAccount_allocationInput = {
account?: Prisma.AccountUpdateOneRequiredWithoutConsumer_accountNestedInput
pos?: Prisma.PosUpdateOneWithoutAccountNestedInput
permission?: Prisma.PermissionConsumerUpdateOneWithoutConsumer_accountNestedInput
sales_invoices?: Prisma.SalesInvoiceUpdateManyWithoutConsumer_accountNestedInput
account_device?: Prisma.ConsumerAccountDeviceUpdateOneWithoutConsumer_accountNestedInput
sales_invoices?: Prisma.SalesInvoiceUpdateManyWithoutConsumer_accountNestedInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteUpdateManyWithoutConsumer_accountNestedInput
}
export type ConsumerAccountUncheckedUpdateWithoutAccount_allocationInput = {
@@ -675,8 +703,9 @@ export type ConsumerAccountUncheckedUpdateWithoutAccount_allocationInput = {
account_id?: Prisma.StringFieldUpdateOperationsInput | string
pos?: Prisma.PosUncheckedUpdateOneWithoutAccountNestedInput
permission?: Prisma.PermissionConsumerUncheckedUpdateOneWithoutConsumer_accountNestedInput
sales_invoices?: Prisma.SalesInvoiceUncheckedUpdateManyWithoutConsumer_accountNestedInput
account_device?: Prisma.ConsumerAccountDeviceUncheckedUpdateOneWithoutConsumer_accountNestedInput
sales_invoices?: Prisma.SalesInvoiceUncheckedUpdateManyWithoutConsumer_accountNestedInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteUncheckedUpdateManyWithoutConsumer_accountNestedInput
}
export type ConsumerAccountCreateWithoutPermissionInput = {
@@ -688,8 +717,9 @@ export type ConsumerAccountCreateWithoutPermissionInput = {
account: Prisma.AccountCreateNestedOneWithoutConsumer_accountInput
pos?: Prisma.PosCreateNestedOneWithoutAccountInput
account_allocation?: Prisma.LicenseAccountAllocationCreateNestedOneWithoutAccountInput
sales_invoices?: Prisma.SalesInvoiceCreateNestedManyWithoutConsumer_accountInput
account_device?: Prisma.ConsumerAccountDeviceCreateNestedOneWithoutConsumer_accountInput
sales_invoices?: Prisma.SalesInvoiceCreateNestedManyWithoutConsumer_accountInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteCreateNestedManyWithoutConsumer_accountInput
}
export type ConsumerAccountUncheckedCreateWithoutPermissionInput = {
@@ -701,8 +731,9 @@ export type ConsumerAccountUncheckedCreateWithoutPermissionInput = {
account_id: string
pos?: Prisma.PosUncheckedCreateNestedOneWithoutAccountInput
account_allocation?: Prisma.LicenseAccountAllocationUncheckedCreateNestedOneWithoutAccountInput
sales_invoices?: Prisma.SalesInvoiceUncheckedCreateNestedManyWithoutConsumer_accountInput
account_device?: Prisma.ConsumerAccountDeviceUncheckedCreateNestedOneWithoutConsumer_accountInput
sales_invoices?: Prisma.SalesInvoiceUncheckedCreateNestedManyWithoutConsumer_accountInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteUncheckedCreateNestedManyWithoutConsumer_accountInput
}
export type ConsumerAccountCreateOrConnectWithoutPermissionInput = {
@@ -730,8 +761,9 @@ export type ConsumerAccountUpdateWithoutPermissionInput = {
account?: Prisma.AccountUpdateOneRequiredWithoutConsumer_accountNestedInput
pos?: Prisma.PosUpdateOneWithoutAccountNestedInput
account_allocation?: Prisma.LicenseAccountAllocationUpdateOneWithoutAccountNestedInput
sales_invoices?: Prisma.SalesInvoiceUpdateManyWithoutConsumer_accountNestedInput
account_device?: Prisma.ConsumerAccountDeviceUpdateOneWithoutConsumer_accountNestedInput
sales_invoices?: Prisma.SalesInvoiceUpdateManyWithoutConsumer_accountNestedInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteUpdateManyWithoutConsumer_accountNestedInput
}
export type ConsumerAccountUncheckedUpdateWithoutPermissionInput = {
@@ -743,8 +775,9 @@ export type ConsumerAccountUncheckedUpdateWithoutPermissionInput = {
account_id?: Prisma.StringFieldUpdateOperationsInput | string
pos?: Prisma.PosUncheckedUpdateOneWithoutAccountNestedInput
account_allocation?: Prisma.LicenseAccountAllocationUncheckedUpdateOneWithoutAccountNestedInput
sales_invoices?: Prisma.SalesInvoiceUncheckedUpdateManyWithoutConsumer_accountNestedInput
account_device?: Prisma.ConsumerAccountDeviceUncheckedUpdateOneWithoutConsumer_accountNestedInput
sales_invoices?: Prisma.SalesInvoiceUncheckedUpdateManyWithoutConsumer_accountNestedInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteUncheckedUpdateManyWithoutConsumer_accountNestedInput
}
export type ConsumerAccountCreateWithoutAccount_deviceInput = {
@@ -758,6 +791,7 @@ export type ConsumerAccountCreateWithoutAccount_deviceInput = {
permission?: Prisma.PermissionConsumerCreateNestedOneWithoutConsumer_accountInput
account_allocation?: Prisma.LicenseAccountAllocationCreateNestedOneWithoutAccountInput
sales_invoices?: Prisma.SalesInvoiceCreateNestedManyWithoutConsumer_accountInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteCreateNestedManyWithoutConsumer_accountInput
}
export type ConsumerAccountUncheckedCreateWithoutAccount_deviceInput = {
@@ -771,6 +805,7 @@ export type ConsumerAccountUncheckedCreateWithoutAccount_deviceInput = {
permission?: Prisma.PermissionConsumerUncheckedCreateNestedOneWithoutConsumer_accountInput
account_allocation?: Prisma.LicenseAccountAllocationUncheckedCreateNestedOneWithoutAccountInput
sales_invoices?: Prisma.SalesInvoiceUncheckedCreateNestedManyWithoutConsumer_accountInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteUncheckedCreateNestedManyWithoutConsumer_accountInput
}
export type ConsumerAccountCreateOrConnectWithoutAccount_deviceInput = {
@@ -800,6 +835,7 @@ export type ConsumerAccountUpdateWithoutAccount_deviceInput = {
permission?: Prisma.PermissionConsumerUpdateOneWithoutConsumer_accountNestedInput
account_allocation?: Prisma.LicenseAccountAllocationUpdateOneWithoutAccountNestedInput
sales_invoices?: Prisma.SalesInvoiceUpdateManyWithoutConsumer_accountNestedInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteUpdateManyWithoutConsumer_accountNestedInput
}
export type ConsumerAccountUncheckedUpdateWithoutAccount_deviceInput = {
@@ -813,6 +849,7 @@ export type ConsumerAccountUncheckedUpdateWithoutAccount_deviceInput = {
permission?: Prisma.PermissionConsumerUncheckedUpdateOneWithoutConsumer_accountNestedInput
account_allocation?: Prisma.LicenseAccountAllocationUncheckedUpdateOneWithoutAccountNestedInput
sales_invoices?: Prisma.SalesInvoiceUncheckedUpdateManyWithoutConsumer_accountNestedInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteUncheckedUpdateManyWithoutConsumer_accountNestedInput
}
export type ConsumerAccountCreateWithoutConsumerInput = {
@@ -824,8 +861,9 @@ export type ConsumerAccountCreateWithoutConsumerInput = {
pos?: Prisma.PosCreateNestedOneWithoutAccountInput
permission?: Prisma.PermissionConsumerCreateNestedOneWithoutConsumer_accountInput
account_allocation?: Prisma.LicenseAccountAllocationCreateNestedOneWithoutAccountInput
sales_invoices?: Prisma.SalesInvoiceCreateNestedManyWithoutConsumer_accountInput
account_device?: Prisma.ConsumerAccountDeviceCreateNestedOneWithoutConsumer_accountInput
sales_invoices?: Prisma.SalesInvoiceCreateNestedManyWithoutConsumer_accountInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteCreateNestedManyWithoutConsumer_accountInput
}
export type ConsumerAccountUncheckedCreateWithoutConsumerInput = {
@@ -837,8 +875,9 @@ export type ConsumerAccountUncheckedCreateWithoutConsumerInput = {
pos?: Prisma.PosUncheckedCreateNestedOneWithoutAccountInput
permission?: Prisma.PermissionConsumerUncheckedCreateNestedOneWithoutConsumer_accountInput
account_allocation?: Prisma.LicenseAccountAllocationUncheckedCreateNestedOneWithoutAccountInput
sales_invoices?: Prisma.SalesInvoiceUncheckedCreateNestedManyWithoutConsumer_accountInput
account_device?: Prisma.ConsumerAccountDeviceUncheckedCreateNestedOneWithoutConsumer_accountInput
sales_invoices?: Prisma.SalesInvoiceUncheckedCreateNestedManyWithoutConsumer_accountInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteUncheckedCreateNestedManyWithoutConsumer_accountInput
}
export type ConsumerAccountCreateOrConnectWithoutConsumerInput = {
@@ -888,8 +927,9 @@ export type ConsumerAccountCreateWithoutPosInput = {
account: Prisma.AccountCreateNestedOneWithoutConsumer_accountInput
permission?: Prisma.PermissionConsumerCreateNestedOneWithoutConsumer_accountInput
account_allocation?: Prisma.LicenseAccountAllocationCreateNestedOneWithoutAccountInput
sales_invoices?: Prisma.SalesInvoiceCreateNestedManyWithoutConsumer_accountInput
account_device?: Prisma.ConsumerAccountDeviceCreateNestedOneWithoutConsumer_accountInput
sales_invoices?: Prisma.SalesInvoiceCreateNestedManyWithoutConsumer_accountInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteCreateNestedManyWithoutConsumer_accountInput
}
export type ConsumerAccountUncheckedCreateWithoutPosInput = {
@@ -901,8 +941,9 @@ export type ConsumerAccountUncheckedCreateWithoutPosInput = {
account_id: string
permission?: Prisma.PermissionConsumerUncheckedCreateNestedOneWithoutConsumer_accountInput
account_allocation?: Prisma.LicenseAccountAllocationUncheckedCreateNestedOneWithoutAccountInput
sales_invoices?: Prisma.SalesInvoiceUncheckedCreateNestedManyWithoutConsumer_accountInput
account_device?: Prisma.ConsumerAccountDeviceUncheckedCreateNestedOneWithoutConsumer_accountInput
sales_invoices?: Prisma.SalesInvoiceUncheckedCreateNestedManyWithoutConsumer_accountInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteUncheckedCreateNestedManyWithoutConsumer_accountInput
}
export type ConsumerAccountCreateOrConnectWithoutPosInput = {
@@ -930,8 +971,9 @@ export type ConsumerAccountUpdateWithoutPosInput = {
account?: Prisma.AccountUpdateOneRequiredWithoutConsumer_accountNestedInput
permission?: Prisma.PermissionConsumerUpdateOneWithoutConsumer_accountNestedInput
account_allocation?: Prisma.LicenseAccountAllocationUpdateOneWithoutAccountNestedInput
sales_invoices?: Prisma.SalesInvoiceUpdateManyWithoutConsumer_accountNestedInput
account_device?: Prisma.ConsumerAccountDeviceUpdateOneWithoutConsumer_accountNestedInput
sales_invoices?: Prisma.SalesInvoiceUpdateManyWithoutConsumer_accountNestedInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteUpdateManyWithoutConsumer_accountNestedInput
}
export type ConsumerAccountUncheckedUpdateWithoutPosInput = {
@@ -943,8 +985,81 @@ export type ConsumerAccountUncheckedUpdateWithoutPosInput = {
account_id?: Prisma.StringFieldUpdateOperationsInput | string
permission?: Prisma.PermissionConsumerUncheckedUpdateOneWithoutConsumer_accountNestedInput
account_allocation?: Prisma.LicenseAccountAllocationUncheckedUpdateOneWithoutAccountNestedInput
sales_invoices?: Prisma.SalesInvoiceUncheckedUpdateManyWithoutConsumer_accountNestedInput
account_device?: Prisma.ConsumerAccountDeviceUncheckedUpdateOneWithoutConsumer_accountNestedInput
sales_invoices?: Prisma.SalesInvoiceUncheckedUpdateManyWithoutConsumer_accountNestedInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteUncheckedUpdateManyWithoutConsumer_accountNestedInput
}
export type ConsumerAccountCreateWithoutConsumer_account_good_favoritesInput = {
id?: string
role: $Enums.ConsumerRole
created_at?: Date | string
updated_at?: Date | string
consumer: Prisma.ConsumerCreateNestedOneWithoutAccountsInput
account: Prisma.AccountCreateNestedOneWithoutConsumer_accountInput
pos?: Prisma.PosCreateNestedOneWithoutAccountInput
permission?: Prisma.PermissionConsumerCreateNestedOneWithoutConsumer_accountInput
account_allocation?: Prisma.LicenseAccountAllocationCreateNestedOneWithoutAccountInput
account_device?: Prisma.ConsumerAccountDeviceCreateNestedOneWithoutConsumer_accountInput
sales_invoices?: Prisma.SalesInvoiceCreateNestedManyWithoutConsumer_accountInput
}
export type ConsumerAccountUncheckedCreateWithoutConsumer_account_good_favoritesInput = {
id?: string
role: $Enums.ConsumerRole
created_at?: Date | string
updated_at?: Date | string
consumer_id: string
account_id: string
pos?: Prisma.PosUncheckedCreateNestedOneWithoutAccountInput
permission?: Prisma.PermissionConsumerUncheckedCreateNestedOneWithoutConsumer_accountInput
account_allocation?: Prisma.LicenseAccountAllocationUncheckedCreateNestedOneWithoutAccountInput
account_device?: Prisma.ConsumerAccountDeviceUncheckedCreateNestedOneWithoutConsumer_accountInput
sales_invoices?: Prisma.SalesInvoiceUncheckedCreateNestedManyWithoutConsumer_accountInput
}
export type ConsumerAccountCreateOrConnectWithoutConsumer_account_good_favoritesInput = {
where: Prisma.ConsumerAccountWhereUniqueInput
create: Prisma.XOR<Prisma.ConsumerAccountCreateWithoutConsumer_account_good_favoritesInput, Prisma.ConsumerAccountUncheckedCreateWithoutConsumer_account_good_favoritesInput>
}
export type ConsumerAccountUpsertWithoutConsumer_account_good_favoritesInput = {
update: Prisma.XOR<Prisma.ConsumerAccountUpdateWithoutConsumer_account_good_favoritesInput, Prisma.ConsumerAccountUncheckedUpdateWithoutConsumer_account_good_favoritesInput>
create: Prisma.XOR<Prisma.ConsumerAccountCreateWithoutConsumer_account_good_favoritesInput, Prisma.ConsumerAccountUncheckedCreateWithoutConsumer_account_good_favoritesInput>
where?: Prisma.ConsumerAccountWhereInput
}
export type ConsumerAccountUpdateToOneWithWhereWithoutConsumer_account_good_favoritesInput = {
where?: Prisma.ConsumerAccountWhereInput
data: Prisma.XOR<Prisma.ConsumerAccountUpdateWithoutConsumer_account_good_favoritesInput, Prisma.ConsumerAccountUncheckedUpdateWithoutConsumer_account_good_favoritesInput>
}
export type ConsumerAccountUpdateWithoutConsumer_account_good_favoritesInput = {
id?: Prisma.StringFieldUpdateOperationsInput | string
role?: Prisma.EnumConsumerRoleFieldUpdateOperationsInput | $Enums.ConsumerRole
created_at?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updated_at?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
consumer?: Prisma.ConsumerUpdateOneRequiredWithoutAccountsNestedInput
account?: Prisma.AccountUpdateOneRequiredWithoutConsumer_accountNestedInput
pos?: Prisma.PosUpdateOneWithoutAccountNestedInput
permission?: Prisma.PermissionConsumerUpdateOneWithoutConsumer_accountNestedInput
account_allocation?: Prisma.LicenseAccountAllocationUpdateOneWithoutAccountNestedInput
account_device?: Prisma.ConsumerAccountDeviceUpdateOneWithoutConsumer_accountNestedInput
sales_invoices?: Prisma.SalesInvoiceUpdateManyWithoutConsumer_accountNestedInput
}
export type ConsumerAccountUncheckedUpdateWithoutConsumer_account_good_favoritesInput = {
id?: Prisma.StringFieldUpdateOperationsInput | string
role?: Prisma.EnumConsumerRoleFieldUpdateOperationsInput | $Enums.ConsumerRole
created_at?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updated_at?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
consumer_id?: Prisma.StringFieldUpdateOperationsInput | string
account_id?: Prisma.StringFieldUpdateOperationsInput | string
pos?: Prisma.PosUncheckedUpdateOneWithoutAccountNestedInput
permission?: Prisma.PermissionConsumerUncheckedUpdateOneWithoutConsumer_accountNestedInput
account_allocation?: Prisma.LicenseAccountAllocationUncheckedUpdateOneWithoutAccountNestedInput
account_device?: Prisma.ConsumerAccountDeviceUncheckedUpdateOneWithoutConsumer_accountNestedInput
sales_invoices?: Prisma.SalesInvoiceUncheckedUpdateManyWithoutConsumer_accountNestedInput
}
export type ConsumerAccountCreateWithoutSales_invoicesInput = {
@@ -958,6 +1073,7 @@ export type ConsumerAccountCreateWithoutSales_invoicesInput = {
permission?: Prisma.PermissionConsumerCreateNestedOneWithoutConsumer_accountInput
account_allocation?: Prisma.LicenseAccountAllocationCreateNestedOneWithoutAccountInput
account_device?: Prisma.ConsumerAccountDeviceCreateNestedOneWithoutConsumer_accountInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteCreateNestedManyWithoutConsumer_accountInput
}
export type ConsumerAccountUncheckedCreateWithoutSales_invoicesInput = {
@@ -971,6 +1087,7 @@ export type ConsumerAccountUncheckedCreateWithoutSales_invoicesInput = {
permission?: Prisma.PermissionConsumerUncheckedCreateNestedOneWithoutConsumer_accountInput
account_allocation?: Prisma.LicenseAccountAllocationUncheckedCreateNestedOneWithoutAccountInput
account_device?: Prisma.ConsumerAccountDeviceUncheckedCreateNestedOneWithoutConsumer_accountInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteUncheckedCreateNestedManyWithoutConsumer_accountInput
}
export type ConsumerAccountCreateOrConnectWithoutSales_invoicesInput = {
@@ -1000,6 +1117,7 @@ export type ConsumerAccountUpdateWithoutSales_invoicesInput = {
permission?: Prisma.PermissionConsumerUpdateOneWithoutConsumer_accountNestedInput
account_allocation?: Prisma.LicenseAccountAllocationUpdateOneWithoutAccountNestedInput
account_device?: Prisma.ConsumerAccountDeviceUpdateOneWithoutConsumer_accountNestedInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteUpdateManyWithoutConsumer_accountNestedInput
}
export type ConsumerAccountUncheckedUpdateWithoutSales_invoicesInput = {
@@ -1013,6 +1131,7 @@ export type ConsumerAccountUncheckedUpdateWithoutSales_invoicesInput = {
permission?: Prisma.PermissionConsumerUncheckedUpdateOneWithoutConsumer_accountNestedInput
account_allocation?: Prisma.LicenseAccountAllocationUncheckedUpdateOneWithoutAccountNestedInput
account_device?: Prisma.ConsumerAccountDeviceUncheckedUpdateOneWithoutConsumer_accountNestedInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteUncheckedUpdateManyWithoutConsumer_accountNestedInput
}
export type ConsumerAccountCreateManyConsumerInput = {
@@ -1032,8 +1151,9 @@ export type ConsumerAccountUpdateWithoutConsumerInput = {
pos?: Prisma.PosUpdateOneWithoutAccountNestedInput
permission?: Prisma.PermissionConsumerUpdateOneWithoutConsumer_accountNestedInput
account_allocation?: Prisma.LicenseAccountAllocationUpdateOneWithoutAccountNestedInput
sales_invoices?: Prisma.SalesInvoiceUpdateManyWithoutConsumer_accountNestedInput
account_device?: Prisma.ConsumerAccountDeviceUpdateOneWithoutConsumer_accountNestedInput
sales_invoices?: Prisma.SalesInvoiceUpdateManyWithoutConsumer_accountNestedInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteUpdateManyWithoutConsumer_accountNestedInput
}
export type ConsumerAccountUncheckedUpdateWithoutConsumerInput = {
@@ -1045,8 +1165,9 @@ export type ConsumerAccountUncheckedUpdateWithoutConsumerInput = {
pos?: Prisma.PosUncheckedUpdateOneWithoutAccountNestedInput
permission?: Prisma.PermissionConsumerUncheckedUpdateOneWithoutConsumer_accountNestedInput
account_allocation?: Prisma.LicenseAccountAllocationUncheckedUpdateOneWithoutAccountNestedInput
sales_invoices?: Prisma.SalesInvoiceUncheckedUpdateManyWithoutConsumer_accountNestedInput
account_device?: Prisma.ConsumerAccountDeviceUncheckedUpdateOneWithoutConsumer_accountNestedInput
sales_invoices?: Prisma.SalesInvoiceUncheckedUpdateManyWithoutConsumer_accountNestedInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteUncheckedUpdateManyWithoutConsumer_accountNestedInput
}
export type ConsumerAccountUncheckedUpdateManyWithoutConsumerInput = {
@@ -1064,10 +1185,12 @@ export type ConsumerAccountUncheckedUpdateManyWithoutConsumerInput = {
export type ConsumerAccountCountOutputType = {
sales_invoices: number
consumer_account_good_favorites: number
}
export type ConsumerAccountCountOutputTypeSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
sales_invoices?: boolean | ConsumerAccountCountOutputTypeCountSales_invoicesArgs
consumer_account_good_favorites?: boolean | ConsumerAccountCountOutputTypeCountConsumer_account_good_favoritesArgs
}
/**
@@ -1087,6 +1210,13 @@ export type ConsumerAccountCountOutputTypeCountSales_invoicesArgs<ExtArgs extend
where?: Prisma.SalesInvoiceWhereInput
}
/**
* ConsumerAccountCountOutputType without action
*/
export type ConsumerAccountCountOutputTypeCountConsumer_account_good_favoritesArgs<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
where?: Prisma.ConsumerAccountGoodFavoriteWhereInput
}
export type ConsumerAccountSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetSelect<{
id?: boolean
@@ -1100,8 +1230,9 @@ export type ConsumerAccountSelect<ExtArgs extends runtime.Types.Extensions.Inter
pos?: boolean | Prisma.ConsumerAccount$posArgs<ExtArgs>
permission?: boolean | Prisma.ConsumerAccount$permissionArgs<ExtArgs>
account_allocation?: boolean | Prisma.ConsumerAccount$account_allocationArgs<ExtArgs>
sales_invoices?: boolean | Prisma.ConsumerAccount$sales_invoicesArgs<ExtArgs>
account_device?: boolean | Prisma.ConsumerAccount$account_deviceArgs<ExtArgs>
sales_invoices?: boolean | Prisma.ConsumerAccount$sales_invoicesArgs<ExtArgs>
consumer_account_good_favorites?: boolean | Prisma.ConsumerAccount$consumer_account_good_favoritesArgs<ExtArgs>
_count?: boolean | Prisma.ConsumerAccountCountOutputTypeDefaultArgs<ExtArgs>
}, ExtArgs["result"]["consumerAccount"]>
@@ -1123,8 +1254,9 @@ export type ConsumerAccountInclude<ExtArgs extends runtime.Types.Extensions.Inte
pos?: boolean | Prisma.ConsumerAccount$posArgs<ExtArgs>
permission?: boolean | Prisma.ConsumerAccount$permissionArgs<ExtArgs>
account_allocation?: boolean | Prisma.ConsumerAccount$account_allocationArgs<ExtArgs>
sales_invoices?: boolean | Prisma.ConsumerAccount$sales_invoicesArgs<ExtArgs>
account_device?: boolean | Prisma.ConsumerAccount$account_deviceArgs<ExtArgs>
sales_invoices?: boolean | Prisma.ConsumerAccount$sales_invoicesArgs<ExtArgs>
consumer_account_good_favorites?: boolean | Prisma.ConsumerAccount$consumer_account_good_favoritesArgs<ExtArgs>
_count?: boolean | Prisma.ConsumerAccountCountOutputTypeDefaultArgs<ExtArgs>
}
@@ -1136,8 +1268,9 @@ export type $ConsumerAccountPayload<ExtArgs extends runtime.Types.Extensions.Int
pos: Prisma.$PosPayload<ExtArgs> | null
permission: Prisma.$PermissionConsumerPayload<ExtArgs> | null
account_allocation: Prisma.$LicenseAccountAllocationPayload<ExtArgs> | null
sales_invoices: Prisma.$SalesInvoicePayload<ExtArgs>[]
account_device: Prisma.$ConsumerAccountDevicePayload<ExtArgs> | null
sales_invoices: Prisma.$SalesInvoicePayload<ExtArgs>[]
consumer_account_good_favorites: Prisma.$ConsumerAccountGoodFavoritePayload<ExtArgs>[]
}
scalars: runtime.Types.Extensions.GetPayloadResult<{
id: string
@@ -1491,8 +1624,9 @@ export interface Prisma__ConsumerAccountClient<T, Null = never, ExtArgs extends
pos<T extends Prisma.ConsumerAccount$posArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.ConsumerAccount$posArgs<ExtArgs>>): Prisma.Prisma__PosClient<runtime.Types.Result.GetResult<Prisma.$PosPayload<ExtArgs>, T, "findUniqueOrThrow", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions>
permission<T extends Prisma.ConsumerAccount$permissionArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.ConsumerAccount$permissionArgs<ExtArgs>>): Prisma.Prisma__PermissionConsumerClient<runtime.Types.Result.GetResult<Prisma.$PermissionConsumerPayload<ExtArgs>, T, "findUniqueOrThrow", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions>
account_allocation<T extends Prisma.ConsumerAccount$account_allocationArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.ConsumerAccount$account_allocationArgs<ExtArgs>>): Prisma.Prisma__LicenseAccountAllocationClient<runtime.Types.Result.GetResult<Prisma.$LicenseAccountAllocationPayload<ExtArgs>, T, "findUniqueOrThrow", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions>
sales_invoices<T extends Prisma.ConsumerAccount$sales_invoicesArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.ConsumerAccount$sales_invoicesArgs<ExtArgs>>): Prisma.PrismaPromise<runtime.Types.Result.GetResult<Prisma.$SalesInvoicePayload<ExtArgs>, T, "findMany", GlobalOmitOptions> | Null>
account_device<T extends Prisma.ConsumerAccount$account_deviceArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.ConsumerAccount$account_deviceArgs<ExtArgs>>): Prisma.Prisma__ConsumerAccountDeviceClient<runtime.Types.Result.GetResult<Prisma.$ConsumerAccountDevicePayload<ExtArgs>, T, "findUniqueOrThrow", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions>
sales_invoices<T extends Prisma.ConsumerAccount$sales_invoicesArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.ConsumerAccount$sales_invoicesArgs<ExtArgs>>): Prisma.PrismaPromise<runtime.Types.Result.GetResult<Prisma.$SalesInvoicePayload<ExtArgs>, T, "findMany", GlobalOmitOptions> | Null>
consumer_account_good_favorites<T extends Prisma.ConsumerAccount$consumer_account_good_favoritesArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.ConsumerAccount$consumer_account_good_favoritesArgs<ExtArgs>>): Prisma.PrismaPromise<runtime.Types.Result.GetResult<Prisma.$ConsumerAccountGoodFavoritePayload<ExtArgs>, T, "findMany", GlobalOmitOptions> | Null>
/**
* Attaches callbacks for the resolution and/or rejection of the Promise.
* @param onfulfilled The callback to execute when the Promise is resolved.
@@ -1932,6 +2066,25 @@ export type ConsumerAccount$account_allocationArgs<ExtArgs extends runtime.Types
where?: Prisma.LicenseAccountAllocationWhereInput
}
/**
* ConsumerAccount.account_device
*/
export type ConsumerAccount$account_deviceArgs<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
/**
* Select specific fields to fetch from the ConsumerAccountDevice
*/
select?: Prisma.ConsumerAccountDeviceSelect<ExtArgs> | null
/**
* Omit specific fields from the ConsumerAccountDevice
*/
omit?: Prisma.ConsumerAccountDeviceOmit<ExtArgs> | null
/**
* Choose, which related nodes to fetch as well
*/
include?: Prisma.ConsumerAccountDeviceInclude<ExtArgs> | null
where?: Prisma.ConsumerAccountDeviceWhereInput
}
/**
* ConsumerAccount.sales_invoices
*/
@@ -1957,22 +2110,27 @@ export type ConsumerAccount$sales_invoicesArgs<ExtArgs extends runtime.Types.Ext
}
/**
* ConsumerAccount.account_device
* ConsumerAccount.consumer_account_good_favorites
*/
export type ConsumerAccount$account_deviceArgs<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
export type ConsumerAccount$consumer_account_good_favoritesArgs<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
/**
* Select specific fields to fetch from the ConsumerAccountDevice
* Select specific fields to fetch from the ConsumerAccountGoodFavorite
*/
select?: Prisma.ConsumerAccountDeviceSelect<ExtArgs> | null
select?: Prisma.ConsumerAccountGoodFavoriteSelect<ExtArgs> | null
/**
* Omit specific fields from the ConsumerAccountDevice
* Omit specific fields from the ConsumerAccountGoodFavorite
*/
omit?: Prisma.ConsumerAccountDeviceOmit<ExtArgs> | null
omit?: Prisma.ConsumerAccountGoodFavoriteOmit<ExtArgs> | null
/**
* Choose, which related nodes to fetch as well
*/
include?: Prisma.ConsumerAccountDeviceInclude<ExtArgs> | null
where?: Prisma.ConsumerAccountDeviceWhereInput
include?: Prisma.ConsumerAccountGoodFavoriteInclude<ExtArgs> | null
where?: Prisma.ConsumerAccountGoodFavoriteWhereInput
orderBy?: Prisma.ConsumerAccountGoodFavoriteOrderByWithRelationInput | Prisma.ConsumerAccountGoodFavoriteOrderByWithRelationInput[]
cursor?: Prisma.ConsumerAccountGoodFavoriteWhereUniqueInput
take?: number
skip?: number
distinct?: Prisma.ConsumerAccountGoodFavoriteScalarFieldEnum | Prisma.ConsumerAccountGoodFavoriteScalarFieldEnum[]
}
/**
File diff suppressed because it is too large Load Diff
+179 -5
View File
@@ -309,6 +309,7 @@ export type GoodWhereInput = {
category?: Prisma.XOR<Prisma.GoodCategoryNullableScalarRelationFilter, Prisma.GoodCategoryWhereInput> | null
business_activity?: Prisma.XOR<Prisma.BusinessActivityNullableScalarRelationFilter, Prisma.BusinessActivityWhereInput> | null
sales_invoice_items?: Prisma.SalesInvoiceItemListRelationFilter
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteListRelationFilter
}
export type GoodOrderByWithRelationInput = {
@@ -333,6 +334,7 @@ export type GoodOrderByWithRelationInput = {
category?: Prisma.GoodCategoryOrderByWithRelationInput
business_activity?: Prisma.BusinessActivityOrderByWithRelationInput
sales_invoice_items?: Prisma.SalesInvoiceItemOrderByRelationAggregateInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteOrderByRelationAggregateInput
_relevance?: Prisma.GoodOrderByRelevanceInput
}
@@ -361,6 +363,7 @@ export type GoodWhereUniqueInput = Prisma.AtLeast<{
category?: Prisma.XOR<Prisma.GoodCategoryNullableScalarRelationFilter, Prisma.GoodCategoryWhereInput> | null
business_activity?: Prisma.XOR<Prisma.BusinessActivityNullableScalarRelationFilter, Prisma.BusinessActivityWhereInput> | null
sales_invoice_items?: Prisma.SalesInvoiceItemListRelationFilter
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteListRelationFilter
}, "id" | "local_sku" | "barcode">
export type GoodOrderByWithAggregationInput = {
@@ -427,6 +430,7 @@ export type GoodCreateInput = {
category?: Prisma.GoodCategoryCreateNestedOneWithoutGoodsInput
business_activity?: Prisma.BusinessActivityCreateNestedOneWithoutGoodsInput
sales_invoice_items?: Prisma.SalesInvoiceItemCreateNestedManyWithoutGoodInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteCreateNestedManyWithoutGoodInput
}
export type GoodUncheckedCreateInput = {
@@ -447,6 +451,7 @@ export type GoodUncheckedCreateInput = {
category_id?: string | null
business_activity_id?: string | null
sales_invoice_items?: Prisma.SalesInvoiceItemUncheckedCreateNestedManyWithoutGoodInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteUncheckedCreateNestedManyWithoutGoodInput
}
export type GoodUpdateInput = {
@@ -467,6 +472,7 @@ export type GoodUpdateInput = {
category?: Prisma.GoodCategoryUpdateOneWithoutGoodsNestedInput
business_activity?: Prisma.BusinessActivityUpdateOneWithoutGoodsNestedInput
sales_invoice_items?: Prisma.SalesInvoiceItemUpdateManyWithoutGoodNestedInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteUpdateManyWithoutGoodNestedInput
}
export type GoodUncheckedUpdateInput = {
@@ -487,6 +493,7 @@ export type GoodUncheckedUpdateInput = {
category_id?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
business_activity_id?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
sales_invoice_items?: Prisma.SalesInvoiceItemUncheckedUpdateManyWithoutGoodNestedInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteUncheckedUpdateManyWithoutGoodNestedInput
}
export type GoodCreateManyInput = {
@@ -552,6 +559,11 @@ export type GoodOrderByRelationAggregateInput = {
_count?: Prisma.SortOrder
}
export type GoodScalarRelationFilter = {
is?: Prisma.GoodWhereInput
isNot?: Prisma.GoodWhereInput
}
export type GoodOrderByRelevanceInput = {
fields: Prisma.GoodOrderByRelevanceFieldEnum | Prisma.GoodOrderByRelevanceFieldEnum[]
sort: Prisma.SortOrder
@@ -623,11 +635,6 @@ export type GoodSumOrderByAggregateInput = {
base_sale_price?: Prisma.SortOrder
}
export type GoodScalarRelationFilter = {
is?: Prisma.GoodWhereInput
isNot?: Prisma.GoodWhereInput
}
export type GoodCreateNestedManyWithoutBusiness_activityInput = {
create?: Prisma.XOR<Prisma.GoodCreateWithoutBusiness_activityInput, Prisma.GoodUncheckedCreateWithoutBusiness_activityInput> | Prisma.GoodCreateWithoutBusiness_activityInput[] | Prisma.GoodUncheckedCreateWithoutBusiness_activityInput[]
connectOrCreate?: Prisma.GoodCreateOrConnectWithoutBusiness_activityInput | Prisma.GoodCreateOrConnectWithoutBusiness_activityInput[]
@@ -670,6 +677,20 @@ export type GoodUncheckedUpdateManyWithoutBusiness_activityNestedInput = {
deleteMany?: Prisma.GoodScalarWhereInput | Prisma.GoodScalarWhereInput[]
}
export type GoodCreateNestedOneWithoutConsumer_account_good_favoritesInput = {
create?: Prisma.XOR<Prisma.GoodCreateWithoutConsumer_account_good_favoritesInput, Prisma.GoodUncheckedCreateWithoutConsumer_account_good_favoritesInput>
connectOrCreate?: Prisma.GoodCreateOrConnectWithoutConsumer_account_good_favoritesInput
connect?: Prisma.GoodWhereUniqueInput
}
export type GoodUpdateOneRequiredWithoutConsumer_account_good_favoritesNestedInput = {
create?: Prisma.XOR<Prisma.GoodCreateWithoutConsumer_account_good_favoritesInput, Prisma.GoodUncheckedCreateWithoutConsumer_account_good_favoritesInput>
connectOrCreate?: Prisma.GoodCreateOrConnectWithoutConsumer_account_good_favoritesInput
upsert?: Prisma.GoodUpsertWithoutConsumer_account_good_favoritesInput
connect?: Prisma.GoodWhereUniqueInput
update?: Prisma.XOR<Prisma.XOR<Prisma.GoodUpdateToOneWithWhereWithoutConsumer_account_good_favoritesInput, Prisma.GoodUpdateWithoutConsumer_account_good_favoritesInput>, Prisma.GoodUncheckedUpdateWithoutConsumer_account_good_favoritesInput>
}
export type EnumGoodPricingModelFieldUpdateOperationsInput = {
set?: $Enums.GoodPricingModel
}
@@ -843,6 +864,7 @@ export type GoodCreateWithoutBusiness_activityInput = {
measure_unit: Prisma.MeasureUnitsCreateNestedOneWithoutGoodsInput
category?: Prisma.GoodCategoryCreateNestedOneWithoutGoodsInput
sales_invoice_items?: Prisma.SalesInvoiceItemCreateNestedManyWithoutGoodInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteCreateNestedManyWithoutGoodInput
}
export type GoodUncheckedCreateWithoutBusiness_activityInput = {
@@ -862,6 +884,7 @@ export type GoodUncheckedCreateWithoutBusiness_activityInput = {
measure_unit_id: string
category_id?: string | null
sales_invoice_items?: Prisma.SalesInvoiceItemUncheckedCreateNestedManyWithoutGoodInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteUncheckedCreateNestedManyWithoutGoodInput
}
export type GoodCreateOrConnectWithoutBusiness_activityInput = {
@@ -912,6 +935,102 @@ export type GoodScalarWhereInput = {
business_activity_id?: Prisma.StringNullableFilter<"Good"> | string | null
}
export type GoodCreateWithoutConsumer_account_good_favoritesInput = {
id?: string
name: string
is_default_guild_good?: boolean
pricing_model: $Enums.GoodPricingModel
description?: string | null
local_sku?: string | null
barcode?: string | null
base_sale_price?: runtime.Decimal | runtime.DecimalJsLike | number | string | null
image_url?: string | null
created_at?: Date | string
updated_at?: Date | string
deleted_at?: Date | string | null
sku: Prisma.StockKeepingUnitsCreateNestedOneWithoutGoodsInput
measure_unit: Prisma.MeasureUnitsCreateNestedOneWithoutGoodsInput
category?: Prisma.GoodCategoryCreateNestedOneWithoutGoodsInput
business_activity?: Prisma.BusinessActivityCreateNestedOneWithoutGoodsInput
sales_invoice_items?: Prisma.SalesInvoiceItemCreateNestedManyWithoutGoodInput
}
export type GoodUncheckedCreateWithoutConsumer_account_good_favoritesInput = {
id?: string
name: string
is_default_guild_good?: boolean
pricing_model: $Enums.GoodPricingModel
description?: string | null
local_sku?: string | null
barcode?: string | null
base_sale_price?: runtime.Decimal | runtime.DecimalJsLike | number | string | null
image_url?: string | null
created_at?: Date | string
updated_at?: Date | string
deleted_at?: Date | string | null
sku_id: string
measure_unit_id: string
category_id?: string | null
business_activity_id?: string | null
sales_invoice_items?: Prisma.SalesInvoiceItemUncheckedCreateNestedManyWithoutGoodInput
}
export type GoodCreateOrConnectWithoutConsumer_account_good_favoritesInput = {
where: Prisma.GoodWhereUniqueInput
create: Prisma.XOR<Prisma.GoodCreateWithoutConsumer_account_good_favoritesInput, Prisma.GoodUncheckedCreateWithoutConsumer_account_good_favoritesInput>
}
export type GoodUpsertWithoutConsumer_account_good_favoritesInput = {
update: Prisma.XOR<Prisma.GoodUpdateWithoutConsumer_account_good_favoritesInput, Prisma.GoodUncheckedUpdateWithoutConsumer_account_good_favoritesInput>
create: Prisma.XOR<Prisma.GoodCreateWithoutConsumer_account_good_favoritesInput, Prisma.GoodUncheckedCreateWithoutConsumer_account_good_favoritesInput>
where?: Prisma.GoodWhereInput
}
export type GoodUpdateToOneWithWhereWithoutConsumer_account_good_favoritesInput = {
where?: Prisma.GoodWhereInput
data: Prisma.XOR<Prisma.GoodUpdateWithoutConsumer_account_good_favoritesInput, Prisma.GoodUncheckedUpdateWithoutConsumer_account_good_favoritesInput>
}
export type GoodUpdateWithoutConsumer_account_good_favoritesInput = {
id?: Prisma.StringFieldUpdateOperationsInput | string
name?: Prisma.StringFieldUpdateOperationsInput | string
is_default_guild_good?: Prisma.BoolFieldUpdateOperationsInput | boolean
pricing_model?: Prisma.EnumGoodPricingModelFieldUpdateOperationsInput | $Enums.GoodPricingModel
description?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
local_sku?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
barcode?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
base_sale_price?: Prisma.NullableDecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string | null
image_url?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
created_at?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updated_at?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
deleted_at?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
sku?: Prisma.StockKeepingUnitsUpdateOneRequiredWithoutGoodsNestedInput
measure_unit?: Prisma.MeasureUnitsUpdateOneRequiredWithoutGoodsNestedInput
category?: Prisma.GoodCategoryUpdateOneWithoutGoodsNestedInput
business_activity?: Prisma.BusinessActivityUpdateOneWithoutGoodsNestedInput
sales_invoice_items?: Prisma.SalesInvoiceItemUpdateManyWithoutGoodNestedInput
}
export type GoodUncheckedUpdateWithoutConsumer_account_good_favoritesInput = {
id?: Prisma.StringFieldUpdateOperationsInput | string
name?: Prisma.StringFieldUpdateOperationsInput | string
is_default_guild_good?: Prisma.BoolFieldUpdateOperationsInput | boolean
pricing_model?: Prisma.EnumGoodPricingModelFieldUpdateOperationsInput | $Enums.GoodPricingModel
description?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
local_sku?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
barcode?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
base_sale_price?: Prisma.NullableDecimalFieldUpdateOperationsInput | runtime.Decimal | runtime.DecimalJsLike | number | string | null
image_url?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
created_at?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
updated_at?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string
deleted_at?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null
sku_id?: Prisma.StringFieldUpdateOperationsInput | string
measure_unit_id?: Prisma.StringFieldUpdateOperationsInput | string
category_id?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
business_activity_id?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
sales_invoice_items?: Prisma.SalesInvoiceItemUncheckedUpdateManyWithoutGoodNestedInput
}
export type GoodCreateWithoutCategoryInput = {
id?: string
name: string
@@ -929,6 +1048,7 @@ export type GoodCreateWithoutCategoryInput = {
measure_unit: Prisma.MeasureUnitsCreateNestedOneWithoutGoodsInput
business_activity?: Prisma.BusinessActivityCreateNestedOneWithoutGoodsInput
sales_invoice_items?: Prisma.SalesInvoiceItemCreateNestedManyWithoutGoodInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteCreateNestedManyWithoutGoodInput
}
export type GoodUncheckedCreateWithoutCategoryInput = {
@@ -948,6 +1068,7 @@ export type GoodUncheckedCreateWithoutCategoryInput = {
measure_unit_id: string
business_activity_id?: string | null
sales_invoice_items?: Prisma.SalesInvoiceItemUncheckedCreateNestedManyWithoutGoodInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteUncheckedCreateNestedManyWithoutGoodInput
}
export type GoodCreateOrConnectWithoutCategoryInput = {
@@ -993,6 +1114,7 @@ export type GoodCreateWithoutMeasure_unitInput = {
category?: Prisma.GoodCategoryCreateNestedOneWithoutGoodsInput
business_activity?: Prisma.BusinessActivityCreateNestedOneWithoutGoodsInput
sales_invoice_items?: Prisma.SalesInvoiceItemCreateNestedManyWithoutGoodInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteCreateNestedManyWithoutGoodInput
}
export type GoodUncheckedCreateWithoutMeasure_unitInput = {
@@ -1012,6 +1134,7 @@ export type GoodUncheckedCreateWithoutMeasure_unitInput = {
category_id?: string | null
business_activity_id?: string | null
sales_invoice_items?: Prisma.SalesInvoiceItemUncheckedCreateNestedManyWithoutGoodInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteUncheckedCreateNestedManyWithoutGoodInput
}
export type GoodCreateOrConnectWithoutMeasure_unitInput = {
@@ -1057,6 +1180,7 @@ export type GoodCreateWithoutSkuInput = {
category?: Prisma.GoodCategoryCreateNestedOneWithoutGoodsInput
business_activity?: Prisma.BusinessActivityCreateNestedOneWithoutGoodsInput
sales_invoice_items?: Prisma.SalesInvoiceItemCreateNestedManyWithoutGoodInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteCreateNestedManyWithoutGoodInput
}
export type GoodUncheckedCreateWithoutSkuInput = {
@@ -1076,6 +1200,7 @@ export type GoodUncheckedCreateWithoutSkuInput = {
category_id?: string | null
business_activity_id?: string | null
sales_invoice_items?: Prisma.SalesInvoiceItemUncheckedCreateNestedManyWithoutGoodInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteUncheckedCreateNestedManyWithoutGoodInput
}
export type GoodCreateOrConnectWithoutSkuInput = {
@@ -1121,6 +1246,7 @@ export type GoodCreateWithoutSales_invoice_itemsInput = {
measure_unit: Prisma.MeasureUnitsCreateNestedOneWithoutGoodsInput
category?: Prisma.GoodCategoryCreateNestedOneWithoutGoodsInput
business_activity?: Prisma.BusinessActivityCreateNestedOneWithoutGoodsInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteCreateNestedManyWithoutGoodInput
}
export type GoodUncheckedCreateWithoutSales_invoice_itemsInput = {
@@ -1140,6 +1266,7 @@ export type GoodUncheckedCreateWithoutSales_invoice_itemsInput = {
measure_unit_id: string
category_id?: string | null
business_activity_id?: string | null
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteUncheckedCreateNestedManyWithoutGoodInput
}
export type GoodCreateOrConnectWithoutSales_invoice_itemsInput = {
@@ -1175,6 +1302,7 @@ export type GoodUpdateWithoutSales_invoice_itemsInput = {
measure_unit?: Prisma.MeasureUnitsUpdateOneRequiredWithoutGoodsNestedInput
category?: Prisma.GoodCategoryUpdateOneWithoutGoodsNestedInput
business_activity?: Prisma.BusinessActivityUpdateOneWithoutGoodsNestedInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteUpdateManyWithoutGoodNestedInput
}
export type GoodUncheckedUpdateWithoutSales_invoice_itemsInput = {
@@ -1194,6 +1322,7 @@ export type GoodUncheckedUpdateWithoutSales_invoice_itemsInput = {
measure_unit_id?: Prisma.StringFieldUpdateOperationsInput | string
category_id?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
business_activity_id?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteUncheckedUpdateManyWithoutGoodNestedInput
}
export type GoodCreateManyBusiness_activityInput = {
@@ -1231,6 +1360,7 @@ export type GoodUpdateWithoutBusiness_activityInput = {
measure_unit?: Prisma.MeasureUnitsUpdateOneRequiredWithoutGoodsNestedInput
category?: Prisma.GoodCategoryUpdateOneWithoutGoodsNestedInput
sales_invoice_items?: Prisma.SalesInvoiceItemUpdateManyWithoutGoodNestedInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteUpdateManyWithoutGoodNestedInput
}
export type GoodUncheckedUpdateWithoutBusiness_activityInput = {
@@ -1250,6 +1380,7 @@ export type GoodUncheckedUpdateWithoutBusiness_activityInput = {
measure_unit_id?: Prisma.StringFieldUpdateOperationsInput | string
category_id?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
sales_invoice_items?: Prisma.SalesInvoiceItemUncheckedUpdateManyWithoutGoodNestedInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteUncheckedUpdateManyWithoutGoodNestedInput
}
export type GoodUncheckedUpdateManyWithoutBusiness_activityInput = {
@@ -1305,6 +1436,7 @@ export type GoodUpdateWithoutCategoryInput = {
measure_unit?: Prisma.MeasureUnitsUpdateOneRequiredWithoutGoodsNestedInput
business_activity?: Prisma.BusinessActivityUpdateOneWithoutGoodsNestedInput
sales_invoice_items?: Prisma.SalesInvoiceItemUpdateManyWithoutGoodNestedInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteUpdateManyWithoutGoodNestedInput
}
export type GoodUncheckedUpdateWithoutCategoryInput = {
@@ -1324,6 +1456,7 @@ export type GoodUncheckedUpdateWithoutCategoryInput = {
measure_unit_id?: Prisma.StringFieldUpdateOperationsInput | string
business_activity_id?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
sales_invoice_items?: Prisma.SalesInvoiceItemUncheckedUpdateManyWithoutGoodNestedInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteUncheckedUpdateManyWithoutGoodNestedInput
}
export type GoodUncheckedUpdateManyWithoutCategoryInput = {
@@ -1379,6 +1512,7 @@ export type GoodUpdateWithoutMeasure_unitInput = {
category?: Prisma.GoodCategoryUpdateOneWithoutGoodsNestedInput
business_activity?: Prisma.BusinessActivityUpdateOneWithoutGoodsNestedInput
sales_invoice_items?: Prisma.SalesInvoiceItemUpdateManyWithoutGoodNestedInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteUpdateManyWithoutGoodNestedInput
}
export type GoodUncheckedUpdateWithoutMeasure_unitInput = {
@@ -1398,6 +1532,7 @@ export type GoodUncheckedUpdateWithoutMeasure_unitInput = {
category_id?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
business_activity_id?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
sales_invoice_items?: Prisma.SalesInvoiceItemUncheckedUpdateManyWithoutGoodNestedInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteUncheckedUpdateManyWithoutGoodNestedInput
}
export type GoodUncheckedUpdateManyWithoutMeasure_unitInput = {
@@ -1453,6 +1588,7 @@ export type GoodUpdateWithoutSkuInput = {
category?: Prisma.GoodCategoryUpdateOneWithoutGoodsNestedInput
business_activity?: Prisma.BusinessActivityUpdateOneWithoutGoodsNestedInput
sales_invoice_items?: Prisma.SalesInvoiceItemUpdateManyWithoutGoodNestedInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteUpdateManyWithoutGoodNestedInput
}
export type GoodUncheckedUpdateWithoutSkuInput = {
@@ -1472,6 +1608,7 @@ export type GoodUncheckedUpdateWithoutSkuInput = {
category_id?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
business_activity_id?: Prisma.NullableStringFieldUpdateOperationsInput | string | null
sales_invoice_items?: Prisma.SalesInvoiceItemUncheckedUpdateManyWithoutGoodNestedInput
consumer_account_good_favorites?: Prisma.ConsumerAccountGoodFavoriteUncheckedUpdateManyWithoutGoodNestedInput
}
export type GoodUncheckedUpdateManyWithoutSkuInput = {
@@ -1499,10 +1636,12 @@ export type GoodUncheckedUpdateManyWithoutSkuInput = {
export type GoodCountOutputType = {
sales_invoice_items: number
consumer_account_good_favorites: number
}
export type GoodCountOutputTypeSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
sales_invoice_items?: boolean | GoodCountOutputTypeCountSales_invoice_itemsArgs
consumer_account_good_favorites?: boolean | GoodCountOutputTypeCountConsumer_account_good_favoritesArgs
}
/**
@@ -1522,6 +1661,13 @@ export type GoodCountOutputTypeCountSales_invoice_itemsArgs<ExtArgs extends runt
where?: Prisma.SalesInvoiceItemWhereInput
}
/**
* GoodCountOutputType without action
*/
export type GoodCountOutputTypeCountConsumer_account_good_favoritesArgs<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
where?: Prisma.ConsumerAccountGoodFavoriteWhereInput
}
export type GoodSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetSelect<{
id?: boolean
@@ -1545,6 +1691,7 @@ export type GoodSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = r
category?: boolean | Prisma.Good$categoryArgs<ExtArgs>
business_activity?: boolean | Prisma.Good$business_activityArgs<ExtArgs>
sales_invoice_items?: boolean | Prisma.Good$sales_invoice_itemsArgs<ExtArgs>
consumer_account_good_favorites?: boolean | Prisma.Good$consumer_account_good_favoritesArgs<ExtArgs>
_count?: boolean | Prisma.GoodCountOutputTypeDefaultArgs<ExtArgs>
}, ExtArgs["result"]["good"]>
@@ -1576,6 +1723,7 @@ export type GoodInclude<ExtArgs extends runtime.Types.Extensions.InternalArgs =
category?: boolean | Prisma.Good$categoryArgs<ExtArgs>
business_activity?: boolean | Prisma.Good$business_activityArgs<ExtArgs>
sales_invoice_items?: boolean | Prisma.Good$sales_invoice_itemsArgs<ExtArgs>
consumer_account_good_favorites?: boolean | Prisma.Good$consumer_account_good_favoritesArgs<ExtArgs>
_count?: boolean | Prisma.GoodCountOutputTypeDefaultArgs<ExtArgs>
}
@@ -1587,6 +1735,7 @@ export type $GoodPayload<ExtArgs extends runtime.Types.Extensions.InternalArgs =
category: Prisma.$GoodCategoryPayload<ExtArgs> | null
business_activity: Prisma.$BusinessActivityPayload<ExtArgs> | null
sales_invoice_items: Prisma.$SalesInvoiceItemPayload<ExtArgs>[]
consumer_account_good_favorites: Prisma.$ConsumerAccountGoodFavoritePayload<ExtArgs>[]
}
scalars: runtime.Types.Extensions.GetPayloadResult<{
id: string
@@ -1950,6 +2099,7 @@ export interface Prisma__GoodClient<T, Null = never, ExtArgs extends runtime.Typ
category<T extends Prisma.Good$categoryArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.Good$categoryArgs<ExtArgs>>): Prisma.Prisma__GoodCategoryClient<runtime.Types.Result.GetResult<Prisma.$GoodCategoryPayload<ExtArgs>, T, "findUniqueOrThrow", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions>
business_activity<T extends Prisma.Good$business_activityArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.Good$business_activityArgs<ExtArgs>>): Prisma.Prisma__BusinessActivityClient<runtime.Types.Result.GetResult<Prisma.$BusinessActivityPayload<ExtArgs>, T, "findUniqueOrThrow", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions>
sales_invoice_items<T extends Prisma.Good$sales_invoice_itemsArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.Good$sales_invoice_itemsArgs<ExtArgs>>): Prisma.PrismaPromise<runtime.Types.Result.GetResult<Prisma.$SalesInvoiceItemPayload<ExtArgs>, T, "findMany", GlobalOmitOptions> | Null>
consumer_account_good_favorites<T extends Prisma.Good$consumer_account_good_favoritesArgs<ExtArgs> = {}>(args?: Prisma.Subset<T, Prisma.Good$consumer_account_good_favoritesArgs<ExtArgs>>): Prisma.PrismaPromise<runtime.Types.Result.GetResult<Prisma.$ConsumerAccountGoodFavoritePayload<ExtArgs>, T, "findMany", GlobalOmitOptions> | Null>
/**
* Attaches callbacks for the resolution and/or rejection of the Promise.
* @param onfulfilled The callback to execute when the Promise is resolved.
@@ -2404,6 +2554,30 @@ export type Good$sales_invoice_itemsArgs<ExtArgs extends runtime.Types.Extension
distinct?: Prisma.SalesInvoiceItemScalarFieldEnum | Prisma.SalesInvoiceItemScalarFieldEnum[]
}
/**
* Good.consumer_account_good_favorites
*/
export type Good$consumer_account_good_favoritesArgs<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
/**
* Select specific fields to fetch from the ConsumerAccountGoodFavorite
*/
select?: Prisma.ConsumerAccountGoodFavoriteSelect<ExtArgs> | null
/**
* Omit specific fields from the ConsumerAccountGoodFavorite
*/
omit?: Prisma.ConsumerAccountGoodFavoriteOmit<ExtArgs> | null
/**
* Choose, which related nodes to fetch as well
*/
include?: Prisma.ConsumerAccountGoodFavoriteInclude<ExtArgs> | null
where?: Prisma.ConsumerAccountGoodFavoriteWhereInput
orderBy?: Prisma.ConsumerAccountGoodFavoriteOrderByWithRelationInput | Prisma.ConsumerAccountGoodFavoriteOrderByWithRelationInput[]
cursor?: Prisma.ConsumerAccountGoodFavoriteWhereUniqueInput
take?: number
skip?: number
distinct?: Prisma.ConsumerAccountGoodFavoriteScalarFieldEnum | Prisma.ConsumerAccountGoodFavoriteScalarFieldEnum[]
}
/**
* Good without action
*/
@@ -1,13 +1,16 @@
import { PasswordFieldValidator, UsernameFieldValidator } from '@/common/utils'
import { ApiProperty, PartialType } from '@nestjs/swagger'
import { IsEnum, IsOptional, IsString } from 'class-validator'
import { AccountStatus, ConsumerRole } from 'generated/prisma/enums'
export class CreateConsumerAccountDto {
@IsString()
@UsernameFieldValidator()
@ApiProperty({ required: true })
username: string
@IsString()
@PasswordFieldValidator()
@ApiProperty({ required: true })
password: string
@@ -1,3 +1,4 @@
import { PasswordFieldValidator, UsernameFieldValidator } from '@/common/utils'
import { ConsumerStatus } from '@/generated/prisma/enums'
import { ApiProperty, OmitType, PartialType } from '@nestjs/swagger'
import { IsEnum, IsOptional, IsString } from 'class-validator'
@@ -16,10 +17,12 @@ export class CreateConsumerDto {
last_name: string
@IsString()
@UsernameFieldValidator()
@ApiProperty({ required: true })
username: string
@IsString()
@PasswordFieldValidator()
@ApiProperty({ required: true })
password: string
@@ -12,6 +12,6 @@ export class AdminGuildCacheInvalidationService {
async invalidateGoodsList(guildId: string): Promise<void> {
await this.redisService.delete(RedisKeyMaker.guildGoodsList(guildId))
await this.posCacheInvalidationService.invalidateGoodsListByGuild(guildId)
await this.posCacheInvalidationService.invalidatePosGoodsByGuildPattern(guildId)
}
}
@@ -39,8 +39,12 @@ export class GoodsController {
},
},
})
create(@Body() data: CreateGuildGoodDto, @UploadedFile() file: Express.Multer.File) {
return this.goodsService.create(data, file)
create(
@Param('guildId') guildId: string,
@Body() data: CreateGuildGoodDto,
@UploadedFile() file: Express.Multer.File,
) {
return this.goodsService.create(guildId, data, file)
}
@Patch(':id')
@@ -55,10 +59,11 @@ export class GoodsController {
},
})
update(
@Param('guildId') guildId: string,
@Param('id') id: string,
@Body() data: UpdateGuildGoodDto,
@UploadedFile() file: Express.Multer.File,
) {
return this.goodsService.update(id, data, file)
return this.goodsService.update(guildId, id, data, file)
}
}
+16 -41
View File
@@ -57,13 +57,10 @@ export class GoodsService {
async findAll(guildId: string) {
const cacheKey = RedisKeyMaker.guildGoodsList(guildId)
const cached = await this.redisService.getJson<{ goods: unknown[]; total: number }>(
return this.redisService.getAndSet(
cacheKey,
)
if (cached) {
return ResponseMapper.paginate(cached.goods, { total: cached.total })
}
'paginate',
async () => {
const [goods, total] = await this.prisma.$transaction([
this.prisma.good.findMany({
where: this.defaultWhere(guildId),
@@ -72,11 +69,10 @@ export class GoodsService {
this.prisma.good.count(),
])
await this.redisService.setJson(cacheKey, { goods, total }, this.listCacheTtlSeconds)
return ResponseMapper.paginate(goods, {
total,
})
return { items: goods, total }
},
this.listCacheTtlSeconds,
)
}
async findOne(guild_id: string, id: string) {
@@ -91,12 +87,8 @@ export class GoodsService {
return ResponseMapper.single(good)
}
async create(data: CreateGuildGoodDto, file: Express.Multer.File) {
async create(guildId: string, data: CreateGuildGoodDto, file: Express.Multer.File) {
const { category_id, measure_unit_id, sku_id, ...rest } = data
const category = await this.prisma.goodCategory.findUnique({
where: { id: category_id },
select: { guild_id: true },
})
const good = await this.prisma.$transaction(async tx => {
let image_url = ''
@@ -133,28 +125,21 @@ export class GoodsService {
})
})
if (category?.guild_id) {
await this.cacheInvalidationService.invalidateGoodsList(category.guild_id)
}
await this.cacheInvalidationService.invalidateGoodsList(guildId)
return ResponseMapper.create(good)
}
async update(id: string, data: UpdateGuildGoodDto, file: Express.Multer.File) {
async update(
guildId: string,
id: string,
data: UpdateGuildGoodDto,
file: Express.Multer.File,
) {
const { category_id, measure_unit_id, sku_id, ...rest } = data
const prevGood = await this.prisma.good.findUnique({
where: { id },
select: { category: { select: { guild_id: true } } },
})
const nextCategory = category_id
? await this.prisma.goodCategory.findUnique({
where: { id: category_id },
select: { guild_id: true },
})
: null
const good = await this.prisma.$transaction(async tx => {
let image_url = ''
let image_url = undefined as string | undefined
if (file) {
const uploadedUrl = await this.uploaderService.uploadFile(
file,
@@ -198,17 +183,7 @@ export class GoodsService {
})
})
const cacheGuildIds = new Set<string>()
if (prevGood?.category?.guild_id) {
cacheGuildIds.add(prevGood.category.guild_id)
}
if (nextCategory?.guild_id) {
cacheGuildIds.add(nextCategory.guild_id)
}
for (const guildId of cacheGuildIds) {
await this.cacheInvalidationService.invalidateGoodsList(guildId)
}
return ResponseMapper.create(good)
}
@@ -31,20 +31,20 @@ export class StockKeepingUnitsService {
async findAll(guild_id: string) {
const cacheKey = this.getListCacheKey(guild_id)
const cached = await this.redisService.getJson<unknown[]>(cacheKey)
if (cached) {
return ResponseMapper.list(cached)
}
return await this.redisService.getAndSet(
cacheKey,
'list',
async () => {
const items = await this.prisma.stockKeepingUnits.findMany({
where: { guild_id },
orderBy: { created_at: 'desc' },
})
const mappedData = items.map(this.mapData)
await this.redisService.setJson(cacheKey, mappedData, this.listCacheTtlSeconds)
return ResponseMapper.list(mappedData)
return mappedData
},
this.listCacheTtlSeconds,
)
}
async create(guild_id: string, data: CreateStockKeepingUnitDto) {
@@ -17,14 +17,6 @@ export class PartnerActivatedLicensesService {
) {}
async findAll(partner_id: string, page = 1, perPage = 10) {
const cacheKey = RedisKeyMaker.partnerActivatedLicensesList(partner_id, page, perPage)
const cached = await this.redisService.getJson<{ data: unknown[]; total: number }>(
cacheKey,
)
if (cached) {
return ResponseMapper.paginate(cached.data, { page, perPage, total: cached.total })
}
const defaultWhere: LicenseActivationWhereInput = {
license: {
charge_transaction: {
@@ -32,6 +24,8 @@ export class PartnerActivatedLicensesService {
},
},
}
const cacheKey = RedisKeyMaker.partnerActivatedLicensesList(partner_id, page, perPage)
return await this.redisService.getAndSet(cacheKey, 'paginate', async () => {
const [activatedLicense, total] = await this.prisma.$transaction(async tx => [
await tx.licenseActivation.findMany({
where: defaultWhere,
@@ -87,13 +81,12 @@ export class PartnerActivatedLicensesService {
},
}
})
await this.redisService.setJson(cacheKey, { data: mappedLicenses, total }, 300)
return ResponseMapper.paginate(mappedLicenses, {
return {
items: mappedLicenses,
page,
perPage,
total,
}
})
}
@@ -65,17 +65,11 @@ export class PartnerLicenseChargeTransactionService {
page,
perPage,
)
const cached = await this.redisService.getJson<{ data: unknown[]; total: number }>(
cacheKey,
)
if (cached) {
return ResponseMapper.paginate(cached.data, { page, perPage, total: cached.total })
}
const defaultWhere: LicenseChargeTransactionWhereInput = {
partner_id,
}
return await this.redisService.getAndSet(cacheKey, 'paginate', async () => {
const [transactions, total] = await this.prisma.$transaction(async tx => [
await tx.licenseChargeTransaction.findMany({
where: defaultWhere,
@@ -89,22 +83,18 @@ export class PartnerLicenseChargeTransactionService {
])
const mappedTransactions = transactions.map(this.mappedTransaction)
await this.redisService.setJson(cacheKey, { data: mappedTransactions, total }, 300)
return ResponseMapper.paginate(mappedTransactions, {
return {
items: mappedTransactions,
page,
perPage,
total,
}
})
}
async findOne(partner_id: string, id: string) {
const cacheKey = RedisKeyMaker.partnerLicenseChargeTransactionDetail(partner_id, id)
const cached = await this.redisService.getJson<unknown>(cacheKey)
if (cached) {
return ResponseMapper.single(cached)
}
return await this.redisService.getAndSet(cacheKey, 'single', async () => {
const transaction = await this.prisma.licenseChargeTransaction.findUniqueOrThrow({
where: {
id,
@@ -112,9 +102,8 @@ export class PartnerLicenseChargeTransactionService {
},
select: this.defaultSelect,
})
const mappedTransaction = this.mappedTransaction(transaction)
await this.redisService.setJson(cacheKey, mappedTransaction, 300)
return ResponseMapper.single(mappedTransaction)
return this.mappedTransaction(transaction)
})
}
async create(partner_id: string, data: ChargeLicenseDto) {
@@ -1,3 +1,4 @@
import { PasswordFieldValidator, UsernameFieldValidator } from '@/common/utils'
import { PartnerStatus, TspProviderType } from '@/generated/prisma/enums'
import { ApiProperty, PartialType } from '@nestjs/swagger'
import { IsEnum, IsNumber, IsOptional, IsString } from 'class-validator'
@@ -21,10 +22,12 @@ export class CreatePartnerDto {
// license_quota?: number
@IsString()
@UsernameFieldValidator()
@ApiProperty({ required: true })
username: string
@IsString()
@PasswordFieldValidator()
@ApiProperty({ required: true })
password: string
@@ -1,3 +1,4 @@
import { PasswordFieldValidator, UsernameFieldValidator } from '@/common/utils'
import { ApiProperty, PartialType } from '@nestjs/swagger'
import { IsEnum, IsOptional, IsString } from 'class-validator'
import { PartnerRole } from 'generated/prisma/enums'
@@ -5,9 +6,11 @@ import { PartnerRole } from 'generated/prisma/enums'
export class CreatePartnerAccountDto {
@IsString()
@ApiProperty({})
@UsernameFieldValidator()
username: string
@IsString()
@PasswordFieldValidator()
@ApiProperty({})
password: string
}
+6 -19
View File
@@ -143,39 +143,26 @@ export class PartnersService {
async findAll() {
const cacheKey = RedisKeyMaker.partnersList()
const cached = await this.redisService.getJson<unknown[]>(cacheKey)
if (cached) {
console.log('cached', cached)
return ResponseMapper.list(cached)
}
return await this.redisService.getAndSet(cacheKey, 'list', async () => {
const partners = await this.prisma.partner.findMany({
select: this.defaultSelect,
})
const mappedPartners = partners.map(this.mapPartner)
await this.redisService.setJson(cacheKey, mappedPartners, 300)
return ResponseMapper.list(mappedPartners)
return partners.map(this.mapPartner)
})
}
async findOne(id: string) {
const cacheKey = RedisKeyMaker.partnerDetail(id)
const cached = await this.redisService.getJson<unknown>(cacheKey)
if (cached) {
return ResponseMapper.single(cached)
}
return await this.redisService.getAndSet(cacheKey, 'single', async () => {
const partner = await this.prisma.partner.findUniqueOrThrow({
where: { id },
select: this.defaultSelect,
})
const mappedPartner = this.mapPartner(partner)
await this.redisService.setJson(cacheKey, mappedPartner, 300)
return ResponseMapper.single(mappedPartner)
return this.mapPartner(partner)
})
}
async create(data: CreatePartnerDto, logo?: any) {
@@ -1,13 +1,16 @@
import { PasswordFieldValidator, UsernameFieldValidator } from '@/common/utils'
import { ApiProperty, PartialType } from '@nestjs/swagger'
import { IsEnum, IsOptional, IsString } from 'class-validator'
import { AccountStatus, AccountType } from 'generated/prisma/enums'
export class CreateAccountDto {
@IsString()
@UsernameFieldValidator()
@ApiProperty()
username: string
@IsString()
@PasswordFieldValidator()
@ApiProperty()
password: string
+5 -2
View File
@@ -2,11 +2,14 @@ import { ApiProperty } from '@nestjs/swagger'
import { IsBoolean, IsOptional, IsString } from 'class-validator'
export class LoginDto {
@ApiProperty({ description: 'Mobile number used as username', example: '09120258156' })
@ApiProperty({
description: 'you can use your mobile number as username',
example: '09120258156',
})
@IsString()
username: string
@ApiProperty({ description: 'OTP password (one-time password)', example: '11111' })
@ApiProperty({ example: '11111' })
@IsString()
password: string
+6 -12
View File
@@ -52,20 +52,14 @@ export class CatalogsService {
async getSKU(search: string) {
const items = await this.prisma.stockKeepingUnits.findMany({
// where: {
// OR: [{ code: { contains: search } }, { name: { contains: search } }],
// },
select: {
id: true,
code: true,
name: true,
is_domestic: true,
is_public: true,
VAT: true,
},
take: 100,
})
return ResponseMapper.list(items)
const mappedItems = items.map(item => ({
...item,
fullname: `${item.code} - ${item.name}`,
}))
return ResponseMapper.list(mappedItems)
}
async getGuildGoodCategories(guild_id: string) {
@@ -1,13 +1,16 @@
import { PasswordFieldValidator, UsernameFieldValidator } from '@/common/utils'
import { ApiProperty, PartialType } from '@nestjs/swagger'
import { IsEnum, IsOptional, IsString } from 'class-validator'
import { AccountStatus } from 'generated/prisma/enums'
export class CreateConsumerAccountDto {
@IsString()
@UsernameFieldValidator()
@ApiProperty({ required: true })
username: string
@IsString()
@PasswordFieldValidator()
@ApiProperty({ required: true })
password: string
@@ -61,34 +61,23 @@ export class BusinessActivitiesService {
async findAll(consumer_id: string) {
const cacheKey = RedisKeyMaker.consumerBusinessActivitiesList(consumer_id)
const cached = await this.redisService.getJson<unknown[]>(cacheKey)
if (cached) {
return ResponseMapper.list(cached)
}
const businessActivities =
await this.businessActivitiesQueryService.findAllByConsumer(
return await this.redisService.getAndSet(cacheKey, 'list', async () => {
return await this.businessActivitiesQueryService.findAllByConsumer(
consumer_id,
this.defaultSelect,
)
await this.redisService.setJson(cacheKey, businessActivities, this.cacheTtlSeconds)
return ResponseMapper.list(businessActivities)
})
}
async findOne(consumer_id: string, id: string) {
const cacheKey = RedisKeyMaker.consumerBusinessActivityInfo(consumer_id, id)
const cached = await this.redisService.getJson<unknown>(cacheKey)
if (cached) {
return ResponseMapper.single(cached)
}
const businessActivity = await this.businessActivitiesQueryService.findOneByConsumer(
return await this.redisService.getAndSet(cacheKey, 'list', async () => {
return await this.businessActivitiesQueryService.findOneByConsumer(
consumer_id,
id,
this.defaultSelect,
)
await this.redisService.setJson(cacheKey, businessActivity, this.cacheTtlSeconds)
return ResponseMapper.single(businessActivity)
})
}
async update(consumer_id: string, id: string, data: any) {
@@ -36,7 +36,6 @@ export class ConsumerBusinessActivityGoodsController {
async findOne(
@TokenAccount('userId') consumer_id: string,
@Param('businessActivityId') businessActivityId: string,
@Param('id') id: string,
): Promise<ConsumerBusinessActivityGoodsServiceFindOneResponseDto> {
return this.service.findOne(consumer_id, businessActivityId, id)
@@ -111,10 +111,15 @@ export class ConsumerBusinessActivityGoodsService {
},
},
},
select: this.defaultSelect,
})
await this.posCacheInvalidationService.invalidateGoodsListByBusinessActivity(
if (good.category) {
await this.posCacheInvalidationService.invalidatePosGoodsList(
good.category.guild_id!,
business_activity_id,
)
}
return ResponseMapper.create(good)
}
@@ -127,7 +132,7 @@ export class ConsumerBusinessActivityGoodsService {
) {
const good = await this.prisma.$transaction(async tx => {
const { category_id, sku_id, measure_unit_id, ...rest } = data
let image_url = ''
let image_url = undefined as string | undefined
if (file) {
const uploadedUrl = await this.uploaderService.uploadFile(
file,
@@ -177,11 +182,16 @@ export class ConsumerBusinessActivityGoodsService {
},
...rest,
},
select: this.defaultSelect,
})
})
await this.posCacheInvalidationService.invalidateGoodsListByBusinessActivity(
if (good.category) {
await this.posCacheInvalidationService.invalidatePosGoodsList(
good.category.guild_id!,
business_activity_id,
)
}
return ResponseMapper.update(good)
}
+3 -7
View File
@@ -21,11 +21,8 @@ export class ConsumerService {
async getInfo(consumer_id: string) {
const cacheKey = RedisKeyMaker.consumerInfo(consumer_id)
const cached = await this.redisService.getJson<unknown>(cacheKey)
if (cached) {
return ResponseMapper.single(cached)
}
return await this.redisService.getAndSet(cacheKey, 'single', async () => {
const consumer = await this.prisma.consumer.findUniqueOrThrow({
where: {
id: consumer_id,
@@ -37,9 +34,8 @@ export class ConsumerService {
},
})
const mappedConsumer = consumer_mappersUtil(consumer)
await this.redisService.setJson(cacheKey, mappedConsumer, this.infoCacheTtlSeconds)
return ResponseMapper.single(mappedConsumer)
return consumer_mappersUtil(consumer)
})
}
async updateInfo(consumer_id: string, data: UpdateConsumerInfoDto) {
@@ -0,0 +1,16 @@
import { Public } from '@/common/decorators/public.decorator'
import { Controller, Get, Param } from '@nestjs/common'
import { ApiTags } from '@nestjs/swagger'
import { InvoicesService } from './invoices.service'
@ApiTags('PublicInvoices')
@Controller('public-invoices')
export class InvoicesController {
constructor(private readonly service: InvoicesService) {}
@Get(':id')
@Public()
findOne(@Param('id') id: string) {
return this.service.findOne(id)
}
}
+10
View File
@@ -0,0 +1,10 @@
import { PrismaService } from '@/prisma/prisma.service'
import { Module } from '@nestjs/common'
import { InvoicesController } from './invoices.controller'
import { InvoicesService } from './invoices.service'
@Module({
controllers: [InvoicesController],
providers: [InvoicesService, PrismaService],
})
export class PublicInvoicesModule {}
+143
View File
@@ -0,0 +1,143 @@
import { RedisKeyMaker, translateEnumValue } from '@/common/utils'
import { TspProviderResponseStatus } from '@/generated/prisma/enums'
import { SalesInvoiceSelect } from '@/generated/prisma/models'
import { PrismaService } from '@/prisma/prisma.service'
import { RedisService } from '@/redis/redis.service'
import { Injectable } from '@nestjs/common'
@Injectable()
export class InvoicesService {
constructor(
private readonly prisma: PrismaService,
private readonly redisService: RedisService,
) {}
private readonly summarySelect: SalesInvoiceSelect = {
id: true,
code: true,
invoice_date: true,
invoice_number: true,
notes: true,
tax_id: true,
total_amount: true,
type: true,
pos: {
select: {
name: true,
complex: {
select: {
name: true,
branch_code: true,
business_activity: {
select: {
name: true,
guild: {
select: {
name: true,
},
},
},
},
},
},
},
},
payments: {
select: {
amount: true,
paid_at: true,
payment_method: true,
terminal_info: {
select: {
stan: true,
rrn: true,
transaction_date_time: true,
customer_card_no: true,
},
},
},
},
unknown_customer: true,
customer: {
select: {
type: true,
legal: {
select: {
name: true,
economic_code: true,
postal_code: true,
registration_number: true,
},
},
individual: {
select: {
economic_code: true,
first_name: true,
last_name: true,
mobile_number: true,
national_id: true,
postal_code: true,
},
},
},
},
items: {
select: {
good_snapshot: true,
measure_unit_text: true,
notes: true,
quantity: true,
total_amount: true,
unit_price: true,
discount: true,
payload: true,
sku_code: true,
sku_vat: true,
},
},
}
private readonly select: SalesInvoiceSelect = {
...this.summarySelect,
tsp_attempts: {
orderBy: {
created_at: 'desc',
},
select: {
status: true,
},
take: 1,
},
}
private readonly where = () => ({})
private readonly invoiceMapper = (invoice: any) => {
const { tsp_attempts, type, ...rest } = invoice || {}
return {
...rest,
type: translateEnumValue('TspProviderRequestType', type),
status: translateEnumValue(
'TspProviderResponseStatus',
invoice.tsp_attempts?.[0]?.status || TspProviderResponseStatus.NOT_SEND,
),
}
}
async findOne(id: string) {
await this.redisService.delete(RedisKeyMaker.publicSaleInvoice(id))
return await this.redisService.getAndSet(
RedisKeyMaker.publicSaleInvoice(id),
'single',
async () => {
const item = await this.prisma.salesInvoice.findUnique({
where: { ...this.where(), id },
select: this.select,
})
return this.invoiceMapper(item)
},
60 * 60,
)
}
}
@@ -1,13 +1,16 @@
import { PasswordFieldValidator, UsernameFieldValidator } from '@/common/utils'
import { ApiProperty, PartialType } from '@nestjs/swagger'
import { IsEnum, IsOptional, IsString } from 'class-validator'
import { AccountStatus, ConsumerRole } from 'generated/prisma/enums'
export class CreateConsumerAccountDto {
@IsString()
@UsernameFieldValidator()
@ApiProperty({ required: true })
username: string
@IsString()
@PasswordFieldValidator()
@ApiProperty({ required: true })
password: string
@@ -1,9 +1,12 @@
import { RedisKeyMaker } from '@/common/utils'
import { BusinessActivitySelect } from '@/generated/prisma/models'
import {
BusinessActivityCreateInput,
BusinessActivitySelect,
} from '@/generated/prisma/models'
import { getPartnerFirstRemainingLicense } from '@/modules/partners/utils/getPartnerRemainingLicenses.util'
import { PrismaService } from '@/prisma/prisma.service'
import { RedisService } from '@/redis/redis.service'
import { BadRequestException, Injectable } from '@nestjs/common'
import { Injectable } from '@nestjs/common'
import { ResponseMapper } from 'common/response/response-mapper'
import { PartnersCacheInvalidationService } from '../../cache/partners-cache-invalidation.service'
import { CreateBusinessActivitiesDto } from './dto/create-business-activities.dto'
@@ -100,13 +103,7 @@ export class BusinessActivitiesService {
page,
perPage,
)
const cached = await this.redisService.getJson<{ items: unknown[]; total: number }>(
cacheKey,
)
if (cached) {
return ResponseMapper.paginate(cached.items, { total: cached.total, page, perPage })
}
return await this.redisService.getAndSet(cacheKey, 'paginate', async () => {
const where = this.defaultWhere(partner_id, consumer_id)
const [businessActivities, total] = await this.prisma.$transaction(async tx => [
await tx.businessActivity.findMany({
@@ -118,12 +115,14 @@ export class BusinessActivitiesService {
await tx.businessActivity.count({ where }),
])
const mappedItems = businessActivities.map(this.prepareBusinessActivityResponse)
await this.redisService.setJson(
cacheKey,
{ items: mappedItems, total },
this.cacheTtlSeconds,
)
return ResponseMapper.paginate(mappedItems, { total, page, perPage })
return {
items: mappedItems,
total,
page,
perPage,
}
})
}
async findOne(partner_id: string, consumer_id: string, id: string) {
@@ -132,11 +131,7 @@ export class BusinessActivitiesService {
consumer_id,
id,
)
const cached = await this.redisService.getJson<unknown>(cacheKey)
if (cached) {
return ResponseMapper.single(cached)
}
return await this.redisService.getAndSet(cacheKey, 'single', async () => {
const businessActivity = await this.prisma.businessActivity.findUnique({
where: {
...this.defaultWhere(partner_id, consumer_id),
@@ -144,9 +139,8 @@ export class BusinessActivitiesService {
},
select: this.defaultSelect,
})
const mappedItem = this.prepareBusinessActivityResponse(businessActivity)
await this.redisService.setJson(cacheKey, mappedItem, this.cacheTtlSeconds)
return ResponseMapper.single(mappedItem)
return this.prepareBusinessActivityResponse(businessActivity)
})
}
async create(
@@ -158,6 +152,37 @@ export class BusinessActivitiesService {
const license = await getPartnerFirstRemainingLicense(tx, { partner_id })
const { guild_id, license_starts_at, expires_at, ...rest } = data
const dataToCreate: BusinessActivityCreateInput = {
...rest,
economic_code: String(data.economic_code),
guild: {
connect: {
id: guild_id,
},
},
consumer: {
connect: {
id: consumer_id,
},
},
}
if (license_starts_at) {
dataToCreate.license_activation = {
create: {
starts_at: license_starts_at ?? new Date(),
expires_at:
expires_at ?? this.setExpireDate(new Date(license_starts_at || '')),
license: {
connect: {
id: license.id,
},
},
},
}
}
const createdBusinessActivity = await tx.businessActivity.create({
data: {
...rest,
@@ -196,10 +221,7 @@ export class BusinessActivitiesService {
})
const activationId = createdBusinessActivity.license_activation?.id
if (!activationId) {
throw new BadRequestException('لایسنس برای این فعالیت تجاری ایجاد نشد.')
}
if (activationId) {
const licenseAllocationCreation = Array.from({
length: license.accounts_limit,
}).map(() =>
@@ -215,6 +237,7 @@ export class BusinessActivitiesService {
)
await Promise.all(licenseAllocationCreation)
}
return tx.businessActivity.findUniqueOrThrow({
where: {
@@ -65,13 +65,7 @@ export class BusinessActivityComplexesService {
page,
perPage,
)
const cached = await this.redisService.getJson<{ items: unknown[]; total: number }>(
cacheKey,
)
if (cached) {
return ResponseMapper.paginate(cached.items, { total: cached.total, page, perPage })
}
return await this.redisService.getAndSet(cacheKey, 'paginate', async () => {
const where = this.defaultWhere(partner_id, consumer_id, business_activity_id)
const [complexes, total] = await this.prisma.$transaction(async tx => [
await tx.complex.findMany({
@@ -97,12 +91,14 @@ export class BusinessActivityComplexesService {
pos_count: _count.pos_list,
}
})
await this.redisService.setJson(
cacheKey,
{ items: mappedComplexes, total },
this.cacheTtlSeconds,
)
return ResponseMapper.paginate(mappedComplexes, { total, page, perPage })
return {
items: mappedComplexes,
total,
page,
perPage,
}
})
}
async findOne(
@@ -117,11 +113,7 @@ export class BusinessActivityComplexesService {
business_activity_id,
id,
)
const cached = await this.redisService.getJson<unknown>(cacheKey)
if (cached) {
return ResponseMapper.single(cached)
}
return await this.redisService.getAndSet(cacheKey, 'single', async () => {
const complex = await this.prisma.complex.findFirst({
where: {
...this.defaultWhere(partner_id, consumer_id, business_activity_id),
@@ -134,8 +126,8 @@ export class BusinessActivityComplexesService {
throw new BadRequestException('شعبه مورد نظر یافت نشد.')
}
await this.redisService.setJson(cacheKey, complex, this.cacheTtlSeconds)
return ResponseMapper.single(complex)
return complex
})
}
async create(
@@ -1,5 +1,6 @@
import { FiscalIdFieldValidator } from '@/common/utils'
import { ApiProperty, PartialType } from '@nestjs/swagger'
import { IsDateString, IsOptional, IsString } from 'class-validator'
import { IsDateString, IsNumber, IsOptional, IsString, Max, Min } from 'class-validator'
export class CreateBusinessActivitiesDto {
@IsString()
@@ -11,6 +12,7 @@ export class CreateBusinessActivitiesDto {
economic_code: string
@IsString()
@FiscalIdFieldValidator()
@ApiProperty({ required: true })
fiscal_id: string
@@ -22,6 +24,12 @@ export class CreateBusinessActivitiesDto {
@ApiProperty({ required: true })
guild_id: string
@ApiProperty({ required: false, default: '1' })
@IsNumber()
@Min(0)
@Max(1_000_000_000)
invoice_number_sequence: number
@IsDateString()
@IsOptional()
@ApiProperty({ required: false })
@@ -64,13 +64,7 @@ export class PartnerConsumersService {
async findAll(partner_id: string, page = 1, perPage = 10) {
const cacheKey = RedisKeyMaker.partnerConsumersList(partner_id, page, perPage)
const cached = await this.redisService.getJson<{ items: unknown[]; total: number }>(
cacheKey,
)
if (cached) {
return ResponseMapper.paginate(cached.items, { total: cached.total, page, perPage })
}
return await this.redisService.getAndSet(cacheKey, 'paginate', async () => {
const [consumers, total] = await this.prisma.$transaction(async tx => [
await tx.consumer.findMany({
where: this.defaultWhere(partner_id),
@@ -82,26 +76,20 @@ export class PartnerConsumersService {
where: this.defaultWhere(partner_id),
}),
])
const mappedItems = consumers.map(mapConsumerWithLicenseUtil)
await this.redisService.setJson(
cacheKey,
{ items: mappedItems, total },
this.infoCacheTtlSeconds,
)
return ResponseMapper.paginate(mappedItems, {
const mappedConsumers = consumers.map(mapConsumerWithLicenseUtil)
return {
items: mappedConsumers,
total,
page,
perPage,
}
})
}
async findOne(partner_id: string, consumer_id: string) {
const cacheKey = RedisKeyMaker.partnerConsumerInfo(partner_id, consumer_id)
const cached = await this.redisService.getJson<unknown>(cacheKey)
if (cached) {
return ResponseMapper.single(cached)
}
return await this.redisService.getAndSet(cacheKey, 'single', async () => {
const consumer = await this.prisma.consumer.findUniqueOrThrow({
where: {
...(this.defaultWhere(partner_id) as any),
@@ -110,14 +98,8 @@ export class PartnerConsumersService {
select: this.defaultSelect,
})
const mappedConsumer = mapConsumerWithLicenseUtil(consumer)
await this.redisService.setJson(
RedisKeyMaker.consumerInfo(consumer_id),
mappedConsumer,
this.infoCacheTtlSeconds,
)
await this.redisService.setJson(cacheKey, mappedConsumer, this.infoCacheTtlSeconds)
return ResponseMapper.single(mappedConsumer)
return mapConsumerWithLicenseUtil(consumer)
})
}
async create(partner_id: string, data: CreateConsumerDto) {
@@ -1,3 +1,4 @@
import { PasswordFieldValidator, UsernameFieldValidator } from '@/common/utils'
import { ConsumerIndividual, ConsumerLegal } from '@/generated/prisma/client'
import { ConsumerStatus, ConsumerType } from '@/generated/prisma/enums'
import { ApiProperty, OmitType, PartialType } from '@nestjs/swagger'
@@ -9,10 +10,12 @@ export class CreateConsumerDto {
type: ConsumerType
@IsString()
@UsernameFieldValidator()
@ApiProperty({ required: true })
username: string
@IsString()
@PasswordFieldValidator()
@ApiProperty({ required: true })
password: string
+77 -15
View File
@@ -1,25 +1,87 @@
import { Injectable } from '@nestjs/common'
import { PosKeyMaker } from '@/common/utils'
import { RedisService } from '@/redis/redis.service'
import { Injectable } from '@nestjs/common'
@Injectable()
export class PosCacheInvalidationService {
constructor(private readonly redisService: RedisService) {}
async invalidateGoodsListByGuild(guildId: string): Promise<void> {
const client = await this.redisService.getClient()
const keys = await client.keys(`pos:ba:*:guild:${guildId}:goods:list`)
if (keys.length > 0) {
await client.del(keys)
}
}
async invalidateGoodsListByBusinessActivity(
async invalidatePosGoodsList(
guildId: string,
businessActivityId: string,
): Promise<void> {
const client = await this.redisService.getClient()
const keys = await client.keys(`pos:ba:${businessActivityId}:guild:*:goods:list`)
if (keys.length > 0) {
await client.del(keys)
}
this.redisService.delete(PosKeyMaker.goodList(guildId, businessActivityId))
}
async invalidatePosGoodsByGuildPattern(guildId: string): Promise<void> {
this.redisService.deleteByPattern(PosKeyMaker.goodListByGuildPattern(guildId))
}
async invalidatePosStatisticsInvoicesByBusinessActivityId(
businessActivityId: string,
): Promise<void> {
this.redisService.deleteByPattern(
PosKeyMaker.statisticInvoicesPattern(businessActivityId),
)
}
async invalidatePosStatisticsInvoicesAll(
businessActivityId: string,
posId: string,
from: string,
): Promise<void> {
this.redisService.delete(
PosKeyMaker.statisticInvoices(businessActivityId, posId, from),
)
}
async invalidatePosStatisticsInvoicesFailure(
businessActivityId: string,
posId: string,
from: string,
): Promise<void> {
this.redisService.delete(
PosKeyMaker.statisticInvoicesFailure(businessActivityId, posId, from),
)
}
async invalidatePosStatisticsInvoicesSuccess(
businessActivityId: string,
posId: string,
from: string,
): Promise<void> {
this.redisService.delete(
PosKeyMaker.statisticInvoicesSuccess(businessActivityId, posId, from),
)
}
async invalidatePosStatisticsInvoicesPending(
businessActivityId: string,
posId: string,
from: string,
): Promise<void> {
this.redisService.delete(
PosKeyMaker.statisticInvoicesPending(businessActivityId, posId, from),
)
}
async invalidatePosStatisticsInvoicesCredit(
businessActivityId: string,
posId: string,
from: string,
): Promise<void> {
this.redisService.delete(
PosKeyMaker.statisticInvoicesCredit(businessActivityId, posId, from),
)
}
async invalidatePosStatisticsInvoicesNotSent(
businessActivityId: string,
posId: string,
from: string,
): Promise<void> {
this.redisService.delete(
PosKeyMaker.statisticInvoicesNotSent(businessActivityId, posId, from),
)
}
}
+3 -44
View File
@@ -1,47 +1,6 @@
import { GoodPricingModel } from '@/generated/prisma/enums'
import { ApiProperty, PartialType } from '@nestjs/swagger'
import { IsEnum, IsNumber, IsOptional, IsString } from 'class-validator'
import { CreateGuildGoodDto } from '@/modules/admin/guilds/goods/dto/create-good.dto'
import { PartialType } from '@nestjs/swagger'
export class CreateGoodDto {
@IsString()
@ApiProperty()
name: string
@IsOptional()
@IsString()
@ApiProperty({ required: false })
description?: string
@IsString()
@ApiProperty({ required: true })
sku_id: string
@IsString()
@ApiProperty()
local_sku: string
@IsEnum(GoodPricingModel)
@ApiProperty({ required: true, enum: GoodPricingModel })
pricing_model: GoodPricingModel
@IsOptional()
@IsString()
@ApiProperty({ required: false })
barcode?: string
@IsOptional()
@IsString()
@ApiProperty({ required: false })
category_id?: string
@IsOptional()
@IsNumber()
@ApiProperty({ required: false })
base_sale_price?: number
@IsString()
@ApiProperty({ required: true })
measure_unit_id: string
}
export class CreateGoodDto extends CreateGuildGoodDto {}
export class UpdateGoodDto extends PartialType(CreateGoodDto) {}
@@ -1,5 +1,4 @@
import type { GoodsService } from '../goods.service'
export type GoodsServiceCreateResponseDto = Awaited<ReturnType<GoodsService['create']>>
export type GoodsServiceFindAllResponseDto = Awaited<ReturnType<GoodsService['findAll']>>
export type GoodsServiceFindOneResponseDto = Awaited<ReturnType<GoodsService['findOne']>>
@@ -0,0 +1,25 @@
import { PosInfo } from '@/common/decorators/posInfo.decorator'
import type { IPosPayload } from '@/common/models/posPayload.model'
import { Controller, Delete, Param, Post } from '@nestjs/common'
import { PosGoodFavoriteService } from './favorite.service'
@Controller('pos/goods/:good_id/favorite')
export class PosGoodFavoriteController {
constructor(private readonly service: PosGoodFavoriteService) {}
@Post()
attach(
@Param('good_id') good_id: string,
@PosInfo() { business_id, guild_id, consumer_account_id }: IPosPayload,
) {
return this.service.attach(good_id, business_id, guild_id, consumer_account_id)
}
@Delete()
detach(
@Param('good_id') good_id: string,
@PosInfo() { business_id, guild_id, consumer_account_id }: IPosPayload,
) {
return this.service.detach(good_id, business_id, guild_id, consumer_account_id)
}
}
@@ -0,0 +1,9 @@
import { Module } from '@nestjs/common'
import { PosGoodFavoriteController } from './favorite.controller'
import { PosGoodFavoriteService } from './favorite.service'
@Module({
controllers: [PosGoodFavoriteController],
providers: [PosGoodFavoriteService],
})
export class PosGoodFavoriteModule {}
@@ -0,0 +1,84 @@
import { RedisService } from '@/redis/redis.service'
import { Injectable } from '@nestjs/common'
import { ResponseMapper } from '../../../../common/response/response-mapper'
import { PrismaService } from '../../../../prisma/prisma.service'
import { PosCacheInvalidationService } from '../../cache/pos-cache-invalidation.service'
@Injectable()
export class PosGoodFavoriteService {
constructor(
private prisma: PrismaService,
private readonly redisService: RedisService,
private readonly posCacheInvalidationService: PosCacheInvalidationService,
) {}
async attach(
good_id: string,
business_id: string,
guild_id: string,
consumer_account_id: string,
) {
const favorite = await this.prisma.consumerAccountGoodFavorite.upsert({
where: {
consumer_account_id_good_id: {
consumer_account_id,
good_id,
},
good: {
OR: [
{
business_activity_id: business_id,
},
{
sku: {
guild_id,
},
},
],
},
},
update: {},
create: {
consumer_account_id,
good_id,
},
})
await this.posCacheInvalidationService.invalidatePosGoodsList(guild_id, business_id)
return ResponseMapper.create(favorite)
}
async detach(
good_id: string,
business_id: string,
guild_id: string,
consumer_account_id: string,
) {
const favorite = await this.prisma.consumerAccountGoodFavorite.delete({
where: {
consumer_account_id_good_id: {
consumer_account_id,
good_id,
},
good: {
OR: [
{
business_activity_id: business_id,
},
{
sku: {
guild_id,
},
},
],
},
},
})
await this.posCacheInvalidationService.invalidatePosGoodsList(guild_id, business_id)
return ResponseMapper.delete()
}
}
+5 -5
View File
@@ -1,15 +1,15 @@
import { PosInfo } from '@/common/decorators/posInfo.decorator'
import type { IPosPayload } from '@/common/models/posPayload.model'
import { Controller, Get, Param } from '@nestjs/common'
import { GoodsService } from './goods.service'
import type { IPosPayload } from '@/common/models/posPayload.model'
@Controller('pos/goods')
export class GoodsController {
constructor(private readonly goodsService: GoodsService) {}
@Get()
findAll(@PosInfo() { business_id, guild_id }: IPosPayload) {
return this.goodsService.findAll(business_id, guild_id)
findAll(@PosInfo() { business_id, guild_id, consumer_account_id }: IPosPayload) {
return this.goodsService.findAll(business_id, guild_id, consumer_account_id)
}
@Get(':id')
@@ -21,7 +21,7 @@ export class GoodsController {
}
// @Post()
// create(@Body() data: CreateGoodDto, @PosInfo() { complex_id, guild_id }: IPosPayload) {
// return this.goodsService.create(data, complex_id, guild_id)
// create(@Body() data: CreateGoodDto, @PosInfo('complex_id') complex_id: string) {
// return this.goodsService.create(data, complex_id)
// }
}
+2
View File
@@ -1,8 +1,10 @@
import { Module } from '@nestjs/common'
import { PosGoodFavoriteModule } from './favorite/favorite.module'
import { GoodsController } from './goods.controller'
import { GoodsService } from './goods.service'
@Module({
imports: [PosGoodFavoriteModule],
controllers: [GoodsController],
providers: [GoodsService],
})
+121 -123
View File
@@ -1,19 +1,15 @@
import { ResponseMapper } from '@/common/response/response-mapper'
import { RedisKeyMaker } from '@/common/utils/redisKeyMaker'
import { GoodSelect } from '@/generated/prisma/models'
import { PosCacheInvalidationService } from '@/modules/pos/cache/pos-cache-invalidation.service'
import { PrismaService } from '@/prisma/prisma.service'
import { RedisService } from '@/redis/redis.service'
import { Injectable } from '@nestjs/common'
import { ResponseMapper } from '../../../common/response/response-mapper'
import { PrismaService } from '../../../prisma/prisma.service'
import { CreateGoodDto } from './dto/create-good.dto'
import { UpdateGoodDto } from './dto/update-good.dto'
@Injectable()
export class GoodsService {
constructor(
private prisma: PrismaService,
private readonly redisService: RedisService,
private readonly posCacheInvalidationService: PosCacheInvalidationService,
) {}
private readonly listCacheTtlSeconds = 300
@@ -51,13 +47,16 @@ export class GoodsService {
},
}
async findAll(business_activity_id: string, guild_id: string) {
async findAll(
business_activity_id: string,
guild_id: string,
consumer_account_id: string,
) {
const cacheKey = RedisKeyMaker.posGoodsList(business_activity_id, guild_id)
const cached = await this.redisService.getJson<unknown[]>(cacheKey)
if (cached) {
return ResponseMapper.list(cached)
}
return this.redisService.getAndSet(
cacheKey,
'list',
async () => {
const goods = await this.prisma.good.findMany({
where: {
OR: [
@@ -72,12 +71,25 @@ export class GoodsService {
},
],
},
select: this.defaultSelect,
select: {
...this.defaultSelect,
consumer_account_good_favorites: {
where: {
consumer_account_id,
},
},
},
})
await this.redisService.setJson(cacheKey, goods, this.listCacheTtlSeconds)
const mappedGoods = goods.map(good => ({
...good,
is_favorite: good.consumer_account_good_favorites.length > 0,
}))
return ResponseMapper.list(goods)
return mappedGoods
},
this.listCacheTtlSeconds,
)
}
async findOne(good_id: string, business_activity_id: string, guild_id: string) {
@@ -95,113 +107,99 @@ export class GoodsService {
return ResponseMapper.single(good)
}
async create(data: CreateGoodDto, business_activity_id: string) {
const { category_id, sku_id, measure_unit_id, ...rest } = data
// async create(data: CreateGoodDto, business_activity_id: string, guild_id: string) {
// const { category_id, sku_id, measure_unit_id, ...rest } = data
const dataToCreate = {
...rest,
business_activity_id,
connect: {
category: {
id: category_id,
},
},
}
const good = await this.prisma.good.create({
data: {
...rest,
measure_unit: {
connect: {
id: measure_unit_id,
},
},
sku: {
connect: {
id: sku_id,
},
},
category: {
connect: {
id: category_id,
},
},
business_activity: {
connect: {
id: business_activity_id,
},
},
},
select: this.defaultSelect,
})
await this.posCacheInvalidationService.invalidateGoodsListByBusinessActivity(
business_activity_id,
)
return ResponseMapper.create(good)
}
async update(id: string, data: UpdateGoodDto, business_activity_id: string) {
const { category_id, sku_id, measure_unit_id, ...rest } = data
const good = await this.prisma.good.update({
where: {
id,
business_activity_id,
},
data: {
...rest,
...(measure_unit_id
? {
measure_unit: {
connect: {
id: measure_unit_id,
},
},
}
: {}),
...(sku_id
? {
sku: {
connect: {
id: sku_id,
},
},
}
: {}),
...(category_id
? {
category: {
connect: {
id: category_id,
},
},
}
: {}),
},
select: this.defaultSelect,
})
await this.posCacheInvalidationService.invalidateGoodsListByBusinessActivity(
business_activity_id,
)
return ResponseMapper.update(good)
}
async delete(id: string, business_activity_id: string) {
await this.prisma.good.delete({
where: {
id,
business_activity_id,
},
})
await this.posCacheInvalidationService.invalidateGoodsListByBusinessActivity(
business_activity_id,
)
return ResponseMapper.delete()
}
// const dataToCreate = {
// ...rest,
// measure_unit: {
// connect: {
// id: measure_unit_id,
// },
// },
// sku: {
// connect: {
// id: sku_id,
// },
// },
// category: {
// connect: {
// id: category_id,
// },
// },
// business_activity: {
// connect: {
// id: business_activity_id,
// },
// },
// }
// const good = await this.prisma.good.create({
// data: {
// ...dataToCreate,
// },
// select: this.defaultSelect,
// })
// await this.posCacheInvalidationService.invalidatePosGoodsList(
// guild_id,
// business_activity_id,
// )
// return ResponseMapper.create(good)
// }
// async update(
// id: string,
// data: UpdateGoodDto,
// business_activity_id: string,
// guild_id: string,
// ) {
// const { category_id, sku_id, measure_unit_id, ...rest } = data
// const good = await this.prisma.good.update({
// where: {
// id,
// business_activity_id,
// },
// data: {
// ...rest,
// ...(measure_unit_id
// ? {
// measure_unit: {
// connect: {
// id: measure_unit_id,
// },
// },
// }
// : {}),
// ...(sku_id
// ? {
// sku: {
// connect: {
// id: sku_id,
// },
// },
// }
// : {}),
// ...(category_id
// ? {
// category: {
// connect: {
// id: category_id,
// },
// },
// }
// : {}),
// },
// select: this.defaultSelect,
// })
// await this.posCacheInvalidationService.invalidatePosGoodsList(
// guild_id,
// business_activity_id,
// )
// return ResponseMapper.update(good)
// }
}
@@ -0,0 +1,3 @@
import { CreateGuildGoodDto } from '@/modules/admin/guilds/goods/dto/create-good.dto'
export class CreateOwnedGoodsDto extends CreateGuildGoodDto {}
@@ -0,0 +1,4 @@
import { PartialType } from '@nestjs/swagger'
import { CreateOwnedGoodsDto } from './create-owned-goods.dto'
export class UpdateOwnedGoodsDto extends PartialType(CreateOwnedGoodsDto) {}
@@ -0,0 +1,72 @@
import { PosInfo } from '@/common/decorators/posInfo.decorator'
import type { IPosPayload } from '@/common/models'
import { multerImageOptions } from '@/multer.config'
import {
Body,
Controller,
Get,
Param,
Patch,
Post,
UploadedFile,
UseInterceptors,
} from '@nestjs/common'
import { FileInterceptor } from '@nestjs/platform-express'
import { ApiBody, ApiConsumes } from '@nestjs/swagger'
import { CreateOwnedGoodsDto } from './dto/create-owned-goods.dto'
import { UpdateOwnedGoodsDto } from './dto/update-owned-goods.dto'
import { OwnedGoodsService } from './owned-goods.service'
@Controller('pos/owned-goods')
export class OwnedGoodsController {
constructor(private readonly service: OwnedGoodsService) {}
@Get()
findAll(@PosInfo('business_id') business_id: string) {
return this.service.findAll(business_id)
}
@Get(':id')
findOne(@PosInfo('business_id') business_id: string, @Param('id') id: string) {
return this.service.findOne(business_id, id)
}
@Post()
@UseInterceptors(FileInterceptor('image', multerImageOptions))
@ApiConsumes('multipart/form-data')
@ApiBody({
schema: {
type: 'object',
properties: {
image: { type: 'string', format: 'binary' },
},
},
})
create(
@PosInfo() { business_id, guild_id }: IPosPayload,
@UploadedFile() file: Express.Multer.File,
@Body() dto: CreateOwnedGoodsDto,
) {
return this.service.create(guild_id, business_id, dto, file)
}
@Patch(':id')
@UseInterceptors(FileInterceptor('image', multerImageOptions))
@ApiConsumes('multipart/form-data')
@ApiBody({
schema: {
type: 'object',
properties: {
image: { type: 'string', format: 'binary' },
},
},
})
update(
@PosInfo() { business_id, guild_id }: IPosPayload,
@Param('id') id: string,
@UploadedFile() file: Express.Multer.File,
@Body() dto: UpdateOwnedGoodsDto,
) {
return this.service.update(guild_id, business_id, id, dto, file)
}
}
@@ -0,0 +1,12 @@
import { UploaderModule } from '@/modules/uploader/uploader.module'
import { PrismaService } from '@/prisma/prisma.service'
import { Module } from '@nestjs/common'
import { OwnedGoodsController } from './owned-goods.controller'
import { OwnedGoodsService } from './owned-goods.service'
@Module({
controllers: [OwnedGoodsController],
providers: [OwnedGoodsService, PrismaService],
imports: [UploaderModule],
})
export class OwnedGoodsModule {}
@@ -0,0 +1,191 @@
import { UploadedFileTypes } from '@/common/enums/enums'
import { ResponseMapper } from '@/common/response/response-mapper'
import { GoodSelect, GoodWhereInput } from '@/generated/prisma/models'
import { UploaderService } from '@/modules/uploader/uploader.service'
import { PrismaService } from '@/prisma/prisma.service'
import { Injectable } from '@nestjs/common'
import { PosCacheInvalidationService } from '../cache/pos-cache-invalidation.service'
import { CreateOwnedGoodsDto } from './dto/create-owned-goods.dto'
import { UpdateOwnedGoodsDto } from './dto/update-owned-goods.dto'
@Injectable()
export class OwnedGoodsService {
constructor(
private readonly prisma: PrismaService,
private readonly uploaderService: UploaderService,
private readonly posCacheInvalidationService: PosCacheInvalidationService,
) {}
private readonly where = (business_activity_id: string): GoodWhereInput => ({
is_default_guild_good: false,
business_activity_id,
})
private readonly select: GoodSelect = {
id: true,
name: true,
pricing_model: true,
image_url: true,
description: true,
sku: {
select: {
id: true,
name: true,
code: true,
},
},
measure_unit: {
select: {
id: true,
name: true,
code: true,
},
},
category: {
select: {
id: true,
name: true,
},
},
}
async findAll(business_activity_id: string) {
const items = await this.prisma.good.findMany({
where: this.where(business_activity_id),
select: this.select,
})
return ResponseMapper.list(items)
}
async findOne(business_activity_id: string, id: string) {
const item = await this.prisma.good.findUnique({
where: { ...(this.where(business_activity_id) as any), id },
select: this.select,
})
return ResponseMapper.single(item)
}
async create(
guild_id: string,
business_activity_id: string,
data: CreateOwnedGoodsDto,
file: Express.Multer.File,
) {
const { category_id, measure_unit_id, sku_id, ...rest } = data
const good = await this.prisma.$transaction(async tx => {
let image_url = ''
if (file) {
const uploadedUrl = await this.uploaderService.uploadFile(
file,
UploadedFileTypes.GOOD,
)
image_url = uploadedUrl || ''
}
return await tx.good.create({
data: {
...rest,
is_default_guild_good: true,
image_url,
sku: {
connect: {
id: sku_id,
},
},
measure_unit: {
connect: {
id: measure_unit_id,
},
},
category: {
connect: {
id: category_id,
},
},
business_activity: {
connect: {
id: business_activity_id,
},
},
},
select: this.select,
})
})
await this.posCacheInvalidationService.invalidatePosGoodsList(
guild_id,
business_activity_id,
)
return ResponseMapper.create(good)
}
async update(
guild_id: string,
business_activity_id: string,
id: string,
data: UpdateOwnedGoodsDto,
file: Express.Multer.File,
) {
const { category_id, measure_unit_id, sku_id, ...rest } = data
const good = await this.prisma.$transaction(async tx => {
let image_url = undefined as string | undefined
if (file) {
const uploadedUrl = await this.uploaderService.uploadFile(
file,
UploadedFileTypes.GOOD,
)
image_url = uploadedUrl
}
const prevImage = await tx.good.findUnique({
where: { id },
select: { image_url: true },
})
if (image_url && prevImage?.image_url) {
this.uploaderService.deleteFile(prevImage.image_url, UploadedFileTypes.GOOD)
}
return await tx.good.update({
where: { ...(this.where(business_activity_id) as any), id },
data: {
...rest,
is_default_guild_good: false,
image_url,
sku: {
connect: {
id: sku_id,
},
},
measure_unit: {
connect: {
id: measure_unit_id,
},
},
category: {
connect: {
id: category_id,
},
},
business_activity: {
connect: {
id: business_activity_id,
},
},
},
select: this.select,
})
})
await this.posCacheInvalidationService.invalidatePosGoodsList(
guild_id,
business_activity_id,
)
return ResponseMapper.create(good)
}
}
+4
View File
@@ -3,10 +3,12 @@ import { JwtService } from '@nestjs/jwt'
import { PosCustomersModule } from './customers/customers.module'
import { PosGoodCategoriesModule } from './good-categories/good-categories.module'
import { PosGoodsModule } from './goods/goods.module'
import { OwnedGoodsModule } from './owned-goods/owned-goods.module'
import { PosController } from './pos.controller'
import { PosMiddleware } from './pos.middleware'
import { PosService } from './pos.service'
import { PosSalesInvoicesModule } from './sales-invoices/sales-invoices.module'
import { StatisticsModule } from './statistics/statistics.module'
@Module({
controllers: [PosController],
@@ -16,6 +18,8 @@ import { PosSalesInvoicesModule } from './sales-invoices/sales-invoices.module'
PosGoodCategoriesModule,
PosGoodsModule,
PosSalesInvoicesModule,
OwnedGoodsModule,
StatisticsModule,
],
})
export class PosModule implements NestModule {
+18 -14
View File
@@ -19,11 +19,10 @@ export class PosService {
async getInfo(pos_id: string) {
const cacheKey = RedisKeyMaker.posInfo(pos_id)
const cached = await this.redisService.getJson<unknown>(cacheKey)
if (cached) {
return ResponseMapper.single(cached)
}
return await this.redisService.getAndSet(
cacheKey,
'single',
async () => {
const pos = await this.prisma.pos.findUniqueOrThrow({
where: {
id: pos_id,
@@ -104,8 +103,11 @@ export class PosService {
},
partner: license_activation?.license.charge_transaction.partner,
}
await this.redisService.setJson(cacheKey, payload, this.infoCacheTtlSeconds)
return ResponseMapper.single(payload)
return payload
},
this.infoCacheTtlSeconds,
)
}
async getAccessible(account_id: string) {
@@ -153,11 +155,10 @@ export class PosService {
async getMe(account_id: string, pos_id: string) {
const cacheKey = RedisKeyMaker.posMe(account_id, pos_id)
const cached = await this.redisService.getJson<unknown>(cacheKey)
if (cached) {
return ResponseMapper.single(cached)
}
return await this.redisService.getAndSet(
cacheKey,
'single',
async () => {
const pos = await this.prisma.consumerAccount.findUniqueOrThrow({
where: {
id: account_id,
@@ -203,7 +204,10 @@ export class PosService {
...rest,
consumer: consumer_mappersUtil(consumer),
}
await this.redisService.setJson(cacheKey, payload, this.meCacheTtlSeconds)
return ResponseMapper.single(payload)
return payload
},
this.meCacheTtlSeconds,
)
}
}
@@ -0,0 +1,20 @@
import { PosInfo } from '@/common/decorators/posInfo.decorator'
import type { IPosPayload } from '@/common/models'
import { Controller, Get, Query } from '@nestjs/common'
import { ApiTags } from '@nestjs/swagger'
import { StatisticsService } from './statistics.service'
@ApiTags('PosStatistics')
@Controller('pos/statistics')
export class StatisticsController {
constructor(private readonly service: StatisticsService) {}
@Get('sale-invoices')
findAll(@PosInfo() PosInfo: IPosPayload, @Query('from_date') from_date?: string) {
return this.service.findAll(
PosInfo.pos_id,
PosInfo.business_id,
from_date ? new Date(from_date) : new Date(),
)
}
}
@@ -0,0 +1,10 @@
import { Module } from '@nestjs/common';
import { StatisticsService } from './statistics.service';
import { StatisticsController } from './statistics.controller';
import { PrismaService } from '@/prisma/prisma.service';
@Module({
controllers: [StatisticsController],
providers: [StatisticsService, PrismaService],
})
export class StatisticsModule {}
@@ -0,0 +1,88 @@
import { ResponseMapper } from '@/common/response/response-mapper'
import { getCurrentJalaliSeasonRange } from '@/common/utils'
import { TspProviderResponseStatus } from '@/generated/prisma/enums'
import { PrismaService } from '@/prisma/prisma.service'
import { Injectable } from '@nestjs/common'
@Injectable()
export class StatisticsService {
constructor(private readonly prisma: PrismaService) {}
async findAll(posId: string, businessId: string, fromDate: Date = new Date()) {
const seasonDate = getCurrentJalaliSeasonRange(fromDate)
const [item] = await this.prisma.$queryRaw<
Array<{
all_amount_sum: number | null
all_count: number | null
success_amount_sum: number | null
success_count: number | null
failure_amount_sum: number | null
failure_count: number | null
pending_amount_sum: number | null
pending_count: number | null
not_sended_amount_sum: number | null
not_sended_count: number | null
}>
>`
SELECT
SUM(si.total_amount) AS all_amount_sum,
COUNT(*) AS all_count,
SUM(CASE WHEN la.status = ${TspProviderResponseStatus.SUCCESS} THEN si.total_amount ELSE 0 END) AS success_amount_sum,
SUM(CASE WHEN la.status = ${TspProviderResponseStatus.SUCCESS} THEN 1 ELSE 0 END) AS success_count,
SUM(CASE WHEN la.status = ${TspProviderResponseStatus.FAILURE} THEN si.total_amount ELSE 0 END) AS failure_amount_sum,
SUM(CASE WHEN la.status = ${TspProviderResponseStatus.FAILURE} THEN 1 ELSE 0 END) AS failure_count,
SUM(CASE WHEN la.status = ${TspProviderResponseStatus.QUEUED} THEN si.total_amount ELSE 0 END) AS pending_amount_sum,
SUM(CASE WHEN la.status = ${TspProviderResponseStatus.QUEUED} THEN 1 ELSE 0 END) AS pending_count,
SUM(CASE WHEN la.status IS NULL THEN si.total_amount ELSE 0 END) AS not_sended_amount_sum,
SUM(CASE WHEN la.status IS NULL THEN 1 ELSE 0 END) AS not_sended_count
FROM sales_invoices si
INNER JOIN poses p ON p.id = si.pos_id
LEFT JOIN (
SELECT a1.invoice_id, a1.status
FROM sale_invoice_tsp_attempts a1
INNER JOIN (
SELECT invoice_id, MAX(attempt_no) AS max_attempt_no
FROM sale_invoice_tsp_attempts
GROUP BY invoice_id
) latest
ON latest.invoice_id = a1.invoice_id
AND latest.max_attempt_no = a1.attempt_no
) la ON la.invoice_id = si.id
WHERE si.invoice_date >= ${seasonDate.start}
AND si.invoice_date <= ${seasonDate.end}
AND si.pos_id = ${posId}
AND p.complex_id IN (
SELECT c.id FROM complexes c WHERE c.business_activity_id = ${businessId}
)
`
return ResponseMapper.single({
all: {
total_amount: Number(item?.all_amount_sum || 0),
total_tax: Number(0),
count: Number(item?.all_count || 0),
},
success: {
total_amount: Number(item?.success_amount_sum || 0),
total_tax: Number(0),
count: Number(item?.success_count || 0),
},
failure: {
total_amount: Number(item?.failure_amount_sum || 0),
total_tax: Number(0),
count: Number(item?.failure_count || 0),
},
pending: {
total_amount: Number(item?.pending_amount_sum || 0),
total_tax: Number(0),
count: Number(item?.pending_count || 0),
},
notSended: {
total_amount: Number(item?.not_sended_amount_sum || 0),
total_tax: Number(0),
count: Number(item?.not_sended_count || 0),
},
})
}
}
@@ -1,14 +0,0 @@
import { ApiProperty, PartialType } from '@nestjs/swagger'
import { IsString } from 'class-validator'
export class CreateTriggerLogDto {
@ApiProperty()
@IsString()
message: string
@ApiProperty()
@IsString()
name: string
}
export class UpdateTriggerLogDto extends PartialType(CreateTriggerLogDto) {}
@@ -1,5 +0,0 @@
import type { TriggerLogsService } from '../trigger-logs.service'
export type TriggerLogsServiceCreateResponseDto = Awaited<ReturnType<TriggerLogsService['create']>>
export type TriggerLogsServiceFindAllResponseDto = Awaited<ReturnType<TriggerLogsService['findAll']>>
export type TriggerLogsServiceFindOneResponseDto = Awaited<ReturnType<TriggerLogsService['findOne']>>
@@ -1,22 +0,0 @@
import { Body, Controller, Get, Param, Post } from '@nestjs/common'
import { TriggerLogsService } from './trigger-logs.service'
@Controller('trigger-logs')
export class TriggerLogsController {
constructor(private readonly triggerLogsService: TriggerLogsService) {}
@Get()
findAll() {
return this.triggerLogsService.findAll()
}
@Get(':id')
findOne(@Param('id') id: string) {
return this.triggerLogsService.findOne(+id)
}
@Post()
create(@Body() data: any) {
return this.triggerLogsService.create(data)
}
}
@@ -1,9 +0,0 @@
import { Module } from '@nestjs/common'
import { TriggerLogsController } from './trigger-logs.controller'
import { TriggerLogsService } from './trigger-logs.service'
@Module({
controllers: [TriggerLogsController],
providers: [TriggerLogsService],
})
export class TriggerLogsModule {}
@@ -1,19 +0,0 @@
import { Injectable } from '@nestjs/common'
@Injectable()
export class TriggerLogsService {
findAll() {
// TODO: Implement fetching all trigger logs
return []
}
findOne(id: number) {
// TODO: Implement fetching a single trigger log
return {}
}
create(data: any) {
// TODO: Implement trigger log creation
return data
}
}
+1 -1
View File
@@ -14,7 +14,7 @@ export class PrismaService extends PrismaClient implements OnModuleInit, OnModul
password: env('DATABASE_PASSWORD'),
database: env('DATABASE_NAME'),
port: env('DATABASE_PORT') ? Number(env('DATABASE_PORT')) : 3306,
connectionLimit: 50,
connectionLimit: 10,
})
const prismaOptions = getPrismaOptions()
+148 -24
View File
@@ -1,27 +1,35 @@
import {
MapperWrapper,
Paginated,
ResponseMapper,
} from '@/common/response/response-mapper'
import { Injectable, Logger, OnModuleDestroy } from '@nestjs/common'
import Redis from 'ioredis'
interface PaginatedCache<T> {
items: T[]
total: number
page?: number
perPage?: number
}
@Injectable()
export class RedisService implements OnModuleDestroy {
private static readonly scanCount = 100
private readonly logger = new Logger(RedisService.name)
private readonly client: Redis
constructor() {
const host = process.env.REDIS_HOST || 'redis'
const port = Number(process.env.REDIS_PORT || 6379)
const password = process.env.REDIS_PASSWORD || undefined
const db = Number(process.env.REDIS_DB || 0)
this.client = new Redis({
host,
port,
password,
db,
host: process.env.REDIS_HOST || 'redis',
port: Number(process.env.REDIS_PORT || 6379),
password: process.env.REDIS_PASSWORD || undefined,
db: Number(process.env.REDIS_DB || 0),
lazyConnect: true,
maxRetriesPerRequest: 3,
})
this.client.on('error', (error) => {
this.client.on('error', error => {
this.logger.error(`Redis error: ${error.message}`)
})
}
@@ -53,11 +61,7 @@ export class RedisService implements OnModuleDestroy {
}
}
async set(
key: string,
value: string,
ttlSeconds?: number,
): Promise<'OK' | null> {
async set(key: string, value: string, ttlSeconds?: number): Promise<'OK' | null> {
const client = await this.getClient()
if (ttlSeconds && ttlSeconds > 0) {
return client.set(key, value, 'EX', ttlSeconds)
@@ -65,11 +69,7 @@ export class RedisService implements OnModuleDestroy {
return client.set(key, value)
}
async setJson(
key: string,
value: unknown,
ttlSeconds?: number,
): Promise<'OK' | null> {
async setJson(key: string, value: unknown, ttlSeconds?: number): Promise<'OK' | null> {
return this.set(key, JSON.stringify(value), ttlSeconds)
}
@@ -101,14 +101,12 @@ export class RedisService implements OnModuleDestroy {
'MATCH',
pattern,
'COUNT',
100,
RedisService.scanCount,
)
cursor = nextCursor
if (keys.length > 0) {
const pipeline = client.pipeline()
keys.forEach(k => pipeline.del(k))
const results = await pipeline.exec()
const results = await this.deleteKeys(client, keys)
if (results) {
deletedCount += results.reduce((sum, [, value]) => {
return sum + (typeof value === 'number' ? value : 0)
@@ -127,6 +125,132 @@ export class RedisService implements OnModuleDestroy {
return deletedCounts.reduce((sum, count) => sum + count, 0)
}
async getAndSet<T>(
key: string,
type: 'single',
callback: () => Promise<T>,
ttlSeconds?: number,
): Promise<MapperWrapper<T>>
async getAndSet<T>(
key: string,
type: 'list',
callback: () => Promise<T[]>,
ttlSeconds?: number,
): Promise<MapperWrapper<T>>
async getAndSet<T>(
key: string,
type: 'paginate',
callback: () => Promise<PaginatedCache<T>>,
ttlSeconds?: number,
): Promise<Paginated<T>>
async getAndSet<T>(
key: string,
type: 'single' | 'list' | 'paginate',
callback: () => Promise<T | T[] | PaginatedCache<T>>,
ttlSeconds?: number,
): Promise<MapperWrapper<T> | Paginated<T>> {
switch (type) {
case 'single':
return this.getAndSetSingle(key, callback as () => Promise<T>, ttlSeconds)
case 'list':
return this.getAndSetList(key, callback as () => Promise<T[]>, ttlSeconds)
case 'paginate':
return this.getAndSetPaginate(
key,
callback as () => Promise<PaginatedCache<T>>,
ttlSeconds,
)
default: {
const neverType: never = type
throw new Error(`Unsupported cache type: ${neverType}`)
}
}
}
private async getAndSetSingle<T>(
key: string,
callback: () => Promise<T>,
ttlSeconds?: number,
): Promise<MapperWrapper<T>> {
const cached = await this.tryReadJson<T>(key)
if (cached !== null) {
return ResponseMapper.single(cached)
}
const data = await callback()
await this.tryWriteJson(key, data, ttlSeconds)
return ResponseMapper.single(data)
}
private async getAndSetList<T>(
key: string,
callback: () => Promise<T[]>,
ttlSeconds?: number,
): Promise<MapperWrapper<T>> {
const cached = await this.tryReadJson<T[]>(key)
if (cached !== null) {
return ResponseMapper.list(cached)
}
const data = await callback()
await this.tryWriteJson(key, data, ttlSeconds)
return ResponseMapper.list(data)
}
private async getAndSetPaginate<T>(
key: string,
callback: () => Promise<PaginatedCache<T>>,
ttlSeconds?: number,
): Promise<Paginated<T>> {
const cached = await this.tryReadJson<PaginatedCache<T>>(key)
if (cached !== null) {
return ResponseMapper.paginate(cached.items, {
total: cached.total,
page: cached.page,
perPage: cached.perPage,
})
}
const data = await callback()
await this.tryWriteJson(key, data, ttlSeconds)
return ResponseMapper.paginate(data.items, {
total: data.total,
page: data.page,
perPage: data.perPage,
})
}
private async tryReadJson<T>(key: string): Promise<T | null> {
try {
return await this.getJson<T>(key)
} catch (error) {
this.logger.warn(`Redis read failed for "${key}": ${(error as Error).message}`)
return null
}
}
private async tryWriteJson(
key: string,
value: unknown,
ttlSeconds: number = 300,
): Promise<void> {
try {
await this.setJson(key, value, ttlSeconds)
} catch (error) {
this.logger.warn(`Redis write failed for "${key}": ${(error as Error).message}`)
}
}
private async deleteKeys(
client: Redis,
keys: string[],
): Promise<Array<[Error | null, unknown]>> {
const pipeline = client.pipeline()
keys.forEach(key => pipeline.del(key))
const results = await pipeline.exec()
return results ?? []
}
async onModuleDestroy() {
await this.client.quit()
}