@open-mercato/core 0.5.1-develop.2699.f8b50c8046 → 0.5.1-develop.2708.d6c4f6e5d1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/modules/customer_accounts/services/customerTokenService.js +2 -2
- package/dist/modules/customer_accounts/services/customerTokenService.js.map +2 -2
- package/dist/modules/messages/lib/tokenConsumption.js +1 -1
- package/dist/modules/messages/lib/tokenConsumption.js.map +2 -2
- package/package.json +6 -3
- package/src/modules/customer_accounts/services/customerTokenService.ts +2 -2
- package/src/modules/customers/i18n/de.json +4 -0
- package/src/modules/customers/i18n/en.json +4 -0
- package/src/modules/customers/i18n/es.json +4 -0
- package/src/modules/customers/i18n/pl.json +4 -0
- package/src/modules/messages/lib/tokenConsumption.ts +1 -1
- package/src/modules/sales/i18n/de.json +2 -0
- package/src/modules/sales/i18n/en.json +2 -0
- package/src/modules/sales/i18n/es.json +2 -0
- package/src/modules/sales/i18n/pl.json +2 -0
|
@@ -67,7 +67,7 @@ class CustomerTokenService {
|
|
|
67
67
|
if (tenantId && user?.tenantId !== tenantId) return null;
|
|
68
68
|
const db = getKysely(this.em);
|
|
69
69
|
const updateResult = await db.updateTable("customer_user_email_verifications").set({ used_at: /* @__PURE__ */ new Date() }).where("id", "=", record.id).where("used_at", "is", null).where("expires_at", ">", /* @__PURE__ */ new Date()).executeTakeFirst();
|
|
70
|
-
const consumed = Number(updateResult?.numUpdatedRows ??
|
|
70
|
+
const consumed = Number(updateResult?.numUpdatedRows ?? 0);
|
|
71
71
|
if (consumed === 0) return null;
|
|
72
72
|
const resolvedUserId = typeof user === "string" ? user : user.id;
|
|
73
73
|
const resolvedTenantId = typeof user === "string" ? "" : user.tenantId;
|
|
@@ -85,7 +85,7 @@ class CustomerTokenService {
|
|
|
85
85
|
if (tenantId && user?.tenantId !== tenantId) return null;
|
|
86
86
|
const db = getKysely(this.em);
|
|
87
87
|
const updateResult = await db.updateTable("customer_user_password_resets").set({ used_at: /* @__PURE__ */ new Date() }).where("id", "=", record.id).where("used_at", "is", null).where("expires_at", ">", /* @__PURE__ */ new Date()).executeTakeFirst();
|
|
88
|
-
const consumed = Number(updateResult?.numUpdatedRows ??
|
|
88
|
+
const consumed = Number(updateResult?.numUpdatedRows ?? 0);
|
|
89
89
|
if (consumed === 0) return null;
|
|
90
90
|
const resolvedUserId = typeof user === "string" ? user : user.id;
|
|
91
91
|
const resolvedTenantId = typeof user === "string" ? "" : user.tenantId;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/customer_accounts/services/customerTokenService.ts"],
|
|
4
|
-
"sourcesContent": ["import { EntityManager } from '@mikro-orm/postgresql'\nimport type { Kysely } from 'kysely'\nimport {\n CustomerUser,\n CustomerUserEmailVerification,\n CustomerUserPasswordReset,\n} from '@open-mercato/core/modules/customer_accounts/data/entities'\nimport { generateSecureToken, hashToken } from '@open-mercato/core/modules/customer_accounts/lib/tokenGenerator'\n\nfunction getKysely(em: EntityManager): Kysely<any> {\n return (em as unknown as { getKysely: () => Kysely<any> }).getKysely()\n}\n\nconst EMAIL_VERIFICATION_TTL_MS = 24 * 60 * 60 * 1000 // 24 hours\nconst MAGIC_LINK_TTL_MS = 15 * 60 * 1000 // 15 minutes\nconst PASSWORD_RESET_TTL_MS = 60 * 60 * 1000 // 60 minutes\n\nexport class CustomerTokenService {\n constructor(private em: EntityManager) {}\n\n async createEmailVerification(userId: string, tenantId: string): Promise<string> {\n const rawToken = generateSecureToken()\n const tokenHashed = hashToken(rawToken)\n const expiresAt = new Date(Date.now() + EMAIL_VERIFICATION_TTL_MS)\n const record = this.em.create(CustomerUserEmailVerification, {\n user: userId as any,\n token: tokenHashed,\n purpose: 'email_verification',\n expiresAt,\n createdAt: new Date(),\n } as any)\n await this.em.persist(record).flush()\n return rawToken\n }\n\n async createMagicLink(userId: string, tenantId: string): Promise<string> {\n const rawToken = generateSecureToken()\n const tokenHashed = hashToken(rawToken)\n const expiresAt = new Date(Date.now() + MAGIC_LINK_TTL_MS)\n const record = this.em.create(CustomerUserEmailVerification, {\n user: userId as any,\n token: tokenHashed,\n purpose: 'magic_link',\n expiresAt,\n createdAt: new Date(),\n } as any)\n await this.em.persist(record).flush()\n return rawToken\n }\n\n async createPasswordReset(userId: string, tenantId: string): Promise<string> {\n const rawToken = generateSecureToken()\n const tokenHashed = hashToken(rawToken)\n const expiresAt = new Date(Date.now() + PASSWORD_RESET_TTL_MS)\n const record = this.em.create(CustomerUserPasswordReset, {\n user: userId as any,\n token: tokenHashed,\n expiresAt,\n createdAt: new Date(),\n } as any)\n await this.em.persist(record).flush()\n return rawToken\n }\n\n async verifyEmailToken(token: string, purpose: string, tenantId?: string): Promise<{ userId: string; tenantId: string } | null> {\n const tokenHashed = hashToken(token)\n const record = await this.em.findOne(CustomerUserEmailVerification, {\n token: tokenHashed,\n purpose,\n }, { populate: ['user'] })\n if (!record) return null\n if (record.usedAt) return null\n if (record.expiresAt.getTime() < Date.now()) return null\n\n const user = record.user as CustomerUser\n if (tenantId && user?.tenantId !== tenantId) return null\n\n const db = getKysely(this.em)\n const updateResult = await db\n .updateTable('customer_user_email_verifications' as any)\n .set({ used_at: new Date() } as any)\n .where('id' as any, '=', record.id)\n .where('used_at' as any, 'is', null)\n .where('expires_at' as any, '>', new Date())\n .executeTakeFirst()\n const consumed = Number(updateResult?.numUpdatedRows ??
|
|
5
|
-
"mappings": "AAEA;AAAA,EAEE;AAAA,EACA;AAAA,OACK;AACP,SAAS,qBAAqB,iBAAiB;AAE/C,SAAS,UAAU,IAAgC;AACjD,SAAQ,GAAmD,UAAU;AACvE;AAEA,MAAM,4BAA4B,KAAK,KAAK,KAAK;AACjD,MAAM,oBAAoB,KAAK,KAAK;AACpC,MAAM,wBAAwB,KAAK,KAAK;AAEjC,MAAM,qBAAqB;AAAA,EAChC,YAAoB,IAAmB;AAAnB;AAAA,EAAoB;AAAA,EAExC,MAAM,wBAAwB,QAAgB,UAAmC;AAC/E,UAAM,WAAW,oBAAoB;AACrC,UAAM,cAAc,UAAU,QAAQ;AACtC,UAAM,YAAY,IAAI,KAAK,KAAK,IAAI,IAAI,yBAAyB;AACjE,UAAM,SAAS,KAAK,GAAG,OAAO,+BAA+B;AAAA,MAC3D,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,MACT;AAAA,MACA,WAAW,oBAAI,KAAK;AAAA,IACtB,CAAQ;AACR,UAAM,KAAK,GAAG,QAAQ,MAAM,EAAE,MAAM;AACpC,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,gBAAgB,QAAgB,UAAmC;AACvE,UAAM,WAAW,oBAAoB;AACrC,UAAM,cAAc,UAAU,QAAQ;AACtC,UAAM,YAAY,IAAI,KAAK,KAAK,IAAI,IAAI,iBAAiB;AACzD,UAAM,SAAS,KAAK,GAAG,OAAO,+BAA+B;AAAA,MAC3D,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,MACT;AAAA,MACA,WAAW,oBAAI,KAAK;AAAA,IACtB,CAAQ;AACR,UAAM,KAAK,GAAG,QAAQ,MAAM,EAAE,MAAM;AACpC,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,oBAAoB,QAAgB,UAAmC;AAC3E,UAAM,WAAW,oBAAoB;AACrC,UAAM,cAAc,UAAU,QAAQ;AACtC,UAAM,YAAY,IAAI,KAAK,KAAK,IAAI,IAAI,qBAAqB;AAC7D,UAAM,SAAS,KAAK,GAAG,OAAO,2BAA2B;AAAA,MACvD,MAAM;AAAA,MACN,OAAO;AAAA,MACP;AAAA,MACA,WAAW,oBAAI,KAAK;AAAA,IACtB,CAAQ;AACR,UAAM,KAAK,GAAG,QAAQ,MAAM,EAAE,MAAM;AACpC,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,iBAAiB,OAAe,SAAiB,UAAyE;AAC9H,UAAM,cAAc,UAAU,KAAK;AACnC,UAAM,SAAS,MAAM,KAAK,GAAG,QAAQ,+BAA+B;AAAA,MAClE,OAAO;AAAA,MACP;AAAA,IACF,GAAG,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC;AACzB,QAAI,CAAC,OAAQ,QAAO;AACpB,QAAI,OAAO,OAAQ,QAAO;AAC1B,QAAI,OAAO,UAAU,QAAQ,IAAI,KAAK,IAAI,EAAG,QAAO;AAEpD,UAAM,OAAO,OAAO;AACpB,QAAI,YAAY,MAAM,aAAa,SAAU,QAAO;AAEpD,UAAM,KAAK,UAAU,KAAK,EAAE;AAC5B,UAAM,eAAe,MAAM,GACxB,YAAY,mCAA0C,EACtD,IAAI,EAAE,SAAS,oBAAI,KAAK,EAAE,CAAQ,EAClC,MAAM,MAAa,KAAK,OAAO,EAAE,EACjC,MAAM,WAAkB,MAAM,IAAI,EAClC,MAAM,cAAqB,KAAK,oBAAI,KAAK,CAAC,EAC1C,iBAAiB;AACpB,UAAM,WAAW,OAAO,cAAc,kBAAkB,
|
|
4
|
+
"sourcesContent": ["import { EntityManager } from '@mikro-orm/postgresql'\nimport type { Kysely } from 'kysely'\nimport {\n CustomerUser,\n CustomerUserEmailVerification,\n CustomerUserPasswordReset,\n} from '@open-mercato/core/modules/customer_accounts/data/entities'\nimport { generateSecureToken, hashToken } from '@open-mercato/core/modules/customer_accounts/lib/tokenGenerator'\n\nfunction getKysely(em: EntityManager): Kysely<any> {\n return (em as unknown as { getKysely: () => Kysely<any> }).getKysely()\n}\n\nconst EMAIL_VERIFICATION_TTL_MS = 24 * 60 * 60 * 1000 // 24 hours\nconst MAGIC_LINK_TTL_MS = 15 * 60 * 1000 // 15 minutes\nconst PASSWORD_RESET_TTL_MS = 60 * 60 * 1000 // 60 minutes\n\nexport class CustomerTokenService {\n constructor(private em: EntityManager) {}\n\n async createEmailVerification(userId: string, tenantId: string): Promise<string> {\n const rawToken = generateSecureToken()\n const tokenHashed = hashToken(rawToken)\n const expiresAt = new Date(Date.now() + EMAIL_VERIFICATION_TTL_MS)\n const record = this.em.create(CustomerUserEmailVerification, {\n user: userId as any,\n token: tokenHashed,\n purpose: 'email_verification',\n expiresAt,\n createdAt: new Date(),\n } as any)\n await this.em.persist(record).flush()\n return rawToken\n }\n\n async createMagicLink(userId: string, tenantId: string): Promise<string> {\n const rawToken = generateSecureToken()\n const tokenHashed = hashToken(rawToken)\n const expiresAt = new Date(Date.now() + MAGIC_LINK_TTL_MS)\n const record = this.em.create(CustomerUserEmailVerification, {\n user: userId as any,\n token: tokenHashed,\n purpose: 'magic_link',\n expiresAt,\n createdAt: new Date(),\n } as any)\n await this.em.persist(record).flush()\n return rawToken\n }\n\n async createPasswordReset(userId: string, tenantId: string): Promise<string> {\n const rawToken = generateSecureToken()\n const tokenHashed = hashToken(rawToken)\n const expiresAt = new Date(Date.now() + PASSWORD_RESET_TTL_MS)\n const record = this.em.create(CustomerUserPasswordReset, {\n user: userId as any,\n token: tokenHashed,\n expiresAt,\n createdAt: new Date(),\n } as any)\n await this.em.persist(record).flush()\n return rawToken\n }\n\n async verifyEmailToken(token: string, purpose: string, tenantId?: string): Promise<{ userId: string; tenantId: string } | null> {\n const tokenHashed = hashToken(token)\n const record = await this.em.findOne(CustomerUserEmailVerification, {\n token: tokenHashed,\n purpose,\n }, { populate: ['user'] })\n if (!record) return null\n if (record.usedAt) return null\n if (record.expiresAt.getTime() < Date.now()) return null\n\n const user = record.user as CustomerUser\n if (tenantId && user?.tenantId !== tenantId) return null\n\n const db = getKysely(this.em)\n const updateResult = await db\n .updateTable('customer_user_email_verifications' as any)\n .set({ used_at: new Date() } as any)\n .where('id' as any, '=', record.id)\n .where('used_at' as any, 'is', null)\n .where('expires_at' as any, '>', new Date())\n .executeTakeFirst()\n const consumed = Number(updateResult?.numUpdatedRows ?? 0)\n if (consumed === 0) return null\n\n const resolvedUserId = typeof user === 'string' ? user : user.id\n const resolvedTenantId = typeof user === 'string' ? '' : user.tenantId\n return { userId: resolvedUserId, tenantId: resolvedTenantId }\n }\n\n async verifyPasswordResetToken(token: string, tenantId?: string): Promise<{ userId: string; tenantId: string } | null> {\n const tokenHashed = hashToken(token)\n const record = await this.em.findOne(CustomerUserPasswordReset, {\n token: tokenHashed,\n }, { populate: ['user'] })\n if (!record) return null\n if (record.usedAt) return null\n if (record.expiresAt.getTime() < Date.now()) return null\n\n const user = record.user as CustomerUser\n if (tenantId && user?.tenantId !== tenantId) return null\n\n const db = getKysely(this.em)\n const updateResult = await db\n .updateTable('customer_user_password_resets' as any)\n .set({ used_at: new Date() } as any)\n .where('id' as any, '=', record.id)\n .where('used_at' as any, 'is', null)\n .where('expires_at' as any, '>', new Date())\n .executeTakeFirst()\n const consumed = Number(updateResult?.numUpdatedRows ?? 0)\n if (consumed === 0) return null\n\n const resolvedUserId = typeof user === 'string' ? user : user.id\n const resolvedTenantId = typeof user === 'string' ? '' : user.tenantId\n return { userId: resolvedUserId, tenantId: resolvedTenantId }\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -11,7 +11,7 @@ async function consumeMessageAccessToken(em, tokenId) {
|
|
|
11
11
|
use_count: sql`use_count + 1`,
|
|
12
12
|
used_at: now
|
|
13
13
|
}).where("id", "=", tokenId).where("use_count", "<", MAX_TOKEN_USE_COUNT).where("expires_at", ">", now).executeTakeFirst();
|
|
14
|
-
const consumed = Number(updateResult?.numUpdatedRows ??
|
|
14
|
+
const consumed = Number(updateResult?.numUpdatedRows ?? 0);
|
|
15
15
|
if (consumed > 0) return { ok: true };
|
|
16
16
|
em.clear();
|
|
17
17
|
const fresh = await em.findOne(MessageAccessToken, { id: tokenId });
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/messages/lib/tokenConsumption.ts"],
|
|
4
|
-
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { type Kysely, sql } from 'kysely'\nimport { MessageAccessToken } from '../data/entities'\n\nexport const MAX_TOKEN_USE_COUNT = 25\n\nexport type TokenConsumptionFailureReason = 'expired' | 'exhausted' | 'not_found'\n\nexport type TokenConsumptionResult =\n | { ok: true }\n | { ok: false; reason: TokenConsumptionFailureReason }\n\nfunction getKysely(em: EntityManager): Kysely<any> {\n return (em as unknown as { getKysely: () => Kysely<any> }).getKysely()\n}\n\nexport async function consumeMessageAccessToken(\n em: EntityManager,\n tokenId: string,\n): Promise<TokenConsumptionResult> {\n const db = getKysely(em)\n const now = new Date()\n const updateResult = await db\n .updateTable('message_access_tokens' as any)\n .set({\n use_count: sql`use_count + 1`,\n used_at: now,\n } as any)\n .where('id' as any, '=', tokenId)\n .where('use_count' as any, '<', MAX_TOKEN_USE_COUNT)\n .where('expires_at' as any, '>', now)\n .executeTakeFirst()\n const consumed = Number(updateResult?.numUpdatedRows ??
|
|
5
|
-
"mappings": "AACA,SAAsB,WAAW;AACjC,SAAS,0BAA0B;AAE5B,MAAM,sBAAsB;AAQnC,SAAS,UAAU,IAAgC;AACjD,SAAQ,GAAmD,UAAU;AACvE;AAEA,eAAsB,0BACpB,IACA,SACiC;AACjC,QAAM,KAAK,UAAU,EAAE;AACvB,QAAM,MAAM,oBAAI,KAAK;AACrB,QAAM,eAAe,MAAM,GACxB,YAAY,uBAA8B,EAC1C,IAAI;AAAA,IACH,WAAW;AAAA,IACX,SAAS;AAAA,EACX,CAAQ,EACP,MAAM,MAAa,KAAK,OAAO,EAC/B,MAAM,aAAoB,KAAK,mBAAmB,EAClD,MAAM,cAAqB,KAAK,GAAG,EACnC,iBAAiB;AACpB,QAAM,WAAW,OAAO,cAAc,kBAAkB,
|
|
4
|
+
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { type Kysely, sql } from 'kysely'\nimport { MessageAccessToken } from '../data/entities'\n\nexport const MAX_TOKEN_USE_COUNT = 25\n\nexport type TokenConsumptionFailureReason = 'expired' | 'exhausted' | 'not_found'\n\nexport type TokenConsumptionResult =\n | { ok: true }\n | { ok: false; reason: TokenConsumptionFailureReason }\n\nfunction getKysely(em: EntityManager): Kysely<any> {\n return (em as unknown as { getKysely: () => Kysely<any> }).getKysely()\n}\n\nexport async function consumeMessageAccessToken(\n em: EntityManager,\n tokenId: string,\n): Promise<TokenConsumptionResult> {\n const db = getKysely(em)\n const now = new Date()\n const updateResult = await db\n .updateTable('message_access_tokens' as any)\n .set({\n use_count: sql`use_count + 1`,\n used_at: now,\n } as any)\n .where('id' as any, '=', tokenId)\n .where('use_count' as any, '<', MAX_TOKEN_USE_COUNT)\n .where('expires_at' as any, '>', now)\n .executeTakeFirst()\n const consumed = Number(updateResult?.numUpdatedRows ?? 0)\n if (consumed > 0) return { ok: true }\n\n em.clear()\n const fresh = await em.findOne(MessageAccessToken, { id: tokenId })\n if (!fresh) return { ok: false, reason: 'not_found' }\n if (fresh.expiresAt < now) return { ok: false, reason: 'expired' }\n return { ok: false, reason: 'exhausted' }\n}\n"],
|
|
5
|
+
"mappings": "AACA,SAAsB,WAAW;AACjC,SAAS,0BAA0B;AAE5B,MAAM,sBAAsB;AAQnC,SAAS,UAAU,IAAgC;AACjD,SAAQ,GAAmD,UAAU;AACvE;AAEA,eAAsB,0BACpB,IACA,SACiC;AACjC,QAAM,KAAK,UAAU,EAAE;AACvB,QAAM,MAAM,oBAAI,KAAK;AACrB,QAAM,eAAe,MAAM,GACxB,YAAY,uBAA8B,EAC1C,IAAI;AAAA,IACH,WAAW;AAAA,IACX,SAAS;AAAA,EACX,CAAQ,EACP,MAAM,MAAa,KAAK,OAAO,EAC/B,MAAM,aAAoB,KAAK,mBAAmB,EAClD,MAAM,cAAqB,KAAK,GAAG,EACnC,iBAAiB;AACpB,QAAM,WAAW,OAAO,cAAc,kBAAkB,CAAC;AACzD,MAAI,WAAW,EAAG,QAAO,EAAE,IAAI,KAAK;AAEpC,KAAG,MAAM;AACT,QAAM,QAAQ,MAAM,GAAG,QAAQ,oBAAoB,EAAE,IAAI,QAAQ,CAAC;AAClE,MAAI,CAAC,MAAO,QAAO,EAAE,IAAI,OAAO,QAAQ,YAAY;AACpD,MAAI,MAAM,YAAY,IAAK,QAAO,EAAE,IAAI,OAAO,QAAQ,UAAU;AACjE,SAAO,EAAE,IAAI,OAAO,QAAQ,YAAY;AAC1C;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-mercato/core",
|
|
3
|
-
"version": "0.5.1-develop.
|
|
3
|
+
"version": "0.5.1-develop.2708.d6c4f6e5d1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -223,6 +223,9 @@
|
|
|
223
223
|
}
|
|
224
224
|
},
|
|
225
225
|
"dependencies": {
|
|
226
|
+
"@mikro-orm/core": "^7.0.10",
|
|
227
|
+
"@mikro-orm/decorators": "^7.0.10",
|
|
228
|
+
"@mikro-orm/postgresql": "^7.0.10",
|
|
226
229
|
"@xyflow/react": "^12.10.2",
|
|
227
230
|
"ai": "^6.0.168",
|
|
228
231
|
"date-fns": "^4.1.0",
|
|
@@ -234,10 +237,10 @@
|
|
|
234
237
|
"ts-pattern": "^5.0.0"
|
|
235
238
|
},
|
|
236
239
|
"peerDependencies": {
|
|
237
|
-
"@open-mercato/shared": "0.5.1-develop.
|
|
240
|
+
"@open-mercato/shared": "0.5.1-develop.2708.d6c4f6e5d1"
|
|
238
241
|
},
|
|
239
242
|
"devDependencies": {
|
|
240
|
-
"@open-mercato/shared": "0.5.1-develop.
|
|
243
|
+
"@open-mercato/shared": "0.5.1-develop.2708.d6c4f6e5d1",
|
|
241
244
|
"@testing-library/dom": "^10.4.1",
|
|
242
245
|
"@testing-library/jest-dom": "^6.9.1",
|
|
243
246
|
"@testing-library/react": "^16.3.1",
|
|
@@ -83,7 +83,7 @@ export class CustomerTokenService {
|
|
|
83
83
|
.where('used_at' as any, 'is', null)
|
|
84
84
|
.where('expires_at' as any, '>', new Date())
|
|
85
85
|
.executeTakeFirst()
|
|
86
|
-
const consumed = Number(updateResult?.numUpdatedRows ??
|
|
86
|
+
const consumed = Number(updateResult?.numUpdatedRows ?? 0)
|
|
87
87
|
if (consumed === 0) return null
|
|
88
88
|
|
|
89
89
|
const resolvedUserId = typeof user === 'string' ? user : user.id
|
|
@@ -111,7 +111,7 @@ export class CustomerTokenService {
|
|
|
111
111
|
.where('used_at' as any, 'is', null)
|
|
112
112
|
.where('expires_at' as any, '>', new Date())
|
|
113
113
|
.executeTakeFirst()
|
|
114
|
-
const consumed = Number(updateResult?.numUpdatedRows ??
|
|
114
|
+
const consumed = Number(updateResult?.numUpdatedRows ?? 0)
|
|
115
115
|
if (consumed === 0) return null
|
|
116
116
|
|
|
117
117
|
const resolvedUserId = typeof user === 'string' ? user : user.id
|
|
@@ -966,6 +966,9 @@
|
|
|
966
966
|
"customers.linking.preview.label": "Vorschau",
|
|
967
967
|
"customers.linking.preview.loading": "Details werden geladen…",
|
|
968
968
|
"customers.linking.primary.badge": "Primär",
|
|
969
|
+
"customers.linking.primary.current": "Primär",
|
|
970
|
+
"customers.linking.primary.help": "Wähle aus, welcher verknüpfte Datensatz als primär behandelt werden soll.",
|
|
971
|
+
"customers.linking.primary.set": "Als primär festlegen",
|
|
969
972
|
"customers.linking.primary.setAction": "Als primär festlegen",
|
|
970
973
|
"customers.linking.resultsCount": "{{count}} Ergebnisse",
|
|
971
974
|
"customers.linking.searchResults": "Suchergebnisse",
|
|
@@ -973,6 +976,7 @@
|
|
|
973
976
|
"customers.linking.selectEntity": "{{name}} auswählen",
|
|
974
977
|
"customers.linking.selected.clearAll": "Zurücksetzen",
|
|
975
978
|
"customers.linking.selected.count": "{{count}} ausgewählt",
|
|
979
|
+
"customers.linking.selected.label": "Ausgewählt",
|
|
976
980
|
"customers.linking.selected.remove": "Entfernen",
|
|
977
981
|
"customers.linking.selected.title": "Ausgewählt",
|
|
978
982
|
"customers.linking.settings.label": "Verknüpfungseinstellungen",
|
|
@@ -966,6 +966,9 @@
|
|
|
966
966
|
"customers.linking.preview.label": "Preview",
|
|
967
967
|
"customers.linking.preview.loading": "Loading details…",
|
|
968
968
|
"customers.linking.primary.badge": "Primary",
|
|
969
|
+
"customers.linking.primary.current": "Primary",
|
|
970
|
+
"customers.linking.primary.help": "Choose which linked record should be treated as primary.",
|
|
971
|
+
"customers.linking.primary.set": "Set primary",
|
|
969
972
|
"customers.linking.primary.setAction": "Set primary",
|
|
970
973
|
"customers.linking.resultsCount": "{{count}} results",
|
|
971
974
|
"customers.linking.searchResults": "Search results",
|
|
@@ -973,6 +976,7 @@
|
|
|
973
976
|
"customers.linking.selectEntity": "Select {{name}}",
|
|
974
977
|
"customers.linking.selected.clearAll": "Clear",
|
|
975
978
|
"customers.linking.selected.count": "{{count}} selected",
|
|
979
|
+
"customers.linking.selected.label": "Selected",
|
|
976
980
|
"customers.linking.selected.remove": "Remove",
|
|
977
981
|
"customers.linking.selected.title": "Selected",
|
|
978
982
|
"customers.linking.settings.label": "Link settings",
|
|
@@ -966,6 +966,9 @@
|
|
|
966
966
|
"customers.linking.preview.label": "Vista previa",
|
|
967
967
|
"customers.linking.preview.loading": "Cargando detalles…",
|
|
968
968
|
"customers.linking.primary.badge": "Principal",
|
|
969
|
+
"customers.linking.primary.current": "Principal",
|
|
970
|
+
"customers.linking.primary.help": "Elige qué registro vinculado debe tratarse como principal.",
|
|
971
|
+
"customers.linking.primary.set": "Definir principal",
|
|
969
972
|
"customers.linking.primary.setAction": "Marcar como principal",
|
|
970
973
|
"customers.linking.resultsCount": "{{count}} resultados",
|
|
971
974
|
"customers.linking.searchResults": "Resultados de la búsqueda",
|
|
@@ -973,6 +976,7 @@
|
|
|
973
976
|
"customers.linking.selectEntity": "Seleccionar {{name}}",
|
|
974
977
|
"customers.linking.selected.clearAll": "Limpiar",
|
|
975
978
|
"customers.linking.selected.count": "{{count}} seleccionados",
|
|
979
|
+
"customers.linking.selected.label": "Seleccionados",
|
|
976
980
|
"customers.linking.selected.remove": "Eliminar",
|
|
977
981
|
"customers.linking.selected.title": "Seleccionados",
|
|
978
982
|
"customers.linking.settings.label": "Ajustes del vínculo",
|
|
@@ -966,6 +966,9 @@
|
|
|
966
966
|
"customers.linking.preview.label": "Podgląd",
|
|
967
967
|
"customers.linking.preview.loading": "Wczytywanie szczegółów…",
|
|
968
968
|
"customers.linking.primary.badge": "Główny",
|
|
969
|
+
"customers.linking.primary.current": "Główny",
|
|
970
|
+
"customers.linking.primary.help": "Wybierz, który powiązany rekord ma być traktowany jako główny.",
|
|
971
|
+
"customers.linking.primary.set": "Ustaw główny",
|
|
969
972
|
"customers.linking.primary.setAction": "Ustaw jako główny",
|
|
970
973
|
"customers.linking.resultsCount": "{{count}} wyników",
|
|
971
974
|
"customers.linking.searchResults": "Wyniki wyszukiwania",
|
|
@@ -973,6 +976,7 @@
|
|
|
973
976
|
"customers.linking.selectEntity": "Wybierz {{name}}",
|
|
974
977
|
"customers.linking.selected.clearAll": "Wyczyść",
|
|
975
978
|
"customers.linking.selected.count": "Wybrano: {{count}}",
|
|
979
|
+
"customers.linking.selected.label": "Wybrane",
|
|
976
980
|
"customers.linking.selected.remove": "Usuń",
|
|
977
981
|
"customers.linking.selected.title": "Wybrane",
|
|
978
982
|
"customers.linking.settings.label": "Ustawienia powiązania",
|
|
@@ -30,7 +30,7 @@ export async function consumeMessageAccessToken(
|
|
|
30
30
|
.where('use_count' as any, '<', MAX_TOKEN_USE_COUNT)
|
|
31
31
|
.where('expires_at' as any, '>', now)
|
|
32
32
|
.executeTakeFirst()
|
|
33
|
-
const consumed = Number(updateResult?.numUpdatedRows ??
|
|
33
|
+
const consumed = Number(updateResult?.numUpdatedRows ?? 0)
|
|
34
34
|
if (consumed > 0) return { ok: true }
|
|
35
35
|
|
|
36
36
|
em.clear()
|
|
@@ -1338,10 +1338,12 @@
|
|
|
1338
1338
|
"sales.shipment-statuses.create": "Sendungsstatus hinzufügen",
|
|
1339
1339
|
"sales.shipment-statuses.delete": "Sendungsstatus löschen",
|
|
1340
1340
|
"sales.shipment-statuses.update": "Sendungsstatus aktualisieren",
|
|
1341
|
+
"sales.shipments.fully_returned": "Die Sendung kann nicht geändert werden: Die Bestellung wurde vollständig retourniert.",
|
|
1341
1342
|
"sales.shipments.invalid_order": "Die Sendung gehört nicht zu dieser Bestellung.",
|
|
1342
1343
|
"sales.shipments.items_required": "Füge mindestens eine Position zur Sendung hinzu.",
|
|
1343
1344
|
"sales.shipments.line_missing": "Bestellposition wurde nicht gefunden.",
|
|
1344
1345
|
"sales.shipments.not_found": "Sendung wurde nicht gefunden",
|
|
1346
|
+
"sales.shipments.payment_completed": "Die Sendung kann nicht geändert werden: Die Zahlung der Bestellung ist abgeschlossen.",
|
|
1345
1347
|
"sales.shipments.quantity_exceeded": "Es kann nicht mehr als die verbleibende Menge versendet werden.",
|
|
1346
1348
|
"sales.stageBar.changeFailed": "Failed to update stage",
|
|
1347
1349
|
"sales.stageBar.changed": "Stage updated",
|
|
@@ -1338,10 +1338,12 @@
|
|
|
1338
1338
|
"sales.shipment-statuses.create": "Add shipment status",
|
|
1339
1339
|
"sales.shipment-statuses.delete": "Delete shipment status",
|
|
1340
1340
|
"sales.shipment-statuses.update": "Update shipment status",
|
|
1341
|
+
"sales.shipments.fully_returned": "Cannot modify shipment: order is fully returned.",
|
|
1341
1342
|
"sales.shipments.invalid_order": "Shipment does not belong to this order.",
|
|
1342
1343
|
"sales.shipments.items_required": "Add at least one line to ship.",
|
|
1343
1344
|
"sales.shipments.line_missing": "Order line not found.",
|
|
1344
1345
|
"sales.shipments.not_found": "Shipment not found",
|
|
1346
|
+
"sales.shipments.payment_completed": "Cannot modify shipment: order payment is completed.",
|
|
1345
1347
|
"sales.shipments.quantity_exceeded": "Cannot ship more than the remaining quantity.",
|
|
1346
1348
|
"sales.stageBar.changeFailed": "Failed to update stage",
|
|
1347
1349
|
"sales.stageBar.changed": "Stage updated",
|
|
@@ -1338,10 +1338,12 @@
|
|
|
1338
1338
|
"sales.shipment-statuses.create": "Agregar estado de envío",
|
|
1339
1339
|
"sales.shipment-statuses.delete": "Eliminar estado de envío",
|
|
1340
1340
|
"sales.shipment-statuses.update": "Actualizar estado de envío",
|
|
1341
|
+
"sales.shipments.fully_returned": "No se puede modificar el envío: el pedido fue devuelto por completo.",
|
|
1341
1342
|
"sales.shipments.invalid_order": "El envío no pertenece a este pedido.",
|
|
1342
1343
|
"sales.shipments.items_required": "Agrega al menos una línea para enviar.",
|
|
1343
1344
|
"sales.shipments.line_missing": "Línea de pedido no encontrada.",
|
|
1344
1345
|
"sales.shipments.not_found": "Envío no encontrado",
|
|
1346
|
+
"sales.shipments.payment_completed": "No se puede modificar el envío: el pago del pedido está completado.",
|
|
1345
1347
|
"sales.shipments.quantity_exceeded": "No se puede enviar más de la cantidad restante.",
|
|
1346
1348
|
"sales.stageBar.changeFailed": "Failed to update stage",
|
|
1347
1349
|
"sales.stageBar.changed": "Stage updated",
|
|
@@ -1338,10 +1338,12 @@
|
|
|
1338
1338
|
"sales.shipment-statuses.create": "Dodaj status wysyłki",
|
|
1339
1339
|
"sales.shipment-statuses.delete": "Usuń status wysyłki",
|
|
1340
1340
|
"sales.shipment-statuses.update": "Zaktualizuj status wysyłki",
|
|
1341
|
+
"sales.shipments.fully_returned": "Nie można zmodyfikować wysyłki: zamówienie zostało w pełni zwrócone.",
|
|
1341
1342
|
"sales.shipments.invalid_order": "Wysyłka nie należy do tego zamówienia.",
|
|
1342
1343
|
"sales.shipments.items_required": "Dodaj co najmniej jedną linię do wysyłki.",
|
|
1343
1344
|
"sales.shipments.line_missing": "Nie znaleziono linii zamówienia.",
|
|
1344
1345
|
"sales.shipments.not_found": "Nie znaleziono wysyłki",
|
|
1346
|
+
"sales.shipments.payment_completed": "Nie można zmodyfikować wysyłki: płatność za zamówienie jest zakończona.",
|
|
1345
1347
|
"sales.shipments.quantity_exceeded": "Nie można wysłać więcej niż pozostała ilość.",
|
|
1346
1348
|
"sales.stageBar.changeFailed": "Failed to update stage",
|
|
1347
1349
|
"sales.stageBar.changed": "Stage updated",
|