gruene-seele/app/Services/PaymentService.php
2025-08-12 15:51:04 +02:00

201 lines
No EOL
7 KiB
PHP

<?php
namespace App\Services;
use App\Models\ShoppingOrder;
use App\Models\ShoppingPayment;
use App\Models\UserPayCredit;
use App\Models\PaymentTransaction;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
class PaymentService
{
public static $txaction_art = [
'user_order' => "Vertriebspartner",
'customer_order' => "Kundenbestellung",
'user_for_customer' => "VP.Kundenbestellung",
];
// Konstanten für bessere Wartbarkeit
const CREDIT_STATUS_DEDUCTION = 2;
const CREDIT_STATUS_RETURN = 4;
const CREDIT_STATUS_CHARGED = 7;
const CREDIT_STATUS_REMOVED = 8;
const TRANSACTION_REQUEST = 'transaction';
const DEFAULT_TXID = 0;
const DEFAULT_USERID = 0;
/**
* Aktualisiert den Transaktionsstatus einer Bestellung
*
* @param int $orderId
* @param string $txaction
* @param int $paymentId
* @return bool
* @throws \Exception
*/
public static function updateTransactionStatus($orderId, $txaction, $paymentId)
{
// Validierung der Eingabeparameter
if (empty($orderId) || empty($txaction) || empty($paymentId)) {
throw new \InvalidArgumentException('Alle Parameter müssen angegeben werden');
}
return DB::transaction(function () use ($orderId, $txaction, $paymentId) {
$shopping_order = ShoppingOrder::findOrFail($orderId);
$shopping_payment = ShoppingPayment::findOrFail($paymentId);
// Prüfen ob sich der Status tatsächlich geändert hat
if ($shopping_payment->txaction === $txaction) {
return false;
}
// Guthaben-Logik für Partner-Center Bestellungen
self::handlePartnerCenterCredits($shopping_order, $txaction);
// PaymentTransaction erstellen
$paymentTransaction = self::createPaymentTransaction($shopping_payment, $txaction);
// Bestellung und Payment aktualisieren
self::updateOrderAndPayment($shopping_order, $shopping_payment, $txaction, $paymentTransaction);
// Paid-Action ausführen falls nötig
self::handlePaidAction($paymentTransaction, $shopping_order);
// Credit-Loading Logik
self::handleCreditLoading($shopping_order, $txaction);
// E-Mail versenden
self::sendStatusEmail($shopping_order, $shopping_payment, $paymentTransaction);
return true;
});
}
/**
* Behandelt Guthaben-Logik für Partner-Center Bestellungen
*/
private static function handlePartnerCenterCredits(ShoppingOrder $shoppingOrder, string $txaction): void
{
if (!$shoppingOrder->shopping_order_margin || $shoppingOrder->shopping_order_margin->from_payment_credit <= 0) {
return;
}
$lastUserPayCredit = self::getLastUserPayCredit($shoppingOrder->id, [self::CREDIT_STATUS_DEDUCTION, self::CREDIT_STATUS_RETURN]);
if (!$lastUserPayCredit) {
return;
}
// Status Keine Zahlung, Guthaben zurückführen
if ($txaction === 'non' && $lastUserPayCredit->status === self::CREDIT_STATUS_DEDUCTION) {
Payment::handelUserPayCredits($shoppingOrder, 'return');
}
// Status Zahlung, vorher gab es eine Storno, Guthaben abziehen
if ($lastUserPayCredit->status === self::CREDIT_STATUS_RETURN && in_array($txaction, ['open', 'paid'])) {
Payment::handelUserPayCredits($shoppingOrder, 'deduction');
}
}
/**
* Erstellt eine neue PaymentTransaction
*/
private static function createPaymentTransaction(ShoppingPayment $shoppingPayment, string $txaction): PaymentTransaction
{
return PaymentTransaction::create([
'shopping_payment_id' => $shoppingPayment->id,
'request' => self::TRANSACTION_REQUEST,
'txid' => self::DEFAULT_TXID,
'userid' => self::DEFAULT_USERID,
'status' => $shoppingPayment->clearingtype,
'transmitted_data' => null,
'txaction' => $txaction,
'mode' => $shoppingPayment->mode,
]);
}
/**
* Aktualisiert Bestellung und Payment
*/
private static function updateOrderAndPayment(ShoppingOrder $shoppingOrder, ShoppingPayment $shoppingPayment, string $txaction, PaymentTransaction $paymentTransaction): void
{
$shoppingOrder->txaction = $txaction;
$shoppingOrder->paid = $paymentTransaction->txaction === 'paid';
$shoppingOrder->save();
$shoppingPayment->txaction = $txaction;
$shoppingPayment->save();
}
/**
* Führt Paid-Action aus falls nötig
*/
private static function handlePaidAction(PaymentTransaction $paymentTransaction, ShoppingOrder $shoppingOrder): void
{
if ($paymentTransaction->status === 'vor' && $paymentTransaction->txaction === 'paid') {
Payment::paymentStatusPaidAction($shoppingOrder, true);
}
}
/**
* Behandelt Credit-Loading Logik
*/
private static function handleCreditLoading(ShoppingOrder $shoppingOrder, string $txaction): void
{
if (!$shoppingOrder->shopping_user || $shoppingOrder->shopping_user->is_for !== 'cr') {
return;
}
$lastUserPayCredit = self::getLastUserPayCredit($shoppingOrder->id, [self::CREDIT_STATUS_CHARGED, self::CREDIT_STATUS_REMOVED]);
if (!$lastUserPayCredit) {
return;
}
// Status Keine Zahlung, Guthaben abziehen
if ($txaction === 'non' && $lastUserPayCredit->status === self::CREDIT_STATUS_CHARGED) {
Payment::handelUserPayChargingCredits($shoppingOrder, 'remove');
}
// Status Zahlung, vorher gab es eine Storno, Guthaben wieder aufladen
if ($lastUserPayCredit->status === self::CREDIT_STATUS_REMOVED && $txaction === 'paid') {
Payment::handelUserPayChargingCredits($shoppingOrder, 'add');
}
}
/**
* Sendet Status-E-Mail
*/
private static function sendStatusEmail(ShoppingOrder $shoppingOrder, ShoppingPayment $shoppingPayment, PaymentTransaction $paymentTransaction): void
{
$emailData = [
'mode' => $paymentTransaction->mode,
'txaction' => $paymentTransaction->txaction,
'send_link' => false,
];
try {
Payment::paymentStatusSendMail($shoppingOrder, $shoppingPayment, $emailData);
} catch (\Exception $e) {
Log::error('Fehler beim Senden der Status-E-Mail', [
'order_id' => $shoppingOrder->id,
'payment_id' => $shoppingPayment->id,
'error' => $e->getMessage()
]);
}
}
/**
* Holt den letzten UserPayCredit Eintrag
*/
private static function getLastUserPayCredit(int $orderId, array $statuses): ?UserPayCredit
{
return UserPayCredit::where('shopping_order_id', $orderId)
->whereIn('status', $statuses)
->orderBy('id', 'DESC')
->first();
}
}