Loading module/Oscar/src/Oscar/Controller/ActivityAvenantsController.php +16 −33 Original line number Diff line number Diff line Loading @@ -71,20 +71,32 @@ class ActivityAvenantsController extends AbstractOscarController implements UseL } catch (\Exception $e) { return $this->jsonError("Impossible de charger les avenants"); } break; case 'POST': // TODO Tester les droits d'accès $datas = $_POST; $action = $_POST['action']; switch($action){ case "create": try { $datas['file'] = $this->fileAvenantDrop($activity); $datas['status'] = ActivityAvenant::STATUS_DRAFT; $this->getLoggerService()->debug(print_r($datas, true)); $this->getActivityAvenantsService()->createAvenantFromArray($activity, $datas); $this->getActivityAvenantsService()->saveAvenantFromArray($activity, $datas); return $this->getResponseOk("Avenant ajouté"); } catch (\Exception $e) { return $this->jsonError("Impossible d'ajouter l'avenant : " . $e->getMessage()); } case "update": try { $this->getActivityAvenantsService()->saveAvenantFromArray($activity, $datas); return $this->getResponseOk("Avenant modifié"); } catch (\Exception $e) { return $this->jsonError("Impossible de mettre à jour l'avenant : " . $e->getMessage()); } default: return $this->jsonError("Action non reconnue"); } case 'DELETE': // TODO Tester les droits d'accès Loading Loading @@ -151,33 +163,4 @@ class ActivityAvenantsController extends AbstractOscarController implements UseL throw new OscarException("Impossible de charger l'activité $idActivity"); } } private function fileAvenantDrop( Activity $activity ) :string { if( !array_key_exists('file', $_FILES) ){ $this->getLoggerService()->error("Aucun fichier d'avenant envoyé"); throw new OscarException("Fichier manquant"); } try { $uploader = new FileUploadStandard(); $avenant_directory = $this->getOscarConfigurationService()->getDocumentDropLocation(); $filename_pattern = $this->getOscarConfigurationService()->getConfiguration('avenant_filename'); $filename = sprintf( $filename_pattern, $activity->getId(), (new \DateTime())->format('Y-m-d'), uniqid() ); $mimes = ["application/pdf" => "pdf"]; $uploader->setDestination($avenant_directory) ->setFilename($filename) ->setMimesAllowed($mimes); $uploader->updoad($_FILES['file']); $this->getLoggerService()->info("Upload ok"); return $uploader->getUploadName(); } catch (\Exception $e){ $this->getLoggerService()->error($e->getMessage()); throw new OscarException("Impossible de téléverser le fichier de l'avenant : " . $e->getMessage()); } } } module/Oscar/src/Oscar/Entity/ActivityAvenant.php +29 −0 Original line number Diff line number Diff line Loading @@ -3,6 +3,8 @@ namespace Oscar\Entity; use DateTime; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; /** Loading Loading @@ -36,6 +38,14 @@ class ActivityAvenant */ private Activity $activity; /** * Liste des modifications * * @var ArrayCollection * @ORM\OneToMany(targetEntity="ActivityAvenantModification", mappedBy="avenant", cascade={"remove"}) */ protected $modifications; /** * @var string * @ORM\Column(type="string") Loading @@ -54,6 +64,11 @@ class ActivityAvenant */ private int $status; public function __construct() { $this->modifications = new ArrayCollection(); } /** * @return mixed */ Loading Loading @@ -122,6 +137,20 @@ class ActivityAvenant return $this; } /** * @return ActivityAvenantModification[] */ public function getModifications() { return $this->modifications; } public function setModifications($modifications): self { $this->modifications = $modifications; return $this; } public function getResourceId() { return self::class; Loading module/Oscar/src/Oscar/Entity/ActivityAvenantModification.php +77 −30 Original line number Diff line number Diff line Loading @@ -10,6 +10,25 @@ use Doctrine\ORM\Mapping as ORM; */ class ActivityAvenantModification { const TYPE_PERSON_DEL = 'personDel'; const TYPE_PERSON_ADD = 'personAdd'; const TYPE_ORGANIZATION_ADD = 'organizationAdd'; const TYPE_ORGANIZATION_DEL = 'organizationDel'; const TYPE_CHANGE_AMOUNT = 'changeAmount'; const TYPE_DATE_END = 'dateEnd'; public static function getTypes(): array { return array( self::TYPE_PERSON_DEL => "Suppression d'une personne", self::TYPE_PERSON_ADD => "Ajout d'une personne", self::TYPE_ORGANIZATION_ADD => "Suppression d'une organization", self::TYPE_ORGANIZATION_DEL => "Ajout d'une organisation", self::TYPE_CHANGE_AMOUNT => "Modification du montant", self::TYPE_DATE_END => "Modification de la date de fin", ); } /** * @ORM\Id * @ORM\GeneratedValue(strategy="IDENTITY") Loading @@ -17,12 +36,6 @@ class ActivityAvenantModification */ private $id; /** * @var Activity * @ORM\ManyToOne(targetEntity="ActivityAvenant") */ private Activity $avenant; /** * @var string * @ORM\Column(type="string") Loading @@ -30,43 +43,55 @@ class ActivityAvenantModification private string $type; /** * @var string * @ORM\Column(type="string") * @var ?string * @ORM\Column(type="string", nullable=true) */ private string $newValue1; private ?string $newValue1; /** * @var string * @ORM\Column(type="string") * @var ?string * @ORM\Column(type="string", nullable=true) */ private string $oldValue1; private ?string $oldValue1; /** * @var string * @ORM\Column(type="string") * @var ?string * @ORM\Column(type="string", nullable=true) */ private string $newValue2; private ?string $newValue2; /** * @var string * @ORM\Column(type="string") * @var ?string * @ORM\Column(type="string", nullable=true) */ private string $oldValue2; private ?string $oldValue2; /** * @var ?string * @ORM\Column(type="string", nullable=true) */ private ?string $info; /** * @var ActivityAvenant * @ORM\ManyToOne(targetEntity="ActivityAvenant", inversedBy="modifications") */ private ActivityAvenant $avenant; /** * @return mixed */ public function getId() public function getId(): mixed { return $this->id; } public function getAvenant(): Activity public function getAvenant(): ActivityAvenant { return $this->avenant; } public function setAvenant(Activity $avenant): self public function setAvenant(ActivityAvenant $avenant): self { $this->avenant = $avenant; return $this; Loading @@ -83,52 +108,74 @@ class ActivityAvenantModification return $this; } public function getNewValue1(): string public function getNewValue1(): ?string { return $this->newValue1; } public function setNewValue1(string $newValue1): self public function setNewValue1(?string $newValue1): self { $this->newValue1 = $newValue1; return $this; } public function getOldValue1(): string public function getOldValue1(): ?string { return $this->oldValue1; } public function setOldValue1(string $oldValue1): self public function setOldValue1(?string $oldValue1): self { $this->oldValue1 = $oldValue1; return $this; } public function getNewValue2(): string public function getNewValue2(): ?string { return $this->newValue2; } public function setNewValue2(string $newValue2): self public function setNewValue2(?string $newValue2): self { $this->newValue2 = $newValue2; return $this; } public function getOldValue2(): string public function getOldValue2(): ?string { return $this->oldValue2; } public function setOldValue2(string $oldValue2): self public function setOldValue2(?string $oldValue2): self { $this->oldValue2 = $oldValue2; return $this; } public function getResourceId() public function getInfo(): ?string { return $this->info; } public function setInfo(?string $info): self { $this->info = $info; return $this; } public function getResourceId(): string { return self::class; } public function toJson() :array { return [ 'id' => $this->getId(), 'type' => $this->getType(), 'value1' => $this->getNewValue1(), 'value2' => $this->getNewValue2(), 'oldValue1' => $this->getOldValue1(), 'info' => $this->getInfo(), ]; } } module/Oscar/src/Oscar/Service/ActivityAvenantsService.php +176 −1 Original line number Diff line number Diff line Loading @@ -2,13 +2,20 @@ namespace Oscar\Service; use Doctrine\ORM\Exception\NotSupported; use Doctrine\ORM\Exception\ORMException; use Moment\Moment; use Oscar\Entity\Activity; use Oscar\Entity\ActivityAvenant; use Oscar\Entity\ActivityAvenantModification; use Oscar\Entity\ActivityPayment; use Oscar\Entity\Currency; use Oscar\Entity\LogActivity; use Oscar\Entity\Person; use Oscar\Entity\Repository\ActivityPaymentRepository; use Oscar\Entity\Role; use Oscar\Exception\OscarException; use Oscar\Strategy\Upload\FileUploadStandard; use Oscar\Traits\UseActivityLogService; use Oscar\Traits\UseActivityLogServiceTrait; use Oscar\Traits\UseEntityManager; Loading Loading @@ -71,6 +78,80 @@ class ActivityAvenantsService implements } } /** * @param Activity $activity * @param array $datas * @return void * @throws OscarException */ public function saveAvenantFromArray(Activity $activity, array $datas): void { $this->getLoggerService()->debug(__METHOD__); $this->getLoggerService()->debug(json_encode($datas)); if ($datas['id']) { $mode = "update"; $avenant = $this->getEntityManager()->getRepository(ActivityAvenant::class)->find($datas['id']); } else { $mode = "create"; $avenant = new ActivityAvenant(); $avenant->setStatus(ActivityAvenant::STATUS_DRAFT); $avenant->setActivity($activity); $this->getEntityManager()->persist($avenant); } // Traitement des données try { $avenant_date = DateTimeUtils::getDateTimeFromStr($datas['dateAvenant']); } catch (\Exception $e) { throw new OscarException("Date de l'avenant invalide"); } $idsModification = []; foreach ($avenant->getModifications() as $modification) { $idsModification[] = $modification->getId(); } if ($datas['modifications']) { $modificationsSend = json_decode($datas['modifications'], true); foreach ($modificationsSend as $modification) { $idsModification = array_diff($idsModification, [$modification['id']]); $this->saveModification($avenant, $modification); } } $fileUploaded = $this->uploadAvenantFile($activity); if (($mode == "update" && $fileUploaded)) { $this->deleteAvenantFile($avenant->getFilename()); } if ($fileUploaded) { $avenant->setFilename($fileUploaded); } if (($mode == "create" && !$fileUploaded)) { throw new OscarException("Fichier manquant"); } // Modification foreach ($idsModification as $modificationId) { $modification = $this->getEntityManager()->getRepository(ActivityAvenantModification::class)->find($modificationId); $this->getEntityManager()->remove($modification); } try { $avenant->setDateAvenant($avenant_date); $avenant->setComment($datas['comment']); $this->getEntityManager()->flush(); } catch (\Exception $e) { $this->getLoggerService()->critical($e->getMessage()); if ($fileUploaded) { $this->deleteAvenantFile($fileUploaded); } throw new OscarException("Impossible de créer l'avenant"); } } /** * @param mixed $id * @return void Loading @@ -84,13 +165,41 @@ class ActivityAvenantsService implements $this->deleteAvenantFile($avenant->getFilename()); $this->getEntityManager()->remove($avenant); $this->getEntityManager()->flush(); } catch (\Exception $e) { $this->getLoggerService()->critical($e->getMessage()); throw new OscarException("Impossible de supprimer l'avenant"); } } private function uploadAvenantFile(Activity $activity): ?string { if (!array_key_exists('file', $_FILES)) { $this->getLoggerService()->error("Aucun fichier d'avenant envoyé"); return null; } try { $uploader = new FileUploadStandard(); $avenant_directory = $this->getOscarConfigurationService()->getDocumentDropLocation(); $filename_pattern = $this->getOscarConfigurationService()->getConfiguration('avenant_filename'); $filename = sprintf( $filename_pattern, $activity->getId(), (new \DateTime())->format('Y-m-d'), uniqid() ); $mimes = ["application/pdf" => "pdf"]; $uploader->setDestination($avenant_directory) ->setFilename($filename) ->setMimesAllowed($mimes); $uploader->updoad($_FILES['file']); $this->getLoggerService()->info("Upload ok"); return $uploader->getUploadName(); } catch (\Exception $e) { $this->getLoggerService()->error($e->getMessage()); throw new OscarException("Impossible de téléverser le fichier de l'avenant : " . $e->getMessage()); } } /** * @param string $filename * @return bool Loading Loading @@ -124,6 +233,8 @@ class ActivityAvenantsService implements $size = filesize($location); $filename = $avenant->getFilename(); // Déplacer le type dans la BDD $type = 'application/pdf'; $content = FileSystemUtils::getInstance()->file_get_contents($location); Loading Loading @@ -159,4 +270,68 @@ class ActivityAvenantsService implements throw new OscarException($msg); } } /** * @param ActivityAvenant $avenant * @param array $modification * @param bool $fetch * @return void * @throws NotSupported * @throws ORMException * @throws OscarException */ private function saveModification(ActivityAvenant $avenant, array $modification, bool $fetch = false): void { $this->getLoggerService()->debug("Traitement modification"); $this->getLoggerService()->debug(json_encode($modification)); $type = $modification['type']; $newValue1 = $modification['value1']; $newValue2 = $modification['value2']; $oldValue1 = null; $oldValue2 = null; if( !array_key_exists($type, ActivityAvenantModification::getTypes()) ) { throw new OscarException("Le type d'avenant '$type' n'existe pas"); } if ($modification['id']) { $avenantModif = $this->getEntityManager()->getRepository(ActivityAvenantModification::class)->find( $modification['id'] ); } else { $avenantModif = new ActivityAvenantModification(); $this->getEntityManager()->persist($avenantModif); $avenantModif->setAvenant($avenant); } $msg = "Modification non-traitée"; switch ($type) { case ActivityAvenantModification::TYPE_DATE_END: $moment = Moment::fromDateTime(new \DateTime($newValue1)); $msg = "Modification de la date de fin pour " . $moment->format('d/m/Y'); $oldValue1 = $avenant->getActivity()->getDateEndStr(); break; case ActivityAvenantModification::TYPE_PERSON_DEL: $person = $this->getEntityManager()->getRepository(Person::class)->find($newValue1); $role = $this->getEntityManager()->getRepository(Role::class)->find($newValue2); $msg = "Suppression de $person ($role)"; break; case ActivityAvenantModification::TYPE_PERSON_ADD: $person = $this->getEntityManager()->getRepository(Person::class)->find($newValue1); $role = $this->getEntityManager()->getRepository(Role::class)->find($newValue2); $msg = "Ajout de $person ($role)"; break; } $avenantModif->setType($modification['type']); $avenantModif->setNewValue1($newValue1); $avenantModif->setNewValue2($newValue2); $avenantModif->setOldValue1($oldValue1); $avenantModif->setOldValue2($oldValue2); $avenantModif->setInfo($msg); $this->getLoggerService()->debug("MODIF : " . $modification['type']); } } No newline at end of file module/Oscar/src/Oscar/Service/ProjectGrantApiService.php +27 −8 Original line number Diff line number Diff line Loading @@ -171,7 +171,6 @@ class ProjectGrantApiService implements UseEntityManager, UsePersonService, UseO OscarUserContext $oscarUserContext, array $perimeters ): array { $locked = $activity->isLocked(); $editable = $oscarUserContext->hasPrivileges(Privileges::ACTIVITY_EDIT, $activity); $lockEditable = $oscarUserContext->hasPrivileges(Privileges::ACTIVITY_EDIT_LOCKED, $activity); Loading Loading @@ -283,15 +282,27 @@ class ProjectGrantApiService implements UseEntityManager, UsePersonService, UseO case 'milestones': $credentials['milestones'] = [ 'read' => $oscarUserContext->hasPrivileges(Privileges::ACTIVITY_MILESTONE_SHOW, $activity), 'edit' => $oscarUserContext->hasPrivileges(Privileges::ACTIVITY_MILESTONE_MANAGE, $activity), 'progression' => $oscarUserContext->hasPrivileges(Privileges::ACTIVITY_MILESTONE_PROGRESSION, $activity), 'read' => $oscarUserContext->hasPrivileges( Privileges::ACTIVITY_MILESTONE_SHOW, $activity ), 'edit' => $oscarUserContext->hasPrivileges( Privileges::ACTIVITY_MILESTONE_MANAGE, $activity ), 'progression' => $oscarUserContext->hasPrivileges( Privileges::ACTIVITY_MILESTONE_PROGRESSION, $activity ), ]; break; case 'organizations': $credentials['organizations'] = [ 'edit' => !$locked && $oscarUserContext->hasPrivileges(Privileges::ACTIVITY_ORGANIZATION_MANAGE, $activity), 'edit' => !$locked && $oscarUserContext->hasPrivileges( Privileges::ACTIVITY_ORGANIZATION_MANAGE, $activity ), 'read' => $oscarUserContext->hasPrivileges(Privileges::ACTIVITY_ORGANIZATION_SHOW, $activity), 'show' => $oscarUserContext->hasPrivileges(Privileges::ORGANIZATION_SHOW), ]; Loading @@ -305,7 +316,10 @@ class ProjectGrantApiService implements UseEntityManager, UsePersonService, UseO break; case 'persons': $credentials['persons'] = [ 'edit' => !$locked && $oscarUserContext->hasPrivileges(Privileges::ACTIVITY_PERSON_MANAGE, $activity), 'edit' => !$locked && $oscarUserContext->hasPrivileges( Privileges::ACTIVITY_PERSON_MANAGE, $activity ), 'read' => $oscarUserContext->hasPrivileges(Privileges::ACTIVITY_PERSON_SHOW, $activity), 'show' => $oscarUserContext->hasPrivileges(Privileges::PERSON_SHOW), ]; Loading Loading @@ -354,7 +368,6 @@ class ProjectGrantApiService implements UseEntityManager, UsePersonService, UseO ?Url $urlPlugin = null, ?array $perimeters = null ): array { $datas = [ "api" => "Oscar Activity API" ]; Loading Loading @@ -1205,8 +1218,8 @@ class ProjectGrantApiService implements UseEntityManager, UsePersonService, UseO } /** * @throws NotSupported * @return array * @throws NotSupported */ private function getCurrencies(): array { Loading Loading @@ -1240,6 +1253,11 @@ class ProjectGrantApiService implements UseEntityManager, UsePersonService, UseO $out = []; /** @var ActivityAvenant $item */ foreach ($result as $item) { $modifications = []; foreach ($item->getModifications() as $modification) { $modifications[] = $modification->toJson(); } $out[] = [ 'id' => $item->getId(), 'comment' => $item->getComment(), Loading @@ -1247,6 +1265,7 @@ class ProjectGrantApiService implements UseEntityManager, UsePersonService, UseO 'date' => $item->getDateAvenant()->format('Y-m-d'), 'status' => $item->getStatus(), 'status_text' => $item->getStatusLabel(), 'modifications' => $modifications, 'url_api' => $urlPlugin->fromRoute('avenant/api', [ 'activity_id' => $activity->getId(), 'avenant_id' => $item->getId() Loading Loading
module/Oscar/src/Oscar/Controller/ActivityAvenantsController.php +16 −33 Original line number Diff line number Diff line Loading @@ -71,20 +71,32 @@ class ActivityAvenantsController extends AbstractOscarController implements UseL } catch (\Exception $e) { return $this->jsonError("Impossible de charger les avenants"); } break; case 'POST': // TODO Tester les droits d'accès $datas = $_POST; $action = $_POST['action']; switch($action){ case "create": try { $datas['file'] = $this->fileAvenantDrop($activity); $datas['status'] = ActivityAvenant::STATUS_DRAFT; $this->getLoggerService()->debug(print_r($datas, true)); $this->getActivityAvenantsService()->createAvenantFromArray($activity, $datas); $this->getActivityAvenantsService()->saveAvenantFromArray($activity, $datas); return $this->getResponseOk("Avenant ajouté"); } catch (\Exception $e) { return $this->jsonError("Impossible d'ajouter l'avenant : " . $e->getMessage()); } case "update": try { $this->getActivityAvenantsService()->saveAvenantFromArray($activity, $datas); return $this->getResponseOk("Avenant modifié"); } catch (\Exception $e) { return $this->jsonError("Impossible de mettre à jour l'avenant : " . $e->getMessage()); } default: return $this->jsonError("Action non reconnue"); } case 'DELETE': // TODO Tester les droits d'accès Loading Loading @@ -151,33 +163,4 @@ class ActivityAvenantsController extends AbstractOscarController implements UseL throw new OscarException("Impossible de charger l'activité $idActivity"); } } private function fileAvenantDrop( Activity $activity ) :string { if( !array_key_exists('file', $_FILES) ){ $this->getLoggerService()->error("Aucun fichier d'avenant envoyé"); throw new OscarException("Fichier manquant"); } try { $uploader = new FileUploadStandard(); $avenant_directory = $this->getOscarConfigurationService()->getDocumentDropLocation(); $filename_pattern = $this->getOscarConfigurationService()->getConfiguration('avenant_filename'); $filename = sprintf( $filename_pattern, $activity->getId(), (new \DateTime())->format('Y-m-d'), uniqid() ); $mimes = ["application/pdf" => "pdf"]; $uploader->setDestination($avenant_directory) ->setFilename($filename) ->setMimesAllowed($mimes); $uploader->updoad($_FILES['file']); $this->getLoggerService()->info("Upload ok"); return $uploader->getUploadName(); } catch (\Exception $e){ $this->getLoggerService()->error($e->getMessage()); throw new OscarException("Impossible de téléverser le fichier de l'avenant : " . $e->getMessage()); } } }
module/Oscar/src/Oscar/Entity/ActivityAvenant.php +29 −0 Original line number Diff line number Diff line Loading @@ -3,6 +3,8 @@ namespace Oscar\Entity; use DateTime; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; /** Loading Loading @@ -36,6 +38,14 @@ class ActivityAvenant */ private Activity $activity; /** * Liste des modifications * * @var ArrayCollection * @ORM\OneToMany(targetEntity="ActivityAvenantModification", mappedBy="avenant", cascade={"remove"}) */ protected $modifications; /** * @var string * @ORM\Column(type="string") Loading @@ -54,6 +64,11 @@ class ActivityAvenant */ private int $status; public function __construct() { $this->modifications = new ArrayCollection(); } /** * @return mixed */ Loading Loading @@ -122,6 +137,20 @@ class ActivityAvenant return $this; } /** * @return ActivityAvenantModification[] */ public function getModifications() { return $this->modifications; } public function setModifications($modifications): self { $this->modifications = $modifications; return $this; } public function getResourceId() { return self::class; Loading
module/Oscar/src/Oscar/Entity/ActivityAvenantModification.php +77 −30 Original line number Diff line number Diff line Loading @@ -10,6 +10,25 @@ use Doctrine\ORM\Mapping as ORM; */ class ActivityAvenantModification { const TYPE_PERSON_DEL = 'personDel'; const TYPE_PERSON_ADD = 'personAdd'; const TYPE_ORGANIZATION_ADD = 'organizationAdd'; const TYPE_ORGANIZATION_DEL = 'organizationDel'; const TYPE_CHANGE_AMOUNT = 'changeAmount'; const TYPE_DATE_END = 'dateEnd'; public static function getTypes(): array { return array( self::TYPE_PERSON_DEL => "Suppression d'une personne", self::TYPE_PERSON_ADD => "Ajout d'une personne", self::TYPE_ORGANIZATION_ADD => "Suppression d'une organization", self::TYPE_ORGANIZATION_DEL => "Ajout d'une organisation", self::TYPE_CHANGE_AMOUNT => "Modification du montant", self::TYPE_DATE_END => "Modification de la date de fin", ); } /** * @ORM\Id * @ORM\GeneratedValue(strategy="IDENTITY") Loading @@ -17,12 +36,6 @@ class ActivityAvenantModification */ private $id; /** * @var Activity * @ORM\ManyToOne(targetEntity="ActivityAvenant") */ private Activity $avenant; /** * @var string * @ORM\Column(type="string") Loading @@ -30,43 +43,55 @@ class ActivityAvenantModification private string $type; /** * @var string * @ORM\Column(type="string") * @var ?string * @ORM\Column(type="string", nullable=true) */ private string $newValue1; private ?string $newValue1; /** * @var string * @ORM\Column(type="string") * @var ?string * @ORM\Column(type="string", nullable=true) */ private string $oldValue1; private ?string $oldValue1; /** * @var string * @ORM\Column(type="string") * @var ?string * @ORM\Column(type="string", nullable=true) */ private string $newValue2; private ?string $newValue2; /** * @var string * @ORM\Column(type="string") * @var ?string * @ORM\Column(type="string", nullable=true) */ private string $oldValue2; private ?string $oldValue2; /** * @var ?string * @ORM\Column(type="string", nullable=true) */ private ?string $info; /** * @var ActivityAvenant * @ORM\ManyToOne(targetEntity="ActivityAvenant", inversedBy="modifications") */ private ActivityAvenant $avenant; /** * @return mixed */ public function getId() public function getId(): mixed { return $this->id; } public function getAvenant(): Activity public function getAvenant(): ActivityAvenant { return $this->avenant; } public function setAvenant(Activity $avenant): self public function setAvenant(ActivityAvenant $avenant): self { $this->avenant = $avenant; return $this; Loading @@ -83,52 +108,74 @@ class ActivityAvenantModification return $this; } public function getNewValue1(): string public function getNewValue1(): ?string { return $this->newValue1; } public function setNewValue1(string $newValue1): self public function setNewValue1(?string $newValue1): self { $this->newValue1 = $newValue1; return $this; } public function getOldValue1(): string public function getOldValue1(): ?string { return $this->oldValue1; } public function setOldValue1(string $oldValue1): self public function setOldValue1(?string $oldValue1): self { $this->oldValue1 = $oldValue1; return $this; } public function getNewValue2(): string public function getNewValue2(): ?string { return $this->newValue2; } public function setNewValue2(string $newValue2): self public function setNewValue2(?string $newValue2): self { $this->newValue2 = $newValue2; return $this; } public function getOldValue2(): string public function getOldValue2(): ?string { return $this->oldValue2; } public function setOldValue2(string $oldValue2): self public function setOldValue2(?string $oldValue2): self { $this->oldValue2 = $oldValue2; return $this; } public function getResourceId() public function getInfo(): ?string { return $this->info; } public function setInfo(?string $info): self { $this->info = $info; return $this; } public function getResourceId(): string { return self::class; } public function toJson() :array { return [ 'id' => $this->getId(), 'type' => $this->getType(), 'value1' => $this->getNewValue1(), 'value2' => $this->getNewValue2(), 'oldValue1' => $this->getOldValue1(), 'info' => $this->getInfo(), ]; } }
module/Oscar/src/Oscar/Service/ActivityAvenantsService.php +176 −1 Original line number Diff line number Diff line Loading @@ -2,13 +2,20 @@ namespace Oscar\Service; use Doctrine\ORM\Exception\NotSupported; use Doctrine\ORM\Exception\ORMException; use Moment\Moment; use Oscar\Entity\Activity; use Oscar\Entity\ActivityAvenant; use Oscar\Entity\ActivityAvenantModification; use Oscar\Entity\ActivityPayment; use Oscar\Entity\Currency; use Oscar\Entity\LogActivity; use Oscar\Entity\Person; use Oscar\Entity\Repository\ActivityPaymentRepository; use Oscar\Entity\Role; use Oscar\Exception\OscarException; use Oscar\Strategy\Upload\FileUploadStandard; use Oscar\Traits\UseActivityLogService; use Oscar\Traits\UseActivityLogServiceTrait; use Oscar\Traits\UseEntityManager; Loading Loading @@ -71,6 +78,80 @@ class ActivityAvenantsService implements } } /** * @param Activity $activity * @param array $datas * @return void * @throws OscarException */ public function saveAvenantFromArray(Activity $activity, array $datas): void { $this->getLoggerService()->debug(__METHOD__); $this->getLoggerService()->debug(json_encode($datas)); if ($datas['id']) { $mode = "update"; $avenant = $this->getEntityManager()->getRepository(ActivityAvenant::class)->find($datas['id']); } else { $mode = "create"; $avenant = new ActivityAvenant(); $avenant->setStatus(ActivityAvenant::STATUS_DRAFT); $avenant->setActivity($activity); $this->getEntityManager()->persist($avenant); } // Traitement des données try { $avenant_date = DateTimeUtils::getDateTimeFromStr($datas['dateAvenant']); } catch (\Exception $e) { throw new OscarException("Date de l'avenant invalide"); } $idsModification = []; foreach ($avenant->getModifications() as $modification) { $idsModification[] = $modification->getId(); } if ($datas['modifications']) { $modificationsSend = json_decode($datas['modifications'], true); foreach ($modificationsSend as $modification) { $idsModification = array_diff($idsModification, [$modification['id']]); $this->saveModification($avenant, $modification); } } $fileUploaded = $this->uploadAvenantFile($activity); if (($mode == "update" && $fileUploaded)) { $this->deleteAvenantFile($avenant->getFilename()); } if ($fileUploaded) { $avenant->setFilename($fileUploaded); } if (($mode == "create" && !$fileUploaded)) { throw new OscarException("Fichier manquant"); } // Modification foreach ($idsModification as $modificationId) { $modification = $this->getEntityManager()->getRepository(ActivityAvenantModification::class)->find($modificationId); $this->getEntityManager()->remove($modification); } try { $avenant->setDateAvenant($avenant_date); $avenant->setComment($datas['comment']); $this->getEntityManager()->flush(); } catch (\Exception $e) { $this->getLoggerService()->critical($e->getMessage()); if ($fileUploaded) { $this->deleteAvenantFile($fileUploaded); } throw new OscarException("Impossible de créer l'avenant"); } } /** * @param mixed $id * @return void Loading @@ -84,13 +165,41 @@ class ActivityAvenantsService implements $this->deleteAvenantFile($avenant->getFilename()); $this->getEntityManager()->remove($avenant); $this->getEntityManager()->flush(); } catch (\Exception $e) { $this->getLoggerService()->critical($e->getMessage()); throw new OscarException("Impossible de supprimer l'avenant"); } } private function uploadAvenantFile(Activity $activity): ?string { if (!array_key_exists('file', $_FILES)) { $this->getLoggerService()->error("Aucun fichier d'avenant envoyé"); return null; } try { $uploader = new FileUploadStandard(); $avenant_directory = $this->getOscarConfigurationService()->getDocumentDropLocation(); $filename_pattern = $this->getOscarConfigurationService()->getConfiguration('avenant_filename'); $filename = sprintf( $filename_pattern, $activity->getId(), (new \DateTime())->format('Y-m-d'), uniqid() ); $mimes = ["application/pdf" => "pdf"]; $uploader->setDestination($avenant_directory) ->setFilename($filename) ->setMimesAllowed($mimes); $uploader->updoad($_FILES['file']); $this->getLoggerService()->info("Upload ok"); return $uploader->getUploadName(); } catch (\Exception $e) { $this->getLoggerService()->error($e->getMessage()); throw new OscarException("Impossible de téléverser le fichier de l'avenant : " . $e->getMessage()); } } /** * @param string $filename * @return bool Loading Loading @@ -124,6 +233,8 @@ class ActivityAvenantsService implements $size = filesize($location); $filename = $avenant->getFilename(); // Déplacer le type dans la BDD $type = 'application/pdf'; $content = FileSystemUtils::getInstance()->file_get_contents($location); Loading Loading @@ -159,4 +270,68 @@ class ActivityAvenantsService implements throw new OscarException($msg); } } /** * @param ActivityAvenant $avenant * @param array $modification * @param bool $fetch * @return void * @throws NotSupported * @throws ORMException * @throws OscarException */ private function saveModification(ActivityAvenant $avenant, array $modification, bool $fetch = false): void { $this->getLoggerService()->debug("Traitement modification"); $this->getLoggerService()->debug(json_encode($modification)); $type = $modification['type']; $newValue1 = $modification['value1']; $newValue2 = $modification['value2']; $oldValue1 = null; $oldValue2 = null; if( !array_key_exists($type, ActivityAvenantModification::getTypes()) ) { throw new OscarException("Le type d'avenant '$type' n'existe pas"); } if ($modification['id']) { $avenantModif = $this->getEntityManager()->getRepository(ActivityAvenantModification::class)->find( $modification['id'] ); } else { $avenantModif = new ActivityAvenantModification(); $this->getEntityManager()->persist($avenantModif); $avenantModif->setAvenant($avenant); } $msg = "Modification non-traitée"; switch ($type) { case ActivityAvenantModification::TYPE_DATE_END: $moment = Moment::fromDateTime(new \DateTime($newValue1)); $msg = "Modification de la date de fin pour " . $moment->format('d/m/Y'); $oldValue1 = $avenant->getActivity()->getDateEndStr(); break; case ActivityAvenantModification::TYPE_PERSON_DEL: $person = $this->getEntityManager()->getRepository(Person::class)->find($newValue1); $role = $this->getEntityManager()->getRepository(Role::class)->find($newValue2); $msg = "Suppression de $person ($role)"; break; case ActivityAvenantModification::TYPE_PERSON_ADD: $person = $this->getEntityManager()->getRepository(Person::class)->find($newValue1); $role = $this->getEntityManager()->getRepository(Role::class)->find($newValue2); $msg = "Ajout de $person ($role)"; break; } $avenantModif->setType($modification['type']); $avenantModif->setNewValue1($newValue1); $avenantModif->setNewValue2($newValue2); $avenantModif->setOldValue1($oldValue1); $avenantModif->setOldValue2($oldValue2); $avenantModif->setInfo($msg); $this->getLoggerService()->debug("MODIF : " . $modification['type']); } } No newline at end of file
module/Oscar/src/Oscar/Service/ProjectGrantApiService.php +27 −8 Original line number Diff line number Diff line Loading @@ -171,7 +171,6 @@ class ProjectGrantApiService implements UseEntityManager, UsePersonService, UseO OscarUserContext $oscarUserContext, array $perimeters ): array { $locked = $activity->isLocked(); $editable = $oscarUserContext->hasPrivileges(Privileges::ACTIVITY_EDIT, $activity); $lockEditable = $oscarUserContext->hasPrivileges(Privileges::ACTIVITY_EDIT_LOCKED, $activity); Loading Loading @@ -283,15 +282,27 @@ class ProjectGrantApiService implements UseEntityManager, UsePersonService, UseO case 'milestones': $credentials['milestones'] = [ 'read' => $oscarUserContext->hasPrivileges(Privileges::ACTIVITY_MILESTONE_SHOW, $activity), 'edit' => $oscarUserContext->hasPrivileges(Privileges::ACTIVITY_MILESTONE_MANAGE, $activity), 'progression' => $oscarUserContext->hasPrivileges(Privileges::ACTIVITY_MILESTONE_PROGRESSION, $activity), 'read' => $oscarUserContext->hasPrivileges( Privileges::ACTIVITY_MILESTONE_SHOW, $activity ), 'edit' => $oscarUserContext->hasPrivileges( Privileges::ACTIVITY_MILESTONE_MANAGE, $activity ), 'progression' => $oscarUserContext->hasPrivileges( Privileges::ACTIVITY_MILESTONE_PROGRESSION, $activity ), ]; break; case 'organizations': $credentials['organizations'] = [ 'edit' => !$locked && $oscarUserContext->hasPrivileges(Privileges::ACTIVITY_ORGANIZATION_MANAGE, $activity), 'edit' => !$locked && $oscarUserContext->hasPrivileges( Privileges::ACTIVITY_ORGANIZATION_MANAGE, $activity ), 'read' => $oscarUserContext->hasPrivileges(Privileges::ACTIVITY_ORGANIZATION_SHOW, $activity), 'show' => $oscarUserContext->hasPrivileges(Privileges::ORGANIZATION_SHOW), ]; Loading @@ -305,7 +316,10 @@ class ProjectGrantApiService implements UseEntityManager, UsePersonService, UseO break; case 'persons': $credentials['persons'] = [ 'edit' => !$locked && $oscarUserContext->hasPrivileges(Privileges::ACTIVITY_PERSON_MANAGE, $activity), 'edit' => !$locked && $oscarUserContext->hasPrivileges( Privileges::ACTIVITY_PERSON_MANAGE, $activity ), 'read' => $oscarUserContext->hasPrivileges(Privileges::ACTIVITY_PERSON_SHOW, $activity), 'show' => $oscarUserContext->hasPrivileges(Privileges::PERSON_SHOW), ]; Loading Loading @@ -354,7 +368,6 @@ class ProjectGrantApiService implements UseEntityManager, UsePersonService, UseO ?Url $urlPlugin = null, ?array $perimeters = null ): array { $datas = [ "api" => "Oscar Activity API" ]; Loading Loading @@ -1205,8 +1218,8 @@ class ProjectGrantApiService implements UseEntityManager, UsePersonService, UseO } /** * @throws NotSupported * @return array * @throws NotSupported */ private function getCurrencies(): array { Loading Loading @@ -1240,6 +1253,11 @@ class ProjectGrantApiService implements UseEntityManager, UsePersonService, UseO $out = []; /** @var ActivityAvenant $item */ foreach ($result as $item) { $modifications = []; foreach ($item->getModifications() as $modification) { $modifications[] = $modification->toJson(); } $out[] = [ 'id' => $item->getId(), 'comment' => $item->getComment(), Loading @@ -1247,6 +1265,7 @@ class ProjectGrantApiService implements UseEntityManager, UsePersonService, UseO 'date' => $item->getDateAvenant()->format('Y-m-d'), 'status' => $item->getStatus(), 'status_text' => $item->getStatusLabel(), 'modifications' => $modifications, 'url_api' => $urlPlugin->fromRoute('avenant/api', [ 'activity_id' => $activity->getId(), 'avenant_id' => $item->getId() Loading