Skip to content

Commit 3313f0b

Browse files
authored
Merge pull request #149 from Blair2004/purchase-order-improvements
Purchase order improvements
2 parents 9a4dc13 + 44bfde2 commit 3313f0b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+1383
-423
lines changed
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?php
2+
3+
namespace App\Console\Commands;
4+
5+
use Illuminate\Console\Command;
6+
use App\Services\BarcodeService;
7+
use App\Services\ProductService;
8+
use App\Models\Product;
9+
10+
class RecreateBarcodeForProductsCommand extends Command
11+
{
12+
/**
13+
* The name and signature of the console command.
14+
*
15+
* @var string
16+
*/
17+
protected $signature = 'ns:products {operation}';
18+
19+
/**
20+
* The console command description.
21+
*
22+
* @var string
23+
*/
24+
protected $description = 'Perform various bulk operations on products';
25+
26+
/**
27+
* The barcode service used to generate barcode
28+
*
29+
* @var ProductService $barcodeService
30+
*/
31+
protected $productService;
32+
33+
/**
34+
* Create a new command instance.
35+
*
36+
* @return void
37+
*/
38+
public function __construct(
39+
ProductService $productService
40+
)
41+
{
42+
parent::__construct();
43+
44+
$this->productService = $productService;
45+
}
46+
47+
/**
48+
* Execute the console command.
49+
*
50+
* @return int
51+
*/
52+
public function handle()
53+
{
54+
if ( $this->argument( 'operation' ) === 'refresh-barcode' ) {
55+
$products = $this->withProgressBar( Product::get(), function( $product ) {
56+
$this->productService->generateProductBarcode( $product );
57+
});
58+
59+
$this->newLine();
60+
return $this->info( __( 'The product barcodes has been refreshed successfully.' ) );
61+
}
62+
63+
return $this->error( __( 'Invalid operation provided.' ) );
64+
}
65+
}

app/Crud/ProductCrud.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,16 @@ public function getForm( $entry = null )
302302
'label' => __( 'Units' ),
303303
'fields' => [
304304
[
305+
'type' => 'switch',
306+
'description' => __( 'The product won\'t be visible on the grid and fetched only using the barcode reader or associated barcode.' ),
307+
'options' => Helper::kvToJsOptions([
308+
true => __( 'Yes' ),
309+
false => __( 'No' ),
310+
]),
311+
'name' => 'accurate_tracking',
312+
'label' => __( 'Accurate Tracking' ),
313+
'value' => $entry->accurate_tracking ?? false,
314+
], [
305315
'type' => 'select',
306316
'options' => Helper::toJsOptions( $groups, [ 'id', 'name' ] ),
307317
'name' => 'unit_group',
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
namespace App\Events;
4+
5+
use App\Models\Product;
6+
use Illuminate\Broadcasting\Channel;
7+
use Illuminate\Broadcasting\InteractsWithSockets;
8+
use Illuminate\Broadcasting\PresenceChannel;
9+
use Illuminate\Broadcasting\PrivateChannel;
10+
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
11+
use Illuminate\Foundation\Events\Dispatchable;
12+
use Illuminate\Queue\SerializesModels;
13+
14+
class ProductAfterCreatedEvent
15+
{
16+
use Dispatchable, InteractsWithSockets, SerializesModels;
17+
18+
public $product;
19+
20+
/**
21+
* Create a new event instance.
22+
*
23+
* @return void
24+
*/
25+
public function __construct( Product $product )
26+
{
27+
$this->product = $product;
28+
}
29+
30+
/**
31+
* Get the channels the event should broadcast on.
32+
*
33+
* @return \Illuminate\Broadcasting\Channel|array
34+
*/
35+
public function broadcastOn()
36+
{
37+
return new PrivateChannel('channel-name');
38+
}
39+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
namespace App\Events;
4+
5+
use App\Models\Product;
6+
use Illuminate\Broadcasting\Channel;
7+
use Illuminate\Broadcasting\InteractsWithSockets;
8+
use Illuminate\Broadcasting\PresenceChannel;
9+
use Illuminate\Broadcasting\PrivateChannel;
10+
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
11+
use Illuminate\Foundation\Events\Dispatchable;
12+
use Illuminate\Queue\SerializesModels;
13+
14+
class ProductAfterUpdatedEvent
15+
{
16+
use Dispatchable, InteractsWithSockets, SerializesModels;
17+
18+
public $product;
19+
20+
/**
21+
* Create a new event instance.
22+
*
23+
* @return void
24+
*/
25+
public function __construct( Product $product )
26+
{
27+
$this->product = $product;
28+
}
29+
30+
/**
31+
* Get the channels the event should broadcast on.
32+
*
33+
* @return \Illuminate\Broadcasting\Channel|array
34+
*/
35+
public function broadcastOn()
36+
{
37+
return new PrivateChannel('channel-name');
38+
}
39+
}

app/Http/Controllers/Dashboard/CategoryController.php

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -231,12 +231,15 @@ public function getCategories( $id = '0' )
231231
$category = ProductCategory::where( 'id', $id )
232232
->displayOnPOS()
233233
->with( 'subCategories' )
234-
->with( 'products.galleries' )
235234
->first();
236235

237236
return [
238-
'products' => $category->products,
239-
'categories' => $category->subCategories()
237+
'products' => $category->products()
238+
->with( 'galleries' )
239+
->trackingDisabled()
240+
->get(),
241+
'categories' => $category
242+
->subCategories()
240243
->displayOnPOS()
241244
->get(),
242245
'previousCategory' => ProductCategory::find( $category->parent_id ) ?? null, // means should return to the root

app/Http/Controllers/Dashboard/ProductsController.php

Lines changed: 65 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use App\Classes\Output;
1111
use App\Crud\ProductHistoryCrud;
1212
use App\Crud\ProductUnitQuantitiesCrud;
13+
use App\Exceptions\NotAllowedException;
1314
use App\Exceptions\NotFoundException;
1415
use App\Http\Controllers\DashboardController;
1516
use App\Models\ProcurementProduct;
@@ -25,6 +26,7 @@
2526
use App\Models\Unit;
2627
use App\Models\ProductUnitQuantity;
2728
use App\Services\CrudService;
29+
use App\Services\DateService;
2830
use App\Services\Helper;
2931
use App\Services\ProductService;
3032
use App\Services\Options;
@@ -37,13 +39,20 @@ class ProductsController extends DashboardController
3739
/** @var ProductService */
3840
protected $productService;
3941

42+
/**
43+
* @var DateService
44+
*/
45+
protected $dateService;
46+
4047
public function __construct(
41-
ProductService $productService
48+
ProductService $productService,
49+
DateService $dateService
4250
)
4351
{
4452
parent::__construct();
4553

4654
$this->productService = $productService;
55+
$this->dateService = $dateService;
4756
}
4857

4958
public function saveProduct( Request $request )
@@ -523,19 +532,71 @@ public function createAdjustment( Request $request )
523532

524533
public function searchUsingArgument( $reference )
525534
{
526-
$product = Product::barcode( $reference )
535+
$procurementProduct = ProcurementProduct::barcode( $reference )->first();
536+
$productUnitQuantity = ProductUnitQuantity::barcode( $reference )->first();
537+
$product = Product::barcode( $reference )
527538
->searchable()
528-
->with( 'unit_quantities' )
529539
->first();
530540

541+
if ( $procurementProduct instanceof ProcurementProduct ) {
542+
543+
$product = $procurementProduct->product;
544+
545+
/**
546+
* check if the product has expired
547+
* and the sales are disallowed.
548+
*/
549+
if (
550+
$this->dateService->copy()->greaterThan( $procurementProduct->expiration_date ) &&
551+
$product->expires &&
552+
$product->on_expiration === Product::EXPIRES_PREVENT_SALES ) {
553+
throw new NotAllowedException( __( 'Unable to add the product to the cart as it has expired.' ) );
554+
}
555+
556+
/**
557+
* We need to add a reference of the procurement product
558+
* in order to deplete the available quantity accordingly.
559+
* Will also be helpful to track how products are sold.
560+
*/
561+
$product->procurement_product_id = $procurementProduct->id;
562+
563+
} else if ( $productUnitQuantity instanceof ProductUnitQuantity ) {
564+
565+
/**
566+
* if a product unit quantity is loaded. Then we make sure to return the parent
567+
* product with the selected unit quantity.
568+
*/
569+
$productUnitQuantity->load( 'unit' );
570+
571+
$product = Product::find( $productUnitQuantity->product_id );
572+
$product->load( 'unit_quantities' );
573+
$product->selectedUnitQuantity = $productUnitQuantity;
574+
575+
} else if ( $product instanceof Product ) {
576+
577+
$product->load( 'unit_quantities' );
578+
579+
if ( $product->accurate_tracking ) {
580+
throw new NotAllowedException( __( 'Unable to add a product that has accurate tracking enabled, using an ordinary barcode.' ) );
581+
}
582+
}
583+
531584
if ( $product instanceof Product ) {
532585
return [
533586
'type' => 'product',
534587
'product' => $product
535588
];
536589
}
537590

538-
throw new NotFoundException( __( 'The product request cannot be found.' ) );
591+
throw new NotFoundException( __( 'There is no products matching the current request.' ) );
592+
}
593+
594+
public function printLabels()
595+
{
596+
return $this->view( 'pages.dashboard.products.print-labels', [
597+
'title' => __( 'Print Labels' ),
598+
'description' => __( 'Customize and print products labels.' ),
599+
]);
539600
}
540601
}
541602

app/Http/Middleware/CheckApplicationHealthMiddleware.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ public function handle(Request $request, Closure $next)
4949
}
5050

5151
/**
52-
* we'll check here is a module is missing a
52+
* we'll check here is a module has a missing
5353
* dependency to disable it
5454
* @var ModulesService
5555
*/

app/Listeners/ProductEventsSubscriber.php

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
<?php
22
namespace App\Listeners;
33

4+
use App\Events\ProductAfterCreatedEvent;
45
use App\Services\ProductService;
56
use App\Events\ProductAfterDeleteEvent;
67
use App\Events\ProductAfterStockAdjustmentEvent;
8+
use App\Events\ProductAfterUpdatedEvent;
79
use App\Events\ProductBeforeDeleteEvent;
810
use App\Jobs\HandleStockAdjustmentJob;
11+
use App\Services\BarcodeService;
912
use App\Services\ProcurementService;
1013
use App\Services\ReportService;
1114

@@ -20,14 +23,19 @@ class ProductEventsSubscriber
2023
/** @var ReportService */
2124
protected $reportService;
2225

26+
/** @var BarcodeService */
27+
protected $barcodeService;
28+
2329
public function __construct(
2430
ProductService $productService,
2531
ProcurementService $procurementService,
26-
ReportService $reportService
32+
ReportService $reportService,
33+
BarcodeService $barcodeService
2734
) {
2835
$this->productService = $productService;
2936
$this->procurementService = $procurementService;
3037
$this->reportService = $reportService;
38+
$this->barcodeService = $barcodeService;
3139
}
3240

3341
public function subscribe( $events )
@@ -46,6 +54,16 @@ public function subscribe( $events )
4654
ProductAfterStockAdjustmentEvent::class,
4755
[ ProductEventsSubscriber::class, 'afterStockAdjustment' ]
4856
);
57+
58+
$events->listen(
59+
ProductAfterCreatedEvent::class,
60+
[ ProductEventsSubscriber::class, 'generateBarcode' ]
61+
);
62+
63+
$events->listen(
64+
ProductAfterUpdatedEvent::class,
65+
[ ProductEventsSubscriber::class, 'generateBarcode' ]
66+
);
4967
}
5068

5169
public function beforeDeleteProduct( ProductBeforeDeleteEvent $event )
@@ -67,6 +85,24 @@ public function beforeDeleteProduct( ProductBeforeDeleteEvent $event )
6785
});
6886
}
6987

88+
public function generateBarcode( $event )
89+
{
90+
$this->barcodeService->generateBarcode(
91+
$event->product->barcode,
92+
$event->product->barcode_type
93+
);
94+
95+
/**
96+
* save barcode for unit quantities
97+
*/
98+
$event->product->unit_quantities->each( function( $unitQuantity ) use ( $event ) {
99+
$this->barcodeService->generateBarcode(
100+
$unitQuantity->barcode,
101+
$event->product->barcode_type
102+
);
103+
});
104+
}
105+
70106
public function afterStockAdjustment( ProductAfterStockAdjustmentEvent $event )
71107
{
72108
HandleStockAdjustmentJob::dispatch( $event )

0 commit comments

Comments
 (0)