ver. 0.274 - ShopProduct mass_edit + tree UI cleanup
This commit is contained in:
@@ -244,4 +244,157 @@ class ProductRepository
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pobiera listę wszystkich produktów głównych (id => name) do masowej edycji.
|
||||
* Zwraca tylko produkty bez parent_id (bez kombinacji).
|
||||
*
|
||||
* @return array<int, string> Mapa id => nazwa produktu
|
||||
*/
|
||||
public function allProductsForMassEdit(): array
|
||||
{
|
||||
$defaultLang = $this->db->get( 'pp_langs', 'id', [ 'start' => 1 ] );
|
||||
if ( !$defaultLang ) {
|
||||
$defaultLang = 'pl';
|
||||
}
|
||||
|
||||
$results = $this->db->select( 'pp_shop_products', 'id', [ 'parent_id' => null ] );
|
||||
$products = [];
|
||||
|
||||
if ( is_array( $results ) ) {
|
||||
foreach ( $results as $id ) {
|
||||
$name = $this->db->get( 'pp_shop_products_langs', 'name', [
|
||||
'AND' => [ 'product_id' => $id, 'lang_id' => $defaultLang ]
|
||||
] );
|
||||
$products[ (int) $id ] = $name ?: '';
|
||||
}
|
||||
}
|
||||
|
||||
return $products;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pobiera listę ID produktów przypisanych do danej kategorii.
|
||||
*
|
||||
* @param int $categoryId ID kategorii
|
||||
* @return int[] Lista ID produktów
|
||||
*/
|
||||
public function getProductsByCategory(int $categoryId): array
|
||||
{
|
||||
$results = $this->db->select(
|
||||
'pp_shop_products_categories',
|
||||
'product_id',
|
||||
[ 'category_id' => $categoryId ]
|
||||
);
|
||||
|
||||
return is_array( $results ) ? $results : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Aplikuje rabat procentowy na produkt (cena promocyjna = cena - X%).
|
||||
* Aktualizuje również ceny kombinacji produktu.
|
||||
*
|
||||
* @param int $productId ID produktu
|
||||
* @param float $discountPercent Procent rabatu
|
||||
* @return array|null Tablica z price_brutto i price_brutto_promo lub null przy błędzie
|
||||
*/
|
||||
public function applyDiscountPercent(int $productId, float $discountPercent): ?array
|
||||
{
|
||||
$product = $this->db->get( 'pp_shop_products', [
|
||||
'vat', 'price_brutto', 'price_netto'
|
||||
], [ 'id' => $productId ] );
|
||||
|
||||
if ( !$product ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$vat = $product['vat'];
|
||||
$priceBrutto = (float) $product['price_brutto'];
|
||||
$priceNetto = (float) $product['price_netto'];
|
||||
|
||||
$priceBruttoPromo = $priceBrutto - ( $priceBrutto * ( $discountPercent / 100 ) );
|
||||
$priceNettoPromo = $priceNetto - ( $priceNetto * ( $discountPercent / 100 ) );
|
||||
|
||||
if ( $priceBrutto == $priceBruttoPromo ) {
|
||||
$priceBruttoPromo = null;
|
||||
}
|
||||
if ( $priceNetto == $priceNettoPromo ) {
|
||||
$priceNettoPromo = null;
|
||||
}
|
||||
|
||||
$this->db->update( 'pp_shop_products', [
|
||||
'price_brutto_promo' => $priceBruttoPromo,
|
||||
'price_netto_promo' => $priceNettoPromo
|
||||
], [ 'id' => $productId ] );
|
||||
|
||||
$this->updateCombinationPrices( $productId, $priceNetto, $vat, $priceNettoPromo );
|
||||
|
||||
return [
|
||||
'price_brutto' => $priceBrutto,
|
||||
'price_brutto_promo' => $priceBruttoPromo
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Aktualizuje ceny kombinacji produktu uwzględniając wpływ na cenę (impact_on_the_price).
|
||||
*
|
||||
* @param int $productId ID produktu nadrzędnego
|
||||
* @param float $priceNetto Cena netto bazowa
|
||||
* @param float $vat Stawka VAT
|
||||
* @param float|null $priceNettoPromo Cena promo netto bazowa (null = brak)
|
||||
*/
|
||||
private function updateCombinationPrices(int $productId, float $priceNetto, float $vat, ?float $priceNettoPromo): void
|
||||
{
|
||||
$priceBrutto = \S::normalize_decimal( $priceNetto * ( 100 + $vat ) / 100, 2 );
|
||||
$priceBruttoPromo = $priceNettoPromo !== null
|
||||
? \S::normalize_decimal( $priceNettoPromo * ( 100 + $vat ) / 100, 2 )
|
||||
: null;
|
||||
|
||||
$combinations = $this->db->query(
|
||||
'SELECT psp.id '
|
||||
. 'FROM pp_shop_products AS psp '
|
||||
. 'INNER JOIN pp_shop_products_attributes AS pspa ON psp.id = pspa.product_id '
|
||||
. 'INNER JOIN pp_shop_attributes_values AS psav ON pspa.value_id = psav.id '
|
||||
. 'WHERE psav.impact_on_the_price > 0 AND psp.parent_id = :product_id',
|
||||
[ ':product_id' => $productId ]
|
||||
);
|
||||
|
||||
if ( !$combinations ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$rows = $combinations->fetchAll( \PDO::FETCH_ASSOC );
|
||||
foreach ( $rows as $row ) {
|
||||
$combBrutto = $priceBrutto;
|
||||
$combBruttoPromo = $priceBruttoPromo;
|
||||
|
||||
$values = $this->db->query(
|
||||
'SELECT impact_on_the_price FROM pp_shop_attributes_values AS psav '
|
||||
. 'INNER JOIN pp_shop_products_attributes AS pspa ON pspa.value_id = psav.id '
|
||||
. 'WHERE impact_on_the_price IS NOT NULL AND product_id = :product_id',
|
||||
[ ':product_id' => $row['id'] ]
|
||||
);
|
||||
|
||||
if ( $values ) {
|
||||
foreach ( $values->fetchAll( \PDO::FETCH_ASSOC ) as $value ) {
|
||||
$combBrutto += $value['impact_on_the_price'];
|
||||
if ( $combBruttoPromo !== null ) {
|
||||
$combBruttoPromo += $value['impact_on_the_price'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$combNetto = \S::normalize_decimal( $combBrutto / ( 100 + $vat ) * 100, 2 );
|
||||
$combNettoPromo = $combBruttoPromo !== null
|
||||
? \S::normalize_decimal( $combBruttoPromo / ( 100 + $vat ) * 100, 2 )
|
||||
: null;
|
||||
|
||||
$this->db->update( 'pp_shop_products', [
|
||||
'price_netto' => $combNetto,
|
||||
'price_brutto' => $combBrutto,
|
||||
'price_netto_promo' => $combNettoPromo,
|
||||
'price_brutto_promo' => $combBruttoPromo
|
||||
], [ 'id' => $row['id'] ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -440,7 +440,9 @@ class ArticlesController
|
||||
$html .= '<ol class="sortable" id="sortable_' . $menuId . '">';
|
||||
$html .= '<li id="list_' . $menuId . '" class="menu_' . $menuId . '" menu="' . $menuId . '">';
|
||||
$html .= '<div class="context_0 content content_menu"' . ($menuStatus ? '' : ' style="color: #cc0000;"') . '>';
|
||||
$html .= '<span class="disclose"><span></span></span>Menu: <b>' . $menuName . '</b>';
|
||||
$html .= '<button type="button" class="disclose layout-tree-toggle" aria-expanded="false" title="Rozwin / zwin">'
|
||||
. '<i class="fa fa-caret-right"></i>'
|
||||
. '</button>Menu: <b>' . $menuName . '</b>';
|
||||
$html .= '</div>';
|
||||
$html .= \Tpl::view('articles/subpages-list', [
|
||||
'pages' => $menuPages,
|
||||
|
||||
70
autoload/admin/Controllers/ShopProductController.php
Normal file
70
autoload/admin/Controllers/ShopProductController.php
Normal file
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
namespace admin\Controllers;
|
||||
|
||||
use Domain\Product\ProductRepository;
|
||||
|
||||
/**
|
||||
* Kontroler masowej edycji produktów.
|
||||
* Obsługuje akcje: mass_edit (widok), mass_edit_save (AJAX), get_products_by_category (AJAX).
|
||||
* Pozostałe akcje shop_product (view_list, product_edit, save itd.) nadal działają
|
||||
* przez fallback na \admin\controls\ShopProduct.
|
||||
*/
|
||||
class ShopProductController
|
||||
{
|
||||
private ProductRepository $repository;
|
||||
|
||||
public function __construct(ProductRepository $repository)
|
||||
{
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Widok masowej edycji produktów.
|
||||
*/
|
||||
public function mass_edit(): string
|
||||
{
|
||||
return \Tpl::view( 'shop-product/mass-edit', [
|
||||
'products' => $this->repository->allProductsForMassEdit(),
|
||||
'categories' => \admin\factory\ShopCategory::subcategories( null ),
|
||||
'dlang' => \front\factory\Languages::default_language()
|
||||
] );
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX: zastosowanie rabatu procentowego na zaznaczonych produktach.
|
||||
*/
|
||||
public function mass_edit_save(): void
|
||||
{
|
||||
$discountPercent = \S::get( 'discount_percent' );
|
||||
$products = \S::get( 'products' );
|
||||
|
||||
if ( $discountPercent != '' && $products && is_array( $products ) && count( $products ) > 0 ) {
|
||||
$productId = (int) $products[0];
|
||||
$result = $this->repository->applyDiscountPercent( $productId, (float) $discountPercent );
|
||||
|
||||
if ( $result !== null ) {
|
||||
echo json_encode( [
|
||||
'status' => 'ok',
|
||||
'price_brutto_promo' => $result['price_brutto_promo'],
|
||||
'price_brutto' => $result['price_brutto']
|
||||
] );
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode( [ 'status' => 'error' ] );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX: pobranie ID produktów z danej kategorii.
|
||||
*/
|
||||
public function get_products_by_category(): void
|
||||
{
|
||||
$categoryId = (int) \S::get( 'category_id' );
|
||||
$products = $this->repository->getProductsByCategory( $categoryId );
|
||||
|
||||
echo json_encode( [ 'status' => 'ok', 'products' => $products ] );
|
||||
exit;
|
||||
}
|
||||
}
|
||||
@@ -377,6 +377,13 @@ class Site
|
||||
new \Domain\Languages\LanguagesRepository( $mdb )
|
||||
);
|
||||
},
|
||||
'ShopProduct' => function() {
|
||||
global $mdb;
|
||||
|
||||
return new \admin\Controllers\ShopProductController(
|
||||
new \Domain\Product\ProductRepository( $mdb )
|
||||
);
|
||||
},
|
||||
];
|
||||
|
||||
return self::$newControllers;
|
||||
|
||||
@@ -2,56 +2,6 @@
|
||||
namespace admin\controls;
|
||||
class ShopProduct
|
||||
{
|
||||
static public function mass_edit_save()
|
||||
{
|
||||
global $mdb;
|
||||
|
||||
if ( \S::get( 'discount_percent' ) != '' and \S::get( 'products' ) )
|
||||
{
|
||||
$product_details = \admin\factory\ShopProduct::product_details( \S::get( 'products' )[0] );
|
||||
|
||||
$vat = $product_details['vat'];
|
||||
$price_brutto = $product_details['price_brutto'];
|
||||
$price_brutto_promo = $price_brutto - ( $price_brutto * ( \S::get( 'discount_percent' ) / 100 ) );
|
||||
$price_netto = $product_details['price_netto'];
|
||||
$price_netto_promo = $price_netto - ( $price_netto * ( \S::get( 'discount_percent' ) / 100 ) );
|
||||
|
||||
if ( $price_brutto == $price_brutto_promo)
|
||||
$price_brutto_promo = null;
|
||||
|
||||
if ( $price_netto == $price_netto_promo )
|
||||
$price_netto_promo = null;
|
||||
|
||||
$mdb -> update( 'pp_shop_products', [ 'price_brutto_promo' => $price_brutto_promo, 'price_netto_promo' => $price_netto_promo ], [ 'id' => \S::get( 'products' )[0] ] );
|
||||
|
||||
\admin\factory\ShopProduct::update_product_combinations_prices( \S::get( 'products' )[0], $price_netto, $vat, $price_netto_promo );
|
||||
|
||||
echo json_encode( [ 'status' => 'ok', 'price_brutto_promo' => $price_brutto_promo, 'price_brutto' => $price_brutto ] );
|
||||
exit;
|
||||
}
|
||||
echo json_encode( [ 'status' => 'error' ] );
|
||||
exit;
|
||||
}
|
||||
|
||||
// get_products_by_category
|
||||
static public function get_products_by_category() {
|
||||
global $mdb;
|
||||
|
||||
$products = $mdb -> select( 'pp_shop_products_categories', 'product_id', [ 'category_id' => \S::get( 'category_id' ) ] );
|
||||
|
||||
echo json_encode( [ 'status' => 'ok', 'products' => $products ] );
|
||||
exit;
|
||||
}
|
||||
|
||||
static public function mass_edit()
|
||||
{
|
||||
return \Tpl::view( 'shop-product/mass-edit', [
|
||||
'products' => \admin\factory\ShopProduct::products_list(),
|
||||
'categories' => \admin\factory\ShopCategory::subcategories( null ),
|
||||
'dlang' => \front\factory\Languages::default_language()
|
||||
] );
|
||||
}
|
||||
|
||||
static public function generate_combination()
|
||||
{
|
||||
foreach ( $_POST as $key => $val )
|
||||
|
||||
Reference in New Issue
Block a user