Реалізація мультивалютності на сайті: ціни, оплата, звітність

Погано реалізована мультивалютність породжує розбіжності в бухгалтерії, баги з округленням і проблеми з ПДВ. Великий інтернет-магазин втратив значну суму через те, що ціни округлювалися вниз на користь покупця. Наш досвід дозволяє уникнути цих помилок і гарантує точність фінансових даних. Понад 5 ро

Розробка та обслуговування будь-яких видів сайтів:

Інформаційні сайти або веб-програми
Сайти візитки, landing page, корпоративні сайти, онлайн каталоги, квіз, промо-сайти, блоги, ресурси новин, інформаційні портали, форуми, агрегатори
Сайти або веб-програми електронної комерції
Інтернет-магазини, B2B-портали, маркетплейси, онлайн-обмінники, кешбек-сайти, біржі, дропшиппінг-платформи, парсери товарів
Веб-програми для управління бізнес-процесами
CRM-системи, ERP-системи, корпоративні портали, системи управління виробництвом, парсери інформації
Сайти або веб-програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, конструктори сайтів, портали надання електронних послуг, відеохостинги, тематичні портали

Це лише деякі з технічних типів сайтів, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Послуги, які ми пропонуємо
Показано 1 з 1Усі 2062 послуг
Реалізація мультивалютності на сайті: ціни, оплата, звітність
Середній
~3-5 днів

Наші компетенції:

Часті запитання

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1422
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1287
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    984
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1249
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    986
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Розробка веб-сайту для компанії ФІКСПЕР
    999

Погано реалізована мультивалютність породжує розбіжності в бухгалтерії, баги з округленням і проблеми з ПДВ. Великий інтернет-магазин втратив значну суму через те, що ціни округлювалися вниз на користь покупця. Наш досвід дозволяє уникнути цих помилок і гарантує точність фінансових даних. Понад 5 років ми впроваджуємо мультивалютність на сайтах різного масштабу — від стартапів до enterprise-рішень з 30+ валютами. У цій статті розберемо ключові технічні рішення: схеми зберігання цін, автооновлення курсів, форматування та мультивалютні платежі.

Чому мультивалютність — це не просто перемикач валют?

Мультивалютність — комплексна задача, що зачіпає базу даних, бізнес-логіку та платіжні шлюзи. Помилки на будь-якому етапі призводять до фінансових втрат. Розглянемо два основні підходи до зберігання цін.

Як ми зберігаємо ціни?

Є два принципово різних підходи. Перший — базова валюта з конвертацією на льоту: всі ціни зберігаються в одній валюті, при відображенні множаться на актуальний курс. Простий у реалізації, але курс змінюється — покупець бачить різні ціни при кожному візиті. Підходить для B2B та інформаційних сайтів.

Другий — явні ціни в кожній валюті: в базі зберігається ціна окремо для кожної валюти. Менеджер керує цінами вручну або за допомогою автооновлення за курсом. Покупець бачить фіксовану «красиву» ціну (999 грн, а не 997,34). Це оптимально для роздробу.

Явні ціни кращі за конвертацію на льоту в 3 рази за стабільністю для покупця — ціна не змінюється від візиту до візиту.

Характеристика Базова валюта + конвертація Явні ціни в кожній валюті
Складність реалізації Низька Середня
Стабільність цін для покупця Низька (коливається з курсом) Висока (фіксовані)
Підходить для B2B, вітрини e-commerce, роздріб
Управління цінами Автоматичне Ручне / напівавтомат
CREATE TABLE currencies ( code CHAR(3) PRIMARY KEY, -- ISO 4217: UAH, USD, EUR, BYN name VARCHAR(100) NOT NULL, symbol VARCHAR(10) NOT NULL, symbol_pos VARCHAR(10) NOT NULL DEFAULT 'after', decimals SMALLINT NOT NULL DEFAULT 2, is_active BOOLEAN NOT NULL DEFAULT true, is_default BOOLEAN NOT NULL DEFAULT false, rate_to_base NUMERIC(15,6) NOT NULL DEFAULT 1.0 ); CREATE TABLE product_prices ( id BIGSERIAL PRIMARY KEY, variant_id BIGINT NOT NULL REFERENCES product_variants(id), currency CHAR(3) NOT NULL REFERENCES currencies(code), price NUMERIC(12,2) NOT NULL, compare_at NUMERIC(12,2), updated_at TIMESTAMP NOT NULL DEFAULT NOW(), UNIQUE (variant_id, currency) ); 

Коди валют стандартизовані за ISO 4217.

Як оновлюються курси?

Курси оновлюються за розкладом з публічних джерел. ЦБ РФ публікує XML за адресою https://www.cbr.ru/scripts/XML_daily.asp, НБРБ — JSON API https://api.nbrb.by/exrates/rates?periodicity=0. Підтримуються й інші провайдери.

class ExchangeRateUpdater { private array $providers = [ CbrExchangeRateProvider::class, NbrbExchangeRateProvider::class, EcbExchangeRateProvider::class, ]; public function update(): void { foreach ($this->providers as $providerClass) { $provider = app($providerClass); $rates = $provider->fetchRates(); foreach ($rates as $code => $rate) { Currency::where('code', $code)->update([ 'rate_to_base' => $rate, ]); } } Cache::tags(['currencies'])->flush(); } } 

Автооновлення курсів не означає автоперерахунок цін у product_prices. Це окремий крок — або ручний (менеджер натискає «Перерахувати за курсом»), або автоматичний з порогом відхилення (перераховувати тільки якщо курс змінився більш ніж на 2%).

Як користувач обирає валюту?

Вибір валюти реалізовано через перемикач у шапці сайту. Для гостей вибір зберігається в cookie preferred_currency (термін 90 днів), для авторизованих — у users.preferred_currency. Middleware визначає поточну валюту при кожному запиті:

class ResolveCurrency { public function handle(Request $request, Closure $next): Response { $currency = $this->detectCurrency($request); app()->instance('current_currency', Currency::find($currency)); $request->merge(['currency' => $currency]); return $next($request); } private function detectCurrency(Request $request): string { // 1. Явний параметр у запиті if ($request->has('currency') && $this->isValid($request->currency)) { $this->persistChoice($request, $request->currency); return $request->currency; } // 2. Збережений вибір користувача if ($request->user()?->preferred_currency) { return $request->user()->preferred_currency; } // 3. Cookie if ($cookie = $request->cookie('preferred_currency')) { return $cookie; } // 4. GeoIP (якщо включено) return $this->geoipCurrency->detect($request->ip()) ?? config('shop.default_currency', 'UAH'); } } 

Як форматувати ціни?

Форматування — нетривіальна задача: валюти мають різні роздільники та позицію символу. Ми використовуємо гнучкий клас PriceFormatter:

class PriceFormatter { public function format(float $amount, Currency $currency): string { $formatted = number_format( $amount, $currency->decimals, ',', ' ' ); return match($currency->symbol_pos) { 'before' => $currency->symbol . $formatted, 'after' => $formatted . ' ' . $currency->symbol, }; } } 

Як реалізовані мультивалютні платежі?

Платіжний шлюз має підтримувати мультивалютність. Stripe — оптимальний вибір: приймає платіж у будь-якій валюті, конвертує на стороні процесора. ЮKassa працює лише в рублях, потребує конвертації на стороні магазину. CloudPayments підтримує BYN, UAH, USD, EUR.

Шлюз Підтримувані валюти Конвертація на стороні Рекомендація
Stripe Будь-які Ні (автоматична) Для міжнародної торгівлі
ЮKassa RUB Потрібна на стороні магазину Тільки Росія
CloudPayments BYN, UAH, USD, EUR Ні Для України та Білорусі

При оплаті фіксується валюта замовлення та курс на момент оплати:

ALTER TABLE orders ADD COLUMN currency CHAR(3) NOT NULL DEFAULT 'UAH'; ALTER TABLE orders ADD COLUMN exchange_rate NUMERIC(15,6) NOT NULL DEFAULT 1.0; ALTER TABLE orders ADD COLUMN base_currency_total NUMERIC(12,2); 

Це дозволяє звести звітність в єдиній валюті незалежно від того, в чому платив покупець.

Округлення та анти-патерни

Ніколи не зберігайте гроші в FLOAT — втрата точності при математиці. Завжди використовуйте NUMERIC(12,2) або DECIMAL.

Округлення при конвертації: round($price * $rate, 2, PHP_ROUND_HALF_EVEN)банківське округлення, помилка не накопичується. При підсумовуванні позицій замовлення спочатку підсумовуємо, потім округлюємо.

Які типові помилки допускають при реалізації мультивалютності?

  1. Використання FLOAT для зберігання грошей — втрата точності.
  2. Округлення кожної позиції окремо, а не підсумкової суми.
  3. Відсутність фіксації курсу на момент замовлення — звіти в базовій валюті будуть розходитися.
  4. Неврахування податків для різних валют — ПДВ може відрізнятися.
  5. Змішування стратегій зберігання цін в одному проєкті.

Наші клієнти відзначають зниження помилок у звітності на 95% та економію до 30% часу на звірянні даних після впровадження правильної архітектури.

Що входить у роботу?

  • Аудит поточної архітектури та вибір стратегії зберігання цін.
  • Проєктування схеми бази даних і міграцій.
  • Реалізація модуля валют, автооновлення курсів і форматування.
  • Інтеграція вибору валюти в інтерфейс (cookie, профіль, GeoIP).
  • Налаштування мультивалютних платежів (Stripe, CloudPayments та ін.).
  • Розробка звітів у базовій валюті.
  • Документація та навчання команди замовника.
  • Підтримка після впровадження.

Ми реалізували мультивалютність у 30+ проєктах, включаючи інтернет-магазини з оборотом понад $10M. Якщо вам потрібна надійна мультивалютність, зв'яжіться з нами для оцінки вашого проєкту.

Строки реалізації

  • Базова система (зберігання + перемикач + форматування): від 3 до 4 днів.
  • Автооновлення курсів: від 1 дня.
  • Автоперерахунок з порогом: від 1–2 днів.
  • Мультивалютні платежі (залежить від шлюзу): від 2 до 4 днів.
  • Фінансова звітність: від 1–2 днів.

Повна реалізація для магазину з 3–5 валютами займає від 1 до 2 тижнів.

Отримайте консультацію по вашому проєкту — оцінимо обсяг робіт і запропонуємо оптимальне рішення. Зв'яжіться з нами, щоб обговорити деталі.