where('amount', '<', 0)->get(); foreach ($transactions as $transaction) { $mapped = false; $keywords = array_filter(explode(" ", $transaction->transaction_description . " " . $transaction->transaction_description_2)); if($transaction->amount > 0){ // Exchange Sales $creditTransactions = $this->getTransactions($transaction->posting_date, $transaction->amount, TransactionType::PAYMENT, Booking::class, PaymentMethodType::WALLET, [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED], $keywords); foreach ($creditTransactions as $creditTransaction) { $isArray = is_array($creditTransaction); $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::SALES, 'system' => 'EXCHANGE', 'owner_type' => Transaction::class, 'owner_id'=> $isArray ? $creditTransaction['owner_id'] : $creditTransaction->id, 'owner_reference'=> $isArray ? $creditTransaction['owner_reference'] : $creditTransaction->owner->marking, ]); } // Shipping Portal Sales $creditTransactions = $this->getTransactionsFromShippingPortal($transaction->amount, $this->getDateRange($transaction->posting_date, 1), [2], PaymentMethodType::WALLET); foreach ($creditTransactions as $creditTransaction) { if($creditTransaction['owner_type'] === Wallet::class) continue; $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::SALES, 'system' => 'SHIPPING_PORTAL', 'owner_type' => $creditTransaction['owner_type'], 'owner_id'=> $creditTransaction['owner_id'], 'owner_reference'=> $creditTransaction['owner_reference'], ]); } // Exchange Wallet Top Up $creditTransactions = $this->getTransactions($transaction->posting_date, $transaction->amount, TransactionType::TOP_UP, Wallet::class, null, [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED], $keywords); foreach ($creditTransactions as $creditTransaction) { $isArray = is_array($creditTransaction); $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::WALLET_TOP_UP, 'system' => 'EXCHANGE', 'owner_type' => Transaction::class, 'owner_id'=> $isArray ? $creditTransaction['owner_id'] : $creditTransaction->id, 'owner_reference'=> $isArray ? $creditTransaction['owner_reference'] : $creditTransaction->owner->owner->reference, ]); } $creditTransactions = $this->getTransactionsFromShippingPortal($transaction->amount, $this->getDateRange($transaction->posting_date, 1), [5,15], null); foreach ($creditTransactions as $creditTransaction) { $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::WALLET_TOP_UP, 'system' => 'SHIPPING_PORTAL', 'owner_type' => $creditTransaction['owner_type'], 'owner_id'=> $creditTransaction['owner_id'], 'owner_reference'=> $creditTransaction['owner_reference'], ]); } // fpx charge refund if($transaction->transaction_description === 'DUITNOW S/CHRG REFUND'){ $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::FPX_CHARGE_REFUND ]); } // Customer Refund // INTERNAL_BANK_TRANSFER_IN if(str_contains($transaction->transaction_description_2, 'CIEF WORLDWIDE')){ $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::INTERNAL_BANK_TRANSFER_IN ]); } } if($transaction->amount < 0){ // Supplier Purchase Order Payments foreach (['YSN', 'HCK', 'ATVANTIC', 'HIGH HILL'] as $reference){ if(str_contains($transaction->transaction_description.' '.$transaction->transaction_description_2.' '.$transaction->transaction_description_3.' '.$transaction->transaction_description_4.' '.$transaction->transaction_description_5 , $reference)) { $paymentDateStart = $transaction->posting_date->startOfDay()->subDays(1); $paymentDateEnd = $transaction->posting_date->endOfDay(); if($paymentDateStart->dayOfWeek === Carbon::SUNDAY){ $paymentDateStart->subDays(2); } $issuer = Company::where('name', 'like', '%'.$reference.'%')->get()->pluck('id'); $debitTransactions = Group::whereIn('issuer', $issuer)->where('amount', '>=', (($transaction->amount * -1) - 0.01)) ->where('amount', '<=', (($transaction->amount * -1) + 0.01))->whereDate('created_at', '>=', $paymentDateStart)->whereDate('created_at', '<=', $paymentDateEnd)->get(); foreach ($debitTransactions as $debitTransaction) { $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::SUPPLIER_PAYMENT, 'system' => 'EXCHANGE', 'owner_type' => Group::class, 'owner_id'=> $debitTransaction->id, 'owner_reference'=> $debitTransaction->reference ]); } } } // Exchange Wallet Withdrawal $debitTransactions = $this->getTransactions($transaction->posting_date, $transaction->amount, TransactionType::DEBIT_NOTE, Wallet::class, null, [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED], $keywords); foreach ($debitTransactions as $debitTransaction) { $isArray = is_array($creditTransaction); $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::WALLET_WITHDRAWAL, 'system' => 'EXCHANGE', 'owner_type' => Transaction::class, 'owner_id'=> $isArray ? $debitTransaction['owner_id'] : $debitTransaction->id, 'owner_reference'=> $isArray ? $debitTransaction['owner_reference'] : $debitTransaction->owner->owner->marking, ]); } // SALARY // STATUTORY if(str_contains($transaction->transaction_description_2, 'PEMBANGUNAN SUMBER') || str_contains($transaction->transaction_description_2, 'HASIL') || str_contains($transaction->transaction_description_2, 'PERTUBUHAN KESELAMAT') || str_contains($transaction->transaction_description_2, 'KUMPULAN WANG SIMPAN')){ $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::STATUTORY ]); } // FPX_CHARGE if($transaction->transaction_description === 'DR DUITNOW S/CHRG' || str_contains($transaction->transaction_description, 'Manual FPX') || str_contains($transaction->transaction_description, 'CMS - DR FPX CHG')){ $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::FPX_CHARGE ]); } // BANK_CHARGE if($transaction->transaction_description === 'CMS - DR CORP CHG' || $transaction->transaction_description === 'MONTHLY PROFIT DEBIT'){ $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::BANK_CHARGE ]); } // CREDIT_CARD_PAYMENT if(str_contains($transaction->transaction_description_2, 'VISA CARD')){ $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::CREDIT_CARD_PAYMENT ]); } // INTERNAL_BANK_TRANSFER_OUT if(str_contains($transaction->transaction_description_2, 'CIEF WORLDWIDE') || str_contains($transaction->transaction_description_2, 'CIEF WORLWIDE') || str_contains($transaction->transaction_description_2, 'IZYIM GLOBAL')){ $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::INTERNAL_BANK_TRANSFER_OUT ]); } // non-operational charges if(str_contains($transaction->transaction_description_2, 'HIRE PURCHASE') || str_contains($transaction->transaction_description_2, 'TENAGA NASIONAL') || str_contains($transaction->transaction_description, 'CABLE CHARGE') || str_contains($transaction->transaction_description_2, 'CTOS DATA SYSTEMS') || str_contains($transaction->transaction_description_2, 'MAXIS')){ $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::NON_OPERATIONAL ]); } } if (isset($data) && $data->wasRecentlyCreated) $mapped = true; $this->updateMappedRate($transaction, $mapped); } } private function getTransactions($date, $amount, $type, $ownerType, $paymentMethod, $statuses, $keywords, $model = Transaction::class) { $dateRange = $this->getDateRange($date, 4); if (App::environment(['production'])) { $query = $model::whereIn('status', $statuses) ->where(function ($query) use ($ownerType, $paymentMethod, $type) { if ($ownerType) { $query->where('owner_type', $ownerType); } if ($paymentMethod) { $query->where('payment_method', '!=', $paymentMethod); } if ($type) { $query->where('type', $type); } }) ->whereDate('created_at', '>=', $dateRange['start_date']) ->whereDate('created_at', '<=', $dateRange['end_date']) ->where('amount', '>', ($amount - 0.05)) ->where('amount', '<', ($amount + 0.05)); if ($query->count() > 1) { $transactions = clone $query; $transactions->whereDate('created_at', $date->format('Y-m-d')); if ($transactions->count() === 1) { return $transactions->get(); } $transactions = clone $query; if ($ownerType === Booking::class) { $transactions = $transactions->whereHasMorph('owner', [Booking::class], function ($q1) use ($keywords) { return $q1->whereHas('company', function ($company) use ($keywords) { return $company->where(function ($q2) use ($keywords) { foreach($keywords as $keyword) { $q2->orWhere('name', 'LIKE', '%'.$keyword.'%'); } $q2->orWhereHas('contacts', function ($contact) use($keywords) { return $contact->where(function ($q3) use($keywords) { foreach($keywords as $keyword) { $q3->orWhere('reference', 'LIKE', '%'.$keyword.'%'); } }); }); }); }); }); } if ($ownerType === Wallet::class) { $transactions = $transactions->whereHasMorph('owner', [Wallet::class], function ($q1) use ($keywords) { return $q1->whereHasMorph('owner', [Company::class], function ($company) use($keywords) { return $company->where(function ($q2) use ($keywords) { foreach($keywords as $keyword) { $q2->orWhere('name', 'LIKE', '%'.$keyword.'%'); } $q2->orWhereHas('contacts', function ($contact) use($keywords) { return $contact->where(function ($q3) use($keywords) { foreach($keywords as $keyword) { $q3->orWhere('reference', 'LIKE', '%'.$keyword.'%'); } }); }); }); }); }); } if ($transactions->count() === 1) { return $transactions->get(); } } return $query->get(); } else { $result = $this->getTransactionsFromExchange($amount, $dateRange, $type, $ownerType, $paymentMethod); return $result; } } private function getTransactionsFromExchange($amount, $dateRange, $type, $ownerType, $paymentMethod){ $url = 'https://exchange.cief-malaysia.com/public/api/v1/transactions/mappable/query'; return $this->getFromExchange($url, $amount, $dateRange, $type, $ownerType, $paymentMethod); } private function getFromExchange($url, $amount, $dateRange, $type, $ownerType, $paymentMethod){ $paymentMethodFilter = ""; if ($paymentMethod) { $paymentMethodFilter = ',"payment_method_not_in":['.$paymentMethod.']'; } $ownerType = addslashes($ownerType); try{ $client = new \GuzzleHttp\Client(['verify' => false]); $response = $client->request('GET', $url.'?api-key=510acd13d8d24375cf038ad626c282565451461a9c2399357e0b65365300787e&filters={"order_by":{"column":"id","DESC":true},"status_in":[2,3],"owner_type":"'. $ownerType . '"' . $paymentMethodFilter.',"type":'.$type.',"created_after_or_equal":"'.$dateRange['start_date'].'","created_before_or_equal":"'.$dateRange['end_date'].'","amount_exceed":'.($amount - 0.01).',"amount_short":'.($amount + 0.01).'}'); $body = $response->getBody(); $data = json_decode($body, true); $payload = $data['payload']; $transactions2 = $payload['data']; return $transactions2; }catch(\Exception $exception){ Log::error($exception); return []; } } private function getTransactionsFromShippingPortal($amount, $dateRange, $type, $paymentMethod){ $url = 'https://izyim.cief-malaysia.com/public/api/v1/transactions/mappable/query'; return $this->getFromShippingPortal($amount, $dateRange, $url, $type, $paymentMethod); } private function getGroupsFromShippingPortal($amount, $dateRange, $type, $paymentMethod){ $url = 'https://izyim.cief-malaysia.com/public/api/v1/groups/query'; return $this->getFromShippingPortal($amount, $dateRange, $url, $type, $paymentMethod); } private function getFromShippingPortal($amount, $dateRange, $url, $type, $paymentMethod){ $paymentMethodFilter = ""; if ($paymentMethod) { $paymentMethodFilter = ',"payment_method_not_in":['.$paymentMethod.']'; } try{ $client = new \GuzzleHttp\Client(['verify' => false]); $response = $client->request('GET', $url.'?api-key=510acd13d8d24375cf038ad626c282565451461a9c2399357e0b65365300787e&filters={"order_by":{"column":"id","DESC":true},"status_in":[2]'.$paymentMethodFilter.',"created_after":"'.$dateRange['start_date'].'","created_before":"'.$dateRange['end_date'].'","amount_exceed":'.($amount - 0.01).',"amount_short":'.($amount + 0.01).',"type_in":'.json_encode($type).'}'); $body = $response->getBody(); $data = json_decode($body, true); $payload = $data['payload']; $transactions2 = $payload['data']; return $transactions2; }catch(\Exception $exception){ Log::error($exception); return []; } } private function getDateRange(string $dateStr, int $range) { // Create a DateTime object from the input string $date = strtotime($dateStr); // Get the first day of the month $today = date('Y-m-d', strtotime('-' . $range . ' day', $date)); // Get the first day of the next month $nextDay = date('Y-m-d', strtotime('+' . $range . ' day', $date)); return [ 'start_date' => $today, 'end_date' => $nextDay, ]; } private function updateMappedRate($transaction, $mapped) { $statement = $transaction->statement; $statement->total_rows = StatementTransaction::where('account_statement_id',$transaction->account_statement_id)->count(); $statement->mapped_rows = $mapped ? $statement->mapped_rows+1 : $statement->mapped_rows; $statement->save(); } }