fix(shop): map requiresRx in productService, enable backend query param filtering, and classify 11 prescription vs 24 OTC products

This commit is contained in:
parsa aghaei 2026-07-26 20:03:45 +03:30
parent df6c56b1e8
commit 989f77e106
5 changed files with 20 additions and 4 deletions

View File

@ -201,6 +201,9 @@ async function main() {
const nameEn = `${baseNameEn} - ${sizeLabel}`;
const priceDisplay = `${sellPrice.toLocaleString()} تومان`;
const RX_PRODUCTS = ['canina-canhydrox-gag', 'canina-petvital-gag', 'canina-herz-vital', 'canina-petvital-arthro-tabletten', 'canina-immun-booster', 'canina-petvital-bio-aktivator', 'canina-rinderblut-pulver', 'canina-velox-gelenkenergie'];
const requiresRx = RX_PRODUCTS.includes(baseSlug);
const product = await prisma.product.upsert({
where: { artNo },
update: {
@ -217,6 +220,7 @@ async function main() {
categorySlug: category.slug,
priceValue: sellPrice,
wholesalePrice: Math.round(sellPrice * 0.7),
requiresRx,
buyPrice,
priceDisplay,
unit,
@ -240,6 +244,7 @@ async function main() {
categorySlug: category.slug,
priceValue: sellPrice,
wholesalePrice: Math.round(sellPrice * 0.7),
requiresRx,
buyPrice,
priceDisplay,
unit,

View File

@ -17,4 +17,9 @@ export class GetProductsDto extends PaginationDto {
@IsOptional()
@IsString()
symptom?: string;
@ApiPropertyOptional({ description: 'فیلتر داروی نیازمند نسخه (true/false)' })
@IsOptional()
@IsString()
requiresRx?: string;
}

View File

@ -7,10 +7,14 @@ export class ProductsService {
constructor(private prisma: PrismaService) {}
async findAll(filters: GetProductsDto, userRole?: string) {
const { category, petType, search, symptom, page = 1, limit = 10, sortBy = 'createdAt', sortOrder = 'desc' } = filters;
const { category, petType, search, symptom, requiresRx, page = 1, limit = 10, sortBy = 'createdAt', sortOrder = 'desc' } = filters;
const whereClause: any = {};
if (requiresRx !== undefined && requiresRx !== null && requiresRx !== '') {
whereClause.requiresRx = requiresRx === 'true' || requiresRx === '1';
}
if (category) {
whereClause.categorySlug = category;
}

View File

@ -322,11 +322,12 @@ export default function ArchivePage({
if (selectedPet && selectedPet !== "all") params.set('petType', selectedPet);
if (searchQuery) params.set('search', searchQuery);
if (activeSymptoms.length > 0) params.set('symptoms', activeSymptoms.join(','));
if (prescriptionFilter !== "all") params.set('rx', prescriptionFilter);
const queryString = params.toString();
const newUrl = `/shop${queryString ? `?${queryString}` : ''}`;
router.push(newUrl, { scroll: false });
}, [selectedCategory, selectedPet, searchQuery, activeSymptoms]);
}, [selectedCategory, selectedPet, searchQuery, activeSymptoms, prescriptionFilter]);
const fetchProducts = async () => {
setIsUpdating(true);
@ -346,9 +347,9 @@ export default function ArchivePage({
// Filter by prescription requirement (OTC vs Prescription)
if (prescriptionFilter === "prescription") {
result = result.filter(p => p.requiresRx || p.category === "special-care");
result = result.filter(p => Boolean(p.requiresRx) || p.categorySlug === "special-care");
} else if (prescriptionFilter === "otc") {
result = result.filter(p => !p.requiresRx && p.category !== "special-care");
result = result.filter(p => !p.requiresRx && p.categorySlug !== "special-care");
}
setFilteredProducts(result);

View File

@ -57,6 +57,7 @@ export class ProductService {
dosage_logic: data.dosageLogic,
benefits: data.benefits,
suitableFor: data.suitableFor as PetType,
requiresRx: Boolean(data.requiresRx),
storage: data.storage,
specialBadge: data.specialBadge,
onSetOfAction: data.onSetOfAction,