Merge branch 'onTheFly' into thirdparty

This commit is contained in:
2021-09-30 15:13:03 +02:00
74 changed files with 1490 additions and 804 deletions

View File

@@ -18,7 +18,7 @@ use Chill\MainBundle\Pagination\PaginatorFactory;
/**
* Routes for operations on ThirdParties.
*
*
* @Route("/{_locale}/thirdparty/thirdparty")
*/
class ThirdPartyController extends Controller
@@ -28,21 +28,21 @@ class ThirdPartyController extends Controller
* @var AuthorizationHelper
*/
protected $authorizationHelper;
/**
*
* @var TranslatorInterface
*/
protected $translator;
/**
*
* @var PaginatorFactory
*/
protected $paginatorFactory;
public function __construct(
AuthorizationHelper $authorizationHelper,
AuthorizationHelper $authorizationHelper,
TranslatorInterface $translator,
PaginatorFactory $paginatorFactory
) {
@@ -51,7 +51,7 @@ class ThirdPartyController extends Controller
$this->paginatorFactory = $paginatorFactory;
}
/**
* @Route("/index", name="chill_3party_3party_index")
*/
@@ -60,22 +60,12 @@ class ThirdPartyController extends Controller
$this->denyAccessUnlessGranted(ThirdPartyVoter::SHOW);
$repository = $this->getDoctrine()->getManager()
->getRepository(ThirdParty::class);
$centers = $this->authorizationHelper
->getReachableCenters(
$this->getUser(),
new Role(ThirdPartyVoter::SHOW)
);
$nbThirdParties = $repository->countByMemberOfCenters($centers); //
$nbThirdParties = $repository->count([]); //$repository->countByMemberOfCenters($centers);
$pagination = $this->paginatorFactory->create($nbThirdParties);
$thirdParties = $repository->findByMemberOfCenters(
$centers,
$pagination->getCurrentPage()->getFirstItemNumber(),
$pagination->getItemsPerPage()
);
$thirdParties = $repository->findAll();
return $this->render('ChillThirdPartyBundle:ThirdParty:index.html.twig', array(
'third_parties' => $thirdParties,
'pagination' => $pagination
@@ -89,45 +79,36 @@ class ThirdPartyController extends Controller
{
$this->denyAccessUnlessGranted(ThirdPartyVoter::CREATE);
/* $centers = $this->authorizationHelper
->getReachableCenters(
$this->getUser(),
new Role(ThirdPartyVoter::CREATE)
);
if ($centers === []) { //
throw new \LogicException("There should be at least one center reachable "
. "if role ".ThirdPartyVoter::CREATE." is granted");
} */
$centers = [];
$thirdParty = new ThirdParty();
$thirdParty->setCenters(new ArrayCollection($centers));
$form = $this->createForm(ThirdPartyType::class, $thirdParty, [
'usage' => 'create'
]);
$form->add('submit', SubmitType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($thirdParty);
$em->flush();
$this->addFlash('success',
$this->translator->trans("Third party created")
);
return $this->redirectToRoute('chill_3party_3party_show', [
'thirdparty_id' => $thirdParty->getId()
]);
} elseif ($form->isSubmitted()) {
$msg = $this->translator->trans('This form contains errors');
$this->addFlash('error', $msg);
}
return $this->render('@ChillThirdParty/ThirdParty/new.html.twig', [
'form' => $form->createView(),
'thirdParty' => $thirdParty
@@ -142,58 +123,52 @@ class ThirdPartyController extends Controller
{
$this->denyAccessUnlessGranted(ThirdPartyVoter::CREATE);
/* $centers = $this->authorizationHelper
->getReachableCenters(
$this->getUser(),
new Role(ThirdPartyVoter::CREATE)
);
$repository = $this->getDoctrine()->getManager()
->getRepository(ThirdParty::class);
if ($centers === []) {
throw new \LogicException("There should be at least one center reachable "
. "if role ".ThirdPartyVoter::CREATE." is granted");
} */
$centers = $repository->findAll();
// we want to keep centers the users has no access to. So we will add them
// later if they are removed. (this is a ugly hack but it will works
$centersAssociatedNotForUsers = \array_diff(
$thirdParty->getCenters()->toArray(),
$thirdParty->getCenters()->toArray(),
$centers);
$form = $this->createForm(ThirdPartyType::class, $thirdParty, [
'usage' => 'create'
]);
$form->add('submit', SubmitType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
// re-add centers the user has no accesses:
foreach ($centersAssociatedNotForUsers as $c) {
$thirdParty->addCenter($c);
}
$em = $this->getDoctrine()->getManager();
$em->flush();
$this->addFlash('success',
$this->translator->trans("Third party updated")
);
return $this->redirectToRoute('chill_3party_3party_show', [
'thirdparty_id' => $thirdParty->getId()
]);
} elseif ($form->isSubmitted()) {
$msg = $this->translator->trans('This form contains errors');
$this->addFlash('error', $msg);
}
return $this->render('@ChillThirdParty/ThirdParty/update.html.twig', [
'form' => $form->createView(),
'thirdParty' => $thirdParty
]);
}
/**
* @Route("/{thirdparty_id}/show", name="chill_3party_3party_show")
* @ParamConverter("thirdParty", options={"id": "thirdparty_id"})
@@ -201,7 +176,7 @@ class ThirdPartyController extends Controller
public function showAction(ThirdParty $thirdParty, Request $request)
{
$this->denyAccessUnlessGranted(ThirdPartyVoter::SHOW, $thirdParty);
return $this->render('@ChillThirdParty/ThirdParty/show.html.twig', [
'thirdParty' => $thirdParty
]);

View File

@@ -59,27 +59,23 @@ class ChillThirdPartyExtension extends Extension implements PrependExtensionInte
'class' => \Chill\ThirdPartyBundle\Entity\ThirdParty::class,
'name' => 'thirdparty',
'base_path' => '/api/1.0/thirdparty/thirdparty',
'base_role' => \Chill\ThirdPartyBundle\Security\Authorization\ThirdPartyVoter::class,
//'base_role' => \Chill\ThirdPartyBundle\Security\Authorization\ThirdPartyVoter::SHOW,
//'controller' => \Chill\ThirdPartyBundle\Controller\ThirdPartyApiController::class,
'actions' => [
'_index' => [
'methods' => [
Request::METHOD_GET => true,
Request::METHOD_HEAD => true,
Request::METHOD_POST => true,
],
],
'_entity' => [
'methods' => [
Request::METHOD_GET => true,
Request::METHOD_HEAD => true,
Request::METHOD_POST=> true,
Request::METHOD_POST => true,
Request::METHOD_PUT => true,
Request::METHOD_PATCH => true
],
'roles' => [
Request::METHOD_GET => \Chill\ThirdPartyBundle\Security\Voter\ThirdPartyVoter::SHOW,
Request::METHOD_HEAD => \Chill\ThirdPartyBundle\Security\Voter\ThirdPartyVoter::SHOW,
Request::METHOD_POST => \Chill\ThirdPartyBundle\Security\Voter\ThirdPartyVoter::CREATE,
Request::METHOD_PUT => \Chill\ThirdPartyBundle\Security\Voter\ThirdPartyVoter::CREATE,
Request::METHOD_PATCH => \Chill\ThirdPartyBundle\Security\Voter\ThirdPartyVoter::CREATE
],
]
]

View File

@@ -60,7 +60,7 @@ class ThirdParty
* @var string
* @ORM\Column(name="name", type="string", length=255)
* @Assert\Length(min="2")
* @Groups({"read"})
* @Groups({"read", "write"})
*/
private $name;
@@ -69,6 +69,7 @@ class ThirdParty
* @var string
* @ORM\Column(name="name_company", type="string", length=255, nullable=true)
* @Assert\Length(min="3")
* @Groups({"read", "write"})
*/
private $nameCompany;
@@ -77,6 +78,7 @@ class ThirdParty
* @var string
* @ORM\Column(name="acronym", type="string", length=64, nullable=true)
* @Assert\Length(min="2")
* @Groups({"read", "write"})
*/
private $acronym;
@@ -94,7 +96,7 @@ class ThirdParty
* @ORM\Column(name="types", type="json", nullable=true)
* @Assert\Count(min=1)
*/
private $type;
private $types;
/**
* Contact Persons: One Institutional ThirdParty has Many Contact Persons
@@ -130,7 +132,7 @@ class ThirdParty
* @Assert\Regex("/^([\+{1}])([0-9\s*]{4,20})$/",
* message="Invalid phone number: it should begin with the international prefix starting with ""+"", hold only digits and be smaller than 20 characters. Ex: +33123456789"
* )
* @Groups({"read"})
* @Groups({"read", "write"})
*/
private $telephone;
@@ -138,7 +140,7 @@ class ThirdParty
* @var string|null
* @ORM\Column(name="email", type="string", length=255, nullable=true)
* @Assert\Email(checkMX=false)
* @Groups({"read"})
* @Groups({"read", "write"})
*/
private $email;
@@ -147,7 +149,7 @@ class ThirdParty
* @ORM\ManyToOne(targetEntity="\Chill\MainBundle\Entity\Address",
* cascade={"persist", "remove"})
* @ORM\JoinColumn(nullable=true, onDelete="SET NULL")
* @Groups({"read"})
* @Groups({"read", "write"})
*/
private $address;
@@ -168,7 +170,6 @@ class ThirdParty
* @var Collection
* @ORM\ManyToMany(targetEntity="\Chill\MainBundle\Entity\Center")
* @ORM\JoinTable(name="chill_3party.party_center")
* @Assert\Count(min=1)
*/
private $centers;
@@ -325,7 +326,7 @@ class ThirdParty
* @param array|null $type
* @return ThirdParty
*/
public function setType(array $type = null)
public function setTypes(array $type = null)
{
// remove all keys from the input data
$this->type = \array_values($type);
@@ -338,9 +339,9 @@ class ThirdParty
*
* @return array|null
*/
public function getType()
public function getTypes()
{
return $this->type;
return $this->types;
}
/**

View File

@@ -64,10 +64,10 @@ class ThirdPartyType extends AbstractType
}
if (count($types) === 1) {
$builder
->add('type', HiddenType::class, [
->add('types', HiddenType::class, [
'data' => array_values($types)
])
->get('type')
->get('types')
->addModelTransformer(new CallbackTransformer(
function (?array $typeArray): ?string {
if (null === $typeArray) {
@@ -84,7 +84,7 @@ class ThirdPartyType extends AbstractType
))
;
} else {
$builder->add('type', ChoiceType::class, [
$builder->add('types', ChoiceType::class, [
'choices' => $types,
'expanded' => true,
'multiple' => true,

View File

@@ -13,7 +13,7 @@ const getThirdparty = (id) => {
};
/*
* POST a new person
* POST a new thirdparty
*/
const postThirdparty = (body) => {
const url = `/api/1.0/thirdparty/thirdparty.json`;
@@ -29,8 +29,27 @@ const postThirdparty = (body) => {
throw Error('Error with request resource response');
});
};
export {
getThirdparty,
postThirdparty
};
/*
* PATCH an existing thirdparty
*/
const patchThirdparty = (id, body) => {
const url = `/api/1.0/thirdparty/thirdparty/${id}.json`;
return fetch(url, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json;charset=utf-8'
},
body: JSON.stringify(body)
})
.then(response => {
if (response.ok) { return response.json(); }
throw Error('Error with request resource response');
});
};
export {
getThirdparty,
postThirdparty,
patchThirdparty
};

View File

@@ -8,25 +8,17 @@
<div :class="'denomination h' + options.hLevel">
<a v-if="this.options.addLink == true" href="#">
<a v-if="this.options.addLink === true" href="#">
<span class="name">{{ thirdparty.text }}</span>
</a>
<span class="name">{{ thirdparty.text }}</span>
<span v-if="options.addId == true" class="id-number" :title="'n° ' + thirdparty.id">{{ thirdparty.id }}</span>
<span v-if="options.addEntity == true && thirdparty.type == 'thirdparty'" class="badge rounded-pill bg-secondary">{{ $t('renderbox.type.thirdparty') }}</span>
<span v-if="options.addEntity == true && thirdparty.type === 'thirdparty'" class="badge rounded-pill bg-secondary">{{ $t('renderbox.type.thirdparty') }}</span>
</div>
<p v-if="this.options.addInfo == true" class="moreinfo">
<i v-if="thirdparty.birthdate" :class="'fa fa-fw ' + getGenderIcon" title="{{ getGender }}"></i>
<time v-if="thirdparty.birthdate" datetime="{{ thirdparty.birthdate.datetime }}" title="{{ birthdate }}">
{{ $t(getGender) + ' ' + $d(birthdate, 'short') }}
</time>
<time v-else-if="thirdparty.deathdate" datetime="{{ thirdparty.deathdate.datetime }}" title="{{ thirdparty.deathdate }}">
{{ birthdate }} - {{ deathdate }}
</time>
<span v-if="options.addAge == true" class="age">{{ thirdparty.age }}</span>
<p v-if="this.options.addInfo === true" class="moreinfo">
</p>
</div>
</div>
@@ -42,9 +34,9 @@
<i class="fa fa-li fa-map-marker"></i>
<address-render-box :address="thirdparty.address" :isMultiline="isMultiline"></address-render-box>
</li>
<li v-if="thirdparty.telephone">
<li v-if="thirdparty.phonenumber">
<i class="fa fa-li fa-mobile"></i>
<a :href="'tel: ' + thirdparty.telephone">{{ thirdparty.telephone }}</a>
<a :href="'tel: ' + thirdparty.phonenumber">{{ thirdparty.phonenumber }}</a>
</li>
<li v-if="thirdparty.email">
<i class="fa fa-li fa-envelope-o"></i>
@@ -78,21 +70,7 @@ export default {
} else {
return false
}
},
getGender: function() {
return this.thirdparty.gender == 'woman' ? 'renderbox.birthday.woman' : 'renderbox.birthday.man';
},
getGenderIcon: function() {
return this.thirdparty.gender == 'woman' ? 'fa-venus' : this.thirdparty.gender == 'man' ? 'fa-mars' : 'fa-neuter';
},
birthdate: function(){
var date = new Date(this.thirdparty.birthdate.datetime);
return dateToISO(date);
},
deathdate: function(){
var date = new Date(this.thirdparty.deathdate.datetime);
return dateToISO(date);
},
}
}
}
</script>

View File

@@ -1,5 +1,5 @@
<template>
<div v-if="action === 'show'">
<div v-if="action === 'show'">
<div class="flex-table">
<third-party-render-box
:thirdparty="thirdparty"
@@ -19,15 +19,10 @@
</div>
</div>
<div v-else-if="action === 'edit' || action === 'create'">
<div class="form-floating mb-3">
<input class="form-control form-control-lg" id="firstname" v-model="thirdparty.firstName" v-bind:placeholder="$t('thirdparty.firstname')" />
<label for="firstname">{{ $t('thirdparty.firstname') }}</label>
</div>
<div class="form-floating mb-3">
<input class="form-control form-control-lg" id="lastname" v-model="thirdparty.lastName" v-bind:placeholder="$t('thirdparty.lastname')" />
<label for="lastname">{{ $t('thirdparty.lastname') }}</label>
<input class="form-control form-control-lg" id="name" v-model="thirdparty.text" v-bind:placeholder="$t('thirdparty.name')" />
<label for="name">{{ $t('thirdparty.name') }}</label>
</div>
<div class="input-group mb-3">
@@ -47,44 +42,82 @@
v-bind:aria-label="$t('thirdparty.phonenumber')"
aria-describedby="phonenumber" />
</div>
<!--
<add-address
:context="this.context"
:options="this.addAddress.options"
:address-changed-callback="submitAddress">
</add-address>
-->
</div>
</template>
<script>
import ThirdPartyRenderBox from '../Entity/ThirdPartyRenderBox.vue';
import { getThirdparty, postThirdparty } from '../../_api/OnTheFly';
import AddAddress from 'ChillMainAssets/vuejs/Address/components/AddAddress';
import { getThirdparty } from '../../_api/OnTheFly';
export default {
name: "OnTheFlyThirdParty",
props: ['id', 'type', 'action'],
components: {
ThirdPartyRenderBox,
AddAddress
},
data: function() {
data() {
return {
thirdparty: {
type: 'thirdparty'
},
addAddress: {
options: {
openPanesInModal: true,
onlyButton: false,
/*
button: {
text: {
create: 'courselocation.add_temporary_address',
edit: 'courselocation.edit_temporary_address'
}
},
title: {
create: 'courselocation.add_temporary_address',
edit: 'courselocation.edit_temporary_address'
} */
}
}
}
},
computed: {
context() {
let context = {
target: {
name: this.type,
id: this.id
},
edit: false,
addressId: null
};
console.log('context', context);
return context;
},
},
methods: {
loadThirdparty(){
loadData(){
getThirdparty(this.id).then(thirdparty => new Promise((resolve, reject) => {
this.thirdparty = thirdparty;
console.log('get thirdparty', thirdparty);
resolve();
}));
},
postData() {
postThirdparty(this.thirdparty).then(thirdparty => new Promise((resolve, reject) => {
this.thirdparty = thirdparty;
resolve();
}))
submitAddress(payload) {
console.log('submitAddress', payload);
}
},
mounted() {
if (this.action !== 'create'){
this.loadThirdparty();
if (this.action !== 'create') {
this.loadData();
}
},
}

View File

@@ -0,0 +1,11 @@
const thirdpartyMessages = {
fr: {
thirdparty: {
name: "Dénomination",
email: "Courriel",
phonenumber: "Téléphone",
}
}
};
export { thirdpartyMessages };

View File

@@ -51,7 +51,7 @@
<th>{{ (tp.active ? '<i class="fa fa-check chill-green">' : '<i class="fa fa-times chill-red">')|raw }}</th>
<td>{{ tp.name }}</td>
{% set types = [] %}
{% for t in tp.type %}
{% for t in tp.types %}
{% set types = types|merge( [ ('chill_3party.key_label.'~t)|trans ] ) %}
{% endfor %}
<td>{{ types|join(', ') }}</td>

View File

@@ -26,7 +26,7 @@
{{ form_row(form.profession) }}
{% endif %}
{{ form_row(form.type) }}
{{ form_row(form.types) }}
{{ form_row(form.categories) }}
{{ form_row(form.telephone) }}

View File

@@ -48,7 +48,7 @@
<dt>{{ 'Type'|trans }}</dt>
{% set types = [] %}
{% for t in thirdParty.type %}
{% for t in thirdParty.types %}
{% set types = types|merge( [ ('chill_3party.key_label.'~t)|trans ] ) %}
{% endfor %}
<dd>

View File

@@ -43,7 +43,7 @@
{{ form_row(form.profession) }}
{% endif %}
{{ form_row(form.type) }}
{{ form_row(form.types) }}
{{ form_row(form.categories) }}
{{ form_row(form.telephone) }}

View File

@@ -63,6 +63,8 @@ class ThirdPartyVoter extends AbstractChillVoter implements ProvideRoleHierarchy
if (!$user instanceof User) {
return false;
}
return true;
$centers = $this->authorizationHelper
->getReachableCenters($user, new Role($attribute));

View File

@@ -8,17 +8,57 @@ servers:
- url: "/api"
description: "Your current dev server"
components:
schemas:
Thirdparty:
type: object
properties:
id:
type: integer
readOnly: true
type:
type: string
enum:
- "thirdparty"
name:
type: string
email:
type: string
telephone:
type: string
address:
$ref: "#/components/schemas/Address"
Address:
type: object
properties:
id:
type: integer
paths:
/1.0/thirdparty/thirdparty.json:
get:
post:
tags:
- thirdparty
summary: Return a list of all thirdparty items
summary: Create a single thirdparty
requestBody:
description: "A thirdparty"
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/Thirdparty"
responses:
200:
description: "ok"
401:
description: "OK"
content:
application/json:
schema:
$ref: "#/components/schemas/Thirdparty"
403:
description: "Unauthorized"
422:
description: "Invalid data"
/1.0/thirdparty/thirdparty/{id}.json:
get:
@@ -41,3 +81,32 @@ paths:
description: "not found"
401:
description: "Unauthorized"
patch:
tags:
- thirdparty
summary: "Alter a thirdparty"
parameters:
- name: id
in: path
required: true
description: The thirdparty's id
schema:
type: integer
format: integer
minimum: 1
requestBody:
description: "A thirdparty"
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/Thirdparty"
responses:
401:
description: "Unauthorized"
404:
description: "Not found"
200:
description: "OK"
422:
description: "Object with validation errors"