473 lines
14 KiB
PHP
Executable File
473 lines
14 KiB
PHP
Executable File
<?php
|
||
|
||
namespace common\modules\abiturient\models\bachelor;
|
||
|
||
use backend\models\UploadableFileTrait;
|
||
use common\components\AfterValidateHandler\LoggingAfterValidateHandler;
|
||
use common\components\changeHistoryHandler\interfaces\ChangeHistoryHandlerInterface;
|
||
use common\components\CodeSettingsManager\CodeSettingsManager;
|
||
use common\components\FilesWorker\FilesWorker;
|
||
use common\components\ini\iniGet;
|
||
use common\models\errors\RecordNotValid;
|
||
use common\models\interfaces\ArchiveModelInterface;
|
||
use common\models\interfaces\FileToSendInterface;
|
||
use common\models\relation_presenters\comparison\interfaces\ICanGivePropsToCompare;
|
||
use common\models\relation_presenters\comparison\interfaces\IHaveIdentityProp;
|
||
use common\models\relation_presenters\OneToManyRelationPresenter;
|
||
use common\models\SendingFile;
|
||
use common\models\traits\ArchiveTrait;
|
||
use common\models\User;
|
||
use common\modules\abiturient\models\bachelor\changeHistory\ChangeHistory;
|
||
use common\modules\abiturient\models\bachelor\changeHistory\ChangeHistoryClasses;
|
||
use common\modules\abiturient\models\bachelor\changeHistory\interfaces\ChangeLoggedModelInterface;
|
||
use common\modules\abiturient\models\drafts\IHasRelations;
|
||
use common\modules\abiturient\models\interfaces\ICanGetPathToStoreFile;
|
||
use common\modules\abiturient\models\interfaces\IHaveCallbackAfterDraftCopy;
|
||
use Yii;
|
||
use yii\base\UserException;
|
||
use yii\behaviors\TimestampBehavior;
|
||
use yii\db\ActiveRecord;
|
||
use yii\helpers\ArrayHelper;
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
class AdmissionAgreement extends ActiveRecord
|
||
implements
|
||
FileToSendInterface,
|
||
ChangeLoggedModelInterface,
|
||
ArchiveModelInterface,
|
||
IHasRelations,
|
||
IHaveIdentityProp,
|
||
ICanGetPathToStoreFile,
|
||
ICanGivePropsToCompare,
|
||
IHaveCallbackAfterDraftCopy
|
||
{
|
||
use ArchiveTrait;
|
||
use UploadableFileTrait;
|
||
|
||
const STATUS_NOTVERIFIED = 0;
|
||
const STATUS_VERIFIED = 1;
|
||
const STATUS_MARKED_TO_DELETE = 2;
|
||
|
||
public const SCENARIO_NEW_AGREEMENT = 'insert';
|
||
public const SCENARIO_RECOVER = 'recover';
|
||
|
||
public $file;
|
||
|
||
const DOCUMENT_TYPE_PREDEFINED_DATA_NAME = 'СогласиеНаЗачисление';
|
||
|
||
public static function tableName()
|
||
{
|
||
return '{{%admission_agreement}}';
|
||
}
|
||
|
||
public static function getFileRelationTable()
|
||
{
|
||
return '{{%agreements_files}}';
|
||
}
|
||
|
||
public static function getFileRelationColumn()
|
||
{
|
||
return 'agreement_id';
|
||
}
|
||
|
||
public function behaviors()
|
||
{
|
||
return [
|
||
TimestampBehavior::class,
|
||
];
|
||
}
|
||
|
||
|
||
|
||
|
||
public function rules()
|
||
{
|
||
return [
|
||
[['archived_at'], 'integer'],
|
||
[
|
||
[
|
||
'sent_at',
|
||
'speciality_id',
|
||
],
|
||
'integer'
|
||
],
|
||
[
|
||
['speciality_id'],
|
||
'required'
|
||
],
|
||
[
|
||
['speciality_id'],
|
||
'validateUniqueSpec',
|
||
'on' => self::SCENARIO_NEW_AGREEMENT
|
||
],
|
||
[
|
||
'status',
|
||
'default',
|
||
'value' => self::STATUS_NOTVERIFIED
|
||
],
|
||
[['archive'], 'boolean'],
|
||
[
|
||
'status',
|
||
'in',
|
||
'range' => [
|
||
AdmissionAgreement::STATUS_NOTVERIFIED,
|
||
AdmissionAgreement::STATUS_VERIFIED,
|
||
AdmissionAgreement::STATUS_MARKED_TO_DELETE,
|
||
]
|
||
],
|
||
[
|
||
['file'],
|
||
'file',
|
||
'extensions' => AdmissionAgreement::getExtensionsListForRules(),
|
||
'skipOnEmpty' => true,
|
||
'maxSize' => iniGet::getUploadMaxFilesize(false),
|
||
'except' => [static::SCENARIO_RECOVER]
|
||
],
|
||
];
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
public static function getExtensionsListForRules(): string
|
||
{
|
||
return implode(', ', static::getExtensionsList());
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
public static function getExtensionsList(): array
|
||
{
|
||
return FilesWorker::getAllowedExtensionsToUploadList();
|
||
}
|
||
|
||
public function validateUniqueSpec()
|
||
{
|
||
if ($this->status === self::STATUS_MARKED_TO_DELETE) {
|
||
return true;
|
||
}
|
||
if (AdmissionAgreement::find()
|
||
->active()
|
||
->andWhere([AdmissionAgreement::tableName() . '.speciality_id' => $this->speciality_id])
|
||
->andWhere(['not', [AdmissionAgreement::tableName() . '.status' => self::STATUS_MARKED_TO_DELETE]])
|
||
->exists()
|
||
) {
|
||
$this->addError(
|
||
'speciality_id',
|
||
Yii::t(
|
||
'abiturient/bachelor/application/admission-agreement',
|
||
'Подсказка с ошибкой для поля "speciality_id"; формы согласия: `Невозможно прикрепить несколько согласий на зачисление на одно направление подготовки.`'
|
||
)
|
||
);
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
public function scenarios()
|
||
{
|
||
$scenarios = parent::scenarios();
|
||
$scenarios[self::SCENARIO_NEW_AGREEMENT] = $scenarios[self::SCENARIO_DEFAULT];
|
||
return $scenarios;
|
||
}
|
||
|
||
public function getStatusString()
|
||
{
|
||
switch ($this->status) {
|
||
case self::STATUS_NOTVERIFIED:
|
||
return Yii::t('abiturient/bachelor/application/admission-agreement', 'Статус согласия: `Не подтверждено`');
|
||
case self::STATUS_VERIFIED:
|
||
return Yii::t('abiturient/bachelor/application/admission-agreement', 'Статус согласия: `Подтверждено`');
|
||
case self::STATUS_MARKED_TO_DELETE:
|
||
return Yii::t('abiturient/bachelor/application/admission-agreement', 'Статус согласия: `Отклонено`');
|
||
default:
|
||
return Yii::t('abiturient/bachelor/application/admission-agreement', 'Статус согласия: `Неизвестно`');
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
public function attributeLabels()
|
||
{
|
||
return [
|
||
'file' => Yii::t('abiturient/bachelor/application/admission-agreement', 'Подпись для поля "file"; формы согласия: `файл`'),
|
||
'status' => Yii::t('abiturient/bachelor/application/admission-agreement', 'Подпись для поля "status"; формы согласия: `Статус`'),
|
||
'statusString' => Yii::t('abiturient/bachelor/application/admission-agreement', 'Подпись для поля "status"; формы согласия: `Статус`'),
|
||
'filename' => Yii::t('abiturient/bachelor/application/admission-agreement', 'Подпись для поля "filename"; формы согласия: `Имя файла`'),
|
||
'speciality_id' => Yii::t('abiturient/bachelor/application/admission-agreement', 'Подпись для поля "speciality_id"; формы согласия: `Направление подготовки`'),
|
||
];
|
||
}
|
||
|
||
public function getSpeciality()
|
||
{
|
||
return $this->hasOne(BachelorSpeciality::class, ['id' => 'speciality_id']);
|
||
}
|
||
|
||
public function getUser()
|
||
{
|
||
return ArrayHelper::getValue($this, 'speciality.application.user');
|
||
}
|
||
|
||
public function getRawAgreementDecline()
|
||
{
|
||
return $this->hasOne(AgreementDecline::class, ['agreement_id' => 'id'])
|
||
->orderBy([AgreementDecline::tableName() . '.archive' => SORT_ASC]);
|
||
}
|
||
|
||
public function getAgreementDecline()
|
||
{
|
||
return $this->hasOne(AgreementDecline::class, ['agreement_id' => 'id'])
|
||
->active()
|
||
->orderBy([AgreementDecline::tableName() . '.archive' => SORT_ASC]);
|
||
}
|
||
|
||
protected function getOwnerId()
|
||
{
|
||
return $this->user->id;
|
||
}
|
||
|
||
public function checkAccess($user)
|
||
{
|
||
if ($user->isModer()) {
|
||
return true;
|
||
} elseif ($user->id == $this->getOwnerId()) {
|
||
return true;
|
||
} else {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
public function makeDeclined()
|
||
{
|
||
if ($this->status === AdmissionAgreement::STATUS_NOTVERIFIED) {
|
||
return $this->archive();
|
||
}
|
||
$user_id = ArrayHelper::getValue($this, 'speciality.application.user.id');
|
||
$app_code = ArrayHelper::getValue($this, 'speciality.application_code');
|
||
$campaign_code = ArrayHelper::getValue($this, 'speciality.application.type.campaign.referenceType.reference_id');
|
||
$transaction = Yii::$app->db->beginTransaction();
|
||
try {
|
||
if (isset($user_id, $app_code, $campaign_code)) {
|
||
$toDeleteEntity = new AdmissionAgreementToDelete([
|
||
'user_id' => $user_id,
|
||
'agreement_id' => $this->id,
|
||
'application_code' => $app_code,
|
||
'campaign_code' => $campaign_code,
|
||
'archive' => false
|
||
]);
|
||
$result = $this->markToDelete() && $toDeleteEntity->validate();
|
||
if ($result) {
|
||
$toDeleteEntity->save(false);
|
||
$transaction->commit();
|
||
return true;
|
||
}
|
||
}
|
||
$transaction->rollBack();
|
||
return false;
|
||
} catch (\Throwable $e) {
|
||
$transaction->rollBack();
|
||
throw $e;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
public function markToDelete()
|
||
{
|
||
$this->status = self::STATUS_MARKED_TO_DELETE;
|
||
if ($this->validate()) {
|
||
$this->save(false);
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
public function archiveAllDeclines()
|
||
{
|
||
if (isset($this->speciality->application_code)) {
|
||
AdmissionAgreementToDelete::updateAll(['archive' => true], [
|
||
'user_id' => $this->user->id,
|
||
'id' => $this->getRawAgreementToDelete()->select('id')->column()
|
||
]);
|
||
AgreementDecline::updateAll(['archive' => true], [
|
||
'id' => $this->getAgreementDecline()->select('id')->column()
|
||
]);
|
||
}
|
||
}
|
||
|
||
public function getRawAgreementToDelete()
|
||
{
|
||
return $this->hasOne(AdmissionAgreementToDelete::class, ['agreement_id' => 'id']);
|
||
}
|
||
|
||
public function getAgreementToDelete()
|
||
{
|
||
return $this->getRawAgreementToDelete()->andOnCondition([AdmissionAgreementToDelete::tableName() . '.archive' => false]);
|
||
}
|
||
|
||
public function getClassTypeForChangeHistory(): int
|
||
{
|
||
return ChangeHistoryClasses::CLASS_AGREEMENT;
|
||
}
|
||
|
||
public function getChangeLoggedAttributes()
|
||
{
|
||
return [];
|
||
}
|
||
|
||
public function getOldClass(): ChangeLoggedModelInterface
|
||
{
|
||
return $this;
|
||
}
|
||
|
||
public function getEntityIdentifier(): ?string
|
||
{
|
||
if ($this->speciality !== null) {
|
||
return $this->speciality->getEntityIdentifier();
|
||
}
|
||
return '';
|
||
}
|
||
|
||
public function getChangeHistoryHandler(): ?ChangeHistoryHandlerInterface
|
||
{
|
||
return null;
|
||
}
|
||
|
||
public function getEntityChangeType(): int
|
||
{
|
||
return ChangeHistory::CHANGE_HISTORY_NEW_AGREEMENT;
|
||
}
|
||
|
||
public function setChangeHistoryHandler(ChangeHistoryHandlerInterface $handler)
|
||
{
|
||
return null;
|
||
}
|
||
|
||
public function beforeArchive()
|
||
{
|
||
if ($this->agreementDecline) {
|
||
$this->agreementDecline->archive();
|
||
}
|
||
}
|
||
|
||
public function beforeDelete()
|
||
{
|
||
if (parent::beforeDelete()) {
|
||
$transaction = Yii::$app->db->beginTransaction();
|
||
|
||
$deleteSuccess = true;
|
||
try {
|
||
$errorFrom = '';
|
||
|
||
$agreementDecline = $this->getRawAgreementDecline()->all();
|
||
if (!empty($agreementDecline)) {
|
||
foreach ($agreementDecline as $dataToDelete) {
|
||
$deleteSuccess = $dataToDelete->delete();
|
||
if (!$deleteSuccess) {
|
||
$errorFrom .= "{$this->tableName()} -> {$dataToDelete->tableName()} -> {$dataToDelete->id}\n";
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
if ($deleteSuccess) {
|
||
$agreementToDelete = $this->getRawAgreementToDelete()->all();
|
||
if (!empty($agreementToDelete)) {
|
||
foreach ($agreementToDelete as $dataToDelete) {
|
||
$deleteSuccess = $dataToDelete->delete();
|
||
if (!$deleteSuccess) {
|
||
$errorFrom .= "{$this->tableName()} -> {$dataToDelete->tableName()} -> {$dataToDelete->id}\n";
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if ($deleteSuccess) {
|
||
$this->deleteAttachedFile();
|
||
|
||
$transaction->commit();
|
||
} else {
|
||
Yii::error("Ошибка при удалении данных с портала. В таблице: {$errorFrom}");
|
||
$transaction->rollBack();
|
||
|
||
return false;
|
||
}
|
||
return true;
|
||
} catch (\Throwable $e) {
|
||
$transaction->rollBack();
|
||
Yii::error("Ошибка при удалении данных с портала. " . $e->getMessage());
|
||
return false;
|
||
}
|
||
} else {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
public function afterValidate()
|
||
{
|
||
(new LoggingAfterValidateHandler())
|
||
->setModel($this)
|
||
->invoke();
|
||
}
|
||
|
||
|
||
public function getRelationsInfo(): array
|
||
{
|
||
return [
|
||
new OneToManyRelationPresenter('agreementDeclines', [
|
||
'parent_instance' => $this,
|
||
'child_class' => AgreementDecline::class,
|
||
'child_column_name' => 'agreement_id',
|
||
]),
|
||
new OneToManyRelationPresenter('agreementsToDelete', [
|
||
'parent_instance' => $this,
|
||
'child_class' => AdmissionAgreementToDelete::class,
|
||
'child_column_name' => 'agreement_id',
|
||
'ignore_in_comparison' => true,
|
||
]),
|
||
];
|
||
}
|
||
|
||
public function getIdentityString(): string
|
||
{
|
||
$declined = (int)(bool)$this->agreementDecline;
|
||
return "{$this->status}_{$declined}_{$this->filename}";
|
||
}
|
||
|
||
public function getPropsToCompare(): array
|
||
{
|
||
return [
|
||
'statusString',
|
||
'filename',
|
||
];
|
||
}
|
||
}
|