Compare commits
28 Commits
aee6d9440c
...
cfea605fc1
| Author | SHA1 | Date |
|---|---|---|
|
|
cfea605fc1 | 1 year ago |
|
|
e2ab453d66 | 1 year ago |
|
|
2ed57016bc | 1 year ago |
|
|
3ff470bc55 | 1 year ago |
|
|
3322055ac5 | 1 year ago |
|
|
163d5a0486 | 1 year ago |
|
|
56384c1fa9 | 1 year ago |
|
|
b82fb64dd3 | 1 year ago |
|
|
22f99b29fa | 1 year ago |
|
|
52b7e91405 | 1 year ago |
|
|
eee7c263ab | 1 year ago |
|
|
d50cde1189 | 1 year ago |
|
|
9ae7e9f7b3 | 1 year ago |
|
|
363f11136e | 1 year ago |
|
|
b6e3edecde | 2 years ago |
|
|
2c1a415979 | 2 years ago |
|
|
158106c758 | 2 years ago |
|
|
d947df81d3 | 2 years ago |
|
|
7118fea237 | 2 years ago |
|
|
d1c4f39591 | 2 years ago |
|
|
e2e6c2b6f8 | 2 years ago |
|
|
cbbe612658 | 2 years ago |
|
|
5e46b20720 | 2 years ago |
|
|
4b56d762f6 | 2 years ago |
|
|
fb281607d1 | 2 years ago |
|
|
546df1abf6 | 2 years ago |
|
|
2a7a0b32f3 | 2 years ago |
|
|
4bde317a23 | 2 years ago |
@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Helper\Sts\Indokargo;
|
||||
use App\Models\StsLog;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class StsReschedule extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'sts:reschedule';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Resschedule failed sts to sts data';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle(): void {
|
||||
$sleep = 30; // 30 second
|
||||
while(true) {
|
||||
$this->info('---------------------------');
|
||||
$this->info('reschedule sts:' . Carbon::now()->toDateTimeString());
|
||||
$this->info('---------------------------');
|
||||
|
||||
// get reschedu;e sts logs
|
||||
$success = 0;
|
||||
$failed = 0;
|
||||
$rescheduleStsLogs = StsLog::where(['is_retry' => true])->get();
|
||||
foreach($rescheduleStsLogs as $rescheduleStsLog) {
|
||||
try {
|
||||
$partner = $rescheduleStsLog->partner;
|
||||
$module = $rescheduleStsLog->module;
|
||||
$serviceName = $rescheduleStsLog->service_name;
|
||||
$request = new Request((array) $rescheduleStsLog->request_data ?? []);
|
||||
$localId = $rescheduleStsLog->local_id;
|
||||
$partnerId = $rescheduleStsLog->partner_id;
|
||||
$lastSeq = $rescheduleStsLog->seq;
|
||||
|
||||
if($partner == StsLog::PARTNER_INDOKARGO) {
|
||||
if($module == StsLog::MODULE_TV) {
|
||||
if($serviceName == StsLog::SERVICE_CREATE_TV_ADDRESS) {
|
||||
Indokargo::createTVAddress($request, $localId, $lastSeq);
|
||||
} else if($serviceName == StsLog::SERVICE_UPDATE_TV_ADDRESS) {
|
||||
Indokargo::updateTVAddress($request, $localId, $partnerId, $lastSeq);
|
||||
} else if($serviceName == StsLog::SERVICE_CHANGE_STATUS_TV_ADDRESS) {
|
||||
Indokargo::changeStatusAddress($request, $localId, $partnerId, $lastSeq);
|
||||
} else {
|
||||
throw new \Exception("Service name '$partner' > '$module' > '$serviceName' not found service");
|
||||
}
|
||||
} else {
|
||||
throw new \Exception("Module name '$partner' > '$module' not found service");
|
||||
}
|
||||
} else {
|
||||
throw new \Exception("Partner name '$partner' not found service");
|
||||
}
|
||||
$success++;
|
||||
} catch(\Throwable $th) {
|
||||
$failed++;
|
||||
$this->info("stsLog id: ". $rescheduleStsLog->id . " => " . $th->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// save all retry request is retry false
|
||||
$rescheduleStsLogIds = $rescheduleStsLogs->pluck('id')->toArray();
|
||||
StsLog::whereIn('id', $rescheduleStsLogIds)->update(['is_retry' => false]);
|
||||
|
||||
$this->info('---------------------------');
|
||||
$this->info("result: $success success, $failed failed" );
|
||||
$this->info("Sleep in $sleep seconds" );
|
||||
$this->info('---------------------------');
|
||||
sleep($sleep);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
<?php
|
||||
namespace App\Helper\Frontend;
|
||||
|
||||
use App\Helper\JSONResponse;
|
||||
use App\Models\Tv;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
/**
|
||||
* Note:
|
||||
* if any of frontend component need specific api query / data specific.
|
||||
* Please add function to get data here.
|
||||
*
|
||||
* But, if the parent component still needs to pass the url to the
|
||||
* child component, the url api can be placed in the app/Http/Controllers/api/superadmin/GeneralController
|
||||
*/
|
||||
|
||||
class ApiUtilities {
|
||||
|
||||
// for components/app/tv/button/excel.vue
|
||||
public static function tvExcel(Request $request) {
|
||||
$request->validate(['a' => 'nullable|string']);
|
||||
|
||||
switch($request->a) {
|
||||
case 'excelTemplate':
|
||||
return Tv::getExcelTemplate();
|
||||
break;
|
||||
case 'validateData':
|
||||
$tvCodes = $request->tvCodes ?? [];
|
||||
$tvs = $request->tvs ?? [];
|
||||
$oValidation = TV::validateExcel($tvs, $tvCodes);
|
||||
return JSONResponse::Success(['oValidation' => $oValidation]);
|
||||
break;
|
||||
case 'uploadExcel':
|
||||
$tvCodes = $request->tvCodes ?? [];
|
||||
$tvs = $request->tvs ?? [];
|
||||
$oValidation = TV::validateExcel($tvs, $tvCodes);
|
||||
$result = TV::uploadExcel($tvs, $oValidation, $request->user());
|
||||
return JSONResponse::Success($result);
|
||||
break;
|
||||
case 'exportData':
|
||||
return Tv::getExportData($request);
|
||||
break;
|
||||
case 'excelDetail':
|
||||
return Tv::getExcelDetail($request);
|
||||
break;
|
||||
|
||||
}
|
||||
throw new \Exception('Invalid Request Command');
|
||||
}
|
||||
}
|
||||
?>
|
||||
@ -0,0 +1,180 @@
|
||||
<?php
|
||||
namespace App\Helper\STS;
|
||||
|
||||
use App\Helper\JSONResponse;
|
||||
use App\Models\StsLog;
|
||||
use App\Models\Tv;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Client\ConnectionException;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
class Indokargo {
|
||||
const STATUS_SUCCESS = 'Success';
|
||||
const STATUS_FAILURE = 'Failure';
|
||||
// const STATUS_WARNING = 'Warning';
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
//-- UTILITIES
|
||||
private static function _checkIkResponse($res) {
|
||||
$status = $res['status'];
|
||||
if($res['status'] == self::STATUS_SUCCESS) return;
|
||||
else if($res['status'] == self::STATUS_FAILURE) {
|
||||
// note: Indokargo error message can be array or string
|
||||
$errorMessage = $res['error']['error_message'];
|
||||
if(is_array($errorMessage)) throw ValidationException::withMessages($errorMessage);
|
||||
else throw new \Exception($errorMessage);
|
||||
}
|
||||
else {
|
||||
throw new \Exception("Indokargo status is not valid (ik status = $status)" );
|
||||
}
|
||||
}
|
||||
private static function _HttpTransaction(StsLog $stsLog, $callback) {
|
||||
try {
|
||||
return $callback();
|
||||
} catch(ConnectionException $e) {
|
||||
// if error cause by connection error, try again later
|
||||
$stsLog->error_info = [
|
||||
'message' => $e->getMessage(),
|
||||
'errors' => $e->getTrace()
|
||||
];
|
||||
$stsLog->result = StsLog::STATUS_FAILED;
|
||||
$stsLog->is_retry = true;
|
||||
$stsLog->save();
|
||||
return JSONResponse::Success(['is_warning' => true,
|
||||
'message' => "Failed to sync data with indokargo data, don't worry, we will sync data later"]);
|
||||
} catch(\Throwable $th) {
|
||||
DB::rollBack();
|
||||
$stsLog->error_info = [
|
||||
'message' => $th->getMessage(),
|
||||
'errors' => $th->getTrace()
|
||||
];
|
||||
$stsLog->result = StsLog::STATUS_FAILED;
|
||||
$stsLog->save();
|
||||
throw $th;
|
||||
}
|
||||
}
|
||||
//-- END UTILITIES
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
public static function createTVAddress(Request $request, int $tvFk, int $lastSeq = 0) {
|
||||
$seq = $lastSeq + 1;
|
||||
|
||||
/**
|
||||
* local id = TV FK, partnerId = ik_address_id
|
||||
* Why not new tv request id as local_id?
|
||||
* - New Tv request data will be deleted after TV data is inserted into the local DB
|
||||
*/
|
||||
$stsLog = new StsLog();
|
||||
$stsLog->partner = StsLog::PARTNER_INDOKARGO;
|
||||
$stsLog->is_outgoing = true;
|
||||
$stsLog->module = StsLog::MODULE_TV;
|
||||
$stsLog->service_name = StsLog::SERVICE_CREATE_TV_ADDRESS;
|
||||
$stsLog->local_id = $tvFk;
|
||||
$stsLog->partner_id = null;
|
||||
$stsLog->seq = $seq;
|
||||
$stsLog->request_data = $request->all();
|
||||
$stsLog->request_time = Carbon::now();
|
||||
|
||||
return self::_HttpTransaction($stsLog, function() use($tvFk, $request, $stsLog) {
|
||||
$request->validate(['code' => 'required|string']);
|
||||
|
||||
$result = Http::indokargo()->post('tv/address/create', $request->all());
|
||||
$res = $result->throw()->json();
|
||||
|
||||
// update stsLog
|
||||
$stsLog->response_data = $res;
|
||||
$stsLog->response_time = Carbon::now();
|
||||
|
||||
self::_checkIkResponse($res);
|
||||
|
||||
$ikAddress = $res['data']['0'];
|
||||
$ikAddressId = $ikAddress['id'];
|
||||
$stsLog->partner_id = $ikAddressId;
|
||||
|
||||
// check ik address id is exist (almost impossible to happen, 0.01%)
|
||||
$isDuplicateIkAddressId = TV::where([
|
||||
['ik_address_id', '=', $ikAddressId],
|
||||
['id', '!=', $tvFk]
|
||||
])->first();
|
||||
if($isDuplicateIkAddressId) throw new \Exception("IK Address ID Already exist in current db ($ikAddressId)");
|
||||
|
||||
DB::beginTransaction();
|
||||
$tv = Tv::findOrFail($tvFk);
|
||||
$tv->ik_address_id = $ikAddressId;
|
||||
$tv->save();
|
||||
|
||||
$stsLog->result = StsLog::STATUS_SUCCESS;
|
||||
$stsLog->save();
|
||||
DB::commit();
|
||||
return JSONResponse::Success(['is_warning' => false, 'message' => 'Success To Save Data']);
|
||||
});
|
||||
}
|
||||
|
||||
public static function updateTVAddress(Request $request, int $tvFk, String $ikAddressId, int $lastSeq = 0) {
|
||||
$seq = $lastSeq + 1;
|
||||
|
||||
$request->merge(['ik_address_id' => $ikAddressId]);
|
||||
$stsLog = new StsLog();
|
||||
$stsLog->partner = StsLog::PARTNER_INDOKARGO;
|
||||
$stsLog->is_outgoing = true;
|
||||
$stsLog->module = StsLog::MODULE_TV;
|
||||
$stsLog->service_name = StsLog::SERVICE_UPDATE_TV_ADDRESS;
|
||||
$stsLog->local_id = $tvFk;
|
||||
$stsLog->partner_id = $ikAddressId;
|
||||
$stsLog->seq = $seq;
|
||||
$stsLog->request_data = $request->all();
|
||||
$stsLog->request_time = Carbon::now();
|
||||
|
||||
return self::_HttpTransaction($stsLog, function() use($stsLog, $request) {
|
||||
$request->validate(['code' => 'required|string', 'ik_address_id' => 'required|string']);
|
||||
$result = Http::indokargo()->post('tv/address/update-tv', $request->all());
|
||||
$res = $result->throw()->json();
|
||||
|
||||
// update stsLog
|
||||
$stsLog->response_data = $res;
|
||||
$stsLog->response_time = Carbon::now();
|
||||
self::_checkIkResponse($res);
|
||||
$stsLog->result = StsLog::STATUS_SUCCESS;
|
||||
$stsLog->save();
|
||||
DB::commit();
|
||||
return JSONResponse::Success(['message' => "Success to save data"]);
|
||||
});
|
||||
}
|
||||
|
||||
public static function changeStatusAddress(Request $request, int $tvFk, String $ikAddressId, int $lastSeq = 0) {
|
||||
$seq = $lastSeq + 1;
|
||||
|
||||
$request->merge(['ik_address_id' => $ikAddressId]);
|
||||
$stsLog = new StsLog();
|
||||
$stsLog->partner = StsLog::PARTNER_INDOKARGO;
|
||||
$stsLog->is_outgoing = true;
|
||||
$stsLog->module = StsLog::MODULE_TV;
|
||||
$stsLog->service_name = StsLog::SERVICE_CHANGE_STATUS_TV_ADDRESS;
|
||||
$stsLog->local_id = $tvFk;
|
||||
$stsLog->partner_id = $request->ik_address_id;
|
||||
$stsLog->seq = $seq;
|
||||
$stsLog->request_data = $request->all();
|
||||
$stsLog->request_time = Carbon::now();
|
||||
|
||||
return self::_HttpTransaction($stsLog, function() use($stsLog, $request) {
|
||||
$request->validate(['ik_address_id' => 'required|string', 'is_active'=> 'required|boolean']);
|
||||
$result = Http::indokargo()->post('tv/address/change-status', $request->all());
|
||||
$res = $result->throw()->json();
|
||||
|
||||
// update stsLog
|
||||
$stsLog->response_data = $res;
|
||||
$stsLog->response_time = Carbon::now();
|
||||
self::_checkIkResponse($res);
|
||||
$stsLog->result = StsLog::STATUS_SUCCESS;
|
||||
$stsLog->save();
|
||||
DB::commit();
|
||||
|
||||
return JSONResponse::Success(['is_warning' => false, 'message' => 'Success To Change Status']);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\api\mobile;
|
||||
|
||||
use App\Helper\JSONResponse;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\ApkUpdate;
|
||||
use App\Models\NewTvRequest;
|
||||
use App\Models\Tv;
|
||||
use App\Models\VideoUpdate;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class TvController extends Controller {
|
||||
public function newRequest(Request $request) {
|
||||
return NewTvRequest::checkOrCreateFromRequest($request);
|
||||
}
|
||||
|
||||
public function checkUpdate(Request $request) {
|
||||
$request->validate(['id' => 'nullable|integer',
|
||||
'apk_version_code' => 'required|integer',
|
||||
'apk_version_name' => 'required|string']);
|
||||
|
||||
$tv = null;
|
||||
$latestApkUpdate = null;
|
||||
$latestVideoUpdate = null;
|
||||
if($request->id) {
|
||||
$tv = Tv::find($request->id);
|
||||
$tv->last_connected_at = now();
|
||||
$tv->apk_version_code = $request->apk_version_code;
|
||||
$tv->apk_version_name = $request->apk_version_name;
|
||||
$tv->save();
|
||||
$latestApkUpdate = ApkUpdate::getLatest();
|
||||
$latestVideoUpdate = VideoUpdate::getLatestSelected();
|
||||
}
|
||||
|
||||
return JSONResponse::Success(['tv' => $tv, 'latestApkUpdate' => $latestApkUpdate, 'latestVideoUpdate' => $latestVideoUpdate]);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\api\superadmin;
|
||||
|
||||
use App\Helper\JSONResponse;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Tv;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class GeneralController extends Controller {
|
||||
public function tvSearch(Request $request) {
|
||||
$request->validate(['search' => 'nullable|string']);
|
||||
$tvs = Tv::multiSearch($request->search, ['code'])->orderBy('code', 'asc')->limit(10)->get();
|
||||
return JSONResponse::Success(['tvs' => $tvs ]);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\api\superadmin\tv;
|
||||
|
||||
use App\Helper\DatabaseHelper;
|
||||
use App\Helper\JSONResponse;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\NewTvRequest;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class NewTvRequestController extends Controller {
|
||||
public function init(Request $request) {
|
||||
NewTvRequest::deleteExpiredRequests();
|
||||
$request->validate([
|
||||
'perPage' => 'nullable|integer|min:1',
|
||||
...DatabaseHelper::getOrderBysValidations(),
|
||||
'search' => DatabaseHelper::getSearchValidation()
|
||||
]);
|
||||
|
||||
$newTvRequests = NewTvRequest::with('tv')
|
||||
->addColumnCanApprove()
|
||||
->addColumnCanReject()
|
||||
->multiSearch($request->search, ['code'])
|
||||
->multiOrderBy($request->orderBys, 'created_at desc')
|
||||
->paginate($request->perPage ?? 10);
|
||||
|
||||
return JSONResponse::Success(['data' => $newTvRequests ]);
|
||||
}
|
||||
|
||||
public function approve(Request $request) { return NewTvRequest::approveFromRequest($request); }
|
||||
public function reject(Request $request) { return NewTvRequest::rejectFromRequest($request); }
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\api\superadmin\tv;
|
||||
|
||||
use App\Helper\DatabaseHelper;
|
||||
use App\Helper\Frontend\ApiUtilities;
|
||||
use App\Helper\JSONResponse;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\ApkUpdate;
|
||||
use App\Models\Tv;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class TvController extends Controller {
|
||||
public function init(Request $request) {
|
||||
$request->validate([
|
||||
'perPage' => 'nullable|integer|min:1',
|
||||
'isFirstTime' => 'nullable|boolean',
|
||||
]);
|
||||
|
||||
$additionalData = [];
|
||||
if($request->isFirstTime) {
|
||||
$additionalData['apkUpdates'] = ApkUpdate::select('version_code', 'version_name')
|
||||
->orderBy('version_code', 'desc')
|
||||
->get();
|
||||
}
|
||||
$newTvRequests = TV::validateAndGetEloquentFromRequest($request)->paginate($request->perPage ?? 10);
|
||||
return JSONResponse::Success(['data' => $newTvRequests, ...$additionalData ]);
|
||||
}
|
||||
|
||||
public function excel(Request $request) { return ApiUtilities::tvExcel($request); }
|
||||
public function update(Request $request) { return Tv::updateFromRequest($request); }
|
||||
public function changeStatus(Request $request) { return Tv::changeStatusFromRequest($request); }
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class TvAppInfo extends Model {
|
||||
use HasFactory;
|
||||
|
||||
protected $table = 'tv_app_infos';
|
||||
protected $primaryKey = 'tv_fk';
|
||||
public $incrementing = false;
|
||||
|
||||
//------------------------------------------------------------
|
||||
// -- RELATED TO RELATIONSHIP
|
||||
/// BELONGS TO
|
||||
public function tv(): BelongsTo { return $this->belongsTo(Tv::class, 'tv_fk', 'id'); }
|
||||
// -- END RELATED TO RELATIONSHIP
|
||||
//------------------------------------------------------------
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class TvConnectLog extends Model {
|
||||
use HasFactory;
|
||||
|
||||
//------------------------------------------------------------
|
||||
// -- RELATED TO RELATIONSHIP
|
||||
/// BELONGS TO
|
||||
public function tv(): BelongsTo { return $this->belongsTo(Tv::class, 'tv_fk', 'id'); }
|
||||
// -- END RELATED TO RELATIONSHIP
|
||||
//------------------------------------------------------------
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class TvSession extends Model {
|
||||
use HasFactory;
|
||||
|
||||
//------------------------------------------------------------
|
||||
// -- RELATED TO RELATIONSHIP
|
||||
/// BELONGS TO
|
||||
public function tv(): BelongsTo { return $this->belongsTo(Tv::class, 'tv_fk', 'id'); }
|
||||
// -- END RELATED TO RELATIONSHIP
|
||||
//------------------------------------------------------------
|
||||
}
|
||||
@ -0,0 +1,225 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Helper\JSONResponse;
|
||||
use App\Helper\STS\Indokargo;
|
||||
use App\Helper\Traits\Models\CanMultiOrderBy;
|
||||
use App\Helper\Traits\Models\CanMultiSearch;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Casts\AsArrayObject;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class NewTvRequest extends Model {
|
||||
use HasFactory;
|
||||
use CanMultiSearch;
|
||||
use CanMultiOrderBy;
|
||||
|
||||
protected $table = 'new_tv_requests';
|
||||
protected $casts = ['device_info'=>AsArrayObject::class];
|
||||
|
||||
//------------------------------------------------------------
|
||||
// -- RELATED TO RELATIONSHIP
|
||||
// HAS ONE
|
||||
public function self(): HasOne { return $this->hasOne(self::class, 'id', 'id'); }
|
||||
/// BELONGS TO
|
||||
public function tv(): BelongsTo { return $this->belongsTo(Tv::class, 'tv_fk', 'id'); }
|
||||
// -- END RELATED TO RELATIONSHIP
|
||||
//------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------
|
||||
// -- RELATED TO SCOPE
|
||||
public function scopeAddColumnCanApprove(Builder $query) {
|
||||
$query->withCount(['self as can_approve' => function($q) {
|
||||
$q->whereNull('approved_at');
|
||||
}]);
|
||||
}
|
||||
public function scopeAddColumnCanReject(Builder $query) {
|
||||
$query->withCount(['self as can_reject' => function($q) {
|
||||
$q->whereNull('approved_at');
|
||||
}]);
|
||||
}
|
||||
// -- END RELATED TO SCOPE
|
||||
//------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------
|
||||
// -- RELATED TO DATA FUNCTION
|
||||
private static function _generateRandomCode(): string {
|
||||
$totalDigit = 6;
|
||||
$randomDigit = '';
|
||||
while(true) {
|
||||
$randomDigit = strtoupper(Str::random($totalDigit));
|
||||
$isExist = NewTvRequest::where('code', $randomDigit)->first();
|
||||
if(!$isExist) break;
|
||||
}
|
||||
return $randomDigit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rule:
|
||||
* 1. if it has not been approved for more than the expiry date, deleted it
|
||||
* 2. if it has been approved & has been responded more than expiry date, delete it
|
||||
* - case: when has been approved, but intenet connection missing, how can device know
|
||||
* that the new request tv has been approved?
|
||||
*/
|
||||
private static function _getMaxExpiredTime() :Carbon { return Carbon::now()->subHour(); }
|
||||
public static function deleteExpiredRequests() {
|
||||
$expiredTime = self::_getMaxExpiredTime()->toDateTimeString();
|
||||
NewTvRequest::where(function($q) use ($expiredTime) {
|
||||
$q->whereNull('approved_at')->where('created_at', '<=', $expiredTime);
|
||||
})->orWhere(function($q) use ($expiredTime) {
|
||||
$q->where('responded_at', '<=', $expiredTime );
|
||||
})->delete();
|
||||
}
|
||||
// -- END RELATED TO DATA FUNCTION
|
||||
//------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------
|
||||
// -- RELATED TO FROM REQUEST FUNCTION
|
||||
private static function _checkOrCreateResponse(NewTvRequest $newTvReq) {
|
||||
if($newTvReq->approved_at) {
|
||||
// make sure waiting tv_device responded before deleted
|
||||
if(empty($newTvReq->responded_at)) {
|
||||
$newTvReq->responded_at = now();
|
||||
$newTvReq->save();
|
||||
}
|
||||
|
||||
return JSONResponse::Success([
|
||||
'message' => 'approved',
|
||||
'new_tv_request' => $newTvReq,
|
||||
'tv' => $newTvReq->tv
|
||||
]);
|
||||
}
|
||||
|
||||
return JSONResponse::Success([
|
||||
'message' => 'not activate',
|
||||
'new_tv_request' => $newTvReq,
|
||||
'tv' => null
|
||||
]);
|
||||
}
|
||||
public static function checkOrCreateFromRequest(Request $request) {
|
||||
$request->validate([
|
||||
'id' => 'nullable|string|required_with:code|integer',
|
||||
'code' => 'nullable|string|required_with:id',
|
||||
'device_info' => 'required|array'
|
||||
]);
|
||||
|
||||
if(!empty($request->id)) {
|
||||
$checkTvReq = NewTvRequest::where('code', $request->code)->find($request->id);
|
||||
if($checkTvReq) return self::_checkOrCreateResponse($checkTvReq);
|
||||
}
|
||||
|
||||
$newTvReq = new self;
|
||||
$newTvReq->code = self::_generateRandomCode();
|
||||
$newTvReq->device_info = $request->device_info;
|
||||
$newTvReq->save();
|
||||
return self::_checkOrCreateResponse($newTvReq);
|
||||
}
|
||||
|
||||
public static function approveFromRequest(Request $request) {
|
||||
$request->validate([
|
||||
'id' => 'required|integer|exists:App\Models\NewTvRequest',
|
||||
'tv' => 'nullable|array',
|
||||
'existingTv' => 'nullable|array',
|
||||
'action' => 'required|string',
|
||||
]);
|
||||
|
||||
$newTvReq = NewTvRequest::addColumnCanApprove()
|
||||
->findOrFail($request->id);
|
||||
if(!$newTvReq->can_approve) throw new \Exception('Cannot approve current request');
|
||||
|
||||
try {
|
||||
$tv = null;
|
||||
if($request->action == 'existing') {
|
||||
$existingTvRequest = new Request($request->existingTv);
|
||||
$existingTvRequest->validate([
|
||||
'id' => 'required|integer|exists:App\Models\Tv',
|
||||
]);
|
||||
|
||||
$tv = TV::findOrFail($existingTvRequest->id);
|
||||
} else if ($request->action == 'new') {
|
||||
$tvRequest = new Request($request->tv);
|
||||
if($tvRequest->code) $tvRequest->merge(['code' => strtoupper($tvRequest->code)]);
|
||||
|
||||
$tvRequest->validate([
|
||||
'company_name' => 'nullable|string',
|
||||
'address' => 'nullable|string',
|
||||
'street_address' => 'nullable|string',
|
||||
'col1' => 'nullable|string',
|
||||
'col2' => 'nullable|string',
|
||||
'col3' => 'nullable|string',
|
||||
'col4' => 'nullable|string',
|
||||
'col5' => 'nullable|string',
|
||||
'col6' => 'nullable|string',
|
||||
'col7' => 'nullable|string',
|
||||
'col8' => 'nullable|string',
|
||||
'col9' => 'nullable|string',
|
||||
'col10' => 'nullable|string',
|
||||
'notes' => 'nullable|string',
|
||||
]);
|
||||
|
||||
DB::beginTransaction();
|
||||
$tv = new Tv();
|
||||
$tv->code = TV::generateUniqueCode();
|
||||
$tv->company_name = $tvRequest->company_name;
|
||||
$tv->address = $tvRequest->address;
|
||||
$tv->street_address = $tvRequest->street_address;
|
||||
$tv->col1 = $tvRequest->col1;
|
||||
$tv->col2 = $tvRequest->col2;
|
||||
$tv->col3 = $tvRequest->col3;
|
||||
$tv->col4 = $tvRequest->col4;
|
||||
$tv->col5 = $tvRequest->col5;
|
||||
$tv->col6 = $tvRequest->col6;
|
||||
$tv->col7 = $tvRequest->col7;
|
||||
$tv->col8 = $tvRequest->col8;
|
||||
$tv->col9 = $tvRequest->col9;
|
||||
$tv->col10 = $tvRequest->col10;
|
||||
$tv->notes = $tvRequest->notes;
|
||||
$tv->device_info = $newTvReq->device_info;
|
||||
$tv->installed_at = now();
|
||||
$tv->save();
|
||||
TVLog::historyCreate($request->user(), $tv->id, $tv);
|
||||
|
||||
// TODO: waiting execution until update from ops
|
||||
// NEED TO REFACTOR (cause by add existing tv code)
|
||||
// // try to sys_to_sys with indokargo
|
||||
// DB::commit();
|
||||
// $jsonResponse = Indokargo::createTVAddress($tvRequest, $tv->id);
|
||||
// return $jsonResponse;
|
||||
} else {
|
||||
throw new \Exception('INVALID FORM ACTION');
|
||||
}
|
||||
|
||||
$newTvReq->approved_at = now();
|
||||
$newTvReq->tv_fk = $tv->id;
|
||||
$newTvReq->save();
|
||||
|
||||
DB::commit();
|
||||
return JSONResponse::Success(['message'=>'Success to approve new tv request']);
|
||||
} catch(\Throwable $th) {
|
||||
DB::rollback();
|
||||
throw $th;
|
||||
}
|
||||
}
|
||||
|
||||
public static function rejectFromRequest(Request $request) {
|
||||
$request->validate([
|
||||
'id' => 'required|integer|exists:App\Models\NewTvRequest',
|
||||
]);
|
||||
$newTvRequest = NewTvRequest::addColumnCanReject()
|
||||
->findOrFail($request->id);
|
||||
if(!$newTvRequest->can_reject) throw new \Exception('Cannot reject current request');
|
||||
$newTvRequest->delete();
|
||||
|
||||
return JSONResponse::Success(['data' => $newTvRequest ]);
|
||||
}
|
||||
// -- END RELATED TO FROM REQUEST FUNCTION
|
||||
//------------------------------------------------------------
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||
|
||||
class Outlet extends Model {
|
||||
use HasFactory;
|
||||
|
||||
protected $table = 'outlets';
|
||||
|
||||
//------------------------------------------------------------
|
||||
// -- RELATED TO MIGRATION
|
||||
/// HAS ONE
|
||||
public function tv_app_info(): HasOne { return $this->hasOne(Tv::class, 'outlet_fk', 'id'); }
|
||||
// -- END RELATED TO MIGRATION2
|
||||
//------------------------------------------------------------
|
||||
}
|
||||
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Casts\AsArrayObject;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class StsLog extends Model {
|
||||
use HasFactory;
|
||||
|
||||
protected $table = 'sts_logs';
|
||||
|
||||
protected $fillable = [
|
||||
'partner',
|
||||
'is_outgoing',
|
||||
'module',
|
||||
'service_name',
|
||||
'local_id',
|
||||
'partner_id',
|
||||
'seq',
|
||||
'result',
|
||||
'error_info',
|
||||
'request_data',
|
||||
'request_time',
|
||||
'response_data',
|
||||
'response_time',
|
||||
'is_retry',
|
||||
'created_at',
|
||||
'updated_at'
|
||||
];
|
||||
protected $casts = [
|
||||
'error_info' => AsArrayObject::class,
|
||||
'request_data' => AsArrayObject::class,
|
||||
'response_data' => AsArrayObject::class,
|
||||
];
|
||||
|
||||
const STATUS_SUCCESS = 'success';
|
||||
const STATUS_FAILED = 'failed';
|
||||
const STATUS_WARNING = 'warning';
|
||||
|
||||
const PARTNER_INDOKARGO = 'indokargo';
|
||||
|
||||
// related to indokargo
|
||||
const MODULE_TV = 'tv';
|
||||
const SERVICE_CREATE_TV_ADDRESS = 'create-tv-address';
|
||||
const SERVICE_UPDATE_TV_ADDRESS = 'update-tv-address';
|
||||
const SERVICE_CHANGE_STATUS_TV_ADDRESS = 'change-statustv-address';
|
||||
}
|
||||
@ -0,0 +1,372 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Helper\Common;
|
||||
use App\Helper\DatabaseHelper;
|
||||
use App\Helper\JSONResponse;
|
||||
use App\Helper\STS\Indokargo;
|
||||
use App\Helper\Traits\Models\CanMultiOrderBy;
|
||||
use App\Helper\Traits\Models\CanMultiSearch;
|
||||
use Illuminate\Database\Eloquent\Casts\AsArrayObject;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
class Tv extends Model {
|
||||
use HasFactory;
|
||||
use CanMultiSearch;
|
||||
use CanMultiOrderBy;
|
||||
|
||||
protected $table = 'tvs';
|
||||
protected $hidden = ['ik_cust_id', 'ik_address_id'];
|
||||
protected $casts = ['device_info'=>AsArrayObject::class];
|
||||
|
||||
//------------------------------------------------------------
|
||||
// -- RELATED TO RELATIONSHIP
|
||||
/// HAS ONE
|
||||
public function new_tv_request(): HasOne { return $this->hasOne(NewTvRequest::class, 'tv_fk', 'id'); }
|
||||
public function tv_app_info(): HasOne { return $this->hasOne(TvAppInfo::class, 'tv_fk', 'id'); }
|
||||
/// HAS MANY
|
||||
public function tv_connect_logs(): HasMany { return $this->hasMany(TvConnectLog::class, 'tv_fk', 'id'); }
|
||||
public function tv_sessions(): HasMany { return $this->hasMany(TvSession::class, 'tv_fk', 'id'); }
|
||||
/// BELONGS TO
|
||||
public function outlet(): BelongsTo { return $this->belongsTo(Outlet::class, 'outlet_fk', 'id'); }
|
||||
// -- END RELATED TO RELATIONSHIP
|
||||
//------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------
|
||||
// -- RELATED TO DATA FUNCTION
|
||||
public static function generateUniqueCode() {
|
||||
// init
|
||||
$countSuffixDigit = 5;
|
||||
date_default_timezone_set('Asia/Jakarta');
|
||||
$prefixCode = 'TV' . date('Ym');
|
||||
|
||||
// try to get unique suffix
|
||||
$uniqueCode = '';
|
||||
while(true) {
|
||||
$suffixCode = strtoupper(Str::random($countSuffixDigit));
|
||||
$uniqueCode = $prefixCode . $suffixCode;
|
||||
$isUnique = TV::where('code', $uniqueCode)->first();
|
||||
if(!$isUnique) break;
|
||||
}
|
||||
return $uniqueCode;
|
||||
}
|
||||
// -- END RELATED TO DATA FUNCTION
|
||||
//------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------
|
||||
// -- RELATED TO REQUEST
|
||||
public static function validateAndGetEloquentFromRequest(Request $request) {
|
||||
$request->validate([
|
||||
...DatabaseHelper::getOrderBysValidations(),
|
||||
'search' => DatabaseHelper::getSearchValidation(),
|
||||
'apkVersionCode' => 'nullable|integer',
|
||||
'tz' => 'required|timezone',
|
||||
'isActive' => 'nullable|boolean',
|
||||
'installedAt' => 'nullable|array',
|
||||
'installedAt.from' => 'nullable|date',
|
||||
'installedAt.to' => 'nullable|date',
|
||||
'lastConnectedAt' => 'nullable|array',
|
||||
'lastConnectedAt.from' => 'nullable|date',
|
||||
'lastConnectedAt.to' => 'nullable|date',
|
||||
'lastConnectedDay' => 'nullable|int'
|
||||
]);
|
||||
Common::setTimezone($request->tz);
|
||||
|
||||
return Tv::when($request->isActive != null, function($q) use($request) {
|
||||
$q->where('is_active', $request->isActive);
|
||||
})
|
||||
->when($request->apkVersionCode, function($q, $apkVersionCode) {
|
||||
$q->where('apk_version_code', $apkVersionCode);
|
||||
})
|
||||
->when($request->installedAt['from'] ?? '', function($q, $from) {
|
||||
$q->where(DB::raw('DATE(installed_at)'), '>=', $from);
|
||||
})
|
||||
->when($request->installedAt['to'] ?? '', function($q, $to) {
|
||||
$q->where(DB::raw('DATE(installed_at)'), '<=', $to);
|
||||
})
|
||||
->when($request->lastConnectedAt['from'] ?? '', function($q, $from) {
|
||||
$q->where(DB::raw('DATE(last_connected_at)'), '>=', $from);
|
||||
})
|
||||
->when($request->lastConnectedAt['to'] ?? '', function($q, $to) {
|
||||
$q->where(DB::raw('DATE(last_connected_at)'), '<=', $to);
|
||||
})
|
||||
->multiSearch($request->search, ['code', 'company_name'])
|
||||
->multiOrderBy($request->orderBys, 'created_at desc');
|
||||
}
|
||||
|
||||
public static function updateFromRequest(Request $request) {
|
||||
if($request->code) $request->merge(['code' => strtoupper($request->code)]);
|
||||
$request->validate([
|
||||
'id' => 'required|integer|exists:App\Models\Tv',
|
||||
'code' => ['required','string',Rule::unique('tvs', 'code')
|
||||
->when($request->id, function($q, $id) { $q->whereNot('id', $id);})],
|
||||
'company_name' => 'nullable|string',
|
||||
'address' => 'nullable|string',
|
||||
'street_address' => 'nullable|string',
|
||||
'col1' => 'nullable|string',
|
||||
'col2' => 'nullable|string',
|
||||
'col3' => 'nullable|string',
|
||||
'col4' => 'nullable|string',
|
||||
'col5' => 'nullable|string',
|
||||
'col6' => 'nullable|string',
|
||||
'col7' => 'nullable|string',
|
||||
'col8' => 'nullable|string',
|
||||
'col9' => 'nullable|string',
|
||||
'col10' => 'nullable|string',
|
||||
'notes' => 'nullable|string',
|
||||
]);
|
||||
|
||||
try {
|
||||
DB::beginTransaction();
|
||||
$tv = TV::findOrFail($request->id);
|
||||
$oldTv = $tv->replicate();
|
||||
$tv->company_name = $request->company_name;
|
||||
$tv->address = $request->address;
|
||||
$tv->street_address = $request->street_address;
|
||||
$tv->code = $request->code;
|
||||
$tv->col1 = $request->col1;
|
||||
$tv->col2 = $request->col2;
|
||||
$tv->col3 = $request->col3;
|
||||
$tv->col4 = $request->col4;
|
||||
$tv->col5 = $request->col5;
|
||||
$tv->col6 = $request->col6;
|
||||
$tv->col7 = $request->col7;
|
||||
$tv->col8 = $request->col8;
|
||||
$tv->col9 = $request->col9;
|
||||
$tv->col10 = $request->col10;
|
||||
$tv->notes = $request->notes;
|
||||
$tv->update();
|
||||
|
||||
TvLog::historyUpdate($request->user(), $tv->id, $oldTv, $tv);
|
||||
DB::commit();
|
||||
return JSONResponse::Success(['message'=>'Success to update tv data']);
|
||||
|
||||
// TODO: waiting from ops workflow (Dont forget to resync co_name, address, street address in ik)
|
||||
// // try to sys_to_sys with indokargo
|
||||
// $jsonResponse = Indokargo::updateTVAddress($request, $tv->id, $tv->ik_address_id);
|
||||
// DB::commit();
|
||||
// return $jsonResponse;
|
||||
} catch(\Throwable $th) {
|
||||
DB::rollback();
|
||||
throw $th;
|
||||
}
|
||||
|
||||
}
|
||||
public static function changeStatusFromRequest(Request $request) {
|
||||
$request->validate(['id' => 'required|integer|exists:App\Models\TV,id']);
|
||||
|
||||
try {
|
||||
DB::beginTransaction();
|
||||
$tv = Tv::findOrFail($request->id);
|
||||
$tv->is_active = !$tv->is_active;
|
||||
$tv->save();
|
||||
DB::commit();
|
||||
return JSONResponse::Success(['message'=>'Success to change tv status']);
|
||||
|
||||
// TODO: waiting from ops workflow (Dont forget to resync co_name, address, street address in ik)
|
||||
// // try to sys_to_sys with indokargo
|
||||
// $jsonResponse = Indokargo::changeStatusAddress(new Request(['is_active' => $tv->is_active]),
|
||||
// $tv->id, $tv->ik_address_id);
|
||||
// DB::commit();
|
||||
// return $jsonResponse;
|
||||
} catch(\Throwable $th) {
|
||||
DB::rollback();
|
||||
throw $th;
|
||||
}
|
||||
}
|
||||
// -- END RELATED TO REQUEST
|
||||
//------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------
|
||||
// -- RELATED TO EXCEL
|
||||
public static function getExcelDetail(Request $request) {
|
||||
return JSONResponse::Success(['rows' => TV::validateAndGetEloquentFromRequest($request)->get()]);
|
||||
}
|
||||
|
||||
// ---- RELATED TO EXPORT IMPORT
|
||||
const EXCEL_SUCCESS = 'success';
|
||||
const EXCEL_FAILED = 'failed';
|
||||
const EXCEL_NO_CHANGE = 'no_change';
|
||||
const EXCEL_UPDATE = 'update';
|
||||
const EXCEL_TEMPLATE_COLS = ['code', 'company_name', 'address', 'street_address', 'notes',
|
||||
'col1', 'col2', 'col3', 'col4', 'col5',
|
||||
'col6', 'col7', 'col8', 'col9', 'col10',
|
||||
'is_active'];
|
||||
public static function getExcelTemplate() {
|
||||
$row = [];
|
||||
foreach(self::EXCEL_TEMPLATE_COLS as $col) { $row[$col] = ''; }
|
||||
$rows = [$row];
|
||||
return JSONResponse::Success(['rows' => $rows]);
|
||||
}
|
||||
public static function getExportData(Request $request) {
|
||||
$rows = TV::validateAndGetEloquentFromRequest($request)->get();
|
||||
return JSONResponse::Success(['rows' => $rows, 'cols' => self::EXCEL_TEMPLATE_COLS]);
|
||||
}
|
||||
// ------ RELATED TO IMPORT
|
||||
private static function _checkExcelFormat($tvRows) {
|
||||
if(!$tvRows) throw new \Exception("No Data");
|
||||
|
||||
$firstTvRow = $tvRows[0];
|
||||
if(!$firstTvRow) throw new \Exception('Column not found');
|
||||
|
||||
// check if excel is empty or not
|
||||
$firstTvRow['row'] = null;
|
||||
if(!array_filter($firstTvRow)) throw new \Exception("Excel is empty");
|
||||
|
||||
// check is header col is exists
|
||||
$errors = [];
|
||||
foreach(self::EXCEL_TEMPLATE_COLS as $col) {
|
||||
if(!array_key_exists($col, $firstTvRow)) $errors[$col] = "Column $col is Required";
|
||||
}
|
||||
if($errors) throw ValidationException::withMessages($errors);
|
||||
}
|
||||
private static function _getCountTvCodes($tvRows, $tvCodes) {
|
||||
if(!$tvCodes) $tvCodes = array_column($tvRows, 'code');
|
||||
$tvCodes = array_map(function($code) { return DatabaseHelper::trimUpperNull($code) ?? ''; }, $tvCodes);
|
||||
return array_count_values($tvCodes);
|
||||
}
|
||||
private static function _changeModelFromTvRow(Tv $tv, $tvRow) {
|
||||
$tv->company_name = $tvRow['company_name'];
|
||||
$tv->address = $tvRow['address'];
|
||||
$tv->street_address = $tvRow['street_address'];
|
||||
$tv->code = $tvRow['code'];
|
||||
$tv->col1 = $tvRow['col1'];
|
||||
$tv->col2 = $tvRow['col2'];
|
||||
$tv->col3 = $tvRow['col3'];
|
||||
$tv->col4 = $tvRow['col4'];
|
||||
$tv->col5 = $tvRow['col5'];
|
||||
$tv->col6 = $tvRow['col6'];
|
||||
$tv->col7 = $tvRow['col7'];
|
||||
$tv->col8 = $tvRow['col8'];
|
||||
$tv->col9 = $tvRow['col9'];
|
||||
$tv->col10 = $tvRow['col10'];
|
||||
$tv->notes = $tvRow['notes'];
|
||||
return $tv;
|
||||
}
|
||||
public static function validateExcel($tvRows, $tvCodes = []) {
|
||||
self::_checkExcelFormat($tvRows);
|
||||
$countTvCodes = self::_getCountTvCodes($tvRows, $tvCodes);
|
||||
|
||||
$endStatus = self::EXCEL_SUCCESS;
|
||||
$results = [];
|
||||
foreach($tvRows as $tvRow) {
|
||||
$status = self::EXCEL_NO_CHANGE;
|
||||
$message = '';
|
||||
$tvRow['code'] = strtoupper($tvRow['code'] ?? '');
|
||||
|
||||
try {
|
||||
// STEP 1: check validation
|
||||
$validator = Validator::make($tvRow, [
|
||||
'row' => 'required|integer',
|
||||
'code' => 'required|string',
|
||||
'company_name' => 'nullable|string',
|
||||
'address' => 'nullable|string',
|
||||
'street_address' => 'nullable|string',
|
||||
'col1' => 'nullable|string',
|
||||
'col2' => 'nullable|string',
|
||||
'col3' => 'nullable|string',
|
||||
'col4' => 'nullable|string',
|
||||
'col5' => 'nullable|string',
|
||||
'col6' => 'nullable|string',
|
||||
'col7' => 'nullable|string',
|
||||
'col8' => 'nullable|string',
|
||||
'col9' => 'nullable|string',
|
||||
'col10' => 'nullable|string',
|
||||
'notes' => 'nullable|string',
|
||||
]);
|
||||
if($validator->fails()) {
|
||||
$errors = $validator->errors()->toArray();
|
||||
$messages = [];
|
||||
foreach($errors as $eMessages) { $messages = array_merge($messages, $eMessages); }
|
||||
throw new \Exception(implode(', ', $messages));
|
||||
}
|
||||
|
||||
// STEP 2: check code is duplicate or not or not
|
||||
$code = $tvRow['code'];
|
||||
if(($countTvCodes[$code] ?? 0) > 1) throw new \Exception('Code is Duplicate in Excel');
|
||||
|
||||
// STEP 3: check code existing in database or not
|
||||
$tvCheck = Tv::where('code', 'ilike', $code)->first();
|
||||
if(!$tvCheck) throw new \Exception("TV Code '$code' not found in database");
|
||||
|
||||
// STEP 4: check has update data or not
|
||||
$tvCheck = self::_changeModelFromTvRow($tvCheck, $tvRow);
|
||||
if($tvCheck->isDirty()) {
|
||||
$status = self::EXCEL_UPDATE;
|
||||
$message = DatabaseHelper::compileDirtyEloquentToArrMessage($tvCheck);
|
||||
}
|
||||
} catch (\Throwable $th) {
|
||||
$endStatus = self::EXCEL_FAILED;
|
||||
$status = self::EXCEL_FAILED;
|
||||
$message = $th->getMessage();
|
||||
}
|
||||
$results[] = ['row' => $tvRow['row'], 'status' => $status, 'message' => $message];
|
||||
}
|
||||
return ['status' => $endStatus, 'results' => $results];
|
||||
}
|
||||
public static function uploadExcel($tvRows, $oValidation, User $user) {
|
||||
$validationResults = $oValidation['results'];
|
||||
$countUploads = [
|
||||
self::EXCEL_UPDATE => 0, self::EXCEL_NO_CHANGE => 0, self::EXCEL_FAILED => 0
|
||||
];
|
||||
$additionalErrors = [];
|
||||
|
||||
foreach($validationResults as $result) {
|
||||
$validateStatus = $result['status'];
|
||||
try {
|
||||
switch($validateStatus) {
|
||||
case self::EXCEL_FAILED:
|
||||
throw new \Exception($result['message']);
|
||||
break;
|
||||
|
||||
case self::EXCEL_UPDATE:
|
||||
// get sparepart data
|
||||
$idxTvRow = array_search($result['row'], array_column($tvRows, 'row'));
|
||||
if($idxTvRow === false) throw new \Exception('Row Not Found');
|
||||
$tvRow = $tvRows[$idxTvRow];
|
||||
$tvRow['code'] = strtoupper($tvRow['code'] ?? '');
|
||||
|
||||
// try to upsert
|
||||
DB::beginTransaction();
|
||||
$tv = TV::where('code', 'ilike', $tvRow['code'])->firstOrFail();
|
||||
$oldTV = $tv->replicate();
|
||||
$newTv = self::_changeModelFromTvRow($tv, $tvRow);
|
||||
if(!$newTv->isDirty()) throw new \Exception('No Change');
|
||||
$newTv->save();
|
||||
|
||||
// save data log
|
||||
TvLog::historyUpdateExcel($user, $newTv->id, $oldTV, $newTv);
|
||||
DB::commit();
|
||||
break;
|
||||
|
||||
case self::EXCEL_NO_CHANGE:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} catch (\Throwable $th) {
|
||||
DB::rollBack();
|
||||
$validateStatus = self::EXCEL_FAILED;
|
||||
$additionalErrors[] = 'row ' . ($result['row'] ?? '-') . ' => ' . $th->getMessage();
|
||||
}
|
||||
|
||||
$countUploads[$validateStatus]++;
|
||||
}
|
||||
|
||||
return ['countUploads' => $countUploads, 'additionalErrors' => $additionalErrors];
|
||||
}
|
||||
// ------ END RELATED TO IMPORT
|
||||
// ---- END RELATED TO EXPORT IMPORT
|
||||
// -- END RELATED TO EXCEL
|
||||
//------------------------------------------------------------
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class TvLog extends Model {
|
||||
use HasFactory;
|
||||
|
||||
protected $table = 'tv_logs';
|
||||
protected $hidden = ['ik_cust_id', 'ik_address_id'];
|
||||
protected $casts = ['from'=>'object', 'to'=>'object'];
|
||||
|
||||
const TYPES = ['create', 'update', 'update-excel'];
|
||||
|
||||
public static function historyCreate(User $user, int $tvFk, Tv $newTv) { self::saveHistory('create', $user, $tvFk, null, $newTv); }
|
||||
public static function historyUpdate(User $user, int $tvFk, Tv $oldTv, Tv $newTv) { self::saveHistory('update', $user, $tvFk, $oldTv, $newTv); }
|
||||
public static function historyUpdateExcel(User $user, int $tvFk, Tv $oldTv, Tv $newTv) { self::saveHistory('update-excel', $user, $tvFk, $oldTv, $newTv); }
|
||||
|
||||
private static function saveHistory(String $type, ?User $user, int $tvFk, ?Tv $oldTv, ?Tv $newTv) {
|
||||
if(!in_array($type, self::TYPES)) throw new \Exception("Type '$type' No Valid");
|
||||
$tvLog = new TvLog();
|
||||
$tvLog->tv_fk = $tvFk;
|
||||
$tvLog->type = $type;
|
||||
if($oldTv) {
|
||||
$oldTv = $oldTv->toArray();
|
||||
unset($oldTv['id']);
|
||||
$tvLog->from =$oldTv;
|
||||
}
|
||||
if($newTv) {
|
||||
$newTv = $newTv->toArray();
|
||||
unset($newTv['id']);
|
||||
$tvLog->to = $newTv;
|
||||
}
|
||||
if($user) { $tvLog->user_fk = $user->id; }
|
||||
$tvLog->save();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,4 @@
|
||||
Notes:
|
||||
- Auto Update app
|
||||
- Auto Update video
|
||||
- Laravel Sanctum
|
||||
@ -0,0 +1,2 @@
|
||||
Notes:
|
||||
- TV information & Logs
|
||||
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void {
|
||||
Schema::create('outlets', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('code', 50)->index();
|
||||
$table->string('name', 255)->nullable()->index();
|
||||
$table->string('address', 255)->nullable();
|
||||
$table->string('street_address', 255)->nullable();
|
||||
$table->string('phone', 50)->nullable()->index();
|
||||
$table->double('lat')->default(0);
|
||||
$table->double('long')->default(0);
|
||||
$table->string('notes', 255)->nullable();
|
||||
$table->string('country', 255);
|
||||
$table->string('ik_country_id', 255);
|
||||
$table->string('state', 255);
|
||||
$table->string('ik_state_id', 255);
|
||||
$table->string('region', 255);
|
||||
$table->string('ik_region_id', 255);
|
||||
$table->string('city', 255);
|
||||
$table->string('ik_city_id', 255);
|
||||
$table->string('zipcode', 255)->nullable();
|
||||
$table->timestampTz('last_visited_at')->nullable();
|
||||
$table->timestampsTz();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void {
|
||||
Schema::drop('outlets');
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration {
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void {
|
||||
Schema::create('tvs', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('code', 50)->unique();
|
||||
$table->string('ik_address_id', 255)->nullable();
|
||||
$table->integer('apk_version_code')->nullable();
|
||||
$table->string('apk_version_name')->nullable();
|
||||
$table->string('company_name')->nullable();
|
||||
$table->string('address')->nullable();
|
||||
$table->string('street_address')->nullable();
|
||||
$table->string('col1', 255)->nullable();
|
||||
$table->string('col2', 255)->nullable();
|
||||
$table->string('col3', 255)->nullable();
|
||||
$table->string('col4', 255)->nullable();
|
||||
$table->string('col5', 255)->nullable();
|
||||
$table->string('col6', 255)->nullable();
|
||||
$table->string('col7', 255)->nullable();
|
||||
$table->string('col8', 255)->nullable();
|
||||
$table->string('col9', 255)->nullable();
|
||||
$table->string('col10', 255)->nullable();
|
||||
$table->string('notes', 255)->nullable();
|
||||
$table->boolean('is_active')->default(true);
|
||||
$table->jsonb('device_info')->nullable();
|
||||
$table->timestampTz('installed_at');
|
||||
$table->timestampTz('last_connected_at')->nullable();
|
||||
$table->timestampsTz();
|
||||
});
|
||||
|
||||
Schema::create('new_tv_requests', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('code', 50);
|
||||
$table->jsonb('device_info')->nullable();
|
||||
$table->foreignId('tv_fk')->nullable();
|
||||
$table->timestampTz('approved_at')->nullable();
|
||||
$table->timestampTz('responded_at')->nullable();
|
||||
$table->timestampsTz();
|
||||
});
|
||||
|
||||
Schema::create('tv_logs', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('tv_fk');
|
||||
$table->string('type');
|
||||
$table->json('from')->nullable();
|
||||
$table->json('to')->nullable();
|
||||
$table->foreignId('user_fk')->nullable();
|
||||
$table->timestampsTz();
|
||||
|
||||
$table->foreign('tv_fk')->references('id')->on('tvs')->cascadeOnDelete();
|
||||
$table->foreign('user_fk')->references('id')->on('users');
|
||||
});
|
||||
|
||||
// Schema::create('tv_sessions', function (Blueprint $table) {
|
||||
// $table->id();
|
||||
// $table->foreignId('tv_fk')->index();
|
||||
// $table->timestampTz('started_at')->index();
|
||||
// $table->timestampTz('finished_at')->nullable()->index();
|
||||
// $table->boolean('is_playing_video');
|
||||
// $table->jsonb('current_videos')->nullable();
|
||||
// $table->timestampsTz();
|
||||
|
||||
// $table->foreign('tv_fk')->references('id')->on('tvs');
|
||||
// });
|
||||
|
||||
// Schema::create('tv_app_infos', function (Blueprint $table) {
|
||||
// $table->foreignId('tv_fk')->unique()->index();
|
||||
// $table->timestampTz('installed_at')->nullable()->index();
|
||||
// $table->jsonb('current_videos')->nullable();
|
||||
// $table->timestampTz('last_updated_video')->nullable()->index();
|
||||
// $table->timestampsTz();
|
||||
|
||||
// $table->foreign('tv_fk')->references('id')->on('tvs');
|
||||
// });
|
||||
|
||||
// Schema::create('tv_app_logs', function (Blueprint $table) {
|
||||
// $table->id();
|
||||
// $table->foreignId('tv_fk')->index();
|
||||
// $table->string('requested_to');
|
||||
// $table->string('ip', 50);
|
||||
// $table->jsonb('request_data')->nullable();
|
||||
// $table->enum('result', ['success', 'failed']);
|
||||
// $table->jsonb('response_data')->nullable();
|
||||
// $table->timestampsTz();
|
||||
|
||||
// $table->foreign('tv_fk')->references('id')->on('tvs');
|
||||
// });
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void {
|
||||
// Schema::drop('tv_app_logs');
|
||||
// Schema::drop('tv_app_infos');
|
||||
// Schema::drop('tv_sessions');
|
||||
Schema::drop('tv_logs');
|
||||
Schema::drop('new_tv_requests');
|
||||
Schema::drop('tvs');
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void {
|
||||
Schema::create('sts_logs', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('partner', 255)->nullable();
|
||||
$table->boolean('is_outgoing');
|
||||
$table->string('module', 255)->nullable();
|
||||
$table->string('service_name', 255)->nullable();
|
||||
$table->string('local_id', 255)->nullable();
|
||||
$table->string('partner_id', 255)->nullable();
|
||||
$table->enum('result', ['success', 'failed', 'warning']);
|
||||
$table->jsonb('error_info')->nullable();
|
||||
$table->tinyInteger('seq');
|
||||
$table->jsonb('request_data')->nullable();
|
||||
$table->timestampTz('request_time')->nullable();
|
||||
$table->jsonb('response_data')->nullable();
|
||||
$table->timestampTz('response_time')->nullable();
|
||||
$table->boolean('is_retry')->default('false');
|
||||
$table->timestampsTz();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void {
|
||||
Schema::drop('sts_logs');
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void {
|
||||
Schema::table('video_updates', function(Blueprint $table) {
|
||||
$table->double('file_size_kb')->default(0);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void {
|
||||
Schema::table('video_updates', function(Blueprint $table) {
|
||||
$table->dropColumn('file_size_kb');
|
||||
});
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('apk_updates', function (Blueprint $table) {
|
||||
$table->string('version_name', 50)->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('apk_updates', function (Blueprint $table) {
|
||||
$table->dropColumn('version_name');
|
||||
});
|
||||
}
|
||||
};
|
||||
@ -1,10 +1,16 @@
|
||||
<?php
|
||||
|
||||
use App\Http\Controllers\api\mobile\CheckUpdateController;
|
||||
use App\Http\Controllers\api\mobile\TvController;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::controller(CheckUpdateController::class)->group(function() {
|
||||
Route::post('/check-update/video-update/latest', 'videoUpdateLatest');
|
||||
Route::post('/check-update/apk-update/latest', 'apkUpdateLatest');
|
||||
})
|
||||
});
|
||||
|
||||
Route::controller(TvController::class)->group(function() {
|
||||
Route::post('/tv/new-request', 'newRequest');
|
||||
Route::post('/tv/check-update', 'checkUpdate');
|
||||
});
|
||||
?>
|
||||
Loading…
Reference in New Issue