From be3f4b60c80228df191b68559f0675ce0801e6c9 Mon Sep 17 00:00:00 2001 From: shopkeeperdev Date: Mon, 6 Oct 2025 17:03:16 -0400 Subject: [PATCH] Initial commit of individual extension --- .../PDFingPO/Plugin/Amasty/.gitkeep | 0 .../PDFingPO/Plugin/Amasty/FilterPlugin.php | 104 +++++++++++ .../PDFingPO/Plugin/Amasty/TemplatePlugin.php | 170 ++++++++++++++++++ app/code/Shopkeeper/PDFingPO/composer.json | 15 ++ app/code/Shopkeeper/PDFingPO/etc/.gitkeep | 0 app/code/Shopkeeper/PDFingPO/etc/di.xml | 17 ++ app/code/Shopkeeper/PDFingPO/etc/module.xml | 10 ++ app/code/Shopkeeper/PDFingPO/registration.php | 8 + 8 files changed, 324 insertions(+) create mode 100644 app/code/Shopkeeper/PDFingPO/Plugin/Amasty/.gitkeep create mode 100644 app/code/Shopkeeper/PDFingPO/Plugin/Amasty/FilterPlugin.php create mode 100644 app/code/Shopkeeper/PDFingPO/Plugin/Amasty/TemplatePlugin.php create mode 100644 app/code/Shopkeeper/PDFingPO/composer.json create mode 100644 app/code/Shopkeeper/PDFingPO/etc/.gitkeep create mode 100644 app/code/Shopkeeper/PDFingPO/etc/di.xml create mode 100644 app/code/Shopkeeper/PDFingPO/etc/module.xml create mode 100644 app/code/Shopkeeper/PDFingPO/registration.php diff --git a/app/code/Shopkeeper/PDFingPO/Plugin/Amasty/.gitkeep b/app/code/Shopkeeper/PDFingPO/Plugin/Amasty/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/app/code/Shopkeeper/PDFingPO/Plugin/Amasty/FilterPlugin.php b/app/code/Shopkeeper/PDFingPO/Plugin/Amasty/FilterPlugin.php new file mode 100644 index 0000000..9523e7e --- /dev/null +++ b/app/code/Shopkeeper/PDFingPO/Plugin/Amasty/FilterPlugin.php @@ -0,0 +1,104 @@ +productRepository = $productRepository; + $this->logger = $logger; + } + + /** + * Add variables before filtering + */ + public function beforeFilter($subject, $value) +{ + if (!$this->costVariablesAdded) { + // Get existing variables + $variables = []; + if (method_exists($subject, 'getVariables')) { + $variables = $subject->getVariables(); + } else { + // Fallback to reflection + try { + $reflection = new \ReflectionObject($subject); + $propNames = ['_templateVars', 'templateVars', 'variables']; // Common property names + foreach ($propNames as $propName) { + if ($reflection->hasProperty($propName)) { + $prop = $reflection->getProperty($propName); + $prop->setAccessible(true); + $variables = $prop->getValue($subject); + break; + } + } + } catch (\Exception $e) { + $this->logger->info('FilterPlugin: Could not access variables: ' . $e->getMessage()); + } + } + + if (isset($variables['order']) && $variables['order'] instanceof Order) { + $this->logger->info('FilterPlugin: Adding cost variables for order ' . $variables['order']->getIncrementId()); + + $order = $variables['order']; + $itemsHtml = ''; + $totalCost = 0; + + foreach ($order->getAllVisibleItems() as $item) { + try { + $product = $this->productRepository->getById($item->getProductId()); + $cost = (float)($product->getCost() ?: $product->getData('cost') ?: 0); + } catch (\Exception $e) { + $cost = 0; + } + + $qty = (float) $item->getQtyOrdered(); + $rowTotal = $cost * $qty; + $totalCost += $rowTotal; + + $itemsHtml .= ''; + $itemsHtml .= '' . htmlspecialchars($item->getName()) . ''; + $itemsHtml .= '' . htmlspecialchars($item->getSku()) . ''; + $itemsHtml .= '' . (int)$qty . ''; + $itemsHtml .= '' . $this->formatPrice($cost, $order) . ''; + $itemsHtml .= '' . $this->formatPrice($rowTotal, $order) . ''; + $itemsHtml .= ''; + } + + $shippingCost = $order->getShippingAmount() ?: 0; + + // Add new variables to the array + $variables['items_html'] = $itemsHtml; + $variables['order_subtotal_cost'] = $this->formatPrice($totalCost, $order); + $variables['order_total_cost'] = $this->formatPrice($totalCost + $shippingCost, $order); + $variables['shipping_cost'] = $this->formatPrice($shippingCost, $order); + $variables['raw_subtotal_cost'] = $totalCost; + $variables['raw_total_cost'] = $totalCost + $shippingCost; + $variables['raw_shipping_cost'] = $shippingCost; + + // Set the updated variables array + $subject->setVariables($variables); + + $this->costVariablesAdded = true; + $this->logger->info('FilterPlugin: Cost variables added successfully'); + } + } + + return [$value]; +} + + protected function formatPrice($price, $order) + { + return $order->getOrderCurrency()->formatPrecision($price, 2, [], false); + } +} diff --git a/app/code/Shopkeeper/PDFingPO/Plugin/Amasty/TemplatePlugin.php b/app/code/Shopkeeper/PDFingPO/Plugin/Amasty/TemplatePlugin.php new file mode 100644 index 0000000..f4a667d --- /dev/null +++ b/app/code/Shopkeeper/PDFingPO/Plugin/Amasty/TemplatePlugin.php @@ -0,0 +1,170 @@ +productRepository = $productRepository; + $this->logger = $logger; + } + + /** + * Add cost variables before processing template + */ + public function beforeProcessTemplate($subject, array $variables = []) + { + if (!$this->isProcessing) { + $this->logger->info('TemplatePlugin: beforeProcessTemplate called'); + + // Check if we have an order in variables + if (isset($variables['order']) && $variables['order'] instanceof Order) { + $this->logger->info('TemplatePlugin: Found order ' . $variables['order']->getIncrementId()); + $variables = $this->addCostVariables($variables, $variables['order']); + } + } + + return [$variables]; + } + + /** + * Hook into setVars to add our variables + */ + public function afterSetVars($subject, $result, $variables) + { + // Only process once to avoid infinite loop + if (!$this->isProcessing && is_array($variables) && isset($variables['order']) && $variables['order'] instanceof Order) { + $this->isProcessing = true; + + $this->logger->info('TemplatePlugin: afterSetVars called - adding cost variables'); + + // Add cost variables + $enhancedVariables = $this->addCostVariables($variables, $variables['order']); + + // Set variables back + $subject->setVars($enhancedVariables); + + $this->isProcessing = false; + } + + return $result; + } + + /** + * Add cost variables to the variables array + */ + protected function addCostVariables($variables, $order) + { + // Check if we already added these variables + if (isset($variables['items_html'])) { + $this->logger->info('Cost variables already exist, skipping'); + return $variables; + } + + try { + // Build ONLY the table rows (tbody content) + $itemsHtml = ''; + $totalCost = 0; + $itemCount = 0; + + foreach ($order->getAllVisibleItems() as $item) { + $itemCount++; + try { + $product = $this->productRepository->getById($item->getProductId()); + $cost = (float)($product->getCost() ?: $product->getData('cost') ?: 0); + + $this->logger->info('Product ' . $item->getSku() . ' cost: ' . $cost); + } catch (\Exception $e) { + $this->logger->error('Could not load product: ' . $e->getMessage()); + $cost = 0; + } + + $qty = (float) $item->getQtyOrdered(); + $rowTotal = $cost * $qty; + $totalCost += $rowTotal; + + // Just the row content + $itemsHtml .= ''; + $itemsHtml .= '' . htmlspecialchars($item->getName()) . ''; + $itemsHtml .= '' . htmlspecialchars($item->getSku()) . ''; + $itemsHtml .= '' . (int)$qty . ''; + $itemsHtml .= '' . $this->formatPrice($cost, $order) . ''; + $itemsHtml .= '' . $this->formatPrice($rowTotal, $order) . ''; + $itemsHtml .= ''; + } + + $shippingCost = $order->getShippingAmount() ?: 0; + + // Create a complete table HTML for standalone use + $completeTableHtml = ''; + $completeTableHtml .= ''; + $completeTableHtml .= ''; + $completeTableHtml .= ''; + $completeTableHtml .= ''; + $completeTableHtml .= ''; + $completeTableHtml .= ''; + $completeTableHtml .= ''; + $completeTableHtml .= ''; + $completeTableHtml .= ''; + $completeTableHtml .= ''; + $completeTableHtml .= $itemsHtml; + $completeTableHtml .= ''; + $completeTableHtml .= ''; + $completeTableHtml .= ''; + $completeTableHtml .= ''; + $completeTableHtml .= ''; + $completeTableHtml .= ''; + if ($shippingCost > 0) { + $completeTableHtml .= ''; + $completeTableHtml .= ''; + $completeTableHtml .= ''; + $completeTableHtml .= ''; + } + $completeTableHtml .= ''; + $completeTableHtml .= ''; + $completeTableHtml .= ''; + $completeTableHtml .= ''; + $completeTableHtml .= ''; + $completeTableHtml .= '
ItemSKUQtyUnit CostTotal Cost
Subtotal:' . $this->formatPrice($totalCost, $order) . '
Shipping:' . $this->formatPrice($shippingCost, $order) . '
Grand Total:' . $this->formatPrice($totalCost + $shippingCost, $order) . '
'; + + $terms = $order->getData('terms') ?? ''; // Or $order->getTerms() if it's a getter + $termsHtml = str_replace(',', '
', htmlspecialchars($terms)); + + // Add variables for both approaches + $variables['items_html'] = $itemsHtml; // Just rows for inserting into existing table + $variables['items_complete_table'] = $completeTableHtml; // Complete table + $variables['order_subtotal_cost'] = $this->formatPrice($totalCost, $order); + $variables['order_total_cost'] = $this->formatPrice($totalCost + $shippingCost, $order); + $variables['shipping_cost'] = $this->formatPrice($shippingCost, $order); + $variables['raw_subtotal_cost'] = $totalCost; + $variables['raw_total_cost'] = $totalCost + $shippingCost; + $variables['raw_shipping_cost'] = $shippingCost; + $variables['terms_html'] = $termsHtml; + + // Test variable + $variables['test_cost_injection'] = 'WORKING'; + + $this->logger->info('Added cost variables - Items: ' . $itemCount . ', Total: ' . $totalCost); + + } catch (\Exception $e) { + $this->logger->error('Error adding cost variables: ' . $e->getMessage()); + } + + return $variables; + } + + protected function formatPrice($price, $order) + { + return $order->getOrderCurrency()->formatPrecision($price, 2, [], false); + } +} diff --git a/app/code/Shopkeeper/PDFingPO/composer.json b/app/code/Shopkeeper/PDFingPO/composer.json new file mode 100644 index 0000000..d614880 --- /dev/null +++ b/app/code/Shopkeeper/PDFingPO/composer.json @@ -0,0 +1,15 @@ +{ + "name": "shopkeeper/module-pdfing-po", + "description": "Display product costs in purchase order PDFs (PDFingPO)", + "type": "magento2-module", + "version": "1.0.0", + "license": "proprietary", + "autoload": { + "files": [ + "registration.php" + ], + "psr-4": { + "Shopkeeper\\PDFingPO\\": "" + } + } +} diff --git a/app/code/Shopkeeper/PDFingPO/etc/.gitkeep b/app/code/Shopkeeper/PDFingPO/etc/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/app/code/Shopkeeper/PDFingPO/etc/di.xml b/app/code/Shopkeeper/PDFingPO/etc/di.xml new file mode 100644 index 0000000..9e5377e --- /dev/null +++ b/app/code/Shopkeeper/PDFingPO/etc/di.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + diff --git a/app/code/Shopkeeper/PDFingPO/etc/module.xml b/app/code/Shopkeeper/PDFingPO/etc/module.xml new file mode 100644 index 0000000..a3e8f9f --- /dev/null +++ b/app/code/Shopkeeper/PDFingPO/etc/module.xml @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/app/code/Shopkeeper/PDFingPO/registration.php b/app/code/Shopkeeper/PDFingPO/registration.php new file mode 100644 index 0000000..c6073ef --- /dev/null +++ b/app/code/Shopkeeper/PDFingPO/registration.php @@ -0,0 +1,8 @@ +