Compare commits
28 Commits
ea4f46f96d
...
d2c72a3f33
Author | SHA1 | Date | |
---|---|---|---|
d2c72a3f33 | |||
3dc4b98959 | |||
b6592d7945 | |||
bc63a4074b | |||
2d5688b66e | |||
f02fb63bfd | |||
6fdf471463 | |||
6be8998e3a | |||
671a2950c7 | |||
2461a4457a | |||
e898f3d884 | |||
a188c34409 | |||
081be2f930 | |||
153014dba8 | |||
51f21f94c1 | |||
4eb94a736a | |||
07c250eaac | |||
4500ce0c27 | |||
f188063967 | |||
bcd5c6cdef | |||
86e48f8e16 | |||
63d5f427ad | |||
5de1726ce8 | |||
01f602f8d6 | |||
320fc0cc98 | |||
4e952f96c0 | |||
43eebd9528 | |||
3defbd8253 |
31
.env.example
31
.env.example
@ -1,9 +1,9 @@
|
|||||||
APP_NAME=Laravel
|
APP_NAME="Top Notch"
|
||||||
APP_ENV=local
|
APP_ENV=local
|
||||||
APP_KEY=
|
APP_KEY=base64:vRgghlbIdXQxXIEvgUArbI9FURhgdyqx3LDXDwHYSmA=
|
||||||
APP_DEBUG=true
|
APP_DEBUG=true
|
||||||
APP_TIMEZONE=UTC
|
APP_TIMEZONE=UTC
|
||||||
APP_URL=http://localhost
|
APP_URL=localhost
|
||||||
|
|
||||||
APP_LOCALE=en
|
APP_LOCALE=en
|
||||||
APP_FALLBACK_LOCALE=en
|
APP_FALLBACK_LOCALE=en
|
||||||
@ -19,12 +19,12 @@ LOG_STACK=single
|
|||||||
LOG_DEPRECATIONS_CHANNEL=null
|
LOG_DEPRECATIONS_CHANNEL=null
|
||||||
LOG_LEVEL=debug
|
LOG_LEVEL=debug
|
||||||
|
|
||||||
DB_CONNECTION=sqlite
|
DB_CONNECTION=mysql
|
||||||
# DB_HOST=127.0.0.1
|
DB_HOST=mysql
|
||||||
# DB_PORT=3306
|
DB_PORT=3306
|
||||||
# DB_DATABASE=laravel
|
DB_DATABASE=laravel
|
||||||
# DB_USERNAME=root
|
DB_USERNAME=sail
|
||||||
# DB_PASSWORD=
|
DB_PASSWORD=password
|
||||||
|
|
||||||
SESSION_DRIVER=database
|
SESSION_DRIVER=database
|
||||||
SESSION_LIFETIME=120
|
SESSION_LIFETIME=120
|
||||||
@ -42,13 +42,13 @@ CACHE_PREFIX=
|
|||||||
MEMCACHED_HOST=127.0.0.1
|
MEMCACHED_HOST=127.0.0.1
|
||||||
|
|
||||||
REDIS_CLIENT=phpredis
|
REDIS_CLIENT=phpredis
|
||||||
REDIS_HOST=127.0.0.1
|
REDIS_HOST=redis
|
||||||
REDIS_PASSWORD=null
|
REDIS_PASSWORD=null
|
||||||
REDIS_PORT=6379
|
REDIS_PORT=6379
|
||||||
|
|
||||||
MAIL_MAILER=log
|
MAIL_MAILER=smtp
|
||||||
MAIL_HOST=127.0.0.1
|
MAIL_HOST=mailpit
|
||||||
MAIL_PORT=2525
|
MAIL_PORT=1025
|
||||||
MAIL_USERNAME=null
|
MAIL_USERNAME=null
|
||||||
MAIL_PASSWORD=null
|
MAIL_PASSWORD=null
|
||||||
MAIL_ENCRYPTION=null
|
MAIL_ENCRYPTION=null
|
||||||
@ -62,3 +62,8 @@ AWS_BUCKET=
|
|||||||
AWS_USE_PATH_STYLE_ENDPOINT=false
|
AWS_USE_PATH_STYLE_ENDPOINT=false
|
||||||
|
|
||||||
VITE_APP_NAME="${APP_NAME}"
|
VITE_APP_NAME="${APP_NAME}"
|
||||||
|
|
||||||
|
SCOUT_DRIVER=meilisearch
|
||||||
|
MEILISEARCH_HOST=http://meilisearch:7700
|
||||||
|
|
||||||
|
MEILISEARCH_NO_ANALYTICS=false
|
||||||
|
14
README.md
14
README.md
@ -1,4 +1,18 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
**2025-04-11**
|
||||||
|
- Fixed #132 - Inches / cm toggle for order page (and show unit on pdf)
|
||||||
|
|
||||||
|
**2025-04-10**
|
||||||
|
- Fixed #145 - Default order sort is incorrect (newest will always show on top now)
|
||||||
|
- Fixed #142 - Packing Slip content field should be required
|
||||||
|
|
||||||
|
**2025-04-08**
|
||||||
|
- Added #138 - Add Decoration method to order list
|
||||||
|
- Fixed #133 - Make product name not required
|
||||||
|
- Fixed #127 - Implement resource lock for orders
|
||||||
|
- Fixed #125 - 'Add Payment' on LIst Invoice page modal is too wide
|
||||||
|
- Fixed #124 - Reorder button for product services is displayed on wrong side
|
||||||
|
- Fixed #123 - Typo 'Add to product Services'
|
||||||
|
|
||||||
**2025-03-11**
|
**2025-03-11**
|
||||||
- Fixed #122 - Non-admins can see payments
|
- Fixed #122 - Non-admins can see payments
|
||||||
|
@ -2,9 +2,10 @@
|
|||||||
|
|
||||||
namespace App\Enums;
|
namespace App\Enums;
|
||||||
|
|
||||||
|
use Filament\Support\Contracts\HasColor;
|
||||||
use Filament\Support\Contracts\HasLabel;
|
use Filament\Support\Contracts\HasLabel;
|
||||||
|
|
||||||
enum OrderType: string implements HasLabel
|
enum OrderType: string implements HasColor, HasLabel
|
||||||
{
|
{
|
||||||
case EMB = 'embroidery';
|
case EMB = 'embroidery';
|
||||||
case SCP = 'screen_printing';
|
case SCP = 'screen_printing';
|
||||||
@ -22,4 +23,15 @@ public function getLabel(): string
|
|||||||
self::MISC => 'Misc',
|
self::MISC => 'Misc',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getColor(): string
|
||||||
|
{
|
||||||
|
return match ($this) {
|
||||||
|
self::EMB => 'embroidery',
|
||||||
|
self::SCP => 'screen_printing',
|
||||||
|
self::DTG => 'primary',
|
||||||
|
self::VINYL => 'vinyl',
|
||||||
|
self::MISC => 'misc',
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -249,6 +249,7 @@ public static function table(Table $table): Table
|
|||||||
BulkAction::make('Create Payment')
|
BulkAction::make('Create Payment')
|
||||||
->icon(IconEnum::PAYMENTS->value)
|
->icon(IconEnum::PAYMENTS->value)
|
||||||
->form(fn ($form) => PaymentResource::form($form))
|
->form(fn ($form) => PaymentResource::form($form))
|
||||||
|
->modalWidth('lg')
|
||||||
->action(function (Collection $records, array $data) {
|
->action(function (Collection $records, array $data) {
|
||||||
if ($records->pluck('customer_id')->unique()->count() !== 1) {
|
if ($records->pluck('customer_id')->unique()->count() !== 1) {
|
||||||
Notification::make()
|
Notification::make()
|
||||||
|
@ -33,12 +33,29 @@
|
|||||||
use Filament\Tables\Actions\BulkActionGroup;
|
use Filament\Tables\Actions\BulkActionGroup;
|
||||||
use Filament\Tables\Columns\IconColumn\IconColumnSize;
|
use Filament\Tables\Columns\IconColumn\IconColumnSize;
|
||||||
use Filament\Tables\Columns\TextColumn;
|
use Filament\Tables\Columns\TextColumn;
|
||||||
|
use Filament\Tables\Filters\SelectFilter;
|
||||||
use Filament\Tables\Table;
|
use Filament\Tables\Table;
|
||||||
use Guava\FilamentClusters\Forms\Cluster;
|
use Guava\FilamentClusters\Forms\Cluster;
|
||||||
use Icetalker\FilamentTableRepeater\Forms\Components\TableRepeater;
|
use Icetalker\FilamentTableRepeater\Forms\Components\TableRepeater;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Database\Eloquent\Collection;
|
use Illuminate\Database\Eloquent\Collection;
|
||||||
|
|
||||||
|
function recalculateRowTotal(callable $set, callable $get): void
|
||||||
|
{
|
||||||
|
$amounts = collect([
|
||||||
|
$get('xs'),
|
||||||
|
$get('s'),
|
||||||
|
$get('m'),
|
||||||
|
$get('l'),
|
||||||
|
$get('xl'),
|
||||||
|
$get('2xl'),
|
||||||
|
$get('3xl'),
|
||||||
|
$get('osfa'),
|
||||||
|
])->map(fn ($val) => floatval($val ?? 0));
|
||||||
|
|
||||||
|
$set('total', $amounts->sum());
|
||||||
|
}
|
||||||
|
|
||||||
class OrderResource extends Resource
|
class OrderResource extends Resource
|
||||||
{
|
{
|
||||||
protected static ?string $model = Order::class;
|
protected static ?string $model = Order::class;
|
||||||
@ -51,6 +68,8 @@ public static function form(Form $form): Form
|
|||||||
{
|
{
|
||||||
return $form->schema([
|
return $form->schema([
|
||||||
Group::make()
|
Group::make()
|
||||||
|
->columns(6)
|
||||||
|
->columnSpan(2)
|
||||||
->schema([
|
->schema([
|
||||||
Section::make([
|
Section::make([
|
||||||
Grid::make(1)
|
Grid::make(1)
|
||||||
@ -139,55 +158,82 @@ public static function form(Form $form): Form
|
|||||||
->columnSpan(1)
|
->columnSpan(1)
|
||||||
->hidden(fn (?Order $record) => $record === null)
|
->hidden(fn (?Order $record) => $record === null)
|
||||||
->extraAttributes(['class' => 'h-full']),
|
->extraAttributes(['class' => 'h-full']),
|
||||||
])
|
]),
|
||||||
->columns(6)
|
|
||||||
->columnSpan(2),
|
|
||||||
|
|
||||||
TableRepeater::make('order_products')
|
TableRepeater::make('order_products')
|
||||||
->label('Garments')
|
->label('Garments')
|
||||||
|
->addActionLabel('Add new garment')
|
||||||
|
->reorderable()
|
||||||
|
->cloneable()
|
||||||
|
->defaultItems(1)
|
||||||
->schema([
|
->schema([
|
||||||
TextInput::make('sku')
|
TextInput::make('sku')
|
||||||
->datalist(OrderProduct::all()->unique('sku')->pluck('sku')->toArray()),
|
->datalist(OrderProduct::all()->unique('sku')->pluck('sku')->toArray()),
|
||||||
TextInput::make('product_name')
|
TextInput::make('product_name')
|
||||||
->datalist(OrderProduct::all()->unique('product_name')->pluck('product_name')->toArray())
|
->datalist(OrderProduct::all()->unique('product_name')->pluck('product_name')->toArray()),
|
||||||
->required(),
|
|
||||||
TextInput::make('color')
|
TextInput::make('color')
|
||||||
->datalist(OrderProduct::all()->unique('color')->pluck('color')->toArray()),
|
->datalist(OrderProduct::all()->unique('color')->pluck('color')->toArray()),
|
||||||
Cluster::make([
|
Cluster::make([
|
||||||
TextInput::make('xs')
|
TextInput::make('xs')
|
||||||
->placeholder('xs')
|
->placeholder('xs')
|
||||||
->rules('numeric'),
|
->rules('numeric')
|
||||||
|
->reactive()
|
||||||
|
->afterStateUpdated(fn ($state, callable $set, callable $get) => recalculateRowTotal($set, $get)),
|
||||||
|
|
||||||
TextInput::make('s')
|
TextInput::make('s')
|
||||||
->placeholder('s')
|
->placeholder('s')
|
||||||
->rules('numeric'),
|
->rules('numeric')
|
||||||
|
->reactive()
|
||||||
|
->afterStateUpdated(fn ($state, callable $set, callable $get) => recalculateRowTotal($set, $get)),
|
||||||
|
|
||||||
TextInput::make('m')
|
TextInput::make('m')
|
||||||
->placeholder('m')
|
->placeholder('m')
|
||||||
->rules('numeric'),
|
->rules('numeric')
|
||||||
|
->reactive()
|
||||||
|
->afterStateUpdated(fn ($state, callable $set, callable $get) => recalculateRowTotal($set, $get)),
|
||||||
|
|
||||||
TextInput::make('l')
|
TextInput::make('l')
|
||||||
->placeholder('l')
|
->placeholder('l')
|
||||||
->rules('numeric'),
|
->rules('numeric')
|
||||||
|
->reactive()
|
||||||
|
->afterStateUpdated(fn ($state, callable $set, callable $get) => recalculateRowTotal($set, $get)),
|
||||||
|
|
||||||
TextInput::make('xl')
|
TextInput::make('xl')
|
||||||
->placeholder('xl')
|
->placeholder('xl')
|
||||||
->rules('numeric'),
|
->rules('numeric')
|
||||||
|
->reactive()
|
||||||
|
->afterStateUpdated(fn ($state, callable $set, callable $get) => recalculateRowTotal($set, $get)),
|
||||||
|
|
||||||
TextInput::make('2xl')
|
TextInput::make('2xl')
|
||||||
->placeholder('2xl')
|
->placeholder('2xl')
|
||||||
->rules('numeric'),
|
->rules('numeric')
|
||||||
|
->reactive()
|
||||||
|
->afterStateUpdated(fn ($state, callable $set, callable $get) => recalculateRowTotal($set, $get)),
|
||||||
|
|
||||||
TextInput::make('3xl')
|
TextInput::make('3xl')
|
||||||
->placeholder('3xl')
|
->placeholder('3xl')
|
||||||
->rules('numeric'),
|
->rules('numeric')
|
||||||
|
->reactive()
|
||||||
|
->afterStateUpdated(fn ($state, callable $set, callable $get) => recalculateRowTotal($set, $get)),
|
||||||
|
|
||||||
TextInput::make('osfa')
|
TextInput::make('osfa')
|
||||||
->placeholder('osfa')
|
->placeholder('osfa')
|
||||||
->rules('numeric'),
|
->rules('numeric')
|
||||||
])
|
->reactive()
|
||||||
->label('Sizes'),
|
->afterStateUpdated(fn ($state, callable $set, callable $get) => recalculateRowTotal($set, $get)),
|
||||||
])
|
])->label('Sizes'),
|
||||||
->reorderable()
|
|
||||||
->cloneable()
|
TextInput::make('total')
|
||||||
->defaultItems(1),
|
->disabled()
|
||||||
|
->dehydrated(false)
|
||||||
|
->afterStateHydrated(fn (callable $get, callable $set) => recalculateRowTotal($set, $get)),
|
||||||
|
|
||||||
|
]),
|
||||||
|
|
||||||
Repeater::make('services')
|
Repeater::make('services')
|
||||||
->view('filament.forms.compact-repeater')
|
->view('filament.forms.compact-repeater')
|
||||||
->label('Product Services')
|
->label('Product Services')
|
||||||
|
->addActionLabel('Add new product service')
|
||||||
->schema([
|
->schema([
|
||||||
Grid::make(19)
|
Grid::make(19)
|
||||||
->schema([
|
->schema([
|
||||||
@ -228,34 +274,44 @@ public static function form(Form $form): Form
|
|||||||
->prefix('h')
|
->prefix('h')
|
||||||
->rules('numeric'),
|
->rules('numeric'),
|
||||||
])
|
])
|
||||||
->label('Dimensions (inches)')
|
->label('Dimensions')
|
||||||
->columnSpan(4),
|
->columnSpan(4),
|
||||||
|
|
||||||
TextInput::make('amount')
|
TextInput::make('amount')
|
||||||
->label('Quantity')
|
->label('Quantity')
|
||||||
->live()
|
|
||||||
->prefix('#')
|
->prefix('#')
|
||||||
->columnSpan(2)
|
->columnSpan(2)
|
||||||
->rules('numeric'),
|
->rules('numeric'),
|
||||||
|
|
||||||
TextInput::make('amount_price')
|
TextInput::make('amount_price')
|
||||||
->label('Amount')
|
->label('Unit price')
|
||||||
->prefix('$')
|
->prefix('$')
|
||||||
->columnSpan(2)
|
->columnSpan(2)
|
||||||
->rules('numeric'),
|
->rules('numeric'),
|
||||||
]),
|
]),
|
||||||
|
|
||||||
Grid::make(9)
|
Grid::make(19)
|
||||||
->schema([
|
->schema([
|
||||||
TextInput::make('serviceFileCode')
|
TextInput::make('serviceFileCode')
|
||||||
->label('Code')
|
->label('Code')
|
||||||
->datalist(ServiceFile::all()->unique('code')->pluck('code')->toArray())
|
->datalist(ServiceFile::all()->unique('code')->pluck('code')->toArray())
|
||||||
->columnSpan(1)
|
->columnSpan(2)
|
||||||
->placeholder('A1234'),
|
->placeholder('A1234'),
|
||||||
|
|
||||||
|
Select::make('serviceFileSizeUnit')
|
||||||
|
->columnSpan(2)
|
||||||
|
->selectablePlaceholder(false)
|
||||||
|
->label('Unit')
|
||||||
|
->options([
|
||||||
|
'in' => 'Inches',
|
||||||
|
'cm' => 'cm',
|
||||||
|
]),
|
||||||
|
|
||||||
Textarea::make('notes')
|
Textarea::make('notes')
|
||||||
->placeholder('Thread colors...')
|
->placeholder('Thread colors... (press enter for new line)')
|
||||||
->columnSpan(8),
|
->autosize()
|
||||||
|
->rows(1)
|
||||||
|
->columnSpan(15),
|
||||||
]),
|
]),
|
||||||
])
|
])
|
||||||
->reorderable()
|
->reorderable()
|
||||||
@ -298,6 +354,11 @@ public static function table(Table $table): Table
|
|||||||
})
|
})
|
||||||
->sortable(),
|
->sortable(),
|
||||||
|
|
||||||
|
TextColumn::make('order_type')
|
||||||
|
->badge()
|
||||||
|
->searchable()
|
||||||
|
->sortable(),
|
||||||
|
|
||||||
TextColumn::make('customer.company_name')
|
TextColumn::make('customer.company_name')
|
||||||
->searchable()
|
->searchable()
|
||||||
->sortable(),
|
->sortable(),
|
||||||
@ -326,8 +387,16 @@ public static function table(Table $table): Table
|
|||||||
->searchable()
|
->searchable()
|
||||||
->sortable(),
|
->sortable(),
|
||||||
])
|
])
|
||||||
->defaultSort('order_date', 'desc')
|
->defaultSort('id', 'desc')
|
||||||
->filters([
|
->filters([
|
||||||
|
SelectFilter::make('order_type')
|
||||||
|
->options(OrderType::class)
|
||||||
|
->multiple(),
|
||||||
|
|
||||||
|
SelectFilter::make('status')
|
||||||
|
->options(OrderStatus::class)
|
||||||
|
->multiple(),
|
||||||
|
|
||||||
Tables\Filters\Filter::make('order_date')
|
Tables\Filters\Filter::make('order_date')
|
||||||
->form([
|
->form([
|
||||||
DatePicker::make('created_from'),
|
DatePicker::make('created_from'),
|
||||||
|
@ -63,6 +63,7 @@ protected function handleRecordCreation(array $data): Order
|
|||||||
'width' => $service['serviceFileWidth'] ?? null,
|
'width' => $service['serviceFileWidth'] ?? null,
|
||||||
'height' => $service['serviceFileHeight'] ?? null,
|
'height' => $service['serviceFileHeight'] ?? null,
|
||||||
'setup_number' => $service['serviceFileSetupNumber'] ?? null,
|
'setup_number' => $service['serviceFileSetupNumber'] ?? null,
|
||||||
|
'size_unit' => $service['serviceFileSizeUnit'] ?? 'inch',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
ProductService::create([
|
ProductService::create([
|
||||||
|
@ -21,9 +21,12 @@
|
|||||||
use Filament\Resources\Pages\EditRecord;
|
use Filament\Resources\Pages\EditRecord;
|
||||||
use Illuminate\Contracts\Support\Htmlable;
|
use Illuminate\Contracts\Support\Htmlable;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Kenepa\ResourceLock\Resources\Pages\Concerns\UsesResourceLock;
|
||||||
|
|
||||||
class EditOrder extends EditRecord
|
class EditOrder extends EditRecord
|
||||||
{
|
{
|
||||||
|
use UsesResourceLock;
|
||||||
|
|
||||||
protected static string $resource = OrderResource::class;
|
protected static string $resource = OrderResource::class;
|
||||||
|
|
||||||
public function getTitle(): string|Htmlable
|
public function getTitle(): string|Htmlable
|
||||||
@ -65,6 +68,7 @@ protected function mutateFormDataBeforeFill(array $data): array
|
|||||||
'serviceFileHeight' => $service->serviceFile->height ?? '',
|
'serviceFileHeight' => $service->serviceFile->height ?? '',
|
||||||
'serviceFileCode' => $service->serviceFile->code ?? '',
|
'serviceFileCode' => $service->serviceFile->code ?? '',
|
||||||
'serviceFileSetupNumber' => $service->serviceFile->setup_number ?? '',
|
'serviceFileSetupNumber' => $service->serviceFile->setup_number ?? '',
|
||||||
|
'serviceFileSizeUnit' => $service->serviceFile->size_unit ?? 'inch',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,6 +140,7 @@ public function handleRecordUpdate(Model $record, array $data): Model
|
|||||||
'width' => $service['serviceFileWidth'] ?? null,
|
'width' => $service['serviceFileWidth'] ?? null,
|
||||||
'height' => $service['serviceFileHeight'] ?? null,
|
'height' => $service['serviceFileHeight'] ?? null,
|
||||||
'setup_number' => $service['serviceFileSetupNumber'] ?? null,
|
'setup_number' => $service['serviceFileSetupNumber'] ?? null,
|
||||||
|
'size_unit' => $service['serviceFileSizeUnit'] ?? 'inch',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
ProductService::create([
|
ProductService::create([
|
||||||
|
@ -10,11 +10,17 @@
|
|||||||
use Filament\Actions;
|
use Filament\Actions;
|
||||||
use Filament\Resources\Components\Tab;
|
use Filament\Resources\Components\Tab;
|
||||||
use Filament\Resources\Pages\ListRecords;
|
use Filament\Resources\Pages\ListRecords;
|
||||||
|
use Filament\Support\Enums\MaxWidth;
|
||||||
|
|
||||||
class ListOrders extends ListRecords
|
class ListOrders extends ListRecords
|
||||||
{
|
{
|
||||||
protected static string $resource = OrderResource::class;
|
protected static string $resource = OrderResource::class;
|
||||||
|
|
||||||
|
public function getMaxContentWidth(): string
|
||||||
|
{
|
||||||
|
return 'max-w-[1920px]';
|
||||||
|
}
|
||||||
|
|
||||||
private function excludeStatuses($query): mixed
|
private function excludeStatuses($query): mixed
|
||||||
{
|
{
|
||||||
return $query
|
return $query
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
namespace App\Filament\Admin\Resources;
|
namespace App\Filament\Admin\Resources;
|
||||||
|
|
||||||
use App\Enums\IconEnum;
|
use App\Enums\IconEnum;
|
||||||
use App\Models\Customer;
|
|
||||||
use App\Models\Order;
|
use App\Models\Order;
|
||||||
use App\Models\PackingSlip;
|
use App\Models\PackingSlip;
|
||||||
use Filament\Forms\Components\DatePicker;
|
use Filament\Forms\Components\DatePicker;
|
||||||
@ -39,11 +38,16 @@ public static function form(Form $form): Form
|
|||||||
DatePicker::make('date_received')
|
DatePicker::make('date_received')
|
||||||
->default(today())
|
->default(today())
|
||||||
->required(),
|
->required(),
|
||||||
|
|
||||||
Select::make('customer_id')
|
Select::make('customer_id')
|
||||||
->label('Customer')
|
->label('Customer')
|
||||||
->options(Customer::all()->pluck('company_name', 'id'))
|
->relationship(name: 'customer', titleAttribute: 'company_name')
|
||||||
|
->preload()
|
||||||
|
->createOptionForm(fn ($form) => CustomerResource::form($form))
|
||||||
|
->createOptionAction(fn ($action) => $action->modalWidth('lg'))
|
||||||
->reactive()
|
->reactive()
|
||||||
->searchable(),
|
->searchable(),
|
||||||
|
|
||||||
Select::make('order_id')
|
Select::make('order_id')
|
||||||
->label('Order')
|
->label('Order')
|
||||||
->options(fn ($get): array => Order::where('customer_id', $get('customer_id') ?? null)
|
->options(fn ($get): array => Order::where('customer_id', $get('customer_id') ?? null)
|
||||||
@ -57,6 +61,7 @@ public static function form(Form $form): Form
|
|||||||
Grid::make(1)
|
Grid::make(1)
|
||||||
->schema([
|
->schema([
|
||||||
TextArea::make('contents')
|
TextArea::make('contents')
|
||||||
|
->required()
|
||||||
->rows(9),
|
->rows(9),
|
||||||
])
|
])
|
||||||
->columnSpan(1),
|
->columnSpan(1),
|
||||||
@ -73,7 +78,6 @@ public static function table(Table $table): Table
|
|||||||
->sortable()
|
->sortable()
|
||||||
->searchable(),
|
->searchable(),
|
||||||
TextColumn::make('order.customer_po')
|
TextColumn::make('order.customer_po')
|
||||||
// ->url(fn ($record) => $record->to)
|
|
||||||
->url(fn ($record) => OrderResource::getUrl('edit', ['record' => $record->id]))
|
->url(fn ($record) => OrderResource::getUrl('edit', ['record' => $record->id]))
|
||||||
->weight('bold')
|
->weight('bold')
|
||||||
->color('code')
|
->color('code')
|
||||||
|
@ -49,7 +49,7 @@ private function getOrdersPast30Days(): string
|
|||||||
->where('order_status', '!=', OrderStatus::READY_FOR_INVOICE)
|
->where('order_status', '!=', OrderStatus::READY_FOR_INVOICE)
|
||||||
->where('order_status', '!=', OrderStatus::SHIPPED)
|
->where('order_status', '!=', OrderStatus::SHIPPED)
|
||||||
->where('order_status', '!=', OrderStatus::INVOICED)
|
->where('order_status', '!=', OrderStatus::INVOICED)
|
||||||
->whereBetween('created_at', [now()->startOfMonth(), now()->endOfMonth()])
|
->whereBetween('created_at', [now()->subDays(30), now()])
|
||||||
->count();
|
->count();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,13 +16,14 @@
|
|||||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
use Illuminate\Support\Carbon;
|
use Illuminate\Support\Carbon;
|
||||||
|
use Kenepa\ResourceLock\Models\Concerns\HasLocks;
|
||||||
|
|
||||||
#[ObservedBy(OrderObserver::class)]
|
#[ObservedBy(OrderObserver::class)]
|
||||||
|
|
||||||
class Order extends Model
|
class Order extends Model
|
||||||
{
|
{
|
||||||
/** @use HasFactory<OrderFactory> */
|
/** @use HasFactory<OrderFactory> */
|
||||||
use HasFactory, SoftDeletes;
|
use HasFactory, HasLocks, SoftDeletes;
|
||||||
|
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
'customer_id',
|
'customer_id',
|
||||||
|
@ -26,6 +26,7 @@ class ProductService extends Model
|
|||||||
'amount',
|
'amount',
|
||||||
'amount_price',
|
'amount_price',
|
||||||
'notes',
|
'notes',
|
||||||
|
'size_unit',
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $appends = [
|
protected $appends = [
|
||||||
|
@ -19,6 +19,7 @@ class ServiceFile extends Model
|
|||||||
'width',
|
'width',
|
||||||
'height',
|
'height',
|
||||||
'setup_number',
|
'setup_number',
|
||||||
|
'size_unit',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
use Illuminate\Session\Middleware\AuthenticateSession;
|
use Illuminate\Session\Middleware\AuthenticateSession;
|
||||||
use Illuminate\Session\Middleware\StartSession;
|
use Illuminate\Session\Middleware\StartSession;
|
||||||
use Illuminate\View\Middleware\ShareErrorsFromSession;
|
use Illuminate\View\Middleware\ShareErrorsFromSession;
|
||||||
|
use Kenepa\ResourceLock\ResourceLockPlugin;
|
||||||
|
|
||||||
class AdminPanelProvider extends PanelProvider
|
class AdminPanelProvider extends PanelProvider
|
||||||
{
|
{
|
||||||
@ -29,10 +30,14 @@ public function panel(Panel $panel): Panel
|
|||||||
->path('admin')
|
->path('admin')
|
||||||
->login(UsernameLogin::class)
|
->login(UsernameLogin::class)
|
||||||
->colors([
|
->colors([
|
||||||
'primary' => Color::Blue,
|
'primary' => Color::Blue,
|
||||||
'code' => Color::hex('#d63384'),
|
'code' => Color::hex('#d63384'),
|
||||||
'invoicing' => Color::hex('#DD00DD'),
|
'invoicing' => Color::hex('#DD00DD'),
|
||||||
'invoiced' => Color::hex('#900090'),
|
'invoiced' => Color::hex('#900090'),
|
||||||
|
'embroidery' => Color::hex('#FF00FF'),
|
||||||
|
'screen_printing' => Color::hex('#0088FF'),
|
||||||
|
'vinyl' => Color::hex('#22AA22'),
|
||||||
|
'misc' => Color::hex('#0000FF'),
|
||||||
])
|
])
|
||||||
->discoverResources(in: app_path('Filament/Admin/Resources/'), for: 'App\\Filament\\Admin\\Resources')
|
->discoverResources(in: app_path('Filament/Admin/Resources/'), for: 'App\\Filament\\Admin\\Resources')
|
||||||
->discoverPages(in: app_path('Filament/Admin/Pages'), for: 'App\\Filament\\Admin\\Pages')
|
->discoverPages(in: app_path('Filament/Admin/Pages'), for: 'App\\Filament\\Admin\\Pages')
|
||||||
@ -62,6 +67,7 @@ public function panel(Panel $panel): Panel
|
|||||||
NavigationGroup::make('Financial'),
|
NavigationGroup::make('Financial'),
|
||||||
NavigationGroup::make('Reports'),
|
NavigationGroup::make('Reports'),
|
||||||
NavigationGroup::make('Settings'),
|
NavigationGroup::make('Settings'),
|
||||||
]);
|
])
|
||||||
|
->plugin(ResourceLockPlugin::make());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,15 +7,17 @@
|
|||||||
"require": {
|
"require": {
|
||||||
"php": "^8.2",
|
"php": "^8.2",
|
||||||
"davidhsianturi/blade-bootstrap-icons": "^1.5",
|
"davidhsianturi/blade-bootstrap-icons": "^1.5",
|
||||||
|
"doctrine/dbal": "^4.2",
|
||||||
|
"fakerphp/faker": "^1.23",
|
||||||
"filament/filament": "^3.2",
|
"filament/filament": "^3.2",
|
||||||
"guava/filament-clusters": "^1.4",
|
"guava/filament-clusters": "^1.4",
|
||||||
"icetalker/filament-table-repeater": "^1.3",
|
"icetalker/filament-table-repeater": "^1.3",
|
||||||
|
"kenepa/resource-lock": "^2.1",
|
||||||
"laravel/framework": "^11.9",
|
"laravel/framework": "^11.9",
|
||||||
"laravel/tinker": "^2.9",
|
"laravel/tinker": "^2.9",
|
||||||
"livewire/livewire": "^3.5",
|
"livewire/livewire": "^3.5",
|
||||||
"mallardduck/blade-lucide-icons": "^1.23",
|
"mallardduck/blade-lucide-icons": "^1.23",
|
||||||
"spatie/laravel-pdf": "^1.5",
|
"spatie/laravel-pdf": "^1.5"
|
||||||
"fakerphp/faker": "^1.23"
|
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"barryvdh/laravel-ide-helper": "^3.5",
|
"barryvdh/laravel-ide-helper": "^3.5",
|
||||||
|
70
composer.lock
generated
70
composer.lock
generated
@ -4,7 +4,7 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "46ac06345fc3d57a7d0a01cfcaeaac17",
|
"content-hash": "139b4d2b0a40ace1cf1efaf4c7facf20",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "anourvalar/eloquent-serialize",
|
"name": "anourvalar/eloquent-serialize",
|
||||||
@ -2238,6 +2238,74 @@
|
|||||||
],
|
],
|
||||||
"time": "2025-03-05T16:06:45+00:00"
|
"time": "2025-03-05T16:06:45+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "kenepa/resource-lock",
|
||||||
|
"version": "2.1.3",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/kenepa/resource-lock.git",
|
||||||
|
"reference": "dda6e14b5c4a47817569081b11248c572ebdfd07"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/kenepa/resource-lock/zipball/dda6e14b5c4a47817569081b11248c572ebdfd07",
|
||||||
|
"reference": "dda6e14b5c4a47817569081b11248c572ebdfd07",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"filament/filament": "^3.0",
|
||||||
|
"illuminate/contracts": "^9.0|^10.0|^11.0|^12.0",
|
||||||
|
"php": "^8.1",
|
||||||
|
"spatie/laravel-package-tools": "^1.15.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"laravel/pint": "^1.0",
|
||||||
|
"nunomaduro/collision": "^7.0|^8.1",
|
||||||
|
"nunomaduro/larastan": "^2.0.1",
|
||||||
|
"orchestra/testbench": "^7.0|^8.0|^9.0|^10.0",
|
||||||
|
"pestphp/pest": "^2.0|^3.7",
|
||||||
|
"pestphp/pest-plugin-laravel": "^2.0|^3.1",
|
||||||
|
"pestphp/pest-plugin-livewire": "^2.0|^3.0",
|
||||||
|
"phpstan/extension-installer": "^1.1",
|
||||||
|
"phpstan/phpstan-deprecation-rules": "^1.0|^2.0",
|
||||||
|
"phpstan/phpstan-phpunit": "^1.0|^2.0",
|
||||||
|
"spatie/laravel-ray": "^1.26",
|
||||||
|
"tightenco/duster": "^1.1|^3.1"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"laravel": {
|
||||||
|
"aliases": {
|
||||||
|
"ResourceLock": "Kenepa\\ResourceLock\\Facades\\ResourceLock"
|
||||||
|
},
|
||||||
|
"providers": [
|
||||||
|
"Kenepa\\ResourceLock\\ResourceLockServiceProvider"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Kenepa\\ResourceLock\\": "src",
|
||||||
|
"Kenepa\\ResourceLock\\Database\\Factories\\": "database/factories"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"description": "Filament Resource Lock is a Filament plugin that adds resource locking functionality to your site.",
|
||||||
|
"homepage": "https://github.com/kenepa/resource-lock",
|
||||||
|
"keywords": [
|
||||||
|
"Kenepa",
|
||||||
|
"laravel",
|
||||||
|
"resource-lock"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/kenepa/resource-lock/issues",
|
||||||
|
"source": "https://github.com/kenepa/resource-lock/tree/2.1.3"
|
||||||
|
},
|
||||||
|
"time": "2025-03-14T16:31:20+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "kirschbaum-development/eloquent-power-joins",
|
"name": "kirschbaum-development/eloquent-power-joins",
|
||||||
"version": "4.2.1",
|
"version": "4.2.1",
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
| or any other location as required by the application or its packages.
|
| or any other location as required by the application or its packages.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'version' => '20250311',
|
'version' => '20250411',
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
|
130
config/resource-lock.php
Normal file
130
config/resource-lock.php
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Models
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| The models configuration specifies the classes that represent your application's
|
||||||
|
| data objects. This configuration is used by the framework to interact with
|
||||||
|
| the application's data models. You can even implement your own ResourceLock model.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'models' => [
|
||||||
|
'User' => \App\Models\User::class,
|
||||||
|
// 'ResourceLock' => null,
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Filament Resource
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| The resource lock filament resource displays all the current locks in place.
|
||||||
|
| You are able to replace the resource Lock with your own resource class.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'resource' => [
|
||||||
|
'class' => \Kenepa\ResourceLock\Resources\LockResource::class,
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Resource Unlocker Button
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| The unlocker configuration specifies whether limited access is enabled for
|
||||||
|
| the resource unlock button. If limited access is enabled, only specific
|
||||||
|
| users or roles will be able to unlock locked resources directly from
|
||||||
|
| the modal.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'unlocker' => [
|
||||||
|
'limited_access' => false,
|
||||||
|
// 'gate' => ''
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Lock Notice
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| The lock notice contains several configuration options for the modal
|
||||||
|
| that is display when a resource is locked.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'lock_notice' => [
|
||||||
|
'display_resource_lock_owner' => false,
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Resource Lock Manager
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| The resource lock manager provides a simple way to view all resource locks
|
||||||
|
| of your application. It provides several ways to quickly unlock all or
|
||||||
|
| specific resources within your app.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'manager' => [
|
||||||
|
'navigation_badge' => false,
|
||||||
|
'navigation_icon' => 'heroicon-o-lock-closed',
|
||||||
|
'navigation_label' => 'Resource Locks',
|
||||||
|
'plural_label' => 'Resource Locks',
|
||||||
|
'navigation_group' => 'Settings',
|
||||||
|
'navigation_sort' => 200,
|
||||||
|
'limited_access' => false,
|
||||||
|
'should_register_navigation' => true,
|
||||||
|
// 'gate' => ''
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Lock timeout (in minutes)
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| The lock_timeout configuration specifies the time interval, in minutes,
|
||||||
|
| after which a lock on a resource will expire if it has not been manually
|
||||||
|
| unlocked or released by the user.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'lock_timeout' => 10,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Check Locks before saving
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| The check_locks_before_saving configuration specifies whether a lock of a resource will be checked
|
||||||
|
| before saving a resource if a tech-savvy user is able to bypass the locked
|
||||||
|
| resource modal and attempt to save the resource. In some cases you may want to turns this off.
|
||||||
|
| It's recommended to keep this on.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'check_locks_before_saving' => true,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Actions
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Action classes are simple classes that execute some logic within the package.
|
||||||
|
| If you want to add your own custom logic you are able to extend your own
|
||||||
|
| class with class your overwriting.
|
||||||
|
| Learn more about action classes: https://freek.dev/2442-strategies-for-making-laravel-packages-customizable
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'actions' => [
|
||||||
|
'get_resource_lock_owner_action' => \Kenepa\ResourceLock\Actions\GetResourceLockOwnerAction::class,
|
||||||
|
],
|
||||||
|
];
|
@ -19,7 +19,6 @@ public function definition(): array
|
|||||||
'name' => $this->faker->word(),
|
'name' => $this->faker->word(),
|
||||||
'width' => round($this->faker->randomFloat(2, 0, 10), 1),
|
'width' => round($this->faker->randomFloat(2, 0, 10), 1),
|
||||||
'height' => round($this->faker->randomFloat(2, 0, 10), 1),
|
'height' => round($this->faker->randomFloat(2, 0, 10), 1),
|
||||||
'unit' => 'inch',
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('resource_locks', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->timestamps();
|
||||||
|
$table->foreignId('user_id')->constrained();
|
||||||
|
$table->morphs('lockable');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('resource_locks');
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('order_products', function (Blueprint $table) {
|
||||||
|
$table->string('product_name')->nullable()->change();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('order_products', function (Blueprint $table) {
|
||||||
|
$table->string('product_name')->nullable(false)->change();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('service_files', function (Blueprint $table) {
|
||||||
|
$table->string('size_unit')->default('in');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('service_files', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('size_unit');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
2
package-lock.json
generated
2
package-lock.json
generated
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "topnotch_website",
|
"name": "order_system",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
|
@ -118,6 +118,7 @@ class="fi-fo-repeater-item divide-y divide-gray-100 rounded-xl bg-white shadow-
|
|||||||
>
|
>
|
||||||
@if ($reorderActionIsVisible || $moveUpActionIsVisible || $moveDownActionIsVisible)
|
@if ($reorderActionIsVisible || $moveUpActionIsVisible || $moveDownActionIsVisible)
|
||||||
<ul class="flex items-center gap-x-3">
|
<ul class="flex items-center gap-x-3">
|
||||||
|
{{--
|
||||||
@if ($reorderActionIsVisible)
|
@if ($reorderActionIsVisible)
|
||||||
<li
|
<li
|
||||||
x-sortable-handle
|
x-sortable-handle
|
||||||
@ -126,6 +127,7 @@ class="fi-fo-repeater-item divide-y divide-gray-100 rounded-xl bg-white shadow-
|
|||||||
{{ $reorderAction }}
|
{{ $reorderAction }}
|
||||||
</li>
|
</li>
|
||||||
@endif
|
@endif
|
||||||
|
--}}
|
||||||
|
|
||||||
@if ($moveUpActionIsVisible || $moveDownActionIsVisible)
|
@if ($moveUpActionIsVisible || $moveDownActionIsVisible)
|
||||||
<li
|
<li
|
||||||
@ -156,7 +158,7 @@ class="flex items-center justify-center"
|
|||||||
</h4>
|
</h4>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
@if ($cloneActionIsVisible || $deleteActionIsVisible || $isCollapsible || $visibleExtraItemActions)
|
@if ($cloneActionIsVisible || $deleteActionIsVisible || $isCollapsible || $visibleExtraItemActions || $reorderActionIsVisible)
|
||||||
<ul
|
<ul
|
||||||
class="ms-auto flex items-center gap-x-3"
|
class="ms-auto flex items-center gap-x-3"
|
||||||
>
|
>
|
||||||
@ -166,6 +168,15 @@ class="ms-auto flex items-center gap-x-3"
|
|||||||
</li>
|
</li>
|
||||||
@endforeach
|
@endforeach
|
||||||
|
|
||||||
|
@if ($reorderActionIsVisible)
|
||||||
|
<li
|
||||||
|
x-sortable-handle
|
||||||
|
x-on:click.stop
|
||||||
|
>
|
||||||
|
{{ $reorderAction }}
|
||||||
|
</li>
|
||||||
|
@endif
|
||||||
|
|
||||||
@if ($cloneActionIsVisible)
|
@if ($cloneActionIsVisible)
|
||||||
<li x-on:click.stop>
|
<li x-on:click.stop>
|
||||||
{{ $cloneAction }}
|
{{ $cloneAction }}
|
||||||
|
@ -111,7 +111,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="fs-6 text-primary">
|
<div class="fs-6 text-primary">
|
||||||
{{$order->customer_po}}
|
{{$order->customer_po}}
|
||||||
@if($order->pre_production)<span class="text-danger"> (pre-pro)</span>@endif()
|
@if($order->pre_production)
|
||||||
|
<span class="text-danger"> (pre-pro)</span>
|
||||||
|
@endif()
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -153,7 +155,7 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
@foreach($order->orderProducts as $product)
|
@foreach($order->orderProducts as $product)
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>{{$product->sku}}</code></td>
|
<td><code style="font-size: 0.9rem;">{{$product->sku}}</code></td>
|
||||||
<td class="text-uppercase">{{$product->product_name}}</td>
|
<td class="text-uppercase">{{$product->product_name}}</td>
|
||||||
<td class="text-uppercase">{{$product->color}}</td>
|
<td class="text-uppercase">{{$product->color}}</td>
|
||||||
<td style="width: 40px;">{{$product->productSizes()->get()->where('size', 'xs')->first()->amount ?? ''}}</td>
|
<td style="width: 40px;">{{$product->productSizes()->get()->where('size', 'xs')->first()->amount ?? ''}}</td>
|
||||||
@ -182,12 +184,13 @@
|
|||||||
|
|
||||||
<!-- Services Table -->
|
<!-- Services Table -->
|
||||||
<div class="row mt-2">
|
<div class="row mt-2">
|
||||||
<table class="table table-striped" style="font-size: 12px;">
|
<table class="table table-striped" style="font-size: 13px;">
|
||||||
<thead class="opacity-50 fw-normal">
|
<thead class="opacity-50 fw-normal">
|
||||||
<th>Placement & Service</th>
|
<th>Placement & Service</th>
|
||||||
<th class="w-50">Logo Name & Instructions</th>
|
<th class="w-50">Logo Name & Instructions</th>
|
||||||
<th>Width</th>
|
<th>Width</th>
|
||||||
<th>Height</th>
|
<th>Height</th>
|
||||||
|
<th>Unit</th>
|
||||||
<th>QTY</th>
|
<th>QTY</th>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
||||||
@ -200,18 +203,18 @@
|
|||||||
</div>
|
</div>
|
||||||
<br>
|
<br>
|
||||||
<div class="text-uppercase">
|
<div class="text-uppercase">
|
||||||
<code style="font-size: 12px">
|
<code style="font-size: 14px">
|
||||||
{{$service->serviceFile->code}}
|
{{$service->serviceFile->code ?? ''}}
|
||||||
</code>
|
</code>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="text-uppercase">
|
<div class="text-uppercase">
|
||||||
{{$service->serviceFile->name}}
|
{{$service->serviceFile->name ?? ''}}
|
||||||
</div>
|
</div>
|
||||||
<br>
|
<br>
|
||||||
<div class="text-uppercase">
|
<div class="text-uppercase" style="color: #d63384;">
|
||||||
{{$service->notes}}
|
{{$service->notes ?? ''}}
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
@ -220,6 +223,9 @@
|
|||||||
<td>
|
<td>
|
||||||
{{$service->serviceFile->height}}
|
{{$service->serviceFile->height}}
|
||||||
</td>
|
</td>
|
||||||
|
<td>
|
||||||
|
{{$service->serviceFile->size_unit}}
|
||||||
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{{$service->amount}}
|
{{$service->amount}}
|
||||||
</td>
|
</td>
|
||||||
|
@ -6,9 +6,11 @@ export default {
|
|||||||
"./app/Filament/**/*.php",
|
"./app/Filament/**/*.php",
|
||||||
"./vendor/filament/**/*.php"
|
"./vendor/filament/**/*.php"
|
||||||
],
|
],
|
||||||
|
safelist: [
|
||||||
|
'max-w-[1920px]'
|
||||||
|
],
|
||||||
theme: {
|
theme: {
|
||||||
extend: {},
|
extend: {},
|
||||||
},
|
},
|
||||||
plugins: [],
|
plugins: [],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
0
tests/Feature/.placeholder
Normal file
0
tests/Feature/.placeholder
Normal file
@ -54,7 +54,7 @@
|
|||||||
->assertHasNoErrors();
|
->assertHasNoErrors();
|
||||||
|
|
||||||
$this->assertDatabaseHas('invoices', [
|
$this->assertDatabaseHas('invoices', [
|
||||||
'internal_id' => 'TN40001',
|
'internal_id' => 'TN4001',
|
||||||
'customer_id' => $formData['customer_id'],
|
'customer_id' => $formData['customer_id'],
|
||||||
'status' => $formData['status'],
|
'status' => $formData['status'],
|
||||||
'has_gst' => $formData['has_gst'],
|
'has_gst' => $formData['has_gst'],
|
||||||
@ -65,7 +65,7 @@
|
|||||||
'hst_rate' => $hst_rate,
|
'hst_rate' => $hst_rate,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$invoice = Invoice::where('internal_id', 'TN40001')->firstOrFail();
|
$invoice = Invoice::where('internal_id', 'TN4001')->firstOrFail();
|
||||||
|
|
||||||
$this->assertEquals($invoice->orders->isEmpty(), true);
|
$this->assertEquals($invoice->orders->isEmpty(), true);
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user