build: rebuild release bundles for build 181
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Haiku 5.5
parent
532ceee189
commit
c845f6db19
+268
-21
@@ -88603,6 +88603,23 @@ var require_sms_service = __commonJS({
|
||||
}
|
||||
});
|
||||
|
||||
// dist/common/brand.js
|
||||
var require_brand = __commonJS({
|
||||
"dist/common/brand.js"(exports2) {
|
||||
"use strict";
|
||||
Object.defineProperty(exports2, "__esModule", { value: true });
|
||||
exports2.brandName = brandName;
|
||||
exports2.brandSiteUrl = brandSiteUrl;
|
||||
var env_12 = require_env();
|
||||
function brandName() {
|
||||
return (0, env_12.envOr)("BRAND_NAME", "\u0632\u0631\u062A\u0627\u062C");
|
||||
}
|
||||
function brandSiteUrl() {
|
||||
return (0, env_12.envOr)("BRAND_SITE_URL", "https://bnk.montzar.ir");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// dist/modules/customer-auth/customer-auth.service.js
|
||||
var require_customer_auth_service = __commonJS({
|
||||
"dist/modules/customer-auth/customer-auth.service.js"(exports2) {
|
||||
@@ -88673,6 +88690,7 @@ var require_customer_auth_service = __commonJS({
|
||||
var customer_jwt_strategy_1 = require_customer_jwt_strategy();
|
||||
var digits_1 = require_digits();
|
||||
var sms_service_12 = require_sms_service();
|
||||
var brand_1 = require_brand();
|
||||
var TooManyRequestsException = class extends common_12.HttpException {
|
||||
constructor(message) {
|
||||
super(message, common_12.HttpStatus.TOO_MANY_REQUESTS);
|
||||
@@ -88684,6 +88702,8 @@ var require_customer_auth_service = __commonJS({
|
||||
var MAX_SENDS_PER_IP = 20;
|
||||
var SEND_WINDOW_MS = 10 * 60 * 1e3;
|
||||
var RESEND_COOLDOWN_MS = 60 * 1e3;
|
||||
var MAX_REGISTRATIONS_PER_IP = 5;
|
||||
var REGISTER_WINDOW_MS = 60 * 60 * 1e3;
|
||||
function masterOtpCode() {
|
||||
if (!(0, production_checks_12.masterCodeAllowed)(process.env))
|
||||
return null;
|
||||
@@ -88766,6 +88786,13 @@ var require_customer_auth_service = __commonJS({
|
||||
select: { id: true }
|
||||
});
|
||||
if (!customer) {
|
||||
const pending = await this.prisma.customer.findFirst({
|
||||
where: { mobile, isActive: false, isArchived: false, verificationStep: client_1.VerificationStep.STEP_ONE_SUBMITTED },
|
||||
select: { id: true }
|
||||
});
|
||||
if (pending) {
|
||||
throw new common_12.ForbiddenException("\u062B\u0628\u062A \u0646\u0627\u0645 \u0634\u0645\u0627 \u062F\u0631 \u0627\u0646\u062A\u0638\u0627\u0631 \u062A\u0627\u06CC\u06CC\u062F \u06A9\u0627\u0631\u0634\u0646\u0627\u0633\u0627\u0646 \u0627\u0633\u062A. \u067E\u0633 \u0627\u0632 \u062A\u0627\u06CC\u06CC\u062F \u0645\u06CC\u200C\u062A\u0648\u0627\u0646\u06CC\u062F \u0648\u0627\u0631\u062F \u0634\u0648\u06CC\u062F.");
|
||||
}
|
||||
this.logger.warn(`OTP requested for unknown or inactive mobile ${mobile}`);
|
||||
throw new common_12.NotFoundException("\u0627\u06CC\u0646 \u0634\u0645\u0627\u0631\u0647 \u062F\u0631 \u0633\u06CC\u0633\u062A\u0645 \u062B\u0628\u062A \u0646\u0634\u062F\u0647 \u0627\u0633\u062A. \u0644\u0637\u0641\u0627\u064B \u0628\u0627 \u067E\u0634\u062A\u06CC\u0628\u0627\u0646\u06CC \u062A\u0645\u0627\u0633 \u0628\u06AF\u06CC\u0631\u06CC\u062F.");
|
||||
}
|
||||
@@ -88782,6 +88809,81 @@ var require_customer_auth_service = __commonJS({
|
||||
await this.deliver(mobile, code);
|
||||
return { sent: true };
|
||||
}
|
||||
/**
|
||||
* Self-registration from the app — port of Major/CustomerController::register
|
||||
* (henza_server :19-75). Before this the app's register form was a stub that
|
||||
* showed "registered" and saved nothing, so new customers never reached the
|
||||
* admin's «مشتریان در انتظار» list.
|
||||
*
|
||||
* Uses the reference's ORIGINAL review flow (its commented-out "نیاز به تایید
|
||||
* ادمین" block), not the later auto-approve: the row is inactive with step one
|
||||
* awaiting review, which is exactly what that list shows. Approving step one
|
||||
* in the admin panel activates it (AdminCustomersService.verify). Credit limit
|
||||
* and wage offset stay at their defaults for the admin to set on review.
|
||||
*/
|
||||
async register(dto, ip) {
|
||||
const mobile = (0, digits_1.faToEn)(dto.mobile);
|
||||
if (!/^09\d{9}$/.test(mobile)) {
|
||||
throw new common_12.BadRequestException("\u0634\u0645\u0627\u0631\u0647 \u0645\u0648\u0628\u0627\u06CC\u0644 \u0645\u0639\u062A\u0628\u0631 \u0646\u06CC\u0633\u062A");
|
||||
}
|
||||
this.assertRegisterAllowed(ip);
|
||||
const fname = dto.fname.trim();
|
||||
const lname = dto.lname.trim();
|
||||
const existing = await this.prisma.customer.findUnique({ where: { mobile }, select: { id: true } });
|
||||
if (existing) {
|
||||
throw new common_12.ConflictException("\u0627\u06CC\u0646 \u0634\u0645\u0627\u0631\u0647 \u0645\u0648\u0628\u0627\u06CC\u0644 \u0642\u0628\u0644\u0627\u064B \u062B\u0628\u062A \u0634\u062F\u0647 \u0627\u0633\u062A. \u0627\u0632 \u0628\u062E\u0634 \u0648\u0631\u0648\u062F \u0648\u0627\u0631\u062F \u0634\u0648\u06CC\u062F.");
|
||||
}
|
||||
try {
|
||||
await this.prisma.customer.create({
|
||||
data: {
|
||||
fullName: `${fname} ${lname}`,
|
||||
firstName: fname,
|
||||
lastName: lname,
|
||||
mobile,
|
||||
passwordHash: password_hash_1.OTP_ONLY_PASSWORD_HASH,
|
||||
kind: client_1.CustomerKind.APP_SHOPKEEPER,
|
||||
storeName: dto.store_name.trim(),
|
||||
phone: (0, digits_1.faToEn)(dto.phone),
|
||||
address: dto.address.trim(),
|
||||
cityNameRaw: dto.city.trim(),
|
||||
verificationStep: client_1.VerificationStep.STEP_ONE_SUBMITTED,
|
||||
isActive: false
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
if (e instanceof client_1.Prisma.PrismaClientKnownRequestError && e.code === "P2002") {
|
||||
throw new common_12.ConflictException("\u0627\u06CC\u0646 \u0634\u0645\u0627\u0631\u0647 \u0645\u0648\u0628\u0627\u06CC\u0644 \u0642\u0628\u0644\u0627\u064B \u062B\u0628\u062A \u0634\u062F\u0647 \u0627\u0633\u062A. \u0627\u0632 \u0628\u062E\u0634 \u0648\u0631\u0648\u062F \u0648\u0627\u0631\u062F \u0634\u0648\u06CC\u062F.");
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
const brand = (0, brand_1.brandName)();
|
||||
const fire = (to, body) => {
|
||||
void this.sms.send(to, body).catch((err) => {
|
||||
this.logger.error(`Registration SMS to ${to} failed: ${String(err)}`);
|
||||
});
|
||||
};
|
||||
fire(mobile, `${brand}
|
||||
\u0647\u0645\u06A9\u0627\u0631 \u06AF\u0631\u0627\u0645\u06CC ${fname} ${lname}
|
||||
\u062B\u0628\u062A \u0646\u0627\u0645 \u0634\u0645\u0627 \u0628\u0627 \u0645\u0648\u0641\u0642\u06CC\u062A \u0627\u0646\u062C\u0627\u0645 \u0634\u062F \u0648 \u062F\u0631 \u0627\u0646\u062A\u0638\u0627\u0631 \u062A\u0627\u06CC\u06CC\u062F \u06A9\u0627\u0631\u0634\u0646\u0627\u0633\u0627\u0646 \u0627\u0633\u062A.`);
|
||||
for (const admin of (0, env_12.envList)("PROFILE_ADMIN_MOBILES")) {
|
||||
fire(admin, `${brand}
|
||||
\u0645\u0634\u062A\u0631\u06CC \u0628\u0627 \u0646\u0627\u0645 ${fname} ${lname} \u062B\u0628\u062A \u0646\u0627\u0645 \u06A9\u0631\u062F \u0648 \u062F\u0631 \u0627\u0646\u062A\u0638\u0627\u0631 \u062A\u0627\u06CC\u06CC\u062F \u0627\u0633\u062A.`);
|
||||
}
|
||||
return { ok: true };
|
||||
}
|
||||
/** Public endpoint with an SMS side effect: cap how many accounts one IP can open. */
|
||||
registrationsByIp = /* @__PURE__ */ new Map();
|
||||
assertRegisterAllowed(ip) {
|
||||
if (!ip)
|
||||
return;
|
||||
const now = Date.now();
|
||||
const recent = (this.registrationsByIp.get(ip) ?? []).filter((t) => now - t < REGISTER_WINDOW_MS);
|
||||
if (recent.length >= MAX_REGISTRATIONS_PER_IP) {
|
||||
throw new TooManyRequestsException("\u062A\u0639\u062F\u0627\u062F \u062B\u0628\u062A \u0646\u0627\u0645\u200C\u0647\u0627 \u0628\u06CC\u0634 \u0627\u0632 \u062D\u062F \u0645\u062C\u0627\u0632 \u0627\u0633\u062A. \u0644\u0637\u0641\u0627\u064B \u0628\u0639\u062F\u0627\u064B \u062A\u0644\u0627\u0634 \u06A9\u0646\u06CC\u062F.");
|
||||
}
|
||||
recent.push(now);
|
||||
this.registrationsByIp.set(ip, recent);
|
||||
}
|
||||
/**
|
||||
* D21 — find an active sales expert by mobile and return their trading
|
||||
* Customer account, creating it on first sign-in.
|
||||
@@ -89245,7 +89347,7 @@ var require_customer_auth_service = __commonJS({
|
||||
*/
|
||||
async deliver(mobile, code) {
|
||||
const smsText = `<#> code is ${code}
|
||||
\u0631\u0645\u0632 \u0639\u0628\u0648\u0631 \u06CC\u06A9\u0628\u0627\u0631 \u0645\u0635\u0631\u0641 \u0634\u0645\u0627 \u062C\u0647\u062A \u0648\u0631\u0648\u062F \u0628\u0647 \u0627\u067E\u0644\u06CC\u06A9\u06CC\u0634\u0646 \u0645\u0646\u062A\u0632\u0631 ${code} \u0645\u06CC \u0628\u0627\u0634\u062F
|
||||
\u0631\u0645\u0632 \u0639\u0628\u0648\u0631 \u06CC\u06A9\u0628\u0627\u0631 \u0645\u0635\u0631\u0641 \u0634\u0645\u0627 \u062C\u0647\u062A \u0648\u0631\u0648\u062F \u0628\u0647 \u0627\u067E\u0644\u06CC\u06A9\u06CC\u0634\u0646 ${(0, brand_1.brandName)()} ${code} \u0645\u06CC \u0628\u0627\u0634\u062F
|
||||
aMo6iFyUQaY`;
|
||||
const result = await this.sms.send(mobile, smsText, { persist: false });
|
||||
const devNoGateway = process.env.NODE_ENV !== "production" && !result.ok && result.error === "sms-not-configured";
|
||||
@@ -89348,6 +89450,77 @@ var require_verify_otp_dto = __commonJS({
|
||||
}
|
||||
});
|
||||
|
||||
// dist/modules/customer-auth/dto/register.dto.js
|
||||
var require_register_dto = __commonJS({
|
||||
"dist/modules/customer-auth/dto/register.dto.js"(exports2) {
|
||||
"use strict";
|
||||
var __decorate4 = exports2 && exports2.__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 __metadata3 = exports2 && exports2.__metadata || function(k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
Object.defineProperty(exports2, "__esModule", { value: true });
|
||||
exports2.RegisterDto = void 0;
|
||||
var class_validator_1 = require_cjs();
|
||||
var RegisterDto = class {
|
||||
fname;
|
||||
lname;
|
||||
mobile;
|
||||
store_name;
|
||||
phone;
|
||||
address;
|
||||
city;
|
||||
};
|
||||
exports2.RegisterDto = RegisterDto;
|
||||
__decorate4([
|
||||
(0, class_validator_1.IsString)(),
|
||||
(0, class_validator_1.IsNotEmpty)({ message: "\u0646\u0627\u0645 \u0627\u0644\u0632\u0627\u0645\u06CC \u0627\u0633\u062A" }),
|
||||
(0, class_validator_1.MaxLength)(100),
|
||||
__metadata3("design:type", String)
|
||||
], RegisterDto.prototype, "fname", void 0);
|
||||
__decorate4([
|
||||
(0, class_validator_1.IsString)(),
|
||||
(0, class_validator_1.IsNotEmpty)({ message: "\u0646\u0627\u0645 \u062E\u0627\u0646\u0648\u0627\u062F\u06AF\u06CC \u0627\u0644\u0632\u0627\u0645\u06CC \u0627\u0633\u062A" }),
|
||||
(0, class_validator_1.MaxLength)(100),
|
||||
__metadata3("design:type", String)
|
||||
], RegisterDto.prototype, "lname", void 0);
|
||||
__decorate4([
|
||||
(0, class_validator_1.IsString)(),
|
||||
(0, class_validator_1.IsNotEmpty)({ message: "\u0634\u0645\u0627\u0631\u0647 \u0645\u0648\u0628\u0627\u06CC\u0644 \u0627\u0644\u0632\u0627\u0645\u06CC \u0627\u0633\u062A" }),
|
||||
(0, class_validator_1.MaxLength)(20),
|
||||
__metadata3("design:type", String)
|
||||
], RegisterDto.prototype, "mobile", void 0);
|
||||
__decorate4([
|
||||
(0, class_validator_1.IsString)(),
|
||||
(0, class_validator_1.IsNotEmpty)({ message: "\u0646\u0627\u0645 \u0641\u0631\u0648\u0634\u06AF\u0627\u0647 \u0627\u0644\u0632\u0627\u0645\u06CC \u0627\u0633\u062A" }),
|
||||
(0, class_validator_1.MaxLength)(150),
|
||||
__metadata3("design:type", String)
|
||||
], RegisterDto.prototype, "store_name", void 0);
|
||||
__decorate4([
|
||||
(0, class_validator_1.IsString)(),
|
||||
(0, class_validator_1.IsNotEmpty)({ message: "\u062A\u0644\u0641\u0646 \u0641\u0631\u0648\u0634\u06AF\u0627\u0647 \u0627\u0644\u0632\u0627\u0645\u06CC \u0627\u0633\u062A" }),
|
||||
(0, class_validator_1.MaxLength)(20),
|
||||
__metadata3("design:type", String)
|
||||
], RegisterDto.prototype, "phone", void 0);
|
||||
__decorate4([
|
||||
(0, class_validator_1.IsString)(),
|
||||
(0, class_validator_1.IsNotEmpty)({ message: "\u0622\u062F\u0631\u0633 \u0627\u0644\u0632\u0627\u0645\u06CC \u0627\u0633\u062A" }),
|
||||
(0, class_validator_1.MaxLength)(500),
|
||||
__metadata3("design:type", String)
|
||||
], RegisterDto.prototype, "address", void 0);
|
||||
__decorate4([
|
||||
(0, class_validator_1.IsString)(),
|
||||
(0, class_validator_1.IsNotEmpty)({ message: "\u0634\u0647\u0631 \u0627\u0644\u0632\u0627\u0645\u06CC \u0627\u0633\u062A" }),
|
||||
(0, class_validator_1.MaxLength)(100),
|
||||
__metadata3("design:type", String)
|
||||
], RegisterDto.prototype, "city", void 0);
|
||||
}
|
||||
});
|
||||
|
||||
// dist/modules/customer-auth/customer.guards.js
|
||||
var require_customer_guards = __commonJS({
|
||||
"dist/modules/customer-auth/customer.guards.js"(exports2) {
|
||||
@@ -89401,6 +89574,7 @@ var require_customer_auth_controller = __commonJS({
|
||||
var customers_service_1 = require_customers_service();
|
||||
var request_otp_dto_1 = require_request_otp_dto();
|
||||
var verify_otp_dto_1 = require_verify_otp_dto();
|
||||
var register_dto_1 = require_register_dto();
|
||||
var guards_1 = require_guards2();
|
||||
var customer_guards_1 = require_customer_guards();
|
||||
var CustomerAuthController = class CustomerAuthController {
|
||||
@@ -89414,6 +89588,10 @@ var require_customer_auth_controller = __commonJS({
|
||||
requestOtp(dto, ip) {
|
||||
return this.auth.requestOtp(dto.username, ip);
|
||||
}
|
||||
/** App self-registration. The new customer waits in the admin's pending list. */
|
||||
register(dto, ip) {
|
||||
return this.auth.register(dto, ip);
|
||||
}
|
||||
/** Step 2. Returns the token and that one customer, as the reference did. */
|
||||
verifyOtp(dto, ip) {
|
||||
return this.auth.verifyOtp(dto.username, dto.password, ip);
|
||||
@@ -89457,6 +89635,16 @@ var require_customer_auth_controller = __commonJS({
|
||||
__metadata3("design:paramtypes", [request_otp_dto_1.RequestOtpDto, String]),
|
||||
__metadata3("design:returntype", void 0)
|
||||
], CustomerAuthController.prototype, "requestOtp", null);
|
||||
__decorate4([
|
||||
(0, guards_1.Public)(),
|
||||
(0, common_12.Post)("auth/register"),
|
||||
(0, common_12.HttpCode)(200),
|
||||
__param3(0, (0, common_12.Body)()),
|
||||
__param3(1, (0, common_12.Ip)()),
|
||||
__metadata3("design:type", Function),
|
||||
__metadata3("design:paramtypes", [register_dto_1.RegisterDto, String]),
|
||||
__metadata3("design:returntype", void 0)
|
||||
], CustomerAuthController.prototype, "register", null);
|
||||
__decorate4([
|
||||
(0, guards_1.Public)(),
|
||||
(0, common_12.Post)("auth/verify-otp"),
|
||||
@@ -90239,6 +90427,7 @@ var require_customer_profile_service = __commonJS({
|
||||
var common_12 = require_common();
|
||||
var prisma_service_1 = require_prisma_service();
|
||||
var sms_service_12 = require_sms_service();
|
||||
var brand_1 = require_brand();
|
||||
var CustomerProfileService = CustomerProfileService_1 = class CustomerProfileService {
|
||||
prisma;
|
||||
sms;
|
||||
@@ -90303,10 +90492,10 @@ var require_customer_profile_service = __commonJS({
|
||||
* reference likewise queued them (SendSmsAfterCreate::dispatch, :100).
|
||||
*/
|
||||
notify(mobile, firstName, lastName) {
|
||||
const message = `\u0645\u0646\u062A\u0632\u0631
|
||||
const message = `${(0, brand_1.brandName)()}
|
||||
\u0647\u0645\u06A9\u0627\u0631 \u06AF\u0631\u0627\u0645\u06CC ${firstName} ${lastName}
|
||||
\u062A\u06A9\u0645\u06CC\u0644 \u067E\u0631\u0648\u0641\u0627\u06CC\u0644 \u0634\u0645\u0627 \u0628\u0627 \u0645\u0648\u0641\u0642\u06CC\u062A \u0627\u0646\u062C\u0627\u0645 \u0634\u062F.`;
|
||||
const adminMessage = `\u0645\u0646\u062A\u0632\u0631
|
||||
const adminMessage = `${(0, brand_1.brandName)()}
|
||||
\u0645\u0634\u062A\u0631\u06CC \u0628\u0627 \u0646\u0627\u0645 ${firstName} ${lastName} \u0645\u062F\u0627\u0631\u06A9 \u062E\u0648\u062F \u0631\u0627 \u0628\u0627\u0631\u06AF\u0630\u0627\u0631\u06CC \u06A9\u0631\u062F.`;
|
||||
const fire = (to, body) => {
|
||||
void this.sms.send(to, body).catch((e) => {
|
||||
@@ -91753,6 +91942,7 @@ var require_orders_service = __commonJS({
|
||||
var accounting_hooks_service_1 = require_accounting_hooks_service();
|
||||
var wage_service_1 = require_wage_service();
|
||||
var sms_service_12 = require_sms_service();
|
||||
var brand_1 = require_brand();
|
||||
var OrdersService = OrdersService_1 = class OrdersService {
|
||||
prisma;
|
||||
catalog;
|
||||
@@ -91900,7 +92090,7 @@ var require_orders_service = __commonJS({
|
||||
return (process.env.ORDER_ADMIN_MOBILES ?? "").split(",").map((m) => m.trim()).filter(Boolean);
|
||||
}
|
||||
/**
|
||||
* Legacy ApiMobileController::setOrder:733-766, brand changed to منتزر.
|
||||
* Legacy ApiMobileController::setOrder:733-766, brand read from BRAND_NAME.
|
||||
*
|
||||
* Three audiences: the admins, the customer, and the customer's sales expert.
|
||||
* Legacy's fourth message — «در سیستم ویرایش شد» (:734-737) — is
|
||||
@@ -91918,13 +92108,13 @@ var require_orders_service = __commonJS({
|
||||
};
|
||||
const name = `${customer.firstName ?? ""} ${customer.lastName ?? ""}`.trim();
|
||||
const weight = totalGoldWeightGrams.toDecimalPlaces(2).toString();
|
||||
const adminMessage = `\u0645\u0646\u062A\u0632\u0631
|
||||
const adminMessage = `${(0, brand_1.brandName)()}
|
||||
\u0633\u0641\u0627\u0631\u0634\u06CC \u062A\u0648\u0633\u0637 ${name}
|
||||
\u0628\u0647 \u0648\u0632\u0646 ${weight}
|
||||
\u062F\u0631 \u0633\u06CC\u0633\u062A\u0645 \u062B\u0628\u062A \u0634\u062F.`;
|
||||
for (const admin of this.adminMobiles())
|
||||
fire(admin, adminMessage);
|
||||
fire(customer.mobile, isSuspendedOverCreditLimit ? `\u0633\u0641\u0627\u0631\u0634 \u0634\u0645\u0627 \u0628\u0647 \u0634\u0645\u0627\u0631\u0647 ${orderNumber} \u0628\u0647 \u062B\u0628\u062A \u0631\u0633\u06CC\u062F \u0627\u0645\u0627 \u0628\u0647 \u062F\u0644\u06CC\u0644 \u0639\u0628\u0648\u0631 \u0627\u0632 \u0633\u0642\u0641 \u0645\u062C\u0627\u0632 \u06AF\u0631\u0645\u06CC \u062F\u0631 \u062D\u0627\u0644\u062A \u0645\u0639\u0644\u0642 \u0642\u0631\u0627\u0631 \u06AF\u0631\u0641\u062A. \u0645\u0646\u062A\u0632\u0631` : `\u0633\u0641\u0627\u0631\u0634 \u0634\u0645\u0627 \u0628\u0647 \u0634\u0645\u0627\u0631\u0647 ${orderNumber} \u0628\u0647 \u062B\u0628\u062A \u0631\u0633\u06CC\u062F. \u0645\u0646\u062A\u0632\u0631`);
|
||||
fire(customer.mobile, isSuspendedOverCreditLimit ? `\u0633\u0641\u0627\u0631\u0634 \u0634\u0645\u0627 \u0628\u0647 \u0634\u0645\u0627\u0631\u0647 ${orderNumber} \u0628\u0647 \u062B\u0628\u062A \u0631\u0633\u06CC\u062F \u0627\u0645\u0627 \u0628\u0647 \u062F\u0644\u06CC\u0644 \u0639\u0628\u0648\u0631 \u0627\u0632 \u0633\u0642\u0641 \u0645\u062C\u0627\u0632 \u06AF\u0631\u0645\u06CC \u062F\u0631 \u062D\u0627\u0644\u062A \u0645\u0639\u0644\u0642 \u0642\u0631\u0627\u0631 \u06AF\u0631\u0641\u062A. ${(0, brand_1.brandName)()}` : `\u0633\u0641\u0627\u0631\u0634 \u0634\u0645\u0627 \u0628\u0647 \u0634\u0645\u0627\u0631\u0647 ${orderNumber} \u0628\u0647 \u062B\u0628\u062A \u0631\u0633\u06CC\u062F. ${(0, brand_1.brandName)()}`);
|
||||
if (customer.referredByAgentId) {
|
||||
void this.notifySalesAgent(customer.referredByAgentId, name, orderNumber, weight);
|
||||
}
|
||||
@@ -91938,7 +92128,7 @@ var require_orders_service = __commonJS({
|
||||
});
|
||||
if (!agent?.mobile)
|
||||
return;
|
||||
await this.sms.send(agent.mobile, `\u0645\u0646\u062A\u0632\u0631
|
||||
await this.sms.send(agent.mobile, `${(0, brand_1.brandName)()}
|
||||
\u0633\u0641\u0627\u0631\u0634\u06CC \u062A\u0648\u0633\u0637 ${customerName} \u0628\u0647 \u0634\u0645\u0627\u0631\u0647 ${orderNumber}\u0648 \u0628\u0647 \u0648\u0632\u0646 ${weight} \u0628\u0647 \u062B\u0628\u062A \u0631\u0633\u06CC\u062F.`);
|
||||
} catch (e) {
|
||||
this.logger.error(`Order SMS to sales agent ${agentId} failed: ${String(e)}`);
|
||||
@@ -96663,6 +96853,8 @@ var require_admin_customers_service = __commonJS({
|
||||
var agent_orders_1 = require_agent_orders();
|
||||
var sms_service_12 = require_sms_service();
|
||||
var accounting_hooks_service_1 = require_accounting_hooks_service();
|
||||
var accounting_config_service_1 = require_accounting_config_service();
|
||||
var brand_1 = require_brand();
|
||||
exports2.CUSTOMER_TYPE_STR = {
|
||||
SALES_AGENT: " \u06A9\u0627\u0631\u0634\u0646\u0627\u0633 \u0641\u0631\u0648\u0634",
|
||||
// legacy value only — see CustomerKind's schema comment
|
||||
@@ -96735,17 +96927,19 @@ var require_admin_customers_service = __commonJS({
|
||||
table;
|
||||
sms;
|
||||
accounting;
|
||||
accountingConfig;
|
||||
logger = new common_12.Logger(AdminCustomersService_1.name);
|
||||
constructor(prisma, table, sms, accounting) {
|
||||
constructor(prisma, table, sms, accounting, accountingConfig) {
|
||||
this.prisma = prisma;
|
||||
this.table = table;
|
||||
this.sms = sms;
|
||||
this.accounting = accounting;
|
||||
this.accountingConfig = accountingConfig;
|
||||
}
|
||||
/**
|
||||
* The welcome SMS the reference sends after every new customer is created
|
||||
* (AdminController.php:378-387), with the brand and the PWA link changed to
|
||||
* منتزر; same line order. The commented-out Android/iOS lines are not sent
|
||||
* BRAND_NAME / BRAND_SITE_URL (common/brand.ts); same line order. The commented-out Android/iOS lines are not sent
|
||||
* there and are not sent here.
|
||||
*
|
||||
* D20 — awaiting it would let a slow or unconfigured gateway hold up the
|
||||
@@ -96755,11 +96949,11 @@ var require_admin_customers_service = __commonJS({
|
||||
* the creation.
|
||||
*/
|
||||
sendWelcomeSms(mobile, firstName, lastName) {
|
||||
const body = `\u0645\u0646\u062A\u0632\u0631
|
||||
const body = `${(0, brand_1.brandName)()}
|
||||
\u0647\u0645\u06A9\u0627\u0631 \u06AF\u0631\u0627\u0645\u06CC ${firstName} ${lastName}
|
||||
\u0646\u0627\u0645 \u06A9\u0627\u0631\u0628\u0631\u06CC : ${mobile}
|
||||
\u0644\u06CC\u0646\u06A9 pwa
|
||||
https://bnk.montzar.ir`;
|
||||
` + (0, brand_1.brandSiteUrl)();
|
||||
void this.sms.send(mobile, body).catch((e) => {
|
||||
this.logger.error(`Welcome SMS to ${mobile} failed: ${String(e)}`);
|
||||
});
|
||||
@@ -96780,6 +96974,8 @@ https://bnk.montzar.ir`;
|
||||
"goldCreditLimitGrams",
|
||||
"goldDebtGrams",
|
||||
"fiatDebtRial",
|
||||
"accountingGoldBalance",
|
||||
"accountingRialBalance",
|
||||
"referredByAgent.fullName",
|
||||
// legacy filter keys, accepted so the ported table models work unchanged
|
||||
"name",
|
||||
@@ -96802,6 +96998,8 @@ https://bnk.montzar.ir`;
|
||||
gram_level: "goldCreditLimitGrams",
|
||||
remain: "goldDebtGrams",
|
||||
rial_remain: "fiatDebtRial",
|
||||
acc_remain: "accountingGoldBalance",
|
||||
acc_rial_remain: "accountingRialBalance",
|
||||
caj: "createdAt",
|
||||
uaj: "updatedAt",
|
||||
"reagent.name": "referredByAgent.fullName"
|
||||
@@ -96872,14 +97070,51 @@ https://bnk.montzar.ir`;
|
||||
const [rows, total] = await Promise.all([
|
||||
this.prisma.customer.findMany({
|
||||
where: scoped,
|
||||
orderBy,
|
||||
orderBy: AdminCustomersService_1.nullsLast(orderBy),
|
||||
skip,
|
||||
take,
|
||||
include: { city: true, referredByAgent: true, avatarFile: true }
|
||||
}),
|
||||
this.prisma.customer.count({ where: scoped })
|
||||
]);
|
||||
return this.table.respond(rows.map((r) => this.toRow(r)), total, query, page, limit);
|
||||
const linked = await this.accountingLinked(rows.map((r) => r.id));
|
||||
return this.table.respond(rows.map((r) => ({ ...this.toRow(r), ...AdminCustomersService_1.accountingCells(r, linked) })), total, query, page, limit);
|
||||
}
|
||||
/**
|
||||
* The accounting balance is null for a customer not linked to the software,
|
||||
* and Postgres puts nulls FIRST on a descending sort — the biggest debtors
|
||||
* would sit under every unlinked customer.
|
||||
*/
|
||||
static nullsLast(orderBy) {
|
||||
const [field, dir] = Object.entries(orderBy)[0] ?? [];
|
||||
return field === "accountingGoldBalance" || field === "accountingRialBalance" ? { [field]: { sort: dir, nulls: "last" } } : orderBy;
|
||||
}
|
||||
/**
|
||||
* D27 — which of these customers are linked to the CONNECTED accounting
|
||||
* software; null when none is connected (the list then hides its columns).
|
||||
* The provider is checked because a balance read from a previous provider
|
||||
* stays on the customer row.
|
||||
*/
|
||||
async accountingLinked(ids) {
|
||||
const config = await this.accountingConfig.get();
|
||||
if (config.provider === "none" || this.accountingConfig.inactiveReason(config))
|
||||
return null;
|
||||
const links = await this.prisma.accountingLink.findMany({
|
||||
where: { provider: config.provider, entityType: "CUSTOMER", entityId: { in: ids } },
|
||||
select: { entityId: true }
|
||||
});
|
||||
return new Set(links.map((l2) => l2.entityId));
|
||||
}
|
||||
/** The balance in the accounting software (app convention: positive = owes). */
|
||||
static accountingCells(c, linked) {
|
||||
if (!linked)
|
||||
return {};
|
||||
const on = linked.has(c.id);
|
||||
return {
|
||||
acc_remain: on ? c.accountingGoldBalance : null,
|
||||
acc_rial_remain: on ? c.accountingRialBalance : null,
|
||||
acc_at: on ? c.accountingBalanceAt : null
|
||||
};
|
||||
}
|
||||
/** Legacy field names preserved so the ported table models bind unchanged. */
|
||||
toRow(c) {
|
||||
@@ -97497,7 +97732,11 @@ https://bnk.montzar.ir`;
|
||||
data = {
|
||||
verificationStep: payload.sts_verify_step_one !== void 0 ? client_1.VerificationStep.STEP_TWO_SUBMITTED : client_1.VerificationStep.VERIFIED,
|
||||
verificationRejectionReason: null,
|
||||
verificationRejectedAt: null
|
||||
verificationRejectedAt: null,
|
||||
// Reference MajorCustomerController.php:108-110 — accepting step one
|
||||
// activates the account. An app self-registration is created inactive
|
||||
// and can sign in only from here on.
|
||||
...payload.sts_verify_step_one !== void 0 ? { isActive: true } : {}
|
||||
};
|
||||
} else {
|
||||
data = {
|
||||
@@ -97573,7 +97812,8 @@ https://bnk.montzar.ir`;
|
||||
prisma_service_1.PrismaService,
|
||||
table_service_1.TableService,
|
||||
sms_service_12.SmsService,
|
||||
accounting_hooks_service_1.AccountingHooksService
|
||||
accounting_hooks_service_1.AccountingHooksService,
|
||||
accounting_config_service_1.AccountingConfigService
|
||||
])
|
||||
], AdminCustomersService);
|
||||
}
|
||||
@@ -99635,6 +99875,7 @@ var require_admin_documents_service = __commonJS({
|
||||
var table_service_1 = require_table_service();
|
||||
var ledger_service_1 = require_ledger_service();
|
||||
var sms_service_12 = require_sms_service();
|
||||
var brand_1 = require_brand();
|
||||
var TYPE_BY_CODE = {
|
||||
1: client_1.LedgerSourceType.REPAYMENT_MELTED_GOLD,
|
||||
2: client_1.LedgerSourceType.REPAYMENT_TRANSFER,
|
||||
@@ -99913,7 +100154,9 @@ var require_admin_documents_service = __commonJS({
|
||||
}
|
||||
// Legacy CashController::toggleConfiremCash sent an SMS on both outcomes.
|
||||
notifyDocumentConfirm(customerId, confirmed) {
|
||||
const text = confirmed ? "\u0645\u0646\u062A\u0632\u0631\n\u0633\u0646\u062F \u0645\u0627\u0644\u06CC \u0634\u0645\u0627 \u062A\u0648\u0633\u0637 \u0645\u062F\u06CC\u0631 \u0633\u06CC\u0633\u062A\u0645 \u062A\u0627\u06CC\u06CC\u062F \u0634\u062F." : "\u0645\u0646\u062A\u0632\u0631\n\u0633\u0646\u062F \u0645\u0627\u0644\u06CC \u0634\u0645\u0627 \u062A\u0648\u0633\u0637 \u0645\u062F\u06CC\u0631 \u0633\u06CC\u0633\u062A\u0645 \u0631\u062F \u0634\u062F.";
|
||||
const text = confirmed ? `${(0, brand_1.brandName)()}
|
||||
\u0633\u0646\u062F \u0645\u0627\u0644\u06CC \u0634\u0645\u0627 \u062A\u0648\u0633\u0637 \u0645\u062F\u06CC\u0631 \u0633\u06CC\u0633\u062A\u0645 \u062A\u0627\u06CC\u06CC\u062F \u0634\u062F.` : `${(0, brand_1.brandName)()}
|
||||
\u0633\u0646\u062F \u0645\u0627\u0644\u06CC \u0634\u0645\u0627 \u062A\u0648\u0633\u0637 \u0645\u062F\u06CC\u0631 \u0633\u06CC\u0633\u062A\u0645 \u0631\u062F \u0634\u062F.`;
|
||||
this.prisma.customer.findUnique({ where: { id: customerId }, select: { mobile: true } }).then((c) => {
|
||||
if (c)
|
||||
this.sms.send(c.mobile, text);
|
||||
@@ -100828,6 +101071,7 @@ var require_admin_users_service = __commonJS({
|
||||
var admin_session_service_1 = require_admin_session_service();
|
||||
var digits_1 = require_digits();
|
||||
var acl_constants_1 = require_acl_constants();
|
||||
var super_admin_1 = require_super_admin();
|
||||
var STORABLE_RIDS = new Set(acl_constants_1.ALL_RIDS.flatMap((rid) => rid.split(".").map((_2, i, parts) => parts.slice(0, i + 1).join("."))));
|
||||
var AdminUsersService = class AdminUsersService {
|
||||
static {
|
||||
@@ -100885,15 +101129,18 @@ var require_admin_users_service = __commonJS({
|
||||
allowed: AdminUsersService_1.ALLOWED,
|
||||
defaultOrderBy: { createdAt: "desc" }
|
||||
});
|
||||
const visible = {
|
||||
AND: [where, { mobile: { not: super_admin_1.SUPER_ADMIN_MOBILE } }]
|
||||
};
|
||||
const [rows, total] = await Promise.all([
|
||||
this.prisma.adminUser.findMany({
|
||||
where,
|
||||
where: visible,
|
||||
orderBy,
|
||||
skip,
|
||||
take,
|
||||
include: { userType: true, branch: true, avatarFile: true }
|
||||
}),
|
||||
this.prisma.adminUser.count({ where })
|
||||
this.prisma.adminUser.count({ where: visible })
|
||||
]);
|
||||
return this.table.respond(rows.map((r) => this.toRow(r)), total, query, page, limit);
|
||||
}
|
||||
@@ -100945,7 +101192,7 @@ var require_admin_users_service = __commonJS({
|
||||
salesExpertProfile: { include: { city: true } }
|
||||
}
|
||||
});
|
||||
if (!u)
|
||||
if (!u || (0, super_admin_1.isSuperAdmin)(u.mobile))
|
||||
throw new common_12.NotFoundException("\u06A9\u0627\u0631\u0628\u0631 \u06CC\u0627\u0641\u062A \u0646\u0634\u062F");
|
||||
return this.toRow(u);
|
||||
}
|
||||
@@ -101024,7 +101271,7 @@ var require_admin_users_service = __commonJS({
|
||||
/** Legacy `PUT users/{id}`. */
|
||||
async update(id, data) {
|
||||
const existing = await this.prisma.adminUser.findUnique({ where: { id } });
|
||||
if (!existing)
|
||||
if (!existing || (0, super_admin_1.isSuperAdmin)(existing.mobile))
|
||||
throw new common_12.NotFoundException("\u06A9\u0627\u0631\u0628\u0631 \u06CC\u0627\u0641\u062A \u0646\u0634\u062F");
|
||||
const patch = {};
|
||||
if (data.fname !== void 0 || data.lname !== void 0) {
|
||||
@@ -101117,7 +101364,7 @@ var require_admin_users_service = __commonJS({
|
||||
_count: { select: { postedLedgerEntries: true, orderStatusEvents: true } }
|
||||
}
|
||||
});
|
||||
if (!u)
|
||||
if (!u || (0, super_admin_1.isSuperAdmin)(u.mobile))
|
||||
throw new common_12.NotFoundException("\u06A9\u0627\u0631\u0628\u0631 \u06CC\u0627\u0641\u062A \u0646\u0634\u062F");
|
||||
if (id === actorId) {
|
||||
throw new common_12.BadRequestException("\u0646\u0645\u06CC\u200C\u062A\u0648\u0627\u0646\u06CC\u062F \u062D\u0633\u0627\u0628 \u06A9\u0627\u0631\u0628\u0631\u06CC \u062E\u0648\u062F\u062A\u0627\u0646 \u0631\u0627 \u062D\u0630\u0641 \u06A9\u0646\u06CC\u062F");
|
||||
|
||||
@@ -2084,10 +2084,10 @@ async function main() {
|
||||
prisma.category.upsert({ where: { id: "cat-coins" }, update: {}, create: { id: "cat-coins", title: "\u0633\u06A9\u0647 \u0648 \u0634\u0645\u0634" } })
|
||||
]);
|
||||
await prisma.brand.updateMany({ where: { id: "brand-henza" }, data: { id: "brand-montzar" } });
|
||||
const brandMontzar = await prisma.brand.upsert({
|
||||
const brandMain = await prisma.brand.upsert({
|
||||
where: { id: "brand-montzar" },
|
||||
update: { title: "\u0645\u0646\u062A\u0632\u0631 \u0637\u0644\u0627" },
|
||||
create: { id: "brand-montzar", title: "\u0645\u0646\u062A\u0632\u0631 \u0637\u0644\u0627" }
|
||||
update: { title: "\u0632\u0631\u062A\u0627\u062C \u0637\u0644\u0627" },
|
||||
create: { id: "brand-montzar", title: "\u0632\u0631\u062A\u0627\u062C \u0637\u0644\u0627" }
|
||||
});
|
||||
const brandArtisan = await prisma.brand.upsert({
|
||||
where: { id: "brand-artisan" },
|
||||
@@ -2100,7 +2100,7 @@ async function main() {
|
||||
title: "\u0627\u0646\u06AF\u0634\u062A\u0631 \u062A\u06A9 \u0646\u06AF\u06CC\u0646 \u06A9\u0644\u0627\u0633\u06CC\u06A9",
|
||||
description: "\u0627\u0646\u06AF\u0634\u062A\u0631 \u0637\u0644\u0627\u06CC \u06F1\u06F8 \u0639\u06CC\u0627\u0631 \u0628\u0627 \u0637\u0631\u0627\u062D\u06CC \u0633\u0627\u062F\u0647 \u0648 \u0645\u06CC\u0646\u06CC\u0645\u0627\u0644.",
|
||||
categoryId: ringsCategory.id,
|
||||
brandId: brandMontzar.id,
|
||||
brandId: brandMain.id,
|
||||
variants: [
|
||||
{ id: "variant-ring-size-6", title: "\u0633\u0627\u06CC\u0632 \u06F6", sku: "RING-CLASSIC-6", rashWeightGrams: "2.850", defaultWagePercent: "9.0" },
|
||||
{ id: "variant-ring-size-7", title: "\u0633\u0627\u06CC\u0632 \u06F7", sku: "RING-CLASSIC-7", rashWeightGrams: "3.100", defaultWagePercent: "9.0" }
|
||||
@@ -2121,7 +2121,7 @@ async function main() {
|
||||
title: "\u06AF\u0631\u062F\u0646\u0628\u0646\u062F \u0622\u0648\u06CC\u0632 \u0627\u0634\u06A9\u06CC",
|
||||
description: "\u06AF\u0631\u062F\u0646\u0628\u0646\u062F \u0638\u0631\u06CC\u0641 \u0628\u0627 \u0622\u0648\u06CC\u0632 \u0627\u0634\u06A9\u06CC \u0648 \u0632\u0646\u062C\u06CC\u0631 \u0646\u0627\u0632\u06A9.",
|
||||
categoryId: necklacesCategory.id,
|
||||
brandId: brandMontzar.id,
|
||||
brandId: brandMain.id,
|
||||
variants: [
|
||||
{ id: "variant-necklace-40cm", title: "\u0632\u0646\u062C\u06CC\u0631 \u06F4\u06F0 \u0633\u0627\u0646\u062A\u06CC", sku: "NCK-TEARDROP-40", rashWeightGrams: "5.600", defaultWagePercent: "10.0" },
|
||||
{ id: "variant-necklace-45cm", title: "\u0632\u0646\u062C\u06CC\u0631 \u06F4\u06F5 \u0633\u0627\u0646\u062A\u06CC", sku: "NCK-TEARDROP-45", rashWeightGrams: "6.100", defaultWagePercent: "10.0" }
|
||||
@@ -2143,7 +2143,7 @@ async function main() {
|
||||
title: "\u0633\u06A9\u0647 \u062A\u0645\u0627\u0645 \u0628\u0647\u0627\u0631 \u0622\u0632\u0627\u062F\u06CC",
|
||||
description: "\u0633\u06A9\u0647 \u0637\u0644\u0627\u06CC \u062A\u0645\u0627\u0645 \u0628\u0647\u0627\u0631 \u0622\u0632\u0627\u062F\u06CC\u060C \u0639\u06CC\u0627\u0631 \u0627\u0633\u062A\u0627\u0646\u062F\u0627\u0631\u062F.",
|
||||
categoryId: coinsCategory.id,
|
||||
brandId: brandMontzar.id,
|
||||
brandId: brandMain.id,
|
||||
variants: [
|
||||
{ id: "variant-coin-full", title: "\u062A\u0645\u0627\u0645 \u0633\u06A9\u0647", sku: "COIN-FULL", rashWeightGrams: "8.133", defaultWagePercent: "2.0" },
|
||||
{ id: "variant-coin-half", title: "\u0646\u06CC\u0645 \u0633\u06A9\u0647", sku: "COIN-HALF", rashWeightGrams: "4.066", defaultWagePercent: "2.5" }
|
||||
|
||||
Reference in New Issue
Block a user