src/Controller/DashboardController.php line 33

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use App\Entity\Purchase;
  4. use App\Entity\PurchaseAPOD;
  5. use App\Entity\PurchaseEtsy;
  6. use App\Entity\PurchaseItemEtsy;
  7. use App\Entity\PurchaseItemSide;
  8. use App\Entity\PurchaseItemsEtsySellerNotes;
  9. use App\Entity\PurchaseShipStationRate;
  10. use App\Entity\User;
  11. use Doctrine\ORM\EntityManagerInterface;
  12. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  13. use Symfony\Component\HttpFoundation\Response;
  14. use Symfony\Component\Routing\Annotation\Route;
  15. use Psr\Log\LoggerInterface;
  16. use App\Service\Stripe\StripeHelper;
  17. use Symfony\Component\HttpFoundation\Request;
  18. use Symfony\Component\HttpFoundation\JsonResponse;
  19. use Doctrine\ORM\Query\Expr\Join;
  20. class DashboardController extends AbstractHappyLauncherController
  21. {
  22. public function __construct(
  23. private EntityManagerInterface $entityManager,
  24. private LoggerInterface $logger,
  25. protected StripeHelper $stripeHelper,
  26. ) {
  27. }
  28. #[Route('/', name: 'app_dashboard')]
  29. public function index(Request $request): Response
  30. {
  31. $query = $request->query->all();
  32. /** @var User $user */
  33. $user = $this->getUser();
  34. $storeList = [];
  35. foreach ($user->getUserStores() as $store) {
  36. $storeList[] = $store->getId();
  37. }
  38. if (empty($storeList)) $storeList = [ -1 ]; // avoid SQL errors
  39. $capability = in_array( 'ROLE_ADMIN', $user->getRoles() );
  40. $purchaseRepo = $this->entityManager->getRepository(Purchase::class);
  41. $working_page = (int)($query['working_page'] ?? 1) ?: 1;
  42. $working_page_size = (int)($query['working_page_size'] ?? 10) ?: 10;
  43. // $working_order_criteria = [
  44. // 'userStore' => $storeList,
  45. // 'status' => [
  46. // Purchase::STATUS_PURCHASE_ERROR,
  47. // Purchase::STATUS_FOUND,
  48. // Purchase::STATUS_ODESK_PROCESSNG,
  49. // Purchase::STATUS_PAID,
  50. // Purchase::STATUS_SENT_TO_ORDER_DESK,
  51. // ]
  52. // ];
  53. $working_qb = $this->entityManager->createQueryBuilder();
  54. $working_qb->select('p')
  55. ->from(Purchase::class, 'p')
  56. ->leftJoin(PurchaseAPOD::class, 'p_apod', Join::WITH, 'p.id = p_apod.id')
  57. ->where($working_qb->expr()->in('p.status', [
  58. Purchase::STATUS_PURCHASE_ERROR,
  59. Purchase::STATUS_FOUND,
  60. Purchase::STATUS_ODESK_PROCESSNG,
  61. Purchase::STATUS_PAID,
  62. Purchase::STATUS_SENT_TO_ORDER_DESK,
  63. ]))
  64. ->andWhere($working_qb->expr()->orX(
  65. $working_qb->expr()->in('p.userStore', $storeList), // Etsy
  66. $working_qb->expr()->eq('p_apod.user', $user->getId()), // APOD
  67. ));
  68. // $countOfWorking = $purchaseRepo->count($working_order_criteria);
  69. $countOfWorking = count($working_qb->getQuery()->getResult());
  70. $countOfWorkingPages = (int)($countOfWorking / $working_page_size);
  71. $countOfWorkingPages += (int)(($countOfWorking % $working_page_size) != 0);
  72. $working_purchases = [];
  73. if ($working_page - 1 * $working_page_size < $countOfWorking) {
  74. /** @var Purchase[] $working_purchases */
  75. // $working_purchases = $purchaseRepo->findBy(
  76. // $working_order_criteria,
  77. // null,
  78. // $working_page_size,
  79. // ($working_page - 1) * $working_page_size,
  80. // );
  81. $working_purchases = $working_qb->getQuery()->setMaxResults($working_page_size)->setFirstResult(($working_page - 1) * $working_page_size)->getResult();
  82. usort($working_purchases, function ($a, $b) {
  83. return $b->getId() - $a->getId();
  84. });
  85. }
  86. $complete_page = ((int)($query['complete_page'] ?? 1)) ?: 1;
  87. $complete_page_size = ((int)($query['complete_page_size'] ?? 10)) ?: 10;
  88. // $complete_order_criteria = [
  89. // 'userStore' => $storeList,
  90. // 'status' => [
  91. // Purchase::STATUS_CANCELED,
  92. // Purchase::STATUS_COMPLETE,
  93. // Purchase::STATUS_SHIPPED,
  94. // ]
  95. // ];
  96. $complete_qb = $this->entityManager->createQueryBuilder();
  97. $complete_qb->select('p')
  98. ->from(Purchase::class, 'p')
  99. ->leftJoin(PurchaseAPOD::class, 'p_apod', Join::WITH, 'p.id = p_apod.id')
  100. ->where($complete_qb->expr()->in('p.status', [
  101. Purchase::STATUS_CANCELED,
  102. Purchase::STATUS_COMPLETE,
  103. Purchase::STATUS_SHIPPED,
  104. ]))
  105. ->andWhere($complete_qb->expr()->orX(
  106. $complete_qb->expr()->in('p.userStore', $storeList), // Etsy
  107. $complete_qb->expr()->eq('p_apod.user', $user->getId()), // APOD
  108. ))
  109. ->orderBy('p.id', 'DESC');
  110. // $countOfComplete = $purchaseRepo->count($complete_order_criteria);
  111. $countOfComplete = count($complete_qb->getQuery()->getResult());
  112. $countOfCompletePages = (int)($countOfComplete / $complete_page_size);
  113. $countOfCompletePages += (int)(($countOfComplete % $complete_page_size) != 0);
  114. $complete_purchases = [];
  115. if ($complete_page - 1 * $complete_page_size < $countOfComplete) {
  116. /** @var Purchase[] $complete_purchases */
  117. // $complete_purchases = $purchaseRepo->findBy(
  118. // $complete_order_criteria,
  119. // [
  120. // 'id' => 'DESC'
  121. // ],
  122. // $complete_page_size,
  123. // ($complete_page - 1) * $complete_page_size,
  124. // );
  125. $complete_purchases = $complete_qb->getQuery()->setMaxResults($complete_page_size)->setFirstResult(($complete_page - 1) * $complete_page_size)->getResult();
  126. }
  127. $notShippedPurchases = [];
  128. $personalizedCountData = [];
  129. $customize_status = [];
  130. $purchaseShipmentRates = [];
  131. $purchaseShipment = [];
  132. $hasSelectedRates = [];
  133. foreach ($working_purchases as $purchase) {
  134. $rates = $purchase->getPurchaseShipStationRates();
  135. $purchaseRates = [];
  136. $itemId = null;
  137. $hasSelectedRates[$purchase->getId()] = false;
  138. if (! $rates->isEmpty()) {
  139. foreach ($rates as $rate) {
  140. if ($rate->getServiceCode() == 'usps_media_mail') {
  141. continue;
  142. }
  143. if (! $purchase instanceof PurchaseAPOD) {
  144. $item = $rate->getPurchaseItemEtsy()->getId();
  145. $itemId ??= $item;
  146. if ($itemId !== $item) {
  147. continue;
  148. }
  149. }
  150. if ($rate->getSelected() == 'yes') {
  151. $hasSelectedRates[$purchase->getId()] = true;
  152. }
  153. $purchaseRates[] = $rate;
  154. }
  155. $purchaseShipmentRates[$purchase->getId()] = $purchaseRates;
  156. }
  157. $purchaseId = $purchase->getId();
  158. if ($purchase->getHasPersonalizedItem()) {
  159. $getPersonalizedCountData = $this->getPersonalizedItemsCountData($purchaseId);
  160. $personalizedCountData[$purchaseId] = $getPersonalizedCountData;
  161. $customize_status[$purchaseId] =
  162. $getPersonalizedCountData['itemsCount'] == $getPersonalizedCountData['completedItemsCount'];
  163. } else {
  164. $personalizedCountData[$purchaseId] = [
  165. 'needCustomization' => false,
  166. ];
  167. $customize_status[$purchaseId] = true;
  168. }
  169. $notShippedPurchases[] = $purchase;
  170. }
  171. $shippedPurchases = [];
  172. foreach ($complete_purchases as $purchase) {
  173. $purchaseId = $purchase->getId();
  174. if ($purchase->getHasPersonalizedItem()) {
  175. $getPersonalizedCountData = $this->getPersonalizedItemsCountData($purchaseId);
  176. $personalizedCountData[$purchaseId] = $getPersonalizedCountData;
  177. $customize_status[$purchaseId] =
  178. $getPersonalizedCountData['itemsCount'] == $getPersonalizedCountData['completedItemsCount'];
  179. } else {
  180. $personalizedCountData[$purchaseId] = [
  181. 'needCustomization' => false,
  182. ];
  183. $customize_status[$purchaseId] = true;
  184. }
  185. if (! $purchase->getShipStationShipments()->isEmpty()) {
  186. $purchaseShipment[$purchase->getId()] = $purchase->getShipStationShipments()->get(0);
  187. }
  188. $shippedPurchases[] = $purchase;
  189. }
  190. $showPage = $this->checkPartnerAndStripeExistance();
  191. return $this->render('dashboard/index.html.twig', [
  192. 'controller_name' => 'DashboardController',
  193. 'showPage' => $showPage,
  194. 'purchases' => [
  195. 'shipped' => $shippedPurchases,
  196. 'notShipped' => $notShippedPurchases,
  197. 'personalizedCountData' => $personalizedCountData,
  198. 'customize_status' => $customize_status,
  199. 'capability' => $capability,
  200. 'purchaseShipmentRates' => $purchaseShipmentRates,
  201. 'purchaseShipment' => $purchaseShipment,
  202. 'hasSelectedRate' => $hasSelectedRates,
  203. ],
  204. 'complete_pagination' => [
  205. 'first_page_link' => $this->generateUrl(
  206. 'app_dashboard',
  207. [
  208. 'complete_page' => 1,
  209. 'complete_page_size' => $complete_page_size,
  210. 'working_page' => $working_page,
  211. 'working_page_size' => $working_page_size,
  212. ]
  213. ),
  214. 'has_previous' => $complete_page > 1,
  215. 'previous_page_link' => $complete_page == 1 ? null : $this->generateUrl(
  216. 'app_dashboard',
  217. [
  218. 'complete_page' => $complete_page - 1,
  219. 'complete_page_size' => $complete_page_size,
  220. 'working_page' => $working_page,
  221. 'working_page_size' => $working_page_size,
  222. ]
  223. ),
  224. 'page' => $complete_page,
  225. 'page_size' => $complete_page_size,
  226. 'page_count' => $countOfCompletePages,
  227. 'has_next' => $complete_page < $countOfCompletePages,
  228. 'next_page_link' => $complete_page >= $countOfCompletePages ? null : $this->generateUrl(
  229. 'app_dashboard',
  230. [
  231. 'complete_page' => $complete_page + 1,
  232. 'complete_page_size' => $complete_page_size,
  233. 'working_page' => $working_page,
  234. 'working_page_size' => $working_page_size,
  235. ]
  236. ),
  237. 'last_page_link' => $this->generateUrl(
  238. 'app_dashboard',
  239. [
  240. 'complete_page' => $countOfCompletePages,
  241. 'complete_page_size' => $complete_page_size,
  242. 'working_page' => $working_page,
  243. 'working_page_size' => $working_page_size,
  244. ]
  245. ),
  246. ],
  247. 'working_pagination' => [
  248. 'first_page_link' => $this->generateUrl(
  249. 'app_dashboard',
  250. [
  251. 'complete_page' => $complete_page,
  252. 'complete_page_size' => $complete_page_size,
  253. 'working_page' => 1,
  254. 'working_page_size' => $working_page_size,
  255. ]
  256. ),
  257. 'has_previous' => $working_page > 1,
  258. 'previous_page_link' => $working_page == 1 ? null : $this->generateUrl(
  259. 'app_dashboard',
  260. [
  261. 'complete_page' => $complete_page,
  262. 'complete_page_size' => $complete_page_size,
  263. 'working_page' => $working_page - 1,
  264. 'working_page_size' => $working_page_size,
  265. ]
  266. ),
  267. 'page' => $working_page,
  268. 'page_size' => $working_page_size,
  269. 'page_count' => $countOfWorkingPages,
  270. 'has_next' => $complete_page < $countOfCompletePages,
  271. 'next_page_link' => $complete_page >= $countOfCompletePages ? null : $this->generateUrl(
  272. 'app_dashboard',
  273. [
  274. 'complete_page' => $complete_page + 1,
  275. 'complete_page_size' => $complete_page_size,
  276. 'working_page' => $working_page,
  277. 'working_page_size' => $working_page_size,
  278. ]
  279. ),
  280. 'last_page_link' => $this->generateUrl(
  281. 'app_dashboard',
  282. [
  283. 'complete_page' => $countOfCompletePages,
  284. 'complete_page_size' => $complete_page_size,
  285. 'working_page' => $working_page,
  286. 'working_page_size' => $working_page_size,
  287. ]
  288. ),
  289. ],
  290. ]);
  291. }
  292. public function getPersonalizedItemsCountData($purchaseId): array
  293. {
  294. $purchaseItemEtsyRepository = $this->entityManager->getRepository(PurchaseItemEtsy::class);
  295. $purchaseItemsEtsy = $purchaseItemEtsyRepository->findBy(['purchase' => $purchaseId]);
  296. $countPersonalized = 0;
  297. $countCompleted = 0;
  298. foreach ($purchaseItemsEtsy as $purchaseItemEtsy) {
  299. if (empty($purchaseItemEtsy->getPersonalizationInstruction())) {
  300. continue;
  301. }
  302. $sideByNumber = [];
  303. foreach ($purchaseItemEtsy->getPurchaseItemSides() as $purchaseItemSide) {
  304. $sideByNumber[$purchaseItemSide->getItemNumber()] ??= 1;
  305. }
  306. $countPersonalized += $purchaseItemEtsy->getQuantity();
  307. $countCompleted += count($sideByNumber);
  308. }
  309. return [
  310. 'itemsCount' => $countPersonalized,
  311. 'completedItemsCount' => $countCompleted,
  312. 'needCustomization' => true,
  313. ];
  314. }
  315. #[Route('/purchase-item-seller-notes', name: 'purchaseItemSellerNotes', methods: ["POST"])]
  316. public function purchaseItemSellerNotes(Request $request): JsonResponse
  317. {
  318. //@todo check that the user has access to the purchase
  319. $data = json_decode($request->getContent(), true);
  320. $purchaseId = $data['purchaseId'] ?? null;
  321. $notes = $data['notes'] ?? '';
  322. $type = $data['type'] ?? '';
  323. if(!$purchaseId && $notes == ''){
  324. return new JsonResponse(
  325. [
  326. 'message' => 'Something went wrong.',
  327. 'status' => false
  328. ]);
  329. }
  330. if( $type == 'order'){
  331. $purchaseEtsyRepository = $this->entityManager->getRepository(PurchaseEtsy::class);
  332. $purchaseEtsy = $purchaseEtsyRepository->find($purchaseId);
  333. $purchaseEtsy->setSellerNotes($notes);
  334. $this->entityManager->persist($purchaseEtsy);
  335. }
  336. $purchaseItemRepository = $this->entityManager->getRepository(PurchaseItemEtsy::class);
  337. $purchaseItemsEtsy = $purchaseItemRepository->findBy(['purchase' => $purchaseId]);
  338. $purchaseItemsEtsySellerNotesRepository = new PurchaseItemsEtsySellerNotes;
  339. foreach ($purchaseItemsEtsy as $purchaseItemEtsy) {
  340. $purchaseItemsEtsySellerNotesRepository->setSellerNotes($notes);
  341. $purchaseItemsEtsySellerNotesRepository->setPurchaseItem($purchaseItemEtsy);
  342. $this->entityManager->persist($purchaseItemsEtsySellerNotesRepository);
  343. }
  344. $this->entityManager->flush();
  345. return new JsonResponse(
  346. [
  347. 'message' => 'Notes saved successfully.',
  348. 'status' => true
  349. ]);
  350. }
  351. #[Route('/purchase-set-shipping-rate', name: 'purchaseSetShippingRate', methods: ["POST"])]
  352. public function purchaseSetShippingRate(Request $request): JsonResponse
  353. {
  354. //@todo check that the user has access to the purchase
  355. $data = $request->toArray();
  356. $purchaseId = $data['purchaseId'] ?? null;
  357. $rateId = $data['rateId'] ?? null;
  358. if(!$purchaseId && !$rateId){
  359. return new JsonResponse(
  360. [
  361. 'message' => 'Data is incomplete.',
  362. 'status' => false
  363. ]);
  364. }
  365. $purchaseRepository = $this->entityManager->getRepository(Purchase::class);
  366. $purchase = $purchaseRepository->find($purchaseId);
  367. $purchaseShipStationRateRepository = $this->entityManager->getRepository(PurchaseShipStationRate::class);
  368. $purchaseShipStationRate = $purchaseShipStationRateRepository->findOneBy(
  369. [
  370. 'purchase' => $purchase,
  371. 'id' => $rateId,
  372. ],
  373. );
  374. $selectedRates = $purchaseShipStationRateRepository->findBy(
  375. [
  376. 'purchase' => $purchase,
  377. 'selected' => 'yes',
  378. ]
  379. );
  380. foreach ($selectedRates as $selectedRate) {
  381. if ($selectedRate->getId() == $rateId) {
  382. continue;
  383. }
  384. $selectedRate->setSelected('no');
  385. $this->entityManager->persist($selectedRate);
  386. $this->entityManager->flush();
  387. }
  388. $purchaseShipStationRate->setSelected('yes');
  389. $this->entityManager->persist($purchaseShipStationRate);
  390. $this->entityManager->flush();
  391. return new JsonResponse(
  392. [
  393. 'message' => 'Purchase shipping rate successfully saved.',
  394. 'status' => true,
  395. ]);
  396. }
  397. }