commit 08-2025
This commit is contained in:
parent
9b54eb0512
commit
02f2a4c23e
184 changed files with 31653 additions and 22327 deletions
252
app/Console/Commands/PaymentsReminders.php
Normal file
252
app/Console/Commands/PaymentsReminders.php
Normal file
|
|
@ -0,0 +1,252 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\PaymentReminder;
|
||||
use App\Models\ShoppingPayment;
|
||||
use App\Services\PaymentReminderService;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
/**
|
||||
* Command für automatische Zahlungserinnerungen
|
||||
*
|
||||
* Dieser Command wird als Cron-Job ausgeführt und sendet automatisch
|
||||
* Zahlungserinnerungen basierend auf den konfigurierten Intervallen.
|
||||
*
|
||||
* Verwendung:
|
||||
* php artisan payments:reminders
|
||||
*
|
||||
* Cron-Job Konfiguration (täglich um 9:00 Uhr):
|
||||
* 0 9 * * * cd /path/to/project && php artisan payments:reminders >> /dev/null 2>&1
|
||||
*
|
||||
* Oder für stündliche Ausführung:
|
||||
* 0 * * * * cd /path/to/project && php artisan payments:reminders >> /dev/null 2>&1
|
||||
*
|
||||
* Logs werden automatisch in storage/logs/laravel.log geschrieben
|
||||
*/
|
||||
class PaymentsReminders extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'payments:reminders';
|
||||
protected $description = 'Run Payments Reminders';
|
||||
|
||||
private $timeStart;
|
||||
private $dev = false;
|
||||
private $paymentReminderService;
|
||||
private $stats = [
|
||||
'total_processed' => 0,
|
||||
'reminders_sent' => 0,
|
||||
'errors' => 0,
|
||||
'skipped' => 0
|
||||
];
|
||||
|
||||
public function __construct(PaymentReminderService $paymentReminderService)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->paymentReminderService = $paymentReminderService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
\Log::info('Starting PaymentsReminders Command', ['timestamp' => now()]);
|
||||
$this->info('RUN Command Payments Reminders: '.date('d.m.Y H:i'));
|
||||
$this->timeStart = microtime(true);
|
||||
|
||||
try {
|
||||
$this->functionReminder();
|
||||
|
||||
$executionTime = round(microtime(true) - $this->timeStart, 2);
|
||||
$this->info("\n=== PAYMENT REMINDERS ABGESCHLOSSEN ===");
|
||||
$this->info("Ausführungszeit: {$executionTime} Sekunden");
|
||||
$this->info("Statistiken:");
|
||||
$this->info(" - Gesamt verarbeitet: {$this->stats['total_processed']}");
|
||||
$this->info(" - Erinnerungen gesendet: {$this->stats['reminders_sent']}");
|
||||
$this->info(" - Fehler: {$this->stats['errors']}");
|
||||
$this->info(" - Übersprungen: {$this->stats['skipped']}");
|
||||
|
||||
\Log::info('PaymentsReminders Command completed successfully', [
|
||||
'execution_time' => $executionTime,
|
||||
'stats' => $this->stats
|
||||
]);
|
||||
return 0;
|
||||
} catch (\Exception $e) {
|
||||
\Log::error('PaymentsReminders Command failed', [
|
||||
'error' => $e->getMessage(),
|
||||
'trace' => $e->getTraceAsString()
|
||||
]);
|
||||
$this->error('Command failed: ' . $e->getMessage());
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hauptfunktion für die Verarbeitung der Zahlungserinnerungen
|
||||
*/
|
||||
private function functionReminder()
|
||||
{
|
||||
$this->info('=== STARTE PAYMENT REMINDERS ===');
|
||||
|
||||
// Hole alle aktiven PaymentReminder und gruppiere sie nach clearingtype
|
||||
$payment_reminders = PaymentReminder::where('active', true)->get();
|
||||
$this->info("Gefundene aktive PaymentReminder: " . $payment_reminders->count());
|
||||
|
||||
if ($payment_reminders->isEmpty()) {
|
||||
$this->warn("Keine aktiven PaymentReminder gefunden!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Finde für jeden clearingtype das kleinste Intervall (in Tagen)
|
||||
$intervals = $this->paymentReminderService->getActiveIntervals();
|
||||
|
||||
$this->info("Gefundene clearingtypes mit kleinsten Intervallen:");
|
||||
foreach($intervals as $clearingtype => $interval){
|
||||
$this->line(" - {$clearingtype}: {$interval} Tage");
|
||||
}
|
||||
|
||||
// Verarbeite jeden clearingtype mit seinem kleinsten Intervall
|
||||
foreach($intervals as $clearingtype => $interval){
|
||||
$this->info("\n--- Verarbeite clearingtype: {$clearingtype} mit Intervall: {$interval} Tage ---");
|
||||
|
||||
$date = Carbon::now()->subDays($interval);
|
||||
$this->line("Suche Zahlungen vor: " . $date->format('d.m.Y H:i:s'));
|
||||
|
||||
// Hole nur die neueste ShoppingPayment pro shopping_order_id
|
||||
$shopping_payments = $this->paymentReminderService->getOpenPaymentsForClearingType($clearingtype, $interval);
|
||||
|
||||
$this->info("Gefundene offene Zahlungen für {$clearingtype}: " . $shopping_payments->count());
|
||||
|
||||
if ($shopping_payments->isEmpty()) {
|
||||
$this->line(" Keine Zahlungen für {$clearingtype} gefunden.");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Verarbeite jede Zahlung
|
||||
foreach($shopping_payments as $shopping_payment){
|
||||
$this->processPayment($shopping_payment, $clearingtype);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verarbeitet eine einzelne Zahlung und sendet ggf. eine Erinnerung
|
||||
*/
|
||||
private function processPayment($shopping_payment, $clearingtype)
|
||||
{
|
||||
$this->stats['total_processed']++;
|
||||
|
||||
try {
|
||||
$this->line(" Verarbeite Order ID: {$shopping_payment->shopping_order_id}, Created: {$shopping_payment->created_at->format('d.m.Y H:i:s')}, Amount: {$shopping_payment->amount}, Reminder: {$shopping_payment->reminder}");
|
||||
|
||||
// Prüfe ob eine Erinnerung gesendet werden soll
|
||||
if ($this->shouldSendReminder($shopping_payment, $clearingtype)) {
|
||||
$this->sendReminderForPayment($shopping_payment);
|
||||
} else {
|
||||
$this->line(" ⏭️ Übersprungen - Keine Erinnerung fällig");
|
||||
$this->stats['skipped']++;
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$this->error(" ❌ Fehler bei Order ID {$shopping_payment->shopping_order_id}: " . $e->getMessage());
|
||||
$this->stats['errors']++;
|
||||
|
||||
\Log::error('Error processing payment reminder', [
|
||||
'order_id' => $shopping_payment->shopping_order_id,
|
||||
'payment_id' => $shopping_payment->id,
|
||||
'error' => $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prüft ob eine Erinnerung für diese Zahlung gesendet werden soll
|
||||
*
|
||||
* Logik:
|
||||
* - Erste Erinnerung: Nach X Tagen ab Bestelldatum
|
||||
* - Weitere Erinnerungen: Nach Y Tagen ab letzter Erinnerung
|
||||
*/
|
||||
private function shouldSendReminder($shopping_payment, $clearingtype)
|
||||
{
|
||||
// Hole alle aktiven Erinnerungen für diesen Clearingtype
|
||||
$payment_reminders = PaymentReminder::where('active', true)
|
||||
->where('clearingtype', $clearingtype)
|
||||
->orderBy('interval', 'asc')
|
||||
->get();
|
||||
|
||||
if ($payment_reminders->isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Wenn alle Erinnerungen bereits gesendet wurden
|
||||
if ($shopping_payment->reminder >= $payment_reminders->count()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Hole die nächste Erinnerung
|
||||
$next_reminder = $payment_reminders[$shopping_payment->reminder];
|
||||
|
||||
// Wenn noch keine Erinnerung gesendet wurde, prüfe das erste Intervall
|
||||
if ($shopping_payment->reminder == 0) {
|
||||
$daysSinceOrder = $shopping_payment->created_at->diffInDays(now());
|
||||
return $daysSinceOrder >= $next_reminder->interval;
|
||||
}
|
||||
|
||||
// Wenn bereits Erinnerungen gesendet wurden, prüfe das nächste Intervall
|
||||
if ($shopping_payment->reminder_date) {
|
||||
$current_reminder = $payment_reminders[$shopping_payment->reminder - 1];
|
||||
$interval_difference = $next_reminder->interval - $current_reminder->interval;
|
||||
|
||||
$next_reminder_date = Carbon::parse($shopping_payment->reminder_date)->addDays($interval_difference);
|
||||
return now()->gte($next_reminder_date);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sendet eine Erinnerung für eine spezifische Zahlung
|
||||
*/
|
||||
private function sendReminderForPayment($shopping_payment)
|
||||
{
|
||||
try {
|
||||
$this->line(" 📧 Sende Erinnerung...");
|
||||
|
||||
$result = $this->paymentReminderService->sendReminder($shopping_payment);
|
||||
|
||||
if ($result) {
|
||||
$this->line(" ✅ Erinnerung erfolgreich gesendet");
|
||||
$this->stats['reminders_sent']++;
|
||||
|
||||
// Log für Cron-Job
|
||||
\Log::info('Payment reminder sent via cron', [
|
||||
'order_id' => $shopping_payment->shopping_order_id,
|
||||
'payment_id' => $shopping_payment->id,
|
||||
'reminder_count' => $shopping_payment->reminder + 1,
|
||||
'email' => $shopping_payment->shopping_order->shopping_user->billing_email ?? 'N/A'
|
||||
]);
|
||||
} else {
|
||||
$this->line(" ⚠️ Keine Erinnerung gesendet (keine weitere Erinnerung verfügbar)");
|
||||
$this->stats['skipped']++;
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$this->error(" ❌ Fehler beim Senden der Erinnerung: " . $e->getMessage());
|
||||
$this->stats['errors']++;
|
||||
|
||||
\Log::error('Error sending payment reminder', [
|
||||
'order_id' => $shopping_payment->shopping_order_id,
|
||||
'payment_id' => $shopping_payment->id,
|
||||
'error' => $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -24,13 +24,22 @@ class Kernel extends ConsoleKernel
|
|||
*/
|
||||
protected function schedule(Schedule $schedule)
|
||||
{
|
||||
$schedule->command('payments:accounts')
|
||||
/*$schedule->command('payments:accounts')
|
||||
->sendOutputTo(storage_path('logs/cron.log'))
|
||||
->appendOutputTo(storage_path('logs/cron-history.log'))
|
||||
->emailOutputOnFailure(config('app.exception_mail'))
|
||||
->onFailure(function () {
|
||||
\Log::error('Payments:accounts command failed');
|
||||
});
|
||||
*/
|
||||
|
||||
$schedule->command('payments:reminders')
|
||||
->sendOutputTo(storage_path('logs/cron.log'))
|
||||
->appendOutputTo(storage_path('logs/cron-reminders.log'))
|
||||
->emailOutputOnFailure(config('app.exception_mail'))
|
||||
->onFailure(function () {
|
||||
\Log::error('Payments:reminders command failed');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -4,6 +4,9 @@ namespace App\Exceptions;
|
|||
|
||||
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
|
||||
use Throwable;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Symfony\Component\ErrorHandler\Exception\FlattenException;
|
||||
use Symfony\Component\ErrorHandler\ErrorRenderer\HtmlErrorRenderer;
|
||||
|
||||
class Handler extends ExceptionHandler
|
||||
{
|
||||
|
|
@ -36,6 +39,9 @@ class Handler extends ExceptionHandler
|
|||
*/
|
||||
public function report(Throwable $exception)
|
||||
{
|
||||
if ($this->shouldReport($exception)) {
|
||||
$this->sendEmail($exception);
|
||||
}
|
||||
parent::report($exception);
|
||||
}
|
||||
|
||||
|
|
@ -52,4 +58,35 @@ class Handler extends ExceptionHandler
|
|||
{
|
||||
return parent::render($request, $exception);
|
||||
}
|
||||
|
||||
public function sendEmail(Throwable $exception)
|
||||
{
|
||||
try {
|
||||
$e = FlattenException::create($exception);
|
||||
$handler = new HtmlErrorRenderer(true); // boolean, true raises debug flag...
|
||||
|
||||
$css = $handler->getStylesheet();
|
||||
$content = $handler->getBody($e);
|
||||
//Mail::to(config('app.exception_mail'))->send(new MailContact($contact));
|
||||
// Verwende normale Mail-Klasse statt Facade, um Probleme bei der Initialisierung zu vermeiden
|
||||
$to = config('app.exception_mail');
|
||||
$subject = 'gruene-seele Exception: ' . \Request::fullUrl();
|
||||
|
||||
if ($to) {
|
||||
\Mail::send('emails.exception', compact('css', 'content'), function ($message) use ($to, $subject) {
|
||||
$message
|
||||
->to($to)
|
||||
->subject($subject)
|
||||
;
|
||||
});
|
||||
}
|
||||
} catch (Throwable $ex) {
|
||||
// Einfache Fehlerprotokollierung ohne Facade
|
||||
file_put_contents(
|
||||
storage_path('logs/laravel-' . date('Y-m-d') . '.log'),
|
||||
'[' . date('Y-m-d H:i:s') . '] exception-handler-error: ' . $ex->getMessage() . "\n",
|
||||
FILE_APPEND
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,33 +0,0 @@
|
|||
<?php
|
||||
namespace App\Exports;
|
||||
|
||||
use Maatwebsite\Excel\Excel;
|
||||
use Maatwebsite\Excel\Concerns\FromCollection;
|
||||
use Maatwebsite\Excel\Concerns\Exportable;
|
||||
use Maatwebsite\Excel\Concerns\WithHeadings;
|
||||
|
||||
class UserTeamExport implements FromCollection, WithHeadings
|
||||
{
|
||||
protected $collection;
|
||||
protected $headings;
|
||||
|
||||
use Exportable;
|
||||
|
||||
|
||||
public function __construct($data,$header)
|
||||
{
|
||||
$this->collection = $data;
|
||||
$this->headings = $header;
|
||||
}
|
||||
|
||||
public function collection()
|
||||
{
|
||||
return collect($this->collection);
|
||||
}
|
||||
|
||||
public function headings(): array
|
||||
{
|
||||
return [$this->headings];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
<?php
|
||||
namespace App\Exports;
|
||||
|
||||
use Maatwebsite\Excel\Excel;
|
||||
use Maatwebsite\Excel\Concerns\FromCollection;
|
||||
use Maatwebsite\Excel\Concerns\Exportable;
|
||||
use Maatwebsite\Excel\Concerns\WithHeadings;
|
||||
|
||||
class XLSExport implements FromCollection, WithHeadings
|
||||
{
|
||||
protected $collection;
|
||||
protected $headings;
|
||||
|
||||
use Exportable;
|
||||
|
||||
|
||||
public function __construct($data,$header)
|
||||
{
|
||||
$this->collection = $data;
|
||||
$this->headings = $header;
|
||||
}
|
||||
|
||||
public function collection()
|
||||
{
|
||||
return collect($this->collection);
|
||||
}
|
||||
|
||||
public function headings(): array
|
||||
{
|
||||
return [$this->headings];
|
||||
}
|
||||
|
||||
}
|
||||
41
app/Http/Controllers/Admin/PaymentReminderController.php
Normal file
41
app/Http/Controllers/Admin/PaymentReminderController.php
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Services\PaymentReminderService;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class PaymentReminderController extends Controller
|
||||
{
|
||||
|
||||
/* not used at the moment */
|
||||
private $paymentReminderService;
|
||||
|
||||
public function __construct(PaymentReminderService $paymentReminderService)
|
||||
{
|
||||
$this->paymentReminderService = $paymentReminderService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Zeige die Payment Reminders Übersicht
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$detailedData = $this->paymentReminderService->getDetailedPaymentsData();
|
||||
$summaryData = $this->paymentReminderService->getAllOpenPayments();
|
||||
|
||||
// Statistiken für die Übersicht
|
||||
$totalPayments = collect($detailedData)->count();
|
||||
$totalAmount = collect($detailedData)->sum('amount');
|
||||
$clearingTypes = collect($detailedData)->groupBy('clearingtype')->map->count();
|
||||
|
||||
return view('admin.payment.reminder.index', compact(
|
||||
'detailedData',
|
||||
'summaryData',
|
||||
'totalPayments',
|
||||
'totalAmount',
|
||||
'clearingTypes'
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,200 +0,0 @@
|
|||
<?php
|
||||
|
||||
|
||||
namespace App\Http\Controllers\Evo;
|
||||
use Auth;
|
||||
use Request;
|
||||
use App\User;
|
||||
use Carbon\Carbon;
|
||||
use App\Services\HTMLHelper;
|
||||
use App\Models\ShoppingOrder;
|
||||
use App\Exports\UserTeamExport;
|
||||
use App\Models\ShoppingOrderItem;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use App\Services\BusinessPlan\ExportBot;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
|
||||
class SalesController extends Controller
|
||||
{
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('admin');
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
|
||||
$this->setFilterVars();
|
||||
$data = [
|
||||
'filter_months' => HTMLHelper::getTransMonths(),
|
||||
'filter_years' => HTMLHelper::getYearRange(2022),
|
||||
];
|
||||
return view('admin.evaluation.salesvolume', $data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function download(){
|
||||
|
||||
if(Request::get('action') === "export"){
|
||||
$objects = $this->initSearch(false);
|
||||
$columns = [];
|
||||
$filename = "gs-absatzmengen-".session('product_sales_vol_filter_month').'_'.session('product_sales_vol_filter_year')."-export";
|
||||
$headers = array(
|
||||
'#',
|
||||
'Produkt',
|
||||
'Artikelnummer',
|
||||
'Menge',
|
||||
|
||||
);
|
||||
if($objects){
|
||||
foreach ($objects as $key => $obj){
|
||||
$columns[] = array(
|
||||
'id' => $key,
|
||||
'name' => $obj['name'],
|
||||
'number' => $obj['number'],
|
||||
'value' => $obj['value'],
|
||||
);
|
||||
}
|
||||
}
|
||||
return Excel::download(new UserTeamExport($columns, $headers), $filename.'.xls');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private function setFilterVars(){
|
||||
|
||||
if(!session('product_sales_vol_filter_month')){
|
||||
session(['product_sales_vol_filter_month' => intval(date('m'))]);
|
||||
}
|
||||
if(!session('product_sales_vol_filter_year')){
|
||||
session(['product_sales_vol_filter_year' => intval(date('Y'))]);
|
||||
}
|
||||
|
||||
if(Request::get('product_sales_vol_filter_month')){
|
||||
session(['product_sales_vol_filter_month' => Request::get('product_sales_vol_filter_month')]);
|
||||
}
|
||||
if(Request::get('product_sales_vol_filter_year')){
|
||||
session(['product_sales_vol_filter_year' => Request::get('product_sales_vol_filter_year')]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private function initSearch($returnColl = true)
|
||||
{
|
||||
$this->setFilterVars();
|
||||
|
||||
$date_start = Carbon::parse('01.'.session('product_sales_vol_filter_month').'.'.session('product_sales_vol_filter_year'))->format('Y-m-d H:i:s');
|
||||
$date_end = Carbon::parse('01.'.session('product_sales_vol_filter_month').'.'.session('product_sales_vol_filter_year'))->endOfMonth()->format('Y-m-d H:i:s');
|
||||
|
||||
$ShoppingOrders = ShoppingOrder::where('paid', 1)->where('mode', 'live')->whereBetween('created_at', [$date_start, $date_end])->get();
|
||||
|
||||
$objects = [];
|
||||
foreach($ShoppingOrders as $ShoppingOrder){
|
||||
foreach($ShoppingOrder->shopping_order_items as $shopping_order_item){
|
||||
|
||||
if($shopping_order_item->product){
|
||||
if(isset($objects[$shopping_order_item->product->id])){
|
||||
$value = intval($objects[$shopping_order_item->product->id]['value'] + $shopping_order_item->qty);
|
||||
$objects[$shopping_order_item->product->id]['value'] = $value;
|
||||
}else{
|
||||
$objects[$shopping_order_item->product->id] = [
|
||||
'name' => $shopping_order_item->product->name,
|
||||
'number' => $shopping_order_item->product->number,
|
||||
'value' => $shopping_order_item->qty
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if($returnColl){
|
||||
$collection = collect();
|
||||
|
||||
foreach($objects as $key => $obj){
|
||||
$collection->push([
|
||||
'id' => $key,
|
||||
'name' => $obj['name'],
|
||||
'number' => $obj['number'],
|
||||
'value' => $obj['value'],
|
||||
]);
|
||||
}
|
||||
return $collection;
|
||||
}
|
||||
return $objects;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function datatable(){
|
||||
|
||||
$collection = $this->initSearch(true);
|
||||
|
||||
$collect = collect([
|
||||
['id' => 1, 'name' => 'John', 'number'=>92012, 'value'=>123],
|
||||
['id' => 2, 'name' => 'Jane', 'number'=>92012, 'value'=>123],
|
||||
['id' => 3, 'name' => 'James', 'number'=>92012, 'value'=>123],
|
||||
]);
|
||||
|
||||
return \DataTables::of($collection)->toJson();
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/*private function testCheckFunction(){
|
||||
|
||||
//$date_start = Carbon::parse('01.'.session('product_sales_vol_filter_month').'.'.session('product_sales_vol_filter_year'))->format('Y-m-d');
|
||||
//$date_end = Carbon::parse('01.'.session('product_sales_vol_filter_month').'.'.session('product_sales_vol_filter_year'))->endOfMonth()->format('Y-m-d');
|
||||
|
||||
$date_start = Carbon::parse('01.01.2024')->format('Y-m-d H:i:s');
|
||||
$date_end = Carbon::parse('01.01.2024')->endOfMonth()->format('Y-m-d H:i:s');
|
||||
dump($date_start);
|
||||
dump($date_end);
|
||||
|
||||
$ShoppingOrders = ShoppingOrder::where('mode', 'live')->whereBetween('created_at', [$date_start, $date_end])->get();
|
||||
|
||||
$objects = [];
|
||||
$counter = 0;
|
||||
foreach($ShoppingOrders as $ShoppingOrder){
|
||||
foreach($ShoppingOrder->shopping_order_items as $shopping_order_item){
|
||||
|
||||
if($shopping_order_item->product){
|
||||
if($shopping_order_item->product->id === 122){
|
||||
//dump($shopping_order_item->qty);
|
||||
//$counter += $shopping_order_item->qty;
|
||||
if(isset($objects[$shopping_order_item->product->id])){
|
||||
$value = intval($objects[$shopping_order_item->product->id]['value'] + $shopping_order_item->qty);
|
||||
$objects[$shopping_order_item->product->id]['value'] = $value;
|
||||
}else{
|
||||
$objects[$shopping_order_item->product->id] = [
|
||||
'name' => $shopping_order_item->product->name,
|
||||
'number' => $shopping_order_item->product->number,
|
||||
'value' => $shopping_order_item->qty
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
$ShoppingOrderItems = ShoppingOrderItem::whereProductId(122)->whereBetween('created_at', [$date_start, $date_end])->get();
|
||||
$counter = 0;
|
||||
foreach($ShoppingOrderItems as $ShoppingOrderItem){
|
||||
$counter += $ShoppingOrderItem->qty;
|
||||
dump($ShoppingOrderItem->id);
|
||||
}
|
||||
// dump($objects);
|
||||
dump($counter);
|
||||
dd("OKAY");
|
||||
}*/
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -27,7 +27,7 @@ class ModalController extends Controller
|
|||
if(Request::ajax()){
|
||||
if($data['action'] === 'shopping-order-change-member'){
|
||||
$value = ShoppingOrder::find($data['id']);
|
||||
$route = route('admin_sales_customers_detail', [$value->id]);
|
||||
$route = route('admin_sales_detail', [$value->id]);
|
||||
$ret = view("admin.modal.member", compact('value', 'data', 'route'))->render();
|
||||
}
|
||||
if($data['action'] === 'shopping-user-change-member'){
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ class PaymentInvoiceController extends Controller
|
|||
|
||||
return \DataTables::eloquent($query)
|
||||
->addColumn('id', function (ShoppingOrder $ShoppingOrder) {
|
||||
return '<a href="' . route('admin_sales_customers_detail', [$ShoppingOrder->id]) . '" class="btn icon-btn btn-sm btn-primary"><span class="fa fa-edit"></span></a>';
|
||||
return '<a href="' . route('admin_sales_detail', [$ShoppingOrder->id]) . '" class="btn icon-btn btn-sm btn-primary"><span class="fa fa-edit"></span></a>';
|
||||
})
|
||||
->addColumn('total_shipping', function (ShoppingOrder $ShoppingOrder) {
|
||||
return $ShoppingOrder->getFormattedTotalShipping()." €";
|
||||
|
|
|
|||
147
app/Http/Controllers/PaymentReminderController.php
Normal file
147
app/Http/Controllers/PaymentReminderController.php
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
<?php
|
||||
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Carbon;
|
||||
use Request;
|
||||
use App\Models\PaymentReminder;
|
||||
use App\Models\ShoppingPayment;
|
||||
use App\Services\PaymentReminderService;
|
||||
|
||||
class PaymentReminderController extends Controller
|
||||
{
|
||||
|
||||
private $filter_user_status;
|
||||
private $paymentReminderService;
|
||||
|
||||
public function __construct(PaymentReminderService $paymentReminderService)
|
||||
{
|
||||
$this->middleware('auth');
|
||||
$this->paymentReminderService = $paymentReminderService;
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
// Hole die detaillierten Daten für die Tabellen-Ansicht
|
||||
$detailedData = $this->paymentReminderService->getDetailedPaymentsData();
|
||||
// $summaryData = $this->paymentReminderService->getAllOpenPayments();
|
||||
|
||||
// Statistiken für die Übersicht
|
||||
$totalPayments = collect($detailedData)->count();
|
||||
$totalAmount = collect($detailedData)->sum('amount')/100;
|
||||
$clearingTypes = collect($detailedData)->groupBy('clearingtype')->map->count();
|
||||
|
||||
$data = [
|
||||
'reminders' => PaymentReminder::all(),
|
||||
'detailedData' => $detailedData,
|
||||
//'summaryData' => $summaryData,
|
||||
'totalPayments' => $totalPayments,
|
||||
'totalAmount' => $totalAmount,
|
||||
'clearingTypes' => $clearingTypes,
|
||||
];
|
||||
return view('admin.payment.reminder.index', $data);
|
||||
}
|
||||
|
||||
public function create()
|
||||
{
|
||||
$reminder = new PaymentReminder();
|
||||
$reminder->active = true;
|
||||
$data = [
|
||||
'reminder' => $reminder,
|
||||
];
|
||||
return view('admin.payment.reminder.edit', $data);
|
||||
}
|
||||
|
||||
public function edit($id)
|
||||
{
|
||||
$data = [
|
||||
'reminder' => PaymentReminder::find($id),
|
||||
];
|
||||
return view('admin.payment.reminder.edit', $data);
|
||||
}
|
||||
|
||||
public function store()
|
||||
{
|
||||
$data = Request::all();
|
||||
$data['active'] = isset($data['active']) ? true : false;
|
||||
$data['action'] = isset($data['action']) ? $data['action'] : NULL;
|
||||
|
||||
if ($data['id'] === 'new') {
|
||||
PaymentReminder::create($data);
|
||||
} else {
|
||||
$reminder = PaymentReminder::find($data['id']);
|
||||
$reminder->update($data);
|
||||
}
|
||||
return redirect()->route('admin_payments_reminder')->with('success', 'Erinnerung gespeichert');
|
||||
}
|
||||
|
||||
public function action($action, $id)
|
||||
{
|
||||
|
||||
$payment = ShoppingPayment::find($id);
|
||||
if($action == 'send_reminder'){
|
||||
$bool = $this->paymentReminderService->sendReminder($payment);
|
||||
if($bool){
|
||||
\Session()->flash('alert-success', "Zahlungserinnerung gesendet");
|
||||
}else{
|
||||
\Session()->flash('alert-error', "Keine Zahlungserinnerung gesendet");
|
||||
}
|
||||
}
|
||||
if($action == 'no_payment'){
|
||||
$this->paymentReminderService->setNoNPayment($payment);
|
||||
\Session()->flash('alert-success', "Zahlung als nicht bezahlt markiert");
|
||||
}
|
||||
return redirect()->route('admin_payments_reminder');
|
||||
}
|
||||
|
||||
public function delete($id)
|
||||
{
|
||||
$reminder = PaymentReminder::find($id);
|
||||
$reminder->delete();
|
||||
return redirect()->route('admin_payments_reminder');
|
||||
}
|
||||
|
||||
public function logs()
|
||||
{
|
||||
// Hole die Log-Statistiken für verschiedene Zeiträume
|
||||
$stats7Days = $this->paymentReminderService->getLogStatistics(7);
|
||||
$stats30Days = $this->paymentReminderService->getLogStatistics(30);
|
||||
$stats90Days = $this->paymentReminderService->getLogStatistics(90);
|
||||
|
||||
// Hole die neuesten Logs
|
||||
$recentLogs = $this->paymentReminderService->getPaymentReminderLogs(50);
|
||||
|
||||
// Filter-Parameter
|
||||
$orderId = Request::get('order_id');
|
||||
$action = Request::get('action');
|
||||
$startDate = Request::get('start_date');
|
||||
$endDate = Request::get('end_date');
|
||||
|
||||
// Gefilterte Logs
|
||||
$filteredLogs = null;
|
||||
if ($orderId || $action || $startDate || $endDate) {
|
||||
if ($startDate && $endDate) {
|
||||
$filteredLogs = $this->paymentReminderService->getLogsForDateRange($startDate, $endDate);
|
||||
} elseif ($orderId) {
|
||||
$filteredLogs = $this->paymentReminderService->getLogsForPayment($orderId);
|
||||
} elseif ($action) {
|
||||
$filteredLogs = $this->paymentReminderService->getPaymentReminderLogs(100, null, $action);
|
||||
}
|
||||
}
|
||||
|
||||
$data = [
|
||||
'stats7Days' => $stats7Days,
|
||||
'stats30Days' => $stats30Days,
|
||||
'stats90Days' => $stats90Days,
|
||||
'recentLogs' => $recentLogs,
|
||||
'filteredLogs' => $filteredLogs,
|
||||
'orderId' => $orderId,
|
||||
'action' => $action,
|
||||
'startDate' => $startDate,
|
||||
'endDate' => $endDate,
|
||||
];
|
||||
|
||||
return view('admin.payment.reminder.logs', $data);
|
||||
}
|
||||
}
|
||||
|
|
@ -4,7 +4,6 @@ namespace App\Http\Controllers;
|
|||
|
||||
use Request;
|
||||
use App\Models\Setting;
|
||||
use App\Models\UserShop;
|
||||
use App\Services\Payment;
|
||||
use App\Models\ShoppingUser;
|
||||
use App\Models\ShoppingOrder;
|
||||
|
|
@ -13,6 +12,7 @@ use App\Models\ShoppingPayment;
|
|||
use App\Models\PaymentTransaction;
|
||||
use App\Services\CustomerPriority;
|
||||
use App\Repositories\InvoiceRepository;
|
||||
use App\Services\PaymentService;
|
||||
|
||||
class SalesController extends Controller
|
||||
{
|
||||
|
|
@ -21,7 +21,167 @@ class SalesController extends Controller
|
|||
$this->middleware('admin');
|
||||
}
|
||||
|
||||
public function users(){
|
||||
public function index(){
|
||||
|
||||
if(Request::get('reset') === 'filter'){
|
||||
set_user_attr('filter_txaction', null);
|
||||
set_user_attr('filter_member_id', null);
|
||||
set_user_attr('filter_art', null);
|
||||
set_user_attr('filter_shipped', null);
|
||||
return redirect(route('admin_sales'));
|
||||
}
|
||||
//set Filter!
|
||||
$filter_members = ShoppingOrder::join('users', 'member_id', '=', 'users.id')->groupBy('member_id')->join('user_accounts', 'account_id', '=', 'user_accounts.id')->select('users.id', 'users.email', 'user_accounts.first_name', 'user_accounts.last_name')->get();
|
||||
$data = [
|
||||
'filter_members' => $filter_members,
|
||||
];
|
||||
return view('admin.sales.index', $data);
|
||||
}
|
||||
|
||||
public function detail($id){
|
||||
|
||||
$ShoppingOrder = ShoppingOrder::find($id);
|
||||
if($ShoppingOrder->shipped == 0){
|
||||
$ShoppingOrder->shipped = 1;
|
||||
$ShoppingOrder->save();
|
||||
}
|
||||
$data = [
|
||||
'shopping_order' => $ShoppingOrder,
|
||||
'isAdmin' => true,
|
||||
'isView' => $ShoppingOrder->auth_user_id ? 'sales_user' : 'sales_customer',
|
||||
];
|
||||
|
||||
return view('admin.sales.detail', $data);
|
||||
}
|
||||
|
||||
public function detailStore($id){
|
||||
|
||||
$data = Request::all();
|
||||
$change_member_error = false;
|
||||
if($data['action']==='shopping-order-change-member'){
|
||||
if(!isset($data['change_member_key']) || $data['change_member_key'] !== config('main.edit_data_pass')){
|
||||
$change_member_error = "Das Passwort ist falsch.";
|
||||
}else{
|
||||
//change
|
||||
$shopping_order = ShoppingOrder::findOrFail($data['id']);
|
||||
CustomerPriority::newMemberForOrder($shopping_order, $data['change_member_id'], $data['customer_set_member_for']);
|
||||
\Session()->flash('alert-save', true);
|
||||
return redirect(route('admin_sales_detail', [$shopping_order->id]));
|
||||
}
|
||||
}
|
||||
if($data['action']==='shopping-user-is-like-member'){
|
||||
if(!isset($data['change_member_key']) || $data['change_member_key'] !== config('main.edit_data_pass')){
|
||||
\Session()->flash('alert-error', 'Das Passwort ist falsch.');
|
||||
return redirect($data['back']);
|
||||
}else{
|
||||
if(!isset($data['is_like_shopping_user_id'])){
|
||||
\Session()->flash('alert-error', 'Keine Änderung ausgewählt');
|
||||
return redirect($data['back']);
|
||||
}
|
||||
$shopping_user = ShoppingUser::findOrFail($data['id']);
|
||||
$set_like_shopping_user = ShoppingUser::findOrFail($data['is_like_shopping_user_id']);
|
||||
$send_member_mail = isset($data['send_member_mail']) ? true : false;
|
||||
$change_shopping_user = isset($data['change_shopping_user']) ? true : false;
|
||||
//Mail send in setIsLike
|
||||
CustomerPriority::setIsLike($shopping_user, $set_like_shopping_user, $send_member_mail, $change_shopping_user);
|
||||
\Session()->flash('alert-save', true);
|
||||
return redirect($data['back']);
|
||||
}
|
||||
}
|
||||
$ShoppingOrder = ShoppingOrder::find($id);
|
||||
$data = [
|
||||
'change_member_error' => $change_member_error,
|
||||
'shopping_order' => $ShoppingOrder,
|
||||
'isAdmin' => true,
|
||||
'isView' => $ShoppingOrder->auth_user_id ? 'sales_user' : 'sales_customer',
|
||||
];
|
||||
return view('admin.sales.detail', $data);
|
||||
}
|
||||
|
||||
public function datatable(){
|
||||
|
||||
$query = ShoppingOrder::with('shopping_user', 'shopping_payments')->select('shopping_orders.*');
|
||||
|
||||
set_user_attr('filter_txaction', Request::get('filter_txaction'));
|
||||
if(Request::get('filter_txaction') != ""){
|
||||
if(Request::get('filter_txaction') === 'NULL'){
|
||||
$query->where('txaction', '=', NULL);
|
||||
|
||||
}else{
|
||||
$query->where('txaction', '=', Request::get('filter_txaction'));
|
||||
}
|
||||
}
|
||||
set_user_attr('filter_member_id', Request::get('filter_member_id'));
|
||||
if(Request::get('filter_member_id') != ""){
|
||||
$query->where('member_id', '=', Request::get('filter_member_id'));
|
||||
}
|
||||
|
||||
set_user_attr('filter_art', Request::get('filter_art'));
|
||||
if(Request::get('filter_art') != ""){
|
||||
if(Request::get('filter_art') === 'user_order'){
|
||||
$query->where('shopping_orders.auth_user_id', '!=', NULL)->where('payment_for', '!=', 6);
|
||||
}elseif(Request::get('filter_art') === 'customer_order'){
|
||||
$query->where('shopping_orders.auth_user_id', NULL);
|
||||
}elseif(Request::get('filter_art') === 'user_for_customer'){
|
||||
$query->where('shopping_user_id', '!=', NULL)->where('payment_for', '=', 6);
|
||||
}
|
||||
// $query->where('payment_for', '=', Request::get('filter_art'));
|
||||
}
|
||||
set_user_attr('filter_shipped', Request::get('filter_shipped'));
|
||||
if(Request::get('filter_shipped') != ""){
|
||||
$query->where('shipped', '=', Request::get('filter_shipped'));
|
||||
}
|
||||
return \DataTables::eloquent($query)
|
||||
->addColumn('id', function (ShoppingOrder $ShoppingOrder) {
|
||||
return '<a href="' . route('admin_sales_detail', [$ShoppingOrder->id]) . '" class="btn icon-btn btn-sm btn-primary"><span class="fa fa-edit"></span></a>';
|
||||
})
|
||||
->addColumn('created_at', function (ShoppingOrder $ShoppingOrder) {
|
||||
return $ShoppingOrder->created_at->format("d.m.Y");
|
||||
})
|
||||
->addColumn('txaction', function (ShoppingOrder $ShoppingOrder) {
|
||||
return Payment::getShoppingOrderBadge($ShoppingOrder);
|
||||
})
|
||||
->addColumn('total_shipping', function (ShoppingOrder $ShoppingOrder) {
|
||||
return $ShoppingOrder->getFormattedTotalShipping()." €";
|
||||
})
|
||||
->addColumn('payment', function (ShoppingOrder $ShoppingOrder) {
|
||||
return $ShoppingOrder->getLastShoppingPayment('getPaymentType');
|
||||
})
|
||||
->addColumn('shipped', function (ShoppingOrder $ShoppingOrder) {
|
||||
return '<span class="badge badge-pill badge-'.$ShoppingOrder->getShippedColor().'">'.$ShoppingOrder->getShippedType().'</span>';
|
||||
})
|
||||
->addColumn('payment_for', function (ShoppingOrder $ShoppingOrder) {
|
||||
return Payment::getPaymentForTypeBadge($ShoppingOrder);
|
||||
})
|
||||
->addColumn('reference', function (ShoppingOrder $ShoppingOrder) {
|
||||
return $ShoppingOrder->getLastShoppingPayment('reference');
|
||||
})
|
||||
->addColumn('member_id', function (ShoppingOrder $ShoppingOrder) {
|
||||
if($ShoppingOrder->member_id) {
|
||||
return $ShoppingOrder->member_id ? '<a href="' . route('admin_lead_edit', [$ShoppingOrder->member_id]) . '">' . $ShoppingOrder->member->getFullName() . '</a>' : '';
|
||||
}
|
||||
if($ShoppingOrder->shopping_user && $ShoppingOrder->shopping_user->is_like){
|
||||
return '<button type="button" class="btn btn-xs btn-outline-info" data-toggle="modal" data-target="#modals-load-content"
|
||||
data-id="'.$ShoppingOrder->shopping_user->id.'"
|
||||
data-action="shopping-user-is-like-member"
|
||||
data-back="'.route('admin_sales').'"
|
||||
data-modal="modal-xl"
|
||||
data-route="'.route('modal_load').'"><span class="fa fa-edit"></span> Vertriebspartner zuordnen</button>';
|
||||
}
|
||||
return '';
|
||||
})
|
||||
|
||||
->orderColumn('id', 'id $1')
|
||||
->orderColumn('txaction', 'txaction $1')
|
||||
->orderColumn('payment_for', 'payment_for $1')
|
||||
->orderColumn('member_id', 'member_id $1')
|
||||
->orderColumn('shipped', 'shipped $1')
|
||||
->orderColumn('total_shipping', 'total_shipping $1')
|
||||
->rawColumns(['id', 'member_id', 'txaction', 'user_shop_id', 'payment_for', 'shipped'])
|
||||
->make(true);
|
||||
}
|
||||
|
||||
/*public function users(){
|
||||
|
||||
if(Request::get('reset') === 'filter'){
|
||||
return redirect(route('admin_sales_users'));
|
||||
|
|
@ -105,7 +265,7 @@ class SalesController extends Controller
|
|||
if(Request::get('reset') === 'filter'){
|
||||
set_user_attr('filter_txaction', null);
|
||||
set_user_attr('filter_member_id', null);
|
||||
return redirect(route('admin_sales_customers'));
|
||||
return redirect(route('admin_sales'));
|
||||
}
|
||||
$filter_members = ShoppingOrder::join('users', 'member_id', '=', 'users.id')->groupBy('member_id')->join('user_accounts', 'account_id', '=', 'user_accounts.id')->select('users.id', 'users.email', 'user_accounts.first_name', 'user_accounts.last_name')->get(); //->pluck('email', 'id')->unique()->toArray();
|
||||
$data = [
|
||||
|
|
@ -141,7 +301,7 @@ class SalesController extends Controller
|
|||
$shopping_order = ShoppingOrder::findOrFail($data['id']);
|
||||
CustomerPriority::newMemberForOrder($shopping_order, $data['change_member_id'], $data['customer_set_member_for']);
|
||||
\Session()->flash('alert-save', true);
|
||||
return redirect(route('admin_sales_customers_detail', [$shopping_order->id]));
|
||||
return redirect(route('admin_sales_detail', [$shopping_order->id]));
|
||||
}
|
||||
}
|
||||
if($data['action']==='shopping-user-is-like-member'){
|
||||
|
|
@ -169,7 +329,7 @@ class SalesController extends Controller
|
|||
'isAdmin' => true,
|
||||
'isView' => 'sales_customer',
|
||||
];
|
||||
return view('admin.sales.customer_detail', $data);
|
||||
return view('admin.sales._detail', $data);
|
||||
}
|
||||
|
||||
public function customersDatatable(){
|
||||
|
|
@ -192,7 +352,7 @@ class SalesController extends Controller
|
|||
|
||||
return \DataTables::eloquent($query)
|
||||
->addColumn('id', function (ShoppingOrder $ShoppingOrder) {
|
||||
return '<a href="' . route('admin_sales_customers_detail', [$ShoppingOrder->id]) . '" class="btn icon-btn btn-sm btn-primary"><span class="fa fa-edit"></span></a>';
|
||||
return '<a href="' . route('admin_sales_detail', [$ShoppingOrder->id]) . '" class="btn icon-btn btn-sm btn-primary"><span class="fa fa-edit"></span></a>';
|
||||
})
|
||||
->addColumn('created_at', function (ShoppingOrder $ShoppingOrder) {
|
||||
return $ShoppingOrder->created_at->format("d.m.Y");
|
||||
|
|
@ -223,7 +383,7 @@ class SalesController extends Controller
|
|||
return '<button type="button" class="btn btn-xs btn-outline-info" data-toggle="modal" data-target="#modals-load-content"
|
||||
data-id="'.$ShoppingOrder->shopping_user->id.'"
|
||||
data-action="shopping-user-is-like-member"
|
||||
data-back="'.route('admin_sales_customers').'"
|
||||
data-back="'.route('admin_sales').'"
|
||||
data-modal="modal-xl"
|
||||
data-route="'.route('modal_load').'"><span class="fa fa-edit"></span> Vertriebspartner zuordnen</button>';
|
||||
}
|
||||
|
|
@ -238,7 +398,7 @@ class SalesController extends Controller
|
|||
->orderColumn('total_shipping', 'total_shipping $1')
|
||||
->rawColumns(['id', 'member_id', 'txaction', 'user_shop_id', 'payment_for', 'shipped'])
|
||||
->make(true);
|
||||
}
|
||||
}*/
|
||||
|
||||
public function store(){
|
||||
$data = Request::all();
|
||||
|
|
@ -306,67 +466,11 @@ class SalesController extends Controller
|
|||
|
||||
}
|
||||
|
||||
|
||||
/* txaction ändern
|
||||
änderung der txaction von der Bestellung, Status Zahlung, offen, bezahlt, keine zahlung */
|
||||
if($data['action'] === 'store_txaction' && isset($data['txaction']) && isset($data['payment_id'])){
|
||||
$shopping_order = ShoppingOrder::findOrFail($data['id']);
|
||||
$shopping_payment = ShoppingPayment::findOrFail($data['payment_id']);
|
||||
|
||||
if($shopping_payment->txaction === $data['txaction']){
|
||||
return back();
|
||||
|
||||
}
|
||||
//shopping_order_margin Bestellung im partner Center
|
||||
if($shopping_order->shopping_order_margin && $shopping_order->shopping_order_margin->from_payment_credit > 0){
|
||||
$last_UserPayCredit = UserPayCredit::where('shopping_order_id', $shopping_order->id)->whereIn('status', [2, 4])->orderBy('id', 'DESC')->first();
|
||||
//Status Keine Zahlung, Guthaben zurückführen, wenn status 2 / deduction from payment
|
||||
if($last_UserPayCredit && $data['txaction'] === 'non' && $last_UserPayCredit->status === 2){
|
||||
Payment::handelUserPayCredits($shopping_order, 'return');
|
||||
}
|
||||
//Status Zahlung, voher gab es eine Storno, Guthaben abziehen wenn status 4 / return from order
|
||||
if($last_UserPayCredit && $last_UserPayCredit->status === 4 && ($data['txaction'] === 'open' || $data['txaction'] === 'paid')){
|
||||
Payment::handelUserPayCredits($shopping_order, 'deduction');
|
||||
}
|
||||
}
|
||||
$payt = PaymentTransaction::create([
|
||||
'shopping_payment_id' => $shopping_payment->id,
|
||||
'request' => 'transaction',
|
||||
'txid' => 0,
|
||||
'userid' => 0,
|
||||
'status' => $shopping_payment->clearingtype,
|
||||
'transmitted_data' => NULL,
|
||||
'txaction' => $data['txaction'],
|
||||
'mode' => $shopping_payment->mode,
|
||||
]);
|
||||
|
||||
$shopping_order->txaction = $data['txaction'];
|
||||
$shopping_order->paid = $payt->txaction === 'paid' ? true : false;
|
||||
$shopping_order->save();
|
||||
$shopping_payment->txaction = $data['txaction'];
|
||||
$shopping_payment->save();
|
||||
if($payt->status === 'vor' && $payt->txaction === 'paid'){
|
||||
$send_link = Payment::paymentStatusPaidAction($shopping_order, true);
|
||||
}
|
||||
|
||||
//handel credit loading by change when by $shopping_order_item->handl
|
||||
if($shopping_order->shopping_user->is_for === 'cr'){
|
||||
$last_UserPayCredit = UserPayCredit::where('shopping_order_id', $shopping_order->id)->whereIn('status', [7, 8])->orderBy('id', 'DESC')->first();
|
||||
//Status Keine Zahlung, Guthaben abziehen, wenn status 7 <- wurde aufgeladen
|
||||
if($data['txaction'] === 'non' && $last_UserPayCredit && $last_UserPayCredit->status === 7){
|
||||
Payment::handelUserPayChargingCredits($shopping_order, 'remove');
|
||||
}
|
||||
//Status Zahlung, voher gab es eine Storno, Guthaben wieder aufladen, wenn bezahlt wenn status 8
|
||||
if($last_UserPayCredit && $last_UserPayCredit->status === 8 && $data['txaction'] === 'paid'){
|
||||
Payment::handelUserPayChargingCredits($shopping_order, 'add');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$edata = [
|
||||
'mode' => $payt->mode,
|
||||
'txaction' => $payt->txaction,
|
||||
'send_link' => false,
|
||||
];
|
||||
//TODO can send MAIL
|
||||
Payment::paymentStatusSendMail($shopping_order, $shopping_payment, $edata);
|
||||
PaymentService::updateTransactionStatus($data['id'], $data['txaction'], $data['payment_id']);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -391,9 +495,21 @@ class SalesController extends Controller
|
|||
}else{
|
||||
$user_invoice = $invoice_repo->create($data);
|
||||
}
|
||||
return redirect(route('admin_sales_users_detail', [$shopping_order->id]));
|
||||
return redirect(route('admin_sales_detail', [$shopping_order->id]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function sendLogisticMail($id){
|
||||
$shopping_order = ShoppingOrder::findOrFail($id);
|
||||
|
||||
if(\App\Services\Invoice::isInvoice($shopping_order)){
|
||||
\App\Services\Invoice::sendLogisticMail($shopping_order);
|
||||
\Session()->flash('alert-success', "Rechnung / Lieferschein wurde an den Versand gesendet.");
|
||||
}else{
|
||||
\Session()->flash('alert-error', "Keine Rechnung vorhanden.");
|
||||
}
|
||||
return redirect(route('admin_sales_detail', [$shopping_order->id]));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -43,7 +43,6 @@ class SalesController extends Controller
|
|||
|
||||
public function download()
|
||||
{
|
||||
|
||||
$this->setFilterVars();
|
||||
|
||||
if (Request::get('action') === "filter") {
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ class PromotionController extends Controller
|
|||
if(isset($data['action']) && $data['action'] === 'save-user-promotion'){
|
||||
$rules = array(
|
||||
'name' => 'required',
|
||||
'user_promotion_url' => ' required|alpha_dash|profanity|'.'unique:promotion_users,url,'.$id.',id'.'|min:4|max:20|full_word_check',
|
||||
'user_promotion_url' => ' required|alpha_dash|'.'unique:promotion_users,url,'.$id.',id'.'|min:4|max:20|full_word_check',
|
||||
);
|
||||
Validator::extend('full_word_check', function ($attribute, $value, $parameters, $validator) {
|
||||
$profanity = \App\Models\Setting::getContentBySlug('promotion_user_url_profanity');
|
||||
|
|
@ -107,7 +107,7 @@ class PromotionController extends Controller
|
|||
$unique .= ','.$data['puid'].',id';
|
||||
}
|
||||
$rules = array(
|
||||
'user_promotion_url' => ' required|alpha_dash|profanity|'.$unique.'|min:4|max:20|full_word_check',
|
||||
'user_promotion_url' => ' required|alpha_dash|'.$unique.'|min:4|max:20|full_word_check',
|
||||
);
|
||||
Validator::extend('full_word_check', function ($attribute, $value, $parameters, $validator) {
|
||||
$profanity = \App\Models\Setting::getContentBySlug('promotion_user_url_profanity');
|
||||
|
|
|
|||
|
|
@ -1,53 +0,0 @@
|
|||
<?php
|
||||
|
||||
|
||||
namespace App\Http\Controllers\User;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\User;
|
||||
use Request;
|
||||
use Carbon;
|
||||
use App\Models\ShoppingOrder;
|
||||
|
||||
|
||||
class RevenueController extends Controller
|
||||
{
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('auth');
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
$start = 2021;
|
||||
$end = date('Y');
|
||||
$years = range($start, $end);
|
||||
|
||||
if(Request::get('filter_sales_year')){
|
||||
$active_year = Request::get('filter_sales_year');
|
||||
}else{
|
||||
$active_year = $end;
|
||||
}
|
||||
|
||||
$date1 = Carbon::parse('01.01.'.$active_year." 00:00:00")->format('Y-m-d H:i:s');
|
||||
$date2 = Carbon::parse('31.12.'.$active_year." 23:59:59")->toDateString();
|
||||
|
||||
|
||||
$values = ShoppingOrder::where('shopping_orders.auth_user_id', '!=', NULL) //::with('shopping_user', )->select('shopping_orders.*')
|
||||
->where('mode', '=', 'live')
|
||||
->where('paid', '=', 1)
|
||||
->whereHas('shopping_order_items', function($q) {
|
||||
|
||||
$q->where('product_id', 34)->OrWhere('product_id', 35)->OrWhere('product_id', 36)->OrWhere('product_id', 67)->OrWhere('product_id', 69);
|
||||
})
|
||||
->whereBetween('created_at', [$date1, $date2])
|
||||
->get();
|
||||
|
||||
$data = [
|
||||
'years' => $years,
|
||||
'active_year' => $active_year,
|
||||
'values' => $values,
|
||||
];
|
||||
return view('user.revenue.index', $data);
|
||||
}
|
||||
}
|
||||
|
|
@ -54,7 +54,7 @@ class ShopController extends Controller
|
|||
if(isset($data['action']) && $data['action'] === 'save-user-shop'){
|
||||
$rules = array(
|
||||
'name' => 'required',
|
||||
'user_shop_url' => ' required|alpha_dash|profanity|'.'unique:user_shops,url,'.$user->shop->id.',id'.'|min:4|max:20|full_word_check',
|
||||
'user_shop_url' => ' required|alpha_dash|'.'unique:user_shops,url,'.$user->shop->id.',id'.'|min:4|max:20|full_word_check',
|
||||
);
|
||||
Validator::extend('full_word_check', function ($attribute, $value, $parameters, $validator) {
|
||||
$profanity = \App\Models\Setting::getContentBySlug('promotion_user_url_profanity');
|
||||
|
|
@ -84,7 +84,7 @@ class ShopController extends Controller
|
|||
$unique .= ','.$data['usid'].',id';
|
||||
}
|
||||
$rules = array(
|
||||
'user_shop_url' => ' required|alpha_dash|profanity|'.$unique.'|min:4|max:20|full_word_check',
|
||||
'user_shop_url' => ' required|alpha_dash|'.$unique.'|min:4|max:20|full_word_check',
|
||||
);
|
||||
Validator::extend('full_word_check', function ($attribute, $value, $parameters, $validator) {
|
||||
$profanity = \App\Models\Setting::getContentBySlug('promotion_user_url_profanity');
|
||||
|
|
|
|||
|
|
@ -270,7 +270,7 @@ class UserShopController extends Controller
|
|||
|
||||
if(Request::get('shop_submit') == 'check'){
|
||||
$rules = array(
|
||||
'user_shop_name' => ' required|alpha_dash|profanity|unique:user_shops,name|min:4|max:20|full_word_check',
|
||||
'user_shop_name' => ' required|alpha_dash|unique:user_shops,name|min:4|max:20|full_word_check',
|
||||
);
|
||||
Validator::extend('full_word_check', function ($attribute, $value, $parameters, $validator) {
|
||||
if(in_array($value, config('profanity.full_word_check'))){
|
||||
|
|
@ -291,7 +291,7 @@ class UserShopController extends Controller
|
|||
if(Request::get('shop_submit') == 'action') {
|
||||
|
||||
$rules = array(
|
||||
'user_shop_name' => ' required|alpha_dash|profanity|unique:user_shops,name|min:4|max:20|full_word_check',
|
||||
'user_shop_name' => ' required|alpha_dash|unique:user_shops,name|min:4|max:20|full_word_check',
|
||||
);
|
||||
Validator::extend('full_word_check', function ($attribute, $value, $parameters, $validator) {
|
||||
if(in_array($value, config('profanity.full_word_check'))){
|
||||
|
|
@ -381,7 +381,7 @@ class UserShopController extends Controller
|
|||
public function checkUserShopName(){
|
||||
|
||||
$rules = array(
|
||||
'user_shop_name' => ' required|alpha_dash|profanity|unique:user_shops,name|min:4|max:20|full_word_check',
|
||||
'user_shop_name' => ' required|alpha_dash|unique:user_shops,name|min:4|max:20|full_word_check',
|
||||
);
|
||||
Validator::extend('full_word_check', function ($attribute, $value, $parameters, $validator) {
|
||||
if(in_array($value, config('profanity.full_word_check'))){
|
||||
|
|
|
|||
|
|
@ -3,14 +3,15 @@
|
|||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Mail\MailActivateUser;
|
||||
use App\User;
|
||||
use Auth;
|
||||
use Validator;
|
||||
use Request;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Connection;
|
||||
use App\Mail\MailActivateUser;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Str;
|
||||
use Request;
|
||||
use Validator;
|
||||
|
||||
class UserUpdateEmailController extends Controller
|
||||
{
|
||||
|
|
@ -152,7 +153,7 @@ class UserUpdateEmailController extends Controller
|
|||
|
||||
protected function getToken()
|
||||
{
|
||||
return hash_hmac('sha256', str_random(40), config('app.key'));
|
||||
return hash_hmac('sha256', Str::random(40), config('app.key'));
|
||||
}
|
||||
|
||||
public function createActivation($user, array $data)
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ class Kernel extends HttpKernel
|
|||
*/
|
||||
protected $middleware = [
|
||||
\App\Http\Middleware\TrustProxies::class,
|
||||
\Fruitcake\Cors\HandleCors::class,
|
||||
\Illuminate\Http\Middleware\HandleCors::class,
|
||||
\App\Http\Middleware\CheckForMaintenanceMode::class,
|
||||
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
|
||||
\App\Http\Middleware\TrimStrings::class,
|
||||
|
|
|
|||
|
|
@ -2,15 +2,15 @@
|
|||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Illuminate\Http\Middleware\TrustProxies as Middleware;
|
||||
use Illuminate\Http\Request;
|
||||
use Fideloper\Proxy\TrustProxies as Middleware;
|
||||
|
||||
class TrustProxies extends Middleware
|
||||
{
|
||||
/**
|
||||
* The trusted proxies for this application.
|
||||
*
|
||||
* @var array|string
|
||||
* @var array|string|null
|
||||
*/
|
||||
protected $proxies;
|
||||
|
||||
|
|
@ -19,5 +19,10 @@ class TrustProxies extends Middleware
|
|||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $headers = Request::HEADER_X_FORWARDED_ALL;
|
||||
protected $headers =
|
||||
Request::HEADER_X_FORWARDED_FOR |
|
||||
Request::HEADER_X_FORWARDED_HOST |
|
||||
Request::HEADER_X_FORWARDED_PORT |
|
||||
Request::HEADER_X_FORWARDED_PROTO |
|
||||
Request::HEADER_X_FORWARDED_AWS_ELB;
|
||||
}
|
||||
|
|
|
|||
188
app/Libraries/MyPDFMerger.php
Normal file
188
app/Libraries/MyPDFMerger.php
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
<?php
|
||||
namespace App\Libraries;
|
||||
|
||||
//use FPDI in myMerge v2
|
||||
//use FPDF;
|
||||
//use FPDI;
|
||||
|
||||
class MyPDFMerger
|
||||
{
|
||||
private $_files; //['form.pdf'] ["1,2,4, 5-19"]
|
||||
private $_fpdi;
|
||||
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
/* if(!class_exists("FPDF")) {
|
||||
require_once(__DIR__.'/fpdf/fpdf.php');
|
||||
}
|
||||
if(!class_exists("FPDI")) {
|
||||
require_once(__DIR__.'/fpdi/fpdi.php');
|
||||
}*/
|
||||
}
|
||||
|
||||
public function addPDF($filepath, $pages = 'all')
|
||||
{
|
||||
if (file_exists($filepath)) {
|
||||
if (strtolower($pages) != 'all') {
|
||||
$pages = $this->_rewritepages($pages);
|
||||
}
|
||||
|
||||
$this->_files[] = array($filepath, $pages);
|
||||
} else {
|
||||
throw new \exception("Could not locate PDF on '$filepath'");
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function myMerge($outputmode = 'browser', $outputpath = 'newfile.pdf', $theme = false)
|
||||
{
|
||||
if (!isset($this->_files) || !is_array($this->_files)): throw new \exception("No PDFs to merge."); endif;
|
||||
|
||||
$fpdi = new \setasign\Fpdi\Fpdi();
|
||||
$first = 1;
|
||||
|
||||
//
|
||||
//merger operations
|
||||
foreach ($this->_files as $file) {
|
||||
$filename = $file[0];
|
||||
$filepages = $file[1];
|
||||
|
||||
|
||||
$count = $fpdi->setSourceFile($filename);
|
||||
|
||||
//add the pages
|
||||
if ($filepages == 'all') {
|
||||
for ($i = 1; $i <= $count; $i++) {
|
||||
$count = $fpdi->setSourceFile($filename);
|
||||
$template = $fpdi->importPage($i);
|
||||
$size = $fpdi->getTemplateSize($template);
|
||||
$orientation = ($size['height'] > $size['width']) ? 'P' : 'L';
|
||||
|
||||
$fpdi->AddPage($orientation, array($size['width'], $size['height']));
|
||||
if($theme){
|
||||
$fpdi->setSourceFile(__DIR__ . '/../../public/pdf/'.$theme.'-'.$first.'.pdf');
|
||||
if($first == 1){
|
||||
$first = 2;
|
||||
}
|
||||
$backId = $fpdi->importPage(1);
|
||||
$fpdi->useTemplate($backId);
|
||||
|
||||
}
|
||||
$fpdi->useTemplate($template);
|
||||
}
|
||||
} else {
|
||||
foreach ($filepages as $page) {
|
||||
$count = $fpdi->setSourceFile($filename);
|
||||
if (!$template = $fpdi->importPage($page)): throw new \exception("Could not load page '$page' in PDF '$filename'. Check that the page exists."); endif;
|
||||
$size = $fpdi->getTemplateSize($template);
|
||||
$orientation = ($size['h'] > $size['w']) ? 'P' : 'L';
|
||||
|
||||
$fpdi->AddPage($orientation, array($size['w'], $size['h']));
|
||||
if($theme){
|
||||
$fpdi->setSourceFile(__DIR__ . '/../../public/pdf/'.$theme.'-'.$first.'.pdf');
|
||||
if($first == 1){
|
||||
$first = 2;
|
||||
}
|
||||
$backId = $fpdi->importPage(1);
|
||||
$fpdi->useTemplate($backId);
|
||||
}
|
||||
|
||||
$fpdi->useTemplate($template);
|
||||
}
|
||||
}
|
||||
//after first file (invoice) on bpaper
|
||||
$slug = false;
|
||||
}
|
||||
|
||||
//output operations
|
||||
$mode = $this->_switchmode($outputmode);
|
||||
|
||||
if ($mode == 'S') {
|
||||
return $fpdi->Output($outputpath, 'S');
|
||||
} else {
|
||||
if ($fpdi->Output($outputpath, $mode) == '') {
|
||||
return true;
|
||||
} else {
|
||||
throw new \exception("Error outputting PDF to '$outputmode'.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* FPDI uses single characters for specifying the output location. Change our more descriptive string into proper format.
|
||||
* @param $mode
|
||||
* @return Character
|
||||
*/
|
||||
private function _switchmode($mode)
|
||||
{
|
||||
switch (strtolower($mode)) {
|
||||
case 'download':
|
||||
return 'D';
|
||||
break;
|
||||
case 'browser':
|
||||
return 'I';
|
||||
break;
|
||||
case 'file':
|
||||
return 'F';
|
||||
break;
|
||||
case 'string':
|
||||
return 'S';
|
||||
break;
|
||||
default:
|
||||
return 'I';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes our provided pages in the form of 1,3,4,16-50 and creates an array of all pages
|
||||
* @param $pages
|
||||
* @return array
|
||||
* @throws exception
|
||||
*/
|
||||
private function _rewritepages($pages)
|
||||
{
|
||||
$pages = str_replace(' ', '', $pages);
|
||||
$part = explode(',', $pages);
|
||||
|
||||
//parse hyphens
|
||||
foreach ($part as $i) {
|
||||
$ind = explode('-', $i);
|
||||
|
||||
if (count($ind) == 2) {
|
||||
$x = $ind[0]; //start page
|
||||
$y = $ind[1]; //end page
|
||||
|
||||
if ($x > $y): throw new \exception("Starting page, '$x' is greater than ending page '$y'.");
|
||||
return false; endif;
|
||||
|
||||
//add middle pages
|
||||
while ($x <= $y): $newpages[] = (int)$x;
|
||||
$x++; endwhile;
|
||||
} else {
|
||||
$newpages[] = (int)$ind[0];
|
||||
}
|
||||
}
|
||||
|
||||
return $newpages;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
$pdf = new PDFMerger;
|
||||
|
||||
$pdf->addPDF('samplepdfs/one.pdf', '1, 3, 4')
|
||||
->addPDF('samplepdfs/two.pdf', '1-2')
|
||||
->addPDF('samplepdfs/three.pdf', 'all')
|
||||
->merge('file', 'samplepdfs/TEST2.pdf');
|
||||
|
||||
//REPLACE 'file' WITH 'browser', 'download', 'string', or 'file' for output options
|
||||
//You do not need to give a file path for browser, string, or download - just the name.
|
||||
*/
|
||||
87
app/Mail/MailLogistic.php
Normal file
87
app/Mail/MailLogistic.php
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
<?php
|
||||
namespace App\Mail;
|
||||
|
||||
use App\User;
|
||||
use App\Services\Invoice;
|
||||
use App\Models\ShoppingOrder;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Storage;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
|
||||
class MailLogistic extends Mailable
|
||||
{
|
||||
use Queueable, SerializesModels;
|
||||
|
||||
protected $shopping_order;
|
||||
|
||||
public $subject;
|
||||
|
||||
|
||||
public function __construct(ShoppingOrder $shopping_order)
|
||||
{
|
||||
$this->shopping_order = $shopping_order;
|
||||
$name = $shopping_order->shopping_user->billing_firstname . ' ' . $shopping_order->shopping_user->billing_lastname;
|
||||
$company = $shopping_order->shopping_user->billing_company ?? '';
|
||||
|
||||
$this->subject = 'Partner';
|
||||
if($shopping_order->user_white_label){
|
||||
//Bei allen, die ein eigenes Logo haben
|
||||
$this->subject .= ' (mit Logo)';
|
||||
}else{
|
||||
//Bei allen, die kein Tattoostudio sind
|
||||
$this->subject = ' - ';
|
||||
}
|
||||
if($shopping_order->shopping_user->same_as_billing){
|
||||
//Rechnungsadresse und Lieferadresse sind gleich
|
||||
$this->subject = '';
|
||||
}else{
|
||||
//hat eine andere Lieferadresse
|
||||
$this->subject = ' Lieferadresse';
|
||||
}
|
||||
$this->subject .= ' '.$company.' (' . $name . ')';
|
||||
|
||||
}
|
||||
|
||||
public function build()
|
||||
{
|
||||
$title = false;
|
||||
$copy1line = false;
|
||||
|
||||
$filename = Invoice::getFilename($this->shopping_order);
|
||||
$path = Invoice::getDownloadPath($this->shopping_order);
|
||||
if (!Storage::disk('public')->exists($path)) {
|
||||
return;
|
||||
}
|
||||
$file = Storage::disk('public')->path($path);
|
||||
$mime = Storage::disk('public')->mimeType($path);
|
||||
|
||||
|
||||
$mail = $this->view('emails.logistic')->with([
|
||||
'title' => $title,
|
||||
'copy1line' => $copy1line,
|
||||
])->attach($file,[
|
||||
'as' => $filename,
|
||||
'mime' => $mime,
|
||||
]);
|
||||
|
||||
//Wenn das Logo gesetzt ist und die Rechnungsadresse und Lieferadresse unterschiedlich sind, dann wird der Lieferschein angehängt
|
||||
if($this->shopping_order->user_white_label && !$this->shopping_order->shopping_user->same_as_billing){
|
||||
$filenameDelivery = Invoice::getDeliveryFilename($this->shopping_order);
|
||||
$pathDelivery = Invoice::getDownloadPathDelivery($this->shopping_order);
|
||||
if (!Storage::disk('public')->exists($pathDelivery)) {
|
||||
return;
|
||||
}
|
||||
$fileDelivery = Storage::disk('public')->path($pathDelivery);
|
||||
$mimeDelivery = Storage::disk('public')->mimeType($pathDelivery);
|
||||
|
||||
$mail->attach($fileDelivery,[
|
||||
'as' => $filenameDelivery,
|
||||
'mime' => $mimeDelivery,
|
||||
]); // attach file;
|
||||
}
|
||||
|
||||
return $mail;
|
||||
}
|
||||
}
|
||||
59
app/Mail/MailLogitic.php
Normal file
59
app/Mail/MailLogitic.php
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
namespace App\Mail;
|
||||
|
||||
use App\User;
|
||||
use App\Services\Invoice;
|
||||
use App\Models\ShoppingOrder;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Storage;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
|
||||
class MailLogistic extends Mailable
|
||||
{
|
||||
use Queueable, SerializesModels;
|
||||
|
||||
protected $shopping_order;
|
||||
|
||||
public $subject;
|
||||
|
||||
|
||||
public function __construct(ShoppingOrder $shopping_order)
|
||||
{
|
||||
$this->shopping_order = $shopping_order;
|
||||
if($shopping_order->user_white_label){
|
||||
//Bei allen, die ein eigenes Logo haben
|
||||
$this->subject = 'Partner (mit Logo) - Firma (Vorname Nachname)';
|
||||
}else{
|
||||
//Bei allen, die kein Tattoostudio sind
|
||||
$this->subject = 'Partner - Firma (Vorname Nachname)';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function build()
|
||||
{
|
||||
|
||||
|
||||
$title = false;
|
||||
$copy1line = false;
|
||||
|
||||
$filename = Invoice::getFilename($this->shopping_order);
|
||||
$path = Invoice::getDownloadPath($this->shopping_order);
|
||||
if (!Storage::disk('public')->exists($path)) {
|
||||
return;
|
||||
}
|
||||
$file = Storage::disk('public')->path($path);
|
||||
$mime = Storage::disk('public')->mimeType($path);
|
||||
|
||||
|
||||
return $this->view('emails.blank')->with([
|
||||
'title' => $title,
|
||||
'copy1line' => $copy1line,
|
||||
])->attach($file,[
|
||||
'as' => $filename,
|
||||
'mime' => $mime,
|
||||
]); // attach file;
|
||||
}
|
||||
}
|
||||
60
app/Mail/PaymentReminderEmail.php
Normal file
60
app/Mail/PaymentReminderEmail.php
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
<?php
|
||||
|
||||
namespace App\Mail;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use App\Services\Util;
|
||||
|
||||
class PaymentReminderEmail extends Mailable
|
||||
{
|
||||
use Queueable, SerializesModels;
|
||||
|
||||
protected $emailSubject;
|
||||
protected $message;
|
||||
protected $order;
|
||||
|
||||
public $data;
|
||||
|
||||
/**
|
||||
* Erstellt eine neue PaymentReminderEmail Instanz
|
||||
*
|
||||
* @param string $subject
|
||||
* @param string $message
|
||||
* @param object|null $user
|
||||
* @param object|null $order
|
||||
* @param float|null $paymentAmount
|
||||
* @param string|null $dueDate
|
||||
* @param string|null $paymentUrl
|
||||
*/
|
||||
public function __construct($subject, $message, $order = null)
|
||||
{
|
||||
$this->emailSubject = $subject;
|
||||
$this->message = $message;
|
||||
$this->order = $order;
|
||||
}
|
||||
|
||||
/**
|
||||
* Baut die E-Mail
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function build()
|
||||
{
|
||||
|
||||
|
||||
|
||||
$paymentUrl = route('user_myorder_detail', ['id' => $this->order->id]);
|
||||
$buttonText = __('email.my_orders') ?: 'Meine Bestellungen';
|
||||
|
||||
return $this->subject($this->emailSubject)
|
||||
->view('emails.payment_reminder')
|
||||
->with([
|
||||
'content' => $this->message,
|
||||
'url' => $paymentUrl,
|
||||
'button' => $buttonText,
|
||||
]);
|
||||
}
|
||||
}
|
||||
57
app/Models/PaymentReminder.php
Normal file
57
app/Models/PaymentReminder.php
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Created by Reliese Model.
|
||||
*/
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
* Class PaymentReminder
|
||||
*
|
||||
* @property int $id
|
||||
* @property string|null $title
|
||||
* @property int|null $interval
|
||||
* @property string|null $message
|
||||
* @property string|null $action
|
||||
* @property bool $active
|
||||
* @property Carbon|null $created_at
|
||||
* @property Carbon|null $updated_at
|
||||
*
|
||||
* @package App\Models
|
||||
*/
|
||||
class PaymentReminder extends Model
|
||||
{
|
||||
protected $table = 'payment_reminders';
|
||||
|
||||
protected $casts = [
|
||||
'interval' => 'int',
|
||||
'active' => 'bool'
|
||||
];
|
||||
|
||||
protected $fillable = [
|
||||
'title',
|
||||
'subject',
|
||||
'interval',
|
||||
'message',
|
||||
'action',
|
||||
'clearingtype',
|
||||
'active'
|
||||
];
|
||||
|
||||
protected static $clearingtypes = [
|
||||
'fnc' => 'Rechnung',
|
||||
'vor' => 'Vorkasse',
|
||||
];
|
||||
|
||||
public function getClearingtype(){
|
||||
return isset(self::$clearingtypes[$this->clearingtype]) ? self::$clearingtypes[$this->clearingtype] : 'Kein Typ';
|
||||
}
|
||||
|
||||
public static function returnClearingtypes(){
|
||||
return self::$clearingtypes;
|
||||
}
|
||||
}
|
||||
|
|
@ -105,6 +105,8 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
|||
* @method static \Illuminate\Database\Eloquent\Builder|ShoppingOrder whereShippingOption($value)
|
||||
* @property array|null $delivery
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ShoppingOrder whereDelivery($value)
|
||||
* @property bool $user_white_label
|
||||
* @method static \Illuminate\Database\Eloquent\Builder<static>|ShoppingOrder whereUserWhiteLabel($value)
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class ShoppingOrder extends Model
|
||||
|
|
@ -138,6 +140,7 @@ class ShoppingOrder extends Model
|
|||
'paid',
|
||||
'invoice',
|
||||
'delivery',
|
||||
'user_white_label',
|
||||
'invoice_number',
|
||||
'txaction',
|
||||
'wp_invoice_path',
|
||||
|
|
@ -146,7 +149,7 @@ class ShoppingOrder extends Model
|
|||
'shipped',
|
||||
'shipped_at',
|
||||
'shipping_option',
|
||||
'tracking'
|
||||
'tracking',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
|
|
@ -154,6 +157,7 @@ class ShoppingOrder extends Model
|
|||
'invoice' => 'array',
|
||||
'delivery' => 'array',
|
||||
'shipped_at' => 'datetime',
|
||||
'user_white_label' => 'boolean',
|
||||
];
|
||||
|
||||
public static $shippedTypes = [
|
||||
|
|
@ -161,6 +165,7 @@ class ShoppingOrder extends Model
|
|||
1 => 'in Bearbeitung',
|
||||
2 => 'versendet',
|
||||
3 => 'abgeschlossen',
|
||||
5 => 'Wartestellung',
|
||||
4 => 'Abholung',
|
||||
10 => 'storniert'
|
||||
];
|
||||
|
|
@ -213,6 +218,7 @@ class ShoppingOrder extends Model
|
|||
2 => 'success',
|
||||
3 => 'secondary',
|
||||
4 => 'success',
|
||||
5 => 'warning-dark',
|
||||
10 => 'danger',
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -58,6 +58,14 @@ use Illuminate\Database\Eloquent\Model;
|
|||
* @method static \Illuminate\Database\Eloquent\Builder|ShoppingOrderMargin wherePartnerCommissionPendingTo($value)
|
||||
* @property int|null $user_credit_id
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ShoppingOrderMargin whereUserCreditId($value)
|
||||
* @property bool $order_paid
|
||||
* @property bool $out_paid
|
||||
* @property \Illuminate\Support\Carbon|null $margin_pending_to
|
||||
* @property bool|null $margin_paid
|
||||
* @method static \Illuminate\Database\Eloquent\Builder<static>|ShoppingOrderMargin whereMarginPaid($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder<static>|ShoppingOrderMargin whereMarginPendingTo($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder<static>|ShoppingOrderMargin whereOrderPaid($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder<static>|ShoppingOrderMargin whereOutPaid($value)
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class ShoppingOrderMargin extends Model
|
||||
|
|
@ -113,7 +121,12 @@ class ShoppingOrderMargin extends Model
|
|||
|
||||
public static $statusTypes = [
|
||||
0 => 'user order',
|
||||
1 => '',
|
||||
1 => 'Registrierung',
|
||||
2 => 'Mitgliedschaft',
|
||||
3 => 'Guthabenaufladung',
|
||||
4 => 'VP.Bestellung Abholung',
|
||||
5 => 'VP.Bestellung Lieferung',
|
||||
6 => 'VP.Kundenbestellung',
|
||||
7 => 'from promotion',
|
||||
8 => 'from shop',
|
||||
9 => 'storniert'
|
||||
|
|
|
|||
|
|
@ -54,9 +54,18 @@ class ShoppingPayment extends Model
|
|||
'reference',
|
||||
'amount',
|
||||
'currency',
|
||||
'status',
|
||||
'reminder',
|
||||
'reminder_date',
|
||||
'txaction',
|
||||
'mode'
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'reminder' => 'integer',
|
||||
'reminder_date' => 'datetime',
|
||||
];
|
||||
|
||||
|
||||
public function shopping_order()
|
||||
{
|
||||
|
|
@ -91,6 +100,7 @@ class ShoppingPayment extends Model
|
|||
if($this->clearingtype === 'non') {
|
||||
return 'keine';
|
||||
}
|
||||
return 'keine';
|
||||
}
|
||||
|
||||
public function getPaymentAmount(){
|
||||
|
|
|
|||
72
app/Policies/ModelPolicy.php
Executable file
72
app/Policies/ModelPolicy.php
Executable file
|
|
@ -0,0 +1,72 @@
|
|||
<?php
|
||||
|
||||
namespace App\Policies;
|
||||
|
||||
use App\User;
|
||||
use Illuminate\Auth\Access\HandlesAuthorization;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
abstract class ModelPolicy
|
||||
{
|
||||
use HandlesAuthorization;
|
||||
|
||||
abstract protected function getModelClass(): string;
|
||||
|
||||
public function viewAny(User $user)
|
||||
{
|
||||
return $user->can('view-any-' . $this->getModelClass());
|
||||
}
|
||||
|
||||
public function view(User $user, Model $model)
|
||||
{
|
||||
if ($user->can('view-' . $this->getModelClass())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($user->can('view-self-' . $this->getModelClass())) {
|
||||
return $this->isOwner($user, $model);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function create(User $user)
|
||||
{
|
||||
return $user->can('create-' . $this->getModelClass());
|
||||
}
|
||||
|
||||
public function update(User $user, Model $model)
|
||||
{
|
||||
if ($user->can('update-' . $this->getModelClass())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($user->can('update-self-' . $this->getModelClass())) {
|
||||
return $this->isOwner($user, $model);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function delete(User $user, Model $model)
|
||||
{
|
||||
if ($user->can('delete-' . $this->getModelClass())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($user->can('delete-self-' . $this->getModelClass())) {
|
||||
return $this->isOwner($user, $model);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function isOwner(User $user, Model $model): bool
|
||||
{
|
||||
if (!empty($user) && method_exists($model, 'user')) {
|
||||
return $user->getKey() === $model->getRelation('user')->getKey();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Providers;
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
class AppServiceProvider extends ServiceProvider
|
||||
|
|
@ -13,7 +14,7 @@ class AppServiceProvider extends ServiceProvider
|
|||
*/
|
||||
public function boot()
|
||||
{
|
||||
//
|
||||
Schema::defaultStringLength(191);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -23,6 +24,10 @@ class AppServiceProvider extends ServiceProvider
|
|||
*/
|
||||
public function register()
|
||||
{
|
||||
//
|
||||
|
||||
if ($this->app->environment() !== 'production') {
|
||||
$this->app->register(\Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider::class);
|
||||
}
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ use Illuminate\Support\Facades\Gate;
|
|||
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
|
||||
use Laravel\Passport\Passport;
|
||||
|
||||
|
||||
class AuthServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
|
|
@ -15,7 +14,7 @@ class AuthServiceProvider extends ServiceProvider
|
|||
* @var array
|
||||
*/
|
||||
protected $policies = [
|
||||
// 'App\Model' => 'App\Policies\ModelPolicy',
|
||||
'App\Model' => 'App\Policies\ModelPolicy',
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
@ -26,7 +25,12 @@ class AuthServiceProvider extends ServiceProvider
|
|||
public function boot()
|
||||
{
|
||||
$this->registerPolicies();
|
||||
Passport::routes();
|
||||
|
||||
// Die neuere Passport-Konfiguration verwendet separate Methoden
|
||||
// anstelle von Passport::routes()
|
||||
Passport::tokensExpireIn(now()->addDays(15));
|
||||
Passport::refreshTokensExpireIn(now()->addDays(30));
|
||||
Passport::personalAccessTokensExpireIn(now()->addMonths(6));
|
||||
|
||||
//
|
||||
}
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@ class ContractPDFRepository extends BaseRepository {
|
|||
$filename = "Vertriebspartnervertrag.pdf";
|
||||
Storage::disk($this->disk)->put($this->dir.$filename, $pdf->Output('S'));
|
||||
$size = Storage::disk($this->disk)->size($this->dir.$filename);
|
||||
$mine = Storage::disk($this->disk)->getMimeType($this->dir.$filename);
|
||||
$mine = Storage::disk($this->disk)->mimeType($this->dir.$filename);
|
||||
|
||||
File::create([
|
||||
'user_id' => $this->model->id,
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ class CreditRepository extends BaseRepository {
|
|||
if(!Storage::disk('public')->exists( $dir )){
|
||||
Storage::disk('public')->makeDirectory($dir); //creates directory
|
||||
}
|
||||
$path = Storage::disk('public')->getAdapter()->getPathPrefix();
|
||||
$path = Storage::disk('public')->path('');
|
||||
$filename = Credit::makeCreditFilename($credit_number);
|
||||
|
||||
$pdf->save($path.$dir.$filename);
|
||||
|
|
@ -87,7 +87,7 @@ class CreditRepository extends BaseRepository {
|
|||
private function finishUserCredit($user_credit){
|
||||
//next number
|
||||
Credit::makeNextCreditNumber();
|
||||
//Partner Provision
|
||||
//Partner Provision shopping order margin
|
||||
$ShoppingOrderMargins = UserMarign::getPartnerCommissionItems($this->model->id, false);
|
||||
foreach($ShoppingOrderMargins as $ShoppingOrderMargin){
|
||||
$ShoppingOrderMargin->partner_commission_paid = true;
|
||||
|
|
@ -96,7 +96,7 @@ class CreditRepository extends BaseRepository {
|
|||
$ShoppingOrderMargin->save();
|
||||
}
|
||||
|
||||
//Shop Provision
|
||||
//Shop Provision shopping order margin
|
||||
$ShoppingOrderMargins = UserMarign::getShopCommissionItems($this->model->id, false);
|
||||
foreach($ShoppingOrderMargins as $ShoppingOrderMargin){
|
||||
$ShoppingOrderMargin->margin_paid = true;
|
||||
|
|
@ -105,7 +105,7 @@ class CreditRepository extends BaseRepository {
|
|||
$ShoppingOrderMargin->save();
|
||||
}
|
||||
|
||||
//Hinzugefügte Provision
|
||||
//Hinzugefügte Provision user credit margin
|
||||
$UserCreditMargins = UserMarign::getUserCreditMarginByUserID($this->model->id);
|
||||
foreach($UserCreditMargins as $UserCreditMargin){
|
||||
$UserCreditMargin->paid = true; //wurde ausgezahlt
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ class InvoiceRepository extends BaseRepository {
|
|||
private $delivery_dir;
|
||||
private $delivery_filename;
|
||||
|
||||
|
||||
public function __construct(ShoppingOrder $model)
|
||||
{
|
||||
$this->model = $model;
|
||||
|
|
@ -130,7 +131,7 @@ class InvoiceRepository extends BaseRepository {
|
|||
if(!Storage::disk('public')->exists( $this->delivery_dir )){
|
||||
Storage::disk('public')->makeDirectory($this->delivery_dir); //creates directory
|
||||
}
|
||||
$path = Storage::disk('public')->getAdapter()->getPathPrefix();
|
||||
$path = Storage::disk('public')->path('');
|
||||
|
||||
$pdf_file = new InvoicePDF('pdf.invoice');
|
||||
$pdf_file->create($data, $this->filename, 'save', $path.$this->dir);
|
||||
|
|
@ -176,6 +177,10 @@ class InvoiceRepository extends BaseRepository {
|
|||
foreach($whitelabel_image->attributes as $attribute){
|
||||
if(in_array($attribute, $label->attributes)){
|
||||
//found and overwrite
|
||||
if(!$this->model->user_white_label){
|
||||
$this->model->user_white_label = true;
|
||||
$this->model->save();
|
||||
}
|
||||
$labels[$key] = $whitelabel_image;
|
||||
}
|
||||
}
|
||||
|
|
@ -184,7 +189,6 @@ class InvoiceRepository extends BaseRepository {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach($labels as $key=>$label){
|
||||
//label hat attribue
|
||||
$varinats = [];
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
namespace App\Services;
|
||||
|
||||
use App\Mail\MailInvoice;
|
||||
use App\Mail\MailLogistic;
|
||||
use App\Services\Util;
|
||||
use App\Models\Setting;
|
||||
use App\Models\ShoppingOrder;
|
||||
|
|
@ -118,4 +119,9 @@ class Invoice
|
|||
}
|
||||
Mail::to($billing_email)->bcc($bcc)->send(new MailInvoice($shopping_order));
|
||||
}
|
||||
|
||||
public static function sendLogisticMail(ShoppingOrder $shopping_order){
|
||||
$to = [config('app.logistic_mail')]; //['versand@aloe-vera.bio'];
|
||||
Mail::to($to)->send(new MailLogistic($shopping_order));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ class PDFMerger {
|
|||
* Construct and initialize a new instance
|
||||
* @param Filesystem $oFilesystem
|
||||
*/
|
||||
public function __construct(Filesystem $oFilesystem = null){
|
||||
public function __construct($oFilesystem = null){
|
||||
$this->oFilesystem = $oFilesystem;
|
||||
$this->oFPDI = new FPDI();
|
||||
$this->tmpFiles = collect([]);
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ namespace App\Services;
|
|||
|
||||
use App\User;
|
||||
use App\Models\Product;
|
||||
use App\Models\Setting;
|
||||
use App\Mail\MailCheckout;
|
||||
use App\Models\ProductBuy;
|
||||
use App\Models\ShoppingOrder;
|
||||
|
|
@ -19,15 +18,16 @@ class Payment
|
|||
|
||||
public static $txaction_text = [
|
||||
'paid' => "bezahlt",
|
||||
'appointed' => "offen",
|
||||
'open' => "offen",
|
||||
'appointed' => "offen (appointed)",
|
||||
'failed' => "abbruch",
|
||||
'extern' => "extern",
|
||||
'open' => "offen",
|
||||
'invoice_open' => "Re. offen",
|
||||
'invoice_paid' => "Re. bezahlt",
|
||||
'invoice_non' => "Re. keine Zahlung",
|
||||
'non' => "keine Zahlung",
|
||||
'non' => "keine Zahlung (non)",
|
||||
'NULL' => 'keine Zahlung',
|
||||
'prev' => "keine Zahlung (prev)",
|
||||
];
|
||||
|
||||
public static $txaction_invoice = [
|
||||
|
|
@ -56,10 +56,10 @@ class Payment
|
|||
'invoice_open' => "warning",
|
||||
'invoice_paid' => "success",
|
||||
'invoice_non' => "danger",
|
||||
|
||||
'prev' => "warning",
|
||||
];
|
||||
|
||||
|
||||
|
||||
public static function getFormattedTxaction($txaction){
|
||||
if($txaction && isset(self::$txaction_text[$txaction])){
|
||||
return self::$txaction_text[$txaction];
|
||||
|
|
@ -360,26 +360,60 @@ class Payment
|
|||
|
||||
}
|
||||
|
||||
public static function paymentStatusSendMail(ShoppingOrder $shopping_order, $shopping_payment, $data){
|
||||
$bcc = [];
|
||||
$billing_email = $shopping_order->shopping_user->billing_email;
|
||||
if(!$billing_email){
|
||||
if($data['mode'] === 'test'){
|
||||
$billing_email = config('app.checkout_test_mail');
|
||||
}else{
|
||||
$billing_email = config('app.checkout_mail');
|
||||
}
|
||||
public static function paymentStatusSendMail(ShoppingOrder $shopping_order, $shopping_payment, $data)
|
||||
{
|
||||
$billing_email = self::determineBillingEmail($shopping_order, $data);
|
||||
$bcc = self::determineBccRecipients($shopping_order, $data);
|
||||
|
||||
try {
|
||||
Mail::to($billing_email)
|
||||
->bcc($bcc)
|
||||
->send(new MailCheckout(
|
||||
$data['txaction'],
|
||||
$shopping_order,
|
||||
$shopping_payment,
|
||||
$data['send_link'],
|
||||
$data['mode']
|
||||
));
|
||||
} catch (\Exception $e) {
|
||||
\Log::error('Fehler beim E-Mail-Versand: ' . $e->getMessage());
|
||||
}
|
||||
if($data['mode'] === 'test'){
|
||||
$bcc[] = config('app.checkout_test_mail');
|
||||
}else{
|
||||
$bcc[] = config('app.checkout_mail');
|
||||
}
|
||||
|
||||
private static function determineBillingEmail($shopping_order, $data)
|
||||
{
|
||||
if (Util::isTestSystem()) {
|
||||
return config('app.checkout_test_mail');
|
||||
}
|
||||
|
||||
if(!$shopping_order->shopping_user->is_like && $shopping_order->shopping_user->member){
|
||||
$billing_email = $shopping_order->shopping_user->billing_email;
|
||||
if (!$billing_email) {
|
||||
return $data['mode'] === 'test'
|
||||
? config('app.checkout_test_mail')
|
||||
: config('app.checkout_mail');
|
||||
}
|
||||
|
||||
return $billing_email;
|
||||
}
|
||||
|
||||
private static function determineBccRecipients($shopping_order, $data)
|
||||
{
|
||||
$bcc = [];
|
||||
|
||||
// Add checkout email to BCC
|
||||
$bcc[] = $data['mode'] === 'test'
|
||||
? config('app.checkout_test_mail')
|
||||
: config('app.checkout_mail');
|
||||
|
||||
// Add member email to BCC if applicable
|
||||
if ($data['mode'] !== 'test'
|
||||
&& !Util::isTestSystem()
|
||||
&& !$shopping_order->shopping_user->is_like
|
||||
&& $shopping_order->shopping_user->member
|
||||
) {
|
||||
$bcc[] = $shopping_order->shopping_user->member->email;
|
||||
}
|
||||
|
||||
Mail::to($billing_email)->bcc($bcc)->send(new MailCheckout($data['txaction'], $shopping_order, $shopping_payment, $data['send_link'], $data['mode']));
|
||||
|
||||
return $bcc;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,269 +0,0 @@
|
|||
<?php
|
||||
namespace App\Services\Stats;
|
||||
|
||||
|
||||
use Carbon\Carbon;
|
||||
use App\Services\Util;
|
||||
use App\Models\ShoppingOrder;
|
||||
|
||||
class Sales
|
||||
{
|
||||
private $month;
|
||||
private $year;
|
||||
private $products;
|
||||
private $objects;
|
||||
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->month = 0;
|
||||
$this->year = 0;
|
||||
$this->products = [];
|
||||
$this->objects = [];
|
||||
}
|
||||
|
||||
public function setFilterVars($month = null, $year = null, $products = null){
|
||||
$this->month = $month ? $month : intval(date('m'));
|
||||
$this->year = $year ? $year : intval(date('Y'));
|
||||
$this->products = $products;
|
||||
}
|
||||
|
||||
public function setFilterProducts(){
|
||||
|
||||
$ShoppingOrders = $this->getShoppingOrdersBy($this->month, $this->year);
|
||||
$products = [];
|
||||
foreach($ShoppingOrders as $ShoppingOrder){
|
||||
foreach($ShoppingOrder->shopping_order_items as $shopping_order_item){
|
||||
if($shopping_order_item->product && !$shopping_order_item->product->exclude_stats_sales && !isset($products[$shopping_order_item->product->id])){
|
||||
$products[$shopping_order_item->product->id] = $shopping_order_item->product->name.' # '.
|
||||
($shopping_order_item->product->single_commission ? $shopping_order_item->product->value_commission.' / '.$shopping_order_item->product->partner_commission : 'Staffelrabatt');
|
||||
}
|
||||
}
|
||||
}
|
||||
return $products;
|
||||
}
|
||||
|
||||
private function getShoppingOrdersBy($month, $year){
|
||||
if($month == '13'){ //all the year
|
||||
$date_start = Carbon::parse('01.01.'.$year)->format('Y-m-d H:i:s');
|
||||
$date_end = Carbon::parse('31.12.'.$year)->endOfMonth()->format('Y-m-d H:i:s');
|
||||
}else{
|
||||
$date_start = Carbon::parse('01.'.$month.'.'.$year)->format('Y-m-d H:i:s');
|
||||
$date_end = Carbon::parse('01.'.$month.'.'.$year)->endOfMonth()->format('Y-m-d H:i:s');
|
||||
}
|
||||
return ShoppingOrder::where('paid', 1)->where('mode', 'live')->whereBetween('created_at', [$date_start, $date_end])->get();
|
||||
}
|
||||
|
||||
public function getCollection(){
|
||||
|
||||
$this->getObjects();
|
||||
$collection = collect();
|
||||
|
||||
foreach($this->objects as $key => $obj){
|
||||
$collection->push([
|
||||
'id' => $key,
|
||||
'name' => $obj['name'],
|
||||
'number' => $obj['number'],
|
||||
'qty' => $obj['qty'],
|
||||
'total' => $obj['total'],
|
||||
'pre_qty' => $obj['pre_qty'],
|
||||
'pre_total' => $obj['pre_total'],
|
||||
'single_commission' => $obj['single_commission'],
|
||||
'value_commission' => $obj['value_commission'],
|
||||
'partner_commission' => $obj['partner_commission'],
|
||||
|
||||
]);
|
||||
}
|
||||
return $collection;
|
||||
}
|
||||
|
||||
public function getObjects(){
|
||||
$this->readObjects();
|
||||
$this->readObjectsPreview();
|
||||
return $this->objects;
|
||||
}
|
||||
|
||||
private function readObjects()
|
||||
{
|
||||
$shoppingOrders = $this->getShoppingOrdersBy($this->month, $this->year);
|
||||
$this->objects = [];
|
||||
|
||||
$subtotal_full = 0; // gesamtumsatz
|
||||
$subtotal = 0; // gesamtumsatz ohne rabatte
|
||||
$discount = 0; // gesamtrabatte
|
||||
$subtotal_hide = 0; // ausgeschlossene Produkte
|
||||
|
||||
foreach($shoppingOrders as $ShoppingOrder){
|
||||
$subtotal_full += $ShoppingOrder->subtotal_full;
|
||||
$subtotal += $ShoppingOrder->subtotal;
|
||||
$discount += $ShoppingOrder->discount;
|
||||
|
||||
foreach($ShoppingOrder->shopping_order_items as $shopping_order_item){
|
||||
|
||||
if($shopping_order_item->product){
|
||||
if(!in_array($shopping_order_item->product->id, $this->products) && !$shopping_order_item->product->exclude_stats_sales){ //ausschließen der Produkte über filter und exclude_stats_sales
|
||||
if(isset($this->objects[$shopping_order_item->product->id])){
|
||||
$qty = intval($this->objects[$shopping_order_item->product->id]['qty'] + $shopping_order_item->qty);
|
||||
$total = round($this->objects[$shopping_order_item->product->id]['total'] + ($shopping_order_item->price_net * $shopping_order_item->qty), 3);
|
||||
$this->objects[$shopping_order_item->product->id]['qty'] = $qty;
|
||||
$this->objects[$shopping_order_item->product->id]['total'] = $total;
|
||||
}else{
|
||||
$this->objects[$shopping_order_item->product->id] = [
|
||||
'name' => $shopping_order_item->product->name,
|
||||
'number' => $shopping_order_item->product->number,
|
||||
'qty' => $shopping_order_item->qty,
|
||||
'total' => round($shopping_order_item->price_net * $shopping_order_item->qty, 3),
|
||||
'pre_qty' => 0,
|
||||
'pre_total' => 0,
|
||||
'single_commission' => $shopping_order_item->product->single_commission ? 'Ja' : 'Nein',
|
||||
'value_commission' => $shopping_order_item->product->single_commission ? $shopping_order_item->product->value_commission : '',
|
||||
'partner_commission' => $shopping_order_item->product->single_commission ? $shopping_order_item->product->partner_commission : '',
|
||||
|
||||
];
|
||||
}
|
||||
}else{
|
||||
$subtotal_hide += $shopping_order_item->price_net * $shopping_order_item->qty;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
$this->objects[9990] = [
|
||||
'name' => 'Angezeigter Umsatz netto €',
|
||||
'number' => '',
|
||||
'qty' => '',
|
||||
'total' => round($subtotal_full - $subtotal_hide, 2),
|
||||
'pre_qty' => 0,
|
||||
'pre_total' => 0,
|
||||
'single_commission' => '',
|
||||
'value_commission' => '',
|
||||
'partner_commission' => '',
|
||||
|
||||
];
|
||||
|
||||
$this->objects[9991] = [
|
||||
'name' => 'Ausgeblendeter Umsatz netto €',
|
||||
'number' => '',
|
||||
'qty' => '',
|
||||
'total' => $subtotal_hide,
|
||||
'pre_qty' => 0,
|
||||
'pre_total' => 0,
|
||||
'single_commission' => '',
|
||||
'value_commission' => '',
|
||||
'partner_commission' => '',
|
||||
|
||||
];
|
||||
|
||||
$this->objects[9992] = [
|
||||
'name' => 'Gesamter Umsatz netto € (alle Verkäufe)',
|
||||
'number' => '',
|
||||
'qty' => '',
|
||||
'total' => $subtotal_full,
|
||||
'pre_qty' => 0,
|
||||
'pre_total' => 0,
|
||||
'single_commission' => '',
|
||||
'value_commission' => '',
|
||||
'partner_commission' => '',
|
||||
|
||||
];
|
||||
|
||||
$this->objects[9998] = [
|
||||
'name' => 'Gesamte Rabatte netto € (alle Verkäufe)',
|
||||
'number' => '',
|
||||
'qty' => '',
|
||||
'total' => ($discount),
|
||||
'pre_qty' => 0,
|
||||
'pre_total' => 0,
|
||||
'single_commission' => '',
|
||||
'value_commission' => '',
|
||||
'partner_commission' => '',
|
||||
|
||||
];
|
||||
|
||||
$this->objects[9999] = [
|
||||
'name' => 'Gesamt netto € (alle Verkäufe)',
|
||||
'number' => '',
|
||||
'qty' => '',
|
||||
'total' => ($subtotal),
|
||||
'pre_qty' => 0,
|
||||
'pre_total' => 0,
|
||||
'single_commission' => '',
|
||||
'value_commission' => '',
|
||||
'partner_commission' => '',
|
||||
|
||||
];
|
||||
|
||||
//format total
|
||||
foreach($this->objects as $key => $obj){
|
||||
$this->objects[$key]['total'] = formatNumber($obj['total']);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private function readObjectsPreview(){
|
||||
|
||||
|
||||
$shoppingOrders = $this->getShoppingOrdersBy($this->month, $this->year-1);
|
||||
|
||||
$subtotal_full = 0; // gesamtumsatz
|
||||
$subtotal = 0; // gesamtumsatz ohne rabatte
|
||||
$discount = 0; // gesamtrabatte
|
||||
$subtotal_hide = 0; // ausgeschlossene Produkte
|
||||
|
||||
foreach($shoppingOrders as $ShoppingOrder){
|
||||
$subtotal_full += $ShoppingOrder->subtotal_full;
|
||||
$subtotal += $ShoppingOrder->subtotal;
|
||||
$discount += $ShoppingOrder->discount;
|
||||
|
||||
foreach($ShoppingOrder->shopping_order_items as $shopping_order_item){
|
||||
|
||||
if($shopping_order_item->product){
|
||||
if(!in_array($shopping_order_item->product->id, $this->products) && !$shopping_order_item->product->exclude_stats_sales){ //ausschließen der Produkte über filter und exclude_stats_sales
|
||||
if(isset($this->objects[$shopping_order_item->product->id])){ //einsetzen der Zahlen, wenn vorhanden
|
||||
$qty = intval($this->objects[$shopping_order_item->product->id]['pre_qty'] + $shopping_order_item->qty);
|
||||
$total = round($this->objects[$shopping_order_item->product->id]['pre_total'] + ($shopping_order_item->price_net * $shopping_order_item->qty), 3);
|
||||
$this->objects[$shopping_order_item->product->id]['pre_qty'] = $qty;
|
||||
$this->objects[$shopping_order_item->product->id]['pre_total'] = $total;
|
||||
}else{ // nicht vorhanden, anlegen
|
||||
$this->objects[$shopping_order_item->product->id] = [
|
||||
'name' => $shopping_order_item->product->name,
|
||||
'number' => $shopping_order_item->product->number,
|
||||
'qty' => 0,
|
||||
'total' => 0,
|
||||
'pre_qty' => $shopping_order_item->qty,
|
||||
'pre_total' => round($shopping_order_item->price_net * $shopping_order_item->qty, 3),
|
||||
'single_commission' => $shopping_order_item->product->single_commission ? 'Ja' : 'Nein',
|
||||
'value_commission' => $shopping_order_item->product->single_commission ? $shopping_order_item->product->value_commission : '',
|
||||
'partner_commission' => $shopping_order_item->product->single_commission ? $shopping_order_item->product->partner_commission : '',
|
||||
|
||||
];
|
||||
}
|
||||
}else{
|
||||
//ausgeschlossene Produkte
|
||||
$subtotal_hide += $shopping_order_item->price_net * $shopping_order_item->qty;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
$this->objects[9990]['pre_total'] = round($subtotal_full - $subtotal_hide, 2);
|
||||
$this->objects[9991]['pre_total'] = $subtotal_hide;
|
||||
$this->objects[9992]['pre_total'] = $subtotal_full;
|
||||
$this->objects[9998]['pre_total'] = ($discount);
|
||||
$this->objects[9999]['pre_total'] = ($subtotal);
|
||||
|
||||
//format total
|
||||
foreach($this->objects as $key => $obj){
|
||||
$this->objects[$key]['pre_total'] = formatNumber($obj['pre_total']);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -30,6 +30,7 @@ class UserBot
|
|||
|
||||
//user die manuelle Gutschriften haben
|
||||
$usersWithCreditMargin = $this->getUsersWithCreditMargin();
|
||||
|
||||
//user die Shop Provisionen haben
|
||||
$usersWithShopCommission = $this->getUsersWithShopCommission(false);
|
||||
|
||||
|
|
@ -181,9 +182,9 @@ class UserBot
|
|||
$entry->badge = \App\Services\Payment::getPaymentForTypeBadge($shoppingOrderMargin->shopping_order);
|
||||
|
||||
if ($shoppingOrderMargin->shopping_order->payment_for === 7 || $shoppingOrderMargin->shopping_order->payment_for === 8) {
|
||||
$entry->link = route('admin_sales_customers_detail', [$shoppingOrderMargin->shopping_order->id]);
|
||||
$entry->link = route('admin_sales_detail', [$shoppingOrderMargin->shopping_order->id]);
|
||||
} else {
|
||||
$entry->link = route('admin_sales_users_detail', [$shoppingOrderMargin->shopping_order->id]);
|
||||
$entry->link = route('admin_sales_detail', [$shoppingOrderMargin->shopping_order->id]);
|
||||
}
|
||||
|
||||
$entry->name = $shoppingOrderMargin->shopping_order->shopping_user->billing_firstname . " " .
|
||||
|
|
@ -258,7 +259,8 @@ class UserBot
|
|||
->whereOutPaid(false)
|
||||
->whereCancellation(false)
|
||||
->whereMarginPaid(false)
|
||||
->whereNotNull('margin_pending_to');
|
||||
->whereNotNull('margin_pending_to')
|
||||
->whereIn('status', [7,8]);
|
||||
|
||||
if ($isPending) {
|
||||
$query->where('margin_pending_to', '>=', Carbon::now());
|
||||
|
|
|
|||
13
app/Services/PaymentHelper.php
Normal file
13
app/Services/PaymentHelper.php
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
class PaymentHelper
|
||||
{
|
||||
public static $txaction_art = [
|
||||
'user_order' => "Vertriebspartner",
|
||||
'customer_order' => "Kundenbestellung",
|
||||
'user_for_customer' => "VP.Kundenbestellung",
|
||||
];
|
||||
|
||||
}
|
||||
453
app/Services/PaymentReminderService.php
Normal file
453
app/Services/PaymentReminderService.php
Normal file
|
|
@ -0,0 +1,453 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\Logger;
|
||||
use App\Models\PaymentReminder;
|
||||
use App\Models\ShoppingPayment;
|
||||
use App\Mail\PaymentReminderEmail;
|
||||
use App\Services\Util;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
|
||||
class PaymentReminderService
|
||||
{
|
||||
protected $clearingtypes = [];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->clearingtypes = PaymentReminder::returnClearingtypes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstellt einen Log-Eintrag für Payment Reminder Aktivitäten
|
||||
*/
|
||||
private function createLog($action, $message, $model = null, $modelId = null, $level = 2)
|
||||
{
|
||||
return Logger::create([
|
||||
'user_id' => null, // System-Aktion
|
||||
'model_id' => $modelId,
|
||||
'model' => $model,
|
||||
'action' => $action,
|
||||
'channel' => 'payment_reminder',
|
||||
'message' => $message,
|
||||
'level' => $level
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hole alle aktiven Intervalle für Zahlungserinnerungen
|
||||
*/
|
||||
public function getActiveIntervals()
|
||||
{
|
||||
$intervals = [];
|
||||
$payment_reminders = PaymentReminder::where('active', true)->get();
|
||||
|
||||
foreach($payment_reminders as $reminder) {
|
||||
$intervals[$reminder->clearingtype] = $reminder->interval;
|
||||
}
|
||||
|
||||
return $intervals;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hole alle offenen Zahlungen für einen bestimmten clearingtype
|
||||
*/
|
||||
public function getOpenPaymentsForClearingType($clearingtype, $interval)
|
||||
{
|
||||
$date = Carbon::now()->subDays($interval);
|
||||
|
||||
$payments = ShoppingPayment::join('shopping_orders', 'shopping_payments.shopping_order_id', '=', 'shopping_orders.id')
|
||||
->where('shopping_payments.clearingtype', '=', $clearingtype)
|
||||
->where('shopping_payments.txaction', '=', 'open')
|
||||
->where('shopping_payments.mode', '=', 'live')
|
||||
->where('shopping_payments.created_at', '<', $date)
|
||||
->where('shopping_payments.amount', '>', 0)
|
||||
->whereNull('shopping_orders.deleted_at')
|
||||
->whereIn('shopping_payments.id', function($query) use ($clearingtype, $date) {
|
||||
$query->selectRaw('MAX(shopping_payments.id)')
|
||||
->from('shopping_payments')
|
||||
->join('shopping_orders', 'shopping_payments.shopping_order_id', '=', 'shopping_orders.id')
|
||||
->where('shopping_payments.clearingtype', '=', $clearingtype)
|
||||
->where('shopping_payments.txaction', '=', 'open')
|
||||
->where('shopping_payments.mode', '=', 'live')
|
||||
->where('shopping_payments.created_at', '<', $date)
|
||||
->where('shopping_payments.amount', '>', 0)
|
||||
->whereNull('shopping_orders.deleted_at')
|
||||
->groupBy('shopping_payments.shopping_order_id');
|
||||
})
|
||||
->select('shopping_payments.*')
|
||||
->get();
|
||||
|
||||
|
||||
return $payments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hole alle offenen Zahlungen für alle clearingtypes
|
||||
*/
|
||||
public function getAllOpenPayments()
|
||||
{
|
||||
$intervals = $this->getActiveIntervals();
|
||||
$results = [];
|
||||
|
||||
foreach($intervals as $clearingtype => $interval){
|
||||
$date = Carbon::now()->subDays($interval);
|
||||
$payments = $this->getOpenPaymentsForClearingType($clearingtype, $interval);
|
||||
|
||||
$results[$clearingtype] = [
|
||||
'interval' => $interval,
|
||||
'date_limit' => $date,
|
||||
'payments' => $payments,
|
||||
'count' => $payments->count()
|
||||
];
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hole detaillierte Daten für Tabellen-Ansicht
|
||||
*/
|
||||
public function getDetailedPaymentsData()
|
||||
{
|
||||
$intervals = $this->getActiveIntervals();
|
||||
$detailedData = [];
|
||||
|
||||
foreach($intervals as $clearingtype => $interval){
|
||||
$date = Carbon::now()->subDays($interval);
|
||||
$payments = $this->getOpenPaymentsForClearingType($clearingtype, $interval);
|
||||
|
||||
foreach($payments as $payment){
|
||||
$name = !isset($payment->shopping_order->shopping_user) ? 'Kein Name' : $payment->shopping_order->shopping_user->billing_firstname.' '.$payment->shopping_order->shopping_user->billing_lastname;
|
||||
$email = !isset($payment->shopping_order->shopping_user) ? 'Keine Email' : $payment->shopping_order->shopping_user->billing_email;
|
||||
$shipped = '<span class="badge badge-pill badge-'.$payment->shopping_order->getShippedColor().'">'.$payment->shopping_order->getShippedType().'</span>';
|
||||
|
||||
// Countdown für nächste Erinnerung berechnen
|
||||
$countdown = $this->getNextReminderCountdown($payment);
|
||||
|
||||
$detailedData[] = [
|
||||
'clearingtype' => $clearingtype,
|
||||
'clearingtype_name' => $this->getClearingtype($clearingtype),
|
||||
'interval_days' => $interval,
|
||||
'date_limit' => $date->format('d.m.Y H:i:s'),
|
||||
'order_id' => $payment->shopping_order_id,
|
||||
'payment_id' => $payment->id,
|
||||
'amount' => $payment->amount,
|
||||
'created_at' => $payment->created_at->format('d.m.Y H:i:s'),
|
||||
'days_old' => $payment->created_at->diffInDays(now()),
|
||||
'payment' => $payment, // Vollständiges Payment-Objekt für weitere Verarbeitung
|
||||
'name' => $name,
|
||||
'email' => $email,
|
||||
'shipped' => $shipped,
|
||||
'reminder' => $payment->reminder,
|
||||
'reminder_date' => $payment->reminder_date ? $payment->reminder_date->format('d.m.Y H:i:s') : null,
|
||||
'countdown' => $countdown,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $detailedData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sende die nächste Zahlungserinnerung
|
||||
* noch kein reminder gesendet = 1. Zahlungserinnerung
|
||||
* reminder > 0 die nächste zahlungserinnerung aus der liste holen
|
||||
*/
|
||||
public function sendReminder($payment)
|
||||
{
|
||||
|
||||
|
||||
//holen der nächsten zahlungserinnerung
|
||||
$payment_reminder = $this->getReminder((int) $payment->reminder, $payment->clearingtype);
|
||||
if(!$payment_reminder){
|
||||
return false;
|
||||
}
|
||||
|
||||
//zahlungserinnerung Platzhalter ersetzen.
|
||||
$payment_reminder = $this->replacePlaceholder($payment, $payment_reminder);
|
||||
|
||||
//zahlungserinnerung senden
|
||||
$emailSent = $this->sendReminderEmail($payment, $payment_reminder);
|
||||
|
||||
if ($emailSent) {
|
||||
$this->createLog(
|
||||
'email_sent',
|
||||
"Zahlungserinnerung E-Mail gesendet an: {$payment->shopping_order->shopping_user->billing_email}, Subject: {$payment_reminder->subject}",
|
||||
'ShoppingOrder',
|
||||
$payment->shopping_order_id,
|
||||
3
|
||||
);
|
||||
}
|
||||
|
||||
//action ausführen
|
||||
if($payment_reminder->action === 'set_order_status_cancelled'){
|
||||
$this->setNoNPayment($payment);
|
||||
$payment->shopping_order->shipped = 10;
|
||||
$payment->shopping_order->save();
|
||||
$this->createLog(
|
||||
'action_completed',
|
||||
"Action abgeschlossen: Bestellung auf 'Storniert' gesetzt, Payment auf 'non' gesetzt",
|
||||
'ShoppingOrder',
|
||||
$payment->shopping_order_id,
|
||||
3
|
||||
);
|
||||
}
|
||||
|
||||
//reminder setzen +1
|
||||
$payment->reminder = (int) $payment->reminder + 1;
|
||||
$payment->reminder_date = Carbon::now();
|
||||
$payment->save();
|
||||
|
||||
$this->createLog(
|
||||
'reminder_completed',
|
||||
"Zahlungserinnerung für Payment ID: {$payment->id}, Order ID: {$payment->shopping_order_id}",
|
||||
'ShoppingOrder',
|
||||
$payment->shopping_order_id,
|
||||
4
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function setNoNPayment($payment)
|
||||
{
|
||||
$this->createLog(
|
||||
'set_non_payment',
|
||||
"Setze Payment ID: {$payment->id} auf 'non' Status",
|
||||
'ShoppingOrder',
|
||||
$payment->shopping_order_id,
|
||||
4
|
||||
);
|
||||
PaymentService::updateTransactionStatus($payment->shopping_order_id, 'non', $payment->id);
|
||||
}
|
||||
|
||||
public function getClearingtype($clearingtype)
|
||||
{
|
||||
return isset($this->clearingtypes[$clearingtype]) ? $this->clearingtypes[$clearingtype] : $clearingtype;
|
||||
}
|
||||
|
||||
public function getReminder($reminder, $clearingtype)
|
||||
{
|
||||
$payment_reminders = PaymentReminder::where('active', true)
|
||||
->where('clearingtype', $clearingtype)
|
||||
->orderBy('interval', 'asc')
|
||||
->get();
|
||||
|
||||
if($payment_reminders->isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
// Wenn reminder größer ist als Anzahl der Erinnerungen
|
||||
if($reminder >= $payment_reminders->count()) {
|
||||
return false;
|
||||
}
|
||||
// Hole die Erinnerung an Position $reminder (0,1,2,3...)
|
||||
return $payment_reminders[$reminder];
|
||||
}
|
||||
|
||||
public function replacePlaceholder($payment, $payment_reminder)
|
||||
{
|
||||
$shopping_order = $payment->shopping_order;
|
||||
$shopping_user = $shopping_order->shopping_user;
|
||||
|
||||
$replacements = [
|
||||
'{billing_first_name}' => $shopping_user->billing_firstname,
|
||||
'{billing_last_name}' => $shopping_user->billing_lastname,
|
||||
'{order_number}' => '<b>'.$shopping_order->getLastShoppingPayment('reference').'</b>',
|
||||
'{order_date}' => '<b>'.$shopping_order->created_at->format('d.m.Y').'</b>',
|
||||
'{order_total}' => '<b>'.$shopping_order->getFormattedTotalShipping().'</b>'
|
||||
];
|
||||
|
||||
$payment_reminder->subject = str_replace(
|
||||
array_keys($replacements),
|
||||
array_values($replacements),
|
||||
$payment_reminder->subject
|
||||
);
|
||||
|
||||
$payment_reminder->message = str_replace(
|
||||
array_keys($replacements),
|
||||
array_values($replacements),
|
||||
$payment_reminder->message
|
||||
);
|
||||
|
||||
return $payment_reminder;
|
||||
}
|
||||
|
||||
public function sendReminderEmail($payment, $payment_reminder)
|
||||
{
|
||||
try {
|
||||
$email = $payment->shopping_order->shopping_user->billing_email;
|
||||
$subject = $payment_reminder->subject;
|
||||
$message = $payment_reminder->message;
|
||||
|
||||
if(Util::isTestSystem()){
|
||||
$email = config('app.checkout_test_mail');
|
||||
}
|
||||
|
||||
if($payment->shopping_order->mode === 'test' || Util::isTestSystem()){
|
||||
$bcc[] = config('app.checkout_test_mail');
|
||||
}else{
|
||||
$bcc[] = config('app.checkout_mail');
|
||||
}
|
||||
|
||||
Mail::to($email)->bcc($bcc)->send(new PaymentReminderEmail($subject, $message, $payment->shopping_order));
|
||||
|
||||
return true;
|
||||
} catch (\Exception $e) {
|
||||
\Log::error('Fehler beim E-Mail-Versand: ' . $e->getMessage());
|
||||
$this->createLog(
|
||||
'email_exception',
|
||||
"E-Mail Exception: " . $e->getMessage() . " für Payment ID: {$payment->id}",
|
||||
'ShoppingOrder',
|
||||
$payment->shopping_order_id,
|
||||
5
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Berechnet den Countdown bis zur nächsten Zahlungserinnerung
|
||||
*/
|
||||
public function getNextReminderCountdown($payment)
|
||||
{
|
||||
// Wenn noch keine Erinnerung gesendet wurde
|
||||
if ($payment->reminder == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Hole alle aktiven Erinnerungen für diesen Clearingtype
|
||||
$payment_reminders = PaymentReminder::where('active', true)
|
||||
->where('clearingtype', $payment->clearingtype)
|
||||
->orderBy('interval', 'asc')
|
||||
->get();
|
||||
|
||||
if ($payment_reminders->isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Wenn alle Erinnerungen bereits gesendet wurden
|
||||
if ($payment->reminder >= $payment_reminders->count()) {
|
||||
return [
|
||||
'type' => 'completed',
|
||||
'message' => 'Alle Erinnerungen gesendet',
|
||||
'days_left' => 0
|
||||
];
|
||||
}
|
||||
|
||||
// Hole die nächste Erinnerung
|
||||
$next_reminder = $payment_reminders[$payment->reminder];
|
||||
|
||||
// Berechne die Differenz zwischen aktuellem und nächstem Reminder
|
||||
$current_reminder = $payment_reminders[$payment->reminder - 1];
|
||||
$interval_difference = $next_reminder->interval - $current_reminder->interval;
|
||||
|
||||
// Berechne das Datum der nächsten Erinnerung
|
||||
$next_reminder_date = Carbon::parse($payment->reminder_date)->addDays($interval_difference);
|
||||
|
||||
// Berechne die verbleibenden Tage
|
||||
$days_left = Carbon::now()->diffInDays($next_reminder_date, false);
|
||||
|
||||
// Wenn die nächste Erinnerung bereits fällig ist
|
||||
if ($days_left <= 0) {
|
||||
return [
|
||||
'type' => 'overdue',
|
||||
'message' => 'Nächste Erinnerung fällig',
|
||||
'days_left' => 0,
|
||||
'next_reminder_date' => $next_reminder_date
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'type' => 'countdown',
|
||||
'message' => 'Nächste Erinnerung in ' . $days_left . ' Tagen',
|
||||
'days_left' => $days_left,
|
||||
'next_reminder_date' => $next_reminder_date,
|
||||
'next_reminder_interval' => $interval_difference
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Hole alle Logs für Payment Reminder
|
||||
*/
|
||||
public function getPaymentReminderLogs($limit = 100, $paymentId = null, $action = null)
|
||||
{
|
||||
$query = Logger::where('channel', 'payment_reminder')
|
||||
->orderBy('created_at', 'desc');
|
||||
|
||||
if ($paymentId) {
|
||||
$query->where('model_id', $paymentId);
|
||||
}
|
||||
|
||||
if ($action) {
|
||||
$query->where('action', $action);
|
||||
}
|
||||
|
||||
return $query->limit($limit)->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Hole Logs für einen spezifischen Payment
|
||||
*/
|
||||
public function getLogsForPayment($orderId)
|
||||
{
|
||||
return Logger::where('channel', 'payment_reminder')
|
||||
->where('model_id', $orderId)
|
||||
->orderBy('created_at', 'desc')
|
||||
->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Hole Logs für einen spezifischen Zeitraum
|
||||
*/
|
||||
public function getLogsForDateRange($startDate, $endDate)
|
||||
{
|
||||
return Logger::where('channel', 'payment_reminder')
|
||||
->whereBetween('created_at', [$startDate, $endDate])
|
||||
->orderBy('created_at', 'desc')
|
||||
->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Hole Statistiken für Payment Reminder Logs
|
||||
*/
|
||||
public function getLogStatistics($days = 30)
|
||||
{
|
||||
$startDate = Carbon::now()->subDays($days);
|
||||
|
||||
$stats = Logger::where('channel', 'payment_reminder')
|
||||
->where('created_at', '>=', $startDate)
|
||||
->selectRaw('action, level, COUNT(*) as count')
|
||||
->groupBy('action', 'level')
|
||||
->get();
|
||||
|
||||
$summary = [
|
||||
'total_logs' => Logger::where('channel', 'payment_reminder')
|
||||
->where('created_at', '>=', $startDate)
|
||||
->count(),
|
||||
'emails_sent' => Logger::where('channel', 'payment_reminder')
|
||||
->where('action', 'email_sent')
|
||||
->where('created_at', '>=', $startDate)
|
||||
->count(),
|
||||
'emails_failed' => Logger::where('channel', 'payment_reminder')
|
||||
->where('action', 'email_exception')
|
||||
->where('created_at', '>=', $startDate)
|
||||
->count(),
|
||||
'reminders_completed' => Logger::where('channel', 'payment_reminder')
|
||||
->where('action', 'reminder_completed')
|
||||
->where('created_at', '>=', $startDate)
|
||||
->count(),
|
||||
'actions_executed' => Logger::where('channel', 'payment_reminder')
|
||||
->where('action', 'action_completed')
|
||||
->where('created_at', '>=', $startDate)
|
||||
->count(),
|
||||
];
|
||||
|
||||
return [
|
||||
'summary' => $summary,
|
||||
'detailed_stats' => $stats
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
201
app/Services/PaymentService.php
Normal file
201
app/Services/PaymentService.php
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
<?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();
|
||||
}
|
||||
}
|
||||
|
|
@ -44,7 +44,11 @@ class UserMarign
|
|||
return $sum_net_amount;
|
||||
}
|
||||
|
||||
public static function getMontlyAmount(User $user, $date = null, $format = false){
|
||||
public static function getMontlyAmount($user, $date = null, $format = false){
|
||||
|
||||
if(!$user instanceof User){
|
||||
return 0;
|
||||
}
|
||||
|
||||
$now = $date ? Carbon::parse($date) : Carbon::now();
|
||||
$startDay = $now->startOfMonth()->toDateString();
|
||||
|
|
@ -202,7 +206,8 @@ class UserMarign
|
|||
->whereOutPaid(false)
|
||||
->whereCancellation(false)
|
||||
->whereMarginPaid(false)
|
||||
->whereNotNull('margin_pending_to');
|
||||
->whereNotNull('margin_pending_to')
|
||||
->whereIn('status', [7,8]);
|
||||
|
||||
if ($isPending) {
|
||||
$query->where('margin_pending_to', '>=', Carbon::now());
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ namespace App\Services;
|
|||
|
||||
use Yard;
|
||||
use App\User;
|
||||
use Illuminate\Support\Str;
|
||||
use App\Models\PromotionUser;
|
||||
use App\Models\ShippingCountry;
|
||||
|
||||
|
|
@ -18,7 +19,7 @@ class UserService
|
|||
public static function createConfirmationCode() {
|
||||
$unique = false;
|
||||
do{
|
||||
$confirmation_code = str_random(30);
|
||||
$confirmation_code = Str::random(30);
|
||||
if(User::where('confirmation_code', '=', $confirmation_code)->count() == 0){
|
||||
$unique = true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ class Util
|
|||
|
||||
public static function getToken()
|
||||
{
|
||||
return hash_hmac('sha256', str_random(40), config('app.key'));
|
||||
return hash_hmac('sha256', Str::random(40), config('app.key'));
|
||||
}
|
||||
|
||||
public static function uuidToken()
|
||||
|
|
@ -127,7 +127,7 @@ class Util
|
|||
return false;
|
||||
}
|
||||
|
||||
public static function setUserHistoryValue($values = [], $identifier){
|
||||
public static function setUserHistoryValue($values, $identifier){
|
||||
if($user_history = self::getUserHistory($identifier)){
|
||||
foreach ($values as $key=>$val){
|
||||
$user_history->{$key} = $val;
|
||||
|
|
@ -171,6 +171,13 @@ class Util
|
|||
return false;
|
||||
}
|
||||
|
||||
public static function isTestSystem(){
|
||||
if(config('app.debug')){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function isPromotionUrl($debug = false){
|
||||
if($debug && config('app.debug')){
|
||||
return false;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue