FEAT: Mejorar la importación de datos y evitar duplicados en ventas
This commit is contained in:
parent
f070777945
commit
39d1b3aee5
@ -19,6 +19,7 @@
|
|||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use PhpOffice\PhpSpreadsheet\IOFactory;
|
use PhpOffice\PhpSpreadsheet\IOFactory;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
use Notsoweb\ApiResponse\Enums\ApiResponse;
|
use Notsoweb\ApiResponse\Enums\ApiResponse;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -131,15 +132,15 @@ public function import(Request $request)
|
|||||||
$sheet = $spreadsheet->getActiveSheet();
|
$sheet = $spreadsheet->getActiveSheet();
|
||||||
$rows = $sheet->toArray();
|
$rows = $sheet->toArray();
|
||||||
|
|
||||||
DB::beginTransaction();
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Leer encabezados de la primera fila
|
// Leer encabezados de la primera fila
|
||||||
$this->buildColumnMap($rows[0]);
|
$this->buildColumnMap($rows[0]);
|
||||||
|
|
||||||
foreach ($rows as $index => $row) {
|
foreach ($rows as $index => $row) {
|
||||||
if ($index === 0) continue; // Saltar encabezados
|
if ($index === 0) continue; // Saltar encabezados
|
||||||
|
|
||||||
|
// Iniciar transacción por fila
|
||||||
|
DB::beginTransaction();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$this->processRow([
|
$this->processRow([
|
||||||
'iccid' => $this->getColumnValue($row, 'ICCID'),
|
'iccid' => $this->getColumnValue($row, 'ICCID'),
|
||||||
@ -149,30 +150,27 @@ public function import(Request $request)
|
|||||||
'fecha_venta' => $this->getColumnValue($row, 'FECHA_VENTA'),
|
'fecha_venta' => $this->getColumnValue($row, 'FECHA_VENTA'),
|
||||||
'metodo_pago' => $this->getColumnValue($row, 'METODO_PAGO'),
|
'metodo_pago' => $this->getColumnValue($row, 'METODO_PAGO'),
|
||||||
], $index + 1);
|
], $index + 1);
|
||||||
|
|
||||||
|
// Commit después de cada fila exitosa
|
||||||
|
DB::commit();
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
// Capturar información detallada del error antes de revertir
|
// Revertir solo esta fila
|
||||||
DB::rollBack();
|
DB::rollBack();
|
||||||
|
|
||||||
return ApiResponse::BAD_REQUEST->response([
|
// Agregar error pero continuar con las demás filas
|
||||||
'success' => false,
|
$this->stats['errors'][] = [
|
||||||
'message' => 'Error en la importación',
|
|
||||||
'error' => $e->getMessage(),
|
|
||||||
'fila' => $index + 1,
|
'fila' => $index + 1,
|
||||||
'datos_fila' => [
|
'error' => $e->getMessage(),
|
||||||
|
'datos' => [
|
||||||
'iccid' => $this->getColumnValue($row, 'ICCID'),
|
'iccid' => $this->getColumnValue($row, 'ICCID'),
|
||||||
'msisdn' => $this->getColumnValue($row, 'MSISDN'),
|
'msisdn' => $this->getColumnValue($row, 'MSISDN'),
|
||||||
'paquetes' => $this->getColumnValue($row, 'PAQUETES'),
|
'paquetes' => $this->getColumnValue($row, 'PAQUETES'),
|
||||||
'usuario' => $this->getColumnValue($row, 'USUARIO'),
|
'usuario' => $this->getColumnValue($row, 'USUARIO'),
|
||||||
'fecha_venta' => $this->getColumnValue($row, 'FECHA_VENTA'),
|
]
|
||||||
'metodo_pago' => $this->getColumnValue($row, 'METODO_PAGO'),
|
];
|
||||||
],
|
|
||||||
'stats' => $this->stats,
|
|
||||||
], 500);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DB::commit();
|
|
||||||
|
|
||||||
return ApiResponse::OK->response([
|
return ApiResponse::OK->response([
|
||||||
'success' => true,
|
'success' => true,
|
||||||
'message' => 'Importación completada',
|
'message' => 'Importación completada',
|
||||||
@ -182,10 +180,6 @@ public function import(Request $request)
|
|||||||
'price' => $p->price
|
'price' => $p->price
|
||||||
], $this->packageCache)),
|
], $this->packageCache)),
|
||||||
]);
|
]);
|
||||||
} catch (\Exception $e) {
|
|
||||||
DB::rollBack();
|
|
||||||
throw $e;
|
|
||||||
}
|
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
return ApiResponse::BAD_REQUEST->response([
|
return ApiResponse::BAD_REQUEST->response([
|
||||||
'success' => false,
|
'success' => false,
|
||||||
@ -267,6 +261,16 @@ private function processSale(SimCard $sim, array $row)
|
|||||||
$packageInfo['price']
|
$packageInfo['price']
|
||||||
);
|
);
|
||||||
|
|
||||||
|
//Evitar duplicados
|
||||||
|
$existingSaleItem = SaleItem::where('sim_card_id', $sim->id)
|
||||||
|
->where('package_id', $package->id)
|
||||||
|
->first();
|
||||||
|
|
||||||
|
if ($existingSaleItem) {
|
||||||
|
// Ya existe una venta para esta SIM+Paquete, salir
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Buscar o crear el cliente
|
// Buscar o crear el cliente
|
||||||
$usuario = trim($row['usuario'] ?? '');
|
$usuario = trim($row['usuario'] ?? '');
|
||||||
$client = Client::where('full_name', $usuario)->first()
|
$client = Client::where('full_name', $usuario)->first()
|
||||||
@ -297,7 +301,7 @@ private function processSale(SimCard $sim, array $row)
|
|||||||
// Crear la venta
|
// Crear la venta
|
||||||
$sale = Sale::create([
|
$sale = Sale::create([
|
||||||
'client_id' => $client->id,
|
'client_id' => $client->id,
|
||||||
'cash_close_id' => null, // Se dejará null para importaciones
|
'cash_close_id' => null,
|
||||||
'total_amount' => $package->price,
|
'total_amount' => $package->price,
|
||||||
'payment_method' => $paymentMethod,
|
'payment_method' => $paymentMethod,
|
||||||
'sale_date' => $saleDate,
|
'sale_date' => $saleDate,
|
||||||
@ -325,37 +329,7 @@ private function processSale(SimCard $sim, array $row)
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verificar si ya existe una venta para esta SIM con este paquete
|
// Asignar paquete a la SIM
|
||||||
// (para evitar duplicados en reimportaciones)
|
|
||||||
$existingSale = Sale::whereHas('saleItems', function ($query) use ($sim, $package) {
|
|
||||||
$query->where('sim_card_id', $sim->id)
|
|
||||||
->where('package_id', $package->id);
|
|
||||||
})->where('client_id', $client->id)
|
|
||||||
->where('sale_date', $saleDate)
|
|
||||||
->exists();
|
|
||||||
|
|
||||||
if (!$existingSale) {
|
|
||||||
// Crear la venta
|
|
||||||
$sale = Sale::create([
|
|
||||||
'client_id' => $client->id,
|
|
||||||
'cash_close_id' => null, // Importaciones no tienen corte de caja
|
|
||||||
'total_amount' => $package->price,
|
|
||||||
'payment_method' => $paymentMethod,
|
|
||||||
'sale_date' => $saleDate,
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Crear el item de venta
|
|
||||||
SaleItem::create([
|
|
||||||
'sale_id' => $sale->id,
|
|
||||||
'sim_card_id' => $sim->id,
|
|
||||||
'package_id' => $package->id,
|
|
||||||
]);
|
|
||||||
|
|
||||||
$this->stats['sales_created']++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Asignar paquete a la SIM (usando syncWithoutDetaching para evitar duplicados)
|
|
||||||
// Primero verificamos si ya existe la relación activa
|
|
||||||
$hasActivePackage = $sim->packages()
|
$hasActivePackage = $sim->packages()
|
||||||
->wherePivot('package_id', $package->id)
|
->wherePivot('package_id', $package->id)
|
||||||
->wherePivot('is_active', true)
|
->wherePivot('is_active', true)
|
||||||
@ -371,30 +345,40 @@ private function processSale(SimCard $sim, array $row)
|
|||||||
// Actualizar status de la SIM
|
// Actualizar status de la SIM
|
||||||
$sim->update(['status' => SimCardStatus::ASSIGNED]);
|
$sim->update(['status' => SimCardStatus::ASSIGNED]);
|
||||||
|
|
||||||
|
// stats
|
||||||
|
$this->stats['sales_created']++;
|
||||||
$this->stats['assigned']++;
|
$this->stats['assigned']++;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function parseSaleDate($dateValue)
|
private function parseSaleDate($dateValue)
|
||||||
{
|
{
|
||||||
if (empty($dateValue)) {
|
if (empty($dateValue)) {
|
||||||
return now();
|
return now()->startOfDay()->format('Y-m-d H:i:s');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Si es numérico
|
||||||
if (is_numeric($dateValue)) {
|
if (is_numeric($dateValue)) {
|
||||||
try {
|
try {
|
||||||
$excelBaseDate = new \DateTime('1899-12-30');
|
$excelBaseDate = new \DateTime('1899-12-30');
|
||||||
$excelBaseDate->modify("+{$dateValue} days");
|
$excelBaseDate->modify("+{$dateValue} days");
|
||||||
return $excelBaseDate->format('Y-m-d H:i:s');
|
return $excelBaseDate->format('Y-m-d') . ' 00:00:00';
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
return now();
|
return now()->startOfDay()->format('Y-m-d H:i:s');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Intentar parsear como fecha
|
// Si es string, intentar parsear como DD/MM/YYYY
|
||||||
try {
|
try {
|
||||||
return \Carbon\Carbon::parse($dateValue)->format('Y-m-d H:i:s');
|
// Primero intentar formato DD/MM/YYYY explícitamente
|
||||||
|
$date = \Carbon\Carbon::createFromFormat('d/m/Y', $dateValue);
|
||||||
|
return $date->startOfDay()->format('Y-m-d H:i:s');
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
return now();
|
// Fallback: intentar parsear automáticamente
|
||||||
|
try {
|
||||||
|
return \Carbon\Carbon::parse($dateValue)->startOfDay()->format('Y-m-d H:i:s');
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return now()->startOfDay()->format('Y-m-d H:i:s');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user