status !== 'delivered' || $shipment->accounting_journal_mapping_id) { return; } if (! class_exists(AccountingAccTransMapping::class)) { return; } $businessId = (int) $shipment->business_id; if (! $this->tmsUtil->isAccountingEnabled($businessId)) { return; } $settings = $this->tmsUtil->getTmsSettings($businessId); if (empty($settings['auto_post_freight_journal'])) { return; } $expenseAccountId = $settings['freight_expense_account_id'] ?? null; $paymentAccountId = $settings['freight_payment_account_id'] ?? null; if (empty($expenseAccountId) || empty($paymentAccountId)) { return; } $amount = (float) $shipment->freight_cost; if ($amount <= 0) { return; } DB::beginTransaction(); try { if (class_exists(\Modules\Accounting\Services\FinancialPostingService::class)) { $postingService = app(\Modules\Accounting\Services\FinancialPostingService::class); $entityResolution = app(\Modules\Accounting\Services\HoldingEntityResolutionService::class); $holdingEntityId = $entityResolution->resolveFromLocation($businessId, $shipment->origin_location_id ? (int) $shipment->origin_location_id : null); $mapping = $postingService->post(new \Modules\Accounting\Domain\FinancialPostingRequest( businessId: $businessId, userId: $userId, sourceType: 'tms_freight', sourceId: $shipment->id, note: __('tms::lang.freight_journal_note', ['ref' => $shipment->ref_no]), lines: [ ['accounting_account_id' => $expenseAccountId, 'amount' => $amount, 'type' => 'debit', 'holding_entity_id' => $holdingEntityId], ['accounting_account_id' => $paymentAccountId, 'amount' => $amount, 'type' => 'credit', 'holding_entity_id' => $holdingEntityId], ], operationDate: ($shipment->delivered_at ?? now())->toDateTimeString(), holdingEntityId: $holdingEntityId, )); $shipment->update(['accounting_journal_mapping_id' => $mapping?->id]); DB::commit(); return; } $mapping = new AccountingAccTransMapping(); $mapping->business_id = $businessId; $mapping->ref_no = $this->generateRefNo($businessId); $mapping->note = __('tms::lang.freight_journal_note', ['ref' => $shipment->ref_no]); $mapping->type = 'journal_entry'; $mapping->created_by = $userId; $mapping->operation_date = $shipment->delivered_at ?? now(); $mapping->save(); $operationDate = $mapping->operation_date; AccountingAccountsTransaction::create([ 'accounting_account_id' => $expenseAccountId, 'amount' => $amount, 'type' => 'debit', 'sub_type' => 'journal_entry', 'created_by' => $userId, 'operation_date' => $operationDate, 'acc_trans_mapping_id' => $mapping->id, ]); AccountingAccountsTransaction::create([ 'accounting_account_id' => $paymentAccountId, 'amount' => $amount, 'type' => 'credit', 'sub_type' => 'journal_entry', 'created_by' => $userId, 'operation_date' => $operationDate, 'acc_trans_mapping_id' => $mapping->id, ]); $shipment->update(['accounting_journal_mapping_id' => $mapping->id]); DB::commit(); } catch (\Throwable $e) { DB::rollBack(); \Log::error('TMS freight accounting journal failed: '.$e->getMessage()); } } public function postCustomsDutiesOnClearance(\Modules\Tms\Models\CustomsClearance $clearance, int $userId): void { if (! in_array($clearance->status, ['cleared', 'released'], true) || $clearance->accounting_journal_mapping_id) { return; } if (! class_exists(AccountingAccTransMapping::class)) { return; } $businessId = (int) $clearance->business_id; if (! $this->tmsUtil->isAccountingEnabled($businessId)) { return; } $settings = $this->tmsUtil->getTmsSettings($businessId); if (empty($settings['auto_post_customs_journal'])) { return; } $expenseAccountId = $settings['customs_duty_expense_account_id'] ?? null; $paymentAccountId = $settings['customs_payment_account_id'] ?? null; if (empty($expenseAccountId) || empty($paymentAccountId)) { return; } $amount = (float) $clearance->total_duties; if ($amount <= 0) { return; } DB::beginTransaction(); try { if (class_exists(\Modules\Accounting\Services\FinancialPostingService::class)) { $postingService = app(\Modules\Accounting\Services\FinancialPostingService::class); $entityResolution = app(\Modules\Accounting\Services\HoldingEntityResolutionService::class); $shipment = $clearance->shipment; $locationId = $shipment?->origin_location_id; $holdingEntityId = $entityResolution->resolveFromLocation($businessId, $locationId ? (int) $locationId : null); $mapping = $postingService->post(new \Modules\Accounting\Domain\FinancialPostingRequest( businessId: $businessId, userId: $userId, sourceType: 'tms_customs', sourceId: $clearance->id, note: __('tms::lang.customs_journal_note', ['ref' => $clearance->ref_no]), lines: [ ['accounting_account_id' => $expenseAccountId, 'amount' => $amount, 'type' => 'debit', 'holding_entity_id' => $holdingEntityId], ['accounting_account_id' => $paymentAccountId, 'amount' => $amount, 'type' => 'credit', 'holding_entity_id' => $holdingEntityId], ], operationDate: ($clearance->cleared_at ?? now())->toDateTimeString(), holdingEntityId: $holdingEntityId, )); $clearance->update(['accounting_journal_mapping_id' => $mapping?->id]); DB::commit(); return; } $mapping = new AccountingAccTransMapping(); $mapping->business_id = $businessId; $mapping->ref_no = $this->generateRefNo($businessId); $mapping->note = __('tms::lang.customs_journal_note', ['ref' => $clearance->ref_no]); $mapping->type = 'journal_entry'; $mapping->created_by = $userId; $mapping->operation_date = $clearance->cleared_at ?? now(); $mapping->save(); $operationDate = $mapping->operation_date; AccountingAccountsTransaction::create([ 'accounting_account_id' => $expenseAccountId, 'amount' => $amount, 'type' => 'debit', 'sub_type' => 'journal_entry', 'created_by' => $userId, 'operation_date' => $operationDate, 'acc_trans_mapping_id' => $mapping->id, ]); AccountingAccountsTransaction::create([ 'accounting_account_id' => $paymentAccountId, 'amount' => $amount, 'type' => 'credit', 'sub_type' => 'journal_entry', 'created_by' => $userId, 'operation_date' => $operationDate, 'acc_trans_mapping_id' => $mapping->id, ]); $clearance->update(['accounting_journal_mapping_id' => $mapping->id]); DB::commit(); } catch (\Throwable $e) { DB::rollBack(); \Log::error('TMS customs accounting journal failed: '.$e->getMessage()); } } protected function generateRefNo(int $businessId): string { $accountingUtil = class_exists(\Modules\Accounting\Utils\AccountingUtil::class) ? app(\Modules\Accounting\Utils\AccountingUtil::class) : null; $settings = $accountingUtil ? $accountingUtil->getAccountingSettings($businessId) : []; $refCount = $this->util->setAndGetReferenceCount('journal_entry'); $prefix = $settings['journal_entry_prefix'] ?? 'MJ-'; return $this->util->generateReferenceNumber('journal_entry', $refCount, $businessId, $prefix); } }