2020-12-01 17:02:10 +01:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
|
|
2021-09-09 14:08:59 +02:00
|
|
|
use App\Enums\CustomerExportType;
|
|
|
|
|
use App\Http\Requests\CustomerExport;
|
2020-12-01 17:02:10 +01:00
|
|
|
use App\Models\Brand;
|
|
|
|
|
use App\Models\Customer;
|
2021-02-28 12:04:49 +01:00
|
|
|
use App\Models\CustomerInfo;
|
2020-12-01 17:02:10 +01:00
|
|
|
use App\Models\CustomerLogin;
|
2021-09-09 14:08:59 +02:00
|
|
|
use App\Models\SingleOptin;
|
2023-06-26 15:10:28 +02:00
|
|
|
use Illuminate\Database\Eloquent\Builder;
|
2021-09-10 15:43:27 +02:00
|
|
|
use Illuminate\Database\Query\JoinClause;
|
2021-09-09 15:09:13 +02:00
|
|
|
use Illuminate\Http\Request;
|
2021-09-09 14:08:59 +02:00
|
|
|
use Illuminate\Support\Carbon;
|
2021-12-19 15:57:24 +01:00
|
|
|
use Illuminate\Support\Facades\DB;
|
2021-09-09 15:09:13 +02:00
|
|
|
use Illuminate\Support\Facades\Schema;
|
|
|
|
|
use Illuminate\Support\Facades\Session;
|
2021-09-09 14:08:59 +02:00
|
|
|
use Illuminate\Support\Str;
|
|
|
|
|
use League\Csv\Writer;
|
|
|
|
|
use Symfony\Component\HttpFoundation\StreamedResponse;
|
2020-12-01 17:02:10 +01:00
|
|
|
|
2021-12-19 15:57:24 +01:00
|
|
|
/**
|
|
|
|
|
* @codeCoverageIgnore
|
|
|
|
|
*/
|
2020-12-01 17:02:10 +01:00
|
|
|
class CustomerController extends Controller
|
|
|
|
|
{
|
2021-12-19 15:57:24 +01:00
|
|
|
/**
|
|
|
|
|
* View all customers
|
|
|
|
|
*
|
2023-06-23 17:18:59 +02:00
|
|
|
* @param \Illuminate\Http\Request $request
|
2021-12-19 15:57:24 +01:00
|
|
|
* @return \Illuminate\Http\Response
|
|
|
|
|
*/
|
2021-09-09 15:09:13 +02:00
|
|
|
public function index(Request $request)
|
2021-02-28 12:04:49 +01:00
|
|
|
{
|
2021-09-10 16:26:45 +02:00
|
|
|
$modelTable = (new Customer())->getTable();
|
|
|
|
|
$modelClass = Customer::class;
|
2021-09-09 15:09:13 +02:00
|
|
|
$brands = Brand::select('id', 'name')->get();
|
2021-09-10 15:56:01 +02:00
|
|
|
$columns = ['customer_infos.lastname', 'customer_infos.firstname'];
|
2021-09-09 15:09:13 +02:00
|
|
|
|
2021-12-19 15:57:24 +01:00
|
|
|
// * Jointure pour pouvoir trier les colonnes.
|
2021-09-09 15:09:13 +02:00
|
|
|
/** @var \Illuminate\Database\Eloquent\Builder */
|
2021-09-10 15:43:27 +02:00
|
|
|
$query = CustomerInfo::join('customer_logins', function (JoinClause $join) {
|
|
|
|
|
$join->on('customer_logins.brand_id', '=', 'customer_infos.brand_id')
|
|
|
|
|
->on('customer_logins.customer_id', '=', 'customer_infos.customer_id');
|
|
|
|
|
})
|
|
|
|
|
->join('customers', function (JoinClause $join) {
|
|
|
|
|
$join->on('customers.id', '=', 'customer_infos.customer_id');
|
|
|
|
|
})
|
|
|
|
|
->join('brands', function (JoinClause $join) {
|
|
|
|
|
$join->on('brands.id', '=', 'customer_infos.brand_id');
|
|
|
|
|
});
|
2022-03-28 16:22:33 +02:00
|
|
|
|
|
|
|
|
if ($request->rst) {
|
|
|
|
|
Session::remove("crud.$modelTable.brand");
|
|
|
|
|
Session::remove("crud.$modelTable.search");
|
|
|
|
|
Session::remove("crud.$modelTable.sort_way");
|
|
|
|
|
Session::remove("crud.$modelTable.sort_col");
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-10 16:11:52 +02:00
|
|
|
if (request()->brand or Session::has("crud.$modelTable.brand")) {
|
|
|
|
|
$brand = $request->brand ?? Session::get("crud.$modelTable.brand");
|
|
|
|
|
Session::put("crud.$modelTable.brand", $brand);
|
|
|
|
|
$query = $query->where('customer_infos.brand_id', $brand);
|
2021-09-09 15:09:13 +02:00
|
|
|
}
|
|
|
|
|
|
2021-12-19 15:57:24 +01:00
|
|
|
// * Search on crud Label column.
|
2021-09-10 16:11:52 +02:00
|
|
|
if ($request->search or Session::has("crud.$modelTable.search")) {
|
|
|
|
|
$search = $request->search ?? Session::get("crud.$modelTable.search");
|
|
|
|
|
Session::put("crud.$modelTable.search", $search);
|
|
|
|
|
$query->where(function ($q) use ($columns, $search) {
|
2021-09-10 15:56:01 +02:00
|
|
|
foreach ($columns as $column) {
|
2021-09-10 16:11:52 +02:00
|
|
|
$q = $q->orWhere($column, 'LIKE', "%$search%");
|
2021-09-10 15:56:01 +02:00
|
|
|
}
|
2021-09-10 16:11:52 +02:00
|
|
|
$q = $q->orWhere('customers.email', 'LIKE', "%$search%");
|
|
|
|
|
$q = $q->orWhere('customer_logins.last_connection', 'LIKE', "%$search%");
|
2021-09-10 15:56:01 +02:00
|
|
|
});
|
2021-09-09 15:09:13 +02:00
|
|
|
}
|
|
|
|
|
|
2021-12-19 15:57:24 +01:00
|
|
|
// * Sort columns.
|
2021-09-09 15:09:13 +02:00
|
|
|
if ($request->sort_col) {
|
|
|
|
|
Session::put("crud.$modelTable.sort_col", $request->sort_col);
|
|
|
|
|
}
|
|
|
|
|
if ($request->sort_way) {
|
|
|
|
|
Session::put("crud.$modelTable.sort_way", $request->sort_way);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
Session::has("crud.$modelTable.sort_col") and
|
|
|
|
|
Session::has("crud.$modelTable.sort_way") and
|
2021-09-10 15:43:27 +02:00
|
|
|
(Schema::hasColumn($modelTable, Session::get("crud.$modelTable.sort_col")) or
|
|
|
|
|
in_array(Session::get("crud.$modelTable.sort_col"), [
|
|
|
|
|
'brands.name',
|
|
|
|
|
'customers.email',
|
|
|
|
|
'customer_infos.firstname',
|
|
|
|
|
'customer_infos.lastname',
|
|
|
|
|
'customer_infos.opt_in',
|
|
|
|
|
'customer_logins.last_connection',
|
|
|
|
|
'customer_logins.status'
|
|
|
|
|
]))
|
2021-09-09 15:09:13 +02:00
|
|
|
) {
|
|
|
|
|
$query = $query->orderBy(
|
|
|
|
|
Session::get("crud.$modelTable.sort_col"),
|
|
|
|
|
Session::get("crud.$modelTable.sort_way")
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-15 13:16:51 +02:00
|
|
|
$searchFields = trans('Email, Prénom, Nom');
|
|
|
|
|
|
2021-09-09 15:09:13 +02:00
|
|
|
/** @var \Illuminate\Pagination\AbstractPaginator */
|
2023-06-13 11:05:53 +02:00
|
|
|
$customerModels = $query->paginate(50);
|
2021-09-08 16:43:44 +02:00
|
|
|
|
2023-06-13 11:05:53 +02:00
|
|
|
return view('customers.index', compact(
|
2021-09-08 16:43:44 +02:00
|
|
|
'modelClass',
|
|
|
|
|
'modelTable',
|
2023-06-13 11:05:53 +02:00
|
|
|
'customerModels',
|
2023-06-15 13:16:51 +02:00
|
|
|
'brands',
|
|
|
|
|
'searchFields'
|
2021-09-08 16:43:44 +02:00
|
|
|
));
|
2020-12-01 17:02:10 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-19 15:57:24 +01:00
|
|
|
/**
|
|
|
|
|
* Show a specific custmer
|
|
|
|
|
*
|
2023-06-23 17:18:59 +02:00
|
|
|
* @param \App\Models\Customer $customer
|
|
|
|
|
* @param \App\Models\Brand $brand
|
2021-12-19 15:57:24 +01:00
|
|
|
* @return \Illuminate\Http\Response
|
|
|
|
|
*/
|
2021-07-22 15:14:07 +02:00
|
|
|
public function show(Customer $customer, Brand $brand)
|
2021-02-28 12:04:49 +01:00
|
|
|
{
|
2021-08-04 09:42:48 +02:00
|
|
|
$customerInfos = CustomerInfo::where('customer_id', $customer->id)
|
2021-07-22 15:14:07 +02:00
|
|
|
->where('brand_id', $brand->id)->firstOrFail();
|
|
|
|
|
$customerLogin = CustomerLogin::where('customer_id', $customer->id)
|
|
|
|
|
->where('brand_id', $brand->id)->first();
|
2021-09-08 16:43:44 +02:00
|
|
|
|
2023-06-13 11:05:53 +02:00
|
|
|
return view('customers.show', compact(
|
2021-09-08 16:43:44 +02:00
|
|
|
'customerInfos',
|
|
|
|
|
'customerLogin'
|
|
|
|
|
));
|
2020-12-01 17:02:10 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-19 15:57:24 +01:00
|
|
|
/**
|
|
|
|
|
* Delete a specific customer info
|
|
|
|
|
*
|
2023-06-23 17:18:59 +02:00
|
|
|
* @param \App\Models\Customer $customer
|
|
|
|
|
* @param \App\Models\Brand $brand
|
2021-12-19 15:57:24 +01:00
|
|
|
* @return \Illuminate\Http\RedirectResponse
|
|
|
|
|
*/
|
2021-08-23 20:00:07 +02:00
|
|
|
public function delete(Customer $customer, Brand $brand)
|
2021-08-02 17:22:56 +02:00
|
|
|
{
|
2021-12-19 15:57:24 +01:00
|
|
|
try {
|
|
|
|
|
// TODO: Gestion avec mesBR.
|
|
|
|
|
/** @var \App\Models\CustomerInfo */
|
|
|
|
|
$customerInfo = $customer->info($brand, Customer::FIRST_OR_FAIL);
|
|
|
|
|
/** @var \App\Models\CustomerLogin */
|
|
|
|
|
$customerLogin = $customer->login($brand, Customer::FIRST_OR_FAIL);
|
2021-08-02 17:22:56 +02:00
|
|
|
|
2021-12-19 15:57:24 +01:00
|
|
|
DB::transaction(function () use (
|
|
|
|
|
$brand,
|
|
|
|
|
$customer,
|
|
|
|
|
$customerLogin,
|
|
|
|
|
$customerInfo
|
|
|
|
|
) {
|
|
|
|
|
if (
|
|
|
|
|
$customerInfo->delete() === false ||
|
|
|
|
|
$customerLogin->delete() === false
|
|
|
|
|
) {
|
|
|
|
|
throw new \ErrorException('Api failed to delete customer.');
|
|
|
|
|
};
|
2021-08-02 17:22:56 +02:00
|
|
|
|
2021-12-19 15:57:24 +01:00
|
|
|
$customer->optInHistory()->whereHas('brand', function ($q) use ($brand) {
|
|
|
|
|
$q->where('id', $brand->id);
|
|
|
|
|
})->delete();
|
|
|
|
|
|
|
|
|
|
$logins = $customer->logins()->count();
|
|
|
|
|
$infos = $customer->infos()->count();
|
|
|
|
|
$history = $customer->optInHistory()->count();
|
2021-08-02 17:22:56 +02:00
|
|
|
|
2021-12-19 15:57:24 +01:00
|
|
|
// If customer is not associated with any brand then delete.
|
|
|
|
|
if (!$logins and !$infos and !$history) {
|
|
|
|
|
if ($customer->delete() === false) {
|
|
|
|
|
throw new \ErrorException('Api failed to update customer.');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
} catch (\ErrorException $e) {
|
|
|
|
|
return redirect()->route('customers.index')
|
2023-06-15 12:28:05 +02:00
|
|
|
->with('error', trans('Le compte n\'a pas pu être supprimé.'));
|
2021-12-19 15:57:24 +01:00
|
|
|
} //end try
|
|
|
|
|
|
|
|
|
|
return redirect()->route('customers.index')->with('warning', trans('Compte supprimé.'));
|
2021-08-02 17:22:56 +02:00
|
|
|
}
|
2021-09-09 14:08:59 +02:00
|
|
|
|
2021-12-19 15:57:24 +01:00
|
|
|
/**
|
|
|
|
|
* Show export the customers form
|
|
|
|
|
*
|
|
|
|
|
* @return \Illuminate\Http\Response
|
|
|
|
|
*/
|
2021-09-09 14:08:59 +02:00
|
|
|
public function export()
|
|
|
|
|
{
|
2021-11-03 11:18:19 +01:00
|
|
|
$brands = Brand::all();
|
2023-06-13 11:05:53 +02:00
|
|
|
return view('customers.export', compact(
|
2021-11-03 11:18:19 +01:00
|
|
|
'brands'
|
2021-09-09 14:08:59 +02:00
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-19 15:57:24 +01:00
|
|
|
/**
|
|
|
|
|
* Exports customers following the requested export type
|
|
|
|
|
*
|
2023-06-23 17:18:59 +02:00
|
|
|
* @param \App\Http\Requests\CustomerExport $request
|
2021-12-19 15:57:24 +01:00
|
|
|
* @return \Symfony\Component\HttpFoundation\StreamedResponse
|
|
|
|
|
* @throws \Exception If the request export type in not handled.
|
|
|
|
|
*/
|
2021-09-09 14:08:59 +02:00
|
|
|
public function exportSubmit(CustomerExport $request)
|
|
|
|
|
{
|
|
|
|
|
$pagination = 2000;
|
|
|
|
|
$header = '"lastname";"firstname";"email";"hashcode"';
|
|
|
|
|
|
|
|
|
|
$w = Writer::createFromString($header . PHP_EOL);
|
|
|
|
|
$w->setDelimiter(';');
|
|
|
|
|
$w->setEnclosure('"');
|
|
|
|
|
$w->setOutputBOM(Writer::BOM_UTF8);
|
|
|
|
|
|
|
|
|
|
$exportType = CustomerExportType::make(\intval($request->export_type));
|
|
|
|
|
|
2021-12-19 15:57:24 +01:00
|
|
|
// * We send the CSV using Symfony StreamedResponse.
|
2021-09-09 14:08:59 +02:00
|
|
|
$response = new StreamedResponse();
|
|
|
|
|
$response->headers->set('Content-Encoding', 'none');
|
|
|
|
|
$response->headers->set('Content-Type', 'text/csv; charset=UTF-8');
|
|
|
|
|
$response->headers->set('Description', 'File Transfer');
|
|
|
|
|
$response->headers->set(
|
|
|
|
|
'Content-Disposition',
|
|
|
|
|
sprintf(
|
2021-09-09 16:29:32 +02:00
|
|
|
'attachment; filename="Export pour newsletter %s %s.csv"',
|
2023-06-28 15:47:23 +02:00
|
|
|
Carbon::now()->isoFormat('DD-MM-YYYY_HH-mm'),
|
2021-09-09 14:08:59 +02:00
|
|
|
Str::slug($exportType)
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
switch ($exportType) {
|
|
|
|
|
case CustomerExportType::both():
|
|
|
|
|
$continue = true;
|
2021-12-19 15:57:24 +01:00
|
|
|
// ! Continue
|
2021-09-09 14:08:59 +02:00
|
|
|
case CustomerExportType::customer():
|
2021-10-25 17:37:31 +02:00
|
|
|
$page = 1;
|
2021-09-09 14:08:59 +02:00
|
|
|
/** @var \Illuminate\Database\Eloquent\Builder $req */
|
2021-11-08 16:01:45 +01:00
|
|
|
$req = CustomerInfo::where('brand_id', $request->brand)
|
|
|
|
|
->where('opt_in', true);
|
2021-09-09 14:08:59 +02:00
|
|
|
$total = $req->count();
|
2021-10-25 17:37:31 +02:00
|
|
|
$pages = \ceil($total / $pagination);
|
2021-09-09 14:08:59 +02:00
|
|
|
do {
|
|
|
|
|
/** @var \Illuminate\Pagination\LengthAwarePaginator $items */
|
|
|
|
|
$items = $req->with('customer', function ($q) {
|
|
|
|
|
$q->select(['id', 'email']);
|
|
|
|
|
})->paginate(
|
|
|
|
|
$pagination,
|
|
|
|
|
['lastname', 'firstname', 'hashcode', 'customer_id'],
|
|
|
|
|
'page',
|
2021-10-25 17:37:31 +02:00
|
|
|
$page
|
2021-09-09 14:08:59 +02:00
|
|
|
);
|
|
|
|
|
$items->map(function (CustomerInfo $customerInfo) use ($w) {
|
|
|
|
|
$w->insertOne([
|
|
|
|
|
'lastname' => $customerInfo->lastname,
|
|
|
|
|
'firstname' => $customerInfo->firstname,
|
|
|
|
|
'email' => $customerInfo->customer->email,
|
|
|
|
|
'hashcode' => $customerInfo->hashcode
|
|
|
|
|
]);
|
|
|
|
|
});
|
2021-10-25 17:37:31 +02:00
|
|
|
} while ($page++ <= $pages);
|
2021-09-09 14:08:59 +02:00
|
|
|
if (!isset($continue)) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
2021-12-19 15:57:24 +01:00
|
|
|
// ! Continue
|
2021-09-09 14:08:59 +02:00
|
|
|
case CustomerExportType::singleOptin():
|
2023-06-26 15:10:28 +02:00
|
|
|
SingleOptin::query()->whereHas('brand', function (Builder $q) use ($request) {
|
|
|
|
|
$q->where('id', $request->brand);
|
|
|
|
|
})->get()->map(function (SingleOptin $singleOptin) use ($w) {
|
|
|
|
|
$w->insertOne([
|
|
|
|
|
'lastname' => '',
|
|
|
|
|
'firstname' => '',
|
|
|
|
|
'email' => $singleOptin->email,
|
|
|
|
|
'hashcode' => $singleOptin->hashcode
|
|
|
|
|
]);
|
|
|
|
|
});
|
2021-09-09 14:08:59 +02:00
|
|
|
break;
|
2021-10-25 17:37:31 +02:00
|
|
|
default:
|
2021-12-19 15:57:24 +01:00
|
|
|
throw new \Exception(sprintf('Unhandled CustomerExportType %s', $exportType->label));
|
|
|
|
|
} //end switch
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
We create a callable to output the CSV in chunk
|
|
|
|
|
with Symfony StreamResponse you can flush the body content if necessary
|
|
|
|
|
see Symfony documentation for more information
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
// * The flush value should depend on your CSV size.
|
|
|
|
|
$flush_threshold = 1000;
|
2021-09-09 14:08:59 +02:00
|
|
|
|
|
|
|
|
$response->setCallback(function () use ($w, $flush_threshold) {
|
|
|
|
|
foreach ($w->chunk(1024) as $offset => $chunk) {
|
|
|
|
|
echo $chunk;
|
|
|
|
|
if ($offset % $flush_threshold === 0) {
|
|
|
|
|
flush();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
return $response;
|
|
|
|
|
}
|
2020-12-01 17:02:10 +01:00
|
|
|
}
|