<?php
namespace App\Controller\Admin;
use App\Entity\OrderDetails;
use App\Repository\DonationRepository;
use App\Service\DonationService;
use App\Service\FilmApplicationService;
use App\Service\OrderDetailsService;
use App\Service\UserService;
use App\String\Constant;
use App\Utility\PdfExporter;
use Doctrine\ORM\QueryBuilder;
use Doctrine\ORM\EntityManagerInterface;
use EasyCorp\Bundle\EasyAdminBundle\Collection\FieldCollection;
use EasyCorp\Bundle\EasyAdminBundle\Collection\FilterCollection;
use EasyCorp\Bundle\EasyAdminBundle\Config\Action;
use EasyCorp\Bundle\EasyAdminBundle\Config\Actions;
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
use EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
use EasyCorp\Bundle\EasyAdminBundle\Dto\BatchActionDto;
use EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto;
use EasyCorp\Bundle\EasyAdminBundle\Dto\SearchDto;
use EasyCorp\Bundle\EasyAdminBundle\Field\ChoiceField;
use EasyCorp\Bundle\EasyAdminBundle\Field\DateField;
use EasyCorp\Bundle\EasyAdminBundle\Field\IdField;
use EasyCorp\Bundle\EasyAdminBundle\Field\MoneyField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
use EasyCorp\Bundle\EasyAdminBundle\Orm\EntityRepository;
use EasyCorp\Bundle\EasyAdminBundle\Router\AdminUrlGenerator;
use Knp\Snappy\Pdf;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Response;
use Twig\Environment;
class OrderDetailsCrudController extends AbstractCrudController
{
private UserService $userService;
private OrderDetailsService $orderDetailsService;
private AdminUrlGenerator $adminUrlGenerator;
private $donationRepository;
public function __construct(UserService $userService, OrderDetailsService $orderDetailsService, AdminUrlGenerator $adminUrlGenerator, DonationRepository $donationRepository)
{
$this->userService = $userService;
$this->orderDetailsService = $orderDetailsService;
$this->adminUrlGenerator = $adminUrlGenerator;
$this->donationRepository = $donationRepository;
}
public static function getEntityFqcn(): string
{
return OrderDetails::class;
}
public function configureFields(string $pageName): iterable
{
return [
IdField::new('id', 'Order Id')->hideOnForm()->setTemplatePath('admin/field/order_mw_id.html.twig')->setSortable(true)->setPermission(Constant::ADMIN_ROLE),
TextField::new('invoiceNumber', 'Invoice Id')->hideOnForm()->setTemplatePath('admin/field/order_details_id.html.twig'),
TextField::new('orderBillingDetails.fullName', 'Account Name')->hideOnForm(),
TextField::new('type', 'Order Type'),
TextField::new('projectTitle', 'Project')->hideOnForm(),
DateField::new('modifiedAt', 'Date')->setFormat('dd MMM yyyy'),
MoneyField::new('total', 'Amount')->setCurrency('AUD')->setTextAlign('left'),
TextField::new('paymentDetails.status', 'Status')->setTemplatePath('admin/field/payment_status.html.twig')->hideOnForm()->setSortable(true),
ChoiceField::new('paymentDetails.status', 'Status')->setChoices([
'Pending' => 'Pending',
'Completed' => 'Completed',
'Refunded' => 'Refunded',
])->hideOnIndex(),
TextField::new('paymentDetails.type', 'Payment Type')->setTemplatePath('admin/field/payment_type.html.twig')->hideOnForm(),
ChoiceField::new('paymentDetails.type', 'Payment Type')->setChoices([
Constant::PAYMENT_EFT => Constant::PAYMENT_EFT,
Constant::PAYMENT_CREDIT_CARD => Constant::PAYMENT_CREDIT_CARD,
])->hideOnIndex(),
];
}
public function createEntity(string $entityFqcn)
{
$user = $this->userService->getCurrentUser();
$entity = $this->orderDetailsService->createDonationOrderObj($user);
return $entity;
}
public function deleteEntity(EntityManagerInterface $entityManager, $entityInstance): void
{
$paymentDetails = $entityInstance->getPaymentDetails();
$paymentDetails->setStatus('archived');
$entityManager->persist($entityInstance);
$entityManager->flush();
$this->addFlash('Receipt removed', 'The receipt has been removed.');
}
public function createIndexQueryBuilder(SearchDto $searchDto, EntityDto $entityDto, FieldCollection $fields, FilterCollection $filters): QueryBuilder
{
$user = $this->getUser();
$response = $this->container->get(EntityRepository::class)->createQueryBuilder($searchDto, $entityDto, $fields, $filters);
if ($user->isAdmin()) {
$response
->innerJoin('entity.paymentDetails','p')
->andWhere('entity.total > 0')
->andWhere('p.status IS NOT NULL')
// ->andWhere('p.status = :completed')
// ->setParameter('completed', 'Completed')
->andWhere('p.status != :archived')
->setParameter('archived', 'archived')
->addOrderBy('entity.modifiedAt', 'DESC');
return $response;
}
$response
->innerJoin('entity.paymentDetails','p')
->innerJoin('entity.orderBillingDetails','ob')
->andWhere('entity.total > 0')
->andWhere('p.status IS NOT NULL')
// ->andWhere('(p.status != :refunded) and (p.status != :partialRefunded) and (p.status != :archived)')
->andWhere('p.status != :archived')
->andWhere('(ob.emailAddress = :email) or (entity.user = :userId)')
->setParameter('email', $user->getEmail())
->setParameter('userId', $user->getId())
// ->setParameter('refunded', 'Refunded')
->setParameter('archived', 'archived')
// ->setParameter('partialRefunded', 'Partially Refunded')
->addOrderBy('entity.modifiedAt', 'DESC');
return $response;
}
public function configureCrud(Crud $crud): Crud
{
$crud
->setSearchFields(['invoiceNumber', 'orderBillingDetails.firstName', 'orderBillingDetails.lastName', 'type', 'donation.filmProject.title', 'filmProject.title'])
->setPageTitle('index', 'View Receipts')
->setPageTitle('new', 'Add New Transaction')
->setPageTitle('edit', 'Edit Transaction')
->overrideTemplate('crud/index', 'admin/index/index_alt.html.twig')
->overrideTemplate('flash_messages', 'admin/crud/flash_messages_alt.html.twig')
;
return $crud;
}
public function configureActions(Actions $actions): Actions
{
$viewInvoice = Action::new('viewInvoice', 'View Receipt', '')
->setHtmlAttributes(['target' => '_blank'])
->linkToCrudAction('viewInvoice')
->displayIf(static function($entity) {
$paymentDetails = $entity->getPaymentDetails();
return ($paymentDetails->getStatus() == Constant::PAYMENT_STATUS_PAID && !empty($entity->getXeroId()));
})
;
$downloadInvoice = Action::new('downloadInvoice', 'Download Receipt', '')
->linkToCrudAction('downloadInvoice')
->displayIf(static function($entity) {
$paymentDetails = $entity->getPaymentDetails();
return ($paymentDetails->getStatus() == Constant::PAYMENT_STATUS_PAID && !empty($entity->getXeroId()));
})
;
$generateCustomInvoice = Action::new('generateCustomInvoice', 'Download Receipt', '')
->linkToCrudAction('generateCustomInvoice')
->displayIf(static function($entity) {
$paymentDetails = $entity->getPaymentDetails();
return ($paymentDetails->getStatus() == Constant::PAYMENT_STATUS_PAID && !empty($entity->getXeroId()));
})
;
$downloadInvoices = Action::new('downloadInvoices', 'Export to PDF')
->linkToCrudAction('downloadInvoices')
;
$refundTransaction = Action::new('refundTransaction', 'Refund', '')
->linkToCrudAction('refundTransaction')
->displayIf(static function ($entity) {
$paymentDetails = $entity->getPaymentDetails();
$paymentStatus = $paymentDetails->getStatus();
$isRefund = false;
if ($paymentStatus == Constant::PAYMENT_STATUS_PAID && ($paymentDetails->getType() != Constant::PAYMENT_EFT)) {
$isRefund = true;
}
return $isRefund;
})
;
$getRefundInvoice = Action::new('getRefundInvoice', 'Download Refund Bill', '')
->linkToCrudAction('getRefundInvoice')
->displayIf(static function ($entity) {
$isRefund = $entity->isIsRefund();
return $isRefund;
})
;
$fixInvoice = Action::new('fixInvoice', 'Fix Invoice', '')
->linkToCrudAction('fixInvoice')
->displayIf(static function ($entity) {
$xeroId = $entity->getXeroId();
return empty($xeroId);
})
;
return $actions
->add(Crud::PAGE_INDEX, $viewInvoice)
->add(Crud::PAGE_INDEX, $generateCustomInvoice)
->add(Crud::PAGE_INDEX, $refundTransaction)
->add(Crud::PAGE_INDEX, $getRefundInvoice)
->add(Crud::PAGE_INDEX, $fixInvoice)
->remove(Crud::PAGE_INDEX, Action::NEW)
->remove(Crud::PAGE_INDEX, Action::DELETE)
//->addBatchAction($downloadInvoices)
->reorder(Crud::PAGE_INDEX, [Action::EDIT, 'viewInvoice', 'generateCustomInvoice', 'refundTransaction', 'getRefundInvoice'])
->setPermission(Crud::PAGE_EDIT, Constant::ADMIN_ROLE)
// ->setPermission(Action::DELETE, Constant::ADMIN_ROLE)
->setPermission(Action::BATCH_DELETE, Constant::ADMIN_ROLE)
->setPermission($refundTransaction, Constant::ADMIN_ROLE)
->setPermission($getRefundInvoice, Constant::ADMIN_ROLE)
;
}
// Custom Actions
public function viewInvoice(AdminContext $context): Response
{
$entityInstance = $context->getEntity()->getInstance();
$xeroId = $entityInstance->getXeroId();
return $this->redirectToRoute('app_view_custom_invoice', ['invoiceId' => $xeroId]);
}
public function downloadInvoice(AdminContext $context): Response
{
$entityInstance = $context->getEntity()->getInstance();
$xeroId = $entityInstance->getXeroId();
return $this->redirectToRoute('app_xero_invoice', ['invoiceId' => $xeroId]);
}
public function downloadInvoices(BatchActionDto $batchActionDto)
{
$className = $batchActionDto->getEntityFqcn();
$entityManager = $this->container->get('doctrine')->getManagerForClass($className);
$invoiceIds = [];
foreach ($batchActionDto->getEntityIds() as $id) {
$orderDetails = $entityManager->find($className, $id);
$invoiceId = $orderDetails->getXeroId();
$invoiceName = 'Invoice '. $orderDetails->getInvoiceNumber() .'.pdf';
$invoiceIds[$invoiceName] = $invoiceId;
}
$this->orderDetailsService->downloadInvoicesByInvoiceIds($invoiceIds);
}
public function refundTransaction(AdminContext $context): Response
{
$entityInstance = $context->getEntity()->getInstance();
$this->orderDetailsService->refundTransaction($entityInstance);
$donationIndexUrl = $this->adminUrlGenerator->setController(OrderDetailsCrudController::class)
->setAction(Action::INDEX)
->generateUrl();
$this->addFlash('success', 'The receipt has been refunded.');
return new RedirectResponse($donationIndexUrl);
}
public function getRefundInvoice(AdminContext $context): Response
{
$entityInstance = $context->getEntity()->getInstance();
$xeroId = $entityInstance->getRefundXeroId();
return $this->redirectToRoute('app_xero_refund_invoice', ['invoiceId' => $xeroId]);
}
/**
* Generates invoice through custom pdf exporter
*/
public function generateCustomInvoice(AdminContext $context, Environment $twig = null, Pdf $pdf)
{
$orderDetails = $context->getEntity()->getInstance();
$pdfExporter = new PdfExporter($twig, $pdf);
if (!empty($orderDetails->getFilmProject())) {
$pdfExporter->convertFilmReceiptPdf($orderDetails);
} else {
$pdfExporter->convertDonationReceiptPdf($orderDetails);
}
}
public function fixInvoice(AdminContext $context, FilmApplicationService $filmApplicationService, DonationService $donationService): Response
{
$orderIndexUrl = $this->adminUrlGenerator->setController(OrderDetailsCrudController::class)
->setAction(Action::INDEX)
->generateUrl();
$orderDetails = $context->getEntity()->getInstance();
assert($orderDetails instanceof OrderDetails); // ensure orderDetails is an instance of OrderDetails
if ($orderDetails->getType() == Constant::DONATION_PRODUCT_TYPE) { // Donation
$donation = $orderDetails->getDonation();
if (!$donation) {
$this->addFlash('failed', 'Donation doesn\'t exist in this order.');
return new RedirectResponse(($orderIndexUrl));
}
$donationService->dispatchPersistEntity($donation);
} else { // Film Application
$user = $orderDetails->getUser() ?? $this->getUser();
$filmApplicationService->createFilmProjectInvoice($user, $orderDetails->getFilmProject()); // Re-create Xero ID
}
$this->addFlash('success', 'The invoice has been fixed.');
return new RedirectResponse(($orderIndexUrl));
}
}