diff --git a/app/Classes/General/Abstracts/AbstractControllerLogic.php b/app/Classes/General/Abstracts/AbstractControllerLogic.php index 61c70f44..f26e2ad0 100644 --- a/app/Classes/General/Abstracts/AbstractControllerLogic.php +++ b/app/Classes/General/Abstracts/AbstractControllerLogic.php @@ -69,7 +69,7 @@ abstract class AbstractControllerLogic } catch (ErrorException|GeneralExceptions $exception){ if ($exception instanceof JobResourceNotFoundException) { - Log::error(sprintf( + Log::channel('vue_polling')->info(sprintf( "Uncaught exception '%s' with message '%s' in %s:%d", get_class($exception), $exception->getMessage(), diff --git a/app/Classes/General/Eloquent/Filters/DoesNotHaveRefundInProgress.php b/app/Classes/General/Eloquent/Filters/DoesNotHaveRefundInProgress.php new file mode 100644 index 00000000..60618626 --- /dev/null +++ b/app/Classes/General/Eloquent/Filters/DoesNotHaveRefundInProgress.php @@ -0,0 +1,24 @@ +whereDoesntHave('transactions', function ($query) { + return $query->where('type', TransactionType::REFUND)->whereIn('status', [ApprovalStatus::PENDING_SUBMISSION, ApprovalStatus::PENDING_VERIFICATION]); + }); + } +} diff --git a/app/Classes/General/Eloquent/Filters/GroupByImportedDate.php b/app/Classes/General/Eloquent/Filters/GroupByImportedDate.php new file mode 100644 index 00000000..25f20fa3 --- /dev/null +++ b/app/Classes/General/Eloquent/Filters/GroupByImportedDate.php @@ -0,0 +1,18 @@ +groupby('imported_date'); + } +} \ No newline at end of file diff --git a/app/Classes/General/Eloquent/Filters/ImportedDateFrom.php b/app/Classes/General/Eloquent/Filters/ImportedDateFrom.php new file mode 100644 index 00000000..140bbb20 --- /dev/null +++ b/app/Classes/General/Eloquent/Filters/ImportedDateFrom.php @@ -0,0 +1,18 @@ +whereDate('imported_date', '>=', date('Y-m-d',strtotime($value))); + } +} \ No newline at end of file diff --git a/app/Classes/General/Eloquent/Filters/ImportedDateTo.php b/app/Classes/General/Eloquent/Filters/ImportedDateTo.php new file mode 100644 index 00000000..11bd3857 --- /dev/null +++ b/app/Classes/General/Eloquent/Filters/ImportedDateTo.php @@ -0,0 +1,18 @@ +whereDate('imported_date', '<=', date('Y-m-d',strtotime($value))); + } +} \ No newline at end of file diff --git a/app/Classes/General/Eloquent/Filters/IsNotFullyRefunded.php b/app/Classes/General/Eloquent/Filters/IsNotFullyRefunded.php new file mode 100644 index 00000000..fdbb2994 --- /dev/null +++ b/app/Classes/General/Eloquent/Filters/IsNotFullyRefunded.php @@ -0,0 +1,24 @@ +withSum(['transactions as total_refund_amount' => function($q) { + $q->refunds()->where('status', ApprovalStatus::APPROVED); + }], 'original_amount') + ->having('total_refund_amount', '<', DB::raw('original_amount')); + } +} diff --git a/app/Classes/General/Eloquent/Filters/StatementTransactionInvoiceReference.php b/app/Classes/General/Eloquent/Filters/StatementTransactionInvoiceReference.php new file mode 100644 index 00000000..9e3ba1e9 --- /dev/null +++ b/app/Classes/General/Eloquent/Filters/StatementTransactionInvoiceReference.php @@ -0,0 +1,22 @@ +whereHas('owners', function ($query) use ($value) { + return $query->where('Invoice_reference', $value); + }); + } + +} diff --git a/app/Classes/General/Eloquent/Filters/StatementTransactionOwnerReference.php b/app/Classes/General/Eloquent/Filters/StatementTransactionOwnerReference.php new file mode 100644 index 00000000..c0a7beaf --- /dev/null +++ b/app/Classes/General/Eloquent/Filters/StatementTransactionOwnerReference.php @@ -0,0 +1,22 @@ +whereHas('owners', function ($query) use ($value) { + return $query->where('owner_reference', $value); + }); + } + +} diff --git a/app/Classes/General/Eloquent/Filters/StatementTransactionReceiptReference.php b/app/Classes/General/Eloquent/Filters/StatementTransactionReceiptReference.php new file mode 100644 index 00000000..f808f784 --- /dev/null +++ b/app/Classes/General/Eloquent/Filters/StatementTransactionReceiptReference.php @@ -0,0 +1,22 @@ +whereHas('owners', function ($query) use ($value) { + return $query->where('receipt_reference', $value); + }); + } + +} diff --git a/app/Classes/General/Interfaces/KeyValueInterface.php b/app/Classes/General/Interfaces/KeyValueInterface.php new file mode 100644 index 00000000..fbee5265 --- /dev/null +++ b/app/Classes/General/Interfaces/KeyValueInterface.php @@ -0,0 +1,12 @@ +user = $user; + $this->voucher = $voucher; + $this->emailSentCount = $emailSentCount; + } + + + public function handle() + { + $currentDatetime = Carbon::now(); + $dateToCompare = Carbon::parse($this->voucher->end_date); + if (!$this->user->hasAttribute($this->voucher->code."_EMAIL_COUNT") + && $this->user->rewards->where('voucher_id', $this->voucher->id)->count() > 0 + && $currentDatetime->isBefore($dateToCompare)) + { + //Key #1 + $keyValuePairObject = new KeyValuePairObject( + $this->voucher->code."_EMAIL_COUNT", + $this->emailSentCount + ); + (App()->make(CreatesKeyValuePair::class))->execute($this->user, $keyValuePairObject); + + //Key #2 + $keyValuePairObject = new KeyValuePairObject( + $this->voucher->code."_EMAIL_DATE_".$this->emailSentCount, + Carbon::now() + ); + (App()->make(CreatesKeyValuePair::class))->execute($this->user, $keyValuePairObject); + + $this->user->notify(new WelcomeVoucherEmail($this->user, $this->voucher)); + } + } +} diff --git a/app/Classes/Jobs/UpdatePerfexCRMInvoice.php b/app/Classes/Jobs/UpdatePerfexCRMInvoice.php index 26131bca..80a60c15 100644 --- a/app/Classes/Jobs/UpdatePerfexCRMInvoice.php +++ b/app/Classes/Jobs/UpdatePerfexCRMInvoice.php @@ -57,16 +57,15 @@ class UpdatePerfexCRMInvoice implements ShouldQueue $number = 'EXC-'.$number; $invoice = (App()->make(FetchesPerfexCRMInvoice::class))->execute($customer->userid,"INV-", $number); - Log::error(json_encode('UpdatePerfexCRMInvoice debug $number: '.$number)); + Log::channel('perfex_crm')->info(('UpdatePerfexCRMInvoice debug $number: '.$number)); if(is_null($invoice)){ $result = (App()->make(CreatePerfexCRMInvoiceProcessor::class))->execute($transaction); if ($result) { $invoiceId = $result->payload['id']; } else { - // Log::error(json_encode('UpdatePerfexCRMInvoice CreatePerfexCRMInvoiceProcessor failed')); $log['message'] = 'UpdatePerfexCRMInvoice CreatePerfexCRMInvoiceProcessor failed'; - Helper::debugLogger($log); + Log::channel('perfex_crm')->info($log); } } else{ @@ -75,7 +74,7 @@ class UpdatePerfexCRMInvoice implements ShouldQueue //This only run when invoice already exist and the invoice does not have a PAID status if($invoiceStatus != PerfexCRMInvoiceStatus::PAID){ - Log::error(json_encode('UpdatePerfexCRMInvoice debug $this->updatePerfexCRMInvoiceObject->getProjectId(): '.$this->updatePerfexCRMInvoiceObject->getProjectId())); + Log::channel('perfex_crm')->info('UpdatePerfexCRMInvoice debug $this->updatePerfexCRMInvoiceObject->getProjectId(): '.$this->updatePerfexCRMInvoiceObject->getProjectId()); //update invoice (App()->make(UpdatesPerfexCRMInvoice::class))->execute($invoice, $this->updatePerfexCRMInvoiceObject->getProjectId()); diff --git a/app/Classes/Modules/Accounting/ControllersLogic/HistoryImportedTransactionMappedControllerLogic.php b/app/Classes/Modules/Accounting/ControllersLogic/HistoryImportedTransactionMappedControllerLogic.php new file mode 100644 index 00000000..2f96c613 --- /dev/null +++ b/app/Classes/Modules/Accounting/ControllersLogic/HistoryImportedTransactionMappedControllerLogic.php @@ -0,0 +1,49 @@ + 'Retrieved History Imported Invoices', + 'message' => 'You have successfully retrieved history imported invoices' + ]; + } + + /** @var ListTransactionMappingLogs */ + private $listTransactionMappingLogs; + + /** + * UpdateAnnouncementLogic constructor. + * @param ListTransactionMappingLogs $listTransactionMappingLogs + */ + public function __construct( + ListTransactionMappingLogs $listTransactionMappingLogs + ) { + $this->listTransactionMappingLogs = $listTransactionMappingLogs; + } + + /** + * @param Request $request + * @return JsonResponse + */ + public function logic(Request $request): JsonResponse + { + $query = $this->listTransactionMappingLogs->execute($this->listTransactionMappingLogs->deserializeFilters($request->input('filters'))); + + return $this->collectionResponse(TransactionMappingLogResource::collection($query)); + } +} diff --git a/app/Classes/Modules/Accounting/ControllersLogic/UpdateStatementTransactionStatusLogic.php b/app/Classes/Modules/Accounting/ControllersLogic/UpdateStatementTransactionStatusLogic.php index 3a006e9e..b208c2e3 100644 --- a/app/Classes/Modules/Accounting/ControllersLogic/UpdateStatementTransactionStatusLogic.php +++ b/app/Classes/Modules/Accounting/ControllersLogic/UpdateStatementTransactionStatusLogic.php @@ -2,16 +2,14 @@ namespace App\Classes\Modules\Accounting\ControllersLogic; -use App\Classes\General\Abstracts\AbstractControllerLogic; -use App\Classes\Modules\Accounting\Services\FetchesBankStatementTransaction; -use App\Http\Resources\BankStatementTransactionResource; -use App\Classes\Modules\Accounting\Services\UpdatesBankStatementTransactionOwnerStatus; -use App\Classes\ValueObjects\Constants\ApprovalStatus; -use App\Classes\ValueObjects\Constants\StatementTransactionOwnerType; -use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; -use App\Classes\Modules\Transactions\Services\UpdatesTransactionStatus; - +use Illuminate\Http\JsonResponse; +use App\Classes\ValueObjects\Constants\ApprovalStatus; +use App\Classes\General\Abstracts\AbstractControllerLogic; +use App\Http\Resources\BankStatementTransactionOwnerResource; +use App\Classes\ValueObjects\Constants\StatementTransactionOwnerType; +use App\Classes\Modules\Accounting\Services\FetchesBankStatementTransactionOwner; +use App\Classes\Modules\Accounting\Services\UpdatesBankStatementTransactionOwnerStatus; class UpdateStatementTransactionStatusLogic extends AbstractControllerLogic { @@ -27,29 +25,23 @@ class UpdateStatementTransactionStatusLogic extends AbstractControllerLogic ]; } - /** @var FetchesBankStatementTransaction */ - private $fetchesBankStatementTransaction; + /** @var FetchesBankStatementTransactionOwner */ + private $fetchesBankStatementTransactionOwner; /** @var UpdatesBankStatementTransactionOwnerStatus */ private $updatesBankStatementTransactionOwnerStatus; - /** @var UpdatesTransactionStatus */ - private $updatesTransactionStatus; - /** * UpdateAnnouncementLogic constructor. - * @param FetchesBankStatementTransaction $fetchesBankStatementTransaction + * @param FetchesBankStatementTransactionOwner $fetchesBankStatementTransactionOwner * @param UpdatesBankStatementTransactionOwnerStatus $updatesBankStatementTransactionOwnerStatus - * @param UpdatesTransactionStatus $updatesTransactionStatus */ public function __construct( - FetchesBankStatementTransaction $fetchesBankStatementTransaction, - UpdatesBankStatementTransactionOwnerStatus $updatesBankStatementTransactionOwnerStatus, - UpdatesTransactionStatus $updatesTransactionStatus + FetchesBankStatementTransactionOwner $fetchesBankStatementTransactionOwner, + UpdatesBankStatementTransactionOwnerStatus $updatesBankStatementTransactionOwnerStatus ) { - $this->fetchesBankStatementTransaction = $fetchesBankStatementTransaction; + $this->fetchesBankStatementTransactionOwner = $fetchesBankStatementTransactionOwner; $this->updatesBankStatementTransactionOwnerStatus = $updatesBankStatementTransactionOwnerStatus; - $this->updatesTransactionStatus = $updatesTransactionStatus; } /** @@ -61,21 +53,10 @@ class UpdateStatementTransactionStatusLogic extends AbstractControllerLogic */ public function logic(Request $request): JsonResponse { - $statementTrasaction = $this->fetchesBankStatementTransaction->execute(['id' => $request->route('id')]); - - $statementTrasactionOwner = $statementTrasaction->owners->first(); + $statementTrasactionOwner = $this->fetchesBankStatementTransactionOwner->execute(['id' => $request->route('id')]); $this->updatesBankStatementTransactionOwnerStatus->execute($statementTrasactionOwner, $request->route('status') == 'approve' ? ApprovalStatus::APPROVED : ApprovalStatus::REJECTED); - // todo-new: approve payments status, need to check the owner(if system is shipping, need to api with shipping portal) - // if ($request->route('status') == 'approve') { - // if ($statementTrasactionOwner->transaction->type === StatementTransactionOwnerType::SALES) { - // if ($statementTrasactionOwner->owner->status === ApprovalStatus::PENDING_VERIFICATION) { - // $this->updatesTransactionStatus->execute($statementTrasactionOwner->owner, ApprovalStatus::APPROVED); - // } - // } - // } - - return $this->resourceResponse(new BankStatementTransactionResource($statementTrasaction)); + return $this->resourceResponse(new BankStatementTransactionOwnerResource($statementTrasactionOwner)); } } diff --git a/app/Classes/Modules/Accounting/Processors/ListShippingPortalTransactions.php b/app/Classes/Modules/Accounting/Processors/ListShippingPortalTransactions.php index f80c3c0e..18ec9c36 100644 --- a/app/Classes/Modules/Accounting/Processors/ListShippingPortalTransactions.php +++ b/app/Classes/Modules/Accounting/Processors/ListShippingPortalTransactions.php @@ -13,6 +13,7 @@ class ListShippingPortalTransactions { try { $url = 'https://izyim.cief-malaysia.com/public/api/v1/transactions/mappable/query/with-details'; + // $url = 'http://127.0.0.1:8001/public/api/v1/transactions/mappable/query/with-details'; $client = new \GuzzleHttp\Client(['verify' => false]); $response = $client->request('GET', $url . '?api-key=510acd13d8d24375cf038ad626c282565451461a9c2399357e0b65365300787e&filters=' . json_encode($filters)); $body = $response->getBody(); diff --git a/app/Classes/Modules/Accounting/Services/FetchesBankStatementTransactionOwner.php b/app/Classes/Modules/Accounting/Services/FetchesBankStatementTransactionOwner.php new file mode 100644 index 00000000..17c620f5 --- /dev/null +++ b/app/Classes/Modules/Accounting/Services/FetchesBankStatementTransactionOwner.php @@ -0,0 +1,31 @@ +repository = $repository; + } + + /** + * @return Builder + */ + public function getRepository(): Builder + { + return $this->repository->newQuery(); + } +} diff --git a/app/Classes/Modules/Accounting/Services/ListTransactionMappingLogs.php b/app/Classes/Modules/Accounting/Services/ListTransactionMappingLogs.php new file mode 100644 index 00000000..fdeff835 --- /dev/null +++ b/app/Classes/Modules/Accounting/Services/ListTransactionMappingLogs.php @@ -0,0 +1,32 @@ +repository = $repository; + } + + + /** + * @return Builder + */ + public function getRepository(): Builder + { + return $this->repository->newQuery(); + } +} diff --git a/app/Classes/Modules/Accounts/ControllersLogic/CreateCustomerLogic.php b/app/Classes/Modules/Accounts/ControllersLogic/CreateCustomerLogic.php index aeacf9ac..3b011c55 100644 --- a/app/Classes/Modules/Accounts/ControllersLogic/CreateCustomerLogic.php +++ b/app/Classes/Modules/Accounts/ControllersLogic/CreateCustomerLogic.php @@ -30,6 +30,7 @@ use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; use Illuminate\Support\Facades\App; use App\Classes\Modules\Segments\Services\CreatesSeasonalSegment; +use App\Classes\ValueObjects\Constants\Vouchers; class CreateCustomerLogic extends AbstractControllerLogic { @@ -162,7 +163,7 @@ class CreateCustomerLogic extends AbstractControllerLogic $this->newCustomerToVoucherifyProcessor->execute($company->id, $user, true); - $this->createVoucherProcessor->execute($user, 'WELCOME50%OFF'); + $this->createVoucherProcessor->execute($user, Vouchers::WELCOME_50_PERCENT_OFF); return $this->response($this->authenticationProcessor->execute($request, false)); diff --git a/app/Classes/Modules/Accounts/ControllersLogic/UserEmailVerificationLogic.php b/app/Classes/Modules/Accounts/ControllersLogic/UserEmailVerificationLogic.php index bae6f5eb..13a8bcc7 100644 --- a/app/Classes/Modules/Accounts/ControllersLogic/UserEmailVerificationLogic.php +++ b/app/Classes/Modules/Accounts/ControllersLogic/UserEmailVerificationLogic.php @@ -9,6 +9,9 @@ use App\Classes\Modules\Accounts\Services\CompletesEmailVerificationAttempt; use App\Classes\Modules\Accounts\Services\FetchesEmailVerificationAttempt; use App\Classes\Modules\Accounts\Services\VerifiesUser; use App\Classes\Modules\Accounts\Standards\Criteria\EmailVerificationActiveAttemptExists; +use App\Classes\Modules\Vouchers\Services\FetchesVoucher; +use App\Classes\Jobs\SendWelcomeVoucherEmail; +use App\Classes\ValueObjects\Constants\Vouchers; use App\Models\UserEmailVerification; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; @@ -36,19 +39,29 @@ class UserEmailVerificationLogic extends AbstractControllerLogic /** @var VerifiesUser */ private $verifiesUser; + /** @var SendWelcomeVoucherEmail */ + private $sendWelcomeVoucherEmail; + + /** @var FetchesVoucher */ + private $fetchesVoucher; + /** * UserEmailVerificationLogic constructor. * @param EmailVerificationActiveAttemptExists $emailVerificationActiveAttemptExists * @param CompletesEmailVerificationAttempt $completesEmailVerificationAttempt * @param FetchesEmailVerificationAttempt $fetchesEmailVerificationAttempt * @param VerifiesUser $verifiesUser + * @param SendWelcomeVoucherEmail $sendWelcomeVoucherEmail + * @param FetchesVoucher $fetchesVoucher */ - public function __construct(EmailVerificationActiveAttemptExists $emailVerificationActiveAttemptExists, CompletesEmailVerificationAttempt $completesEmailVerificationAttempt, FetchesEmailVerificationAttempt $fetchesEmailVerificationAttempt, VerifiesUser $verifiesUser) + public function __construct(EmailVerificationActiveAttemptExists $emailVerificationActiveAttemptExists, CompletesEmailVerificationAttempt $completesEmailVerificationAttempt, FetchesEmailVerificationAttempt $fetchesEmailVerificationAttempt, VerifiesUser $verifiesUser, SendWelcomeVoucherEmail $sendWelcomeVoucherEmail, FetchesVoucher $fetchesVoucher) { $this->emailVerificationActiveAttemptExists = $emailVerificationActiveAttemptExists; $this->completesEmailVerificationAttempt = $completesEmailVerificationAttempt; $this->fetchesEmailVerificationAttempt = $fetchesEmailVerificationAttempt; $this->verifiesUser = $verifiesUser; + $this->sendWelcomeVoucherEmail = $sendWelcomeVoucherEmail; + $this->fetchesVoucher = $fetchesVoucher; } /** @@ -68,9 +81,19 @@ class UserEmailVerificationLogic extends AbstractControllerLogic $this->completesEmailVerificationAttempt->execute($attempt); - $this->verifiesUser->execute($attempt->user); + $user = $attempt->user; + $this->verifiesUser->execute($user); + + // if (env('SENDING_EMAIL_WELCOME_VOUCHER_ENABLED', false)){ + if (app()->environment('production') && env('SENDING_EMAIL_WELCOME_VOUCHER_ENABLED', false)){ + try{ //In case voucher got deleted unintentionally + $voucher = $this->fetchesVoucher->execute(['code' => Vouchers::WELCOME_50_PERCENT_OFF]); + if($voucher) $this->sendWelcomeVoucherEmail::dispatch($user, $voucher, 1); + } + catch(\Exception $e){} + } return $this->response([]); } -} \ No newline at end of file +} diff --git a/app/Classes/Modules/Accounts/DataTransferObjects/KeyValuePairObject.php b/app/Classes/Modules/Accounts/DataTransferObjects/KeyValuePairObject.php new file mode 100644 index 00000000..fd1eff49 --- /dev/null +++ b/app/Classes/Modules/Accounts/DataTransferObjects/KeyValuePairObject.php @@ -0,0 +1,44 @@ +key = $key; + $this->value = $value; + } + + /** + * @return string + */ + public function getKey(): string + { + return $this->key; + } + + /** + * @return string + */ + public function getValue(): string + { + return $this->value; + } + +} diff --git a/app/Classes/Modules/Accounts/Services/CreatesKeyValuePair.php b/app/Classes/Modules/Accounts/Services/CreatesKeyValuePair.php new file mode 100644 index 00000000..c963ec4e --- /dev/null +++ b/app/Classes/Modules/Accounts/Services/CreatesKeyValuePair.php @@ -0,0 +1,28 @@ +key = $object->getKey(); + $model->value = $object->getValue(); + + return $this->handler($kv->attributes(), $model); + + } +} diff --git a/app/Classes/Modules/Bookings/ControllersLogic/CreateBookingPaymentLogic.php b/app/Classes/Modules/Bookings/ControllersLogic/CreateBookingPaymentLogic.php index c429d91d..ab654675 100644 --- a/app/Classes/Modules/Bookings/ControllersLogic/CreateBookingPaymentLogic.php +++ b/app/Classes/Modules/Bookings/ControllersLogic/CreateBookingPaymentLogic.php @@ -19,6 +19,7 @@ use App\Classes\ValueObjects\Constants\PaymentMethodType; use App\Classes\ValueObjects\Constants\TransactionType; use App\Classes\Modules\Currencies\DataTransferObjects\CurrencyConversionObject; use App\Http\Resources\TransactionResource; +use App\Classes\Modules\Bookings\Services\CalculatesBookingRefundAmount; use App\Classes\Modules\Transactions\Processors\CreateCashBackTransactionProcessor; use App\Classes\Modules\Vouchers\Processors\Voucherify\BookingToVoucherifyProcessor; @@ -77,6 +78,9 @@ class CreateBookingPaymentLogic extends AbstractControllerLogic /** @var BookingToVoucherifyProcessor */ private $bookingToVoucherifyProcessor; + /** @var CalculatesBookingRefundAmount */ + private $calculatesBookingRefundAmount; + /** * CreateBookingPaymentLogic constructor. * @param FetchesBookingQuotation $fetchBookingQuotation @@ -90,8 +94,9 @@ class CreateBookingPaymentLogic extends AbstractControllerLogic * @param CreateCashBackTransactionProcessor $createCashBackTransactionProcessor * @param RecalculatesWalletBalance $recalculatesWalletBalance * @param BookingToVoucherifyProcessor $bookingToVoucherifyProcessor + * @param CalculatesBookingRefundAmount $calculatesBookingRefundAmount */ - public function __construct(FetchesBookingQuotation $fetchBookingQuotation, FetchesCompanyPaymentAttemptLimit $fetchesCompanyPaymentAttemptLimit, GeneratesTransactionBillNumber $generatesTransactionBillNumber, CreatesTransaction $createsTransaction, CalculatesBookingOutstanding $calculatesBookingOutstanding, CreatesBillplzBill $createsBillplzBill, UpdatesWalletBalance $updatesWalletBalance, UpdatesTransactionStatus $updatesTransactionStatus, CreateCashBackTransactionProcessor $createCashBackTransactionProcessor, RecalculatesWalletBalance $recalculatesWalletBalance, BookingToVoucherifyProcessor $bookingToVoucherifyProcessor) + public function __construct(FetchesBookingQuotation $fetchBookingQuotation, FetchesCompanyPaymentAttemptLimit $fetchesCompanyPaymentAttemptLimit, GeneratesTransactionBillNumber $generatesTransactionBillNumber, CreatesTransaction $createsTransaction, CalculatesBookingOutstanding $calculatesBookingOutstanding, CreatesBillplzBill $createsBillplzBill, UpdatesWalletBalance $updatesWalletBalance, UpdatesTransactionStatus $updatesTransactionStatus, CreateCashBackTransactionProcessor $createCashBackTransactionProcessor, RecalculatesWalletBalance $recalculatesWalletBalance, BookingToVoucherifyProcessor $bookingToVoucherifyProcessor, CalculatesBookingRefundAmount $calculatesBookingRefundAmount) { $this->fetchBookingQuotation = $fetchBookingQuotation; $this->fetchesCompanyPaymentAttemptLimit = $fetchesCompanyPaymentAttemptLimit; @@ -104,6 +109,7 @@ class CreateBookingPaymentLogic extends AbstractControllerLogic $this->createCashBackTransactionProcessor = $createCashBackTransactionProcessor; $this->recalculatesWalletBalance = $recalculatesWalletBalance; $this->bookingToVoucherifyProcessor = $bookingToVoucherifyProcessor; + $this->calculatesBookingRefundAmount = $calculatesBookingRefundAmount; } /** @@ -119,7 +125,7 @@ class CreateBookingPaymentLogic extends AbstractControllerLogic $conversionObject = new CurrencyConversionObject(floatval(str_replace(',', '', $request->input('amount'))), $booking->convertible_currency_id, $booking->service_id, $booking->fix_currency_id === 1 ? 0:1, PaymentMethodType::PAYMENT_METHODS[$request->input('payment_method')]); - $outstanding = $this->calculatesBookingOutstanding->execute($booking); + $outstanding = $this->calculatesBookingOutstanding->execute($booking) + $this->calculatesBookingRefundAmount->execute($booking, $booking->fix_currency_id); if($conversionObject->getAmount() > round($outstanding, 2)) throw new MalformedRequestException('Your payment must not be greater than '. $outstanding .'.'); diff --git a/app/Classes/Modules/Bookings/ControllersLogic/CreateBookingRefundLogic.php b/app/Classes/Modules/Bookings/ControllersLogic/CreateBookingRefundLogic.php index d31ee2ce..0648629e 100644 --- a/app/Classes/Modules/Bookings/ControllersLogic/CreateBookingRefundLogic.php +++ b/app/Classes/Modules/Bookings/ControllersLogic/CreateBookingRefundLogic.php @@ -15,10 +15,10 @@ use App\Classes\Modules\Transactions\Services\CreatesTransaction; use App\Classes\Modules\Transactions\Services\FetchesTransaction; use App\Classes\Modules\Bookings\Services\FetchesBookingQuotation; use App\Classes\Modules\Transactions\Services\UpdatesTransactionStatus; -use App\Classes\Modules\Bookings\Services\CalculatesBookingRefundAmount; use App\Classes\Modules\Transactions\DataTransferObjects\TransactionObject; use App\Classes\Modules\Transactions\Services\GeneratesTransactionBillNumber; use App\Classes\Modules\Transactions\DataTransferObjects\TransactionRefundCalculationObject; +use App\Classes\ValueObjects\Constants\PaymentMethodType; class CreateBookingRefundLogic extends AbstractControllerLogic { @@ -48,9 +48,6 @@ class CreateBookingRefundLogic extends AbstractControllerLogic /** @var CreatesTransaction */ private $createsTransaction; - /** @var CalculatesBookingRefundAmount */ - private $calculatesBookingRefundAmount; - /** * CreateBookingPaymentLogic constructor. * @param FetchesBookingQuotation $fetchBookingQuotation @@ -58,16 +55,14 @@ class CreateBookingRefundLogic extends AbstractControllerLogic * @param UpdatesTransactionStatus $updatesTransactionStatus * @param GeneratesTransactionBillNumber $generatesTransactionBillNumber * @param CreatesTransaction $createsTransaction - * @param CalculatesBookingRefundAmount $calculatesBookingRefundAmount */ - public function __construct(FetchesBookingQuotation $fetchBookingQuotation, FetchesTransaction $fetchesTransaction, UpdatesTransactionStatus $updatesTransactionStatus, GeneratesTransactionBillNumber $generatesTransactionBillNumber, CreatesTransaction $createsTransaction, CalculatesBookingRefundAmount $calculatesBookingRefundAmount) + public function __construct(FetchesBookingQuotation $fetchBookingQuotation, FetchesTransaction $fetchesTransaction, UpdatesTransactionStatus $updatesTransactionStatus, GeneratesTransactionBillNumber $generatesTransactionBillNumber, CreatesTransaction $createsTransaction) { $this->fetchBookingQuotation = $fetchBookingQuotation; $this->fetchesTransaction = $fetchesTransaction; $this->updatesTransactionStatus = $updatesTransactionStatus; $this->generatesTransactionBillNumber = $generatesTransactionBillNumber; $this->createsTransaction = $createsTransaction; - $this->calculatesBookingRefundAmount = $calculatesBookingRefundAmount; } /** @@ -80,25 +75,30 @@ class CreateBookingRefundLogic extends AbstractControllerLogic $transaction = $this->fetchesTransaction->execute(['id' => $request->route('payment_id')]); + if ($transaction->transactions()->bills()->first()) { + throw new MalformedRequestException('Booking under white form cannot request for refund'); + } + $booking = $transaction->owner; $billNumber = $this->generatesTransactionBillNumber->execute('RFD-'); - $refund = $transaction->transactions()->refunds()->sum('amount'); + $refund = $transaction->transactions()->refunds()->whereIn('status', [ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::APPROVED])->sum('original_amount'); if($refund + $request->input('amount') > $transaction->original_amount) throw new MalformedRequestException('Your refund must not be greater than '. $transaction->original_amount .'.'); - $amount = $transaction->booking->fix_currency_id == 1 ? $request->input('amount') : $request->input('amount') / $transaction->currency_rate; + // $transactionRefundCalculationObject = new TransactionRefundCalculationObject($booking, $transaction, $request->input('amount')); + // $transactionRefundCalculationObject->init(); - - $transactionRefundCalculationObject = new TransactionRefundCalculationObject($booking, $transaction, $amount); - $transactionRefundCalculationObject->init(); + $refundAmount = bcdiv($request->input('amount'), $transaction->currency_rate, 7); + // refund service charges if is fully refund + $refundTotal = ($refund + $request->input('amount')) == $transaction->original_amount ? $refundAmount + $transaction->service_charge + $transaction->tax : $refundAmount; $object = new TransactionObject($billNumber, TransactionType::REFUND, 1, $booking->company->id, - 1, $transactionRefundCalculationObject->getConversionObject()->getPaymentMethod(), - $transactionRefundCalculationObject->getRefundTotalAmount(), $transactionRefundCalculationObject->getAmount(), 1, - $transactionRefundCalculationObject->getConversionObject()->getCurrencyId(), $transactionRefundCalculationObject->getTransaction()->currency_rate, - $transactionRefundCalculationObject->getRefundTax(), $transactionRefundCalculationObject->getRefundServiceCharge(), null, ApprovalStatus::PENDING_VERIFICATION, [], $transaction->bill_no); + 1, PaymentMethodType::CASH, + $refundTotal, $request->input('amount'), 1, + $transaction->original_currency_id, $transaction->currency_rate, + 0, 0, null, ApprovalStatus::PENDING_VERIFICATION, [], $transaction->bill_no); $transaction = $this->createsTransaction->execute($transaction, $object); diff --git a/app/Classes/Modules/Bookings/ControllersLogic/FetchBookingLogic.php b/app/Classes/Modules/Bookings/ControllersLogic/FetchBookingLogic.php index d9857548..d1f2286e 100644 --- a/app/Classes/Modules/Bookings/ControllersLogic/FetchBookingLogic.php +++ b/app/Classes/Modules/Bookings/ControllersLogic/FetchBookingLogic.php @@ -18,7 +18,7 @@ class FetchBookingLogic extends AbstractControllerLogic */ protected function notification():array { return [ - 'title' => 'Retrieved Address', + 'title' => 'Retrieved Booking', 'message' => 'You have successfully retrieved a Address' ]; } diff --git a/app/Classes/Modules/Bookings/ControllersLogic/FetchBookingPaymentQuotationLogic.php b/app/Classes/Modules/Bookings/ControllersLogic/FetchBookingPaymentQuotationLogic.php index 8effdb2f..e9a42101 100644 --- a/app/Classes/Modules/Bookings/ControllersLogic/FetchBookingPaymentQuotationLogic.php +++ b/app/Classes/Modules/Bookings/ControllersLogic/FetchBookingPaymentQuotationLogic.php @@ -14,6 +14,7 @@ use App\Classes\ValueObjects\Constants\PaymentMethodType; use App\Models\Booking; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; +use App\Classes\Modules\Bookings\Services\CalculatesBookingRefundAmount; class FetchBookingPaymentQuotationLogic extends AbstractControllerLogic { @@ -40,6 +41,9 @@ class FetchBookingPaymentQuotationLogic extends AbstractControllerLogic /** @var CalculatesBookingOutstanding */ private $calculatesBookingOutstanding; + /** @var CalculatesBookingRefundAmount */ + private $calculatesBookingRefundAmount; + /** * FetchBookingPaymentQuotationLogic constructor. * @param FetchesBookingQuotation $fetchBookingQuotation @@ -47,12 +51,13 @@ class FetchBookingPaymentQuotationLogic extends AbstractControllerLogic * @param FetchesCompanyPaymentAttemptLimit $fetchesCompanyPaymentAttemptLimit * @param CalculatesBookingOutstanding $calculatesBookingOutstanding */ - public function __construct(FetchesBookingQuotation $fetchBookingQuotation, GeneratesBookingQuotation $generatesBookingQuotation, FetchesCompanyPaymentAttemptLimit $fetchesCompanyPaymentAttemptLimit, CalculatesBookingOutstanding $calculatesBookingOutstanding) + public function __construct(FetchesBookingQuotation $fetchBookingQuotation, GeneratesBookingQuotation $generatesBookingQuotation, FetchesCompanyPaymentAttemptLimit $fetchesCompanyPaymentAttemptLimit, CalculatesBookingOutstanding $calculatesBookingOutstanding, CalculatesBookingRefundAmount $calculatesBookingRefundAmount) { $this->fetchBookingQuotation = $fetchBookingQuotation; $this->generatesBookingQuotation = $generatesBookingQuotation; $this->fetchesCompanyPaymentAttemptLimit = $fetchesCompanyPaymentAttemptLimit; $this->calculatesBookingOutstanding = $calculatesBookingOutstanding; + $this->calculatesBookingRefundAmount = $calculatesBookingRefundAmount; } /** @@ -66,7 +71,7 @@ class FetchBookingPaymentQuotationLogic extends AbstractControllerLogic $conversionObject = new CurrencyConversionObject(floatval(str_replace(',', '', $request->input('amount'))), $booking->convertible_currency_id, $booking->service_id, $booking->fix_currency_id === 1 ? 0:1, PaymentMethodType::PAYMENT_METHODS[$request->input('payment_method')]); - $outstanding = $this->calculatesBookingOutstanding->execute($booking); + $outstanding = $this->calculatesBookingOutstanding->execute($booking) + $this->calculatesBookingRefundAmount->execute($booking, $booking->fix_currency_id); if($conversionObject->getAmount() > round($outstanding, 2)) throw new MalformedRequestException('Your payment must not be greater than '.$booking->fixedCurrency->short_code.' '. number_format((float)$outstanding, 2, '.', ',')); //Voucherify diff --git a/app/Classes/Modules/Bookings/Services/CalculatesBookingRefundAmount.php b/app/Classes/Modules/Bookings/Services/CalculatesBookingRefundAmount.php index 14a4a9ef..239545af 100644 --- a/app/Classes/Modules/Bookings/Services/CalculatesBookingRefundAmount.php +++ b/app/Classes/Modules/Bookings/Services/CalculatesBookingRefundAmount.php @@ -2,19 +2,30 @@ namespace App\Classes\Modules\Bookings\Services; - use App\Classes\ValueObjects\Constants\ApprovalStatus; -use App\Classes\ValueObjects\Constants\TransactionType; use App\Models\Booking; -use Carbon\Carbon; class CalculatesBookingRefundAmount { + public function execute(Booking $booking, int $type, ?string $payment_reference = null): float + { + $refundAmounts = $booking->transactions()->payments()->get()->map(function ($payment) use ($type) { + return $this->calculateRefundAmount($payment, $type); + }); - public function execute(Booking $booking, int $type, ?string $payment_reference = NULL){ - return $type === 1 ? - $booking->transactions()->refunds($payment_reference) - ->selectRaw('sum(amount - service_charge - tax) as sub_total')->get()->sum('sub_total') : $booking->transactions()->refunds($payment_reference)->sum('original_amount'); + $totalRefundAmount = $refundAmounts->sum(); + + return $totalRefundAmount; } -} \ No newline at end of file + public function calculateRefundAmount($payment, int $type): float + { + $refundTransactions = $payment->transactions()->refunds()->whereIn('status', [ApprovalStatus::APPROVED]); + + if ($type === 1) { + return $refundTransactions->selectRaw('sum(amount - service_charge - tax) as sub_total')->get()->sum('sub_total'); + } + + return $refundTransactions->sum('original_amount'); + } +} diff --git a/app/Classes/Modules/Exports/Services/ExportsImportedInvoiceMappeds.php b/app/Classes/Modules/Exports/Services/ExportsImportedInvoiceMappeds.php index e629675f..ead22543 100644 --- a/app/Classes/Modules/Exports/Services/ExportsImportedInvoiceMappeds.php +++ b/app/Classes/Modules/Exports/Services/ExportsImportedInvoiceMappeds.php @@ -59,7 +59,6 @@ class ExportsImportedInvoiceMappeds implements FromQuery, WithHeadings, WithHead */ public function map($transaction): array { - // dd($transaction); $this->count += 1; $data = $transaction->data; return [ diff --git a/app/Classes/Modules/Exports/Services/ExportsImportedReceiptMappeds.php b/app/Classes/Modules/Exports/Services/ExportsImportedReceiptMappeds.php new file mode 100644 index 00000000..efe95fd3 --- /dev/null +++ b/app/Classes/Modules/Exports/Services/ExportsImportedReceiptMappeds.php @@ -0,0 +1,86 @@ +dateTime = $request->input('date').' '.$request->input('time'); + $this->count = 0; + } + + public function headings(): array + { + return [ + 'Check', + 'Doc No', + 'Doc Date', + 'Debtor Code', + 'Company Name', + 'Description', + 'Payment Amount', + 'Created User', + 'Curr.', + 'To Home Rate', + 'Local Payment Amount', + 'Cancelled', + 'Mapped Status', + 'Mapped Reference No', + ]; + } + + /** + * @return \Illuminate\Support\Collection|mixed + */ + public function query() + { + return TransactionMappingLog::where('imported_date', $this->dateTime); + } + + /** + * @param Transaction $transaction + * + * @return array + */ + public function map($transaction): array + { + $this->count += 1; + $data = $transaction->data; + return [ + $this->count, + Arr::get($data,'doc_no'), + Arr::get($data,'doc_date'), + Arr::get($data,'debtor_code'), + Arr::get($data,'company_name'), + Arr::get($data,'description'), + Arr::get($data,'payment_amount'), + Arr::get($data,'created_user'), + Arr::get($data,'curr'), + Arr::get($data,'to_home_rate'), + Arr::get($data,'local_payment_amount'), + Arr::get($data,'cancelled'), + Arr::get($data,'2nd_doc_no'), + Arr::get($data,'mapped_status'), + Arr::get($data,'mapped_result_reference'), + ]; + + } +} diff --git a/app/Classes/Modules/Exports/Services/ExportsInvoiceTransactions.php b/app/Classes/Modules/Exports/Services/ExportsInvoiceTransactions.php index a7041b1c..85df0be8 100644 --- a/app/Classes/Modules/Exports/Services/ExportsInvoiceTransactions.php +++ b/app/Classes/Modules/Exports/Services/ExportsInvoiceTransactions.php @@ -108,13 +108,13 @@ class ExportsInvoiceTransactions implements FromQuery, WithHeadings, WithHeading '500-0000', 'CIEF' ]; - } else { + } elseif ($statementTransactionOwner->owner_id) { $row = (App()->make(ListShippingPortalTransactions::class))->execute([ 'id' => $statementTransactionOwner->owner_id, 'with_company' => true, ]); - if (empty($row) || $row[0]['status'] != 'success') { + if (!empty($row) && $row[0]['status'] == 'success') { $textToAppend = Carbon::now()->format('[Y-m-d H:i:s]') . ' Fetch Shipping Transaction Fail ' . json_encode([ 'id' => $statementTransactionOwner->owner_id, 'with_company' => true, @@ -125,46 +125,46 @@ class ExportsInvoiceTransactions implements FromQuery, WithHeadings, WithHeading $textToAppend = Carbon::now()->format('[Y-m-d H:i:s]') . ' Shipping Portal Respnose ' . json_encode($row) . PHP_EOL; file_put_contents($errorFilePath, $textToAppend, FILE_APPEND); - Log::info('Error in Exports Invoice Transactions ' . $this->counter); + $row = $row[0]; return [ - 'Transaction Not Found', - $transaction->posting_date->format('m/d/Y H:m'), - $transaction->transaction_description.' - '.$transaction->transaction_description_2, - $statementTransactionOwner->system, + '<>', + Carbon::parse($row['created_at'])->format('m/d/Y H:m'), + $row['debtor_code'], + $row['type'] === ShippingTransactionType::PAYMENT ? $row['order_reference'] : $row['marking'], '', + 'MYR', + $row['type'] === ShippingTransactionType::PAYMENT ? $row['order_reference'] : $row['bill_no'], + $row['type'] === ShippingTransactionType::PAYMENT ? '' : 'W1', + $row['type'] === ShippingTransactionType::PAYMENT ? 'PLEASE REFER TO THE ATTACHED APPENDIX REF `' . $row['order_reference'] : 'CREDIT SALES', '', - '', - '', - '', - '', - 0, - $transaction->amount, - '', - '', - '', - '' + 1, + round($row['amount'], 2), + '500-0000', + 'CIEF' ]; + } - - $row = $row[0]; - - return [ - '<>', - Carbon::parse($row['updated_at'])->format('m/d/Y H:m'), - $row['debtor_code'], - $row['type'] === ShippingTransactionType::PAYMENT ? $row['order_reference'] : $row['marking'], - '', - 'MYR', - $row['type'] === ShippingTransactionType::PAYMENT ? $row['order_reference'] : $row['bill_no'], - $row['type'] === ShippingTransactionType::PAYMENT ? '' : 'W1', - $row['type'] === ShippingTransactionType::PAYMENT ? 'PLEASE REFER TO THE ATTACHED APPENDIX REF `' . $row['order_reference'] : 'CREDIT SALES', - '', - 1, - round($row['amount'], 2), - '500-0000', - 'CIEF' - ]; } + + return [ + 'Transaction Not Found', + $transaction->posting_date->format('m/d/Y H:m'), + $transaction->transaction_description.' - '.$transaction->transaction_description_2, + $statementTransactionOwner->system, + '', + '', + '', + '', + '', + '', + 0, + $transaction->amount, + '', + '', + '', + '' + ]; } + } diff --git a/app/Classes/Modules/Jobs/Processors/FetchesJobResultProcessor.php b/app/Classes/Modules/Jobs/Processors/FetchesJobResultProcessor.php index e19456e7..89783fe8 100644 --- a/app/Classes/Modules/Jobs/Processors/FetchesJobResultProcessor.php +++ b/app/Classes/Modules/Jobs/Processors/FetchesJobResultProcessor.php @@ -2,6 +2,7 @@ namespace App\Classes\Modules\Jobs\Processors; +use App\Classes\Exceptions\JobResourceNotFoundException; use App\Classes\Modules\Jobs\Services\FetchesJobResult; use Illuminate\Http\Request; use Illuminate\Support\Facades\Log; @@ -32,12 +33,13 @@ class FetchesJobResultProcessor public function execute(Request $request){ $res1 = $this->fetchesJobResult->execute(['job_id' => $request->route('job_id')]); + if($request->route('is_last')){ + $res2 = $this->fetchesJobResult->execute(['request_signature' => $res1->request_signature, 'result_not_null' => true, 'order_by_id_desc' => true]); + return $res2; + } if(!$res1->result){ - Log::info('Job id: '.$request->route('job_id')); - $res2 = $this->fetchesJobResult->execute(['request_signature' => $res1->request_signature, 'result_not_null' => true, 'order_by_id_desc' => true]); - Log::info('Job id: '.$res2->id." , request_signature: ".$res2->request_signature); - return $res2; + throw new JobResourceNotFoundException('Unable to find any job based on the criteria provided'); } return $res1; diff --git a/app/Classes/Modules/Jobs/Processors/UpdateJobResultProcessor.php b/app/Classes/Modules/Jobs/Processors/UpdateJobResultProcessor.php index fff83bb0..0106417d 100644 --- a/app/Classes/Modules/Jobs/Processors/UpdateJobResultProcessor.php +++ b/app/Classes/Modules/Jobs/Processors/UpdateJobResultProcessor.php @@ -44,9 +44,9 @@ class UpdateJobResultProcessor try{ $jobResultExisting = $this->fetchesJobResult->execute(['request_signature' => $jobResultCurrent->request_signature, 'result_not_null' => true, 'order_by_id_desc' => true]); $resultSignatureExisting = $jobResultExisting->result_signature; - if($resultSignatureExisting != $resultSignatureCurrent){ + //if($resultSignatureExisting != $resultSignatureCurrent){ $this->updateJobResult($jobResultCurrent, $resultCurrentJson, $resultSignatureCurrent, $listGenericJobObject->getJobCommandName(), $listGenericJobObject->getJobCommand()); - } + //} } catch (JobResourceNotFoundException $exception){ $this->updateJobResult($jobResultCurrent, $resultCurrentJson, $resultSignatureCurrent, $listGenericJobObject->getJobCommandName(), $listGenericJobObject->getJobCommand()); } diff --git a/app/Classes/Modules/PerfexCRM/Processors/CreatePerfexCRMInvoiceProcessor.php b/app/Classes/Modules/PerfexCRM/Processors/CreatePerfexCRMInvoiceProcessor.php index 4edb2ef5..dae44588 100644 --- a/app/Classes/Modules/PerfexCRM/Processors/CreatePerfexCRMInvoiceProcessor.php +++ b/app/Classes/Modules/PerfexCRM/Processors/CreatePerfexCRMInvoiceProcessor.php @@ -108,12 +108,12 @@ class CreatePerfexCRMInvoiceProcessor $email = null; if ($firstSupplier) { $email = $firstSupplier->email; - Log::error('CreatePerfexCRMInvoiceProcessor debug:'.$email); + Log::channel('perfex_crm')->info('CreatePerfexCRMInvoiceProcessor debug:'.$email); } else { $bookingMarking = $transaction->owner->marking; $serviceTypeName = $transaction->owner->company->services()->where('id', $transaction->owner->service_id)->first()->name; $projectName = 'Exchange | '.$serviceTypeName.' | '.$bookingMarking; - Log::error('$projectName: '.$projectName); + Log::channel('perfex_crm')->info('$projectName: '.$projectName); return $email; } diff --git a/app/Classes/Modules/PerfexCRM/Processors/FetchPerfexCRMInvoiceProcessor.php b/app/Classes/Modules/PerfexCRM/Processors/FetchPerfexCRMInvoiceProcessor.php index 4c8ee9bf..c073fb7a 100644 --- a/app/Classes/Modules/PerfexCRM/Processors/FetchPerfexCRMInvoiceProcessor.php +++ b/app/Classes/Modules/PerfexCRM/Processors/FetchPerfexCRMInvoiceProcessor.php @@ -62,7 +62,7 @@ class FetchPerfexCRMInvoiceProcessor $invoiceId = $result->payload['id']; } else { $log['message'] = 'FetchPerfexCRMInvoiceProcessor failed for transaction > bill_no: '.$number; - Helper::debugLogger($log); + Log::channel('perfex_crm')->info($log); } } else{ diff --git a/app/Classes/Modules/PerfexCRM/Processors/UpdatePerfexCRMProcessor.php b/app/Classes/Modules/PerfexCRM/Processors/UpdatePerfexCRMProcessor.php index fbf64be8..ac422c33 100644 --- a/app/Classes/Modules/PerfexCRM/Processors/UpdatePerfexCRMProcessor.php +++ b/app/Classes/Modules/PerfexCRM/Processors/UpdatePerfexCRMProcessor.php @@ -217,8 +217,8 @@ class UpdatePerfexCRMProcessor } $result = $this->fetchesPerfexCRMTask->execute($taskName, $milestoneId, 'project', $projectId, $updatePerfexCRMObject->getInvoiceId()); - // Log::error("UpdatePerfexCRMProcessor task: ".$taskName." , ".json_encode($result)); - Log::error("UpdatePerfexCRMProcessor task: ".$taskName); + // Log::channel('perfex_crm')->info("UpdatePerfexCRMProcessor task: ".$taskName." , ".json_encode($result)); + Log::channel('perfex_crm')->info("UpdatePerfexCRMProcessor task: ".$taskName); if(isset($result->payload)){ //&& $result->payload[0]['status'] == PerfexCRMTaskStatus::NOT_STARTED diff --git a/app/Classes/Modules/PerfexCRM/Services/ConvertsPerfexCRMLeadToCustomer.php b/app/Classes/Modules/PerfexCRM/Services/ConvertsPerfexCRMLeadToCustomer.php index e6e7323e..92e90a52 100644 --- a/app/Classes/Modules/PerfexCRM/Services/ConvertsPerfexCRMLeadToCustomer.php +++ b/app/Classes/Modules/PerfexCRM/Services/ConvertsPerfexCRMLeadToCustomer.php @@ -24,7 +24,7 @@ class ConvertsPerfexCRMLeadToCustomer return (object) $data; }else{ - Log::error($response); + Log::channel('perfex_crm')->info($response); return null; } }catch(\Exception $exception){ diff --git a/app/Classes/Modules/PerfexCRM/Services/CreatesPerfexCRMCustomer.php b/app/Classes/Modules/PerfexCRM/Services/CreatesPerfexCRMCustomer.php index e5a19ce3..b7eabaa7 100644 --- a/app/Classes/Modules/PerfexCRM/Services/CreatesPerfexCRMCustomer.php +++ b/app/Classes/Modules/PerfexCRM/Services/CreatesPerfexCRMCustomer.php @@ -27,7 +27,7 @@ class CreatesPerfexCRMCustomer $data = $response->json(); return (object) $data; }else{ - Log::error($response); + Log::channel('perfex_crm')->info($response); return null; } }catch(\Exception $exception){ diff --git a/app/Classes/Modules/PerfexCRM/Services/CreatesPerfexCRMCustomerContact.php b/app/Classes/Modules/PerfexCRM/Services/CreatesPerfexCRMCustomerContact.php index 519c1495..12d3d7e8 100644 --- a/app/Classes/Modules/PerfexCRM/Services/CreatesPerfexCRMCustomerContact.php +++ b/app/Classes/Modules/PerfexCRM/Services/CreatesPerfexCRMCustomerContact.php @@ -34,7 +34,7 @@ class CreatesPerfexCRMCustomerContact $data = $response->json(); return (object) $data; }else{ - Log::error($response); + Log::channel('perfex_crm')->info($response); return null; } }catch(\Exception $exception){ diff --git a/app/Classes/Modules/PerfexCRM/Services/CreatesPerfexCRMCustomerProject.php b/app/Classes/Modules/PerfexCRM/Services/CreatesPerfexCRMCustomerProject.php index f5d4de3e..1f513f31 100644 --- a/app/Classes/Modules/PerfexCRM/Services/CreatesPerfexCRMCustomerProject.php +++ b/app/Classes/Modules/PerfexCRM/Services/CreatesPerfexCRMCustomerProject.php @@ -33,7 +33,7 @@ class CreatesPerfexCRMCustomerProject $data = $response->json(); return (object) $data; }else{ - Log::error($response); + Log::channel('perfex_crm')->info($response); return null; } }catch(\Exception $exception){ diff --git a/app/Classes/Modules/PerfexCRM/Services/CreatesPerfexCRMInvoice.php b/app/Classes/Modules/PerfexCRM/Services/CreatesPerfexCRMInvoice.php index ba0c2755..df952c4b 100644 --- a/app/Classes/Modules/PerfexCRM/Services/CreatesPerfexCRMInvoice.php +++ b/app/Classes/Modules/PerfexCRM/Services/CreatesPerfexCRMInvoice.php @@ -53,7 +53,7 @@ class CreatesPerfexCRMInvoice $data = $response->json(); return (object) $data; }else{ - Log::error($response); + Log::channel('perfex_crm')->info($response); return null; } }catch(\Exception $exception){ diff --git a/app/Classes/Modules/PerfexCRM/Services/CreatesPerfexCRMInvoicePayment.php b/app/Classes/Modules/PerfexCRM/Services/CreatesPerfexCRMInvoicePayment.php index f3e92529..64590232 100644 --- a/app/Classes/Modules/PerfexCRM/Services/CreatesPerfexCRMInvoicePayment.php +++ b/app/Classes/Modules/PerfexCRM/Services/CreatesPerfexCRMInvoicePayment.php @@ -33,7 +33,7 @@ class CreatesPerfexCRMInvoicePayment $data = $response->json(); return (object) $data; }else{ - Log::error($response); + Log::channel('perfex_crm')->info($response); return null; } }catch(\Exception $exception){ diff --git a/app/Classes/Modules/PerfexCRM/Services/CreatesPerfexCRMLead.php b/app/Classes/Modules/PerfexCRM/Services/CreatesPerfexCRMLead.php index 373f4171..5ecef6e7 100644 --- a/app/Classes/Modules/PerfexCRM/Services/CreatesPerfexCRMLead.php +++ b/app/Classes/Modules/PerfexCRM/Services/CreatesPerfexCRMLead.php @@ -40,7 +40,7 @@ class CreatesPerfexCRMLead $data = $response->json(); return (object) $data; }else{ - Log::error($response); + Log::channel('perfex_crm')->info($response); return null; } }catch(\Exception $exception){ diff --git a/app/Classes/Modules/PerfexCRM/Services/CreatesPerfexCRMMilestone.php b/app/Classes/Modules/PerfexCRM/Services/CreatesPerfexCRMMilestone.php index 80cb49bf..91afd314 100644 --- a/app/Classes/Modules/PerfexCRM/Services/CreatesPerfexCRMMilestone.php +++ b/app/Classes/Modules/PerfexCRM/Services/CreatesPerfexCRMMilestone.php @@ -36,7 +36,7 @@ class CreatesPerfexCRMMilestone $data = $response->json(); return (object) $data; }else{ - Log::error($response); + Log::channel('perfex_crm')->info($response); return null; } }catch(\Exception $exception){ diff --git a/app/Classes/Modules/PerfexCRM/Services/CreatesPerfexCRMTask.php b/app/Classes/Modules/PerfexCRM/Services/CreatesPerfexCRMTask.php index feb8f9c8..45105fa9 100644 --- a/app/Classes/Modules/PerfexCRM/Services/CreatesPerfexCRMTask.php +++ b/app/Classes/Modules/PerfexCRM/Services/CreatesPerfexCRMTask.php @@ -56,7 +56,7 @@ class CreatesPerfexCRMTask $data = $response->json(); return (object) $data; }else{ - Log::error($response); + Log::channel('perfex_crm')->info($response); return null; } }catch(\Exception $exception){ diff --git a/app/Classes/Modules/PerfexCRM/Services/FetchesPerfexCRMCustomer.php b/app/Classes/Modules/PerfexCRM/Services/FetchesPerfexCRMCustomer.php index 9f3928f6..6efebec4 100644 --- a/app/Classes/Modules/PerfexCRM/Services/FetchesPerfexCRMCustomer.php +++ b/app/Classes/Modules/PerfexCRM/Services/FetchesPerfexCRMCustomer.php @@ -24,7 +24,7 @@ class FetchesPerfexCRMCustomer return (object) $data; }else{ - Log::error($response); + Log::channel('perfex_crm')->info($response); return null; } }catch(\Exception $exception){ diff --git a/app/Classes/Modules/PerfexCRM/Services/FetchesPerfexCRMInvoice.php b/app/Classes/Modules/PerfexCRM/Services/FetchesPerfexCRMInvoice.php index cd7aff30..7946cfec 100644 --- a/app/Classes/Modules/PerfexCRM/Services/FetchesPerfexCRMInvoice.php +++ b/app/Classes/Modules/PerfexCRM/Services/FetchesPerfexCRMInvoice.php @@ -26,7 +26,7 @@ class FetchesPerfexCRMInvoice return (object) $data; }else{ - Log::error($response); + Log::channel('perfex_crm')->info($response); return null; } }catch(\Exception $exception){ diff --git a/app/Classes/Modules/PerfexCRM/Services/FetchesPerfexCRMLead.php b/app/Classes/Modules/PerfexCRM/Services/FetchesPerfexCRMLead.php index df9c754d..a3543b20 100644 --- a/app/Classes/Modules/PerfexCRM/Services/FetchesPerfexCRMLead.php +++ b/app/Classes/Modules/PerfexCRM/Services/FetchesPerfexCRMLead.php @@ -24,7 +24,7 @@ class FetchesPerfexCRMLead return (object) $data; }else{ - Log::error($response); + Log::channel('perfex_crm')->info($response); return null; } }catch(\Exception $exception){ diff --git a/app/Classes/Modules/PerfexCRM/Services/FetchesPerfexCRMMilestone.php b/app/Classes/Modules/PerfexCRM/Services/FetchesPerfexCRMMilestone.php index 30ae0737..9c482fe7 100644 --- a/app/Classes/Modules/PerfexCRM/Services/FetchesPerfexCRMMilestone.php +++ b/app/Classes/Modules/PerfexCRM/Services/FetchesPerfexCRMMilestone.php @@ -30,7 +30,7 @@ class FetchesPerfexCRMMilestone return (object) $data; }else{ - Log::error($response); + Log::channel('perfex_crm')->info($response); return null; } }catch(\Exception $exception){ diff --git a/app/Classes/Modules/PerfexCRM/Services/FetchesPerfexCRMProject.php b/app/Classes/Modules/PerfexCRM/Services/FetchesPerfexCRMProject.php index c55f2c01..ce9762d8 100644 --- a/app/Classes/Modules/PerfexCRM/Services/FetchesPerfexCRMProject.php +++ b/app/Classes/Modules/PerfexCRM/Services/FetchesPerfexCRMProject.php @@ -30,7 +30,7 @@ class FetchesPerfexCRMProject return (object) $data; }else{ - Log::error($response); + Log::channel('perfex_crm')->info($response); return null; } }catch(\Exception $exception){ diff --git a/app/Classes/Modules/PerfexCRM/Services/FetchesPerfexCRMTask.php b/app/Classes/Modules/PerfexCRM/Services/FetchesPerfexCRMTask.php index 6cd4f052..0ab2b0fd 100644 --- a/app/Classes/Modules/PerfexCRM/Services/FetchesPerfexCRMTask.php +++ b/app/Classes/Modules/PerfexCRM/Services/FetchesPerfexCRMTask.php @@ -44,7 +44,7 @@ class FetchesPerfexCRMTask return (object) $data; }else{ - Helper::debugLogger($response); + Log::channel('perfex_crm')->info($response); return null; } }catch(\Exception $exception){ diff --git a/app/Classes/Modules/PerfexCRM/Services/UpdatesPerfexCRMCustomer.php b/app/Classes/Modules/PerfexCRM/Services/UpdatesPerfexCRMCustomer.php index 6d91c081..15963c31 100644 --- a/app/Classes/Modules/PerfexCRM/Services/UpdatesPerfexCRMCustomer.php +++ b/app/Classes/Modules/PerfexCRM/Services/UpdatesPerfexCRMCustomer.php @@ -38,7 +38,7 @@ class UpdatesPerfexCRMCustomer $data = $response->json(); return (object) $data; }else{ - Helper::debugLogger($response); + Log::channel('perfex_crm')->info($response); return null; } }catch(\Exception $exception){ diff --git a/app/Classes/Modules/PerfexCRM/Services/UpdatesPerfexCRMInvoice.php b/app/Classes/Modules/PerfexCRM/Services/UpdatesPerfexCRMInvoice.php index 9adb9460..9825dde2 100644 --- a/app/Classes/Modules/PerfexCRM/Services/UpdatesPerfexCRMInvoice.php +++ b/app/Classes/Modules/PerfexCRM/Services/UpdatesPerfexCRMInvoice.php @@ -60,7 +60,7 @@ class UpdatesPerfexCRMInvoice $data = $response->json(); return (object) $data; }else{ - Log::error($response); + Log::channel('perfex_crm')->info($response); return null; } }catch(\Exception $exception){ diff --git a/app/Classes/Modules/PerfexCRM/Services/UpdatesPerfexCRMLead.php b/app/Classes/Modules/PerfexCRM/Services/UpdatesPerfexCRMLead.php index f8fbc944..69ac7fa8 100644 --- a/app/Classes/Modules/PerfexCRM/Services/UpdatesPerfexCRMLead.php +++ b/app/Classes/Modules/PerfexCRM/Services/UpdatesPerfexCRMLead.php @@ -41,7 +41,7 @@ class UpdatesPerfexCRMLead $data = $response->json(); return (object) $data; }else{ - Log::error($response); + Log::channel('perfex_crm')->info($response); return null; } }catch(\Exception $exception){ diff --git a/app/Classes/Modules/PerfexCRM/Services/UpdatesPerfexCRMProject.php b/app/Classes/Modules/PerfexCRM/Services/UpdatesPerfexCRMProject.php index cf782806..4b65347e 100644 --- a/app/Classes/Modules/PerfexCRM/Services/UpdatesPerfexCRMProject.php +++ b/app/Classes/Modules/PerfexCRM/Services/UpdatesPerfexCRMProject.php @@ -33,7 +33,7 @@ class UpdatesPerfexCRMProject $data = $response->json(); return (object) $data; }else{ - Log::error($response); + Log::channel('perfex_crm')->info($response); return null; } }catch(\Exception $exception){ diff --git a/app/Classes/Modules/PerfexCRM/Services/UpdatesPerfexCRMTask.php b/app/Classes/Modules/PerfexCRM/Services/UpdatesPerfexCRMTask.php index 95a09525..053fa16d 100644 --- a/app/Classes/Modules/PerfexCRM/Services/UpdatesPerfexCRMTask.php +++ b/app/Classes/Modules/PerfexCRM/Services/UpdatesPerfexCRMTask.php @@ -40,7 +40,7 @@ class UpdatesPerfexCRMTask $data = $response->json(); return (object) $data; }else{ - Log::error($response); + Log::channel('perfex_crm')->info($response); return null; } }catch(\Exception $exception){ diff --git a/app/Classes/Modules/Transactions/ControllersLogic/CreateSupplierTransactionLogic.php b/app/Classes/Modules/Transactions/ControllersLogic/CreateSupplierTransactionLogic.php index 2dcbd0f7..4c407cf5 100644 --- a/app/Classes/Modules/Transactions/ControllersLogic/CreateSupplierTransactionLogic.php +++ b/app/Classes/Modules/Transactions/ControllersLogic/CreateSupplierTransactionLogic.php @@ -3,6 +3,7 @@ namespace App\Classes\Modules\Transactions\ControllersLogic; +use App\Classes\Exceptions\MalformedRequestException; use App\Classes\Modules\Transactions\Processors\CreateSupplierTransactionProcessor; use App\Classes\Modules\Transactions\Services\GeneratesTransactionBillNumber; use App\Models\Document; @@ -18,6 +19,7 @@ use App\Classes\General\Abstracts\AbstractControllerLogic; use App\Classes\Modules\Companies\Services\FetchesCompany; use App\Classes\Modules\Documents\Services\CreatesDocument; use App\Classes\Modules\Documents\DataTransferObjects\DocumentObject; +use App\Classes\Modules\Transactions\Services\FetchesTransaction; class CreateSupplierTransactionLogic extends AbstractControllerLogic { @@ -48,6 +50,9 @@ class CreateSupplierTransactionLogic extends AbstractControllerLogic /** @var GeneratesTransactionBillNumber */ private $generatesTransactionBillNumber; + /** @var FetchesTransaction */ + private $fetchesTransaction; + /** * CreateSupplierTransactionLogic constructor. @@ -56,14 +61,16 @@ class CreateSupplierTransactionLogic extends AbstractControllerLogic * @param CreatesDocument $createsDocument * @param CreatesFiles $createsFile * @param GeneratesTransactionBillNumber $generatesTransactionBillNumber + * @param FetchesTransaction $fetchesTransaction */ - public function __construct(FetchesCompany $fetchesCompany, CreateSupplierTransactionProcessor $createSupplierTransactionProcessor, CreatesDocument $createsDocument, CreatesFiles $createsFile, GeneratesTransactionBillNumber $generatesTransactionBillNumber) + public function __construct(FetchesCompany $fetchesCompany, CreateSupplierTransactionProcessor $createSupplierTransactionProcessor, CreatesDocument $createsDocument, CreatesFiles $createsFile, GeneratesTransactionBillNumber $generatesTransactionBillNumber, FetchesTransaction $fetchesTransaction) { $this->fetchesCompany = $fetchesCompany; $this->createSupplierTransactionProcessor = $createSupplierTransactionProcessor; $this->createsDocument = $createsDocument; $this->createsFile = $createsFile; $this->generatesTransactionBillNumber = $generatesTransactionBillNumber; + $this->fetchesTransaction = $fetchesTransaction; } public function logic(Request $request) : JsonResponse @@ -75,6 +82,23 @@ class CreateSupplierTransactionLogic extends AbstractControllerLogic $payments = $request->input('payments'); + // todo-refund: activate this for partial refund + foreach($payments as $payment){ + $payment = $this->fetchesTransaction->execute(['id' => $payment['id']]); + + $pendingRefundRequest = $payment->transactions()->refunds()->where('status', ApprovalStatus::PENDING_VERIFICATION)->first(); + + if ($pendingRefundRequest) { + throw new MalformedRequestException('Unable to create supplier order for pending refund request payment'); + } + + $totalRefund = $payment->transactions()->refunds()->where('status', ApprovalStatus::APPROVED)->sum('original_amount'); + + if ($payment->original_amount - $totalRefund <= 0) { + throw new MalformedRequestException('Unable to create supplier order for fully refunded payment'); + } + } + $this->createSupplierTransactionProcessor->execute($supplier, $rate, $payments); if(!count($this->createSupplierTransactionProcessor->getBills())) return $this->response([]); diff --git a/app/Classes/Modules/Transactions/ControllersLogic/UpdateRefundTransactionStatusLogic.php b/app/Classes/Modules/Transactions/ControllersLogic/UpdateRefundTransactionStatusLogic.php index b86e4878..09e4b102 100644 --- a/app/Classes/Modules/Transactions/ControllersLogic/UpdateRefundTransactionStatusLogic.php +++ b/app/Classes/Modules/Transactions/ControllersLogic/UpdateRefundTransactionStatusLogic.php @@ -13,6 +13,8 @@ use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; use App\Classes\Modules\Wallets\Processors\CreditWalletProcessor; +use App\Classes\Modules\Bookings\Services\CalculatesBookingPayableAmount; +use App\Classes\Modules\Bookings\Services\CalculatesBookingRefundAmount; class UpdateRefundTransactionStatusLogic extends AbstractControllerLogic @@ -43,6 +45,12 @@ class UpdateRefundTransactionStatusLogic extends AbstractControllerLogic /** @var CreditWalletProcessor */ private $creditWalletProcessor; + /** @var CalculatesBookingPayableAmount */ + private $calculatesBookingPayableAmount; + + /** @var CalculatesBookingRefundAmount */ + private $calculatesBookingRefundAmount; + /** * CreatePaymentVerificationDocumentLogic constructor. * @param FetchesCompany $fetchesCompany @@ -50,14 +58,18 @@ class UpdateRefundTransactionStatusLogic extends AbstractControllerLogic * @param UpdatesTransactionStatus $updatesTransactionStatus * @param DeletesDocument $deletesDocument * @param CreditWalletProcessor $creditWalletProcessor + * @param CalculatesBookingPayableAmount $calculatesBookingPayableAmount + * @param CalculatesBookingRefundAmount $calculatesBookingRefundAmount */ - public function __construct(FetchesCompany $fetchesCompany, FetchesTransaction $fetchesTransaction, UpdatesTransactionStatus $updatesTransactionStatus, DeletesDocument $deletesDocument, CreditWalletProcessor $creditWalletProcessor) + public function __construct(FetchesCompany $fetchesCompany, FetchesTransaction $fetchesTransaction, UpdatesTransactionStatus $updatesTransactionStatus, DeletesDocument $deletesDocument, CreditWalletProcessor $creditWalletProcessor, CalculatesBookingPayableAmount $calculatesBookingPayableAmount, CalculatesBookingRefundAmount $calculatesBookingRefundAmount) { $this->fetchesCompany = $fetchesCompany; $this->fetchesTransaction = $fetchesTransaction; $this->updatesTransactionStatus = $updatesTransactionStatus; $this->deletesDocument = $deletesDocument; $this->creditWalletProcessor = $creditWalletProcessor; + $this->calculatesBookingPayableAmount = $calculatesBookingPayableAmount; + $this->calculatesBookingRefundAmount = $calculatesBookingRefundAmount; } /** @@ -67,19 +79,24 @@ class UpdateRefundTransactionStatusLogic extends AbstractControllerLogic */ public function logic(Request $request) : JsonResponse { - $transaction = $this->fetchesTransaction->execute(['id' => $request->route('id')]); + $refundTransaction = $this->fetchesTransaction->execute(['id' => $request->route('id')]); - $transaction = $this->updatesTransactionStatus->execute($transaction, $request->input('status')); + $refundTransaction = $this->updatesTransactionStatus->execute($refundTransaction, $request->route('status')); - $booking = $transaction->owner->owner; + $paymentTransaction = $refundTransaction->owner; - $reference = 'Credit Voucher for Overpaid for Ref. '.$booking->marking; + $booking = $paymentTransaction->owner; - if ($transaction->status == ApprovalStatus::APPROVED) { - $this->creditWalletProcessor->execute($booking->company, $transaction->type, $transaction->amount, $reference); + $reference = $refundTransaction->amount == $paymentTransaction->amount ? 'Fully Refund for Ref. ' . $booking->marking : 'Partially Refund for Ref. ' . $booking->marking; + + if ($refundTransaction->status == ApprovalStatus::APPROVED) { + $this->creditWalletProcessor->execute($booking->company, $refundTransaction->type, $refundTransaction->amount, $reference); } - + $paidAmount = $paymentTransaction->original_amount - $this->calculatesBookingRefundAmount->calculateRefundAmount($paymentTransaction, $booking->fix_currency_id); + if (!$paidAmount > 0) { + $this->updatesTransactionStatus->execute($paymentTransaction, ApprovalStatus::REFUNDED); + } return $this->response([]); } diff --git a/app/Classes/Modules/Transactions/Processors/CreateSupplierTransactionProcessor.php b/app/Classes/Modules/Transactions/Processors/CreateSupplierTransactionProcessor.php index 9b944a5b..b514b404 100644 --- a/app/Classes/Modules/Transactions/Processors/CreateSupplierTransactionProcessor.php +++ b/app/Classes/Modules/Transactions/Processors/CreateSupplierTransactionProcessor.php @@ -81,15 +81,19 @@ class CreateSupplierTransactionProcessor if($payment->status !== ApprovalStatus::APPROVED) continue; + $totalRefund = $payment->transactions()->refunds()->where('status', ApprovalStatus::APPROVED)->sum('original_amount'); + + $original_amount_after_refund = $payment->original_amount - $totalRefund; + $this->updatesTransactionStatus->execute($payment, ApprovalStatus::COMPLETED); $billNumber = $this->generatesTransactionBillNumber->execute('SPLR-'); $constant = SegmentConstant::where('reference', SegmentConstants::SERVICE_CHARGE)->where('detail->id', $supplier->id)->first(); - $serviceCharge = $this->calculatesTransactionServiceCharge->execute($payment->original_amount, $rate, $constant); + $serviceCharge = $this->calculatesTransactionServiceCharge->execute($original_amount_after_refund, $rate, $constant); $object = new TransactionObject($billNumber, TransactionType::BILL, $supplier->id, 1, $supplier->banks()->where('default', true)->first()->id, PaymentMethodType::CASH, - $payment->original_amount * (1 / $rate), $payment->original_amount, 1, $payment->original_currency_id, + $original_amount_after_refund * (1 / $rate), $original_amount_after_refund, 1, $payment->original_currency_id, $rate, 0, $serviceCharge, null, ApprovalStatus::PENDING_SUBMISSION); /** @var Transaction $billTransaction */ @@ -101,7 +105,7 @@ class CreateSupplierTransactionProcessor $transferFee = $this->calculatesTransactionTransferFee->execute($billTransaction->original_amount, $constant); $object = new TransactionObject($transferFeeNumber, TransactionType::TRANSFER_FEE, 1, $supplier->id, $supplier->banks()->where('default', true)->first()->id, PaymentMethodType::CASH, - $payment->original_amount, $payment->original_amount, $payment->original_currency_id, $payment->original_currency_id, + $original_amount_after_refund, $original_amount_after_refund, $payment->original_currency_id, $payment->original_currency_id, 1, 0, $transferFee, null, ApprovalStatus::PENDING_VERIFICATION); $this->pushTransferFee($this->createsTransaction->execute($billTransaction, $object)); diff --git a/app/Classes/Modules/Vouchers/ControllersLogic/ListUserVouchersLogic.php b/app/Classes/Modules/Vouchers/ControllersLogic/ListUserVouchersLogic.php index 16356f0f..013be9d6 100644 --- a/app/Classes/Modules/Vouchers/ControllersLogic/ListUserVouchersLogic.php +++ b/app/Classes/Modules/Vouchers/ControllersLogic/ListUserVouchersLogic.php @@ -4,9 +4,11 @@ namespace App\Classes\Modules\Vouchers\ControllersLogic; use App\Classes\General\Abstracts\AbstractControllerLogic; use App\Classes\Modules\Rewards\Services\ListsUserRewards; +use App\Classes\ValueObjects\Constants\RoleTypes; use App\Http\Resources\UserRewardResource; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; +use Illuminate\Support\Facades\Auth; class ListUserVouchersLogic extends AbstractControllerLogic { @@ -40,6 +42,11 @@ class ListUserVouchersLogic extends AbstractControllerLogic public function logic(Request $request) : JsonResponse { $query = $this->listsUserRewards->execute($this->listsUserRewards->deserializeFilters($request->input('filters'))); + + if(in_array(Auth::user()->type, RoleTypes::ADMIN_ROLES)){ + $request->merge(['isAdmin' => true]); + } + return $this->collectionResponse(UserRewardResource::collection($query)); } diff --git a/app/Classes/Modules/Vouchers/ControllersLogic/ValidateVoucherLogic.php b/app/Classes/Modules/Vouchers/ControllersLogic/ValidateVoucherLogic.php index 4b820eb1..30e7fe12 100644 --- a/app/Classes/Modules/Vouchers/ControllersLogic/ValidateVoucherLogic.php +++ b/app/Classes/Modules/Vouchers/ControllersLogic/ValidateVoucherLogic.php @@ -44,10 +44,16 @@ class ValidateVoucherLogic extends AbstractControllerLogic { $booking = Booking::find($request->input('itemId')); $employee = $booking->company->employees()->first(); + $amount = $this->floatvalue($request->input('amount')); - $validateVoucherifyVoucherObject = new ValidateVoucherifyVoucherObject($booking->company_id, $request->input('voucherCode'), $request->input('amount'), $employee); + $validateVoucherifyVoucherObject = new ValidateVoucherifyVoucherObject($booking->company_id, $request->input('voucherCode'), $amount, $employee); $result = $this->validatesVoucherifyVoucher->execute($validateVoucherifyVoucherObject); return $this->response(['data' => $result]); } + private function floatvalue($val){ + $val = str_replace(",",".",$val); + $val = preg_replace('/\.(?=.*\.)/', '', $val); + return floatval($val); + } } diff --git a/app/Classes/Modules/Vouchers/DataTransferObjects/VoucherObject.php b/app/Classes/Modules/Vouchers/DataTransferObjects/VoucherObject.php index f624b3cc..d4fd1e7b 100644 --- a/app/Classes/Modules/Vouchers/DataTransferObjects/VoucherObject.php +++ b/app/Classes/Modules/Vouchers/DataTransferObjects/VoucherObject.php @@ -3,6 +3,7 @@ namespace App\Classes\Modules\Vouchers\DataTransferObjects; use App\Classes\General\Interfaces\DataTransferObject; +use Carbon\Carbon; use DateTime; use Illuminate\Support\Facades\Log; @@ -86,7 +87,8 @@ class VoucherObject implements DataTransferObject { try { if(!$this->startDate) return null; - $dateTime = new DateTime($this->startDate); + // $dateTime = new DateTime($this->startDate); + $dateTime = Carbon::parse($this->startDate)->tz('Asia/Kuala_Lumpur'); return $dateTime; } catch (\Exception $e) { Log::error($e); @@ -101,7 +103,7 @@ class VoucherObject implements DataTransferObject { try { if(!$this->endDate) return null; - $dateTime = new DateTime($this->endDate); + $dateTime = Carbon::parse($this->endDate)->tz('Asia/Kuala_Lumpur'); return $dateTime; } catch (\Exception $e) { Log::error($e); diff --git a/app/Classes/Notifications/WelcomeVoucherEmail.php b/app/Classes/Notifications/WelcomeVoucherEmail.php new file mode 100644 index 00000000..0800b8cc --- /dev/null +++ b/app/Classes/Notifications/WelcomeVoucherEmail.php @@ -0,0 +1,43 @@ +user = $user; + $this->voucher = $voucher; + } + + + public function toMail() + { + $this->voucher->end_date = Carbon::parse($this->voucher->end_date)->format('Y-m-d'); + $mailMessage = (new MailMessage) + ->subject('Welcome Voucher') + ->view('emails.accounts.welcome_voucher', ['user' => $this->user, 'voucher' => $this->voucher]); + + return $mailMessage; + } + + +} diff --git a/app/Classes/ValueObjects/Constants/Vouchers.php b/app/Classes/ValueObjects/Constants/Vouchers.php new file mode 100644 index 00000000..d43194f9 --- /dev/null +++ b/app/Classes/ValueObjects/Constants/Vouchers.php @@ -0,0 +1,8 @@ +generatesPurchaseOrderProducts = $generatesPurchaseOrderProducts; + $this->generatesTransactionBillNumber = $generatesTransactionBillNumber; + $this->createPurchaseOrderTransactionProcessor = $createPurchaseOrderTransactionProcessor; + } + + /** + * Execute the console command. + * + * @return int + */ + public function handle() + { + // 5. If purchase order not fill up in 2 month, auto fill up it + $bookings = Booking::where('status', ApprovalStatus::APPROVED) + ->where('created_at', '<', now()->subDays(60)->endOfDay()) + ->whereHas('transactions', function($transaction) { + return $transaction->where('type', TransactionType::PAYMENT)->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]); + }) + ->whereDoesntHave('transactions', function($transaction){ + $transaction->where('type', TransactionType::PURCHASE_ORDER); + $transaction->whereIn('status', [ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::APPROVED]); + })->get(); + + foreach ($bookings as $booking) { + $po = Transaction::where('type', TransactionType::PURCHASE_ORDER) + ->where('status', ApprovalStatus::APPROVED)->where('issuer', $booking->company_id) + ->select('*', DB::raw('abs(amount - ' . $booking->fix_amount . ') as nearest_price'))->orderBy('nearest_price')->first(); + + + if (!$po) { + $po = Transaction::where('type', TransactionType::PURCHASE_ORDER) + ->where('status', ApprovalStatus::APPROVED)->select('*', DB::raw('abs(amount - ' . $booking->fix_amount . ') as nearest_price'))->orderBy('nearest_price')->first(); + } + + $products = $this->generatesPurchaseOrderProducts->execute($po, $booking->fix_amount); + + $deference = $booking->fix_amount - $products->sum('total'); + + if($deference > -150 && $deference < 150 && $deference != 0) { + + $products->push([ + 'description' => $deference < 0 ? 'Discount':'Shipping Fee', + 'quantity' => 1, + 'stockCode' => '', + 'total' => $deference, + 'unit_price' => $deference + ]); + } + + $billNumber = $this->generatesTransactionBillNumber->execute('XPO-'); + + $total = $products->sum('total'); + + $object = new TransactionObject($billNumber, TransactionType::PURCHASE_ORDER, $booking->company->id, 1, + 1, PaymentMethodType::CASH, + $total, $total, $booking->fix_currency_id, $booking->fix_currency_id, + 1, 0, 0, null, ApprovalStatus::PENDING_SUBMISSION, $products->toArray()); + + $this->createPurchaseOrderTransactionProcessor->execute($booking, $object); + } + } +} diff --git a/app/Console/Commands/ExpiredBookingCommand.php b/app/Console/Commands/ExpiredBookingCommand.php new file mode 100644 index 00000000..fe4f260e --- /dev/null +++ b/app/Console/Commands/ExpiredBookingCommand.php @@ -0,0 +1,100 @@ +updatesBookingStatus = $updatesBookingStatus; + } + + /** + * Execute the console command. + * + * @return int + */ + public function handle() + { + // 1. Cancel booking without payment & purchase order (1 month) + $bookings = Booking::where('status', ApprovalStatus::APPROVED) + ->where('created_at', '<', now()->subDays(30)->endOfDay()) + ->where(function ($query) { + $query->whereDoesntHave('transactions') + ->orWhereDoesntHave('transactions', function($transaction) { + return $transaction->where('type', TransactionType::PURCHASE_ORDER)->orWhere(function ($q) { + $q->where('type', TransactionType::PAYMENT)->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]); + }); + }); + })->get(); + + foreach ($bookings as $booking) { + $this->updatesBookingStatus->execute($booking, ApprovalStatus::EXPIRED); + $this->info(Carbon::now() . " : Expired Booking without payment & purchase order, booking id: " . $booking->id); + $transactions = $booking->transactions; + + foreach ($transactions as $transaction) { + $prevStatus = $transaction->status; + $transaction->status = ApprovalStatus::EXPIRED; + $transaction->save(); + $this->info(Carbon::now() . " : Expired Transaction id: {$transaction->id} from Booking id: {$booking->id}. Status before update: {$prevStatus}"); + } + } + + // 2. Cancel booking without payment but with purchase order (2 month) + $bookings = Booking::where('status', ApprovalStatus::APPROVED) + ->where('created_at', '<', now()->subDays(60)->endOfDay()) + ->where(function ($query) { + $query->whereDoesntHave('transactions', function($transaction) { + return $transaction->where('type', TransactionType::PAYMENT)->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]); + })->whereHas('transactions', function($transaction) { + return $transaction->where('type', TransactionType::PURCHASE_ORDER); + }); + })->get(); + + foreach ($bookings as $booking) { + $this->updatesBookingStatus->execute($booking, ApprovalStatus::EXPIRED); + $this->info(Carbon::now() . " : Expired Booking without payment but with purchase order, booking id: " . $booking->id); + $transactions = $booking->transactions; + + foreach ($transactions as $transaction) { + $prevStatus = $transaction->status; + $transaction->status = ApprovalStatus::EXPIRED; + $transaction->save(); + $this->info(Carbon::now() . " : Expired Transaction id: {$transaction->id} from Booking id: {$booking->id}. Status before update: {$prevStatus}"); + } + } + } +} diff --git a/app/Console/Commands/ExpiredRefundedBookingCommand.php b/app/Console/Commands/ExpiredRefundedBookingCommand.php new file mode 100644 index 00000000..db7e00a7 --- /dev/null +++ b/app/Console/Commands/ExpiredRefundedBookingCommand.php @@ -0,0 +1,162 @@ +updatesBookingStatus = $updatesBookingStatus; + $this->generatesTransactionBillNumber = $generatesTransactionBillNumber; + $this->createsTransaction = $createsTransaction; + } + + /** + * Execute the console command. + * + * @return int + */ + public function handle() + { + // 3. Cancel fully refunded payment & cancel booking + $transactions = Transaction::where('type', TransactionType::CREDIT_NOTE)->where('payment_reference', 'LIKE', "%refund%")->get(); + + foreach ($transactions as $transaction) { + // get the booking marking + $payment_reference = explode(" ", trim($transaction->payment_reference)); + // $marking = substr($transaction->payment_reference, -5); + $marking = trim(end($payment_reference)); + + if (!preg_match('/^[0-9]+$/', $marking)) { + $payment_reference = explode(".", trim($transaction->payment_reference)); + $marking = trim(end($payment_reference)); + } + + // for a special payment reference on transaction id: 140231 + if (!preg_match('/^[0-9]+$/', $marking)) { + $payment_reference = explode("No", trim($transaction->payment_reference)); + $marking = end($payment_reference); + } + + // for a special payment reference on transaction id: 152013 + if (!preg_match('/^[0-9]+$/', $marking)) { + $payment_reference = explode(" ", trim($transaction->payment_reference)); + $marking = end($payment_reference); + $marking = prev($payment_reference); + } + + if (preg_match('/^[0-9]+$/', $marking)) { + $booking = Booking::where('marking', $marking)->first(); + + if ($booking) { + $bookingPayment = $booking->transactions()->payments()->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])->first(); + if (!$bookingPayment) { + $bookingPaymentCount = $booking->transactions()->payments()->count(); + if ($bookingPaymentCount > 1) { + Log::info("Credit note transaction id: {$transaction->id}, there are {$bookingPaymentCount} payment for the booking."); + foreach ($booking->transactions()->payments()->get() as $bp) { + if ($transaction->amount - $bp->amount < 0.01) { + $bookingPayment = $bp; + break; + } + } + } + + if (!$bookingPayment) { + $bookingPayment = $booking->transactions()->payments()->whereIn('status', [ApprovalStatus::SUSPENDED, ApprovalStatus::EXPIRED, ApprovalStatus::REJECTED])->orderBy('id', 'DESC')->first(); + } + $status = ApprovalStatus::APPROVAL_STATUS_ID[$bookingPayment->status]; + Log::info("Credit note transaction id: {$transaction->id}, the payment for the booking is in status {$status}"); + } + $bookingPaymentAmount = $bookingPayment->amount; + // check if the booking is fully refund + $amountDifference = bcsub($transaction->amount, $bookingPaymentAmount, 7); + + if (abs($amountDifference) < 0.01) { + // rejecting booking payment transaction + // $bookingPayment->status = ApprovalStatus::REJECTED; + // $bookingPayment->save(); + + //expired booking + // $this->updatesBookingStatus->execute($booking, ApprovalStatus::EXPIRED); + Log::info("Credit note transaction id: {$transaction->id} is fully refunded, the refunded amount was {$transaction->amount} the payment reference is: {$transaction->payment_reference}"); + // Log::info("Credit note transaction id: {$transaction->id}, Rejected Booking Transaction Payment id: {$bookingPayment->id}, the payment amount was {$bookingPayment->amount}"); + // Log::info("Credit note transaction id: {$transaction->id}, Expired Booking id: {$booking->id}"); + } else { + Log::info("Credit note transaction id: {$transaction->id} is not fully refunded, the refunded amount was {$transaction->amount}, the payment amount was {$bookingPayment->amount}, the payment reference is: {$transaction->payment_reference}"); + } + + $refund = $bookingPayment->transactions()->refunds()->where('amount', $transaction->amount)->where('status', ApprovalStatus::APPROVED)->first(); + + $bookingInWhiteForm = $bookingPayment->transactions()->bills()->first(); + + if ($refund) { + Log::info("Credit note transaction id: {$transaction->id}, already created same amount of refund transaction for same booking payment transaction"); + } + + if ($bookingInWhiteForm) { + Log::info("Credit note transaction id: {$transaction->id}, booking is in white form"); + } + + if (!$refund && !$bookingInWhiteForm) { + $billNumber = $this->generatesTransactionBillNumber->execute('RFD-'); + + $object = new TransactionObject($billNumber, TransactionType::REFUND, 1, $booking->company->id, + 1, PaymentMethodType::CASH, + $transaction->amount, $transaction->amount * $bookingPayment->currency_rate, 1, + $bookingPayment->original_currency_id, $bookingPayment->currency_rate, + 0, 0, null, ApprovalStatus::APPROVED, [], $bookingPayment->bill_no); + + $transaction = $this->createsTransaction->execute($bookingPayment, $object); + } + } else { + Log::info("Credit note transaction id: {$transaction->id}, booking marking not found, the payment reference is: {$transaction->payment_reference}"); + } + } else { + Log::info("Credit note transaction id: {$transaction->id} does not have booking marking, the payment reference is: {$transaction->payment_reference}"); + } + } + } +} diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index c191dc3f..bd3901f4 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -67,6 +67,17 @@ class Kernel extends ConsoleKernel ->hourly() ->appendOutputTo(storage_path().'/logs/delete-bulk-download-files.log') ->withoutOverlapping(); + + //cief todo: command version 2 + $schedule->command('booking:expired') + ->dailyAt('02:00') + ->appendOutputTo(storage_path().'/logs/expire-booking.log') + ->withoutOverlapping(); + + //cief todo: command version 2 + // $schedule->command('purchaseOrder:autoFill') + // ->dailyAt('03:00') + // ->withoutOverlapping(); } } diff --git a/app/Http/Controllers/Accounting/HistoryImportedTransactionMappedController.php b/app/Http/Controllers/Accounting/HistoryImportedTransactionMappedController.php new file mode 100644 index 00000000..8b4a2cde --- /dev/null +++ b/app/Http/Controllers/Accounting/HistoryImportedTransactionMappedController.php @@ -0,0 +1,20 @@ +execute($request); + } + +} \ No newline at end of file diff --git a/app/Http/Controllers/Exports/ExportCustomersToExcelController.php b/app/Http/Controllers/Exports/ExportCustomersToExcelController.php index 733c84fa..0f351c7d 100644 --- a/app/Http/Controllers/Exports/ExportCustomersToExcelController.php +++ b/app/Http/Controllers/Exports/ExportCustomersToExcelController.php @@ -18,6 +18,7 @@ use Maatwebsite\Excel\Excel; use App\Classes\Modules\Exports\Services\ExportsImportedInvoiceMappeds; use App\Models\TransactionMappingLog; use App\Classes\Modules\Exports\Services\ExportsReceiptTransactions; +use App\Classes\Modules\Exports\Services\ExportsImportedReceiptMappeds; class ExportCustomersToExcelController { @@ -91,4 +92,10 @@ class ExportCustomersToExcelController ob_end_clean(); return $response; } + + public function importedReceiptMapped(ExportsImportedReceiptMappeds $exportsImportedReceiptMappeds, Request $request) { + $response = $exportsImportedReceiptMappeds->download($request->input('fileName').'.xls', Excel::XLS, ['Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']); + ob_end_clean(); + return $response; + } } \ No newline at end of file diff --git a/app/Http/Controllers/Imports/ImportStatementInvoiceController.php b/app/Http/Controllers/Imports/ImportStatementInvoiceController.php index 75953f2b..e4c35eb5 100644 --- a/app/Http/Controllers/Imports/ImportStatementInvoiceController.php +++ b/app/Http/Controllers/Imports/ImportStatementInvoiceController.php @@ -100,6 +100,7 @@ class ImportStatementInvoiceController TransactionMappingLog::create([ 'imported_date'=>$importDate, + 'type' => 'invoices', 'data'=>$row, ]); array_push($data, $row); diff --git a/app/Http/Controllers/Imports/ImportStatementReceiptsController.php b/app/Http/Controllers/Imports/ImportStatementReceiptsController.php index a43f2dda..6c117642 100644 --- a/app/Http/Controllers/Imports/ImportStatementReceiptsController.php +++ b/app/Http/Controllers/Imports/ImportStatementReceiptsController.php @@ -69,6 +69,7 @@ class ImportStatementReceiptsController TransactionMappingLog::create([ 'imported_date'=>$importDate, + 'type' => 'receipts', 'data'=>$row, ]); array_push($data, $row); diff --git a/app/Http/Resources/BookingResource.php b/app/Http/Resources/BookingResource.php index 020db09c..14fd2936 100644 --- a/app/Http/Resources/BookingResource.php +++ b/app/Http/Resources/BookingResource.php @@ -32,7 +32,8 @@ class BookingResource extends JsonResource 'amount' => $this->fix_amount, 'floating_amount' => floatval((App()->make(CalculatesBookingFloatingAmount::class))->execute($this->resource, $this->fix_currency_id)), 'paid_amount' => floatval((App()->make(CalculatesBookingPayableAmount::class))->execute($this->resource, $this->fix_currency_id)) - floatval((App()->make(CalculatesBookingRefundAmount::class))->execute($this->resource, $this->fix_currency_id)), - 'outstanding_amount' => floatval((App()->make(CalculatesBookingOutstanding::class))->execute($this->resource)) - floatval((App()->make(CalculatesBookingRefundAmount::class))->execute($this->resource, $this->fix_currency_id)), + // 'outstanding_amount' => floatval((App()->make(CalculatesBookingOutstanding::class))->execute($this->resource)) + floatval((App()->make(CalculatesBookingRefundAmount::class))->execute($this->resource, $this->fix_currency_id)), + 'outstanding_amount' => floatval((App()->make(CalculatesBookingOutstanding::class))->execute($this->resource)), 'fixed_currency' => new CurrencyResource($this->fixedCurrency), 'convertible_currency' => new CurrencyResource($this->convertibleCurrency), 'conversion_currency' => new CurrencyResource($this->conversionCurrency), @@ -58,7 +59,7 @@ class BookingResource extends JsonResource 'expired_payment_attempts' => TransactionResource::collection($this->transactions()->payments()->where('status', ApprovalStatus::PENDING_SUBMISSION)->whereDate('expires_on', '>=', Carbon::now())->where('expires_on', '>', Carbon::now()->toTimeString())->get()), 'payment_history' => TransactionResource::collection($this->transactions()->where(function($query){ $query->where(function($query){ - $query->payments()->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::COMPLETED, ApprovalStatus::REJECTED]); + $query->payments()->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::COMPLETED, ApprovalStatus::REJECTED, ApprovalStatus::REFUNDED]); })->orWhere(function($query){ $query->where(function($query){ $query->where('type', TransactionType::REFUND)->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::REJECTED, ApprovalStatus::COMPLETED]); diff --git a/app/Http/Resources/KeyValueBasicResource.php b/app/Http/Resources/KeyValueBasicResource.php new file mode 100644 index 00000000..94725a0a --- /dev/null +++ b/app/Http/Resources/KeyValueBasicResource.php @@ -0,0 +1,24 @@ + $this->id, + 'key' => $this->key, + 'value' => $this->value, + ]; + } +} diff --git a/app/Http/Resources/TransactionMappingLogResource.php b/app/Http/Resources/TransactionMappingLogResource.php new file mode 100644 index 00000000..954294f1 --- /dev/null +++ b/app/Http/Resources/TransactionMappingLogResource.php @@ -0,0 +1,23 @@ + $this->id, + 'imported_date' => $this->imported_date, + 'type' => $this->type + ]; + } +} diff --git a/app/Http/Resources/TransactionResource.php b/app/Http/Resources/TransactionResource.php index 27fd17ab..09967f4c 100644 --- a/app/Http/Resources/TransactionResource.php +++ b/app/Http/Resources/TransactionResource.php @@ -2,6 +2,7 @@ namespace App\Http\Resources; +use App\Classes\Modules\Bookings\Services\CalculatesBookingRefundAmount; use App\Classes\ValueObjects\Constants\TransactionType; use App\Models\Booking; use Carbon\Carbon; @@ -43,8 +44,10 @@ class TransactionResource extends JsonResource 'documents' => new DocumentResource($this->documents()->first()), 'transaction_bill' => new TransactionResource($this->when((int) $this->type === TransactionType::PAYMENT, $this->transactions()->bills()->first())), 'transaction_refunds' => TransactionResource::collection($this->when((int) $this->type === TransactionType::PAYMENT, $this->transactions()->refunds()->get())), + 'refunded_amount' => $this->booking ? floatval((App()->make(CalculatesBookingRefundAmount::class))->calculateRefundAmount($this->resource, $this->booking->fix_currency_id)) : null, 'expires_on' => Carbon::parse($this->expires_on)->format('d-m-Y h:i:s A'), 'updated_at' => Carbon::parse($this->updated_at)->format('d-m-Y h:i:s A'), + 'created_at' => Carbon::parse($this->created_at)->format('d-m-Y h:i:s A'), 'interval' => [ 'value' => $days->gt(Carbon::now()) ? '+' : '-', 'duration' => $days->diff(Carbon::now())->format('%d'), diff --git a/app/Http/Resources/UserRewardResource.php b/app/Http/Resources/UserRewardResource.php index ed693b4c..b988a1d3 100644 --- a/app/Http/Resources/UserRewardResource.php +++ b/app/Http/Resources/UserRewardResource.php @@ -2,6 +2,7 @@ namespace App\Http\Resources; + use Illuminate\Http\Resources\Json\JsonResource; class UserRewardResource extends JsonResource @@ -14,6 +15,13 @@ class UserRewardResource extends JsonResource */ public function toArray($request) { + $emailReminder = null; + if ($request->has('isAdmin')) { + $keyValuePairs = $this->user->attributes()->get(); + $emailReminder = KeyValueBasicResource::collection($keyValuePairs); + $this->voucher->email = $emailReminder; + } + return [ 'id' => $this->id, 'user_id' => $this->user_id, diff --git a/app/Http/Resources/VoucherResource.php b/app/Http/Resources/VoucherResource.php index 54193eeb..3f3112bb 100644 --- a/app/Http/Resources/VoucherResource.php +++ b/app/Http/Resources/VoucherResource.php @@ -2,6 +2,7 @@ namespace App\Http\Resources; +use ArrayObject; use Illuminate\Http\Resources\Json\JsonResource; class VoucherResource extends JsonResource @@ -14,9 +15,16 @@ class VoucherResource extends JsonResource */ public function toArray($request) { - $filteredRedemptions = $this->redemptions->filter(function ($redemption) { - return $redemption->transaction && $redemption->transaction->owner; - }); + $filteredRedemptions = new ArrayObject([]); + if ($request->has('filters') && str_contains($request->input('filters'), "has_active_reward")) { + $filteredRedemptions = new ArrayObject([]); + } + else{ + $filteredRedemptions = $this->redemptions->filter(function ($redemption) { + return $redemption->transaction && $redemption->transaction->owner; + }); + } + return [ 'id' => $this->id, 'name' => $this->name, @@ -25,7 +33,8 @@ class VoucherResource extends JsonResource 'value' => (float) $this->value, 'start_date' => $this->start_date, 'end_date' => $this->end_date, - 'is_redeemed' => $filteredRedemptions->count() > 0 + 'is_redeemed' => $filteredRedemptions->count() > 0, + 'email' => $this->email ? new KeyValueBasicResource($this->email->where('key', $this->code.'_EMAIL_COUNT')->first()) : null, ]; } } diff --git a/app/Models/KeyValuePair.php b/app/Models/KeyValuePair.php new file mode 100644 index 00000000..3ad6d6cd --- /dev/null +++ b/app/Models/KeyValuePair.php @@ -0,0 +1,15 @@ +morphTo(); + } +} diff --git a/app/Models/TransactionMappingLog.php b/app/Models/TransactionMappingLog.php index d6093f39..e9ddab33 100644 --- a/app/Models/TransactionMappingLog.php +++ b/app/Models/TransactionMappingLog.php @@ -7,7 +7,7 @@ use Illuminate\Database\Eloquent\Model; class TransactionMappingLog extends Model { - protected $fillable = ['imported_by','data','imported_date']; + protected $fillable = ['imported_by','data','imported_date','type']; protected $casts = [ 'data' => 'array', diff --git a/app/Models/User.php b/app/Models/User.php index 4bc7ec17..7e0a4aa9 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Classes\General\Interfaces\KeyValueInterface; use App\Classes\General\Interfaces\Voucherifiable; use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\HasMany; @@ -26,7 +27,8 @@ class User extends AbstractModel implements AuthenticatableContract, AuthorizableContract, CanResetPasswordContract, - Voucherifiable + Voucherifiable, + KeyValueInterface { use HasRoles, Notifiable, Authenticatable, Authorizable, CanResetPassword, MustVerifyEmail, SoftDeletes; @@ -101,4 +103,21 @@ class User extends AbstractModel implements { return $this->HasMany(UserReward::class, 'user_id', 'id'); } + + public function hasAttribute(string $key, $value = null): bool + { + $query = $this->attributes()->where('key', $key); + + if ($value !== null) { + $query->where('value', $value); + } + + return $query->exists(); + } + + + public function attributes(): MorphMany + { + return $this->morphMany(KeyValuePair::class, 'owner'); + } } diff --git a/config/logging.php b/config/logging.php index fb872693..d4894384 100644 --- a/config/logging.php +++ b/config/logging.php @@ -104,6 +104,23 @@ return [ 'path' => storage_path('logs/regenerateInvoice.log'), 'level' => 'info', ], + 'guzzleShippingPortal' => [ + 'driver' => 'errorlog', + 'level' => 'debug', + ], + + 'vue_polling' => [ + 'driver' => 'single', + 'path' => storage_path('logs/laravel_vue_plling.log'), + 'level' => 'info', + ], + + 'perfex_crm' => [ + 'driver' => 'single', + 'path' => storage_path('logs/laravel_perfex_crm.log'), + 'level' => 'info', + ], + ], ]; diff --git a/config/queue.php b/config/queue.php index 00b76d65..fc718e49 100644 --- a/config/queue.php +++ b/config/queue.php @@ -34,6 +34,13 @@ return [ 'driver' => 'sync', ], + 'high_priority' => [ + 'driver' => 'database', + 'table' => 'jobs', + 'queue' => 'high_priority', + 'retry_after' => 90, + ], + 'database' => [ 'driver' => 'database', 'table' => 'jobs', diff --git a/database/migrations/2023_12_26_152448_add_type_to_transaction_mapping_logs_table.php b/database/migrations/2023_12_26_152448_add_type_to_transaction_mapping_logs_table.php new file mode 100644 index 00000000..3927920a --- /dev/null +++ b/database/migrations/2023_12_26_152448_add_type_to_transaction_mapping_logs_table.php @@ -0,0 +1,40 @@ +string('type',50)->default('invoices')->after('imported_date'); + }); + + foreach (DB::table('transaction_mapping_logs')->get() as $key => $value) { + $data = json_decode($value->data); + DB::table('transaction_mapping_logs')->where('id',$value->id)->update([ + 'type' => (isset($data->description) ? 'receipts' : 'invoices') + ]); + } + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('transaction_mapping_logs', function (Blueprint $table) { + $table->dropColumn('type'); + }); + } +} diff --git a/database/migrations/2024_03_08_135259_create_key_value_pairs_table.php b/database/migrations/2024_03_08_135259_create_key_value_pairs_table.php new file mode 100644 index 00000000..b952ff56 --- /dev/null +++ b/database/migrations/2024_03_08_135259_create_key_value_pairs_table.php @@ -0,0 +1,37 @@ +id(); + $table->string('owner_type'); //'user', 'order', 'transaction' + $table->unsignedBigInteger('owner_id'); + $table->string('key'); + $table->string('value'); + $table->timestamps(); + + $table->index(['owner_type', 'owner_id']); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('key_value_pairs'); + } +} diff --git a/resources/assets/vue/components/accounting/elements/HistoryImportedInvoices.vue b/resources/assets/vue/components/accounting/elements/HistoryImportedInvoices.vue new file mode 100644 index 00000000..d3d68cfb --- /dev/null +++ b/resources/assets/vue/components/accounting/elements/HistoryImportedInvoices.vue @@ -0,0 +1,39 @@ + + + diff --git a/resources/assets/vue/components/accounting/elements/HistoryImportedReceipts.vue b/resources/assets/vue/components/accounting/elements/HistoryImportedReceipts.vue new file mode 100644 index 00000000..00138fa5 --- /dev/null +++ b/resources/assets/vue/components/accounting/elements/HistoryImportedReceipts.vue @@ -0,0 +1,39 @@ + + + diff --git a/resources/assets/vue/components/accounting/elements/StatementTransactionComponent.vue b/resources/assets/vue/components/accounting/elements/StatementTransactionComponent.vue index 0c193871..787f2f37 100644 --- a/resources/assets/vue/components/accounting/elements/StatementTransactionComponent.vue +++ b/resources/assets/vue/components/accounting/elements/StatementTransactionComponent.vue @@ -74,7 +74,7 @@
{{ owner.reference }} -
+
@@ -89,6 +89,21 @@ > + + + + + +
@@ -143,7 +158,7 @@ contentText="Are you sure you want to reject this mapping?" modalType="delete" class="text-center" - :apiRoute="route('api.accounting.statement_transaction.owner.status.update', item.id, 'reject')" + :apiRoute="route('api.accounting.statement_transaction.owner.status.update', item.owners.pending_verification[0].id, 'reject')" apiMethod="post" :section="section" > diff --git a/resources/assets/vue/components/accounting/sections/ImportedInvoiceMappedComponent.vue b/resources/assets/vue/components/accounting/sections/ImportedInvoiceMappedComponent.vue index f10f9181..185da370 100644 --- a/resources/assets/vue/components/accounting/sections/ImportedInvoiceMappedComponent.vue +++ b/resources/assets/vue/components/accounting/sections/ImportedInvoiceMappedComponent.vue @@ -98,21 +98,17 @@ }, methods: { appendComponentTitle() { - this.componentTitle = this.section == 'importInvoiceMapping' ? 'Imported Invoices Mapped' : 'Imported Receipts Mapped'; + this.componentTitle = 'Imported Invoices Mapped'; }, appendComponentTableHeader() { - if (this.section == 'importInvoiceMapping') { - this.tableHeaders = ['No','Doc No','Date','Debtor Code','Debtor Name','Shipping Info','Net Total','Cancelled','Mapped Status','Mapped Reference No','Payment Received Date']; - } else { - this.tableHeaders = ['No','OR No','Date','Creditor Code','Creditor Name','Shipping Info','Net Total','Cancelled','Mapped Status','Mapped Reference No']; - } + this.tableHeaders = ['No','Doc No','Date','Debtor Code','Debtor Name','Shipping Info','Net Total','Cancelled','Mapped Status','Mapped Reference No','Payment Received Date']; }, importInvoice(){ this.isLoading = true; this.parameters = { files: this.files }; - this.submit(this.route('api.'+(this.section == 'importInvoiceMapping' ? 'import_invoices' : 'import_receipts')+'.upload'), 'post', this.section, true, false); + this.submit(this.route('api.import_invoices.upload'), 'post', this.section, true, false); }, successHandler(response){ @@ -128,7 +124,7 @@ downloadInvoiceMapped() { var arrDateTime = this.importedDate.split(" "); - const fileName = this.section == 'importInvoiceMapping' ? 'InvoiceMapped' : 'ReceiptMapped'; + const fileName = 'importInvoiceMapping'; window.open(this.route('importedInvoiceMapped.export')+'?date='+arrDateTime[0]+'&time='+arrDateTime[1]+'&fileName='+fileName, '_blank'); }, diff --git a/resources/assets/vue/components/accounting/sections/ImportedReceiptMappedComponent.vue b/resources/assets/vue/components/accounting/sections/ImportedReceiptMappedComponent.vue new file mode 100644 index 00000000..25db762e --- /dev/null +++ b/resources/assets/vue/components/accounting/sections/ImportedReceiptMappedComponent.vue @@ -0,0 +1,138 @@ + + + \ No newline at end of file diff --git a/resources/assets/vue/components/accounting/sections/ReportTransactionsMappedComponent.vue b/resources/assets/vue/components/accounting/sections/ReportTransactionsMappedComponent.vue index e3d4e0d2..86da623c 100644 --- a/resources/assets/vue/components/accounting/sections/ReportTransactionsMappedComponent.vue +++ b/resources/assets/vue/components/accounting/sections/ReportTransactionsMappedComponent.vue @@ -3,19 +3,74 @@
-
-
-
-
Mapped Report
+
+ +
+
+
+
Mapped Report
+
+
+
+
+
History Imported Invoices Report
+
+
+
+
+
History Imported Receipts Report
+
+
-
+
+
+
+
+ + + + +
+
+ + + + +
+
+ + + + +
+
+
+
+ + + + +
+
+ + + + +
+
+
+
Mapped Report
+
+
+
+
@@ -35,7 +90,7 @@
- + @@ -44,22 +99,175 @@
+ + +
+
+
+
+
+
+
+ + + + +
+
+ + + + +
+
+
+
History Imported Invoices Report
+
+
+
+
+
+
+
+
Date
+
+
+
+ + + + +
+
+
+
+ + +
+
+
+
+
+
+
+ + + + +
+
+ + + + +
+
+
+
History Imported Receipts Report
+
+
+
+
+
+
+
+
Date
+
+
+
+ + + + +
+
+
+
\ No newline at end of file + }, + mixins: [FormHandler, ModalFormHandler] +} + diff --git a/resources/assets/vue/components/bookings/elements/RefundVerificationComponent.vue b/resources/assets/vue/components/bookings/elements/RefundVerificationComponent.vue index 42d5682e..24ec68a6 100644 --- a/resources/assets/vue/components/bookings/elements/RefundVerificationComponent.vue +++ b/resources/assets/vue/components/bookings/elements/RefundVerificationComponent.vue @@ -115,7 +115,7 @@ approveRefund(status){ this.isLoading = true; this.parameters.status = status; - this.submit(this.route('api.transaction.refund.status.update', this.data.id), 'put', 'listRefundTransactionSection', true, true); + this.submit(this.route('api.transaction.refund.status.update', this.data.id, status), 'put', 'listRefundTransactionSection', true, true); }, }, mixins: [componentHandler, staticFormHandler] diff --git a/resources/assets/vue/components/bookings/elements/SupplierPendingOrderComponent.vue b/resources/assets/vue/components/bookings/elements/SupplierPendingOrderComponent.vue index e4877e96..309f2b9b 100644 --- a/resources/assets/vue/components/bookings/elements/SupplierPendingOrderComponent.vue +++ b/resources/assets/vue/components/bookings/elements/SupplierPendingOrderComponent.vue @@ -56,6 +56,16 @@ {{item.original_currency.short_code}}
+
+
+
+
Refunded Amount
+
+ {{(Math.round((totalRefunds + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}} +
+
+
+
@@ -95,7 +105,7 @@
Amount
- {{(Math.round((item.original_amount + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}} + {{(Math.round((item.original_amount - totalRefunds + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}
@@ -124,11 +134,20 @@ active: false, } }, + computed: { + totalRefunds() { + var TotalRequestedRefund = 0; + this.data.transaction_refunds.forEach(function(refunds) { + TotalRequestedRefund += refunds.status === 2 ? refunds.original_amount : 0; + }); + return TotalRequestedRefund; + } + }, methods: { activate(){ this.active = !this.active; this.$emit('input', this.item) - } + }, }, mixins: [componentHandler] } diff --git a/resources/assets/vue/components/bookings/forms/BookingPaymentQuotationComponent.vue b/resources/assets/vue/components/bookings/forms/BookingPaymentQuotationComponent.vue index 57a5a93f..03e857cf 100644 --- a/resources/assets/vue/components/bookings/forms/BookingPaymentQuotationComponent.vue +++ b/resources/assets/vue/components/bookings/forms/BookingPaymentQuotationComponent.vue @@ -252,21 +252,21 @@
- +
Apply a voucher -
+
{{ voucherCodeFailedReason }} Voucher applied
- +
diff --git a/resources/assets/vue/components/bookings/forms/PurchaseOrderFormComponent.vue b/resources/assets/vue/components/bookings/forms/PurchaseOrderFormComponent.vue index 9a1bf774..9b8045f9 100644 --- a/resources/assets/vue/components/bookings/forms/PurchaseOrderFormComponent.vue +++ b/resources/assets/vue/components/bookings/forms/PurchaseOrderFormComponent.vue @@ -240,7 +240,11 @@ }, watch: { 'data': function () { - this.products = this.data.purchase_order.details + if (this.data && this.data.purchase_order && this.data.purchase_order.details) { + this.products = this.data.purchase_order.details; + } else { + this.products = []; + } } }, methods: { diff --git a/resources/assets/vue/components/bookings/forms/SupplierPlaceOrderFormComponent.vue b/resources/assets/vue/components/bookings/forms/SupplierPlaceOrderFormComponent.vue index 4ec71edd..0f27eb95 100644 --- a/resources/assets/vue/components/bookings/forms/SupplierPlaceOrderFormComponent.vue +++ b/resources/assets/vue/components/bookings/forms/SupplierPlaceOrderFormComponent.vue @@ -115,7 +115,12 @@ computed: { total(){ return this.payments.reduce(function (total, currentValue) { - return total + currentValue.original_amount; + return total + currentValue.original_amount - currentValue.transaction_refunds.reduce(function (totalRefund, refundTransaction) { + if (refundTransaction.status === 2) { + return totalRefund + refundTransaction.original_amount; + } + return totalRefund; + }, 0); }, 0); }, diff --git a/resources/assets/vue/components/bookings/sections/AdminPaymentsBillingSectionComponent.vue b/resources/assets/vue/components/bookings/sections/AdminPaymentsBillingSectionComponent.vue index 03244ff4..966ccbbc 100644 --- a/resources/assets/vue/components/bookings/sections/AdminPaymentsBillingSectionComponent.vue +++ b/resources/assets/vue/components/bookings/sections/AdminPaymentsBillingSectionComponent.vue @@ -90,34 +90,34 @@
- + - -
-
- + +
+
+ - -
-
- + +
+
+ - +
- + - -
+
+
diff --git a/resources/assets/vue/components/bookings/sections/AdminPaymentsBillingSectionPollingComponent.vue b/resources/assets/vue/components/bookings/sections/AdminPaymentsBillingSectionPollingComponent.vue new file mode 100644 index 00000000..47d14857 --- /dev/null +++ b/resources/assets/vue/components/bookings/sections/AdminPaymentsBillingSectionPollingComponent.vue @@ -0,0 +1,136 @@ + + diff --git a/resources/assets/vue/components/bookings/sections/SupplierPendingOrdersSectionComponent.vue b/resources/assets/vue/components/bookings/sections/SupplierPendingOrdersSectionComponent.vue index 528e870b..fb766fe4 100644 --- a/resources/assets/vue/components/bookings/sections/SupplierPendingOrdersSectionComponent.vue +++ b/resources/assets/vue/components/bookings/sections/SupplierPendingOrdersSectionComponent.vue @@ -117,17 +117,16 @@
- - - + +
@@ -201,7 +200,9 @@ }, updateList(){ - this.$refs.pendingOrdersList.updateFilters({per_page: 10000, status: 2, type: 1, original_currency_id_in: [this.selectedCurrency.id], transaction_service_id: this.selectedService.id}); + // todo-refund: activate this for partial refund + // this.$refs.pendingOrdersList.updateFilters({per_page: 10000, status: 2, type: 1, original_currency_id_in: [this.selectedCurrency.id], transaction_service_id: this.selectedService.id, is_not_fully_refunded: true}); + this.$refs.pendingOrdersList.updateFilters({per_page: 10000, status: 2, type: 1, original_currency_id_in: [this.selectedCurrency.id], transaction_service_id: this.selectedService.id, does_not_have_refund_in_progress: true}); this.selectedSupplier.status = false; this.currencyDropdownLaunch.status = false; diff --git a/resources/assets/vue/components/companies/elements/SingleUserRewardItemComponent.vue b/resources/assets/vue/components/companies/elements/SingleUserRewardItemComponent.vue index 8f25ab60..9cc2409a 100644 --- a/resources/assets/vue/components/companies/elements/SingleUserRewardItemComponent.vue +++ b/resources/assets/vue/components/companies/elements/SingleUserRewardItemComponent.vue @@ -9,6 +9,10 @@

RM{{ item.voucher.value/100 }} Discount

{{ item.voucher.value }}% Discount

+
+ + +