Files
docs/business/BUSINESS-03-ECOMMERCE-STORES.md
T
masoodafar-web b861b66cda docs: fix Regular Store payment — wallet-only, no IPG/ZarinPal
- Regular Store: Balance deduction only (SubmitShopBuyOrderCommandHandler)
  NO ZarinPal redirect, NO payment gateway
- Discount Store: DiscountBalance + ZarinPal IPG for remainder
  Added gatewayAmount=0 edge case (discount covers 100%)
- VAT: Both stores use 9% (ShopVAT=0.1 is stale/unused constant)
- Added ZarinPal usage scope note (only: Discount Store, Wallet Top-up, Package Purchase)
- Fixed BUSINESS-02: sections 2, 5.2, 5.3, 7
- Fixed BUSINESS-03: store comparison chart
- Fixed OVERVIEW-01: user journey + both store flowcharts
- Fixed OVERVIEW-03: timeline entry
2026-02-18 23:52:35 +03:30

7.0 KiB
Raw Blame History

🛒 فروشگاه، موجودی و محصولات

منابع ادغام‌شده: discount-shop-business.md, DISCOUNT-STORE-STATUS.md, package-purchase-system.md, INVENTORY-IMPROVEMENTS.md, INVENTORY-REFACTORING-STATUS.md, PRODUCT-BUNDLE-FEATURE.md, SHOP-UNIFICATION.md
آخرین بروزرسانی: اسفند ۱۴۰۴


۱. دو فروشگاه FourSat

flowchart LR
    subgraph RS["Regular Store — /store"]
        R1["همه کاربران"]
        R2["پرداخت از Balance کیف‌پول"]
        R3["قیمت عادی"]
        R4["VAT = 9%"]
    end

    subgraph DS["Discount Store — /discount-store"]
        D1["فقط اعضای باشگاه"]
        D2["پرداخت ترکیبی تخفیف+نقد"]
        D3["تخفیف بر اساس MaxDiscountPercent"]
        D4["VAT = 9%"]
    end

    subgraph SHARED["مشترک"]
        S1["Products"]
        S2["Categories"]
        S3["Inventory"]
        S4["ProductImages 1:1"]
    end

    RS --> SHARED
    DS --> SHARED

۲. Lazy Loading محصولات

۲.۱ API

// ProductService.cs
public record ProductListResult(List<ProductDto> Products, int TotalCount);

public async Task<ProductListResult> GetProductsPagedAsync(
    int skip, int take, 
    Guid? categoryId = null, 
    string? search = null)
{
    var request = new GetProductsRequest {
        Pagination = new PaginationState { Skip = skip, Take = take },
        CategoryId = categoryId?.ToString() ?? "",
        SearchTerm = search ?? ""
    };
    // gRPC call...
}

۲.۲ پیاده‌سازی UI (هر دو فروشگاه)

flowchart TD
    A["بارگذاری اولیه: 12 محصول"] --> B["اسکرول → نمایش دکمه\nنمایش محصولات بیشتر"]
    B --> C["کلیک → LoadMore\nskip += 12"]
    C --> D["محصولات جدید append به لیست"]
    D --> E{"Products.Count >= TotalCount?"}
    E -->|خیر| B
    E -->|بله| F["مخفی‌شدن دکمه"]

۳. مدیریت موجودی (Inventory)

۳.۱ بهبودهای اخیر

بهبود توضیح وضعیت
Auto-Create ایجاد خودکار رکورد موجودی هنگام ساخت محصول
Hangfire Worker InventorySyncJob — بررسی دوره‌ای و ایجاد رکوردهای گمشده
Autocomplete جستجوی محصول در صفحه موجودی BackOffice با autocomplete
Lazy Load بارگذاری تنبل محصولات در هر دو فروشگاه

۳.۲ Entity ها

public class Inventory {
    public Guid Id { get; set; }
    public Guid ProductId { get; set; }         // FK → Product
    public int Quantity { get; set; }            // موجودی فعلی
    public int ReservedQuantity { get; set; }    // رزرو‌شده
    public int MinimumStock { get; set; }        // حداقل موجودی (هشدار)
    public bool TrackInventory { get; set; }     // آیا موجودی رصد شود؟
}

// فیلد کلیدی در Product:
public int MaxDiscountPercent { get; set; }  // 0 تا 100 — درصد تخفیف در فروشگاه تخفیفی

۳.۳ فلوی سفارش و موجودی

flowchart TD
    A["سفارش جدید"] --> B{"Quantity - Reserved >= OrderQty?"}
    B -->|بله| C["Reserved += OrderQty"]
    C --> D{"پرداخت موفق؟"}
    D -->|موفق| E["✅ Quantity -= OrderQty\nReserved -= OrderQty"]
    D -->|ناموفق| F["❌ Reserved -= OrderQty\nآزادسازی"]
    B -->|خیر| G["نمایش: موجودی کافی نیست"]

۴. تصاویر محصول (۱:۱ مربعی)

AppImage Component (Shared):
    • ObjectFit = Cover
    • AspectRatio = 1:1 (مربع)
    • Fallback = آیکون پیش‌فرض MudBlazor
    • LazyLoading = true
    
اعمال در:
    ✅ Regular Store — ProductCard
    ✅ Discount Store — ProductCard
    ✅ BackOffice — Product List
    ✅ Product Detail Pages

۵. باندل محصولات (Product Bundle)

⚠️ وضعیت: طراحی کامل — پیاده‌سازی نشده

۵.۱ مدل داده

public class ProductBundle {
    public Guid Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public decimal OriginalPrice { get; set; }    // مجموع قیمت تکی
    public decimal BundlePrice { get; set; }       // قیمت باندل
    public decimal DiscountPercentage { get; set; }
    public bool IsActive { get; set; }
    public List<BundleItem> Items { get; set; }
}

public class BundleItem {
    public Guid ProductId { get; set; }
    public int Quantity { get; set; }
}

۵.۲ فلو

flowchart TD
    A["ادمین → ساخت باندل\nانتخاب محصولات + تعیین قیمت"] --> B["نمایش در فروشگاه\nبا تگ باندل"]
    B --> C["خرید → تمام محصولات\nیکجا به سبد"]
    C --> D["پرداخت → کسر موجودی\nهر محصول جداگانه"]

۶. یکپارچه‌سازی فروشگاه‌ها (Shop Unification)

۶.۱ اجزای مشترک

کامپوننت کاربرد وضعیت
ProductCard کارت محصول (۱:۱) مشترک
AppImage نمایش تصویر مشترک
CategoryFilter فیلتر دسته‌بندی مشترک
SearchBar جستجوی محصول مشترک
LoadMoreButton Lazy loading مشترک
CartSummary خلاصه سبد جداگانه

۶.۲ مسیرهای Navigation

فروشگاه عادی:
  /store                    → لیست محصولات
  /store/product/{id}       → جزئیات محصول
  /store/cart               → سبد خرید
  /store/checkout            → پرداخت

فروشگاه تخفیفی:
  /discount-store            → لیست محصولات
  /discount-store/product/{id} → جزئیات
  /discount-store/cart        → سبد (ترکیبی)
  /discount-store/checkout    → پرداخت ترکیبی

۷. دسته‌بندی‌ها (Categories)

graph TD
    ROOT["دسته‌بندی‌ها"] --> A["سلامت و زیبایی"]
    ROOT --> B["تغذیه"]
    ROOT --> C["ورزشی"]

    A --> A1["مکمل‌ها"]
    A --> A2["مراقبت پوست"]
    A --> A3["مراقبت مو"]

    B --> B1["ارگانیک"]
    B --> B2["رژیمی"]

مدل: Category (Id, Name, ParentId?, ImageUrl, IsActive, SortOrder)


۸. خلاصه وضعیت

ماژول وضعیت درصد
فروشگاه عادی کامل 100%
فروشگاه تخفیفی کامل 100%
Lazy Loading کامل 100%
موجودی خودکار کامل 100%
تصاویر مربعی کامل 100%
باندل محصولات طراحی 30%
مقایسه محصول ایده 0%