Как построить интернет-магазин для казахстанского рынка с нуля (2015)
Коротко: Для казахстанского рынка 2015 года: PHP + MySQL + WooCommerce (WordPress) для старта менее чем за месяц, или PHP + Laravel для кастомного решения. Обязательно: Kaspi Pay, доставка «Казпочтой» + курьер, цены в тенге, двуязычный контент (kk + ru).
Технологический выбор
В 2015 году мы протестировали два подхода для казахстанских клиентов:
WooCommerce (WordPress 4.3 + WooCommerce 2.4):
- Запуск: 2-3 недели
- Стоимость разработки: $800-1,500
- Плюсы: быстро, много плагинов, клиент сам управляет
- Минусы: производительность при >5000 товаров, сложность кастомизации
Laravel 5 + кастомный магазин:
- Запуск: 6-10 недель
- Стоимость: $3,000-6,000
- Плюсы: полный контроль, производительность, кастомная логика
- Минусы: дольше, дороже, нужен разработчик для поддержки
Для большинства клиентов с бюджетом $1,000-2,000 - WooCommerce.
Структура БД (Laravel-вариант)
-- Продукты с поддержкой казахского языка
CREATE TABLE products (
id INT AUTO_INCREMENT PRIMARY KEY,
sku VARCHAR(100) UNIQUE NOT NULL,
price DECIMAL(10,2) NOT NULL,
price_old DECIMAL(10,2), -- Зачёркнутая цена
stock INT DEFAULT 0,
weight_kg DECIMAL(5,2), -- Для расчёта доставки
status ENUM('active','draft','out_of_stock') DEFAULT 'active',
created_at DATETIME DEFAULT NOW()
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- Переводы: отдельная таблица для kk/ru/en
CREATE TABLE product_translations (
id INT AUTO_INCREMENT PRIMARY KEY,
product_id INT NOT NULL,
lang CHAR(2) NOT NULL, -- 'kk', 'ru', 'en'
name VARCHAR(500) NOT NULL,
description TEXT,
slug VARCHAR(500) UNIQUE,
meta_title VARCHAR(200),
meta_desc TEXT,
UNIQUE KEY uniq_product_lang (product_id, lang),
INDEX idx_slug (slug),
FOREIGN KEY (product_id) REFERENCES products(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- Заказы
CREATE TABLE orders (
id INT AUTO_INCREMENT PRIMARY KEY,
order_number VARCHAR(20) UNIQUE, -- KZ-2015-00001
user_id INT,
status ENUM('new','confirmed','processing','shipped','delivered','cancelled') DEFAULT 'new',
total DECIMAL(10,2) NOT NULL,
currency CHAR(3) DEFAULT 'KZT',
payment_method ENUM('kaspi','card','cod') DEFAULT 'cod',
delivery_type ENUM('courier','kazpost','pickup') DEFAULT 'courier',
delivery_city VARCHAR(100), -- Алматы, Астана, Шымкент...
delivery_cost DECIMAL(10,2) DEFAULT 0,
-- Контакты покупателя
customer_name VARCHAR(200) NOT NULL,
customer_phone VARCHAR(20) NOT NULL,
customer_email VARCHAR(200),
delivery_address TEXT,
notes TEXT, -- Комментарий к заказу
created_at DATETIME DEFAULT NOW()
) ENGINE=InnoDB;
Расчёт стоимости доставки
<?php
// DeliveryCalculator.php - расчёт доставки по Казахстану 2015
class DeliveryCalculator {
// Тарифы Казпочты по зонам (2015, приблизительные)
private array $kazpostZones = [
'Алматы' => 0, // Бесплатно в пределах Алматы (курьер)
'Астана' => 1200, // Тенге за посылку до 1 кг
'Шымкент' => 1100,
'Актобе' => 1400,
'Атырау' => 1600,
'Усть-Каменогорск' => 1500,
'Павлодар' => 1300,
'Семей' => 1400,
'Тараз' => 1100,
'default' => 1800, // Другие города
];
public function calculate(array $cartItems, string $city, string $method): array {
$totalWeight = array_sum(array_map(
fn($item) => $item['product']['weight_kg'] * $item['qty'],
$cartItems
));
$totalValue = array_sum(array_map(
fn($item) => $item['product']['price'] * $item['qty'],
$cartItems
));
if ($method === 'pickup') {
return ['cost' => 0, 'days' => 0, 'description' => 'Самовывоз'];
}
if ($method === 'courier') {
// Курьер только по Алматы
if ($city !== 'Алматы') {
return ['available' => false];
}
$cost = $totalValue >= 15000 ? 0 : 800; // Бесплатно от 15,000 тенге
return ['cost' => $cost, 'days' => 1, 'description' => 'Курьер (1 день)'];
}
if ($method === 'kazpost') {
$baseCost = $this->kazpostZones[$city] ?? $this->kazpostZones['default'];
$weightCost = $totalWeight > 1 ? (int)(($totalWeight - 1) * 400) : 0;
$cost = $baseCost + $weightCost;
$days = $city === 'Алматы' ? 2 : ($city === 'Астана' ? 4 : 7);
return [
'cost' => $cost,
'days' => $days,
'description' => "Казпочта ({$days} дней)"
];
}
return ['cost' => 0, 'days' => 0];
}
}
Генерация номера заказа по казахстанскому стандарту
<?php
// Генерация читаемого номера заказа: KZ-2015-00001
function generateOrderNumber(): string {
$year = date('Y');
$prefix = 'KZ-' . $year . '-';
// Найти последний номер за этот год
$lastOrder = DB::query(
"SELECT order_number FROM orders WHERE order_number LIKE ? ORDER BY id DESC LIMIT 1",
[$prefix . '%']
)->fetchColumn();
if ($lastOrder) {
$lastNum = (int)substr($lastOrder, strlen($prefix));
$newNum = $lastNum + 1;
} else {
$newNum = 1;
}
return $prefix . str_pad($newNum, 5, '0', STR_PAD_LEFT);
// Пример: KZ-2015-00001, KZ-2015-00002, ...
}
Уведомления: SMS через Mobizon (KZ)
<?php
// В 2015 SMS-шлюзы для Казахстана: Mobizon, SMS.kz, SMSC.kz
// Mobizon имел казахстанские номера и транзитные маршруты к Kcell/Beeline KZ
class SmsNotifier {
private string $apiKey;
private string $apiUrl = 'http://mobizon.kz/help/api/smssend';
public function send(string $phone, string $text): bool {
// Нормализовать казахстанский номер
$phone = preg_replace('/[^0-9]/', '', $phone);
if (str_starts_with($phone, '8') && strlen($phone) === 11) {
$phone = '7' . substr($phone, 1); // 87xxxxxxxxx → 77xxxxxxxxx
}
$response = file_get_contents($this->apiUrl . '?' . http_build_query([
'apiKey' => $this->apiKey,
'recipient' => $phone,
'text' => $text,
'from' => 'MyShop', // Имя отправителя (до 11 символов)
]));
$data = json_decode($response, true);
return ($data['code'] ?? -1) === 0;
}
public function notifyOrderConfirmed(array $order): void {
$text = "Заказ #{$order['order_number']} подтверждён. "
. "Сумма: " . number_format($order['total'], 0, '.', ' ') . " тг. "
. "Доставка: {$order['delivery_days']} дн. MyShop.kz";
$this->send($order['customer_phone'], $text);
}
}
Результаты первого года
Один из наших клиентов - магазин электроники в Алматы:
| Период | Заказы/мес | Средний чек | Оборот |
|---|---|---|---|
| Запуск (янв 2015) | 45 | 12,400 тг | 558,000 тг |
| 6 месяцев | 180 | 14,800 тг | 2,664,000 тг |
| 12 месяцев | 420 | 16,200 тг | 6,804,000 тг |
Kaspi Pay обеспечил 52% транзакций к концу года. SEO под казахстанские запросы дало 38% трафика.