diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cac762f --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/vendor/ +/.idea/ diff --git a/CHANGELOG.md b/CHANGELOG.md index f7dff06..3644d74 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,14 @@ Todas as mudanças relevantes serão documentadas nesse arquivo. O formato é baseado no [Keep a Changelog](https://keepachangelog.com/pt-BR/1.1.0), e esse projeto adere ao [Semantic Versionning](https://semver.org/spec/v2.0.0.html). +## [1.1.1] - 2024-05-27 +### Adicionado +- Adicionada notificação no painel de controle do proponente quando o parecer é publicado. +- Adicionada publicação de parecer em avaliações técnicas. +### Correções +- Retirado link fantasma para o perfil do parecerista na visão do proponente; +- Corrigido botão "Visualizar Pareceres" para aparecer ao proponente, somente quando pareceres estiverem publicados. + ## [1.1.0] - 2024-03-13 ### Adicionado - Agora o administrador pode selecionar se quer fazer publicação dos pareceres de forma automática ou manual; @@ -10,5 +18,5 @@ O formato é baseado no [Keep a Changelog](https://keepachangelog.com/pt-BR/1.1. ## [1.0.0] - 2024-02-27 ### Adicionado -- O administrador da oportunidade consegue ver a lista de pareceres na aba de inscrições da oportunidade. +- O administrador da oportunidade consegue ver a lista de pareceres na aba de inscrições da oportunidade; - O proponente consegue visualizar o parecer documental desde que a oportunidade esteja com o resultado publicado. diff --git a/Controllers/OpinionManagement.php b/Controllers/OpinionManagement.php index 247a12d..3c915da 100644 --- a/Controllers/OpinionManagement.php +++ b/Controllers/OpinionManagement.php @@ -2,8 +2,10 @@ namespace OpinionManagement\Controllers; +use Doctrine\Common\Collections\Criteria; use MapasCulturais\Controller, MapasCulturais\App; +use MapasCulturais\Entities\Notification; use OpinionManagement\Helpers\EvaluationList; class OpinionManagement extends Controller @@ -37,11 +39,14 @@ public function GET_opinions(): void $registration = $app->repo('Registration')->find($this->getData['id']); if($registration->canUser('view')) { $opinions = new EvaluationList($registration); - $this->json($opinions); + $this->json([ + 'evaluationMethod' => (string) $registration->opportunity->evaluationMethodConfiguration->type, + 'opinions' => $opinions, + ]); return; } - $this->errorJson(['permission-denied'], 403); + $this->json(['permission-denied'], 403); } public function POST_publishOpinions(): void @@ -58,13 +63,48 @@ public function POST_publishOpinions(): void } - $opportunity->setMetadata('publishedOpinions', 'true'); + $opportunity->setMetadata('publishedOpinions', true); $error = $opportunity->save(true); if($error) { $this->errorJson(['error' => new \PDOException('Cannot save this data')], 500); return; } + $this->notificateUsers($opportunity->id); + $this->json(['success' => true]); } + + public static function notificateUsers(int $opportunityId, bool $verifyPublishingOpinions = true): bool + { + $app = App::i(); + $opportunity = $app->repo('Opportunity')->find($opportunityId); + if($verifyPublishingOpinions && $opportunity->publishedOpinions === false) { + return false; + } + + set_time_limit(500); + + $criteria = new Criteria(); + $criteria->where($criteria->expr()->eq('opportunity', $opportunity)); + $criteria->andWhere($criteria->expr()->gt('status', '0')); + + $registrations = $app->repo('Registration')->matching($criteria); + $count = count($registrations); + foreach ($registrations as $i => $registration) { + $notification = new Notification(); + $notification->user = $registration->owner->user; + $notification->message = + sprintf( + "Sua inscrição %s" . + " da oportunidade %sestá com os pareceres publicados.", + $registration->number, + $opportunity->name + ); + $notification->save(true); + $app->log->debug("Notificação ".($i+1)."/$count enviada para o usuário {$registration->owner->user->id} ({$registration->owner->name})"); + } + + return true; + } } diff --git a/Plugin.php b/Plugin.php index cc7cc3a..179fbb4 100644 --- a/Plugin.php +++ b/Plugin.php @@ -4,6 +4,8 @@ use MapasCulturais\App, OpinionManagement\Controllers\OpinionManagement; +use MapasCulturais\Entities\Opportunity as OpportunityEntity; +use MapasCulturais\Entities\Registration; /** * @method part(string $string, array $args = []) @@ -38,27 +40,20 @@ public function _init(): void ); }); - $app->hook('template(opportunity.edit.registration-config):after', function () use ($app) { + $plugin = $this; + + $app->hook('template(opportunity.edit.evaluations-config):begin', function () use ($app, $plugin) { $opportunity = $this->controller->requestedEntity; - /** - * @todo: Refatorar quando for mudar para publicar pareceres técnicos - */ - if($opportunity->evaluationMethodConfiguration->type != 'documentary') { - return; + + if($plugin::isEvaluationMethodValid($opportunity)) { + $this->part('OpinionManagement/selection-autopublish', ['opportunity' => $opportunity]); } - $this->part('OpinionManagement/selection-autopublish', ['opportunity' => $opportunity]); }); - $app->hook('template(opportunity.single.registration-list-header):end', function() use($app) { + $app->hook('template(opportunity.single.registration-list-header):end', function() use($app, $plugin) { $opportunity = $this->controller->requestedEntity; - /** - * @todo: Refatorar quando for mudar para publicar pareceres técnicos - */ - if($opportunity->evaluationMethodConfiguration->type != 'documentary') { - return; - } - if($opportunity->canUser('@control')) { + if($plugin::isEvaluationMethodValid($opportunity) && $opportunity->canUser('@control')) { $this->part('OpinionManagement/admin-registrations-table-column.php'); $app->view->enqueueScript( 'app', @@ -73,68 +68,53 @@ public function _init(): void }); $app->hook('template(opportunity.single.user-registration-table--registration--status):end', function ($registration, $opportunity) use ($app) { - /** - * @todo: Refatorar quando for mudar para publicar pareceres técnicos - */ - if($opportunity->publishedOpinions != 'true') { - return; - } - - if($registration->canUser('@control')) { + if($opportunity->publishedOpinions === true && $registration->canUser('@control')) { $this->part('OpinionManagement/user-btn-show-opinion.php', ['registration' => $registration]); } }); - $app->hook('template(opportunity.single.opportunity-registrations--tables):begin', function () use ($app) { + $app->hook('template(opportunity.single.opportunity-registrations--tables):begin', function () use ($app, $plugin) { $opportunity = $this->controller->requestedEntity; - /** - * @todo: Refatorar quando for mudar para publicar pareceres técnicos - */ - if($opportunity->evaluationMethodConfiguration->type != 'documentary' - || $opportunity->autopublishOpinions !== 'Não' - || $opportunity->publishedOpinions == 'true' + if($plugin::isEvaluationMethodValid($opportunity) + && $opportunity->autopublishOpinions !== 'Sim' + && !$opportunity->publishedOpinions ) { - return; + $this->part('OpinionManagement/admin-btn-publish-opinions.php', ['opportunity' => $opportunity]); } - - $this->part('OpinionManagement/admin-btn-publish-opinions.php', ['opportunity' => $opportunity]); }); - $app->hook('template(registration.view.header-fieldset):after', function() use($app) { + $app->hook('template(registration.view.header-fieldset):after', function() use($app, $plugin) { $registration = $this->controller->requestedEntity; $opportunity = $registration->opportunity; - /** - * @todo: Refatorar quando for mudar para publicar pareceres técnicos - */ - if($opportunity->evaluationMethodConfiguration->type != 'documentary' || (!$opportunity->publishedRegistrations && !$opportunity->canUser('@control'))) { - return; - } - - if($registration->canUser('@control')) { + if($plugin::isEvaluationMethodValid($opportunity) + && $opportunity->publishedOpinions + && $opportunity->canUser('@control') + ) { $this->part('OpinionManagement/user-btn-show-opinion.php'); } }); - $app->hook('template(panel.<>.panel-registration):end', function ($registration) use ($app) { - /** - * @todo: Refatorar quando for mudar para publicar pareceres técnicos - */ - if(!$registration->opportunity->publishedRegistrations - || $registration->opportunity->evaluationMethodConfiguration->type != 'documentary' - ) return; - $this->part('OpinionManagement/user-btn-show-opinion.php', ['registration' => $registration]); - $app->view->enqueueScript( - 'app', - 'opinion-management', - 'OpinionManagement/js/opinionManagement.js' - ); + $app->hook('template(panel.<>.panel-registration):end', function (Registration $registration) use ($app,$plugin) { + if($registration->opportunity->publishedOpinions + && $plugin::isEvaluationMethodValid($registration->opportunity) + ) { + $this->part('OpinionManagement/user-btn-show-opinion.php', ['registration' => $registration]); + $app->view->enqueueScript( + 'app', + 'opinion-management', + 'OpinionManagement/js/opinionManagement.js' + ); + } }); $app->hook('entity(Opportunity).publishRegistrations:before', function () { - if($this->autopublishOpinions == 'Sim') - $this->setMetadata('publishedOpinions', 'true'); + if($this->autopublishOpinions === 'Sim') { + $this->setMetadata('publishedOpinions', true); + OpinionManagement::notificateUsers($this->id); + } }); + } /** @@ -155,11 +135,17 @@ public function register(): void 'required' => true, ]); $this->registerOpportunityMetadata('publishedOpinions', [ - 'type' => 'select', + 'type' => 'boolean', 'label' => \MapasCulturais\i::__('Pareceres publicados'), - 'default_value' => 'false', - 'options' => ['true', 'false'], + 'default_value' => false, + 'options' => [true, false], 'required' => true, ]); } + + public static function isEvaluationMethodValid(OpportunityEntity $opportunity): bool + { + return $opportunity->evaluationMethodConfiguration->type == 'documentary' + || $opportunity->evaluationMethodConfiguration->type == 'technical'; + } } diff --git a/assets/OpinionManagement/js/opinionManagement.js b/assets/OpinionManagement/js/opinionManagement.js index e509ced..60ae63a 100644 --- a/assets/OpinionManagement/js/opinionManagement.js +++ b/assets/OpinionManagement/js/opinionManagement.js @@ -1,4 +1,7 @@ -const handleChkCollapseChange = target => { +const handleChkCollapseChange = (target, evaluationMethod) => { + if(evaluationMethod === 'technical') { + return + } const chkCollapses = $('.chk-collapse') for(let i= 0;i < chkCollapses.length; i++) { if (chkCollapses[i] === target) continue @@ -6,28 +9,58 @@ const handleChkCollapseChange = target => { } } -const opinionHtml = opinion => { - let htmlParsed = '
' - htmlParsed += `
-

Parecerista ${opinion.agent.name}

- -

Resultado da avaliação documental:

-
- ` - for(const criteriaId in opinion.evaluationData) { - const criteria = opinion.evaluationData[criteriaId] - criteria.obs_items = criteria.obs_items?.replace('\n','
') - criteria.obs = criteria.obs?.replace('\n','
') - - htmlParsed += `
` - htmlParsed += `
${criteria.label}
` - htmlParsed += `

` - // htmlParsed += criteria.evaluation === 'invalid' ? `

${criteria['obs_items']}

` : '' - htmlParsed += `

${criteria['obs_items']}

` - htmlParsed += `

${criteria['obs']}

` - htmlParsed += `
` +const opinionHtml = (opinion, evaluationMethod) => { + const resultHtml = (opinionUrl, result, evaluationMethod) => { + if (evaluationMethod === 'documentary') + return `

+ Resultado da avaliação documental: + +

`; + if (evaluationMethod === 'technical') + return `

Nota da avaliação técnica:${result}

` } - htmlParsed += '
' + + const evaluationToHtml = (opinion, evaluationMethod) => { + let evaluationHtml = '' + if(evaluationMethod === 'documentary') { + for(const criteriaId in opinion.evaluationData) { + const criteria = opinion.evaluationData[criteriaId] + criteria.obs_items = criteria.obs_items?.replace('\n','
') + criteria.obs = criteria.obs?.replace('\n','
') + + evaluationHtml += `
+
${criteria.label}
+

+ ${criteria.evaluation === 'invalid' ? `

${criteria['obs_items']}

` : ''} +

${criteria['obs']}

+
` + } + } + if(evaluationMethod === 'technical') { + evaluationHtml += `
+

${opinion.evaluationData.obs}

+
` + } + + return evaluationHtml + } + + let htmlParsed = `
+
+

+ Parecerista + ${opinion.agent.singleUrl ? + ''+opinion.agent.name+'' : + opinion.agent.name + } +

+ + ${resultHtml(opinion.singleUrl, opinion.result, evaluationMethod)} +
+ + ${evaluationToHtml(opinion, evaluationMethod)} +
` return htmlParsed } @@ -44,7 +77,7 @@ const showOpinions = registrationId => { if (!response.ok) throw new Error(response.statusText) return response.json() }) - .then(opinions => { + .then(({opinions, evaluationMethod}) => { // @todo: Em versões futuras fazer alteração para mostrar quem são os pareceristas com pendências na avaliação if(opinions.length === 0) return Swal.fire({ @@ -52,7 +85,8 @@ const showOpinions = registrationId => { text: "As avaliações desta inscrição ainda não foram iniciadas." }) - const html = `
${opinions.map(opinion => opinionHtml(opinion)).join('')}
`; + + const html = `
${opinions.map(opinion => opinionHtml(opinion, evaluationMethod)).join('')}
`; Swal.fire({ html, @@ -99,7 +133,6 @@ const publishOpinions = target => { return response.json() }) .then(response => { - console.log(response) Swal.fire({ title: "Pareceres publicados com sucesso!", text: "Os pareceres desta inscrição agora encontram-se publicados.", @@ -126,3 +159,37 @@ const errorAlert = message => { showCloseButton: true, }) } + +alertPublish = id => { + Swal.fire({ + title: "Tem certeza?", + html: "ATENÇÃO, essa ação é uma ação irreversível. Caso a próxima fase seja uma prestação de contas, primeiro crie a fase de prestação de contas para só depois fazer a publicação.", + showConfirmButton: true, + showCloseButton: false, + showCancelButton: true, + confirmButtonText: 'Publicar', + cancelButtonText: 'Cancelar', + }) + .then(function (result) { + if(!result.isConfirmed) { + MapasCulturais.Messages.alert("Ação cancelada!") + return + } + + let loading = Swal.fire({ + title: "Verificando se há notificações a serem enviadas.", + allowOutsideClick: false, + showConfirmButton: false, + didOpen: () => { + Swal.showLoading(); + }, + }) + + var url = MapasCulturais.createUrl('opportunity', 'publishRegistrations', [id]); + $.get(url, function() { + loading.close() + MapasCulturais.Messages.success('Resultado publicado'); + }) + location.reload(); + }); +} \ No newline at end of file diff --git a/layouts/parts/OpinionManagement/selection-autopublish.php b/layouts/parts/OpinionManagement/selection-autopublish.php index 82dd916..c382390 100644 --- a/layouts/parts/OpinionManagement/selection-autopublish.php +++ b/layouts/parts/OpinionManagement/selection-autopublish.php @@ -1,14 +1,8 @@ - -

Publicação de Pareceres

Deseja que os pareceres desta fase/oportunidade sejam publicados para os proponentes automaticamente ao publicar os resultados?