mirror of
https://gitlab.com/CIEFWorldwideSdnBhd/exchange-2.0.git
synced 2026-08-21 21:43:57 +00:00
Merge branch 'development' into vapor/development
This commit is contained in:
@@ -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');
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\General\Eloquent\Filters;
|
||||
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class HasActiveRewardForAdmin implements Filter
|
||||
{
|
||||
|
||||
/**
|
||||
* @param Builder $builder
|
||||
* @param $value
|
||||
* @return Builder|mixed
|
||||
*/
|
||||
public static function apply(Builder $builder, $value)
|
||||
{
|
||||
return $builder->where('user_id', $value)
|
||||
->where(function ($query) {
|
||||
$query->whereHas('reward', function ($subquery) {
|
||||
$subquery->where('is_active', true);
|
||||
});
|
||||
// ->orWhereDoesntHave('reward');
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\General\Eloquent\Filters;
|
||||
|
||||
use App\Classes\ValueObjects\Constants\RoleTypes;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class HasVouchersAll implements Filter
|
||||
{
|
||||
|
||||
/**
|
||||
* @param Builder $builder
|
||||
* @param $value
|
||||
* @return 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);
|
||||
});
|
||||
}
|
||||
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');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\General\Open1688;
|
||||
|
||||
class SignatureUtil {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param $path
|
||||
* @param array $parameters
|
||||
* @param RequestPolicy $requestPolicy
|
||||
* @param ClientPolicy $clientPolicy
|
||||
* @return string
|
||||
*/
|
||||
public static function signature($path, array $parameters) {
|
||||
$paramsToSign = array ();
|
||||
foreach ( $parameters as $k => $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;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\General;
|
||||
|
||||
use App\Classes\Exceptions\MalformedRequestException;
|
||||
use App\Classes\General\Open1688\SignatureUtil;
|
||||
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
|
||||
|
||||
class Open1688Helper
|
||||
{
|
||||
|
||||
public static function productSearchKeyword($keyword, $page) {
|
||||
$requestData = [
|
||||
'offerQueryParam' => "{\"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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\Jobs;
|
||||
|
||||
use App\Classes\Modules\Milestones\Processors\MilestoneRewardByTransactionProcessor;
|
||||
use App\Models\Transaction;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class CreateMilestoneRewardByTransactionJob implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
/** @var Transaction */
|
||||
private $transaction;
|
||||
|
||||
/** @var array */
|
||||
private $milestones;
|
||||
|
||||
/**
|
||||
* CreateMilestoneRewardByTransactionJob constructor.
|
||||
* @param Transaction $transaction
|
||||
* @param array $milestones
|
||||
*/
|
||||
public function __construct(Transaction $transaction, array $milestones)
|
||||
{
|
||||
$this->transaction = $transaction;
|
||||
$this->milestones = $milestones;
|
||||
}
|
||||
|
||||
public function handle()
|
||||
{
|
||||
(App()->make(MilestoneRewardByTransactionProcessor::class))->execute($this->transaction, $this->milestones);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)];
|
||||
}
|
||||
|
||||
@@ -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]);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 .'.');
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\Modules\Milestones\Processors;
|
||||
|
||||
|
||||
use App\Classes\Modules\Milestones\Processors\CheckMilestonesForRewardProcessor;
|
||||
use App\Classes\ValueObjects\Constants\ApprovalStatus;
|
||||
use App\Classes\ValueObjects\Constants\Milestones;
|
||||
use App\Models\Booking;
|
||||
use App\Models\Transaction;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class MilestoneRewardByTransactionProcessor
|
||||
{
|
||||
/** @var CheckMilestonesForRewardProcessor */
|
||||
private $checkMilestonesForRewardProcessor;
|
||||
|
||||
/**
|
||||
* MilestoneRewardByTransactionProcessor constructor.
|
||||
* @param CheckMilestonesForRewardProcessor $checkMilestonesForRewardProcessor
|
||||
*/
|
||||
public function __construct(CheckMilestonesForRewardProcessor $checkMilestonesForRewardProcessor)
|
||||
{
|
||||
$this->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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\Modules\Open1688\ControllersLogic;
|
||||
|
||||
use App\Classes\General\Abstracts\AbstractControllerLogic;
|
||||
use App\Classes\General\Open1688Helper;
|
||||
|
||||
use ErrorException;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class GetProductDetailLogic extends AbstractControllerLogic
|
||||
{
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
protected function notification():array {
|
||||
return [
|
||||
'title' => '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]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\Modules\Open1688\ControllersLogic;
|
||||
|
||||
use App\Classes\General\Abstracts\AbstractControllerLogic;
|
||||
use App\Classes\General\Open1688Helper;
|
||||
use App\Http\Resources\WalletResource;
|
||||
|
||||
use ErrorException;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class KeywordSearchProductLogic extends AbstractControllerLogic
|
||||
{
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
protected function notification():array {
|
||||
return [
|
||||
'title' => '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);
|
||||
}
|
||||
}
|
||||
+20
-2
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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-');
|
||||
|
||||
|
||||
@@ -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],
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use App\Classes\Modules\Transactions\ControllersLogic\UpdateGroupLogic;
|
||||
use App\Classes\ValueObjects\Constants\ApprovalStatus;
|
||||
use App\Classes\ValueObjects\Constants\TransactionType;
|
||||
use App\Models\BillGroup;
|
||||
use App\Models\Group;
|
||||
use App\Models\Transaction;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Routing\Route;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Route as FacadesRoute;
|
||||
|
||||
class UpdateBillGroupAndGroupToIncludeTransferFee extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'updateBillGroupAndGroupToIncludeTransferFee';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Update bill group and group to include transfer fee calculation';
|
||||
|
||||
/** @var UpdateGroupLogic */
|
||||
private $updateGroupLogic;
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @param UpdateGroupLogic $updateGroupLogic
|
||||
*/
|
||||
public function __construct(UpdateGroupLogic $updateGroupLogic)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->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}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\SeasonalSegment;
|
||||
use Illuminate\Console\Command;
|
||||
use Carbon\Carbon;
|
||||
use App\Classes\Modules\Companies\Services\RemovesCompanyFromSegment;
|
||||
use App\Classes\ValueObjects\Constants\ApprovalStatus;
|
||||
use App\Classes\ValueObjects\Constants\TransactionType;
|
||||
use App\Models\Group;
|
||||
use App\Models\Transaction;
|
||||
use App\Models\Wallet;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class UpdateGroupWithTransferFee extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'updateGroupWithTransferFee';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Update group with transfer fee';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
ini_set('max_execution_time', 0);
|
||||
set_time_limit(0);
|
||||
$groups = Group::whereDate('updated_at', '<', Carbon::now())->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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Open1688;
|
||||
|
||||
use App\Classes\Modules\Open1688\ControllersLogic\GetProductDetailLogic;
|
||||
use App\Classes\Modules\Open1688\ControllersLogic\KeywordSearchProductLogic;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class Open1688Controller
|
||||
{
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param KeywordSearchProductLogic $logic
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function keywordSearchProduct(Request $request, KeywordSearchProductLogic $logic): JsonResponse {
|
||||
return $logic->execute($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param GetProductDetailLogic $logic
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function getProductDetail(Request $request, GetProductDetailLogic $logic): JsonResponse {
|
||||
return $logic->execute($request);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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' => [
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class ApiResponseTimeLog
|
||||
{
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
// Get route information
|
||||
$route = $request->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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class WebResponseTimeLog
|
||||
{
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
// Get route information
|
||||
$route = $request->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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
|
||||
@@ -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'),
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'app_key' => 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', ''),
|
||||
];
|
||||
@@ -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();
|
||||
// });
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateIndexForTransactionTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('transactions', function (Blueprint $table) {
|
||||
$table->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');
|
||||
});
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -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"
|
||||
|
||||
Vendored
+13
@@ -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,
|
||||
|
||||
+1
-1
@@ -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 [];
|
||||
}
|
||||
|
||||
+2
-1
@@ -10,7 +10,8 @@
|
||||
<div class="row">
|
||||
<div class="col">{{item.owners.pending_verification[0].system}}</div>
|
||||
<div class="col">{{ typeString(item.owners.pending_verification[0].type) }}</div>
|
||||
<div class="col"><a :href="item.owners.pending_verification[0].reference_link" target="_blank">{{item.owners.pending_verification[0].reference}}</a></div>
|
||||
<div class="col" v-if="item.owners.pending_verification[0].system === 'LITE' && typeString(item.owners.pending_verification[0].type) == 'Wallet Top Up'"><a :href="'https://lite.cief-malaysia.com/admin/index.php?route=sale/topup&filter_topup_id=' + item.owners.pending_verification[0].reference" target="_blank">{{item.owners.pending_verification[0].reference}}</a></div>
|
||||
<div class="col" v-else><a :href="item.owners.pending_verification[0].reference_link" target="_blank">{{item.owners.pending_verification[0].reference}}</a></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
+46
-28
@@ -76,26 +76,30 @@
|
||||
</div>
|
||||
|
||||
<!-- filter for Pending Export tab -->
|
||||
<div v-if="stage === 4">
|
||||
<div class="row pt-3 pb-3">
|
||||
<div class="col-5 col-md-3 ">
|
||||
<validation-wrapper-component :validator="$v.parameters.startDate">
|
||||
<label class="all-caps">Start Date</label>
|
||||
<date-picker-component :parameters="parameters" v-model.lazy="parameters.startDate"></date-picker-component>
|
||||
</validation-wrapper-component>
|
||||
</div>
|
||||
<div class="col-5 col-md-3 ">
|
||||
<validation-wrapper-component :validator="$v.parameters.endDate">
|
||||
<label class="all-caps">End Date</label>
|
||||
<date-picker-component :parameters="parameters" v-model.lazy="parameters.endDate"></date-picker-component>
|
||||
</validation-wrapper-component>
|
||||
</div>
|
||||
<div class="col-2 col-md-auto">
|
||||
<div class="btn btn-lg btn-primary fs-11 w-100 h-100 d-flex justify-content-center align-items-center" @click="startMapping(4)">
|
||||
<span>
|
||||
Search
|
||||
</span>
|
||||
</div>
|
||||
<div class="row pt-3 pb-3">
|
||||
<div class="col-5 col-md-3 ">
|
||||
<validation-wrapper-component :validator="$v.parameters.account" selectable>
|
||||
<label class="all-caps">Account</label>
|
||||
<select-component :options="['CIEF WORLDWIDE SDN. BHD. (568603010762)', 'CIEF WORLDWIDE SDN. BHD. AMBANK (8881040198515)']" v-model="parameters.account"></select-component>
|
||||
</validation-wrapper-component>
|
||||
</div>
|
||||
<div class="col-5 col-md-3 ">
|
||||
<validation-wrapper-component :validator="$v.parameters.startDate">
|
||||
<label class="all-caps">Start Date</label>
|
||||
<date-picker-component :parameters="parameters" v-model.lazy="parameters.startDate"></date-picker-component>
|
||||
</validation-wrapper-component>
|
||||
</div>
|
||||
<div class="col-5 col-md-3 ">
|
||||
<validation-wrapper-component :validator="$v.parameters.endDate">
|
||||
<label class="all-caps">End Date</label>
|
||||
<date-picker-component :parameters="parameters" v-model.lazy="parameters.endDate"></date-picker-component>
|
||||
</validation-wrapper-component>
|
||||
</div>
|
||||
<div class="col-2 col-md-auto">
|
||||
<div class="btn btn-lg btn-primary fs-11 w-100 h-100 d-flex justify-content-center align-items-center" @click="startMapping(stage)">
|
||||
<span>
|
||||
Search
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -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}};
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
<template>
|
||||
<div class="row h-100 parentContainer">
|
||||
<div class="col">
|
||||
<a :href="route('rewards')" >
|
||||
<div class="text-white all-caps fs-12">Vouchers</div>
|
||||
<div v-if="showVoucherUpdateIndicator" class="update-indicator"></div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
computed: {
|
||||
showVoucherUpdateIndicator() {
|
||||
return this.$store.getters.showVoucherUpdateIndicator;
|
||||
}
|
||||
},
|
||||
created(){
|
||||
this.submit(this.route('api.voucher.user.list') + '?filters=' + JSON.stringify( { 'has_vouchers_all': true, order_by:{ column:'id', DESC:true }} ), 'get', 'voucherNavigationSection', false, false);
|
||||
},
|
||||
methods: {
|
||||
successHandler(response){
|
||||
this.$store.dispatch('updateLatestVoucherTimestamp', response.payload.data.length > 0 ? response.payload.data[0].created_at : null)
|
||||
.then(() => {
|
||||
this.$store.dispatch('updateVoucherCount', response.payload.data.length);
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
<style>
|
||||
.update-indicator {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
background-color: red;
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
right: 5px;
|
||||
}
|
||||
</style>
|
||||
@@ -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');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
<template>
|
||||
<div class="row p-2 pointer h-100">
|
||||
<div class="col no-padding card btn btn-raised shadow">
|
||||
<img :src="itemDetails.imageUrl" class="w-100" alt="productImg"/>
|
||||
<div class="col p-2 d-flex flex-column">
|
||||
<div class="row align-top">
|
||||
<div class="col">
|
||||
<div class="text-left">{{ itemDetails.subject }}</div>
|
||||
<div class="muted p-t-10 text-left">复购率:{{ itemDetails.repurchaseRate }}</div>
|
||||
<div class="muted text-left">销量:{{ itemDetails.monthSold }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" style="margin-top: auto;">
|
||||
<div class="col">
|
||||
<div class="fs-20 bold text-right" style="color: #ff6000;">¥{{ itemDetails.priceInfo.price }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import componentHandler from '../../../general/mixins/componentHandler';
|
||||
export default {
|
||||
props:{
|
||||
itemDetails: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
mixins: [componentHandler]
|
||||
}
|
||||
</script>
|
||||
@@ -12,11 +12,14 @@
|
||||
<span>{{ item.voucher.code }}</span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span v-if="item.voucher.end_date">
|
||||
<span v-if="item.voucher.end_date && new Date() > new Date(item.voucher.end_date)">
|
||||
This voucher has expired.
|
||||
</span>
|
||||
<span v-else-if="item.voucher.end_date">
|
||||
Valid till {{ item.voucher.end_date }}
|
||||
</span>
|
||||
<span v-else>
|
||||
No expiry date
|
||||
Non-expired
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -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){
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
</div>
|
||||
<div class="row m-b-10">
|
||||
<div class="col p-r-0">
|
||||
<validation-wrapper-component :validator="$v.parameters.fee">
|
||||
<validation-wrapper-component :validator="$v.parameters.group_transfer_fee">
|
||||
<label class="all-caps">Transfer Fee</label>
|
||||
<input type="text" class="form-control" v-model.lazy="parameters.fee" v-money="{decimal: '.',thousands: ',', precision: 2}">
|
||||
<input type="text" class="form-control" v-model.lazy="parameters.group_transfer_fee" v-money="{decimal: '.',thousands: ',', precision: 2}">
|
||||
</validation-wrapper-component>
|
||||
</div>
|
||||
<div class="col-auto b-r b-t b-b b-grey">
|
||||
@@ -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]
|
||||
|
||||
@@ -26,11 +26,14 @@
|
||||
<p v-if="item.voucher.type == 'AMOUNT'">RM{{ item.voucher.value/100 }} Discount</p>
|
||||
<p v-if="item.voucher.type == 'PERCENT'">{{ item.voucher.value }}% Discount</p>
|
||||
</div>
|
||||
<div class="col" v-if="item.voucher.end_date">
|
||||
<div class="col" v-if="item.voucher.end_date && new Date() > new Date(item.voucher.end_date)">
|
||||
This voucher has expired.
|
||||
</div>
|
||||
<div class="col" v-else-if="item.voucher.end_date">
|
||||
Valid till {{ item.voucher.end_date }}
|
||||
</div>
|
||||
<div class="col" v-else>
|
||||
No expiry date
|
||||
Non-expired
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -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){
|
||||
|
||||
@@ -289,6 +289,17 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row m-t-10" v-show="[2, 3].includes(item.status)">
|
||||
<div class="col" v-if="data.booking.company.shipping_company_module_id">
|
||||
<button class="btn btn-sm all-caps b-rad-none btn-success btn-block" @click="trackShipment">Track your shipment</button>
|
||||
</div>
|
||||
<div class="col" v-else>
|
||||
<button class="btn btn-sm all-caps b-rad-none btn-success btn-block requestModal" data-type="connectIzyim">Track your shipment with us</button>
|
||||
<modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in" type="connectIzyim" size="large">
|
||||
<connect-izyim-form-component :data="data" :section="section"></connect-izyim-form-component>
|
||||
</modal-component>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row m-t-10" v-show="[2, 3].includes(item.status) && (totalRequestedRefund + totalRefunds) < data.original_amount">
|
||||
<div class="col" v-if="$store.getters.isAdmin">
|
||||
<button class="btn btn-xs all-caps b-rad-none bg-master-lighter btn-block no-border requestModal" data-type="transferSummary">Request Refund</button>
|
||||
|
||||
+25
-9
@@ -2,7 +2,7 @@
|
||||
<div class="row m-b-10 parentContainer">
|
||||
<div class="col">
|
||||
<loading-component style="height: 200px; top: 0;" key="1" color="success" v-show="isLoading"></loading-component>
|
||||
<div class="row align-items-center pointer p-b-5 b-b b-grey" v-show="!isLoading" @click="activate()">
|
||||
<div class="row align-items-center pointer p-b-5 b-b b-grey" v-show="!isLoading" @click="activate($event)">
|
||||
<div class="col-auto p-r-0">
|
||||
<div class="b-grey b-a fs-10 btn-rounded icon-thumbnail icon-25 m-r-0" :class="[{'bg-primary': active}, {'bg-transparent': !active}]">
|
||||
<i class="fa fa-check text-white fs-12 fa-fw"></i>
|
||||
@@ -87,9 +87,12 @@
|
||||
<button class="btn btn-xs btn-primary b-rad-none requestModal" data-type="editTransactionGroup">
|
||||
Edit Transfer Fee
|
||||
</button>
|
||||
<modal-component small type="editTransactionGroup">
|
||||
<edit-transfer-fee-form-component :section="section" :transfer_fee="item.transfer_fee" :id="item.id"></edit-transfer-fee-form-component>
|
||||
</modal-component>
|
||||
<div class="do-not-activate">
|
||||
<modal-component small type="editTransactionGroup">
|
||||
<edit-transfer-fee-form-component :section="section" :transfer_fee="item.transfer_fee" :id="item.id" :supplier_id="item.issuer_id" :rate="item.currency_rate"></edit-transfer-fee-form-component>
|
||||
</modal-component>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -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){
|
||||
|
||||
@@ -0,0 +1,270 @@
|
||||
<template>
|
||||
<div class="row bg-white p-5 overflow-auto" style="height: 90vh;width: 1200px;">
|
||||
<div class="col">
|
||||
<loading-component style="height: 300px; top: 0;" key="1" color="success" v-if="isLoading"></loading-component>
|
||||
<div class="row justify-content-center" v-if="!isLoading && productInfo">
|
||||
<div class="col-4">
|
||||
<div class="row b-a b-grey">
|
||||
<div class="col" style="min-height: 330px;">
|
||||
<img v-if="!selectedContent.isVideo" :src="selectedContent.link" class="w-100" alt="productImg"/>
|
||||
<video v-else :src="selectedContent.link" style="width: 100%;height: 100%;object-fit: contain;" controls></video>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col no-padding card btn btn-raised shadow" v-if="productInfo.mainVideo">
|
||||
<video :src="productInfo.mainVideo" style="width: 100%;height: 100%;object-fit: contain;" @click="setSelectedContent(productInfo.mainVideo, true)"></video>
|
||||
</div>
|
||||
<div class="col no-padding card btn btn-raised shadow" v-for="image in productInfo.productImage.images" @click="setSelectedContent(image)">
|
||||
<img :src="image" class="w-100" alt="productImg"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-8">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="fs-18">{{ productInfo.subject }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mx-1">
|
||||
<div class="col">
|
||||
<div class="fs-28 bold" style="color: #ff6000;">{{ variantInfo ? "CNY ¥" + variantInfo.price : productInfo.priceRange }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row m-b-20 mx-1" v-for="(selections, key) in productInfo.variants">
|
||||
<div class="col">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="fs-18">
|
||||
{{ key }}:
|
||||
<span class="text-primary"> {{ selectedVariantAttr[key] }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div v-for="selection in selections">
|
||||
<div class="m-1">
|
||||
<button v-if="selection.image" class="col-auto no-padding card btn shadow" :disabled="shouldDisable(key, selection.value)" :class="[{'disabled': shouldDisable(key, selection.value)}, {'b-success': selectedVariantAttr[key] === selection.value}]" @click="onClickAttr(key, selection)">
|
||||
<img :src="selection.image" style="object-fit: cover;width: 65px;height: 65px;border-radius: 3px;" alt="selectionImg"/>
|
||||
</button>
|
||||
<button v-else class="col-auto no-padding card btn btn-raised btn shadow" :disabled="shouldDisable(key, selection.value)" :class="[{'disabled': shouldDisable(key, selection.value)}, {'b-success': selectedVariantAttr[key] === selection.value}]" style="height: 65px;" @click="onClickAttr(key, selection)">
|
||||
<div class="fs-14 text-center px-3" :class="[{'text-success': selectedVariantAttr[key] === selection.value}]" style="margin-top: auto;margin-bottom: auto;">{{ selection.value }}</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="col-12 pl-md-1">
|
||||
<div class="form-group form-group-default b-rad-none no-padding no-border">
|
||||
<div class="row no-margin">
|
||||
<div id="minus-quantity" name="minus-quantity" class="col-auto bg-master-lightest pointer" @click="updateQuantity('minus')">
|
||||
<div class="row h-100 align-items-center">
|
||||
<div class="col">
|
||||
<i class="fa fa-minus"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto no-padding">
|
||||
<label class="p-t-5 p-l-5 text-center">Quantity</label>
|
||||
<input id="quantity" name="quantity" type="text" class="form-control m-b-5 b-rad-none no-border text-center fs-18" v-model.lazy="quantity" v-mask="'#########'"/>
|
||||
</div>
|
||||
<div id="add-quantity" name="add-quantity" class="col-auto bg-master-lightest pointer" @click="updateQuantity('add')">
|
||||
<div class="row h-100 align-items-center">
|
||||
<div class="col">
|
||||
<i class="fa fa-plus"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto d-flex align-items-center muted" v-if="productInfo.variantInfo[this.uniqueVariantKey]">
|
||||
<div class="fs-16">库存: {{ productInfo.variantInfo[this.uniqueVariantKey].amountOnSale }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<button class="btn btn-lg all-caps b-rad-none btn-success btn-block" @click="addToPurchaseOrder()">Add to purchase order</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 tabsContainer b-a b-grey mt-5">
|
||||
<div class="row">
|
||||
<div class="col bg-master-lighter card btn shadow active tabButton padding-15" tab-name="description">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="fs-12 m-t-5 all-caps">商品详情</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col bg-master-lighter card btn shadow tabButton padding-15" tab-name="property">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="fs-12 m-t-5 all-caps">规格参数</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col tabsContainer tabContent active" tab-name="description">
|
||||
<div class="row py-3">
|
||||
<div class="col-12 d-flex justify-content-center" v-if="productInfo.detailVideo">
|
||||
<video :src="productInfo.detailVideo" style="width: 85%;height: 100%;object-fit: contain;" controls></video>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12 d-flex justify-content-center">
|
||||
<div v-html="productInfo.description"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col tabsContainer tabContent hide d-flex justify-content-center" tab-name="property">
|
||||
<table class="w-100 table table-bordered my-3">
|
||||
<tr v-for="(value, key) in productInfo.productAttribute">
|
||||
<td>
|
||||
{{ key }}
|
||||
</td>
|
||||
<td>
|
||||
{{ value }}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import componentHandler from '../../../general/mixins/componentHandler';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
bookingId: {
|
||||
required: true,
|
||||
type: Number
|
||||
}
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
section: 'bookingDetailSection',
|
||||
isLoading: true,
|
||||
isFetchingProduct: true,
|
||||
productInfo: null,
|
||||
priceSection: '',
|
||||
selectedVariantAttr: {},
|
||||
uniqueVariantKey: '',
|
||||
variantInfo: null,
|
||||
selectedContent: {},
|
||||
quantity: 0
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
'data': function() {
|
||||
this.fetchProduct();
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
updateQuantity(type){
|
||||
type === 'add' ? this.quantity++ : this.quantity > 0 ? this.quantity-- : null
|
||||
},
|
||||
setSelectedContent(link, isVideo = false) {
|
||||
this.selectedContent = {
|
||||
link,
|
||||
isVideo
|
||||
}
|
||||
},
|
||||
shouldDisable(key, value) {
|
||||
let combineKey = '';
|
||||
this.productInfo.variantKeyCombinationOrder.forEach((variantKey) => {
|
||||
if (variantKey !== key) {
|
||||
combineKey += this.selectedVariantAttr[variantKey];
|
||||
} else {
|
||||
combineKey += value;
|
||||
}
|
||||
});
|
||||
|
||||
if (combineKey.includes("undefined")) {
|
||||
return false;
|
||||
} else {
|
||||
return this.productInfo.variantInfo[combineKey] ? false : true;
|
||||
}
|
||||
|
||||
},
|
||||
onClickAttr(key, selection) {
|
||||
if (selection.image) {
|
||||
this.setSelectedContent(selection.image)
|
||||
}
|
||||
this.$set(this.selectedVariantAttr, key, selection.value);
|
||||
this.uniqueVariantKey = '';
|
||||
this.productInfo.variantKeyCombinationOrder.forEach((variantKey) => {
|
||||
this.uniqueVariantKey += this.selectedVariantAttr[variantKey];
|
||||
});
|
||||
|
||||
this.variantInfo = this.productInfo.variantInfo[this.uniqueVariantKey];
|
||||
},
|
||||
addToPurchaseOrder() {
|
||||
this.variantInfo = this.productInfo.variantInfo[this.uniqueVariantKey];
|
||||
if (this.variantInfo && this.quantity > 0) {
|
||||
const variantdescription = Object.keys(this.selectedVariantAttr).map((variantKey) => `${variantKey}:${this.selectedVariantAttr[variantKey]}`).join(',')
|
||||
const productDescription = `${this.productInfo.subject}:{${variantdescription}}`;
|
||||
let product = {
|
||||
stockCode: `offerId:${this.productInfo.offerId},skuId:${this.variantInfo.skuId}`,
|
||||
description: productDescription,
|
||||
quantity: this.quantity,
|
||||
unit_price: parseFloat((this.variantInfo.price).toString().replaceAll(',', '')),
|
||||
total: this.quantity * parseFloat((this.variantInfo.price).toString().replace(',', ''))
|
||||
}
|
||||
this.parameters = {
|
||||
products: [product],
|
||||
pushToExisting: true,
|
||||
};
|
||||
|
||||
this.isFetchingProduct = false;
|
||||
this.submit(route('api.transaction.po.create', this.bookingId), 'post', 'bookingDetailSection', true, true);
|
||||
}
|
||||
|
||||
},
|
||||
fetchProduct() {
|
||||
this.isFetchingProduct = true;
|
||||
this.parameters = null;
|
||||
this.isLoading = true;
|
||||
this.submit(route('api.open1688.getProductDetail', this.data.offerId), 'get', 'bookingDetailSection', false, true)
|
||||
},
|
||||
successHandler(response){
|
||||
if (this.isFetchingProduct) {
|
||||
this.productInfo = response.payload.data;
|
||||
this.selectedVariantAttr = {};
|
||||
this.priceSection = response.payload.data.priceRange;
|
||||
this.setSelectedContent(response.payload.data.productImage.images[0])
|
||||
this.uniqueVariantKey = '';
|
||||
this.variantInfo = null;
|
||||
this.quantity = 0;
|
||||
this.isLoading = false;
|
||||
} else {
|
||||
this.closeModal();
|
||||
this.updateList();
|
||||
}
|
||||
|
||||
},
|
||||
errorHandler(error){
|
||||
if (this.isFetchingProduct) {
|
||||
this.productInfo = null;
|
||||
this.selectedVariantAttr = {};
|
||||
this.priceSection = '';
|
||||
this.setSelectedContent({})
|
||||
this.uniqueVariantKey = '';
|
||||
this.variantInfo = null;
|
||||
this.quantity = 0;
|
||||
this.isLoading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
mixins: [componentHandler]
|
||||
|
||||
}
|
||||
</script>
|
||||
@@ -93,8 +93,8 @@
|
||||
</div>
|
||||
<div class="row m-b-20">
|
||||
<div class="col">
|
||||
<p class="no-margin" v-if="serviceType.id === 1">The recipient can expect to receive the transfer within <span class="text-success bold">1-3 working days</span>. Explore our BANK TRANSFER (SAVER) option for a better rate!</p>
|
||||
<p class="no-margin" v-if="serviceType.id === 3">Enjoy a <span class="bold text-underline">better rate</span> with this option! The recipient will receive the transfer after <span class="text-success bold">3-5 working days.</span>.</p>
|
||||
<p class="no-margin" v-if="serviceType.id === 1">The recipient can expect to receive the transfer within <span class="text-success bold">3-5 working days</span>. Explore our BANK TRANSFER (SAVER) option for a better rate!</p>
|
||||
<p class="no-margin" v-if="serviceType.id === 3">Enjoy a <span class="bold text-underline">better rate</span> with this option! The recipient will receive the transfer after <span class="text-success bold">5-7 working days.</span>.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
|
||||
@@ -268,7 +268,8 @@
|
||||
<div class="row m-l-0 m-r-0" v-show="showApplyVoucher" style="height: 20px">
|
||||
<i class="fa fa-spinner fa-spin m-b-5" v-if="voucherIsChecking"></i>
|
||||
<span class="text-danger" v-if="voucherCodeFailedReason">{{ voucherCodeFailedReason }}</span>
|
||||
<span class="text-success" v-if="voucherCodeFailedReason === '' && voucherValidated">Voucher applied</span>
|
||||
<span class="text-success" v-if="voucherCodeFailedReason === '' && voucherValidated && voucherCode.trim()">Voucher applied</span>
|
||||
<span class="text-danger" v-else-if="voucherCodeFailedReason === '' && voucherValidated ">No voucher applied</span>
|
||||
</div>
|
||||
<div class="row m-l-0 m-r-0" v-show="showApplyVoucher">
|
||||
<div class="col">
|
||||
|
||||
@@ -22,7 +22,10 @@
|
||||
<div class="col">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<p class="no-margin bold fs-12">{{product.description}}</p>
|
||||
<a :href="`https://detail.1688.com/offer/${product.offer_id_1688}.html`" target="_blank" v-if="product.item_from_1688">
|
||||
<p class="no-margin bold fs-12">{{product.description}}</p>
|
||||
</a>
|
||||
<p class="no-margin bold fs-12" v-else>{{product.description}}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
<template>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="row p-b-5">
|
||||
<div class="col-auto">
|
||||
<div class="row d-flex align-items-center">
|
||||
<div class="col">
|
||||
<img src="/images/1688_logo.png" alt="" width="40">
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<div class="fs-14 bold all-caps">1688 Product Search</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" @keyup.enter="searchProducts">
|
||||
<div class="col-8">
|
||||
<validation-wrapper-component :validator="$v.keyword">
|
||||
<label class="all-caps">Keyword</label>
|
||||
<input type="text" class="form-control" v-model.lazy="keyword">
|
||||
</validation-wrapper-component>
|
||||
</div>
|
||||
<div class="col-2 d-flex align-items-center justify-content-center mt-2 mt-md-0">
|
||||
<button type="button" class="btn btn-lg btn-primary fs-11 w-100 d-block mr-2 mr-md-0" @click="searchProducts()">Search</button>
|
||||
</div>
|
||||
<div class="col-2 d-flex align-items-center justify-content-center mt-2 mt-md-0">
|
||||
<button type="button" class="btn btn-lg btn-primary fs-11 w-100 d-block mr-2 mr-md-0" @click="showProductList = !showProductList">{{ showProductList ? "Hide" : "Show" }} Section</button>
|
||||
</div>
|
||||
</div>
|
||||
<div v-show="showProductList">
|
||||
<div class="row">
|
||||
<div class="col-12" style="min-height: 20px;" v-show="isLoading">
|
||||
<loading-component style="height: 470px; top: 0;" key="1" color="success"></loading-component>
|
||||
</div>
|
||||
<div class="col-12 m-t-10" v-show="products.length === 0 && !isLoading">
|
||||
<div class="row align-items-center justify-content-center hint-text">
|
||||
<div class="col-4 hint-text"><img src="/images/not-found-illustration.png" class="w-100 hint-text"/></div>
|
||||
</div>
|
||||
<div class="row text-center">
|
||||
<div class="col">
|
||||
<div class="row m-t-20">
|
||||
<div class="col">
|
||||
<p class="all-caps no-margin fs-11" style="letter-spacing: 2px;">Nothing To Show Here</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row m-t-5 align-items-center justify-content-center">
|
||||
<div class="col">
|
||||
<small class="fs-9 muted all-caps font-lato" style="letter-spacing: 2px">There is no results found, Try adjusting your filters to find what you are looking for.</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col" v-show="products.length > 0">
|
||||
<div class="row" style="padding-left: 15px;padding-right: 15px;">
|
||||
<div class="col-lg-2 col-md-3 col-sm-6 requestModal" data-type="alibabaProduct" @click="selectedProduct=product" v-for="product in products">
|
||||
<alibaba-product-overview-component :itemDetails="product"></alibaba-product-overview-component>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in" type="alibabaProduct">
|
||||
<alibaba-product-detail-form-component :data="selectedProduct" :bookingId="bookingId" section="alibabaProductDetailSection"></alibaba-product-detail-form-component>
|
||||
</modal-component>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" v-if="products.length > 0">
|
||||
<div class="col-12 p-t-20 d-flex align-items-center justify-content-center">
|
||||
<nav>
|
||||
<ul class="pagination">
|
||||
<li class="page-item pointer" @click="setPage(1)">
|
||||
<div class="page-link" aria-label="Previous">
|
||||
<span aria-hidden="true">«</span>
|
||||
<span class="sr-only">Previous</span>
|
||||
</div>
|
||||
</li>
|
||||
<li class="page-item pointer" @click="setPage(currentPage - 2)"><div class="page-link" v-if="currentPage === totalPage">{{ currentPage - 2 }}</div></li>
|
||||
<li class="page-item pointer" @click="setPage(currentPage - 1)"><div class="page-link" v-if="currentPage - 1 > 0">{{ currentPage - 1 }}</div></li>
|
||||
<li class="page-item pointer active" @click="setPage(currentPage)"><div class="page-link">{{ currentPage }}</div></li>
|
||||
<li class="page-item pointer" @click="setPage(currentPage + 1)"><div class="page-link" v-if="currentPage !== totalPage">{{ currentPage + 1 }}</div></li>
|
||||
<li class="page-item pointer" @click="setPage(currentPage + 2)"><div class="page-link" v-if="currentPage === 1">{{ currentPage + 2 }}</div></li>
|
||||
<li class="page-item pointer" @click="setPage(totalPage)">
|
||||
<div class="page-link" aria-label="Next">
|
||||
<span aria-hidden="true">»</span>
|
||||
<span class="sr-only">Next</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { required } from "vuelidate/lib/validators";
|
||||
|
||||
export default {
|
||||
props: {
|
||||
bookingId: {
|
||||
required: true,
|
||||
type: Number
|
||||
}
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
keyword: '',
|
||||
isLoading: false,
|
||||
products: [],
|
||||
currentPage: 1,
|
||||
totalPage: 0,
|
||||
selectedProduct: null,
|
||||
showProductList: false,
|
||||
}
|
||||
},
|
||||
validations: {
|
||||
keyword: {
|
||||
required
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
setPage(newPage) {
|
||||
this.currentPage = newPage;
|
||||
this.searchProducts()
|
||||
},
|
||||
searchProducts(){
|
||||
if (this.keyword) {
|
||||
this.showProductList = true;
|
||||
this.products = [];
|
||||
this.isLoading = true;
|
||||
}
|
||||
this.submit(route('api.open1688.keywordSearchProduct') + '?page=' + this.currentPage + '&keyword=' + this.keyword, 'get', 'alibabaSiteSection', false, true);
|
||||
},
|
||||
successHandler(response){
|
||||
this.isLoading = false;
|
||||
this.totalPage = response.payload.totalPage;
|
||||
if (response.payload.totalRecords > 0) {
|
||||
this.products = response.payload.data;
|
||||
}
|
||||
},
|
||||
errorHandler(error){
|
||||
this.isLoading = false;
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
+7
-1
@@ -110,10 +110,15 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" v-if='booking.service.id === 4'>
|
||||
<div class="col">
|
||||
<alibaba-site-section-component :bookingId="booking.id"></alibaba-site-section-component>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12 col-sm-12 col-md">
|
||||
<div class="row no-margin relative b-b b-dashed b-grey">
|
||||
<div class="absolute" style="top: -5px;right: -5px;width: 0px;height: 0px;border-style: solid;border-width: 0px 80px 80px 0px;border-color: transparent rgb(249, 249, 249) transparent transparent;z-index: 2;"></div>
|
||||
<div class="absolute" style="top: 0;right: -5px;width: 0px;height: 0px;border-style: solid;border-width: 0px 80px 80px 0px;border-color: transparent rgb(249, 249, 249) transparent transparent;z-index: 2;"></div>
|
||||
<div class="absolute shadow-sm " style="top: 0px; right: 0px; width: 0px; height: 0px; border-style: solid; border-width: 70px 0px 0px 70px; border-color: transparent transparent transparent rgb(255, 255, 255); z-index: 1;"></div>
|
||||
<div class="col bg-white padding-25">
|
||||
<div class="row">
|
||||
@@ -460,6 +465,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="col col-sm-12 col-md-3">
|
||||
<vouchers-summary-component></vouchers-summary-component>
|
||||
<wallet-component class="m-b-20" :data="booking.company"></wallet-component>
|
||||
<verification-warning-component :data="booking.company"></verification-warning-component>
|
||||
</div>
|
||||
|
||||
+4
-1
@@ -48,7 +48,7 @@
|
||||
<div class="col">
|
||||
<list-component :key="currencyOrderKey" section="transactionGroupsListPaymentSection" :options="{'per_page': 20, 'without_bill_group': true, 'issuer_in': [this.selectedSupplier.id]}" :endpoint="route('api.transaction.group.list')">
|
||||
<template slot="list" slot-scope="{data}">
|
||||
<transaction-group-payment-component section="transactionGroupsListPaymentSection" :data="data" :payments="payments" v-on:input="updateOrder($event)"></transaction-group-payment-component>
|
||||
<transaction-group-payment-component section="transactionGroupsListPaymentSection" :data="data" :payments="payments" v-on:input="updateOrder($event)" :emptyPaymentList="emptyPaymentList"></transaction-group-payment-component>
|
||||
</template>
|
||||
</list-component>
|
||||
</div>
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
+4
-4
@@ -117,16 +117,16 @@
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<!-- <list-component ref="pendingOrdersList" section="pendingOrdersSection" :endpoint="route('api.transaction.list')" :options="{per_page: 5, status: 2, owner_type: 'App\\Models\\Booking', type: 1, original_currency_id_in: [selectedCurrency.id], transaction_service_id: selectedService.id, does_not_have_refund_in_progress: true}">
|
||||
<list-component ref="pendingOrdersList" section="pendingOrdersSection" :endpoint="route('api.transaction.list')" :options="{per_page: 5, status: 2, owner_type: 'App\\Models\\Booking', type: 1, original_currency_id_in: [selectedCurrency.id], transaction_service_id: selectedService.id, does_not_have_refund_in_progress: true}">
|
||||
<template slot="list" slot-scope="{data}">
|
||||
<supplier-pending-order-component :data="data" v-on:input="updateOrder($event)"></supplier-pending-order-component>
|
||||
</template>
|
||||
</list-component> -->
|
||||
<list-polling-component ref="pendingOrdersList" section="pendingOrdersSection" :endpoint="route('api.transaction.list.job')" :options="{per_page: 5, status: 2, owner_type: 'App\\Models\\Booking', type: 1, original_currency_id_in: [selectedCurrency.id], transaction_service_id: selectedService.id, does_not_have_refund_in_progress: true}">
|
||||
</list-component>
|
||||
<!-- <list-polling-component ref="pendingOrdersList" section="pendingOrdersSection" :endpoint="route('api.transaction.list.job')" :options="{per_page: 5, status: 2, owner_type: 'App\\Models\\Booking', is_not_fully_refunded: true, type: 1, original_currency_id_in: [selectedCurrency.id], transaction_service_id: selectedService.id}">
|
||||
<template slot="list" slot-scope="{data}">
|
||||
<supplier-pending-order-component :data="data" v-on:input="updateOrder($event)"></supplier-pending-order-component>
|
||||
</template>
|
||||
</list-polling-component>
|
||||
</list-polling-component> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+4
-1
@@ -17,11 +17,14 @@
|
||||
<p v-if="item.voucher && item.voucher.is_redeemed">
|
||||
Voucher claimed
|
||||
</p>
|
||||
<p v-else-if="item.voucher.end_date && new Date() > new Date(item.voucher.end_date)">
|
||||
This voucher has expired.
|
||||
</p>
|
||||
<p v-else-if="item.voucher && item.voucher.end_date">
|
||||
Valid till {{ item.voucher.end_date }}
|
||||
</p>
|
||||
<p v-else>
|
||||
-
|
||||
Non-expired
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+1
@@ -201,6 +201,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-lg-3">
|
||||
<vouchers-summary-component></vouchers-summary-component>
|
||||
<wallet-component :data="company"></wallet-component>
|
||||
<verification-warning-component v-if="!isLoading" :data="company"></verification-warning-component>
|
||||
<new-service-announcement-component :data="company"></new-service-announcement-component>
|
||||
|
||||
+2
-1
@@ -141,6 +141,7 @@
|
||||
<div class="col">
|
||||
<div class="row">
|
||||
<div class="col m-b-15">
|
||||
<vouchers-summary-admin-component v-if="company" :company="company"></vouchers-summary-admin-component>
|
||||
<wallet-component :data="company" :creditable=true></wallet-component>
|
||||
</div>
|
||||
</div>
|
||||
@@ -213,4 +214,4 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</script>
|
||||
|
||||
+7
-2
@@ -52,7 +52,7 @@
|
||||
<div class="col">
|
||||
<div class="row">
|
||||
<div class="col" v-if="this.$store.getters.getUserId">
|
||||
<list-component section="customerVouchersListSection" :endpoint="route('api.voucher.user.list')" :options="{ 'has_active_reward': id }">
|
||||
<list-component section="customerVouchersListSection" :endpoint="route('api.voucher.user.list')" :options="{ 'has_vouchers_all': id }">
|
||||
<template slot="list" slot-scope="{data}">
|
||||
<single-user-reward-item-component :data="data"></single-user-reward-item-component>
|
||||
</template>
|
||||
@@ -69,10 +69,15 @@
|
||||
<div class="col">
|
||||
<div class="row">
|
||||
<div class="col" v-if="this.$store.getters.getUserId">
|
||||
<list-component section="customerRewardsListSection" :endpoint="route('api.reward.list.details.admin', id)" :options="{'is_active': true, order_by:{ column:'order', DESC:false}}">
|
||||
<!-- <list-component section="customerRewardsListSection" :endpoint="route('api.reward.list.details.admin', id)" :options="{'is_active': true, order_by:{ column:'order', DESC:false}}">
|
||||
<template slot="list" slot-scope="{data}">
|
||||
<single-reward-details-item-component :data="data"></single-reward-details-item-component>
|
||||
</template>
|
||||
</list-component> -->
|
||||
<list-component section="customerRewardsListSection" :endpoint="route('api.voucher.user.list')" :options="{'has_active_reward_for_admin': id}">
|
||||
<template slot="list" slot-scope="{data}">
|
||||
<single-user-reward-item-component :data="data"></single-user-reward-item-component>
|
||||
</template>
|
||||
</list-component>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+15
-6
@@ -19,7 +19,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col m-r-5 d-none d-md-inline">
|
||||
<!-- <div class="col m-r-5 d-none d-md-inline">
|
||||
<div class="row fs-12 text-center">
|
||||
<div class="col p-t-20 p-b-20 bg-master-lighter tabButton" tab-name="rewards">
|
||||
<div class="row">
|
||||
@@ -29,7 +29,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
<div class="col m-r-5 d-none d-md-inline">
|
||||
<div class="row fs-12 text-center">
|
||||
<div class="col p-t-20 p-b-20 bg-master-lighter tabButton" tab-name="used">
|
||||
@@ -52,7 +52,7 @@
|
||||
<div class="col">
|
||||
<div class="row">
|
||||
<div class="col" v-if="this.$store.getters.getUserId">
|
||||
<list-component section="customerVouchersListSection" :endpoint="route('api.voucher.user.list')" :options="{ 'has_active_reward': true }">
|
||||
<list-component section="customerVouchersListSection" :endpoint="route('api.voucher.user.list')" :options="{ 'has_vouchers_all': true }">
|
||||
<template slot="list" slot-scope="{data}">
|
||||
<single-user-reward-item-component :data="data"></single-user-reward-item-component>
|
||||
</template>
|
||||
@@ -69,11 +69,16 @@
|
||||
<div class="col">
|
||||
<div class="row">
|
||||
<div class="col" v-if="this.$store.getters.getUserId">
|
||||
<list-component section="customerRewardsListSection" :endpoint="route('api.reward.list.details')" :options="{'is_active': true, order_by:{ column:'order', DESC:false}}">
|
||||
<!-- <list-component section="customerRewardsListSection" :endpoint="route('api.reward.list.details')" :options="{'is_active': true, order_by:{ column:'order', DESC:false}}">
|
||||
<template slot="list" slot-scope="{data}">
|
||||
<single-reward-details-item-component :data="data"></single-reward-details-item-component>
|
||||
</template>
|
||||
</list-component>
|
||||
</list-component> -->
|
||||
<!-- <list-component section="customerRewardsListSection" :endpoint="route('api.voucher.user.list')" :options="{'has_active_reward': true}">
|
||||
<template slot="list" slot-scope="{data}">
|
||||
<single-user-reward-item-component :data="data"></single-user-reward-item-component>
|
||||
</template>
|
||||
</list-component> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -108,5 +113,9 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {}
|
||||
export default {
|
||||
created(){
|
||||
this.$store.dispatch('markVouchersAsSeen');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
<template>
|
||||
<div class="row parentContainer" style="margin-bottom: 8px;">
|
||||
<div class="col">
|
||||
<div class="bg-complete">
|
||||
<div class="row align-items-end" style="padding: 8px 25px;">
|
||||
<div class="col-auto">
|
||||
<a :href="route('customer.reward', company.reference)" target="_blank">
|
||||
<i class="fa fa-spinner fa-spin m-b-5 text-white" v-show="$store.getters.isLoading(section)"></i>
|
||||
<div v-show="!$store.getters.isLoading(section)" class="text-primary-lighter fs-10 text-uppercase">Vouchers: <span class="text-white no-margin bold">{{ vouchersCount }}</span><i class="fa fa-external-link text-white m-l-10"></i></div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
company: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
section: 'customerVouchersSummaryAdminSection',
|
||||
vouchersCount: 0,
|
||||
}
|
||||
},
|
||||
created(){
|
||||
this.submit(this.route('api.voucher.user.list') + '?filters=' + JSON.stringify( { 'has_vouchers_all': this.company.employee.id, order_by:{ column:'id', DESC:true }} ), 'get', this.section, false, false);
|
||||
},
|
||||
methods: {
|
||||
successHandler(response){
|
||||
this.vouchersCount = response.payload.data.length;
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
<template>
|
||||
<div class="row parentContainer" style="margin-bottom: 8px;">
|
||||
<div class="col">
|
||||
<div class="bg-complete">
|
||||
<div class="row align-items-end" style="padding: 8px 25px;">
|
||||
<div class="col-auto">
|
||||
<a :href="route('rewards')" >
|
||||
<div class="text-primary-lighter fs-10 text-uppercase">Vouchers: <span class="text-white no-margin bold">{{ vouchersCount }}</span></div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
computed: {
|
||||
vouchersCount() {
|
||||
return this.$store.getters.getVouchersCount;
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -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]
|
||||
}
|
||||
|
||||
@@ -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');
|
||||
},
|
||||
}
|
||||
}
|
||||
Vendored
+3
-1
@@ -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,
|
||||
}
|
||||
})
|
||||
|
||||
@@ -9,10 +9,6 @@
|
||||
}
|
||||
</style>
|
||||
<body class="horizontal-menu horizontal-app-menu bg-master-lightest overflow-hidden">
|
||||
<!-- Google Tag Manager (noscript) -->
|
||||
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-TQKCPCD"
|
||||
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
|
||||
<!-- End Google Tag Manager (noscript) -->
|
||||
<div id="app" style="min-height: 100%;">
|
||||
<div id="grecaptcha_container"></div>
|
||||
@yield('content')
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<div class="row" v-if="$store.getters.isAdmin">
|
||||
<div class="col p-t-15 p-b-15">
|
||||
<billing-component></billing-component>
|
||||
<admin-payments-billing-section-component></admin-payments-billing-section-component>
|
||||
<admin-payments-billing-section-polling-component></admin-payments-billing-section-polling-component>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
<tr>
|
||||
<td width="70%" style="text-align: right;">Transfer fee: </td>
|
||||
@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
|
||||
<td>{{$transaction->original_currency->short_code}} {{$transfer_fee}}</td>
|
||||
</tr>
|
||||
|
||||
@@ -66,9 +66,10 @@
|
||||
<div v-if="$store.getters.isCustomer" class="col-auto p-r-20">
|
||||
<a href="{{route('banks')}}"><div class="text-white all-caps fs-12">Bank Accounts</div></a>
|
||||
</div>
|
||||
<!-- <div v-if="$store.getters.isCustomer" class="col-auto p-r-20">
|
||||
<a href="{{route('rewards')}}"><div class="text-white all-caps fs-12">Vouchers</div></a>
|
||||
</div> -->
|
||||
<div v-if="$store.getters.isCustomer" class="col-auto p-r-20">
|
||||
<vouchers-navigation-bar-component></vouchers-navigation-bar-component>
|
||||
<!-- <a href="{{route('rewards')}}"><div class="text-white all-caps fs-12">Vouchers</div></a> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
-8
@@ -1,11 +1,3 @@
|
||||
<!-- Google Tag Manager -->
|
||||
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
|
||||
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
|
||||
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
|
||||
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
|
||||
})(window,document,'script','dataLayer','GTM-TQKCPCD');</script>
|
||||
<!-- End Google Tag Manager -->
|
||||
<script>window.LARAVEL_VAPOR_ENABLED=@json(env('LARAVEL_VAPOR_ENABLED', false));</script>
|
||||
<meta http-equiv="content-type" content="text/html;charset=UTF-8"/>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Exchange - Overseas Money Transfers</title>
|
||||
|
||||
+8
-4
@@ -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';
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::group(['prefix' => 'open1688', 'namespace' => 'Open1688', 'as' => 'open1688.'], function () {
|
||||
Route::get('/', 'Open1688Controller@keywordSearchProduct')->name('keywordSearchProduct');
|
||||
Route::get('/{offer_id}', 'Open1688Controller@getProductDetail')->name('getProductDetail');
|
||||
});
|
||||
Reference in New Issue
Block a user