Merge branch 'master' of github.com:bagisto/bagisto

This commit is contained in:
Carlos Augusto Gartner 2020-08-05 08:50:13 -03:00
commit d5126e9257
61 changed files with 648 additions and 321 deletions

View File

@ -45,6 +45,19 @@ class OrderInvoicesDataGrid extends DataGrid
'filterable' => true,
]);
$this->addColumn([
'index' => 'created_at',
'label' => trans('admin::app.datagrid.invoice-date'),
'type' => 'string',
'searchable' => true,
'sortable' => true,
'filterable' => true,
'closure' => true,
'wrapper' => function ($value) {
return \Carbon\Carbon::parse($value->created_at)->format('d-m-Y');
}
]);
$this->addColumn([
'index' => 'base_grand_total',
'label' => trans('admin::app.datagrid.grand-total'),
@ -55,12 +68,22 @@ class OrderInvoicesDataGrid extends DataGrid
]);
$this->addColumn([
'index' => 'created_at',
'label' => trans('admin::app.datagrid.invoice-date'),
'type' => 'datetime',
'index' => 'state',
'label' => trans('admin::app.datagrid.state'),
'type' => 'string',
'closure' => true,
'searchable' => true,
'sortable' => true,
'filterable' => true,
'wrapper' => function ($value) {
if ($value->state == 'paid') {
return '<span class="badge badge-md badge-success">'. trans('admin::app.sales.orders.invoice-status-paid') .'</span>';
} elseif ($value->state == "pending") {
return '<span class="badge badge-md badge-warning">'. trans('admin::app.sales.orders.invoice-status-pending') .'</span>';
} elseif ($value->state == "overdue") {
return '<span class="badge badge-md badge-danger">'. trans('admin::app.sales.orders.invoice-status-overdue') . '</span>';
}
}
]);
}

View File

@ -64,12 +64,12 @@ class CustomerController extends Controller
CustomerGroupRepository $customerGroupRepository,
ChannelRepository $channelRepository
)
{
$this->_config = request('_config');
$this->middleware('admin');
$this->customerRepository = $customerRepository;
$this->customerAddressRepository = $customerAddressRepository;
$this->customerGroupRepository = $customerGroupRepository;
$this->channelRepository = $channelRepository;
@ -200,12 +200,19 @@ class CustomerController extends Controller
$customer = $this->customerRepository->findorFail($id);
try {
$this->customerRepository->delete($id);
if (! $this->customerRepository->checkIfCustomerHasOrderPendingOrProcessing($customer)) {
$this->customerRepository->delete($id);
} else {
return response()->json(['message' => false], 400);
}
session()->flash('success', trans('admin::app.response.delete-success', ['name' => 'Customer']));
return response()->json(['message' => true], 200);
} catch (\Exception $e) {
session()->flash('error', trans('admin::app.response.delete-failed', ['name' => 'Customer']));
}
@ -279,12 +286,18 @@ class CustomerController extends Controller
{
$customerIds = explode(',', request()->input('indexes'));
foreach ($customerIds as $customerId) {
$this->customerRepository->deleteWhere(['id' => $customerId]);
if (!$this->customerRepository->checkBulkCustomerIfTheyHaveOrderPendingOrProcessing($customerIds)) {
foreach ($customerIds as $customerId) {
$this->customerRepository->deleteWhere(['id' => $customerId]);
}
session()->flash('success', trans('admin::app.customers.customers.mass-destroy-success'));
return redirect()->back();
}
session()->flash('success', trans('admin::app.customers.customers.mass-destroy-success'));
session()->flash('error', trans('admin::app.response.order-pending', ['name' => 'Customers']));
return redirect()->back();
}
}

View File

@ -2,9 +2,12 @@
namespace Webkul\Admin\Http\Controllers\Sales;
use Illuminate\Http\Request;
use Webkul\Admin\Http\Controllers\Controller;
use Webkul\Sales\Repositories\OrderRepository;
use Webkul\Sales\Repositories\InvoiceRepository;
use PDF;
class InvoiceController extends Controller
@ -97,7 +100,7 @@ class InvoiceController extends Controller
$data = request()->all();
$haveProductToInvoice = false;
foreach ($data['invoice']['items'] as $itemId => $qty) {
if ($qty) {
$haveProductToInvoice = true;
@ -145,4 +148,29 @@ class InvoiceController extends Controller
return $pdf->download('invoice-' . $invoice->created_at->format('d-m-Y') . '.pdf');
}
/**
* Update the invoice state.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function updateState($id, Request $request)
{
$invoice = $this->invoiceRepository->findOrFail($id);
$task = $this->invoiceRepository->updateInvoiceState($invoice, $request->state);
if($request->state == 'paid'){
$order = $this->orderRepository->findOrFail($invoice->order->id);
$this->orderRepository->updateOrderStatus($order);
}
if ($task){
session()->flash('success', trans('admin::app.sales.orders.invoice-status-confirmed'));
} else {
session()->flash('success', trans('admin::app.sales.orders.invoice-status-error'));
}
return back();
}
}

View File

@ -29,9 +29,17 @@ class ConfigurationForm extends FormRequest
if (request()->has('general.design.admin_logo.logo_image')
&& ! request()->input('general.design.admin_logo.logo_image.delete')
) {
$this->rules = [
'general.design.admin_logo.logo_image' => 'required|mimes:jpeg,bmp,png,jpg',
];
$this->rules = array_merge($this->rules, [
'general.design.admin_logo.logo_image' => 'required|mimes:jpeg,bmp,png,jpg|max:5000',
]);
}
if (request()->has('general.design.admin_logo.favicon')
&& ! request()->input('general.design.admin_logo.favicon.delete')
) {
$this->rules = array_merge($this->rules, [
'general.design.admin_logo.favicon' => 'required|mimes:jpeg,bmp,png,jpg|max:5000',
]);
}
return $this->rules;
@ -48,4 +56,15 @@ class ConfigurationForm extends FormRequest
'general.design.admin_logo.logo_image.mimes' => 'Invalid file format. Use only jpeg, bmp, png, jpg.',
];
}
}
/**
* Set the attribute name.
*/
public function attributes()
{
return [
'general.design.admin_logo.logo_image' => 'Logo Image',
'general.design.admin_logo.favicon' => 'Favicon Image'
];
}
}

View File

@ -211,6 +211,10 @@ Route::group(['middleware' => ['web']], function () {
'view' => 'admin::sales.invoices.print',
])->name('admin.sales.invoices.print');
Route::post('/invoices/update/state/{order_id}', 'Webkul\Admin\Http\Controllers\Sales\InvoiceController@updateState')->defaults('_config', [
'redirect' => 'admin.sales.orders.view',
])->name('admin.sales.invoices.update.state');
// Sales Shipments Routes
Route::get('/shipments', 'Webkul\Admin\Http\Controllers\Sales\ShipmentController@index')->defaults('_config', [

View File

@ -320,6 +320,14 @@ return array (
'invoice-btn-title' => 'Rechnung',
'info' => 'Informationen',
'invoices' => 'Rechnungen',
'invoices-change-title' => 'Change invoice state',
'invoices-change-state-desc' => 'Please select the new invoice state:',
'invoice-status-paid' => 'Paid',
'invoice-status-pending' => 'Pending',
'invoice-status-overdue' => 'Overdue',
'invoice-status-update' => 'Save changes',
'invoice-status-confirmed' => 'The invoice state has been changed.',
'invoice-status-error' => 'Could not update the invoice state. ',
'shipments' => 'Sendungen',
'order-and-account' => 'Bestellung und Rechnung',
'order-info' => 'Bestellinformationen',

View File

@ -319,6 +319,14 @@ return [
'invoice-btn-title' => 'Invoice',
'info' => 'Information',
'invoices' => 'Invoices',
'invoices-change-title' => 'Change invoice state',
'invoices-change-state-desc' => 'Please select the new invoice state:',
'invoice-status-paid' => 'Paid',
'invoice-status-pending' => 'Pending',
'invoice-status-overdue' => 'Overdue',
'invoice-status-update' => 'Save changes',
'invoice-status-confirmed' => 'The invoice state has been changed.',
'invoice-status-error' => 'Could not update the invoice state. ',
'shipments' => 'Shipments',
'order-and-account' => 'Order and Account',
'order-info' => 'Order Information',
@ -1219,7 +1227,7 @@ return [
'cancel-success' => ':name canceled successfully.',
'cancel-error' => ':name can not be canceled.',
'already-taken' => 'The :name has already been taken.',
'order-pending' => 'Cannot delete account because some Order(s) are pending or processing state.'
'order-pending' => 'Cannot delete :name account because some Order(s) are pending or processing state.'
],
'footer' => [

View File

@ -318,6 +318,14 @@ return [
'invoice-btn-title' => 'صورت حساب',
'info' => 'اطلاعات',
'invoices' => 'صورت حساب ها',
'invoices-change-title' => 'Change invoice state',
'invoices-change-state-desc' => 'Please select the new invoice state:',
'invoice-status-paid' => 'Paid',
'invoice-status-pending' => 'Pending',
'invoice-status-overdue' => 'Overdue',
'invoice-status-update' => 'Save changes',
'invoice-status-confirmed' => 'The invoice state has been changed.',
'invoice-status-error' => 'Could not update the invoice state. ',
'shipments' => 'حمل و نقل ها',
'order-and-account' => 'سفارش و حساب',
'order-info' => 'اطلاعات سفارش',

View File

@ -318,6 +318,14 @@ return [
'invoice-btn-title' => 'Fattura',
'info' => 'Informazoni',
'invoices' => 'Fatture',
'invoices-change-title' => 'Change invoice state',
'invoices-change-state-desc' => 'Please select the new invoice state:',
'invoice-status-paid' => 'Paid',
'invoice-status-pending' => 'Pending',
'invoice-status-overdue' => 'Overdue',
'invoice-status-update' => 'Save changes',
'invoice-status-confirmed' => 'The invoice state has been changed.',
'invoice-status-error' => 'Could not update the invoice state. ',
'shipments' => 'Spedizioni',
'order-and-account' => 'Ordine e Account',
'order-info' => 'informazioni Ordine',

View File

@ -318,6 +318,14 @@ return [
'invoice-btn-title' => 'Factuur',
'info' => 'Informatie',
'invoices' => 'Facturen',
'invoices-change-title' => 'Change invoice state',
'invoices-change-state-desc' => 'Please select the new invoice state:',
'invoice-status-paid' => 'Paid',
'invoice-status-pending' => 'Pending',
'invoice-status-overdue' => 'Overdue',
'invoice-status-update' => 'Save changes',
'invoice-status-confirmed' => 'The invoice state has been changed.',
'invoice-status-error' => 'Could not update the invoice state. ',
'shipments' => 'Verzendingen',
'order-and-account' => 'Order and Account',
'order-info' => 'Order Information',

View File

@ -317,6 +317,14 @@ return [
'invoice-btn-title' => 'Faktura',
'info' => 'Informacje',
'invoices' => 'Faktury',
'invoices-change-title' => 'Change invoice state',
'invoices-change-state-desc' => 'Please select the new invoice state:',
'invoice-status-paid' => 'Paid',
'invoice-status-pending' => 'Pending',
'invoice-status-overdue' => 'Overdue',
'invoice-status-update' => 'Save changes',
'invoice-status-confirmed' => 'The invoice state has been changed.',
'invoice-status-error' => 'Could not update the invoice state. ',
'shipments' => 'Przesyłki',
'order-and-account' => 'Zamówienie i konto',
'order-info' => 'Informacje o zamówieniu',

View File

@ -318,6 +318,14 @@ return [
'invoice-btn-title' => 'Faturar',
'info' => 'Informação',
'invoices' => 'Faturas',
'invoices-change-title' => 'Change invoice state',
'invoices-change-state-desc' => 'Please select the new invoice state:',
'invoice-status-paid' => 'Paid',
'invoice-status-pending' => 'Pending',
'invoice-status-overdue' => 'Overdue',
'invoice-status-update' => 'Save changes',
'invoice-status-confirmed' => 'The invoice state has been changed.',
'invoice-status-error' => 'Could not update the invoice state. ',
'shipments' => 'Envios',
'order-and-account' => 'Pedido e Conta',
'order-info' => 'Informação do Pedido',

View File

@ -316,6 +316,14 @@ return [
'invoice-btn-title' => 'Fatura',
'info' => 'Bilgi',
'invoices' => 'Faturalar',
'invoices-change-title' => 'Change invoice state',
'invoices-change-state-desc' => 'Please select the new invoice state:',
'invoice-status-paid' => 'Paid',
'invoice-status-pending' => 'Pending',
'invoice-status-overdue' => 'Overdue',
'invoice-status-update' => 'Save changes',
'invoice-status-confirmed' => 'The invoice state has been changed.',
'invoice-status-error' => 'Could not update the invoice state. ',
'shipments' => 'Kargo',
'order-and-account' => 'Sipariş ve Hesap',
'order-info' => 'Sipariş Bilgisi',

View File

@ -13,10 +13,7 @@
<div class="page-action">
<div class="export-import" @click="showModal('downloadDataGrid')">
<i class="export-icon"></i>
<span>
{{ __('admin::app.export.export') }}
</span>
<i class="export-icon"></i> <span>{{ __('admin::app.export.export') }}</span>
</div>
</div>
</div>

View File

@ -1,10 +1,10 @@
@extends('admin::layouts.master')
@extends('admin::layouts.content')
@section('page_title')
{{ __('admin::app.sales.invoices.view-title', ['invoice_id' => $invoice->id]) }}
@stop
@section('content-wrapper')
@section('content')
<?php $order = $invoice->order; ?>
@ -15,11 +15,18 @@
{!! view_render_event('sales.invoice.title.before', ['order' => $order]) !!}
<i class="icon angle-left-icon back-link" onclick="history.length > 1 ? history.go(-1) : window.location = '{{ route('admin.dashboard.index') }}';"></i>
{{ __('admin::app.sales.invoices.view-title', ['invoice_id' => $invoice->id]) }}
{!! view_render_event('sales.invoice.title.after', ['order' => $order]) !!}
</h1>
@if($invoice->state == 'paid')
<small><span class="badge badge-md badge-success">{{ __('admin::app.sales.orders.invoice-status-paid') }}</span></small>
@elseif($invoice->state == 'pending')
<span class="badge badge-md badge-warning">{{ __('admin::app.sales.orders.invoice-status-pending') }}</span>
@else
<span class="badge badge-md badge-danger">{{ __('admin::app.sales.orders.invoice-status-overdue') }}</span>
@endif
</div>
<div class="page-action">
@ -29,6 +36,10 @@
{{ __('admin::app.sales.invoices.print') }}
</a>
@if($invoice->state == "pending" || $invoice->state == "overdue")
<a href="#" id="ChangeStatus" class="btn btn-lg btn-primary" @click="showModal('changeInvoiceState')">{{ __('admin::app.sales.orders.invoices-change-title') }}</a>
@endif
{!! view_render_event('sales.invoice.page_action.after', ['order' => $order]) !!}
</div>
</div>
@ -37,7 +48,7 @@
<div class="sale-container">
<accordian :title="'{{ __('admin::app.sales.orders.order-and-account') }}'" :active="true">
<div slot="body">
<div slot="body" style="display: flex; overflow:auto;">
<div class="sale-section">
<div class="secton-title">
@ -46,10 +57,7 @@
<div class="section-content">
<div class="row">
<span class="title">
{{ __('admin::app.sales.invoices.order-id') }}
</span>
<span class="title">{{ __('admin::app.sales.invoices.order-id') }}</span>
<span class="value">
<a href="{{ route('admin.sales.orders.view', $order->id) }}">#{{ $order->increment_id }}</a>
</span>
@ -58,69 +66,55 @@
{!! view_render_event('sales.invoice.increment_id.after', ['order' => $order]) !!}
<div class="row">
<span class="title">
{{ __('admin::app.sales.orders.order-date') }}
</span>
<span class="value">
{{ $order->created_at }}
</span>
<span class="title">{{ __('admin::app.sales.orders.order-date') }}</span>
<span class="value">{{ $order->created_at }}</span>
</div>
{!! view_render_event('sales.invoice.created_at.after', ['order' => $order]) !!}
<div class="row">
<span class="title">
{{ __('admin::app.sales.orders.order-status') }}
</span>
<span class="value">
{{ $order->status_label }}
</span>
<span class="title">{{ __('admin::app.sales.orders.order-status') }}</span>
<span class="value">{{ $order->status_label }}</span>
</div>
{!! view_render_event('sales.invoice.status_label.after', ['order' => $order]) !!}
<div class="row">
<span class="title">
{{ __('admin::app.sales.orders.channel') }}
</span>
<span class="value">
{{ $order->channel_name }}
</span>
<span class="title">{{ __('admin::app.sales.orders.channel') }}</span>
<span class="value">{{ $order->channel_name }}</span>
</div>
{!! view_render_event('sales.invoice.channel_name.after', ['order' => $order]) !!}
<div class="row">
<span class="title">{{ __('admin::app.sales.orders.payment-method') }}</span>
<span class="value">{{ core()->getConfigData('sales.paymentmethods.' . $order->payment->method . '.title') }}</span>
</div>
<div class="row">
<span class="title">{{ __('admin::app.sales.orders.shipping-method') }}</span>
<span class="value">{{ $order->shipping_title }}</span>
</div>
{!! view_render_event('sales.invoice.shipping-method.after', ['order' => $order]) !!}
</div>
</div>
<div class="sale-section">
<div class="sale-section" style="margin: 0 0 0 300px;">
<div class="secton-title">
<span>{{ __('admin::app.sales.orders.account-info') }}</span>
</div>
<div class="section-content">
<div class="row">
<span class="title">
{{ __('admin::app.sales.orders.customer-name') }}
</span>
<span class="value">
{{ $invoice->address->name }}
</span>
<span class="title">{{ __('admin::app.sales.orders.customer-name') }}</span>
<span class="value">{{ $invoice->address->name }}</span>
</div>
{!! view_render_event('sales.invoice.customer_name.after', ['order' => $order]) !!}
<div class="row">
<span class="title">
{{ __('admin::app.sales.orders.email') }}
</span>
<span class="value">
{{ $invoice->address->email }}
</span>
<span class="title">{{ __('admin::app.sales.orders.email') }}</span>
<span class="value">{{ $invoice->address->email }}</span>
</div>
{!! view_render_event('sales.invoice.customer_email.after', ['order' => $order]) !!}
@ -131,14 +125,14 @@
</accordian>
<accordian :title="'{{ __('admin::app.sales.orders.address') }}'" :active="true">
<div slot="body">
<div slot="body" style="display: flex; overflow:auto;">
<div class="sale-section">
<div class="secton-title">
<div class="secton-title" style="width: 380px;">
<span>{{ __('admin::app.sales.orders.billing-address') }}</span>
</div>
<div class="section-content">
<div class="section-content" style="width: 380px;">
@include ('admin::sales.address', ['address' => $order->billing_address])
{!! view_render_event('sales.invoice.billing_address.after', ['order' => $order]) !!}
@ -146,86 +140,18 @@
</div>
@if ($order->shipping_address)
<div class="sale-section">
<div class="secton-title">
<div class="sale-section" style="margin: 0 0 0 300px;">
<div class="secton-title" style="width: 400px;">
<span>{{ __('admin::app.sales.orders.shipping-address') }}</span>
</div>
<div class="section-content">
<div class="section-content" style="width: 400px;">
@include ('admin::sales.address', ['address' => $order->shipping_address])
{!! view_render_event('sales.invoice.shipping_address.after', ['order' => $order]) !!}
</div>
</div>
@endif
</div>
</accordian>
<accordian :title="'{{ __('admin::app.sales.orders.payment-and-shipping') }}'" :active="true">
<div slot="body">
<div class="sale-section">
<div class="secton-title">
<span>{{ __('admin::app.sales.orders.payment-info') }}</span>
</div>
<div class="section-content">
<div class="row">
<span class="title">
{{ __('admin::app.sales.orders.payment-method') }}
</span>
<span class="value">
{{ core()->getConfigData('sales.paymentmethods.' . $order->payment->method . '.title') }}
</span>
</div>
<div class="row">
<span class="title">
{{ __('admin::app.sales.orders.currency') }}
</span>
<span class="value">
{{ $order->order_currency_code }}
</span>
</div>
{!! view_render_event('sales.invoice.payment-method.after', ['order' => $order]) !!}
</div>
</div>
@if ($order->shipping_address)
<div class="sale-section">
<div class="secton-title">
<span>{{ __('admin::app.sales.orders.shipping-info') }}</span>
</div>
<div class="section-content">
<div class="row">
<span class="title">
{{ __('admin::app.sales.orders.shipping-method') }}
</span>
<span class="value">
{{ $order->shipping_title }}
</span>
</div>
<div class="row">
<span class="title">
{{ __('admin::app.sales.orders.shipping-price') }}
</span>
<span class="value">
{{ core()->formatBasePrice($order->base_shipping_amount) }}
</span>
</div>
{!! view_render_event('sales.invoice.shipping-method.after', ['order' => $order]) !!}
</div>
</div>
@endif
</div>
</accordian>
@ -254,9 +180,7 @@
@foreach ($invoice->items as $item)
<tr>
<td>{{ $item->getTypeInstance()->getOrderedItem($item)->sku }}</td>
<td>
{{ $item->name }}
<td>{{ $item->name }}
@if (isset($item->additional['attributes']))
<div class="item-options">
@ -264,19 +188,14 @@
@foreach ($item->additional['attributes'] as $attribute)
<b>{{ $attribute['attribute_name'] }} : </b>{{ $attribute['option_label'] }}</br>
@endforeach
</div>
@endif
</td>
<td>{{ core()->formatBasePrice($item->base_price) }}</td>
<td>{{ $item->qty }}</td>
<td>{{ core()->formatBasePrice($item->base_total) }}</td>
<td>{{ core()->formatBasePrice($item->base_tax_amount) }}</td>
@if ($invoice->base_discount_amount > 0)
<td>{{ core()->formatBasePrice($item->base_discount_amount) }}</td>
@endif
@ -284,7 +203,6 @@
<td>{{ core()->formatBasePrice($item->base_total + $item->base_tax_amount - $item->base_discount_amount) }}</td>
</tr>
@endforeach
</tbody>
</table>
</div>
@ -322,12 +240,61 @@
<td>{{ core()->formatBasePrice($invoice->base_grand_total) }}</td>
</tr>
</table>
</div>
</accordian>
</div>
</div>
</div>
@stop
</div>
<modal id="changeInvoiceState" :is-open="modalIds.changeInvoiceState">
<h3 slot="header">{{ __('admin::app.sales.orders.invoices-change-title') }}</h3>
<div slot="body">
<option-wrapper></option-wrapper>
</div>
</modal>
@stop
@push('scripts')
<script type="text/x-template" id="options-template">
<form method="POST" action="{{ route('admin.sales.invoices.update.state', $invoice->id) }}">
<div class="page-content">
<p>Please select the new invoice state:</p>
<div class="form-container">
@csrf()
<div>
<input type="radio" name="state" id="paid" value="paid">
<label for="paid">{{ __('admin::app.sales.orders.invoice-status-paid') }}</label>
</div>
<div>
<input type="radio" name="state" id="pending" value="pending" @if($invoice->state == "pending") checked @endif>
<label for="pending">{{ __('admin::app.sales.orders.invoice-status-pending') }}</label>
</div>
<div>
<input type="radio" name="state" id="overdue" value="overdue" @if($invoice->state == "overdue") checked @endif>
<label for="overdue">{{ __('admin::app.sales.orders.invoice-status-overdue') }}</label>
</div>
</div>
<br />
<button type="submit" class="btn btn-md btn-primary">{{ __('admin::app.sales.orders.invoice-status-update')}}</button>
</div>
</form>
</script>
<script>
Vue.component('option-wrapper', {
template: '#options-template',
methods: {
onSubmit: function(e) {
// e.target.submit();
}
}
});
</script>
@endpush

View File

@ -157,37 +157,41 @@
</div>
</accordian>
<accordian :title="'{{ __('admin::app.sales.orders.address') }}'" :active="true">
<div slot="body">
@if ($order->billing_address || $order->shipping_address)
<accordian :title="'{{ __('admin::app.sales.orders.address') }}'" :active="true">
<div slot="body">
<div class="sale-section">
<div class="secton-title">
<span>{{ __('admin::app.sales.orders.billing-address') }}</span>
</div>
@if($order->billing_address)
<div class="sale-section">
<div class="secton-title">
<span>{{ __('admin::app.sales.orders.billing-address') }}</span>
</div>
<div class="section-content">
@include ('admin::sales.address', ['address' => $order->billing_address])
<div class="section-content">
@include ('admin::sales.address', ['address' => $order->billing_address])
{!! view_render_event('sales.order.billing_address.after', ['order' => $order]) !!}
</div>
</div>
@endif
@if ($order->shipping_address)
<div class="sale-section">
<div class="secton-title">
<span>{{ __('admin::app.sales.orders.shipping-address') }}</span>
</div>
<div class="section-content">
@include ('admin::sales.address', ['address' => $order->shipping_address])
{!! view_render_event('sales.order.shipping_address.after', ['order' => $order]) !!}
</div>
</div>
@endif
{!! view_render_event('sales.order.billing_address.after', ['order' => $order]) !!}
</div>
</div>
@if ($order->shipping_address)
<div class="sale-section">
<div class="secton-title">
<span>{{ __('admin::app.sales.orders.shipping-address') }}</span>
</div>
<div class="section-content">
@include ('admin::sales.address', ['address' => $order->shipping_address])
{!! view_render_event('sales.order.shipping_address.after', ['order' => $order]) !!}
</div>
</div>
@endif
</div>
</accordian>
</accordian>
@endif
<accordian :title="'{{ __('admin::app.sales.orders.payment-and-shipping') }}'" :active="true">
<div slot="body">
@ -470,7 +474,15 @@
<td>{{ $invoice->created_at }}</td>
<td>#{{ $invoice->order->increment_id }}</td>
<td>{{ $invoice->address->name }}</td>
<td>{{ $invoice->status_label }}</td>
<td>
@if($invoice->state == "paid")
{{ __('admin::app.sales.orders.invoice-status-paid') }}
@elseif($invoice->state == "overdue")
{{ __('admin::app.sales.orders.invoice-status-overdue') }}
@else
{{ __('admin::app.sales.orders.invoice-status-pending') }}
@endif
</td>
<td>{{ core()->formatBasePrice($invoice->base_grand_total) }}</td>
<td class="action">
<a href="{{ route('admin.sales.invoices.view', $invoice->id) }}">

View File

@ -107,37 +107,41 @@
</div>
</accordian>
<accordian :title="'{{ __('admin::app.sales.orders.address') }}'" :active="true">
<div slot="body">
@if ($order->billing_address || $order->shipping_address)
<accordian :title="'{{ __('admin::app.sales.orders.address') }}'" :active="true">
<div slot="body">
<div class="sale-section">
<div class="secton-title">
<span>{{ __('admin::app.sales.orders.billing-address') }}</span>
</div>
@if ($order->billing_address)
<div class="sale-section">
<div class="secton-title">
<span>{{ __('admin::app.sales.orders.billing-address') }}</span>
</div>
<div class="section-content">
<div class="section-content">
@include ('admin::sales.address', ['address' => $order->billing_address])
@include ('admin::sales.address', ['address' => $order->billing_address])
</div>
</div>
@endif
@if ($order->shipping_address)
<div class="sale-section">
<div class="secton-title">
<span>{{ __('admin::app.sales.orders.shipping-address') }}</span>
</div>
<div class="section-content">
@include ('admin::sales.address', ['address' => $order->shipping_address])
</div>
</div>
@endif
</div>
</div>
@if ($order->shipping_address)
<div class="sale-section">
<div class="secton-title">
<span>{{ __('admin::app.sales.orders.shipping-address') }}</span>
</div>
<div class="section-content">
@include ('admin::sales.address', ['address' => $order->shipping_address])
</div>
</div>
@endif
</div>
</accordian>
</accordian>
@endif
<accordian :title="'{{ __('admin::app.sales.orders.payment-and-shipping') }}'" :active="true">
<div slot="body">

View File

@ -2,6 +2,7 @@
namespace Webkul\BookingProduct\Repositories;
use Illuminate\Support\Facades\Event;
use Webkul\Core\Eloquent\Repository;
use Illuminate\Support\Str;
@ -18,12 +19,16 @@ class BookingProductEventTicketRepository extends Repository
}
/**
* @param array $data
* @param \Webkul\BookingProduct\Contracts\BookingProduct $bookingProduct
* @param array $data
* @param \Webkul\BookingProduct\Contracts\BookingProduct $bookingProduct
*
* @return void
* @throws \Prettus\Validator\Exceptions\ValidatorException
*/
public function saveEventTickets($data, $bookingProduct)
public function saveEventTickets($data, $bookingProduct): void
{
Event::dispatch('booking_product.booking.event-ticket.save.before', ['data' => $data, 'bookingProduct' => $bookingProduct]);
$previousTicketIds = $bookingProduct->event_tickets()->pluck('id');
if (isset($data['tickets'])) {
@ -54,7 +59,7 @@ class BookingProductEventTicketRepository extends Repository
}
if (Str::contains($ticketId, 'ticket_')) {
$this->create(array_merge([
$ticket = $this->create(array_merge([
'booking_product_id' => $bookingProduct->id,
], $ticketInputs));
} else {
@ -62,13 +67,18 @@ class BookingProductEventTicketRepository extends Repository
$previousTicketIds->forget($index);
}
$this->update($ticketInputs, $ticketId);
$ticket = $this->update($ticketInputs, $ticketId);
}
$savedTickets[$ticketId]['ticket'] = $ticket;
$savedTickets[$ticketId]['ticketInputs'] = $ticketInputs;
}
}
foreach ($previousTicketIds as $previousTicketId) {
$this->delete($previousTicketId);
}
Event::dispatch('booking_product.booking.event-ticket.save.after', ['tickets' => $savedTickets]);
}
}

View File

@ -7,8 +7,11 @@ namespace Webkul\Core\Helpers;
use Faker\Factory;
use Codeception\Module\Laravel5;
use Webkul\BookingProduct\Models\BookingProduct;
use Webkul\BookingProduct\Models\BookingProductEventTicket;
use Webkul\Checkout\Models\Cart;
use Webkul\Checkout\Models\CartItem;
use Webkul\Customer\Models\Customer;
use Webkul\Product\Models\Product;
use Webkul\Attribute\Models\Attribute;
use Webkul\Checkout\Models\CartAddress;
@ -31,21 +34,19 @@ class Laravel5Helper extends Laravel5
public const SIMPLE_PRODUCT = 1;
public const VIRTUAL_PRODUCT = 2;
public const DOWNLOADABLE_PRODUCT = 3;
public const BOOKING_EVENT_PRODUCT = 4;
/**
* Returns the field name of the given attribute in which a value should be saved inside
* the 'product_attribute_values' table. Depends on the type.
*
* @param string $attribute
* @param string $type
*
* @return string|null
* @part ORM
*/
public static function getAttributeFieldName(string $type): ?string
{
$attributes = [];
$possibleTypes = [
'text' => 'text_value',
'select' => 'integer_value',
@ -60,7 +61,7 @@ class Laravel5Helper extends Laravel5
public function prepareCart(array $options = []): array
{
$faker = \Faker\Factory::create();
$faker = Factory::create();
$I = $this;
@ -108,7 +109,7 @@ class Laravel5Helper extends Laravel5
$cartItems = [];
$generatedCartItems = rand(3, 10);
$generatedCartItems = random_int(3, 10);
for ($i = 2; $i <= $generatedCartItems; $i++) {
$quantity = random_int(1, 10);
@ -178,6 +179,10 @@ class Laravel5Helper extends Laravel5
$I = $this;
switch ($productType) {
case self::BOOKING_EVENT_PRODUCT:
$product = $I->haveBookingEventProduct($configs, $productStates);
break;
case self::DOWNLOADABLE_PRODUCT:
$product = $I->haveDownloadableProduct($configs, $productStates);
break;
@ -205,7 +210,6 @@ class Laravel5Helper extends Laravel5
$productStates = array_merge($productStates, ['simple']);
}
/** @var Product $product */
$product = $I->createProduct($configs['productAttributes'] ?? [], $productStates);
$I->createAttributeValues($product->id, $configs['attributeValues'] ?? []);
@ -222,7 +226,6 @@ class Laravel5Helper extends Laravel5
$productStates = array_merge($productStates, ['virtual']);
}
/** @var Product $product */
$product = $I->createProduct($configs['productAttributes'] ?? [], $productStates);
$I->createAttributeValues($product->id, $configs['attributeValues'] ?? []);
@ -239,7 +242,6 @@ class Laravel5Helper extends Laravel5
$productStates = array_merge($productStates, ['downloadable']);
}
/** @var Product $product */
$product = $I->createProduct($configs['productAttributes'] ?? [], $productStates);
$I->createAttributeValues($product->id, $configs['attributeValues'] ?? []);
@ -249,6 +251,22 @@ class Laravel5Helper extends Laravel5
return $product->refresh();
}
private function haveBookingEventProduct(array $configs = [], array $productStates = []): Product
{
$I = $this;
if (! in_array('booking', $productStates)) {
$productStates = array_merge($productStates, ['booking']);
}
$product = $I->createProduct($configs['productAttributes'] ?? [], $productStates);
$I->createAttributeValues($product->id, $configs['attributeValues'] ?? []);
$I->createBookingEventProduct($product->id);
return $product->refresh();
}
private function createProduct(array $attributes = [], array $states = []): Product
{
return factory(Product::class)->states($states)->create($attributes);
@ -275,6 +293,18 @@ class Laravel5Helper extends Laravel5
]);
}
private function createBookingEventProduct(int $productId): void
{
$I = $this;
$bookingProduct = $I->have(BookingProduct::class, [
'product_id' => $productId,
]);
$I->have(BookingProductEventTicket::class, [
'booking_product_id' => $bookingProduct->id,
]);
}
private function createAttributeValues(int $productId, array $attributeValues = []): void
{
$I = $this;
@ -295,7 +325,7 @@ class Laravel5Helper extends Laravel5
}
/** @var array $defaultAttributeValues
/**
* Some defaults that should apply to all generated products.
* By defaults products will be generated as saleable.
* If you do not want this, this defaults can be overriden by $attributeValues.
@ -314,7 +344,7 @@ class Laravel5Helper extends Laravel5
'special_price' => null,
'price' => $faker->randomFloat(2, 1, 1000),
'weight' => '1.00', // necessary for shipping
'brand' => AttributeOption::firstWhere('attribute_id', $brand->id)->id,
'brand' => AttributeOption::query()->firstWhere('attribute_id', $brand->id)->id,
];
$attributeValues = array_merge($defaultAttributeValues, $attributeValues);

View File

@ -156,7 +156,7 @@ class CustomerController extends Controller
$orders = $customerRepository->all_orders->whereIn('status', ['pending', 'processing'])->first();
if ($orders) {
session()->flash('error', trans('admin::app.response.order-pending'));
session()->flash('error', trans('admin::app.response.order-pending', ['name' => 'Customer']));
return redirect()->route($this->_config['redirect']);
} else {

View File

@ -11,16 +11,16 @@ class CustomerUpdatePassword extends Mailable
use Queueable, SerializesModels;
/**
* The admin instance.
* The customer instance.
*
* @var \Webkul\User\Contracts\Admin $admin
* @var \Webkul\Customer\Models\Customer $customer
*/
public $customer;
/**
* Create a new message instance.
*
* @param \Webkul\User\Contracts\Admin $admin
* @param \Webkul\Customer\Models\Customer $customer
* @return void
*/
public function __construct($customer)

View File

@ -16,4 +16,36 @@ class CustomerRepository extends Repository
{
return 'Webkul\Customer\Contracts\Customer';
}
/**
* Check if customer has order pending or processing.
*
* @param Webkul\Customer\Models\Customer
* @return boolean
*/
public function checkIfCustomerHasOrderPendingOrProcessing($customer)
{
return $customer->all_orders->pluck('status')->contains(function ($val) {
return $val === 'pending' || $val === 'processing';
});
}
/**
* Check if bulk customers, if they have order pending or processing.
*
* @param array
* @return boolean
*/
public function checkBulkCustomerIfTheyHaveOrderPendingOrProcessing($customerIds)
{
foreach ($customerIds as $customerId) {
$customer = $this->findorFail($customerId);
if ($this->checkIfCustomerHasOrderPendingOrProcessing($customer)) {
return true;
}
}
return false;
}
}

View File

@ -6,12 +6,8 @@ use Faker\Generator as Faker;
use Webkul\Product\Models\Product;
$factory->define(Product::class, function (Faker $faker) {
$now = date("Y-m-d H:i:s");
return [
'sku' => $faker->uuid,
'created_at' => $now,
'updated_at' => $now,
'attribute_family_id' => 1,
];
});
@ -26,4 +22,8 @@ $factory->state(Product::class, 'virtual', [
$factory->state(Product::class, 'downloadable', [
'type' => 'downloadable',
]);
$factory->state(Product::class, 'booking', [
'type' => 'booking',
]);

View File

@ -277,6 +277,12 @@ class Order extends Model implements OrderContract
return false;
}
foreach ($this->invoices as $item) {
if ($item->state == "pending" || $item->state == "overdue") {
return false;
}
}
foreach ($this->items as $item) {
if ($item->qty_to_refund > 0) {
return true;

View File

@ -97,7 +97,7 @@ class InvoiceRepository extends Repository
$invoice = $this->model->create([
'order_id' => $order->id,
'total_qty' => $totalQty,
'state' => 'paid',
'state' => 'pending',
'base_currency_code' => $order->base_currency_code,
'channel_currency_code' => $order->channel_currency_code,
'order_currency_code' => $order->order_currency_code,
@ -106,7 +106,7 @@ class InvoiceRepository extends Repository
foreach ($data['invoice']['items'] as $itemId => $qty) {
if (! $qty) {
continue;
continue;
}
$orderItem = $this->orderItemRepository->find($itemId);
@ -192,11 +192,8 @@ class InvoiceRepository extends Repository
}
$this->collectTotals($invoice);
$this->orderRepository->collectTotals($order);
$this->orderRepository->updateOrderStatus($order);
Event::dispatch('sales.invoice.save.after', $invoice);
} catch (\Exception $e) {
DB::rollBack();
@ -256,4 +253,16 @@ class InvoiceRepository extends Repository
return $invoice;
}
/**
* @param \Webkul\Sales\Contracts\Invoice $invoice
* @return void
*/
public function updateInvoiceState($invoice, $status)
{
$invoice->state = $status;
$invoice->save();
return true;
}
}

View File

@ -91,6 +91,13 @@
: '{{ __('velocity::app.shop.general.no') }}'"
></span>
@break;
@case('file')
<a v-if="product.product['{{ $attribute['code'] }}']" :href="`${baseUrl}/storage/${product.product['{{ $attribute['code'] }}']}`">
<span v-text="product.product['{{ $attribute['code'] }}'].substr(product.product['{{ $attribute['code'] }}'].lastIndexOf('/') + 1)" class="fs16"></span>
<i class='icon sort-down-icon download'></i>
</a>
<a v-else class="fs16">__</span>
@break;
@default
<span v-html="product['{{ $attribute['code'] }}'] ? product['{{ $attribute['code'] }}'] : product.product['{{ $attribute['code'] }}'] ? product.product['{{ $attribute['code'] }}'] : '__'" class="fs16"></span>
@break;

View File

@ -5,20 +5,24 @@
@if ($total = $reviewHelper->getTotalReviews($product))
<div class="product-ratings mb-10">
<span class="stars">
@for ($i = 1; $i <= round($reviewHelper->getAverageRating($product)); $i++)
<span class="icon star-icon"></span>
@for ($i = 1; $i <= 5; $i++)
@if($i <= round($reviewHelper->getAverageRating($product)))
<span class="icon star-icon"></span>
@else
<span class="icon star-icon-blank"></span>
@endif
@endfor
</span>
<div class="total-reviews">
{{
{{
__('shop::app.products.total-rating', [
'total_rating' => $reviewHelper->getTotalRating($product),
'total_rating' => $reviewHelper->getAverageRating($product),
'total_reviews' => $total,
])
])
}}
</div>
</div>
@endif
{!! view_render_event('bagisto.shop.products.review.after', ['product' => $product]) !!}
{!! view_render_event('bagisto.shop.products.review.after', ['product' => $product]) !!}

View File

@ -55,16 +55,20 @@
</span>
<span class="stars">
@for ($i = 1; $i <= $reviewHelper->getAverageRating($product); $i++)
@for ($i = 1; $i <= 5; $i++)
@if($i <= round($reviewHelper->getAverageRating($product)))
<span class="icon star-icon"></span>
@else
<span class="icon star-icon-blank"></span>
@endif
@endfor
</span>
<div class="total-reviews mt-5">
{{ __('shop::app.reviews.ratingreviews', [
'rating' => $reviewHelper->getTotalRating($product),
'rating' => $reviewHelper->getAverageRating($product),
'review' => $reviewHelper->getTotalReviews($product)])
}}
</div>
@ -101,9 +105,13 @@
</div>
<span class="stars">
@for ($i = 1; $i <= $review->rating; $i++)
@for ($i = 1; $i <= 5; $i++)
@if($i <= $review->rating)
<span class="icon star-icon"></span>
@else
<span class="icon star-icon-blank"></span>
@endif
@endfor
</span>
@ -154,4 +162,4 @@
</script>
@endpush
@endpush

View File

@ -10,22 +10,24 @@
<span>{{ __('shop::app.products.qty') }}</span>
</li>
@foreach ($product->grouped_products as $groupedProduct)
<li>
<span class="name">
{{ $groupedProduct->associated_product->name }}
@if($groupedProduct->associated_product->getTypeInstance()->isSaleable())
<li>
<span class="name">
{{ $groupedProduct->associated_product->name }}
@include ('shop::products.price', ['product' => $groupedProduct->associated_product])
</span>
@include ('shop::products.price', ['product' => $groupedProduct->associated_product])
</span>
<span class="qty">
<quantity-changer
:control-name="'qty[{{$groupedProduct->associated_product_id}}]'"
:validations="'required|numeric|min_value:0'"
quantity="{{ $groupedProduct->qty }}"
min-quantity="0">
</quantity-changer>
</span>
</li>
<span class="qty">
<quantity-changer
:control-name="'qty[{{$groupedProduct->associated_product_id}}]'"
:validations="'required|numeric|min_value:0'"
quantity="{{ $groupedProduct->qty }}"
min-quantity="0">
</quantity-changer>
</span>
</li>
@endif
@endforeach
</ul>
</div>

View File

@ -16,9 +16,13 @@
</span>
<span class="stars">
@for ($i = 1; $i <= round($reviewHelper->getAverageRating($product)); $i++)
@for ($i = 1; $i <= 5; $i++)
@if($i <= round($reviewHelper->getAverageRating($product)))
<span class="icon star-icon"></span>
@else
<span class="icon star-icon-blank"></span>
@endif
@endfor
</span>
@ -46,9 +50,13 @@
</div>
<span class="stars">
@for ($i = 1; $i <= $review->rating; $i++)
@for ($i = 1; $i <= 5; $i++)
@if($i <= $review->rating)
<span class="icon star-icon"></span>
@else
<span class="icon star-icon-blank"></span>
@endif
@endfor
</span>
@ -87,4 +95,4 @@
@endif
@endif
{!! view_render_event('bagisto.shop.products.view.reviews.after', ['product' => $product]) !!}
{!! view_render_event('bagisto.shop.products.view.reviews.after', ['product' => $product]) !!}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 50 (54983) - http://www.bohemiancoding.com/sketch -->
<title>Star-icon-blank</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Star-icon-blank" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<polygon id="Star" fill="#d4d4d4" fill-rule="nonzero" points="7.99999999 13.2668737 3.05572808 16 4 10.2111456 0 6.11145618 5.52786404 5.26687371 7.99999999 0 10.472136 5.26687371 16 6.11145618 12 10.2111456 12.9442719 16"></polygon>
</g>
</svg>

After

Width:  |  Height:  |  Size: 706 B

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,4 @@
{
"/js/ui.js": "/js/ui.js?id=9f7467acd7ea119b7d87",
"/css/ui.css": "/css/ui.css?id=b5bedc0ff04a145ca18a"
"/js/ui.js": "/js/ui.js?id=706b63016a08ec91d32b",
"/css/ui.css": "/css/ui.css?id=54e0814214c81d98a101"
}

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 50 (54983) - http://www.bohemiancoding.com/sketch -->
<title>Star-icon-blank</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Star-icon-blank" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<polygon id="Star" fill="#d4d4d4" fill-rule="nonzero" points="7.99999999 13.2668737 3.05572808 16 4 10.2111456 0 6.11145618 5.52786404 5.26687371 7.99999999 0 10.472136 5.26687371 16 6.11145618 12 10.2111456 12.9442719 16"></polygon>
</g>
</svg>

After

Width:  |  Height:  |  Size: 706 B

View File

@ -194,6 +194,12 @@
height: 24px;
}
.star-icon-blank {
background-image: url("../images/Star-Icon-Blank.svg");
width: 24px;
height: 24px;
}
.arrow-down-white-icon {
background-image: url("../images/down-arrow-white.svg");
width: 17px;
@ -346,4 +352,4 @@
background-image: url("../images/Camera.svg");
width: 24px;
height: 24px;
}
}

View File

@ -1,5 +1,5 @@
<tbody>
@if (count($records))
@if ($records instanceof \Illuminate\Pagination\LengthAwarePaginator && count($records))
@foreach ($records as $key => $record)
<tr>
@if ($enableMassActions)
@ -59,7 +59,7 @@
data-method="{{ $action['method'] }}"
data-action="{{ route($action['route'], $record->{$index}) }}"
data-token="{{ csrf_token() }}"
@if (isset($action['target']))
target="{{ $action['target'] }}"
@endif
@ -78,7 +78,9 @@
@endforeach
@else
<tr>
<td colspan="10" style="text-align: center;">{{ $norecords }}</td>
<td colspan="10">
<p style="text-align: center;">{{ $norecords }}</p>
</td>
</tr>
@endif
</tbody>

View File

@ -1,4 +1,4 @@
@if (gettype($results) == 'object')
@if ($results instanceof \Illuminate\Pagination\LengthAwarePaginator)
<div class="pagination">
{{ $results->links() }}
</div>

View File

@ -1,6 +1,6 @@
<thead v-if="massActionsToggle == false">
<tr style="height: 65px;">
@if (count($results['records']) && $results['enableMassActions'])
@if ($results['records'] instanceof \Illuminate\Pagination\LengthAwarePaginator && count($results['records']) && $results['enableMassActions'])
<th class="grid_head" id="mastercheckbox" style="width: 50px;">
<span class="checkbox">
<input type="checkbox" v-model="allSelected" v-on:change="selectAll">

View File

@ -8,22 +8,9 @@
@push('scripts')
<script type="text/x-template" id="datagrid-filters">
<div class="grid-container">
<div class="datagrid-filters" id="datagrid-filters">
<div class="datagrid-filters">
<div class="filter-left">
<div class="search-filter">
<input type="search" id="search-field" class="control"
placeholder="{{ __('ui::app.datagrid.search') }}" v-model="searchValue"
v-on:keyup.enter="searchCollection(searchValue)"/>
<div class="icon-wrapper">
<span class="icon search-icon search-btn"
v-on:click="searchCollection(searchValue)"></span>
</div>
</div>
</div>
<div class="filter-right">
@if (isset($results['extraFilters']['channels']))
<div class="dropdown-filters per-page">
<div class="control-group">
@ -82,7 +69,24 @@
</div>
</div>
@endif
</div>
</div>
<div class="datagrid-filters" id="datagrid-filters">
<div class="filter-left">
<div class="search-filter">
<input type="search" id="search-field" class="control"
placeholder="{{ __('ui::app.datagrid.search') }}" v-model="searchValue"
v-on:keyup.enter="searchCollection(searchValue)"/>
<div class="icon-wrapper">
<span class="icon search-icon search-btn"
v-on:click="searchCollection(searchValue)"></span>
</div>
</div>
</div>
<div class="filter-right">
<div class="dropdown-filters per-page">
<div class="control-group">
<label class="per-page-label" for="perPage">

View File

@ -18,7 +18,7 @@ class AdminUpdatePassword extends Mailable
public $admin;
/**
* Create a new message instance.
* Create a new admin instance.
*
* @param \Webkul\User\Contracts\Admin $admin
* @return void

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,5 @@
{
"/js/velocity.js": "/js/velocity.js?id=c18e7d7ccfb80712f078",
"/js/velocity.js": "/js/velocity.js?id=0dcf3ed371cdd1a97616",
"/css/velocity-admin.css": "/css/velocity-admin.css?id=612d35e452446366eef7",
"/css/velocity.css": "/css/velocity.css?id=a47fd28f19c39ff820ba"
"/css/velocity.css": "/css/velocity.css?id=fde6d681177207bbbbb1"
}

View File

@ -1,12 +1,12 @@
<template>
<div class="col-12 lg-card-container list-card product-card row" v-if="list">
<div class="product-image">
<div class="product-image" style="margin: auto;">
<a :title="product.name" :href="`${baseUrl}/${product.slug}`">
<img
:src="product.image"
:onerror="`this.src='${this.$root.baseUrl}/vendor/webkul/ui/assets/images/product/large-product-placeholder.png'`" />
<product-quick-view-btn :quick-view-details="product"></product-quick-view-btn>
<product-quick-view-btn :quick-view-details="product" v-if="!isMobile()"></product-quick-view-btn>
</a>
</div>
@ -101,5 +101,15 @@
'addToCartHtml': '',
}
},
methods: {
'isMobile': function () {
if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
return true;
} else {
return false;
}
}
}
}
</script>

View File

@ -56,6 +56,7 @@
margin-bottom: 1rem;
margin-top: 68px;
color: #212529;
overflow-x: auto;
}
.per-page {
@ -87,13 +88,13 @@
.quick-view-btn-container {
left: -26px;
width: 109px;
}
}
.quick-view-btn-container span {
left: 24%;
top: -24px;
font-size: 13px;
}
}
}
@media only screen and (max-width: 992px) {
@ -467,20 +468,23 @@
td {
width: 100%;
display: block;
border-top: none;
border-right: 1px solid $border-common !important;
&:before {
content: attr(data-value);
font-size: 15px;
font-weight: 600;
display: inline-block;
width: 120px;
}
.action {
display: inline-block;
}
&:first-child {
font-weight: bold;
}
}
}
}
@ -1014,4 +1018,4 @@
position: absolute;
display: inline-block;
}
}
}

View File

@ -59,6 +59,13 @@ body {
}
}
}
#mini-cart {
.badge {
top: -8px;
left: 73%;
}
}
}
}

View File

@ -263,12 +263,14 @@ return [
'view' => 'رأي',
'filter' => 'منقي',
'update' => 'تحديث',
'download' => 'تحميل',
'addresses' => 'عناوين',
'reviews' => 'التعليقات',
'orders' => 'الطلب #٪ s',
'currencies' => 'Currencies',
'reviews' => 'التعليقات',
'top-brands' => 'ارقى الماركات',
'new-password' => 'كلمة مرور جديدة',
'no-file-available' => 'لا يوجد ملف متاح!',
'downloadables' => 'المنتجات القابلة للتحميل',
'confirm-new-password' => 'تأكيد كلمة المرور الجديدة',
'enter-current-password' => 'أدخل كلمة المرور الحالية',

View File

@ -272,6 +272,8 @@ return [
'downloadables' => 'Herunterladbare Produkte',
'confirm-new-password' => 'Bestätigen Sie Ihr neues Passwort',
'enter-current-password' => 'Geben Sie Ihr aktuelles Passwort ein',
'download' => 'Downloaden',
'no-file-available' => 'Geen bestand beschikbaar!',
'alert' => [
'info' => 'Information',

View File

@ -265,10 +265,12 @@ return [
'orders' => 'Orders',
'update' => 'Update',
'reviews' => 'Reviews',
'download' => 'Download',
'currencies' => 'Currencies',
'addresses' => 'Addresses',
'top-brands' => 'Top Brands',
'new-password' => 'New password',
'no-file-available' => 'No File Available!',
'downloadables' => 'Downloadable Products',
'confirm-new-password' => 'Confirm new password',
'enter-current-password' => 'Enter your current password',

View File

@ -260,16 +260,18 @@ return [
'general' => [
'no' => 'No',
'yes' => 'Yes',
'view' => 'چشم انداز',
'filter' => 'فیلتر',
'view' => 'چشم انداز',
'orders' => 'سفارشات',
'update' => 'به روز رسانی',
'download' => 'دانلود',
'reviews' => 'بررسی ها',
'addresses' => 'آدرس ها',
'update' => 'به روز رسانی',
'currencies' => 'Currencies',
'top-brands' => 'برندهای برتر',
'new-password' => 'رمز عبور جدید',
'downloadables' => 'محصولات دانلودی',
'no-file-available' => 'هیچ پرونده ای موجود نیست',
'confirm-new-password' => 'رمزعبور جدید را تأیید کنید',
'enter-current-password' => 'رمز عبور فعلی خود را وارد کنید',

View File

@ -274,6 +274,8 @@ return [
'downloadables' => 'Prodotti Scaricabili',
'confirm-new-password' => 'Conferma nuova password',
'enter-current-password' => 'Inserisci la password attuale',
'download' => 'Scarica',
'no-file-available' => 'Nessun file disponibile!',
'alert' => [
'info' => 'Info',

View File

@ -266,12 +266,14 @@ return [
'update' => 'Bijwerken',
'reviews' => 'Reviews',
'addresses' => 'Adressen',
'download' => 'Downloaden',
'currencies' => 'Currencies',
'top-brands' => 'Top merken',
'new-password' => 'Nieuw wachtwoord',
'downloadables' => 'Downloadable Products',
'confirm-new-password' => 'Bevestig uw nieuw wachtwoord',
'enter-current-password' => 'Huidig wachtwoord',
'no-file-available' => 'Geen bestand beschikbaar!',
'confirm-new-password' => 'Bevestig uw nieuw wachtwoord',
'alert' => [
'info' => 'Info',

View File

@ -270,6 +270,8 @@ return [
'downloadables' => 'Produkty do pobrania',
'confirm-new-password' => 'Potwierdź nowe hasło',
'enter-current-password' => 'Wpisz swoje aktualne hasło',
'download' => 'Pobieranie',
'no-file-available' => 'Brak dostępnego pliku!',
'alert' => [
'info' => 'Info',

View File

@ -273,6 +273,8 @@ return [
'downloadables' => 'Produtos para download',
'confirm-new-password' => 'Confirme a nova senha',
'enter-current-password' => 'Digite sua senha atual',
'download' => 'Baixar',
'no-file-available' => 'Nenhum arquivo disponível!',
'alert' => [
'info' => 'Informações',

View File

@ -269,6 +269,8 @@ return [
'downloadables' => 'İndirilebilir Ürünler',
'confirm-new-password' => 'Parola Doğrula',
'enter-current-password' => 'Mevcut Parolanızı Girin',
'download' => 'İndir',
'no-file-available' => 'Dosya Yok!',
'alert' => [
'info' => 'Bilgi',

View File

@ -110,7 +110,14 @@
? '{{ __('velocity::app.shop.general.yes') }}'
: '{{ __('velocity::app.shop.general.no') }}'"
></span>
@break;
@break;
@case('file')
<a v-if="product.product['{{ $attribute['code'] }}']" :href="`${$root.baseUrl}/storage/${product.product['{{ $attribute['code'] }}']}`">
<span v-text="product.product['{{ $attribute['code'] }}'].substr(product.product['{{ $attribute['code'] }}'].lastIndexOf('/') + 1)" class="fs16"></span>
<i class='material-icons'>arrow_downward</i>
</a>
<a v-else class="fs16">__</span>
@break;
@default
<span v-html="product['{{ $attribute['code'] }}'] ? product['{{ $attribute['code'] }}'] : product.product['{{ $attribute['code'] }}'] ? product.product['{{ $attribute['code'] }}'] : '__'" class="fs16"></span>
@break;

View File

@ -8,7 +8,7 @@
$total = $reviewHelper->getTotalReviews($product);
$avgRatings = $reviewHelper->getAverageRating($product);
$avgStarRating = ceil($avgRatings);
$avgStarRating = round($avgRatings);
$productImages = [];
$images = $productImageHelper->getGalleryImages($product);

View File

@ -27,8 +27,8 @@
@if ($attribute['type'] == 'file' && $attribute['value'])
<td>
<a href="{{ route('shop.product.file.download', [$product->product_id, $attribute['id']])}}">
<i class="icon sort-down-icon download"></i>
<a href="{{ route('shop.product.file.download', [$product->product_id, $attribute['id']])}}" style="color:black;">
<i class="icon rango-download-1"></i>
</a>
</td>
@elseif ($attribute['type'] == 'image' && $attribute['value'])

View File

@ -10,22 +10,24 @@
<span>{{ __('shop::app.products.qty') }}</span>
</li>
@foreach ($product->grouped_products as $groupedProduct)
<li>
<span class="name">
{{ $groupedProduct->associated_product->name }}
@if($groupedProduct->associated_product->getTypeInstance()->isSaleable())
<li>
<span class="name">
{{ $groupedProduct->associated_product->name }}
@include ('shop::products.price', ['product' => $groupedProduct->associated_product])
</span>
@include ('shop::products.price', ['product' => $groupedProduct->associated_product])
</span>
<span class="qty">
<quantity-changer
:control-name="'qty[{{$groupedProduct->associated_product_id}}]'"
:validations="'required|numeric|min_value:0'"
quantity="{{ $groupedProduct->qty }}"
min-quantity="0">
</quantity-changer>
</span>
</li>
<span class="qty">
<quantity-changer
:control-name="'qty[{{$groupedProduct->associated_product_id}}]'"
:validations="'required|numeric|min_value:0'"
quantity="{{ $groupedProduct->qty }}"
min-quantity="0">
</quantity-changer>
</span>
</li>
@endif
@endforeach
</ul>
</div>

View File

@ -6,7 +6,7 @@
$total = $reviewHelper->getTotalReviews($product);
$avgRatings = $reviewHelper->getAverageRating($product);
$avgStarRating = ceil($avgRatings);
$avgStarRating = round($avgRatings);
}
$percentageRatings = $reviewHelper->getPercentageRating($product);