src/Controller/Admin/DonationCrudController.php line 409

Open in your IDE?
  1. <?php
  2. namespace App\Controller\Admin;
  3. use App\Entity\Donation;
  4. use App\Message\ExportDonation;
  5. use App\Filter\OrderDetailsStatusFilter;
  6. use App\Filter\OrderDetailsTotalFilter;
  7. use App\Filter\DonationDateFilter;
  8. use App\Form\AdminOrderItemsFormType;
  9. use App\Repository\FilmProjectRepository;
  10. use App\Service\DonationService;
  11. use App\Service\UserService;
  12. use App\String\Constant;
  13. use App\Utility\DropdownValues;
  14. use App\Utility\PdfExporter;
  15. use Doctrine\ORM\EntityManagerInterface;
  16. use Doctrine\ORM\QueryBuilder;
  17. use EasyCorp\Bundle\EasyAdminBundle\Dto\EntityDto;
  18. use EasyCorp\Bundle\EasyAdminBundle\Dto\SearchDto;
  19. use EasyCorp\Bundle\EasyAdminBundle\Collection\FieldCollection;
  20. use EasyCorp\Bundle\EasyAdminBundle\Collection\FilterCollection;
  21. use EasyCorp\Bundle\EasyAdminBundle\Config\Action;
  22. use EasyCorp\Bundle\EasyAdminBundle\Config\Actions;
  23. use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
  24. use EasyCorp\Bundle\EasyAdminBundle\Config\Filters;
  25. use EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext;
  26. use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
  27. use EasyCorp\Bundle\EasyAdminBundle\Dto\BatchActionDto;
  28. use EasyCorp\Bundle\EasyAdminBundle\Factory\FilterFactory;
  29. use EasyCorp\Bundle\EasyAdminBundle\Field\AssociationField;
  30. use EasyCorp\Bundle\EasyAdminBundle\Field\BooleanField;
  31. use EasyCorp\Bundle\EasyAdminBundle\Field\ChoiceField;
  32. use EasyCorp\Bundle\EasyAdminBundle\Field\CollectionField;
  33. use EasyCorp\Bundle\EasyAdminBundle\Field\DateField;
  34. use EasyCorp\Bundle\EasyAdminBundle\Field\DateTimeField;
  35. use EasyCorp\Bundle\EasyAdminBundle\Field\FormField;
  36. use EasyCorp\Bundle\EasyAdminBundle\Field\IdField;
  37. use EasyCorp\Bundle\EasyAdminBundle\Field\MoneyField;
  38. use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
  39. use EasyCorp\Bundle\EasyAdminBundle\Filter\BooleanFilter;
  40. use EasyCorp\Bundle\EasyAdminBundle\Orm\EntityRepository;
  41. use EasyCorp\Bundle\EasyAdminBundle\Router\AdminUrlGenerator;
  42. use PhpOffice\PhpSpreadsheet\Spreadsheet;
  43. use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
  44. use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
  45. use Symfony\Component\HttpFoundation\RedirectResponse;
  46. use Symfony\Component\HttpFoundation\Response;
  47. use Twig\Environment;
  48. use Knp\Snappy\Pdf;
  49. use Symfony\Component\Messenger\MessageBusInterface;
  50. class DonationCrudController extends AbstractCrudController
  51. {
  52.     private UserService $userService;
  53.     private DonationService $donationService;
  54.     private $adminUrlGenerator;
  55.     public function __construct(UserService $userServiceDonationService $donationServiceAdminUrlGenerator $adminUrlGenerator)
  56.     {
  57.         $this->userService $userService;
  58.         $this->donationService $donationService;
  59.         $this->adminUrlGenerator $adminUrlGenerator;
  60.     }
  61.     public static function getEntityFqcn(): string
  62.     {
  63.         return Donation::class;
  64.     }
  65.     public function configureFields(string $pageName): iterable
  66.     {
  67.         return [
  68.             FormField::addPanel('Donor Details'),
  69.             TextField::new('orderDetails.orderBillingDetails.firstName''First Name')->setRequired(true)->setColumns(3)->hideOnIndex(),
  70.             TextField::new('orderDetails.orderBillingDetails.LastName''Last Name')->setRequired(true)->setColumns(3)->hideOnIndex(),
  71.             TextField::new('orderDetails.orderBillingDetails.emailAddress''Email')->setRequired(true)->setColumns(3)->hideOnIndex(),
  72.             TextField::new('orderDetails.orderBillingDetails.phoneNumber''Phone Number')->setRequired(true)->setColumns(3)->hideOnIndex(),
  73.             TextField::new('wordpressDonorName''Wordpress Donor Name')->setColumns(6)->hideOnIndex()->setHelp('If empty, project page will show default donor or organisation name.')->setPermission(Constant::ROLE_FINANCE),
  74.             BooleanField::new('isDisplayOrganisation''Display donor organisation on project page and receipt')->setColumns(12)->renderAsSwitch(false)->addCssClass('fw-bold')->hideOnIndex()->addCssClass('display-organisation-tickbox'),
  75.             TextField::new('orderDetails.orderBillingDetails.organisation''Organisation / Company')->setColumns(12)->hideOnIndex()->setHelp('Leave blank if no organisation/company applicable')->addCssClass('display-organisation-input'),
  76.             TextField::new('orderDetails.orderBillingDetails.street''Street')->setRequired(true)->setColumns(12)->hideOnIndex(),
  77.             TextField::new('orderDetails.orderBillingDetails.suburb''Suburb')->setRequired(true)->setColumns(3)->hideOnIndex(),
  78.             ChoiceField::new('orderDetails.orderBillingDetails.state''State')->setRequired(true)->setColumns(3)->setChoices(DropdownValues::$states)->hideOnIndex(),
  79.             ChoiceField::new('orderDetails.orderBillingDetails.country''Country')->setColumns(3)->hideOnIndex()->setRequired(true)->setChoices(DropdownValues::$countries),
  80.             TextField::new('orderDetails.orderBillingDetails.postcode''Postcode')->setRequired(true)->setColumns(3)->hideOnIndex(),
  81.             
  82.             FormField::addPanel('Donation Details'),
  83.             AssociationField::new('filmProject''Project')->setRequired(true)->setColumns(12)->setPermission(Constant::ADMIN_ROLE)->setFormTypeOptions([
  84.                 'query_builder' => function (FilmProjectRepository $er) {
  85.                     return $er->createQueryBuilder('e')
  86.                         ->andWhere('e.status = :approved')
  87.                         ->setParameter('approved''approved')
  88.                         ->orderBy('e.title''ASC')
  89.                     ;
  90.                 }
  91.             ])->hideOnIndex()->onlyWhenCreating(),
  92.             AssociationField::new('filmProject''Project')->setRequired(true)->setColumns(12)->setPermission(Constant::ADMIN_ROLE)->setFormTypeOptions([
  93.                 'query_builder' => function (FilmProjectRepository $er) {
  94.                     return $er->createQueryBuilder('e')
  95.                         ->andWhere('e.status = :approved')
  96.                         ->setParameter('approved''approved')
  97.                         ->orderBy('e.title''ASC')
  98.                     ;
  99.                 }
  100.             ])->hideOnIndex()->onlyWhenUpdating(),
  101.             CollectionField::new('orderDetails.orderItems''Product')
  102.                 ->showEntryLabel()
  103.                 ->setEntryIsComplex()
  104.                 ->setEntryType(AdminOrderItemsFormType::class)
  105.                 ->renderExpanded()
  106.                 ->setColumns('col-12')
  107.                 ->addCssClass('custom-collection-form product-selection-form')
  108.                 ->hideOnIndex()
  109.                 ->allowAdd(false)
  110.                 ->allowDelete(false),
  111.             ChoiceField::new('orderDetails.paymentDetails.type''Payment type')->setChoices([
  112.                 Constant::PAYMENT_EFT => Constant::PAYMENT_EFT,
  113.                 Constant::PAYMENT_CREDIT_CARD => Constant::PAYMENT_CREDIT_CARD,
  114.             ])->setColumns(4)->hideOnIndex(),
  115.             MoneyField::new('orderDetails.total''Donation Amount')->setRequired(true)->setColumns(8)->setCurrency('AUD')->addCssClass('custom-money-field')->setTextAlign('left')->hideOnIndex()->onlyWhenCreating(),
  116.             MoneyField::new('orderDetails.total''Donation Amount')->setRequired(true)->setColumns(8)->setCurrency('AUD')->addCssClass('custom-money-field')->setTextAlign('left')->hideOnIndex()->onlyWhenUpdating()->setFormTypeOption('disabled','disabled'),
  117.        
  118.             DateTimeField::new('modifiedAt''Date')->setFormat('dd MMM yyyy HH:mm:ss')->setColumns('col-4')->addCssClass('custom-date-field')->hideOnIndex(),
  119.             FormField::addPanel('Additional Information'),
  120.             ChoiceField::new('isDonationEmail''Is donation acknowledgement email and receipt required to donor?')->setChoices([
  121.                 'Yes' => true,
  122.                 'No' => false,
  123.             ])->renderExpanded()->setColumns(12)->hideOnIndex()->setRequired(true),
  124.             ChoiceField::new('isOrganisationConsent''Consent to having my name or organisation listed on the project page or any public list of donations for this project.')->setChoices([
  125.                 'I consent' => true,
  126.                 'I do not consent (this donation will be listed as anonymous)' => false,
  127.             ])->renderExpanded()->setColumns(12)->hideOnIndex()->setRequired(true),
  128.             ChoiceField::new('isContactShared''Consent to having my name and contact details shared with the filmmaker for the purpose of receiving communications from the filmmaker.')->setChoices([
  129.                 'I consent' => true,
  130.                 'I do not consent' => false,
  131.             ])->renderExpanded()->setColumns(12)->hideOnIndex()->setRequired(true),
  132.             ChoiceField::new('isNameApproved''Consent for my name as above to be listed in relevant project credits and/or organisational reporting as appropriate.')->setChoices([
  133.                 'I consent' => true,
  134.                 'I do not consent' => false,
  135.             ])->renderExpanded()->setColumns(12)->hideOnIndex()->setRequired(true),
  136.             FormField::addPanel('Xero Details')->setHelp('Leave Xero ID field blank to create a Xero ID object.'),
  137.             TextField::new('orderDetails.xeroId''Xero ID')->setColumns(4)->hideOnIndex(),
  138.             TextField::new('orderDetails.xeroContactId''Xero Contact ID')->setColumns(4)->hideOnIndex(),
  139.             TextField::new('orderDetails.invoiceNumber''Invoice Number')->setColumns(4)->hideOnIndex(),
  140.             FormField::addPanel('Salesforce Details')->setHelp('Leave this field blank to create a Salesforce object.'),
  141.             TextField::new('orderDetails.salesforceId''Salesforce ID')->setColumns(6)->hideOnIndex(),
  142.             // Index field
  143.             IdField::new('orderDetails.id''Order Id')->hideOnForm()->setTemplatePath('admin/field/order_mw_id.html.twig')->setSortable(true)->setPermission(Constant::ADMIN_ROLE),
  144.             TextField::new('orderDetails.invoiceNumber''Receipt Id')->setSortable(true)->hideOnForm()->setTemplatePath('admin/field/order_details_id.html.twig'),
  145.             TextField::new('orderDetails.orderBillingDetails.fullName''Donor Name')->setSortable(false)->hideOnForm(),
  146.             TextField::new('orderDetails.orderBillingDetails.organisation''Organisation')->setSortable(false)->hideOnForm()->setTemplatePath('admin/field/organisation.html.twig'),
  147.             TextField::new('filmProject.title''Donation to')->setSortable(true)->hideOnForm()->setTemplatePath('admin/field/donation_project_title.html.twig'),
  148.             BooleanField::new('isOrganisationConsent''Displayed Anonymous Status')->hideOnForm()->setTemplatePath('admin/field/is_organisation_consent.html.twig')->setTextAlign('left'),
  149.             MoneyField::new('orderDetails.total''Total Amount')->setSortable(true)->setCurrency('USD')->hideOnForm()->setTextAlign('left'),
  150.             MoneyField::new('totalDonation''Project Amount')->setSortable(true)->setCurrency('USD')->hideOnForm()->setTextAlign('left'),
  151.             MoneyField::new('popupAmount''Pop-up Amount')->setCurrency('USD')->hideOnForm()->setTextAlign('left')->setTemplatePath('admin/field/project_title.html.twig'),
  152.             DateField::new('modifiedAt''Date')->hideOnForm()->setFormat('dd MMM yyyy'),
  153.             TextField::new('orderDetails.paymentDetails.status''Status')->hideOnForm()->setTemplatePath('admin/field/payment_status.html.twig'),
  154.             TextField::new('orderDetails.paymentDetails.type''Method')->hideOnForm(),
  155.             // TextField::new('orderDetails.paymentDetails.type', 'Payment Type')->hideOnForm()->setTemplatePath('admin/field/payment_type.html.twig'),
  156.             
  157.         ];
  158.     }
  159.     
  160.     public function createEntity(string $entityFqcn)
  161.     {
  162.         $user $this->userService->getCurrentUser();
  163.         
  164.         $donation =  $this->donationService->createObject(null);
  165.         $orderDetails $donation->getOrderDetails();
  166.         $paymentDetails $orderDetails->getPaymentDetails();
  167.         $paymentDetails->setEftType();
  168.         return $donation;
  169.     }
  170.     public function persistEntity(EntityManagerInterface $entityManager$entityInstance): void
  171.     {
  172.         $orderDetails $entityInstance->getOrderDetails();
  173.         $orderDetails->setCreatedAt($entityInstance->getModifiedAt());
  174.         $orderDetails->setModifiedAt($entityInstance->getModifiedAt());
  175.         $entityInstance->setCreatedAt($entityInstance->getModifiedAt());
  176.         $entityManager->persist($orderDetails);
  177.         $entityManager->flush();
  178.         // Since it's manual donation, we have to make sure that the payment details is completed as well
  179.         $paymentDetails $orderDetails->getPaymentDetails();
  180.         $paymentDetails
  181.             ->setStatus('Completed')
  182.             ->setIsPaid(true)
  183.         ;
  184.         
  185.         $this->donationService->dispatchPersistEntity($entityInstance);
  186.         $entityManager->persist($entityInstance);
  187.         $entityManager->persist($paymentDetails);
  188.         $entityManager->flush();
  189.         $orderDetails $entityInstance->getOrderDetails();
  190.         $invoiceNumber $orderDetails->getInvoiceNumber();
  191.         // Finally, update the project donations on the Wordpress
  192.         $this->addFlash('Donation Confirmed''donation '$invoiceNumber .' has successfully been processed.');
  193.     }
  194.     public function updateEntity(EntityManagerInterface $entityManager$entityInstance): void
  195.     {
  196.         $uow $entityManager->getUnitOfWork();
  197.         $originalEntityData $uow->getOriginalEntityData$entityInstance ); // Get original data before edit
  198.         $oldProjectId null;
  199.         if (isset($originalEntityData['film_project_id'])) {
  200.             if ($originalEntityData['film_project_id'] != $entityInstance->getFilmProject()->getId()) {
  201.                 $oldProjectId $originalEntityData['film_project_id'];
  202.             }
  203.         } // Check if project is changed
  204.         $orderDetails $entityInstance->getOrderDetails();
  205.         // Rare case to cover changes from DAF Core to filmmaker projects and full amount of support daf is converted.
  206.         $filmProject $entityInstance->getFilmProject();
  207.         if (!$filmProject->isIsDafCore() && $entityInstance->getSupportDaf() >= $orderDetails->getTotal()) {
  208.             $entityInstance->setSupportDaf(null);
  209.         } 
  210.         $entityManager->persist($entityInstance);
  211.         $entityManager->flush();
  212.         if ($orderDetails->getXeroId()) {
  213.             $this->donationService->updateDonation($entityInstance$oldProjectId);
  214.         } else {
  215.             $this->donationService->dispatchPersistEntity($entityInstance);
  216.         }
  217.         $this->addFlash('Receipt updated''The receipt has been updated.'); 
  218.     }
  219.     public function deleteEntity(EntityManagerInterface $entityManager$entityInstance): void
  220.     {
  221.         $orderDetails $entityInstance->getOrderDetails();
  222.         if ($orderDetails) {
  223.             $paymentDetails $orderDetails->getPaymentDetails();
  224.             $paymentDetails->setStatus('archived');
  225.             
  226.             $entityManager->persist($entityInstance);
  227.             $entityManager->flush();   
  228.         }
  229.         $this->donationService->archiveDonation($entityInstance);
  230.         $this->addFlash('Receipt removed''The receipt has been removed.');  
  231.     }
  232.     public function createIndexQueryBuilder(SearchDto $searchDtoEntityDto $entityDtoFieldCollection $fieldsFilterCollection $filters): QueryBuilder
  233.     {
  234.         $request $this->container->get('request_stack')->getCurrentRequest();
  235.         $recurringDonationId $request->query->get('recurringDonationId');
  236.         $user $this->getUser();
  237.         $response $this->container->get(EntityRepository::class)->createQueryBuilder($searchDto$entityDto$fields$filters);
  238.         
  239.         if ($user->isAdmin()) {
  240.             $response
  241.                 ->leftJoin('entity.orderDetails','od')
  242.                 ->leftJoin('od.paymentDetails','p')
  243.                 ->andWhere('p.status != :archived')
  244.                 ->setParameter('archived''archived')
  245.                 ->addOrderBy('entity.modifiedAt''DESC')
  246.                 ->groupBy('od.modifiedAt')
  247.                 ->groupBy('od.id')
  248.             ;
  249.             if ($queryVal $searchDto->getQuery()) {
  250.                 $queryVal str_replace('MW'''$queryVal);
  251.                 $queryVal str_replace('"'''$queryVal);
  252.                 $response
  253.                     ->orWhere('od.id LIKE :query')
  254.                     ->setParameter('query'$queryVal)
  255.                 ;
  256.             }
  257.         } else {
  258.             $response
  259.                 ->leftJoin('entity.orderDetails','od')
  260.                 ->leftJoin('od.orderBillingDetails','ob')
  261.                 ->leftJoin('od.paymentDetails','p')
  262.                 ->andWhere('(ob.emailAddress = :email) or (od.user = :userId)')
  263.                 ->andWhere('p.status != :archived')
  264.                 ->setParameter('email'$user->getEmail())
  265.                 ->setParameter('userId'$user->getId())
  266.                 ->setParameter('archived''archived')
  267.                 ->addOrderBy('entity.modifiedAt''DESC')
  268.                 ->groupBy('od.modifiedAt')
  269.                 ->groupBy('od.id')
  270.             ;
  271.         }
  272.         if ($recurringDonationId) {
  273.             $response
  274.                 ->leftJoin('entity.recurringDonation','r')
  275.                 ->andWhere('entity.isRecurringDonation IS NOT NULL')
  276.                 ->andWhere('r.id = :recurringDonationId')
  277.                 ->setParameter('recurringDonationId'$recurringDonationId)
  278.             ;
  279.         }
  280.         
  281.         return $response;
  282.     }
  283.     public function configureCrud(Crud $crud): Crud
  284.     {
  285.         $crud
  286.             ->setSearchFields(['orderDetails.id''orderDetails.invoiceNumber''orderDetails.orderBillingDetails.firstName',  'orderDetails.orderBillingDetails.lastName''filmProject.title'])
  287.             ->setPageTitle('index''Donations')
  288.             ->setPageTitle('new''Add New Donation')
  289.             ->setPageTitle('edit''Edit Donation')
  290.             ->overrideTemplate('flash_messages''admin/crud/flash_messages_alt.html.twig')
  291.             ->overrideTemplate('crud/index''admin/index/donation_index.html.twig')
  292.             ->overrideTemplate('crud/new''admin/form/new_donation_form_theme.html.twig')
  293.             ->overrideTemplate('crud/edit''admin/form/edit_donation_form_theme.html.twig')
  294.         ;
  295.         // If recurring donation
  296.         $request $this->container->get('request_stack')->getCurrentRequest();
  297.         $recurringDonationId $request->query->get('recurringDonationId');
  298.         if ($recurringDonationId) {
  299.             $crud->setPageTitle('index''View Recurring Donation(s)');
  300.         }
  301.         return $crud;
  302.     }
  303.     public function configureActions(Actions $actions): Actions
  304.     {
  305.         $appearAsAnonymous Action::new('appearAsAnonymous''Appear as anonymous on project page')
  306.             ->linkToCrudAction('appearAsAnonymous')
  307.             ->displayIf(static function ($entity) {
  308.                 $orderDetails $entity->getOrderDetails();
  309.                 $paymentDetails $orderDetails->getPaymentDetails();
  310.                 return ($entity->isIsOrganisationConsent() && $paymentDetails->getStatus() != Constant::PAYMENT_STATUS_REFUNDED);
  311.             })
  312.         ;
  313.         $appearAsOrganisation Action::new('appearAsOrganisation''Appear as organisation on project page')
  314.             ->linkToCrudAction('appearAsOrganisation')
  315.             ->displayIf(static function ($entity) {
  316.                 $orderDetails $entity->getOrderDetails();
  317.                 $paymentDetails $orderDetails->getPaymentDetails();
  318.                 return (!$entity->isIsOrganisationConsent() && $paymentDetails->getStatus() != Constant::PAYMENT_STATUS_REFUNDED);
  319.             })
  320.         ;
  321.         $setAmountInvisible Action::new('setAmountInvisible''Make Donation Amount Invisible')
  322.             ->linkToCrudAction('setAmountInvisible')
  323.             ->displayIf(static function ($entity) {
  324.                 $orderDetails $entity->getOrderDetails();
  325.                 $paymentDetails $orderDetails->getPaymentDetails();
  326.                 return (!$entity->isIsAmountInvisible() && $paymentDetails->getStatus() != Constant::PAYMENT_STATUS_REFUNDED);
  327.             })
  328.         ;
  329.         $setAmountVisible Action::new('setAmountVisible''Make Donation Amount Visible')
  330.             ->linkToCrudAction('setAmountVisible')
  331.             ->displayIf(static function ($entity) {
  332.                 $orderDetails $entity->getOrderDetails();
  333.                 $paymentDetails $orderDetails->getPaymentDetails();
  334.                 return ($entity->isIsAmountInvisible() && $paymentDetails->getStatus() != Constant::PAYMENT_STATUS_REFUNDED);
  335.             })
  336.         ;
  337.         $viewInvoice Action::new('viewInvoice''View Receipt''')
  338.             ->setHtmlAttributes(['target' => '_blank'])
  339.             ->linkToCrudAction('viewInvoice')
  340.             ->displayIf(static function($entity) {
  341.                 $orderDetails $entity->getOrderDetails();
  342.                 $paymentDetails $orderDetails->getPaymentDetails();
  343.                 return ($paymentDetails->getStatus() == Constant::PAYMENT_STATUS_PAID && !empty($orderDetails->getXeroId()));
  344.             })
  345.         ;
  346.         $downloadInvoice Action::new('downloadInvoice''Download Receipt''')
  347.             ->linkToCrudAction('downloadInvoice')
  348.             ->displayIf(static function($entity) {
  349.                 $orderDetails $entity->getOrderDetails();
  350.                 $paymentDetails $orderDetails->getPaymentDetails();
  351.                 return ($paymentDetails->getStatus() == Constant::PAYMENT_STATUS_PAID && !empty($orderDetails->getXeroId()));
  352.             })
  353.         ;
  354.         $sendInvoice Action::new('sendInvoice''Send Receipt''')
  355.             ->linkToCrudAction('sendInvoice')
  356.             ->displayIf(static function($entity) {
  357.                 $orderDetails $entity->getOrderDetails();
  358.                 $paymentDetails $orderDetails->getPaymentDetails();
  359.                 return ($paymentDetails->getStatus() == Constant::PAYMENT_STATUS_PAID && !empty($orderDetails->getXeroId()));
  360.             })
  361.         ;
  362.         $sendInvoiceBatch Action::new('sendInvoiceBatch''Send Receipt''')
  363.             ->linkToCrudAction('sendInvoiceBatch')
  364.             ->createAsGlobalAction()
  365.             ->displayIf(static function($entity) {
  366.                 $orderDetails $entity->getOrderDetails();
  367.                 $paymentDetails $orderDetails->getPaymentDetails();
  368.                 return ($paymentDetails->getStatus() == Constant::PAYMENT_STATUS_PAID && !empty($orderDetails->getXeroId()));
  369.             })
  370.         ;
  371.         $generateCustomInvoice Action::new('generateCustomInvoice''Download Receipt''')
  372.             ->linkToCrudAction('generateCustomInvoice')
  373.             ->displayIf(static function($entity) {
  374.                 $orderDetails $entity->getOrderDetails();
  375.                 $paymentDetails $orderDetails->getPaymentDetails();
  376.                 return ($paymentDetails->getStatus() == Constant::PAYMENT_STATUS_PAID && !empty($orderDetails->getXeroId()));
  377.             })
  378.         ;
  379.         $refundDonation Action::new('refundDonation''Refund''')
  380.             ->linkToCrudAction('refundDonation')
  381.             ->displayIf(static function ($entity) {
  382.                 $orderDetails $entity->getOrderDetails();
  383.                 $paymentDetails $orderDetails->getPaymentDetails();
  384.                 $paymentStatus $paymentDetails->getStatus();
  385.                 $isRefund false;
  386.                 if ($paymentStatus == Constant::PAYMENT_STATUS_PAID && ($paymentDetails->getType() != Constant::PAYMENT_EFT)) {
  387.                     $isRefund true;
  388.                 } 
  389.                 return $isRefund;
  390.             })
  391.         ;
  392.         $refundModalDonation Action::new('refundModalDonation''Refund''')
  393.             ->linkToUrl('/')
  394.             ->displayIf(static function ($entity) {
  395.                 $orderDetails $entity->getOrderDetails();
  396.                 $paymentDetails $orderDetails->getPaymentDetails();
  397.                 $paymentStatus $paymentDetails->getStatus();
  398.                 $isRefund false;
  399.                 if ($paymentStatus == Constant::PAYMENT_STATUS_PAID && ($paymentDetails->getType() != Constant::PAYMENT_EFT)) {
  400.                     $isRefund true;
  401.                 } 
  402.                 return $isRefund;
  403.             })
  404.         ;
  405.         $partialRefundDonation Action::new('partialRefundDonation''Partial Refund''')
  406.             ->linkToCrudAction('partialRefundDonation')
  407.             ->displayIf(static function ($entity) {
  408.                 $orderDetails $entity->getOrderDetails();
  409.                 $paymentDetails $orderDetails->getPaymentDetails();
  410.                 $paymentStatus $paymentDetails->getStatus();
  411.                 $isRefund false;
  412.                 if ($paymentStatus == Constant::PAYMENT_STATUS_PAID && ($paymentDetails->getType() != Constant::PAYMENT_EFT) && (!empty($entity->getSupportDaf()))) {
  413.                     $isRefund true;
  414.                 } 
  415.                 return $isRefund;
  416.             })
  417.         ;
  418.         $partialRefundModalDonation Action::new('partialRefundModalDonation''Partial Refund''')
  419.             ->linkToUrl('/')
  420.             ->displayIf(static function ($entity) {
  421.                 $orderDetails $entity->getOrderDetails();
  422.                 $paymentDetails $orderDetails->getPaymentDetails();
  423.                 $paymentStatus $paymentDetails->getStatus();
  424.                 $isRefund false;
  425.                 if ($paymentStatus == Constant::PAYMENT_STATUS_PAID && ($paymentDetails->getType() != Constant::PAYMENT_EFT) && (!empty($entity->getSupportDaf()))) {
  426.                     $isRefund true;
  427.                 } 
  428.                 return $isRefund;
  429.             })
  430.         ;
  431.         $getRefundInvoice Action::new('getRefundInvoice''Download Refund Bill''')
  432.             ->linkToCrudAction('getRefundInvoice')
  433.             ->displayIf(static function ($entity) {
  434.                 $orderDetails $entity->getOrderDetails();
  435.                 $isRefund $orderDetails->isIsRefund();
  436.                 return $isRefund;
  437.             })
  438.         ;
  439.         $exportBatchDonations Action::new('exportBatchDonations''Export Donations''')
  440.             ->linkToCrudAction('exportBatchDonations')
  441.             ->createAsGlobalAction()
  442.         ;
  443.         return $actions
  444.             ->add(Crud::PAGE_INDEX$appearAsAnonymous)
  445.             ->add(Crud::PAGE_INDEX$appearAsOrganisation)
  446.             ->add(Crud::PAGE_INDEX$setAmountInvisible)
  447.             ->add(Crud::PAGE_INDEX$setAmountVisible)
  448.             ->add(Crud::PAGE_INDEX$viewInvoice)
  449.             // ->add(Crud::PAGE_INDEX, $downloadInvoice)
  450.             ->add(Crud::PAGE_INDEX$generateCustomInvoice)
  451.             ->add(Crud::PAGE_INDEX$sendInvoice)
  452.             ->add(Crud::PAGE_INDEX$refundDonation)
  453.             ->add(Crud::PAGE_INDEX$refundModalDonation)
  454.             ->add(Crud::PAGE_INDEX$partialRefundDonation)
  455.             ->add(Crud::PAGE_INDEX$partialRefundModalDonation)
  456.             ->add(Crud::PAGE_INDEX$getRefundInvoice)
  457.             ->add(Crud::PAGE_INDEX$exportBatchDonations)
  458.             ->addBatchAction($sendInvoiceBatch)
  459.             
  460.             ->remove(Crud::PAGE_NEWAction::SAVE_AND_ADD_ANOTHER)
  461.             ->remove(Crud::PAGE_EDITAction::SAVE_AND_CONTINUE)
  462.             ->update(Crud::PAGE_INDEXAction::NEW, function (Action $action) {
  463.                 return $action
  464.                     ->setLabel('Create New')
  465.                 ;
  466.             })
  467.             ->update(Crud::PAGE_INDEX$refundDonation, function (Action $action) {
  468.                 return $action->addCssClass('d-none action-refundDonation');
  469.             })
  470.             ->update(Crud::PAGE_INDEX$partialRefundDonation, function (Action $action) {
  471.                 return $action->addCssClass('d-none action-partialRefundDonation');
  472.             })
  473.             ->update(Crud::PAGE_INDEX$exportBatchDonations, function (Action $action) {
  474.                 return $action->addCssClass('btn btn-secondary');
  475.             })
  476.             ->reorder(Crud::PAGE_INDEX, [Action::EDIT'appearAsAnonymous''appearAsOrganisation''setAmountInvisible''setAmountVisible''viewInvoice''generateCustomInvoice''sendInvoice''refundDonation''refundModalDonation''partialRefundDonation''partialRefundModalDonation''getRefundInvoice'Action::DELETE])
  477.         
  478.             ->setPermission(Action::NEW, Constant::ADMIN_ROLE)
  479.             ->setPermission($refundDonationConstant::ROLE_FINANCE)
  480.             ->setPermission($partialRefundDonationConstant::ROLE_FINANCE)
  481.             ->setPermission($refundModalDonationConstant::ROLE_FINANCE)
  482.             ->setPermission($partialRefundModalDonationConstant::ROLE_FINANCE)
  483.             ->setPermission($getRefundInvoiceConstant::ROLE_FINANCE)
  484.             ->setPermission($exportBatchDonationsConstant::ROLE_FINANCE)
  485.             ->setPermission(Action::EDITConstant::ADMIN_ROLE)
  486.             ->setPermission(Action::DELETEConstant::ROLE_FINANCE)
  487.             ->setPermission(Action::BATCH_DELETEConstant::ROLE_FINANCE)
  488.             ->setPermission($sendInvoiceBatchConstant::ADMIN_ROLE)
  489.         ;
  490.     }
  491.     public function configureFilters(Filters $filters): Filters
  492.     {
  493.         return $filters
  494.             ->add(DonationDateFilter::new('modifiedAt'))
  495.             ->add(BooleanFilter::new('isDonationEmail''Donation Email required to donor'))
  496.             ->add(BooleanFilter::new('isOrganisationConsent''Consent to display Organisation on project page'))
  497.             ->add(BooleanFilter::new('isContactShared''Consent to share contact details with filmmaker'))
  498.             ->add(BooleanFilter::new('isNameApproved''Consent name to be listed in relevant project credits'))
  499.             ->add(OrderDetailsTotalFilter::new('orderDetails''Total'))
  500.             // ->add(OrderDetailsStatusFilter::new('orderDetails', 'Payment Status'))
  501.         ;
  502.     }
  503.     // Custom Actions
  504.     public function appearAsAnonymous(AdminContext $context): Response
  505.     {
  506.         $entityInstance $context->getEntity()->getInstance();
  507.         $this->donationService->appearAsAnonymous($entityInstance);
  508.         $this->addFlash('Success''This donation is now appearing as anonymous on project page.' );
  509.         $donationIndexUrl $this->adminUrlGenerator->setController(DonationCrudController::class)
  510.             ->setAction(Action::INDEX)
  511.             ->generateUrl();
  512.         return new RedirectResponse($donationIndexUrl);
  513.     }
  514.     public function appearAsOrganisation(AdminContext $context): Response
  515.     {
  516.         $entityInstance $context->getEntity()->getInstance();
  517.         $this->donationService->appearAsNonAnonymous($entityInstance);
  518.         $this->addFlash('Success''This donation is now appearing as organisation on project page.' );
  519.         $donationIndexUrl $this->adminUrlGenerator->setController(DonationCrudController::class)
  520.             ->setAction(Action::INDEX)
  521.             ->generateUrl();
  522.         return new RedirectResponse($donationIndexUrl);
  523.     }
  524.     public function setAmountInvisible(AdminContext $context): Response
  525.     {
  526.         $entityInstance $context->getEntity()->getInstance();
  527.         $this->donationService->setAmountVisibility($entityInstancetrue);
  528.         $this->addFlash('Success''This donation amount is now invisible on project page.' );
  529.        
  530.         $donationIndexUrl $this->adminUrlGenerator->setController(DonationCrudController::class)
  531.         ->setAction(Action::INDEX)
  532.         ->generateUrl();
  533.         return new RedirectResponse($donationIndexUrl);
  534.     }
  535.     public function setAmountVisible(AdminContext $context): Response
  536.     {
  537.         $entityInstance $context->getEntity()->getInstance();
  538.         $this->donationService->setAmountVisibility($entityInstancefalse);
  539.         $this->addFlash('Success''This donation amount is now visible on project page.' );
  540.        
  541.         $donationIndexUrl $this->adminUrlGenerator->setController(DonationCrudController::class)
  542.         ->setAction(Action::INDEX)
  543.         ->generateUrl();
  544.         return new RedirectResponse($donationIndexUrl);
  545.     }
  546.     public function viewInvoice(AdminContext $context): Response
  547.     {
  548.         $entityInstance $context->getEntity()->getInstance();
  549.         $orderDetails $entityInstance->getOrderDetails();
  550.         $xeroId $orderDetails->getXeroId();
  551.         return $this->redirectToRoute('app_view_custom_invoice', ['invoiceId' => $xeroId]);
  552.     }
  553.     public function downloadInvoice(AdminContext $context): Response
  554.     {
  555.         $entityInstance $context->getEntity()->getInstance();
  556.         $orderDetails $entityInstance->getOrderDetails();
  557.         $xeroId $orderDetails->getXeroId();
  558.         return $this->redirectToRoute('app_xero_invoice', ['invoiceId' => $xeroId]);
  559.     }
  560.     public function sendInvoice(AdminContext $contextDonationService $donationService): Response
  561.     {
  562.         $entityInstance $context->getEntity()->getInstance();
  563.         $orderDetails $entityInstance->getOrderDetails();
  564.         $donationService->sendInvoice($entityInstance);
  565.         $donationIndexUrl $this->adminUrlGenerator->setController(DonationCrudController::class)
  566.             ->setAction(Action::INDEX)
  567.             ->generateUrl();
  568.         $this->addFlash('Success''Receipt MW'$orderDetails->getId() .' has been sent to its recipient.' );
  569.         
  570.         return new RedirectResponse($donationIndexUrl);
  571.     }
  572.     public function sendInvoiceBatch(BatchActionDto $batchActionDto,  DonationService $donationService): Response
  573.     {
  574.         $className $batchActionDto->getEntityFqcn();
  575.         $entityManager $this->container->get('doctrine')->getManagerForClass($className);
  576.         foreach ($batchActionDto->getEntityIds() as $id) {
  577.             $entityInstance $entityManager->find($className$id);
  578.             $orderDetails $entityInstance->getOrderDetails();
  579.             
  580.             $donationService->sendInvoice($entityInstance);
  581.         }
  582.         $this->addFlash('Success''Receipt MW'$orderDetails->getId() .' has been sent to its recipient.' );
  583.         return $this->redirect($batchActionDto->getReferrerUrl());
  584.     }
  585.     /**
  586.      * Generates invoice through custom pdf exporter
  587.      */
  588.     public function generateCustomInvoice(AdminContext $contextEnvironment $twig nullPdf $pdf)
  589.     {
  590.         $donation $context->getEntity()->getInstance();
  591.         $orderDetails $donation->getOrderDetails();
  592.         $pdfExporter = new PdfExporter($twig$pdf);
  593.         $pdfExporter->convertDonationReceiptPdf($orderDetails);
  594.     }
  595.     public function refundDonation(AdminContext $context): Response
  596.     {
  597.         $entityInstance $context->getEntity()->getInstance();
  598.         $this->donationService->refundDonation($entityInstance);
  599.         $orderDetails $entityInstance->getOrderDetails();
  600.         $donationIndexUrl $this->adminUrlGenerator->setController(DonationCrudController::class)
  601.             ->setAction(Action::INDEX)
  602.             ->generateUrl();
  603.         $this->addFlash('success''Donation '$orderDetails->getInvoiceNumber() .' has been refunded.');
  604.         return new RedirectResponse($donationIndexUrl);
  605.     }
  606.     public function partialRefundDonation(AdminContext $context): Response
  607.     {
  608.         $entityInstance $context->getEntity()->getInstance();
  609.         $this->donationService->partialRefundDonation($entityInstance);
  610.         $orderDetails $entityInstance->getOrderDetails();
  611.         $donationIndexUrl $this->adminUrlGenerator->setController(DonationCrudController::class)
  612.             ->setAction(Action::INDEX)
  613.             ->generateUrl();
  614.         $this->addFlash('success''Donation '$orderDetails->getInvoiceNumber() .' has been refunded.');
  615.         return new RedirectResponse($donationIndexUrl);
  616.     }
  617.     public function getRefundInvoice(AdminContext $context): Response
  618.     {
  619.         $entityInstance $context->getEntity()->getInstance();
  620.         $orderDetails $entityInstance->getOrderDetails();
  621.         $xeroId $orderDetails->getRefundXeroId();
  622.         return $this->redirectToRoute('app_xero_refund_invoice', ['invoiceId' => $xeroId]);
  623.     }
  624.     public function exportBatchDonations(AdminContext $contextMessageBusInterface $messageBus
  625.     {
  626.         $fields FieldCollection::new($this->configureFields(Crud::PAGE_INDEX));
  627.         $filters $this->container->get(FilterFactory::class)->create($context->getCrud()->getFiltersConfig(), $fields$context->getEntity());
  628.         $donations $this->createIndexQueryBuilder($context->getSearch(), $context->getEntity(), $fields$filters)
  629.             ->getQuery()
  630.             ->getResult();
  631.         ;
  632.         $message = new ExportDonation($donations);
  633.         $messageBus->dispatch($message);
  634.     }
  635. }