/** * @param array $data * @return bool */ public function saveFrontierCharge($data) { /** * @var \DDD\Dao\Booking\Booking $bookingDao * @var \Library\Authentication\BackofficeAuthenticationService $authenticationService * @var \DDD\Dao\Booking\Charge $chargingDao * @var BankTransaction $serviceTransaction * @var Logger $logger * @var \DDD\Service\Booking\BookingAddon $addonService * @var \DDD\Dao\ApartmentGroup\ApartmentGroup $apartmentManagementDao */ $addonService = $this->getServiceLocator()->get('service_booking_booking_addon'); $serviceTransaction = $this->getServiceLocator()->get('service_booking_bank_transaction'); $bookingDao = $this->getServiceLocator()->get('dao_booking_booking'); $logger = $this->getServiceLocator()->get('ActionLogger'); $apartmentManagementDao = $this->getServiceLocator()->get('dao_apartment_group_apartment_group'); if (!isset($data['bookingId']) || !($rowBooking = $bookingDao->getBookingForFrontierCharge($data['bookingId'])) || !$data['cc_id']) { return false; } $authenticationService = $this->getServiceLocator()->get('library_backoffice_auth'); $loggedInUserID = $authenticationService->getIdentity()->id; $chargingDao = $this->getServiceLocator()->get('dao_booking_charge'); $parkingInventoryDao = $this->getServiceLocator()->get('dao_parking_spot_inventory'); $addons = $addonService->getAddonsArray(); $groupId = isset($data['groupId']) ? (int) $data['groupId'] : 0; $pspId = $apartmentManagementDao->getPsp($groupId); /** * @var Psp $pspService */ $pspService = $this->getServiceLocator()->get('service_psp'); $pspInfo = $pspService->getPspInfo($pspId); try { $chargingDao->beginTransaction(); if (isset($data['accommodation_amount'])) { foreach ($data['accommodation_amount'] as $key => $value) { if (isset($data['entityId'][$key]) && (int) $data['entityId'][$key] > 0) { if ((int) $data['addonstype'][$key] == Constants::ADDONS_PARKING) { $isAvailable = $parkingInventoryDao->getSpotInventoryAvailability($data['entityId'][$key], $data['nightDate'][$key]); if (!$isAvailable) { return false; } } } } $params = ['reservation_id' => $rowBooking['id'], 'date' => date('Y-m-d H:i:s'), 'user_id' => $loggedInUserID, 'comment' => Helper::setLog('commentWithoutData', $data['charge_comment']), 'acc_currency' => $rowBooking['apartment_currency_code'], 'type' => 'n', 'apartment_id' => $rowBooking['apartment_id_assigned']]; // set business model if ($rowBooking['model'] == PartnerService::BUSINESS_MODEL_GINOSI_COLLECT) { $params['money_direction'] = Charge::CHARGE_MONEY_DIRECTION_GINOSI_COLLECT; } elseif (in_array($rowBooking['model'], PartnerService::partnerBusinessModel())) { $params['money_direction'] = Charge::CHARGE_MONEY_DIRECTION_PARTNER_COLLECT; } $provideParking = []; foreach ($data['accommodation_amount'] as $key => $row) { //nightly data if (isset($data['reservation_nightly_ids'][$key]) && (int) $data['reservation_nightly_ids'][$key] > 0) { $params['reservation_nightly_id'] = (int) $data['reservation_nightly_ids'][$key]; $params['rate_name'] = $data['rateNames'][$key]; $params['reservation_nightly_date'] = $data['nightDate'][$key]; } else { $params['reservation_nightly_id'] = 0; $params['rate_name'] = NUll; $params['reservation_nightly_date'] = NULL; } //entityId is being used for parking now if (isset($data['entityId'][$key]) && (int) $data['entityId'][$key] > 0) { $params['entity_id'] = (int) $data['entityId'][$key]; if ((int) $data['addonstype'][$key] == Constants::ADDONS_PARKING) { //close spot availability $parkingInventoryDao->save(['availability' => 0], ['spot_id' => $params['entity_id'], 'date' => $params['reservation_nightly_date']]); } } else { $params['entity_id'] = 0; } $params['acc_amount'] = number_format((double) $row, 2, '.', ''); $params['addons_type'] = (int) $data['addonstype'][$key]; $params['addons_value'] = (int) $data['addons_value'][$key]; $params['tax_type'] = isset($data['taxtype'][$key]) ? (double) $data['taxtype'][$key] : 0; if (isset($addons[$params['addons_type']]['default_commission']) && $addons[$params['addons_type']]['default_commission']) { $params['commission'] = $rowBooking['partner_commission']; } else { $params['commission'] = 0; } $params['status'] = 0; $chargingDao->save($params); if ($params['addons_type'] == Constants::ADDONS_PARKING) { if (!isset($provideParking[$params['rate_name']])) { $provideParking[$params['rate_name']] = []; } array_push($provideParking[$params['rate_name']], $params['reservation_nightly_date']); } } $parkingChargesByDateRanges = $this->calculateDateRangesForSpot($provideParking); foreach ($parkingChargesByDateRanges as $parkingSpotRequested) { $logger->save(Logger::MODULE_BOOKING, $rowBooking['id'], Logger::ACTION_PROVIDE_PARKING, 'Provide Parking on ' . $parkingSpotRequested['date'] . ' for ' . $parkingSpotRequested['spot']); } $bookingTicketService = $this->getServiceLocator()->get('service_booking_booking_ticket'); $balanceAndSummaryArray = $bookingTicketService->getSumAndBalanc($rowBooking['id']); $bookingArray = ['guest_balance' => $balanceAndSummaryArray['ginosiBalanceInApartmentCurrency'], 'partner_balance' => $balanceAndSummaryArray['partnerBalanceInApartmentCurrency'], 'check_charged' => 1]; // recalculatePenalty $newPenalty = $this->recalculatePenalty($rowBooking['id']); if ($newPenalty > 0) { $bookingArray['penalty_fixed_amount'] = $newPenalty; } $bookingDao->save($bookingArray, ['res_number' => $rowBooking['res_number']]); } $transactionAmountInApartmentCurrency = doubleval($data['transaction_amount_apartment_currency']); if (is_float($transactionAmountInApartmentCurrency) && $transactionAmountInApartmentCurrency > 0) { $transactionAmountInCustomerCurrency = $transactionAmountInApartmentCurrency * $rowBooking['currency_rate']; // Transaction $transactionData = ['res_number' => $rowBooking['res_number'], 'transaction_type' => BankTransaction::BANK_TRANSACTION_TYPE_COLLECT, 'transaction_psp' => $pspId, 'reservation_id' => $rowBooking['id'], 'acc_currency_rate' => $rowBooking['acc_currency_rate'], 'transaction_acc_amount' => $transactionAmountInApartmentCurrency, 'transaction_customer_amount' => $transactionAmountInCustomerCurrency, 'transaction_money_account_currency' => $pspInfo['currency'], 'transaction_money_account_currency_rate' => $rowBooking['currency_rate'], 'transaction_charge_amount' => $transactionAmountInApartmentCurrency, 'transaction_money_account_id' => $pspInfo['money_account_id'], 'transaction_charge_comment' => $data['charge_comment'], 'accId' => $rowBooking['apartment_id_assigned'], 'transaction_status' => BankTransaction::BANK_TRANSACTION_STATUS_APPROVED, 'transaction_rrn' => '', 'transaction_auth_code' => '', 'cardId' => $data['cc_id']]; $responseTransaction = $serviceTransaction->saveTransaction($transactionData, BankTransaction::TRANSACTION_MONEY_DIRECTION_GINOSI_COLLECT, true); if ($responseTransaction['status'] == 'error') { $chargingDao->rollbackTransaction(); return false; } } else { $chargingDao->rollbackTransaction(); return false; } $chargingDao->commitTransaction(); return $rowBooking['res_number']; } catch (\Exception $e) { $chargingDao->rollbackTransaction(); } return false; }
/** * @param array $data * @param int $moneyDirection * @param bool $isFrontier * * @return bool|string */ public function saveTransaction($data, $moneyDirection = self::TRANSACTION_MONEY_DIRECTION_GINOSI_COLLECT, $isFrontier = false) { /** * @var \DDD\Dao\Booking\ChargeTransaction $bankTransactionDao * @var \Library\Authentication\BackofficeAuthenticationService $authenticationService * @var \DDD\Service\Booking\BookingTicket $bookingTicketService * @var \DDD\Domain\Booking\ForCharge $rowBooking * @var ForCharge $bookingDao * @var \DDD\Service\Fraud $serviceFraud * @var \DDD\Dao\Psp\Psp $pspDao * @var Logger $logger */ $transactionDate = date('Y-m-d H:i:s'); $bankTransactionDao = $this->getServiceLocator()->get('dao_booking_change_transaction'); $pspDao = $this->getServiceLocator()->get('dao_psp_psp'); $transactionType = (int) $data['transaction_type']; $transactionStatus = isset($data['transaction_status']) ? (int) $data['transaction_status'] : 0; $errorRespond = ['status' => 'error', 'msg' => TextConstants::ERROR_CHARGED]; $error = ''; $transactionTypesWhichRequireCreditCard = [self::BANK_TRANSACTION_TYPE_COLLECT, self::BANK_TRANSACTION_TYPE_REFUND, self::BANK_TRANSACTION_TYPE_VALIDATION]; if (in_array($transactionType, $transactionTypesWhichRequireCreditCard) && (!isset($data['cardId']) || !(int) $data['cardId'])) { return ['status' => 'error', 'msg' => TextConstants::ERROR_NO_CARD]; } $creditCardId = intval($data['cardId']); /** * @var \DDD\Dao\Booking\Booking $bookingDao */ $bookingDao = $this->getServiceLocator()->get('dao_booking_booking'); $bookingDao->setEntity(new \DDD\Domain\Booking\ForCharge()); $rowBooking = $bookingDao->fetchOne(['res_number' => $data['res_number']], ['id', 'partner_id', 'customer_id']); if (!$rowBooking) { return $errorRespond; } try { if (!$isFrontier) { $bankTransactionDao->beginTransaction(); } $authenticationService = $this->getServiceLocator()->get('library_backoffice_auth'); $bookingTicketService = $this->getServiceLocator()->get('service_booking_booking_ticket'); $loggedInUserID = $authenticationService->getIdentity()->id; $transactionApartmentAmount = $data['transaction_acc_amount']; $accAmount = number_format(doubleval($transactionApartmentAmount), 2, '.', ''); if ($transactionType == self::BANK_TRANSACTION_TYPE_DEDUCTED_SALARY) { $bankAmount = 0; $bankRate = 0; $moneyAccountCurrency = $data['acc_currency']; $cashUser = (int) $data['userCache_id']; } else { $moneyAccountCurrency = $data['transaction_money_account_currency']; $bankRate = $data['transaction_money_account_currency_rate']; $bankAmount = number_format($data['transaction_charge_amount'], 2, '.', ''); $cashUser = 0; } // Calculate exact bank amount $bankAmount = $this->applyPercentDeductionByPSP($bankAmount, $data['transaction_psp']); if ($transactionType == self::BANK_TRANSACTION_TYPE_DEDUCTED_SALARY) { $moneyAccountId = 0; } elseif (in_array($transactionType, [self::BANK_TRANSACTION_TYPE_CASH, self::BANK_TRANSACTION_TYPE_CASH_REFUND])) { $moneyAccountId = (int) $data['personal_account_id']; } elseif (in_array($transactionType, [self::BANK_TRANSACTION_TYPE_CHARGEBACK_DISPUTE, self::BANK_TRANSACTION_TYPE_CHARGEBACK_FRAUD, self::BANK_TRANSACTION_TYPE_CHARGEBACK_OTHER])) { $moneyAccountId = (int) $data['transaction_chargeback_bank']; } elseif ($transactionType == self::BANK_TRANSACTION_TYPE_BANK_DEPOSIT) { $moneyAccountId = (int) $data['money_account_deposit_id']; $moneyDirection = (int) $data['money_direction_received']; } else { $moneyAccountId = (int) $data['transaction_money_account_id']; } if ($transactionType == self::BANK_TRANSACTION_TYPE_BANK_DEPOSIT) { $moneyDirection = self::TRANSACTION_MONEY_DIRECTION_GINOSI_COLLECT; } // All Refunds and Chargebacks if (in_array($transactionType, [self::BANK_TRANSACTION_TYPE_REFUND, self::BANK_TRANSACTION_TYPE_CHARGEBACK_FRAUD, self::BANK_TRANSACTION_TYPE_CHARGEBACK_DISPUTE, self::BANK_TRANSACTION_TYPE_CHARGEBACK_OTHER, self::BANK_TRANSACTION_TYPE_CASH_REFUND])) { if ($transactionType != self::BANK_TRANSACTION_TYPE_CASH_REFUND) { $bankAmount = -$bankAmount; } $accAmount = -$accAmount; } $params = ['reservation_id' => $data['reservation_id'], 'money_account_id' => $moneyAccountId, 'date' => $transactionDate, 'user_id' => $loggedInUserID, 'bank_amount' => $bankAmount, 'money_account_currency' => $moneyAccountCurrency, 'acc_amount' => $accAmount, 'bank_rate' => $bankRate, 'comment' => Helper::setLog('commentWithoutData', Helper::stripTages($data['transaction_charge_comment'])), 'type' => $transactionType, 'cache_user' => $cashUser, 'apartment_id' => (int) $data['accId'], 'money_direction' => $moneyDirection]; if (in_array($transactionType, [self::BANK_TRANSACTION_TYPE_CASH, self::BANK_TRANSACTION_TYPE_CASH_REFUND, self::BANK_TRANSACTION_TYPE_BANK_DEPOSIT, self::BANK_TRANSACTION_TYPE_DEDUCTED_SALARY])) { $params['cc_id'] = 0; } else { $params['cc_id'] = $creditCardId; } if ($transactionType == self::BANK_TRANSACTION_TYPE_COLLECT) { $cardStatus = $transactionStatus + 1; /** * @var CardService $cardService */ $cardService = $this->getServiceLocator()->get('service_card'); $cardPartnerBusinessModel = $cardService->getCardPartnerBusinessModel($creditCardId); // check card partner business model if ($cardPartnerBusinessModel && $cardPartnerBusinessModel == Partners::BUSINESS_MODEL_GINOSI_COLLECT_PARTNER) { $params['money_direction'] = self::TRANSACTION_MONEY_DIRECTION_PARTNER_COLLECT; if ($transactionStatus == self::BANK_TRANSACTION_STATUS_APPROVED) { $cardStatus = CardService::CC_STATUS_DO_NOT_USE; } } // update card status $cardService->changeCardStatus($creditCardId, $cardStatus); } // Define Transaction Status if ($transactionType == self::BANK_TRANSACTION_TYPE_CASH || $transactionType == self::BANK_TRANSACTION_TYPE_CASH_REFUND) { $params['status'] = self::BANK_TRANSACTION_STATUS_PENDING; } elseif ($transactionStatus) { $params['status'] = $transactionStatus; } else { $params['status'] = self::BANK_TRANSACTION_STATUS_PENDING; } if (in_array($transactionType, [self::BANK_TRANSACTION_TYPE_COLLECT, self::BANK_TRANSACTION_TYPE_REFUND, self::BANK_TRANSACTION_TYPE_VALIDATION, self::BANK_TRANSACTION_TYPE_BANK_DEPOSIT])) { $params['psp_id'] = $data['transaction_psp']; if ($transactionStatus == self::BANK_TRANSACTION_STATUS_DECLINED) { if (isset($data['transaction_error_code']) && $data['transaction_error_code']) { $params['error_code'] = $data['transaction_error_code']; } } if ($transactionStatus == self::BANK_TRANSACTION_STATUS_APPROVED) { if (isset($data['transaction_auth_code']) && $data['transaction_auth_code']) { $params['auth_code'] = $data['transaction_auth_code']; } if (isset($data['transaction_rrn']) && $data['transaction_rrn']) { $params['rrn'] = $data['transaction_rrn']; } } } // Frontier charge if ($isFrontier) { $params['status'] = self::BANK_TRANSACTION_STATUS_PENDING; $params['reviewed'] = self::FRONTIER_TRANSACTION_REVIEWED; } // } // save transaction $bankTransactionDao->save($params); $transactorId = $bankTransactionDao->lastInsertValue; // after transaction save, we must recalculate balance and update it in reservations table $balances = $bookingTicketService->getSumAndBalanc($rowBooking->getId()); $updateReservationData = ['guest_balance' => number_format($balances['ginosiBalanceInApartmentCurrency'], 2, '.', ''), 'partner_balance' => number_format($balances['partnerBalanceInApartmentCurrency'], 2, '.', '')]; if (in_array($transactionType, [self::BANK_TRANSACTION_TYPE_COLLECT, self::BANK_TRANSACTION_TYPE_REFUND, self::BANK_TRANSACTION_TYPE_VALIDATION]) && $transactionStatus == self::BANK_TRANSACTION_STATUS_APPROVED) { $updateReservationData['funds_confirmed'] = BookingTicket::CC_STATUS_VALID; } $bookingDao->save($updateReservationData, ['res_number' => $data['res_number']]); // in case when transaction is chargeback and it's reason of fraud, we must update data in black list table if ($transactionType == self::BANK_TRANSACTION_TYPE_CHARGEBACK_FRAUD && $transactionStatus == self::BANK_TRANSACTION_STATUS_APPROVED) { $serviceFraud = $this->getServiceLocator()->get('service_fraud'); $fraud = $serviceFraud->saveFraudManual($rowBooking->getId()); if (isset($fraud['status']) && $fraud['status'] != 'success' && isset($fraud['msg'])) { $error .= $fraud['msg']; } } // Make money transaction $transactionTypesToSkip = [self::BANK_TRANSACTION_TYPE_DEDUCTED_SALARY, self::BANK_TRANSACTION_TYPE_VALIDATION]; $pspDao->setEntity(new \ArrayObject()); $isBatch = $pspDao->fetchOne(['id' => $data['transaction_psp']], ['batch']); $isBatch = $isBatch ? $isBatch['batch'] : false; // For some cases money transaction is not acceptable if (!in_array($transactionType, $transactionTypesToSkip) && $params['status'] != self::BANK_TRANSACTION_STATUS_DECLINED && !$isBatch) { if ($transactionStatus != self::BANK_TRANSACTION_STATUS_DECLINED) { $transactionDate = $this->changeDateForSomePSP($transactionDate, $data['transaction_psp']); } $reservationTransaction = new Reservation(TransactionBase::ACCOUNT_CUSTOMER, TransactionBase::ACCOUNT_MONEY_ACCOUNT); $reservationTransaction->setServiceLocator($this->getServiceLocator()); $reservationTransaction->setAccountIdentity($rowBooking->getCustomerId(), $moneyAccountId); $reservationTransaction->setTransactorId($transactorId); $reservationTransaction->setTransactionDate($transactionDate); $reservationTransaction->setDescription("Reservation Transaction #{$data['res_number']}."); $reservationTransaction->setAmount($bankAmount); $reservationTransaction->setStatus($params['status']); $reservationTransaction->prepare(); if (!$reservationTransaction->process()) { throw new \Exception('Cannot process money transaction.'); } } if (!$isFrontier) { $bankTransactionDao->commitTransaction(); } if ($error) { $status = 'warning'; $msg = TextConstants::SUCCESS_TRANSACTED . $error; } else { $status = 'success'; $msg = TextConstants::SUCCESS_TRANSACTED; } return ['status' => $status, 'msg' => $msg]; } catch (\Exception $ex) { if (!$isFrontier) { $bankTransactionDao->rollbackTransaction(); } return $errorRespond; } }