Add SMS OTP, harden auth, and fix order/checkout server bugs.

Ship 4-digit OTP with rate-limit attempts, Tehran-safe expiry/rass math, larger JSON body limit for check images, and safer order pricing/status guards. Include rebuilt dist for prebuilt deploy.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-08 14:55:26 +03:30
co-authored by Cursor
parent b121797263
commit 345a4a4708
100 changed files with 1476 additions and 353 deletions
+14 -1
View File
@@ -18,8 +18,21 @@ RUN_SEED=false
JWT_SECRET=change-me-to-a-long-random-string
JWT_EXPIRES_IN=7d
MOCK_OTP_CODE=123456
MOCK_OTP_CODE=1234
OTP_TTL_MINUTES=5
# پیامک OTP (مثل آبشده خانگی — rayegansms / createsms)
SMS_ENABLED=true
SMS_API_URL=http://185.231.112.101/api/createsms
SMS_SECRET_KEY=your-sms-secret-key
SMS_PLATFORM=rayegansms
SMS_HOST=پارچه
SMS_APP_NAME=پارچه
# سقف حجم بدنه JSON (تصاویر چک و رسید base64 هستند)
BODY_LIMIT=25mb
TZ=Asia/Tehran
NODE_ENV=production
NPM_REGISTRY=https://registry.npmmirror.com
COMPOSE_BAKE=false
+1
View File
@@ -3,6 +3,7 @@ FROM node:22-bookworm
WORKDIR /app
ENV NODE_ENV=production
ENV TZ=Asia/Tehran
COPY deploy-bundle.tar.gz /tmp/deploy-bundle.tar.gz
RUN tar -xzf /tmp/deploy-bundle.tar.gz -C /app \
+1
View File
@@ -5,6 +5,7 @@ FROM node:22-alpine
WORKDIR /app
ENV NODE_ENV=production
ENV TZ=Asia/Tehran
COPY package.json package-lock.json ./
COPY node_modules ./node_modules
+8 -2
View File
@@ -60,7 +60,7 @@ RUN_SEED=true docker compose up -d
| نقش | ورود | رمز / OTP |
|------|------|-----------|
| ادمین | `09121112222` | `admin123` |
| مشتری | `09121234567` | OTP: `123456` |
| مشتری | `09121234567` | OTP پیامکی (۴ رقم) — با `SMS_ENABLED=false` کد ثابت: `1234` |
## متغیرهای محیطی
@@ -71,8 +71,14 @@ DATABASE_URL=postgresql://fabric:fabric123@localhost:5432/fabric_trade?schema=pu
JWT_SECRET=fabric-trade-dev-secret-change-me
JWT_EXPIRES_IN=7d
PORT=3000
MOCK_OTP_CODE=123456
MOCK_OTP_CODE=1234
OTP_TTL_MINUTES=5
SMS_ENABLED=true
SMS_API_URL=http://185.231.112.101/api/createsms
SMS_SECRET_KEY=...
SMS_PLATFORM=rayegansms
SMS_HOST=پارچه
SMS_APP_NAME=پارچه
```
## اسکریپت‌ها
+4 -2
View File
@@ -86,7 +86,8 @@ let AdminUsersService = class AdminUsersService {
return this.map(user);
}
catch (e) {
if (e instanceof client_1.Prisma.PrismaClientKnownRequestError && e.code === 'P2002') {
if (e instanceof client_1.Prisma.PrismaClientKnownRequestError &&
e.code === 'P2002') {
throw new common_1.ConflictException('شماره یا ایمیل تکراری است');
}
throw e;
@@ -118,7 +119,8 @@ let AdminUsersService = class AdminUsersService {
return this.map(user);
}
catch (e) {
if (e instanceof client_1.Prisma.PrismaClientKnownRequestError && e.code === 'P2002') {
if (e instanceof client_1.Prisma.PrismaClientKnownRequestError &&
e.code === 'P2002') {
throw new common_1.ConflictException('شماره یا ایمیل تکراری است');
}
throw e;
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"admin-users.service.js","sourceRoot":"","sources":["../../src/admin-users/admin-users.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,2CAKwB;AACxB,2CAAmD;AACnD,iDAAmC;AACnC,6DAAyD;AAEzD,iDAI+B;AAE/B,MAAM,gBAAgB,GAAG,UAAU,CAAC;AAG7B,IAAM,iBAAiB,GAAvB,MAAM,iBAAiB;IACC;IAA7B,YAA6B,MAAqB;QAArB,WAAM,GAAN,MAAM,CAAe;IAAG,CAAC;IAEtD,KAAK,CAAC,OAAO;QACX,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC;YACjD,OAAO,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE;SAC/B,CAAC,CAAC;QACH,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACvC,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,EAAU;QACtB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;QACvE,IAAI,CAAC,IAAI;YAAE,MAAM,IAAI,0BAAiB,CAAC,sBAAsB,CAAC,CAAC;QAC/D,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACxB,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,GAAuB;QAClC,MAAM,KAAK,GAAG,IAAA,sBAAc,EAAC,IAAA,uBAAe,EAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;QACzD,IAAI,CAAC,IAAA,oBAAY,EAAC,KAAK,CAAC,EAAE,CAAC;YACzB,MAAM,IAAI,4BAAmB,CAAC,0BAA0B,CAAC,CAAC;QAC5D,CAAC;QACD,MAAM,YAAY,GAAG,MAAM,MAAM,CAAC,IAAI,CACpC,GAAG,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,gBAAgB,EACxC,EAAE,CACH,CAAC;QAEF,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC;gBAC9C,IAAI,EAAE;oBACJ,QAAQ,EAAE,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE;oBAC7B,KAAK;oBACL,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE;oBACrC,YAAY;oBACZ,IAAI,EAAE,GAAG,CAAC,IAAI,IAAI,kBAAS,CAAC,KAAK;oBACjC,QAAQ,EAAE,GAAG,CAAC,QAAQ,IAAI,IAAI;iBAC/B;aACF,CAAC,CAAC;YACH,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACxB,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAI,CAAC,YAAY,eAAM,CAAC,6BAA6B,IAAI,CAAC,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;gBAC5E,MAAM,IAAI,0BAAiB,CAAC,2BAA2B,CAAC,CAAC;YAC3D,CAAC;YACD,MAAM,CAAC,CAAC;QACV,CAAC;IACH,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,EAAU,EAAE,GAAuB;QAC9C,MAAM,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACtB,MAAM,KAAK,GACT,GAAG,CAAC,KAAK,KAAK,SAAS;YACrB,CAAC,CAAC,IAAA,sBAAc,EAAC,IAAA,uBAAe,EAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YAC5C,CAAC,CAAC,SAAS,CAAC;QAChB,IAAI,KAAK,KAAK,SAAS,IAAI,CAAC,IAAA,oBAAY,EAAC,KAAK,CAAC,EAAE,CAAC;YAChD,MAAM,IAAI,4BAAmB,CAAC,0BAA0B,CAAC,CAAC;QAC5D,CAAC;QAED,MAAM,IAAI,GAAgC;YACxC,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,IAAI,EAAE;YAC9B,KAAK;YACL,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE;YACtC,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,QAAQ,EAAE,GAAG,CAAC,QAAQ;SACvB,CAAC;QACF,IAAI,GAAG,CAAC,QAAQ,EAAE,IAAI,EAAE,EAAE,CAAC;YACzB,IAAI,CAAC,YAAY,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;QACjE,CAAC;QAED,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC;gBAC9C,KAAK,EAAE,EAAE,EAAE,EAAE;gBACb,IAAI;aACL,CAAC,CAAC;YACH,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACxB,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAI,CAAC,YAAY,eAAM,CAAC,6BAA6B,IAAI,CAAC,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;gBAC5E,MAAM,IAAI,0BAAiB,CAAC,2BAA2B,CAAC,CAAC;YAC3D,CAAC;YACD,MAAM,CAAC,CAAC;QACV,CAAC;IACH,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,EAAU,EAAE,QAAiB;QAC3C,MAAM,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACtB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC;YAC9C,KAAK,EAAE,EAAE,EAAE,EAAE;YACb,IAAI,EAAE,EAAE,QAAQ,EAAE;SACnB,CAAC,CAAC;QACH,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACxB,CAAC;IAEO,KAAK,CAAC,MAAM,CAAC,EAAU;QAC7B,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;QACvE,IAAI,CAAC,IAAI;YAAE,MAAM,IAAI,0BAAiB,CAAC,sBAAsB,CAAC,CAAC;QAC/D,OAAO,IAAI,CAAC;IACd,CAAC;IAEO,GAAG,CAAC,IAUX;QACC,OAAO;YACL,EAAE,EAAE,IAAI,CAAC,EAAE;YACX,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,WAAW,EAAE,IAAI,IAAI;YACpD,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE;YACvC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE;SACxC,CAAC;IACJ,CAAC;CACF,CAAA;AAvHY,8CAAiB;4BAAjB,iBAAiB;IAD7B,IAAA,mBAAU,GAAE;qCAE0B,8BAAa;GADvC,iBAAiB,CAuH7B"}
{"version":3,"file":"admin-users.service.js","sourceRoot":"","sources":["../../src/admin-users/admin-users.service.ts"],"names":[],"mappings":"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"}
+1 -1
View File
@@ -9,10 +9,10 @@ export declare class AuthController {
service: string;
};
requestOtp(dto: RequestOtpDto): Promise<{
debugCode?: string | undefined;
success: boolean;
message: string;
expiresAt: Date;
debugCode: string;
}>;
verifyOtp(dto: VerifyOtpDto): Promise<{
accessToken: string;
+4 -1
View File
@@ -12,17 +12,20 @@ const jwt_1 = require("@nestjs/jwt");
const config_1 = require("@nestjs/config");
const auth_service_1 = require("./auth.service");
const auth_controller_1 = require("./auth.controller");
const sms_module_1 = require("../sms/sms.module");
const jwt_secret_1 = require("../common/utils/jwt-secret");
let AuthModule = class AuthModule {
};
exports.AuthModule = AuthModule;
exports.AuthModule = AuthModule = __decorate([
(0, common_1.Module)({
imports: [
sms_module_1.SmsModule,
jwt_1.JwtModule.registerAsync({
imports: [config_1.ConfigModule],
inject: [config_1.ConfigService],
useFactory: (config) => ({
secret: config.get('JWT_SECRET', 'fabric-trade-dev-secret'),
secret: (0, jwt_secret_1.resolveJwtSecret)(config),
signOptions: {
expiresIn: config.get('JWT_EXPIRES_IN', '7d'),
},
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"auth.module.js","sourceRoot":"","sources":["../../src/auth/auth.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,qCAAwC;AACxC,2CAA6D;AAC7D,iDAA6C;AAC7C,uDAAmD;AAmB5C,IAAM,UAAU,GAAhB,MAAM,UAAU;CAAG,CAAA;AAAb,gCAAU;qBAAV,UAAU;IAjBtB,IAAA,eAAM,EAAC;QACN,OAAO,EAAE;YACP,eAAS,CAAC,aAAa,CAAC;gBACtB,OAAO,EAAE,CAAC,qBAAY,CAAC;gBACvB,MAAM,EAAE,CAAC,sBAAa,CAAC;gBACvB,UAAU,EAAE,CAAC,MAAqB,EAAE,EAAE,CAAC,CAAC;oBACtC,MAAM,EAAE,MAAM,CAAC,GAAG,CAAS,YAAY,EAAE,yBAAyB,CAAC;oBACnE,WAAW,EAAE;wBACX,SAAS,EAAE,MAAM,CAAC,GAAG,CAAC,gBAAgB,EAAE,IAAI,CAAiB;qBAC9D;iBACF,CAAC;aACH,CAAC;SACH;QACD,WAAW,EAAE,CAAC,gCAAc,CAAC;QAC7B,SAAS,EAAE,CAAC,0BAAW,CAAC;QACxB,OAAO,EAAE,CAAC,0BAAW,EAAE,eAAS,CAAC;KAClC,CAAC;GACW,UAAU,CAAG"}
{"version":3,"file":"auth.module.js","sourceRoot":"","sources":["../../src/auth/auth.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,qCAAwC;AACxC,2CAA6D;AAC7D,iDAA6C;AAC7C,uDAAmD;AACnD,kDAA8C;AAC9C,2DAA8D;AAoBvD,IAAM,UAAU,GAAhB,MAAM,UAAU;CAAG,CAAA;AAAb,gCAAU;qBAAV,UAAU;IAlBtB,IAAA,eAAM,EAAC;QACN,OAAO,EAAE;YACP,sBAAS;YACT,eAAS,CAAC,aAAa,CAAC;gBACtB,OAAO,EAAE,CAAC,qBAAY,CAAC;gBACvB,MAAM,EAAE,CAAC,sBAAa,CAAC;gBACvB,UAAU,EAAE,CAAC,MAAqB,EAAE,EAAE,CAAC,CAAC;oBACtC,MAAM,EAAE,IAAA,6BAAgB,EAAC,MAAM,CAAC;oBAChC,WAAW,EAAE;wBACX,SAAS,EAAE,MAAM,CAAC,GAAG,CAAC,gBAAgB,EAAE,IAAI,CAAC;qBAC9C;iBACF,CAAC;aACH,CAAC;SACH;QACD,WAAW,EAAE,CAAC,gCAAc,CAAC;QAC7B,SAAS,EAAE,CAAC,0BAAW,CAAC;QACxB,OAAO,EAAE,CAAC,0BAAW,EAAE,eAAS,CAAC;KAClC,CAAC;GACW,UAAU,CAAG"}
+5 -2
View File
@@ -1,18 +1,21 @@
import { ConfigService } from '@nestjs/config';
import { JwtService } from '@nestjs/jwt';
import { PrismaService } from '../prisma/prisma.service';
import { SmsService } from '../sms/sms.service';
import { AdminLoginDto, RequestOtpDto, UpdateProfileDto, VerifyOtpDto } from './dto/auth.dto';
export declare class AuthService {
private readonly prisma;
private readonly jwt;
private readonly config;
constructor(prisma: PrismaService, jwt: JwtService, config: ConfigService);
private readonly sms;
constructor(prisma: PrismaService, jwt: JwtService, config: ConfigService, sms: SmsService);
requestOtp(dto: RequestOtpDto): Promise<{
debugCode?: string | undefined;
success: boolean;
message: string;
expiresAt: Date;
debugCode: string;
}>;
private exposesDebugCode;
verifyOtp(dto: VerifyOtpDto): Promise<{
accessToken: string;
user: {
+62 -17
View File
@@ -46,24 +46,31 @@ exports.AuthService = void 0;
const common_1 = require("@nestjs/common");
const config_1 = require("@nestjs/config");
const jwt_1 = require("@nestjs/jwt");
const node_crypto_1 = require("node:crypto");
const bcrypt = __importStar(require("bcryptjs"));
const prisma_service_1 = require("../prisma/prisma.service");
const sms_service_1 = require("../sms/sms.service");
const phone_1 = require("../common/utils/phone");
const MAX_OTP_ATTEMPTS = 5;
let AuthService = class AuthService {
prisma;
jwt;
config;
constructor(prisma, jwt, config) {
sms;
constructor(prisma, jwt, config, sms) {
this.prisma = prisma;
this.jwt = jwt;
this.config = config;
this.sms = sms;
}
async requestOtp(dto) {
const phone = (0, phone_1.normalizePhone)((0, phone_1.toEnglishDigits)(dto.phone));
if (!(0, phone_1.isValidPhone)(phone)) {
throw new common_1.BadRequestException('شماره موبایل نامعتبر است');
}
const existing = await this.prisma.customer.findUnique({ where: { phone } });
const existing = await this.prisma.customer.findUnique({
where: { phone },
});
const isRegister = Boolean(dto.isRegister);
if (isRegister) {
if (!dto.firstName?.trim() || !dto.lastName?.trim()) {
@@ -76,27 +83,49 @@ let AuthService = class AuthService {
else if (!existing) {
throw new common_1.BadRequestException('کاربری با این شماره یافت نشد');
}
const code = this.config.get('MOCK_OTP_CODE', '123456');
else if (!existing.isActive) {
throw new common_1.UnauthorizedException('حساب کاربری شما غیرفعال است');
}
const smsEnabled = this.sms.isEnabled();
const code = smsEnabled
? String((0, node_crypto_1.randomInt)(1000, 10000))
: this.config.get('MOCK_OTP_CODE', '1234');
const ttl = Number(this.config.get('OTP_TTL_MINUTES', 5));
const expiresAt = new Date(Date.now() + ttl * 60_000);
await this.prisma.otpChallenge.deleteMany({ where: { phone } });
await this.prisma.otpChallenge.create({
data: {
phone,
code,
firstName: dto.firstName?.trim(),
lastName: dto.lastName?.trim(),
isRegister,
expiresAt,
},
const challenge = await this.prisma.$transaction(async (tx) => {
await tx.otpChallenge.deleteMany({ where: { phone } });
return tx.otpChallenge.create({
data: {
phone,
code,
firstName: dto.firstName?.trim(),
lastName: dto.lastName?.trim(),
isRegister,
expiresAt,
},
});
});
if (smsEnabled) {
const sent = await this.sms.send(phone, this.sms.buildOtpMessage(code));
if (!sent.success) {
await this.prisma.otpChallenge.deleteMany({
where: { id: challenge.id },
});
throw new common_1.ServiceUnavailableException('ارسال پیامک با خطا مواجه شد؛ دوباره تلاش کنید');
}
}
return {
success: true,
message: 'کد تأیید ارسال شد',
expiresAt,
debugCode: code,
...(this.exposesDebugCode(smsEnabled) ? { debugCode: code } : {}),
};
}
exposesDebugCode(smsEnabled) {
if (smsEnabled)
return false;
return this.config.get('NODE_ENV') !== 'production';
}
async verifyOtp(dto) {
const phone = (0, phone_1.normalizePhone)((0, phone_1.toEnglishDigits)(dto.phone));
const code = (0, phone_1.toEnglishDigits)(dto.code).trim();
@@ -107,7 +136,15 @@ let AuthService = class AuthService {
if (!challenge || challenge.expiresAt < new Date()) {
throw new common_1.UnauthorizedException('کد منقضی شده است');
}
if (challenge.attempts >= MAX_OTP_ATTEMPTS) {
await this.prisma.otpChallenge.deleteMany({ where: { phone } });
throw new common_1.UnauthorizedException('تعداد تلاش‌های نادرست زیاد است؛ کد جدید بگیرید');
}
if (challenge.code !== code) {
await this.prisma.otpChallenge.update({
where: { id: challenge.id },
data: { attempts: { increment: 1 } },
});
throw new common_1.UnauthorizedException('کد تأیید نادرست است');
}
let user = await this.prisma.customer.findUnique({ where: { phone } });
@@ -126,6 +163,9 @@ let AuthService = class AuthService {
else if (!user) {
throw new common_1.UnauthorizedException('کاربر یافت نشد');
}
else if (!user.isActive) {
throw new common_1.UnauthorizedException('حساب کاربری شما غیرفعال است');
}
await this.prisma.otpChallenge.deleteMany({ where: { phone } });
const accessToken = await this.signCustomerToken(user.id, user.phone);
return {
@@ -166,7 +206,9 @@ let AuthService = class AuthService {
}
async me(userId, type) {
if (type === 'admin') {
const admin = await this.prisma.adminUser.findUnique({ where: { id: userId } });
const admin = await this.prisma.adminUser.findUnique({
where: { id: userId },
});
if (!admin)
throw new common_1.UnauthorizedException();
return {
@@ -177,7 +219,9 @@ let AuthService = class AuthService {
role: admin.role,
};
}
const user = await this.prisma.customer.findUnique({ where: { id: userId } });
const user = await this.prisma.customer.findUnique({
where: { id: userId },
});
if (!user)
throw new common_1.UnauthorizedException();
return this.mapCustomer(user);
@@ -216,6 +260,7 @@ exports.AuthService = AuthService = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [prisma_service_1.PrismaService,
jwt_1.JwtService,
config_1.ConfigService])
config_1.ConfigService,
sms_service_1.SmsService])
], AuthService);
//# sourceMappingURL=auth.service.js.map
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -48,7 +48,7 @@ __decorate([
], VerifyOtpDto.prototype, "phone", void 0);
__decorate([
(0, class_validator_1.IsString)(),
(0, class_validator_1.MinLength)(4),
(0, class_validator_1.Length)(4, 4),
__metadata("design:type", String)
], VerifyOtpDto.prototype, "code", void 0);
class AdminLoginDto {
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"auth.dto.js","sourceRoot":"","sources":["../../../src/auth/dto/auth.dto.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,qDAA6E;AAE7E,MAAa,aAAa;IAExB,KAAK,CAAU;IAIf,SAAS,CAAU;IAInB,QAAQ,CAAU;IAIlB,UAAU,CAAW;CACtB;AAfD,sCAeC;AAbC;IADC,IAAA,0BAAQ,GAAE;;4CACI;AAIf;IAFC,IAAA,4BAAU,GAAE;IACZ,IAAA,0BAAQ,GAAE;;gDACQ;AAInB;IAFC,IAAA,4BAAU,GAAE;IACZ,IAAA,0BAAQ,GAAE;;+CACO;AAIlB;IAFC,IAAA,4BAAU,GAAE;IACZ,IAAA,2BAAS,GAAE;;iDACS;AAGvB,MAAa,YAAY;IAEvB,KAAK,CAAU;IAIf,IAAI,CAAU;CACf;AAPD,oCAOC;AALC;IADC,IAAA,0BAAQ,GAAE;;2CACI;AAIf;IAFC,IAAA,0BAAQ,GAAE;IACV,IAAA,2BAAS,EAAC,CAAC,CAAC;;0CACC;AAGhB,MAAa,aAAa;IAExB,KAAK,CAAU;IAIf,QAAQ,CAAU;CACnB;AAPD,sCAOC;AALC;IADC,IAAA,0BAAQ,GAAE;;4CACI;AAIf;IAFC,IAAA,0BAAQ,GAAE;IACV,IAAA,2BAAS,EAAC,CAAC,CAAC;;+CACK;AAGpB,MAAa,gBAAgB;IAG3B,SAAS,CAAU;IAInB,QAAQ,CAAU;IAIlB,UAAU,CAAU;CACrB;AAZD,4CAYC;AATC;IAFC,IAAA,4BAAU,GAAE;IACZ,IAAA,0BAAQ,GAAE;;mDACQ;AAInB;IAFC,IAAA,4BAAU,GAAE;IACZ,IAAA,0BAAQ,GAAE;;kDACO;AAIlB;IAFC,IAAA,4BAAU,GAAE;IACZ,IAAA,0BAAQ,GAAE;;oDACS"}
{"version":3,"file":"auth.dto.js","sourceRoot":"","sources":["../../../src/auth/dto/auth.dto.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,qDAMyB;AAEzB,MAAa,aAAa;IAExB,KAAK,CAAU;IAIf,SAAS,CAAU;IAInB,QAAQ,CAAU;IAIlB,UAAU,CAAW;CACtB;AAfD,sCAeC;AAbC;IADC,IAAA,0BAAQ,GAAE;;4CACI;AAIf;IAFC,IAAA,4BAAU,GAAE;IACZ,IAAA,0BAAQ,GAAE;;gDACQ;AAInB;IAFC,IAAA,4BAAU,GAAE;IACZ,IAAA,0BAAQ,GAAE;;+CACO;AAIlB;IAFC,IAAA,4BAAU,GAAE;IACZ,IAAA,2BAAS,GAAE;;iDACS;AAGvB,MAAa,YAAY;IAEvB,KAAK,CAAU;IAIf,IAAI,CAAU;CACf;AAPD,oCAOC;AALC;IADC,IAAA,0BAAQ,GAAE;;2CACI;AAIf;IAFC,IAAA,0BAAQ,GAAE;IACV,IAAA,wBAAM,EAAC,CAAC,EAAE,CAAC,CAAC;;0CACC;AAGhB,MAAa,aAAa;IAExB,KAAK,CAAU;IAIf,QAAQ,CAAU;CACnB;AAPD,sCAOC;AALC;IADC,IAAA,0BAAQ,GAAE;;4CACI;AAIf;IAFC,IAAA,0BAAQ,GAAE;IACV,IAAA,2BAAS,EAAC,CAAC,CAAC;;+CACK;AAGpB,MAAa,gBAAgB;IAG3B,SAAS,CAAU;IAInB,QAAQ,CAAU;IAIlB,UAAU,CAAU;CACrB;AAZD,4CAYC;AATC;IAFC,IAAA,4BAAU,GAAE;IACZ,IAAA,0BAAQ,GAAE;;mDACQ;AAInB;IAFC,IAAA,4BAAU,GAAE;IACZ,IAAA,0BAAQ,GAAE;;kDACO;AAIlB;IAFC,IAAA,4BAAU,GAAE;IACZ,IAAA,0BAAQ,GAAE;;oDACS"}
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"carts.controller.js","sourceRoot":"","sources":["../../src/carts/carts.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAQwB;AACxB,mDAA+C;AAC/C,0EAAgE;AAChE,wFAA0E;AAE1E,6CAIwB;AAIjB,IAAM,eAAe,GAArB,MAAM,eAAe;IACG;IAA7B,YAA6B,YAA0B;QAA1B,iBAAY,GAAZ,YAAY,CAAc;IAAG,CAAC;IAG3D,OAAO,CAAgB,IAAmB;QACxC,OAAO,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC5C,CAAC;IAGD,OAAO,CACU,IAAmB,EAC1B,GAAmB;QAE3B,OAAO,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;IACjD,CAAC;IAGD,UAAU,CACO,IAAmB,EACjB,MAAc,EACvB,GAA8B;QAEtC,OAAO,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5D,CAAC;IAGD,UAAU,CACO,IAAmB,EACjB,MAAc;QAE/B,OAAO,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;IACvD,CAAC;IAGD,WAAW,CACM,IAAmB,EAC1B,GAAuB;QAE/B,OAAO,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;IACrD,CAAC;IAGD,KAAK,CAAgB,IAAmB;QACtC,OAAO,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC9C,CAAC;CACF,CAAA;AA7CY,0CAAe;AAI1B;IADC,IAAA,YAAG,GAAE;IACG,WAAA,IAAA,oCAAW,GAAE,CAAA;;;;8CAErB;AAGD;IADC,IAAA,aAAI,EAAC,OAAO,CAAC;IAEX,WAAA,IAAA,oCAAW,GAAE,CAAA;IACb,WAAA,IAAA,aAAI,GAAE,CAAA;;6CAAM,yBAAc;;8CAG5B;AAGD;IADC,IAAA,cAAK,EAAC,eAAe,CAAC;IAEpB,WAAA,IAAA,oCAAW,GAAE,CAAA;IACb,WAAA,IAAA,cAAK,EAAC,QAAQ,CAAC,CAAA;IACf,WAAA,IAAA,aAAI,GAAE,CAAA;;qDAAM,oCAAyB;;iDAGvC;AAGD;IADC,IAAA,eAAM,EAAC,eAAe,CAAC;IAErB,WAAA,IAAA,oCAAW,GAAE,CAAA;IACb,WAAA,IAAA,cAAK,EAAC,QAAQ,CAAC,CAAA;;;;iDAGjB;AAGD;IADC,IAAA,cAAK,EAAC,OAAO,CAAC;IAEZ,WAAA,IAAA,oCAAW,GAAE,CAAA;IACb,WAAA,IAAA,aAAI,GAAE,CAAA;;6CAAM,6BAAkB;;kDAGhC;AAGD;IADC,IAAA,eAAM,GAAE;IACF,WAAA,IAAA,oCAAW,GAAE,CAAA;;;;4CAEnB;0BA5CU,eAAe;IAF3B,IAAA,mBAAU,EAAC,OAAO,CAAC;IACnB,IAAA,0BAAQ,EAAC,UAAU,CAAC;qCAEwB,4BAAY;GAD5C,eAAe,CA6C3B"}
{"version":3,"file":"carts.controller.js","sourceRoot":"","sources":["../../src/carts/carts.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAQwB;AACxB,mDAA+C;AAC/C,0EAAgE;AAChE,wFAA0E;AAE1E,6CAIwB;AAIjB,IAAM,eAAe,GAArB,MAAM,eAAe;IACG;IAA7B,YAA6B,YAA0B;QAA1B,iBAAY,GAAZ,YAAY,CAAc;IAAG,CAAC;IAG3D,OAAO,CAAgB,IAAmB;QACxC,OAAO,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC5C,CAAC;IAGD,OAAO,CAAgB,IAAmB,EAAU,GAAmB;QACrE,OAAO,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;IACjD,CAAC;IAGD,UAAU,CACO,IAAmB,EACjB,MAAc,EACvB,GAA8B;QAEtC,OAAO,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5D,CAAC;IAGD,UAAU,CACO,IAAmB,EACjB,MAAc;QAE/B,OAAO,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;IACvD,CAAC;IAGD,WAAW,CACM,IAAmB,EAC1B,GAAuB;QAE/B,OAAO,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;IACrD,CAAC;IAGD,KAAK,CAAgB,IAAmB;QACtC,OAAO,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC9C,CAAC;CACF,CAAA;AA1CY,0CAAe;AAI1B;IADC,IAAA,YAAG,GAAE;IACG,WAAA,IAAA,oCAAW,GAAE,CAAA;;;;8CAErB;AAGD;IADC,IAAA,aAAI,EAAC,OAAO,CAAC;IACL,WAAA,IAAA,oCAAW,GAAE,CAAA;IAAuB,WAAA,IAAA,aAAI,GAAE,CAAA;;6CAAM,yBAAc;;8CAEtE;AAGD;IADC,IAAA,cAAK,EAAC,eAAe,CAAC;IAEpB,WAAA,IAAA,oCAAW,GAAE,CAAA;IACb,WAAA,IAAA,cAAK,EAAC,QAAQ,CAAC,CAAA;IACf,WAAA,IAAA,aAAI,GAAE,CAAA;;qDAAM,oCAAyB;;iDAGvC;AAGD;IADC,IAAA,eAAM,EAAC,eAAe,CAAC;IAErB,WAAA,IAAA,oCAAW,GAAE,CAAA;IACb,WAAA,IAAA,cAAK,EAAC,QAAQ,CAAC,CAAA;;;;iDAGjB;AAGD;IADC,IAAA,cAAK,EAAC,OAAO,CAAC;IAEZ,WAAA,IAAA,oCAAW,GAAE,CAAA;IACb,WAAA,IAAA,aAAI,GAAE,CAAA;;6CAAM,6BAAkB;;kDAGhC;AAGD;IADC,IAAA,eAAM,GAAE;IACF,WAAA,IAAA,oCAAW,GAAE,CAAA;;;;4CAEnB;0BAzCU,eAAe;IAF3B,IAAA,mBAAU,EAAC,OAAO,CAAC;IACnB,IAAA,0BAAQ,EAAC,UAAU,CAAC;qCAEwB,4BAAY;GAD5C,eAAe,CA0C3B"}
+1 -1
View File
File diff suppressed because one or more lines are too long
+15
View File
@@ -14,6 +14,18 @@ const common_1 = require("@nestjs/common");
const client_1 = require("@prisma/client");
const prisma_service_1 = require("../prisma/prisma.service");
const name_1 = require("../common/utils/name");
const RECEIPT_SUBMITTABLE_STATUSES = [
client_1.OrderStatus.awaiting_review,
client_1.OrderStatus.pricing,
client_1.OrderStatus.needs_correction,
client_1.OrderStatus.awaiting_settlement,
client_1.OrderStatus.awaiting_settlement_fix,
client_1.OrderStatus.cash_in_progress,
client_1.OrderStatus.cash_invoice_issued,
client_1.OrderStatus.awaiting_cash_payment,
client_1.OrderStatus.cash_payment_submitted,
client_1.OrderStatus.awaiting_cash_confirmation,
];
let CashPaymentsService = class CashPaymentsService {
prisma;
constructor(prisma) {
@@ -32,6 +44,9 @@ let CashPaymentsService = class CashPaymentsService {
if (order.settlementType !== client_1.SettlementType.cash) {
throw new common_1.BadRequestException('این سفارش تسویه نقدی نیست');
}
if (!RECEIPT_SUBMITTABLE_STATUSES.includes(order.status)) {
throw new common_1.BadRequestException('در وضعیت فعلی سفارش امکان ثبت رسید وجود ندارد');
}
if (order.cashInvoiceExpiresAt &&
order.cashInvoiceExpiresAt.getTime() < Date.now()) {
throw new common_1.BadRequestException('مهلت پرداخت فاکتور نقدی به پایان رسیده است');
File diff suppressed because one or more lines are too long
+4 -2
View File
@@ -68,7 +68,8 @@ let CatalogsService = class CatalogsService {
return this.map(catalog);
}
catch (e) {
if (e instanceof client_1.Prisma.PrismaClientKnownRequestError && e.code === 'P2002') {
if (e instanceof client_1.Prisma.PrismaClientKnownRequestError &&
e.code === 'P2002') {
throw new common_1.ConflictException('کد کاتالوگ در این شرکت تکراری است');
}
throw e;
@@ -96,7 +97,8 @@ let CatalogsService = class CatalogsService {
return this.map(catalog);
}
catch (e) {
if (e instanceof client_1.Prisma.PrismaClientKnownRequestError && e.code === 'P2002') {
if (e instanceof client_1.Prisma.PrismaClientKnownRequestError &&
e.code === 'P2002') {
throw new common_1.ConflictException('کد کاتالوگ در این شرکت تکراری است');
}
throw e;
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"catalogs.service.js","sourceRoot":"","sources":["../../src/catalogs/catalogs.service.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"catalogs.service.js","sourceRoot":"","sources":["../../src/catalogs/catalogs.service.ts"],"names":[],"mappings":"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"}
+6 -2
View File
@@ -19,7 +19,9 @@ let ChecksService = class ChecksService {
this.prisma = prisma;
}
async findByOrder(orderId) {
const order = await this.prisma.order.findUnique({ where: { id: orderId } });
const order = await this.prisma.order.findUnique({
where: { id: orderId },
});
if (!order)
throw new common_1.NotFoundException('سفارش یافت نشد');
const checks = await this.prisma.check.findMany({
@@ -45,7 +47,9 @@ let ChecksService = class ChecksService {
: check.notes,
},
});
const siblings = await tx.check.findMany({ where: { orderId: check.orderId } });
const siblings = await tx.check.findMany({
where: { orderId: check.orderId },
});
const allApproved = siblings.every((c) => c.status === client_1.CheckStatus.approved);
const anyRejected = siblings.some((c) => c.status === client_1.CheckStatus.rejected);
let nextStatus = null;
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"checks.service.js","sourceRoot":"","sources":["../../src/checks/checks.service.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"checks.service.js","sourceRoot":"","sources":["../../src/checks/checks.service.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAA+D;AAC/D,2CAA0D;AAC1D,6DAAyD;AAIlD,IAAM,aAAa,GAAnB,MAAM,aAAa;IACK;IAA7B,YAA6B,MAAqB;QAArB,WAAM,GAAN,MAAM,CAAe;IAAG,CAAC;IAEtD,KAAK,CAAC,WAAW,CAAC,OAAe;QAC/B,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC;YAC/C,KAAK,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE;SACvB,CAAC,CAAC;QACH,IAAI,CAAC,KAAK;YAAE,MAAM,IAAI,0BAAiB,CAAC,gBAAgB,CAAC,CAAC;QAE1D,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC;YAC9C,KAAK,EAAE,EAAE,OAAO,EAAE;YAClB,OAAO,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE;SACxB,CAAC,CAAC;QACH,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACxC,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,EAAU,EAAE,OAAe,EAAE,GAAyB;QACvE,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC;YAC/C,KAAK,EAAE,EAAE,EAAE,EAAE;YACb,OAAO,EAAE,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE;SAClD,CAAC,CAAC;QACH,IAAI,CAAC,KAAK;YAAE,MAAM,IAAI,0BAAiB,CAAC,aAAa,CAAC,CAAC;QAEvD,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;YAC1D,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC;gBACnC,KAAK,EAAE,EAAE,EAAE,EAAE;gBACb,IAAI,EAAE;oBACJ,MAAM,EAAE,GAAG,CAAC,MAAM;oBAClB,KAAK,EAAE,GAAG,CAAC,IAAI;wBACb,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;wBACpD,CAAC,CAAC,KAAK,CAAC,KAAK;iBAChB;aACF,CAAC,CAAC;YAEH,MAAM,QAAQ,GAAG,MAAM,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC;gBACvC,KAAK,EAAE,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE;aAClC,CAAC,CAAC;YACH,MAAM,WAAW,GAAG,QAAQ,CAAC,KAAK,CAChC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,oBAAW,CAAC,QAAQ,CACzC,CAAC;YACF,MAAM,WAAW,GAAG,QAAQ,CAAC,IAAI,CAC/B,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,oBAAW,CAAC,QAAQ,CACzC,CAAC;YAEF,IAAI,UAAU,GAAuB,IAAI,CAAC;YAC1C,IAAI,WAAW,EAAE,CAAC;gBAChB,UAAU,GAAG,oBAAW,CAAC,cAAc,CAAC;YAC1C,CAAC;iBAAM,IAAI,WAAW,EAAE,CAAC;gBACvB,UAAU,GAAG,oBAAW,CAAC,eAAe,CAAC;YAC3C,CAAC;iBAAM,IAAI,GAAG,CAAC,MAAM,KAAK,oBAAW,CAAC,QAAQ,EAAE,CAAC;gBAC/C,UAAU,GAAG,oBAAW,CAAC,eAAe,CAAC;YAC3C,CAAC;YAED,IAAI,UAAU,IAAI,UAAU,KAAK,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;gBACpD,MAAM,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC;oBACpB,KAAK,EAAE,EAAE,EAAE,EAAE,KAAK,CAAC,OAAO,EAAE;oBAC5B,IAAI,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE;iBAC7B,CAAC,CAAC;gBACH,MAAM,EAAE,CAAC,kBAAkB,CAAC,MAAM,CAAC;oBACjC,IAAI,EAAE;wBACJ,OAAO,EAAE,KAAK,CAAC,OAAO;wBACtB,UAAU,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM;wBAC9B,QAAQ,EAAE,UAAU;wBACpB,SAAS,EAAE,SAAS,OAAO,EAAE;wBAC7B,IAAI,EAAE,GAAG,CAAC,IAAI,IAAI,eAAe,GAAG,CAAC,MAAM,YAAY;qBACxD;iBACF,CAAC,CAAC;YACL,CAAC;YAED,OAAO,MAAM,CAAC;QAChB,CAAC,CAAC,CAAC;QAEH,OAAO,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC3B,CAAC;IAEO,GAAG,CAAC,CAoBX;QACC,OAAO;YACL,EAAE,EAAE,CAAC,CAAC,EAAE;YACR,OAAO,EAAE,CAAC,CAAC,OAAO;YAClB,GAAG,EAAE,CAAC,CAAC,GAAG;YACV,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE;YAChC,OAAO,EAAE,CAAC,CAAC,OAAO,IAAI,EAAE;YACxB,WAAW,EAAE,CAAC,CAAC,WAAW,IAAI,SAAS;YACvC,eAAe,EAAE,CAAC,CAAC,eAAe,IAAI,SAAS;YAC/C,cAAc,EAAE,CAAC,CAAC,cAAc,IAAI,SAAS;YAC7C,aAAa,EAAE,CAAC,CAAC,aAAa,IAAI,SAAS;YAC3C,QAAQ,EAAE,CAAC,CAAC,QAAQ,IAAI,EAAE;YAC1B,UAAU,EAAE,CAAC,CAAC,UAAU,IAAI,SAAS;YACrC,UAAU,EAAE,CAAC,CAAC,UAAU,IAAI,SAAS;YACrC,SAAS,EAAE,CAAC,CAAC,SAAS,IAAI,SAAS;YACnC,KAAK,EAAE,CAAC,CAAC,KAAK,IAAI,SAAS;YAC3B,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,SAAS,EAAE,CAAC,CAAC,SAAS,CAAC,WAAW,EAAE;YACpC,SAAS,EAAE,CAAC,CAAC,SAAS,CAAC,WAAW,EAAE;SACrC,CAAC;IACJ,CAAC;CACF,CAAA;AAtHY,sCAAa;wBAAb,aAAa;IADzB,IAAA,mBAAU,GAAE;qCAE0B,8BAAa;GADvC,aAAa,CAsHzB"}
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"current-user.decorator.js","sourceRoot":"","sources":["../../../src/common/decorators/current-user.decorator.ts"],"names":[],"mappings":";;;AAAA,2CAAwE;AAS3D,QAAA,WAAW,GAAG,IAAA,6BAAoB,EAC7C,CAAC,KAAc,EAAE,GAAqB,EAAiB,EAAE;IACvD,MAAM,OAAO,GAAG,GAAG,CAAC,YAAY,EAAE,CAAC,UAAU,EAAE,CAAC;IAChD,OAAO,OAAO,CAAC,IAAI,CAAC;AACtB,CAAC,CACF,CAAC"}
{"version":3,"file":"current-user.decorator.js","sourceRoot":"","sources":["../../../src/common/decorators/current-user.decorator.ts"],"names":[],"mappings":";;;AAAA,2CAAwE;AAS3D,QAAA,WAAW,GAAG,IAAA,6BAAoB,EAC7C,CAAC,KAAc,EAAE,GAAqB,EAAiB,EAAE;IACvD,MAAM,OAAO,GAAG,GAAG,CAAC,YAAY,EAAE,CAAC,UAAU,EAA2B,CAAC;IACzE,OAAO,OAAO,CAAC,IAAI,CAAC;AACtB,CAAC,CACF,CAAC"}
+2 -1
View File
@@ -15,6 +15,7 @@ const core_1 = require("@nestjs/core");
const jwt_1 = require("@nestjs/jwt");
const config_1 = require("@nestjs/config");
const auth_decorators_1 = require("../decorators/auth.decorators");
const jwt_secret_1 = require("../utils/jwt-secret");
let JwtAuthGuard = class JwtAuthGuard {
reflector;
jwtService;
@@ -40,7 +41,7 @@ let JwtAuthGuard = class JwtAuthGuard {
let payload;
try {
payload = await this.jwtService.verifyAsync(token, {
secret: this.config.get('JWT_SECRET'),
secret: (0, jwt_secret_1.resolveJwtSecret)(this.config),
});
}
catch {
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"jwt-auth.guard.js","sourceRoot":"","sources":["../../../src/common/guards/jwt-auth.guard.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAMwB;AACxB,uCAAyC;AACzC,qCAAyC;AACzC,2CAA+C;AAC/C,mEAIuC;AAIhC,IAAM,YAAY,GAAlB,MAAM,YAAY;IAEJ;IACA;IACA;IAHnB,YACmB,SAAoB,EACpB,UAAsB,EACtB,MAAqB;QAFrB,cAAS,GAAT,SAAS,CAAW;QACpB,eAAU,GAAV,UAAU,CAAY;QACtB,WAAM,GAAN,MAAM,CAAe;IACrC,CAAC;IAEJ,KAAK,CAAC,WAAW,CAAC,OAAyB;QACzC,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAAU,+BAAa,EAAE;YACxE,OAAO,CAAC,UAAU,EAAE;YACpB,OAAO,CAAC,QAAQ,EAAE;SACnB,CAAC,CAAC;QACH,IAAI,QAAQ;YAAE,OAAO,IAAI,CAAC;QAE1B,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,UAAU,EAAE,CAAC;QACpD,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,aAAmC,CAAC;QACvE,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YACvC,MAAM,IAAI,8BAAqB,CAAC,4BAA4B,CAAC,CAAC;QAChE,CAAC;QAED,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAClC,IAAI,OAAyC,CAAC;QAC9C,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,KAAK,EAAE;gBACjD,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAS,YAAY,CAAC;aAC9C,CAAC,CAAC;QACL,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,8BAAqB,CAAC,+BAA+B,CAAC,CAAC;QACnE,CAAC;QAED,MAAM,IAAI,GAAkB;YAC1B,EAAE,EAAE,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,EAAE;YAC7B,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,KAAK,EAAE,OAAO,CAAC,KAAK;SACrB,CAAC;QACF,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;QAEpB,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAC/C,+BAAa,EACb,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAC3C,CAAC;QACF,IAAI,QAAQ,IAAI,QAAQ,KAAK,KAAK,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC7D,MAAM,IAAI,2BAAkB,CAAC,kBAAkB,CAAC,CAAC;QACnD,CAAC;QAED,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAAW,2BAAS,EAAE;YAClE,OAAO,CAAC,UAAU,EAAE;YACpB,OAAO,CAAC,QAAQ,EAAE;SACnB,CAAC,CAAC;QACH,IAAI,KAAK,EAAE,MAAM,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;YAChE,MAAM,IAAI,2BAAkB,CAAC,sBAAsB,CAAC,CAAC;QACvD,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;CACF,CAAA;AAxDY,oCAAY;uBAAZ,YAAY;IADxB,IAAA,mBAAU,GAAE;qCAGmB,gBAAS;QACR,gBAAU;QACd,sBAAa;GAJ7B,YAAY,CAwDxB"}
{"version":3,"file":"jwt-auth.guard.js","sourceRoot":"","sources":["../../../src/common/guards/jwt-auth.guard.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAMwB;AACxB,uCAAyC;AACzC,qCAAyC;AACzC,2CAA+C;AAC/C,mEAIuC;AAEvC,oDAAuD;AAGhD,IAAM,YAAY,GAAlB,MAAM,YAAY;IAEJ;IACA;IACA;IAHnB,YACmB,SAAoB,EACpB,UAAsB,EACtB,MAAqB;QAFrB,cAAS,GAAT,SAAS,CAAW;QACpB,eAAU,GAAV,UAAU,CAAY;QACtB,WAAM,GAAN,MAAM,CAAe;IACrC,CAAC;IAEJ,KAAK,CAAC,WAAW,CAAC,OAAyB;QACzC,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAAU,+BAAa,EAAE;YACxE,OAAO,CAAC,UAAU,EAAE;YACpB,OAAO,CAAC,QAAQ,EAAE;SACnB,CAAC,CAAC;QACH,IAAI,QAAQ;YAAE,OAAO,IAAI,CAAC;QAE1B,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,UAAU,EAG7C,CAAC;QACL,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC;QACjD,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YACvC,MAAM,IAAI,8BAAqB,CAAC,4BAA4B,CAAC,CAAC;QAChE,CAAC;QAED,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAClC,IAAI,OAAyC,CAAC;QAC9C,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,KAAK,EAAE;gBACjD,MAAM,EAAE,IAAA,6BAAgB,EAAC,IAAI,CAAC,MAAM,CAAC;aACtC,CAAC,CAAC;QACL,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,8BAAqB,CAAC,+BAA+B,CAAC,CAAC;QACnE,CAAC;QAED,MAAM,IAAI,GAAkB;YAC1B,EAAE,EAAE,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,EAAE;YAC7B,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,KAAK,EAAE,OAAO,CAAC,KAAK;SACrB,CAAC;QACF,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;QAEpB,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAE/C,+BAAa,EAAE,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;QAC7D,IAAI,QAAQ,IAAI,QAAQ,KAAK,KAAK,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC7D,MAAM,IAAI,2BAAkB,CAAC,kBAAkB,CAAC,CAAC;QACnD,CAAC;QAED,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAAW,2BAAS,EAAE;YAClE,OAAO,CAAC,UAAU,EAAE;YACpB,OAAO,CAAC,QAAQ,EAAE;SACnB,CAAC,CAAC;QACH,IAAI,KAAK,EAAE,MAAM,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;YAChE,MAAM,IAAI,2BAAkB,CAAC,sBAAsB,CAAC,CAAC;QACvD,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;CACF,CAAA;AA1DY,oCAAY;uBAAZ,YAAY;IADxB,IAAA,mBAAU,GAAE;qCAGmB,gBAAS;QACR,gBAAU;QACd,sBAAa;GAJ7B,YAAY,CA0DxB"}
+3 -3
View File
@@ -1,14 +1,14 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.computeCashInvoiceExpiry = computeCashInvoiceExpiry;
const tehran_time_1 = require("./tehran-time");
function computeCashInvoiceExpiry(company) {
const now = new Date();
if (company.cashInvoiceValidUntilHour != null &&
Number.isFinite(company.cashInvoiceValidUntilHour)) {
const expires = new Date(now);
expires.setHours(company.cashInvoiceValidUntilHour, 0, 0, 0);
const expires = (0, tehran_time_1.tehranAtHour)(now, company.cashInvoiceValidUntilHour);
if (expires.getTime() <= now.getTime()) {
expires.setDate(expires.getDate() + 1);
return (0, tehran_time_1.tehranAtHour)((0, tehran_time_1.addDays)(now, 1), company.cashInvoiceValidUntilHour);
}
return expires;
}
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"cash-expiry.js","sourceRoot":"","sources":["../../../src/common/utils/cash-expiry.ts"],"names":[],"mappings":";;AAAA,4DAoBC;AApBD,SAAgB,wBAAwB,CAAC,OAGxC;IACC,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IACvB,IACE,OAAO,CAAC,yBAAyB,IAAI,IAAI;QACzC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,yBAAyB,CAAC,EAClD,CAAC;QACD,MAAM,OAAO,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC;QAC9B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,yBAAyB,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QAC7D,IAAI,OAAO,CAAC,OAAO,EAAE,IAAI,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC;YACvC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;QACzC,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,OAAO,IAAI,IAAI,CACb,GAAG,CAAC,OAAO,EAAE,GAAG,OAAO,CAAC,wBAAwB,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAClE,CAAC;AACJ,CAAC"}
{"version":3,"file":"cash-expiry.js","sourceRoot":"","sources":["../../../src/common/utils/cash-expiry.ts"],"names":[],"mappings":";;AAEA,4DAmBC;AArBD,+CAAsD;AAEtD,SAAgB,wBAAwB,CAAC,OAGxC;IACC,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IACvB,IACE,OAAO,CAAC,yBAAyB,IAAI,IAAI;QACzC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,yBAAyB,CAAC,EAClD,CAAC;QACD,MAAM,OAAO,GAAG,IAAA,0BAAY,EAAC,GAAG,EAAE,OAAO,CAAC,yBAAyB,CAAC,CAAC;QACrE,IAAI,OAAO,CAAC,OAAO,EAAE,IAAI,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC;YACvC,OAAO,IAAA,0BAAY,EAAC,IAAA,qBAAO,EAAC,GAAG,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,yBAAyB,CAAC,CAAC;QAC1E,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,OAAO,IAAI,IAAI,CACb,GAAG,CAAC,OAAO,EAAE,GAAG,OAAO,CAAC,wBAAwB,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAClE,CAAC;AACJ,CAAC"}
+5 -10
View File
@@ -1,11 +1,7 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.calculateCheckRass = calculateCheckRass;
function startOfDay(date) {
const d = new Date(date);
d.setHours(0, 0, 0, 0);
return d;
}
const tehran_time_1 = require("./tehran-time");
function calculateCheckRass(checks, baseDate = new Date()) {
if (checks.length === 0) {
return {
@@ -17,20 +13,19 @@ function calculateCheckRass(checks, baseDate = new Date()) {
rassDate: null,
};
}
const base = startOfDay(baseDate);
const base = (0, tehran_time_1.tehranCalendarDay)(baseDate);
let totalAmount = 0;
let weightedDays = 0;
const dueDates = [];
for (const check of checks) {
const due = startOfDay(new Date(check.dueDate));
const due = (0, tehran_time_1.calendarDayOf)(check.dueDate);
dueDates.push(due);
const days = Math.max(0, Math.round((due.getTime() - base.getTime()) / (1000 * 60 * 60 * 24)));
const days = Math.max(0, (0, tehran_time_1.diffInDays)(base, due));
totalAmount += check.amount;
weightedDays += check.amount * days;
}
const rassDays = totalAmount > 0 ? Math.round(weightedDays / totalAmount) : 0;
const rassDate = new Date(base);
rassDate.setDate(rassDate.getDate() + rassDays);
const rassDate = (0, tehran_time_1.addDays)(base, rassDays);
dueDates.sort((a, b) => a.getTime() - b.getTime());
return {
checkCount: checks.length,
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"check-rass.js","sourceRoot":"","sources":["../../../src/common/utils/check-rass.ts"],"names":[],"mappings":";;AAoBA,gDA4CC;AAlDD,SAAS,UAAU,CAAC,IAAU;IAC5B,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IACvB,OAAO,CAAC,CAAC;AACX,CAAC;AAED,SAAgB,kBAAkB,CAChC,MAAwB,EACxB,WAAiB,IAAI,IAAI,EAAE;IAE3B,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO;YACL,UAAU,EAAE,CAAC;YACb,WAAW,EAAE,CAAC;YACd,cAAc,EAAE,IAAI;YACpB,eAAe,EAAE,IAAI;YACrB,QAAQ,EAAE,CAAC;YACX,QAAQ,EAAE,IAAI;SACf,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;IAClC,IAAI,WAAW,GAAG,CAAC,CAAC;IACpB,IAAI,YAAY,GAAG,CAAC,CAAC;IACrB,MAAM,QAAQ,GAAW,EAAE,CAAC;IAE5B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,GAAG,GAAG,UAAU,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QAChD,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACnB,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CACnB,CAAC,EACD,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,IAAI,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CACrE,CAAC;QACF,WAAW,IAAI,KAAK,CAAC,MAAM,CAAC;QAC5B,YAAY,IAAI,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC;IACtC,CAAC;IAED,MAAM,QAAQ,GAAG,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9E,MAAM,QAAQ,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC;IAChC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,EAAE,GAAG,QAAQ,CAAC,CAAC;IAChD,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;IAEnD,OAAO;QACL,UAAU,EAAE,MAAM,CAAC,MAAM;QACzB,WAAW;QACX,cAAc,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,IAAI;QAClD,eAAe,EAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,IAAI;QACrE,QAAQ;QACR,QAAQ,EAAE,QAAQ,CAAC,WAAW,EAAE;KACjC,CAAC;AACJ,CAAC"}
{"version":3,"file":"check-rass.js","sourceRoot":"","sources":["../../../src/common/utils/check-rass.ts"],"names":[],"mappings":";;AAqBA,gDAwCC;AA/CD,+CAKuB;AAEvB,SAAgB,kBAAkB,CAChC,MAAwB,EACxB,WAAiB,IAAI,IAAI,EAAE;IAE3B,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO;YACL,UAAU,EAAE,CAAC;YACb,WAAW,EAAE,CAAC;YACd,cAAc,EAAE,IAAI;YACpB,eAAe,EAAE,IAAI;YACrB,QAAQ,EAAE,CAAC;YACX,QAAQ,EAAE,IAAI;SACf,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,IAAA,+BAAiB,EAAC,QAAQ,CAAC,CAAC;IACzC,IAAI,WAAW,GAAG,CAAC,CAAC;IACpB,IAAI,YAAY,GAAG,CAAC,CAAC;IACrB,MAAM,QAAQ,GAAW,EAAE,CAAC;IAE5B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,GAAG,GAAG,IAAA,2BAAa,EAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACzC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACnB,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAA,wBAAU,EAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC;QAChD,WAAW,IAAI,KAAK,CAAC,MAAM,CAAC;QAC5B,YAAY,IAAI,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC;IACtC,CAAC;IAED,MAAM,QAAQ,GAAG,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9E,MAAM,QAAQ,GAAG,IAAA,qBAAO,EAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACzC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;IAEnD,OAAO;QACL,UAAU,EAAE,MAAM,CAAC,MAAM;QACzB,WAAW;QACX,cAAc,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,IAAI;QAClD,eAAe,EAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,IAAI;QACrE,QAAQ;QACR,QAAQ,EAAE,QAAQ,CAAC,WAAW,EAAE;KACjC,CAAC;AACJ,CAAC"}
+2
View File
@@ -0,0 +1,2 @@
import { ConfigService } from '@nestjs/config';
export declare function resolveJwtSecret(config: ConfigService): string;
+14
View File
@@ -0,0 +1,14 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.resolveJwtSecret = resolveJwtSecret;
const DEV_FALLBACK = 'fabric-trade-dev-secret';
function resolveJwtSecret(config) {
const secret = config.get('JWT_SECRET')?.trim();
if (secret)
return secret;
if (config.get('NODE_ENV') === 'production') {
throw new Error('JWT_SECRET تنظیم نشده است');
}
return DEV_FALLBACK;
}
//# sourceMappingURL=jwt-secret.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"jwt-secret.js","sourceRoot":"","sources":["../../../src/common/utils/jwt-secret.ts"],"names":[],"mappings":";;AAOA,4CAQC;AAbD,MAAM,YAAY,GAAG,yBAAyB,CAAC;AAK/C,SAAgB,gBAAgB,CAAC,MAAqB;IACpD,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAS,YAAY,CAAC,EAAE,IAAI,EAAE,CAAC;IACxD,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAE1B,IAAI,MAAM,CAAC,GAAG,CAAS,UAAU,CAAC,KAAK,YAAY,EAAE,CAAC;QACpD,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;IAC/C,CAAC;IACD,OAAO,YAAY,CAAC;AACtB,CAAC"}
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"name.js","sourceRoot":"","sources":["../../../src/common/utils/name.ts"],"names":[],"mappings":";;AAAA,sCAgBC;AAED,oCAEC;AApBD,SAAgB,aAAa,CAAC,IAAY;IAIxC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACjD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;IAClD,CAAC;IACD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACjC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC,CAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;IAChD,CAAC;IACD,OAAO;QACL,SAAS,EAAE,KAAK,CAAC,CAAC,CAAE;QACpB,QAAQ,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;KACnC,CAAC;AACJ,CAAC;AAED,SAAgB,YAAY,CAAC,SAAiB,EAAE,QAAgB;IAC9D,OAAO,GAAG,SAAS,IAAI,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC;AAC3C,CAAC"}
{"version":3,"file":"name.js","sourceRoot":"","sources":["../../../src/common/utils/name.ts"],"names":[],"mappings":";;AAAA,sCAgBC;AAED,oCAEC;AApBD,SAAgB,aAAa,CAAC,IAAY;IAIxC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACjD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;IAClD,CAAC;IACD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACjC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;IAC/C,CAAC;IACD,OAAO;QACL,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC;QACnB,QAAQ,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;KACnC,CAAC;AACJ,CAAC;AAED,SAAgB,YAAY,CAAC,SAAiB,EAAE,QAAgB;IAC9D,OAAO,GAAG,SAAS,IAAI,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC;AAC3C,CAAC"}
+28 -4
View File
@@ -5,18 +5,40 @@ exports.resolveAdminStatusFilter = resolveAdminStatusFilter;
exports.toAdminStatus = toAdminStatus;
const client_1 = require("@prisma/client");
exports.ADMIN_STATUS_MAP = {
pending_review: [client_1.OrderStatus.awaiting_review, client_1.OrderStatus.pricing],
pending_review: [
client_1.OrderStatus.cart,
client_1.OrderStatus.awaiting_settlement,
client_1.OrderStatus.cash_in_progress,
client_1.OrderStatus.check_in_progress,
client_1.OrderStatus.submitted,
client_1.OrderStatus.awaiting_review,
client_1.OrderStatus.pricing,
client_1.OrderStatus.cash_invoice_issued,
client_1.OrderStatus.awaiting_cash_payment,
client_1.OrderStatus.cash_payment_submitted,
client_1.OrderStatus.awaiting_cash_confirmation,
],
pending_check: [client_1.OrderStatus.awaiting_check_review],
needs_correction: [client_1.OrderStatus.needs_correction],
check_correction: [client_1.OrderStatus.check_needs_fix],
needs_correction: [
client_1.OrderStatus.needs_correction,
client_1.OrderStatus.awaiting_settlement_fix,
],
check_correction: [client_1.OrderStatus.check_needs_fix, client_1.OrderStatus.check_rejected],
final_approval: [
client_1.OrderStatus.final_approved,
client_1.OrderStatus.checks_approved,
client_1.OrderStatus.cash_confirmed,
client_1.OrderStatus.preparing,
client_1.OrderStatus.ready_to_ship,
],
shipped: [client_1.OrderStatus.shipped],
delivered: [client_1.OrderStatus.delivered],
};
const TERMINAL_STATUSES = [
client_1.OrderStatus.cancelled,
client_1.OrderStatus.rejected,
client_1.OrderStatus.expired,
];
function resolveAdminStatusFilter(status) {
if (!status)
return undefined;
@@ -32,7 +54,9 @@ function toAdminStatus(status) {
if (list.includes(status))
return admin;
}
return status;
if (TERMINAL_STATUSES.includes(status))
return status;
return 'pending_review';
}
exports.ORDER_STATUS_LABELS = {
cart: 'سبد خرید',
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"order-status.js","sourceRoot":"","sources":["../../../src/common/utils/order-status.ts"],"names":[],"mappings":";;;AAiBA,4DASC;AAED,sCAKC;AAjCD,2CAA6C;AAGhC,QAAA,gBAAgB,GAAkC;IAC7D,cAAc,EAAE,CAAC,oBAAW,CAAC,eAAe,EAAE,oBAAW,CAAC,OAAO,CAAC;IAClE,aAAa,EAAE,CAAC,oBAAW,CAAC,qBAAqB,CAAC;IAClD,gBAAgB,EAAE,CAAC,oBAAW,CAAC,gBAAgB,CAAC;IAChD,gBAAgB,EAAE,CAAC,oBAAW,CAAC,eAAe,CAAC;IAC/C,cAAc,EAAE;QACd,oBAAW,CAAC,cAAc;QAC1B,oBAAW,CAAC,eAAe;QAC3B,oBAAW,CAAC,cAAc;KAC3B;IACD,OAAO,EAAE,CAAC,oBAAW,CAAC,OAAO,CAAC;IAC9B,SAAS,EAAE,CAAC,oBAAW,CAAC,SAAS,CAAC;CACnC,CAAC;AAEF,SAAgB,wBAAwB,CACtC,MAAe;IAEf,IAAI,CAAC,MAAM;QAAE,OAAO,SAAS,CAAC;IAC9B,IAAI,wBAAgB,CAAC,MAAM,CAAC;QAAE,OAAO,wBAAgB,CAAC,MAAM,CAAC,CAAC;IAC9D,IAAI,MAAM,CAAC,MAAM,CAAC,oBAAW,CAAC,CAAC,QAAQ,CAAC,MAAqB,CAAC,EAAE,CAAC;QAC/D,OAAO,CAAC,MAAqB,CAAC,CAAC;IACjC,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAgB,aAAa,CAAC,MAAmB;IAC/C,KAAK,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,wBAAgB,CAAC,EAAE,CAAC;QAC7D,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;YAAE,OAAO,KAAK,CAAC;IAC1C,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAEY,QAAA,mBAAmB,GAAgC;IAC9D,IAAI,EAAE,UAAU;IAChB,mBAAmB,EAAE,iBAAiB;IACtC,gBAAgB,EAAE,iBAAiB;IACnC,iBAAiB,EAAE,eAAe;IAClC,SAAS,EAAE,SAAS;IACpB,eAAe,EAAE,iBAAiB;IAClC,OAAO,EAAE,YAAY;IACrB,gBAAgB,EAAE,eAAe;IACjC,uBAAuB,EAAE,aAAa;IACtC,mBAAmB,EAAE,kBAAkB;IACvC,qBAAqB,EAAE,uBAAuB;IAC9C,sBAAsB,EAAE,qBAAqB;IAC7C,0BAA0B,EAAE,mBAAmB;IAC/C,cAAc,EAAE,sBAAsB;IACtC,qBAAqB,EAAE,UAAU;IACjC,eAAe,EAAE,UAAU;IAC3B,cAAc,EAAE,OAAO;IACvB,eAAe,EAAE,aAAa;IAC9B,cAAc,EAAE,aAAa;IAC7B,SAAS,EAAE,YAAY;IACvB,aAAa,EAAE,aAAa;IAC5B,OAAO,EAAE,WAAW;IACpB,SAAS,EAAE,WAAW;IACtB,SAAS,EAAE,SAAS;IACpB,QAAQ,EAAE,QAAQ;IAClB,OAAO,EAAE,OAAO;CACjB,CAAC"}
{"version":3,"file":"order-status.js","sourceRoot":"","sources":["../../../src/common/utils/order-status.ts"],"names":[],"mappings":"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"}
+5
View File
@@ -0,0 +1,5 @@
export declare function tehranCalendarDay(date: Date): Date;
export declare function calendarDayOf(date: Date | string): Date;
export declare function addDays(date: Date, days: number): Date;
export declare function diffInDays(from: Date, to: Date): number;
export declare function tehranAtHour(date: Date, hour: number): Date;
+32
View File
@@ -0,0 +1,32 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.tehranCalendarDay = tehranCalendarDay;
exports.calendarDayOf = calendarDayOf;
exports.addDays = addDays;
exports.diffInDays = diffInDays;
exports.tehranAtHour = tehranAtHour;
const TEHRAN_OFFSET_MS = (3 * 60 + 30) * 60 * 1000;
const DAY_MS = 24 * 60 * 60 * 1000;
function utcStartOfDay(date) {
const d = new Date(date);
d.setUTCHours(0, 0, 0, 0);
return d;
}
function tehranCalendarDay(date) {
return utcStartOfDay(new Date(date.getTime() + TEHRAN_OFFSET_MS));
}
function calendarDayOf(date) {
return utcStartOfDay(new Date(date));
}
function addDays(date, days) {
return new Date(date.getTime() + days * DAY_MS);
}
function diffInDays(from, to) {
return Math.round((to.getTime() - from.getTime()) / DAY_MS);
}
function tehranAtHour(date, hour) {
return new Date(tehranCalendarDay(date).getTime() +
hour * 60 * 60 * 1000 -
TEHRAN_OFFSET_MS);
}
//# sourceMappingURL=tehran-time.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"tehran-time.js","sourceRoot":"","sources":["../../../src/common/utils/tehran-time.ts"],"names":[],"mappings":";;AAiBA,8CAEC;AAGD,sCAEC;AAED,0BAEC;AAED,gCAEC;AAGD,oCAMC;AArCD,MAAM,gBAAgB,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;AACnD,MAAM,MAAM,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAEnC,SAAS,aAAa,CAAC,IAAU;IAC/B,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAC1B,OAAO,CAAC,CAAC;AACX,CAAC;AAMD,SAAgB,iBAAiB,CAAC,IAAU;IAC1C,OAAO,aAAa,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,gBAAgB,CAAC,CAAC,CAAC;AACpE,CAAC;AAGD,SAAgB,aAAa,CAAC,IAAmB;IAC/C,OAAO,aAAa,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AACvC,CAAC;AAED,SAAgB,OAAO,CAAC,IAAU,EAAE,IAAY;IAC9C,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,IAAI,GAAG,MAAM,CAAC,CAAC;AAClD,CAAC;AAED,SAAgB,UAAU,CAAC,IAAU,EAAE,EAAQ;IAC7C,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC;AAC9D,CAAC;AAGD,SAAgB,YAAY,CAAC,IAAU,EAAE,IAAY;IACnD,OAAO,IAAI,IAAI,CACb,iBAAiB,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE;QAC/B,IAAI,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI;QACrB,gBAAgB,CACnB,CAAC;AACJ,CAAC"}
+19 -7
View File
@@ -23,7 +23,9 @@ let CompaniesService = class CompaniesService {
where: activeOnly ? { isActive: true } : undefined,
orderBy: [{ displayOrder: 'asc' }, { name: 'asc' }],
include: {
_count: { select: { catalogs: true, products: true, bankAccounts: true } },
_count: {
select: { catalogs: true, products: true, bankAccounts: true },
},
},
});
return companies.map((c) => this.mapCompany(c));
@@ -33,7 +35,9 @@ let CompaniesService = class CompaniesService {
where: { id },
include: {
bankAccounts: { orderBy: { displayOrder: 'asc' } },
_count: { select: { catalogs: true, products: true, bankAccounts: true } },
_count: {
select: { catalogs: true, products: true, bankAccounts: true },
},
},
});
if (!company)
@@ -58,13 +62,16 @@ let CompaniesService = class CompaniesService {
isActive: dto.isActive ?? true,
},
include: {
_count: { select: { catalogs: true, products: true, bankAccounts: true } },
_count: {
select: { catalogs: true, products: true, bankAccounts: true },
},
},
});
return this.mapCompany(company);
}
catch (e) {
if (e instanceof client_1.Prisma.PrismaClientKnownRequestError && e.code === 'P2002') {
if (e instanceof client_1.Prisma.PrismaClientKnownRequestError &&
e.code === 'P2002') {
throw new common_1.ConflictException('اسلاگ شرکت تکراری است');
}
throw e;
@@ -89,13 +96,16 @@ let CompaniesService = class CompaniesService {
isActive: dto.isActive,
},
include: {
_count: { select: { catalogs: true, products: true, bankAccounts: true } },
_count: {
select: { catalogs: true, products: true, bankAccounts: true },
},
},
});
return this.mapCompany(company);
}
catch (e) {
if (e instanceof client_1.Prisma.PrismaClientKnownRequestError && e.code === 'P2002') {
if (e instanceof client_1.Prisma.PrismaClientKnownRequestError &&
e.code === 'P2002') {
throw new common_1.ConflictException('اسلاگ شرکت تکراری است');
}
throw e;
@@ -107,7 +117,9 @@ let CompaniesService = class CompaniesService {
where: { id },
data: { isActive },
include: {
_count: { select: { catalogs: true, products: true, bankAccounts: true } },
_count: {
select: { catalogs: true, products: true, bankAccounts: true },
},
},
});
return this.mapCompany(company);
File diff suppressed because one or more lines are too long
+7 -3
View File
@@ -84,7 +84,8 @@ let CustomersService = class CustomersService {
return this.map(customer);
}
catch (e) {
if (e instanceof client_1.Prisma.PrismaClientKnownRequestError && e.code === 'P2002') {
if (e instanceof client_1.Prisma.PrismaClientKnownRequestError &&
e.code === 'P2002') {
throw new common_1.ConflictException('این شماره قبلاً ثبت شده است');
}
throw e;
@@ -100,7 +101,9 @@ let CustomersService = class CustomersService {
}
let firstName;
let lastName;
if (dto.name !== undefined || dto.firstName !== undefined || dto.lastName !== undefined) {
if (dto.name !== undefined ||
dto.firstName !== undefined ||
dto.lastName !== undefined) {
const names = this.resolveNames(dto);
firstName = names.firstName;
lastName = names.lastName;
@@ -127,7 +130,8 @@ let CustomersService = class CustomersService {
return this.map(customer);
}
catch (e) {
if (e instanceof client_1.Prisma.PrismaClientKnownRequestError && e.code === 'P2002') {
if (e instanceof client_1.Prisma.PrismaClientKnownRequestError &&
e.code === 'P2002') {
throw new common_1.ConflictException('این شماره قبلاً ثبت شده است');
}
throw e;
File diff suppressed because one or more lines are too long
+6 -1
View File
@@ -186,7 +186,12 @@ let DashboardService = class DashboardService {
{ id: 'cd-today', label: 'امروز', tone: 'danger', days: 0 },
{ id: 'cd-3', label: '۳ روز آینده', tone: 'warning', days: 3 },
{ id: 'cd-7', label: '۷ روز آینده', tone: 'warning', days: 7 },
{ id: 'cd-30', label: '۳۰ روز آینده', tone: 'neutral', days: 30 },
{
id: 'cd-30',
label: '۳۰ روز آینده',
tone: 'neutral',
days: 30,
},
];
return buckets.map((bucket) => {
const end = new Date(startOfToday);
File diff suppressed because one or more lines are too long
+5 -1
View File
@@ -3,9 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
const core_1 = require("@nestjs/core");
const common_1 = require("@nestjs/common");
const swagger_1 = require("@nestjs/swagger");
const express_1 = require("express");
const app_module_1 = require("./app.module");
async function bootstrap() {
const app = await core_1.NestFactory.create(app_module_1.AppModule);
const bodyLimit = process.env.BODY_LIMIT || '25mb';
app.use((0, express_1.json)({ limit: bodyLimit }));
app.use((0, express_1.urlencoded)({ extended: true, limit: bodyLimit }));
const globalPrefix = process.env.GLOBAL_PREFIX || 'api';
app.setGlobalPrefix(globalPrefix);
app.enableCors({
@@ -31,5 +35,5 @@ async function bootstrap() {
console.log(`Fabric Trade API listening on http://localhost:${port}/${globalPrefix}`);
console.log(`Swagger docs at http://localhost:${port}/${globalPrefix}/docs`);
}
bootstrap();
void bootstrap();
//# sourceMappingURL=main.js.map
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";;AAAA,uCAA2C;AAC3C,2CAAgD;AAChD,6CAAiE;AACjE,6CAAyC;AAEzC,KAAK,UAAU,SAAS;IACtB,MAAM,GAAG,GAAG,MAAM,kBAAW,CAAC,MAAM,CAAC,sBAAS,CAAC,CAAC;IAGhD,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,KAAK,CAAC;IACxD,GAAG,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC;IAClC,GAAG,CAAC,UAAU,CAAC;QACb,MAAM,EAAE,IAAI;QACZ,WAAW,EAAE,IAAI;KAClB,CAAC,CAAC;IACH,GAAG,CAAC,cAAc,CAChB,IAAI,uBAAc,CAAC;QACjB,SAAS,EAAE,IAAI;QACf,SAAS,EAAE,IAAI;QACf,oBAAoB,EAAE,IAAI;QAC1B,gBAAgB,EAAE,EAAE,wBAAwB,EAAE,IAAI,EAAE;KACrD,CAAC,CACH,CAAC;IAEF,MAAM,aAAa,GAAG,IAAI,yBAAe,EAAE;SACxC,QAAQ,CAAC,kBAAkB,CAAC;SAC5B,cAAc,CAAC,sBAAsB,CAAC;SACtC,UAAU,CAAC,KAAK,CAAC;SACjB,aAAa,EAAE;SACf,KAAK,EAAE,CAAC;IACX,MAAM,QAAQ,GAAG,uBAAa,CAAC,cAAc,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;IAClE,uBAAa,CAAC,KAAK,CAAC,GAAG,YAAY,OAAO,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC;IAE3D,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,IAAI,CAAC;IACtC,MAAM,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACvB,OAAO,CAAC,GAAG,CAAC,kDAAkD,IAAI,IAAI,YAAY,EAAE,CAAC,CAAC;IACtF,OAAO,CAAC,GAAG,CAAC,oCAAoC,IAAI,IAAI,YAAY,OAAO,CAAC,CAAC;AAC/E,CAAC;AACD,SAAS,EAAE,CAAC"}
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";;AAAA,uCAA2C;AAC3C,2CAAgD;AAChD,6CAAiE;AACjE,qCAA2C;AAC3C,6CAAyC;AAEzC,KAAK,UAAU,SAAS;IACtB,MAAM,GAAG,GAAG,MAAM,kBAAW,CAAC,MAAM,CAAC,sBAAS,CAAC,CAAC;IAGhD,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,MAAM,CAAC;IACnD,GAAG,CAAC,GAAG,CAAC,IAAA,cAAI,EAAC,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;IACpC,GAAG,CAAC,GAAG,CAAC,IAAA,oBAAU,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;IAG1D,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,KAAK,CAAC;IACxD,GAAG,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC;IAClC,GAAG,CAAC,UAAU,CAAC;QACb,MAAM,EAAE,IAAI;QACZ,WAAW,EAAE,IAAI;KAClB,CAAC,CAAC;IACH,GAAG,CAAC,cAAc,CAChB,IAAI,uBAAc,CAAC;QACjB,SAAS,EAAE,IAAI;QACf,SAAS,EAAE,IAAI;QACf,oBAAoB,EAAE,IAAI;QAC1B,gBAAgB,EAAE,EAAE,wBAAwB,EAAE,IAAI,EAAE;KACrD,CAAC,CACH,CAAC;IAEF,MAAM,aAAa,GAAG,IAAI,yBAAe,EAAE;SACxC,QAAQ,CAAC,kBAAkB,CAAC;SAC5B,cAAc,CAAC,sBAAsB,CAAC;SACtC,UAAU,CAAC,KAAK,CAAC;SACjB,aAAa,EAAE;SACf,KAAK,EAAE,CAAC;IACX,MAAM,QAAQ,GAAG,uBAAa,CAAC,cAAc,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;IAClE,uBAAa,CAAC,KAAK,CAAC,GAAG,YAAY,OAAO,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC;IAE3D,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,IAAI,CAAC;IACtC,MAAM,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACvB,OAAO,CAAC,GAAG,CACT,kDAAkD,IAAI,IAAI,YAAY,EAAE,CACzE,CAAC;IACF,OAAO,CAAC,GAAG,CAAC,oCAAoC,IAAI,IAAI,YAAY,OAAO,CAAC,CAAC;AAC/E,CAAC;AACD,KAAK,SAAS,EAAE,CAAC"}
+2
View File
@@ -2,6 +2,7 @@ import { CheckRegistrationMode, OrderStatus, SettlementType } from '@prisma/clie
export declare class SubmitOrderItemDto {
productId: string;
meterage: number;
requestedMeterage?: number;
notes?: string;
}
export declare class SubmitOrderCheckDto {
@@ -22,6 +23,7 @@ export declare class SubmitOrderCheckDto {
export declare class SubmitOrderDto {
companyId: string;
settlementType: SettlementType;
settlementMethod?: SettlementType;
checkMode?: CheckRegistrationMode;
notes?: string;
items: SubmitOrderItemDto[];
+13
View File
@@ -16,6 +16,7 @@ const client_1 = require("@prisma/client");
class SubmitOrderItemDto {
productId;
meterage;
requestedMeterage;
notes;
}
exports.SubmitOrderItemDto = SubmitOrderItemDto;
@@ -29,6 +30,12 @@ __decorate([
(0, class_validator_1.Min)(0.001),
__metadata("design:type", Number)
], SubmitOrderItemDto.prototype, "meterage", void 0);
__decorate([
(0, class_validator_1.IsOptional)(),
(0, class_transformer_1.Type)(() => Number),
(0, class_validator_1.IsNumber)(),
__metadata("design:type", Number)
], SubmitOrderItemDto.prototype, "requestedMeterage", void 0);
__decorate([
(0, class_validator_1.IsOptional)(),
(0, class_validator_1.IsString)(),
@@ -118,6 +125,7 @@ __decorate([
class SubmitOrderDto {
companyId;
settlementType;
settlementMethod;
checkMode;
notes;
items;
@@ -132,6 +140,11 @@ __decorate([
(0, class_validator_1.IsEnum)(client_1.SettlementType),
__metadata("design:type", String)
], SubmitOrderDto.prototype, "settlementType", void 0);
__decorate([
(0, class_validator_1.IsOptional)(),
(0, class_validator_1.IsEnum)(client_1.SettlementType),
__metadata("design:type", String)
], SubmitOrderDto.prototype, "settlementMethod", void 0);
__decorate([
(0, class_validator_1.IsOptional)(),
(0, class_validator_1.IsEnum)(client_1.CheckRegistrationMode),
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"order.dto.js","sourceRoot":"","sources":["../../../src/orders/dto/order.dto.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"order.dto.js","sourceRoot":"","sources":["../../../src/orders/dto/order.dto.ts"],"names":[],"mappings":"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"}
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"orders.controller.js","sourceRoot":"","sources":["../../src/orders/orders.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAQwB;AACxB,qDAAiD;AACjD,0EAAgE;AAChE,wFAA0E;AAE1E,+CAMyB;AAGlB,IAAM,wBAAwB,GAA9B,MAAM,wBAAwB;IACN;IAA7B,YAA6B,aAA4B;QAA5B,kBAAa,GAAb,aAAa,CAAe;IAAG,CAAC;IAI7D,QAAQ,CAAgB,IAAmB;QACzC,OAAO,IAAI,CAAC,aAAa,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAClD,CAAC;IAID,OAAO,CACU,IAAmB,EACrB,EAAU;QAEvB,OAAO,IAAI,CAAC,aAAa,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;IACrD,CAAC;IAID,MAAM,CACW,IAAmB,EAC1B,GAAmB;QAE3B,OAAO,IAAI,CAAC,aAAa,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;IACtD,CAAC;IAID,YAAY,CACK,IAAmB,EACrB,EAAU,EACf,GAAyB;QAEjC,OAAO,IAAI,CAAC,aAAa,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC;IAC3D,CAAC;CACF,CAAA;AApCY,4DAAwB;AAKnC;IAFC,IAAA,0BAAQ,EAAC,UAAU,CAAC;IACpB,IAAA,YAAG,GAAE;IACI,WAAA,IAAA,oCAAW,GAAE,CAAA;;;;wDAEtB;AAID;IAFC,IAAA,0BAAQ,EAAC,UAAU,CAAC;IACpB,IAAA,YAAG,EAAC,KAAK,CAAC;IAER,WAAA,IAAA,oCAAW,GAAE,CAAA;IACb,WAAA,IAAA,cAAK,EAAC,IAAI,CAAC,CAAA;;;;uDAGb;AAID;IAFC,IAAA,0BAAQ,EAAC,UAAU,CAAC;IACpB,IAAA,aAAI,GAAE;IAEJ,WAAA,IAAA,oCAAW,GAAE,CAAA;IACb,WAAA,IAAA,aAAI,GAAE,CAAA;;6CAAM,0BAAc;;sDAG5B;AAID;IAFC,IAAA,0BAAQ,EAAC,UAAU,CAAC;IACpB,IAAA,cAAK,EAAC,YAAY,CAAC;IAEjB,WAAA,IAAA,oCAAW,GAAE,CAAA;IACb,WAAA,IAAA,cAAK,EAAC,IAAI,CAAC,CAAA;IACX,WAAA,IAAA,aAAI,GAAE,CAAA;;qDAAM,gCAAoB;;4DAGlC;mCAnCU,wBAAwB;IADpC,IAAA,mBAAU,EAAC,QAAQ,CAAC;qCAEyB,8BAAa;GAD9C,wBAAwB,CAoCpC;AAIM,IAAM,qBAAqB,GAA3B,MAAM,qBAAqB;IACH;IAA7B,YAA6B,aAA4B;QAA5B,kBAAa,GAAb,aAAa,CAAe;IAAG,CAAC;IAG7D,OAAO,CAAkB,MAAe,EAAc,CAAU;QAC9D,OAAO,IAAI,CAAC,aAAa,CAAC,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;IAC3D,CAAC;IAGD,OAAO,CAAc,EAAU;QAC7B,OAAO,IAAI,CAAC,aAAa,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC;IAC/C,CAAC;IAGD,MAAM,CACW,IAAmB,EAC1B,GAAwB;QAEhC,OAAO,IAAI,CAAC,aAAa,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;IACtD,CAAC;IAGD,aAAa,CACI,IAAmB,EACrB,EAAU,EACf,GAA0B;QAElC,OAAO,IAAI,CAAC,aAAa,CAAC,aAAa,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;IAC5D,CAAC;IAGD,YAAY,CACK,IAAmB,EACrB,EAAU,EACf,GAAyB;QAEjC,OAAO,IAAI,CAAC,aAAa,CAAC,YAAY,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;IAC3D,CAAC;CACF,CAAA;AAtCY,sDAAqB;AAIhC;IADC,IAAA,YAAG,GAAE;IACG,WAAA,IAAA,cAAK,EAAC,QAAQ,CAAC,CAAA;IAAmB,WAAA,IAAA,cAAK,EAAC,GAAG,CAAC,CAAA;;;;oDAEpD;AAGD;IADC,IAAA,YAAG,EAAC,KAAK,CAAC;IACF,WAAA,IAAA,cAAK,EAAC,IAAI,CAAC,CAAA;;;;oDAEnB;AAGD;IADC,IAAA,aAAI,GAAE;IAEJ,WAAA,IAAA,oCAAW,GAAE,CAAA;IACb,WAAA,IAAA,aAAI,GAAE,CAAA;;6CAAM,+BAAmB;;mDAGjC;AAGD;IADC,IAAA,cAAK,EAAC,aAAa,CAAC;IAElB,WAAA,IAAA,oCAAW,GAAE,CAAA;IACb,WAAA,IAAA,cAAK,EAAC,IAAI,CAAC,CAAA;IACX,WAAA,IAAA,aAAI,GAAE,CAAA;;qDAAM,iCAAqB;;0DAGnC;AAGD;IADC,IAAA,cAAK,EAAC,YAAY,CAAC;IAEjB,WAAA,IAAA,oCAAW,GAAE,CAAA;IACb,WAAA,IAAA,cAAK,EAAC,IAAI,CAAC,CAAA;IACX,WAAA,IAAA,aAAI,GAAE,CAAA;;qDAAM,gCAAoB;;yDAGlC;gCArCU,qBAAqB;IAFjC,IAAA,mBAAU,EAAC,cAAc,CAAC;IAC1B,IAAA,0BAAQ,EAAC,OAAO,CAAC;qCAE4B,8BAAa;GAD9C,qBAAqB,CAsCjC"}
{"version":3,"file":"orders.controller.js","sourceRoot":"","sources":["../../src/orders/orders.controller.ts"],"names":[],"mappings":"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"}
+1
View File
@@ -938,6 +938,7 @@ export declare class OrdersService {
}>;
private mapCheckCreate;
private nextOrderNumber;
private createWithUniqueOrderNumber;
private getOrder;
mapOrder(order: OrderFull, adminView?: boolean): {
id: string;
+58 -20
View File
@@ -28,6 +28,19 @@ const orderInclude = {
user: true,
company: true,
};
function roundMoney(value) {
return Math.round(value * 100) / 100;
}
const CHECK_EDITABLE_STATUSES = [
client_1.OrderStatus.awaiting_review,
client_1.OrderStatus.pricing,
client_1.OrderStatus.needs_correction,
client_1.OrderStatus.awaiting_settlement_fix,
client_1.OrderStatus.check_in_progress,
client_1.OrderStatus.awaiting_check_review,
client_1.OrderStatus.check_needs_fix,
client_1.OrderStatus.check_rejected,
];
let OrdersService = class OrdersService {
prisma;
constructor(prisma) {
@@ -140,8 +153,7 @@ let OrdersService = class OrdersService {
const cashInvoiceExpiresAt = settlementType === client_1.SettlementType.cash
? (0, cash_expiry_1.computeCashInvoiceExpiry)(company)
: null;
const orderNumber = await this.nextOrderNumber();
const order = await this.prisma.$transaction(async (tx) => {
const order = await this.createWithUniqueOrderNumber((orderNumber) => this.prisma.$transaction(async (tx) => {
const created = await tx.order.create({
data: {
orderNumber,
@@ -188,7 +200,7 @@ let OrdersService = class OrdersService {
});
}
return created;
});
}));
return this.mapOrder(order);
}
async adminCreate(adminId, dto) {
@@ -207,7 +219,9 @@ let OrdersService = class OrdersService {
if (!(0, phone_1.isValidPhone)(phone)) {
throw new common_1.BadRequestException('شماره موبایل نامعتبر است');
}
let customer = await this.prisma.customer.findUnique({ where: { phone } });
let customer = await this.prisma.customer.findUnique({
where: { phone },
});
if (!customer) {
const names = (0, name_1.splitFullName)(dto.customerName || 'مشتری جدید');
customer = await this.prisma.customer.create({
@@ -223,12 +237,12 @@ let OrdersService = class OrdersService {
if (!userId) {
throw new common_1.BadRequestException('شناسه یا شماره مشتری الزامی است');
}
const orderNumber = await this.nextOrderNumber();
const totalMeterage = dto.meterage ?? 0;
const order = await this.prisma.order.create({
const ownerId = userId;
const order = await this.createWithUniqueOrderNumber((orderNumber) => this.prisma.order.create({
data: {
orderNumber,
userId,
userId: ownerId,
companyId: company.id,
companyName: company.name,
settlementType,
@@ -245,33 +259,39 @@ let OrdersService = class OrdersService {
},
},
include: orderInclude,
});
}));
return this.mapOrder(order, true);
}
async updatePricing(id, adminId, dto) {
const order = await this.getOrder(id);
const unknown = dto.items.find((item) => !order.items.some((i) => i.id === item.id));
if (unknown) {
throw new common_1.BadRequestException(`آیتم ${unknown.id} یافت نشد`);
}
await this.prisma.$transaction(async (tx) => {
let totalAmount = 0;
let totalMeterage = 0;
for (const item of dto.items) {
const existing = order.items.find((i) => i.id === item.id);
if (!existing) {
throw new common_1.BadRequestException(`آیتم ${item.id} یافت نشد`);
}
const unitPrice = item.unitPrice !== undefined
for (const existing of order.items) {
const item = dto.items.find((i) => i.id === existing.id);
const unitPrice = item?.unitPrice !== undefined
? item.unitPrice
: item.supplyPrice !== undefined
: item?.supplyPrice !== undefined
? item.supplyPrice
: (existing.unitPrice ?? 0);
const unitDiscount = item.unitDiscount ?? existing.unitDiscount ?? 0;
const confirmed = item.confirmedMeterage ??
const unitDiscount = item?.unitDiscount ?? existing.unitDiscount ?? 0;
if (unitDiscount > unitPrice) {
throw new common_1.BadRequestException('تخفیف واحد نمی‌تواند از قیمت واحد بیشتر باشد');
}
const confirmed = item?.confirmedMeterage ??
existing.confirmedMeterage ??
existing.requestedMeterage;
const lineTotal = Math.max(0, (unitPrice - unitDiscount) * confirmed);
const lineTotal = roundMoney(Math.max(0, (unitPrice - unitDiscount) * confirmed));
totalAmount += lineTotal;
totalMeterage += confirmed;
if (!item)
continue;
await tx.orderItem.update({
where: { id: item.id },
where: { id: existing.id },
data: {
confirmedMeterage: confirmed,
unitPrice,
@@ -280,9 +300,10 @@ let OrdersService = class OrdersService {
},
});
}
totalAmount = roundMoney(totalAmount);
const shippingCost = dto.shippingCost ?? order.shippingCost ?? 0;
const totalDiscount = dto.totalDiscount ?? order.totalDiscount ?? 0;
const finalAmount = Math.max(0, totalAmount + shippingCost - totalDiscount);
const finalAmount = roundMoney(Math.max(0, totalAmount + shippingCost - totalDiscount));
const nextStatus = order.status === client_1.OrderStatus.awaiting_review ||
order.status === client_1.OrderStatus.pricing
? client_1.OrderStatus.pricing
@@ -354,6 +375,9 @@ let OrdersService = class OrdersService {
if (order.settlementType !== client_1.SettlementType.check) {
throw new common_1.BadRequestException('این سفارش تسویه چکی نیست');
}
if (!CHECK_EDITABLE_STATUSES.includes(order.status)) {
throw new common_1.BadRequestException('در وضعیت فعلی سفارش امکان ویرایش چک‌ها وجود ندارد');
}
const checkMode = dto.checkMode ?? order.checkMode ?? client_1.CheckRegistrationMode.full;
const rass = (0, check_rass_1.calculateCheckRass)(dto.checks.map((c) => ({ amount: c.amount, dueDate: c.dueDate })), order.createdAt);
await this.prisma.$transaction(async (tx) => {
@@ -418,6 +442,20 @@ let OrdersService = class OrdersService {
}
return `${(0, order_number_1.generateOrderNumber)()}-${Date.now().toString().slice(-3)}`;
}
async createWithUniqueOrderNumber(create) {
for (let attempt = 0;; attempt++) {
const orderNumber = await this.nextOrderNumber();
try {
return await create(orderNumber);
}
catch (e) {
const isDuplicate = e instanceof client_1.Prisma.PrismaClientKnownRequestError &&
e.code === 'P2002';
if (!isDuplicate || attempt >= 4)
throw e;
}
}
}
async getOrder(id) {
const order = await this.prisma.order.findUnique({
where: { id },
+1 -1
View File
File diff suppressed because one or more lines are too long
+4 -2
View File
@@ -83,7 +83,8 @@ let ProductsService = class ProductsService {
return this.map(product);
}
catch (e) {
if (e instanceof client_1.Prisma.PrismaClientKnownRequestError && e.code === 'P2002') {
if (e instanceof client_1.Prisma.PrismaClientKnownRequestError &&
e.code === 'P2002') {
throw new common_1.ConflictException('کد محصول در این شرکت تکراری است');
}
throw e;
@@ -131,7 +132,8 @@ let ProductsService = class ProductsService {
return this.map(product);
}
catch (e) {
if (e instanceof client_1.Prisma.PrismaClientKnownRequestError && e.code === 'P2002') {
if (e instanceof client_1.Prisma.PrismaClientKnownRequestError &&
e.code === 'P2002') {
throw new common_1.ConflictException('کد محصول در این شرکت تکراری است');
}
throw e;
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"shipments.controller.js","sourceRoot":"","sources":["../../src/shipments/shipments.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAQwB;AACxB,2CAAgD;AAChD,2DAAuD;AACvD,0EAAgE;AAChE,wFAA0E;AAE1E,qDAI4B;AAIrB,IAAM,mBAAmB,GAAzB,MAAM,mBAAmB;IACD;IAA7B,YAA6B,gBAAkC;QAAlC,qBAAgB,GAAhB,gBAAgB,CAAkB;IAAG,CAAC;IAGnE,OAAO,CAAkB,MAAuB;QAC9C,OAAO,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/C,CAAC;IAGD,OAAO,CAAc,EAAU;QAC7B,OAAO,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC3C,CAAC;IAGD,MAAM,CACW,IAAmB,EAC1B,GAAsB;QAE9B,OAAO,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;IACpD,CAAC;IAGD,MAAM,CAAc,EAAU,EAAU,GAAsB;QAC5D,OAAO,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;IAC/C,CAAC;IAGD,aAAa,CACI,IAAmB,EACrB,EAAU,EACf,GAA6B;QAErC,OAAO,IAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;IAC/D,CAAC;CACF,CAAA;AAlCY,kDAAmB;AAI9B;IADC,IAAA,YAAG,GAAE;IACG,WAAA,IAAA,cAAK,EAAC,QAAQ,CAAC,CAAA;;;;kDAEvB;AAGD;IADC,IAAA,YAAG,EAAC,KAAK,CAAC;IACF,WAAA,IAAA,cAAK,EAAC,IAAI,CAAC,CAAA;;;;kDAEnB;AAGD;IADC,IAAA,aAAI,GAAE;IAEJ,WAAA,IAAA,oCAAW,GAAE,CAAA;IACb,WAAA,IAAA,aAAI,GAAE,CAAA;;6CAAM,gCAAiB;;iDAG/B;AAGD;IADC,IAAA,cAAK,EAAC,KAAK,CAAC;IACL,WAAA,IAAA,cAAK,EAAC,IAAI,CAAC,CAAA;IAAc,WAAA,IAAA,aAAI,GAAE,CAAA;;6CAAM,gCAAiB;;iDAE7D;AAGD;IADC,IAAA,cAAK,EAAC,YAAY,CAAC;IAEjB,WAAA,IAAA,oCAAW,GAAE,CAAA;IACb,WAAA,IAAA,cAAK,EAAC,IAAI,CAAC,CAAA;IACX,WAAA,IAAA,aAAI,GAAE,CAAA;;qDAAM,uCAAwB;;wDAGtC;8BAjCU,mBAAmB;IAF/B,IAAA,mBAAU,EAAC,iBAAiB,CAAC;IAC7B,IAAA,0BAAQ,EAAC,OAAO,CAAC;qCAE+B,oCAAgB;GADpD,mBAAmB,CAkC/B"}
{"version":3,"file":"shipments.controller.js","sourceRoot":"","sources":["../../src/shipments/shipments.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAQwB;AACxB,2CAAgD;AAChD,2DAAuD;AACvD,0EAAgE;AAChE,wFAA0E;AAE1E,qDAI4B;AAIrB,IAAM,mBAAmB,GAAzB,MAAM,mBAAmB;IACD;IAA7B,YAA6B,gBAAkC;QAAlC,qBAAgB,GAAhB,gBAAgB,CAAkB;IAAG,CAAC;IAGnE,OAAO,CAAkB,MAAuB;QAC9C,OAAO,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/C,CAAC;IAGD,OAAO,CAAc,EAAU;QAC7B,OAAO,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC3C,CAAC;IAGD,MAAM,CAAgB,IAAmB,EAAU,GAAsB;QACvE,OAAO,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;IACpD,CAAC;IAGD,MAAM,CAAc,EAAU,EAAU,GAAsB;QAC5D,OAAO,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;IAC/C,CAAC;IAGD,aAAa,CACI,IAAmB,EACrB,EAAU,EACf,GAA6B;QAErC,OAAO,IAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;IAC/D,CAAC;CACF,CAAA;AA/BY,kDAAmB;AAI9B;IADC,IAAA,YAAG,GAAE;IACG,WAAA,IAAA,cAAK,EAAC,QAAQ,CAAC,CAAA;;;;kDAEvB;AAGD;IADC,IAAA,YAAG,EAAC,KAAK,CAAC;IACF,WAAA,IAAA,cAAK,EAAC,IAAI,CAAC,CAAA;;;;kDAEnB;AAGD;IADC,IAAA,aAAI,GAAE;IACC,WAAA,IAAA,oCAAW,GAAE,CAAA;IAAuB,WAAA,IAAA,aAAI,GAAE,CAAA;;6CAAM,gCAAiB;;iDAExE;AAGD;IADC,IAAA,cAAK,EAAC,KAAK,CAAC;IACL,WAAA,IAAA,cAAK,EAAC,IAAI,CAAC,CAAA;IAAc,WAAA,IAAA,aAAI,GAAE,CAAA;;6CAAM,gCAAiB;;iDAE7D;AAGD;IADC,IAAA,cAAK,EAAC,YAAY,CAAC;IAEjB,WAAA,IAAA,oCAAW,GAAE,CAAA;IACb,WAAA,IAAA,cAAK,EAAC,IAAI,CAAC,CAAA;IACX,WAAA,IAAA,aAAI,GAAE,CAAA;;qDAAM,uCAAwB;;wDAGtC;8BA9BU,mBAAmB;IAF/B,IAAA,mBAAU,EAAC,iBAAiB,CAAC;IAC7B,IAAA,0BAAQ,EAAC,OAAO,CAAC;qCAE+B,oCAAgB;GADpD,mBAAmB,CA+B/B"}
File diff suppressed because one or more lines are too long
+2
View File
@@ -0,0 +1,2 @@
export declare class SmsModule {
}
+21
View File
@@ -0,0 +1,21 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SmsModule = void 0;
const common_1 = require("@nestjs/common");
const sms_service_1 = require("./sms.service");
let SmsModule = class SmsModule {
};
exports.SmsModule = SmsModule;
exports.SmsModule = SmsModule = __decorate([
(0, common_1.Module)({
providers: [sms_service_1.SmsService],
exports: [sms_service_1.SmsService],
})
], SmsModule);
//# sourceMappingURL=sms.module.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"sms.module.js","sourceRoot":"","sources":["../../src/sms/sms.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,+CAA2C;AAMpC,IAAM,SAAS,GAAf,MAAM,SAAS;CAAG,CAAA;AAAZ,8BAAS;oBAAT,SAAS;IAJrB,IAAA,eAAM,EAAC;QACN,SAAS,EAAE,CAAC,wBAAU,CAAC;QACvB,OAAO,EAAE,CAAC,wBAAU,CAAC;KACtB,CAAC;GACW,SAAS,CAAG"}
+14
View File
@@ -0,0 +1,14 @@
import { ConfigService } from '@nestjs/config';
export type SmsSendResult = {
success: boolean;
raw: unknown;
};
export declare class SmsService {
private readonly config;
private readonly logger;
constructor(config: ConfigService);
isEnabled(): boolean;
send(to: string, message: string): Promise<SmsSendResult>;
buildOtpMessage(code: string): string;
private resolveHost;
}
+104
View File
@@ -0,0 +1,104 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var SmsService_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.SmsService = void 0;
const common_1 = require("@nestjs/common");
const config_1 = require("@nestjs/config");
function maskPhone(phone) {
return phone.length <= 4
? '****'
: `${phone.slice(0, 4)}****${phone.slice(-2)}`;
}
let SmsService = SmsService_1 = class SmsService {
config;
logger = new common_1.Logger(SmsService_1.name);
constructor(config) {
this.config = config;
}
isEnabled() {
const raw = (this.config.get('SMS_ENABLED', 'true') ?? 'true').toLowerCase();
return raw === '1' || raw === 'true' || raw === 'yes';
}
async send(to, message) {
const url = this.config.get('SMS_API_URL', 'http://185.231.112.101/api/createsms');
const secretKey = this.config.get('SMS_SECRET_KEY')?.trim();
if (!secretKey) {
this.logger.error('SMS_SECRET_KEY تنظیم نشده است');
return { success: false, raw: 'SMS_SECRET_KEY missing' };
}
const platform = this.config.get('SMS_PLATFORM', 'rayegansms');
const host = this.resolveHost();
try {
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
secret_key: secretKey,
},
body: JSON.stringify({
phone: to,
host,
text: message.trim(),
platform,
}),
signal: AbortSignal.timeout(15_000),
});
const text = await response.text();
let body = text;
try {
body = text ? JSON.parse(text) : null;
}
catch {
}
let success = response.ok;
if (success && body && typeof body === 'object') {
const obj = body;
if ('success' in obj && obj.success === false)
success = false;
else if ('ok' in obj && obj.ok === false)
success = false;
else if (typeof obj.status === 'string' &&
['error', 'failed', 'fail'].includes(obj.status.toLowerCase())) {
success = false;
}
}
if (!success) {
this.logger.warn(`SMS failed to ${maskPhone(to)}: ${JSON.stringify(body)}`);
}
return { success, raw: body };
}
catch (err) {
this.logger.error(`SMS request error to ${maskPhone(to)}`, err instanceof Error ? err.stack : err);
return {
success: false,
raw: err instanceof Error ? err.message : String(err),
};
}
}
buildOtpMessage(code) {
const appName = this.config.get('SMS_APP_NAME', 'پارچه');
return `رمز عبور یکبار مصرف شما جهت ورود به اپلیکیشن ${appName} ${code} می باشد`;
}
resolveHost() {
const fromEnv = this.config.get('SMS_HOST')?.trim() ||
this.config.get('SMS_APP_NAME')?.trim();
if (fromEnv)
return fromEnv;
return 'fabric';
}
};
exports.SmsService = SmsService;
exports.SmsService = SmsService = SmsService_1 = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [config_1.ConfigService])
], SmsService);
//# sourceMappingURL=sms.service.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"sms.service.js","sourceRoot":"","sources":["../../src/sms/sms.service.ts"],"names":[],"mappings":"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"}
+11 -2
View File
@@ -28,11 +28,20 @@ services:
condition: service_healthy
environment:
DATABASE_URL: postgresql://${POSTGRES_USER:-fabric}:${POSTGRES_PASSWORD:-fabric123}@postgres:5432/${POSTGRES_DB:-fabric_trade}?schema=public
JWT_SECRET: ${JWT_SECRET:-fabric-trade-dev-secret-change-me}
JWT_SECRET: ${JWT_SECRET:?JWT_SECRET is required}
JWT_EXPIRES_IN: ${JWT_EXPIRES_IN:-7d}
PORT: 3000
MOCK_OTP_CODE: ${MOCK_OTP_CODE:-123456}
MOCK_OTP_CODE: ${MOCK_OTP_CODE:-1234}
OTP_TTL_MINUTES: ${OTP_TTL_MINUTES:-5}
SMS_ENABLED: ${SMS_ENABLED:-true}
SMS_API_URL: ${SMS_API_URL:-http://185.231.112.101/api/createsms}
SMS_SECRET_KEY: ${SMS_SECRET_KEY:-}
SMS_PLATFORM: ${SMS_PLATFORM:-rayegansms}
SMS_HOST: ${SMS_HOST:-پارچه}
SMS_APP_NAME: ${SMS_APP_NAME:-پارچه}
BODY_LIMIT: ${BODY_LIMIT:-25mb}
TZ: ${TZ:-Asia/Tehran}
NODE_ENV: ${NODE_ENV:-production}
RUN_SEED: ${RUN_SEED:-false}
ports:
- '127.0.0.1:${API_PORT:-3000}:3000'
+1
View File
@@ -33,6 +33,7 @@ services:
environment:
DATABASE_URL: postgresql://${POSTGRES_USER:-fabric}:${POSTGRES_PASSWORD:-fabric123}@postgres:5432/${POSTGRES_DB:-fabric_trade}?schema=public
PORT: ${PORT:-3000}
TZ: ${TZ:-Asia/Tehran}
ports:
- '127.0.0.1:${API_PORT:-8585}:3000'
+1
View File
@@ -19,6 +19,7 @@
"test:cov": "jest --coverage",
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
"test:e2e": "jest --config ./test/jest-e2e.json",
"test:smoke": "node scripts/smoke-order-flow.mjs",
"prisma:generate": "prisma generate",
"prisma:migrate": "prisma migrate dev",
"prisma:deploy": "prisma migrate deploy",
@@ -0,0 +1,2 @@
-- شمارنده تلاش ناموفق برای جلوگیری از حدس‌زدن کد ۴ رقمی
ALTER TABLE "OtpChallenge" ADD COLUMN "attempts" INTEGER NOT NULL DEFAULT 0;
+1
View File
@@ -210,6 +210,7 @@ model OtpChallenge {
firstName String?
lastName String?
isRegister Boolean @default(false)
attempts Int @default(0)
expiresAt DateTime
createdAt DateTime @default(now())
+1 -1
View File
@@ -636,7 +636,7 @@ async function main() {
void order1;
console.log('Seed completed successfully.');
console.log('Admin login: 09121112222 / admin123');
console.log('Customer OTP login: 09121234567 / code 123456');
console.log('Customer OTP login: 09121234567 / code 1234');
}
main()
+335
View File
@@ -0,0 +1,335 @@
/**
* تست دود جریان کامل سفارش: ورود مشتری، سبد، ثبت چکی و نقدی،
* قیمت‌گذاری ادمین، رسید نقدی و بررسی وضعیت‌ها.
* اجرا: node scripts/smoke-order-flow.mjs
*/
const BASE = process.env.SMOKE_BASE_URL || 'http://127.0.0.1:3999/api';
const CUSTOMER_PHONE = '09121234567';
const ADMIN_PHONE = '09121112222';
const ADMIN_PASSWORD = 'admin123';
let passed = 0;
let failed = 0;
function check(name, condition, detail) {
if (condition) {
passed++;
console.log(` PASS ${name}`);
} else {
failed++;
console.log(` FAIL ${name}${detail ? ` → ${detail}` : ''}`);
}
}
async function api(path, { method = 'GET', body, token } = {}) {
const res = await fetch(`${BASE}${path}`, {
method,
headers: {
Accept: 'application/json',
...(body ? { 'Content-Type': 'application/json' } : {}),
...(token ? { Authorization: `Bearer ${token}` } : {}),
},
body: body ? JSON.stringify(body) : undefined,
});
const text = await res.text();
let data = null;
try {
data = text ? JSON.parse(text) : null;
} catch {
data = text;
}
return { status: res.status, data };
}
function jalaliIsoInDays(days) {
const d = new Date(Date.now() + days * 86400000);
return d.toISOString().slice(0, 10);
}
/** تصویر base64 بزرگ‌تر از سقف پیش‌فرض ۱۰۰KB اکسپرس */
function bigBase64(kb) {
return `data:image/jpeg;base64,${'A'.repeat(kb * 1024)}`;
}
async function main() {
console.log(`\n== Smoke test @ ${BASE} ==\n`);
console.log('[1] احراز هویت');
const otp = await api('/auth/otp/request', {
method: 'POST',
body: { phone: CUSTOMER_PHONE },
});
check('درخواست OTP', otp.status === 201 || otp.status === 200, `status=${otp.status}`);
const code = otp.data?.debugCode ?? '1234';
check('کد OTP چهار رقمی است', /^\d{4}$/.test(String(code)), `code=${code}`);
const badVerify = await api('/auth/otp/verify', {
method: 'POST',
body: { phone: CUSTOMER_PHONE, code: '0000' === code ? '1111' : '0000' },
});
check('کد اشتباه رد می‌شود', badVerify.status === 401, `status=${badVerify.status}`);
const verify = await api('/auth/otp/verify', {
method: 'POST',
body: { phone: CUSTOMER_PHONE, code: String(code) },
});
check('ورود مشتری', !!verify.data?.accessToken, JSON.stringify(verify.data).slice(0, 120));
const userToken = verify.data?.accessToken;
const adminLogin = await api('/admin/auth/login', {
method: 'POST',
body: { phone: ADMIN_PHONE, password: ADMIN_PASSWORD },
});
check('ورود ادمین', !!adminLogin.data?.accessToken, JSON.stringify(adminLogin.data).slice(0, 120));
const adminToken = adminLogin.data?.accessToken;
console.log('\n[2] جداسازی دسترسی');
const crossAccess = await api('/admin/orders', { token: userToken });
check('توکن مشتری به مسیر ادمین دسترسی ندارد', crossAccess.status === 403, `status=${crossAccess.status}`);
const custWithAdmin = await api('/orders', { token: adminToken });
check('توکن ادمین به مسیر مشتری دسترسی ندارد', custWithAdmin.status === 403, `status=${custWithAdmin.status}`);
const noToken = await api('/orders');
check('بدون توکن ۴۰۱', noToken.status === 401, `status=${noToken.status}`);
console.log('\n[3] سبد خرید');
const companies = await api('/companies/public');
const company = companies.data?.[0];
check('لیست شرکت‌ها', !!company, JSON.stringify(companies.data).slice(0, 120));
const products = await api(`/products?companyId=${company.id}`, { token: userToken });
const product = (Array.isArray(products.data) ? products.data : products.data?.items)?.find(
(p) => p.companyId === company.id,
);
check('لیست محصولات', !!product, JSON.stringify(products.data).slice(0, 160));
const meterage = Math.max(product.minMeterage ?? 1, product.orderMultiplier ?? 1);
await api('/carts', { method: 'DELETE', token: userToken });
const addItem = await api('/carts/items', {
method: 'POST',
token: userToken,
body: { productId: product.id, meterage },
});
check('افزودن به سبد', addItem.status < 300, `status=${addItem.status} ${JSON.stringify(addItem.data).slice(0, 120)}`);
console.log('\n[4] ثبت سفارش چکی با تصویر بزرگ');
const checkOrder = await api('/orders', {
method: 'POST',
token: userToken,
body: {
companyId: company.id,
settlementType: 'check',
checkMode: 'full',
items: [{ productId: product.id, meterage }],
checks: [
{
amount: 2000000,
dueDate: jalaliIsoInDays(30),
sayadId: '1234567890123456',
checkNumber: '123456',
ownerNationalId: '0012345678',
ownerFirstName: 'علی',
ownerLastName: 'رضایی',
bankName: 'ملی',
branchName: 'مرکزی',
frontImage: bigBase64(300),
backImage: bigBase64(300),
mode: 'full',
},
],
},
});
check(
'ثبت سفارش چکی (بدنه ~۶۰۰KB)',
checkOrder.status < 300,
`status=${checkOrder.status} ${JSON.stringify(checkOrder.data).slice(0, 200)}`,
);
const checkOrderId = checkOrder.data?.id;
check('راس چک محاسبه شد', checkOrder.data?.checkRassDays === 30, `rass=${checkOrder.data?.checkRassDays}`);
console.log('\n[5] فیلدهای اضافه باید رد شوند');
const extraField = await api('/orders', {
method: 'POST',
token: userToken,
body: {
companyId: company.id,
settlementType: 'cash',
items: [{ productId: product.id, meterage }],
bogusField: 'x',
},
});
check('فیلد ناشناخته ۴۰۰ می‌دهد', extraField.status === 400, `status=${extraField.status}`);
console.log('\n[6] ثبت سفارش نقدی');
await api('/carts/items', {
method: 'POST',
token: userToken,
body: { productId: product.id, meterage },
});
const cashOrder = await api('/orders', {
method: 'POST',
token: userToken,
body: {
companyId: company.id,
settlementType: 'cash',
items: [{ productId: product.id, meterage }],
},
});
check('ثبت سفارش نقدی', cashOrder.status < 300, `status=${cashOrder.status} ${JSON.stringify(cashOrder.data).slice(0, 200)}`);
const cashOrderId = cashOrder.data?.id;
const expiry = cashOrder.data?.cashInvoiceExpiresAt;
check('انقضای فاکتور در آینده است', !!expiry && new Date(expiry) > new Date(), `expiry=${expiry}`);
console.log('\n[7] سفارش در لیست مشتری دیده می‌شود');
const myOrders = await api('/orders', { token: userToken });
const ids = (myOrders.data ?? []).map((o) => o.id);
check('سفارش چکی در لیست', ids.includes(checkOrderId));
check('سفارش نقدی در لیست', ids.includes(cashOrderId));
console.log('\n[8] لیست و فیلتر ادمین');
const adminOrders = await api('/admin/orders', { token: adminToken });
const adminIds = (adminOrders.data ?? []).map((o) => o.id);
check('هر دو سفارش برای ادمین', adminIds.includes(checkOrderId) && adminIds.includes(cashOrderId));
const adminStatuses = new Set((adminOrders.data ?? []).map((o) => o.adminStatus));
const allowedTabs = new Set([
'pending_review',
'pending_check',
'needs_correction',
'check_correction',
'final_approval',
'shipped',
'delivered',
'cancelled',
'rejected',
'expired',
]);
const unknown = [...adminStatuses].filter((s) => !allowedTabs.has(s));
check('همه وضعیت‌ها به تب معتبر نگاشت شده‌اند', unknown.length === 0, `unknown=${unknown.join(',')}`);
const filtered = await api('/admin/orders?status=pending_review', { token: adminToken });
check(
'فیلتر «در انتظار بررسی» سفارش‌ها را برمی‌گرداند',
(filtered.data ?? []).some((o) => o.id === cashOrderId),
`count=${(filtered.data ?? []).length}`,
);
console.log('\n[9] قیمت‌گذاری ادمین');
const detail = await api(`/admin/orders/${cashOrderId}`, { token: adminToken });
const items = detail.data?.items ?? [];
check('سفارش آیتم دارد', items.length > 0);
const pricing = await api(`/admin/orders/${cashOrderId}/pricing`, {
method: 'PATCH',
token: adminToken,
body: {
items: [{ id: items[0].id, confirmedMeterage: meterage, unitPrice: 100000, unitDiscount: 0 }],
shippingCost: 50000,
},
});
const expectedTotal = 100000 * meterage;
check('قیمت‌گذاری موفق', pricing.status < 300, `status=${pricing.status} ${JSON.stringify(pricing.data).slice(0, 150)}`);
check(
'جمع کل درست است',
Math.abs((pricing.data?.totalAmount ?? 0) - expectedTotal) < 0.01,
`total=${pricing.data?.totalAmount} expected=${expectedTotal}`,
);
check(
'مبلغ نهایی = جمع + حمل',
Math.abs((pricing.data?.finalAmount ?? 0) - (expectedTotal + 50000)) < 0.01,
`final=${pricing.data?.finalAmount}`,
);
const badDiscount = await api(`/admin/orders/${cashOrderId}/pricing`, {
method: 'PATCH',
token: adminToken,
body: { items: [{ id: items[0].id, unitPrice: 1000, unitDiscount: 5000 }] },
});
check('تخفیف بیشتر از قیمت رد می‌شود', badDiscount.status === 400, `status=${badDiscount.status}`);
console.log('\n[10] رسید پرداخت نقدی');
const accounts = await api(`/companies/${company.id}/bank-accounts`, { token: userToken });
const account = (accounts.data ?? [])[0];
check('حساب بانکی موجود', !!account, JSON.stringify(accounts.data).slice(0, 120));
const receipt = await api(`/orders/${cashOrderId}/cash-receipt`, {
method: 'POST',
token: userToken,
body: {
amount: expectedTotal + 50000,
transferDate: jalaliIsoInDays(0),
transferTime: '12:00',
trackingNumber: '987654321',
destinationAccountId: account.id,
receiptImage: bigBase64(400),
},
});
check('ثبت رسید (تصویر ۴۰۰KB)', receipt.status < 300, `status=${receipt.status} ${JSON.stringify(receipt.data).slice(0, 200)}`);
const afterReceipt = await api(`/orders/${cashOrderId}`, { token: userToken });
check(
'وضعیت به تأیید پرداخت رفت',
afterReceipt.data?.status === 'awaiting_cash_confirmation',
`status=${afterReceipt.data?.status}`,
);
console.log('\n[11] دسترسی متقاطع بین مشتری‌ها');
const otherPhone = '09129999001';
await api('/auth/otp/request', {
method: 'POST',
body: { phone: otherPhone, firstName: 'تست', lastName: 'دوم', isRegister: true },
});
const otherVerify = await api('/auth/otp/verify', {
method: 'POST',
body: { phone: otherPhone, code: String(code) },
});
const otherToken = otherVerify.data?.accessToken;
check('ثبت‌نام مشتری دوم', !!otherToken, JSON.stringify(otherVerify.data).slice(0, 120));
if (otherToken) {
const foreign = await api(`/orders/${cashOrderId}`, { token: otherToken });
check('سفارش دیگری قابل خواندن نیست', foreign.status === 403, `status=${foreign.status}`);
const foreignReceipt = await api(`/orders/${cashOrderId}/cash-receipt`, {
method: 'POST',
token: otherToken,
body: {
amount: 1000,
transferDate: jalaliIsoInDays(0),
transferTime: '12:00',
trackingNumber: '1',
destinationAccountId: account.id,
},
});
check('رسید روی سفارش دیگری رد می‌شود', foreignReceipt.status === 403, `status=${foreignReceipt.status}`);
}
console.log('\n[12] محافظت از ویرایش چک بعد از تأیید');
const approve = await api(`/admin/orders/${checkOrderId}/status`, {
method: 'PATCH',
token: adminToken,
body: { status: 'delivered' },
});
check('تغییر وضعیت توسط ادمین', approve.status < 300, `status=${approve.status}`);
const lateEdit = await api(`/orders/${checkOrderId}/checks`, {
method: 'PATCH',
token: userToken,
body: { checks: [{ amount: 1, dueDate: jalaliIsoInDays(10), mode: 'brief' }] },
});
check('ویرایش چک بعد از تحویل رد می‌شود', lateEdit.status === 400, `status=${lateEdit.status}`);
const lateReceipt = await api(`/orders/${checkOrderId}/cash-receipt`, {
method: 'POST',
token: userToken,
body: {
amount: 1000,
transferDate: jalaliIsoInDays(0),
transferTime: '12:00',
trackingNumber: '1',
destinationAccountId: account.id,
},
});
check('رسید نقدی روی سفارش چکی رد می‌شود', lateReceipt.status === 400, `status=${lateReceipt.status}`);
console.log(`\n== نتیجه: ${passed} موفق، ${failed} ناموفق ==\n`);
process.exit(failed === 0 ? 0 : 1);
}
main().catch((e) => {
console.error('اجرای تست شکست خورد:', e);
process.exit(1);
});
+1 -1
View File
@@ -35,4 +35,4 @@ echo " npm run start:dev"
echo ""
echo "Swagger: http://localhost:3000/api/docs"
echo "Admin: 09121112222 / admin123"
echo "OTP: 09121234567 / 123456"
echo "OTP: 09121234567 / 1234"
+8 -2
View File
@@ -56,7 +56,10 @@ export class AdminUsersService {
});
return this.map(user);
} catch (e) {
if (e instanceof Prisma.PrismaClientKnownRequestError && e.code === 'P2002') {
if (
e instanceof Prisma.PrismaClientKnownRequestError &&
e.code === 'P2002'
) {
throw new ConflictException('شماره یا ایمیل تکراری است');
}
throw e;
@@ -91,7 +94,10 @@ export class AdminUsersService {
});
return this.map(user);
} catch (e) {
if (e instanceof Prisma.PrismaClientKnownRequestError && e.code === 'P2002') {
if (
e instanceof Prisma.PrismaClientKnownRequestError &&
e.code === 'P2002'
) {
throw new ConflictException('شماره یا ایمیل تکراری است');
}
throw e;
+5 -2
View File
@@ -3,16 +3,19 @@ import { JwtModule } from '@nestjs/jwt';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
import { SmsModule } from '../sms/sms.module';
import { resolveJwtSecret } from '../common/utils/jwt-secret';
@Module({
imports: [
SmsModule,
JwtModule.registerAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (config: ConfigService) => ({
secret: config.get<string>('JWT_SECRET', 'fabric-trade-dev-secret'),
secret: resolveJwtSecret(config),
signOptions: {
expiresIn: config.get('JWT_EXPIRES_IN', '7d') as `${number}d`,
expiresIn: config.get('JWT_EXPIRES_IN', '7d'),
},
}),
}),
+70 -17
View File
@@ -1,19 +1,28 @@
import {
BadRequestException,
Injectable,
ServiceUnavailableException,
UnauthorizedException,
} from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { JwtService } from '@nestjs/jwt';
import { randomInt } from 'node:crypto';
import * as bcrypt from 'bcryptjs';
import { PrismaService } from '../prisma/prisma.service';
import { SmsService } from '../sms/sms.service';
import {
AdminLoginDto,
RequestOtpDto,
UpdateProfileDto,
VerifyOtpDto,
} from './dto/auth.dto';
import { isValidPhone, normalizePhone, toEnglishDigits } from '../common/utils/phone';
import {
isValidPhone,
normalizePhone,
toEnglishDigits,
} from '../common/utils/phone';
const MAX_OTP_ATTEMPTS = 5;
@Injectable()
export class AuthService {
@@ -21,6 +30,7 @@ export class AuthService {
private readonly prisma: PrismaService,
private readonly jwt: JwtService,
private readonly config: ConfigService,
private readonly sms: SmsService,
) {}
async requestOtp(dto: RequestOtpDto) {
@@ -29,7 +39,9 @@ export class AuthService {
throw new BadRequestException('شماره موبایل نامعتبر است');
}
const existing = await this.prisma.customer.findUnique({ where: { phone } });
const existing = await this.prisma.customer.findUnique({
where: { phone },
});
const isRegister = Boolean(dto.isRegister);
if (isRegister) {
@@ -41,33 +53,58 @@ export class AuthService {
}
} else if (!existing) {
throw new BadRequestException('کاربری با این شماره یافت نشد');
} else if (!existing.isActive) {
throw new UnauthorizedException('حساب کاربری شما غیرفعال است');
}
const code = this.config.get<string>('MOCK_OTP_CODE', '123456');
const smsEnabled = this.sms.isEnabled();
const code = smsEnabled
? String(randomInt(1000, 10000))
: this.config.get<string>('MOCK_OTP_CODE', '1234');
const ttl = Number(this.config.get('OTP_TTL_MINUTES', 5));
const expiresAt = new Date(Date.now() + ttl * 60_000);
await this.prisma.otpChallenge.deleteMany({ where: { phone } });
await this.prisma.otpChallenge.create({
data: {
phone,
code,
firstName: dto.firstName?.trim(),
lastName: dto.lastName?.trim(),
isRegister,
expiresAt,
},
const challenge = await this.prisma.$transaction(async (tx) => {
await tx.otpChallenge.deleteMany({ where: { phone } });
return tx.otpChallenge.create({
data: {
phone,
code,
firstName: dto.firstName?.trim(),
lastName: dto.lastName?.trim(),
isRegister,
expiresAt,
},
});
});
if (smsEnabled) {
const sent = await this.sms.send(phone, this.sms.buildOtpMessage(code));
if (!sent.success) {
// چالش ناموفق را پاک می‌کنیم تا کاربر با کدی که هرگز نرسیده گیر نکند
await this.prisma.otpChallenge.deleteMany({
where: { id: challenge.id },
});
throw new ServiceUnavailableException(
'ارسال پیامک با خطا مواجه شد؛ دوباره تلاش کنید',
);
}
}
return {
success: true,
message: 'کد تأیید ارسال شد',
expiresAt,
// فقط برای محیط توسعه
debugCode: code,
...(this.exposesDebugCode(smsEnabled) ? { debugCode: code } : {}),
};
}
/** کد فقط در محیط توسعه و وقتی پیامک خاموش است برگردانده می‌شود. */
private exposesDebugCode(smsEnabled: boolean): boolean {
if (smsEnabled) return false;
return this.config.get<string>('NODE_ENV') !== 'production';
}
async verifyOtp(dto: VerifyOtpDto) {
const phone = normalizePhone(toEnglishDigits(dto.phone));
const code = toEnglishDigits(dto.code).trim();
@@ -80,7 +117,17 @@ export class AuthService {
if (!challenge || challenge.expiresAt < new Date()) {
throw new UnauthorizedException('کد منقضی شده است');
}
if (challenge.attempts >= MAX_OTP_ATTEMPTS) {
await this.prisma.otpChallenge.deleteMany({ where: { phone } });
throw new UnauthorizedException(
'تعداد تلاش‌های نادرست زیاد است؛ کد جدید بگیرید',
);
}
if (challenge.code !== code) {
await this.prisma.otpChallenge.update({
where: { id: challenge.id },
data: { attempts: { increment: 1 } },
});
throw new UnauthorizedException('کد تأیید نادرست است');
}
@@ -98,6 +145,8 @@ export class AuthService {
});
} else if (!user) {
throw new UnauthorizedException('کاربر یافت نشد');
} else if (!user.isActive) {
throw new UnauthorizedException('حساب کاربری شما غیرفعال است');
}
await this.prisma.otpChallenge.deleteMany({ where: { phone } });
@@ -147,7 +196,9 @@ export class AuthService {
async me(userId: string, type: 'customer' | 'admin') {
if (type === 'admin') {
const admin = await this.prisma.adminUser.findUnique({ where: { id: userId } });
const admin = await this.prisma.adminUser.findUnique({
where: { id: userId },
});
if (!admin) throw new UnauthorizedException();
return {
id: admin.id,
@@ -158,7 +209,9 @@ export class AuthService {
};
}
const user = await this.prisma.customer.findUnique({ where: { id: userId } });
const user = await this.prisma.customer.findUnique({
where: { id: userId },
});
if (!user) throw new UnauthorizedException();
return this.mapCustomer(user);
}
+8 -2
View File
@@ -1,4 +1,10 @@
import { IsBoolean, IsOptional, IsString, MinLength } from 'class-validator';
import {
IsBoolean,
IsOptional,
IsString,
Length,
MinLength,
} from 'class-validator';
export class RequestOtpDto {
@IsString()
@@ -22,7 +28,7 @@ export class VerifyOtpDto {
phone!: string;
@IsString()
@MinLength(4)
@Length(4, 4)
code!: string;
}
+1 -4
View File
@@ -28,10 +28,7 @@ export class CartsController {
}
@Post('items')
addItem(
@CurrentUser() user: AuthPrincipal,
@Body() dto: AddCartItemDto,
) {
addItem(@CurrentUser() user: AuthPrincipal, @Body() dto: AddCartItemDto) {
return this.cartsService.addItem(user.id, dto);
}
+2 -4
View File
@@ -96,8 +96,7 @@ export class CartsService {
where: { id: itemId },
data: {
meterage: dto.meterage,
notes:
dto.notes === undefined ? undefined : dto.notes?.trim() || null,
notes: dto.notes === undefined ? undefined : dto.notes?.trim() || null,
},
});
await this.prisma.cart.update({
@@ -152,8 +151,7 @@ export class CartsService {
`حداقل متراژ برای ${product.name} برابر ${product.minMeterage} است`,
);
}
const rem =
Math.round((meterage / product.orderMultiplier) * 1000) / 1000;
const rem = Math.round((meterage / product.orderMultiplier) * 1000) / 1000;
if (Math.abs(rem - Math.round(rem)) > 1e-6) {
throw new BadRequestException(
`متراژ باید مضرب ${product.orderMultiplier} باشد`,
+23 -6
View File
@@ -4,11 +4,7 @@ import {
Injectable,
NotFoundException,
} from '@nestjs/common';
import {
CashPaymentStatus,
OrderStatus,
SettlementType,
} from '@prisma/client';
import { CashPaymentStatus, OrderStatus, SettlementType } from '@prisma/client';
import { PrismaService } from '../prisma/prisma.service';
import {
SubmitCashReceiptDto,
@@ -16,6 +12,20 @@ import {
} from './dto/cash-payment.dto';
import { joinFullName } from '../common/utils/name';
/** بعد از تأیید پرداخت یا ارسال، رسید جدید نباید وضعیت را به عقب برگرداند. */
const RECEIPT_SUBMITTABLE_STATUSES: OrderStatus[] = [
OrderStatus.awaiting_review,
OrderStatus.pricing,
OrderStatus.needs_correction,
OrderStatus.awaiting_settlement,
OrderStatus.awaiting_settlement_fix,
OrderStatus.cash_in_progress,
OrderStatus.cash_invoice_issued,
OrderStatus.awaiting_cash_payment,
OrderStatus.cash_payment_submitted,
OrderStatus.awaiting_cash_confirmation,
];
@Injectable()
export class CashPaymentsService {
constructor(private readonly prisma: PrismaService) {}
@@ -36,11 +46,18 @@ export class CashPaymentsService {
if (order.settlementType !== SettlementType.cash) {
throw new BadRequestException('این سفارش تسویه نقدی نیست');
}
if (!RECEIPT_SUBMITTABLE_STATUSES.includes(order.status)) {
throw new BadRequestException(
'در وضعیت فعلی سفارش امکان ثبت رسید وجود ندارد',
);
}
if (
order.cashInvoiceExpiresAt &&
order.cashInvoiceExpiresAt.getTime() < Date.now()
) {
throw new BadRequestException('مهلت پرداخت فاکتور نقدی به پایان رسیده است');
throw new BadRequestException(
'مهلت پرداخت فاکتور نقدی به پایان رسیده است',
);
}
const account = await this.prisma.bankAccount.findFirst({
+8 -2
View File
@@ -61,7 +61,10 @@ export class CatalogsService {
});
return this.map(catalog);
} catch (e) {
if (e instanceof Prisma.PrismaClientKnownRequestError && e.code === 'P2002') {
if (
e instanceof Prisma.PrismaClientKnownRequestError &&
e.code === 'P2002'
) {
throw new ConflictException('کد کاتالوگ در این شرکت تکراری است');
}
throw e;
@@ -90,7 +93,10 @@ export class CatalogsService {
});
return this.map(catalog);
} catch (e) {
if (e instanceof Prisma.PrismaClientKnownRequestError && e.code === 'P2002') {
if (
e instanceof Prisma.PrismaClientKnownRequestError &&
e.code === 'P2002'
) {
throw new ConflictException('کد کاتالوگ در این شرکت تکراری است');
}
throw e;
+15 -17
View File
@@ -1,11 +1,5 @@
import {
Injectable,
NotFoundException,
} from '@nestjs/common';
import {
CheckStatus,
OrderStatus,
} from '@prisma/client';
import { Injectable, NotFoundException } from '@nestjs/common';
import { CheckStatus, OrderStatus } from '@prisma/client';
import { PrismaService } from '../prisma/prisma.service';
import { UpdateCheckStatusDto } from './dto/check.dto';
@@ -14,7 +8,9 @@ export class ChecksService {
constructor(private readonly prisma: PrismaService) {}
async findByOrder(orderId: string) {
const order = await this.prisma.order.findUnique({ where: { id: orderId } });
const order = await this.prisma.order.findUnique({
where: { id: orderId },
});
if (!order) throw new NotFoundException('سفارش یافت نشد');
const checks = await this.prisma.check.findMany({
@@ -24,11 +20,7 @@ export class ChecksService {
return checks.map((c) => this.map(c));
}
async updateStatus(
id: string,
adminId: string,
dto: UpdateCheckStatusDto,
) {
async updateStatus(id: string, adminId: string, dto: UpdateCheckStatusDto) {
const check = await this.prisma.check.findUnique({
where: { id },
include: { order: { include: { checks: true } } },
@@ -46,9 +38,15 @@ export class ChecksService {
},
});
const siblings = await tx.check.findMany({ where: { orderId: check.orderId } });
const allApproved = siblings.every((c) => c.status === CheckStatus.approved);
const anyRejected = siblings.some((c) => c.status === CheckStatus.rejected);
const siblings = await tx.check.findMany({
where: { orderId: check.orderId },
});
const allApproved = siblings.every(
(c) => c.status === CheckStatus.approved,
);
const anyRejected = siblings.some(
(c) => c.status === CheckStatus.rejected,
);
let nextStatus: OrderStatus | null = null;
if (anyRejected) {
@@ -9,7 +9,7 @@ export interface AuthPrincipal {
export const CurrentUser = createParamDecorator(
(_data: unknown, ctx: ExecutionContext): AuthPrincipal => {
const request = ctx.switchToHttp().getRequest();
const request = ctx.switchToHttp().getRequest<{ user: AuthPrincipal }>();
return request.user;
},
);
+10 -7
View File
@@ -14,6 +14,7 @@ import {
ROLES_KEY,
} from '../decorators/auth.decorators';
import { AuthPrincipal } from '../decorators/current-user.decorator';
import { resolveJwtSecret } from '../utils/jwt-secret';
@Injectable()
export class JwtAuthGuard implements CanActivate {
@@ -30,8 +31,11 @@ export class JwtAuthGuard implements CanActivate {
]);
if (isPublic) return true;
const request = context.switchToHttp().getRequest();
const authHeader = request.headers.authorization as string | undefined;
const request = context.switchToHttp().getRequest<{
headers: Record<string, string | undefined>;
user?: AuthPrincipal;
}>();
const authHeader = request.headers.authorization;
if (!authHeader?.startsWith('Bearer ')) {
throw new UnauthorizedException('توکن احراز هویت الزامی است');
}
@@ -40,7 +44,7 @@ export class JwtAuthGuard implements CanActivate {
let payload: AuthPrincipal & { sub?: string };
try {
payload = await this.jwtService.verifyAsync(token, {
secret: this.config.get<string>('JWT_SECRET'),
secret: resolveJwtSecret(this.config),
});
} catch {
throw new UnauthorizedException('توکن نامعتبر یا منقضی شده است');
@@ -54,10 +58,9 @@ export class JwtAuthGuard implements CanActivate {
};
request.user = user;
const authType = this.reflector.getAllAndOverride<'customer' | 'admin' | 'any'>(
AUTH_TYPE_KEY,
[context.getHandler(), context.getClass()],
);
const authType = this.reflector.getAllAndOverride<
'customer' | 'admin' | 'any'
>(AUTH_TYPE_KEY, [context.getHandler(), context.getClass()]);
if (authType && authType !== 'any' && user.type !== authType) {
throw new ForbiddenException('دسترسی مجاز نیست');
}
+4 -3
View File
@@ -1,3 +1,5 @@
import { addDays, tehranAtHour } from './tehran-time';
export function computeCashInvoiceExpiry(company: {
cashInvoiceValidUntilHour: number | null;
cashInvoiceValidityHours: number;
@@ -7,10 +9,9 @@ export function computeCashInvoiceExpiry(company: {
company.cashInvoiceValidUntilHour != null &&
Number.isFinite(company.cashInvoiceValidUntilHour)
) {
const expires = new Date(now);
expires.setHours(company.cashInvoiceValidUntilHour, 0, 0, 0);
const expires = tehranAtHour(now, company.cashInvoiceValidUntilHour);
if (expires.getTime() <= now.getTime()) {
expires.setDate(expires.getDate() + 1);
return tehranAtHour(addDays(now, 1), company.cashInvoiceValidUntilHour);
}
return expires;
}
+10 -13
View File
@@ -12,11 +12,12 @@ export type CheckRassResult = {
rassDate: string | null;
};
function startOfDay(date: Date): Date {
const d = new Date(date);
d.setHours(0, 0, 0, 0);
return d;
}
import {
addDays,
calendarDayOf,
diffInDays,
tehranCalendarDay,
} from './tehran-time';
export function calculateCheckRass(
checks: CheckRassInput[],
@@ -33,25 +34,21 @@ export function calculateCheckRass(
};
}
const base = startOfDay(baseDate);
const base = tehranCalendarDay(baseDate);
let totalAmount = 0;
let weightedDays = 0;
const dueDates: Date[] = [];
for (const check of checks) {
const due = startOfDay(new Date(check.dueDate));
const due = calendarDayOf(check.dueDate);
dueDates.push(due);
const days = Math.max(
0,
Math.round((due.getTime() - base.getTime()) / (1000 * 60 * 60 * 24)),
);
const days = Math.max(0, diffInDays(base, due));
totalAmount += check.amount;
weightedDays += check.amount * days;
}
const rassDays = totalAmount > 0 ? Math.round(weightedDays / totalAmount) : 0;
const rassDate = new Date(base);
rassDate.setDate(rassDate.getDate() + rassDays);
const rassDate = addDays(base, rassDays);
dueDates.sort((a, b) => a.getTime() - b.getTime());
return {
+16
View File
@@ -0,0 +1,16 @@
import { ConfigService } from '@nestjs/config';
const DEV_FALLBACK = 'fabric-trade-dev-secret';
/**
* امضا و اعتبارسنجی توکن باید از یک منبع بخوانند؛ در production نبود مقدار خطای راه‌اندازی است.
*/
export function resolveJwtSecret(config: ConfigService): string {
const secret = config.get<string>('JWT_SECRET')?.trim();
if (secret) return secret;
if (config.get<string>('NODE_ENV') === 'production') {
throw new Error('JWT_SECRET تنظیم نشده است');
}
return DEV_FALLBACK;
}
+2 -2
View File
@@ -8,10 +8,10 @@ export function splitFullName(name: string): {
}
const parts = trimmed.split(' ');
if (parts.length === 1) {
return { firstName: parts[0]!, lastName: '' };
return { firstName: parts[0], lastName: '' };
}
return {
firstName: parts[0]!,
firstName: parts[0],
lastName: parts.slice(1).join(' '),
};
}
+29 -4
View File
@@ -2,19 +2,43 @@ import { OrderStatus } from '@prisma/client';
/** Admin UI simplified statuses → full Prisma OrderStatus values */
export const ADMIN_STATUS_MAP: Record<string, OrderStatus[]> = {
pending_review: [OrderStatus.awaiting_review, OrderStatus.pricing],
pending_review: [
OrderStatus.cart,
OrderStatus.awaiting_settlement,
OrderStatus.cash_in_progress,
OrderStatus.check_in_progress,
OrderStatus.submitted,
OrderStatus.awaiting_review,
OrderStatus.pricing,
OrderStatus.cash_invoice_issued,
OrderStatus.awaiting_cash_payment,
OrderStatus.cash_payment_submitted,
OrderStatus.awaiting_cash_confirmation,
],
pending_check: [OrderStatus.awaiting_check_review],
needs_correction: [OrderStatus.needs_correction],
check_correction: [OrderStatus.check_needs_fix],
needs_correction: [
OrderStatus.needs_correction,
OrderStatus.awaiting_settlement_fix,
],
check_correction: [OrderStatus.check_needs_fix, OrderStatus.check_rejected],
final_approval: [
OrderStatus.final_approved,
OrderStatus.checks_approved,
OrderStatus.cash_confirmed,
OrderStatus.preparing,
OrderStatus.ready_to_ship,
],
shipped: [OrderStatus.shipped],
delivered: [OrderStatus.delivered],
};
/** وضعیت‌های پایانی عمداً در تب‌های جریان کاری نمی‌آیند و با برچسب خودشان نمایش داده می‌شوند. */
const TERMINAL_STATUSES: OrderStatus[] = [
OrderStatus.cancelled,
OrderStatus.rejected,
OrderStatus.expired,
];
export function resolveAdminStatusFilter(
status?: string,
): OrderStatus[] | undefined {
@@ -30,7 +54,8 @@ export function toAdminStatus(status: OrderStatus): string {
for (const [admin, list] of Object.entries(ADMIN_STATUS_MAP)) {
if (list.includes(status)) return admin;
}
return status;
if (TERMINAL_STATUSES.includes(status)) return status;
return 'pending_review';
}
export const ORDER_STATUS_LABELS: Record<OrderStatus, string> = {
+42
View File
@@ -0,0 +1,42 @@
/**
* محاسبات تقویمی باید مستقل از تایم‌زون سرور باشد؛ کانتینرها روی UTC اجرا می‌شوند.
* ایران از ۱۴۰۱ تغییر ساعت تابستانی ندارد، پس آفست ثابت +۰۳:۳۰ درست است.
*/
const TEHRAN_OFFSET_MS = (3 * 60 + 30) * 60 * 1000;
const DAY_MS = 24 * 60 * 60 * 1000;
function utcStartOfDay(date: Date): Date {
const d = new Date(date);
d.setUTCHours(0, 0, 0, 0);
return d;
}
/**
* روز تقویمی تهرانِ یک لحظه را به‌صورت نیمه‌شب UTC همان روز برمی‌گرداند.
* خروجی برای اختلاف‌گیری روزانه و سریال‌سازی `YYYY-MM-DD` امن است.
*/
export function tehranCalendarDay(date: Date): Date {
return utcStartOfDay(new Date(date.getTime() + TEHRAN_OFFSET_MS));
}
/** تاریخ سررسید فقط-روز است و نیمه‌شب UTC ذخیره می‌شود. */
export function calendarDayOf(date: Date | string): Date {
return utcStartOfDay(new Date(date));
}
export function addDays(date: Date, days: number): Date {
return new Date(date.getTime() + days * DAY_MS);
}
export function diffInDays(from: Date, to: Date): number {
return Math.round((to.getTime() - from.getTime()) / DAY_MS);
}
/** لحظه‌ای که در تهران ساعتِ داده‌شده از همان روزِ تقویمی است. */
export function tehranAtHour(date: Date, hour: number): Date {
return new Date(
tehranCalendarDay(date).getTime() +
hour * 60 * 60 * 1000 -
TEHRAN_OFFSET_MS,
);
}
+39 -26
View File
@@ -21,7 +21,9 @@ export class CompaniesService {
where: activeOnly ? { isActive: true } : undefined,
orderBy: [{ displayOrder: 'asc' }, { name: 'asc' }],
include: {
_count: { select: { catalogs: true, products: true, bankAccounts: true } },
_count: {
select: { catalogs: true, products: true, bankAccounts: true },
},
},
});
return companies.map((c) => this.mapCompany(c));
@@ -32,7 +34,9 @@ export class CompaniesService {
where: { id },
include: {
bankAccounts: { orderBy: { displayOrder: 'asc' } },
_count: { select: { catalogs: true, products: true, bankAccounts: true } },
_count: {
select: { catalogs: true, products: true, bankAccounts: true },
},
},
});
if (!company) throw new NotFoundException('شرکت یافت نشد');
@@ -57,12 +61,17 @@ export class CompaniesService {
isActive: dto.isActive ?? true,
},
include: {
_count: { select: { catalogs: true, products: true, bankAccounts: true } },
_count: {
select: { catalogs: true, products: true, bankAccounts: true },
},
},
});
return this.mapCompany(company);
} catch (e) {
if (e instanceof Prisma.PrismaClientKnownRequestError && e.code === 'P2002') {
if (
e instanceof Prisma.PrismaClientKnownRequestError &&
e.code === 'P2002'
) {
throw new ConflictException('اسلاگ شرکت تکراری است');
}
throw e;
@@ -90,12 +99,17 @@ export class CompaniesService {
isActive: dto.isActive,
},
include: {
_count: { select: { catalogs: true, products: true, bankAccounts: true } },
_count: {
select: { catalogs: true, products: true, bankAccounts: true },
},
},
});
return this.mapCompany(company);
} catch (e) {
if (e instanceof Prisma.PrismaClientKnownRequestError && e.code === 'P2002') {
if (
e instanceof Prisma.PrismaClientKnownRequestError &&
e.code === 'P2002'
) {
throw new ConflictException('اسلاگ شرکت تکراری است');
}
throw e;
@@ -108,7 +122,9 @@ export class CompaniesService {
where: { id },
data: { isActive },
include: {
_count: { select: { catalogs: true, products: true, bankAccounts: true } },
_count: {
select: { catalogs: true, products: true, bankAccounts: true },
},
},
});
return this.mapCompany(company);
@@ -151,8 +167,7 @@ export class CompaniesService {
accountNumber: dto.accountNumber?.trim(),
cardNumber: dto.cardNumber?.trim(),
iban: dto.iban?.trim(),
notes:
dto.notes === undefined ? undefined : dto.notes?.trim() || null,
notes: dto.notes === undefined ? undefined : dto.notes?.trim() || null,
displayOrder: dto.displayOrder,
isActive: dto.isActive,
},
@@ -181,23 +196,21 @@ export class CompaniesService {
return account;
}
private mapCompany(
company: {
id: string;
name: string;
slug: string;
description: string | null;
logoUrl: string | null;
isActive: boolean;
displayOrder: number;
maxMeteragePerInvoice: number;
cashInvoiceValidityHours: number;
cashInvoiceValidUntilHour: number | null;
createdAt: Date;
updatedAt: Date;
_count?: { catalogs: number; products: number; bankAccounts: number };
},
) {
private mapCompany(company: {
id: string;
name: string;
slug: string;
description: string | null;
logoUrl: string | null;
isActive: boolean;
displayOrder: number;
maxMeteragePerInvoice: number;
cashInvoiceValidityHours: number;
cashInvoiceValidUntilHour: number | null;
createdAt: Date;
updatedAt: Date;
_count?: { catalogs: number; products: number; bankAccounts: number };
}) {
return {
id: company.id,
name: company.name,
+13 -3
View File
@@ -83,7 +83,10 @@ export class CustomersService {
});
return this.map(customer);
} catch (e) {
if (e instanceof Prisma.PrismaClientKnownRequestError && e.code === 'P2002') {
if (
e instanceof Prisma.PrismaClientKnownRequestError &&
e.code === 'P2002'
) {
throw new ConflictException('این شماره قبلاً ثبت شده است');
}
throw e;
@@ -102,7 +105,11 @@ export class CustomersService {
let firstName: string | undefined;
let lastName: string | undefined;
if (dto.name !== undefined || dto.firstName !== undefined || dto.lastName !== undefined) {
if (
dto.name !== undefined ||
dto.firstName !== undefined ||
dto.lastName !== undefined
) {
const names = this.resolveNames(dto);
firstName = names.firstName;
lastName = names.lastName;
@@ -131,7 +138,10 @@ export class CustomersService {
});
return this.map(customer);
} catch (e) {
if (e instanceof Prisma.PrismaClientKnownRequestError && e.code === 'P2002') {
if (
e instanceof Prisma.PrismaClientKnownRequestError &&
e.code === 'P2002'
) {
throw new ConflictException('این شماره قبلاً ثبت شده است');
}
throw e;
+14 -8
View File
@@ -107,11 +107,7 @@ export class DashboardService {
const sumAmounts = (
rows: { finalAmount: number | null; totalAmount: number | null }[],
) =>
rows.reduce(
(s, o) => s + (o.finalAmount ?? o.totalAmount ?? 0),
0,
);
) => rows.reduce((s, o) => s + (o.finalAmount ?? o.totalAmount ?? 0), 0);
const todaySales = sumAmounts(todayOrders);
const yesterdaySales = sumAmounts(yesterdayOrders);
@@ -130,7 +126,7 @@ export class DashboardService {
(24 * 60 * 60 * 1000),
);
if (dayIndex >= 0 && dayIndex < 28) {
salesByDay[dayIndex]! += order.finalAmount ?? order.totalAmount ?? 0;
salesByDay[dayIndex] += order.finalAmount ?? order.totalAmount ?? 0;
}
}
const maxSale = Math.max(...salesByDay, 1);
@@ -189,7 +185,12 @@ export class DashboardService {
const byCompany = new Map<
string,
{ companyName: string; orderCount: number; totalAmount: number; meterage: number }
{
companyName: string;
orderCount: number;
totalAmount: number;
meterage: number;
}
>();
const byStatus = new Map<string, number>();
@@ -228,7 +229,12 @@ export class DashboardService {
{ id: 'cd-today', label: 'امروز', tone: 'danger' as const, days: 0 },
{ id: 'cd-3', label: '۳ روز آینده', tone: 'warning' as const, days: 3 },
{ id: 'cd-7', label: '۷ روز آینده', tone: 'warning' as const, days: 7 },
{ id: 'cd-30', label: '۳۰ روز آینده', tone: 'neutral' as const, days: 30 },
{
id: 'cd-30',
label: '۳۰ روز آینده',
tone: 'neutral' as const,
days: 30,
},
];
return buckets.map((bucket) => {
+10 -2
View File
@@ -1,11 +1,17 @@
import { NestFactory } from '@nestjs/core';
import { ValidationPipe } from '@nestjs/common';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import { json, urlencoded } from 'express';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// تصاویر چک و رسید به‌صورت base64 داخل JSON می‌آیند و از سقف پیش‌فرض ۱۰۰KB رد می‌شوند
const bodyLimit = process.env.BODY_LIMIT || '25mb';
app.use(json({ limit: bodyLimit }));
app.use(urlencoded({ extended: true, limit: bodyLimit }));
// پشت LiteSpeed روی /server → GLOBAL_PREFIX=server/api
const globalPrefix = process.env.GLOBAL_PREFIX || 'api';
app.setGlobalPrefix(globalPrefix);
@@ -33,7 +39,9 @@ async function bootstrap() {
const port = process.env.PORT ?? 3000;
await app.listen(port);
console.log(`Fabric Trade API listening on http://localhost:${port}/${globalPrefix}`);
console.log(
`Fabric Trade API listening on http://localhost:${port}/${globalPrefix}`,
);
console.log(`Swagger docs at http://localhost:${port}/${globalPrefix}/docs`);
}
bootstrap();
void bootstrap();
+11
View File
@@ -25,6 +25,12 @@ export class SubmitOrderItemDto {
@Min(0.001)
meterage!: number;
/** Alias پذیرفته‌شده از کلاینت‌های قدیمی؛ نادیده گرفته می‌شود */
@IsOptional()
@Type(() => Number)
@IsNumber()
requestedMeterage?: number;
@IsOptional()
@IsString()
notes?: string;
@@ -91,6 +97,11 @@ export class SubmitOrderDto {
@IsEnum(SettlementType)
settlementType!: SettlementType;
/** Alias پذیرفته‌شده از کلاینت‌های قدیمی؛ نادیده گرفته می‌شود */
@IsOptional()
@IsEnum(SettlementType)
settlementMethod?: SettlementType;
@IsOptional()
@IsEnum(CheckRegistrationMode)
checkMode?: CheckRegistrationMode;
+3 -12
View File
@@ -31,19 +31,13 @@ export class CustomerOrdersController {
@AuthType('customer')
@Get(':id')
findOne(
@CurrentUser() user: AuthPrincipal,
@Param('id') id: string,
) {
findOne(@CurrentUser() user: AuthPrincipal, @Param('id') id: string) {
return this.ordersService.findMyOrder(user.id, id);
}
@AuthType('customer')
@Post()
submit(
@CurrentUser() user: AuthPrincipal,
@Body() dto: SubmitOrderDto,
) {
submit(@CurrentUser() user: AuthPrincipal, @Body() dto: SubmitOrderDto) {
return this.ordersService.submitOrder(user.id, dto);
}
@@ -74,10 +68,7 @@ export class AdminOrdersController {
}
@Post()
create(
@CurrentUser() user: AuthPrincipal,
@Body() dto: AdminCreateOrderDto,
) {
create(@CurrentUser() user: AuthPrincipal, @Body() dto: AdminCreateOrderDto) {
return this.ordersService.adminCreate(user.id, dto);
}
+150 -97
View File
@@ -45,6 +45,23 @@ const orderInclude = {
type OrderFull = Prisma.OrderGetPayload<{ include: typeof orderInclude }>;
/** مبالغ ریالی روی Float ذخیره می‌شوند؛ گرد کردن از انباشت خطای اعشاری جلوگیری می‌کند. */
function roundMoney(value: number): number {
return Math.round(value * 100) / 100;
}
/** بعد از تأیید چک‌ها یا ارسال سفارش، مشتری نباید بتواند چک‌ها را بازنویسی کند. */
const CHECK_EDITABLE_STATUSES: OrderStatus[] = [
OrderStatus.awaiting_review,
OrderStatus.pricing,
OrderStatus.needs_correction,
OrderStatus.awaiting_settlement_fix,
OrderStatus.check_in_progress,
OrderStatus.awaiting_check_review,
OrderStatus.check_needs_fix,
OrderStatus.check_rejected,
];
@Injectable()
export class OrdersService {
constructor(private readonly prisma: PrismaService) {}
@@ -180,62 +197,62 @@ export class OrdersService {
? computeCashInvoiceExpiry(company)
: null;
const orderNumber = await this.nextOrderNumber();
const order = await this.prisma.$transaction(async (tx) => {
const created = await tx.order.create({
data: {
orderNumber,
userId,
companyId: company.id,
companyName: company.name,
settlementType,
checkMode,
status: OrderStatus.awaiting_review,
totalMeterage,
notes: dto.notes?.trim() || null,
checkRassDays: rass?.rassDays ?? null,
checkRassDate: rass?.rassDate ? new Date(rass.rassDate) : null,
cashInvoiceExpiresAt,
items: { create: itemsData },
checks:
settlementType === SettlementType.check && dto.checks
? {
create: dto.checks.map((c, index) =>
this.mapCheckCreate(c, index + 1, checkMode!),
),
}
: undefined,
statusHistory: {
create: [
{
fromStatus: null,
toStatus: OrderStatus.submitted,
changedBy: 'customer',
note: 'سفارش ثبت شد',
},
{
fromStatus: OrderStatus.submitted,
toStatus: OrderStatus.awaiting_review,
changedBy: 'customer',
note: 'ارسال برای بررسی مدیریت',
},
],
const order = await this.createWithUniqueOrderNumber((orderNumber) =>
this.prisma.$transaction(async (tx) => {
const created = await tx.order.create({
data: {
orderNumber,
userId,
companyId: company.id,
companyName: company.name,
settlementType,
checkMode,
status: OrderStatus.awaiting_review,
totalMeterage,
notes: dto.notes?.trim() || null,
checkRassDays: rass?.rassDays ?? null,
checkRassDate: rass?.rassDate ? new Date(rass.rassDate) : null,
cashInvoiceExpiresAt,
items: { create: itemsData },
checks:
settlementType === SettlementType.check && dto.checks
? {
create: dto.checks.map((c, index) =>
this.mapCheckCreate(c, index + 1, checkMode!),
),
}
: undefined,
statusHistory: {
create: [
{
fromStatus: null,
toStatus: OrderStatus.submitted,
changedBy: 'customer',
note: 'سفارش ثبت شد',
},
{
fromStatus: OrderStatus.submitted,
toStatus: OrderStatus.awaiting_review,
changedBy: 'customer',
note: 'ارسال برای بررسی مدیریت',
},
],
},
},
},
include: orderInclude,
});
// Clear cart items for this company after successful submit
const cart = await tx.cart.findFirst({ where: { userId } });
if (cart) {
await tx.cartItem.deleteMany({
where: { cartId: cart.id, companyId: company.id },
include: orderInclude,
});
}
return created;
});
// Clear cart items for this company after successful submit
const cart = await tx.cart.findFirst({ where: { userId } });
if (cart) {
await tx.cartItem.deleteMany({
where: { cartId: cart.id, companyId: company.id },
});
}
return created;
}),
);
return this.mapOrder(order);
}
@@ -257,7 +274,9 @@ export class OrdersService {
if (!isValidPhone(phone)) {
throw new BadRequestException('شماره موبایل نامعتبر است');
}
let customer = await this.prisma.customer.findUnique({ where: { phone } });
let customer = await this.prisma.customer.findUnique({
where: { phone },
});
if (!customer) {
const names = splitFullName(dto.customerName || 'مشتری جدید');
customer = await this.prisma.customer.create({
@@ -274,67 +293,79 @@ export class OrdersService {
throw new BadRequestException('شناسه یا شماره مشتری الزامی است');
}
const orderNumber = await this.nextOrderNumber();
const totalMeterage = dto.meterage ?? 0;
const ownerId = userId;
const order = await this.prisma.order.create({
data: {
orderNumber,
userId,
companyId: company.id,
companyName: company.name,
settlementType,
status: OrderStatus.awaiting_review,
totalMeterage,
notes: dto.notes?.trim() || null,
statusHistory: {
create: {
fromStatus: null,
toStatus: OrderStatus.awaiting_review,
changedBy: `admin:${adminId}`,
note: 'سفارش توسط ادمین ثبت شد',
const order = await this.createWithUniqueOrderNumber((orderNumber) =>
this.prisma.order.create({
data: {
orderNumber,
userId: ownerId,
companyId: company.id,
companyName: company.name,
settlementType,
status: OrderStatus.awaiting_review,
totalMeterage,
notes: dto.notes?.trim() || null,
statusHistory: {
create: {
fromStatus: null,
toStatus: OrderStatus.awaiting_review,
changedBy: `admin:${adminId}`,
note: 'سفارش توسط ادمین ثبت شد',
},
},
},
},
include: orderInclude,
});
include: orderInclude,
}),
);
return this.mapOrder(order, true);
}
async updatePricing(
id: string,
adminId: string,
dto: UpdateOrderPricingDto,
) {
async updatePricing(id: string, adminId: string, dto: UpdateOrderPricingDto) {
const order = await this.getOrder(id);
const unknown = dto.items.find(
(item) => !order.items.some((i) => i.id === item.id),
);
if (unknown) {
throw new BadRequestException(`آیتم ${unknown.id} یافت نشد`);
}
await this.prisma.$transaction(async (tx) => {
let totalAmount = 0;
let totalMeterage = 0;
for (const item of dto.items) {
const existing = order.items.find((i) => i.id === item.id);
if (!existing) {
throw new BadRequestException(`آیتم ${item.id} یافت نشد`);
}
// جمع کل باید روی همه آیتم‌های سفارش حساب شود، نه فقط آیتم‌های ارسالی
for (const existing of order.items) {
const item = dto.items.find((i) => i.id === existing.id);
const unitPrice =
item.unitPrice !== undefined
item?.unitPrice !== undefined
? item.unitPrice
: item.supplyPrice !== undefined
: item?.supplyPrice !== undefined
? item.supplyPrice
: (existing.unitPrice ?? 0);
const unitDiscount = item.unitDiscount ?? existing.unitDiscount ?? 0;
const unitDiscount = item?.unitDiscount ?? existing.unitDiscount ?? 0;
if (unitDiscount > unitPrice) {
throw new BadRequestException(
'تخفیف واحد نمی‌تواند از قیمت واحد بیشتر باشد',
);
}
const confirmed =
item.confirmedMeterage ??
item?.confirmedMeterage ??
existing.confirmedMeterage ??
existing.requestedMeterage;
const lineTotal = Math.max(0, (unitPrice - unitDiscount) * confirmed);
const lineTotal = roundMoney(
Math.max(0, (unitPrice - unitDiscount) * confirmed),
);
totalAmount += lineTotal;
totalMeterage += confirmed;
if (!item) continue;
await tx.orderItem.update({
where: { id: item.id },
where: { id: existing.id },
data: {
confirmedMeterage: confirmed,
unitPrice,
@@ -343,10 +374,13 @@ export class OrdersService {
},
});
}
totalAmount = roundMoney(totalAmount);
const shippingCost = dto.shippingCost ?? order.shippingCost ?? 0;
const totalDiscount = dto.totalDiscount ?? order.totalDiscount ?? 0;
const finalAmount = Math.max(0, totalAmount + shippingCost - totalDiscount);
const finalAmount = roundMoney(
Math.max(0, totalAmount + shippingCost - totalDiscount),
);
const nextStatus =
order.status === OrderStatus.awaiting_review ||
@@ -382,11 +416,7 @@ export class OrdersService {
return this.findAdminOrder(id);
}
async updateStatus(
id: string,
adminId: string,
dto: UpdateOrderStatusDto,
) {
async updateStatus(id: string, adminId: string, dto: UpdateOrderStatusDto) {
const order = await this.getOrder(id);
if (order.status === dto.status) {
return this.mapOrder(order, true);
@@ -435,8 +465,14 @@ export class OrdersService {
if (order.settlementType !== SettlementType.check) {
throw new BadRequestException('این سفارش تسویه چکی نیست');
}
if (!CHECK_EDITABLE_STATUSES.includes(order.status)) {
throw new BadRequestException(
'در وضعیت فعلی سفارش امکان ویرایش چک‌ها وجود ندارد',
);
}
const checkMode = dto.checkMode ?? order.checkMode ?? CheckRegistrationMode.full;
const checkMode =
dto.checkMode ?? order.checkMode ?? CheckRegistrationMode.full;
const rass = calculateCheckRass(
dto.checks.map((c) => ({ amount: c.amount, dueDate: c.dueDate })),
order.createdAt,
@@ -512,6 +548,23 @@ export class OrdersService {
return `${generateOrderNumber()}-${Date.now().toString().slice(-3)}`;
}
/** بین انتخاب شماره و درج، امکان تصاحب شماره توسط درخواست هم‌زمان هست. */
private async createWithUniqueOrderNumber<T>(
create: (orderNumber: string) => Promise<T>,
): Promise<T> {
for (let attempt = 0; ; attempt++) {
const orderNumber = await this.nextOrderNumber();
try {
return await create(orderNumber);
} catch (e) {
const isDuplicate =
e instanceof Prisma.PrismaClientKnownRequestError &&
e.code === 'P2002';
if (!isDuplicate || attempt >= 4) throw e;
}
}
}
private async getOrder(id: string): Promise<OrderFull> {
const order = await this.prisma.order.findUnique({
where: { id },
+8 -2
View File
@@ -81,7 +81,10 @@ export class ProductsService {
});
return this.map(product);
} catch (e) {
if (e instanceof Prisma.PrismaClientKnownRequestError && e.code === 'P2002') {
if (
e instanceof Prisma.PrismaClientKnownRequestError &&
e.code === 'P2002'
) {
throw new ConflictException('کد محصول در این شرکت تکراری است');
}
throw e;
@@ -135,7 +138,10 @@ export class ProductsService {
});
return this.map(product);
} catch (e) {
if (e instanceof Prisma.PrismaClientKnownRequestError && e.code === 'P2002') {
if (
e instanceof Prisma.PrismaClientKnownRequestError &&
e.code === 'P2002'
) {
throw new ConflictException('کد محصول در این شرکت تکراری است');
}
throw e;
+1 -4
View File
@@ -34,10 +34,7 @@ export class ShipmentsController {
}
@Post()
create(
@CurrentUser() user: AuthPrincipal,
@Body() dto: CreateShipmentDto,
) {
create(@CurrentUser() user: AuthPrincipal, @Body() dto: CreateShipmentDto) {
return this.shipmentsService.create(user.id, dto);
}
+1 -1
View File
@@ -158,7 +158,7 @@ export class ShipmentsService {
include: { order: { include: { user: true } } },
});
const nextOrderStatus = SHIPMENT_TO_ORDER[nextStatus!];
const nextOrderStatus = SHIPMENT_TO_ORDER[nextStatus];
if (shipment.order.status !== nextOrderStatus) {
await tx.order.update({
where: { id: shipment.orderId },
+8
View File
@@ -0,0 +1,8 @@
import { Module } from '@nestjs/common';
import { SmsService } from './sms.service';
@Module({
providers: [SmsService],
exports: [SmsService],
})
export class SmsModule {}
+109
View File
@@ -0,0 +1,109 @@
import { Injectable, Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
export type SmsSendResult = {
success: boolean;
raw: unknown;
};
function maskPhone(phone: string): string {
return phone.length <= 4
? '****'
: `${phone.slice(0, 4)}****${phone.slice(-2)}`;
}
@Injectable()
export class SmsService {
private readonly logger = new Logger(SmsService.name);
constructor(private readonly config: ConfigService) {}
isEnabled(): boolean {
const raw = (
this.config.get<string>('SMS_ENABLED', 'true') ?? 'true'
).toLowerCase();
return raw === '1' || raw === 'true' || raw === 'yes';
}
async send(to: string, message: string): Promise<SmsSendResult> {
const url = this.config.get<string>(
'SMS_API_URL',
'http://185.231.112.101/api/createsms',
);
const secretKey = this.config.get<string>('SMS_SECRET_KEY')?.trim();
if (!secretKey) {
this.logger.error('SMS_SECRET_KEY تنظیم نشده است');
return { success: false, raw: 'SMS_SECRET_KEY missing' };
}
const platform = this.config.get<string>('SMS_PLATFORM', 'rayegansms');
const host = this.resolveHost();
try {
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
secret_key: secretKey,
},
body: JSON.stringify({
phone: to,
host,
text: message.trim(),
platform,
}),
signal: AbortSignal.timeout(15_000),
});
const text = await response.text();
let body: unknown = text;
try {
body = text ? JSON.parse(text) : null;
} catch {
/* keep raw text */
}
let success = response.ok;
if (success && body && typeof body === 'object') {
const obj = body as Record<string, unknown>;
if ('success' in obj && obj.success === false) success = false;
else if ('ok' in obj && obj.ok === false) success = false;
else if (
typeof obj.status === 'string' &&
['error', 'failed', 'fail'].includes(obj.status.toLowerCase())
) {
success = false;
}
}
if (!success) {
this.logger.warn(
`SMS failed to ${maskPhone(to)}: ${JSON.stringify(body)}`,
);
}
return { success, raw: body };
} catch (err) {
this.logger.error(
`SMS request error to ${maskPhone(to)}`,
err instanceof Error ? err.stack : err,
);
return {
success: false,
raw: err instanceof Error ? err.message : String(err),
};
}
}
buildOtpMessage(code: string): string {
const appName = this.config.get<string>('SMS_APP_NAME', 'پارچه');
return `رمز عبور یکبار مصرف شما جهت ورود به اپلیکیشن ${appName} ${code} می باشد`;
}
private resolveHost(): string {
const fromEnv =
this.config.get<string>('SMS_HOST')?.trim() ||
this.config.get<string>('SMS_APP_NAME')?.trim();
if (fromEnv) return fromEnv;
return 'fabric';
}
}