pashynskyi / instashop
Requires
- php: >=8.0.0
- daaner/turbosms: ^1.1
- intervention/image: ^2.7
- laravel/framework: >=8.0
- laravel/socialite: ^5.16
- liqpay/liqpay: ^1.2
- mcamara/laravel-localization: >=1.6
- pashynskyi/localizable: *
- pashynskyi/nova-poshta: *
- pashynskyi/xml-builder: *
- spatie/laravel-html: ^3.13
Requires (Dev)
- orchestra/testbench: ^10.0
This package is not auto-updated.
Last update: 2026-08-13 08:57:06 UTC
README
Laravel-пакет для інтернет-магазину: каталог товарів (продукти, варіанти, категорії, групи, характеристики), кошик, список бажань, замовлення з оплатою (LiqPay) і доставкою (Нова Пошта / самовивіз), особистий кабінет, автентифікація (включно з соцмережами та SMS-кодами відновлення пароля), динамічне ціноутворення й upsell-рекомендації, XML-фіди (Google Merchant, Facebook), а також синхронізація каталогу й замовлень із віддаленим сервером (складом).
Пакет самодостатній: підключає власні роути, міграції, конфіги і переклади (uk/ru) через InstashopServiceProvider, а host-застосунок здебільшого лише публікує й кастомізує те, що потрібно.
Вимоги
- PHP >= 8.0
- Laravel >= 8.0
- Розширення/пакети:
mcamara/laravel-localization,laravel/socialite,intervention/image,daaner/turbosms,liqpay/liqpay,spatie/laravel-html, а також приватні пакетиpashynskyi/localizable,pashynskyi/nova-poshta,pashynskyi/xml-builder
Встановлення
composer require pashynskyi/instashop
Провайдер (Pashynskyi\Instashop\Providers\InstashopServiceProvider) підключається автоматично через Laravel package discovery.
Опублікувати те, що потрібно кастомізувати в проєкті:
php artisan vendor:publish --tag=config # config/instashop.php
php artisan vendor:publish --tag=options # options/instashop/*.php (доставка, оплата, ціни, загальні)
php artisan vendor:publish --tag=migrations # database/migrations/vendor/instashop
php artisan vendor:publish --tag=locales # resources/lang/vendor/instashop
php artisan vendor:publish --tag=routes # routes/instashop/web.php
php artisan vendor:publish --tag=instashop-assets
Змінні оточення (config/instashop.php читає їх напряму):
STOREHOUSE_SERVER=
STOREHOUSE_API_TOKEN=
STOREHOUSE_SITE_ID=
LIQPAY_PUBLIC_KEY=
LIQPAY_PRIVATE_KEY=
Структура пакету
| Директорія | Призначення |
|---|---|
src/Models | Eloquent-моделі: Product, Variant, ProductCategory, ProductGroup, Feature/FeatureValue, Order, User, Page, Setting, Visit, Localization тощо |
src/Http/Controllers | Контролери каталогу, кошика, замовлень, платежів, автентифікації (включно з соцмережами), фідів, особистого кабінету |
src/App | Бізнес-логіка: Cart, Wishlist, Viewed, Price/PriceCalculator, Settings, SMS-нотифікації |
src/App/Pricing | Конфігурована система знижок (умови/дії/правила, будуються з JSON-конфігу) |
src/App/Upsell | Конфігурований rule-based upsell (тригери, джерела кандидатів, пріоритетна каскадна видача) |
src/Remote | Синхронізація з віддаленим сервером — SyncRegistry, Get/Set, StorehouseRemoteGetter/StorehouseRemoteSetter |
src/Services | OrderSyncService (синхронізація замовлення), CatalogCache, аналітика (Facebook Pixel, Google Analytics) |
src/Console/Commands | instashop:sync-orders — ретрай несинхронізованих замовлень |
src/Config | instashop.php + дефолтні опційні конфіги (Options/deliveries.php, payments.php, price.php, general.php) |
src/Database/Migrations | Повна схема БД магазину |
src/UI | Дрібні UI-білдери для форм доставки/оплати (spatie/laravel-html) |
Конфіг instashop.php
Головний конфіг пакету (src/Config/instashop.php, публікується тегом config): мета-дані сайту, контактні телефони, налаштування XML-фідів (Google/Facebook, включно з мапінгом категорій на зовнішні таксономії), соцмережі, remote (доступи Storehouse — див. нижче) і payments.liqpay.
Опційні конфіги (options/instashop/*.php)
Окремий шар конфігів, публікується тегом options, читається через options('файл.ключ', 'instashop'); пакет постачає дефолти (src/Config/Options/*.php), поки застосунок не опублікує власні:
deliveries.php— способи доставки (self/np/ukr), кожен — обʼєктDeliveryз полями форми, ціною, порогом безкоштовної доставки, комісією за накладений платіж.payments.php— способи оплати (liqpay/cash), обʼєктPaymentз передоплатою/повною сумою.general.php— статус нового замовлення (order_status) і головне меню сайту (menu, будується зProductGroup).price.php— не редагується руками, генерується автоматично з CRM-конфігу черезPricingConfigService(див. "Ціноутворення").
Синхронізація зі Storehouse (CRM)
Каталог, сторінки, ціни/upsell-конфіги та замовлення синхронізуються із зовнішньою CRM Storehouse (~/Projects/general/storehouse) через її HTTP API. Модулі реєструються в SyncRegistry під час boot() провайдера: product, order, category, group, page, price_config, upsell_config. StorehouseRemoteGetter тягне дані з CRM (матчинг по remote_id), StorehouseRemoteSetter надсилає клієнтів і замовлення.
Для синхронізації потрібен токен і ID сайту з боку CRM:
- У CRM-адмінці (
/admin/sites) створити сайт для сторефронту — вказатиCallback url(домен) і придумати Token (унікальний рядок, задається вручну, автогенерації немає). - Взяти
idствореного сайту. - Прописати в
.envсторефронту:STOREHOUSE_SERVER=https://<домен-crm>/api/v1/ STOREHOUSE_API_TOKEN=<token із кроку 1> STOREHOUSE_SITE_ID=<id сайту із кроку 2>
CRM перевіряє пару api_token+site_id проти активного Site (і активності його Shop) на кожному запиті (App\Http\Middleware\Remote у Storehouse) — без збігу повертає {"success": false, ...}.
Синхронізація замовлень і ретрай
OrderSyncService::sync(Order $order) надсилає замовлення на CRM під час створення (OrderController@create). Якщо CRM недоступна або повернула помилку — замовлення не падає, а зберігається з remote_id = null і причиною відмови в remote_fail. Ознака "не синхронізовано" — саме remote_id IS NULL, окремого поля для цього не заведено.
Несинхронізовані замовлення підхоплює консольна команда:
php artisan instashop:sync-orders
Вона сама реєструється в шедулері (everyFiveMinutes(), withoutOverlapping()) — жодних змін у Kernel.php host-застосунку не потрібно. Помилка на одному замовленні (виняток чи невдала відповідь сервера) не зупиняє обробку решти черги.
Ціноутворення (Pricing)
PricingConfigService будує з JSON-конфігу (options/instashop/price.php) список знижок і промокодів:
- Знижки — пара умова (
Conditions: категорія, група, роль користувача, наявність опт-ціни, діапазон дат, значення характеристики, або комбінація правил) + дія (Actions: відсоток мінус, відсоток мінус за мапою). Знижки сортуються заpriority, кожна може бутиstackable(продовжити застосовувати наступні) або ні. - Промокоди — застосовуються до підсумкової ціни (
Price), підтримують лише відсоткову знижку.
Upsell-рекомендації
UpsellConfigService::resolve() — пріоритетна каскадна видача: правила з конфігу (options/instashop/general.php чи окремий upsell-конфіг) перевіряються по черзі за priority, перше правило, чий тригер спрацював і має що показати, "виграє" весь блок (повідомлення + список товарів не змішуються з двох різних правил).
- Тригери (
Triggers): завжди, поріг суми кошика, категорія/група в кошику, поріг кількості, конкретний товар. - Джерела кандидатів (
Sources): усі доступні, за мапінгом категорій, за мапінгом груп, вручну заданий список. - Кандидати фільтруються за ціною (для
fill_to_threshold— не дорожче суми, що бракує до порогу, з підлогоюmin_price_cap), деревом категорій (щоб не пропонувати той самий підрозділ, що вже в кошику), уже купленим, уже в кошику/показаним на попередній сторінці, збігом характеристик; максимум один варіант на товар. loadMore()довантажує наступну сторінку кандидатів того самого правила, що виграло першу.
Консольні команди
| Команда | Опис |
|---|---|
instashop:sync-orders | Повторно надсилає на віддалений сервер замовлення без remote_id |
Тестування
Пакет має власний набір тестів на orchestra/testbench (SQLite in-memory, RefreshDatabase).
composer install
vendor/bin/phpunit
Феєрчастина тестового оточення (tests/TestCase.php) сама піднімає провайдер пакету, БД і потрібні конфіги; HTTP-рівневі тести (OrderControllerCreateTest) додатково підміняють ISetter фейком (tests/Support/FakeOrderSetter), щоб не ходити в реальну мережу.
Автор
Alexander Pashynskyi — pashynskyi@gmail.com