diff --git a/app/Classes/General/Eloquent/Filters/HasActiveReward.php b/app/Classes/General/Eloquent/Filters/HasActiveReward.php index 5770ca6e..26385b96 100644 --- a/app/Classes/General/Eloquent/Filters/HasActiveReward.php +++ b/app/Classes/General/Eloquent/Filters/HasActiveReward.php @@ -2,7 +2,6 @@ namespace App\Classes\General\Eloquent\Filters; -use App\Classes\ValueObjects\Constants\RoleTypes; use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\Facades\Auth; @@ -12,33 +11,17 @@ class HasActiveReward implements Filter /** * @param Builder $builder * @param $value - * @return mixed + * @return Builder|mixed */ public static function apply(Builder $builder, $value) { - if(in_array(Auth::user()->type, RoleTypes::ADMIN_ROLES)){ - // $userId = $value !== 1 ? $value : Auth::user()->id; - $userId = $value; - return $builder->where('user_id', $userId) - ->where(function ($query) { - $query->whereHas('reward', function ($subquery) { - $subquery->where('is_active', true); - }) - ->orWhereDoesntHave('reward'); - }) - ->whereDoesntHave('voucher.redemptions.transaction.booking.company.employees', function ($query) use ($userId) { - $query->where('user_id', $userId); + return $builder->where('user_id', Auth::user()->id) //cief todo: should not use Auth::user()->id + ->where(function ($query) { + $query->whereHas('reward', function ($subquery) { + $subquery->where('is_active', true); }); - } - else{ - return $builder->where('user_id', Auth::user()->id) - ->where(function ($query) { - $query->whereHas('reward', function ($subquery) { - $subquery->where('is_active', true); - }) - ->orWhereDoesntHave('reward'); - }) - ->whereDoesntHave('voucher.redemptions.transaction.owner'); - } + // ->orWhereDoesntHave('reward'); + }); } + } diff --git a/app/Classes/General/Eloquent/Filters/HasActiveRewardForAdmin.php b/app/Classes/General/Eloquent/Filters/HasActiveRewardForAdmin.php new file mode 100644 index 00000000..5d69aa4b --- /dev/null +++ b/app/Classes/General/Eloquent/Filters/HasActiveRewardForAdmin.php @@ -0,0 +1,26 @@ +where('user_id', $value) + ->where(function ($query) { + $query->whereHas('reward', function ($subquery) { + $subquery->where('is_active', true); + }); + // ->orWhereDoesntHave('reward'); + }); + } + +} diff --git a/app/Classes/General/Eloquent/Filters/HasVouchersAll.php b/app/Classes/General/Eloquent/Filters/HasVouchersAll.php new file mode 100644 index 00000000..d2ff7a2e --- /dev/null +++ b/app/Classes/General/Eloquent/Filters/HasVouchersAll.php @@ -0,0 +1,44 @@ +type, RoleTypes::ADMIN_ROLES)){ + // $userId = $value !== 1 ? $value : Auth::user()->id; + $userId = $value; + return $builder->where('user_id', $userId) + ->where(function ($query) { + $query->whereHas('reward', function ($subquery) { + $subquery->where('is_active', true); + }) + ->orWhereDoesntHave('reward'); + }) + ->whereDoesntHave('voucher.redemptions.transaction.booking.company.employees', function ($query) use ($userId) { + $query->where('user_id', $userId); + }); + } + else{ + return $builder->where('user_id', Auth::user()->id) + ->where(function ($query) { + $query->whereHas('reward', function ($subquery) { + $subquery->where('is_active', true); + }) + ->orWhereDoesntHave('reward'); + }) + ->whereDoesntHave('voucher.redemptions.transaction.owner'); + } + } +} diff --git a/app/Classes/General/Open1688/SignatureUtil.php b/app/Classes/General/Open1688/SignatureUtil.php new file mode 100644 index 00000000..91c21005 --- /dev/null +++ b/app/Classes/General/Open1688/SignatureUtil.php @@ -0,0 +1,31 @@ + $v ) { + $paramToSign = $k . $v; + Array_push ( $paramsToSign, $paramToSign ); + } + sort ( $paramsToSign ); + $implodeParams = implode ( $paramsToSign ); + $pathAndParams = $path . $implodeParams; + $sign = hash_hmac ( "sha1", $pathAndParams, config('open1688.app_secret'), true ); + $signHexWithLowcase = bin2hex ( $sign ); + $signHexUppercase = strtoupper ( $signHexWithLowcase ); + return $signHexUppercase; + } +} + +?> \ No newline at end of file diff --git a/app/Classes/General/Open1688Helper.php b/app/Classes/General/Open1688Helper.php new file mode 100644 index 00000000..70bbf8eb --- /dev/null +++ b/app/Classes/General/Open1688Helper.php @@ -0,0 +1,79 @@ + "{\"keyword\":\"$keyword\",\"beginPage\":$page,\"pageSize\":18,\"country\":\"en\"}", + ]; + + return self::getFromOpen1688($requestData, config('open1688.product_search_keyword_api')); + } + + public static function productDetail($offerId) { + $requestData = [ + 'offerDetailParam' => "{\"offerId\":$offerId,\"country\":\"en\"}", + ]; + + return self::getFromOpen1688($requestData, config('open1688.product_detail_api')); + } + + private static function getFromOpen1688($requestData, $apiName) { + $requestData["access_token"] = config('open1688.access_token'); + + $signaturedStr = self::generateRequestSignature($apiName, $requestData); + $url = config('open1688.url') . $apiName . "/" . config('open1688.app_key') . "?_aop_signature=" . $signaturedStr; + + + foreach($requestData as $k => $v) { + $url = $url . "&$k=$v"; + } + + try { + $client = new \GuzzleHttp\Client(['verify' => false]); + $response = $client->request('GET', $url); + $body = $response->getBody(); + $contents = json_decode($body, true); + + return $contents['result']['result']; + } catch(\GuzzleHttp\Exception\RequestException $exception){ + throw new MalformedRequestException(json_decode($exception->getResponse()->getBody()->getContents(), true)['error_message']); + } + + } + + private static function generateRequestSignature ($apiName, $requestData) { + $pathToSign = self::generateAPIPath($apiName); + $signaturedStr = SignatureUtil::signature ($pathToSign, $requestData); + + return $signaturedStr; + } + + private static function generateAPIPath($apiName) { + $urlResult = ""; + $defs = array ( + $urlResult, + "param2", + "/", + "1", + "/", + "com.alibaba.fenxiao.crossborder", + "/", + $apiName, + "/", + config('open1688.app_key') + ); + + $urlResult = implode ( $defs ); + + return $urlResult; + } + +} diff --git a/app/Classes/Jobs/CreateMilestoneRewardByTransactionJob.php b/app/Classes/Jobs/CreateMilestoneRewardByTransactionJob.php new file mode 100644 index 00000000..86208cc9 --- /dev/null +++ b/app/Classes/Jobs/CreateMilestoneRewardByTransactionJob.php @@ -0,0 +1,38 @@ +transaction = $transaction; + $this->milestones = $milestones; + } + + public function handle() + { + (App()->make(MilestoneRewardByTransactionProcessor::class))->execute($this->transaction, $this->milestones); + } +} diff --git a/app/Classes/Modules/Accounting/ControllersLogic/ImportCiefLiteStatementLogic.php b/app/Classes/Modules/Accounting/ControllersLogic/ImportCiefLiteStatementLogic.php index 9a909d71..164cb142 100644 --- a/app/Classes/Modules/Accounting/ControllersLogic/ImportCiefLiteStatementLogic.php +++ b/app/Classes/Modules/Accounting/ControllersLogic/ImportCiefLiteStatementLogic.php @@ -7,6 +7,7 @@ use App\Classes\Exceptions\MalformedRequestException; use App\Classes\General\Abstracts\AbstractControllerLogic; use App\Classes\Modules\Documents\DataTransferObjects\DocumentObject; use App\Classes\ValueObjects\Constants\ApprovalStatus; +use App\Classes\ValueObjects\Constants\StatementTransactionOwnerType; use App\Models\AccountStatement; use App\Models\StatementAccount; use App\Models\StatementTransaction; @@ -45,77 +46,28 @@ class ImportCiefLiteStatementLogic extends AbstractControllerLogic $sheet = $collection->first()->skip(1); - $dateTo = $sheet->first()[10]; - $dateFrom = $sheet->last()[10]; - $totalTransaction = $sheet->count(); - - $offset = 1; - do { - $dateFrom = $sheet->offsetGet($sheet->count() - $offset)[10]; - $offset += 1; - } while(!$dateFrom); - - - $dateFrom = carbon::parse($dateFrom); - $dateTo = carbon::parse($dateTo); - - $statement = AccountStatement::whereDate('date_from', $dateFrom) - ->whereDate('date_to', $dateTo) - ->where('total_amount', $totalTransaction) - ->first(); - - if(!$statement){ - $statement = new AccountStatement([ - 'date_from' => $dateFrom, - 'date_to' => $dateTo, - 'total_amount' => $totalTransaction, - ]); - } - - $account = StatementAccount::where("name", "CIEF LITE")->first(); - - if (!$account) { - throw new Exception("Statement Account for CIEF LITE not found."); - } - - $account->statements()->save($statement); - - $sheet->map(function ($row) use ($statement) { - if (!$row[0]) { + $sheet->map(function ($row) { + if (!$row[0] || trim($row[8]) !== "已审核") { return; } - $postingDate = $row[10]; - $transactionDescription = trim($row[1]); - $description2 = trim($row[2]); - $description3 = "Fee " . $row[6]; - $description4 = trim($row[8]); - $transactionRef = trim($row[12]); + $postingDate =date('Y-m-d', strtotime($row[10])); $amount = ((float) str_replace(',', '', $row[7])); - $transactionCode = $row[0]; - $transaction = new StatementTransaction([ - 'posting_date' => $postingDate, - 'transaction_description' => $transactionDescription, - 'transaction_description_2' => $description2, - 'transaction_description_3' => $description3, - 'transaction_description_4' => $description4, - 'transaction_ref' => $transactionRef, - 'amount' => $amount, - 'transaction_code' => $transactionCode, - ]); + + $statementTransaction = StatementTransaction::whereHas('account', function($query) { + $query->where('statement_accounts.number', 8881040198515); + })->whereDate('posting_date', $postingDate)->where('amount', $amount)->first(); - // Check if the transaction already exists for this statement - $existingTransaction = StatementTransaction::where('transaction_ref', $transactionRef) - ->where('posting_date', $postingDate) - ->where('amount', $amount) - ->where('transaction_description', $transactionDescription) - ->where('transaction_code', $transactionCode) - ->first(); - - if (!$existingTransaction) { - $statement->transactions()->save($transaction); + if (!$statementTransaction) { + return; } - return $transaction; + $owner = $statementTransaction->owners()->firstOrCreate([ + 'type' => StatementTransactionOwnerType::WALLET_TOP_UP, + 'system' => 'LITE', + 'owner_reference'=> $row[0], + ]); + + return $owner; }); } diff --git a/app/Classes/Modules/Accounts/ControllersLogic/CreateCustomerLogic.php b/app/Classes/Modules/Accounts/ControllersLogic/CreateCustomerLogic.php index d86e0bf7..9a155f74 100644 --- a/app/Classes/Modules/Accounts/ControllersLogic/CreateCustomerLogic.php +++ b/app/Classes/Modules/Accounts/ControllersLogic/CreateCustomerLogic.php @@ -12,7 +12,6 @@ use App\Classes\Modules\Companies\Processors\AssignEmployeeProcessor; use App\Classes\Modules\Companies\Processors\AssignSegmentProcessor; use App\Classes\Modules\Companies\Processors\CreateCompanyProcessor; use App\Classes\Modules\Contacts\Processors\CreateContactProcessor; -use App\Classes\Modules\Milestones\Processors\CheckMilestonesForRewardProcessor; use App\Classes\Modules\Vouchers\Processors\Voucherify\NewCustomerToVoucherifyProcessor; use App\Classes\Modules\Vouchers\Processors\CreateVoucherProcessor; use App\Classes\Modules\Companies\DataTransferObjects\EmploymentObject; @@ -74,9 +73,6 @@ class CreateCustomerLogic extends AbstractControllerLogic /** @var CreatesSeasonalSegment */ private $createsSeasonalSegment; - /** @var CheckMilestonesForRewardProcessor */ - private $checkMilestonesForRewardProcessor; - /** @var NewCustomerToVoucherifyProcessor */ private $newCustomerToVoucherifyProcessor; @@ -100,14 +96,13 @@ class CreateCustomerLogic extends AbstractControllerLogic * @param GenerateEmailVerificationAttemptProcessor $generateEmailVerificationAttemptProcessor * @param AssignSegmentProcessor $assignCompanyToSegmentProcessor * @param CreatesSeasonalSegment $createsSeasonalSegment - * @param CheckMilestonesForRewardProcessor $checkMilestonesForRewardProcessor * @param NewCustomerToVoucherifyProcessor $newCustomerToVoucherifyProcessor * @param CreateVoucherProcessor $createVoucherProcessor * @param RegisterOnShippingProcessor $registerOnShippingProcessor * @param ConnectCompanyToShippingCompanyModule $connectCompanyToShippingCompanyModule */ public function __construct(CreateUserProcessor $createUserProcessor, CreateCompanyProcessor $createCompanyProcessor, CreateContactProcessor $createContactProcessor, AssignEmployeeProcessor $assignEmployeeProcessor, AssignSegmentProcessor $assignSegmentProcessor, AuthenticationProcessor $authenticationProcessor, GenerateEmailVerificationAttemptProcessor $generateEmailVerificationAttemptProcessor, - CreatesSeasonalSegment $createsSeasonalSegment, CheckMilestonesForRewardProcessor $checkMilestonesForRewardProcessor, NewCustomerToVoucherifyProcessor $newCustomerToVoucherifyProcessor, CreateVoucherProcessor $createVoucherProcessor, RegisterOnShippingProcessor $registerOnShippingProcessor, ConnectCompanyToShippingCompanyModule $connectCompanyToShippingCompanyModule) + CreatesSeasonalSegment $createsSeasonalSegment, NewCustomerToVoucherifyProcessor $newCustomerToVoucherifyProcessor, CreateVoucherProcessor $createVoucherProcessor, RegisterOnShippingProcessor $registerOnShippingProcessor, ConnectCompanyToShippingCompanyModule $connectCompanyToShippingCompanyModule) { $this->createUserProcessor = $createUserProcessor; $this->createCompanyProcessor = $createCompanyProcessor; @@ -118,7 +113,6 @@ class CreateCustomerLogic extends AbstractControllerLogic $this->generateEmailVerificationAttemptProcessor = $generateEmailVerificationAttemptProcessor; $this->assignCompanyToSegmentProcessor = $assignSegmentProcessor; $this->createsSeasonalSegment = $createsSeasonalSegment; - $this->checkMilestonesForRewardProcessor = $checkMilestonesForRewardProcessor; $this->newCustomerToVoucherifyProcessor = $newCustomerToVoucherifyProcessor; $this->createVoucherProcessor = $createVoucherProcessor; $this->registerOnShippingProcessor = $registerOnShippingProcessor; diff --git a/app/Classes/Modules/Accounts/Processors/AuthenticationProcessor.php b/app/Classes/Modules/Accounts/Processors/AuthenticationProcessor.php index 952bebdd..7e5fca53 100644 --- a/app/Classes/Modules/Accounts/Processors/AuthenticationProcessor.php +++ b/app/Classes/Modules/Accounts/Processors/AuthenticationProcessor.php @@ -81,8 +81,8 @@ class AuthenticationProcessor $this->newCustomerToVoucherifyProcessor->execute(0, $user, false); } - //cief todo: case study 1 voucherify - //$this->checkMilestonesForRewardProcessor->execute($user, [Milestones::MILESTONE_1]); + //cief todo: case study 1 + //$this->checkMilestonesForRewardProcessor->execute($user, [Milestones::MILESTONE_DEMO_1]); return ['access_token' => $this->generatesAuthenticationToken->execute($user), 'redirect_url' => $this->authenticationRedirect->url($user)]; } diff --git a/app/Classes/Modules/Billplzs/ControllersLogic/CallbackBillplzLogic.php b/app/Classes/Modules/Billplzs/ControllersLogic/CallbackBillplzLogic.php index 186ef3b6..a6d48a5e 100644 --- a/app/Classes/Modules/Billplzs/ControllersLogic/CallbackBillplzLogic.php +++ b/app/Classes/Modules/Billplzs/ControllersLogic/CallbackBillplzLogic.php @@ -27,6 +27,7 @@ use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Log; use App\Classes\Modules\Wallets\Services\RecalculatesWalletBalance; + class CallbackBillplzLogic { @@ -55,7 +56,9 @@ class CallbackBillplzLogic * @param FetchesTransaction $fetchesTransaction * @param UpdatesTransactionStatus $updatesTransactionStatus * @param UpdatesWalletBalance $updatesWalletBalance + * @param CreateCashBackTransactionProcessor $createCashBackTransactionProcessor * @param RecalculatesWalletBalance $recalculatesWalletBalance + * @param CreateMilestoneRewardJob $createMilestoneRewardJob */ public function __construct(GetBillplzBill $getBillplzBill, FetchesTransaction $fetchesTransaction, UpdatesTransactionStatus $updatesTransactionStatus, UpdatesWalletBalance $updatesWalletBalance, CreateCashBackTransactionProcessor $createCashBackTransactionProcessor, RecalculatesWalletBalance $recalculatesWalletBalance) { @@ -117,4 +120,4 @@ class CallbackBillplzLogic return $request->method() === 'POST' ? true : view('pages.payments_redirect', ['marking' => $marking ?? null, 'transaction' => $transaction, 'status' => $status]); } -} \ No newline at end of file +} diff --git a/app/Classes/Modules/Bookings/ControllersLogic/CreateBookingPaymentLogic.php b/app/Classes/Modules/Bookings/ControllersLogic/CreateBookingPaymentLogic.php index 6b6adc16..c652e773 100644 --- a/app/Classes/Modules/Bookings/ControllersLogic/CreateBookingPaymentLogic.php +++ b/app/Classes/Modules/Bookings/ControllersLogic/CreateBookingPaymentLogic.php @@ -115,9 +115,7 @@ class CreateBookingPaymentLogic extends AbstractControllerLogic $conversionObject = $this->createConversionObject($request, $booking); - $outstanding = $this->calculatesBookingOutstanding->execute($booking); - - if($conversionObject->getAmount() > round($outstanding, 2)) throw new MalformedRequestException('Your payment must not be greater than '. $outstanding .'.'); + $this->validatePayment($request, $booking, $conversionObject); $configurations = $this->fetchBookingQuotation->execute($booking->company, $conversionObject, $request->input('voucher_code')); @@ -138,6 +136,10 @@ class CreateBookingPaymentLogic extends AbstractControllerLogic $this->updatesTransactionStatus->execute($transaction, ApprovalStatus::PENDING_VERIFICATION); } + if(PaymentMethodType::PAYMENT_METHODS[$request->input('payment_method')] == PaymentMethodType::WALLET){ + $this->updatesTransactionStatus->execute($transaction, ApprovalStatus::APPROVED); + } + return $this->resourceResponse(new TransactionResource($transaction)); } @@ -154,7 +156,7 @@ class CreateBookingPaymentLogic extends AbstractControllerLogic private function validatePayment(Request $request, Booking $booking, CurrencyConversionObject $conversionObject): void { - $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/Milestones/Processors/CheckMilestonesForRewardProcessor.php b/app/Classes/Modules/Milestones/Processors/CheckMilestonesForRewardProcessor.php index 597fa8bc..1a138dfa 100644 --- a/app/Classes/Modules/Milestones/Processors/CheckMilestonesForRewardProcessor.php +++ b/app/Classes/Modules/Milestones/Processors/CheckMilestonesForRewardProcessor.php @@ -81,9 +81,12 @@ class CheckMilestonesForRewardProcessor try{ foreach($milestone_constants as $constant) { - //update milestone progress - /** @var Milestone $milestone */ - $milestone = $this->fetchesMilestone->execute(['name' => $constant]); + //update milestone progres + $milestone = Milestone::where('name', $constant)->first(); + if(!$milestone) { + Log::error("{$constant} NOT FOUND!"); + continue; + } $result = null; if($user->milestoneProgress->count() > 0){ $result = $user->milestoneProgress->where('milestone_id', $milestone->id)->first(); @@ -130,6 +133,10 @@ class CheckMilestonesForRewardProcessor //Voucherify - Create Voucher $result = $this->createsVoucherifyVoucher->execute($user, intval($reward->value)); } + else if($reward->type == RewardType::REWARD_CODE){ + //Voucherify - Get Voucher + $result = $this->fetchesVoucherifyVoucher->execute($user, $reward->value); + } else{ //Voucherify - Validates Voucher $ValidateVoucherifyVoucherObject = new ValidateVoucherifyVoucherObject(0, $reward->value, 0.00, $user); diff --git a/app/Classes/Modules/Milestones/Processors/MilestoneRewardByTransactionProcessor.php b/app/Classes/Modules/Milestones/Processors/MilestoneRewardByTransactionProcessor.php new file mode 100644 index 00000000..ea9abf9c --- /dev/null +++ b/app/Classes/Modules/Milestones/Processors/MilestoneRewardByTransactionProcessor.php @@ -0,0 +1,48 @@ +checkMilestonesForRewardProcessor = $checkMilestonesForRewardProcessor; + } + + + /** + * @param Transaction $transaction + * @param array $milestones + * @throws \App\Classes\Exceptions\AccessForbiddenException + * @throws \App\Classes\Exceptions\MalformedRequestException + */ + public function execute(Transaction $transaction, array $milestones) + { + $company = $transaction->owner instanceof Booking ? $transaction->owner()->first()->company : null; + if($company){ + $completedBookingCount = count($company->bookings()->where('status', ApprovalStatus::COMPLETED)->get()); + Log::info("Number of completed bookings completed for company ".$company->reference. ": " .$completedBookingCount); + if (in_array(Milestones::MILESTONE_1, $milestones)) { + if($completedBookingCount === 2){ + $user = $company->employees()->first(); + $this->checkMilestonesForRewardProcessor->execute($user, [Milestones::MILESTONE_1]); + } + } + } + } +} diff --git a/app/Classes/Modules/Open1688/ControllersLogic/GetProductDetailLogic.php b/app/Classes/Modules/Open1688/ControllersLogic/GetProductDetailLogic.php new file mode 100644 index 00000000..1ec60540 --- /dev/null +++ b/app/Classes/Modules/Open1688/ControllersLogic/GetProductDetailLogic.php @@ -0,0 +1,84 @@ + 'Get product detail', + 'message' => 'You have successfully get 1688 product detail' + ]; + } + + /** + * @param Request $request + * @return JsonResponse + * @throws ErrorException + */ + public function logic(Request $request) : JsonResponse + { + $result = Open1688Helper::productDetail($request->route('offer_id')); + $productAttribute = []; + $variants = []; + $uniqueVariants = []; + $variantInfo = []; + $priceList = []; + $variantKeyCombinationOrder = []; + + foreach ($result['productAttribute'] as $attr) { + $productAttribute[$attr['attributeName']] = array_key_exists($attr['attributeName'], $productAttribute) ? $productAttribute[$attr['attributeName']] . ", " . $attr['value'] : $attr['value']; + } + + $result['productAttribute'] = $productAttribute; + + foreach ($result['productSkuInfos'] as $sku) { + $uniqueVariantKey = ''; + foreach ($sku['skuAttributes'] as $skuAttr) { + if (count($variantKeyCombinationOrder) < count($sku['skuAttributes'])) { + array_push($variantKeyCombinationOrder, $skuAttr['attributeName']); + } + if (!in_array($skuAttr['value'], $uniqueVariants)) { + $variants[$skuAttr['attributeName']][] = [ + 'image' => isset($skuAttr['skuImageUrl']) ? $skuAttr['skuImageUrl'] : null, + 'value' => $skuAttr['value'] + ]; + } + + array_push($uniqueVariants, $skuAttr['value']); + + $uniqueVariantKey .= $skuAttr['value']; + } + + $price = isset($sku['price']) ? $sku['price'] : $sku['consignPrice']; + + $variantInfo[$uniqueVariantKey] = [ + 'skuId' => $sku['skuId'], + 'amountOnSale' => $sku['amountOnSale'], + 'price' => $price, + ]; + array_push($priceList, $price); + } + + $result['variants'] = $variants; + $result['variantInfo'] = $variantInfo; + + $minPrice = min($priceList); + $maxPrice = max($priceList); + + $result['priceRange'] = $minPrice === $maxPrice ? $minPrice : "CNY ¥$minPrice - CNY ¥$maxPrice"; + $result['variantKeyCombinationOrder'] = $variantKeyCombinationOrder; + + return $this->response(['data' => $result]); + } +} diff --git a/app/Classes/Modules/Open1688/ControllersLogic/KeywordSearchProductLogic.php b/app/Classes/Modules/Open1688/ControllersLogic/KeywordSearchProductLogic.php new file mode 100644 index 00000000..526c3b1f --- /dev/null +++ b/app/Classes/Modules/Open1688/ControllersLogic/KeywordSearchProductLogic.php @@ -0,0 +1,36 @@ + 'Search 1688 Products', + 'message' => 'You have successfully retrieved a list of products from 1688' + ]; + } + + /** + * @param Request $request + * @return JsonResponse + * @throws ErrorException + */ + public function logic(Request $request) : JsonResponse + { + $result = Open1688Helper::productSearchKeyword($request->input('keyword'), $request->input('page')); + + return $this->response($result); + } +} diff --git a/app/Classes/Modules/Transactions/ControllersLogic/CreatePurchaseOrderTransactionLogic.php b/app/Classes/Modules/Transactions/ControllersLogic/CreatePurchaseOrderTransactionLogic.php index 9bab107f..68072a6e 100644 --- a/app/Classes/Modules/Transactions/ControllersLogic/CreatePurchaseOrderTransactionLogic.php +++ b/app/Classes/Modules/Transactions/ControllersLogic/CreatePurchaseOrderTransactionLogic.php @@ -72,14 +72,32 @@ class CreatePurchaseOrderTransactionLogic extends AbstractControllerLogic $billNumber = $this->generatesTransactionBillNumber->execute('PO-'); - $total = collect($request->input('products'))->sum(function($product){ + $products = $request->input('products'); + + if ($request->input('pushToExisting')) { + $transaction = $booking->transactions()->where('type', TransactionType::PURCHASE_ORDER)->first(); + + if ($transaction) { + foreach ($transaction->transactionDetails as $detail) { + array_push($products, [ + 'stockCode' => $detail->product_code, + 'description' => $detail->product_name, + 'quantity' => $detail->quantity, + 'unit_price' => $detail->price, + 'total' => $detail->amount + ]); + } + } + } + + $total = collect($products)->sum(function($product){ return $product['quantity'] * floatval(str_replace(',', '', $product['unit_price'])); }); $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, $request->input('products')); + 1, 0, 0, null, ApprovalStatus::PENDING_SUBMISSION, $products); $transaction = $this->createPurchaseOrderTransactionProcessor->execute($booking, $object); diff --git a/app/Classes/Modules/Transactions/ControllersLogic/UpdateGroupLogic.php b/app/Classes/Modules/Transactions/ControllersLogic/UpdateGroupLogic.php index f29db055..8e16233b 100644 --- a/app/Classes/Modules/Transactions/ControllersLogic/UpdateGroupLogic.php +++ b/app/Classes/Modules/Transactions/ControllersLogic/UpdateGroupLogic.php @@ -16,10 +16,12 @@ use App\Classes\Modules\Transactions\DataTransferObjects\TransactionObject; use App\Classes\Modules\Transactions\Services\FetchesGroup; use App\Classes\Modules\Transactions\Services\UpdatesTransaction; use App\Classes\Modules\Transactions\Services\CalculatesTransactionTransferFee; +use App\Classes\Modules\Transactions\Services\GeneratesTransactionBillNumber; use App\Classes\ValueObjects\Constants\TransactionType; use App\Classes\ValueObjects\Constants\PaymentMethodType; use App\Classes\ValueObjects\Constants\SegmentConstants; use App\Classes\ValueObjects\Constants\ApprovalStatus; +use App\Models\Transaction; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; use ErrorException; @@ -60,6 +62,9 @@ class UpdateGroupLogic extends AbstractControllerLogic /** @var CreatesFiles */ private $createsFile; + /** @var GeneratesTransactionBillNumber */ + private $generatesTransactionBillNumber; + /** * UpdateGroupLogic constructor. * @param FetchesGroup $fetchesGroup @@ -69,8 +74,9 @@ class UpdateGroupLogic extends AbstractControllerLogic * @param CalculatesTransactionTransferFee $calculatesTransactionTransferFee * @param CreatesDocument $createsDocument * @param CreatesFiles $createsFile + * @param GeneratesTransactionBillNumber $generatesTransactionBillNumber */ - public function __construct(FetchesGroup $fetchesGroup, FetchesCompany $fetchesCompany, CalculatesTransactionServiceCharge $calculatesTransactionServiceCharge, UpdatesTransaction $updatesTransaction, CalculatesTransactionTransferFee $calculatesTransactionTransferFee, CreatesDocument $createsDocument, CreatesFiles $createsFile) + public function __construct(FetchesGroup $fetchesGroup, FetchesCompany $fetchesCompany, CalculatesTransactionServiceCharge $calculatesTransactionServiceCharge, UpdatesTransaction $updatesTransaction, CalculatesTransactionTransferFee $calculatesTransactionTransferFee, CreatesDocument $createsDocument, CreatesFiles $createsFile, GeneratesTransactionBillNumber $generatesTransactionBillNumber) { $this->fetchesGroup = $fetchesGroup; $this->fetchesCompany = $fetchesCompany; @@ -79,6 +85,7 @@ class UpdateGroupLogic extends AbstractControllerLogic $this->calculatesTransactionTransferFee = $calculatesTransactionTransferFee; $this->createsDocument = $createsDocument; $this->createsFile = $createsFile; + $this->generatesTransactionBillNumber = $generatesTransactionBillNumber; } /** @@ -162,8 +169,61 @@ class UpdateGroupLogic extends AbstractControllerLogic $this->updatesTransaction->execute($transferTransaction, $object); } + // group transfer fee from supplier currency order dashboard manual input + if ($request->input('group_transfer_fee')) { + $fee = $request->input('group_transfer_fee'); + + $group_transfer_fee = $group->morphTransactions()->where('type', TransactionType::TRANSFER_FEE)->first(); + + if ($group_transfer_fee) { + $group_transfer_fee->amount = $fee; + $group_transfer_fee->original_amount = $fee; + $group_transfer_fee->save(); + } else { + $transferFeeNumber = $this->generatesTransactionBillNumber->execute('TRFR-'); + $object = new TransactionObject($transferFeeNumber, TransactionType::TRANSFER_FEE, 1, $supplier->id, + $supplier->banks()->where('default', true)->first()->id, PaymentMethodType::CASH, + $fee, $fee, $group->original_currency_id, $group->original_currency_id, + 1, 0, 0, null, ApprovalStatus::APPROVED); + + $model = new Transaction(); + $model->bill_no = $object->getBillNo(); + $model->type = $object->getTransactionType(); + $model->issuer = $object->getIssuer(); + $model->receiver = $object->getReceiver(); + $model->recipient_bank_account_id = $object->getRecipientBankAccountId(); + $model->payment_method = $object->getPaymentMethod(); + $model->amount = $object->getAmount(); + $model->original_amount = $object->getOriginalAmount(); + $model->currency_id = $object->getCurrencyId(); + $model->original_currency_id = $object->getOriginalCurrencyId(); + $model->currency_rate = $object->getCurrencyRate(); + $model->tax = $object->getTax(); + $model->service_charge = $object->getServiceCharge(); + $model->expires_on = $object->getExpiresOn(); + $model->status = $object->getStatus(); + $model->payment_reference = $object->getPaymentReference(); + + $group->morphTransactions()->save($model); + } + } + + $group_transfer_fee = $group->morphTransactions()->where('type', TransactionType::TRANSFER_FEE)->first(); + + $group_transfer_fee_original_amount = 0; + + if ($group_transfer_fee) { + $group_transfer_fee_original_amount = $group_transfer_fee->original_amount; + } + + $transferFeeTransactions = $group->transactions()->with([ + 'transactions' => function ($transaction) { + return $transaction->where('type', TransactionType::TRANSFER_FEE); + }])->get()->pluck('transactions')->flatten(); + $group->issuer = $supplier->id; - $group->amount = $group->transactions()->sum('amount'); + $group->original_amount = $group->transactions()->sum('original_amount') + ((float)$transferFeeTransactions->sum('service_charge') + (float)$group_transfer_fee_original_amount); + $group->amount = $group->transactions()->sum('amount') + (((float)$transferFeeTransactions->sum('service_charge') + (float)$group_transfer_fee_original_amount) / $rate); $group->currency_rate = $rate; $group->tax = $group->transactions()->sum('tax'); $group->service_charge = $group->transactions()->sum('service_charge'); @@ -172,12 +232,7 @@ class UpdateGroupLogic extends AbstractControllerLogic $group->documents()->delete(); - $transferFeeTransactions = $group->transactions()->with([ - 'transactions' => function ($transaction) { - return $transaction->where('type', TransactionType::TRANSFER_FEE); - }])->get()->pluck('transactions')->flatten(); - - $pdf = LaravelMpdf::loadView('pages.pdfs.currency_vendor_order', ['transactions' => $group->transactions, 'transferFeeTransactions' => $transferFeeTransactions, 'supplier' => $supplier]); + $pdf = LaravelMpdf::loadView('pages.pdfs.currency_vendor_order', ['transactions' => $group->transactions, 'transferFeeTransactions' => $transferFeeTransactions, 'supplier' => $supplier, 'groupTransferFeeOriginalAmount' => $group_transfer_fee_original_amount]); $object = new DocumentObject( DocumentType::CURRENCY_VENDOR_ORDER, diff --git a/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionProcessor.php b/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionProcessor.php index 7f105dc8..76f7cef7 100644 --- a/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionProcessor.php +++ b/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionProcessor.php @@ -14,13 +14,16 @@ use App\Classes\Modules\Bookings\Services\CalculatesBookingCurrencyAverageRate; use App\Classes\Modules\Companies\Services\FetchesCompany; use App\Classes\Modules\Bookings\Services\UpdatesBookingStatus; use App\Classes\Modules\Transactions\DataTransferObjects\TransactionObject; +use App\Classes\Jobs\CreateMilestoneRewardByTransactionJob; use App\Classes\ValueObjects\Constants\ApprovalStatus; use App\Classes\ValueObjects\Constants\SegmentConstants; use App\Classes\ValueObjects\Constants\TransactionType; use App\Classes\ValueObjects\Constants\DocumentType; +use App\Classes\ValueObjects\Constants\Milestones; use App\Models\Booking; use App\Models\SegmentConstant; + class CreateInvoiceTransactionProcessor { @@ -123,6 +126,7 @@ class CreateInvoiceTransactionProcessor $transaction = $booking->transactions() ->where('type', TransactionType::PAYMENT) ->latest()->get()[0]; + CreateMilestoneRewardByTransactionJob::dispatch($transaction, [Milestones::MILESTONE_1]); $billNumber = $this->generatesTransactionBillNumber->execute('INV-'); diff --git a/app/Classes/ValueObjects/Constants/MilestoneCreationOptions.php b/app/Classes/ValueObjects/Constants/MilestoneCreationOptions.php index 4631b25b..6e94e610 100644 --- a/app/Classes/ValueObjects/Constants/MilestoneCreationOptions.php +++ b/app/Classes/ValueObjects/Constants/MilestoneCreationOptions.php @@ -6,8 +6,9 @@ class MilestoneCreationOptions { const OPTIONS_MILESTONE_NAME= [ ['text' => 'MILESTONE 1', 'id' => Milestones::MILESTONE_1], - ['text' => 'MILESTONE 2', 'id' => Milestones::MILESTONE_2], - ['text' => 'MILESTONE 3', 'id' => Milestones::MILESTONE_3], + // ['text' => 'MILESTONE DEMO 1', 'id' => Milestones::MILESTONE_DEMO_1], + // ['text' => 'MILESTONE 2', 'id' => Milestones::MILESTONE_2], + // ['text' => 'MILESTONE 3', 'id' => Milestones::MILESTONE_3], // ['text' => 'MILESTONE 4', 'id' => Milestones::MILESTONE_4], // ['text' => 'MILESTONE 5', 'id' => Milestones::MILESTONE_5], // ['text' => 'MILESTONE 6', 'id' => Milestones::MILESTONE_6], diff --git a/app/Classes/ValueObjects/Constants/Milestones.php b/app/Classes/ValueObjects/Constants/Milestones.php index 19961d68..6a85abbe 100644 --- a/app/Classes/ValueObjects/Constants/Milestones.php +++ b/app/Classes/ValueObjects/Constants/Milestones.php @@ -4,9 +4,10 @@ namespace App\Classes\ValueObjects\Constants; class Milestones { - public const MILESTONE_1 = 'MILESTONE 1'; //Authentication (Sign in) or CreateCustomerLogic (Sign up) - public const MILESTONE_2 = 'MILESTONE 2'; //Create Identification Document - public const MILESTONE_3 = 'MILESTONE 3'; //Assign Company to Segment Logic -segment.assign when accept 1688 + public const MILESTONE_1 = 'MILESTONE 1'; //Has 2 successful bookings + // public const MILESTONE_DEMO_1 = 'MILESTONE_DEMO_1 1'; //Authentication (Sign in) or CreateCustomerLogic (Sign up) + // public const MILESTONE_2 = 'MILESTONE 2'; //Create Identification Document + // public const MILESTONE_3 = 'MILESTONE 3'; //Assign Company to Segment Logic -segment.assign when accept 1688 // public const MILESTONE_4 = 'MILESTONE 4'; //Create Bank Logic (Transfer Now from dashboard) // public const MILESTONE_5 = 'MILESTONE 5'; //Create Booking Logic // public const MILESTONE_6 = 'MILESTONE 6'; //Create Address Logic (At transfer page before create booking) diff --git a/app/Console/Commands/UpdateBillGroupAndGroupToIncludeTransferFee.php b/app/Console/Commands/UpdateBillGroupAndGroupToIncludeTransferFee.php new file mode 100644 index 00000000..72a1c8f2 --- /dev/null +++ b/app/Console/Commands/UpdateBillGroupAndGroupToIncludeTransferFee.php @@ -0,0 +1,130 @@ +updateGroupLogic = $updateGroupLogic; + } + + /** + * Execute the console command. + * + * @return int + */ + public function handle() + { + + // update group to include transfer fee + $groups = Group::all(); + + foreach ($groups as $group) { + $originalTransferFees = (float)Transaction::where('type', TransactionType::TRANSFER_FEE)->whereIn('owner_id', $group->transactions->pluck('id'))->sum('service_charge'); + $correctOriginalAmount = $group->transactions()->sum('original_amount'); + $correctOriginalAmount += $originalTransferFees; + $correctAmount = $group->transactions()->sum('amount'); + $transferFees = $originalTransferFees / $group->currency_rate; + $correctAmount += $transferFees; + + if ($group->original_amount != $correctOriginalAmount || $group->amount != $correctAmount) { + $group->original_amount = $correctOriginalAmount; + $group->amount = $correctAmount; + $group->save(); + + $this->info("updated group id: {$group->id}, added transfer fee CNY {$correctOriginalAmount}"); + } + } + + // update group calculation to include individual group transfer fee + $groups = Group::whereHas('morphTransactions', function ($q) { + $q->where('type', TransactionType::TRANSFER_FEE); + })->get(); + + foreach ($groups as $group) { + $route = FacadesRoute::getRoutes()->getByName('api.transaction.group.update'); + $request = Request::create(route('api.transaction.group.update', $group->id)); + $uri = $route->uri; + $request->setRouteResolver(function () use ($request, $uri) { + // Associate Route to request so we can access route parameters. + return (new Route('PUT', $uri, []))->bind($request); + }); + + $request['rate'] = $group->currency_rate; + $request['supplier_id'] = $group->issuer; + $this->updateGroupLogic->execute($request); + + $group_transfer_fee = $group->morphTransactions()->where('type', TransactionType::TRANSFER_FEE)->first(); + $this->info("updated group id: {$group->id}, added transfer fee to individual white form CNY {$group_transfer_fee->original_amount}"); + } + + // update bill group calculation to include individual group transfer fee + $billGroups = BillGroup::all(); + + foreach ($billGroups as $billGroup) { + // ignore those has bill group refund + if ($billGroup->billRefunds()->count() > 0) { + continue; + } + + $totalOriginal = $billGroup->groups()->sum('original_amount'); + $total = $billGroup->groups()->sum('amount'); + + // update bill group payment transaction amount if there is only 1 payment transaction + $payment_transactions = $billGroup->transactions()->whereIn('status', [ApprovalStatus::PENDING_SUBMISSION, ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])->get(); + + if ($payment_transactions->count() === 1) { + $payment_transaction = $payment_transactions->first(); + if ($payment_transaction->amount === $billGroup->amount) { + $payment_transaction->original_amount = $total; + $payment_transaction->amount = $total; + $payment_transaction->save(); + $this->info("updated bill group payment transaction id: {$payment_transaction->id}, update original amount to CNY {$totalOriginal}"); + } + } + + // update bill group amount and original amount + $billGroup->original_amount = $totalOriginal; + $billGroup->amount = $total; + $billGroup->save(); + + $this->info("updated bill group id: {$billGroup->id}, added transfer fee, final original amount is CNY {$totalOriginal}"); + } + } +} diff --git a/app/Console/Commands/UpdateGroupWithTransferFee.php b/app/Console/Commands/UpdateGroupWithTransferFee.php deleted file mode 100644 index dec74d5c..00000000 --- a/app/Console/Commands/UpdateGroupWithTransferFee.php +++ /dev/null @@ -1,68 +0,0 @@ -get(); - - foreach ($groups as $group) { - $originalTransferFees = (float)Transaction::where('type', TransactionType::TRANSFER_FEE)->whereIn('owner_id', $group->transactions->pluck('id'))->sum('service_charge'); - $correctOriginalAmount = $group->transactions()->sum('original_amount'); - $correctOriginalAmount += $originalTransferFees; - $correctAmount = $group->transactions()->sum('amount'); - $transferFees = $originalTransferFees / $group->currency_rate; - $correctAmount += $transferFees; - - if ($group->original_amount != $correctOriginalAmount) { - $group->original_amount = $correctOriginalAmount; - $group->amount = $correctAmount; - $group->save(); - } - } - } -} diff --git a/app/Http/Controllers/Open1688/Open1688Controller.php b/app/Http/Controllers/Open1688/Open1688Controller.php new file mode 100644 index 00000000..2ed20540 --- /dev/null +++ b/app/Http/Controllers/Open1688/Open1688Controller.php @@ -0,0 +1,30 @@ +execute($request); + } + + /** + * @param Request $request + * @param GetProductDetailLogic $logic + * @return JsonResponse + */ + public function getProductDetail(Request $request, GetProductDetailLogic $logic): JsonResponse { + return $logic->execute($request); + } + +} diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index 20741c52..42e1a43e 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -47,12 +47,14 @@ class Kernel extends HttpKernel VerifyCsrfToken::class, \Illuminate\Routing\Middleware\SubstituteBindings::class, // \App\Http\Middleware\WebRouteLogs::class, + \App\Http\Middleware\WebResponseTimeLog::class, ], 'api' => [ 'throttle:300,1', \Illuminate\Routing\Middleware\SubstituteBindings::class, // \App\Http\Middleware\ApiRouteLogs::class, + \App\Http\Middleware\ApiResponseTimeLog::class, ], 'apipub' => [ diff --git a/app/Http/Middleware/ApiResponseTimeLog.php b/app/Http/Middleware/ApiResponseTimeLog.php new file mode 100644 index 00000000..aae6d91e --- /dev/null +++ b/app/Http/Middleware/ApiResponseTimeLog.php @@ -0,0 +1,29 @@ +route(); + $routeName = $route ? $route->getName() : 'undefined'; + $uri = $request->getPathInfo(); + + $startTime = microtime(true); // Start time + + $response = $next($request); // Handle the request + + $endTime = microtime(true); // End time + $responseTime = $endTime - $startTime; // Calculate the response time + + Log::channel('apiResponseTimeLog')->info("\nRequest to route: {$uri} \nRoute name: {$routeName} \nTime Taken: " . number_format($responseTime * 1000, 2) . "ms\n"); + + return $response; + } +} diff --git a/app/Http/Middleware/WebResponseTimeLog.php b/app/Http/Middleware/WebResponseTimeLog.php new file mode 100644 index 00000000..9a4c3e6e --- /dev/null +++ b/app/Http/Middleware/WebResponseTimeLog.php @@ -0,0 +1,29 @@ +route(); + $routeName = $route ? $route->getName() : 'undefined'; + $uri = $request->getPathInfo(); + + $startTime = microtime(true); // Start time + + $response = $next($request); // Handle the request + + $endTime = microtime(true); // End time + $responseTime = $endTime - $startTime; // Calculate the response time + + Log::channel('webResponseTimeLog')->info("\nRequest to route: {$uri} \nRoute name: {$routeName} \nTime Taken: " . number_format($responseTime * 1000, 2) . "ms\n"); + + return $response; + } +} diff --git a/app/Http/Resources/TransactionDetailResource.php b/app/Http/Resources/TransactionDetailResource.php index 4257a9fb..63c6661b 100644 --- a/app/Http/Resources/TransactionDetailResource.php +++ b/app/Http/Resources/TransactionDetailResource.php @@ -14,14 +14,23 @@ class TransactionDetailResource extends JsonResource */ public function toArray($request) { - + $item_from_1688 = str_contains($this->product_code, 'offerId'); + $offer_id_1688 = null; + if ($item_from_1688) { + $offerId = explode(',', $this->product_code)[0]; + $offer_id_1688 = substr($offerId, strpos($offerId, ':') + 1); + } + + return [ 'id' => $this->id, 'stockCode' => $this->product_code, 'description' => $this->product_name, 'quantity' => $this->quantity, 'unit_price' => (double) $this->price, - 'total' => (double) $this->amount + 'total' => (double) $this->amount, + 'item_from_1688' => $item_from_1688, + 'offer_id_1688' => $offer_id_1688 ]; } } diff --git a/app/Http/Resources/VoucherResource.php b/app/Http/Resources/VoucherResource.php index 3f3112bb..031cf39f 100644 --- a/app/Http/Resources/VoucherResource.php +++ b/app/Http/Resources/VoucherResource.php @@ -16,7 +16,7 @@ class VoucherResource extends JsonResource public function toArray($request) { $filteredRedemptions = new ArrayObject([]); - if ($request->has('filters') && str_contains($request->input('filters'), "has_active_reward")) { + if ($request->has('filters') && str_contains($request->input('filters'), "has_vouchers_all")) { $filteredRedemptions = new ArrayObject([]); } else{ diff --git a/app/Models/StatementTransaction.php b/app/Models/StatementTransaction.php index 4bba7903..6f9013b7 100644 --- a/app/Models/StatementTransaction.php +++ b/app/Models/StatementTransaction.php @@ -56,7 +56,9 @@ class StatementTransaction extends Model public function scopeDoesntMapStatement($query) { - $query->whereDoesntHave('owners', function($query){ + $query->whereHas('account', function($query) { + $query->where('statement_accounts.number', 568603010762); + })->whereDoesntHave('owners', function($query){ return $query->whereIn('status', [ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]); })->orderBy('posting_date'); } diff --git a/config/logging.php b/config/logging.php index 0c9a6ec1..3d2c5ac9 100644 --- a/config/logging.php +++ b/config/logging.php @@ -112,6 +112,22 @@ return [ 'level' => 'info', ], + 'apiResponseTimeLog' => [ + 'driver' => 'single', + 'path' => storage_path('logs/apiResponseTime.log'), + 'level' => 'info', + ], + + 'webResponseTimeLog' => [ + 'driver' => 'single', + 'path' => storage_path('logs/webResponseTimeLog.log'), + 'level' => 'info', + ], + 'guzzleShippingPortal' => [ + 'driver' => 'errorlog', + 'level' => 'debug', + ], + 'vue_polling' => [ 'driver' => 'single', 'path' => storage_path('logs/laravel_vue_plling.log'), diff --git a/config/open1688.php b/config/open1688.php new file mode 100644 index 00000000..7cf948f4 --- /dev/null +++ b/config/open1688.php @@ -0,0 +1,11 @@ + env('OPEN_1688_APP_KEY', ''), + 'app_secret' => env('OPEN_1688_APP_SECRET', ''), + 'access_token' => env('open_1688_ACCESS_TOKEN', ''), + 'refresh_token' => env('open_1688_REFRESH_TOKEN', ''), + 'url' => env('OPEN_1688_URL', ''), + 'product_search_keyword_api' => env('OPEN_1688_PRODUCT_SEARCH_KEYWORD', ''), + 'product_detail_api' => env('OPEN_1688_PRODUCT_DETAIL', ''), +]; diff --git a/database/migrations/2022_12_27_165842_create_route_logs_table.php b/database/migrations/2022_12_27_165842_create_route_logs_table.php index bdab0257..78b18b2a 100644 --- a/database/migrations/2022_12_27_165842_create_route_logs_table.php +++ b/database/migrations/2022_12_27_165842_create_route_logs_table.php @@ -13,21 +13,21 @@ class CreateRouteLogsTable extends Migration */ public function up() { - Schema::create('route_logs', function (Blueprint $table) { - $table->id(); - $table->foreignId('user_id')->unsigned(); - $table->string('ip_address'); - $table->string('url', 255); - $table->string('request_method'); - $table->string('browser')->nullable(); - $table->string('platform')->nullable(); - $table->string('longitude')->nullable(); - $table->string('latitude')->nullable(); - $table->string('last_page')->nullable(); - $table->string('countryname')->nullable(); - $table->integer('route_type'); - $table->timestamps(); - }); + // Schema::create('route_logs', function (Blueprint $table) { + // $table->id(); + // $table->foreignId('user_id')->unsigned(); + // $table->string('ip_address'); + // $table->string('url', 255); + // $table->string('request_method'); + // $table->string('browser')->nullable(); + // $table->string('platform')->nullable(); + // $table->string('longitude')->nullable(); + // $table->string('latitude')->nullable(); + // $table->string('last_page')->nullable(); + // $table->string('countryname')->nullable(); + // $table->integer('route_type'); + // $table->timestamps(); + // }); } /** diff --git a/database/migrations/2023_12_18_230408_create_index_for_transaction_table.php b/database/migrations/2023_12_18_230408_create_index_for_transaction_table.php new file mode 100644 index 00000000..e343589f --- /dev/null +++ b/database/migrations/2023_12_18_230408_create_index_for_transaction_table.php @@ -0,0 +1,58 @@ +index('status'); + $table->index('type'); + $table->index('payment_method'); + $table->index('payment_reference'); + $table->index('bill_no'); + $table->index('owner_type'); + $table->index('owner_id'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('transactions', function (Blueprint $table) { + $table->dropIndex('owner_type'); + $table->dropIndex('owner_id'); + $table->dropIndex('type'); + $table->dropIndex('issuer'); + $table->dropIndex('receiver'); + $table->dropIndex('recipient_bank_account_id'); + $table->dropIndex('payment_method'); + $table->dropIndex('payment_reference'); + $table->dropIndex('bill_no'); + $table->dropIndex('amount'); + $table->dropIndex('original_amount'); + $table->dropIndex('currency_id'); + $table->dropIndex('original_currency_id'); + $table->dropIndex('currency_rate'); + $table->dropIndex('tax'); + $table->dropIndex('service_charge'); + $table->dropIndex('expires_on'); + $table->dropIndex('status'); + $table->dropIndex('deleted_at'); + $table->dropIndex('created_at'); + $table->dropIndex('updated_at'); + }); + } +} diff --git a/package.json b/package.json index 6b27498c..32058424 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,8 @@ "vue": "^2.7.14", "vue-avatar": "^2.1.8", "vue-debounce": "^2.6.0", - "vue-template-compiler": "^2.7.14", + "vue-gtag": "^1.16.1", + "vue-template-compiler": "^2.6.10", "vue-the-mask": "^0.11.1", "vuelidate": "^0.7.4", "vuex": "^3.1.1" diff --git a/resources/assets/vue/app.js b/resources/assets/vue/app.js index 19d403c5..11d3ed9f 100644 --- a/resources/assets/vue/app.js +++ b/resources/assets/vue/app.js @@ -2,6 +2,7 @@ /** Dependencies */ import Vue from 'vue' import store from './vuex/store'; +import VueGtag from 'vue-gtag' window.route = require('./general/functions/router'); @@ -59,6 +60,18 @@ Vue.component(Avatar); const files = require.context('./', true, /\.vue$/i); files.keys().map(key => Vue.component(key.split('/').pop().split('.')[0], files(key).default)); +// Google Analytics 4 (GA4) Integration +Vue.use(VueGtag, { + property: { + id: 'G-FEJNZTR0WP', + params: { + user_id: store.getters.getUserId + } + } +}); + +console.log('Google Tag pushed'); + const app = new Vue({ el: '#app', store, diff --git a/resources/assets/vue/components/accounting/elements/EditSingleItemInListComponent.vue b/resources/assets/vue/components/accounting/elements/EditSingleItemInListComponent.vue index 5d1341b1..3e077bbc 100644 --- a/resources/assets/vue/components/accounting/elements/EditSingleItemInListComponent.vue +++ b/resources/assets/vue/components/accounting/elements/EditSingleItemInListComponent.vue @@ -136,7 +136,7 @@ case 'Sales': return ['Exchange', 'Izyim', 'Lite', 'Cntr', 'Probashi', 'Pets']; case 'Top Up': - return ['Exchange', 'Izyim']; + return ['Exchange', 'Izyim', 'Lite']; default: return []; } diff --git a/resources/assets/vue/components/accounting/elements/StatementTransactionComponent.vue b/resources/assets/vue/components/accounting/elements/StatementTransactionComponent.vue index 787f2f37..d1b59663 100644 --- a/resources/assets/vue/components/accounting/elements/StatementTransactionComponent.vue +++ b/resources/assets/vue/components/accounting/elements/StatementTransactionComponent.vue @@ -10,7 +10,8 @@
{{item.owners.pending_verification[0].system}}
{{ typeString(item.owners.pending_verification[0].type) }}
-
{{item.owners.pending_verification[0].reference}}
+
{{item.owners.pending_verification[0].reference}}
+
{{item.owners.pending_verification[0].reference}}
diff --git a/resources/assets/vue/components/accounting/sections/TransactionsMappingComponent.vue b/resources/assets/vue/components/accounting/sections/TransactionsMappingComponent.vue index 65f5b0b1..967b4b68 100644 --- a/resources/assets/vue/components/accounting/sections/TransactionsMappingComponent.vue +++ b/resources/assets/vue/components/accounting/sections/TransactionsMappingComponent.vue @@ -76,26 +76,30 @@ -
-
-
- - - - -
-
- - - - -
-
-
- - Search - -
+
+
+ + + + +
+
+ + + + +
+
+ + + + +
+
+
+ + Search +
@@ -231,6 +235,7 @@ export default { parameters: { startDate: '', endDate: '', + account: '', }, type: null, stage: null, @@ -253,6 +258,7 @@ export default { endDate: { required }, + account: {}, }, files: { // required // todo-new: set required if is pdf section @@ -327,6 +333,17 @@ export default { this.files = []; this.parameters = {}; }, + getAccountId(){ + if (this.parameters.account) { + if (this.parameters.account.includes('568603010762')) { + return 4; + } + if (this.parameters.account.includes('8881040198515')) { + return 5; + } + } + return false; + }, startMapping(stage){ this.stage = stage; @@ -334,16 +351,17 @@ export default { if(this.type === 1){ switch(this.stage){ case 1: - this.filter = {min_amount: 0, is_mapped: true, is_mapped_with_multiple: false, statement_transaction_owner_type_in: [1, 2], statement_transaction_owner_status_in: [1], per_page: 100, order_by: {column: 'posting_date', DESC: true}} + this.filter = {min_amount: 0, is_mapped: true, is_mapped_with_multiple: false, statement_transaction_owner_type_in: [1, 2], statement_transaction_owner_status_in: [1], ...this.parameters.account && {statement_transaction_account_id: this.getAccountId()}, ...this.parameters.startDate && {statement_transaction_posting_start: this.parameters.startDate}, ...this.parameters.endDate && {statement_transaction_posting_end: this.parameters.endDate}, per_page: 100, order_by: {column: 'posting_date', DESC: true}} + break; case 2: - this.filter = {min_amount: 0, is_mapped: true, is_mapped_with_multiple: true, statement_transaction_owner_type_in: [1, 2], statement_transaction_owner_status_in: [1], per_page: 100, order_by: {column: 'posting_date', DESC: true}} + this.filter = {min_amount: 0, is_mapped: true, is_mapped_with_multiple: true, statement_transaction_owner_type_in: [1, 2], statement_transaction_owner_status_in: [1], ...this.parameters.account && {statement_transaction_account_id: this.getAccountId()}, ...this.parameters.startDate && {statement_transaction_posting_start: this.parameters.startDate}, ...this.parameters.endDate && {statement_transaction_posting_end: this.parameters.endDate}, per_page: 100, order_by: {column: 'posting_date', DESC: true}} break; case 3: - this.filter = {min_amount: 0, is_mapped_false_or_mapped_but_status_in: [4], per_page: 100, order_by: {column: 'posting_date', DESC: true}} + this.filter = {min_amount: 0, is_mapped_false_or_mapped_but_status_in: [4], ...this.parameters.account && {statement_transaction_account_id: this.getAccountId()}, ...this.parameters.startDate && {statement_transaction_posting_start: this.parameters.startDate}, ...this.parameters.endDate && {statement_transaction_posting_end: this.parameters.endDate}, per_page: 100, order_by: {column: 'posting_date', DESC: true}} break; case 4: - this.filter = {min_amount: 0, is_mapped: true, statement_transaction_owner_type_in: [1, 2], statement_transaction_owner_status_in: [2], per_page: 100, order_by: {column: 'posting_date', DESC: true}} + this.filter = {min_amount: 0, is_mapped: true, statement_transaction_owner_type_in: [1, 2], statement_transaction_owner_status_in: [2], ...this.parameters.account && {statement_transaction_account_id: this.getAccountId()}, per_page: 100, order_by: {column: 'posting_date', DESC: true}} if (typeof this.parameters.startDate != 'undefined' && this.parameters.startDate != '') this.filter = {...this.filter, ...{statement_transaction_posting_start: this.parameters.startDate}}; @@ -355,16 +373,16 @@ export default { if(this.type === 2){ switch(this.stage){ case 1: - this.filter = {max_amount: 0, is_mapped: true, is_mapped_with_multiple: false, statement_transaction_owner_type_in: [3, 5],statement_transaction_owner_status_in: [1], per_page: 100, order_by: {column: 'posting_date', DESC: true}} + this.filter = {max_amount: 0, is_mapped: true, is_mapped_with_multiple: false, statement_transaction_owner_type_in: [3, 5],statement_transaction_owner_status_in: [1], ...this.parameters.account && {statement_transaction_account_id: this.getAccountId()}, ...this.parameters.startDate && {statement_transaction_posting_start: this.parameters.startDate}, ...this.parameters.endDate && {statement_transaction_posting_end: this.parameters.endDate}, per_page: 100, order_by: {column: 'posting_date', DESC: true}} break; case 2: - this.filter = {max_amount: 0, is_mapped: true, is_mapped_with_multiple: true, statement_transaction_owner_type_in: [3, 5], statement_transaction_owner_status_in: [1], per_page: 100, order_by: {column: 'posting_date', DESC: true}} + this.filter = {max_amount: 0, is_mapped: true, is_mapped_with_multiple: true, statement_transaction_owner_type_in: [3, 5], statement_transaction_owner_status_in: [1], ...this.parameters.account && {statement_transaction_account_id: this.getAccountId()}, ...this.parameters.startDate && {statement_transaction_posting_start: this.parameters.startDate}, ...this.parameters.endDate && {statement_transaction_posting_end: this.parameters.endDate}, per_page: 100, order_by: {column: 'posting_date', DESC: true}} break; case 3: - this.filter = {max_amount: 0, is_mapped: false, per_page: 100, order_by: {column: 'posting_date', DESC: true}} + this.filter = {max_amount: 0, is_mapped: false, ...this.parameters.account && {statement_transaction_account_id: this.getAccountId()}, ...this.parameters.startDate && {statement_transaction_posting_start: this.parameters.startDate}, ...this.parameters.endDate && {statement_transaction_posting_end: this.parameters.endDate}, per_page: 100, order_by: {column: 'posting_date', DESC: true}} break; case 4: - this.filter = {max_amount: 0, is_mapped: true, statement_transaction_owner_type_in: [3, 5], statement_transaction_owner_status_in: [2], per_page: 100, order_by: {column: 'posting_date', DESC: true}} + this.filter = {max_amount: 0, is_mapped: true, statement_transaction_owner_type_in: [3, 5], statement_transaction_owner_status_in: [2], ...this.parameters.account && {statement_transaction_account_id: this.getAccountId()}, per_page: 100, order_by: {column: 'posting_date', DESC: true}} if (typeof this.parameters.startDate != 'undefined' && this.parameters.startDate != '') this.filter = {...this.filter, ...{statement_transaction_posting_start: this.parameters.startDate}}; diff --git a/resources/assets/vue/components/accounts/elements/VouchersNavigationBarComponent.vue b/resources/assets/vue/components/accounts/elements/VouchersNavigationBarComponent.vue new file mode 100644 index 00000000..60947cb9 --- /dev/null +++ b/resources/assets/vue/components/accounts/elements/VouchersNavigationBarComponent.vue @@ -0,0 +1,42 @@ + + + diff --git a/resources/assets/vue/components/accounts/forms/LogOutFormComponent.vue b/resources/assets/vue/components/accounts/forms/LogOutFormComponent.vue index 4956260f..5843111c 100644 --- a/resources/assets/vue/components/accounts/forms/LogOutFormComponent.vue +++ b/resources/assets/vue/components/accounts/forms/LogOutFormComponent.vue @@ -68,11 +68,13 @@ }, successHandler(){ this.$store.dispatch('userAuthentication', {access_token: '', redirect_url: this.route('login')}); + this.$store.dispatch('clearVoucher'); }, errorHandler(){ this.$store.dispatch('userAuthentication', {access_token: '', redirect_url: this.route('login')}); + this.$store.dispatch('clearVoucher'); } } } - \ No newline at end of file + diff --git a/resources/assets/vue/components/bookings/elements/AlibabaProductOverviewComponent.vue b/resources/assets/vue/components/bookings/elements/AlibabaProductOverviewComponent.vue new file mode 100644 index 00000000..7c5f43fa --- /dev/null +++ b/resources/assets/vue/components/bookings/elements/AlibabaProductOverviewComponent.vue @@ -0,0 +1,34 @@ + + + \ No newline at end of file diff --git a/resources/assets/vue/components/bookings/elements/AvailableVouchersComponent.vue b/resources/assets/vue/components/bookings/elements/AvailableVouchersComponent.vue index 89a56b0f..9b08e7f3 100644 --- a/resources/assets/vue/components/bookings/elements/AvailableVouchersComponent.vue +++ b/resources/assets/vue/components/bookings/elements/AvailableVouchersComponent.vue @@ -12,11 +12,14 @@ {{ item.voucher.code }}
- + + This voucher has expired. + + Valid till {{ item.voucher.end_date }} - No expiry date + Non-expired
@@ -62,7 +65,7 @@ fetchVouchers(){ this.isLoading = true; if(this.employee){ - this.submit(route('api.voucher.user.list') + '?filters=' + JSON.stringify( { 'has_active_reward': this.employee.id} ), 'get', this.section, false, false); + this.submit(route('api.voucher.user.list') + '?filters=' + JSON.stringify( { 'has_vouchers_all': this.employee.id} ), 'get', this.section, false, false); } }, successHandler(response){ diff --git a/resources/assets/vue/components/bookings/elements/EditTransferFeeFormComponent.vue b/resources/assets/vue/components/bookings/elements/EditTransferFeeFormComponent.vue index bb82964a..5c46d594 100644 --- a/resources/assets/vue/components/bookings/elements/EditTransferFeeFormComponent.vue +++ b/resources/assets/vue/components/bookings/elements/EditTransferFeeFormComponent.vue @@ -15,9 +15,9 @@
- + - +
@@ -54,24 +54,34 @@ id: { type: Number, required: true - } + }, + rate:{ + type: Number, + required: true + }, + supplier_id: { + type: Number, + required: true + }, }, data(){ return { error: '', parameters: { - fee: (Math.round((this.transfer_fee + Number.EPSILON) * 100) / 100).toFixed(2) + supplier_id: this.supplier_id, + rate: this.rate, + group_transfer_fee: (Math.round((this.transfer_fee + Number.EPSILON) * 100) / 100).toFixed(2) }, } }, validations: { parameters: { - fee: { }, + group_transfer_fee: { }, }, }, methods: { submitForm() { - this.submit(route('api.transaction.group.fee.update', this.id), 'put', this.section, true, true); + this.submit(route('api.transaction.group.update', this.id), 'put', this.section, true, true); } }, mixins: [ModalFormHandler] diff --git a/resources/assets/vue/components/bookings/elements/ListVouchersComponent.vue b/resources/assets/vue/components/bookings/elements/ListVouchersComponent.vue index 7b4664a7..e351248e 100644 --- a/resources/assets/vue/components/bookings/elements/ListVouchersComponent.vue +++ b/resources/assets/vue/components/bookings/elements/ListVouchersComponent.vue @@ -26,11 +26,14 @@

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

{{ item.voucher.value }}% Discount

-
+
+ This voucher has expired. +
+
Valid till {{ item.voucher.end_date }}
- No expiry date + Non-expired
@@ -76,7 +79,7 @@ fetchVouchers(){ this.isLoading = true; if(this.employee){ - this.submit(route('api.voucher.user.list') + '?filters=' + JSON.stringify( { 'has_active_reward': this.employee.id} ), 'get', this.section, false, false); + this.submit(route('api.voucher.user.list') + '?filters=' + JSON.stringify( { 'has_vouchers_all': this.employee.id} ), 'get', this.section, false, false); } }, successHandler(response){ diff --git a/resources/assets/vue/components/bookings/elements/PaymentHistoryComponent.vue b/resources/assets/vue/components/bookings/elements/PaymentHistoryComponent.vue index e560f76d..cbbb60c4 100644 --- a/resources/assets/vue/components/bookings/elements/PaymentHistoryComponent.vue +++ b/resources/assets/vue/components/bookings/elements/PaymentHistoryComponent.vue @@ -289,6 +289,17 @@ +
+
+ +
+
+ + + + +
+
diff --git a/resources/assets/vue/components/bookings/elements/TransactionGroupPaymentComponent.vue b/resources/assets/vue/components/bookings/elements/TransactionGroupPaymentComponent.vue index 2696ceb5..2700de72 100644 --- a/resources/assets/vue/components/bookings/elements/TransactionGroupPaymentComponent.vue +++ b/resources/assets/vue/components/bookings/elements/TransactionGroupPaymentComponent.vue @@ -2,7 +2,7 @@
-
+
@@ -87,9 +87,12 @@ - - - +
+ + + +
+
@@ -123,20 +126,33 @@ payments:{ type: Array, required: true - } + }, + emptyPaymentList: { + type: Function, + required: true + }, }, data(){ return { expanded: false, - active: this.item ? this.payments.some(payment => payment.id === this.item.id) : false, + // active: this.item ? this.payments.some(payment => payment.id === this.item.id) : false, } }, created(){ - this.active = this.payments.some(payment => payment.id === this.item.id); + // this.active = this.payments.some(payment => payment.id === this.item.id); + }, + computed: { + active() { + return this.payments.some(payment => payment.id === this.item.id); + } }, methods: { - activate(){ - this.active = !this.active; + activate(event){ + if ((event.target.tagName.toLowerCase() === 'button' && event.target.getAttribute('data-type') === 'editTransactionGroup') || Boolean(event.target.closest('.do-not-activate'))) { + this.emptyPaymentList(); + return; + } + // this.active = !this.active; this.$emit('input', this.item) }, expand(event){ diff --git a/resources/assets/vue/components/bookings/forms/AlibabaProductDetailFormComponent.vue b/resources/assets/vue/components/bookings/forms/AlibabaProductDetailFormComponent.vue new file mode 100644 index 00000000..95e1c72a --- /dev/null +++ b/resources/assets/vue/components/bookings/forms/AlibabaProductDetailFormComponent.vue @@ -0,0 +1,270 @@ + + \ No newline at end of file diff --git a/resources/assets/vue/components/bookings/forms/BookingFormComponent.vue b/resources/assets/vue/components/bookings/forms/BookingFormComponent.vue index 7b2138bf..c6043b8a 100644 --- a/resources/assets/vue/components/bookings/forms/BookingFormComponent.vue +++ b/resources/assets/vue/components/bookings/forms/BookingFormComponent.vue @@ -93,8 +93,8 @@
-

The recipient can expect to receive the transfer within 1-3 working days. Explore our BANK TRANSFER (SAVER) option for a better rate!

-

Enjoy a better rate with this option! The recipient will receive the transfer after 3-5 working days..

+

The recipient can expect to receive the transfer within 3-5 working days. Explore our BANK TRANSFER (SAVER) option for a better rate!

+

Enjoy a better rate with this option! The recipient will receive the transfer after 5-7 working days..

diff --git a/resources/assets/vue/components/bookings/forms/BookingPaymentQuotationComponent.vue b/resources/assets/vue/components/bookings/forms/BookingPaymentQuotationComponent.vue index abf3e8e2..f336c1ee 100644 --- a/resources/assets/vue/components/bookings/forms/BookingPaymentQuotationComponent.vue +++ b/resources/assets/vue/components/bookings/forms/BookingPaymentQuotationComponent.vue @@ -268,7 +268,8 @@
{{ voucherCodeFailedReason }} - Voucher applied + Voucher applied + No voucher applied
diff --git a/resources/assets/vue/components/bookings/forms/PurchaseOrderItemFormComponent.vue b/resources/assets/vue/components/bookings/forms/PurchaseOrderItemFormComponent.vue index d91d2661..16a10b64 100644 --- a/resources/assets/vue/components/bookings/forms/PurchaseOrderItemFormComponent.vue +++ b/resources/assets/vue/components/bookings/forms/PurchaseOrderItemFormComponent.vue @@ -22,7 +22,10 @@
-

{{product.description}}

+ +

{{product.description}}

+
+

{{product.description}}

diff --git a/resources/assets/vue/components/bookings/sections/AlibabaSiteSectionComponent.vue b/resources/assets/vue/components/bookings/sections/AlibabaSiteSectionComponent.vue new file mode 100644 index 00000000..de9cd26a --- /dev/null +++ b/resources/assets/vue/components/bookings/sections/AlibabaSiteSectionComponent.vue @@ -0,0 +1,147 @@ + + \ No newline at end of file diff --git a/resources/assets/vue/components/bookings/sections/BookingDetailsSectionComponent.vue b/resources/assets/vue/components/bookings/sections/BookingDetailsSectionComponent.vue index a2762ce7..10a8b702 100644 --- a/resources/assets/vue/components/bookings/sections/BookingDetailsSectionComponent.vue +++ b/resources/assets/vue/components/bookings/sections/BookingDetailsSectionComponent.vue @@ -110,10 +110,15 @@
+
+
+ +
+
-
+
@@ -460,6 +465,7 @@
+
diff --git a/resources/assets/vue/components/bookings/sections/SupplierPendingOrderPaymentSectionComponent.vue b/resources/assets/vue/components/bookings/sections/SupplierPendingOrderPaymentSectionComponent.vue index eba9fde5..0849bd31 100644 --- a/resources/assets/vue/components/bookings/sections/SupplierPendingOrderPaymentSectionComponent.vue +++ b/resources/assets/vue/components/bookings/sections/SupplierPendingOrderPaymentSectionComponent.vue @@ -48,7 +48,7 @@
@@ -103,6 +103,9 @@ this.selectedSupplier.status = false; this.payments = []; }, + emptyPaymentList() { + this.payments = []; + }, updateOrder(payment){ this.payments.some(item => item.id === payment.id) ? this.payments = this.payments.filter(item => item.id !== payment.id) : this.payments.push(payment); } diff --git a/resources/assets/vue/components/bookings/sections/SupplierPendingOrdersSectionComponent.vue b/resources/assets/vue/components/bookings/sections/SupplierPendingOrdersSectionComponent.vue index 6b83d563..fb720737 100644 --- a/resources/assets/vue/components/bookings/sections/SupplierPendingOrdersSectionComponent.vue +++ b/resources/assets/vue/components/bookings/sections/SupplierPendingOrdersSectionComponent.vue @@ -117,16 +117,16 @@
- - + +
diff --git a/resources/assets/vue/components/companies/elements/SingleUserRewardItemComponent.vue b/resources/assets/vue/components/companies/elements/SingleUserRewardItemComponent.vue index 9cc2409a..164c98c1 100644 --- a/resources/assets/vue/components/companies/elements/SingleUserRewardItemComponent.vue +++ b/resources/assets/vue/components/companies/elements/SingleUserRewardItemComponent.vue @@ -17,11 +17,14 @@

Voucher claimed

+

+ This voucher has expired. +

Valid till {{ item.voucher.end_date }}

- - + Non-expired

diff --git a/resources/assets/vue/components/companies/sections/CustomerDashboardSectionComponent.vue b/resources/assets/vue/components/companies/sections/CustomerDashboardSectionComponent.vue index 5a0766cb..074354ca 100644 --- a/resources/assets/vue/components/companies/sections/CustomerDashboardSectionComponent.vue +++ b/resources/assets/vue/components/companies/sections/CustomerDashboardSectionComponent.vue @@ -201,6 +201,7 @@
+ diff --git a/resources/assets/vue/components/companies/sections/CustomerProfileSectionComponent.vue b/resources/assets/vue/components/companies/sections/CustomerProfileSectionComponent.vue index bd646426..76c28e1d 100644 --- a/resources/assets/vue/components/companies/sections/CustomerProfileSectionComponent.vue +++ b/resources/assets/vue/components/companies/sections/CustomerProfileSectionComponent.vue @@ -141,6 +141,7 @@
+
@@ -213,4 +214,4 @@ } } } - \ No newline at end of file + diff --git a/resources/assets/vue/components/companies/sections/CustomerRewardsAdminSectionComponent.vue b/resources/assets/vue/components/companies/sections/CustomerRewardsAdminSectionComponent.vue index 9429593a..aba22978 100644 --- a/resources/assets/vue/components/companies/sections/CustomerRewardsAdminSectionComponent.vue +++ b/resources/assets/vue/components/companies/sections/CustomerRewardsAdminSectionComponent.vue @@ -52,7 +52,7 @@
- + @@ -69,10 +69,15 @@
- + + +
diff --git a/resources/assets/vue/components/companies/sections/CustomerRewardsSectionComponent.vue b/resources/assets/vue/components/companies/sections/CustomerRewardsSectionComponent.vue index 2a85b9ea..b1f2a5f9 100644 --- a/resources/assets/vue/components/companies/sections/CustomerRewardsSectionComponent.vue +++ b/resources/assets/vue/components/companies/sections/CustomerRewardsSectionComponent.vue @@ -19,7 +19,7 @@
-
+
@@ -52,7 +52,7 @@
- + @@ -69,11 +69,16 @@
- + +
@@ -108,5 +113,9 @@ diff --git a/resources/assets/vue/components/general/elements/VouchersSummaryAdminComponent.vue b/resources/assets/vue/components/general/elements/VouchersSummaryAdminComponent.vue new file mode 100644 index 00000000..dc4a2a54 --- /dev/null +++ b/resources/assets/vue/components/general/elements/VouchersSummaryAdminComponent.vue @@ -0,0 +1,42 @@ + + + + diff --git a/resources/assets/vue/components/general/elements/VouchersSummaryComponent.vue b/resources/assets/vue/components/general/elements/VouchersSummaryComponent.vue new file mode 100644 index 00000000..e90748af --- /dev/null +++ b/resources/assets/vue/components/general/elements/VouchersSummaryComponent.vue @@ -0,0 +1,26 @@ + + + + diff --git a/resources/assets/vue/components/general/forms/RemarkCommentFormComponent.vue b/resources/assets/vue/components/general/forms/RemarkCommentFormComponent.vue index ed35250c..c2a0bd93 100644 --- a/resources/assets/vue/components/general/forms/RemarkCommentFormComponent.vue +++ b/resources/assets/vue/components/general/forms/RemarkCommentFormComponent.vue @@ -47,12 +47,7 @@ methods: { submitForm() { this.submit(this.data ? this.route('api.remark.update', this.data.id) : this.route('api.remark.create', this.id), this.data ? 'put' : 'post', this.section, true, true); - this.$emit('submit') }, - successHandler(response){ - this.parameters.content = ''; - this.closeModal(); - } }, mixins: [modalFormHandler] } diff --git a/resources/assets/vue/vuex/modules/voucherUpdates.js b/resources/assets/vue/vuex/modules/voucherUpdates.js new file mode 100644 index 00000000..86495b73 --- /dev/null +++ b/resources/assets/vue/vuex/modules/voucherUpdates.js @@ -0,0 +1,60 @@ +const initialState = { + vouchersCount: localStorage.getItem('voucher-count') || 0, + latestVoucherTimestamp: localStorage.getItem('latest-voucher-timestamp') || null, + lastSeenVoucherTimestamp: localStorage.getItem('last-seen-voucher-timestamp') || null, +}; + +export default { + state: { ...initialState }, + getters: { + getVouchersCount: state => { + return state.vouchersCount; + }, + showVoucherUpdateIndicator: state => { + if (!state.lastSeenVoucherTimestamp && state.latestVoucherTimestamp && state.voucherCount > 0) { + return true; + } + if (!state.latestVoucherTimestamp) { + return false; + } + const latestTime = new Date(state.latestVoucherTimestamp).getTime(); + const lastSeenTime = new Date(state.lastSeenVoucherTimestamp).getTime(); + return latestTime > lastSeenTime; + } + }, + mutations: { + SET_VOUCHER_LATEST_TIMESTAMP(state, timestamp) { + state.latestVoucherTimestamp = timestamp; + }, + SET_VOUCHER_LAST_SEEN_TIMESTAMP(state, timestamp) { + state.lastSeenVoucherTimestamp = timestamp; + }, + SET_VOUCHER_COUNT(state, count) { + state.vouchersCount = count; + }, + RESET_VOUCHER_STATE(state) { + Object.assign(state, initialState); + } + }, + actions: { + updateLatestVoucherTimestamp(store, timestamp){ + localStorage.setItem('latest-voucher-timestamp', timestamp); + store.commit('SET_VOUCHER_LATEST_TIMESTAMP', timestamp); + }, + markVouchersAsSeen(store) { + const latestVoucherTimestamp = store.state.latestVoucherTimestamp; + localStorage.setItem('last-seen-voucher-timestamp', latestVoucherTimestamp); + store.commit('SET_VOUCHER_LAST_SEEN_TIMESTAMP', latestVoucherTimestamp); + }, + updateVoucherCount(store, count){ + localStorage.setItem('voucher-count', count); + store.commit('SET_VOUCHER_COUNT', count); + }, + clearVoucher(store, count){ + localStorage.removeItem('voucher-count'); + localStorage.removeItem('latest-voucher-timestamp'); + localStorage.removeItem('last-seen-voucher-timestamp'); + store.commit('RESET_VOUCHER_STATE'); + }, + } +} diff --git a/resources/assets/vue/vuex/store.js b/resources/assets/vue/vuex/store.js index 907e20e4..2c285d06 100644 --- a/resources/assets/vue/vuex/store.js +++ b/resources/assets/vue/vuex/store.js @@ -7,6 +7,7 @@ import crudRequest from './modules/crudRequest' import crudRequestV2 from './modules/crudRequestV2' import authentication from './modules/authentication' import loadRequestQueue from './modules/loadRequestQueue' +import voucherUpdates from './modules/voucherUpdates' import jobPolling from './modules/jobPolling' Vue.use(Vuex); @@ -20,6 +21,7 @@ export default new Vuex.Store({ crudRequest, crudRequestV2, authentication, - jobPolling + voucherUpdates, + jobPolling, } }) diff --git a/resources/views/layouts/base.blade.php b/resources/views/layouts/base.blade.php index c820242e..c6e645b9 100644 --- a/resources/views/layouts/base.blade.php +++ b/resources/views/layouts/base.blade.php @@ -9,10 +9,6 @@ } - - -
@yield('content') diff --git a/resources/views/pages/billings.blade.php b/resources/views/pages/billings.blade.php index da84f8b9..d1caee2d 100644 --- a/resources/views/pages/billings.blade.php +++ b/resources/views/pages/billings.blade.php @@ -3,7 +3,7 @@
- +
@endsection diff --git a/resources/views/pages/pdfs/currency_vendor_order.blade.php b/resources/views/pages/pdfs/currency_vendor_order.blade.php index 987c42f2..881ca2ca 100644 --- a/resources/views/pages/pdfs/currency_vendor_order.blade.php +++ b/resources/views/pages/pdfs/currency_vendor_order.blade.php @@ -59,7 +59,7 @@ Transfer fee: @php - $transfer_fee = number_format((float)$transferFeeTransactions->sum('service_charge'), 2, '.', ''); + $transfer_fee = number_format(((float)$transferFeeTransactions->sum('service_charge') + (float)($groupTransferFeeOriginalAmount ?? 0)), 2, '.', ''); @endphp {{$transaction->original_currency->short_code}} {{$transfer_fee}} diff --git a/resources/views/partials/header.blade.php b/resources/views/partials/header.blade.php index eaeeaec7..ba1a25ad 100644 --- a/resources/views/partials/header.blade.php +++ b/resources/views/partials/header.blade.php @@ -66,9 +66,10 @@ - +
+ + +
diff --git a/resources/views/vendor/head.blade.php b/resources/views/vendor/head.blade.php index 22a97ead..48a6e17f 100644 --- a/resources/views/vendor/head.blade.php +++ b/resources/views/vendor/head.blade.php @@ -1,11 +1,3 @@ - - - - Exchange - Overseas Money Transfers diff --git a/routes/api.php b/routes/api.php index 6281dbd5..e774dbfb 100644 --- a/routes/api.php +++ b/routes/api.php @@ -17,7 +17,7 @@ Route::group(['middleware' => 'api', 'prefix' => 'v1', 'as' => 'api.'], function require __DIR__ . '/account.php'; -// Route::get('/rate/calculate', 'RateCalculateCurrencyController@convert')->name('calculate'); + // Route::get('/rate/calculate', 'RateCalculateCurrencyController@convert')->name('calculate'); Route::group(['prefix' => 'service', 'as' => 'service.'], function () { Route::get('countries/list', 'Services\CountriesListController@index')->name('list.countries'); @@ -78,12 +78,16 @@ Route::group(['middleware' => 'api', 'prefix' => 'v1', 'as' => 'api.'], function require __DIR__ . '/milestone.php'; - require __DIR__ . '/remark.php'; + require __DIR__ . '/open1688.php'; + + require __DIR__.'/remark.php'; + + // require __DIR__ . '/accounting.php'; //cief todo: To check if this is needed require __DIR__ . '/job.php'; -// require __DIR__ . '/rate.php'; -// require __DIR__ . '/receipt.php'; + // require __DIR__ . '/rate.php'; + // require __DIR__ . '/receipt.php'; }); }); diff --git a/routes/open1688.php b/routes/open1688.php new file mode 100644 index 00000000..93250f21 --- /dev/null +++ b/routes/open1688.php @@ -0,0 +1,8 @@ + 'open1688', 'namespace' => 'Open1688', 'as' => 'open1688.'], function () { + Route::get('/', 'Open1688Controller@keywordSearchProduct')->name('keywordSearchProduct'); + Route::get('/{offer_id}', 'Open1688Controller@getProductDetail')->name('getProductDetail'); +});