File: /var/www/kpopbg.com/deploy_currency_conversion.php
<?php
/**
* PrestaShop BGN to EUR Email Currency Conversion - PHP Deployment Script
*
* This PHP script applies all necessary changes to add EUR price equivalents
* to email templates in a PrestaShop installation.
*
* Usage: php deploy_currency_conversion.php [prestashop_root_path]
* Example: php deploy_currency_conversion.php /var/www/html/prestashop
*
* Author: GitHub Copilot
* Date: July 26, 2025
* Exchange Rate: 1 BGN = 1.95583 EUR (1 BGN = 0.5110789 EUR)
*/
// Set error reporting
error_reporting(E_ALL);
ini_set('display_errors', 1);
class CurrencyConversionDeployer
{
private $psRoot;
private $backupSuffix;
public function __construct($psRoot = null)
{
$this->backupSuffix = '.backup.' . date('Ymd_His');
if ($psRoot) {
$this->psRoot = rtrim($psRoot, '/');
} else {
$this->psRoot = $this->getPrestaShopRoot();
}
$this->validatePrestaShopDirectory();
}
private function getPrestaShopRoot()
{
echo "Enter PrestaShop root directory path: ";
$handle = fopen("php://stdin", "r");
$path = trim(fgets($handle));
fclose($handle);
return rtrim($path, '/');
}
private function validatePrestaShopDirectory()
{
if (!is_dir($this->psRoot)) {
throw new Exception("Directory does not exist: {$this->psRoot}");
}
if (!file_exists($this->psRoot . '/config/config.inc.php') || !is_dir($this->psRoot . '/classes')) {
throw new Exception("Invalid PrestaShop directory: {$this->psRoot}");
}
$this->log("ā Valid PrestaShop directory: {$this->psRoot}");
}
private function log($message)
{
echo $message . "\n";
}
private function backupFile($file)
{
if (file_exists($file)) {
$backupFile = $file . $this->backupSuffix;
copy($file, $backupFile);
$this->log("ā Backed up: " . basename($file));
return true;
}
return false;
}
private function createCurrencyConverterHelper()
{
$this->log("\nš Creating CurrencyConverterHelper class...");
$helperContent = '<?php
/**
* CurrencyConverter Helper
*
* This class provides functionality to convert BGN prices to EUR
* for email templates display purposes.
*/
class CurrencyConverterHelper
{
// Exchange rate: 1 BGN = 0.5110789 EUR (1 / 1.95583)
const BGN_TO_EUR_RATE = 0.5110789;
/**
* Convert BGN amount to EUR
*
* @param float $bgn_amount Amount in BGN
* @return float Amount in EUR
*/
public static function convertBgnToEur($bgn_amount)
{
return (float) $bgn_amount * self::BGN_TO_EUR_RATE;
}
/**
* Format BGN amount with EUR equivalent
*
* @param float $bgn_amount Amount in BGN
* @param string $bgn_symbol BGN currency symbol (default: \'лв.\')
* @param string $eur_symbol EUR currency symbol (default: \'ā¬\')
* @return string Formatted string with both currencies
*/
public static function formatBgnWithEur($bgn_amount, $bgn_symbol = \'лв.\', $eur_symbol = \'ā¬\')
{
$eur_amount = self::convertBgnToEur($bgn_amount);
// Format the amounts with proper decimals
$bgn_formatted = number_format($bgn_amount, 2, \'.\', \'\');
$eur_formatted = number_format($eur_amount, 2, \'.\', \'\');
return $bgn_formatted . \' \' . $bgn_symbol . \' (\' . $eur_formatted . \' \' . $eur_symbol . \')\';
}
/**
* Format price using PrestaShop\'s locale formatter and add EUR equivalent
*
* @param float $bgn_amount Amount in BGN
* @param Context $context PrestaShop context
* @return string Formatted string with both currencies
*/
public static function formatPriceWithEur($bgn_amount, $context = null)
{
if (!$context) {
$context = Context::getContext();
}
$eur_amount = self::convertBgnToEur($bgn_amount);
// Format BGN using PrestaShop\'s formatter
$bgn_formatted = Tools::getContextLocale($context)->formatPrice($bgn_amount, $context->currency->iso_code);
// Format EUR amount
$eur_formatted = number_format($eur_amount, 2, \'.\', \'\') . \' ā¬\';
return $bgn_formatted . \' (\' . $eur_formatted . \')\';
}
}';
$helperFile = $this->psRoot . '/classes/CurrencyConverterHelper.php';
file_put_contents($helperFile, $helperContent);
$this->log("ā Created: classes/CurrencyConverterHelper.php");
}
private function updatePaymentModule()
{
$this->log("\nš§ Updating PaymentModule...");
$paymentModule = $this->psRoot . '/classes/PaymentModule.php';
if (file_exists($paymentModule)) {
$this->backupFile($paymentModule);
$content = file_get_contents($paymentModule);
// Update all the formatPrice calls to use CurrencyConverterHelper
$replacements = [
'Tools::getContextLocale($this->context)->formatPrice($order->total_paid, $this->context->currency->iso_code)' =>
'CurrencyConverterHelper::formatPriceWithEur($order->total_paid, $this->context)',
'Tools::getContextLocale($this->context)->formatPrice(Product::getTaxCalculationMethod() == PS_TAX_EXC ? $order->total_products : $order->total_products_wt, $this->context->currency->iso_code)' =>
'CurrencyConverterHelper::formatPriceWithEur(Product::getTaxCalculationMethod() == PS_TAX_EXC ? $order->total_products : $order->total_products_wt, $this->context)',
'Tools::getContextLocale($this->context)->formatPrice($order->total_discounts, $this->context->currency->iso_code)' =>
'CurrencyConverterHelper::formatPriceWithEur($order->total_discounts, $this->context)',
'Tools::getContextLocale($this->context)->formatPrice($order->total_shipping, $this->context->currency->iso_code)' =>
'CurrencyConverterHelper::formatPriceWithEur($order->total_shipping, $this->context)',
'Tools::getContextLocale($this->context)->formatPrice($order->total_shipping_tax_excl, $this->context->currency->iso_code)' =>
'CurrencyConverterHelper::formatPriceWithEur($order->total_shipping_tax_excl, $this->context)',
'Tools::getContextLocale($this->context)->formatPrice($order->total_shipping_tax_incl, $this->context->currency->iso_code)' =>
'CurrencyConverterHelper::formatPriceWithEur($order->total_shipping_tax_incl, $this->context)',
'Tools::getContextLocale($this->context)->formatPrice($order->total_wrapping, $this->context->currency->iso_code)' =>
'CurrencyConverterHelper::formatPriceWithEur($order->total_wrapping, $this->context)',
'Tools::getContextLocale($this->context)->formatPrice(($order->total_paid_tax_incl - $order->total_paid_tax_excl), $this->context->currency->iso_code)' =>
'CurrencyConverterHelper::formatPriceWithEur(($order->total_paid_tax_incl - $order->total_paid_tax_excl), $this->context)'
];
foreach ($replacements as $search => $replace) {
$content = str_replace($search, $replace, $content);
}
file_put_contents($paymentModule, $content);
$this->log("ā Updated: classes/PaymentModule.php");
} else {
$this->log("ā PaymentModule not found, skipping...");
}
}
private function updateEmailAlertsModule()
{
$this->log("\nš§ Updating ps_emailalerts module...");
$emailAlerts = $this->psRoot . '/modules/ps_emailalerts/ps_emailalerts.php';
if (file_exists($emailAlerts)) {
$this->backupFile($emailAlerts);
$content = file_get_contents($emailAlerts);
// Update email alerts with EUR conversions
$replacements = [
"'{total_paid}' => \$contextLocale->formatPrice(\$order->total_paid, \$currency->iso_code)" =>
"'{total_paid}' => class_exists('CurrencyConverterHelper') ? CurrencyConverterHelper::formatPriceWithEur(\$order->total_paid, Context::getContext()) : \$contextLocale->formatPrice(\$order->total_paid, \$currency->iso_code)",
"'{total_products}' => \$contextLocale->formatPrice(\$total_products, \$currency->iso_code)" =>
"'{total_products}' => class_exists('CurrencyConverterHelper') ? CurrencyConverterHelper::formatPriceWithEur(\$total_products, Context::getContext()) : \$contextLocale->formatPrice(\$total_products, \$currency->iso_code)",
"'{total_discounts}' => \$contextLocale->formatPrice(\$order->total_discounts, \$currency->iso_code)" =>
"'{total_discounts}' => class_exists('CurrencyConverterHelper') ? CurrencyConverterHelper::formatPriceWithEur(\$order->total_discounts, Context::getContext()) : \$contextLocale->formatPrice(\$order->total_discounts, \$currency->iso_code)",
"'{total_shipping}' => \$contextLocale->formatPrice(\$order->total_shipping, \$currency->iso_code)" =>
"'{total_shipping}' => class_exists('CurrencyConverterHelper') ? CurrencyConverterHelper::formatPriceWithEur(\$order->total_shipping, Context::getContext()) : \$contextLocale->formatPrice(\$order->total_shipping, \$currency->iso_code)",
"'{total_shipping_tax_excl}' => \$contextLocale->formatPrice(\$order->total_shipping_tax_excl, \$currency->iso_code)" =>
"'{total_shipping_tax_excl}' => class_exists('CurrencyConverterHelper') ? CurrencyConverterHelper::formatPriceWithEur(\$order->total_shipping_tax_excl, Context::getContext()) : \$contextLocale->formatPrice(\$order->total_shipping_tax_excl, \$currency->iso_code)"
];
foreach ($replacements as $search => $replace) {
$content = str_replace($search, $replace, $content);
}
file_put_contents($emailAlerts, $content);
$this->log("ā Updated: modules/ps_emailalerts/ps_emailalerts.php");
} else {
$this->log("ā ps_emailalerts module not found, skipping...");
}
}
private function updateEmailPartialTemplates()
{
$this->log("\nš§ Updating email partial templates...");
// Update product list template (HTML)
$productListTpl = $this->psRoot . '/mails/_partials/order_conf_product_list.tpl';
if (file_exists($productListTpl)) {
$this->backupFile($productListTpl);
$content = file_get_contents($productListTpl);
// Add EUR conversion for unit prices and total prices
$content = str_replace(
' {$product[\'unit_price\']}',
' {if class_exists(\'CurrencyConverterHelper\')}
{assign var="bgn_price" value=$product[\'unit_price\']|regex_replace:\'/[^0-9.,]/\' :\'\'}
{$product[\'unit_price\']} ({($bgn_price * 0.5110789)|string_format:"%.2f"} ā¬)
{else}
{$product[\'unit_price\']}
{/if}',
$content
);
$content = str_replace(
' {$product[\'price\']}',
' {if class_exists(\'CurrencyConverterHelper\')}
{assign var="bgn_price" value=$product[\'price\']|regex_replace:\'/[^0-9.,]/\' :\'\'}
{$product[\'price\']} ({($bgn_price * 0.5110789)|string_format:"%.2f"} ā¬)
{else}
{$product[\'price\']}
{/if}',
$content
);
file_put_contents($productListTpl, $content);
$this->log("ā Updated: mails/_partials/order_conf_product_list.tpl");
}
// Update product list template (Text)
$productListTxt = $this->psRoot . '/mails/_partials/order_conf_product_list.txt';
if (file_exists($productListTxt)) {
$this->backupFile($productListTxt);
$txtContent = '{foreach $list as $product}
{$product[\'reference\']}
{$product[\'name\']}
{assign var="bgn_price" value=$product[\'price\']|regex_replace:\'/[^0-9.,]/\' :\'\'}
{$product[\'price\']}{if $bgn_price > 0} ({($bgn_price * 0.5110789)|string_format:"%.2f"} ā¬){/if}
{capture "productPriceBlock"}{hook h=\'displayProductPriceBlock\' product=$product type="unit_price"}{/capture}{$smarty.capture.productPriceBlock|strip_tags|trim}
{$product[\'quantity\']}
{assign var="bgn_total_price" value=$product[\'price\']|regex_replace:\'/[^0-9.,]/\' :\'\'}
{$product[\'price\']}{if $bgn_total_price > 0} ({($bgn_total_price * 0.5110789)|string_format:"%.2f"} ā¬){/if}
{foreach $product[\'customization\'] as $customization}
{$customization[\'customization_text\']}
{if count($product[\'customization\']) > 1}
{$customization[\'customization_quantity\']}
{/if}
{/foreach}
{/foreach}';
file_put_contents($productListTxt, $txtContent);
$this->log("ā Updated: mails/_partials/order_conf_product_list.txt");
}
// Update cart rules template (HTML)
$cartRulesTpl = $this->psRoot . '/mails/_partials/order_conf_cart_rules.tpl';
if (file_exists($cartRulesTpl)) {
$this->backupFile($cartRulesTpl);
$content = file_get_contents($cartRulesTpl);
$content = str_replace(
' {$cart_rule[\'voucher_reduction\']}',
' {assign var="bgn_reduction" value=$cart_rule[\'voucher_reduction\']|regex_replace:\'/[^0-9.,]/\' :\'\'}
{$cart_rule[\'voucher_reduction\']}{if $bgn_reduction > 0} ({($bgn_reduction * 0.5110789)|string_format:"%.2f"} ā¬){/if}',
$content
);
file_put_contents($cartRulesTpl, $content);
$this->log("ā Updated: mails/_partials/order_conf_cart_rules.tpl");
}
// Update cart rules template (Text)
$cartRulesTxt = $this->psRoot . '/mails/_partials/order_conf_cart_rules.txt';
if (file_exists($cartRulesTxt)) {
$this->backupFile($cartRulesTxt);
$txtContent = '{foreach $list as $cart_rule}
{assign var="bgn_reduction" value=$cart_rule[\'voucher_reduction\']|regex_replace:\'/[^0-9.,]/\' :\'\'}
{$cart_rule[\'voucher_name\']} {$cart_rule[\'voucher_reduction\']}{if $bgn_reduction > 0} ({($bgn_reduction * 0.5110789)|string_format:"%.2f"} ā¬){/if}
{/foreach}';
file_put_contents($cartRulesTxt, $txtContent);
$this->log("ā Updated: mails/_partials/order_conf_cart_rules.txt");
}
}
private function createTestScript()
{
$this->log("\nš§Ŗ Creating test script...");
$testContent = '<?php
/**
* Simple Currency Converter Test
* Tests the CurrencyConverterHelper class without requiring full PrestaShop initialization
*/
// Include the helper class directly
require_once(dirname(__FILE__) . \'/classes/CurrencyConverterHelper.php\');
echo "Testing CurrencyConverterHelper class...\\n\\n";
try {
// Test basic conversion
$testAmount = 195.58;
$eurAmount = CurrencyConverterHelper::convertBgnToEur($testAmount);
echo "ā Basic conversion test:\\n";
echo " {$testAmount} BGN = {$eurAmount} EUR\\n\\n";
// Test formatting
$formatted = CurrencyConverterHelper::formatBgnWithEur($testAmount);
echo "ā Formatting test:\\n";
echo " Input: {$testAmount} BGN\\n";
echo " Output: {$formatted}\\n\\n";
// Test various amounts
$testAmounts = [100.00, 50.25, 1000.99, 0.01];
echo "ā Multiple amount tests:\\n";
foreach ($testAmounts as $amount) {
$eur = CurrencyConverterHelper::convertBgnToEur($amount);
$formatted = CurrencyConverterHelper::formatBgnWithEur($amount);
echo " {$amount} BGN ā {$formatted}\\n";
}
echo "\\nā All tests passed! The CurrencyConverterHelper is working correctly.\\n";
echo "\\nExchange rate used: 1 BGN = " . CurrencyConverterHelper::BGN_TO_EUR_RATE . " EUR\\n";
echo "(Based on: 1 BGN = 1 / 1.95583 EUR)\\n";
} catch (Exception $e) {
echo "ā Error: " . $e->getMessage() . "\\n";
}';
$testFile = $this->psRoot . '/test_currency_converter.php';
file_put_contents($testFile, $testContent);
$this->log("ā Created: test_currency_converter.php");
}
private function runTest()
{
$this->log("\nš§Ŗ Testing currency converter...");
$testFile = $this->psRoot . '/test_currency_converter.php';
$output = shell_exec("cd {$this->psRoot} && php test_currency_converter.php 2>&1");
if (strpos($output, 'ā All tests passed!') !== false) {
$this->log("ā
Currency converter test passed!");
} else {
$this->log("ā Currency converter test failed - output:");
$this->log($output);
}
}
private function clearCache()
{
$this->log("\nš§¹ Attempting to clear PrestaShop cache...");
$cacheDirs = [
$this->psRoot . '/var/cache',
$this->psRoot . '/cache'
];
foreach ($cacheDirs as $cacheDir) {
if (is_dir($cacheDir)) {
$this->clearDirectory($cacheDir);
$this->log("ā Cleared: " . basename($cacheDir) . " directory");
}
}
}
private function clearDirectory($dir)
{
$files = array_diff(scandir($dir), array('.', '..'));
foreach ($files as $file) {
$path = $dir . '/' . $file;
if (is_dir($path)) {
$this->clearDirectory($path);
rmdir($path);
} else {
unlink($path);
}
}
}
public function deploy()
{
echo "==========================================\n";
echo "PrestaShop BGN to EUR Currency Converter\n";
echo "Email Template Deployment Script (PHP)\n";
echo "==========================================\n\n";
echo "This script will:\n";
echo " 1. Create backups of all modified files\n";
echo " 2. Add CurrencyConverterHelper class\n";
echo " 3. Update PaymentModule to include EUR prices\n";
echo " 4. Update ps_emailalerts module\n";
echo " 5. Update email partial templates\n";
echo " 6. Test the implementation\n\n";
echo "Continue? (y/N): ";
$handle = fopen("php://stdin", "r");
$confirm = trim(fgets($handle));
fclose($handle);
if (strtolower($confirm) !== 'y' && strtolower($confirm) !== 'yes') {
$this->log("Deployment cancelled.");
return;
}
try {
$this->createCurrencyConverterHelper();
$this->updatePaymentModule();
$this->updateEmailAlertsModule();
$this->updateEmailPartialTemplates();
$this->createTestScript();
$this->runTest();
$this->clearCache();
echo "\n==========================================\n";
echo "ā
DEPLOYMENT COMPLETED SUCCESSFULLY!\n";
echo "==========================================\n\n";
echo "Summary of changes:\n";
echo " ā Created CurrencyConverterHelper class\n";
echo " ā Updated PaymentModule for EUR conversions\n";
echo " ā Updated ps_emailalerts module\n";
echo " ā Updated email partial templates\n";
echo " ā Created test script\n";
echo " ā Cleared PrestaShop cache\n\n";
echo "Exchange rate applied: 1 BGN = 1.95583 EUR\n\n";
echo "All email templates will now show:\n";
echo " ⢠Order totals: 195.58 лв. (99.96 ā¬)\n";
echo " ⢠Product prices: 25.00 лв. (12.78 ā¬)\n";
echo " ⢠Discounts: -5.00 лв. (-2.56 ā¬)\n\n";
echo "Test the implementation:\n";
echo " cd {$this->psRoot} && php test_currency_converter.php\n\n";
echo "Backup files created with timestamp suffix{$this->backupSuffix}\n\n";
$this->log("ā
Deployment completed successfully!");
} catch (Exception $e) {
$this->log("ā Error during deployment: " . $e->getMessage());
exit(1);
}
}
}
// Main execution
try {
$psRoot = isset($argv[1]) ? $argv[1] : null;
$deployer = new CurrencyConversionDeployer($psRoot);
$deployer->deploy();
} catch (Exception $e) {
echo "ā Fatal error: " . $e->getMessage() . "\n";
exit(1);
}