From 3ab45419333b0a4ccfdb1d5210cae7d086aefe73 Mon Sep 17 00:00:00 2001 From: parsa aghaei Date: Sun, 26 Jul 2026 14:36:53 +0330 Subject: [PATCH] feat(wholesale): implement Bulk Order Matrix with role-based wholesale pricing display [TASK-104] --- .ai_agency/memory/backlog.json | 2 +- .ai_agency/memory/state.json | 10 +-- frontend/application/components/B2BPortal.tsx | 88 +++++++++++++------ 3 files changed, 66 insertions(+), 34 deletions(-) diff --git a/.ai_agency/memory/backlog.json b/.ai_agency/memory/backlog.json index 74875ac..d996be2 100644 --- a/.ai_agency/memory/backlog.json +++ b/.ai_agency/memory/backlog.json @@ -46,7 +46,7 @@ "title": "پیاده‌سازی پنل و جدول سفارش حجمی (Bulk Order Matrix) برای خریداران عمده تاییدشده", "priority": "HIGH", "assigned_role": "05_dev_frontend", - "status": "pending", + "status": "completed", "max_file_count": 3, "estimated_minutes": 15, "dependency_task_ids": ["TASK-103"], diff --git a/.ai_agency/memory/state.json b/.ai_agency/memory/state.json index e32e18a..fb03c04 100644 --- a/.ai_agency/memory/state.json +++ b/.ai_agency/memory/state.json @@ -5,8 +5,8 @@ "checkpoint": { "stage": "DEVELOPMENT", "active_agent": "05_dev_frontend", - "current_ticket_id": "TASK-104", - "sub_step_index": 4, + "current_ticket_id": "TASK-105", + "sub_step_index": 5, "total_sub_steps": 5 }, "execution_guards": { @@ -16,11 +16,11 @@ "token_usage_total": 0 }, "git_state": { - "active_branch": "feature/TASK-103", + "active_branch": "feature/TASK-104", "last_healthy_commit": "HEAD" }, "context_buffer": { - "last_agent_summary": "TASK-103 (Wholesale Buyer Verification & License Form) completed and verified." + "last_agent_summary": "TASK-104 (Bulk Order Matrix and Wholesale Pricing Tiers) completed and verified." }, - "last_updated": "2026-07-26T14:35:00Z" + "last_updated": "2026-07-26T14:36:00Z" } diff --git a/frontend/application/components/B2BPortal.tsx b/frontend/application/components/B2BPortal.tsx index 0a767f2..da50667 100644 --- a/frontend/application/components/B2BPortal.tsx +++ b/frontend/application/components/B2BPortal.tsx @@ -2,6 +2,7 @@ import React, { useState, useEffect } from "react"; import { Product } from "../lib/data/products"; import { useCartStore } from "../lib/store/cartStore"; +import { useUserStore } from "../lib/store/userStore"; import { productService } from "../lib/services/productService"; import { motion, AnimatePresence } from "motion/react"; import { @@ -12,9 +13,12 @@ import { FileText, Package, CheckCircle2, + Lock, + Percent, X } from "lucide-react"; import SafeImage from "./SafeImage"; +import { toPersian } from "../lib/utils"; interface QuickOrderItem { product: Product; @@ -26,8 +30,11 @@ export default function B2BPortal({ onClose }: { onClose: () => void }) { const [quantities, setQuantities] = useState>({}); const [searchQuery, setSearchQuery] = useState(""); const { addItem } = useCartStore(); + const { role } = useUserStore(); const [showSuccess, setShowSuccess] = useState(false); + const isWholesaleVerified = (role as string) === "User_Wholesale" || (role as string) === "ADMIN" || (role as string) === "User_Partner"; + useEffect(() => { productService.getProducts({ limit: 999 }).then(res => setProducts(res.data)); }, []); @@ -57,6 +64,16 @@ export default function B2BPortal({ onClose }: { onClose: () => void }) { }; const totalItems = Object.values(quantities).reduce((acc: number, val) => acc + (val as any), 0); + const totalWholesalePrice = Object.entries(quantities).reduce((sum, [id, qty]) => { + const numQty = qty as number; + const prod = products.find(p => p.id === id); + if (prod && numQty > 0) { + const basePrice = prod.priceValue || 0; + const wholesalePrice = basePrice * 0.7; // 30% discount for wholesale + return sum + (wholesalePrice * numQty); + } + return sum; + }, 0); return ( void }) { تصویر نام و کد کالا - وضعیت موجودی + قیمت تک‌فروشی + قیمت عمده (همکار) تعداد سفارش - {filteredProducts.map(product => ( - - - - - -
{product.name}
-
شناسه کالا: {product.artNo}
- - - - - آماده ارسال - - - - handleQuantityChange(product.id, e.target.value)} - placeholder="0" - className="w-20 bg-medical-gray-50 border border-medical-gray-200 rounded-xl py-2 px-3 text-center font-mono font-bold focus:ring-2 focus:ring-canina-blue/20 outline-none" - /> - - - ))} + {filteredProducts.map(product => { + const basePrice = product.priceValue || 0; + const wholesalePrice = basePrice * 0.7; // 30% discount + return ( + + + + + +
{product.name}
+
شناسه کالا: {product.artNo}
+ + + {toPersian(basePrice.toLocaleString())} تومان + + + {isWholesaleVerified ? ( + + + {toPersian(wholesalePrice.toLocaleString())} تومان + + ) : ( + + + نیازمند تایید ادمین + + )} + + + handleQuantityChange(product.id, e.target.value)} + placeholder="0" + className="w-20 bg-medical-gray-50 border border-medical-gray-200 rounded-xl py-2 px-3 text-center font-mono font-bold focus:ring-2 focus:ring-canina-blue/20 outline-none" + /> + + + ); + })}