| @@ -3,6 +3,7 @@ | |||||
| namespace App\Http\Controllers\Web\QRService\Acquisition; | namespace App\Http\Controllers\Web\QRService\Acquisition; | ||||
| use App\Http\Controllers\Web\WebController; | use App\Http\Controllers\Web\WebController; | ||||
| use App\Logics\QRService\QRCryptoLogic; | |||||
| use App\Models\HtpmsCustomer\QRService\AcquisitionTicketToken; | use App\Models\HtpmsCustomer\QRService\AcquisitionTicketToken; | ||||
| use Illuminate\Http\JsonResponse; | use Illuminate\Http\JsonResponse; | ||||
| use Illuminate\Http\Request; | use Illuminate\Http\Request; | ||||
| @@ -43,6 +44,7 @@ class GetAcquisitionTokenController extends WebController | |||||
| $res = [ | $res = [ | ||||
| "token" => $token->token, | "token" => $token->token, | ||||
| ]; | ]; | ||||
| return $this->successResponse($res); | return $this->successResponse($res); | ||||
| } | } | ||||
| } | } | ||||
| @@ -0,0 +1,48 @@ | |||||
| <?php | |||||
| namespace App\Http\Controllers\Web\QRService\Certification; | |||||
| use App\Http\Controllers\Web\WebController; | |||||
| use App\Logics\QRService\CertificateLogic; | |||||
| use Illuminate\Http\JsonResponse; | |||||
| use Illuminate\Http\Request; | |||||
| class CertificationController extends WebController | |||||
| { | |||||
| public function name(): string | |||||
| { | |||||
| return "QRサービス券認証"; | |||||
| } | |||||
| public function description(): string | |||||
| { | |||||
| return "QRサービス券を認証する"; | |||||
| } | |||||
| public function __construct(protected CertificationParam $param) | |||||
| { | |||||
| parent::__construct(); | |||||
| } | |||||
| protected function run(Request $request): JsonResponse | |||||
| { | |||||
| $param = $this->param; | |||||
| $cartification = CertificateLogic::certificate( | |||||
| $param->parkingManagementCode, | |||||
| $param->publishingTerminalCode, | |||||
| $param->publishingDate, | |||||
| $param->publishingNo, | |||||
| $this->sessionUser->shopId(), | |||||
| $param->discountTicketCode, | |||||
| ); | |||||
| $res = [ | |||||
| "expires_at" => $cartification->expires_at, | |||||
| ]; | |||||
| return $this->successResponse($res); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,29 @@ | |||||
| <?php | |||||
| namespace App\Http\Controllers\Web\QRService\Certification; | |||||
| use App\Http\Controllers\Web\BaseParam; | |||||
| use App\Http\Controllers\Web\Rule; | |||||
| use App\Models\HtpmsCustomer\QRService\CertificationTicket; | |||||
| use Illuminate\Support\Carbon; | |||||
| /** | |||||
| * @property string parkingManagementCode | |||||
| * @property string publishingTerminalCode | |||||
| * @property Carbon publishingDate | |||||
| * @property int publishingNo | |||||
| * @property int discountTicketCode | |||||
| */ | |||||
| class CertificationParam extends BaseParam | |||||
| { | |||||
| public function rules(): array | |||||
| { | |||||
| return [ | |||||
| CertificationTicket::COL_NAME_PARKING_MANAGEMENT_CODE => $this->str([...Rule::parkingManagementCode()]), | |||||
| CertificationTicket::COL_NAME_PUBLISHING_TERMINAL_CODE => $this->str("reg_ex:/^[0-9]{2}$/"), | |||||
| CertificationTicket::COL_NAME_PUBLISHING_DATE => $this->date(), | |||||
| CertificationTicket::COL_NAME_PUBLISHING_NO => $this->numeric("between:0,999999"), | |||||
| CertificationTicket::COL_NAME_DISCOUNT_TICKET_CODE => $this->numeric("between:0,99"), | |||||
| ]; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,138 @@ | |||||
| <?php | |||||
| namespace App\Http\Controllers\Web\QRService\Certification; | |||||
| use App\Exceptions\GeneralErrorMessageException; | |||||
| use App\Http\Controllers\Web\WebController; | |||||
| use App\Logics\QRService\QRCryptoLogic; | |||||
| use App\Models\ColumnName; | |||||
| use App\Models\HtpmsCustomer\Existing\DiscountTicket; | |||||
| use App\Models\HtpmsCustomer\Existing\Parking; | |||||
| use App\Models\HtpmsCustomer\Mst\ShopNoRelation; | |||||
| use App\Models\HtpmsCustomer\QRService\CertificationAvailableSetting; | |||||
| use App\Models\HtpmsCustomer\QRService\CertificationTicket; | |||||
| use Illuminate\Http\JsonResponse; | |||||
| use Illuminate\Http\Request; | |||||
| use Illuminate\Support\Carbon; | |||||
| class CheckDataFormatController extends WebController | |||||
| { | |||||
| public function name(): string | |||||
| { | |||||
| return "データチェック"; | |||||
| } | |||||
| public function description(): string | |||||
| { | |||||
| return "暗号化文字列をチェック認証に必要な情報を取得する"; | |||||
| } | |||||
| public function __construct(protected CheckDataFormatParam $param) | |||||
| { | |||||
| parent::__construct(); | |||||
| } | |||||
| protected function run(Request $request): JsonResponse | |||||
| { | |||||
| $param = $this->param; | |||||
| // 暗号化文字列の解読 | |||||
| $data = DataConverter::read($param->data); | |||||
| // 対象の駐車場か判定 | |||||
| $relation = ShopNoRelation::whereShopId($this->sessionUser->shopId()) | |||||
| ->whereParkingManagementCode($data->駐車場管理コード) | |||||
| ->first(); | |||||
| if ($relation === null) { | |||||
| throw new GeneralErrorMessageException("認証できない駐車場"); | |||||
| } | |||||
| // 認証可能なサービス券一覧取得 | |||||
| $setting = CertificationAvailableSetting::whereShopId($this->sessionUser->shopId()) | |||||
| ->whereParkingManagementCode($data->駐車場管理コード) | |||||
| ->get(); | |||||
| if ($setting->isEmpty()) { | |||||
| throw new GeneralErrorMessageException("認証できるサービス券なし"); | |||||
| } | |||||
| // 駐車場情報の取得 | |||||
| $parking = Parking::whereParkCode($data->駐車場管理コード) | |||||
| ->first(); | |||||
| if ($parking instanceof Parking === false) { | |||||
| throw new GeneralErrorMessageException("存在しない駐車場"); | |||||
| } | |||||
| // 認証済みチェック | |||||
| if (CertificationTicket::whereParkingManagementCode($data->駐車場管理コード) | |||||
| ->wherePublishingTerminalCode($data->発行端末) | |||||
| ->wherePublishingDate($data->発行日) | |||||
| ->wherePublishingNo($data->発行連番) | |||||
| ->exists() | |||||
| ) { | |||||
| throw new GeneralErrorMessageException("認証ずみのサービス券"); | |||||
| } | |||||
| // サービス券一覧の取得 | |||||
| $discountTicketCodes = $setting->pluck(CertificationAvailableSetting::COL_NAME_DISCOUNT_TICKET_CODE)->toArray(); | |||||
| $discountTickets = DiscountTicket::whereParkId($parking->id) | |||||
| ->whereIn(DiscountTicket::COL_NAME_DISCOUNT_TICKET_CODE, $discountTicketCodes) | |||||
| ->select([ | |||||
| sprintf("%s as %s", DiscountTicket::COL_NAME_DISCOUNT_TICKET_CODE, ColumnName::DISCOUNT_TICKET_CODE), | |||||
| sprintf("%s as %s", DiscountTicket::COL_NAME_TICKET_NAME, "ticket_name"), | |||||
| ])->get(); | |||||
| $res = [ | |||||
| "parking" => [ | |||||
| "parking_name" => $parking->park_name, | |||||
| "parking_management_code" => $parking->park_code, | |||||
| "publishing_terminal_code" => $data->発行端末, | |||||
| "publishing_date" => $data->発行日, | |||||
| "publishing_no" => $data->発行連番, | |||||
| ], | |||||
| "discount_tickets" => $discountTickets, | |||||
| ]; | |||||
| return $this->successResponse($res); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * 精算機で暗号化された文字列をパースする | |||||
| */ | |||||
| class DataConverter | |||||
| { | |||||
| public string $発行端末; | |||||
| public Carbon $発行日; | |||||
| public int $発行連番; | |||||
| public string $顧客コード; | |||||
| public string $駐車場管理コード; | |||||
| public static function read(string $data): static | |||||
| { | |||||
| $ret = new static(); | |||||
| $dec = QRCryptoLogic::decrypt($data); | |||||
| if (strlen($dec) !== 30) { | |||||
| throw new GeneralErrorMessageException("文字数不正"); | |||||
| } | |||||
| $data = substr($dec, 5); | |||||
| $ret->発行端末 = substr($data, 0, 2); | |||||
| $ret->発行日 = Carbon::createFromFormat("Ymd", substr($data, 2, 8)); | |||||
| $ret->発行連番 = intval(substr($data, 10, 6)); | |||||
| $ret->顧客コード = substr($data, 16, 4); | |||||
| $ret->駐車場管理コード = substr($data, 20, 5); | |||||
| return $ret; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,18 @@ | |||||
| <?php | |||||
| namespace App\Http\Controllers\Web\QRService\Certification; | |||||
| use App\Http\Controllers\Web\BaseParam; | |||||
| /** | |||||
| * @property string $data | |||||
| */ | |||||
| class CheckDataFormatParam extends BaseParam | |||||
| { | |||||
| public function rules(): array | |||||
| { | |||||
| return [ | |||||
| 'data' => $this->str(), | |||||
| ]; | |||||
| } | |||||
| } | |||||
| @@ -2,6 +2,7 @@ | |||||
| namespace App\Models\HtpmsCustomer\Existing; | namespace App\Models\HtpmsCustomer\Existing; | ||||
| use App\Models\ColumnName; | |||||
| use App\Util\DateUtil; | use App\Util\DateUtil; | ||||
| use Illuminate\Database\Eloquent\Model; | use Illuminate\Database\Eloquent\Model; | ||||
| use Illuminate\Database\Query\Builder; | use Illuminate\Database\Query\Builder; | ||||
| @@ -20,6 +21,8 @@ class DiscountTicket extends Model | |||||
| protected $visible = [ | protected $visible = [ | ||||
| self::COL_NAME_TICKET_NAME, | self::COL_NAME_TICKET_NAME, | ||||
| self::COL_NAME_DISCOUNT_TICKET_CODE, | self::COL_NAME_DISCOUNT_TICKET_CODE, | ||||
| "ticket_name", | |||||
| ColumnName::DISCOUNT_TICKET_CODE, | |||||
| ]; | ]; | ||||
| @@ -65,6 +65,8 @@ Route::middleware('auth:sanctum')->group(function () { | |||||
| RouteHelper::get('/shop/deposit', App\Http\Controllers\Web\Shop\MyDepositController::class); | RouteHelper::get('/shop/deposit', App\Http\Controllers\Web\Shop\MyDepositController::class); | ||||
| RouteHelper::get('/qr-service/acquisition/token', App\Http\Controllers\Web\QRService\Acquisition\GetAcquisitionTokenController::class); | RouteHelper::get('/qr-service/acquisition/token', App\Http\Controllers\Web\QRService\Acquisition\GetAcquisitionTokenController::class); | ||||
| RouteHelper::post('/qr-service/acquisition/token/refresh', App\Http\Controllers\Web\QRService\Acquisition\RefreshAcquisitionTokenController::class); | RouteHelper::post('/qr-service/acquisition/token/refresh', App\Http\Controllers\Web\QRService\Acquisition\RefreshAcquisitionTokenController::class); | ||||
| RouteHelper::post('/qr-service/certification/check-data-format', App\Http\Controllers\Web\QRService\Certification\CheckDataFormatController::class); | |||||
| RouteHelper::post('/qr-service/certification', App\Http\Controllers\Web\QRService\Certification\CertificationController::class); | |||||
| }); | }); | ||||
| // 管理者運営会社ルート | // 管理者運営会社ルート | ||||
| @@ -0,0 +1,31 @@ | |||||
| <?php | |||||
| namespace Tests\Feature\Http; | |||||
| use App\Codes\UserRole; | |||||
| use App\Logics\QRService\CertificateLogic; | |||||
| use App\Models\HtpmsCustomer\Deposit\Deposit; | |||||
| use App\Models\HtpmsCustomer\Mst\Shop; | |||||
| use App\Models\HtpmsCustomer\Mst\ShopNoRelation; | |||||
| use App\Models\HtpmsCustomer\QRService\CertificationAvailableSetting; | |||||
| use App\Models\HtpmsCustomer\QRService\CertificationTicket; | |||||
| use App\Models\User; | |||||
| use App\Util\DateUtil; | |||||
| use Illuminate\Support\Carbon; | |||||
| use Tests\TestCase; | |||||
| class CustomerListTest extends TestCase | |||||
| { | |||||
| public function test(): void | |||||
| { | |||||
| $user = User::whereRole(UserRole::ADMIN)->firstOrFail(); | |||||
| $res = $this->actingAs($user) | |||||
| ->get('/api/customer/list'); | |||||
| print_r($res->json()); | |||||
| $this->assertEquals("0", $res->json('result')); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,45 @@ | |||||
| <?php | |||||
| namespace Tests\Unit\Repositories; | |||||
| use App\Codes\UserRole; | |||||
| use App\Repositories\LoginUserRepository; | |||||
| use Tests\TestCase; | |||||
| /** | |||||
| * @group Repository | |||||
| */ | |||||
| class LoginUserRepositoryTest extends TestCase | |||||
| { | |||||
| public function test_get_all(): void | |||||
| { | |||||
| $repository = new LoginUserRepository(); | |||||
| $repository->get([]); | |||||
| $this->assertTrue(true); | |||||
| } | |||||
| public function test_email_condition(): void | |||||
| { | |||||
| $repository = new LoginUserRepository(); | |||||
| $data = $repository->get([ | |||||
| LoginUserRepository::CONDITION_EMAIL => "aa.com" | |||||
| ]); | |||||
| $this->assertCount(1, $data); | |||||
| $data = $repository->get([ | |||||
| LoginUserRepository::CONDITION_EMAIL => "satellite" | |||||
| ]); | |||||
| $this->assertCount(0, $data); | |||||
| } | |||||
| public function test_role_condition(): void | |||||
| { | |||||
| $repository = new LoginUserRepository(); | |||||
| $data = $repository->get([ | |||||
| LoginUserRepository::CONDITION_ROLE => UserRole::ADMIN | |||||
| ]); | |||||
| $this->assertCount(1, $data); | |||||
| $data = $repository->get([ | |||||
| LoginUserRepository::CONDITION_ROLE => UserRole::SHOP | |||||
| ]); | |||||
| $this->assertCount(0, $data); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,22 @@ | |||||
| <?php | |||||
| namespace Tests\Unit\Repositories; | |||||
| use App\Codes\UserRole; | |||||
| use App\Repositories\LoginUserRepository; | |||||
| use App\Repositories\QRServiceParkingGroupRepository; | |||||
| use Tests\TestCase; | |||||
| /** | |||||
| * @group Repository | |||||
| */ | |||||
| class QRServiceParkingGroupRepositoryTest extends TestCase | |||||
| { | |||||
| public function test_get_all(): void | |||||
| { | |||||
| $repository = new QRServiceParkingGroupRepository(); | |||||
| $repository->get([]); | |||||
| $this->assertTrue(true); | |||||
| } | |||||
| } | |||||