diff --git a/app/Classes/Jobs/Commands/V2/ProcessCreditNoteReportV2CommandJob.php b/app/Classes/Jobs/Commands/V2/ProcessCreditNoteReportV2CommandJob.php index 91dc27bb..41e2fe8b 100644 --- a/app/Classes/Jobs/Commands/V2/ProcessCreditNoteReportV2CommandJob.php +++ b/app/Classes/Jobs/Commands/V2/ProcessCreditNoteReportV2CommandJob.php @@ -15,6 +15,7 @@ use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; use App\Models\Booking; +use App\Models\Transaction; use Illuminate\Support\Facades\Log; @@ -71,19 +72,29 @@ class ProcessCreditNoteReportV2CommandJob implements ShouldQueue 'EInvoiceValidationLink' => $eInvoiceValidationLink, ]); - $booking = Booking::where('marking', $ref)->first(); - if($booking){ + // $booking = Booking::where('marking', $ref)->first(); + // if($booking){ + // if($docNo != "" && $docNo != "<>"){ + // $payments = $booking->transactions()->payments()->get(); + // foreach ($payments as $payment) { + // $refundTransaction = $payment->transactions()->refunds()->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])->latest()->first(); + // if($refundTransaction){ + // $this->updateOrCreateKeyValuePair($refundTransaction, KVPKey::AUTOCOUNT_DOCNO_CREDIT_NOTE, $docNo); + // if($eInvoiceValidationLink){ + // $this->updateOrCreateKeyValuePair($refundTransaction, KVPKey::AUTOCOUNT_EINVOICE_VALIDATION_LINK_CREDIT_NOTE, $eInvoiceValidationLink); + // } + // break; + // } + // } + // } + // } + + $transaction = Transaction::where('bill_no', $ref)->first(); + if($transaction){ if($docNo != "" && $docNo != "<>"){ - $payments = $booking->transactions()->payments()->get(); - foreach ($payments as $payment) { - $refundTransaction = $payment->transactions()->refunds()->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])->latest()->first(); - if($refundTransaction){ - $this->updateOrCreateKeyValuePair($refundTransaction, KVPKey::AUTOCOUNT_DOCNO_CREDIT_NOTE, $docNo); - if($eInvoiceValidationLink){ - $this->updateOrCreateKeyValuePair($refundTransaction, KVPKey::AUTOCOUNT_EINVOICE_VALIDATION_LINK_CREDIT_NOTE, $eInvoiceValidationLink); - } - break; - } + $this->updateOrCreateKeyValuePair($transaction, KVPKey::AUTOCOUNT_DOCNO_CREDIT_NOTE, $docNo); + if($eInvoiceValidationLink){ + $this->updateOrCreateKeyValuePair($transaction, KVPKey::AUTOCOUNT_EINVOICE_VALIDATION_LINK_CREDIT_NOTE, $eInvoiceValidationLink); } } } diff --git a/app/Classes/Modules/Exports/Services/ExportsARCreditNoteReport.php b/app/Classes/Modules/Exports/Services/ExportsARCreditNoteReport.php index 94651460..679f3003 100644 --- a/app/Classes/Modules/Exports/Services/ExportsARCreditNoteReport.php +++ b/app/Classes/Modules/Exports/Services/ExportsARCreditNoteReport.php @@ -79,7 +79,7 @@ class ExportsARCreditNoteReport implements FromQuery, WithHeadings, WithHeadingR $refundRemarkGroupAccNo = null; $company = $transaction->owner->owner; $kvps = KeyValuePair::where('value', $transaction->id) - ->where('key', 'App\Models\Transaction') + ->where('key', KVPKey::TRANSACTION_MODEL_CLASS) ->orderByDesc('created_at') ->get(); @@ -119,7 +119,7 @@ class ExportsARCreditNoteReport implements FromQuery, WithHeadings, WithHeadingR '<>', //DocNo $formattedDocumentDate, //DocDate $company->debtor, //DebtorCode - $booking ? $booking->marking : '', //Ref + $transaction->bill_no ?? '', //Ref $refundRemarkGroup ?? '', //Description $refundRemarkGroup ?? '', //Reason 'C', //DeptNo diff --git a/app/Classes/Modules/Transactions/ControllersLogic/GenerateCreditNotePdfV2Logic.php b/app/Classes/Modules/Transactions/ControllersLogic/GenerateCreditNotePdfV2Logic.php index b65985b0..1ae1bfeb 100644 --- a/app/Classes/Modules/Transactions/ControllersLogic/GenerateCreditNotePdfV2Logic.php +++ b/app/Classes/Modules/Transactions/ControllersLogic/GenerateCreditNotePdfV2Logic.php @@ -94,26 +94,43 @@ class GenerateCreditNotePdfV2Logic if($eInvoiceStarted) { $eInvoiceStarted = false; //reset to re-evaluate second time - $kvp = KeyValuePair::where('key', KVPKey::TRANSACTION_MODEL_CLASS)->where('value', $transaction->id)->first(); - $refundTransaction = $kvp ? $kvp->owner : null; - if($refundTransaction && $refundTransaction->type === TransactionType::REFUND){ - $metadata = $refundTransaction->attributesKVP()->where('key', KVPKey::AUTOCOUNT_DOCNO_CREDIT_NOTE)->first(); + //OLD BUSINESS LOGIC + // $kvp = KeyValuePair::where('key', KVPKey::TRANSACTION_MODEL_CLASS)->where('value', $transaction->id)->first(); + // $refundTransaction = $kvp ? $kvp->owner : null; + // if($refundTransaction && $refundTransaction->type === TransactionType::REFUND){ + // $metadata = $refundTransaction->attributesKVP()->where('key', KVPKey::AUTOCOUNT_DOCNO_CREDIT_NOTE)->first(); + // if($metadata){ + // $autoCountInvoiceId = $metadata->value; + // } + // $metadata = $refundTransaction->attributesKVP()->where('key', KVPKey::AUTOCOUNT_EINVOICE_VALIDATION_LINK_CREDIT_NOTE)->first(); + // if($metadata){ + // $autoCountEInvoiceValidationLink = $metadata->value; + // } + + // if($autoCountInvoiceId && $autoCountEInvoiceValidationLink){ + // $eInvoiceStarted = true; + // } + // } + if($transaction && $transaction->type === TransactionType::CREDIT_NOTE){ + $metadata = $transaction->attributesKVP()->where('key', KVPKey::AUTOCOUNT_DOCNO_CREDIT_NOTE)->first(); if($metadata){ $autoCountInvoiceId = $metadata->value; - } - $metadata = $refundTransaction->attributesKVP()->where('key', KVPKey::AUTOCOUNT_EINVOICE_VALIDATION_LINK_CREDIT_NOTE)->first(); - if($metadata){ - $autoCountEInvoiceValidationLink = $metadata->value; - } + $metadata = $transaction->attributesKVP()->where('key', KVPKey::AUTOCOUNT_EINVOICE_VALIDATION_LINK_CREDIT_NOTE)->first(); + if($metadata){ + $autoCountEInvoiceValidationLink = $metadata->value; + } - Log::info('AUTOCOUNT_DOCNO_CREDIT_NOTE: ' . $autoCountInvoiceId); - Log::info('AUTOCOUNT_EINVOICE_VALIDATION_LINK_CREDIT_NOTE: ' . $autoCountEInvoiceValidationLink); + if($autoCountInvoiceId && $autoCountEInvoiceValidationLink){ + $eInvoiceStarted = true; + } + } + else{ - if($autoCountInvoiceId && $autoCountEInvoiceValidationLink){ - $eInvoiceStarted = true; } } } + Log::info('AUTOCOUNT_DOCNO_CREDIT_NOTE: ' . $autoCountInvoiceId); + Log::info('AUTOCOUNT_EINVOICE_VALIDATION_LINK_CREDIT_NOTE: ' . $autoCountEInvoiceValidationLink); if($eInvoiceStarted) { diff --git a/app/Classes/Modules/Wallets/Processors/CreditWalletProcessor.php b/app/Classes/Modules/Wallets/Processors/CreditWalletProcessor.php index 6e9b33fc..29996e01 100644 --- a/app/Classes/Modules/Wallets/Processors/CreditWalletProcessor.php +++ b/app/Classes/Modules/Wallets/Processors/CreditWalletProcessor.php @@ -111,10 +111,10 @@ class CreditWalletProcessor $wallet = $this->updatesWallet->execute($wallet, $walletObject); if($relatedTransaction && $relatedTransaction instanceof Transaction){ - $kvp = $relatedTransaction->attributesKVP()->where('key', 'App\Models\Transaction')->where('value', $transaction->id)->latest()->first(); + $kvp = $relatedTransaction->attributesKVP()->where('key', KVPKey::TRANSACTION_MODEL_CLASS)->where('value', $transaction->id)->latest()->first(); if(!$kvp){ $keyValuePairObject = new KeyValuePairObject( - "App\Models\Transaction", + KVPKey::TRANSACTION_MODEL_CLASS, $transaction->id ); $this->createsKeyValuePair->execute($relatedTransaction, $keyValuePairObject); diff --git a/app/Console/Commands/LarkPushBookingModuleCommand.php b/app/Console/Commands/LarkPushBookingModuleCommand.php new file mode 100644 index 00000000..f29d4b11 --- /dev/null +++ b/app/Console/Commands/LarkPushBookingModuleCommand.php @@ -0,0 +1,110 @@ +error('[Lark ' . $module . '] Missing LARK_BOOKING1_WEBHOOK_ID'); + return self::FAILURE; + } + + if (!app()->isProduction()) { + $this->info('[Lark ' . $module . '] Skipped in non-production.'); + return self::SUCCESS; + } + + $limit = (int) $this->option('limit'); + $url = "https://hfbbr1an7s0.sg.larksuite.com/base/automation/webhook/event/{$webhookId}"; + $statusM = ApprovalStatus::APPROVAL_STATUS_ID; + + $bookings = Booking::query() + ->whereNotExists(function ($q) { + $b = new Booking; + $q->selectRaw(1) + ->from('lark_pushed') + ->whereColumn('lark_pushed.owner_id', 'bookings.id') + ->where('lark_pushed.owner_type', $b->getMorphClass()) + ->where('lark_pushed.is_success', 1); + }) + ->limit($limit) + ->get(); + + if ($bookings->isEmpty()) { + $this->warn('[Lark ' . $module . '] Nothing to push.'); + return self::SUCCESS; + } + + $this->info("[Lark " . $module . "] Pushing {$bookings->count()} record(s)..."); + Log::info('[Lark ' . $module . '] Start', ['limit' => $limit, 'env' => app()->environment()]); + + foreach ($bookings as $b) { + $payload = [ + 'id' => (string) $b->id, + 'marking' => (string) $b->marking, + 'company_name' => (string) $b->company->name, + 'company_reference' => (string) $b->company->reference, + 'service_name' => (string) $b->service->name, + 'currency' => (string) $b->fixedCurrency->short_code, + 'amount' => $b->fix_amount, + 'status' => (string) ($statusM[$b->status] ?? $b->status), + 'created_at' => $b->created_at->format('Y-m-d H:i'), + 'updated_at' => $b->updated_at->format('Y-m-d H:i'), + ]; + + try { + $res = Http::asJson()->post($url, $payload); + $ok = $res->successful() && (int) data_get($res->json(), 'code', -1) === 0; + + LarkPushed::create([ + 'owner_id' => $b->id, + 'owner_type' => $b->getMorphClass(), + 'is_success' => $ok ? 1 : 0, + ]); + + if ($ok) { + $this->info("[Lark $module]: ✅ Sent: {$b->id} | {$b->marking}"); + } else { + $this->error("[Lark $module] Failed {$b->id} | {$b->marking}: {$res->status()} {$res->body()}"); + Log::error('[Lark ' . $module . '] Push failed', [ + 'booking_id' => $b->id, + 'status' => $res->status(), + 'body' => $res->body(), + ]); + } + } catch (\Throwable $e) { + LarkPushed::create([ + 'owner_id' => $b->id, + 'owner_type' => $b->getMorphClass(), + 'is_success' => 0, + ]); + $this->error("[Lark $module]: ❌ Exception {$b->id} | {$b->marking}: {$e->getMessage()}"); + Log::error('[Lark ' . $module . '] Exception', [ + 'booking_id' => $b->id, + 'exception' => $e->getMessage(), + ]); + } + + sleep(1); + } + + $this->info("[Lark " . $module . "] Finished {$bookings->count()} record(s)."); + Log::info('[Lark ' . $module . '] Finished', ['count' => $bookings->count()]); + + return self::SUCCESS; + } +} diff --git a/app/Console/Commands/LarkPushCompanyModuleCommand.php b/app/Console/Commands/LarkPushCompanyModuleCommand.php index 75df0788..11d7ec1f 100644 --- a/app/Console/Commands/LarkPushCompanyModuleCommand.php +++ b/app/Console/Commands/LarkPushCompanyModuleCommand.php @@ -27,7 +27,7 @@ class LarkPushCompanyModuleCommand extends Command } $this->info('Starting Lark push company module...'); - Log::info('Lark push started', [ + Log::info('[Company Module]: Lark push started', [ 'limit' => (int) $this->option('limit'), 'env' => app()->environment(), ]); @@ -49,7 +49,6 @@ class LarkPushCompanyModuleCommand extends Command if ($companies->isEmpty()) { $this->warn('⚠️ Nothing to push (all already marked success or none found).'); - Log::info('Lark push: nothing to push'); return self::SUCCESS; } @@ -74,12 +73,7 @@ class LarkPushCompanyModuleCommand extends Command ]); if ($ok) { - $this->info('✅ Sent: ' . $company->name . ' | ' . $company->reference); - Log::info('Lark push success', [ - 'company_id' => $company->id, - 'name' => $company->name, - 'reference' => $company->reference, - ]); + $this->info('[Company Module]: ✅ Sent: ' . $company->name . ' | ' . $company->reference); } else { $this->error('❌ Failed for ' . $company->name . ': ' . $res->status() . ' ' . $res->body()); Log::error('Lark push failed', [ @@ -106,7 +100,7 @@ class LarkPushCompanyModuleCommand extends Command } $this->info('Finished sending ' . $companies->count() . ' records.'); - Log::info('Lark push finished', ['count' => $companies->count()]); + Log::info('[Company Module]: Lark push finished', ['count' => $companies->count()]); return self::SUCCESS; } diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 63d5e462..cc9f1ff3 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -75,6 +75,10 @@ class Kernel extends ConsoleKernel $schedule->command('lark:push-company-module') ->hourly() ->withoutOverlapping(); + // Push booking module to Lark + $schedule->command('lark:push-booking-module') + ->hourly() + ->withoutOverlapping(); } } //Commands Version 1: Before Laravel Vapor/AWS diff --git a/app/Http/Resources/TransactionResource.php b/app/Http/Resources/TransactionResource.php index b013f9db..172c29fd 100644 --- a/app/Http/Resources/TransactionResource.php +++ b/app/Http/Resources/TransactionResource.php @@ -7,6 +7,7 @@ use App\Classes\ValueObjects\Constants\ApprovalStatus; use App\Classes\ValueObjects\Constants\KVPKey; use App\Classes\ValueObjects\Constants\TransactionType; use App\Models\Booking; +use App\Models\Transaction; use Carbon\Carbon; use Illuminate\Http\Resources\Json\JsonResource; use Illuminate\Support\Facades\Log; @@ -40,9 +41,13 @@ class TransactionResource extends JsonResource $eInvoice = false; if($booking && $this->type === TransactionType::REFUND){ - $kvp = $this->attributesKVP()->where('key', KVPKey::AUTOCOUNT_DOCNO_CREDIT_NOTE)->first(); - if($kvp){ - $eInvoice = true; + $kvp = $this->attributesKVP()->where('key', KVPKey::TRANSACTION_MODEL_CLASS)->first(); + $transactionCreditNote = Transaction::where('id', $kvp->value)->first(); + if($transactionCreditNote){ + $kvp = $transactionCreditNote->attributesKVP()->where('key', KVPKey::AUTOCOUNT_DOCNO_CREDIT_NOTE)->first(); + if($kvp){ + $eInvoice = true; + } } } diff --git a/resources/assets/vue/components/bookings/elements/DownloadUploadComponent.vue b/resources/assets/vue/components/bookings/elements/DownloadUploadComponent.vue index 62b859e5..db55e7b0 100644 --- a/resources/assets/vue/components/bookings/elements/DownloadUploadComponent.vue +++ b/resources/assets/vue/components/bookings/elements/DownloadUploadComponent.vue @@ -113,6 +113,9 @@ +
+ Note: Date filter not applicable to import +
{{error}}
diff --git a/resources/views/pages/pdfs/e_credit_note.blade.php b/resources/views/pages/pdfs/e_credit_note.blade.php index 0828ba1a..3ed5d861 100644 --- a/resources/views/pages/pdfs/e_credit_note.blade.php +++ b/resources/views/pages/pdfs/e_credit_note.blade.php @@ -119,25 +119,27 @@ - - - - - - - - - - -
- -
-

{{ $autocountEInvoiceValidationLink }}

-
+ +
+ + + +
+ {{ $autocountEInvoiceValidationLink }} +
+
+
This is generated by computer. No signature required.