From 62a53e33bebddd89ba8e2466e1d3ed4e6cb7a503 Mon Sep 17 00:00:00 2001 From: copift Date: Mon, 29 Sep 2025 23:17:00 +0800 Subject: [PATCH 1/2] homework --- Src/Core/abstract_model.py | 30 ++++++++++------------ Src/Core/validator.py | 2 ++ Src/Models/company_model.py | 47 +++++++++++++++++++++------------- Src/Models/storage_model.py | 48 ++++++++++++++++++++++++++-------- Src/settings_manager.py | 9 ++++--- Tst/settings.json | 2 +- Tst/test_models.py | 51 ++++++++++++++++++++++++++++++++++--- 7 files changed, 137 insertions(+), 52 deletions(-) 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/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/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() From e6d6a5d914bbe542bc48b807635dd41d678bfa1d Mon Sep 17 00:00:00 2001 From: copift Date: Tue, 30 Sep 2025 16:22:06 +0800 Subject: [PATCH 2/2] add other models --- Src/Models/nomenclature_group_model.py | 28 +++ Src/Models/nomenclature_model.py | 68 +++++++ Src/Models/unit_model.py | 47 +++++ _legacy/index.html | 2 + _legacy/legacy.png | Bin 0 -> 11570 bytes _legacy/main.py | 251 +++++++++++++++++++++++++ _legacy/readme.md | 29 +++ 7 files changed, 425 insertions(+) create mode 100644 Src/Models/nomenclature_group_model.py create mode 100644 Src/Models/nomenclature_model.py create mode 100644 Src/Models/unit_model.py create mode 100644 _legacy/index.html create mode 100644 _legacy/legacy.png create mode 100644 _legacy/main.py create mode 100644 _legacy/readme.md 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/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/_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
NdPnWtSrCzwPtSob
 123456
78910111213
14151617181920
21222324252627
28293031   
\ No newline at end of file diff --git a/_legacy/legacy.png b/_legacy/legacy.png new file mode 100644 index 0000000000000000000000000000000000000000..4064afbe54bad140797798f15a697d1a63c145c7 GIT binary patch literal 11570 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 Bkk0@B literal 0 HcmV?d00001 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** календарь на текущий месяц. +Получен следующий вариант: + +| | +|------| +|![legacy.png](legacy.png) +| | + +Заказчик просит внести изменения. + +> К сожалению, разработчик, которому ранее было поручено создать данный календарь не завершил работу. +> Увы, он сильно заболел и не доступен для консультаций. +> По мнению менеджмента, для Вас не должно составить никаких проблем. + +Вам необходимо: +- Дописать программу. Сделать выгрузку календаря в формат HTML, в файл. Наименование файла должен определять Заказчик (произвольное), но расширение - строго HTML +- Сделать календарь на русском языке по умолчанию. Так же, добавить разные языки: английский, немецкий. В перспективе, язык должен настраиваться. +- Календарь должен отображаться в зависимости от языка. Если русский, то начинаться с понедельника, если западный язык, то с воскресенья, как сейчас. +- Суббота и воскресенье должны отмечаться одним цветом. Фон светло красный, а цвет текста - ярко красный. Праздник (23 фебраля, 8-е марта и прочее) должен отображаться синим цветом и светло синим фоном. +Календарь должен формироваться за любой указанный месяц Заказчиком. + + +[Вот файл с программой который передал нам коллега](main.py)
+**Удачи, бро!** + +