diff --git a/src/conf/opportunity-types.php b/src/conf/opportunity-types.php index e2efb451c2..596389001e 100644 --- a/src/conf/opportunity-types.php +++ b/src/conf/opportunity-types.php @@ -245,6 +245,16 @@ function compareNamesOpportunity ($item1, $item2) { 'label' => \MapasCulturais\i::__('Total de vagas'), // 'description' => \MapasCulturais\i::__("Quantidades de vagas que esse edital irá disponibilizar."), ), + 'isModel' => array( + 'type' => 'integer', + 'label' => \MapasCulturais\i::__('É modelo?'), + 'default_value' => 0 + ), + 'isModelOfficial' => array( + 'type' => 'integer', + 'label' => \MapasCulturais\i::__('É modelo oficial?'), + ), + ), 'items' => $items, diff --git a/src/core/Controllers/Opportunity.php b/src/core/Controllers/Opportunity.php index 5e20ca2ae5..d09a4a04b9 100644 --- a/src/core/Controllers/Opportunity.php +++ b/src/core/Controllers/Opportunity.php @@ -34,6 +34,7 @@ class Opportunity extends EntityController { Traits\ControllerAPI, Traits\ControllerAPINested, Traits\EntityOpportunityDuplicator, + Traits\EntityGenerateModel, Traits\ControllerEntityActions { Traits\ControllerEntityActions::PATCH_single as _PATCH_single; } diff --git a/src/core/Traits/EntityGenerateModel.php b/src/core/Traits/EntityGenerateModel.php new file mode 100644 index 0000000000..45630c7812 --- /dev/null +++ b/src/core/Traits/EntityGenerateModel.php @@ -0,0 +1,163 @@ +requireAuthentication(); + $this->opportunity = $this->requestedEntity; + $this->opportunityModel = $this->generateModel(); + + $this->generateEvaluationMethods(); + $this->generatePhases(); + $this->generateMetadata(); + $this->generateRegistrationFieldsAndFiles(); + + $this->opportunityModel->save(true); + + if($this->isAjax()){ + $this->json($this->opportunity); + }else{ + $app->redirect($app->request->getReferer()); + } + } + + private function generateModel() : ProjectOpportunity + { + $app = App::i(); + + $postData = $this->postData; + + $name = $postData['name']; + $description = $postData['description']; + + $this->opportunityModel = clone $this->opportunity; + + $this->opportunityModel->setName($name); + $this->opportunityModel->setStatus(-1); + $this->opportunityModel->setShortDescription($description); + $app->em->persist($this->opportunityModel); + $app->em->flush(); + + return $this->opportunityModel; + } + + private function generateEvaluationMethods() : void + { + $app = App::i(); + + // duplica o método de avaliação para a oportunidade primária + $evaluationMethodConfigurations = $app->repo('EvaluationMethodConfiguration')->findBy([ + 'opportunity' => $this->opportunity + ]); + foreach ($evaluationMethodConfigurations as $evaluationMethodConfiguration) { + $newMethodConfiguration = clone $evaluationMethodConfiguration; + $newMethodConfiguration->setOpportunity($this->opportunityModel); + $newMethodConfiguration->save(true); + + // duplica os metadados das configurações do modelo de avaliação + foreach ($evaluationMethodConfiguration->getMetadata() as $metadataKey => $metadataValue) { + $newMethodConfiguration->setMetadata($metadataKey, $metadataValue); + $newMethodConfiguration->save(true); + } + } + } + + private function generatePhases() : void + { + $app = App::i(); + + $phases = $app->repo('Opportunity')->findBy([ + 'parent' => $this->opportunity + ]); + foreach ($phases as $phase) { + if (!$phase->getMetadata('isLastPhase')) { + $newPhase = clone $phase; + $newPhase->setParent($this->opportunityModel); + + foreach ($phase->getMetadata() as $metadataKey => $metadataValue) { + if (!is_null($metadataValue) && $metadataValue != '') { + $newPhase->setMetadata($metadataKey, $metadataValue); + $newPhase->save(true); + } + } + + $newPhase->save(true); + + $evaluationMethodConfigurations = $app->repo('EvaluationMethodConfiguration')->findBy([ + 'opportunity' => $phase + ]); + + foreach ($evaluationMethodConfigurations as $evaluationMethodConfiguration) { + $newMethodConfiguration = clone $evaluationMethodConfiguration; + $newMethodConfiguration->setOpportunity($newPhase); + $newMethodConfiguration->save(true); + + // duplica os metadados das configurações do modelo de avaliação para a fase + foreach ($evaluationMethodConfiguration->getMetadata() as $metadataKey => $metadataValue) { + $newMethodConfiguration->setMetadata($metadataKey, $metadataValue); + $newMethodConfiguration->save(true); + } + } + } + + if ($phase->getMetadata('isLastPhase')) { + $publishDate = $phase->getPublishTimestamp(); + } + } + + if (isset($publishDate)) { + $phases = $app->repo('Opportunity')->findBy([ + 'parent' => $this->opportunityModel + ]); + + foreach ($phases as $phase) { + if ($phase->getMetadata('isLastPhase')) { + $phase->setPublishTimestamp($publishDate); + $phase->save(true); + } + } + } + } + + + private function generateMetadata() : void + { + foreach ($this->opportunity->getMetadata() as $metadataKey => $metadataValue) { + if (!is_null($metadataValue) && $metadataValue != '') { + $this->opportunityModel->setMetadata($metadataKey, $metadataValue); + } + } + + $this->opportunityModel->setMetadata('isModel', 1); + $this->opportunityModel->setMetadata('isModelOfficial', 0); + + $this->opportunityModel->saveTerms(); + } + + private function generateRegistrationFieldsAndFiles() : void + { + foreach ($this->opportunity->getRegistrationFieldConfigurations() as $registrationFieldConfiguration) { + $fieldConfiguration = clone $registrationFieldConfiguration; + $fieldConfiguration->setOwnerId($this->opportunityModel->getId()); + $fieldConfiguration->save(true); + } + + foreach ($this->opportunity->getRegistrationFileConfigurations() as $registrationFileConfiguration) { + $fileConfiguration = clone $registrationFileConfiguration; + $fileConfiguration->setOwnerId($this->opportunityModel->getId()); + $fileConfiguration->save(true); + } + + } +} diff --git a/src/cypress/e2e/opportunity/index.cy.js b/src/cypress/e2e/opportunity/index.cy.js index 1ceb10c179..d237c46107 100644 --- a/src/cypress/e2e/opportunity/index.cy.js +++ b/src/cypress/e2e/opportunity/index.cy.js @@ -149,7 +149,7 @@ describe("Opportunity Page", () => { ], "11 Oportunidades encontradas"); }); - it("Garante geração de modelo da oportunidade", () => { + it("Garante duplicação da oportunidade", () => { cy.visit("/autenticacao/"); loginWith("Admin@local", "mapas123"); cy.get(':nth-child(4) > :nth-child(1) > a').click(); @@ -159,7 +159,7 @@ describe("Opportunity Page", () => { cy.get('.rowBtn > :nth-child(6)').click(); - cy.contains("Salvar modelo"); + cy.contains("Duplicar modelo"); cy.contains("Todas as configurações atuais da oportunidade, incluindo o vínculo com a entidade associada e os campos de formulário criados, serão duplicadas."); cy.get('.modal__action > .button--primary').click(); @@ -169,4 +169,51 @@ describe("Opportunity Page", () => { cy.get('.panel-entity-card__header > .left > .panel-entity-card__header--info > .panel-entity-card__header--info-link > .mc-title').contains("[Cópia]"); }); + + it("Garante preenchimento obrigatório na geração de modelo baseado em uma oportunidade", () => { + cy.visit("/autenticacao/"); + loginWith("Admin@local", "mapas123"); + cy.get(':nth-child(4) > :nth-child(1) > a').click(); + cy.get('.right > .button--primary').click(); + + cy.wait(1000); + + cy.get('.col-12 > .button').click(); + + cy.get('.modal__content > :nth-child(3) > :nth-child(1) > input').should('be.visible').clear(); + + cy.get(':nth-child(3) > textarea').should('be.visible').clear(); + + cy.get('.modal__action > .button--primary').click(); + + cy.contains('Todos os campos são obrigatorio'); + }); + + it("Garante geração de modelo baseado em uma oportunidade", () => { + cy.visit("/autenticacao/"); + loginWith("Admin@local", "mapas123"); + cy.get(':nth-child(4) > :nth-child(1) > a').click(); + cy.get('.right > .button--primary').click(); + + cy.wait(1000); + + cy.get('.col-12 > .button').click(); + + cy.contains("Salvar modelo"); + cy.contains("Para salvar um modelo, preencha os campos abaixo."); + cy.contains("Nome do modelo"); + cy.contains("Breve descrição do modelo"); + cy.contains("Salvar modelo"); + + cy.get('.modal__content > :nth-child(3) > :nth-child(1) > input').should('be.visible').clear().type('Nome do modelo'); + + cy.get(':nth-child(3) > textarea').should('be.visible').type('Descrição do modelo'); + + cy.get('.modal__action > .button--primary').click(); + cy.wait(3000); + + cy.visit("/minhas-oportunidades/#mymodels"); + cy.wait(1000); + cy.contains("Nome do modelo"); + }); }); diff --git a/src/modules/Entities/components/entity-actions/template.php b/src/modules/Entities/components/entity-actions/template.php index b0ef8de91f..c8a4afc4c5 100644 --- a/src/modules/Entities/components/entity-actions/template.php +++ b/src/modules/Entities/components/entity-actions/template.php @@ -9,6 +9,7 @@ $this->import(' mc-confirm-button mc-loading + opportunity-create-model '); ?>
@@ -47,16 +48,20 @@ +
+ +
+ applyTemplateHook('entity-actions--primary', 'end') ?>
applyTemplateHook('entity-actions--leftGroupBtn', 'after'); ?> diff --git a/src/modules/Entities/components/opportunity-create-model/README.md b/src/modules/Entities/components/opportunity-create-model/README.md new file mode 100644 index 0000000000..6e50a8aae7 --- /dev/null +++ b/src/modules/Entities/components/opportunity-create-model/README.md @@ -0,0 +1,11 @@ +# Componente `` + +### Importando componente +```PHP +import('opportunity-create-model'); +?> +``` +### Exemplos de uso +```HTML + \ No newline at end of file diff --git a/src/modules/Entities/components/opportunity-create-model/script.js b/src/modules/Entities/components/opportunity-create-model/script.js new file mode 100644 index 0000000000..48aa662fd8 --- /dev/null +++ b/src/modules/Entities/components/opportunity-create-model/script.js @@ -0,0 +1,62 @@ +app.component('opportunity-create-model', { + template: $TEMPLATES['opportunity-create-model'], + setup() { + const messages = useMessages(); + const text = Utils.getTexts('opportunity-create-model') + return { text, messages } + }, + props: { + entity: { + type: Entity, + required: true, + }, + }, + + data() { + let sendSuccess = false; + let formData = { + name: this.entity.name, + description: '', + } + + return { sendSuccess, formData } + }, + + methods: { + async save() { + this.__processing = this.text('Gerando modelo...'); + + const api = new API(this.entity.__objectType); + + let objt = this.formData; + objt.entityId = this.entity.id; + + let error = null; + + if (error = this.validade(objt)) { + let mess = ""; + mess = this.text('Todos os campos são obrigatorio'); + this.messages.error(mess); + return; + } + + await api.POST(`/opportunity/generatemodel/${objt.entityId}`, objt).then(res => { + this.messages.success(this.text('Modelo gerado com sucesso')); + this.sendSuccess = true; + window.location.href = '/minhas-oportunidades/#mymodels'; + }); + }, + validade(objt) { + let result = null; + let ignore = []; + + Object.keys(objt).forEach(function (item) { + if (!objt[item] && !ignore.includes(item)) { + result = item; + return; + } + }); + return result; + }, + }, +}); diff --git a/src/modules/Entities/components/opportunity-create-model/template.php b/src/modules/Entities/components/opportunity-create-model/template.php new file mode 100644 index 0000000000..4c0837446a --- /dev/null +++ b/src/modules/Entities/components/opportunity-create-model/template.php @@ -0,0 +1,39 @@ +import(" + mc-modal +"); +?> +
+ + + + + + + +
\ No newline at end of file diff --git a/src/modules/Entities/components/opportunity-create-model/texts.php b/src/modules/Entities/components/opportunity-create-model/texts.php new file mode 100644 index 0000000000..453df2b0a0 --- /dev/null +++ b/src/modules/Entities/components/opportunity-create-model/texts.php @@ -0,0 +1,10 @@ + i::__('Recaptcha inválida'), + 'Todos os campos são obrigatorio' => i::__('Todos os campos são obrigatorio'), + 'Modelo gerado com sucesso' => i::__('Modelo gerado com sucesso'), + 'Gerando modelo...' => i::__('Gerando modelo...'), +]; diff --git a/src/modules/Panel/components/panel--entity-card/script.js b/src/modules/Panel/components/panel--entity-card/script.js index 9dd18c6d72..ca55355f84 100644 --- a/src/modules/Panel/components/panel--entity-card/script.js +++ b/src/modules/Panel/components/panel--entity-card/script.js @@ -23,6 +23,10 @@ app.component('panel--entity-card', { return this.class; }, leftButtons() { + if (this.entity.isModel) { + return 'delete'; + } + let buttons = 'archive,delete,destroy'; if(this.entity.status === 0) { diff --git a/src/modules/Panel/components/panel--entity-tabs/script.js b/src/modules/Panel/components/panel--entity-tabs/script.js index 53cdb2c67f..b36f6bc5fb 100644 --- a/src/modules/Panel/components/panel--entity-tabs/script.js +++ b/src/modules/Panel/components/panel--entity-tabs/script.js @@ -11,10 +11,23 @@ app.component('panel--entity-tabs', { }, data() { - let query = { + let query = {}; + + if (this.type == 'opportunity') { + query.isModel = 'OR(NULL(), EQ(0))'; + } + + query = { + ...query, '@order': 'updateTimestamp DESC', '@permissions': 'view' }; + + let queryGetModel = { + '@order': 'updateTimestamp DESC', + '@permissions': 'view' + }; + if (this.user) { query.user = `EQ(${this.user})` } @@ -25,6 +38,7 @@ app.component('panel--entity-tabs', { publish: { status: 'GTE(1)', ...query }, draft: { status: 'EQ(0)', ...query }, granted: { ...query, '@permissions': '@control', status: 'GTE(0)', user: '!EQ(@me)' }, + mymodels: { status: 'EQ(-1)', isModel: 'EQ(1)', ...queryGetModel }, trash: { status: 'EQ(-10)', ...query }, archived: { status: 'EQ(-2)', ...query }, }, @@ -44,11 +58,11 @@ app.component('panel--entity-tabs', { }, select: { type: String, - default: 'id,status,name,type,createTimestamp,terms,files.avatar,currentUserPermissions' + default: 'id,status,name,type,createTimestamp,terms,files.avatar,currentUserPermissions,isModel' }, tabs: { type: String, - default: "publish,draft,granted,trash,archived" + default: "publish,draft,granted,mymodels,trash,archived" }, }, @@ -64,6 +78,8 @@ app.component('panel--entity-tabs', { if (status == 'publish') { return true; + } else if (status == 'mymodels' && this.type == 'opportunity') { + return true; } else if (typeof this.description?.status == 'undefined') { return false; } else if (typeof this.description?.status?.options[status] != 'undefined') { diff --git a/src/modules/Panel/components/panel--entity-tabs/template.php b/src/modules/Panel/components/panel--entity-tabs/template.php index abddb6c250..9e67392fd2 100644 --- a/src/modules/Panel/components/panel--entity-tabs/template.php +++ b/src/modules/Panel/components/panel--entity-tabs/template.php @@ -18,6 +18,7 @@ 'publish' => i::esc_attr__('Publicados'), 'draft' => i::esc_attr__('Em rascunho'), 'granted' => i::esc_attr__('Com permissão'), + 'mymodels' => i::esc_attr__('Meus modelos'), 'archived' => i::esc_attr__('Arquivados'), 'trash' => i::esc_attr__('Lixeira'), ]; @@ -70,7 +71,6 @@ -