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>
194 lines
8.8 KiB
Markdown
194 lines
8.8 KiB
Markdown
# اجرت ریالی — راهنمای پورت به نسخهٔ دیگر
|
||
|
||
این سند خلاصهٔ کارهایی است که برای **اجرت ریالی** (`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` (نه خطا).
|