diff --git a/README.md b/README.md index d95bf20..49010e4 100644 --- a/README.md +++ b/README.md @@ -5,10 +5,11 @@ ### Was kann das Modul? Dieses Modul stellt 2 Aufrufe bereit, die in Standardkonstellationen die MwSt.-Sätze anpasst, die in Deutschland zum 01.07.20 und zum 01.01.2021 geändert werden (Bestandteil des beschlossenen Corona-Konjunkturpaketes). +Weiterhin können über 2 weitere Aufrufe die Artikelpreise passend reduziert bzw. erhöht werden. Die Anpassung kann über entsprechende Cronjobs zeitgesteuert zum Stichtermin ausgeführt werden, ohne dass hierfür Ihre Anwesenheit erforderlich ist. -Die Scripte ändern: +Die Steuerscripte ändern: - den im Shop eingestellten allgemeinen Steuersatz - an den Artikeln hinterlegte spezielle Steuersätze @@ -16,6 +17,19 @@ Die Scripte ändern: - von 7% zu 5% - sowie später auch zurück +Die Steuerscripte ändern: +- den Standardpreis der Artikel +- den UVP-Preis der Artikel +- den Varminpreis an Elternartikeln (der Variantenpreis selbst wird schon mit dem Standardpreis geändert) +- den Varmaxpreis an Elternartikeln (der Variantenpreis selbst wird schon mit dem Standardpreis geändert) + +- von 19% zu 16% und +- von 7% zu 5% +- sowie später auch zurück + +Berücksichtigt werden artikelabhängige Steuersätze sowie auch der generelle Steuersatz des Shops. Bei den Varianten-MinPreisen und Max-Preisen wird der Steuersatz des Elternartikels zugrunde gelegt. +Weicht der Steuersatz der Varianten vom Elternartikel ab, muss dies manuell nachgearbeitet werden. + Bei Multishopinstallationen (Enterprise Edition) können die zu aktualisierenden Subshops definiert werden. Die Scripte prüfen anhand der Systemzeit mit kleinen Toleranzen (+/-3 Tage um das jeweilige Umstellungsdatum), ob die Veränderung ausgeführt werden darf. Damit wird verhindert, dass ein versehentliches Auslösen zur falschen Shopkonfiguration führt. @@ -28,10 +42,14 @@ Weiterhin werden auch die absoluten Artikelpreise und Berechnungswege nicht ange - Werden Artikelpreise brutto gepflegt und angezeigt, werden danach weiterhin die bisherigen Preise verwendet, jedoch mit geändertem Steuersatz. - Werden Artikelpreise netto gepflegt und brutto angezeigt, ändern sich die daraus errechneten Bruttopreise. -Passen Sie die Artikelpreise danach ggf. an. Beachten Sie hierbei speziell die Artikel, die einer Preisbindung unterliegen. +Für die Preisanpassungen stehen Ihnen die entsprechenden Scripte im Modul zur Verfügung. + +Beachten Sie bei der Preisanpassung speziell die Artikel, die einer Preisbindung unterliegen. Artikel, die von der Steuersenkung ausgenommen sind (z.B. Tabakwaren) können hierbei nicht berücksichtigt werden und erfordern eine manuelle Nachbearbeitung. +Die Preise werden immer auf dem im Shop vorliegenden Preis angewandt. Hierbei kann es durchaus zu Rundungsungenauigkeiten kommen. + Gibt es in Ihrem Shop reguläre Steuersätze mit 16% oder 5%, werden diese beim Zurücksetzen ebenfalls auf 19% bzw. 7% angehoben. Eine Unterscheidung, welcher Steuersatz vorab reduziert wurde, gibt es nicht. Diese Anpassung muss dann manuell durchgeführt werden. ## Systemanforderung @@ -63,6 +81,22 @@ Richten Sie einen zweiten Cronjob ein, der idealerweise am 01.01.2021 um 00:00 f [ Shoppfad ]/_taxRates/bin/raiseTaxRate ``` +Nutzen Sie für die Preisanpassungen die folgenden Scripte als Cronjob zum passenden Moment: + +um die Artikelpreise zu senken:: + +``` +[ Shoppfad ]/vendor/bin/reduceArticlePrices +``` + +um die Artikelpreise zurückzusetzen: + +``` +[ Shoppfad ]/vendor/bin/raiseArtikelPrices +``` + +Führen Sie die Preisanpassungsscripte nur ein einziges Mal aus, da die Preise sonst mehrfach gesenkt / erhöht werden. + Bei Fragen zur Einrichtung der Cronjobs kontaktieren Sie bitte Ihren Hostingprovider. Prüfen Sie nach Ausführung der Scripte Ihren Shop bitte zeitnah auf richtige Funktion. @@ -87,6 +121,8 @@ Nach heutigem Stand werden die Scripte nach dem Zurücksetzen der Steuersätze n - falsche Konvertierung der ShopId entfernt - 1.0.2 - PHP-Versionshinweis angepasst +- unreleased + - Preisanpassungsscripte eingefügt ## Support diff --git a/copy_this/_taxRates/Models/articlePricesAbstract.php b/copy_this/_taxRates/Models/articlePricesAbstract.php new file mode 100644 index 0000000..a542d9a --- /dev/null +++ b/copy_this/_taxRates/Models/articlePricesAbstract.php @@ -0,0 +1,151 @@ + + * @link http://www.oxidmodule.com + */ + +namespace D3\TaxRatesAdjustment\Models; + +use D3\ModCfg\Application\Model\d3database; +use OxidEsales\Eshop\Application\Model\Shop; +use OxidEsales\Eshop\Core\Config; +use OxidEsales\Eshop\Core\DatabaseProvider; + +abstract class articlePricesAbstract extends genericAbstract +{ + public $baseQueriesDefaultTax = [ + //'UPDATE oxarticles SET oxprice = (oxprice / 1.19 * 1.16) WHERE oxshopid = 'oxbaseshop' AND (oxvat IS NULL);', + // default prices + 'UPDATE oxarticles SET oxprice = (oxprice / :oldTaxPercent * :newTaxPercent) WHERE oxshopid = :shopid AND (oxvat IS NULL)', + // recommended retail price + 'UPDATE oxarticles SET oxtprice = (oxtprice / :oldTaxPercent * :newTaxPercent) WHERE oxshopid = :shopid AND (oxvat IS NULL)', + + // varminprices + 'UPDATE oxarticles SET oxvarminprice = (oxvarminprice / :oldTaxPercent * :newTaxPercent) WHERE oxshopid = :shopid AND (oxvat IS NULL)', + // varmaxprices + 'UPDATE oxarticles SET oxvarmaxprice = (oxvarmaxprice / :oldTaxPercent * :newTaxPercent) WHERE oxshopid = :shopid AND (oxvat IS NULL)' + ]; + + public $baseQueriesCustomTax = [ + //'UPDATE oxarticles SET oxprice = (oxprice / 1.19 * 1.16) WHERE oxshopid = 'oxbaseshop' AND (oxvat IN(16, 19));', + // default prices + 'UPDATE oxarticles SET oxprice = (oxprice / :oldTaxPercent * :newTaxPercent) WHERE oxshopid = :shopid AND (oxvat IN(:oldTaxRate, :newTaxRate))', + // recommended retail price + 'UPDATE oxarticles SET oxtprice = (oxtprice / :oldTaxPercent * :newTaxPercent) WHERE oxshopid = :shopid AND (oxvat IN(:oldTaxRate, :newTaxRate))', + + // varminprices + 'UPDATE oxarticles SET oxvarminprice = (oxvarminprice / :oldTaxPercent * :newTaxPercent) WHERE oxshopid = :shopid AND (oxvat IN(:oldTaxRate, :newTaxRate))', + // varmaxprices + 'UPDATE oxarticles SET oxvarmaxprice = (oxvarmaxprice / :oldTaxPercent * :newTaxPercent) WHERE oxshopid = :shopid AND (oxvat IN(:oldTaxRate, :newTaxRate))' + ]; + + /** + * @throws \OxidEsales\Eshop\Core\Exception\DatabaseConnectionException + * @throws \OxidEsales\Eshop\Core\Exception\DatabaseErrorException + */ + public function run() + { + if (false === $this->isInExecutableTimeRange()) { + trigger_error("script shouldn't run outside the defined time range", E_USER_WARNING); + die(); + }; + + $this->changeArticlePrices(); + } + + /** + * @throws \OxidEsales\Eshop\Core\Exception\DatabaseConnectionException + * @throws \OxidEsales\Eshop\Core\Exception\DatabaseErrorException + */ + public function changeArticlePrices() + { + $shop = new Shop(); + + // use shop list, when parameter -d is set + $opts = getopt("s:"); + + $where = isset($opts['s']) ? + "oxid IN (".implode(', ', array_map( + function ($a) {return DatabaseProvider::getDb()->quote(trim($a));}, + explode(',', $opts['s'])) + ).")" : + "1"; + + $q = "SELECT oxid FROM " . $shop->getCoreTableName() . " WHERE ".$where ; + + foreach ( DatabaseProvider::getDb( DatabaseProvider::FETCH_MODE_ASSOC )->getAll( $q ) as $record ) { + $shopId = (int) $record["oxid"]; + + $count = 0; + + $count += $this->changeSubshopArticlePricesDefaultTax($shopId); + $count += $this->changeSubshopArticlePricesCustomTax($shopId); + + echo "$count article prices in shop $shopId changed.".PHP_EOL; + } + } + + + public function changeSubshopArticlePricesDefaultTax($shopId) + { + $count = 0; + + $oCurrConfig = new Config(); + + $oldTaxRate = (int) $oCurrConfig->getConfigParam('dDefaultVAT'); + $newTaxRate = $this->rateChanges[$oldTaxRate]; + + if ($newTaxRate === null) { + $flipped = array_flip($this->rateChanges); + $oldTaxRate = $flipped[(int) $oCurrConfig->getConfigParam('dDefaultVAT')]; + $newTaxRate = $this->rateChanges[$oldTaxRate]; + } + + foreach ($this->baseQueriesDefaultTax as $query) { + $db = DatabaseProvider::getDb(DatabaseProvider::FETCH_MODE_ASSOC); + + $queryParameters = [ + 'shopid' => $shopId, + 'oldTaxRate'=> $oldTaxRate, + 'oldTaxPercent' => 1 + ($oldTaxRate / 100), + 'newTaxRate'=> $newTaxRate, + 'newTaxPercent' => 1 + ($newTaxRate / 100), + ]; + + $count += $db->execute($query, $queryParameters); + } + + return $count; + } + + public function changeSubshopArticlePricesCustomTax($shopId) + { + $count = 0; + foreach ($this->baseQueriesCustomTax as $query) { + foreach ($this->rateChanges as $oldTaxRate => $newTaxRate) { + $db = DatabaseProvider::getDb(DatabaseProvider::FETCH_MODE_ASSOC); + + $queryParameters = [ + 'shopid' => $shopId, + 'oldTaxRate'=> $oldTaxRate, + 'oldTaxPercent' => 1 + ($oldTaxRate / 100), + 'newTaxRate'=> $newTaxRate, + 'newTaxPercent' => 1 + ($newTaxRate / 100), + ]; + + $count += $db->execute($query, $queryParameters); + } + } + + return $count; + } +} \ No newline at end of file diff --git a/copy_this/_taxRates/Models/genericAbstract.php b/copy_this/_taxRates/Models/genericAbstract.php new file mode 100644 index 0000000..68fa284 --- /dev/null +++ b/copy_this/_taxRates/Models/genericAbstract.php @@ -0,0 +1,65 @@ + + * @link http://www.oxidmodule.com + */ + +namespace D3\TaxRatesAdjustment\Models; + +use OxidEsales\Eshop\Core\Config; +use OxidEsales\Eshop\Core\Registry; + +abstract class genericAbstract +{ + public $rateChanges = [ + 19 => 16, + 7 => 5 + ]; + + /** + * @return bool + */ + public function isInExecutableTimeRange() + { + // skip time check, when parameter -d is set + $opts = getopt("d"); + if (is_array($opts) && isset($opts['d'])) { + return true; + } + + list($from, $to) = $this->execPeriod; + + return (time() > strtotime($from)) && (time() < strtotime($to)); + } + + /** + * @param int $id + * + * @throws \oxConnectionException + */ + public function switchToShop($id) + { + if (Registry::getConfig()->isMall() + && $id != Registry::getConfig()->getActiveShop()->getId() + ) { + /** @var Config $oNewConf */ + $oNewConf = new Config(); + $oNewConf->setShopId($id); + $oNewConf->init(); + + Registry::getConfig()->onShopChange(); + Registry::getSession()->setVariable('actshop', $id); + Registry::getSession()->setVariable('currentadminshop', $id); + Registry::getConfig()->setShopId($id); + } + } +} \ No newline at end of file diff --git a/copy_this/_taxRates/Models/raiseArticlePrices.php b/copy_this/_taxRates/Models/raiseArticlePrices.php new file mode 100644 index 0000000..d73f4a5 --- /dev/null +++ b/copy_this/_taxRates/Models/raiseArticlePrices.php @@ -0,0 +1,21 @@ + + * @link http://www.oxidmodule.com + */ + +namespace D3\TaxRatesAdjustment\Models; + +class raiseArticlePrices extends articlePricesAbstract +{ + use raiseTrait; +} \ No newline at end of file diff --git a/copy_this/_taxRates/Models/raiseTaxRate.php b/copy_this/_taxRates/Models/raiseTaxRate.php index 23bb9c9..b4456d2 100644 --- a/copy_this/_taxRates/Models/raiseTaxRate.php +++ b/copy_this/_taxRates/Models/raiseTaxRate.php @@ -19,13 +19,5 @@ require 'taxRateAbstract.php'; class raiseTaxRate extends taxRateAbstract { - public $execPeriod = [ - '2020-12-28', - '2021-01-03', - ]; - - public function __construct() - { - $this->rateChanges = array_flip($this->rateChanges); - } + use raiseTrait; } diff --git a/copy_this/_taxRates/Models/raiseTrait.php b/copy_this/_taxRates/Models/raiseTrait.php new file mode 100644 index 0000000..03f93b2 --- /dev/null +++ b/copy_this/_taxRates/Models/raiseTrait.php @@ -0,0 +1,29 @@ + + * @link http://www.oxidmodule.com + */ + +namespace D3\TaxRatesAdjustment\Models; + +trait raiseTrait +{ + public $execPeriod = [ + '2020-12-28', + '2021-01-03', + ]; + + public function __construct() + { + $this->rateChanges = array_flip($this->rateChanges); + } +} \ No newline at end of file diff --git a/copy_this/_taxRates/Models/reduceArticlePrices.php b/copy_this/_taxRates/Models/reduceArticlePrices.php new file mode 100644 index 0000000..019b256 --- /dev/null +++ b/copy_this/_taxRates/Models/reduceArticlePrices.php @@ -0,0 +1,21 @@ + + * @link http://www.oxidmodule.com + */ + +namespace D3\TaxRatesAdjustment\Models; + +class reduceArticlePrices extends articlePricesAbstract +{ + use reduceTrait; +} \ No newline at end of file diff --git a/copy_this/_taxRates/Models/reduceTaxRate.php b/copy_this/_taxRates/Models/reduceTaxRate.php index f68d20b..63b90a9 100644 --- a/copy_this/_taxRates/Models/reduceTaxRate.php +++ b/copy_this/_taxRates/Models/reduceTaxRate.php @@ -19,8 +19,5 @@ require 'taxRateAbstract.php'; class reduceTaxRate extends taxRateAbstract { - public $execPeriod = [ - '2020-06-27', - '2020-07-03', - ]; + use reduceTrait; } diff --git a/copy_this/_taxRates/Models/reduceTrait.php b/copy_this/_taxRates/Models/reduceTrait.php new file mode 100644 index 0000000..fbdbf9c --- /dev/null +++ b/copy_this/_taxRates/Models/reduceTrait.php @@ -0,0 +1,24 @@ + + * @link http://www.oxidmodule.com + */ + +namespace D3\TaxRatesAdjustment\Models; + +trait reduceTrait +{ + public $execPeriod = [ + '2020-06-27', + '2020-07-03', + ]; +} \ No newline at end of file diff --git a/copy_this/_taxRates/Models/taxRateAbstract.php b/copy_this/_taxRates/Models/taxRateAbstract.php index 7b44245..b6fe59f 100644 --- a/copy_this/_taxRates/Models/taxRateAbstract.php +++ b/copy_this/_taxRates/Models/taxRateAbstract.php @@ -21,34 +21,12 @@ use oxDb; use oxRegistry; use oxShop; -abstract class taxRateAbstract +abstract class taxRateAbstract extends genericAbstract { - public $execPeriod = [ - '2020-01-01', - '2019-12-31', - ]; - - public $rateChanges = [ - 19 => 16, - 7 => 5 - ]; - /** - * @return bool + * @throws \OxidEsales\Eshop\Core\Exception\DatabaseConnectionException + * @throws \OxidEsales\Eshop\Core\Exception\DatabaseErrorException */ - public function isInExecutableTimeRange() - { - // skip time check, when parameter -d is set - $opts = getopt("d"); - if (is_array($opts) && isset($opts['d'])) { - return true; - } - - list($from, $to) = $this->execPeriod; - - return (time() > strtotime($from)) && (time() < strtotime($to)); - } - public function run() { if (false === $this->isInExecutableTimeRange()) { @@ -83,28 +61,6 @@ abstract class taxRateAbstract } } - /** - * @param int $id - * - * @throws \oxConnectionException - */ - public function switchToShop($id) - { - if (oxRegistry::getConfig()->isMall() - && $id != oxRegistry::getConfig()->getActiveShop()->getId() - ) { - /** @var oxConfig $oNewConf */ - $oNewConf = new oxConfig(); - $oNewConf->setShopId($id); - $oNewConf->init(); - - oxRegistry::getConfig()->onShopChange(); - oxRegistry::getSession()->setVariable('actshop', $id); - oxRegistry::getSession()->setVariable('currentadminshop', $id); - oxRegistry::getConfig()->setShopId($id); - } - } - /** * @param int $shopId */ diff --git a/copy_this/_taxRates/bin/raiseArticlePrices b/copy_this/_taxRates/bin/raiseArticlePrices new file mode 100644 index 0000000..d7fc2d8 --- /dev/null +++ b/copy_this/_taxRates/bin/raiseArticlePrices @@ -0,0 +1,15 @@ +#!/usr/bin/env php +run(); +} catch ( \Exception $e) { + echo $e->getMessage(); +} \ No newline at end of file diff --git a/copy_this/_taxRates/bin/reduceArticlePrices b/copy_this/_taxRates/bin/reduceArticlePrices new file mode 100644 index 0000000..ae4ad5d --- /dev/null +++ b/copy_this/_taxRates/bin/reduceArticlePrices @@ -0,0 +1,15 @@ +#!/usr/bin/env php +run(); +} catch ( \Exception $e) { + echo $e->getMessage(); +} \ No newline at end of file