diff --git a/kodorvan/constructor/system/databases/scripts/workers.php b/kodorvan/constructor/system/databases/scripts/workers.php new file mode 100644 index 0000000..8902ba4 --- /dev/null +++ b/kodorvan/constructor/system/databases/scripts/workers.php @@ -0,0 +1,75 @@ +read( + filter: fn(record $record) => $record->domain === 'buddy_volkodav', +); + +var_dump($account); + +// Searching for the account authorizations +$authorizations = $account->authorizations(); + +var_dump($authorizations); + +// Creating the worker +$worker = new worker()->write( + account: $account->identifier, + hour: 2000, + currency: currency::rub, + active: true +); + +var_dump($worker); + diff --git a/kodorvan/constructor/system/localizations/russian.php b/kodorvan/constructor/system/localizations/russian.php index a89191f..7b49ca8 100644 --- a/kodorvan/constructor/system/localizations/russian.php +++ b/kodorvan/constructor/system/localizations/russian.php @@ -26,10 +26,14 @@ return [ 'project_create_title' => 'Создание проекта', /* 'project_create_description' => "Расчитайте ориентировочное время разработки, затем выберите разработчиков и получите стоимость\n\nПосле расчётов можно будет отправить проект в заказ разработчикам и приложить ТЗ, либо краткое описание задачи\n\nМы погружаемся в проекты полностью, поэтому стараемся не распыляться - от степени нагрузки меняется коэффициент стоимости!", */ 'project_create_description' => "Задайте параметры и получите ориентировочное время разработки, затем выберите разработчиков и получите стоимость их работы\n\n_После расчётов можно отправить проект в заказ и приложить ТЗ, либо описание задачи_", + 'project_create_cost_description' => "Стоимость и сроки выполнения предоставлены для планирования и *не являются публичной офертой*", 'project_create_time' => 'Время разработки', 'project_create_time_hours' => 'ч', 'project_create_time_hours_from' => 'от', + 'project_create_time_days' => 'дн', + 'project_create_cost' => 'Стоимость', 'project_create_button_back' => 'Назад', + 'project_create_button_cost_per_hour' => 'Час', 'project_create_button_request' => 'Заказать', 'project_create_architectures_title' => 'Выбор архитектуры проекта', diff --git a/kodorvan/constructor/system/models/account.php b/kodorvan/constructor/system/models/account.php index 1068b6c..41b44d7 100644 --- a/kodorvan/constructor/system/models/account.php +++ b/kodorvan/constructor/system/models/account.php @@ -8,6 +8,7 @@ namespace kodorvan\constructor\models; use kodorvan\constructor\models\core, kodorvan\constructor\models\authorizations, kodorvan\constructor\models\settings, + kodorvan\constructor\models\worker, kodorvan\constructor\models\project, kodorvan\constructor\models\project\enumerations\type as project_type, kodorvan\constructor\models\project\enumerations\status as project_status; @@ -65,6 +66,13 @@ final class account extends core implements record_interface */ public protected(set) database $database; + /** + * Serialized + * + * @var bool $serialized Is the implementator object serialized? + */ + private bool $serialized = true; + /** * Constructor * @@ -84,6 +92,7 @@ final class account extends core implements record_interface new column('name_first', type::string, ['length' => 64]), new column('name_second', type::string, ['length' => 64]), new column('language', type::string, ['length' => 2]), + new column('currency', type::string, ['length' => 3]), new column('robot', type::char), /* new column('', type::), */ new column('active', type::char), @@ -215,6 +224,7 @@ final class account extends core implements record_interface name_second: (string) $telegram->last_name, domain: (string) $telegram->username, language: (string) $telegram->language_code, + currency: CURRENCY_DEFAULT, robot: (bool) $telegram->is_bot ); @@ -256,6 +266,7 @@ final class account extends core implements record_interface * @param string $name_second * @param string $domain * @param language|string $language + * @param currency|string $currency * @param bool $robot Is a robot? * @param bool $active Is the record active? * @@ -267,6 +278,7 @@ final class account extends core implements record_interface string $name_first = '', string $name_second = '', language|string $language = LANGUAGE_DEFAULT ?? language::en, + currency|string $currency = CURRENCY_DEFAULT ?? currency::usd, bool $robot = false, bool $active = true, ): record|false { @@ -278,6 +290,7 @@ final class account extends core implements record_interface $name_first, $name_second, $language instanceof language ? $language->name : (string) $language, + $currency instanceof currency ? $currency->name : (string) $currency, (int) $robot, /* */ (int) $active, @@ -299,11 +312,22 @@ final class account extends core implements record_interface */ public function serialize(): self { + if ($this->serialized) { + // The record implementor is serialized + + // Exit (fail) + throw new exception_runtime('The record implementor is already serialized'); + } + // Serializing the record parameters $this->record->language = $this->record->language->name; + $this->record->currency = $this->record->currency->name; $this->record->robot = (int) $this->record->robot; $this->record->active = (int) $this->record->active; + // Writing the status of serializing + $this->serialized = true; + // Exit (success) return $this; } @@ -315,11 +339,22 @@ final class account extends core implements record_interface */ public function deserialize(): self { + if (!$this->serialized) { + // The record implementor is deserialized + + // Exit (fail) + throw new exception_runtime('The record implementor is already deserialized'); + } + // Deserializing the record parameters $this->record->language = language::{$this->record->language} ?? LANGUAGE_DEFAULT ?? language::en; + $this->record->currency = currency::{$this->record->currency} ?? CURRENCY_DEFAULT ?? currency::usd; $this->record->robot = (bool) $this->record->robot; $this->record->active = (bool) $this->record->active; + // Writing the status of serializing + $this->serialized = false; + // Exit (success) return $this; } @@ -347,6 +382,29 @@ final class account extends core implements record_interface return null; } + /** + * Worker + * + * Search for the account worker + * + * @return worker|null The account worker + */ + public function worker(): ?worker + { + // Search for the account worker + $worker = new worker()->read(filter: fn(record $record) => $record->active === 1 && $record->account === $this->identifier); + + if ($worker instanceof worker) { + // Found the account worker + + // Exit (success) + return $worker; + } + + // Exit (fail) + return null; + } + /** * Settings * diff --git a/kodorvan/constructor/system/models/authorizations.php b/kodorvan/constructor/system/models/authorizations.php index ae19b69..31833bf 100644 --- a/kodorvan/constructor/system/models/authorizations.php +++ b/kodorvan/constructor/system/models/authorizations.php @@ -51,6 +51,13 @@ final class authorizations extends core implements record_interface */ public protected(set) database $database; + /** + * Serialized + * + * @var bool $serialized Is the implementator object serialized? + */ + private bool $serialized = true; + /** * Constructor * @@ -124,12 +131,22 @@ final class authorizations extends core implements record_interface */ public function serialize(): self { + if ($this->serialized) { + // The record implementor is serialized + + // Exit (fail) + throw new exception_runtime('The record implementor is already serialized'); + } + // Serializing the record parameters $this->record->system = (int) $this->record->system; $this->record->settings = (int) $this->record->settings; $this->record->system_settings = (int) $this->record->system_settings; $this->record->active = (int) $this->record->active; + // Writing the status of serializing + $this->serialized = true; + // Exit (success) return $this; } @@ -141,12 +158,22 @@ final class authorizations extends core implements record_interface */ public function deserialize(): self { + if (!$this->serialized) { + // The record implementor is deserialized + + // Exit (fail) + throw new exception_runtime('The record implementor is already deserialized'); + } + // Deserializing the record parameters $this->record->system = (bool) $this->record->system; $this->record->settings = (bool) $this->record->settings; $this->record->system_settings = (bool) $this->record->system_settings; $this->record->active = (bool) $this->record->active; + // Writing the status of serializing + $this->serialized = false; + // Exit (success) return $this; } diff --git a/kodorvan/constructor/system/models/project.php b/kodorvan/constructor/system/models/project.php index 41cc090..225b7e0 100644 --- a/kodorvan/constructor/system/models/project.php +++ b/kodorvan/constructor/system/models/project.php @@ -53,6 +53,13 @@ final class project extends core implements record_interface */ public protected(set) database $database; + /** + * Serialized + * + * @var bool $serialized Is the implementator object serialized? + */ + private bool $serialized = true; + /** * Constructor * diff --git a/kodorvan/constructor/system/models/project/enumerations/architecture.php b/kodorvan/constructor/system/models/project/enumerations/architecture.php index aa4353d..bf45b4d 100644 --- a/kodorvan/constructor/system/models/project/enumerations/architecture.php +++ b/kodorvan/constructor/system/models/project/enumerations/architecture.php @@ -31,10 +31,8 @@ enum architecture case chat_robot; case parser; case script; - case crm; case site; case program; - /* case calculator; */ case complex; @@ -61,9 +59,6 @@ enum architecture language::en => 'Script', language::ru => 'Скрипт' }, - static::crm => match ($language) { - default => 'CRM' - }, static::site => match ($language) { language::en => 'Site', language::ru => 'Сайт' @@ -88,13 +83,12 @@ enum architecture { // Exit (success) return match ($this) { - static::chat_robot => 2, + static::chat_robot => 1, static::parser => 1, static::script => 1, - static::crm => 1, static::site => 1, static::program => 1, - static::complex => 2, + static::complex => 4, default => 1 }; } @@ -125,8 +119,6 @@ enum architecture purpose::calculate, purpose::landing, purpose::marketplace, - purpose::events, - purpose::charity ], static::parser => [ purpose::search @@ -134,12 +126,6 @@ enum architecture static::script => [ purpose::logic ], - static::crm => [ - purpose::workers, - purpose::tools, - purpose::objects, - purpose::events - ], static::site => [ purpose::funnel, purpose::contact, @@ -149,22 +135,12 @@ enum architecture purpose::calculate, purpose::landing, purpose::marketplace, - purpose::workers, - purpose::tools, - purpose::objects, - purpose::events, - purpose::charity ], static::program => [ purpose::neural_network, purpose::crm, purpose::calculate, purpose::marketplace, - purpose::workers, - purpose::tools, - purpose::objects, - purpose::events, - purpose::charity ], default => [] }; @@ -231,10 +207,6 @@ enum architecture currency::usd => 10, currency::rub => 1000 }, - static::crm => match ($currency) { - currency::usd => 100, - currency::rub => 8000 - }, static::site => match ($currency) { currency::usd => 50, currency::rub => 5000 @@ -262,7 +234,6 @@ enum architecture static::chat_robot => 3, static::parser => 2, static::script => 1, - static::crm => 6, static::site => 3, static::program => 4, static::complex => 5, diff --git a/kodorvan/constructor/system/models/project/enumerations/integration.php b/kodorvan/constructor/system/models/project/enumerations/integration.php index 9001f01..82d8241 100644 --- a/kodorvan/constructor/system/models/project/enumerations/integration.php +++ b/kodorvan/constructor/system/models/project/enumerations/integration.php @@ -87,7 +87,7 @@ enum integration { // Exit (success) return match ($this) { - static::one_c => 5, + static::one_c => 3, static::bitrix24 => 3.5, static::moy_sklad => 3, static::telegram => 2, diff --git a/kodorvan/constructor/system/models/project/enumerations/purpose.php b/kodorvan/constructor/system/models/project/enumerations/purpose.php index 9f64af6..29271bf 100644 --- a/kodorvan/constructor/system/models/project/enumerations/purpose.php +++ b/kodorvan/constructor/system/models/project/enumerations/purpose.php @@ -28,16 +28,16 @@ enum purpose case crm; case landing; case marketplace; - case charity; + /* case charity; */ case search; case calculate; - case logic; + /* case logic; */ case game; - case workers; + /* case workers; case tools; case objects; - case events; + case events; */ case special; @@ -83,10 +83,10 @@ enum purpose language::en => 'Marketplace', language::ru => 'Маркетплейс' }, - static::charity => match ($language) { + /* static::charity => match ($language) { language::en => 'Charity', language::ru => 'Благотворительность' - }, + }, */ static::search => match ($language) { language::en => 'Search', language::ru => 'Поиск' @@ -95,15 +95,15 @@ enum purpose language::en => 'Calculate', language::ru => 'Расчёты' }, - static::logic => match ($language) { + /* static::logic => match ($language) { language::en => 'Logic', language::ru => 'Логика' - }, + }, */ static::game => match ($language) { language::en => 'Game', language::ru => 'Игра' }, - static::workers => match ($language) { + /* static::workers => match ($language) { language::en => 'Workes', language::ru => 'Рабочие' }, @@ -118,7 +118,7 @@ enum purpose static::events => match ($language) { language::en => 'Events', language::ru => 'События' - }, + }, */ static::special => match ($language) { language::en => 'Special', language::ru => 'Особенный' @@ -164,18 +164,18 @@ enum purpose integration::moy_sklad, integration::excel ], - static::charity => [ + /* static::charity => [ integration::one_c, integration::moy_sklad, integration::excel - ], + ], */ static::search => [], static::calculate => [ integration::one_c, integration::moy_sklad, integration::excel ], - static::logic => [], + /* static::logic => [], static::tools => [ integration::one_c, integration::moy_sklad, @@ -200,7 +200,7 @@ enum purpose integration::one_c, integration::moy_sklad, integration::excel - ], + ], */ default => [] }; } @@ -222,14 +222,14 @@ enum purpose static::crm => 1, static::landing => 1, static::marketplace => 2, - static::charity => 2, + /* static::charity => 2, */ static::search => 2, static::calculate => 2, - static::logic => 1, + /* static::logic => 1, static::tools => 1, static::workers => 1, static::objects => 1, - static::events => 1, + static::events => 1, */ static::special => 4, default => 1 }; @@ -244,22 +244,22 @@ enum purpose { // Exit (success) return match ($this) { - static::funnel => 1.4, + static::funnel => 2, static::contact => 1.1, - static::neural_network => 2, + static::neural_network => 4, static::game => 3, static::gallery => 1, - static::crm => 3, - static::landing => 1.2, - static::marketplace => 2, - static::charity => 0.8, + static::crm => 6, + static::landing => 1.5, + static::marketplace => 8, + /* static::charity => 0.8, */ static::search => 1, - static::calculate => 1.1, - static::logic => 1, + static::calculate => 2, + /* static::logic => 1, static::tools => 1, static::workers => 1.2, static::objects => 1, - static::events => 1.5, + static::events => 1.5, */ static::special => 2, default => 1 }; diff --git a/kodorvan/constructor/system/models/settings.php b/kodorvan/constructor/system/models/settings.php index 74eb3ae..389df45 100644 --- a/kodorvan/constructor/system/models/settings.php +++ b/kodorvan/constructor/system/models/settings.php @@ -51,6 +51,13 @@ final class settings extends core implements record_interface */ public protected(set) database $database; + /** + * Serialized + * + * @var bool $serialized Is the implementator object serialized? + */ + private bool $serialized = true; + /** * Constructor * @@ -111,9 +118,19 @@ final class settings extends core implements record_interface */ public function serialize(): self { + if ($this->serialized) { + // The record implementor is serialized + + // Exit (fail) + throw new exception_runtime('The record implementor is already serialized'); + } + // Serializing the record parameters $this->record->active = (int) $this->record->active; + // Writing the status of serializing + $this->serialized = true; + // Exit (success) return $this; } @@ -125,9 +142,19 @@ final class settings extends core implements record_interface */ public function deserialize(): self { + if (!$this->serialized) { + // The record implementor is deserialized + + // Exit (fail) + throw new exception_runtime('The record implementor is already deserialized'); + } + // Deserializing the record parameters $this->record->active = (bool) $this->record->active; + // Writing the status of serializing + $this->serialized = false; + // Exit (success) return $this; } diff --git a/kodorvan/constructor/system/models/telegram/conversations/project/create.php b/kodorvan/constructor/system/models/telegram/conversations/project/create.php index 3d428f6..ae22b6d 100644 --- a/kodorvan/constructor/system/models/telegram/conversations/project/create.php +++ b/kodorvan/constructor/system/models/telegram/conversations/project/create.php @@ -71,6 +71,13 @@ final class create extends menu */ public array $integrations = []; + /** + * Cost + * + * @var int|float $cost Cost per hour + */ + public int|float $cost = PROJECT_CREATE_COST_HOUR_DEFAULT ?? 0; + /** * Start * @@ -105,16 +112,23 @@ final class create extends menu // Initializing the project development hours $hours = $this->hours(); + // Initializing the calculated offer + $offer = "*$localization->project_create_time:* $hours$localization->project_create_time_hours _\(" . ceil(($hours / PROJECT_CREATE_DAY_HOURS) + PROJECT_CREATE_DAY_ADDITIONAL) . "$localization->project_create_time_days\)_\n" . "*$localization->project_create_cost:* " . unmarkdown((string) ceil($hours * $this->cost)) . $account->currency->symbol(); + // Generating the message text $text = implode( "\n\n", - [ - "🏛 *$localization->project_create_title*", - /* $hours > 0 ? "*$localization->project_create_time* " . unmarkdown((string) $hours) . " $localization->hours" : $localization->project_create_description */ - $new - ? $localization->project_create_description - : "*$localization->project_create_time:* $hours$localization->project_create_time_hours" - ] + array_filter( + [ + "🏛 *$localization->project_create_title*", + $new + ? $localization->project_create_description + : $offer, + !$new || isset($this->cost) + ? '⚠️ ' . $localization->project_create_cost_description + : null, + ] + ) ); if ($this->text !== $text) { @@ -197,7 +211,6 @@ final class create extends menu if (match ($this->architecture) { project_architecture::chat_robot, project_architecture::parser, - project_architecture::crm, project_architecture::site, project_architecture::program, project_architecture::complex => true, @@ -215,7 +228,6 @@ final class create extends menu } if (match ($this->architecture) { - project_architecture::crm, project_architecture::site, project_architecture::program, project_architecture::complex => true, @@ -226,11 +238,7 @@ final class create extends menu if (isset($this->interface)) { // Initialized the project interface - if ($this->architecture === project_architecture::crm) { - // CRM - - // site, mobile or desktop program - } else if ($this->architecture === project_architecture::program) { + if ($this->architecture === project_architecture::program) { // Program // mobile or desktop @@ -238,11 +246,7 @@ final class create extends menu } else { // Not initialized the project interface - if ($this->architecture === project_architecture::crm) { - // CRM - - // site, mobile or desktop program - } else if ($this->architecture === project_architecture::program) { + if ($this->architecture === project_architecture::program) { // Program // mobile or desktop @@ -253,7 +257,6 @@ final class create extends menu if (match ($this->architecture) { project_architecture::chat_robot, project_architecture::parser, - project_architecture::crm, project_architecture::site, project_architecture::program, project_architecture::complex => true, @@ -273,7 +276,6 @@ final class create extends menu if (match ($this->architecture) { project_architecture::chat_robot, project_architecture::parser, - project_architecture::crm, project_architecture::site, project_architecture::program, project_architecture::complex => true, @@ -291,7 +293,6 @@ final class create extends menu } if (match ($this->architecture) { - project_architecture::crm, project_architecture::site, project_architecture::program, project_architecture::complex => true, @@ -309,7 +310,6 @@ final class create extends menu } if (match ($this->architecture) { - project_architecture::crm, project_architecture::site, project_architecture::program, project_architecture::complex => true, @@ -329,7 +329,6 @@ final class create extends menu if (match ($this->architecture) { project_architecture::chat_robot, project_architecture::parser, - project_architecture::crm, project_architecture::site, project_architecture::program, project_architecture::complex => true, @@ -348,7 +347,6 @@ final class create extends menu if (match ($this->architecture) { project_architecture::chat_robot, - project_architecture::crm, project_architecture::site, project_architecture::program, project_architecture::complex => true, @@ -368,7 +366,6 @@ final class create extends menu if (match ($this->architecture) { project_architecture::chat_robot, project_architecture::parser, - project_architecture::crm, project_architecture::site, project_architecture::complex => true, default => false @@ -386,7 +383,6 @@ final class create extends menu if (match ($this->architecture) { project_architecture::chat_robot, - project_architecture::crm, project_architecture::site, project_architecture::program, project_architecture::complex => true, @@ -405,7 +401,6 @@ final class create extends menu if (match ($this->architecture) { project_architecture::chat_robot, - project_architecture::crm, project_architecture::site, project_architecture::complex => true, default => false @@ -424,7 +419,6 @@ final class create extends menu if (match ($this->architecture) { project_architecture::chat_robot, project_architecture::parser, - project_architecture::crm, project_architecture::site, project_architecture::program, project_architecture::complex => true, @@ -443,7 +437,6 @@ final class create extends menu if (match ($this->architecture) { project_architecture::chat_robot, - project_architecture::crm, project_architecture::site, project_architecture::program, project_architecture::complex => true, @@ -463,7 +456,6 @@ final class create extends menu if (match ($this->architecture) { project_architecture::chat_robot, project_architecture::parser, - project_architecture::crm, project_architecture::site, project_architecture::program, project_architecture::complex => true, @@ -516,13 +508,32 @@ final class create extends menu if (!$new) { // The project development hours was calculated - // Writing the project architecture button - $this->addButtonRow( - button::make( - text: "☑️ $localization->project_create_button_request", - callback_data: '@request' - ) - ); + + if (isset($this->cost)) { + // Initialized the project cost per hour + + // Writing the project buttons + $this->addButtonRow( + button::make( + text: '⚖️ ' . "$localization->project_create_button_cost_per_hour: $this->cost" . $account->currency->symbol(), + callback_data: '@cost' + ), + button::make( + text: "📦 $localization->project_create_button_request", + callback_data: '@request' + ) + ); + } else { + // Not initialized the project cost per hour + + // Writing the project cost per hour button + $this->addButtonRow( + button::make( + text: '⚖️ ' . $localization->project_create_button_cost_per_hour, + callback_data: '@cost' + ) + ); + } } // Updating the message and saving its text @@ -994,7 +1005,7 @@ final class create extends menu // Writing the integration button into the row $row[] = button::make( - text: (isset($target) && $target ? '🔹' : '') . ($localization['project_integration_' . $integration->name] ?? $integration->label(language: $language)), + text: (isset($target) && $target ? '🔘 ' : '') . ($localization['project_integration_' . $integration->name] ?? $integration->label(language: $language)), callback_data: "$integration->name@integration" ); @@ -1092,6 +1103,48 @@ final class create extends menu $this->integrations(robot: $robot); } + /** + * Cost + * + * Write the project cost per hour + * + * @param telegram $robot The robot + * + * @return void + */ + public function cost(telegram $robot): void + { + // Initializing the account language + $language = $robot->get('language') ?? LANGUAGE_DEFAULT; + + // Initializing the account localization + $localization = $robot->get('localization') ?? new localization($language); + + // Initializing the integration + $integration = project_integration::{$robot->callbackQuery()->data}; + + if (isset($this->integrations[$integration->name])) { + // Enabled + + // Disabling + unset($this->integrations[$integration->name]); + } else { + // Disabled + + // Enabling + $this->integrations[$integration->name] = $integration; + }; + + // Sending the popup notification + $robot->answerCallbackQuery( + text: $localization['project_integrations_' . (isset($this->integrations[$integration->name]) ? 'enabled' : 'disabled')], + show_alert: false + ); + + // Deleting the message buttons + $this->integrations(robot: $robot); + } + /** * Clear * @@ -1134,37 +1187,12 @@ final class create extends menu * * Calculate the project development hours * + * @param bool $absolute Summary all coefficients and then multiply? + * * @return int|float The project development hours */ - public function hours(): int|float - { // Declaring coefficient - $coefficient = PROJECT_CREATE_START_COEFFICIENT ?? 0; - - if (isset($this->architecture)) { - // Initialized the project architecture - - // Adding into the coefficient - $coefficient += $this->architecture->coefficient(); - } - - if (isset($this->purpose)) { - // Initialized the project purpose - - // Adding into the coefficient - $coefficient += $this->purpose->coefficient(); - } - - if (!empty($this->integrations)) { - // Initialized the project integrations - - foreach ($this->integrations as $integration) { - // Iterating over the project integrations - - // Adding into the coefficient - $coefficient += $integration->coefficient(); - } - } - + public function hours(bool $absolute = false): int|float + { // Initializing start hours $start = PROJECT_CREATE_START_HOURS ?? 1; $start < 1 and $start = 1; @@ -1172,11 +1200,79 @@ final class create extends menu // Initializing additional hours $additional = PROJECT_CREATE_HOURS_ADDITIONAL ?? 0; - // Calculating the development hours - $hours = $start * $coefficient + $additional; + if ($absolute) { + // The absolute coefficient - // Calculating and exit (success) - return ceil(max($hours, PROJECT_CREATE_HOURS_MINIMAL)); + // Declaring coefficient + $coefficient = PROJECT_CREATE_START_COEFFICIENT ?? 0; + + if (isset($this->architecture)) { + // Initialized the project architecture + + // Adding into the coefficient + $coefficient += $this->architecture->coefficient() ?? 0; + } + + if (isset($this->purpose)) { + // Initialized the project purpose + + // Adding into the coefficient + $coefficient += $this->purpose->coefficient() ?? 0; + } + + if (!empty($this->integrations)) { + // Initialized the project integrations + + foreach ($this->integrations as $integration) { + // Iterating over the project integrations + + // Adding into the coefficient + $coefficient += $integration->coefficient() ?? 0; + } + } + + // Calculating the development hours + $hours = $start * $coefficient + $additional; + + // Calculating and exit (success) + return ceil(max($hours, PROJECT_CREATE_HOURS_MINIMAL)); + } else { + // The relative coefficient + + // Initializing the development hours + $hours = $start; + + if (isset($this->architecture)) { + // Initialized the project architecture + + // Adding into the coefficient + $hours *= $this->architecture->coefficient() ?? 1; + } + + if (isset($this->purpose)) { + // Initialized the project purpose + + // Adding into the coefficient + $hours *= $this->purpose->coefficient() ?? 1; + } + + if (!empty($this->integrations)) { + // Initialized the project integrations + + foreach ($this->integrations as $integration) { + // Iterating over the project integrations + + // Adding into the coefficient + $hours *= $integration->coefficient() ?? 1; + } + } + + // + $hours += $additional; + + // Calculating and exit (success) + return ceil(max($hours, PROJECT_CREATE_HOURS_MINIMAL)); + } } /** diff --git a/kodorvan/constructor/system/models/worker.php b/kodorvan/constructor/system/models/worker.php new file mode 100644 index 0000000..ca942f4 --- /dev/null +++ b/kodorvan/constructor/system/models/worker.php @@ -0,0 +1,227 @@ + + */ +final class worker extends core implements record_interface +{ + use record_trait; + + /** + * File + * + * @var string $file Path to the database file + */ + protected string $file = DATABASES . DIRECTORY_SEPARATOR . 'workers.baza'; + + /** + * Database + * + * @var database $database The database + */ + public protected(set) database $database; + + /** + * Serialized + * + * @var bool $serialized Is the implementator object serialized? + */ + private bool $serialized = true; + + /** + * Constructor + * + * @method record|null $record The record + * + * @return void + */ + public function __construct(?record $record = null) + { + // Initializing the database + $this->database = new database() + ->encoding(encoding::utf8) + ->columns( + new column('identifier', type::long_long_unsigned), + new column('account', type::long_long_unsigned), + new column('hour', type::integer_unsigned), + new column('currency', type::string, ['length' => 3]), + new column('active', type::char), + new column('updated', type::integer_unsigned), + new column('created', type::integer_unsigned) + ) + ->connect($this->file); + + // Initializing the record + $record instanceof record and $this->record = $record; + } + + /** + * Write + * + * @param int $account The account identifier + * @param int|float $hour Cost per hour + * @param currency|string $currency Currency of cost per hour + * @param bool $active Is the record active? + * + * @return record|false The record, if created + */ + public function write( + int $account, + int|float $hour, + currency|string $currency = CURRENCY_DEFAULT ?? currency::usd, + bool $active = true, + ): record|false { + // Initializing the record + $record = $this->database->record( + $this->database->count() + 1, + (int) $account, + $hour, + $currency instanceof currency ? $currency->name : (string) $currency, + (int) $active, + svoboda::timestamp(), + svoboda::timestamp() + ); + + // Writing the record into the database + $created = $this->database->write($record); + + // Exit (success) + return $created ? $record : false; + } + + /** + * Account + * + * Search for the worker account + * + * @return account|null The account worker + */ + public function account(): ?account + { + // Search for the worker account + $account = new account()->read(filter: fn(record $record) => $record->active === 1 && $record->identifier === $this->account); + + if ($account instanceof account) { + // Found the worker account + + // Exit (success) + return $account; + } + + // Exit (fail) + return null; + } + + /** + * Workers + * + * Search for workers + * + * @param int $amount Amount + * + * @return array Workers + */ + public static function workers(int $amount = 100): array + { + // Search for workers and exit (success/fail) + return new static()->database->read( + filter: fn(record $record) => $record->active === 1, + amount: $amount + ); + } + + /** + * Serialize + * + * @return self The instance from which the method was called (fluent interface) + */ + public function serialize(): self + { + if ($this->serialized) { + // The record implementor is serialized + + // Exit (fail) + throw new exception_runtime('The record implementor is already serialized'); + } + + // Serializing the record parameters + $this->record->currency = $this->record->currency->name; + $this->record->active = (int) $this->record->active; + + // Writing the status of serializing + $this->serialized = true; + + // Exit (success) + return $this; + } + + /** + * Deserialize + * + * @return self The instance from which the method was called (fluent interface) + */ + public function deserialize(): self + { + if (!$this->serialized) { + // The record implementor is deserialized + + // Exit (fail) + throw new exception_runtime('The record implementor is already deserialized'); + } + + // Deserializing the record parameters + $this->record->currency = currency::{$this->record->currency} ?? CURRENCY_DEFAULT ?? currency::usd; + $this->record->active = (bool) $this->record->active; + + // Writing the status of serializing + $this->serialized = false; + + // Exit (success) + return $this; + } +} diff --git a/kodorvan/constructor/system/models/worker/enumerations/type.php b/kodorvan/constructor/system/models/worker/enumerations/type.php new file mode 100644 index 0000000..fd1365d --- /dev/null +++ b/kodorvan/constructor/system/models/worker/enumerations/type.php @@ -0,0 +1,25 @@ + + * + * @deprecated + */ +enum type +{ + case programmer; + case designer; +} diff --git a/kodorvan/constructor/system/settings/system.php.sample b/kodorvan/constructor/system/settings/system.php.sample index d8c4992..8ab5f47 100644 --- a/kodorvan/constructor/system/settings/system.php.sample +++ b/kodorvan/constructor/system/settings/system.php.sample @@ -22,18 +22,21 @@ define('PROJECT_OPERATOR_URL', 'https://t.me/kodorvan?direct'); define('PROJECT_REPOSITORY', REPOSITORY . '/' . PROJECT_CREATOR . '/' . PROJECT_NAME); define('PROJECT_REPOSITORY_LANGUAGE_ADD', PROJECT_REPOSITORY . '/src/branch/stable/' . PROJECT_CREATOR . '/' . PROJECT_NAME . '/system/localizations'); +define('CURRENCY_DEFAULT', currency::usd); +define('LANGUAGE_DEFAULT', language::en); + define('PROJECT_CREATE_START_HOURS', 1); define('PROJECT_CREATE_START_COEFFICIENT', 0); define('PROJECT_CREATE_HOURS_ADDITIONAL', 0); define('PROJECT_CREATE_HOURS_MINIMAL', 4); -define('PROJECT_CREATE_COST_HOUR_DEFAULT', 1200); +define('PROJECT_CREATE_DAY_HOURS', 4); +define('PROJECT_CREATE_DAY_ADDITIONAL', 1); +define('PROJECT_CREATE_COST_HOUR_DEFAULT', 20); +define('PROJECT_CREATE_COST_CURRENCY', CURRENCY_DEFAULT); define('PROJECT_CREATE_REQUEST_RECEIVERS', [ - + '-0000000000000' ]); -define('CURRENCY_DEFAULT', currency::rub); -define('LANGUAGE_DEFAULT', language::en); - // Initializing default theme for the views templater define('THEME', 'default');