Compare commits
6 Commits
1.0.0-rc.3
...
1.0.0-rc.4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ae7f8ed2c9 | ||
|
|
a3a86f4b2f | ||
|
|
9c081574c8 | ||
|
|
11edccad02 | ||
|
|
7c796802be | ||
|
|
5cc43bc889 |
@@ -55,6 +55,7 @@ RUN chmod +x artisan
|
|||||||
|
|
||||||
RUN ./artisan vendor:publish --tag=public --force ## creates public/vendor/jsvalidation
|
RUN ./artisan vendor:publish --tag=public --force ## creates public/vendor/jsvalidation
|
||||||
RUN ./artisan vendor:publish --tag=boilerplate-public --force --ansi ## creates public/vendor/boilerplate
|
RUN ./artisan vendor:publish --tag=boilerplate-public --force --ansi ## creates public/vendor/boilerplate
|
||||||
|
RUN ./artisan vendor:publish --tag=datatables-buttons --force --ansi ## creates public/vendor/datatables/buttons
|
||||||
|
|
||||||
## XXXvlab: 2025-09-25 these migration files are breaking first
|
## XXXvlab: 2025-09-25 these migration files are breaking first
|
||||||
## install, but we had to resolve to not install from scratch and use
|
## install, but we had to resolve to not install from scratch and use
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
namespace App\Http\Controllers\Shop\Auth;
|
namespace App\Http\Controllers\Shop\Auth;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Repositories\Core\User\ShopCart;
|
||||||
use Illuminate\Foundation\Auth\AuthenticatesUsers;
|
use Illuminate\Foundation\Auth\AuthenticatesUsers;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
@@ -31,6 +32,7 @@ class LoginController extends Controller
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
if ($this->guard()->attempt($credentials, $request->get('remember'))) {
|
if ($this->guard()->attempt($credentials, $request->get('remember'))) {
|
||||||
|
ShopCart::migrateGuestCartToUser();
|
||||||
$request->session()->regenerate();
|
$request->session()->regenerate();
|
||||||
if (back()->getTargetUrl() === route('Shop.Orders.store')) {
|
if (back()->getTargetUrl() === route('Shop.Orders.store')) {
|
||||||
$route = 'Shop.Orders.order';
|
$route = 'Shop.Orders.order';
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ namespace App\Http\Controllers\Shop\Auth;
|
|||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Http\Requests\Shop\RegisterCustomer;
|
use App\Http\Requests\Shop\RegisterCustomer;
|
||||||
|
use App\Repositories\Core\User\ShopCart;
|
||||||
use App\Repositories\Shop\CustomerSaleChannels;
|
use App\Repositories\Shop\CustomerSaleChannels;
|
||||||
use App\Repositories\Shop\CustomerAddresses;
|
use App\Repositories\Shop\CustomerAddresses;
|
||||||
use App\Repositories\Shop\Customers;
|
use App\Repositories\Shop\Customers;
|
||||||
@@ -33,6 +34,7 @@ class RegisterController extends Controller
|
|||||||
$user = $this->create($request->all());
|
$user = $this->create($request->all());
|
||||||
|
|
||||||
$this->guard()->login($user);
|
$this->guard()->login($user);
|
||||||
|
ShopCart::migrateGuestCartToUser();
|
||||||
|
|
||||||
return $request->wantsJson()
|
return $request->wantsJson()
|
||||||
? new JsonResponse([], 201)
|
? new JsonResponse([], 201)
|
||||||
|
|||||||
@@ -3,9 +3,11 @@
|
|||||||
namespace App\Models\Shop;
|
namespace App\Models\Shop;
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
class CustomerAddress extends Model
|
class CustomerAddress extends Model
|
||||||
{
|
{
|
||||||
|
use SoftDeletes;
|
||||||
protected $guarded = ['id'];
|
protected $guarded = ['id'];
|
||||||
|
|
||||||
protected $table = 'shop_customer_addresses';
|
protected $table = 'shop_customer_addresses';
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ class Invoice extends Model
|
|||||||
|
|
||||||
public function address(): BelongsTo
|
public function address(): BelongsTo
|
||||||
{
|
{
|
||||||
return $this->belongsTo(CustomerAddress::class, 'invoice_address_id');
|
return $this->belongsTo(CustomerAddress::class, 'invoice_address_id')->withTrashed();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function scopeByCustomer($query, $customerId)
|
public function scopeByCustomer($query, $customerId)
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ class Order extends Model
|
|||||||
|
|
||||||
public function delivery_address(): BelongsTo
|
public function delivery_address(): BelongsTo
|
||||||
{
|
{
|
||||||
return $this->belongsTo(CustomerAddress::class, 'delivery_address_id');
|
return $this->belongsTo(CustomerAddress::class, 'delivery_address_id')->withTrashed();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function delivery(): BelongsTo
|
public function delivery(): BelongsTo
|
||||||
|
|||||||
@@ -94,11 +94,106 @@ class ShopCart
|
|||||||
return self::get()->getContent();
|
return self::get()->getContent();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function get()
|
public static function migrateGuestCartToUser($userId = null)
|
||||||
{
|
{
|
||||||
$userId = Auth::guard('customer')->id();
|
$userId = self::resolveUserId($userId);
|
||||||
$sessionKey = 'cart_'.sha1(static::class . ($userId ?? 'guest'));
|
|
||||||
|
|
||||||
return Cart::session($sessionKey);
|
if ($userId === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$guestSessionKey = self::sessionKey();
|
||||||
|
$guestItems = Cart::session($guestSessionKey)->getContent();
|
||||||
|
|
||||||
|
if ($guestItems->count() === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$userSessionKey = self::sessionKey($userId);
|
||||||
|
|
||||||
|
foreach ($guestItems as $item) {
|
||||||
|
$existing = Cart::session($userSessionKey)->get($item->id);
|
||||||
|
|
||||||
|
if ($existing) {
|
||||||
|
Cart::session($userSessionKey)->update($item->id, [
|
||||||
|
'quantity' => [
|
||||||
|
'relative' => false,
|
||||||
|
'value' => $existing->quantity + $item->quantity,
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$itemData = [
|
||||||
|
'id' => $item->id,
|
||||||
|
'name' => $item->name,
|
||||||
|
'price' => $item->price,
|
||||||
|
'quantity' => $item->quantity,
|
||||||
|
'attributes' => self::extractAttributes($item),
|
||||||
|
];
|
||||||
|
|
||||||
|
if (isset($item->associatedModel)) {
|
||||||
|
$itemData['associatedModel'] = $item->associatedModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
$conditions = self::extractConditions($item);
|
||||||
|
if (! empty($conditions)) {
|
||||||
|
$itemData['conditions'] = $conditions;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cart::session($userSessionKey)->add($itemData);
|
||||||
|
}
|
||||||
|
|
||||||
|
Cart::session($guestSessionKey)->clear();
|
||||||
|
Cart::session($userSessionKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function extractAttributes($item)
|
||||||
|
{
|
||||||
|
if (! isset($item->attributes)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_object($item->attributes) && method_exists($item->attributes, 'toArray')) {
|
||||||
|
return $item->attributes->toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (array) $item->attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function extractConditions($item)
|
||||||
|
{
|
||||||
|
if (! isset($item->conditions)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_object($item->conditions) && method_exists($item->conditions, 'toArray')) {
|
||||||
|
return $item->conditions->toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (array) $item->conditions;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function resolveUserId($userId = null)
|
||||||
|
{
|
||||||
|
return $userId ?? Auth::guard('customer')->id();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function sessionKey($userId = null)
|
||||||
|
{
|
||||||
|
$key = $userId ?? 'guest';
|
||||||
|
|
||||||
|
return 'cart_'.sha1(static::class.$key);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function session($userId = null)
|
||||||
|
{
|
||||||
|
return Cart::session(self::sessionKey($userId));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function get($userId = null)
|
||||||
|
{
|
||||||
|
return self::session(self::resolveUserId($userId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,12 +17,15 @@ class InvoicePDF
|
|||||||
public static function get($id)
|
public static function get($id)
|
||||||
{
|
{
|
||||||
$invoice = Invoices::getFull($id);
|
$invoice = Invoices::getFull($id);
|
||||||
|
$customFields = [];
|
||||||
|
if ($orderRef = optional($invoice->order)->ref) {
|
||||||
|
$customFields['order number'] = $orderRef;
|
||||||
|
}
|
||||||
|
|
||||||
$customer = new Party([
|
$customer = new Party([
|
||||||
'name' => $invoice->customer->name,
|
'name' => optional($invoice->customer)->name ?? __('Client inconnu'),
|
||||||
'address' => self::makeAddress($invoice->address),
|
'address' => self::makeAddress($invoice->address),
|
||||||
'custom_fields' => [
|
'custom_fields' => $customFields,
|
||||||
'order number' => $invoice->order->ref,
|
|
||||||
],
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$items = self::makeItems($invoice->order->detail);
|
$items = self::makeItems($invoice->order->detail);
|
||||||
@@ -48,7 +51,17 @@ class InvoicePDF
|
|||||||
|
|
||||||
public static function makeAddress($address)
|
public static function makeAddress($address)
|
||||||
{
|
{
|
||||||
return $address->address.'<br>'.$address->zipcode.' '.$address->city;
|
if (! $address) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$lines = array_filter([
|
||||||
|
$address->address ?? '',
|
||||||
|
$address->address2 ?? '',
|
||||||
|
trim(($address->zipcode ?? '').' '.($address->city ?? '')),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return implode('<br>', $lines);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function makeItems($details)
|
public static function makeItems($details)
|
||||||
|
|||||||
@@ -48,13 +48,20 @@
|
|||||||
var $list = $('#addresses_list_{{ $prefix }}');
|
var $list = $('#addresses_list_{{ $prefix }}');
|
||||||
var storeUrl = '{{ route('Shop.Customers.address.store') }}';
|
var storeUrl = '{{ route('Shop.Customers.address.store') }}';
|
||||||
|
|
||||||
$('#add_address_{{ $prefix }}').on('click', function() {
|
var $toggleBtn = $('#add_address_{{ $prefix }}');
|
||||||
$formContainer.toggleClass('d-none');
|
|
||||||
|
$toggleBtn.on('click', function() {
|
||||||
|
var isHidden = $formContainer.hasClass('d-none');
|
||||||
|
if (isHidden) {
|
||||||
|
$formContainer.removeClass('d-none');
|
||||||
|
$toggleBtn.prop('disabled', true);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#cancel_address_{{ $prefix }}').on('click', function() {
|
$('#cancel_address_{{ $prefix }}').on('click', function() {
|
||||||
$formContainer.addClass('d-none');
|
$formContainer.addClass('d-none');
|
||||||
$formContainer.find('input[type="text"]').val('');
|
$formContainer.find('input[type="text"]').val('');
|
||||||
|
$toggleBtn.prop('disabled', false);
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#save_address_{{ $prefix }}').on('click', function() {
|
$('#save_address_{{ $prefix }}').on('click', function() {
|
||||||
@@ -69,6 +76,7 @@
|
|||||||
}
|
}
|
||||||
$formContainer.addClass('d-none');
|
$formContainer.addClass('d-none');
|
||||||
$formContainer.find('input[type="text"]').val('');
|
$formContainer.find('input[type="text"]').val('');
|
||||||
|
$toggleBtn.prop('disabled', false);
|
||||||
if (response.id) {
|
if (response.id) {
|
||||||
const $newRadio = $list.find('#address_' + response.id);
|
const $newRadio = $list.find('#address_' + response.id);
|
||||||
$list.find('input[type="radio"]').not($newRadio).prop('checked', false);
|
$list.find('input[type="radio"]').not($newRadio).prop('checked', false);
|
||||||
|
|||||||
@@ -16,11 +16,27 @@
|
|||||||
@push('js')
|
@push('js')
|
||||||
<script>
|
<script>
|
||||||
$(function() {
|
$(function() {
|
||||||
|
const articleShowUrlTemplate = "{{ route('Shop.Articles.show', ['id' => '__ARTICLE_ID__']) }}";
|
||||||
|
|
||||||
$('#search-general .fa-search').click(function() {
|
$('#search-general .fa-search').click(function() {
|
||||||
$('#search-general').submit();
|
$('#search-general').submit();
|
||||||
});
|
});
|
||||||
|
|
||||||
initAutocomplete('#search_name');
|
function redirectToArticle(item, evt) {
|
||||||
|
if (!item || typeof item.value === 'undefined' || item.value === null || item.value === '') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
evt.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
const targetUrl = articleShowUrlTemplate.replace('__ARTICLE_ID__', item.value);
|
||||||
|
window.location.href = targetUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
initAutocomplete('#search_name', redirectToArticle);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
@endpush
|
@endpush
|
||||||
|
|||||||
@@ -13,9 +13,10 @@
|
|||||||
var id = item.value;
|
var id = item.value;
|
||||||
$('#' + field).val(id);
|
$('#' + field).val(id);
|
||||||
|
|
||||||
if (typeof(callback) != 'undefined') {
|
if (typeof callback === 'function') {
|
||||||
var c = callback + '(' + id + ')';
|
callback.call(this, item, evt);
|
||||||
eval(c);
|
} else if (typeof callback === 'string' && callback.length && typeof window[callback] === 'function') {
|
||||||
|
window[callback].call(this, item, evt);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user