## الأرقام صارت من جدول `kazan` الحيّ لا من تقدير العمولة 11٪/12٪/14٪ مطابقة حرفياً. وثلاثة تصحيحات على الخام: - **محورا الأردن مقلوبان**: أعمدة الفئات تحمل سعر الدقيقة (0.043) وأعمدة النوافذ سعر الكيلومتر (0.184) — عكس مصر وسوريا. قراءتها كما هي تجعل رحلة 27 كم بأقلّ من دينارين. - **نِسَب الفئات في مصر وسوريا معطوبة**: الكهربائي 0.23 والفان 0.25–0.40 من الاقتصادي، أي فان أرخص من اقتصادي. نِسَب الأردن وحدها متماسكة فاعتُمدت. - سعر الكيلو في مصر 4 جنيهات لا 3.5 (قرار المالك). ## البنية صارت مطابقة لسيرو — وهي ما سيكتب فيه بوت استخبارات الأسعار سعر الكيلو يتغيّر بالفئة فقط (رقم يعرفه السوق)، وسعر الدقيقة بالنافذة فقط. **لا فتحة عدّاد** (`startPrice = 0` في كل صفوف سيرو): الحدّ الأدنى أرضية لا رسم يُضاف — «ما في رحلة أقل من 20 جنيهاً». `fuelPrice` محفوظ كمدخل للبوت. ## تسريبان أغلقهما الاختبار الحيّ (بموافقة المالك) 1. **فئة مجهولة = رحلة مجانية**: `service_class` يأتي من الطلب بلا تحقّق، والاستثناء كان يُبتلع فتُنشأ رحلة بـ`quoted_fare = null` ثم تُسوّى بصفر. صار الطلب يُرفض بـ400 — الفشل الصريح أأمن من الصامت. 2. **`fixed` لا تُزرع**: سعر ثابت بلا جدول خطوط يعني رقماً واحداً لكل الوجهات — أظهر الاختبار رحلة 55.8 كم بـ2.5 ديناراً مقابل 23.2 للاقتصادي. 300 اختبار خضر. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
61 lines
3.2 KiB
TypeScript
61 lines
3.2 KiB
TypeScript
import { writeFileSync } from 'fs';
|
|
import { join } from 'path';
|
|
import {
|
|
buildDefinition,
|
|
COUNTRY_TARIFFS,
|
|
SEEDED_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 SEEDED_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}`);
|