Merge branch 'feature/candidate_payments' into homo_experimental
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('telepagos_payment_candidates', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('telepagos_payment_id')
|
||||
->constrained('telepagos_payments')
|
||||
->cascadeOnDelete();
|
||||
$table->foreignId('compra_id')->constrained('compras')->cascadeOnDelete();
|
||||
$table->boolean('dni_matches');
|
||||
$table->boolean('amount_matches');
|
||||
$table->decimal('payment_amount', 10, 2);
|
||||
$table->decimal('purchase_amount', 10, 2);
|
||||
$table->decimal('amount_difference', 10, 2);
|
||||
$table->string('match_reason');
|
||||
$table->string('confidence');
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(
|
||||
['telepagos_payment_id', 'compra_id'],
|
||||
'telepagos_payment_candidate_unique',
|
||||
);
|
||||
});
|
||||
|
||||
$this->migrateExistingCandidates();
|
||||
|
||||
Schema::table('telepagos_payments', function (Blueprint $table) {
|
||||
$table->dropColumn('matched_purchase_ids');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('telepagos_payments', function (Blueprint $table) {
|
||||
$table->json('matched_purchase_ids')->nullable()->after('compra_id');
|
||||
});
|
||||
|
||||
DB::table('telepagos_payments')
|
||||
->whereNull('compra_id')
|
||||
->orderBy('id')
|
||||
->each(function (object $payment): void {
|
||||
$candidateIds = DB::table('telepagos_payment_candidates')
|
||||
->where('telepagos_payment_id', $payment->id)
|
||||
->pluck('compra_id')
|
||||
->all();
|
||||
|
||||
if ($candidateIds !== []) {
|
||||
DB::table('telepagos_payments')
|
||||
->where('id', $payment->id)
|
||||
->update(['matched_purchase_ids' => json_encode($candidateIds)]);
|
||||
}
|
||||
});
|
||||
|
||||
Schema::dropIfExists('telepagos_payment_candidates');
|
||||
}
|
||||
|
||||
private function migrateExistingCandidates(): void
|
||||
{
|
||||
DB::table('telepagos_payments')
|
||||
->whereNull('compra_id')
|
||||
->whereNotNull('matched_purchase_ids')
|
||||
->orderBy('id')
|
||||
->each(function (object $payment): void {
|
||||
$candidateIds = json_decode((string) $payment->matched_purchase_ids, true);
|
||||
|
||||
if (! is_array($candidateIds)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$paymentAmount = number_format((float) $payment->amount, 2, '.', '');
|
||||
$payerDni = $payment->cuit_buyer
|
||||
? substr((string) $payment->cuit_buyer, 2, -1)
|
||||
: null;
|
||||
|
||||
foreach ($candidateIds as $candidateId) {
|
||||
$purchase = DB::table('compras')->find($candidateId);
|
||||
|
||||
if ($purchase === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$purchaseAmount = number_format((float) $purchase->total, 2, '.', '');
|
||||
$dniMatches = $payerDni !== null && $purchase->transfer_payer_dni === $payerDni;
|
||||
$amountMatches = $purchaseAmount === $paymentAmount;
|
||||
|
||||
DB::table('telepagos_payment_candidates')->insertOrIgnore([
|
||||
'telepagos_payment_id' => $payment->id,
|
||||
'compra_id' => $purchase->id,
|
||||
'dni_matches' => $dniMatches,
|
||||
'amount_matches' => $amountMatches,
|
||||
'payment_amount' => $paymentAmount,
|
||||
'purchase_amount' => $purchaseAmount,
|
||||
'amount_difference' => number_format(
|
||||
abs((float) $purchaseAmount - (float) $paymentAmount),
|
||||
2,
|
||||
'.',
|
||||
'',
|
||||
),
|
||||
'match_reason' => $this->matchReason($dniMatches, $amountMatches),
|
||||
'confidence' => $this->confidence($dniMatches, $amountMatches),
|
||||
'created_at' => $payment->created_at,
|
||||
'updated_at' => $payment->updated_at,
|
||||
]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private function matchReason(bool $dniMatches, bool $amountMatches): string
|
||||
{
|
||||
if ($dniMatches && $amountMatches) {
|
||||
return 'ambiguous_exact_match';
|
||||
}
|
||||
|
||||
if ($dniMatches) {
|
||||
return 'exact_dni_near_amount';
|
||||
}
|
||||
|
||||
if ($amountMatches) {
|
||||
return 'exact_amount_different_dni';
|
||||
}
|
||||
|
||||
return 'legacy_candidate';
|
||||
}
|
||||
|
||||
private function confidence(bool $dniMatches, bool $amountMatches): string
|
||||
{
|
||||
if ($dniMatches && $amountMatches) {
|
||||
return 'exact';
|
||||
}
|
||||
|
||||
return $dniMatches ? 'high' : 'medium';
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
use App\Domains\Purchase\Services\DniDistanceService;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('telepagos_payment_candidates', function (Blueprint $table) {
|
||||
$table->unsignedTinyInteger('dni_distance')->nullable()->after('dni_matches');
|
||||
$table->string('payment_dni', 8)->nullable()->after('dni_distance');
|
||||
$table->string('purchase_dni', 8)->nullable()->after('payment_dni');
|
||||
});
|
||||
|
||||
$dniDistance = new DniDistanceService;
|
||||
|
||||
DB::table('telepagos_payment_candidates as candidate')
|
||||
->join('telepagos_payments as payment', 'payment.id', '=', 'candidate.telepagos_payment_id')
|
||||
->join('compras as purchase', 'purchase.id', '=', 'candidate.compra_id')
|
||||
->select([
|
||||
'candidate.id',
|
||||
'candidate.match_reason',
|
||||
'payment.cuit_buyer',
|
||||
'purchase.transfer_payer_dni',
|
||||
])
|
||||
->orderBy('candidate.id')
|
||||
->each(function (object $candidate) use ($dniDistance): void {
|
||||
if ($candidate->cuit_buyer === null || $candidate->transfer_payer_dni === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$payerDni = substr((string) $candidate->cuit_buyer, 2, -1);
|
||||
$distance = $dniDistance->distance($payerDni, (string) $candidate->transfer_payer_dni);
|
||||
|
||||
if ($candidate->match_reason === 'exact_amount_different_dni' && $distance > 2) {
|
||||
DB::table('telepagos_payment_candidates')->where('id', $candidate->id)->delete();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
DB::table('telepagos_payment_candidates')
|
||||
->where('id', $candidate->id)
|
||||
->update([
|
||||
'dni_distance' => $distance,
|
||||
'payment_dni' => $payerDni,
|
||||
'purchase_dni' => $candidate->transfer_payer_dni,
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('telepagos_payment_candidates', function (Blueprint $table) {
|
||||
$table->dropColumn(['dni_distance', 'payment_dni', 'purchase_dni']);
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
DB::table('telepagos_payment_candidates')
|
||||
->where('match_reason', 'exact_amount_different_dni')
|
||||
->update(['match_reason' => 'exact_amount_near_dni']);
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
DB::table('telepagos_payment_candidates')
|
||||
->where('match_reason', 'exact_amount_near_dni')
|
||||
->update(['match_reason' => 'exact_amount_different_dni']);
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user