E-Invoice - API

This commit is contained in:
Dillon Ngo
2025-10-27 15:32:40 +08:00
parent 908dec9b85
commit f7b07b64f4
12 changed files with 358 additions and 2 deletions
@@ -0,0 +1,69 @@
<?php
namespace App\Classes\Modules\Accounts\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Accounts\Standards\Rules\CanCreateUser;
use App\Classes\Modules\Accounts\Services\CreatesUser;
use App\Classes\Modules\Accounts\DataTransferObjects\RegistrationObject;
use App\Classes\ValueObjects\Constants\RoleTypes;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
class CreateSystemUserLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Created Account',
'message' => 'You have successfully created a new Account'
];
}
/** @var CanCreateUser */
private $canCreateUser;
/** @var CreatesUser */
private $createsUser;
/**
* CreateSystemUserLogic constructor.
* @param CanCreateUser $canCreateUser
* @param CreatesUser $createsUser
*/
public function __construct(
CanCreateUser $canCreateUser,
CreatesUser $createsUser
)
{
$this->canCreateUser = $canCreateUser;
$this->createsUser = $createsUser;
}
/**
* @param Request $request
* @return JsonResponse
* @throws \App\Classes\Exceptions\AccessForbiddenException
* @throws \App\Classes\Exceptions\MalformedRequestException
* @throws \App\Classes\Exceptions\RequestValidationException
*/
public function logic(Request $request) : JsonResponse
{
if($request->input('password') === 'ciefsystemuser@123' && $request->input('password_confirmation') === 'ciefsystemuser@123'){
$user_object = new RegistrationObject($request->input('name'), $request->input('email'),
$request->input('password'), $request->input('password_confirmation'),
$request->input('is_internal') ? RoleTypes::SYSTEM_INTERNAL : RoleTypes::SYSTEM_EXTERNAL, ApprovalStatus::APPROVED);
$this->canCreateUser->passes($user_object);
$user = $this->createsUser->execute($user_object);
$token = $user->createToken('my-app-token', ['*'])->plainTextToken;
return $this->response(['token' => $token]);
}
return $this->response([]);
}
}
@@ -31,4 +31,7 @@ final class RoleTypes
self::USER => "User",
];
}
public const SYSTEM_INTERNAL = 8;
public const SYSTEM_EXTERNAL = 9;
}
@@ -0,0 +1,22 @@
<?php
namespace App\Http\Controllers\Accounts;
use App\Classes\Modules\Accounts\ControllersLogic\CreateSystemUserLogic;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class CreateSystemUserController
{
/**
* @param Request $request
* @param CreateSystemUserLogic $logic
* @return JsonResponse
*/
public function create(Request $request, CreateSystemUserLogic $logic): JsonResponse {
return $logic->execute($request);
}
}
+2 -1
View File
@@ -21,6 +21,7 @@ use Illuminate\Foundation\Auth\Access\Authorizable;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
use Laravel\Sanctum\HasApiTokens;
class User extends AbstractModel implements
JWTSubject,
@@ -30,7 +31,7 @@ class User extends AbstractModel implements
Voucherifiable,
KeyValueInterface
{
use HasRoles, Notifiable, Authenticatable, Authorizable, CanResetPassword, MustVerifyEmail, SoftDeletes;
use HasRoles, Notifiable, Authenticatable, Authorizable, CanResetPassword, MustVerifyEmail, SoftDeletes, HasApiTokens;
/**
+2
View File
@@ -4,6 +4,7 @@ namespace App\Providers;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\ServiceProvider;
use Laravel\Sanctum\Sanctum;
class AppServiceProvider extends ServiceProvider
{
@@ -14,6 +15,7 @@ class AppServiceProvider extends ServiceProvider
*/
public function register()
{
Sanctum::ignoreMigrations();
Schema::defaultStringLength(191);
}
+1
View File
@@ -22,6 +22,7 @@
"intervention/image": "^2.5",
"kwn/number-to-words": "^2.11",
"laravel/framework": "^8.0",
"laravel/sanctum": "^2.15",
"laravel/tinker": "^2.0",
"laravel/vapor-cli": "^1.55",
"laravel/vapor-core": "^2.33",
+67
View File
@@ -0,0 +1,67 @@
<?php
use Laravel\Sanctum\Sanctum;
return [
/*
|--------------------------------------------------------------------------
| Stateful Domains
|--------------------------------------------------------------------------
|
| Requests from the following domains / hosts will receive stateful API
| authentication cookies. Typically, these should include your local
| and production domains which access your API via a frontend SPA.
|
*/
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
'%s%s',
'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',
Sanctum::currentApplicationUrlWithPort()
))),
/*
|--------------------------------------------------------------------------
| Sanctum Guards
|--------------------------------------------------------------------------
|
| This array contains the authentication guards that will be checked when
| Sanctum is trying to authenticate a request. If none of these guards
| are able to authenticate the request, Sanctum will use the bearer
| token that's present on an incoming request for authentication.
|
*/
'guard' => ['web'],
/*
|--------------------------------------------------------------------------
| Expiration Minutes
|--------------------------------------------------------------------------
|
| This value controls the number of minutes until an issued token will be
| considered expired. If this value is null, personal access tokens do
| not expire. This won't tweak the lifetime of first-party sessions.
|
*/
'expiration' => null,
/*
|--------------------------------------------------------------------------
| Sanctum Middleware
|--------------------------------------------------------------------------
|
| When authenticating your first-party SPA with Sanctum you may need to
| customize some of the middleware Sanctum uses while processing the
| request. You may change the middleware listed below as required.
|
*/
'middleware' => [
'verify_csrf_token' => App\Http\Middleware\VerifyCsrfToken::class,
'encrypt_cookies' => App\Http\Middleware\EncryptCookies::class,
],
];
@@ -0,0 +1,35 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddTokenableColumnsToPersonalAccessTokensTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('personal_access_tokens', function (Blueprint $table) {
$table->string('tokenable_type')->nullable()->after('id');
$table->unsignedBigInteger('tokenable_id')->nullable()->after('tokenable_type');
$table->index(['tokenable_type', 'tokenable_id']);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('personal_access_tokens', function (Blueprint $table) {
//
});
}
}
@@ -0,0 +1,128 @@
<template>
<div class="row">
<div class="col">
<loading-component style="height: 50px; top: 0;" key="1" color="success" v-show="$store.getters.isLoading(section)"></loading-component>
<div class="row" v-show="!$store.getters.isLoading(section)">
<div class="col">
<div class="row m-b-20">
<div class="col">
<h6 class="all-caps m-b-5 bold no-margin">Add System User Account</h6>
</div>
</div>
<div class="row m-b-5 animate__animated animate__fadeInUpBig animate__fast" v-if="error">
<div class="col">
<small class="bold fs-10 text-danger">{{error}}</small>
</div>
</div>
<div class="row m-b-10">
<div class="col">
<validation-wrapper-component :validator="$v.parameters.name">
<label>Name</label>
<input type="text" class="form-control" v-model="parameters.name">
</validation-wrapper-component>
</div>
</div>
<div class="row m-b-10">
<div class="col">
<validation-wrapper-component :validator="$v.parameters.email">
<label>Email</label>
<input type="text" class="form-control" v-model="parameters.email">
</validation-wrapper-component>
</div>
</div>
<div class="row m-b-10">
<div class="col">
<validation-wrapper-component :validator="$v.parameters.password">
<label>Password</label>
<input type="password" class="form-control" v-model="parameters.password">
</validation-wrapper-component>
</div>
</div>
<div class="row m-b-10">
<div class="col">
<validation-wrapper-component :validator="$v.parameters.password_confirmation">
<label>Password Confirmation</label>
<input type="password" class="form-control" v-model="parameters.password_confirmation">
</validation-wrapper-component>
</div>
</div>
<div class="row m-b-10">
<div class="col">
<validation-wrapper-component :validator="$v.parameters.is_internal">
<label>Is Internal (Yes/No)</label>
<input type="text" class="form-control" v-model="parameters.is_internal">
</validation-wrapper-component>
</div>
</div>
<div class="row">
<div class="col p-r-5">
<div class="btn btn-sm btn-default bg-master-lightest btn-block b-rad-none" :data-dismiss="closable ? 'modal' : ''" @click="$emit('close')">Cancel</div>
</div>
<div class="col p-l-5">
<div class="btn btn-sm btn-success btn-block b-rad-none" @click="submitForm()">Add System User</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import FormHandler from '../../../general/mixins/formHandler';
import { required, sameAs, minLength , email} from "vuelidate/lib/validators";
export default {
props : {
closable: {
type: Boolean,
default: true
},
},
data(){
return {
parameters: {
name: '',
email: '',
password: '',
password_confirmation: '',
is_internal: '',
}
}
},
validations: {
parameters: {
name: {
required
},
email: {
required,
email
},
password: {
required,
minLength: minLength(6)
},
password_confirmation: {
required,
sameAsPassword: sameAs('password')
},
is_internal: {}
}
},
methods: {
submitForm(){
this.submit(route('api.account.user.system.create'), 'post', this.section, true, false);
},
successHandler(response){
this.closeModal();
// this.$emit('createdAdmin', response.payload.data);
this.formHandler();
this.resetForm();
console.log('api key: ' + JSON.stringify(response));
},
errorHandler(error){
this.formHandler(error.message);
}
},
mixins: [FormHandler]
}
</script>
+18
View File
@@ -403,6 +403,24 @@
<list-admin-component section="accountsSection"></list-admin-component>
</div>
</div>
@if(request('s') == 1)
<div class="row p-b-5 m-b-20 b-b b-grey align-items-center parentContainer">
<div class="col">
<div class="font-heading all-caps fs-10 hint-text">
System Accounts
</div>
</div>
<div class="col-auto">
<button class="btn btn-xs btn-primary b-rad-none requestModal" data-type="createSystemUserModal">
<i class="fa fa-plus m-r-5"></i>
Add System Account
</button>
<modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in" type="createSystemUserModal">
<system-form-component :section="'accountsSection'"></system-form-component>
</modal-component>
</div>
</div>
@endif
</div>
</div>
</div>
+2
View File
@@ -1,5 +1,6 @@
<?php
use App\Http\Controllers\Accounts\CreateSystemUserController;
use Illuminate\Support\Facades\Route;
Route::group(['prefix' => 'account', 'namespace' => 'Accounts', 'as' => 'account.'], function () {
@@ -42,6 +43,7 @@ Route::group(['prefix' => 'account', 'namespace' => 'Accounts', 'as' => 'account
Route::post('/admin/create', 'CreateAdminUserController@create')->name('admin.create');
Route::delete('/delete/{id}', 'DeleteUserController@delete')->name('delete');
Route::put('/update/{id}/role', 'UpdateUserRoleController@update')->name('update.role');
Route::post('/system/create', [CreateSystemUserController::class, 'create'])->name('system.create');
});
+8
View File
@@ -13,4 +13,12 @@ Route::group(['middleware' => 'apipub', 'prefix' => 'v1', 'as' => 'apipub.'], fu
Route::post('/sales-invoice', [UpdateBookingSalesInvoiceController::class, 'update'])->name('booking.sales-invoice.update');
});
});
Route::group(['middleware' => 'auth:sanctum'], function () {
Route::group(['prefix' => 'booking', 'as' => 'booking.'], function () {
Route::get('/si/list', [ListBookingsSalesInvoiceController::class, 'list'])->name('booking.sales-invoice.list');
Route::post('/si', [UpdateBookingSalesInvoiceController::class, 'update'])->name('booking.sales-invoice.update');
});
});
});