feat: implement rewards module with referral/coupon systems, update tariff seeding, and add trip distance service for improved billing accuracy.

This commit is contained in:
Hamza-Ayed
2026-07-19 00:20:37 +03:00
parent 22d18f32fe
commit 92f1eeb48c
39 changed files with 3612 additions and 208 deletions
@@ -0,0 +1,60 @@
import { writeFileSync } from 'fs';
import { join } from 'path';
import {
buildDefinition,
COUNTRY_TARIFFS,
SERVICE_CLASSES,
} from '../../modules/tariff/default-tariffs';
/**
* يولّد `tariffs.sql` لتطبيقها على قاعدة **قائمة** — للمستأجرين الموجودين
* قبل أن يصير الزرع تلقائياً.
*
* التشغيل: `npx ts-node src/database/seeds/generate-tariff-sql.ts`
*
* مستأجر جديد لا يحتاج هذا الملف إطلاقاً: `SeedService` يزرع له التعرفة من
* **نفس** `default-tariffs.ts` عند الإقلاع. هذا المولّد للحاق بالقائم فقط،
* ولذلك يقرأ من مصدر الحقيقة نفسه — نسختان من أرقام التسعير كانتا ستتباعدان.
*
* الناتج **آمن للتكرار**: كل تشغيل يطفئ الفعّالة ويُدرج `max(version)+1`،
* فلا يبقى صفّان فعّالان لنفس (مستأجر، مدينة، فئة) — و`getActive` ترتّب
* `version DESC` فكان الاختيار بينهما غير محدَّد.
*/
function generateSql(): string {
let sql = `-- Tripz — تعرفة الانطلاق الافتراضية لكل بلد.\n`;
sql += `-- مولَّد من src/database/seeds/generate-tariff-sql.ts — لا يُحرَّر يدوياً.\n`;
sql += `-- المصدر: src/modules/tariff/default-tariffs.ts\n`;
sql += `-- آمن للتكرار: كل تشغيل يطفئ الفعّالة ويُدرج نسخة أعلى.\n\n`;
sql += `BEGIN;\n\n`;
for (const country of COUNTRY_TARIFFS) {
sql += `-- ============ ${country.countryPack.toUpperCase()} (${country.currency}) ============\n`;
for (const serviceClass of Object.values(SERVICE_CLASSES)) {
const definition = buildDefinition(country, serviceClass);
const defJson = JSON.stringify(definition).replace(/'/g, "''");
// يطال **كل** مستأجر في هذا البلد لا سيرو وحده: تعرفة الانطلاق عامة،
// وربطها بمستأجر واحد كان يترك كل مستأجر آخر بلا تسعير.
sql += `-- ${serviceClass}\n`;
sql += `UPDATE tripz_tariffs SET active = false\n`;
sql += ` WHERE city = 'default' AND service_class = '${serviceClass}' AND active = true\n`;
sql += ` AND tenant_id IN (SELECT id FROM tripz_tenants WHERE country_pack = '${country.countryPack}');\n`;
sql += `INSERT INTO tripz_tariffs (id, tenant_id, city, service_class, version, active, definition)\n`;
sql += `SELECT uuid_generate_v4(), t.id, 'default', '${serviceClass}',\n`;
sql += ` COALESCE((SELECT MAX(version) FROM tripz_tariffs x\n`;
sql += ` WHERE x.tenant_id = t.id AND x.city = 'default'\n`;
sql += ` AND x.service_class = '${serviceClass}'), 0) + 1,\n`;
sql += ` true, '${defJson}'::jsonb\n`;
sql += ` FROM tripz_tenants t WHERE t.country_pack = '${country.countryPack}';\n\n`;
}
}
sql += `COMMIT;\n`;
return sql;
}
const out = join(__dirname, 'tariffs.sql');
writeFileSync(out, generateSql());
// eslint-disable-next-line no-console
console.log(`✅ generated ${out}`);