Complete Domain-Driven Architecture migration: - Phase 1-4: Transport, ProductSet, Coupon, Shop, Search, Basket, ProductCustomField, Category, ProductAttribute, Promotion - Phase 5: Order (~562 lines) + Product (~952 lines) - ~20 Product methods migrated to ProductRepository - Apilo sync migrated to OrderAdminService - Production hotfixes: stale Redis cache (prices 0.00), unqualified Product:: refs in LayoutEngine, object->array template conversion - AttributeRepository::getAttributeValueById() Redis cache added Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
233 lines
9.4 KiB
PHP
233 lines
9.4 KiB
PHP
<div class="g-container" data="table:order-details">
|
|
<div class="panel panel-info panel-border top">
|
|
<div class="panel-heading">
|
|
<span class="panel-title">Kombinacje produktu: <?= $this -> product['languages'][ $this -> default_language ]['name'];?></span>
|
|
</div>
|
|
<div class="panel-heading p10 pl15" id="g-menu" style="height: auto;">
|
|
<a class="btn btn btn-dark btn-sm mr5 btn-sm mr5" href="/admin/shop_product/view_list/"><i class="fa fa-reply mr5"></i>Wstecz</a>
|
|
</div>
|
|
<div class="panel-body">
|
|
<div class="row">
|
|
<div class="col-lg-7 col-xl-9">
|
|
<div class="table-responsive">
|
|
<table class="table table-hover table-bordered table-condensed">
|
|
<thead>
|
|
<tr>
|
|
<th>Kombinacja</th>
|
|
<th>SKU</th>
|
|
<th>Stan magazynowy</th>
|
|
<th>Cena netto</th>
|
|
<th>Zam. przy braku</th>
|
|
<th style="width: 100px;">Opcje</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<? if ( \Shared\Helpers\Helpers::is_array_fix( $this -> product_permutations ) ): foreach ( $this -> product_permutations as $product ):?>
|
|
<tr data-combination-id="<?= $product['id'];?>">
|
|
<td>
|
|
<?
|
|
$attributes = explode( '|', $product['permutation_hash'] );
|
|
foreach ( $attributes as $attribute ):
|
|
$attribute_tmp = explode( '-', $attribute );
|
|
$attrRepo = new \Domain\Attribute\AttributeRepository( $GLOBALS['mdb'] );
|
|
echo $attrRepo->getAttributeNameById( (int)$attribute_tmp[0], $this -> default_language ) . ' - <b>' . $attrRepo->getAttributeValueById( (int)$attribute_tmp[1], $this -> default_language ) . '</b>';
|
|
if ( $attribute != end( $attributes ) )
|
|
echo ', ';
|
|
endforeach;
|
|
?>
|
|
</td>
|
|
<td>
|
|
<input type="text" value="<?= $product['sku'];?>" class="form-control combination-field" style="max-width: 100px;" data-product-id="<?= $product['id'];?>" data-field="sku">
|
|
</td>
|
|
<td>
|
|
<input type="text" value="<?= $product['quantity'];?>" class="form-control combination-field" style="max-width: 100px;" data-product-id="<?= $product['id'];?>" data-field="quantity">
|
|
</td>
|
|
<td>
|
|
<input type="text" value="<?= $product['price_netto'];?>" class="form-control combination-field" style="max-width: 100px;" data-product-id="<?= $product['id'];?>" data-field="price">
|
|
</td>
|
|
<td>
|
|
<input type="checkbox" class="g-checkbox combination-checkbox" data-product-id="<?= $product['id'];?>" <? if ( $product['stock_0_buy'] ): echo 'checked="checked"'; endif;?>>
|
|
</td>
|
|
<td class="text-center">
|
|
<button type="button" class="btn btn-danger btn-delete-permutation" data-combination-id="<?= $product['id'];?>"><i class="fa fa-trash"></i></button>
|
|
</td>
|
|
</tr>
|
|
<? endforeach; endif;?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<div class="col-lg-5 col-xl-3">
|
|
<form action="/admin/shop_product/generate_combination/product_id=<?= $this -> product['id'];?>" method="POST">
|
|
<button type="submit" class="btn btn-success" style="margin-bottom: 25px;">Wygeneruj kombinacje</button>
|
|
<? foreach ( $this -> attributes as $attribute ):?>
|
|
<div class="combination-attribute">
|
|
<div class="title">
|
|
<?= $attribute['languages'][ $this -> default_language ]['name'];?>
|
|
<label style="float: right; font-weight: normal; font-size: 12px; cursor: pointer;"><input type="checkbox" class="g-checkbox select-all-attr"> wszystkie</label>
|
|
</div>
|
|
<ul class="values">
|
|
<? foreach ( $attribute['values'] as $value ):?>
|
|
<li>
|
|
<input type="checkbox" class="g-checkbox" name="attribute_<?= $attribute['id'];?>[]" value="<?= $value['id'];?>"> <?= $value['languages'][ $this -> default_language ]['name'];?>
|
|
</li>
|
|
<? endforeach;?>
|
|
</ul>
|
|
</div>
|
|
<? endforeach;?>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<link rel="stylesheet" type="text/css" href="/libraries/grid/plugins/icheck/skins/minimal/minimal.css">
|
|
<link rel="stylesheet" type="text/css" href="/libraries/grid/plugins/icheck/skins/minimal/blue.css">
|
|
<script type="text/javascript" src="/libraries/grid/plugins/icheck/icheck.min.js"></script>
|
|
<script type="text/javascript">
|
|
$( function()
|
|
{
|
|
$( '.g-checkbox, .g-radio' ).iCheck({
|
|
checkboxClass: 'icheckbox_minimal-blue',
|
|
radioClass: 'iradio_minimal-blue'
|
|
});
|
|
|
|
// "Zaznacz wszystkie" per atrybut
|
|
$( '.select-all-attr' ).on( 'ifChanged', function()
|
|
{
|
|
var checked = $( this ).is( ':checked' );
|
|
$( this ).closest( '.combination-attribute' ).find( '.g-checkbox' ).each( function()
|
|
{
|
|
$( this ).iCheck( checked ? 'check' : 'uncheck' );
|
|
});
|
|
});
|
|
|
|
// Inline save — SKU, ilość, cena
|
|
var fieldUrlMap = {
|
|
'sku': '/admin/shop_product/product_combination_sku_save/',
|
|
'quantity': '/admin/shop_product/product_combination_quantity_save/',
|
|
'price': '/admin/shop_product/product_combination_price_save/'
|
|
};
|
|
|
|
$( 'body' ).on( 'change', '.combination-field', function()
|
|
{
|
|
var $input = $( this );
|
|
var field = $input.data( 'field' );
|
|
var data = { product_id: $input.data( 'product-id' ) };
|
|
data[ field ] = $input.val();
|
|
|
|
$.ajax({
|
|
type: 'POST',
|
|
cache: false,
|
|
url: fieldUrlMap[ field ],
|
|
data: data,
|
|
beforeSend: function() {
|
|
$( '#overlay' ).show();
|
|
},
|
|
success: function( data ) {
|
|
$( '#overlay' ).hide();
|
|
var response = jQuery.parseJSON( data );
|
|
if ( response.status === 'ok' ) {
|
|
$input.css( 'border-color', '#1cbb8c' );
|
|
setTimeout( function() { $input.css( 'border-color', '' ); }, 1500 );
|
|
} else {
|
|
$input.css( 'border-color', '#ff3d60' );
|
|
setTimeout( function() { $input.css( 'border-color', '' ); }, 1500 );
|
|
if ( response.msg ) create_error( response.msg );
|
|
}
|
|
},
|
|
error: function() {
|
|
$( '#overlay' ).hide();
|
|
$input.css( 'border-color', '#ff3d60' );
|
|
setTimeout( function() { $input.css( 'border-color', '' ); }, 1500 );
|
|
}
|
|
});
|
|
});
|
|
|
|
// Inline save — checkbox stock_0_buy (iCheck event)
|
|
$( 'body' ).on( 'ifChanged', '.combination-checkbox', function()
|
|
{
|
|
var $cb = $( this );
|
|
|
|
$.ajax({
|
|
type: 'POST',
|
|
cache: false,
|
|
url: '/admin/shop_product/product_combination_stock_0_buy_save/',
|
|
data: { product_id: $cb.data( 'product-id' ), stock_0_buy: $cb.is( ':checked' ) },
|
|
beforeSend: function() {
|
|
$( '#overlay' ).show();
|
|
},
|
|
success: function( data ) {
|
|
$( '#overlay' ).hide();
|
|
var response = jQuery.parseJSON( data );
|
|
if ( response.status !== 'ok' && response.msg ) {
|
|
create_error( response.msg );
|
|
}
|
|
},
|
|
error: function() {
|
|
$( '#overlay' ).hide();
|
|
}
|
|
});
|
|
});
|
|
|
|
// Usuwanie kombinacji — AJAX
|
|
$( 'body' ).on( 'click', '.btn-delete-permutation', function(e)
|
|
{
|
|
e.preventDefault();
|
|
var combinationId = $( this ).data( 'combination-id' );
|
|
var $row = $( this ).closest( 'tr' );
|
|
|
|
$.alert(
|
|
{
|
|
title: 'Pytanie',
|
|
content: 'Na pewno chcesz usunąć wybraną kombinację?',
|
|
type: 'orange',
|
|
closeIcon: true,
|
|
closeIconClass: 'fa fa-times',
|
|
typeAnimated: true,
|
|
animation: 'opacity',
|
|
columnClass: 'col-12 col-lg-10',
|
|
theme: 'modern',
|
|
icon: 'fa fa-question',
|
|
buttons: {
|
|
cancel: {
|
|
text: 'Nie',
|
|
btnClass: 'btn-dark',
|
|
action: function() {}
|
|
},
|
|
confirm: {
|
|
text: 'Tak',
|
|
btnClass: 'btn-danger',
|
|
keys: ['enter'],
|
|
action: function()
|
|
{
|
|
$.ajax({
|
|
type: 'POST',
|
|
cache: false,
|
|
url: '/admin/shop_product/delete_combination_ajax/',
|
|
data: { combination_id: combinationId },
|
|
beforeSend: function() {
|
|
$( '#overlay' ).show();
|
|
},
|
|
success: function( data ) {
|
|
$( '#overlay' ).hide();
|
|
var response = jQuery.parseJSON( data );
|
|
if ( response.status === 'ok' ) {
|
|
$row.fadeOut( 300, function() { $( this ).remove(); } );
|
|
} else {
|
|
if ( response.msg ) create_error( response.msg );
|
|
}
|
|
},
|
|
error: function() {
|
|
$( '#overlay' ).hide();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
});
|
|
</script>
|