feat: catalog read cache (api + user apps) and clearer Zarrin accounting errors

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
s.esmaeili
2026-10-11 14:31:32 +03:30
co-authored by Cursor
parent 561addc676
commit 574fa1b4aa
53 changed files with 1241 additions and 401 deletions
@@ -1,15 +1,22 @@
import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common';
import { PrismaService } from '../../prisma/prisma.service';
import { AccountingHooksService } from '../accounting-sync/accounting-hooks.service';
import { CatalogCacheService } from './catalog-cache.service';
@Injectable()
export class CatalogService {
constructor(
private readonly prisma: PrismaService,
private readonly accounting: AccountingHooksService,
private readonly catalogCache: CatalogCacheService,
) {}
async listProducts() {
/** Served from CatalogCacheService; see there for what invalidates it. */
listProducts() {
return this.catalogCache.get(() => this.buildProductList());
}
private async buildProductList() {
const products = await this.prisma.product.findMany({
// D27 — a product with no image is never shown in the app. Products now
// also arrive from the accounting software, which carries no pictures;
@@ -34,6 +41,7 @@ export class CatalogService {
},
});
const stockBlocked = await this.accounting.stockBlocker();
const out = [];
for (const p of products) {
const { accountingStockWeight, accountingStockCount, accountingStockAt, ...product } = p;
@@ -41,7 +49,7 @@ export class CatalogService {
// qty 0, which the apps already render as «ناموجود» and refuse to add to
// the cart unless it is a pre-order variant. The stock figures themselves
// stay server-side; this endpoint is public.
const blocked = await this.accounting.stockBlocked({ accountingStockWeight, accountingStockCount, accountingStockAt });
const blocked = stockBlocked({ accountingStockWeight, accountingStockCount, accountingStockAt });
out.push(blocked ? { ...product, variants: product.variants.map((v) => (v.isPreOrder ? v : { ...v, qty: 0 })) } : product);
}
return out;