new: make the debug info available to all backoffice users with helpful links
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
namespace App\Repositories\Shop;
|
||||
|
||||
use App\Models\Shop\Offer;
|
||||
use App\Models\Shop\PriceList;
|
||||
use App\Models\Shop\PriceListValue;
|
||||
use App\Models\Shop\SaleChannel;
|
||||
use App\Traits\Model\Basic;
|
||||
@@ -185,20 +186,44 @@ class Offers
|
||||
->with([
|
||||
'article',
|
||||
'tariff:id,status_id',
|
||||
'variation',
|
||||
])
|
||||
->get();
|
||||
|
||||
return $channels->map(function ($channel) use ($offers) {
|
||||
$priceValue = null;
|
||||
$candidateOffer = null;
|
||||
$allOffersForChannel = [];
|
||||
|
||||
foreach ($offers as $offer) {
|
||||
$priceCandidate = self::getPrice($offer->id, 1, $channel->id);
|
||||
|
||||
if ($priceCandidate && (float) $priceCandidate->price_taxed > 0) {
|
||||
$priceValue = $priceCandidate;
|
||||
$candidateOffer = $offer;
|
||||
break;
|
||||
// Get price list name
|
||||
$priceListName = null;
|
||||
if ($priceCandidate) {
|
||||
$priceListModel = PriceList::find($priceCandidate->price_list_id);
|
||||
$priceListName = $priceListModel ? $priceListModel->name : null;
|
||||
}
|
||||
|
||||
// Collect all offers with their details
|
||||
$allOffersForChannel[] = [
|
||||
'id' => $offer->id,
|
||||
'variation_name' => $offer->variation ? $offer->variation->name : null,
|
||||
'stock_current' => (int) $offer->stock_current,
|
||||
'status_id' => (int) $offer->status_id,
|
||||
'is_active' => (int) $offer->status_id === 1,
|
||||
'tariff_id' => $offer->tariff_id ? (int) $offer->tariff_id : null,
|
||||
'price_taxed' => (float) $priceCandidate->price_taxed,
|
||||
'quantity' => (int) $priceCandidate->quantity,
|
||||
'price_list_name' => $priceListName,
|
||||
];
|
||||
|
||||
// Keep first valid offer as the main candidate
|
||||
if (!$candidateOffer) {
|
||||
$priceValue = $priceCandidate;
|
||||
$candidateOffer = $offer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,6 +234,7 @@ class Offers
|
||||
$offerHasStock = $candidateOffer && $candidateOffer->stock_current !== null
|
||||
? (float) $candidateOffer->stock_current > 0
|
||||
: null;
|
||||
$offerTariffId = $candidateOffer && $candidateOffer->tariff_id ? (int) $candidateOffer->tariff_id : null;
|
||||
|
||||
return [
|
||||
'id' => $channel->id,
|
||||
@@ -221,6 +247,8 @@ class Offers
|
||||
'offer_stock_current' => $offerStock,
|
||||
'offer_has_stock' => $offerHasStock,
|
||||
'tariff_status_id' => $offerTariffStatus,
|
||||
'tariff_id' => $offerTariffId,
|
||||
'all_offers' => $allOffersForChannel,
|
||||
];
|
||||
})->toArray();
|
||||
}
|
||||
|
||||
@@ -48,8 +48,8 @@
|
||||
|
||||
</div>
|
||||
<div class="col-lg-3 col-xs-12">
|
||||
@if (config('app.debug') && !empty($article['available_sale_channels']))
|
||||
<div class="alert alert-info p-2 mb-3">
|
||||
@if (auth('web')->check() && !empty($article['available_sale_channels']))
|
||||
<div id="article-admin-offers" class="alert alert-info p-2 mb-3">
|
||||
<strong class="d-block">Offres :</strong>
|
||||
<ul class="list-unstyled mb-0 small">
|
||||
@php
|
||||
@@ -82,16 +82,61 @@
|
||||
</span>
|
||||
</span>
|
||||
@if ($priceTaxed !== null)
|
||||
<span class="ml-2 text-nowrap text-right {{ $nameClass }}">
|
||||
{{ number_format($priceTaxed, 2, ',', ' ') }} € TTC
|
||||
@if (! empty($quantity))
|
||||
<span class="d-block text-muted" style="font-size: 0.85em;">Qté min. {{ $quantity }}</span>
|
||||
@endif
|
||||
</span>
|
||||
@php
|
||||
$tariffId = $channel['tariff_id'] ?? null;
|
||||
@endphp
|
||||
@if ($tariffId)
|
||||
<a href="{{ route('Admin.Shop.Tariffs.edit', $tariffId) }}" target="_blank" rel="noopener" class="ml-2 text-nowrap text-right {{ $nameClass }} text-decoration-none text-reset d-inline-block admin-link-group admin-price-link">
|
||||
{{ number_format($priceTaxed, 2, ',', ' ') }} € TTC
|
||||
@if (! empty($quantity))
|
||||
<span class="d-block text-muted" style="font-size: 0.85em;">Qté min. {{ $quantity }}</span>
|
||||
@endif
|
||||
</a>
|
||||
@else
|
||||
<span class="ml-2 text-nowrap text-right {{ $nameClass }}">
|
||||
{{ number_format($priceTaxed, 2, ',', ' ') }} € TTC
|
||||
@if (! empty($quantity))
|
||||
<span class="d-block text-muted" style="font-size: 0.85em;">Qté min. {{ $quantity }}</span>
|
||||
@endif
|
||||
</span>
|
||||
@endif
|
||||
@else
|
||||
<span class="ml-2 text-muted">–</span>
|
||||
@endif
|
||||
</div>
|
||||
@if (!empty($channel['all_offers']))
|
||||
<ul class="list-unstyled mb-0 mt-1" style="padding-left: 0.75em;">
|
||||
@foreach ($channel['all_offers'] as $offer)
|
||||
@php
|
||||
$isSelectedOffer = $offer['id'] === $channel['offer_id'];
|
||||
$offerClass = $offer['is_active'] ? 'text-dark' : 'text-muted';
|
||||
$stockClass = $offer['stock_current'] > 0 ? 'text-success' : 'text-danger';
|
||||
@endphp
|
||||
<li class="small {{ $offerClass }}" style="font-size: 0.85em;">
|
||||
<a href="{{ route('Admin.Shop.Offers.edit', $offer['id']) }}" target="_blank" rel="noopener" class="text-decoration-none {{ $offerClass }} admin-link-group admin-offer-link">
|
||||
<div class="d-flex justify-content-between align-items-start">
|
||||
<div>
|
||||
<span style="opacity: 0.5;">{{ $isSelectedOffer ? '▸' : '○' }}</span>
|
||||
@if ($offer['variation_name'])
|
||||
{{ $offer['variation_name'] }}
|
||||
@endif
|
||||
- Stock: <strong class="{{ $stockClass }}">{{ $offer['stock_current'] }}</strong>
|
||||
@if (!$offer['is_active'])
|
||||
<span class="text-muted">(inactive)</span>
|
||||
@endif
|
||||
</div>
|
||||
<div class="text-right text-nowrap ml-2">
|
||||
{{ number_format($offer['price_taxed'], 2, ',', ' ') }} €
|
||||
@if ($offer['quantity'] > 1)
|
||||
<span class="text-muted">(min {{ $offer['quantity'] }})</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
@endif
|
||||
</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
@@ -103,3 +148,67 @@
|
||||
@endsection
|
||||
|
||||
@include('load.layout.modal')
|
||||
|
||||
@if (auth('web')->check() && !empty($article['available_sale_channels']))
|
||||
@push('styles')
|
||||
<style>
|
||||
#article-admin-offers .admin-link-group {
|
||||
transition: background-color 0.15s ease;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
#article-admin-offers .admin-price-link {
|
||||
display: inline-block;
|
||||
padding: 2px 4px;
|
||||
margin: -2px -4px;
|
||||
}
|
||||
|
||||
#article-admin-offers .admin-offer-link {
|
||||
display: block;
|
||||
padding: 2px 4px;
|
||||
margin: -2px -4px;
|
||||
}
|
||||
|
||||
#article-admin-offers .admin-link-group:hover,
|
||||
#article-admin-offers .admin-link-group:focus,
|
||||
#article-admin-offers .admin-link-group.linked-hover {
|
||||
background-color: rgba(0, 123, 255, 0.1);
|
||||
text-decoration: none;
|
||||
}
|
||||
</style>
|
||||
@endpush
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const container = document.getElementById('article-admin-offers');
|
||||
if (!container) {
|
||||
return;
|
||||
}
|
||||
|
||||
const links = Array.from(container.querySelectorAll('a.admin-link-group[href]'));
|
||||
const grouped = new Map();
|
||||
|
||||
links.forEach((link) => {
|
||||
const href = link.getAttribute('href');
|
||||
if (!grouped.has(href)) {
|
||||
grouped.set(href, []);
|
||||
}
|
||||
grouped.get(href).push(link);
|
||||
});
|
||||
|
||||
grouped.forEach((group) => {
|
||||
group.forEach((link) => {
|
||||
const addHighlight = () => group.forEach((item) => item.classList.add('linked-hover'));
|
||||
const removeHighlight = () => group.forEach((item) => item.classList.remove('linked-hover'));
|
||||
|
||||
link.addEventListener('mouseenter', addHighlight);
|
||||
link.addEventListener('mouseleave', removeHighlight);
|
||||
link.addEventListener('focus', addHighlight);
|
||||
link.addEventListener('blur', removeHighlight);
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
@endif
|
||||
|
||||
Reference in New Issue
Block a user