feat: order revision, rial wage from variant, product tags; drop user-app-v2

Admin order edit with category chips and timeline; customer checkout charges variant rialWage; product tags; retire the unused user-app-v2 tree.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
saeed
2026-10-28 14:29:12 +03:30
co-authored by Cursor
parent 4e09a66fbf
commit feb5727c0e
429 changed files with 3942 additions and 30302 deletions
+1 -3
View File
@@ -15,15 +15,13 @@
- `apps/user-app/public/img/brand-logo.png` و `.webp`
- `apps/user-app/src/assets/img/brand-logo.png`
- `apps/user-app-v2/public/img/brand-logo.png` و `.webp`
- `apps/user-app-v2/src/assets/img/brand-logo.png`
- `apps/admin-panel/src/assets/images/logo/brand-icon.png` و `.webp`، `brand-horizontal.png`
- آیکون‌های PWA و favicon: `apps/*/public/icon-192.png`، `icon-512.png`، `favicon.*`
- اسکریپت ساخت همهٔ این‌ها از یک تصویر: [`scripts/generate-brand-icons.py`](../scripts/generate-brand-icons.py) (مسیر تصویر ورودی را در خط اول آن عوض کنید)
### بعد از تغییر
1. `dist` هر سه فرانت و `apps/api/release` را دوباره بسازید (طبق روال انتشار).
1. `dist` هر دو فرانت و `apps/api/release` را دوباره بسازید (طبق روال انتشار).
2. اگر در دیتابیس فعلی برندی به نام قدیمی در «برندهای محصول» هست، از پنل ادمین ویرایشش کنید (seed فقط دیتابیس خالی را پر می‌کند).
## ۲. عمداً عوض نشده‌اند (نام داخلی، دیده نمی‌شوند)
+1 -1
View File
@@ -5,7 +5,7 @@
این سند برای **همین ریپو (gold-bank / هدناگلد)** است تا ایرادها را verify کنیم یا باقی‌مانده‌ها را ببندیم — و در عین حال قالب تکرار برای پروژهٔ مشابه.
> قبل از هر تغییر **UI سمت اپ**: از مالک (Honar) بپرس. منطق/رفتار بدون سوال؛ ظاهر نه.
> اپ مبنا برای منطق: هر دو `apps/user-app` و `apps/user-app-v2` (مگر خلافش گفته شود).
> اپ مبنا برای منطق: `apps/user-app` (مگر خلافش گفته شود). `user-app-v2` از ۲۰۲۶-۱۰-۲۸ حذف شده.
---
+193
View File
@@ -0,0 +1,193 @@
# اجرت ریالی — راهنمای پورت به نسخهٔ دیگر
این سند خلاصهٔ کارهایی است که برای **اجرت ریالی** (`rial_pay` / `rialWage` / `flatRialCharge`) در این ریپو انجام شده، تا بتوان همان رفتار را روی یک branch/نسخهٔ دیگر پیاده کرد.
اجرت ریالی با **اجرت درصدی** (`wagePercent`) فرق دارد: درصد داخل فرمول وزن طلا می‌رود؛ ریالی یک مبلغ ثابت ریال روی تنوع است و جداگانه روی سفارش می‌نشیند.
---
## نگاشت نام‌ها
| لایه | نام | معنی |
|------|-----|------|
| لگاسی / API ادمین و کاتالوگ | `rial_pay` | مبلغ ثابت ریال روی تنوع |
| لگاسی جمع سفارش | `rial_input` | Σ (ریال خط × تعداد) |
| Prisma تنوع | `ProductVariant.rialWage` | همان `rial_pay` |
| Prisma سفارش / آیتم | `Order.flatRialCharge` / `OrderItem.flatRialCharge` | جمع سفارش / مبلغ واحد هر خط |
| لیست ادمین سفارش | `total_price` | alias همان `Order.flatRialCharge` |
---
## جریان انتها‌به‌انتها
```
ادمین در فرم محصول → variant.rial_pay
↓
ProductVariant.rialWage (DB)
↓
کاتالوگ / API محصول → rial_pay
↓
اپ کاربر: نمایش در سبد (اختیاری)
↓
ثبت سفارش:
• مشتری → flatRialCharge = variant.rialWage (از body خوانده نمی‌شود)
• اپراتور پنل → flatRialCharge از body / rial_input
↓
OrderItem.flatRialCharge (واحد) + Order.flatRialCharge = Σ(واحد × qty)
↓
وضعیت تحویل‌شده → Ledger بدهی RIAL = Order.flatRialCharge
```
فرمول وزن طلا (بدون ریال):
```
weight = rash × (1 + (wagePercent − discountPercent) / 100)
```
---
## چک‌لیست پورت (به ترتیب)
### ۱) دیتابیس / Prisma
- [ ] فیلد روی تنوع:
```prisma
/// Legacy rial_pay — fixed Rial making charge per variant.
rialWage Decimal? @db.Decimal(18, 0)
```
- [ ] مایگریشن (نمونه از این ریپو: `apps/api/prisma/migrations/20261025143000_variant_legacy_fields/migration.sql`):
```sql
ALTER TABLE "ProductVariant" ADD COLUMN IF NOT EXISTS "rialWage" DECIMAL(18,0);
```
- [ ] از قبل باید باشند (معمولاً در schema اولیه):
- `Order.flatRialCharge Decimal @default(0) @db.Decimal(20,2)`
- `OrderItem.flatRialCharge Decimal @default(0) @db.Decimal(20,2)`
### ۲) API — نگاشت محصول / کاتالوگ
| فایل | کار |
|------|-----|
| `apps/api/src/modules/admin-products/admin-products.service.ts` | خواندن: `rial_pay: Number(v.rialWage) \| null` — نوشتن: `rialWage` از `v.rial_pay` |
| `apps/api/src/modules/catalog/catalog.service.ts` | روی هر variant کاتالوگ: `rial_pay: v.rialWage != null ? Number(v.rialWage) : null` |
### ۳) API — ثبت سفارش (مهم‌ترین رفتار)
فایل: `apps/api/src/modules/orders/orders.service.ts`
```ts
// مسیر مشتری: فقط از DB (variant.rialWage) — body نادیده گرفته می‌شود
const flatRialCharge = quotes
? new Prisma.Decimal(variant.rialWage ?? 0)
: new Prisma.Decimal(item.flatRialCharge ?? 0);
```
جمع سفارش:
```ts
Order.flatRialCharge = Σ (item.flatRialCharge × quantity)
```
- DTO آیتم (`create-order.dto.ts`): `flatRialCharge?: number` اختیاری است.
- مسیر اپراتور ادمین (`admin-orders.service` create): `rial_input` → `flatRialCharge`.
- تست‌ها در `orders.service.spec.ts` باید با همین قانون هم‌خوان باشند (تمپر کلاینت روی ریال بی‌اثر بماند).
> **توجه تاریخی:** قبلاً (MON-08) مسیر مشتری عمداً `flatRialCharge = 0` بود. نسخهٔ فعلی از `variant.rialWage` شارژ می‌کند. روی نسخهٔ مقصد همین تصمیم را صریح نگه دارید.
### ۴) API — ویرایش سفارش (اگر آن نسخه revision دارد)
فایل: `apps/api/src/modules/orders/order-revision.service.ts`
- پیش‌فرض خط: `flatRialCharge ?? variant.rialWage ?? 0`
- جمع revision مثل create از Σ واحد × qty
### ۵) لجر / حسابداری / گزارش
| فایل | کار |
|------|-----|
| ledger (بدهی ریال هنگام تحویل) | `Order.flatRialCharge` |
| `accounting-sync.service.ts` | `flatRial: item.flatRialCharge × qty` |
| `admin-report.service.ts` | ستون اکسل «اجرت ریالی» از `item.flatRialCharge` |
### ۶) ادمین پنل — فرم محصول
فایل: `apps/admin-panel/src/views/apps/product/AddProduct.vue`
- ستون جدول تنوع: «اجرت ریالی» ← `rial_pay`
- مودال تنوع: فیلد «اجرت ریالی» (`a-input-number`) ← `variantForm.rial_pay`
- در save/load: `rial_pay` را با API رد و بدل کنید
### ۷) ادمین پنل — جزئیات / ویرایش سفارش
فایل: `apps/admin-panel/src/views/order/OrderDetailBody.vue` (+ `List.vue` / `OmdeList.vue`)
- نمایش chip وقتی `flatRialCharge > 0`
- در حالت ویرایش: `a-input-number` روی `item.flatRialCharge`
- هنگام افزودن خط از تنوع: seed با `row.rial_pay`
- payload پیشنهاد ویرایش باید `flatRialCharge` هر خط را بفرستد
### ۸) اپ کاربر
| فایل | کار |
|------|-----|
| `user-app/src/api/client.ts` | `ProductVariantSummary.rial_pay`؛ سفارش‌ها `flatRialCharge` |
| `CartItem.vue` | اگر `rial_pay > 0` → «اجرت ریالی … ریال» |
| `cartStore.ts` | `totalRial()` = Σ `rial_pay × qty` (پیش‌نمایش) |
| `OrderCard.vue` / `OrderItemCard.vue` | نمایش `flatRialCharge` وقتی > 0 |
| `CartView.vue` | معمولاً `flatRialCharge` را **نمی‌فرستد**؛ سرور از `rialWage` پر می‌کند |
### ۹) ایمپورت لگاسی (اختیاری ولی توصیه می‌شود)
- تنوع: `rial_pay` → `ProductVariant.rialWage`
- خط سفارش: `rial_pay` → `OrderItem.flatRialCharge`
- هدر سفارش: `rial_input` → `Order.flatRialCharge`
اگر اسکریپت ایمپورت هنوز می‌گوید «فیلد مقصد ندارد»، بعد از افزودن `rialWage` باید به‌روز شود.
---
## فایل‌های کلیدی این ریپو (مرجع کپی)
```
apps/api/prisma/schema.prisma # rialWage + flatRialCharge
apps/api/prisma/migrations/20261025143000_variant_legacy_fields/migration.sql
apps/api/src/modules/admin-products/admin-products.service.ts
apps/api/src/modules/catalog/catalog.service.ts
apps/api/src/modules/orders/orders.service.ts
apps/api/src/modules/orders/orders.service.spec.ts
apps/api/src/modules/orders/order-revision.service.ts # اگر ویرایش سفارش دارید
apps/api/src/modules/admin-orders/admin-orders.service.ts
apps/admin-panel/src/views/apps/product/AddProduct.vue
apps/admin-panel/src/views/order/OrderDetailBody.vue
apps/user-app/src/components/product/CartItem.vue
apps/user-app/src/stores/cartStore.ts
apps/user-app/src/components/product/OrderCard.vue
apps/user-app/src/components/product/OrderItemCard.vue
apps/user-app/src/api/client.ts
```
کامیت مرجع فیلد تنوع: `55d2715` — `feat(products): port missing variant fields from henza…`
شارژ مسیر مشتری از `rialWage` و UI سبد/سفارش ممکن است روی working tree باشد؛ هنگام پورت از وضعیت فعلی این فایل‌ها کپی بگیرید، نه فقط از آن کامیت.
---
## تست دستی سریع بعد از پورت
1. در ادمین روی یک تنوع «اجرت ریالی» مثلاً `500000` بگذارید و ذخیره کنید.
2. کاتالوگ / جزئیات محصول در اپ همان عدد را به‌صورت `rial_pay` بدهد.
3. سبد: اگر UI پورت شده، خط «اجرت ریالی» دیده شود.
4. ثبت سفارش از اپ: `OrderItem.flatRialCharge` و جمع `Order.flatRialCharge` برابر مقدار تنوع × تعداد باشد — حتی اگر کلاینت عدد دیگری فرستاده باشد.
5. ثبت/ویرایش از پنل ادمین: عدد وارد‌شدهٔ اپراتور حفظ شود.
6. بعد از وضعیت تحویل: بدهی ریال لجر با جمع سفارش هم‌خوان باشد.
---
## چیزهایی که عمداً تغییر نمی‌کنند
- فرمول وزن/اجرت درصدی (`wage-formula.ts`) ریال را داخل وزن حساب نمی‌کند.
- نام API بیرونی برای تنوع همان `rial_pay` می‌ماند؛ فقط ستون DB `rialWage` است.
- بدون مقدار روی تنوع → شارژ `0` (نه خطا).
+3
View File
@@ -3,6 +3,9 @@
**CONFIRMED by the user at the Phase 0 gate (2026-09-21).**
Rulings are recorded in `DECISIONS.md` (D0–D12).
> **2026-10-28 — `apps/user-app-v2` removed by owner.** Sections that still
> name v2 below are historical; the only customer app is `apps/user-app`.
Items here are intentional changes in `gold-banking-monorepo`. Per `CLAUDE.md` §4
they must **not** be removed, restyled, restructured, or have their behaviour
changed. You may only **ADD** what the reference has and they lack, in a way that