Added: Sales Return Module & Sale Return Payments

This commit is contained in:
Fahim 2021-08-08 21:52:15 +06:00
parent 7719b464e9
commit 3f9ff85595
61 changed files with 2210 additions and 9 deletions

View File

@ -21,7 +21,7 @@ class CreatePurchasePaymentsTable extends Migration
$table->string('reference');
$table->string('payment_method');
$table->text('note')->nullable();
$table->foreign('purchase_id')->references('id')->on('purchase_payments')->cascadeOnDelete();
$table->foreign('purchase_id')->references('id')->on('purchases')->cascadeOnDelete();
$table->timestamps();
});
}

View File

@ -21,7 +21,7 @@ class CreateSalePaymentsTable extends Migration
$table->string('reference');
$table->string('payment_method');
$table->text('note')->nullable();
$table->foreign('sale_id')->references('id')->on('sale_payments')->cascadeOnDelete();
$table->foreign('sale_id')->references('id')->on('sales')->cascadeOnDelete();
$table->timestamps();
});
}

View File

@ -39,6 +39,7 @@ class SaleController extends Controller
public function store(StoreSaleRequest $request) {
DB::transaction(function () use ($request) {
$due_amount = $request->total_amount - $request->paid_amount;
if ($due_amount == $request->total_amount) {
$payment_status = 'Unpaid';
} elseif ($due_amount > 0) {
@ -149,6 +150,7 @@ class SaleController extends Controller
public function update(UpdateSaleRequest $request, Sale $sale) {
DB::transaction(function () use ($request, $sale) {
$due_amount = $request->total_amount - $request->paid_amount;
if ($due_amount == $request->total_amount) {
$payment_status = 'Unpaid';

View File

@ -57,6 +57,7 @@ class SalePaymentsController extends Controller
$sale = Sale::findOrFail($request->sale_id);
$due_amount = $sale->due_amount - $request->amount;
if ($due_amount == $sale->total_amount) {
$payment_status = 'Unpaid';
} elseif ($due_amount > 0) {

View File

@ -1,4 +1,4 @@
d@if ($data->status == 'Pending')
@if ($data->status == 'Pending')
<span class="badge badge-info">
{{ $data->status }}
</span>

View File

View File

@ -0,0 +1,5 @@
<?php
return [
'name' => 'SalesReturn'
];

View File

View File

@ -0,0 +1,48 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateSaleReturnsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('sale_returns', function (Blueprint $table) {
$table->id();
$table->date('date');
$table->string('reference');
$table->unsignedBigInteger('customer_id')->nullable();
$table->string('customer_name');
$table->integer('tax_percentage')->default(0);
$table->integer('tax_amount')->default(0);
$table->integer('discount_percentage')->default(0);
$table->integer('discount_amount')->default(0);
$table->integer('shipping_amount')->default(0);
$table->integer('total_amount');
$table->integer('paid_amount');
$table->integer('due_amount');
$table->string('status');
$table->string('payment_status');
$table->string('payment_method');
$table->text('note')->nullable();
$table->foreign('customer_id')->references('id')->on('customers')->nullOnDelete();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('sale_returns');
}
}

View File

@ -0,0 +1,46 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateSaleReturnDetailsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('sale_return_details', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('sale_return_id');
$table->unsignedBigInteger('product_id')->nullable();
$table->string('product_name');
$table->string('product_code');
$table->integer('quantity');
$table->integer('price');
$table->integer('unit_price');
$table->integer('sub_total');
$table->integer('product_discount_amount');
$table->string('product_discount_type')->default('fixed');
$table->integer('product_tax_amount');
$table->foreign('sale_return_id')->references('id')
->on('sale_returns')->cascadeOnDelete();
$table->foreign('product_id')->references('id')
->on('products')->nullOnDelete();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('sale_return_details');
}
}

View File

@ -0,0 +1,38 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateSaleReturnPaymentsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('sale_return_payments', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('sale_return_id');
$table->integer('amount');
$table->date('date');
$table->string('reference');
$table->string('payment_method');
$table->text('note')->nullable();
$table->foreign('sale_return_id')->references('id')->on('sale_returns')->cascadeOnDelete();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('sale_return_payments');
}
}

View File

@ -0,0 +1,21 @@
<?php
namespace Modules\SalesReturn\Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Database\Eloquent\Model;
class SalesReturnDatabaseSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
Model::unguard();
// $this->call("OthersTableSeeder");
}
}

View File

View File

@ -0,0 +1,49 @@
<?php
namespace Modules\SalesReturn\Entities;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
class SaleReturn extends Model
{
use HasFactory;
protected $guarded = [];
public function saleReturnDetails() {
return $this->hasMany(SaleReturnDetail::class, 'sale_return_id', 'id');
}
public function saleReturnPayments() {
return $this->hasMany(SaleReturnPayment::class, 'sale_return_id', 'id');
}
public function getReferenceAttribute($value) {
return strtoupper($value) . '_' . str_pad($this->attributes['id'], 6, '0', STR_PAD_LEFT);
}
public function getShippingAmountAttribute($value) {
return $value / 100;
}
public function getPaidAmountAttribute($value) {
return $value / 100;
}
public function getTotalAmountAttribute($value) {
return $value / 100;
}
public function getDueAmountAttribute($value) {
return $value / 100;
}
public function getTaxAmountAttribute($value) {
return $value / 100;
}
public function getDiscountAmountAttribute($value) {
return $value / 100;
}
}

View File

@ -0,0 +1,44 @@
<?php
namespace Modules\SalesReturn\Entities;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Modules\Product\Entities\Product;
class SaleReturnDetail extends Model
{
use HasFactory;
protected $guarded = [];
protected $with = ['product'];
public function product() {
return $this->belongsTo(Product::class, 'product_id', 'id');
}
public function saleReturn() {
return $this->belongsTo(SaleReturnPayment::class, 'sale_return_id', 'id');
}
public function getPriceAttribute($value) {
return $value / 100;
}
public function getUnitPriceAttribute($value) {
return $value / 100;
}
public function getSubTotalAttribute($value) {
return $value / 100;
}
public function getProductDiscountAmountAttribute($value) {
return $value / 100;
}
public function getProductTaxAmountAttribute($value) {
return $value / 100;
}
}

View File

@ -0,0 +1,34 @@
<?php
namespace Modules\SalesReturn\Entities;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Support\Carbon;
class SaleReturnPayment extends Model
{
use HasFactory;
protected $guarded = [];
public function saleReturn() {
return $this->belongsTo(SaleReturn::class, 'sale_return_id', 'id');
}
public function setAmountAttribute($value) {
$this->attributes['amount'] = $value * 100;
}
public function getAmountAttribute($value) {
return $value / 100;
}
public function getDateAttribute($value) {
return Carbon::parse($value)->format('d M, Y');
}
public function scopeBySaleReturn($query) {
return $query->where('sale_return_id', request()->route('sale_return_id'));
}
}

View File

@ -0,0 +1,147 @@
<?php
namespace Modules\SalesReturn\Http\Controllers;
use App\DataTables\SaleReturnPaymentsDataTable;
use Illuminate\Contracts\Support\Renderable;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Gate;
use Modules\SalesReturn\Entities\SaleReturn;
use Modules\SalesReturn\Entities\SaleReturnPayment;
class SaleReturnPaymentsController extends Controller
{
public function index($sale_return_id, SaleReturnPaymentsDataTable $dataTable) {
abort_if(Gate::denies('access_sale_return_payments'), 403);
$sale_return = SaleReturn::findOrFail($sale_return_id);
return $dataTable->render('salesreturn::payments.index', compact('sale_return'));
}
public function create($sale_return_id) {
abort_if(Gate::denies('access_sale_payments'), 403);
$sale_return = SaleReturn::findOrFail($sale_return_id);
return view('salesreturn::payments.create', compact('sale_return'));
}
public function store(Request $request) {
abort_if(Gate::denies('access_sale_payments'), 403);
$request->validate([
'date' => 'required|date',
'reference' => 'required|string|max:255',
'amount' => 'required|numeric',
'note' => 'nullable|string|max:1000',
'sale_return_id' => 'required',
'payment_method' => 'required|string|max:255'
]);
DB::transaction(function () use ($request) {
SaleReturnPayment::create([
'date' => $request->date,
'reference' => $request->reference,
'amount' => $request->amount,
'note' => $request->note,
'sale_return_id' => $request->sale_return_id,
'payment_method' => $request->payment_method
]);
$sale_return = SaleReturn::findOrFail($request->sale_return_id);
$due_amount = $sale_return->due_amount - $request->amount;
if ($due_amount == $sale_return->total_amount) {
$payment_status = 'Unpaid';
} elseif ($due_amount > 0) {
$payment_status = 'Partial';
} else {
$payment_status = 'Paid';
}
$sale_return->update([
'paid_amount' => ($sale_return->paid_amount + $request->amount) * 100,
'due_amount' => $due_amount * 100,
'payment_status' => $payment_status
]);
});
toast('Sale Return Payment Created!', 'success');
return redirect()->route('sale-returns.index');
}
public function edit($sale_return_id, SaleReturnPayment $saleReturnPayment) {
abort_if(Gate::denies('access_sale_return_payments'), 403);
$sale_return = SaleReturn::findOrFail($sale_return_id);
return view('salesreturn::payments.edit', compact('saleReturnPayment', 'sale_return'));
}
public function update(Request $request, SaleReturnPayment $saleReturnPayment) {
abort_if(Gate::denies('access_sale_return_payments'), 403);
$request->validate([
'date' => 'required|date',
'reference' => 'required|string|max:255',
'amount' => 'required|numeric',
'note' => 'nullable|string|max:1000',
'sale_return_id' => 'required',
'payment_method' => 'required|string|max:255'
]);
DB::transaction(function () use ($request, $saleReturnPayment) {
$sale_return = $saleReturnPayment->saleReturn;
$due_amount = ($sale_return->due_amount + $saleReturnPayment->amount) - $request->amount;
if ($due_amount == $sale_return->total_amount) {
$payment_status = 'Unpaid';
} elseif ($due_amount > 0) {
$payment_status = 'Partial';
} else {
$payment_status = 'Paid';
}
$sale_return->update([
'paid_amount' => (($sale_return->paid_amount - $saleReturnPayment->amount) + $request->amount) * 100,
'due_amount' => $due_amount * 100,
'payment_status' => $payment_status
]);
$saleReturnPayment->update([
'date' => $request->date,
'reference' => $request->reference,
'amount' => $request->amount,
'note' => $request->note,
'sale_return_id' => $request->sale_return_id,
'payment_method' => $request->payment_method
]);
});
toast('Sale Return Payment Updated!', 'info');
return redirect()->route('sale-returns.index');
}
public function destroy(SaleReturnPayment $saleReturnPayment) {
abort_if(Gate::denies('access_sale_return_payments'), 403);
$saleReturnPayment->delete();
toast('Sale Return Payment Deleted!', 'warning');
return redirect()->route('sale-returns.index');
}
}

View File

@ -0,0 +1,233 @@
<?php
namespace Modules\SalesReturn\Http\Controllers;
use App\DataTables\SaleReturnsDataTable;
use Gloudemans\Shoppingcart\Facades\Cart;
use Illuminate\Contracts\Support\Renderable;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Gate;
use Modules\People\Entities\Customer;
use Modules\Product\Entities\Product;
use Modules\SalesReturn\Entities\SaleReturn;
use Modules\SalesReturn\Entities\SaleReturnDetail;
use Modules\SalesReturn\Entities\SaleReturnPayment;
use Modules\SalesReturn\Http\Requests\StoreSaleReturnRequest;
use Modules\SalesReturn\Http\Requests\UpdateSaleReturnRequest;
class SalesReturnController extends Controller
{
public function index(SaleReturnsDataTable $dataTable) {
abort_if(Gate::denies('access_sale_returns'), 403);
return $dataTable->render('salesreturn::index');
}
public function create() {
abort_if(Gate::denies('create_sale_returns'), 403);
Cart::instance('sale_return')->destroy();
return view('salesreturn::create');
}
public function store(StoreSaleReturnRequest $request) {
DB::transaction(function () use ($request) {
$due_amount = $request->total_amount - $request->paid_amount;
if ($due_amount == $request->total_amount) {
$payment_status = 'Unpaid';
} elseif ($due_amount > 0) {
$payment_status = 'Partial';
} else {
$payment_status = 'Paid';
}
$sale_return = SaleReturn::create([
'date' => $request->date,
'reference' => $request->reference,
'customer_id' => $request->customer_id,
'customer_name' => Customer::findOrFail($request->customer_id)->customer_name,
'tax_percentage' => $request->tax_percentage,
'discount_percentage' => $request->discount_percentage,
'shipping_amount' => $request->shipping_amount * 100,
'paid_amount' => $request->paid_amount * 100,
'total_amount' => $request->total_amount * 100,
'due_amount' => $due_amount * 100,
'status' => $request->status,
'payment_status' => $payment_status,
'payment_method' => $request->payment_method,
'note' => $request->note,
'tax_amount' => Cart::instance('sale_return')->tax() * 100,
'discount_amount' => Cart::instance('sale_return')->discount() * 100,
]);
foreach (Cart::instance('sale_return')->content() as $cart_item) {
SaleReturnDetail::create([
'sale_return_id' => $sale_return->id,
'product_id' => $cart_item->id,
'product_name' => $cart_item->name,
'product_code' => $cart_item->options->code,
'quantity' => $cart_item->qty,
'price' => $cart_item->price * 100,
'unit_price' => $cart_item->options->unit_price * 100,
'sub_total' => $cart_item->options->sub_total * 100,
'product_discount_amount' => $cart_item->options->product_discount * 100,
'product_discount_type' => $cart_item->options->product_discount_type,
'product_tax_amount' => $cart_item->options->product_tax * 100,
]);
if ($request->status == 'Completed') {
$product = Product::findOrFail($cart_item->id);
$product->update([
'product_quantity' => $product->product_quantity + $cart_item->qty
]);
}
}
Cart::instance('sale_return')->destroy();
SaleReturnPayment::create([
'date' => $request->date,
'reference' => 'INV/'.$sale_return->reference,
'amount' => $sale_return->paid_amount,
'sale_return_id' => $sale_return->id,
'payment_method' => $request->payment_method
]);
});
toast('Sale Return Created!', 'success');
return redirect()->route('sale-returns.index');
}
public function show(SaleReturn $sale_return) {
abort_if(Gate::denies('show_sale_returns'), 403);
$customer = Customer::findOrFail($sale_return->customer_id);
return view('salesreturn::show', compact('sale_return', 'customer'));
}
public function edit(SaleReturn $sale_return) {
abort_if(Gate::denies('edit_sales'), 403);
$sale_return_details = $sale_return->saleReturnDetails;
Cart::instance('sale_return')->destroy();
$cart = Cart::instance('sale_return');
foreach ($sale_return_details as $sale_return_detail) {
$cart->add([
'id' => $sale_return_detail->product_id,
'name' => $sale_return_detail->product_name,
'qty' => $sale_return_detail->quantity,
'price' => $sale_return_detail->price,
'weight' => 1,
'options' => [
'product_discount' => $sale_return_detail->product_discount_amount,
'product_discount_type' => $sale_return_detail->product_discount_type,
'sub_total' => $sale_return_detail->sub_total,
'code' => $sale_return_detail->product_code,
'stock' => Product::findOrFail($sale_return_detail->product_id)->product_quantity,
'product_tax' => $sale_return_detail->product_tax_amount,
'unit_price' => $sale_return_detail->unit_price
]
]);
}
return view('salesreturn::edit', compact('sale_return'));
}
public function update(UpdateSaleReturnRequest $request, SaleReturn $sale_return) {
DB::transaction(function () use ($request, $sale_return) {
$due_amount = $request->total_amount - $request->paid_amount;
if ($due_amount == $request->total_amount) {
$payment_status = 'Unpaid';
} elseif ($due_amount > 0) {
$payment_status = 'Partial';
} else {
$payment_status = 'Paid';
}
foreach ($sale_return->saleReturnDetails as $sale_return_detail) {
if ($sale_return->status == 'Completed') {
$product = Product::findOrFail($sale_return_detail->product_id);
$product->update([
'product_quantity' => $product->product_quantity - $sale_return_detail->quantity
]);
}
$sale_return_detail->delete();
}
$sale_return->update([
'date' => $request->date,
'reference' => $request->reference,
'customer_id' => $request->customer_id,
'customer_name' => Customer::findOrFail($request->customer_id)->customer_name,
'tax_percentage' => $request->tax_percentage,
'discount_percentage' => $request->discount_percentage,
'shipping_amount' => $request->shipping_amount * 100,
'paid_amount' => $request->paid_amount * 100,
'total_amount' => $request->total_amount * 100,
'due_amount' => $due_amount * 100,
'status' => $request->status,
'payment_status' => $payment_status,
'payment_method' => $request->payment_method,
'note' => $request->note,
'tax_amount' => Cart::instance('sale_return')->tax() * 100,
'discount_amount' => Cart::instance('sale_return')->discount() * 100,
]);
foreach (Cart::instance('sale_return')->content() as $cart_item) {
SaleReturnDetail::create([
'sale_return_id' => $sale_return->id,
'product_id' => $cart_item->id,
'product_name' => $cart_item->name,
'product_code' => $cart_item->options->code,
'quantity' => $cart_item->qty,
'price' => $cart_item->price * 100,
'unit_price' => $cart_item->options->unit_price * 100,
'sub_total' => $cart_item->options->sub_total * 100,
'product_discount_amount' => $cart_item->options->product_discount * 100,
'product_discount_type' => $cart_item->options->product_discount_type,
'product_tax_amount' => $cart_item->options->product_tax * 100,
]);
if ($request->status == 'Completed') {
$product = Product::findOrFail($cart_item->id);
$product->update([
'product_quantity' => $product->product_quantity + $cart_item->qty
]);
}
}
Cart::instance('sale_return')->destroy();
});
toast('Sale Return Updated!', 'info');
return redirect()->route('sale-returns.index');
}
public function destroy(SaleReturn $sale_return) {
abort_if(Gate::denies('delete_sale_returns'), 403);
$sale_return->delete();
toast('Sale Return Deleted!', 'warning');
return redirect()->route('sale-returns.index');
}
}

View File

@ -0,0 +1,40 @@
<?php
namespace Modules\SalesReturn\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Gate;
class StoreSaleReturnRequest extends FormRequest
{
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'customer_id' => 'required|numeric',
'reference' => 'required|string|max:255',
'tax_percentage' => 'required|integer|min:0|max:100',
'discount_percentage' => 'required|integer|min:0|max:100',
'shipping_amount' => 'required|numeric',
'total_amount' => 'required|numeric',
'paid_amount' => 'required|numeric',
'status' => 'required|string|max:255',
'payment_method' => 'required|string|max:255',
'note' => 'nullable|string|max:1000'
];
}
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return Gate::allows('create_sales');
}
}

View File

@ -0,0 +1,40 @@
<?php
namespace Modules\SalesReturn\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Gate;
class UpdateSaleReturnRequest extends FormRequest
{
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'customer_id' => 'required|numeric',
'reference' => 'required|string|max:255',
'tax_percentage' => 'required|integer|min:0|max:100',
'discount_percentage' => 'required|integer|min:0|max:100',
'shipping_amount' => 'required|numeric',
'total_amount' => 'required|numeric',
'paid_amount' => 'required|numeric|max:' . $this->sale_return->total_amount,
'status' => 'required|string|max:255',
'payment_method' => 'required|string|max:255',
'note' => 'nullable|string|max:1000'
];
}
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return Gate::allows('edit_sale_returns');
}
}

View File

View File

@ -0,0 +1,69 @@
<?php
namespace Modules\SalesReturn\Providers;
use Illuminate\Support\Facades\Route;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
class RouteServiceProvider extends ServiceProvider
{
/**
* The module namespace to assume when generating URLs to actions.
*
* @var string
*/
protected $moduleNamespace = 'Modules\SalesReturn\Http\Controllers';
/**
* Called before routes are registered.
*
* Register any model bindings or pattern based filters.
*
* @return void
*/
public function boot()
{
parent::boot();
}
/**
* Define the routes for the application.
*
* @return void
*/
public function map()
{
$this->mapApiRoutes();
$this->mapWebRoutes();
}
/**
* Define the "web" routes for the application.
*
* These routes all receive session state, CSRF protection, etc.
*
* @return void
*/
protected function mapWebRoutes()
{
Route::middleware('web')
->namespace($this->moduleNamespace)
->group(module_path('SalesReturn', '/Routes/web.php'));
}
/**
* Define the "api" routes for the application.
*
* These routes are typically stateless.
*
* @return void
*/
protected function mapApiRoutes()
{
Route::prefix('api')
->middleware('api')
->namespace($this->moduleNamespace)
->group(module_path('SalesReturn', '/Routes/api.php'));
}
}

View File

@ -0,0 +1,112 @@
<?php
namespace Modules\SalesReturn\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Database\Eloquent\Factory;
class SalesReturnServiceProvider extends ServiceProvider
{
/**
* @var string $moduleName
*/
protected $moduleName = 'SalesReturn';
/**
* @var string $moduleNameLower
*/
protected $moduleNameLower = 'salesreturn';
/**
* Boot the application events.
*
* @return void
*/
public function boot()
{
$this->registerTranslations();
$this->registerConfig();
$this->registerViews();
$this->loadMigrationsFrom(module_path($this->moduleName, 'Database/Migrations'));
}
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
$this->app->register(RouteServiceProvider::class);
}
/**
* Register config.
*
* @return void
*/
protected function registerConfig()
{
$this->publishes([
module_path($this->moduleName, 'Config/config.php') => config_path($this->moduleNameLower . '.php'),
], 'config');
$this->mergeConfigFrom(
module_path($this->moduleName, 'Config/config.php'), $this->moduleNameLower
);
}
/**
* Register views.
*
* @return void
*/
public function registerViews()
{
$viewPath = resource_path('views/modules/' . $this->moduleNameLower);
$sourcePath = module_path($this->moduleName, 'Resources/views');
$this->publishes([
$sourcePath => $viewPath
], ['views', $this->moduleNameLower . '-module-views']);
$this->loadViewsFrom(array_merge($this->getPublishableViewPaths(), [$sourcePath]), $this->moduleNameLower);
}
/**
* Register translations.
*
* @return void
*/
public function registerTranslations()
{
$langPath = resource_path('lang/modules/' . $this->moduleNameLower);
if (is_dir($langPath)) {
$this->loadTranslationsFrom($langPath, $this->moduleNameLower);
} else {
$this->loadTranslationsFrom(module_path($this->moduleName, 'Resources/lang'), $this->moduleNameLower);
}
}
/**
* Get the services provided by the provider.
*
* @return array
*/
public function provides()
{
return [];
}
private function getPublishableViewPaths(): array
{
$paths = [];
foreach (\Config::get('view.paths') as $path) {
if (is_dir($path . '/modules/' . $this->moduleNameLower)) {
$paths[] = $path . '/modules/' . $this->moduleNameLower;
}
}
return $paths;
}
}

View File

View File

View File

@ -0,0 +1,139 @@
@extends('layouts.app')
@section('title', 'Create Sale Return')
@section('breadcrumb')
<ol class="breadcrumb border-0 m-0">
<li class="breadcrumb-item"><a href="{{ route('home') }}">Home</a></li>
<li class="breadcrumb-item"><a href="{{ route('sale-returns.index') }}">Sale Returns</a></li>
<li class="breadcrumb-item active">Add</li>
</ol>
@endsection
@section('content')
<div class="container-fluid mb-4">
<div class="row">
<div class="col-12">
<livewire:search-product/>
</div>
</div>
<div class="row mt-4">
<div class="col-md-12">
<div class="card">
<div class="card-body">
@include('utils.alerts')
<form id="sale-return-form" action="{{ route('sale-returns.store') }}" method="POST">
@csrf
<div class="form-row">
<div class="col-lg-4">
<div class="form-group">
<label for="reference">Reference <span class="text-danger">*</span></label>
<input type="text" class="form-control" name="reference" required readonly value="SLRN">
</div>
</div>
<div class="col-lg-4">
<div class="from-group">
<div class="form-group">
<label for="customer_id">Customer <span class="text-danger">*</span></label>
<select class="form-control" name="customer_id" id="customer_id" required>
@foreach(\Modules\People\Entities\Customer::all() as $customer)
<option value="{{ $customer->id }}">{{ $customer->customer_name }}</option>
@endforeach
</select>
</div>
</div>
</div>
<div class="col-lg-4">
<div class="from-group">
<div class="form-group">
<label for="date">Date <span class="text-danger">*</span></label>
<input type="date" class="form-control" name="date" required value="{{ now()->format('Y-m-d') }}">
</div>
</div>
</div>
</div>
<livewire:product-cart :cartInstance="'sale_return'"/>
<div class="form-row">
<div class="col-lg-4">
<div class="form-group">
<label for="status">Status <span class="text-danger">*</span></label>
<select class="form-control" name="status" id="status" required>
<option value="Pending">Pending</option>
<option value="Shipped">Shipped</option>
<option value="Completed">Completed</option>
</select>
</div>
</div>
<div class="col-lg-4">
<div class="from-group">
<div class="form-group">
<label for="payment_method">Payment Method <span class="text-danger">*</span></label>
<select class="form-control" name="payment_method" id="payment_method" required>
<option value="Cash">Cash</option>
<option value="Credit Card">Credit Card</option>
<option value="Bank Transfer">Bank Transfer</option>
<option value="Cheque">Cheque</option>
<option value="Other">Other</option>
</select>
</div>
</div>
</div>
<div class="col-lg-4">
<div class="form-group">
<label for="paid_amount">Amount Received <span class="text-danger">*</span></label>
<div class="input-group">
<input id="paid_amount" type="text" class="form-control" name="paid_amount" required>
<div class="input-group-append">
<button id="getTotalAmount" class="btn btn-primary" type="button">
<i class="bi bi-check-square"></i>
</button>
</div>
</div>
</div>
</div>
</div>
<div class="form-group">
<label for="note">Note (If Needed)</label>
<textarea name="note" id="note" rows="5" class="form-control"></textarea>
</div>
<div class="mt-3">
<button type="submit" class="btn btn-primary">
Create Sale Return <i class="bi bi-check"></i>
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection
@push('page_scripts')
<script src="{{ asset('js/jquery-mask-money.js') }}"></script>
<script>
$(document).ready(function () {
$('#paid_amount').maskMoney({
prefix:'{{ settings()->currency->symbol }}',
thousands:'{{ settings()->currency->thousand_separator }}',
decimal:'{{ settings()->currency->decimal_separator }}',
allowZero: true,
});
$('#getTotalAmount').click(function () {
$('#paid_amount').maskMoney('mask', {{ Cart::instance('sale_return')->total() }});
});
$('#sale-return-form').submit(function () {
var paid_amount = $('#paid_amount').maskMoney('unmasked')[0];
$('#paid_amount').val(paid_amount);
});
});
</script>
@endpush

View File

@ -0,0 +1,124 @@
@extends('layouts.app')
@section('title', 'Edit Sale Return')
@section('breadcrumb')
<ol class="breadcrumb border-0 m-0">
<li class="breadcrumb-item"><a href="{{ route('home') }}">Home</a></li>
<li class="breadcrumb-item"><a href="{{ route('sale-returns.index') }}">Sale Returns</a></li>
<li class="breadcrumb-item active">Edit</li>
</ol>
@endsection
@section('content')
<div class="container-fluid mb-4">
<div class="row">
<div class="col-12">
<livewire:search-product/>
</div>
</div>
<div class="row mt-4">
<div class="col-md-12">
<div class="card">
<div class="card-body">
@include('utils.alerts')
<form id="sale-return-form" action="{{ route('sale-returns.update', $sale_return) }}" method="POST">
@csrf
@method('patch')
<div class="form-row">
<div class="col-lg-4">
<div class="form-group">
<label for="reference">Reference <span class="text-danger">*</span></label>
<input type="text" class="form-control" name="reference" required value="SLRN" readonly>
</div>
</div>
<div class="col-lg-4">
<div class="from-group">
<div class="form-group">
<label for="customer_id">Customer <span class="text-danger">*</span></label>
<select class="form-control" name="customer_id" id="customer_id" required>
@foreach(\Modules\People\Entities\Customer::all() as $customer)
<option {{ $sale_return->customer_id == $customer->id ? 'selected' : '' }} value="{{ $customer->id }}">{{ $customer->customer_name }}</option>
@endforeach
</select>
</div>
</div>
</div>
<div class="col-lg-4">
<div class="from-group">
<div class="form-group">
<label for="date">Date <span class="text-danger">*</span></label>
<input type="date" class="form-control" name="date" required value="{{ $sale_return->date }}">
</div>
</div>
</div>
</div>
<livewire:product-cart :cartInstance="'sale_return'" :data="$sale_return"/>
<div class="form-row">
<div class="col-lg-4">
<div class="form-group">
<label for="status">Status <span class="text-danger">*</span></label>
<select class="form-control" name="status" id="status" required>
<option {{ $sale_return->status == 'Pending' ? 'selected' : '' }} value="Pending">Pending</option>
<option {{ $sale_return->status == 'Shipped' ? 'selected' : '' }} value="Shipped">Shipped</option>
<option {{ $sale_return->status == 'Completed' ? 'selected' : '' }} value="Completed">Completed</option>
</select>
</div>
</div>
<div class="col-lg-4">
<div class="from-group">
<div class="form-group">
<label for="payment_method">Payment Method <span class="text-danger">*</span></label>
<input type="text" class="form-control" name="payment_method" required value="{{ $sale_return->payment_method }}" readonly>
</div>
</div>
</div>
<div class="col-lg-4">
<div class="form-group">
<label for="paid_amount">Amount Paid <span class="text-danger">*</span></label>
<input id="paid_amount" type="text" class="form-control" name="paid_amount" required value="{{ $sale_return->paid_amount }}" readonly>
</div>
</div>
</div>
<div class="form-group">
<label for="note">Note (If Needed)</label>
<textarea name="note" id="note" rows="5" class="form-control">{{ $sale_return->note }}</textarea>
</div>
<div class="mt-3">
<button type="submit" class="btn btn-primary">
Update Sale Return <i class="bi bi-check"></i>
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection
@push('page_scripts')
<script src="{{ asset('js/jquery-mask-money.js') }}"></script>
<script>
$(document).ready(function () {
$('#paid_amount').maskMoney({
prefix:'{{ settings()->currency->symbol }}',
thousands:'{{ settings()->currency->thousand_separator }}',
decimal:'{{ settings()->currency->decimal_separator }}',
allowZero: true,
});
$('#paid_amount').maskMoney('mask');
$('#sale-return-form').submit(function () {
var paid_amount = $('#paid_amount').maskMoney('unmasked')[0];
$('#paid_amount').val(paid_amount);
});
});
</script>
@endpush

View File

@ -0,0 +1,40 @@
@extends('layouts.app')
@section('title', 'Sale Returns')
@section('third_party_stylesheets')
<link rel="stylesheet" href="https://cdn.datatables.net/1.10.25/css/dataTables.bootstrap4.min.css">
@endsection
@section('breadcrumb')
<ol class="breadcrumb border-0 m-0">
<li class="breadcrumb-item"><a href="{{ route('home') }}">Home</a></li>
<li class="breadcrumb-item active">Sale Returns</li>
</ol>
@endsection
@section('content')
<div class="container-fluid">
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-body">
<a href="{{ route('sale-returns.create') }}" class="btn btn-primary">
Add Sale Return <i class="bi bi-plus"></i>
</a>
<hr>
<div class="table-responsive">
{!! $dataTable->table() !!}
</div>
</div>
</div>
</div>
</div>
</div>
@endsection
@push('page_scripts')
{!! $dataTable->scripts() !!}
@endpush

View File

@ -0,0 +1,42 @@
<div class="btn-group dropleft">
<button type="button" class="btn btn-ghost-primary dropdown rounded" data-toggle="dropdown" aria-expanded="false">
<i class="bi bi-three-dots-vertical"></i>
</button>
<div class="dropdown-menu">
@can('access_sale_payments')
<a href="{{ route('sale-return-payments.index', $data->id) }}" class="dropdown-item">
<i class="bi bi-cash-coin mr-2 text-warning" style="line-height: 1;"></i> Show Payments
</a>
@endcan
@can('access_sale_payments')
@if($data->due_amount > 0)
<a href="{{ route('sale-return-payments.create', $data->id) }}" class="dropdown-item">
<i class="bi bi-plus-circle-dotted mr-2 text-success" style="line-height: 1;"></i> Add Payment
</a>
@endif
@endcan
@can('edit_sales')
<a href="{{ route('sale-returns.edit', $data->id) }}" class="dropdown-item">
<i class="bi bi-pencil mr-2 text-primary" style="line-height: 1;"></i> Edit
</a>
@endcan
@can('show_sales')
<a href="{{ route('sale-returns.show', $data->id) }}" class="dropdown-item">
<i class="bi bi-eye mr-2 text-info" style="line-height: 1;"></i> Details
</a>
@endcan
@can('delete_sales')
<button id="delete" class="dropdown-item" onclick="
event.preventDefault();
if (confirm('Are you sure? It will delete the data permanently!')) {
document.getElementById('destroy{{ $data->id }}').submit()
}">
<i class="bi bi-trash mr-2 text-danger" style="line-height: 1;"></i> Delete
<form id="destroy{{ $data->id }}" class="d-none" action="{{ route('sale-returns.destroy', $data->id) }}" method="POST">
@csrf
@method('delete')
</form>
</button>
@endcan
</div>
</div>

View File

@ -0,0 +1,13 @@
@if ($data->payment_status == 'Partial')
<span class="badge badge-warning">
{{ $data->payment_status }}
</span>
@elseif ($data->payment_status == 'Paid')
<span class="badge badge-success">
{{ $data->payment_status }}
</span>
@else
<span class="badge badge-danger">
{{ $data->payment_status }}
</span>
@endif

View File

@ -0,0 +1,13 @@
@if ($data->status == 'Pending')
<span class="badge badge-info">
{{ $data->status }}
</span>
@elseif ($data->status == 'Shipped')
<span class="badge badge-primary">
{{ $data->status }}
</span>
@else
<span class="badge badge-success">
{{ $data->status }}
</span>
@endif

View File

@ -0,0 +1,114 @@
@extends('layouts.app')
@section('title', 'Create Payment')
@section('breadcrumb')
<ol class="breadcrumb border-0 m-0">
<li class="breadcrumb-item"><a href="{{ route('home') }}">Home</a></li>
<li class="breadcrumb-item"><a href="{{ route('sale-returns.index') }}">Sale Returns</a></li>
<li class="breadcrumb-item"><a href="{{ route('sale-returns.show', $sale_return) }}">{{ $sale_return->reference }}</a></li>
<li class="breadcrumb-item active">Add Payment</li>
</ol>
@endsection
@section('content')
<div class="container-fluid">
<form id="payment-form" action="{{ route('sale-return-payments.store') }}" method="POST">
@csrf
<div class="row">
<div class="col-lg-12">
@include('utils.alerts')
<div class="form-group">
<button class="btn btn-primary">Create Payment <i class="bi bi-check"></i></button>
</div>
</div>
<div class="col-lg-12">
<div class="card">
<div class="card-body">
<div class="form-row">
<div class="col-lg-6">
<div class="form-group">
<label for="reference">Reference <span class="text-danger">*</span></label>
<input type="text" class="form-control" name="reference" required readonly value="INV/{{ $sale_return->reference }}">
</div>
</div>
<div class="col-lg-6">
<div class="form-group">
<label for="date">Date <span class="text-danger">*</span></label>
<input type="date" class="form-control" name="date" required value="{{ now()->format('Y-m-d') }}">
</div>
</div>
</div>
<div class="form-row">
<div class="col-lg-4">
<div class="form-group">
<label for="due_amount">Due Amount <span class="text-danger">*</span></label>
<input type="text" class="form-control" name="due_amount" required value="{{ format_currency($sale_return->due_amount) }}" readonly>
</div>
</div>
<div class="col-lg-4">
<div class="form-group">
<label for="amount">Amount <span class="text-danger">*</span></label>
<div class="input-group">
<input id="amount" type="text" class="form-control" name="amount" required value="{{ old('amount') }}">
<div class="input-group-append">
<button id="getTotalAmount" class="btn btn-primary" type="button">
<i class="bi bi-check-square"></i>
</button>
</div>
</div>
</div>
</div>
<div class="col-lg-4">
<div class="from-group">
<div class="form-group">
<label for="payment_method">Payment Method <span class="text-danger">*</span></label>
<select class="form-control" name="payment_method" id="payment_method" required>
<option value="Cash">Cash</option>
<option value="Credit Card">Credit Card</option>
<option value="Bank Transfer">Bank Transfer</option>
<option value="Cheque">Cheque</option>
<option value="Other">Other</option>
</select>
</div>
</div>
</div>
</div>
<div class="form-group">
<label for="note">Note</label>
<textarea class="form-control" rows="4" name="note">{{ old('note') }}</textarea>
</div>
<input type="hidden" value="{{ $sale_return->id }}" name="sale_return_id">
</div>
</div>
</div>
</div>
</form>
</div>
@endsection
@push('page_scripts')
<script src="{{ asset('js/jquery-mask-money.js') }}"></script>
<script>
$(document).ready(function () {
$('#amount').maskMoney({
prefix:'{{ settings()->currency->symbol }}',
thousands:'{{ settings()->currency->thousand_separator }}',
decimal:'{{ settings()->currency->decimal_separator }}',
});
$('#getTotalAmount').click(function () {
$('#amount').maskMoney('mask', {{ $sale_return->due_amount }});
});
$('#payment-form').submit(function () {
var amount = $('#amount').maskMoney('unmasked')[0];
$('#amount').val(amount);
});
});
</script>
@endpush

View File

@ -0,0 +1,117 @@
@extends('layouts.app')
@section('title', 'Edit Payment')
@section('breadcrumb')
<ol class="breadcrumb border-0 m-0">
<li class="breadcrumb-item"><a href="{{ route('home') }}">Home</a></li>
<li class="breadcrumb-item"><a href="{{ route('sale-returns.index') }}">Sale Returns</a></li>
<li class="breadcrumb-item"><a href="{{ route('sale-returns.show', $sale_return) }}">{{ $sale_return->reference }}</a></li>
<li class="breadcrumb-item active">Edit Payment</li>
</ol>
@endsection
@section('content')
<div class="container-fluid">
<form id="payment-form" action="{{ route('sale-return-payments.update', $saleReturnPayment) }}" method="POST">
@csrf
@method('patch')
<div class="row">
<div class="col-lg-12">
@include('utils.alerts')
<div class="form-group">
<button class="btn btn-primary">Update Payment <i class="bi bi-check"></i></button>
</div>
</div>
<div class="col-lg-12">
<div class="card">
<div class="card-body">
<div class="form-row">
<div class="col-lg-6">
<div class="form-group">
<label for="reference">Reference <span class="text-danger">*</span></label>
<input type="text" class="form-control" name="reference" required readonly value="{{ $saleReturnPayment->reference }}">
</div>
</div>
<div class="col-lg-6">
<div class="form-group">
<label for="date">Date <span class="text-danger">*</span></label>
<input type="date" class="form-control" name="date" required value="{{ $saleReturnPayment->getAttributes()['date'] }}">
</div>
</div>
</div>
<div class="form-row">
<div class="col-lg-4">
<div class="form-group">
<label for="due_amount">Due Amount <span class="text-danger">*</span></label>
<input type="text" class="form-control" name="due_amount" required value="{{ format_currency($sale_return->due_amount) }}" readonly>
</div>
</div>
<div class="col-lg-4">
<div class="form-group">
<label for="amount">Amount <span class="text-danger">*</span></label>
<div class="input-group">
<input id="amount" type="text" class="form-control" name="amount" required value="{{ old('amount') ?? $saleReturnPayment->amount }}">
<div class="input-group-append">
<button id="getTotalAmount" class="btn btn-primary" type="button">
<i class="bi bi-check-square"></i>
</button>
</div>
</div>
</div>
</div>
<div class="col-lg-4">
<div class="from-group">
<div class="form-group">
<label for="payment_method">Payment Method <span class="text-danger">*</span></label>
<select class="form-control" name="payment_method" id="payment_method" required>
<option {{ $saleReturnPayment->payment_method == 'Cash' ? 'selected' : '' }} value="Cash">Cash</option>
<option {{ $saleReturnPayment->payment_method == 'Credit Card' ? 'selected' : '' }} value="Credit Card">Credit Card</option>
<option {{ $saleReturnPayment->payment_method == 'Bank Transfer' ? 'selected' : '' }} value="Bank Transfer">Bank Transfer</option>
<option {{ $saleReturnPayment->payment_method == 'Cheque' ? 'selected' : '' }} value="Cheque">Cheque</option>
<option {{ $saleReturnPayment->payment_method == 'Other' ? 'selected' : '' }} value="Other">Other</option>
</select>
</div>
</div>
</div>
</div>
<div class="form-group">
<label for="note">Note</label>
<textarea class="form-control" rows="4" name="note">{{ old('note') ?? $saleReturnPayment->note }}</textarea>
</div>
<input type="hidden" value="{{ $sale_return->id }}" name="sale_return_id">
</div>
</div>
</div>
</div>
</form>
</div>
@endsection
@push('page_scripts')
<script src="{{ asset('js/jquery-mask-money.js') }}"></script>
<script>
$(document).ready(function () {
$('#amount').maskMoney({
prefix:'{{ settings()->currency->symbol }}',
thousands:'{{ settings()->currency->thousand_separator }}',
decimal:'{{ settings()->currency->decimal_separator }}',
});
$('#amount').maskMoney('mask');
$('#getTotalAmount').click(function () {
$('#amount').maskMoney('mask', {{ $sale_return->due_amount }});
});
$('#payment-form').submit(function () {
var amount = $('#amount').maskMoney('unmasked')[0];
$('#amount').val(amount);
});
});
</script>
@endpush

View File

@ -0,0 +1,37 @@
@extends('layouts.app')
@section('title', 'Sale Payments')
@section('third_party_stylesheets')
<link rel="stylesheet" href="https://cdn.datatables.net/1.10.25/css/dataTables.bootstrap4.min.css">
@endsection
@section('breadcrumb')
<ol class="breadcrumb border-0 m-0">
<li class="breadcrumb-item"><a href="{{ route('home') }}">Home</a></li>
<li class="breadcrumb-item"><a href="{{ route('sale-returns.index') }}">Sale Returns</a></li>
<li class="breadcrumb-item"><a href="{{ route('sales.show', $sale_return) }}">{{ $sale_return->reference }}</a></li>
<li class="breadcrumb-item active">Payments</li>
</ol>
@endsection
@section('content')
<div class="container-fluid">
<div class="row">
<div class="col-12">
@include('utils.alerts')
<div class="card">
<div class="card-body">
<div class="table-responsive">
{!! $dataTable->table() !!}
</div>
</div>
</div>
</div>
</div>
</div>
@endsection
@push('page_scripts')
{!! $dataTable->scripts() !!}
@endpush

View File

@ -0,0 +1,19 @@
@can('access_sale_return_payments')
<a href="{{ route('sale-return-payments.edit', [$data->saleReturn->id, $data->id]) }}" class="btn btn-info btn-sm">
<i class="bi bi-pencil"></i>
</a>
@endcan
@can('access_sale_return_payments')
<button id="delete" class="btn btn-danger btn-sm" onclick="
event.preventDefault();
if (confirm('Are you sure? It will delete the data permanently!')) {
document.getElementById('destroy{{ $data->id }}').submit()
}
">
<i class="bi bi-trash"></i>
<form id="destroy{{ $data->id }}" class="d-none" action="{{ route('sale-return-payments.destroy', $data->id) }}" method="POST">
@csrf
@method('delete')
</form>
</button>
@endcan

View File

@ -0,0 +1,138 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Sale Return Details</title>
<link rel="stylesheet" href="{{ public_path('b3/bootstrap.min.css') }}">
</head>
<body>
<div class="container-fluid">
<div class="row">
<div class="col-xs-12">
<div style="text-align: center;margin-bottom: 25px;">
<img width="180" src="{{ public_path('images/logo-dark.png') }}" alt="Logo">
<h4 style="margin-bottom: 20px;">
<span>Reference::</span> <strong>{{ $sale_return->reference }}</strong>
</h4>
</div>
<div class="card">
<div class="card-body">
<div class="row mb-4">
<div class="col-xs-4 mb-3 mb-md-0">
<h4 class="mb-2" style="border-bottom: 1px solid #dddddd;padding-bottom: 10px;">Company Info:</h4>
<div><strong>{{ settings()->company_name }}</strong></div>
<div>{{ settings()->company_address }}</div>
<div>Email: {{ settings()->company_email }}</div>
<div>Phone: {{ settings()->company_phone }}</div>
</div>
<div class="col-xs-4 mb-3 mb-md-0">
<h4 class="mb-2" style="border-bottom: 1px solid #dddddd;padding-bottom: 10px;">Customer Info:</h4>
<div><strong>{{ $customer->customer_name }}</strong></div>
<div>{{ $customer->address }}</div>
<div>Email: {{ $customer->customer_email }}</div>
<div>Phone: {{ $customer->customer_phone }}</div>
</div>
<div class="col-xs-4 mb-3 mb-md-0">
<h4 class="mb-2" style="border-bottom: 1px solid #dddddd;padding-bottom: 10px;">Invoice Info:</h4>
<div>Invoice: <strong>INV/{{ $sale_return->reference }}</strong></div>
<div>Date: {{ \Carbon\Carbon::parse($sale_return->date)->format('d M, Y') }}</div>
<div>
Status: <strong>{{ $sale_return->status }}</strong>
</div>
<div>
Payment Status: <strong>{{ $sale_return->payment_status }}</strong>
</div>
</div>
</div>
<div class="table-responsive-sm" style="margin-top: 30px;">
<table class="table table-striped">
<thead>
<tr>
<th class="align-middle">Product</th>
<th class="align-middle">Net Unit Price</th>
<th class="align-middle">Stock</th>
<th class="align-middle">Quantity</th>
<th class="align-middle">Discount</th>
<th class="align-middle">Tax</th>
<th class="align-middle">Sub Total</th>
</tr>
</thead>
<tbody>
@foreach($sale_return->saleReturnDetails as $item)
<tr>
<td class="align-middle">
{{ $item->product_name }} <br>
<span class="badge badge-success">
{{ $item->product_code }}
</span>
</td>
<td class="align-middle">{{ format_currency($item->unit_price) }}</td>
<td class="align-middle">
<span class="badge badge-info">{{ $item->product->product_quantity }}</span>
</td>
<td class="align-middle">
{{ $item->quantity }}
</td>
<td class="align-middle">
{{ format_currency($item->product_discount_amount) }}
</td>
<td class="align-middle">
{{ format_currency($item->product_tax_amount) }}
</td>
<td class="align-middle">
{{ format_currency($item->sub_total) }}
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
<div class="row">
<div class="col-xs-4 col-xs-offset-8">
<table class="table">
<tbody>
<tr>
<td class="left"><strong>Discount ({{ $sale_return->discount_percentage }}%)</strong></td>
<td class="right">{{ format_currency($sale_return->discount_amount) }}</td>
</tr>
<tr>
<td class="left"><strong>Tax ({{ $sale_return->tax_percentage }}%)</strong></td>
<td class="right">{{ format_currency($sale_return->tax_amount) }}</td>
</tr>
<tr>
<td class="left"><strong>Shipping)</strong></td>
<td class="right">{{ format_currency($sale_return->shipping_amount) }}</td>
</tr>
<tr>
<td class="left"><strong>Grand Total</strong></td>
<td class="right"><strong>{{ format_currency($sale_return->total_amount) }}</strong></td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="row" style="margin-top: 25px;">
<div class="col-xs-12">
<p style="font-style: italic;text-align: center">Computer generated invoice. {{ settings()->company_name }} &copy; {{ date('Y') }}.</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,140 @@
@extends('layouts.app')
@section('title', 'Sales Details')
@section('breadcrumb')
<ol class="breadcrumb border-0 m-0">
<li class="breadcrumb-item"><a href="{{ route('home') }}">Home</a></li>
<li class="breadcrumb-item"><a href="{{ route('sale-returns.index') }}">Sale Returns</a></li>
<li class="breadcrumb-item active">Details</li>
</ol>
@endsection
@section('content')
<div class="container-fluid">
<div class="row">
<div class="col-lg-12">
<div class="card">
<div class="card-header d-flex flex-wrap align-items-center">
<div>
Reference: <strong>{{ $sale_return->reference }}</strong>
</div>
<a target="_blank" class="btn btn-sm btn-secondary mfs-auto mfe-1 d-print-none" href="{{ route('sale-returns.pdf', $sale_return->id) }}">
<i class="bi bi-printer"></i> Print
</a>
<a target="_blank" class="btn btn-sm btn-info mfe-1 d-print-none" href="{{ route('sale-returns.pdf', $sale_return->id) }}">
<i class="bi bi-save"></i> Save
</a>
</div>
<div class="card-body">
<div class="row mb-4">
<div class="col-sm-4 mb-3 mb-md-0">
<h5 class="mb-2 border-bottom pb-2">Company Info:</h5>
<div><strong>{{ settings()->company_name }}</strong></div>
<div>{{ settings()->company_address }}</div>
<div>Email: {{ settings()->company_email }}</div>
<div>Phone: {{ settings()->company_phone }}</div>
</div>
<div class="col-sm-4 mb-3 mb-md-0">
<h5 class="mb-2 border-bottom pb-2">Customer Info:</h5>
<div><strong>{{ $customer->customer_name }}</strong></div>
<div>{{ $customer->address }}</div>
<div>Email: {{ $customer->customer_email }}</div>
<div>Phone: {{ $customer->customer_phone }}</div>
</div>
<div class="col-sm-4 mb-3 mb-md-0">
<h5 class="mb-2 border-bottom pb-2">Invoice Info:</h5>
<div>Invoice: <strong>INV/{{ $sale_return->reference }}</strong></div>
<div>Date: {{ \Carbon\Carbon::parse($sale_return->date)->format('d M, Y') }}</div>
<div>
Status: <strong>{{ $sale_return->status }}</strong>
</div>
<div>
Payment Status: <strong>{{ $sale_return->payment_status }}</strong>
</div>
</div>
</div>
<div class="table-responsive-sm">
<table class="table table-striped">
<thead>
<tr>
<th class="align-middle">Product</th>
<th class="align-middle">Net Unit Price</th>
<th class="align-middle">Stock</th>
<th class="align-middle">Quantity</th>
<th class="align-middle">Discount</th>
<th class="align-middle">Tax</th>
<th class="align-middle">Sub Total</th>
</tr>
</thead>
<tbody>
@foreach($sale_return->saleReturnDetails as $item)
<tr>
<td class="align-middle">
{{ $item->product_name }} <br>
<span class="badge badge-success">
{{ $item->product_code }}
</span>
</td>
<td class="align-middle">{{ format_currency($item->unit_price) }}</td>
<td class="align-middle">
<span class="badge badge-info">{{ $item->product->product_quantity }}</span>
</td>
<td class="align-middle">
{{ $item->quantity }}
</td>
<td class="align-middle">
{{ format_currency($item->product_discount_amount) }}
</td>
<td class="align-middle">
{{ format_currency($item->product_tax_amount) }}
</td>
<td class="align-middle">
{{ format_currency($item->sub_total) }}
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
<div class="row">
<div class="col-lg-4 col-sm-5 ml-md-auto">
<table class="table">
<tbody>
<tr>
<td class="left"><strong>Discount ({{ $sale_return->discount_percentage }}%)</strong></td>
<td class="right">{{ format_currency($sale_return->discount_amount) }}</td>
</tr>
<tr>
<td class="left"><strong>Tax ({{ $sale_return->tax_percentage }}%)</strong></td>
<td class="right">{{ format_currency($sale_return->tax_amount) }}</td>
</tr>
<tr>
<td class="left"><strong>Shipping)</strong></td>
<td class="right">{{ format_currency($sale_return->shipping_amount) }}</td>
</tr>
<tr>
<td class="left"><strong>Grand Total</strong></td>
<td class="right"><strong>{{ format_currency($sale_return->total_amount) }}</strong></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
@endsection

View File

View File

@ -0,0 +1,18 @@
<?php
use Illuminate\Http\Request;
/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/
Route::middleware('auth:api')->get('/salesreturn', function (Request $request) {
return $request->user();
});

View File

@ -0,0 +1,44 @@
<?php
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::group(['middleware' => 'auth'], function () {
//Generate PDF
Route::get('/sale-returns/pdf/{id}', function ($id) {
$saleReturn = \Modules\SalesReturn\Entities\SaleReturn::findOrFail($id);
$customer = \Modules\People\Entities\Customer::findOrFail($saleReturn->customer_id);
$pdf = \PDF::loadView('salesreturn::print', [
'sale_return' => $saleReturn,
'customer' => $customer,
])->setPaper('a4');
return $pdf->stream('sale-return-'. $saleReturn->reference .'.pdf');
})->name('sale-returns.pdf');
//Sale Returns
Route::resource('sale-returns', 'SalesReturnController');
//Payments
Route::get('/sale-return-payments/{sale_return_id}', 'SaleReturnPaymentsController@index')
->name('sale-return-payments.index');
Route::get('/sale-return-payments/{sale_return_id}/create', 'SaleReturnPaymentsController@create')
->name('sale-return-payments.create');
Route::post('/sale-return-payments/store', 'SaleReturnPaymentsController@store')
->name('sale-return-payments.store');
Route::get('/sale-return-payments/{sale_return_id}/edit/{saleReturnPayment}', 'SaleReturnPaymentsController@edit')
->name('sale-return-payments.edit');
Route::patch('/sale-return-payments/update/{saleReturnPayment}', 'SaleReturnPaymentsController@update')
->name('sale-return-payments.update');
Route::delete('/sale-return-payments/destroy/{saleReturnPayment}', 'SaleReturnPaymentsController@destroy')
->name('sale-return-payments.destroy');
});

View File

View File

@ -0,0 +1,23 @@
{
"name": "nwidart/salesreturn",
"description": "",
"authors": [
{
"name": "Nicolas Widart",
"email": "n.widart@gmail.com"
}
],
"extra": {
"laravel": {
"providers": [],
"aliases": {
}
}
},
"autoload": {
"psr-4": {
"Modules\\SalesReturn\\": ""
}
}
}

View File

@ -0,0 +1,13 @@
{
"name": "SalesReturn",
"alias": "salesreturn",
"description": "",
"keywords": [],
"priority": 0,
"providers": [
"Modules\\SalesReturn\\Providers\\SalesReturnServiceProvider"
],
"aliases": {},
"files": [],
"requires": []
}

View File

@ -0,0 +1,17 @@
{
"private": true,
"scripts": {
"dev": "npm run development",
"development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
"watch": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
"watch-poll": "npm run watch -- --watch-poll",
"hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
"prod": "npm run production",
"production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
},
"devDependencies": {
"cross-env": "^7.0",
"laravel-mix": "^5.0.1",
"laravel-mix-merge-manifest": "^0.1.2"
}
}

14
Modules/SalesReturn/webpack.mix.js vendored Normal file
View File

@ -0,0 +1,14 @@
const dotenvExpand = require('dotenv-expand');
dotenvExpand(require('dotenv').config({ path: '../../.env'/*, debug: true*/}));
const mix = require('laravel-mix');
require('laravel-mix-merge-manifest');
mix.setPublicPath('../../public').mergeManifest();
mix.js(__dirname + '/Resources/assets/js/app.js', 'js/salesreturn.js')
.sass( __dirname + '/Resources/assets/sass/app.scss', 'css/salesreturn.css');
if (mix.inProduction()) {
mix.version();
}

View File

@ -60,6 +60,14 @@ class PermissionsTableSeeder extends Seeder
'delete_sales',
//Sale Payments
'access_sale_payments',
//Purchases
'access_purchases',
'create_purchases',
'show_purchases',
'edit_purchases',
'delete_purchases',
//Purchase Payments
'access_purchase_payments',
//Currencies
'access_currencies',
'create_currencies',

View File

@ -48,11 +48,6 @@ class SalePaymentsDataTable extends DataTable
);
}
/**
* Get columns.
*
* @return array
*/
protected function getColumns() {
return [
Column::make('date')

View File

@ -0,0 +1,78 @@
<?php
namespace App\DataTables;
use Modules\SalesReturn\Entities\SaleReturnPayment;
use Yajra\DataTables\Html\Button;
use Yajra\DataTables\Html\Column;
use Yajra\DataTables\Html\Editor\Editor;
use Yajra\DataTables\Html\Editor\Fields;
use Yajra\DataTables\Services\DataTable;
class SaleReturnPaymentsDataTable extends DataTable
{
public function dataTable($query) {
return datatables()
->eloquent($query)
->addColumn('amount', function ($data) {
return format_currency($data->amount);
})
->addColumn('action', function ($data) {
return view('salesreturn::payments.partials.actions', compact('data'));
});
}
public function query(SaleReturnPayment $model) {
return $model->newQuery()->bySaleReturn()->with('saleReturn');
}
public function html() {
return $this->builder()
->setTableId('sale-payments-table')
->columns($this->getColumns())
->minifiedAjax()
->dom("<'row'<'col-md-3'l><'col-md-5 mb-2'B><'col-md-4'f>> .
'tr' .
<'row'<'col-md-5'i><'col-md-7 mt-2'p>>")
->orderBy(5)
->buttons(
Button::make('excel')
->text('<i class="bi bi-file-earmark-excel-fill"></i> Excel'),
Button::make('print')
->text('<i class="bi bi-printer-fill"></i> Print'),
Button::make('reset')
->text('<i class="bi bi-x-circle"></i> Reset'),
Button::make('reload')
->text('<i class="bi bi-arrow-repeat"></i> Reload')
);
}
protected function getColumns() {
return [
Column::make('date')
->className('align-middle text-center'),
Column::make('reference')
->className('align-middle text-center'),
Column::computed('amount')
->className('align-middle text-center'),
Column::make('payment_method')
->className('align-middle text-center'),
Column::computed('action')
->exportable(false)
->printable(false)
->className('align-middle text-center'),
Column::make('created_at')
->visible(false),
];
}
protected function filename()
{
return 'SaleReturnPayments_' . date('YmdHis');
}
}

View File

@ -0,0 +1,100 @@
<?php
namespace App\DataTables;
use Modules\SalesReturn\Entities\SaleReturn;
use Yajra\DataTables\Html\Button;
use Yajra\DataTables\Html\Column;
use Yajra\DataTables\Html\Editor\Editor;
use Yajra\DataTables\Html\Editor\Fields;
use Yajra\DataTables\Services\DataTable;
class SaleReturnsDataTable extends DataTable
{
public function dataTable($query) {
return datatables()
->eloquent($query)
->addColumn('total_amount', function ($data) {
return format_currency($data->total_amount);
})
->addColumn('paid_amount', function ($data) {
return format_currency($data->paid_amount);
})
->addColumn('due_amount', function ($data) {
return format_currency($data->due_amount);
})
->addColumn('status', function ($data) {
return view('salesreturn::partials.status', compact('data'));
})
->addColumn('payment_status', function ($data) {
return view('salesreturn::partials.payment-status', compact('data'));
})
->addColumn('action', function ($data) {
return view('salesreturn::partials.actions', compact('data'));
});
}
public function query(SaleReturn $model) {
return $model->newQuery();
}
public function html() {
return $this->builder()
->setTableId('sale-returns-table')
->columns($this->getColumns())
->minifiedAjax()
->dom("<'row'<'col-md-3'l><'col-md-5 mb-2'B><'col-md-4'f>> .
'tr' .
<'row'<'col-md-5'i><'col-md-7 mt-2'p>>")
->orderBy(8)
->buttons(
Button::make('excel')
->text('<i class="bi bi-file-earmark-excel-fill"></i> Excel'),
Button::make('print')
->text('<i class="bi bi-printer-fill"></i> Print'),
Button::make('reset')
->text('<i class="bi bi-x-circle"></i> Reset'),
Button::make('reload')
->text('<i class="bi bi-arrow-repeat"></i> Reload')
);
}
protected function getColumns() {
return [
Column::make('reference')
->className('text-center align-middle'),
Column::make('customer_name')
->title('Customer')
->className('text-center align-middle'),
Column::computed('status')
->className('text-center align-middle'),
Column::computed('total_amount')
->className('text-center align-middle'),
Column::computed('paid_amount')
->className('text-center align-middle'),
Column::computed('due_amount')
->className('text-center align-middle'),
Column::computed('payment_status')
->className('text-center align-middle'),
Column::computed('action')
->exportable(false)
->printable(false)
->className('text-center align-middle'),
Column::make('created_at')
->visible(false)
];
}
protected function filename()
{
return 'SaleReturns_' . date('YmdHis');
}
}

View File

@ -8,5 +8,7 @@
"Currency": true,
"Setting": true,
"Sale": true,
"Purchase": true
"Purchase": true,
"SaleReturn": true,
"SalesReturn": true
}

View File

@ -110,6 +110,30 @@
</li>
@endcan
@can('access_sale_returns')
<li class="c-sidebar-nav-item c-sidebar-nav-dropdown {{ request()->routeIs('sale-returns*') || request()->routeIs('sale-return-payments*') ? 'c-show' : '' }}">
<a class="c-sidebar-nav-link c-sidebar-nav-dropdown-toggle" href="#">
<i class="c-sidebar-nav-icon bi bi-arrow-return-left" style="line-height: 1;"></i> Sale Returns
</a>
@can('create_sale_returns')
<ul class="c-sidebar-nav-dropdown-items">
<li class="c-sidebar-nav-item">
<a class="c-sidebar-nav-link {{ request()->routeIs('sale-returns.create') ? 'c-active' : '' }}" href="{{ route('sale-returns.create') }}">
<i class="c-sidebar-nav-icon bi bi-journal-plus" style="line-height: 1;"></i> Create Sale Return
</a>
</li>
</ul>
@endcan
<ul class="c-sidebar-nav-dropdown-items">
<li class="c-sidebar-nav-item">
<a class="c-sidebar-nav-link {{ request()->routeIs('sale-returns.index') ? 'c-active' : '' }}" href="{{ route('sale-returns.index') }}">
<i class="c-sidebar-nav-icon bi bi-journals" style="line-height: 1;"></i> All Sale Returns
</a>
</li>
</ul>
</li>
@endcan
@can('access_expenses')
<li class="c-sidebar-nav-item c-sidebar-nav-dropdown {{ request()->routeIs('expenses.*') || request()->routeIs('expense-categories.*') ? 'c-show' : '' }}">
<a class="c-sidebar-nav-link c-sidebar-nav-dropdown-toggle" href="#">