Files
tehran_taj/apps/api/release/seed.js
T
s.esmaeiliandClaude Sonnet 5 2b6795d007 api: fix migration runner, serve uploads correctly, add product photos
Three real bugs found and fixed while wiring up product images end-to-end:

1. src/prisma/migrate.ts only discovered flat prisma/migrations/<name>.sql
   files, never Prisma's own folder-per-migration layout
   (<timestamp>_<name>/migration.sql). Every migration created the normal
   way (via 'prisma migrate dev') was silently skipped; only a hand-added
   flat duplicate (prisma/migrations/0001_init.sql, now removed) ever ran.
   This meant schema.prisma had drifted well ahead of what any real deploy
   database actually had (missing columns on City, Customer, Branch,
   Product, several new tables). Fixed to discover both layouts; the
   drift is closed with a new 20260914165255_sync_schema_drift migration.

2. Neither nginx.conf (production) nor vite.config.ts (dev) proxied
   /uploads/ to the API — only /api/. UploadedFile/ProductImage URLs
   (/uploads/<file>, served by main.ts's useStaticAssets OUTSIDE the /api
   prefix) 404'd through both. Both now proxy /uploads/ the same way /api/
   already was.

3. docker-compose.yml's api service had no volume for storage/uploads, so
   every uploaded file — and by extension every ProductImage row pointing
   at one — was lost on the next container recreate/redeploy. Added a
   named volume.

Also: main.ts's static file serving now sets Content-Type: image/avif
explicitly (serve-static's bundled mime table predates .avif and served it
as application/octet-stream; browsers rendered it anyway by sniffing, but
a stricter client would not have).

Product photos: copied 15 real jewelry photos into the uploads volume,
registered them as UploadedFile rows, and assigned each of the 5 existing
Product rows a randomly picked one (duplicates allowed, per request),
replacing their /img/no-items.png placeholder ProductImage row. Verified
end-to-end in a real browser against the real containerized API+DB: logged
in, opened the admin product list, confirmed all 5 rows render their photo
(naturalWidth/Height populated, network 200s, no console errors).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-14 20:56:17 +03:30

2412 lines
60 KiB
JavaScript

"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
// prisma/seed.ts
var import_client = require("@prisma/client");
// ../../node_modules/.pnpm/bcryptjs@3.0.3/node_modules/bcryptjs/index.js
var import_crypto = __toESM(require("crypto"), 1);
var randomFallback = null;
function randomBytes(len) {
try {
return crypto.getRandomValues(new Uint8Array(len));
} catch {
}
try {
return import_crypto.default.randomBytes(len);
} catch {
}
if (!randomFallback) {
throw Error(
"Neither WebCryptoAPI nor a crypto module is available. Use bcrypt.setRandomFallback to set an alternative"
);
}
return randomFallback(len);
}
function genSaltSync(rounds, seed_length) {
rounds = rounds || GENSALT_DEFAULT_LOG2_ROUNDS;
if (typeof rounds !== "number")
throw Error(
"Illegal arguments: " + typeof rounds + ", " + typeof seed_length
);
if (rounds < 4) rounds = 4;
else if (rounds > 31) rounds = 31;
var salt = [];
salt.push("$2b$");
if (rounds < 10) salt.push("0");
salt.push(rounds.toString());
salt.push("$");
salt.push(base64_encode(randomBytes(BCRYPT_SALT_LEN), BCRYPT_SALT_LEN));
return salt.join("");
}
function hashSync(password, salt) {
if (typeof salt === "undefined") salt = GENSALT_DEFAULT_LOG2_ROUNDS;
if (typeof salt === "number") salt = genSaltSync(salt);
if (typeof password !== "string" || typeof salt !== "string")
throw Error("Illegal arguments: " + typeof password + ", " + typeof salt);
return _hash(password, salt);
}
var nextTick = typeof setImmediate === "function" ? setImmediate : typeof scheduler === "object" && typeof scheduler.postTask === "function" ? scheduler.postTask.bind(scheduler) : setTimeout;
function utf8Length(string) {
var len = 0, c = 0;
for (var i = 0; i < string.length; ++i) {
c = string.charCodeAt(i);
if (c < 128) len += 1;
else if (c < 2048) len += 2;
else if ((c & 64512) === 55296 && (string.charCodeAt(i + 1) & 64512) === 56320) {
++i;
len += 4;
} else len += 3;
}
return len;
}
function utf8Array(string) {
var offset = 0, c1, c2;
var buffer = new Array(utf8Length(string));
for (var i = 0, k = string.length; i < k; ++i) {
c1 = string.charCodeAt(i);
if (c1 < 128) {
buffer[offset++] = c1;
} else if (c1 < 2048) {
buffer[offset++] = c1 >> 6 | 192;
buffer[offset++] = c1 & 63 | 128;
} else if ((c1 & 64512) === 55296 && ((c2 = string.charCodeAt(i + 1)) & 64512) === 56320) {
c1 = 65536 + ((c1 & 1023) << 10) + (c2 & 1023);
++i;
buffer[offset++] = c1 >> 18 | 240;
buffer[offset++] = c1 >> 12 & 63 | 128;
buffer[offset++] = c1 >> 6 & 63 | 128;
buffer[offset++] = c1 & 63 | 128;
} else {
buffer[offset++] = c1 >> 12 | 224;
buffer[offset++] = c1 >> 6 & 63 | 128;
buffer[offset++] = c1 & 63 | 128;
}
}
return buffer;
}
var BASE64_CODE = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".split("");
var BASE64_INDEX = [
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
0,
1,
54,
55,
56,
57,
58,
59,
60,
61,
62,
63,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
-1,
-1,
-1,
-1,
-1,
-1,
28,
29,
30,
31,
32,
33,
34,
35,
36,
37,
38,
39,
40,
41,
42,
43,
44,
45,
46,
47,
48,
49,
50,
51,
52,
53,
-1,
-1,
-1,
-1,
-1
];
function base64_encode(b, len) {
var off = 0, rs = [], c1, c2;
if (len <= 0 || len > b.length) throw Error("Illegal len: " + len);
while (off < len) {
c1 = b[off++] & 255;
rs.push(BASE64_CODE[c1 >> 2 & 63]);
c1 = (c1 & 3) << 4;
if (off >= len) {
rs.push(BASE64_CODE[c1 & 63]);
break;
}
c2 = b[off++] & 255;
c1 |= c2 >> 4 & 15;
rs.push(BASE64_CODE[c1 & 63]);
c1 = (c2 & 15) << 2;
if (off >= len) {
rs.push(BASE64_CODE[c1 & 63]);
break;
}
c2 = b[off++] & 255;
c1 |= c2 >> 6 & 3;
rs.push(BASE64_CODE[c1 & 63]);
rs.push(BASE64_CODE[c2 & 63]);
}
return rs.join("");
}
function base64_decode(s, len) {
var off = 0, slen = s.length, olen = 0, rs = [], c1, c2, c3, c4, o, code;
if (len <= 0) throw Error("Illegal len: " + len);
while (off < slen - 1 && olen < len) {
code = s.charCodeAt(off++);
c1 = code < BASE64_INDEX.length ? BASE64_INDEX[code] : -1;
code = s.charCodeAt(off++);
c2 = code < BASE64_INDEX.length ? BASE64_INDEX[code] : -1;
if (c1 == -1 || c2 == -1) break;
o = c1 << 2 >>> 0;
o |= (c2 & 48) >> 4;
rs.push(String.fromCharCode(o));
if (++olen >= len || off >= slen) break;
code = s.charCodeAt(off++);
c3 = code < BASE64_INDEX.length ? BASE64_INDEX[code] : -1;
if (c3 == -1) break;
o = (c2 & 15) << 4 >>> 0;
o |= (c3 & 60) >> 2;
rs.push(String.fromCharCode(o));
if (++olen >= len || off >= slen) break;
code = s.charCodeAt(off++);
c4 = code < BASE64_INDEX.length ? BASE64_INDEX[code] : -1;
o = (c3 & 3) << 6 >>> 0;
o |= c4;
rs.push(String.fromCharCode(o));
++olen;
}
var res = [];
for (off = 0; off < olen; off++) res.push(rs[off].charCodeAt(0));
return res;
}
var BCRYPT_SALT_LEN = 16;
var GENSALT_DEFAULT_LOG2_ROUNDS = 10;
var BLOWFISH_NUM_ROUNDS = 16;
var MAX_EXECUTION_TIME = 100;
var P_ORIG = [
608135816,
2242054355,
320440878,
57701188,
2752067618,
698298832,
137296536,
3964562569,
1160258022,
953160567,
3193202383,
887688300,
3232508343,
3380367581,
1065670069,
3041331479,
2450970073,
2306472731
];
var S_ORIG = [
3509652390,
2564797868,
805139163,
3491422135,
3101798381,
1780907670,
3128725573,
4046225305,
614570311,
3012652279,
134345442,
2240740374,
1667834072,
1901547113,
2757295779,
4103290238,
227898511,
1921955416,
1904987480,
2182433518,
2069144605,
3260701109,
2620446009,
720527379,
3318853667,
677414384,
3393288472,
3101374703,
2390351024,
1614419982,
1822297739,
2954791486,
3608508353,
3174124327,
2024746970,
1432378464,
3864339955,
2857741204,
1464375394,
1676153920,
1439316330,
715854006,
3033291828,
289532110,
2706671279,
2087905683,
3018724369,
1668267050,
732546397,
1947742710,
3462151702,
2609353502,
2950085171,
1814351708,
2050118529,
680887927,
999245976,
1800124847,
3300911131,
1713906067,
1641548236,
4213287313,
1216130144,
1575780402,
4018429277,
3917837745,
3693486850,
3949271944,
596196993,
3549867205,
258830323,
2213823033,
772490370,
2760122372,
1774776394,
2652871518,
566650946,
4142492826,
1728879713,
2882767088,
1783734482,
3629395816,
2517608232,
2874225571,
1861159788,
326777828,
3124490320,
2130389656,
2716951837,
967770486,
1724537150,
2185432712,
2364442137,
1164943284,
2105845187,
998989502,
3765401048,
2244026483,
1075463327,
1455516326,
1322494562,
910128902,
469688178,
1117454909,
936433444,
3490320968,
3675253459,
1240580251,
122909385,
2157517691,
634681816,
4142456567,
3825094682,
3061402683,
2540495037,
79693498,
3249098678,
1084186820,
1583128258,
426386531,
1761308591,
1047286709,
322548459,
995290223,
1845252383,
2603652396,
3431023940,
2942221577,
3202600964,
3727903485,
1712269319,
422464435,
3234572375,
1170764815,
3523960633,
3117677531,
1434042557,
442511882,
3600875718,
1076654713,
1738483198,
4213154764,
2393238008,
3677496056,
1014306527,
4251020053,
793779912,
2902807211,
842905082,
4246964064,
1395751752,
1040244610,
2656851899,
3396308128,
445077038,
3742853595,
3577915638,
679411651,
2892444358,
2354009459,
1767581616,
3150600392,
3791627101,
3102740896,
284835224,
4246832056,
1258075500,
768725851,
2589189241,
3069724005,
3532540348,
1274779536,
3789419226,
2764799539,
1660621633,
3471099624,
4011903706,
913787905,
3497959166,
737222580,
2514213453,
2928710040,
3937242737,
1804850592,
3499020752,
2949064160,
2386320175,
2390070455,
2415321851,
4061277028,
2290661394,
2416832540,
1336762016,
1754252060,
3520065937,
3014181293,
791618072,
3188594551,
3933548030,
2332172193,
3852520463,
3043980520,
413987798,
3465142937,
3030929376,
4245938359,
2093235073,
3534596313,
375366246,
2157278981,
2479649556,
555357303,
3870105701,
2008414854,
3344188149,
4221384143,
3956125452,
2067696032,
3594591187,
2921233993,
2428461,
544322398,
577241275,
1471733935,
610547355,
4027169054,
1432588573,
1507829418,
2025931657,
3646575487,
545086370,
48609733,
2200306550,
1653985193,
298326376,
1316178497,
3007786442,
2064951626,
458293330,
2589141269,
3591329599,
3164325604,
727753846,
2179363840,
146436021,
1461446943,
4069977195,
705550613,
3059967265,
3887724982,
4281599278,
3313849956,
1404054877,
2845806497,
146425753,
1854211946,
1266315497,
3048417604,
3681880366,
3289982499,
290971e4,
1235738493,
2632868024,
2414719590,
3970600049,
1771706367,
1449415276,
3266420449,
422970021,
1963543593,
2690192192,
3826793022,
1062508698,
1531092325,
1804592342,
2583117782,
2714934279,
4024971509,
1294809318,
4028980673,
1289560198,
2221992742,
1669523910,
35572830,
157838143,
1052438473,
1016535060,
1802137761,
1753167236,
1386275462,
3080475397,
2857371447,
1040679964,
2145300060,
2390574316,
1461121720,
2956646967,
4031777805,
4028374788,
33600511,
2920084762,
1018524850,
629373528,
3691585981,
3515945977,
2091462646,
2486323059,
586499841,
988145025,
935516892,
3367335476,
2599673255,
2839830854,
265290510,
3972581182,
2759138881,
3795373465,
1005194799,
847297441,
406762289,
1314163512,
1332590856,
1866599683,
4127851711,
750260880,
613907577,
1450815602,
3165620655,
3734664991,
3650291728,
3012275730,
3704569646,
1427272223,
778793252,
1343938022,
2676280711,
2052605720,
1946737175,
3164576444,
3914038668,
3967478842,
3682934266,
1661551462,
3294938066,
4011595847,
840292616,
3712170807,
616741398,
312560963,
711312465,
1351876610,
322626781,
1910503582,
271666773,
2175563734,
1594956187,
70604529,
3617834859,
1007753275,
1495573769,
4069517037,
2549218298,
2663038764,
504708206,
2263041392,
3941167025,
2249088522,
1514023603,
1998579484,
1312622330,
694541497,
2582060303,
2151582166,
1382467621,
776784248,
2618340202,
3323268794,
2497899128,
2784771155,
503983604,
4076293799,
907881277,
423175695,
432175456,
1378068232,
4145222326,
3954048622,
3938656102,
3820766613,
2793130115,
2977904593,
26017576,
3274890735,
3194772133,
1700274565,
1756076034,
4006520079,
3677328699,
720338349,
1533947780,
354530856,
688349552,
3973924725,
1637815568,
332179504,
3949051286,
53804574,
2852348879,
3044236432,
1282449977,
3583942155,
3416972820,
4006381244,
1617046695,
2628476075,
3002303598,
1686838959,
431878346,
2686675385,
1700445008,
1080580658,
1009431731,
832498133,
3223435511,
2605976345,
2271191193,
2516031870,
1648197032,
4164389018,
2548247927,
300782431,
375919233,
238389289,
3353747414,
2531188641,
2019080857,
1475708069,
455242339,
2609103871,
448939670,
3451063019,
1395535956,
2413381860,
1841049896,
1491858159,
885456874,
4264095073,
4001119347,
1565136089,
3898914787,
1108368660,
540939232,
1173283510,
2745871338,
3681308437,
4207628240,
3343053890,
4016749493,
1699691293,
1103962373,
3625875870,
2256883143,
3830138730,
1031889488,
3479347698,
1535977030,
4236805024,
3251091107,
2132092099,
1774941330,
1199868427,
1452454533,
157007616,
2904115357,
342012276,
595725824,
1480756522,
206960106,
497939518,
591360097,
863170706,
2375253569,
3596610801,
1814182875,
2094937945,
3421402208,
1082520231,
3463918190,
2785509508,
435703966,
3908032597,
1641649973,
2842273706,
3305899714,
1510255612,
2148256476,
2655287854,
3276092548,
4258621189,
236887753,
3681803219,
274041037,
1734335097,
3815195456,
3317970021,
1899903192,
1026095262,
4050517792,
356393447,
2410691914,
3873677099,
3682840055,
3913112168,
2491498743,
4132185628,
2489919796,
1091903735,
1979897079,
3170134830,
3567386728,
3557303409,
857797738,
1136121015,
1342202287,
507115054,
2535736646,
337727348,
3213592640,
1301675037,
2528481711,
1895095763,
1721773893,
3216771564,
62756741,
2142006736,
835421444,
2531993523,
1442658625,
3659876326,
2882144922,
676362277,
1392781812,
170690266,
3921047035,
1759253602,
3611846912,
1745797284,
664899054,
1329594018,
3901205900,
3045908486,
2062866102,
2865634940,
3543621612,
3464012697,
1080764994,
553557557,
3656615353,
3996768171,
991055499,
499776247,
1265440854,
648242737,
3940784050,
980351604,
3713745714,
1749149687,
3396870395,
4211799374,
3640570775,
1161844396,
3125318951,
1431517754,
545492359,
4268468663,
3499529547,
1437099964,
2702547544,
3433638243,
2581715763,
2787789398,
1060185593,
1593081372,
2418618748,
4260947970,
69676912,
2159744348,
86519011,
2512459080,
3838209314,
1220612927,
3339683548,
133810670,
1090789135,
1078426020,
1569222167,
845107691,
3583754449,
4072456591,
1091646820,
628848692,
1613405280,
3757631651,
526609435,
236106946,
48312990,
2942717905,
3402727701,
1797494240,
859738849,
992217954,
4005476642,
2243076622,
3870952857,
3732016268,
765654824,
3490871365,
2511836413,
1685915746,
3888969200,
1414112111,
2273134842,
3281911079,
4080962846,
172450625,
2569994100,
980381355,
4109958455,
2819808352,
2716589560,
2568741196,
3681446669,
3329971472,
1835478071,
660984891,
3704678404,
4045999559,
3422617507,
3040415634,
1762651403,
1719377915,
3470491036,
2693910283,
3642056355,
3138596744,
1364962596,
2073328063,
1983633131,
926494387,
3423689081,
2150032023,
4096667949,
1749200295,
3328846651,
309677260,
2016342300,
1779581495,
3079819751,
111262694,
1274766160,
443224088,
298511866,
1025883608,
3806446537,
1145181785,
168956806,
3641502830,
3584813610,
1689216846,
3666258015,
3200248200,
1692713982,
2646376535,
4042768518,
1618508792,
1610833997,
3523052358,
4130873264,
2001055236,
3610705100,
2202168115,
4028541809,
2961195399,
1006657119,
2006996926,
3186142756,
1430667929,
3210227297,
1314452623,
4074634658,
4101304120,
2273951170,
1399257539,
3367210612,
3027628629,
1190975929,
2062231137,
2333990788,
2221543033,
2438960610,
1181637006,
548689776,
2362791313,
3372408396,
3104550113,
3145860560,
296247880,
1970579870,
3078560182,
3769228297,
1714227617,
3291629107,
3898220290,
166772364,
1251581989,
493813264,
448347421,
195405023,
2709975567,
677966185,
3703036547,
1463355134,
2715995803,
1338867538,
1343315457,
2802222074,
2684532164,
233230375,
2599980071,
2000651841,
3277868038,
1638401717,
4028070440,
3237316320,
6314154,
819756386,
300326615,
590932579,
1405279636,
3267499572,
3150704214,
2428286686,
3959192993,
3461946742,
1862657033,
1266418056,
963775037,
2089974820,
2263052895,
1917689273,
448879540,
3550394620,
3981727096,
150775221,
3627908307,
1303187396,
508620638,
2975983352,
2726630617,
1817252668,
1876281319,
1457606340,
908771278,
3720792119,
3617206836,
2455994898,
1729034894,
1080033504,
976866871,
3556439503,
2881648439,
1522871579,
1555064734,
1336096578,
3548522304,
2579274686,
3574697629,
3205460757,
3593280638,
3338716283,
3079412587,
564236357,
2993598910,
1781952180,
1464380207,
3163844217,
3332601554,
1699332808,
1393555694,
1183702653,
3581086237,
1288719814,
691649499,
2847557200,
2895455976,
3193889540,
2717570544,
1781354906,
1676643554,
2592534050,
3230253752,
1126444790,
2770207658,
2633158820,
2210423226,
2615765581,
2414155088,
3127139286,
673620729,
2805611233,
1269405062,
4015350505,
3341807571,
4149409754,
1057255273,
2012875353,
2162469141,
2276492801,
2601117357,
993977747,
3918593370,
2654263191,
753973209,
36408145,
2530585658,
25011837,
3520020182,
2088578344,
530523599,
2918365339,
1524020338,
1518925132,
3760827505,
3759777254,
1202760957,
3985898139,
3906192525,
674977740,
4174734889,
2031300136,
2019492241,
3983892565,
4153806404,
3822280332,
352677332,
2297720250,
60907813,
90501309,
3286998549,
1016092578,
2535922412,
2839152426,
457141659,
509813237,
4120667899,
652014361,
1966332200,
2975202805,
55981186,
2327461051,
676427537,
3255491064,
2882294119,
3433927263,
1307055953,
942726286,
933058658,
2468411793,
3933900994,
4215176142,
1361170020,
2001714738,
2830558078,
3274259782,
1222529897,
1679025792,
2729314320,
3714953764,
1770335741,
151462246,
3013232138,
1682292957,
1483529935,
471910574,
1539241949,
458788160,
3436315007,
1807016891,
3718408830,
978976581,
1043663428,
3165965781,
1927990952,
4200891579,
2372276910,
3208408903,
3533431907,
1412390302,
2931980059,
4132332400,
1947078029,
3881505623,
4168226417,
2941484381,
1077988104,
1320477388,
886195818,
18198404,
3786409e3,
2509781533,
112762804,
3463356488,
1866414978,
891333506,
18488651,
661792760,
1628790961,
3885187036,
3141171499,
876946877,
2693282273,
1372485963,
791857591,
2686433993,
3759982718,
3167212022,
3472953795,
2716379847,
445679433,
3561995674,
3504004811,
3574258232,
54117162,
3331405415,
2381918588,
3769707343,
4154350007,
1140177722,
4074052095,
668550556,
3214352940,
367459370,
261225585,
2610173221,
4209349473,
3468074219,
3265815641,
314222801,
3066103646,
3808782860,
282218597,
3406013506,
3773591054,
379116347,
1285071038,
846784868,
2669647154,
3771962079,
3550491691,
2305946142,
453669953,
1268987020,
3317592352,
3279303384,
3744833421,
2610507566,
3859509063,
266596637,
3847019092,
517658769,
3462560207,
3443424879,
370717030,
4247526661,
2224018117,
4143653529,
4112773975,
2788324899,
2477274417,
1456262402,
2901442914,
1517677493,
1846949527,
2295493580,
3734397586,
2176403920,
1280348187,
1908823572,
3871786941,
846861322,
1172426758,
3287448474,
3383383037,
1655181056,
3139813346,
901632758,
1897031941,
2986607138,
3066810236,
3447102507,
1393639104,
373351379,
950779232,
625454576,
3124240540,
4148612726,
2007998917,
544563296,
2244738638,
2330496472,
2058025392,
1291430526,
424198748,
50039436,
29584100,
3605783033,
2429876329,
2791104160,
1057563949,
3255363231,
3075367218,
3463963227,
1469046755,
985887462
];
var C_ORIG = [
1332899944,
1700884034,
1701343084,
1684370003,
1668446532,
1869963892
];
function _encipher(lr, off, P, S) {
var n, l = lr[off], r = lr[off + 1];
l ^= P[0];
n = S[l >>> 24];
n += S[256 | l >> 16 & 255];
n ^= S[512 | l >> 8 & 255];
n += S[768 | l & 255];
r ^= n ^ P[1];
n = S[r >>> 24];
n += S[256 | r >> 16 & 255];
n ^= S[512 | r >> 8 & 255];
n += S[768 | r & 255];
l ^= n ^ P[2];
n = S[l >>> 24];
n += S[256 | l >> 16 & 255];
n ^= S[512 | l >> 8 & 255];
n += S[768 | l & 255];
r ^= n ^ P[3];
n = S[r >>> 24];
n += S[256 | r >> 16 & 255];
n ^= S[512 | r >> 8 & 255];
n += S[768 | r & 255];
l ^= n ^ P[4];
n = S[l >>> 24];
n += S[256 | l >> 16 & 255];
n ^= S[512 | l >> 8 & 255];
n += S[768 | l & 255];
r ^= n ^ P[5];
n = S[r >>> 24];
n += S[256 | r >> 16 & 255];
n ^= S[512 | r >> 8 & 255];
n += S[768 | r & 255];
l ^= n ^ P[6];
n = S[l >>> 24];
n += S[256 | l >> 16 & 255];
n ^= S[512 | l >> 8 & 255];
n += S[768 | l & 255];
r ^= n ^ P[7];
n = S[r >>> 24];
n += S[256 | r >> 16 & 255];
n ^= S[512 | r >> 8 & 255];
n += S[768 | r & 255];
l ^= n ^ P[8];
n = S[l >>> 24];
n += S[256 | l >> 16 & 255];
n ^= S[512 | l >> 8 & 255];
n += S[768 | l & 255];
r ^= n ^ P[9];
n = S[r >>> 24];
n += S[256 | r >> 16 & 255];
n ^= S[512 | r >> 8 & 255];
n += S[768 | r & 255];
l ^= n ^ P[10];
n = S[l >>> 24];
n += S[256 | l >> 16 & 255];
n ^= S[512 | l >> 8 & 255];
n += S[768 | l & 255];
r ^= n ^ P[11];
n = S[r >>> 24];
n += S[256 | r >> 16 & 255];
n ^= S[512 | r >> 8 & 255];
n += S[768 | r & 255];
l ^= n ^ P[12];
n = S[l >>> 24];
n += S[256 | l >> 16 & 255];
n ^= S[512 | l >> 8 & 255];
n += S[768 | l & 255];
r ^= n ^ P[13];
n = S[r >>> 24];
n += S[256 | r >> 16 & 255];
n ^= S[512 | r >> 8 & 255];
n += S[768 | r & 255];
l ^= n ^ P[14];
n = S[l >>> 24];
n += S[256 | l >> 16 & 255];
n ^= S[512 | l >> 8 & 255];
n += S[768 | l & 255];
r ^= n ^ P[15];
n = S[r >>> 24];
n += S[256 | r >> 16 & 255];
n ^= S[512 | r >> 8 & 255];
n += S[768 | r & 255];
l ^= n ^ P[16];
lr[off] = r ^ P[BLOWFISH_NUM_ROUNDS + 1];
lr[off + 1] = l;
return lr;
}
function _streamtoword(data, offp) {
for (var i = 0, word = 0; i < 4; ++i)
word = word << 8 | data[offp] & 255, offp = (offp + 1) % data.length;
return { key: word, offp };
}
function _key(key, P, S) {
var offset = 0, lr = [0, 0], plen = P.length, slen = S.length, sw;
for (var i = 0; i < plen; i++)
sw = _streamtoword(key, offset), offset = sw.offp, P[i] = P[i] ^ sw.key;
for (i = 0; i < plen; i += 2)
lr = _encipher(lr, 0, P, S), P[i] = lr[0], P[i + 1] = lr[1];
for (i = 0; i < slen; i += 2)
lr = _encipher(lr, 0, P, S), S[i] = lr[0], S[i + 1] = lr[1];
}
function _ekskey(data, key, P, S) {
var offp = 0, lr = [0, 0], plen = P.length, slen = S.length, sw;
for (var i = 0; i < plen; i++)
sw = _streamtoword(key, offp), offp = sw.offp, P[i] = P[i] ^ sw.key;
offp = 0;
for (i = 0; i < plen; i += 2)
sw = _streamtoword(data, offp), offp = sw.offp, lr[0] ^= sw.key, sw = _streamtoword(data, offp), offp = sw.offp, lr[1] ^= sw.key, lr = _encipher(lr, 0, P, S), P[i] = lr[0], P[i + 1] = lr[1];
for (i = 0; i < slen; i += 2)
sw = _streamtoword(data, offp), offp = sw.offp, lr[0] ^= sw.key, sw = _streamtoword(data, offp), offp = sw.offp, lr[1] ^= sw.key, lr = _encipher(lr, 0, P, S), S[i] = lr[0], S[i + 1] = lr[1];
}
function _crypt(b, salt, rounds, callback, progressCallback) {
var cdata = C_ORIG.slice(), clen = cdata.length, err;
if (rounds < 4 || rounds > 31) {
err = Error("Illegal number of rounds (4-31): " + rounds);
if (callback) {
nextTick(callback.bind(this, err));
return;
} else throw err;
}
if (salt.length !== BCRYPT_SALT_LEN) {
err = Error(
"Illegal salt length: " + salt.length + " != " + BCRYPT_SALT_LEN
);
if (callback) {
nextTick(callback.bind(this, err));
return;
} else throw err;
}
rounds = 1 << rounds >>> 0;
var P, S, i = 0, j;
if (typeof Int32Array === "function") {
P = new Int32Array(P_ORIG);
S = new Int32Array(S_ORIG);
} else {
P = P_ORIG.slice();
S = S_ORIG.slice();
}
_ekskey(salt, b, P, S);
function next() {
if (progressCallback) progressCallback(i / rounds);
if (i < rounds) {
var start = Date.now();
for (; i < rounds; ) {
i = i + 1;
_key(b, P, S);
_key(salt, P, S);
if (Date.now() - start > MAX_EXECUTION_TIME) break;
}
} else {
for (i = 0; i < 64; i++)
for (j = 0; j < clen >> 1; j++) _encipher(cdata, j << 1, P, S);
var ret = [];
for (i = 0; i < clen; i++)
ret.push((cdata[i] >> 24 & 255) >>> 0), ret.push((cdata[i] >> 16 & 255) >>> 0), ret.push((cdata[i] >> 8 & 255) >>> 0), ret.push((cdata[i] & 255) >>> 0);
if (callback) {
callback(null, ret);
return;
} else return ret;
}
if (callback) nextTick(next);
}
if (typeof callback !== "undefined") {
next();
} else {
var res;
while (true) if (typeof (res = next()) !== "undefined") return res || [];
}
}
function _hash(password, salt, callback, progressCallback) {
var err;
if (typeof password !== "string" || typeof salt !== "string") {
err = Error("Invalid string / salt: Not a string");
if (callback) {
nextTick(callback.bind(this, err));
return;
} else throw err;
}
var minor, offset;
if (salt.charAt(0) !== "$" || salt.charAt(1) !== "2") {
err = Error("Invalid salt version: " + salt.substring(0, 2));
if (callback) {
nextTick(callback.bind(this, err));
return;
} else throw err;
}
if (salt.charAt(2) === "$") minor = String.fromCharCode(0), offset = 3;
else {
minor = salt.charAt(2);
if (minor !== "a" && minor !== "b" && minor !== "y" || salt.charAt(3) !== "$") {
err = Error("Invalid salt revision: " + salt.substring(2, 4));
if (callback) {
nextTick(callback.bind(this, err));
return;
} else throw err;
}
offset = 4;
}
if (salt.charAt(offset + 2) > "$") {
err = Error("Missing salt rounds");
if (callback) {
nextTick(callback.bind(this, err));
return;
} else throw err;
}
var r1 = parseInt(salt.substring(offset, offset + 1), 10) * 10, r2 = parseInt(salt.substring(offset + 1, offset + 2), 10), rounds = r1 + r2, real_salt = salt.substring(offset + 3, offset + 25);
password += minor >= "a" ? "\0" : "";
var passwordb = utf8Array(password), saltb = base64_decode(real_salt, BCRYPT_SALT_LEN);
function finish(bytes) {
var res = [];
res.push("$2");
if (minor >= "a") res.push(minor);
res.push("$");
if (rounds < 10) res.push("0");
res.push(rounds.toString());
res.push("$");
res.push(base64_encode(saltb, saltb.length));
res.push(base64_encode(bytes, C_ORIG.length * 4 - 1));
return res.join("");
}
if (typeof callback == "undefined")
return finish(_crypt(passwordb, saltb, rounds));
else {
_crypt(
passwordb,
saltb,
rounds,
function(err2, bytes) {
if (err2) callback(err2, null);
else callback(null, finish(bytes));
},
progressCallback
);
}
}
// src/modules/auth/acl.constants.ts
var ALL_RIDS = [
"branch.create",
"branch.list",
"buy.order.list",
"cities.create",
"cities.list",
"cities.list.remove",
"cities.list.view",
"cities.list.view.edit",
"collection.create",
"collection.list",
"collection.list.edit",
"collection.list.remove",
"comment",
"comment.remove",
"comment.state",
"comment.view",
"comment.view.edit",
"config.report",
"config.statics",
"config.statics.brand",
"config.statics.brand.create",
"config.statics.brand.edit",
"config.statics.brand.remove",
"config.statics.tags",
"config.statics.tags.create",
"config.statics.tags.edit",
"config.statics.tags.remove",
"config.wallet",
"custom.config.statics.slider",
"custom.config.statics.tags.banner.ids",
"dashboard.omde",
"dashboard.tak",
"document.create",
"document.list",
"document.list.confirm",
"document.list.deny",
"document.list.edit",
"document.list.get",
"document.list.remove",
"invoice.create",
"invoice.list",
"newsletters",
"notify.create",
"notify.me",
"offers.autopromotion",
"offers.create",
"offers.create.tak",
"offers.list",
"offers.list.edit",
"offers.list.remove",
"offers.list.tak.edit",
"offers.list.tak.remove",
"offersIgnore",
"order.create",
"order.list",
"order.list.pdf",
"order.list.sts",
"order.list.sts.remove",
"order.list.sts.submit",
"order.list.view",
"order.list.view.edit",
"order.makeOrder",
"order.makeOrder.get",
"order.makeOrder.remove",
"order.makeOrder.state",
"order.makeOrder.state.remove",
"order.makeOrder.state.submit",
"order.makeOrder.view",
"order.makeOrder.view.edit",
"order.omde",
"order.omde.get",
"order.omde.remove",
"order.omde.state",
"order.omde.state.remove",
"order.omde.state.submit",
"order.omde.view",
"order.omde.view.edit",
"order.omde.view.remove",
"order.tamin",
"order.tamin.state",
"order.tamin.state.remove",
"order.tamin.state.submit",
"order.tamin.view",
"order.tamin.view.edit",
"persons.create",
"persons.create.client",
"persons.create.customer.tak",
"persons.create.seller",
"persons.list.client.omde",
"persons.list.client.omde.able",
"persons.list.client.omde.able.order",
"persons.list.client.omde.edit",
"persons.list.client.omde.unable",
"persons.list.client.omde.unable.order",
"persons.list.client.omde.view",
"persons.list.client.omde.view.documents",
"persons.list.client.omde.view.orders",
"persons.list.client.single",
"persons.list.client.single.edit",
"persons.list.client.single.view",
"persons.list.sellers",
"persons.list.sellers.able",
"persons.list.sellers.able.order",
"persons.list.sellers.edit",
"persons.list.sellers.unable",
"persons.list.sellers.unable.order",
"persons.list.sellers.view",
"persons.list.sellers.view.documents",
"persons.list.sellers.view.orders",
"product.create",
"product.list",
"product.list.edit",
"product.list.group.edit",
"product.list.remove",
"product.list.variants",
"product.list.variants.add",
"product.list.variants.edit",
"product.list.variants.remove",
"product.list.view",
"product.percent",
"report.order.item",
"report.product",
"sms.create",
"sms.create.all",
"sms.create.multiple",
"sms.create.omde",
"sms.create.reagent",
"sms.create.single",
"sms.list",
"statics",
"user.create",
"user.list",
"user.list.create",
"user.list.edit",
"user.list.remove",
"user.permission",
"user.permission.create",
"user.permission.edit",
"wallet",
"wallet.charge",
"wallet.list",
"wallet.percent",
"workshop.create",
"workshop.list"
];
// prisma/seed.ts
var prisma = new import_client.PrismaClient();
var DEV_PASSWORD = "admin1234";
var PLACEHOLDER_PASSWORD_HASH = hashSync(DEV_PASSWORD, 10);
var DEV_TEST_PHONE = "09128081392";
var DEV_TEST_PHONE_PASSWORD_HASH = hashSync(DEV_TEST_PHONE, 10);
var PLACEHOLDER_PRODUCT_IMAGE = "/img/no-items.png";
async function main() {
const [tehran, mashhad, isfahan, tabriz] = await Promise.all([
prisma.city.upsert({ where: { id: "city-tehran" }, update: {}, create: { id: "city-tehran", name: "\u062A\u0647\u0631\u0627\u0646", province: "\u062A\u0647\u0631\u0627\u0646" } }),
prisma.city.upsert({ where: { id: "city-mashhad" }, update: {}, create: { id: "city-mashhad", name: "\u0645\u0634\u0647\u062F", province: "\u062E\u0631\u0627\u0633\u0627\u0646 \u0631\u0636\u0648\u06CC" } }),
prisma.city.upsert({ where: { id: "city-isfahan" }, update: {}, create: { id: "city-isfahan", name: "\u0627\u0635\u0641\u0647\u0627\u0646", province: "\u0627\u0635\u0641\u0647\u0627\u0646" } }),
prisma.city.upsert({ where: { id: "city-tabriz" }, update: {}, create: { id: "city-tabriz", name: "\u062A\u0628\u0631\u06CC\u0632", province: "\u0622\u0630\u0631\u0628\u0627\u06CC\u062C\u0627\u0646 \u0634\u0631\u0642\u06CC" } })
]);
const branchTehran = await prisma.branch.upsert({
where: { id: "branch-tehran-bazaar" },
update: {},
create: { id: "branch-tehran-bazaar", name: "\u0634\u0639\u0628\u0647 \u0628\u0627\u0632\u0627\u0631 \u0628\u0632\u0631\u06AF \u062A\u0647\u0631\u0627\u0646", cityId: tehran.id }
});
const branchMashhad = await prisma.branch.upsert({
where: { id: "branch-mashhad-main" },
update: {},
create: { id: "branch-mashhad-main", name: "\u0634\u0639\u0628\u0647 \u0645\u0631\u06A9\u0632\u06CC \u0645\u0634\u0647\u062F", cityId: mashhad.id }
});
await prisma.workshop.upsert({
where: { id: "workshop-central" },
update: {},
create: { id: "workshop-central", name: "\u06A9\u0627\u0631\u06AF\u0627\u0647 \u0645\u0631\u06A9\u0632\u06CC \u0633\u0627\u062E\u062A \u0637\u0644\u0627" }
});
const userTypes = [
// Full access — every rid the routers gate.
{ id: 85, title: "\u0645\u062F\u06CC\u0631 \u0627\u0631\u0634\u062F", rids: ALL_RIDS },
{
id: 86,
title: "\u06A9\u0627\u0631\u0634\u0646\u0627\u0633 \u0641\u0631\u0648\u0634",
rids: [
"order.list",
"order.create",
"order.omde",
"order.makeOrder",
"persons.list.client.omde",
"persons.list.client.omde.view",
"persons.list.client.single",
"persons.list.client.single.view",
"persons.create",
"product.list",
"dashboard.tak",
"comment"
]
},
{
id: 87,
title: "\u062D\u0633\u0627\u0628\u062F\u0627\u0631",
rids: [
"document.list",
"document.create",
"document.list.edit",
"invoice.list",
"invoice.create",
"wallet",
"config.wallet",
"report.order.item",
"report.product",
"config.report",
"dashboard.omde"
]
},
{
id: 88,
title: "\u0633\u0631\u067E\u0631\u0633\u062A \u06A9\u0627\u0631\u06AF\u0627\u0647",
rids: ["workshop.list", "workshop.create", "order.tamin", "order.list", "product.list"]
},
{
id: 89,
title: "\u06A9\u0627\u0631\u0628\u0631 \u0634\u0639\u0628\u0647",
rids: ["buy.order.list", "order.create", "persons.create", "branch.list"]
}
];
for (const ut of userTypes) {
await prisma.userType.upsert({
where: { id: ut.id },
update: { title: ut.title },
create: { id: ut.id, title: ut.title }
});
await prisma.permission.createMany({
data: ut.rids.map((rid) => ({ rid, userTypeId: ut.id })),
skipDuplicates: true
});
}
await prisma.adminUser.upsert({
where: { mobile: DEV_TEST_PHONE },
update: { passwordHash: DEV_TEST_PHONE_PASSWORD_HASH, userTypeId: 85, branchId: null },
create: {
mobile: DEV_TEST_PHONE,
fullName: "\u06A9\u0627\u0631\u0628\u0631 \u062A\u0633\u062A \u062A\u0648\u0633\u0639\u0647",
passwordHash: DEV_TEST_PHONE_PASSWORD_HASH,
role: import_client.AdminRole.SUPER_ADMIN,
userTypeId: 85,
branchId: null
}
});
await prisma.adminUser.upsert({
where: { mobile: "09120000001" },
update: { passwordHash: PLACEHOLDER_PASSWORD_HASH, userTypeId: 85, branchId: null },
create: {
mobile: "09120000001",
fullName: "\u0645\u062F\u06CC\u0631 \u0627\u0631\u0634\u062F \u0633\u06CC\u0633\u062A\u0645",
passwordHash: PLACEHOLDER_PASSWORD_HASH,
role: import_client.AdminRole.SUPER_ADMIN,
userTypeId: 85,
// Head office: deliberately branch-less. Legacy scoped every list by
// branch_id whenever the user had one, so head-office staff must have none
// or they would see only a single branch's data.
branchId: null
}
});
const agentReza = await prisma.adminUser.upsert({
where: { mobile: "09121234567" },
update: { passwordHash: PLACEHOLDER_PASSWORD_HASH, userTypeId: 86 },
create: {
mobile: "09121234567",
fullName: "\u0631\u0636\u0627 \u0627\u062D\u0645\u062F\u06CC",
passwordHash: PLACEHOLDER_PASSWORD_HASH,
role: import_client.AdminRole.SALES_EXPERT,
userTypeId: 86,
branchId: branchTehran.id,
wagePercent: 1.5
}
});
const agentSara = await prisma.adminUser.upsert({
where: { mobile: "09129876543" },
update: { passwordHash: PLACEHOLDER_PASSWORD_HASH, userTypeId: 86 },
create: {
mobile: "09129876543",
fullName: "\u0633\u0627\u0631\u0627 \u06A9\u0631\u06CC\u0645\u06CC",
passwordHash: PLACEHOLDER_PASSWORD_HASH,
role: import_client.AdminRole.SALES_EXPERT,
userTypeId: 86,
branchId: branchMashhad.id,
wagePercent: 1.2
}
});
await prisma.adminUser.upsert({
where: { mobile: "09123334444" },
update: { passwordHash: PLACEHOLDER_PASSWORD_HASH, userTypeId: 88 },
create: {
mobile: "09123334444",
fullName: "\u0647\u0648\u0645\u0646 \u06CC\u0632\u062F\u0627\u0646\u06CC",
passwordHash: PLACEHOLDER_PASSWORD_HASH,
role: import_client.AdminRole.WORKSHOP_SUPERVISOR,
userTypeId: 88
}
});
await prisma.adminUser.upsert({
where: { mobile: "09125556666" },
update: { passwordHash: PLACEHOLDER_PASSWORD_HASH, userTypeId: 87, branchId: null },
create: {
mobile: "09125556666",
fullName: "\u0641\u0631\u0632\u0627\u0646\u0647 \u0645\u062D\u0645\u0648\u062F\u06CC",
passwordHash: PLACEHOLDER_PASSWORD_HASH,
role: import_client.AdminRole.ACCOUNTANT,
userTypeId: 87,
branchId: null
}
});
const customerData = [
{
// DEV-ONLY test login, per explicit request: same number as the admin
// panel account above, so it can also sign in to the user-app (OTP step
// matches on mobile against a real seeded customer — see LoginView.vue).
// Fully verified so no onboarding step blocks it. Not for a real deployment.
id: "customer-dev-test",
kind: import_client.CustomerKind.APP_SHOPKEEPER,
memberCode: "DEV-TEST",
fullName: "\u06A9\u0627\u0631\u0628\u0631 \u062A\u0633\u062A \u062A\u0648\u0633\u0639\u0647",
mobile: DEV_TEST_PHONE,
nationalCode: "0000000000",
cityId: tehran.id,
referredByAgentId: null,
goldCreditLimitGrams: "1000",
verificationStep: import_client.VerificationStep.VERIFIED
},
{
id: "customer-1",
kind: import_client.CustomerKind.BANKER,
storeName: "\u0637\u0644\u0627\u06CC \u0645\u062D\u0645\u062F\u06CC",
pasazhName: "\u067E\u0627\u0633\u0627\u0698 \u0628\u0632\u0631\u06AF",
zone: "\u0628\u0627\u0632\u0627\u0631",
memberCode: "M-1001",
phone: "02133445566",
address: "\u062A\u0647\u0631\u0627\u0646\u060C \u0628\u0627\u0632\u0627\u0631 \u0628\u0632\u0631\u06AF\u060C \u067E\u0644\u0627\u06A9 \u06F1\u06F2",
fullName: "\u0639\u0644\u06CC \u0645\u062D\u0645\u062F\u06CC",
mobile: "09151112233",
nationalCode: "0012345678",
cityId: tehran.id,
referredByAgentId: agentReza.id,
goldCreditLimitGrams: "200",
verificationStep: import_client.VerificationStep.VERIFIED
},
{
id: "customer-2",
kind: import_client.CustomerKind.APP_SHOPKEEPER,
storeName: "\u06AF\u0627\u0644\u0631\u06CC \u062D\u0633\u06CC\u0646\u06CC",
zone: "\u0648\u0646\u06A9",
memberCode: "M-1002",
phone: "02188776655",
fullName: "\u0645\u0631\u06CC\u0645 \u062D\u0633\u06CC\u0646\u06CC",
mobile: "09151112234",
nationalCode: "0012345679",
cityId: tehran.id,
referredByAgentId: agentReza.id,
goldCreditLimitGrams: "100",
verificationStep: import_client.VerificationStep.VERIFIED
},
{
id: "customer-3",
kind: import_client.CustomerKind.WALK_IN_SHOPKEEPER,
storeName: "\u0632\u0631\u06AF\u0631\u06CC \u0646\u0648\u0631\u0648\u0632\u06CC",
pasazhName: "\u067E\u0627\u0633\u0627\u0698 \u0631\u0636\u0627",
zone: "\u0637\u0631\u0642",
memberCode: "M-1003",
fullName: "\u062C\u0648\u0627\u062F \u0646\u0648\u0631\u0648\u0632\u06CC",
mobile: "09151112235",
nationalCode: "0012345680",
cityId: mashhad.id,
referredByAgentId: agentSara.id,
goldCreditLimitGrams: "50",
verificationStep: import_client.VerificationStep.STEP_TWO_SUBMITTED
},
{
id: "customer-4",
kind: import_client.CustomerKind.APP_SHOPKEEPER,
memberCode: "M-1004",
fullName: "\u0646\u0631\u06AF\u0633 \u0627\u0628\u0631\u0627\u0647\u06CC\u0645\u06CC",
mobile: "09151112236",
nationalCode: "0012345681",
cityId: isfahan.id,
referredByAgentId: null,
goldCreditLimitGrams: "30",
verificationStep: import_client.VerificationStep.UNVERIFIED,
// archived, so the "لیست بایگانی" grid has a row and the type lists
// correctly exclude it
isArchived: true
},
{
id: "customer-5",
kind: import_client.CustomerKind.BANKER,
storeName: "\u0635\u0627\u062F\u0642\u06CC \u0648 \u067E\u0633\u0631\u0627\u0646",
zone: "\u0628\u0627\u0632\u0627\u0631",
memberCode: "M-1005",
phone: "02155443322",
fullName: "\u06A9\u0627\u0645\u0631\u0627\u0646 \u0635\u0627\u062F\u0642\u06CC",
mobile: "09151112237",
nationalCode: "0012345682",
cityId: tehran.id,
referredByAgentId: agentReza.id,
goldCreditLimitGrams: "500",
verificationStep: import_client.VerificationStep.VERIFIED
},
{
id: "customer-6",
kind: import_client.CustomerKind.WALK_IN_SHOPKEEPER,
storeName: "\u0637\u0644\u0627\u0633\u0631\u0627\u06CC \u0642\u0627\u0633\u0645\u06CC",
zone: "\u0627\u0626\u0644 \u06AF\u0644\u06CC",
memberCode: "M-1006",
fullName: "\u0632\u0647\u0631\u0627 \u0642\u0627\u0633\u0645\u06CC",
mobile: "09151112238",
nationalCode: "0012345683",
cityId: tabriz.id,
referredByAgentId: agentSara.id,
goldCreditLimitGrams: "80",
verificationStep: import_client.VerificationStep.STEP_ONE_SUBMITTED
}
];
const customers = [];
for (const c of customerData) {
customers.push(
await prisma.customer.upsert({
where: { id: c.id },
// Re-assert the DESCRIPTIVE fields on an existing row so a re-seed
// backfills columns added after that row was first created. Balances,
// verification state and credit limits are deliberately NOT touched —
// those are live data a re-seed must never overwrite.
update: {
kind: c.kind,
phone: "phone" in c ? c.phone : null,
address: "address" in c ? c.address : null,
storeName: "storeName" in c ? c.storeName : null,
pasazhName: "pasazhName" in c ? c.pasazhName : null,
zone: "zone" in c ? c.zone : null,
memberCode: c.memberCode,
isArchived: "isArchived" in c ? c.isArchived : false
},
create: {
id: c.id,
fullName: c.fullName,
mobile: c.mobile,
nationalCode: c.nationalCode,
passwordHash: PLACEHOLDER_PASSWORD_HASH,
cityId: c.cityId,
referredByAgentId: c.referredByAgentId,
goldCreditLimitGrams: c.goldCreditLimitGrams,
verificationStep: c.verificationStep,
kind: c.kind,
phone: "phone" in c ? c.phone : null,
address: "address" in c ? c.address : null,
storeName: "storeName" in c ? c.storeName : null,
pasazhName: "pasazhName" in c ? c.pasazhName : null,
zone: "zone" in c ? c.zone : null,
memberCode: c.memberCode,
isArchived: "isArchived" in c ? c.isArchived : false
}
})
);
}
const byId = (id) => customers.find((c) => c.id === id);
const customer1 = byId("customer-1");
const customer2 = byId("customer-2");
const customer5 = byId("customer-5");
const [ringsCategory, braceletsCategory, necklacesCategory, earringsCategory, coinsCategory] = await Promise.all([
prisma.category.upsert({ where: { id: "cat-rings" }, update: {}, create: { id: "cat-rings", title: "\u0627\u0646\u06AF\u0634\u062A\u0631" } }),
prisma.category.upsert({ where: { id: "cat-bracelets" }, update: {}, create: { id: "cat-bracelets", title: "\u062F\u0633\u062A\u0628\u0646\u062F" } }),
prisma.category.upsert({ where: { id: "cat-necklaces" }, update: {}, create: { id: "cat-necklaces", title: "\u06AF\u0631\u062F\u0646\u0628\u0646\u062F" } }),
prisma.category.upsert({ where: { id: "cat-earrings" }, update: {}, create: { id: "cat-earrings", title: "\u06AF\u0648\u0634\u0648\u0627\u0631\u0647" } }),
prisma.category.upsert({ where: { id: "cat-coins" }, update: {}, create: { id: "cat-coins", title: "\u0633\u06A9\u0647 \u0648 \u0634\u0645\u0634" } })
]);
const brandHenza = await prisma.brand.upsert({
where: { id: "brand-henza" },
update: {},
create: { id: "brand-henza", title: "\u0647\u0646\u0632\u0627 \u0637\u0644\u0627" }
});
const brandArtisan = await prisma.brand.upsert({
where: { id: "brand-artisan" },
update: {},
create: { id: "brand-artisan", title: "\u0645\u062C\u0645\u0648\u0639\u0647 \u0635\u0646\u0639\u062A\u06AF\u0631" }
});
const productDefs = [
{
id: "product-classic-ring",
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: brandHenza.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" }
]
},
{
id: "product-woven-bracelet",
title: "\u062F\u0633\u062A\u0628\u0646\u062F \u0628\u0627\u0641\u062A \u0632\u0646\u062C\u06CC\u0631\u06CC",
description: "\u062F\u0633\u062A\u0628\u0646\u062F \u0628\u0627\u0641\u062A\u200C\u062F\u0627\u0631 \u062F\u0633\u062A\u200C\u0633\u0627\u0632 \u0627\u0632 \u0637\u0644\u0627\u06CC \u06F1\u06F8 \u0639\u06CC\u0627\u0631.",
categoryId: braceletsCategory.id,
brandId: brandArtisan.id,
variants: [
{ id: "variant-bracelet-standard", title: "\u0627\u0633\u062A\u0627\u0646\u062F\u0627\u0631\u062F \u06F1\u06F8 \u0633\u0627\u0646\u062A\u06CC", sku: "BRC-WOVEN-18", rashWeightGrams: "14.200", defaultWagePercent: "11.5" }
]
},
{
id: "product-pendant-necklace",
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: brandHenza.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" }
]
},
{
id: "product-hoop-earrings",
title: "\u06AF\u0648\u0634\u0648\u0627\u0631\u0647 \u062D\u0644\u0642\u0647\u200C\u0627\u06CC \u06A9\u0644\u0627\u0633\u06CC\u06A9",
description: "\u06AF\u0648\u0634\u0648\u0627\u0631\u0647 \u062D\u0644\u0642\u0647\u200C\u0627\u06CC \u0637\u0644\u0627\u06CC \u06F1\u06F8 \u0639\u06CC\u0627\u0631 \u0645\u0646\u0627\u0633\u0628 \u0627\u0633\u062A\u0641\u0627\u062F\u0647 \u0631\u0648\u0632\u0645\u0631\u0647.",
categoryId: earringsCategory.id,
brandId: brandArtisan.id,
variants: [
{ id: "variant-hoop-small", title: "\u06A9\u0648\u0686\u06A9", sku: "ERG-HOOP-S", rashWeightGrams: "1.900", defaultWagePercent: "8.5" },
{ id: "variant-hoop-large", title: "\u0628\u0632\u0631\u06AF", sku: "ERG-HOOP-L", rashWeightGrams: "3.400", defaultWagePercent: "8.5" }
]
},
{
id: "product-full-coin",
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: brandHenza.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" }
]
}
];
const createdVariantIds = {};
let imageCount = 0;
for (const p of productDefs) {
const product = await prisma.product.upsert({
where: { id: p.id },
update: {},
create: {
id: p.id,
title: p.title,
description: p.description,
categoryId: p.categoryId,
brandId: p.brandId
}
});
for (const v of p.variants) {
await prisma.productVariant.upsert({
where: { id: v.id },
update: {},
create: {
id: v.id,
productId: product.id,
title: v.title,
sku: v.sku,
rashWeightGrams: v.rashWeightGrams,
defaultWagePercent: v.defaultWagePercent
}
});
createdVariantIds[v.id] = v.id;
}
await prisma.productImage.upsert({
where: { id: `${p.id}-img-1` },
update: { url: PLACEHOLDER_PRODUCT_IMAGE },
create: {
id: `${p.id}-img-1`,
productId: product.id,
url: PLACEHOLDER_PRODUCT_IMAGE,
sortOrder: 0
}
});
imageCount += 1;
}
const featured = await prisma.collection.upsert({
where: { id: "collection-featured" },
update: {},
create: { id: "collection-featured", title: "\u067E\u0631\u0641\u0631\u0648\u0634\u200C\u0647\u0627\u06CC \u0627\u06CC\u0646 \u0647\u0641\u062A\u0647", description: "\u0645\u0646\u062A\u062E\u0628\u06CC \u0627\u0632 \u0645\u062D\u0628\u0648\u0628\u200C\u062A\u0631\u06CC\u0646 \u0645\u062D\u0635\u0648\u0644\u0627\u062A \u0641\u0631\u0648\u0634\u06AF\u0627\u0647." }
});
await prisma.collectionProduct.upsert({
where: { collectionId_productId: { collectionId: featured.id, productId: "product-classic-ring" } },
update: {},
create: { collectionId: featured.id, productId: "product-classic-ring" }
});
await prisma.collectionProduct.upsert({
where: { collectionId_productId: { collectionId: featured.id, productId: "product-pendant-necklace" } },
update: {},
create: { collectionId: featured.id, productId: "product-pendant-necklace" }
});
await prisma.collectionProduct.upsert({
where: { collectionId_productId: { collectionId: featured.id, productId: "product-full-coin" } },
update: {},
create: { collectionId: featured.id, productId: "product-full-coin" }
});
await prisma.goldPriceQuote.create({
data: { karatPerMille: 750, pricePerGramRial: "61500000", source: "seed-illustrative" }
});
const existingRetail = await prisma.order.findUnique({
where: { orderNumber: "ORD-SEED-0002" }
});
if (!existingRetail) {
const rash = "2.400";
const wage = 7.5;
const computed = (parseFloat(rash) * (1 + wage / 100)).toFixed(4);
await prisma.order.create({
data: {
orderNumber: "ORD-SEED-0002",
customerId: customer2.id,
branchId: branchTehran.id,
channel: import_client.OrderChannel.RETAIL,
status: "PLACED",
totalGoldWeightGrams: computed,
wageWeightGrams: (parseFloat(computed) - parseFloat(rash)).toFixed(4),
flatRialCharge: "0",
items: {
create: [
{
productVariantId: "variant-ring-size-7",
quantity: 1,
rashWeightGramsSnapshot: rash,
wagePercentSnapshot: wage.toString(),
discountPercentSnapshot: "0",
computedWeightGrams: computed,
flatRialCharge: "0"
}
]
},
statusEvents: { create: [{ toStatus: "PLACED" }] }
}
});
}
await prisma.order.updateMany({
where: { orderNumber: "ORD-SEED-0001" },
data: { channel: import_client.OrderChannel.WHOLESALE }
});
await prisma.order.updateMany({
where: { orderNumber: "ORD-SEED-0002" },
data: { channel: import_client.OrderChannel.RETAIL }
});
const existingDemoOrder = await prisma.order.findUnique({ where: { orderNumber: "ORD-SEED-0001" } });
if (!existingDemoOrder) {
const rashWeight = "3.100";
const wagePercent = 9;
const discountPercent = 0;
const computedWeight = (parseFloat(rashWeight) * (1 + (wagePercent - discountPercent) / 100)).toFixed(4);
const quantity = 1;
const flatRialChargePerUnit = "500000";
const order = await prisma.order.create({
data: {
orderNumber: "ORD-SEED-0001",
customerId: customer1.id,
branchId: branchTehran.id,
// customer1 is a بنکدار, so this belongs to the wholesale grid
channel: import_client.OrderChannel.WHOLESALE,
status: "DELIVERED_TO_CUSTOMER",
totalGoldWeightGrams: computedWeight,
wageWeightGrams: (parseFloat(computedWeight) - parseFloat(rashWeight)).toFixed(4),
flatRialCharge: flatRialChargePerUnit,
deliveredAt: /* @__PURE__ */ new Date(),
items: {
create: [
{
productVariantId: "variant-ring-size-7",
quantity,
rashWeightGramsSnapshot: rashWeight,
wagePercentSnapshot: wagePercent.toString(),
discountPercentSnapshot: discountPercent.toString(),
computedWeightGrams: computedWeight,
flatRialCharge: flatRialChargePerUnit
}
]
},
statusEvents: {
create: [{ toStatus: "PLACED" }, { toStatus: "ADMIN_APPROVED" }, { toStatus: "DELIVERED_TO_CUSTOMER" }]
}
}
});
await prisma.ledgerEntry.create({
data: {
customerId: customer1.id,
currency: "GOLD_GRAM",
direction: "DEBIT",
sourceType: "ORDER_STOCK",
amount: computedWeight,
orderId: order.id,
confirmed: true,
confirmedAt: /* @__PURE__ */ new Date(),
note: "\u0628\u062F\u0647\u06CC \u0648\u0632\u0646\u06CC \u0637\u0644\u0627 \u0647\u0646\u06AF\u0627\u0645 \u062A\u062D\u0648\u06CC\u0644 (\u062F\u0627\u062F\u0647 \u0622\u0632\u0645\u0627\u06CC\u0634\u06CC)"
}
});
await prisma.ledgerEntry.create({
data: {
customerId: customer1.id,
currency: "RIAL",
direction: "DEBIT",
sourceType: "ORDER_STOCK",
amount: flatRialChargePerUnit,
orderId: order.id,
confirmed: true,
confirmedAt: /* @__PURE__ */ new Date(),
note: "\u0647\u0632\u06CC\u0646\u0647 \u062B\u0627\u0628\u062A \u0631\u06CC\u0627\u0644\u06CC \u0647\u0646\u06AF\u0627\u0645 \u062A\u062D\u0648\u06CC\u0644 (\u062F\u0627\u062F\u0647 \u0622\u0632\u0645\u0627\u06CC\u0634\u06CC)"
}
});
await prisma.customer.update({
where: { id: customer1.id },
data: { goldDebtGrams: { increment: computedWeight }, fiatDebtRial: { increment: flatRialChargePerUnit } }
});
await prisma.ledgerEntry.create({
data: {
customerId: customer1.id,
currency: "GOLD_GRAM",
direction: "CREDIT",
sourceType: "REPAYMENT_MELTED_GOLD",
amount: "1.5000",
karatPerMille: 750,
confirmed: false,
note: "\u062A\u0633\u0648\u06CC\u0647 \u0628\u0627 \u0637\u0644\u0627\u06CC \u0622\u0628\u200C\u0634\u062F\u0647\u060C \u062F\u0631 \u0627\u0646\u062A\u0638\u0627\u0631 \u062A\u0627\u06CC\u06CC\u062F (\u062F\u0627\u062F\u0647 \u0622\u0632\u0645\u0627\u06CC\u0634\u06CC)"
}
});
}
await prisma.customer.update({ where: { id: customer2.id }, data: { goldDebtGrams: "8.2500", fiatDebtRial: "2000000" } });
await prisma.customer.update({ where: { id: customer5.id }, data: { goldDebtGrams: "0", fiatDebtRial: "0" } });
const preOrderSeeds = [
{
id: "preorder-0001",
customerId: customer2.id,
cityId: tehran.id,
status: "PLACED",
colorName: "\u0631\u0632\u06AF\u0644\u062F",
sizeSpec: "\u06F1\u06F6",
stoneColor: "\u0633\u0641\u06CC\u062F",
minaColor: "\u0622\u0628\u06CC",
description: "\u0627\u0646\u06AF\u0634\u062A\u0631 \u0637\u0631\u062D \u0633\u0646\u062A\u06CC \u0628\u0627 \u0646\u06AF\u06CC\u0646 \u0633\u0641\u06CC\u062F",
estimatedWeightGrams: "4.5000"
},
{
id: "preorder-0002",
customerId: customer5.id,
cityId: mashhad.id,
status: "ADMIN_APPROVED",
colorName: "\u0632\u0631\u062F",
sizeSpec: "\u06F1\u06F8",
stoneColor: "\u0642\u0631\u0645\u0632",
minaColor: "\u0633\u0628\u0632",
description: "\u062F\u0633\u062A\u0628\u0646\u062F \u0645\u06CC\u0646\u0627 \u06A9\u0627\u0631\u06CC",
estimatedWeightGrams: "9.2500"
}
];
for (const po of preOrderSeeds) {
await prisma.preOrder.upsert({
where: { id: po.id },
update: {},
create: po
});
}
const allProducts = await prisma.product.findMany({ take: 3 });
if (allProducts.length > 0) {
const commentSeeds = [
{
id: "comment-0001",
productId: allProducts[0].id,
customerId: customer2.id,
body: "\u06A9\u06CC\u0641\u06CC\u062A \u0633\u0627\u062E\u062A \u0639\u0627\u0644\u06CC \u0628\u0648\u062F\u060C \u0645\u0645\u0646\u0648\u0646 \u0627\u0632 \u0627\u0631\u0633\u0627\u0644 \u0633\u0631\u06CC\u0639.",
status: "APPROVED"
},
{
id: "comment-0002",
productId: allProducts[0].id,
customerId: customer5.id,
body: "\u0622\u06CC\u0627 \u0627\u06CC\u0646 \u0645\u062F\u0644 \u062F\u0631 \u0633\u0627\u06CC\u0632 \u0628\u0632\u0631\u06AF\u200C\u062A\u0631 \u0647\u0645 \u0645\u0648\u062C\u0648\u062F \u0645\u06CC\u200C\u0634\u0648\u062F\u061F",
status: "PENDING"
},
{
id: "comment-0003",
productId: allProducts[Math.min(1, allProducts.length - 1)].id,
customerId: customer2.id,
body: "\u0648\u0632\u0646 \u0628\u0627 \u0622\u0646\u0686\u0647 \u0646\u0648\u0634\u062A\u0647 \u0634\u062F\u0647 \u06A9\u0645\u06CC \u062A\u0641\u0627\u0648\u062A \u062F\u0627\u0634\u062A.",
status: "REJECTED"
}
];
for (const c of commentSeeds) {
await prisma.comment.upsert({ where: { id: c.id }, update: {}, create: c });
}
}
const allVariants = await prisma.productVariant.findMany();
for (const [i, v] of allVariants.entries()) {
await prisma.productVariant.update({
where: { id: v.id },
data: { qty: 5 + i % 4, isPreOrder: i % 5 === 0 }
});
}
const codedProducts = await prisma.product.findMany({ orderBy: { title: "asc" } });
for (const [i, p] of codedProducts.entries()) {
await prisma.product.update({
where: { id: p.id },
data: { productCode: `P-${String(i + 1).padStart(4, "0")}` }
});
}
console.log("Seed complete:", {
cities: 4,
branches: 2,
adminUsers: 5,
customers: customers.length,
products: productDefs.length,
variants: Object.keys(createdVariantIds).length,
productImages: imageCount
});
}
main().catch((e) => {
console.error(e);
process.exit(1);
}).finally(async () => {
await prisma.$disconnect();
});