mivita/app/Http/Controllers/Web/CheckoutController.php
2025-04-01 10:36:47 +02:00

552 lines
No EOL
20 KiB
PHP
Executable file

<?php
namespace App\Http\Controllers\Web;
use App\Http\Controllers\Controller;
use App\Http\Controllers\Pay\PayoneController;
use App\Models\PaymentTransaction;
use App\Models\ShoppingOrder;
use App\Models\ShoppingPayment;
use App\Models\ShoppingUser;
use App\Repositories\CheckoutRepository;
use App\Services\AboHelper;
use App\Services\CustomerPriority;
use App\Services\OrderPaymentService;
use App\Services\Payment;
use App\Services\Shop;
use App\Services\Util;
use App\User;
use Illuminate\Support\Facades\Session;
use Request;
use Validator;
use Yard;
class CheckoutController extends Controller
{
private $checkoutRepo;
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct(CheckoutRepository $checkoutRepository)
{
$this->checkoutRepo = $checkoutRepository;
}
/**
* Zeigt die Checkout-Seite an
*
* @return \Illuminate\View\View
*/
public function checkout()
{
$shopping_data = Yard::instance('shopping')->getYardExtra('shopping_data');
$is_from = $shopping_data['is_from'] ?? 'shopping';
$is_for = $shopping_data['is_for'] ?? false;
$is_abo = isset($shopping_data['is_abo']) ? (bool) $shopping_data['is_abo'] : false;
$abo_interval = $shopping_data['abo_interval'] ?? 0;
$homeparty_id = $shopping_data['homeparty_id'] ?? null;
$shopping_user = null;
if ($is_for === 'ot-customer' || $is_for === 'abo-ot-customer') {
$is_from = 'shopping';
}
Util::setInstanceStatus(1, true); // link_check
if ($is_abo) {
$instance_status = Util::getInstanceStatus();
if ($instance_status === 'link_paid') {
return $this->redirectToIsFinal($instance_status);
}
}
if (Session::has('new_session')) {
$this->checkoutRepo->sessionDestroy();
Session::forget('new_session');
}
if (!$this->checkoutRepo->getSessionPayments('shopping_user_id')) {
if ($shopping_data && $is_from !== 'shopping') {
$shopping_user = $this->checkoutRepo->shoppingUserAuthData($is_from, $is_for, $shopping_data);
$shopping_user->save();
$this->checkoutRepo->putSessionPayments('shopping_user_id', $shopping_user->id);
} elseif ($is_from === 'shopping' && ($is_for !== 'ot-customer' && $is_for !== 'abo-ot-customer')) {
$shopping_user = $this->initializeShoppingUser($is_for, $is_from, $homeparty_id);
} elseif ($is_from === 'shopping' && ($is_for === 'ot-customer' || $is_for === 'abo-ot-customer')) {
$shopping_user = $this->checkoutRepo->makeCustomerShoppingUser($shopping_data);
$shopping_user->is_for = $is_for;
$shopping_user->is_from = $is_from;
$shopping_user->mode = 'prev';
$shopping_user->language = \App::getLocale();
}
} else {
$shopping_user = $this->getExistingShoppingUser();
}
$this->prepareShoppingUserData($shopping_user);
$payment_methods = $this->checkoutRepo->getPaymentsMethods($is_from, $is_abo);
$data = [
'is_from' => $is_from,
'is_for' => $is_for,
'is_abo' => $is_abo,
'abo_interval' => $abo_interval,
'shopping_data' => $shopping_data,
'user_shop' => Util::getUserShop(),
'shopping_user' => $shopping_user,
'shopping_mode' => Util::getUserShoppingMode(),
'payment_methods' => $payment_methods['default'],
'payment_methods_active' => $payment_methods['active'],
'payment_data' => $payment_methods['data'],
'instance_status' => $instance_status ?? false,
];
return view('web.templates.checkout', $data);
}
/**
* Initialisiert einen neuen ShoppingUser
*
* @param string $is_for
* @param string $is_from
* @param int|null $homeparty_id
* @return ShoppingUser
*/
private function initializeShoppingUser($is_for, $is_from, $homeparty_id = null)
{
$shopping_user = new ShoppingUser();
$shopping_user->is_for = $is_for;
$shopping_user->is_from = $is_from;
$shopping_user->homeparty_id = $homeparty_id;
$shopping_user->mode = 'prev';
$shopping_user->language = \App::getLocale();
return $shopping_user;
}
/**
* Holt den existierenden ShoppingUser und bereitet ihn vor
*
* @return ShoppingUser
*/
private function getExistingShoppingUser()
{
$shopping_user = ShoppingUser::findOrFail($this->checkoutRepo->getSessionPayments('shopping_user_id'));
$shopping_user->billing_state = Shop::getCountryShippingCountryId($shopping_user->billing_country_id);
$shopping_user->shipping_state = Shop::getCountryShippingCountryId($shopping_user->shipping_country_id);
$shopping_user->same_as_billing = $shopping_user->same_as_billing ? false : true; // reinvert
return $shopping_user;
}
/**
* Bereitet die ShoppingUser-Daten vor
*
* @param ShoppingUser $shopping_user
* @return void
*/
private function prepareShoppingUserData(ShoppingUser $shopping_user)
{
if ($shopping_user->same_as_billing === NULL) {
$shopping_user->same_as_billing = false;
}
if (!$shopping_user->billing_country_id) {
$shopping_user->billing_country_id = Yard::instance('shopping')->getUserCountryId();
// Die Zeile unten entfernen, da die Relation automatisch geladen wird
// $shopping_user->billing_country = Yard::instance('shopping')->getUserCountry();
}
if (!$shopping_user->shipping_country_id) {
$shopping_user->shipping_country_id = Yard::instance('shopping')->getUserCountryId();
// Die Zeile unten entfernen, da die Relation automatisch geladen wird
// $shopping_user->shipping_country = Yard::instance('shopping')->getUserCountry();
}
if (old('selected_country') && old('selected_country') === 'change') {
Session::forget('_old_input.selected_country');
$shopping_user->billing_state = old('billing_state');
$shopping_user->shipping_state = old('shipping_state');
} else {
$shopping_user->billing_state = Yard::instance('shopping')->getShippingCountryId();
$shopping_user->shipping_state = Yard::instance('shopping')->getShippingCountryId();
}
}
/**
* Verarbeitet den Checkout-Prozess
*
* @return \Illuminate\Http\RedirectResponse
*/
public function checkoutFinal()
{
$data = Request::all();
if (isset($data['payment_method'])) {
$this->checkoutRepo->isPaymentsMethodsActive($data['payment_method'], $data['is_from'], $data['is_abo']);
}
Util::setInstanceStatus(2, true); // link_check
// Länderwechsel verarbeiten
if (isset($data['selected_country']) && $data['selected_country'] === 'change') {
return $this->handleCountryChange($data);
}
// Validierung
$validator = $this->validateCheckoutData();
if ($validator->fails()) {
return back()->withErrors($validator)->withInput(Request::all());
}
// Benutzer und Bestellung erstellen
$shopping_user = $this->checkoutRepo->makeShoppingUser($data);
$shopping_order = $this->checkoutRepo->makeShoppingOrder($shopping_user, $data);
// CustomerPriority prüfen
if ($shopping_user->is_from === 'shopping') {
CustomerPriority::checkOne(ShoppingUser::find($shopping_user->id), true);
}
Util::setUserHistoryValue(['status' => 2, 'shopping_order_id' => $shopping_order->id]);
// Zahlungsmethode verarbeiten
if (Request::get('payment_method')) {
return $this->processPaymentMethod($data, $shopping_user, $shopping_order);
}
return redirect()->back();
}
/**
* Verarbeitet den Länderwechsel
*
* @param array $data
* @return \Illuminate\Http\RedirectResponse
*/
private function handleCountryChange($data)
{
if (!Request::get('same_as_billing')) {
Yard::instance('shopping')->setShippingCountryWithPrice($data['billing_state'], $data['is_for']);
} else {
Yard::instance('shopping')->setShippingCountryWithPrice($data['shipping_state'], $data['is_for']);
}
return back()->withInput(Request::all());
}
/**
* Validiert die Checkout-Daten
*
* @return \Illuminate\Validation\Validator
*/
private function validateCheckoutData()
{
$rules = [
'billing_salutation' => 'required',
'billing_firstname' => 'required',
'billing_lastname' => 'required',
'billing_email' => 'required|email',
'billing_address' => 'required',
'billing_zipcode' => 'required',
'billing_city' => 'required',
'accepted_data_checkbox' => 'accepted',
];
if (Request::get('same_as_billing')) {
$rules = array_merge($rules, [
'shipping_firstname' => 'required',
'shipping_lastname' => 'required',
'shipping_address' => 'required',
'shipping_zipcode' => 'required',
'shipping_city' => 'required',
'shipping_salutation' => 'required'
]);
}
return Validator::make(Request::all(), $rules);
}
/**
* Verarbeitet die Zahlungsmethode
*
* @param array $data
* @param ShoppingUser $shopping_user
* @param ShoppingOrder $shopping_order
* @return mixed
*/
private function processPaymentMethod($data, $shopping_user, $shopping_order)
{
$result = [];
$payment_method = Request::get('payment_method');
// Kreditkarte prüfen
if ($payment_method === 'cc') {
$result = $this->checkCreditCard($data, $shopping_user, $shopping_order);
if (!isset($result['returnstatus']) || $result['returnstatus'] !== 'VALID') {
return $result;
}
}
// SEPA prüfen
if ($payment_method === 'elv') {
$result = $this->checkSepaAccount($data, $shopping_user, $shopping_order);
if (!isset($result['returnstatus']) || $result['returnstatus'] !== 'VALID') {
return $result;
}
}
// Zahlung vorbereiten
$pay = new PayoneController();
$pay->init($shopping_user, $shopping_order);
$amount = Yard::instance('shopping')->totalWithShipping(2, '.', '') * 100;
$reference = $pay->setPrePayment($payment_method, $amount, 'EUR', $result);
$this->checkoutRepo->putSessionPayments('payment_reference', $reference);
$pay->setPersonalData();
return $pay->ResponseData();
}
/**
* Prüft die Kreditkartendaten
*
* @param array $data
* @param ShoppingUser $shopping_user
* @param ShoppingOrder $shopping_order
* @return bool|\Illuminate\Http\RedirectResponse
*/
private function checkCreditCard($data, $shopping_user, $shopping_order)
{
$pay = new PayoneController();
$pay->init($shopping_user, $shopping_order);
$ret['cc'] = $pay->checkCreditCard($data);
if ($ret['cc']['status'] === 'ERROR' || $ret['cc']['status'] === 'INVALID') {
Session::flash('cc-error', 1);
Session::flash('errormessage', $ret['cc']['errormessage']);
Session::flash('customermessage', $ret['cc']['customermessage']);
return redirect(route('checkout.checkout_card'))->withInput(Request::all());
}
$ret['returnstatus'] = 'VALID';
return $ret;
}
/**
* Prüft die SEPA-Kontodaten
*
* @param array $data
* @param ShoppingUser $shopping_user
* @param ShoppingOrder $shopping_order
* @return bool|\Illuminate\Http\RedirectResponse
*/
private function checkSepaAccount($data, $shopping_user, $shopping_order)
{
if (is_null(Request::get('mandate_identification'))) {
$pay = new PayoneController();
$pay->init($shopping_user, $shopping_order);
$amount = Yard::instance('shopping')->totalWithShipping(2, '.', '') * 100;
$ret['elv'] = $pay->checkBankAccount($data, $amount, 'EUR', $shopping_user);
if ($ret['elv']['status'] === 'ERROR' || $ret['elv']['status'] === 'INVALID') {
Session::flash('elv-error', 1);
Session::flash('errormessage', $ret['elv']['errormessage']);
Session::flash('customermessage', $ret['elv']['customermessage']);
return redirect(route('checkout.checkout_card'))->withInput(Request::all());
}
if ($ret['elv']['status'] === 'APPROVED' && $ret['elv']['mandate_status'] !== "active") {
Session::flash('elv-managemandate', 1);
Session::flash('elv-mandate_identification', $ret['elv']['mandate_identification']);
Session::flash('elv-mandate_text', $ret['elv']['mandate_text']);
Session::flash('elv-creditor_identifier', $ret['elv']['creditor_identifier']);
return redirect(route('checkout.checkout_card'))->withInput(Request::all());
}
$ret['elv']['bankaccountholder'] = $data['elv_bankaccountholder'];
} else {
$ret['elv'] = [
'mandate_identification' => Request::get('mandate_identification'),
'creditor_identifier' => Request::get('creditor_identifier'),
'iban' => $data['elv_iban'],
'bic' => $data['elv_bic'],
'bankaccountholder' => $data['elv_bankaccountholder']
];
$this->storeUserPaymentsData($shopping_user, $ret);
}
$ret['returnstatus'] = 'VALID';
return $ret;
}
/**
* Leitet zur Abschlussseite weiter
*
* @return \Illuminate\View\View
*/
public function redirectToIsFinal()
{
$data = [
'user_shop' => Util::getUserShop(),
];
return view('web.templates.checkout-is-final', $data);
}
/**
* Verarbeitet den Transaktionsstatus
*
* @param string $status
* @param string $reference
* @return \Illuminate\View\View|\Illuminate\Http\RedirectResponse
*/
public function transactionStatus($status, $reference)
{
$shopping_order_id = $this->checkoutRepo->getSessionPayments('shopping_order_id');
$ShoppingPayment = ShoppingPayment::where('shopping_order_id', $shopping_order_id)
->where('reference', $reference)
->first();
if (!$ShoppingPayment) {
Util::setUserHistoryValue(['status' => 21]);
Session::flash('checkout-error', 'Der Zahlungsvorgang konnte nicht abgeschlossen werden, die Zahlung wurde nicht gefunden: ' . $reference);
return redirect(route('checkout.checkout_card'));
}
$ShoppingPayment->status = $status;
$ShoppingPayment->save();
if ($status === "success") {
return $this->handleSuccessfulTransaction($ShoppingPayment, $reference);
}
if ($status === "cancel") {
Util::setUserHistoryValue(['status' => 22]);
Util::setInstanceStatus(5); // link_canceled
Session::flash('checkout-error', 'Der Zahlungsvorgang wurde abgebrochen, die Bestellung konnte nicht ausgeführt werden.');
return redirect(route('checkout.checkout_card'));
}
if ($status === "error") {
Util::setUserHistoryValue(['status' => 23]);
Util::setInstanceStatus(6); // link_failed
Session::flash('checkout-error', 'Der Zahlungsvorgang wurde abgebrochen, die Bestellung konnte nicht ausgeführt werden.');
return redirect(route('checkout.checkout_card'));
}
}
/**
* Verarbeitet eine erfolgreiche Transaktion
*
* @param ShoppingPayment $ShoppingPayment
* @param string $reference
* @return \Illuminate\View\View
*/
private function handleSuccessfulTransaction($ShoppingPayment, $reference)
{
Yard::instance('shopping')->destroy();
$this->checkoutRepo->sessionDestroy();
Util::setInstanceStatus(3, true); // link_pending
// Abo erstellen, falls nötig
if ($ShoppingPayment->shopping_order->is_abo) {
AboHelper::createNewAbo($ShoppingPayment);
}
$payt = $ShoppingPayment->payment_transactions->last();
$data = [
'user_shop' => Util::getUserShop(),
'order_reference' => $reference,
'pay_trans' => $payt,
];
return view('web.templates.checkout-final', $data);
}
/**
* Verarbeitet eine genehmigte Transaktion
*
* @param int $transactionId
* @param string $reference
* @return \Illuminate\View\View
*/
public function transactionApproved($transactionId, $reference)
{
$payt = PaymentTransaction::findOrFail($transactionId);
if ($payt->shopping_payment->reference != $reference) {
abort(404);
}
Yard::instance('shopping')->destroy();
$this->checkoutRepo->sessionDestroy();
Util::setInstanceStatus(3, true); // link_pending
// Abo erstellen, falls nötig
if ($payt->shopping_payment->shopping_order->is_abo) {
AboHelper::createNewAbo($payt->shopping_payment);
}
// Rechnung MIV
if ($payt->status === 'FNCMIV') {
$this->directPaymentStatus($payt);
}
$data = [
'user_shop' => Util::getUserShop(),
'order_reference' => $payt->shopping_payment->reference,
'pay_trans' => $payt,
];
return view('web.templates.checkout-final', $data);
}
/**
* Speichert die Zahlungsdaten des Benutzers
*
* @param ShoppingUser $shopping_user
* @param array $ret
* @return void
*/
private function storeUserPaymentsData($shopping_user, $ret)
{
if ($shopping_user->auth_user_id) {
$user = User::find($shopping_user->auth_user_id);
if ($user && $user->account) {
if (isset($ret['elv']) && is_array($ret['elv'])) {
$user->account->payment_data = $ret['elv'];
$user->account->save();
}
}
}
}
/**
* Verarbeitet den direkten Zahlungsstatus (Rechnung MIV)
*
* @param PaymentTransaction $payt
* @return void
*/
private function directPaymentStatus(PaymentTransaction $payt)
{
if (isset($payt->transmitted_data['param'])) {
$shopping_order = ShoppingOrder::find($payt->transmitted_data['param']);
$shopping_order->txaction = 'invoice_open';
$shopping_order->save();
$shopping_payment = ShoppingPayment::where('reference', $payt->transmitted_data['reference'])->first();
if ($shopping_payment) {
$shopping_payment->txaction = 'invoice_open';
$shopping_payment->save();
}
$send_link = Payment::paymentStatusPaidAction($shopping_order, false, $shopping_payment);
$data = [
'mode' => $payt->transmitted_data['mode'],
'txaction' => $payt->txaction,
'send_link' => $send_link,
];
Payment::paymentStatusSendMail($shopping_order, $shopping_payment, $data);
}
}
}