add bill categories
add webdav client change pdf viewer
This commit is contained in:
parent
cb4905b151
commit
688fdd49ee
5
.env
5
.env
|
@ -31,3 +31,8 @@ DATABASE_URL="sqlite:///%kernel.project_dir%/var/data.db"
|
|||
# DATABASE_URL="mysql://db_user:db_password@127.0.0.1:3306/db_name?serverVersion=5.7"
|
||||
# DATABASE_URL="postgresql://db_user:db_password@127.0.0.1:5432/db_name?serverVersion=13&charset=utf8"
|
||||
###< doctrine/doctrine-bundle ###
|
||||
|
||||
WEBDAV_BILLING_SERVER=https://deblan.cloud
|
||||
WEBDAV_BILLING_BASE_URL=/public.php/webdav/
|
||||
WEBDAV_BILLING_USERNAME=
|
||||
WEBDAV_BILLING_PASSWORD=
|
||||
|
|
|
@ -4,8 +4,10 @@ const AddressAutocomplete = require('./modules/address.js')
|
|||
const FilesCollectionSorter = require('./modules/collection-sorter.js')
|
||||
const Calendar = require('./modules/calendar.js')
|
||||
const Masks = require('./modules/masks.js')
|
||||
const PdfViewer = require('./modules/pdf-viewer.js')
|
||||
|
||||
new AddressAutocomplete()
|
||||
new FilesCollectionSorter()
|
||||
new Calendar()
|
||||
new Masks()
|
||||
new PdfViewer()
|
||||
|
|
17
assets/js/modules/pdf-viewer.js
Normal file
17
assets/js/modules/pdf-viewer.js
Normal file
|
@ -0,0 +1,17 @@
|
|||
const viewer = require('pdfobject')
|
||||
|
||||
class PdfViewer {
|
||||
constructor () {
|
||||
this.showPdfs()
|
||||
}
|
||||
|
||||
showPdfs () {
|
||||
const elements = document.querySelectorAll('*[data-pdf]')
|
||||
|
||||
for (const element of elements) {
|
||||
viewer.embed(element.getAttribute('data-pdf'), `#${element.getAttribute('id')}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = PdfViewer
|
|
@ -10,7 +10,7 @@
|
|||
"doctrine/orm": "2.11.*",
|
||||
"knplabs/knp-snappy": "^1.4",
|
||||
"murph/murph-core": "^1.18",
|
||||
"sabre/dav": "^4.3"
|
||||
"sabre/dav": "^4.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/browser-kit": "^5.4",
|
||||
|
|
|
@ -4,6 +4,10 @@
|
|||
# Put parameters here that don't need to change on each machine where the app is deployed
|
||||
# https://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
|
||||
parameters:
|
||||
webdav_billing_server: "%env(WEBDAV_BILLING_SERVER)%"
|
||||
webdav_billing_base_url: "%env(WEBDAV_BILLING_BASE_URL)%"
|
||||
webdav_billing_username: "%env(WEBDAV_BILLING_USERNAME)%"
|
||||
webdav_billing_password: "%env(WEBDAV_BILLING_PASSWORD)%"
|
||||
|
||||
services:
|
||||
# default configuration for services in *this* file
|
||||
|
@ -65,5 +69,13 @@ services:
|
|||
$privateKeyPath: '%kernel.project_dir%/config/secrets/prod.private.key'
|
||||
$filesystem: '@filesystem'
|
||||
|
||||
App\Api\Webdav\Client:
|
||||
public: true
|
||||
arguments:
|
||||
$server: '%webdav_billing_server%'
|
||||
$baseUrl: '%webdav_billing_base_url%'
|
||||
$username: '%webdav_billing_username%'
|
||||
$password: '%webdav_billing_password%'
|
||||
|
||||
# add more service definitions when explicit configuration is needed
|
||||
# please note that last definitions always *replace* previous ones
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
"chunk": "^0.0.3",
|
||||
"inputmask": "^5.0.8-beta.17",
|
||||
"murph-project": "^1",
|
||||
"pdfobject": "^2.2.8",
|
||||
"vue-fragment": "^1.5.2"
|
||||
}
|
||||
}
|
||||
|
|
73
src/Api/Webdav/Client.php
Normal file
73
src/Api/Webdav/Client.php
Normal file
|
@ -0,0 +1,73 @@
|
|||
<?php
|
||||
|
||||
namespace App\Api\Webdav;
|
||||
|
||||
use Sabre\DAV\Client as BaseClient;
|
||||
|
||||
/**
|
||||
* class Client.
|
||||
*
|
||||
* @author Simon Vieille <simon@deblan.fr>
|
||||
*/
|
||||
class Client
|
||||
{
|
||||
protected BaseClient $client;
|
||||
protected string $baseUrl;
|
||||
|
||||
public function __construct(string $server, string $baseUrl, ?string $username, ?string $password)
|
||||
{
|
||||
$settings = [
|
||||
'baseUri' => $server,
|
||||
'userName' => $username,
|
||||
'password' => $password,
|
||||
'authType' => 1,
|
||||
];
|
||||
|
||||
$this->baseUrl = rtrim($baseUrl, '/');
|
||||
$this->client = new BaseClient($settings);
|
||||
}
|
||||
|
||||
public function sendFile(string $localFile, string $remoteFile): array
|
||||
{
|
||||
return $this->client->request(
|
||||
'PUT',
|
||||
$this->baseUrl.'/'.$remoteFile,
|
||||
fopen($localFile, 'r')
|
||||
);
|
||||
}
|
||||
|
||||
public function mv(string $source, string $destination): array
|
||||
{
|
||||
return $this->client->request(
|
||||
'MOVE',
|
||||
$this->baseUrl.'/'.$source,
|
||||
null,
|
||||
[
|
||||
'Destination' => $this->baseUrl.'/'.$destination,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function mkdir(string $directory): array
|
||||
{
|
||||
return $this->client->request(
|
||||
'MKCOL',
|
||||
$this->baseUrl.'/'.$directory
|
||||
);
|
||||
}
|
||||
|
||||
public function rm(string $file): array
|
||||
{
|
||||
return $this->client->request(
|
||||
'DELETE',
|
||||
$this->baseUrl.'/'.$file
|
||||
);
|
||||
}
|
||||
|
||||
public function exists(string $file): bool
|
||||
{
|
||||
$response = $this->client->request('GET', $this->baseUrl.'/'.$file);
|
||||
|
||||
return 404 !== $response['statusCode'];
|
||||
}
|
||||
}
|
|
@ -21,6 +21,8 @@ use Symfony\Component\Form\Form;
|
|||
use function Symfony\Component\String\u;
|
||||
use App\Repository\BillVendorRepositoryQuery;
|
||||
use App\Factory\BillVendorFactory;
|
||||
use App\Repository\BillCategoryRepositoryQuery;
|
||||
use App\Factory\BillCategoryFactory;
|
||||
|
||||
class BillAdminController extends CrudController
|
||||
{
|
||||
|
@ -71,6 +73,8 @@ class BillAdminController extends CrudController
|
|||
EntityManager $entityManager,
|
||||
BillVendorRepositoryQuery $vendorQuery,
|
||||
BillVendorFactory $vendorFactory,
|
||||
BillCategoryRepositoryQuery $categoryQuery,
|
||||
BillCategoryFactory $categoryFactory,
|
||||
Request $request
|
||||
): Response
|
||||
{
|
||||
|
@ -78,25 +82,39 @@ class BillAdminController extends CrudController
|
|||
$entity,
|
||||
$entityManager,
|
||||
$request,
|
||||
function(Entity $entity, Form $form, Request $request) use ($entityManager, $vendorQuery, $vendorFactory) {
|
||||
$vendor = $form->get('vendor')->getData();
|
||||
$customVendor = $form->get('customVendor')->getData();
|
||||
function(Entity $entity, Form $form, Request $request) use (
|
||||
$entityManager,
|
||||
$vendorQuery,
|
||||
$vendorFactory,
|
||||
$categoryQuery,
|
||||
$categoryFactory
|
||||
) {
|
||||
foreach ([
|
||||
'vendor' => [$vendorQuery, $vendorFactory, true],
|
||||
'category' => [$categoryQuery, $categoryFactory, false],
|
||||
] as $key => $elements) {
|
||||
$value = $form->get($key)->getData();
|
||||
$customValue = $form->get(u('custom_'.$key)->camel())->getData();
|
||||
|
||||
if ($customVendor !== null) {
|
||||
$customVendor = u($customVendor)->upper();
|
||||
$vendor = $vendorQuery->create()
|
||||
->where('.label = :label')
|
||||
->setParameter(':label', $customVendor)
|
||||
->findOne()
|
||||
;
|
||||
if ($customValue !== null) {
|
||||
if ($elements[2]) {
|
||||
$customValue = u($customValue)->upper();
|
||||
}
|
||||
|
||||
if ($vendor === null) {
|
||||
$vendor = $vendorFactory->create($customVendor);
|
||||
$entityManager->create($vendor);
|
||||
$value = $elements[0]->create()
|
||||
->where('.label = :label')
|
||||
->setParameter(':label', $customValue)
|
||||
->findOne()
|
||||
;
|
||||
|
||||
if ($value === null) {
|
||||
$value = $elements[1]->create($customValue);
|
||||
$entityManager->create($value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$entity->setVendor($vendor);
|
||||
$entity->{(string) u('set_'.$key)->camel()}($value);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -178,6 +196,12 @@ class BillAdminController extends CrudController
|
|||
'button_attr' => ['style' => 'user-select: all'],
|
||||
'sort' => ['vendor', '.vendor'],
|
||||
])
|
||||
->setField('index', 'Catégorie', Field\ButtonField::class, [
|
||||
'property' => 'category',
|
||||
'button_tag' => 'span',
|
||||
'button_attr' => ['style' => 'user-select: all'],
|
||||
'sort' => ['category', '.category'],
|
||||
])
|
||||
->setField('index', 'Date', Field\DateField::class, [
|
||||
'property' => 'date',
|
||||
'sort' => ['date', '.date'],
|
||||
|
|
129
src/Controller/BillCategoryAdminController.php
Normal file
129
src/Controller/BillCategoryAdminController.php
Normal file
|
@ -0,0 +1,129 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Core\Controller\Admin\Crud\CrudController;
|
||||
use App\Core\Crud\CrudConfiguration;
|
||||
use App\Core\Crud\Field;
|
||||
use App\Core\Entity\EntityInterface;
|
||||
use App\Core\Manager\EntityManager;
|
||||
use App\Entity\BillCategory as Entity;
|
||||
use App\Factory\BillCategoryFactory as Factory;
|
||||
use App\Form\BillCategoryType as Type;
|
||||
use App\Repository\BillCategoryRepositoryQuery as RepositoryQuery;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpFoundation\Session\Session;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
|
||||
class BillCategoryAdminController extends CrudController
|
||||
{
|
||||
#[Route(path: '/admin/user/edit/{entity}', name: 'admin_user_edit', methods: ['GET', 'POST'])]
|
||||
|
||||
#[Route(path: "/admin/bill_category/{page}", name: "admin_bill_category_index", methods: ['GET'], requirements: ['page' => '\d+'])]
|
||||
public function index(RepositoryQuery $query, Request $request, Session $session, int $page = 1): Response
|
||||
{
|
||||
return $this->doIndex($page, $query, $request, $session);
|
||||
}
|
||||
|
||||
#[Route(path: "/admin/bill_category/new", name: "admin_bill_category_new", methods: ['GET', 'POST'])]
|
||||
public function new(Factory $factory, EntityManager $entityManager, Request $request): Response
|
||||
{
|
||||
return $this->doNew($factory->create(), $entityManager, $request);
|
||||
}
|
||||
|
||||
#[Route(path: "/admin/bill_category/show/{entity}", name: "admin_bill_category_show", methods: ['GET'])]
|
||||
public function show(Entity $entity): Response
|
||||
{
|
||||
return $this->doShow($entity);
|
||||
}
|
||||
|
||||
#[Route(path: "/admin/bill_category/filter", name: "admin_bill_category_filter", methods: ['GET'])]
|
||||
public function filter(Session $session): Response
|
||||
{
|
||||
return $this->doFilter($session);
|
||||
}
|
||||
|
||||
#[Route(path: "/admin/bill_category/edit/{entity}", name: "admin_bill_category_edit", methods: ['GET', 'POST'])]
|
||||
public function edit(Entity $entity, EntityManager $entityManager, Request $request): Response
|
||||
{
|
||||
return $this->doEdit($entity, $entityManager, $request);
|
||||
}
|
||||
|
||||
#[Route(path: "/admin/bill_category/sort/{page}", name: "admin_bill_category_sort", methods: ['POST'], requirements: ['page' => '\d+'])]
|
||||
public function sort(RepositoryQuery $query, EntityManager $entityManager, Request $request, Session $session, int $page = 1): Response
|
||||
{
|
||||
return $this->doSort($page, $query, $entityManager, $request, $session);
|
||||
}
|
||||
|
||||
#[Route(path: "/admin/bill_category/batch/{page}", name: "admin_bill_category_batch", methods: ['POST'], requirements: ['page' => '\d+'])]
|
||||
public function batch(RepositoryQuery $query, EntityManager $entityManager, Request $request, Session $session, int $page = 1): Response
|
||||
{
|
||||
return $this->doBatch($page, $query, $entityManager, $request, $session);
|
||||
}
|
||||
|
||||
#[Route(path: "/admin/bill_category/delete/{entity}", name: "admin_bill_category_delete", methods: ['DELETE', 'POST'])]
|
||||
public function delete(Entity $entity, EntityManager $entityManager, Request $request): Response
|
||||
{
|
||||
return $this->doDelete($entity, $entityManager, $request);
|
||||
}
|
||||
|
||||
protected function getConfiguration(): CrudConfiguration
|
||||
{
|
||||
return CrudConfiguration::create()
|
||||
->setPageTitle('index', 'Catégories des factures')
|
||||
->setPageTitle('edit', '{label}')
|
||||
->setPageTitle('new', 'Nouvelle catégorie')
|
||||
->setPageTitle('show', '{label}')
|
||||
|
||||
->setPageRoute('index', 'admin_bill_category_index')
|
||||
->setPageRoute('new', 'admin_bill_category_new')
|
||||
->setPageRoute('edit', 'admin_bill_category_edit')
|
||||
->setPageRoute('show', 'admin_bill_category_show')
|
||||
->setPageRoute('sort', 'admin_bill_category_sort')
|
||||
->setPageRoute('batch', 'admin_bill_category_batch')
|
||||
->setPageRoute('delete', 'admin_bill_category_delete')
|
||||
->setPageRoute('filter', 'admin_bill_category_filter')
|
||||
|
||||
->setForm('edit', Type::class, [])
|
||||
->setForm('new', Type::class)
|
||||
// ->setForm('filter', Type::class)
|
||||
|
||||
// ->setMaxPerPage('index', 20)
|
||||
|
||||
// ->setIsSortableCollection('index', false)
|
||||
// ->setSortableCollectionProperty('sortOrder')
|
||||
|
||||
// ->setAction('index', 'new', true)
|
||||
// ->setAction('index', 'show', true)
|
||||
// ->setAction('index', 'edit', true)
|
||||
// ->setAction('index', 'delete', true)
|
||||
|
||||
// ->setAction('edit', 'back', true)
|
||||
// ->setAction('edit', 'show', true)
|
||||
// ->setAction('edit', 'delete', true)
|
||||
|
||||
// ->setAction('show', 'back', true)
|
||||
// ->setAction('show', 'edit', true)
|
||||
|
||||
->setDefaultSort('index', 'label', 'ASC')
|
||||
->setField('index', 'Libellé', Field\TextField::class, [
|
||||
'property' => 'label',
|
||||
'sort' => ['label', '.label'],
|
||||
])
|
||||
|
||||
// ->setField('index', 'Foo', Field\TextField::class, [
|
||||
// 'property' => 'foo',
|
||||
// ])
|
||||
|
||||
// ->setBatchAction('index', 'delete', 'Delete', function(EntityInterface $entity, EntityManager $manager) {
|
||||
// $manager->delete($entity);
|
||||
// })
|
||||
;
|
||||
}
|
||||
|
||||
protected function getSection(): string
|
||||
{
|
||||
return 'bill_category';
|
||||
}
|
||||
}
|
|
@ -6,8 +6,10 @@ use App\Repository\BillRepository;
|
|||
use Doctrine\DBAL\Types\Types;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use App\Core\Entity\EntityInterface;
|
||||
use App\Core\Doctrine\Timestampable;
|
||||
|
||||
#[ORM\Entity(repositoryClass: BillRepository::class)]
|
||||
#[ORM\HasLifecycleCallbacks]
|
||||
class Bill implements EntityInterface
|
||||
{
|
||||
#[ORM\Id]
|
||||
|
@ -40,6 +42,12 @@ class Bill implements EntityInterface
|
|||
#[ORM\JoinColumn(onDelete: 'SET NULL')]
|
||||
private ?BillVendor $vendor = null;
|
||||
|
||||
#[ORM\ManyToOne(inversedBy: 'bills')]
|
||||
#[ORM\JoinColumn(onDelete: 'SET NULL')]
|
||||
private ?BillCategory $category = null;
|
||||
|
||||
use Timestampable;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
|
@ -145,4 +153,47 @@ class Bill implements EntityInterface
|
|||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCategory(): ?BillCategory
|
||||
{
|
||||
return $this->category;
|
||||
}
|
||||
|
||||
public function setCategory(?BillCategory $category): self
|
||||
{
|
||||
$this->category = $category;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isPdf(): bool
|
||||
{
|
||||
return (bool) preg_match('/\.pdf/', $this->getFile());
|
||||
}
|
||||
|
||||
public function getRemoteFile(): ?string
|
||||
{
|
||||
if (!$this->getFile()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!$this->getDate()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!$this->getCategory()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!$this->getVendor()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return implode('/', [
|
||||
$this->getDate()->format('Y'),
|
||||
$this->getCategory()->getLabel(),
|
||||
$this->getVendor()->getLabel(),
|
||||
basename($this->getFile()),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
85
src/Entity/BillCategory.php
Normal file
85
src/Entity/BillCategory.php
Normal file
|
@ -0,0 +1,85 @@
|
|||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Repository\BillCategoryRepository;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use App\Core\Entity\EntityInterface;
|
||||
use App\Core\Doctrine\Timestampable;
|
||||
|
||||
#[ORM\Entity(repositoryClass: BillCategoryRepository::class)]
|
||||
#[ORM\HasLifecycleCallbacks]
|
||||
class BillCategory implements EntityInterface
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue]
|
||||
#[ORM\Column]
|
||||
private ?int $id = null;
|
||||
|
||||
#[ORM\Column(length: 255)]
|
||||
private ?string $label = null;
|
||||
|
||||
#[ORM\OneToMany(mappedBy: 'category', targetEntity: Bill::class)]
|
||||
private Collection $bills;
|
||||
|
||||
use Timestampable;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->bills = new ArrayCollection();
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return (string) $this->getLabel();
|
||||
}
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getLabel(): ?string
|
||||
{
|
||||
return $this->label;
|
||||
}
|
||||
|
||||
public function setLabel(string $label): self
|
||||
{
|
||||
$this->label = $label;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection<int, Bill>
|
||||
*/
|
||||
public function getBills(): Collection
|
||||
{
|
||||
return $this->bills;
|
||||
}
|
||||
|
||||
public function addBill(Bill $bill): self
|
||||
{
|
||||
if (!$this->bills->contains($bill)) {
|
||||
$this->bills->add($bill);
|
||||
$bill->setCategory($this);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeBill(Bill $bill): self
|
||||
{
|
||||
if ($this->bills->removeElement($bill)) {
|
||||
// set the owning side to null (unless already changed)
|
||||
if ($bill->getCategory() === $this) {
|
||||
$bill->setCategory(null);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
|
@ -7,8 +7,10 @@ use Doctrine\Common\Collections\ArrayCollection;
|
|||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use App\Core\Entity\EntityInterface;
|
||||
use App\Core\Doctrine\Timestampable;
|
||||
|
||||
#[ORM\Entity(repositoryClass: BillVendorRepository::class)]
|
||||
#[ORM\HasLifecycleCallbacks]
|
||||
class BillVendor implements EntityInterface
|
||||
{
|
||||
#[ORM\Id]
|
||||
|
@ -22,6 +24,8 @@ class BillVendor implements EntityInterface
|
|||
#[ORM\OneToMany(mappedBy: 'vendor', targetEntity: Bill::class)]
|
||||
private Collection $bills;
|
||||
|
||||
use Timestampable;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->bills = new ArrayCollection();
|
||||
|
|
17
src/Factory/BillCategoryFactory.php
Normal file
17
src/Factory/BillCategoryFactory.php
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
namespace App\Factory;
|
||||
|
||||
use App\Core\Factory\FactoryInterface;
|
||||
use App\Entity\BillCategory as Entity;
|
||||
|
||||
class BillCategoryFactory implements FactoryInterface
|
||||
{
|
||||
public function create(?string $label = null): Entity
|
||||
{
|
||||
$entity = new Entity();
|
||||
$entity->setLabel((string) $label);
|
||||
|
||||
return $entity;
|
||||
}
|
||||
}
|
|
@ -7,10 +7,10 @@ use App\Entity\BillVendor as Entity;
|
|||
|
||||
class BillVendorFactory implements FactoryInterface
|
||||
{
|
||||
public function create(string $label): Entity
|
||||
public function create(?string $label = null): Entity
|
||||
{
|
||||
$entity = new Entity();
|
||||
$entity->setLabel($label);
|
||||
$entity->setLabel((string) $label);
|
||||
|
||||
return $entity;
|
||||
}
|
||||
|
|
25
src/Form/BillCategoryType.php
Normal file
25
src/Form/BillCategoryType.php
Normal file
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
namespace App\Form;
|
||||
|
||||
use App\Entity\BillCategory;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
class BillCategoryType extends AbstractType
|
||||
{
|
||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||
{
|
||||
$builder
|
||||
->add('label')
|
||||
;
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver): void
|
||||
{
|
||||
$resolver->setDefaults([
|
||||
'data_class' => BillCategory::class,
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -15,6 +15,7 @@ use App\Entity\BillPeer;
|
|||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||
use App\Entity\BillVendor;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use App\Entity\BillCategory;
|
||||
|
||||
class BillFilterType extends AbstractType
|
||||
{
|
||||
|
@ -42,6 +43,19 @@ class BillFilterType extends AbstractType
|
|||
'data-jschoice' => '',
|
||||
],
|
||||
])
|
||||
->add('category', EntityType::class, [
|
||||
'label' => 'Catégorie',
|
||||
'required' => false,
|
||||
'class' => BillCategory::class,
|
||||
'query_builder' => function (EntityRepository $er) {
|
||||
return $er->createQueryBuilder('v')
|
||||
->orderBy('v.label', 'ASC')
|
||||
;
|
||||
},
|
||||
'attr' => [
|
||||
'data-jschoice' => '',
|
||||
],
|
||||
])
|
||||
->add('status', ChoiceType::class, [
|
||||
'choices' => BillPeer::choices(),
|
||||
'required' => false,
|
||||
|
|
|
@ -15,6 +15,7 @@ use Symfony\Component\Validator\Constraints\File;
|
|||
use Symfony\Component\Validator\Constraints\NotBlank;
|
||||
use Symfony\Component\Form\Extension\Core\Type\NumberType;
|
||||
use App\Entity\BillPeer;
|
||||
use App\Entity\BillCategory;
|
||||
|
||||
class BillType extends AbstractType
|
||||
{
|
||||
|
@ -64,6 +65,30 @@ class BillType extends AbstractType
|
|||
'required' => false,
|
||||
'mapped' => false,
|
||||
])
|
||||
->add('category', EntityType::class, [
|
||||
'label' => 'Catégorie',
|
||||
'required' => false,
|
||||
'class' => BillCategory::class,
|
||||
'label_attr' => [
|
||||
'class' => 'mt-3',
|
||||
],
|
||||
'query_builder' => function (EntityRepository $er) {
|
||||
return $er->createQueryBuilder('v')
|
||||
->orderBy('v.label', 'ASC')
|
||||
;
|
||||
},
|
||||
'attr' => [
|
||||
'data-jschoice' => '',
|
||||
],
|
||||
])
|
||||
->add('customCategory', null, [
|
||||
'label' => 'Ajouter une catégorie',
|
||||
'label_attr' => [
|
||||
'class' => 'font-weight-normal',
|
||||
],
|
||||
'required' => false,
|
||||
'mapped' => false,
|
||||
])
|
||||
->add('date', null, [
|
||||
'html5' => true,
|
||||
'widget' => 'single_text',
|
||||
|
@ -79,13 +104,21 @@ class BillType extends AbstractType
|
|||
->add('amountTtc', NumberType::class, [
|
||||
'label' => 'Montant TTC',
|
||||
'html5' => true,
|
||||
'scale' => 2,
|
||||
'label_attr' => [
|
||||
'class' => 'mt-3',
|
||||
],
|
||||
'attr' => [
|
||||
'step' => 0.01,
|
||||
],
|
||||
])
|
||||
->add('amountHt', NumberType::class, [
|
||||
'label' => 'Montant HT',
|
||||
'scale' => 2,
|
||||
'html5' => true,
|
||||
'attr' => [
|
||||
'step' => 0.01,
|
||||
],
|
||||
])
|
||||
->add('status', ChoiceType::class, [
|
||||
'choices' => BillPeer::choices(),
|
||||
|
|
66
src/Repository/BillCategoryRepository.php
Normal file
66
src/Repository/BillCategoryRepository.php
Normal file
|
@ -0,0 +1,66 @@
|
|||
<?php
|
||||
|
||||
namespace App\Repository;
|
||||
|
||||
use App\Entity\BillCategory;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @extends ServiceEntityRepository<BillCategory>
|
||||
*
|
||||
* @method BillCategory|null find($id, $lockMode = null, $lockVersion = null)
|
||||
* @method BillCategory|null findOneBy(array $criteria, array $orderBy = null)
|
||||
* @method BillCategory[] findAll()
|
||||
* @method BillCategory[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||
*/
|
||||
class BillCategoryRepository extends ServiceEntityRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, BillCategory::class);
|
||||
}
|
||||
|
||||
public function save(BillCategory $entity, bool $flush = false): void
|
||||
{
|
||||
$this->getEntityManager()->persist($entity);
|
||||
|
||||
if ($flush) {
|
||||
$this->getEntityManager()->flush();
|
||||
}
|
||||
}
|
||||
|
||||
public function remove(BillCategory $entity, bool $flush = false): void
|
||||
{
|
||||
$this->getEntityManager()->remove($entity);
|
||||
|
||||
if ($flush) {
|
||||
$this->getEntityManager()->flush();
|
||||
}
|
||||
}
|
||||
|
||||
// /**
|
||||
// * @return BillCategory[] Returns an array of BillCategory objects
|
||||
// */
|
||||
// public function findByExampleField($value): array
|
||||
// {
|
||||
// return $this->createQueryBuilder('b')
|
||||
// ->andWhere('b.exampleField = :val')
|
||||
// ->setParameter('val', $value)
|
||||
// ->orderBy('b.id', 'ASC')
|
||||
// ->setMaxResults(10)
|
||||
// ->getQuery()
|
||||
// ->getResult()
|
||||
// ;
|
||||
// }
|
||||
|
||||
// public function findOneBySomeField($value): ?BillCategory
|
||||
// {
|
||||
// return $this->createQueryBuilder('b')
|
||||
// ->andWhere('b.exampleField = :val')
|
||||
// ->setParameter('val', $value)
|
||||
// ->getQuery()
|
||||
// ->getOneOrNullResult()
|
||||
// ;
|
||||
// }
|
||||
}
|
15
src/Repository/BillCategoryRepositoryQuery.php
Normal file
15
src/Repository/BillCategoryRepositoryQuery.php
Normal file
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
namespace App\Repository;
|
||||
|
||||
use App\Core\Repository\RepositoryQuery;
|
||||
use Knp\Component\Pager\PaginatorInterface;
|
||||
use App\Repository\BillCategoryRepository as Repository;
|
||||
|
||||
class BillCategoryRepositoryQuery extends RepositoryQuery
|
||||
{
|
||||
public function __construct(Repository $repository, PaginatorInterface $paginator)
|
||||
{
|
||||
parent::__construct($repository, 'b', $paginator);
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
{% if entity.id %}
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<div class="col-md-4">
|
||||
{% for item in form %}
|
||||
{% if configuration.isI18n and item.vars.name == 'translations' %}
|
||||
{% include(configuration.view('form_translations', '@Core/admin/crud/_form_translations.html.twig')) with {form: item} %}
|
||||
|
@ -9,9 +9,20 @@
|
|||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="col-md-9 pl-5">
|
||||
<iframe src = "{{ asset('vendor/viewerjs/index.html#' ~ asset(entity.file)) }}" style="width: 100%; height: calc(100vh * 3 / 4)" u webkitallowfullscreen>
|
||||
</iframe>
|
||||
<div class="col-md-8 pl-5">
|
||||
{% if entity.isPdf %}
|
||||
<div data-pdf="{{ asset(entity.file) }}" style="height: calc(100vh / 3 * 2)" id="pdf"></div>
|
||||
{% else %}
|
||||
<div class="form-filepicker">
|
||||
<div class="card">
|
||||
<div class="card-img-top bg-tiles text-center">
|
||||
<a href="{{ asset(entity.file) }}" target="_blank">
|
||||
<img src="{{ asset(entity.file) }}" class="img-fluid">
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
{% set values = {
|
||||
'Référence': entity.reference,
|
||||
'Fournisseur': entity.vendor,
|
||||
'Catégorie': entity.category,
|
||||
'Montant TTC': entity.amountTtc is not null ? (entity.amountTtc|number_format(2, ',') ~ ' €') : '/',
|
||||
'Montant HT': entity.amountHt is not null ? (entity.amountHt|number_format(2, ',') ~ ' €') : '/',
|
||||
'Status': entity.humanStatus,
|
||||
|
@ -19,8 +20,19 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="col-md-8 pl-3">
|
||||
<iframe src = "{{ asset('vendor/viewerjs/index.html#' ~ asset(entity.file)) }}" style="width: 100%; height: calc(100vh * 2 / 3)" u webkitallowfullscreen>
|
||||
</iframe>
|
||||
{% if entity.isPdf %}
|
||||
<div data-pdf="{{ asset(entity.file) }}" style="height: calc(100vh / 3 * 2)" id="pdf"></div>
|
||||
{% else %}
|
||||
<div class="form-filepicker">
|
||||
<div class="card">
|
||||
<div class="card-img-top bg-tiles text-center">
|
||||
<a href="{{ asset(entity.file) }}" target="_blank">
|
||||
<img src="{{ asset(entity.file) }}" class="img-fluid">
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -66,19 +66,28 @@
|
|||
{{ include('@Core/admin/module/_menu_section.html.twig', {label: 'Comptabilité'}) }}
|
||||
|
||||
<ul class="nav flex-column">
|
||||
{{ include('@Core/admin/module/_menu_item.html.twig', {
|
||||
id: 'bill',
|
||||
label: 'Factures',
|
||||
route: path('admin_bill_index'),
|
||||
icon: 'fa fa-file'
|
||||
}) }}
|
||||
{% if is_granted('ROLE_TREASURER') %}
|
||||
{{ include('@Core/admin/module/_menu_item.html.twig', {
|
||||
id: 'bill',
|
||||
label: 'Factures',
|
||||
route: path('admin_bill_index'),
|
||||
icon: 'fa fa-file'
|
||||
}) }}
|
||||
|
||||
{{ include('@Core/admin/module/_menu_item.html.twig', {
|
||||
id: 'bill_vendor',
|
||||
label: 'Fournisseurs',
|
||||
route: path('admin_bill_vendor_index'),
|
||||
icon: 'fa fa-store'
|
||||
}) }}
|
||||
{{ include('@Core/admin/module/_menu_item.html.twig', {
|
||||
id: 'bill_vendor',
|
||||
label: 'Fournisseurs',
|
||||
route: path('admin_bill_vendor_index'),
|
||||
icon: 'fa fa-store'
|
||||
}) }}
|
||||
|
||||
{{ include('@Core/admin/module/_menu_item.html.twig', {
|
||||
id: 'bill_category',
|
||||
label: 'Catégories',
|
||||
route: path('admin_bill_category_index'),
|
||||
icon: 'fa fa-folder'
|
||||
}) }}
|
||||
{% endif %}
|
||||
|
||||
{{ include('@Core/admin/module/_menu_item.html.twig', {
|
||||
id: 'expense_report',
|
||||
|
|
|
@ -6429,6 +6429,11 @@ path-type@^2.0.0:
|
|||
dependencies:
|
||||
pify "^2.0.0"
|
||||
|
||||
pdfobject@^2.2.8:
|
||||
version "2.2.8"
|
||||
resolved "https://registry.yarnpkg.com/pdfobject/-/pdfobject-2.2.8.tgz#956c8ce254883cdbc7c3cbee3d74d5a017f98d0b"
|
||||
integrity sha512-dB/soWNMLtVGHfXERXnAtsKm0XwC6lyGVYegQcZxL4rw07rNOKvawc9kddBzlGr7TbiBZuGf4Drb3kyRbTf/QA==
|
||||
|
||||
performance-now@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
|
||||
|
|
Loading…
Reference in a new issue