portal.mkgtu.ru/common/services/abiturientController/bachelor/accounting_benefits/AccountingBenefitsService.php

503 lines
15 KiB
PHP
Raw Permalink Normal View History

2024-03-28 09:51:45 +03:00
<?php
namespace common\services\abiturientController\bachelor\accounting_benefits;
use Closure;
use common\components\AttachmentManager;
use common\components\configurationManager;
use common\components\filesystem\FilterFilename;
use common\components\ReferenceTypeManager\ContractorManager;
use common\models\Attachment;
use common\models\dictionary\AvailableDocumentTypesForConcession;
use common\models\dictionary\DocumentType;
use common\models\dictionary\DocumentTypesForConcessionJunctionToFilters;
use common\models\dictionary\Privilege;
use common\models\dictionary\SpecialMark;
use common\models\dictionary\StoredReferenceType\StoredAdmissionCampaignReferenceType;
use common\models\dictionary\StoredReferenceType\StoredAvailableDocumentTypeFilterReferenceType;
use common\models\ModelFrom1CByOData;
use common\models\User;
use common\modules\abiturient\models\bachelor\BachelorApplication;
use common\modules\abiturient\models\bachelor\BachelorPreferences;
use common\modules\abiturient\models\bachelor\BachelorTargetReception;
use common\services\abiturientController\bachelor\BachelorService;
use Throwable;
use Yii;
use yii\base\UserException;
use yii\caching\CacheInterface;
use yii\db\ActiveQuery;
use yii\db\ActiveRecord;
use yii\helpers\ArrayHelper;
use yii\web\NotFoundHttpException;
use yii\web\Request;
use ZipArchive;
class AccountingBenefitsService extends BachelorService
{
protected CacheInterface $cache;
public function __construct(
Request $request,
CacheInterface $cache,
configurationManager $configurationManager
) {
$this->cache = $cache;
parent::__construct($request, $configurationManager);
}
public function postProcessingRegulationsAndAttachments(
BachelorApplication $application,
array $attachments,
array $regulations
): array {
if ($this->request->post('UserRegulation') !== null) {
return parent::postProcessingRegulationsAndAttachments($application, $attachments, $regulations);
}
return [
'hasChanges' => false,
'attachments' => $attachments,
'regulations' => $regulations,
];
}
public function getNextStep(BachelorApplication $application, string $currentStep = 'accounting-benefits'): string
{
return parent::getNextStep($application, $currentStep);
}
public function canGenerateFilesToDownloadAccountingBenefits(?int $id = null, string $accountingBenefitsClass): bool
{
AccountingBenefitsService::checkIsCorrectAccountingBenefitsClass($accountingBenefitsClass);
if (isset($id)) {
$model = $accountingBenefitsClass::findOne($id);
if (isset($model)) {
return $model->getAttachments()->exists();
}
}
return false;
}
protected function getDocTypesByBachelorPreferenceCodeAndBachelorApplication(BachelorApplication $application, ?ModelFrom1CByOData $preference)
{
$ValueArray = null;
if ($preference) {
if ($preference instanceof Privilege) {
$subject_type = DocumentTypesForConcessionJunctionToFilters::SUBJECT_TYPE_PRIVILEGES;
} else {
$subject_type = DocumentTypesForConcessionJunctionToFilters::SUBJECT_TYPE_SPECIAL_MARKS;
}
$id_subject = $preference->ref_key;
$tnFilterJunctions = DocumentTypesForConcessionJunctionToFilters::tableName();
$tnAvailableDocumentTypeFilterRef = StoredAvailableDocumentTypeFilterReferenceType::tableName();
$query = AvailableDocumentTypesForConcession::find()
->joinWith('admissionCampaignRef', false)
->joinWith('documentTypeRef', false)
->joinWith(['filterJunctions'])
->joinWith('availableDocumentTypeFilterRef')
->andWhere(["{$tnFilterJunctions}.subject_type" => $subject_type])
->andWhere(["{$tnAvailableDocumentTypeFilterRef}.reference_uid" => $id_subject])
->andWhere([StoredAdmissionCampaignReferenceType::tableName() . '.reference_uid' => $application->type->rawCampaign->referenceType->reference_uid])
->andWhere(['dictionary_available_document_types_for_concession.archive' => false])
->select(DocumentType::tableName() . '.ref_key');
$ValueArray = DocumentType::find()
->notMarkedToDelete()
->active()
->select(['maxid' => 'max(dictionary_document_type.id)', 'dictionary_document_type.ref_key', 'dictionary_document_type.description'])
->andWhere(['dictionary_document_type.ref_key' => $query])
->andWhere(['dictionary_document_type.is_folder' => false])
->groupBy(['dictionary_document_type.ref_key', 'dictionary_document_type.description'])
->orderBy('dictionary_document_type.description')
->asArray()
->all();
}
if (empty($ValueArray)) {
$ValueArray = DocumentType::find()
->notMarkedToDelete()
->active()
->select(['maxid' => 'max(dictionary_document_type.id)', 'dictionary_document_type.ref_key', 'dictionary_document_type.description'])
->andWhere(['dictionary_document_type.is_folder' => false])
->groupBy(['dictionary_document_type.ref_key', 'dictionary_document_type.description'])
->orderBy('dictionary_document_type.description')
->asArray()
->all();
}
return $ValueArray;
}
protected function initBachelorPreferences(BachelorApplication $application, string $type): BachelorPreferences
{
$model = new BachelorPreferences();
$model->id_application = $application->id;
$model->setPreferenceType($type);
return $model;
}
protected function getDocumentItems(?string $docTypeUid = null): array
{
$tnDocumentType = DocumentType::tableName();
$docsQuery = DocumentType::find()
->notMarkedToDelete()
->active()
->andWhere(['is_folder' => false])
->orderBy("{$tnDocumentType}.description");
if ($docTypeUid) {
$docsQuery->andWhere(["{$tnDocumentType}.ref_key" => $docTypeUid]);
}
return ArrayHelper::map($docsQuery->all(), 'id', 'description');
}
protected function editAccountingBenefits(string $formName)
{
if ($this->request->isPost) {
$appId = $this->request->post($formName)['id_application'];
$id = $this->request->post($formName)['id'];
if ($appId) {
$application = $this->getApplication($appId);
return [
'id' => $id,
'appId' => $appId,
'application' => $application,
];
}
}
throw new UserException('Не переданы необходимые параметры');
}
protected function getAccountingBenefitsQueryForEditFunction(
int $id,
int $appId,
string $accountingBenefitsClass
): ActiveQuery {
AccountingBenefitsService::checkIsCorrectAccountingBenefitsClass($accountingBenefitsClass);
$tnAccountingBenefits = $accountingBenefitsClass::tableName();
return $accountingBenefitsClass::find()
->andWhere([
"{$tnAccountingBenefits}.id" => $id,
"{$tnAccountingBenefits}.id_application" => $appId,
]);
}
protected function saveNewAccountingBenefits(
?int $id,
string $formName
): BachelorApplication {
if ($this->request->isPost) {
if (!$id) {
$id = $this->request->post($formName)['id_application'];
}
return $this->getApplication($id);
}
throw new UserException('Не переданы необходимые параметры');
}
protected function generateFilesToDownloadAccountingBenefits(
User $currentUser,
?int $id,
string $accountingBenefitClass,
Closure $fileNameCallback,
string $throwMessage
): array {
AccountingBenefitsService::checkIsCorrectAccountingBenefitsClass($accountingBenefitClass);
$accountingBenefit = $accountingBenefitClass::findOne((int)$id);
if ($accountingBenefit != null) {
$zip = new ZipArchive();
$collection = $accountingBenefit->attachmentCollection;
$filename = FilterFilename::sanitize($fileNameCallback($accountingBenefit, $collection));
if ($zip->open(Yii::getAlias("@storage/web/tempZip/{$filename}"), ZipArchive::CREATE | ZipArchive::OVERWRITE) !== true) {
throw new UserException('Не удалось создать архив.');
}
foreach ($collection->attachments as $key => $attachment) {
if ($attachment->checkAccess($currentUser)) {
$path = $attachment->getAbsPath();
if ($path && file_exists($path)) {
$number = $key + 1;
$zip->addFile(
$path,
FilterFilename::sanitize("{$number}. " .
$attachment->getAttachmentTypeName() .
'.' .
$attachment->extension)
);
}
}
}
if ($zip->numFiles > 0) {
$pathToZipArchive = $zip->filename;
$zip->close();
return [
'filename' => $filename,
'pathToZipArchive' => $pathToZipArchive
];
} else {
throw new UserException('Нет файлов для отправки.');
}
}
throw new NotFoundHttpException($throwMessage);
}
protected function updateAccountingBenefitsFromPost(
User $currentUser,
BachelorApplication $application,
$accountingBenefitsFrom,
Closure $beforeSaveCallback,
string $errorMessageTemplate
): array {
$saveSuccess = false;
$hasChangedAttributes = false;
if ($accountingBenefitsFrom->load($this->request->post())) {
$this->updateContractorFromPost($accountingBenefitsFrom);
$accountingBenefitsFrom = $beforeSaveCallback($accountingBenefitsFrom);
$hasChangedAttributes = $accountingBenefitsFrom->hasChangedAttributes();
if ($accountingBenefitsFrom->save()) {
if (!$currentUser->isModer()) {
$application->resetStatus();
}
$attachedFileHashList = $accountingBenefitsFrom->buildAttachmentHash();
AttachmentManager::handleAttachmentUpload([$accountingBenefitsFrom->attachmentCollection]);
$saveSuccess = true;
if (!$accountingBenefitsFrom->checkIfDocumentIsChanged($attachedFileHashList)) {
$accountingBenefitsFrom->setDocumentCheckStatusNotVerified();
$accountingBenefitsFrom->save(['document_check_status_ref_id']);
$hasChangedAttributes = true;
}
} else {
$log = ['data' => [
'id' => $accountingBenefitsFrom->id,
'id_application' => $application->id,
'formName' => $accountingBenefitsFrom->formName(),
]];
Yii::error(
$errorMessageTemplate .
PHP_EOL .
print_r($accountingBenefitsFrom->errors, true) .
PHP_EOL .
print_r($log, true),
'AccountingBenefitsService.updateAccountingBenefitsFromPost'
);
}
}
return [$accountingBenefitsFrom, $saveSuccess, $hasChangedAttributes];
}
protected function archiveAccountingBenefit(
?int $id = null,
User $currentUser,
string $accountingBenefitsClass,
string $errorMessageOnFileDeletion,
string $errorMessageOnAccountingBenefitArchiving,
bool $updateApplicationHistory = true
): void {
if (isset($id)) {
AccountingBenefitsService::checkIsCorrectAccountingBenefitsClass($accountingBenefitsClass);
$tnAccountingBenefits = $accountingBenefitsClass::tableName();
$model = $accountingBenefitsClass::find()
->notInEnlistedApp()
->andWhere(["{$tnAccountingBenefits}.id" => $id])
->one();
if (isset($model) && !$model->read_only) {
$db = $accountingBenefitsClass::getDb();
$transaction = $db->beginTransaction();
if (!isset($transaction)) {
throw new UserException('Невозможно начать транзакцию');
}
try {
foreach ($model->attachments as $attachment) {
if (!$attachment->safeDelete($currentUser, $updateApplicationHistory)) {
throw new UserException($errorMessageOnFileDeletion);
}
}
if (!$model->archive()) {
throw new UserException($errorMessageOnAccountingBenefitArchiving);
}
if (!$currentUser->isModer()) {
$model->application->resetStatus();
}
$transaction->commit();
} catch (Throwable $e) {
$transaction->rollBack();
throw $e;
}
}
}
}
private static function checkIsCorrectAccountingBenefitsClass(string $accountingBenefitsClass): bool
{
$correctAccountingBenefitsClasses = [
BachelorPreferences::class,
BachelorTargetReception::class,
];
if (in_array(
$accountingBenefitsClass,
$correctAccountingBenefitsClasses
)) {
return true;
}
throw new UserException("Был передан класс не относящийся к категории «особых прав» ({$accountingBenefitsClass})");
}
protected function updateContractorFromPost($accountingBenefitsFrom): void
{
if ($accountingBenefitsFrom->notFoundContractor) {
$accountingBenefitsFrom->contractor_id = ContractorManager::Upsert(
$this->request->post('Contractor'),
$accountingBenefitsFrom->documentType
)->id;
}
}
}