Modificaciones a usuarios y roles #2

Merged
juan.zapata merged 11 commits from develop into main 2025-11-11 15:42:32 +00:00
11 changed files with 208 additions and 82 deletions
Showing only changes of commit 4d6059a1e9 - Show all commits

View File

@ -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,
],
],
]);
}

View File

@ -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');

View File

@ -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;
}
}

View File

@ -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(),
]);
}

View File

@ -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();
});

View File

@ -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
{
//
}
};

View File

@ -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');
});
}
};

View File

@ -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',
]
];

View File

@ -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);
}
}

View File

@ -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:

View File

@ -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']);
});