Merge branch 'bagisto/master' into introduce-product-copy

This commit is contained in:
Herbert Maschke 2020-08-10 17:43:31 +02:00
commit c4fdf11633
13 changed files with 1578 additions and 142 deletions

View File

@ -23,5 +23,15 @@ return [
'name' => 'Velocity',
'parent' => 'default'
],
],
'admin-default' => 'default',
'admin-themes' => [
'default' => [
'views_path' => 'resources/admin-themes/default/views',
'assets_path' => 'public/admin-themes/default/assets',
'name' => 'Default'
]
]
];

View File

@ -51,7 +51,7 @@ class ProductDataGrid extends DataGrid
->select(
'product_flat.locale',
'product_flat.channel',
'product_flat.product_id as product_id',
'product_flat.product_id',
'products.sku as product_sku',
'product_flat.name as product_name',
'products.type as product_type',
@ -61,17 +61,9 @@ class ProductDataGrid extends DataGrid
DB::raw('SUM(DISTINCT ' . DB::getTablePrefix() . 'product_inventories.qty) as quantity')
);
if ($this->locale !== 'all') {
$queryBuilder->where('product_flat.locale', $this->locale);
}
if ($this->channel !== 'all') {
$queryBuilder->where('product_flat.channel', $this->channel);
}
$queryBuilder->groupBy('product_flat.product_id');
$queryBuilder->having('locale', $this->locale !== 'all' ? $this->locale : 'en');
$queryBuilder->having('channel', $this->channel !== 'all' ? $this->channel : 'default');
$queryBuilder->groupBy('product_flat.product_id', 'product_flat.locale', 'product_flat.channel');
$queryBuilder->where('locale', $this->locale !== 'all' ? $this->locale : 'en');
$queryBuilder->where('channel', $this->channel !== 'all' ? $this->channel : 'default');
$this->addFilter('product_id', 'product_flat.product_id');
$this->addFilter('product_name', 'product_flat.name');

View File

@ -206,6 +206,7 @@ class CustomerController extends Controller
$this->customerRepository->delete($id);
} else {
session()->flash('error', trans('admin::app.response.order-pending', ['name' => 'Customer']));
return response()->json(['message' => false], 400);
}

View File

@ -23,17 +23,19 @@ class Order
*/
public function sendNewOrderMail($order)
{
$customerLocale = $this->getLocale($order);
try {
/* email to customer */
$configKey = 'emails.general.notifications.emails.general.notifications.new-order';
if (core()->getConfigData($configKey))
Mail::queue(new NewOrderNotification($order));
if (core()->getConfigData($configKey)) {
$this->prepareMail($customerLocale, new NewOrderNotification($order));
}
/* email to admin */
$configKey = 'emails.general.notifications.emails.general.notifications.new-admin';
if (core()->getConfigData($configKey)) {
app()->setLocale(env('APP_LOCALE'));
Mail::queue(new NewAdminNotification($order));
$this->prepareMail(env('APP_LOCALE'), new NewAdminNotification($order));
}
} catch (\Exception $e) {
report($e);
@ -48,15 +50,17 @@ class Order
*/
public function sendNewInvoiceMail($invoice)
{
$customerLocale = $this->getLocale($invoice);
try {
if ($invoice->email_sent) {
return;
}
/* email to customer */
$configKey = 'emails.general.notifications.emails.general.notifications.new-invoice';
if (core()->getConfigData($configKey)) {
Mail::queue(new NewInvoiceNotification($invoice));
$this->prepareMail($customerLocale, new NewInvoiceNotification($invoice));
}
} catch (\Exception $e) {
report($e);
@ -71,11 +75,13 @@ class Order
*/
public function sendNewRefundMail($refund)
{
try {
$configKey = 'emails.general.notifications.emails.general.notifications.new-refund';
$customerLocale = $this->getLocale($refund);
try {
/* email to customer */
$configKey = 'emails.general.notifications.emails.general.notifications.new-refund';
if (core()->getConfigData($configKey)) {
Mail::queue(new NewRefundNotification($refund));
$this->prepareMail($customerLocale, new NewRefundNotification($refund));
}
} catch (\Exception $e) {
report($e);
@ -90,21 +96,23 @@ class Order
*/
public function sendNewShipmentMail($shipment)
{
$customerLocale = $this->getLocale($shipment);
try {
if ($shipment->email_sent) {
return;
}
/* email to customer */
$configKey = 'emails.general.notifications.emails.general.notifications.new-shipment';
if (core()->getConfigData($configKey)) {
Mail::queue(new NewShipmentNotification($shipment));
$this->prepareMail($customerLocale, new NewShipmentNotification($shipment));
}
/* email to admin */
$configKey = 'emails.general.notifications.emails.general.notifications.new-inventory-source';
if (core()->getConfigData($configKey)) {
Mail::queue(new NewInventorySourceNotification($shipment));
$this->prepareMail(env('APP_LOCALE'), new NewInventorySourceNotification($shipment));
}
} catch (\Exception $e) {
report($e);
@ -117,18 +125,19 @@ class Order
*/
public function sendCancelOrderMail($order)
{
$customerLocale = $this->getLocale($order);
try {
/* email to customer */
$configKey = 'emails.general.notifications.emails.general.notifications.cancel-order';
if (core()->getConfigData($configKey)) {
Mail::queue(new CancelOrderNotification($order));
$this->prepareMail($customerLocale, new CancelOrderNotification($order));
}
/* email to admin */
$configKey = 'emails.general.notifications.emails.general.notifications.new-admin';
if (core()->getConfigData($configKey)) {
app()->setLocale(env('APP_LOCALE'));
Mail::queue(new CancelOrderAdminNotification($order));
$this->prepareMail(env('APP_LOCALE'), new CancelOrderAdminNotification($order));
}
} catch (\Exception $e) {
report($e);
@ -141,14 +150,43 @@ class Order
*/
public function sendOrderCommentMail($comment)
{
$customerLocale = $this->getLocale($comment);
if (! $comment->customer_notified) {
return;
}
try {
Mail::queue(new OrderCommentNotification($comment));
/* email to customer */
$this->prepareMail($customerLocale, new OrderCommentNotification($comment));
} catch (\Exception $e) {
report($e);
}
}
/**
* Get the locale of the customer if somehow item name changes then the english locale will pe provided.
*
* @param object \Webkul\Sales\Contracts\Order|\Webkul\Sales\Contracts\Invoice|\Webkul\Sales\Contracts\Refund|\Webkul\Sales\Contracts\Shipment|\Webkul\Sales\Contracts\OrderComment
* @return string
*/
private function getLocale($object)
{
if ($object instanceof \Webkul\Sales\Contracts\OrderComment) {
$object = $object->order;
}
$objectFirstItem = $object->items->first();
return isset($objectFirstItem->additional['locale']) ? $objectFirstItem->additional['locale'] : 'en';
}
/**
* Prepare Mail.
* @return void
*/
private function prepareMail($locale, $notification)
{
app()->setLocale($locale);
Mail::queue($notification);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -159,8 +159,6 @@ class AttributeController extends Controller
$suppressFlash = true;
$this->attributeRepository->delete($value);
} else {
session()->flash('error', trans('admin::app.response.user-define-error', ['name' => 'Attribute']));
}
} catch (\Exception $e) {
report($e);
@ -174,7 +172,7 @@ class AttributeController extends Controller
if ($suppressFlash) {
session()->flash('success', trans('admin::app.datagrid.mass-ops.delete-success', ['resource' => 'attributes']));
} else {
session()->flash('info', trans('admin::app.datagrid.mass-ops.partial-action', ['resource' => 'attributes']));
session()->flash('error', trans('admin::app.response.user-define-error', ['name' => 'Attribute']));
}
return redirect()->back();

View File

@ -886,6 +886,8 @@ class Cart
*/
public function prepareDataForOrderItem($data): array
{
$locale = ['locale' => core()->getCurrentLocale()->code];
$finalData = [
'product' => $this->productRepository->find($data['product_id']),
'sku' => $data['sku'],
@ -904,7 +906,7 @@ class Cart
'discount_percent' => $data['discount_percent'],
'discount_amount' => $data['discount_amount'],
'base_discount_amount' => $data['base_discount_amount'],
'additional' => $data['additional'],
'additional' => is_array($data['additional']) ? array_merge($data['additional'], $locale) : $locale,
];
if (isset($data['children']) && $data['children']) {

View File

@ -254,7 +254,7 @@ class InvoiceRepository extends Repository
return $invoice;
}
/**
/*
* @param \Webkul\Sales\Contracts\Invoice $invoice
* @return void
*/

View File

@ -25,13 +25,13 @@
$comparableAttributes = $comparableAttributes->toArray();
array_splice($comparableAttributes, 1, 0, [[
'code' => 'image',
'admin_name' => 'Product Image'
'admin_name' => 'Product Image',
'type' => 'product_image'
]]);
array_splice($comparableAttributes, 2, 0, [[
'code' => 'addToCartHtml',
'admin_name' => 'Actions'
'admin_name' => 'Actions',
'type' => 'action'
]]);
@endphp
@ -42,70 +42,67 @@
</td>
<td :key="`title-${index}`" v-for="(product, index) in products">
@switch ($attribute['code'])
@case('name')
@switch ($attribute['type'])
@case('text')
<a :href="`${baseUrl}/${product.url_key}`" class="unset remove-decoration active-hover">
<h3 class="fw6 fs18" v-text="product['{{ $attribute['code'] }}']"></h3>
</a>
@break;
@case('textarea')
<span v-html="product.product['{{ $attribute['code'] }}']"></span>
@break;
@case('price')
<span v-html="product.product['{{ $attribute['code'] }}']"></span>
@break;
@case('boolean')
<span
v-text="product.product['{{ $attribute['code'] }}']
? '{{ __('velocity::app.shop.general.yes') }}'
: '{{ __('velocity::app.shop.general.no') }}'"
></span>
@break;
@case('select')
<span v-html="product.product['{{ $attribute['code'] }}']" class="fs16"></span>
@break;
@case('multiselect')
<span v-html="product.product['{{ $attribute['code'] }}']" class="fs16"></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>
<span v-else class="fs16">__</span>
@break;
@case('image')
<img v-if="product.product['{{ $attribute['code'] }}']" :src="`${baseUrl}/storage/${product.product['{{ $attribute['code'] }}']}`">
@break;
@case('product_image')
<a :href="`${baseUrl}/${product.url_key}`" class="unset">
<img
class="image-wrapper"
:src="product['{{ $attribute['code'] }}']"
:src="product['product_image']"
:onerror="`this.src='${baseUrl}/vendor/webkul/ui/assets/images/product/large-product-placeholder.png'`" />
</a>
@break
@break
@case('price')
<span v-html="product['priceHTML']"></span>
@break
@case('addToCartHtml')
@case('action')
<div class="action">
<div v-html="product.defaultAddToCart"></div>
<span class="icon white-cross-sm-icon remove-product" @click="removeProductCompare(product.id)"></span>
</div>
@break
@break;
@case('color')
<span v-html="product.color_label" class="fs16"></span>
@break
@case('size')
<span v-html="product.size_label" class="fs16"></span>
@break
@case('description')
<span v-html="product.description"></span>
@break
@default
@switch ($attribute['type'])
@case('boolean')
<span
v-text="product.product['{{ $attribute['code'] }}']
? '{{ __('velocity::app.shop.general.yes') }}'
: '{{ __('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;
@endswitch
@break
@endswitch
@endswitch
</td>
</tr>
@endforeach

View File

@ -4,6 +4,7 @@ namespace Webkul\Theme;
use Webkul\Theme\Facades\Themes;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use Illuminate\View\FileViewFinder;
class ThemeViewFinder extends FileViewFinder
@ -19,7 +20,7 @@ class ThemeViewFinder extends FileViewFinder
// Extract the $view and the $namespace parts
list($namespace, $view) = $this->parseNamespaceSegments($name);
if ($namespace != 'admin') {
if (! Str::contains(request()->route()->uri, 'admin/')) {
$paths = $this->addThemeNamespacePaths($namespace);
try {
@ -34,7 +35,23 @@ class ThemeViewFinder extends FileViewFinder
return $this->findInPaths($view, $paths);
}
} else {
return $this->findInPaths($view, $this->hints[$namespace]);
$themes = app('themes');
$themes->set(config('themes.admin-default'));
$paths = $this->addThemeNamespacePaths($namespace);
try {
return $this->findInPaths($view, $paths);
} catch(\Exception $e) {
if ($namespace != 'admin') {
if (strpos($view, 'admin.') !== false) {
$view = str_replace('admin.', 'admin.' . Themes::current()->code . '.', $view);
}
}
return $this->findInPaths($view, $paths);
}
}
}
@ -84,19 +101,6 @@ class ThemeViewFinder extends FileViewFinder
}
}
/**
* Get the string contents of the view.
*
* @param callable|null $callback
* @return array|string
*
* @throws \Throwable
*/
public function render(callable $callback = null)
{
dd(111);
}
/**
* Set the array of paths where the views are being searched.
*

View File

@ -3,6 +3,7 @@
namespace Webkul\Theme;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Str;
use Webkul\Theme\Theme;
class Themes
@ -42,9 +43,15 @@ class Themes
*/
public function __construct()
{
$this->laravelViewsPath = Config::get('view.paths');
$routeURI = request()->route()->uri;
$this->defaultThemeCode = Config::get('themes.default', null);
if (Str::contains(request()->route()->uri, 'admin/')) {
$this->defaultThemeCode = Config::get('themes.admin-default', null);
} else {
$this->defaultThemeCode = Config::get('themes.default', null);
}
$this->laravelViewsPath = Config::get('view.paths');
$this->loadThemes();
}
@ -85,7 +92,11 @@ class Themes
{
$parentThemes = [];
$themes = config('themes.themes', []);
if (Str::contains(request()->route()->uri, 'admin/')) {
$themes = config('themes.admin-themes', []);
} else {
$themes = config('themes.themes', []);
}
foreach ($themes as $code => $data) {
$this->themes[] = new Theme(
@ -140,6 +151,7 @@ class Themes
Config::set('view.paths', $paths);
$themeViewFinder = app('view.finder');
$themeViewFinder->setPaths($paths);
return $theme;

View File

@ -385,7 +385,7 @@ class Helper extends Review
$productMetaDetails = [];
$productMetaDetails['slug'] = $product->url_key;
$productMetaDetails['image'] = $formattedProduct['image'];
$productMetaDetails['product_image'] = $formattedProduct['image'];
$productMetaDetails['priceHTML'] = $formattedProduct['priceHTML'];
$productMetaDetails['new'] = $formattedProduct['new'];
$productMetaDetails['addToCartHtml'] = $formattedProduct['addToCartHtml'];

View File

@ -1,6 +1,10 @@
@php
$attributeRepository = app('\Webkul\Attribute\Repositories\AttributeRepository');
$comparableAttributes = $attributeRepository->findByField('is_comparable', 1);
$locale = request()->get('locale') ?: app()->getLocale();
$attributeOptionTranslations = DB::table(DB::getTablePrefix() . 'attribute_option_translations')->where('locale', $locale)->get()->toJson();
@endphp
@push('css')
@ -39,13 +43,13 @@
$comparableAttributes = $comparableAttributes->toArray();
array_splice($comparableAttributes, 1, 0, [[
'code' => 'image',
'admin_name' => __('velocity::app.customer.compare.product_image')
'admin_name' => 'Product Image',
'type' => 'product_image'
]]);
array_splice($comparableAttributes, 2, 0, [[
'code' => 'addToCartHtml',
'admin_name' => __('velocity::app.customer.compare.actions')
'admin_name' => 'Actions',
'type' => 'action'
]]);
@endphp
@ -56,51 +60,65 @@
</td>
<td :key="`title-${index}`" v-for="(product, index) in products">
@switch ($attribute['code'])
@case('name')
<a :href="`${$root.baseUrl}/${product.url_key}`" class="unset remove-decoration active-hover">
<h1 class="fw6 fs18" v-text="product['{{ $attribute['code'] }}']"></h1>
@switch ($attribute['type'])
@case('text')
<a :href="`${baseUrl}/${product.url_key}`" class="unset remove-decoration active-hover">
<h3 class="fw6 fs18" v-text="product['{{ $attribute['code'] }}']"></h3>
</a>
@break;
@case('textarea')
<span v-html="product.product['{{ $attribute['code'] }}']"></span>
@break;
@case('price')
<span v-html="product.product['{{ $attribute['code'] }}']"></span>
@break;
@case('boolean')
<span
v-text="product.product['{{ $attribute['code'] }}']
? '{{ __('velocity::app.shop.general.yes') }}'
: '{{ __('velocity::app.shop.general.no') }}'"
></span>
@break;
@case('select')
<span v-html="product.product['{{ $attribute['code'] }}']" class="fs16"></span>
@break;
@case('multiselect')
<span v-html="product.product['{{ $attribute['code'] }}']" class="fs16"></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>
<span v-else class="fs16">__</span>
@break;
@case('image')
<a :href="`${$root.baseUrl}/${product.url_key}`" class="unset">
<img v-if="product.product['{{ $attribute['code'] }}']" :src="`${baseUrl}/storage/${product.product['{{ $attribute['code'] }}']}`">
@break;
@case('product_image')
<a :href="`${baseUrl}/${product.url_key}`" class="unset">
<img
class="image-wrapper"
:src="product['{{ $attribute['code'] }}']"
onload="window.updateHeight ? window.updateHeight() : ''"
:onerror="`this.src='${$root.baseUrl}/vendor/webkul/ui/assets/images/product/large-product-placeholder.png'`" />
:src="product['product_image']"
:onerror="`this.src='${baseUrl}/vendor/webkul/ui/assets/images/product/large-product-placeholder.png'`" />
</a>
@break
@break
@case('price')
<span v-html="product['priceHTML']"></span>
@break
@case('addToCartHtml')
@case('action')
<div class="action">
<vnode-injector :nodes="getDynamicHTML(product.addToCartHtml)"></vnode-injector>
<div v-html="product.defaultAddToCart"></div>
<i
class="material-icons cross fs16"
@click="removeProductCompare(product.id)">
close
</i>
<span class="icon white-cross-sm-icon remove-product" @click="removeProductCompare(product.id)"></span>
</div>
@break
@case('color')
<span v-html="product.color_label" class="fs16"></span>
@break
@case('size')
<span v-html="product.size_label" class="fs16"></span>
@break
@case('description')
<span v-html="product.description"></span>
@break
@break;
@default
@switch ($attribute['type'])
@ -116,7 +134,17 @@
<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>
<span v-else class="fs16">__</span>
@break;
@case('checkbox')
<span v-if="product.product['{{ $attribute['code'] }}']" v-html="getAttributeOptions(product['{{ $attribute['code'] }}'] ? product : product.product['{{ $attribute['code'] }}'] ? product.product : null, '{{ $attribute['code'] }}', 'multiple')" class="fs16"></span>
<span v-else class="fs16">__</span>
@break;
@case('select')
<span v-if="product.product['{{ $attribute['code'] }}']" v-html="getAttributeOptions(product['{{ $attribute['code'] }}'] ? product : product.product['{{ $attribute['code'] }}'] ? product.product : null, '{{ $attribute['code'] }}', 'single')" class="fs16"></span>
<span 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>
@ -148,6 +176,7 @@
return {
'products': [],
'isProductListLoaded': false,
'attributeOptions': JSON.parse(@json($attributeOptionTranslations)),
'isCustomer': '{{ auth()->guard('customer')->user() ? "true" : "false" }}' == "true",
}
},
@ -218,6 +247,7 @@
if (productId == "all") {
updatedItems = [];
this.$set(this, 'products', []);
window.showAlert(
`alert-success`,
this.__('shop.general.alert.success'),
@ -226,6 +256,7 @@
} else {
updatedItems = existingItems.filter(item => item != productId);
this.$set(this, 'products', this.products.filter(product => product.id != productId));
window.showAlert(
`alert-success`,
this.__('shop.general.alert.success'),
@ -238,6 +269,42 @@
this.$root.headerItemsCount++;
},
'getAttributeOptions': function (productDetails, attributeValues, type) {
var attributeOptions = '__';
if (productDetails && attributeValues) {
var attributeItems;
if (type == "multiple") {
attributeItems = productDetails[attributeValues].split(',');
} else if (type == "single") {
attributeItems = productDetails[attributeValues];
}
attributeOptions = this.attributeOptions.filter(option => {
if (type == "multiple") {
if (attributeItems.indexOf(option.attribute_option_id.toString()) > -1) {
return true;
}
} else if (type == "single") {
if (attributeItems == option.attribute_option_id.toString()) {
return true;
}
}
return false;
});
attributeOptions = attributeOptions.map(option => {
return option.label;
});
attributeOptions = attributeOptions.join(', ');
}
return attributeOptions;
}
}
});
</script>