Loading module/Oscar/src/Oscar/Service/ActivityAvenantsService.php +130 −6 Original line number Diff line number Diff line Loading @@ -8,6 +8,8 @@ use Moment\Moment; use Oscar\Entity\Activity; use Oscar\Entity\ActivityAvenant; use Oscar\Entity\ActivityAvenantModification; use Oscar\Entity\ActivityOrganization; use Oscar\Entity\ActivityPerson; use Oscar\Entity\Organization; use Oscar\Entity\OrganizationRole; use Oscar\Entity\Person; Loading @@ -22,20 +24,25 @@ use Oscar\Traits\UseLoggerService; use Oscar\Traits\UseLoggerServiceTrait; use Oscar\Traits\UseOscarConfigurationService; use Oscar\Traits\UseOscarConfigurationServiceTrait; use Oscar\Traits\UseProjectGrantService; use Oscar\Traits\UseProjectGrantServiceTrait; use Oscar\Utils\DateTimeUtils; use Oscar\Utils\FileSystemUtils; class ActivityAvenantsService implements UseLoggerService, UseEntityManager, UseActivityLogService, UseOscarConfigurationService UseEntityManager, UseLoggerService, UseOscarConfigurationService, UseProjectGrantService { use UseLoggerServiceTrait, UseEntityManagerTrait, use UseActivityLogServiceTrait, UseOscarConfigurationServiceTrait; UseEntityManagerTrait, UseLoggerServiceTrait, UseOscarConfigurationServiceTrait, UseProjectGrantServiceTrait; /** * Création d'un nouvel avenant. Loading Loading @@ -82,6 +89,7 @@ class ActivityAvenantsService implements public function saveAvenantFromArray(Activity $activity, array $datas): void { if ($datas['id']) { $this->getLoggerService()->debug("UPDATE avenant"); $mode = "update"; $avenant = $this->getEntityManager() ->getRepository(ActivityAvenant::class) Loading @@ -91,6 +99,7 @@ class ActivityAvenantsService implements } } else { $this->getLoggerService()->debug("CREATE avenant"); $mode = "create"; $avenant = new ActivityAvenant(); $avenant->setStatus(ActivityAvenant::STATUS_DRAFT); Loading Loading @@ -191,12 +200,127 @@ class ActivityAvenantsService implements $modification->setOldValue1($activity->getDateEndStr()); $activity->setDateEnd($modification->getNewValue1()); break; case ActivityAvenantModification::TYPE_CHANGE_AMOUNT: $this->getLoggerService()->info($modification->getNewValue1()); $modification->setOldValue1($activity->getAmount()); $activity->setAmount($modification->getNewValue1()); break; case ActivityAvenantModification::TYPE_PERSON_ADD: try { $person = $this->getEntityManager() ->getRepository(Person::class) ->find($modification->getNewValue1()); $this->getLoggerService()->info('person: ' . $person); $role = $this->getEntityManager() ->getRepository(Role::class) ->find($modification->getNewValue2()); $this->getLoggerService()->info('role: ' . $role); $this->getProjectGrantService()->getPersonService()->personActivityAdd( $activity, $person, $role); } catch (\Exception $e){ $this->getLoggerService()->critical($e->getMessage()); throw new OscarException("Impossible d'ajouter la personne dans l'activité"); } break; case ActivityAvenantModification::TYPE_PERSON_DEL: try { $person = $this->getEntityManager() ->getRepository(Person::class) ->find($modification->getNewValue1()); $this->getLoggerService()->info('person: ' . $person); $role = $this->getEntityManager() ->getRepository(Role::class) ->find($modification->getNewValue2()); $this->getLoggerService()->info('role: ' . $role); /** @var ActivityPerson $repo */ $affectations = $this->getEntityManager() ->getRepository(ActivityPerson::class) ->findBy([ 'activity' => $activity, 'person' => $person, 'roleObj' => $role, ]); if( count($affectations) === 0 ) { throw new OscarException("Affectation non-trouvée"); } foreach ($affectations as $affectation) { $this->getProjectGrantService() ->getPersonService() ->personActivityRemove($affectation); } } catch (\Exception $e){ $this->getLoggerService()->critical($e->getMessage()); throw new OscarException("Impossible de supprimer la personne dans l'activité"); } break; case ActivityAvenantModification::TYPE_ORGANIZATION_ADD: try { $organization = $this->getEntityManager() ->getRepository(Organization::class) ->find($modification->getNewValue1()); $this->getLoggerService()->info('organization: ' . $organization); $role = $this->getEntityManager() ->getRepository(OrganizationRole::class) ->find($modification->getNewValue2()); $this->getLoggerService()->info('role: ' . $role); $this->getProjectGrantService()->organizationActivityAdd( $organization, $activity, $role); } catch (\Exception $e){ $this->getLoggerService()->critical($e->getMessage()); throw new OscarException("Impossible d'ajouter l'organisation dans l'activité"); } break; case ActivityAvenantModification::TYPE_ORGANIZATION_DEL: try { $organization = $this->getEntityManager() ->getRepository(Organization::class) ->find($modification->getNewValue1()); $role = $this->getEntityManager() ->getRepository(OrganizationRole::class) ->find($modification->getNewValue2()); /** @var ActivityPerson $repo */ $affectations = $this->getEntityManager() ->getRepository(ActivityOrganization::class) ->findBy([ 'activity' => $activity, 'organization' => $organization, 'roleObj' => $role, ]); if( count($affectations) === 0 ) { throw new OscarException("Affectation non-trouvée"); } foreach ($affectations as $affectation) { $this->getProjectGrantService() ->activityOrganizationRemove($affectation); } } catch (\Exception $e){ $this->getLoggerService()->critical($e->getMessage()); throw new OscarException("Impossible de supprimer l'organisation dans l'activité"); } break; default: throw new OscarException("Type de modification '".$modification->getType()."' non-traité"); } } Loading module/Oscar/src/Oscar/Service/ActivityAvenantsServiceFactory.php +1 −0 Original line number Diff line number Diff line Loading @@ -13,6 +13,7 @@ class ActivityAvenantsServiceFactory implements FactoryInterface $s->setEntityManager($container->get(EntityManager::class)); $s->setOscarConfigurationService($container->get(OscarConfigurationService::class)); $s->setLoggerService($container->get('Logger')); $s->setProjectGrantService($container->get(ProjectGrantService::class)); return $s; } } No newline at end of file ui/src/utils/ButtonConfirm.vue 0 → 100644 +119 −0 Original line number Diff line number Diff line <template> <div v-if="modal" class="overlay confirm-dialog"> <div class="overlay-content"> <h3> <i class="icon-attention-1"></i> <slot name="title"> Confirmer ? </slot> </h3> <div class="overlay-message"> <slot name="message"> Voulez-vous continuer ? </slot> </div> <div v-if="checkbox"> <label for="confirm_ok" class="checkbox"> <input type="checkbox" id="confirm_ok" v-model="checked" /> J'ai bien compris </label> </div> <nav> <a href="#" @click.prevent="handlerCancel" class="btn btn-danger"> <i class="icon-block"></i> Annuler </a> <a href="#" @click.prevent="handlerConfirm" class="btn btn-success" :class="{'disabled': !confirmEnabled}"> <i class="icon-ok-circled"></i> Confirmer</a> </nav> </div> </div> <a href="#" :class="class" @click.prevent="modal = true"> <slot>Texte par défaut</slot> </a> </template> <script> export default { name: 'ButtonConfirm', props: { class: { type: String, default: 'btn btn-default' }, checkbox: { type: Boolean, default: false } }, data() { return { modal: false, checked: false } }, computed: { confirmEnabled () { return (this.checkbox && this.checked) || this.checkbox === false; } }, watch: { modal(val) { this.checked = false; } }, methods: { handlerClick() { this.$emit('click'); }, handlerCancel() { this.modal = false; this.$emit('cancel'); }, handlerConfirm() { if( this.confirmEnabled ){ this.modal = false; this.$emit('confirm'); } } }, activated() { console.log('ButtonConfirm activated'); } } </script> <style scoped> .confirm-dialog { z-index: 10000; .overlay-content { flex-basis: 30% !important; h3 { border-bottom: thin solid #eee; margin: .25em .5em; padding: .25em .5em; } .overlay-message { font-size: 1.4em; } nav { height: 50px; width: 100%; padding: .25em .5em; margin: .25em .5em; border-top: thin solid #eee; display: flex; flex-wrap: wrap; justify-content: space-between; align-content: space-between; a.btn { } } } } </style> No newline at end of file ui/src/views/ActivityAvenants.vue +39 −14 Original line number Diff line number Diff line Loading @@ -141,7 +141,7 @@ <section class="avenants"> <article class="avenant card" v-for="a in avenants.avenants"> <h3> <h4> <i class="icon-ok-circled text-success" v-if="a.status == 200"></i> <i class="icon-pencil" v-if="a.status == 100"></i> <strong> Loading @@ -150,9 +150,8 @@ <small> - {{ a.status_text }} </small> </h3> {{ a }} <section class="modification"> </h4> <section class="modification small"> <article class="change" v-for="change in a.modifications"> <i class="icon-calendar" v-if="change.type === 'dateEnd'"></i> <i class="icon-user" v-if="change.type === 'personAdd'"></i> Loading @@ -167,20 +166,37 @@ </section> <p>{{ a.comment }}</p> <nav> <a :href="a.url_download" class="btn btn-xs btn-primary"> <i class="icon-file-pdf"></i> Télécharger</a> <a href="#" class="btn btn-xs btn-danger" @click.prevent="handlerDelete(a)" v-if="manage"> <ButtonConfirm @confirm="handlerDelete(a)" :class="'btn btn-xs btn-danger'" v-if="manage" :checkbox="true"> <i class="icon-trash"></i> Supprimer</a> Supprimer <template #message> Supprimer <strong>définitivement</strong> cet avenant ? </template> </ButtonConfirm> <a href="#" class="btn btn-xs btn-default" @click.prevent="handlerEdit(a)" v-if="manage && a.editable"> <i class="icon-pencil"></i> Editer </a> <a href="#" class="btn btn-xs btn-success" @click.prevent="handlerApplyAvenant(a)" v-if="a.status === 100 && manage"> <i class="icon-valid"></i> Appliquer l'avenant </a> <ButtonConfirm @confirm="handlerApplyAvenant(a)" :class="'btn btn-xs btn-success'" v-if="a.status === 100 && manage"> <i class="icon-trash"></i> Appliquer <template #message> Confirmer l'application de l'avenant pour cette activité ? <strong>L'activité sera verrouillée</strong> </template> </ButtonConfirm> </nav> </article> </section> Loading @@ -188,9 +204,6 @@ <button class="btn btn-primary" @click="handlerNew" v-if="manage"> Nouvel avenant </button> <button class="btn btn-primary" @click="fetch"> Fetch </button> </template> <script> Loading @@ -201,11 +214,13 @@ import PersonAutoCompleter from "../components/PersonAutoCompleter.vue"; import AxiosOscar from "../utils/AxiosOscar.js"; import OrganizationAutoComplete from "../components/OrganizationAutoComplete.vue"; import Amount from "../components/Amount.vue"; import ButtonConfirm from "../utils/ButtonConfirm.vue"; //import Test from "../../../vendor/unicaen/signature/public/src/views/SignatureFlows.vue"; export default { name: 'ActivityAvenants', components: { ButtonConfirm, Amount, AvenantDate, Datepicker, Loading Loading @@ -277,6 +292,16 @@ export default { }, methods: { handlerConfirm(message, handler, args){ console.log("confirm", message); handler.call(this, args); }, handlerOk(arg){ console.log(JSON.stringify(arg)); console.log(this.avenants.url_api); }, handlerNew() { this.edit = { id: null, Loading Loading @@ -381,7 +406,7 @@ export default { firstName: event.firstName, lastName: event.lastName, }; change.value1 = event.valueObj.id; change.value1 = event.id; }, handlerUpdateOrganizationChange(change, event) { Loading Loading
module/Oscar/src/Oscar/Service/ActivityAvenantsService.php +130 −6 Original line number Diff line number Diff line Loading @@ -8,6 +8,8 @@ use Moment\Moment; use Oscar\Entity\Activity; use Oscar\Entity\ActivityAvenant; use Oscar\Entity\ActivityAvenantModification; use Oscar\Entity\ActivityOrganization; use Oscar\Entity\ActivityPerson; use Oscar\Entity\Organization; use Oscar\Entity\OrganizationRole; use Oscar\Entity\Person; Loading @@ -22,20 +24,25 @@ use Oscar\Traits\UseLoggerService; use Oscar\Traits\UseLoggerServiceTrait; use Oscar\Traits\UseOscarConfigurationService; use Oscar\Traits\UseOscarConfigurationServiceTrait; use Oscar\Traits\UseProjectGrantService; use Oscar\Traits\UseProjectGrantServiceTrait; use Oscar\Utils\DateTimeUtils; use Oscar\Utils\FileSystemUtils; class ActivityAvenantsService implements UseLoggerService, UseEntityManager, UseActivityLogService, UseOscarConfigurationService UseEntityManager, UseLoggerService, UseOscarConfigurationService, UseProjectGrantService { use UseLoggerServiceTrait, UseEntityManagerTrait, use UseActivityLogServiceTrait, UseOscarConfigurationServiceTrait; UseEntityManagerTrait, UseLoggerServiceTrait, UseOscarConfigurationServiceTrait, UseProjectGrantServiceTrait; /** * Création d'un nouvel avenant. Loading Loading @@ -82,6 +89,7 @@ class ActivityAvenantsService implements public function saveAvenantFromArray(Activity $activity, array $datas): void { if ($datas['id']) { $this->getLoggerService()->debug("UPDATE avenant"); $mode = "update"; $avenant = $this->getEntityManager() ->getRepository(ActivityAvenant::class) Loading @@ -91,6 +99,7 @@ class ActivityAvenantsService implements } } else { $this->getLoggerService()->debug("CREATE avenant"); $mode = "create"; $avenant = new ActivityAvenant(); $avenant->setStatus(ActivityAvenant::STATUS_DRAFT); Loading Loading @@ -191,12 +200,127 @@ class ActivityAvenantsService implements $modification->setOldValue1($activity->getDateEndStr()); $activity->setDateEnd($modification->getNewValue1()); break; case ActivityAvenantModification::TYPE_CHANGE_AMOUNT: $this->getLoggerService()->info($modification->getNewValue1()); $modification->setOldValue1($activity->getAmount()); $activity->setAmount($modification->getNewValue1()); break; case ActivityAvenantModification::TYPE_PERSON_ADD: try { $person = $this->getEntityManager() ->getRepository(Person::class) ->find($modification->getNewValue1()); $this->getLoggerService()->info('person: ' . $person); $role = $this->getEntityManager() ->getRepository(Role::class) ->find($modification->getNewValue2()); $this->getLoggerService()->info('role: ' . $role); $this->getProjectGrantService()->getPersonService()->personActivityAdd( $activity, $person, $role); } catch (\Exception $e){ $this->getLoggerService()->critical($e->getMessage()); throw new OscarException("Impossible d'ajouter la personne dans l'activité"); } break; case ActivityAvenantModification::TYPE_PERSON_DEL: try { $person = $this->getEntityManager() ->getRepository(Person::class) ->find($modification->getNewValue1()); $this->getLoggerService()->info('person: ' . $person); $role = $this->getEntityManager() ->getRepository(Role::class) ->find($modification->getNewValue2()); $this->getLoggerService()->info('role: ' . $role); /** @var ActivityPerson $repo */ $affectations = $this->getEntityManager() ->getRepository(ActivityPerson::class) ->findBy([ 'activity' => $activity, 'person' => $person, 'roleObj' => $role, ]); if( count($affectations) === 0 ) { throw new OscarException("Affectation non-trouvée"); } foreach ($affectations as $affectation) { $this->getProjectGrantService() ->getPersonService() ->personActivityRemove($affectation); } } catch (\Exception $e){ $this->getLoggerService()->critical($e->getMessage()); throw new OscarException("Impossible de supprimer la personne dans l'activité"); } break; case ActivityAvenantModification::TYPE_ORGANIZATION_ADD: try { $organization = $this->getEntityManager() ->getRepository(Organization::class) ->find($modification->getNewValue1()); $this->getLoggerService()->info('organization: ' . $organization); $role = $this->getEntityManager() ->getRepository(OrganizationRole::class) ->find($modification->getNewValue2()); $this->getLoggerService()->info('role: ' . $role); $this->getProjectGrantService()->organizationActivityAdd( $organization, $activity, $role); } catch (\Exception $e){ $this->getLoggerService()->critical($e->getMessage()); throw new OscarException("Impossible d'ajouter l'organisation dans l'activité"); } break; case ActivityAvenantModification::TYPE_ORGANIZATION_DEL: try { $organization = $this->getEntityManager() ->getRepository(Organization::class) ->find($modification->getNewValue1()); $role = $this->getEntityManager() ->getRepository(OrganizationRole::class) ->find($modification->getNewValue2()); /** @var ActivityPerson $repo */ $affectations = $this->getEntityManager() ->getRepository(ActivityOrganization::class) ->findBy([ 'activity' => $activity, 'organization' => $organization, 'roleObj' => $role, ]); if( count($affectations) === 0 ) { throw new OscarException("Affectation non-trouvée"); } foreach ($affectations as $affectation) { $this->getProjectGrantService() ->activityOrganizationRemove($affectation); } } catch (\Exception $e){ $this->getLoggerService()->critical($e->getMessage()); throw new OscarException("Impossible de supprimer l'organisation dans l'activité"); } break; default: throw new OscarException("Type de modification '".$modification->getType()."' non-traité"); } } Loading
module/Oscar/src/Oscar/Service/ActivityAvenantsServiceFactory.php +1 −0 Original line number Diff line number Diff line Loading @@ -13,6 +13,7 @@ class ActivityAvenantsServiceFactory implements FactoryInterface $s->setEntityManager($container->get(EntityManager::class)); $s->setOscarConfigurationService($container->get(OscarConfigurationService::class)); $s->setLoggerService($container->get('Logger')); $s->setProjectGrantService($container->get(ProjectGrantService::class)); return $s; } } No newline at end of file
ui/src/utils/ButtonConfirm.vue 0 → 100644 +119 −0 Original line number Diff line number Diff line <template> <div v-if="modal" class="overlay confirm-dialog"> <div class="overlay-content"> <h3> <i class="icon-attention-1"></i> <slot name="title"> Confirmer ? </slot> </h3> <div class="overlay-message"> <slot name="message"> Voulez-vous continuer ? </slot> </div> <div v-if="checkbox"> <label for="confirm_ok" class="checkbox"> <input type="checkbox" id="confirm_ok" v-model="checked" /> J'ai bien compris </label> </div> <nav> <a href="#" @click.prevent="handlerCancel" class="btn btn-danger"> <i class="icon-block"></i> Annuler </a> <a href="#" @click.prevent="handlerConfirm" class="btn btn-success" :class="{'disabled': !confirmEnabled}"> <i class="icon-ok-circled"></i> Confirmer</a> </nav> </div> </div> <a href="#" :class="class" @click.prevent="modal = true"> <slot>Texte par défaut</slot> </a> </template> <script> export default { name: 'ButtonConfirm', props: { class: { type: String, default: 'btn btn-default' }, checkbox: { type: Boolean, default: false } }, data() { return { modal: false, checked: false } }, computed: { confirmEnabled () { return (this.checkbox && this.checked) || this.checkbox === false; } }, watch: { modal(val) { this.checked = false; } }, methods: { handlerClick() { this.$emit('click'); }, handlerCancel() { this.modal = false; this.$emit('cancel'); }, handlerConfirm() { if( this.confirmEnabled ){ this.modal = false; this.$emit('confirm'); } } }, activated() { console.log('ButtonConfirm activated'); } } </script> <style scoped> .confirm-dialog { z-index: 10000; .overlay-content { flex-basis: 30% !important; h3 { border-bottom: thin solid #eee; margin: .25em .5em; padding: .25em .5em; } .overlay-message { font-size: 1.4em; } nav { height: 50px; width: 100%; padding: .25em .5em; margin: .25em .5em; border-top: thin solid #eee; display: flex; flex-wrap: wrap; justify-content: space-between; align-content: space-between; a.btn { } } } } </style> No newline at end of file
ui/src/views/ActivityAvenants.vue +39 −14 Original line number Diff line number Diff line Loading @@ -141,7 +141,7 @@ <section class="avenants"> <article class="avenant card" v-for="a in avenants.avenants"> <h3> <h4> <i class="icon-ok-circled text-success" v-if="a.status == 200"></i> <i class="icon-pencil" v-if="a.status == 100"></i> <strong> Loading @@ -150,9 +150,8 @@ <small> - {{ a.status_text }} </small> </h3> {{ a }} <section class="modification"> </h4> <section class="modification small"> <article class="change" v-for="change in a.modifications"> <i class="icon-calendar" v-if="change.type === 'dateEnd'"></i> <i class="icon-user" v-if="change.type === 'personAdd'"></i> Loading @@ -167,20 +166,37 @@ </section> <p>{{ a.comment }}</p> <nav> <a :href="a.url_download" class="btn btn-xs btn-primary"> <i class="icon-file-pdf"></i> Télécharger</a> <a href="#" class="btn btn-xs btn-danger" @click.prevent="handlerDelete(a)" v-if="manage"> <ButtonConfirm @confirm="handlerDelete(a)" :class="'btn btn-xs btn-danger'" v-if="manage" :checkbox="true"> <i class="icon-trash"></i> Supprimer</a> Supprimer <template #message> Supprimer <strong>définitivement</strong> cet avenant ? </template> </ButtonConfirm> <a href="#" class="btn btn-xs btn-default" @click.prevent="handlerEdit(a)" v-if="manage && a.editable"> <i class="icon-pencil"></i> Editer </a> <a href="#" class="btn btn-xs btn-success" @click.prevent="handlerApplyAvenant(a)" v-if="a.status === 100 && manage"> <i class="icon-valid"></i> Appliquer l'avenant </a> <ButtonConfirm @confirm="handlerApplyAvenant(a)" :class="'btn btn-xs btn-success'" v-if="a.status === 100 && manage"> <i class="icon-trash"></i> Appliquer <template #message> Confirmer l'application de l'avenant pour cette activité ? <strong>L'activité sera verrouillée</strong> </template> </ButtonConfirm> </nav> </article> </section> Loading @@ -188,9 +204,6 @@ <button class="btn btn-primary" @click="handlerNew" v-if="manage"> Nouvel avenant </button> <button class="btn btn-primary" @click="fetch"> Fetch </button> </template> <script> Loading @@ -201,11 +214,13 @@ import PersonAutoCompleter from "../components/PersonAutoCompleter.vue"; import AxiosOscar from "../utils/AxiosOscar.js"; import OrganizationAutoComplete from "../components/OrganizationAutoComplete.vue"; import Amount from "../components/Amount.vue"; import ButtonConfirm from "../utils/ButtonConfirm.vue"; //import Test from "../../../vendor/unicaen/signature/public/src/views/SignatureFlows.vue"; export default { name: 'ActivityAvenants', components: { ButtonConfirm, Amount, AvenantDate, Datepicker, Loading Loading @@ -277,6 +292,16 @@ export default { }, methods: { handlerConfirm(message, handler, args){ console.log("confirm", message); handler.call(this, args); }, handlerOk(arg){ console.log(JSON.stringify(arg)); console.log(this.avenants.url_api); }, handlerNew() { this.edit = { id: null, Loading Loading @@ -381,7 +406,7 @@ export default { firstName: event.firstName, lastName: event.lastName, }; change.value1 = event.valueObj.id; change.value1 = event.id; }, handlerUpdateOrganizationChange(change, event) { Loading