feat: profile_photo en contratos activos, notificaciones bilingues en reportes y foto en panel usuarios

- API contratos activos (cliente y proveedor): agrega campo profile_photo (técnico asignado o supplier, null si no tiene)
- Notificaciones push bilingues en comentarios de reporte: "Nueva actividad en tu reporte" / "New activity on your report"
- Moderador en web panel notifica a cliente y proveedor al comentar, con prefijo Moderador/Moderator
- Panel usuarios: columna de foto de perfil entre ID y Nombre

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-23 17:17:14 -06:00
parent 38da1b56ce
commit 0ed98c96ee
40 changed files with 1390 additions and 651 deletions

View File

@@ -20,7 +20,7 @@ class CreateUsersTable extends Migration
$table->string('profile_photo')->nullable();
$table->BigInteger('role_id')->unsigned()->nullable();
$table->string('social_id')->unique()->nullable();
$table->string('openpay_id')->unique()->nullable();
$table->string('stripe_customer_id')->unique()->nullable();
$table->string('phone')->unique()->nullable();
$table->timestamp('phone_verified_at')->nullable();
$table->string('password')->nullable();

View File

@@ -16,7 +16,11 @@ class CreateCardsTable extends Migration
Schema::create('cards', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('user_id');
$table->string('token');
$table->string('stripe_pm_id')->unique();
$table->string('brand');
$table->string('last4', 4);
$table->unsignedTinyInteger('exp_month');
$table->unsignedSmallInteger('exp_year');
$table->timestamps();
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
});

View File

@@ -36,7 +36,9 @@ class CreateFinishedcontractsTable extends Migration
$table->unsignedBigInteger('parent_contract_id')->nullable();
$table->Integer('score')->nullable();
$table->timestamp('scored_at')->nullable();
$table->unsignedBigInteger('technical_id')->nullable();
$table->boolean('paid')->default(false);
$table->timestamp('paid_at')->nullable();
$table->timestamps();
$table->foreign('user_id')->references('id')->on('users')->onDelete('set null');
$table->foreign('supplier_id')->references('id')->on('suppliers')->onDelete('set null');

View File

@@ -34,6 +34,7 @@ class CreateCurrentContractsTable extends Migration
$table->unsignedBigInteger('status_id')->nullable()->default('1');
$table->BigInteger('code')->nullable();
$table->unsignedBigInteger('parent_contract_id')->nullable();
$table->unsignedBigInteger('technical_id')->nullable();
$table->timestamps();
$table->foreign('user_id')->references('id')->on('users')->onDelete('set null');
$table->foreign('supplier_id')->references('id')->on('suppliers')->onDelete('set null');

View File

@@ -0,0 +1,27 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreatePaymentBatchesTable extends Migration
{
public function up()
{
Schema::create('payment_batches', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('file_name');
$table->string('file_path');
$table->unsignedBigInteger('generated_by')->nullable();
$table->date('date_from')->nullable();
$table->date('date_to')->nullable();
$table->timestamps();
$table->foreign('generated_by')->references('id')->on('users')->onDelete('set null');
});
}
public function down()
{
Schema::dropIfExists('payment_batches');
}
}

View File

@@ -0,0 +1,42 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateTechniciansTable extends Migration
{
public function up()
{
Schema::create('technicians', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('user_id');
$table->unsignedBigInteger('supplier_id');
$table->timestamps();
$table->unique(['user_id', 'supplier_id']);
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->foreign('supplier_id')->references('id')->on('suppliers')->onDelete('cascade');
});
Schema::table('finished_contracts', function (Blueprint $table) {
$table->foreign('technical_id')->references('id')->on('technicians')->onDelete('set null');
});
Schema::table('current_contracts', function (Blueprint $table) {
$table->foreign('technical_id')->references('id')->on('technicians')->onDelete('set null');
});
}
public function down()
{
Schema::table('finished_contracts', function (Blueprint $table) {
$table->dropForeign(['technical_id']);
});
Schema::table('current_contracts', function (Blueprint $table) {
$table->dropForeign(['technical_id']);
});
Schema::dropIfExists('technicians');
}
}

View File

@@ -0,0 +1,27 @@
<?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::dropIfExists('cards');
}
public function down(): void
{
Schema::create('cards', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('user_id');
$table->string('stripe_pm_id')->nullable();
$table->string('brand')->nullable();
$table->string('last4')->nullable();
$table->unsignedTinyInteger('exp_month')->nullable();
$table->unsignedSmallInteger('exp_year')->nullable();
$table->timestamps();
});
}
};

View File

@@ -44,6 +44,10 @@ class DatabaseSeeder extends Seeder
'name' => 'SuperAdmin',
]);
DB::table('roles')->insert([
'name' => 'Técnico',
]);
DB::table('users')->insert([
'name' => 'Admin',
'email' => 'torch2196@gmail.com',
@@ -102,6 +106,10 @@ class DatabaseSeeder extends Seeder
'en_name' => 'canceled',
]);
DB::table('statuses')->insert([
'name' => 'ausente',
'en_name' => 'absent',
]);
DB::table('statuses')->insert([
'name' => 'fuera de casa',
'en_name' => 'no home',
]);
@@ -110,9 +118,14 @@ class DatabaseSeeder extends Seeder
'en_name' => 'reported',
]);
DB::table('statuses')->insert([
'name' => 'ausente',
'en_name' => 'absent',
'name' => 'devuelto al cliente',
'en_name' => 'returned to client',
]);
DB::table('statuses')->insert([
'name' => 'disptuta terminada',
'en_name' => 'complain ended',
]);
$this->call([
BanksSeeder::class,