chore: [env] .env.example 업데이트 및 .gitignore 정리
- .env.example을 SAM 프로젝트 실제 키 구조로 업데이트 - .gitignore에 !.env.example 예외 추가 - GCS_* 중복 키 제거, Gemini/Claude/Vertex 키 섹션 추가
This commit is contained in:
@@ -8,14 +8,13 @@
|
||||
use App\Models\Tenants\Tenant;
|
||||
use App\Traits\Auditable;
|
||||
use App\Traits\BelongsToTenant;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Spatie\Permission\Models\Role as SpatieRole;
|
||||
|
||||
/**
|
||||
* @mixin IdeHelperRole
|
||||
*/
|
||||
class Role extends SpatieRole
|
||||
class Role extends Model
|
||||
{
|
||||
use Auditable, BelongsToTenant, SoftDeletes;
|
||||
|
||||
@@ -35,6 +34,14 @@ class Role extends SpatieRole
|
||||
'tenant_id' => 'integer',
|
||||
];
|
||||
|
||||
/**
|
||||
* 관계: 메뉴 권한 (다대다)
|
||||
*/
|
||||
public function menuPermissions()
|
||||
{
|
||||
return $this->hasMany(RoleMenuPermission::class, 'role_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* 관계: 테넌트
|
||||
*/
|
||||
@@ -54,7 +61,7 @@ public function userRoles()
|
||||
/**
|
||||
* 관계: 사용자 (user_roles 테이블 통해)
|
||||
*/
|
||||
public function users(): BelongsToMany
|
||||
public function users()
|
||||
{
|
||||
return $this->belongsToMany(
|
||||
User::class,
|
||||
@@ -64,6 +71,19 @@ public function users(): BelongsToMany
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 관계: 권한 (role_has_permissions 테이블 통해)
|
||||
*/
|
||||
public function permissions()
|
||||
{
|
||||
return $this->belongsToMany(
|
||||
Permission::class,
|
||||
'role_has_permissions',
|
||||
'role_id',
|
||||
'permission_id'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 스코프: 공개된 역할만
|
||||
*/
|
||||
|
||||
@@ -40,34 +40,16 @@ class BankAccount extends Model
|
||||
'account_number',
|
||||
'account_holder',
|
||||
'account_name',
|
||||
'account_type',
|
||||
'balance',
|
||||
'currency',
|
||||
'opened_at',
|
||||
'last_transaction_at',
|
||||
'branch_name',
|
||||
'memo',
|
||||
'status',
|
||||
'assigned_user_id',
|
||||
'is_primary',
|
||||
'sort_order',
|
||||
'created_by',
|
||||
'updated_by',
|
||||
'deleted_by',
|
||||
];
|
||||
|
||||
protected $hidden = [
|
||||
'created_by',
|
||||
'updated_by',
|
||||
'deleted_by',
|
||||
'deleted_at',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'balance' => 'decimal:2',
|
||||
'is_primary' => 'boolean',
|
||||
'opened_at' => 'date',
|
||||
'last_transaction_at' => 'datetime',
|
||||
];
|
||||
|
||||
protected $attributes = [
|
||||
@@ -107,69 +89,22 @@ public function updater(): BelongsTo
|
||||
// 헬퍼 메서드
|
||||
// =========================================================================
|
||||
|
||||
// =========================================================================
|
||||
// Accessors
|
||||
// =========================================================================
|
||||
|
||||
/**
|
||||
* 포맷된 잔액
|
||||
*/
|
||||
public function getFormattedBalanceAttribute(): string
|
||||
{
|
||||
$amount = abs($this->balance ?? 0);
|
||||
|
||||
if ($amount >= 100000000) {
|
||||
return number_format($amount / 100000000, 1).'억원';
|
||||
} elseif ($amount >= 10000000) {
|
||||
return number_format($amount / 10000000, 0).'천만원';
|
||||
} elseif ($amount >= 10000) {
|
||||
return number_format($amount / 10000, 0).'만원';
|
||||
}
|
||||
|
||||
return number_format($amount).'원';
|
||||
}
|
||||
|
||||
/**
|
||||
* 마스킹된 계좌번호
|
||||
* 마스킹된 계좌번호 조회
|
||||
*/
|
||||
public function getMaskedAccountNumber(): string
|
||||
{
|
||||
$number = $this->account_number;
|
||||
if (strlen($number) <= 6) {
|
||||
return $number;
|
||||
$length = strlen($this->account_number);
|
||||
if ($length <= 4) {
|
||||
return $this->account_number;
|
||||
}
|
||||
|
||||
return substr($number, 0, 3).'-***-'.substr($number, -4);
|
||||
$visibleEnd = substr($this->account_number, -4);
|
||||
$maskedPart = str_repeat('*', $length - 4);
|
||||
|
||||
return $maskedPart.$visibleEnd;
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// Scopes
|
||||
// =========================================================================
|
||||
|
||||
public function scopeActive($query)
|
||||
{
|
||||
return $query->where('status', 'active');
|
||||
}
|
||||
|
||||
public function scopePrimary($query)
|
||||
{
|
||||
return $query->where('is_primary', true);
|
||||
}
|
||||
|
||||
public function scopeByType($query, string $accountType)
|
||||
{
|
||||
return $query->where('account_type', $accountType);
|
||||
}
|
||||
|
||||
public function scopeOrdered($query)
|
||||
{
|
||||
return $query->orderBy('sort_order')->orderBy('bank_name');
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// 헬퍼 메서드
|
||||
// =========================================================================
|
||||
|
||||
/**
|
||||
* 활성 상태 여부
|
||||
*/
|
||||
@@ -187,13 +122,10 @@ public function toggleStatus(): void
|
||||
}
|
||||
|
||||
/**
|
||||
* 잔액 업데이트
|
||||
* 대표계좌로 설정
|
||||
*/
|
||||
public function updateBalance(float $newBalance): void
|
||||
public function setAsPrimary(): void
|
||||
{
|
||||
$this->update([
|
||||
'balance' => $newBalance,
|
||||
'last_transaction_at' => now(),
|
||||
]);
|
||||
$this->is_primary = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Tenants;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class BarobillConfig extends Model
|
||||
{
|
||||
use SoftDeletes;
|
||||
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'environment',
|
||||
'cert_key',
|
||||
'corp_num',
|
||||
'base_url',
|
||||
'description',
|
||||
'is_active',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'is_active' => 'boolean',
|
||||
];
|
||||
|
||||
public static function getActiveTest(): ?self
|
||||
{
|
||||
return self::where('environment', 'test')->first();
|
||||
}
|
||||
|
||||
public static function getActiveProduction(): ?self
|
||||
{
|
||||
return self::where('environment', 'production')->first();
|
||||
}
|
||||
|
||||
public static function getActive(bool $isTestMode = false): ?self
|
||||
{
|
||||
return $isTestMode ? self::getActiveTest() : self::getActiveProduction();
|
||||
}
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Tenants;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class BarobillMember extends Model
|
||||
{
|
||||
use SoftDeletes;
|
||||
|
||||
protected $table = 'barobill_members';
|
||||
|
||||
protected $fillable = [
|
||||
'tenant_id',
|
||||
'biz_no',
|
||||
'corp_name',
|
||||
'ceo_name',
|
||||
'addr',
|
||||
'biz_type',
|
||||
'biz_class',
|
||||
'barobill_id',
|
||||
'barobill_pwd',
|
||||
'manager_name',
|
||||
'manager_email',
|
||||
'manager_hp',
|
||||
'status',
|
||||
'server_mode',
|
||||
'last_sales_fetch_at',
|
||||
'last_purchases_fetch_at',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'created_at' => 'datetime',
|
||||
'updated_at' => 'datetime',
|
||||
'deleted_at' => 'datetime',
|
||||
'barobill_pwd' => 'encrypted',
|
||||
'last_sales_fetch_at' => 'datetime',
|
||||
'last_purchases_fetch_at' => 'datetime',
|
||||
];
|
||||
|
||||
protected $hidden = [
|
||||
'barobill_pwd',
|
||||
];
|
||||
|
||||
public function tenant(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Tenant::class);
|
||||
}
|
||||
|
||||
public function getFormattedBizNoAttribute(): string
|
||||
{
|
||||
$bizNo = preg_replace('/[^0-9]/', '', $this->biz_no);
|
||||
if (strlen($bizNo) === 10) {
|
||||
return substr($bizNo, 0, 3).'-'.substr($bizNo, 3, 2).'-'.substr($bizNo, 5);
|
||||
}
|
||||
|
||||
return $this->biz_no;
|
||||
}
|
||||
|
||||
public function isTestMode(): bool
|
||||
{
|
||||
return $this->server_mode !== 'production';
|
||||
}
|
||||
}
|
||||
@@ -22,17 +22,8 @@
|
||||
* @property string $expiry_date
|
||||
* @property string|null $card_password_encrypted
|
||||
* @property string $card_name
|
||||
* @property string|null $card_type
|
||||
* @property string|null $alias
|
||||
* @property string|null $cvc_encrypted
|
||||
* @property int|null $payment_day
|
||||
* @property float|null $total_limit
|
||||
* @property float|null $used_amount
|
||||
* @property float|null $remaining_limit
|
||||
* @property string $status
|
||||
* @property bool $is_manual
|
||||
* @property int|null $assigned_user_id
|
||||
* @property string|null $memo
|
||||
* @property int|null $created_by
|
||||
* @property int|null $updated_by
|
||||
* @property int|null $deleted_by
|
||||
@@ -46,22 +37,13 @@ class Card extends Model
|
||||
protected $fillable = [
|
||||
'tenant_id',
|
||||
'card_company',
|
||||
'card_type',
|
||||
'card_number_encrypted',
|
||||
'card_number_last4',
|
||||
'expiry_date',
|
||||
'card_password_encrypted',
|
||||
'card_name',
|
||||
'alias',
|
||||
'cvc_encrypted',
|
||||
'payment_day',
|
||||
'total_limit',
|
||||
'used_amount',
|
||||
'remaining_limit',
|
||||
'status',
|
||||
'is_manual',
|
||||
'assigned_user_id',
|
||||
'memo',
|
||||
'created_by',
|
||||
'updated_by',
|
||||
'deleted_by',
|
||||
@@ -70,29 +52,12 @@ class Card extends Model
|
||||
protected $hidden = [
|
||||
'card_number_encrypted',
|
||||
'card_password_encrypted',
|
||||
'cvc_encrypted',
|
||||
];
|
||||
|
||||
protected $appends = [
|
||||
'csv',
|
||||
];
|
||||
|
||||
protected $attributes = [
|
||||
'status' => 'active',
|
||||
'is_manual' => false,
|
||||
];
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'payment_day' => 'integer',
|
||||
'total_limit' => 'decimal:2',
|
||||
'used_amount' => 'decimal:2',
|
||||
'remaining_limit' => 'decimal:2',
|
||||
'is_manual' => 'boolean',
|
||||
];
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// 관계 정의
|
||||
// =========================================================================
|
||||
@@ -162,38 +127,6 @@ public function getDecryptedCardPassword(): ?string
|
||||
: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* CVC/CVV 암호화 설정
|
||||
*/
|
||||
public function setCvc(?string $cvc): void
|
||||
{
|
||||
$this->cvc_encrypted = $cvc
|
||||
? Crypt::encryptString($cvc)
|
||||
: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* CVC/CVV 복호화 조회
|
||||
*/
|
||||
public function getDecryptedCvc(): ?string
|
||||
{
|
||||
return $this->cvc_encrypted
|
||||
? Crypt::decryptString($this->cvc_encrypted)
|
||||
: null;
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// Accessor (JSON 직렬화용)
|
||||
// =========================================================================
|
||||
|
||||
/**
|
||||
* CSV(CVC) 복호화 값 — $appends로 JSON 응답에 포함
|
||||
*/
|
||||
public function getCsvAttribute(): ?string
|
||||
{
|
||||
return $this->getDecryptedCvc();
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// 헬퍼 메서드
|
||||
// =========================================================================
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Tenants;
|
||||
|
||||
use App\Traits\BelongsToTenant;
|
||||
use App\Traits\ModelTrait;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
/**
|
||||
* 법인카드 모델
|
||||
*
|
||||
* @property int $id
|
||||
* @property int $tenant_id
|
||||
* @property string $card_name
|
||||
* @property string $card_company
|
||||
* @property string $card_number
|
||||
* @property string $card_type
|
||||
* @property int $payment_day
|
||||
* @property float $credit_limit
|
||||
* @property float $current_usage
|
||||
* @property string $card_holder_name
|
||||
* @property string $actual_user
|
||||
* @property string|null $expiry_date
|
||||
* @property string|null $cvc
|
||||
* @property string $status
|
||||
* @property string|null $memo
|
||||
*/
|
||||
class CorporateCard extends Model
|
||||
{
|
||||
use BelongsToTenant, ModelTrait, SoftDeletes;
|
||||
|
||||
protected $table = 'corporate_cards';
|
||||
|
||||
protected $fillable = [
|
||||
'tenant_id',
|
||||
'card_name',
|
||||
'card_company',
|
||||
'card_number',
|
||||
'card_type',
|
||||
'payment_day',
|
||||
'credit_limit',
|
||||
'current_usage',
|
||||
'card_holder_name',
|
||||
'actual_user',
|
||||
'expiry_date',
|
||||
'cvc',
|
||||
'status',
|
||||
'memo',
|
||||
];
|
||||
|
||||
protected $hidden = [
|
||||
'cvc',
|
||||
'deleted_at',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'payment_day' => 'integer',
|
||||
'credit_limit' => 'decimal:2',
|
||||
'current_usage' => 'decimal:2',
|
||||
];
|
||||
|
||||
protected $attributes = [
|
||||
'status' => 'active',
|
||||
'payment_day' => 15,
|
||||
'credit_limit' => 0,
|
||||
'current_usage' => 0,
|
||||
];
|
||||
|
||||
// =========================================================================
|
||||
// Scopes
|
||||
// =========================================================================
|
||||
|
||||
public function scopeActive($query)
|
||||
{
|
||||
return $query->where('status', 'active');
|
||||
}
|
||||
|
||||
public function scopeByType($query, string $cardType)
|
||||
{
|
||||
return $query->where('card_type', $cardType);
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// 헬퍼 메서드
|
||||
// =========================================================================
|
||||
|
||||
public function isActive(): bool
|
||||
{
|
||||
return $this->status === 'active';
|
||||
}
|
||||
|
||||
public function toggleStatus(): void
|
||||
{
|
||||
$this->status = $this->status === 'active' ? 'inactive' : 'active';
|
||||
}
|
||||
|
||||
/**
|
||||
* 마스킹된 카드번호
|
||||
*/
|
||||
public function getMaskedCardNumber(): string
|
||||
{
|
||||
$number = preg_replace('/[^0-9]/', '', $this->card_number);
|
||||
if (strlen($number) <= 4) {
|
||||
return $this->card_number;
|
||||
}
|
||||
|
||||
return '****-****-****-'.substr($number, -4);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user