-
Notifications
You must be signed in to change notification settings - Fork 69
Gestion de produits pour les devis #2216
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| admin_accounting_produits_list: | ||
| path: / | ||
| defaults: {_controller: AppBundle\Controller\Admin\Accounting\Produit\ListProduitAction} | ||
|
|
||
| admin_accounting_produits_add: | ||
| path: /add | ||
| defaults: {_controller: AppBundle\Controller\Admin\Accounting\Produit\AddProduitAction} | ||
|
|
||
| admin_accounting_produits_edit: | ||
| path: /edit/{id} | ||
| defaults: {_controller: AppBundle\Controller\Admin\Accounting\Produit\EditProduitAction} | ||
| requirements: | ||
| id: '\d+' | ||
|
|
||
| admin_accounting_produits_delete: | ||
| path: /delete/{id} | ||
| defaults: {_controller: AppBundle\Controller\Admin\Accounting\Produit\DeleteProduitAction} | ||
| requirements: | ||
| id: '\d+' |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| <?php | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| use Phinx\Migration\AbstractMigration; | ||
|
|
||
| final class CreateComptaProduitTable extends AbstractMigration | ||
| { | ||
| public function change(): void | ||
| { | ||
| $this->table('compta_produit') | ||
| ->addColumn('reference', 'string', ['limit' => 255, 'null' => false]) | ||
| ->addColumn('designation', 'string', ['limit' => 255, 'null' => false]) | ||
| ->addColumn('quantite', 'integer', ['null' => true]) | ||
| ->addColumn('prix_unitaire_ht', 'float', ['null' => false]) | ||
| ->addColumn('taux_tva', 'float', ['null' => true]) | ||
| ->create(); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| <?php | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| namespace AppBundle\Accounting\Entity; | ||
|
|
||
| use Doctrine\ORM\Mapping as ORM; | ||
|
|
||
| #[ORM\Entity] | ||
| #[ORM\Table(name: 'compta_produit')] | ||
| class Produit | ||
| { | ||
| #[ORM\Id] | ||
| #[ORM\GeneratedValue] | ||
| #[ORM\Column] | ||
| public ?int $id = null; | ||
|
|
||
| #[ORM\Column(length: 255, nullable: false)] | ||
| public string $reference; | ||
|
|
||
| #[ORM\Column(length: 255, nullable: false)] | ||
| public string $designation; | ||
|
|
||
| #[ORM\Column(nullable: true)] | ||
| public ?int $quantite = null; | ||
|
|
||
| #[ORM\Column(type: 'decimal', precision: 10, scale: 2, nullable: false)] | ||
| public float $prixUnitaireHt; | ||
|
|
||
| #[ORM\Column(nullable: true)] | ||
| public ?float $tauxTva = null; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| <?php | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| namespace AppBundle\Accounting\Entity\Repository; | ||
|
|
||
| use AppBundle\Accounting\Entity\Produit; | ||
| use AppBundle\Doctrine\EntityRepository; | ||
| use Doctrine\Persistence\ManagerRegistry; | ||
|
|
||
| /** | ||
| * @extends EntityRepository<Produit> | ||
| */ | ||
| final class ProduitRepository extends EntityRepository | ||
| { | ||
| public function __construct(ManagerRegistry $registry) | ||
| { | ||
| parent::__construct($registry, Produit::class); | ||
| } | ||
|
|
||
| /** | ||
| * @return array<Produit> | ||
| */ | ||
| public function getAllSortedByReference(): array | ||
| { | ||
| return $this->createQueryBuilder('p') | ||
| ->orderBy('p.reference', 'asc') | ||
| ->getQuery() | ||
| ->execute(); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| <?php | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| namespace AppBundle\Accounting\Form; | ||
|
|
||
| use Symfony\Component\Form\AbstractType; | ||
| use Symfony\Component\Form\Extension\Core\Type\ChoiceType; | ||
| use Symfony\Component\Form\Extension\Core\Type\IntegerType; | ||
| use Symfony\Component\Form\Extension\Core\Type\NumberType; | ||
| use Symfony\Component\Form\Extension\Core\Type\TextareaType; | ||
| use Symfony\Component\Form\Extension\Core\Type\TextType; | ||
| use Symfony\Component\Form\FormBuilderInterface; | ||
| use Symfony\Component\Validator\Constraints as Assert; | ||
|
|
||
| class ProduitType extends AbstractType | ||
| { | ||
| public function buildForm(FormBuilderInterface $builder, array $options): void | ||
| { | ||
| $builder->add('reference', TextType::class, [ | ||
| 'label' => 'Référence', | ||
| 'required' => true, | ||
| 'constraints' => [ | ||
| new Assert\NotBlank(), | ||
| new Assert\Type('string'), | ||
| new Assert\Length(max: 20), | ||
|
stakovicz marked this conversation as resolved.
|
||
| ], | ||
| ])->add('designation', TextareaType::class, [ | ||
| 'label' => 'Désignation', | ||
| 'required' => true, | ||
| 'constraints' => [ | ||
| new Assert\NotBlank(), | ||
| new Assert\Type('string'), | ||
| new Assert\Length(max: 100), | ||
|
Mopolo marked this conversation as resolved.
|
||
| ], | ||
| ])->add('quantite', IntegerType::class, [ | ||
| 'label' => 'Quantité par défaut', | ||
| 'required' => false, | ||
| 'constraints' => [ | ||
| new Assert\Positive(), | ||
| ], | ||
| ])->add('prixUnitaireHt', NumberType::class, [ | ||
| 'label' => 'Prix unitaire HT', | ||
| 'required' => true, | ||
| 'scale' => 2, | ||
| 'constraints' => [ | ||
| new Assert\NotBlank(), | ||
| new Assert\Positive(), | ||
| ], | ||
| ])->add('tauxTva', ChoiceType::class, [ | ||
| 'label' => 'Taux de TVA', | ||
| 'required' => false, | ||
| 'expanded' => true, | ||
| 'multiple' => false, | ||
| 'placeholder' => 'Non soumis', | ||
| 'choices' => [ | ||
| '5.5%' => 5.5, | ||
| '10%' => 10.0, | ||
| '20%' => 20.0, | ||
|
Comment on lines
+57
to
+59
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. suggestion : Peut être travailler avec un Enum ou des constantes ou utiliser des taux qui existe déjà, non ?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm je n'y avais pas pensé. Je regarde et si ça fait trop de diff dans cette PR j'en ferais une autre pour ça pour le reste du code. |
||
| ], | ||
| ]); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| <?php | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| namespace AppBundle\Controller\Admin\Accounting\Produit; | ||
|
|
||
| use AppBundle\Accounting\Entity\Produit; | ||
| use AppBundle\Accounting\Entity\Repository\ProduitRepository; | ||
| use AppBundle\Accounting\Form\ProduitType; | ||
| use AppBundle\AuditLog\Audit; | ||
| use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; | ||
| use Symfony\Component\HttpFoundation\Request; | ||
| use Symfony\Component\HttpFoundation\Response; | ||
|
|
||
| final class AddProduitAction extends AbstractController | ||
| { | ||
| public function __construct( | ||
| private readonly ProduitRepository $produitRepository, | ||
| private readonly Audit $audit, | ||
| ) {} | ||
|
|
||
| public function __invoke(Request $request): Response | ||
| { | ||
| $produit = new Produit(); | ||
| $form = $this->createForm(ProduitType::class, $produit); | ||
| $form->handleRequest($request); | ||
| if ($form->isSubmitted() && $form->isValid()) { | ||
| $this->produitRepository->save($produit); | ||
| $this->audit->log('Ajout du produit ' . $produit->reference); | ||
| $this->addFlash('notice', 'Le produit a été ajouté'); | ||
| return $this->redirectToRoute('admin_accounting_produits_list'); | ||
| } | ||
|
|
||
| return $this->render('admin/accounting/produit/form.html.twig', [ | ||
| 'form' => $form->createView(), | ||
| 'produit' => $produit, | ||
| 'formTitle' => 'Ajouter un produit', | ||
| 'submitLabel' => 'Ajouter', | ||
| ]); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| <?php | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| namespace AppBundle\Controller\Admin\Accounting\Produit; | ||
|
|
||
| use AppBundle\Accounting\Entity\Produit; | ||
| use AppBundle\Accounting\Entity\Repository\ProduitRepository; | ||
| use AppBundle\AuditLog\Audit; | ||
| use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; | ||
| use Symfony\Component\HttpFoundation\Request; | ||
| use Symfony\Component\HttpFoundation\Response; | ||
|
|
||
| final class DeleteProduitAction extends AbstractController | ||
| { | ||
| public function __construct( | ||
| private readonly ProduitRepository $produitRepository, | ||
| private readonly Audit $audit, | ||
| ) {} | ||
|
|
||
| public function __invoke(Request $request, int $id): Response | ||
| { | ||
| $produit = $this->produitRepository->find($id); | ||
| if (!$produit instanceof Produit) { | ||
| $this->addFlash('error', 'Une erreur est survenue lors de la suppression du produit'); | ||
| return $this->redirectToRoute('admin_accounting_produits_list'); | ||
| } | ||
|
|
||
| $this->produitRepository->delete($produit); | ||
| $this->audit->log('Suppression du produit ' . $produit->reference); | ||
| $this->addFlash('notice', 'Le produit a été supprimé'); | ||
| return $this->redirectToRoute('admin_accounting_produits_list'); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| <?php | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| namespace AppBundle\Controller\Admin\Accounting\Produit; | ||
|
|
||
| use AppBundle\Accounting\Entity\Produit; | ||
| use AppBundle\Accounting\Entity\Repository\ProduitRepository; | ||
| use AppBundle\Accounting\Form\ProduitType; | ||
| use AppBundle\AuditLog\Audit; | ||
| use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; | ||
| use Symfony\Component\HttpFoundation\Request; | ||
| use Symfony\Component\HttpFoundation\Response; | ||
|
|
||
| final class EditProduitAction extends AbstractController | ||
| { | ||
| public function __construct( | ||
| private readonly ProduitRepository $produitRepository, | ||
| private readonly Audit $audit, | ||
| ) {} | ||
|
|
||
| public function __invoke(int $id, Request $request): Response | ||
| { | ||
| $produit = $this->produitRepository->find($id); | ||
|
Mopolo marked this conversation as resolved.
|
||
| if (!$produit instanceof Produit) { | ||
| throw $this->createNotFoundException(sprintf('Le produit n\'a pas été trouvé avec l\'id "%s"', $id)); | ||
| } | ||
|
|
||
| $form = $this->createForm(ProduitType::class, $produit); | ||
| $form->handleRequest($request); | ||
|
|
||
| if ($form->isSubmitted() && $form->isValid()) { | ||
| $this->produitRepository->save($produit); | ||
| $this->audit->log('Modification du produit ' . $produit->reference); | ||
| $this->addFlash('notice', 'Le produit a été modifié'); | ||
| return $this->redirectToRoute('admin_accounting_produits_list'); | ||
| } | ||
|
|
||
| return $this->render('admin/accounting/produit/form.html.twig', [ | ||
| 'form' => $form->createView(), | ||
| 'produit' => $produit, | ||
| 'formTitle' => 'Modifier un produit', | ||
| 'submitLabel' => 'Modifier', | ||
| ]); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| <?php | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| namespace AppBundle\Controller\Admin\Accounting\Produit; | ||
|
|
||
| use AppBundle\Accounting\Entity\Repository\ProduitRepository; | ||
| use Symfony\Component\HttpFoundation\Request; | ||
| use Symfony\Component\HttpFoundation\Response; | ||
| use Twig\Environment; | ||
|
|
||
| final readonly class ListProduitAction | ||
| { | ||
| public function __construct( | ||
| private ProduitRepository $produitRepository, | ||
| private Environment $twig, | ||
| ) {} | ||
|
|
||
| public function __invoke(Request $request): Response | ||
| { | ||
| $produits = $this->produitRepository->getAllSortedByReference(); | ||
|
|
||
| return new Response($this->twig->render('admin/accounting/produit/list.html.twig', [ | ||
| 'produits' => $produits, | ||
| ])); | ||
| } | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.