Merge branch 'master' of gitlab.com:CIEFWorldwideSdnBhd/exchange-2.0 into supplier-bill-group-dashboard

This commit is contained in:
edmondlang
2024-04-02 11:53:43 +08:00
49 changed files with 513 additions and 49 deletions
@@ -69,7 +69,7 @@ abstract class AbstractControllerLogic
} catch (ErrorException|GeneralExceptions $exception){
if ($exception instanceof JobResourceNotFoundException) {
Log::error(sprintf(
Log::channel('vue_polling')->info(sprintf(
"Uncaught exception '%s' with message '%s' in %s:%d",
get_class($exception),
$exception->getMessage(),
@@ -0,0 +1,12 @@
<?php
namespace App\Classes\General\Interfaces;
use Illuminate\Database\Eloquent\Relations\MorphMany;
interface KeyValueInterface
{
public function attributes(): morphMany;
}
@@ -0,0 +1,70 @@
<?php
namespace App\Classes\Jobs;
use App\Classes\Modules\Accounts\DataTransferObjects\KeyValuePairObject;
use App\Classes\Modules\Accounts\Services\CreatesKeyValuePair;
use App\Classes\Notifications\WelcomeVoucherEmail;
use App\Models\User;
use App\Models\Voucher;
use Carbon\Carbon;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class SendWelcomeVoucherEmail implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/** @var User */
private $user;
/** @var Voucher */
private $voucher;
/** @var int */
private $emailSentCount;
/**
* SendWelcomeVoucherEmail constructor.
* @param User $user
* @param Voucher $voucher
* @param int $emailSentCount
*/
public function __construct(User $user, Voucher $voucher, int $emailSentCount = 1)
{
$this->user = $user;
$this->voucher = $voucher;
$this->emailSentCount = $emailSentCount;
}
public function handle()
{
$currentDatetime = Carbon::now();
$dateToCompare = Carbon::parse($this->voucher->end_date);
if (!$this->user->hasAttribute($this->voucher->code."_EMAIL_COUNT")
&& $this->user->rewards->where('voucher_id', $this->voucher->id)->count() > 0
&& $currentDatetime->isBefore($dateToCompare))
{
//Key #1
$keyValuePairObject = new KeyValuePairObject(
$this->voucher->code."_EMAIL_COUNT",
$this->emailSentCount
);
(App()->make(CreatesKeyValuePair::class))->execute($this->user, $keyValuePairObject);
//Key #2
$keyValuePairObject = new KeyValuePairObject(
$this->voucher->code."_EMAIL_DATE_".$this->emailSentCount,
Carbon::now()
);
(App()->make(CreatesKeyValuePair::class))->execute($this->user, $keyValuePairObject);
$this->user->notify(new WelcomeVoucherEmail($this->user, $this->voucher));
}
}
}
+3 -4
View File
@@ -57,16 +57,15 @@ class UpdatePerfexCRMInvoice implements ShouldQueue
$number = 'EXC-'.$number;
$invoice = (App()->make(FetchesPerfexCRMInvoice::class))->execute($customer->userid,"INV-", $number);
Log::error(json_encode('UpdatePerfexCRMInvoice debug $number: '.$number));
Log::channel('perfex_crm')->info(('UpdatePerfexCRMInvoice debug $number: '.$number));
if(is_null($invoice)){
$result = (App()->make(CreatePerfexCRMInvoiceProcessor::class))->execute($transaction);
if ($result) {
$invoiceId = $result->payload['id'];
} else {
// Log::error(json_encode('UpdatePerfexCRMInvoice CreatePerfexCRMInvoiceProcessor failed'));
$log['message'] = 'UpdatePerfexCRMInvoice CreatePerfexCRMInvoiceProcessor failed';
Helper::debugLogger($log);
Log::channel('perfex_crm')->info($log);
}
}
else{
@@ -75,7 +74,7 @@ class UpdatePerfexCRMInvoice implements ShouldQueue
//This only run when invoice already exist and the invoice does not have a PAID status
if($invoiceStatus != PerfexCRMInvoiceStatus::PAID){
Log::error(json_encode('UpdatePerfexCRMInvoice debug $this->updatePerfexCRMInvoiceObject->getProjectId(): '.$this->updatePerfexCRMInvoiceObject->getProjectId()));
Log::channel('perfex_crm')->info('UpdatePerfexCRMInvoice debug $this->updatePerfexCRMInvoiceObject->getProjectId(): '.$this->updatePerfexCRMInvoiceObject->getProjectId());
//update invoice
(App()->make(UpdatesPerfexCRMInvoice::class))->execute($invoice, $this->updatePerfexCRMInvoiceObject->getProjectId());
@@ -30,6 +30,7 @@ use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
use App\Classes\Modules\Segments\Services\CreatesSeasonalSegment;
use App\Classes\ValueObjects\Constants\Vouchers;
class CreateCustomerLogic extends AbstractControllerLogic
{
@@ -159,7 +160,7 @@ class CreateCustomerLogic extends AbstractControllerLogic
$this->newCustomerToVoucherifyProcessor->execute($company->id, $user, true);
$this->createVoucherProcessor->execute($user, 'WELCOME50%OFF');
$this->createVoucherProcessor->execute($user, Vouchers::WELCOME_50_PERCENT_OFF);
return $this->response($this->authenticationProcessor->execute($request, false));
@@ -9,6 +9,9 @@ use App\Classes\Modules\Accounts\Services\CompletesEmailVerificationAttempt;
use App\Classes\Modules\Accounts\Services\FetchesEmailVerificationAttempt;
use App\Classes\Modules\Accounts\Services\VerifiesUser;
use App\Classes\Modules\Accounts\Standards\Criteria\EmailVerificationActiveAttemptExists;
use App\Classes\Modules\Vouchers\Services\FetchesVoucher;
use App\Classes\Jobs\SendWelcomeVoucherEmail;
use App\Classes\ValueObjects\Constants\Vouchers;
use App\Models\UserEmailVerification;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
@@ -36,19 +39,29 @@ class UserEmailVerificationLogic extends AbstractControllerLogic
/** @var VerifiesUser */
private $verifiesUser;
/** @var SendWelcomeVoucherEmail */
private $sendWelcomeVoucherEmail;
/** @var FetchesVoucher */
private $fetchesVoucher;
/**
* UserEmailVerificationLogic constructor.
* @param EmailVerificationActiveAttemptExists $emailVerificationActiveAttemptExists
* @param CompletesEmailVerificationAttempt $completesEmailVerificationAttempt
* @param FetchesEmailVerificationAttempt $fetchesEmailVerificationAttempt
* @param VerifiesUser $verifiesUser
* @param SendWelcomeVoucherEmail $sendWelcomeVoucherEmail
* @param FetchesVoucher $fetchesVoucher
*/
public function __construct(EmailVerificationActiveAttemptExists $emailVerificationActiveAttemptExists, CompletesEmailVerificationAttempt $completesEmailVerificationAttempt, FetchesEmailVerificationAttempt $fetchesEmailVerificationAttempt, VerifiesUser $verifiesUser)
public function __construct(EmailVerificationActiveAttemptExists $emailVerificationActiveAttemptExists, CompletesEmailVerificationAttempt $completesEmailVerificationAttempt, FetchesEmailVerificationAttempt $fetchesEmailVerificationAttempt, VerifiesUser $verifiesUser, SendWelcomeVoucherEmail $sendWelcomeVoucherEmail, FetchesVoucher $fetchesVoucher)
{
$this->emailVerificationActiveAttemptExists = $emailVerificationActiveAttemptExists;
$this->completesEmailVerificationAttempt = $completesEmailVerificationAttempt;
$this->fetchesEmailVerificationAttempt = $fetchesEmailVerificationAttempt;
$this->verifiesUser = $verifiesUser;
$this->sendWelcomeVoucherEmail = $sendWelcomeVoucherEmail;
$this->fetchesVoucher = $fetchesVoucher;
}
/**
@@ -68,9 +81,19 @@ class UserEmailVerificationLogic extends AbstractControllerLogic
$this->completesEmailVerificationAttempt->execute($attempt);
$this->verifiesUser->execute($attempt->user);
$user = $attempt->user;
$this->verifiesUser->execute($user);
// if (env('SENDING_EMAIL_WELCOME_VOUCHER_ENABLED', false)){
if (app()->environment('production') && env('SENDING_EMAIL_WELCOME_VOUCHER_ENABLED', false)){
try{ //In case voucher got deleted unintentionally
$voucher = $this->fetchesVoucher->execute(['code' => Vouchers::WELCOME_50_PERCENT_OFF]);
if($voucher) $this->sendWelcomeVoucherEmail::dispatch($user, $voucher, 1);
}
catch(\Exception $e){}
}
return $this->response([]);
}
}
}
@@ -0,0 +1,44 @@
<?php
namespace App\Classes\Modules\Accounts\DataTransferObjects;
use App\Classes\General\Interfaces\DataTransferObject;
class KeyValuePairObject implements DataTransferObject
{
/** @var string */
private $key;
/** @var string */
private $value;
/**
* KeyValuePairObject constructor.
* @param string $key
* @param string $value
*/
public function __construct(string $key, string $value)
{
$this->key = $key;
$this->value = $value;
}
/**
* @return string
*/
public function getKey(): string
{
return $this->key;
}
/**
* @return string
*/
public function getValue(): string
{
return $this->value;
}
}
@@ -0,0 +1,28 @@
<?php
namespace App\Classes\Modules\Accounts\Services;
use App\Classes\General\Eloquent\AbstractUpdateRelationshipRecord;
use App\Classes\General\Interfaces\KeyValueInterface;
use App\Classes\Modules\Accounts\DataTransferObjects\KeyValuePairObject;
use App\Models\KeyValuePair;
class CreatesKeyValuePair extends AbstractUpdateRelationshipRecord
{
/**
* @param KeyValueInterface $kv
* @param KeyValuePairObject $object
* @return \Illuminate\Database\Eloquent\Model
* @throws \App\Classes\Exceptions\MalformedRequestException
*/
public function execute(KeyValueInterface $kv, KeyValuePairObject $object) {
$model = new KeyValuePair();
$model->key = $object->getKey();
$model->value = $object->getValue();
return $this->handler($kv->attributes(), $model);
}
}
@@ -45,7 +45,7 @@ class ExpireBookingPaymentControllerLogic extends AbstractControllerLogic
$booking = $this->fetchesBooking->execute(['id' => $request->route('id')]);
$payment = $booking->transactions()
->payments()->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])
->payments()->whereIn('status', [ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])
->first();
$payment->status = ApprovalStatus::EXPIRED;
@@ -62,7 +62,7 @@ class ListBookingJobLogic extends AbstractControllerLogic
$userInfo
);
ListBookingsJob::dispatch($listGenericJobObject);
ListBookingsJob::dispatch($listGenericJobObject)->onQueue('high_priority');
$result = [];
$result['job_id'] = $jobId;
@@ -63,7 +63,7 @@ class ListDocumentJobLogic extends AbstractControllerLogic
$userInfo
);
ListDocumentsJob::dispatch($listGenericJobObject);
ListDocumentsJob::dispatch($listGenericJobObject)->onQueue('high_priority');
$result = [];
$result['job_id'] = $jobId;
@@ -108,12 +108,12 @@ class CreatePerfexCRMInvoiceProcessor
$email = null;
if ($firstSupplier) {
$email = $firstSupplier->email;
Log::error('CreatePerfexCRMInvoiceProcessor debug:'.$email);
Log::channel('perfex_crm')->info('CreatePerfexCRMInvoiceProcessor debug:'.$email);
} else {
$bookingMarking = $transaction->owner->marking;
$serviceTypeName = $transaction->owner->company->services()->where('id', $transaction->owner->service_id)->first()->name;
$projectName = 'Exchange | '.$serviceTypeName.' | '.$bookingMarking;
Log::error('$projectName: '.$projectName);
Log::channel('perfex_crm')->info('$projectName: '.$projectName);
return $email;
}
@@ -62,7 +62,7 @@ class FetchPerfexCRMInvoiceProcessor
$invoiceId = $result->payload['id'];
} else {
$log['message'] = 'FetchPerfexCRMInvoiceProcessor failed for transaction > bill_no: '.$number;
Helper::debugLogger($log);
Log::channel('perfex_crm')->info($log);
}
}
else{
@@ -217,8 +217,8 @@ class UpdatePerfexCRMProcessor
}
$result = $this->fetchesPerfexCRMTask->execute($taskName, $milestoneId, 'project', $projectId, $updatePerfexCRMObject->getInvoiceId());
// Log::error("UpdatePerfexCRMProcessor task: ".$taskName." , ".json_encode($result));
Log::error("UpdatePerfexCRMProcessor task: ".$taskName);
// Log::channel('perfex_crm')->info("UpdatePerfexCRMProcessor task: ".$taskName." , ".json_encode($result));
Log::channel('perfex_crm')->info("UpdatePerfexCRMProcessor task: ".$taskName);
if(isset($result->payload)){
//&& $result->payload[0]['status'] == PerfexCRMTaskStatus::NOT_STARTED
@@ -24,7 +24,7 @@ class ConvertsPerfexCRMLeadToCustomer
return (object) $data;
}else{
Log::error($response);
Log::channel('perfex_crm')->info($response);
return null;
}
}catch(\Exception $exception){
@@ -27,7 +27,7 @@ class CreatesPerfexCRMCustomer
$data = $response->json();
return (object) $data;
}else{
Log::error($response);
Log::channel('perfex_crm')->info($response);
return null;
}
}catch(\Exception $exception){
@@ -34,7 +34,7 @@ class CreatesPerfexCRMCustomerContact
$data = $response->json();
return (object) $data;
}else{
Log::error($response);
Log::channel('perfex_crm')->info($response);
return null;
}
}catch(\Exception $exception){
@@ -33,7 +33,7 @@ class CreatesPerfexCRMCustomerProject
$data = $response->json();
return (object) $data;
}else{
Log::error($response);
Log::channel('perfex_crm')->info($response);
return null;
}
}catch(\Exception $exception){
@@ -53,7 +53,7 @@ class CreatesPerfexCRMInvoice
$data = $response->json();
return (object) $data;
}else{
Log::error($response);
Log::channel('perfex_crm')->info($response);
return null;
}
}catch(\Exception $exception){
@@ -33,7 +33,7 @@ class CreatesPerfexCRMInvoicePayment
$data = $response->json();
return (object) $data;
}else{
Log::error($response);
Log::channel('perfex_crm')->info($response);
return null;
}
}catch(\Exception $exception){
@@ -40,7 +40,7 @@ class CreatesPerfexCRMLead
$data = $response->json();
return (object) $data;
}else{
Log::error($response);
Log::channel('perfex_crm')->info($response);
return null;
}
}catch(\Exception $exception){
@@ -36,7 +36,7 @@ class CreatesPerfexCRMMilestone
$data = $response->json();
return (object) $data;
}else{
Log::error($response);
Log::channel('perfex_crm')->info($response);
return null;
}
}catch(\Exception $exception){
@@ -56,7 +56,7 @@ class CreatesPerfexCRMTask
$data = $response->json();
return (object) $data;
}else{
Log::error($response);
Log::channel('perfex_crm')->info($response);
return null;
}
}catch(\Exception $exception){
@@ -24,7 +24,7 @@ class FetchesPerfexCRMCustomer
return (object) $data;
}else{
Log::error($response);
Log::channel('perfex_crm')->info($response);
return null;
}
}catch(\Exception $exception){
@@ -26,7 +26,7 @@ class FetchesPerfexCRMInvoice
return (object) $data;
}else{
Log::error($response);
Log::channel('perfex_crm')->info($response);
return null;
}
}catch(\Exception $exception){
@@ -24,7 +24,7 @@ class FetchesPerfexCRMLead
return (object) $data;
}else{
Log::error($response);
Log::channel('perfex_crm')->info($response);
return null;
}
}catch(\Exception $exception){
@@ -30,7 +30,7 @@ class FetchesPerfexCRMMilestone
return (object) $data;
}else{
Log::error($response);
Log::channel('perfex_crm')->info($response);
return null;
}
}catch(\Exception $exception){
@@ -30,7 +30,7 @@ class FetchesPerfexCRMProject
return (object) $data;
}else{
Log::error($response);
Log::channel('perfex_crm')->info($response);
return null;
}
}catch(\Exception $exception){
@@ -44,7 +44,7 @@ class FetchesPerfexCRMTask
return (object) $data;
}else{
Helper::debugLogger($response);
Log::channel('perfex_crm')->info($response);
return null;
}
}catch(\Exception $exception){
@@ -38,7 +38,7 @@ class UpdatesPerfexCRMCustomer
$data = $response->json();
return (object) $data;
}else{
Helper::debugLogger($response);
Log::channel('perfex_crm')->info($response);
return null;
}
}catch(\Exception $exception){
@@ -60,7 +60,7 @@ class UpdatesPerfexCRMInvoice
$data = $response->json();
return (object) $data;
}else{
Log::error($response);
Log::channel('perfex_crm')->info($response);
return null;
}
}catch(\Exception $exception){
@@ -41,7 +41,7 @@ class UpdatesPerfexCRMLead
$data = $response->json();
return (object) $data;
}else{
Log::error($response);
Log::channel('perfex_crm')->info($response);
return null;
}
}catch(\Exception $exception){
@@ -33,7 +33,7 @@ class UpdatesPerfexCRMProject
$data = $response->json();
return (object) $data;
}else{
Log::error($response);
Log::channel('perfex_crm')->info($response);
return null;
}
}catch(\Exception $exception){
@@ -40,7 +40,7 @@ class UpdatesPerfexCRMTask
$data = $response->json();
return (object) $data;
}else{
Log::error($response);
Log::channel('perfex_crm')->info($response);
return null;
}
}catch(\Exception $exception){
@@ -61,7 +61,7 @@ class ListTransactionsJobLogic extends AbstractControllerLogic
$userInfo
);
ListTransactionsJob::dispatch($listGenericJobObject);
ListTransactionsJob::dispatch($listGenericJobObject)->onQueue('high_priority');
$result = [];
$result['job_id'] = $jobId;
@@ -4,9 +4,11 @@ namespace App\Classes\Modules\Vouchers\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Rewards\Services\ListsUserRewards;
use App\Classes\ValueObjects\Constants\RoleTypes;
use App\Http\Resources\UserRewardResource;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class ListUserVouchersLogic extends AbstractControllerLogic
{
@@ -40,6 +42,11 @@ class ListUserVouchersLogic extends AbstractControllerLogic
public function logic(Request $request) : JsonResponse
{
$query = $this->listsUserRewards->execute($this->listsUserRewards->deserializeFilters($request->input('filters')));
if(in_array(Auth::user()->type, RoleTypes::ADMIN_ROLES)){
$request->merge(['isAdmin' => true]);
}
return $this->collectionResponse(UserRewardResource::collection($query));
}
@@ -0,0 +1,43 @@
<?php
namespace App\Classes\Notifications;
use App\Models\User;
use App\Models\Voucher;
use Carbon\Carbon;
use Illuminate\Notifications\Messages\MailMessage;
class WelcomeVoucherEmail extends AbstractEmail
{
/** @var User */
private $user;
/** @var Voucher */
private $voucher;
/**
* WelcomeVoucherEmail constructor.
* @param User $user
* @param Voucher $voucher
*/
public function __construct(User $user, Voucher $voucher)
{
$this->user = $user;
$this->voucher = $voucher;
}
public function toMail()
{
$this->voucher->end_date = Carbon::parse($this->voucher->end_date)->format('Y-m-d');
$mailMessage = (new MailMessage)
->subject('Welcome Voucher')
->view('emails.accounts.welcome_voucher', ['user' => $this->user, 'voucher' => $this->voucher]);
return $mailMessage;
}
}
@@ -0,0 +1,8 @@
<?php
namespace App\Classes\ValueObjects\Constants;
final class Vouchers {
public const WELCOME_50_PERCENT_OFF = 'WELCOME50%OFF';
}
@@ -0,0 +1,24 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class KeyValueBasicResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
// 'id' => $this->id,
'key' => $this->key,
'value' => $this->value,
];
}
}
@@ -2,6 +2,7 @@
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class UserRewardResource extends JsonResource
@@ -14,6 +15,13 @@ class UserRewardResource extends JsonResource
*/
public function toArray($request)
{
$emailReminder = null;
if ($request->has('isAdmin')) {
$keyValuePairs = $this->user->attributes()->get();
$emailReminder = KeyValueBasicResource::collection($keyValuePairs);
$this->voucher->email = $emailReminder;
}
return [
'id' => $this->id,
'user_id' => $this->user_id,
+13 -4
View File
@@ -2,6 +2,7 @@
namespace App\Http\Resources;
use ArrayObject;
use Illuminate\Http\Resources\Json\JsonResource;
class VoucherResource extends JsonResource
@@ -14,9 +15,16 @@ class VoucherResource extends JsonResource
*/
public function toArray($request)
{
$filteredRedemptions = $this->redemptions->filter(function ($redemption) {
return $redemption->transaction && $redemption->transaction->owner;
});
$filteredRedemptions = new ArrayObject([]);
if ($request->has('filters') && str_contains($request->input('filters'), "has_active_reward")) {
$filteredRedemptions = new ArrayObject([]);
}
else{
$filteredRedemptions = $this->redemptions->filter(function ($redemption) {
return $redemption->transaction && $redemption->transaction->owner;
});
}
return [
'id' => $this->id,
'name' => $this->name,
@@ -25,7 +33,8 @@ class VoucherResource extends JsonResource
'value' => (float) $this->value,
'start_date' => $this->start_date,
'end_date' => $this->end_date,
'is_redeemed' => $filteredRedemptions->count() > 0
'is_redeemed' => $filteredRedemptions->count() > 0,
'email' => $this->email ? new KeyValueBasicResource($this->email->where('key', $this->code.'_EMAIL_COUNT')->first()) : null,
];
}
}
+15
View File
@@ -0,0 +1,15 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Relations\MorphTo;
class KeyValuePair extends AbstractModel
{
protected $table = 'key_value_pairs';
public function owner(): MorphTo
{
return $this->morphTo();
}
}
+20 -1
View File
@@ -2,6 +2,7 @@
namespace App\Models;
use App\Classes\General\Interfaces\KeyValueInterface;
use App\Classes\General\Interfaces\Voucherifiable;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
@@ -26,7 +27,8 @@ class User extends AbstractModel implements
AuthenticatableContract,
AuthorizableContract,
CanResetPasswordContract,
Voucherifiable
Voucherifiable,
KeyValueInterface
{
use HasRoles, Notifiable, Authenticatable, Authorizable, CanResetPassword, MustVerifyEmail, SoftDeletes;
@@ -101,4 +103,21 @@ class User extends AbstractModel implements
{
return $this->HasMany(UserReward::class, 'user_id', 'id');
}
public function hasAttribute(string $key, $value = null): bool
{
$query = $this->attributes()->where('key', $key);
if ($value !== null) {
$query->where('value', $value);
}
return $query->exists();
}
public function attributes(): MorphMany
{
return $this->morphMany(KeyValuePair::class, 'owner');
}
}
+13
View File
@@ -108,6 +108,19 @@ return [
'driver' => 'errorlog',
'level' => 'debug',
],
'vue_polling' => [
'driver' => 'single',
'path' => storage_path('logs/laravel_vue_plling.log'),
'level' => 'info',
],
'perfex_crm' => [
'driver' => 'single',
'path' => storage_path('logs/laravel_perfex_crm.log'),
'level' => 'info',
],
],
];
+7
View File
@@ -34,6 +34,13 @@ return [
'driver' => 'sync',
],
'high_priority' => [
'driver' => 'database',
'table' => 'jobs',
'queue' => 'high_priority',
'retry_after' => 90,
],
'database' => [
'driver' => 'database',
'table' => 'jobs',
@@ -0,0 +1,37 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateKeyValuePairsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('key_value_pairs', function (Blueprint $table) {
$table->id();
$table->string('owner_type'); //'user', 'order', 'transaction'
$table->unsignedBigInteger('owner_id');
$table->string('key');
$table->string('value');
$table->timestamps();
$table->index(['owner_type', 'owner_id']);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('key_value_pairs');
}
}
@@ -9,6 +9,10 @@
<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="card-body border-top" v-if="$store.getters.isAdmin && item.voucher.email && item.voucher.email.key === item.voucher.code + '_EMAIL_COUNT'">
<button disabled type="button" v-if="item.voucher.email && item.voucher.email.key === item.voucher.code + '_EMAIL_COUNT' && item.voucher.email.value == '1'" class="btn btn-lg btn-primary">Email Reminder #1 Sent</button>
<!-- <button type="button" v-else @click="submit()" class="btn btn-lg btn-primary">Send Email Reminder #1</button> -->
</div>
<div class="card-footer text-muted">
<p v-if="item.voucher && item.voucher.is_redeemed">
Voucher claimed
@@ -25,6 +29,9 @@
<script>
import componentHandler from '../../../general/mixins/componentHandler';
export default {
methods: {
submit(){},
},
mixins: [componentHandler]
}
</script>
@@ -0,0 +1,13 @@
@extends('emails.layout.base')
@section('content')
<img style="width: 100%;" src="https://assets.izyim.com/public/images/emails/welcome50%25off.png"/>
<p style="font-size: 0.9em">Hello from CIEF! Thanks for signing up with us. Thinking about using our RMB payment transfer services? Use code {{$voucher->code}} and get a 50% discount on your first order. Why not give it a try?</p>
<p style="font-size: 0.9em">Any questions? I'm here to help. Start here: <a href="{{env('APP_URL').'/dashboard'}}">{{env('APP_URL').'/dashboard'}}</a></p>
<p style="font-size: 0.9em">叮咚!非常感谢您在我们代付网站注册, 您是否对我们的代付服务感兴趣却还在犹豫或者在因为其他因素还没正式使用呢? 如果是首次下单, 不妨使用我们专门为新用户准备的独家优惠, 只需在首次下单时使用代码【{{$voucher->code}}】,就能享有5折的手续费折扣呢! 尝试了一次, 或许你会喜欢我们公司的服务,点击以下网址开始启用吧!</p>
<p style="font-size: 0.9em"><a href="{{env('APP_URL').'/dashboard'}}">{{env('APP_URL').'/dashboard'}}</a></p>
<p style="font-size: 0.9em">如果您有任何疑问或需要更多信息,随时联系我。我们期待着能为您提供物流以及代付服务!</span></p>
<p style="font-size: 0.9em">Thanks</span></p>
<p style="font-size: 0.9em">谢谢!</span></p>
@endsection
+83 -6
View File
@@ -139,16 +139,16 @@ Route::get('/transfer/{marking}/latest/{document_type}', function ($marking, $do
$lowercaseDocumentType = null;
switch ($document_type) {
case 'po':
case 'po':
$lowercaseDocumentType = DocumentType::PURCHASE_ORDER;
break;
case 'do':
case 'do':
$lowercaseDocumentType = DocumentType::DELIVER_ORDER;
break;
case 'sdo':
case 'sdo':
$lowercaseDocumentType = DocumentType::SUPPLIER_DELIVER_ORDER;
break;
default:
default:
$lowercaseDocumentType = DocumentType::INVOICE;
break;
}
@@ -879,8 +879,14 @@ Route::get('/vouchers', function () {
})->name('rewards');
Route::get('/customer/vouchers/{marking}', function ($marking) {
$id = \App\Models\Company::where('reference', '=', $marking)->first()->employees->first()->id;
return view('pages.customers.reward', ['id' => $id]);
$company = \App\Models\Company::where('reference', '=', $marking)->first();
if($company){
$id = $company->employees->first()->id;
return view('pages.customers.reward', ['id' => $id]);
}
else{
abort(404);
}
})->name('customer.reward');
Route::get('transaction/{id}/credit_note/download', 'Transactions\GenerateCreditNotePdfController@download')->name('transaction.credit_note.download');
@@ -961,3 +967,74 @@ Route::get('/invoice/{marking}/{started_at}/{ended_at}/fix', function($marking,
}
);
})->name('invoice.fix.byCustomerMarking');
Route::get('/show-white-form-transactions-in-date-range/{from_date}/{to_date}', function ($from_date, $to_date) {
$approvedTransactions = Transaction::where('type', TransactionType::PAYMENT)->whereIn('status', [ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::APPROVED])->where('owner_type', '!=', Wallet::class)->orderBy('status')->get();
echo '<h1>Pending Orders Payments</h1>';
echo '<table style="border-collapse: collapse;">';
echo '<thead>';
echo '<tr>';
echo '<th style="border: 1px solid black;">Booking</th>';
echo '<th style="border: 1px solid black;">Amount</th>';
echo '<th style="border: 1px solid black;">Payment Date</th>';
echo '<th style="border: 1px solid black;">Status</th>';
echo '</tr>';
echo '</thead>';
echo '<tbody>';
foreach ($approvedTransactions as $approvedTransaction) {
echo '<tr>';
echo '<td style="border: 1px solid black;"><a href="' . \route('booking.details', $approvedTransaction->owner->marking) . '" target="_blank">' . $approvedTransaction->owner->marking . '</a></td>';
echo '<td style="border: 1px solid black;">' . round($approvedTransaction->amount, 2) . '</td>';
echo '<td style="border: 1px solid black;">' . $approvedTransaction->created_at->format('d-m-Y h:i A') . '</td>';
echo '<td style="border: 1px solid black;">' . ApprovalStatus::APPROVAL_STATUS_ID[$approvedTransaction->status] . '</td>';
echo '</tr>';
}
echo '</tbody>';
echo '</table>';
$startDate = Carbon::createFromFormat('d-m-Y', $from_date)->startOfDay();
$endDate = Carbon::createFromFormat('d-m-Y', $to_date)->endOfDay();
echo '<h1>Bills in the date range</h1>';
echo '<table style="border-collapse: collapse; width: 100%;">';
echo '<thead>';
echo '<tr>';
echo '<th style="border: 1px solid black;">Booking</th>';
echo '<th style="border: 1px solid black;">Amount</th>';
echo '<th style="border: 1px solid black;">Customer payment date</th>';
echo '<th style="border: 1px solid black;">White form date</th>';
echo '<th style="border: 1px solid black;">Supplier</th>';
echo '<th style="border: 1px solid black;">Upload bank slip Date</th>';
echo '<th style="border: 1px solid black;">PO submit date</th>';
echo '<th style="border: 1px solid black;">PO approve date</th>';
echo '</tr>';
echo '</thead>';
echo '<tbody>';
$bills = Transaction::where('type', TransactionType::BILL)->whereBetween('created_at', [$startDate, $endDate])->get();
foreach ($bills as $bill) {
echo '<tr>';
$payment = $bill->owner;
$po = $payment->owner->transactions()->where('type', TransactionType::PURCHASE_ORDER)->whereIn('status', [ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::APPROVED])->first();
echo '<td style="border: 1px solid black;"><a href="' . \route('booking.details', $bill->owner->owner->marking) . '" target="_blank">' . $payment->owner->marking . '</a></td>';
echo '<td style="border: 1px solid black;">' . round($payment->amount, 2) . '</td>';
echo '<td style="border: 1px solid black;">' . $payment->created_at->format('d-m-Y h:i A') . '</td>';
echo '<td style="border: 1px solid black;">' . $bill->created_at->format('d-m-Y h:i A') . '</td>';
echo '<td style="border: 1px solid black;">' . $bill->issuerCompany->name . '</td>';
echo '<td style="border: 1px solid black; color: '.($bill->status === ApprovalStatus::APPROVED ? "green" : "red").';">' . ($bill->status === ApprovalStatus::APPROVED ? $bill->updated_at->format('d-m-Y h:i A') : 'Pending Upload') . '</td>';
echo '<td style="border: 1px solid black; color: '.($po ? "green" : "red").';">' . ($po ? $po->updated_at->format('d-m-Y h:i A') : 'Pending Submission') . '</td>';
echo '<td style="border: 1px solid black;">' . ($po ? ($po->status === ApprovalStatus::APPROVED ? $po->updated_at->format('d-m-Y h:i A') : '' ) : '' ). '</td>';
echo '</tr>';
}
echo '</tbody>';
echo '</table>';
});