Skip to content

Commit

Permalink
Доработка проверки периодов отчёта
Browse files Browse the repository at this point in the history
  • Loading branch information
WoolenSweater committed Sep 22, 2020
1 parent 3a680d6 commit 591a6c3
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 18 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# CHANGELOG

### [0.6.3] - 2020-09-22

- Доработка проверки периодов. Если формат периода отчета отличается от описанного формата в документации. Происходит попытка конвертации его допустимый. Механизм конвертации должен полностью повторять аналогичный в оффициальной программе от РосСтата.
- Вернул на место проверку формата значений ячеек. Удалил по невнимательности.


### [0.6.2] - 2020-09-21

- Доработка проверок формата строк и значений в графах:
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# РосСтат ФЛК

Форматно-логический контроль отчетности РосСтата.
Инструмент для форматно-логического контроля отчетности, отправляемой в РосСтат.

Документация описывающая формат отчетности и контроли - [Приказ РосСтата от 28.10.2010 №372](http://www.consultant.ru/document/cons_doc_LAW_115689/)

**Не готово для использования в продакшене! [CHANGELOG](CHANGELOG.md)**
Список изменений - [CHANGELOG](CHANGELOG.md)

## Установка
```bash
Expand Down
62 changes: 52 additions & 10 deletions rosstat/report.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,20 @@
from .validator.schema import str_int


def max_divider(num, terms):
def _calc(a, b):
mn = min(a, b)
mx = max(a, b)
for i in range(mn, 1, -1):
if mn % i == 0 and mx % i == 0:
return i
return 1

for term_id in terms:
num = _calc(num, int(term_id))
return num


@dataclass
class Row:
code: str
Expand Down Expand Up @@ -73,8 +87,9 @@ class Report:
_year: str = None
_title: Dict[str, str] = None
_data: Dict[str, Section] = None
_period_raw: str = None
_period_type: Optional[str] = None
_period_code: str = None
_period_code: Optional[str] = None
_row_counters: defdict = f(default_factory=lambda: defdict(int))

def __repr__(self):
Expand Down Expand Up @@ -148,14 +163,41 @@ def _read_data(self, xml):
def _read_row_specs(self, row):
return (row.attrib.get(f's{i}') for i in range(1, 4))

def _get_periods(self, xml):
period = xml.xpath('/report/@period')[0]
if len(period) != 4:
self._period_code = str_int(period)
else:
period_type, period_code = period[:2], period[2:]
self._period_type = str_int(period_type)
self._period_code = str_int(period_code)

def _get_year(self, xml):
self._year = xml.xpath('/report/@year')[0]

def _get_periods(self, xml):
self._period_raw = xml.xpath('/report/@period')[0]
if len(self._period_raw) == 4:
self._period_type = str_int(self._period_raw[:2])
self._period_code = str_int(self._period_raw[2:])

def set_periods(self, schema):
try:
periods_id = self._get_periods_id(schema.dics)

if int(self._period_raw) not in periods_id:
return False

max_code = max(periods_id)

if max_code <= int(schema.idp):
self._period_type = schema.idp
self._period_code = self._period_raw
return True

max_div = max_divider(max_code, periods_id)

if max_code <= int(schema.idp) * max_div:
self._period_type = schema.idp
self._period_code = str(int(int(self._period_raw) / max_div))
return True
return False
except Exception as ex:
return False

def _get_periods_id(self, dics):
try:
return [int(term_id) for term_id in dics['s_time'].keys()]
except KeyError:
return [int(term_id) for term_id in dics['s_mes'].keys()]
6 changes: 4 additions & 2 deletions rosstat/validator/checkers/format.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def check(self, obj, spec=None, specs_map=None):
self._check_row(obj, spec, specs_map)

def _check_cell(self, cell):
'''Метод вызова проверки формата значения'''
'''Метод проверки значения'''
self.__check_format(cell)
if self.vld_type == '1':
self.__check_value_dic(cell)
Expand All @@ -59,6 +59,7 @@ def _check_cell(self, cell):
self.__check_value_list(cell)

def _check_row(self, row, spec, specs_map):
'''Метод проверки специфик строки'''
if self.vld_type == '4':
self.__check_value_dic_add(row, spec)
elif self.vld_type == '5':
Expand Down Expand Up @@ -88,11 +89,12 @@ def __check_value_list(self, value):
raise OutOfList()

def __check_value_dic_add(self, row, spec):
'''Проверка на вхождение в справочник приложение'''
'''Проверка на вхождение в справочник'''
if getattr(row, spec) not in self._dics[self.vld_param]:
raise OutOfAdditionDict()

def __check_value_dic_coord(self, row, spec, specs_map):
'''Проверка на вхождение в справочник и связь с главной спецификой'''
dic, coords = self.vld_param.split('=#')
*_, c_idx = coords.split(',')
spec_value = getattr(row, spec)
Expand Down
10 changes: 7 additions & 3 deletions rosstat/validator/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def _prepare_format(self):
return form

def _get_adds(self, section, section_code):
'''Получение дополнительных данных для проверки: черекеры по умолчанию,
'''Получение дополнительных данных для проверки: чекеры по умолчанию,
заполнение словаря размерности секций отчёта, определение имен
колонок специфик
'''
Expand Down Expand Up @@ -134,11 +134,14 @@ def _check(self, report):
break

def _check_attributes(self, report):
'''Проверка соответствия атрибутов шаблона: периода и года'''
'''Проверка соответствия атрибутов шаблона: периодов и года'''
if report.period_type is not None and report.period_type != self.idp:
self._add_error('Тип периодичности отчёта не соответствует '
'типу периодичности шаблона')

if report.period_code is None and not report.set_periods(self):
self._add_error('Неверное значение периода отчёта')

if not year_pattern.match(report.year):
self._add_error('Указан недопустимый год')

Expand Down Expand Up @@ -206,6 +209,7 @@ def _check_format(self, report):
for r_idx, rows in section.items():
for row in rows:
self.__check_row(row, s_idx, r_idx)
self.__check_cells(row, s_idx, r_idx)

def __check_row(self, row, s_idx, r_idx):
'''Итерация по ожидаемым спецификам с их последующей проверкой'''
Expand Down Expand Up @@ -233,7 +237,7 @@ def __check_fmt(self, s_idx, r_idx, c_idx, *args, err_msg=None):
print('Unexpected Error', traceback.format_exc())

def __get_format_checker(self, s_idx, r_idx, c_idx):
'''Получение чекера для поля'''
'''Получение чекера для поля/строки'''
try:
return self.format[s_idx][r_idx][c_idx]
except KeyError:
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

setup(
name='rosstat-flc',
version='0.6.2',
version='0.6.3',
description='Tool for format-logistic control of reports sent to RosStat',
long_description=open('README.md', 'r').read(),
long_description_content_type="text/markdown",
Expand Down

0 comments on commit 591a6c3

Please sign in to comment.