WIP #1
@ -5,6 +5,7 @@
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\CashClose;
|
||||
use App\Models\Sale;
|
||||
use App\Models\SaleItem;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Notsoweb\ApiResponse\Enums\ApiResponse;
|
||||
@ -35,28 +36,59 @@ public function index(Request $request)
|
||||
]);
|
||||
}
|
||||
|
||||
public function closeCashClose($id)
|
||||
public function closeCashClose(Request $request)
|
||||
{
|
||||
$today = now()->format('Y-m-d');
|
||||
$request ->validate([
|
||||
'exit' => 'sometimes|numeric|min:0',
|
||||
]);
|
||||
|
||||
$cashClose = CashClose::findOrFail($id);
|
||||
$cashClose = CashClose::open()->first();
|
||||
|
||||
$totalSales = Sale::where('cash_close_id', $id)->sum('total_amount');
|
||||
$paymentMethods = Sale::where('cash_close_id', $id)
|
||||
if(!$cashClose) {
|
||||
return ApiResponse::NOT_FOUND->response([
|
||||
'message' => 'No hay un corte de caja abierto para cerrar.',
|
||||
]);
|
||||
}
|
||||
|
||||
$totalSales = Sale::where('cash_close_id', $cashClose->id)->sum('total_amount');
|
||||
|
||||
$paymentMethods = Sale::where('cash_close_id', $cashClose->id)
|
||||
->select('payment_method', DB::raw('SUM(total_amount) as total'))
|
||||
->groupBy('payment_method')
|
||||
->get();
|
||||
->pluck('total', 'payment_method');
|
||||
|
||||
$exit = $request->input('exit', 0);
|
||||
|
||||
$cashClose->update([
|
||||
'closed_at' => now(),
|
||||
'income' => $totalSales,
|
||||
'balance' => $totalSales - $cashClose->exit,
|
||||
'exit' => $exit,
|
||||
'income_cash' => $paymentMethods->get('cash', 0),
|
||||
'income_card' => $paymentMethods->get('card', 0),
|
||||
'income_transfer' => $paymentMethods->get('transfer', 0),
|
||||
'status' => 'closed',
|
||||
'close_date' => $today,
|
||||
]);
|
||||
|
||||
$balanceFinal = $cashClose->initial_balance + $totalSales - $exit;
|
||||
|
||||
return ApiResponse::OK->response([
|
||||
'message' => 'Corte de caja cerrado exitosamente.',
|
||||
'data' => $cashClose,
|
||||
'cash_close' => $cashClose->fresh('user'),
|
||||
'resumen' => [
|
||||
'periodo' => [
|
||||
'apertura' => $cashClose->opened_at,
|
||||
'cierre' => $cashClose->closed_at,
|
||||
],
|
||||
'totales' => [
|
||||
'fondo_inicial' => $cashClose->initial_balance,
|
||||
'total_ventas' => $totalSales,
|
||||
'efectivo' => $paymentMethods->get('cash', 0),
|
||||
'tarjeta' => $paymentMethods->get('card', 0),
|
||||
'transferencia' => $paymentMethods->get('transfer', 0),
|
||||
'egresos' => $exit,
|
||||
'balance_final' => $balanceFinal,
|
||||
],
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@ -21,6 +21,29 @@ public function index()
|
||||
]);
|
||||
}
|
||||
|
||||
public function search(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'filter' => 'required|string|min:2',
|
||||
]);
|
||||
|
||||
$search = $request->input('filter');
|
||||
|
||||
$clients = Client::with('simCards:id,msisdn')
|
||||
->where(function($q) use ($search) {
|
||||
$q->whereRaw("CONCAT(name, ' ', paternal, ' ', maternal) LIKE ?", ["%{$search}%"])
|
||||
->orWhere('rfc', 'like', "%{$search}%")
|
||||
->orWhere('email', 'like', "%{$search}%")
|
||||
->orWhere('phone', 'like', "%{$search}%");
|
||||
})
|
||||
->orderBy('id', 'asc')
|
||||
->paginate(config('app.pagination'));
|
||||
|
||||
return ApiResponse::OK->response([
|
||||
'data' => $clients,
|
||||
]);
|
||||
}
|
||||
|
||||
public function show(Client $client)
|
||||
{
|
||||
$client->load('simCards:id,msisdn');
|
||||
|
||||
@ -1,27 +1,31 @@
|
||||
<?php namespace App\Models;
|
||||
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class CashClose extends Model
|
||||
{
|
||||
protected $fillable = [
|
||||
'balance',
|
||||
'user_id',
|
||||
'opened_at',
|
||||
'closed_at',
|
||||
'initial_balance',
|
||||
'income',
|
||||
'exit',
|
||||
'close_date',
|
||||
'income_cash',
|
||||
'income_card',
|
||||
'income_transfer',
|
||||
'status',
|
||||
'user_id',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'balance' => 'decimal:2',
|
||||
'initial_balance' => 'decimal:2',
|
||||
'income' => 'decimal:2',
|
||||
'exit' => 'decimal:2',
|
||||
'close_date' => 'date',
|
||||
'income_cash' => 'decimal:2',
|
||||
'income_card' => 'decimal:2',
|
||||
'income_transfer' => 'decimal:2',
|
||||
'opened_at' => 'datetime',
|
||||
'closed_at' => 'datetime',
|
||||
];
|
||||
|
||||
/**
|
||||
@ -55,26 +59,4 @@ public function scopeClosed($query)
|
||||
{
|
||||
return $query->where('status', 'closed');
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope para cortes de una fecha específica
|
||||
*/
|
||||
public function scopeByDate($query, $date)
|
||||
{
|
||||
return $query->whereDate('close_date', $date);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calcula automáticamente el balance
|
||||
*/
|
||||
public function calculateBalance()
|
||||
{
|
||||
$this->balance = $this->income - $this->exit;
|
||||
|
||||
if ($this->expected_balance) {
|
||||
$this->difference = $this->balance - $this->expected_balance;
|
||||
}
|
||||
|
||||
return $this->balance;
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,17 +12,19 @@ class CashCloseService
|
||||
*/
|
||||
public static function getOrCreateOpenCashClose()
|
||||
{
|
||||
$today = now()->format('Y-m-d');
|
||||
$cashClose = CashClose::open()->byDate($today)->first();
|
||||
$cashClose = CashClose::open()->first();
|
||||
|
||||
if (!$cashClose) {
|
||||
$cashClose = CashClose::create([
|
||||
'close_date' => $today,
|
||||
'user_id' => Auth::id(),
|
||||
'opened_at' => now(),
|
||||
'initial_balance' => 0,
|
||||
'income' => 0,
|
||||
'exit' => 0,
|
||||
'balance' => 0,
|
||||
'income_cash' => 0,
|
||||
'income_card' => 0,
|
||||
'income_transfer' => 0,
|
||||
'status' => 'open',
|
||||
'user_id' => Auth::id(),
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@ -17,7 +17,7 @@ public function up(): void
|
||||
$table->decimal('balance', 10, 2);
|
||||
$table->decimal('income', 10, 2);
|
||||
$table->decimal('exit', 10, 2)->default(0);
|
||||
$table->enum('status', ['open', 'closed', 'reviewed'])->default('open')->comment('Estado del corte');
|
||||
$table->enum('status', ['open', 'closed'])->default('open')->comment('Estado del corte');
|
||||
$table->timestamp('close_date');
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
@ -0,0 +1,24 @@
|
||||
<?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('clients', function (Blueprint $table) {
|
||||
$table->string('rfc', 13)->unique()->change();
|
||||
$table->string('phone')->unique()->change();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
//
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,55 @@
|
||||
<?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('cash_closes', function (Blueprint $table) {
|
||||
$table->timestamp('opened_at')->nullable()->after('user_id');
|
||||
|
||||
$table->decimal('initial_balance', 10, 2)->default(0)->after('user_id');
|
||||
|
||||
$table->dropColumn('balance');
|
||||
|
||||
$table->decimal('income_cash', 10, 2)->default(0)->after('income');
|
||||
$table->decimal('income_card', 10, 2)->default(0)->after('income_cash');
|
||||
$table->decimal('income_transfer', 10, 2)->default(0)->after('income_card');
|
||||
});
|
||||
|
||||
// Renombrar y hacer nullable en una segunda operación
|
||||
Schema::table('cash_closes', function (Blueprint $table) {
|
||||
$table->renameColumn('close_date', 'closed_at');
|
||||
});
|
||||
|
||||
// Modificar closed_at para que sea nullable
|
||||
Schema::table('cash_closes', function (Blueprint $table) {
|
||||
$table->timestamp('closed_at')->nullable()->change();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('cash_closes', function (Blueprint $table) {
|
||||
$table->timestamp('closed_at')->nullable(false)->change();
|
||||
});
|
||||
|
||||
Schema::table('cash_closes', function (Blueprint $table) {
|
||||
$table->renameColumn('closed_at', 'close_date');
|
||||
});
|
||||
|
||||
Schema::table('cash_closes', function (Blueprint $table) {
|
||||
$table->dropColumn([
|
||||
'opened_at',
|
||||
'initial_balance',
|
||||
'income_cash',
|
||||
'income_card',
|
||||
'income_transfer',
|
||||
]);
|
||||
$table->decimal('balance', 10, 2)->after('user_id');
|
||||
});
|
||||
}
|
||||
};
|
||||
@ -34,6 +34,7 @@ public function run(): void
|
||||
'maternal' => 'Cruz',
|
||||
'email' => 'maria.hernandez@example.com',
|
||||
'phone' => '555-1003',
|
||||
'rfc' => 'MAHC910203XXX',
|
||||
],
|
||||
[
|
||||
'name' => 'Carlos',
|
||||
@ -41,6 +42,7 @@ public function run(): void
|
||||
'maternal' => 'Ruiz',
|
||||
'email' => 'carlos.sanchez@example.com',
|
||||
'phone' => '555-1004',
|
||||
'rfc' => 'CASR910203XXX',
|
||||
],
|
||||
[
|
||||
'name' => 'Laura',
|
||||
@ -48,6 +50,7 @@ public function run(): void
|
||||
'maternal' => 'Flores',
|
||||
'email' => 'laura.gomez@example.com',
|
||||
'phone' => '555-1005',
|
||||
'rfc' => 'LAGF910203XXX',
|
||||
]
|
||||
];
|
||||
|
||||
|
||||
@ -22,5 +22,9 @@ public function run(): void
|
||||
$this->call(RoleSeeder::class);
|
||||
$this->call(UserSeeder::class);
|
||||
$this->call(SettingSeeder::class);
|
||||
|
||||
$this->call(ClientSeeder::class);
|
||||
$this->call(SimCardSeeder::class);
|
||||
$this->call(PackageSeeder::class);
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,9 +19,9 @@ services:
|
||||
mem_limit: 512m
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
# depends_on:
|
||||
# mysql:
|
||||
# condition: service_healthy
|
||||
depends_on:
|
||||
mysql:
|
||||
condition: service_healthy
|
||||
|
||||
nginx:
|
||||
image: nginx:alpine
|
||||
@ -36,37 +36,37 @@ services:
|
||||
depends_on:
|
||||
- netbien-backend
|
||||
|
||||
# mysql:
|
||||
# image: mysql:8.0
|
||||
# environment:
|
||||
# MYSQL_DATABASE: ${DB_DATABASE}
|
||||
# MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
|
||||
# MYSQL_PASSWORD: ${DB_PASSWORD}
|
||||
# MYSQL_USER: ${DB_USERNAME}
|
||||
# ports:
|
||||
# - "${DB_PORT}:3306"
|
||||
# volumes:
|
||||
# - mysql_data:/var/lib/mysql
|
||||
# networks:
|
||||
# - netbien-network
|
||||
# mem_limit: 512m
|
||||
# healthcheck:
|
||||
# test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
|
||||
# timeout: 15s
|
||||
# retries: 10
|
||||
mysql:
|
||||
image: mysql:8.0
|
||||
environment:
|
||||
MYSQL_DATABASE: ${DB_DATABASE}
|
||||
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
|
||||
MYSQL_PASSWORD: ${DB_PASSWORD}
|
||||
MYSQL_USER: ${DB_USERNAME}
|
||||
ports:
|
||||
- "${DB_PORT}:3306"
|
||||
volumes:
|
||||
- mysql_data:/var/lib/mysql
|
||||
networks:
|
||||
- netbien-network
|
||||
mem_limit: 512m
|
||||
healthcheck:
|
||||
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
|
||||
timeout: 15s
|
||||
retries: 10
|
||||
|
||||
# phpmyadmin:
|
||||
# image: phpmyadmin/phpmyadmin
|
||||
# environment:
|
||||
# PMA_HOST: mysql
|
||||
# PMA_PORT: 3306
|
||||
# ports:
|
||||
# - "${PMA_PORT}:80"
|
||||
# depends_on:
|
||||
# - mysql
|
||||
# networks:
|
||||
# - netbien-network
|
||||
# mem_limit: 512m
|
||||
phpmyadmin:
|
||||
image: phpmyadmin/phpmyadmin
|
||||
environment:
|
||||
PMA_HOST: mysql
|
||||
PMA_PORT: 3306
|
||||
ports:
|
||||
- "${PMA_PORT}:80"
|
||||
depends_on:
|
||||
- mysql
|
||||
networks:
|
||||
- netbien-network
|
||||
mem_limit: 512m
|
||||
|
||||
volumes:
|
||||
mysql_data:
|
||||
|
||||
@ -28,12 +28,13 @@
|
||||
|
||||
Route::resource('packages', PackagesController::class);
|
||||
|
||||
Route::get('clients/search', [ClientController::class, 'search']);
|
||||
Route::resource('clients', ClientController::class);
|
||||
|
||||
Route::resource('sales', SaleController::class);
|
||||
|
||||
Route::get('cash-closes', [CashCloseController::class, 'index']);
|
||||
Route::put('cash-closes/{id}/close', [CashCloseController::class, 'CloseCashClose']);
|
||||
Route::put('cash-closes/close', [CashCloseController::class, 'CloseCashClose']);
|
||||
Route::get('cash-closes/{id}/report', [CashCloseController::class, 'report']);
|
||||
});
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user