[PROMOTE] dev -> demo:綠界電子發票設定條件式必填驗證
1. [FEAT] 綠界電子發票設定整組選填一旦啟用即全欄必填:store/update 加入 required_with 群組驗證、email 格式驗證、三語系訊息與表單動態必填提示。
This commit is contained in:
commit
8256fcb623
@ -51,7 +51,7 @@ class PaymentConfigController extends AdminController
|
||||
'name' => 'required|string|max:255',
|
||||
'company_id' => 'nullable|exists:companies,id',
|
||||
'settings' => 'required|array',
|
||||
]);
|
||||
] + $this->ecpayInvoiceRules(), $this->ecpayInvoiceMessages());
|
||||
|
||||
PaymentConfig::create([
|
||||
'name' => $request->name,
|
||||
@ -83,7 +83,7 @@ class PaymentConfigController extends AdminController
|
||||
'name' => 'required|string|max:255',
|
||||
'company_id' => 'nullable|exists:companies,id',
|
||||
'settings' => 'required|array',
|
||||
]);
|
||||
] + $this->ecpayInvoiceRules(), $this->ecpayInvoiceMessages());
|
||||
|
||||
$paymentConfig->update([
|
||||
'name' => $request->name,
|
||||
@ -105,4 +105,30 @@ class PaymentConfigController extends AdminController
|
||||
return redirect()->route('admin.basic-settings.payment-configs.index')
|
||||
->with('success', __('Payment Configuration deleted successfully.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 綠界電子發票群組驗證規則:整組選填,但只要填了任一欄,
|
||||
* store_id / hash_key / hash_iv / email 即全部必填(綠界開立發票需金鑰齊備,
|
||||
* 且 email 為「電話/信箱擇一」的唯一來源,缺一即無法開立)。
|
||||
* 依賴 ConvertEmptyStringsToNull middleware:空欄送出為 null,required_with 不會誤觸發。
|
||||
*/
|
||||
private function ecpayInvoiceRules(): array
|
||||
{
|
||||
$g = 'settings.ecpay_invoice';
|
||||
return [
|
||||
"{$g}.store_id" => "nullable|string|max:20|required_with:{$g}.hash_key,{$g}.hash_iv,{$g}.email",
|
||||
"{$g}.hash_key" => "nullable|string|max:64|required_with:{$g}.store_id,{$g}.hash_iv,{$g}.email",
|
||||
"{$g}.hash_iv" => "nullable|string|max:64|required_with:{$g}.store_id,{$g}.hash_key,{$g}.email",
|
||||
"{$g}.email" => "nullable|email|max:100|required_with:{$g}.store_id,{$g}.hash_key,{$g}.hash_iv",
|
||||
];
|
||||
}
|
||||
|
||||
/** 綠界電子發票群組的驗證訊息(三語系)。 */
|
||||
private function ecpayInvoiceMessages(): array
|
||||
{
|
||||
return [
|
||||
'settings.ecpay_invoice.*.required_with' => __('ECPay e-invoice is optional, but once any field is filled, Store ID / Hash Key / Hash IV / Email are all required.'),
|
||||
'settings.ecpay_invoice.email.email' => __('Please enter a valid ECPay e-invoice notification email.'),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@ -609,6 +609,7 @@
|
||||
"EASY_MERCHANT_ID": "EASY_MERCHANT_ID (EasyWallet)",
|
||||
"ECPay Invoice": "ECPay Invoice",
|
||||
"ECPay Invoice Settings Description": "ECPay Invoice Settings Description",
|
||||
"ECPay e-invoice is optional, but once any field is filled, Store ID / Hash Key / Hash IV / Email are all required.": "ECPay e-invoice is optional, but once any field is filled, Store ID / Hash Key / Hash IV / Email are all required.",
|
||||
"ECPay has no such invoice; marked as pending re-issue": "ECPay has no such invoice; marked as pending re-issue",
|
||||
"ECPay query failed": "ECPay query failed",
|
||||
"ESUN": "ESUN",
|
||||
@ -1404,6 +1405,7 @@
|
||||
"Optional notes...": "Optional notes...",
|
||||
"Optional remarks": "Optional remarks",
|
||||
"Optional remarks...": "Optional remarks...",
|
||||
"Optional. If you fill in any field, all fields below become required.": "Optional. If you fill in any field, all fields below become required.",
|
||||
"Or Choose Custom Date": "Or Choose Custom Date",
|
||||
"Order Details": "Order Details",
|
||||
"Order Info": "Order Info",
|
||||
@ -1536,6 +1538,7 @@
|
||||
"Please check the form for errors.": "Please check the form for errors.",
|
||||
"Please confirm the details below": "Please confirm the details below",
|
||||
"Please enter Webhook URL first.": "Please enter Webhook URL first.",
|
||||
"Please enter a valid ECPay e-invoice notification email.": "Please enter a valid ECPay e-invoice notification email.",
|
||||
"Please enter address first": "Please enter address first",
|
||||
"Please enter configuration name": "Please enter configuration name",
|
||||
"Please enter machine flavor": "Please enter machine flavor",
|
||||
|
||||
@ -609,6 +609,7 @@
|
||||
"EASY_MERCHANT_ID": "EASY_MERCHANT_ID (悠遊付)",
|
||||
"ECPay Invoice": "ECPay 電子領収書",
|
||||
"ECPay Invoice Settings Description": "ECPay 電子領収書設定",
|
||||
"ECPay e-invoice is optional, but once any field is filled, Store ID / Hash Key / Hash IV / Email are all required.": "ECPay 電子インボイスは任意ですが、いずれかの項目を入力した場合は、店舗 ID / Hash Key / Hash IV / Email がすべて必須になります。",
|
||||
"ECPay has no such invoice; marked as pending re-issue": "ECPay has no such invoice; marked as pending re-issue",
|
||||
"ECPay query failed": "ECPay query failed",
|
||||
"ESUN": "玉山銀行",
|
||||
@ -1404,6 +1405,7 @@
|
||||
"Optional notes...": "任意のメモ...",
|
||||
"Optional remarks": "任意の備考",
|
||||
"Optional remarks...": "任意の備考...",
|
||||
"Optional. If you fill in any field, all fields below become required.": "任意。いずれかの項目を入力すると、以下のすべての項目が必須になります。",
|
||||
"Or Choose Custom Date": "または日付を選択",
|
||||
"Order Details": "注文詳細",
|
||||
"Order Info": "注文情報",
|
||||
@ -1536,6 +1538,7 @@
|
||||
"Please check the form for errors.": "フォームのエラーを確認してください。",
|
||||
"Please confirm the details below": "以下の詳細を確認してください",
|
||||
"Please enter Webhook URL first.": "最初にWebhook URLを入力してください。",
|
||||
"Please enter a valid ECPay e-invoice notification email.": "有効な ECPay 電子インボイス通知用メールアドレスを入力してください。",
|
||||
"Please enter address first": "先に住所を入力してください",
|
||||
"Please enter configuration name": "設定名を入力してください",
|
||||
"Please enter machine flavor": "機台フレーバーを入力してください",
|
||||
|
||||
@ -609,6 +609,7 @@
|
||||
"EASY_MERCHANT_ID": "EASY_MERCHANT_ID (悠遊付)",
|
||||
"ECPay Invoice": "綠界電子發票",
|
||||
"ECPay Invoice Settings Description": "綠界科技電子發票設定",
|
||||
"ECPay e-invoice is optional, but once any field is filled, Store ID / Hash Key / Hash IV / Email are all required.": "綠界電子發票為選填,但只要填寫任一欄位,特店 ID / Hash Key / Hash IV / Email 即全部必填。",
|
||||
"ECPay has no such invoice; marked as pending re-issue": "綠界查無此發票,已標記為待補開",
|
||||
"ECPay query failed": "綠界查詢失敗",
|
||||
"ESUN": "玉山銀行",
|
||||
@ -1404,6 +1405,7 @@
|
||||
"Optional notes...": "備註內容(選填)...",
|
||||
"Optional remarks": "選填備註",
|
||||
"Optional remarks...": "選填備註...",
|
||||
"Optional. If you fill in any field, all fields below become required.": "選填。只要填寫任一欄位,以下欄位即全部必填。",
|
||||
"Or Choose Custom Date": "或選擇自訂日期",
|
||||
"Order Details": "訂單詳情",
|
||||
"Order Info": "單據資訊",
|
||||
@ -1536,6 +1538,7 @@
|
||||
"Please check the form for errors.": "請檢查欄位內容是否正確。",
|
||||
"Please confirm the details below": "請確認以下詳細資訊",
|
||||
"Please enter Webhook URL first.": "請先輸入 Webhook 網址。",
|
||||
"Please enter a valid ECPay e-invoice notification email.": "請輸入有效的綠界電子發票通知 Email。",
|
||||
"Please enter address first": "請先輸入地址",
|
||||
"Please enter configuration name": "請輸入設定名稱",
|
||||
"Please enter machine flavor": "請輸入機台風味",
|
||||
|
||||
@ -98,22 +98,27 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="space-y-6">
|
||||
<div class="space-y-6" x-data="{ vals: { store_id: '', hash_key: '', hash_iv: '', email: '' }, get anyFilled() { return Object.values(this.vals).some(v => (v || '').trim() !== '') } }">
|
||||
<p class="text-[11px] font-bold text-slate-400 leading-relaxed -mt-2">{{ __('Optional. If you fill in any field, all fields below become required.') }}</p>
|
||||
<div>
|
||||
<label class="block text-[11px] font-black text-slate-400 uppercase tracking-[0.2em] mb-2">{{ __('Invoice Store ID') }}</label>
|
||||
<input type="text" name="settings[ecpay_invoice][store_id]" class="luxury-input w-full">
|
||||
<label class="block text-[11px] font-black text-slate-400 uppercase tracking-[0.2em] mb-2">{{ __('Invoice Store ID') }}<span x-show="anyFilled" class="text-rose-500 ml-0.5">*</span></label>
|
||||
<input type="text" name="settings[ecpay_invoice][store_id]" x-model="vals.store_id" class="luxury-input w-full">
|
||||
@error('settings.ecpay_invoice.store_id')<p class="mt-1.5 text-[11px] font-bold text-rose-500">{{ $message }}</p>@enderror
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-[11px] font-black text-slate-400 uppercase tracking-[0.2em] mb-2">{{ __('Invoice HashKey') }}</label>
|
||||
<input type="text" name="settings[ecpay_invoice][hash_key]" class="luxury-input w-full">
|
||||
<label class="block text-[11px] font-black text-slate-400 uppercase tracking-[0.2em] mb-2">{{ __('Invoice HashKey') }}<span x-show="anyFilled" class="text-rose-500 ml-0.5">*</span></label>
|
||||
<input type="text" name="settings[ecpay_invoice][hash_key]" x-model="vals.hash_key" class="luxury-input w-full">
|
||||
@error('settings.ecpay_invoice.hash_key')<p class="mt-1.5 text-[11px] font-bold text-rose-500">{{ $message }}</p>@enderror
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-[11px] font-black text-slate-400 uppercase tracking-[0.2em] mb-2">{{ __('Invoice HashIV') }}</label>
|
||||
<input type="text" name="settings[ecpay_invoice][hash_iv]" class="luxury-input w-full">
|
||||
<label class="block text-[11px] font-black text-slate-400 uppercase tracking-[0.2em] mb-2">{{ __('Invoice HashIV') }}<span x-show="anyFilled" class="text-rose-500 ml-0.5">*</span></label>
|
||||
<input type="text" name="settings[ecpay_invoice][hash_iv]" x-model="vals.hash_iv" class="luxury-input w-full">
|
||||
@error('settings.ecpay_invoice.hash_iv')<p class="mt-1.5 text-[11px] font-bold text-rose-500">{{ $message }}</p>@enderror
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-[11px] font-black text-slate-400 uppercase tracking-[0.2em] mb-2">{{ __('Invoice Notification Email') }}</label>
|
||||
<input type="text" name="settings[ecpay_invoice][email]" class="luxury-input w-full">
|
||||
<label class="block text-[11px] font-black text-slate-400 uppercase tracking-[0.2em] mb-2">{{ __('Invoice Notification Email') }}<span x-show="anyFilled" class="text-rose-500 ml-0.5">*</span></label>
|
||||
<input type="text" name="settings[ecpay_invoice][email]" x-model="vals.email" class="luxury-input w-full">
|
||||
@error('settings.ecpay_invoice.email')<p class="mt-1.5 text-[11px] font-bold text-rose-500">{{ $message }}</p>@enderror
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -102,22 +102,27 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="space-y-6">
|
||||
<div class="space-y-6" x-data="{ vals: { store_id: @js($settings['ecpay_invoice']['store_id'] ?? ''), hash_key: @js($settings['ecpay_invoice']['hash_key'] ?? ''), hash_iv: @js($settings['ecpay_invoice']['hash_iv'] ?? ''), email: @js($settings['ecpay_invoice']['email'] ?? '') }, get anyFilled() { return Object.values(this.vals).some(v => (v || '').trim() !== '') } }">
|
||||
<p class="text-[11px] font-bold text-slate-400 leading-relaxed -mt-2">{{ __('Optional. If you fill in any field, all fields below become required.') }}</p>
|
||||
<div>
|
||||
<label class="block text-[11px] font-black text-slate-400 uppercase tracking-[0.2em] mb-2">{{ __('Invoice Store ID') }}</label>
|
||||
<input type="text" name="settings[ecpay_invoice][store_id]" value="{{ $settings['ecpay_invoice']['store_id'] ?? '' }}" class="luxury-input w-full">
|
||||
<label class="block text-[11px] font-black text-slate-400 uppercase tracking-[0.2em] mb-2">{{ __('Invoice Store ID') }}<span x-show="anyFilled" class="text-rose-500 ml-0.5">*</span></label>
|
||||
<input type="text" name="settings[ecpay_invoice][store_id]" x-model="vals.store_id" value="{{ $settings['ecpay_invoice']['store_id'] ?? '' }}" class="luxury-input w-full">
|
||||
@error('settings.ecpay_invoice.store_id')<p class="mt-1.5 text-[11px] font-bold text-rose-500">{{ $message }}</p>@enderror
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-[11px] font-black text-slate-400 uppercase tracking-[0.2em] mb-2">{{ __('Invoice HashKey') }}</label>
|
||||
<input type="text" name="settings[ecpay_invoice][hash_key]" value="{{ $settings['ecpay_invoice']['hash_key'] ?? '' }}" class="luxury-input w-full">
|
||||
<label class="block text-[11px] font-black text-slate-400 uppercase tracking-[0.2em] mb-2">{{ __('Invoice HashKey') }}<span x-show="anyFilled" class="text-rose-500 ml-0.5">*</span></label>
|
||||
<input type="text" name="settings[ecpay_invoice][hash_key]" x-model="vals.hash_key" value="{{ $settings['ecpay_invoice']['hash_key'] ?? '' }}" class="luxury-input w-full">
|
||||
@error('settings.ecpay_invoice.hash_key')<p class="mt-1.5 text-[11px] font-bold text-rose-500">{{ $message }}</p>@enderror
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-[11px] font-black text-slate-400 uppercase tracking-[0.2em] mb-2">{{ __('Invoice HashIV') }}</label>
|
||||
<input type="text" name="settings[ecpay_invoice][hash_iv]" value="{{ $settings['ecpay_invoice']['hash_iv'] ?? '' }}" class="luxury-input w-full">
|
||||
<label class="block text-[11px] font-black text-slate-400 uppercase tracking-[0.2em] mb-2">{{ __('Invoice HashIV') }}<span x-show="anyFilled" class="text-rose-500 ml-0.5">*</span></label>
|
||||
<input type="text" name="settings[ecpay_invoice][hash_iv]" x-model="vals.hash_iv" value="{{ $settings['ecpay_invoice']['hash_iv'] ?? '' }}" class="luxury-input w-full">
|
||||
@error('settings.ecpay_invoice.hash_iv')<p class="mt-1.5 text-[11px] font-bold text-rose-500">{{ $message }}</p>@enderror
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-[11px] font-black text-slate-400 uppercase tracking-[0.2em] mb-2">{{ __('Invoice Notification Email') }}</label>
|
||||
<input type="text" name="settings[ecpay_invoice][email]" value="{{ $settings['ecpay_invoice']['email'] ?? '' }}" class="luxury-input w-full">
|
||||
<label class="block text-[11px] font-black text-slate-400 uppercase tracking-[0.2em] mb-2">{{ __('Invoice Notification Email') }}<span x-show="anyFilled" class="text-rose-500 ml-0.5">*</span></label>
|
||||
<input type="text" name="settings[ecpay_invoice][email]" x-model="vals.email" value="{{ $settings['ecpay_invoice']['email'] ?? '' }}" class="luxury-input w-full">
|
||||
@error('settings.ecpay_invoice.email')<p class="mt-1.5 text-[11px] font-bold text-rose-500">{{ $message }}</p>@enderror
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user