diff --git a/app/Console/Commands/BusinessStore.php b/app/Console/Commands/BusinessStore.php
index 809e7700..67484d00 100644
--- a/app/Console/Commands/BusinessStore.php
+++ b/app/Console/Commands/BusinessStore.php
@@ -17,7 +17,7 @@ class BusinessStore extends Command
*
* @var string
*/
- protected $signature = 'business:store {month} {year}';
+ protected $signature = 'business:store {month} {year}';
/**
* The console command description.
diff --git a/app/Console/Commands/UserCleanUp.php b/app/Console/Commands/UserCleanUp.php
new file mode 100644
index 00000000..8a8e5295
--- /dev/null
+++ b/app/Console/Commands/UserCleanUp.php
@@ -0,0 +1,159 @@
+info('RUN Command user:cleanup');
+
+ $this->timeStart = microtime(true);
+
+ $this->deleteInavtiveUsers();
+ //alle inaktive User werden deaktivert, die childs werden dem nächsten aktiven Berater (parent) zugewiesen.
+ $this->cleanUpInActiveUser();
+
+ return 0;
+
+ //\Log::info('Cron is running');
+ //return 0;
+ }
+
+ //gibt es gelöschte Berater mit Kunden und childs???
+
+ private function deleteInavtiveUsers(){
+
+ $this->info('START Command deleteInavtiveUsers');
+ $count = 0;
+
+ $date = Carbon::now()->modify('-2 month');
+ $delete_users = User::where('admin', 0)->where('payment_account', '<', $date)->get();
+
+ foreach($delete_users as $delete_user){
+ /*
+ dump('delete_users ---------- ');
+ dump($delete_user->id);
+ dump($delete_user->email);
+ */
+ //finde nächsten aktiven Sponsor $delete_user->id kann sponsor oder pre sponsor sein
+ $active_sponsor = UserUtil::findNextActiveSponsor($delete_user->id);
+ if($active_sponsor){
+ //setze alle Berater vom Sponsor für alle childs
+ UserUtil::setNewSponsorToChilds($delete_user->id, $active_sponsor->id);
+ UserUtil::setShoppingUserToNewMember($delete_user->id, $active_sponsor->id);
+ }else{
+ \Log::channel('cleanup')->error('deleteInavtiveUsers find no active_sponsor by delete_user_id:'.$delete_user->id);
+ continue;
+ }
+ /*
+ dump('findNextActiveSponsor');
+ dump($active_sponsor->email);
+ */
+ //make User to an Client from sponsor and delete User
+ UserUtil::setUserToClient($delete_user->id, $active_sponsor->id);
+
+ $data = [
+ 'user_id' => $delete_user->id,
+ 'email' => $delete_user->email,
+ 'm_account' => $delete_user->account ? $delete_user->account->m_account : '',
+ 'm_first_name' => $delete_user->account ? $delete_user->account->m_first_name : '',
+ 'm_last_name' => $delete_user->account ? $delete_user->account->m_last_name : '',
+ ];
+ $count ++;
+ \Log::channel('cleanup')->info('deleteUser: '.json_encode($data));
+ UserUtil::deleteUser($delete_user);
+ }
+
+ $diff = microtime(true) - $this->timeStart;
+ $sec = intval($diff);
+ $micro = $diff - $sec;
+
+ $this->info('END Command deleteInavtiveUsers: '.$count. ' | Time: '.$sec. 'sec :' . round($micro * 1000, 4) . " ms");
+
+ }
+
+ private function cleanUpInActiveUser(){
+
+ $this->info('START Command cleanUpInActiveUser');
+ $count = 0;
+
+ //clean up user where inactive since 2 weeks
+ $date = Carbon::now()->modify('-2 weeks');
+
+ $inactive_users = User::where('active', true)->where('m_sponsor', '!=', null)->where('payment_account', '<', $date)->get();
+ foreach($inactive_users as $inactive_user){
+ /*
+ dump('inactive_user ---------- ');
+ dump($inactive_user->id);
+ dump($inactive_user->email);
+ */
+ $active_sponsor = UserUtil::findNextActiveSponsor($inactive_user->m_sponsor);
+ if($active_sponsor){
+ UserUtil::setNewSponsorToChilds($inactive_user->id, $active_sponsor->id);
+ }else{
+ \Log::channel('cleanup')->error('cleanUpInActiveUser find no active_sponsor by inactive_user:'.$inactive_user->id);
+ }
+ /*
+ dump('findNextActiveSponsor');
+ dump($active_sponsor->email);
+ */
+ $data = [
+ 'user_id' => $inactive_user->id,
+ 'email' => $inactive_user->email,
+ 'm_account' => $inactive_user->account ? $inactive_user->account->m_account : '',
+ 'm_first_name' => $inactive_user->account ? $inactive_user->account->m_first_name : '',
+ 'm_last_name' => $inactive_user->account ? $inactive_user->account->m_last_name : '',
+ ];
+ $count ++;
+
+ \Log::channel('cleanup')->info('inactive_user: '.json_encode($data));
+ UserUtil::deactiveUser($inactive_user);
+ }
+
+ $diff = microtime(true) - $this->timeStart;
+ $sec = intval($diff);
+ $micro = $diff - $sec;
+
+ $this->info('END Command cleanUpInActiveUser: '.$count. ' | Time: '.$sec. 'sec :' . round($micro * 1000, 4) . " ms");
+ }
+}
diff --git a/app/Console/Commands/UserRestore.php b/app/Console/Commands/UserRestore.php
new file mode 100644
index 00000000..6ee9b69f
--- /dev/null
+++ b/app/Console/Commands/UserRestore.php
@@ -0,0 +1,112 @@
+info('RUN Command user:restore');
+
+ $this->timeStart = microtime(true);
+
+ $this->restoreInavtiveUsers();
+ return 0;
+
+ //\Log::info('Cron is running');
+ //return 0;
+ }
+
+ //gibt es gelöschte Berater mit Kunden und childs???
+
+ private function restoreInavtiveUsers(){
+
+ $this->info('START Command restoreInavtiveUsers');
+ $count = 0;
+
+ $this->user_id = $this->argument('user_id');
+
+ if(!$this->user_id){
+ $this->info('NO user_id as argument');
+ return;
+ }
+
+ $this->info('RUN Command restoreInavtiveUsers on user_id: '.$this->user_id);
+
+ $user = User::find($this->user_id);
+
+ if(!$user){
+ $this->info('restoreInavtiveUsers find no user by user_id:'.$this->user_id);
+ \Log::channel('cleanup')->error('restoreInavtiveUsers find no user by user_id:'.$this->user_id);
+ return 0;
+ }
+
+ $data = [
+ 'user_id' => $user->id,
+ 'email' => $user->email,
+ 'm_account' => $user->account ? $user->account->m_account : '',
+ 'm_first_name' => $user->account ? $user->account->m_first_name : '',
+ 'm_last_name' => $user->account ? $user->account->m_last_name : '',
+ ];
+ \Log::channel('cleanup')->info('reactiveUser: '.json_encode($data));
+
+ UserUtil::reactiveUser($user);
+ //childs wieder herstellen
+ UserUtil::resetChildsToSponsor($user->id);
+
+
+ $diff = microtime(true) - $this->timeStart;
+ $sec = intval($diff);
+ $micro = $diff - $sec;
+
+ $this->info('END Command deleteInavtiveUsers: '.$count. ' | Time: '.$sec. 'sec :' . round($micro * 1000, 4) . " ms");
+
+ }
+}
+
+
+//497
+
+//489 -> de
+
+//478 new
\ No newline at end of file
diff --git a/app/Cron/UserLevelUpdate.php b/app/Cron/UserLevelUpdate.php
index 88e5d96b..c56e54f3 100644
--- a/app/Cron/UserLevelUpdate.php
+++ b/app/Cron/UserLevelUpdate.php
@@ -63,6 +63,6 @@ class UserLevelUpdate
}else{
$bcc[] = config('app.checkout_mail');
}
- Mail::to($email)->bcc($bcc)->send(new MailUserLevelUpdate($tp, $to));
+ Mail::to($email)->bcc($bcc)->locale($user->getLocale())->send(new MailUserLevelUpdate($tp, $to));
}
}
diff --git a/app/Cron/UserPaymentCredits.php b/app/Cron/UserPaymentCredits.php
index aac5ca74..24d12fb8 100644
--- a/app/Cron/UserPaymentCredits.php
+++ b/app/Cron/UserPaymentCredits.php
@@ -32,8 +32,10 @@ class UserPaymentCredits
}
public function addUserCreditItem($userBusiness)
- {
- $date = HTMLHelper::getMonth($userBusiness->month).' '.$userBusiness->year;
+ {
+ //HTMLHelper::getMonth($userBusiness->month)
+
+ $date = $userBusiness->month.'#'.$userBusiness->year;
if($userBusiness->commission_shop_sales > 0){
if($this->hasNotUserCreditItem($userBusiness, 1)){
@@ -41,7 +43,9 @@ class UserPaymentCredits
'user_id' => $userBusiness->user_id,
'user_business_id' => $userBusiness->id,
'credit' => $userBusiness->commission_shop_sales,
- 'message' => 'Provision Shop '.$date,
+ 'message' => 'payment.commission_shop#'.$date,
+ 'from_month' => $userBusiness->month,
+ 'from_year' => $userBusiness->year,
'status' => 1,
]);
}
@@ -52,7 +56,9 @@ class UserPaymentCredits
'user_id' => $userBusiness->user_id,
'user_business_id' => $userBusiness->id,
'credit' => $userBusiness->commission_pp_total,
- 'message' => 'Provision Payline '.$date,
+ 'message' => 'payment.commission_payline#'.$date,
+ 'from_month' => $userBusiness->month,
+ 'from_year' => $userBusiness->year,
'status' => 2,
]);
}
@@ -63,7 +69,9 @@ class UserPaymentCredits
'user_id' => $userBusiness->user_id,
'user_business_id' => $userBusiness->id,
'credit' => $userBusiness->commission_growth_total,
- 'message' => 'Provision Wachstumsbonus '.$date,
+ 'message' => 'payment.commission_growth_bonus#'.$date,
+ 'from_month' => $userBusiness->month,
+ 'from_year' => $userBusiness->year,
'status' => 5,
]);
}
diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php
index 59c585dc..3586c3f6 100755
--- a/app/Exceptions/Handler.php
+++ b/app/Exceptions/Handler.php
@@ -2,8 +2,12 @@
namespace App\Exceptions;
-use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Throwable;
+use Illuminate\Support\Facades\Log;
+use Illuminate\Support\Facades\Mail;
+use Symfony\Component\ErrorHandler\Exception\FlattenException;
+use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
+use Symfony\Component\ErrorHandler\ErrorRenderer\HtmlErrorRenderer;
class Handler extends ExceptionHandler
{
@@ -36,6 +40,10 @@ class Handler extends ExceptionHandler
*/
public function report(Throwable $exception)
{
+
+ if ($this->shouldReport($exception)) {
+ $this->sendEmail($exception);
+ }
parent::report($exception);
}
@@ -52,4 +60,23 @@ 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));
+ \Mail::send('emails.exception', compact('css','content'), function ($message) {
+ $message
+ ->to(config('app.exception_mail'))
+ ->subject('mivita Exception: ' . \Request::fullUrl())
+ ;
+ });
+ } catch (Throwable $ex) {
+ Log::error($ex);
+ }
+ }
}
diff --git a/app/Exports/xExport.php b/app/Exports/xExport.php
new file mode 100644
index 00000000..2494092b
--- /dev/null
+++ b/app/Exports/xExport.php
@@ -0,0 +1,33 @@
+collection = $data;
+ $this->headings = $header;
+ }
+
+ public function collection()
+ {
+ return collect($this->collection);
+ }
+
+ public function headings(): array
+ {
+ return [$this->headings];
+ }
+
+}
\ No newline at end of file
diff --git a/app/Http/Controllers/Admin/DownloadController.php b/app/Http/Controllers/Admin/DownloadController.php
new file mode 100644
index 00000000..0eeb6586
--- /dev/null
+++ b/app/Http/Controllers/Admin/DownloadController.php
@@ -0,0 +1,188 @@
+middleware('admin');
+ $this->tagRepository = $tagRepository;
+ $this->fileRepository = $fileRepository;
+ }
+
+ public function files(){
+ $q = DcFile::orderBy('id', 'desc')->get(); //File::all();
+ $data = [
+ 'files' => $q,
+ ];
+ return view('admin.downloadcenter.files', $data);
+ }
+
+ public function fileEdit($id = null){
+ $file = $id ? DcFile::find($id) : new DcFile;
+ $data = [
+ 'file' => $file,
+ 'categories' => DcCategory::where('active', true)->orderBy('pos')->get(),
+ 'tags' => DcTag::orderBy('pos')->get(),
+ ];
+ return view('admin.downloadcenter.file_edit', $data);
+ }
+
+ public function fileUpdate($do, $id){
+
+ if($do === 'make_thumb'){
+ $this->fileRepository->makeThumb($id);
+ \Session()->flash('alert-success', 'Vorschaubild erstellt!');
+ return back();
+ }
+ if($do === 'delete'){
+ $this->fileRepository->deleteFile($id);
+ \Session()->flash('alert-success', 'Datei gelöscht!');
+ return redirect(route('admin_downloadcenter_files'));
+ }
+ if($do === 'delete_thumb'){
+ $this->fileRepository->deleteThumb($id);
+ \Session()->flash('alert-success', 'Vorschaubild gelöscht!');
+ return back();
+ }
+ if($do === 'deactivate'){
+ $file = DcFile::findOrFail($id);
+ $file->active = false;
+ $file->save();
+ \Session()->flash('alert-success', 'Datei nicht anzeigen!');
+ return back();
+ }
+
+ if($do === 'activate'){
+ $file = DcFile::findOrFail($id);
+ $file->active = true;
+ $file->save();
+ \Session()->flash('alert-success', 'Datei wird angezeigt!');
+ return back();
+ }
+ if($do === 'file_tags_update'){
+ $file = DcFile::findOrFail($id);
+ $this->fileRepository->tagsUpdate($id, Request::get('nestable_check'));
+ \Session()->flash('alert-success', 'Tags aktualisiert!');
+ return back();
+ }
+
+ }
+
+ public function upload(){
+ return view('admin.downloadcenter.file_upload');
+ }
+
+ public function uploadFile(){
+ $data = Request::all();
+ $file = $this->fileRepository->uploadFile($data);
+
+ return Response::json([
+ 'error' => false,
+ 'filename' => $file->filename,
+ 'filedata' => '',
+ 'code' => 200
+ ], 200);
+
+ //return response()->json(['success'=>basename($file)]);
+ }
+
+ public function tags($flash = false){
+
+ $active = DcCategory::orderBy('pos')->get();
+ $inactive = DcTag::where('category_id', null)->get();
+ $data = [
+ 'category_active' => $active,
+ 'tags_inactive' => $inactive,
+ ];
+ if($flash){
+ \Session()->flash('alert-success', 'gespeichert!');
+ }
+ return view('admin.downloadcenter.tags', $data);
+ }
+
+ public function storeItem($obj = false){
+ $data = Request::all();
+ return $this->tagRepository->storeItem($obj, $data);
+ return redirect(route('admin_downloadcenter_tags'));
+ }
+
+
+ public function deleteItem($obj, $id){
+ $this->tagRepository->deleteItem($obj, $id);
+ return redirect(route('admin_downloadcenter_tags'));
+ }
+
+ public function datatable(){
+
+ $query = DcFile::with('tags')->select('dc_files.*');
+ return \DataTables::eloquent($query)
+ ->addColumn('id', function (DcFile $file) {
+ return '';
+ })
+ ->addColumn('image', function (DcFile $file) {
+ return ($file->hasThumb() && $file->hasBig()) ?
+ '' :
+ ' Vorschaubild
erstellen ';
+ })
+ ->addColumn('name', function (DcFile $file) {
+ //Storage::disk('local')->url($file->filename) }}
+ return ''.$file->original_name.'';
+ // return ''.$file->original_name.'';
+ })
+ ->addColumn('category', function (DcFile $file) {
+ //return $file->category ? $file->category->name : '';
+ })
+ ->addColumn('tags', function (DcFile $file) {
+ //return $file->hasTags() ? '('.$file->fileTag()->count().')' : 'X';
+ return $file->tags->implode('name', '
');
+ })
+ ->addColumn('size', function (DcFile $file) {
+ return Util::formatBytes($file->size);
+ })
+ ->addColumn('active', function (DcFile $file) {
+ return get_active_badge($file->active);
+ //return $file->active ? ' aktiv' : ' inaktiv';
+ })
+ ->addColumn('created_at', function (DcFile $file) {
+ return $file->created_at->format('d.m.Y H:i');
+ })
+ ->addColumn('updated_at', function (DcFile $file) {
+ return $file->updated_at->format('d.m.Y');
+ })
+ ->addColumn('action', function (DcFile $file) {
+ return '';
+ })
+ ->filterColumn('name', function($query, $keyword) {
+ if($keyword != ""){
+ $query->where('original_name', 'LIKE', '%'.$keyword.'%');
+ }
+ })
+ ->orderColumn('id', 'id $1')
+ ->orderColumn('name', 'original_name $1')
+ ->orderColumn('original_name', 'original_name $1')
+ ->orderColumn('category', 'category $1')
+ ->orderColumn('size', 'size $1')
+ ->orderColumn('active', 'active $1')
+ ->orderColumn('created_at', 'created_at $1')
+ ->rawColumns(['id', 'image', 'name', 'active', 'tags', 'action'])
+ ->make(true);
+ }
+
+}
diff --git a/app/Http/Controllers/Admin/PaymentSalesController.php b/app/Http/Controllers/Admin/PaymentSalesController.php
new file mode 100644
index 00000000..528e24d5
--- /dev/null
+++ b/app/Http/Controllers/Admin/PaymentSalesController.php
@@ -0,0 +1,467 @@
+middleware('admin');
+ }
+
+ public function index()
+ {
+ $this->setFilterVars();
+ $data = [
+ 'filter_months' => HTMLHelper::getTransMonths(),
+ 'filter_years' => HTMLHelper::getYearRange(2022),
+ ];
+ return view('admin.payment.salesvolume', $data);
+ }
+
+
+ public function download(){
+
+ /*
+ EXCEL EXPORT function */
+
+ /*
+ if(Request::get('action') === "exportfull_paid"){
+ return $this->exportFullList(1);
+ }
+ if(Request::get('action') === "exportfull_unpaid"){
+ return $this->exportFullList(0);
+ }
+ */
+ if(Request::get('action') === "exportfull_paid_invoice"){
+ return $this->exportFullListInvoice();
+ }
+ if(Request::get('action') === "export"){
+ return $this->exportKompaktListInvoice();
+ }
+ }
+
+
+ private function setFilterVars(){
+
+ if(!session('payment_sales_vol_filter_month')){
+ session(['payment_sales_vol_filter_month' => intval(date('m'))]);
+ }
+ if(!session('payment_sales_vol_filter_year')){
+ session(['payment_sales_vol_filter_year' => intval(date('Y'))]);
+ }
+
+ if(Request::get('payment_sales_vol_filter_month')){
+ session(['payment_sales_vol_filter_month' => Request::get('payment_sales_vol_filter_month')]);
+ }
+ if(Request::get('payment_sales_vol_filter_year')){
+ session(['payment_sales_vol_filter_year' => Request::get('payment_sales_vol_filter_year')]);
+ }
+ }
+
+ private function exportKompaktListInvoice(){
+ $objects = $this->initKompaktList();
+ $columns = [];
+ $filename = "mivita-absatzmengen-kompakt".session('payment_sales_vol_filter_month').'_'.session('payment_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 exportFullListInvoice(){
+
+ $this->setFilterVars();
+
+ $UserInvoices = UserInvoice::with('shopping_order')->with('shopping_order.shopping_user')->select('user_invoices.*')
+ ->where('user_invoices.month', '=', session('payment_sales_vol_filter_month'))
+ ->where('user_invoices.year', '=', session('payment_sales_vol_filter_year'))
+ ->get();
+
+ $headers = array('Rechnungsnummer','Datum', 'EMail', 'Zahlung', 'ProduktNummer', 'ProduktName', 'Anzahl', 'Summe', 'Kompensation');
+ $columns = [];
+ $hasSOID = [];
+ $total_value = [];
+
+ foreach($UserInvoices as $UserInvoice){
+ if($UserInvoice->shopping_order){
+ $ShoppingOrder = $UserInvoice->shopping_order;
+ $object = [];
+ $object['Rechnungsnummer'] = $UserInvoice->full_number;
+ $object['Datum'] = $UserInvoice->date;
+ $object['EMail'] = $ShoppingOrder->shopping_user ? $ShoppingOrder->shopping_user->billing_email : 'n/a';
+ $object['Zahlung'] = $ShoppingOrder->getPaymentForType();
+
+ if($ShoppingOrder->payment_for === 5){ //homeparty
+ if($ShoppingOrder->homeparty){
+ foreach($ShoppingOrder->homeparty->homeparty_order_items as $homeparty_item){
+ $total_value[$homeparty_item->product_id] = isset($total_value[$homeparty_item->product_id]) ? $total_value[$homeparty_item->product_id] + $homeparty_item->qty : $homeparty_item->qty;
+ $object['ProduktNummer'] = $homeparty_item->product ? $homeparty_item->product->number : "n/a";
+ $object['ProduktName'] = $homeparty_item->product ? $homeparty_item->product->name : "n/a";
+ $object['Anzahl'] = $homeparty_item->qty;
+ $object['Summe'] = $total_value[$homeparty_item->product_id];
+ $object['Kompensation'] = '';
+ $columns[] = $object;
+ }
+ }
+
+ }elseif($ShoppingOrder->payment_for === 8){ //collective_invoice
+ if($ShoppingOrder->shopping_collect_order){
+ foreach($ShoppingOrder->shopping_collect_order->shop_items as $shop_item){
+ $total_value[$shop_item['pid']] = isset($total_value[$shop_item['pid']]) ? $total_value[$shop_item['pid']] + $shop_item['qty'] : $shop_item['qty'];
+ $object['ProduktNummer'] = $shop_item['number'];
+ $object['ProduktName'] = $shop_item['name'];
+ $object['Anzahl'] = $shop_item['qty'];
+ $object['Summe'] = $total_value[$shop_item['pid']];
+ $object['Kompensation'] = '';
+ $columns[] = $object;
+ }
+
+ }
+ }else{
+ if($ShoppingOrder->shopping_order_items){
+ foreach($ShoppingOrder->shopping_order_items as $shopping_order_item){
+ $total_value[$shopping_order_item->product_id] = isset($total_value[$shopping_order_item->product_id]) ? $total_value[$shopping_order_item->product_id] + $shopping_order_item->qty : $shopping_order_item->qty;
+ $object['ProduktNummer'] = $shopping_order_item->product ? $shopping_order_item->product->number : "n/a";
+ $object['ProduktName'] = $shopping_order_item->product ? $shopping_order_item->product->name : "n/a";
+ $object['Anzahl'] = $shopping_order_item->qty;
+ $object['Summe'] = $total_value[$shopping_order_item->product_id];
+ $object['Kompensation'] = ($shopping_order_item->comp ? $shopping_order_item->comp : '');
+
+ $columns[] = $object;
+ }
+ }
+ }
+ $hasSOID[] = $ShoppingOrder->id;
+
+ }
+ }
+
+ $filename = "mivita-absatzmengen-voll-".session('payment_sales_vol_filter_month').'_'.session('payment_sales_vol_filter_year')."-export";
+ return Excel::download(new xExport($columns, $headers), $filename.'.xls');
+
+ }
+
+
+
+ private function initKompaktList()
+ {
+ $this->setFilterVars();
+
+ $UserInvoices = UserInvoice::with('shopping_order')->with('shopping_order.shopping_user')->select('user_invoices.*')
+ ->where('user_invoices.month', '=', session('payment_sales_vol_filter_month'))
+ ->where('user_invoices.year', '=', session('payment_sales_vol_filter_year'))
+ ->get();
+
+ $objects = [];
+
+ foreach($UserInvoices as $UserInvoice){
+ if($UserInvoice->shopping_order){
+ $ShoppingOrder = $UserInvoice->shopping_order;
+
+ if($ShoppingOrder->payment_for === 5){ //homeparty
+ if($ShoppingOrder->homeparty){
+ foreach($ShoppingOrder->homeparty->homeparty_order_items as $homeparty_item){
+ if(isset($objects[$homeparty_item->product_id])){
+ $value = intval($objects[$homeparty_item->product_id]['value'] + $homeparty_item->qty);
+ $objects[$homeparty_item->product_id]['value'] = $value;
+ }else{
+ $objects[$homeparty_item->product_id] = [
+ 'name' => $homeparty_item->product ? $homeparty_item->product->name : "n/a ".$homeparty_item->product_id,
+ 'number' => $homeparty_item->product ? $homeparty_item->product->number : "n/a ".$homeparty_item->product_id,
+ 'value' => $homeparty_item->qty
+ ];
+ }
+ }
+ }
+
+ }elseif($ShoppingOrder->payment_for === 8){ //collective_invoice
+ if($ShoppingOrder->shopping_collect_order){
+ foreach($ShoppingOrder->shopping_collect_order->shop_items as $shop_item){
+
+ if(isset($objects[$shop_item['pid']])){
+ $value = intval($objects[$shop_item['pid']]['value'] + $shop_item['qty']);
+ $objects[$shop_item['pid']]['value'] = $value;
+ }else{
+ $objects[$shop_item['pid']] = [
+ 'name' => $shop_item['name'],
+ 'number' => $shop_item['number'],
+ 'value' => $shop_item['qty']
+ ];
+ }
+ }
+ }
+ }else{
+ if($ShoppingOrder->shopping_order_items){
+ foreach($ShoppingOrder->shopping_order_items as $shopping_order_item){
+ 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 ? $shopping_order_item->product->name : "n/a ".$shopping_order_item->product_id,
+ 'number' => $shopping_order_item->product ? $shopping_order_item->product->number : "n/a ".$shopping_order_item->product_id,
+ 'value' => $shopping_order_item->qty
+ ];
+ }
+ }
+ }
+ }
+ $hasSOID[] = $ShoppingOrder->id;
+
+ }
+ }
+
+ return $objects;
+
+ }
+
+ public function datatable(){
+
+
+ /*$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],
+ ]);*/
+ $objects = $this->initKompaktList();
+ $collection = collect();
+ if($objects){
+ foreach($objects as $key => $obj){
+ $collection->push([
+ 'id' => $key,
+ 'name' => $obj['name'],
+ 'number' => $obj['number'],
+ 'value' => $obj['value'],
+ ]);
+ }
+ }
+
+ return \DataTables::of($collection)->toJson();
+ }
+
+ /*
+ //Auswertung nach ShoppingOrder
+ //nach Datum created_at wann die Bestellung erstellt wurde
+ //Ist nicht das Datum der Rechnung, da hier teilweise die Sammelrechnungen oder Zahlungen erst in nächsten Monat erfolgen
+
+
+ public function exportFullList($paid = 1){
+
+
+ $date_start = Carbon::parse('01.'.session('payment_sales_vol_filter_month').'.'.session('payment_sales_vol_filter_year'))->format('Y-m-d H:i:s');
+ $date_end = Carbon::parse('01.'.session('payment_sales_vol_filter_month').'.'.session('payment_sales_vol_filter_year'))->endOfMonth()->format('Y-m-d H:i:s');
+ $ShoppingOrders = ShoppingOrder::where('paid', $paid)->where('mode', 'live')->whereBetween('created_at', [$date_start, $date_end])->get();
+
+ $txActions = ['prev' => 'keine Zahlung', 'appointed' => 'offen', 'failed' => 'abbruch', 'paid' => 'bezahlt'];
+ $headers = array('ID', 'Zahlung', 'Datum', 'EMail', 'ProduktID', 'ProduktNummer', 'ProduktName', 'Anzahl', 'Notiz', 'Gesamt');
+ $objects = [];
+ $columns = [];
+ $hasSOID = [];
+ foreach($ShoppingOrders as $ShoppingOrder){
+ foreach($ShoppingOrder->shopping_order_items as $shopping_order_item){
+ $value = "";
+ 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
+ ];
+ $value = $shopping_order_item->qty;
+
+ }
+
+ }
+ $object = [];
+ if(in_array($ShoppingOrder->id, $hasSOID)){
+ $object['ID'] = '';
+ $object['EMail'] = '';
+ $object['Zahlung'] = '';
+ $object['Datum'] = '';
+ }else{
+ $object['ID'] = $ShoppingOrder->id;
+ $object['EMail'] = $ShoppingOrder->shopping_user ? $ShoppingOrder->shopping_user->billing_email : 'n/a';
+ $object['Zahlung'] = isset($txActions[$ShoppingOrder->txaction]) ? $txActions[$ShoppingOrder->txaction] : $ShoppingOrder->txaction;
+ $object['Datum'] = $ShoppingOrder->created_at->format('d.m.Y');
+ }
+ $object['ProduktID'] = $shopping_order_item->product_id;
+ $object['ProduktNummer'] = $shopping_order_item->product ? $shopping_order_item->product->number : "n/a";
+ $object['ProduktName'] = $shopping_order_item->product ? $shopping_order_item->product->name : "n/a";
+ $object['Anzahl'] = $shopping_order_item->qty;
+ $object['Notiz'] = ($shopping_order_item->comp ? 'Compensation '.$shopping_order_item->comp : '') . ($shopping_order_item->shopping_collect_order_id ? 'Sammelbestellung '.$shopping_order_item->shopping_collect_order_id : '');
+ $object['Gesamt'] = $value;
+ $columns[] = $object;
+
+ $hasSOID[] = $ShoppingOrder->id;
+ }
+ }
+ if($paid){
+ $filename = "mivita-absatzmengen-full-paid-".session('payment_sales_vol_filter_month').'_'.session('payment_sales_vol_filter_year')."-export";
+ }else{
+ $filename = "mivita-absatzmengen-full-unpaid-".session('payment_sales_vol_filter_month').'_'.session('payment_sales_vol_filter_year')."-export";
+ }
+
+ return Excel::download(new xExport($columns, $headers), $filename.'.xls');
+
+ //CSV EXPORT function
+ $headers = array(
+ "Content-type" => "text/csv",
+ "Content-Disposition" => "attachment; filename=$fileName",
+ "Pragma" => "no-cache",
+ "Cache-Control" => "must-revalidate, post-check=0, pre-check=0",
+ "Expires" => "0"
+ );
+
+ $header = array('ID', 'Zahlung', 'Datum', 'EMail', 'ProduktID', 'ProduktNummer', 'ProduktName', 'Anzahl', 'Notiz', 'Gesamt');
+
+ $callback = function() use($columns, $header) {
+
+ $file = fopen('php://output', 'w');
+ fputcsv($file, $header);
+ $row = [];
+
+ foreach ($columns as $row) {
+ fputcsv($file, $row);
+
+ }
+
+ fclose($file);
+ };
+
+ return response()->stream($callback, 200, $headers);
+
+
+
+ }
+ */
+
+ /*
+ //alte Funktion auswerung nach ShoppingOrder
+ private function testCheckFunction(){
+ //$date_start = Carbon::parse('01.'.session('payment_sales_vol_filter_month').'.'.session('payment_sales_vol_filter_year'))->format('Y-m-d');
+ //$date_end = Carbon::parse('01.'.session('payment_sales_vol_filter_month').'.'.session('payment_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");
+ }*/
+
+ /*
+ // alte Funktion auswerung nach ShoppingOrder
+ private function initSearch($returnColl = true)
+ {
+ $this->setFilterVars();
+
+ $date_start = Carbon::parse('01.'.session('payment_sales_vol_filter_month').'.'.session('payment_sales_vol_filter_year'))->format('Y-m-d H:i:s');
+ $date_end = Carbon::parse('01.'.session('payment_sales_vol_filter_month').'.'.session('payment_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;
+ }
+ */
+
+}
\ No newline at end of file
diff --git a/app/Http/Controllers/AdminUserController.php b/app/Http/Controllers/AdminUserController.php
index f1e7d10c..ff1d882d 100755
--- a/app/Http/Controllers/AdminUserController.php
+++ b/app/Http/Controllers/AdminUserController.php
@@ -4,18 +4,19 @@ namespace App\Http\Controllers;
-use App\Models\PaymentMethod;
-use App\Models\UserAccount;
-use App\Repositories\UserRepository;
-use App\Services\HTMLHelper;
-use App\Services\SysLog;
-use App\User;
use Auth;
-use Illuminate\Support\Facades\Mail;
+use Carbon;
use Request;
+use App\User;
use Validator;
-
-
+use App\Services\SysLog;
+use App\Services\UserUtil;
+use App\Models\UserAccount;
+use App\Services\HTMLHelper;
+use App\Models\PaymentMethod;
+use App\Repositories\UserRepository;
+use Illuminate\Support\Facades\Mail;
+use Util;
class AdminUserController extends Controller
{
@@ -74,7 +75,7 @@ class AdminUserController extends Controller
SysLog::action('save-admin', 'admin_user', 3)
->setUserId(Auth::user()->id)
->setModel($user->id, User::class)
- ->setMessage('Set user admin value: '.HTMLHelper::getRoleLabel($user->admin))
+ ->setMessage('Set user admin value: '.HTMLHelper::getLabel($user->admin))
->save();
}
@@ -125,8 +126,21 @@ class AdminUserController extends Controller
$user->payment_account = null;
}else{
$user->wizard = 100;
- $user->payment_account = \Carbon::parse(str_replace("- ", "", $data['payment_account']));
+ $payment_account = \Carbon::parse(str_replace("- ", "", $data['payment_account']));
+ $user->payment_account = $payment_account;
+ if($payment_account > Carbon::now()){
+ if($user->active === 0){
+ $user->active = true;
+ UserUtil::reactiveUserResetChilds($user->id, 'on save-account AdminUserController');
+ }
+ }else{
+ if($user->active === 1){
+ $user->active = false;
+ UserUtil::deactiveUserNewSponsorChilds($user->id, 'on save-account AdminUserController');
+ }
+ }
}
+ //th.schifferegger@gmail.com
SysLog::action('save-account', 'admin_user', 3)
->setUserId(Auth::user()->id)
->setModel($user->id, User::class)
@@ -178,7 +192,7 @@ class AdminUserController extends Controller
$user = User::findOrFail($user_id);
$this->userRepo->deleteUser($user);
- \Session()->flash('alert-success', "Kontakt gelöscht");
+ \Session()->flash('alert-success', __('msg.contact_delete'));
return redirect('/admin/users');
}
@@ -192,4 +206,93 @@ class AdminUserController extends Controller
}
}
-}
\ No newline at end of file
+ public function getUsers()
+ {
+ $query = User::with('account')->select('users.*')->where('users.deleted_at', '=', null)->where('users.admin', "<", 5);
+
+ return \DataTables::eloquent($query)
+ ->addColumn('first_name', function (User $user) {
+ return $user->account ? $user->account->first_name : '';
+ })
+ ->addColumn('last_name', function (User $user) {
+ return $user->account ? $user->account->last_name : '';
+ })
+ ->addColumn('id', function (User $user) {
+ return '';
+ })
+ ->addColumn('admin', function (User $user) {
+ return ''.HTMLHelper::getRoleLabel($user->admin).'';
+ })
+ ->addColumn('confirmed', function (User $user) {
+ $date = $user->getConfirmationDateFormat();
+ $link = '';
+ return $user->confirmed ? $link.' '.$date.'' : $link.'';
+ })
+ ->addColumn('active', function (User $user) {
+ $date = $user->getActiveDateFormat();
+ $link = '';
+ return $user->active ? $link.' '.$date.'' : $link.'';
+ })
+ ->addColumn('account', function (User $user) {
+ $date = $user->getPaymentAccountDateFormat();
+ $link = '';
+ if($user->payment_account){
+ if($user->isActiveAccount()){
+ return $link.' '.$date.'';
+ }
+ return $link.' '.$date.'';
+ }
+ return $link.'';
+ })
+ ->addColumn('shop', function (User $user) {
+ $date = $user->getPaymentShopDateFormat();
+ $link = '';
+ if($user->payment_shop){
+ if($user->isActiveShop()){
+ return $link.' '.$date.'';
+ }
+ return $link.' '.$date.'';
+ }
+ return $link.'';
+ })
+ ->addColumn('since', function (User $user) {
+ if($user->shop){
+ if($user->shop->active){
+ return $user->shop->getActiveDateFormatSmall();
+ }
+ return $user->shop->getActiveDateFormatSmall();
+ }
+ return "-";
+ })
+ ->addColumn('country', function (User $user) {
+ return ($user->account && $user->account->country) ? $user->account->country->de : '';
+ })
+ ->addColumn('my_payment_methods', function (User $user) {
+ $payment_methods = json_encode($user->payment_methods);
+ $link = '';
+ if(!$user->payment_methods){
+ return $link.'';
+ }
+ return $link.' '.$user->getPaymentMethodsShort().'';
+
+ })
+ ->addColumn('action_login', function (User $user) {
+ return '';
+ })
+ ->addColumn('action_delete', function (User $user) {
+ return '';
+ })
+ ->addColumn('test_mode', function (User $user) {
+ $link = '';
+ return $user->test_mode ? $link.'' : $link.'';
+
+ })
+ ->orderColumn('id', 'id $1')
+ ->orderColumn('confirmed', 'confirmed $1')
+ ->orderColumn('active', 'active $1')
+ ->orderColumn('shop', 'shop $1')
+ ->orderColumn('admin', 'active $1')
+ ->rawColumns(['id', 'admin', 'confirmed', 'active', 'account', 'shop', 'my_payment_methods', 'test_mode', 'action_login', 'action_delete'])
+ ->make(true);
+ }
+}
diff --git a/app/Http/Controllers/Api/KasController.php b/app/Http/Controllers/Api/KasController.php
index 4a12020f..13210be1 100755
--- a/app/Http/Controllers/Api/KasController.php
+++ b/app/Http/Controllers/Api/KasController.php
@@ -13,7 +13,7 @@ class KasController extends Controller
// Logindaten
private $kas_user = 'w017f6e4'; // KAS-Logon
- private $kas_pass = '7mMJUF4YSVWNpp39'; // KAS-Passwort
+ private $kas_pass = 'Medxiz-funteb-7dubdi'; // KAS-Passwort
private $session_lifetime = 600; // Gültigkeit des Tokens in Sek. bis zur neuen Authentifizierung
private $session_update_lifetime = 'Y'; // bei N läuft die Session nach <$session_lifetime> Sekunden ab, bei Y verlängert sich die Session mit jeder Benutzung
private $CredentialToken = false;
diff --git a/app/Http/Controllers/Api/PayoneController.php b/app/Http/Controllers/Api/PayoneController.php
index 64811c06..2b51b82b 100755
--- a/app/Http/Controllers/Api/PayoneController.php
+++ b/app/Http/Controllers/Api/PayoneController.php
@@ -123,7 +123,7 @@ class PayoneController extends Controller
$shopping_payment->save();
$send_link = false;
-
+ $send_mail = true;
if($data['txaction'] === 'failed'){
$shopping_order->setUserHistoryValue(['status' => 6]);
@@ -135,10 +135,16 @@ class PayoneController extends Controller
}
if($data['txaction'] === 'paid'){
- $send_link = Payment::paymentStatusPaidAction($shopping_order, true);
+ if(!$shopping_order->paid){
+ $send_link = Payment::paymentStatusPaidAction($shopping_order, true);
+ }else{
+ $send_mail = false;
+ }
}
$data['send_link'] = $send_link;
- Payment::paymentStatusSendMail($shopping_order, $shopping_payment, $data);
+ if($send_mail){
+ Payment::paymentStatusSendMail($shopping_order, $shopping_payment, $data);
+ }
print("TSOK");
exit;
}
diff --git a/app/Http/Controllers/Api/ShoppingUserController.php b/app/Http/Controllers/Api/ShoppingUserController.php
index 348492be..24c96f5f 100755
--- a/app/Http/Controllers/Api/ShoppingUserController.php
+++ b/app/Http/Controllers/Api/ShoppingUserController.php
@@ -258,7 +258,7 @@ class ShoppingUserController extends Controller
$data['number'] = ShoppingUser::max('number') + 1;
$data['mode'] = $request->mode ? $request->mode : 'live';
$data['is_from'] = 'extern';
- $data['is_for'] = 'ot';
+ $data['is_for'] = 'ot-member';
$shopping_user = ShoppingUser::create($data);
@@ -484,7 +484,7 @@ class ShoppingUserController extends Controller
foreach ($shopping_order->shopping_order_items as $item){
$ret['items'][] = [
'article' => $item->product->wp_number,
- 'name' => $item->product->name,
+ 'name' => $item->product->getLang('name'),
'qty' => $item->qty,
'price' => ($item->price * 100),
];
@@ -593,7 +593,7 @@ class ShoppingUserController extends Controller
if ($order->price != ($product->price * 100)) {
$error[] = "different price: " . ($product->price * 100);
}
- $cartItem = Yard::instance('shopping')->add($product->id, $product->name, (int) $order->qty, $product->price, false, false, ['image' => [], 'slug' => $product->slug, 'weight' => $product->weight, 'points' => $product->points, 'no_commission' => $product->no_commission]);
+ $cartItem = Yard::instance('shopping')->add($product->id, $product->getLang('name'), (int) $order->qty, $product->price, false, false, ['image' => [], 'slug' => $product->slug, 'weight' => $product->weight, 'points' => $product->points, 'no_commission' => $product->no_commission]);
Yard::setTax($cartItem->rowId, $product->getTaxWith());
}
}
@@ -620,6 +620,7 @@ class ShoppingUserController extends Controller
'shopping_user_id' => $shopping_user->id,
'auth_user_id' => $shopping_user->auth_user_id,
'country_id' => Yard::instance('shopping')->getShippingCountryId(),
+ 'language' => \App::getLocale(),
'user_shop_id' => auth()->user()->user_sponsor->shop->id,
'payment_for' => 7,
'member_id' => $shopping_user->member_id,
@@ -711,7 +712,7 @@ class ShoppingUserController extends Controller
$bcc[] = config('app.checkout_mail');
}
- Mail::to($user_mail)->bcc($bcc)->send(new MailCheckout($shopping_order->txaction, $shopping_order, null, false, $shopping_order->mode));
+ Mail::to($user_mail)->bcc($bcc)->locale($shopping_order->getLocale())->send(new MailCheckout($shopping_order->txaction, $shopping_order, null, false, $shopping_order->mode));
}
}
\ No newline at end of file
diff --git a/app/Http/Controllers/BusinessCommissionController.php b/app/Http/Controllers/BusinessCommissionController.php
index a83e8619..f0fa1d2d 100644
--- a/app/Http/Controllers/BusinessCommissionController.php
+++ b/app/Http/Controllers/BusinessCommissionController.php
@@ -32,7 +32,7 @@ class BusinessCommissionController extends Controller
$this->setFilterVars();
$data = [
- 'filter_months' => HTMLHelper::$months,
+ 'filter_months' => HTMLHelper::getTransMonths(),
'filter_years' => HTMLHelper::getYearRange(),
'filter_members' => $filter_members,
'filter_show' => $this->filter_show,
@@ -108,7 +108,7 @@ class BusinessCommissionController extends Controller
data-back=""
data-modal="modal-xl"
data-init_from="user"
- data-route="'.route('modal_load').'">';
+ data-route="'.route('modal_load').'">';
})*/
diff --git a/app/Http/Controllers/BusinessController.php b/app/Http/Controllers/BusinessController.php
index bf70a66e..56e344d5 100644
--- a/app/Http/Controllers/BusinessController.php
+++ b/app/Http/Controllers/BusinessController.php
@@ -27,10 +27,9 @@ class BusinessController extends Controller
{
$this->setFilterVars();
$data = [
- 'filter_months' => HTMLHelper::$months,
+ 'filter_months' => HTMLHelper::getTransMonths(),
'filter_years' => HTMLHelper::getYearRange(),
'filter_active' => $this->filter_active,
-
];
return view('admin.business.show', $data);
}
@@ -45,7 +44,7 @@ class BusinessController extends Controller
$TreeCalcBot->initStructureAdmin();
$data = [
- 'filter_months' => HTMLHelper::$months,
+ 'filter_months' => HTMLHelper::getTransMonths(),
'filter_years' => HTMLHelper::getYearRange(),
'TreeCalcBot' => $TreeCalcBot,
];
@@ -94,7 +93,13 @@ class BusinessController extends Controller
if(!session('business_user_filter_active')){
session(['business_user_filter_active' => 1]);
}
+ if(!session('business_user_filter_depiction')){
+ session(['business_user_filter_depiction' => 'active']);
+ }
+ if(Request::get('business_user_filter_depiction')){
+ session(['business_user_filter_depiction' => Request::get('business_user_filter_depiction')]);
+ }
if(Request::get('business_user_filter_name')){
session(['business_user_filter_name' => Request::get('business_user_filter_name')]);
}
@@ -166,7 +171,7 @@ class BusinessController extends Controller
->addColumn('is_qual_kp', function (UserBusiness $userBusiness) {
if($userBusiness->m_level_id){
$isQualKP = ($userBusiness->sales_volume_points_sum >= $userBusiness->qual_kp) ? true : false;
- return ' KP '.$userBusiness->qual_kp.'';
+ return ' KU '.$userBusiness->qual_kp.'';
}
return '-';
})
@@ -295,14 +300,14 @@ class BusinessController extends Controller
return $user->account ? $user->account->m_account : '';
})
->addColumn('user_level', function (User $user) {
- return $user->user_level ? $user->user_level->name : '';
+ return $user->user_level ? $user->user_level->getLang('name') : '';
})
->addColumn('is_qual_kp', function (User $user) {
if($user->user_level){
$qual_kp = $user->user_level->qual_kp;
$sales_volume_points_sum = $user->getUserSalesVolumeBy($this->month, $this->year, 'sales_volume_points_KP_sum');
$isQualKP = ($sales_volume_points_sum >= $qual_kp) ? true : false;
- return ' KP '.$qual_kp.'';
+ return ' KU '.$qual_kp.'';
}
return '-';
})
diff --git a/app/Http/Controllers/BusinessPointsController.php b/app/Http/Controllers/BusinessPointsController.php
index 4c5932d8..ddadb36b 100644
--- a/app/Http/Controllers/BusinessPointsController.php
+++ b/app/Http/Controllers/BusinessPointsController.php
@@ -28,9 +28,11 @@ class BusinessPointsController extends Controller
$this->setFilterVars();
$data = [
- 'filter_months' => HTMLHelper::$months,
+ 'filter_months' => HTMLHelper::getTransMonths(),
'filter_years' => HTMLHelper::getYearRange(),
'filter_members' => $filter_members,
+ 'filter_status_types' => UserSalesVolume::getTransStatusType(),
+
];
return view('admin.business.points', $data);
@@ -76,7 +78,8 @@ class BusinessPointsController extends Controller
}
session(['points_filter_member_id' => Request::get('points_filter_member_id')]);
-
+ session(['points_filter_status_type_id' => Request::get('points_filter_status_type_id')]);
+
if(Request::get('points_filter_month')){
session(['points_filter_month' => Request::get('points_filter_month')]);
}
@@ -98,6 +101,9 @@ class BusinessPointsController extends Controller
if(Request::get('points_filter_member_id')){
$query->where('user_sales_volumes.user_id', '=', Request::get('points_filter_member_id'));
}
+ if(Request::get('points_filter_status_type_id')){
+ $query->where('user_sales_volumes.status', '=', Request::get('points_filter_status_type_id'));
+ }
return $query;
}
@@ -112,7 +118,7 @@ class BusinessPointsController extends Controller
data-back=""
data-modal="modal-xl"
data-init_from="user"
- data-route="'.route('modal_load').'">';
+ data-route="'.route('modal_load').'">';
})
->addColumn('order', function (UserSalesVolume $UserSalesVolume) {
if($UserSalesVolume->shopping_order){
@@ -128,6 +134,9 @@ class BusinessPointsController extends Controller
->addColumn('total_net', function (UserSalesVolume $UserSalesVolume) {
return formatNumber($UserSalesVolume->total_net).' €';
})
+ ->addColumn('status_turnover', function (UserSalesVolume $UserSalesVolume) {
+ return ''.$UserSalesVolume->getStatusTurnoverType().'';
+ })
->addColumn('status', function (UserSalesVolume $UserSalesVolume) {
return ''.$UserSalesVolume->getStatusType().'';
})
@@ -172,7 +181,7 @@ class BusinessPointsController extends Controller
->orderColumn('m_account', 'm_account $1')
->orderColumn('first_name', 'first_name $1')
->orderColumn('last_name', 'last_name $1')
- ->rawColumns(['id', 'order', 'status', 'status_points', 'message', 'info', 'total_net'])
+ ->rawColumns(['id', 'order', 'status_turnover', 'status', 'status_points', 'message', 'info', 'total_net'])
->make(true);
}
}
\ No newline at end of file
diff --git a/app/Http/Controllers/CategoryController.php b/app/Http/Controllers/CategoryController.php
index 20e93da9..2c37a9a3 100755
--- a/app/Http/Controllers/CategoryController.php
+++ b/app/Http/Controllers/CategoryController.php
@@ -124,7 +124,7 @@ class CategoryController extends Controller
return redirect(route('admin_product_categories'));
}
if(Category::where('parent_id', $id)->count()){
- \Session()->flash('alert-error', 'Eintrag wird als Haup-Kategorie verwendet');
+ \Session()->flash('alert-error', 'Eintrag wird als Haupt-Kategorie verwendet');
return redirect(route('admin_product_categories'));
}
$model = Category::findOrFail($id);
@@ -184,15 +184,15 @@ class CategoryController extends Controller
$category->headline_image_id = $iq_image->id;
$category->save();
- \Session()->flash('alert-success', "Datei hochgeladen");
+ \Session()->flash('alert-success', __('msg.file_uploaded'));
return redirect(route('admin_product_category_edit', [$category->id]));
}
- \Session()->flash('alert-danger', "Datei leer");
+ \Session()->flash('alert-danger', __('msg.file_empty'));
return redirect(route('admin_product_category_edit', [$category->id]));
}
catch (Exception $e) {
- \Session()->flash('alert-danger', "Fehler".$e);
+ \Session()->flash('alert-danger', "Error: ".$e);
return redirect(route('admin_product_category_edit', [$category->id]));
}
}
@@ -210,11 +210,11 @@ class CategoryController extends Controller
$iq_image->delete();
- \Session()->flash('alert-success', "Datei gelöscht");
+ \Session()->flash('alert-success', __('msg.file_deleted'));
return redirect(route('admin_product_category_edit', [$category->id]));
}
- \Session()->flash('alert-danger', "Datei nicht gefunden");
+ \Session()->flash('alert-danger', __('msg.file_not_found'));
return redirect(route('admin_product_category_edit', [$category->id]));
}
diff --git a/app/Http/Controllers/CountryController.php b/app/Http/Controllers/CountryController.php
index c491ac71..fdd5eef9 100755
--- a/app/Http/Controllers/CountryController.php
+++ b/app/Http/Controllers/CountryController.php
@@ -39,7 +39,6 @@ class CountryController extends Controller
}
$data = [
'country' => $model,
- 'trans' => array_keys(config('localization.supportedLocales')),
];
return view('admin.country.edit', $data);
@@ -52,6 +51,7 @@ class CountryController extends Controller
$data['active'] = isset($data['active']) ? true : false;
$data['switch'] = isset($data['switch']) ? true : false;
+ $data['translate'] = isset($data['translate']) ? true : false;
$data['eu_country'] = isset($data['eu_country']) ? true : false;
$data['own_eur'] = isset($data['own_eur']) ? true : false;
$data['currency'] = isset($data['currency']) ? true : false;
diff --git a/app/Http/Controllers/CronController.php b/app/Http/Controllers/CronController.php
index c34b719c..a66ce93d 100644
--- a/app/Http/Controllers/CronController.php
+++ b/app/Http/Controllers/CronController.php
@@ -2,14 +2,15 @@
namespace App\Http\Controllers;
-use App\Mail\MailCustomMessage;
-use App\Mail\MailVerifyAccount;
+use Carbon;
+use App\User;
+use App\Services\Util;
use App\Models\UserHistory;
use App\Models\UserMessage;
-use App\Repositories\UserRepository;
+use App\Mail\MailCustomMessage;
+use App\Mail\MailVerifyAccount;
use App\Services\PaymentHelper;
-use App\User;
-use Carbon;
+use App\Repositories\UserRepository;
use Illuminate\Support\Facades\Mail;
@@ -69,7 +70,7 @@ class CronController extends Controller
}
//send new remider
if ($user->confirmation_code_remider == 0) {
- Mail::to($user->email)->send(new MailVerifyAccount($user->confirmation_code, $user));
+ Mail::to($user->email)->locale($user->getLocale())->send(new MailVerifyAccount($user->confirmation_code, $user));
$user->confirmation_code_to = $next;
$user->confirmation_code_remider = 1;
$user->save();
@@ -106,7 +107,9 @@ class CronController extends Controller
die();*/
foreach ($users as $user){
$this->checkReminderPayments($user);
+ /* Abo Option deaktiviert
$this->userInitAboPayment($user);
+ */
}
return "TOSK";
}
@@ -151,11 +154,13 @@ class CronController extends Controller
//35 reminder_deaktiv, 36 reminder_deaktiv_sepa
if(!$user->isActiveAccount()){
- if($user->isAboOption()){
- $isSend = $this->checkIsReminderSend($user, 35);
+ /* Abo Option deaktiviert
+ if($user->isAboOption()){
+ $isSend = $this->checkIsReminderSend($user, 36);
return $isSend;
}
- $isSend = $this->checkIsReminderSend($user, 36);
+ */
+ $isSend = $this->checkIsReminderSend($user, 35);
return $isSend;
}
@@ -167,18 +172,24 @@ class CronController extends Controller
//33 reminder_sec
if($user->daysActiveAccount() <= config('mivita.remind_sec_days')){
- if(!$user->isAboOption()){
+ /* Abo Option deaktiviert
+ if(!$user->isAboOption()){
$isSend = $this->checkIsReminderSend($user, 33);
return $isSend;
}
+ */
+
+ $isSend = $this->checkIsReminderSend($user, 33);
+ return $isSend;
}
//31 reminder_first, 32 reminder_first_sepa
if($user->daysActiveAccount() > config('mivita.remind_sec_days')){
+ /* Abo Option deaktiviert
if($user->isAboOption()){
$isSend = $this->checkIsReminderSend($user, 32);
return $isSend;
- }
+ } */
$isSend = $this->checkIsReminderSend($user, 31);
return $isSend;
}
@@ -233,6 +244,7 @@ class CronController extends Controller
'button' => $button,
];
//dump($data);
+
$sender = User::find(1);
$customer_mail = UserMessage::create([
'user_id' => $user->id,
@@ -243,9 +255,9 @@ class CronController extends Controller
]);
try{
if($status >= 34){
- Mail::to($user->email)->bcc(config('app.default_mail'))->send(new MailCustomMessage($user, $data, $sender, false));
+ Mail::to($user->email)->locale($user->getLocale())->bcc(config('app.default_mail'))->send(new MailCustomMessage($user, $data, $sender, false));
}else{
- Mail::to($user->email)->send(new MailCustomMessage($user, $data, $sender, false));
+ Mail::to($user->email)->locale($user->getLocale())->send(new MailCustomMessage($user, $data, $sender, false));
}
}
catch(\Exception $e){
@@ -274,7 +286,11 @@ class CronController extends Controller
if($key !== 'G8ZvEbnP8fEPfnWX4L'){
abort(404);
}
- exec("/bin/bash ../cron_script.sh 2>&1", $out, $result);
+ if(Util::isTestSystem()){
+ exec("/bin/bash ../cron_script_local.sh 2>&1", $out, $result);
+ }else{
+ exec("/bin/bash ../cron_script_server.sh 2>&1", $out, $result);
+ }
echo "Returncode: " .$result ."
";
echo "Ausgabe des Scripts: " ."
";
echo "
"; print_r($out);
diff --git a/app/Http/Controllers/CustomerController.php b/app/Http/Controllers/CustomerController.php
index 71eced7d..bff2ead5 100755
--- a/app/Http/Controllers/CustomerController.php
+++ b/app/Http/Controllers/CustomerController.php
@@ -113,6 +113,8 @@ class CustomerController extends Controller
}
$shopping_user = ShoppingUser::findOrFail($id);
+
+ $data['language'] = isset($data['language']) ? $data['language'] : \App::getLocale();
$data['has_buyed'] = isset($data['has_buyed']) ? true : false;
$data['subscribed'] = isset($data['subscribed']) ? true : false;
//subscribed can only true when has_buyed ist active
@@ -154,7 +156,7 @@ class CustomerController extends Controller
}*/
return \DataTables::eloquent($query)
->addColumn('id', function (ShoppingUser $ShoppingUser) {
- return '';
+ return '';
})
->addColumn('billing_email', function (ShoppingUser $ShoppingUser) {
return $ShoppingUser->faker_mail ? "-" : $ShoppingUser->billing_email;
diff --git a/app/Http/Controllers/DataTableController.php b/app/Http/Controllers/DataTableController.php
index ed109b4f..f29f38d1 100644
--- a/app/Http/Controllers/DataTableController.php
+++ b/app/Http/Controllers/DataTableController.php
@@ -13,90 +13,4 @@ class DataTableController extends Controller
return view('datatable');
}
- public function getUsers()
- {
- $query = User::with('account')->select('users.*')->where('users.deleted_at', '=', null)->where('users.admin', "<", 4);
-
- return \DataTables::eloquent($query)
- ->addColumn('first_name', function (User $user) {
- return $user->account ? $user->account->first_name : '';
- })
- ->addColumn('last_name', function (User $user) {
- return $user->account ? $user->account->last_name : '';
- })
- ->addColumn('id', function (User $user) {
- return '';
- })
- ->addColumn('admin', function (User $user) {
- return ''.HTMLHelper::getRoleLabel($user->admin).'';
- })
- ->addColumn('confirmed', function (User $user) {
- $date = $user->getConfirmationDateFormat();
- $link = '';
- return $user->confirmed ? $link.' '.$date.'' : $link.'';
- })
- ->addColumn('active', function (User $user) {
- $date = $user->getActiveDateFormat();
- $link = '';
- return $user->active ? $link.' '.$date.'' : $link.'';
- })
- ->addColumn('account', function (User $user) {
- $date = $user->getPaymentAccountDateFormat();
- $link = '';
- if($user->payment_account){
- if($user->isActiveAccount()){
- return $link.' '.$date.'';
- }
- return $link.' '.$date.'';
- }
- return $link.'';
- })
- ->addColumn('shop', function (User $user) {
- $date = $user->getPaymentShopDateFormat();
- $link = '';
- if($user->payment_shop){
- if($user->isActiveShop()){
- return $link.' '.$date.'';
- }
- return $link.' '.$date.'';
- }
- return $link.'';
- })
- ->addColumn('since', function (User $user) {
- if($user->shop){
- if($user->shop->active){
- return $user->shop->getActiveDateFormatSmall();
- }
- return $user->shop->getActiveDateFormatSmall();
- }
- return "-";
- })
- ->addColumn('my_payment_methods', function (User $user) {
- $payment_methods = json_encode($user->payment_methods);
- $link = '';
- if(!$user->payment_methods){
- return $link.'';
- }
- return $link.' '.$user->getPaymentMethodsShort().'';
-
- })
- ->addColumn('action_login', function (User $user) {
- return '';
- })
- ->addColumn('action_delete', function (User $user) {
- return '';
- })
- ->addColumn('test_mode', function (User $user) {
- $link = '';
- return $user->test_mode ? $link.'' : $link.'';
-
- })
- ->orderColumn('id', 'id $1')
- ->orderColumn('confirmed', 'confirmed $1')
- ->orderColumn('active', 'active $1')
- ->orderColumn('shop', 'shop $1')
- ->orderColumn('admin', 'active $1')
- ->rawColumns(['id', 'admin', 'confirmed', 'active', 'account', 'shop', 'my_payment_methods', 'test_mode', 'action_login', 'action_delete'])
- ->make(true);
- }
}
diff --git a/app/Http/Controllers/FileController.php b/app/Http/Controllers/FileController.php
index ee92b1a8..b772f059 100644
--- a/app/Http/Controllers/FileController.php
+++ b/app/Http/Controllers/FileController.php
@@ -2,9 +2,11 @@
namespace App\Http\Controllers;
+use Auth;
use Storage;
use Response;
-use Auth;
+use App\Models\UserCredit;
+use App\Repositories\CreditRepository;
class FileController extends Controller
{
@@ -32,10 +34,19 @@ class FileController extends Controller
abort(404);
}
- public function show($id = null, $disk = null, $do='file')
+ private function isPermissionAuth(){
+ if(Auth::check()){
+ return true;
+ }
+ abort(404);
+ }
+
+ public function show($id = null, $from = null, $do='file')
{
+
$path = "";
$filename = "";
+ $disk = "public";
/*if($disk === 'user'){
$file = \App\Models\File::findOrFail($id);
@@ -45,25 +56,19 @@ class FileController extends Controller
return Response::file($path);
}
}*/
-
- if ($disk === 'invoice'){
+ if ($from === 'invoice'){
$shopping_order = \App\Models\ShoppingOrder::findOrFail($id);
if($shopping_order->user_invoice){
$this->isPermissionShoppingOrder($shopping_order);
$user_invoice = $shopping_order->user_invoice;
$filename = $user_invoice->filename;
$disk = $user_invoice->disk;
- $path = $user_invoice->getDownloadPath();
- if (!Storage::disk($disk)->exists($path)) {
- return Response::make('File no found.', 404);;
- }
- $file = Storage::disk($disk)->get($path);
- $mime = Storage::disk($disk)->mimeType($path);
+ $path = $user_invoice->getDownloadPath();
}
-
+
}
- if ($disk === 'delivery'){
+ if ($from === 'delivery'){
$shopping_order = \App\Models\ShoppingOrder::findOrFail($id);
if($shopping_order->user_invoice){
$this->isPermissionShoppingOrder($shopping_order);
@@ -71,28 +76,63 @@ class FileController extends Controller
$filename = $user_invoice->delivery_filename;
$disk = $user_invoice->disk;
$path = $user_invoice->getDownloadPathDelivery();
- if (!Storage::disk($disk)->exists($path)) {
- return Response::make('File no found.', 404);;
- }
- $file = Storage::disk($disk)->get($path);
- $mime = Storage::disk($disk)->mimeType($path);
}
-
}
- if ($disk === 'credit'){
+ if ($from === 'credit'){
$user_credit = \App\Models\UserCredit::findOrFail($id);
$this->isPermissionUserCredit($user_credit);
$filename = $user_credit->filename;
$disk = $user_credit->disk;
$path = $user_credit->getDownloadPath();
- if (!Storage::disk($disk)->exists($path)) {
- return Response::make('File no found.', 404);;
- }
- $file = Storage::disk($disk)->get($path);
- $mime = Storage::disk($disk)->mimeType($path);
}
+
+ if ($from === 'credit_detail'){
+ $user_credit = \App\Models\UserCredit::findOrFail($id);
+ $this->isPermissionUserCredit($user_credit);
+
+ return $this->create_credit_detail($user_credit, $do);
+
+ /*
+ $filename = $user_credit->filename;
+ $disk = $user_credit->disk;
+ $path = $user_credit->getDownloadPath();
+ */
+ }
+
+
+ if ($from === 'dc_file'){
+ $this->isPermissionAuth();
+ $dc_file = \App\Models\DcFile::findOrFail($id);
+ $filename = $dc_file->filename;
+ $disk = 'public';
+ $path = $dc_file->getFile();
+ }
+ if ($from === 'dc_thumb'){
+ $this->isPermissionAuth();
+ $dc_file = \App\Models\DcFile::findOrFail($id);
+ $filename = $dc_file->filename;
+ $disk = 'public';
+ $path = $dc_file->getThumb();
+ }
+
+ if ($from === 'dc_big'){
+ $this->isPermissionAuth();
+ $dc_file = \App\Models\DcFile::findOrFail($id);
+ $filename = $dc_file->filename;
+ $disk = 'public';
+ $path = $dc_file->getBig();
+ }
+
+
+
+ if(!Storage::disk($disk)->exists($path)){
+ // return Response::make('File no found.', 404);
+ }
+ $file = Storage::disk($disk)->get($path);
+ $mime = Storage::disk($disk)->mimeType($path);
+
if(isset($file)){
if($do === 'download'){
return Response::make($file, 200)
@@ -104,34 +144,35 @@ class FileController extends Controller
->header("Content-Type", $mime)
->header('Content-disposition','inline; filename="'.$filename.'"');
}
+
+ if($do === 'file'){
+ return Response::make($file, 200)
+ ->header("Content-Type", $mime)
+ ->header('Content-disposition', 'filename="'.$filename.'"');
+ }
+ if($do === 'image'){
+ return Response::make($file, 200)
+ ->header("Content-Type", $mime);
+ }
+ if($do === 'pdf'){
+ $path = storage_path().'/app/public/' . $path;
+
+ $headers = array(
+ 'Content-Type:'. $mime,
+ // 'Content-Length: ' . $file->size
+ // 'Content-Disposition: ' . $stream . '; filename=' . $file->original_name
+ );
+
+ return Response::download($path, $filename, $headers);
+ }
}
-
-
- /*if ($disk === 'credit'){
- $this->isPermission($UserCredit->auth_user_id);
-
- $filename = Credit::getFilename($UserCredit);
- $path = Credit::getDownloadPath($UserCredit);
-
- if (!Storage::disk('public')->exists($path)) {
- return Response::make('File no found.', 404);
- }
- $file = Storage::disk('public')->get($path);
- $mime = Storage::disk('public')->mimeType($path);
-
- if($do === 'download'){
- return Response::make($file, 200)
- ->header("Content-Type", $mime)
- ->header('Content-disposition', 'attachment; filename="'.$filename.'"');
- }
- if($do === 'stream'){
- return Response::make($file, 200)
- ->header("Content-Type", $mime)
- ->header('Content-disposition','filename="'.$filename.'"');
- }
-
- }*/
-
}
+ private function create_credit_detail(UserCredit $user_credit, $do){
+
+ $credit_repo = new CreditRepository($user_credit->user);
+ return $credit_repo->create_report($user_credit, $do);
+ //\Session()->flash('alert-success', "Gutschrift erstellt");
+
+ }
}
\ No newline at end of file
diff --git a/app/Http/Controllers/HomeController.php b/app/Http/Controllers/HomeController.php
index 84df5d26..fc6386ec 100755
--- a/app/Http/Controllers/HomeController.php
+++ b/app/Http/Controllers/HomeController.php
@@ -237,7 +237,7 @@ class HomeController extends Controller
}
}else{
- \Session()->flash('alert-error', "Es ist ein Fehler bei der Bestellung aufgetreten");
+ \Session()->flash('alert-error', __('msg.error_occurred_with_order'));
return redirect(route('/'));
}
diff --git a/app/Http/Controllers/LeadController.php b/app/Http/Controllers/LeadController.php
index dd78eec7..6a0a930a 100755
--- a/app/Http/Controllers/LeadController.php
+++ b/app/Http/Controllers/LeadController.php
@@ -8,6 +8,7 @@ use Validator;
use App\Services\SysLog;
use App\Models\UserAccount;
use App\Models\UserHistory;
+use App\Services\HTMLHelper;
use App\Services\UserService;
use App\Mail\MailAccountActive;
use App\Mail\MailCustomMessage;
@@ -33,13 +34,42 @@ class LeadController extends Controller
*/
public function index()
{
+
+
+ $filter_sponsor = User::join('user_accounts', 'account_id', '=', 'user_accounts.id')->select('users.id', 'users.email', 'user_accounts.first_name', 'user_accounts.last_name')->where('users.deleted_at', '=', null)->where('users.admin', "<", 4)->get();
+
+ $this->setFilterVars();
$data = [
- 'values' => User::where('admin', '=', 0)->where('confirmation_code_remider', '!=', 2)->get(),
+ 'filter_months' => HTMLHelper::getTransMonths(),
+ 'filter_years' => HTMLHelper::getYearRange(),
+ 'filter_sponsor' => $filter_sponsor,
];
+
return view('admin.lead.index', $data);
}
+ private function setFilterVars(){
+
+ /*if(!session('leads_filter_month')){
+ session(['leads_filter_month' => intval(date('m'))]);
+ }
+ if(!session('leads_filter_year')){
+ session(['leads_filter_year' => intval(date('Y'))]);
+ }*/
+
+ session(['leads_filter_sponsor_id' => Request::get('leads_filter_sponsor_id')]);
+
+ /* if(Request::get('leads_filter_month')){
+ session(['leads_filter_month' => Request::get('leads_filter_month')]);
+ }
+ if(Request::get('leads_filter_year')){
+ session(['leads_filter_year' => Request::get('leads_filter_year')]);
+ }*/
+ }
+
+
+
/**
* @param $id
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
@@ -122,6 +152,18 @@ class LeadController extends Controller
$data = Request::all();
$show = Request::get('show');
+ if(isset($data['action']) && $data['action'] == "reverse_charge_validate" && isset($data['user_id'])){
+ $user = User::findOrFail($data['user_id']);
+ return $this->userRepo->reverse_charge_validate($data, $user, route('admin_lead_edit', [$user->id]));
+ }
+
+ if(isset($data['action']) && $data['action'] == "reverse_charge_delete" && isset($data['user_id'])){
+ $user = User::findOrFail($data['user_id']);
+ return $this->userRepo->reverse_charge_delete($data, $user, route('admin_lead_edit', [$user->id]));
+ }
+
+
+ /*
if(isset($data['reverse_charge_validate']) && isset($data['user_id'])){
$user = User::findOrFail($data['user_id']);
$user->wizard = 1;
@@ -136,7 +178,7 @@ class LeadController extends Controller
$user->save();
$userRepo = new UserRepository($user);
return $userRepo->reverse_charge_delete($data, $user);
- }
+ }*/
if ($data['user_id'] === "new" || $data['user_id'] == 0) {
$rules = array(
@@ -234,7 +276,7 @@ class LeadController extends Controller
//10 == start wizard form create Lead
$user->wizard = 10;
$user->save();
- Mail::to($user->email)->send(new MailVerifyContact($confirmation_code, $user));
+ Mail::to($user->email)->locale($user->getLocale())->send(new MailVerifyContact($confirmation_code, $user));
\Session()->flash('alert-save', true);
return redirect(route('admin_leads'));
@@ -242,10 +284,6 @@ class LeadController extends Controller
\Session()->flash('alert-save', true);
return redirect(route('admin_lead_edit', [$user->id])."?show=".$show);
-
-
-
-
}
//user released when register is complete
public function released($action, $id){
@@ -260,7 +298,7 @@ class LeadController extends Controller
if(!$user->account->m_first_name){
$validator->errors()->add('m_first_name', __('Berater hat keinen Vornamen.'));
}
- if(!$user->account->m_first_name){
+ if(!$user->account->m_last_name){
$validator->errors()->add('m_last_name', __('Berater hat keinen Nachnamen.'));
}
if(!$user->account->m_account){
@@ -288,7 +326,7 @@ class LeadController extends Controller
$user->save();
//mail with code to user?
- Mail::to($user->email)->send(new MailAccountActive($user));
+ Mail::to($user->email)->locale($user->getLocale())->send(new MailAccountActive($user));
UserHistory::create(['user_id' => $user->id, 'action'=>'released_completed', 'status'=>0]);
\Session()->flash('alert-success', "Berater freigeschaltet!");
}
@@ -312,7 +350,7 @@ class LeadController extends Controller
'confirmation_code' => $confirmation_code,
];
try {
- Mail::to($user->email)->send(new MailCustomMessage($user, $data, \Auth::user(), true));
+ Mail::to($user->email)->locale($user->getLocale())->send(new MailCustomMessage($user, $data, \Auth::user(), true));
}
catch(\Exception $e){
dump($e->getMessage());
@@ -338,7 +376,7 @@ class LeadController extends Controller
$user->save();
try {
- Mail::to($user->email)->send(new MailVerifyAccount($confirmation_code, $user));
+ Mail::to($user->email)->locale($user->getLocale())->send(new MailVerifyAccount($confirmation_code, $user));
}
catch(\Exception $e){
dump($e->getMessage());
@@ -357,19 +395,36 @@ class LeadController extends Controller
if($relation === 'upload'){
$user = User::findOrFail($user_id);
$file = $user->files()->findOrFail($file_id);
+ if($file->identifier === 'business_license'){
+ $user->account->setNotice('business_license', '');
+ }
//remove file
\Storage::disk('user')->delete($file->dir.$file->filename);
$file->delete();
- \Session()->flash('alert-success', "Datei gelöscht");
+ \Session()->flash('alert-success', __('msg.file_deleted'));
}
return back();
}
+ private function initSearch()
+ {
+ $this->setFilterVars();
+
+ //$query = UserSalesVolume::with('user', 'user.account')->with('shopping_order')->select('user_sales_volumes.*')
+
+ $query = User::with('account')->select('users.*')->where('users.deleted_at', '=', null)->where('users.admin', "<", 5);
+ if(Request::get('leads_filter_sponsor_id')){
+ $query->where('users.m_sponsor', '=', Request::get('leads_filter_sponsor_id'));
+ }
+ return $query;
+ }
+
public function getLeads()
{
- $query = User::with('account')->select('users.*')->where('users.deleted_at', '=', null)->where('users.admin', "<", 4);
+ $query = $this->initSearch();
+
return \DataTables::eloquent($query)
->addColumn('first_name', function (User $user) {
@@ -379,10 +434,14 @@ class LeadController extends Controller
return $user->account ? $user->account->last_name : '';
})
->addColumn('user_level', function (User $user) {
- return $user->user_level ? $user->user_level->name : '';
+ return $user->user_level ? ''.$user->user_level->name.'' : '';
+ })
+ ->addColumn('user_sponsor', function (User $user) {
+ return $user->user_sponsor ?
+ ''.$user->user_sponsor->account->first_name." ".$user->user_sponsor->account->last_name.'' : "-";
})
->addColumn('id', function (User $user) {
- return '';
+ return '';
})
->addColumn('confirmed', function (User $user) {
return $user->confirmed ? '' : '';
@@ -393,6 +452,36 @@ class LeadController extends Controller
->addColumn('agreement', function (User $user) {
return $user->agreement ? ' ' : '';
})
+
+ ->addColumn('useractive', function (User $user) {
+ $date = $user->getActiveDateFormat();
+ $link = '';
+ return $user->active ? $link.' '.$date.'' : $link.'';
+ })
+ ->addColumn('payaccount', function (User $user) {
+ $date = $user->getPaymentAccountDateFormat();
+ $link = '';
+ if($user->payment_account){
+ if($user->isActiveAccount()){
+ return $link.' '.$date.'';
+ }
+ return $link.' '.$date.'';
+ }
+ return $link.'';
+ })
+ ->addColumn('payshop', function (User $user) {
+ $date = $user->getPaymentShopDateFormat();
+ $link = '';
+ if($user->payment_shop){
+ if($user->isActiveShop()){
+ return $link.' '.$date.'';
+ }
+ return $link.' '.$date.'';
+ }
+ return $link.'';
+ })
+
+
->addColumn('payment_account', function (User $user) {
return $user->payment_account ? ' ' : '';
})
@@ -402,11 +491,12 @@ class LeadController extends Controller
->addColumn('payment_shop', function (User $user) {
return $user->payment_shop ? ' ' : '';
})
+
->addColumn('payment_shop_date', function (User $user) {
return $user->payment_shop ? $user->getPaymentShopDateFormat(false) : "-";
})
->addColumn('shop_domain', function (User $user) {
- return $user->shop ? ' '.$user->shop->getSubdomain(false).'' : '';
+ return $user->shop ? ' '.$user->shop->getSubdomain(false).'' : '';
})
->addColumn('turnover', function (User $user) {
@@ -421,7 +511,7 @@ class LeadController extends Controller
->orderColumn('agreement', 'agreement $1')
->orderColumn('payment_account', 'payment_account $1')
->orderColumn('payment_shop', 'payment_shop $1')
- ->rawColumns(['id', 'confirmed', 'active', 'agreement', 'payment_account', 'payment_shop', 'shop_domain'])
+ ->rawColumns(['id', 'user_level', 'user_sponsor', 'confirmed', 'useractive', 'payaccount', 'payshop', 'agreement', 'active', 'payment_account', 'payment_shop', 'shop_domain'])
->make(true);
}
}
\ No newline at end of file
diff --git a/app/Http/Controllers/ModalController.php b/app/Http/Controllers/ModalController.php
index fbcd2b7e..52ac2441 100644
--- a/app/Http/Controllers/ModalController.php
+++ b/app/Http/Controllers/ModalController.php
@@ -92,7 +92,6 @@ class ModalController extends Controller
if($data['action'] === 'user-order-my-delivery-add'){
$user = \Auth::user();
-
/* $product = Product::find($data['id']); //current user form order
$ret = view("admin.modal.show_product", compact('product', 'data'))->render(); */
}
@@ -108,6 +107,11 @@ class ModalController extends Controller
$route = route('admin_level_store', [$value->id]);
$ret = view("admin.modal.user_level_edit", compact('value', 'data', 'route'))->render();
}
+ if($data['action'] === 'user-level-add'){
+ $value = new UserLevel();
+ $route = route('admin_level_store', ['new']);
+ $ret = view("admin.modal.user_level_edit", compact('value', 'data', 'route'))->render();
+ }
if($data['action'] === 'business-user-detail'){
$user = User::findOrFail($data['id']);
if($data['init_from'] === 'admin'){
@@ -121,6 +125,16 @@ class ModalController extends Controller
$route = "";
$ret = view("admin.modal.business_user_detail", compact('TreeCalcBot', 'user', 'data'))->render();
}
+
+ if($data['action'] === 'business-user-show'){
+ $user = User::find($data['id']);
+ if($user && $user->account){
+ $route = "";
+ $ret = view("admin.modal.business_user_show", compact('user', 'data'))->render();
+ }
+ $ret = view("admin.modal.business_user_notfound", compact('data'))->render();
+
+ }
if($data['action'] === 'edit_user_sales_volume'){
$userSalesVolume = UserSalesVolume::findOrFail($data['id']);
$route = route('admin_business_points_store', );
diff --git a/app/Http/Controllers/Pay/PayoneController.php b/app/Http/Controllers/Pay/PayoneController.php
index d88ebe83..97459246 100644
--- a/app/Http/Controllers/Pay/PayoneController.php
+++ b/app/Http/Controllers/Pay/PayoneController.php
@@ -27,10 +27,9 @@ namespace App\Http\Controllers\Pay;
use App\Http\Controllers\Controller;
use App\Models\PaymentTransaction;
use App\Models\ShoppingPayment;
+use App\Services\MyLog;
use App\Services\Payone;
-use Illuminate\Http\Request;
use Util;
-use Yard;
class PayoneController extends Controller
@@ -45,6 +44,7 @@ class PayoneController extends Controller
private $default = [];
private $personalData = [];
+ private $aboInitPayment = [];
private $method = [];
private $prepayment = [];
@@ -54,6 +54,8 @@ class PayoneController extends Controller
private $deliveryData = [];
+
+
// private $payment_method;
private $urls = [];
@@ -95,8 +97,14 @@ class PayoneController extends Controller
"amount" => $amount, // amount in smallest currency unit, i.e. cents
"currency" => $currency,
"param" => $this->shopping_order->id,
-
];
+ //init Abo
+ if($this->shopping_order->is_abo){
+ $this->aboInitPayment = [
+ 'recurrence'=>'recurring',
+ 'customer_is_present'=>'yes'
+ ];
+ }
$this->shopping_payment = ShoppingPayment::create([
'shopping_order_id' => $this->shopping_order->id,
@@ -106,6 +114,8 @@ class PayoneController extends Controller
'reference' => $this->reference,
'amount' => $amount,
'currency' => $currency,
+ 'is_abo' => $this->shopping_order->is_abo,
+ 'abo_interval' => $this->shopping_order->abo_interval,
'mode' => $this->shopping_order->mode,
]);
@@ -222,7 +232,7 @@ class PayoneController extends Controller
"wallettype" => "",
'onlinebanktransfertype' => "",
"request" => "authorization",
- "pseudocardpan" => $ret['cc']['pseudocardpan']
+ "pseudocardpan" => $ret['cc']['pseudocardpan'],
//"xid" => "3-D Secure transaction ID"
];
}
@@ -230,14 +240,14 @@ class PayoneController extends Controller
}
public function onlyPaymentResponse(){
- $request = array_merge($this->default, $this->personalData, $this->deliveryData, $this->method, $this->prepayment, $this->urls);
+ $request = array_merge($this->default, $this->personalData, $this->deliveryData, $this->method, $this->aboInitPayment, $this->prepayment, $this->urls);
$response = Payone::sendRequest($request);
return $response;
}
public function ResponseData(){
- $request = array_merge($this->default, $this->personalData, $this->deliveryData, $this->method, $this->prepayment, $this->urls);
+ $request = array_merge($this->default, $this->personalData, $this->deliveryData, $this->method, $this->aboInitPayment, $this->prepayment, $this->urls);
//RECHNUNG MIV
if($this->shopping_payment->clearingtype === 'fnc' && $this->shopping_payment->onlinebanktransfertype === 'MIV'){
@@ -336,14 +346,25 @@ class PayoneController extends Controller
if($response['status'] === 'PENDING'){
- var_dump($response);
+ MyLog::writeLog(
+ 'payone',
+ 'error',
+ 'Error:1000 Status PENDING App\Http\Controllers\Pay\PayoneController::ResponseData response status PENDING',
+ $response
+ );
die();
//txid
//Payment process ID (PAYONE)
//userid
//Debtor ID (PAYONE)
}
- die("error");
+ MyLog::writeLog(
+ 'payone',
+ 'error',
+ 'Error:1001 Der Zahlungsanbieter ist nicht erreichbar, die Zahlung konnte nicht durchgeführt werden. App\Http\Controllers\Pay\PayoneController::ResponseData error no response status',
+ $response
+ );
+ abort(403, 'Der Zahlungsanbieter ist nicht erreichbar, die Zahlung konnte nicht durchgeführt werden. Bitte versuchen Sie es später erneut. Fehlercode: 1001');
}
@@ -365,7 +386,6 @@ class PayoneController extends Controller
return Payone::sendRequest($request);
}
-
public function checkBankAccount($data, $amount, $currency, $shopping_user)
{
$this->shopping_user = $shopping_user;
diff --git a/app/Http/Controllers/PaymentCreditController.php b/app/Http/Controllers/PaymentCreditController.php
index fbe933dd..41b88f3f 100644
--- a/app/Http/Controllers/PaymentCreditController.php
+++ b/app/Http/Controllers/PaymentCreditController.php
@@ -18,6 +18,7 @@ use App\Models\ShoppingOrderMargin;
use App\Repositories\CreditRepository;
use App\Models\Models\UserCreditMargin as ModelsUserCreditMargin;
+use App\Models\UserAccount;
use stdClass;
class PaymentCreditController extends Controller
@@ -32,7 +33,7 @@ class PaymentCreditController extends Controller
{
$this->setFilterVars();
$data = [
- 'filter_months' => HTMLHelper::$months,
+ 'filter_months' => HTMLHelper::getTransMonths(),
'filter_years' => HTMLHelper::getYearRange(2022),
'user_credit_items' => $this->makeUserCreditItems(),
];
@@ -114,15 +115,30 @@ class PaymentCreditController extends Controller
$ret[$userCreditItem->user_id]['sum'] += $userCreditItem->credit;
$ret[$userCreditItem->user_id]['entries'][$userCreditItem->id] = $userCreditItem;
}else{
- $ret[$userCreditItem->user_id] = [
- 'user_id' => $userCreditItem->user_id,
- 'm_account' => $userCreditItem->user->account->m_account,
- 'first_name' => $userCreditItem->user->account->first_name,
- 'last_name' => $userCreditItem->user->account->last_name,
- 'email' => $userCreditItem->user->email,
- 'sum' => $userCreditItem->credit,
- 'entries' => [$userCreditItem->id => $userCreditItem],
- ];
+ if(!isset($userCreditItem->user)){
+ /* gelöschte User nicht anzeigen
+ $user = User::withTrashed()->with(['account' => fn($q) => $q->withTrashed()])->where('id', $userCreditItem->user_id)->first();
+ $ret[$userCreditItem->user_id] = [
+ 'user_id' => $userCreditItem->user_id,
+ 'm_account' => $user ? $user->account->m_account : "gelöscht",
+ 'first_name' => $user ? $user->account->first_name : "gelöscht",
+ 'last_name' => $user ? $user->account->last_name : "gelöscht",
+ 'email' => $user ? $user->email : "gelöscht",
+ 'sum' => $userCreditItem->credit,
+ 'entries' => [$userCreditItem->id => $userCreditItem],
+ ];
+ */
+ }else{
+ $ret[$userCreditItem->user_id] = [
+ 'user_id' => $userCreditItem->user_id,
+ 'm_account' => $userCreditItem->user->account->m_account,
+ 'first_name' => $userCreditItem->user->account->first_name,
+ 'last_name' => $userCreditItem->user->account->last_name,
+ 'email' => $userCreditItem->user->email,
+ 'sum' => $userCreditItem->credit,
+ 'entries' => [$userCreditItem->id => $userCreditItem],
+ ];
+ }
}
}
return $ret;
@@ -147,19 +163,16 @@ class PaymentCreditController extends Controller
$this->setFilterVars();
-
$date_start = Carbon::parse('01.'.Request::get('credit_filter_month').'.'.Request::get('credit_filter_year'))->format('Y-m-d');
$date_end = Carbon::parse('01.'.Request::get('credit_filter_month').'.'.Request::get('credit_filter_year'))->endOfMonth()->format('Y-m-d');
$query = UserCredit::with('user', 'user.account')->select('user_credits.*')
->whereBetween('date', [$date_start, $date_end]);
-
+
if(Request::get('credit_filter_name')){
$query->whereHas('user.account', function ($query) {
- return $query->where('first_name', 'LIKE', '%'.Request::get('credit_filter_name').'%')->orWhere('last_name', 'LIKE', '%'.Request::get('credit_filter_name').'%');
- })->get();
- $query->whereHas('user', function ($query) {
- return $query->where('email', 'LIKE', '%'.Request::get('credit_filter_name').'%');
- })->get();
+ return $query->where('first_name', 'LIKE', '%'.Request::get('credit_filter_name').'%')
+ ->orWhere('last_name', 'LIKE', '%'.Request::get('credit_filter_name').'%');
+ });
}
return $query;
}
@@ -169,11 +182,26 @@ class PaymentCreditController extends Controller
$query = $this->initSearch();
return \DataTables::eloquent($query)
+
+ ->addColumn('user.account.first_name', function (UserCredit $UserCredit) {
+ return isset($UserCredit->user->account) ? $UserCredit->user->account->first_name : "gelöscht";
+ })
+ ->addColumn('user.account.last_name', function (UserCredit $UserCredit) {
+ return isset($UserCredit->user->account) ? $UserCredit->user->account->last_name : "gelöscht";
+ })
+ ->addColumn('user.email', function (UserCredit $UserCredit) {
+ return isset($UserCredit->user) ? $UserCredit->user->email : "gelöscht";
+ })
->addColumn('view', function (UserCredit $UserCredit) {
$ret = "";
if($UserCredit->isCredit()){
$ret .= ' ';
- $ret .= '';
+ $ret .= '
';
+
+ $ret .= ' ';
+ $ret .= ' ';
+
+
}else{
$ret = "-";
}
@@ -187,7 +215,7 @@ class PaymentCreditController extends Controller
$ret = "";
if($UserCredit->user_credit_items){
foreach($UserCredit->user_credit_items as $user_credit_item){
- $ret .= nl2br($user_credit_item->message)." / ".$user_credit_item->created_at->format('d.m.Y')."
";
+ $ret .= nl2br($user_credit_item->getTransMessage())." / ".$user_credit_item->created_at->format('d.m.Y')."
";
}
}
@@ -199,7 +227,27 @@ class PaymentCreditController extends Controller
'.$UserCredit->getStatusType().'
';
})
-
+ ->filterColumn('user.account.first_name', function($query, $keyword) {
+ if($keyword != ""){
+ $query->whereHas('user.account', function ($query) use ($keyword) {
+ return $query->where('first_name', 'LIKE', '%'.$keyword.'%');
+ });
+ }
+ })
+ ->filterColumn('user.account.last_name', function($query, $keyword) {
+ if($keyword != ""){
+ $query->whereHas('user.account', function ($query) use ($keyword) {
+ return $query->where('last_name', 'LIKE', '%'.$keyword.'%');
+ });
+ }
+ })
+ ->filterColumn('user.email', function($query, $keyword) {
+ if($keyword != ""){
+ $query->whereHas('user', function ($query) use ($keyword) {
+ return $query->where('email', 'LIKE', '%'.$keyword.'%');
+ });
+ }
+ })
->orderColumn('id', 'id $1')
->orderColumn('status', 'status $1')
->orderColumn('total', 'total $1')
diff --git a/app/Http/Controllers/PaymentInvoiceController.php b/app/Http/Controllers/PaymentInvoiceController.php
index fe5d90e0..3285a1f6 100644
--- a/app/Http/Controllers/PaymentInvoiceController.php
+++ b/app/Http/Controllers/PaymentInvoiceController.php
@@ -22,7 +22,7 @@ class PaymentInvoiceController extends Controller
$this->setFilterVars();
$data = [
- 'filter_months' => HTMLHelper::$months,
+ 'filter_months' => HTMLHelper::getTransMonths(),
'filter_years' => HTMLHelper::getYearRange(),
];
return view('admin.payment.invoice', $data);
@@ -81,15 +81,6 @@ class PaymentInvoiceController extends Controller
->addColumn('created_at', function (UserInvoice $UserInvoice) {
return $UserInvoice->created_at->format("d.m.Y");
})
- /*
- ->addColumn('shipping_order', function (UserInvoice $UserInvoice) {
- $ret = "";
- foreach($UserInvoice->shopping_order_items as $shopping_order_item){
- $ret .= $shopping_order_item->product->name."
";
- }
- return $ret;
- })
- */
->addColumn('txaction', function (UserInvoice $UserInvoice) {
if($UserInvoice->shopping_order){
return Payment::getShoppingOrderBadge($UserInvoice->shopping_order);
@@ -113,6 +104,9 @@ class PaymentInvoiceController extends Controller
->orderColumn('txaction', 'txaction $1')
->orderColumn('shipped', 'shipped $1')
->orderColumn('total_shipping', 'total_shipping $1')
+ ->orderColumn('created_at', 'created_at $1')
+ ->orderColumn('status', 'status $1')
+
->rawColumns(['id', 'shipping_order', 'txaction', 'total_shipping', 'status', 'txaction', 'invoice'])
->make(true);
}
diff --git a/app/Http/Controllers/PaymentMethodController.php b/app/Http/Controllers/PaymentMethodController.php
index fd965e72..fbea8b4a 100755
--- a/app/Http/Controllers/PaymentMethodController.php
+++ b/app/Http/Controllers/PaymentMethodController.php
@@ -36,6 +36,7 @@ class PaymentMethodController extends Controller
'short' => $data['short'],
'pos' => $data['pos'],
'show_on' => isset($data['show_on']) ? $data['show_on'] : null,
+ 'is_abo' => isset($data['is_abo']) ? $data['is_abo'] : null,
'default' => isset($data['default']) ? true : false,
'active' => isset($data['active']) ? true : false,
]);
@@ -44,6 +45,7 @@ class PaymentMethodController extends Controller
$model->name = $data['name'];
$model->short = $data['short'];
$model->pos = $data['pos'];
+ $model->is_abo = isset($data['is_abo']) ? true : false;
$model->show_on = isset($data['show_on']) ? $data['show_on'] : null;
$model->default = isset($data['default']) ? true : false;
$model->active = isset($data['active']) ? true : false;
diff --git a/app/Http/Controllers/PaymentPointsController.php b/app/Http/Controllers/PaymentPointsController.php
index c5fd60b5..263dea79 100644
--- a/app/Http/Controllers/PaymentPointsController.php
+++ b/app/Http/Controllers/PaymentPointsController.php
@@ -26,7 +26,7 @@ class PaymentPointsController extends Controller
dd("function?");
$this->setFilterVars();
$data = [
- 'filter_months' => HTMLHelper::$months,
+ 'filter_months' => HTMLHelper::getTransMonths(),
'filter_years' => HTMLHelper::getYearRange(),
];
return view('admin.payment.invoice', $data);
@@ -90,15 +90,6 @@ class PaymentPointsController extends Controller
->addColumn('created_at', function (UserInvoice $UserInvoice) {
return $UserInvoice->created_at->format("d.m.Y");
})
- /*
- ->addColumn('shipping_order', function (UserInvoice $UserInvoice) {
- $ret = "";
- foreach($UserInvoice->shopping_order_items as $shopping_order_item){
- $ret .= $shopping_order_item->product->name."
";
- }
- return $ret;
- })
- */
->addColumn('txaction', function (UserInvoice $UserInvoice) {
if($UserInvoice->shopping_order){
return Payment::getShoppingOrderBadge($UserInvoice->shopping_order);
diff --git a/app/Http/Controllers/PaymentTaxAdvisorController.php b/app/Http/Controllers/PaymentTaxAdvisorController.php
new file mode 100644
index 00000000..9afcada9
--- /dev/null
+++ b/app/Http/Controllers/PaymentTaxAdvisorController.php
@@ -0,0 +1,246 @@
+ 8120, //für Kunden aus der Schweiz
+ 11 => 8125, //Steuerfreie EU-Lieferungen
+ 2 => 8300, //Erlöse mit 7 % meistens für Käufe mit Aloe Vera
+ 3 => 8400, //Regulär mit 19 %
+ ];
+
+
+ private $accountKey = [
+ 'A'=>'10000',
+ 'B'=>'10100',
+ 'C'=>'10200',
+ 'D'=>'10300',
+ 'E'=>'10400',
+ 'F'=>'10500',
+ 'G'=>'10600',
+ 'H'=>'10700',
+ 'I'=>'10800',
+ 'J'=>'10900',
+ 'K'=>'11000',
+ 'L'=>'11100',
+ 'M'=>'11200',
+ 'N'=>'11300',
+ 'O'=>'11400',
+ 'P'=>'11500',
+ 'Q'=>'11600',
+ 'R'=>'11700',
+ 'S'=>'11800',
+ 'SCH'=>'11900',
+ 'T'=>'12000',
+ 'U'=>'12100',
+ 'V'=>'12200',
+ 'W'=>'12300',
+ 'X'=>'12400',
+ 'Y'=>'12500',
+ 'Z'=>'12600'
+ ];
+
+ public function __construct()
+ {
+ $this->middleware('admin');
+ }
+
+ public function index()
+ {
+
+ $this->setFilterVars();
+ $data = [
+ 'filter_months' => HTMLHelper::getTransMonths(),
+ 'filter_years' => HTMLHelper::getYearRange(2023),
+ ];
+ return view('admin.payment.taxadvisor', $data);
+ }
+
+
+ public function createZip($filesToZip)
+ {
+ $zip = new ZipArchive;
+ $zipFileName = 'mysample.zip';
+ $path = storage_path().'/app/public/zip/';
+ if ($zip->open($path.$zipFileName, ZipArchive::CREATE) === TRUE) {
+ foreach ($filesToZip as $file) {
+ $zip->addFile($file, basename($file));
+ }
+
+ $zip->close();
+ return response()->download($path.$zipFileName)->deleteFileAfterSend(true);
+ } else {
+ return "Failed to create the zip file.";
+ }
+ }
+
+
+ public function download(){
+
+
+ $query = $this->initSearch();
+
+ $files = [];
+
+ $user_invoices = $query->get();
+ foreach ($user_invoices as $user_invoice) {
+ $filename = $user_invoice->filename;
+ $disk = $user_invoice->disk;
+ $path = $user_invoice->getDownloadPath();
+ if (Storage::disk($disk)->exists($path)) {
+ $file = Storage::disk($disk)->get($path);
+ $pdf_path = storage_path().'/app/public/'.$path;
+ $files[] = $pdf_path;
+ }
+ }
+
+ return $this->createZip($files);
+
+ dd("asd");
+
+
+
+ if(Request::get('action') === "export"){
+ $objects = $this->initSearch(false);
+ $columns = [];
+ $filename = "mivita-absatzmengen-".session('payment_taxadvisor_filter_month').'_'.session('payment_taxadvisor_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('payment_taxadvisor_filter_month')){
+ session(['payment_taxadvisor_filter_month' => intval(date('m'))]);
+ }
+ if(!session('payment_taxadvisor_filter_year')){
+ session(['payment_taxadvisor_filter_year' => intval(date('Y'))]);
+ }
+
+ if(Request::get('payment_taxadvisor_filter_month')){
+ session(['payment_taxadvisor_filter_month' => Request::get('payment_taxadvisor_filter_month')]);
+ }
+ if(Request::get('payment_taxadvisor_filter_year')){
+ session(['payment_taxadvisor_filter_year' => Request::get('payment_taxadvisor_filter_year')]);
+ }
+ }
+
+
+ private function initSearch()
+ {
+ $this->setFilterVars();
+
+ $query = UserInvoice::with('shopping_order')->with('shopping_order.shopping_user')->select('user_invoices.*')
+ ->where('user_invoices.month', '=', Request::get('payment_taxadvisor_filter_month'))
+ ->where('user_invoices.year', '=', Request::get('payment_taxadvisor_filter_year'));
+
+
+ return $query;
+ }
+
+
+ public function datatable(){
+
+ $query = $this->initSearch();
+
+
+ return \DataTables::eloquent($query)
+ ->addColumn('id', function (UserInvoice $UserInvoice) {
+ return $UserInvoice->id;
+
+ })
+
+ ->addColumn('turnover', function (UserInvoice $UserInvoice) {
+ return ''.$UserInvoice->shopping_order->getFormattedTotalShipping()." €";
+ })
+ ->addColumn('debit_credit_indicator', function (UserInvoice $UserInvoice) {
+ return "H";
+ })
+ ->addColumn('account', function (UserInvoice $UserInvoice) {
+ if($UserInvoice->shopping_order && $UserInvoice->shopping_order->shopping_user){
+ $key = strtoupper(substr($UserInvoice->shopping_order->shopping_user->billing_lastname, 0, 1));
+ if($key === "S"){
+ if(strtoupper(substr($UserInvoice->shopping_order->shopping_user->billing_lastname, 0, 3)) === "SCH"){
+ return $this->accountKey['SCH'];
+ }
+ }
+ return isset($this->accountKey[$key]) ? $this->accountKey[$key] : $key;
+ }
+ return "-";
+ })
+ ->addColumn('contra_account', function (UserInvoice $UserInvoice) {
+ return "-";
+ })
+ ->addColumn('bu_key', function (UserInvoice $UserInvoice) {
+ if($UserInvoice->shopping_order){
+ return $UserInvoice->shopping_order->country_id;
+ }
+ })
+ ->addColumn('voucher_date', function (UserInvoice $UserInvoice) {
+ // 101 -> für 01 Januar
+ return $UserInvoice->month."01";
+ })
+ ->addColumn('document_field_1', function (UserInvoice $UserInvoice) {
+ //Rechnungsnummer
+ return $UserInvoice->full_number;
+ })
+ ->addColumn('posting_text', function (UserInvoice $UserInvoice) {
+ //Buchungstext – hier wäre es toll wenn der Name des Kunden steht.
+ if($UserInvoice->shopping_order && $UserInvoice->shopping_order->shopping_user){
+ return $UserInvoice->shopping_order->shopping_user->billing_firstname." ".$UserInvoice->shopping_order->shopping_user->billing_lastname;
+ }
+ return "-";
+ })
+ ->addColumn('invoice', function (UserInvoice $UserInvoice) {
+ $ret = "";
+ $ret .= ' ';
+ $ret .= '';
+ return $ret;
+ })
+ ->orderColumn('id', 'id $1')
+ ->orderColumn('invoice_number', 'invoice_number $1')
+ ->orderColumn('turnover', 'turnover $1')
+ ->orderColumn('shipped', 'shipped $1')
+ ->orderColumn('total_shipping', 'total_shipping $1')
+ ->rawColumns(['id', 'shipping_order', 'turnover', 'total_shipping', 'status', 'txaction', 'invoice'])
+ ->make(true);
+
+
+
+ }
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/Http/Controllers/ProductController.php b/app/Http/Controllers/ProductController.php
index 0e7ab156..0b25ef06 100755
--- a/app/Http/Controllers/ProductController.php
+++ b/app/Http/Controllers/ProductController.php
@@ -182,10 +182,10 @@ class ProductController extends Controller
]);
- \Session()->flash('alert-success', "Datei hochgeladen");
+ \Session()->flash('alert-success', __('msg.file_uploaded'));
return redirect(route('admin_product_edit', [$product->id]));
}
- \Session()->flash('alert-danger', "Datei leer");
+ \Session()->flash('alert-danger', __('msg.file_empty'));
return redirect(route('admin_product_edit', [$product->id]));
}
@@ -206,11 +206,11 @@ class ProductController extends Controller
$product_image->delete();
- \Session()->flash('alert-success', "Datei gelöscht");
+ \Session()->flash('alert-success', __('msg.file_deleted'));
return redirect(route('admin_product_edit', [$product->id]));
}
- \Session()->flash('alert-danger', "Datei nicht gefunden");
+ \Session()->flash('alert-danger', __('msg.file_not_found'));
return redirect(route('admin_product_edit', [$product->id]));
}
diff --git a/app/Http/Controllers/SalesController.php b/app/Http/Controllers/SalesController.php
index 382ed4ed..d72f045b 100755
--- a/app/Http/Controllers/SalesController.php
+++ b/app/Http/Controllers/SalesController.php
@@ -89,7 +89,7 @@ class SalesController extends Controller
data-back=""
data-modal="modal-xl"
data-init_from="user"
- data-route="'.route('modal_load').'">';
+ data-route="'.route('modal_load').'">';
}
return ''.$ShoppingOrder->getShippedType().'';
})
@@ -145,6 +145,9 @@ class SalesController extends Controller
public function customersDetail($id)
{
$ShoppingOrder = ShoppingOrder::find($id);
+ if(!$ShoppingOrder){
+ abort(404);
+ }
if( $ShoppingOrder->payment_for !== 6 && $ShoppingOrder->payment_for !== 7){
return redirect(route('admin_sales_users_detail', [$ShoppingOrder->id]));
abort(403, 'Beraterbestellung');
diff --git a/app/Http/Controllers/SitesController.php b/app/Http/Controllers/SitesController.php
index 0270d388..014bd87f 100755
--- a/app/Http/Controllers/SitesController.php
+++ b/app/Http/Controllers/SitesController.php
@@ -97,15 +97,15 @@ class SitesController extends Controller
$model->iq_image_id = $iq_image->id;
$model->save();
- \Session()->flash('alert-success', "Datei hochgeladen");
+ \Session()->flash('alert-success', __('msg.file_uploaded'));
return redirect(route('admin_sites', [$model->slug]));
}
- \Session()->flash('alert-danger', "Datei leer");
+ \Session()->flash('alert-danger', __('msg.file_empty'));
return redirect(route('admin_sites', [$model->slug]));
}
catch (Exception $e) {
- \Session()->flash('alert-danger', "Fehler".$e);
+ \Session()->flash('alert-danger', "Error: ".$e);
return redirect(route('admin_sites', [$model->slug]));
}
}
@@ -124,11 +124,11 @@ class SitesController extends Controller
$iq_image->delete();
- \Session()->flash('alert-success', "Datei gelöscht");
+ \Session()->flash('alert-success', __('msg.file_deleted'));
return redirect(route('admin_sites', [$model->slug]));
}
- \Session()->flash('alert-danger', "Datei nicht gefunden");
+ \Session()->flash('alert-danger', __('msg.file_not_found'));
return redirect(route('admin_sites', [$model->slug]));
}
diff --git a/app/Http/Controllers/SyS/SysController.php b/app/Http/Controllers/SyS/SysController.php
index d99745d9..3a549bd9 100644
--- a/app/Http/Controllers/SyS/SysController.php
+++ b/app/Http/Controllers/SyS/SysController.php
@@ -14,7 +14,12 @@ use App\Http\Controllers\Controller;
use App\Services\SyS\ShoppingOrders;
use App\Services\SyS\BuyingsProducts;
use App\Services\SyS\BusinessStructur;
+use App\Services\SyS\ImportDbipCountry;
use App\Services\SyS\ChangeUserBusinesses;
+use App\Services\SyS\UserCreditItemsAddFrom;
+use App\Services\SyS\RepairSalesVolumeInvoice;
+use App\Services\SyS\CleanHTMLProductDescription;
+use App\Services\SyS\UserCreditItemsChangeMessage;
class SysController extends Controller
{
@@ -35,7 +40,9 @@ class SysController extends Controller
{
switch ($serve) {
-
+ case 'user_credit_items_add_from':
+ return UserCreditItemsAddFrom::show();
+ break;
case 'buyings_products':
return BuyingsProducts::show();
break;
@@ -66,6 +73,22 @@ class SysController extends Controller
case 'change_user_businesses':
return ChangeUserBusinesses::show();
break;
+ case 'repair_sales_volume_invoice':
+ return RepairSalesVolumeInvoice::show();
+ break;
+ case 'user_credit_items_change_message':
+ return UserCreditItemsChangeMessage::show();
+ break;
+ case 'clean_html_product_description':
+ return CleanHTMLProductDescription::show();
+ break;
+ case 'import_dbip_country_lite':
+ return ImportDbipCountry::show();
+ break;
+
+
+
+
}
abort(403, 'not found tool');
@@ -74,6 +97,9 @@ class SysController extends Controller
public function store($serve)
{
switch ($serve) {
+ case 'user_credit_items_add_from':
+ return UserCreditItemsAddFrom::show();
+ break;
case 'buyings_products':
return BuyingsProducts::store();
break;
@@ -104,6 +130,18 @@ class SysController extends Controller
case 'change_user_businesses':
return ChangeUserBusinesses::store();
break;
+ case 'repair_sales_volume_invoice':
+ return RepairSalesVolumeInvoice::store();
+ break;
+ case 'user_credit_items_change_message':
+ return UserCreditItemsChangeMessage::store();
+ break;
+ case 'clean_html_product_description':
+ return CleanHTMLProductDescription::store();
+ break;
+ case 'import_dbip_country_lite':
+ return ImportDbipCountry::store();
+ break;
}
abort(403, 'not found tool');
}
diff --git a/app/Http/Controllers/ProductsSalesController.php b/app/Http/Controllers/TaxAdvisorController.php
similarity index 72%
rename from app/Http/Controllers/ProductsSalesController.php
rename to app/Http/Controllers/TaxAdvisorController.php
index a966a08b..7f607922 100644
--- a/app/Http/Controllers/ProductsSalesController.php
+++ b/app/Http/Controllers/TaxAdvisorController.php
@@ -15,7 +15,7 @@ use Maatwebsite\Excel\Facades\Excel;
use App\Services\BusinessPlan\ExportBot;
use Illuminate\Database\Eloquent\Collection;
-class ProductsSalesController extends Controller
+class TaxAdvisorController extends Controller
{
public function __construct()
@@ -28,10 +28,10 @@ class ProductsSalesController extends Controller
$this->setFilterVars();
$data = [
- 'filter_months' => HTMLHelper::$months,
- 'filter_years' => HTMLHelper::getYearRange(2022),
+ 'filter_months' => HTMLHelper::getTransMonths(),
+ 'filter_years' => HTMLHelper::getYearRange(2023),
];
- return view('admin.product.salesvolume', $data);
+ return view('admin.payment.taxadvisor', $data);
}
public function download(){
@@ -39,7 +39,7 @@ class ProductsSalesController extends Controller
if(Request::get('action') === "export"){
$objects = $this->initSearch(false);
$columns = [];
- $filename = "mivita-absatzmengen-".session('product_sales_vol_filter_month').'_'.session('product_sales_vol_filter_year')."-export";
+ $filename = "mivita-absatzmengen-".session('payment_taxadvisor_filter_month').'_'.session('payment_taxadvisor_filter_year')."-export";
$headers = array(
'#',
'Produkt',
@@ -64,18 +64,18 @@ class ProductsSalesController extends Controller
private function setFilterVars(){
- if(!session('product_sales_vol_filter_month')){
- session(['product_sales_vol_filter_month' => intval(date('m'))]);
+ if(!session('payment_taxadvisor_filter_month')){
+ session(['payment_taxadvisor_filter_month' => intval(date('m'))]);
}
- if(!session('product_sales_vol_filter_year')){
- session(['product_sales_vol_filter_year' => intval(date('Y'))]);
+ if(!session('payment_taxadvisor_filter_year')){
+ session(['payment_taxadvisor_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('payment_taxadvisor_filter_month')){
+ session(['payment_taxadvisor_filter_month' => Request::get('payment_taxadvisor_filter_month')]);
}
- if(Request::get('product_sales_vol_filter_year')){
- session(['product_sales_vol_filter_year' => Request::get('product_sales_vol_filter_year')]);
+ if(Request::get('payment_taxadvisor_filter_year')){
+ session(['payment_taxadvisor_filter_year' => Request::get('payment_taxadvisor_filter_year')]);
}
}
@@ -84,8 +84,8 @@ class ProductsSalesController extends Controller
{
$this->setFilterVars();
- $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.'.session('payment_taxadvisor_filter_month').'.'.session('payment_taxadvisor_filter_year'))->format('Y-m-d');
+ $date_end = Carbon::parse('01.'.session('payment_taxadvisor_filter_month').'.'.session('payment_taxadvisor_filter_year'))->endOfMonth()->format('Y-m-d');
$ShoppingOrders = ShoppingOrder::where('paid', 1)->where('mode', 'live')->whereBetween('created_at', [$date_start, $date_end])->get();
@@ -133,11 +133,13 @@ class ProductsSalesController extends Controller
$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();
diff --git a/app/Http/Controllers/TranslationController.php b/app/Http/Controllers/TranslationController.php
index 43af7571..d02464de 100755
--- a/app/Http/Controllers/TranslationController.php
+++ b/app/Http/Controllers/TranslationController.php
@@ -2,180 +2,258 @@
namespace App\Http\Controllers;
-use App;
-use File;
+use App\Models\Category;
use Request;
+use App\Models\Product;
+use App\Models\Ingredient;
+use App\Models\Shipping;
+use App\Models\TransCategory;
+use App\Models\TransProduct;
+use App\Models\TransIngredient;
+use App\Models\TransShipping;
+use App\Models\TransUserLevel;
+use App\Models\UserLevel;
+use Illuminate\Support\Collection;
+use JoeDixon\Translation\Language;
+
class TranslationController extends Controller
{
- protected $languagesPath;
- protected $directory_separator;
- protected $from;
+ protected $sourceLanguage;
+ protected $selectLanguage;
+ protected $selectKey;
+ protected $keys;
+ protected $model;
+
/**
- * Create a new controller instance.
- *
- * @return void
*/
public function __construct()
{
+ $this->sourceLanguage = 'de';
+ $this->selectLanguage = 'en';
+ $this->keys = [];
+ $this->model = "";
+ }
+ /**
+ */
+ public function index($model, $lang=null)
+ {
+ //Request::get('key')
+ //Request::get('language')
+ $this->initByModel($model);
+ $languages = $this->allLanguages();
+ $languages->forget('de');
- $this->directory_separator = DIRECTORY_SEPARATOR;
- $this->languagesPath = App::langPath();
+ $translations = $this->getTranslationsFormModel();
+
+ $data = [
+ 'keys' => $this->keys,
+ 'languages' => $languages,
+ 'model' => $this->model,
+ 'select_language' => $this->selectLanguage,
+ 'source_language' => $this->sourceLanguage,
+ 'translations' => $translations,
+ 'select_key' => $this->selectKey
+ ];
+ return view('translation::languages.translations.custom', $data);
}
/**
- * Show the application dashboard.
+ */
+ public function initByModel($model)
+ {
+ if($model === 'products'){
+ $this->model = $model;
+ $this->keys = [
+ 'name'=>'Produktname',
+ 'copy'=>'Produktbeschreibung',
+ 'description'=>'Beschreibung',
+ 'usage'=>'Anwendung',
+ 'ingredients'=>'Hinweise',
+ ];
+ $this->selectKey = 'name';
+ }
+
+ if($model === 'ingredients'){
+ $this->model = $model;
+ $this->keys = [
+ 'name'=>'Name',
+ 'inci'=>'INCI',
+ 'effect'=>'Wirkung',
+ ];
+ $this->selectKey = 'name';
+ }
+
+ if($model === 'user_levels'){
+ $this->model = $model;
+ $this->keys = [
+ 'name'=>'Name',
+ ];
+ $this->selectKey = 'name';
+ }
+
+ if($model === 'shippings'){
+ $this->model = $model;
+ $this->keys = [
+ 'name'=>'Name',
+ ];
+ $this->selectKey = 'name';
+ }
+
+ if($model === 'categories'){
+ $this->model = $model;
+ $this->keys = [
+ 'name'=>'Name',
+ 'headline'=>'Headline',
+ ];
+ $this->selectKey = 'name';
+ }
+
+ if(Request::get('key')){
+ $this->selectKey = Request::get('key');
+ }
+ if(Request::get('language')){
+ $this->selectLanguage = Request::get('language');
+ }
+ //Request::get('language')
+ }
+
+ public function getTranslationsFormModel(){
+
+ if($this->model === 'products'){
+ return Product::all()->mapWithKeys(function ($value) {
+ return [$value->id => [
+ 'master' => $value->name,
+ 'source' => $value->{$this->selectKey},
+ 'trans' => $value->getTrans($this->selectKey, $this->selectLanguage),
+ ]
+ ];
+ });
+ }
+ if($this->model === 'ingredients'){
+ return Ingredient::all()->mapWithKeys(function ($value) {
+ return [$value->id => [
+ 'master' => $value->name,
+ 'source' => $value->{$this->selectKey},
+ 'trans' => $value->getTrans($this->selectKey, $this->selectLanguage),
+ ]
+ ];
+ });
+ }
+ if($this->model === 'user_levels'){
+ return UserLevel::all()->mapWithKeys(function ($value) {
+ return [$value->id => [
+ 'master' => $value->name,
+ 'source' => $value->{$this->selectKey},
+ 'trans' => $value->getTrans($this->selectKey, $this->selectLanguage),
+ ]
+ ];
+ });
+ }
+ if($this->model === 'shippings'){
+ return Shipping::all()->mapWithKeys(function ($value) {
+ return [$value->id => [
+ 'master' => $value->name,
+ 'source' => $value->{$this->selectKey},
+ 'trans' => $value->getTrans($this->selectKey, $this->selectLanguage),
+ ]
+ ];
+ });
+ }
+ if($this->model === 'categories'){
+ return Category::all()->mapWithKeys(function ($value) {
+ return [$value->id => [
+ 'master' => $value->name,
+ 'source' => $value->{$this->selectKey},
+ 'trans' => $value->getTrans($this->selectKey, $this->selectLanguage),
+ ]
+ ];
+ });
+ }
+ }
+
+ public function update($model)
+ {
+ $id = Request::get('key'); //id
+ $key = Request::get('group'); //key colum
+ $language = Request::get('language'); //selectLanguage
+
+ $value = Request::get('value') ?: ''; //value
+
+ if($model === 'products'){
+ TransProduct::updateOrCreate([
+ 'language' => $language,
+ 'product_id' => $id,
+ 'key' => $key,
+ ], [
+ 'key' => $key,
+ 'value' => $value,
+ ]);
+ }
+
+ if($model === 'ingredients'){
+ TransIngredient::updateOrCreate([
+ 'language' => $language,
+ 'ingredient_id' => $id,
+ 'key' => $key,
+ ], [
+ 'key' => $key,
+ 'value' => $value,
+ ]);
+ }
+
+ if($model === 'user_levels'){
+ TransUserLevel::updateOrCreate([
+ 'language' => $language,
+ 'user_level_id' => $id,
+ 'key' => $key,
+ ], [
+ 'key' => $key,
+ 'value' => $value,
+ ]);
+ }
+
+ if($model === 'shippings'){
+ TransShipping::updateOrCreate([
+ 'language' => $language,
+ 'shipping_id' => $id,
+ 'key' => $key,
+ ], [
+ 'key' => $key,
+ 'value' => $value,
+ ]);
+ }
+
+ if($model === 'categories'){
+ TransCategory::updateOrCreate([
+ 'language' => $language,
+ 'categorie_id' => $id,
+ 'key' => $key,
+ ], [
+ 'key' => $key,
+ 'value' => $value,
+ ]);
+ }
+
+ return ['success' => true];
+ }
+
+ /**
+ * Get all languages from the application.
*
- * @return \Illuminate\Http\Response
+ * @return Collection
*/
- public function index()
+
+ public function allLanguages()
{
- return redirect('admin/translate/all/edit/de');
+ return Language::all()->mapWithKeys(function ($language) {
+ return [$language->language => $language->name ?: $language->language];
+ });
}
- /**
- * @param $language
- * @param string $from
- * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
- * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
- */
- public function edit($language, $from = 'en')
- {
- $localisations = array_keys(config('localization.supportedLocales'));
- $files = $this->json_files($localisations);
- $translations = $this->translationsJson($language, $from);
- $show = "all";
- return view('translation.index', compact('files','translations', 'language', 'from', 'show'));
- }
-
-
- /**
- * @param $lang
- * @return \Illuminate\Http\RedirectResponse
- * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
- */
- public function update($language)
- {
-
-
- $path = $this->resourcePath($this->languagesPath);
- $file = $path.$language.".json";
- $data = Request::all();
- $this->backup($path, $language.".json");
- unset($data['_token']);
-
- $ret = [];
- //file make keys
- $source = json_decode(File::get($path."de.json"));
- foreach ($source as $key => $v){
- $skey = $this->sanitize($key);
- if(!empty($data[$skey])) {
- $ret[$key] = $data[$skey];
- }
- }
- $jsonData = json_encode($ret, TRUE);
- file_put_contents($file, $jsonData);
- return redirect()
- ->route('admin_translate_all_edit', [$language])
- ->with('message', 'Translation added successfully');
- }
-
- /**
- * @param $langs
- * @return array
- * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
- */
- public function json_files($localisations){
- $path = $this->resourcePath($this->languagesPath);
- $content = array();
- foreach ($localisations as $local){
- $file = File::get($path.$local.".json");
- if($file){
- $content[$local] = array('path'=>$path.$local.".json", 'content'=>json_encode($file));
- }
- }
- return $content;
-
-
- }
-
- /**
- * @param $language
- * @param $from
- * @return array
- * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
- */
- public function translationsJson($language, $from)
- {
- $path = $this->resourcePath($this->languagesPath);
- $file = array();
- $file['keys'] = (array) json_decode(File::get($path."de.json"));
- $file['keys'] = $this->sanitizeKey($file['keys']);
- $file['from'] = (array) json_decode(File::get($path.$from.".json"));
- $file['from'] = $this->sanitizeKey($file['from']);
- $file['dest'] = (array) json_decode(File::get($path.$language.".json"));
- $file['dest'] = $this->sanitizeKey($file['dest']);
-
- return $file;
- }
-
- private function backup($path, $file)
- {
-
- if (!File::exists(storage_path('language/'))) {
- File::makeDirectory(storage_path('language/'), 0755, true);
- }
-
- return File::copy($path.$file, storage_path('language/'.time()."-".$file));
- }
-
- /**
- * @param $path
- * @return string
- */
- protected function resourcePath($path)
- {
- return "{$path}{$this->directory_separator}";
- }
-
- /**
- * @param $arr
- * @return mixed
- */
- protected function sanitizeKey($arr){
- foreach ($arr as $key => $val){
- unset($arr[$key]);
- $arr[$this->sanitize($key)] = $val;
- }
- return $arr;
-
- }
-
- /**
- * @param $string
- * @param bool $force_lowercase
- * @param bool $anal
- * @return mixed|null|string|string[]
- */
- protected function sanitize($string, $force_lowercase = true, $anal = false)
- {
- $strip = array("~", "`", "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "_", "=", "+", "[", "{", "]",
- "}", "\\", "|", ";", ":", "\"", "'", "‘", "’", "“", "”", "–", "—",
- "—", "–", ",", "<", ".", ">", "/", "?");
- $clean = trim(str_replace($strip, "", strip_tags($string)));
- $clean = preg_replace('/\s+/', "_", $clean);
- $clean = ($anal) ? preg_replace("/[^a-zA-Z0-9]/", "", $clean) : $clean ;
-
- return ($force_lowercase) ?
- (function_exists('mb_strtolower')) ?
- mb_strtolower($clean, 'UTF-8') :
- strtolower($clean) :
- $clean;
- }
-
}
diff --git a/app/Http/Controllers/User/CustomerController.php b/app/Http/Controllers/User/CustomerController.php
index d5c279c7..01b8ffaa 100755
--- a/app/Http/Controllers/User/CustomerController.php
+++ b/app/Http/Controllers/User/CustomerController.php
@@ -189,6 +189,8 @@ class CustomerController extends Controller
return back()->withErrors($validator)->withInput(Request::all());
}
}
+
+ $data['language'] = isset($data['language']) ? $data['language'] : \App::getLocale();
$data['faker_mail'] = isset($data['faker_mail']) ? true : false;
$data['has_buyed'] = isset($data['has_buyed']) ? true : false;
$data['subscribed'] = isset($data['subscribed']) ? true : false;
@@ -237,10 +239,12 @@ class CustomerController extends Controller
if(Request::get('filter_member_id') != ""){
$query->where('member_id', '=', Request::get('filter_member_id'));
}*/
+
return \DataTables::eloquent($query)
->addColumn('send_to', function (ShoppingUser $ShoppingUser) {
- return $ShoppingUser->is_like ? ' in Prüfung' : ' wählen';
+ $ot = Request::get('isfor') ? Request::get('isfor') : 'ot-member';
+ return $ShoppingUser->is_like ? ' '.__('customer.under_review').'' : ' '.__('customer.select').'';
})
->addColumn('billing_email', function (ShoppingUser $ShoppingUser) {
return $ShoppingUser->faker_mail ? "-" : $ShoppingUser->billing_email;
@@ -264,7 +268,7 @@ class CustomerController extends Controller
return get_active_badge($ShoppingUser->subscribed);
})
->addColumn('status', function (ShoppingUser $ShoppingUser) {
- return $ShoppingUser->is_like ? ' in Prüfung ' : ' zugewiesen';
+ return $ShoppingUser->is_like ? ' '.__('customer.under_review').' ' : ' '.__('customer.assigned').'';
})
->addColumn('extras', function (ShoppingUser $ShoppingUser) {
return $ShoppingUser->wp_order_number.($ShoppingUser->mode==='dev' ? ' dev' : '');
diff --git a/app/Http/Controllers/User/DocumentsController.php b/app/Http/Controllers/User/DocumentsController.php
new file mode 100644
index 00000000..78646057
--- /dev/null
+++ b/app/Http/Controllers/User/DocumentsController.php
@@ -0,0 +1,131 @@
+middleware('auth');
+ $this->fileRepo = $fileRepo;
+ }
+
+
+ public function index()
+ {
+ $user = User::find(Auth::user()->id);
+
+ $data = [
+ 'user' => $user,
+ 'business_license_choose' => $user->account->getNotice('business_license'),
+ ];
+ return view('user.documents.index', $data);
+
+ }
+
+ public function store($action){
+
+
+ $data = Request::all();
+ $user = User::findOrFail(Auth::user()->id);
+
+ if ($action == 'verification') {
+ if(Request::get('submit') === 'do'){
+ if(File::whereUserId($user->id)->whereIdentifier('id_card')->count() == 0){
+ $validator = Validator::make(Request::all(), []);
+ $validator->errors()->add('field', __('msg.no_id_card_deposited_please_upload_first'));
+ $user->save();
+ return redirect(route('user_documents'))->withErrors($validator)->withInput(Request::all());
+ }
+ $user->save();
+ return redirect(route('user_documents'));
+ }
+ $this->fileRepo->_set('disk', 'user');
+ $this->fileRepo->_set('dir', '/'.$user->id.'/verification/');
+ $this->fileRepo->_set('user_id', $user->id);
+ $this->fileRepo->_set('identifier', 'id_card');
+ return $this->fileRepo->uploadFile(Request::all());
+ }
+
+ if ($action == 'business_license') {
+ if(Request::get('submit') === 'do'){
+ $data = Request::all();
+
+ if($data['business_license_choose'] === "now"){
+ if(File::whereUserId($user->id)->whereIdentifier('business_license')->count() == 0){
+ $validator = Validator::make(Request::all(), []);
+ $validator->errors()->add('field', __('msg.no_trade_licence_deposited_please_upload_first'));
+ $user->save();
+ return redirect(route('user_documents'))->withErrors($validator)->withInput(Request::all());
+ }
+ $user->account->setNotice('business_license_reason', '');
+
+ }
+ if($data['business_license_choose'] === "later"){
+ $user->account->setNotice('business_license_reason', '');
+
+ }
+ if($data['business_license_choose'] === "non"){
+ if(!$data['non_business_license_reason'] || $data['non_business_license_reason'] == ""){
+ $validator = Validator::make(Request::all(), []);
+ $validator->errors()->add('field', __('msg.please_enter_reason_why_you_not_need_trade_licence'));
+ $user->save();
+ return redirect(route('user_documents'))->withErrors($validator)->withInput(Request::all());
+ }else{
+ $user->account->setNotice('business_license_reason', $data['non_business_license_reason']);
+ }
+ }
+ $user->account->setNotice('business_license', $data['business_license_choose']);
+ $user->save();
+
+ if($user->isTestMode()){
+ $mail = config('app.info_test_mail');
+ }else{
+ $mail = config('app.info_mail');
+ }
+
+ Mail::to($mail)->locale($user->getLocale())->send(new MailReleaseDocument($user));
+
+ return redirect(route('user_documents'));
+ }
+ $this->fileRepo->_set('disk', 'user');
+ $this->fileRepo->_set('dir', '/'.$user->id.'/verification/');
+ $this->fileRepo->_set('user_id', $user->id);
+ $this->fileRepo->_set('identifier', 'business_license');
+ return $this->fileRepo->uploadFile(Request::all());
+ }
+
+ }
+
+ public function delete($id, $relation){
+
+ if($relation === 'upload'){
+ $user = User::findOrFail(Auth::user()->id);
+ $file = $user->files()->findOrFail($id);
+ //remove file
+ \Storage::disk('user')->delete($file->dir.$file->filename);
+ $file->delete();
+ \Session()->flash('alert-success', __('msg.file_deleted'));
+ }
+ return back();
+ }
+
+}
\ No newline at end of file
diff --git a/app/Http/Controllers/User/DownloadController.php b/app/Http/Controllers/User/DownloadController.php
new file mode 100644
index 00000000..76706385
--- /dev/null
+++ b/app/Http/Controllers/User/DownloadController.php
@@ -0,0 +1,145 @@
+middleware('active.account');
+ }
+
+ public function index()
+ {
+
+ $this->setFilterVars();
+ $files = DcFile::where('active', true)->orderBy('id', 'desc')->get(); //File::all();
+
+ $filter_list = $this->makeFilterList();
+ $data = [
+ 'files' => $files,
+ 'filter_list' => $filter_list,
+ 'tag_ids' => array(),
+ 'resTagIds' => array(),
+ 'search' => false,
+
+ ];
+
+ return view('user.downloadcenter.index', $data);
+ }
+
+ public function search(){
+
+ $request = Request::all();
+
+
+ if(Request::ajax()){
+
+ $request['tagIds'] = isset($request['tagIds']) ? $request['tagIds'] : array();
+ $request['searchinput'] = isset($request['searchinput']) ? $request['searchinput'] : "";
+ $tag_ids = $request['tagIds'];
+ $searchTags = [];
+ foreach ($tag_ids as $tags) {
+ if($tags != "" && $tags != "0"){
+ if(is_array($tags)){
+ foreach ($tags as $tag) {
+ array_push($searchTags, $tag);
+ }
+ }else{
+ array_push($searchTags, $tags);
+ }
+ }
+ }
+ $q = DcFile::with('fileTag')->where('active', 1);
+ if($request['searchinput'] != ""){
+ $q->where('original_name', 'LIKE', '%'.$request['searchinput'].'%');
+ }
+ if(count($searchTags) > 0){
+ $q->whereHas('fileTag', function ($query) use ($searchTags){
+ $query->whereIn('tag_id', $searchTags);
+ });
+ }
+
+ $files = $q->orderBy('id', 'desc')->get();
+ $returnContentFiles = view('user.downloadcenter.content-files')->with('files', $files)->render();
+ /* if(strlen($files) < 1){
+ $returnContentFiles = "Keine Einträge vorhanden";
+ }*/
+ /*
+ $resTagIds = array();
+ foreach ($files as $file) {
+ foreach ($file->fileTag as $tagId) {
+ if(empty($resTagIds[$tagId->tag_id])){
+ $resTagIds[$tagId->tag_id] = 1;
+ }else{
+ $resTagIds[$tagId->tag_id]++;
+ }
+
+ }
+ }
+
+ $categories = DcCategory::orderBy('pos')->get();
+ $data = [
+ 'categories' => $categories,
+ 'tag_ids' => $tag_ids,
+ 'resTagIds' => $resTagIds,
+ 'search' => true,
+ ];
+ $returnFilters = view('content-collapse')->with('data', $data)->render();
+ */
+ $returnFilters = "";
+ return response()->json( array('success' => true, 'request' => $request, 'searchTags' => $searchTags, 'content_files'=>$returnContentFiles, 'content_filter'=>$returnFilters) );
+ }
+ return false;
+
+ }
+
+ private function setFilterVars(){
+
+
+ /* if(!session('user_shop_api_orders_filter')){
+ session(['user_shop_api_orders_filter' => 1]);
+ }
+ if(Request::get('user_shop_api_orders_filter')){
+ session(['user_shop_api_orders_filter' => Request::get('user_shop_api_orders_filter')]);
+ }
+ */
+ }
+ private function makeFilterList($archive = false, $request = true)
+ {
+ $ret = [];
+ $categories = DcCategory::where('active', true)->orderBy('pos')->get();
+ foreach($categories as $category){
+ $tags = DcTag::where('category_id', $category->id)->where('active', true)->orderBy('pos')->get();
+ $items = [];
+ foreach ($tags as $tag){
+ //has file tags
+ $count = DcFileTag::with('dc_file')->where('tag_id', $tag->id)->whereHas('dc_file', function ($query){
+ $query->where('active', true);
+ })->count();
+ if($count > 0){
+ $tag->count = $count;
+ $items[] = $tag;
+ }
+ }
+ if(isset($items) && count($items) > 0){
+ $ret[$category->id]['items'] = $items;
+ $ret[$category->id]['name'] = $category->name;
+ }
+ }
+
+
+ return $ret;
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/Http/Controllers/User/HomepartyController.php b/app/Http/Controllers/User/HomepartyController.php
index f7c5064c..a349a063 100755
--- a/app/Http/Controllers/User/HomepartyController.php
+++ b/app/Http/Controllers/User/HomepartyController.php
@@ -42,7 +42,6 @@ class HomepartyController extends Controller
$homeparty = new Homeparty();
$homeparty->id = 0;
$step = 1;
- $homeparty->description = "Willkommen zu unserer Auszeitparty rund um das Thema Bio Aloe Vera und Naturkosmetik. Wir informieren Dich darüber, was Premiumqualität bei Naturkosmetik wirklich ausmacht, zeigen Dir viele Anwendungsbeispiele bei Haut- und Darmproblemen und natürlich kannst Du unsere Produkte ausgiebig testen. Wir freuen uns auf Dich!";
}else{
$homeparty = $this->getHomparty($id);
if($homeparty->step < 10){
@@ -76,6 +75,7 @@ class HomepartyController extends Controller
public function store($id = null, $step = false)
{
$data = Request::all();
+
if($data['action'] === 'homeparty-party-store-detail'){
$rules = array(
'date' => 'required',
@@ -130,6 +130,7 @@ class HomepartyController extends Controller
$data['step'] = 2;
$step = 2;
$homeparty = Homeparty::create($data);
+ $this->storeTranslations($homeparty, \App::getLocale(), $data);
$homeparty_user = HomepartyUser::create([
'homeparty_id' => $homeparty->id,
'auth_user_id' => \Auth::user()->id,
@@ -141,6 +142,7 @@ class HomepartyController extends Controller
}else {
$homeparty = $this->getHomparty($id);
$homeparty->fill($data)->save();
+ $this->storeTranslations($homeparty, \App::getLocale(), $data);
$step = 10;
}
}
@@ -174,6 +176,20 @@ class HomepartyController extends Controller
return redirect(route('user_homeparty_detail', [$homeparty->id, $step]));
}
+ private function storeTranslations($homeparty, $lang, $data){
+
+ if($lang == 'de'){
+ $homeparty->description = $data['description'];
+ $homeparty->save();
+ return;
+ }
+ $trans = $homeparty->trans_description;
+ $trans[$lang] = $data['description'];
+ $homeparty->trans_description = $trans;
+ $homeparty->save();
+ return;
+ }
+
public function guests($id = null)
{
@@ -269,7 +285,7 @@ class HomepartyController extends Controller
}
UserService::checkUserTaxShippingCountry($user, $shipping_country_id);
if($this->userChangeCountry($homeparty)){
- \Session()->flash('custom-error', 'Das Rechnungsland wurde geändert und der Warenkrob zurückgesetzt.');
+ \Session()->flash('custom-error', __('msg.country_account_has_been_changed__cost_has_been_reset'));
return redirect(route('user_homeparty_order', [$homeparty->id]));
}
HomepartyCart::calculateHomeparty($homeparty);
@@ -450,7 +466,7 @@ class HomepartyController extends Controller
HomepartyCart::calculateHomeparty($homeparty);
if(\App\Services\HomepartyCart::$price === 0){
- \Session()->flash('alert-error', 'Dein Warenkorb ist leer, bitte füge erst Produkte hinzu.');
+ \Session()->flash('alert-error', __('msg.your_shopping_cart_is_empty_please_add_products_first'));
return redirect(route('user_homeparty_order', [$homeparty->id]));
}
@@ -490,9 +506,10 @@ class HomepartyController extends Controller
'identifier' => $identifier,
'user_shop_id' => 1, //is first faker shop for nuy intern
'auth_user_id' => Auth::user()->id,
- 'payment' => 5, //Berater Membership
+ 'payment' => 5, //Berater Homeparty
'subdomain' => url('/'),
'country_id' => Yard::instance('shopping')->getShippingCountryId(),
+ 'language' => \App::getLocale(),
'shopping_data' => $data,
'back' => url()->previous(),
@@ -524,7 +541,7 @@ class HomepartyController extends Controller
}
//$homeparty_user->save();
$homeparty_user->delete();
- \Session()->flash('alert-success', "Auszeitparty Gast gelöscht");
+ \Session()->flash('alert-success', __('msg.homeparty_guest_delete'));
return redirect(route('user_homeparty_guests', [$homeparty->id]));
}
@@ -547,7 +564,7 @@ class HomepartyController extends Controller
}
}
$homeparty->delete();
- \Session()->flash('alert-success', "Auszeitparty gelöscht");
+ \Session()->flash('alert-success', __('msg.homeparty_delete'));
return redirect(route('user_homepartys'));
}
diff --git a/app/Http/Controllers/MembershipController.php b/app/Http/Controllers/User/MembershipController.php
similarity index 90%
rename from app/Http/Controllers/MembershipController.php
rename to app/Http/Controllers/User/MembershipController.php
index c9d7ab23..99296f88 100755
--- a/app/Http/Controllers/MembershipController.php
+++ b/app/Http/Controllers/User/MembershipController.php
@@ -1,12 +1,11 @@
account->payment_data = null;
$user->account->save();
UserHistory::create(['user_id' => $user->id, 'action'=>'abo_options_remove', 'status'=>10]);
- \Session()->flash('alert-success', "Abo-Option deaktiviert");
+ \Session()->flash('alert-success', __('msg.abo_deaktivert'));
return back();
}
- \Session()->flash('alert-error', "Fehler, Checkbox nicht bestätigt.");
+ \Session()->flash('alert-error', __('msg.error_checkbox_not_confirm'));
return back();
}
//#### payment order
@@ -111,8 +110,8 @@ class MembershipController extends Controller
$product = Product::find(Request::get('switchers-package-wizard'));
$showAboOptions = false;
if(Request::get('abo_options')){
- $showAboOptions = true;
- $user->abo_options = true;
+ $showAboOptions = false; //true Abo Option deaktivert
+ $user->abo_options = false; //true Abo Option deaktivert
$user->save();
}
@@ -155,6 +154,7 @@ class MembershipController extends Controller
'payment' => 3, //Berater Membership
'subdomain' => url('/'),
'country_id' => Yard::instance('shopping')->getShippingCountryId(),
+ 'language' => \App::getLocale(),
'shopping_data' => $data,
'back' => url()->previous(),
@@ -174,14 +174,14 @@ class MembershipController extends Controller
$user = User::find(Auth::user()->id);
$product = Product::find(Request::get('switchers-package-wizard'));
if($user->payment_order_id == $product->id){
- \Session()->flash('alert-success', "keine Änderung vorgenommen.");
+ \Session()->flash('alert-success', __('msg.no_change_made'));
return back();
}
if($product && $product->active){
$user->payment_order_id = $product->id;
$user->save();
UserHistory::create(['user_id' => $user->id, 'action'=>$action, 'status'=>10, 'product_id'=>$product->id]);
- \Session()->flash('alert-success', "gebuchtes Paket wurde geändert.");
+ \Session()->flash('alert-success', __('msg.booked_package_has_been_changed'));
return back();
}
@@ -198,10 +198,10 @@ class MembershipController extends Controller
}
Mail::to($mail)->send(new MailInfo($user, 'delete_membership'));
UserHistory::create(['user_id' => $user->id, 'action'=>$action, 'status'=>50]);
- \Session()->flash('alert-success', "Mitgliedschaft beenden ist beantragt");
+ \Session()->flash('alert-success', __('msg.cancel_membership_is_requested'));
return back();
}
- \Session()->flash('alert-error', "Fehler, Checkbox nicht bestätigt.");
+ \Session()->flash('alert-error', __('msg.error_checkbox_not_confirm'));
return back();
}
diff --git a/app/Http/Controllers/User/OrderController.php b/app/Http/Controllers/User/OrderController.php
index 5e4dbae7..27c40c08 100755
--- a/app/Http/Controllers/User/OrderController.php
+++ b/app/Http/Controllers/User/OrderController.php
@@ -2,23 +2,25 @@
namespace App\Http\Controllers\User;
-use App\Http\Controllers\Controller;
+
+use Auth;
+use Yard;
+use Request;
+use App\User;
+use Validator;
+use App\Services\Shop;
+use App\Services\Util;
use App\Models\Product;
+use App\Services\Payment;
+use App\Models\UserHistory;
+use App\Models\ShoppingUser;
+use App\Models\ShoppingOrder;
+use App\Services\UserService;
+use App\Mail\MailCustomPaymet;
use App\Models\ShippingCountry;
use App\Models\ShoppingInstance;
-use App\Models\ShoppingOrder;
-use App\Models\ShoppingUser;
-use App\Models\UserHistory;
-use App\Models\UserShop;
-use App\Services\Payment;
-use App\Services\UserService;
-use App\Services\Util;
-use App\User;
-use Auth;
-use Request;
-use Validator;
-use Yard;
-
+use App\Http\Controllers\Controller;
+use Illuminate\Support\Facades\Mail;
class OrderController extends Controller
{
@@ -85,7 +87,7 @@ class OrderController extends Controller
data-back=""
data-modal="modal-xl"
data-init_from="user"
- data-route="'.route('modal_load').'">';
+ data-route="'.route('modal_load').'">';
}
return ''.$ShoppingOrder->getShippedType().'';
})
@@ -109,29 +111,31 @@ class OrderController extends Controller
->make(true);
}
+ /*
+ $for = me, ot-member, ot-customer, abo-ot-member, abo-ot-customer, abo-me
+ */
public function delivery($for, $id=null)
{
$user = User::find(\Auth::user()->id);
$shopping_user = null;
$delivery_id = null;
- if($for === 'ot'){
- $shopping_user = $this->checkShoppingUser($id, $user);
+ if(strpos($for, 'ot') !== false){ //ot-member, ot-customer abo-ot-member, abo-ot-customer,
+ $shopping_user = Shop::checkShoppingUser($id, $user);
$delivery_id = $shopping_user->id;
- if(!$this->checkShoppingCountry($for, $delivery_id) && !\Session()->has('custom-error')){
- \Session()->flash('custom-error', __('validation.custom.shipping_not_found'));
+ if(!Shop::checkShoppingCountry($for, $delivery_id) && !\Session()->has('custom-error')){
+ $country = Shop::getDeliveryCountry($for, $delivery_id);
+ \Session()->flash('custom-error', $country.": ".__('validation.custom.shipping_not_found'));
return redirect(route('user_order_my_delivery', [$for, $delivery_id]));
}
}
-
if(Request::get('action') === 'next'){
Yard::instance('shopping')->destroy();
- if(Request::get('switchers-radio-is-for') === 'ot'){
+ if(strpos(Request::get('switchers-radio-is-for'), 'ot') !== false){
$delivery_id = $id;
}
return redirect(route('user_order_my_list', [Request::get('switchers-radio-is-for'), $delivery_id]));
}
-
$data = [
'shopping_user' => $shopping_user,
'isAdmin' => false,
@@ -144,31 +148,36 @@ class OrderController extends Controller
public function list($for, $id=null)
{
-
$user = User::find(\Auth::user()->id);
$shopping_user = null;
$delivery_id = null;
- if($for === 'ot'){
- $shopping_user = $this->checkShoppingUser($id, $user);
+ if(strpos($for, 'ot') !== false){ //ot-member, ot-customer abo-ot-member, abo-ot-customer,
+ $shopping_user = Shop::checkShoppingUser($id, $user);
$delivery_id = $shopping_user->id;
}
- $shipping_country_id = $this->checkShoppingCountry($for, $id);
- if(!$shipping_country_id){
- \Session()->flash('custom-error', __('validation.custom.shipping_not_found'));
- return redirect(route('user_order_my_delivery', [$for, $delivery_id]));
+ if($for === 'ot-customer' || $for === 'abo-ot-customer'){
+ //Liederung an (abo-) ot-customer (Kunden) Zahlung und Rechnung geht an Kunden
+ UserService::initCustomerYard($shopping_user, $for);
+ }else{
+ //Lieferung an user oder (abo-) ot-member (Kunden) rechnung geht an User
+ //lieferland und rechnungsland prüfen
+ $shipping_country_id = Shop::checkShoppingCountry($for, $id);
+ if(!$shipping_country_id){
+ $country = Shop::getDeliveryCountry($for, $id);
+ \Session()->flash('custom-error', $country.": ".__('validation.custom.shipping_not_found'));
+ return redirect(route('user_order_my_delivery', [$for, $delivery_id]));
+ }
+ UserService::initUserYard($user, $shipping_country_id, $for);
}
- UserService::checkUserTaxShippingCountry($user, $shipping_country_id);
- Yard::instance('shopping')->setShippingCountryWithPrice($shipping_country_id, $for);
- Yard::instance('shopping')->setUserPriceInfos(UserService::getYardInfo());
-
-
$data = [
'shopping_user' => $shopping_user,
'user' => $user,
'isAdmin' => false,
'isView' => 'customer',
'for' => $for,
+ 'template' => str_replace('abo-', '', $for),
'delivery_id' => $delivery_id,
+ 'is_abo' => strpos($for, 'abo') !== false,
'comp_products' => $this->getCompProducts($for),
];
return view('user.order.list', $data);
@@ -187,20 +196,21 @@ class OrderController extends Controller
'shipping_state' => 'required',
);
$validator = Validator::make(Request::all(), $rules);
-
if ($validator->fails()) {
return back()->withErrors($validator)->withInput(Request::all());
}
+ //hier prüfen, ob versand etc richtig berechnet wurde
+ $this->checkSendYardForPayment($data, $id);
if(Yard::instance('shopping')->getNumComp() > 0){
if(!isset($data['switchers-comp-product'])){
- $validator->errors()->add('switchers-comp-product', __('Bitte wähle ein Kompensationsprodukt aus'));
+ $validator->errors()->add('switchers-comp-product', __('msg.please_select_compensation_product'));
}else{
if(!is_array($data['switchers-comp-product'])){
- $validator->errors()->add('switchers-comp-product', __('Bitte wähle ein Kompensationsprodukt aus'));
+ $validator->errors()->add('switchers-comp-product', __('msg.please_select_compensation_product'));
}else{
if(count($data['switchers-comp-product']) !== Yard::instance('shopping')->getNumComp()){
- $validator->errors()->add('switchers-comp-product', __('Bitte wähle :count Kompensationsprodukte aus', ['count'=>Yard::instance('shopping')->getNumComp()]));
+ $validator->errors()->add('switchers-comp-product', __('mdg.please_select_count_compensation_products', ['count'=>Yard::instance('shopping')->getNumComp()]));
}
}
}
@@ -213,92 +223,170 @@ class OrderController extends Controller
} while( ShoppingInstance::where('identifier', $identifier)->count() );
$data['is_from'] = 'user_order';
$data['is_for'] = $for;
+ $data['is_abo'] = $data['is_abo'] ?? 0;
+ $data['abo_interval'] = $data['abo_interval'] ?? 0;
$data['shopping_user_id'] = $id;
$data['user_price_infos'] = Yard::instance('shopping')->getUserPriceInfos();
unset($data['quantity']);
unset($data['_token']);
+ $data['mode'] = 'live';
- ShoppingInstance::create([
- 'identifier' => $identifier,
- 'user_shop_id' => 1, //is first faker shop for buy intern
- 'auth_user_id' => Auth::user()->id,
- 'payment' => 2, //Berater Shop
- 'subdomain' => url('/'),
- 'country_id' => Yard::instance('shopping')->getShippingCountryId(),
- 'shopping_data' => $data,
- 'back' => url()->previous(),
+ if($for === 'ot-customer' || $for === 'abo-ot-customer'){
+ ShoppingInstance::create([
+ 'identifier' => $identifier,
+ 'user_shop_id' => $user->shop->id,
+ 'payment' => 6, //Berater Shop to Customer Shop
+ 'subdomain' => $user->shop->getSubdomain(),
+ 'country_id' => Yard::instance('shopping')->getShippingCountryId(),
+ 'language' => \App::getLocale(),
+ 'shopping_data' => $data,
+ 'back' => url()->previous(),
+
+ ]);
+ $yard_shopping_items = Shop::getYardShoppingItems();
+ Yard::instance('shopping')->store($identifier);
+ // send Mail to Customer
+ $this->customPaymentSendMail($user, $identifier, $yard_shopping_items, $data);
+ UserHistory::create(['user_id' => $user->id, 'action'=>'user_order_customer', 'status'=>1, 'product_id'=>null, 'identifier'=>$identifier, 'is_abo'=>$data['is_abo']]);
- ]);
- Yard::instance('shopping')->store($identifier);
+ //eine Abschließen bestellseite für den User + Link zum Kunden Shop + Mail an den Kunden / Berater
+ return redirect(route('user_order_my_custom_payment', ['identifier'=>$identifier]));
+ }else{
+ ShoppingInstance::create([
+ 'identifier' => $identifier,
+ 'user_shop_id' => 1, //is first faker shop for buy intern
+ 'auth_user_id' => Auth::user()->id,
+ 'payment' => 2, //Berater Shop
+ 'subdomain' => url('/'),
+ 'country_id' => Yard::instance('shopping')->getShippingCountryId(),
+ 'language' => \App::getLocale(),
+ 'shopping_data' => $data,
+ 'back' => url()->previous(),
-
- //add to DB
- $path = route('checkout.checkout_card', ['identifier'=>$identifier]);
- UserHistory::create(['user_id' => $user->id, 'action'=>'user_order_payment', 'status'=>1, 'product_id'=>null, 'identifier'=>$identifier, 'abo_options'=>0]);
- //$path = str_replace('http', 'https', $path);
- return redirect()->secure($path);
+ ]);
+ Yard::instance('shopping')->store($identifier);
+ $path = route('checkout.checkout_card', ['identifier'=>$identifier]);
+ UserHistory::create(['user_id' => $user->id, 'action'=>'user_order_payment', 'status'=>1, 'product_id'=>null, 'identifier'=>$identifier, 'is_abo'=>$data['is_abo']]);
+ //$path = str_replace('http', 'https', $path);
+ return redirect()->secure($path);
+ }
}
- private function checkShoppingCountry($for, $id=null){
+ private function checkSendYardForPayment($data, $id){
- $country_id = null;
- if($for === 'me'){
- $user = User::find(\Auth::user()->id);
- if($user->account->same_as_billing){
- $country_id = $user->account->country_id;
- }else{
- $country_id = $user->account->shipping_country_id;
- }
+ $user = User::find(\Auth::user()->id);
+ $shopping_user = null;
+ if(strpos($data['shipping_is_for'], 'ot') !== false){
+ $shopping_user = Shop::checkShoppingUser($id, $user);
}
- if($for === 'ot' && $id){
- $shopping_user = ShoppingUser::findOrFail($id);
- if($shopping_user->same_as_billing){
- $country_id = $shopping_user->billing_country_id;
- }else{
- $country_id = $shopping_user->shipping_country_id;
- }
- }
- if($country_id){
- if($shipping_country = ShippingCountry::whereCountryId($country_id)->first()){
- if($shipping_country->shipping && $shipping_country->shipping->active){
- return $shipping_country->id;
- }
-
- }
- }
- return false;
- }
- private function checkShoppingUser($id, $user){
- if($id === null){
- abort(403, 'Error: Keine User ID');
+ $shipping_country_id = Shop::checkShoppingCountry($data['shipping_is_for'], $id);
+ if(!$shipping_country_id){
+ $identifier = 'error-'.time().mt_rand(1000000, 9999999);
+ Yard::instance('shopping')->store($identifier);
+ $data['user_id'] = Auth::user()->id;
+ $data['shopping_user_id'] = $id;
+ \App\Services\MyLog::writeLog('payment', 'error', 'no shipping_country_id found | Yard identifier: '.$identifier, $data);
+ abort(403, __('msg.shipping_country_was_not_found'));
}
- $shopping_user = ShoppingUser::findOrFail($id);
- if($shopping_user->member_id !== $user->id){
- abort(403, 'Error: Falsche User ID');
+ //must be the same shipping country
+ if($shipping_country_id != Yard::instance('shopping')->getShippingCountryId()){
+ $identifier = 'error-'.time().mt_rand(1000000, 9999999);
+ Yard::instance('shopping')->store($identifier);
+ $data['user_id'] = Auth::user()->id;
+ $data['shopping_user_id'] = $id;
+ \App\Services\MyLog::writeLog('payment', 'error', 'shipping_country_id is not the same from Yard | Yard identifier: '.$identifier, $data);
+ abort(403, __('msg.shipping_country_was_not_correctly'));
}
- $shopping_user = ShoppingUser::findOrFail($id);
- if($shopping_user->is_like){
- abort(403, 'Error: Kunde in Prüfung');
+
+ if($data['shipping_is_for'] !== 'ot-customer'){
+ if(Yard::instance('shopping')->shipping_free){
+ $identifier = 'error-'.time().mt_rand(1000000, 9999999);
+ Yard::instance('shopping')->store($identifier);
+ $data['user_id'] = Auth::user()->id;
+ $data['shopping_user_id'] = $id;
+ \App\Services\MyLog::writeLog('payment', 'error', 'Yard can by not shipping_free | Yard identifier: '.$identifier, $data);
+ abort(403, __('msg.shopping_cart_was_shipping_free'));
+ }
+ }
+
+ if($data['shipping_is_for'] === 'ot-customer'){
+ if(!$user->shop){
+ $identifier = 'error-'.time().mt_rand(1000000, 9999999);
+ Yard::instance('shopping')->store($identifier);
+ $data['user_id'] = Auth::user()->id;
+ $data['shopping_user_id'] = $id;
+ \App\Services\MyLog::writeLog('payment', 'error', 'User has no Shop for an User to Customer order| Yard identifier: '.$identifier, $data);
+ abort(403, __('msg.shopping_cart_was_not_user_shop'));
+ }
+ }
+
+ $shipping_price = Shop::getShippingPriceByShippingCountryId($shipping_country_id, Yard::instance('shopping')->weight());
+ //for other and has weight - check
+ if(strpos($data['shipping_is_for'], 'ot') !== false && $data['shipping_is_for'] !== 'ot-customer' && Yard::instance('shopping')->weight() > 0){
+ if(!Yard::instance('shopping')->getShippingPrice() || Yard::instance('shopping')->getShippingPrice() == 0){
+ $identifier = 'error-'.time().mt_rand(1000000, 9999999);
+ Yard::instance('shopping')->store($identifier);
+ $data['user_id'] = Auth::user()->id;
+ $data['shopping_user_id'] = $id;
+ \App\Services\MyLog::writeLog('payment', 'error', 'Yard OT shipping_price is 0 or | Yard identifier: '.$identifier, $data);
+ abort(403, __('msg.shipping_cost_cannot_be_0'));
+ }
+ if(Yard::instance('shopping')->getShippingPrice() != $shipping_price->price){
+ $identifier = 'error-'.time().mt_rand(1000000, 9999999);
+ Yard::instance('shopping')->store($identifier);
+ $data['user_id'] = Auth::user()->id;
+ $data['shopping_user_id'] = $id;
+ \App\Services\MyLog::writeLog('payment', 'error', 'Yard OT shipping_price is not the same from shipping_price | Yard identifier: '.$identifier, $data);
+ abort(403, __('msg.shipping_costs_were_not_calculated_correctly'));
+ }
+ }
+
+ if(($data['shipping_is_for'] == 'me' || $data['shipping_is_for'] == 'abo-me') && Yard::instance('shopping')->weight() > 0){
+ if(!Yard::instance('shopping')->getShippingPrice() || Yard::instance('shopping')->getShippingPrice() == 0){
+ $identifier = 'error-'.time().mt_rand(1000000, 9999999);
+ Yard::instance('shopping')->store($identifier);
+ $data['user_id'] = Auth::user()->id;
+ $data['shopping_user_id'] = $id;
+ \App\Services\MyLog::writeLog('payment', 'error', 'Yard ME shipping_price is 0 or | Yard identifier: '.$identifier, $data);
+ abort(403, __('msg.shipping_cost_cannot_be_0'));
+ }
+ if(Yard::instance('shopping')->getShippingPrice() != $shipping_price->price_comp){
+ $identifier = 'error-'.time().mt_rand(1000000, 9999999);
+ Yard::instance('shopping')->store($identifier);
+ $data['user_id'] = Auth::user()->id;
+ $data['shopping_user_id'] = $id;
+ \App\Services\MyLog::writeLog('payment', 'error', 'Yard ME shipping_price is not the same from shipping_price | Yard identifier: '.$identifier, $data);
+ abort(403, __('msg.shipping_costs_were_not_calculated_correctly'));
+ }
+
+ if(Yard::instance('shopping')->getNumComp() != $shipping_price->num_comp){
+ $identifier = 'error-'.time().mt_rand(1000000, 9999999);
+ Yard::instance('shopping')->store($identifier);
+ $data['user_id'] = Auth::user()->id;
+ $data['shopping_user_id'] = $id;
+ \App\Services\MyLog::writeLog('payment', 'error', 'Yard num_comp is 0 | Yard identifier: '.$identifier, $data);
+ abort(403, __('msg.compensation_products_cannot_be_0'));
+ }
+
}
- return $shopping_user;
}
public function datatable(){
- if(Request::get('shipping_is_for') === 'me'){
- // $query = Product::with('product_buyings')->select('products.*')->where('active', true)->whereJsonContains('show_on', '2');
-
+ if(Request::get('shipping_is_for') === 'me' || Request::get('shipping_is_for') === 'abo-me'){
+ $show_on = Request::get('is_abo') ? '12' : '2';
$query = Product::with('product_buyings')
->select('products.*')->where('products.active', true)
- ->whereJsonContains('products.show_on', '2')
+ ->whereJsonContains('products.show_on', $show_on)
->whereDoesntHave('product_buyings', function ($q){
$q->where('product_buyings.user_id', '=', \Auth::user()->id);
});
}else{
- $query = Product::select('products.*')->where('active', true)->whereJsonContains('show_on', '3');
+ $show_on = Request::get('is_abo') ? '13' : '3';
+ $query = Product::select('products.*')->where('active', true)->whereJsonContains('show_on', $show_on);
}
return \DataTables::eloquent($query)
@@ -306,7 +394,7 @@ class OrderController extends Controller
$cartItem = Yard::instance('shopping')->getCartItemByProduct($product->id);
$qty = isset($cartItem->qty) ? $cartItem->qty : 0;
$rowId = isset($cartItem->rowId) ? $cartItem->rowId : '';
- return ''.$product->name.'
+ return ''.$product->getLang('name').'
@@ -358,6 +446,15 @@ class OrderController extends Controller
->addColumn('price_vk_gross', function (Product $product) {
return ''.$product->getFormattedPriceWith(false, false, Yard::instance('shopping')->getUserCountry()). " €".''.$product->getFormattedPriceCurrencyWith(false, false, Yard::instance('shopping')->getUserCountry()).'';
})
+ ->addColumn('customer_price_net', function (Product $product) {
+ return ''.$product->getFormattedPriceWith(true, false, Yard::instance('shopping')->getUserCountry()). " €".''.$product->getFormattedPriceCurrencyWith(true, false, Yard::instance('shopping')->getUserCountry()).'';
+ })
+ ->addColumn('customer_price_gross', function (Product $product) {
+ return ''.$product->getFormattedPriceWith(false, false, Yard::instance('shopping')->getUserCountry()). " €".''.$product->getFormattedPriceCurrencyWith(false, false, Yard::instance('shopping')->getUserCountry()).'';
+ })
+ ->addColumn('my_commission_net', function (Product $product) {
+ return ''.$product->getFormattedPriceWith(true, false, Yard::instance('shopping')->getUserCountry(), true). " €".''.$product->getFormattedPriceCurrencyWith(true, false, Yard::instance('shopping')->getUserCountry(), true).'';
+ })
->addColumn('action', function (Product $product) {
return '';
+ data-route="'.route('modal_load').'">';
})
->addColumn('api_status', function (ShoppingOrder $ShoppingOrder) {
if($ShoppingOrder->api_status === 2){
diff --git a/app/Http/Controllers/User/TeamController.php b/app/Http/Controllers/User/TeamController.php
index be68a7b3..dedb1d2c 100755
--- a/app/Http/Controllers/User/TeamController.php
+++ b/app/Http/Controllers/User/TeamController.php
@@ -13,6 +13,8 @@ use Maatwebsite\Excel\Facades\Excel;
use App\Services\BusinessPlan\ExportBot;
use App\Services\BusinessPlan\TreeCalcBot;
+use function Ramsey\Uuid\v1;
+
class TeamController extends Controller
{
@@ -45,7 +47,7 @@ class TeamController extends Controller
//for testing
//$TreeCalcBot->initUser(56);
$data = [
- 'filter_months' => HTMLHelper::$months,
+ 'filter_months' => HTMLHelper::getTransMonths(),
'filter_years' => HTMLHelper::getYearRange(2022),
'TreeCalcBot' => $TreeCalcBot,
];
@@ -59,7 +61,7 @@ class TeamController extends Controller
$userSalesVolume = $user->getUserSalesVolume(intval(session('team_user_points_filter_month')), intval(session('team_user_points_filter_year')), 'first');
$data = [
'userSalesVolume' => $userSalesVolume,
- 'filter_months' => HTMLHelper::$months,
+ 'filter_months' => HTMLHelper::getTransMonths(),
'filter_years' => HTMLHelper::getYearRange(2022),
];
return view('user.team.points', $data);
@@ -69,6 +71,9 @@ class TeamController extends Controller
{
$user = User::find(\Auth::user()->id);
+ if(!$user->isVIP()){
+ abort(404);
+ }
$ExportBot = new ExportBot('member');
$ExportBot->initStructureUser($user, 'list'); //tree or list
$data = [
@@ -84,44 +89,44 @@ class TeamController extends Controller
$ExportBot = new ExportBot('member');
$ExportBot->initStructureUser($user, 'list'); //tree or list
$columns = [];
- $filename = "mivita-mein-team-export-".date('Y-m-d-H-i-s');
+ $filename = __('team.filename_export').date('Y-m-d-H-i-s');
$headers = array(
- 'Line',
- 'Level',
- 'E-Mail',
- 'Vorname',
- 'Nachname',
- 'Adresse',
- 'Zusatz',
- 'PLZ',
- 'Ort',
- 'Land',
- 'Tel',
- 'Mobil',
- 'Geburtstag',
- 'Account',
- 'Account bis',
- 'Sponsor',
+ __('tables.line'),
+ __('tables.level'),
+ __('tables.email'),
+ __('tables.firstname'),
+ __('tables.lastname'),
+ __('tables.address'),
+ __('tables.addition'),
+ __('tables.postcode'),
+ __('tables.city'),
+ __('tables.country'),
+ __('tables.phone'),
+ __('tables.mobil'),
+ __('tables.birthday'),
+ __('tables.account'),
+ __('tables.account_to'),
+ __('tables.sponsor'),
);
if(isset($ExportBot->user_list->childs)){
foreach ($ExportBot->user_list->childs as $child){
$columns[] = array(
- 'Line' => $child->line,
- 'Level' => $child->level_name,
- 'E-Mail' => $child->email,
- 'Vorname' => $child->first_name,
- 'Nachname' => $child->last_name,
- 'Adresse' => $child->address,
- 'Zusatz' => $child->address_2,
- 'PLZ' => $child->zipcode,
- 'Ort' => $child->city,
- 'Land' => $child->country_id,
- 'Tel' => $child->phone,
- 'Mobil' => $child->mobil,
- 'Geburtstag' => $child->birthday,
- 'Account' => ($child->active_account == 1 ? 'JA' : 'NEIN'),
- 'Account bis' => $child->payment_account_date,
- 'Sponsor' => $child->sponsor_name,
+ __('tables.line') => $child->line,
+ __('tables.level') => $child->level_name,
+ __('tables.email') => $child->email,
+ __('tables.firstname') => $child->first_name,
+ __('tables.lastname') => $child->last_name,
+ __('tables.address') => $child->address,
+ __('tables.addition') => $child->address_2,
+ __('tables.postcode') => $child->zipcode,
+ __('tables.city') => $child->city,
+ __('tables.country') => $child->country_id,
+ __('tables.phone') => $child->phone,
+ __('tables.mobil') => $child->mobil,
+ __('tables.birthday') => $child->birthday,
+ __('tables.account') => ($child->active_account == 1 ? __('yes') : __('no')),
+ __('tables.account_to') => $child->payment_account_date,
+ __('tables.sponsor') => $child->sponsor_name,
);
}
}
@@ -192,7 +197,9 @@ class TeamController extends Controller
->addColumn('total_net', function (UserSalesVolume $UserSalesVolume) {
return formatNumber($UserSalesVolume->total_net).' €';
})
-
+ ->addColumn('status_turnover', function (UserSalesVolume $UserSalesVolume) {
+ return ''.$UserSalesVolume->getStatusTurnoverType().'';
+ })
->addColumn('status', function (UserSalesVolume $UserSalesVolume) {
return ''.$UserSalesVolume->getStatusType().'';
})
@@ -209,7 +216,7 @@ class TeamController extends Controller
->orderColumn('message', 'message $1')
->orderColumn('info', 'info $1')
- ->rawColumns(['id', 'order', 'status', 'message', 'info', 'total_net'])
+ ->rawColumns(['id', 'order', 'status_turnover', 'status', 'message', 'info', 'total_net'])
->make(true);
}
diff --git a/app/Http/Controllers/UserDataController.php b/app/Http/Controllers/UserDataController.php
index 24702c4f..1a7cf783 100755
--- a/app/Http/Controllers/UserDataController.php
+++ b/app/Http/Controllers/UserDataController.php
@@ -47,13 +47,13 @@ class UserDataController extends Controller
}*/
$data = Request::all();
- if(isset($data['reverse_charge_validate'])){
- return $this->userRepo->reverse_charge_validate($data, $user);
- }
-
- if(isset($data['reverse_charge_delete'])){
- return $this->userRepo->reverse_charge_delete($data, $user);
+ if(isset($data['action']) && $data['action'] == "reverse_charge_validate"){
+ return $this->userRepo->reverse_charge_validate($data, $user, route('user_edit', [$user->id]));
}
+
+ if(isset($data['action']) && $data['action'] == "reverse_charge_delete"){
+ return $this->userRepo->reverse_charge_delete($data, $user, route('user_edit', [$user->id]));
+ }
$rules = array(
'salutation' => 'required',
diff --git a/app/Http/Controllers/UserShopController.php b/app/Http/Controllers/UserShopController.php
index b8a9a6c3..b492cb89 100755
--- a/app/Http/Controllers/UserShopController.php
+++ b/app/Http/Controllers/UserShopController.php
@@ -35,10 +35,9 @@ class UserShopController extends Controller
if ($user->account) {
$user->shop->contact = $this->generate_contact($user);
} else {
- $user->shop->contact = "Deine Straße/Nr • Dein PLZ Ort\nFestnetz: Deine Festnetz-Nummer\nMobil: Deine Mobil-Nummer\nDeine E-Mail-Adresse";
+ $user->shop->contact = __('shop.shop_contact_text');
}
-
- $user->shop->accessibility = "Mo-Fr: 9.00 - 19.00 Uhr\nSa-So: 11.00 - 18.00 Uhr";
+ $user->shop->accessibility =__('shop.shop_accessibility_text');
}
$data = [
@@ -48,6 +47,33 @@ class UserShopController extends Controller
}
+ public function translate()
+ {
+ $user = Auth::user();
+ $data = [
+ 'user' => $user,
+ 'localizations' => array_keys(config('localization.supportedLocales')),
+
+ ];
+ return view('user.shop.translate', $data);
+
+ }
+
+ public function translateStore()
+ {
+ $user = Auth::user();
+ $data = Request::all();
+
+ if (!$user->shop) {
+ abort(404);
+ }
+ foreach($data['trans'] as $lang => $val){
+ $this->storeTranslations($user->shop, $lang, $val);
+ }
+ \Session()->flash('alert-save', true);
+ return redirect(route('user_shop_translate'));
+ }
+
public function store()
{
$user = Auth::user();
@@ -57,35 +83,51 @@ class UserShopController extends Controller
abort(404);
}
$user->shop->title = $data['title'];
- $user->shop->contact = trim(preg_replace('/\s*\n+/',"\n", $data['contact']));
- $user->shop->accessibility = trim(preg_replace('/\s*\n+/',"\n", $data['accessibility']));
- $user->shop->about = trim(preg_replace('/\s+/', ' ',$data['about']));
$user->shop->active = isset($data['active']) ? true : false;
$user->shop->set_defaults = true;
$user->shop->save();
+ $this->storeTranslations($user->shop, \App::getLocale(), $data);
\Session()->flash('alert-save', true);
return redirect(route('user_shop'));
}
+ private function storeTranslations($user_shop, $lang, $data){
+
+ if($lang == 'de'){
+ $user_shop->contact = trim(preg_replace('/\s*\n+/',"\n", $data['contact']));
+ $user_shop->accessibility = trim(preg_replace('/\s*\n+/',"\n", $data['accessibility']));
+ $user_shop->about = trim(preg_replace('/\s+/', ' ',$data['about']));
+ $user_shop->save();
+ return;
+ }
+ $trans = $user_shop->trans;
+ $trans[$lang]['contact'] = trim(preg_replace('/\s*\n+/',"\n", $data['contact']));
+ $trans[$lang]['accessibility'] = trim(preg_replace('/\s*\n+/',"\n", $data['accessibility']));
+ $trans[$lang]['about'] = trim(preg_replace('/\s+/', ' ',$data['about']));
+ $user_shop->trans = $trans;
+ $user_shop->save();
+ return;
+ }
+
private function generate_contact($user)
{
$ret = "";
$sep = "\n";
- $ret = $user->account->street != "" ? $user->account->street : "Deine Straße/Nr";
+ $ret = $user->account->street != "" ? $user->account->street : __('shop.your_street_number');
$ret .= " • ";
- $ret.= $user->account->postal_code != "" ? $user->account->postal_code." " : "Dein PLZ ";
- $ret.= $user->account->city != "" ? $user->account->city : "Dein Ort";
+ $ret.= $user->account->postal_code != "" ? $user->account->postal_code." " : __('shop.your_zip_code');
+ $ret.= $user->account->city != "" ? $user->account->city : __('shop.your_city');
$ret.= $sep;
$pre = $user->account->pre_phone_id != "" ? $user->account->pre_phone->phone." " : "";
- $ret.= "Festnetz: ".($user->account->phone != "" ? $pre.$user->account->phone : "Deine Festnetz-Nummer");
+ $ret.= __('shop.phone').": ".($user->account->phone != "" ? $pre.$user->account->phone : __('shop.your_phone_number'));
$ret.= $sep;
$pre = $user->account->pre_mobil_id != "" ? $user->account->pre_mobil->phone." " : "";
- $ret.= "Mobil: ".($user->account->mobil != "" ? $pre.$user->account->mobil : "Deine Mobil-Nummer");
+ $ret.= __('shop.mobil').": ".($user->account->mobil != "" ? $pre.$user->account->mobil : __('shop.your_mobile_number'));
$ret.= $sep;
$ret.= $user->email;
@@ -138,15 +180,15 @@ class UserShopController extends Controller
- \Session()->flash('alert-success', "Datei hochgeladen");
+ \Session()->flash('alert-success', __('msg.file_uploaded'));
return redirect(route('user_shop'));
}
- \Session()->flash('alert-danger', "Datei leer");
+ \Session()->flash('alert-danger', __('msg.file_empty'));
return redirect(route('user_shop'));
}
catch (\Exception $e) {
- \Session()->flash('alert-danger', "Fehler".$e);
+ \Session()->flash('alert-danger', "Error: ".$e);
return redirect(route('user_shop'));
}
}
@@ -170,11 +212,11 @@ class UserShopController extends Controller
$user->shop->size = null;
$user->shop->save();
- \Session()->flash('alert-success', "Datei gelöscht");
+ \Session()->flash('alert-success', __('msg.file_deleted'));
return redirect(route('user_shop'));
}
- \Session()->flash('alert-danger', "Datei nicht gefunden");
+ \Session()->flash('alert-danger', __('msg.file_not_found'));
return redirect(route('user_shop'));
}
@@ -223,15 +265,15 @@ class UserShopController extends Controller
'size' => $image['input']['size']
]);
- \Session()->flash('alert-success', "Datei hochgeladen");
+ \Session()->flash('alert-success', __('msg.file_uploaded'));
return redirect(route('user_shop'));
}
- \Session()->flash('alert-danger', "Datei leer");
+ \Session()->flash('alert-danger', __('msg.file_empty'));
return redirect(route('user_shop'));
}
catch (\Exception $e) {
- \Session()->flash('alert-danger', "Fehler".$e);
+ \Session()->flash('alert-danger', "Error: ".$e);
return redirect(route('user_shop'));
}
}
@@ -250,11 +292,11 @@ class UserShopController extends Controller
$image->delete();
- \Session()->flash('alert-success', "Datei gelöscht");
+ \Session()->flash('alert-success', __('msg.file_deleted'));
return redirect(route('user_shop'));
}
- \Session()->flash('alert-danger', "Datei nicht gefunden");
+ \Session()->flash('alert-danger', __('msg.file_not_found'));
return redirect(route('user_shop'));
}
@@ -345,9 +387,12 @@ class UserShopController extends Controller
//check if exisist
$subdomains = $kas->action('get_subdomains');
foreach ($subdomains as $subdomain){
+ if(!isset($subdomain['subdomain_name'])){
+ continue;
+ }
$sub = str_replace(".".$domain, '', $subdomain['subdomain_name']);
if($sub == $slug){
- return ['success' => false, 'error' => 'Fehler: Subdomain existierts bereits, bitte einen neues Namen wählen'];
+ return ['success' => false, 'error' => __('shop.error_subdomain_exists')];
}
}
//add
@@ -356,7 +401,7 @@ class UserShopController extends Controller
'subdomain_name' => $slug,
'domain_name' => $domain,
'subdomain_path' => '/mein.mivita.care/public/',
- 'php_version' => '7.3',
+ 'php_version' => config('app.php_version'),
//'ssl_proxy' => 'Y',
//'redirect_status' => 0
);
diff --git a/app/Http/Controllers/UserUpdateEmailController.php b/app/Http/Controllers/UserUpdateEmailController.php
index 6db4c767..211698a7 100755
--- a/app/Http/Controllers/UserUpdateEmailController.php
+++ b/app/Http/Controllers/UserUpdateEmailController.php
@@ -146,7 +146,7 @@ class UserUpdateEmailController extends Controller
public function sendActivationMail($user, array $data)
{
$token = $this->createActivation($user, $data);
- Mail::to($data['email'])->send(new MailActivateUser($token, $user));
+ Mail::to($data['email'])->locale($user->getLocale())->send(new MailActivateUser($token, $user));
}
diff --git a/app/Http/Controllers/Web/CardController.php b/app/Http/Controllers/Web/CardController.php
index e2d35a4d..fb55deb3 100755
--- a/app/Http/Controllers/Web/CardController.php
+++ b/app/Http/Controllers/Web/CardController.php
@@ -33,7 +33,10 @@ class CardController extends Controller
if($product->images->count()){
$image = $product->images->first()->slug;
}
- $cartItem = Yard::instance('shopping')->add($product->id, $product->getLang('name'), $quantity, $product->getPriceWith(Yard::instance('shopping')->getUserTaxFree(), false, Yard::instance('shopping')->getUserCountry()), false, false, ['image' => $image, 'slug' => $product->slug, 'weight' => $product->weight, 'points' => $product->points, 'no_commission' => $product->no_commission, 'no_free_shipping' => $product->no_free_shipping]);
+ $cartItem = Yard::instance('shopping')
+ ->add($product->id, $product->getLang('name'), $quantity,
+ $product->getPriceWith(Yard::instance('shopping')->getUserTaxFree(), false, Yard::instance('shopping')->getUserCountry()), false, false,
+ ['image' => $image, 'slug' => $product->slug, 'weight' => $product->weight, 'points' => $product->points, 'no_commission' => $product->no_commission, 'no_free_shipping' => $product->no_free_shipping]);
if(Yard::instance('shopping')->getUserTaxFree()){
Yard::setTax($cartItem->rowId, 0);
}else{
@@ -59,7 +62,10 @@ class CardController extends Controller
$image = $product->images->first()->slug;
}
$quantity = Request::get('quantity') ? Request::get('quantity') : 1;
- $cartItem = Yard::instance('shopping')->add($product->id, $product->getLang('name'), $quantity, $product->getPriceWith(Yard::instance('shopping')->getUserTaxFree(), false, Yard::instance('shopping')->getUserCountry()), false, false, ['image' => $image, 'slug' => $product->slug, 'weight' => $product->weight, 'points' => $product->points, 'no_commission' => $product->no_commission, 'no_free_shipping' => $product->no_free_shipping]);
+ $cartItem = Yard::instance('shopping')
+ ->add($product->id, $product->getLang('name'), $quantity,
+ $product->getPriceWith(Yard::instance('shopping')->getUserTaxFree(), false, Yard::instance('shopping')->getUserCountry()), false, false,
+ ['image' => $image, 'slug' => $product->slug, 'weight' => $product->weight, 'points' => $product->points, 'no_commission' => $product->no_commission, 'no_free_shipping' => $product->no_free_shipping]);
if(Yard::instance('shopping')->getUserTaxFree()){
Yard::setTax($cartItem->rowId, 0);
}else{
@@ -117,17 +123,18 @@ class CardController extends Controller
$data['is_from'] = 'shopping';
$data['user_price_infos'] = Yard::instance('shopping')->getUserPriceInfos();
-
ShoppingInstance::create([
'identifier' => $identifier,
'user_shop_id' => $user_shop->id,
- 'payment' => 1,
+ 'payment' => 1, //Customer Shop Payment
'subdomain' => url('/'),
'country_id' => Yard::instance('shopping')->getShippingCountryId(),
+ 'language' => \App::getLocale(),
'shopping_data' => $data,
'back' => url()->previous(),
]);
+
Yard::instance('shopping')->store($identifier);
//add to DB
$path = route('checkout.checkout_card', ['identifier'=>$identifier]);
diff --git a/app/Http/Controllers/Web/CheckoutController.php b/app/Http/Controllers/Web/CheckoutController.php
index 432c1304..c2fbc928 100755
--- a/app/Http/Controllers/Web/CheckoutController.php
+++ b/app/Http/Controllers/Web/CheckoutController.php
@@ -11,6 +11,7 @@ use App\Services\Shop;
use App\Services\Util;
use App\Models\Homeparty;
use App\Services\Payment;
+use App\Services\AboHelper;
use App\Models\ShoppingUser;
use App\Models\PaymentMethod;
use App\Models\ShoppingOrder;
@@ -49,23 +50,19 @@ class CheckoutController extends Controller
$is_from = isset($shopping_data['is_from']) ? $shopping_data['is_from'] : 'shopping';
$is_for = isset($shopping_data['is_for']) ? $shopping_data['is_for'] : false;
+ $is_abo = isset($shopping_data['is_abo']) ? (bool) $shopping_data['is_abo'] : false;
+ $abo_interval = isset($shopping_data['abo_interval']) ? $shopping_data['abo_interval'] : 0;
+ if($is_for === 'ot-customer' || $is_for === 'abo-ot-customer'){
+ $is_from = 'shopping';
+ }
$homeparty_id = isset($shopping_data['homeparty_id']) ? $shopping_data['homeparty_id'] : null;
$shopping_user = null;
- /*if(!$this->getPayments('shopping_user_id') && Util::getAuthUser()){//$is_from !== 'shopping' && ){ //
-
- $shopping_user = $this->shoppingUserAuthData($is_from, $is_for, $shopping_data);
- // $shopping_user->save();
- // $this->putPayments('shopping_user_id', $shopping_user->id);
-
- }else{
- $shopping_user = ShoppingUser::findOrNew($this->getPayments('shopping_user_id'));
- }*/
if(\Session::has('new_session')){
$this->destroy();
\Session::forget('new_session');
}
-
+
if(!$this->getPayments('shopping_user_id')){
if($shopping_data && $is_from !== 'shopping'){
//can wizard membership user_order
@@ -73,12 +70,19 @@ class CheckoutController extends Controller
$shopping_user = $this->shoppingUserAuthData($is_from, $is_for, $shopping_data);
$shopping_user->save();
$this->putPayments('shopping_user_id', $shopping_user->id);
- }elseif($is_from === 'shopping') {
+ }elseif($is_from === 'shopping' && ($is_for !== 'ot-customer' || $is_for !== 'abo-ot-customer')){
$shopping_user = new ShoppingUser();
$shopping_user->is_for = $is_for;
$shopping_user->is_from = $is_from;
$shopping_user->homeparty_id = $homeparty_id;
$shopping_user->mode = 'prev';
+ $shopping_user->language = \App::getLocale();
+ }elseif($is_from === 'shopping' && ($is_for === 'ot-customer' || $is_for === 'abo-ot-customer')){
+ $shopping_user = $this->makeCustomerShoppingUser($shopping_data);
+ $shopping_user->is_for = $is_for;
+ $shopping_user->is_from = $is_from;
+ $shopping_user->mode = 'prev';
+ $shopping_user->language = \App::getLocale();
}
}else{
$shopping_user = ShoppingUser::findOrFail($this->getPayments('shopping_user_id'));
@@ -105,16 +109,12 @@ class CheckoutController extends Controller
$shopping_user->billing_state = Yard::instance('shopping')->getShippingCountryId();
$shopping_user->shipping_state = Yard::instance('shopping')->getShippingCountryId();
}
-
- if(Util::getAuthUser()){
- $shopping_user->abo_options = Util::getUserHistoryValue('abo_options');
- //$shopping_user->save();
- }
-
- $payment_methods = $this->getPaymentsMethods($is_from);
+ $payment_methods = $this->getPaymentsMethods($is_from, $is_abo);
$data = [
'is_from' => $is_from,
'is_for' => $is_for,
+ 'is_abo' => $is_abo,
+ 'abo_interval' => $abo_interval,
'shopping_data' => $shopping_data,
'user_shop' => Util::getUserShop(),
'shopping_user' => $shopping_user,
@@ -126,24 +126,27 @@ class CheckoutController extends Controller
return view('web.templates.checkout', $data);
}
- private function getPaymentsMethods($is_from){
+ private function getPaymentsMethods($is_from, $is_abo = false){
$payment_methods = [];
if($is_from !== 'shopping' && Util::getAuthUser()){
$user = Util::getAuthUser();
$payment_methods['default'] = $user->payment_methods;
$payment_methods['data'] = $user->account->payment_data;
}else{
- $payment_methods['default'] = PaymentMethod::getDefaultAsArray()->toArray();
+ $payment_methods['default'] = PaymentMethod::getDefaultAsArray($is_abo)->toArray();
$payment_methods['data'] = false;
}
-
- $payment_methods['active'] = \App\Models\PaymentMethod::where('active', true)->get()->pluck( 'id', 'short')->toArray();
+ if($is_abo){
+ $payment_methods['active'] = \App\Models\PaymentMethod::where('active', true)->where('is_abo', true)->get()->pluck( 'id', 'short')->toArray();
+ }else{
+ $payment_methods['active'] = \App\Models\PaymentMethod::where('active', true)->get()->pluck( 'id', 'short')->toArray();
+ }
return $payment_methods;
}
- private function isPaymentsMethodsActive($payment_method, $is_from){
+ private function isPaymentsMethodsActive($payment_method, $is_from, $is_abo = false){
$payment_names = ['wlt#PPE' => 'PP', 'cc' => 'CC', 'sb#PNT' => 'SB', 'elv' => 'SEPA', 'vor' => 'VOR', 'fnc#MIV' => 'FNC'];
- $payment_methods = $this->getPaymentsMethods($is_from);
+ $payment_methods = $this->getPaymentsMethods($is_from, $is_abo);
if(isset($payment_names[$payment_method])){
$payment_with = $payment_names[$payment_method];
if(array_key_exists($payment_with, $payment_methods['active']) && in_array($payment_methods['active'][$payment_with], $payment_methods['default'])){
@@ -159,7 +162,8 @@ class CheckoutController extends Controller
$shopping_user = new ShoppingUser();
$shopping_user->auth_user_id = $user->id;
$shopping_user->mode = 'prev';
-
+ $shopping_user->language = \App::getLocale();
+
$shopping_user->billing_salutation = $user->account->salutation;
$shopping_user->billing_company = $user->account->company;
$shopping_user->billing_firstname = $user->account->first_name;
@@ -182,7 +186,7 @@ class CheckoutController extends Controller
//Lieferadresse
if($is_from === 'user_order'){
- if(isset($data['shopping_user_id']) && $data['is_for'] === 'ot'){
+ if(isset($data['shopping_user_id']) && strpos($data['is_for'], 'ot') !== false){
$s_user = ShoppingUser::findOrFail($data['shopping_user_id']);
/* $shopping_user->billing_salutation = $s_user->billing_salutation;
$shopping_user->billing_company = $s_user->billing_company;
@@ -236,7 +240,7 @@ class CheckoutController extends Controller
$data = Request::all();
if(isset($data['payment_method'])){
- $this->isPaymentsMethodsActive($data['payment_method'], $data['is_from']);
+ $this->isPaymentsMethodsActive($data['payment_method'], $data['is_from'], $data['is_abo']);
}
//change selected Country
@@ -280,7 +284,15 @@ class CheckoutController extends Controller
$shopping_user = $this->makeShoppingUser($data);
//make Order and Items
- $shopping_order = $this->makeShoppingOrder($shopping_user);
+ $shopping_order = $this->makeShoppingOrder($shopping_user, $data);
+
+ //delete session
+ if(\Session::has('user_shop_payment') && \Session::get('user_shop_payment') === 6){
+ $user_shop_identifier = \Session::get('user_shop_identifier');
+ Yard::instance('shopping')->deleteStoredCart($user_shop_identifier);
+ \App\Models\ShoppingInstance::where('identifier', $user_shop_identifier)->delete();
+ }
+
//CustomerPriority
if($shopping_user->is_from === 'shopping'){
$ret = CustomerPriority::checkOne(ShoppingUser::find($shopping_user->id), true);
@@ -390,7 +402,6 @@ class CheckoutController extends Controller
if(!$ShoppingPayment){
//TODO log this
Util::setUserHistoryValue(['status'=>21]);
-
\Session::flash('checkout-error', 'Der Zahlungsvorgang konnte nicht abgeschlossen werden, die Zahlung wurde nicht gefunden: '.$reference);
return redirect(route('checkout.checkout_card'));
}
@@ -402,10 +413,8 @@ class CheckoutController extends Controller
Yard::instance('shopping')->destroy();
$this->destroy();
-
-
$payt = $ShoppingPayment->payment_transactions->last();
-
+ AboHelper::createNewAbo($ShoppingPayment);
$data = [
'user_shop' => Util::getUserShop(),
'order_reference' => $reference,
@@ -483,7 +492,22 @@ class CheckoutController extends Controller
return $shopping_user;
}
- private function makeShoppingOrder($shopping_user){
+ private function makeCustomerShoppingUser($shopping_data){
+ // $shopping_user = ShoppingUser::findOrFail($shopping_data['shopping_user_id']);
+ $shopping_user = new ShoppingUser();
+ $shopping_user->fill($shopping_data);
+ $shopping_user->faker_mail = false;
+
+ $shopping_user->auth_user_id = null;
+ $shopping_user->homeparty_id = null;
+ $shopping_user->same_as_billing = $shopping_user->same_as_billing ? false : true; //reinvert
+ // $shopping_user->id = null;
+ $shopping_user->accepted_data_checkbox = 1;
+
+ return $shopping_user;
+
+ }
+ private function makeShoppingOrder($shopping_user, $data){
$user_shop = Util::getUserShop();
@@ -496,6 +520,7 @@ class CheckoutController extends Controller
'shopping_user_id' => $shopping_user->id,
'auth_user_id' => $shopping_user->auth_user_id,
'country_id' => Yard::instance('shopping')->getShippingCountryId(),
+ 'language' => \App::getLocale(),
'user_shop_id' => $user_shop->id,
'payment_for' => $shopping_user->getOrderPaymentFor(),
'homeparty_id' => $shopping_user->homeparty_id,
@@ -520,6 +545,7 @@ class CheckoutController extends Controller
'shopping_user_id' => $shopping_user->id,
'auth_user_id' => $shopping_user->auth_user_id,
'country_id' => Yard::instance('shopping')->getShippingCountryId(),
+ 'language' => \App::getLocale(),
'user_shop_id' => $user_shop->id,
'payment_for' => $shopping_user->getOrderPaymentFor(),
'total' => $total,
@@ -540,6 +566,7 @@ class CheckoutController extends Controller
'shopping_user_id' => $shopping_user->id,
'auth_user_id' => $shopping_user->auth_user_id,
'country_id' => Yard::instance('shopping')->getShippingCountryId(),
+ 'language' => \App::getLocale(),
'user_shop_id' => $user_shop->id,
'payment_for' => $shopping_user->getOrderPaymentFor(),
'total' => Yard::instance('shopping')->total(2, '.', ''),
@@ -551,6 +578,8 @@ class CheckoutController extends Controller
'total_shipping' => Yard::instance('shopping')->totalWithShipping(2, '.', ''),
'points' => Yard::instance('shopping')->points(),
'weight' => Yard::instance('shopping')->weight(),
+ 'is_abo' => isset($data['is_abo']) ? $data['is_abo'] : false,
+ 'abo_interval' => isset($data['abo_interval']) ? $data['abo_interval'] : null,
'txaction' => 'prev',
'mode' => Util::getUserShoppingMode(),
];
diff --git a/app/Http/Controllers/Web/ContactController.php b/app/Http/Controllers/Web/ContactController.php
index b5bbea39..66da2d52 100755
--- a/app/Http/Controllers/Web/ContactController.php
+++ b/app/Http/Controllers/Web/ContactController.php
@@ -88,9 +88,9 @@ class ContactController extends Controller
$contact_mail = config('app.contact_mail');
if($user_shop){
- Mail::to($contact['email'])->bcc([$user_shop->user->email, $contact_mail])->send(new MailContact($contact));
+ Mail::to($contact['email'])->bcc([$user_shop->user->email, $contact_mail])->locale(\App::getLocale())->send(new MailContact($contact));
}else{
- Mail::to($contact['email'])->bcc($contact_mail)->send(new MailContact($contact));
+ Mail::to($contact['email'])->bcc($contact_mail)->locale(\App::getLocale())->send(new MailContact($contact));
}
$data = [
diff --git a/app/Http/Controllers/Web/HomepartyController.php b/app/Http/Controllers/Web/HomepartyController.php
index 19917a6c..77cfd7c1 100755
--- a/app/Http/Controllers/Web/HomepartyController.php
+++ b/app/Http/Controllers/Web/HomepartyController.php
@@ -33,7 +33,7 @@ class HomepartyController extends Controller
$homeparty = Homeparty::where('token', $token)->where('token_active', true)->first();
if(!$homeparty){
- abort(403, 'Link für die Homeparty wurde nicht gefunden, oder ist nicht mehr aktiv.');
+ abort(403, __('msg.link_for_homeparty_not_found'));
}
$homeparty_user = null;
if($gid){
@@ -45,11 +45,11 @@ class HomepartyController extends Controller
}else{
//no edit
- abort(403, 'Link für die Homeparty wurde nicht gefunden, oder ist nicht mehr aktiv.');
+ abort(403, __('msg.link_for_homeparty_not_found'));
$homeparty_user = HomepartyUser::find($gid);
if(!$homeparty_user || $homeparty_user->homeparty_id !== $homeparty->id){
- abort(403, 'Link für die Homeparty wurde nicht gefunden, oder ist nicht mehr aktiv.');
+ abort(403, __('msg.link_for_homeparty_not_found'));
}
}
}
@@ -70,7 +70,7 @@ class HomepartyController extends Controller
}
$homeparty = Homeparty::where('token', $token)->where('token_active', true)->first();
if(!$homeparty){
- abort(403, 'Link für die Homeparty wurde nicht gefunden, oder ist nicht mehr aktiv.');
+ abort(403, __('msg.link_for_homeparty_not_found'));
}
$rules = array(
@@ -110,15 +110,15 @@ class HomepartyController extends Controller
]);
}else{
//no edit
- abort(403, 'Link für die Homeparty wurde nicht gefunden, oder ist nicht mehr aktiv.');
+ abort(403, __('msg.link_for_homeparty_not_found'));
$homeparty_user = HomepartyUser::find($gid);
if(!$homeparty_user || $homeparty_user->homeparty_id !== $homeparty->id){
- abort(403, 'Link für die Homeparty wurde nicht gefunden, oder ist nicht mehr aktiv.');
+ abort(403, __('msg.link_for_homeparty_not_found'));
}
}
if(!$homeparty_user){
- abort(403, 'Link für die Homeparty wurde nicht gefunden, oder ist nicht mehr aktiv.');
+ abort(403, __('msg.link_for_homeparty_not_found'));
}
$data = Request::all();
diff --git a/app/Http/Controllers/Web/RegisterController.php b/app/Http/Controllers/Web/RegisterController.php
index 23f1d799..a5b03454 100755
--- a/app/Http/Controllers/Web/RegisterController.php
+++ b/app/Http/Controllers/Web/RegisterController.php
@@ -79,7 +79,7 @@ class RegisterController extends Controller
);
Validator::extend('recaptcha', function($attribute, $value, $parameters, $validator) {
- return $this->reCaptcha_validate($attribute, $value, $parameters, $validator);
+ return $this->reCaptcha_validate($attribute, $value, $parameters, $validator);
});
$validator = Validator::make(Request::all(), $rules);
@@ -119,7 +119,7 @@ class RegisterController extends Controller
$user->account->data_protection = now();
$user->account->save();
- Mail::to($user->email)->send(new MailVerifyAccount($confirmation_code, $user));
+ Mail::to($user->email)->locale($user->getLocale())->send(new MailVerifyAccount($confirmation_code, $user));
return redirect('/registrierung/finish');
diff --git a/app/Http/Controllers/Web/SiteController.php b/app/Http/Controllers/Web/SiteController.php
index 084f1436..3d2ebf93 100755
--- a/app/Http/Controllers/Web/SiteController.php
+++ b/app/Http/Controllers/Web/SiteController.php
@@ -18,6 +18,7 @@ class SiteController extends Controller
public function index()
{
+ $this->setIPInfo();
$products = ['aloe-vera-gel-99', 'aloe-vera-saft-500-ml', 'aloe-vera-lippenbalsam'];
// $set_products = ['aloe-vera-cleaner-set', 'aloe-vera-koerper-set', 'aloe-vera-repair-set'];
$set_products = ['aloe-vera-koerper-set', 'baby-set', 'aloe-vera-gel-set'];
@@ -41,6 +42,9 @@ class SiteController extends Controller
$mylangs = Shop::getLangChange();
foreach($mylangs as $code => $country){
if(strtolower($data['change_country_id']) === strtolower($code)){
+ \Session::put('user_init_country', strtolower($code));
+ \Session::forget('user_init_country_options');
+ \Session::put('locale', strtolower($data['change_locale_id']));
Shop::initUserShopLang($country);
return back();
}
@@ -48,8 +52,54 @@ class SiteController extends Controller
}
}
+ private function setIPinfo()
+ {
+ //wurde schon gesetzt //cache
+ $country = strtolower(Shop::getIPDatabaseInfo());
+ if(\Session::has('user_init_country')){
+ return;
+ }
+ if(config('app.ipinfo')){
+ $country = strtolower(Shop::getIPDatabaseInfo());
+ if($country === 'de'){ //$locale de - init AT
+ \Session::put('user_init_country', $country);
+ return;
+ }
+ if($country === 'error'){ //$locale at - init AT
+ $country = 'de';
+ }
+ }else{
+ $country = 'de';
+ }
+
+ //$locale = strtolower(\App::getLocale());
+ //ist default
+
+ //sprache
+ if(array_key_exists($country, \App\Services\UserService::getTransChange())){
+ \Session::put('user_init_country', $country);
+ \Session::put('locale', $country);
+ \App::setLocale($country);
+ }else{
+ //default EN
+ \Session::put('user_init_country', 'de');
+ \Session::put('locale', 'de');
+ \App::setLocale('de');
+ }
+
+ //bestelland / versandland
+ if(array_key_exists($country, Shop::getLangChange())){
+ \Session::put('user_init_country_options', $country);
+ }else{
+ \Session::put('user_init_country_options', 'de');
+ }
+
+ return redirect(route('home'));
+ }
+
public function site($site, $subsite = false, $product_slug = false)
{
+ $this->setIPInfo();
$subsite = trim($subsite, '/');
$product_slug = trim($product_slug, '/');
if($product_slug){
@@ -106,7 +156,7 @@ class SiteController extends Controller
'products' => Product::where('active', true)->whereJsonContains('show_on', '1')->orderBy('pos', 'DESC')->get(),
'product_categories' => false,
'p_count' => Product::where('active', true)->whereJsonContains('show_on', '1')->count(),
- 'headline' => 'Produktwelt',
+ 'headline' => __('website.productworld'),
'headline_image' => false,
];
return view('web.templates.'.$site, $data);
@@ -126,6 +176,4 @@ class SiteController extends Controller
}
return view('web.templates.'.$site, $data);
}
-
-
}
\ No newline at end of file
diff --git a/app/Http/Controllers/WizardController.php b/app/Http/Controllers/WizardController.php
index d958db2d..6b601ee0 100755
--- a/app/Http/Controllers/WizardController.php
+++ b/app/Http/Controllers/WizardController.php
@@ -14,12 +14,15 @@ use App\Models\Product;
use App\Models\UserAccount;
use App\Models\UserHistory;
use App\Services\UserService;
+use App\Mail\MailAccountActive;
use App\Models\ShippingCountry;
use App\Mail\MailReleaseAccount;
use App\Models\ShoppingInstance;
+use App\Mail\MailAutoReleaseAccount;
use App\Repositories\FileRepository;
use App\Repositories\UserRepository;
use Illuminate\Support\Facades\Mail;
+use App\Repositories\ContractPDFRepository;
class WizardController extends Controller
{
@@ -175,12 +178,18 @@ class WizardController extends Controller
if (!Auth::check()) {
return redirect('login');
}
-
$user = User::findOrFail(Auth::user()->id);
if (!$user->account) {
$user->account = new UserAccount();
}
+
+ $data = Request::all();
+ if($step == 7 && Request::get('user_country_id')){
+ $user->account->country_id = Request::get('user_country_id');
+ $user->account->save();
+ return redirect(route('wizard_register', [1]));
+ }
if ($step == 0) {
$rules = array(
'accepted_data_protection' => 'required',
@@ -216,21 +225,21 @@ class WizardController extends Controller
return redirect(route('wizard_register'));
}
if ($step == 1) {
- $data = Request::all();
- if(isset($data['reverse_charge_validate'])){
+ $data = Request::all();
+ if(isset($data['action']) && $data['action'] == "reverse_charge_validate"){
$user->wizard = 1;
$user->save();
$userRepo = new UserRepository($user);
- return $userRepo->reverse_charge_validate($data, $user);
+ return $userRepo->reverse_charge_validate($data, $user, route('wizard_register', [0]));
}
-
- if(isset($data['reverse_charge_delete'])){
+
+ if(isset($data['action']) && $data['action'] == "reverse_charge_delete"){
$user->wizard = 1;
$user->save();
$userRepo = new UserRepository($user);
- return $userRepo->reverse_charge_delete($data, $user);
- }
+ return $userRepo->reverse_charge_delete($data, $user, route('wizard_register', [0]));
+ }
$rules = array(
'salutation' => 'required',
@@ -273,7 +282,7 @@ class WizardController extends Controller
if(Request::get('submit') === 'do'){
if(File::whereUserId($user->id)->whereIdentifier('id_card')->count() == 0){
$validator = Validator::make(Request::all(), []);
- $validator->errors()->add('field', __('Kein Ausweis hinterlegt, bitte erst hochladen.'));
+ $validator->errors()->add('field', __('msg.no_id_card_deposited_please_upload_first'));
$user->wizard = 2;
$user->save();
return redirect(route('wizard_register'))->withErrors($validator)->withInput(Request::all());
@@ -296,7 +305,7 @@ class WizardController extends Controller
if($data['business_license_choose'] === "now"){
if(File::whereUserId($user->id)->whereIdentifier('business_license')->count() == 0){
$validator = Validator::make(Request::all(), []);
- $validator->errors()->add('field', __('Kein Gewerbeschein hinterlegt, bitte erst hochladen.'));
+ $validator->errors()->add('field', __('msg.no_trade_licence_deposited_please_upload_first'));
$user->wizard = 3;
$user->save();
return redirect(route('wizard_register'))->withErrors($validator)->withInput(Request::all());
@@ -308,7 +317,7 @@ class WizardController extends Controller
if($data['business_license_choose'] === "non"){
if(!$data['non_business_license_reason'] || $data['non_business_license_reason'] == ""){
$validator = Validator::make(Request::all(), []);
- $validator->errors()->add('field', __('Bitte gib eine Begründung ein, warum Du keinen Gewerbeschein benötigst.'));
+ $validator->errors()->add('field', __('msg.please_enter_reason_why_you_not_need_trade_licence'));
$user->wizard = 3;
$user->save();
return redirect(route('wizard_register'))->withErrors($validator)->withInput(Request::all());
@@ -331,7 +340,10 @@ class WizardController extends Controller
}
if ($step == 4) {
- $user->wizard = 5;
+
+ return $this->releaseAccount($user);
+ /*
+ $user->wizard = 5; // muss freigeschaltet werden
$user->release_account = now();
UserHistory::create(['user_id' => $user->id, 'action'=>'release_account', 'status'=>0]);
$user->save();
@@ -341,12 +353,56 @@ class WizardController extends Controller
}else{
$mail = config('app.info_mail');
}
- Mail::to($mail)->send(new MailReleaseAccount($user));
+ //Mail zur Freischaltung
+ Mail::to($mail)->locale($user->getLocale())->send(new MailReleaseAccount($user));
- return redirect(route('wizard_register'));
+ //return redirect(route('wizard_register'));
+ */
}
}
+ //auto release account
+ public function releaseAccount($user)
+ {
+
+ $user->m_sponsor = $user->m_sponsor ? $user->m_sponsor : 1;
+ $user->account->m_first_name = $user->account->m_first_name ? $user->account->m_first_name : $user->account->first_name;
+ $user->account->m_last_name = $user->account->m_last_name ? $user->account->m_last_name : $user->account->last_name;
+ $user->account->m_account = UserAccount::withTrashed()->max('m_account') +1;
+ $user->account->save();
+ $user->save();
+ //create PDF
+ $pdf = new ContractPDFRepository($user);
+ $pdf->_set('disk', 'user');
+ $pdf->_set('dir', '/'.$user->id.'/documents/');
+ $pdf->_set('user_id', $user->id);
+ $pdf->_set('identifier', 'contract');
+ $pdf->createContractPDF();
+
+ //set wizard tp payments
+ $user->wizard = 20;
+ $user->active = 1;
+ $user->active_date = now();
+ $user->release_account = now();
+ $user->confirmation_code = null;
+ $user->confirmation_code_to = null;
+ $user->confirmation_code_remider = 0;
+ $user->save();
+
+ //mail with code to user?
+ if($user->isTestMode()){
+ $mail = config('app.info_test_mail');
+ }else{
+ $mail = config('app.info_mail');
+ }
+ Mail::to($mail)->locale($user->getLocale())->send(new MailAutoReleaseAccount($user));
+ UserHistory::create(['user_id' => $user->id, 'action'=>'release_account', 'status'=>0]);
+ Mail::to($user->email)->locale($user->getLocale())->send(new MailAccountActive($user));
+ UserHistory::create(['user_id' => $user->id, 'action'=>'released_completed', 'status'=>0]);
+ \Session()->flash('alert-success', __('msg.account_released'));
+ return redirect(route('wizard_payment'));
+ }
+
public function storeCreate($step = 0)
{
@@ -423,6 +479,24 @@ class WizardController extends Controller
return redirect(route('wizard_create', [12]));
}
if($step == 12){
+
+ $data = Request::all();
+
+ if(isset($data['action']) && $data['action'] == "reverse_charge_validate"){
+ $user->wizard = 12;
+ $user->save();
+ $userRepo = new UserRepository($user);
+ return $userRepo->reverse_charge_validate($data, $user, route('wizard_create', [12]));
+ }
+
+ if(isset($data['action']) && $data['action'] == "reverse_charge_delete"){
+ $user->wizard = 12;
+ $user->save();
+ $userRepo = new UserRepository($user);
+ return $userRepo->reverse_charge_delete($data, $user, route('wizard_create', [12]));
+ }
+
+
$rules = array(
'salutation' => 'required',
'first_name' => 'required',
@@ -477,8 +551,8 @@ class WizardController extends Controller
$product = Product::find(Request::get('switchers-package-wizard'));
$showAboOptions = false;
if(Request::get('abo_options')){
- $showAboOptions = true;
- $user->abo_options = true;
+ $showAboOptions = false; //true Abo Option deaktivert
+ $user->abo_options = false; //true Abo Option deaktivert
$user->save();
}
@@ -538,6 +612,7 @@ class WizardController extends Controller
'payment' => 4, //Berater Wizard
'subdomain' => url('/'),
'country_id' => Yard::instance('shopping')->getShippingCountryId(),
+ 'language' => \App::getLocale(),
'shopping_data' => $data,
'back' => url()->previous(),
@@ -563,7 +638,7 @@ class WizardController extends Controller
//remove file
\Storage::disk('user')->delete($file->dir.$file->filename);
$file->delete();
- \Session()->flash('alert-success', "Datei gelöscht");
+ \Session()->flash('alert-success', __('msg.file_deleted'));
}
return back();
}
diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php
index a8728da2..1ceaf60a 100755
--- a/app/Http/Kernel.php
+++ b/app/Http/Kernel.php
@@ -36,13 +36,16 @@ class Kernel extends HttpKernel
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
- //\App\Http\Middleware\Localization::class,
+ \App\Http\Middleware\Localization::class,
],
-
'api' => [
'throttle:60,1',
'bindings',
],
+ 'admin' => [
+ 'web',
+ 'auth',
+ ]
];
/**
diff --git a/app/Http/Middleware/Checkout.php b/app/Http/Middleware/Checkout.php
index 1ec495d5..f7eb56e9 100755
--- a/app/Http/Middleware/Checkout.php
+++ b/app/Http/Middleware/Checkout.php
@@ -8,6 +8,7 @@ use Closure;
use Auth;
use phpDocumentor\Reflection\DocBlock\Tags\Uses;
use App\Services\Util;
+use Session;
use Yard;
class Checkout
@@ -23,6 +24,10 @@ class Checkout
{
if($shopping_instance = ShoppingInstance::where('identifier', $request->route('identifier'))->first()){
//user shop
+
+ //set Lang
+ \Session::put('locale', $shopping_instance->getLocale());
+ \App::setLocale($shopping_instance->getLocale());
$user_shop = $shopping_instance->user_shop;
if($user_shop && $user_shop->active == 1 && $user_shop->user->isActiveShop()){
Util::setPostRoute('user/');
@@ -42,15 +47,24 @@ class Checkout
\Session::put('new_session', true);
Yard::instance('shopping')->destroy();
//restore yard
- Yard::instance('shopping')->restore($request->route('identifier'));
-
+ if($shopping_instance->payment !== 6){
+ Yard::instance('shopping')->restore($request->route('identifier'));
+ }else{
+ //dont delete shopping instance
+ Yard::instance('shopping')->restore($request->route('identifier'), [], false);
+ }
Yard::instance('shopping')->putYardExtra('user_shop_payment', $shopping_instance->payment);
Yard::instance('shopping')->putYardExtra('shopping_data', $shopping_instance->shopping_data);
- $is_for = isset($shopping_instance->shopping_data['is_for']) ? $shopping_instance->shopping_data['is_for'] : 'ot';
- Yard::instance('shopping')->setShippingCountryWithPrice($shopping_instance->country_id, $is_for);
+ $is_for = isset($shopping_instance->shopping_data['is_for']) ? $shopping_instance->shopping_data['is_for'] : 'ot-member';
Yard::instance('shopping')->setUserPriceInfos($shopping_instance->shopping_data['user_price_infos']);
- ShoppingInstance::where('identifier', $request->route('identifier'))->delete();
+ Yard::instance('shopping')->setShippingCountryWithPrice($shopping_instance->country_id, $is_for);
+
+ if($shopping_instance->payment !== 6){
+ //delete shopping instance
+ ShoppingInstance::where('identifier', $request->route('identifier'))->delete();
+ }
+
$request->route()->forgetParameter('identifier');
return $next($request);
diff --git a/app/Http/Middleware/Localization.php b/app/Http/Middleware/Localization.php
index 39754ffc..413e2982 100755
--- a/app/Http/Middleware/Localization.php
+++ b/app/Http/Middleware/Localization.php
@@ -18,10 +18,10 @@ class Localization
public function handle($request, Closure $next)
{
-
- if ( \Session::has('locale')) {
+ if (\Session::has('locale')) {
\App::setLocale(\Session::get('locale'));
- Carbon::setLocale(\Session::get('locale'));
+ // Carbon::setLocale('\Session::get('locale')');
+ //Carbon::setLocale('de');
}
return $next($request);
diff --git a/app/Libraries/CreditDetailsPDF.php b/app/Libraries/CreditDetailsPDF.php
new file mode 100644
index 00000000..2ac2288a
--- /dev/null
+++ b/app/Libraries/CreditDetailsPDF.php
@@ -0,0 +1,41 @@
+view = $view;
+ }
+
+ public function create($data, $name='test.pdf', $output='stream', $path = false){
+
+ header('Content-type: text/html; charset=UTF-8') ;//chrome
+
+ $pdf = app('dompdf.wrapper');
+ $pdf->getDomPDF()->set_option("enable_php", true);
+ $pdf->loadView($this->view, $data);
+ $pdf->setPaper('A4', 'portrait');
+
+ if($output === 'stream'){
+ return $pdf->stream($name);
+ }
+ if($output === 'download'){
+ return $pdf->download($name);
+ }
+
+ if($output === 'save'){
+ if($path){
+ $pdf->save($path.$name);
+ return $path.$name;
+ }
+ }
+ }
+
+}
+?>
diff --git a/app/Libraries/InvoicePDF.php b/app/Libraries/InvoicePDF.php
index 49180d39..45b5a133 100644
--- a/app/Libraries/InvoicePDF.php
+++ b/app/Libraries/InvoicePDF.php
@@ -22,7 +22,8 @@ class InvoicePDF{
//dd($data);
$pdf = app('dompdf.wrapper');
- $pdf->getDomPDF()->set_option("enable_php", true);
+ $pdf->getDomPDF();
+ $pdf->set_option("enable_php", true);
$pdf->loadView($this->view, $data);
$pdf->setPaper('A4', 'portrait');
diff --git a/app/Libraries/MyPDFMerger.php b/app/Libraries/MyPDFMerger.php
new file mode 100644
index 00000000..ddf9c0fd
--- /dev/null
+++ b/app/Libraries/MyPDFMerger.php
@@ -0,0 +1,188 @@
+_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.
+*/
\ No newline at end of file
diff --git a/app/Mail/Exception.php b/app/Mail/Exception.php
new file mode 100644
index 00000000..71d0f860
--- /dev/null
+++ b/app/Mail/Exception.php
@@ -0,0 +1,38 @@
+css = $css;
+ $this->content = $content;
+
+ }
+ /**
+ * Build the message.
+ *
+ * @return $this
+ */
+ public function build()
+ {
+ return $this->view('emails.exception')
+ ->subject('mivita Exception Logged!')
+ ->with([
+ 'content' => $this->content,
+ 'css' => $this->css,
+
+ ]);
+ }
+}
\ No newline at end of file
diff --git a/app/Mail/ExceptionOccured.php b/app/Mail/ExceptionOccured.php
new file mode 100644
index 00000000..b51e36b0
--- /dev/null
+++ b/app/Mail/ExceptionOccured.php
@@ -0,0 +1,36 @@
+content = $content;
+ }
+
+ /**
+ * Build the message.
+ *
+ * @return $this
+ */
+ public function build()
+ {
+ return $this->view('emails.exception')
+ ->with('content', $this->content);
+ }
+}
\ No newline at end of file
diff --git a/app/Mail/MailAutoReleaseAccount.php b/app/Mail/MailAutoReleaseAccount.php
new file mode 100644
index 00000000..2363137a
--- /dev/null
+++ b/app/Mail/MailAutoReleaseAccount.php
@@ -0,0 +1,62 @@
+user = $user;
+ $this->subject = 'Neuer Berater Registrierung und freigeschaltet';
+ }
+
+
+ public function build()
+ {
+ $content = __(strtoupper($this->user->account->salutation))." ";
+ $content .= $this->user->account->first_name." ".$this->user->account->last_name."\n";
+ $content .= $this->user->account->address."\n";
+ $content .= $this->user->account->zipcode." ".$this->user->account->city."\n";
+ $content .= $this->user->account->country_id ? $this->user->account->country->de."\n\n" : "\n\n";
+ if($this->user->account->phone){
+ $content .= "Telefon: ";
+ $content .= $this->user->account->pre_phone_id ? $this->user->account->pre_phone->phone." " : " ";
+ $content .= $this->user->account->phone;
+ }
+ if($this->user->account->mobil){
+ $content .= "Mobil: ";
+ $content .= $this->user->account->pre_mobil_id ? $this->user->account->pre_mobil->phone." " : " ";
+ $content .= $this->user->account->mobil;
+ }
+ $content .= "E-Mail: ".$this->user->email;
+
+
+ $copy1line = "Ein neuer Berater hat sich registriert und wurde automatisch freigeschaltet. Seine Daten müssen nachträglich Überprüfung werden:"."\n";
+ $copy1line .= "+ Überprüfung der Ausweisdaten"."\n";
+ $copy1line .= "+ Überprüfung des Gewerbenachweises"."\n";
+ $copy1line .= "+ Eintrag Account ID"."\n";
+ $copy1line .= "+ Überprüfung / Kenntnisnahme Sponsor"."\n";
+ $copy1line .= "+ Überprüfung der Rechnungsdaten"."\n";
+ $copy1line .= 'Sollte Daten nicht vollständig sein, bitte Kontakt zum Berater aufnehmen.'."\n";
+
+ return $this->view('emails.info')->with([
+ 'url' => route('admin_lead_edit', $this->user->id).'?show=check_lead',
+ 'title' => 'Berater Registrierung prüfen',
+ 'button' => 'zur Berater Prüfung',
+ 'copy1line' => $copy1line,
+ 'copy2line' => __('email.copy2line'),
+ 'content' => $content,
+ ]);
+ }
+}
\ No newline at end of file
diff --git a/app/Mail/MailCredit.php b/app/Mail/MailCredit.php
index 33507146..7a12c718 100644
--- a/app/Mail/MailCredit.php
+++ b/app/Mail/MailCredit.php
@@ -24,7 +24,7 @@ class MailCredit extends Mailable
public function __construct(UserCredit $user_credit)
{
$this->user_credit = $user_credit;
- $this->subject = 'Deine Gutschrift auf mivita.care';
+ $this->subject = __('email.credit_title');
}
public function build()
diff --git a/app/Mail/MailCustomPaymet.php b/app/Mail/MailCustomPaymet.php
new file mode 100644
index 00000000..e9a8407e
--- /dev/null
+++ b/app/Mail/MailCustomPaymet.php
@@ -0,0 +1,57 @@
+route = $route;
+ $this->shopping_user = $shopping_user;
+ $this->shopping_instance = $shopping_instance;
+ $this->mode = $mode;
+ $this->yard_shopping_items = $yard_shopping_items;
+
+ $this->name = $shopping_user->member->account->first_name." ".$shopping_user->member->account->last_name." - ";
+ $this->subject = __('email.subject_custom_payout', ['name' => $this->name]);
+ }
+
+
+ public function build()
+ {
+ $salutation = __('email.hello')." ".$this->shopping_user->billing_firstname.",";
+
+ return $this->view('emails.custom_payment')->with([
+ 'salutation' => $salutation,
+ 'copy1line' => __('email.your_custom_payout', ['name' => $this->name]),
+ 'shopping_user' => $this->shopping_user,
+ 'shopping_instance' => $this->shopping_instance,
+ 'yard_shopping_items' => $this->yard_shopping_items,
+ 'copy3line' => __('email.checkout_copy3line'),
+ 'greetings' => __('email.greetings'),
+ 'route' => $this->route,
+ 'mode' => $this->mode,
+ 'sender' => __('email.sender'),
+ ]);
+ }
+}
\ No newline at end of file
diff --git a/app/Mail/MailInvoice.php b/app/Mail/MailInvoice.php
index bd147957..3cd17465 100644
--- a/app/Mail/MailInvoice.php
+++ b/app/Mail/MailInvoice.php
@@ -23,8 +23,7 @@ class MailInvoice extends Mailable
{
$this->shopping_order = $shopping_order;
$this->user_invoice = $user_invoice;
- $this->subject = 'Rechnung zu Deiner Bestellung: '.$shopping_order->getLastShoppingPayment('reference') ;
-
+ $this->subject = __('email.invoice_subject').': '.$shopping_order->getLastShoppingPayment('reference') ;
}
public function build()
diff --git a/app/Mail/MailLog.php b/app/Mail/MailLog.php
new file mode 100644
index 00000000..e31a92e0
--- /dev/null
+++ b/app/Mail/MailLog.php
@@ -0,0 +1,63 @@
+channel = $channel;
+ $this->context = $context;
+ $this->message = $message;
+ $this->data = $data;
+ $this->subject = 'mivita Log';
+
+ }
+
+
+ public function build()
+ {
+ $title = 'Log: '.$this->channel.' '.$this->context;
+
+ //make Data readable
+ $this->data = json_encode($this->data, JSON_PRETTY_PRINT);
+ $content = "";
+
+
+ $content .= "\n";
+ $content .= "Channel: ".$this->channel."\n";
+ $content .= "Context: ".$this->context."\n";
+ if(\Auth::check()){
+ $content .= "From User: ".\Auth::user()->id." | ".\Auth::user()->email."\n";
+ }
+ $content .= "\n";
+ $content .= "Message: ".$this->message."\n";
+ $content .= "\n";
+ $content .= "Data: ".$this->data."\n";
+ $content .= "\n";
+ $content .= "\n";
+ $content .= "Time: ".now()->format("d.m.Y H:i");
+ $content .= "\n";
+ $content .= request()->header('User-Agent');
+
+
+ return $this->view('emails.sys')->with([
+ 'title' => $title,
+ 'content' => $content,
+ ]);
+ }
+}
\ No newline at end of file
diff --git a/app/Mail/MailReleaseAccount.php b/app/Mail/MailReleaseAccount.php
index 8a390568..e064716d 100644
--- a/app/Mail/MailReleaseAccount.php
+++ b/app/Mail/MailReleaseAccount.php
@@ -43,7 +43,7 @@ class MailReleaseAccount extends Mailable
$copy1line = "Ein neuer Berater hat sich registriert und wartet auf die Überprüfung und Freigabe seiner Daten:"."\n";
- $copy1line .= "+ Überprüfung der Ausweisdate"."\n";
+ $copy1line .= "+ Überprüfung der Ausweisdaten"."\n";
$copy1line .= "+ Überprüfung des Gewerbenachweises"."\n";
$copy1line .= "+ Eintrag Account ID"."\n";
$copy1line .= "+ Überprüfung / Kenntnisnahme Sponsor"."\n";
diff --git a/app/Mail/MailReleaseDocument.php b/app/Mail/MailReleaseDocument.php
new file mode 100644
index 00000000..565ebaaa
--- /dev/null
+++ b/app/Mail/MailReleaseDocument.php
@@ -0,0 +1,59 @@
+user = $user;
+ $this->subject = 'Berater Unterlagen prüfen';
+ }
+
+ public function build()
+ {
+ $content = __(strtoupper($this->user->account->salutation))." ";
+ $content .= $this->user->account->first_name." ".$this->user->account->last_name."\n";
+ $content .= $this->user->account->address."\n";
+ $content .= $this->user->account->zipcode." ".$this->user->account->city."\n";
+ $content .= $this->user->account->country_id ? $this->user->account->country->de."\n\n" : "\n\n";
+ $content .= "E-Mail: ".$this->user->email;
+
+
+ $copy1line = "Ein Berater hat Daten zum Gewerbenachweis geändert, bitte um Prüfung:"."\n\n";
+
+ $business_license_choose = $this->user->account->getNotice('business_license');
+ if($business_license_choose === 'now'){
+ $copy1line .= "+ Gewerbeschein jetzt zur Freigabe"."\n\n";
+ }
+ if($business_license_choose === 'later'){
+ $copy1line .= "+ Ich reiche meinen Gewerbeschein innerhalb der nächsten 4 Wochen nach"."\n\n";
+ }
+ if($business_license_choose === 'non'){
+ $copy1line .= "+ Ich benötige keinen Gewerbeschein"."\n";
+ $copy1line .= "+ Begründung: ".$this->user->account->getNotice('business_license_reason')."\n\n";
+ }
+
+ $copy1line .= 'Bei fehlerhafter Angabe nimm bitte kontakt mit dem Berater auf.'."\n";
+
+ return $this->view('emails.info')->with([
+ 'url' => route('admin_lead_edit', $this->user->id).'?show=check_lead',
+ 'title' => 'Berater Unterlagen prüfen',
+ 'button' => 'zur Berater Prüfung',
+ 'copy1line' => $copy1line,
+ 'copy2line' => __('email.copy2line'),
+ 'content' => $content,
+ ]);
+ }
+}
\ No newline at end of file
diff --git a/app/Mail/MailUserLevelUpdate.php b/app/Mail/MailUserLevelUpdate.php
index 7d3bac29..74f893e1 100644
--- a/app/Mail/MailUserLevelUpdate.php
+++ b/app/Mail/MailUserLevelUpdate.php
@@ -25,7 +25,7 @@ class MailUserLevelUpdate extends Mailable
$this->team_points = $team_points;
$this->update_to = $update_to;
- $this->subject = 'Deine Karriere-Level auf mivita.care';
+ $this->subject = __('email.update_level_title');
}
public function build()
diff --git a/app/Models/Category.php b/app/Models/Category.php
index a1d15ce4..a61fc67f 100644
--- a/app/Models/Category.php
+++ b/app/Models/Category.php
@@ -45,6 +45,8 @@ use Cviebrock\EloquentSluggable\Sluggable;
* @property-read \App\Models\IqImage|null $iq_image
* @property-read int|null $product_categories_count
* @method static \Illuminate\Database\Eloquent\Builder|Category withUniqueSlugConstraints(\Illuminate\Database\Eloquent\Model $model, string $attribute, array $config, string $slug)
+ * @property-read \Illuminate\Database\Eloquent\Collection $translations
+ * @property-read int|null $translations_count
* @mixin \Eloquent
*/
class Category extends Model
@@ -53,7 +55,6 @@ class Category extends Model
protected $table = 'categories';
- protected $casts = ['trans_name' => 'array', 'trans_headline' => 'array'];
protected $fillable = [
'parent_id', 'name', 'headline', 'pos', 'active',
@@ -84,6 +85,27 @@ class Category extends Model
}
+ public function productCategoriesCountActive()
+ {
+ $category_id = $this->id;
+ return Product::where('active', true)->whereHas('product_categories', function ($query) use ($category_id) {
+ $query->where('category_id', $category_id); //
+ })->orderBy('pos', 'ASC')->count();
+ }
+
+ public function productCategoriesCountActiveOn($show_on = ['1'])
+ {
+ $category_id = $this->id;
+ return Product::where('active', true)->whereJsonContains('show_on', $show_on)
+ ->whereHas('product_categories', function ($query) use ($category_id) {
+ $query->where('category_id', $category_id); //
+ })->orderBy('pos', 'ASC')->count();
+ }
+
+
+
+
+
public function iq_image()
{
return $this->belongsTo('App\Models\IqImage', 'headline_image_id');
@@ -93,44 +115,29 @@ class Category extends Model
$this->attributes['pos'] = is_numeric($value) ? $value : null;
}
- public function getLang($key)
+
+
+ public function translations()
+ {
+ return $this->hasMany(TransCategory::class, 'categorie_id');
+ }
+
+
+ public function getLang($key)
{
$lang = \App::getLocale();
- if ($lang === 'de') {
+ if ($lang == 'de') {
return $this->{$key};
}
$trans = $this->getTrans($key, $lang);
- if (!$trans || $trans == '') {
- return $this->{$key};
- }
- return $trans;
+ return $trans != '' ? $trans : $this->{$key};
}
public function getTrans($key, $lang)
{
- $key = 'trans_' . $key;
- if (!empty($this->{$key}[$lang])) {
- return $this->{$key}[$lang];
- }
- return "";
- }
-
- public function getTranNames()
- {
- $ret = "";
- foreach ((array) $this->trans_name as $value){
- $ret .= $value.', ';
- }
- return rtrim($ret, ', ');
- }
-
- public function getTranHeadlines()
- {
- $ret = "";
- foreach ((array) $this->trans_headline as $value){
- $ret .= $value.', ';
- }
- return rtrim($ret, ', ');
+ $trans = $this->translations->where('language','=', $lang)->where('key', $key)->first();
+ return $trans ? $trans->value : '';
}
+
}
diff --git a/app/Models/Country.php b/app/Models/Country.php
index aaeb5249..1285bda1 100644
--- a/app/Models/Country.php
+++ b/app/Models/Country.php
@@ -37,10 +37,8 @@ use PHPUnit\Framework\Constraint\Count;
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Country whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Country whereTrans($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Country whereUpdatedAt($value)
- * @property string|null $trans_name
* @property array|null $attr
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Country whereAttr($value)
- * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Country whereTransName($value)
* @property bool|null $switch
* @property bool|null $own_eur
* @property bool|null $currency
@@ -60,6 +58,8 @@ use PHPUnit\Framework\Constraint\Count;
* @property bool|null $supply_country
* @method static \Illuminate\Database\Eloquent\Builder|Country whereEuCountry($value)
* @method static \Illuminate\Database\Eloquent\Builder|Country whereSupplyCountry($value)
+ * @property bool|null $translate
+ * @method static \Illuminate\Database\Eloquent\Builder|Country whereTranslate($value)
* @mixin \Eloquent
*/
class Country extends Model
@@ -68,19 +68,19 @@ class Country extends Model
protected $casts = [
'switch' => 'bool',
+ 'translate' => 'bool',
'supply_country' => 'bool',
'eu_country' => 'bool',
'own_eur' => 'bool',
'currency' => 'bool',
'currency_calc' => 'bool',
- 'trans_name' => 'array',
'attr' => 'array'
];
protected $fillable = [
'code', 'phone', 'en', 'de', 'es', 'fr', 'it', 'ru',
- 'supply_country', 'eu_country', 'switch', 'own_eur', 'currency', 'currency_unit', 'currency_calc', 'currency_faktor',
- 'active', 'trans_name', 'attr',
+ 'supply_country', 'eu_country', 'switch', 'translate', 'own_eur', 'currency', 'currency_unit', 'currency_calc', 'currency_faktor',
+ 'active', 'attr',
];
public function country_prices()
@@ -92,7 +92,6 @@ class Country extends Model
if(!$lang){
$lang = \App::getLocale();
-
}
if($lang === 'de'){
return $this->de;
@@ -114,22 +113,10 @@ class Country extends Model
}
//search by trans
-
- if($val = $this->getTrans('name', $lang)){
- return $val;
- }
return $this->de;
}
- public function getTrans($key, $lang)
- {
- $key = 'trans_' . $key;
- if (!empty($this->{$key}[$lang])) {
- return $this->{$key}[$lang];
- }
- return "";
- }
-
+
public function getAttrByKey($key)
{
$name = 'attr';
diff --git a/app/Models/DbipLookup.php b/app/Models/DbipLookup.php
new file mode 100644
index 00000000..dc769ffe
--- /dev/null
+++ b/app/Models/DbipLookup.php
@@ -0,0 +1,33 @@
+ 'int',
+ 'active' => 'bool'
+ ];
+
+ protected $fillable = [
+ 'name',
+ 'pos',
+ 'slug',
+ 'active'
+ ];
+
+ public function sluggable()
+ {
+ return [
+ 'slug' => [
+ 'source' => 'name'
+ ]
+ ];
+ }
+}
diff --git a/app/Models/DcFile.php b/app/Models/DcFile.php
new file mode 100644
index 00000000..81cf0dce
--- /dev/null
+++ b/app/Models/DcFile.php
@@ -0,0 +1,190 @@
+ 'int',
+ 'active' => 'int'
+ ];
+
+ protected $fillable = [
+ 'filename',
+ 'original_name',
+ 'ext',
+ 'mine',
+ 'size',
+ 'active'
+ ];
+
+ public function dc_file_tags()
+ {
+ return $this->hasMany(DcFileTag::class, 'file_id');
+ }
+
+ public function tags(){
+ return $this->belongsToMany(DcTag::class, 'dc_file_tags', 'file_id', 'tag_id');
+ }
+
+ public function fileTag(){
+ return $this->hasMany(DcFileTag::class, 'file_id');
+ }
+
+ public function hasTags()
+ {
+ if($this->fileTag()->count()){
+ return true;
+ }
+ return false;
+ }
+ //path /storage/app/dc/ ...
+ /*public function isImage(){
+ if(empty($this->attributes['filename']) || @$this->attributes['filename'] == null || @$this->attributes['filename'] == ""){
+ return false;
+ }
+ if(!\Storage::disk('public')->has('images/shop/'.$this->filename)){
+ return false;
+ }
+ return true;
+ }
+
+ public function getImage(){
+ if($this->isImage()){
+ $link = 'images/shop/'.$this->filename;
+ return '/storage/'.$link.'?=lm='.\Storage::disk('public')->lastModified($link);
+ }
+ return false;
+ }*/
+
+ public function hasThumb(){
+ if(\Storage::disk('public')->exists('dc/thumb/'.$this->filename) || \Storage::disk('public')->exists('dc/thumb/'.$this->filename.".jpg")){
+ return true;
+ }
+ return false;
+ }
+
+ public function hasBig(){
+ if(\Storage::disk('public')->exists('dc/big/'.$this->filename) || \Storage::disk('public')->exists('dc/big/'.$this->filename.".jpg")){
+ return true;
+ }
+ return false;
+ }
+ public function hasFile(){
+ if(\Storage::disk('public')->exists('dc/files/'.$this->filename) || \Storage::disk('public')->exists('dc/files/'.$this->filename.".jpg")){
+ return true;
+ }
+ return false;
+ }
+
+ public function getThumb($full = false){
+ $link = 'dc/thumb/'.$this->filename;
+ if(\Storage::disk('public')->exists($link)){
+ return $full ? \Storage::disk('public')->path($link) : $link;
+ }
+ $link.=".jpg";
+ if(\Storage::disk('public')->exists($link)){
+ return $full ? \Storage::disk('public')->path($link) : $link;
+ }
+
+ return false;
+ }
+
+ public function getBig($full = false){
+ $link = 'dc/big/'.$this->filename;
+ if(\Storage::disk('public')->exists($link)){
+ return $full ? \Storage::disk('public')->path($link) : $link;
+ }
+ $link.=".jpg";
+ if(\Storage::disk('public')->exists($link)){
+ return $full ? \Storage::disk('public')->path($link) : $link;
+ }
+ return false;
+ }
+
+
+ public function getFile($full = false){
+ $link = 'dc/files/'.$this->filename;
+ if(\Storage::disk('public')->exists($link)){
+ return $full ? \Storage::disk('public')->path($link) : $link;
+ }
+ $link.=".jpg";
+ if(\Storage::disk('public')->exists($link)){
+ return $full ? \Storage::disk('public')->path($link) : $link;
+ }
+ return false;
+ }
+
+ public function getLastModified($type = 'thumb'){
+ if($type == 'thumb'){
+ $link = $this->getThumb();
+ }
+ if($type == 'big'){
+ $link = $this->getBig();
+ }
+ if($type == 'file'){
+ $link = $this->getFile();
+ }
+ return \Storage::disk('public')->lastModified($link);
+ }
+
+
+ public function getTags(){
+ $tags = $this->tags;
+ $tagArray = [];
+ foreach($tags as $tag){
+ $tagArray[] = $tag->name;
+ }
+ return implode(', ', $tagArray);
+ }
+ public function thumb(){
+ $ext = $this->ext;
+ $ext = strtolower($ext);
+ if($ext == 'pdf'){
+ return 'pdf.png';
+ }
+ if($ext == 'doc' || $ext == 'docx'){
+ return 'doc.png';
+ }
+ if($ext == 'xls' || $ext == 'xlsx'){
+ return 'xls.png';
+ }
+ if($ext == 'ppt' || $ext == 'pptx'){
+ return 'ppt.png';
+ }
+ if($ext == 'zip' || $ext == 'rar'){
+ return 'zip.png';
+ }
+ if($ext == 'jpg' || $ext == 'jpeg' || $ext == 'png' || $ext == 'gif'){
+ return $this->filename;
+ }
+ return 'file.png';
+ }
+}
diff --git a/app/Models/DcFileTag.php b/app/Models/DcFileTag.php
new file mode 100644
index 00000000..24d68e83
--- /dev/null
+++ b/app/Models/DcFileTag.php
@@ -0,0 +1,49 @@
+ 'int',
+ 'tag_id' => 'int'
+ ];
+
+ protected $fillable = [
+ 'file_id',
+ 'tag_id'
+ ];
+
+ public function dc_file()
+ {
+ return $this->belongsTo(DcFile::class, 'file_id');
+ }
+
+ public function dc_tag()
+ {
+ return $this->belongsTo(DcTag::class, 'tag_id');
+ }
+}
diff --git a/app/Models/DcTag.php b/app/Models/DcTag.php
new file mode 100644
index 00000000..9cc6f0e0
--- /dev/null
+++ b/app/Models/DcTag.php
@@ -0,0 +1,63 @@
+ 'int',
+ 'pos' => 'int',
+ 'active' => 'bool'
+ ];
+
+ protected $fillable = [
+ 'category_id',
+ 'name',
+ 'pos',
+ 'slug',
+ 'active'
+ ];
+
+ public function sluggable()
+ {
+ return [
+ 'slug' => [
+ 'source' => 'name'
+ ]
+ ];
+ }
+
+ public function dc_file_tags()
+ {
+ return $this->hasMany(DcFileTag::class, 'tag_id');
+ }
+}
diff --git a/app/Models/Homeparty.php b/app/Models/Homeparty.php
index 2c7d3bd4..95dee2ac 100644
--- a/app/Models/Homeparty.php
+++ b/app/Models/Homeparty.php
@@ -90,6 +90,7 @@ class Homeparty extends Model
'settings' => 'array',
'order' => 'array',
'card_info' => 'array',
+ 'trans_description' => 'array',
];
protected $dates = [
@@ -106,7 +107,6 @@ class Homeparty extends Model
'name',
'place',
'country_id',
- 'description',
'pos',
'completed',
'status',
@@ -152,6 +152,39 @@ class Homeparty extends Model
}
+ public function getLang($key, $default = true)
+ {
+ $lang = \App::getLocale();
+ if ($lang == 'de') {
+ return $this->{$key};
+ }
+ return $this->getTrans($key, $lang, $default);
+ }
+
+ public function getTrans($key, $lang, $default = true)
+ {
+ if ($lang == 'de') {
+ return $this->{$key};
+ }
+ if($key === 'description' && !empty($this->trans_description[$lang])){
+ return $this->trans_description[$lang];
+ }
+ if($default){
+ return !empty($this->{$key}) ? $this->{$key} : '';
+ }
+ return "";
+ }
+
+ public function getLangOrDefault($key, $default = true)
+ {
+ $dkey = 'default_'.$key;
+ $value = $this->getLang($key, $default);
+ if(!$value || $value == ""){
+ return __('homeparty.welcome_copy');
+ }
+ return $value;
+ }
+
public function getDateAttribute($value)
{
if (!$value) {
diff --git a/app/Models/Ingredient.php b/app/Models/Ingredient.php
index 2330fc83..3ff12fab 100644
--- a/app/Models/Ingredient.php
+++ b/app/Models/Ingredient.php
@@ -43,6 +43,8 @@ use Illuminate\Database\Eloquent\Model;
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Ingredient whereTransInci($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Ingredient whereTransName($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Ingredient whereUpdatedAt($value)
+ * @property-read Collection $translations
+ * @property-read int|null $translations_count
* @mixin \Eloquent
*/
class Ingredient extends Model
@@ -56,11 +58,8 @@ class Ingredient extends Model
protected $fillable = [
'name',
- 'trans_name',
'inci',
- 'trans_inci',
'effect',
- 'trans_effect',
'active',
'pos'
];
@@ -77,4 +76,26 @@ class Ingredient extends Model
return $this->hasMany(ProductIngredient::class, 'product_ingredients', 'id');
}
+
+ public function translations()
+ {
+ return $this->hasMany(TransIngredient::class, 'ingredient_id');
+ }
+
+
+ public function getLang($key)
+ {
+ $lang = \App::getLocale();
+ if ($lang == 'de') {
+ return $this->{$key};
+ }
+ $trans = $this->getTrans($key, $lang);
+ return $trans != '' ? $trans : $this->{$key};
+ }
+
+ public function getTrans($key, $lang)
+ {
+ $trans = $this->translations->where('language','=', $lang)->where('key', $key)->first();
+ return $trans ? $trans->value : '';
+ }
}
diff --git a/app/Models/Models/_UserInvoiceCredit.php b/app/Models/Models/_UserInvoiceCredit.php
deleted file mode 100644
index 3c973a3d..00000000
--- a/app/Models/Models/_UserInvoiceCredit.php
+++ /dev/null
@@ -1,223 +0,0 @@
- 'int',
- 'shopping_order_id' => 'int',
- 'shopping_user_id' => 'int',
- 'number' => 'int',
- 'year' => 'int',
- 'month' => 'int',
- 'net' => 'float',
- 'tax_rate' => 'float',
- 'tax' => 'float',
- 'total' => 'float',
- 'paid' => 'bool',
- 'cancellation_id' => 'int',
- 'status' => 'int',
- 'file' => 'array',
- 'contents' => 'array',
- 'infos' => 'array',
-
- ];
-
- protected $dates = [
- 'paid_date',
- 'cancellation_date'
- ];
-
- protected $fillable = [
- 'auth_user_id',
- 'shopping_order_id',
- 'shopping_user_id',
- 'type',
- 'year',
- 'month',
- 'full_number',
- 'number',
- 'net',
- 'tax_rate',
- 'tax',
- 'total',
- 'file',
- 'contents',
- 'infos',
- 'subject',
- 'address',
- 'paid',
- 'paid_date',
- 'cancellation_id',
- 'cancellation_date',
- 'status'
- ];
-
- public static $monthNames = [
- 1 => 'Januar',
- 2 => 'Februar',
- 3 => 'März',
- 4 => 'April',
- 5 => 'Mai',
- 6 => 'Juni',
- 7 => 'Juli',
- 8 => 'August',
- 9 => 'September',
- 10 => 'Oktober',
- 11 => 'November',
- 12 => 'Dezember'
- ];
-
- public static $statusTypes = [
- 0 => 'offen',
- 1 => 'bezahlt',
- 2 => 'prüfen',
- 10 => 'storniert'
- ];
-
- public static $statusColors = [
- 0 => 'warning',
- 1 => 'success',
- 2 => 'secondary',
- 10 => 'danger',
- ];
-
- public function user()
- {
- return $this->belongsTo(\App\User::class, 'auth_user_id');
- }
-
- public function user_invoice_credit()
- {
- return $this->belongsTo(UserInvoiceCredit::class, 'cancellation_id');
- }
-
- public function shopping_order()
- {
- return $this->belongsTo(ShoppingOrder::class);
- }
-
- public function shopping_user()
- {
- return $this->belongsTo(ShoppingUser::class);
- }
-
- public function user_invoice_credits()
- {
- return $this->hasMany(UserInvoiceCredit::class, 'cancellation_id');
- }
-
- public function getPaidDateAttribute($value){
- return $this->attributes['paid_date'] ? Carbon::parse($this->attributes['paid_date'])->format(\Util::formatDateDB()) : '';
- }
- public function setPaidDateAttribute( $value ) {
- $this->attributes['paid_date'] = isset($value) ? (new Carbon($value))->format('Y-m-d') : NULL;
- }
- public function getPaidDateRaw(){
- return isset($this->attributes['paid_date']) ? $this->attributes['paid_date'] : NULL;
- }
-
- public function getCancellationDateAttribute($value){
- return $this->attributes['cancellation_date'] ? Carbon::parse($this->attributes['cancellation_date'])->format(\Util::formatDateDB()) : '';
- }
- public function setCancellationDateAttribute( $value ) {
- $this->attributes['cancellation_date'] = isset($value) ? (new Carbon($value))->format('Y-m-d') : NULL;
- }
- public function getCancellationDateRaw(){
- return isset($this->attributes['cancellation_date']) ? $this->attributes['cancellation_date'] : NULL;
- }
-
-
- public static function getMonthName($month)
- {
- return isset(self::$monthNames[$month]) ? self::$monthNames[$month] : $month;
- }
-
- public function getStatusType(){
- return isset(self::$statusTypes[$this->status]) ? self::$statusTypes[$this->status] : "";
- }
-
- public function getStatusColor(){
- return isset(self::$statusColors[$this->status]) ? self::$statusColors[$this->status] : "default";
- }
-
-}
diff --git a/app/Models/PaymentMethod.php b/app/Models/PaymentMethod.php
index 9880cd3d..d66bc69d 100644
--- a/app/Models/PaymentMethod.php
+++ b/app/Models/PaymentMethod.php
@@ -48,6 +48,7 @@ class PaymentMethod extends Model
'pos' => 'int',
'active' => 'bool',
'default' => 'bool',
+ 'is_abo' => 'bool',
'show_on' => 'array',
];
@@ -58,6 +59,7 @@ class PaymentMethod extends Model
'show_on',
'pos',
'default',
+ 'is_abo',
'active'
];
@@ -95,7 +97,10 @@ class PaymentMethod extends Model
return $ret;
}
- public static function getDefaultAsArray($short=false){
+ public static function getDefaultAsArray($is_abo=false){
+ if($is_abo){
+ return PaymentMethod::where('active', true)->where('default', true)->where('is_abo', $is_abo)->pluck('id');
+ }
return PaymentMethod::where('active', true)->where('default', true)->pluck('id');
}
}
diff --git a/app/Models/Product.php b/app/Models/Product.php
index 01b39e44..2fd77439 100644
--- a/app/Models/Product.php
+++ b/app/Models/Product.php
@@ -125,6 +125,16 @@ use Illuminate\Database\Eloquent\SoftDeletes;
* @property-read \Illuminate\Database\Eloquent\Collection $product_buyings
* @property-read int|null $product_buyings_count
* @property-read \Illuminate\Database\Eloquent\Collection $product_buyings
+ * @property bool|null $sponsor_buying_points
+ * @property int|null $sponsor_buying_points_amount
+ * @property-read \Illuminate\Database\Eloquent\Collection $product_buyings
+ * @method static \Illuminate\Database\Eloquent\Builder|Product whereSponsorBuyingPoints($value)
+ * @method static \Illuminate\Database\Eloquent\Builder|Product whereSponsorBuyingPointsAmount($value)
+ * @property-read \Illuminate\Database\Eloquent\Collection $product_buyings
+ * @property-read \Illuminate\Database\Eloquent\Collection $translations
+ * @property-read int|null $translations_count
+ * @property-read \Illuminate\Database\Eloquent\Collection $product_categories
+ * @property-read int|null $product_categories_count
* @mixin \Eloquent
*/
class Product extends Model
@@ -215,8 +225,8 @@ class Product extends Model
0 => '',
1 => 'ml',
2 => 'g',
- 3 => 'Liter',
- 4 => 'KG',
+ 3 => 'liter',
+ 4 => 'kg',
];
public $showATs = [
@@ -239,6 +249,9 @@ class Product extends Model
8 => 'Mitgliedschaft Berater',
9 => 'Onboarding Berater',
10 => 'zur internen Berechnung',
+ 12 => 'Abo-ShopBerater',
+ 13 => 'Abo-ShopBeraterKunden',
+
];
public $actions = [
@@ -278,6 +291,10 @@ class Product extends Model
return $this->hasMany('App\Models\ProductCategory', 'product_id', 'id')->orderBy('pos', 'DESC');
}
+ public function product_categories(){
+ return $this->hasMany('App\Models\ProductCategory', 'product_id', 'id')->orderBy('pos', 'DESC');
+ }
+
public function images(){
return $this->hasMany('App\Models\ProductImage', 'product_id', 'id')->orderBy('pos');
}
@@ -302,6 +319,10 @@ class Product extends Model
return $this->hasMany(CountryPrice::class, 'product_id');
}
+ public function translations()
+ {
+ return $this->hasMany(TransProduct::class, 'product_id');
+ }
public function p_ingredients()
{
@@ -382,6 +403,19 @@ class Product extends Model
}
return $price;
}
+
+ private function calcPriceUserCommission($price){
+ if($this->no_commission){
+ return $price;
+ }
+ if(\Auth::user() && \Auth::user()->user_level){
+ $margin = \Auth::user()->user_level->margin;
+ $price = $price / 100 * $margin;
+ }
+ return $price;
+ }
+
+
/*price net*/
private function calcPriceNet($price, $country=null){
$tax = $this->getTaxWith($country);
@@ -389,18 +423,21 @@ class Product extends Model
return $price / $tax_rate;
}
//price calu with
- public function getPriceWith(Bool $net = true, Bool $ufactor = true, $country = null){
+ public function getPriceWith(Bool $net = true, Bool $ufactor = true, $country = null, $commission=false){
$price = isset($this->attributes['price']) ? $this->attributes['price'] : null;
$cprice = $country ? $this->getCPrice($country) : null;
$price = $cprice ? $cprice : $price;
$price = $net ? $this->calcPriceNet($price, $country) : $price;
$price = $ufactor ? $this->calcPriceUserFactor($price) : $price;
+ $price = $commission ? $this->calcPriceUserCommission($price) : $price;
+
return round($price, 2);
}
+
/*out*/
- public function getFormattedPriceWith(Bool $net = true, Bool $ufactor = true, $country = null)
+ public function getFormattedPriceWith(Bool $net = true, Bool $ufactor = true, $country = null, $commission=false)
{
- return isset($this->attributes['price']) ? Util::formatNumber($this->getPriceWith($net, $ufactor, $country)) : "";
+ return isset($this->attributes['price']) ? Util::formatNumber($this->getPriceWith($net, $ufactor, $country, $commission)) : "";
}
public function getTaxWith($country = null){
@@ -496,7 +533,7 @@ class Product extends Model
public function getUnitType(){
- return isset($this->unitTypes[$this->unit]) ? $this->unitTypes[$this->unit] : '-';
+ return isset($this->unitTypes[$this->unit]) ? __($this->unitTypes[$this->unit]) : '-';
}
public function getShowAtType(){
return isset($this->showATs[$this->show_at]) ? $this->showATs[$this->show_at] : '-';
@@ -523,18 +560,13 @@ class Product extends Model
return $this->{$key};
}
$trans = $this->getTrans($key, $lang);
- if (!$trans || $trans == '') {
- return $this->{$key};
- }
- return $trans;
+ return $trans != '' ? $trans : $this->{$key};
}
public function getTrans($key, $lang)
{
- $key = 'trans_' . $key;
- if (!empty($this->{$key}[$lang])) {
- return $this->{$key}[$lang];
- }
+ $trans = $this->translations->where('language','=', $lang)->where('key', $key)->first();
+ return $trans ? $trans->value : '';
}
public function getTranNames()
@@ -573,10 +605,10 @@ class Product extends Model
return $this->price;
}
- public function getFormattedPriceCurrencyWith(Bool $net = true, Bool $ufactor = true, Country $country = null){
+ public function getFormattedPriceCurrencyWith(Bool $net = true, Bool $ufactor = true, Country $country = null, $commission = false){
$ret = "";
if($country && isset($country->currency) && $country->currency){
- $price = $this->getPriceWith($net, $ufactor, $country);
+ $price = $this->getPriceWith($net, $ufactor, $country, $commission);
$ret = formatNumber($price * $country->currency_faktor)." ".$country->currency_unit;
return '
~'.$ret.'';
}
diff --git a/app/Models/Shipping.php b/app/Models/Shipping.php
index 6ae8f9ca..171e34fa 100644
--- a/app/Models/Shipping.php
+++ b/app/Models/Shipping.php
@@ -30,16 +30,14 @@ use Illuminate\Database\Eloquent\Model;
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Shipping whereUpdatedAt($value)
* @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\ShippingPrice[] $shipping_prices
* @property-read int|null $shipping_prices_count
+ * @property-read \Illuminate\Database\Eloquent\Collection $translations
+ * @property-read int|null $translations_count
* @mixin \Eloquent
*/
class Shipping extends Model
{
protected $table = 'shippings';
- protected $casts = [
- 'trans_name' => 'array',
- ];
-
protected $fillable = [
'name', 'active', 'free'
];
@@ -78,4 +76,25 @@ class Shipping extends Model
public function shipping_prices(){
return $this->hasMany('App\Models\ShippingPrice', 'shipping_id', 'id');
}
+
+ public function translations()
+ {
+ return $this->hasMany(TransShipping::class, 'shipping_id');
+ }
+
+ public function getLang($key)
+ {
+ $lang = \App::getLocale();
+ if ($lang == 'de') {
+ return $this->{$key};
+ }
+ $trans = $this->getTrans($key, $lang);
+ return $trans != '' ? $trans : $this->{$key};
+ }
+
+ public function getTrans($key, $lang)
+ {
+ $trans = $this->translations->where('language','=', $lang)->where('key', $key)->first();
+ return $trans ? $trans->value : '';
+ }
}
diff --git a/app/Models/ShoppingCollectOrder.php b/app/Models/ShoppingCollectOrder.php
index f544c144..bdc36ec4 100644
--- a/app/Models/ShoppingCollectOrder.php
+++ b/app/Models/ShoppingCollectOrder.php
@@ -118,7 +118,8 @@ class ShoppingCollectOrder extends Model
public function addTaxToSplit($tax_rate, $add_tax)
{
$tax_split = $this->tax_split;
- $tax_split[$tax_rate] = isset($tax_split[$tax_rate]) ? round($tax_split[$tax_rate] += $add_tax, 2) : round($add_tax, 2);
+ $add_tax = round($add_tax, 2);
+ $tax_split[$tax_rate] = isset($tax_split[$tax_rate]) ? round($tax_split[$tax_rate] += $add_tax, 2) : $add_tax;
foreach($tax_split as $key=>$value){
$tax_split[$key] = number_format($value, 2);
@@ -129,7 +130,8 @@ class ShoppingCollectOrder extends Model
public function addNetToSplit($tax_rate, $add_net)
{
$net_split = $this->net_split;
- $net_split[$tax_rate] = isset($net_split[$tax_rate]) ? round($net_split[$tax_rate] += $add_net, 2) : round($add_net, 2);
+ $add_net = round($add_net, 2);
+ $net_split[$tax_rate] = isset($net_split[$tax_rate]) ? round($net_split[$tax_rate] += $add_net, 2) : $add_net;
foreach($net_split as $key=>$value){
$net_split[$key] = number_format($value, 2);
diff --git a/app/Models/ShoppingInstance.php b/app/Models/ShoppingInstance.php
index 5a733e72..19192224 100644
--- a/app/Models/ShoppingInstance.php
+++ b/app/Models/ShoppingInstance.php
@@ -33,17 +33,21 @@ use Illuminate\Database\Eloquent\Model;
* @property string|null $back
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\ShoppingInstance whereBack($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\ShoppingInstance whereShoppingData($value)
+ * @property string|null $language
+ * @method static \Illuminate\Database\Eloquent\Builder|ShoppingInstance whereLanguage($value)
* @mixin \Eloquent
*/
class ShoppingInstance extends Model
{
public $paymentTypes = [
- 1 => 'User Shop',
+ 1 => 'Customer Shop',
2 => 'Berater Shop',
3 => 'Berater Membership',
4 => 'Berater Wizard',
5 => 'Berater Homeparty',
+ 6 => 'Berater Shop to Customer Shop',
+
];
protected $table = 'shopping_instances';
@@ -51,9 +55,13 @@ class ShoppingInstance extends Model
protected $casts = ['shopping_data' => 'array'];
protected $fillable = [
- 'identifier', 'user_shop_id', 'auth_user_id', 'payment', 'subdomain', 'country_id', 'shopping_data', 'back'
+ 'identifier', 'user_shop_id', 'auth_user_id', 'payment', 'subdomain', 'language', 'country_id', 'shopping_data', 'back'
];
+ public function getLocale(){
+ return $this->language ? $this->language : \App::getLocale();
+ }
+
public function user_shop()
{
return $this->belongsTo('App\Models\UserShop', 'user_shop_id');
diff --git a/app/Models/ShoppingOrder.php b/app/Models/ShoppingOrder.php
index a2df7908..1e20e317 100644
--- a/app/Models/ShoppingOrder.php
+++ b/app/Models/ShoppingOrder.php
@@ -95,6 +95,8 @@ use Illuminate\Database\Eloquent\SoftDeletes;
* @property-read \App\Models\ShoppingCollectOrder|null $shopping_collect_order
* @property array|null $net_split
* @method static \Illuminate\Database\Eloquent\Builder|ShoppingOrder whereNetSplit($value)
+ * @property string|null $language
+ * @method static \Illuminate\Database\Eloquent\Builder|ShoppingOrder whereLanguage($value)
* @mixin \Eloquent
*/
class ShoppingOrder extends Model
@@ -111,6 +113,7 @@ class ShoppingOrder extends Model
'homeparty_id',
'payment_for',
'country_id',
+ 'language',
'user_shop_id',
'total',
'subtotal',
@@ -124,6 +127,8 @@ class ShoppingOrder extends Model
'points',
'weight',
'paid',
+ 'is_abo',
+ 'abo_interval',
'txaction',
'wp_invoice_path',
'api_notice',
@@ -137,15 +142,17 @@ class ShoppingOrder extends Model
'api_notice' => 'array',
'tax_split' => 'array',
'net_split' => 'array',
-
+ 'abo_interval' => 'int',
+ 'is_abo' => 'bool',
];
public static $shippedTypes = [
- 0 => 'offen',
- 1 => 'in Bearbeitung',
- 2 => 'versendet',
- 3 => 'abgeschlossen',
- 10 => 'storniert'
+ 0 => 'open',
+ 1 => 'in_process',
+ 2 => 'shipped',
+ 3 => 'completed',
+ 4 => 'trade_fair',
+ 10 => 'cancelled'
];
public static $apiShippedTypes = [
@@ -153,14 +160,15 @@ class ShoppingOrder extends Model
1 => 'process', //(Fullfilment durch MIVITA: nicht Versand)
2 => 'sent', //(Fullfilment durch MIVITA: Versand erfolgt)'
3 => 'close', //(Fullfilment durch MIVITA: Versand erfolgt)',
+ 4 => 'trade', //(Fullfilment durch MIVITA: Versand erfolgt)',
10 => 'cancel'
];
public static $apiStatusTypes = [
- 0 => 'bestellt',
- 1 => 'im Prozess',
- 2 => 'bezahlt',
- 5 => 'entfernt',
+ 0 => 'ordered',
+ 1 => 'in_process',
+ 2 => 'paid',
+ 5 => 'removed',
];
public static $apiStatusColors = [
0 => 'warning',
@@ -173,19 +181,20 @@ class ShoppingOrder extends Model
1 => 'info',
2 => 'success',
3 => 'secondary',
+ 4 => 'secondary',
10 => 'danger',
];
public static $paymentForTypes = [
0 => '',
- 1 => 'Registrierung',
- 2 => 'Mitgliedschaft',
- 3 => 'Bestellung',
- 4 => 'Kundenbestellung',
- 5 => 'Homeparty',
- 6 => 'Shop',
- 7 => 'extern',
- 8 => 'Sammelrechnung',
+ 1 => 'registration',
+ 2 => 'membership',
+ 3 => 'order',
+ 4 => 'customer_order',
+ 5 => 'homeparty',
+ 6 => 'shop',
+ 7 => 'external',
+ 8 => 'collective_invoice',
10 => '',
];
@@ -273,7 +282,9 @@ class ShoppingOrder extends Model
}
-
+ public function getLocale(){
+ return $this->language ? $this->language : \App::getLocale();
+ }
public function setUserHistoryValue($values = []){
if($user_history = $this->user_history){
@@ -311,7 +322,14 @@ class ShoppingOrder extends Model
}
public function getShippedType(){
- return isset(self::$shippedTypes[$this->shipped]) ? self::$shippedTypes[$this->shipped] : "";
+ return isset(self::$shippedTypes[$this->shipped]) ? __('payment.'.self::$shippedTypes[$this->shipped]) : "";
+ }
+ public static function getTransShippedType(){
+ $ret = [];
+ foreach(self::$shippedTypes as $key=>$val){
+ $ret[$key] = trans('payment.'.$val);
+ }
+ return $ret;
}
public function getAPIShippedType(){
@@ -323,7 +341,7 @@ class ShoppingOrder extends Model
}
public function getAPIStatusType(){
- return isset(self::$apiStatusTypes[$this->api_status]) ? self::$apiStatusTypes[$this->api_status] : "bestellt";
+ return isset(self::$apiStatusTypes[$this->api_status]) ? __('payment.'.self::$apiStatusTypes[$this->api_status]) : "bestellt";
}
public function getAPIStatusColor(){
@@ -381,7 +399,7 @@ class ShoppingOrder extends Model
}
public function getPaymentForType(){
- return isset(self::$paymentForTypes[$this->payment_for]) ? self::$paymentForTypes[$this->payment_for] : "";
+ return isset(self::$paymentForTypes[$this->payment_for]) ? __('payment.'.self::$paymentForTypes[$this->payment_for]) : "";
}
public function getPaymentForColor(){
return isset(self::$paymentForColors[$this->payment_for]) ? self::$paymentForColors[$this->payment_for] : "";
@@ -579,6 +597,19 @@ class ShoppingOrder extends Model
$this->save();
}
+ public function getShoppingUserFullName(){
+
+ if($this->shopping_user){
+ $fullname = $this->shopping_user->getFullNameAsArray();
+ $ret = "";
+ $ret .= $fullname['company'] ? $fullname['company'].' | ' : '';
+ $ret .= $fullname['salutation'] ? \App\Services\HTMLHelper::getSalutationLang($fullname['salutation']).' ' : '';
+ $ret .= $fullname['firstname'] ? $fullname['firstname'].' ' : '';
+ $ret .= $fullname['lastname'] ? $fullname['lastname'] : '';
+ $ret .= $fullname['email'] ? ' | '.$fullname['email'].'' : '';
+ }
+ return $ret;
+ }
}
diff --git a/app/Models/ShoppingPayment.php b/app/Models/ShoppingPayment.php
index 84cb241f..1abb82a1 100644
--- a/app/Models/ShoppingPayment.php
+++ b/app/Models/ShoppingPayment.php
@@ -54,7 +54,9 @@ class ShoppingPayment extends Model
'reference',
'amount',
'currency',
- 'mode'
+ 'mode',
+ 'is_abo',
+ 'abo_interval',
];
@@ -72,26 +74,26 @@ class ShoppingPayment extends Model
if($this->clearingtype === 'wlt') {
if ($this->wallettype === 'PPE') {
- return 'PayPal';
+ return __('payment.paypal');
}
}
if($this->clearingtype === 'cc') {
- return 'Kreditkarte';
+ return __('payment.credit_card');
}
if($this->clearingtype === 'vor') {
- return 'Vorkasse';
+ return __('payment.prepayment');
}
if($this->clearingtype === 'elv') {
- return 'SEPA Lastschrift';
+ return __('payment.sepa_direct_debit');
}
if($this->clearingtype === 'sb') {
if ($this->onlinebanktransfertype === 'PNT') {
- return 'Sofort Überweisung';
+ return __('payment.sofort_bank_transfer');
}
}
if($this->clearingtype === 'fnc') {
if ($this->onlinebanktransfertype === 'MIV') {
- return 'Rechnung';
+ return __('payment.purchase_on_account');
}
}
}
diff --git a/app/Models/ShoppingUser.php b/app/Models/ShoppingUser.php
index 426cc473..4124b051 100644
--- a/app/Models/ShoppingUser.php
+++ b/app/Models/ShoppingUser.php
@@ -118,6 +118,8 @@ use Illuminate\Database\Eloquent\SoftDeletes;
* @method static \Illuminate\Database\Eloquent\Builder|ShoppingUser whereShoppingCollectOrderId($value)
* @property string|null $remarks
* @method static \Illuminate\Database\Eloquent\Builder|ShoppingUser whereRemarks($value)
+ * @property string|null $language
+ * @method static \Illuminate\Database\Eloquent\Builder|ShoppingUser whereLanguage($value)
* @mixin \Eloquent
*/
class ShoppingUser extends Model
@@ -134,6 +136,7 @@ class ShoppingUser extends Model
'member_id',
'number',
'is_like',
+ 'language',
'billing_salutation',
'billing_company',
'billing_firstname',
@@ -215,6 +218,10 @@ class ShoppingUser extends Model
return $this->hasOne('App\Models\ShoppingOrder','shopping_user_id');
}
+ public function getLocale(){
+ return $this->language ? $this->language : \App::getLocale();
+ }
+
public function setNotice($key, $value){
$notice = $this->notice;
$notice[$key] = $value;
@@ -262,7 +269,7 @@ class ShoppingUser extends Model
case 'membership':
return 2;
case 'user_order':
- return $this->is_for === 'me' ? 3 : 4;
+ return ($this->is_for === 'me' || $this->is_for === 'abo_me') ? 3 : 4;
case 'homeparty':
return 5;
case 'shopping':
@@ -275,6 +282,18 @@ class ShoppingUser extends Model
return 0;
}
+ public function setIsForAttribute($value){
+ if($value === 'abo-me' || $value === 'me'){
+ $this->attributes['is_for'] = 'me';
+ return;
+ }
+ if($value === 'ot-member' || $value === 'ot-customer' || $value === 'abo-ot-member' || $value === 'abo-ot-customer'){
+ $this->attributes['is_for'] = 'ot';
+ return;
+ }
+ $this->attributes['is_for'] = $value;
+ }
+
public function getAPIShippedType() {
if($this->shopping_order){
@@ -282,4 +301,15 @@ class ShoppingUser extends Model
}
return "free";
}
+
+ public function getFullNameAsArray() {
+ return [
+ 'company' => $this->billing_company,
+ 'salutation' => $this->billing_salutation,
+ 'firstname' => $this->billing_firstname,
+ 'lastname' => $this->billing_lastname,
+ 'email' => $this->billing_email,
+
+ ];
+ }
}
\ No newline at end of file
diff --git a/app/Models/ShoppingUserMemberLog.php b/app/Models/ShoppingUserMemberLog.php
new file mode 100644
index 00000000..dfe4e8cd
--- /dev/null
+++ b/app/Models/ShoppingUserMemberLog.php
@@ -0,0 +1,69 @@
+ 'int',
+ 'shopping_user_id' => 'int',
+ 'new_member_id' => 'int'
+ ];
+
+ protected $fillable = [
+ 'pre_member_id',
+ 'shopping_user_id',
+ 'new_member_id'
+ ];
+
+ public function pre_member()
+ {
+ return $this->belongsTo(User::class, 'pre_member_id');
+ }
+
+ public function new_member()
+ {
+ return $this->belongsTo(User::class, 'new_member_id');
+ }
+
+
+ public function shopping_user()
+ {
+ return $this->belongsTo(ShoppingUser::class);
+ }
+}
diff --git a/app/Models/TransCategory.php b/app/Models/TransCategory.php
new file mode 100644
index 00000000..fddc3264
--- /dev/null
+++ b/app/Models/TransCategory.php
@@ -0,0 +1,55 @@
+ 'int'
+ ];
+
+ protected $fillable = [
+ 'language',
+ 'categorie_id',
+ 'key',
+ 'value'
+ ];
+
+ public function category()
+ {
+ return $this->belongsTo(Category::class, 'categorie_id');
+ }
+}
diff --git a/app/Models/TransIngredient.php b/app/Models/TransIngredient.php
new file mode 100644
index 00000000..09ac23a6
--- /dev/null
+++ b/app/Models/TransIngredient.php
@@ -0,0 +1,55 @@
+ 'int'
+ ];
+
+ protected $fillable = [
+ 'language',
+ 'ingredient_id',
+ 'key',
+ 'value'
+ ];
+
+ public function ingredient()
+ {
+ return $this->belongsTo(Ingredient::class);
+ }
+}
diff --git a/app/Models/TransProduct.php b/app/Models/TransProduct.php
new file mode 100644
index 00000000..c6c2b76e
--- /dev/null
+++ b/app/Models/TransProduct.php
@@ -0,0 +1,57 @@
+ 'int'
+ ];
+
+ protected $fillable = [
+ 'language',
+ 'product_id',
+ 'key',
+ 'value'
+ ];
+
+ public function product()
+ {
+ return $this->belongsTo(Product::class);
+ }
+}
\ No newline at end of file
diff --git a/app/Models/TransShipping.php b/app/Models/TransShipping.php
new file mode 100644
index 00000000..ac75beb8
--- /dev/null
+++ b/app/Models/TransShipping.php
@@ -0,0 +1,55 @@
+ 'int'
+ ];
+
+ protected $fillable = [
+ 'language',
+ 'shipping_id',
+ 'key',
+ 'value'
+ ];
+
+ public function shipping()
+ {
+ return $this->belongsTo(Shipping::class);
+ }
+}
diff --git a/app/Models/TransUserLevel.php b/app/Models/TransUserLevel.php
new file mode 100644
index 00000000..bd6719f4
--- /dev/null
+++ b/app/Models/TransUserLevel.php
@@ -0,0 +1,55 @@
+ 'int'
+ ];
+
+ protected $fillable = [
+ 'language',
+ 'user_level_id',
+ 'key',
+ 'value'
+ ];
+
+ public function user_level()
+ {
+ return $this->belongsTo(UserLevel::class);
+ }
+}
diff --git a/app/Models/UserAbo.php b/app/Models/UserAbo.php
new file mode 100644
index 00000000..fa3b7b17
--- /dev/null
+++ b/app/Models/UserAbo.php
@@ -0,0 +1,131 @@
+ 'int',
+ 'shopping_user_id' => 'int',
+ 'payone_userid' => 'int',
+ 'amount' => 'int',
+ 'active' => 'bool',
+ 'status' => 'int',
+ 'abo_interval' => 'int',
+ 'start_date' => 'datetime',
+ 'last_date' => 'datetime',
+ 'next_date' => 'datetime',
+ 'cancel_date' => 'datetime',
+ 'count' => 'int',
+ 'user_deleted_at' => 'datetime'
+ ];
+
+ protected $fillable = [
+ 'user_id',
+ 'shopping_user_id',
+ 'is_for',
+ 'payone_userid',
+ 'clearingtype',
+ 'wallettype',
+ 'amount',
+ 'currency',
+ 'active',
+ 'status',
+ 'abo_interval',
+ 'start_date',
+ 'last_date',
+ 'next_date',
+ 'cancel_date',
+ 'count',
+ 'user_deleted_at'
+ ];
+
+ public function user()
+ {
+ return $this->belongsTo(User::class);
+ }
+
+ public function shopping_user()
+ {
+ return $this->belongsTo('App\Models\ShoppingUser','shopping_user_id');
+ }
+
+
+ public function user_abo_orders()
+ {
+ return $this->hasMany(UserAboOrder::class);
+ }
+
+ public function setStartDateAttribute( $value ) {
+ $this->attributes['start_date'] = isset($value) ? (new Carbon($value))->format('Y-m-d') : NULL;
+ }
+ public function getStartDateAttribute()
+ {
+ return $this->attributes['start_date'] ? Carbon::parse($this->attributes['start_date'])->format(\Util::formatDateDB()) : '';
+ }
+
+ public function setLastDateAttribute( $value ) {
+ $this->attributes['last_date'] = isset($value) ? (new Carbon($value))->format('Y-m-d') : NULL;
+ }
+ public function getLastDateAttribute()
+ {
+ return $this->attributes['last_date'] ? Carbon::parse($this->attributes['last_date'])->format(\Util::formatDateDB()) : '';
+ }
+
+ public function setNextDateAttribute( $value ) {
+ $this->attributes['next_date'] = isset($value) ? (new Carbon($value))->format('Y-m-d') : NULL;
+ }
+ public function getNextDateAttribute()
+ {
+ return $this->attributes['next_date'] ? Carbon::parse($this->attributes['next_date'])->format(\Util::formatDateDB()) : '';
+ }
+
+ public function setCancelDateAttribute( $value ) {
+ $this->attributes['cancel_date'] = isset($value) ? (new Carbon($value))->format('Y-m-d') : NULL;
+ }
+ public function getCancelDateAttribute()
+ {
+ return $this->attributes['cancel_date'] ? Carbon::parse($this->attributes['cancel_date'])->format(\Util::formatDateDB()) : '';
+ }
+
+
+}
diff --git a/app/Models/UserAboOrder.php b/app/Models/UserAboOrder.php
new file mode 100644
index 00000000..c6ad621b
--- /dev/null
+++ b/app/Models/UserAboOrder.php
@@ -0,0 +1,54 @@
+ 'int',
+ 'shopping_order_id' => 'int',
+ 'status' => 'int'
+ ];
+
+ protected $fillable = [
+ 'user_abo_id',
+ 'user_id',
+ 'shopping_order_id',
+ 'status'
+ ];
+
+ public function shopping_order()
+ {
+ return $this->belongsTo(ShoppingOrder::class);
+ }
+
+ public function user_abo()
+ {
+ return $this->belongsTo(UserAbo::class);
+ }
+}
diff --git a/app/Models/UserAccount.php b/app/Models/UserAccount.php
index 79af9cb6..c5a111db 100644
--- a/app/Models/UserAccount.php
+++ b/app/Models/UserAccount.php
@@ -237,11 +237,33 @@ class UserAccount extends Model
}
public function getPhoneNumber(){
- if($this->phone && $this->phone !== ""){
- return ($this->pre_phone ? $this->pre_phone->phone : '')." ".$this->phone;
- }
if($this->mobil && $this->mobil !== ""){
return ($this->pre_mobil ? $this->pre_mobil->phone : '')." ".$this->mobil;
}
+ if($this->phone && $this->phone !== ""){
+ return ($this->pre_phone ? $this->pre_phone->phone : '')." ".$this->phone;
+ }
+
+ }
+
+ public function getPhoneFull(){
+ if($this->phone && $this->phone !== ""){
+ return ($this->pre_phone ? $this->pre_phone->phone : '')." ".$this->phone;
+ }
+ return "";
+ }
+
+ public function getMobilFull(){
+ if($this->mobil && $this->mobil !== ""){
+ return ($this->pre_mobil ? $this->pre_mobil->phone : '')." ".$this->mobil;
+ }
+ return "";
+ }
+
+ public function getShippingPhoneFull(){
+ if($this->shipping_phone && $this->shipping_phone !== ""){
+ return ($this->shipping_pre_phone ? $this->shipping_pre_phone->phone : '')." ".$this->shipping_phone;
+ }
+ return "";
}
}
diff --git a/app/Models/UserBusiness.php b/app/Models/UserBusiness.php
index fb86d49d..a7171ff2 100644
--- a/app/Models/UserBusiness.php
+++ b/app/Models/UserBusiness.php
@@ -98,6 +98,27 @@ use Illuminate\Database\Eloquent\Casts\AsArrayObject;
* @method static \Illuminate\Database\Eloquent\Builder|UserBusiness whereQualPp($value)
* @method static \Illuminate\Database\Eloquent\Builder|UserBusiness whereTotalPp($value)
* @method static \Illuminate\Database\Eloquent\Builder|UserBusiness whereTotalQualPp($value)
+ * @property int|null $sales_volume_KP_points
+ * @property int|null $sales_volume_TP_points
+ * @property int|null $sales_volume_points_KP_sum
+ * @property int|null $sales_volume_points_TP_sum
+ * @property int|null $payline_points
+ * @property int|null $payline_points_qual_kp
+ * @property float|null $commission_growth_total
+ * @property array|null $qual_user_level_next
+ * @property array|null $next_can_user_level
+ * @property int $version
+ * @method static \Illuminate\Database\Eloquent\Builder|UserBusiness whereCommissionGrowthTotal($value)
+ * @method static \Illuminate\Database\Eloquent\Builder|UserBusiness whereCommissionPpTotal($value)
+ * @method static \Illuminate\Database\Eloquent\Builder|UserBusiness whereNextCanUserLevel($value)
+ * @method static \Illuminate\Database\Eloquent\Builder|UserBusiness wherePaylinePoints($value)
+ * @method static \Illuminate\Database\Eloquent\Builder|UserBusiness wherePaylinePointsQualKp($value)
+ * @method static \Illuminate\Database\Eloquent\Builder|UserBusiness whereQualUserLevelNext($value)
+ * @method static \Illuminate\Database\Eloquent\Builder|UserBusiness whereSalesVolumeKPPoints($value)
+ * @method static \Illuminate\Database\Eloquent\Builder|UserBusiness whereSalesVolumePointsKPSum($value)
+ * @method static \Illuminate\Database\Eloquent\Builder|UserBusiness whereSalesVolumePointsTPSum($value)
+ * @method static \Illuminate\Database\Eloquent\Builder|UserBusiness whereSalesVolumeTPPoints($value)
+ * @method static \Illuminate\Database\Eloquent\Builder|UserBusiness whereVersion($value)
* @mixin \Eloquent
*/
class UserBusiness extends Model
@@ -161,6 +182,8 @@ class UserBusiness extends Model
'email',
'first_name',
'last_name',
+ 'user_birthday',
+ 'user_phone',
'sales_volume_KP_points',
'sales_volume_TP_points',
'sales_volume_points_shop',
@@ -212,6 +235,10 @@ class UserBusiness extends Model
$this->attributes['active_date'] = isset($value) ? (new Carbon($value))->format('Y-m-d') : NULL;
}
+ public function getSalesVolumeTotalMargin(){
+ return $this->sales_volume_total / 100 * $this->margin;
+ }
+
}
diff --git a/app/Models/UserCleanUpLog.php b/app/Models/UserCleanUpLog.php
new file mode 100644
index 00000000..5941c73d
--- /dev/null
+++ b/app/Models/UserCleanUpLog.php
@@ -0,0 +1,68 @@
+ 'int',
+ 'child_user_id' => 'int',
+ 'new_sponsor_id' => 'int'
+ ];
+
+ protected $fillable = [
+ 'inactive_sponsor_id',
+ 'child_user_id',
+ 'new_sponsor_id'
+ ];
+
+ public function inactive_sponsor()
+ {
+ return $this->belongsTo(User::class, 'inactive_sponsor_id');
+ }
+
+ public function child_user()
+ {
+ return $this->belongsTo(User::class, 'child_user_id');
+ }
+
+ public function new_sponsor()
+ {
+ return $this->belongsTo(User::class, 'new_sponsor_id');
+ }
+}
diff --git a/app/Models/UserCredit.php b/app/Models/UserCredit.php
index 8f4ce7cb..61c26706 100644
--- a/app/Models/UserCredit.php
+++ b/app/Models/UserCredit.php
@@ -130,10 +130,10 @@ class UserCredit extends Model
];
public static $statusTypes = [
- 0 => 'offen',
- 1 => 'bezahlt',
- 2 => 'prüfen',
- 10 => 'storniert'
+ 0 => 'open',
+ 1 => 'paid',
+ 2 => 'check',
+ 10 => 'cancelled'
];
public static $statusColors = [
@@ -145,9 +145,9 @@ class UserCredit extends Model
public static $taxableTypes = [
0 => '',
- 1 => 'umsatzsteuerpflichtig / DE',
- 2 => 'nicht umsatzsteuerpflichtig / DE',
- 3 => 'nicht umsatzsteuerpflichtig / Ausland'
+ 1 => 'umsatzsteuerpflichtig / DE', //payment.to_sales_tax_de
+ 2 => 'nicht umsatzsteuerpflichtig / DE', //payment.not_to_sales_tax_de
+ 3 => 'nicht umsatzsteuerpflichtig / Ausland' //payment.not_to_sales_tax_foreign
];
@@ -195,13 +195,22 @@ class UserCredit extends Model
public function getStatusType(){
- return isset(self::$statusTypes[$this->status]) ? self::$statusTypes[$this->status] : "";
+ //trans('payment.cancelled')
+ return isset(self::$statusTypes[$this->status]) ? __('payment.'.self::$statusTypes[$this->status]) : "";
}
public function getStatusColor(){
return isset(self::$statusColors[$this->status]) ? self::$statusColors[$this->status] : "default";
}
+ public static function getTransStatusType(){
+ $ret = [];
+ foreach(self::$statusTypes as $key=>$val){
+ $ret[$key] = trans('payment.'.$val);
+ }
+ return $ret;
+ }
+
public function getDownloadPath($full = false){
if(!$full){
return $this->dir.$this->filename;
diff --git a/app/Models/UserCreditItem.php b/app/Models/UserCreditItem.php
index 74f05596..5599d623 100644
--- a/app/Models/UserCreditItem.php
+++ b/app/Models/UserCreditItem.php
@@ -6,6 +6,7 @@
namespace App\Models;
+use App\Services\HTMLHelper;
use App\User;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
@@ -46,11 +47,11 @@ class UserCreditItem extends Model
public static $statusTypes = [
- 1 => 'Provision Shop',
- 2 => 'Provision Payline',
- 3 => 'Guthaben hinzugefügt',
- 4 => 'commission ...',
- 5 => 'Provision Wachstumsbonus',
+ 1 => 'commission_shop',
+ 2 => 'commission_payline',
+ 3 => 'credit_added',
+ 4 => 'commission',
+ 5 => 'commission_growth_bonus',
];
@@ -73,6 +74,8 @@ class UserCreditItem extends Model
'user_business_id' => 'int',
'credit' => 'float',
'status' => 'int',
+ 'from_month' => 'int',
+ 'from_year' => 'int',
'paid' => 'bool'
];
@@ -83,6 +86,8 @@ class UserCreditItem extends Model
'credit',
'message',
'status',
+ 'from_month',
+ 'from_year',
'paid'
];
@@ -106,12 +111,28 @@ class UserCreditItem extends Model
}
public function getStatusType(){
- return isset(self::$statusTypes[$this->status]) ? self::$statusTypes[$this->status] : "";
+ return isset(self::$statusTypes[$this->status]) ? __('payment.'.self::$statusTypes[$this->status]) : "";
}
public function getStatusColor(){
return isset(self::$statusColors[$this->status]) ? self::$statusColors[$this->status] : "default";
}
+ public function getTransMessage(){
+ $ret = "";
+ if(strpos($this->message, '#')){
+ $em = explode("#", $this->message);
+ if(isset($em[0])){ //Provision
+ $ret .= trans($em[0])." ";
+ }
+ if(isset($em[1])){ //month
+ $ret .= HTMLHelper::getMonth($em[1])." ";
+ }
+ if(isset($em[2])){ //year
+ $ret .= $em[2];
+ }
+ }
+ return $ret;
+ }
}
diff --git a/app/Models/UserHistory.php b/app/Models/UserHistory.php
index 3b7cedf9..771ad62f 100644
--- a/app/Models/UserHistory.php
+++ b/app/Models/UserHistory.php
@@ -105,6 +105,7 @@ class UserHistory extends Model
'referenz',
'identifier',
'abo_options',
+ 'is_abo',
'status'
];
diff --git a/app/Models/UserLevel.php b/app/Models/UserLevel.php
index d906b2ed..7627b6e9 100644
--- a/app/Models/UserLevel.php
+++ b/app/Models/UserLevel.php
@@ -11,7 +11,6 @@ use App\Models\UserLevel as ModelsUserLevel;
*
* @property int $id
* @property string $name
- * @property array|null $trans_name
* @property float|null $margin
* @property int|null $pos
* @property int $active
@@ -28,7 +27,6 @@ use App\Models\UserLevel as ModelsUserLevel;
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\UserLevel whereMargin($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\UserLevel whereName($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\UserLevel wherePos($value)
- * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\UserLevel whereTransName($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\UserLevel whereUpdatedAt($value)
* @property int|null $next_id
* @property int|null $margin_shop
@@ -58,14 +56,18 @@ use App\Models\UserLevel as ModelsUserLevel;
* @method static \Illuminate\Database\Eloquent\Builder|UserLevel wherePrLine7($value)
* @method static \Illuminate\Database\Eloquent\Builder|UserLevel wherePrLine8($value)
* @method static \Illuminate\Database\Eloquent\Builder|UserLevel whereQualPp($value)
+ * @property int|null $paylines
+ * @method static \Illuminate\Database\Eloquent\Builder|UserLevel wherePaylines($value)
+ * @property string|null $trans_name
+ * @property-read \Illuminate\Database\Eloquent\Collection $translations
+ * @property-read int|null $translations_count
+ * @method static \Illuminate\Database\Eloquent\Builder|UserLevel whereTransName($value)
* @mixin \Eloquent
*/
class UserLevel extends Model
{
protected $table = 'user_levels';
- protected $casts = ['trans_name' => 'array'];
-
protected $fillable = [
'next_id', 'name', 'margin', 'margin_shop', 'qual_kp', 'qual_pp', 'growth_bonus', 'pr_line_1', 'pr_line_2', 'pr_line_3', 'pr_line_4', 'pr_line_5', 'pr_line_6', 'pr_line_7', 'pr_line_8', 'paylines', 'pos', 'active', 'default',
];
@@ -76,6 +78,11 @@ class UserLevel extends Model
return $this->belongsTo('App\Models\UserLevel', 'next_id', 'id');
}
+ public function translations()
+ {
+ return $this->hasMany(TransUserLevel::class, 'user_level_id');
+ }
+
public function getNextUserLevels(){
//$ret = [0=>'Keinen'];
$ret = UserLevel::where('active', true)->where('id', '!=', $this->id)->orderBy('pos', 'asc')->get()->pluck('name', 'id')->toArray();
@@ -98,37 +105,29 @@ class UserLevel extends Model
public function getFormattedMargin()
{
- return isset($this->attributes['margin']) ? $this->attributes['margin'] : "";
+ return isset($this->attributes['margin']) ? Util::formatNumber($this->attributes['margin'], 1) : "";
+ }
+
+ public function getFormattedMarginShop()
+ {
+ return isset($this->attributes['margin_shop']) ? Util::formatNumber($this->attributes['margin_shop'], 1) : "";
}
-
public function getLang($key)
{
$lang = \App::getLocale();
- if ($lang === 'de') {
+ if ($lang == 'de') {
return $this->{$key};
}
$trans = $this->getTrans($key, $lang);
- if (!$trans || $trans == '') {
- return $this->{$key};
- }
- return $trans;
+ return $trans != '' ? $trans : $this->{$key};
}
public function getTrans($key, $lang)
{
- $key = 'trans_' . $key;
- if (!empty($this->{$key}[$lang])) {
- return $this->{$key}[$lang];
- }
+ $trans = $this->translations->where('language','=', $lang)->where('key', $key)->first();
+ return $trans ? $trans->value : '';
}
- public function getTranNames()
- {
- $ret = "";
- foreach ((array) $this->trans_name as $value){
- $ret .= $value.', ';
- }
- return rtrim($ret, ', ');
- }
+
}
diff --git a/app/Models/UserSalesVolume.php b/app/Models/UserSalesVolume.php
index 8f3f4315..2f88c23f 100644
--- a/app/Models/UserSalesVolume.php
+++ b/app/Models/UserSalesVolume.php
@@ -61,6 +61,12 @@ use App\User;
* @method static \Illuminate\Database\Eloquent\Builder|UserSalesVolume whereSyslog($value)
* @method static \Illuminate\Database\Eloquent\Builder|UserSalesVolume whereInfo($value)
* @method static \Illuminate\Database\Eloquent\Builder|UserSalesVolume whereStatusPoints($value)
+ * @property int|null $month_KP_points
+ * @property int|null $month_TP_points
+ * @method static \Illuminate\Database\Eloquent\Builder|UserSalesVolume whereMonthKPPoints($value)
+ * @method static \Illuminate\Database\Eloquent\Builder|UserSalesVolume whereMonthTPPoints($value)
+ * @property int|null $status_turnover
+ * @method static \Illuminate\Database\Eloquent\Builder|UserSalesVolume whereStatusTurnover($value)
* @mixin \Eloquent
*/
class UserSalesVolume extends Model
@@ -78,6 +84,7 @@ class UserSalesVolume extends Model
'month_TP_points' => 'int',
'month_shop_points' => 'int',
'status_points' => 'int',
+ 'status_turnover' => 'int',
'total_net' => 'float',
'month_total_net' => 'float',
'month_shop_total_net' => 'float',
@@ -101,6 +108,7 @@ class UserSalesVolume extends Model
'month_TP_points',
'month_shop_points',
'status_points',
+ 'status_turnover',
'total_net',
'month_total_net',
'month_shop_total_net',
@@ -112,18 +120,23 @@ class UserSalesVolume extends Model
public static $statusPointsTypes = [
- 1 => 'KP + TP', //Eigene + Team
- 2 => 'KP', //nur Eigene nicht Team
+ 1 => 'KU + TP', //Eigene + Team
+ 2 => 'KU', //nur Eigene nicht Team
+ ];
+
+ public static $statusTurnoverTypes = [
+ 1 => 'advisor_order', //hinzugefügt aus
+ 2 => 'shoporder', //hinzugefügt aus
];
public static $statusTypes = [
- 0 => 'nicht zugewiesen',
- 1 => 'Beraterbestellung', //hinzugefügt aus
- 2 => 'Shopbestellung', //hinzugefügt aus
- 3 => 'Shopbestellung / pending', //hinzugefügt aus
- 4 => 'Gutschrift', //hinzugefügt aus
- 5 => 'Registrierung', //hinzugefügt aus
- 10 => ''
+ 0 => 'not_assigned',
+ 1 => 'advisor_order', //hinzugefügt aus
+ 2 => 'shoporder', //hinzugefügt aus
+ 3 => 'shoporder_pending', //hinzugefügt aus
+ 4 => 'credit', //hinzugefügt aus
+ 5 => 'registration', //hinzugefügt aus
+ // 10 => ''
];
public static $statusColors = [
@@ -173,7 +186,23 @@ class UserSalesVolume extends Model
}
public function getStatusType(){
- return isset(self::$statusTypes[$this->status]) ? self::$statusTypes[$this->status] : "";
+ return isset(self::$statusTypes[$this->status]) ? __('payment.'.self::$statusTypes[$this->status]) : "";
+ }
+
+ public static function getTransStatusType(){
+ $ret = [];
+ foreach(self::$statusTypes as $key=>$val){
+ $ret[$key] = trans('payment.'.$val);
+ }
+ return $ret;
+ }
+
+ public static function getTransTurnoverTypes(){
+ $ret = [];
+ foreach(self::$statusTurnoverTypes as $key=>$val){
+ $ret[$key] = trans('payment.'.$val);
+ }
+ return $ret;
}
public function getStatusColor(){
@@ -187,6 +216,43 @@ class UserSalesVolume extends Model
return isset(self::$statusColors[$this->status_points]) ? self::$statusColors[$this->status_points] : "default";
}
+ public function getStatusTurnoverType(){
+ switch ($this->status) {
+ case 1: //Bestellung Berater
+ return 'E';
+ case 2: //Shop
+ return 'S';
+ case 4: //Gutschrift
+ if($this->status_turnover === 2){
+ return 'S';
+ }else{
+ return 'E';
+ }
+ case 5: //Registrierung
+ return 'E';
+ }
+ return "";
+ }
+ public function getStatusTurnoverColor(){
+
+
+ switch ($this->status) {
+ case 1: //Bestellung Berater
+ return 'success';
+ case 2: //Shop
+ return 'secondary';
+ case 4: //Gutschrift
+ if($this->status_turnover === 2){
+ return 'secondary';
+ }else{
+ return 'success';
+ }
+ case 5: //Registrierung
+ return 'success';
+ }
+ return "default";
+ }
+
public function getFormatedMonthYear(){
return str_pad($this->month, 2, "0", STR_PAD_LEFT)."/".$this->year;
}
@@ -197,4 +263,11 @@ class UserSalesVolume extends Model
}
return false;
}
+
+ public function caluCommissonTotalNet($margin){
+ if($this->total_net > 0 && $margin > 0){
+ return $this->total_net / 100 * $margin;
+ }
+ return 0;
+ }
}
\ No newline at end of file
diff --git a/app/Models/UserShop.php b/app/Models/UserShop.php
index 81c2ac36..7351c56a 100644
--- a/app/Models/UserShop.php
+++ b/app/Models/UserShop.php
@@ -76,6 +76,7 @@ class UserShop extends Model
protected $casts = [
'featured' => 'array',
+ 'trans' => 'array',
];
protected $fillable = [
@@ -114,6 +115,29 @@ class UserShop extends Model
return Carbon::parse($this->attributes['active_date'])->format("d.m.Y");
}
+ public function getLang($key, $default = true)
+ {
+ $lang = \App::getLocale();
+ if ($lang == 'de') {
+ return $this->{$key};
+ }
+ return $this->getTrans($key, $lang, $default);
+ }
+
+ public function getTrans($key, $lang, $default = true)
+ {
+ if ($lang == 'de') {
+ return $this->{$key};
+ }
+ if(!empty($this->trans[$lang][$key])){
+ return $this->trans[$lang][$key];
+ }
+ if($default){
+ return !empty($this->{$key}) ? $this->{$key} : '';
+ }
+ return "";
+ }
+
public function getSubdomain($session=true)
{
if($session && \Session::has('user_shop_domain')){
diff --git a/app/Policies/AppServiceProvider.php b/app/Policies/AppServiceProvider.php
new file mode 100755
index 00000000..d1f29286
--- /dev/null
+++ b/app/Policies/AppServiceProvider.php
@@ -0,0 +1,72 @@
+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;
+ }
+}
\ No newline at end of file
diff --git a/app/Policies/ModelPolicy.php b/app/Policies/ModelPolicy.php
new file mode 100755
index 00000000..d1f29286
--- /dev/null
+++ b/app/Policies/ModelPolicy.php
@@ -0,0 +1,72 @@
+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;
+ }
+}
\ No newline at end of file
diff --git a/app/Repositories/CreditRepository.php b/app/Repositories/CreditRepository.php
index 1d06ddaa..cad466f8 100644
--- a/app/Repositories/CreditRepository.php
+++ b/app/Repositories/CreditRepository.php
@@ -7,8 +7,12 @@ use Storage;
use App\User;
use App\Services\Credit;
use App\Models\UserCredit;
-use App\Services\MyPDFMerger;
+use Response;
+use App\Libraries\MyPDFMerger;
use App\Models\UserCreditItem;
+use App\Models\UserSalesVolume;
+use App\Libraries\CreditDetailsPDF;
+use App\Services\BusinessPlan\TreeCalcBot;
class CreditRepository extends BaseRepository {
@@ -87,7 +91,6 @@ class CreditRepository extends BaseRepository {
}
}
-
private function makeUserCredit(){
$this->user_credit->net = 0;
@@ -127,4 +130,240 @@ class CreditRepository extends BaseRepository {
return $user_credit_items;
}
+ /*
+ Erstellt einen detalierten Report zur Gutschrift
+ Alle Postionen werden einzeln aufgelistet
+ //$do ?= html, pdf
+ */
+ public function create_report(UserCredit $user_credit, $do = 'html')
+ {
+ //collect all data
+ $collection = new \stdClass();
+ $collection->calc_bot = [];
+ $collection->commission_shop = [];
+ $collection->commission_payline = [];
+ $collection->commission_growth_bonus = [];
+ $collection->own_order = [];
+ $collection->commission_registration = [];
+ $collection->commission_credit = [];
+
+
+ $dates = [];
+ /* für jede Postion aus der Gutschrift nach Status */
+ foreach($user_credit->user_credit_items as $user_credit_item){
+
+ $date = $user_credit_item->from_month.'-'.$user_credit_item->from_year;
+ if(!isset($dates[$date])){
+ $dates[$date] = ['year' => $user_credit_item->from_year, 'month' => $user_credit_item->from_month];
+ }
+
+ /*
+ //calc bot for the month year
+ */
+ if(!isset($collection->calc_bot[$date])){
+ $TreeCalcBot = new TreeCalcBot($user_credit_item->from_month, $user_credit_item->from_year, 'admin');
+ $TreeCalcBot->initBusinesslUserDetail($user_credit->user);
+ $TreeCalcBot->initStructureUser($user_credit->user->id);
+
+ $collection->calc_bot[$date] = $TreeCalcBot;
+ }
+
+ /*
+ status === 1 commission_shop
+ Auswertung der Shopbestellungen vom User für einen Monat / Jahr
+ Auslistung der Positonen / Gesamter Umsatz / Marge / Provision
+ */
+ if($user_credit_item->status === 1){
+ $user_sales_volumes = UserSalesVolume::where('user_id', $user_credit_item->user_id)
+ ->where('month', $user_credit_item->from_month)
+ ->where('year', $user_credit_item->from_year)
+ ->where('status', 2) //'shoporder', //hinzugefügt aus
+ ->orderBy('id', 'ASC')->get();
+
+ $user_sales_volumes_total = UserSalesVolume::where('user_id', $user_credit_item->user_id)
+ ->where('month', $user_credit_item->from_month)
+ ->where('year', $user_credit_item->from_year)
+ ->where('status', 2) //'shoporder', //hinzugefügt aus
+ ->orderBy('id', 'DESC')->first();
+
+
+
+ $obj = new \stdClass();
+ $obj->user_sales_volumes = $user_sales_volumes;
+ $obj->user_sales_volumes_total = $user_sales_volumes_total;
+ $obj->user_credit_item = $user_credit_item;
+ $collection->commission_shop[$date] = $obj;
+
+ /*
+ UserSalesVolume::status
+ 4 => 'credit', //hinzugefügt aus //VE == status_turnover 2 shop verrechnung
+ Listen der hinzufegügten Gutschriften vom User für einen Monat / Jahr
+ */
+ $user_sales_volumes_credit = UserSalesVolume::where('user_id', $user_credit_item->user_id)
+ ->where('month', $user_credit_item->from_month)
+ ->where('year', $user_credit_item->from_year)
+ ->where('status', 4) //'credit', //hinzugefügt aus
+ ->where('status_turnover', 2) //VE shop
+ ->orderBy('id', 'ASC')->get();
+
+ $collection->commission_credit[$date] = $user_sales_volumes_credit;
+ }
+
+
+
+ /*
+ status === 2 commission_payline
+ Auswertung der Payline nach der Struktur vom User für einen Monat / Jahr
+ Auslistung aller Berater mit Gesamter Umsatz / Provision / rang
+ */
+
+ /*
+ status === 5 commission_growth_bonus
+ Auswertung der Payline nach der Struktur vom User für einen Monat / Jahr
+ Auslistung aller Berater mit Gesamter Umsatz / Provision / rang
+ */
+
+
+ }
+
+ /*
+ nicht enhalten in der Gutschrift
+ für alle Monate / Jahr die in der Gutschrift enthalten sind
+ */
+ foreach($dates as $date => $dateObj){
+ /*
+ UserSalesVolume::status
+ 1 => 'advisor_order', own_order //hinzugefügt aus
+ Listen der Beraterbestellungen vom User für einen Monat / Jahr
+ */
+ $user_sales_volumes = UserSalesVolume::where('user_id', $user_credit_item->user_id)
+ ->where('month', $dateObj['month'])
+ ->where('year', $dateObj['year'])
+ ->where('status', 1) //'own_order', //hinzugefügt aus
+ ->orderBy('id', 'ASC')->get();
+
+ $credit_total_net = UserSalesVolume::where('user_id', $user_credit_item->user_id)
+ ->where('month', $dateObj['month'])
+ ->where('year', $dateObj['year'])
+ ->where('status', 1) //'own_order', //hinzugefügt aus
+ ->sum('total_net'); //sum('total_net');
+
+ $credit_total_points = UserSalesVolume::where('user_id', $user_credit_item->user_id)
+ ->where('month', $dateObj['month'])
+ ->where('year', $dateObj['year'])
+ ->where('status', 1) //'own_order', //hinzugefügt aus
+ ->sum('points'); //sum('points');
+
+ if($user_sales_volumes->count() > 0){
+ $obj = new \stdClass();
+ $obj->user_sales_volumes = $user_sales_volumes;
+ $obj->credit_total_net = $credit_total_net;
+ $obj->credit_total_points = $credit_total_points;
+ $collection->own_order[$date] = $obj;
+ }
+ /*
+ UserSalesVolume::status
+ 5 => 'registration', //hinzugefügt aus
+ Listen der Gutschriften aus Reg vom User für einen Monat / Jahr
+ Enthält nur Punkte wird separat aufgeführt
+ turnover = immer E / 1 verrechnung mit Eigenem Umsatz
+ */
+
+ $user_sales_volumes = UserSalesVolume::where('user_id', $user_credit_item->user_id)
+ ->where('month', $dateObj['month'])
+ ->where('year', $dateObj['year'])
+ ->where('status', 5) //'registration', //hinzugefügt aus
+ ->orderBy('id', 'ASC')->get();
+
+ $credit_total_net = UserSalesVolume::where('user_id', $user_credit_item->user_id)
+ ->where('month', $dateObj['month'])
+ ->where('year', $dateObj['year'])
+ ->where('status', 5) //'registration', //hinzugefügt aus
+ ->sum('total_net'); //sum('total_net');
+
+ $credit_total_points = UserSalesVolume::where('user_id', $user_credit_item->user_id)
+ ->where('month', $dateObj['month'])
+ ->where('year', $dateObj['year'])
+ ->where('status', 5) //'registration', //hinzugefügt aus
+ ->sum('points'); //sum('points');
+
+ if($user_sales_volumes->count() > 0){
+ $obj = new \stdClass();
+ $obj->user_sales_volumes = $user_sales_volumes;
+ $obj->credit_total_net = $credit_total_net;
+ $obj->credit_total_points = $credit_total_points;
+ $collection->commission_registration[$date] = $obj;
+ }
+
+ }
+
+
+
+ /*
+ //need this?
+ $user_credit_item->status = 3; //credit_added
+ $user_credit_item->status = 4; //commission
+ */
+
+ $data = [
+ 'dates' => $dates,
+ 'user_credit' => $user_credit,
+ 'collection' => $collection,
+ ];
+ if($do === 'html'){
+ return view('admin.payment.credit_detail', $data);
+ }
+
+ if($do === 'pdf'){
+
+
+ $dir = Credit::getCreditDetailStorageDir($user_credit->date);
+ if(!Storage::disk('public')->exists( $dir )){
+ Storage::disk('public')->makeDirectory($dir); //creates directory
+ }
+ $path = Storage::disk('public')->getAdapter()->getPathPrefix();
+ $filename = Credit::makeCreditDetailFilename($user_credit->full_number);
+
+ $pdf = new CreditDetailsPDF('pdf.credit_details');
+ //return $pdf->create($data, 'credit_details.pdf', 'stream');
+
+ $pdf->create($data, $filename, 'save', $path.$dir);
+
+
+ /*$pdf = PDF::loadView('pdf.credit', $data);
+ $pdf->setPaper('A4', 'portrait');
+ $pdf->save($path.$dir.$filename);*/
+
+ $pdfMerger = new MyPDFMerger();
+ $pdfMerger->addPDF($path.$dir.$filename);
+ $file = $pdfMerger->myMerge('string', $filename, 'template_report_de');
+ Storage::disk('public')->put($dir.$filename, $file);
+ $path = $dir.$filename;
+ //$file = Storage::disk('public')->get($path);
+ $mime = Storage::disk('public')->mimeType($path);
+
+ return Response::make($file, 200)
+ ->header("Content-Type", $mime)
+ ->header('Content-disposition','inline; filename="'.$filename.'"');
+
+
+ //return $dir.$filename;
+ /*
+ $dir = Credit::getCreditStorageDir($credit_date);
+ if(!Storage::disk('public')->exists( $dir )){
+ Storage::disk('public')->makeDirectory($dir); //creates directory
+ }
+ $path = Storage::disk('public')->getAdapter()->getPathPrefix();
+
+ $filename = Credit::makeCreditFilename($credit_number);
+
+ $pdf->save($path.$dir.$filename);
+
+ $pdfMerger = new MyPDFMerger();
+ $pdfMerger->addPDF($path.$dir.$filename);
+ $file = $pdfMerger->myMerge('string', $filename, 'template_invoice_de');
+ Storage::disk('public')->put($dir.$filename, $file);
+ */
+ }
+ }
}
\ No newline at end of file
diff --git a/app/Repositories/DC/FileRepository.php b/app/Repositories/DC/FileRepository.php
new file mode 100644
index 00000000..054f4321
--- /dev/null
+++ b/app/Repositories/DC/FileRepository.php
@@ -0,0 +1,151 @@
+getClientOriginalName();
+ $extension = $file->getClientOriginalExtension();
+ $mine = $file->getClientMimeType();
+ $size = $file->getSize();
+
+ $originalNameWithoutExt = substr($originalName, 0, strlen($originalName) - strlen($extension) - 1);
+ $filename = Util::sanitize($originalNameWithoutExt, true, false, true);
+ $allowed_filename = uniqid() . '_' . $filename.".".$extension;
+ $file->storeAs('dc/files', $allowed_filename, 'public');
+ // $store = $file->store('files/');
+
+ $dc_file = DcFile::create([
+ 'filename' => $allowed_filename,
+ 'original_name' => $originalName,
+ 'ext' => $extension,
+ 'mine' => $mine,
+ 'size' => $size
+ ]);
+ $this->makeThumbFromFile($dc_file);
+ return $dc_file;
+ }
+
+ public function makeThumb($id){
+ $file = DcFile::findOrFail($id);
+ $this->makeThumbFromFile($file);
+ }
+
+ public function makeThumbFromFile($file)
+ {
+ $path = $file->getFile(true);
+ $filename = $file->filename;
+ $mine = \File::mimeType($path);
+ //make thumb
+ $allowedMimeTypes = ['image/jpeg','image/gif','image/png'];
+ if (in_array($mine, $allowedMimeTypes)) {
+ $img = Image::make($path);
+ $img->resize(542, 360, function ($c) {
+ $c->aspectRatio();
+ $c->upsize();
+ });
+ \Storage::disk('public')->put('dc/thumb/'.basename($filename), (string) $img->encode());
+
+ $img = Image::make($path);
+ $img->resize(1600, 900, function ($c) {
+ $c->aspectRatio();
+ $c->upsize();
+ });
+ \Storage::disk('public')->put('dc/big/'.basename($filename), (string) $img->encode());
+ }
+
+ $allowedMimeTypes = ['application/pdf'];
+ if (in_array($mine, $allowedMimeTypes)) {
+ $imagick = new \Imagick ($path.'[0]'); // 0 specifies the first page of the pdf
+ $imagick->setImageBackgroundColor('#ffffff');
+ $imagick = $imagick->mergeImageLayers( Imagick::LAYERMETHOD_FLATTEN );
+ $imagick->setImageFormat('jpg'); // set the format of the output image
+ $imagick->setImageCompression(\Imagick::COMPRESSION_JPEG);
+ $imagick->setImageCompressionQuality(60);
+
+ $imagick->resizeImage(1600, 900, \Imagick::FILTER_LANCZOS, 1,1);
+ $filestore = \Storage::disk('public')->path('dc/big/').basename($filename).".jpg";
+ $imagick->writeImage($filestore);
+
+ $imagick->resizeImage(542, 360, \Imagick::FILTER_LANCZOS, 1,1);
+ $filestore = \Storage::disk('public')->path('dc/thumb/').basename($filename).".jpg";
+ $imagick->writeImage($filestore);
+
+ }
+
+ return true;
+ }
+
+ public function tagsUpdate($id, $tags){
+ $file = DcFile::findOrFail($id);
+ $file_tags = DcFileTag::where('file_id', $file->id)->get();
+
+ //remove Tags
+ foreach ($file_tags as $file_tag) {
+ if(is_array($tags) && ($pos = array_search($file_tag->tag_id, $tags)) !== FALSE){
+ unset($tags[$pos]);
+ }else{
+ $file_tag->delete();
+ }
+ }
+ //set taTagsgs
+ if(is_array($tags)){
+ foreach ($tags as $key => $tag_id) {
+ DcFileTag::create([
+ 'file_id' => $file->id,
+ 'tag_id' => $tag_id
+ ]);
+ }
+ }
+ return true;
+ }
+
+ public function deleteThumb($id){
+ $file = DcFile::findOrFail($id);
+ $path_thumb = $file->getThumb(true);
+ if (file_exists($path_thumb)) {
+ unlink($path_thumb);
+ }
+ $path_big = $file->getBig(true);
+ if (file_exists($path_big)) {
+ unlink($path_big);
+ }
+ return true;
+ }
+
+ public function deleteFile($id){
+ $file = DcFile::findOrFail($id);
+ $path_thumb = $file->getThumb(true);
+ if (file_exists($path_thumb)) {
+ unlink($path_thumb);
+ }
+ $path_big = $file->getBig(true);
+ if (file_exists($path_big)) {
+ unlink($path_big);
+ }
+ $path = $file->getFile(true);
+ if (file_exists($path)) {
+ unlink($path);
+ }
+ $file->delete();
+ return true;
+ }
+
+}
\ No newline at end of file
diff --git a/app/Repositories/DC/TagRepository.php b/app/Repositories/DC/TagRepository.php
new file mode 100644
index 00000000..89d6389a
--- /dev/null
+++ b/app/Repositories/DC/TagRepository.php
@@ -0,0 +1,141 @@
+name = $data['dc_category_name'];
+ $category->pos = 0 ;
+ $category->save();
+ \Session()->flash('alert-success', 'Kategorie erstellt');
+ return redirect(route('admin_downloadcenter_tags'));
+ }
+
+ if($obj === 'tag' && isset($data['dc_tag_name'])){
+ $data = Request::all();
+ $tag = new DcTag;
+ $tag->name = $data['dc_tag_name'];
+ $tag->pos = 0;
+ $tag->save();
+ \Session()->flash('alert-success', 'Tag erstellt');
+ return redirect(route('admin_downloadcenter_tags'));
+ }
+ if($obj === 'structure' && isset($data['nestable'])){
+ $bool = $this->updateStructure($data);
+ if(Request::ajax()){
+ return response()->json([
+ 'success' => $bool,
+ 'redirect' => route('admin_downloadcenter_tags', ['flash' => true])
+ ]);
+ }
+ }
+ if($obj === 'update_ajax' && isset($data['action'])){
+
+ $active = $this->updateAjax($data);
+ if(Request::ajax()){
+ return response()->json([
+ 'success' => $data['action'],
+ 'active' => $active,
+ ]);
+ }
+ }
+ return true;
+ }
+
+ protected function updateAjax($data){
+
+ if($data['action'] == 'update-tag-active' && isset($data['id'])){
+ $tag = DcTag::findOrFail($data['id']);
+ $tag->active = $tag->active ? 0 : 1;
+ $tag->save();
+ return $tag->active;
+
+ }
+ if($data['action'] == 'update-category-active' && isset($data['id'])){
+ $category = DcCategory::findOrFail($data['id']);
+ $category->active = $category->active ? 0 : 1;
+ $category->save();
+ return $category->active;
+ }
+ return false;
+ }
+
+ protected function updateStructure($data)
+ {
+ if(empty($data['nestable']) || !is_array($data['nestable'])){
+ return false;
+ }
+ $tags = DcTag::all();
+ foreach ($tags as $value) {
+ $value->category_id = null;
+ $value->pos = NULL;
+ $value->save();
+ }
+ $this->saveStructureLevel($data['nestable']);
+ return true;
+ }
+
+ protected function saveStructureLevel($nestable, $deep = 0, $category_id = false){
+
+ foreach ($nestable as $key => $value) {
+ if($value['id'] == 0){
+ continue;
+ }
+ if($deep == 0){
+ $cat = DcCategory::findOrFail($value['id']);
+ $cat->pos = $key;
+ $cat->save();
+ }
+
+ if($deep == 1){
+ $tag = DcTag::findOrFail($value['id']);
+ $tag->category_id = $category_id;
+ $tag->pos = $key;
+ $tag->save();
+
+ }
+ if(!empty($value['children'])){
+ $this->saveStructureLevel($value['children'], $deep+1, $value['id']);
+ }
+ }
+ }
+
+ public function deleteItem($obj, $id){
+ if($obj == 'category'){
+ $this->deleteCategory($id);
+ }
+ if($obj == 'tag'){
+ $this->deleteTag($id);
+ }
+ }
+
+ public function deleteCategory($id){
+ $cat = DcCategory::findOrFail($id);
+ $tags = DcTag::where('category_id', $cat->id)->get();
+ foreach ($tags as $tag) {
+ $this->deleteTag($tag->id);
+ }
+ $cat->delete();
+ }
+
+ public function deleteTag($id){
+ $tag = DcTag::findOrFail($id);
+ $tag->delete();
+ }
+
+}
\ No newline at end of file
diff --git a/app/Repositories/FileRepository.php b/app/Repositories/FileRepository.php
index e6a850d1..d64f497b 100644
--- a/app/Repositories/FileRepository.php
+++ b/app/Repositories/FileRepository.php
@@ -84,7 +84,7 @@ class FileRepository extends BaseRepository {
'error' => false,
'filename' => $allowed_filename,
'filedata' => 'pdf',
- 'redirect' => route('wizard_register'),
+ 'redirect' => $form_data['redirect'],
'code' => 200
], 200);
}
diff --git a/app/Repositories/ImportRepository.php b/app/Repositories/ImportRepository.php
index 097ab752..2a21a510 100644
--- a/app/Repositories/ImportRepository.php
+++ b/app/Repositories/ImportRepository.php
@@ -59,8 +59,6 @@ class ImportRepository extends BaseRepository {
return false;
}
return $this->import(storage_path("app/import/").$file, $file, $skip, $limit);
-
-
}
protected function import($file_path, $file, $skip, $limit){
diff --git a/app/Repositories/InvoiceRepository.php b/app/Repositories/InvoiceRepository.php
index 7146649d..8c8606c8 100644
--- a/app/Repositories/InvoiceRepository.php
+++ b/app/Repositories/InvoiceRepository.php
@@ -8,7 +8,7 @@ use App\Services\Invoice;
use App\Models\UserInvoice;
use App\Libraries\InvoicePDF;
use App\Models\ShoppingOrder;
-use App\Services\MyPDFMerger;
+use App\Libraries\MyPDFMerger;
use App\Services\UserService;
use App\Models\UserSalesVolume;
use App\Services\BusinessPlan\SalesPointsVolume;
diff --git a/app/Repositories/ShopApiRepository.php b/app/Repositories/ShopApiRepository.php
index 450b7d27..588527e0 100644
--- a/app/Repositories/ShopApiRepository.php
+++ b/app/Repositories/ShopApiRepository.php
@@ -79,6 +79,7 @@ class ShopApiRepository extends BaseRepository {
'payment' => 2, //Berater Shop
'subdomain' => url('/'),
'country_id' => Yard::instance('shopping')->getShippingCountryId(),
+ 'language' => \App::getLocale(),
'shopping_data' => $data,
'back' => route('user_shop_api_orders'),
diff --git a/app/Repositories/UserRepository.php b/app/Repositories/UserRepository.php
index e3b60faa..eeba363a 100644
--- a/app/Repositories/UserRepository.php
+++ b/app/Repositories/UserRepository.php
@@ -2,14 +2,15 @@
namespace App\Repositories;
+use Util;
+use Request;
use App\User;
+use Validator;
+use App\Services\UserUtil;
use App\Models\UserAccount;
use App\Models\PaymentMethod;
use Illuminate\Support\Facades\Hash;
use App\Http\Controllers\Api\KasController;
-use Util;
-use Validator;
-use Request;
class UserRepository extends BaseRepository {
@@ -77,80 +78,56 @@ class UserRepository extends BaseRepository {
public function deleteUser(User $user)
{
- if($user->account){
- $user->account->delete();
+ $active_sponsor = UserUtil::findNextActiveSponsor($user->id);
+ if($active_sponsor){
+ UserUtil::setNewSponsorToChilds($user->id, $active_sponsor->id);
+ UserUtil::setShoppingUserToNewMember($user->id, $active_sponsor->id);
}
- if($user->shop){
- $subdomain_name = $user->shop->slug.'.mivita.care';
- $user->shop->name = "delete".$user->shop->id;
- $user->shop->slug = "delete".$user->shop->id;
- $user->shop->save();
- $user->shop->delete();
- //isset KAS - delete Subdomain
- if(!Util::isTestSystem()){
- $kas = new KasController();
- $pra = array(
- 'subdomain_name' => $subdomain_name,
- );
- $kas->action('delete_subdomain', $pra);
- }
-
- }
- $user->email = "delete".time();
- $user->password = "delete".time();
- $user->confirmed = 0;
- $user->confirmation_code = "delete".time();
- $user->confirmation_date = null;
- $user->confirmation_code_to = null;
- $user->confirmation_code_remider = 2;
- $user->agreement = null;
- $user->active = 0;
- $user->remember_token = '';
- $user->active_date = null;
- $user->admin = 0;
- $user->deleted_at = now();
- $user->save();
-
- return true;
+ UserUtil::deleteUser($user);
}
- public function reverse_charge_validate($data, $user){
- if(isset($data['reverse_charge_validate'])){
+ public function reverse_charge_validate($data, $user, $route){
+ if(isset($data['action']) && $data['action'] == 'reverse_charge_validate'){
$rules = array(
'tax_identification_number' => 'required',
- 'reverse_charge' => 'required',
);
$validator = Validator::make($data, $rules);
if ($validator->fails()) {
$data = [
'user' => $user,
];
- return view('user.edit', $data)->withErrors($validator);
+ return redirect($route.'#user-vat-validation')->withErrors($validator)->withInput($data);
}
$ret = $this->reverse_charge_activate($data, $user);
if($ret === 'error'){
$validator = Validator::make($data, []);
- $validator->errors()->add('tax_identification_number', __('Die UST-ID konnte nicht validiert werden, Eingabe bitte prüfen.'));
+ $validator->errors()->add('tax_identification_number_validated', __('msg.VATID_could_not_be_validated'));
$data['reverse_charge'] = 0;
- return redirect(route('user_edit'))->withErrors($validator)->withInput($data);
+ $data = [
+ 'user' => $user,
+ ];
+ return redirect($route.'#user-vat-validation')->withErrors($validator)->withInput($data);
}
if($ret === 'valid'){
- \Session()->flash('alert-success', 'UST-ID erfolgreich eingetragen.');
- return redirect('/user/edit');
+ \Session()->flash('alert-success', __('msg.VATID_successfully_entered'));
+ return redirect($route.'#user-vat-validation')->withInput($data);
+
+ return redirect($route.'#user-vat-validation')->withInput($data);
}
}
}
- public function reverse_charge_delete($data, $user){
- if(isset($data['reverse_charge_delete'])){
+ public function reverse_charge_delete($data, $user, $route){
+ if(isset($data['action']) && $data['action'] == 'reverse_charge_delete'){
$user->account->tax_identification_number = '';
$user->account->reverse_charge = 0;
$user->account->reverse_charge_code = null;
$user->account->reverse_charge_valid = null;
$user->account->save();
- \Session()->flash('alert-success', 'Reverse Charge Verfahren und UST-ID gelöscht.');
- return redirect('/user/edit');
+ $data['tax_identification_number'] = '';
+ \Session()->flash('alert-success', __('msg.reverse_charge_procedure_and_VATID_deleted'));
+ return redirect($route.'#user-vat-validation')->withInput($data);
}
}
@@ -221,7 +198,5 @@ class UserRepository extends BaseRepository {
} else {
return 'error';
}
-
-
}
}
\ No newline at end of file
diff --git a/app/Services/AboHelper.php b/app/Services/AboHelper.php
new file mode 100644
index 00000000..dfcca27d
--- /dev/null
+++ b/app/Services/AboHelper.php
@@ -0,0 +1,48 @@
+payment_transactions->last();
+ $user_abo = UserAbo::create([
+ 'user_id' => $shopping_payment->shopping_order->auth_user_id,
+ 'shopping_user_id' => $shopping_payment->shopping_order->shopping_user_id,
+ 'is_for' => $shopping_payment->shopping_order->shopping_user->is_for,
+ 'payone_userid' => $payment_transaction->userid,
+ 'clearingtype' => $shopping_payment->clearingtype,
+ 'wallettype' => $shopping_payment->wallettype,
+ 'amount' => $shopping_payment->amount,
+ 'currency' => $shopping_payment->currency,
+ 'status' => 1,
+ 'abo_interval' => $shopping_payment->abo_interval,
+ 'start_date' => now(),
+ 'last_date' => now(),
+ 'next_date' => now()->addWeeks($shopping_payment->abo_interval),
+ 'next_abo_date' => $shopping_payment->created_at->addMonths($shopping_payment->abo_interval),
+ 'count' => 1,
+ ]);
+ if($user_abo){
+ UserAboOrder::create([
+ 'user_abo_id' => $user_abo->id,
+ 'shopping_order_id' => $shopping_payment->shopping_order_id,
+ 'status' => 1,
+ ]);
+ }
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/Services/BusinessPlan/BusinessTreeUserItem.php b/app/Services/BusinessPlan/BusinessTreeUserItem.php
deleted file mode 100644
index ec59ebea..00000000
--- a/app/Services/BusinessPlan/BusinessTreeUserItem.php
+++ /dev/null
@@ -1,172 +0,0 @@
-date = $date;
- return $this;
- }
-
- public function makeUser(User $user){
-
- $this->user_level_active = $user->user_level ? $user->user_level : null;
- $this->b_user = new UserBusiness();
- $fill = [
- 'user_id' => $user->id,
- 'month' => $this->date->month,
- 'year' => $this->date->year,
- 'm_level' => $user->m_level,
- 'm_sponsor' => $user->m_sponsor,
- 'user_level_name' => $user->user_level ? $user->user_level->name : '',
- 'active_account' => $user->payment_account ? Carbon::parse($user->payment_account)->gt(Carbon::parse($this->date->start_date)) : false,
- 'payment_account_date' => $user->payment_account ? $user->getPaymentAccountDateFormat(false) : NULL,
- 'active_date' => $user->active_date ? $user->active_date : NULL,
- 'm_account' => $user->account->m_account,
- 'email' => $user->email,
- 'first_name' => $user->account->first_name,
- 'last_name' => $user->account->last_name,
- 'sales_volume_points' => $user->getUserSalesVolumeBy($this->date->month, $this->date->year, 'sales_volume_points'),
- 'sales_volume_points_shop' => $user->getUserSalesVolumeBy($this->date->month, $this->date->year, 'sales_volume_points_shop'),
- 'sales_volume_points_sum' => $user->getUserSalesVolumeBy($this->date->month, $this->date->year, 'sales_volume_points_sum'),
- 'sales_volume_total' => $user->getUserSalesVolumeBy($this->date->month, $this->date->year, 'sales_volume_total'),
- 'sales_volume_total_shop' => $user->getUserSalesVolumeBy($this->date->month, $this->date->year, 'sales_volume_total_shop'),
- 'sales_volume_total_sum' => $user->getUserSalesVolumeBy($this->date->month, $this->date->year, 'sales_volume_total_sum'),
- 'margin' => $user->user_level_active ? $user->user_level_active->margin : 0,
- 'margin_shop' => $user->user_level_active ? $user->user_level_active->margin_shop : 0,
- 'qual_kp' => $user->user_level_active ? $user->user_level_active->qual_kp : 0,
- 'qual_tp' => $user->user_level_active ? $user->user_level_active->qual_tp : 0,
- ];
- $this->b_user->fill($fill);
- }
-
- public function addUserID(){
- TreeCalcBot::addUserID($this->user_id);
- }
-
- public function isQualKP(){
- return ($this->sales_volume_points_sum >= $this->qual_kp) ? true : false;
- }
-
- public function getRestQualKP(){
- return $this->sales_volume_points_sum - $this->qual_kp;
- }
-
- public function checkSponsor(){
- if($this->m_sponsor === null){
- $this->m_sponsor_name = 'Keinen Sponsor zugewiesen';
- return;
- }
- $user = User::find($this->m_sponsor);
- if($user){
- if($user->account){
- $this->m_sponsor_name = substr('Sponsor: '.$user->account->first_name.' '.$user->account->last_name.' | '.$user->email.' | '.$user->account->m_account, 0, 190);
- }else{
- $this->m_sponsor_name = 'Sponsor: '.$user->email;
- }
- return;
- }
- $this->m_sponsor_name = 'Sponsor wurde gelöscht.';
- return;
- }
- /*
-
- 'total_tp' => ,
- 'total_qual_tp' => ,
- 'commission_total' => ,
- 'lines',
- 'items',
- 'qual_user_level_id'
- */
- public function readParentsUser(){
-
- $users = User::with('account')->select('users.*')
- ->where('users.deleted_at', '=', null)
- ->where('users.id', '!=', 1)
- ->where('users.admin', "<", 4)
- ->where('users.m_level', "!=", null)
- ->where('users.m_sponsor', "=", $this->user_id) //<- need the id for parents / sponsors
- ->where('users.payment_account', "!=", null)
- ->where('users.active_date', "<=", $this->date->end_date)
- ->get();
- dd($users);
- if($users){
- foreach($users as $user){
- $TreeUserItem = new TreeUserItem($this->date);
- $TreeUserItem->makeUser($user);
- $TreeUserItem->addUserID();
- $this->items[] = $TreeUserItem;
- }
- }
-
- foreach($this->items as $item){
- $item->readParentsUser();
- }
-
- }
-
-
- public function calcUserTP($line){
- if(!isset($this->lines[$line])){
- $this->lines[$line] = new stdClass();
- $this->lines[$line]->points = 0;
- }
- foreach($this->items as $item){
- if(count($item->items) > 0){
- $this->calcUserTP($line+1);
- }
- $this->lines[$line]->points += $item->sales_volume_points_sum;
- $this->total_tp += $item->sales_volume_points_sum;
-
- }
- }
-
-
- public function calcQualTP(){
- if($this->isQualKP()){
- $this->total_qual_tp = $this->total_tp + $this->getRestQualKP();
- $this->qual_user_level = UserLevel::where('qual_tp', '<=', $this->total_qual_tp)->where('pos', '<=', $this->user->user_level->pos)->orderBy('qual_tp', 'desc')->first();
- $this->commission_total = 0;
- if($this->qual_user_level){
- foreach($this->lines as $line => $values){
- $values->margin = $this->qual_user_level->{'pr_line_'.$line};
- if($line > 6){
- //wachstumsbonus
- $values->margin = $this->qual_user_level->growth_bonus;
- }
- $values->commission = round($values->points / 100 * $values->margin, 2);
-
- $this->commission_total += $values->commission;
- $this->lines[$line] = $values;
- }
- }
- }
- }
-
-
- public function __get($property) {
- if (property_exists($this->b_user, $property)) {
- return $this->b_user->$property;
- }
- if (isset($this->b_user->{$property})) {
- return $this->b_user->{$property};
- }
- }
-
-}
diff --git a/app/Services/BusinessPlan/BusinessUserItem.php b/app/Services/BusinessPlan/BusinessUserItem.php
index 2367c920..86017a22 100644
--- a/app/Services/BusinessPlan/BusinessUserItem.php
+++ b/app/Services/BusinessPlan/BusinessUserItem.php
@@ -6,6 +6,7 @@ use stdClass;
use Carbon\Carbon;
use App\Models\UserLevel;
use App\Models\UserBusiness;
+use App\Services\TranslationHelper;
use App\Models\UserBusinessStructure;
@@ -27,7 +28,7 @@ class BusinessUserItem
public function makeUser($user_id){
- //check for user an load
+ //check for user an load is saved
$this->b_user = UserBusiness::where('user_id', $user_id)->where('month', $this->date->month)->where('year', $this->date->year)->first();
if($this->b_user !== null){
return;
@@ -53,6 +54,8 @@ class BusinessUserItem
'email' => $user->email,
'first_name' => $user->account->first_name,
'last_name' => $user->account->last_name,
+ 'user_birthday' => $user->account->birthday,
+ 'user_phone' => $user->account->getPhoneNumber(),
'sales_volume_KP_points' => $user->getUserSalesVolumeBy($this->date->month, $this->date->year, 'sales_volume_KP_points'),
'sales_volume_TP_points' => $user->getUserSalesVolumeBy($this->date->month, $this->date->year, 'sales_volume_TP_points'),
@@ -83,6 +86,11 @@ class BusinessUserItem
}
+
+ public function getSalesVolumeTotalMargin(){
+ return $this->b_user->getSalesVolumeTotalMargin();
+ }
+
public function addUserID(){
TreeCalcBot::addUserID($this->b_user->user_id);
}
@@ -239,14 +247,17 @@ class BusinessUserItem
$qualUserLevelNext = UserLevel::where('id', '=', $this->b_user->qual_user_level['next_id'])->orderBy('qual_pp', 'asc')->first();
if($qualUserLevelNext){
$this->b_user->qual_user_level_next = $qualUserLevelNext->toArray();
+
}
}
}
private function setNextUserLevel(){
- dd($this->b_user->payline_points_qual_kp);
- $this->b_user->total_qual_pp = $this->total_pp + $this->getRestQualKP();
- $nextQualUserLevel = UserLevel::where('qual_pp', '<=', $this->total_qual_pp)->where('pos', '>', $this->user_level_active_pos)->orderBy('qual_pp', 'desc')->first();
+ // $this->b_user->payline_points_qual_kp // das sind die Payline Points + Rest KP
+ //$this->b_user->total_qual_pp = $this->total_pp + $this->getRestQualKP(); //hier werden alle Linien TP gezähle
+ //$this->b_user->total_qual_pp = $this->total_pp + $this->getRestQualKP(); //hier werden alle Linien TP gezähle
+
+ $nextQualUserLevel = UserLevel::where('qual_pp', '<=', $this->payline_points_qual_kp)->where('pos', '>', $this->user_level_active_pos)->orderBy('qual_pp', 'desc')->first();
if($nextQualUserLevel && $this->isQualKP()){
$this->b_user->next_qual_user_level = $nextQualUserLevel->toArray();
}else{
@@ -289,7 +300,7 @@ class BusinessUserItem
->where('users.m_level', "!=", null)
->where('users.m_sponsor', "=", $this->b_user->user_id) //<- need the id for parents / sponsors
->where('users.payment_account', "!=", null)
- ->where('users.active_date', "<=", $this->date->end_date)
+ ->where('users.active_date', "<=", $this->date->end_date) // wurde in dem Monat freigeschaltet
->get();
if($users){
diff --git a/app/Services/BusinessPlan/ExportBot.php b/app/Services/BusinessPlan/ExportBot.php
index 1fde3b2c..0d6a9366 100644
--- a/app/Services/BusinessPlan/ExportBot.php
+++ b/app/Services/BusinessPlan/ExportBot.php
@@ -79,7 +79,7 @@ class ExportBot
$obj->user_id = $user->id;
$obj->m_level = $user->m_level;
- $obj->level_name = $user->user_level ? $user->user_level->name : '';
+ $obj->level_name = $user->user_level ? $user->user_level->getLang('name') : '';
$obj->m_sponsor = $user->m_sponsor;
$obj->sponsor_name = $sponsor_name;
$obj->m_account = $user->m_account;
@@ -92,7 +92,7 @@ class ExportBot
$obj->address_2 = $user->account->address_2;
$obj->zipcode = $user->account->zipcode;
$obj->city = $user->account->city;
- $obj->country_id = $user->account->country_id ? $user->account->country->de : "";
+ $obj->country_id = $user->account->country_id ? $user->account->country->getLocated() : "";
$pre_phone = $user->account->pre_phone_id != "" ? $user->account->pre_phone->phone." " : "";
$pre_mobil = $user->account->pre_mobil_id != "" ? $user->account->pre_mobil->phone." " : "";
$obj->phone = $pre_phone.$user->account->phone;
diff --git a/app/Services/BusinessPlan/SalesPointsVolume.php b/app/Services/BusinessPlan/SalesPointsVolume.php
index 147c1a0d..ab100c46 100644
--- a/app/Services/BusinessPlan/SalesPointsVolume.php
+++ b/app/Services/BusinessPlan/SalesPointsVolume.php
@@ -84,9 +84,16 @@ class SalesPointsVolume
break;
case 4: //Gutschrift
$month_points = self::add_KP_TP_Points($userSalesVolume, $month_points);
- $month_total_net += $userSalesVolume->total_net;
+
+ if($userSalesVolume->status_turnover === 2){
+ $month_shop_total_net += $userSalesVolume->total_net;
+ //ggf hier zu den Shop Points zählen wäre aber immer KP + TP kann nicht keine trennung bei month_shop_points
+ }else{
+ $month_total_net += $userSalesVolume->total_net;
+ }
+
break;
- case 4: //Registrierung
+ case 5: //Registrierung
$month_points = self::add_KP_TP_Points($userSalesVolume, $month_points);
$month_total_net += $userSalesVolume->total_net;
break;
@@ -138,6 +145,8 @@ class SalesPointsVolume
self::reCalculateSalesPointsVolume($user_sales_volume->user_id, $user_sales_volume->month, $user_sales_volume->year);
}
+ return $user_sales_volume;
+
}
public static function setToUserAndReCalculate(UserSalesVolume $user_sales_volume, $user_id){
@@ -186,9 +195,10 @@ class SalesPointsVolume
$user_sales_volume->message = 'geändert: '.date('d.m.Y');
$user_sales_volume->info = $data['info'];
$user_sales_volume->status_points = $data['status_points'];
+ $user_sales_volume->status_turnover = isset($data['status_turnover']) ? intval($data['status_turnover']) : null;
$syslog = $user_sales_volume->syslog;
- $syslog[date('d.m.Y-h:i:s')] = 'edit points: #'.$old_points.' '.$user_sales_volume->points .' total: #'.$old_total_net.' '.$user_sales_volume->total_ne;
+ $syslog[date('d.m.Y-h:i:s')] = 'edit points: #'.$old_points.' '.$user_sales_volume->points .' total: #'.$old_total_net.' '.$user_sales_volume->total_net;
$user_sales_volume->syslog = $syslog;
$user_sales_volume->save();
@@ -216,6 +226,7 @@ class SalesPointsVolume
$points = isset($data['points']) ? intval($data['points']) : 0;
$syslog[date('d.m.Y-h:i:s')] = 'add points: #'.$points.' total: #'.$total_net;
$status = isset($data['status']) ? intval($data['status']) : 4;
+ $status_turnover = isset($data['status_turnover']) ? intval($data['status_turnover']) : null;
$user_sales_volume = UserSalesVolume::create([
'user_id' => $user->id,
@@ -225,6 +236,7 @@ class SalesPointsVolume
'date' => $date,
'points' => $points,
'status_points' => $data['status_points'],
+ 'status_turnover' => $status_turnover,
'total_net' => $total_net,
'message' => 'hinzugefügt: '.date('d.m.Y'),
'info' => $data['info'],
diff --git a/app/Services/BusinessPlan/SalesPointsVolumeHelper.php b/app/Services/BusinessPlan/SalesPointsVolumeHelper.php
index 27a65449..71d8e632 100644
--- a/app/Services/BusinessPlan/SalesPointsVolumeHelper.php
+++ b/app/Services/BusinessPlan/SalesPointsVolumeHelper.php
@@ -7,6 +7,130 @@ use App\Models\UserSalesVolume;
class SalesPointsVolumeHelper
{
-
+
+ //protected static $business_users_table = [];
+ /*
+ $sort = 'structur' || 'line'
+ structur: nach baumstruktur sortiert, wird übergeben
+ line: nach reihenfolge sortiert,
+ */
+ private static $business_users_line = [];
+
+ private static $cbot = null;
+
+
+ public static function getBusinessUsersTable($cbot, $sort = 'structur'){
+
+ self::$cbot = $cbot;
+ if($sort == 'structur'){
+ return self::getBusinessUsersTableStructur();
+ }
+ if($sort == 'line'){
+ return self::getBusinessUsersTableLine();
+ }
+
+
+ }
+ /* getBusinessUsersTableStructur */
+ private static function getBusinessUsersTableStructur(){
+ $deep = 0;
+ $ret = "";
+ foreach(self::$cbot->business_users as $business_user){
+
+ $ret .= self::addTableItemStructur($business_user, $deep);
+ }
+ return $ret;
+ }
+
+ private static function addTableItemStructur($item, $deep) {
+ $ret = self::setTableHTMLItemStructur($item, $deep);
+ if($item->businessUserItems){
+ foreach($item->businessUserItems as $parent){
+ $ret .= self::addTableItemStructur($parent, $deep+1);
+ }
+ }
+ return $ret;
+ }
+
+ private static function setTableHTMLItemStructur($item, $deep){
+
+ $pp = '';
+ $margin = 0;
+ $points = $item->sales_volume_points_KP_sum;
+ $commission = 0;
+ if($deep > 0){
+ $pp = str_repeat(' ', $deep-1).''.$deep.'. '.__('team.PP').'';
+ $margin = self::$cbot->getKeybyLine($deep, 'margin');
+ $commission = $points / 100 * $margin;
+ }
+
+ $ret = '
+ '.$pp.'
+ '.$item->first_name.' '.$item->last_name.'
+
+ '.formatNumber($points, 0).' €
+ '.formatNumber($margin, 1).' %
+ '.formatNumber($commission, 2).' €
+ '.$item->user_level_name.'
+ ';
+
+ return $ret;
+ }
+
+ private static function getBusinessUsersTableLine(){
+ $deep = 0;
+ $ret = "";
+ foreach(self::$cbot->business_users as $business_user){
+ self::addTableItemLine($business_user, $deep);
+ }
+ foreach(self::$business_users_line as $deep => $items){
+ foreach($items as $item){
+ $ret .= self::setTableHTMLItemLine($item, $deep);
+ }
+ }
+ return $ret;
+ }
+ private static function addTableItemLine($item, $deep) {
+ $item->deep = $deep;
+ self::$business_users_line[$deep][] = $item;
+ if($item->businessUserItems){
+ foreach($item->businessUserItems as $parent){
+ self::addTableItemLine($parent, $deep+1);
+ }
+ }
+ }
+
+ private static function setTableHTMLItemLine($item, $deep){
+
+ $pp = '';
+ $margin = 0;
+ $points = $item->sales_volume_points_KP_sum;
+ $commission = 0;
+ if($deep > 0){
+ $pp = ''.$deep.'. '.__('team.PP').'';
+ $margin = self::$cbot->getKeybyLine($deep, 'margin');
+ $commission = $points / 100 * $margin;
+ }
+ //
+ /*
+ {{__('tables.line')}}
+ {{ __('shop.name') }}
+ {{__('tables.points')}}
+ {{__('tables.commission')}} %
+ {{__('tables.commission')}} €
+ {{ __('tables.level') }}
+ */
+ $ret = '
+ '.$pp.'
+ '.$item->first_name.' '.$item->last_name.'
+
+ '.formatNumber($points, 0).' €
+ '.formatNumber($margin, 1).' %
+ '.formatNumber($commission, 2).' €
+ '.$item->user_level_name.'
+ ';
+
+ return $ret;
+ }
}
diff --git a/app/Services/BusinessPlan/TreeCalcBot.php b/app/Services/BusinessPlan/TreeCalcBot.php
index 7b8f19d7..e92ae163 100644
--- a/app/Services/BusinessPlan/TreeCalcBot.php
+++ b/app/Services/BusinessPlan/TreeCalcBot.php
@@ -31,6 +31,7 @@ class TreeCalcBot
$this->date->start_date = $date->format('Y-m-d H:i:s');
$this->date->end_date = $date->endOfMonth()->format('Y-m-d H:i:s');
$this->init_from = $init_from;
+
}
public function initStructureAdmin($check = true)
@@ -63,14 +64,12 @@ class TreeCalcBot
if(isset($this->business_users[0]) && $this->business_users[0]->sponsor){
$this->readStoredSponsorUser($this->business_users[0]->sponsor->user_id);
}
-
}else{
$this->readParentsUsers();
$this->readSponsorUser($user_id);
}
}
-
public function initBusinesslUserDetail($user)
{
$this->business_user = new BusinessUserItem($this->date);
@@ -253,6 +252,7 @@ class TreeCalcBot
$ret = '';
foreach($this->business_users as $business_user){
$ret .= $this->addItem($business_user, $deep);
+
}
$ret .= '
';
return $ret;
@@ -269,7 +269,7 @@ class TreeCalcBot
data-back=""
data-modal="modal-xl"
data-init_from="'.$this->init_from .'"
- data-route="'.route('modal_load').'">';
+ data-route="'.route('modal_load').'">';
}
return ''.
'
@@ -279,15 +279,20 @@ class TreeCalcBot
-
- '.$item->first_name.' '.$item->last_name.' '.$item->email.' '.$item->user_level_name.' | '.$item->m_account.'
+
+ '.$item->first_name.' '.$item->last_name.'
+
+ '.$item->email.'
+ '.($item->user_birthday ? ' | '.$item->user_birthday : '').'
+ '.($item->user_phone ? ' | '.$item->user_phone : '').'
+ '.\App\Services\TranslationHelper::transUserLevelName($item->user_level_name).' | '.$item->m_account.'
'.
($item->active_account ?
- 'Gesamte Points: '.$item->sales_volume_points_sum.' | E: '.$item->sales_volume_KP_points.' | S: '.$item->sales_volume_points_shop.'
- | Umsatz netto: '.formatNumber($item->sales_volume_total_sum).' € | E: '.formatNumber($item->sales_volume_total).' € | S: '.formatNumber($item->sales_volume_total_shop).' €'.
+ ''.__('team.total_points').': '.$item->sales_volume_points_KP_sum.' | '.__('team.e').': '.$item->sales_volume_KP_points.' | '.__('team.s').': '.$item->sales_volume_points_shop.'
+ | '.__('team.net_turnover').': '.formatNumber($item->sales_volume_total_sum).' € | '.__('team.e').': '.formatNumber($item->sales_volume_total).' € | '.__('team.s').': '.formatNumber($item->sales_volume_total_shop).' €'.
$button
:
- 'Account bis: '.$item->payment_account_date).
+ __('team.account_to').': '.$item->payment_account_date).
'
@@ -323,20 +328,25 @@ class TreeCalcBot
$ret .= ' '.
'
-
- '.$item->first_name.' '.$item->last_name.' '.$item->email.' '.$item->user_level_name.' | '.$item->m_account.'
+
+ '.$item->first_name.' '.$item->last_name.'
+
+ '.$item->email.'
+ '.($item->user_birthday ? ' | '.$item->user_birthday : '').'
+ '.($item->user_phone ? ' | '.$item->user_phone : '').'
+ '.\App\Services\TranslationHelper::transUserLevelName($item->user_level_name).' | '.$item->m_account.'
'.
($item->active_account ?
- 'Gesamte Points: '.$item->sales_volume_points_sum.' | E: '.$item->sales_volume_KP_points.' | S: '.$item->sales_volume_points_shop.'
- | Umsatz netto: '.formatNumber($item->sales_volume_total_sum).' € | E: '.formatNumber($item->sales_volume_total).' € | S: '.formatNumber($item->sales_volume_total_shop).' €'.
+ ''.__('team.total_points').': '.$item->sales_volume_points_KP_sum.' | '.__('team.e').': '.$item->sales_volume_KP_points.' | '.__('team.s').': '.$item->sales_volume_points_shop.'
+ | '.__('team.net_turnover').': '.formatNumber($item->sales_volume_total_sum).' € | '.__('team.e').': '.formatNumber($item->sales_volume_total).' € | '.__('team.s').': '.formatNumber($item->sales_volume_total_shop).' €'.
' | '
+ data-route="'.route('modal_load').'">'
:
- 'Account bis: '.$item->payment_account_date).
+ __('team.account_to').' '.$item->payment_account_date).
'
'.$item->m_sponsor_name.
'
@@ -349,20 +359,25 @@ class TreeCalcBot
public function makeSponsorHtml(){
if($this->sponsor){
- //' | '
+ //' | '
$ret = ''.
'
-
- '.$this->sponsor->first_name.' '.$this->sponsor->last_name.' '.$this->sponsor->email.' '.$this->sponsor->user_level_name.' | '.$this->sponsor->m_account.'';
+
+ '.$this->sponsor->first_name.' '.$this->sponsor->last_name.'
+
+ '.$this->sponsor->email.'
+ '.($this->sponsor->user_birthday ? ' | '.$this->sponsor->user_birthday : '').'
+ '.($this->sponsor->user_phone ? ' | '.$this->sponsor->user_phone : '').'
+ '.\App\Services\TranslationHelper::transUserLevelName($this->sponsor->user_level_name).' | '.$this->sponsor->m_account.'';
if($this->init_from === 'admin'){
$ret .= '
'.
($this->sponsor->active_account ?
- 'Gesamte Points: '.$this->sponsor->sales_volume_points_sum.' | E: '.$this->sponsor->sales_volume_KP_points.' | S: '.$this->sponsor->sales_volume_points_shop.'
- | Umsatz netto: '.formatNumber($this->sponsor->sales_volume_total_sum).' € | E: '.formatNumber($this->sponsor->sales_volume_total).' € | S: '.formatNumber($this->sponsor->sales_volume_total_shop).' €'
+ ''.__('team.total_points').': '.$this->sponsor->sales_volume_points_KP_sum.' | '.__('team.e').': '.$this->sponsor->sales_volume_KP_points.' | '.__('team.s').': '.$this->sponsor->sales_volume_points_shop.'
+ | '.__('team.net_turnover').': '.formatNumber($this->sponsor->sales_volume_total_sum).' € | '.__('team.e').': '.formatNumber($this->sponsor->sales_volume_total).' € | '.__('team.s').': '.formatNumber($this->sponsor->sales_volume_total_shop).' €'
:
- 'Account bis: '.$this->sponsor->payment_account_date).
+ __('team.account_to').' '.$this->sponsor->payment_account_date).
'';
}
$ret .= '
@@ -371,9 +386,7 @@ class TreeCalcBot
return $ret;
}
- return 'Keinen Sponsor zugewiesen';
-
-
+ return __('team.no_sponsor_assigned');
}
}
diff --git a/app/Services/BusinessPlan/TreeExportBot.php b/app/Services/BusinessPlan/TreeExportBot.php
deleted file mode 100644
index ffbd7820..00000000
--- a/app/Services/BusinessPlan/TreeExportBot.php
+++ /dev/null
@@ -1,379 +0,0 @@
-date = new stdClass();
- $date = Carbon::parse($year.'-'.$month.'-1');
- $this->date->month = $month;
- $this->date->year = $year;
- $this->date->start_date = $date->format('Y-m-d H:i:s');
- $this->date->end_date = $date->endOfMonth()->format('Y-m-d H:i:s');
- $this->init_from = $init_from;
- }
-
- public function initStructureAdmin($check = true)
- {
- //check is month is saved.
- if($check && $UserBusinessStructure = self::isFromStored($this->date->month, $this->date->year)){
- $this->readStoredRootUsers($UserBusinessStructure);
- $this->readStoredParentsUsers($UserBusinessStructure);
- $this->readStoredParentlessUser($UserBusinessStructure);
- }else{
- $this->readRootUsers();
- $this->readParentsUsers();
- $this->readParentlessUser();
- }
-
- }
-
- public function initStructureUser($user_id)
- {
-
- $BusinessUserItem = new BusinessUserItem($this->date);
- $BusinessUserItem->makeUser($user_id);
- $BusinessUserItem->addUserID();
- $this->business_users[] = $BusinessUserItem;
-
- //check is month is saved.
- if($UserBusinessStructure = self::isFromStored($this->date->month, $this->date->year)){
- $this->readStoredParentsUsers($UserBusinessStructure);
-
- if(isset($this->business_users[0]) && $this->business_users[0]->sponsor){
- $this->readStoredSponsorUser($this->business_users[0]->sponsor->user_id);
- }
-
- }else{
- $this->readParentsUsers();
- $this->readSponsorUser($user_id);
- }
- }
-
-
- public function initBusinesslUserDetail($user)
- {
- $this->business_user = new BusinessUserItem($this->date);
- $this->business_user->makeUser($user->id);
- $this->business_user->checkSponsor($user);
- if(!$this->business_user->isSave()){
- //Aufbau der Struktur für den User in die unendliche Tiefe.
- $this->business_user->readParentsBusinessUsers();
- //calculate Points in Lines
- if(count($this->business_user->businessUserItems) > 0){
- $this->calcUserPoints($this->business_user->businessUserItems, 1);
- }
- //qualifikation nach qual_kp (KundenPoints) und qual_pp (PaylinePoints)
- $this->business_user->calcQualPP();
- }
- }
-
- /*public function storeBusinesslUser()
- {
- $this->business_user->storeUser();
- }*/
-
- public static function isFromStored($month, $year){
- //when is stored an completed
- $UserBusinessStructure = UserBusinessStructure::where('year', $year)->where('month', $month)->first();
- if($UserBusinessStructure && $UserBusinessStructure->completed){
- return $UserBusinessStructure;
- }
- return false;
- }
-
- private function calcUserPoints($businessUserItems, $line){
- if(!isset($this->business_user->business_lines[$line])){
- $obj = new stdClass();
- $obj->points = 0;
- $this->business_user->addBusinessLineToUser($line, $obj);
- }
- foreach($businessUserItems as $business_user_item){
- if(count($business_user_item->businessUserItems) > 0){
- $this->calcUserPoints($business_user_item->businessUserItems, $line+1);
- }
- //business_lines points nach line
- $this->business_user->addBusinessLinePoints($line, $business_user_item->sales_volume_points_TP_sum); //TP + Shop Points
- //total_pp gesamte Punkte
- $this->business_user->addTotalTP($business_user_item->sales_volume_points_TP_sum); //TP + Shop Points
- }
- }
-
- public function getGrowthBonus(){
- if(count($this->business_user->business_lines) > 6){
- $b_lines = $this->business_user->business_lines->toArray();
- return array_slice($b_lines, 6);
- }
- return [];
- }
-
-
- public function getKeybyLine($line, $key){
- if($this->business_user->business_lines){
- $b_lines = $this->business_user->business_lines;
- if(isset($b_lines[$line])){
- if($b_lines[$line] instanceof stdClass){
- if(isset($b_lines[$line]->{$key})){
- return $b_lines[$line]->{$key};
- }
- }else{
- if(isset($b_lines[$line][$key])){
- return $b_lines[$line][$key];
- }
- }
-
- }
- }
- return 0;
- }
-
- //* reading from current*//
- private function readRootUsers(){
- $users = User::with('account')->select('users.*')
- ->where('users.deleted_at', '=', null)
- ->where('users.id', '!=', 1)
- ->where('users.admin', "<", 4)
- ->where('users.m_level', "!=", null)
- ->where('users.m_sponsor', "=", null)
- ->where('users.payment_account', "!=", null)
- ->where('users.active_date', "<=", $this->date->end_date)
- ->get();
- if($users){
- foreach($users as $user){
- $BusinessUserItem = new BusinessUserItem($this->date);
- $BusinessUserItem->makeUser($user->id);
- $BusinessUserItem->addUserID();
- $this->business_users[] = $BusinessUserItem;
- }
- }
- }
-
- private function readParentsUsers(){
- foreach($this->business_users as $business_user){
- $business_user->readParentsBusinessUsers();
- }
- }
-
- private function readParentlessUser(){
- $users = User::with('account')->select('users.*')
- ->where('users.deleted_at', '=', null)
- ->where('users.id', '!=', 1)
- ->where('users.admin', "<", 4)
- ->where('users.payment_account', "!=", null)
- ->where('users.active_date', "<=", $this->date->end_date)
- ->get();
-
- foreach($users as $user){
- if(!isset(self::$userIDs[$user->id])){
- $BusinessUserItem = new BusinessUserItem($this->date);
- $BusinessUserItem->makeUser($user->id);
- $this->parentless[] = $BusinessUserItem;
- }
- }
- }
-
-
- //* reading from stored*//
- private function readStoredRootUsers(UserBusinessStructure $userBusinessStructure){
- //first level is root
- if($userBusinessStructure->structure){
- foreach($userBusinessStructure->structure as $obj){
- $BusinessUserItem = new BusinessUserItem($this->date);
- $BusinessUserItem->makeUser($obj->user_id);
- $BusinessUserItem->addUserID();
- $this->business_users[] = $BusinessUserItem;
-
- }
- }
- }
-
- private function readStoredParentsUsers(UserBusinessStructure $userBusinessStructure){
- foreach($this->business_users as $business_user){
- $business_user->readStoredParentsBusinessUsers($userBusinessStructure->structure);
- }
- }
-
- private function readStoredParentlessUser(UserBusinessStructure $userBusinessStructure){
- if($userBusinessStructure->parentless){
- foreach($userBusinessStructure->parentless as $obj){
- if(!isset(self::$userIDs[$obj->user_id])){
- $BusinessUserItem = new BusinessUserItem($this->date);
- $BusinessUserItem->makeUser($obj->user_id);
- $this->parentless[] = $BusinessUserItem;
-
- }
- }
- }
- }
-
-
- public function readSponsorUser($user_id){
- $user = User::find($user_id);
- $userSponsor = User::find($user->m_sponsor);
- if($userSponsor){
- $this->sponsor = new BusinessUserItem($this->date);
- $this->sponsor->makeUser($userSponsor->id);
- }
- }
-
- public function readStoredSponsorUser($user_id){
-
- $this->sponsor = new BusinessUserItem($this->date);
- $this->sponsor->makeUser($user_id);
-
- }
-
-
- public function getItems(){
- return $this->business_users;
- }
-
- public function makeHtmlTree(){
- $deep = 0;
- $ret = '';
- foreach($this->business_users as $business_user){
- $ret .= $this->addItem($business_user, $deep);
- }
- $ret .= '
';
- return $ret;
- }
-
- private function addItem($item, $deep){
-
- $button = '';
-
- if(($this->init_from === 'admin' && \Auth::user()->isAdmin()) || ($this->init_from === 'member')){ // && \Auth::user()->id === $item->user_id
- $button = ' | ';
- }
- return ''.
- '
-
-
- '.(($deep > 0) ? ''.$deep.'' : '').'
-
-
-
-
- '.$item->first_name.' '.$item->last_name.' '.$item->email.' '.$item->user_level_name.' | '.$item->m_account.'
-
'.
- ($item->active_account ?
- 'Gesamte Points: '.$item->sales_volume_points_sum.' | E: '.$item->sales_volume_KP_points.' | S: '.$item->sales_volume_points_shop.'
- | Umsatz netto: '.formatNumber($item->sales_volume_total_sum).' € | E: '.formatNumber($item->sales_volume_total).' € | S: '.formatNumber($item->sales_volume_total_shop).' €'.
- $button
- :
- 'Account bis: '.$item->payment_account_date).
- '
-
-
-
-
-
- '.
- $this->addParentItem($item, $deep).
- ' ';
-
- }
-
- private function addParentItem($item, $deep){
- if($item->businessUserItems){
- $ret = '';
- foreach($item->businessUserItems as $parent){
- $ret .= $this->addItem($parent, $deep+1);
- }
- $ret .='
';
- return $ret;
- }
- return;
- }
-
-
- public function isParentless(){
- return $this->parentless ? true : false;
- }
-
- public function makeParentlessHtml(){
- $ret = "";
- foreach($this->parentless as $item){
- $ret .= ''.
- '
-
-
- '.$item->first_name.' '.$item->last_name.' '.$item->email.' '.$item->user_level_name.' | '.$item->m_account.'
-
'.
- ($item->active_account ?
- 'Gesamte Points: '.$item->sales_volume_points_sum.' | E: '.$item->sales_volume_KP_points.' | S: '.$item->sales_volume_points_shop.'
- | Umsatz netto: '.formatNumber($item->sales_volume_total_sum).' € | E: '.formatNumber($item->sales_volume_total).' € | S: '.formatNumber($item->sales_volume_total_shop).' €'.
- ' | '
- :
- 'Account bis: '.$item->payment_account_date).
- '
'.$item->m_sponsor_name.
- '
-
- '.
- ' ';
- }
- return $ret;
- }
-
- public function makeSponsorHtml(){
-
- if($this->sponsor){
- //' | '
- $ret = ''.
- '
-
-
- '.$this->sponsor->first_name.' '.$this->sponsor->last_name.' '.$this->sponsor->email.' '.$this->sponsor->user_level_name.' | '.$this->sponsor->m_account.'';
-
- if($this->init_from === 'admin'){
- $ret .= '
'.
- ($this->sponsor->active_account ?
- 'Gesamte Points: '.$this->sponsor->sales_volume_points_sum.' | E: '.$this->sponsor->sales_volume_KP_points.' | S: '.$this->sponsor->sales_volume_points_shop.'
- | Umsatz netto: '.formatNumber($this->sponsor->sales_volume_total_sum).' € | E: '.formatNumber($this->sponsor->sales_volume_total).' € | S: '.formatNumber($this->sponsor->sales_volume_total_shop).' €'
- :
- 'Account bis: '.$this->sponsor->payment_account_date).
- '';
- }
- $ret .= '
-
- ';
-
- return $ret;
- }
- return 'Keinen Sponsor zugewiesen';
-
-
- }
-
-}
diff --git a/app/Services/Credit.php b/app/Services/Credit.php
index 8701dbfd..086388c7 100644
--- a/app/Services/Credit.php
+++ b/app/Services/Credit.php
@@ -35,10 +35,18 @@ class Credit
return "/credit/".\Carbon::parse($credit_date)->format('Y/m/');
}
+ public static function getCreditDetailStorageDir($credit_date){
+ return "/credit_details/".\Carbon::parse($credit_date)->format('Y/m/');
+ }
+
public static function makeCreditFilename($credit_number){
return $credit_number."-MIVITA-Gutschrift.pdf";
}
+ public static function makeCreditDetailFilename($credit_number){
+ return $credit_number."-MIVITA-Report.pdf";
+ }
+
public static function isCredit(UserCredit $user_credit){
return $user_credit->isCredit();
}
@@ -79,6 +87,6 @@ class Credit
}else{
$bcc[] = config('app.checkout_mail');
}
- Mail::to($email)->bcc($bcc)->send(new MailCredit($user_credit));
+ Mail::to($email)->bcc($bcc)->locale($user_credit->user->getLocale())->send(new MailCredit($user_credit));
}
}
diff --git a/app/Services/CustomerPriority.php b/app/Services/CustomerPriority.php
index 8e68aba2..be35c2e8 100644
--- a/app/Services/CustomerPriority.php
+++ b/app/Services/CustomerPriority.php
@@ -39,7 +39,7 @@ class CustomerPriority
if($entryExistsLike){
if(self::entryExistsLike($shopping_user)){ //existiert die Email bei einem anderem member?
if($mail){ //send mail
- Mail::to(config('app.info_mail'))->send(new MailInfo($shopping_user, 'check_is_like_customer'));
+ Mail::to(config('app.priority_mail'))->send(new MailInfo($shopping_user, 'check_is_like_customer'));
}
return 'exists';
}
@@ -50,7 +50,7 @@ class CustomerPriority
}
if(self::entryLike($shopping_user)){ //existiert die Adresse bei einem anderem member?
if($mail){ //send mail
- Mail::to(config('app.info_mail'))->send(new MailInfo($shopping_user, 'check_is_like_customer'));
+ Mail::to(config('app.priority_mail'))->send(new MailInfo($shopping_user, 'check_is_like_customer'));
}
return 'like'.$shopping_user->member_id;
}
@@ -178,7 +178,7 @@ class CustomerPriority
}
//look for entry
if($matches && $mail){ //send mail
- Mail::to(config('app.info_mail'))->send(new MailInfo($shopping_user, 'change_is_like_customer', $change));
+ Mail::to(config('app.priority_mail'))->send(new MailInfo($shopping_user, 'change_is_like_customer', $change));
}
return $ret;
@@ -190,7 +190,7 @@ class CustomerPriority
public static function checkNewOne($shopping_user, $mail=false){
if(self::entryLike($shopping_user)){
if($mail){ //send mail
- Mail::to(config('app.info_mail'))->send(new MailInfo($shopping_user, 'check_is_like_customer'));
+ Mail::to(config('app.priority_mail'))->send(new MailInfo($shopping_user, 'check_is_like_customer'));
}
//return 'like';
}
diff --git a/app/Services/DcHelper.php b/app/Services/DcHelper.php
new file mode 100644
index 00000000..758c6077
--- /dev/null
+++ b/app/Services/DcHelper.php
@@ -0,0 +1,108 @@
+ ['name' => 'German', 'script' => 'Latn', 'native' => 'Deutsch', 'regional' => 'de_DE'],
+ 'en' => ['name' => 'English', 'script' => 'Latn', 'native' => 'English', 'regional' => 'en_GB'],
+ 'es' => ['name' => 'Spanish', 'script' => 'Latn', 'native' => 'español', 'regional' => 'es_ES'],
+ ];
+
+ $ret = [];
+ foreach($langs as $code => $lang){
+ $ret[strtolower($code)] = strtolower($lang['native']);
+ }
+ return $ret;
+ }
+
+ public static function makeNestableList($category_id){
+ $tags = DcTag::where('category_id', $category_id)->orderBy('pos')->get();
+ $out = "";
+ foreach ($tags as $tag){
+
+ $out .= '
+
+
+ ' . ($tag->active ? '' : '') . '
+
+
+
+
+ '.$tag->name.'
+
+ ';
+ }
+ return $out;
+ }
+
+
+ public static function makeNestableListCheckbox($category_id, $file_id){
+
+ $tags = DcTag::where('category_id', $category_id)->orderBy('pos')->get();
+ $file_tags = DcFileTag::where('file_id', $file_id)->get();
+
+ $search = array();
+ foreach ($file_tags as $file_tag) {
+ $search[] = $file_tag->tag_id;
+ }
+
+ $out = "";
+ foreach ($tags as $tag){
+ $out .= '
+
+
+
+ ';
+ }
+ return $out;
+ }
+
+ public static function makeFilterList($filter_list, $split = false, $chunk = false){
+
+ $out = "";
+ $splitOn = 0;
+ if($split){
+ $count = count($filter_list);
+ if($count > 0){
+ $splitOn = intval(ceil($count / $split));
+ $filter_chunk = array_chunk($filter_list, $splitOn, true);
+ $filter_list = $filter_chunk[$chunk];
+ }
+
+ }
+
+ foreach($filter_list as $category_id => $value){
+ $out .= '';
+ $out .= '';
+
+ }
+ return $out;
+ }
+
+ private function getAttributesOptions($ids = array(), $all = true){
+ $ret = "";
+
+ return $ret;
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/Services/HTMLHelper.php b/app/Services/HTMLHelper.php
index fb9f6804..fa9d9435 100644
--- a/app/Services/HTMLHelper.php
+++ b/app/Services/HTMLHelper.php
@@ -16,31 +16,40 @@ class HTMLHelper
public static $months = [
- 1 => 'Januar',
- 2 => 'Februar',
- 3 => 'März',
+ 1 => 'January',
+ 2 => 'February',
+ 3 => 'March',
4 => 'April',
- 5 => 'Mai',
- 6 => 'Juni',
- 7 => 'Juli',
+ 5 => 'May',
+ 6 => 'June',
+ 7 => 'July',
8 => 'August',
9 => 'September',
- 10 => 'Oktober',
+ 10 => 'October',
11 => 'November',
- 12 => 'Dezember'
+ 12 => 'December'
];
private static $roles = [
0 => 'Kunde',
- 1 => 'Admin',
- 2 => 'SuperAdmin',
- 3 => 'SySAdmin',
+ 1 => 'VIP',
+ 2 => 'Admin',
+ 3 => 'SuperAdmin',
+ 4 => 'SySAdmin',
];
public static function getMonth($i){
- return self::$months[intval($i)];
+ return trans('cal.months.'.self::$months[intval($i)]);
+ }
+
+ public static function getTransMonths(){
+ $ret = [];
+ foreach(self::$months as $key=>$val){
+ $ret[$key] = trans('cal.months.'.$val);
+ }
+ return $ret;
}
public static function getYearRange($start = 2021)
@@ -49,7 +58,6 @@ class HTMLHelper
return array_reverse(range($start, $end));
}
-
public static function getRoleLabel($role_id = 0){
return ''.self::$roles[$role_id].'';
}
@@ -60,14 +68,17 @@ class HTMLHelper
return 'badge-default';
break;
case 1:
- return 'badge-warning';
+ return 'badge-secondary';
break;
case 2:
- return 'badge-primary';
+ return 'badge-warning';
break;
case 3:
return 'badge-primary';
break;
+ case 4:
+ return 'badge-primary';
+ break;
}
}
@@ -93,11 +104,28 @@ class HTMLHelper
return $ret;
}
+ public static function getAboIntervallWeeks($default = 1){
+ $values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
+ $ret = "";
+ foreach ($values as $value){
+ $attr = ($value == $default) ? 'selected="selected"' : '';
+ $str = self::getAboWeeksLang($value);
+ $ret .= '\n';
+ }
+ return $ret;
+ }
+
+ public static function getAboWeeksLang($num){
+ if($num == 1){
+ return __('order.every_week');
+ }
+ return __('order.every_weeks', ['num' => $num]);
+ }
public static function getAttributesWithoutParents($id = false, $sameId = false, $all = true){
$values = Attribute::where('parent_id', null)->get();
$ret = "";
if($all){
- $ret .= '\n';
+ $ret .= '\n';
}
foreach ($values as $value){
if($sameId == $value->id){
@@ -113,7 +141,7 @@ class HTMLHelper
$values = Category::where('parent_id', null)->get();
$ret = "";
if($all){
- $ret .= '\n';
+ $ret .= '\n';
}
foreach ($values as $value){
if($sameId == $value->id){
@@ -132,7 +160,7 @@ class HTMLHelper
$values = Product::where('active', 1)->get();
$ret = "";
if($all){
- $ret .= '\n';
+ $ret .= '\n';
}
foreach ($values as $value){
$attr = in_array($value->id, $ids) ? 'selected="selected"' : '';
@@ -145,7 +173,7 @@ class HTMLHelper
$values = Category::where('active', 1)->orderBy('pos', 'DESC')->get();
$ret = "";
if($all){
- $ret .= '\n';
+ $ret .= '\n';
}
foreach ($values as $value){
$attr = in_array($value->id, $ids) ? 'selected="selected"' : '';
@@ -170,7 +198,7 @@ class HTMLHelper
$values = Attribute::where('active', 1)->get();
$ret = "";
if($all){
- $ret .= '\n';
+ $ret .= '\n';
}
foreach ($values as $value){
$attr = in_array($value->id, $ids) ? 'selected="selected"' : '';
@@ -183,7 +211,7 @@ class HTMLHelper
$values = UserLevel::where('active', 1)->get();
$ret = "";
if($all){
- $ret .= '\n';
+ $ret .= '\n';
}
foreach ($values as $value){
$attr = ($value->id == $id) ? 'selected="selected"' : '';
@@ -303,7 +331,7 @@ class HTMLHelper
}
public static function getTaxSaleOptions($id){
- $values = array('1' => __('taxable_sales_1'), '2' => __('taxable_sales_2'));
+ $values = array('1' => __('account.taxable_sales_1'), '2' => __('account.taxable_sales_2'));
$ret = "";
$ret .= '\n';
foreach ($values as $key => $value){
@@ -339,7 +367,6 @@ class HTMLHelper
$ret .= '\n';
}
foreach ($values as $value){
- dump($value);
$attr = ($value->id == $id) ? 'selected="selected"' : '';
$to = $value->billing_firstname." ".$value->billing_lastname." | ".$value->billing_email;
$ret .= '\n';
diff --git a/app/Services/IPinfo/.editorconfig b/app/Services/IPinfo/.editorconfig
new file mode 100644
index 00000000..cd8eb86e
--- /dev/null
+++ b/app/Services/IPinfo/.editorconfig
@@ -0,0 +1,15 @@
+; This file is for unifying the coding style for different editors and IDEs.
+; More information at http://editorconfig.org
+
+root = true
+
+[*]
+charset = utf-8
+indent_size = 4
+indent_style = space
+end_of_line = lf
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+[*.md]
+trim_trailing_whitespace = false
diff --git a/app/Services/IPinfo/.github/workflows/phpunit.yaml b/app/Services/IPinfo/.github/workflows/phpunit.yaml
new file mode 100644
index 00000000..c5ccfcf4
--- /dev/null
+++ b/app/Services/IPinfo/.github/workflows/phpunit.yaml
@@ -0,0 +1,42 @@
+name: Unit Tests
+
+on:
+ pull_request:
+
+permissions:
+ contents: read
+
+jobs:
+ run:
+
+ runs-on: ${{ matrix.operating-system }}
+ strategy:
+ matrix:
+ operating-system: [ubuntu-latest]
+ php-versions: ['8.0', '8.1', '8.2']
+ phpunit-versions: ['9.5.20']
+
+ name: PHP ${{ matrix.php-versions }} Test on ${{ matrix.operating-system }}
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v2
+
+ - name: Setup PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: ${{ matrix.php-versions }}
+ tools: phpunit:${{ matrix.phpunit-versions }}
+
+ - name: Check PHP Version
+ run: php -v
+
+ - name: Validate composer.json and composer.lock
+ run: composer validate --strict
+
+ - name: Composer install
+ run: composer install --optimize-autoloader --prefer-dist --ignore-platform-reqs
+
+ - name: Run test suite
+ env:
+ IPINFO_TOKEN: ${{ secrets.IPINFO_TOKEN }}
+ run: /usr/local/bin/phpunit --coverage-text
diff --git a/app/Services/IPinfo/.styleci.yml b/app/Services/IPinfo/.styleci.yml
new file mode 100644
index 00000000..247a09c5
--- /dev/null
+++ b/app/Services/IPinfo/.styleci.yml
@@ -0,0 +1 @@
+preset: psr2
diff --git a/app/Services/IPinfo/Details.php b/app/Services/IPinfo/Details.php
new file mode 100644
index 00000000..fea4126c
--- /dev/null
+++ b/app/Services/IPinfo/Details.php
@@ -0,0 +1,55 @@
+ $value) {
+ $this->$property = $value;
+ }
+ $this->all = $raw_details;
+ }
+
+ /**
+ * Returns json string representation.
+ *
+ * @internal this class should implement Stringable explicitly when leaving support for PHP verision < 8.0
+ */
+ public function __toString(): string {
+ return json_encode($this);
+ }
+}
diff --git a/app/Services/IPinfo/IPinfo.php b/app/Services/IPinfo/IPinfo.php
new file mode 100644
index 00000000..f7d29f06
--- /dev/null
+++ b/app/Services/IPinfo/IPinfo.php
@@ -0,0 +1,419 @@
+access_token = $access_token;
+ $this->settings = $settings;
+
+ /*
+ Support a timeout first-class, then a `guzzle_opts` key that can
+ override anything.
+ */
+ $guzzle_opts = [
+ 'http_errors' => false,
+ 'headers' => $this->buildHeaders(),
+ 'timeout' => $settings['timeout'] ?? self::REQUEST_TIMEOUT_DEFAULT
+ ];
+ if (isset($settings['guzzle_opts'])) {
+ $guzzle_opts = array_merge($guzzle_opts, $settings['guzzle_opts']);
+ }
+ $this->http_client = new Client($guzzle_opts);
+
+ $countries_file = $settings['countries_file'] ?? self::COUNTRIES_FILE_DEFAULT;
+ $countries_flags_file = $settings['countries_flags_file'] ?? self::COUNTRIES_FLAGS_FILE_DEFAULT;
+ $countries_currencies_file = $settings['countries_currencies_file'] ?? self::COUNTRIES_CURRENCIES_FILE_DEFAULT;
+ $eu_countries_file = $settings['eu_countries_file'] ?? self::EU_COUNTRIES_FILE_DEFAULT;
+ $continents_file = $settings['continent_file'] ?? self::CONTINENT_FILE_DEFAULT;
+ $this->countries = $this->readJSONFile($countries_file);
+ $this->countries_flags = $this->readJSONFile($countries_flags_file);
+ $this->countries_currencies = $this->readJSONFile($countries_currencies_file);
+ $this->eu_countries = $this->readJSONFile($eu_countries_file);
+ $this-> continents = $this->readJSONFile($continents_file);
+
+ /*if (!array_key_exists('cache_disabled', $this->settings) || $this->settings['cache_disabled'] == false) {
+ if (array_key_exists('cache', $settings)) {
+ $this->cache = $settings['cache'];
+ } else {
+ $maxsize = $settings['cache_maxsize'] ?? self::CACHE_MAXSIZE;
+ $ttl = $settings['cache_ttl'] ?? self::CACHE_TTL;
+ $this->cache = new DefaultCache($maxsize, $ttl);
+ }
+ } else {
+ $this->cache = null;
+ }*/
+ }
+
+ /**
+ * Get formatted details for an IP address.
+ * @param string|null $ip_address IP address to look up.
+ * @return Details Formatted IPinfo data.
+ * @throws IPinfoException
+ */
+ public function getDetails($ip_address = null)
+ {
+ $response_details = $this->getRequestDetails((string) $ip_address);
+ return $this->formatDetailsObject($response_details);
+ }
+
+ /**
+ * Get formatted details for a list of IP addresses.
+ * @param $urls the array of URLs.
+ * @param $batchSize default value is set to max value for batch size, which is 1000.
+ * @param batchTimeout in seconds. Default value is 5 seconds.
+ * @param filter default value is false.
+ * @return $results
+ */
+ public function getBatchDetails(
+ $urls,
+ $batchSize = 0,
+ $batchTimeout = self::BATCH_TIMEOUT,
+ $filter = false
+ ) {
+ $lookupUrls = [];
+ $results = [];
+
+ // no items?
+ if (count($urls) == 0) {
+ return $results;
+ }
+
+ // clip batch size.
+ if (!is_numeric($batchSize) || $batchSize <= 0 || $batchSize > self::BATCH_MAX_SIZE) {
+ $batchSize = self::BATCH_MAX_SIZE;
+ }
+
+ // filter out URLs already cached.
+ if ($this->cache != null) {
+ foreach ($urls as $url) {
+ $cachedRes = $this->cache->get($this->cacheKey($url));
+ if ($cachedRes != null) {
+ $results[$url] = $cachedRes;
+ } else {
+ $lookupUrls[] = $url;
+ }
+ }
+ } else {
+ $lookupUrls = $urls;
+ }
+
+ // everything cached? exit early.
+ if (count($lookupUrls) == 0) {
+ return $results;
+ }
+
+ // prepare each batch & fire it off asynchronously.
+ $apiUrl = self::API_URL . "/batch";
+ if ($filter) {
+ $apiUrl .= '?filter=1';
+ }
+ $promises = [];
+ $totalBatches = ceil(count($lookupUrls) / $batchSize);
+ for ($i = 0; $i < $totalBatches; $i++) {
+ $start = $i * $batchSize;
+ $batch = array_slice($lookupUrls, $start, $batchSize);
+ $promise = $this->http_client->postAsync($apiUrl, [
+ 'body' => json_encode($batch),
+ 'timeout' => $batchTimeout
+ ])->then(function ($resp) use (&$results) {
+ $batchResult = json_decode($resp->getBody(), true);
+ foreach ($batchResult as $k => $v) {
+ $results[$k] = $v;
+ }
+ });
+ $promises[] = $promise;
+ }
+
+ // wait for all batches to finish.
+ Promise\Utils::settle($promises)->wait();
+
+ // cache any new results.
+ if ($this->cache != null) {
+ foreach ($lookupUrls as $url) {
+ if (array_key_exists($url, $results)) {
+ $this->cache->set($this->cacheKey($url), $results[$url]);
+ }
+ }
+ }
+
+ return $results;
+ }
+
+ public function formatDetailsObject($details = [])
+ {
+ $country = $details['country'] ?? null;
+ $details['country_name'] = $this->countries[$country] ?? null;
+ $details['is_eu'] = in_array($country, $this->eu_countries);
+ $details['country_flag'] = $this->countries_flags[$country] ?? null;
+ $details['country_flag_url'] = self::COUNTRY_FLAG_URL.$country.".svg";
+ $details['country_currency'] = $this->countries_currencies[$country] ?? null;
+ $details['continent'] = $this->continents[$country] ?? null;
+
+ if (array_key_exists('loc', $details)) {
+ $coords = explode(',', $details['loc']);
+ $details['latitude'] = $coords[0];
+ $details['longitude'] = $coords[1];
+ } else {
+ $details['latitude'] = null;
+ $details['longitude'] = null;
+ }
+
+ return new Details($details);
+ }
+
+ /**
+ * Get details for a specific IP address.
+ * @param string $ip_address IP address to query API for.
+ * @return array IP response data.
+ * @throws IPinfoException
+ */
+ public function getRequestDetails(string $ip_address)
+ {
+ if ($this->isBogon($ip_address)) {
+ return [
+ "ip" => $ip_address,
+ "bogon" => true,
+ ];
+ }
+
+ if ($this->cache != null) {
+ $cachedRes = $this->cache->get($this->cacheKey($ip_address));
+ if ($cachedRes != null) {
+ return $cachedRes;
+ }
+ }
+
+ $url = self::API_URL;
+ if ($ip_address) {
+ $url .= "/$ip_address";
+ }
+
+ try {
+ $response = $this->http_client->request('GET', $url);
+ } catch (GuzzleException $e) {
+ \Log::channel('ipinfo')->error('IPinfo::getRequestDetails GuzzleException.'. $e->getMessage());
+ return [
+ "ip" => $ip_address,
+ "error" => $e->getMessage(),
+ ];
+ //throw new IPinfoException($e->getMessage());
+ } catch (Exception $e) {
+ \Log::channel('ipinfo')->error('IPinfo::getRequestDetails Exception.'. $e->getMessage());
+ return [
+ "ip" => $ip_address,
+ "error" => $e->getMessage(),
+ ];
+ //throw new IPinfoException($e->getMessage());
+ }
+
+ if ($response->getStatusCode() == self::STATUS_CODE_QUOTA_EXCEEDED) {
+ //throw new IPinfoException('IPinfo request quota exceeded.');
+ } elseif ($response->getStatusCode() >= 400) {
+ \Log::channel('ipinfo')->error('IPinfo::getRequestDetails getStatusCode.'. json_encode([
+ 'status' => $response->getStatusCode(),
+ 'reason' => $response->getReasonPhrase(),
+ ]));
+
+ return [
+ "ip" => $ip_address,
+ 'status' => $response->getStatusCode(),
+ 'reason' => $response->getReasonPhrase(),
+ "error" => 'getStatusCode',
+ ];
+ /*throw new IPinfoException('Exception: ' . json_encode([
+ 'status' => $response->getStatusCode(),
+ 'reason' => $response->getReasonPhrase(),
+ ]));*/
+ }
+
+ $raw_details = json_decode($response->getBody(), true);
+
+ if ($this->cache != null) {
+ $this->cache->set($this->cacheKey($ip_address), $raw_details);
+ }
+
+ return $raw_details;
+ }
+
+ /**
+ * Gets a URL to a map on https://ipinfo.io/map given a list of IPs (max
+ * 500,000).
+ * @param array $ips list of IP addresses to put on the map.
+ * @return string URL to the map.
+ */
+ public function getMapUrl($ips)
+ {
+ $url = sprintf("%s/map?cli=1", self::API_URL);
+
+ try {
+ $response = $this->http_client->request(
+ 'POST',
+ $url,
+ [
+ 'json' => $ips
+ ]
+ );
+ } catch (GuzzleException $e) {
+ throw new IPinfoException($e->getMessage());
+ } catch (Exception $e) {
+ throw new IPinfoException($e->getMessage());
+ }
+
+ $res = json_decode($response->getBody(), true);
+ return $res['reportUrl'];
+ }
+
+ /**
+ * Build headers for API request.
+ * @return array Headers for API request.
+ */
+ private function buildHeaders()
+ {
+ $headers = [
+ 'user-agent' => 'IPinfoClient/PHP/3.1.0',
+ 'accept' => 'application/json',
+ 'content-type' => 'application/json',
+ ];
+
+ if ($this->access_token) {
+ $headers['authorization'] = "Bearer {$this->access_token}";
+ }
+
+ return $headers;
+ }
+
+ /**
+ * Read JSON from a file and return as an array.
+ * @param string $countries_file JSON file of country_code => country_name mappings
+ * @return array country_code => country_name mappings
+ */
+ private function readJSONFile($countries_file)
+ {
+ $file_contents = file_get_contents($countries_file);
+ return json_decode($file_contents, true);
+ }
+
+ /**
+ * Returns a versioned cache key given a user-input key.
+ * @param string $k key to transform into a versioned cache key.
+ * @return string the versioned cache key.
+ */
+ private function cacheKey($k)
+ {
+ return sprintf('%s:%s', $k, self::CACHE_KEY_VSN);
+ }
+
+ /**
+ * Check if an IP address is a bogon.
+ *
+ * @param string $ip The IP address to check
+ * @return bool True if the IP address is a bogon, false otherwise
+ */
+ public function isBogon($ip)
+ {
+ // Check if the IP address is in the range
+ return IpUtils::checkIp($ip, $this->bogonNetworks);
+ }
+
+ // List of bogon CIDRs.
+ protected $bogonNetworks = [
+ "0.0.0.0/8",
+ "10.0.0.0/8",
+ "100.64.0.0/10",
+ "127.0.0.0/8",
+ "169.254.0.0/16",
+ "172.16.0.0/12",
+ "192.0.0.0/24",
+ "192.0.2.0/24",
+ "192.168.0.0/16",
+ "198.18.0.0/15",
+ "198.51.100.0/24",
+ "203.0.113.0/24",
+ "224.0.0.0/4",
+ "240.0.0.0/4",
+ "255.255.255.255/32",
+ "::/128",
+ "::1/128",
+ "::ffff:0:0/96",
+ "::/96",
+ "100::/64",
+ "2001:10::/28",
+ "2001:db8::/32",
+ "fc00::/7",
+ "fe80::/10",
+ "fec0::/10",
+ "ff00::/8",
+ "2002::/24",
+ "2002:a00::/24",
+ "2002:7f00::/24",
+ "2002:a9fe::/32",
+ "2002:ac10::/28",
+ "2002:c000::/40",
+ "2002:c000:200::/40",
+ "2002:c0a8::/32",
+ "2002:c612::/31",
+ "2002:c633:6400::/40",
+ "2002:cb00:7100::/40",
+ "2002:e000::/20",
+ "2002:f000::/20",
+ "2002:ffff:ffff::/48",
+ "2001::/40",
+ "2001:0:a00::/40",
+ "2001:0:7f00::/40",
+ "2001:0:a9fe::/48",
+ "2001:0:ac10::/44",
+ "2001:0:c000::/56",
+ "2001:0:c000:200::/56",
+ "2001:0:c0a8::/48",
+ "2001:0:c612::/47",
+ "2001:0:c633:6400::/56",
+ "2001:0:cb00:7100::/56",
+ "2001:0:e000::/36",
+ "2001:0:f000::/36",
+ "2001:0:ffff:ffff::/64"
+ ];
+}
diff --git a/app/Services/IPinfo/IPinfoException.php b/app/Services/IPinfo/IPinfoException.php
new file mode 100644
index 00000000..bc48ca21
--- /dev/null
+++ b/app/Services/IPinfo/IPinfoException.php
@@ -0,0 +1,8 @@
+= 8.0.
+- Add local bogon checking.
+
+### 2.3.1 (June 27 2022)
+
+- Added Stringable implementation for PHP 8.0 with backward compatibility.
+
+### 2.3.0 (September 21 2021)
+
+- Added batch ops integration.
+- Added the ability to disable cache usage entirely.
+
+### 2.2.0 (April 22nd 2021)
+
+- Added Maps integration.
+- Added versioned cache keys.
+ This allows more reliable changes to cached data in the future without
+ causing confusing incompatibilities. This should be transparent to the user.
+ This is primarily useful for users with persistent cache implementations.
+
+### 2.1.1 (January 12 2021)
+
+- Bug fix issue reported in Laravel SDK
+ (https://github.com/ipinfo/laravel/issues/14) which also applies in PHP SDK,
+ with https://github.com/ipinfo/php/pull/27.
+
+### 2.1.0 (December 2 2020)
+
+- Deprecate PHP 7.2 support.
+- Add support for PHP 8.0.
+
+### 2.0.0 (November 2020)
+
+- A `guzzle_opts` option is supported in the settings, which allows full Guzzle
+ option overrides.
+- A `timeout` option is supported in the settings, which is the request timeout
+ value, and defaults to 2 seconds.
+ **BREAKING**: this was previously unconfigurable and was 0 seconds,
+ i.e. infinite timeout.
+- The `buildHeaders` method on the main `IPinfo` client is now private.
+ **BREAKING**: this will no longer be available for use from the client.
+- Only non-EOL PHP 7 versions are supported. In particular, PHP 7.2 and above
+ are all supported and tested in the CI.
diff --git a/app/Services/IPinfo/_info/README.md b/app/Services/IPinfo/_info/README.md
new file mode 100644
index 00000000..3878903b
--- /dev/null
+++ b/app/Services/IPinfo/_info/README.md
@@ -0,0 +1,257 @@
+# [
](https://ipinfo.io/) IPinfo PHP Client Library
+
+This is the official PHP client library for the [IPinfo.io](https://ipinfo.io) IP address API, allowing you to look up your own IP address, or get any of the following details for an IP:
+ - [IP to Geolocation data](https://ipinfo.io/ip-geolocation-api) (city, region, country, postal code, latitude, and longitude)
+ - [ASN information](https://ipinfo.io/asn-api) (ISP or network operator, associated domain name, and type, such as business, hosting, or company)
+ - [Company details](https://ipinfo.io/ip-company-api) (the name and domain of the business that uses the IP address)
+ - [Carrier information](https://ipinfo.io/ip-carrier-api) (the name of the mobile carrier and MNC and MCC for that carrier if the IP is used exclusively for mobile traffic)
+
+Check all the data we have for your IP address [here](https://ipinfo.io/what-is-my-ip).
+
+### Getting Started
+
+You'll need an IPinfo API access token, which you can get by signing up for a free account at [https://ipinfo.io/signup](https://ipinfo.io/signup?ref=lib-PHP).
+
+The free plan is limited to 50,000 requests per month, and doesn't include some of the data fields such as IP type and company data. To enable all the data fields and additional request volumes see [https://ipinfo.io/pricing](https://ipinfo.io/pricing?ref=lib-PHP).
+
+#### Installation
+
+The package works with PHP 8 and is available using [Composer](https://getcomposer.org).
+
+```shell
+composer require ipinfo/ipinfo
+```
+
+#### Quick Start
+
+```php
+getDetails($ip_address);
+
+$details->city; // Emeryville
+$details->loc; // 37.8342,-122.2900
+```
+
+### Usage
+
+The `IPinfo->getDetails()` method accepts an IP address as an optional, positional argument. If no IP address is specified, the API will return data for the IP address from which it receives the request.
+
+```php
+$client = new IPinfo();
+$ip_address = '216.239.36.21';
+$details = $client->getDetails($ip_address);
+$details->city; // Emeryville
+$details->loc; // 37.8342,-122.2900
+```
+
+### Authentication
+
+The IPinfo library can be authenticated with your IPinfo API token, which is passed in as a positional argument. It also works without an authentication token, but in a more limited capacity.
+
+```php
+$access_token = '123456789abc';
+$client = new IPinfo($access_token);
+```
+
+### Details Data
+
+`IPinfo->getDetails()` will return a `Details` object that contains all fields listed [IPinfo developer docs](https://ipinfo.io/developers/responses#full-response) with a few minor additions. Properties can be accessed directly.
+
+```php
+$details->hostname; // cpe-104-175-221-247.socal.res.rr.com
+```
+
+#### Country Name
+
+`Details->country_name` will return the country name, as supplied by the `countries.json` file. See below for instructions on changing that file for use with non-English languages. `Details->country` will still return the country code.
+
+```php
+$details->country; // US
+$details->country_name; // United States
+```
+
+#### EU Country
+
+`Details->is_eu` will return true if the country is a member of the EU, as supplied by the `eu.json` file.
+
+```php
+$details->is_eu; // False
+```
+
+#### Country Flag
+
+`Details->country_flag` will return the emoji and Unicode representations of
+the country's flag, as supplied by the `flags.json` file.
+
+```php
+$details->country_flag['emoji']; // 🇺🇸
+$details->country_flag['unicode']; // U+1F1FA U+1F1F8
+```
+
+#### Country Flag URL
+
+`Details->country_flag_url` will return a public link to the country's flag image as an SVG which can be used anywhere.
+
+```php
+$details->country_flag_url; // https://cdn.ipinfo.io/static/images/countries-flags/US.svg
+```
+
+#### Country Currency
+
+`Details->country_currency` will return the code and symbol of the
+country's currency, as supplied by the `currency.json` file.
+
+```php
+$details->country_currency['code']; // USD
+$details->country_currency['symbol']; // $
+```
+
+#### Continent
+
+`Details->continent` will return the code and name of the
+continent, as supplied by the `continent.json` file.
+
+```php
+$details->continent['code']; // NA
+$details->continent['name']; // North America
+```
+
+#### Longitude and Latitude
+
+`Details->latitude` and `Details->longitude` will return latitude and longitude, respectively, as strings. `Details->loc` will still return a composite string of both values.
+
+```php
+$details->loc; // 34.0293,-118.3570
+$details->latitude; // 34.0293
+$details->longitude; // -118.3570
+```
+
+#### Accessing all properties
+
+`Details->all` will return all details data as a dictionary.
+
+```php
+$details->all;
+/*
+ {
+ 'asn': { 'asn': 'AS20001',
+ 'domain': 'twcable.com',
+ 'name': 'Time Warner Cable Internet LLC',
+ 'route': '104.172.0.0/14',
+ 'type': 'isp'},
+ 'city': 'Los Angeles',
+ 'company': { 'domain': 'twcable.com',
+ 'name': 'Time Warner Cable Internet LLC',
+ 'type': 'isp'},
+ 'country': 'US',
+ 'country_name': 'United States',
+ 'hostname': 'cpe-104-175-221-247.socal.res.rr.com',
+ 'ip': '104.175.221.247',
+ 'loc': '34.0293,-118.3570',
+ 'latitude': '34.0293',
+ 'longitude': '-118.3570',
+ 'phone': '323',
+ 'postal': '90016',
+ 'region': 'California'
+ }
+*/
+```
+
+### Caching
+
+In-memory caching of `Details` data is provided by default via the [symfony/cache](https://github.com/symfony/cache/) library. LRU (least recently used) cache-invalidation functionality has been added to the default TTL (time to live). This means that values will be cached for the specified duration; if the cache's max size is reached, cache values will be invalidated as necessary, starting with the oldest cached value.
+
+#### Modifying cache options
+
+Default cache TTL and maximum size can be changed by setting values in the `$settings` argument array.
+
+* Default maximum cache size: 4096 (multiples of 2 are recommended to increase efficiency)
+* Default TTL: 24 hours (in seconds)
+
+```php
+$access_token = '123456789abc';
+$settings = ['cache_maxsize' => 30, 'cache_ttl' => 128];
+$client = new IPinfo($access_token, $settings);
+```
+
+#### Using a different cache
+
+It's possible to use a custom cache by creating a child class of the [CacheInterface](https://github.com/ipinfo/php/blob/master/src/cache/Interface.php) class and passing this into the handler object with the `cache` keyword argument. FYI this is known as [the Strategy Pattern](https://sourcemaking.com/design_patterns/strategy).
+
+```php
+$access_token = '123456789abc';
+$settings = ['cache' => $my_fancy_custom_cache];
+$client = new IPinfo($access_token, $settings);
+```
+
+#### Disabling the cache
+
+You may disable the cache by passing in a `cache_disabled` key in the settings:
+
+```php
+$access_token = '123456789abc';
+$settings = ['cache_disabled' => true];
+$client = new IPinfo($access_token, $settings);
+```
+
+### Overriding HTTP Client options
+
+The IPinfo client constructor accepts a `timeout` key which is the request
+timeout in seconds.
+
+For full flexibility, a `guzzle_opts` key is accepted which accepts an
+associative array which is described in [Guzzle Request Options](https://docs.guzzlephp.org/en/stable/request-options.html).
+Options set here will override any custom settings set by the IPinfo client
+internally in case of conflict, including headers.
+
+### Batch Operations
+
+Looking up a single IP at a time can be slow. It could be done concurrently from the client side, but IPinfo supports a batch endpoint to allow you to group together IPs and let us handle retrieving details for them in bulk for you.
+
+```php
+$access_token = '123456789abc';
+$client = new IPinfo($access_token);
+$ips = ['1.1.1.1', '8.8.8.8', '1.2.3.4/country'];
+$results = $client->getBatchDetails($ips);
+echo $results['1.2.3.4/country']; // AU
+var_dump($results['1.1.1.1']);
+var_dump($results['8.8.8.8']);
+```
+
+The input size is not limited, as the interface will chunk operations for you behind the scenes.
+
+Please see [the official documentation](https://ipinfo.io/developers/batch) for more information and limitations.
+
+### Internationalization
+
+When looking up an IP address, the response object includes a `Details->country_name` attribute which includes the country name based on American English. It is possible to return the country name in other languages by setting the `countries_file` keyword argument when creating the `IPinfo` object.
+
+The file must be a `.json` file with the following structure:
+
+```JSON
+{
+ "BD": "Bangladesh",
+ "BE": "Belgium",
+ "BF": "Burkina Faso",
+ "BG": "Bulgaria"
+ ...
+}
+```
+
+### Other Libraries
+
+There are official IPinfo client libraries available for many languages including PHP, Python, Go, Java, Ruby, and many popular frameworks such as Django, Rails, and Laravel. There are also many third-party libraries and integrations available for our API.
+
+### About IPinfo
+
+Founded in 2013, IPinfo prides itself on being the most reliable, accurate, and in-depth source of IP address data available anywhere. We process terabytes of data to produce our custom IP geolocation, company, carrier, privacy, hosted domains and IP type data sets. Our API handles over 40 billion requests a month for 100,000 businesses and developers.
+
+[](https://ipinfo.io/)
diff --git a/app/Services/IPinfo/_info/composer.json b/app/Services/IPinfo/_info/composer.json
new file mode 100644
index 00000000..b9440ba2
--- /dev/null
+++ b/app/Services/IPinfo/_info/composer.json
@@ -0,0 +1,64 @@
+{
+ "name": "ipinfo/ipinfo",
+ "type": "library",
+ "description": "The official PHP library for IPinfo, the most reliable, accurate, and in-depth source of IP address data available anywhere. We process terabytes of data to produce our custom IP geolocation, company, carrier and IP type data sets. Visit our developer docs at https://ipinfo.io/developers.",
+ "keywords": [
+ "ipinfo"
+ ],
+ "homepage": "https://github.com/ipinfo/php",
+ "license": "Apache-2.0",
+ "authors": [
+ {
+ "name": "James Timmins",
+ "email": "jameshtimmins@gmail.com",
+ "homepage": "https://github.com/jhtimmins",
+ "role": "Developer"
+ },
+ {
+ "name": "Uman Shahzad",
+ "email": "uman@mslm.io",
+ "homepage": "https://github.com/UmanShahzad",
+ "role": "Developer"
+ },
+ {
+ "name": "Umar Farooq",
+ "email": "umar@ipinfo.io",
+ "homepage": "https://github.com/rm-Umar",
+ "role": "Developer"
+ }
+ ],
+ "require": {
+ "php": ">=8.0",
+ "ext-json": "*",
+ "guzzlehttp/guzzle": "^6.3||^7.0",
+ "symfony/cache": "^6.3",
+ "symfony/http-foundation": "^6.2"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.0.0",
+ "squizlabs/php_codesniffer": "^3.5.8"
+ },
+ "autoload": {
+ "psr-4": {
+ "ipinfo\\ipinfo\\": "src"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "ipinfo\\ipinfo\\": "tests"
+ }
+ },
+ "scripts": {
+ "test": "phpunit",
+ "check-style": "phpcs -p --standard=PSR2 --runtime-set ignore_errors_on_exit 1 --runtime-set ignore_warnings_on_exit 1 src tests",
+ "fix-style": "phpcbf -p --standard=PSR2 --runtime-set ignore_errors_on_exit 1 --runtime-set ignore_warnings_on_exit 1 src tests"
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.1.1-dev"
+ }
+ },
+ "config": {
+ "sort-packages": true
+ }
+}
diff --git a/app/Services/IPinfo/cache/CacheInterface.php b/app/Services/IPinfo/cache/CacheInterface.php
new file mode 100644
index 00000000..ca462744
--- /dev/null
+++ b/app/Services/IPinfo/cache/CacheInterface.php
@@ -0,0 +1,31 @@
+cache = new ArrayAdapter();
+ $this->element_queue = array();
+ $this->maxsize = $maxsize;
+ $this->ttl = $ttl;
+ }
+
+ /**
+ * Tests if the specified IP address is cached.
+ * @param string $ip_address IP address to lookup.
+ * @return boolean Is the IP address data in the cache.
+ */
+ public function has(string $name): bool
+ {
+ return $this->cache->hasItem($name);
+ }
+
+ /**
+ * Set the IP address key to the specified value.
+ * @param string $ip_address IP address to cache data for.
+ * @param mixed $value Data for specified IP address.
+ */
+ public function set(string $name, $value)
+ {
+ if (!$this->cache->hasItem($name)) {
+ $this->element_queue[] = $name;
+ }
+
+ $this->cache->get($name, function (ItemInterface $item) use ($value) {
+ $item->set($value)->expiresAfter($this->ttl);
+ return $item->get();
+ });
+
+ $this->manageSize();
+ }
+
+ /**
+ * Get data for the specified IP address.
+ * @param string $ip_address IP address to lookup in cache.
+ * @return mixed IP address data.
+ */
+ public function get(string $name)
+ {
+ return $this->cache->getItem($name)->get();
+ }
+
+ /**
+ * If cache maxsize has been reached, remove oldest elements until limit is reached.
+ */
+ private function manageSize()
+ {
+ $overflow = count($this->element_queue) - $this->maxsize;
+ if ($overflow > 0) {
+ foreach (array_slice($this->element_queue, 0, $overflow) as $name) {
+ if ($this->has($name)) {
+ $this->cache->delete($name);
+ }
+ }
+ $this->element_queue = array_slice($this->element_queue, $overflow);
+ }
+ }
+}
diff --git a/app/Services/IPinfo/json/continent.json b/app/Services/IPinfo/json/continent.json
new file mode 100644
index 00000000..3006a592
--- /dev/null
+++ b/app/Services/IPinfo/json/continent.json
@@ -0,0 +1,252 @@
+{
+ "BD": {"code": "AS", "name": "Asia"},
+ "BE": {"code": "EU", "name": "Europe"},
+ "BF": {"code": "AF", "name": "Africa"},
+ "BG": {"code": "EU", "name": "Europe"},
+ "BA": {"code": "EU", "name": "Europe"},
+ "BB": {"code": "NA", "name": "North America"},
+ "WF": {"code": "OC", "name": "Oceania"},
+ "BL": {"code": "NA", "name": "North America"},
+ "BM": {"code": "NA", "name": "North America"},
+ "BN": {"code": "AS", "name": "Asia"},
+ "BO": {"code": "SA", "name": "South America"},
+ "BH": {"code": "AS", "name": "Asia"},
+ "BI": {"code": "AF", "name": "Africa"},
+ "BJ": {"code": "AF", "name": "Africa"},
+ "BT": {"code": "AS", "name": "Asia"},
+ "JM": {"code": "NA", "name": "North America"},
+ "BV": {"code": "AN", "name": "Antarctica"},
+ "BW": {"code": "AF", "name": "Africa"},
+ "WS": {"code": "OC", "name": "Oceania"},
+ "BQ": {"code": "NA", "name": "North America"},
+ "BR": {"code": "SA", "name": "South America"},
+ "BS": {"code": "NA", "name": "North America"},
+ "JE": {"code": "EU", "name": "Europe"},
+ "BY": {"code": "EU", "name": "Europe"},
+ "BZ": {"code": "NA", "name": "North America"},
+ "RU": {"code": "EU", "name": "Europe"},
+ "RW": {"code": "AF", "name": "Africa"},
+ "RS": {"code": "EU", "name": "Europe"},
+ "TL": {"code": "OC", "name": "Oceania"},
+ "RE": {"code": "AF", "name": "Africa"},
+ "TM": {"code": "AS", "name": "Asia"},
+ "TJ": {"code": "AS", "name": "Asia"},
+ "RO": {"code": "EU", "name": "Europe"},
+ "TK": {"code": "OC", "name": "Oceania"},
+ "GW": {"code": "AF", "name": "Africa"},
+ "GU": {"code": "OC", "name": "Oceania"},
+ "GT": {"code": "NA", "name": "North America"},
+ "GS": {"code": "AN", "name": "Antarctica"},
+ "GR": {"code": "EU", "name": "Europe"},
+ "GQ": {"code": "AF", "name": "Africa"},
+ "GP": {"code": "NA", "name": "North America"},
+ "JP": {"code": "AS", "name": "Asia"},
+ "GY": {"code": "SA", "name": "South America"},
+ "GG": {"code": "EU", "name": "Europe"},
+ "GF": {"code": "SA", "name": "South America"},
+ "GE": {"code": "AS", "name": "Asia"},
+ "GD": {"code": "NA", "name": "North America"},
+ "GB": {"code": "EU", "name": "Europe"},
+ "GA": {"code": "AF", "name": "Africa"},
+ "SV": {"code": "NA", "name": "North America"},
+ "GN": {"code": "AF", "name": "Africa"},
+ "GM": {"code": "AF", "name": "Africa"},
+ "GL": {"code": "NA", "name": "North America"},
+ "GI": {"code": "EU", "name": "Europe"},
+ "GH": {"code": "AF", "name": "Africa"},
+ "OM": {"code": "AS", "name": "Asia"},
+ "TN": {"code": "AF", "name": "Africa"},
+ "JO": {"code": "AS", "name": "Asia"},
+ "HR": {"code": "EU", "name": "Europe"},
+ "HT": {"code": "NA", "name": "North America"},
+ "HU": {"code": "EU", "name": "Europe"},
+ "HK": {"code": "AS", "name": "Asia"},
+ "HN": {"code": "NA", "name": "North America"},
+ "HM": {"code": "AN", "name": "Antarctica"},
+ "VE": {"code": "SA", "name": "South America"},
+ "PR": {"code": "NA", "name": "North America"},
+ "PS": {"code": "AS", "name": "Asia"},
+ "PW": {"code": "OC", "name": "Oceania"},
+ "PT": {"code": "EU", "name": "Europe"},
+ "SJ": {"code": "EU", "name": "Europe"},
+ "PY": {"code": "SA", "name": "South America"},
+ "IQ": {"code": "AS", "name": "Asia"},
+ "PA": {"code": "NA", "name": "North America"},
+ "PF": {"code": "OC", "name": "Oceania"},
+ "PG": {"code": "OC", "name": "Oceania"},
+ "PE": {"code": "SA", "name": "South America"},
+ "PK": {"code": "AS", "name": "Asia"},
+ "PH": {"code": "AS", "name": "Asia"},
+ "PN": {"code": "OC", "name": "Oceania"},
+ "PL": {"code": "EU", "name": "Europe"},
+ "PM": {"code": "NA", "name": "North America"},
+ "ZM": {"code": "AF", "name": "Africa"},
+ "EH": {"code": "AF", "name": "Africa"},
+ "EE": {"code": "EU", "name": "Europe"},
+ "EG": {"code": "AF", "name": "Africa"},
+ "ZA": {"code": "AF", "name": "Africa"},
+ "EC": {"code": "SA", "name": "South America"},
+ "IT": {"code": "EU", "name": "Europe"},
+ "VN": {"code": "AS", "name": "Asia"},
+ "SB": {"code": "OC", "name": "Oceania"},
+ "ET": {"code": "AF", "name": "Africa"},
+ "SO": {"code": "AF", "name": "Africa"},
+ "ZW": {"code": "AF", "name": "Africa"},
+ "SA": {"code": "AS", "name": "Asia"},
+ "ES": {"code": "EU", "name": "Europe"},
+ "ER": {"code": "AF", "name": "Africa"},
+ "ME": {"code": "EU", "name": "Europe"},
+ "MD": {"code": "EU", "name": "Europe"},
+ "MG": {"code": "AF", "name": "Africa"},
+ "MF": {"code": "NA", "name": "North America"},
+ "MA": {"code": "AF", "name": "Africa"},
+ "MC": {"code": "EU", "name": "Europe"},
+ "UZ": {"code": "AS", "name": "Asia"},
+ "MM": {"code": "AS", "name": "Asia"},
+ "ML": {"code": "AF", "name": "Africa"},
+ "MO": {"code": "AS", "name": "Asia"},
+ "MN": {"code": "AS", "name": "Asia"},
+ "MH": {"code": "OC", "name": "Oceania"},
+ "MK": {"code": "EU", "name": "Europe"},
+ "MU": {"code": "AF", "name": "Africa"},
+ "MT": {"code": "EU", "name": "Europe"},
+ "MW": {"code": "AF", "name": "Africa"},
+ "MV": {"code": "AS", "name": "Asia"},
+ "MQ": {"code": "NA", "name": "North America"},
+ "MP": {"code": "OC", "name": "Oceania"},
+ "MS": {"code": "NA", "name": "North America"},
+ "MR": {"code": "AF", "name": "Africa"},
+ "IM": {"code": "EU", "name": "Europe"},
+ "UG": {"code": "AF", "name": "Africa"},
+ "TZ": {"code": "AF", "name": "Africa"},
+ "MY": {"code": "AS", "name": "Asia"},
+ "MX": {"code": "NA", "name": "North America"},
+ "IL": {"code": "AS", "name": "Asia"},
+ "FR": {"code": "EU", "name": "Europe"},
+ "IO": {"code": "AS", "name": "Asia"},
+ "SH": {"code": "AF", "name": "Africa"},
+ "FI": {"code": "EU", "name": "Europe"},
+ "FJ": {"code": "OC", "name": "Oceania"},
+ "FK": {"code": "SA", "name": "South America"},
+ "FM": {"code": "OC", "name": "Oceania"},
+ "FO": {"code": "EU", "name": "Europe"},
+ "NI": {"code": "NA", "name": "North America"},
+ "NL": {"code": "EU", "name": "Europe"},
+ "NO": {"code": "EU", "name": "Europe"},
+ "NA": {"code": "AF", "name": "Africa"},
+ "VU": {"code": "OC", "name": "Oceania"},
+ "NC": {"code": "OC", "name": "Oceania"},
+ "NE": {"code": "AF", "name": "Africa"},
+ "NF": {"code": "OC", "name": "Oceania"},
+ "NG": {"code": "AF", "name": "Africa"},
+ "NZ": {"code": "OC", "name": "Oceania"},
+ "NP": {"code": "AS", "name": "Asia"},
+ "NR": {"code": "OC", "name": "Oceania"},
+ "NU": {"code": "OC", "name": "Oceania"},
+ "CK": {"code": "OC", "name": "Oceania"},
+ "XK": {"code": "EU", "name": "Europe"},
+ "CI": {"code": "AF", "name": "Africa"},
+ "CH": {"code": "EU", "name": "Europe"},
+ "CO": {"code": "SA", "name": "South America"},
+ "CN": {"code": "AS", "name": "Asia"},
+ "CM": {"code": "AF", "name": "Africa"},
+ "CL": {"code": "SA", "name": "South America"},
+ "CC": {"code": "AS", "name": "Asia"},
+ "CA": {"code": "NA", "name": "North America"},
+ "CG": {"code": "AF", "name": "Africa"},
+ "CF": {"code": "AF", "name": "Africa"},
+ "CD": {"code": "AF", "name": "Africa"},
+ "CZ": {"code": "EU", "name": "Europe"},
+ "CY": {"code": "EU", "name": "Europe"},
+ "CX": {"code": "AS", "name": "Asia"},
+ "CR": {"code": "NA", "name": "North America"},
+ "CW": {"code": "NA", "name": "North America"},
+ "CV": {"code": "AF", "name": "Africa"},
+ "CU": {"code": "NA", "name": "North America"},
+ "SZ": {"code": "AF", "name": "Africa"},
+ "SY": {"code": "AS", "name": "Asia"},
+ "SX": {"code": "NA", "name": "North America"},
+ "KG": {"code": "AS", "name": "Asia"},
+ "KE": {"code": "AF", "name": "Africa"},
+ "SS": {"code": "AF", "name": "Africa"},
+ "SR": {"code": "SA", "name": "South America"},
+ "KI": {"code": "OC", "name": "Oceania"},
+ "KH": {"code": "AS", "name": "Asia"},
+ "KN": {"code": "NA", "name": "North America"},
+ "KM": {"code": "AF", "name": "Africa"},
+ "ST": {"code": "AF", "name": "Africa"},
+ "SK": {"code": "EU", "name": "Europe"},
+ "KR": {"code": "AS", "name": "Asia"},
+ "SI": {"code": "EU", "name": "Europe"},
+ "KP": {"code": "AS", "name": "Asia"},
+ "KW": {"code": "AS", "name": "Asia"},
+ "SN": {"code": "AF", "name": "Africa"},
+ "SM": {"code": "EU", "name": "Europe"},
+ "SL": {"code": "AF", "name": "Africa"},
+ "SC": {"code": "AF", "name": "Africa"},
+ "KZ": {"code": "AS", "name": "Asia"},
+ "KY": {"code": "NA", "name": "North America"},
+ "SG": {"code": "AS", "name": "Asia"},
+ "SE": {"code": "EU", "name": "Europe"},
+ "SD": {"code": "AF", "name": "Africa"},
+ "DO": {"code": "NA", "name": "North America"},
+ "DM": {"code": "NA", "name": "North America"},
+ "DJ": {"code": "AF", "name": "Africa"},
+ "DK": {"code": "EU", "name": "Europe"},
+ "VG": {"code": "NA", "name": "North America"},
+ "DE": {"code": "EU", "name": "Europe"},
+ "YE": {"code": "AS", "name": "Asia"},
+ "DZ": {"code": "AF", "name": "Africa"},
+ "US": {"code": "NA", "name": "North America"},
+ "UY": {"code": "SA", "name": "South America"},
+ "YT": {"code": "AF", "name": "Africa"},
+ "UM": {"code": "OC", "name": "Oceania"},
+ "LB": {"code": "AS", "name": "Asia"},
+ "LC": {"code": "NA", "name": "North America"},
+ "LA": {"code": "AS", "name": "Asia"},
+ "TV": {"code": "OC", "name": "Oceania"},
+ "TW": {"code": "AS", "name": "Asia"},
+ "TT": {"code": "NA", "name": "North America"},
+ "TR": {"code": "AS", "name": "Asia"},
+ "LK": {"code": "AS", "name": "Asia"},
+ "LI": {"code": "EU", "name": "Europe"},
+ "LV": {"code": "EU", "name": "Europe"},
+ "TO": {"code": "OC", "name": "Oceania"},
+ "LT": {"code": "EU", "name": "Europe"},
+ "LU": {"code": "EU", "name": "Europe"},
+ "LR": {"code": "AF", "name": "Africa"},
+ "LS": {"code": "AF", "name": "Africa"},
+ "TH": {"code": "AS", "name": "Asia"},
+ "TF": {"code": "AN", "name": "Antarctica"},
+ "TG": {"code": "AF", "name": "Africa"},
+ "TD": {"code": "AF", "name": "Africa"},
+ "TC": {"code": "NA", "name": "North America"},
+ "LY": {"code": "AF", "name": "Africa"},
+ "VA": {"code": "EU", "name": "Europe"},
+ "VC": {"code": "NA", "name": "North America"},
+ "AE": {"code": "AS", "name": "Asia"},
+ "AD": {"code": "EU", "name": "Europe"},
+ "AG": {"code": "NA", "name": "North America"},
+ "AF": {"code": "AS", "name": "Asia"},
+ "AI": {"code": "NA", "name": "North America"},
+ "VI": {"code": "NA", "name": "North America"},
+ "IS": {"code": "EU", "name": "Europe"},
+ "IR": {"code": "AS", "name": "Asia"},
+ "AM": {"code": "AS", "name": "Asia"},
+ "AL": {"code": "EU", "name": "Europe"},
+ "AO": {"code": "AF", "name": "Africa"},
+ "AQ": {"code": "AN", "name": "Antarctica"},
+ "AS": {"code": "OC", "name": "Oceania"},
+ "AR": {"code": "SA", "name": "South America"},
+ "AU": {"code": "OC", "name": "Oceania"},
+ "AT": {"code": "EU", "name": "Europe"},
+ "AW": {"code": "NA", "name": "North America"},
+ "IN": {"code": "AS", "name": "Asia"},
+ "AX": {"code": "EU", "name": "Europe"},
+ "AZ": {"code": "AS", "name": "Asia"},
+ "IE": {"code": "EU", "name": "Europe"},
+ "ID": {"code": "AS", "name": "Asia"},
+ "UA": {"code": "EU", "name": "Europe"},
+ "QA": {"code": "AS", "name": "Asia"},
+ "MZ": {"code": "AF", "name": "Africa"}
+ }
diff --git a/app/Services/IPinfo/json/countries.json b/app/Services/IPinfo/json/countries.json
new file mode 100644
index 00000000..e9c6f71d
--- /dev/null
+++ b/app/Services/IPinfo/json/countries.json
@@ -0,0 +1 @@
+{"BD": "Bangladesh", "BE": "Belgium", "BF": "Burkina Faso", "BG": "Bulgaria", "BA": "Bosnia and Herzegovina", "BB": "Barbados", "WF": "Wallis and Futuna", "BL": "Saint Barthelemy", "BM": "Bermuda", "BN": "Brunei", "BO": "Bolivia", "BH": "Bahrain", "BI": "Burundi", "BJ": "Benin", "BT": "Bhutan", "JM": "Jamaica", "BV": "Bouvet Island", "BW": "Botswana", "WS": "Samoa", "BQ": "Bonaire, Saint Eustatius and Saba ", "BR": "Brazil", "BS": "Bahamas", "JE": "Jersey", "BY": "Belarus", "BZ": "Belize", "RU": "Russia", "RW": "Rwanda", "RS": "Serbia", "TL": "East Timor", "RE": "Reunion", "TM": "Turkmenistan", "TJ": "Tajikistan", "RO": "Romania", "TK": "Tokelau", "GW": "Guinea-Bissau", "GU": "Guam", "GT": "Guatemala", "GS": "South Georgia and the South Sandwich Islands", "GR": "Greece", "GQ": "Equatorial Guinea", "GP": "Guadeloupe", "JP": "Japan", "GY": "Guyana", "GG": "Guernsey", "GF": "French Guiana", "GE": "Georgia", "GD": "Grenada", "GB": "United Kingdom", "GA": "Gabon", "SV": "El Salvador", "GN": "Guinea", "GM": "Gambia", "GL": "Greenland", "GI": "Gibraltar", "GH": "Ghana", "OM": "Oman", "TN": "Tunisia", "JO": "Jordan", "HR": "Croatia", "HT": "Haiti", "HU": "Hungary", "HK": "Hong Kong", "HN": "Honduras", "HM": "Heard Island and McDonald Islands", "VE": "Venezuela", "PR": "Puerto Rico", "PS": "Palestinian Territory", "PW": "Palau", "PT": "Portugal", "SJ": "Svalbard and Jan Mayen", "PY": "Paraguay", "IQ": "Iraq", "PA": "Panama", "PF": "French Polynesia", "PG": "Papua New Guinea", "PE": "Peru", "PK": "Pakistan", "PH": "Philippines", "PN": "Pitcairn", "PL": "Poland", "PM": "Saint Pierre and Miquelon", "ZM": "Zambia", "EH": "Western Sahara", "EE": "Estonia", "EG": "Egypt", "ZA": "South Africa", "EC": "Ecuador", "IT": "Italy", "VN": "Vietnam", "SB": "Solomon Islands", "ET": "Ethiopia", "SO": "Somalia", "ZW": "Zimbabwe", "SA": "Saudi Arabia", "ES": "Spain", "ER": "Eritrea", "ME": "Montenegro", "MD": "Moldova", "MG": "Madagascar", "MF": "Saint Martin", "MA": "Morocco", "MC": "Monaco", "UZ": "Uzbekistan", "MM": "Myanmar", "ML": "Mali", "MO": "Macao", "MN": "Mongolia", "MH": "Marshall Islands", "MK": "Macedonia", "MU": "Mauritius", "MT": "Malta", "MW": "Malawi", "MV": "Maldives", "MQ": "Martinique", "MP": "Northern Mariana Islands", "MS": "Montserrat", "MR": "Mauritania", "IM": "Isle of Man", "UG": "Uganda", "TZ": "Tanzania", "MY": "Malaysia", "MX": "Mexico", "IL": "Israel", "FR": "France", "IO": "British Indian Ocean Territory", "SH": "Saint Helena", "FI": "Finland", "FJ": "Fiji", "FK": "Falkland Islands", "FM": "Micronesia", "FO": "Faroe Islands", "NI": "Nicaragua", "NL": "Netherlands", "NO": "Norway", "NA": "Namibia", "VU": "Vanuatu", "NC": "New Caledonia", "NE": "Niger", "NF": "Norfolk Island", "NG": "Nigeria", "NZ": "New Zealand", "NP": "Nepal", "NR": "Nauru", "NU": "Niue", "CK": "Cook Islands", "XK": "Kosovo", "CI": "Ivory Coast", "CH": "Switzerland", "CO": "Colombia", "CN": "China", "CM": "Cameroon", "CL": "Chile", "CC": "Cocos Islands", "CA": "Canada", "CG": "Republic of the Congo", "CF": "Central African Republic", "CD": "Democratic Republic of the Congo", "CZ": "Czech Republic", "CY": "Cyprus", "CX": "Christmas Island", "CR": "Costa Rica", "CW": "Curacao", "CV": "Cape Verde", "CU": "Cuba", "SZ": "Swaziland", "SY": "Syria", "SX": "Sint Maarten", "KG": "Kyrgyzstan", "KE": "Kenya", "SS": "South Sudan", "SR": "Suriname", "KI": "Kiribati", "KH": "Cambodia", "KN": "Saint Kitts and Nevis", "KM": "Comoros", "ST": "Sao Tome and Principe", "SK": "Slovakia", "KR": "South Korea", "SI": "Slovenia", "KP": "North Korea", "KW": "Kuwait", "SN": "Senegal", "SM": "San Marino", "SL": "Sierra Leone", "SC": "Seychelles", "KZ": "Kazakhstan", "KY": "Cayman Islands", "SG": "Singapore", "SE": "Sweden", "SD": "Sudan", "DO": "Dominican Republic", "DM": "Dominica", "DJ": "Djibouti", "DK": "Denmark", "VG": "British Virgin Islands", "DE": "Germany", "YE": "Yemen", "DZ": "Algeria", "US": "United States", "UY": "Uruguay", "YT": "Mayotte", "UM": "United States Minor Outlying Islands", "LB": "Lebanon", "LC": "Saint Lucia", "LA": "Laos", "TV": "Tuvalu", "TW": "Taiwan", "TT": "Trinidad and Tobago", "TR": "Turkey", "LK": "Sri Lanka", "LI": "Liechtenstein", "LV": "Latvia", "TO": "Tonga", "LT": "Lithuania", "LU": "Luxembourg", "LR": "Liberia", "LS": "Lesotho", "TH": "Thailand", "TF": "French Southern Territories", "TG": "Togo", "TD": "Chad", "TC": "Turks and Caicos Islands", "LY": "Libya", "VA": "Vatican", "VC": "Saint Vincent and the Grenadines", "AE": "United Arab Emirates", "AD": "Andorra", "AG": "Antigua and Barbuda", "AF": "Afghanistan", "AI": "Anguilla", "VI": "U.S. Virgin Islands", "IS": "Iceland", "IR": "Iran", "AM": "Armenia", "AL": "Albania", "AO": "Angola", "AQ": "Antarctica", "AS": "American Samoa", "AR": "Argentina", "AU": "Australia", "AT": "Austria", "AW": "Aruba", "IN": "India", "AX": "Aland Islands", "AZ": "Azerbaijan", "IE": "Ireland", "ID": "Indonesia", "UA": "Ukraine", "QA": "Qatar", "MZ": "Mozambique"}
diff --git a/app/Services/IPinfo/json/currency.json b/app/Services/IPinfo/json/currency.json
new file mode 100644
index 00000000..9c962b9e
--- /dev/null
+++ b/app/Services/IPinfo/json/currency.json
@@ -0,0 +1,253 @@
+{
+ "AD" : { "code": "EUR" ,"symbol": "€"},
+ "AE" : { "code": "AED" ,"symbol": "د.إ"},
+ "AF" : { "code": "AFN" ,"symbol": "؋"},
+ "AG" : { "code": "XCD" ,"symbol": "$"},
+ "AI" : { "code": "XCD" ,"symbol": "$"},
+ "AL" : { "code": "ALL" ,"symbol": "L"},
+ "AM" : { "code": "AMD" ,"symbol": "֏"},
+ "AO" : { "code": "AOA" ,"symbol": "Kz"},
+ "AQ" : { "code": "" ,"symbol": "$"},
+ "AR" : { "code": "ARS" ,"symbol": "$"},
+ "AS" : { "code": "USD" ,"symbol": "$"},
+ "AT" : { "code": "EUR" ,"symbol": "€"},
+ "AU" : { "code": "AUD" ,"symbol": "$"},
+ "AW" : { "code": "AWG" ,"symbol": "ƒ"},
+ "AX" : { "code": "EUR" ,"symbol": "€"},
+ "AZ" : { "code": "AZN" ,"symbol": "₼"},
+ "BA" : { "code": "BAM" ,"symbol": "KM"},
+ "BB" : { "code": "BBD" ,"symbol": "$"},
+ "BD" : { "code": "BDT" ,"symbol": "৳"},
+ "BE" : { "code": "EUR" ,"symbol": "€"},
+ "BF" : { "code": "XOF" ,"symbol": "CFA"},
+ "BG" : { "code": "BGN" ,"symbol": "лв"},
+ "BH" : { "code": "BHD" ,"symbol": ".د.ب"},
+ "BI" : { "code": "BIF" ,"symbol": "FBu"},
+ "BJ" : { "code": "XOF" ,"symbol": "CFA"},
+ "BL" : { "code": "EUR" ,"symbol": "€"},
+ "BM" : { "code": "BMD" ,"symbol": "$"},
+ "BN" : { "code": "BND" ,"symbol": "$"},
+ "BO" : { "code": "BOB" ,"symbol": "$b"},
+ "BQ" : { "code": "USD" ,"symbol": "$"},
+ "BR" : { "code": "BRL" ,"symbol": "R$"},
+ "BS" : { "code": "BSD" ,"symbol": "$"},
+ "BT" : { "code": "BTN" ,"symbol": "Nu."},
+ "BV" : { "code": "NOK" ,"symbol": "kr"},
+ "BW" : { "code": "BWP" ,"symbol": "P"},
+ "BY" : { "code": "BYR" ,"symbol": "Br"},
+ "BZ" : { "code": "BZD" ,"symbol": "BZ$"},
+ "CA" : { "code": "CAD" ,"symbol": "$"},
+ "CC" : { "code": "AUD" ,"symbol": "$"},
+ "CD" : { "code": "CDF" ,"symbol": "FC"},
+ "CF" : { "code": "XAF" ,"symbol": "FCFA"},
+ "CG" : { "code": "XAF" ,"symbol": "FCFA"},
+ "CH" : { "code": "CHF" ,"symbol": "CHF"},
+ "CI" : { "code": "XOF" ,"symbol": "CFA"},
+ "CK" : { "code": "NZD" ,"symbol": "$"},
+ "CL" : { "code": "CLP" ,"symbol": "$"},
+ "CM" : { "code": "XAF" ,"symbol": "FCFA"},
+ "CN" : { "code": "CNY" ,"symbol": "¥"},
+ "CO" : { "code": "COP" ,"symbol": "$"},
+ "CR" : { "code": "CRC" ,"symbol": "₡"},
+ "CU" : { "code": "CUP" ,"symbol": "₱"},
+ "CV" : { "code": "CVE" ,"symbol": "$"},
+ "CW" : { "code": "ANG" ,"symbol": "ƒ"},
+ "CX" : { "code": "AUD" ,"symbol": "$"},
+ "CY" : { "code": "EUR" ,"symbol": "€"},
+ "CZ" : { "code": "CZK" ,"symbol": "Kč"},
+ "DE" : { "code": "EUR" ,"symbol": "€"},
+ "DJ" : { "code": "DJF" ,"symbol": "Fdj"},
+ "DK" : { "code": "DKK" ,"symbol": "kr"},
+ "DM" : { "code": "XCD" ,"symbol": "$"},
+ "DO" : { "code": "DOP" ,"symbol": "RD$"},
+ "DZ" : { "code": "DZD" ,"symbol": "دج"},
+ "EC" : { "code": "USD" ,"symbol": "$"},
+ "EE" : { "code": "EUR" ,"symbol": "€"},
+ "EG" : { "code": "EGP" ,"symbol": "£"},
+ "EH" : { "code": "MAD" ,"symbol": "MAD"},
+ "ER" : { "code": "ERN" ,"symbol": "Nfk"},
+ "ES" : { "code": "EUR" ,"symbol": "€"},
+ "ET" : { "code": "ETB" ,"symbol": "Br"},
+ "FI" : { "code": "EUR" ,"symbol": "€"},
+ "FJ" : { "code": "FJD" ,"symbol": "$"},
+ "FK" : { "code": "FKP" ,"symbol": "£"},
+ "FM" : { "code": "USD" ,"symbol": "$"},
+ "FO" : { "code": "DKK" ,"symbol": "kr"},
+ "FR" : { "code": "EUR" ,"symbol": "€"},
+ "GA" : { "code": "XAF" ,"symbol": "FCFA"},
+ "GB" : { "code": "GBP" ,"symbol": "£"},
+ "GD" : { "code": "XCD" ,"symbol": "$"},
+ "GE" : { "code": "GEL" ,"symbol": "ლ"},
+ "GF" : { "code": "EUR" ,"symbol": "€"},
+ "GG" : { "code": "GBP" ,"symbol": "£"},
+ "GH" : { "code": "GHS" ,"symbol": "GH₵"},
+ "GI" : { "code": "GIP" ,"symbol": "£"},
+ "GL" : { "code": "DKK" ,"symbol": "kr"},
+ "GM" : { "code": "GMD" ,"symbol": "D"},
+ "GN" : { "code": "GNF" ,"symbol": "FG"},
+ "GP" : { "code": "EUR" ,"symbol": "€"},
+ "GQ" : { "code": "XAF" ,"symbol": "FCFA"},
+ "GR" : { "code": "EUR" ,"symbol": "€"},
+ "GS" : { "code": "GBP" ,"symbol": "£"},
+ "GT" : { "code": "GTQ" ,"symbol": "Q"},
+ "GU" : { "code": "USD" ,"symbol": "$"},
+ "GW" : { "code": "XOF" ,"symbol": "CFA"},
+ "GY" : { "code": "GYD" ,"symbol": "$"},
+ "HK" : { "code": "HKD" ,"symbol": "$"},
+ "HM" : { "code": "AUD" ,"symbol": "$"},
+ "HN" : { "code": "HNL" ,"symbol": "L"},
+ "HR" : { "code": "HRK" ,"symbol": "kn"},
+ "HT" : { "code": "HTG" ,"symbol": "G"},
+ "HU" : { "code": "HUF" ,"symbol": "Ft"},
+ "ID" : { "code": "IDR" ,"symbol": "Rp"},
+ "IE" : { "code": "EUR" ,"symbol": "€"},
+ "IL" : { "code": "ILS" ,"symbol": "₪"},
+ "IM" : { "code": "GBP" ,"symbol": "£"},
+ "IN" : { "code": "INR" ,"symbol": "₹"},
+ "IO" : { "code": "USD" ,"symbol": "$"},
+ "IQ" : { "code": "IQD" ,"symbol": "ع.د"},
+ "IR" : { "code": "IRR" ,"symbol": "﷼"},
+ "IS" : { "code": "ISK" ,"symbol": "kr"},
+ "IT" : { "code": "EUR" ,"symbol": "€"},
+ "JE" : { "code": "GBP" ,"symbol": "£"},
+ "JM" : { "code": "JMD" ,"symbol": "J$"},
+ "JO" : { "code": "JOD" ,"symbol": "JD"},
+ "JP" : { "code": "JPY" ,"symbol": "¥"},
+ "KE" : { "code": "KES" ,"symbol": "KSh"},
+ "KG" : { "code": "KGS" ,"symbol": "лв"},
+ "KH" : { "code": "KHR" ,"symbol": "៛"},
+ "KI" : { "code": "AUD" ,"symbol": "$"},
+ "KM" : { "code": "KMF" ,"symbol": "CF"},
+ "KN" : { "code": "XCD" ,"symbol": "$"},
+ "KP" : { "code": "KPW" ,"symbol": "₩"},
+ "KR" : { "code": "KRW" ,"symbol": "₩"},
+ "KW" : { "code": "KWD" ,"symbol": "KD"},
+ "KY" : { "code": "KYD" ,"symbol": "$"},
+ "KZ" : { "code": "KZT" ,"symbol": "₸"},
+ "LA" : { "code": "LAK" ,"symbol": "₭"},
+ "LB" : { "code": "LBP" ,"symbol": "£"},
+ "LC" : { "code": "XCD" ,"symbol": "$"},
+ "LI" : { "code": "CHF" ,"symbol": "CHF"},
+ "LK" : { "code": "LKR" ,"symbol": "₨"},
+ "LR" : { "code": "LRD" ,"symbol": "$"},
+ "LS" : { "code": "LSL" ,"symbol": "M"},
+ "LT" : { "code": "LTL" ,"symbol": "Lt"},
+ "LU" : { "code": "EUR" ,"symbol": "€"},
+ "LV" : { "code": "EUR" ,"symbol": "€"},
+ "LY" : { "code": "LYD" ,"symbol": "LD"},
+ "MA" : { "code": "MAD" ,"symbol": "MAD"},
+ "MC" : { "code": "EUR" ,"symbol": "€"},
+ "MD" : { "code": "MDL" ,"symbol": "lei"},
+ "ME" : { "code": "EUR" ,"symbol": "€"},
+ "MF" : { "code": "EUR" ,"symbol": "€"},
+ "MG" : { "code": "MGA" ,"symbol": "Ar"},
+ "MH" : { "code": "USD" ,"symbol": "$"},
+ "MK" : { "code": "MKD" ,"symbol": "ден"},
+ "ML" : { "code": "XOF" ,"symbol": "CFA"},
+ "MM" : { "code": "MMK" ,"symbol": "K"},
+ "MN" : { "code": "MNT" ,"symbol": "₮"},
+ "MO" : { "code": "MOP" ,"symbol": "MOP$"},
+ "MP" : { "code": "USD" ,"symbol": "$"},
+ "MQ" : { "code": "EUR" ,"symbol": "€"},
+ "MR" : { "code": "MRO" ,"symbol": "UM"},
+ "MS" : { "code": "XCD" ,"symbol": "$"},
+ "MT" : { "code": "EUR" ,"symbol": "€"},
+ "MU" : { "code": "MUR" ,"symbol": "₨"},
+ "MV" : { "code": "MVR" ,"symbol": "Rf"},
+ "MW" : { "code": "MWK" ,"symbol": "MK"},
+ "MX" : { "code": "MXN" ,"symbol": "$"},
+ "MY" : { "code": "MYR" ,"symbol": "RM"},
+ "MZ" : { "code": "MZN" ,"symbol": "MT"},
+ "NA" : { "code": "NAD" ,"symbol": "$"},
+ "NC" : { "code": "XPF" ,"symbol": "₣"},
+ "NE" : { "code": "XOF" ,"symbol": "CFA"},
+ "NF" : { "code": "AUD" ,"symbol": "$"},
+ "NG" : { "code": "NGN" ,"symbol": "₦"},
+ "NI" : { "code": "NIO" ,"symbol": "C$"},
+ "NL" : { "code": "EUR" ,"symbol": "€"},
+ "NO" : { "code": "NOK" ,"symbol": "kr"},
+ "NP" : { "code": "NPR" ,"symbol": "₨"},
+ "NR" : { "code": "AUD" ,"symbol": "$"},
+ "NU" : { "code": "NZD" ,"symbol": "$"},
+ "NZ" : { "code": "NZD" ,"symbol": "$"},
+ "OM" : { "code": "OMR" ,"symbol": "﷼"},
+ "PA" : { "code": "PAB" ,"symbol": "B/."},
+ "PE" : { "code": "PEN" ,"symbol": "S/."},
+ "PF" : { "code": "XPF" ,"symbol": "₣"},
+ "PG" : { "code": "PGK" ,"symbol": "K"},
+ "PH" : { "code": "PHP" ,"symbol": "₱"},
+ "PK" : { "code": "PKR" ,"symbol": "₨"},
+ "PL" : { "code": "PLN" ,"symbol": "zł"},
+ "PM" : { "code": "EUR" ,"symbol": "€"},
+ "PN" : { "code": "NZD" ,"symbol": "$"},
+ "PR" : { "code": "USD" ,"symbol": "$"},
+ "PS" : { "code": "ILS" ,"symbol": "₪"},
+ "PT" : { "code": "EUR" ,"symbol": "€"},
+ "PW" : { "code": "USD" ,"symbol": "$"},
+ "PY" : { "code": "PYG" ,"symbol": "Gs"},
+ "QA" : { "code": "QAR" ,"symbol": "﷼"},
+ "RE" : { "code": "EUR" ,"symbol": "€"},
+ "RO" : { "code": "RON" ,"symbol": "lei"},
+ "RS" : { "code": "RSD" ,"symbol": "Дин."},
+ "RU" : { "code": "RUB" ,"symbol": "₽"},
+ "RW" : { "code": "RWF" ,"symbol": "R₣"},
+ "SA" : { "code": "SAR" ,"symbol": "﷼"},
+ "SB" : { "code": "SBD" ,"symbol": "$"},
+ "SC" : { "code": "SCR" ,"symbol": "₨"},
+ "SD" : { "code": "SDG" ,"symbol": "ج.س."},
+ "SE" : { "code": "SEK" ,"symbol": "kr"},
+ "SG" : { "code": "SGD" ,"symbol": "S$"},
+ "SH" : { "code": "SHP" ,"symbol": "£"},
+ "SI" : { "code": "EUR" ,"symbol": "€"},
+ "SJ" : { "code": "NOK" ,"symbol": "kr"},
+ "SK" : { "code": "EUR" ,"symbol": "€"},
+ "SL" : { "code": "SLL" ,"symbol": "Le"},
+ "SM" : { "code": "EUR" ,"symbol": "€"},
+ "SN" : { "code": "XOF" ,"symbol": "CFA"},
+ "SO" : { "code": "SOS" ,"symbol": "S"},
+ "SR" : { "code": "SRD" ,"symbol": "$"},
+ "SS" : { "code": "SSP" ,"symbol": "£"},
+ "ST" : { "code": "STD" ,"symbol": "Db"},
+ "SV" : { "code": "USD" ,"symbol": "$"},
+ "SX" : { "code": "ANG" ,"symbol": "ƒ"},
+ "SY" : { "code": "SYP" ,"symbol": "£"},
+ "SZ" : { "code": "SZL" ,"symbol": "E"},
+ "TC" : { "code": "USD" ,"symbol": "$"},
+ "TD" : { "code": "XAF" ,"symbol": "FCFA"},
+ "TF" : { "code": "EUR" ,"symbol": "€"},
+ "TG" : { "code": "XOF" ,"symbol": "CFA"},
+ "TH" : { "code": "THB" ,"symbol": "฿"},
+ "TJ" : { "code": "TJS" ,"symbol": "SM"},
+ "TK" : { "code": "NZD" ,"symbol": "$"},
+ "TL" : { "code": "USD" ,"symbol": "$"},
+ "TM" : { "code": "TMT" ,"symbol": "T"},
+ "TN" : { "code": "TND" ,"symbol": "د.ت"},
+ "TO" : { "code": "TOP" ,"symbol": "T$"},
+ "TR" : { "code": "TRY" ,"symbol": "₺"},
+ "TT" : { "code": "TTD" ,"symbol": "TT$"},
+ "TV" : { "code": "AUD" ,"symbol": "$"},
+ "TW" : { "code": "TWD" ,"symbol": "NT$"},
+ "TZ" : { "code": "TZS" ,"symbol": "TSh"},
+ "UA" : { "code": "UAH" ,"symbol": "₴"},
+ "UG" : { "code": "UGX" ,"symbol": "USh"},
+ "UM" : { "code": "USD" ,"symbol": "$"},
+ "US" : { "code": "USD" ,"symbol": "$"},
+ "UY" : { "code": "UYU" ,"symbol": "$U"},
+ "UZ" : { "code": "UZS" ,"symbol": "лв"},
+ "VA" : { "code": "EUR" ,"symbol": "€"},
+ "VC" : { "code": "XCD" ,"symbol": "$"},
+ "VE" : { "code": "VEF" ,"symbol": "Bs"},
+ "VG" : { "code": "USD" ,"symbol": "$"},
+ "VI" : { "code": "USD" ,"symbol": "$"},
+ "VN" : { "code": "VND" ,"symbol": "₫"},
+ "VU" : { "code": "VUV" ,"symbol": "VT"},
+ "WF" : { "code": "XPF" ,"symbol": "₣"},
+ "WS" : { "code": "WST" ,"symbol": "WS$"},
+ "XK" : { "code": "EUR" ,"symbol": "€"},
+ "YE" : { "code": "YER" ,"symbol": "﷼"},
+ "YT" : { "code": "EUR" ,"symbol": "€"},
+ "ZA" : { "code": "ZAR" ,"symbol": "R"},
+ "ZM" : { "code": "ZMK" ,"symbol": "ZK"},
+ "ZW" : { "code": "ZWL" ,"symbol": "$"}
+ }
+
\ No newline at end of file
diff --git a/app/Services/IPinfo/json/eu.json b/app/Services/IPinfo/json/eu.json
new file mode 100644
index 00000000..a8872d54
--- /dev/null
+++ b/app/Services/IPinfo/json/eu.json
@@ -0,0 +1 @@
+["IE","AT","LT","LU","LV","DE","DK","SE","SI","SK","CZ","CY","NL","FI","FR","MT","ES","IT","EE","PL","PT","HU","HR","GR","RO","BG","BE"]
diff --git a/app/Services/IPinfo/json/flags.json b/app/Services/IPinfo/json/flags.json
new file mode 100644
index 00000000..950dc774
--- /dev/null
+++ b/app/Services/IPinfo/json/flags.json
@@ -0,0 +1,252 @@
+{
+ "AD": {"emoji": "🇦🇩","unicode": "U+1F1E6 U+1F1E9"},
+ "AE": {"emoji": "🇦🇪","unicode": "U+1F1E6 U+1F1EA"},
+ "AF": {"emoji": "🇦🇫","unicode": "U+1F1E6 U+1F1EB"},
+ "AG": {"emoji": "🇦🇬","unicode": "U+1F1E6 U+1F1EC"},
+ "AI": {"emoji": "🇦🇮","unicode": "U+1F1E6 U+1F1EE"},
+ "AL": {"emoji": "🇦🇱","unicode": "U+1F1E6 U+1F1F1"},
+ "AM": {"emoji": "🇦🇲","unicode": "U+1F1E6 U+1F1F2"},
+ "AO": {"emoji": "🇦🇴","unicode": "U+1F1E6 U+1F1F4"},
+ "AQ": {"emoji": "🇦🇶","unicode": "U+1F1E6 U+1F1F6"},
+ "AR": {"emoji": "🇦🇷","unicode": "U+1F1E6 U+1F1F7"},
+ "AS": {"emoji": "🇦🇸","unicode": "U+1F1E6 U+1F1F8"},
+ "AT": {"emoji": "🇦🇹","unicode": "U+1F1E6 U+1F1F9"},
+ "AU": {"emoji": "🇦🇺","unicode": "U+1F1E6 U+1F1FA"},
+ "AW": {"emoji": "🇦🇼","unicode": "U+1F1E6 U+1F1FC"},
+ "AX": {"emoji": "🇦🇽","unicode": "U+1F1E6 U+1F1FD"},
+ "AZ": {"emoji": "🇦🇿","unicode": "U+1F1E6 U+1F1FF"},
+ "BA": {"emoji": "🇧🇦","unicode": "U+1F1E7 U+1F1E6"},
+ "BB": {"emoji": "🇧🇧","unicode": "U+1F1E7 U+1F1E7"},
+ "BD": {"emoji": "🇧🇩","unicode": "U+1F1E7 U+1F1E9"},
+ "BE": {"emoji": "🇧🇪","unicode": "U+1F1E7 U+1F1EA"},
+ "BF": {"emoji": "🇧🇫","unicode": "U+1F1E7 U+1F1EB"},
+ "BG": {"emoji": "🇧🇬","unicode": "U+1F1E7 U+1F1EC"},
+ "BH": {"emoji": "🇧🇭","unicode": "U+1F1E7 U+1F1ED"},
+ "BI": {"emoji": "🇧🇮","unicode": "U+1F1E7 U+1F1EE"},
+ "BJ": {"emoji": "🇧🇯","unicode": "U+1F1E7 U+1F1EF"},
+ "BL": {"emoji": "🇧🇱","unicode": "U+1F1E7 U+1F1F1"},
+ "BM": {"emoji": "🇧🇲","unicode": "U+1F1E7 U+1F1F2"},
+ "BN": {"emoji": "🇧🇳","unicode": "U+1F1E7 U+1F1F3"},
+ "BO": {"emoji": "🇧🇴","unicode": "U+1F1E7 U+1F1F4"},
+ "BQ": {"emoji": "🇧🇶","unicode": "U+1F1E7 U+1F1F6"},
+ "BR": {"emoji": "🇧🇷","unicode": "U+1F1E7 U+1F1F7"},
+ "BS": {"emoji": "🇧🇸","unicode": "U+1F1E7 U+1F1F8"},
+ "BT": {"emoji": "🇧🇹","unicode": "U+1F1E7 U+1F1F9"},
+ "BV": {"emoji": "🇧🇻","unicode": "U+1F1E7 U+1F1FB"},
+ "BW": {"emoji": "🇧🇼","unicode": "U+1F1E7 U+1F1FC"},
+ "BY": {"emoji": "🇧🇾","unicode": "U+1F1E7 U+1F1FE"},
+ "BZ": {"emoji": "🇧🇿","unicode": "U+1F1E7 U+1F1FF"},
+ "CA": {"emoji": "🇨🇦","unicode": "U+1F1E8 U+1F1E6"},
+ "CC": {"emoji": "🇨🇨","unicode": "U+1F1E8 U+1F1E8"},
+ "CD": {"emoji": "🇨🇩","unicode": "U+1F1E8 U+1F1E9"},
+ "CF": {"emoji": "🇨🇫","unicode": "U+1F1E8 U+1F1EB"},
+ "CG": {"emoji": "🇨🇬","unicode": "U+1F1E8 U+1F1EC"},
+ "CH": {"emoji": "🇨🇭","unicode": "U+1F1E8 U+1F1ED"},
+ "CI": {"emoji": "🇨🇮","unicode": "U+1F1E8 U+1F1EE"},
+ "CK": {"emoji": "🇨🇰","unicode": "U+1F1E8 U+1F1F0"},
+ "CL": {"emoji": "🇨🇱","unicode": "U+1F1E8 U+1F1F1"},
+ "CM": {"emoji": "🇨🇲","unicode": "U+1F1E8 U+1F1F2"},
+ "CN": {"emoji": "🇨🇳","unicode": "U+1F1E8 U+1F1F3"},
+ "CO": {"emoji": "🇨🇴","unicode": "U+1F1E8 U+1F1F4"},
+ "CR": {"emoji": "🇨🇷","unicode": "U+1F1E8 U+1F1F7"},
+ "CU": {"emoji": "🇨🇺","unicode": "U+1F1E8 U+1F1FA"},
+ "CV": {"emoji": "🇨🇻","unicode": "U+1F1E8 U+1F1FB"},
+ "CW": {"emoji": "🇨🇼","unicode": "U+1F1E8 U+1F1FC"},
+ "CX": {"emoji": "🇨🇽","unicode": "U+1F1E8 U+1F1FD"},
+ "CY": {"emoji": "🇨🇾","unicode": "U+1F1E8 U+1F1FE"},
+ "CZ": {"emoji": "🇨🇿","unicode": "U+1F1E8 U+1F1FF"},
+ "DE": {"emoji": "🇩🇪","unicode": "U+1F1E9 U+1F1EA"},
+ "DJ": {"emoji": "🇩🇯","unicode": "U+1F1E9 U+1F1EF"},
+ "DK": {"emoji": "🇩🇰","unicode": "U+1F1E9 U+1F1F0"},
+ "DM": {"emoji": "🇩🇲","unicode": "U+1F1E9 U+1F1F2"},
+ "DO": {"emoji": "🇩🇴","unicode": "U+1F1E9 U+1F1F4"},
+ "DZ": {"emoji": "🇩🇿","unicode": "U+1F1E9 U+1F1FF"},
+ "EC": {"emoji": "🇪🇨","unicode": "U+1F1EA U+1F1E8"},
+ "EE": {"emoji": "🇪🇪","unicode": "U+1F1EA U+1F1EA"},
+ "EG": {"emoji": "🇪🇬","unicode": "U+1F1EA U+1F1EC"},
+ "EH": {"emoji": "🇪🇭","unicode": "U+1F1EA U+1F1ED"},
+ "ER": {"emoji": "🇪🇷","unicode": "U+1F1EA U+1F1F7"},
+ "ES": {"emoji": "🇪🇸","unicode": "U+1F1EA U+1F1F8"},
+ "ET": {"emoji": "🇪🇹","unicode": "U+1F1EA U+1F1F9"},
+ "FI": {"emoji": "🇫🇮","unicode": "U+1F1EB U+1F1EE"},
+ "FJ": {"emoji": "🇫🇯","unicode": "U+1F1EB U+1F1EF"},
+ "FK": {"emoji": "🇫🇰","unicode": "U+1F1EB U+1F1F0"},
+ "FM": {"emoji": "🇫🇲","unicode": "U+1F1EB U+1F1F2"},
+ "FO": {"emoji": "🇫🇴","unicode": "U+1F1EB U+1F1F4"},
+ "FR": {"emoji": "🇫🇷","unicode": "U+1F1EB U+1F1F7"},
+ "GA": {"emoji": "🇬🇦","unicode": "U+1F1EC U+1F1E6"},
+ "GB": {"emoji": "🇬🇧","unicode": "U+1F1EC U+1F1E7"},
+ "GD": {"emoji": "🇬🇩","unicode": "U+1F1EC U+1F1E9"},
+ "GE": {"emoji": "🇬🇪","unicode": "U+1F1EC U+1F1EA"},
+ "GF": {"emoji": "🇬🇫","unicode": "U+1F1EC U+1F1EB"},
+ "GG": {"emoji": "🇬🇬","unicode": "U+1F1EC U+1F1EC"},
+ "GH": {"emoji": "🇬🇭","unicode": "U+1F1EC U+1F1ED"},
+ "GI": {"emoji": "🇬🇮","unicode": "U+1F1EC U+1F1EE"},
+ "GL": {"emoji": "🇬🇱","unicode": "U+1F1EC U+1F1F1"},
+ "GM": {"emoji": "🇬🇲","unicode": "U+1F1EC U+1F1F2"},
+ "GN": {"emoji": "🇬🇳","unicode": "U+1F1EC U+1F1F3"},
+ "GP": {"emoji": "🇬🇵","unicode": "U+1F1EC U+1F1F5"},
+ "GQ": {"emoji": "🇬🇶","unicode": "U+1F1EC U+1F1F6"},
+ "GR": {"emoji": "🇬🇷","unicode": "U+1F1EC U+1F1F7"},
+ "GS": {"emoji": "🇬🇸","unicode": "U+1F1EC U+1F1F8"},
+ "GT": {"emoji": "🇬🇹","unicode": "U+1F1EC U+1F1F9"},
+ "GU": {"emoji": "🇬🇺","unicode": "U+1F1EC U+1F1FA"},
+ "GW": {"emoji": "🇬🇼","unicode": "U+1F1EC U+1F1FC"},
+ "GY": {"emoji": "🇬🇾","unicode": "U+1F1EC U+1F1FE"},
+ "HK": {"emoji": "🇭🇰","unicode": "U+1F1ED U+1F1F0"},
+ "HM": {"emoji": "🇭🇲","unicode": "U+1F1ED U+1F1F2"},
+ "HN": {"emoji": "🇭🇳","unicode": "U+1F1ED U+1F1F3"},
+ "HR": {"emoji": "🇭🇷","unicode": "U+1F1ED U+1F1F7"},
+ "HT": {"emoji": "🇭🇹","unicode": "U+1F1ED U+1F1F9"},
+ "HU": {"emoji": "🇭🇺","unicode": "U+1F1ED U+1F1FA"},
+ "ID": {"emoji": "🇮🇩","unicode": "U+1F1EE U+1F1E9"},
+ "IE": {"emoji": "🇮🇪","unicode": "U+1F1EE U+1F1EA"},
+ "IL": {"emoji": "🇮🇱","unicode": "U+1F1EE U+1F1F1"},
+ "IM": {"emoji": "🇮🇲","unicode": "U+1F1EE U+1F1F2"},
+ "IN": {"emoji": "🇮🇳","unicode": "U+1F1EE U+1F1F3"},
+ "IO": {"emoji": "🇮🇴","unicode": "U+1F1EE U+1F1F4"},
+ "IQ": {"emoji": "🇮🇶","unicode": "U+1F1EE U+1F1F6"},
+ "IR": {"emoji": "🇮🇷","unicode": "U+1F1EE U+1F1F7"},
+ "IS": {"emoji": "🇮🇸","unicode": "U+1F1EE U+1F1F8"},
+ "IT": {"emoji": "🇮🇹","unicode": "U+1F1EE U+1F1F9"},
+ "JE": {"emoji": "🇯🇪","unicode": "U+1F1EF U+1F1EA"},
+ "JM": {"emoji": "🇯🇲","unicode": "U+1F1EF U+1F1F2"},
+ "JO": {"emoji": "🇯🇴","unicode": "U+1F1EF U+1F1F4"},
+ "JP": {"emoji": "🇯🇵","unicode": "U+1F1EF U+1F1F5"},
+ "KE": {"emoji": "🇰🇪","unicode": "U+1F1F0 U+1F1EA"},
+ "KG": {"emoji": "🇰🇬","unicode": "U+1F1F0 U+1F1EC"},
+ "KH": {"emoji": "🇰🇭","unicode": "U+1F1F0 U+1F1ED"},
+ "KI": {"emoji": "🇰🇮","unicode": "U+1F1F0 U+1F1EE"},
+ "KM": {"emoji": "🇰🇲","unicode": "U+1F1F0 U+1F1F2"},
+ "KN": {"emoji": "🇰🇳","unicode": "U+1F1F0 U+1F1F3"},
+ "KP": {"emoji": "🇰🇵","unicode": "U+1F1F0 U+1F1F5"},
+ "KR": {"emoji": "🇰🇷","unicode": "U+1F1F0 U+1F1F7"},
+ "KW": {"emoji": "🇰🇼","unicode": "U+1F1F0 U+1F1FC"},
+ "KY": {"emoji": "🇰🇾","unicode": "U+1F1F0 U+1F1FE"},
+ "KZ": {"emoji": "🇰🇿","unicode": "U+1F1F0 U+1F1FF"},
+ "LA": {"emoji": "🇱🇦","unicode": "U+1F1F1 U+1F1E6"},
+ "LB": {"emoji": "🇱🇧","unicode": "U+1F1F1 U+1F1E7"},
+ "LC": {"emoji": "🇱🇨","unicode": "U+1F1F1 U+1F1E8"},
+ "LI": {"emoji": "🇱🇮","unicode": "U+1F1F1 U+1F1EE"},
+ "LK": {"emoji": "🇱🇰","unicode": "U+1F1F1 U+1F1F0"},
+ "LR": {"emoji": "🇱🇷","unicode": "U+1F1F1 U+1F1F7"},
+ "LS": {"emoji": "🇱🇸","unicode": "U+1F1F1 U+1F1F8"},
+ "LT": {"emoji": "🇱🇹","unicode": "U+1F1F1 U+1F1F9"},
+ "LU": {"emoji": "🇱🇺","unicode": "U+1F1F1 U+1F1FA"},
+ "LV": {"emoji": "🇱🇻","unicode": "U+1F1F1 U+1F1FB"},
+ "LY": {"emoji": "🇱🇾","unicode": "U+1F1F1 U+1F1FE"},
+ "MA": {"emoji": "🇲🇦","unicode": "U+1F1F2 U+1F1E6"},
+ "MC": {"emoji": "🇲🇨","unicode": "U+1F1F2 U+1F1E8"},
+ "MD": {"emoji": "🇲🇩","unicode": "U+1F1F2 U+1F1E9"},
+ "ME": {"emoji": "🇲🇪","unicode": "U+1F1F2 U+1F1EA"},
+ "MF": {"emoji": "🇲🇫","unicode": "U+1F1F2 U+1F1EB"},
+ "MG": {"emoji": "🇲🇬","unicode": "U+1F1F2 U+1F1EC"},
+ "MH": {"emoji": "🇲🇭","unicode": "U+1F1F2 U+1F1ED"},
+ "MK": {"emoji": "🇲🇰","unicode": "U+1F1F2 U+1F1F0"},
+ "ML": {"emoji": "🇲🇱","unicode": "U+1F1F2 U+1F1F1"},
+ "MM": {"emoji": "🇲🇲","unicode": "U+1F1F2 U+1F1F2"},
+ "MN": {"emoji": "🇲🇳","unicode": "U+1F1F2 U+1F1F3"},
+ "MO": {"emoji": "🇲🇴","unicode": "U+1F1F2 U+1F1F4"},
+ "MP": {"emoji": "🇲🇵","unicode": "U+1F1F2 U+1F1F5"},
+ "MQ": {"emoji": "🇲🇶","unicode": "U+1F1F2 U+1F1F6"},
+ "MR": {"emoji": "🇲🇷","unicode": "U+1F1F2 U+1F1F7"},
+ "MS": {"emoji": "🇲🇸","unicode": "U+1F1F2 U+1F1F8"},
+ "MT": {"emoji": "🇲🇹","unicode": "U+1F1F2 U+1F1F9"},
+ "MU": {"emoji": "🇲🇺","unicode": "U+1F1F2 U+1F1FA"},
+ "MV": {"emoji": "🇲🇻","unicode": "U+1F1F2 U+1F1FB"},
+ "MW": {"emoji": "🇲🇼","unicode": "U+1F1F2 U+1F1FC"},
+ "MX": {"emoji": "🇲🇽","unicode": "U+1F1F2 U+1F1FD"},
+ "MY": {"emoji": "🇲🇾","unicode": "U+1F1F2 U+1F1FE"},
+ "MZ": {"emoji": "🇲🇿","unicode": "U+1F1F2 U+1F1FF"},
+ "NA": {"emoji": "🇳🇦","unicode": "U+1F1F3 U+1F1E6"},
+ "NC": {"emoji": "🇳🇨","unicode": "U+1F1F3 U+1F1E8"},
+ "NE": {"emoji": "🇳🇪","unicode": "U+1F1F3 U+1F1EA"},
+ "NF": {"emoji": "🇳🇫","unicode": "U+1F1F3 U+1F1EB"},
+ "NG": {"emoji": "🇳🇬","unicode": "U+1F1F3 U+1F1EC"},
+ "NI": {"emoji": "🇳🇮","unicode": "U+1F1F3 U+1F1EE"},
+ "NL": {"emoji": "🇳🇱","unicode": "U+1F1F3 U+1F1F1"},
+ "NO": {"emoji": "🇳🇴","unicode": "U+1F1F3 U+1F1F4"},
+ "NP": {"emoji": "🇳🇵","unicode": "U+1F1F3 U+1F1F5"},
+ "NR": {"emoji": "🇳🇷","unicode": "U+1F1F3 U+1F1F7"},
+ "NU": {"emoji": "🇳🇺","unicode": "U+1F1F3 U+1F1FA"},
+ "NZ": {"emoji": "🇳🇿","unicode": "U+1F1F3 U+1F1FF"},
+ "OM": {"emoji": "🇴🇲","unicode": "U+1F1F4 U+1F1F2"},
+ "PA": {"emoji": "🇵🇦","unicode": "U+1F1F5 U+1F1E6"},
+ "PE": {"emoji": "🇵🇪","unicode": "U+1F1F5 U+1F1EA"},
+ "PF": {"emoji": "🇵🇫","unicode": "U+1F1F5 U+1F1EB"},
+ "PG": {"emoji": "🇵🇬","unicode": "U+1F1F5 U+1F1EC"},
+ "PH": {"emoji": "🇵🇭","unicode": "U+1F1F5 U+1F1ED"},
+ "PK": {"emoji": "🇵🇰","unicode": "U+1F1F5 U+1F1F0"},
+ "PL": {"emoji": "🇵🇱","unicode": "U+1F1F5 U+1F1F1"},
+ "PM": {"emoji": "🇵🇲","unicode": "U+1F1F5 U+1F1F2"},
+ "PN": {"emoji": "🇵🇳","unicode": "U+1F1F5 U+1F1F3"},
+ "PR": {"emoji": "🇵🇷","unicode": "U+1F1F5 U+1F1F7"},
+ "PS": {"emoji": "🇵🇸","unicode": "U+1F1F5 U+1F1F8"},
+ "PT": {"emoji": "🇵🇹","unicode": "U+1F1F5 U+1F1F9"},
+ "PW": {"emoji": "🇵🇼","unicode": "U+1F1F5 U+1F1FC"},
+ "PY": {"emoji": "🇵🇾","unicode": "U+1F1F5 U+1F1FE"},
+ "QA": {"emoji": "🇶🇦","unicode": "U+1F1F6 U+1F1E6"},
+ "RE": {"emoji": "🇷🇪","unicode": "U+1F1F7 U+1F1EA"},
+ "RO": {"emoji": "🇷🇴","unicode": "U+1F1F7 U+1F1F4"},
+ "RS": {"emoji": "🇷🇸","unicode": "U+1F1F7 U+1F1F8"},
+ "RU": {"emoji": "🇷🇺","unicode": "U+1F1F7 U+1F1FA"},
+ "RW": {"emoji": "🇷🇼","unicode": "U+1F1F7 U+1F1FC"},
+ "SA": {"emoji": "🇸🇦","unicode": "U+1F1F8 U+1F1E6"},
+ "SB": {"emoji": "🇸🇧","unicode": "U+1F1F8 U+1F1E7"},
+ "SC": {"emoji": "🇸🇨","unicode": "U+1F1F8 U+1F1E8"},
+ "SD": {"emoji": "🇸🇩","unicode": "U+1F1F8 U+1F1E9"},
+ "SE": {"emoji": "🇸🇪","unicode": "U+1F1F8 U+1F1EA"},
+ "SG": {"emoji": "🇸🇬","unicode": "U+1F1F8 U+1F1EC"},
+ "SH": {"emoji": "🇸🇭","unicode": "U+1F1F8 U+1F1ED"},
+ "SI": {"emoji": "🇸🇮","unicode": "U+1F1F8 U+1F1EE"},
+ "SJ": {"emoji": "🇸🇯","unicode": "U+1F1F8 U+1F1EF"},
+ "SK": {"emoji": "🇸🇰","unicode": "U+1F1F8 U+1F1F0"},
+ "SL": {"emoji": "🇸🇱","unicode": "U+1F1F8 U+1F1F1"},
+ "SM": {"emoji": "🇸🇲","unicode": "U+1F1F8 U+1F1F2"},
+ "SN": {"emoji": "🇸🇳","unicode": "U+1F1F8 U+1F1F3"},
+ "SO": {"emoji": "🇸🇴","unicode": "U+1F1F8 U+1F1F4"},
+ "SR": {"emoji": "🇸🇷","unicode": "U+1F1F8 U+1F1F7"},
+ "SS": {"emoji": "🇸🇸","unicode": "U+1F1F8 U+1F1F8"},
+ "ST": {"emoji": "🇸🇹","unicode": "U+1F1F8 U+1F1F9"},
+ "SV": {"emoji": "🇸🇻","unicode": "U+1F1F8 U+1F1FB"},
+ "SX": {"emoji": "🇸🇽","unicode": "U+1F1F8 U+1F1FD"},
+ "SY": {"emoji": "🇸🇾","unicode": "U+1F1F8 U+1F1FE"},
+ "SZ": {"emoji": "🇸🇿","unicode": "U+1F1F8 U+1F1FF"},
+ "TC": {"emoji": "🇹🇨","unicode": "U+1F1F9 U+1F1E8"},
+ "TD": {"emoji": "🇹🇩","unicode": "U+1F1F9 U+1F1E9"},
+ "TF": {"emoji": "🇹🇫","unicode": "U+1F1F9 U+1F1EB"},
+ "TG": {"emoji": "🇹🇬","unicode": "U+1F1F9 U+1F1EC"},
+ "TH": {"emoji": "🇹🇭","unicode": "U+1F1F9 U+1F1ED"},
+ "TJ": {"emoji": "🇹🇯","unicode": "U+1F1F9 U+1F1EF"},
+ "TK": {"emoji": "🇹🇰","unicode": "U+1F1F9 U+1F1F0"},
+ "TL": {"emoji": "🇹🇱","unicode": "U+1F1F9 U+1F1F1"},
+ "TM": {"emoji": "🇹🇲","unicode": "U+1F1F9 U+1F1F2"},
+ "TN": {"emoji": "🇹🇳","unicode": "U+1F1F9 U+1F1F3"},
+ "TO": {"emoji": "🇹🇴","unicode": "U+1F1F9 U+1F1F4"},
+ "TR": {"emoji": "🇹🇷","unicode": "U+1F1F9 U+1F1F7"},
+ "TT": {"emoji": "🇹🇹","unicode": "U+1F1F9 U+1F1F9"},
+ "TV": {"emoji": "🇹🇻","unicode": "U+1F1F9 U+1F1FB"},
+ "TW": {"emoji": "🇹🇼","unicode": "U+1F1F9 U+1F1FC"},
+ "TZ": {"emoji": "🇹🇿","unicode": "U+1F1F9 U+1F1FF"},
+ "UA": {"emoji": "🇺🇦","unicode": "U+1F1FA U+1F1E6"},
+ "UG": {"emoji": "🇺🇬","unicode": "U+1F1FA U+1F1EC"},
+ "UM": {"emoji": "🇺🇲","unicode": "U+1F1FA U+1F1F2"},
+ "US": {"emoji": "🇺🇸","unicode": "U+1F1FA U+1F1F8"},
+ "UY": {"emoji": "🇺🇾","unicode": "U+1F1FA U+1F1FE"},
+ "UZ": {"emoji": "🇺🇿","unicode": "U+1F1FA U+1F1FF"},
+ "VA": {"emoji": "🇻🇦","unicode": "U+1F1FB U+1F1E6"},
+ "VC": {"emoji": "🇻🇨","unicode": "U+1F1FB U+1F1E8"},
+ "VE": {"emoji": "🇻🇪","unicode": "U+1F1FB U+1F1EA"},
+ "VG": {"emoji": "🇻🇬","unicode": "U+1F1FB U+1F1EC"},
+ "VI": {"emoji": "🇻🇮","unicode": "U+1F1FB U+1F1EE"},
+ "VN": {"emoji": "🇻🇳","unicode": "U+1F1FB U+1F1F3"},
+ "VU": {"emoji": "🇻🇺","unicode": "U+1F1FB U+1F1FA"},
+ "WF": {"emoji": "🇼🇫","unicode": "U+1F1FC U+1F1EB"},
+ "WS": {"emoji": "🇼🇸","unicode": "U+1F1FC U+1F1F8"},
+ "XK": {"emoji": "🇽🇰","unicode": "U+1F1FD U+1F1F0"},
+ "YE": {"emoji": "🇾🇪","unicode": "U+1F1FE U+1F1EA"},
+ "YT": {"emoji": "🇾🇹","unicode": "U+1F1FE U+1F1F9"},
+ "ZA": {"emoji": "🇿🇦","unicode": "U+1F1FF U+1F1E6"},
+ "ZM": {"emoji": "🇿🇲","unicode": "U+1F1FF U+1F1F2"},
+ "ZW": {"emoji": "🇿🇼","unicode": "U+1F1FF U+1F1FC"}
+ }
diff --git a/app/Services/Invoice.php b/app/Services/Invoice.php
index 0ec77996..70ad3c58 100644
--- a/app/Services/Invoice.php
+++ b/app/Services/Invoice.php
@@ -61,6 +61,7 @@ class Invoice
}else{
$bcc[] = config('app.checkout_mail');
}
- Mail::to($billing_email)->bcc($bcc)->send(new MailInvoice($shopping_order, $user_invoice));
+
+ Mail::to($billing_email)->bcc($bcc)->locale($shopping_order->getLocale())->send(new MailInvoice($shopping_order, $user_invoice));
}
}
diff --git a/app/Services/MyLog.php b/app/Services/MyLog.php
new file mode 100644
index 00000000..04c92327
--- /dev/null
+++ b/app/Services/MyLog.php
@@ -0,0 +1,34 @@
+notice($message.' : '.json_encode($data));
+ break;
+ case 'warning':
+ \Log::channel($channel)->warning($message.' : '.json_encode($data));
+ break;
+ case 'info':
+ \Log::channel($channel)->info($message.' : '.json_encode($data));
+ break;
+ default:
+ \Log::channel($channel)->error($message.' : '.json_encode($data));
+ break;
+ }
+ Mail::to(config('app.exception_mail'))->send(new MailLog($channel, $context, $message, $data));
+ }
+}
+
+
+
diff --git a/app/Services/Payment.php b/app/Services/Payment.php
index ad0952f1..c0d74ad2 100644
--- a/app/Services/Payment.php
+++ b/app/Services/Payment.php
@@ -5,6 +5,7 @@ namespace App\Services;
use App\User;
use App\Models\UserLevel;
use App\Mail\MailCheckout;
+use App\Services\UserUtil;
use App\Models\ProductBuying;
use App\Models\ShoppingOrder;
use App\Models\UserCreditItem;
@@ -18,52 +19,52 @@ class Payment
{
public static $txaction_text = [
- 'paid' => "bezahlt",
- 'appointed' => "offen",
- 'failed' => "abbruch",
- 'extern' => "offen", //offen
- 'extern_paid' => "bezahlt",
- 'invoice_open' => "offen",
- 'invoice_paid' => "bezahlt",
- 'invoice_non' => "keine Zahlung",
- 'NULL' => 'keine Zahlung',
+ 'paid' => 'paid',
+ 'appointed' => 'open',
+ 'failed' => 'failed',
+ 'extern' => 'open', //offen
+ 'extern_paid' => 'paid',
+ 'invoice_open' => 'open',
+ 'invoice_paid' => 'paid',
+ 'invoice_non' => 'no_payment',
+ 'NULL' => 'no_payment',
];
public static $txaction_filter_text = [
- 'paid' => "Zahlung bezahlt",
- 'appointed' => "Zahlung offen",
- 'failed' => "Zahlung abbruch",
- 'extern' => "Extern offen", //offen
- 'extern_paid' => "Extern bezahlt",
- 'invoice_open' => "Rechnung offen",
- 'invoice_paid' => "Rechnung bezahlt",
- 'invoice_non' => "Rechnung keine Zahlung",
- 'NULL' => 'keine Zahlung',
+ 'paid' => 'paymend_paid',
+ 'appointed' => 'paymend_open',
+ 'failed' => 'paymend_failed',
+ 'extern' => 'extern_open', //offen
+ 'extern_paid' => 'extern_paid',
+ 'invoice_open' => 'invoice_open',
+ 'invoice_paid' => 'invoice_paid',
+ 'invoice_non' => 'invoice_no_payment',
+ 'NULL' => 'no_payment',
];
public static $txaction_invoice = [
- 'invoice_open' => "Rechnung offen",
- 'invoice_paid' => "Rechnung bezahlt",
- 'invoice_non' => 'keine Zahlung',
+ 'invoice_open' => 'invoice_open',
+ 'invoice_paid' => 'invoice_paid',
+ 'invoice_non' => 'no_payment',
];
public static $txaction_color = [
- 'paid' => "success",
- 'appointed' => "warning",
- 'failed' => "danger",
- 'extern' => "warning",
- 'extern_paid' => "success",
- 'invoice_open' => "warning",
- 'invoice_paid' => "success",
- 'invoice_non' => "failed",
+ 'paid' => 'success',
+ 'appointed' => 'warning',
+ 'failed' => 'danger',
+ 'extern' => 'warning',
+ 'extern_paid' => 'success',
+ 'invoice_open' => 'warning',
+ 'invoice_paid' => 'success',
+ 'invoice_non' => 'failed',
];
public static function getFormattedTxaction($txaction){
if($txaction && isset(self::$txaction_text[$txaction])){
- return self::$txaction_text[$txaction];
+ return __('payment.'.self::$txaction_text[$txaction]);
}
- return self::$txaction_text['NULL'];
+ return __('payment.'.self::$txaction_text['NULL']);
}
public static function getFormattedTxactionColor($txaction){
@@ -73,6 +74,22 @@ class Payment
return "warning";
}
+ public static function getTransTxactionFilterText(){
+ $ret = [];
+ foreach(self::$txaction_filter_text as $key=>$val){
+ $ret[$key] = trans('payment.'.$val);
+ }
+ return $ret;
+ }
+
+ public static function getTransTxactionInvoice(){
+ $ret = [];
+ foreach(self::$txaction_invoice as $key=>$val){
+ $ret[$key] = trans('payment.'.$val);
+ }
+ return $ret;
+ }
+
public static function getShoppingOrderBadge(ShoppingOrder $shopping_order){
if($shopping_order->mode === 'test'){
return ''.strtoupper($shopping_order->mode).' - '.self::getFormattedTxaction($shopping_order->txaction).'';
@@ -95,6 +112,8 @@ class Payment
'user_id' => $user->id,
'credit' => $credit,
'message' => $message,
+ 'from_month' => date('n'),
+ 'from_year' => date('Y'),
'status' => $status,
]);
}
@@ -171,6 +190,14 @@ class Payment
$user->payment_order_id = $shopping_order_item->product->id; //34
$user->payment_account = $date;
$user->wizard = 100;
+ //only date is > now and acount is deactive.
+ if($date > \Carbon::now()){
+ if($user->active === 0){
+ $user->active = true;
+ UserUtil::reactiveUserResetChilds($user->id, 'on payment_for_account Payment');
+ }
+ }
+
$shopping_order->setUserHistoryValue(['status' => 9]);
}
if($shopping_order_item->product->getActionName($do) === 'payment_for_shop'){
@@ -210,7 +237,6 @@ class Payment
}
//make Invoice and
-
$invoice_repo = new InvoiceRepository($shopping_order);
if(!$shopping_order->isInvoice()){
$invoice_repo->createAndSalesVolume();
@@ -237,6 +263,6 @@ class Payment
if(!$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']));
+ Mail::to($billing_email)->bcc($bcc)->locale($shopping_order->getLocale())->send(new MailCheckout($data['txaction'], $shopping_order, $shopping_payment, $data['send_link'], $data['mode']));
}
}
diff --git a/app/Services/PaymentHelper.php b/app/Services/PaymentHelper.php
index abdfc282..f214795b 100644
--- a/app/Services/PaymentHelper.php
+++ b/app/Services/PaymentHelper.php
@@ -83,6 +83,7 @@ class PaymentHelper
$shopping_user = new ShoppingUser();
$shopping_user->auth_user_id = $user->id;
$shopping_user->mode = 'prev';
+ $shopping_user->language = $user->getLocale();
$shopping_user->billing_salutation = $user->account->salutation;
$shopping_user->billing_company = $user->account->company;
$shopping_user->billing_firstname = $user->account->first_name;
@@ -121,6 +122,7 @@ class PaymentHelper
'shopping_user_id' => $shopping_user->id,
'auth_user_id' => $shopping_user->auth_user_id,
'country_id' => Yard::instance('shopping')->getShippingCountryId(),
+ 'language' => \App::getLocale(),
'user_shop_id' => 1,
'payment_for' => $shopping_user->getOrderPaymentFor(),
'total' => Yard::instance('shopping')->total(2, '.', ''),
diff --git a/app/Services/Payone.php b/app/Services/Payone.php
index d72d608e..5bc575d4 100644
--- a/app/Services/Payone.php
+++ b/app/Services/Payone.php
@@ -29,6 +29,7 @@ namespace App\Services;
//require 'vendor/autoload.php';
use Exception;
+
use GuzzleHttp\Client;
use Psr\Http\Message\ResponseInterface;
@@ -41,7 +42,7 @@ class Payone {
* The URL of the Payone API
*/
const PAYONE_SERVER_API_URL = 'https://api.pay1.de/post-gateway/';
- const PAYONE_CLIENT_API_URL = 'https://secure.pay1.de/client-api//';
+ const PAYONE_CLIENT_API_URL = 'https://secure.pay1.de/client-api/';
/**
* performing the HTTP POST request to the PAYONE platform
@@ -57,35 +58,84 @@ class Payone {
if ($responsetype === "json") {
// appends the accept: application/json header to the request
// This is used to retrieve structured JSON in the response
- $client = new Client(['headers' => ['accept' => 'application/json']]);
+ // $client = new Client(['headers' => ['accept' => 'application/json', 'content-type' => 'text/plain;charset=UTF-8']]);
+ $client = new Client(['headers' => ['accept' => 'application/json']]);
+
}
else {
// if $responsetype is set to anything else than "json", use the standard request
- $client = new Client();
+ // $client = new Client(['headers' => ['content-type' => 'text/plain;charset=UTF-8']]);
+ $client = new Client();
}
// echo "Requesting...";
$begin = microtime(true);
+ try {
+ $response = $client->request('POST', self::PAYONE_SERVER_API_URL, ['form_params' => $request]);
+ }
+ catch (\GuzzleHttp\Exception\ClientException $e) {
+ $error = $e->getResponse();
+ $responseBodyAsString = $error->getBody()->getContents();
+ MyLog::writeLog(
+ 'payone',
+ 'error',
+ 'Error:1002 Der Zahlungsanbieter ist nicht erreichbar, die Zahlung konnte nicht durchgeführt werden. App\Services\Payone::sendRequest Something went wrong during the HTTP request.',
+ ['error' => $error, 'responseBodyAsString' => $responseBodyAsString, 'request' => $request]
+ );
+ abort(403, 'Der Zahlungsanbieter ist nicht erreichbar, die Zahlung konnte nicht durchgeführt werden. Bitte versuchen Sie es später erneut. Fehlercode: 1002');
- if ($response = $client->request('POST', self::PAYONE_SERVER_API_URL, ['form_params' => $request])) {
-
- if (implode($response->getHeader('Content-Type')) == 'text/plain; charset=UTF-8'){
+ }
+ if (isset($response)) {
+ if (implode($response->getHeader('Content-Type')) == 'text/plain;charset=UTF-8'){
// if the content type is text/plain, parse response into array
$return = self::parseResponse($response);
+ // \Log::channel('payone')->error('App\Services\Payone::sendRequest content type is text/plain: '.$response);
+
} else {
// if the content type is anything else, just return the response body
- $return = $response->getBody();
+ $return = json_decode($response->getBody(),true);
+ MyLog::writeLog(
+ 'payone',
+ 'error',
+ 'Error: App\Services\Payone::sendRequest content type is anything else',
+ ['error' => $return, 'response' => $response, 'request' => $request]
+ );
}
} else {
+ MyLog::writeLog(
+ 'payone',
+ 'error',
+ 'Error: App\Services\Payone::sendRequest Something went wrong during the HTTP request',
+ ['request' => $request]
+ );
throw new Exception('Something went wrong during the HTTP request.');
}
$end = microtime(true);
$duration = $end - $begin;
+ if(!is_array($return)){
+ MyLog::writeLog(
+ 'payone',
+ 'error',
+ 'Error: 1003 App\Http\Controllers\Pay\PayoneController::ResponseData response is non array: return:',
+ ['return'=>$return, 'response' => $response, 'request' => $request]
+ );
+ abort(403, 'Der Zahlungsanbieter ist nicht erreichbar, die Zahlung konnte nicht durchgeführt werden. Bitte versuchen Sie es später erneut. Fehlercode: 1003');
+ }
+
+ if(!isset($return['status'])){
+ MyLog::writeLog(
+ 'payone',
+ 'error',
+ 'Error: 1004 App\Http\Controllers\Pay\PayoneController::ResponseData response has non status',
+ ['return'=>$return, 'response' => $response, 'request' => $request]
+ );
+ abort(403, 'Der Zahlungsanbieter ist nicht erreichbar, die Zahlung konnte nicht durchgeführt werden. Bitte versuchen Sie es später erneut. Fehlercode: 1004');
+ }
/* echo "done.\n";
- echo "Request took " . $duration . " seconds.\n";
- echo "
";
+ echo "Request took " . $duration . " seconds.\n";
+ echo "
";
*/
return $return;
}
diff --git a/app/Services/Shop.php b/app/Services/Shop.php
index a5444fe1..dd5668ac 100644
--- a/app/Services/Shop.php
+++ b/app/Services/Shop.php
@@ -3,9 +3,13 @@ namespace App\Services;
use Yard;
+use App\User;
use App\Models\Country;
+use App\Models\Setting;
use App\Models\ShoppingUser;
+use App\Services\dbip\MyDBIP;
use App\Models\ShippingCountry;
+use App\Services\IPinfo\IPinfo;
class Shop
{
@@ -117,11 +121,9 @@ class Shop
Yard::instance('shopping')->setShippingCountryWithPrice($ShippingCountry->id);
Yard::instance('shopping')->setUserPriceInfos(Shop::getShopYardInfo());
-
-
-
}
+
public static function getShopYardInfo(){
return [
'user_tax_free' => self::$user_tax_free,
@@ -131,5 +133,328 @@ class Shop
'shipping_country_id' => self::$shipping_country->id,
];
}
-
+
+ public static function getYardShoppingItems(){
+ $rows = Yard::instance('shopping')->getContentByOrder();
+ $ret = [];
+ $ret['items'] = [];
+ $is_currency = Yard::instance('shopping')->isPriceCurrency();
+ $tax_free = Yard::instance('shopping')->getUserTaxFree();
+
+ foreach($rows as $row){
+ $product = \App\Models\Product::find($row->id);
+ $item = new \stdClass();
+ $item->image = $row->options->has('image') ? $row->options->image : null;
+ $item->price_net = (float) Yard::instance('shopping')->rowPriceNet($row, 3, '.', '');
+ $item->price_net_total = (float) Yard::instance('shopping')->rowSubtotalNet($row, 2, '.', '');
+ $item->price_currency = $is_currency ? "~".Yard::instance('shopping')->getCurrencyByKey('rowPriceNetCurrency', $row, 3)." ".Yard::instance('shopping')->getPriceCurrencyUnit() : null;
+ $item->price_currency_total = $is_currency ? "~".Yard::instance('shopping')->getCurrencyByKey('rowSubtotalCurrency', $row, 3)." ".Yard::instance('shopping')->getPriceCurrencyUnit() : null;
+ $item->price = $row->price;
+ $item->price_total = ($row->qty * $row->price);
+ $item->qty = $row->qty;
+ $item->name = $product->name;
+ $item->contents = $product->contents;
+ $item->numbers = $product->numbers;
+ $ret['items'][] = $item;
+ }
+
+ $ret['tax_free'] = $tax_free;
+ $ret['total']['subtotal'] = Yard::instance('shopping')->subtotal();
+ $ret['total']['subtotal_currency'] = $is_currency ? "~".Yard::instance('shopping')->getCurrencyByKey('subtotal')." ".Yard::instance('shopping')->getPriceCurrencyUnit() : null;
+ $ret['total']['shippingCountryName'] = Yard::instance('shopping')->getShippingCountryName();
+ $ret['total']['shippingNet'] = Yard::instance('shopping')->shippingNet();
+ $ret['total']['shippingNet currency'] = $is_currency ? "~".Yard::instance('shopping')->getCurrencyByKey('shippingNet')." ".Yard::instance('shopping')->getPriceCurrencyUnit() : null;
+ $ret['total']['subtotalWithShipping'] = Yard::instance('shopping')->subtotalWithShipping();
+ $ret['total']['subtotalWithShipping_currency'] = $is_currency ? "~".Yard::instance('shopping')->getCurrencyByKey('subtotalWithShipping')." ".Yard::instance('shopping')->getPriceCurrencyUnit() : null;
+ $ret['total']['taxWithShipping'] = Yard::instance('shopping')->taxWithShipping();
+ $ret['total']['taxWithShipping_currency'] = $is_currency ? "~".Yard::instance('shopping')->getCurrencyByKey('taxWithShipping')." ".Yard::instance('shopping')->getPriceCurrencyUnit() : null;
+ $ret['total']['totalWithShipping'] = Yard::instance('shopping')->totalWithShipping();
+ $ret['total']['totalWithShipping_currency'] = $is_currency ? "~".Yard::instance('shopping')->getCurrencyByKey('totalWithShipping')." ".Yard::instance('shopping')->getPriceCurrencyUnit() : null;
+
+
+
+ return $ret;
+ }
+ public static function checkShoppingUser($id, $user){
+ if($id === null){
+ abort(403, 'Error: Keine User ID');
+ }
+ $shopping_user = ShoppingUser::findOrFail($id);
+ if($shopping_user->member_id !== $user->id){
+ abort(403, 'Error: Falsche User ID');
+ }
+ $shopping_user = ShoppingUser::findOrFail($id);
+ if($shopping_user->is_like){
+ abort(403, 'Error: Kunde in Prüfung');
+ }
+ return $shopping_user;
+ }
+
+ public static function checkShoppingCountry($for, $id=null){
+ $country_id = null;
+ if($for === 'me' || $for === 'abo-me'){
+ $user = User::find(\Auth::user()->id);
+ if($user->account->same_as_billing){
+ $country_id = $user->account->country_id;
+ }else{
+ $country_id = $user->account->shipping_country_id;
+ }
+ }
+ if(strpos($for, 'ot') !== false && $id){
+ $shopping_user = ShoppingUser::findOrFail($id);
+ if($shopping_user->same_as_billing){
+ $country_id = $shopping_user->billing_country->id;
+ }else{
+ $country_id = $shopping_user->shipping_country->id;
+ }
+ }
+ if($country_id){
+ if($shipping_country = ShippingCountry::whereCountryId($country_id)->first()){
+ if($shipping_country->shipping && $shipping_country->shipping->active){
+ return $shipping_country->id;
+ }
+
+ }
+ }
+ return false;
+ }
+
+ public static function getDeliveryCountry($for, $id=null){
+ $country_id = null;
+ if($for === 'me' || $for === 'abo-me'){
+ $user = User::find(\Auth::user()->id);
+ if($user->account->same_as_billing){
+ return $user->account->country ? $user->account->country->getLocated() : '';
+ }else{
+ return $user->account->shipping_country ? $user->account->shipping_country->getLocated() : '';
+ }
+ }
+ if(strpos($for, 'ot') !== false && $id){
+ $shopping_user = ShoppingUser::findOrFail($id);
+ if($shopping_user->same_as_billing){
+ return $shopping_user->billing_country ? $shopping_user->billing_country->getLocated() : '';
+ }else{
+ return $shopping_user->shipping_country ? $shopping_user->shipping_country->getLocated() : '';
+ }
+ }
+ return '';
+ }
+
+
+ public static function getShippingPriceByShippingCountryId($shipping_country_id, $shipping_weight){
+ $shippingCountry = ShippingCountry::find($shipping_country_id);
+ if(!$shippingCountry){
+ abort(403, 'Fehler: Versandland nicht gefunden');
+ }
+ if(!isset($shippingCountry->shipping) && count($shippingCountry->shipping->shipping_prices) === 0){
+ abort(403, 'Fehler: Kein Preise für das Versandland angelegt');
+ }
+ $shipping_price = $shippingCountry->shipping->shipping_prices->first();
+ if(!$shipping_price){
+ abort(403, 'Fehler: Preis vom Versandland nicht gefunden');
+ }
+
+ /*if(!$shipping_weight){
+ abort(403, 'Fehler: Kein Versandgewicht');
+ }*/
+
+ if($shipping_weight == 0){
+ $shipping_price->price = 0;
+ $shipping_price->price_comp = 0;
+ return $shipping_price;
+ }
+
+ if($shipping_weight > 0){
+ /*
+ if($this->shipping_free && $this->total(2, '.', '') >= $this->shipping_free){
+ if($this->weightByFreeShipping() == 0){
+ $shipping_price->price = 0;
+ $shipping_price->price_comp = 0;
+ }else{
+ $shipping_price = $this->shippingPriceByWeight($shipping->shipping_prices, $this->weightByFreeShipping());
+ }
+
+ }else{
+ */
+
+ return self::shippingPriceByWeight($shippingCountry->shipping->shipping_prices, $shipping_weight);
+ }
+ /*if($this->weight() == 0){
+
+ }else{
+
+ $shipping_price = $this->shippingPriceByWeight($shipping->shipping_prices, $this->weight());
+ //first by price
+ //$shipping_price = $this->shippingPriceByTotal($shipping->shipping_prices, $this->total(2, '.', ''));
+ //sec by weight
+ //if(!$shipping_price){
+ //}
+ }
+ //default
+
+ }*/
+
+ }
+
+ public static function shippingPriceByWeight($shipping_prices, $shipping_weight){
+ foreach ($shipping_prices as $price){
+ if($price->weight_from > 0 && $price->weight_to > 0){
+ if($shipping_weight >= $price->weight_from && $shipping_weight <= $price->weight_to){
+ return $price;
+ }
+ }
+ }
+ abort(403, 'Fehler: Preis nach Gewicht im Versandland nicht gefunden');
+ }
+
+ public static function isCompProducts($for){
+ /*
+ $for = me, ot-member, ot-customer, abo-ot-member, abo-ot-customer, abo-me
+ */
+ if($for === 'me'){
+ return (bool) Setting::getContentBySlug('is_comp_me_order');
+ }
+ if($for === 'abo-me'){
+ return (bool) Setting::getContentBySlug('is_comp_me_abo');
+ }
+ return false;
+ }
+
+ public static function getIPDatabaseInfo(){
+
+ //first check the DBs for the IP
+
+
+ /* testing
+
+ foreach(self::testIps() as $ip_address){
+ $country = MyDBIP::lookup($ip_address);
+ dump($country);
+ if($country !== false){
+ continue;
+ //return strtolower($country);
+ }
+ dump("not found ".$ip_address);
+ //not found search in IPinfo
+ $access_token = 'e1054aa11daf1e';
+ $client = new IPinfo($access_token);
+
+ $details = $client->getDetails($ip_address);
+ if(isset($details->error) && $details->error !== null){
+ //return 'error';
+ dump("not foun on IPinfo ".$details->error);
+ }
+ if(isset($details->country) && $details->country !== null){
+ MyDBIP::insert($ip_address, $details->country);
+ dump("found on IPinfo ".$details->country);
+ //return strtolower($details->country);
+ }
+ //return 'error';
+ }
+
+ dd("done");
+ */
+
+ /* live */
+
+ $ip_address = \Request::ip();
+ // $ip_address = '86.189.47.78'; //testing
+ $country = MyDBIP::lookup($ip_address);
+ if($country !== false){
+ return strtolower($country);
+ }
+ //not found search in IPinfo
+ $access_token = 'e1054aa11daf1e';
+ $client = new IPinfo($access_token);
+
+ $details = $client->getDetails($ip_address);
+ if(isset($details->error) && $details->error !== null){
+ return 'error';
+ }
+ if(isset($details->country) && $details->country !== null){
+ MyDBIP::insert($ip_address, $details->country);
+ return strtolower($details->country);
+ }
+ return 'error';
+ }
+
+
+ private static function testIps(){
+ return [
+ '58.217.40.197'
+ ,'207.117.144.54'
+ ,'65.169.228.128'
+ ,'6.84.3.236'
+ ,'214.56.36.93'
+ ,'9.43.145.245'
+ ,'231.199.26.76'
+ ,'86.189.47.78'
+ ,'3.122.58.75'
+ ,'251.133.143.149'
+ ,'6.142.181.83'
+ ,'2.55.191.86'
+ ,'90.189.58.233'
+ ,'57.3.139.111'
+ ,'41.130.99.194'
+ ,'1.59.123.14'
+ ,'9.119.131.109'
+ ,'54.240.231.9'
+ ,'117.19.131.144'
+ ,'221.217.39.211'
+ ,'7.43.125.76'
+ ,'224.86.233.79'
+ ,'32.151.38.98'
+ ,'4.134.40.92'
+ ,'4.70.188.58'
+ ,'24.7.152.228'
+ ,'58.122.179.1'
+ ,'5.123.9.44'
+ ,'3.175.206.5'
+ ,'8.142.119.47'
+ ,'40.248.58.203'
+ ,'7.84.254.187'
+ ,'215.215.239.71'
+ ,'124.40.66.196'
+ ,'215.87.143.102'
+ ,'143.39.97.13'
+ ,'202.56.79.198'
+ ,'143.60.125.142'
+ ,'73.233.153.126'
+ ,'121.144.28.245'
+ ,'53.232.193.122'
+ ,'104.222.102.209'
+ ,'216.55.215.13'
+ ,'84.106.145.239'
+ ,'200.131.52.20'
+ ,'132.252.158.0'
+ ,'220.11.129.27'
+ ,'8.153.0.186'
+ ,'119.206.117.107'
+ ,'222.93.42.133'
+ ,'105.104.224.98'
+ ,'252.156.181.78'
+ ,'7.139.235.187'
+ ,'111.140.127.91'
+ ,'1.186.17.84'
+ ,'85.59.39.221'
+ ,'231.152.252.43'
+ ,'125.214.216.123'
+ ,'69.31.65.238'
+ ,'126.12.105.55'
+ ,'211.39.4.118'
+ ,'73.102.88.79'
+ ,'210.229.38.137'
+ ,'5.3.230.214'
+ ,'208.92.91.242'
+ ,'4.105.177.199'
+ ,'38.10.48.92'
+ ,'133.33.44.13'
+ ,'202.189.24.255'
+ ,'5.101.244.234'
+ ,'2.52.110.194'
+ ,'1.130.73.146'
+ ,'84.237.232.120'
+ ,'25.163.83.194'
+ ];
+ }
}
\ No newline at end of file
diff --git a/app/Services/ShopApiOrderCart.php b/app/Services/ShopApiOrderCart.php
index bce9db5a..3fd4ede2 100644
--- a/app/Services/ShopApiOrderCart.php
+++ b/app/Services/ShopApiOrderCart.php
@@ -79,8 +79,8 @@ class ShopApiOrderCart
//only for tax split / tax and price on calculate function
- $this->shoppingCollectOrder->addTaxToSplit($tax_rate, $user_tax_qty);
- $this->shoppingCollectOrder->addNetToSplit($tax_rate, $user_price_net_qty);
+ $this->shoppingCollectOrder->addTaxToSplit((int)$tax_rate, (float)$user_tax_qty);
+ $this->shoppingCollectOrder->addNetToSplit((int)$tax_rate, (float)$user_price_net_qty);
$this->shoppingCollectOrder->tax_total += $user_tax_qty;
$this->shoppingCollectOrder->price_total_net += $user_price_net_qty;
$this->shoppingCollectOrder->points += ($item->points * $item->qty);
diff --git a/app/Services/SyS/CleanHTMLProductDescription.php b/app/Services/SyS/CleanHTMLProductDescription.php
new file mode 100644
index 00000000..2e50cc98
--- /dev/null
+++ b/app/Services/SyS/CleanHTMLProductDescription.php
@@ -0,0 +1,102 @@
+get();
+ dump(count($TransProducts));
+ $c = 0;
+ foreach($TransProducts as $item){
+ if($item->value){
+ $item->value = self::cleanHTML($item->value);
+ $item->save();
+
+ //dump($item->value);
+ $c++;
+ }
+ }
+ dump("counter TransProduct");
+ dump($c);
+
+ $Products = Product::limit(2000)->get();
+ dump(count($Products));
+ $c = 0;
+ foreach($Products as $item){
+ if($item){
+ $item->copy = self::cleanHTML($item->copy);
+ $item->description = self::cleanHTML($item->description);
+ $item->usage = self::cleanHTML($item->usage);
+ $item->ingredients = self::cleanHTML($item->ingredients);
+
+ $item->save();
+
+ //dump($item->value);
+ $c++;
+ }
+ }
+
+ dump("counter");
+ dd($c);
+ }
+
+ public static function cleanHTML($html)
+ {
+ // $html = preg_replace("/(?)div/", "$1p", $html);
+
+ $html = str_replace('
', '', $html);
+ $html = str_replace('', '', $html);
+ $html = str_replace('
', '', $html);
+ $html = str_replace('
', '', $html);
+
+ $html = str_replace('
', '', $html);
+ $html = str_replace('text -primary', 'text-primary', $html);
+ $html = str_replace('fa -check', 'fa-check', $html);
+ $html = str_replace('text- primary', 'text-primary', $html);
+ $html = str_replace('fa- check', 'fa-check', $html);
+ $html = str_replace('', '', $html);
+
+ $html = str_replace('', '', $html);
+ $html = preg_replace('/(<[^>]+) style=".*?"/i', '$1', $html);
+
+ $html = str_replace('', '', $html);
+ $html = str_replace(' ', '', $html);
+ $html = str_replace('< i', '', '', $html);
+
+ $html = str_replace(' i>', ' ', $html);
+ $html = str_replace(' li>', '', $html);
+
+ $html = str_replace(' b>', '', $html);
+ $html = str_replace('< /b>', '', $html);
+
+ $html = str_replace(' p>', '', $html);
+ $html = str_replace('< /p>', '', $html);
+
+ $html = str_replace('< /i>', '', $html);
+ $html = str_replace('< /li>', '', $html);
+ $html = str_replace('', '', $html);
+ $html = str_replace('', '', $html);
+ $html = str_replace('>>', '>', $html);
+ return $html;
+
+ }
+
+ public static function store()
+ {
+ $data = Request::all();
+ \Session()->flash('alert-save', true);
+ return back();
+ }
+
+
+}
diff --git a/app/Services/SyS/CronJobs.php b/app/Services/SyS/CronJobs.php
index f9509c15..cef26f9a 100644
--- a/app/Services/SyS/CronJobs.php
+++ b/app/Services/SyS/CronJobs.php
@@ -3,7 +3,7 @@ namespace App\Services\SyS;
use Request;
-class Cronjobs
+class CronJobs
{
public static function show()
diff --git a/app/Services/SyS/DomainSSL.php b/app/Services/SyS/DomainSSL.php
index d93540b3..d45508b5 100644
--- a/app/Services/SyS/DomainSSL.php
+++ b/app/Services/SyS/DomainSSL.php
@@ -18,19 +18,29 @@ class DomainSSL
//$domain = 'mivita.care';
// $ssl = KasSLLController::getApiSSLParameter();
$SubDomains = [];
+
$get_subdomains = $kas->action('get_subdomains');
foreach ($get_subdomains as $subdomain){
+ if(isset($subdomain['subdomain_name'])){
+ if(strpos($subdomain['subdomain_name'], 'www.') !== false){
+ continue;
+ }
+ if(strpos($subdomain['subdomain_name'], 'api.') !== false){
+ continue;
+ }
+ if(strpos($subdomain['subdomain_name'], 'checkout.') !== false){
+ continue;
+ }
+ $SubDomains[$subdomain['subdomain_name']] =
+ [
+ 'ssl_certificate_sni' => $subdomain['ssl_certificate_sni'],
+ 'php_version' => $subdomain['php_version'],
+ ];
- if(strpos($subdomain['subdomain_name'], 'www.') !== false){
- continue;
+ }else{
+ @dump($subdomain);
}
- if(strpos($subdomain['subdomain_name'], 'api.') !== false){
- continue;
- }
- if(strpos($subdomain['subdomain_name'], 'checkout.') !== false){
- continue;
- }
- $SubDomains[$subdomain['subdomain_name']] = $subdomain['ssl_certificate_sni'];
+
/* if($subdomain['ssl_certificate_sni'] !== "Y"){
$pra = array(
@@ -50,19 +60,32 @@ class DomainSSL
//$text .= "\n";
}
+
+ $dobbleDomains = [];
+
foreach($user_shops as $user_shop){
$user_shop->hasSubdomain = false;
$user_shop->hasSSL = false;
+ $user_shop->PHPversion = "";
if(array_key_exists($user_shop->slug.'.mivita.care', $SubDomains)){
$user_shop->hasSubdomain = true;
- $user_shop->hasSSL = $SubDomains[$user_shop->slug.'.mivita.care'] === 'Y' ? true : false;
+ $user_shop->hasSSL = $SubDomains[$user_shop->slug.'.mivita.care']['ssl_certificate_sni'] === 'Y' ? true : false;
+ $user_shop->PHPversion = $SubDomains[$user_shop->slug.'.mivita.care']['php_version'];
unset($SubDomains[$user_shop->slug.'.mivita.care']);
}
+ $dobbleDomains[$user_shop->user_id][$user_shop->id] = $user_shop->slug.'.mivita.care';
+ }
+ foreach($dobbleDomains as $key => $dobbleDomain){
+ if(count($dobbleDomain) === 1){
+ unset($dobbleDomains[$key]);
+ }
}
$data = [
'values' => $user_shops,
'text' => $text,
'SubDomains' => $SubDomains,
+ 'dobbleDomains' => $dobbleDomains,
+
];
return view('sys.tools.domain-ssl', $data);
@@ -98,16 +121,22 @@ class DomainSSL
}
if(isset($data['update_ssl'])){
+
+ //prüfen ob subdomain existiert
$user_shop = UserShop::findOrFail($data['update_ssl']);
$subdomain_name = $user_shop->slug.'.mivita.care';
+
$kas = new KasController();
- $ssl = KasSLLController::getApiSSLParameter();
- $pra = array(
- 'hostname' => $subdomain_name
- );
- $pra = array_merge($pra, $ssl);
- $value = $kas->action('update_ssl', $pra);
- \Session()->flash('alert-success', 'update SSL: '.$value.'');
+ $subdomain = $kas->action('get_subdomains', ['subdomain_name' => $subdomain_name]);
+ if(!isset($subdomain[0]['subdomain_name'])){ //not found
+ self::makeNewSubDomain($user_shop->slug);
+ \Session()->flash('alert-danger', 'subdomain: '.$subdomain_name.' nicht gefunden');
+ return back();
+ }else{
+ self::updateSubDomain($subdomain_name);
+ }
+
+
}
@@ -115,4 +144,55 @@ class DomainSSL
return back();
}
+ private static function updateSubDomain($subdomain_name){
+
+ $kas = new KasController();
+ $ssl = KasSLLController::getApiSSLParameter();
+ $pra = array(
+ 'hostname' => $subdomain_name
+ );
+ $pra = array_merge($pra, $ssl);
+ $value = $kas->action('update_ssl', $pra);
+ \Session()->flash('alert-success', 'update SSL: '.$value.'');
+ return $value;
+ }
+
+ private static function makeNewSubDomain($slug){
+
+ $kas = new KasController();
+ $domain = 'mivita.care';
+
+ //check if exisist
+ $subdomains = $kas->action('get_subdomains');
+ foreach ($subdomains as $subdomain){
+ if(!isset($subdomain['subdomain_name'])){
+ continue;
+ }
+ $sub = str_replace(".".$domain, '', $subdomain['subdomain_name']);
+ if($sub == $slug){
+ \Session()->flash('alert-danger', __('shop.error_subdomain_exists'));
+ return;
+ }
+ }
+
+ //add
+ $full_subdomain_name = $slug.".".$domain;
+ $pra = array(
+ 'subdomain_name' => $slug,
+ 'domain_name' => $domain,
+ 'subdomain_path' => '/mein.mivita.care/public/',
+ 'php_version' => config('app.php_version'),
+ //'ssl_proxy' => 'Y',
+ //'redirect_status' => 0
+ );
+ $add_subdomain = $kas->action('add_subdomain', $pra);
+ if($add_subdomain == $full_subdomain_name){
+ \Session()->flash('alert-success', 'Add Subdomain: '.$add_subdomain.'');
+ return $add_subdomain;
+ }
+ \Session()->flash('alert-danger', 'Fehler: '.$add_subdomain.'');
+ return $add_subdomain;
+
+
+ }
}
diff --git a/app/Services/SyS/ImportDbipCountry.php b/app/Services/SyS/ImportDbipCountry.php
new file mode 100644
index 00000000..11121da2
--- /dev/null
+++ b/app/Services/SyS/ImportDbipCountry.php
@@ -0,0 +1,84 @@
+orderBy('ip_start', 'desc')->first());
+ if(!Storage::disk('import')->has($filename)){
+ die("File not found in import folder: ".$filename);
+ }*/
+
+ $path = Storage::disk('import')->path($filename);
+ $fileContents = file($path);
+ $c = 0;
+ foreach ($fileContents as $line) {
+ $row = str_getcsv($line);
+ $row[] = self::addrType($row[0]);
+
+
+ //
+ //base64_encode(file_get_contents($path))
+ // dump($row);
+ \DB::table('dbip_lookup')->insert([
+ 'ip_start' => inet_pton($row[0]),
+ 'ip_end' => inet_pton($row[1]),
+ 'country' => $row[2],
+ 'addr_type' => $row[3]
+ ]);
+
+
+ //dump(inet_pton($row[0]));
+ /* DbipLookup::create([
+ 'ip_start' => ,
+ 'ip_end' => inet_pton($row[1]),
+ 'country' => $row[2],
+ 'addr_type' => $row[3]
+ ]);*/
+
+ }
+
+ return true;
+
+ }
+ private static function addrType($addr) {
+ if (ip2long($addr) !== false) {
+ return "ipv4";
+ } else if (preg_match('/^[0-9a-fA-F:]+$/', $addr) && @inet_pton($addr)) {
+ return "ipv6";
+ }
+ die("unknown address type for {$addr}");
+ }
+
+ public static function store()
+ {
+ $data = Request::all();
+ \Session()->flash('alert-save', true);
+ return back();
+ }
+
+
+}
diff --git a/app/Services/SyS/RepairSalesVolumeInvoice.php b/app/Services/SyS/RepairSalesVolumeInvoice.php
new file mode 100644
index 00000000..3edf7288
--- /dev/null
+++ b/app/Services/SyS/RepairSalesVolumeInvoice.php
@@ -0,0 +1,45 @@
+where('user_invoice_id', null)->orderBy('id', 'desc')->limit(1000)->get();
+ dump(count($UserSalesVolumes));
+ $c = 0;
+ foreach($UserSalesVolumes as $user_sales_volume){
+
+ if($user_sales_volume->shopping_order_id){
+ $UserInvoice = UserInvoice::where('shopping_order_id', $user_sales_volume->shopping_order_id)->first();
+ if($UserInvoice){
+ $user_sales_volume->user_invoice_id = $UserInvoice->id;
+ $user_sales_volume->save();
+ $c++;
+ }
+ }
+ }
+ dump("counter");
+ dd($c);
+
+ }
+
+
+ public static function store()
+ {
+ $data = Request::all();
+ \Session()->flash('alert-save', true);
+ return back();
+ }
+
+
+}
diff --git a/app/Services/SyS/UserCreditItemsAddFrom.php b/app/Services/SyS/UserCreditItemsAddFrom.php
new file mode 100644
index 00000000..9b25bf2b
--- /dev/null
+++ b/app/Services/SyS/UserCreditItemsAddFrom.php
@@ -0,0 +1,48 @@
+each(function($item){
+ $date = self::getExplodeMessage($item);
+ $item->from_month = $date['n'];
+ $item->from_year = $date['Y'];
+ $item->save();
+ });
+ dd("done");
+ }
+
+
+ private static function getExplodeMessage($item){
+ $date = [];
+ if(strpos($item->message, '#')){
+ $em = explode("#", $item->message);
+
+ if(isset($em[1])){ //month
+ $data['n'] =$em[1];
+ }
+ if(isset($em[2])){ //year
+ $data['Y'] =$em[2];
+ }
+ }
+ return $data;
+ }
+
+ public static function store()
+ {
+ abort(403, 'STOP funtion not online');
+ dd("");
+
+
+ }
+}
diff --git a/app/Services/SyS/UserCreditItemsChangeMessage.php b/app/Services/SyS/UserCreditItemsChangeMessage.php
new file mode 100644
index 00000000..0bef4f5e
--- /dev/null
+++ b/app/Services/SyS/UserCreditItemsChangeMessage.php
@@ -0,0 +1,88 @@
+limit(1000)->get();
+ dump(count($UserCreditItems));
+ $c = 0;
+ foreach($UserCreditItems as $item){
+ if($item->message){
+ $item->message = self::convertMessage($item->message);
+ $item->save();
+ $c++;
+ }
+ }
+ dump("counter");
+ dd($c);
+ }
+
+ public static function convertMessage($message){
+ $months = [
+ 'Januar' => "1#",
+ 'Februar' => "2#",
+ 'März' => "3#",
+ 'April' => "4#",
+ 'Mai' => "5#",
+ 'Juni' => "6#",
+ 'Juli' => "7#",
+ 'August' => "8#",
+ 'September' => "9#",
+ 'Oktober' => "10#",
+ 'November' => "11#",
+ 'Dezember' => "12#",
+ ];
+
+ $em = explode(" ", $message);
+ $new_message = "";
+ if($em[0] === "Provision"){
+ switch ($em[1]) {
+ case 'Shop':
+ $new_message .= 'payment.commission_shop#';
+ break;
+ case 'Team':
+ $new_message .= 'payment.commission_team#';
+ break;
+ case 'Payline':
+ $new_message .= 'payment.commission_payline#';
+ break;
+ case 'Wachstumsbonus':
+ $new_message .= 'payment.commission_growth_bonus#';
+ break;
+ default:
+ dd("Error: ".$message);
+ break;
+ }
+
+ if(isset($months[$em[2]])){
+ $new_message .= $months[$em[2]];
+ }
+ $new_message .= $em[3];
+ return $new_message;
+ }
+
+ return $message;
+
+ }
+
+ public static function store()
+ {
+ $data = Request::all();
+ \Session()->flash('alert-save', true);
+ return back();
+ }
+
+
+}
diff --git a/app/Services/SysLog.php b/app/Services/SysLog.php
index 95ddf38d..85afd16d 100644
--- a/app/Services/SysLog.php
+++ b/app/Services/SysLog.php
@@ -69,9 +69,7 @@ class SysLog
}
}
- public function getLevelType(){
- return $this->levelTypes[$this->log->level];
- }
+
diff --git a/app/Services/TranslationHelper.php b/app/Services/TranslationHelper.php
new file mode 100644
index 00000000..8e7ce6ac
--- /dev/null
+++ b/app/Services/TranslationHelper.php
@@ -0,0 +1,17 @@
+first();
+ return $UserLevel ? $UserLevel->getLang('name') : $name;
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/Services/UserService.php b/app/Services/UserService.php
index b0aa3229..5d56184e 100644
--- a/app/Services/UserService.php
+++ b/app/Services/UserService.php
@@ -1,7 +1,7 @@
$lang){
+ $ret[strtolower($code)] = strtolower($lang['native']);
+ }
+ return $ret;
+ }
+
+
+ public static function initCustomerYard($shopping_user, $for){
+ self::$user_tax_free = false;
+ if($shopping_user->same_as_billing){
+ self::$user_country = $shopping_user->billing_country;
+ self::$shipping_country = $shopping_user->billing_country;
+ }else{
+ self::$user_country = $shopping_user->billing_country;
+ self::$shipping_country = $shopping_user->shipping_country;
+ }
+ if(self::$user_country->supply_country && self::$shipping_country->supply_country){
+ self::$user_tax_free = true;
+ }
+ $ShippingCountry = ShippingCountry::whereCountryId(self::$shipping_country->id)->first();
+ self::$shipping_free = $ShippingCountry->shipping ? $ShippingCountry->shipping->free : false;
+ self::$shipping_free = self::$shipping_free !== null ? self::$shipping_free : false;
+ Yard::instance('shopping')->setShippingCountryWithPrice($ShippingCountry->id, $for);
+ Yard::instance('shopping')->setUserPriceInfos(self::getYardInfo());
+ }
+
+ public static function initUserYard(User $user, $shipping_country_id, $for){
+ self::$shipping_free = false;
+ self::checkUserTaxShippingCountry($user, $shipping_country_id,);
+ Yard::instance('shopping')->setShippingCountryWithPrice($shipping_country_id, $for);
+ Yard::instance('shopping')->setUserPriceInfos(self::getYardInfo());
+ }
+
+
public static function checkUserTaxShippingCountry(User $user, $shipping_country_id) {
- if(!$user->account && !$user->account->country_id){
+ if(!$user->account || !$user->account->country_id){
abort(403, 'Error: User hat kein Land!');
}
$ShippingCountry = ShippingCountry::findOrFail($shipping_country_id);
self::$user_tax_free = self::performUserTaxShippingCountry($user, $ShippingCountry);
-
+ return $ShippingCountry;
/*
dump( self::$user_price_code );
dump( self::$user_tax_free );
@@ -54,13 +93,12 @@ class UserService
}
}
//Lieferland ohne RSV
-
return false;
}
public static function getYardInfo(){
return [
- 'shipping_free' => false,
+ 'shipping_free' => self::$shipping_free,
'user_tax_free' => self::$user_tax_free,
'user_reverse_charge' => self::$user_reverse_charge,
'user_country_id' => self::$user_country->id,
@@ -81,7 +119,9 @@ class UserService
}
public static function getOrderInfo($key = false){
-
+ if(!self::$user_country){
+ return '';
+ }
switch ($key) {
case 'billing_state':
return self::$user_country->getLocated();
@@ -90,10 +130,10 @@ class UserService
return self::$shipping_country->getLocated();
break;
case 'tax_free':
- return self::$user_tax_free ? 'Nein' : 'Ja';
+ return self::$user_tax_free ? __('no') : __('yes');
break;
case 'user_reverse_charge':
- return self::$user_reverse_charge ? 'Ja' : 'Nein';
+ return self::$user_reverse_charge ? __('yes') : __('no');
break;
}
diff --git a/app/Services/UserUtil.php b/app/Services/UserUtil.php
new file mode 100644
index 00000000..96c8f676
--- /dev/null
+++ b/app/Services/UserUtil.php
@@ -0,0 +1,230 @@
+get();
+ foreach($ShoppingUsers as $shopping_user){
+ ShoppingUserMemberLog::create([
+ 'pre_member_id' => $shopping_user->member_id,
+ 'shopping_user_id' => $shopping_user->id,
+ 'new_member_id' => $new_member_id
+ ]);
+ $shopping_user->member_id = $new_member_id;
+ $shopping_user->save();
+ }
+ }
+
+ public static function setNewSponsorToChilds($inactive_sponsor_id, $new_sponsor_id){
+ //alle User die diesen inaktivien Sponsor haben
+ $child_users = User::where('m_sponsor', $inactive_sponsor_id)->get(); //auch deaktiverte
+ foreach($child_users as $child_user){
+ UserCleanUpLog::create([
+ 'inactive_sponsor_id' => $inactive_sponsor_id,
+ 'child_user_id' => $child_user->id,
+ 'new_sponsor_id' => $new_sponsor_id,
+ ]);
+ $child_user->m_sponsor = $new_sponsor_id;
+ $child_user->save();
+ }
+ }
+
+ public static function resetChildsToSponsor($re_sponsor_id){
+ //alle alten Childs vom re_sponsor_id / User wieder herstellen
+ $UserCleanUpUsers = UserCleanUpLog::where('inactive_sponsor_id', $re_sponsor_id)->get();
+ foreach($UserCleanUpUsers as $UserCleanUpUser){
+ $child_user = User::find($UserCleanUpUser->child_user_id);
+ if($child_user){
+ //delete Logs from user child where is newer then this
+ $deleteUserCleanUpLogs = UserCleanUpLog::where('child_user_id', $UserCleanUpUser->child_user_id)->where('created_at', '>', $UserCleanUpUser->created_at)->get();
+ foreach($deleteUserCleanUpLogs as $deleteUserCleanUpLog){
+ $deleteUserCleanUpLog->delete();
+ }
+ if($child_user->m_sponsor){ // child is active
+ $child_user->m_sponsor = $re_sponsor_id;
+ }
+ if($child_user->pre_sponsor){ //child is inactive
+ $child_user->pre_sponsor = $re_sponsor_id;
+ }
+ $child_user->save();
+ //delete this log
+ $UserCleanUpUser->delete();
+ }
+ }
+
+ }
+
+ public static function setUserToClient($user_id, $sponsor_id){
+ $user = User::find($user_id);
+
+ if($user){
+ $data = [
+ 'member_id' => $sponsor_id,
+ 'language' => $user->lang ? $user->lang : 'de',
+ 'billing_salutation' => $user->account->salutation,
+ 'billing_company' => $user->account->company,
+ 'billing_firstname' => $user->account->first_name,
+ 'billing_lastname' => $user->account->last_name,
+ 'billing_address' => $user->account->address,
+ 'billing_address_2' => $user->account->address_2,
+ 'billing_zipcode' => $user->account->zipcode,
+ 'billing_city' => $user->account->city,
+ 'billing_country_id' => $user->account->country_id,
+ 'billing_phone' => $user->account->getPhoneNumber(),
+ 'billing_email' => $user->email,
+ 'same_as_billing' => $user->account->same_as_billing,
+ 'shipping_salutation' => $user->account->shipping_salutation,
+ 'shipping_company' => $user->account->shipping_company,
+ 'shipping_firstname' => $user->account->shipping_firstname,
+ 'shipping_lastname' => $user->account->shipping_lastname,
+ 'shipping_address' => $user->account->shipping_address,
+ 'shipping_address_2' => $user->account->shipping_address_2,
+ 'shipping_zipcode' => $user->account->shipping_zipcode,
+ 'shipping_city' => $user->account->shipping_city,
+ 'shipping_country_id' => $user->account->shipping_country_id,
+ 'shipping_phone' => $user->account->getShippingPhoneFull(),
+ ];
+ ShoppingUser::create($data);
+ }
+ }
+
+
+ /*
+ find next activ sponsor on user id
+ first $sponsor_id can user_id, looks has m_sponsor or pre_sponsor.
+ */
+ public static function findNextActiveSponsor($sponsor_id){
+
+ $user = User::withTrashed()->find($sponsor_id);
+ if(!$user){ //kein User unter der ID - to root
+ return User::find(6);
+ }
+ //user ist aktiv
+ if($user->isActiveAccount()){
+ return $user;
+ }
+ if($user->m_sponsor){ //hat der User einen m_sponsor
+ return self::findNextActiveSponsor($user->m_sponsor);
+ }
+ if($user->pre_sponsor){ //hat der User einen pre_sponsor - schon inaktiv
+ return self::findNextActiveSponsor($user->pre_sponsor);
+ }
+ //dump('not sponsor');
+ return $user;
+ }
+
+ public static function deactiveUser($user){
+
+ $user->pre_sponsor = $user->m_sponsor; //den sponsor speichern für wiederherstellung
+ $user->m_sponsor = null;
+ $user->active = false;
+ $user->save();
+ }
+
+ public static function reactiveUser($user){
+
+ if($user->pre_sponsor){
+ $pre_sponsor = self::findNextActiveSponsor($user->pre_sponsor);
+ $user->m_sponsor = $pre_sponsor->id; //den sponsor wiederherstellen
+ $user->pre_sponsor = null;
+ }
+ $user->active = true;
+ $user->save();
+ }
+
+ public static function deleteUser(User $user)
+ {
+ if($user->account){
+ $user->account->delete();
+ }
+ if($user->shop){
+ $subdomain_name = $user->shop->slug.'.mivita.care';
+ $user->shop->name = "delete".$user->shop->id;
+ $user->shop->slug = "delete".$user->shop->id;
+ $user->shop->save();
+ $user->shop->delete();
+ //isset KAS - delete Subdomain
+ if(!Util::isTestSystem()){
+ $kas = new KasController();
+ $pra = array(
+ 'subdomain_name' => $subdomain_name,
+ );
+ $kas->action('delete_subdomain', $pra);
+ }
+ }
+ $user->email = "delete".time().mt_rand(1000000, 9999999);
+ $user->password = "delete".time();
+ $user->confirmed = 0;
+ $user->confirmation_code = "delete".time();
+ $user->confirmation_date = null;
+ $user->confirmation_code_to = null;
+ $user->confirmation_code_remider = 2;
+ $user->agreement = null;
+ $user->active = 0;
+ $user->remember_token = '';
+ $user->active_date = null;
+ $user->admin = 0;
+ $user->deleted_at = now();
+ $user->save();
+
+ return true;
+ }
+
+ public static function reactiveUserResetChilds($user_id, $info = ''){
+
+ $user = User::find($user_id);
+ if(!$user){
+ \Log::channel('cleanup')->error('reactiveUserResetChilds find no user by user_id:'.$user_id);
+ return 0;
+ }
+ $data = [
+ 'user_id' => $user->id,
+ 'email' => $user->email,
+ 'm_account' => $user->account ? $user->account->m_account : '',
+ 'm_first_name' => $user->account ? $user->account->m_first_name : '',
+ 'm_last_name' => $user->account ? $user->account->m_last_name : '',
+ ];
+ \Log::channel('cleanup')->info('reactiveUserResetChilds '.$info.' : '.json_encode($data));
+
+ self::reactiveUser($user);
+ self::resetChildsToSponsor($user->id);
+ }
+
+ public static function deactiveUserNewSponsorChilds($user_id, $info = ''){
+
+ $user = User::find($user_id);
+ if(!$user){
+ \Log::channel('cleanup')->error('deactiveUserNewSponsorChilds find no user by user_id:'.$user_id);
+ return 0;
+ }
+ $data = [
+ 'user_id' => $user->id,
+ 'email' => $user->email,
+ 'm_account' => $user->account ? $user->account->m_account : '',
+ 'm_first_name' => $user->account ? $user->account->m_first_name : '',
+ 'm_last_name' => $user->account ? $user->account->m_last_name : '',
+ ];
+
+ $active_sponsor = self::findNextActiveSponsor($user->m_sponsor);
+ if($active_sponsor){
+ self::setNewSponsorToChilds($user->id, $active_sponsor->id);
+ }else{
+ \Log::channel('cleanup')->error('cleanUpInActiveUser find no active_sponsor by inactive_user:'.$user->id);
+ }
+ \Log::channel('cleanup')->info('deactiveUserNewSponsorChilds '.$info.' : '.json_encode($data));
+ self::deactiveUser($user);
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/Services/Util.php b/app/Services/Util.php
index e340750a..a4f4084f 100644
--- a/app/Services/Util.php
+++ b/app/Services/Util.php
@@ -270,12 +270,28 @@ class Util
return \Config::get('app.url') === config('app.domain').config('app.tld_shop');
}
- public static function isTestSystem(){
+ public static function isTestSystem($dev = false){
if(\Config::get('app.tld_care') === '.test' || \Config::get('app.tld_shop') === '.lshop'){
+ if($dev && config('app.debug') !== true){
+ return false;
+ }
return true;
}
return false;
}
+
+ public static function formatBytes($size, $precision = 2)
+ {
+ if ($size > 0) {
+ $size = (int) $size;
+ $base = log($size) / log(1024);
+ $suffixes = array(' bytes', ' KB', ' MB', ' GB', ' TB');
+
+ return round(pow(1024, $base - floor($base)), $precision) . $suffixes[floor($base)];
+ } else {
+ return $size;
+ }
+ }
public static function sanitize($string, $force_lowercase = true, $anal = false, $substr = false)
{
diff --git a/app/Services/Yard.php b/app/Services/Yard.php
index b430dccf..9d04a222 100644
--- a/app/Services/Yard.php
+++ b/app/Services/Yard.php
@@ -1,6 +1,7 @@
shipping_price;
+ }
+
+
public function getYContent()
{
if (is_null($this->ysession->get($this->yinstance))) {
@@ -149,7 +156,7 @@ class Yard extends Cart
$this->calculateShippingPrice();
}
- public function setShippingCountryWithPrice($shipping_country_id, $shipping_is_for = 'ot')
+ public function setShippingCountryWithPrice($shipping_country_id, $shipping_is_for = 'ot-member')
{
$this->shipping_country_id = $shipping_country_id;
$this->putYardExtra('shipping_country_id', $shipping_country_id);
@@ -208,6 +215,15 @@ class Yard extends Cart
return $this->shipping_free;
}
+ public function getShippingFreeMissingValue()
+ {
+ if($this->shipping_free && $this->total(2, '.', '') < $this->shipping_free){
+ return $this->shipping_free - $this->total(2, '.', '');
+ }
+ return 0;
+ }
+
+
private function calculateShippingPrice(){
$shippingCountry = ShippingCountry::find($this->shipping_country_id);
@@ -246,8 +262,8 @@ class Yard extends Cart
}
if($shipping_price){
$price = $shipping_price->price;
- $this->num_comp = 0;
- if($this->shipping_is_for === 'me'){
+ $this->num_comp = 0; //compensation is checked in Settings
+ if(Shop::isCompProducts($this->shipping_is_for)){
$price = $shipping_price->price_comp;
$this->num_comp = $shipping_price->num_comp;
diff --git a/app/Services/dbip/MyDBIP.php b/app/Services/dbip/MyDBIP.php
new file mode 100644
index 00000000..d26979ca
--- /dev/null
+++ b/app/Services/dbip/MyDBIP.php
@@ -0,0 +1,94 @@
+where('ip_start', '<=', $addrStart)->orderBy('ip_start', 'desc')->first();
+ $c1 = isset($res->country) ? $res->country : null;
+
+ $res = DbipLookup2::where('addr_type', $addrType)->where('ip_start', '<=', $addrStart)->orderBy('ip_start', 'desc')->first();
+ $c2 = isset($res->country) ? $res->country : null;
+
+ if($c1 == $c2){
+ return $c1;
+ }
+
+ $res = DbipLookup3::where('addr_type', $addrType)->where('ip_start', '<=', $addrStart)->orderBy('ip_start', 'desc')->first();
+ if(isset($res->country)){
+ return $res->country;
+ }
+
+ //look in api
+
+ return false;
+ }
+
+ static private function addrType($addr) {
+ if (ip2long($addr) !== false) {
+ return "ipv4";
+ } else if (preg_match('/^[0-9a-fA-F:]+$/', $addr) && @inet_pton($addr)) {
+ return "ipv6";
+ }
+ throw new DBIPException("unknown address type for {$addr}");
+ }
+
+ static public function insert($addr, $country) {
+
+ $lookup = new DbipLookup3();
+ $lookup->addr_type = self::addrType($addr);
+ $lookup->ip_start = inet_pton($addr);
+ $lookup->ip_end = inet_pton($addr);
+ $lookup->country = strtoupper($country);
+ $lookup->save();
+
+ }
+
+}
\ No newline at end of file
diff --git a/app/Services/dbip/dbip-convert.php b/app/Services/dbip/dbip-convert.php
new file mode 100755
index 00000000..915bd89f
--- /dev/null
+++ b/app/Services/dbip/dbip-convert.php
@@ -0,0 +1,211 @@
+#!/usr/bin/env php
+ function(array $csvData, $of, string $firstIpBin, string $lastIpBin): void {
+ writeCSV($of, $csvData);
+ },
+ "cidr" => function(array $csvData, $of, string $firstIpBin, string $lastIpBin): void {
+ array_shift($csvData);
+ foreach (rangeToCIDR($firstIpBin, $lastIpBin) as $cidrNet) {
+ $csvData[0] = $cidrNet;
+ writeCSV($of, $csvData);
+ }
+ },
+ "long" => function(array $csvData, $of, string $firstIpBin, string $lastIpBin): void {
+ if (($firstIpLong = ip2long($csvData[0])) === false) {
+ throw new Exception("invalid IP address for long conversion : {$csvData[0]}");
+ } else if (($lastIpLong = ip2long($csvData[1])) === false) {
+ throw new Exception("invalid IP address for long conversion : {$csvData[1]}");
+ }
+ $csvData[0] = $firstIpLong;
+ $csvData[1] = $lastIpLong;
+ writeCSV($of, $csvData);
+ },
+];
+
+function writeCSV($of, $csvData) {
+ fputcsv($of, $csvData);
+}
+
+function vEcho(string $s): void {
+ if (!$GLOBALS["verbose"]) {
+ return;
+ }
+ echo $s;
+}
+
+function findLargestNetwork(string $ipStartBin): int {
+ for ($i = strlen($ipStartBin); $i--; $i >= 0) {
+ $byte = ord($ipStartBin[$i]);
+ for ($j = 7; $j >= 0; $j--) {
+ if ($byte & (0xff >> $j)) {
+ return ($i << 3) + $j + 1;
+ }
+ }
+ }
+ return 0;
+}
+
+function getLastAddress(string $ipStartBin, int $cidrBits): string {
+ $ret = $ipStartBin;
+ for ($i = strlen($ipStartBin); $i--; $i >= 0) {
+ $firstBit = ($i << 3) + 1;
+ $lastBit = ($i + 1) << 3;
+ if ($cidrBits > $lastBit) {
+ continue;
+ } else if ($cidrBits < $firstBit) {
+ $ret[$i] = "\xff";
+ } else {
+ $ret[$i] = chr(ord($ret[$i]) | (0xff >> ($cidrBits - $firstBit + 1)));
+ }
+ }
+ return $ret;
+}
+
+function getNextAddress(string $ipStartBin): string {
+ $ret = $ipStartBin;
+ for ($i = strlen($ipStartBin); $i--; $i >= 0) {
+ for ($j = 7; $j >= 0; $j--) {
+ $byte = ord($ret[$i]);
+ $mask = 1 << (7 - $j);
+ if ($byte & $mask) {
+ $ret[$i] = chr($byte & ~$mask);
+ } else {
+ $ret[$i] = chr($byte | $mask);
+ return $ret;
+ }
+ }
+ }
+ throw new Exception("no next address for " . inet_ntop($ipStartBin));
+}
+
+function rangeToCIDR(string $ipStartBin, string $ipEndBin): array {
+ if (strcmp($ipStartBin, $ipEndBin) > 0) {
+ throw new Exception("wrong ip address order");
+ }
+ $cidrNets = [];
+ $cidrBits = findLargestNetwork($ipStartBin);
+ do {
+ $lastAddrBin = getLastAddress($ipStartBin, $cidrBits);
+ if (($cmp = strcmp($lastAddrBin, $ipEndBin)) <= 0) {
+ $cidrNets[] = inet_ntop($ipStartBin) . "/" . $cidrBits;
+ if ($cmp === 0) {
+ return $cidrNets;
+ }
+ $ipStartBin = getNextAddress($lastAddrBin);
+ $cidrBits = findLargestNetwork($ipStartBin);
+ } else {
+ $cidrBits++;
+ }
+ } while (true);
+}
+
+try {
+
+ $exitCode = 0;
+ $opts = getopt("i:o:f:qhw46");
+ $verbose = !isset($opts["q"]);
+
+ if (!$opts || isset($opts["h"]) || !isset($opts["i"]) || !isset($opts["o"]) || !isset($opts["f"]) || (isset($opts["4"]) && isset($opts["6"]))) {
+ echo "usage: {$argv[0]} -i -o -f [-4|-6] [-w] [-q]\n";
+ echo " -i input CSV file\n";
+ echo " -o output file name\n";
+ echo " -f output format (" . implode("|", array_keys($outputFormats)) . ")\n";
+ echo " -4 output ipv4 networks only\n";
+ echo " -6 output ipv6 networks only\n";
+ echo " -w overwrite output file if it already exists\n";
+ echo " -q be quiet\n";
+ exit(1);
+ }
+
+ $inputFile = $opts["i"];
+ if (!file_exists($inputFile)) {
+ throw new Exception("cannot find input file: {$inputFile}");
+ } else if (!is_readable($inputFile)) {
+ throw new Exception("cannot read input file: {$inputFile}");
+ }
+ if (substr($inputFile, -3) === ".gz") {
+ $inputFile = "compress.zlib://" . $inputFile;
+ }
+ if (!$if = fopen($inputFile, "r")) {
+ throw new Exception("cannot open input file: {$inputFile}");
+ }
+
+ $outputFile = $opts["o"];
+ if (file_exists($outputFile) && !isset($opts["w"])) {
+ throw new Exception("output file {$outputFile} already exists, use -w to force overwrite");
+ }
+ if (substr($outputFile, -3) === ".gz") {
+ $outputFile = "compress.zlib://" . $outputFile;
+ }
+ if (!$of = fopen($outputFile, "w")) {
+ throw new Exception("cannot open output file: {$outPutFile}");
+ }
+
+ if (!isset($outputFormats[$opts["f"]])) {
+ throw new Exception("invalid output format {$opts['f']}");
+ }
+ $outputFormatter = $outputFormats[$opts["f"]];
+
+ $i = 0;
+ while ($r = fgetcsv($if, 8192)) {
+ $i++;
+ [ $firstIp, $lastIp ] = $r;
+ try {
+ if (!$firstIpBin = inet_pton($firstIp)) {
+ throw new Exception("invalid first IP '{$firstIp}' in CSV record");
+ } else if (!$lastIpBin = inet_pton($lastIp)) {
+ throw new Exception("invalid last IP '{$lastIp}' in CSV record");
+ } else if (($addrLen = strlen($firstIpBin)) !== strlen($lastIpBin)) {
+ throw new Exception("first and last IP address family mismatch ({$firstIp} / {$lastIp})");
+ }
+ if (isset($opts["4"]) && ($addrLen !== 4)) {
+ continue;
+ } else if (isset($opts["6"]) && ($addrLen !== 16)) {
+ continue;
+ }
+ $outputFormatter($r, $of, $firstIpBin, $lastIpBin);
+ } catch (Exception $e) {
+ throw new Exception("line {$i}: {$e->getMessage()}");
+ }
+ }
+ fclose($if);
+ fclose($of);
+
+ vEcho("Wrote {$outputFile}\n");
+
+} catch (Exception $e) {
+ if ($stdErr = @fopen("php://stderr", "w")) {
+ fwrite($stdErr, "ERROR: {$e->getMessage()}\n");
+ fclose($stdErr);
+ } else {
+ echo "ERROR: {$e->getMessage()}\n";
+ }
+ $exitCode = 1;
+}
+if ($exitCode) {
+ exit($exitCode);
+}
\ No newline at end of file
diff --git a/app/Services/dbip/dbip-update.ini.sample b/app/Services/dbip/dbip-update.ini.sample
new file mode 100644
index 00000000..e63deedf
--- /dev/null
+++ b/app/Services/dbip/dbip-update.ini.sample
@@ -0,0 +1,10 @@
+[account]
+; Your account key is available in your customer section at https://db-ip.com/account/
+accountKey = INSERT_YOUR_ACCOUNT_KEY_HERE
+
+[database]
+; This is the PDO Data Source Name for your database instance, see http://php.net/manual/pdo.construct.php
+dataSourceName = "mysql:host=localhost;dbname=myapp"
+; dbUser and dbPassword are the database account credentials
+dbUser = myapp
+dbPassword = myapp123
diff --git a/app/Services/dbip/dbip-update.php b/app/Services/dbip/dbip-update.php
new file mode 100755
index 00000000..b390034c
--- /dev/null
+++ b/app/Services/dbip/dbip-update.php
@@ -0,0 +1,327 @@
+#!/usr/bin/env php
+error)) {
+ throw new Exception("API error: {$resp->error}");
+ }
+ return $resp;
+}
+
+function vEcho($s) {
+ if (!$GLOBALS["verbose"]) {
+ return false;
+ }
+ echo $s;
+}
+
+try {
+
+ $exitCode = 0;
+ $opts = getopt("k:d:f:o:zZqlnwb:u:p:t:c:D");
+ $verbose = !isset($opts["q"]);
+
+ if (isset($opts["c"])) {
+ if (!file_exists($opts["c"]) || !is_readable($opts["c"])) {
+ throw new Exception("cannot read configuration file {$opts['c']}");
+ }
+ $confName = $opts["c"];
+ } else if (file_exists(__DIR__ . DIRECTORY_SEPARATOR . DEFAULT_CONF) && is_readable(__DIR__ . DIRECTORY_SEPARATOR . DEFAULT_CONF)) {
+ $confName = __DIR__ . DIRECTORY_SEPARATOR . DEFAULT_CONF;
+ }
+
+ if (isset($confName)) {
+ if (($conf = parse_ini_file($confName)) === false) {
+ throw new Exception("cannot parse configuration file {$confName}");
+ }
+ $confMap = [
+ "accountKey" => "k",
+ "dbType" => "d",
+ "format" => "f",
+ "outputDir" => "o",
+ "outputFileName" => "o",
+ "dataSourceName" => "b",
+ "dbUser" => "u",
+ "dbPassword" => "p",
+ "dbTableName" => "t",
+ ];
+ foreach ($conf as $name => $value) {
+ if (!isset($confMap[$name])) {
+ throw new Exception("invalid configuration parameter {$name}");
+ } else if (!isset($opts[$confMap[$name]])) {
+ $opts[$confMap[$name]] = $value;
+ }
+ }
+ }
+
+ if (!isset($opts["k"]) || !$opts["k"]) {
+ echo "usage: {$argv[0]} -k [-l] [-d ] [-f ] [-o ] [-b [-u ] [-p ] [-D]] [-c ] [-n] [-z|-Z] [-w] [-q]\n";
+ echo " -l list available items and exit\n";
+ echo " -n request new items only\n";
+ echo " -z fetch uncompressed file (default for mmdb format)\n";
+ echo " -Z fetch compressed file (default for csv format)\n";
+ echo " -w overwrite destination file if it already exists\n";
+ echo " -b PDO DSN for database update (ie. \"mysql:host=localhost;dbname=dbip\")\n";
+ echo " -u database username (default 'root')\n";
+ echo " -p database password (default '')\n";
+ echo " -t name of database table (default 'dbip_lookup')\n";
+ echo " -D do not use a temporary table (table specified by -t must be empty)\n";
+ echo " -q be quiet\n";
+ exit(1);
+ }
+ $apiKey = $opts["k"];
+
+ if (!isset($opts["d"])) {
+ $dbList = apiRequest("/", $apiKey);
+ if (count((array)$dbList) > 1) {
+ vEcho("Use -d to select a database type :\n");
+ foreach ($dbList as $dbType => $dbInfo) {
+ echo $dbType . "\n";
+ }
+ exit();
+ } else {
+ foreach ($dbList as $dbType => $dbInfo) {
+ break;
+ }
+ }
+ } else {
+ $dbType = $opts["d"];
+ }
+
+ if (isset($opts["b"])) {
+ if (isset($opts["o"])) {
+ throw new Exception("Arguments -b and -o cannot be used in the same command line");
+ }
+ $dbUser = isset($opts["u"]) ? $opts["u"] : "root";
+ $dbPassword = isset($opts["p"]) ? $opts["p"] : "";
+ $dbTable = isset($opts["t"]) ? $opts["t"] : "dbip_lookup";
+ $format = "csv";
+ try {
+ $dsn = $opts["b"];
+ if (preg_match('/^mysql:/', $dsn)) {
+ if (!preg_match('/charset=/', $dsn)) {
+ $dsn .= ";charset=utf8mb4";
+ }
+ $dbQuoteChar = '`'; // backquote for MySQL
+ } else {
+ $dbQuoteChar = '"'; // double quote for ANSI SQL
+ }
+ $db = new PDO($dsn, $dbUser, $dbPassword);
+ $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+ $db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
+ $dbUseTempTable = !isset($opts["D"]);
+ } catch (PDOException $e) {
+ throw new Exception("Cannot connect to database: {$e->getMessage()}");
+ }
+ } else {
+ if (!isset($opts["f"])) {
+ $filesList = apiRequest("/{$dbType}", $apiKey);
+ vEcho("Use -f to specify a format for your {$dbType} subscription :\n");
+ foreach ($filesList as $format => $fileInfo) {
+ echo $format . "\n";
+ }
+ exit();
+ }
+ $format = $opts["f"];
+ }
+ $onlyNew = isset($opts["n"]);
+
+ try {
+ $queryString = $onlyNew ? "?new=1" : "";
+ $fileInfo = apiRequest("/{$dbType}/{$format}{$queryString}", $apiKey);
+ if ($onlyNew && !$fileInfo) {
+ vEcho("there are no new downloads available\n");
+ exit(0);
+ }
+ } catch (Exception $e) {
+ throw new Exception("cannot access download info : {$e->getMessage()}");
+ }
+
+ if (isset($opts["l"])) {
+ if (!isset($fileInfo)) {
+ vEcho("no download file match\n");
+ exit();
+ }
+ foreach ($fileInfo as $name => $value) {
+ echo "{$name}: {$value}\n";
+ }
+ exit();
+ }
+
+ if (isset($opts["z"])) {
+ $uncompress = true;
+ } else if (isset($opts["Z"]) || ($format === "csv")) {
+ $uncompress = false;
+ } else {
+ $uncompress = true;
+ }
+
+ $outputFile = "." . DIRECTORY_SEPARATOR . $fileInfo->name;
+ if (isset($opts["o"])) {
+ if (is_dir($opts["o"])) {
+ $outputFile = $opts["o"] . DIRECTORY_SEPARATOR . $fileInfo->name;
+ } else {
+ $outputFile = $opts["o"];
+ }
+ }
+ $sourcePrefix = $uncompress ? "compress.zlib://" : "";
+ if ($uncompress && preg_match('/\.gz$/i', $outputFile)) {
+ $outputFile = preg_replace('/\.gz$/i', '', $outputFile);
+ }
+ $outputTempFile = $outputFile . ".update-tmp";
+
+ if (file_exists($outputTempFile) && !unlink($outputTempFile)) {
+ throw new Exception("cannot delete temporary file {$outputTempFile}");
+ } else if (!isset($db) && file_exists($outputFile) && !isset($opts["w"])) {
+ throw new Exception("destination file {$outputFile} already exists, use -w to force overwrite");
+ }
+
+ vEcho("Starting update for {$dbType} ({$fileInfo->date})\n");
+ if (!copy($sourcePrefix . $fileInfo->url, $outputTempFile, stream_context_create([], [ "notification" => function($notificationCode, $severity, $message, $messageCode, $bytesTransferred, $bytesMax) {
+ static $totBytes, $prevPct = false;
+ if ($bytesMax) {
+ $totBytes = $bytesMax;
+ }
+ if ($bytesTransferred) {
+ if (isset($totBytes) && $totBytes) {
+ $pct = number_format(($bytesTransferred / $totBytes) * 100, 1);
+ }
+ if ($pct !== $prevPct) {
+ vEcho("\rDownloading: " . number_format($bytesTransferred / 1024) . " KB" . (isset($pct) ? " ({$pct}%)" : ""));
+ $prevPct = $pct;
+ }
+ }
+ }]))) {
+ throw new Exception("unable to download file to {$outputTempFile}");
+ }
+ vEcho("\rDownload completed: " . number_format(filesize($outputTempFile) / 1024, 1) . " KB\n");
+
+ $checkPrefix = $uncompress ? "" : "compress.zlib://";
+ if (isset($fileInfo->md5sum) || isset($fileInfo->sha1sum)) {
+ vEcho("Verify signature: ");
+ if (isset($fileInfo->md5sum)) {
+ $md5sum = md5_file($checkPrefix . $outputTempFile);
+ if ($md5sum !== $fileInfo->md5sum) {
+ vEcho("MISMATCH {$md5sum} != {$fileInfo->md5sum}\n");
+ throw new Exception("MD5 signature verification failed, file is probably corrupt or altered");
+ }
+ vEcho("[MD5] ");
+ }
+ if (isset($fileInfo->sha1sum)) {
+ $sha1sum = sha1_file($checkPrefix . $outputTempFile);
+ if ($sha1sum !== $fileInfo->sha1sum) {
+ vEcho("MISMATCH {$sha1sum} != {$fileInfo->sha1sum}\n");
+ throw new Exception("SHA1 signature verification failed, file is probably corrupt or altered");
+ }
+ vEcho("[SHA1] ");
+ }
+ vEcho("passed\n");
+ }
+
+ if (isset($db)) {
+ $dbip = new DBIP($db, $dbQuoteChar);
+ $relId = $dbType;
+ if ($fileInfo->version) {
+ $relId .= "-v{$fileInfo->version}";
+ }
+ switch ($relId) {
+ case "ip-to-country-lite": $importType = DBIP::TYPE_COUNTRY_LITE; break;
+ case "ip-to-city-lite": $importType = DBIP::TYPE_CITY_LITE; break;
+ case "ip-to-country-v4": $importType = DBIP::TYPE_COUNTRY_V4; break;
+ case "ip-to-location-v4": $importType = DBIP::TYPE_LOCATION_V4; break;
+ case "ip-to-isp-v4": $importType = DBIP::TYPE_ISP_V4; break;
+ case "ip-to-location-isp-v4":
+ case "ip-to-full-v4": $importType = DBIP::TYPE_FULL_V4; break;
+ case "ip-to-country-v3": $importType = DBIP::TYPE_COUNTRY_V3; break;
+ case "ip-to-location-v3": $importType = DBIP::TYPE_LOCATION_V3; break;
+ case "ip-to-isp-v3": $importType = DBIP::TYPE_ISP_V3; break;
+ case "ip-to-location-isp-v3":
+ case "ip-to-full-v3": $importType = DBIP::TYPE_FULL_V3; break;
+ case "ip-to-location-v2": $importType = DBIP::TYPE_LOCATION_V2; break;
+ case "ip-to-isp-v2": $importType = DBIP::TYPE_ISP_V2; break;
+ case "ip-to-location-isp-v2":
+ case "ip-to-full-v2": $importType = DBIP::TYPE_FULL_V2; break;
+ default: throw new Exception("unsupported database type");
+ }
+ if ($dbUseTempTable) {
+ $tempTable = "dbip_update_" . time();
+ $db->exec("drop table if exists {$dbQuoteChar}{$tempTable}{$dbQuoteChar}");
+ $db->exec("create table {$dbQuoteChar}{$tempTable}{$dbQuoteChar} like {$dbQuoteChar}{$dbTable}{$dbQuoteChar}");
+ } else {
+ $tempTable = $dbTable;
+ }
+ $dbip->importFromCsv($outputTempFile, $importType, $tempTable, function($numRows) use ($fileInfo) {
+ if ($numRows % 1000) {
+ return false;
+ }
+ if (isset($fileInfo->rows) && $fileInfo->rows) {
+ $pct = number_format(($numRows / $fileInfo->rows) * 100, 1);
+ }
+ vEcho("\rImporting: " . number_format($numRows) . " rows" . (isset($pct) ? " ({$pct}%)" : ""));
+ });
+ $numRows = (int)$db->query("select count(1) cnt from {$dbQuoteChar}{$tempTable}{$dbQuoteChar}")->fetchObject()->cnt;
+ if ($dbUseTempTable) {
+ $db->exec("drop table if exists {$dbQuoteChar}{$tempTable}_old{$dbQuoteChar}");
+ $db->exec("rename table {$dbQuoteChar}{$dbTable}{$dbQuoteChar} to {$dbQuoteChar}{$tempTable}_old{$dbQuoteChar}, {$dbQuoteChar}{$tempTable}{$dbQuoteChar} to {$dbQuoteChar}{$dbTable}{$dbQuoteChar}");
+ $db->exec("drop table {$dbQuoteChar}{$tempTable}_old{$dbQuoteChar}");
+ }
+ vEcho("\rDatabase updated: " . number_format($numRows) . " rows imported\n");
+ } else {
+ if (!rename($outputTempFile, $outputFile)) {
+ throw new Exception("cannot rename temporary file {$outputTempFile} to {$outputFile}");
+ }
+ vEcho("Wrote {$outputFile}\n");
+ }
+
+} catch (Exception $e) {
+ if ($stdErr = @fopen("php://stderr", "w")) {
+ fwrite($stdErr, "ERROR: {$e->getMessage()}\n");
+ fclose($stdErr);
+ } else {
+ echo "ERROR: {$e->getMessage()}\n";
+ }
+ $exitCode = 1;
+} finally {
+ if (isset($outputTempFile) && file_exists($outputTempFile)) {
+ unlink($outputTempFile);
+ }
+ if (isset($db) && isset($tempTable) && $dbUseTempTable) {
+ $db->exec("drop table if exists {$dbQuoteChar}{$tempTable}{$dbQuoteChar}");
+ $db->exec("drop table if exists {$dbQuoteChar}{$tempTable}_old{$dbQuoteChar}");
+ }
+}
+if ($exitCode) {
+ exit($exitCode);
+}
diff --git a/app/Services/dbip/dbip.class.php b/app/Services/dbip/dbip.class.php
new file mode 100755
index 00000000..0fb28c4c
--- /dev/null
+++ b/app/Services/dbip/dbip.class.php
@@ -0,0 +1,346 @@
+db = $db;
+ $this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+ $this->dbQuoteChar = $dbQuoteChar;
+ }
+
+ public function importFromCsv($fileName, $type, $tableName = "dbip_lookup", $progressCallback = null) {
+ switch ($type) {
+ case self::TYPE_COUNTRY_LITE:
+ $fields = array("ip_start", "ip_end", "country");
+ $fieldsprepare = $fields;
+ break;
+ case self::TYPE_COUNTRY_IPINFO:
+ $fields = array("ip_start", "ip_end", "country", "d1", "d2", "d3");
+ $fieldsprepare = array("ip_start", "ip_end", "country");
+ break;
+ case self::TYPE_CITY_LITE:
+ $fields = array("ip_start", "ip_end", "continent", "country", "stateprov", "city", "latitude", "longitude");
+ break;
+ case self::TYPE_COUNTRY_V4:
+ case self::TYPE_COUNTRY_V3:
+ $fields = array("ip_start", "ip_end", "continent", "country");
+ break;
+ case self::TYPE_LOCATION_V4:
+ $fields = array("ip_start", "ip_end", "continent", "country", "stateprov_code", "stateprov", "district", "city", "zipcode", "latitude", "longitude", "geoname_id", "timezone_offset", "timezone_name", "weather_code");
+ break;
+ case self::TYPE_ISP_V4:
+ $fields = array("ip_start", "ip_end", "continent", "country", "isp_name", "as_number", "usage_type", "connection_type", "organization_name");
+ break;
+ case self::TYPE_FULL_V4:
+ $fields = array("ip_start", "ip_end", "continent", "country", "stateprov_code", "stateprov", "district", "city", "zipcode", "latitude", "longitude", "geoname_id", "timezone_offset", "timezone_name", "weather_code", "isp_name", "as_number", "usage_type", "connection_type", "organization_name");
+ break;
+ case self::TYPE_LOCATION_V3:
+ $fields = array("ip_start", "ip_end", "continent", "country", "stateprov", "district", "city", "zipcode", "latitude", "longitude", "geoname_id", "timezone_offset", "timezone_name", "weather_code");
+ break;
+ case self::TYPE_ISP_V3:
+ $fields = array("ip_start", "ip_end", "continent", "country", "isp_name", "as_number", "connection_type", "organization_name");
+ break;
+ case self::TYPE_FULL_V3:
+ $fields = array("ip_start", "ip_end", "continent", "country", "stateprov", "district", "city", "zipcode", "latitude", "longitude", "geoname_id", "timezone_offset", "timezone_name", "weather_code", "isp_name", "as_number", "connection_type", "organization_name");
+ break;
+ case self::TYPE_LOCATION_V2:
+ $fields = array("ip_start", "ip_end", "country", "stateprov", "district", "city", "zipcode", "latitude", "longitude", "geoname_id", "timezone_offset", "timezone_name");
+ break;
+ case self::TYPE_ISP_V2:
+ $fields = array("ip_start", "ip_end", "country", "isp_name", "connection_type", "organization_name");
+ break;
+ case self::TYPE_FULL_V2:
+ $fields = array("ip_start", "ip_end", "country", "stateprov", "district", "city", "zipcode", "latitude", "longitude", "geoname_id", "timezone_offset", "timezone_name", "isp_name", "connection_type", "organization_name");
+ break;
+ default:
+ throw new DBIPException("invalid database type");
+ }
+ if (!file_exists($fileName)) {
+ throw new DBIPException("file {$fileName} does not exists");
+ }
+ $q = $this->prepareImport($tableName, $fieldsprepare);
+ if (preg_match('/\.gz(\..+)?$/', $fileName)) {
+ $openName = "compress.zlib://" . $fileName;
+ } else {
+ $openName = $fileName;
+ }
+ $f = @fopen($openName, "r");
+ if (!is_resource($f)) {
+ throw new DBIPException("cannot open {$fileName} for reading");
+ }
+ $nrecs = 0;
+ while ($r = fgetcsv($f, 1024, ",", '"', "\0")) {
+ foreach ($r as $k => $v) {
+ if (!isset($fields[$k])) {
+ throw new DBIPException("invalid CSV record for {$r[0]}");
+ }
+ switch ($fields[$k]) {
+ case "latitude":
+ case "longitude":
+ case "timezone_offset":
+ $r[$k] = (float)$v;
+ break;
+ case "d1":
+ case "d2":
+ case "d3":
+ unset($r[$k]);
+ break;
+ case "isp_name":
+ case "organization_name":
+ $r[$k] = mb_substr($v, 0, 128);
+ break;
+ case "city":
+ case "district":
+ case "stateprov":
+ $r[$k] = mb_substr($v, 0, 80);
+ break;
+ case "zipcode":
+ $r[$k] = mb_substr($v, 0, 20);
+ break;
+ case "timezone_name":
+ $r[$k] = mb_substr($v, 0, 64);
+ break;
+ case "connection_type":
+ case "stateprov_code":
+ case "usage_type":
+ case "geoname_id":
+ case "as_number":
+ if (!$r[$k]) $r[$k] = null;
+ break;
+ default:
+ }
+ }
+
+ try {
+ /*$r[] = self::addrType($r[0]);
+ $r[0] = inet_pton($r[0]);
+ $r[1] = inet_pton($r[1]);*/
+
+ $set = [
+ 0 => inet_pton($r[0]),
+ 1 => inet_pton($r[1]),
+ 2 => $r[2],
+ 3 => self::addrType($r[0])
+ ];
+ $this->importRow($q, $set);
+ } catch (Exception $e) {
+ throw new Exception("cannot import record #{$nrecs}: {$e->getMessage()}");
+ }
+ if ((($nrecs % 100) === 0) && is_callable($progressCallback)) {
+ call_user_func($progressCallback, $nrecs);
+ }
+ $nrecs++;
+ }
+ fclose($f);
+ $this->finalizeImport();
+ return $nrecs;
+ }
+
+ public function lookup($addr, $tableName = "dbip_lookup") {
+ if ($ret = $this->doLookup($tableName, self::addrType($addr), inet_pton($addr))) {
+ $ret->ip_start = inet_ntop($ret->ip_start);
+ $ret->ip_end = inet_ntop($ret->ip_end);
+ return $ret;
+ } else {
+ throw new DBIPException("address not found");
+ }
+ }
+
+ protected function prepareImport($tableName, array $fields) {
+ try {
+ if ($this->db->query("select count(*) as cnt from {$this->dbQuoteChar}{$tableName}{$this->dbQuoteChar}")->fetchObject()->cnt) {
+ throw new DBIPException("table {$tableName} is not empty");
+ }
+ $this->db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
+ $this->db->beginTransaction();
+ $q = $this->db->prepare("insert into {$this->dbQuoteChar}{$tableName}{$this->dbQuoteChar} (" . implode(",", $fields) . ",addr_type) values (" . implode(",", array_fill(0, count($fields), "?")) . ",?)");
+ return $q;
+ } catch (PDOException $e) {
+ throw new DBIPException("database error: {$e->getMessage()}");
+ }
+ }
+
+ protected function finalizeImport() {
+ try{
+ $this->db->commit();
+ }catch (Exception $e) {
+ throw new Exception("commit import record: {$e->getMessage()}");
+ }
+
+ }
+
+ protected function importRow($res, $row) {
+ return $res->execute($row);
+ }
+
+ protected function doLookup($tableName, $addrType, $addrStart) {
+ $q = $this->db->prepare("select * from {$this->dbQuoteChar}{$tableName}{$this->dbQuoteChar} where addr_type = ? and ip_start <= ? order by ip_start desc limit 1");
+ $q->execute(array($addrType, $addrStart));
+ return $q->fetchObject();
+ }
+
+ static private function addrType($addr) {
+ if (ip2long($addr) !== false) {
+ return "ipv4";
+ } else if (preg_match('/^[0-9a-fA-F:]+$/', $addr) && @inet_pton($addr)) {
+ return "ipv6";
+ }
+ throw new DBIPException("unknown address type for {$addr}");
+ }
+
+}
+
+/**
+ * DBIP MySQL class
+ *
+ * If you are using a MySQL database backend, please prefer the DBIP base class which uses the PDO mysql driver.
+ * This is only meant to be used on PHP installations where PDO is disabled and the old mysql_* interface is available.
+ */
+class DBIPMySQL extends DBIP {
+
+ private $db;
+
+ public function __construct($db) {
+ $this->db = $db;
+ }
+
+ protected function prepareImport($tableName, array $fields) {
+ $q = mysql_query("select count(*) as cnt from {$this->dbQuoteChar}{$tableName}{$this->dbQuoteChar}", $this->db);
+ $r = mysql_fetch_object($q);
+ mysql_free_result($q);
+ if ($r->cnt) {
+ throw new DBIPException("table {$tableName} is not empty");
+ }
+ return array($tableName, $fields);
+ }
+
+ protected function finalizeImport() {
+ }
+
+ protected function importRow($res, $row) {
+ $vals = array();
+ foreach ($row as $val) {
+ $vals[] = "'" . mysql_real_escape_string($val) . "'";
+ }
+ if (!mysql_query("insert into {$this->dbQuoteChar}{$res[0]}{$this->dbQuoteChar} (" . implode(",", $res[1]) . ",addr_type) values (" . implode(",", $vals) . ")", $this->db)) {
+ throw new DBIPException("database error: cannot insert row");
+ }
+ return true;
+ }
+
+ protected function doLookup($tableName, $addrType, $addrStart) {
+ $q = mysql_query("select * from {$this->dbQuoteChar}{$tableName}{$this->dbQuoteChar} where addr_type = '{$addrType}' and ip_start <= '" . mysql_real_escape_string($addrStart) . "' order by ip_start desc limit 1", $this->db);
+ $r = mysql_fetch_object($q);
+ mysql_free_result($q);
+ return $r;
+ }
+
+}
+
+/**
+ * DBIP MySQLI class
+ *
+ * If you are using a MySQL database backend, please prefer the DBIP base class which uses the PDO mysql driver.
+ * This is only meant to be used on PHP installations where PDO is disabled and the old mysqli_* interface is available.
+ */
+class DBIPMySQLI extends DBIP {
+
+ private $db;
+
+ public function __construct($db) {
+ $this->db = $db;
+ }
+
+ protected function prepareImport($tableName, array $fields) {
+ $q = mysqli_query($this->db, "select count(*) as cnt from {$this->dbQuoteChar}{$tableName}{$this->dbQuoteChar}");
+ $r = mysqli_fetch_object($q);
+ mysqli_free_result($q);
+ if ($r->cnt) {
+ throw new DBIPException("table {$tableName} is not empty");
+ }
+ return array($tableName, $fields);
+ }
+
+ protected function finalizeImport() {
+ }
+
+ protected function importRow($res, $row) {
+ $vals = array();
+ foreach ($row as $val) {
+ $vals[] = "'" . mysqli_real_escape_string($this->db, $val) . "'";
+ }
+ if (!mysqli_query($this->db, "insert into {$this->dbQuoteChar}{$res[0]}{$this->dbQuoteChar} (" . implode(",", $res[1]) . ",addr_type) values (" . implode(",", $vals) . ")")) {
+ throw new DBIPException("database error: cannot insert row");
+ }
+ return true;
+ }
+
+ protected function doLookup($tableName, $addrType, $addrStart) {
+ $q = mysqli_query($this->db, "select * from {$this->dbQuoteChar}{$tableName}{$this->dbQuoteChar} where addr_type = '{$addrType}' and ip_start <= '" . mysqli_real_escape_string($this->db, $addrStart) . "' order by ip_start desc limit 1");
+ $r = mysqli_fetch_object($q);
+ mysqli_free_result($q);
+ return $r;
+ }
+
+}
\ No newline at end of file
diff --git a/app/Services/dbip/import.php b/app/Services/dbip/import.php
new file mode 100755
index 00000000..d8255170
--- /dev/null
+++ b/app/Services/dbip/import.php
@@ -0,0 +1,96 @@
+#!/usr/bin/env php
+ [-d ] [-b ] [-t ] [-u ] [-p ]\n");
+}
+
+switch (strtolower($type)) {
+ case "country-lite": $dbtype = DBIP::TYPE_COUNTRY_LITE; break;
+ case "country-ipinfo": $dbtype = DBIP::TYPE_COUNTRY_IPINFO; break;
+ case "city-lite": $dbtype = DBIP::TYPE_CITY_LITE; break;
+ case "country": $dbtype = DBIP::TYPE_COUNTRY; break;
+ case "location": $dbtype = DBIP::TYPE_LOCATION; break;
+ case "isp": $dbtype = DBIP::TYPE_ISP; break;
+ case "full": $dbtype = DBIP::TYPE_FULL; break;
+ default: echo "invalid database type\n"; exit(1);
+}
+
+try {
+ // Connect to the database
+ $db = new PDO("mysql:{$host}=localhost;dbname={$dbname};charset=utf8mb4", $username, $password);
+ // Alternatively connect to MySQL using the old interface
+ // Comment the PDO statement above and uncomment the mysql_ calls
+ // below if your PHP installation doesn't support PDO :
+ // $db = mysql_connect("localhost", $username, $password);
+ // mysql_select_db($dbname, $db);
+
+ // Instanciate a new DBIP object with the database connection
+ $dbip = new DBIP($db); //DBIPMySQLI
+ // Alternatively instanciate a DBIP_MySQL object
+ // Comment the new statement above and uncomment below if your PHP
+ // installation doesn't support PDO :
+ // $dbip = new DBIPMySQL($db);
+
+ $nrecs = $dbip->importFromCsv($filename, $dbtype, $table, function($progress) {
+ echo "\r{$progress} ...";
+ });
+ echo "\rfinished importing " . number_format($nrecs) . " records\n";
+} catch (DBIPException $e) {
+ echo "error: {$e->getMessage()}\n";
+}
\ No newline at end of file
diff --git a/app/Services/dbip/lookup-example.php b/app/Services/dbip/lookup-example.php
new file mode 100755
index 00000000..4e6c07e0
--- /dev/null
+++ b/app/Services/dbip/lookup-example.php
@@ -0,0 +1,73 @@
+#!/usr/bin/env php
+\n");
+ }
+
+ // Connect to the database
+ $db = new PDO("mysql:{$host}=localhost;dbname={$dbname};charset=utf8mb4", $username, $password);
+
+ // Alternatively connect to MySQL using the old interface
+ // Comment the PDO statement above and uncomment the mysql_ calls
+ // below if your PHP installation doesn't support PDO :
+ // $db = mysql_connect("localhost", "root", "");
+ // mysql_select_db("test", $db);
+
+ // Instanciate a new DBIP object with the database connection
+ $dbip = new DBIP($db);
+
+ // Alternatively instanciate a DBIP_MySQL object
+ // Comment the new statement above and uncomment below if your PHP
+ // installation doesn't support PDO :
+ // $dbip = new DBIPMySQL($db);
+
+ // Lookup an IP address
+ $inf = $dbip->lookup($argv[1], $table);
+ // Show the associated country
+ echo "t:".$table." country = " . $inf->country . "\n";
+
+ $inf = $dbip->lookup($argv[1], $table_2);
+ // Show the associated country
+ echo "t:".$table_2." country = " . $inf->country . "\n";
+
+} catch (DBIPException $e) {
+ echo "error: {$e->getMessage()}\n";
+ exit(1);
+}
\ No newline at end of file
diff --git a/app/User.php b/app/User.php
index cfb178fd..b9bac030 100755
--- a/app/User.php
+++ b/app/User.php
@@ -115,6 +115,9 @@ use Laravel\Passport\HasApiTokens;
* @property-read int|null $tokens_count
* @property array|null $payment_methods
* @method static \Illuminate\Database\Eloquent\Builder|\App\User wherePaymentMethods($value)
+ * @property int|null $pre_sponsor
+ * @property-read User|null $user_pre_sponsor
+ * @method static \Illuminate\Database\Eloquent\Builder|User wherePreSponsor($value)
* @mixin \Eloquent
*/
class User extends Authenticatable
@@ -164,6 +167,10 @@ class User extends Authenticatable
return $this->belongsTo('App\User', 'm_sponsor');
}
+ public function user_pre_sponsor(){
+ return $this->belongsTo('App\User', 'pre_sponsor');
+ }
+
public function payment_order_product(){
return $this->belongsTo('App\Models\Product', 'payment_order_id');
}
@@ -201,6 +208,11 @@ class User extends Authenticatable
return $this->hasMany('App\Models\ShoppingUser', 'member_id', 'id');
}
+ public function getLocale(){
+ return $this->lang ? $this->lang : \App::getLocale();
+ }
+
+
public function getMUserSponsor(){
if($this->user_sponsor && $this->user_sponsor->account){
return $this->user_sponsor->account->first_name." ".$this->user_sponsor->account->last_name." | ".$this->user_sponsor->email;
@@ -228,10 +240,11 @@ class User extends Authenticatable
return true;
}
+
/**
* @return bool
*/
- public function isAdmin()
+ public function isVIP()
{
if($this->admin >= 1){
return true;
@@ -239,10 +252,11 @@ class User extends Authenticatable
return false;
}
+
/**
* @return bool
*/
- public function isSuperAdmin()
+ public function isAdmin()
{
if($this->admin >= 2){
return true;
@@ -253,7 +267,7 @@ class User extends Authenticatable
/**
* @return bool
*/
- public function isSySAdmin()
+ public function isSuperAdmin()
{
if($this->admin >= 3){
return true;
@@ -261,6 +275,17 @@ class User extends Authenticatable
return false;
}
+ /**
+ * @return bool
+ */
+ public function isSySAdmin()
+ {
+ if($this->admin >= 4){
+ return true;
+ }
+ return false;
+ }
+
public function isUserHasApi()
{
@@ -275,7 +300,7 @@ class User extends Authenticatable
*/
public function isApiUser()
{
- if($this->admin >= 4){
+ if($this->admin >= 5){
return true;
}
return false;
@@ -301,10 +326,9 @@ class User extends Authenticatable
return false;
}
-
-
public function isAboOption(){
- return ($this->abo_options && $this->account && $this->account->payment_data) ? true : false;
+ return false;
+ // Abo Option deaktiviert ($this->abo_options && $this->account && $this->account->payment_data) ? true : false;
}
public function isActive(){
@@ -470,12 +494,15 @@ class User extends Authenticatable
*/
public function sendPasswordResetNotification($token)
{
- Mail::to($this->email)->send(new MailResetPassword($token, $this));
- // $this->notify(new ResetPasswordNotification($token));
+ //$bcc[] = "kevin.adametz@me.com"; //config('app.checkout_mail');
+ //Mail::to($this->email)->bcc($bcc)->locale(\App::getLocale())->send(new MailResetPassword($token, $this));
+ Mail::to($this->email)->locale(\App::getLocale())->send(new MailResetPassword($token, $this));
+ //$this->notify(new ResetPasswordNotification($token));
}
public function getUserSalesVolumeBy($month, $year, $key)
{
+
//NOTE check ist, cant change month year !
if($this->userSalesVolume === false){
$this->userSalesVolume = $this->getUserSalesVolume($month, $year, 'first');
diff --git a/bootstrap/cache/packages.php b/bootstrap/cache/packages.php
index 301a4f18..85da2c47 100755
--- a/bootstrap/cache/packages.php
+++ b/bootstrap/cache/packages.php
@@ -43,17 +43,6 @@
0 => 'Cviebrock\\EloquentSluggable\\ServiceProvider',
),
),
- 'digital-bird/shoppingcart' =>
- array (
- 'providers' =>
- array (
- 0 => 'Gloudemans\\Shoppingcart\\ShoppingcartServiceProvider',
- ),
- 'aliases' =>
- array (
- 'Cart' => 'Gloudemans\\Shoppingcart\\Facades\\Cart',
- ),
- ),
'facade/ignition' =>
array (
'providers' =>
@@ -101,6 +90,14 @@
'Date' => 'Jenssegers\\Date\\Date',
),
),
+ 'joedixon/laravel-translation' =>
+ array (
+ 'providers' =>
+ array (
+ 0 => 'JoeDixon\\Translation\\TranslationServiceProvider',
+ 1 => 'JoeDixon\\Translation\\TranslationBindingsServiceProvider',
+ ),
+ ),
'laracasts/flash' =>
array (
'providers' =>
diff --git a/bootstrap/cache/services.php b/bootstrap/cache/services.php
index 7cf9e5b9..2a982b87 100755
--- a/bootstrap/cache/services.php
+++ b/bootstrap/cache/services.php
@@ -28,36 +28,37 @@
24 => 'Barryvdh\\DomPDF\\ServiceProvider',
25 => 'Barryvdh\\LaravelIdeHelper\\IdeHelperServiceProvider',
26 => 'Cviebrock\\EloquentSluggable\\ServiceProvider',
- 27 => 'Gloudemans\\Shoppingcart\\ShoppingcartServiceProvider',
- 28 => 'Facade\\Ignition\\IgnitionServiceProvider',
- 29 => 'Fideloper\\Proxy\\TrustedProxyServiceProvider',
- 30 => 'Fruitcake\\Cors\\CorsServiceProvider',
- 31 => 'Intervention\\Image\\ImageServiceProvider',
- 32 => 'Jenssegers\\Date\\DateServiceProvider',
- 33 => 'Laracasts\\Flash\\FlashServiceProvider',
- 34 => 'Laravel\\Passport\\PassportServiceProvider',
- 35 => 'Laravel\\Sail\\SailServiceProvider',
- 36 => 'Laravel\\Tinker\\TinkerServiceProvider',
- 37 => 'Laravel\\Ui\\UiServiceProvider',
- 38 => 'Collective\\Html\\HtmlServiceProvider',
- 39 => 'Maatwebsite\\Excel\\ExcelServiceProvider',
- 40 => 'Carbon\\Laravel\\ServiceProvider',
- 41 => 'NunoMaduro\\Collision\\Adapters\\Laravel\\CollisionServiceProvider',
- 42 => 'Reliese\\Coders\\CodersServiceProvider',
- 43 => 'Yajra\\DataTables\\DataTablesServiceProvider',
- 44 => 'Reliese\\Coders\\CodersServiceProvider',
- 45 => 'Laravel\\Tinker\\TinkerServiceProvider',
- 46 => 'App\\Providers\\AppServiceProvider',
- 47 => 'App\\Providers\\AuthServiceProvider',
- 48 => 'App\\Providers\\EventServiceProvider',
- 49 => 'App\\Providers\\RouteServiceProvider',
- 50 => 'Barryvdh\\LaravelIdeHelper\\IdeHelperServiceProvider',
- 51 => 'Jenssegers\\Date\\DateServiceProvider',
- 52 => 'Collective\\Html\\HtmlServiceProvider',
- 53 => 'Intervention\\Image\\ImageServiceProvider',
- 54 => 'Maatwebsite\\Excel\\ExcelServiceProvider',
- 55 => 'Yajra\\DataTables\\DataTablesServiceProvider',
- 56 => 'App\\Providers\\YardServiceProvider',
+ 27 => 'Facade\\Ignition\\IgnitionServiceProvider',
+ 28 => 'Fideloper\\Proxy\\TrustedProxyServiceProvider',
+ 29 => 'Fruitcake\\Cors\\CorsServiceProvider',
+ 30 => 'Intervention\\Image\\ImageServiceProvider',
+ 31 => 'Jenssegers\\Date\\DateServiceProvider',
+ 32 => 'JoeDixon\\Translation\\TranslationServiceProvider',
+ 33 => 'JoeDixon\\Translation\\TranslationBindingsServiceProvider',
+ 34 => 'Laracasts\\Flash\\FlashServiceProvider',
+ 35 => 'Laravel\\Passport\\PassportServiceProvider',
+ 36 => 'Laravel\\Sail\\SailServiceProvider',
+ 37 => 'Laravel\\Tinker\\TinkerServiceProvider',
+ 38 => 'Laravel\\Ui\\UiServiceProvider',
+ 39 => 'Collective\\Html\\HtmlServiceProvider',
+ 40 => 'Maatwebsite\\Excel\\ExcelServiceProvider',
+ 41 => 'Carbon\\Laravel\\ServiceProvider',
+ 42 => 'NunoMaduro\\Collision\\Adapters\\Laravel\\CollisionServiceProvider',
+ 43 => 'Reliese\\Coders\\CodersServiceProvider',
+ 44 => 'Yajra\\DataTables\\DataTablesServiceProvider',
+ 45 => 'Reliese\\Coders\\CodersServiceProvider',
+ 46 => 'Laravel\\Tinker\\TinkerServiceProvider',
+ 47 => 'App\\Providers\\AppServiceProvider',
+ 48 => 'App\\Providers\\AuthServiceProvider',
+ 49 => 'App\\Providers\\EventServiceProvider',
+ 50 => 'App\\Providers\\RouteServiceProvider',
+ 51 => 'Barryvdh\\LaravelIdeHelper\\IdeHelperServiceProvider',
+ 52 => 'Jenssegers\\Date\\DateServiceProvider',
+ 53 => 'Collective\\Html\\HtmlServiceProvider',
+ 54 => 'Intervention\\Image\\ImageServiceProvider',
+ 55 => 'Maatwebsite\\Excel\\ExcelServiceProvider',
+ 56 => 'Yajra\\DataTables\\DataTablesServiceProvider',
+ 57 => 'App\\Providers\\YardServiceProvider',
),
'eager' =>
array (
@@ -75,12 +76,12 @@
11 => 'Barryvdh\\Debugbar\\ServiceProvider',
12 => 'Barryvdh\\DomPDF\\ServiceProvider',
13 => 'Cviebrock\\EloquentSluggable\\ServiceProvider',
- 14 => 'Gloudemans\\Shoppingcart\\ShoppingcartServiceProvider',
- 15 => 'Facade\\Ignition\\IgnitionServiceProvider',
- 16 => 'Fideloper\\Proxy\\TrustedProxyServiceProvider',
- 17 => 'Fruitcake\\Cors\\CorsServiceProvider',
- 18 => 'Intervention\\Image\\ImageServiceProvider',
- 19 => 'Jenssegers\\Date\\DateServiceProvider',
+ 14 => 'Facade\\Ignition\\IgnitionServiceProvider',
+ 15 => 'Fideloper\\Proxy\\TrustedProxyServiceProvider',
+ 16 => 'Fruitcake\\Cors\\CorsServiceProvider',
+ 17 => 'Intervention\\Image\\ImageServiceProvider',
+ 18 => 'Jenssegers\\Date\\DateServiceProvider',
+ 19 => 'JoeDixon\\Translation\\TranslationServiceProvider',
20 => 'Laracasts\\Flash\\FlashServiceProvider',
21 => 'Laravel\\Passport\\PassportServiceProvider',
22 => 'Laravel\\Ui\\UiServiceProvider',
@@ -218,8 +219,8 @@
'redis.connection' => 'Illuminate\\Redis\\RedisServiceProvider',
'auth.password' => 'Illuminate\\Auth\\Passwords\\PasswordResetServiceProvider',
'auth.password.broker' => 'Illuminate\\Auth\\Passwords\\PasswordResetServiceProvider',
- 'translator' => 'Illuminate\\Translation\\TranslationServiceProvider',
- 'translation.loader' => 'Illuminate\\Translation\\TranslationServiceProvider',
+ 'translator' => 'JoeDixon\\Translation\\TranslationBindingsServiceProvider',
+ 'translation.loader' => 'JoeDixon\\Translation\\TranslationBindingsServiceProvider',
'validator' => 'Illuminate\\Validation\\ValidationServiceProvider',
'validation.presence' => 'Illuminate\\Validation\\ValidationServiceProvider',
'command.ide-helper.generate' => 'Barryvdh\\LaravelIdeHelper\\IdeHelperServiceProvider',
@@ -273,6 +274,9 @@
'Barryvdh\\LaravelIdeHelper\\IdeHelperServiceProvider' =>
array (
),
+ 'JoeDixon\\Translation\\TranslationBindingsServiceProvider' =>
+ array (
+ ),
'Laravel\\Sail\\SailServiceProvider' =>
array (
),
diff --git a/composer.json b/composer.json
index 2bf67dc5..759e3ba0 100755
--- a/composer.json
+++ b/composer.json
@@ -5,17 +5,18 @@
"license": "MIT",
"type": "project",
"require": {
- "php": "^7.3|^8.0",
+ "php": "^7.4|^8.0",
+ "cocur/slugify": "4.4.0",
"askedio/laravel5-profanity-filter": "*",
"barryvdh/laravel-dompdf": "*",
"cviebrock/eloquent-sluggable": "*",
- "digital-bird/shoppingcart": "^5.1",
"doctrine/dbal": "*",
"fideloper/proxy": "^4.4",
"fruitcake/laravel-cors": "^2.0",
"guzzlehttp/guzzle": "^7.0.1",
"intervention/image": "*",
"jenssegers/date": "*",
+ "joedixon/laravel-translation": "^1.1",
"laracasts/flash": "*",
"laravel/framework": "^8.12",
"laravel/helpers": "*",
@@ -28,6 +29,7 @@
"rguedes/pdfmerger": "^1.0",
"setasign/fpdf": "*",
"setasign/fpdi": "*",
+ "vitalybaev/google-merchant-feed": "^2.5",
"yajra/laravel-datatables-oracle": "*"
},
"require-dev": {
@@ -40,6 +42,9 @@
"barryvdh/laravel-debugbar": "*",
"barryvdh/laravel-ide-helper": "*"
},
+ "conflict": {
+ "cocur/slugify": "4.5.0"
+ },
"config": {
"optimize-autoloader": true,
"preferred-install": "dist",
@@ -56,6 +61,7 @@
],
"psr-4": {
"App\\": "app/",
+ "Gloudemans\\Shoppingcart\\": "packages/digital-bird/shoppingcart/src",
"Database\\Factories\\": "database/factories/",
"Database\\Seeders\\": "database/seeders/"
}
diff --git a/composer.lock b/composer.lock
index c6d046b0..c690594f 100755
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "4ddc6a9e1a558cb4029b4c2b401dfb93",
+ "content-hash": "ad50933786d7ea4e9c73f2aed681e366",
"packages": [
{
"name": "askedio/laravel5-profanity-filter",
@@ -251,16 +251,16 @@
},
{
"name": "cocur/slugify",
- "version": "v4.3.0",
+ "version": "v4.4.0",
"source": {
"type": "git",
"url": "https://github.com/cocur/slugify.git",
- "reference": "652234ef5f1be844a2ae1c36ad1b4c88b05160f9"
+ "reference": "4c6ed14a087ca061b220ffda640c07644946e2a0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/cocur/slugify/zipball/652234ef5f1be844a2ae1c36ad1b4c88b05160f9",
- "reference": "652234ef5f1be844a2ae1c36ad1b4c88b05160f9",
+ "url": "https://api.github.com/repos/cocur/slugify/zipball/4c6ed14a087ca061b220ffda640c07644946e2a0",
+ "reference": "4c6ed14a087ca061b220ffda640c07644946e2a0",
"shasum": ""
},
"require": {
@@ -319,22 +319,22 @@
],
"support": {
"issues": "https://github.com/cocur/slugify/issues",
- "source": "https://github.com/cocur/slugify/tree/v4.3.0"
+ "source": "https://github.com/cocur/slugify/tree/v4.4.0"
},
- "time": "2022-12-07T19:48:48+00:00"
+ "time": "2023-08-05T09:42:11+00:00"
},
{
"name": "composer/semver",
- "version": "3.3.2",
+ "version": "3.4.0",
"source": {
"type": "git",
"url": "https://github.com/composer/semver.git",
- "reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9"
+ "reference": "35e8d0af4486141bc745f23a29cc2091eb624a32"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/composer/semver/zipball/3953f23262f2bff1919fc82183ad9acb13ff62c9",
- "reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9",
+ "url": "https://api.github.com/repos/composer/semver/zipball/35e8d0af4486141bc745f23a29cc2091eb624a32",
+ "reference": "35e8d0af4486141bc745f23a29cc2091eb624a32",
"shasum": ""
},
"require": {
@@ -384,9 +384,9 @@
"versioning"
],
"support": {
- "irc": "irc://irc.freenode.org/composer",
+ "irc": "ircs://irc.libera.chat:6697/composer",
"issues": "https://github.com/composer/semver/issues",
- "source": "https://github.com/composer/semver/tree/3.3.2"
+ "source": "https://github.com/composer/semver/tree/3.4.0"
},
"funding": [
{
@@ -402,7 +402,7 @@
"type": "tidelift"
}
],
- "time": "2022-04-01T19:23:25+00:00"
+ "time": "2023-08-31T09:50:34+00:00"
},
{
"name": "cviebrock/eloquent-sluggable",
@@ -479,16 +479,16 @@
},
{
"name": "defuse/php-encryption",
- "version": "v2.3.1",
+ "version": "v2.4.0",
"source": {
"type": "git",
"url": "https://github.com/defuse/php-encryption.git",
- "reference": "77880488b9954b7884c25555c2a0ea9e7053f9d2"
+ "reference": "f53396c2d34225064647a05ca76c1da9d99e5828"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/defuse/php-encryption/zipball/77880488b9954b7884c25555c2a0ea9e7053f9d2",
- "reference": "77880488b9954b7884c25555c2a0ea9e7053f9d2",
+ "url": "https://api.github.com/repos/defuse/php-encryption/zipball/f53396c2d34225064647a05ca76c1da9d99e5828",
+ "reference": "f53396c2d34225064647a05ca76c1da9d99e5828",
"shasum": ""
},
"require": {
@@ -497,7 +497,8 @@
"php": ">=5.6.0"
},
"require-dev": {
- "phpunit/phpunit": "^4|^5|^6|^7|^8|^9"
+ "phpunit/phpunit": "^5|^6|^7|^8|^9|^10",
+ "yoast/phpunit-polyfills": "^2.0.0"
},
"bin": [
"bin/generate-defuse-key"
@@ -539,72 +540,9 @@
],
"support": {
"issues": "https://github.com/defuse/php-encryption/issues",
- "source": "https://github.com/defuse/php-encryption/tree/v2.3.1"
+ "source": "https://github.com/defuse/php-encryption/tree/v2.4.0"
},
- "time": "2021-04-09T23:57:26+00:00"
- },
- {
- "name": "digital-bird/shoppingcart",
- "version": "5.1.4",
- "source": {
- "type": "git",
- "url": "https://github.com/digital-bird/LaravelShoppingcart.git",
- "reference": "9390c78b2d2146672c2d451ab1f929d09da46a3e"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/digital-bird/LaravelShoppingcart/zipball/9390c78b2d2146672c2d451ab1f929d09da46a3e",
- "reference": "9390c78b2d2146672c2d451ab1f929d09da46a3e",
- "shasum": ""
- },
- "require": {
- "illuminate/events": "5.1.*|5.2.*|5.3.*|5.4.*|5.5.*|5.6.*|5.7.*|5.8.*|6.*|7.*|8.*|9.*|10.*",
- "illuminate/session": "5.1.*|5.2.*|5.3.*|5.4.*|5.5.*|5.6.*|5.7.*|5.8.*|6.*|7.*|8.*|9.*|10.*",
- "illuminate/support": "5.1.*|5.2.*|5.3.*|5.4.*|5.5.*|5.6.*|5.7.*|5.8.*|6.*|7.*|8.*|9.*|10.*"
- },
- "require-dev": {
- "mockery/mockery": "~0.9.0",
- "orchestra/testbench": "~3.1",
- "phpunit/phpunit": "~5.0|~6.0|~7.0|~8.0|~9.0|~10.0"
- },
- "suggest": {
- "gloudemans/notify": "Simple flash notifications for Laravel"
- },
- "type": "library",
- "extra": {
- "laravel": {
- "providers": [
- "Gloudemans\\Shoppingcart\\ShoppingcartServiceProvider"
- ],
- "aliases": {
- "Cart": "Gloudemans\\Shoppingcart\\Facades\\Cart"
- }
- }
- },
- "autoload": {
- "psr-4": {
- "Gloudemans\\Shoppingcart\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Rob Gloudemans",
- "email": "info@robgloudemans.nl"
- }
- ],
- "description": "Laravel Shoppingcart",
- "keywords": [
- "laravel",
- "shoppingcart"
- ],
- "support": {
- "source": "https://github.com/digital-bird/LaravelShoppingcart/tree/5.1.4"
- },
- "time": "2023-01-17T05:43:33+00:00"
+ "time": "2023-06-19T06:10:36+00:00"
},
{
"name": "doctrine/cache",
@@ -812,25 +750,29 @@
},
{
"name": "doctrine/deprecations",
- "version": "v1.0.0",
+ "version": "v1.1.1",
"source": {
"type": "git",
"url": "https://github.com/doctrine/deprecations.git",
- "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de"
+ "reference": "612a3ee5ab0d5dd97b7cf3874a6efe24325efac3"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/doctrine/deprecations/zipball/0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de",
- "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de",
+ "url": "https://api.github.com/repos/doctrine/deprecations/zipball/612a3ee5ab0d5dd97b7cf3874a6efe24325efac3",
+ "reference": "612a3ee5ab0d5dd97b7cf3874a6efe24325efac3",
"shasum": ""
},
"require": {
- "php": "^7.1|^8.0"
+ "php": "^7.1 || ^8.0"
},
"require-dev": {
"doctrine/coding-standard": "^9",
- "phpunit/phpunit": "^7.5|^8.5|^9.5",
- "psr/log": "^1|^2|^3"
+ "phpstan/phpstan": "1.4.10 || 1.10.15",
+ "phpstan/phpstan-phpunit": "^1.0",
+ "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
+ "psalm/plugin-phpunit": "0.18.4",
+ "psr/log": "^1 || ^2 || ^3",
+ "vimeo/psalm": "4.30.0 || 5.12.0"
},
"suggest": {
"psr/log": "Allows logging deprecations via PSR-3 logger implementation"
@@ -849,9 +791,9 @@
"homepage": "https://www.doctrine-project.org/",
"support": {
"issues": "https://github.com/doctrine/deprecations/issues",
- "source": "https://github.com/doctrine/deprecations/tree/v1.0.0"
+ "source": "https://github.com/doctrine/deprecations/tree/v1.1.1"
},
- "time": "2022-05-02T15:47:09+00:00"
+ "time": "2023-06-03T09:27:29+00:00"
},
{
"name": "doctrine/event-manager",
@@ -947,28 +889,28 @@
},
{
"name": "doctrine/inflector",
- "version": "2.0.6",
+ "version": "2.0.8",
"source": {
"type": "git",
"url": "https://github.com/doctrine/inflector.git",
- "reference": "d9d313a36c872fd6ee06d9a6cbcf713eaa40f024"
+ "reference": "f9301a5b2fb1216b2b08f02ba04dc45423db6bff"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/doctrine/inflector/zipball/d9d313a36c872fd6ee06d9a6cbcf713eaa40f024",
- "reference": "d9d313a36c872fd6ee06d9a6cbcf713eaa40f024",
+ "url": "https://api.github.com/repos/doctrine/inflector/zipball/f9301a5b2fb1216b2b08f02ba04dc45423db6bff",
+ "reference": "f9301a5b2fb1216b2b08f02ba04dc45423db6bff",
"shasum": ""
},
"require": {
"php": "^7.2 || ^8.0"
},
"require-dev": {
- "doctrine/coding-standard": "^10",
+ "doctrine/coding-standard": "^11.0",
"phpstan/phpstan": "^1.8",
"phpstan/phpstan-phpunit": "^1.1",
"phpstan/phpstan-strict-rules": "^1.3",
"phpunit/phpunit": "^8.5 || ^9.5",
- "vimeo/psalm": "^4.25"
+ "vimeo/psalm": "^4.25 || ^5.4"
},
"type": "library",
"autoload": {
@@ -1018,7 +960,7 @@
],
"support": {
"issues": "https://github.com/doctrine/inflector/issues",
- "source": "https://github.com/doctrine/inflector/tree/2.0.6"
+ "source": "https://github.com/doctrine/inflector/tree/2.0.8"
},
"funding": [
{
@@ -1034,7 +976,7 @@
"type": "tidelift"
}
],
- "time": "2022-10-20T09:10:12+00:00"
+ "time": "2023-06-16T13:40:37+00:00"
},
{
"name": "doctrine/lexer",
@@ -1176,16 +1118,16 @@
},
{
"name": "dragonmantank/cron-expression",
- "version": "v3.3.2",
+ "version": "v3.3.3",
"source": {
"type": "git",
"url": "https://github.com/dragonmantank/cron-expression.git",
- "reference": "782ca5968ab8b954773518e9e49a6f892a34b2a8"
+ "reference": "adfb1f505deb6384dc8b39804c5065dd3c8c8c0a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/782ca5968ab8b954773518e9e49a6f892a34b2a8",
- "reference": "782ca5968ab8b954773518e9e49a6f892a34b2a8",
+ "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/adfb1f505deb6384dc8b39804c5065dd3c8c8c0a",
+ "reference": "adfb1f505deb6384dc8b39804c5065dd3c8c8c0a",
"shasum": ""
},
"require": {
@@ -1225,7 +1167,7 @@
],
"support": {
"issues": "https://github.com/dragonmantank/cron-expression/issues",
- "source": "https://github.com/dragonmantank/cron-expression/tree/v3.3.2"
+ "source": "https://github.com/dragonmantank/cron-expression/tree/v3.3.3"
},
"funding": [
{
@@ -1233,7 +1175,7 @@
"type": "github"
}
],
- "time": "2022-09-10T18:51:20+00:00"
+ "time": "2023-08-10T19:36:49+00:00"
},
{
"name": "egulias/email-validator",
@@ -1629,22 +1571,22 @@
},
{
"name": "guzzlehttp/guzzle",
- "version": "7.5.0",
+ "version": "7.8.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle.git",
- "reference": "b50a2a1251152e43f6a37f0fa053e730a67d25ba"
+ "reference": "1110f66a6530a40fe7aea0378fe608ee2b2248f9"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/guzzle/guzzle/zipball/b50a2a1251152e43f6a37f0fa053e730a67d25ba",
- "reference": "b50a2a1251152e43f6a37f0fa053e730a67d25ba",
+ "url": "https://api.github.com/repos/guzzle/guzzle/zipball/1110f66a6530a40fe7aea0378fe608ee2b2248f9",
+ "reference": "1110f66a6530a40fe7aea0378fe608ee2b2248f9",
"shasum": ""
},
"require": {
"ext-json": "*",
- "guzzlehttp/promises": "^1.5",
- "guzzlehttp/psr7": "^1.9 || ^2.4",
+ "guzzlehttp/promises": "^1.5.3 || ^2.0.1",
+ "guzzlehttp/psr7": "^1.9.1 || ^2.5.1",
"php": "^7.2.5 || ^8.0",
"psr/http-client": "^1.0",
"symfony/deprecation-contracts": "^2.2 || ^3.0"
@@ -1655,7 +1597,8 @@
"require-dev": {
"bamarni/composer-bin-plugin": "^1.8.1",
"ext-curl": "*",
- "php-http/client-integration-tests": "^3.0",
+ "php-http/client-integration-tests": "dev-master#2c025848417c1135031fdf9c728ee53d0a7ceaee as 3.0.999",
+ "php-http/message-factory": "^1.1",
"phpunit/phpunit": "^8.5.29 || ^9.5.23",
"psr/log": "^1.1 || ^2.0 || ^3.0"
},
@@ -1669,9 +1612,6 @@
"bamarni-bin": {
"bin-links": true,
"forward-command": false
- },
- "branch-alias": {
- "dev-master": "7.5-dev"
}
},
"autoload": {
@@ -1737,7 +1677,7 @@
],
"support": {
"issues": "https://github.com/guzzle/guzzle/issues",
- "source": "https://github.com/guzzle/guzzle/tree/7.5.0"
+ "source": "https://github.com/guzzle/guzzle/tree/7.8.0"
},
"funding": [
{
@@ -1753,38 +1693,37 @@
"type": "tidelift"
}
],
- "time": "2022-08-28T15:39:27+00:00"
+ "time": "2023-08-27T10:20:53+00:00"
},
{
"name": "guzzlehttp/promises",
- "version": "1.5.2",
+ "version": "2.0.1",
"source": {
"type": "git",
"url": "https://github.com/guzzle/promises.git",
- "reference": "b94b2807d85443f9719887892882d0329d1e2598"
+ "reference": "111166291a0f8130081195ac4556a5587d7f1b5d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/guzzle/promises/zipball/b94b2807d85443f9719887892882d0329d1e2598",
- "reference": "b94b2807d85443f9719887892882d0329d1e2598",
+ "url": "https://api.github.com/repos/guzzle/promises/zipball/111166291a0f8130081195ac4556a5587d7f1b5d",
+ "reference": "111166291a0f8130081195ac4556a5587d7f1b5d",
"shasum": ""
},
"require": {
- "php": ">=5.5"
+ "php": "^7.2.5 || ^8.0"
},
"require-dev": {
- "symfony/phpunit-bridge": "^4.4 || ^5.1"
+ "bamarni/composer-bin-plugin": "^1.8.1",
+ "phpunit/phpunit": "^8.5.29 || ^9.5.23"
},
"type": "library",
"extra": {
- "branch-alias": {
- "dev-master": "1.5-dev"
+ "bamarni-bin": {
+ "bin-links": true,
+ "forward-command": false
}
},
"autoload": {
- "files": [
- "src/functions_include.php"
- ],
"psr-4": {
"GuzzleHttp\\Promise\\": "src/"
}
@@ -1821,7 +1760,7 @@
],
"support": {
"issues": "https://github.com/guzzle/promises/issues",
- "source": "https://github.com/guzzle/promises/tree/1.5.2"
+ "source": "https://github.com/guzzle/promises/tree/2.0.1"
},
"funding": [
{
@@ -1837,26 +1776,26 @@
"type": "tidelift"
}
],
- "time": "2022-08-28T14:55:35+00:00"
+ "time": "2023-08-03T15:11:55+00:00"
},
{
"name": "guzzlehttp/psr7",
- "version": "2.4.4",
+ "version": "2.6.1",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
- "reference": "3cf1b6d4f0c820a2cf8bcaec39fc698f3443b5cf"
+ "reference": "be45764272e8873c72dbe3d2edcfdfcc3bc9f727"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/guzzle/psr7/zipball/3cf1b6d4f0c820a2cf8bcaec39fc698f3443b5cf",
- "reference": "3cf1b6d4f0c820a2cf8bcaec39fc698f3443b5cf",
+ "url": "https://api.github.com/repos/guzzle/psr7/zipball/be45764272e8873c72dbe3d2edcfdfcc3bc9f727",
+ "reference": "be45764272e8873c72dbe3d2edcfdfcc3bc9f727",
"shasum": ""
},
"require": {
"php": "^7.2.5 || ^8.0",
"psr/http-factory": "^1.0",
- "psr/http-message": "^1.0",
+ "psr/http-message": "^1.1 || ^2.0",
"ralouphie/getallheaders": "^3.0"
},
"provide": {
@@ -1876,9 +1815,6 @@
"bamarni-bin": {
"bin-links": true,
"forward-command": false
- },
- "branch-alias": {
- "dev-master": "2.4-dev"
}
},
"autoload": {
@@ -1940,7 +1876,7 @@
],
"support": {
"issues": "https://github.com/guzzle/psr7/issues",
- "source": "https://github.com/guzzle/psr7/tree/2.4.4"
+ "source": "https://github.com/guzzle/psr7/tree/2.6.1"
},
"funding": [
{
@@ -1956,7 +1892,7 @@
"type": "tidelift"
}
],
- "time": "2023-03-09T13:19:02+00:00"
+ "time": "2023-08-27T10:13:57+00:00"
},
{
"name": "intervention/image",
@@ -2119,6 +2055,56 @@
],
"time": "2020-04-28T06:35:54+00:00"
},
+ {
+ "name": "joedixon/laravel-translation",
+ "version": "v1.1.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/joedixon/laravel-translation.git",
+ "reference": "4a467398bae73cd16522d523b557e96f3455b9d2"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/joedixon/laravel-translation/zipball/4a467398bae73cd16522d523b557e96f3455b9d2",
+ "reference": "4a467398bae73cd16522d523b557e96f3455b9d2",
+ "shasum": ""
+ },
+ "require-dev": {
+ "mockery/mockery": "^1.0.0",
+ "orchestra/testbench": "^4.0",
+ "phpunit/phpunit": "^8.0"
+ },
+ "type": "library",
+ "extra": {
+ "laravel": {
+ "providers": [
+ "JoeDixon\\Translation\\TranslationServiceProvider",
+ "JoeDixon\\Translation\\TranslationBindingsServiceProvider"
+ ]
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "JoeDixon\\Translation\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Joe Dixon",
+ "email": "hello@joedixon.co.uk"
+ }
+ ],
+ "description": "A tool for managing all of your Laravel translations",
+ "support": {
+ "issues": "https://github.com/joedixon/laravel-translation/issues",
+ "source": "https://github.com/joedixon/laravel-translation/tree/master"
+ },
+ "time": "2020-04-13T20:06:24+00:00"
+ },
{
"name": "laracasts/flash",
"version": "3.2.2",
@@ -2484,16 +2470,16 @@
},
{
"name": "laravel/serializable-closure",
- "version": "v1.3.0",
+ "version": "v1.3.1",
"source": {
"type": "git",
"url": "https://github.com/laravel/serializable-closure.git",
- "reference": "f23fe9d4e95255dacee1bf3525e0810d1a1b0f37"
+ "reference": "e5a3057a5591e1cfe8183034b0203921abe2c902"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/f23fe9d4e95255dacee1bf3525e0810d1a1b0f37",
- "reference": "f23fe9d4e95255dacee1bf3525e0810d1a1b0f37",
+ "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/e5a3057a5591e1cfe8183034b0203921abe2c902",
+ "reference": "e5a3057a5591e1cfe8183034b0203921abe2c902",
"shasum": ""
},
"require": {
@@ -2540,20 +2526,20 @@
"issues": "https://github.com/laravel/serializable-closure/issues",
"source": "https://github.com/laravel/serializable-closure"
},
- "time": "2023-01-30T18:31:20+00:00"
+ "time": "2023-07-14T13:56:28+00:00"
},
{
"name": "laravel/tinker",
- "version": "v2.8.1",
+ "version": "v2.8.2",
"source": {
"type": "git",
"url": "https://github.com/laravel/tinker.git",
- "reference": "04a2d3bd0d650c0764f70bf49d1ee39393e4eb10"
+ "reference": "b936d415b252b499e8c3b1f795cd4fc20f57e1f3"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/tinker/zipball/04a2d3bd0d650c0764f70bf49d1ee39393e4eb10",
- "reference": "04a2d3bd0d650c0764f70bf49d1ee39393e4eb10",
+ "url": "https://api.github.com/repos/laravel/tinker/zipball/b936d415b252b499e8c3b1f795cd4fc20f57e1f3",
+ "reference": "b936d415b252b499e8c3b1f795cd4fc20f57e1f3",
"shasum": ""
},
"require": {
@@ -2566,6 +2552,7 @@
},
"require-dev": {
"mockery/mockery": "~1.3.3|^1.4.2",
+ "phpstan/phpstan": "^1.10",
"phpunit/phpunit": "^8.5.8|^9.3.3"
},
"suggest": {
@@ -2606,9 +2593,9 @@
],
"support": {
"issues": "https://github.com/laravel/tinker/issues",
- "source": "https://github.com/laravel/tinker/tree/v2.8.1"
+ "source": "https://github.com/laravel/tinker/tree/v2.8.2"
},
- "time": "2023-02-15T16:40:09+00:00"
+ "time": "2023-08-15T14:27:00+00:00"
},
{
"name": "laravel/ui",
@@ -2673,16 +2660,16 @@
},
{
"name": "laravelcollective/html",
- "version": "v6.4.0",
+ "version": "v6.4.1",
"source": {
"type": "git",
"url": "https://github.com/LaravelCollective/html.git",
- "reference": "ac74f580459a5120079b8def0404e5d312a09504"
+ "reference": "64ddfdcaeeb8d332bd98bef442bef81e39c3910b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/LaravelCollective/html/zipball/ac74f580459a5120079b8def0404e5d312a09504",
- "reference": "ac74f580459a5120079b8def0404e5d312a09504",
+ "url": "https://api.github.com/repos/LaravelCollective/html/zipball/64ddfdcaeeb8d332bd98bef442bef81e39c3910b",
+ "reference": "64ddfdcaeeb8d332bd98bef442bef81e39c3910b",
"shasum": ""
},
"require": {
@@ -2741,7 +2728,8 @@
"issues": "https://github.com/LaravelCollective/html/issues",
"source": "https://github.com/LaravelCollective/html"
},
- "time": "2023-02-13T18:15:35+00:00"
+ "abandoned": "spatie/laravel-html",
+ "time": "2023-04-25T02:46:11+00:00"
},
{
"name": "lcobucci/jwt",
@@ -3063,16 +3051,16 @@
},
{
"name": "league/mime-type-detection",
- "version": "1.11.0",
+ "version": "1.12.0",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/mime-type-detection.git",
- "reference": "ff6248ea87a9f116e78edd6002e39e5128a0d4dd"
+ "reference": "c7f2872fb273bf493811473dafc88d60ae829f48"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/ff6248ea87a9f116e78edd6002e39e5128a0d4dd",
- "reference": "ff6248ea87a9f116e78edd6002e39e5128a0d4dd",
+ "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/c7f2872fb273bf493811473dafc88d60ae829f48",
+ "reference": "c7f2872fb273bf493811473dafc88d60ae829f48",
"shasum": ""
},
"require": {
@@ -3103,7 +3091,7 @@
"description": "Mime-type detection for Flysystem",
"support": {
"issues": "https://github.com/thephpleague/mime-type-detection/issues",
- "source": "https://github.com/thephpleague/mime-type-detection/tree/1.11.0"
+ "source": "https://github.com/thephpleague/mime-type-detection/tree/1.12.0"
},
"funding": [
{
@@ -3115,20 +3103,20 @@
"type": "tidelift"
}
],
- "time": "2022-04-17T13:12:02+00:00"
+ "time": "2023-08-03T07:14:11+00:00"
},
{
"name": "league/oauth2-server",
- "version": "8.4.1",
+ "version": "8.4.2",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/oauth2-server.git",
- "reference": "eed31d86d8cc8e6e9c9f58fbb2113494f8b41e24"
+ "reference": "007dc5f6c0151a73b133fec36c9686cc956209d3"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/thephpleague/oauth2-server/zipball/eed31d86d8cc8e6e9c9f58fbb2113494f8b41e24",
- "reference": "eed31d86d8cc8e6e9c9f58fbb2113494f8b41e24",
+ "url": "https://api.github.com/repos/thephpleague/oauth2-server/zipball/007dc5f6c0151a73b133fec36c9686cc956209d3",
+ "reference": "007dc5f6c0151a73b133fec36c9686cc956209d3",
"shasum": ""
},
"require": {
@@ -3195,7 +3183,7 @@
],
"support": {
"issues": "https://github.com/thephpleague/oauth2-server/issues",
- "source": "https://github.com/thephpleague/oauth2-server/tree/8.4.1"
+ "source": "https://github.com/thephpleague/oauth2-server/tree/8.4.2"
},
"funding": [
{
@@ -3203,7 +3191,7 @@
"type": "github"
}
],
- "time": "2023-03-22T11:47:53+00:00"
+ "time": "2023-08-02T22:54:39+00:00"
},
{
"name": "league/uri",
@@ -3636,26 +3624,24 @@
},
{
"name": "masterminds/html5",
- "version": "2.7.6",
+ "version": "2.8.1",
"source": {
"type": "git",
"url": "https://github.com/Masterminds/html5-php.git",
- "reference": "897eb517a343a2281f11bc5556d6548db7d93947"
+ "reference": "f47dcf3c70c584de14f21143c55d9939631bc6cf"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/897eb517a343a2281f11bc5556d6548db7d93947",
- "reference": "897eb517a343a2281f11bc5556d6548db7d93947",
+ "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/f47dcf3c70c584de14f21143c55d9939631bc6cf",
+ "reference": "f47dcf3c70c584de14f21143c55d9939631bc6cf",
"shasum": ""
},
"require": {
- "ext-ctype": "*",
"ext-dom": "*",
- "ext-libxml": "*",
"php": ">=5.3.0"
},
"require-dev": {
- "phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7"
+ "phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8"
},
"type": "library",
"extra": {
@@ -3699,9 +3685,9 @@
],
"support": {
"issues": "https://github.com/Masterminds/html5-php/issues",
- "source": "https://github.com/Masterminds/html5-php/tree/2.7.6"
+ "source": "https://github.com/Masterminds/html5-php/tree/2.8.1"
},
- "time": "2022-08-18T16:18:26+00:00"
+ "time": "2023-05-10T11:58:31+00:00"
},
{
"name": "monolog/monolog",
@@ -3870,25 +3856,29 @@
},
{
"name": "nesbot/carbon",
- "version": "2.66.0",
+ "version": "2.70.0",
"source": {
"type": "git",
"url": "https://github.com/briannesbitt/Carbon.git",
- "reference": "496712849902241f04902033b0441b269effe001"
+ "reference": "d3298b38ea8612e5f77d38d1a99438e42f70341d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/496712849902241f04902033b0441b269effe001",
- "reference": "496712849902241f04902033b0441b269effe001",
+ "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/d3298b38ea8612e5f77d38d1a99438e42f70341d",
+ "reference": "d3298b38ea8612e5f77d38d1a99438e42f70341d",
"shasum": ""
},
"require": {
"ext-json": "*",
"php": "^7.1.8 || ^8.0",
+ "psr/clock": "^1.0",
"symfony/polyfill-mbstring": "^1.0",
"symfony/polyfill-php80": "^1.16",
"symfony/translation": "^3.4 || ^4.0 || ^5.0 || ^6.0"
},
+ "provide": {
+ "psr/clock-implementation": "1.0"
+ },
"require-dev": {
"doctrine/dbal": "^2.0 || ^3.1.4",
"doctrine/orm": "^2.7",
@@ -3968,20 +3958,20 @@
"type": "tidelift"
}
],
- "time": "2023-01-29T18:53:47+00:00"
+ "time": "2023-09-07T16:43:50+00:00"
},
{
"name": "nikic/php-parser",
- "version": "v4.15.4",
+ "version": "v4.17.1",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
- "reference": "6bb5176bc4af8bcb7d926f88718db9b96a2d4290"
+ "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/6bb5176bc4af8bcb7d926f88718db9b96a2d4290",
- "reference": "6bb5176bc4af8bcb7d926f88718db9b96a2d4290",
+ "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d",
+ "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d",
"shasum": ""
},
"require": {
@@ -4022,29 +4012,28 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
- "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.4"
+ "source": "https://github.com/nikic/PHP-Parser/tree/v4.17.1"
},
- "time": "2023-03-05T19:49:14+00:00"
+ "time": "2023-08-13T19:53:39+00:00"
},
{
"name": "nyholm/psr7",
- "version": "1.6.0",
+ "version": "1.8.0",
"source": {
"type": "git",
"url": "https://github.com/Nyholm/psr7.git",
- "reference": "bf4aebd170fadf5fd808c70b90535de327e81a50"
+ "reference": "3cb4d163b58589e47b35103e8e5e6a6a475b47be"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/Nyholm/psr7/zipball/bf4aebd170fadf5fd808c70b90535de327e81a50",
- "reference": "bf4aebd170fadf5fd808c70b90535de327e81a50",
+ "url": "https://api.github.com/repos/Nyholm/psr7/zipball/3cb4d163b58589e47b35103e8e5e6a6a475b47be",
+ "reference": "3cb4d163b58589e47b35103e8e5e6a6a475b47be",
"shasum": ""
},
"require": {
- "php": ">=7.1",
- "php-http/message-factory": "^1.0",
+ "php": ">=7.2",
"psr/http-factory": "^1.0",
- "psr/http-message": "^1.0"
+ "psr/http-message": "^1.1 || ^2.0"
},
"provide": {
"php-http/message-factory-implementation": "1.0",
@@ -4053,14 +4042,15 @@
},
"require-dev": {
"http-interop/http-factory-tests": "^0.9",
+ "php-http/message-factory": "^1.0",
"php-http/psr7-integration-tests": "^1.0",
- "phpunit/phpunit": "^7.5 || 8.5 || 9.4",
+ "phpunit/phpunit": "^7.5 || ^8.5 || ^9.4",
"symfony/error-handler": "^4.4"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.6-dev"
+ "dev-master": "1.8-dev"
}
},
"autoload": {
@@ -4090,7 +4080,7 @@
],
"support": {
"issues": "https://github.com/Nyholm/psr7/issues",
- "source": "https://github.com/Nyholm/psr7/tree/1.6.0"
+ "source": "https://github.com/Nyholm/psr7/tree/1.8.0"
},
"funding": [
{
@@ -4102,7 +4092,7 @@
"type": "github"
}
],
- "time": "2023-04-09T08:34:27+00:00"
+ "time": "2023-05-02T11:26:24+00:00"
},
{
"name": "opis/closure",
@@ -4376,60 +4366,6 @@
},
"time": "2022-09-06T12:16:56+00:00"
},
- {
- "name": "php-http/message-factory",
- "version": "v1.0.2",
- "source": {
- "type": "git",
- "url": "https://github.com/php-http/message-factory.git",
- "reference": "a478cb11f66a6ac48d8954216cfed9aa06a501a1"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/php-http/message-factory/zipball/a478cb11f66a6ac48d8954216cfed9aa06a501a1",
- "reference": "a478cb11f66a6ac48d8954216cfed9aa06a501a1",
- "shasum": ""
- },
- "require": {
- "php": ">=5.4",
- "psr/http-message": "^1.0"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "1.0-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Http\\Message\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Márk Sági-Kazár",
- "email": "mark.sagikazar@gmail.com"
- }
- ],
- "description": "Factory interfaces for PSR-7 HTTP Message",
- "homepage": "http://php-http.org",
- "keywords": [
- "factory",
- "http",
- "message",
- "stream",
- "uri"
- ],
- "support": {
- "issues": "https://github.com/php-http/message-factory/issues",
- "source": "https://github.com/php-http/message-factory/tree/master"
- },
- "time": "2015-12-19T14:08:53+00:00"
- },
{
"name": "phpoffice/phpspreadsheet",
"version": "1.25.2",
@@ -4612,16 +4548,16 @@
},
{
"name": "phpseclib/phpseclib",
- "version": "3.0.19",
+ "version": "3.0.21",
"source": {
"type": "git",
"url": "https://github.com/phpseclib/phpseclib.git",
- "reference": "cc181005cf548bfd8a4896383bb825d859259f95"
+ "reference": "4580645d3fc05c189024eb3b834c6c1e4f0f30a1"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/cc181005cf548bfd8a4896383bb825d859259f95",
- "reference": "cc181005cf548bfd8a4896383bb825d859259f95",
+ "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/4580645d3fc05c189024eb3b834c6c1e4f0f30a1",
+ "reference": "4580645d3fc05c189024eb3b834c6c1e4f0f30a1",
"shasum": ""
},
"require": {
@@ -4702,7 +4638,7 @@
],
"support": {
"issues": "https://github.com/phpseclib/phpseclib/issues",
- "source": "https://github.com/phpseclib/phpseclib/tree/3.0.19"
+ "source": "https://github.com/phpseclib/phpseclib/tree/3.0.21"
},
"funding": [
{
@@ -4718,7 +4654,7 @@
"type": "tidelift"
}
],
- "time": "2023-03-05T17:13:09+00:00"
+ "time": "2023-07-09T15:24:48+00:00"
},
{
"name": "psr/cache",
@@ -4769,6 +4705,54 @@
},
"time": "2016-08-06T20:24:11+00:00"
},
+ {
+ "name": "psr/clock",
+ "version": "1.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/clock.git",
+ "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/clock/zipball/e41a24703d4560fd0acb709162f73b8adfc3aa0d",
+ "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.0 || ^8.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Psr\\Clock\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interface for reading the clock.",
+ "homepage": "https://github.com/php-fig/clock",
+ "keywords": [
+ "clock",
+ "now",
+ "psr",
+ "psr-20",
+ "time"
+ ],
+ "support": {
+ "issues": "https://github.com/php-fig/clock/issues",
+ "source": "https://github.com/php-fig/clock/tree/1.0.0"
+ },
+ "time": "2022-11-25T14:36:26+00:00"
+ },
{
"name": "psr/container",
"version": "1.1.1",
@@ -5130,16 +5114,16 @@
},
{
"name": "psy/psysh",
- "version": "v0.11.15",
+ "version": "v0.11.20",
"source": {
"type": "git",
"url": "https://github.com/bobthecow/psysh.git",
- "reference": "5350ce0ec8ecf2c5b5cf554cd2496f97b444af85"
+ "reference": "0fa27040553d1d280a67a4393194df5228afea5b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/bobthecow/psysh/zipball/5350ce0ec8ecf2c5b5cf554cd2496f97b444af85",
- "reference": "5350ce0ec8ecf2c5b5cf554cd2496f97b444af85",
+ "url": "https://api.github.com/repos/bobthecow/psysh/zipball/0fa27040553d1d280a67a4393194df5228afea5b",
+ "reference": "0fa27040553d1d280a67a4393194df5228afea5b",
"shasum": ""
},
"require": {
@@ -5200,9 +5184,9 @@
],
"support": {
"issues": "https://github.com/bobthecow/psysh/issues",
- "source": "https://github.com/bobthecow/psysh/tree/v0.11.15"
+ "source": "https://github.com/bobthecow/psysh/tree/v0.11.20"
},
- "time": "2023-04-07T21:57:09+00:00"
+ "time": "2023-07-31T14:32:22+00:00"
},
{
"name": "ralouphie/getallheaders",
@@ -5427,16 +5411,16 @@
},
{
"name": "reliese/laravel",
- "version": "v1.2.2",
+ "version": "v1.2.3",
"source": {
"type": "git",
"url": "https://github.com/reliese/laravel.git",
- "reference": "b283b30b73aba472c006749e6af7700aa541bab3"
+ "reference": "3e0d2e5054c6c4f815d72f22915b35e3ffe82858"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/reliese/laravel/zipball/b283b30b73aba472c006749e6af7700aa541bab3",
- "reference": "b283b30b73aba472c006749e6af7700aa541bab3",
+ "url": "https://api.github.com/repos/reliese/laravel/zipball/3e0d2e5054c6c4f815d72f22915b35e3ffe82858",
+ "reference": "3e0d2e5054c6c4f815d72f22915b35e3ffe82858",
"shasum": ""
},
"require": {
@@ -5486,7 +5470,7 @@
"issues": "https://github.com/reliese/laravel/issues",
"source": "https://github.com/reliese/laravel"
},
- "time": "2023-04-04T11:47:25+00:00"
+ "time": "2023-08-17T07:50:33+00:00"
},
{
"name": "rguedes/pdfmerger",
@@ -5592,17 +5576,143 @@
"time": "2021-12-11T13:40:54+00:00"
},
{
- "name": "setasign/fpdf",
- "version": "1.8.5",
+ "name": "sabre/uri",
+ "version": "2.2.4",
"source": {
"type": "git",
- "url": "https://github.com/Setasign/FPDF.git",
- "reference": "f4104a04c9a3f95c4c26a0a0531abebcc980987a"
+ "url": "https://github.com/sabre-io/uri.git",
+ "reference": "c0c9af9f7754e60a49ebd760e1708adc6d1510c0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/Setasign/FPDF/zipball/f4104a04c9a3f95c4c26a0a0531abebcc980987a",
- "reference": "f4104a04c9a3f95c4c26a0a0531abebcc980987a",
+ "url": "https://api.github.com/repos/sabre-io/uri/zipball/c0c9af9f7754e60a49ebd760e1708adc6d1510c0",
+ "reference": "c0c9af9f7754e60a49ebd760e1708adc6d1510c0",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.1 || ^8.0"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "~2.19.3",
+ "phpstan/phpstan": "^0.12",
+ "phpunit/phpunit": "^7.5 || ^8.5 || ^9.0"
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "lib/functions.php"
+ ],
+ "psr-4": {
+ "Sabre\\Uri\\": "lib/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Evert Pot",
+ "email": "me@evertpot.com",
+ "homepage": "http://evertpot.com/",
+ "role": "Developer"
+ }
+ ],
+ "description": "Functions for making sense out of URIs.",
+ "homepage": "http://sabre.io/uri/",
+ "keywords": [
+ "rfc3986",
+ "uri",
+ "url"
+ ],
+ "support": {
+ "forum": "https://groups.google.com/group/sabredav-discuss",
+ "issues": "https://github.com/sabre-io/uri/issues",
+ "source": "https://github.com/fruux/sabre-uri"
+ },
+ "time": "2022-09-19T12:25:28+00:00"
+ },
+ {
+ "name": "sabre/xml",
+ "version": "2.2.6",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sabre-io/xml.git",
+ "reference": "9cde7cdab1e50893cc83b037b40cd47bfde42a2b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sabre-io/xml/zipball/9cde7cdab1e50893cc83b037b40cd47bfde42a2b",
+ "reference": "9cde7cdab1e50893cc83b037b40cd47bfde42a2b",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-xmlreader": "*",
+ "ext-xmlwriter": "*",
+ "lib-libxml": ">=2.6.20",
+ "php": "^7.1 || ^8.0",
+ "sabre/uri": ">=1.0,<3.0.0"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "~2.17.1",
+ "phpstan/phpstan": "^0.12",
+ "phpunit/phpunit": "^7.5 || ^8.5 || ^9.0"
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "lib/Deserializer/functions.php",
+ "lib/Serializer/functions.php"
+ ],
+ "psr-4": {
+ "Sabre\\Xml\\": "lib/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Evert Pot",
+ "email": "me@evertpot.com",
+ "homepage": "http://evertpot.com/",
+ "role": "Developer"
+ },
+ {
+ "name": "Markus Staab",
+ "email": "markus.staab@redaxo.de",
+ "role": "Developer"
+ }
+ ],
+ "description": "sabre/xml is an XML library that you may not hate.",
+ "homepage": "https://sabre.io/xml/",
+ "keywords": [
+ "XMLReader",
+ "XMLWriter",
+ "dom",
+ "xml"
+ ],
+ "support": {
+ "forum": "https://groups.google.com/group/sabredav-discuss",
+ "issues": "https://github.com/sabre-io/xml/issues",
+ "source": "https://github.com/fruux/sabre-xml"
+ },
+ "time": "2023-06-28T12:56:05+00:00"
+ },
+ {
+ "name": "setasign/fpdf",
+ "version": "1.8.6",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/Setasign/FPDF.git",
+ "reference": "0838e0ee4925716fcbbc50ad9e1799b5edfae0a0"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/Setasign/FPDF/zipball/0838e0ee4925716fcbbc50ad9e1799b5edfae0a0",
+ "reference": "0838e0ee4925716fcbbc50ad9e1799b5edfae0a0",
"shasum": ""
},
"require": {
@@ -5633,22 +5743,22 @@
"pdf"
],
"support": {
- "source": "https://github.com/Setasign/FPDF/tree/1.8.5"
+ "source": "https://github.com/Setasign/FPDF/tree/1.8.6"
},
- "time": "2022-11-18T07:02:00+00:00"
+ "time": "2023-06-26T14:44:25+00:00"
},
{
"name": "setasign/fpdi",
- "version": "v2.3.7",
+ "version": "v2.4.1",
"source": {
"type": "git",
"url": "https://github.com/Setasign/FPDI.git",
- "reference": "bccc892d5fa1f48c43f8ba7db5ed4ba6f30c8c05"
+ "reference": "f4ba73e5bc053ccc90b81717c5df1cb2ea7bae7b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/Setasign/FPDI/zipball/bccc892d5fa1f48c43f8ba7db5ed4ba6f30c8c05",
- "reference": "bccc892d5fa1f48c43f8ba7db5ed4ba6f30c8c05",
+ "url": "https://api.github.com/repos/Setasign/FPDI/zipball/f4ba73e5bc053ccc90b81717c5df1cb2ea7bae7b",
+ "reference": "f4ba73e5bc053ccc90b81717c5df1cb2ea7bae7b",
"shasum": ""
},
"require": {
@@ -5661,7 +5771,7 @@
"require-dev": {
"phpunit/phpunit": "~5.7",
"setasign/fpdf": "~1.8",
- "setasign/tfpdf": "1.31",
+ "setasign/tfpdf": "~1.31",
"squizlabs/php_codesniffer": "^3.5",
"tecnickcom/tcpdf": "~6.2"
},
@@ -5699,7 +5809,7 @@
],
"support": {
"issues": "https://github.com/Setasign/FPDI/issues",
- "source": "https://github.com/Setasign/FPDI/tree/v2.3.7"
+ "source": "https://github.com/Setasign/FPDI/tree/v2.4.1"
},
"funding": [
{
@@ -5707,7 +5817,7 @@
"type": "tidelift"
}
],
- "time": "2023-02-09T10:38:43+00:00"
+ "time": "2023-07-27T08:12:09+00:00"
},
{
"name": "swiftmailer/swiftmailer",
@@ -5787,16 +5897,16 @@
},
{
"name": "symfony/console",
- "version": "v5.4.22",
+ "version": "v5.4.28",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
- "reference": "3cd51fd2e6c461ca678f84d419461281bd87a0a8"
+ "reference": "f4f71842f24c2023b91237c72a365306f3c58827"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/console/zipball/3cd51fd2e6c461ca678f84d419461281bd87a0a8",
- "reference": "3cd51fd2e6c461ca678f84d419461281bd87a0a8",
+ "url": "https://api.github.com/repos/symfony/console/zipball/f4f71842f24c2023b91237c72a365306f3c58827",
+ "reference": "f4f71842f24c2023b91237c72a365306f3c58827",
"shasum": ""
},
"require": {
@@ -5866,7 +5976,7 @@
"terminal"
],
"support": {
- "source": "https://github.com/symfony/console/tree/v5.4.22"
+ "source": "https://github.com/symfony/console/tree/v5.4.28"
},
"funding": [
{
@@ -5882,20 +5992,20 @@
"type": "tidelift"
}
],
- "time": "2023-03-25T09:27:28+00:00"
+ "time": "2023-08-07T06:12:30+00:00"
},
{
"name": "symfony/css-selector",
- "version": "v5.4.21",
+ "version": "v5.4.26",
"source": {
"type": "git",
"url": "https://github.com/symfony/css-selector.git",
- "reference": "95f3c7468db1da8cc360b24fa2a26e7cefcb355d"
+ "reference": "0ad3f7e9a1ab492c5b4214cf22a9dc55dcf8600a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/css-selector/zipball/95f3c7468db1da8cc360b24fa2a26e7cefcb355d",
- "reference": "95f3c7468db1da8cc360b24fa2a26e7cefcb355d",
+ "url": "https://api.github.com/repos/symfony/css-selector/zipball/0ad3f7e9a1ab492c5b4214cf22a9dc55dcf8600a",
+ "reference": "0ad3f7e9a1ab492c5b4214cf22a9dc55dcf8600a",
"shasum": ""
},
"require": {
@@ -5932,7 +6042,7 @@
"description": "Converts CSS selectors to XPath expressions",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/css-selector/tree/v5.4.21"
+ "source": "https://github.com/symfony/css-selector/tree/v5.4.26"
},
"funding": [
{
@@ -5948,7 +6058,7 @@
"type": "tidelift"
}
],
- "time": "2023-02-14T08:03:56+00:00"
+ "time": "2023-07-07T06:10:25+00:00"
},
{
"name": "symfony/deprecation-contracts",
@@ -6019,16 +6129,16 @@
},
{
"name": "symfony/error-handler",
- "version": "v5.4.21",
+ "version": "v5.4.26",
"source": {
"type": "git",
"url": "https://github.com/symfony/error-handler.git",
- "reference": "56a94aa8cb5a5fbc411551d8d014a296b5456549"
+ "reference": "b26719213a39c9ba57520cbc5e52bfcc5e8d92f9"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/error-handler/zipball/56a94aa8cb5a5fbc411551d8d014a296b5456549",
- "reference": "56a94aa8cb5a5fbc411551d8d014a296b5456549",
+ "url": "https://api.github.com/repos/symfony/error-handler/zipball/b26719213a39c9ba57520cbc5e52bfcc5e8d92f9",
+ "reference": "b26719213a39c9ba57520cbc5e52bfcc5e8d92f9",
"shasum": ""
},
"require": {
@@ -6070,7 +6180,7 @@
"description": "Provides tools to manage errors and ease debugging PHP code",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/error-handler/tree/v5.4.21"
+ "source": "https://github.com/symfony/error-handler/tree/v5.4.26"
},
"funding": [
{
@@ -6086,20 +6196,20 @@
"type": "tidelift"
}
],
- "time": "2023-02-14T08:03:56+00:00"
+ "time": "2023-07-16T16:48:57+00:00"
},
{
"name": "symfony/event-dispatcher",
- "version": "v5.4.22",
+ "version": "v5.4.26",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher.git",
- "reference": "1df20e45d56da29a4b1d8259dd6e950acbf1b13f"
+ "reference": "5dcc00e03413f05c1e7900090927bb7247cb0aac"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/1df20e45d56da29a4b1d8259dd6e950acbf1b13f",
- "reference": "1df20e45d56da29a4b1d8259dd6e950acbf1b13f",
+ "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/5dcc00e03413f05c1e7900090927bb7247cb0aac",
+ "reference": "5dcc00e03413f05c1e7900090927bb7247cb0aac",
"shasum": ""
},
"require": {
@@ -6155,7 +6265,7 @@
"description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/event-dispatcher/tree/v5.4.22"
+ "source": "https://github.com/symfony/event-dispatcher/tree/v5.4.26"
},
"funding": [
{
@@ -6171,7 +6281,7 @@
"type": "tidelift"
}
],
- "time": "2023-03-17T11:31:58+00:00"
+ "time": "2023-07-06T06:34:20+00:00"
},
{
"name": "symfony/event-dispatcher-contracts",
@@ -6254,16 +6364,16 @@
},
{
"name": "symfony/finder",
- "version": "v5.4.21",
+ "version": "v5.4.27",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
- "reference": "078e9a5e1871fcfe6a5ce421b539344c21afef19"
+ "reference": "ff4bce3c33451e7ec778070e45bd23f74214cd5d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/finder/zipball/078e9a5e1871fcfe6a5ce421b539344c21afef19",
- "reference": "078e9a5e1871fcfe6a5ce421b539344c21afef19",
+ "url": "https://api.github.com/repos/symfony/finder/zipball/ff4bce3c33451e7ec778070e45bd23f74214cd5d",
+ "reference": "ff4bce3c33451e7ec778070e45bd23f74214cd5d",
"shasum": ""
},
"require": {
@@ -6297,7 +6407,7 @@
"description": "Finds files and directories via an intuitive fluent interface",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/finder/tree/v5.4.21"
+ "source": "https://github.com/symfony/finder/tree/v5.4.27"
},
"funding": [
{
@@ -6313,20 +6423,20 @@
"type": "tidelift"
}
],
- "time": "2023-02-16T09:33:00+00:00"
+ "time": "2023-07-31T08:02:31+00:00"
},
{
"name": "symfony/http-foundation",
- "version": "v5.4.22",
+ "version": "v5.4.28",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-foundation.git",
- "reference": "05cd1acdd0e3ce8473aaba1d86c188321d85f313"
+ "reference": "365992c83a836dfe635f1e903ccca43ee03d3dd2"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/http-foundation/zipball/05cd1acdd0e3ce8473aaba1d86c188321d85f313",
- "reference": "05cd1acdd0e3ce8473aaba1d86c188321d85f313",
+ "url": "https://api.github.com/repos/symfony/http-foundation/zipball/365992c83a836dfe635f1e903ccca43ee03d3dd2",
+ "reference": "365992c83a836dfe635f1e903ccca43ee03d3dd2",
"shasum": ""
},
"require": {
@@ -6373,7 +6483,7 @@
"description": "Defines an object-oriented layer for the HTTP specification",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/http-foundation/tree/v5.4.22"
+ "source": "https://github.com/symfony/http-foundation/tree/v5.4.28"
},
"funding": [
{
@@ -6389,20 +6499,20 @@
"type": "tidelift"
}
],
- "time": "2023-03-28T07:28:17+00:00"
+ "time": "2023-08-21T07:23:18+00:00"
},
{
"name": "symfony/http-kernel",
- "version": "v5.4.22",
+ "version": "v5.4.28",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-kernel.git",
- "reference": "2d3a8be2c756353627398827c409af6f126c096d"
+ "reference": "127a2322ca1828157901092518b8ea8e4e1109d4"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/http-kernel/zipball/2d3a8be2c756353627398827c409af6f126c096d",
- "reference": "2d3a8be2c756353627398827c409af6f126c096d",
+ "url": "https://api.github.com/repos/symfony/http-kernel/zipball/127a2322ca1828157901092518b8ea8e4e1109d4",
+ "reference": "127a2322ca1828157901092518b8ea8e4e1109d4",
"shasum": ""
},
"require": {
@@ -6485,7 +6595,7 @@
"description": "Provides a structured process for converting a Request into a Response",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/http-kernel/tree/v5.4.22"
+ "source": "https://github.com/symfony/http-kernel/tree/v5.4.28"
},
"funding": [
{
@@ -6501,20 +6611,20 @@
"type": "tidelift"
}
],
- "time": "2023-03-31T11:54:37+00:00"
+ "time": "2023-08-26T13:47:51+00:00"
},
{
"name": "symfony/mime",
- "version": "v5.4.21",
+ "version": "v5.4.26",
"source": {
"type": "git",
"url": "https://github.com/symfony/mime.git",
- "reference": "ef57d9fb9cdd5e6b2ffc567d109865d10b6920cd"
+ "reference": "2ea06dfeee20000a319d8407cea1d47533d5a9d2"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/mime/zipball/ef57d9fb9cdd5e6b2ffc567d109865d10b6920cd",
- "reference": "ef57d9fb9cdd5e6b2ffc567d109865d10b6920cd",
+ "url": "https://api.github.com/repos/symfony/mime/zipball/2ea06dfeee20000a319d8407cea1d47533d5a9d2",
+ "reference": "2ea06dfeee20000a319d8407cea1d47533d5a9d2",
"shasum": ""
},
"require": {
@@ -6529,7 +6639,7 @@
"phpdocumentor/reflection-docblock": "<3.2.2",
"phpdocumentor/type-resolver": "<1.4.0",
"symfony/mailer": "<4.4",
- "symfony/serializer": "<5.4.14|>=6.0,<6.0.14|>=6.1,<6.1.6"
+ "symfony/serializer": "<5.4.26|>=6,<6.2.13|>=6.3,<6.3.2"
},
"require-dev": {
"egulias/email-validator": "^2.1.10|^3.1|^4",
@@ -6537,7 +6647,7 @@
"symfony/dependency-injection": "^4.4|^5.0|^6.0",
"symfony/property-access": "^4.4|^5.1|^6.0",
"symfony/property-info": "^4.4|^5.1|^6.0",
- "symfony/serializer": "^5.4.14|~6.0.14|^6.1.6"
+ "symfony/serializer": "^5.4.26|~6.2.13|^6.3.2"
},
"type": "library",
"autoload": {
@@ -6569,7 +6679,7 @@
"mime-type"
],
"support": {
- "source": "https://github.com/symfony/mime/tree/v5.4.21"
+ "source": "https://github.com/symfony/mime/tree/v5.4.26"
},
"funding": [
{
@@ -6585,20 +6695,20 @@
"type": "tidelift"
}
],
- "time": "2023-02-21T19:46:44+00:00"
+ "time": "2023-07-27T06:29:31+00:00"
},
{
"name": "symfony/polyfill-ctype",
- "version": "v1.27.0",
+ "version": "v1.28.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
- "reference": "5bbc823adecdae860bb64756d639ecfec17b050a"
+ "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a",
- "reference": "5bbc823adecdae860bb64756d639ecfec17b050a",
+ "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb",
+ "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb",
"shasum": ""
},
"require": {
@@ -6613,7 +6723,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "1.27-dev"
+ "dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -6651,7 +6761,7 @@
"portable"
],
"support": {
- "source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0"
+ "source": "https://github.com/symfony/polyfill-ctype/tree/v1.28.0"
},
"funding": [
{
@@ -6667,20 +6777,20 @@
"type": "tidelift"
}
],
- "time": "2022-11-03T14:55:06+00:00"
+ "time": "2023-01-26T09:26:14+00:00"
},
{
"name": "symfony/polyfill-iconv",
- "version": "v1.27.0",
+ "version": "v1.28.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-iconv.git",
- "reference": "927013f3aac555983a5059aada98e1907d842695"
+ "reference": "6de50471469b8c9afc38164452ab2b6170ee71c1"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/927013f3aac555983a5059aada98e1907d842695",
- "reference": "927013f3aac555983a5059aada98e1907d842695",
+ "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/6de50471469b8c9afc38164452ab2b6170ee71c1",
+ "reference": "6de50471469b8c9afc38164452ab2b6170ee71c1",
"shasum": ""
},
"require": {
@@ -6695,7 +6805,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "1.27-dev"
+ "dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -6734,7 +6844,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-iconv/tree/v1.27.0"
+ "source": "https://github.com/symfony/polyfill-iconv/tree/v1.28.0"
},
"funding": [
{
@@ -6750,20 +6860,20 @@
"type": "tidelift"
}
],
- "time": "2022-11-03T14:55:06+00:00"
+ "time": "2023-01-26T09:26:14+00:00"
},
{
"name": "symfony/polyfill-intl-grapheme",
- "version": "v1.27.0",
+ "version": "v1.28.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-grapheme.git",
- "reference": "511a08c03c1960e08a883f4cffcacd219b758354"
+ "reference": "875e90aeea2777b6f135677f618529449334a612"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/511a08c03c1960e08a883f4cffcacd219b758354",
- "reference": "511a08c03c1960e08a883f4cffcacd219b758354",
+ "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/875e90aeea2777b6f135677f618529449334a612",
+ "reference": "875e90aeea2777b6f135677f618529449334a612",
"shasum": ""
},
"require": {
@@ -6775,7 +6885,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "1.27-dev"
+ "dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -6815,7 +6925,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.27.0"
+ "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.28.0"
},
"funding": [
{
@@ -6831,20 +6941,20 @@
"type": "tidelift"
}
],
- "time": "2022-11-03T14:55:06+00:00"
+ "time": "2023-01-26T09:26:14+00:00"
},
{
"name": "symfony/polyfill-intl-idn",
- "version": "v1.27.0",
+ "version": "v1.28.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-idn.git",
- "reference": "639084e360537a19f9ee352433b84ce831f3d2da"
+ "reference": "ecaafce9f77234a6a449d29e49267ba10499116d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/639084e360537a19f9ee352433b84ce831f3d2da",
- "reference": "639084e360537a19f9ee352433b84ce831f3d2da",
+ "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/ecaafce9f77234a6a449d29e49267ba10499116d",
+ "reference": "ecaafce9f77234a6a449d29e49267ba10499116d",
"shasum": ""
},
"require": {
@@ -6858,7 +6968,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "1.27-dev"
+ "dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -6902,7 +7012,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.27.0"
+ "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.28.0"
},
"funding": [
{
@@ -6918,20 +7028,20 @@
"type": "tidelift"
}
],
- "time": "2022-11-03T14:55:06+00:00"
+ "time": "2023-01-26T09:30:37+00:00"
},
{
"name": "symfony/polyfill-intl-normalizer",
- "version": "v1.27.0",
+ "version": "v1.28.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
- "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6"
+ "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/19bd1e4fcd5b91116f14d8533c57831ed00571b6",
- "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6",
+ "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92",
+ "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92",
"shasum": ""
},
"require": {
@@ -6943,7 +7053,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "1.27-dev"
+ "dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -6986,7 +7096,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.27.0"
+ "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.28.0"
},
"funding": [
{
@@ -7002,20 +7112,20 @@
"type": "tidelift"
}
],
- "time": "2022-11-03T14:55:06+00:00"
+ "time": "2023-01-26T09:26:14+00:00"
},
{
"name": "symfony/polyfill-mbstring",
- "version": "v1.27.0",
+ "version": "v1.28.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
- "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534"
+ "reference": "42292d99c55abe617799667f454222c54c60e229"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
- "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
+ "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229",
+ "reference": "42292d99c55abe617799667f454222c54c60e229",
"shasum": ""
},
"require": {
@@ -7030,7 +7140,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "1.27-dev"
+ "dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -7069,7 +7179,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0"
+ "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0"
},
"funding": [
{
@@ -7085,20 +7195,20 @@
"type": "tidelift"
}
],
- "time": "2022-11-03T14:55:06+00:00"
+ "time": "2023-07-28T09:04:16+00:00"
},
{
"name": "symfony/polyfill-php72",
- "version": "v1.27.0",
+ "version": "v1.28.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php72.git",
- "reference": "869329b1e9894268a8a61dabb69153029b7a8c97"
+ "reference": "70f4aebd92afca2f865444d30a4d2151c13c3179"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/869329b1e9894268a8a61dabb69153029b7a8c97",
- "reference": "869329b1e9894268a8a61dabb69153029b7a8c97",
+ "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/70f4aebd92afca2f865444d30a4d2151c13c3179",
+ "reference": "70f4aebd92afca2f865444d30a4d2151c13c3179",
"shasum": ""
},
"require": {
@@ -7107,7 +7217,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "1.27-dev"
+ "dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -7145,7 +7255,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-php72/tree/v1.27.0"
+ "source": "https://github.com/symfony/polyfill-php72/tree/v1.28.0"
},
"funding": [
{
@@ -7161,20 +7271,20 @@
"type": "tidelift"
}
],
- "time": "2022-11-03T14:55:06+00:00"
+ "time": "2023-01-26T09:26:14+00:00"
},
{
"name": "symfony/polyfill-php73",
- "version": "v1.27.0",
+ "version": "v1.28.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php73.git",
- "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9"
+ "reference": "fe2f306d1d9d346a7fee353d0d5012e401e984b5"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/9e8ecb5f92152187c4799efd3c96b78ccab18ff9",
- "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9",
+ "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/fe2f306d1d9d346a7fee353d0d5012e401e984b5",
+ "reference": "fe2f306d1d9d346a7fee353d0d5012e401e984b5",
"shasum": ""
},
"require": {
@@ -7183,7 +7293,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "1.27-dev"
+ "dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -7224,7 +7334,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-php73/tree/v1.27.0"
+ "source": "https://github.com/symfony/polyfill-php73/tree/v1.28.0"
},
"funding": [
{
@@ -7240,20 +7350,20 @@
"type": "tidelift"
}
],
- "time": "2022-11-03T14:55:06+00:00"
+ "time": "2023-01-26T09:26:14+00:00"
},
{
"name": "symfony/polyfill-php80",
- "version": "v1.27.0",
+ "version": "v1.28.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php80.git",
- "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936"
+ "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936",
- "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936",
+ "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/6caa57379c4aec19c0a12a38b59b26487dcfe4b5",
+ "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5",
"shasum": ""
},
"require": {
@@ -7262,7 +7372,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "1.27-dev"
+ "dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -7307,7 +7417,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0"
+ "source": "https://github.com/symfony/polyfill-php80/tree/v1.28.0"
},
"funding": [
{
@@ -7323,20 +7433,20 @@
"type": "tidelift"
}
],
- "time": "2022-11-03T14:55:06+00:00"
+ "time": "2023-01-26T09:26:14+00:00"
},
{
"name": "symfony/polyfill-php81",
- "version": "v1.27.0",
+ "version": "v1.28.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php81.git",
- "reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a"
+ "reference": "7581cd600fa9fd681b797d00b02f068e2f13263b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/707403074c8ea6e2edaf8794b0157a0bfa52157a",
- "reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a",
+ "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/7581cd600fa9fd681b797d00b02f068e2f13263b",
+ "reference": "7581cd600fa9fd681b797d00b02f068e2f13263b",
"shasum": ""
},
"require": {
@@ -7345,7 +7455,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "1.27-dev"
+ "dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -7386,7 +7496,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-php81/tree/v1.27.0"
+ "source": "https://github.com/symfony/polyfill-php81/tree/v1.28.0"
},
"funding": [
{
@@ -7402,20 +7512,20 @@
"type": "tidelift"
}
],
- "time": "2022-11-03T14:55:06+00:00"
+ "time": "2023-01-26T09:26:14+00:00"
},
{
"name": "symfony/process",
- "version": "v5.4.22",
+ "version": "v5.4.28",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
- "reference": "4b850da0cc3a2a9181c1ed407adbca4733dc839b"
+ "reference": "45261e1fccad1b5447a8d7a8e67aa7b4a9798b7b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/process/zipball/4b850da0cc3a2a9181c1ed407adbca4733dc839b",
- "reference": "4b850da0cc3a2a9181c1ed407adbca4733dc839b",
+ "url": "https://api.github.com/repos/symfony/process/zipball/45261e1fccad1b5447a8d7a8e67aa7b4a9798b7b",
+ "reference": "45261e1fccad1b5447a8d7a8e67aa7b4a9798b7b",
"shasum": ""
},
"require": {
@@ -7448,7 +7558,7 @@
"description": "Executes commands in sub-processes",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/process/tree/v5.4.22"
+ "source": "https://github.com/symfony/process/tree/v5.4.28"
},
"funding": [
{
@@ -7464,36 +7574,37 @@
"type": "tidelift"
}
],
- "time": "2023-03-06T21:29:33+00:00"
+ "time": "2023-08-07T10:36:04+00:00"
},
{
"name": "symfony/psr-http-message-bridge",
- "version": "v2.1.4",
+ "version": "v2.3.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/psr-http-message-bridge.git",
- "reference": "a125b93ef378c492e274f217874906fb9babdebb"
+ "reference": "581ca6067eb62640de5ff08ee1ba6850a0ee472e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/a125b93ef378c492e274f217874906fb9babdebb",
- "reference": "a125b93ef378c492e274f217874906fb9babdebb",
+ "url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/581ca6067eb62640de5ff08ee1ba6850a0ee472e",
+ "reference": "581ca6067eb62640de5ff08ee1ba6850a0ee472e",
"shasum": ""
},
"require": {
- "php": ">=7.1",
- "psr/http-message": "^1.0",
- "symfony/http-foundation": "^4.4 || ^5.0 || ^6.0"
+ "php": ">=7.2.5",
+ "psr/http-message": "^1.0 || ^2.0",
+ "symfony/deprecation-contracts": "^2.5 || ^3.0",
+ "symfony/http-foundation": "^5.4 || ^6.0"
},
"require-dev": {
"nyholm/psr7": "^1.1",
"psr/log": "^1.1 || ^2 || ^3",
- "symfony/browser-kit": "^4.4 || ^5.0 || ^6.0",
- "symfony/config": "^4.4 || ^5.0 || ^6.0",
- "symfony/event-dispatcher": "^4.4 || ^5.0 || ^6.0",
- "symfony/framework-bundle": "^4.4 || ^5.0 || ^6.0",
- "symfony/http-kernel": "^4.4 || ^5.0 || ^6.0",
- "symfony/phpunit-bridge": "^5.4@dev || ^6.0"
+ "symfony/browser-kit": "^5.4 || ^6.0",
+ "symfony/config": "^5.4 || ^6.0",
+ "symfony/event-dispatcher": "^5.4 || ^6.0",
+ "symfony/framework-bundle": "^5.4 || ^6.0",
+ "symfony/http-kernel": "^5.4 || ^6.0",
+ "symfony/phpunit-bridge": "^6.2"
},
"suggest": {
"nyholm/psr7": "For a super lightweight PSR-7/17 implementation"
@@ -7501,7 +7612,7 @@
"type": "symfony-bridge",
"extra": {
"branch-alias": {
- "dev-main": "2.1-dev"
+ "dev-main": "2.3-dev"
}
},
"autoload": {
@@ -7536,7 +7647,7 @@
],
"support": {
"issues": "https://github.com/symfony/psr-http-message-bridge/issues",
- "source": "https://github.com/symfony/psr-http-message-bridge/tree/v2.1.4"
+ "source": "https://github.com/symfony/psr-http-message-bridge/tree/v2.3.1"
},
"funding": [
{
@@ -7552,20 +7663,20 @@
"type": "tidelift"
}
],
- "time": "2022-11-28T22:46:34+00:00"
+ "time": "2023-07-26T11:53:26+00:00"
},
{
"name": "symfony/routing",
- "version": "v5.4.22",
+ "version": "v5.4.26",
"source": {
"type": "git",
"url": "https://github.com/symfony/routing.git",
- "reference": "c2ac11eb34947999b7c38fb4c835a57306907e6d"
+ "reference": "853fc7df96befc468692de0a48831b38f04d2cb2"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/routing/zipball/c2ac11eb34947999b7c38fb4c835a57306907e6d",
- "reference": "c2ac11eb34947999b7c38fb4c835a57306907e6d",
+ "url": "https://api.github.com/repos/symfony/routing/zipball/853fc7df96befc468692de0a48831b38f04d2cb2",
+ "reference": "853fc7df96befc468692de0a48831b38f04d2cb2",
"shasum": ""
},
"require": {
@@ -7626,7 +7737,7 @@
"url"
],
"support": {
- "source": "https://github.com/symfony/routing/tree/v5.4.22"
+ "source": "https://github.com/symfony/routing/tree/v5.4.26"
},
"funding": [
{
@@ -7642,7 +7753,7 @@
"type": "tidelift"
}
],
- "time": "2023-03-14T14:59:20+00:00"
+ "time": "2023-07-24T13:28:37+00:00"
},
{
"name": "symfony/service-contracts",
@@ -7729,16 +7840,16 @@
},
{
"name": "symfony/string",
- "version": "v5.4.22",
+ "version": "v5.4.26",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
- "reference": "8036a4c76c0dd29e60b6a7cafcacc50cf088ea62"
+ "reference": "1181fe9270e373537475e826873b5867b863883c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/string/zipball/8036a4c76c0dd29e60b6a7cafcacc50cf088ea62",
- "reference": "8036a4c76c0dd29e60b6a7cafcacc50cf088ea62",
+ "url": "https://api.github.com/repos/symfony/string/zipball/1181fe9270e373537475e826873b5867b863883c",
+ "reference": "1181fe9270e373537475e826873b5867b863883c",
"shasum": ""
},
"require": {
@@ -7795,7 +7906,7 @@
"utf8"
],
"support": {
- "source": "https://github.com/symfony/string/tree/v5.4.22"
+ "source": "https://github.com/symfony/string/tree/v5.4.26"
},
"funding": [
{
@@ -7811,20 +7922,20 @@
"type": "tidelift"
}
],
- "time": "2023-03-14T06:11:53+00:00"
+ "time": "2023-06-28T12:46:07+00:00"
},
{
"name": "symfony/translation",
- "version": "v5.4.22",
+ "version": "v5.4.24",
"source": {
"type": "git",
"url": "https://github.com/symfony/translation.git",
- "reference": "9a401392f01bc385aa42760eff481d213a0cc2ba"
+ "reference": "de237e59c5833422342be67402d487fbf50334ff"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/translation/zipball/9a401392f01bc385aa42760eff481d213a0cc2ba",
- "reference": "9a401392f01bc385aa42760eff481d213a0cc2ba",
+ "url": "https://api.github.com/repos/symfony/translation/zipball/de237e59c5833422342be67402d487fbf50334ff",
+ "reference": "de237e59c5833422342be67402d487fbf50334ff",
"shasum": ""
},
"require": {
@@ -7892,7 +8003,7 @@
"description": "Provides tools to internationalize your application",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/translation/tree/v5.4.22"
+ "source": "https://github.com/symfony/translation/tree/v5.4.24"
},
"funding": [
{
@@ -7908,7 +8019,7 @@
"type": "tidelift"
}
],
- "time": "2023-03-27T16:07:23+00:00"
+ "time": "2023-05-19T12:34:17+00:00"
},
{
"name": "symfony/translation-contracts",
@@ -7990,16 +8101,16 @@
},
{
"name": "symfony/var-dumper",
- "version": "v5.4.22",
+ "version": "v5.4.28",
"source": {
"type": "git",
"url": "https://github.com/symfony/var-dumper.git",
- "reference": "e2edac9ce47e6df07e38143c7cfa6bdbc1a6dcc4"
+ "reference": "684b36ff415e1381d4a943c3ca2502cd2debad73"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/var-dumper/zipball/e2edac9ce47e6df07e38143c7cfa6bdbc1a6dcc4",
- "reference": "e2edac9ce47e6df07e38143c7cfa6bdbc1a6dcc4",
+ "url": "https://api.github.com/repos/symfony/var-dumper/zipball/684b36ff415e1381d4a943c3ca2502cd2debad73",
+ "reference": "684b36ff415e1381d4a943c3ca2502cd2debad73",
"shasum": ""
},
"require": {
@@ -8008,12 +8119,12 @@
"symfony/polyfill-php80": "^1.16"
},
"conflict": {
- "phpunit/phpunit": "<5.4.3",
"symfony/console": "<4.4"
},
"require-dev": {
"ext-iconv": "*",
"symfony/console": "^4.4|^5.0|^6.0",
+ "symfony/http-kernel": "^4.4|^5.0|^6.0",
"symfony/process": "^4.4|^5.0|^6.0",
"symfony/uid": "^5.1|^6.0",
"twig/twig": "^2.13|^3.0.4"
@@ -8059,7 +8170,7 @@
"dump"
],
"support": {
- "source": "https://github.com/symfony/var-dumper/tree/v5.4.22"
+ "source": "https://github.com/symfony/var-dumper/tree/v5.4.28"
},
"funding": [
{
@@ -8075,7 +8186,7 @@
"type": "tidelift"
}
],
- "time": "2023-03-25T09:27:28+00:00"
+ "time": "2023-08-24T13:38:36+00:00"
},
{
"name": "tijsverkoyen/css-to-inline-styles",
@@ -8130,6 +8241,52 @@
},
"time": "2023-01-03T09:29:04+00:00"
},
+ {
+ "name": "vitalybaev/google-merchant-feed",
+ "version": "v2.6.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/vitalybaev/php-google-merchant-feed.git",
+ "reference": "b0bcb7290e495c12a2038c6aa8db2a3782dc9f43"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/vitalybaev/php-google-merchant-feed/zipball/b0bcb7290e495c12a2038c6aa8db2a3782dc9f43",
+ "reference": "b0bcb7290e495c12a2038c6aa8db2a3782dc9f43",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.5",
+ "sabre/xml": "^1.5 || ^2.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Vitalybaev\\GoogleMerchant\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Vitaly Baev",
+ "email": "ping@baev.dev"
+ }
+ ],
+ "description": "PHP package for creating Google Merchant products feed",
+ "keywords": [
+ "feed",
+ "google",
+ "merchant"
+ ],
+ "support": {
+ "issues": "https://github.com/vitalybaev/php-google-merchant-feed/issues",
+ "source": "https://github.com/vitalybaev/php-google-merchant-feed/tree/v2.6.0"
+ },
+ "time": "2022-12-23T16:17:16+00:00"
+ },
{
"name": "vlucas/phpdotenv",
"version": "v5.5.0",
@@ -8613,16 +8770,16 @@
},
{
"name": "barryvdh/reflection-docblock",
- "version": "v2.1.0",
+ "version": "v2.1.1",
"source": {
"type": "git",
"url": "https://github.com/barryvdh/ReflectionDocBlock.git",
- "reference": "bf44b757feb8ba1734659029357646466ded673e"
+ "reference": "e6811e927f0ecc37cc4deaa6627033150343e597"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/barryvdh/ReflectionDocBlock/zipball/bf44b757feb8ba1734659029357646466ded673e",
- "reference": "bf44b757feb8ba1734659029357646466ded673e",
+ "url": "https://api.github.com/repos/barryvdh/ReflectionDocBlock/zipball/e6811e927f0ecc37cc4deaa6627033150343e597",
+ "reference": "e6811e927f0ecc37cc4deaa6627033150343e597",
"shasum": ""
},
"require": {
@@ -8659,28 +8816,28 @@
}
],
"support": {
- "source": "https://github.com/barryvdh/ReflectionDocBlock/tree/v2.1.0"
+ "source": "https://github.com/barryvdh/ReflectionDocBlock/tree/v2.1.1"
},
- "time": "2022-10-31T15:35:43+00:00"
+ "time": "2023-06-14T05:06:27+00:00"
},
{
"name": "composer/class-map-generator",
- "version": "1.0.0",
+ "version": "1.1.0",
"source": {
"type": "git",
"url": "https://github.com/composer/class-map-generator.git",
- "reference": "1e1cb2b791facb2dfe32932a7718cf2571187513"
+ "reference": "953cc4ea32e0c31f2185549c7d216d7921f03da9"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/composer/class-map-generator/zipball/1e1cb2b791facb2dfe32932a7718cf2571187513",
- "reference": "1e1cb2b791facb2dfe32932a7718cf2571187513",
+ "url": "https://api.github.com/repos/composer/class-map-generator/zipball/953cc4ea32e0c31f2185549c7d216d7921f03da9",
+ "reference": "953cc4ea32e0c31f2185549c7d216d7921f03da9",
"shasum": ""
},
"require": {
- "composer/pcre": "^2 || ^3",
+ "composer/pcre": "^2.1 || ^3.1",
"php": "^7.2 || ^8.0",
- "symfony/finder": "^4.4 || ^5.3 || ^6"
+ "symfony/finder": "^4.4 || ^5.3 || ^6 || ^7"
},
"require-dev": {
"phpstan/phpstan": "^1.6",
@@ -8718,7 +8875,7 @@
],
"support": {
"issues": "https://github.com/composer/class-map-generator/issues",
- "source": "https://github.com/composer/class-map-generator/tree/1.0.0"
+ "source": "https://github.com/composer/class-map-generator/tree/1.1.0"
},
"funding": [
{
@@ -8734,7 +8891,7 @@
"type": "tidelift"
}
],
- "time": "2022-06-19T11:31:27+00:00"
+ "time": "2023-06-30T13:58:57+00:00"
},
{
"name": "composer/pcre",
@@ -9142,16 +9299,16 @@
},
{
"name": "filp/whoops",
- "version": "2.15.1",
+ "version": "2.15.3",
"source": {
"type": "git",
"url": "https://github.com/filp/whoops.git",
- "reference": "e864ac957acd66e1565f25efda61e37791a5db0b"
+ "reference": "c83e88a30524f9360b11f585f71e6b17313b7187"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/filp/whoops/zipball/e864ac957acd66e1565f25efda61e37791a5db0b",
- "reference": "e864ac957acd66e1565f25efda61e37791a5db0b",
+ "url": "https://api.github.com/repos/filp/whoops/zipball/c83e88a30524f9360b11f585f71e6b17313b7187",
+ "reference": "c83e88a30524f9360b11f585f71e6b17313b7187",
"shasum": ""
},
"require": {
@@ -9201,7 +9358,7 @@
],
"support": {
"issues": "https://github.com/filp/whoops/issues",
- "source": "https://github.com/filp/whoops/tree/2.15.1"
+ "source": "https://github.com/filp/whoops/tree/2.15.3"
},
"funding": [
{
@@ -9209,7 +9366,7 @@
"type": "github"
}
],
- "time": "2023-03-06T18:09:13+00:00"
+ "time": "2023-07-13T12:00:00+00:00"
},
{
"name": "hamcrest/hamcrest-php",
@@ -9390,38 +9547,40 @@
},
{
"name": "mockery/mockery",
- "version": "1.5.1",
+ "version": "1.6.6",
"source": {
"type": "git",
"url": "https://github.com/mockery/mockery.git",
- "reference": "e92dcc83d5a51851baf5f5591d32cb2b16e3684e"
+ "reference": "b8e0bb7d8c604046539c1115994632c74dcb361e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/mockery/mockery/zipball/e92dcc83d5a51851baf5f5591d32cb2b16e3684e",
- "reference": "e92dcc83d5a51851baf5f5591d32cb2b16e3684e",
+ "url": "https://api.github.com/repos/mockery/mockery/zipball/b8e0bb7d8c604046539c1115994632c74dcb361e",
+ "reference": "b8e0bb7d8c604046539c1115994632c74dcb361e",
"shasum": ""
},
"require": {
"hamcrest/hamcrest-php": "^2.0.1",
"lib-pcre": ">=7.0",
- "php": "^7.3 || ^8.0"
+ "php": ">=7.3"
},
"conflict": {
"phpunit/phpunit": "<8.0"
},
"require-dev": {
- "phpunit/phpunit": "^8.5 || ^9.3"
+ "phpunit/phpunit": "^8.5 || ^9.6.10",
+ "psalm/plugin-phpunit": "^0.18.4",
+ "symplify/easy-coding-standard": "^11.5.0",
+ "vimeo/psalm": "^4.30"
},
"type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "1.4.x-dev"
- }
- },
"autoload": {
- "psr-0": {
- "Mockery": "library/"
+ "files": [
+ "library/helpers.php",
+ "library/Mockery.php"
+ ],
+ "psr-4": {
+ "Mockery\\": "library/Mockery"
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -9432,12 +9591,20 @@
{
"name": "Pádraic Brady",
"email": "padraic.brady@gmail.com",
- "homepage": "http://blog.astrumfutura.com"
+ "homepage": "https://github.com/padraic",
+ "role": "Author"
},
{
"name": "Dave Marshall",
"email": "dave.marshall@atstsolutions.co.uk",
- "homepage": "http://davedevelopment.co.uk"
+ "homepage": "https://davedevelopment.co.uk",
+ "role": "Developer"
+ },
+ {
+ "name": "Nathanael Esayeas",
+ "email": "nathanael.esayeas@protonmail.com",
+ "homepage": "https://github.com/ghostwriter",
+ "role": "Lead Developer"
}
],
"description": "Mockery is a simple yet flexible PHP mock object framework",
@@ -9455,10 +9622,13 @@
"testing"
],
"support": {
+ "docs": "https://docs.mockery.io/",
"issues": "https://github.com/mockery/mockery/issues",
- "source": "https://github.com/mockery/mockery/tree/1.5.1"
+ "rss": "https://github.com/mockery/mockery/releases.atom",
+ "security": "https://github.com/mockery/mockery/security/advisories",
+ "source": "https://github.com/mockery/mockery"
},
- "time": "2022-09-07T15:32:08+00:00"
+ "time": "2023-08-09T00:03:52+00:00"
},
{
"name": "myclabs/deep-copy",
@@ -9822,16 +9992,16 @@
},
{
"name": "phpunit/php-code-coverage",
- "version": "9.2.26",
+ "version": "9.2.28",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
- "reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1"
+ "reference": "7134a5ccaaf0f1c92a4f5501a6c9f98ac4dcc0ef"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/443bc6912c9bd5b409254a40f4b0f4ced7c80ea1",
- "reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/7134a5ccaaf0f1c92a4f5501a6c9f98ac4dcc0ef",
+ "reference": "7134a5ccaaf0f1c92a4f5501a6c9f98ac4dcc0ef",
"shasum": ""
},
"require": {
@@ -9887,7 +10057,8 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
- "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.26"
+ "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
+ "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.28"
},
"funding": [
{
@@ -9895,7 +10066,7 @@
"type": "github"
}
],
- "time": "2023-03-06T12:58:08+00:00"
+ "time": "2023-09-12T14:36:20+00:00"
},
{
"name": "phpunit/php-file-iterator",
@@ -10140,16 +10311,16 @@
},
{
"name": "phpunit/phpunit",
- "version": "9.6.6",
+ "version": "9.6.12",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
- "reference": "b65d59a059d3004a040c16a82e07bbdf6cfdd115"
+ "reference": "a122c2ebd469b751d774aa0f613dc0d67697653f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b65d59a059d3004a040c16a82e07bbdf6cfdd115",
- "reference": "b65d59a059d3004a040c16a82e07bbdf6cfdd115",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a122c2ebd469b751d774aa0f613dc0d67697653f",
+ "reference": "a122c2ebd469b751d774aa0f613dc0d67697653f",
"shasum": ""
},
"require": {
@@ -10164,7 +10335,7 @@
"phar-io/manifest": "^2.0.3",
"phar-io/version": "^3.0.2",
"php": ">=7.3",
- "phpunit/php-code-coverage": "^9.2.13",
+ "phpunit/php-code-coverage": "^9.2.28",
"phpunit/php-file-iterator": "^3.0.5",
"phpunit/php-invoker": "^3.1.1",
"phpunit/php-text-template": "^2.0.3",
@@ -10223,7 +10394,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
- "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.6"
+ "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.12"
},
"funding": [
{
@@ -10239,7 +10410,7 @@
"type": "tidelift"
}
],
- "time": "2023-03-27T11:43:46+00:00"
+ "time": "2023-09-12T14:39:31+00:00"
},
{
"name": "sebastian/cli-parser",
@@ -10541,16 +10712,16 @@
},
{
"name": "sebastian/diff",
- "version": "4.0.4",
+ "version": "4.0.5",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/diff.git",
- "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d"
+ "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d",
- "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d",
+ "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/74be17022044ebaaecfdf0c5cd504fc9cd5a7131",
+ "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131",
"shasum": ""
},
"require": {
@@ -10595,7 +10766,7 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/diff/issues",
- "source": "https://github.com/sebastianbergmann/diff/tree/4.0.4"
+ "source": "https://github.com/sebastianbergmann/diff/tree/4.0.5"
},
"funding": [
{
@@ -10603,7 +10774,7 @@
"type": "github"
}
],
- "time": "2020-10-26T13:10:38+00:00"
+ "time": "2023-05-07T05:35:17+00:00"
},
{
"name": "sebastian/environment",
@@ -10747,16 +10918,16 @@
},
{
"name": "sebastian/global-state",
- "version": "5.0.5",
+ "version": "5.0.6",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/global-state.git",
- "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2"
+ "reference": "bde739e7565280bda77be70044ac1047bc007e34"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/0ca8db5a5fc9c8646244e629625ac486fa286bf2",
- "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2",
+ "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bde739e7565280bda77be70044ac1047bc007e34",
+ "reference": "bde739e7565280bda77be70044ac1047bc007e34",
"shasum": ""
},
"require": {
@@ -10799,7 +10970,7 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/global-state/issues",
- "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.5"
+ "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.6"
},
"funding": [
{
@@ -10807,7 +10978,7 @@
"type": "github"
}
],
- "time": "2022-02-14T08:28:10+00:00"
+ "time": "2023-08-02T09:26:13+00:00"
},
{
"name": "sebastian/lines-of-code",
@@ -11265,5 +11436,5 @@
"php": "^7.3|^8.0"
},
"platform-dev": [],
- "plugin-api-version": "2.1.0"
+ "plugin-api-version": "2.3.0"
}
diff --git a/config/app.php b/config/app.php
index 53a85b5c..a7b8065c 100755
--- a/config/app.php
+++ b/config/app.php
@@ -64,13 +64,20 @@ return [
'checkout_mail' => env('APP_CHECKOUT_MAIL', 'no-reply@mivita.care'),
'checkout_test_mail' => env('APP_CHECKOUT_TEST_MAIL', 'devtest@mivita.care'),
'info_mail' => env('APP_INFO_MAIL', 'no-reply@mivita.care'),
+ 'priority_mail' => env('APP_PROORITY_MAIL', 'priority@mivita.care'),
'default_mail' => env('APP_DEFAULT_MAIL', 'info@mivita.care'),
'info_test_mail' => env('APP_INFO_TEST_MAIL', 'devtest@mivita.care'),
+ 'exception_mail' => env('EXCEPTION_MAIL', 'exception@adametz.media'),
+ 'ipinfo' => env('APP_IPINFO', false),
+
+
'main_tax' => env('APP_MAIN_TAX', 1.19),
'main_tax_rate' => env('APP_MAIN_TAX_RATE', 19),
'shipping_tax' => env('APP_SHIPPING_TAX', 19),
+ 'php_version' => env('APP_PHP_VERSION', '7.4'),
+
/* 'url_backend' => env('APP_URL', 'http://mivita.local/'),
'url_backend' => env('APP_URL', 'http://mivita.local/'),
'url_backend' => env('APP_URL', 'http://mivita.local/'),
diff --git a/config/localization.php b/config/localization.php
index 3c497d17..2a76142e 100644
--- a/config/localization.php
+++ b/config/localization.php
@@ -46,13 +46,13 @@ return [
//'en-AU' => ['name' => 'Australian English', 'script' => 'Latn', 'native' => 'Australian English', 'regional' => 'en_AU'],
//'en-GB' => ['name' => 'British English', 'script' => 'Latn', 'native' => 'British English', 'regional' => 'en_GB'],
//'en-US' => ['name' => 'U.S. English', 'script' => 'Latn', 'native' => 'U.S. English', 'regional' => 'en_US'],
- // 'es' => ['name' => 'Spanish', 'script' => 'Latn', 'native' => 'español', 'regional' => 'es_ES'],
+ 'es' => ['name' => 'Spanish', 'script' => 'Latn', 'native' => 'español', 'regional' => 'es_ES'],
//'eo' => ['name' => 'Esperanto', 'script' => 'Latn', 'native' => 'esperanto', 'regional' => ''],
//'eu' => ['name' => 'Basque', 'script' => 'Latn', 'native' => 'euskara', 'regional' => 'eu_ES'],
//'ewo' => ['name' => 'Ewondo', 'script' => 'Latn', 'native' => 'ewondo', 'regional' => ''],
//'ee' => ['name' => 'Ewe', 'script' => 'Latn', 'native' => 'eʋegbe', 'regional' => ''],
//'fil' => ['name' => 'Filipino', 'script' => 'Latn', 'native' => 'Filipino', 'regional' => 'fil_PH'],
- 'fr' => ['name' => 'French', 'script' => 'Latn', 'native' => 'français', 'regional' => 'fr_FR'],
+ //'fr' => ['name' => 'French', 'script' => 'Latn', 'native' => 'français', 'regional' => 'fr_FR'],
//'fr-CA' => ['name' => 'Canadian French', 'script' => 'Latn', 'native' => 'français canadien', 'regional' => 'fr_CA'],
//'fy' => ['name' => 'Western Frisian', 'script' => 'Latn', 'native' => 'frysk', 'regional' => 'fy_DE'],
//'fur' => ['name' => 'Friulian', 'script' => 'Latn', 'native' => 'furlan', 'regional' => 'fur_IT'],
@@ -130,7 +130,7 @@ return [
//'mtr' => ['name' => 'Mewari', 'script' => 'Latn', 'native' => 'Mewari', 'regional' => ''],
//'mua' => ['name' => 'Mundang', 'script' => 'Latn', 'native' => 'Mundang', 'regional' => ''],
//'mi' => ['name' => 'Māori', 'script' => 'Latn', 'native' => 'Māori', 'regional' => 'mi_NZ'],
- 'nl' => ['name' => 'Dutch', 'script' => 'Latn', 'native' => 'Nederlands', 'regional' => 'nl_NL'],
+ //'nl' => ['name' => 'Dutch', 'script' => 'Latn', 'native' => 'Nederlands', 'regional' => 'nl_NL'],
//'nmg' => ['name' => 'Kwasio', 'script' => 'Latn', 'native' => 'ngumba', 'regional' => ''],
//'yav' => ['name' => 'Yangben', 'script' => 'Latn', 'native' => 'nuasue', 'regional' => ''],
//'nn' => ['name' => 'Norwegian Nynorsk', 'script' => 'Latn', 'native' => 'nynorsk', 'regional' => 'nn_NO'],
diff --git a/config/logging.php b/config/logging.php
index 30394b12..7f3a5895 100755
--- a/config/logging.php
+++ b/config/logging.php
@@ -38,6 +38,14 @@ return [
'driver' => 'single',
'path' => storage_path('logs/payone.log'),
],
+ 'cleanup' => [
+ 'driver' => 'single',
+ 'path' => storage_path('logs/cleanup.log'),
+ ],
+ 'payment' => [
+ 'driver' => 'single',
+ 'path' => storage_path('logs/payment.log'),
+ ],
'cron' => [
'driver' => 'single',
'path' => storage_path('logs/corn.log'),
diff --git a/config/translation.php b/config/translation.php
new file mode 100644
index 00000000..3b9001ee
--- /dev/null
+++ b/config/translation.php
@@ -0,0 +1,77 @@
+ 'file',
+
+ /*
+ |--------------------------------------------------------------------------
+ | Route group configuration
+ |--------------------------------------------------------------------------
+ |
+ | The package ships with routes to handle language management. Update the
+ | configuration here to configure the routes with your preferred group options.
+ |
+ */
+ 'route_group_config' => [
+ 'middleware' => 'admin',
+ ],
+
+ /*
+ |--------------------------------------------------------------------------
+ | Translation methods
+ |--------------------------------------------------------------------------
+ |
+ | Update this array to tell the package which methods it should look for
+ | when finding missing translations.
+ |
+ */
+ 'translation_methods' => ['trans', '__'],
+
+ /*
+ |--------------------------------------------------------------------------
+ | Scan paths
+ |--------------------------------------------------------------------------
+ |
+ | Update this array to tell the package which directories to scan when
+ | looking for missing translations.
+ |
+ */
+ 'scan_paths' => [app_path(), resource_path()],
+
+ /*
+ |--------------------------------------------------------------------------
+ | UI URL
+ |--------------------------------------------------------------------------
+ |
+ | Define the URL used to access the language management too.
+ |
+ */
+ 'ui_url' => 'admin/languages',
+
+ /*
+ |--------------------------------------------------------------------------
+ | Database settings
+ |--------------------------------------------------------------------------
+ |
+ | Define the settings for the database driver here.
+ |
+ */
+ 'database' => [
+
+ 'connection' => '',
+
+ 'languages_table' => 'trans_languages',
+
+ 'translations_table' => 'trans_translations',
+ ],
+];
diff --git a/cron_script.sh b/cron_script.sh
index bbd3ecdb..a4d076b9 100644
--- a/cron_script.sh
+++ b/cron_script.sh
@@ -2,5 +2,7 @@
echo $(date) # Will print the output of date command
/Applications/MAMP/bin/php/php7.3.33/bin/php -v
/Applications/MAMP/bin/php/php7.3.33/bin/php ../artisan business:store 0 0 2>&1
+#/usr/bin/php74 -v
+#/usr/bin/php74 ../artisan business:store 0 0 2>&1
# php /path/to/artisan schedule:run 1>> /dev/null 2>&1
# cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1
\ No newline at end of file
diff --git a/cron_script_local.sh b/cron_script_local.sh
new file mode 100644
index 00000000..c519548a
--- /dev/null
+++ b/cron_script_local.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+echo $(date) # Will print the output of date command
+/Applications/MAMP/bin/php/php7.4.33/bin/php -v
+/Applications/MAMP/bin/php/php7.4.33/bin/php ../artisan business:store 0 0 2>&1
+/Applications/MAMP/bin/php/php7.4.33/bin/php ../artisan user:cleanup 2>&1
+
+# php /path/to/artisan schedule:run 1>> /dev/null 2>&1
+# cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1
\ No newline at end of file
diff --git a/cron_script_server.sh b/cron_script_server.sh
new file mode 100644
index 00000000..34ac6ee5
--- /dev/null
+++ b/cron_script_server.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+echo $(date) # Will print the output of date command
+/usr/bin/php74 -v
+/usr/bin/php74 ../artisan business:store 0 0 2>&1
+/usr/bin/php74 ../artisan user:cleanup 2>&1
+# php /path/to/artisan schedule:run 1>> /dev/null 2>&1
+# cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1
\ No newline at end of file
diff --git a/database/migrations/2014_10_12_000000_create_users_table.php b/database/migrations/2014_10_12_000000_create_users_table.php
index d364bd6f..de5aa50a 100755
--- a/database/migrations/2014_10_12_000000_create_users_table.php
+++ b/database/migrations/2014_10_12_000000_create_users_table.php
@@ -22,6 +22,8 @@ class CreateUsersTable extends Migration
$table->unsignedInteger('m_level')->nullable();
$table->unsignedInteger('m_sponsor')->nullable();
+ $table->unsignedInteger('pre_sponsor')->nullable();
+
$table->boolean('confirmed')->default(false);
$table->string('confirmation_code', 30)->index()->nullable();
$table->timestamp('confirmation_date')->nullable();
@@ -68,6 +70,11 @@ class CreateUsersTable extends Migration
->references('id')
->on('users');
+ $table->foreign('pre_sponsor')
+ ->references('id')
+ ->on('users');
+
+
$table->foreign('payment_order_id')
->references('id')
->on('products');
diff --git a/database/migrations/2018_09_29_145909_create_countries_table.php b/database/migrations/2018_09_29_145909_create_countries_table.php
index ccf8a426..b2badba6 100644
--- a/database/migrations/2018_09_29_145909_create_countries_table.php
+++ b/database/migrations/2018_09_29_145909_create_countries_table.php
@@ -28,6 +28,7 @@ class CreateCountriesTable extends Migration
$table->boolean('supply_country')->default(false);
$table->boolean('eu_country')->default(false);
$table->boolean('switch')->default(false);
+ $table->boolean('translate')->default(false);
$table->boolean('own_eur')->default(false);
$table->boolean('currency')->default(false);
$table->string('currency_unit', 10)->nullable();
@@ -38,7 +39,6 @@ class CreateCountriesTable extends Migration
$table->text('trans_name')->nullable();
$table->text('attr')->nullable();
-
$table->timestamps();
diff --git a/database/migrations/2018_10_21_163956_create_attributes_table.php b/database/migrations/2018_10_21_163956_create_attributes_table.php
index a2636ed5..1851be1b 100644
--- a/database/migrations/2018_10_21_163956_create_attributes_table.php
+++ b/database/migrations/2018_10_21_163956_create_attributes_table.php
@@ -18,7 +18,6 @@ class CreateAttributesTable extends Migration
$table->unsignedInteger('parent_id')->index()->nullable();
$table->string('name')->index();
- $table->text('trans_name')->nullable();
$table->tinyInteger('pos')->unsigned()->nullable();
$table->boolean('active')->default(false);
diff --git a/database/migrations/2018_10_21_164001_create_products_table.php b/database/migrations/2018_10_21_164001_create_products_table.php
index 9ea99cdd..4e80a93a 100644
--- a/database/migrations/2018_10_21_164001_create_products_table.php
+++ b/database/migrations/2018_10_21_164001_create_products_table.php
@@ -17,13 +17,8 @@ class CreateProductsTable extends Migration
$table->increments('id');
$table->string('name')->index();
- $table->text('trans_name')->nullable();
-
$table->string('title')->index();
- $table->text('trans_title')->nullable();
-
$table->text('copy')->nullable();
- $table->mediumText('trans_copy')->nullable();
$table->decimal('price', 8, 2)->nullable();
$table->decimal('price_ek', 8, 2)->nullable();
@@ -49,13 +44,10 @@ class CreateProductsTable extends Migration
$table->string('icons')->nullable(); //as array cast
$table->text('description')->nullable();
- $table->mediumText('trans_description')->nullable();
$table->text('usage')->nullable();
- $table->mediumText('trans_usage')->nullable();
$table->text('ingredients')->nullable();
- $table->mediumText('trans_ingredients')->nullable();
$table->tinyInteger('pos')->unsigned()->nullable();
$table->boolean('active')->default(false);
diff --git a/database/migrations/2019_01_03_162833_create_user_shops_table.php b/database/migrations/2019_01_03_162833_create_user_shops_table.php
index b7ed976f..a43931f0 100644
--- a/database/migrations/2019_01_03_162833_create_user_shops_table.php
+++ b/database/migrations/2019_01_03_162833_create_user_shops_table.php
@@ -28,10 +28,10 @@ class CreateUserShopsTable extends Migration
$table->string('title')->nullable();
$table->string('contact')->nullable();
-
$table->string('accessibility')->nullable();
-
$table->string('about')->nullable();
+ $table->text('trans')->nullable();
+
$table->string('featured')->nullable();
diff --git a/database/migrations/2019_02_21_195012_create_shopping_instances_table.php b/database/migrations/2019_02_21_195012_create_shopping_instances_table.php
index e84126c4..184c4908 100644
--- a/database/migrations/2019_02_21_195012_create_shopping_instances_table.php
+++ b/database/migrations/2019_02_21_195012_create_shopping_instances_table.php
@@ -19,6 +19,9 @@ class CreateShoppingInstancesTable extends Migration
$table->unsignedInteger('auth_user_id');
$table->unsignedTinyInteger('payment');
$table->unsignedInteger('country_id');
+ $table->char('language', 2)->nullable();
+
+
$table->string('subdomain');
$table->text('shopping_data')->nullable();
$table->string('back');
diff --git a/database/migrations/2019_02_23_161530_create_shopping_users_table.php b/database/migrations/2019_02_23_161530_create_shopping_users_table.php
index 717b10a2..487c29ab 100644
--- a/database/migrations/2019_02_23_161530_create_shopping_users_table.php
+++ b/database/migrations/2019_02_23_161530_create_shopping_users_table.php
@@ -21,6 +21,7 @@ class CreateShoppingUsersTable extends Migration
$table->unsignedInteger('number')->index()->nullable();
$table->boolean('is_like')->default(false);
+ $table->char('language', 2)->nullable();
$table->char('billing_salutation', 2)->nullable();
$table->string('billing_company')->nullable();
diff --git a/database/migrations/2019_02_23_163527_create_shopping_orders_table.php b/database/migrations/2019_02_23_163527_create_shopping_orders_table.php
index f980f400..8d0dabc7 100644
--- a/database/migrations/2019_02_23_163527_create_shopping_orders_table.php
+++ b/database/migrations/2019_02_23_163527_create_shopping_orders_table.php
@@ -20,6 +20,8 @@ class CreateShoppingOrdersTable extends Migration
$table->unsignedInteger('auth_user_id');
$table->unsignedInteger('country_id');
+ $table->char('language', 2)->nullable();
+
$table->unsignedInteger('user_shop_id');
$table->unsignedInteger('member_id')->nullable();
@@ -46,6 +48,9 @@ class CreateShoppingOrdersTable extends Migration
$table->unsignedInteger('weight')->nullable();
$table->boolean('paid')->default(false);
+ $table->boolean('is_abo')->default(false);
+ $table->unsignedTinyInteger('abo_interval')->nullable();
+
$table->string('wp_invoice_path', 255)->nullable();
$table->text('api_notice')->nullable();
$table->unsignedTinyInteger('api_status')->nullable();
diff --git a/database/migrations/2019_02_23_163832_create_shopping_payments_table.php b/database/migrations/2019_02_23_163832_create_shopping_payments_table.php
index b47d1017..16ff321d 100644
--- a/database/migrations/2019_02_23_163832_create_shopping_payments_table.php
+++ b/database/migrations/2019_02_23_163832_create_shopping_payments_table.php
@@ -28,6 +28,9 @@ class CreateShoppingPaymentsTable extends Migration
$table->string('status', 10)->nullable()->index();
$table->string('txaction', 20)->nullable()->index();
+
+ $table->boolean('is_abo')->default(false);
+ $table->unsignedTinyInteger('abo_interval')->nullable();
$table->char('mode', 4)->nullable();
diff --git a/database/migrations/2019_02_29_170559_create_user_accounts_table.php b/database/migrations/2019_02_29_170559_create_user_accounts_table.php
index da7c68ec..e102a5a3 100644
--- a/database/migrations/2019_02_29_170559_create_user_accounts_table.php
+++ b/database/migrations/2019_02_29_170559_create_user_accounts_table.php
@@ -43,7 +43,7 @@ class CreateUserAccountsTable extends Migration
$table->string('tax_identification_number', 20)->nullable();
$table->unsignedTinyInteger('taxable_sales')->nullable();
- $table->boolean('reverse_charge')->default(true);
+ $table->boolean('reverse_charge')->default(false);
$table->char('reverse_charge_code', 2)->nullable();
$table->timestamp('reverse_charge_valid')->nullable();
diff --git a/database/migrations/2020_03_07_101227_create_user_histories_table.php b/database/migrations/2020_03_07_101227_create_user_histories_table.php
index 00907ccb..e751a198 100644
--- a/database/migrations/2020_03_07_101227_create_user_histories_table.php
+++ b/database/migrations/2020_03_07_101227_create_user_histories_table.php
@@ -25,6 +25,8 @@ class CreateUserHistoriesTable extends Migration
$table->string('identifier')->index()->nullable();
$table->boolean('abo_options')->default(false);
+ $table->boolean('is_abo')->default(false);
+
$table->unsignedTinyInteger('status')->index()->default(0);
diff --git a/database/migrations/2020_07_25_131854_create_payment_methods_table.php b/database/migrations/2020_07_25_131854_create_payment_methods_table.php
index 3b7fbd3f..367acccd 100644
--- a/database/migrations/2020_07_25_131854_create_payment_methods_table.php
+++ b/database/migrations/2020_07_25_131854_create_payment_methods_table.php
@@ -22,6 +22,7 @@ class CreatePaymentMethodsTable extends Migration
$table->unsignedTinyInteger('pos')->nullable()->default(0);
$table->boolean('active')->default(false);
$table->boolean('default')->default(false);
+ $table->boolean('is_abo')->default(false);
$table->timestamps();
});
diff --git a/database/migrations/2020_10_15_151059_create_homeparties_table.php b/database/migrations/2020_10_15_151059_create_homeparties_table.php
index 668b3f04..79a5c1cd 100644
--- a/database/migrations/2020_10_15_151059_create_homeparties_table.php
+++ b/database/migrations/2020_10_15_151059_create_homeparties_table.php
@@ -19,6 +19,7 @@ class CreateHomepartiesTable extends Migration
$table->string('name')->nullable();
$table->string('place')->nullable();
$table->text('description')->nullable();
+ $table->text('trans_description')->nullable();
$table->unsignedTinyInteger('pos')->default(0);
$table->unsignedTinyInteger('completed')->default(0);
diff --git a/database/migrations/2020_11_09_164147_create_ingredients_table.php b/database/migrations/2020_11_09_164147_create_ingredients_table.php
index 9446ab19..006f3d90 100644
--- a/database/migrations/2020_11_09_164147_create_ingredients_table.php
+++ b/database/migrations/2020_11_09_164147_create_ingredients_table.php
@@ -17,13 +17,8 @@ class CreateIngredientsTable extends Migration
$table->increments('id');
$table->string('name')->index();
- $table->text('trans_name')->nullable();
-
$table->text('inci')->nullable();
- $table->mediumText('trans_inci')->nullable();
-
$table->text('effect')->nullable();
- $table->mediumText('trans_effect')->nullable();
$table->boolean('active')->default(false);
$table->unsignedTinyInteger('pos')->nullable()->default(0);
@@ -42,4 +37,4 @@ class CreateIngredientsTable extends Migration
{
Schema::dropIfExists('ingredients');
}
-}
+}
\ No newline at end of file
diff --git a/database/migrations/2022_03_08_102231_create_user_sales_volumes_table.php b/database/migrations/2022_03_08_102231_create_user_sales_volumes_table.php
index 62b1cdba..145ef6fb 100644
--- a/database/migrations/2022_03_08_102231_create_user_sales_volumes_table.php
+++ b/database/migrations/2022_03_08_102231_create_user_sales_volumes_table.php
@@ -27,6 +27,7 @@ class CreateUserSalesVolumesTable extends Migration
$table->integer('month_points')->nullable();
$table->integer('month_shop_points')->nullable();
$table->unsignedTinyInteger('status_points')->index()->default(1);
+ $table->unsignedTinyInteger('status_turnover')->index()->default(1);
$table->decimal('total_net', 13, 2)->nullable();
$table->decimal('month_total_net', 13, 2)->nullable();
diff --git a/database/migrations/2022_07_28_140152_create_user_businesses_table.php b/database/migrations/2022_07_28_140152_create_user_businesses_table.php
index c3bf4ec3..596ac273 100644
--- a/database/migrations/2022_07_28_140152_create_user_businesses_table.php
+++ b/database/migrations/2022_07_28_140152_create_user_businesses_table.php
@@ -39,6 +39,8 @@ class CreateUserBusinessesTable extends Migration
$table->string('email')->nullable();
$table->string('first_name')->nullable();
$table->string('last_name')->nullable();
+ $table->string('user_birthday')->nullable();
+ $table->string('user_phone')->nullable();
$table->integer('sales_volume_KP_points')->nullable();
$table->integer('sales_volume_TP_points')->nullable();
diff --git a/database/migrations/2022_07_29_141050_create_user_credit_items_table.php b/database/migrations/2022_07_29_141050_create_user_credit_items_table.php
index 23251508..69686d76 100644
--- a/database/migrations/2022_07_29_141050_create_user_credit_items_table.php
+++ b/database/migrations/2022_07_29_141050_create_user_credit_items_table.php
@@ -21,6 +21,8 @@ class CreateUserCreditItemsTable extends Migration
$table->decimal('credit', 13, 2)->nullable();
$table->text('message')->nullable();
$table->unsignedTinyInteger('status')->index()->default(0);
+ $table->unsignedTinyInteger('from_month')->nullable();
+ $table->unsignedSmallInteger('from_year')->nullable();
$table->boolean('paid')->default(false);
$table->timestamps();
@@ -44,4 +46,4 @@ class CreateUserCreditItemsTable extends Migration
{
Schema::dropIfExists('user_credit_items');
}
-}
+}
\ No newline at end of file
diff --git a/database/migrations/2022_10_05_150515_create_product_buyings_table.php b/database/migrations/2022_10_05_150515_create_product_buyings_table.php
index 000b4ee7..5d35bf62 100644
--- a/database/migrations/2022_10_05_150515_create_product_buyings_table.php
+++ b/database/migrations/2022_10_05_150515_create_product_buyings_table.php
@@ -43,4 +43,4 @@ class CreateProductBuyingsTable extends Migration
{
Schema::dropIfExists('product_buyings');
}
-}
+}
\ No newline at end of file
diff --git a/database/migrations/2023_08_04_150515_create_user_clean_up_logs_table.php b/database/migrations/2023_08_04_150515_create_user_clean_up_logs_table.php
new file mode 100644
index 00000000..86b9e6fd
--- /dev/null
+++ b/database/migrations/2023_08_04_150515_create_user_clean_up_logs_table.php
@@ -0,0 +1,49 @@
+increments('id');
+ $table->unsignedInteger('inactive_sponsor_id');
+ $table->unsignedInteger('child_user_id');
+ $table->unsignedInteger('new_sponsor_id');
+
+ $table->timestamps();
+
+ $table->foreign('inactive_sponsor_id')
+ ->references('id')
+ ->on('users')
+ ->onDelete('cascade');
+
+ $table->foreign('child_user_id')
+ ->references('id')
+ ->on('users')
+ ->onDelete('cascade');
+
+ $table->foreign('new_sponsor_id')
+ ->references('id')
+ ->on('users');
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::dropIfExists('user_clean_up_logs');
+ }
+}
diff --git a/database/migrations/2023_08_04_150520_create_shopping_user_member_logs_table.php b/database/migrations/2023_08_04_150520_create_shopping_user_member_logs_table.php
new file mode 100644
index 00000000..6606d58c
--- /dev/null
+++ b/database/migrations/2023_08_04_150520_create_shopping_user_member_logs_table.php
@@ -0,0 +1,49 @@
+increments('id');
+ $table->unsignedInteger('pre_member_id');
+ $table->unsignedInteger('shopping_user_id');
+ $table->unsignedInteger('new_member_id');
+
+ $table->timestamps();
+
+ $table->foreign('pre_member_id')
+ ->references('id')
+ ->on('users')
+ ->onDelete('cascade');
+
+ $table->foreign('shopping_user_id')
+ ->references('id')
+ ->on('shopping_users')
+ ->onDelete('cascade');
+
+ $table->foreign('new_member_id')
+ ->references('id')
+ ->on('users');
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::dropIfExists('shopping_user_member_logs');
+ }
+}
diff --git a/database/migrations/2023_09_21_114444_create_trans_products_table.php b/database/migrations/2023_09_21_114444_create_trans_products_table.php
new file mode 100644
index 00000000..18d54843
--- /dev/null
+++ b/database/migrations/2023_09_21_114444_create_trans_products_table.php
@@ -0,0 +1,41 @@
+increments('id');
+ $table->char('language', 2)->index();
+ $table->unsignedInteger('product_id')->index();
+
+ $table->string('key')->nullable();
+ $table->text('value')->nullable();
+ $table->timestamps();
+
+ $table->foreign('product_id')
+ ->references('id')
+ ->on('products');
+
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::dropIfExists('trans_products');
+ }
+}
diff --git a/database/migrations/2023_09_22_114444_create_trans_ingredients_table.php b/database/migrations/2023_09_22_114444_create_trans_ingredients_table.php
new file mode 100644
index 00000000..563baf3d
--- /dev/null
+++ b/database/migrations/2023_09_22_114444_create_trans_ingredients_table.php
@@ -0,0 +1,42 @@
+increments('id');
+ $table->char('language', 2)->index();
+ $table->unsignedInteger('ingredient_id')->index();
+
+ $table->string('key')->nullable();
+ $table->text('value')->nullable();
+ $table->timestamps();
+
+
+ $table->foreign('ingredient_id')
+ ->references('id')
+ ->on('ingredients');
+
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::dropIfExists('trans_ingredients');
+ }
+}
diff --git a/database/migrations/2023_09_22_114445_create_trans_user_levels_table.php b/database/migrations/2023_09_22_114445_create_trans_user_levels_table.php
new file mode 100644
index 00000000..2a4928d7
--- /dev/null
+++ b/database/migrations/2023_09_22_114445_create_trans_user_levels_table.php
@@ -0,0 +1,41 @@
+increments('id');
+ $table->char('language', 2)->index();
+ $table->unsignedInteger('user_level_id')->index();
+
+ $table->string('key')->nullable();
+ $table->text('value')->nullable();
+ $table->timestamps();
+
+ $table->foreign('user_level_id')
+ ->references('id')
+ ->on('user_levels');
+
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::dropIfExists('trans_user_levels');
+ }
+}
diff --git a/database/migrations/2023_09_22_114446_create_trans_shippings_table.php b/database/migrations/2023_09_22_114446_create_trans_shippings_table.php
new file mode 100644
index 00000000..720f9918
--- /dev/null
+++ b/database/migrations/2023_09_22_114446_create_trans_shippings_table.php
@@ -0,0 +1,41 @@
+increments('id');
+ $table->char('language', 2)->index();
+ $table->unsignedInteger('shipping_id')->index();
+
+ $table->string('key')->nullable();
+ $table->text('value')->nullable();
+ $table->timestamps();
+
+ $table->foreign('shipping_id')
+ ->references('id')
+ ->on('shippings');
+
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::dropIfExists('trans_shippings');
+ }
+}
diff --git a/database/migrations/2023_09_22_114447_create_trans_categories_table.php b/database/migrations/2023_09_22_114447_create_trans_categories_table.php
new file mode 100644
index 00000000..8e25c63c
--- /dev/null
+++ b/database/migrations/2023_09_22_114447_create_trans_categories_table.php
@@ -0,0 +1,41 @@
+increments('id');
+ $table->char('language', 2)->index();
+ $table->unsignedInteger('categorie_id')->index();
+
+ $table->string('key')->nullable();
+ $table->text('value')->nullable();
+ $table->timestamps();
+
+ $table->foreign('categorie_id')
+ ->references('id')
+ ->on('categories');
+
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::dropIfExists('trans_categories');
+ }
+}
diff --git a/database/migrations/2024_02_29_161426_create_dc_categories_table.php b/database/migrations/2024_02_29_161426_create_dc_categories_table.php
new file mode 100644
index 00000000..e2ea41c2
--- /dev/null
+++ b/database/migrations/2024_02_29_161426_create_dc_categories_table.php
@@ -0,0 +1,35 @@
+increments('id');
+ $table->string('name')->index();
+ $table->unsignedTinyInteger('pos')->default(0);
+ $table->string('slug')->unique();
+ $table->boolean('active')->default(true);
+ $table->timestamps();
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::dropIfExists('dc_categories');
+ }
+}
diff --git a/database/migrations/2024_02_29_161433_create_dc_tags_table.php b/database/migrations/2024_02_29_161433_create_dc_tags_table.php
new file mode 100644
index 00000000..e45553b9
--- /dev/null
+++ b/database/migrations/2024_02_29_161433_create_dc_tags_table.php
@@ -0,0 +1,36 @@
+increments('id');
+ $table->unsignedInteger('category_id')->nullable();
+ $table->string('name')->index();
+ $table->unsignedTinyInteger('pos')->default(0);
+ $table->string('slug')->unique();
+ $table->boolean('active')->default(true);
+ $table->timestamps();
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::dropIfExists('dc_tags');
+ }
+}
diff --git a/database/migrations/2024_02_29_161438_create_dc_files_table.php b/database/migrations/2024_02_29_161438_create_dc_files_table.php
new file mode 100644
index 00000000..356a3228
--- /dev/null
+++ b/database/migrations/2024_02_29_161438_create_dc_files_table.php
@@ -0,0 +1,37 @@
+increments('id');
+ $table->string('filename')->index();
+ $table->string('original_name')->index();
+ $table->string('ext')->index();
+ $table->string('mine')->default('');
+ $table->integer('size')->nullable();
+ $table->tinyInteger('active')->nullable()->default(1);
+ $table->timestamps();
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::dropIfExists('dc_files');
+ }
+}
diff --git a/database/migrations/2024_02_29_161442_create_dc_file_tags_table.php b/database/migrations/2024_02_29_161442_create_dc_file_tags_table.php
new file mode 100644
index 00000000..98253a72
--- /dev/null
+++ b/database/migrations/2024_02_29_161442_create_dc_file_tags_table.php
@@ -0,0 +1,36 @@
+increments('id');
+ $table->unsignedInteger('file_id');
+ $table->unsignedInteger('tag_id');
+ $table->timestamps();
+
+ $table->foreign('file_id')->references('id')->on('dc_files')->onDelete('cascade');;
+ $table->foreign('tag_id')->references('id')->on('dc_tags')->onDelete('cascade');;
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::dropIfExists('dc_file_tags');
+ }
+}
diff --git a/database/migrations/2024_07_08_121926_create_dbip_lookup_2_table.php b/database/migrations/2024_07_08_121926_create_dbip_lookup_2_table.php
new file mode 100644
index 00000000..9a329212
--- /dev/null
+++ b/database/migrations/2024_07_08_121926_create_dbip_lookup_2_table.php
@@ -0,0 +1,35 @@
+enum('addr_type', ['ipv4', 'ipv6'])->index();
+ $table->string('ip_start', 16)->index();
+ $table->string('ip_end', 16);
+ $table->char('country', 2);
+ });
+
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::dropIfExists('dbip_lookup_2');
+ }
+}
diff --git a/database/migrations/2024_07_08_121926_create_dbip_lookup_3_table.php b/database/migrations/2024_07_08_121926_create_dbip_lookup_3_table.php
new file mode 100644
index 00000000..92eb79da
--- /dev/null
+++ b/database/migrations/2024_07_08_121926_create_dbip_lookup_3_table.php
@@ -0,0 +1,35 @@
+enum('addr_type', ['ipv4', 'ipv6'])->index();
+ $table->string('ip_start', 16)->index();
+ $table->string('ip_end', 16);
+ $table->char('country', 2);
+ });
+
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::dropIfExists('dbip_lookup_3');
+ }
+}
diff --git a/database/migrations/2024_07_08_121926_create_dbip_lookup_table.php b/database/migrations/2024_07_08_121926_create_dbip_lookup_table.php
new file mode 100644
index 00000000..3b0eae24
--- /dev/null
+++ b/database/migrations/2024_07_08_121926_create_dbip_lookup_table.php
@@ -0,0 +1,35 @@
+enum('addr_type', ['ipv4', 'ipv6'])->index();
+ $table->string('ip_start', 16)->index();
+ $table->string('ip_end', 16);
+ $table->char('country', 2);
+ });
+
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::dropIfExists('dbip_lookup');
+ }
+}
diff --git a/database/migrations/2024_07_29_144455_create_user_abos_table.php b/database/migrations/2024_07_29_144455_create_user_abos_table.php
new file mode 100644
index 00000000..7512c0f5
--- /dev/null
+++ b/database/migrations/2024_07_29_144455_create_user_abos_table.php
@@ -0,0 +1,63 @@
+increments('id');
+ $table->unsignedInteger('user_id')->nullable();
+ $table->unsignedInteger('shopping_user_id');
+ $table->char('is_for', 2)->nullable();
+
+ $table->unsignedInteger('payone_userid');
+ $table->string('clearingtype',3);
+ $table->string('wallettype', 3)->nullable();
+ $table->unsignedInteger('amount');
+ $table->string('currency', 6);
+
+ $table->boolean('active')->default(true);
+ $table->unsignedTinyInteger('status')->index()->default(0);
+
+ $table->unsignedTinyInteger('abo_interval')->default(0);
+ $table->date('start_date')->nullable();
+ $table->date('last_date')->nullable();
+ $table->date('next_date')->nullable();
+ $table->date('cancel_date')->nullable();
+
+ $table->unsignedTinyInteger('count')->default(0);
+
+
+ $table->timestamps();
+ $table->softDeletes();
+ $table->timestamp('user_deleted_at')->nullable();
+
+ $table->foreign('user_id')
+ ->references('id')
+ ->on('users');
+
+ $table->foreign('shopping_user_id')
+ ->references('id')
+ ->on('shopping_users');
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::dropIfExists('user_abos');
+ }
+}
diff --git a/database/migrations/2024_07_29_144611_create_user_abo_orders_table.php b/database/migrations/2024_07_29_144611_create_user_abo_orders_table.php
new file mode 100644
index 00000000..14872f92
--- /dev/null
+++ b/database/migrations/2024_07_29_144611_create_user_abo_orders_table.php
@@ -0,0 +1,45 @@
+increments('id');
+ $table->unsignedInteger('user_abo_id');
+ $table->unsignedInteger('shopping_order_id');
+ $table->unsignedTinyInteger('status')->index()->default(0);
+ $table->timestamps();
+
+ $table->foreign('user_abo_id')
+ ->references('id')
+ ->on('user_abos')
+ ->onDelete('cascade');
+
+ $table->foreign('shopping_order_id')
+ ->references('id')
+ ->on('shopping_orders');
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::dropIfExists('user_abo_orders');
+ }
+}
diff --git a/packages/digital-bird/shoppingcart/.editorconfig b/packages/digital-bird/shoppingcart/.editorconfig
new file mode 100644
index 00000000..6d2b9ea9
--- /dev/null
+++ b/packages/digital-bird/shoppingcart/.editorconfig
@@ -0,0 +1,18 @@
+root = true
+
+[*]
+charset = utf-8
+end_of_line = lf
+insert_final_newline = true
+indent_style = space
+indent_size = 4
+trim_trailing_whitespace = true
+
+[*.scss]
+indent_size = 2
+
+[*.md]
+trim_trailing_whitespace = false
+
+[*.yml]
+indent_size = 2
diff --git a/packages/digital-bird/shoppingcart/.gitignore b/packages/digital-bird/shoppingcart/.gitignore
new file mode 100644
index 00000000..0b271013
--- /dev/null
+++ b/packages/digital-bird/shoppingcart/.gitignore
@@ -0,0 +1,5 @@
+/vendor
+composer.phar
+composer.lock
+.DS_Store
+/.idea
diff --git a/packages/digital-bird/shoppingcart/.travis.yml b/packages/digital-bird/shoppingcart/.travis.yml
new file mode 100644
index 00000000..6a80a0b6
--- /dev/null
+++ b/packages/digital-bird/shoppingcart/.travis.yml
@@ -0,0 +1,10 @@
+language: php
+
+php:
+ - 7.0
+
+before_script:
+ - composer self-update
+ - composer install --prefer-source --no-interaction
+
+script: vendor/bin/phpunit
diff --git a/packages/digital-bird/shoppingcart/LICENSE b/packages/digital-bird/shoppingcart/LICENSE
new file mode 100644
index 00000000..61c6afc7
--- /dev/null
+++ b/packages/digital-bird/shoppingcart/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 Rob Gloudemans
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
\ No newline at end of file
diff --git a/packages/digital-bird/shoppingcart/README.md b/packages/digital-bird/shoppingcart/README.md
new file mode 100644
index 00000000..c03bb4c6
--- /dev/null
+++ b/packages/digital-bird/shoppingcart/README.md
@@ -0,0 +1,491 @@
+## LaravelShoppingcart
+[](https://packagist.org/packages/gloudemans/shoppingcart)
+
+A simple shoppingcart implementation for Laravel.
+
+## Installation
+
+Install the package through [Composer](http://getcomposer.org/).
+
+Run the Composer require command from the Terminal:
+
+ composer require digital-bird/shoppingcart
+
+If you're using Laravel 5.5, this is all there is to do.
+
+Should you still be on version 5.4 of Laravel, the final steps for you are to add the service provider of the package and alias the package. To do this open your `config/app.php` file.
+
+Add a new line to the `providers` array:
+
+ Gloudemans\Shoppingcart\ShoppingcartServiceProvider::class
+
+And optionally add a new line to the `aliases` array:
+
+ 'Cart' => Gloudemans\Shoppingcart\Facades\Cart::class,
+
+Now you're ready to start using the shoppingcart in your application.
+
+**As of version 2 of this package it's possibly to use dependency injection to inject an instance of the Cart class into your controller or other class**
+
+## Overview
+Look at one of the following topics to learn more about LaravelShoppingcart
+
+* [Usage](#usage)
+* [Collections](#collections)
+* [Instances](#instances)
+* [Models](#models)
+* [Database](#database)
+* [Exceptions](#exceptions)
+* [Events](#events)
+* [Example](#example)
+
+## Usage
+
+The shoppingcart gives you the following methods to use:
+
+### Cart::add()
+
+Adding an item to the cart is really simple, you just use the `add()` method, which accepts a variety of parameters.
+
+In its most basic form you can specify the id, name, quantity, price, and tax rate of the product you'd like to add to the cart.
+
+```php
+Cart::add('293ad', 'Product 1', 1, 9.99, 10);
+```
+
+As an optional sixth parameter you can pass it options, so you can add multiple items with the same id, but with (for instance) a different size.
+
+The fifth parameter is the tax rate. Eg 10 for 10%.
+
+```php
+Cart::add('293ad', 'Product 1', 1, 9.99, 10, ['size' => 'large']);
+```
+
+**The `add()` method will return an CartItem instance of the item you just added to the cart.**
+
+Maybe you prefer to add the item using an array? As long as the array contains the required keys, you can pass it to the method. The options key is optional.
+
+```php
+Cart::add(['id' => '293ad', 'name' => 'Product 1', 'qty' => 1, 'price' => 9.99, 'taxRate' => 10, 'options' => ['size' => 'large']]);
+```
+
+New in version 2 of the package is the possibility to work with the [Buyable](#buyable) interface. The way this works is that you have a model implement the `Buyable` interface, which will make you implement a few methods so the package knows how to get the id, name and price from your model.
+This way you can just pass the `add()` method a model and the quantity and it will automatically add it to the cart.
+
+The path to the `Buyable` interface is:
+
+ Gloudemans\Shoppingcart\Contracts\Buyable;
+
+**As an added bonus it will automatically associate the model with the CartItem**
+
+```php
+Cart::add($product, 1, ['size' => 'large']);
+```
+As an optional third parameter you can add options.
+```php
+Cart::add($product, 1, ['size' => 'large']);
+```
+
+Finally, you can also add multipe items to the cart at once.
+You can just pass the `add()` method an array of arrays, or an array of Buyables and they will be added to the cart.
+
+**When adding multiple items to the cart, the `add()` method will return an array of CartItems.**
+
+```php
+Cart::add([
+ ['id' => '293ad', 'name' => 'Product 1', 'qty' => 1, 'price' => 10.00, 'taxRate' => 10],
+ ['id' => '4832k', 'name' => 'Product 2', 'qty' => 1, 'price' => 10.00, 'taxRate' => 10, 'options' => ['size' => 'large']]
+]);
+
+Cart::add([$product1, $product2]);
+
+```
+
+### Cart::update()
+
+To update an item in the cart, you'll first need the rowId of the item.
+Next you can use the `update()` method to update it.
+
+If you simply want to update the quantity, you'll pass the update method the rowId and the new quantity:
+
+```php
+$rowId = 'da39a3ee5e6b4b0d3255bfef95601890afd80709';
+
+Cart::update($rowId, 2); // Will update the quantity
+```
+
+If you want to update more attributes of the item, you can either pass the update method an array or a `Buyable` as the second parameter. This way you can update all information of the item with the given rowId.
+
+```php
+Cart::update($rowId, ['name' => 'Product 1']); // Will update the name
+
+Cart::update($rowId, $product); // Will update the id, name and price
+
+```
+
+### Cart::remove()
+
+To remove an item for the cart, you'll again need the rowId. This rowId you simply pass to the `remove()` method and it will remove the item from the cart.
+
+```php
+$rowId = 'da39a3ee5e6b4b0d3255bfef95601890afd80709';
+
+Cart::remove($rowId);
+```
+
+### Cart::get()
+
+If you want to get an item from the cart using its rowId, you can simply call the `get()` method on the cart and pass it the rowId.
+
+```php
+$rowId = 'da39a3ee5e6b4b0d3255bfef95601890afd80709';
+
+Cart::get($rowId);
+```
+
+### Cart::content()
+
+Of course you also want to get the carts content. This is where you'll use the `content` method. This method will return a Collection of CartItems which you can iterate over and show the content to your customers.
+
+```php
+Cart::content();
+```
+
+This method will return the content of the current cart instance, if you want the content of another instance, simply chain the calls.
+
+```php
+Cart::instance('wishlist')->content();
+```
+
+### Cart::destroy()
+
+If you want to completely remove the content of a cart, you can call the destroy method on the cart. This will remove all CartItems from the cart for the current cart instance.
+
+```php
+Cart::destroy();
+```
+
+### Cart::total()
+
+The `total()` method can be used to get the calculated total of all items in the cart, given there price and quantity.
+
+```php
+Cart::total();
+```
+
+The method will automatically format the result, which you can tweak using the three optional parameters
+
+```php
+Cart::total($decimals, $decimalSeperator, $thousandSeperator);
+```
+
+You can set the default number format in the config file.
+
+**If you're not using the Facade, but use dependency injection in your (for instance) Controller, you can also simply get the total property `$cart->total`**
+
+### Cart::tax()
+
+The `tax()` method can be used to get the calculated amount of tax for all items in the cart, given there price and quantity.
+
+```php
+Cart::tax();
+```
+
+The method will automatically format the result, which you can tweak using the three optional parameters
+
+```php
+Cart::tax($decimals, $decimalSeperator, $thousandSeperator);
+```
+
+You can set the default number format in the config file.
+
+**If you're not using the Facade, but use dependency injection in your (for instance) Controller, you can also simply get the tax property `$cart->tax`**
+
+### Cart::subtotal()
+
+The `subtotal()` method can be used to get the total of all items in the cart, minus the total amount of tax.
+
+```php
+Cart::subtotal();
+```
+
+The method will automatically format the result, which you can tweak using the three optional parameters
+
+```php
+Cart::subtotal($decimals, $decimalSeperator, $thousandSeperator);
+```
+
+You can set the default number format in the config file.
+
+**If you're not using the Facade, but use dependency injection in your (for instance) Controller, you can also simply get the subtotal property `$cart->subtotal`**
+
+### Cart::count()
+
+If you want to know how many items there are in your cart, you can use the `count()` method. This method will return the total number of items in the cart. So if you've added 2 books and 1 shirt, it will return 3 items.
+
+```php
+Cart::count();
+```
+
+### Cart::search()
+
+To find an item in the cart, you can use the `search()` method.
+
+**This method was changed on version 2**
+
+Behind the scenes, the method simply uses the filter method of the Laravel Collection class. This means you must pass it a Closure in which you'll specify you search terms.
+
+If you for instance want to find all items with an id of 1:
+
+```php
+$cart->search(function ($cartItem, $rowId) {
+ return $cartItem->id === 1;
+});
+```
+
+As you can see the Closure will receive two parameters. The first is the CartItem to perform the check against. The second parameter is the rowId of this CartItem.
+
+**The method will return a Collection containing all CartItems that where found**
+
+This way of searching gives you total control over the search process and gives you the ability to create very precise and specific searches.
+
+## Collections
+
+On multiple instances the Cart will return to you a Collection. This is just a simple Laravel Collection, so all methods you can call on a Laravel Collection are also available on the result.
+
+As an example, you can quicky get the number of unique products in a cart:
+
+```php
+Cart::content()->count();
+```
+
+Or you can group the content by the id of the products:
+
+```php
+Cart::content()->groupBy('id');
+```
+
+## Instances
+
+The packages supports multiple instances of the cart. The way this works is like this:
+
+You can set the current instance of the cart by calling `Cart::instance('newInstance')`. From this moment, the active instance of the cart will be `newInstance`, so when you add, remove or get the content of the cart, you're work with the `newInstance` instance of the cart.
+If you want to switch instances, you just call `Cart::instance('otherInstance')` again, and you're working with the `otherInstance` again.
+
+So a little example:
+
+```php
+Cart::instance('shopping')->add('192ao12', 'Product 1', 1, 9.99);
+
+// Get the content of the 'shopping' cart
+Cart::content();
+
+Cart::instance('wishlist')->add('sdjk922', 'Product 2', 1, 19.95, ['size' => 'medium']);
+
+// Get the content of the 'wishlist' cart
+Cart::content();
+
+// If you want to get the content of the 'shopping' cart again
+Cart::instance('shopping')->content();
+
+// And the count of the 'wishlist' cart again
+Cart::instance('wishlist')->count();
+```
+
+**N.B. Keep in mind that the cart stays in the last set instance for as long as you don't set a different one during script execution.**
+
+**N.B.2 The default cart instance is called `default`, so when you're not using instances,`Cart::content();` is the same as `Cart::instance('default')->content()`.**
+
+## Models
+
+Because it can be very convenient to be able to directly access a model from a CartItem is it possible to associate a model with the items in the cart. Let's say you have a `Product` model in your application. With the `associate()` method, you can tell the cart that an item in the cart, is associated to the `Product` model.
+
+That way you can access your model right from the `CartItem`!
+
+The model can be accessed via the `model` property on the CartItem.
+
+**If your model implements the `Buyable` interface and you used your model to add the item to the cart, it will associate automatically.**
+
+Here is an example:
+
+```php
+
+// First we'll add the item to the cart.
+$cartItem = Cart::add('293ad', 'Product 1', 1, 9.99, ['size' => 'large']);
+
+// Next we associate a model with the item.
+Cart::associate($cartItem->rowId, 'Product');
+
+// Or even easier, call the associate method on the CartItem!
+$cartItem->associate('Product');
+
+// You can even make it a one-liner
+Cart::add('293ad', 'Product 1', 1, 9.99, ['size' => 'large'])->associate('Product');
+
+// Now, when iterating over the content of the cart, you can access the model.
+foreach(Cart::content() as $row) {
+ echo 'You have ' . $row->qty . ' items of ' . $row->model->name . ' with description: "' . $row->model->description . '" in your cart.';
+}
+```
+
+### Buyable
+
+For the convenience of faster adding items to cart and their automatic association, your model can implement `Buyable` interface. To do so, it must implement such functions:
+
+```php
+ public function getBuyableIdentifier(){
+ return $this->id;
+ }
+
+ public function getBuyableDescription(){
+ return $this->name;
+ }
+
+ public function getBuyablePrice(){
+ return $this->price;
+ }
+```
+
+Example:
+
+```php
+id;
+ }
+
+ public function getBuyableDescription($options = null) {
+ return $this->name;
+ }
+
+ public function getBuyablePrice($options = null) {
+ return $this->price;
+ }
+}
+```
+
+
+## Database
+
+- [Config](#configuration)
+- [Storing the cart](#storing-the-cart)
+- [Restoring the cart](#restoring-the-cart)
+
+### Configuration
+To save cart into the database so you can retrieve it later, the package needs to know which database connection to use and what the name of the table is.
+By default the package will use the default database connection and use a table named `shoppingcart`.
+If you want to change these options, you'll have to publish the `config` file.
+
+ php artisan vendor:publish --provider="Gloudemans\Shoppingcart\ShoppingcartServiceProvider" --tag="config"
+
+This will give you a `cart.php` config file in which you can make the changes.
+
+To make your life easy, the package also includes a ready to use `migration` which you can publish by running:
+
+ php artisan vendor:publish --provider="Gloudemans\Shoppingcart\ShoppingcartServiceProvider" --tag="migrations"
+
+This will place a `shoppingcart` table's migration file into `database/migrations` directory. Now all you have to do is run `php artisan migrate` to migrate your database.
+
+### Storing the cart
+To store your cart instance into the database, you have to call the `store($identifier) ` method. Where `$identifier` is a random key, for instance the id or username of the user.
+
+ Cart::store('username');
+
+ // To store a cart instance named 'wishlist'
+ Cart::instance('wishlist')->store('username');
+
+### Restoring the cart
+If you want to retrieve the cart from the database and restore it, all you have to do is call the `restore($identifier)` where `$identifier` is the key you specified for the `store` method.
+
+ Cart::restore('username');
+
+ // To restore a cart instance named 'wishlist'
+ Cart::instance('wishlist')->restore('username');
+
+## Exceptions
+
+The Cart package will throw exceptions if something goes wrong. This way it's easier to debug your code using the Cart package or to handle the error based on the type of exceptions. The Cart packages can throw the following exceptions:
+
+| Exception | Reason |
+| ---------------------------- | ---------------------------------------------------------------------------------- |
+| *CartAlreadyStoredException* | When trying to store a cart that was already stored using the specified identifier |
+| *InvalidRowIDException* | When the rowId that got passed doesn't exists in the current cart instance |
+| *UnknownModelException* | When you try to associate an none existing model to a CartItem. |
+
+## Events
+
+The cart also has events build in. There are five events available for you to listen for.
+
+| Event | Fired | Parameter |
+| ------------- | ---------------------------------------- | -------------------------------- |
+| cart.added | When an item was added to the cart. | The `CartItem` that was added. |
+| cart.updated | When an item in the cart was updated. | The `CartItem` that was updated. |
+| cart.removed | When an item is removed from the cart. | The `CartItem` that was removed. |
+| cart.stored | When the content of a cart was stored. | - |
+| cart.restored | When the content of a cart was restored. | - |
+
+## Example
+
+Below is a little example of how to list the cart content in a table:
+
+```php
+
+// Add some items in your Controller.
+Cart::add('192ao12', 'Product 1', 1, 9.99);
+Cart::add('1239ad0', 'Product 2', 2, 5.95, ['size' => 'large']);
+
+// Display the content in a View.
+
+
+
+ Product
+ Qty
+ Price
+ Subtotal
+
+
+
+
+
+
+
+
+
+ name; ?>
+ options->has('size') ? $row->options->size : ''); ?>
+
+
+ $price; ?>
+ $total; ?>
+
+
+
+
+
+
+
+
+
+ Subtotal
+
+
+
+
+ Tax
+
+
+
+
+ Total
+
+
+
+
+```
diff --git a/packages/digital-bird/shoppingcart/composer.json b/packages/digital-bird/shoppingcart/composer.json
new file mode 100644
index 00000000..8f66a168
--- /dev/null
+++ b/packages/digital-bird/shoppingcart/composer.json
@@ -0,0 +1,49 @@
+{
+ "name": "digital-bird/shoppingcart",
+ "description": "Laravel Shoppingcart",
+ "keywords": [
+ "laravel",
+ "shoppingcart"
+ ],
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Rob Gloudemans",
+ "email": "info@robgloudemans.nl"
+ }
+ ],
+ "require": {
+ "illuminate/support": "5.1.*|5.2.*|5.3.*|5.4.*|5.5.*|5.6.*|5.7.*|5.8.*|6.*|7.*|8.*",
+ "illuminate/session": "5.1.*|5.2.*|5.3.*|5.4.*|5.5.*|5.6.*|5.7.*|5.8.*|6.*|7.*|8.*",
+ "illuminate/events": "5.1.*|5.2.*|5.3.*|5.4.*|5.5.*|5.6.*|5.7.*|5.8.*|6.*|7.*|8.*"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~5.0|~6.0|~7.0|~8.0|~9,0",
+ "mockery/mockery": "~0.9.0",
+ "orchestra/testbench": "~3.1"
+ },
+ "autoload": {
+ "psr-4": {
+ "Gloudemans\\Shoppingcart\\": "src/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Gloudemans\\Tests\\Shoppingcart\\": "tests/"
+ }
+ },
+ "suggest": {
+ "gloudemans/notify": "Simple flash notifications for Laravel"
+ },
+ "minimum-stability": "stable",
+ "extra": {
+ "laravel": {
+ "providers": [
+ "Gloudemans\\Shoppingcart\\ShoppingcartServiceProvider"
+ ],
+ "aliases": {
+ "Cart": "Gloudemans\\Shoppingcart\\Facades\\Cart"
+ }
+ }
+ }
+}
diff --git a/packages/digital-bird/shoppingcart/config/cart.php b/packages/digital-bird/shoppingcart/config/cart.php
new file mode 100644
index 00000000..51b34cfd
--- /dev/null
+++ b/packages/digital-bird/shoppingcart/config/cart.php
@@ -0,0 +1,105 @@
+ 10,
+
+ /*
+ |--------------------------------------------------------------------------
+ | Allow multiple rows with the same ID
+ |--------------------------------------------------------------------------
+ |
+ | By default, the row ID is generated to a MD5 based on ID + Options array.
+ | If you want to have more than one unique product in a cart, you either have
+ | to set a unique value in the Options array (eg Reason = X), or you can simply
+ | enable this option, and each time you add a new Cart row, it will add to the cart.
+ |
+ */
+ 'allow_multiple_same_id' => false,
+
+ /*
+ |--------------------------------------------------------------------------
+ | Shoppingcart database settings
+ |--------------------------------------------------------------------------
+ |
+ | Here you can set the connection that the shoppingcart should use when
+ | storing and restoring a cart.
+ |
+ */
+
+ 'database' => [
+
+ 'connection' => null,
+
+ 'table' => 'shoppingcart',
+
+ ],
+
+ /*
+ |--------------------------------------------------------------------------
+ | Destroy the cart on user logout
+ |--------------------------------------------------------------------------
+ |
+ | When this option is set to 'true' the cart will automatically
+ | destroy all cart instances when the user logs out.
+ |
+ */
+
+ 'destroy_on_logout' => false,
+
+ /*
+ |--------------------------------------------------------------------------
+ | Default number format
+ |--------------------------------------------------------------------------
+ |
+ | This defaults will be used for the formated numbers if you don't
+ | set them in the method call.
+ |
+ */
+
+ 'format' => [
+
+ // General rule with decimal points is that if it's a unit price then it should be 2 decimals,
+ // as that's what is displayed to the user. Once it's multiplied by quantity, it should be 4 decimals to
+ // account for that multiplication of qty, and the total tax, subtotal inc tax, and total should all reflect that,
+ // and only round to show the user at the absolute final stage.
+
+ 'price_ex_tax_decimals' => 2, // base unit price shown to user ex gst should be 2 by default.
+ 'price_inc_tax_decimals' => 2, // base unit price shown to user ex gst should be 2 by default.
+ 'fee_ex_tax_decimals' => 4, // fee ex tax should be 4 decimals.
+ 'fee_inc_tax_decimals' => 4, // fee inc tax should be 4 decimals.
+ 'fee_total_tax_decimals' => 4, // fee total tax should be 4 decimals.
+ 'tax_decimals' => 4, // unit price tax can be 4 decimals. Eg. $2.81 * 1.1 = $3.091 inc tax = $0.281 tax.
+ 'tax_total_decimals' => 4, // total tax can be 4 decimals. Eg. $0.281 * 12 qty = $3.372 total tax.
+ 'subtotal_ex_tax_decimals' => 4, // subtotal ex tax after qty should be 4 decimals by default, then round to show user after qty.
+ 'subtotal_inc_tax_decimals' => 4, // subtotal inc tax after qty should be 4 decimals by default, then round to show user after qty
+ 'total_decimals' => 4, // total after tax should be 4 decimals by default, then round to show user after qty.
+
+ // @deprecated
+ 'decimals' => 4,
+
+ 'decimal_point' => '.',
+
+ 'thousand_seperator' => ''
+
+ ],
+
+ /*
+ |--------------------------------------------------------------------------
+ | Allows you to choose if the discounts applied to fees
+ |--------------------------------------------------------------------------
+ |
+ */
+ 'discountOnFees' => false,
+
+];
diff --git a/packages/digital-bird/shoppingcart/database/migrations/0000_00_00_000000_create_shoppingcart_table.php b/packages/digital-bird/shoppingcart/database/migrations/0000_00_00_000000_create_shoppingcart_table.php
new file mode 100644
index 00000000..fc5bb26e
--- /dev/null
+++ b/packages/digital-bird/shoppingcart/database/migrations/0000_00_00_000000_create_shoppingcart_table.php
@@ -0,0 +1,30 @@
+string('identifier');
+ $table->string('instance');
+ $table->longText('content');
+ $table->nullableTimestamps();
+
+ $table->primary(['identifier', 'instance']);
+ });
+ }
+ /**
+ * Reverse the migrations.
+ */
+ public function down()
+ {
+ Schema::drop(config('cart.database.table'));
+ }
+}
diff --git a/packages/digital-bird/shoppingcart/phpunit.xml b/packages/digital-bird/shoppingcart/phpunit.xml
new file mode 100644
index 00000000..655d24e6
--- /dev/null
+++ b/packages/digital-bird/shoppingcart/phpunit.xml
@@ -0,0 +1,16 @@
+
+
+
+
+ ./tests/
+
+
+
\ No newline at end of file
diff --git a/packages/digital-bird/shoppingcart/src/CanBeBought.php b/packages/digital-bird/shoppingcart/src/CanBeBought.php
new file mode 100644
index 00000000..e122d1fc
--- /dev/null
+++ b/packages/digital-bird/shoppingcart/src/CanBeBought.php
@@ -0,0 +1,54 @@
+getKey() :
+ $this->id;
+ }
+
+ /**
+ * Get the description or title of the Buyable item.
+ *
+ * @return string
+ */
+ public function getBuyableDescription($options = null)
+ {
+ if (property_exists($this, 'name')) {
+ return $this->name;
+ }
+
+ if (property_exists($this, 'title')) {
+ return $this->title;
+ }
+
+ if (property_exists($this, 'description')) {
+ return $this->description;
+ }
+
+ return null;
+ }
+
+ /**
+ * Get the price of the Buyable item.
+ *
+ * @return float
+ */
+ public function getBuyablePrice($options = null)
+ {
+ if (property_exists($this, 'price')) {
+ return $this->price;
+ }
+
+ return null;
+ }
+}
diff --git a/packages/digital-bird/shoppingcart/src/Cart.php b/packages/digital-bird/shoppingcart/src/Cart.php
new file mode 100644
index 00000000..6309a4c5
--- /dev/null
+++ b/packages/digital-bird/shoppingcart/src/Cart.php
@@ -0,0 +1,842 @@
+items = new Collection;
+ $this->fees = new Collection;
+ $this->session = $session;
+ $this->events = $events;
+
+ $this->instance(self::DEFAULT_INSTANCE);
+ }
+
+ /**
+ * Set the current cart instance.
+ *
+ * @param string|null $instance
+ * @return \Gloudemans\Shoppingcart\Cart
+ */
+ public function instance($instance = null)
+ {
+ $instance = $instance ?: self::DEFAULT_INSTANCE;
+
+ $this->instance = sprintf('%s.%s', 'cart', $instance);
+
+ return $this;
+ }
+
+ /**
+ * Get the current cart instance.
+ *
+ * @return string
+ */
+ public function currentInstance()
+ {
+ return str_replace('cart.', '', $this->instance);
+ }
+
+ /**
+ * Add an item to the cart.
+ *
+ * @param $id
+ * @param $name
+ * @param $qty
+ * @param $price
+ * @param $taxRate
+ * @param $taxIncluded
+ * @param array $options
+ * @param array $eventOptions
+ * @return array|array[]|CartItem|CartItem[]
+ */
+ public function add($id, $name = null, $qty = null, $price = null, $taxRate = null, $taxIncluded = false, array $options = [], array $eventOptions = [])
+ {
+ if ($this->isMulti($id)) {
+ return array_map(function ($item) {
+ return $this->add($item);
+ }, $id);
+ }
+
+ if ($id instanceof CartItem) {
+ $cartItem = $id;
+ } else {
+ $cartItem = $this->createCartItem($id, $name, $qty, $price, $taxRate, $taxIncluded, $options);
+ }
+
+ $content = $this->getContent();
+
+ if ($content->has($cartItem->rowId)) {
+ $cartItem->qty += $content->get($cartItem->rowId)->qty;
+ }
+
+ $content->put($cartItem->rowId, $cartItem);
+
+ $this->items = $content;
+
+ $this->session->put($this->instance, $this->toArray());
+
+ $eventOptions = array_merge([
+ 'cartInstance' => $this->currentInstance(),
+ 'cartItem' => $cartItem,
+ ], $eventOptions);
+
+ $this->events->dispatch('cart.added', [
+ $eventOptions,
+ ]);
+
+ return $cartItem;
+ }
+
+ /**
+ * Update the cart item with the given rowId.
+ *
+ * @param $rowId
+ * @param $qty
+ * @param array $eventOptions
+ * @return CartItem|void
+ */
+ public function update($rowId, $qty, array $eventOptions = [])
+ {
+ $cartItem = $this->get($rowId);
+
+ if ($qty instanceof Buyable) {
+ $cartItem->updateFromBuyable($qty);
+ } elseif (is_array($qty)) {
+ $cartItem->updateFromArray($qty);
+ } else {
+ $cartItem->qty = $qty;
+ }
+
+ $content = $this->getContent();
+
+ if ($rowId !== $cartItem->rowId) {
+ if ($content->has($cartItem->rowId)) {
+ $existingCartItem = $this->get($cartItem->rowId);
+ $cartItem->setQuantity($existingCartItem->qty + $cartItem->qty);
+ }
+
+ $content = $content->mapWithKeys(function ($val, $key) use ($rowId, $cartItem) {
+ if ($key === $rowId) {
+ return [ $cartItem->rowId => $cartItem ];
+ }
+
+ return [ $key => $val ];
+ });
+
+ $this->items = $content;
+ }
+
+ if ($cartItem->qty <= 0) {
+ $this->remove($cartItem->rowId);
+
+ return;
+ }
+
+ $this->session->put($this->instance, $this->toArray());
+
+ $eventOptions = array_merge([
+ 'cartInstance' => $this->currentInstance(),
+ 'cartItem' => $cartItem,
+ ], $eventOptions);
+
+ $this->events->dispatch('cart.updated', [
+ $eventOptions
+ ]);
+
+ return $cartItem;
+ }
+
+ /**
+ * Remove the cart item with the given rowId from the cart.
+ *
+ * @param $rowId
+ * @param array $eventOptions
+ * @return void
+ */
+ public function remove($rowId, array $eventOptions = [])
+ {
+ $cartItem = $this->get($rowId);
+
+ $content = $this->getContent();
+
+ $content->pull($cartItem->rowId);
+
+ $this->items = $content;
+
+ $this->session->put($this->instance, $this->toArray());
+
+ $eventOptions = array_merge([
+ 'cartInstance' => $this->currentInstance(),
+ 'cartItem' => $cartItem,
+ ], $eventOptions);
+
+ $this->events->dispatch('cart.removed', [
+ $eventOptions
+ ]);
+ }
+
+ /**
+ * Get a cart item from the cart by its rowId.
+ *
+ * @param string $rowId
+ * @return \Gloudemans\Shoppingcart\CartItem
+ */
+ public function get($rowId)
+ {
+ $content = $this->getContent();
+
+ if ($content->has($rowId) === false) {
+ throw new InvalidRowIDException("The cart does not contain rowId {$rowId}.");
+ }
+
+ return $content->get($rowId);
+ }
+
+ /**
+ * Destroy the current cart instance.
+ *
+ * @return void
+ */
+ public function destroy()
+ {
+ $this->session->remove($this->instance);
+ }
+
+ /**
+ * Get the content of the cart.
+ *
+ * @return \Illuminate\Support\Collection
+ */
+ public function content()
+ {
+ return $this->getContent();
+ }
+
+ /**
+ * Get the number of items in the cart.
+ *
+ * @return int|float
+ */
+ public function count()
+ {
+ $content = $this->getContent();
+
+ return $content->sum('qty');
+ }
+
+ /**
+ * Get the total price of the items in the cart.
+ *
+ * @param int $decimals
+ * @param string $decimalPoint
+ * @param string $thousandSeperator
+ * @return string
+ */
+ public function total($decimals = null, $decimalPoint = null, $thousandSeperator = null, $withFees = true)
+ {
+ $content = $this->getContent();
+
+ $total = $content->reduce(function ($total, CartItem $cartItem) {
+ return $total + ($cartItem->total);
+ }, 0);
+
+ if ($withFees === true) {
+ $fees = $this->feeTotal(null, null, null, true);
+
+ $total = $total + $fees;
+ }
+
+ $decimals = is_null($decimals) ? config('cart.format.total_decimals') : $decimals;
+
+ return $this->numberFormat($total, $decimals, $decimalPoint, $thousandSeperator);
+ }
+
+ /**
+ * Get the total tax of the items in the cart.
+ *
+ * @param int $decimals
+ * @param string $decimalPoint
+ * @param string $thousandSeperator
+ * @return float
+ */
+ public function tax($decimals = null, $decimalPoint = null, $thousandSeperator = null, $withFees = true)
+ {
+ $content = $this->getContent();
+
+ $tax = $content->reduce(function ($tax, CartItem $cartItem) {
+ return $tax + ($cartItem->taxTotal);
+ }, 0);
+
+ if ($withFees === true) {
+ $fees = $this->feeTax();
+
+ $tax = $tax + floatval($fees);
+ }
+
+ $decimals = is_null($decimals) ? config('cart.format.tax_decimals') : $decimals;
+
+ return $this->numberFormat($tax, $decimals, $decimalPoint, $thousandSeperator);
+ }
+
+ /**
+ * Get the total tax of the items in the cart.
+ *
+ * @param int $decimals
+ * @param string $decimalPoint
+ * @param string $thousandSeperator
+ * @return float
+ */
+ public function feeTax($decimals = null, $decimalPoint = null, $thousandSeperator = null)
+ {
+ $content = $this->getContent();
+
+ $tax = 0;
+
+ foreach ($this->getFees() as $fee) {
+ $tax += $fee->tax;
+ }
+
+ $decimals = is_null($decimals) ? config('cart.format.fee_total_tax_decimals') : $decimals;
+
+ return $this->numberFormat($tax, $decimals, $decimalPoint, $thousandSeperator);
+ }
+
+ /**
+ * Get the subtotal (ex tax) of the items in the cart.
+ *
+ * @param int $decimals
+ * @param string $decimalPoint
+ * @param string $thousandSeperator
+ * @return float
+ */
+ public function subtotal($decimals = null, $decimalPoint = null, $thousandSeperator = null)
+ {
+ $content = $this->getContent();
+
+ $subTotal = $content->reduce(function ($subTotal, CartItem $cartItem) {
+ return $subTotal + ($cartItem->subtotal);
+ }, 0);
+
+ $decimals = is_null($decimals) ? config('cart.format.subtotal_ex_tax_decimals') : $decimals;
+
+ return $this->numberFormat($subTotal, $decimals, $decimalPoint, $thousandSeperator);
+ }
+
+ /**
+ * Get the subtotal (total - tax) of the items in the cart.
+ *
+ * @param int $decimals
+ * @param string $decimalPoint
+ * @param string $thousandSeperator
+ * @return float
+ */
+ public function subtotalTax($decimals = null, $decimalPoint = null, $thousandSeperator = null)
+ {
+ $content = $this->getContent();
+
+ $subTotal = $content->reduce(function ($subTotal, CartItem $cartItem) {
+ return $subTotal + ($cartItem->subtotalTax);
+ }, 0);
+
+ $decimals = is_null($decimals) ? config('cart.format.subtotal_inc_tax_decimals') : $decimals;
+
+ return $this->numberFormat($subTotal, $decimals, $decimalPoint, $thousandSeperator);
+ }
+
+ /**
+ * Search the cart content for a cart item matching the given search closure.
+ *
+ * @param Closure $search
+ * @return \Illuminate\Support\Collection
+ */
+ public function search(Closure $search)
+ {
+ $content = $this->getContent();
+
+ return $content->filter($search);
+ }
+
+ /**
+ * Associate the cart item with the given rowId with the given model.
+ *
+ * @param string $rowId
+ * @param mixed $model
+ * @return void
+ */
+ public function associate($rowId, $model)
+ {
+ if (
+ is_string($model) === true &&
+ class_exists($model) === false
+ ) {
+ throw new UnknownModelException("The supplied model {$model} does not exist.");
+ }
+
+ $cartItem = $this->get($rowId);
+
+ $cartItem->associate($model);
+
+ $content = $this->getContent();
+
+ $content->put($cartItem->rowId, $cartItem);
+
+ $this->session->put($this->instance, $this->toArray());
+ }
+
+ /**
+ * Set the tax rate for the cart item with the given rowId.
+ *
+ * @param string $rowId
+ * @param int|float $taxRate
+ * @return void
+ */
+ public function setTax($rowId, $taxRate)
+ {
+ $cartItem = $this->get($rowId);
+
+ $cartItem->setTaxRate($taxRate);
+
+ $content = $this->getContent();
+
+ $content->put($cartItem->rowId, $cartItem);
+
+ $this->items = $content;
+
+ $this->session->put($this->instance, $this->toArray());
+ }
+
+ /**
+ * Store an the current instance of the cart.
+ *
+ * @param $identifier
+ * @param array $eventOptions
+ * @return void
+ */
+ public function store($identifier, array $eventOptions = [])
+ {
+ // Remove any existing identifiers
+ // Although possibly first or update could work in future
+ $this
+ ->getConnection()
+ ->table($this->getTableName())
+ ->where('identifier', $identifier)
+ ->delete();
+
+ // Insert into the database with the new cart
+ $content = $this->getContent();
+ //dd($content);
+ $this
+ ->getConnection()
+ ->table($this->getTableName())
+ ->insert([
+ 'identifier' => $identifier,
+ 'instance' => $this->currentInstance(),
+ 'content' => serialize($content),
+ 'created_at'=> new DateTime(),
+ ]);
+
+ $eventOptions = array_merge([
+ 'cartInstance' => $this->currentInstance(),
+ ], $eventOptions);
+
+ $this->events->dispatch('cart.stored', [
+ $eventOptions,
+ ]);
+ }
+
+ /**
+ * Restore the cart with the given identifier.
+ *
+ * @param $identifier
+ * @param array $eventOptions
+ * @return void
+ */
+ public function restore($identifier, array $eventOptions = [], $delteStoredCart = true)
+ {
+ if ($this->storedCartWithIdentifierExists($identifier) === false) {
+ return;
+ }
+
+ // Find any existing carts by identifier
+ $stored = $this
+ ->getConnection()
+ ->table($this->getTableName())
+ ->where('identifier', $identifier)
+ ->first();
+
+ // Unserialize the content (either array if new, or collection if old)
+ $storedContent = unserialize($stored->content);
+
+ $currentInstance = $this->currentInstance();
+
+ $this->instance($stored->instance);
+
+ $content = $this->getContent();
+
+ // If the new approach and is array, set this class up.
+ // Note that it overrides any existing items in cart
+ // Does not add to existing.
+ if (is_array($storedContent)) {
+ $this->fromArray($storedContent);
+ }
+
+ // If the old approach and is Collection, push into existing items
+ if ($storedContent instanceof Collection) {
+ foreach ($storedContent as $cartItem) {
+ $content->put($cartItem->rowId, $cartItem);
+ }
+ }
+
+ $eventOptions = array_merge([
+ 'cartInstance' => $this->currentInstance(),
+ ], $eventOptions);
+
+ $this->events->dispatch('cart.restored', [
+ $eventOptions,
+ ]);
+
+ $this->session->put($this->instance, $content);
+
+ $this->instance($currentInstance);
+
+ if($delteStoredCart === true) {
+ $this->deleteStoredCart($identifier);
+ }
+ }
+
+ /**
+ * Gets a specific fee from the fees array.
+ *
+ * @param $name
+ *
+ * @return mixed
+ */
+ public function getFee($name)
+ {
+ return $this->fees->get($name, new CartFee(null, null));
+ }
+
+ /**
+ * Allows to charge for additional fees that may or may not be taxable
+ * ex - service fee , delivery fee, tips.
+ *
+ * Because it uses ->put, the name must be unique otherwise will be overwritten.
+ *
+ * @param $name
+ * @param $amount
+ * @param $taxRate
+ * @param array $options
+ */
+ public function addFee($name, $amount, $taxRate = null, array $options = [])
+ {
+ $this->fees->put($name, new CartFee($amount, $taxRate, $options));
+
+ $this->session->put($this->instance, $this->toArray());
+ }
+
+ /**
+ * Removes a fee from the fee array.
+ *
+ * @todo test to see if i need to restore this
+ *
+ * @param $name
+ */
+ public function removeFee($name)
+ {
+ $this->fees->forget($name);
+
+ $this->session->put($this->instance, $this->toArray());
+ }
+
+ /**
+ * Removes all the fees set in the cart.
+ */
+ public function removeFees()
+ {
+ $this->fees = new Collection;
+
+ $this->session->put($this->instance, $this->toArray());
+ }
+
+ /**
+ * Gets all the fee totals.
+ *
+ * @param bool $format
+ * @param bool $withTax
+ *
+ * @return string
+ */
+ public function feeTotal($decimals = null, $decimalPoint = null, $thousandSeperator = null, $withTax = true)
+ {
+ $feeTotal = 0;
+
+ foreach ($this->getFees() as $fee) {
+ $feeTotal += $fee->amount;
+
+ if ($withTax === true && $fee->taxRate > 0) {
+ $feeTotal += $fee->tax;
+ }
+ }
+
+ return $this->numberFormat($feeTotal, null, null, null);
+ }
+
+ /**
+ * Gets all the fees on the cart object.
+ *
+ * @return mixed
+ */
+ public function getFees()
+ {
+ return $this->fees;
+ }
+
+ /**
+ * Magic method to make accessing the total, tax and subtotal properties possible.
+ *
+ * @param string $attribute
+ * @return float|null
+ */
+ public function __get($attribute)
+ {
+ if ($attribute === 'total') {
+ return $this->total();
+ }
+
+ if ($attribute === 'feeTotal') {
+ return $this->feeTotal(null, null, null, false);
+ }
+
+ if ($attribute === 'feeTotalTax') {
+ return $this->feeTotal(null, null, null, true);
+ }
+
+ if ($attribute === 'tax') {
+ return $this->tax();
+ }
+
+ if ($attribute === 'feeTax') {
+ return $this->feeTax();
+ }
+
+ if ($attribute === 'subtotal') {
+ return $this->subtotal();
+ }
+
+ if ($attribute === 'subtotalTax') {
+ return $this->subtotalTax();
+ }
+
+ return null;
+ }
+
+ /**
+ * @return array
+ */
+ public function toArray()
+ {
+ return [
+ 'items' => $this->items,
+ 'fees' => $this->fees,
+ ];
+ }
+
+ /**
+ * @param $array
+ * @return $this
+ */
+ public function fromArray($array)
+ {
+ $this->items = $array['items'];
+ $this->fees = $array['fees'];
+
+ return $this;
+ }
+
+ /**
+ * Deletes the stored cart with given identifier
+ *
+ * @param mixed $identifier
+ */
+ public function deleteStoredCart($identifier)
+ {
+ $this
+ ->getConnection()
+ ->table($this->getTableName())
+ ->where('identifier', $identifier)
+ ->delete();
+ }
+
+ /**
+ * Get the carts content, if there is no cart content set yet, return a new empty Collection
+ *
+ * @return \Illuminate\Support\Collection
+ */
+ public function getContent(): Collection
+ {
+ $instanceExists = $this->session->has($this->instance);
+
+ if ($instanceExists === false) {
+ $this->items = new Collection;
+
+ return $this->items;
+ }
+
+ $instance = $this->session->get($this->instance);
+ // dd($instance);
+ // If new approach, set $this variables
+ if (is_array($instance) === true) {
+ $this->items = $instance['items'];
+ $this->fees = $instance['fees'];
+ }
+
+ if ($instance instanceof Collection) {
+ $this->items = $instance;
+ }
+
+ return $this->items;
+ }
+
+ /**
+ * Create a new CartItem from the supplied attributes.
+ *
+ * @param mixed $id
+ * @param mixed $name
+ * @param int|float $qty
+ * @param float $price
+ * @param array $options
+ * @return \Gloudemans\Shoppingcart\CartItem
+ */
+ private function createCartItem($id, $name, $qty, $price, $taxRate, bool $taxIncluded, array $options): CartItem
+ {
+ if ($id instanceof Buyable) {
+ $cartItem = CartItem::fromBuyable($id, $qty ?: []);
+ $cartItem->setQuantity($name ?: 1);
+ $cartItem->associate($id);
+ } elseif (is_array($id)) {
+ $cartItem = CartItem::fromArray($id);
+ $cartItem->setQuantity($id['qty']);
+ } else {
+ $cartItem = CartItem::fromAttributes($id, $name, $price, $options);
+ $cartItem->setQuantity($qty);
+ }
+
+ $taxRate = is_int($taxRate) ? $taxRate : config('cart.tax');
+
+ $cartItem->setTaxRate($taxRate);
+ $cartItem->setTaxIncluded($taxIncluded);
+
+ return $cartItem;
+ }
+
+ /**
+ * Check if the item is a multidimensional array or an array of Buyables.
+ *
+ * @param mixed $item
+ * @return bool
+ */
+ private function isMulti($item): bool
+ {
+ if (is_array($item) === false) {
+ return false;
+ }
+
+ return is_array(head($item)) || head($item) instanceof Buyable === true;
+ }
+
+ /**
+ * @param $identifier
+ * @return bool
+ */
+ protected function storedCartWithIdentifierExists($identifier): bool
+ {
+ return $this
+ ->getConnection()
+ ->table($this->getTableName())
+ ->where('identifier', $identifier)
+ ->exists();
+ }
+
+ /**
+ * Get the database connection.
+ *
+ * @return \Illuminate\Database\Connection
+ */
+ protected function getConnection()
+ {
+ $connectionName = $this->getConnectionName();
+
+ return app(DatabaseManager::class)->connection($connectionName);
+ }
+
+ /**
+ * Get the database table name.
+ *
+ * @return string
+ */
+ protected function getTableName()
+ {
+ return config('cart.database.table', 'shoppingcart');
+ }
+
+ /**
+ * Get the database connection name.
+ *
+ * @return string
+ */
+ private function getConnectionName()
+ {
+ $connection = config('cart.database.connection');
+
+ return is_null($connection) ? config('database.default') : $connection;
+ }
+}
diff --git a/packages/digital-bird/shoppingcart/src/CartFee.php b/packages/digital-bird/shoppingcart/src/CartFee.php
new file mode 100644
index 00000000..8694fc4d
--- /dev/null
+++ b/packages/digital-bird/shoppingcart/src/CartFee.php
@@ -0,0 +1,118 @@
+amount = floatval($amount);
+ $this->taxRate = is_null($taxRate) ? config('cart.tax') : $taxRate;
+ $this->options = new CartFeeOptions($options);
+ }
+
+ /**
+ * Returns the formatted fee amount without TAX.
+ *
+ * @param int $decimals
+ * @param string $decimalPoint
+ * @param string $thousandSeperator
+ * @return string
+ */
+ public function amountWithouTax($decimals = null, $decimalPoint = null, $thousandSeperator = null)
+ {
+ $decimals = is_null($decimals) ? config('cart.format.fee_ex_tax_decimals') : $decimals;
+
+ return $this->numberFormat($this->price, $decimals, $decimalPoint, $thousandSeperator);
+ }
+
+ /**
+ * Returns the formatted fee amount with TAX.
+ *
+ * @param int $decimals
+ * @param string $decimalPoint
+ * @param string $thousandSeperator
+ * @return string
+ */
+ public function amountTax($decimals = null, $decimalPoint = null, $thousandSeperator = null)
+ {
+ $priceTax = $this->amount + $this->tax;
+ $decimals = is_null($decimals) ? config('cart.format.fee_inc_tax_decimals') : $decimals;
+
+ return $this->numberFormat($priceTax, $decimals, $decimalPoint, $thousandSeperator);
+ }
+
+ /**
+ * Gets the formatted amount.
+ *
+ * @param bool $format
+ * @param bool $withTax
+ *
+ * @return string
+ */
+ public function getAmount($format = true, $withTax = false)
+ {
+ $total = $this->amount;
+
+ if ($withTax) {
+ $total += $this->taxRate * $total;
+ }
+
+ return $this->numberFormat($total);
+ }
+
+ /**
+ * @return string
+ */
+ public function tax()
+ {
+ $tax = $this->amount * $this->taxRate / 100;
+
+ return $this->numberFormat($tax);
+ }
+
+ /**
+ * Magic method to make accessing the total, tax and subtotal properties possible.
+ *
+ * @param string $attribute
+ * @return float|null
+ */
+ public function __get($attribute)
+ {
+ if (property_exists($this, $attribute)) {
+ return $this->{$attribute};
+ }
+
+ if ($attribute === 'amountWithouTax') {
+ return $this->amountWithouTax();
+ }
+
+ if ($attribute === 'amountTax') {
+ return $this->amountTax();
+ }
+
+ if ($attribute === 'tax') {
+ return $this->tax();
+ }
+
+ return null;
+ }
+}
diff --git a/packages/digital-bird/shoppingcart/src/CartFeeOptions.php b/packages/digital-bird/shoppingcart/src/CartFeeOptions.php
new file mode 100644
index 00000000..dd91b926
--- /dev/null
+++ b/packages/digital-bird/shoppingcart/src/CartFeeOptions.php
@@ -0,0 +1,19 @@
+get($key);
+ }
+}
diff --git a/packages/digital-bird/shoppingcart/src/CartItem.php b/packages/digital-bird/shoppingcart/src/CartItem.php
new file mode 100644
index 00000000..132411e5
--- /dev/null
+++ b/packages/digital-bird/shoppingcart/src/CartItem.php
@@ -0,0 +1,470 @@
+id = $id;
+ $this->name = $name;
+ $this->price = floatval($price);
+ $this->options = new CartItemOptions($options);
+ $this->rowId = $this->generateRowId($id, $options);
+ }
+
+ /**
+ * Returns the formatted price without TAX.
+ *
+ * @param int $decimals
+ * @param string $decimalPoint
+ * @param string $thousandSeperator
+ * @return string
+ */
+ public function price($decimals = null, $decimalPoint = null, $thousandSeperator = null)
+ {
+ $decimals = is_null($decimals) ? config('cart.format.price_ex_tax_decimals') : $decimals;
+
+ return $this->numberFormat($this->price, $decimals, $decimalPoint, $thousandSeperator);
+ }
+
+ /**
+ * Returns the formatted price with TAX.
+ *
+ * @param int $decimals
+ * @param string $decimalPoint
+ * @param string $thousandSeperator
+ * @return string
+ */
+ public function priceTax($decimals = null, $decimalPoint = null, $thousandSeperator = null)
+ {
+ if ($this->taxIncluded === true) {
+ $priceTax = $this->price;
+ } else {
+ $priceTax = $this->price + $this->tax;
+ }
+
+ $decimals = is_null($decimals) ? config('cart.format.price_inc_tax_decimals') : $decimals;
+
+ return $this->numberFormat($priceTax, $decimals, $decimalPoint, $thousandSeperator);
+ }
+
+ /**
+ * Returns the formatted subtotal.
+ * Subtotal is price for whole CartItem without TAX
+ *
+ * @param int $decimals
+ * @param string $decimalPoint
+ * @param string $thousandSeperator
+ * @return string
+ */
+ public function subtotal($decimals = null, $decimalPoint = null, $thousandSeperator = null)
+ {
+ $subtotal = $this->qty * $this->price;
+ $decimals = is_null($decimals) ? config('cart.format.subtotal_ex_tax_decimals') : $decimals;
+
+ return $this->numberFormat($subtotal, $decimals, $decimalPoint, $thousandSeperator);
+ }
+
+ /**
+ * Returns the formatted subtotal.
+ * Subtotal is price for whole CartItem with TAX
+ *
+ * @param int $decimals
+ * @param string $decimalPoint
+ * @param string $thousandSeperator
+ * @return string
+ */
+ public function subtotalTax($decimals = null, $decimalPoint = null, $thousandSeperator = null)
+ {
+ if ($this->taxIncluded === true) {
+ $subtotal = $this->subtotal;
+ } else {
+ $subtotal = $this->subtotal + $this->taxTotal;
+ }
+
+ $decimals = is_null($decimals) ? config('cart.format.subtotal_inc_tax_decimals') : $decimals;
+
+ return $this->numberFormat($subtotal, $decimals, $decimalPoint, $thousandSeperator);
+ }
+
+ /**
+ * Returns the formatted total.
+ * Total is price for whole CartItem with tax
+ *
+ * @param int $decimals
+ * @param string $decimalPoint
+ * @param string $thousandSeperator
+ * @return string
+ */
+ public function total($decimals = null, $decimalPoint = null, $thousandSeperator = null)
+ {
+ $total = $this->subtotalTax;
+ $decimals = is_null($decimals) ? config('cart.format.total_decimals') : $decimals;
+
+ return $this->numberFormat($total, $decimals, $decimalPoint, $thousandSeperator);
+ }
+
+ /**
+ * Returns the formatted tax.
+ *
+ * @param int $decimals
+ * @param string $decimalPoint
+ * @param string $thousandSeperator
+ * @return string
+ */
+ public function tax($decimals = null, $decimalPoint = null, $thousandSeperator = null)
+ {
+ if ($this->taxIncluded === true) {
+ $tax = $this->price / (1 + $this->taxRate);
+ } else {
+ $tax = $this->price * ($this->taxRate / 100);
+ }
+
+ $decimals = is_null($decimals) ? config('cart.format.tax_decimals') : $decimals;
+
+ return $this->numberFormat($tax, $decimals, $decimalPoint, $thousandSeperator);
+ }
+
+ /**
+ * Returns the formatted tax.
+ *
+ * @param int $decimals
+ * @param string $decimalPoint
+ * @param string $thousandSeperator
+ * @return string
+ */
+ public function taxTotal($decimals = null, $decimalPoint = null, $thousandSeperator = null)
+ {
+ $taxTotal = $this->tax * $this->qty;
+ $decimals = is_null($decimals) ? config('cart.format.tax_total_decimals') : $decimals;
+
+ return $this->numberFormat($taxTotal, $decimals, $decimalPoint, $thousandSeperator);
+ }
+
+ /**
+ * Set the quantity for this cart item.
+ *
+ * @param int|float $qty
+ */
+ public function setQuantity($qty)
+ {
+ if(empty($qty) || ! is_numeric($qty))
+ throw new \InvalidArgumentException('Please supply a valid quantity.');
+
+ $this->qty = $qty;
+ }
+
+ /**
+ * Update the cart item from a Buyable.
+ *
+ * @param \Gloudemans\Shoppingcart\Contracts\Buyable $item
+ * @return void
+ */
+ public function updateFromBuyable(Buyable $item)
+ {
+ $this->id = $item->getBuyableIdentifier($this->options);
+ $this->name = $item->getBuyableDescription($this->options);
+ $this->price = $item->getBuyablePrice($this->options);
+ $this->priceTax = $this->price + $this->tax;
+ }
+
+ /**
+ * Update the cart item from an array.
+ *
+ * @param array $attributes
+ * @return void
+ */
+ public function updateFromArray(array $attributes)
+ {
+ $this->id = array_get($attributes, 'id', $this->id);
+ $this->qty = array_get($attributes, 'qty', $this->qty);
+ $this->name = array_get($attributes, 'name', $this->name);
+ $this->price = array_get($attributes, 'price', $this->price);
+ $this->priceTax = $this->price + $this->tax;
+ $this->options = new CartItemOptions(array_get($attributes, 'options', $this->options));
+
+ $this->rowId = $this->generateRowId($this->id, $this->options->all());
+ }
+
+ /**
+ * Associate the cart item with the given model.
+ *
+ * @param mixed $model
+ * @return \Gloudemans\Shoppingcart\CartItem
+ */
+ public function associate($model)
+ {
+ $this->associatedModel = is_string($model) ? $model : get_class($model);
+
+ return $this;
+ }
+
+ /**
+ * Set the tax rate.
+ *
+ * @param int|float $taxRate
+ * @return \Gloudemans\Shoppingcart\CartItem
+ */
+ public function setTaxRate($taxRate)
+ {
+ $this->taxRate = $taxRate;
+
+ return $this;
+ }
+
+ /**
+ * Set the tax rate.
+ *
+ * @param bool $taxIncluded
+ * @return \Gloudemans\Shoppingcart\CartItem
+ */
+ public function setTaxIncluded(bool $taxIncluded)
+ {
+ $this->taxIncluded = $taxIncluded;
+
+ return $this;
+ }
+
+ /**
+ * Set saved state.
+ *
+ * @param bool $bool
+ * @return \Gloudemans\Shoppingcart\CartItem
+ */
+ public function setSaved($bool)
+ {
+ $this->isSaved = $bool;
+
+ return $this;
+ }
+
+ /**
+ * Get an attribute from the cart item or get the associated model.
+ *
+ * @param string $attribute
+ * @return mixed
+ */
+ public function __get($attribute)
+ {
+ if (property_exists($this, $attribute)) {
+ return $this->{$attribute};
+ }
+
+ if ($attribute === 'priceTax') {
+ return $this->priceTax();
+ }
+
+ if ($attribute === 'subtotal') {
+ return $this->subtotal();
+ }
+
+ if ($attribute === 'subtotalTax') {
+ return $this->subtotalTax();
+ }
+
+ if ($attribute === 'total') {
+ return $this->total();
+ }
+
+ if ($attribute === 'tax') {
+ return $this->tax();
+ }
+
+ if ($attribute === 'taxTotal') {
+ return $this->taxTotal();
+ }
+
+ if ($attribute === 'model' && isset($this->associatedModel)) {
+ return with(new $this->associatedModel)->find($this->id);
+ }
+
+ return null;
+ }
+
+ /**
+ * Create a new instance from a Buyable.
+ *
+ * @param \Gloudemans\Shoppingcart\Contracts\Buyable $item
+ * @param array $options
+ * @return \Gloudemans\Shoppingcart\CartItem
+ */
+ public static function fromBuyable(Buyable $item, array $options = [])
+ {
+ return new self($item->getBuyableIdentifier($options), $item->getBuyableDescription($options), $item->getBuyablePrice($options), $options);
+ }
+
+ /**
+ * Create a new instance from the given array.
+ *
+ * @param array $attributes
+ * @return \Gloudemans\Shoppingcart\CartItem
+ */
+ public static function fromArray(array $attributes)
+ {
+ $options = array_get($attributes, 'options', []);
+
+ return new self($attributes['id'], $attributes['name'], $attributes['price'], $options);
+ }
+
+ /**
+ * Create a new instance from the given attributes.
+ *
+ * @param int|string $id
+ * @param string $name
+ * @param float $price
+ * @param array $options
+ * @return \Gloudemans\Shoppingcart\CartItem
+ */
+ public static function fromAttributes($id, $name, $price, array $options = [])
+ {
+ return new self($id, $name, $price, $options);
+ }
+
+ /**
+ * Generate a unique id for the cart item.
+ *
+ * @param string $id
+ * @param array $options
+ * @return string
+ */
+ protected function generateRowId($id, array $options)
+ {
+ ksort($options);
+
+ $uniqueString = '';
+
+ if (config('cart.allow_multiple_same_id') === true) {
+ $uniqueString = microtime(true);
+ }
+
+ return md5($id . $uniqueString . serialize($options));
+ }
+
+ /**
+ * Get the instance as an array.
+ *
+ * @return array
+ */
+ public function toArray()
+ {
+ return [
+ 'rowId' => $this->rowId,
+ 'id' => $this->id,
+ 'name' => $this->name,
+ 'qty' => $this->qty,
+ 'price' => $this->price,
+ 'options' => $this->options->toArray(),
+ 'tax' => $this->tax,
+ 'isSaved' => $this->isSaved,
+ 'subtotal' => $this->subtotal
+ ];
+ }
+
+ /**
+ * Convert the object to its JSON representation.
+ *
+ * @param int $options
+ * @return string
+ */
+ public function toJson($options = 0)
+ {
+ return json_encode($this->toArray(), $options);
+ }
+}
diff --git a/packages/digital-bird/shoppingcart/src/CartItemOptions.php b/packages/digital-bird/shoppingcart/src/CartItemOptions.php
new file mode 100644
index 00000000..1b802053
--- /dev/null
+++ b/packages/digital-bird/shoppingcart/src/CartItemOptions.php
@@ -0,0 +1,19 @@
+get($key);
+ }
+}
diff --git a/packages/digital-bird/shoppingcart/src/Contracts/Buyable.php b/packages/digital-bird/shoppingcart/src/Contracts/Buyable.php
new file mode 100644
index 00000000..f5bfeb7b
--- /dev/null
+++ b/packages/digital-bird/shoppingcart/src/Contracts/Buyable.php
@@ -0,0 +1,27 @@
+app->bind('cart', 'Gloudemans\Shoppingcart\Cart');
+
+ $config = __DIR__ . '/../config/cart.php';
+ $this->mergeConfigFrom($config, 'cart');
+
+ $this->publishes([__DIR__ . '/../config/cart.php' => config_path('cart.php')], 'config');
+
+ $this->app['events']->listen(Logout::class, function () {
+ if ($this->app['config']->get('cart.destroy_on_logout')) {
+ $this->app->make(SessionManager::class)->forget('cart');
+ }
+ });
+
+ if ( ! class_exists('CreateShoppingcartTable')) {
+ // Publish the migration
+ $timestamp = date('Y_m_d_His', time());
+
+ $this->publishes([
+ __DIR__.'/../database/migrations/0000_00_00_000000_create_shoppingcart_table.php' => database_path('migrations/'.$timestamp.'_create_shoppingcart_table.php'),
+ ], 'migrations');
+ }
+ }
+}
diff --git a/packages/digital-bird/shoppingcart/src/Traits/CartHelper.php b/packages/digital-bird/shoppingcart/src/Traits/CartHelper.php
new file mode 100644
index 00000000..cb7968cf
--- /dev/null
+++ b/packages/digital-bird/shoppingcart/src/Traits/CartHelper.php
@@ -0,0 +1,35 @@
+count();
+
+ PHPUnit::assertEquals($items, $cart->count(), "Expected the cart to contain {$items} items, but got {$actual}.");
+ }
+
+ /**
+ * Assert that the cart contains the given number of rows.
+ *
+ * @param int $rows
+ * @param \Gloudemans\Shoppingcart\Cart $cart
+ */
+ public function assertRowsInCart($rows, Cart $cart)
+ {
+ $actual = $cart->content()->count();
+
+ PHPUnit::assertCount($rows, $cart->content(), "Expected the cart to contain {$rows} rows, but got {$actual}.");
+ }
+}
diff --git a/packages/digital-bird/shoppingcart/tests/CartItemTest.php b/packages/digital-bird/shoppingcart/tests/CartItemTest.php
new file mode 100644
index 00000000..2a017149
--- /dev/null
+++ b/packages/digital-bird/shoppingcart/tests/CartItemTest.php
@@ -0,0 +1,56 @@
+ 'XL', 'color' => 'red']);
+ $cartItem->setQuantity(2);
+
+ $this->assertEquals([
+ 'id' => 1,
+ 'name' => 'Some item',
+ 'price' => 10.00,
+ 'rowId' => '07d5da5550494c62daf9993cf954303f',
+ 'qty' => 2,
+ 'options' => [
+ 'size' => 'XL',
+ 'color' => 'red'
+ ],
+ 'tax' => 0.0,
+ 'subtotal' => 20.00,
+ 'isSaved' => false
+ ], $cartItem->toArray());
+ }
+
+ /** @test */
+ public function it_can_be_cast_to_json()
+ {
+ $cartItem = new CartItem(1, 'Some item', 10.00, ['size' => 'XL', 'color' => 'red']);
+ $cartItem->setQuantity(2);
+
+ $this->assertJson($cartItem->toJson());
+
+ $json = '{"rowId":"07d5da5550494c62daf9993cf954303f","id":1,"name":"Some item","qty":2,"price":10,"options":{"size":"XL","color":"red"},"tax":"0.00","isSaved":false,"subtotal":"20.00"}';
+
+ $this->assertEquals($json, $cartItem->toJson());
+ }
+}
diff --git a/packages/digital-bird/shoppingcart/tests/CartTest.php b/packages/digital-bird/shoppingcart/tests/CartTest.php
new file mode 100644
index 00000000..4df29f09
--- /dev/null
+++ b/packages/digital-bird/shoppingcart/tests/CartTest.php
@@ -0,0 +1,945 @@
+set('cart.database.connection', 'testing');
+
+ $app['config']->set('session.driver', 'array');
+
+ $app['config']->set('database.default', 'testing');
+ $app['config']->set('database.connections.testing', [
+ 'driver' => 'sqlite',
+ 'database' => ':memory:',
+ 'prefix' => '',
+ ]);
+ }
+
+ /**
+ * Setup the test environment.
+ *
+ * @return void
+ */
+ protected function setUp()
+ {
+ parent::setUp();
+
+ $this->app->afterResolving('migrator', function ($migrator) {
+ $migrator->path(realpath(__DIR__.'/../database/migrations'));
+ });
+ }
+
+ /** @test */
+ public function it_has_a_default_instance()
+ {
+ $cart = $this->getCart();
+
+ $this->assertEquals(Cart::DEFAULT_INSTANCE, $cart->currentInstance());
+ }
+
+ /** @test */
+ public function it_can_have_multiple_instances()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct(1, 'First item'));
+
+ $cart->instance('wishlist')->add(new BuyableProduct(2, 'Second item'));
+
+ $this->assertItemsInCart(1, $cart->instance(Cart::DEFAULT_INSTANCE));
+ $this->assertItemsInCart(1, $cart->instance('wishlist'));
+ }
+
+ /** @test */
+ public function it_can_add_an_item()
+ {
+ Event::fake();
+
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct);
+
+ $this->assertEquals(1, $cart->count());
+
+ Event::assertDispatched('cart.added');
+ }
+
+ /** @test */
+ public function it_will_return_the_cartitem_of_the_added_item()
+ {
+ Event::fake();
+
+ $cart = $this->getCart();
+
+ $cartItem = $cart->add(new BuyableProduct);
+
+ $this->assertInstanceOf(CartItem::class, $cartItem);
+ $this->assertEquals('027c91341fd5cf4d2579b49c4b6a90da', $cartItem->rowId);
+
+ Event::assertDispatched('cart.added');
+ }
+
+ /** @test */
+ public function it_can_add_multiple_buyable_items_at_once()
+ {
+ Event::fake();
+
+ $cart = $this->getCart();
+
+ $cart->add([new BuyableProduct(1), new BuyableProduct(2)]);
+
+ $this->assertEquals(2, $cart->count());
+
+ Event::assertDispatched('cart.added');
+ }
+
+ /** @test */
+ public function it_will_return_an_array_of_cartitems_when_you_add_multiple_items_at_once()
+ {
+ Event::fake();
+
+ $cart = $this->getCart();
+
+ $cartItems = $cart->add([new BuyableProduct(1), new BuyableProduct(2)]);
+
+ $this->assertTrue(is_array($cartItems));
+ $this->assertCount(2, $cartItems);
+ $this->assertContainsOnlyInstancesOf(CartItem::class, $cartItems);
+
+ Event::assertDispatched('cart.added');
+ }
+
+ /** @test */
+ public function it_can_add_an_item_from_attributes()
+ {
+ Event::fake();
+
+ $cart = $this->getCart();
+
+ $cart->add(1, 'Test item', 1, 10.00);
+
+ $this->assertEquals(1, $cart->count());
+
+ Event::assertDispatched('cart.added');
+ }
+
+ /** @test */
+ public function it_can_add_an_item_from_an_array()
+ {
+ Event::fake();
+
+ $cart = $this->getCart();
+
+ $cart->add(['id' => 1, 'name' => 'Test item', 'qty' => 1, 'price' => 10.00]);
+
+ $this->assertEquals(1, $cart->count());
+
+ Event::assertDispatched('cart.added');
+ }
+
+ /** @test */
+ public function it_can_add_multiple_array_items_at_once()
+ {
+ Event::fake();
+
+ $cart = $this->getCart();
+
+ $cart->add([
+ ['id' => 1, 'name' => 'Test item 1', 'qty' => 1, 'price' => 10.00],
+ ['id' => 2, 'name' => 'Test item 2', 'qty' => 1, 'price' => 10.00]
+ ]);
+
+ $this->assertEquals(2, $cart->count());
+
+ Event::assertDispatched('cart.added');
+ }
+
+ /** @test */
+ public function it_can_add_an_item_with_options()
+ {
+ Event::fake();
+
+ $cart = $this->getCart();
+
+ $options = ['size' => 'XL', 'color' => 'red'];
+
+ $cart->add(new BuyableProduct, 1, $options);
+
+ $cartItem = $cart->get('07d5da5550494c62daf9993cf954303f');
+
+ $this->assertInstanceOf(CartItem::class, $cartItem);
+ $this->assertEquals('XL', $cartItem->options->size);
+ $this->assertEquals('red', $cartItem->options->color);
+
+ Event::assertDispatched('cart.added');
+ }
+
+ /**
+ * @test
+ * @expectedException \InvalidArgumentException
+ * @expectedExceptionMessage Please supply a valid identifier.
+ */
+ public function it_will_validate_the_identifier()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(null, 'Some title', 1, 10.00);
+ }
+
+ /**
+ * @test
+ * @expectedException \InvalidArgumentException
+ * @expectedExceptionMessage Please supply a valid name.
+ */
+ public function it_will_validate_the_name()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(1, null, 1, 10.00);
+ }
+
+ /**
+ * @test
+ * @expectedException \InvalidArgumentException
+ * @expectedExceptionMessage Please supply a valid quantity.
+ */
+ public function it_will_validate_the_quantity()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(1, 'Some title', 'invalid', 10.00);
+ }
+
+ /**
+ * @test
+ * @expectedException \InvalidArgumentException
+ * @expectedExceptionMessage Please supply a valid price.
+ */
+ public function it_will_validate_the_price()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(1, 'Some title', 1, 'invalid');
+ }
+
+ /** @test */
+ public function it_will_update_the_cart_if_the_item_already_exists_in_the_cart()
+ {
+ $cart = $this->getCart();
+
+ $item = new BuyableProduct;
+
+ $cart->add($item);
+ $cart->add($item);
+
+ $this->assertItemsInCart(2, $cart);
+ $this->assertRowsInCart(1, $cart);
+ }
+
+ /** @test */
+ public function it_will_keep_updating_the_quantity_when_an_item_is_added_multiple_times()
+ {
+ $cart = $this->getCart();
+
+ $item = new BuyableProduct;
+
+ $cart->add($item);
+ $cart->add($item);
+ $cart->add($item);
+
+ $this->assertItemsInCart(3, $cart);
+ $this->assertRowsInCart(1, $cart);
+ }
+
+ /** @test */
+ public function it_can_update_the_quantity_of_an_existing_item_in_the_cart()
+ {
+ Event::fake();
+
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct);
+
+ $cart->update('027c91341fd5cf4d2579b49c4b6a90da', 2);
+
+ $this->assertItemsInCart(2, $cart);
+ $this->assertRowsInCart(1, $cart);
+
+ Event::assertDispatched('cart.updated');
+ }
+
+ /** @test */
+ public function it_can_update_an_existing_item_in_the_cart_from_a_buyable()
+ {
+ Event::fake();
+
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct);
+
+ $cart->update('027c91341fd5cf4d2579b49c4b6a90da', new BuyableProduct(1, 'Different description'));
+
+ $this->assertItemsInCart(1, $cart);
+ $this->assertEquals('Different description', $cart->get('027c91341fd5cf4d2579b49c4b6a90da')->name);
+
+ Event::assertDispatched('cart.updated');
+ }
+
+ /** @test */
+ public function it_can_update_an_existing_item_in_the_cart_from_an_array()
+ {
+ Event::fake();
+
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct);
+
+ $cart->update('027c91341fd5cf4d2579b49c4b6a90da', ['name' => 'Different description']);
+
+ $this->assertItemsInCart(1, $cart);
+ $this->assertEquals('Different description', $cart->get('027c91341fd5cf4d2579b49c4b6a90da')->name);
+
+ Event::assertDispatched('cart.updated');
+ }
+
+ /**
+ * @test
+ * @expectedException \Gloudemans\Shoppingcart\Exceptions\InvalidRowIDException
+ */
+ public function it_will_throw_an_exception_if_a_rowid_was_not_found()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct);
+
+ $cart->update('none-existing-rowid', new BuyableProduct(1, 'Different description'));
+ }
+
+ /** @test */
+ public function it_will_regenerate_the_rowid_if_the_options_changed()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct, 1, ['color' => 'red']);
+
+ $cart->update('ea65e0bdcd1967c4b3149e9e780177c0', ['options' => ['color' => 'blue']]);
+
+ $this->assertItemsInCart(1, $cart);
+ $this->assertEquals('7e70a1e9aaadd18c72921a07aae5d011', $cart->content()->first()->rowId);
+ $this->assertEquals('blue', $cart->get('7e70a1e9aaadd18c72921a07aae5d011')->options->color);
+ }
+
+ /** @test */
+ public function it_will_add_the_item_to_an_existing_row_if_the_options_changed_to_an_existing_rowid()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct, 1, ['color' => 'red']);
+ $cart->add(new BuyableProduct, 1, ['color' => 'blue']);
+
+ $cart->update('7e70a1e9aaadd18c72921a07aae5d011', ['options' => ['color' => 'red']]);
+
+ $this->assertItemsInCart(2, $cart);
+ $this->assertRowsInCart(1, $cart);
+ }
+
+ /** @test */
+ public function it_can_remove_an_item_from_the_cart()
+ {
+ Event::fake();
+
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct);
+
+ $cart->remove('027c91341fd5cf4d2579b49c4b6a90da');
+
+ $this->assertItemsInCart(0, $cart);
+ $this->assertRowsInCart(0, $cart);
+
+ Event::assertDispatched('cart.removed');
+ }
+
+ /** @test */
+ public function it_will_remove_the_item_if_its_quantity_was_set_to_zero()
+ {
+ Event::fake();
+
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct);
+
+ $cart->update('027c91341fd5cf4d2579b49c4b6a90da', 0);
+
+ $this->assertItemsInCart(0, $cart);
+ $this->assertRowsInCart(0, $cart);
+
+ Event::assertDispatched('cart.removed');
+ }
+
+ /** @test */
+ public function it_will_remove_the_item_if_its_quantity_was_set_negative()
+ {
+ Event::fake();
+
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct);
+
+ $cart->update('027c91341fd5cf4d2579b49c4b6a90da', -1);
+
+ $this->assertItemsInCart(0, $cart);
+ $this->assertRowsInCart(0, $cart);
+
+ Event::assertDispatched('cart.removed');
+ }
+
+ /** @test */
+ public function it_can_get_an_item_from_the_cart_by_its_rowid()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct);
+
+ $cartItem = $cart->get('027c91341fd5cf4d2579b49c4b6a90da');
+
+ $this->assertInstanceOf(CartItem::class, $cartItem);
+ }
+
+ /** @test */
+ public function it_can_get_the_content_of_the_cart()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct(1));
+ $cart->add(new BuyableProduct(2));
+
+ $content = $cart->content();
+
+ $this->assertInstanceOf(Collection::class, $content);
+ $this->assertCount(2, $content);
+ }
+
+ /** @test */
+ public function it_will_return_an_empty_collection_if_the_cart_is_empty()
+ {
+ $cart = $this->getCart();
+
+ $content = $cart->content();
+
+ $this->assertInstanceOf(Collection::class, $content);
+ $this->assertCount(0, $content);
+ }
+
+ /** @test */
+ public function it_will_include_the_tax_and_subtotal_when_converted_to_an_array()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct(1));
+ $cart->add(new BuyableProduct(2));
+
+ $content = $cart->content();
+
+ $this->assertInstanceOf(Collection::class, $content);
+ $this->assertEquals([
+ '027c91341fd5cf4d2579b49c4b6a90da' => [
+ 'rowId' => '027c91341fd5cf4d2579b49c4b6a90da',
+ 'id' => 1,
+ 'name' => 'Item name',
+ 'qty' => 1,
+ 'price' => 10.00,
+ 'tax' => 2.10,
+ 'subtotal' => 10.0,
+ 'isSaved' => false,
+ 'options' => [],
+ ],
+ '370d08585360f5c568b18d1f2e4ca1df' => [
+ 'rowId' => '370d08585360f5c568b18d1f2e4ca1df',
+ 'id' => 2,
+ 'name' => 'Item name',
+ 'qty' => 1,
+ 'price' => 10.00,
+ 'tax' => 2.10,
+ 'subtotal' => 10.0,
+ 'isSaved' => false,
+ 'options' => [],
+ ]
+ ], $content->toArray());
+ }
+
+ /** @test */
+ public function it_can_destroy_a_cart()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct);
+
+ $this->assertItemsInCart(1, $cart);
+
+ $cart->destroy();
+
+ $this->assertItemsInCart(0, $cart);
+ }
+
+ /** @test */
+ public function it_can_get_the_total_price_of_the_cart_content()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct(1, 'First item', 10.00));
+ $cart->add(new BuyableProduct(2, 'Second item', 25.00), 2);
+
+ $this->assertItemsInCart(3, $cart);
+ $this->assertEquals(60.00, $cart->subtotal());
+ }
+
+ /** @test */
+ public function it_can_return_a_formatted_total()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct(1, 'First item', 1000.00));
+ $cart->add(new BuyableProduct(2, 'Second item', 2500.00), 2);
+
+ $this->assertItemsInCart(3, $cart);
+ $this->assertEquals('6.000,00', $cart->subtotal(2, ',', '.'));
+ }
+
+ /** @test */
+ public function it_can_search_the_cart_for_a_specific_item()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct(1, 'Some item'));
+ $cart->add(new BuyableProduct(2, 'Another item'));
+
+ $cartItem = $cart->search(function ($cartItem, $rowId) {
+ return $cartItem->name == 'Some item';
+ });
+
+ $this->assertInstanceOf(Collection::class, $cartItem);
+ $this->assertCount(1, $cartItem);
+ $this->assertInstanceOf(CartItem::class, $cartItem->first());
+ $this->assertEquals(1, $cartItem->first()->id);
+ }
+
+ /** @test */
+ public function it_can_search_the_cart_for_multiple_items()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct(1, 'Some item'));
+ $cart->add(new BuyableProduct(2, 'Some item'));
+ $cart->add(new BuyableProduct(3, 'Another item'));
+
+ $cartItem = $cart->search(function ($cartItem, $rowId) {
+ return $cartItem->name == 'Some item';
+ });
+
+ $this->assertInstanceOf(Collection::class, $cartItem);
+ }
+
+ /** @test */
+ public function it_can_search_the_cart_for_a_specific_item_with_options()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct(1, 'Some item'), 1, ['color' => 'red']);
+ $cart->add(new BuyableProduct(2, 'Another item'), 1, ['color' => 'blue']);
+
+ $cartItem = $cart->search(function ($cartItem, $rowId) {
+ return $cartItem->options->color == 'red';
+ });
+
+ $this->assertInstanceOf(Collection::class, $cartItem);
+ $this->assertCount(1, $cartItem);
+ $this->assertInstanceOf(CartItem::class, $cartItem->first());
+ $this->assertEquals(1, $cartItem->first()->id);
+ }
+
+ /** @test */
+ public function it_will_associate_the_cart_item_with_a_model_when_you_add_a_buyable()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct);
+
+ $cartItem = $cart->get('027c91341fd5cf4d2579b49c4b6a90da');
+
+ $this->assertContains(BuyableProduct::class, Assert::readAttribute($cartItem, 'associatedModel'));
+ }
+
+ /** @test */
+ public function it_can_associate_the_cart_item_with_a_model()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(1, 'Test item', 1, 10.00);
+
+ $cart->associate('027c91341fd5cf4d2579b49c4b6a90da', new ProductModel);
+
+ $cartItem = $cart->get('027c91341fd5cf4d2579b49c4b6a90da');
+
+ $this->assertEquals(ProductModel::class, Assert::readAttribute($cartItem, 'associatedModel'));
+ }
+
+ /**
+ * @test
+ * @expectedException \Gloudemans\Shoppingcart\Exceptions\UnknownModelException
+ * @expectedExceptionMessage The supplied model SomeModel does not exist.
+ */
+ public function it_will_throw_an_exception_when_a_non_existing_model_is_being_associated()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(1, 'Test item', 1, 10.00);
+
+ $cart->associate('027c91341fd5cf4d2579b49c4b6a90da', 'SomeModel');
+ }
+
+ /** @test */
+ public function it_can_get_the_associated_model_of_a_cart_item()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(1, 'Test item', 1, 10.00);
+
+ $cart->associate('027c91341fd5cf4d2579b49c4b6a90da', new ProductModel);
+
+ $cartItem = $cart->get('027c91341fd5cf4d2579b49c4b6a90da');
+
+ $this->assertInstanceOf(ProductModel::class, $cartItem->model);
+ $this->assertEquals('Some value', $cartItem->model->someValue);
+ }
+
+ /** @test */
+ public function it_can_calculate_the_subtotal_of_a_cart_item()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct(1, 'Some title', 9.99), 3);
+
+ $cartItem = $cart->get('027c91341fd5cf4d2579b49c4b6a90da');
+
+ $this->assertEquals(29.97, $cartItem->subtotal);
+ }
+
+ /** @test */
+ public function it_can_return_a_formatted_subtotal()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct(1, 'Some title', 500), 3);
+
+ $cartItem = $cart->get('027c91341fd5cf4d2579b49c4b6a90da');
+
+ $this->assertEquals('1.500,00', $cartItem->subtotal(2, ',', '.'));
+ }
+
+ /** @test */
+ public function it_can_calculate_tax_based_on_the_default_tax_rate_in_the_config()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct(1, 'Some title', 10.00), 1);
+
+ $cartItem = $cart->get('027c91341fd5cf4d2579b49c4b6a90da');
+
+ $this->assertEquals(2.10, $cartItem->tax);
+ }
+
+ /** @test */
+ public function it_can_calculate_tax_based_on_the_specified_tax()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct(1, 'Some title', 10.00), 1);
+
+ $cart->setTax('027c91341fd5cf4d2579b49c4b6a90da', 19);
+
+ $cartItem = $cart->get('027c91341fd5cf4d2579b49c4b6a90da');
+
+ $this->assertEquals(1.90, $cartItem->tax);
+ }
+
+ /** @test */
+ public function it_can_return_the_calculated_tax_formatted()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct(1, 'Some title', 10000.00), 1);
+
+ $cartItem = $cart->get('027c91341fd5cf4d2579b49c4b6a90da');
+
+ $this->assertEquals('2.100,00', $cartItem->tax(2, ',', '.'));
+ }
+
+ /** @test */
+ public function it_can_calculate_the_total_tax_for_all_cart_items()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct(1, 'Some title', 10.00), 1);
+ $cart->add(new BuyableProduct(2, 'Some title', 20.00), 2);
+
+ $this->assertEquals(10.50, $cart->tax);
+ }
+
+ /** @test */
+ public function it_can_return_formatted_total_tax()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct(1, 'Some title', 1000.00), 1);
+ $cart->add(new BuyableProduct(2, 'Some title', 2000.00), 2);
+
+ $this->assertEquals('1.050,00', $cart->tax(2, ',', '.'));
+ }
+
+ /** @test */
+ public function it_can_return_the_subtotal()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct(1, 'Some title', 10.00), 1);
+ $cart->add(new BuyableProduct(2, 'Some title', 20.00), 2);
+
+ $this->assertEquals(50.00, $cart->subtotal);
+ }
+
+ /** @test */
+ public function it_can_return_formatted_subtotal()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct(1, 'Some title', 1000.00), 1);
+ $cart->add(new BuyableProduct(2, 'Some title', 2000.00), 2);
+
+ $this->assertEquals('5000,00', $cart->subtotal(2, ',', ''));
+ }
+
+ /** @test */
+ public function it_can_return_cart_formated_numbers_by_config_values()
+ {
+ $this->setConfigFormat(2, ',', '');
+
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct(1, 'Some title', 1000.00), 1);
+ $cart->add(new BuyableProduct(2, 'Some title', 2000.00), 2);
+
+ $this->assertEquals('5000,00', $cart->subtotal());
+ $this->assertEquals('1050,00', $cart->tax());
+ $this->assertEquals('6050,00', $cart->total());
+
+ $this->assertEquals('5000,00', $cart->subtotal);
+ $this->assertEquals('1050,00', $cart->tax);
+ $this->assertEquals('6050,00', $cart->total);
+ }
+
+ /** @test */
+ public function it_can_return_cartItem_formated_numbers_by_config_values()
+ {
+ $this->setConfigFormat(2, ',', '');
+
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct(1, 'Some title', 2000.00), 2);
+
+ $cartItem = $cart->get('027c91341fd5cf4d2579b49c4b6a90da');
+
+ $this->assertEquals('2000,00', $cartItem->price());
+ $this->assertEquals('2420,00', $cartItem->priceTax());
+ $this->assertEquals('4000,00', $cartItem->subtotal());
+ $this->assertEquals('4840,00', $cartItem->total());
+ $this->assertEquals('420,00', $cartItem->tax());
+ $this->assertEquals('840,00', $cartItem->taxTotal());
+ }
+
+ /** @test */
+ public function it_can_store_the_cart_in_a_database()
+ {
+ $this->artisan('migrate', [
+ '--database' => 'testing',
+ ]);
+
+ Event::fake();
+
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct);
+
+ $cart->store($identifier = 123);
+
+ $serialized = serialize($cart->content());
+
+ $this->assertDatabaseHas('shoppingcart', ['identifier' => $identifier, 'instance' => 'default', 'content' => $serialized]);
+
+ Event::assertDispatched('cart.stored');
+ }
+
+ /** @test */
+ public function it_can_update_the_cart_in_database()
+ {
+ $this->artisan('migrate', [
+ '--database' => 'testing',
+ ]);
+
+ Event::fake();
+
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct);
+
+ $cart->store($identifier = 123);
+
+ $serialized = serialize($cart->content());
+
+ $this->assertDatabaseHas('shoppingcart', ['identifier' => $identifier, 'instance' => 'default', 'content' => $serialized]);
+
+ Event::assertDispatched('cart.stored');
+ }
+
+ /** @test */
+ public function it_can_restore_a_cart_from_the_database()
+ {
+ $this->artisan('migrate', [
+ '--database' => 'testing',
+ ]);
+
+ Event::fake();
+
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct);
+
+ $cart->store($identifier = 123);
+
+ $cart->destroy();
+
+ $this->assertItemsInCart(0, $cart);
+
+ $cart->restore($identifier);
+
+ $this->assertItemsInCart(1, $cart);
+
+ Event::assertDispatched('cart.restored');
+ }
+
+ /** @test */
+ public function it_will_just_keep_the_current_instance_if_no_cart_with_the_given_identifier_was_stored()
+ {
+ $this->artisan('migrate', [
+ '--database' => 'testing',
+ ]);
+
+ $cart = $this->getCart();
+
+ $cart->restore($identifier = 123);
+
+ $this->assertItemsInCart(0, $cart);
+ }
+
+ /** @test */
+ public function it_can_calculate_all_values()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct(1, 'First item', 10.00), 2);
+
+ $cartItem = $cart->get('027c91341fd5cf4d2579b49c4b6a90da');
+
+ $cart->setTax('027c91341fd5cf4d2579b49c4b6a90da', 19);
+
+ $this->assertEquals(10.00, $cartItem->price(2));
+ $this->assertEquals(11.90, $cartItem->priceTax(2));
+ $this->assertEquals(20.00, $cartItem->subtotal(2));
+ $this->assertEquals(23.80, $cartItem->total(2));
+ $this->assertEquals(1.90, $cartItem->tax(2));
+ $this->assertEquals(3.80, $cartItem->taxTotal(2));
+
+ $this->assertEquals(20.00, $cart->subtotal(2));
+ $this->assertEquals(23.80, $cart->total(2));
+ $this->assertEquals(3.80, $cart->tax(2));
+ }
+
+ /** @test */
+ public function it_will_destroy_the_cart_when_the_user_logs_out_and_the_config_setting_was_set_to_true()
+ {
+ $this->app['config']->set('cart.destroy_on_logout', true);
+
+ $this->app->instance(SessionManager::class, Mockery::mock(SessionManager::class, function ($mock) {
+ $mock->shouldReceive('forget')->once()->with('cart');
+ }));
+
+ $user = Mockery::mock(Authenticatable::class);
+
+ $guard = $this->app->make('auth');
+
+ event(new Logout($guard, $user));
+ }
+
+ /**
+ * Get an instance of the cart.
+ *
+ * @return \Gloudemans\Shoppingcart\Cart
+ */
+ private function getCart()
+ {
+ $session = $this->app->make('session');
+ $events = $this->app->make('events');
+
+ return new Cart($session, $events);
+ }
+
+ /**
+ * Set the config number format.
+ *
+ * @param int $decimals
+ * @param string $decimalPoint
+ * @param string $thousandSeperator
+ */
+ private function setConfigFormat($decimals, $decimalPoint, $thousandSeperator)
+ {
+ $this->app['config']->set('cart.format.decimals', $decimals);
+ $this->app['config']->set('cart.format.decimal_point', $decimalPoint);
+ $this->app['config']->set('cart.format.thousand_seperator', $thousandSeperator);
+ }
+}
diff --git a/packages/digital-bird/shoppingcart/tests/Fixtures/BuyableProduct.php b/packages/digital-bird/shoppingcart/tests/Fixtures/BuyableProduct.php
new file mode 100644
index 00000000..a58e830d
--- /dev/null
+++ b/packages/digital-bird/shoppingcart/tests/Fixtures/BuyableProduct.php
@@ -0,0 +1,67 @@
+id = $id;
+ $this->name = $name;
+ $this->price = $price;
+ }
+
+ /**
+ * Get the identifier of the Buyable item.
+ *
+ * @return int|string
+ */
+ public function getBuyableIdentifier($options = null)
+ {
+ return $this->id;
+ }
+
+ /**
+ * Get the description or title of the Buyable item.
+ *
+ * @return string
+ */
+ public function getBuyableDescription($options = null)
+ {
+ return $this->name;
+ }
+
+ /**
+ * Get the price of the Buyable item.
+ *
+ * @return float
+ */
+ public function getBuyablePrice($options = null)
+ {
+ return $this->price;
+ }
+}
\ No newline at end of file
diff --git a/packages/digital-bird/shoppingcart/tests/Fixtures/ProductModel.php b/packages/digital-bird/shoppingcart/tests/Fixtures/ProductModel.php
new file mode 100644
index 00000000..70494ca5
--- /dev/null
+++ b/packages/digital-bird/shoppingcart/tests/Fixtures/ProductModel.php
@@ -0,0 +1,13 @@
+getKey() : $this->id;
+ }
+
+ /**
+ * Get the description or title of the Buyable item.
+ *
+ * @return string
+ */
+ public function getBuyableDescription($options = null)
+ {
+ if(property_exists($this, 'name')) return $this->name;
+ if(property_exists($this, 'title')) return $this->title;
+ if(property_exists($this, 'description')) return $this->description;
+
+ return null;
+ }
+
+ /**
+ * Get the price of the Buyable item.
+ *
+ * @return float
+ */
+ public function getBuyablePrice($options = null)
+ {
+ if(property_exists($this, 'price')) return $this->price;
+
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/packages/shoppingcart/Cart.php b/packages/shoppingcart/Cart.php
new file mode 100644
index 00000000..eaaf9422
--- /dev/null
+++ b/packages/shoppingcart/Cart.php
@@ -0,0 +1,686 @@
+session = $session;
+ $this->events = $events;
+ $this->extraCosts = new Collection();
+
+ $this->instance(self::DEFAULT_INSTANCE);
+ }
+
+ /**
+ * Set the current cart instance.
+ *
+ * @param string|null $instance
+ * @return Cart
+ */
+ public function instance($instance = null)
+ {
+ $instance = $instance ?: self::DEFAULT_INSTANCE;
+
+ $this->instance = sprintf('%s.%s', 'cart', $instance);
+
+ return $this;
+ }
+
+ /**
+ * Get the current cart instance.
+ *
+ * @return string
+ */
+ public function currentInstance()
+ {
+ return str_replace('cart.', '', $this->instance);
+ }
+
+ /**
+ * Add an item to the cart.
+ *
+ * @param mixed $id
+ * @param mixed $name
+ * @param int|float $qty
+ * @param float $price
+ * @param array $options
+ * @return CartItem
+ */
+ public function add($id, $name = null, $qty = null, $price = null, array $options = [])
+ {
+ if ($this->isMulti($id)) {
+ return array_map(function ($item) {
+ return $this->add($item);
+ }, $id);
+ }
+
+ $cartItem = $this->createCartItem($id, $name, $qty, $price, $options);
+
+ $content = $this->getContent();
+
+ if ($content->has($cartItem->rowId)) {
+ $cartItem->qty += $content->get($cartItem->rowId)->qty;
+ }
+
+ $content->put($cartItem->rowId, $cartItem);
+
+ $this->events->dispatch('cart.added', $cartItem);
+
+ $this->session->put($this->instance, $content);
+
+ return $cartItem;
+ }
+
+ /**
+ * Sets/adds an additional cost on the cart.
+ *
+ * @param string $name
+ * @param float $price
+ * @todo add in session
+ */
+ public function addCost($name, $price)
+ {
+ $oldCost = $this->extraCosts->pull($name, 0);
+
+ $this->extraCosts->put($name, $price + $oldCost);
+ }
+
+ /**
+ * Gets an additional cost by name
+ *
+ * @param $name
+ * @param int|null $decimals
+ * @param string|null $decimalPoint
+ * @param string|null $thousandSeparator
+ * @return string
+ */
+ public function getCost($name)
+ {
+ $cost = $this->extraCosts->get($name, 0);
+
+ return $this->numberFormat($cost);
+ }
+
+ /**
+ * Update the cart item with the given rowId.
+ *
+ * @param string $rowId
+ * @param mixed $qty
+ * @return CartItem
+ */
+ public function update($rowId, $qty)
+ {
+ $cartItem = $this->get($rowId);
+
+ if ($qty instanceof Buyable) {
+ $cartItem->updateFromBuyable($qty);
+ } elseif (is_array($qty)) {
+ $cartItem->updateFromArray($qty);
+ } else {
+ $cartItem->qty = $qty;
+ }
+
+ $content = $this->getContent();
+
+ if ($rowId !== $cartItem->rowId) {
+ $content->pull($rowId);
+
+ if ($content->has($cartItem->rowId)) {
+ $existingCartItem = $this->get($cartItem->rowId);
+ $cartItem->setQuantity($existingCartItem->qty + $cartItem->qty);
+ }
+ }
+
+ if ($cartItem->qty <= 0) {
+ $this->remove($cartItem->rowId);
+ return;
+ } else {
+ $content->put($cartItem->rowId, $cartItem);
+ }
+
+ $this->events->dispatch('cart.updated', $cartItem);
+
+ $this->session->put($this->instance, $content);
+
+ return $cartItem;
+ }
+
+ /**
+ * Remove the cart item with the given rowId from the cart.
+ *
+ * @param string $rowId
+ * @return void
+ */
+ public function remove($rowId)
+ {
+ $cartItem = $this->get($rowId);
+
+ $content = $this->getContent();
+
+ $content->pull($cartItem->rowId);
+
+ $this->events->dispatch('cart.removed', $cartItem);
+
+ $this->session->put($this->instance, $content);
+ }
+
+ /**
+ * Get a cart item from the cart by its rowId.
+ *
+ * @param string $rowId
+ * @return CartItem
+ */
+ public function get($rowId)
+ {
+ $content = $this->getContent();
+
+ if ( ! $content->has($rowId))
+ throw new InvalidRowIDException("The cart does not contain rowId {$rowId}.");
+
+ return $content->get($rowId);
+ }
+
+ /**
+ * Destroy the current cart instance.
+ *
+ * @return void
+ */
+ public function destroy()
+ {
+ $this->session->remove($this->instance);
+ }
+
+ /**
+ * Get the content of the cart.
+ *
+ * @return Collection
+ */
+ public function content()
+ {
+ if (is_null($this->session->get($this->instance))) {
+ return new Collection();
+ }
+
+ return $this->session->get($this->instance);
+ }
+
+ /**
+ * Get the number of items in the cart.
+ *
+ * @return int|float
+ */
+ public function count()
+ {
+ $content = $this->getContent();
+
+ return $content->sum('qty');
+ }
+
+ /**
+ * Get the total price of the items in the cart.
+ *
+ * @param int $decimals
+ * @param string $decimalPoint
+ * @param string $thousandSeparator
+ * @return string
+ */
+ public function total()
+ {
+ $content = $this->getContent();
+
+ $total = $content->reduce(function ($total, CartItem $cartItem) {
+ return $total + ($cartItem->qty * $cartItem->priceTax);
+ }, 0);
+
+ $totalCost = $this->extraCosts->reduce(function ($total, $cost) {
+ return $total + $cost;
+ }, 0);
+
+ $total += $totalCost;
+
+ return $this->numberFormat($total);
+ }
+
+ /**
+ * Get the total tax of the items in the cart.
+ *
+ * @param int $decimals
+ * @param string $decimalPoint
+ * @param string $thousandSeparator
+ * @return float
+ */
+ public function tax()
+ {
+ $content = $this->getContent();
+
+ $tax = $content->reduce(function ($tax, CartItem $cartItem) {
+ return $tax + ($cartItem->qty * $cartItem->tax);
+ }, 0);
+
+ return $this->numberFormat($tax);
+ }
+
+ /**
+ * Get the subtotal (total - tax) of the items in the cart.
+ *
+ * @param int $decimals
+ * @param string $decimalPoint
+ * @param string $thousandSeparator
+ * @return float
+ */
+ public function subtotal()
+ {
+ $content = $this->getContent();
+
+ $subTotal = $content->reduce(function ($subTotal, CartItem $cartItem) {
+ return $subTotal + ($cartItem->qty * $cartItem->price);
+ }, 0);
+
+ return $this->numberFormat($subTotal);
+ }
+
+ /**
+ * Search the cart content for a cart item matching the given search closure.
+ *
+ * @param \Closure $search
+ * @return Collection
+ */
+ public function search(Closure $search)
+ {
+ $content = $this->getContent();
+
+ return $content->filter($search);
+ }
+
+ /**
+ * Associate the cart item with the given rowId with the given model.
+ *
+ * @param string $rowId
+ * @param mixed $model
+ * @return void
+ */
+ public function associate($rowId, $model)
+ {
+ if(is_string($model) && ! class_exists($model)) {
+ throw new UnknownModelException("The supplied model {$model} does not exist.");
+ }
+
+ $cartItem = $this->get($rowId);
+
+ $cartItem->associate($model);
+
+ $content = $this->getContent();
+
+ $content->put($cartItem->rowId, $cartItem);
+
+ $this->session->put($this->instance, $content);
+ }
+
+ /**
+ * Set the tax rate for the cart item with the given rowId.
+ *
+ * @param string $rowId
+ * @param int|float $taxRate
+ * @return void
+ */
+ public function setTax($rowId, $taxRate)
+ {
+ $cartItem = $this->get($rowId);
+
+ $cartItem->setTaxRate($taxRate);
+
+ $content = $this->getContent();
+
+ $content->put($cartItem->rowId, $cartItem);
+
+ $this->session->put($this->instance, $content);
+ }
+
+ /**
+ * Store an the current instance of the cart.
+ *
+ * @param mixed $identifier
+ * @return void
+ */
+ public function store($identifier)
+ {
+ $content = $this->getContent();
+
+ if ($identifier instanceof InstanceIdentifier) {
+ $identifier = $identifier->getInstanceIdentifier();
+ }
+
+ $instance = $this->currentInstance();
+
+ if ($this->storedCartInstanceWithIdentifierExists($instance, $identifier)) {
+ throw new CartAlreadyStoredException("A cart with identifier {$identifier} was already stored.");
+ }
+
+ $this->getConnection()->table($this->getTableName())->insert([
+ 'identifier' => $identifier,
+ 'instance' => $instance,
+ 'content' => serialize($content),
+ 'created_at' => $this->createdAt ?: Carbon::now(),
+ 'updated_at' => Carbon::now(),
+ ]);
+
+ $this->events->dispatch('cart.stored');
+
+ }
+
+ /**
+ * @param $identifier
+ *
+ * @return bool
+ */
+ private function storedCartInstanceWithIdentifierExists($instance, $identifier)
+ {
+ return $this->getConnection()->table($this->getTableName())->where(['identifier' => $identifier, 'instance'=> $instance])->exists();
+ }
+
+
+ /**
+ * Restore the cart with the given identifier.
+ *
+ * @param mixed $identifier
+ * @return void
+ */
+ public function restore($identifier)
+ {
+ if ($identifier instanceof InstanceIdentifier) {
+ $identifier = $identifier->getInstanceIdentifier();
+ }
+
+ $currentInstance = $this->currentInstance();
+
+ if (!$this->storedCartInstanceWithIdentifierExists($currentInstance, $identifier)) {
+ return;
+ }
+
+ $stored = $this->getConnection()->table($this->getTableName())
+ ->where(['identifier'=> $identifier, 'instance' => $currentInstance])->first();
+
+ $storedContent = unserialize(data_get($stored, 'content'));
+
+ $this->instance(data_get($stored, 'instance'));
+
+ $content = $this->getContent();
+
+ foreach ($storedContent as $cartItem) {
+ $content->put($cartItem->rowId, $cartItem);
+ }
+
+ $this->events->dispatch('cart.restored');
+
+ $this->session->put($this->instance, $content);
+
+ $this->instance($currentInstance);
+
+ $this->createdAt = Carbon::parse(data_get($stored, 'created_at'));
+ $this->updatedAt = Carbon::parse(data_get($stored, 'updated_at'));
+
+ $this->getConnection()->table($this->getTableName())->where(['identifier' => $identifier, 'instance' => $currentInstance])->delete();
+
+ }
+
+ /**
+ * Merges the contents of another cart into this cart.
+ *
+ * @param mixed $identifier Identifier of the Cart to merge with.
+ * @param bool $keepDiscount Keep the discount of the CartItems.
+ * @param bool $keepTax Keep the tax of the CartItems.
+ * @param bool $dispatchAdd Flag to dispatch the add events.
+ *
+ * @return bool
+ */
+ public function merge($identifier, $keepTax = false, $dispatchAdd = true, $instance = self::DEFAULT_INSTANCE)
+ {
+ if (!$this->storedCartInstanceWithIdentifierExists($instance, $identifier)) {
+ return false;
+ }
+
+ $stored = $this->getConnection()->table($this->getTableName())
+ ->where(['identifier'=> $identifier, 'instance'=> $instance])->first();
+
+ $storedContent = unserialize($stored->content);
+
+ foreach ($storedContent as $cartItem) {
+ $this->addCartItem($cartItem, $keepTax, $dispatchAdd);
+ }
+
+ $this->events->dispatch('cart.merged');
+
+ return true;
+ }
+
+ /**
+ * Add an item to the cart.
+ *
+ * @param \Gloudemans\Shoppingcart\CartItem $item Item to add to the Cart
+ * @param bool $keepDiscount Keep the discount rate of the Item
+ * @param bool $keepTax Keep the Tax rate of the Item
+ * @param bool $dispatchEvent
+ *
+ * @return \Gloudemans\Shoppingcart\CartItem The CartItem
+ */
+ public function addCartItem($item, $keepTax = false, $dispatchEvent = true)
+ {
+ if (!$keepTax) {
+ $item->setTaxRate($this->taxRate);
+ }
+
+ $content = $this->getContent();
+
+ if ($content->has($item->rowId)) {
+ $item->qty += $content->get($item->rowId)->qty;
+ }
+
+ $content->put($item->rowId, $item);
+
+ if ($dispatchEvent) {
+ $this->events->dispatch('cart.adding', $item);
+ }
+
+ $this->session->put($this->instance, $content);
+
+ if ($dispatchEvent) {
+ $this->events->dispatch('cart.added', $item);
+ }
+
+ return $item;
+ }
+
+ /**
+ * Magic method to make accessing the total, tax and subtotal properties possible.
+ *
+ * @param string $attribute
+ * @return float|null
+ */
+ public function __get($attribute)
+ {
+ if($attribute === 'total') {
+ return $this->total();
+ }
+
+ if($attribute === 'tax') {
+ return $this->tax();
+ }
+
+ if($attribute === 'subtotal') {
+ return $this->subtotal();
+ }
+
+ return null;
+ }
+
+ /**
+ * Get the carts content, if there is no cart content set yet, return a new empty Collection
+ *
+ * @return Collection
+ */
+ protected function getContent()
+ {
+ $content = $this->session->has($this->instance)
+ ? $this->session->get($this->instance)
+ : new Collection;
+
+ return $content;
+ }
+
+ /**
+ * Create a new CartItem from the supplied attributes.
+ *
+ * @param mixed $id
+ * @param mixed $name
+ * @param int|float $qty
+ * @param float $price
+ * @param array $options
+ * @return CartItem
+ */
+ private function createCartItem($id, $name, $qty, $price, array $options)
+ {
+ if ($id instanceof Buyable) {
+ $cartItem = CartItem::fromBuyable($id, $qty ?: []);
+ $cartItem->setQuantity($name ?: 1);
+ $cartItem->associate($id);
+ } elseif (is_array($id)) {
+ $cartItem = CartItem::fromArray($id);
+ $cartItem->setQuantity($id['qty']);
+ } else {
+ $cartItem = CartItem::fromAttributes($id, $name, $price, $options);
+ $cartItem->setQuantity($qty);
+ }
+
+ $cartItem->setTaxRate(config('cart.tax'));
+
+ return $cartItem;
+ }
+
+ /**
+ * Check if the item is a multidimensional array or an array of Buyables.
+ *
+ * @param mixed $item
+ * @return bool
+ */
+ private function isMulti($item)
+ {
+ if ( ! is_array($item)) return false;
+
+ return is_array(head($item)) || head($item) instanceof Buyable;
+ }
+
+ /**
+ * @param $identifier
+ * @return bool
+ */
+ private function storedCartWithIdentifierExists($identifier)
+ {
+ return $this->getConnection()->table($this->getTableName())->where('identifier', $identifier)->exists();
+ }
+
+ /**
+ * Get the database connection.
+ *
+ * @return Connection
+ */
+ private function getConnection()
+ {
+ $connectionName = $this->getConnectionName();
+
+ return app(DatabaseManager::class)->connection($connectionName);
+ }
+
+ /**
+ * Get the database table name.
+ *
+ * @return string
+ */
+ private function getTableName()
+ {
+ return 'shopping_cart';
+ }
+
+ /**
+ * Get the database connection name.
+ *
+ * @return string
+ */
+ private function getConnectionName()
+ {
+ $connection = config('cart.database.connection');
+
+ return is_null($connection) ? config('database.default') : $connection;
+ }
+
+ /**
+ * Get the Formated number
+ *
+ * @param $value
+ * @param $decimals
+ * @param $decimalPoint
+ * @param $thousandSeparator
+ * @return string
+ */
+ private function numberFormat($value)
+ {
+ $decimals = is_null(config('cart.format.decimals')) ? 2 : config('cart.format.decimals');
+ $decimalPoint = is_null(config('cart.format.decimal_point')) ? '.' : config('cart.format.decimal_point');
+ $thousandSeparator = '';
+
+ return number_format($value, $decimals, $decimalPoint, $thousandSeparator);
+ }
+}
diff --git a/packages/shoppingcart/CartItem.php b/packages/shoppingcart/CartItem.php
new file mode 100644
index 00000000..4e740206
--- /dev/null
+++ b/packages/shoppingcart/CartItem.php
@@ -0,0 +1,386 @@
+id = $id;
+ $this->name = $name;
+ $this->price = floatval($price);
+ $this->options = new CartItemOptions($options);
+ $this->rowId = $this->generateRowId($id, $options);
+ }
+
+ /**
+ * Returns the formatted price without TAX.
+ *
+ * @param int $decimals
+ * @param string $decimalPoint
+ * @param string $thousandSeparator
+ * @return string
+ */
+ public function price()
+ {
+ return $this->numberFormat($this->price);
+ }
+
+ /**
+ * Returns the formatted price with TAX.
+ *
+ * @param int $decimals
+ * @param string $decimalPoint
+ * @param string $thousandSeparator
+ * @return string
+ */
+ public function priceTax()
+ {
+ return $this->numberFormat($this->priceTax);
+ }
+
+ /**
+ * Returns the formatted subtotal.
+ * Subtotal is price for whole CartItem without TAX
+ *
+ * @param int $decimals
+ * @param string $decimalPoint
+ * @param string $thousandSeparator
+ * @return string
+ */
+ public function subtotal()
+ {
+ return $this->numberFormat($this->subtotal);
+ }
+
+ /**
+ * Returns the formatted total.
+ * Total is price for whole CartItem with TAX
+ *
+ * @param int $decimals
+ * @param string $decimalPoint
+ * @param string $thousandSeparator
+ * @return string
+ */
+ public function total()
+ {
+ return $this->numberFormat($this->total);
+ }
+
+ /**
+ * Returns the formatted tax.
+ *
+ * @param int $decimals
+ * @param string $decimalPoint
+ * @param string $thousandSeparator
+ * @return string
+ */
+ public function tax()
+ {
+ return $this->numberFormat($this->tax);
+ }
+
+ /**
+ * Returns the formatted tax.
+ *
+ * @param int $decimals
+ * @param string $decimalPoint
+ * @param string $thousandSeparator
+ * @return string
+ */
+ public function taxTotal()
+ {
+ return $this->numberFormat($this->taxTotal);
+ }
+
+ /**
+ * Set the quantity for this cart item.
+ *
+ * @param int|float $qty
+ */
+ public function setQuantity($qty)
+ {
+ if(empty($qty) || ! is_numeric($qty))
+ throw new \InvalidArgumentException('Please supply a valid quantity.');
+
+ $this->qty = $qty;
+ }
+
+ /**
+ * Update the cart item from a Buyable.
+ *
+ * @param Buyable $item
+ * @return void
+ */
+ public function updateFromBuyable(Buyable $item)
+ {
+ $this->id = $item->getBuyableIdentifier($this->options);
+ $this->name = $item->getBuyableDescription($this->options);
+ $this->price = $item->getBuyablePrice($this->options);
+ $this->priceTax = $this->price + $this->tax;
+ }
+
+ /**
+ * Update the cart item from an array.
+ *
+ * @param array $attributes
+ * @return void
+ */
+ public function updateFromArray(array $attributes)
+ {
+ $this->id = Arr::get($attributes, 'id', $this->id);
+ $this->qty = Arr::get($attributes, 'qty', $this->qty);
+ $this->name = Arr::get($attributes, 'name', $this->name);
+ $this->price = Arr::get($attributes, 'price', $this->price);
+ $this->priceTax = $this->price + $this->tax;
+ $this->options = new CartItemOptions(Arr::get($attributes, 'options', $this->options));
+
+ $this->rowId = $this->generateRowId($this->id, $this->options->all());
+ }
+
+ /**
+ * Associate the cart item with the given model.
+ *
+ * @param mixed $model
+ * @return CartItem
+ */
+ public function associate($model)
+ {
+ $this->associatedModel = is_string($model) ? $model : get_class($model);
+
+ return $this;
+ }
+
+ /**
+ * Set the tax rate.
+ *
+ * @param int|float $taxRate
+ * @return CartItem
+ */
+ public function setTaxRate($taxRate)
+ {
+ $this->taxRate = $taxRate;
+
+ return $this;
+ }
+
+ /**
+ * Get an attribute from the cart item or get the associated model.
+ *
+ * @param string $attribute
+ * @return mixed
+ */
+ public function __get($attribute)
+ {
+ if(property_exists($this, $attribute)) {
+ return $this->{$attribute};
+ }
+
+ if($attribute === 'priceTax') {
+ return number_format($this->price + $this->tax, 2, '.', '');
+ }
+
+ if($attribute === 'subtotal') {
+ return number_format($this->qty * $this->price, 2, '.', '');
+ }
+
+ if($attribute === 'total') {
+ return number_format($this->qty * $this->priceTax, 2, '.', '');
+ }
+
+ if($attribute === 'tax') {
+ return number_format($this->price * ($this->taxRate / 100), 2, '.', '');
+ }
+
+ if($attribute === 'taxTotal') {
+ return number_format($this->tax * $this->qty, 2, '.', '');
+ }
+
+ if($attribute === 'model' && isset($this->associatedModel)) {
+ return with(new $this->associatedModel)->find($this->id);
+ }
+
+ return null;
+ }
+
+ /**
+ * Create a new instance from a Buyable.
+ *
+ * @param Buyable $item
+ * @param array $options
+ * @return CartItem
+ */
+ public static function fromBuyable(Buyable $item, array $options = [])
+ {
+ return new self($item->getBuyableIdentifier($options), $item->getBuyableDescription($options), $item->getBuyablePrice($options), $options);
+ }
+
+ /**
+ * Create a new instance from the given array.
+ *
+ * @param array $attributes
+ * @return CartItem
+ */
+ public static function fromArray(array $attributes)
+ {
+ $options = Arr::get($attributes, 'options', []);
+
+ return new self($attributes['id'], $attributes['name'], $attributes['price'], $options);
+ }
+
+ /**
+ * Create a new instance from the given attributes.
+ *
+ * @param int|string $id
+ * @param string $name
+ * @param float $price
+ * @param array $options
+ * @return CartItem
+ */
+ public static function fromAttributes($id, $name, $price, array $options = [])
+ {
+ return new self($id, $name, $price, $options);
+ }
+
+ /**
+ * Generate a unique id for the cart item.
+ *
+ * @param string $id
+ * @param array $options
+ * @return string
+ */
+ protected function generateRowId($id, array $options)
+ {
+ ksort($options);
+
+ return md5($id . serialize($options));
+ }
+
+ /**
+ * Get the instance as an array.
+ *
+ * @return array
+ */
+ public function toArray()
+ {
+ return [
+ 'rowId' => $this->rowId,
+ 'id' => $this->id,
+ 'name' => $this->name,
+ 'qty' => $this->qty,
+ 'price' => $this->price,
+ 'options' => $this->options->toArray(),
+ 'tax' => $this->tax,
+ 'subtotal' => $this->subtotal
+ ];
+ }
+
+ /**
+ * Convert the object to its JSON representation.
+ *
+ * @param int $options
+ * @return string
+ */
+ public function toJson($options = 0)
+ {
+ return json_encode($this->toArray(), $options);
+ }
+
+ /**
+ * Get the formatted number.
+ *
+ * @param float $value
+ * @param int $decimals
+ * @param string $decimalPoint
+ * @param string $thousandSeparator
+ * @return string
+ */
+ private function numberFormat($value)
+ {
+ $decimals = is_null(config('cart.format.decimals')) ? 2 : config('cart.format.decimals');
+ $decimalPoint = is_null(config('cart.format.decimal_point')) ? '.' : config('cart.format.decimal_point');
+ $thousandSeparator = '';
+
+ return number_format($value, $decimals, $decimalPoint, $thousandSeparator);
+ }
+}
diff --git a/packages/shoppingcart/CartItemOptions.php b/packages/shoppingcart/CartItemOptions.php
new file mode 100644
index 00000000..18b9552f
--- /dev/null
+++ b/packages/shoppingcart/CartItemOptions.php
@@ -0,0 +1,19 @@
+get($key);
+ }
+}
\ No newline at end of file
diff --git a/packages/shoppingcart/Contracts/Buyable.php b/packages/shoppingcart/Contracts/Buyable.php
new file mode 100644
index 00000000..aeb95096
--- /dev/null
+++ b/packages/shoppingcart/Contracts/Buyable.php
@@ -0,0 +1,27 @@
+app->bind('cart', 'Gloudemans\Shoppingcart\Cart');
+
+ $config = __DIR__ . '/../config/cart.php';
+ $this->mergeConfigFrom($config, 'cart');
+
+ $this->publishes([__DIR__ . '/../config/cart.php' => config_path('cart.php')], 'config');
+
+ $this->app['events']->listen(Logout::class, function () {
+ if ($this->app['config']->get('cart.destroy_on_logout')) {
+ $this->app->make(SessionManager::class)->forget('cart');
+ }
+ });
+
+ if ( ! class_exists('CreateShoppingcartTable')) {
+ // Publish the migration
+ $timestamp = date('Y_m_d_His', time());
+
+ $this->publishes([
+ __DIR__ . '/../database/migrations/0000_00_00_000000_create_shopping_cart_table.php' => database_path('migrations/'.$timestamp.'_create_shoppingcart_table.php'),
+ ], 'migrations');
+ }
+ }
+}
diff --git a/packages/shoppingcart/_info/LICENSE b/packages/shoppingcart/_info/LICENSE
new file mode 100644
index 00000000..61c6afc7
--- /dev/null
+++ b/packages/shoppingcart/_info/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 Rob Gloudemans
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
\ No newline at end of file
diff --git a/packages/shoppingcart/_info/README.md b/packages/shoppingcart/_info/README.md
new file mode 100644
index 00000000..de8f5ab0
--- /dev/null
+++ b/packages/shoppingcart/_info/README.md
@@ -0,0 +1,477 @@
+## LaravelShoppingcart
+
+A simple shopping cart implementation for Laravel 7 & 8 & 9 & 10.
+
+## Installation
+
+Install the package through [Composer](http://getcomposer.org/).
+
+Run the Composer require command from the Terminal:
+
+ composer require mindscms/laravelshoppingcart
+
+### Laravel <= 7.0
+
+Should you still be on version 7.0 of Laravel, the final steps for you are to add the service provider of the package and alias the package. To do this open your `config/app.php` file.
+
+Add a new line to the `providers` array:
+
+ Gloudemans\Shoppingcart\ShoppingcartServiceProvider::class
+
+And optionally add a new line to the `aliases` array:
+
+ 'Cart' => Gloudemans\Shoppingcart\Facades\Cart::class,
+
+Now you're ready to start using the shopping cart in your application.
+
+**As of version 2 of this package it's possibly to use dependency injection to inject an instance of the Cart class into your controller or other class**
+
+## Overview
+Look at one of the following topics to learn more about LaravelShoppingcart
+
+* [Usage](#usage)
+* [Collections](#collections)
+* [Instances](#instances)
+* [Models](#models)
+* [Database](#database)
+* [Exceptions](#exceptions)
+* [Events](#events)
+* [Example](#example)
+
+## Usage
+
+The shoppingcart gives you the following methods to use:
+
+### Cart::add()
+
+Adding an item to the cart is really simple, you just use the `add()` method, which accepts a variety of parameters.
+
+In its most basic form you can specify the id, name, quantity, price of the product you'd like to add to the cart.
+
+```php
+Cart::add('293ad', 'Product 1', 1, 9.99);
+```
+
+As an optional fifth parameter you can pass it options, so you can add multiple items with the same id, but with (for instance) a different size.
+
+```php
+Cart::add('293ad', 'Product 1', 1, 9.99, ['size' => 'large']);
+```
+
+**The `add()` method will return an CartItem instance of the item you just added to the cart.**
+
+Maybe you prefer to add the item using an array? As long as the array contains the required keys, you can pass it to the method. The options key is optional.
+
+```php
+Cart::add(['id' => '293ad', 'name' => 'Product 1', 'qty' => 1, 'price' => 9.99, 'options' => ['size' => 'large']]);
+```
+
+New in version 2 of the package is the possibility to work with the `Buyable` interface. The way this works is that you have a model implement the `Buyable` interface, which will make you implement a few methods so the package knows how to get the id, name and price from your model.
+This way you can just pass the `add()` method a model and the quantity and it will automatically add it to the cart.
+
+**As an added bonus it will automatically associate the model with the CartItem**
+
+```php
+Cart::add($product, 1, ['size' => 'large']);
+```
+As an optional third parameter you can add options.
+```php
+Cart::add($product, 1, ['size' => 'large']);
+```
+
+Finally, you can also add multipe items to the cart at once.
+You can just pass the `add()` method an array of arrays, or an array of Buyables and they will be added to the cart.
+
+**When adding multiple items to the cart, the `add()` method will return an array of CartItems.**
+
+```php
+Cart::add([
+ ['id' => '293ad', 'name' => 'Product 1', 'qty' => 1, 'price' => 10.00],
+ ['id' => '4832k', 'name' => 'Product 2', 'qty' => 1, 'price' => 10.00, 'options' => ['size' => 'large']]
+]);
+
+Cart::add([$product1, $product2]);
+
+```
+
+### Cart::update()
+
+To update an item in the cart, you'll first need the rowId of the item.
+Next you can use the `update()` method to update it.
+
+If you simply want to update the quantity, you'll pass the update method the rowId and the new quantity:
+
+```php
+$rowId = 'da39a3ee5e6b4b0d3255bfef95601890afd80709';
+
+Cart::update($rowId, 2); // Will update the quantity
+```
+
+If you want to update more attributes of the item, you can either pass the update method an array or a `Buyable` as the second parameter. This way you can update all information of the item with the given rowId.
+
+```php
+Cart::update($rowId, ['name' => 'Product 1']); // Will update the name
+
+Cart::update($rowId, $product); // Will update the id, name and price
+
+```
+
+### Cart::remove()
+
+To remove an item for the cart, you'll again need the rowId. This rowId you simply pass to the `remove()` method and it will remove the item from the cart.
+
+```php
+$rowId = 'da39a3ee5e6b4b0d3255bfef95601890afd80709';
+
+Cart::remove($rowId);
+```
+
+### Cart::get()
+
+If you want to get an item from the cart using its rowId, you can simply call the `get()` method on the cart and pass it the rowId.
+
+```php
+$rowId = 'da39a3ee5e6b4b0d3255bfef95601890afd80709';
+
+Cart::get($rowId);
+```
+
+### Cart::content()
+
+Of course you also want to get the carts content. This is where you'll use the `content` method. This method will return a Collection of CartItems which you can iterate over and show the content to your customers.
+
+```php
+Cart::content();
+```
+
+This method will return the content of the current cart instance, if you want the content of another instance, simply chain the calls.
+
+```php
+Cart::instance('wishlist')->content();
+```
+
+### Cart::destroy()
+
+If you want to completely remove the content of a cart, you can call the destroy method on the cart. This will remove all CartItems from the cart for the current cart instance.
+
+```php
+Cart::destroy();
+```
+
+### Cart::total()
+
+The `total()` method can be used to get the calculated total of all items in the cart, given there price and quantity. Includes any additional costs too.
+
+```php
+Cart::total();
+```
+
+The method will automatically format the result, which you can tweak using the three optional parameters
+
+```php
+Cart::total($decimals, $decimalSeperator, $thousandSeperator);
+```
+
+You can set the default number format in the config file.
+
+**If you're not using the Facade, but use dependency injection in your (for instance) Controller, you can also simply get the total property `$cart->total`**
+
+### Cart::tax()
+
+The `tax()` method can be used to get the calculated amount of tax for all items in the cart, given there price and quantity.
+
+```php
+Cart::tax();
+```
+
+The method will automatically format the result, which you can tweak using the three optional parameters
+
+```php
+Cart::tax($decimals, $decimalSeperator, $thousandSeperator);
+```
+
+You can set the default number format in the config file.
+
+**If you're not using the Facade, but use dependency injection in your (for instance) Controller, you can also simply get the tax property `$cart->tax`**
+
+### Cart::subtotal()
+
+The `subtotal()` method can be used to get the total of all items in the cart, minus the total amount of tax.
+
+```php
+Cart::subtotal();
+```
+
+The method will automatically format the result, which you can tweak using the three optional parameters
+
+```php
+Cart::subtotal($decimals, $decimalSeperator, $thousandSeperator);
+```
+
+You can set the default number format in the config file.
+
+**If you're not using the Facade, but use dependency injection in your (for instance) Controller, you can also simply get the subtotal property `$cart->subtotal`**
+
+### Cart::count()
+
+If you want to know how many items there are in your cart, you can use the `count()` method. This method will return the total number of items in the cart. So if you've added 2 books and 1 shirt, it will return 3 items.
+
+```php
+Cart::count();
+```
+
+### Cart::search()
+
+To find an item in the cart, you can use the `search()` method.
+
+**This method was changed on version 2**
+
+Behind the scenes, the method simply uses the filter method of the Laravel Collection class. This means you must pass it a Closure in which you'll specify you search terms.
+
+If you for instance want to find all items with an id of 1:
+
+```php
+$cart->search(function ($cartItem, $rowId) {
+ return $cartItem->id === 1;
+});
+```
+
+As you can see the Closure will receive two parameters. The first is the CartItem to perform the check against. The second parameter is the rowId of this CartItem.
+
+**The method will return a Collection containing all CartItems that where found**
+
+This way of searching gives you total control over the search process and gives you the ability to create very precise and specific searches.
+
+### Cart::addCost()
+
+If you want to add additional costs to the cart you can use the `addCost()` method. The method accepts a cost name and the price of the cost. This can be used for eg shipping or transaction costs.
+
+```php
+Cart::addCost($name, $price)
+```
+
+**Add this method before summarizing the whole cart. The costs are not saved in the session (yet).**
+
+### Cart::getCost()
+
+Get an addition cost you added by `addCost()`. Accepts the cost name. Returns the formatted price of the cost.
+
+```php
+Cart::getCost($name, $decimals, $decimalPoint, $thousandSeperator)
+```
+
+## Collections
+
+On multiple instances the Cart will return to you a Collection. This is just a simple Laravel Collection, so all methods you can call on a Laravel Collection are also available on the result.
+
+As an example, you can quicky get the number of unique products in a cart:
+
+```php
+Cart::content()->count();
+```
+
+Or you can group the content by the id of the products:
+
+```php
+Cart::content()->groupBy('id');
+```
+
+## Instances
+
+The packages supports multiple instances of the cart. The way this works is like this:
+
+You can set the current instance of the cart by calling `Cart::instance('newInstance')`. From this moment, the active instance of the cart will be `newInstance`, so when you add, remove or get the content of the cart, you're work with the `newInstance` instance of the cart.
+If you want to switch instances, you just call `Cart::instance('otherInstance')` again, and you're working with the `otherInstance` again.
+
+So a little example:
+
+```php
+Cart::instance('shopping')->add('192ao12', 'Product 1', 1, 9.99);
+
+// Get the content of the 'shopping' cart
+Cart::content();
+
+Cart::instance('wishlist')->add('sdjk922', 'Product 2', 1, 19.95, ['size' => 'medium']);
+
+// Get the content of the 'wishlist' cart
+Cart::content();
+
+// If you want to get the content of the 'shopping' cart again
+Cart::instance('shopping')->content();
+
+// And the count of the 'wishlist' cart again
+Cart::instance('wishlist')->count();
+```
+
+**N.B. Keep in mind that the cart stays in the last set instance for as long as you don't set a different one during script execution.**
+
+**N.B.2 The default cart instance is called `default`, so when you're not using instances,`Cart::content();` is the same as `Cart::instance('default')->content()`.**
+
+## Models
+
+Because it can be very convenient to be able to directly access a model from a CartItem is it possible to associate a model with the items in the cart. Let's say you have a `Product` model in your application. With the `associate()` method, you can tell the cart that an item in the cart, is associated to the `Product` model.
+
+That way you can access your model right from the `CartItem`!
+
+The model can be accessed via the `model` property on the CartItem.
+
+**If your model implements the `Buyable` interface and you used your model to add the item to the cart, it will associate automatically.**
+
+Here is an example:
+
+```php
+
+// First we'll add the item to the cart.
+$cartItem = Cart::add('293ad', 'Product 1', 1, 9.99, ['size' => 'large']);
+
+// Next we associate a model with the item.
+Cart::associate($cartItem->rowId, 'Product');
+
+// Or even easier, call the associate method on the CartItem!
+$cartItem->associate('Product');
+
+// You can even make it a one-liner
+Cart::add('293ad', 'Product 1', 1, 9.99, ['size' => 'large'])->associate('Product');
+
+// Now, when iterating over the content of the cart, you can access the model.
+foreach(Cart::content() as $row) {
+ echo 'You have ' . $row->qty . ' items of ' . $row->model->name . ' with description: "' . $row->model->description . '" in your cart.';
+}
+```
+## Database
+
+- [Config](#configuration)
+- [Storing the cart](#save-cart-to-database)
+- [Restoring the cart](#retrieve-cart-from-database)
+
+### Configuration
+To save cart into the database so you can retrieve it later, the package needs to know which database connection to use and what the name of the table is.
+By default the package will use the default database connection and use a table named `shopping_cart`.
+If you want to change these options, you'll have to publish the `config` file.
+
+ php artisan vendor:publish --provider="Gloudemans\Shoppingcart\ShoppingcartServiceProvider" --tag="config"
+
+This will give you a `cart.php` config file in which you can make the changes.
+
+To make your life easy, the package also includes a ready to use `migration` which you can publish by running:
+
+ php artisan vendor:publish --provider="Gloudemans\Shoppingcart\ShoppingcartServiceProvider" --tag="migrations"
+
+This will place a `shopping_cart` table's migration file into `database/migrations` directory. Now all you have to do is run `php artisan migrate` to migrate your database.
+
+### Storing the cart
+To store your cart instance into the database, you have to call the `store($identifier) ` method. Where `$identifier` is a random key, for instance the id or username of the user.
+
+ Cart::store('username');
+
+ // To store a cart instance named 'wishlist'
+ Cart::instance('wishlist')->store('username');
+
+### Restoring the cart
+If you want to retrieve the cart from the database and restore it, all you have to do is call the `restore($identifier)` where `$identifier` is the key you specified for the `store` method.
+
+ Cart::restore('username');
+
+ // To restore a cart instance named 'wishlist'
+ Cart::instance('wishlist')->restore('username');
+
+## Exceptions
+
+The Cart package will throw exceptions if something goes wrong. This way it's easier to debug your code using the Cart package or to handle the error based on the type of exceptions. The Cart packages can throw the following exceptions:
+
+| Exception | Reason |
+| ---------------------------- | ---------------------------------------------------------------------------------- |
+| *CartAlreadyStoredException* | When trying to store a cart that was already stored using the specified identifier |
+| *InvalidRowIDException* | When the rowId that got passed doesn't exists in the current cart instance |
+| *UnknownModelException* | When you try to associate an none existing model to a CartItem. |
+
+## Events
+
+The cart also has events build in. There are five events available for you to listen for.
+
+| Event | Fired | Parameter |
+| ------------- | ---------------------------------------- | -------------------------------- |
+| cart.added | When an item was added to the cart. | The `CartItem` that was added. |
+| cart.updated | When an item in the cart was updated. | The `CartItem` that was updated. |
+| cart.removed | When an item is removed from the cart. | The `CartItem` that was removed. |
+| cart.stored | When the content of a cart was stored. | - |
+| cart.restored | When the content of a cart was restored. | - |
+
+## Example
+
+Below is a little example of how to list the cart content in a table:
+
+```php
+
+// Add some items in your Controller.
+Cart::add('192ao12', 'Product 1', 1, 9.99);
+Cart::add('1239ad0', 'Product 2', 2, 5.95, ['size' => 'large']);
+
+// Set an additional cost (on the same page where you display your cart content)
+Cart::addCost(Cart::COST_TRANSACTION, 0.10);
+Cart::addCost(Cart::COST_SHIPPING, 5.00);
+Cart::addCost('somethingelse', 1.11);
+
+// Display the content in a View.
+
+
+
+ Product
+ Qty
+ Price
+ Subtotal
+
+
+
+
+
+
+
+
+
+ name; ?>
+ options->has('size') ? $row->options->size : ''); ?>
+
+
+ $price; ?>
+ $total; ?>
+
+
+
+
+
+
+
+
+
+ Subtotal
+
+
+
+
+ Tax
+
+
+
+
+ Transaction cost
+
+
+
+
+ Transaction cost
+
+
+
+
+ Transaction cost
+
+
+
+
+ Total
+
+
+
+
+```
diff --git a/packages/shoppingcart/_info/_composer.json b/packages/shoppingcart/_info/_composer.json
new file mode 100644
index 00000000..ee510155
--- /dev/null
+++ b/packages/shoppingcart/_info/_composer.json
@@ -0,0 +1,51 @@
+{
+ "name": "mindscms/laravelshoppingcart",
+ "description": "Laravel Shopping cart",
+ "keywords": ["laravel", "shoppingcart"],
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Rob Gloudemans",
+ "email": "info@robgloudemans.nl"
+ },
+ {
+ "name": "Michael V.",
+ "email": "michael@michaelbelgium.me"
+ },
+ {
+ "name": "Sami Mansour",
+ "email": "mindscms@gmail.com"
+ }
+ ],
+ "require": {
+ "illuminate/support": "^7.0|^8.0|^9.0|^10.0",
+ "illuminate/session": "^7.0|^8.0|^9.0|^10.0",
+ "illuminate/events": "^7.0|^8.0|^9.0|^10.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.5|^10.1",
+ "mockery/mockery": "^1.4",
+ "orchestra/testbench": "^7"
+ },
+ "autoload": {
+ "psr-4": {
+ "Gloudemans\\Shoppingcart\\": "src/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Gloudemans\\Tests\\Shoppingcart\\": "tests/"
+ }
+ },
+ "minimum-stability": "stable",
+ "extra": {
+ "laravel": {
+ "providers": [
+ "Gloudemans\\Shoppingcart\\ShoppingcartServiceProvider"
+ ],
+ "aliases": {
+ "Cart": "Gloudemans\\Shoppingcart\\Facades\\Cart"
+ }
+ }
+ }
+}
diff --git a/packages/shoppingcart/_info/phpunit.xml b/packages/shoppingcart/_info/phpunit.xml
new file mode 100644
index 00000000..f994f39a
--- /dev/null
+++ b/packages/shoppingcart/_info/phpunit.xml
@@ -0,0 +1,17 @@
+
+
+
+
+ ./tests/
+
+
+
\ No newline at end of file
diff --git a/packages/shoppingcart/_info/tests/CartAssertions.php b/packages/shoppingcart/_info/tests/CartAssertions.php
new file mode 100644
index 00000000..c351f405
--- /dev/null
+++ b/packages/shoppingcart/_info/tests/CartAssertions.php
@@ -0,0 +1,35 @@
+count();
+
+ PHPUnit::assertEquals($items, $cart->count(), "Expected the cart to contain {$items} items, but got {$actual}.");
+ }
+
+ /**
+ * Assert that the cart contains the given number of rows.
+ *
+ * @param int $rows
+ * @param \Gloudemans\Shoppingcart\Cart $cart
+ */
+ public function assertRowsInCart($rows, Cart $cart)
+ {
+ $actual = $cart->content()->count();
+
+ PHPUnit::assertCount($rows, $cart->content(), "Expected the cart to contain {$rows} rows, but got {$actual}.");
+ }
+}
diff --git a/packages/shoppingcart/_info/tests/CartItemTest.php b/packages/shoppingcart/_info/tests/CartItemTest.php
new file mode 100644
index 00000000..ac0bdf45
--- /dev/null
+++ b/packages/shoppingcart/_info/tests/CartItemTest.php
@@ -0,0 +1,55 @@
+ 'XL', 'color' => 'red']);
+ $cartItem->setQuantity(2);
+
+ $this->assertEquals([
+ 'id' => 1,
+ 'name' => 'Some item',
+ 'price' => 10.00,
+ 'rowId' => '07d5da5550494c62daf9993cf954303f',
+ 'qty' => 2,
+ 'options' => [
+ 'size' => 'XL',
+ 'color' => 'red'
+ ],
+ 'tax' => 0,
+ 'subtotal' => 20.00,
+ ], $cartItem->toArray());
+ }
+
+ /** @test */
+ public function it_can_be_cast_to_json()
+ {
+ $cartItem = new CartItem(1, 'Some item', 10.00, ['size' => 'XL', 'color' => 'red']);
+ $cartItem->setQuantity(2);
+
+ $this->assertJson($cartItem->toJson());
+
+ $json = '{"rowId":"07d5da5550494c62daf9993cf954303f","id":1,"name":"Some item","qty":2,"price":10,"options":{"size":"XL","color":"red"},"tax":"0.00","subtotal":"20.00"}';
+
+ $this->assertEquals($json, $cartItem->toJson());
+ }
+}
\ No newline at end of file
diff --git a/packages/shoppingcart/_info/tests/CartTest.php b/packages/shoppingcart/_info/tests/CartTest.php
new file mode 100644
index 00000000..ae2f878e
--- /dev/null
+++ b/packages/shoppingcart/_info/tests/CartTest.php
@@ -0,0 +1,945 @@
+set('cart.database.connection', 'testing');
+
+ $app['config']->set('session.driver', 'array');
+
+ $app['config']->set('database.default', 'testing');
+ $app['config']->set('database.connections.testing', [
+ 'driver' => 'sqlite',
+ 'database' => ':memory:',
+ 'prefix' => '',
+ ]);
+ }
+
+ /**
+ * Setup the test environment.
+ *
+ * @return void
+ */
+ protected function setUp()
+ {
+ parent::setUp();
+
+ $this->app->afterResolving('migrator', function ($migrator) {
+ $migrator->path(realpath(__DIR__.'/../database/migrations'));
+ });
+ }
+
+ /** @test */
+ public function it_has_a_default_instance()
+ {
+ $cart = $this->getCart();
+
+ $this->assertEquals(Cart::DEFAULT_INSTANCE, $cart->currentInstance());
+ }
+
+ /** @test */
+ public function it_can_have_multiple_instances()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct(1, 'First item'));
+
+ $cart->instance('wishlist')->add(new BuyableProduct(2, 'Second item'));
+
+ $this->assertItemsInCart(1, $cart->instance(Cart::DEFAULT_INSTANCE));
+ $this->assertItemsInCart(1, $cart->instance('wishlist'));
+ }
+
+ /** @test */
+ public function it_can_add_an_item()
+ {
+ Event::fake();
+
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct);
+
+ $this->assertEquals(1, $cart->count());
+
+ Event::assertDispatched('cart.added');
+ }
+
+ /** @test */
+ public function it_will_return_the_cartitem_of_the_added_item()
+ {
+ Event::fake();
+
+ $cart = $this->getCart();
+
+ $cartItem = $cart->add(new BuyableProduct);
+
+ $this->assertInstanceOf(CartItem::class, $cartItem);
+ $this->assertEquals('027c91341fd5cf4d2579b49c4b6a90da', $cartItem->rowId);
+
+ Event::assertDispatched('cart.added');
+ }
+
+ /** @test */
+ public function it_can_add_multiple_buyable_items_at_once()
+ {
+ Event::fake();
+
+ $cart = $this->getCart();
+
+ $cart->add([new BuyableProduct(1), new BuyableProduct(2)]);
+
+ $this->assertEquals(2, $cart->count());
+
+ Event::assertDispatched('cart.added');
+ }
+
+ /** @test */
+ public function it_will_return_an_array_of_cartitems_when_you_add_multiple_items_at_once()
+ {
+ Event::fake();
+
+ $cart = $this->getCart();
+
+ $cartItems = $cart->add([new BuyableProduct(1), new BuyableProduct(2)]);
+
+ $this->assertTrue(is_array($cartItems));
+ $this->assertCount(2, $cartItems);
+ $this->assertContainsOnlyInstancesOf(CartItem::class, $cartItems);
+
+ Event::assertDispatched('cart.added');
+ }
+
+ /** @test */
+ public function it_can_add_an_item_from_attributes()
+ {
+ Event::fake();
+
+ $cart = $this->getCart();
+
+ $cart->add(1, 'Test item', 1, 10.00);
+
+ $this->assertEquals(1, $cart->count());
+
+ Event::assertDispatched('cart.added');
+ }
+
+ /** @test */
+ public function it_can_add_an_item_from_an_array()
+ {
+ Event::fake();
+
+ $cart = $this->getCart();
+
+ $cart->add(['id' => 1, 'name' => 'Test item', 'qty' => 1, 'price' => 10.00]);
+
+ $this->assertEquals(1, $cart->count());
+
+ Event::assertDispatched('cart.added');
+ }
+
+ /** @test */
+ public function it_can_add_multiple_array_items_at_once()
+ {
+ Event::fake();
+
+ $cart = $this->getCart();
+
+ $cart->add([
+ ['id' => 1, 'name' => 'Test item 1', 'qty' => 1, 'price' => 10.00],
+ ['id' => 2, 'name' => 'Test item 2', 'qty' => 1, 'price' => 10.00]
+ ]);
+
+ $this->assertEquals(2, $cart->count());
+
+ Event::assertDispatched('cart.added');
+ }
+
+ /** @test */
+ public function it_can_add_an_item_with_options()
+ {
+ Event::fake();
+
+ $cart = $this->getCart();
+
+ $options = ['size' => 'XL', 'color' => 'red'];
+
+ $cart->add(new BuyableProduct, 1, $options);
+
+ $cartItem = $cart->get('07d5da5550494c62daf9993cf954303f');
+
+ $this->assertInstanceOf(CartItem::class, $cartItem);
+ $this->assertEquals('XL', $cartItem->options->size);
+ $this->assertEquals('red', $cartItem->options->color);
+
+ Event::assertDispatched('cart.added');
+ }
+
+ /**
+ * @test
+ * @expectedException \InvalidArgumentException
+ * @expectedExceptionMessage Please supply a valid identifier.
+ */
+ public function it_will_validate_the_identifier()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(null, 'Some title', 1, 10.00);
+ }
+
+ /**
+ * @test
+ * @expectedException \InvalidArgumentException
+ * @expectedExceptionMessage Please supply a valid name.
+ */
+ public function it_will_validate_the_name()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(1, null, 1, 10.00);
+ }
+
+ /**
+ * @test
+ * @expectedException \InvalidArgumentException
+ * @expectedExceptionMessage Please supply a valid quantity.
+ */
+ public function it_will_validate_the_quantity()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(1, 'Some title', 'invalid', 10.00);
+ }
+
+ /**
+ * @test
+ * @expectedException \InvalidArgumentException
+ * @expectedExceptionMessage Please supply a valid price.
+ */
+ public function it_will_validate_the_price()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(1, 'Some title', 1, 'invalid');
+ }
+
+ /** @test */
+ public function it_will_update_the_cart_if_the_item_already_exists_in_the_cart()
+ {
+ $cart = $this->getCart();
+
+ $item = new BuyableProduct;
+
+ $cart->add($item);
+ $cart->add($item);
+
+ $this->assertItemsInCart(2, $cart);
+ $this->assertRowsInCart(1, $cart);
+ }
+
+ /** @test */
+ public function it_will_keep_updating_the_quantity_when_an_item_is_added_multiple_times()
+ {
+ $cart = $this->getCart();
+
+ $item = new BuyableProduct;
+
+ $cart->add($item);
+ $cart->add($item);
+ $cart->add($item);
+
+ $this->assertItemsInCart(3, $cart);
+ $this->assertRowsInCart(1, $cart);
+ }
+
+ /** @test */
+ public function it_can_update_the_quantity_of_an_existing_item_in_the_cart()
+ {
+ Event::fake();
+
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct);
+
+ $cart->update('027c91341fd5cf4d2579b49c4b6a90da', 2);
+
+ $this->assertItemsInCart(2, $cart);
+ $this->assertRowsInCart(1, $cart);
+
+ Event::assertDispatched('cart.updated');
+ }
+
+ /** @test */
+ public function it_can_update_an_existing_item_in_the_cart_from_a_buyable()
+ {
+ Event::fake();
+
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct);
+
+ $cart->update('027c91341fd5cf4d2579b49c4b6a90da', new BuyableProduct(1, 'Different description'));
+
+ $this->assertItemsInCart(1, $cart);
+ $this->assertEquals('Different description', $cart->get('027c91341fd5cf4d2579b49c4b6a90da')->name);
+
+ Event::assertDispatched('cart.updated');
+ }
+
+ /** @test */
+ public function it_can_update_an_existing_item_in_the_cart_from_an_array()
+ {
+ Event::fake();
+
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct);
+
+ $cart->update('027c91341fd5cf4d2579b49c4b6a90da', ['name' => 'Different description']);
+
+ $this->assertItemsInCart(1, $cart);
+ $this->assertEquals('Different description', $cart->get('027c91341fd5cf4d2579b49c4b6a90da')->name);
+
+ Event::assertDispatched('cart.updated');
+ }
+
+ /**
+ * @test
+ * @expectedException \Gloudemans\Shoppingcart\Exceptions\InvalidRowIDException
+ */
+ public function it_will_throw_an_exception_if_a_rowid_was_not_found()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct);
+
+ $cart->update('none-existing-rowid', new BuyableProduct(1, 'Different description'));
+ }
+
+ /** @test */
+ public function it_will_regenerate_the_rowid_if_the_options_changed()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct, 1, ['color' => 'red']);
+
+ $cart->update('ea65e0bdcd1967c4b3149e9e780177c0', ['options' => ['color' => 'blue']]);
+
+ $this->assertItemsInCart(1, $cart);
+ $this->assertEquals('7e70a1e9aaadd18c72921a07aae5d011', $cart->content()->first()->rowId);
+ $this->assertEquals('blue', $cart->get('7e70a1e9aaadd18c72921a07aae5d011')->options->color);
+ }
+
+ /** @test */
+ public function it_will_add_the_item_to_an_existing_row_if_the_options_changed_to_an_existing_rowid()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct, 1, ['color' => 'red']);
+ $cart->add(new BuyableProduct, 1, ['color' => 'blue']);
+
+ $cart->update('7e70a1e9aaadd18c72921a07aae5d011', ['options' => ['color' => 'red']]);
+
+ $this->assertItemsInCart(2, $cart);
+ $this->assertRowsInCart(1, $cart);
+ }
+
+ /** @test */
+ public function it_can_remove_an_item_from_the_cart()
+ {
+ Event::fake();
+
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct);
+
+ $cart->remove('027c91341fd5cf4d2579b49c4b6a90da');
+
+ $this->assertItemsInCart(0, $cart);
+ $this->assertRowsInCart(0, $cart);
+
+ Event::assertDispatched('cart.removed');
+ }
+
+ /** @test */
+ public function it_will_remove_the_item_if_its_quantity_was_set_to_zero()
+ {
+ Event::fake();
+
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct);
+
+ $cart->update('027c91341fd5cf4d2579b49c4b6a90da', 0);
+
+ $this->assertItemsInCart(0, $cart);
+ $this->assertRowsInCart(0, $cart);
+
+ Event::assertDispatched('cart.removed');
+ }
+
+ /** @test */
+ public function it_will_remove_the_item_if_its_quantity_was_set_negative()
+ {
+ Event::fake();
+
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct);
+
+ $cart->update('027c91341fd5cf4d2579b49c4b6a90da', -1);
+
+ $this->assertItemsInCart(0, $cart);
+ $this->assertRowsInCart(0, $cart);
+
+ Event::assertDispatched('cart.removed');
+ }
+
+ /** @test */
+ public function it_can_get_an_item_from_the_cart_by_its_rowid()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct);
+
+ $cartItem = $cart->get('027c91341fd5cf4d2579b49c4b6a90da');
+
+ $this->assertInstanceOf(CartItem::class, $cartItem);
+ }
+
+ /** @test */
+ public function it_can_get_the_content_of_the_cart()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct(1));
+ $cart->add(new BuyableProduct(2));
+
+ $content = $cart->content();
+
+ $this->assertInstanceOf(Collection::class, $content);
+ $this->assertCount(2, $content);
+ }
+
+ /** @test */
+ public function it_will_return_an_empty_collection_if_the_cart_is_empty()
+ {
+ $cart = $this->getCart();
+
+ $content = $cart->content();
+
+ $this->assertInstanceOf(Collection::class, $content);
+ $this->assertCount(0, $content);
+ }
+
+ /** @test */
+ public function it_will_include_the_tax_and_subtotal_when_converted_to_an_array()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct(1));
+ $cart->add(new BuyableProduct(2));
+
+ $content = $cart->content();
+
+ $this->assertInstanceOf(Collection::class, $content);
+ $this->assertEquals([
+ '027c91341fd5cf4d2579b49c4b6a90da' => [
+ 'rowId' => '027c91341fd5cf4d2579b49c4b6a90da',
+ 'id' => 1,
+ 'name' => 'Item name',
+ 'qty' => 1,
+ 'price' => 10.00,
+ 'tax' => 2.10,
+ 'subtotal' => 10.0,
+ 'options' => [],
+ ],
+ '370d08585360f5c568b18d1f2e4ca1df' => [
+ 'rowId' => '370d08585360f5c568b18d1f2e4ca1df',
+ 'id' => 2,
+ 'name' => 'Item name',
+ 'qty' => 1,
+ 'price' => 10.00,
+ 'tax' => 2.10,
+ 'subtotal' => 10.0,
+ 'options' => [],
+ ]
+ ], $content->toArray());
+ }
+
+ /** @test */
+ public function it_can_destroy_a_cart()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct);
+
+ $this->assertItemsInCart(1, $cart);
+
+ $cart->destroy();
+
+ $this->assertItemsInCart(0, $cart);
+ }
+
+ /** @test */
+ public function it_can_get_the_total_price_of_the_cart_content()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct(1, 'First item', 10.00));
+ $cart->add(new BuyableProduct(2, 'Second item', 25.00), 2);
+
+ $this->assertItemsInCart(3, $cart);
+ $this->assertEquals(60.00, $cart->subtotal());
+ }
+
+ /** @test */
+ public function it_can_return_a_formatted_total()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct(1, 'First item', 1000.00));
+ $cart->add(new BuyableProduct(2, 'Second item', 2500.00), 2);
+
+ $this->assertItemsInCart(3, $cart);
+ $this->assertEquals('6.000,00', $cart->subtotal(2, ',', '.'));
+ }
+
+ /** @test */
+ public function it_can_search_the_cart_for_a_specific_item()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct(1, 'Some item'));
+ $cart->add(new BuyableProduct(2, 'Another item'));
+
+ $cartItem = $cart->search(function ($cartItem, $rowId) {
+ return $cartItem->name == 'Some item';
+ });
+
+ $this->assertInstanceOf(Collection::class, $cartItem);
+ $this->assertCount(1, $cartItem);
+ $this->assertInstanceOf(CartItem::class, $cartItem->first());
+ $this->assertEquals(1, $cartItem->first()->id);
+ }
+
+ /** @test */
+ public function it_can_search_the_cart_for_multiple_items()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct(1, 'Some item'));
+ $cart->add(new BuyableProduct(2, 'Some item'));
+ $cart->add(new BuyableProduct(3, 'Another item'));
+
+ $cartItem = $cart->search(function ($cartItem, $rowId) {
+ return $cartItem->name == 'Some item';
+ });
+
+ $this->assertInstanceOf(Collection::class, $cartItem);
+ }
+
+ /** @test */
+ public function it_can_search_the_cart_for_a_specific_item_with_options()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct(1, 'Some item'), 1, ['color' => 'red']);
+ $cart->add(new BuyableProduct(2, 'Another item'), 1, ['color' => 'blue']);
+
+ $cartItem = $cart->search(function ($cartItem, $rowId) {
+ return $cartItem->options->color == 'red';
+ });
+
+ $this->assertInstanceOf(Collection::class, $cartItem);
+ $this->assertCount(1, $cartItem);
+ $this->assertInstanceOf(CartItem::class, $cartItem->first());
+ $this->assertEquals(1, $cartItem->first()->id);
+ }
+
+ /** @test */
+ public function it_will_associate_the_cart_item_with_a_model_when_you_add_a_buyable()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct);
+
+ $cartItem = $cart->get('027c91341fd5cf4d2579b49c4b6a90da');
+
+ $this->assertContains(BuyableProduct::class, Assert::readAttribute($cartItem, 'associatedModel'));
+ }
+
+ /** @test */
+ public function it_can_associate_the_cart_item_with_a_model()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(1, 'Test item', 1, 10.00);
+
+ $cart->associate('027c91341fd5cf4d2579b49c4b6a90da', new ProductModel);
+
+ $cartItem = $cart->get('027c91341fd5cf4d2579b49c4b6a90da');
+
+ $this->assertEquals(ProductModel::class, Assert::readAttribute($cartItem, 'associatedModel'));
+ }
+
+ /**
+ * @test
+ * @expectedException \Gloudemans\Shoppingcart\Exceptions\UnknownModelException
+ * @expectedExceptionMessage The supplied model SomeModel does not exist.
+ */
+ public function it_will_throw_an_exception_when_a_non_existing_model_is_being_associated()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(1, 'Test item', 1, 10.00);
+
+ $cart->associate('027c91341fd5cf4d2579b49c4b6a90da', 'SomeModel');
+ }
+
+ /** @test */
+ public function it_can_get_the_associated_model_of_a_cart_item()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(1, 'Test item', 1, 10.00);
+
+ $cart->associate('027c91341fd5cf4d2579b49c4b6a90da', new ProductModel);
+
+ $cartItem = $cart->get('027c91341fd5cf4d2579b49c4b6a90da');
+
+ $this->assertInstanceOf(ProductModel::class, $cartItem->model);
+ $this->assertEquals('Some value', $cartItem->model->someValue);
+ }
+
+ /** @test */
+ public function it_can_calculate_the_subtotal_of_a_cart_item()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct(1, 'Some title', 9.99), 3);
+
+ $cartItem = $cart->get('027c91341fd5cf4d2579b49c4b6a90da');
+
+ $this->assertEquals(29.97, $cartItem->subtotal);
+ }
+
+ /** @test */
+ public function it_can_return_a_formatted_subtotal()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct(1, 'Some title', 500), 3);
+
+ $cartItem = $cart->get('027c91341fd5cf4d2579b49c4b6a90da');
+
+ $this->assertEquals('1.500,00', $cartItem->subtotal(2, ',', '.'));
+ }
+
+ /** @test */
+ public function it_can_calculate_tax_based_on_the_default_tax_rate_in_the_config()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct(1, 'Some title', 10.00), 1);
+
+ $cartItem = $cart->get('027c91341fd5cf4d2579b49c4b6a90da');
+
+ $this->assertEquals(2.10, $cartItem->tax);
+ }
+
+ /** @test */
+ public function it_can_calculate_tax_based_on_the_specified_tax()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct(1, 'Some title', 10.00), 1);
+
+ $cart->setTax('027c91341fd5cf4d2579b49c4b6a90da', 19);
+
+ $cartItem = $cart->get('027c91341fd5cf4d2579b49c4b6a90da');
+
+ $this->assertEquals(1.90, $cartItem->tax);
+ }
+
+ /** @test */
+ public function it_can_return_the_calculated_tax_formatted()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct(1, 'Some title', 10000.00), 1);
+
+ $cartItem = $cart->get('027c91341fd5cf4d2579b49c4b6a90da');
+
+ $this->assertEquals('2.100,00', $cartItem->tax(2, ',', '.'));
+ }
+
+ /** @test */
+ public function it_can_calculate_the_total_tax_for_all_cart_items()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct(1, 'Some title', 10.00), 1);
+ $cart->add(new BuyableProduct(2, 'Some title', 20.00), 2);
+
+ $this->assertEquals(10.50, $cart->tax);
+ }
+
+ /** @test */
+ public function it_can_return_formatted_total_tax()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct(1, 'Some title', 1000.00), 1);
+ $cart->add(new BuyableProduct(2, 'Some title', 2000.00), 2);
+
+ $this->assertEquals('1.050,00', $cart->tax(2, ',', '.'));
+ }
+
+ /** @test */
+ public function it_can_return_the_subtotal()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct(1, 'Some title', 10.00), 1);
+ $cart->add(new BuyableProduct(2, 'Some title', 20.00), 2);
+
+ $this->assertEquals(50.00, $cart->subtotal);
+ }
+
+ /** @test */
+ public function it_can_return_formatted_subtotal()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct(1, 'Some title', 1000.00), 1);
+ $cart->add(new BuyableProduct(2, 'Some title', 2000.00), 2);
+
+ $this->assertEquals('5000,00', $cart->subtotal(2, ',', ''));
+ }
+
+ /** @test */
+ public function it_can_return_cart_formated_numbers_by_config_values()
+ {
+ $this->setConfigFormat(2, ',', '');
+
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct(1, 'Some title', 1000.00), 1);
+ $cart->add(new BuyableProduct(2, 'Some title', 2000.00), 2);
+
+ $this->assertEquals('5000,00', $cart->subtotal());
+ $this->assertEquals('1050,00', $cart->tax());
+ $this->assertEquals('6050,00', $cart->total());
+
+ $this->assertEquals('5000,00', $cart->subtotal);
+ $this->assertEquals('1050,00', $cart->tax);
+ $this->assertEquals('6050,00', $cart->total);
+ }
+
+ /** @test */
+ public function it_can_return_cartItem_formated_numbers_by_config_values()
+ {
+ $this->setConfigFormat(2, ',', '');
+
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct(1, 'Some title', 2000.00), 2);
+
+ $cartItem = $cart->get('027c91341fd5cf4d2579b49c4b6a90da');
+
+ $this->assertEquals('2000,00', $cartItem->price());
+ $this->assertEquals('2420,00', $cartItem->priceTax());
+ $this->assertEquals('4000,00', $cartItem->subtotal());
+ $this->assertEquals('4840,00', $cartItem->total());
+ $this->assertEquals('420,00', $cartItem->tax());
+ $this->assertEquals('840,00', $cartItem->taxTotal());
+ }
+
+ /** @test */
+ public function it_can_store_the_cart_in_a_database()
+ {
+ $this->artisan('migrate', [
+ '--database' => 'testing',
+ ]);
+
+ Event::fake();
+
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct);
+
+ $cart->store($identifier = 123);
+
+ $serialized = serialize($cart->content());
+
+ $this->assertDatabaseHas('shopping_cart', ['identifier' => $identifier, 'instance' => 'default', 'content' => $serialized]);
+
+ Event::assertDispatched('cart.stored');
+ }
+
+ /**
+ * @test
+ * @expectedException \Gloudemans\Shoppingcart\Exceptions\CartAlreadyStoredException
+ * @expectedExceptionMessage A cart with identifier 123 was already stored.
+ */
+ public function it_will_throw_an_exception_when_a_cart_was_already_stored_using_the_specified_identifier()
+ {
+ $this->artisan('migrate', [
+ '--database' => 'testing',
+ ]);
+
+ Event::fake();
+
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct);
+
+ $cart->store($identifier = 123);
+
+ $cart->store($identifier);
+
+ Event::assertDispatched('cart.stored');
+ }
+
+ /** @test */
+ public function it_can_restore_a_cart_from_the_database()
+ {
+ $this->artisan('migrate', [
+ '--database' => 'testing',
+ ]);
+
+ Event::fake();
+
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct);
+
+ $cart->store($identifier = 123);
+
+ $cart->destroy();
+
+ $this->assertItemsInCart(0, $cart);
+
+ $cart->restore($identifier);
+
+ $this->assertItemsInCart(1, $cart);
+
+ $this->assertDatabaseMissing('shopping_cart', ['identifier' => $identifier, 'instance' => 'default']);
+
+ Event::assertDispatched('cart.restored');
+ }
+
+ /** @test */
+ public function it_will_just_keep_the_current_instance_if_no_cart_with_the_given_identifier_was_stored()
+ {
+ $this->artisan('migrate', [
+ '--database' => 'testing',
+ ]);
+
+ $cart = $this->getCart();
+
+ $cart->restore($identifier = 123);
+
+ $this->assertItemsInCart(0, $cart);
+ }
+
+ /** @test */
+ public function it_can_calculate_all_values()
+ {
+ $cart = $this->getCart();
+
+ $cart->add(new BuyableProduct(1, 'First item', 10.00), 2);
+
+ $cartItem = $cart->get('027c91341fd5cf4d2579b49c4b6a90da');
+
+ $cart->setTax('027c91341fd5cf4d2579b49c4b6a90da', 19);
+
+ $this->assertEquals(10.00, $cartItem->price(2));
+ $this->assertEquals(11.90, $cartItem->priceTax(2));
+ $this->assertEquals(20.00, $cartItem->subtotal(2));
+ $this->assertEquals(23.80, $cartItem->total(2));
+ $this->assertEquals(1.90, $cartItem->tax(2));
+ $this->assertEquals(3.80, $cartItem->taxTotal(2));
+
+ $this->assertEquals(20.00, $cart->subtotal(2));
+ $this->assertEquals(23.80, $cart->total(2));
+ $this->assertEquals(3.80, $cart->tax(2));
+ }
+
+ /** @test */
+ public function it_will_destroy_the_cart_when_the_user_logs_out_and_the_config_setting_was_set_to_true()
+ {
+ $this->app['config']->set('cart.destroy_on_logout', true);
+
+ $this->app->instance(SessionManager::class, Mockery::mock(SessionManager::class, function ($mock) {
+ $mock->shouldReceive('forget')->once()->with('cart');
+ }));
+
+ $user = Mockery::mock(Authenticatable::class);
+
+ event(new Logout($user));
+ }
+
+ /**
+ * Get an instance of the cart.
+ *
+ * @return \Gloudemans\Shoppingcart\Cart
+ */
+ private function getCart()
+ {
+ $session = $this->app->make('session');
+ $events = $this->app->make('events');
+
+ return new Cart($session, $events);
+ }
+
+ /**
+ * Set the config number format.
+ *
+ * @param int $decimals
+ * @param string $decimalPoint
+ * @param string $thousandSeperator
+ */
+ private function setConfigFormat($decimals, $decimalPoint, $thousandSeperator)
+ {
+ $this->app['config']->set('cart.format.decimals', $decimals);
+ $this->app['config']->set('cart.format.decimal_point', $decimalPoint);
+ $this->app['config']->set('cart.format.thousand_separator', $thousandSeperator);
+ }
+}
diff --git a/packages/shoppingcart/_info/tests/Fixtures/BuyableProduct.php b/packages/shoppingcart/_info/tests/Fixtures/BuyableProduct.php
new file mode 100644
index 00000000..a58e830d
--- /dev/null
+++ b/packages/shoppingcart/_info/tests/Fixtures/BuyableProduct.php
@@ -0,0 +1,67 @@
+id = $id;
+ $this->name = $name;
+ $this->price = $price;
+ }
+
+ /**
+ * Get the identifier of the Buyable item.
+ *
+ * @return int|string
+ */
+ public function getBuyableIdentifier($options = null)
+ {
+ return $this->id;
+ }
+
+ /**
+ * Get the description or title of the Buyable item.
+ *
+ * @return string
+ */
+ public function getBuyableDescription($options = null)
+ {
+ return $this->name;
+ }
+
+ /**
+ * Get the price of the Buyable item.
+ *
+ * @return float
+ */
+ public function getBuyablePrice($options = null)
+ {
+ return $this->price;
+ }
+}
\ No newline at end of file
diff --git a/packages/shoppingcart/_info/tests/Fixtures/ProductModel.php b/packages/shoppingcart/_info/tests/Fixtures/ProductModel.php
new file mode 100644
index 00000000..70494ca5
--- /dev/null
+++ b/packages/shoppingcart/_info/tests/Fixtures/ProductModel.php
@@ -0,0 +1,13 @@
+ 15,
+
+ /*
+ |--------------------------------------------------------------------------
+ | Shopping cart database settings
+ |--------------------------------------------------------------------------
+ |
+ | Here you can set the connection that the shopping cart should use when
+ | storing and restoring a cart.
+ |
+ */
+
+ 'database' => [
+
+ 'connection' => env('DB_CONNECTION', 'mysql'),
+
+ 'table' => 'shopping_cart',
+
+ ],
+
+ /*
+ |--------------------------------------------------------------------------
+ | Destroy the cart on user logout
+ |--------------------------------------------------------------------------
+ |
+ | When this option is set to 'true' the cart will automatically
+ | destroy all cart instances when the user logs out.
+ |
+ */
+
+ 'destroy_on_logout' => false,
+
+ /*
+ |--------------------------------------------------------------------------
+ | Default number format
+ |--------------------------------------------------------------------------
+ |
+ | This defaults will be used for the formated numbers if you don't
+ | set them in the method call.
+ |
+ */
+
+ 'format' => [
+
+ 'decimals' => 2,
+
+ 'decimal_point' => '.',
+
+ 'thousand_separator' => ''
+
+ ],
+
+];
\ No newline at end of file
diff --git a/packages/shoppingcart/database/migrations/0000_00_00_000000_create_shopping_cart_table.php b/packages/shoppingcart/database/migrations/0000_00_00_000000_create_shopping_cart_table.php
new file mode 100644
index 00000000..891afc73
--- /dev/null
+++ b/packages/shoppingcart/database/migrations/0000_00_00_000000_create_shopping_cart_table.php
@@ -0,0 +1,30 @@
+string('identifier');
+ $table->string('instance');
+ $table->longText('content');
+ $table->nullableTimestamps();
+
+ $table->primary(['identifier', 'instance']);
+ });
+ }
+ /**
+ * Reverse the migrations.
+ */
+ public function down()
+ {
+ Schema::drop('shopping_cart');
+ }
+}
diff --git a/public/assets/images/produktfamilie.jpg b/public/assets/images/produktfamilie.jpg
index fc046519..a65c82c6 100644
Binary files a/public/assets/images/produktfamilie.jpg and b/public/assets/images/produktfamilie.jpg differ
diff --git a/public/assets/js/scripts.js b/public/assets/js/scripts.js
index c21ba24e..a2caeb4e 100644
--- a/public/assets/js/scripts.js
+++ b/public/assets/js/scripts.js
@@ -742,7 +742,12 @@
// Slide Panel
jQuery("a#sidepanel_btn").bind("click", function(e) {
e.preventDefault();
+ _sidepanel_open();
+
+ });
+
+ function _sidepanel_open() {
_pos = "right";
if(jQuery("#sidepanel").hasClass('sidepanel-inverse')) {
_pos = "left";
@@ -775,8 +780,7 @@
}
_sidepanel_overlay();
-
- });
+ }
// button close
jQuery("#sidepanel_close").bind("click", function(e) {
e.preventDefault();
@@ -798,6 +802,10 @@
}
});
+ if(jQuery("#sidepanel").data('init')){
+ jQuery("a#sidepanel_btn").trigger('click');
+ }
+
/** OVERLAY MENU
diff --git a/public/images/flags/ac.svg b/public/images/flags/ac.svg
new file mode 100644
index 00000000..b1ae9ac5
--- /dev/null
+++ b/public/images/flags/ac.svg
@@ -0,0 +1,689 @@
+
diff --git a/public/images/flags/ad.png b/public/images/flags/ad.png
deleted file mode 100755
index 625ca84f..00000000
Binary files a/public/images/flags/ad.png and /dev/null differ
diff --git a/public/images/flags/ad.svg b/public/images/flags/ad.svg
new file mode 100644
index 00000000..3793d99a
--- /dev/null
+++ b/public/images/flags/ad.svg
@@ -0,0 +1,150 @@
+
diff --git a/public/images/flags/ae.png b/public/images/flags/ae.png
deleted file mode 100755
index ef3a1ecf..00000000
Binary files a/public/images/flags/ae.png and /dev/null differ
diff --git a/public/images/flags/ae.svg b/public/images/flags/ae.svg
new file mode 100644
index 00000000..b7acdbdb
--- /dev/null
+++ b/public/images/flags/ae.svg
@@ -0,0 +1,6 @@
+
diff --git a/public/images/flags/af.png b/public/images/flags/af.png
deleted file mode 100755
index a4742e29..00000000
Binary files a/public/images/flags/af.png and /dev/null differ
diff --git a/public/images/flags/af.svg b/public/images/flags/af.svg
new file mode 100644
index 00000000..417dd047
--- /dev/null
+++ b/public/images/flags/af.svg
@@ -0,0 +1,81 @@
+
diff --git a/public/images/flags/ag.png b/public/images/flags/ag.png
deleted file mode 100755
index 556d5504..00000000
Binary files a/public/images/flags/ag.png and /dev/null differ
diff --git a/public/images/flags/ag.svg b/public/images/flags/ag.svg
new file mode 100644
index 00000000..250b5012
--- /dev/null
+++ b/public/images/flags/ag.svg
@@ -0,0 +1,14 @@
+
diff --git a/public/images/flags/ai.png b/public/images/flags/ai.png
deleted file mode 100755
index 74ed29d9..00000000
Binary files a/public/images/flags/ai.png and /dev/null differ
diff --git a/public/images/flags/ai.svg b/public/images/flags/ai.svg
new file mode 100644
index 00000000..81a857d5
--- /dev/null
+++ b/public/images/flags/ai.svg
@@ -0,0 +1,29 @@
+
diff --git a/public/images/flags/al.png b/public/images/flags/al.png
deleted file mode 100755
index 92354cb6..00000000
Binary files a/public/images/flags/al.png and /dev/null differ
diff --git a/public/images/flags/al.svg b/public/images/flags/al.svg
new file mode 100644
index 00000000..b69ae195
--- /dev/null
+++ b/public/images/flags/al.svg
@@ -0,0 +1,5 @@
+
diff --git a/public/images/flags/am.png b/public/images/flags/am.png
deleted file mode 100755
index 344a2a86..00000000
Binary files a/public/images/flags/am.png and /dev/null differ
diff --git a/public/images/flags/am.svg b/public/images/flags/am.svg
new file mode 100644
index 00000000..99fa4dc5
--- /dev/null
+++ b/public/images/flags/am.svg
@@ -0,0 +1,5 @@
+
diff --git a/public/images/flags/an.png b/public/images/flags/an.png
deleted file mode 100755
index 633e4b89..00000000
Binary files a/public/images/flags/an.png and /dev/null differ
diff --git a/public/images/flags/ao.png b/public/images/flags/ao.png
deleted file mode 100755
index bcbd1d6d..00000000
Binary files a/public/images/flags/ao.png and /dev/null differ
diff --git a/public/images/flags/ao.svg b/public/images/flags/ao.svg
new file mode 100644
index 00000000..4dc39f6a
--- /dev/null
+++ b/public/images/flags/ao.svg
@@ -0,0 +1,13 @@
+
diff --git a/public/images/flags/aq.svg b/public/images/flags/aq.svg
new file mode 100644
index 00000000..53840ccc
--- /dev/null
+++ b/public/images/flags/aq.svg
@@ -0,0 +1,5 @@
+
diff --git a/public/images/flags/ar.png b/public/images/flags/ar.png
deleted file mode 100755
index e5ef8f1f..00000000
Binary files a/public/images/flags/ar.png and /dev/null differ
diff --git a/public/images/flags/ar.svg b/public/images/flags/ar.svg
new file mode 100644
index 00000000..364fca8f
--- /dev/null
+++ b/public/images/flags/ar.svg
@@ -0,0 +1,32 @@
+
diff --git a/public/images/flags/arab.svg b/public/images/flags/arab.svg
new file mode 100644
index 00000000..c45e3d20
--- /dev/null
+++ b/public/images/flags/arab.svg
@@ -0,0 +1,109 @@
+
diff --git a/public/images/flags/as.png b/public/images/flags/as.png
deleted file mode 100755
index 32f30e4c..00000000
Binary files a/public/images/flags/as.png and /dev/null differ
diff --git a/public/images/flags/as.svg b/public/images/flags/as.svg
new file mode 100644
index 00000000..b974013a
--- /dev/null
+++ b/public/images/flags/as.svg
@@ -0,0 +1,72 @@
+
diff --git a/public/images/flags/at.png b/public/images/flags/at.png
deleted file mode 100755
index 0f15f34f..00000000
Binary files a/public/images/flags/at.png and /dev/null differ
diff --git a/public/images/flags/at.svg b/public/images/flags/at.svg
new file mode 100644
index 00000000..c2825088
--- /dev/null
+++ b/public/images/flags/at.svg
@@ -0,0 +1,6 @@
+
diff --git a/public/images/flags/au.png b/public/images/flags/au.png
deleted file mode 100755
index a01389a7..00000000
Binary files a/public/images/flags/au.png and /dev/null differ
diff --git a/public/images/flags/au.svg b/public/images/flags/au.svg
new file mode 100644
index 00000000..407fef43
--- /dev/null
+++ b/public/images/flags/au.svg
@@ -0,0 +1,8 @@
+
diff --git a/public/images/flags/aw.png b/public/images/flags/aw.png
deleted file mode 100755
index a3579c2d..00000000
Binary files a/public/images/flags/aw.png and /dev/null differ
diff --git a/public/images/flags/aw.svg b/public/images/flags/aw.svg
new file mode 100644
index 00000000..32cabd54
--- /dev/null
+++ b/public/images/flags/aw.svg
@@ -0,0 +1,186 @@
+
diff --git a/public/images/flags/ax.png b/public/images/flags/ax.png
deleted file mode 100755
index 1eea80a7..00000000
Binary files a/public/images/flags/ax.png and /dev/null differ
diff --git a/public/images/flags/ax.svg b/public/images/flags/ax.svg
new file mode 100644
index 00000000..0584d713
--- /dev/null
+++ b/public/images/flags/ax.svg
@@ -0,0 +1,18 @@
+
diff --git a/public/images/flags/az.png b/public/images/flags/az.png
deleted file mode 100755
index 4ee9fe5c..00000000
Binary files a/public/images/flags/az.png and /dev/null differ
diff --git a/public/images/flags/az.svg b/public/images/flags/az.svg
new file mode 100644
index 00000000..8e56ef53
--- /dev/null
+++ b/public/images/flags/az.svg
@@ -0,0 +1,8 @@
+
diff --git a/public/images/flags/ba.png b/public/images/flags/ba.png
deleted file mode 100755
index c7749924..00000000
Binary files a/public/images/flags/ba.png and /dev/null differ
diff --git a/public/images/flags/ba.svg b/public/images/flags/ba.svg
new file mode 100644
index 00000000..fcd18914
--- /dev/null
+++ b/public/images/flags/ba.svg
@@ -0,0 +1,12 @@
+
diff --git a/public/images/flags/bb.png b/public/images/flags/bb.png
deleted file mode 100755
index 0df19c71..00000000
Binary files a/public/images/flags/bb.png and /dev/null differ
diff --git a/public/images/flags/bb.svg b/public/images/flags/bb.svg
new file mode 100644
index 00000000..263bdec0
--- /dev/null
+++ b/public/images/flags/bb.svg
@@ -0,0 +1,6 @@
+
diff --git a/public/images/flags/bd.png b/public/images/flags/bd.png
deleted file mode 100755
index 076a8bf8..00000000
Binary files a/public/images/flags/bd.png and /dev/null differ
diff --git a/public/images/flags/bd.svg b/public/images/flags/bd.svg
new file mode 100644
index 00000000..16b794de
--- /dev/null
+++ b/public/images/flags/bd.svg
@@ -0,0 +1,4 @@
+
diff --git a/public/images/flags/be.png b/public/images/flags/be.png
deleted file mode 100755
index d86ebc80..00000000
Binary files a/public/images/flags/be.png and /dev/null differ
diff --git a/public/images/flags/be.svg b/public/images/flags/be.svg
new file mode 100644
index 00000000..327f28fa
--- /dev/null
+++ b/public/images/flags/be.svg
@@ -0,0 +1,7 @@
+
diff --git a/public/images/flags/bf.png b/public/images/flags/bf.png
deleted file mode 100755
index ab5ce8fe..00000000
Binary files a/public/images/flags/bf.png and /dev/null differ
diff --git a/public/images/flags/bf.svg b/public/images/flags/bf.svg
new file mode 100644
index 00000000..47138225
--- /dev/null
+++ b/public/images/flags/bf.svg
@@ -0,0 +1,7 @@
+
diff --git a/public/images/flags/bg.png b/public/images/flags/bg.png
deleted file mode 100755
index 0469f060..00000000
Binary files a/public/images/flags/bg.png and /dev/null differ
diff --git a/public/images/flags/bg.svg b/public/images/flags/bg.svg
new file mode 100644
index 00000000..b100dd0d
--- /dev/null
+++ b/public/images/flags/bg.svg
@@ -0,0 +1,7 @@
+
diff --git a/public/images/flags/bh.png b/public/images/flags/bh.png
deleted file mode 100755
index ea8ce687..00000000
Binary files a/public/images/flags/bh.png and /dev/null differ
diff --git a/public/images/flags/bh.svg b/public/images/flags/bh.svg
new file mode 100644
index 00000000..7a2ea549
--- /dev/null
+++ b/public/images/flags/bh.svg
@@ -0,0 +1,4 @@
+
diff --git a/public/images/flags/bi.png b/public/images/flags/bi.png
deleted file mode 100755
index 5cc2e30c..00000000
Binary files a/public/images/flags/bi.png and /dev/null differ
diff --git a/public/images/flags/bi.svg b/public/images/flags/bi.svg
new file mode 100644
index 00000000..1050838b
--- /dev/null
+++ b/public/images/flags/bi.svg
@@ -0,0 +1,15 @@
+
diff --git a/public/images/flags/bj.png b/public/images/flags/bj.png
deleted file mode 100755
index 1cc8b458..00000000
Binary files a/public/images/flags/bj.png and /dev/null differ
diff --git a/public/images/flags/bj.svg b/public/images/flags/bj.svg
new file mode 100644
index 00000000..0846724d
--- /dev/null
+++ b/public/images/flags/bj.svg
@@ -0,0 +1,14 @@
+
diff --git a/public/images/flags/bl.svg b/public/images/flags/bl.svg
new file mode 100644
index 00000000..819afc11
--- /dev/null
+++ b/public/images/flags/bl.svg
@@ -0,0 +1,5 @@
+
diff --git a/public/images/flags/bm.png b/public/images/flags/bm.png
deleted file mode 100755
index c0c7aead..00000000
Binary files a/public/images/flags/bm.png and /dev/null differ
diff --git a/public/images/flags/bm.svg b/public/images/flags/bm.svg
new file mode 100644
index 00000000..a4dbc728
--- /dev/null
+++ b/public/images/flags/bm.svg
@@ -0,0 +1,97 @@
+
diff --git a/public/images/flags/bn.png b/public/images/flags/bn.png
deleted file mode 100755
index 8fb09849..00000000
Binary files a/public/images/flags/bn.png and /dev/null differ
diff --git a/public/images/flags/bn.svg b/public/images/flags/bn.svg
new file mode 100644
index 00000000..f906abfe
--- /dev/null
+++ b/public/images/flags/bn.svg
@@ -0,0 +1,36 @@
+
diff --git a/public/images/flags/bo.png b/public/images/flags/bo.png
deleted file mode 100755
index ce7ba522..00000000
Binary files a/public/images/flags/bo.png and /dev/null differ
diff --git a/public/images/flags/bo.svg b/public/images/flags/bo.svg
new file mode 100644
index 00000000..17a0a0c1
--- /dev/null
+++ b/public/images/flags/bo.svg
@@ -0,0 +1,676 @@
+
diff --git a/public/images/flags/bq.svg b/public/images/flags/bq.svg
new file mode 100644
index 00000000..0e6bc76e
--- /dev/null
+++ b/public/images/flags/bq.svg
@@ -0,0 +1,5 @@
+
diff --git a/public/images/flags/br.png b/public/images/flags/br.png
deleted file mode 100755
index 9b1a5538..00000000
Binary files a/public/images/flags/br.png and /dev/null differ
diff --git a/public/images/flags/br.svg b/public/images/flags/br.svg
new file mode 100644
index 00000000..354a7013
--- /dev/null
+++ b/public/images/flags/br.svg
@@ -0,0 +1,45 @@
+
diff --git a/public/images/flags/bs.png b/public/images/flags/bs.png
deleted file mode 100755
index 639fa6cf..00000000
Binary files a/public/images/flags/bs.png and /dev/null differ
diff --git a/public/images/flags/bs.svg b/public/images/flags/bs.svg
new file mode 100644
index 00000000..513be43a
--- /dev/null
+++ b/public/images/flags/bs.svg
@@ -0,0 +1,13 @@
+
diff --git a/public/images/flags/bt.png b/public/images/flags/bt.png
deleted file mode 100755
index 1d512dff..00000000
Binary files a/public/images/flags/bt.png and /dev/null differ
diff --git a/public/images/flags/bt.svg b/public/images/flags/bt.svg
new file mode 100644
index 00000000..cea6006c
--- /dev/null
+++ b/public/images/flags/bt.svg
@@ -0,0 +1,89 @@
+
diff --git a/public/images/flags/bv.png b/public/images/flags/bv.png
deleted file mode 100755
index 160b6b5b..00000000
Binary files a/public/images/flags/bv.png and /dev/null differ
diff --git a/public/images/flags/bv.svg b/public/images/flags/bv.svg
new file mode 100644
index 00000000..40e16d94
--- /dev/null
+++ b/public/images/flags/bv.svg
@@ -0,0 +1,13 @@
+
diff --git a/public/images/flags/bw.png b/public/images/flags/bw.png
deleted file mode 100755
index fcb10394..00000000
Binary files a/public/images/flags/bw.png and /dev/null differ
diff --git a/public/images/flags/bw.svg b/public/images/flags/bw.svg
new file mode 100644
index 00000000..a1c8db0a
--- /dev/null
+++ b/public/images/flags/bw.svg
@@ -0,0 +1,7 @@
+
diff --git a/public/images/flags/by.png b/public/images/flags/by.png
deleted file mode 100755
index 504774ec..00000000
Binary files a/public/images/flags/by.png and /dev/null differ
diff --git a/public/images/flags/by.svg b/public/images/flags/by.svg
new file mode 100644
index 00000000..8d25ee3c
--- /dev/null
+++ b/public/images/flags/by.svg
@@ -0,0 +1,20 @@
+
diff --git a/public/images/flags/bz.png b/public/images/flags/bz.png
deleted file mode 100755
index be63ee1c..00000000
Binary files a/public/images/flags/bz.png and /dev/null differ
diff --git a/public/images/flags/bz.svg b/public/images/flags/bz.svg
new file mode 100644
index 00000000..08d3579d
--- /dev/null
+++ b/public/images/flags/bz.svg
@@ -0,0 +1,145 @@
+
diff --git a/public/images/flags/ca.png b/public/images/flags/ca.png
deleted file mode 100755
index 1f204193..00000000
Binary files a/public/images/flags/ca.png and /dev/null differ
diff --git a/public/images/flags/ca.svg b/public/images/flags/ca.svg
new file mode 100644
index 00000000..f1b2c968
--- /dev/null
+++ b/public/images/flags/ca.svg
@@ -0,0 +1,4 @@
+
diff --git a/public/images/flags/catalonia.png b/public/images/flags/catalonia.png
deleted file mode 100755
index 5041e308..00000000
Binary files a/public/images/flags/catalonia.png and /dev/null differ
diff --git a/public/images/flags/cc.png b/public/images/flags/cc.png
deleted file mode 100755
index aed3d3b4..00000000
Binary files a/public/images/flags/cc.png and /dev/null differ
diff --git a/public/images/flags/cc.svg b/public/images/flags/cc.svg
new file mode 100644
index 00000000..93025bd2
--- /dev/null
+++ b/public/images/flags/cc.svg
@@ -0,0 +1,19 @@
+
diff --git a/public/images/flags/cd.png b/public/images/flags/cd.png
deleted file mode 100755
index 5e489424..00000000
Binary files a/public/images/flags/cd.png and /dev/null differ
diff --git a/public/images/flags/cd.svg b/public/images/flags/cd.svg
new file mode 100644
index 00000000..e106ddd5
--- /dev/null
+++ b/public/images/flags/cd.svg
@@ -0,0 +1,5 @@
+
diff --git a/public/images/flags/cefta.svg b/public/images/flags/cefta.svg
new file mode 100644
index 00000000..f748d08a
--- /dev/null
+++ b/public/images/flags/cefta.svg
@@ -0,0 +1,13 @@
+
diff --git a/public/images/flags/cf.png b/public/images/flags/cf.png
deleted file mode 100755
index da687bdc..00000000
Binary files a/public/images/flags/cf.png and /dev/null differ
diff --git a/public/images/flags/cf.svg b/public/images/flags/cf.svg
new file mode 100644
index 00000000..a6cd3670
--- /dev/null
+++ b/public/images/flags/cf.svg
@@ -0,0 +1,15 @@
+
diff --git a/public/images/flags/cg.png b/public/images/flags/cg.png
deleted file mode 100755
index a859792e..00000000
Binary files a/public/images/flags/cg.png and /dev/null differ
diff --git a/public/images/flags/cg.svg b/public/images/flags/cg.svg
new file mode 100644
index 00000000..9128715f
--- /dev/null
+++ b/public/images/flags/cg.svg
@@ -0,0 +1,12 @@
+
diff --git a/public/images/flags/ch.png b/public/images/flags/ch.png
deleted file mode 100755
index 242ec01a..00000000
Binary files a/public/images/flags/ch.png and /dev/null differ
diff --git a/public/images/flags/ch.svg b/public/images/flags/ch.svg
new file mode 100644
index 00000000..b42d6709
--- /dev/null
+++ b/public/images/flags/ch.svg
@@ -0,0 +1,9 @@
+
diff --git a/public/images/flags/ci.png b/public/images/flags/ci.png
deleted file mode 100755
index 3f2c62eb..00000000
Binary files a/public/images/flags/ci.png and /dev/null differ
diff --git a/public/images/flags/ci.svg b/public/images/flags/ci.svg
new file mode 100644
index 00000000..e400f0c1
--- /dev/null
+++ b/public/images/flags/ci.svg
@@ -0,0 +1,7 @@
+
diff --git a/public/images/flags/ck.png b/public/images/flags/ck.png
deleted file mode 100755
index 746d3d6f..00000000
Binary files a/public/images/flags/ck.png and /dev/null differ
diff --git a/public/images/flags/ck.svg b/public/images/flags/ck.svg
new file mode 100644
index 00000000..18e547b1
--- /dev/null
+++ b/public/images/flags/ck.svg
@@ -0,0 +1,9 @@
+
diff --git a/public/images/flags/cl.png b/public/images/flags/cl.png
deleted file mode 100755
index 29c6d61b..00000000
Binary files a/public/images/flags/cl.png and /dev/null differ
diff --git a/public/images/flags/cl.svg b/public/images/flags/cl.svg
new file mode 100644
index 00000000..01766fef
--- /dev/null
+++ b/public/images/flags/cl.svg
@@ -0,0 +1,13 @@
+
diff --git a/public/images/flags/cm.png b/public/images/flags/cm.png
deleted file mode 100755
index f65c5bd5..00000000
Binary files a/public/images/flags/cm.png and /dev/null differ
diff --git a/public/images/flags/cm.svg b/public/images/flags/cm.svg
new file mode 100644
index 00000000..389b6627
--- /dev/null
+++ b/public/images/flags/cm.svg
@@ -0,0 +1,15 @@
+
diff --git a/public/images/flags/cn.png b/public/images/flags/cn.png
deleted file mode 100755
index 89144146..00000000
Binary files a/public/images/flags/cn.png and /dev/null differ
diff --git a/public/images/flags/cn.svg b/public/images/flags/cn.svg
new file mode 100644
index 00000000..10d3489a
--- /dev/null
+++ b/public/images/flags/cn.svg
@@ -0,0 +1,11 @@
+
diff --git a/public/images/flags/co.png b/public/images/flags/co.png
deleted file mode 100755
index a118ff4a..00000000
Binary files a/public/images/flags/co.png and /dev/null differ
diff --git a/public/images/flags/co.svg b/public/images/flags/co.svg
new file mode 100644
index 00000000..ebd0a0fb
--- /dev/null
+++ b/public/images/flags/co.svg
@@ -0,0 +1,7 @@
+
diff --git a/public/images/flags/cp.svg b/public/images/flags/cp.svg
new file mode 100644
index 00000000..b3efb074
--- /dev/null
+++ b/public/images/flags/cp.svg
@@ -0,0 +1,7 @@
+
diff --git a/public/images/flags/cr.png b/public/images/flags/cr.png
deleted file mode 100755
index c7a37317..00000000
Binary files a/public/images/flags/cr.png and /dev/null differ
diff --git a/public/images/flags/cr.svg b/public/images/flags/cr.svg
new file mode 100644
index 00000000..5a409eeb
--- /dev/null
+++ b/public/images/flags/cr.svg
@@ -0,0 +1,7 @@
+
diff --git a/public/images/flags/cs.png b/public/images/flags/cs.png
deleted file mode 100755
index 8254790c..00000000
Binary files a/public/images/flags/cs.png and /dev/null differ
diff --git a/public/images/flags/cu.png b/public/images/flags/cu.png
deleted file mode 100755
index 083f1d61..00000000
Binary files a/public/images/flags/cu.png and /dev/null differ
diff --git a/public/images/flags/cu.svg b/public/images/flags/cu.svg
new file mode 100644
index 00000000..6464f8eb
--- /dev/null
+++ b/public/images/flags/cu.svg
@@ -0,0 +1,13 @@
+
diff --git a/public/images/flags/cv.png b/public/images/flags/cv.png
deleted file mode 100755
index a63f7eaf..00000000
Binary files a/public/images/flags/cv.png and /dev/null differ
diff --git a/public/images/flags/cv.svg b/public/images/flags/cv.svg
new file mode 100644
index 00000000..5c251da2
--- /dev/null
+++ b/public/images/flags/cv.svg
@@ -0,0 +1,13 @@
+
diff --git a/public/images/flags/cw.svg b/public/images/flags/cw.svg
new file mode 100644
index 00000000..bb0ece22
--- /dev/null
+++ b/public/images/flags/cw.svg
@@ -0,0 +1,14 @@
+
diff --git a/public/images/flags/cx.png b/public/images/flags/cx.png
deleted file mode 100755
index 48e31adb..00000000
Binary files a/public/images/flags/cx.png and /dev/null differ
diff --git a/public/images/flags/cx.svg b/public/images/flags/cx.svg
new file mode 100644
index 00000000..6803b3b6
--- /dev/null
+++ b/public/images/flags/cx.svg
@@ -0,0 +1,15 @@
+
diff --git a/public/images/flags/cy.png b/public/images/flags/cy.png
deleted file mode 100755
index 5b1ad6c0..00000000
Binary files a/public/images/flags/cy.png and /dev/null differ
diff --git a/public/images/flags/cy.svg b/public/images/flags/cy.svg
new file mode 100644
index 00000000..2f69bf79
--- /dev/null
+++ b/public/images/flags/cy.svg
@@ -0,0 +1,6 @@
+
diff --git a/public/images/flags/cz.png b/public/images/flags/cz.png
deleted file mode 100755
index c8403dd2..00000000
Binary files a/public/images/flags/cz.png and /dev/null differ
diff --git a/public/images/flags/cz.svg b/public/images/flags/cz.svg
new file mode 100644
index 00000000..7913de38
--- /dev/null
+++ b/public/images/flags/cz.svg
@@ -0,0 +1,5 @@
+
diff --git a/public/images/flags/de.png b/public/images/flags/de.png
deleted file mode 100755
index ac4a9773..00000000
Binary files a/public/images/flags/de.png and /dev/null differ
diff --git a/public/images/flags/de.svg b/public/images/flags/de.svg
new file mode 100644
index 00000000..b08334b6
--- /dev/null
+++ b/public/images/flags/de.svg
@@ -0,0 +1,5 @@
+
diff --git a/public/images/flags/dg.svg b/public/images/flags/dg.svg
new file mode 100644
index 00000000..b9f99a99
--- /dev/null
+++ b/public/images/flags/dg.svg
@@ -0,0 +1,130 @@
+
diff --git a/public/images/flags/dj.png b/public/images/flags/dj.png
deleted file mode 100755
index 582af364..00000000
Binary files a/public/images/flags/dj.png and /dev/null differ
diff --git a/public/images/flags/dj.svg b/public/images/flags/dj.svg
new file mode 100644
index 00000000..ebf2fc66
--- /dev/null
+++ b/public/images/flags/dj.svg
@@ -0,0 +1,13 @@
+
diff --git a/public/images/flags/dk.png b/public/images/flags/dk.png
deleted file mode 100755
index e2993d3c..00000000
Binary files a/public/images/flags/dk.png and /dev/null differ
diff --git a/public/images/flags/dk.svg b/public/images/flags/dk.svg
new file mode 100644
index 00000000..563277f8
--- /dev/null
+++ b/public/images/flags/dk.svg
@@ -0,0 +1,5 @@
+
diff --git a/public/images/flags/dm.png b/public/images/flags/dm.png
deleted file mode 100755
index 5fbffcba..00000000
Binary files a/public/images/flags/dm.png and /dev/null differ
diff --git a/public/images/flags/dm.svg b/public/images/flags/dm.svg
new file mode 100644
index 00000000..60457b79
--- /dev/null
+++ b/public/images/flags/dm.svg
@@ -0,0 +1,152 @@
+
diff --git a/public/images/flags/do.png b/public/images/flags/do.png
deleted file mode 100755
index 5a04932d..00000000
Binary files a/public/images/flags/do.png and /dev/null differ
diff --git a/public/images/flags/do.svg b/public/images/flags/do.svg
new file mode 100644
index 00000000..d8376900
--- /dev/null
+++ b/public/images/flags/do.svg
@@ -0,0 +1,121 @@
+
diff --git a/public/images/flags/dz.png b/public/images/flags/dz.png
deleted file mode 100755
index 335c2391..00000000
Binary files a/public/images/flags/dz.png and /dev/null differ
diff --git a/public/images/flags/dz.svg b/public/images/flags/dz.svg
new file mode 100644
index 00000000..5ff29a74
--- /dev/null
+++ b/public/images/flags/dz.svg
@@ -0,0 +1,5 @@
+
diff --git a/public/images/flags/eac.svg b/public/images/flags/eac.svg
new file mode 100644
index 00000000..25a09a13
--- /dev/null
+++ b/public/images/flags/eac.svg
@@ -0,0 +1,48 @@
+
diff --git a/public/images/flags/ec.png b/public/images/flags/ec.png
deleted file mode 100755
index 0caa0b1e..00000000
Binary files a/public/images/flags/ec.png and /dev/null differ
diff --git a/public/images/flags/ec.svg b/public/images/flags/ec.svg
new file mode 100644
index 00000000..65b78858
--- /dev/null
+++ b/public/images/flags/ec.svg
@@ -0,0 +1,138 @@
+
diff --git a/public/images/flags/ee.png b/public/images/flags/ee.png
deleted file mode 100755
index 0c82efb7..00000000
Binary files a/public/images/flags/ee.png and /dev/null differ
diff --git a/public/images/flags/ee.svg b/public/images/flags/ee.svg
new file mode 100644
index 00000000..36ea288c
--- /dev/null
+++ b/public/images/flags/ee.svg
@@ -0,0 +1,7 @@
+
diff --git a/public/images/flags/eg.png b/public/images/flags/eg.png
deleted file mode 100755
index 8a3f7a10..00000000
Binary files a/public/images/flags/eg.png and /dev/null differ
diff --git a/public/images/flags/eg.svg b/public/images/flags/eg.svg
new file mode 100644
index 00000000..58c943c2
--- /dev/null
+++ b/public/images/flags/eg.svg
@@ -0,0 +1,38 @@
+
diff --git a/public/images/flags/eh.png b/public/images/flags/eh.png
deleted file mode 100755
index 90a1195b..00000000
Binary files a/public/images/flags/eh.png and /dev/null differ
diff --git a/public/images/flags/eh.svg b/public/images/flags/eh.svg
new file mode 100644
index 00000000..2c9525bd
--- /dev/null
+++ b/public/images/flags/eh.svg
@@ -0,0 +1,16 @@
+
diff --git a/public/images/flags/en.svg b/public/images/flags/en.svg
new file mode 100644
index 00000000..dbac25ea
--- /dev/null
+++ b/public/images/flags/en.svg
@@ -0,0 +1,7 @@
+
diff --git a/public/images/flags/england.png b/public/images/flags/england.png
deleted file mode 100755
index 3a7311d5..00000000
Binary files a/public/images/flags/england.png and /dev/null differ
diff --git a/public/images/flags/er.png b/public/images/flags/er.png
deleted file mode 100755
index 13065ae9..00000000
Binary files a/public/images/flags/er.png and /dev/null differ
diff --git a/public/images/flags/er.svg b/public/images/flags/er.svg
new file mode 100644
index 00000000..2705295f
--- /dev/null
+++ b/public/images/flags/er.svg
@@ -0,0 +1,8 @@
+
diff --git a/public/images/flags/es-ct.svg b/public/images/flags/es-ct.svg
new file mode 100644
index 00000000..4d859114
--- /dev/null
+++ b/public/images/flags/es-ct.svg
@@ -0,0 +1,4 @@
+
diff --git a/public/images/flags/es-ga.svg b/public/images/flags/es-ga.svg
new file mode 100644
index 00000000..a91ffed0
--- /dev/null
+++ b/public/images/flags/es-ga.svg
@@ -0,0 +1,187 @@
+
diff --git a/public/images/flags/es-pv.svg b/public/images/flags/es-pv.svg
new file mode 100644
index 00000000..21c8759e
--- /dev/null
+++ b/public/images/flags/es-pv.svg
@@ -0,0 +1,5 @@
+
diff --git a/public/images/flags/es.png b/public/images/flags/es.png
deleted file mode 100755
index c2de2d71..00000000
Binary files a/public/images/flags/es.png and /dev/null differ
diff --git a/public/images/flags/es.svg b/public/images/flags/es.svg
new file mode 100644
index 00000000..815e0f84
--- /dev/null
+++ b/public/images/flags/es.svg
@@ -0,0 +1,544 @@
+
diff --git a/public/images/flags/et.png b/public/images/flags/et.png
deleted file mode 100755
index 2e893fa0..00000000
Binary files a/public/images/flags/et.png and /dev/null differ
diff --git a/public/images/flags/et.svg b/public/images/flags/et.svg
new file mode 100644
index 00000000..a3378fd9
--- /dev/null
+++ b/public/images/flags/et.svg
@@ -0,0 +1,14 @@
+
diff --git a/public/images/flags/eu.svg b/public/images/flags/eu.svg
new file mode 100644
index 00000000..bbfefd6b
--- /dev/null
+++ b/public/images/flags/eu.svg
@@ -0,0 +1,28 @@
+
diff --git a/public/images/flags/europeanunion.png b/public/images/flags/europeanunion.png
deleted file mode 100755
index d6d87115..00000000
Binary files a/public/images/flags/europeanunion.png and /dev/null differ
diff --git a/public/images/flags/fam.png b/public/images/flags/fam.png
deleted file mode 100755
index cf50c759..00000000
Binary files a/public/images/flags/fam.png and /dev/null differ
diff --git a/public/images/flags/fi.png b/public/images/flags/fi.png
deleted file mode 100755
index 14ec091b..00000000
Binary files a/public/images/flags/fi.png and /dev/null differ
diff --git a/public/images/flags/fi.svg b/public/images/flags/fi.svg
new file mode 100644
index 00000000..470be2d0
--- /dev/null
+++ b/public/images/flags/fi.svg
@@ -0,0 +1,5 @@
+
diff --git a/public/images/flags/fj.png b/public/images/flags/fj.png
deleted file mode 100755
index cee99889..00000000
Binary files a/public/images/flags/fj.png and /dev/null differ
diff --git a/public/images/flags/fj.svg b/public/images/flags/fj.svg
new file mode 100644
index 00000000..2d7cd980
--- /dev/null
+++ b/public/images/flags/fj.svg
@@ -0,0 +1,120 @@
+
diff --git a/public/images/flags/fk.png b/public/images/flags/fk.png
deleted file mode 100755
index ceaeb27d..00000000
Binary files a/public/images/flags/fk.png and /dev/null differ
diff --git a/public/images/flags/fk.svg b/public/images/flags/fk.svg
new file mode 100644
index 00000000..b4935a55
--- /dev/null
+++ b/public/images/flags/fk.svg
@@ -0,0 +1,90 @@
+
diff --git a/public/images/flags/fm.png b/public/images/flags/fm.png
deleted file mode 100755
index 066bb247..00000000
Binary files a/public/images/flags/fm.png and /dev/null differ
diff --git a/public/images/flags/fm.svg b/public/images/flags/fm.svg
new file mode 100644
index 00000000..85f4f47e
--- /dev/null
+++ b/public/images/flags/fm.svg
@@ -0,0 +1,11 @@
+
diff --git a/public/images/flags/fo.png b/public/images/flags/fo.png
deleted file mode 100755
index cbceb809..00000000
Binary files a/public/images/flags/fo.png and /dev/null differ
diff --git a/public/images/flags/fo.svg b/public/images/flags/fo.svg
new file mode 100644
index 00000000..717ee20b
--- /dev/null
+++ b/public/images/flags/fo.svg
@@ -0,0 +1,12 @@
+
diff --git a/public/images/flags/fr.png b/public/images/flags/fr.png
deleted file mode 100755
index 8332c4ec..00000000
Binary files a/public/images/flags/fr.png and /dev/null differ
diff --git a/public/images/flags/fr.svg b/public/images/flags/fr.svg
new file mode 100644
index 00000000..79689fe9
--- /dev/null
+++ b/public/images/flags/fr.svg
@@ -0,0 +1,5 @@
+
diff --git a/public/images/flags/ga.png b/public/images/flags/ga.png
deleted file mode 100755
index 0e0d4343..00000000
Binary files a/public/images/flags/ga.png and /dev/null differ
diff --git a/public/images/flags/ga.svg b/public/images/flags/ga.svg
new file mode 100644
index 00000000..76edab42
--- /dev/null
+++ b/public/images/flags/ga.svg
@@ -0,0 +1,7 @@
+
diff --git a/public/images/flags/gb-eng.svg b/public/images/flags/gb-eng.svg
new file mode 100644
index 00000000..12e3b67d
--- /dev/null
+++ b/public/images/flags/gb-eng.svg
@@ -0,0 +1,5 @@
+
diff --git a/public/images/flags/gb-nir.svg b/public/images/flags/gb-nir.svg
new file mode 100644
index 00000000..c9510f30
--- /dev/null
+++ b/public/images/flags/gb-nir.svg
@@ -0,0 +1,132 @@
+
diff --git a/public/images/flags/gb-sct.svg b/public/images/flags/gb-sct.svg
new file mode 100644
index 00000000..f50cd322
--- /dev/null
+++ b/public/images/flags/gb-sct.svg
@@ -0,0 +1,4 @@
+
diff --git a/public/images/flags/gb-wls.svg b/public/images/flags/gb-wls.svg
new file mode 100644
index 00000000..6e15fd01
--- /dev/null
+++ b/public/images/flags/gb-wls.svg
@@ -0,0 +1,9 @@
+
diff --git a/public/images/flags/gb.png b/public/images/flags/gb.png
deleted file mode 100755
index ff701e19..00000000
Binary files a/public/images/flags/gb.png and /dev/null differ
diff --git a/public/images/flags/gb.svg b/public/images/flags/gb.svg
new file mode 100644
index 00000000..dbac25ea
--- /dev/null
+++ b/public/images/flags/gb.svg
@@ -0,0 +1,7 @@
+
diff --git a/public/images/flags/gd.png b/public/images/flags/gd.png
deleted file mode 100755
index 9ab57f54..00000000
Binary files a/public/images/flags/gd.png and /dev/null differ
diff --git a/public/images/flags/gd.svg b/public/images/flags/gd.svg
new file mode 100644
index 00000000..f44e8391
--- /dev/null
+++ b/public/images/flags/gd.svg
@@ -0,0 +1,27 @@
+
diff --git a/public/images/flags/ge.png b/public/images/flags/ge.png
deleted file mode 100755
index 728d9707..00000000
Binary files a/public/images/flags/ge.png and /dev/null differ
diff --git a/public/images/flags/ge.svg b/public/images/flags/ge.svg
new file mode 100644
index 00000000..d8126ec8
--- /dev/null
+++ b/public/images/flags/ge.svg
@@ -0,0 +1,6 @@
+
diff --git a/public/images/flags/gf.png b/public/images/flags/gf.png
deleted file mode 100755
index 8332c4ec..00000000
Binary files a/public/images/flags/gf.png and /dev/null differ
diff --git a/public/images/flags/gf.svg b/public/images/flags/gf.svg
new file mode 100644
index 00000000..73493426
--- /dev/null
+++ b/public/images/flags/gf.svg
@@ -0,0 +1,5 @@
+
diff --git a/public/images/flags/gg.svg b/public/images/flags/gg.svg
new file mode 100644
index 00000000..f8216c8b
--- /dev/null
+++ b/public/images/flags/gg.svg
@@ -0,0 +1,9 @@
+
diff --git a/public/images/flags/gh.png b/public/images/flags/gh.png
deleted file mode 100755
index 4e2f8965..00000000
Binary files a/public/images/flags/gh.png and /dev/null differ
diff --git a/public/images/flags/gh.svg b/public/images/flags/gh.svg
new file mode 100644
index 00000000..a6497de8
--- /dev/null
+++ b/public/images/flags/gh.svg
@@ -0,0 +1,6 @@
+
diff --git a/public/images/flags/gi.png b/public/images/flags/gi.png
deleted file mode 100755
index e76797f6..00000000
Binary files a/public/images/flags/gi.png and /dev/null differ
diff --git a/public/images/flags/gi.svg b/public/images/flags/gi.svg
new file mode 100644
index 00000000..92496be6
--- /dev/null
+++ b/public/images/flags/gi.svg
@@ -0,0 +1,32 @@
+
diff --git a/public/images/flags/gl.png b/public/images/flags/gl.png
deleted file mode 100755
index ef12a73b..00000000
Binary files a/public/images/flags/gl.png and /dev/null differ
diff --git a/public/images/flags/gl.svg b/public/images/flags/gl.svg
new file mode 100644
index 00000000..eb5a52e9
--- /dev/null
+++ b/public/images/flags/gl.svg
@@ -0,0 +1,4 @@
+
diff --git a/public/images/flags/gm.png b/public/images/flags/gm.png
deleted file mode 100755
index 0720b667..00000000
Binary files a/public/images/flags/gm.png and /dev/null differ
diff --git a/public/images/flags/gm.svg b/public/images/flags/gm.svg
new file mode 100644
index 00000000..8fe9d669
--- /dev/null
+++ b/public/images/flags/gm.svg
@@ -0,0 +1,14 @@
+
diff --git a/public/images/flags/gn.png b/public/images/flags/gn.png
deleted file mode 100755
index ea660b01..00000000
Binary files a/public/images/flags/gn.png and /dev/null differ
diff --git a/public/images/flags/gn.svg b/public/images/flags/gn.svg
new file mode 100644
index 00000000..40d6ad4f
--- /dev/null
+++ b/public/images/flags/gn.svg
@@ -0,0 +1,7 @@
+
diff --git a/public/images/flags/gp.png b/public/images/flags/gp.png
deleted file mode 100755
index dbb086d0..00000000
Binary files a/public/images/flags/gp.png and /dev/null differ
diff --git a/public/images/flags/gp.svg b/public/images/flags/gp.svg
new file mode 100644
index 00000000..528e554f
--- /dev/null
+++ b/public/images/flags/gp.svg
@@ -0,0 +1,5 @@
+
diff --git a/public/images/flags/gq.png b/public/images/flags/gq.png
deleted file mode 100755
index ebe20a28..00000000
Binary files a/public/images/flags/gq.png and /dev/null differ
diff --git a/public/images/flags/gq.svg b/public/images/flags/gq.svg
new file mode 100644
index 00000000..ba2acf28
--- /dev/null
+++ b/public/images/flags/gq.svg
@@ -0,0 +1,23 @@
+
diff --git a/public/images/flags/gr.png b/public/images/flags/gr.png
deleted file mode 100755
index 8651ade7..00000000
Binary files a/public/images/flags/gr.png and /dev/null differ
diff --git a/public/images/flags/gr.svg b/public/images/flags/gr.svg
new file mode 100644
index 00000000..599741ee
--- /dev/null
+++ b/public/images/flags/gr.svg
@@ -0,0 +1,16 @@
+
diff --git a/public/images/flags/gs.png b/public/images/flags/gs.png
deleted file mode 100755
index 7ef0bf59..00000000
Binary files a/public/images/flags/gs.png and /dev/null differ
diff --git a/public/images/flags/gs.svg b/public/images/flags/gs.svg
new file mode 100644
index 00000000..2e045dfd
--- /dev/null
+++ b/public/images/flags/gs.svg
@@ -0,0 +1,133 @@
+
diff --git a/public/images/flags/gt.png b/public/images/flags/gt.png
deleted file mode 100755
index c43a70d3..00000000
Binary files a/public/images/flags/gt.png and /dev/null differ
diff --git a/public/images/flags/gt.svg b/public/images/flags/gt.svg
new file mode 100644
index 00000000..9b347124
--- /dev/null
+++ b/public/images/flags/gt.svg
@@ -0,0 +1,204 @@
+
diff --git a/public/images/flags/gu.png b/public/images/flags/gu.png
deleted file mode 100755
index 92f37c05..00000000
Binary files a/public/images/flags/gu.png and /dev/null differ
diff --git a/public/images/flags/gu.svg b/public/images/flags/gu.svg
new file mode 100644
index 00000000..a5584ffd
--- /dev/null
+++ b/public/images/flags/gu.svg
@@ -0,0 +1,23 @@
+
diff --git a/public/images/flags/gw.png b/public/images/flags/gw.png
deleted file mode 100755
index b37bcf06..00000000
Binary files a/public/images/flags/gw.png and /dev/null differ
diff --git a/public/images/flags/gw.svg b/public/images/flags/gw.svg
new file mode 100644
index 00000000..b8d566a2
--- /dev/null
+++ b/public/images/flags/gw.svg
@@ -0,0 +1,13 @@
+
diff --git a/public/images/flags/gy.png b/public/images/flags/gy.png
deleted file mode 100755
index 22cbe2f5..00000000
Binary files a/public/images/flags/gy.png and /dev/null differ
diff --git a/public/images/flags/gy.svg b/public/images/flags/gy.svg
new file mode 100644
index 00000000..f4d9b8ab
--- /dev/null
+++ b/public/images/flags/gy.svg
@@ -0,0 +1,9 @@
+
diff --git a/public/images/flags/hk.png b/public/images/flags/hk.png
deleted file mode 100755
index d5c380ca..00000000
Binary files a/public/images/flags/hk.png and /dev/null differ
diff --git a/public/images/flags/hk.svg b/public/images/flags/hk.svg
new file mode 100644
index 00000000..ec40b5fe
--- /dev/null
+++ b/public/images/flags/hk.svg
@@ -0,0 +1,8 @@
+
diff --git a/public/images/flags/hm.png b/public/images/flags/hm.png
deleted file mode 100755
index a01389a7..00000000
Binary files a/public/images/flags/hm.png and /dev/null differ
diff --git a/public/images/flags/hm.svg b/public/images/flags/hm.svg
new file mode 100644
index 00000000..c0748d3b
--- /dev/null
+++ b/public/images/flags/hm.svg
@@ -0,0 +1,8 @@
+
diff --git a/public/images/flags/hn.png b/public/images/flags/hn.png
deleted file mode 100755
index 96f83885..00000000
Binary files a/public/images/flags/hn.png and /dev/null differ
diff --git a/public/images/flags/hn.svg b/public/images/flags/hn.svg
new file mode 100644
index 00000000..1c166dc4
--- /dev/null
+++ b/public/images/flags/hn.svg
@@ -0,0 +1,18 @@
+
diff --git a/public/images/flags/hr.png b/public/images/flags/hr.png
deleted file mode 100755
index 696b5154..00000000
Binary files a/public/images/flags/hr.png and /dev/null differ
diff --git a/public/images/flags/hr.svg b/public/images/flags/hr.svg
new file mode 100644
index 00000000..febbc240
--- /dev/null
+++ b/public/images/flags/hr.svg
@@ -0,0 +1,58 @@
+
diff --git a/public/images/flags/ht.png b/public/images/flags/ht.png
deleted file mode 100755
index 416052af..00000000
Binary files a/public/images/flags/ht.png and /dev/null differ
diff --git a/public/images/flags/ht.svg b/public/images/flags/ht.svg
new file mode 100644
index 00000000..4cd4470f
--- /dev/null
+++ b/public/images/flags/ht.svg
@@ -0,0 +1,116 @@
+
diff --git a/public/images/flags/hu.png b/public/images/flags/hu.png
deleted file mode 100755
index 7baafe44..00000000
Binary files a/public/images/flags/hu.png and /dev/null differ
diff --git a/public/images/flags/hu.svg b/public/images/flags/hu.svg
new file mode 100644
index 00000000..baddf7f5
--- /dev/null
+++ b/public/images/flags/hu.svg
@@ -0,0 +1,7 @@
+
diff --git a/public/images/flags/ic.svg b/public/images/flags/ic.svg
new file mode 100644
index 00000000..81e6ee2e
--- /dev/null
+++ b/public/images/flags/ic.svg
@@ -0,0 +1,7 @@
+
diff --git a/public/images/flags/id.png b/public/images/flags/id.png
deleted file mode 100755
index c6bc0faf..00000000
Binary files a/public/images/flags/id.png and /dev/null differ
diff --git a/public/images/flags/id.svg b/public/images/flags/id.svg
new file mode 100644
index 00000000..3b7c8fcf
--- /dev/null
+++ b/public/images/flags/id.svg
@@ -0,0 +1,4 @@
+
diff --git a/public/images/flags/ie.png b/public/images/flags/ie.png
deleted file mode 100755
index 26baa31e..00000000
Binary files a/public/images/flags/ie.png and /dev/null differ
diff --git a/public/images/flags/ie.svg b/public/images/flags/ie.svg
new file mode 100644
index 00000000..049be14d
--- /dev/null
+++ b/public/images/flags/ie.svg
@@ -0,0 +1,7 @@
+
diff --git a/public/images/flags/il.png b/public/images/flags/il.png
deleted file mode 100755
index 2ca772d0..00000000
Binary files a/public/images/flags/il.png and /dev/null differ
diff --git a/public/images/flags/il.svg b/public/images/flags/il.svg
new file mode 100644
index 00000000..724cf8bf
--- /dev/null
+++ b/public/images/flags/il.svg
@@ -0,0 +1,14 @@
+
diff --git a/public/images/flags/im.svg b/public/images/flags/im.svg
new file mode 100644
index 00000000..3d597a14
--- /dev/null
+++ b/public/images/flags/im.svg
@@ -0,0 +1,36 @@
+
diff --git a/public/images/flags/in.png b/public/images/flags/in.png
deleted file mode 100755
index e4d7e81a..00000000
Binary files a/public/images/flags/in.png and /dev/null differ
diff --git a/public/images/flags/in.svg b/public/images/flags/in.svg
new file mode 100644
index 00000000..c634f68a
--- /dev/null
+++ b/public/images/flags/in.svg
@@ -0,0 +1,25 @@
+
diff --git a/public/images/flags/io.png b/public/images/flags/io.png
deleted file mode 100755
index 3e74b6a3..00000000
Binary files a/public/images/flags/io.png and /dev/null differ
diff --git a/public/images/flags/io.svg b/public/images/flags/io.svg
new file mode 100644
index 00000000..b04c46f5
--- /dev/null
+++ b/public/images/flags/io.svg
@@ -0,0 +1,130 @@
+
diff --git a/public/images/flags/iq.png b/public/images/flags/iq.png
deleted file mode 100755
index 878a3514..00000000
Binary files a/public/images/flags/iq.png and /dev/null differ
diff --git a/public/images/flags/iq.svg b/public/images/flags/iq.svg
new file mode 100644
index 00000000..68917853
--- /dev/null
+++ b/public/images/flags/iq.svg
@@ -0,0 +1,10 @@
+
diff --git a/public/images/flags/ir.png b/public/images/flags/ir.png
deleted file mode 100755
index c5fd136a..00000000
Binary files a/public/images/flags/ir.png and /dev/null differ
diff --git a/public/images/flags/ir.svg b/public/images/flags/ir.svg
new file mode 100644
index 00000000..5c9609ef
--- /dev/null
+++ b/public/images/flags/ir.svg
@@ -0,0 +1,219 @@
+
diff --git a/public/images/flags/is.png b/public/images/flags/is.png
deleted file mode 100755
index b8f6d0f0..00000000
Binary files a/public/images/flags/is.png and /dev/null differ
diff --git a/public/images/flags/is.svg b/public/images/flags/is.svg
new file mode 100644
index 00000000..56cc9778
--- /dev/null
+++ b/public/images/flags/is.svg
@@ -0,0 +1,12 @@
+
diff --git a/public/images/flags/it.png b/public/images/flags/it.png
deleted file mode 100755
index 89692f74..00000000
Binary files a/public/images/flags/it.png and /dev/null differ
diff --git a/public/images/flags/it.svg b/public/images/flags/it.svg
new file mode 100644
index 00000000..20a8bfdc
--- /dev/null
+++ b/public/images/flags/it.svg
@@ -0,0 +1,7 @@
+
diff --git a/public/images/flags/je.svg b/public/images/flags/je.svg
new file mode 100644
index 00000000..e69e4f46
--- /dev/null
+++ b/public/images/flags/je.svg
@@ -0,0 +1,45 @@
+
diff --git a/public/images/flags/jm.png b/public/images/flags/jm.png
deleted file mode 100755
index 7be119e0..00000000
Binary files a/public/images/flags/jm.png and /dev/null differ
diff --git a/public/images/flags/jm.svg b/public/images/flags/jm.svg
new file mode 100644
index 00000000..e03a3422
--- /dev/null
+++ b/public/images/flags/jm.svg
@@ -0,0 +1,8 @@
+
diff --git a/public/images/flags/jo.png b/public/images/flags/jo.png
deleted file mode 100755
index 11bd4972..00000000
Binary files a/public/images/flags/jo.png and /dev/null differ
diff --git a/public/images/flags/jo.svg b/public/images/flags/jo.svg
new file mode 100644
index 00000000..50802915
--- /dev/null
+++ b/public/images/flags/jo.svg
@@ -0,0 +1,16 @@
+
diff --git a/public/images/flags/jp.png b/public/images/flags/jp.png
deleted file mode 100755
index 325fbad3..00000000
Binary files a/public/images/flags/jp.png and /dev/null differ
diff --git a/public/images/flags/jp.svg b/public/images/flags/jp.svg
new file mode 100644
index 00000000..cd03a339
--- /dev/null
+++ b/public/images/flags/jp.svg
@@ -0,0 +1,11 @@
+
diff --git a/public/images/flags/ke.png b/public/images/flags/ke.png
deleted file mode 100755
index 51879adf..00000000
Binary files a/public/images/flags/ke.png and /dev/null differ
diff --git a/public/images/flags/ke.svg b/public/images/flags/ke.svg
new file mode 100644
index 00000000..5b377937
--- /dev/null
+++ b/public/images/flags/ke.svg
@@ -0,0 +1,23 @@
+
diff --git a/public/images/flags/kg.png b/public/images/flags/kg.png
deleted file mode 100755
index 0a818f67..00000000
Binary files a/public/images/flags/kg.png and /dev/null differ
diff --git a/public/images/flags/kg.svg b/public/images/flags/kg.svg
new file mode 100644
index 00000000..626af14d
--- /dev/null
+++ b/public/images/flags/kg.svg
@@ -0,0 +1,15 @@
+
diff --git a/public/images/flags/kh.png b/public/images/flags/kh.png
deleted file mode 100755
index 30f6bb1b..00000000
Binary files a/public/images/flags/kh.png and /dev/null differ
diff --git a/public/images/flags/kh.svg b/public/images/flags/kh.svg
new file mode 100644
index 00000000..c658838f
--- /dev/null
+++ b/public/images/flags/kh.svg
@@ -0,0 +1,61 @@
+
diff --git a/public/images/flags/ki.png b/public/images/flags/ki.png
deleted file mode 100755
index 2dcce4b3..00000000
Binary files a/public/images/flags/ki.png and /dev/null differ
diff --git a/public/images/flags/ki.svg b/public/images/flags/ki.svg
new file mode 100644
index 00000000..1697ffe8
--- /dev/null
+++ b/public/images/flags/ki.svg
@@ -0,0 +1,36 @@
+
diff --git a/public/images/flags/km.png b/public/images/flags/km.png
deleted file mode 100755
index 812b2f56..00000000
Binary files a/public/images/flags/km.png and /dev/null differ
diff --git a/public/images/flags/km.svg b/public/images/flags/km.svg
new file mode 100644
index 00000000..56d62c32
--- /dev/null
+++ b/public/images/flags/km.svg
@@ -0,0 +1,16 @@
+
diff --git a/public/images/flags/kn.png b/public/images/flags/kn.png
deleted file mode 100755
index febd5b48..00000000
Binary files a/public/images/flags/kn.png and /dev/null differ
diff --git a/public/images/flags/kn.svg b/public/images/flags/kn.svg
new file mode 100644
index 00000000..01a3a0a2
--- /dev/null
+++ b/public/images/flags/kn.svg
@@ -0,0 +1,14 @@
+
diff --git a/public/images/flags/kp.png b/public/images/flags/kp.png
deleted file mode 100755
index d3d509aa..00000000
Binary files a/public/images/flags/kp.png and /dev/null differ
diff --git a/public/images/flags/kp.svg b/public/images/flags/kp.svg
new file mode 100644
index 00000000..94bc8e1e
--- /dev/null
+++ b/public/images/flags/kp.svg
@@ -0,0 +1,15 @@
+
diff --git a/public/images/flags/kr.png b/public/images/flags/kr.png
deleted file mode 100755
index 9c0a78eb..00000000
Binary files a/public/images/flags/kr.png and /dev/null differ
diff --git a/public/images/flags/kr.svg b/public/images/flags/kr.svg
new file mode 100644
index 00000000..44b51e25
--- /dev/null
+++ b/public/images/flags/kr.svg
@@ -0,0 +1,24 @@
+
diff --git a/public/images/flags/kw.png b/public/images/flags/kw.png
deleted file mode 100755
index 96546da3..00000000
Binary files a/public/images/flags/kw.png and /dev/null differ
diff --git a/public/images/flags/kw.svg b/public/images/flags/kw.svg
new file mode 100644
index 00000000..7ff91a84
--- /dev/null
+++ b/public/images/flags/kw.svg
@@ -0,0 +1,13 @@
+
diff --git a/public/images/flags/ky.png b/public/images/flags/ky.png
deleted file mode 100755
index 15c5f8e4..00000000
Binary files a/public/images/flags/ky.png and /dev/null differ
diff --git a/public/images/flags/ky.svg b/public/images/flags/ky.svg
new file mode 100644
index 00000000..d6e567b5
--- /dev/null
+++ b/public/images/flags/ky.svg
@@ -0,0 +1,103 @@
+
diff --git a/public/images/flags/kz.png b/public/images/flags/kz.png
deleted file mode 100755
index 45a8c887..00000000
Binary files a/public/images/flags/kz.png and /dev/null differ
diff --git a/public/images/flags/kz.svg b/public/images/flags/kz.svg
new file mode 100644
index 00000000..a69ba7a3
--- /dev/null
+++ b/public/images/flags/kz.svg
@@ -0,0 +1,36 @@
+
diff --git a/public/images/flags/la.png b/public/images/flags/la.png
deleted file mode 100755
index e28acd01..00000000
Binary files a/public/images/flags/la.png and /dev/null differ
diff --git a/public/images/flags/la.svg b/public/images/flags/la.svg
new file mode 100644
index 00000000..9723a781
--- /dev/null
+++ b/public/images/flags/la.svg
@@ -0,0 +1,12 @@
+
diff --git a/public/images/flags/lb.png b/public/images/flags/lb.png
deleted file mode 100755
index d0d452bf..00000000
Binary files a/public/images/flags/lb.png and /dev/null differ
diff --git a/public/images/flags/lb.svg b/public/images/flags/lb.svg
new file mode 100644
index 00000000..49650ad8
--- /dev/null
+++ b/public/images/flags/lb.svg
@@ -0,0 +1,15 @@
+
diff --git a/public/images/flags/lc.png b/public/images/flags/lc.png
deleted file mode 100755
index a47d0655..00000000
Binary files a/public/images/flags/lc.png and /dev/null differ
diff --git a/public/images/flags/lc.svg b/public/images/flags/lc.svg
new file mode 100644
index 00000000..46bbc6cc
--- /dev/null
+++ b/public/images/flags/lc.svg
@@ -0,0 +1,8 @@
+
diff --git a/public/images/flags/li.png b/public/images/flags/li.png
deleted file mode 100755
index 6469909c..00000000
Binary files a/public/images/flags/li.png and /dev/null differ
diff --git a/public/images/flags/li.svg b/public/images/flags/li.svg
new file mode 100644
index 00000000..a08a05ac
--- /dev/null
+++ b/public/images/flags/li.svg
@@ -0,0 +1,43 @@
+
diff --git a/public/images/flags/lk.png b/public/images/flags/lk.png
deleted file mode 100755
index 088aad6d..00000000
Binary files a/public/images/flags/lk.png and /dev/null differ
diff --git a/public/images/flags/lk.svg b/public/images/flags/lk.svg
new file mode 100644
index 00000000..24c6559b
--- /dev/null
+++ b/public/images/flags/lk.svg
@@ -0,0 +1,22 @@
+
diff --git a/public/images/flags/lr.png b/public/images/flags/lr.png
deleted file mode 100755
index 89a5bc7e..00000000
Binary files a/public/images/flags/lr.png and /dev/null differ
diff --git a/public/images/flags/lr.svg b/public/images/flags/lr.svg
new file mode 100644
index 00000000..a31377f9
--- /dev/null
+++ b/public/images/flags/lr.svg
@@ -0,0 +1,14 @@
+
diff --git a/public/images/flags/ls.png b/public/images/flags/ls.png
deleted file mode 100755
index 33fdef10..00000000
Binary files a/public/images/flags/ls.png and /dev/null differ
diff --git a/public/images/flags/ls.svg b/public/images/flags/ls.svg
new file mode 100644
index 00000000..e7016502
--- /dev/null
+++ b/public/images/flags/ls.svg
@@ -0,0 +1,8 @@
+
diff --git a/public/images/flags/lt.png b/public/images/flags/lt.png
deleted file mode 100755
index c8ef0da0..00000000
Binary files a/public/images/flags/lt.png and /dev/null differ
diff --git a/public/images/flags/lt.svg b/public/images/flags/lt.svg
new file mode 100644
index 00000000..90ec5d24
--- /dev/null
+++ b/public/images/flags/lt.svg
@@ -0,0 +1,7 @@
+
diff --git a/public/images/flags/lu.png b/public/images/flags/lu.png
deleted file mode 100755
index 4cabba98..00000000
Binary files a/public/images/flags/lu.png and /dev/null differ
diff --git a/public/images/flags/lu.svg b/public/images/flags/lu.svg
new file mode 100644
index 00000000..c31d2bfa
--- /dev/null
+++ b/public/images/flags/lu.svg
@@ -0,0 +1,5 @@
+
diff --git a/public/images/flags/lv.png b/public/images/flags/lv.png
deleted file mode 100755
index 49b69981..00000000
Binary files a/public/images/flags/lv.png and /dev/null differ
diff --git a/public/images/flags/lv.svg b/public/images/flags/lv.svg
new file mode 100644
index 00000000..6a9e75ec
--- /dev/null
+++ b/public/images/flags/lv.svg
@@ -0,0 +1,6 @@
+
diff --git a/public/images/flags/ly.png b/public/images/flags/ly.png
deleted file mode 100755
index b163a9f8..00000000
Binary files a/public/images/flags/ly.png and /dev/null differ
diff --git a/public/images/flags/ly.svg b/public/images/flags/ly.svg
new file mode 100644
index 00000000..14abcb24
--- /dev/null
+++ b/public/images/flags/ly.svg
@@ -0,0 +1,13 @@
+
diff --git a/public/images/flags/ma.png b/public/images/flags/ma.png
deleted file mode 100755
index f3867702..00000000
Binary files a/public/images/flags/ma.png and /dev/null differ
diff --git a/public/images/flags/ma.svg b/public/images/flags/ma.svg
new file mode 100644
index 00000000..7ce56eff
--- /dev/null
+++ b/public/images/flags/ma.svg
@@ -0,0 +1,4 @@
+
diff --git a/public/images/flags/mc.png b/public/images/flags/mc.png
deleted file mode 100755
index 1aa830f1..00000000
Binary files a/public/images/flags/mc.png and /dev/null differ
diff --git a/public/images/flags/mc.svg b/public/images/flags/mc.svg
new file mode 100644
index 00000000..9cb6c9e8
--- /dev/null
+++ b/public/images/flags/mc.svg
@@ -0,0 +1,6 @@
+
diff --git a/public/images/flags/md.png b/public/images/flags/md.png
deleted file mode 100755
index 4e92c189..00000000
Binary files a/public/images/flags/md.png and /dev/null differ
diff --git a/public/images/flags/md.svg b/public/images/flags/md.svg
new file mode 100644
index 00000000..a806572c
--- /dev/null
+++ b/public/images/flags/md.svg
@@ -0,0 +1,70 @@
+
diff --git a/public/images/flags/me.png b/public/images/flags/me.png
deleted file mode 100755
index ac725355..00000000
Binary files a/public/images/flags/me.png and /dev/null differ
diff --git a/public/images/flags/me.svg b/public/images/flags/me.svg
new file mode 100644
index 00000000..b56cce09
--- /dev/null
+++ b/public/images/flags/me.svg
@@ -0,0 +1,116 @@
+
diff --git a/public/images/flags/mf.svg b/public/images/flags/mf.svg
new file mode 100644
index 00000000..a53ce501
--- /dev/null
+++ b/public/images/flags/mf.svg
@@ -0,0 +1,5 @@
+
diff --git a/public/images/flags/mg.png b/public/images/flags/mg.png
deleted file mode 100755
index d2715b3d..00000000
Binary files a/public/images/flags/mg.png and /dev/null differ
diff --git a/public/images/flags/mg.svg b/public/images/flags/mg.svg
new file mode 100644
index 00000000..5fa2d244
--- /dev/null
+++ b/public/images/flags/mg.svg
@@ -0,0 +1,7 @@
+
diff --git a/public/images/flags/mh.png b/public/images/flags/mh.png
deleted file mode 100755
index fb523a8c..00000000
Binary files a/public/images/flags/mh.png and /dev/null differ
diff --git a/public/images/flags/mh.svg b/public/images/flags/mh.svg
new file mode 100644
index 00000000..46351e54
--- /dev/null
+++ b/public/images/flags/mh.svg
@@ -0,0 +1,7 @@
+
diff --git a/public/images/flags/mk.png b/public/images/flags/mk.png
deleted file mode 100755
index db173aaf..00000000
Binary files a/public/images/flags/mk.png and /dev/null differ
diff --git a/public/images/flags/mk.svg b/public/images/flags/mk.svg
new file mode 100644
index 00000000..4f5cae77
--- /dev/null
+++ b/public/images/flags/mk.svg
@@ -0,0 +1,5 @@
+
diff --git a/public/images/flags/ml.png b/public/images/flags/ml.png
deleted file mode 100755
index 2cec8ba4..00000000
Binary files a/public/images/flags/ml.png and /dev/null differ
diff --git a/public/images/flags/ml.svg b/public/images/flags/ml.svg
new file mode 100644
index 00000000..6f6b7169
--- /dev/null
+++ b/public/images/flags/ml.svg
@@ -0,0 +1,7 @@
+
diff --git a/public/images/flags/mm.png b/public/images/flags/mm.png
deleted file mode 100755
index f464f67f..00000000
Binary files a/public/images/flags/mm.png and /dev/null differ
diff --git a/public/images/flags/mm.svg b/public/images/flags/mm.svg
new file mode 100644
index 00000000..8ed5e6ac
--- /dev/null
+++ b/public/images/flags/mm.svg
@@ -0,0 +1,12 @@
+
diff --git a/public/images/flags/mn.png b/public/images/flags/mn.png
deleted file mode 100755
index 9396355d..00000000
Binary files a/public/images/flags/mn.png and /dev/null differ
diff --git a/public/images/flags/mn.svg b/public/images/flags/mn.svg
new file mode 100644
index 00000000..56cb0729
--- /dev/null
+++ b/public/images/flags/mn.svg
@@ -0,0 +1,14 @@
+
diff --git a/public/images/flags/mo.png b/public/images/flags/mo.png
deleted file mode 100755
index deb801dd..00000000
Binary files a/public/images/flags/mo.png and /dev/null differ
diff --git a/public/images/flags/mo.svg b/public/images/flags/mo.svg
new file mode 100644
index 00000000..257faed6
--- /dev/null
+++ b/public/images/flags/mo.svg
@@ -0,0 +1,9 @@
+
diff --git a/public/images/flags/mp.png b/public/images/flags/mp.png
deleted file mode 100755
index 298d588b..00000000
Binary files a/public/images/flags/mp.png and /dev/null differ
diff --git a/public/images/flags/mp.svg b/public/images/flags/mp.svg
new file mode 100644
index 00000000..6696fdb8
--- /dev/null
+++ b/public/images/flags/mp.svg
@@ -0,0 +1,86 @@
+
diff --git a/public/images/flags/mq.png b/public/images/flags/mq.png
deleted file mode 100755
index 010143b3..00000000
Binary files a/public/images/flags/mq.png and /dev/null differ
diff --git a/public/images/flags/mq.svg b/public/images/flags/mq.svg
new file mode 100644
index 00000000..b221951e
--- /dev/null
+++ b/public/images/flags/mq.svg
@@ -0,0 +1,5 @@
+
diff --git a/public/images/flags/mr.png b/public/images/flags/mr.png
deleted file mode 100755
index 319546b1..00000000
Binary files a/public/images/flags/mr.png and /dev/null differ
diff --git a/public/images/flags/mr.svg b/public/images/flags/mr.svg
new file mode 100644
index 00000000..3f0a6264
--- /dev/null
+++ b/public/images/flags/mr.svg
@@ -0,0 +1,6 @@
+
diff --git a/public/images/flags/ms.png b/public/images/flags/ms.png
deleted file mode 100755
index d4cbb433..00000000
Binary files a/public/images/flags/ms.png and /dev/null differ
diff --git a/public/images/flags/ms.svg b/public/images/flags/ms.svg
new file mode 100644
index 00000000..58641240
--- /dev/null
+++ b/public/images/flags/ms.svg
@@ -0,0 +1,29 @@
+
diff --git a/public/images/flags/mt.png b/public/images/flags/mt.png
deleted file mode 100755
index 00af9487..00000000
Binary files a/public/images/flags/mt.png and /dev/null differ
diff --git a/public/images/flags/mt.svg b/public/images/flags/mt.svg
new file mode 100644
index 00000000..676e801c
--- /dev/null
+++ b/public/images/flags/mt.svg
@@ -0,0 +1,49 @@
+
diff --git a/public/images/flags/mu.png b/public/images/flags/mu.png
deleted file mode 100755
index b7fdce1b..00000000
Binary files a/public/images/flags/mu.png and /dev/null differ
diff --git a/public/images/flags/mu.svg b/public/images/flags/mu.svg
new file mode 100644
index 00000000..82d7a3be
--- /dev/null
+++ b/public/images/flags/mu.svg
@@ -0,0 +1,8 @@
+
diff --git a/public/images/flags/mv.png b/public/images/flags/mv.png
deleted file mode 100755
index 5073d9ec..00000000
Binary files a/public/images/flags/mv.png and /dev/null differ
diff --git a/public/images/flags/mv.svg b/public/images/flags/mv.svg
new file mode 100644
index 00000000..10450f98
--- /dev/null
+++ b/public/images/flags/mv.svg
@@ -0,0 +1,6 @@
+
diff --git a/public/images/flags/mw.png b/public/images/flags/mw.png
deleted file mode 100755
index 13886e9f..00000000
Binary files a/public/images/flags/mw.png and /dev/null differ
diff --git a/public/images/flags/mw.svg b/public/images/flags/mw.svg
new file mode 100644
index 00000000..113aae54
--- /dev/null
+++ b/public/images/flags/mw.svg
@@ -0,0 +1,10 @@
+
diff --git a/public/images/flags/mx.png b/public/images/flags/mx.png
deleted file mode 100755
index 5bc58ab3..00000000
Binary files a/public/images/flags/mx.png and /dev/null differ
diff --git a/public/images/flags/mx.svg b/public/images/flags/mx.svg
new file mode 100644
index 00000000..bb305b8d
--- /dev/null
+++ b/public/images/flags/mx.svg
@@ -0,0 +1,382 @@
+
diff --git a/public/images/flags/my.png b/public/images/flags/my.png
deleted file mode 100755
index 9034cbab..00000000
Binary files a/public/images/flags/my.png and /dev/null differ
diff --git a/public/images/flags/my.svg b/public/images/flags/my.svg
new file mode 100644
index 00000000..264f48ae
--- /dev/null
+++ b/public/images/flags/my.svg
@@ -0,0 +1,26 @@
+
diff --git a/public/images/flags/mz.png b/public/images/flags/mz.png
deleted file mode 100755
index 76405e06..00000000
Binary files a/public/images/flags/mz.png and /dev/null differ
diff --git a/public/images/flags/mz.svg b/public/images/flags/mz.svg
new file mode 100644
index 00000000..eb020058
--- /dev/null
+++ b/public/images/flags/mz.svg
@@ -0,0 +1,21 @@
+
diff --git a/public/images/flags/na.png b/public/images/flags/na.png
deleted file mode 100755
index 63358c67..00000000
Binary files a/public/images/flags/na.png and /dev/null differ
diff --git a/public/images/flags/na.svg b/public/images/flags/na.svg
new file mode 100644
index 00000000..799702e8
--- /dev/null
+++ b/public/images/flags/na.svg
@@ -0,0 +1,16 @@
+
diff --git a/public/images/flags/nc.png b/public/images/flags/nc.png
deleted file mode 100755
index 2cad2837..00000000
Binary files a/public/images/flags/nc.png and /dev/null differ
diff --git a/public/images/flags/nc.svg b/public/images/flags/nc.svg
new file mode 100644
index 00000000..96795408
--- /dev/null
+++ b/public/images/flags/nc.svg
@@ -0,0 +1,13 @@
+
diff --git a/public/images/flags/ne.png b/public/images/flags/ne.png
deleted file mode 100755
index d85f424f..00000000
Binary files a/public/images/flags/ne.png and /dev/null differ
diff --git a/public/images/flags/ne.svg b/public/images/flags/ne.svg
new file mode 100644
index 00000000..39a82b82
--- /dev/null
+++ b/public/images/flags/ne.svg
@@ -0,0 +1,6 @@
+
diff --git a/public/images/flags/nf.png b/public/images/flags/nf.png
deleted file mode 100755
index f9bcdda1..00000000
Binary files a/public/images/flags/nf.png and /dev/null differ
diff --git a/public/images/flags/nf.svg b/public/images/flags/nf.svg
new file mode 100644
index 00000000..ecdb4a3b
--- /dev/null
+++ b/public/images/flags/nf.svg
@@ -0,0 +1,9 @@
+
diff --git a/public/images/flags/ng.png b/public/images/flags/ng.png
deleted file mode 100755
index 3eea2e02..00000000
Binary files a/public/images/flags/ng.png and /dev/null differ
diff --git a/public/images/flags/ng.svg b/public/images/flags/ng.svg
new file mode 100644
index 00000000..81eb35f7
--- /dev/null
+++ b/public/images/flags/ng.svg
@@ -0,0 +1,6 @@
+
diff --git a/public/images/flags/ni.png b/public/images/flags/ni.png
deleted file mode 100755
index 3969aaaa..00000000
Binary files a/public/images/flags/ni.png and /dev/null differ
diff --git a/public/images/flags/ni.svg b/public/images/flags/ni.svg
new file mode 100644
index 00000000..e16e77ae
--- /dev/null
+++ b/public/images/flags/ni.svg
@@ -0,0 +1,129 @@
+
diff --git a/public/images/flags/nl.png b/public/images/flags/nl.png
deleted file mode 100755
index fe44791e..00000000
Binary files a/public/images/flags/nl.png and /dev/null differ
diff --git a/public/images/flags/nl.svg b/public/images/flags/nl.svg
new file mode 100644
index 00000000..4faaf498
--- /dev/null
+++ b/public/images/flags/nl.svg
@@ -0,0 +1,5 @@
+
diff --git a/public/images/flags/no.png b/public/images/flags/no.png
deleted file mode 100755
index 160b6b5b..00000000
Binary files a/public/images/flags/no.png and /dev/null differ
diff --git a/public/images/flags/no.svg b/public/images/flags/no.svg
new file mode 100644
index 00000000..a5f2a152
--- /dev/null
+++ b/public/images/flags/no.svg
@@ -0,0 +1,7 @@
+
diff --git a/public/images/flags/np.png b/public/images/flags/np.png
deleted file mode 100755
index aeb058b7..00000000
Binary files a/public/images/flags/np.png and /dev/null differ
diff --git a/public/images/flags/np.svg b/public/images/flags/np.svg
new file mode 100644
index 00000000..fead9402
--- /dev/null
+++ b/public/images/flags/np.svg
@@ -0,0 +1,13 @@
+
diff --git a/public/images/flags/nr.png b/public/images/flags/nr.png
deleted file mode 100755
index 705fc337..00000000
Binary files a/public/images/flags/nr.png and /dev/null differ
diff --git a/public/images/flags/nr.svg b/public/images/flags/nr.svg
new file mode 100644
index 00000000..e71ddcd8
--- /dev/null
+++ b/public/images/flags/nr.svg
@@ -0,0 +1,12 @@
+
diff --git a/public/images/flags/nu.png b/public/images/flags/nu.png
deleted file mode 100755
index c3ce4aed..00000000
Binary files a/public/images/flags/nu.png and /dev/null differ
diff --git a/public/images/flags/nu.svg b/public/images/flags/nu.svg
new file mode 100644
index 00000000..4067baff
--- /dev/null
+++ b/public/images/flags/nu.svg
@@ -0,0 +1,10 @@
+
diff --git a/public/images/flags/nz.png b/public/images/flags/nz.png
deleted file mode 100755
index 10d6306d..00000000
Binary files a/public/images/flags/nz.png and /dev/null differ
diff --git a/public/images/flags/nz.svg b/public/images/flags/nz.svg
new file mode 100644
index 00000000..a0028fb2
--- /dev/null
+++ b/public/images/flags/nz.svg
@@ -0,0 +1,36 @@
+
diff --git a/public/images/flags/om.png b/public/images/flags/om.png
deleted file mode 100755
index 2ffba7e8..00000000
Binary files a/public/images/flags/om.png and /dev/null differ
diff --git a/public/images/flags/om.svg b/public/images/flags/om.svg
new file mode 100644
index 00000000..1c762179
--- /dev/null
+++ b/public/images/flags/om.svg
@@ -0,0 +1,115 @@
+
diff --git a/public/images/flags/pa.png b/public/images/flags/pa.png
deleted file mode 100755
index 9b2ee9a7..00000000
Binary files a/public/images/flags/pa.png and /dev/null differ
diff --git a/public/images/flags/pa.svg b/public/images/flags/pa.svg
new file mode 100644
index 00000000..8dc03bc6
--- /dev/null
+++ b/public/images/flags/pa.svg
@@ -0,0 +1,14 @@
+
diff --git a/public/images/flags/pe.png b/public/images/flags/pe.png
deleted file mode 100755
index 62a04977..00000000
Binary files a/public/images/flags/pe.png and /dev/null differ
diff --git a/public/images/flags/pe.svg b/public/images/flags/pe.svg
new file mode 100644
index 00000000..33e6cfd4
--- /dev/null
+++ b/public/images/flags/pe.svg
@@ -0,0 +1,4 @@
+
diff --git a/public/images/flags/pf.png b/public/images/flags/pf.png
deleted file mode 100755
index 771a0f65..00000000
Binary files a/public/images/flags/pf.png and /dev/null differ
diff --git a/public/images/flags/pf.svg b/public/images/flags/pf.svg
new file mode 100644
index 00000000..16374f36
--- /dev/null
+++ b/public/images/flags/pf.svg
@@ -0,0 +1,19 @@
+
diff --git a/public/images/flags/pg.png b/public/images/flags/pg.png
deleted file mode 100755
index 10d62334..00000000
Binary files a/public/images/flags/pg.png and /dev/null differ
diff --git a/public/images/flags/pg.svg b/public/images/flags/pg.svg
new file mode 100644
index 00000000..1080add5
--- /dev/null
+++ b/public/images/flags/pg.svg
@@ -0,0 +1,9 @@
+
diff --git a/public/images/flags/ph.png b/public/images/flags/ph.png
deleted file mode 100755
index b89e1593..00000000
Binary files a/public/images/flags/ph.png and /dev/null differ
diff --git a/public/images/flags/ph.svg b/public/images/flags/ph.svg
new file mode 100644
index 00000000..65489e1c
--- /dev/null
+++ b/public/images/flags/ph.svg
@@ -0,0 +1,6 @@
+
diff --git a/public/images/flags/pk.png b/public/images/flags/pk.png
deleted file mode 100755
index e9df70ca..00000000
Binary files a/public/images/flags/pk.png and /dev/null differ
diff --git a/public/images/flags/pk.svg b/public/images/flags/pk.svg
new file mode 100644
index 00000000..fa02f6a8
--- /dev/null
+++ b/public/images/flags/pk.svg
@@ -0,0 +1,15 @@
+
diff --git a/public/images/flags/pl.png b/public/images/flags/pl.png
deleted file mode 100755
index d413d010..00000000
Binary files a/public/images/flags/pl.png and /dev/null differ
diff --git a/public/images/flags/pl.svg b/public/images/flags/pl.svg
new file mode 100644
index 00000000..0fa51452
--- /dev/null
+++ b/public/images/flags/pl.svg
@@ -0,0 +1,6 @@
+
diff --git a/public/images/flags/pm.png b/public/images/flags/pm.png
deleted file mode 100755
index ba91d2c7..00000000
Binary files a/public/images/flags/pm.png and /dev/null differ
diff --git a/public/images/flags/pm.svg b/public/images/flags/pm.svg
new file mode 100644
index 00000000..401139f7
--- /dev/null
+++ b/public/images/flags/pm.svg
@@ -0,0 +1,5 @@
+
diff --git a/public/images/flags/pn.png b/public/images/flags/pn.png
deleted file mode 100755
index aa9344f5..00000000
Binary files a/public/images/flags/pn.png and /dev/null differ
diff --git a/public/images/flags/pn.svg b/public/images/flags/pn.svg
new file mode 100644
index 00000000..9788c9cc
--- /dev/null
+++ b/public/images/flags/pn.svg
@@ -0,0 +1,53 @@
+
diff --git a/public/images/flags/pr.png b/public/images/flags/pr.png
deleted file mode 100755
index 82d9130d..00000000
Binary files a/public/images/flags/pr.png and /dev/null differ
diff --git a/public/images/flags/pr.svg b/public/images/flags/pr.svg
new file mode 100644
index 00000000..3cb403b5
--- /dev/null
+++ b/public/images/flags/pr.svg
@@ -0,0 +1,13 @@
+
diff --git a/public/images/flags/ps.png b/public/images/flags/ps.png
deleted file mode 100755
index f5f54776..00000000
Binary files a/public/images/flags/ps.png and /dev/null differ
diff --git a/public/images/flags/ps.svg b/public/images/flags/ps.svg
new file mode 100644
index 00000000..82031486
--- /dev/null
+++ b/public/images/flags/ps.svg
@@ -0,0 +1,15 @@
+
diff --git a/public/images/flags/pt.png b/public/images/flags/pt.png
deleted file mode 100755
index ece79801..00000000
Binary files a/public/images/flags/pt.png and /dev/null differ
diff --git a/public/images/flags/pt.svg b/public/images/flags/pt.svg
new file mode 100644
index 00000000..2f36b7ee
--- /dev/null
+++ b/public/images/flags/pt.svg
@@ -0,0 +1,57 @@
+
diff --git a/public/images/flags/pw.png b/public/images/flags/pw.png
deleted file mode 100755
index 6178b254..00000000
Binary files a/public/images/flags/pw.png and /dev/null differ
diff --git a/public/images/flags/pw.svg b/public/images/flags/pw.svg
new file mode 100644
index 00000000..089cbcee
--- /dev/null
+++ b/public/images/flags/pw.svg
@@ -0,0 +1,11 @@
+
diff --git a/public/images/flags/py.png b/public/images/flags/py.png
deleted file mode 100755
index cb8723c0..00000000
Binary files a/public/images/flags/py.png and /dev/null differ
diff --git a/public/images/flags/py.svg b/public/images/flags/py.svg
new file mode 100644
index 00000000..bfbf01f1
--- /dev/null
+++ b/public/images/flags/py.svg
@@ -0,0 +1,157 @@
+
diff --git a/public/images/flags/qa.png b/public/images/flags/qa.png
deleted file mode 100755
index ed4c621f..00000000
Binary files a/public/images/flags/qa.png and /dev/null differ
diff --git a/public/images/flags/qa.svg b/public/images/flags/qa.svg
new file mode 100644
index 00000000..bd493c38
--- /dev/null
+++ b/public/images/flags/qa.svg
@@ -0,0 +1,4 @@
+
diff --git a/public/images/flags/re.png b/public/images/flags/re.png
deleted file mode 100755
index 8332c4ec..00000000
Binary files a/public/images/flags/re.png and /dev/null differ
diff --git a/public/images/flags/re.svg b/public/images/flags/re.svg
new file mode 100644
index 00000000..3225dddf
--- /dev/null
+++ b/public/images/flags/re.svg
@@ -0,0 +1,5 @@
+
diff --git a/public/images/flags/readme.txt b/public/images/flags/readme.txt
deleted file mode 100755
index 1028eec3..00000000
--- a/public/images/flags/readme.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-Flag icons - http://www.famfamfam.com
-
-These icons are public domain, and as such are free for any use (attribution appreciated but not required).
-
-Note that these flags are named using the ISO3166-1 alpha-2 country codes where appropriate. A list of codes can be found at http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2
-
-If you find these icons useful, please donate via paypal to mjames@gmail.com (or click the donate button available at http://www.famfamfam.com/lab/icons/silk)
-
-Contact: mjames@gmail.com
\ No newline at end of file
diff --git a/public/images/flags/ro.png b/public/images/flags/ro.png
deleted file mode 100755
index 57e74a65..00000000
Binary files a/public/images/flags/ro.png and /dev/null differ
diff --git a/public/images/flags/ro.svg b/public/images/flags/ro.svg
new file mode 100644
index 00000000..fda0f7be
--- /dev/null
+++ b/public/images/flags/ro.svg
@@ -0,0 +1,7 @@
+
diff --git a/public/images/flags/rs.png b/public/images/flags/rs.png
deleted file mode 100755
index 9439a5b6..00000000
Binary files a/public/images/flags/rs.png and /dev/null differ
diff --git a/public/images/flags/rs.svg b/public/images/flags/rs.svg
new file mode 100644
index 00000000..120293ab
--- /dev/null
+++ b/public/images/flags/rs.svg
@@ -0,0 +1,292 @@
+
diff --git a/public/images/flags/ru.png b/public/images/flags/ru.png
deleted file mode 100755
index 47da4214..00000000
Binary files a/public/images/flags/ru.png and /dev/null differ
diff --git a/public/images/flags/ru.svg b/public/images/flags/ru.svg
new file mode 100644
index 00000000..f4d27efc
--- /dev/null
+++ b/public/images/flags/ru.svg
@@ -0,0 +1,7 @@
+
diff --git a/public/images/flags/rw.png b/public/images/flags/rw.png
deleted file mode 100755
index 53564917..00000000
Binary files a/public/images/flags/rw.png and /dev/null differ
diff --git a/public/images/flags/rw.svg b/public/images/flags/rw.svg
new file mode 100644
index 00000000..6cc669ed
--- /dev/null
+++ b/public/images/flags/rw.svg
@@ -0,0 +1,13 @@
+
diff --git a/public/images/flags/sa.png b/public/images/flags/sa.png
deleted file mode 100755
index b4641c7e..00000000
Binary files a/public/images/flags/sa.png and /dev/null differ
diff --git a/public/images/flags/sa.svg b/public/images/flags/sa.svg
new file mode 100644
index 00000000..660396a7
--- /dev/null
+++ b/public/images/flags/sa.svg
@@ -0,0 +1,25 @@
+
diff --git a/public/images/flags/sb.png b/public/images/flags/sb.png
deleted file mode 100755
index a9937ccf..00000000
Binary files a/public/images/flags/sb.png and /dev/null differ
diff --git a/public/images/flags/sb.svg b/public/images/flags/sb.svg
new file mode 100644
index 00000000..a011360d
--- /dev/null
+++ b/public/images/flags/sb.svg
@@ -0,0 +1,13 @@
+
diff --git a/public/images/flags/sc.png b/public/images/flags/sc.png
deleted file mode 100755
index 39ee3718..00000000
Binary files a/public/images/flags/sc.png and /dev/null differ
diff --git a/public/images/flags/sc.svg b/public/images/flags/sc.svg
new file mode 100644
index 00000000..9a46b369
--- /dev/null
+++ b/public/images/flags/sc.svg
@@ -0,0 +1,7 @@
+
diff --git a/public/images/flags/scotland.png b/public/images/flags/scotland.png
deleted file mode 100755
index a0e57b41..00000000
Binary files a/public/images/flags/scotland.png and /dev/null differ
diff --git a/public/images/flags/sd.png b/public/images/flags/sd.png
deleted file mode 100755
index eaab69eb..00000000
Binary files a/public/images/flags/sd.png and /dev/null differ
diff --git a/public/images/flags/sd.svg b/public/images/flags/sd.svg
new file mode 100644
index 00000000..b8e4b973
--- /dev/null
+++ b/public/images/flags/sd.svg
@@ -0,0 +1,13 @@
+
diff --git a/public/images/flags/se.png b/public/images/flags/se.png
deleted file mode 100755
index 1994653d..00000000
Binary files a/public/images/flags/se.png and /dev/null differ
diff --git a/public/images/flags/se.svg b/public/images/flags/se.svg
new file mode 100644
index 00000000..0e41780e
--- /dev/null
+++ b/public/images/flags/se.svg
@@ -0,0 +1,4 @@
+
diff --git a/public/images/flags/sg.png b/public/images/flags/sg.png
deleted file mode 100755
index dd34d612..00000000
Binary files a/public/images/flags/sg.png and /dev/null differ
diff --git a/public/images/flags/sg.svg b/public/images/flags/sg.svg
new file mode 100644
index 00000000..c4dd4ac9
--- /dev/null
+++ b/public/images/flags/sg.svg
@@ -0,0 +1,13 @@
+
diff --git a/public/images/flags/sh.png b/public/images/flags/sh.png
deleted file mode 100755
index 4b1d2a29..00000000
Binary files a/public/images/flags/sh.png and /dev/null differ
diff --git a/public/images/flags/sh.svg b/public/images/flags/sh.svg
new file mode 100644
index 00000000..353915d3
--- /dev/null
+++ b/public/images/flags/sh.svg
@@ -0,0 +1,7 @@
+
diff --git a/public/images/flags/si.png b/public/images/flags/si.png
deleted file mode 100755
index bb1476ff..00000000
Binary files a/public/images/flags/si.png and /dev/null differ
diff --git a/public/images/flags/si.svg b/public/images/flags/si.svg
new file mode 100644
index 00000000..f2aea016
--- /dev/null
+++ b/public/images/flags/si.svg
@@ -0,0 +1,18 @@
+
diff --git a/public/images/flags/sj.png b/public/images/flags/sj.png
deleted file mode 100755
index 160b6b5b..00000000
Binary files a/public/images/flags/sj.png and /dev/null differ
diff --git a/public/images/flags/sj.svg b/public/images/flags/sj.svg
new file mode 100644
index 00000000..bb2799ce
--- /dev/null
+++ b/public/images/flags/sj.svg
@@ -0,0 +1,7 @@
+
diff --git a/public/images/flags/sk.png b/public/images/flags/sk.png
deleted file mode 100755
index 7ccbc827..00000000
Binary files a/public/images/flags/sk.png and /dev/null differ
diff --git a/public/images/flags/sk.svg b/public/images/flags/sk.svg
new file mode 100644
index 00000000..a1953fa6
--- /dev/null
+++ b/public/images/flags/sk.svg
@@ -0,0 +1,9 @@
+
diff --git a/public/images/flags/sl.png b/public/images/flags/sl.png
deleted file mode 100755
index 12d812d2..00000000
Binary files a/public/images/flags/sl.png and /dev/null differ
diff --git a/public/images/flags/sl.svg b/public/images/flags/sl.svg
new file mode 100644
index 00000000..a07baf75
--- /dev/null
+++ b/public/images/flags/sl.svg
@@ -0,0 +1,7 @@
+
diff --git a/public/images/flags/sm.png b/public/images/flags/sm.png
deleted file mode 100755
index 3df2fdcf..00000000
Binary files a/public/images/flags/sm.png and /dev/null differ
diff --git a/public/images/flags/sm.svg b/public/images/flags/sm.svg
new file mode 100644
index 00000000..0892990b
--- /dev/null
+++ b/public/images/flags/sm.svg
@@ -0,0 +1,75 @@
+
diff --git a/public/images/flags/sn.png b/public/images/flags/sn.png
deleted file mode 100755
index eabb71db..00000000
Binary files a/public/images/flags/sn.png and /dev/null differ
diff --git a/public/images/flags/sn.svg b/public/images/flags/sn.svg
new file mode 100644
index 00000000..7c0673d6
--- /dev/null
+++ b/public/images/flags/sn.svg
@@ -0,0 +1,8 @@
+
diff --git a/public/images/flags/so.png b/public/images/flags/so.png
deleted file mode 100755
index 4a1ea4b2..00000000
Binary files a/public/images/flags/so.png and /dev/null differ
diff --git a/public/images/flags/so.svg b/public/images/flags/so.svg
new file mode 100644
index 00000000..ae582f19
--- /dev/null
+++ b/public/images/flags/so.svg
@@ -0,0 +1,11 @@
+
diff --git a/public/images/flags/sr.png b/public/images/flags/sr.png
deleted file mode 100755
index 5eff9271..00000000
Binary files a/public/images/flags/sr.png and /dev/null differ
diff --git a/public/images/flags/sr.svg b/public/images/flags/sr.svg
new file mode 100644
index 00000000..5e71c400
--- /dev/null
+++ b/public/images/flags/sr.svg
@@ -0,0 +1,6 @@
+
diff --git a/public/images/flags/ss.svg b/public/images/flags/ss.svg
new file mode 100644
index 00000000..73804d80
--- /dev/null
+++ b/public/images/flags/ss.svg
@@ -0,0 +1,8 @@
+
diff --git a/public/images/flags/st.png b/public/images/flags/st.png
deleted file mode 100755
index 2978557b..00000000
Binary files a/public/images/flags/st.png and /dev/null differ
diff --git a/public/images/flags/st.svg b/public/images/flags/st.svg
new file mode 100644
index 00000000..f2e75c14
--- /dev/null
+++ b/public/images/flags/st.svg
@@ -0,0 +1,16 @@
+
diff --git a/public/images/flags/sv.png b/public/images/flags/sv.png
deleted file mode 100755
index 24987990..00000000
Binary files a/public/images/flags/sv.png and /dev/null differ
diff --git a/public/images/flags/sv.svg b/public/images/flags/sv.svg
new file mode 100644
index 00000000..3a63913d
--- /dev/null
+++ b/public/images/flags/sv.svg
@@ -0,0 +1,594 @@
+
diff --git a/public/images/flags/sx.svg b/public/images/flags/sx.svg
new file mode 100644
index 00000000..84844e0f
--- /dev/null
+++ b/public/images/flags/sx.svg
@@ -0,0 +1,56 @@
+
diff --git a/public/images/flags/sy.png b/public/images/flags/sy.png
deleted file mode 100755
index f5ce30dc..00000000
Binary files a/public/images/flags/sy.png and /dev/null differ
diff --git a/public/images/flags/sy.svg b/public/images/flags/sy.svg
new file mode 100644
index 00000000..29636ae0
--- /dev/null
+++ b/public/images/flags/sy.svg
@@ -0,0 +1,6 @@
+
diff --git a/public/images/flags/sz.png b/public/images/flags/sz.png
deleted file mode 100755
index 914ee861..00000000
Binary files a/public/images/flags/sz.png and /dev/null differ
diff --git a/public/images/flags/sz.svg b/public/images/flags/sz.svg
new file mode 100644
index 00000000..5eef6914
--- /dev/null
+++ b/public/images/flags/sz.svg
@@ -0,0 +1,34 @@
+
diff --git a/public/images/flags/ta.svg b/public/images/flags/ta.svg
new file mode 100644
index 00000000..b68ad23c
--- /dev/null
+++ b/public/images/flags/ta.svg
@@ -0,0 +1,76 @@
+
diff --git a/public/images/flags/tc.png b/public/images/flags/tc.png
deleted file mode 100755
index 8fc1156b..00000000
Binary files a/public/images/flags/tc.png and /dev/null differ
diff --git a/public/images/flags/tc.svg b/public/images/flags/tc.svg
new file mode 100644
index 00000000..89d29bbf
--- /dev/null
+++ b/public/images/flags/tc.svg
@@ -0,0 +1,50 @@
+
diff --git a/public/images/flags/td.png b/public/images/flags/td.png
deleted file mode 100755
index 667f21fd..00000000
Binary files a/public/images/flags/td.png and /dev/null differ
diff --git a/public/images/flags/td.svg b/public/images/flags/td.svg
new file mode 100644
index 00000000..fa3bd927
--- /dev/null
+++ b/public/images/flags/td.svg
@@ -0,0 +1,7 @@
+
diff --git a/public/images/flags/tf.png b/public/images/flags/tf.png
deleted file mode 100755
index 80529a43..00000000
Binary files a/public/images/flags/tf.png and /dev/null differ
diff --git a/public/images/flags/tf.svg b/public/images/flags/tf.svg
new file mode 100644
index 00000000..88323d2c
--- /dev/null
+++ b/public/images/flags/tf.svg
@@ -0,0 +1,15 @@
+
diff --git a/public/images/flags/tg.png b/public/images/flags/tg.png
deleted file mode 100755
index 3aa00ad4..00000000
Binary files a/public/images/flags/tg.png and /dev/null differ
diff --git a/public/images/flags/tg.svg b/public/images/flags/tg.svg
new file mode 100644
index 00000000..e20f40d8
--- /dev/null
+++ b/public/images/flags/tg.svg
@@ -0,0 +1,14 @@
+
diff --git a/public/images/flags/th.png b/public/images/flags/th.png
deleted file mode 100755
index dd8ba917..00000000
Binary files a/public/images/flags/th.png and /dev/null differ
diff --git a/public/images/flags/th.svg b/public/images/flags/th.svg
new file mode 100644
index 00000000..1e93a61e
--- /dev/null
+++ b/public/images/flags/th.svg
@@ -0,0 +1,7 @@
+
diff --git a/public/images/flags/tj.png b/public/images/flags/tj.png
deleted file mode 100755
index 617bf645..00000000
Binary files a/public/images/flags/tj.png and /dev/null differ
diff --git a/public/images/flags/tj.svg b/public/images/flags/tj.svg
new file mode 100644
index 00000000..d2ba7333
--- /dev/null
+++ b/public/images/flags/tj.svg
@@ -0,0 +1,22 @@
+
diff --git a/public/images/flags/tk.png b/public/images/flags/tk.png
deleted file mode 100755
index 67b8c8cb..00000000
Binary files a/public/images/flags/tk.png and /dev/null differ
diff --git a/public/images/flags/tk.svg b/public/images/flags/tk.svg
new file mode 100644
index 00000000..65bab137
--- /dev/null
+++ b/public/images/flags/tk.svg
@@ -0,0 +1,5 @@
+
diff --git a/public/images/flags/tl.png b/public/images/flags/tl.png
deleted file mode 100755
index 77da181e..00000000
Binary files a/public/images/flags/tl.png and /dev/null differ
diff --git a/public/images/flags/tl.svg b/public/images/flags/tl.svg
new file mode 100644
index 00000000..bcfc1612
--- /dev/null
+++ b/public/images/flags/tl.svg
@@ -0,0 +1,13 @@
+
diff --git a/public/images/flags/tm.png b/public/images/flags/tm.png
deleted file mode 100755
index 828020ec..00000000
Binary files a/public/images/flags/tm.png and /dev/null differ
diff --git a/public/images/flags/tm.svg b/public/images/flags/tm.svg
new file mode 100644
index 00000000..07c1a2f6
--- /dev/null
+++ b/public/images/flags/tm.svg
@@ -0,0 +1,204 @@
+
diff --git a/public/images/flags/tn.png b/public/images/flags/tn.png
deleted file mode 100755
index 183cdd3d..00000000
Binary files a/public/images/flags/tn.png and /dev/null differ
diff --git a/public/images/flags/tn.svg b/public/images/flags/tn.svg
new file mode 100644
index 00000000..6a1989b4
--- /dev/null
+++ b/public/images/flags/tn.svg
@@ -0,0 +1,4 @@
+
diff --git a/public/images/flags/to.png b/public/images/flags/to.png
deleted file mode 100755
index f89b8ba7..00000000
Binary files a/public/images/flags/to.png and /dev/null differ
diff --git a/public/images/flags/to.svg b/public/images/flags/to.svg
new file mode 100644
index 00000000..d0723370
--- /dev/null
+++ b/public/images/flags/to.svg
@@ -0,0 +1,10 @@
+
diff --git a/public/images/flags/tr.png b/public/images/flags/tr.png
deleted file mode 100755
index be32f77e..00000000
Binary files a/public/images/flags/tr.png and /dev/null differ
diff --git a/public/images/flags/tr.svg b/public/images/flags/tr.svg
new file mode 100644
index 00000000..a92804f8
--- /dev/null
+++ b/public/images/flags/tr.svg
@@ -0,0 +1,8 @@
+
diff --git a/public/images/flags/tt.png b/public/images/flags/tt.png
deleted file mode 100755
index 2a11c1e2..00000000
Binary files a/public/images/flags/tt.png and /dev/null differ
diff --git a/public/images/flags/tt.svg b/public/images/flags/tt.svg
new file mode 100644
index 00000000..14adbe04
--- /dev/null
+++ b/public/images/flags/tt.svg
@@ -0,0 +1,5 @@
+
diff --git a/public/images/flags/tv.png b/public/images/flags/tv.png
deleted file mode 100755
index 28274c5f..00000000
Binary files a/public/images/flags/tv.png and /dev/null differ
diff --git a/public/images/flags/tv.svg b/public/images/flags/tv.svg
new file mode 100644
index 00000000..675210ec
--- /dev/null
+++ b/public/images/flags/tv.svg
@@ -0,0 +1,9 @@
+
diff --git a/public/images/flags/tw.png b/public/images/flags/tw.png
deleted file mode 100755
index f31c654c..00000000
Binary files a/public/images/flags/tw.png and /dev/null differ
diff --git a/public/images/flags/tw.svg b/public/images/flags/tw.svg
new file mode 100644
index 00000000..57fd98b4
--- /dev/null
+++ b/public/images/flags/tw.svg
@@ -0,0 +1,34 @@
+
diff --git a/public/images/flags/tz.png b/public/images/flags/tz.png
deleted file mode 100755
index c00ff796..00000000
Binary files a/public/images/flags/tz.png and /dev/null differ
diff --git a/public/images/flags/tz.svg b/public/images/flags/tz.svg
new file mode 100644
index 00000000..751c1672
--- /dev/null
+++ b/public/images/flags/tz.svg
@@ -0,0 +1,13 @@
+
diff --git a/public/images/flags/ua.png b/public/images/flags/ua.png
deleted file mode 100755
index 09563a21..00000000
Binary files a/public/images/flags/ua.png and /dev/null differ
diff --git a/public/images/flags/ua.svg b/public/images/flags/ua.svg
new file mode 100644
index 00000000..a339eb1b
--- /dev/null
+++ b/public/images/flags/ua.svg
@@ -0,0 +1,6 @@
+
diff --git a/public/images/flags/ug.png b/public/images/flags/ug.png
deleted file mode 100755
index 33f4affa..00000000
Binary files a/public/images/flags/ug.png and /dev/null differ
diff --git a/public/images/flags/ug.svg b/public/images/flags/ug.svg
new file mode 100644
index 00000000..78252a42
--- /dev/null
+++ b/public/images/flags/ug.svg
@@ -0,0 +1,30 @@
+
diff --git a/public/images/flags/um.png b/public/images/flags/um.png
deleted file mode 100755
index c1dd9654..00000000
Binary files a/public/images/flags/um.png and /dev/null differ
diff --git a/public/images/flags/um.svg b/public/images/flags/um.svg
new file mode 100644
index 00000000..e0415949
--- /dev/null
+++ b/public/images/flags/um.svg
@@ -0,0 +1,9 @@
+
diff --git a/public/images/flags/un.svg b/public/images/flags/un.svg
new file mode 100644
index 00000000..e4753370
--- /dev/null
+++ b/public/images/flags/un.svg
@@ -0,0 +1,16 @@
+
diff --git a/public/images/flags/us.png b/public/images/flags/us.png
deleted file mode 100755
index 10f451fe..00000000
Binary files a/public/images/flags/us.png and /dev/null differ
diff --git a/public/images/flags/us.svg b/public/images/flags/us.svg
new file mode 100644
index 00000000..615946d4
--- /dev/null
+++ b/public/images/flags/us.svg
@@ -0,0 +1,9 @@
+
diff --git a/public/images/flags/uy.png b/public/images/flags/uy.png
deleted file mode 100755
index 31d948a0..00000000
Binary files a/public/images/flags/uy.png and /dev/null differ
diff --git a/public/images/flags/uy.svg b/public/images/flags/uy.svg
new file mode 100644
index 00000000..4a54b857
--- /dev/null
+++ b/public/images/flags/uy.svg
@@ -0,0 +1,28 @@
+
diff --git a/public/images/flags/uz.png b/public/images/flags/uz.png
deleted file mode 100755
index fef5dc17..00000000
Binary files a/public/images/flags/uz.png and /dev/null differ
diff --git a/public/images/flags/uz.svg b/public/images/flags/uz.svg
new file mode 100644
index 00000000..aaf9382a
--- /dev/null
+++ b/public/images/flags/uz.svg
@@ -0,0 +1,30 @@
+
diff --git a/public/images/flags/va.png b/public/images/flags/va.png
deleted file mode 100755
index b31eaf22..00000000
Binary files a/public/images/flags/va.png and /dev/null differ
diff --git a/public/images/flags/va.svg b/public/images/flags/va.svg
new file mode 100644
index 00000000..25e6a975
--- /dev/null
+++ b/public/images/flags/va.svg
@@ -0,0 +1,190 @@
+
diff --git a/public/images/flags/vc.png b/public/images/flags/vc.png
deleted file mode 100755
index 8fa17b06..00000000
Binary files a/public/images/flags/vc.png and /dev/null differ
diff --git a/public/images/flags/vc.svg b/public/images/flags/vc.svg
new file mode 100644
index 00000000..450f6f0a
--- /dev/null
+++ b/public/images/flags/vc.svg
@@ -0,0 +1,8 @@
+
diff --git a/public/images/flags/ve.png b/public/images/flags/ve.png
deleted file mode 100755
index 00c90f9a..00000000
Binary files a/public/images/flags/ve.png and /dev/null differ
diff --git a/public/images/flags/ve.svg b/public/images/flags/ve.svg
new file mode 100644
index 00000000..314e7f5f
--- /dev/null
+++ b/public/images/flags/ve.svg
@@ -0,0 +1,26 @@
+
diff --git a/public/images/flags/vg.png b/public/images/flags/vg.png
deleted file mode 100755
index 41569079..00000000
Binary files a/public/images/flags/vg.png and /dev/null differ
diff --git a/public/images/flags/vg.svg b/public/images/flags/vg.svg
new file mode 100644
index 00000000..4d2c3976
--- /dev/null
+++ b/public/images/flags/vg.svg
@@ -0,0 +1,59 @@
+
diff --git a/public/images/flags/vi.png b/public/images/flags/vi.png
deleted file mode 100755
index ed26915a..00000000
Binary files a/public/images/flags/vi.png and /dev/null differ
diff --git a/public/images/flags/vi.svg b/public/images/flags/vi.svg
new file mode 100644
index 00000000..3a64338e
--- /dev/null
+++ b/public/images/flags/vi.svg
@@ -0,0 +1,28 @@
+
diff --git a/public/images/flags/vn.png b/public/images/flags/vn.png
deleted file mode 100755
index ec7cd48a..00000000
Binary files a/public/images/flags/vn.png and /dev/null differ
diff --git a/public/images/flags/vn.svg b/public/images/flags/vn.svg
new file mode 100644
index 00000000..24bedc50
--- /dev/null
+++ b/public/images/flags/vn.svg
@@ -0,0 +1,11 @@
+
diff --git a/public/images/flags/vu.png b/public/images/flags/vu.png
deleted file mode 100755
index b3397bc6..00000000
Binary files a/public/images/flags/vu.png and /dev/null differ
diff --git a/public/images/flags/vu.svg b/public/images/flags/vu.svg
new file mode 100644
index 00000000..efcff895
--- /dev/null
+++ b/public/images/flags/vu.svg
@@ -0,0 +1,21 @@
+
diff --git a/public/images/flags/wales.png b/public/images/flags/wales.png
deleted file mode 100755
index e0d7cee1..00000000
Binary files a/public/images/flags/wales.png and /dev/null differ
diff --git a/public/images/flags/wf.png b/public/images/flags/wf.png
deleted file mode 100755
index 9f955873..00000000
Binary files a/public/images/flags/wf.png and /dev/null differ
diff --git a/public/images/flags/wf.svg b/public/images/flags/wf.svg
new file mode 100644
index 00000000..57feb3a5
--- /dev/null
+++ b/public/images/flags/wf.svg
@@ -0,0 +1,5 @@
+
diff --git a/public/images/flags/ws.png b/public/images/flags/ws.png
deleted file mode 100755
index c1695080..00000000
Binary files a/public/images/flags/ws.png and /dev/null differ
diff --git a/public/images/flags/ws.svg b/public/images/flags/ws.svg
new file mode 100644
index 00000000..0e758a7a
--- /dev/null
+++ b/public/images/flags/ws.svg
@@ -0,0 +1,7 @@
+
diff --git a/public/images/flags/xk.svg b/public/images/flags/xk.svg
new file mode 100644
index 00000000..de6ef4da
--- /dev/null
+++ b/public/images/flags/xk.svg
@@ -0,0 +1,5 @@
+
diff --git a/public/images/flags/xx.svg b/public/images/flags/xx.svg
new file mode 100644
index 00000000..9333be36
--- /dev/null
+++ b/public/images/flags/xx.svg
@@ -0,0 +1,4 @@
+
diff --git a/public/images/flags/ye.png b/public/images/flags/ye.png
deleted file mode 100755
index 468dfad0..00000000
Binary files a/public/images/flags/ye.png and /dev/null differ
diff --git a/public/images/flags/ye.svg b/public/images/flags/ye.svg
new file mode 100644
index 00000000..61f0ed61
--- /dev/null
+++ b/public/images/flags/ye.svg
@@ -0,0 +1,7 @@
+
diff --git a/public/images/flags/yt.png b/public/images/flags/yt.png
deleted file mode 100755
index c298f378..00000000
Binary files a/public/images/flags/yt.png and /dev/null differ
diff --git a/public/images/flags/yt.svg b/public/images/flags/yt.svg
new file mode 100644
index 00000000..5ea2f648
--- /dev/null
+++ b/public/images/flags/yt.svg
@@ -0,0 +1,5 @@
+
diff --git a/public/images/flags/za.png b/public/images/flags/za.png
deleted file mode 100755
index 57c58e21..00000000
Binary files a/public/images/flags/za.png and /dev/null differ
diff --git a/public/images/flags/za.svg b/public/images/flags/za.svg
new file mode 100644
index 00000000..aa54beb8
--- /dev/null
+++ b/public/images/flags/za.svg
@@ -0,0 +1,17 @@
+
diff --git a/public/images/flags/zm.png b/public/images/flags/zm.png
deleted file mode 100755
index c25b07be..00000000
Binary files a/public/images/flags/zm.png and /dev/null differ
diff --git a/public/images/flags/zm.svg b/public/images/flags/zm.svg
new file mode 100644
index 00000000..b8fdd63c
--- /dev/null
+++ b/public/images/flags/zm.svg
@@ -0,0 +1,27 @@
+
diff --git a/public/images/flags/zw.png b/public/images/flags/zw.png
deleted file mode 100755
index 53c97259..00000000
Binary files a/public/images/flags/zw.png and /dev/null differ
diff --git a/public/images/flags/zw.svg b/public/images/flags/zw.svg
new file mode 100644
index 00000000..5c197469
--- /dev/null
+++ b/public/images/flags/zw.svg
@@ -0,0 +1,21 @@
+
diff --git a/public/js/datatables-de.json b/public/js/datatables-de.json
new file mode 100644
index 00000000..32635ed6
--- /dev/null
+++ b/public/js/datatables-de.json
@@ -0,0 +1,243 @@
+{
+ "emptyTable": "Keine Daten in der Tabelle vorhanden",
+ "info": "_START_ bis _END_ von _TOTAL_ Einträgen",
+ "infoEmpty": "Keine Daten vorhanden",
+ "infoFiltered": "(gefiltert von _MAX_ Einträgen)",
+ "infoThousands": ".",
+ "loadingRecords": "Wird geladen ..",
+ "processing": "Bitte warten ..",
+ "paginate": {
+ "first": "Erste",
+ "next": "Nächste",
+ "last": "Letzte",
+ "previous": "Vorherige"
+ },
+ "aria": {
+ "sortAscending": ": aktivieren, um Spalte aufsteigend zu sortieren",
+ "sortDescending": ": aktivieren, um Spalte absteigend zu sortieren"
+ },
+ "select": {
+ "rows": {
+ "_": "%d Zeilen ausgewählt",
+ "1": "1 Zeile ausgewählt"
+ },
+ "cells": {
+ "1": "1 Zelle ausgewählt",
+ "_": "%d Zellen ausgewählt"
+ },
+ "columns": {
+ "1": "1 Spalte ausgewählt",
+ "_": "%d Spalten ausgewählt"
+ }
+ },
+ "buttons": {
+ "print": "Drucken",
+ "copy": "Kopieren",
+ "copyTitle": "In Zwischenablage kopieren",
+ "copySuccess": {
+ "_": "%d Zeilen kopiert",
+ "1": "1 Zeile kopiert"
+ },
+ "collection": "Aktionen {{__('Pos')}}
{{__('Description')}}
{{__('Translate') }}
- {{__('Status')}}
+ {{__('tables.status')}}
@@ -27,14 +27,14 @@
data-name="{{ $value->name }}"
data-trans_name="{{ json_encode($value->trans_name) }}"
data-active="{{ $value->active }}">
-
+
{{ $value->pos }}
{{ $value->name }}
{{ $value->getTranNames() }}
@if($value->active) @else@endif
-
+
@endforeach
@@ -71,7 +71,7 @@
-
+
@@ -93,7 +93,7 @@
@if($tran != 'de')
-
+
@@ -140,7 +140,7 @@
{ "sWidth": "8%" },
],
"language": {
- "url": "/js/German.json"
+ "url": "/js/datatables-{{ \App::getLocale() }}.json"
}
});
});
diff --git a/resources/views/admin/business/_user_detail_in.blade.php b/resources/views/admin/business/_user_detail_in.blade.php
index 937cd572..30e49c8e 100644
--- a/resources/views/admin/business/_user_detail_in.blade.php
+++ b/resources/views/admin/business/_user_detail_in.blade.php
@@ -1,21 +1,21 @@
- Account:
+ {{ __('team.account') }}:
@if($TreeCalcBot->business_user->active_account)
- aktiv
+ {{ __('team.active') }}
@else
- nicht aktiv
+ {{ __('team.not_active') }}
@endif
- @if($TreeCalcBot->business_user->active_date)
- bis: {{ formatDate($TreeCalcBot->business_user->active_date) }}
+ @if($TreeCalcBot->business_user->payment_account_date)
+ {{ __('team.until') }}: {{ formatDate($TreeCalcBot->business_user->payment_account_date) }}
@endif
(ID: {{ $TreeCalcBot->business_user->m_account }})
- Sponsor:
+ {{ __('team.sponsor') }}:
@if($TreeCalcBot->business_user->sponsor->is_sponsor)
{{ $TreeCalcBot->business_user->sponsor->first_name }} {{ $TreeCalcBot->business_user->sponsor->last_name }} |
@@ -28,9 +28,9 @@
- Datum:
+ {{ __('team.date') }}:
- {{ HTMLHelper::getMonth($data['month']) }} {{ $data['year'] }} | Abgeschlossen:
+ {{ HTMLHelper::getMonth($data['month']) }} {{ $data['year'] }} | {{ __('team.completed') }}:
@if($TreeCalcBot->business_user->isSave())
@else
@@ -40,118 +40,139 @@
- Karriere-Level:
+ {{ __('team.career_level') }}:
- {{ $TreeCalcBot->business_user->user_level_name }}
- KP {{ $TreeCalcBot->business_user->qual_kp }} / PP {{ formatNumber($TreeCalcBot->business_user->qual_pp, 0) }}
+ {{ \App\Services\TranslationHelper::transUserLevelName($TreeCalcBot->business_user->user_level_name) }}
+ {{ __('team.KU') }} {{ $TreeCalcBot->business_user->qual_kp }} / {{ __('team.PP') }} {{ formatNumber($TreeCalcBot->business_user->qual_pp, 0) }}
- Kundenprovision:
+ {{ __('team.consultant_margin') }}:
{{ $TreeCalcBot->business_user->margin }} %
- Shop Provision:
+ {{ __('team.shop_commission') }}:
{{ $TreeCalcBot->business_user->margin_shop }} %
- Umsatz netto:
+ {{ __('team.net_turnover') }}:
{{ formatNumber($TreeCalcBot->business_user->sales_volume_total_sum) }} €
- (Eigene: {{ formatNumber($TreeCalcBot->business_user->sales_volume_total) }} € | Shop: {{ formatNumber($TreeCalcBot->business_user->sales_volume_total_shop) }} €)
+ ({{ __('team.own') }}: {{ formatNumber($TreeCalcBot->business_user->sales_volume_total) }} € | {{ __('team.shop') }}: {{ formatNumber($TreeCalcBot->business_user->sales_volume_total_shop) }} €)
- Kunden Points:
+ {{ __('team.customer_points') }}:
- {{ formatNumber($TreeCalcBot->business_user->sales_volume_points_KP_sum, 0) }} KP
- (Eigene: {{ formatNumber($TreeCalcBot->business_user->sales_volume_KP_points, 0) }} | Shop: {{ formatNumber($TreeCalcBot->business_user->sales_volume_points_shop, 0) }})
- KP {{ $TreeCalcBot->business_user->qual_kp }}
+ {{ formatNumber($TreeCalcBot->business_user->sales_volume_points_KP_sum, 0) }} {{ __('team.KU') }}
+ ({{ __('team.own') }}: {{ formatNumber($TreeCalcBot->business_user->sales_volume_KP_points, 0) }} | {{ __('team.shop') }}: {{ formatNumber($TreeCalcBot->business_user->sales_volume_points_shop, 0) }})
+ {{ __('team.KU') }} {{ $TreeCalcBot->business_user->qual_kp }}
@if($TreeCalcBot->business_user->version == 1)
- Qualifikation Points:
+ {{ __('team.qualification_points') }}:
- {{ formatNumber($TreeCalcBot->business_user->total_qual_pp, 0) }} TP (+ Volumen KP)
+ {{ formatNumber($TreeCalcBot->business_user->total_qual_pp, 0) }} {{ __('team.TP') }} (+ {{ __('team.volume_KU') }})
- Qualifikation Provision:
+ {{ __('team.qualification_commission') }}:
@if($TreeCalcBot->business_user->isQualLevel())
-
- KP {{ formatNumber($TreeCalcBot->business_user->sales_volume_points_KP_sum, 0) }} /
+
+ {{ __('team.KP') }} {{ formatNumber($TreeCalcBot->business_user->sales_volume_points_KP_sum, 0) }} /
{{ formatNumber($TreeCalcBot->business_user->qual_user_level['qual_kp'], 0) }} |
- TP {{ formatNumber($TreeCalcBot->business_user->total_qual_pp, 0) }} /
+ {{ __('team.TP') }} {{ formatNumber($TreeCalcBot->business_user->total_qual_pp, 0) }} /
{{ formatNumber($TreeCalcBot->business_user->qual_user_level['qual_pp'], 0) }}
| {{ $TreeCalcBot->business_user->qual_user_level['name'] }}
@endif
-
@endif
@if($TreeCalcBot->business_user->version == 2)
- Payline Points:
+ {{ __('team.payline_points') }}:
- {{ formatNumber($TreeCalcBot->business_user->payline_points, 0) }} PP
+ {{ formatNumber($TreeCalcBot->business_user->payline_points, 0) }} {{ __('team.PP') }}
- Qualifikation Points:
+ {{ __('team.qualification_points') }} :
- {{ formatNumber($TreeCalcBot->business_user->payline_points_qual_kp, 0) }} PP (+ Volumen KP)
+ {{ formatNumber($TreeCalcBot->business_user->payline_points_qual_kp, 0) }} {{ __('team.PP') }} (+ {{ __('team.volume_KU') }})
- aktuelle Provisions-Stufe:
+ {{ __('team.current_commission_level') }}:
@if($TreeCalcBot->business_user->isQualLevel())
- KP {{ formatNumber($TreeCalcBot->business_user->sales_volume_points_KP_sum, 0) }} /
+ {{ __('team.KU') }} {{ formatNumber($TreeCalcBot->business_user->sales_volume_points_KP_sum, 0) }} /
{{ formatNumber($TreeCalcBot->business_user->qual_user_level['qual_kp'], 0) }} |
- PP {{ formatNumber($TreeCalcBot->business_user->payline_points_qual_kp, 0) }} /
+ {{ __('team.PP') }} {{ formatNumber($TreeCalcBot->business_user->payline_points_qual_kp, 0) }} /
{{ formatNumber($TreeCalcBot->business_user->qual_user_level['qual_pp'], 0) }}
- | {{ $TreeCalcBot->business_user->qual_user_level['name'] }}
+ | {{ \App\Services\TranslationHelper::transUserLevelName($TreeCalcBot->business_user->qual_user_level['name']) }}
@endif
@if($TreeCalcBot->business_user->qual_user_level_next)
- nächste Provisions-Stufe:
+ {{ __('team.next_commission_level') }}:
- KP {{ formatNumber($TreeCalcBot->business_user->sales_volume_points_KP_sum, 0) }} /
+ {{ __('team.KU') }} {{ formatNumber($TreeCalcBot->business_user->sales_volume_points_KP_sum, 0) }} /
{{ formatNumber($TreeCalcBot->business_user->qual_user_level_next['qual_kp'], 0) }} |
- PP {{ formatNumber($TreeCalcBot->business_user->payline_points_qual_kp, 0) }} /
+ {{ __('team.PP') }} {{ formatNumber($TreeCalcBot->business_user->payline_points_qual_kp, 0) }} /
{{ formatNumber($TreeCalcBot->business_user->qual_user_level_next['qual_pp'], 0) }}
- | {{ $TreeCalcBot->business_user->qual_user_level_next['name'] }}
+ | {{ \App\Services\TranslationHelper::transUserLevelName($TreeCalcBot->business_user->qual_user_level_next['name']) }}
@endif
@endif
+
+ @if($TreeCalcBot->business_user->next_qual_user_level) {{ __('team.qualification') }}
@endif {{ __('team.next_career_level') }}:
+
+ @if($TreeCalcBot->business_user->next_qual_user_level)
+
+ {{ __('team.KU') }} {{ formatNumber($TreeCalcBot->business_user->sales_volume_points_KP_sum, 0) }} /
+ {{ formatNumber($TreeCalcBot->business_user->next_qual_user_level['qual_kp'], 0) }} |
+ {{ __('team.TP') }} {{ formatNumber($TreeCalcBot->business_user->payline_points_qual_kp, 0) }} /
+ {{ formatNumber($TreeCalcBot->business_user->next_qual_user_level['qual_pp'], 0) }}
+ | {{ \App\Services\TranslationHelper::transUserLevelName($TreeCalcBot->business_user->next_qual_user_level['name']) }}
+ @elseif($TreeCalcBot->business_user->next_can_user_level)
+
+ {{ __('team.KU') }} {{ formatNumber($TreeCalcBot->business_user->sales_volume_points_KP_sum, 0) }} /
+ {{ formatNumber($TreeCalcBot->business_user->next_can_user_level['qual_kp'], 0) }} |
+ {{ __('team.TP') }} {{ formatNumber($TreeCalcBot->business_user->payline_points_qual_kp, 0) }} /
+ {{ formatNumber($TreeCalcBot->business_user->next_can_user_level['qual_pp'], 0) }}
+ | {{ \App\Services\TranslationHelper::transUserLevelName($TreeCalcBot->business_user->next_can_user_level['name']) }}
+ @else
+
+ @endif
+
+
- Provision Shop:
+ {{ __('team.commission_shop') }}:
{{ formatNumber($TreeCalcBot->business_user->commission_shop_sales) }} €
- (Umsatz Shop netto: {{ formatNumber($TreeCalcBot->business_user->sales_volume_total_shop) }} € / {{ $TreeCalcBot->business_user->margin_shop }} %)
+ ({{ __('team.sales_store_net') }}: {{ formatNumber($TreeCalcBot->business_user->sales_volume_total_shop) }} € / {{ $TreeCalcBot->business_user->margin_shop }} %)
@if($TreeCalcBot->business_user->version == 1)
- Provision Team:
+ {{ __('team.commission_team') }}:
{{ formatNumber($TreeCalcBot->business_user->commission_pp_total) }} €
@@ -159,27 +180,27 @@
@endif
@if($TreeCalcBot->business_user->version == 2)
- Provision Payline:
+ {{ __('team.commission_payline') }}:
{{ formatNumber($TreeCalcBot->business_user->commission_pp_total) }} €
- Provision Wachstumsbonus:
+ {{ __('team.commission_WB') }}:
{{ formatNumber($TreeCalcBot->business_user->commission_growth_total) }} €
@endif
- Provision Gesamt:
+ {{ __('team.commission_total') }}:
{{ formatNumber($TreeCalcBot->business_user->getCommissionTotal()) }} €
@if($TreeCalcBot->business_user->version == 2)
-
+ {{--
Team Points:
{{ formatNumber($TreeCalcBot->business_user->total_pp, 0) }} TP
@@ -188,33 +209,12 @@
Qualifikation Team Points:
- {{ formatNumber($TreeCalcBot->business_user->total_qual_pp, 0) }} TP (+ Volumen KP)
+ {{ formatNumber($TreeCalcBot->business_user->payline_points_qual_kp, 0) }} TP (+ Volumen KP)
+ --}}
@endif
-
- @if($TreeCalcBot->business_user->next_qual_user_level) Qualifikation
@endif nächster Karriere-Level:
-
-
- @if($TreeCalcBot->business_user->next_qual_user_level)
-
- KP {{ formatNumber($TreeCalcBot->business_user->sales_volume_points_KP_sum, 0) }} /
- {{ formatNumber($TreeCalcBot->business_user->next_qual_user_level['qual_kp'], 0) }} |
- TP {{ formatNumber($TreeCalcBot->business_user->total_qual_pp, 0) }} /
- {{ formatNumber($TreeCalcBot->business_user->next_qual_user_level['qual_pp'], 0) }}
- | {{ $TreeCalcBot->business_user->next_qual_user_level['name'] }}
- @elseif($TreeCalcBot->business_user->next_can_user_level)
-
- KP {{ formatNumber($TreeCalcBot->business_user->sales_volume_points_KP_sum, 0) }} /
- {{ formatNumber($TreeCalcBot->business_user->next_can_user_level['qual_kp'], 0) }} |
- TP {{ formatNumber($TreeCalcBot->business_user->total_qual_pp, 0) }} /
- {{ formatNumber($TreeCalcBot->business_user->next_can_user_level['qual_pp'], 0) }}
- | {{ $TreeCalcBot->business_user->next_can_user_level['name'] }}
- @else
-
- @endif
-
-
+
@@ -222,10 +222,10 @@