migration

This commit is contained in:
s.esmaeili
2026-10-07 20:20:27 +03:30
parent 92831ed33e
commit 8c5d971d1f
17 changed files with 286 additions and 57 deletions
@@ -10,6 +10,7 @@ import {
type IamIdentity,
} from '../iam/iam.service';
import { AppSessionService } from '../sessions/app-session.service';
import { OTP_ONLY_PASSWORD_HASH } from '../auth/password-hash';
import { envOr, envOrNull } from '../../common/env';
import { CUSTOMER_TOKEN_TYPE, EXPERT_TOKEN_TYPE, type CustomerJwtPayload } from './customer-jwt.strategy';
import { faToEn } from './digits';
@@ -185,6 +186,13 @@ export class CustomerAuthService {
* Returns null for any mobile that is not an active sales expert, so an
* ordinary customer's login is completely unaffected.
*/
/** `code` when it is set and no customer holds it yet, else null. */
private async freeNationalCode(code: string | null): Promise<string | null> {
if (!code) return null;
const taken = await this.prisma.customer.findUnique({ where: { nationalCode: code }, select: { id: true } });
return taken ? null : code;
}
private async resolveExpertTradingAccount(mobile: string): Promise<{ id: string } | null> {
const admin = await this.prisma.adminUser.findFirst({
where: { mobile, isActive: true, role: AdminRole.SALES_EXPERT },
@@ -252,13 +260,13 @@ export class CustomerAuthService {
firstName: admin.firstName,
lastName: admin.lastName,
mobile: admin.mobile,
// Customer.nationalCode is required and unique. The expert's own code
// when they have one, else the mobile — the same fallback
// admin-customers.service.ts uses when a form omits it.
nationalCode: admin.salesExpertProfile.nationalCode || admin.mobile,
// The expert's own national code when they have one and no other
// customer holds it (the column is unique); else none. Never the
// mobile — the column holds national codes only.
nationalCode: await this.freeNationalCode(admin.salesExpertProfile.nationalCode),
// No app password: this account is reached only through the expert's
// AdminUser session, never by a password login of its own.
passwordHash: '',
passwordHash: OTP_ONLY_PASSWORD_HASH,
kind: CustomerKind.APP_SHOPKEEPER,
goldCreditLimitGrams: admin.salesExpertProfile.gramLevel,
makingChargeOffsetPercent: admin.wagePercent ?? new Prisma.Decimal(0),