feat: المجموعة J — الرصيد التشغيلي + تصحيح نموذج العمولة (B3/B6)
فلسفة العمولة الصحيحة (docs/18): السائق يقبض أجرة الراكب **كاملة**،
والعمولة تُخصم من رصيد تشغيلي مدفوع سلفاً. ما بُني في f3fdc1b كان نموذج
أوبر (اقتطاع من الأرباح) — عكس المطلوب.
- J1: driver_credits + credit_txns. خصم ذرّي كنمط I1 لكن **بلا شرط رصيد**
ولا قيد >= 0: الدين مسموح عمداً (قرار المالك: الرحلة لا تُقطع أبداً)
- J2: خصم العمولة عند completed لا paid — الرحلة تمّت فالعمولة استُحقّت.
قاعدة واحدة للكاش والمحفظة (§5.5): لا تفريع حسب وسيلة الدفع
- J3: price_for_driver = price_for_passenger. TariffEngine.split →
commission، وبلا سقف بالأجرة لأن الخصم على رصيد منفصل يجوز أن يسلب
- J4: الحجب عند تجاوز credit_floor فقط، عند setOnline و accept — لا أثناء
رحلة. الحجب يمنع الاتصال أصلاً وإلا عُرضت رحلات يُرفض قبولها
- J6: مكافأة التسجيل عند الاعتماد (3 JOD / 300 SYP جديدة / 300 EGP).
حارسان: فحص تطبيقي للحالة الشائعة + فهرس فريد جزئي للسباق
- J7: credit_floor لكل عملة
- J8: GET /credit + /credit/transactions
تصحيح B3: مشوار الوصول تعويضُ إلغاء بعد انقضاء الانتظار المجاني — لا بند
في كل أجرة. أُزيل مفتاح pickup_leg.charge.
هجرة: DriverCredit.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
2edd8f6916
commit
d9b0faab2d
@@ -0,0 +1,42 @@
|
||||
import { Controller, ForbiddenException, Get, UseGuards } from '@nestjs/common';
|
||||
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
|
||||
import { DriverCreditService, CREDIT_FLOOR } from './driver-credit.service';
|
||||
import { DriversService } from '../drivers/drivers.service';
|
||||
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
|
||||
import { CurrentUser, AuthUser } from '../auth/decorators/current-user.decorator';
|
||||
|
||||
@ApiTags('credit')
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Controller('credit')
|
||||
export class CreditController {
|
||||
constructor(
|
||||
private readonly credit: DriverCreditService,
|
||||
private readonly drivers: DriversService,
|
||||
) {}
|
||||
|
||||
/** رصيدي التشغيلي — يعرضه تطبيق السائق (docs/18 — J8). */
|
||||
@Get()
|
||||
async mine(@CurrentUser() user: AuthUser) {
|
||||
const driver = await this.drivers.findByUser(user.tenantId, user.userId);
|
||||
if (!driver) throw new ForbiddenException('Not a driver');
|
||||
|
||||
const c = await this.credit.get(user.tenantId, driver.id);
|
||||
const floor = CREDIT_FLOOR[c.currency] ?? 0;
|
||||
const balance = Number(c.balance);
|
||||
return {
|
||||
balance,
|
||||
currency: c.currency,
|
||||
floor,
|
||||
inDebt: balance < 0,
|
||||
blocked: balance < floor,
|
||||
};
|
||||
}
|
||||
|
||||
@Get('transactions')
|
||||
async history(@CurrentUser() user: AuthUser) {
|
||||
const driver = await this.drivers.findByUser(user.tenantId, user.userId);
|
||||
if (!driver) throw new ForbiddenException('Not a driver');
|
||||
return this.credit.history(user.tenantId, driver.id);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user