NopCommerce и почта России. Часть 2. Прописываем тарифы.

Часть 2. Прописываем тарифы.
Это — вторая часть серии постов, посвященная настройке CMS на основе NopCommerce для работы с почтой России.

Что бы внести тарифы на доставку с помощью Почты России, достаточно воспользоваться стандартным модулем расчета «Shipping by weight» и небольшим SQL скриптом.

Тарифы Почты России
Само описание тарифов можно посмотреть на сайте Почты России по адресу www.russianpost.ru/rp/servise/ru/home/postuslug/bookpostandparcel/local
Для Москвы тарифы следующие: Россия раздяется на 5 магистральных поясов и доставка до каждого пояса стоит фиксированную сумму за посылку весом до 500 гр. За каждые следующие 500 гр взимается фиксированная доплата.

Стоимости доставки по 1-му магистральному поясу: 149.9 руб + 13.4 за каждые 500 грамм
По 2-му магистральному поясу: 152 руб + 15.6 за каждые 500 грамм
По 3-му магистральному поясу: 158.1 руб + 15.6 за каждые 500 грамм
По 4-му магистральному поясу: 192.6 руб + 22.3 за каждые 500 грамм
По 5-му магистральному поясу: 215 руб + 36.4 за каждые 500 грамм
Эти правила действуют для посылок до 10 кг.

Страховка — 4% от объявленной стоимости посылки.

Использование скрипта

Вначале надо получить нужные коды типа доставки, которые прописаны в Вашей CMS.
Код типа доставки можно посмотреть в таблице [ShippingMethod]. У меня код доставки почтой России — 4, код доставки почтой России со страховкой — 5.

Поэтому для первого запуска скрипта я ставлю @shipping_code = 4, @insurance_percent = 0.
Вторым — @shipping_code = 5, @insurance_percent = 4

Есть три варианта запуска скрипта

Первоначальная настройка с областями из моего списка
Первоначально надо внести список областей, как указано по ссылке на мой предыдущий пост этой серии не модифицируя список оттуда.
После этого можно просто запустить скрипт и получить желаемый результат.

Кроме областей из моего списка есть иные области России
Можно внести список областей, из моего предыдущего поста этой серии и временно или постоянно оставить в работе другие области.
Тогда надо вручную посмотреть в таблице [StateProvince] первый ID области из того списка, раскомментировать строчку /* SET @start_id = ...*/ и внести этот номер.
После этого такой скрипт точно так же можно запустить.
Важно! Список должен быть точно тем же, что и у меня, иначе настройка магистральных поясов собьётся.

У вас уже есть свой список областей, который вы не хотите менять
Устанавливаем следующей командой @start_id в 0
SET @start_id = 0

Переписываем команду INSERT INTO #zones (zone_id, zone_num ) VALUES… под свой набор областей.
Для этого смотрим таблицу [StateProvince], получаем ID областей, распределяем их по магистральным поясам согласно нижеприведенному списку и формируем SQL команду в виде
INSERT INTO #zones (zone_id , zone_num )
     VALUES
	 (110, 1) , (111,1), (112,2) , ...


Здесь первое число — ID области из таблицы [StateProvince], а второе — номер магистрального пояса.
  • 1-й магистральный пояс
    Москва, Брянская обл., Владимирская обл., Вологодская обл., Воронежская обл., Ивановская обл., Калужская обл., Костромская обл., Курская обл., Липецкая обл., Московская обл., Нижегородская, Орловская обл., Рязанская обл., Смоленская обл., Тамбовская обл., Тверская обл., Тульская обл., Ярославская обл.
  • 2-й магистральный пояс
    Санкт-Петербург, Севастополь, Адыгея, Башкортостан, Ингушетия, Кабардино-Балкария, Калмыкия, Карачаево-Черкесия, Карелия, Коми, Крым, Марий Эл, Мордовия, Северная Осетия — Алания, Татарстан, Удмуртия, Чечня, Чувашия, Краснодарский край, Пермский край, Ставропольский край, Архангельская обл., Астраханская обл., Белгородская обл., Волгоградская обл., Калининградская обл., Кировская обл., Ленинградская область, Мурманская обл., Новгородская обл., Оренбургская обл., Пензенская обл., Псковская обл., Ростовская обл., Самарская обл., Саратовская обл., Свердловская обл., Ульяновская обл., Челябинская обл., Ненецкий АО
  • 3-й магистральный пояс
    Алтай, Дагестан, Тыва (Тува), Хакасия, Алтайский край, Красноярский край, Кемеровская обл., Курганская обл., Новосибирская обл., Омская обл., Томская обл., Тюменская обл., Ханты-Мансийский АО — Югра, Ямало-Ненецкий АО
  • 4-й магистральный пояс
    Бурятия, Саха (Якутия), Забайкальский край, Амурская обл., Иркутская обл.
  • 5-й магистральный пояс
    Камчатский край, Приморский край, Хабаровский край, Магаданская обл., Сахалинская обл., Еврейская АО, Чукотский АО

Внимание! Если какие-то изменения в SQL не отображаются на сайте, необходимо нажать «Перезагрузить приложение» в админке. И не забудьте сделать бекап базы данных!

Сам скрипт:
BEGIN TRY

/* Код доставки почтой России - 4. */
DECLARE @shipping_code INT = 4
/* Стоимость страховки */
DECLARE @insurance_percent FLOAT = 0

/* Код магазина. 0 - для всех магазинов */
DECLARE @store_code INT = 0


/* Прописываем тарифы для каждого магистрального пояса */
DECLARE @base_price1 FLOAT = 149.9
DECLARE @delta_price1 FLOAT = 13.4
DECLARE @base_price2 FLOAT = 152
DECLARE @delta_price2 FLOAT = 15.6
DECLARE @base_price3 FLOAT = 158.1
DECLARE @delta_price3 FLOAT = 22.3
DECLARE @base_price4 FLOAT = 192.6
DECLARE @delta_price4 FLOAT = 31.8
DECLARE @base_price5 FLOAT = 215
DECLARE @delta_price5 FLOAT = 36.4

DECLARE @base_price FLOAT
DECLARE @delta_price FLOAT
DECLARE @i INT
DECLARE @russia_code INT
DECLARE @start_id INT
DECLARE @zone_id INT
DECLARE @zone_num INT

SELECT @russia_code = MIN (id) FROM [Country] WHERE [Name] = 'Russia'

/*  Очищаем старые данные  */
DELETE FROM [ShippingByWeight] WHERE [CountryId] = @russia_code and [ShippingMethodId] = @shipping_code

SELECT @start_id = MIN (id) FROM [StateProvince] WHERE [CountryId] = @russia_code
/* SET @start_id = ...*/

/* Создаем временную таблицу и заполняем кодами областей и соответствующими номерами магистральных поясов */
CREATE TABLE  #zones (zone_id INT, zone_num INT)

INSERT INTO #zones (zone_id , zone_num )
     VALUES
(0,1),(38,1),(39,1),(41,1),(42,1),(43,1),(46,1),(49,1),(51,1),(53,1),(55,1),(57,1),(62,1),(66,1),(71,1),(72,1),(73,1),(75,1),(79,1),
(1,2),(2,2),(3,2),(5,2),(8,2),(9,2),(10,2),(11,2),(12,2),(13,2),(14,2),(15,2),(16,2),(18,2),(19,2),(21,2),(23,2),(24,2),(28,2),(30,2),
(32,2),(35,2),(36,2),(37,2),(40,2),(45,2),(48,2),(52,2),(56,2),(58,2),(61,2),(63,2),(64,2),(65,2),(67,2),(68,2),(70,2),(77,2),(78,2),(81,2),
(4,3),(7,3),(20,3),(22,3),(25,3),(29,3),(47,3),(50,3),(59,3),(60,3),(74,3),(76,3),(82,3),(84,3),
(6,4),(17,4),(26,4),(34,4),(44,4),
(27,5),(31,5),(33,5),(54,5),(69,5),(80,5),(83,5)



/* Проходим по всей временной таблице */
DECLARE Zones_Cursor CURSOR FOR
SELECT zone_id, zone_num 
FROM #zones;
OPEN Zones_Cursor ;
FETCH NEXT FROM Zones_Cursor INTO @zone_id, @zone_num;
WHILE @@FETCH_STATUS = 0
   BEGIN
		BEGIN
			/* Определяем параметры тарифа для конкретной области */
			IF  @zone_num = 1  SET @base_price = @base_price1
			IF  @zone_num = 1  SET @delta_price = @delta_price1
			IF  @zone_num = 2  SET @base_price = @base_price2
			IF  @zone_num = 2  SET @delta_price = @delta_price2
			IF  @zone_num = 3  SET @base_price = @base_price3
			IF  @zone_num = 3  SET @delta_price = @delta_price3
			IF  @zone_num = 4  SET @base_price = @base_price4
			IF  @zone_num = 4  SET @delta_price = @delta_price4
			IF  @zone_num = 5  SET @base_price = @base_price5
			IF  @zone_num = 5  SET @delta_price = @delta_price5

			SET @i = 0
			/* Проходим по каждой половине килограмма до 10 кг */
			WHILE @i < 20
				BEGIN
					INSERT INTO [ShippingByWeight]
						([StoreId]
						,[CountryId]
						,[StateProvinceId]
						,[ShippingMethodId]
						,[From]
						,[To]
						,[AdditionalFixedCost]
						,[PercentageRateOfSubtotal]
						,[RatePerWeightUnit]
						,[LowerWeightLimit])
					VALUES (
						@store_code, 
						@russia_code, 
						@start_id + @zone_id , 
						@shipping_code, 
						@i * 500,
                                                (@i + 1) * 500 - 1,
						ROUND (@base_price + @i * @delta_price + 0.499, 0),
						@insurance_percent, 
						0, 
						0)

					SET @i = @i + 1
				END		
		END
		FETCH NEXT FROM Zones_Cursor into @zone_id, @zone_num;
	END;
CLOSE Zones_Cursor ;
DEALLOCATE Zones_Cursor ;

DROP TABLE #zones

END TRY
BEGIN CATCH 
	SELECT
        ERROR_NUMBER() AS ErrorNumber
        ,ERROR_SEVERITY() AS ErrorSeverity
        ,ERROR_STATE() AS ErrorState
        ,ERROR_LINE() AS ErrorLine
        ,ERROR_MESSAGE() AS ErrorMessage;
END CATCH;

NopCommerce и почта России. Часть 1. Прописываем области.

Часть 1. Прописываем области.
Это — первая часть серии постов, посвященная настройке CMS на основе NopCommerce для работы с почтой России.
Вносить области рекоменую этим скриптом, это избавит вас в дальнейшем с проблемами по адаптации скриптов к вашему набору областей.

Сам список областей был взят по ссылкам Субъекты Российской Федерации и Federal subjects of Russia

Внимание! Этот скрипт удаляет все предыдущие области России. В случае наличия каких-то адресов, в которых используются области, скрипт не отработает.

Сайт только первоначально настраивается
Если сайт только настраивается и еще не запущен в реальную работу. Можно просто удалить все записи в таблице [Address] или установить столбец [StateProvinceId] таблицы [Address] для всех записей в произвольное значение, например 1.

Сайт находится в работе

В это случае процедура будет сложнее.
  • Комментируем 2 инструкции удаления DELETE в разделе «Очистка старых данных»
  • Запускаем скрипт
  • Когда новые области будут созданы отдельными SQL запросами меняем ID старых областей в таблице Address на ID новых
  • Удаляем старые области из таблиц [StateProvince] и [LocalizedProperty].


Если какие-то изменения в SQL не отображаются на сайте, необходимо нажать «Перезагрузить приложение» в админке. И не забудьте сделать бекап базы данных!


BEGIN TRY

DECLARE @russia_code INT
DECLARE @language_code INT

DECLARE @start_id INT


/*  Получаем коды России и русского языка в таблицах сайта */
SELECT @russia_code = MIN (id) FROM [Country] WHERE [Name] = 'Russia'
SELECT @language_code = MIN (id) FROM [Language] WHERE [Name] = 'Russian'

/* Очистка старых данных */
DELETE FROM [LocalizedProperty] WHERE [LocaleKeyGroup] = 'StateProvince' AND [LocaleKey] = 'Name' AND [LanguageId] = @language_code 
DELETE FROM [StateProvince] WHERE [CountryId] = @russia_code 



/* Создаем временную таблицу и заполняем именами областей и ID для сортировки */

CREATE TABLE #provinces (
	P_Id INT PRIMARY KEY IDENTITY,
	sort_position INT, 
	english_name nvarchar(50), 
	russian_name nvarchar(50))


/* Создаем временную таблицу и заполняем кодами областей и соответствующими номерами магистральных поясов */
INSERT INTO #provinces (sort_position , english_name, russian_name )
	VALUES
	(1, 'Moscow', 'г. Москва'),
	(4, 'Saint Petersburg', 'г. Санкт-Петербург'),
	(7, 'Sevastopol', 'г. Севастополь'),
	(10, 'Adygea, Republic of', 'Адыгея'),
	(20, 'Altai Republic', 'Алтай'),
	(30, 'Bashkortostan, Republic of', 'Башкортостан'),
	(40, 'Buryatia, Republic of', 'Бурятия'),
	(50, 'Dagestan, Republic of', 'Дагестан'),
	(60, 'Ingushetia, Republic of', 'Ингушетия'),
	(70, 'Kabardino-Balkar Republic', 'Кабардино-Балкария'),
	(80, 'Kalmykia, Republic of', 'Калмыкия'),
	(90, 'Karachay-Cherkess Republic', 'Карачаево-Черкесия'),
	(100, 'Karelia, Republic of', 'Карелия'),
	(110, 'Komi Republic', 'Коми'),
	(120, 'Republic of Crimea', 'Крым'),
	(130, 'Mari El Republic', 'Марий Эл'),
	(140, 'Mordovia, Republic of', 'Мордовия'),
	(150, 'Sakha (Yakutia) Republic', 'Саха (Якутия)'),
	(160, 'North Ossetia-Alania, Republic of', 'Северная Осетия — Алания'),
	(170, 'Tatarstan, Republic of', 'Татарстан'),
	(180, 'Tuva Republic', 'Тыва (Тува)'),
	(190, 'Udmurt Republic', 'Удмуртия'),
	(200, 'Khakassia, Republic of', 'Хакасия'),
	(210, 'Chechen Republic', 'Чечня'),
	(220, 'Chuvash Republic', 'Чувашия'),
	(230, 'Altai Krai', 'Алтайский край'),
	(240, 'Zabaykalsky Krai', 'Забайкальский край'),
	(250, 'Kamchatka Krai', 'Камчатский край'),
	(260, 'Krasnodar Krai', 'Краснодарский край'),
	(270, 'Krasnoyarsk Krai', 'Красноярский край'),
	(280, 'Perm Krai', 'Пермский край'),
	(290, 'Primorsky Krai', 'Приморский край'),
	(300, 'Stavropol Krai', 'Ставропольский край'),
	(310, 'Khabarovsk Krai', 'Хабаровский край'),
	(320, 'Amur Oblast', 'Амурская обл.'),
	(330, 'Arkhangelsk Oblast', 'Архангельская обл.'),
	(340, 'Astrakhan Oblast', 'Астраханская обл.'),
	(350, 'Belgorod Oblast', 'Белгородская обл.'),
	(360, 'Bryansk Oblast', 'Брянская обл.'),
	(370, 'Vladimir Oblast', 'Владимирская обл.'),
	(380, 'Volgograd Oblast', 'Волгоградская обл.'),
	(390, 'Vologda Oblast', 'Вологодская обл.'),
	(400, 'Voronezh Oblast', 'Воронежская обл.'),
	(410, 'Ivanovo Oblast', 'Ивановская обл.'),
	(420, 'Irkutsk Oblast', 'Иркутская обл.'),
	(430, 'Kaliningrad Oblast', 'Калининградская обл.'),
	(440, 'Kaluga Oblast', 'Калужская обл.'),
	(450, 'Kemerovo Oblast', 'Кемеровская обл.'),
	(460, 'Kirov Oblast', 'Кировская обл.'),
	(470, 'Kostroma Oblast', 'Костромская обл.'),
	(480, 'Kurgan Oblast', 'Курганская обл.'),
	(490, 'Kursk Oblast', 'Курская обл.'),
	(500, 'Leningrad Oblast', 'Ленинградская область'),
	(510, 'Lipetsk Oblast', 'Липецкая обл.'),
	(520, 'Magadan Oblast', 'Магаданская обл.'),
	(530, 'Moscow Oblast', 'Московская обл.'),
	(540, 'Murmansk Oblast', 'Мурманская обл.'),
	(550, 'Nizhny Novgorod Oblast', 'Нижегородская обл.'),
	(560, 'Novgorod Oblast', 'Новгородская обл.'),
	(570, 'Novosibirsk Oblast', 'Новосибирская обл.'),
	(580, 'Omsk Oblast', 'Омская обл.'),
	(590, 'Orenburg Oblast', 'Оренбургская обл.'),
	(600, 'Oryol Oblast', 'Орловская обл.'),
	(610, 'Penza Oblast', 'Пензенская обл.'),
	(620, 'Pskov Oblast', 'Псковская обл.'),
	(630, 'Rostov Oblast', 'Ростовская обл.'),
	(640, 'Ryazan Oblast', 'Рязанская обл.'),
	(650, 'Samara Oblast', 'Самарская обл.'),
	(660, 'Saratov Oblast', 'Саратовская обл.'),
	(670, 'Sakhalin Oblast', 'Сахалинская обл.'),
	(680, 'Sverdlovsk Oblast', 'Свердловская обл.'),
	(690, 'Smolensk Oblast', 'Смоленская обл.'),
	(700, 'Tambov Oblast', 'Тамбовская обл.'),
	(710, 'Tver Oblast', 'Тверская обл.'),
	(720, 'Tomsk Oblast', 'Томская обл.'),
	(730, 'Tula Oblast', 'Тульская обл.'),
	(740, 'Tyumen Oblast', 'Тюменская обл.'),
	(750, 'Ulyanovsk Oblast', 'Ульяновская обл.'),
	(760, 'Chelyabinsk Oblast', 'Челябинская обл.'),
	(770, 'Yaroslavl Oblast', 'Ярославская обл.'),
	(810, 'Jewish Autonomous Oblast', 'Еврейская АО'),
	(820, 'Nenets Autonomous Okrug', 'Ненецкий  АО'),
	(830, 'Khanty–Mansi Autonomous Okrug – Yugra', 'Ханты-Мансийский АО - Югра'),
	(840, 'Chukotka Autonomous Okrug', 'Чукотский АО'),
	(850, 'Yamalo-Nenets Autonomous Okrug', 'Ямало-Ненецкий АО')

	/* Заполняем список областей */
INSERT INTO [StateProvince]
           ([CountryId]
           ,[Name]
           ,[Published]
           ,[DisplayOrder])
	SELECT    
		@russia_code, 
		english_name, 
		1, 
		sort_position   
	FROM #provinces


SET @start_id = @@IDENTITY - @@ROWCOUNT 

/* Заполняем переводы областей на русский язык*/
INSERT INTO [LocalizedProperty]
           ([EntityId]
           ,[LanguageId]
           ,[LocaleKeyGroup]
           ,[LocaleKey]
           ,[LocaleValue])
	SELECT 
		@start_id + P_ID, 
		@language_code, 
		'StateProvince', 
		'Name', 
		russian_name  
	FROM #provinces

DROP TABLE #provinces

END TRY
BEGIN CATCH 
	SELECT
        ERROR_NUMBER() AS ErrorNumber
        ,ERROR_SEVERITY() AS ErrorSeverity
        ,ERROR_STATE() AS ErrorState
        ,ERROR_LINE() AS ErrorLine
        ,ERROR_MESSAGE() AS ErrorMessage;
END CATCH;