From 1045d7dd65494eb08eabf6e15380cd42b50ad19f Mon Sep 17 00:00:00 2001 From: "dai.trinh" Date: Mon, 24 Jun 2024 15:53:43 +0700 Subject: [PATCH 01/19] 49984 total price calculator --- dist/onoffice_defaultview.min.js | 2 +- js/onoffice_defaultview.js | 36 +++++ plugin/DataView/DataDetailView.php | 43 ++++++ plugin/DataView/DataDetailViewHandler.php | 1 + plugin/EstateList.php | 40 ++++++ plugin/Field/CostCalculator.php | 135 ++++++++++++++++++ plugin/Gui/AdminPageEstateDetail.php | 13 ++ .../FormModelBuilderEstateDetailSettings.php | 32 +++++ .../InputModelOptionFactoryDetailView.php | 6 + templates.dist/estate/default_detail.php | 53 +++++++ templates.dist/onoffice-style.css | 58 ++++++++ 11 files changed, 418 insertions(+), 1 deletion(-) create mode 100644 plugin/Field/CostCalculator.php diff --git a/dist/onoffice_defaultview.min.js b/dist/onoffice_defaultview.min.js index 1cae9cc11..261b84857 100644 --- a/dist/onoffice_defaultview.min.js +++ b/dist/onoffice_defaultview.min.js @@ -1 +1 @@ -(function($){$((function(){$(document).ready((function(){$("#oo-galleryslide").slick({infinite:true,slidesToShow:1});$("#oo-similarframe").slick({infinite:true,arrows:false,dots:true,autoplay:true,slidesToShow:3,slidesToScroll:1,responsive:[{breakpoint:991,settings:{slidesToShow:2}},{breakpoint:575,settings:{slidesToShow:1}}]})}))}))})(jQuery); \ No newline at end of file +(function($){$((function(){$(document).ready((function(){$("#oo-galleryslide").slick({infinite:true,slidesToShow:1});$("#oo-similarframe").slick({infinite:true,arrows:false,dots:true,autoplay:true,slidesToShow:3,slidesToScroll:1,responsive:[{breakpoint:991,settings:{slidesToShow:2}},{breakpoint:575,settings:{slidesToShow:1}}]});if($(".oo-cost-details").length){initializeDonutChart()}function initializeDonutChart(){const colors=["#00a1e0","#3ac411","#8a56e2","#ff6f61","#ffc72c"];const data=[];let totalCost=0;$(".oo-cost-details > div").each((function(index){const value=$(this).attr("data-value");const totalCosts=$(this).attr("total-value");if(!isNaN(value)){data.push({value:value,color:colors[index]});$(this).find(".color-indicator").css("background-color",colors[index])}if(!isNaN(totalCosts))totalCost=totalCosts}));let start=0;let gradientString="conic-gradient(";data.forEach((item=>{const percentage=item.value/totalCost*100;const end=start+percentage;gradientString+=`${item.color} ${start.toFixed(2)}% ${end.toFixed(2)}%, `;start=end}));gradientString=gradientString.slice(0,-2)+")";$(".oo-donut-chart").css("background",gradientString)}}))}))})(jQuery); \ No newline at end of file diff --git a/js/onoffice_defaultview.js b/js/onoffice_defaultview.js index d7b489e7f..08f8951a0 100644 --- a/js/onoffice_defaultview.js +++ b/js/onoffice_defaultview.js @@ -25,6 +25,42 @@ } }] }); + + if ($('.oo-cost-details').length) { + initializeDonutChart(); + } + + function initializeDonutChart() { + const colors = ['#00a1e0', '#3ac411', '#8a56e2', '#ff6f61', '#ffc72c']; + const data = []; + let totalCost = 0; + + $('.oo-cost-details > div').each(function(index) { + const value = $(this).attr('data-value'); + const totalCosts = $(this).attr('total-value'); + if (!isNaN(value)) { + data.push({ + value: value, + color: colors[index] + }); + $(this).find('.color-indicator').css('background-color', colors[index]); + } + if (!isNaN(totalCosts)) + totalCost = totalCosts; + }); + + let start = 0; + let gradientString = 'conic-gradient('; + data.forEach((item) => { + const percentage = (item.value / totalCost) * 100; + const end = start + percentage; + gradientString += `${item.color} ${start.toFixed(2)}% ${end.toFixed(2)}%, `; + start = end; + }); + + gradientString = gradientString.slice(0, -2) + ')'; + $('.oo-donut-chart').css('background', gradientString); + } }); }); })(jQuery); \ No newline at end of file diff --git a/plugin/DataView/DataDetailView.php b/plugin/DataView/DataDetailView.php index d884825f6..ec2625e2e 100644 --- a/plugin/DataView/DataDetailView.php +++ b/plugin/DataView/DataDetailView.php @@ -56,6 +56,15 @@ class DataDetailView /** */ const FIELD_PRICE_ON_REQUEST = 'show_price_on_request'; + /** */ + const FIELD_TOTAL_COSTS_CALCULATOR = 'show_total_costs_calculator'; + + /** */ + const NOTARY_FEES = 1.5; + + /** */ + const LAND_REGISTER_ENTRY = 0.5; + /** @var string[] */ private $_fields = [ 'objekttitel', @@ -167,6 +176,9 @@ class DataDetailView /** @var bool */ private $_showPriceOnRequest = false; + /** @var bool */ + private $_showTotalCostsCalculator = false; + /** @var string[] */ private $_priceFields = [ 'kaufpreis', @@ -182,6 +194,26 @@ class DataDetailView 'mietpreis_pro_qm', ]; + /** @var string[] */ + private $_propertyTransferTax = [ + 'Baden-Württemberg' => 5, + 'Bayern' => 3.5, + 'Berlin' => 6, + 'Brandenburg' => 6.5, + 'Bremen' => 5, + 'Hamburg' => 5.5, + 'Hessen' => 6, + 'Mecklenburg-Vorpommern' => 6, + 'Niedersachsen' => 5, + 'Nordrhein-Westfalen' => 6.5, + 'Rheinland-Pfalz' => 5, + 'Saarland' => 6.5, + 'Sachsen' => 5.5, + 'Sachsen-Anhalt' => 5, + 'Schleswig-Holstein' => 6.5, + 'Thüringen' => 5 + ]; + /** * */ @@ -369,6 +401,9 @@ public function getShowPriceOnRequest(): bool public function setShowPriceOnRequest(bool $priceOnRequest) { $this->_showPriceOnRequest = $priceOnRequest; } + /** @return array */ + public function getPropertyTransferTax(): array + { return $this->_propertyTransferTax; } /** * @return array @@ -377,4 +412,12 @@ public function getListFieldsShowPriceOnRequest(): array { return $this->_priceFields; } + + /** @return bool */ + public function getShowTotalCostsCalculator(): bool + { return $this->_showTotalCostsCalculator; } + + /** @param bool $costCalculator */ + public function setShowTotalCostsCalculator(bool $costCalculator) + { $this->_showTotalCostsCalculator = $costCalculator; } } diff --git a/plugin/DataView/DataDetailViewHandler.php b/plugin/DataView/DataDetailViewHandler.php index fdc646397..b191d6d8c 100644 --- a/plugin/DataView/DataDetailViewHandler.php +++ b/plugin/DataView/DataDetailViewHandler.php @@ -118,6 +118,7 @@ public function createDetailViewByValues(array $row): DataDetailView $pDataDetailView->setShowStatus($row['show_status'] ?? false); $pDataDetailView->setCustomLabels($row[DataDetailView::FIELD_CUSTOM_LABEL] ?? []); $pDataDetailView->setShowPriceOnRequest($row[DataDetailView::FIELD_PRICE_ON_REQUEST] ?? false); + $pDataDetailView->setShowTotalCostsCalculator($row[DataDetailView::FIELD_TOTAL_COSTS_CALCULATOR] ?? false); return $pDataDetailView; } } \ No newline at end of file diff --git a/plugin/EstateList.php b/plugin/EstateList.php index ace6e20a2..23cd6ec20 100644 --- a/plugin/EstateList.php +++ b/plugin/EstateList.php @@ -58,6 +58,7 @@ use onOffice\WPlugin\WP\WPPluginChecker; use onOffice\WPlugin\Field\Collection\FieldsCollectionBuilderShort; use onOffice\WPlugin\Field\FieldParkingLot; +use onOffice\WPlugin\Field\CostCalculator; class EstateList implements EstateListBase @@ -111,6 +112,9 @@ class EstateList /** @var Redirector */ private $_redirectIfOldUrl; + /** @var array */ + private $_totalCosts = []; + /** * @param DataView $pDataView * @param EstateListEnvironment $pEnvironment @@ -218,6 +222,12 @@ private function loadRecords(int $currentPage) $estateParametersRaw['data'] = $this->_pEnvironment->getEstateStatusLabel()->getFieldsByPrio(); $estateParametersRaw['data'] []= 'vermarktungsart'; $estateParametersRaw['data'] []= 'preisAufAnfrage'; + + if ($this->_pDataView instanceof DataDetailView) { + $data = ['kaufpreis', 'aussen_courtage', 'bundesland', 'waehrung']; + $estateParametersRaw['data'] = array_merge($estateParametersRaw['data'], $data); + } + $pApiClientActionRawValues = clone $this->_pApiClientAction; $pApiClientActionRawValues->setParameters($estateParametersRaw); $pApiClientActionRawValues->addRequestToQueue()->sendRequests(); @@ -492,6 +502,14 @@ public function estateIterator($modifier = EstateViewFieldModifierTypes::MODIFIE $recordModified['vermarktungsstatus'] = $pEstateStatusLabel->getLabel($recordRaw); } + if ($this->_pDataView instanceof DataDetailView && $this->_pDataView->getShowTotalCostsCalculator()) { + $externalCommission = $this->getExternalCommission($recordRaw); + if (!empty((float) $recordRaw['kaufpreis']) && !empty($recordRaw['bundesland']) && !empty($externalCommission)) { + $costCalculator = new CostCalculator($this->getDataView(), $recordRaw['waehrung'] ?? 'EUR', $externalCommission); + $this->_totalCosts = $costCalculator->getTotalCosts($recordRaw); + } + } + if ($modifier === EstateViewFieldModifierTypes::MODIFIER_TYPE_MAP && $this->_pDataView instanceof DataListView) { $recordModified['showGoogleMap'] = $this->getShowMapConfig(); } @@ -536,6 +554,28 @@ public function estateIterator($modifier = EstateViewFieldModifierTypes::MODIFIE return $recordModified; } + /** + * @param array $recordRaw + * @return float + */ + private function getExternalCommission(array $recordRaw): float + { + if (isset($recordRaw['aussen_courtage']) && !empty($recordRaw['aussen_courtage'])){ + if (preg_match('/(\d+,\d+)\s*%/', $recordRaw['aussen_courtage'], $matches)) { + return floatval(str_replace(',', '.', $matches[1])); + } + } + return 0; + } + + /** + * @return array + */ + public function getTotalCosts(): array + { + return $this->_totalCosts; + } + /** * @param ArrayContainerEscape $recordModified * @param string $field diff --git a/plugin/Field/CostCalculator.php b/plugin/Field/CostCalculator.php new file mode 100644 index 000000000..c6882e347 --- /dev/null +++ b/plugin/Field/CostCalculator.php @@ -0,0 +1,135 @@ +. + */ + +namespace onOffice\WPlugin\Field; + +use Exception; +use NumberFormatter; +use onOffice\WPlugin\Language; +use onOffice\WPlugin\DataView\DataDetailView; +use onOffice\WPlugin\DataView\DataView; + +class CostCalculator +{ + /** @var DataView */ + private $_pDataView; + + /** @var string */ + private $_currencyCode; + + /** @var float */ + private $_externalCommission; + + /** + * @param DataView $dataView + * @param string $currencyCode + * @param float $externalCommission + */ + public function __construct(DataView $dataView, string $currencyCode, float $externalCommission) + { + $this->_pDataView = $dataView; + $this->_currencyCode = $currencyCode; + $this->_externalCommission = $externalCommission; + } + + /** + * @param array $data + * @return array + */ + public function getTotalCosts(array $data): array + { + $language = new Language(); + $locale = !empty($language->getLocale()) ? $language->getLocale() : 'de_DE'; + + $format = new NumberFormatter($locale, NumberFormatter::CURRENCY); + $costDetails = $this->calculateRawCosts($data); + + return $this->formatCosts($format, $costDetails); + } + + /** + * @param array $data + * @return array + */ + private function calculateRawCosts(array $data): array + { + $purchasePrice = $data['kaufpreis']; + $propertyTransferTax = $this->_pDataView->getPropertyTransferTax()[$data['bundesland']]; + $costsRate = [ + 'bundesland' => $propertyTransferTax, + 'aussen_courtage' => $this->_externalCommission, + 'notary_fees' => DataDetailView::NOTARY_FEES, + 'land_register_entry' => DataDetailView::LAND_REGISTER_ENTRY + ]; + + $costDetails = ['kaufpreis' => ['raw' => $purchasePrice]]; + $totalCosts = 0; + + foreach ($costsRate as $key => $value) { + $cost = $this->calculateCostByRate($purchasePrice, $value); + $costDetails[$key] = ['raw' => $cost]; + $totalCosts += $cost; + } + + $costDetails['total_costs'] = ['raw' => $purchasePrice + $totalCosts]; + + return $costDetails; + } + + /** + * @param float $price + * @param float $rate + * @return float + */ + private function calculateCostByRate(float $price, float $rate): float + { + return round($price * $rate / 100); + } + + /** + * @param NumberFormatter $format + * @param array $costDetails + * @return array + */ + private function formatCosts(NumberFormatter $format, array $costDetails): array + { + foreach ($costDetails as $key => $value) { + if (isset($value['raw'])) { + $costDetails[$key]['default'] = $this->formatCurrency($format, $value['raw']); + } + } + + return $costDetails; + } + + /** + * @param NumberFormatter $format + * @param float $amount + * @return string + */ + private function formatCurrency(NumberFormatter $format, float $amount): string + { + if (intval($amount) == $amount) { + $format->setAttribute(NumberFormatter::MIN_SIGNIFICANT_DIGITS, 0); + } + + return str_replace("\xc2\xa0", " ", $format->formatCurrency($amount, $this->_currencyCode)); + } +} \ No newline at end of file diff --git a/plugin/Gui/AdminPageEstateDetail.php b/plugin/Gui/AdminPageEstateDetail.php index 0d1596fac..37428c158 100644 --- a/plugin/Gui/AdminPageEstateDetail.php +++ b/plugin/Gui/AdminPageEstateDetail.php @@ -110,6 +110,9 @@ class AdminPageEstateDetail /** */ const FORM_VIEW_SEARCH_FIELD_FOR_FIELD_LISTS_CONFIG = 'viewSearchFieldForFieldListsConfig'; + /** */ + const FORM_VIEW_TOTAL_COSTS_CALCULATOR = 'viewtotalcostscalculator'; + /** * */ @@ -257,6 +260,8 @@ private function generateMetaBoxes() $pFormDocumentTypes = $this->getFormModelByGroupSlug(self::FORM_VIEW_ADDITIONAL_MEDIA); $this->createMetaBoxByForm($pFormDocumentTypes, 'side'); + $pFormTotalCostsCalculator = $this->getFormModelByGroupSlug(self::FORM_VIEW_TOTAL_COSTS_CALCULATOR); + $this->createMetaBoxByForm($pFormTotalCostsCalculator, 'normal'); } /** @@ -330,6 +335,14 @@ protected function buildForms() $pFormModelAccessControl->addInputModel( $pInputModelAccessControl ); $this->addFormModel( $pFormModelAccessControl ); + $pInputModelTotalCostsCalculator = $pFormModelBuilder->createInputModelTotalCostsCalculator(); + $pFormModelTotalCostsCalculator = new FormModel(); + $pFormModelTotalCostsCalculator->setPageSlug($this->getPageSlug()); + $pFormModelTotalCostsCalculator->setGroupSlug(self::FORM_VIEW_TOTAL_COSTS_CALCULATOR); + $pFormModelTotalCostsCalculator->setLabel(__('Total costs calculator', 'onoffice-for-wp-websites')); + $pFormModelTotalCostsCalculator->addInputModel($pInputModelTotalCostsCalculator); + $this->addFormModel($pFormModelTotalCostsCalculator); + $pInputModelDocumentTypes = $pFormModelBuilder->createInputModelExpose(); $pInputModelMovieLinks = $pFormModelBuilder->createInputModelMovieLinks(); $pInputModelOguloLinks = $pFormModelBuilder->createInputModelOguloLinks(); diff --git a/plugin/Model/FormModelBuilder/FormModelBuilderEstateDetailSettings.php b/plugin/Model/FormModelBuilder/FormModelBuilderEstateDetailSettings.php index 3b466a685..6674e3cd7 100644 --- a/plugin/Model/FormModelBuilder/FormModelBuilderEstateDetailSettings.php +++ b/plugin/Model/FormModelBuilder/FormModelBuilderEstateDetailSettings.php @@ -627,4 +627,36 @@ public function createSearchFieldForFieldLists($module, string $htmlType) return $pInputModelFieldsConfig; } + + /** + * @return InputModelOption + * @throws ExceptionInputModelMissingField + */ + public function createInputModelTotalCostsCalculator(): InputModelOption + { + $labelShowTotalCostsCalculator = __('Show total price calculator', 'onoffice-for-wp-websites'); + $pInputModelShowTotalCostsCalculator = $this->_pInputModelDetailViewFactory->create + (InputModelOptionFactoryDetailView::INPUT_SHOW_TOTAL_COSTS_CALCULATOR, $labelShowTotalCostsCalculator); + $pInputModelShowTotalCostsCalculator->setHtmlType(InputModelBase::HTML_TYPE_CHECKBOX); + $pInputModelShowTotalCostsCalculator->setValue($this->_pDataDetailView->getShowTotalCostsCalculator()); + $pInputModelShowTotalCostsCalculator->setValuesAvailable(1); + + $fields = ['kaufpreis', 'aussen_courtage', 'bundesland']; + $result = []; + foreach ($fields as $field) { + if ($this->getFieldsCollection()->containsFieldByModule(onOfficeSDK::MODULE_ESTATE, $field)) { + $result[$field] = $this->getFieldsCollection()->getFieldByKeyUnsafe($field)->getLabel(); + } else { + $result[$field] = $field; + } + } + + $textHint = sprintf(esc_html__( + 'The fields %1$s, %2$s and %3$s must be filled in onOffice enterprise so that output is possible. %4$s %4$s A standard value of 1.5%% and 0.5%% respectively is typically used to calculate the notary and land registry entry costs.', 'onoffice-for-wp-websites'), + ''.$result['kaufpreis'].'', ''.$result['aussen_courtage'].'', ''.$result['bundesland'].'', '
' + ); + $pInputModelShowTotalCostsCalculator->setHintHtml($textHint); + + return $pInputModelShowTotalCostsCalculator; + } } diff --git a/plugin/Model/InputModel/InputModelOptionFactoryDetailView.php b/plugin/Model/InputModel/InputModelOptionFactoryDetailView.php index 6a04f5024..43323100d 100644 --- a/plugin/Model/InputModel/InputModelOptionFactoryDetailView.php +++ b/plugin/Model/InputModel/InputModelOptionFactoryDetailView.php @@ -80,6 +80,9 @@ class InputModelOptionFactoryDetailView /** @var string */ const INPUT_SHOW_PRICE_ON_REQUEST = 'show_price_on_request'; + /** @var string */ + const INPUT_SHOW_TOTAL_COSTS_CALCULATOR = 'show_total_costs_calculator'; + /** @var string */ private $_optionGroup = null; @@ -127,6 +130,9 @@ class InputModelOptionFactoryDetailView ], self::INPUT_SHOW_PRICE_ON_REQUEST => [ self::KEY_TYPE => InputModelOption::SETTING_TYPE_BOOLEAN + ], + self::INPUT_SHOW_TOTAL_COSTS_CALCULATOR => [ + self::KEY_TYPE => InputModelOption::SETTING_TYPE_BOOLEAN ] ]; diff --git a/templates.dist/estate/default_detail.php b/templates.dist/estate/default_detail.php index 68ef09cbb..7ae5945a2 100644 --- a/templates.dist/estate/default_detail.php +++ b/templates.dist/estate/default_detail.php @@ -198,6 +198,59 @@ + getTotalCosts())) { + $totalCosts = $pEstates->getTotalCosts(); + ?> +
+

+
+
+

+
+ +
+
getFieldLabel('kaufpreis')); ?>
+
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+ +
getEstateUnits(); ?>
diff --git a/templates.dist/onoffice-style.css b/templates.dist/onoffice-style.css index 040437a37..abd7cdbbc 100644 --- a/templates.dist/onoffice-style.css +++ b/templates.dist/onoffice-style.css @@ -270,6 +270,64 @@ width: 100%; } +.oo-donut-chart { + width: 250px; + height: 250px; + border-radius: 50%; + display: inline-block; + position: relative; +} + +.oo-donut-chart::before { + content: ''; + position: absolute; + background: white; + width: 180px; + height: 180px; + border-radius: 50%; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); +} + +.oo-cost-details { + width: 50%; + display: inline-block; + vertical-align: top; + margin-left: 20px; + font-family: Arial, sans-serif; +} + +.oo-cost-details > div { + margin-bottom: 5px; + font-size: 16px; +} + +.oo-cost-details .oo-label-price, +.oo-cost-details .oo-costs-info { + display: flex; + align-items: center; +} + +.oo-cost-details .oo-label-price { + width: 100%; + justify-content: space-between; +} + +.oo-cost-details .oo-total-costs-label { + margin-left: 12px; +} + + +.oo-cost-details .color-indicator { + display: inline-block; + width: 10px; + height: 10px; + border-radius: 50%; + margin-right: 5px; + vertical-align: middle; +} + /* responsive */ @media only screen and (max-width: 991px) { .oo-listobject, .oo-searchformfield { From 1b7ad08825bcf2a33a2a070f259e13ec179ca0c0 Mon Sep 17 00:00:00 2001 From: "dai.trinh" Date: Fri, 28 Jun 2024 15:28:19 +0700 Subject: [PATCH 02/19] 49984 refactor code --- dist/onoffice_defaultview.min.js | 2 +- js/onoffice_defaultview.js | 15 +- plugin/DataView/DataDetailView.php | 6 +- plugin/EstateList.php | 54 ++++--- plugin/Field/CostCalculator.php | 135 ---------------- plugin/Field/CostsCalculator.php | 146 ++++++++++++++++++ .../FormModelBuilderEstateDetailSettings.php | 5 +- templates.dist/estate/default_detail.php | 80 +++++----- templates.dist/onoffice-style.css | 36 ++--- 9 files changed, 254 insertions(+), 225 deletions(-) delete mode 100644 plugin/Field/CostCalculator.php create mode 100644 plugin/Field/CostsCalculator.php diff --git a/dist/onoffice_defaultview.min.js b/dist/onoffice_defaultview.min.js index 261b84857..d44f56811 100644 --- a/dist/onoffice_defaultview.min.js +++ b/dist/onoffice_defaultview.min.js @@ -1 +1 @@ -(function($){$((function(){$(document).ready((function(){$("#oo-galleryslide").slick({infinite:true,slidesToShow:1});$("#oo-similarframe").slick({infinite:true,arrows:false,dots:true,autoplay:true,slidesToShow:3,slidesToScroll:1,responsive:[{breakpoint:991,settings:{slidesToShow:2}},{breakpoint:575,settings:{slidesToShow:1}}]});if($(".oo-cost-details").length){initializeDonutChart()}function initializeDonutChart(){const colors=["#00a1e0","#3ac411","#8a56e2","#ff6f61","#ffc72c"];const data=[];let totalCost=0;$(".oo-cost-details > div").each((function(index){const value=$(this).attr("data-value");const totalCosts=$(this).attr("total-value");if(!isNaN(value)){data.push({value:value,color:colors[index]});$(this).find(".color-indicator").css("background-color",colors[index])}if(!isNaN(totalCosts))totalCost=totalCosts}));let start=0;let gradientString="conic-gradient(";data.forEach((item=>{const percentage=item.value/totalCost*100;const end=start+percentage;gradientString+=`${item.color} ${start.toFixed(2)}% ${end.toFixed(2)}%, `;start=end}));gradientString=gradientString.slice(0,-2)+")";$(".oo-donut-chart").css("background",gradientString)}}))}))})(jQuery); \ No newline at end of file +(function($){$((function(){$(document).ready((function(){$("#oo-galleryslide").slick({infinite:true,slidesToShow:1});$("#oo-similarframe").slick({infinite:true,arrows:false,dots:true,autoplay:true,slidesToShow:3,slidesToScroll:1,responsive:[{breakpoint:991,settings:{slidesToShow:2}},{breakpoint:575,settings:{slidesToShow:1}}]});if($(".oo-costs-overview").length){initializeDonutChart()}function initializeDonutChart(){const colors=["#00a1e0","#3ac411","#8a56e2","#ff6f61","#ffc72c"];const data=[];let totalCosts=0;$(".oo-costs-overview > div").each((function(index){const value=$(this).attr("data-value");const totalCostsValue=$(this).attr("total-costs-value");if(!isNaN(value)){data.push({value:value,color:colors[index]});$(this).find(".color-indicator").css("background-color",colors[index])}if(!isNaN(totalCostsValue)){totalCosts=totalCostsValue}}));let start=0;let gradientString="conic-gradient(";data.forEach((item=>{const percentage=item.value/totalCosts*100;const end=start+percentage;gradientString+=`${item.color} ${start.toFixed(2)}% ${end.toFixed(2)}%, `;start=end}));gradientString=gradientString.slice(0,-2)+")";$(".oo-donut-chart").css("background",gradientString)}}))}))})(jQuery); \ No newline at end of file diff --git a/js/onoffice_defaultview.js b/js/onoffice_defaultview.js index 08f8951a0..8a9bbba95 100644 --- a/js/onoffice_defaultview.js +++ b/js/onoffice_defaultview.js @@ -26,18 +26,18 @@ }] }); - if ($('.oo-cost-details').length) { + if ($('.oo-costs-overview').length) { initializeDonutChart(); } function initializeDonutChart() { const colors = ['#00a1e0', '#3ac411', '#8a56e2', '#ff6f61', '#ffc72c']; const data = []; - let totalCost = 0; + let totalCosts = 0; - $('.oo-cost-details > div').each(function(index) { + $('.oo-costs-overview > div').each(function(index) { const value = $(this).attr('data-value'); - const totalCosts = $(this).attr('total-value'); + const totalCostsValue = $(this).attr('total-costs-value'); if (!isNaN(value)) { data.push({ value: value, @@ -45,14 +45,15 @@ }); $(this).find('.color-indicator').css('background-color', colors[index]); } - if (!isNaN(totalCosts)) - totalCost = totalCosts; + if (!isNaN(totalCostsValue)) { + totalCosts = totalCostsValue; + } }); let start = 0; let gradientString = 'conic-gradient('; data.forEach((item) => { - const percentage = (item.value / totalCost) * 100; + const percentage = (item.value / totalCosts) * 100; const end = start + percentage; gradientString += `${item.color} ${start.toFixed(2)}% ${end.toFixed(2)}%, `; start = end; diff --git a/plugin/DataView/DataDetailView.php b/plugin/DataView/DataDetailView.php index ec2625e2e..db1677a4e 100644 --- a/plugin/DataView/DataDetailView.php +++ b/plugin/DataView/DataDetailView.php @@ -417,7 +417,7 @@ public function getListFieldsShowPriceOnRequest(): array public function getShowTotalCostsCalculator(): bool { return $this->_showTotalCostsCalculator; } - /** @param bool $costCalculator */ - public function setShowTotalCostsCalculator(bool $costCalculator) - { $this->_showTotalCostsCalculator = $costCalculator; } + /** @param bool $costsCalculator */ + public function setShowTotalCostsCalculator(bool $costsCalculator) + { $this->_showTotalCostsCalculator = $costsCalculator; } } diff --git a/plugin/EstateList.php b/plugin/EstateList.php index 23cd6ec20..6069204d1 100644 --- a/plugin/EstateList.php +++ b/plugin/EstateList.php @@ -58,7 +58,7 @@ use onOffice\WPlugin\WP\WPPluginChecker; use onOffice\WPlugin\Field\Collection\FieldsCollectionBuilderShort; use onOffice\WPlugin\Field\FieldParkingLot; -use onOffice\WPlugin\Field\CostCalculator; +use onOffice\WPlugin\Field\CostsCalculator; class EstateList implements EstateListBase @@ -113,7 +113,7 @@ class EstateList private $_redirectIfOldUrl; /** @var array */ - private $_totalCosts = []; + private $_totalCostsData = []; /** * @param DataView $pDataView @@ -223,9 +223,9 @@ private function loadRecords(int $currentPage) $estateParametersRaw['data'] []= 'vermarktungsart'; $estateParametersRaw['data'] []= 'preisAufAnfrage'; - if ($this->_pDataView instanceof DataDetailView) { - $data = ['kaufpreis', 'aussen_courtage', 'bundesland', 'waehrung']; - $estateParametersRaw['data'] = array_merge($estateParametersRaw['data'], $data); + if ($this->getShowTotalCostsCalculator()) { + $fields = ['kaufpreis', 'aussen_courtage', 'bundesland', 'waehrung']; + $estateParametersRaw['data'] = array_merge($estateParametersRaw['data'], $fields); } $pApiClientActionRawValues = clone $this->_pApiClientAction; @@ -502,11 +502,12 @@ public function estateIterator($modifier = EstateViewFieldModifierTypes::MODIFIE $recordModified['vermarktungsstatus'] = $pEstateStatusLabel->getLabel($recordRaw); } - if ($this->_pDataView instanceof DataDetailView && $this->_pDataView->getShowTotalCostsCalculator()) { - $externalCommission = $this->getExternalCommission($recordRaw); - if (!empty((float) $recordRaw['kaufpreis']) && !empty($recordRaw['bundesland']) && !empty($externalCommission)) { - $costCalculator = new CostCalculator($this->getDataView(), $recordRaw['waehrung'] ?? 'EUR', $externalCommission); - $this->_totalCosts = $costCalculator->getTotalCosts($recordRaw); + if ($this->getShowTotalCostsCalculator()) { + $externalCommission = $this->getExternalCommission($recordRaw['aussen_courtage'] ?? ''); + $propertyTransferTax = $this->_pDataView->getPropertyTransferTax(); + if (!empty((float) $recordRaw['kaufpreis']) && !empty($recordRaw['bundesland']) && $externalCommission !== null) { + $costsCalculator = $this->_pEnvironment->getContainer()->get(CostsCalculator::class); + $this->_totalCostsData = $costsCalculator->getTotalCosts($recordRaw, $propertyTransferTax, $externalCommission); } } @@ -546,6 +547,7 @@ public function estateIterator($modifier = EstateViewFieldModifierTypes::MODIFIE foreach ($priceFields as $priceField) { $this->displayTextPriceOnRequest($recordModified, $priceField); } + $this->_totalCostsData = []; } } // do not show priceOnRequest as single Field @@ -555,25 +557,24 @@ public function estateIterator($modifier = EstateViewFieldModifierTypes::MODIFIE } /** - * @param array $recordRaw - * @return float + * @param string $externalCommission + * @return mixed */ - private function getExternalCommission(array $recordRaw): float + private function getExternalCommission(string $externalCommission) { - if (isset($recordRaw['aussen_courtage']) && !empty($recordRaw['aussen_courtage'])){ - if (preg_match('/(\d+,\d+)\s*%/', $recordRaw['aussen_courtage'], $matches)) { - return floatval(str_replace(',', '.', $matches[1])); - } + if (preg_match('/(\d+[,]?\d*)\s*%/', $externalCommission, $matches)) { + return floatval(str_replace(',', '.', $matches[1])); } - return 0; + + return null; } /** * @return array */ - public function getTotalCosts(): array + public function getTotalCostsData(): array { - return $this->_totalCosts; + return $this->_totalCostsData; } /** @@ -1153,4 +1154,17 @@ public function setFormatOutput(bool $formatOutput) /** @return EstateListEnvironment */ public function getEnvironment(): EstateListEnvironment { return $this->_pEnvironment; } + + /** + * @return bool + */ + public function getShowTotalCostsCalculator(): bool + { + if ($this->_pDataView instanceof DataDetailView) { + return $this->_pDataView->getShowTotalCostsCalculator(); + } + + return false; + } + } diff --git a/plugin/Field/CostCalculator.php b/plugin/Field/CostCalculator.php deleted file mode 100644 index c6882e347..000000000 --- a/plugin/Field/CostCalculator.php +++ /dev/null @@ -1,135 +0,0 @@ -. - */ - -namespace onOffice\WPlugin\Field; - -use Exception; -use NumberFormatter; -use onOffice\WPlugin\Language; -use onOffice\WPlugin\DataView\DataDetailView; -use onOffice\WPlugin\DataView\DataView; - -class CostCalculator -{ - /** @var DataView */ - private $_pDataView; - - /** @var string */ - private $_currencyCode; - - /** @var float */ - private $_externalCommission; - - /** - * @param DataView $dataView - * @param string $currencyCode - * @param float $externalCommission - */ - public function __construct(DataView $dataView, string $currencyCode, float $externalCommission) - { - $this->_pDataView = $dataView; - $this->_currencyCode = $currencyCode; - $this->_externalCommission = $externalCommission; - } - - /** - * @param array $data - * @return array - */ - public function getTotalCosts(array $data): array - { - $language = new Language(); - $locale = !empty($language->getLocale()) ? $language->getLocale() : 'de_DE'; - - $format = new NumberFormatter($locale, NumberFormatter::CURRENCY); - $costDetails = $this->calculateRawCosts($data); - - return $this->formatCosts($format, $costDetails); - } - - /** - * @param array $data - * @return array - */ - private function calculateRawCosts(array $data): array - { - $purchasePrice = $data['kaufpreis']; - $propertyTransferTax = $this->_pDataView->getPropertyTransferTax()[$data['bundesland']]; - $costsRate = [ - 'bundesland' => $propertyTransferTax, - 'aussen_courtage' => $this->_externalCommission, - 'notary_fees' => DataDetailView::NOTARY_FEES, - 'land_register_entry' => DataDetailView::LAND_REGISTER_ENTRY - ]; - - $costDetails = ['kaufpreis' => ['raw' => $purchasePrice]]; - $totalCosts = 0; - - foreach ($costsRate as $key => $value) { - $cost = $this->calculateCostByRate($purchasePrice, $value); - $costDetails[$key] = ['raw' => $cost]; - $totalCosts += $cost; - } - - $costDetails['total_costs'] = ['raw' => $purchasePrice + $totalCosts]; - - return $costDetails; - } - - /** - * @param float $price - * @param float $rate - * @return float - */ - private function calculateCostByRate(float $price, float $rate): float - { - return round($price * $rate / 100); - } - - /** - * @param NumberFormatter $format - * @param array $costDetails - * @return array - */ - private function formatCosts(NumberFormatter $format, array $costDetails): array - { - foreach ($costDetails as $key => $value) { - if (isset($value['raw'])) { - $costDetails[$key]['default'] = $this->formatCurrency($format, $value['raw']); - } - } - - return $costDetails; - } - - /** - * @param NumberFormatter $format - * @param float $amount - * @return string - */ - private function formatCurrency(NumberFormatter $format, float $amount): string - { - if (intval($amount) == $amount) { - $format->setAttribute(NumberFormatter::MIN_SIGNIFICANT_DIGITS, 0); - } - - return str_replace("\xc2\xa0", " ", $format->formatCurrency($amount, $this->_currencyCode)); - } -} \ No newline at end of file diff --git a/plugin/Field/CostsCalculator.php b/plugin/Field/CostsCalculator.php new file mode 100644 index 000000000..8cfe145c5 --- /dev/null +++ b/plugin/Field/CostsCalculator.php @@ -0,0 +1,146 @@ +. + */ + +namespace onOffice\WPlugin\Field; + +use onOffice\WPlugin\DataView\DataDetailView; +use onOffice\SDK\onOfficeSDK; +use onOffice\WPlugin\API\APIClientActionGeneric; +use onOffice\WPlugin\SDKWrapper; + +class CostsCalculator +{ + /** @var SDKWrapper */ + private $_pSDKWrapper; + + public function __construct(SDKWrapper $_pSDKWrapper) + { + $this->_pSDKWrapper = $_pSDKWrapper; + } + + + /** + * @param array $recordRaw + * @param array $propertyTransferTax + * @param float $externalCommission + * @return array + */ + public function getTotalCosts(array $recordRaw, array $propertyTransferTax, float $externalCommission): array + { + $totalCostsData = $this->calculateRawCosts($recordRaw, $propertyTransferTax, $externalCommission); + + if (empty($this->getCurrencySymbol())) { + return []; + } + + $currency = $this->getCurrencySymbol()[$recordRaw['waehrung']]; + + return $this->formatPrice($totalCostsData, $currency); + } + + /** + * @param array $recordRaw + * @param array $propertyTransferTax + * @param float $externalCommission + * @return array + */ + private function calculateRawCosts(array $recordRaw, array $propertyTransferTax, float $externalCommission): array + { + $purchasePriceRaw = $recordRaw['kaufpreis']; + + $othersCosts = [ + 'bundesland' => $propertyTransferTax[$recordRaw['bundesland']], + 'aussen_courtage' => $externalCommission, + 'notary_fees' => DataDetailView::NOTARY_FEES, + 'land_register_entry' => DataDetailView::LAND_REGISTER_ENTRY + ]; + + $rawAllCosts = ['kaufpreis' => ['raw' => $purchasePriceRaw]]; + $totals = 0; + + foreach ($othersCosts as $key => $value) { + $calculatePrice = $this->calculatePrice($purchasePriceRaw, $value); + $rawAllCosts[$key] = ['raw' => $calculatePrice]; + $totals += $calculatePrice; + } + + $rawAllCosts['total_costs'] = ['raw' => $purchasePriceRaw + $totals]; + + return $rawAllCosts; + } + + /** + * @param float $price + * @param float $rate + * @return float + */ + private function calculatePrice(float $price, float $rate): float + { + return round($price * $rate / 100); + } + + /** + * @param array $totalCostsData + * @param string $currency + * @return array + */ + private function formatPrice(array $totalCostsData, string $currency): array + { + foreach ($totalCostsData as $key => $value) { + $totalCostsData[$key]['default'] = $this->formatCurrency($value['raw'], $currency); + } + + return $totalCostsData; + } + + /** + * @param float $amount + * @param string $currency + * @return string + */ + private function formatCurrency(float $amount, string $currency): string + { + $decimalPlaces = floor($amount) == $amount ? 0 : 2; + return number_format($amount, $decimalPlaces, ',', '.') . ' ' . $currency; + } + + /** + * + */ + + private function getCurrencySymbol() + { + $parametersGetFieldList = [ + 'labels' => true, + 'fieldList' => ['waehrung'], + 'language' => 'DEU', + 'modules' => [onOfficeSDK::MODULE_ESTATE], + ]; + + $pApiClientActionFields = new APIClientActionGeneric + ($this->_pSDKWrapper, onOfficeSDK::ACTION_ID_GET, 'fields'); + $pApiClientActionFields->setParameters($parametersGetFieldList); + $pApiClientActionFields->addRequestToQueue(); + $this->_pSDKWrapper->sendRequests(); + $result = $pApiClientActionFields->getResultRecords(); + + return $result[0]['elements']['waehrung']['permittedvalues'] ?? []; + } +} \ No newline at end of file diff --git a/plugin/Model/FormModelBuilder/FormModelBuilderEstateDetailSettings.php b/plugin/Model/FormModelBuilder/FormModelBuilderEstateDetailSettings.php index 6674e3cd7..8674585fc 100644 --- a/plugin/Model/FormModelBuilder/FormModelBuilderEstateDetailSettings.php +++ b/plugin/Model/FormModelBuilder/FormModelBuilderEstateDetailSettings.php @@ -642,10 +642,11 @@ public function createInputModelTotalCostsCalculator(): InputModelOption $pInputModelShowTotalCostsCalculator->setValuesAvailable(1); $fields = ['kaufpreis', 'aussen_courtage', 'bundesland']; + $pFieldsCollection = $this->getFieldsCollection(); $result = []; foreach ($fields as $field) { - if ($this->getFieldsCollection()->containsFieldByModule(onOfficeSDK::MODULE_ESTATE, $field)) { - $result[$field] = $this->getFieldsCollection()->getFieldByKeyUnsafe($field)->getLabel(); + if ($pFieldsCollection->containsFieldByModule(onOfficeSDK::MODULE_ESTATE, $field)) { + $result[$field] = $pFieldsCollection->getFieldByKeyUnsafe($field)->getLabel(); } else { $result[$field] = $field; } diff --git a/templates.dist/estate/default_detail.php b/templates.dist/estate/default_detail.php index 7ae5945a2..a779a500f 100644 --- a/templates.dist/estate/default_detail.php +++ b/templates.dist/estate/default_detail.php @@ -198,53 +198,55 @@ - getTotalCosts())) { - $totalCosts = $pEstates->getTotalCosts(); + getTotalCostsData())) { + $totalCostsData = $pEstates->getTotalCostsData(); ?>

-
-
-

-
- -
-
getFieldLabel('kaufpreis')); ?>
-
+
+
+
+

+
+ +
+
getFieldLabel('kaufpreis')); ?>
+
+
-
-
- -
-
-
+
+ +
+
+
+
-
-
- -
-
-
+
+ +
+
+
+
-
-
- -
-
-
+
+ +
+
+
+
-
-
- -
-
-
+
+ +
+
+
+
-
-
-
-
-
+
+
+
+
+
diff --git a/templates.dist/onoffice-style.css b/templates.dist/onoffice-style.css index abd7cdbbc..eb0c5c66d 100644 --- a/templates.dist/onoffice-style.css +++ b/templates.dist/onoffice-style.css @@ -270,11 +270,17 @@ width: 100%; } +.oo-costs-container { + width: 100%; + display: flex; + justify-content: space-between; + align-items: flex-start; +} + .oo-donut-chart { - width: 250px; - height: 250px; + width: 40%; + padding-bottom: 40%; border-radius: 50%; - display: inline-block; position: relative; } @@ -282,44 +288,38 @@ content: ''; position: absolute; background: white; - width: 180px; - height: 180px; + width: 70%; + height: 70%; border-radius: 50%; top: 50%; left: 50%; transform: translate(-50%, -50%); } -.oo-cost-details { +.oo-costs-overview { width: 50%; - display: inline-block; - vertical-align: top; - margin-left: 20px; - font-family: Arial, sans-serif; } -.oo-cost-details > div { +.oo-costs-overview > div { margin-bottom: 5px; - font-size: 16px; } -.oo-cost-details .oo-label-price, -.oo-cost-details .oo-costs-info { +.oo-costs-overview .oo-price-label, +.oo-costs-overview .oo-costs-item { display: flex; align-items: center; } -.oo-cost-details .oo-label-price { +.oo-costs-overview .oo-price-label { width: 100%; justify-content: space-between; } -.oo-cost-details .oo-total-costs-label { +.oo-costs-overview .oo-total-costs-label { margin-left: 12px; } - -.oo-cost-details .color-indicator { +.oo-costs-overview .color-indicator { display: inline-block; width: 10px; height: 10px; From b58a459276a44e6f6bcf47c3692ab79065c818e6 Mon Sep 17 00:00:00 2001 From: "dai.trinh" Date: Fri, 28 Jun 2024 15:29:06 +0700 Subject: [PATCH 03/19] 49984 update unit test --- plugin/DataView/DataDetailView.php | 8 +- plugin/EstateList.php | 2 +- plugin/Field/CostsCalculator.php | 12 +-- tests/TestClassDataDetailView.php | 24 +++++ tests/TestClassEstateList.php | 88 +++++++++++++++ ...ssFormModelBuilderEstateDetailSettings.php | 15 +++ tests/TestTemplateEstateDefaultDetail.php | 29 +++++ .../ApiResponseGetFieldsCurrency.json | 47 ++++++++ ...EstatesPublishedENGCostsCalculatorRaw.json | 101 ++++++++++++++++++ .../templates/output_default_detail.html | 51 +++++++++ 10 files changed, 366 insertions(+), 11 deletions(-) create mode 100644 tests/resources/ApiResponseGetFieldsCurrency.json create mode 100644 tests/resources/ApiResponseReadEstatesPublishedENGCostsCalculatorRaw.json diff --git a/plugin/DataView/DataDetailView.php b/plugin/DataView/DataDetailView.php index db1677a4e..f09d966d3 100644 --- a/plugin/DataView/DataDetailView.php +++ b/plugin/DataView/DataDetailView.php @@ -401,10 +401,6 @@ public function getShowPriceOnRequest(): bool public function setShowPriceOnRequest(bool $priceOnRequest) { $this->_showPriceOnRequest = $priceOnRequest; } - /** @return array */ - public function getPropertyTransferTax(): array - { return $this->_propertyTransferTax; } - /** * @return array */ @@ -413,6 +409,10 @@ public function getListFieldsShowPriceOnRequest(): array return $this->_priceFields; } + /** @return array */ + public function getPropertyTransferTax(): array + { return $this->_propertyTransferTax; } + /** @return bool */ public function getShowTotalCostsCalculator(): bool { return $this->_showTotalCostsCalculator; } diff --git a/plugin/EstateList.php b/plugin/EstateList.php index 6069204d1..352ca6383 100644 --- a/plugin/EstateList.php +++ b/plugin/EstateList.php @@ -224,7 +224,7 @@ private function loadRecords(int $currentPage) $estateParametersRaw['data'] []= 'preisAufAnfrage'; if ($this->getShowTotalCostsCalculator()) { - $fields = ['kaufpreis', 'aussen_courtage', 'bundesland', 'waehrung']; + $fields = ['kaufpreis', 'aussen_courtage', 'bundesland', 'waehrung']; $estateParametersRaw['data'] = array_merge($estateParametersRaw['data'], $fields); } diff --git a/plugin/Field/CostsCalculator.php b/plugin/Field/CostsCalculator.php index 8cfe145c5..c043ba93b 100644 --- a/plugin/Field/CostsCalculator.php +++ b/plugin/Field/CostsCalculator.php @@ -127,19 +127,19 @@ private function formatCurrency(float $amount, string $currency): string private function getCurrencySymbol() { - $parametersGetFieldList = [ + $parameters = [ 'labels' => true, - 'fieldList' => ['waehrung'], + 'fieldList' => ['weahrung'], 'language' => 'DEU', 'modules' => [onOfficeSDK::MODULE_ESTATE], ]; - $pApiClientActionFields = new APIClientActionGeneric + $pAPIClientAction = new APIClientActionGeneric ($this->_pSDKWrapper, onOfficeSDK::ACTION_ID_GET, 'fields'); - $pApiClientActionFields->setParameters($parametersGetFieldList); - $pApiClientActionFields->addRequestToQueue(); + $pAPIClientAction->setParameters($parameters); + $pAPIClientAction->addRequestToQueue(); $this->_pSDKWrapper->sendRequests(); - $result = $pApiClientActionFields->getResultRecords(); + $result = $pAPIClientAction->getResultRecords(); return $result[0]['elements']['waehrung']['permittedvalues'] ?? []; } diff --git a/tests/TestClassDataDetailView.php b/tests/TestClassDataDetailView.php index eed72cf58..7affa1445 100644 --- a/tests/TestClassDataDetailView.php +++ b/tests/TestClassDataDetailView.php @@ -78,6 +78,27 @@ class TestClassDataDetailView 'mobile', 'defaultemail', ]; + + /** */ + const PROPERTY_TRANSFER_TAX = [ + 'Baden-Württemberg' => 5, + 'Bayern' => 3.5, + 'Berlin' => 6, + 'Brandenburg' => 6.5, + 'Bremen' => 5, + 'Hamburg' => 5.5, + 'Hessen' => 6, + 'Mecklenburg-Vorpommern' => 6, + 'Niedersachsen' => 5, + 'Nordrhein-Westfalen' => 6.5, + 'Rheinland-Pfalz' => 5, + 'Saarland' => 6.5, + 'Sachsen' => 5.5, + 'Sachsen-Anhalt' => 5, + 'Schleswig-Holstein' => 6.5, + 'Thüringen' => 5 + ]; + /** * */ @@ -100,6 +121,7 @@ public function testDefaultValues() $this->assertEquals(LinksTypes::LINKS_EMBEDDED, $pDataDetailView->getOguloLinks()); $this->assertEquals(LinksTypes::LINKS_DEACTIVATED, $pDataDetailView->getObjectLinks()); $this->assertEquals(LinksTypes::LINKS_DEACTIVATED, $pDataDetailView->getLinks()); + $this->assertEquals(self::PROPERTY_TRANSFER_TAX, $pDataDetailView->getPropertyTransferTax()); } /** @@ -133,6 +155,8 @@ public function testGetterSetter() $pDataDetailView->setShowPriceOnRequest(true); $this->assertEquals(true, $pDataDetailView->getShowPriceOnRequest()); $this->assertTrue($pDataDetailView->getShowStatus()); + $pDataDetailView->setShowTotalCostsCalculator(true); + $this->assertTrue($pDataDetailView->getShowTotalCostsCalculator()); } /** diff --git a/tests/TestClassEstateList.php b/tests/TestClassEstateList.php index 43bf2e2c8..4cbd4b566 100644 --- a/tests/TestClassEstateList.php +++ b/tests/TestClassEstateList.php @@ -899,6 +899,82 @@ public function testGetShowMapConfig() $this->assertEquals('1', $result['showGoogleMap']); } + /** + * + */ + public function testGetShowTotalCostsCalculator() + { + $totalCostsData = [ + 'kaufpreis' => [ + 'raw' => 123456.56, + 'default' => '123.456,56 €' + ], + 'bundesland' => [ + 'raw' => 4321, + 'default' => '4.321 €' + ], + 'aussen_courtage' => [ + 'raw' => 22222, + 'default' => '22.222 €' + ], + 'notary_fees' => [ + 'raw' => 1852, + 'default' => '1.852 €' + ], + 'land_register_entry' => [ + 'raw' => 617, + 'default' => '617 €' + ], + 'total_costs' => [ + 'raw' => 152468.56, + 'default' => '152.468,56 €' + ] + ]; + + $pDataDetailView = $this->getMockBuilder(DataDetailView::class) + ->setConstructorArgs([$this->_pContainer]) + ->setMethods(['getRecordsPerPage', + 'getSortby', + 'getSortorder', + 'getFilterId', + 'getFields', + 'getPictureTypes', + 'getAddressFields', + 'getFilterableFields', + 'getPageId', + 'getViewRestrict', + 'getShowPriceOnRequest', + 'getListFieldsShowPriceOnRequest', + 'getShowTotalCostsCalculator' + ]) + ->getMock(); + $pDataDetailView->method('getRecordsPerPage')->willReturn(5); + $pDataDetailView->method('getSortby')->willReturn('Id'); + $pDataDetailView->method('getSortorder')->willReturn('ASC'); + $pDataDetailView->method('getFilterId')->willReturn(12); + $pDataDetailView->method('getFields')->willReturn(['Id', 'objektart', 'objekttyp', 'objekttitel', 'objektbeschreibung', 'warmmiete', 'kaufpreis', 'erbpacht', 'nettokaltmiete', 'pacht', 'kaltmiete']); + $pDataDetailView->method('getPictureTypes')->willReturn(['Titelbild', 'Foto']); + $pDataDetailView->method('getAddressFields')->willReturn(['Vorname', 'Name']); + $pDataDetailView->method('getFilterableFields')->willReturn([GeoPosition::FIELD_GEO_POSITION]); + $pDataDetailView->method('getPageId')->willReturn(5); + $pDataDetailView->method('getViewRestrict')->willReturn(true); + $pDataDetailView->method('getShowPriceOnRequest')->willReturn(true); + $pDataDetailView->method('getListFieldsShowPriceOnRequest')->willReturn(['kaufpreis', 'erbpacht']); + $pDataDetailView->method('getShowTotalCostsCalculator')->willReturn(true); + + $pDataDetailViewHandler = $this->getMockBuilder(DataDetailViewHandler::class) + ->disableOriginalConstructor() + ->setMethods(['getDetailView']) + ->getMock(); + $pDataDetailViewHandler->method('getDetailView')->willReturn($pDataDetailView); + $this->_pEnvironment->method('getDataDetailViewHandler')->willReturn($pDataDetailViewHandler); + + $this->_pEstateList = new EstateList($pDataDetailView, $this->_pEnvironment); + $this->_pEstateList->loadEstates(); + $this->_pEstateList->estateIterator(); + $this->assertEquals($totalCostsData, $this->_pEstateList->getTotalCostsData()); + } + /** * * @before @@ -921,11 +997,23 @@ public function prepareEstateList() (file_get_contents(__DIR__.'/resources/ApiResponseGetIdsFromRelation.json'), true); $responseGetEstatePictures = json_decode (file_get_contents(__DIR__.'/resources/ApiResponseGetEstatePictures.json'), true); + $dataReadEstateShowTotalCostsCalculatorRaw = json_decode + (file_get_contents(__DIR__.'/resources/ApiResponseReadEstatesPublishedENGCostsCalculatorRaw.json'), true); + $responseReadEstateShowTotalCostsCalculatorRaw = $dataReadEstateShowTotalCostsCalculatorRaw['response']; + $parametersReadEstateShowTotalCostsCalculatorRaw = $dataReadEstateShowTotalCostsCalculatorRaw['parameters']; + $dataGetFieldCurrency = json_decode + (file_get_contents(__DIR__.'/resources/ApiResponseGetFieldsCurrency.json'), true); + $responseGetFieldCurrency = $dataGetFieldCurrency['response']; + $parametersGetFieldCurrency = $dataGetFieldCurrency['parameters']; $this->_pSDKWrapperMocker->addResponseByParameters (onOfficeSDK::ACTION_ID_READ, 'estate', '', $parametersReadEstate, null, $responseReadEstate); $this->_pSDKWrapperMocker->addResponseByParameters (onOfficeSDK::ACTION_ID_READ, 'estate', '', $parametersReadEstateRaw, null, $responseReadEstateRaw); + $this->_pSDKWrapperMocker->addResponseByParameters + (onOfficeSDK::ACTION_ID_READ, 'estate', '', $parametersReadEstateShowTotalCostsCalculatorRaw, null, $responseReadEstateShowTotalCostsCalculatorRaw); + $this->_pSDKWrapperMocker->addResponseByParameters + (onOfficeSDK::ACTION_ID_GET, 'fields', '', $parametersGetFieldCurrency, null, $responseGetFieldCurrency); unset($parametersReadEstate['georangesearch']); $this->_pSDKWrapperMocker->addResponseByParameters diff --git a/tests/TestClassFormModelBuilderEstateDetailSettings.php b/tests/TestClassFormModelBuilderEstateDetailSettings.php index 17acdb07e..60ecfb214 100644 --- a/tests/TestClassFormModelBuilderEstateDetailSettings.php +++ b/tests/TestClassFormModelBuilderEstateDetailSettings.php @@ -421,4 +421,19 @@ public function testCreateSearchFieldForFieldLists() $this->assertNotEmpty($pInputModelOption->getValuesAvailable()); $this->assertEquals($pInputModelOption->getHtmlType(), 'searchFieldForFieldLists'); } + + /** + * @covers onOffice\WPlugin\Model\FormModelBuilder\FormModelBuilderEstateDetailSettings::createInputModelTotalCostsCalculator + * @covers onOffice\WPlugin\Model\FormModelBuilder\FormModelBuilderEstateDetailSettings::getFieldsCollection + */ + public function testCreateInputModelTotalCostsCalculator() + { + $pFormModelBuilderEstateDetailSettings = $this->_pFormModelBuilderEstateDetailSettings; + $pFormModelBuilderEstateDetailSettings->generate('test'); + $pInputModelOption = $pFormModelBuilderEstateDetailSettings->createInputModelTotalCostsCalculator(); + + $this->assertInstanceOf(InputModelOption::class, $pInputModelOption); + $this->assertNotEmpty($pInputModelOption->getValuesAvailable()); + $this->assertEquals($pInputModelOption->getHtmlType(), 'checkbox'); + } } \ No newline at end of file diff --git a/tests/TestTemplateEstateDefaultDetail.php b/tests/TestTemplateEstateDefaultDetail.php index 2d7775c33..96611ae4d 100644 --- a/tests/TestTemplateEstateDefaultDetail.php +++ b/tests/TestTemplateEstateDefaultDetail.php @@ -66,6 +66,7 @@ public function prepare() 'getEstateLinks', 'getLinkEmbedPlayers', 'getDetailView', + 'getTotalCostsData', ]) ->setConstructorArgs([$pDataView]) ->getMock(); @@ -90,6 +91,33 @@ public function prepare() 'MPAreaButlerUrlWithAddress' => 'areabutler.de', ]; + $totalCostsData = [ + 'kaufpreis' => [ + 'raw' => 123456.56, + 'default' => '123.456,56 €' + ], + 'bundesland' => [ + 'raw' => 4321, + 'default' => '4.321 €' + ], + 'aussen_courtage' => [ + 'raw' => 22222, + 'default' => '22.222 €' + ], + 'notary_fees' => [ + 'raw' => 1852, + 'default' => '1.852 €' + ], + 'land_register_entry' => [ + 'raw' => 617, + 'default' => '617 €' + ], + 'total_costs' => [ + 'raw' => 152468.56, + 'default' => '152.468,56 €' + ] + ]; + $pArrayContainerEstateDetail = new ArrayContainerEscape($estateData); $this->_pEstate->setEstateId(52); @@ -99,6 +127,7 @@ public function prepare() ->will($this->returnCallback(function(string $field): string { return 'label-'.$field; })); + $this->_pEstate->method('getTotalCostsData')->willReturn($totalCostsData); $contactData = [ 'Name' => 'Parker', diff --git a/tests/resources/ApiResponseGetFieldsCurrency.json b/tests/resources/ApiResponseGetFieldsCurrency.json new file mode 100644 index 000000000..2bbf57605 --- /dev/null +++ b/tests/resources/ApiResponseGetFieldsCurrency.json @@ -0,0 +1,47 @@ +{ + "parameters": { + "labels": true, + "fieldList": ["weahrung"], + "language": "DEU", + "modules": ["estate"] + }, + "response": { + "actionid": "urn:onoffice-de-ns:smart:2.5:smartml:action:get", + "resourceid": "", + "resourcetype": "fields", + "cacheable": true, + "identifier": "", + "data": { + "meta": { + "cntabsolute": null + }, + "records": [ + { + "id": "estate", + "type": "", + "elements": { + "label": "Adressen", + "waehrung": { + "type": "multiselect", + "length": null, + "permittedvalues": { + "EUR": "€", + "CZK": "Kč", + "TRY": "₺" + }, + "default": null, + "filters": [], + "dependencies": [], + "compoundFields": [], + "label": "Währung" + } + } + } + ] + }, + "status": { + "errorcode": 0, + "message": "OK" + } + } +} diff --git a/tests/resources/ApiResponseReadEstatesPublishedENGCostsCalculatorRaw.json b/tests/resources/ApiResponseReadEstatesPublishedENGCostsCalculatorRaw.json new file mode 100644 index 000000000..2fff2a404 --- /dev/null +++ b/tests/resources/ApiResponseReadEstatesPublishedENGCostsCalculatorRaw.json @@ -0,0 +1,101 @@ +{ + "parameters": { + "data": [ + "referenz", + "reserviert", + "verkauft", + "objekttitel", + "objektbeschreibung", + "exclusive", + "neu", + "top_angebot", + "preisreduktion", + "courtage_frei", + "objekt_des_tages", + "vermarktungsart", + "preisAufAnfrage", + "kaufpreis", + "aussen_courtage", + "bundesland", + "waehrung" + ], + "filter": { + "veroeffentlichen": [ + { + "op": "=", + "val": 1 + } + ], + "referenz": [ + { + "op": "=", + "val": 0 + } + ] + }, + "estatelanguage": "ENG", + "outputlanguage": "ENG", + "listlimit": 5, + "formatoutput": false, + "addMainLangId": true, + "listoffset": 0, + "sortby": "Id", + "sortorder": "ASC", + "filterid": 12 + }, + "response": { + "actionid": "urn:onoffice-de-ns:smart:2.5:smartml:action:read", + "resourceid": "", + "resourcetype": "estate", + "cacheable": true, + "identifier": "", + "data": { + "meta": { + "cntabsolute": 9 + }, + "records": [ + { + "id": 15, + "type": "estate", + "elements": { + "reserviert": "0", + "verkauft": "1", + "vermarktungsart": "kauf", + "referenz": "0", + "exclusive": "0", + "neu": "0", + "top_angebot": "0", + "preisreduktion": "0", + "courtage_frei": "0", + "objekt_des_tages": "0", + "virtualStreet": "", + "virtualHouseNumber": "", + "laengengrad": "0.00000", + "breitengrad": "0.00000", + "virtualLatitude": "0.00000", + "virtualLongitude": "0.00000", + "strasse": "", + "showGoogleMap": "1", + "hausnummer": "", + "objekttitel": "Name id 15", + "objektbeschreibung": "description test", + "ort": "", + "objektnr_extern": "DJ636", + "plz": "", + "land": "DEU", + "preisAufAnfrage": "0", + "mainLangId": null, + "kaufpreis": "123456.56", + "aussen_courtage": "aussen_courtage18%", + "bundesland": "Bayern", + "waehrung": "EUR" + } + } + ] + }, + "status": { + "errorcode": 0, + "message": "OK" + } + } +} diff --git a/tests/resources/templates/output_default_detail.html b/tests/resources/templates/output_default_detail.html index 36e78760f..7a4655ddd 100644 --- a/tests/resources/templates/output_default_detail.html +++ b/tests/resources/templates/output_default_detail.html @@ -55,6 +55,57 @@

label-ausstatt_beschr

label-sonstige_angaben

Vereinbaren sie noch heute einen Besichtigungstermin
+
+

Total costs

+
+
+
+

Overview of costs

+
+ +
+
label-kaufpreis
+
123.456,56 €
+
+
+
+ +
+
Property transfer tax
+
4.321 €
+
+
+
+ +
+
Broker commission
+
22.222 €
+
+
+
+ +
+
Notary Fees
+
1.852 €
+
+
+
+ +
+
Land Register Entry
+
617 €
+
+
+
+
+
Total costs
+
152.468,56 €
+
+
+
+
+
+
Estate Units here
From e2681b4f8374d2eb9d8b68f2f44ee452f50d2712 Mon Sep 17 00:00:00 2001 From: "dai.trinh" Date: Fri, 28 Jun 2024 15:37:55 +0700 Subject: [PATCH 04/19] 49984 change field key --- plugin/Field/CostsCalculator.php | 7 ++++--- tests/resources/ApiResponseGetFieldsCurrency.json | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/plugin/Field/CostsCalculator.php b/plugin/Field/CostsCalculator.php index c043ba93b..32e4a4dec 100644 --- a/plugin/Field/CostsCalculator.php +++ b/plugin/Field/CostsCalculator.php @@ -45,12 +45,13 @@ public function __construct(SDKWrapper $_pSDKWrapper) public function getTotalCosts(array $recordRaw, array $propertyTransferTax, float $externalCommission): array { $totalCostsData = $this->calculateRawCosts($recordRaw, $propertyTransferTax, $externalCommission); + $currencySymbol = $this->getCurrencySymbol(); - if (empty($this->getCurrencySymbol())) { + if (empty($currencySymbol)) { return []; } - $currency = $this->getCurrencySymbol()[$recordRaw['waehrung']]; + $currency = $currencySymbol[$recordRaw['waehrung']]; return $this->formatPrice($totalCostsData, $currency); } @@ -129,7 +130,7 @@ private function getCurrencySymbol() { $parameters = [ 'labels' => true, - 'fieldList' => ['weahrung'], + 'fieldList' => ['waehrung'], 'language' => 'DEU', 'modules' => [onOfficeSDK::MODULE_ESTATE], ]; diff --git a/tests/resources/ApiResponseGetFieldsCurrency.json b/tests/resources/ApiResponseGetFieldsCurrency.json index 2bbf57605..18e6a9fa9 100644 --- a/tests/resources/ApiResponseGetFieldsCurrency.json +++ b/tests/resources/ApiResponseGetFieldsCurrency.json @@ -1,7 +1,7 @@ { "parameters": { "labels": true, - "fieldList": ["weahrung"], + "fieldList": ["waehrung"], "language": "DEU", "modules": ["estate"] }, From 73ecc3bdc72389764df68d6e1ef15a6ef2b7eec5 Mon Sep 17 00:00:00 2001 From: "dai.trinh" Date: Fri, 28 Jun 2024 17:14:27 +0700 Subject: [PATCH 05/19] 49984 update unit test --- tests/TestClassCostsCalculator.php | 114 ++++++++++++++++++ tests/TestClassEstateList.php | 10 +- ...esponseReadEstatesCostsCalculatorRaw.json} | 0 3 files changed, 119 insertions(+), 5 deletions(-) create mode 100644 tests/TestClassCostsCalculator.php rename tests/resources/{ApiResponseReadEstatesPublishedENGCostsCalculatorRaw.json => ApiResponseReadEstatesCostsCalculatorRaw.json} (100%) diff --git a/tests/TestClassCostsCalculator.php b/tests/TestClassCostsCalculator.php new file mode 100644 index 000000000..8ffb1f7f1 --- /dev/null +++ b/tests/TestClassCostsCalculator.php @@ -0,0 +1,114 @@ +. + * + */ + +namespace onOffice\tests; + +use DI\Container; +use WP_UnitTestCase; +use DI\ContainerBuilder; +use onOffice\WPlugin\Field\CostsCalculator; +use onOffice\SDK\onOfficeSDK; +use onOffice\WPlugin\SDKWrapper; + +/** + * + * @url http://www.onoffice.de + * @copyright 2003-2024, onOffice(R) GmbH + * + */ + +class TestClassCostsCalculator + extends WP_UnitTestCase +{ + /** @var Container */ + private $_pContainer; + + /** @var CostsCalculator */ + private $_pCostsCalculator = null; + + /** @var string[] */ + private $_totalCostsData = [ + 'kaufpreis' => [ + 'raw' => 123456.56, + 'default' => '123.456,56 €' + ], + 'bundesland' => [ + 'raw' => 4321, + 'default' => '4.321 €' + ], + 'aussen_courtage' => [ + 'raw' => 22222, + 'default' => '22.222 €' + ], + 'notary_fees' => [ + 'raw' => 1852, + 'default' => '1.852 €' + ], + 'land_register_entry' => [ + 'raw' => 617, + 'default' => '617 €' + ], + 'total_costs' => [ + 'raw' => 152468.56, + 'default' => '152.468,56 €' + ] + ]; + + /** + * @before + */ + public function prepare() + { + $pSDKWrapperMocker = new SDKWrapperMocker(); + $pContainerBuilder = new ContainerBuilder; + $pContainerBuilder->addDefinitions(ONOFFICE_DI_CONFIG_PATH); + $this->_pContainer = $pContainerBuilder->build(); + $dataGetFieldCurrency = json_decode + (file_get_contents(__DIR__.'/resources/ApiResponseGetFieldsCurrency.json'), true); + $responseGetFieldCurrency = $dataGetFieldCurrency['response']; + $parametersGetFieldCurrency = $dataGetFieldCurrency['parameters']; + + $pSDKWrapperMocker->addResponseByParameters + (onOfficeSDK::ACTION_ID_GET, 'fields', '', $parametersGetFieldCurrency, null, $responseGetFieldCurrency); + + $this->_pContainer->set(SDKWrapper::class, $pSDKWrapperMocker); + $this->_pCostsCalculator = $this->_pContainer->get(CostsCalculator::class); + } + + /** + * + */ + public function testGetShowMapConfig() + { + $recordRaw = [ + 'kaufpreis' => '123456.56', + 'bundesland' => 'Bayern', + 'waehrung' => 'EUR' + ]; + $propertyTransferTax = [ + 'Bayern' => 3.5 + ]; + $externalCommission = '18'; + + $totalCostsData = $this->_pCostsCalculator->getTotalCosts($recordRaw, $propertyTransferTax, $externalCommission); + $this->assertEquals($totalCostsData, $this->_totalCostsData); + } +} diff --git a/tests/TestClassEstateList.php b/tests/TestClassEstateList.php index 4cbd4b566..e03aec550 100644 --- a/tests/TestClassEstateList.php +++ b/tests/TestClassEstateList.php @@ -997,10 +997,10 @@ public function prepareEstateList() (file_get_contents(__DIR__.'/resources/ApiResponseGetIdsFromRelation.json'), true); $responseGetEstatePictures = json_decode (file_get_contents(__DIR__.'/resources/ApiResponseGetEstatePictures.json'), true); - $dataReadEstateShowTotalCostsCalculatorRaw = json_decode - (file_get_contents(__DIR__.'/resources/ApiResponseReadEstatesPublishedENGCostsCalculatorRaw.json'), true); - $responseReadEstateShowTotalCostsCalculatorRaw = $dataReadEstateShowTotalCostsCalculatorRaw['response']; - $parametersReadEstateShowTotalCostsCalculatorRaw = $dataReadEstateShowTotalCostsCalculatorRaw['parameters']; + $dataReadEstatesPublishedENGCostsCalculatorRaw = json_decode + (file_get_contents(__DIR__.'/resources/ApiResponseReadEstatesCostsCalculatorRaw.json'), true); + $responseReadEstatesCostsCalculatorRaw = $dataReadEstatesPublishedENGCostsCalculatorRaw['response']; + $parametersReadEstatesCostsCalculatorRaw = $dataReadEstatesPublishedENGCostsCalculatorRaw['parameters']; $dataGetFieldCurrency = json_decode (file_get_contents(__DIR__.'/resources/ApiResponseGetFieldsCurrency.json'), true); $responseGetFieldCurrency = $dataGetFieldCurrency['response']; @@ -1011,7 +1011,7 @@ public function prepareEstateList() $this->_pSDKWrapperMocker->addResponseByParameters (onOfficeSDK::ACTION_ID_READ, 'estate', '', $parametersReadEstateRaw, null, $responseReadEstateRaw); $this->_pSDKWrapperMocker->addResponseByParameters - (onOfficeSDK::ACTION_ID_READ, 'estate', '', $parametersReadEstateShowTotalCostsCalculatorRaw, null, $responseReadEstateShowTotalCostsCalculatorRaw); + (onOfficeSDK::ACTION_ID_READ, 'estate', '', $parametersReadEstatesCostsCalculatorRaw, null, $responseReadEstatesCostsCalculatorRaw); $this->_pSDKWrapperMocker->addResponseByParameters (onOfficeSDK::ACTION_ID_GET, 'fields', '', $parametersGetFieldCurrency, null, $responseGetFieldCurrency); diff --git a/tests/resources/ApiResponseReadEstatesPublishedENGCostsCalculatorRaw.json b/tests/resources/ApiResponseReadEstatesCostsCalculatorRaw.json similarity index 100% rename from tests/resources/ApiResponseReadEstatesPublishedENGCostsCalculatorRaw.json rename to tests/resources/ApiResponseReadEstatesCostsCalculatorRaw.json From cd9801f537e431145898a585cc0e837c847e6e25 Mon Sep 17 00:00:00 2001 From: "dai.trinh" Date: Fri, 28 Jun 2024 17:35:52 +0700 Subject: [PATCH 06/19] 49984 refactor code --- plugin/Field/CostsCalculator.php | 5 +++-- templates.dist/onoffice-style.css | 18 +++++++++--------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/plugin/Field/CostsCalculator.php b/plugin/Field/CostsCalculator.php index 32e4a4dec..7ffe4adf1 100644 --- a/plugin/Field/CostsCalculator.php +++ b/plugin/Field/CostsCalculator.php @@ -119,14 +119,15 @@ private function formatPrice(array $totalCostsData, string $currency): array private function formatCurrency(float $amount, string $currency): string { $decimalPlaces = floor($amount) == $amount ? 0 : 2; + return number_format($amount, $decimalPlaces, ',', '.') . ' ' . $currency; } /** - * + * @return array */ - private function getCurrencySymbol() + private function getCurrencySymbol(): array { $parameters = [ 'labels' => true, diff --git a/templates.dist/onoffice-style.css b/templates.dist/onoffice-style.css index eb0c5c66d..199ccae87 100644 --- a/templates.dist/onoffice-style.css +++ b/templates.dist/onoffice-style.css @@ -277,14 +277,14 @@ align-items: flex-start; } -.oo-donut-chart { +.oo-costs-container .oo-donut-chart { width: 40%; padding-bottom: 40%; border-radius: 50%; position: relative; } -.oo-donut-chart::before { +.oo-costs-container .oo-donut-chart::before { content: ''; position: absolute; background: white; @@ -296,30 +296,30 @@ transform: translate(-50%, -50%); } -.oo-costs-overview { +.oo-costs-container .oo-costs-overview { width: 50%; } -.oo-costs-overview > div { +.oo-costs-container .oo-costs-overview > div { margin-bottom: 5px; } -.oo-costs-overview .oo-price-label, -.oo-costs-overview .oo-costs-item { +.oo-costs-container .oo-costs-overview .oo-price-label, +.oo-costs-container .oo-costs-overview .oo-costs-item { display: flex; align-items: center; } -.oo-costs-overview .oo-price-label { +.oo-costs-container .oo-costs-overview .oo-price-label { width: 100%; justify-content: space-between; } -.oo-costs-overview .oo-total-costs-label { +.oo-costs-container .oo-costs-overview .oo-total-costs-label { margin-left: 12px; } -.oo-costs-overview .color-indicator { +.oo-costs-container .oo-costs-overview .color-indicator { display: inline-block; width: 10px; height: 10px; From 3f66a0c1583d8dab6f027405b3d60498e73f88d9 Mon Sep 17 00:00:00 2001 From: "dai.trinh" Date: Mon, 1 Jul 2024 14:32:19 +0700 Subject: [PATCH 07/19] 49984 update chart color --- dist/onoffice_defaultview.min.js | 2 +- js/onoffice_defaultview.js | 2 +- templates.dist/onoffice-style.css | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dist/onoffice_defaultview.min.js b/dist/onoffice_defaultview.min.js index d44f56811..4b273fd7a 100644 --- a/dist/onoffice_defaultview.min.js +++ b/dist/onoffice_defaultview.min.js @@ -1 +1 @@ -(function($){$((function(){$(document).ready((function(){$("#oo-galleryslide").slick({infinite:true,slidesToShow:1});$("#oo-similarframe").slick({infinite:true,arrows:false,dots:true,autoplay:true,slidesToShow:3,slidesToScroll:1,responsive:[{breakpoint:991,settings:{slidesToShow:2}},{breakpoint:575,settings:{slidesToShow:1}}]});if($(".oo-costs-overview").length){initializeDonutChart()}function initializeDonutChart(){const colors=["#00a1e0","#3ac411","#8a56e2","#ff6f61","#ffc72c"];const data=[];let totalCosts=0;$(".oo-costs-overview > div").each((function(index){const value=$(this).attr("data-value");const totalCostsValue=$(this).attr("total-costs-value");if(!isNaN(value)){data.push({value:value,color:colors[index]});$(this).find(".color-indicator").css("background-color",colors[index])}if(!isNaN(totalCostsValue)){totalCosts=totalCostsValue}}));let start=0;let gradientString="conic-gradient(";data.forEach((item=>{const percentage=item.value/totalCosts*100;const end=start+percentage;gradientString+=`${item.color} ${start.toFixed(2)}% ${end.toFixed(2)}%, `;start=end}));gradientString=gradientString.slice(0,-2)+")";$(".oo-donut-chart").css("background",gradientString)}}))}))})(jQuery); \ No newline at end of file +(function($){$((function(){$(document).ready((function(){$("#oo-galleryslide").slick({infinite:true,slidesToShow:1});$("#oo-similarframe").slick({infinite:true,arrows:false,dots:true,autoplay:true,slidesToShow:3,slidesToScroll:1,responsive:[{breakpoint:991,settings:{slidesToShow:2}},{breakpoint:575,settings:{slidesToShow:1}}]});if($(".oo-costs-overview").length){initializeDonutChart()}function initializeDonutChart(){const colors=["#3F9DE4","#3ac411","#9C27B0","#D81B60","#FEC800"];const data=[];let totalCosts=0;$(".oo-costs-overview > div").each((function(index){const value=$(this).attr("data-value");const totalCostsValue=$(this).attr("total-costs-value");if(!isNaN(value)){data.push({value:value,color:colors[index]});$(this).find(".color-indicator").css("background-color",colors[index])}if(!isNaN(totalCostsValue)){totalCosts=totalCostsValue}}));let start=0;let gradientString="conic-gradient(";data.forEach((item=>{const percentage=item.value/totalCosts*100;const end=start+percentage;gradientString+=`${item.color} ${start.toFixed(2)}% ${end.toFixed(2)}%, `;start=end}));gradientString=gradientString.slice(0,-2)+")";$(".oo-donut-chart").css("background",gradientString)}}))}))})(jQuery); \ No newline at end of file diff --git a/js/onoffice_defaultview.js b/js/onoffice_defaultview.js index 8a9bbba95..6851edc23 100644 --- a/js/onoffice_defaultview.js +++ b/js/onoffice_defaultview.js @@ -31,7 +31,7 @@ } function initializeDonutChart() { - const colors = ['#00a1e0', '#3ac411', '#8a56e2', '#ff6f61', '#ffc72c']; + const colors = ['#3F9DE4', '#3ac411', '#9C27B0', '#D81B60', '#FEC800']; const data = []; let totalCosts = 0; diff --git a/templates.dist/onoffice-style.css b/templates.dist/onoffice-style.css index 199ccae87..ab3dcf12a 100644 --- a/templates.dist/onoffice-style.css +++ b/templates.dist/onoffice-style.css @@ -321,8 +321,8 @@ .oo-costs-container .oo-costs-overview .color-indicator { display: inline-block; - width: 10px; - height: 10px; + width: 14px; + height: 14px; border-radius: 50%; margin-right: 5px; vertical-align: middle; From cc75a86994f04b3bd0c1644bc615ef2fea2f6825 Mon Sep 17 00:00:00 2001 From: Helene Neufeld <70378166+miauzjpg@users.noreply.github.com> Date: Tue, 26 Nov 2024 11:36:21 +0100 Subject: [PATCH 08/19] Update default_detail.php --- templates.dist/estate/default_detail.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates.dist/estate/default_detail.php b/templates.dist/estate/default_detail.php index 3ab1c5496..5a71958ea 100644 --- a/templates.dist/estate/default_detail.php +++ b/templates.dist/estate/default_detail.php @@ -273,7 +273,7 @@ function renderEnergyCertificate(string $energyCertificateType, array $energyCla getTotalCostsData())) { $totalCostsData = $pEstates->getTotalCostsData(); ?> -
+

@@ -588,4 +588,4 @@ function headingLink($url, $title) text-decoration: none; color: #000; } - \ No newline at end of file + From 0a4125d25cf0d23f5dc3188b7cea5597bdab85b0 Mon Sep 17 00:00:00 2001 From: Helene Neufeld <70378166+miauzjpg@users.noreply.github.com> Date: Tue, 26 Nov 2024 11:37:32 +0100 Subject: [PATCH 09/19] Update onoffice-style.css --- templates.dist/onoffice-style.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates.dist/onoffice-style.css b/templates.dist/onoffice-style.css index 60491e46f..1211a873b 100644 --- a/templates.dist/onoffice-style.css +++ b/templates.dist/onoffice-style.css @@ -222,7 +222,7 @@ font-weight: 700; } -.oo-detailsfreetext, .oo-detailsmap, .oo-area-butler { +.oo-detailsfreetext, .oo-detailsmap, .oo-area-butler, .oo-detailspricecalculator { padding-bottom: 15px; padding-top: 15px; border-bottom: 2px solid #efefef; From 8ecc2e00de45a4190dc56f8d6e431976816ebae8 Mon Sep 17 00:00:00 2001 From: Helene Neufeld <70378166+miauzjpg@users.noreply.github.com> Date: Tue, 26 Nov 2024 12:01:38 +0100 Subject: [PATCH 10/19] Update onoffice-style.css added responsive css --- templates.dist/onoffice-style.css | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/templates.dist/onoffice-style.css b/templates.dist/onoffice-style.css index 1211a873b..d5d1e0319 100644 --- a/templates.dist/onoffice-style.css +++ b/templates.dist/onoffice-style.css @@ -419,6 +419,26 @@ .oo-details-sidebar { width: 50%; } + + .oo-costs-container { + width: 100%; + display: flex; + justify-content: space-between; + align-items: center; + flex-direction: column; + gap: 2rem; + } + + .oo-costs-container .oo-donut-chart { + width: 100%; + padding-bottom: 100%; + border-radius: 100%; + position: relative; + } + + .oo-costs-container .oo-costs-overview { + width: 100%; + } } @media only screen and (max-width: 700px) { From ab5788a2490586ec550c02c44bcf906847cffa8d Mon Sep 17 00:00:00 2001 From: Helene Neufeld <70378166+miauzjpg@users.noreply.github.com> Date: Tue, 26 Nov 2024 12:30:15 +0100 Subject: [PATCH 11/19] Update output_default_detail.html --- tests/resources/templates/output_default_detail.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/resources/templates/output_default_detail.html b/tests/resources/templates/output_default_detail.html index 427800225..0fae1ee86 100644 --- a/tests/resources/templates/output_default_detail.html +++ b/tests/resources/templates/output_default_detail.html @@ -66,7 +66,7 @@

label-ausstatt_beschr

label-sonstige_angaben

Vereinbaren sie noch heute einen Besichtigungstermin
-
+

Total costs

@@ -152,4 +152,4 @@

Documents

text-decoration: none; color: #000; } - \ No newline at end of file + From b6cdc165a5f3766a6d991d2409ae0784612c9abe Mon Sep 17 00:00:00 2001 From: "dai.trinh" Date: Wed, 27 Nov 2024 14:21:53 +0700 Subject: [PATCH 12/19] 49984 update unit test --- tests/resources/templates/output_default_detail.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/resources/templates/output_default_detail.html b/tests/resources/templates/output_default_detail.html index 0fae1ee86..5d269a203 100644 --- a/tests/resources/templates/output_default_detail.html +++ b/tests/resources/templates/output_default_detail.html @@ -66,7 +66,7 @@

label-ausstatt_beschr

label-sonstige_angaben

Vereinbaren sie noch heute einen Besichtigungstermin
-
+

Total costs

From d3270bb09b051d3531a3b0d82d9cf7b94176c108 Mon Sep 17 00:00:00 2001 From: miauzjpg Date: Wed, 18 Dec 2024 11:16:57 +0100 Subject: [PATCH 13/19] added svg chart --- plugin/DonutChart.php | 106 +++++++++++++++++++++++ templates.dist/estate/default_detail.php | 54 +++++++++--- templates.dist/onoffice-style.css | 24 +---- 3 files changed, 151 insertions(+), 33 deletions(-) create mode 100644 plugin/DonutChart.php diff --git a/plugin/DonutChart.php b/plugin/DonutChart.php new file mode 100644 index 000000000..bde09311b --- /dev/null +++ b/plugin/DonutChart.php @@ -0,0 +1,106 @@ +. + * + */ + +namespace onOffice\WPlugin; + +use onOffice\WPlugin\EstateList; +/** + * + * @url http://www.onoffice.de + * @copyright 2003-2017, onOffice(R) GmbH + * + */ + class DonutChart + { + private $values; + private $valuesTitle; + private $colors; + + public function __construct(array $values, array $valuesTitle, array $colors) + { + $this->values = $values; + $this->valuesTitle = $valuesTitle; + $this->colors = $colors; + } + + private function toRadians($angle) + { + return $angle * pi() / 180; + } + + + public function getColors($i = null) { + if ($i === null) { + return $this->colors; + } + + if (isset($this->colors[$i])) { + return $this->colors[$i]; + } else { + return ""; + } + + } + private function polarToCartesian($radius, $angle, $subtractGap = false) + { + $adjustedAngle = $this->toRadians($angle - 90); + if ($subtractGap) { + $adjustedAngle -= asin(0 / $radius); + } + $x = 300+ $radius * cos($adjustedAngle); + $y = 210 + $radius * sin($adjustedAngle); + + return sprintf('%0.2f,%0.2f', $x, $y); + } + + public function generateSVG() + { + $total = array_sum($this->values); + //$total = getTotalCostsData(); + $anglePerValue = 360 / $total; + $angleStart = 0; + + $svgContent = "\n"; + $svgContent .= "\n"; + + $counter = 0; + foreach ($this->values as $value) { + $angleDelta = $value * $anglePerValue; + $largeArcFlag = $angleDelta > 180 ? 1 : 0; + $angleEnd = $angleStart + $angleDelta; + + $path = [ + "M" . $this->polarToCartesian(190, $angleStart), + "L" . $this->polarToCartesian(120, $angleStart), + "A 120,120,0,{$largeArcFlag},1," . $this->polarToCartesian(120, $angleEnd, true), + "L" . $this->polarToCartesian(190, $angleEnd, true), + "A 190,190,0,{$largeArcFlag},0," . $this->polarToCartesian(190, $angleStart) + ]; + + $svgContent .= ''.$this->valuesTitle[$counter].'' . "\n"; + $angleStart = $angleEnd; + $counter++; + } + + $svgContent .= "\n"; + return $svgContent; + } + } \ No newline at end of file diff --git a/templates.dist/estate/default_detail.php b/templates.dist/estate/default_detail.php index 90840017c..7a2ffa3a9 100644 --- a/templates.dist/estate/default_detail.php +++ b/templates.dist/estate/default_detail.php @@ -20,8 +20,8 @@ */ use onOffice\WPlugin\EstateDetail; +use onOffice\WPlugin\DonutChart; use onOffice\WPlugin\ViewFieldModifier\EstateViewFieldModifierTypes; - /** * * Default template @@ -85,6 +85,8 @@ padding: 0 10px; } + +
resetEstateIterator(); @@ -272,49 +274,74 @@ function renderEnergyCertificate(string $energyCertificateType, array $energyCla getTotalCostsData())) { $totalCostsData = $pEstates->getTotalCostsData(); + ?> + + +

-
+
+ generateSVG(); ?> + + +
+ + + + +

-
- +
+
getFieldLabel('kaufpreis')); ?>
-
- +
+
-
- +
+
-
- +
+
-
- +
+
-
+
@@ -562,6 +589,7 @@ function headingLink($url, $title) ?>
+
diff --git a/templates.dist/onoffice-style.css b/templates.dist/onoffice-style.css index 6454b1de1..aa72b9341 100644 --- a/templates.dist/onoffice-style.css +++ b/templates.dist/onoffice-style.css @@ -282,31 +282,18 @@ .oo-costs-container { width: 100%; display: flex; - justify-content: space-between; + justify-content: flex-start; align-items: flex-start; } .oo-costs-container .oo-donut-chart { width: 40%; - padding-bottom: 40%; - border-radius: 50%; - position: relative; } -.oo-costs-container .oo-donut-chart::before { - content: ''; - position: absolute; - background: white; - width: 70%; - height: 70%; - border-radius: 50%; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); -} + .oo-costs-container .oo-costs-overview { - width: 50%; + width: 40%; } .oo-costs-container .oo-costs-overview > div { @@ -325,7 +312,7 @@ } .oo-costs-container .oo-costs-overview .oo-total-costs-label { - margin-left: 12px; + margin-left: 20px; } .oo-costs-container .oo-costs-overview .color-indicator { @@ -446,9 +433,6 @@ .oo-costs-container .oo-donut-chart { width: 100%; - padding-bottom: 100%; - border-radius: 100%; - position: relative; } .oo-costs-container .oo-costs-overview { From 618ec4b7e701f8ec5a250a7f175fb5bf9f29d10a Mon Sep 17 00:00:00 2001 From: miauzjpg Date: Thu, 19 Dec 2024 11:00:12 +0100 Subject: [PATCH 14/19] changed unit test --- .../templates/output_default_detail.html | 48 ++++++++++++++----- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/tests/resources/templates/output_default_detail.html b/tests/resources/templates/output_default_detail.html index 51f074bb0..313dbbf2d 100644 --- a/tests/resources/templates/output_default_detail.html +++ b/tests/resources/templates/output_default_detail.html @@ -3,6 +3,8 @@ padding: 0 10px; } + +

flach begrüntes Grundstück

@@ -66,48 +68,67 @@

label-ausstatt_beschr

label-sonstige_angaben

Vereinbaren sie noch heute einen Besichtigungstermin
-
+ + + +

Total costs

-
+
+ + +123.456,56 € +4.321 € +22.222 € +1.852 € +617 € + + + +
+ + + + +

Overview of costs

-
- +
+
label-kaufpreis
123.456,56 €
-
- +
+
Property transfer tax
4.321 €
-
- +
+
Broker commission
22.222 €
-
- +
+
Notary Fees
1.852 €
-
- +
+
Land Register Entry
617 €
-
+
Total costs
152.468,56 €
@@ -142,6 +163,7 @@

Documents

test ogulo link
+
Similar Estates here
From be51cd3d2e1670661d5bd389057cc866b6c8f858 Mon Sep 17 00:00:00 2001 From: miauzjpg Date: Thu, 19 Dec 2024 11:27:39 +0100 Subject: [PATCH 15/19] optimized code --- templates.dist/estate/default_detail.php | 18 ------------------ .../templates/output_default_detail.html | 14 ++------------ 2 files changed, 2 insertions(+), 30 deletions(-) diff --git a/templates.dist/estate/default_detail.php b/templates.dist/estate/default_detail.php index 7a2ffa3a9..3da50a30e 100644 --- a/templates.dist/estate/default_detail.php +++ b/templates.dist/estate/default_detail.php @@ -276,34 +276,16 @@ function renderEnergyCertificate(string $energyCertificateType, array $energyCla $totalCostsData = $pEstates->getTotalCostsData(); ?> - - -

generateSVG(); ?> - -
- - - - -

diff --git a/tests/resources/templates/output_default_detail.html b/tests/resources/templates/output_default_detail.html index 313dbbf2d..7c499c8a1 100644 --- a/tests/resources/templates/output_default_detail.html +++ b/tests/resources/templates/output_default_detail.html @@ -68,10 +68,7 @@

label-ausstatt_beschr

label-sonstige_angaben

Vereinbaren sie noch heute einen Besichtigungstermin
- - - -
+

Total costs

@@ -83,14 +80,7 @@

Total costs

1.852 € 617 € - - -
- - - - - +

Overview of costs

From b41a3a95e9a65b2cb257efeb85e6b85307741348 Mon Sep 17 00:00:00 2001 From: miauzjpg Date: Thu, 19 Dec 2024 12:37:46 +0100 Subject: [PATCH 16/19] optimized colors --- plugin/DonutChart.php | 20 +++------------- templates.dist/estate/default_detail.php | 12 +++++----- templates.dist/onoffice-style.css | 24 ++++++++++++++++++- .../templates/output_default_detail.html | 20 ++++++++-------- 4 files changed, 42 insertions(+), 34 deletions(-) diff --git a/plugin/DonutChart.php b/plugin/DonutChart.php index bde09311b..27ae6eca9 100644 --- a/plugin/DonutChart.php +++ b/plugin/DonutChart.php @@ -32,13 +32,12 @@ class DonutChart { private $values; private $valuesTitle; - private $colors; + private $colors = ['#3F9DE4', '#3ac411', '#9C27B0', '#D81B60', '#FEC800']; - public function __construct(array $values, array $valuesTitle, array $colors) + public function __construct(array $values, array $valuesTitle) { $this->values = $values; $this->valuesTitle = $valuesTitle; - $this->colors = $colors; } private function toRadians($angle) @@ -46,19 +45,6 @@ private function toRadians($angle) return $angle * pi() / 180; } - - public function getColors($i = null) { - if ($i === null) { - return $this->colors; - } - - if (isset($this->colors[$i])) { - return $this->colors[$i]; - } else { - return ""; - } - - } private function polarToCartesian($radius, $angle, $subtractGap = false) { $adjustedAngle = $this->toRadians($angle - 90); @@ -95,7 +81,7 @@ public function generateSVG() "A 190,190,0,{$largeArcFlag},0," . $this->polarToCartesian(190, $angleStart) ]; - $svgContent .= ''.$this->valuesTitle[$counter].'' . "\n"; + $svgContent .= ''.$this->valuesTitle[$counter].'' . "\n"; $angleStart = $angleEnd; $counter++; } diff --git a/templates.dist/estate/default_detail.php b/templates.dist/estate/default_detail.php index 3da50a30e..0e2038358 100644 --- a/templates.dist/estate/default_detail.php +++ b/templates.dist/estate/default_detail.php @@ -283,41 +283,41 @@ function renderEnergyCertificate(string $energyCertificateType, array $energyCla generateSVG(); ?>

- +
getFieldLabel('kaufpreis')); ?>
- +
- +
- +
- +
diff --git a/templates.dist/onoffice-style.css b/templates.dist/onoffice-style.css index aa72b9341..ead52b5c8 100644 --- a/templates.dist/onoffice-style.css +++ b/templates.dist/onoffice-style.css @@ -408,6 +408,28 @@ z-index: 888; } +.oo-donut-chart-color0 { + fill:#3F9DE4; + background-color:#3F9DE4; +} + +.oo-donut-chart-color1 { + fill:#3ac411; + background-color:#3ac411; +} +.oo-donut-chart-color2 { + fill:#9C27B0; + background-color:#9C27B0; +} +.oo-donut-chart-color3 { + fill:#D81B60; + background-color:#D81B60; +} +.oo-donut-chart-color4 { + fill:#FEC800; + background-color:#FEC800; +} + /* responsive */ @media only screen and (max-width: 991px) { .oo-listobject, .oo-searchformfield { @@ -450,4 +472,4 @@ .oo-listobject, .oo-searchformfield, .oo-details-sidebar { width: 100%; } -} +} \ No newline at end of file diff --git a/tests/resources/templates/output_default_detail.html b/tests/resources/templates/output_default_detail.html index 7c499c8a1..fc0f35ab7 100644 --- a/tests/resources/templates/output_default_detail.html +++ b/tests/resources/templates/output_default_detail.html @@ -74,45 +74,45 @@

Total costs

-123.456,56 € -4.321 € -22.222 € -1.852 € -617 € +123.456,56 € +4.321 € +22.222 € +1.852 € +617 €

Overview of costs

- +
label-kaufpreis
123.456,56 €
- +
Property transfer tax
4.321 €
- +
Broker commission
22.222 €
- +
Notary Fees
1.852 €
- +
Land Register Entry
617 €
From b350f78030e519a73a2410ae1c95b85973e8ad80 Mon Sep 17 00:00:00 2001 From: miauzjpg Date: Fri, 20 Dec 2024 08:35:22 +0100 Subject: [PATCH 17/19] deleted unused code --- js/onoffice_defaultview.js | 37 ------------------------------------- 1 file changed, 37 deletions(-) diff --git a/js/onoffice_defaultview.js b/js/onoffice_defaultview.js index 25ffa2ac2..9eddb4d48 100644 --- a/js/onoffice_defaultview.js +++ b/js/onoffice_defaultview.js @@ -26,43 +26,6 @@ }] }); - if ($('.oo-costs-overview').length) { - initializeDonutChart(); - } - - function initializeDonutChart() { - const colors = ['#3F9DE4', '#3ac411', '#9C27B0', '#D81B60', '#FEC800']; - const data = []; - let totalCosts = 0; - - $('.oo-costs-overview > div').each(function(index) { - const value = $(this).attr('data-value'); - const totalCostsValue = $(this).attr('total-costs-value'); - if (!isNaN(value)) { - data.push({ - value: value, - color: colors[index] - }); - $(this).find('.color-indicator').css('background-color', colors[index]); - } - if (!isNaN(totalCostsValue)) { - totalCosts = totalCostsValue; - } - }); - - let start = 0; - let gradientString = 'conic-gradient('; - data.forEach((item) => { - const percentage = (item.value / totalCosts) * 100; - const end = start + percentage; - gradientString += `${item.color} ${start.toFixed(2)}% ${end.toFixed(2)}%, `; - start = end; - }); - - gradientString = gradientString.slice(0, -2) + ')'; - $('.oo-donut-chart').css('background', gradientString); - } - applyGradientToSegments(); function applyGradientToSegments() { From 41aa48603b87ff6735808fe8aec71fd696f461f9 Mon Sep 17 00:00:00 2001 From: miauzjpg Date: Mon, 23 Dec 2024 09:11:19 +0100 Subject: [PATCH 18/19] changed css --- plugin/DonutChart.php | 4 ++-- templates.dist/onoffice-style.css | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/plugin/DonutChart.php b/plugin/DonutChart.php index 27ae6eca9..e999f76b1 100644 --- a/plugin/DonutChart.php +++ b/plugin/DonutChart.php @@ -75,8 +75,8 @@ public function generateSVG() $path = [ "M" . $this->polarToCartesian(190, $angleStart), - "L" . $this->polarToCartesian(120, $angleStart), - "A 120,120,0,{$largeArcFlag},1," . $this->polarToCartesian(120, $angleEnd, true), + "L" . $this->polarToCartesian(130, $angleStart), + "A 130,130,0,{$largeArcFlag},1," . $this->polarToCartesian(130, $angleEnd, true), "L" . $this->polarToCartesian(190, $angleEnd, true), "A 190,190,0,{$largeArcFlag},0," . $this->polarToCartesian(190, $angleStart) ]; diff --git a/templates.dist/onoffice-style.css b/templates.dist/onoffice-style.css index 2063cb9f1..e84d696d2 100644 --- a/templates.dist/onoffice-style.css +++ b/templates.dist/onoffice-style.css @@ -321,7 +321,9 @@ height: 14px; border-radius: 50%; margin-right: 5px; - vertical-align: middle; + flex-basis: 14px; + flex-grow: 0; + flex-shrink: 0; } .oo-details-energy-certificate { From 4bc60ae0a3fd1bfee18760706aeeb63165968392 Mon Sep 17 00:00:00 2001 From: miauzjpg Date: Mon, 23 Dec 2024 09:40:40 +0100 Subject: [PATCH 19/19] changed unit test --- tests/resources/templates/output_default_detail.html | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/resources/templates/output_default_detail.html b/tests/resources/templates/output_default_detail.html index fc0f35ab7..8e083822d 100644 --- a/tests/resources/templates/output_default_detail.html +++ b/tests/resources/templates/output_default_detail.html @@ -74,11 +74,11 @@

Total costs

-123.456,56 € -4.321 € -22.222 € -1.852 € -617 € +123.456,56 € +4.321 € +22.222 € +1.852 € +617 €