build: rebuild release bundles for build 181

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
s.esmaeili
2026-10-14 13:35:35 +03:30
co-authored by Claude Haiku 5.5
parent 532ceee189
commit c845f6db19
353 changed files with 661 additions and 388 deletions
+268 -21
View File
@@ -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");
+6 -6
View File
@@ -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" }