diff --git a/Src/Core/abstract_model.py b/Src/Core/abstract_model.py
index e0c056d..7626975 100644
--- a/Src/Core/abstract_model.py
+++ b/Src/Core/abstract_model.py
@@ -2,28 +2,26 @@
import uuid
from Src.Core.validator import validator
-class abstact_model(ABC):
- __unique_code:str
+class abstract_reference(ABC):
+ __name:str
- def __init__(self) -> None:
+ def __init__(self,name:str) -> None:
super().__init__()
- self.__unique_code = uuid.uuid4().hex
+ self.name = name
+
+
"""
- Уникальный код
+ Уникальный имя
"""
@property
- def unique_code(self) -> str:
- return self.__unique_code
+ def name(self) -> str:
+ return self.__name
- @unique_code.setter
- def unique_code(self, value: str):
- validator.validate(value, str)
- self.__unique_code = value.strip()
+ @name.setter
+ def name(self, value: str):
+ validator.validate(value, str,50)
+ self.__name = value.strip()
- """
- Перегрузка штатного варианта сравнения
- """
- def __eq__(self, value: str) -> bool:
- return self.__unique_code == value
+
diff --git a/Src/Core/validator.py b/Src/Core/validator.py
index 8fc3ad3..19f47ee 100644
--- a/Src/Core/validator.py
+++ b/Src/Core/validator.py
@@ -11,6 +11,8 @@ class argument_exception(Exception):
class operation_exception(Exception):
pass
+class error_proxy(Exception):
+ pass
"""
Набор проверок данных
diff --git a/Src/Models/company_model.py b/Src/Models/company_model.py
index 24e7487..ae126c6 100644
--- a/Src/Models/company_model.py
+++ b/Src/Models/company_model.py
@@ -1,32 +1,44 @@
from Src.Core.validator import validator
-from Src.Core.abstract_model import abstact_model
+from Src.Core.abstract_model import abstract_reference
+
+
###############################################
# Модель организации
-class company_model(abstact_model):
- __name:str = ""
+class company_model(abstract_reference):
+ """
+ Модель компании/организации.
+
+ Наследуется от abstract_reference и содержит реквизиты компании для финансовых операций.
+ Может инициализироваться данными из настроек приложения.
+
+ Attributes:
+ name (str): Название компании (наследуется от abstract_reference)
+ inn (int): ИНН (Идентификационный номер налогоплательщика) - 12 символов
+ bic (int): БИК (Банковский идентификационный код) - 9 символов
+ corr_account (int): Корреспондентский счет - 11 символов
+ account (int): Расчетный счет - 11 символов
+ ownership (str): Вид собственности - 5 символов
+ """
+
__inn:int = 0
__bic:int = 0
__corr_account:int = 0
__account:int = 0
__ownership:str = ""
+ def __init__(self, settings):
- # ИНН : 12 симв
- # Счет 11 симв
- # Корреспондентский счет 11 симв
- # БИК 9 симв
- # Наименование
- # Вид собственности 5 симв
+ if settings.company is not None and validator.validate(settings.company, company_model):
+ # Копируем все поля из настроек
+ super().__init__(settings.company.name)
+ #self.__name = settings.company.name
+ self.__inn = settings.company.inn
+ self.__bic = settings.company.bic
+ self.__corr_account = settings.company.corr_account
+ self.__account = settings.company.account
+ self.__ownership = settings.company.ownership
- # Наименование
- @property
- def name(self) -> str:
- return self.__name
- @name.setter
- def name(self, value:str):
- validator.validate(value, str)
- self.__name = value.strip()
# ИНН
@property
@@ -76,7 +88,6 @@ def ownership(self, value:str):
validator.validate(value, str, 5)
self.__ownership = value.strip()
-
diff --git a/Src/Models/nomenclature_group_model.py b/Src/Models/nomenclature_group_model.py
new file mode 100644
index 0000000..ecbfb45
--- /dev/null
+++ b/Src/Models/nomenclature_group_model.py
@@ -0,0 +1,28 @@
+from Src.Core.abstract_model import abstract_reference
+from Src.Core.validator import validator
+
+
+class nomenclature_group_model(abstract_reference):
+ """
+ Модель группы номенклатуры.
+
+ Наследуется от abstract_reference и добавляет описание для группы товаров/продуктов.
+
+ Attributes:
+ name (str): Название группы номенклатуры (наследуется от abstract_reference)
+ description (str): Описание группы номенклатуры
+
+
+ """
+ __description: str = ""
+
+
+ # description (str): Описание группы номенклатуры
+ @property
+ def description(self) -> str:
+ return self.__description
+
+ @description.setter
+ def description(self, value: str):
+ validator.validate(value, str)
+ self.__description = value.strip()
diff --git a/Src/Models/nomenclature_model.py b/Src/Models/nomenclature_model.py
new file mode 100644
index 0000000..afe96dd
--- /dev/null
+++ b/Src/Models/nomenclature_model.py
@@ -0,0 +1,68 @@
+from Src.Core.abstract_model import abstract_reference
+from Src.Core.validator import validator, argument_exception
+from Src.Models.nomenclature_group_model import nomenclature_group_model
+from Src.Models.unit_model import unit_model
+
+
+class nomenclature_model(abstract_reference):
+ """
+ Модель номенклатуры товара/продукта.
+
+ Наследуется от abstract_reference и содержит полную информацию о товаре,
+ включая артикул, группу и единицу измерения.
+
+ Attributes:
+ name (str): Краткое название номенклатуры (наследуется от abstract_reference)
+ full_name (str): Полное наименование номенклатуры
+ article (str): Артикул товара
+ group (nomenclature_group_model): Группа номенклатуры
+ unit (unit_model): Единица измерения товара
+
+
+ """
+ __full_name: str = ""
+ __article: str = ""
+ __group: nomenclature_group_model = None
+ __unit: unit_model = None
+
+ #full_name (str): Полное наименование номенклатуры
+ @property
+ def full_name(self):
+ return self.__full_name
+
+ @full_name.setter
+ def full_name(self, value:str):
+ validator.validate(value, str, 255)
+ self.__full_name = value
+
+ #article (str): Артикул товара
+ @property
+ def article(self) -> str:
+ return self.__article
+
+ @article.setter
+ def article(self, value: str):
+ validator.validate(value, str, 10)
+ self.__article = value.strip()
+
+ #group (nomenclature_group_model): Группа номенклатуры
+ @property
+ def group(self) -> nomenclature_group_model:
+ return self.__group
+
+ @group.setter
+ def group(self, value: nomenclature_group_model):
+ if value and not isinstance(value, nomenclature_group_model):
+ raise argument_exception("Группа должна быть объектом nomenclature_group_model")
+ self.__group = value
+
+ #unit (unit_model): Единица измерения товара
+ @property
+ def unit(self) -> unit_model:
+ return self.__unit
+
+ @unit.setter
+ def unit(self, value: unit_model):
+ if value and not isinstance(value, unit_model):
+ raise argument_exception("Единица измерения должна быть объектом unit_model")
+ self.__unit = value
diff --git a/Src/Models/storage_model.py b/Src/Models/storage_model.py
index 5af8e1a..a162b01 100644
--- a/Src/Models/storage_model.py
+++ b/Src/Models/storage_model.py
@@ -1,15 +1,43 @@
-from Src.Core.validator import validator
-from Src.Core.abstract_model import abstact_model
+from Src.Core.validator import validator, argument_exception
+from Src.Core.abstract_model import abstract_reference
+from Src.Models.company_model import company_model
-class storage_model(abstact_model):
- __name:str = ""
- # Наименование
+class storage_model(abstract_reference):
+ """
+ Модель склада/хранилища.
+
+ Наследуется от abstract_reference и добавляет информацию о местоположении
+ и принадлежности к компании.
+
+ Attributes:
+ name (str): Название склада (наследуется от abstract_reference)
+ address (str): Физический адрес расположения склада
+ company (company_model): Компания-владелец склада
+
+ """
+
+ __name: str = ""
+ __address: str = ""
+ __company: company_model = None
+
+
+ # address (str): Физический адрес расположения склада
@property
- def name(self) -> str:
- return self.__name
+ def address(self) -> str:
+ return self.__address
- @name.setter
- def name(self, value:str):
+ @address.setter
+ def address(self, value: str):
validator.validate(value, str)
- self.__name = value.strip()
+ self.__address = value.strip()
+
+ # company (company_model): Компания-владелец склада
+ @property
+ def company(self) -> company_model:
+ return self.__company
+
+ @company.setter
+ def company(self, value: company_model):
+ validator.validate(value, company_model)
+ self.__company = value
\ No newline at end of file
diff --git a/Src/Models/unit_model.py b/Src/Models/unit_model.py
new file mode 100644
index 0000000..9f15b33
--- /dev/null
+++ b/Src/Models/unit_model.py
@@ -0,0 +1,47 @@
+from __future__ import annotations
+from Src.Core.abstract_model import abstract_reference
+from Src.Core.validator import validator
+
+
+class unit_model(abstract_reference):
+ """
+ Модель единицы измерения для системы конвертации величин.
+
+ Представляет собой узел в иерархической системе единиц измерения,
+ где каждая единица может быть связана с базовой через коэффициент преобразования.
+
+ Attributes:
+ name (str): Наименование единицы измерения (наследуется от AbstractReference).
+ ratio (int): Коэффициент преобразования к базовой единице. По умолчанию 1.
+ base_model (UnitModel): Ссылка на базовую модель единицы измерения.
+ Если None, текущая единица считается базовой.
+
+ """
+ __ratio: int = 1
+ __base_model: unit_model = None
+
+ def __init__(self, name: str, ratio: int = 1, base_model: unit_model = None):
+ super().__init__(name)
+ # self.__name = name
+ self.__ratio = ratio
+ self.__base_model = base_model
+
+
+ #ratio (int): Коэффициент преобразования к базовой единице.
+ @property
+ def ratio(self) -> int:
+ return self.__ratio
+
+ @ratio.setter
+ def ratio(self, value: int):
+ self.__ratio = value
+
+ #base_model (UnitModel): Ссылка на базовую модель единицы измерения.
+ @property
+ def base_model(self) -> unit_model:
+ return self.__base_model
+
+ @ratio.setter
+ def ratio(self, value:unit_model):
+ self.__base_model = value
+
diff --git a/Src/settings_manager.py b/Src/settings_manager.py
index ec87dfe..1addf02 100644
--- a/Src/settings_manager.py
+++ b/Src/settings_manager.py
@@ -6,7 +6,7 @@
import os
import json
-####################################################
+####################################################3
# Менеджер настроек.
# Предназначен для управления настройками и хранения параметров приложения
class settings_manager:
@@ -80,12 +80,13 @@ def convert(self, data: dict) -> bool:
# Параметры настроек по умолчанию
def set_default(self):
- company = company_model()
+ self.__settings = settings_model()
+
+ company = company_model(settings=settings_model())
company.name = "Рога и копыта"
company.inn = -1
-
- self.__settings = settings_model()
self.__settings.company = company
+
diff --git a/Tst/settings.json b/Tst/settings.json
index 9fce5d6..834a6f2 100644
--- a/Tst/settings.json
+++ b/Tst/settings.json
@@ -2,6 +2,6 @@
"company":
{
"name":"Рога и копыта",
- "inn1":123456789
+ "inn":123456789
}
}
diff --git a/Tst/test_models.py b/Tst/test_models.py
index bccacf1..f65ca2a 100644
--- a/Tst/test_models.py
+++ b/Tst/test_models.py
@@ -1,3 +1,6 @@
+from Src.Models.nomenclature_group_model import nomenclature_group_model
+from Src.Models.nomenclature_model import nomenclature_model
+from Src.Models.unit_model import unit_model
from Src.settings_manager import settings_manager
from Src.Models.company_model import company_model
import unittest
@@ -67,7 +70,7 @@ def test_loadCombo_createmodel_companymodel(self):
print(f"ИНН {manager1.settings.company.inn}")
# Проверка на сравнение двух по значению одинаковых моделей
- def text_equals_storage_model_create(self):
+ def test_text_equals_storage_model_create(self):
# Подготовка
id = uuid.uuid4().hex
storage1 = storage_model()
@@ -79,8 +82,50 @@ def text_equals_storage_model_create(self):
# Проверки
assert storage1 == storage2
+ # тестирование создания модели группы номенклатуры
+ def test_nomenclature_group_model_create(self):
+ # Подготовка
+ nomenclature_group = nomenclature_group_model(name="test")
+ nomenclature_group.description="test desc"
+
+ assert nomenclature_group.name == "test" and nomenclature_group.description=="test desc"
+ # тестирование создания модели unit и использование
+ def test_unit_model(self):
+ # Подготовка
+ gr=unit_model("gr")
+ kg=unit_model("kg",1000,gr)
+
+ mass_g=150000
+ mass_kg=150
+ assert mass_kg*kg.ratio == mass_g
+
+ # тестирование создания модели номенклатуры с всеми подклассами
+ def test_nomenclature_model_create(self):
+ # Подготовка
+ nomenclature_group = nomenclature_group_model(name="test")
+
+ nomenclature_group.description = "test desc"
+
+ gr = unit_model("gr")
+ kg = unit_model("kg", 1000, gr)
+
+ nomenclature=nomenclature_model(name="test nomenclature")
+ nomenclature.group=nomenclature_group
+ nomenclature.unit=kg
+
+ nomenclature.full_name="t" * 254
+ nomenclature.description="test description"
+ nomenclature.article="cle"
+
+
+ assert nomenclature
+ # тестирование создания через фаил
+ def test_company_model_file_create(self):
+ manager = settings_manager()
+ manager.file_name="settings.json"
+ company = company_model(settings=manager.settings)
+
+ assert company.inn ==123456789
-
-
if __name__ == '__main__':
unittest.main()
diff --git a/_legacy/index.html b/_legacy/index.html
new file mode 100644
index 0000000..bbacbb4
--- /dev/null
+++ b/_legacy/index.html
@@ -0,0 +1,2 @@
+
+
Styczen 2024 | Nd | Pn | Wt | Sr | Czw | Pt | Sob | | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | | | |
|
\ No newline at end of file
diff --git a/_legacy/legacy.png b/_legacy/legacy.png
new file mode 100644
index 0000000..4064afb
Binary files /dev/null and b/_legacy/legacy.png differ
diff --git a/_legacy/main.py b/_legacy/main.py
new file mode 100644
index 0000000..7ed6eb4
--- /dev/null
+++ b/_legacy/main.py
@@ -0,0 +1,251 @@
+import time, math
+
+
+cal_ID = 0
+
+class MonthlyCalendar:
+ def __init__(self, year = None, month = None):
+ self.tFontFace = 'Arial, Helvetica'
+ self.tFontSize = 12
+ self.tFontColor = '#FFFFFF'
+ self.tBGColor = '#304B90'
+
+ self.hFontFace = 'Arial, Helvetica'
+ self.hFontSize = 10
+ self.hFontColor = '#FFFFFF'
+ self.hBGColor = '#304B90'
+
+ self.dFontFace = 'Arial, Helvetica'
+ self.dFontSize = 12
+ self.dFontColor = '#000000'
+ self.dBGColor = '#FFFFFF'
+
+ self.wFontFace = 'Arial, Helvetica'
+ self.wFontSize = 10
+ self.wFontColor = '#FFFFFF'
+ self.wBGColor = '#304B90'
+
+ self.saFontColor = '#0000D0'
+ self.saBGColor = '#F6F6FF'
+
+ self.suFontColor = '#D00000'
+ self.suBGColor = '#FFF0F0'
+
+ self.tdBorderColor = 'red'
+
+ self.borderColor = '#304B90'
+ self.hilightColor = '#FFFF00'
+
+ self.link = ''
+ self.offset = 1
+ self.weekNumbers = 0
+
+ self.weekdays = ('Sob', 'Nd', 'Pn', 'Wt', 'Sr', 'Czw', 'Pt')
+
+ self.months = ('Styczen', 'Luty', 'Marzec', 'Kwiecien', 'Maj', 'Czerwiec',
+ 'Lipiec', 'Sierpien', 'Wrzesien', 'Pazdziernik', 'Listopad', 'Grudzien')
+
+ self.error = ('Year must be 1 - 3999!', 'Month must be 1 - 12!')
+
+ if year is None and month is None:
+ year = time.localtime().tm_year
+ month = time.localtime().tm_mon
+ elif year is None and month is not None: year = time.localtime().tm_year
+ elif month is None: month = 1
+ self.year = int(year)
+ self.month = int(month)
+ self.specDays = {}
+
+ __size = 0
+ __mDays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
+
+ def set_styles(self):
+ globals()['cal_ID'] += 1
+ html = ''
+ return html
+
+ def leap_year(self, year):
+ return not (year % 4) and (year < 1582 or year % 100 or not (year % 400))
+
+ def get_weekday(self, year, days):
+ a = days
+ if year: a += (year - 1) * 365
+ for i in range(1, year):
+ if self.leap_year(i): a += 1
+ if year > 1582 or (year == 1582 and days >= 277): a -= 10
+ if a: a = (a - self.offset) % 7
+ elif self.offset: a += 7 - self.offset
+ return a
+
+ def get_week(self, year, days):
+ firstWDay = self.get_weekday(year, 0)
+ return int(math.floor((days + firstWDay) / 7) + (firstWDay <= 3))
+
+ def table_cell(self, content, cls, date = '', style = ''):
+ size = int(round(self.__size * 1.5))
+ html = ' 0:
+ if self.specDays[content][0]:
+ style += 'background-color:' + self.specDays[content][0] + ';'
+ if self.specDays[content][1]:
+ html += ' title="' + self.specDays[content][1] + '"'
+ if self.specDays[content][2]:
+ link = self.specDays[content][2]
+ style += 'cursor:pointer' + ';'
+ else:
+ link='brak'
+ style += 'cursor:pointer' + ';'
+
+ if link=='brak':
+ html += ' onMouseOver="this.className=\'cssHilight' + str(globals()['cal_ID']) + '\'"'
+ html += ' onMouseOut="this.className=\'' + cls + '\'"'
+ html += ' onClick="document.location.href=\'' + '?date=' + date + '\'"'
+
+
+ if link and link!='brak':
+ html += ' onMouseOver="this.className=\'cssHilight' + str(globals()['cal_ID']) + '\'"'
+ html += ' onMouseOut="this.className=\'' + cls + '\'"'
+ html += ' onClick="document.location.href=\'' + link + '?date=' + date + '\'"'
+ if style: html += ' style="' + style + '"'
+ html += '>' + content + ' | '
+ return html
+
+ def table_head(self, content):
+ cols = self.weekNumbers and '8' or '7'
+ html = '' + \
+ content + ' |
'
+ for i in range(len(self.weekdays)):
+ ind = (i + self.offset) % 7
+ wDay = self.weekdays[ind]
+ html += self.table_cell(wDay, 'cssHeading' + str(globals()['cal_ID']))
+ if self.weekNumbers: html += self.table_cell(' ', 'cssHeading' + str(globals()['cal_ID']))
+ html += '
'
+ return html
+
+ def viewEvent(self, start, end, color, title, link = ''):
+ if start > end: return
+ if start < 1 or start > 31: return
+ if end < 1 or end > 31: return
+ while start <= end:
+ self.specDays[str(start)] = [color, title, link]
+ start += 1
+
+ def create(self):
+ self.__size = (self.hFontSize > self.dFontSize) and self.hFontSize or self.dFontSize
+ if self.wFontSize > self.__size: self.__size = self.wFontSize
+
+ date = time.strftime('%Y-%m-%d', time.localtime())
+ (curYear, curMonth, curDay) = [int(v) for v in date.split('-')]
+
+ if self.year < 1 or self.year > 3999: html = '' + self.error[0] + ''
+ elif self.month < 1 or self.month > 12: html = '' + self.error[1] + ''
+ else:
+ if self.leap_year(self.year): self.__mDays[1] = 29
+ days = 0
+ for i in range(self.month - 1): days += self.__mDays[i]
+
+ start = self.get_weekday(self.year, days)
+ stop = self.__mDays[self.month-1]
+
+ html = self.set_styles()
+ html += ''
+ html += ''
+ html += ''
+ title = self.months[self.month-1] + ' ' + str(self.year)
+ html += self.table_head(title)
+ daycount = 1
+
+ if self.year == curYear and self.month == curMonth: inThisMonth = 1
+ else: inThisMonth = 0
+
+ if self.weekNumbers: weekNr = self.get_week(self.year, days)
+
+ while daycount <= stop:
+ html += ''
+ wdays = 0
+
+ for i in range(len(self.weekdays)):
+ ind = (i + self.offset) % 7
+ if ind == 0: cls = 'cssSaturdays'
+ elif ind == 1: cls = 'cssSundays'
+ else: cls = 'cssDays'
+
+ style = ''
+ date = "%s-%s-%s" % (self.year, self.month, daycount)
+
+ if (daycount == 1 and i < start) or daycount > stop: content = ' '
+ else:
+ content = str(daycount)
+ if inThisMonth and daycount == curDay:
+ style = 'padding:0px;border:3px solid ' + self.tdBorderColor + ';'
+ elif self.year == 1582 and self.month == 10 and daycount == 4: daycount = 14
+ daycount += 1
+ wdays += 1
+
+ html += self.table_cell(content, cls + str(globals()['cal_ID']), date, style)
+
+ if self.weekNumbers:
+ if not weekNr:
+ if self.year == 1: content = ' '
+ elif self.year == 1583: content = '52'
+ else: content = str(self.get_week(self.year - 1, 365))
+ elif self.month == 12 and weekNr >= 52 and wdays < 4: content = '1'
+ else: content = str(weekNr)
+
+ html += self.table_cell(content, 'cssWeeks' + str(globals()['cal_ID']))
+ weekNr += 1
+
+ html += ' '
+ html += ' |
'
+ return html
+
+
+if __name__ == "__main__":
+ filepath = "calendar.html"
+ calendar = MonthlyCalendar()
+ body = calendar.create()
+ html = f"{body}"
+ file = open(filepath, "w")
+ file.write(html)
+ file.close()
+
diff --git a/_legacy/readme.md b/_legacy/readme.md
new file mode 100644
index 0000000..75de7ac
--- /dev/null
+++ b/_legacy/readme.md
@@ -0,0 +1,29 @@
+# Legacy
+Первое задание
+
+Перед Вами программа которая формирует в формате **HTML** календарь на текущий месяц.
+Получен следующий вариант:
+
+| |
+|------|
+|
+| |
+
+Заказчик просит внести изменения.
+
+> К сожалению, разработчик, которому ранее было поручено создать данный календарь не завершил работу.
+> Увы, он сильно заболел и не доступен для консультаций.
+> По мнению менеджмента, для Вас не должно составить никаких проблем.
+
+Вам необходимо:
+- Дописать программу. Сделать выгрузку календаря в формат HTML, в файл. Наименование файла должен определять Заказчик (произвольное), но расширение - строго HTML
+- Сделать календарь на русском языке по умолчанию. Так же, добавить разные языки: английский, немецкий. В перспективе, язык должен настраиваться.
+- Календарь должен отображаться в зависимости от языка. Если русский, то начинаться с понедельника, если западный язык, то с воскресенья, как сейчас.
+- Суббота и воскресенье должны отмечаться одним цветом. Фон светло красный, а цвет текста - ярко красный. Праздник (23 фебраля, 8-е марта и прочее) должен отображаться синим цветом и светло синим фоном.
+Календарь должен формироваться за любой указанный месяц Заказчиком.
+
+
+[Вот файл с программой который передал нам коллега](main.py)
+**Удачи, бро!**
+
+