| @@ -3,6 +3,7 @@ | |||
| namespace App\Http\Controllers\Web\QRService\Acquisition; | |||
| use App\Http\Controllers\Web\WebController; | |||
| use App\Logics\QRService\QRCryptoLogic; | |||
| use App\Models\HtpmsCustomer\QRService\AcquisitionTicketToken; | |||
| use Illuminate\Http\JsonResponse; | |||
| use Illuminate\Http\Request; | |||
| @@ -43,6 +44,7 @@ class GetAcquisitionTokenController extends WebController | |||
| $res = [ | |||
| "token" => $token->token, | |||
| ]; | |||
| 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; | |||
| use App\Models\ColumnName; | |||
| use App\Util\DateUtil; | |||
| use Illuminate\Database\Eloquent\Model; | |||
| use Illuminate\Database\Query\Builder; | |||
| @@ -20,6 +21,8 @@ class DiscountTicket extends Model | |||
| protected $visible = [ | |||
| self::COL_NAME_TICKET_NAME, | |||
| 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('/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/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); | |||
| } | |||
| } | |||