From cebf6024ac9f4746e002182cbeaa9eb1d7cb9b62 Mon Sep 17 00:00:00 2001 From: Daniel Seifert Date: Thu, 25 Jun 2020 11:37:04 +0200 Subject: [PATCH] add article price adjustment scripts --- Models/articlePricesAbstract.php | 151 +++++++++++++++++++++++++++++++ Models/genericAbstract.php | 65 +++++++++++++ Models/raiseArticlePrices.php | 21 +++++ Models/raiseTaxRate.php | 10 +- Models/raiseTrait.php | 29 ++++++ Models/reduceArticlePrices.php | 21 +++++ Models/reduceTaxRate.php | 5 +- Models/reduceTrait.php | 24 +++++ Models/taxRateAbstract.php | 50 +--------- README.md | 40 +++++++- bin/raiseArticlePrices | 15 +++ bin/reduceArticlePrices | 15 +++ composer.json | 6 +- 13 files changed, 386 insertions(+), 66 deletions(-) create mode 100644 Models/articlePricesAbstract.php create mode 100644 Models/genericAbstract.php create mode 100644 Models/raiseArticlePrices.php create mode 100644 Models/raiseTrait.php create mode 100644 Models/reduceArticlePrices.php create mode 100644 Models/reduceTrait.php create mode 100644 bin/raiseArticlePrices create mode 100644 bin/reduceArticlePrices diff --git a/Models/articlePricesAbstract.php b/Models/articlePricesAbstract.php new file mode 100644 index 0000000..a542d9a --- /dev/null +++ b/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/Models/genericAbstract.php b/Models/genericAbstract.php new file mode 100644 index 0000000..68fa284 --- /dev/null +++ b/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/Models/raiseArticlePrices.php b/Models/raiseArticlePrices.php new file mode 100644 index 0000000..d73f4a5 --- /dev/null +++ b/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/Models/raiseTaxRate.php b/Models/raiseTaxRate.php index b1110be..b7b396b 100644 --- a/Models/raiseTaxRate.php +++ b/Models/raiseTaxRate.php @@ -21,13 +21,5 @@ use OxidEsales\Eshop\Core\Registry; 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/Models/raiseTrait.php b/Models/raiseTrait.php new file mode 100644 index 0000000..03f93b2 --- /dev/null +++ b/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/Models/reduceArticlePrices.php b/Models/reduceArticlePrices.php new file mode 100644 index 0000000..019b256 --- /dev/null +++ b/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/Models/reduceTaxRate.php b/Models/reduceTaxRate.php index 59ea47b..e5d9a6a 100644 --- a/Models/reduceTaxRate.php +++ b/Models/reduceTaxRate.php @@ -19,8 +19,5 @@ use OxidEsales\Eshop\Core\Registry; class reduceTaxRate extends taxRateAbstract { - public $execPeriod = [ - '2020-06-27', - '2020-07-03', - ]; + use reduceTrait; } diff --git a/Models/reduceTrait.php b/Models/reduceTrait.php new file mode 100644 index 0000000..fbdbf9c --- /dev/null +++ b/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/Models/taxRateAbstract.php b/Models/taxRateAbstract.php index 230a01f..a43c4bf 100644 --- a/Models/taxRateAbstract.php +++ b/Models/taxRateAbstract.php @@ -22,34 +22,8 @@ use OxidEsales\Eshop\Core\DatabaseProvider; use OxidEsales\Eshop\Core\Exception\StandardException; use OxidEsales\Eshop\Core\Registry; -abstract class taxRateAbstract +abstract class taxRateAbstract extends genericAbstract { - public $execPeriod = [ - '2020-01-01', - '2019-12-31', - ]; - - 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)); - } - /** * @throws \OxidEsales\Eshop\Core\Exception\DatabaseConnectionException * @throws \OxidEsales\Eshop\Core\Exception\DatabaseErrorException @@ -92,28 +66,6 @@ abstract class taxRateAbstract } } - /** - * @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); - } - } - /** * @param int $shopId */ diff --git a/README.md b/README.md index 91fecff..2b92af0 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 ]/vendor/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. @@ -92,6 +126,8 @@ composer remove d3/taxratesadjustment --update-no-dev - Composer Command korrigiert - 2.1.2 - PHP-Versionshinweis angepasst +- unreleased + - Preisanpassungsscripte eingefügt ## Support diff --git a/bin/raiseArticlePrices b/bin/raiseArticlePrices new file mode 100644 index 0000000..d7fc2d8 --- /dev/null +++ b/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/bin/reduceArticlePrices b/bin/reduceArticlePrices new file mode 100644 index 0000000..ae4ad5d --- /dev/null +++ b/bin/reduceArticlePrices @@ -0,0 +1,15 @@ +#!/usr/bin/env php +run(); +} catch ( \Exception $e) { + echo $e->getMessage(); +} \ No newline at end of file diff --git a/composer.json b/composer.json index ad426ee..b9d50eb 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "d3/taxratesadjustment", - "description": "adjusts the tax rates for the German economic stimulus package 2020 / 2021", + "description": "adjusts the tax rates and article prices for the German economic stimulus package 2020 / 2021", "type": "library", "require": { "oxid-esales/oxideshop-ce": "^6.0" @@ -20,6 +20,8 @@ }, "bin": [ "bin/reduceTaxRate", - "bin/raiseTaxRate" + "bin/raiseTaxRate", + "bin/reduceArticlePrices", + "bin/raiseArticlePrices" ] }