diff --git a/migrations/0007_regional_pricing.sql b/migrations/0007_regional_pricing.sql new file mode 100644 index 0000000..612f2e6 --- /dev/null +++ b/migrations/0007_regional_pricing.sql @@ -0,0 +1,74 @@ +-- Расширение регионального прайса: UAH/BYN/VND/UZS — по аналогии с уже +-- заведёнными USD/RUB/CNY/TRY/IRR (см. 0001_init.sql). Валюты выбраны по +-- уже сделанным в этой сессии локалям (uk/be/vi/uz). +-- +-- Курс и скидка (~45% от чистой рыночной конвертации, тот же порядок, что +-- уже неявно заложен в RUB/CNY/TRY) — ПРИКИДКА для старта, не сверено с +-- реальными локальными конкурентами по каждому рынку. Легко поправить — +-- это просто UPDATE по этой же таблице, менять код не нужно. +-- +-- VND/UZS — целыми единицами (без копеек/копий), та же логика, что уже у +-- IRR: у донга и сума нет ходовой разменной монеты, дробные суммы не имеют +-- смысла для конечного пользователя. +INSERT INTO plan_prices (plan_name, currency, amount) VALUES + -- ================================================================= + -- УКРАИНА (UAH) + -- ================================================================= + ('GHOST_1M', 'UAH', 11900), -- 119.00 ₴ + ('GHOST_6M', 'UAH', 59900), -- 599.00 ₴ + ('GHOST_12M', 'UAH', 89900), -- 899.00 ₴ + + ('NETRUNNER_1M', 'UAH', 21900), -- 219.00 ₴ + ('NETRUNNER_6M', 'UAH', 109900), -- 1 099.00 ₴ + ('NETRUNNER_12M', 'UAH', 149900), -- 1 499.00 ₴ + + ('MAINFRAME_1M', 'UAH', 49900), -- 499.00 ₴ + ('MAINFRAME_6M', 'UAH', 229900), -- 2 299.00 ₴ + ('MAINFRAME_12M', 'UAH', 349900), -- 3 499.00 ₴ + + -- ================================================================= + -- БЕЛАРУСЬ (BYN) + -- ================================================================= + ('GHOST_1M', 'BYN', 900), -- 9.00 Br + ('GHOST_6M', 'BYN', 4400), -- 44.00 Br + ('GHOST_12M', 'BYN', 6500), -- 65.00 Br + + ('NETRUNNER_1M', 'BYN', 1650), -- 16.50 Br + ('NETRUNNER_6M', 'BYN', 8200), -- 82.00 Br + ('NETRUNNER_12M', 'BYN', 10900), -- 109.00 Br + + ('MAINFRAME_1M', 'BYN', 3600), -- 36.00 Br + ('MAINFRAME_6M', 'BYN', 17500), -- 175.00 Br + ('MAINFRAME_12M', 'BYN', 26000), -- 260.00 Br + + -- ================================================================= + -- ВЬЕТНАМ (VND) — целыми донгами, без копеек (см. заголовок) + -- ================================================================= + ('GHOST_1M', 'VND', 69000), -- 69 000 ₫ + ('GHOST_6M', 'VND', 329000), -- 329 000 ₫ + ('GHOST_12M', 'VND', 499000), -- 499 000 ₫ + + ('NETRUNNER_1M', 'VND', 125000), -- 125 000 ₫ + ('NETRUNNER_6M', 'VND', 619000), -- 619 000 ₫ + ('NETRUNNER_12M', 'VND', 829000), -- 829 000 ₫ + + ('MAINFRAME_1M', 'VND', 279000), -- 279 000 ₫ + ('MAINFRAME_6M', 'VND', 1329000), -- 1 329 000 ₫ + ('MAINFRAME_12M', 'VND', 1999000), -- 1 999 000 ₫ + + -- ================================================================= + -- УЗБЕКИСТАН (UZS) — целыми сумами, без копеек (см. заголовок) + -- ================================================================= + ('GHOST_1M', 'UZS', 35000), -- 35 000 сум + ('GHOST_6M', 'UZS', 169000), -- 169 000 сум + ('GHOST_12M', 'UZS', 249000), -- 249 000 сум + + ('NETRUNNER_1M', 'UZS', 63000), -- 63 000 сум + ('NETRUNNER_6M', 'UZS', 319000), -- 319 000 сум + ('NETRUNNER_12M', 'UZS', 419000), -- 419 000 сум + + ('MAINFRAME_1M', 'UZS', 139000), -- 139 000 сум + ('MAINFRAME_6M', 'UZS', 669000), -- 669 000 сум + ('MAINFRAME_12M', 'UZS', 999000) -- 999 000 сум +ON CONFLICT (plan_name, currency) DO UPDATE +SET amount = EXCLUDED.amount; diff --git a/src/db/repository.rs b/src/db/repository.rs index 6d60857..71d28bb 100644 --- a/src/db/repository.rs +++ b/src/db/repository.rs @@ -124,6 +124,15 @@ pub trait AppRepository: Send + Sync { /// `0001_init.sql`), а не потому что CryptoBot требует именно её. async fn list_active_plans_usd(&self) -> Result, sqlx::Error>; + /// Обобщённая версия `list_active_plans_usd` — тарифы в произвольной + /// валюте (см. `modules::geoip` — валюта определяется по IP/языку). + /// Пустой Vec, если для этой валюты нет ни одной активной строки в + /// `plan_prices` (вызывающая сторона должна фолбэкнуться на USD). + async fn list_active_plans_by_currency( + &self, + currency: &str, + ) -> Result, sqlx::Error>; + async fn create_invoice( &self, user_id: Uuid, @@ -728,6 +737,22 @@ impl AppRepository for PgRepository { .await } + #[instrument(skip(self))] + async fn list_active_plans_by_currency( + &self, + currency: &str, + ) -> Result, sqlx::Error> { + sqlx::query_as( + "SELECT pp.plan_name, pp.amount FROM plan_prices pp \ + JOIN plans p ON p.name = pp.plan_name \ + WHERE pp.currency = $1 AND pp.is_active = TRUE AND p.is_active = TRUE \ + ORDER BY pp.amount ASC", + ) + .bind(currency) + .fetch_all(&self.pool) + .await + } + #[instrument(skip(self))] async fn create_invoice( &self,