Repository: fidals/shopelectro

Issue:
DB contains prices larger then 1C ones
This 1C card contains retail price `600 rub`, but product page (and yandex.yml too) contains price `605 rub`

https://www.shopelectro.ru/catalog/products/3288/

![image](https://user-images.githubusercontent.com/3526796/40871144-a68bcce0-663e-11e8-95e0-ff7b4c39aafd.png)



Discussion:
it's prices from 1C file:
```
<Цены>
    <Цена>
        <Представление>455,1507 руб. за шт</Представление>
        <ИдТипаЦены>8aa67e9a-ea34-11e6-80e1-001dd8b759b2</ИдТипаЦены>
        <ЦенаЗаЕдиницу>455.15</ЦенаЗаЕдиницу>
        <Валюта>руб</Валюта>
    </Цена>
    <Цена>
        <Представление>352,83 руб. за шт</Представление>
        <ИдТипаЦены>de02fae2-f254-11e0-b4a5-e0ca943d5d20</ИдТипаЦены>
        <ЦенаЗаЕдиницу>352.83</ЦенаЗаЕдиницу>
        <Валюта>руб</Валюта>
    </Цена>
    <Цена>
        <Представление>395,1696 руб. за шт</Представление>
        <ИдТипаЦены>8aa67e9c-ea34-11e6-80e1-001dd8b759b2</ИдТипаЦены>
        <ЦенаЗаЕдиницу>395.17</ЦенаЗаЕдиницу>
        <Валюта>руб</Валюта>
    </Цена>
    <Цена>
        <Представление>430,4526 руб. за шт</Представление>
        <ИдТипаЦены>8aa67e9b-ea34-11e6-80e1-001dd8b759b2</ИдТипаЦены>
        <ЦенаЗаЕдиницу>430.45</ЦенаЗаЕдиницу>
        <Валюта>руб</Валюта>
    </Цена>
    <Цена>
        <Представление>606 руб. за шт</Представление>
        <ИдТипаЦены>e10b18e6-ea25-11e6-80e1-001dd8b759b2</ИдТипаЦены>
        <ЦенаЗаЕдиницу>606</ЦенаЗаЕдиницу>
        <Валюта>руб</Валюта>
    </Цена>
</Цены>
```

And it's prices from se78:
![image](https://user-images.githubusercontent.com/3526796/40871218-496e5102-6640-11e8-8e5d-2b17497c0dc9.png)

1C increases prices for this values:
- 1% for retail
- 1.8%, 1.65%, 1.5% for big/medium/small wholesale

So, i'll take this rules to convert from 1C:
- `floor(price * 0.99)`
- `floor(price * 0.98, precision=2)` for every wholesale price

Resolving patch:
diff --git a/shopelectro/management/commands/_update_catalog/update_products.py b/shopelectro/management/commands/_update_catalog/update_products.py
--- a/shopelectro/management/commands/_update_catalog/update_products.py
+++ b/shopelectro/management/commands/_update_catalog/update_products.py
@@ -1,4 +1,5 @@
 import logging
+import typing
 from collections import defaultdict
 from copy import deepcopy
 from functools import reduce
@@ -14,7 +15,7 @@
 from django.template.loader import render_to_string
 
 from shopelectro.management.commands._update_catalog.utils import (
-    XmlFile, is_correct_uuid, NOT_SAVE_TEMPLATE, UUID, Data,
+    XmlFile, is_correct_uuid, NOT_SAVE_TEMPLATE, UUID, Data, floor
 )
 from shopelectro.models import Product, ProductPage, Tag
 
@@ -57,23 +58,30 @@ def fetch_products(root: Element, config: XmlFile) -> Iterator:
         }
 
 
-def fetch_prices(root: Element, config) -> Iterator:
-    def get_prices(prices_el):
-        def get_(price_el: Element) -> float:
-            return float(price_el.find(config.xpaths['price']).text)
-        def prepare_retail_(price: float):
-            return round(price - settings.PRICE_REDUCER)
-        *prices, retail_price = sorted(
-            get_(price)
-            for price in prices_el.findall(config.xpaths['prices'])
+def fetch_prices(root: Element, config) -> typing.Iterator:
+    def get_price_values(prices_el):
+        return list(sorted(
+            float(price_el.find(config.xpaths['price']).text)
+            for price_el in prices_el.findall(config.xpaths['prices'])
+        ))
+    def multiply(prices: typing.List[float]):
+        *wholesale_prices, retail_price = prices
+        def floor_prices(prices, precision: floor):
+            return [
+                floor(price * multiplier, precision)
+                for price, multiplier in zip(prices, settings.PRICE_MULTIPLIERS)
+            ]
+        return (
+            floor_prices(wholesale_prices, precision=2)
+            + floor_prices([retail_price], precision=0)
         )
-        return prices + [prepare_retail_(retail_price)]
+
     product_price_els = root.findall(config.xpaths['product_prices'])
     for prices_el in product_price_els:
         product_uuid = prices_el.find(config.xpaths['product_uuid']).text
         prices = dict(zip(
             config.extra_options['price_types'],
-            get_prices(prices_el)
+            multiply(get_price_values(prices_el))
         ))
         yield product_uuid, prices
 
diff --git a/shopelectro/management/commands/_update_catalog/utils.py b/shopelectro/management/commands/_update_catalog/utils.py
--- a/shopelectro/management/commands/_update_catalog/utils.py
+++ b/shopelectro/management/commands/_update_catalog/utils.py
@@ -1,5 +1,6 @@
 import glob
 import logging
+import math
 import os
 import shutil
 import subprocess
@@ -21,6 +22,16 @@
                     ' saved'
 
 
+def floor(x: float, precision=0) -> float:
+    """
+    The same behaviour as `math.floor`, but with precision
+
+    >>> floor(1.234, precision=2)  # result: 1.23
+    """
+    k = 10**precision
+    return math.floor(x * k) / k
+
+
 def is_correct_uuid(uuid_):
     try:
         val = UUID(uuid_)
diff --git a/shopelectro/settings/base.py b/shopelectro/settings/base.py
--- a/shopelectro/settings/base.py
+++ b/shopelectro/settings/base.py
@@ -348,3 +348,5 @@
 TAG_GROUPS_TITLE_DELIMITER = ' и '
 
 TAGS_ORDER = ['group__position', 'group__name', 'position', 'name']
+
+PRICE_MULTIPLIERS = [float(p) for p in os.getenv('PRICE_MULTIPLIERS').split(', ')]


Test patch:
diff --git a/shopelectro/tests/tests_commands.py b/shopelectro/tests/tests_commands.py
--- a/shopelectro/tests/tests_commands.py
+++ b/shopelectro/tests/tests_commands.py
@@ -57,7 +57,7 @@ def test_delete_xml(self):
         self.assertEqual(len(file_paths), 0)
 
     def test_update_products(self):
-        new_data = {'price': 123}
+        new_data = {'price': 12345.1}
         update_products_count = 30
 
         product_data = {