Merge branch 'dillon/90-e-invoice-shipping-portal-e' into vapor/staging

This commit is contained in:
Dillon Ngo
2025-06-30 23:34:17 +08:00
53 changed files with 2214 additions and 74 deletions
+4
View File
@@ -66,3 +66,7 @@ COMMANDS_V2_ENABLED=false
STORAGE_FEE_LAUNCH_DATE="2023-12-11 00:00:00"
SST_START_DATE="2024-04-01 00:00:00"
E_INVOICE_START_DATE="2025-07-01 00:00:00"
MAINTENANCE_MESSAGE_TITLE="We'll be back online on 00:00 1/7/2025"
MAINTENANCE_MESSAGE="Sorry for the inconvenience but we're performing some maintenance at the moment."
@@ -0,0 +1,14 @@
<?php
namespace App\Classes\Exceptions;
use App\Classes\ValueObjects\Constants\HttpStatus;
final class CriteriaNotFulfilledException extends ServiceApiException {
public function __construct(?string $message = null) {
parent::__construct(
$message ?? 'One or more required criteria were not fulfilled.',
HttpStatus::VALIDATION_FAILED
);
}
}
@@ -0,0 +1,20 @@
<?php
namespace App\Classes\General\Eloquent\Filters;
use Illuminate\Database\Eloquent\Builder;
class TypeNotIn implements Filter
{
/**
* @param Builder $builder
* @param $value
* @return Builder|mixed
*/
public static function apply(Builder $builder, $value)
{
return $builder->whereNotIn('type', $value);
}
}
@@ -6,6 +6,7 @@ namespace App\Classes\Modules\Addresses\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Addresses\Services\ListsAddresses;
use App\Classes\Modules\Addresses\Standards\Rules\CanListAddresses;
use App\Classes\ValueObjects\Constants\AddressType;
use App\Http\Resources\AddressResource;
use ErrorException;
use Illuminate\Http\JsonResponse;
@@ -51,13 +52,12 @@ class ListAddressesLogic extends AbstractControllerLogic
*/
public function logic(Request $request) : JsonResponse
{
$this->canListAddresses->passes();
$query = $this->listsAddresses->execute($this->listsAddresses->deserializeFilters($request->input('filters')));
//$query = $this->listsAddresses->execute($this->listsAddresses->deserializeFilters($request->input('filters')));
$query = $this->listsAddresses->execute(array_merge($this->listsAddresses->deserializeFilters($request->input('filters')), ['type_not_in' => [AddressType::E_INVOICE]]));
return $this->collectionResponse(AddressResource::collection($query));
}
}
}
@@ -23,7 +23,7 @@ class AddressObject implements DataTransferObject
/** @var int */
private $districtId;
/** @var int */
/** @var string */
private $postCode;
/** @var int */
@@ -42,12 +42,12 @@ class AddressObject implements DataTransferObject
* @param int $countryId
* @param int $stateId
* @param int $districtId
* @param int $postCode
* @param string $postCode
* @param int $type
* @param int $status
* @param null|string $reference
*/
public function __construct(string $streetOne, ?string $streetTwo, int $countryId, int $stateId, int $districtId, int $postCode, int $type, int $status, ?string $reference = null)
public function __construct(string $streetOne, ?string $streetTwo, int $countryId, int $stateId, int $districtId, string $postCode, int $type, int $status, ?string $reference = null)
{
$this->streetOne = $streetOne;
$this->streetTwo = $streetTwo;
@@ -101,9 +101,9 @@ class AddressObject implements DataTransferObject
}
/**
* @return int
* @return string
*/
public function getPostCode(): int
public function getPostCode(): string
{
return $this->postCode;
}
@@ -133,4 +133,4 @@ class AddressObject implements DataTransferObject
}
}
}
@@ -0,0 +1,40 @@
<?php
namespace App\Classes\Modules\Addresses\Services;
use App\Classes\General\Eloquent\AbstractUpdateRelationshipRecord;
use App\Classes\General\Interfaces\Addressable;
use App\Classes\Modules\Addresses\DataTransferObjects\AddressObject;
use App\Models\Address;
use App\Models\CompanyModule;
class UpsertsAddress extends AbstractUpdateRelationshipRecord
{
/**
* Create or update the company's address.
*
* @param Addressable $addressable
* @param AddressObject $object
* @param int $id
* @return \Illuminate\Database\Eloquent\Model
* @throws \App\Classes\Exceptions\MalformedRequestException
*/
public function execute(Addressable $addressable, AddressObject $object, int $id)
{
//Create new or update?
$model = $addressable->addresses()->where('id', $id)->first() ?? new Address();
$model->reference = $object->getReference();
$model->street_one = $object->getStreetOne();
$model->street_two = $object->getStreetTwo();
$model->country_id = $object->getCountryId();
$model->state_id = $object->getStateId();
$model->district_id = $object->getDistrictId();
$model->postcode = $object->getPostCode();
$model->status = $object->getStatus();
$model->type = $object->getType();
return $this->handler($addressable->addresses(), $model);
}
}
@@ -0,0 +1,69 @@
<?php
namespace App\Classes\Modules\Companies\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Companies\Services\FetchesCompany;
use App\Classes\Modules\Companies\Standards\Rules\CanFetchCompany;
use App\Classes\ValueObjects\Constants\AddressType;
use App\Http\Resources\EInvoiceInfoResource;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class FetchCompanyEInvoiceInfoLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Retrieved Company E-Invoice Info',
'message' => 'You have successfully retrieved a Company E-Invoice Info'
];
}
/** @var CanFetchCompany */
private $canFetchCompany;
/** @var FetchesCompany */
private $fetchesCompany;
/**
* FetchCompanyEInvoiceInfoLogic constructor.
* @param CanFetchCompany $canFetchCompany
* @param FetchesCompany $fetchesCompany
*/
public function __construct(CanFetchCompany $canFetchCompany, FetchesCompany $fetchesCompany)
{
$this->canFetchCompany = $canFetchCompany;
$this->fetchesCompany = $fetchesCompany;
}
/**
* @param Request $request
* @return JsonResponse
* @throws \App\Classes\Exceptions\AccessForbiddenException
* @throws \App\Classes\Exceptions\RequestValidationException
*/
public function logic(Request $request) : JsonResponse
{
$this->canFetchCompany->passes();
$company = $this->fetchesCompany->execute(['id' => $request->route('id')]);
$eInvoiceInfo = $company->companyModules()->first()->addresses()->where('type', '=', AddressType::E_INVOICE)->latest()->first();
if($eInvoiceInfo){
$eInvoiceInfo->tin = $company->tin;
$eInvoiceInfo->msic_code = $company->msic_code;
$eInvoiceInfo->e_invoice = $company->e_invoice;
}
else{
return $this->response([]);
}
return $this->resourceResponse(new EInvoiceInfoResource($eInvoiceInfo));
}
}
@@ -0,0 +1,153 @@
<?php
namespace App\Classes\Modules\Companies\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Companies\Services\FetchesCompany;
use App\Classes\Modules\Companies\Services\UpdatesCompany;
use App\Classes\Modules\Companies\Services\UpdatesCompanyDebtor;
use App\Classes\Modules\Addresses\Services\UpsertsAddress;
use App\Classes\Modules\Addresses\Services\FetchesDistrict;
use App\Classes\Modules\Companies\Services\UpdatesCompanyModuleName;
use App\Classes\Modules\Documents\Services\FetchesDocument;
use App\Classes\Modules\Documents\Services\UpdatesDocumentReference;
use App\Classes\Modules\Addresses\Standards\Rules\CanCreateAddress;
use App\Classes\Modules\Addresses\DataTransferObjects\AddressObject;
use App\Classes\Modules\Companies\Services\UpdatesCompanyEInvoiceInfo;
use App\Classes\Modules\Companies\Standards\Rules\CanUpdateCompany;
use App\Classes\Modules\Companies\DataTransferObjects\CompanyObject;
use App\Classes\Modules\Companies\DataTransferObjects\UpdateCompanyDetailsDTO;
use App\Classes\ValueObjects\Constants\AddressType;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Http\Resources\CompanyResource;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class UpdateCompanyDetailsLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Update Company Details',
'message' => 'You have successfully updated the Company Details'
];
}
/** @var CanUpdateCompany */
private $canUpdateCompany;
/** @var UpdatesCompany */
private $updatesCompany;
/** @var FetchesCompany */
private $fetchesCompany;
/** @var UpdatesCompanyDebtor */
private $updatesCompanyDebtor;
/** @var CanCreateAddress */
private $canCreateAddress;
/** @var FetchesDistrict */
private $fetchesDistrict;
/** @var UpsertsAddress */
private $upsertsAddress;
/** @var UpdatesCompanyEInvoiceInfo */
private $updatesCompanyEInvoiceInfo;
/** @var UpdatesCompanyModuleName */
private $updatesCompanyModuleName;
/** @var FetchesDocument */
private $fetchesDocument;
/** @var UpdatesDocumentReference */
private $updatesDocumentReference;
/**
* UpdateCompanyDetailsLogic constructor.
* @param CanUpdateCompany $canUpdateCompany
* @param UpdatesCompany $updatesCompany
* @param FetchesCompany $fetchesCompany
* @param UpdatesCompanyDebtor $updatesCompanyDebtor
* @param CanCreateAddress $canCreateAddress
* @param FetchesDistrict $fetchesDistrict
* @param UpsertsAddress $upsertsAddress
* @param UpdatesCompanyEInvoiceInfo $updatesCompanyEInvoiceInfo;
* @param FetchesDocument $fetchesDocument
* @param UpdatesDocumentReference $updatesDocumentReference
*
*/
public function __construct(
CanUpdateCompany $canUpdateCompany,
UpdatesCompany $updatesCompany,
FetchesCompany $fetchesCompany,
UpdatesCompanyDebtor $updatesCompanyDebtor,
CanCreateAddress $canCreateAddress,
FetchesDistrict $fetchesDistrict,
UpsertsAddress $upsertsAddress,
UpdatesCompanyEInvoiceInfo $updatesCompanyEInvoiceInfo,
UpdatesCompanyModuleName $updatesCompanyModuleName,
FetchesDocument $fetchesDocument,
UpdatesDocumentReference $updatesDocumentReference
)
{
$this->canUpdateCompany = $canUpdateCompany;
$this->updatesCompany = $updatesCompany;
$this->fetchesCompany = $fetchesCompany;
$this->updatesCompanyDebtor = $updatesCompanyDebtor;
$this->canCreateAddress = $canCreateAddress;
$this->fetchesDistrict = $fetchesDistrict;
$this->upsertsAddress = $upsertsAddress;
$this->updatesCompanyEInvoiceInfo = $updatesCompanyEInvoiceInfo;
$this->updatesCompanyModuleName = $updatesCompanyModuleName;
$this->fetchesDocument = $fetchesDocument;
$this->updatesDocumentReference = $updatesDocumentReference;
}
/**
* @param Request $request
* @return JsonResponse
* @throws ErrorException
*/
public function logic(Request $request) : JsonResponse
{
$dto = new UpdateCompanyDetailsDTO($request->all());
$object = new CompanyObject($dto->name, $dto->reference, $dto->type);
$this->canUpdateCompany->passes($object);
$company = $this->fetchesCompany->execute(['id' => $request->route('id')]);
$this->updatesCompanyModuleName->execute($company->companyModules()->first(), $object->getName());
//Update Name and Debtor, Type
$company = $this->updatesCompany->execute($company, $object);
if ($request->input('debtor') || $company->first()->debtor !== null) {
$this->updatesCompanyDebtor->execute($company, $request->input('debtor'));
}
//Update EInvoice Related Info
if($company->e_invoice){
$district = $this->fetchesDistrict->execute(['id' => $dto->districtId]);
$addObj = new AddressObject($dto->streetOne, $dto->streetTwo, $district->country_id, $dto->stateId, $district->id, $dto->postCode, AddressType::E_INVOICE, ApprovalStatus::APPROVED, 'E-Invoice');
$this->canCreateAddress->passes($addObj);
$this->upsertsAddress->execute($company->companyModules()->first(), $addObj, $dto->addressId);
$this->updatesCompanyEInvoiceInfo->execute($company, $dto->tin, $dto->msicCode);
}
//Update Identification Card / SSM Registration
if($dto->identificationId){
$document = $this->fetchesDocument->execute(['id' => $dto->identificationId]);
$this->updatesDocumentReference->execute($document, $dto->identificationReference);
}
return $this->resourceResponse(new CompanyResource($company));
}
}
@@ -0,0 +1,109 @@
<?php
namespace App\Classes\Modules\Companies\ControllersLogic;
use App\Classes\Exceptions\CriteriaNotFulfilledException;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Addresses\Services\CreatesAddress;
use App\Classes\Modules\Addresses\Services\FetchesDistrict;
use App\Classes\Modules\Addresses\Standards\Rules\CanCreateAddress;
use App\Classes\Modules\Addresses\DataTransferObjects\AddressObject;
use App\Classes\Modules\Companies\Services\FetchesCompanyModule;
use App\Classes\Modules\Companies\Services\UpdatesCompanyEInvoiceInfo;
use App\Classes\Modules\Companies\DataTransferObjects\EInvoiceInfoDTO;
use App\Classes\Modules\Rules\Services\RuleEvaluator;
use App\Classes\Modules\Rules\Standards\Rules\CanPassEInvoicePromptedRule;
use App\Classes\ValueObjects\Constants\AddressType;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class UpdateCompanyEInvoiceInfoLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'EInvoice Info Update',
'message' => 'You have successfully updated company E-Invoice information'
];
}
/** @var CanCreateAddress */
private $canCreateAddress;
/** @var FetchesDistrict */
private $fetchesDistrict;
/** @var FetchesCompanyModule */
private $fetchesCompanyModule;
/** @var CreatesAddress */
private $createsAddress;
/** @var RuleEvaluator */
private $ruleEvaluator;
/** @var UpdatesCompanyEInvoiceInfo */
private $updatesCompanyEInvoiceInfo;
/** @var CanPassEInvoicePromptedRule */
private $canPassEInvoicePromptedRule;
/**
* UpdateCompanyEInvoiceInfoLogic constructor.
* @param CanCreateAddress $canCreateAddress
* @param FetchesDistrict $fetchesDistrict
* @param FetchesCompanyModule $fetchesCompanyModule
* @param CreatesAddress $createsAddress
* @param RuleEvaluator $ruleEvaluator;
* @param UpdatesCompanyEInvoiceInfo $updatesCompanyEInvoiceInfo;
* @param CanPassEInvoicePromptedRule $canPassEInvoicePromptedRule
*/
public function __construct(CanCreateAddress $canCreateAddress, FetchesDistrict $fetchesDistrict, FetchesCompanyModule $fetchesCompanyModule, CreatesAddress $createsAddress, RuleEvaluator $ruleEvaluator, UpdatesCompanyEInvoiceInfo $updatesCompanyEInvoiceInfo, CanPassEInvoicePromptedRule $canPassEInvoicePromptedRule)
{
$this->canCreateAddress = $canCreateAddress;
$this->fetchesDistrict = $fetchesDistrict;
$this->fetchesCompanyModule = $fetchesCompanyModule;
$this->createsAddress = $createsAddress;
$this->ruleEvaluator = $ruleEvaluator;
$this->updatesCompanyEInvoiceInfo = $updatesCompanyEInvoiceInfo;
$this->canPassEInvoicePromptedRule = $canPassEInvoicePromptedRule;
}
/**
* @param Request $request
* @return JsonResponse
* @throws \App\Classes\Exceptions\AccessForbiddenException
* @throws \App\Classes\Exceptions\MalformedRequestException
* @throws \App\Classes\Exceptions\RequestValidationException
* @throws \App\Classes\Exceptions\CriteriaNotFulfilledException
*/
public function logic(Request $request) : JsonResponse
{
$dto = new EInvoiceInfoDTO($request->all());
$result = $this->ruleEvaluator->evaluate([
$this->canPassEInvoicePromptedRule,
], $dto);
if ($result->failed()) {
throw new CriteriaNotFulfilledException("- " . implode("<br>- ", $result->messages()));
}
$district = $this->fetchesDistrict->execute(['id' => $dto->districtId]);
$object = new AddressObject($dto->streetOne, $dto->streetTwo, $district->country_id, $dto->stateId, $district->id, $dto->postCode, AddressType::E_INVOICE, ApprovalStatus::APPROVED, 'E-Invoice');
//Update Address
$this->canCreateAddress->passes($object);
$companyModule = $this->fetchesCompanyModule->execute(['id' => $dto->companyModuleId]);
$this->createsAddress->execute($companyModule, $object);
//Update tin, msic code
$this->updatesCompanyEInvoiceInfo->execute($companyModule->company, $dto->tin, $dto->msicCode);
return $this->response([]);
}
}
@@ -0,0 +1,59 @@
<?php
namespace App\Classes\Modules\Companies\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Companies\Services\UpdatesCompanyEInvoiceRequest;
use App\Classes\Modules\Companies\Services\FetchesCompanyModule;
use App\Classes\Modules\Companies\DataTransferObjects\EInvoiceRequestDTO;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class UpdateCompanyEInvoiceRequestLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Updated EInvoice Request',
'message' => 'You have successfully updated company E-Invoice request'
];
}
/** @var FetchesCompanyModule */
private $fetchesCompanyModule;
/** @var UpdatesCompanyEInvoiceRequest */
private $updatesCompanyEInvoiceRequest;
/**
* UpdateCompanyEInvoiceRequestLogic constructor.
* @param FetchesCompanyModule $fetchesCompanyModule
* @param UpdatesCompanyEInvoiceRequest $updatesCompanyEInvoiceRequest
*/
public function __construct(FetchesCompanyModule $fetchesCompanyModule, UpdatesCompanyEInvoiceRequest $updatesCompanyEInvoiceRequest)
{
$this->fetchesCompanyModule = $fetchesCompanyModule;
$this->updatesCompanyEInvoiceRequest = $updatesCompanyEInvoiceRequest;
}
/**
* @param Request $request
* @return JsonResponse
* @throws \App\Classes\Exceptions\AccessForbiddenException
* @throws \App\Classes\Exceptions\MalformedRequestException
* @throws \App\Classes\Exceptions\RequestValidationException
*/
public function logic(Request $request) : JsonResponse
{
$dto = new EInvoiceRequestDTO($request->all());
$companyModule = $this->fetchesCompanyModule->execute(['id' => $dto->companyModuleId]);
$this->updatesCompanyEInvoiceRequest->execute($companyModule->company, $dto->eInvoiceRequest);
return $this->response([]);
}
}
@@ -0,0 +1,43 @@
<?php
namespace App\Classes\Modules\Companies\DataTransferObjects;
use App\Classes\General\Interfaces\DataTransferObject;
class EInvoiceInfoDTO implements DataTransferObject
{
public string $tin;
public string $msicCode;
public int $districtId;
public int $stateId;
public int $companyModuleId;
public string $streetOne;
public string $streetTwo;
public string $postCode;
public function __construct(array $data)
{
$this->tin = (string) ($data['tin'] ?? '');
$this->msicCode = (string) ($data['msic_code'] ?? '');
$this->districtId = (int) ($data['district_id'] ?? 0);
$this->stateId = (int) ($data['state_id'] ?? 0);
$this->companyModuleId = (int) ($data['company_module_id'] ?? 0);
$this->streetOne = (string) ($data['street_one'] ?? '');
$this->streetTwo = (string) ($data['street_two'] ?? '');
$this->postCode = (string) ($data['post_code'] ?? '');
}
public function toArray(): array
{
return [
'tin' => $this->tin,
'msic_code' => $this->msicCode,
'district_id' => $this->districtId,
'state_id' => $this->stateId,
'company_module_id' => $this->companyModuleId,
'street_one' => $this->streetOne,
'street_two' => $this->streetTwo,
'post_code' => $this->postCode,
];
}
}
@@ -0,0 +1,25 @@
<?php
namespace App\Classes\Modules\Companies\DataTransferObjects;
use App\Classes\General\Interfaces\DataTransferObject;
class EInvoiceRequestDTO implements DataTransferObject
{
public bool $eInvoiceRequest;
public int $companyModuleId;
public function __construct(array $data)
{
$this->eInvoiceRequest = $data['e_invoice_request'];
$this->companyModuleId = $data['company_module_id'];
}
public function toArray(): array
{
return [
'e_invoice_request' => $this->eInvoiceRequest,
'company_module_id' => $this->companyModuleId,
];
}
}
@@ -0,0 +1,72 @@
<?php
namespace App\Classes\Modules\Companies\DataTransferObjects;
use App\Classes\General\Interfaces\DataTransferObject;
class UpdateCompanyDetailsDTO implements DataTransferObject
{
public int $id;
public string $name;
public string $debtor;
public string $reference;
public int $type;
public string $tin;
public string $msicCode;
public int $addressId;
public int $districtId;
public int $stateId;
public int $companyId;
public string $streetOne;
public string $streetTwo;
public string $postCode;
public string $identificationReference;
public int $identificationId;
public function __construct(array $data)
{
$this->id = (int) ($data['id'] ?? 0);
$this->name = (string) ($data['name'] ?? '');
$this->debtor = (string) ($data['debtor'] ?? '');
$this->reference = (string) ($data['reference'] ?? '');
$this->type = (int) ($data['type'] ?? 0);
$this->tin = (string) ($data['tin'] ?? 0);
$this->msicCode = (string) ($data['msic_code'] ?? '');
$this->addressId = (int) ($data['address_id'] ?? 0);
$this->districtId = (int) ($data['district_id'] ?? 0);
$this->stateId = (int) ($data['state_id'] ?? 0);
$this->companyId = (int) ($data['company_id'] ?? 0);
$this->streetOne = (string) ($data['street_one'] ?? '');
$this->streetTwo = (string) ($data['street_two'] ?? '');
$this->postCode = (string) ($data['post_code'] ?? '');
$this->identificationReference = (string) ($data['identification_reference'] ?? '');
$this->identificationId = (int) ($data['identification_id'] ?? 0);
}
public function toArray(): array
{
return [
'id' => $this->id,
'name' => $this->name,
'debtor' => $this->debtor,
'reference' => $this->reference,
'type' => $this->type,
'tin' => $this->tin,
'msic_code' => $this->msicCode,
'address_id' => $this->addressId,
'district_id' => $this->districtId,
'state_id' => $this->stateId,
'company_id' => $this->companyId,
'street_one' => $this->streetOne,
'street_two' => $this->streetTwo,
'post_code' => $this->postCode,
'identification_reference' => $this->identificationReference,
'identification_id' => $this->identificationId,
];
}
}
@@ -0,0 +1,25 @@
<?php
namespace App\Classes\Modules\Companies\Services;
use App\Classes\General\Eloquent\AbstractUpdateRecord;
use App\Models\Company;
class UpdatesCompanyEInvoiceInfo extends AbstractUpdateRecord
{
/**
* @param Company $model
* @param string $tin
* @param string $msicCode
* @return \Illuminate\Database\Eloquent\Model
* @throws \App\Classes\Exceptions\MalformedRequestException
*/
public function execute(Company $model, string $tin, string $msicCode)
{
$model->tin = $tin;
$model->msic_code = $msicCode;
return $this->handler($model);
}
}
@@ -0,0 +1,29 @@
<?php
namespace App\Classes\Modules\Companies\Services;
use App\Classes\General\Eloquent\AbstractUpdateRecord;
use App\Models\Company;
class UpdatesCompanyEInvoiceRequest extends AbstractUpdateRecord
{
/**
* @param Company $model
* @param bool $eInvoice
* @return \Illuminate\Database\Eloquent\Model
* @throws \App\Classes\Exceptions\MalformedRequestException
*/
public function execute(Company $model, bool $eInvoice)
{
if (is_null($model->e_invoice_requested_at)) {
if($eInvoice){
$model->e_invoice_requested_at = now();
}
}
$model->e_invoice = $eInvoice;
return $this->handler($model);
}
}
@@ -2,18 +2,18 @@
namespace App\Classes\Modules\Exports\Services;
use App\Models\Company;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\WithMapping;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
use App\Classes\General\Eloquent\ApplyFiltersToQuery;
use App\Models\Company;
class ExportsAllCustomersInfoForLarkSystem implements WithHeadings, WithHeadingRow, WithMapping, ShouldAutoSize, FromQuery
class ExportsAllCustomersInfoForLarkSystem implements FromQuery, WithMapping, WithHeadings, ShouldAutoSize
{
use Exportable;
public function __construct() {}
public function headings(): array
@@ -25,33 +25,58 @@ class ExportsAllCustomersInfoForLarkSystem implements WithHeadings, WithHeadingR
'Email',
'Registration Date',
'Last Order Date',
'Debtor Code',
'Credit Term Customer',
'Custom Segments',
];
}
public function query()
{
return (new ApplyFiltersToQuery())->execute(Company::query(), [
'has_business_module_type' => 1,
]);
return (new ApplyFiltersToQuery())->execute(
Company::query()->with([
'companyModules.employees',
'companyModules.connections.segments',
'contacts'
]),
['has_business_module_type' => 1]
);
}
public function map($company): array
{
$company_module = $company->companyModules()->first();
$marking = $company_module->getMarking();
$employees = $company_module->employees()->first();
$companyModule = $company->companyModules->first();
$marking = $companyModule ? $companyModule->getMarking() : '';
$creditTermCustomer = '';
if ($companyModule && $companyModule->connections->first()) {
$creditTermCustomer = $companyModule->connections->first()->is_credit_term ? 'YES' : 'NO';
}
$data = [
$employeeEmail = '';
if ($companyModule && $companyModule->employees->first()) {
$employeeEmail = $companyModule->employees->first()->email;
}
$contactPhone = '';
if ($company->contacts->first()) {
$contactPhone = $company->contacts->first()->phone;
}
$segments = '';
if ($companyModule && $companyModule->connections->first()) {
$segments = $companyModule->connections->first()->segments->pluck('name')->implode(', ');
}
return [
$marking,
$company->name,
$company->contacts()->first()->phone ?? '',
$employees?->email ?? '',
$company->created_at,
$company->updated_at,
$company_module->connections()->first()->segments()->pluck('name')->implode(', ')
$contactPhone,
$employeeEmail,
$company->created_at ? $company->created_at->toDateString() : '',
$company->updated_at ? $company->updated_at->toDateString() : '',
$company->debtor,
$creditTermCustomer,
$segments,
];
return $data;
}
}
@@ -0,0 +1,70 @@
<?php
namespace App\Classes\Modules\Rules\ControllersLogic;
use App\Classes\Exceptions\CriteriaNotFulfilledException;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Rules\DataTransferObjects\CheckEInvoiceRuleDTO;
use App\Classes\Modules\Rules\Services\RuleEvaluator;
use App\Classes\Modules\Rules\Standards\Rules\CanPassEInvoicePromptedRule;
use App\Classes\Modules\Rules\Standards\Rules\CanPassTINRule;
use App\Http\Resources\RuleResource;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class CheckEInvoiceRuleLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Rule Check E-Invoice',
'message' => 'You have successfully passed all rules evaluated'
];
}
/** @var RuleEvaluator */
private $ruleEvaluator;
/** @var CanPassEInvoicePromptedRule */
private $canPassEInvoicePromptedRule;
/** @var CanPassTINRule */
private $canPassTINRule;
/**
* CheckEInvoiceRuleLogic constructor.
*/
public function __construct(RuleEvaluator $ruleEvaluator, CanPassEInvoicePromptedRule $canPassEInvoicePromptedRule, CanPassTINRule $canPassTINRule)
{
$this->ruleEvaluator = $ruleEvaluator;
$this->canPassEInvoicePromptedRule = $canPassEInvoicePromptedRule;
$this->canPassTINRule = $canPassTINRule;
}
/**
* @param Request $request
* @return JsonResponse
* @throws \App\Classes\Exceptions\AccessForbiddenException
* @throws \App\Classes\Exceptions\MalformedRequestException
* @throws \App\Classes\Exceptions\RequestValidationException
* @throws \App\Classes\Exceptions\CriteriaNotFulfilledException
*/
public function logic(Request $request) : JsonResponse
{
$dto = new CheckEInvoiceRuleDTO($request->all());
$result = $this->ruleEvaluator->evaluate([
$this->canPassEInvoicePromptedRule,
$this->canPassTINRule,
], $dto);
if ($result->failed()) {
throw new CriteriaNotFulfilledException("- " . implode("<br>- ", $result->messages()));
}
return $this->resourceResponse(new RuleResource((object)$result));
}
}
@@ -0,0 +1,22 @@
<?php
namespace App\Classes\Modules\Rules\DataTransferObjects;
use App\Classes\General\Interfaces\DataTransferObject;
class CheckEInvoiceRuleDTO implements DataTransferObject
{
public int $companyModuleId;
public function __construct(array $data)
{
$this->companyModuleId = $data['company_module_id'];
}
public function toArray(): array
{
return [
'company_module_id' => $this->companyModuleId,
];
}
}
@@ -0,0 +1,44 @@
<?php
namespace App\Classes\Modules\Rules\Services;
use App\Classes\General\Abstracts\AbstractRule;
use App\Classes\General\Interfaces\DataTransferObject;
use App\Classes\Exceptions\AccessForbiddenException;
use App\Classes\Exceptions\CriteriaNotFulfilledException;
use App\Classes\Exceptions\RequestValidationException;
use App\Classes\ValueObjects\Response\RuleEvaluationResult;
class RuleEvaluator //For using AbstractRule
{
/**
* Evaluate multiple rules.
*
* @param AbstractRule[] $rules
* @param DataTransferObject|null $object
* @return RuleEvaluationResult
*/
public function evaluate(array $rules, ?DataTransferObject $object = null): RuleEvaluationResult
{
$messages = [];
$success = true;
foreach ($rules as $rule) {
try {
if (!$rule->passes($object)) {
$success = false;
$messages[] = get_class($rule) . ' failed without exception';
}
} catch (AccessForbiddenException | RequestValidationException | CriteriaNotFulfilledException $e) {
$success = false;
$messages[] = $e->getMessage();
} catch (\Exception $e) {
$success = false;
$messages[] = 'Unexpected error in ' . get_class($rule) . ': ' . $e->getMessage();
}
}
return new RuleEvaluationResult($success, $messages);
}
}
@@ -0,0 +1,57 @@
<?php
namespace App\Classes\Modules\Rules\Standards\Rules;
use App\Classes\Exceptions\CriteriaNotFulfilledException;
use App\Classes\General\Abstracts\AbstractRule;
use App\Classes\Modules\Companies\Services\FetchesCompanyModule;
use Illuminate\Support\Facades\Log;
class CanPassEInvoicePromptedRule extends AbstractRule
{
/** @var FetchesCompanyModule */
private $fetchesCompanyModule;
/**
* CanPassEInvoicePromptedRule constructor.
* @param FetchesCompanyModule $fetchesCompanyModule
*/
public function __construct(FetchesCompanyModule $fetchesCompanyModule)
{
$this->fetchesCompanyModule = $fetchesCompanyModule;
}
/**
* @return bool
*/
protected function authorized($object): bool
{
return true;
}
/**
* @return bool
*/
protected function validators($object): bool
{
return true;
}
/**
* @return bool
*/
protected function criteria($object): bool
{
//Check if account requires E-Invoice
$companyModule = $this->fetchesCompanyModule->execute(['id' => $object->companyModuleId]);
if($companyModule->company->e_invoice === null){
throw new CriteriaNotFulfilledException("Please refresh page to answer question related to E-Invoice.");
}
return true;
}
}
@@ -0,0 +1,55 @@
<?php
namespace App\Classes\Modules\Rules\Standards\Rules;
use App\Classes\Exceptions\CriteriaNotFulfilledException;
use App\Classes\General\Abstracts\AbstractRule;
use App\Classes\Modules\Companies\Services\FetchesCompanyModule;
class CanPassTINRule extends AbstractRule
{
/** @var FetchesCompanyModule */
private $fetchesCompanyModule;
/**
* CanPassTINRule constructor.
* @param FetchesCompanyModule $fetchesCompanyModule
*/
public function __construct(FetchesCompanyModule $fetchesCompanyModule)
{
$this->fetchesCompanyModule = $fetchesCompanyModule;
}
/**
* @return bool
*/
protected function authorized($object): bool
{
return true;
}
/**
* @return bool
*/
protected function validators($object): bool
{
return true;
}
/**
* @return bool
*/
protected function criteria($object): bool
{
//Check if TIN already provided if account requires E-Invoice
$companyModule = $this->fetchesCompanyModule->execute(['id' => $object->companyModuleId]);
if($companyModule->company->e_invoice === 1 && !$companyModule->company->tin){
throw new CriteriaNotFulfilledException("Please provide all requested E-Invoice Info.");
}
return true;
}
}
@@ -10,4 +10,6 @@ final class AddressType {
public const PICK_UP = 3;
public const E_INVOICE = 4;
}
@@ -0,0 +1,30 @@
<?php
namespace App\Classes\ValueObjects\Response;
class RuleEvaluationResult
{
public bool $success = true;
public array $messages = [];
public function __construct(bool $success = true, array $messages = [])
{
$this->success = $success;
$this->messages = $messages;
}
public function failed(): bool
{
return ! $this->success;
}
public function passed(): bool
{
return $this->success;
}
public function messages(): array
{
return $this->messages;
}
}
@@ -0,0 +1,20 @@
<?php
namespace App\Http\Controllers\Companies;
use App\Classes\Modules\Companies\ControllersLogic\FetchCompanyEInvoiceInfoLogic;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class FetchCompanyEInvoiceInfoController
{
/**
* @param Request $request
* @param FetchCompanyEInvoiceInfoLogic $logic
* @return JsonResponse
*/
public function fetch(Request $request, FetchCompanyEInvoiceInfoLogic $logic): JsonResponse {
return $logic->execute($request);
}
}
@@ -0,0 +1,21 @@
<?php
namespace App\Http\Controllers\Companies;
use App\Classes\Modules\Companies\ControllersLogic\UpdateCompanyDetailsLogic;
use App\Http\Controllers\Controller;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class UpdateCompanyDetailsController extends Controller
{
/**
* @param Request $request
* @param UpdateCompanyDetailsLogic $logic
* @return JsonResponse
*/
public function update(Request $request, UpdateCompanyDetailsLogic $logic) : JsonResponse
{
return $logic->execute($request);
}
}
@@ -0,0 +1,29 @@
<?php
namespace App\Http\Controllers\Companies;
use App\Classes\Modules\Companies\ControllersLogic\UpdateCompanyEInvoiceInfoLogic;
use App\Classes\Modules\Companies\ControllersLogic\UpdateCompanyEInvoiceRequestLogic;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class UpdateCompanyEInvoiceInfoController
{
/**
* @param Request $request
* @param UpdateCompanyEInvoiceInfoLogic $logic
* @return JsonResponse
*/
public function updateInfo(Request $request, UpdateCompanyEInvoiceInfoLogic $logic): JsonResponse {
return $logic->execute($request);
}
/**
* @param Request $request
* @param UpdateCompanyEInvoiceRequestLogic $logic
* @return JsonResponse
*/
public function updateRequest(Request $request, UpdateCompanyEInvoiceRequestLogic $logic): JsonResponse {
return $logic->execute($request);
}
}
@@ -87,7 +87,7 @@ class ExportCompanyModuleSummaryController
}
$exportsAllCustomersInfoForLarkSystem = new ExportsAllCustomersInfoForLarkSystem($request);
$exportFileName = 'all_customers_info_for_lark_system.xls';
$exportFileName = 'shipping_all_customers_info_for_lark_system.xls';
$filesystemDriver = Storage::getDefaultDriver();
if ($filesystemDriver === 's3') {
@@ -0,0 +1,19 @@
<?php
namespace App\Http\Controllers\Rules;
use App\Classes\Modules\Rules\ControllersLogic\CheckEInvoiceRuleLogic;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class CheckRuleController
{
/**
* @param Request $request
* @param CheckEInvoiceRuleLogic $logic
* @return JsonResponse
*/
public function checkEInvoiceRule(Request $request, CheckEInvoiceRuleLogic $logic): JsonResponse {
return $logic->execute($request);
}
}
+1
View File
@@ -75,5 +75,6 @@ class Kernel extends HttpKernel
'storage.invoice.check.bytransactions' => \App\Http\Middleware\CheckForStorageInvoiceByTransactions::class,
'storage.invoice.check.bygroup' => \App\Http\Middleware\CheckForStorageInvoiceByGroup::class,
'storage.invoice.check.bypackinglists' => \App\Http\Middleware\CheckForStorageInvoiceByPackingLists::class,
'admin' => \App\Http\Middleware\EnsureUserIsAdmin::class, //cief todo: 90 - maintenance
];
}
+32
View File
@@ -0,0 +1,32 @@
<?php
namespace App\Http\Middleware;
use App\Classes\ValueObjects\Constants\RoleTypes;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Tymon\JWTAuth\Facades\JWTAuth;
class EnsureUserIsAdmin
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
*/
public function handle(Request $request, Closure $next)
{
$maintenanceTitle = env('MAINTENANCE_MESSAGE_TITLE', null);
if (!empty($maintenanceTitle)) {
$user = JWTAuth::parseToken()->authenticate();
if(!in_array($user->type, RoleTypes::ADMIN_ROLES)){
return response()->view('errors.503', [], 503);
}
}
return $next($request);
}
}
@@ -0,0 +1,28 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class AddressEInvoiceResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'street_one' => $this->street_one,
'street_two' => $this->street_two,
'district' => $this->district,
'state' => $this->state,
'post_code' => (string) $this->postcode,
'country' => $this->country,
'billing' => (int) $this->billing
];
}
}
@@ -51,6 +51,10 @@ class CompanyModuleResource extends JsonResource
'connections' => $this->connections,
'contact' => new ContactResource ($this->when($this->has('contacts'), $this->contacts->first())),
'debtor' => $this->company->debtor,
'e_invoice' => $this->company->e_invoice,
'tin' => $this->company->tin,
'msic_code' => $this->company->msic_code,
'address_einvoice' => $this->company->e_invoice ? new AddressEInvoiceResource($this->when($this->has('addresses'), $this->addresses->where('type', AddressType::E_INVOICE)->sortByDesc('created_at')->first())) : null,
];
}
@@ -0,0 +1,31 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class EInvoiceInfoResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'street_one' => $this->street_one,
'street_two' => $this->street_two,
'district' => $this->district,
'state' => $this->state,
'post_code' => (string) $this->postcode,
'country' => $this->country,
'billing' => (int) $this->billing,
'msic_code' => (string) $this->msic_code,
'tin' => (string) $this->tin,
'e_invoice' => (int) $this->e_invoice,
];
}
}
+22
View File
@@ -0,0 +1,22 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class RuleResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'isPassed' => $this->success,
'messages' => $this->messages,
];
}
}
+6
View File
@@ -0,0 +1,6 @@
<?php
return [
'title' => env('MAINTENANCE_MESSAGE_TITLE', "We'll be back soon!"),
'message' => env('MAINTENANCE_MESSAGE', "Sorry for the inconvenience but we're performing some maintenance at the moment."),
];
@@ -0,0 +1,38 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddTinToCompaniesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('companies', function (Blueprint $table) {
$table->string('tin')->nullable()->after('debtor');
$table->string('msic_code')->nullable()->after('debtor')->comment("5-digit code representing business activity");
$table->timestamp('e_invoice_requested_at')->nullable()->after('debtor');
$table->boolean('e_invoice')->nullable()->default(null)->after('debtor');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('companies', function (Blueprint $table) {
$table->dropColumn('tin');
$table->dropColumn('msic_code');
$table->dropColumn('e_invoice_requested_at');
$table->dropColumn('e_invoice');
});
}
}
@@ -16,7 +16,8 @@
<div class="row">
<div class="col">
<modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in" type="changeCustomerName">
<change-customer-name-form-component :section="'customerProfileSection'" :data="item"></change-customer-name-form-component>
<!-- <change-customer-name-form-component :section="'customerProfileSection'" :data="item"></change-customer-name-form-component> -->
<change-customer-company-details-form-component :section="'customerProfileSection'" :data="item"></change-customer-company-details-form-component>
</modal-component>
<div class="font-heading fs-20 light">
{{item.name}}
@@ -158,14 +159,14 @@
<div class="row align-items-center">
<div class="col">
<h6 class="no-margin fs-12">Company Type </h6>
<modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in" type="changeBusinessType">
<!-- <modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in" type="changeBusinessType">
<change-business-type-form-component :section="'customerProfileSection'" :data="item"></change-business-type-form-component>
</modal-component>
</modal-component> -->
<h6 class="no-margin">
{{item.type_name}}
<div class="btn btn-xs b-rad-none pointer requestModal d-inline rounded no-border hover-primary bg-transparent" data-type="changeBusinessType" v-if="$store.getters.isAdmin">
<!-- <div class="btn btn-xs b-rad-none pointer requestModal d-inline rounded no-border hover-primary bg-transparent" data-type="changeBusinessType" v-if="$store.getters.isAdmin">
<i class="fa fa-edit pointer fa-fw fs-15 m-l-5"></i>
</div>
</div> -->
</h6>
</div>
</div>
@@ -0,0 +1,68 @@
<template>
<div class="row p-t-20 text-left">
<div class="col bg-white padding-30 b-rad-lg">
<div class="row">
<div class="col text-center">
<h3>E-Invoice Info</h3>
</div>
</div>
<div class="row" v-if="eInvoiceData && eInvoiceData.district">
<div class="col">
<div class="padding-15 bg-master-lightest m-b-10">
<p class="muted">TIN</p>
<p class="m-b-0 text-info">{{ eInvoiceData.tin }}</p>
</div>
<div class="padding-15 bg-master-lightest m-b-10" v-if="eInvoiceData.msic_code !== '0'">
<p class="muted">MSIC Code</p>
<p class="m-b-0 text-info">{{ eInvoiceData.msic_code }}</p>
</div>
<div class="padding-15 bg-master-lightest">
<p class="muted">Billing Address</p>
<p class="mb-0 text-info">
<a data-toggle="collapse" href="#billingDetails" role="button" aria-expanded="false" aria-controls="billingDetails">
{{eInvoiceData.street_one}} {{eInvoiceData.street_two}}, {{eInvoiceData.district.name}}, {{eInvoiceData.post_code}} {{eInvoiceData.state.name}}, {{eInvoiceData.country.name}}
</a>
</p>
<div class="collapse mt-2" id="billingDetails">
<ul class="list-unstyled mb-0 text-info">
<li><strong>Street 1:</strong> {{eInvoiceData.street_one}}</li>
<li><strong>Street 2:</strong> {{eInvoiceData.street_two}}</li>
<li><strong>District:</strong> {{eInvoiceData.district.name}}</li>
<li><strong>Postcode:</strong> {{eInvoiceData.post_code}}</li>
<li><strong>State:</strong> {{eInvoiceData.state.name}}</li>
<li><strong>Country:</strong> {{eInvoiceData.country.name}}</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
companyId: {
type: Number,
required: true
}
},
data(){
return {
eInvoiceData: null,
}
},
created(){
this.fetchData();
},
methods: {
fetchData(){
this.submit(route('api.company.einvoice.info', this.companyId), 'get', 'eInvoiceInfoViewOnlySection', false, true)
},
successHandler(response){
this.eInvoiceData = response.payload.data;
}
}
}
</script>
@@ -0,0 +1,246 @@
<template>
<div class="row p-t-25 text-left">
<div class="col bg-white padding-40 b-rad-lg">
<div class="row" v-if="step === 1">
<div class="col">
<div class="row">
<div class="col">
<div class="row m-b-15">
<div class="col text-danger">
Please check carefully, you will not be able to edit this after confirm
</div>
</div>
<div class="row m-b-15">
<div class="col-6 p-r-5">
<validation-wrapper-component :validator="$v.parameters.tin">
<label class="text-primary">TIN</label>
<input class="form-control" name="tin" v-model="parameters.tin">
</validation-wrapper-component>
</div>
<div class="col-6 p-l-5">
<validation-wrapper-component :validator="$v.parameters.msic_code">
<label class="text-primary">
MSIC Code
<a href="https://sdk.myinvois.hasil.gov.my/codes/msic-codes/" target="_blank" rel="noopener noreferrer">
(View List)
</a>
</label>
<input class="form-control" name="msic_code" v-model="parameters.msic_code">
</validation-wrapper-component>
</div>
</div>
<div class="row m-b-15">
<div class="col">
<validation-wrapper-component :validator="$v.parameters.street_one">
<label class="text-primary">Billing Address Line 1</label>
<input class="form-control" name="street_one" v-model="parameters.street_one">
</validation-wrapper-component>
</div>
</div>
<div class="row m-b-15">
<div class="col">
<validation-wrapper-component :validator="$v.parameters.street_two">
<label class="text-primary">Billing Address Line 2</label>
<input class="form-control" name="street_two" v-model="parameters.street_two">
</validation-wrapper-component>
</div>
</div>
<div class="row m-b-15">
<div class="col-7 p-r-5">
<validation-wrapper-component selectable :validator="$v.parameters.district_id">
<label class="text-primary">District</label>
<selectable-component :endpoint="route('api.address.district.list')" section="districtListSection" valueColumn="id" :labelColumn="['city']" v-model="parameters.district_id"></selectable-component>
</validation-wrapper-component>
</div>
<div class="col-5 p-l-5">
<validation-wrapper-component :validator="$v.parameters.post_code">
<label class="text-primary">Post Code</label>
<input class="form-control" name="post_code" v-model="parameters.post_code">
</validation-wrapper-component>
</div>
</div>
<div class="row m-b-15">
<div class="col-6 p-r-5">
<validation-wrapper-component selectable :validator="$v.parameters.state_id">
<label class="text-primary">State</label>
<selectable-component :endpoint="route('api.address.state.list')" section="stateListSection" valueColumn="id" :labelColumn="['name']" v-model="parameters.state_id"></selectable-component>
</validation-wrapper-component>
</div>
</div>
</div>
</div>
<div class="row m-b-15">
<div class="col">
<div class="row">
<div class="col text-right">
<button type="button"
class="btn btn-success btn-block b-rad-none"
@click="updateStep(2)">Update E-Invoice Info</button>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row" v-if="step === 2">
<div class="col">
<div class="row m-b-15">
<div class="col">
<div class="row m-b-15">
<div class="col text-danger">
Please check carefully, you will not be able to edit this after confirm
</div>
</div>
<div class="row">
<div class="col">
<div class="padding-15 bg-master-lightest">
<p class="muted">TIN</p>
<p class="m-b-0 text-info">{{parameters.tin}}</p>
</div>
</div>
</div>
<div class="row">
<div class="col">
<div class="padding-15 bg-master-lightest" v-if="parameters.msic_code !== 0">
<p class="muted">MSIC Code</p>
<p class="m-b-0 text-info">{{parameters.msic_code}}</p>
</div>
</div>
</div>
<div class="row">
<div class="col">
<div class="padding-15 bg-master-lightest">
<p class="muted">Billing Address</p>
<p class="m-b-0 text-info">{{parameters.street_one}} {{parameters.street_two}}, {{districts[parseFloat(parameters.district_id) - 1].text}} {{parameters.post_code}} {{states[parseFloat(parameters.state_id) - 1].text}}, Malaysia</p>
</div>
</div>
</div>
</div>
</div>
<div class="row m-b-15">
<div class="col">
<div class="row">
<div class="col-auto p-r-5">
<button type="button" class="btn bg-master-lighter b-rad-none" @click="updateStep(1)">Edit E-Invoice Info</button>
</div>
<div class="col p-l-0">
<button type="button" class="btn btn-success btn-block b-rad-none" @click="submitForm()">Confirm E-Invoice Info</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import ModalFormHandler from '../../../general/mixins/modalFormHandler';
import { required, minLength, maxLength, alphaNum, helpers } from 'vuelidate/lib/validators'
function mustContainLetterAndNumber(value) {
if (!value) return true;
const hasLetter = /[a-zA-Z]/.test(value);
const hasNumber = /\d/.test(value);
return hasLetter && hasNumber;
}
function notZero(value) {
return value !== 0 && value !== '0' && value !== null && value !== undefined
}
function fiveDigits(value) {
return /^\d{5}$/.test(value)
}
export default {
props: {
companyModuleId: {
type: Number,
required: true
},
companyType: {
type: Number,
required: true
},
},
watch: {
'company_module_id': function() {
this.parameters.company_module_id = this.companyModuleId;
},
},
computed: {
districts () { //cief todo: 90
return this.$store.getters.getSelectableList('districtListSection');
},
states () {
return this.$store.getters.getSelectableList('stateListSection');
}
},
data() {
return {
step: 1,
parameters : {
company_module_id: this.companyModuleId,
street_one: '',
street_two: '',
district_id: '',
state_id: '',
post_code: 0,
tin: '',
msic_code: 0,
}
}
},
validations() {
const companyType = this.companyType
return {
parameters: {
street_one: { required },
street_two: {},
district_id: { required },
state_id: { required },
post_code: { notZero, fiveDigits},
tin: {
...(companyType === 0
? {
required,
alphaNum,
minLength: minLength(10), //was 11
maxLength: maxLength(13)
}
: {}),
...(companyType === 1
? {
required,
alphaNum,
minLength: minLength(10),
maxLength: maxLength(13) ///was 12
}
: {})
},
msic_code: companyType === 1 ? {
notZero, fiveDigits
}: {},
}
}
},
methods:{
updateStep(step){
if(step === 2){
if(!this.validate()){ return; }
}
this.step = step
},
submitForm(){
this.submit((this.route('api.company.einvoice.info.update')), 'post', this.section, true, true);
},
successHandler(response){
this.$emit('eInvoiceInfoUpdated', response.payload.data);
this.closeModal();
}
},
mixins: [ModalFormHandler],
}
</script>
@@ -0,0 +1,65 @@
<template>
<div class="row">
<div class="col bg-white padding-40 b-rad-lg">
<loading-component style="height: 300px; top: 0;" key="1" color="success" v-show="isLoading" />
<div class="row justify-content-center" v-show="!isLoading">
<div class="col">
<div class="row m-b-20">
<div class="col">
<h3 class="all-caps">Do you need E-Invoice?</h3>
<div class="fs-11 text-black">You won't be able to request one after clicking 'No'.</div>
</div>
</div>
<div class="row">
<div class="col p-r-5">
<div class="btn btn-sm btn-block b-rad-none btn-danger" @click="handleChoice(false)">No</div>
</div>
<div class="col p-l-5">
<div class="btn btn-sm btn-block b-rad-none btn-success" @click="handleChoice(true)">Yes</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import componentHandler from '../../../general/mixins/componentHandler';
import ModalFormHandler from '../../../general/mixins/modalFormHandler';
export default {
props: {
section: {
type: String,
required: false
},
companyModuleId: {
type: Number,
required: true
}
},
data() {
return {
parameters : {
company_module_id: this.companyModuleId,
}
}
},
methods: {
handleChoice(choice) {
this.parameters.e_invoice_request = choice ? true : false;
this.$emit('choice-made', { choice });
this.submitForm();
},
submitForm() {
return this.submit(route('api.company.einvoice.request.update'), 'post', this.section, true, true);
},
successHandler() {
this.closeModal();
this.formHandler();
}
},
mixins: [componentHandler, ModalFormHandler]
}
</script>
@@ -58,12 +58,52 @@
</div>
</div>
</div>
<div class="col-auto" v-if="!company.company_module.e_invoice && !company.company_module.tin">
<div class="btn-lg btn-primary b-a b-white pointer fs-14 position-relative bg-transparent requestModal" data-type="requestEInvoiceA" style="z-index: 2;">
<span >
Submit E-Invoice Info
</span>
</div>
</div>
<div class="col-auto" v-else>
<div class="btn-lg btn-primary b-a b-white pointer fs-14 position-relative bg-transparent requestModal" data-type="eInvoiceInfo" style="z-index: 2;">
<span>
View E-Invoice Info
</span>
</div>
</div>
<div class="col-auto">
<div class="btn-lg btn-primary b-a b-white pointer fs-14 position-relative bg-transparent requestModal" data-type="billingAddressComponent" style="z-index: 2;">Change Billing Address</div>
</div>
<modal-component class="animate__animated animate__fast animate__fadeIn" v-if="company.company_module.tin" styleType="fill-in" type="eInvoiceInfo">
<e-invoice-info-component :company-id="company.id"></e-invoice-info-component>
</modal-component>
<modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in" type="billingAddressComponent">
<billing-address-section-component :company_module_id="company.company_module.id" :section="section"></billing-address-section-component>
</modal-component>
<modal-component
id="modal-einvoice-request"
class="animate__animated animate__fast animate__fadeIn"
styleType="fill-in" type="requestEInvoiceA" size="large" :disableClose="true">
<e-invoice-request-form-component
class="text-center"
:section="section"
:company-module-id="company.company_module.id"
/>
</modal-component>
<modal-component
id="modal-einvoice-info"
class="animate__animated animate__fast animate__fadeIn"
styleType="fill-in" type="requestEInvoiceB" size="large" :disableClose="true">
<e-invoice-info-form-component
:section="section"
:company-module-id="company.company_module.id"
:company-type="company.type"
v-on:eInvoiceInfoUpdated="updatedEInvoiceInfo($event)"
v-on:close="createAddress = !createAddress">
</e-invoice-info-form-component>
</modal-component>
</div>
</div>
</div>
@@ -90,6 +130,7 @@
required: true,
}
},
data(){
return {
section: 'orderListSection',
@@ -100,7 +141,7 @@
computed: {
pendingQueue () {
return this.$store.getters.isInCompleteQueue(this.section);
}
},
},
watch: {
pendingQueue(inComplete){
@@ -117,11 +158,41 @@
this.isLoading = true;
this.submit(route('api.company.show', this.company_id), 'get', this.section, false, false)
},
successHandler(response){
successHandler(response, section){
this.$store.dispatch('completeList', {'name': this.section, 'data': []});
this.isLoading = false;
this.company = response.payload.data;
}
if(!this.$store.getters.isAdmin){
if(this.company.company_module.e_invoice === null){
this.$nextTick(() => {
$('#modal-einvoice-request').modal('show');
});
}
else if( this.company.company_module.e_invoice && (this.company.company_module.tin === null || this.company.company_module.msic_code === null) )
{
this.$nextTick(() => {
$('#modal-einvoice-info').modal('show');
});
}
}
else{
if( this.company.company_module.e_invoice && (this.company.company_module.tin === null || this.company.company_module.msic_code === null) )
{
this.$nextTick(() => {
$('#modal-einvoice-info').modal('show');
});
}
}
},
errorHandler(error, statusCode, section) { //E-Invoice
if(section === this.section + 'CheckEInvoiceRule' && statusCode === 422){
$('#modal-einvoice-info').modal('show');
}
},
updatedEInvoiceInfo(info){
this.$store.dispatch('reloadList', {'name': this.section});
},
}
}
</script>
@@ -1,5 +1,6 @@
<template>
<div class="modal modalContainer fade" :class="styleType" :data-type="type">
<div class="modal modalContainer fade" :class="styleType" :data-type="type"
v-bind="disableClose ? { 'data-backdrop': 'static', 'data-keyboard': 'false' } : {}">
<div class="modal-dialog" v-bind:class="[{'modal-lg': size === 'large'}, {'modal-xl': size === 'extra-large'}, {'modal-sm': size === 'small'}]">
<div class="modal-content">
<div class="modal-body">
@@ -22,7 +23,11 @@
styleType: {
type: String,
default: "stick-up"
},
disableClose: {
type: Boolean,
default: false
}
}
},
}
</script>
@@ -0,0 +1,156 @@
<template>
<span>
<a :class="[customClass, { 'link-disabled': isDownloading }]" @click.prevent="showPasswordModal">
<slot></slot>
<span v-if="isDownloading" class="spinner"></span>
</a>
<modal-component styleType="fill-in" type="passwordPrompt" @close="closeModal">
<div class="row bg-white p-t-45 p-b-45 p-l-45 p-r-45">
<div class="col">
<h4 class="m-b-20 text-center">Enter Password</h4>
<div class="form-group">
<input type="password" class="form-control" v-model="password" placeholder="Enter password" @keyup.enter="handleDownload">
</div>
<div class="text-danger m-b-10" v-if="error">{{ error }}</div>
<div class="row">
<div class="col-6">
<button class="btn btn-default btn-block" @click="closeModal">Cancel</button>
</div>
<div class="col-6">
<button class="btn btn-primary btn-block" @click="handleDownload" :disabled="isDownloading">
Download
</button>
</div>
</div>
</div>
</div>
</modal-component>
</span>
</template>
<script>
export default {
props: {
url: {
type: String,
required: true,
},
customClass: {
type: String,
default: ''
}
},
data() {
return {
isDownloading: false,
password: '',
error: '',
modalVisible: false
};
},
methods: {
showPasswordModal() {
this.password = '';
this.error = '';
this.$nextTick(() => {
$('.modalContainer[data-type="passwordPrompt"]').modal('show');
});
},
closeModal() {
$('.modalContainer[data-type="passwordPrompt"]').modal('hide');
},
async handleDownload() {
if (!this.password) {
this.error = 'Please enter a password';
return;
}
this.isDownloading = true;
this.error = '';
try {
const response = await fetch(this.url + '?password=' + this.password, {
method: 'GET',
headers: {
'Authorization': 'Bearer ' + this.$store.getters.getAccessToken,
},
});
if (response.status === 403) {
this.error = 'Invalid password';
this.isDownloading = false;
return;
}
if (response.status === 200) {
// Check if response is JSON
const contentType = response.headers.get('content-type');
if (contentType && contentType.includes('application/json')) {
const data = await response.json();
if (data.src) {
// If JSON contains a file URL, trigger download
window.location.href = data.src;
this.closeModal();
return;
}
}
// Handle direct file download
const contentDisposition = response.headers.get('Content-Disposition');
const filename = contentDisposition ? contentDisposition.split('filename=')[1] : 'downloaded_file';
const blob = await response.blob();
const blobUrl = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = blobUrl;
a.download = filename;
a.style.display = 'none';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
window.URL.revokeObjectURL(blobUrl);
this.closeModal();
} else {
this.error = 'Download failed';
}
} catch (error) {
console.error('Network error:', error);
this.error = 'Network error occurred';
} finally {
this.isDownloading = false;
}
}
}
};
</script>
<style scoped>
.spinner {
border: 2px solid rgba(0, 0, 0, 0.1);
border-left-color: #000;
border-radius: 50%;
width: 20px;
height: 20px;
animation: spin 1s linear infinite;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
@keyframes spin {
0% {
transform: translate(-50%, -50%) rotate(0deg);
}
100% {
transform: translate(-50%, -50%) rotate(360deg);
}
}
.link-disabled {
pointer-events: none;
opacity: 0.6;
border: none;
}
</style>
@@ -2,9 +2,13 @@
<div v-if="validator.$error" class="text-danger fs-10">
<small class="bold" v-for="(object, param) in validator.$params" v-if="!validator[param]">
{{errorMessages[param]}}
<span v-if="object.type === 'minLength'">{{object.min}} characters</span>
<span v-if="object.type === 'sameAs'">{{object.eq}} field</span>
<span v-if="object.type === 'minValue'">{{object.min}}</span>
<span v-if="object && object.type === 'minLength'">{{object.min}} characters</span>
<span v-if="object && object.type === 'maxLength'">{{object.max}} characters</span>
<span v-if="object && object.type === 'sameAs'">{{object.eq}} field</span>
<span v-if="object && object.type === 'minValue'">{{object.min}}</span>
<span v-if="object && object.type === 'maxValue'">{{errorMessages[param]}} {{object.max}}</span>
<span v-if="object && object.type === 'alphaNum'">{{errorMessages[param]}}</span>
<span v-if="object && object.type === 'fiveDigits'">{{ errorMessages[param] }}</span>
</small>
</div>
</template>
@@ -22,9 +26,13 @@
required: 'this field is required',
email: 'enter a valid email address',
minLength: 'this field must have at least',
maxLength: 'this field must have at most',
minValue: 'this field must at least be',
sameAs: 'this field must match the',
numeric: 'this field can only contain numbers'
numeric: 'this field can only contain numbers',
maxValue: 'this value must not exceeds',
alphaNum: 'this value must be alphanumeric',
fiveDigits: 'this value must be exactly 5 digits', //custom
},
}
},
@@ -102,7 +102,7 @@
<div class="col no-padding">
<div class="row">
<div class="col">
<a :href="route('order.show', item.reference)">
<a @click="checkEInvoiceRule()" href="javascript:void(0);">
<div class="btn btn-sm btn-default bg-master-lighter no-border btn-block b-rad-none">More Details</div>
</a>
</div>
@@ -145,10 +145,10 @@
</transition-component>
</div>
<modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in" type="cancelOrder">
<cancel-order-form-component :data="item" section="oderList" class="text-center"></cancel-order-form-component>
<cancel-order-form-component :data="item" :section="section" class="text-center"></cancel-order-form-component>
</modal-component>
<modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in" type="restoreOrder">
<restore-order-form-component :data="item" section="oderList" class="text-center"></restore-order-form-component>
<restore-order-form-component :data="item" :section="section" class="text-center"></restore-order-form-component>
</modal-component>
</div>
</template>
@@ -160,10 +160,18 @@
},
data(){
return {
expanded: false
expanded: false,
section: 'orderList'
}
},
methods: {
successHandler(response, section){
if(section === this.section + 'CheckEInvoiceRule'){
if(response.payload.data.isPassed){
window.location.href = route('order.show', this.item.reference);
}
}
},
download(param) {
let url = route('order.qr.download', param.id);
if(window.LARAVEL_VAPOR_ENABLED){
@@ -185,6 +193,17 @@
window.open(url, '_blank');
}
},
checkEInvoiceRule(){
if(!this.$store.getters.isAdmin){
this.parameters = {
company_module_id: this.item.company_module.id,
};
this.submit(route('api.rule.check.einvoice'), 'post', this.section + 'CheckEInvoiceRule', false, true);
}
else{
window.location.href = route('order.show', this.item.reference);
}
},
},
mixins: [componentHandler]
}
@@ -0,0 +1,222 @@
<template>
<div class="row" style="width: 450px; margin: auto;" @keyup.enter="submitForm">
<div class="col bg-white padding-40 b-rad-lg">
<div class="row m-b-10">
<div class="col text-center">
<h3>Edit Company Details</h3>
</div>
</div>
<div class="row m-b-15">
<div class="col">
<validation-wrapper-component :validator="$v.parameters.name">
<label class="text-primary">Name</label>
<input class="form-control" v-model="parameters.name">
</validation-wrapper-component>
</div>
</div>
<div class="row m-b-15">
<div class="col">
<validation-wrapper-component :validator="$v.parameters.debtor">
<label class="text-primary">Debtor Code</label>
<input class="form-control" v-model="parameters.debtor">
</validation-wrapper-component>
</div>
</div>
<div class="row m-t-15 m-b-15">
<div class="col p-r-5">
<div class="b-grey b-a w-100 text-center p-l-15 p-r-15 p-t-10 p-b-10 pointer fs-15" :class="[{'b-primary': parameters.type === 0}]" @click="updateType(0)">Personal<br>Business</div>
</div>
<div class="col p-l-5">
<div class="b-grey b-a w-100 text-center p-l-15 p-r-15 p-t-10 p-b-10 pointer fs-15" :class="[{'b-primary': parameters.type === 1}]" @click="updateType(1)">Company<br>Business</div>
</div>
</div>
<div class="row m-b-15" v-if="data.identification">
<div class="col">
<validation-wrapper-component :validator="$v.parameters.identification_reference">
<label class="text-primary">{{ data.type === 0 ? 'Identification Card' : 'SSM Registration' }}</label>
<input class="form-control" v-model="parameters.identification_reference">
</validation-wrapper-component>
</div>
</div>
<div class="row m-b-5" v-if="data.company_module.e_invoice !== 0 && data.company_module.e_invoice !== null">
<div class="col">
E-Invoice Info
<div class="row m-b-15">
<div class="col-6 p-r-5">
<validation-wrapper-component :validator="$v.parameters.tin">
<label class="text-primary">TIN</label>
<input class="form-control" v-model="parameters.tin">
</validation-wrapper-component>
</div>
<div class="col-6 p-l-5">
<validation-wrapper-component :validator="$v.parameters.msic_code">
<label class="text-primary">
MSIC Code
<a href="https://sdk.myinvois.hasil.gov.my/codes/msic-codes/" target="_blank" rel="noopener noreferrer">
(View List)
</a>
</label>
<input class="form-control" name="msic_code" v-model="parameters.msic_code">
</validation-wrapper-component>
</div>
</div>
<div class="row m-b-15">
<div class="col">
<validation-wrapper-component :validator="$v.parameters.street_one">
<label class="text-primary">Billing Address Line 1</label>
<input class="form-control" name="street_one" v-model="parameters.street_one">
</validation-wrapper-component>
</div>
</div>
<div class="row m-b-15">
<div class="col">
<validation-wrapper-component :validator="$v.parameters.street_two">
<label class="text-primary">Billing Address Line 2</label>
<input class="form-control" name="street_two" v-model="parameters.street_two">
</validation-wrapper-component>
</div>
</div>
<div class="row m-b-15">
<div class="col-7 p-r-5">
<validation-wrapper-component selectable :validator="$v.parameters.district_id">
<label class="text-primary">District</label>
<selectable-component :endpoint="route('api.address.district.list')" section="districtListSection" valueColumn="id" :labelColumn="['city']" v-model="parameters.district_id"></selectable-component>
</validation-wrapper-component>
</div>
<div class="col-5 p-l-5">
<validation-wrapper-component :validator="$v.parameters.post_code">
<label class="text-primary">Post Code</label>
<input class="form-control" v-model="parameters.post_code">
</validation-wrapper-component>
</div>
</div>
<div class="row m-b-15">
<div class="col-6 p-r-5">
<validation-wrapper-component selectable :validator="$v.parameters.state_id">
<label class="text-primary">State</label>
<selectable-component :endpoint="route('api.address.state.list')" section="stateListSection" valueColumn="id" :labelColumn="['name']" v-model="parameters.state_id"></selectable-component>
</validation-wrapper-component>
</div>
</div>
</div>
</div>
<div class="row m-t-15">
<div class="col-auto p-r-5">
<div class="btn btn-lg btn-default b-rad-none" data-dismiss="modal">Cancel</div>
</div>
<div class="col p-l-5">
<div class="btn btn-primary w-100 btn-lg" @click="submitForm">Confirm</div>
</div>
</div>
</div>
</div>
</template>
<script>
import modalFormHandler from '../../../general/mixins/modalFormHandler';
import { required, minLength, maxLength, alphaNum, helpers } from 'vuelidate/lib/validators'
function mustContainLetterAndNumber(value) {
if (!value) return true;
const hasLetter = /[a-zA-Z]/.test(value);
const hasNumber = /\d/.test(value);
return hasLetter && hasNumber;
}
function notZero(value) {
return value !== 0 && value !== '0' && value !== null && value !== undefined
}
function fiveDigits(value) {
return /^\d{5}$/.test(value)
}
export default {
data() {
return {
parameters: {
id: this.data.id,
name: this.data.name,
debtor: this.data.debtor,
reference: this.data.reference,
type: this.data.type,
tin: this.data.company_module.tin,
email: this.data.employee.email,
employeeId: this.data.employee.id,
msic_code: this.data.company_module.msic_code,
address_id: this.data.company_module.address_einvoice ? this.data.company_module.address_einvoice.id : null,
street_one: this.data.company_module.address_einvoice ? this.data.company_module.address_einvoice.street_one : null,
street_two: this.data.company_module.address_einvoice ? this.data.company_module.address_einvoice.street_two : null,
district_id: this.data.company_module.address_einvoice ? this.data.company_module.address_einvoice.district.id : null,
state_id: this.data.company_module.address_einvoice ? this.data.company_module.address_einvoice.state.id : null,
post_code: this.data.company_module.address_einvoice ? this.data.company_module.address_einvoice.post_code : null,
identification_id: this.data.identification ? this.data.identification.id : null,
identification_reference: this.data.identification ? this.data.identification.reference : null,
}
};
},
validations() {
const companyType = this.data.type;
const isEInvoiceEnabled = this.data.company_module.e_invoice !== 0 && this.data.company_module.e_invoice !== null;
return {
parameters: {
name: {
required,
},
debtor: {},
email: {
required,
},
tin: isEInvoiceEnabled
? {
...(companyType === 0
? {
required,
alphaNum,
minLength: minLength(10), //was 11
maxLength: maxLength(13)
}
: {}),
...(companyType === 1
? {
required,
alphaNum,
minLength: minLength(10),
maxLength: maxLength(13) //was 12
}
: {})
}
: {},
msic_code: isEInvoiceEnabled && companyType === 1 ? {
notZero, fiveDigits
}: {},
address_id: {},
street_one: isEInvoiceEnabled ? { required } : {},
street_two: {},
district_id: isEInvoiceEnabled ? { required } : {},
state_id: isEInvoiceEnabled ? { required } : {},
post_code: isEInvoiceEnabled ? { required, notZero } : {},
identification_reference: this.data.identification ? { required } : {},
}
}
},
methods: {
successHandler(response) {
this.$store.dispatch('reloadList', {'name': 'orderListSection'});
this.closeModal();
},
submitForm() {
this.submit(this.route('api.company.update.details', this.data.id), 'put', this.section, true, true)
},
updateType(type) {
this.parameters.type = type;
},
},
mixins: [modalFormHandler]
}
</script>
+7 -2
View File
@@ -13,16 +13,21 @@ export default {
let statusCode = response.status,
success = response.ok;
// console.log('statusCode: ' + statusCode); //cief todo: 90 - maintenance
if(statusCode == 503){
window.location.href = '/maintenance';
}
response.json().then(response => {
if(!success){
this.openModal();
errorNotification ? this.$store.dispatch('createNotification', {title: response.title, message: response.message, type: 'error'}): null;
this.errorHandler(response, statusCode); return;
this.errorHandler(response, statusCode, section); return;
}
successNotification ? this.$store.dispatch('createNotification', {title: response.title, message: response.message, type: 'success'}): null;
this.successHandler(response, section)
this.successHandler(response, section, this.parameters);
});
+3 -2
View File
@@ -22,8 +22,9 @@
</head>
<body>
<div class="content">
<h1>We'll be back soon!</h1>
<p>Sorry for the inconvenience but we're performing some maintenance at the moment. We'll be back online shortly!</p>
<h1>{{ config('maintenance.title') }}</h1>
<img src="{{ asset('images/maintenance.png') }}" alt="Maintenance" style="max-width: 300px; margin-bottom: 20px;">
<p>{{ config('maintenance.message') }}</p>
<p>&mdash; CIEF IZYIM</p>
</div>
</body>
@@ -158,5 +158,21 @@
</div>
</div>
<div class="col-12" v-if="$store.getters.isSuperAdmin">
<h4>Customer Downloads</h4>
<div class="row">
<div class="col-md-6">
<div class="card mb-3">
<div class="card-body d-flex justify-content-between align-items-center">
<span>shipping_all_customers_info_for_lark_system.xls</span>
<password-protected-download-component custom-class="btn btn-primary" :url="route('exportAllCustomersInfoForLarkSystem.export')">
<i class="fa fa-download"></i> Download
</password-protected-download-component>
</div>
</div>
</div>
</div>
</div>
</div>
@endsection
+27 -24
View File
@@ -27,53 +27,56 @@ Route::group(['middleware' => 'api', 'prefix' => 'v1', 'as' => 'api.'], function
require __DIR__ . '/feedback.php';
Route::group(['middleware' => 'valid.token'], function () {
Route::group(['middleware' => 'admin'], function () { //cief todo: 90 - maintenance
Route::get('/storage/{fileName}/fetch', 'Documents\RenderDocumentController@fileStorageServe')->where(['fileName' => '.*'])->name('storage.document.file');
Route::get('/storage/{fileName}/fetch', 'Documents\RenderDocumentController@fileStorageServe')->where(['fileName' => '.*'])->name('storage.document.file');
Route::post('online_payment/callback', 'Billplz\CallbackBillplzController@callback')->name('online_payment.callback');
Route::post('online_payment/callback', 'Billplz\CallbackBillplzController@callback')->name('online_payment.callback');
Route::post('/import/update-debtor/f614e339d7058904a831aad742e24d55', 'Imports\ImportUpdateDebtorController@import')->name('debtor.import');
Route::post('/import/update-debtor/f614e339d7058904a831aad742e24d55', 'Imports\ImportUpdateDebtorController@import')->name('debtor.import');
require __DIR__ . '/company.php';
require __DIR__ . '/company.php';
require __DIR__ . '/document.php';
require __DIR__ . '/document.php';
require __DIR__ . '/bank.php';
require __DIR__ . '/bank.php';
require __DIR__ . '/currency.php';
require __DIR__ . '/currency.php';
require __DIR__ . '/address.php';
require __DIR__ . '/address.php';
require __DIR__ . '/transaction.php';
require __DIR__ . '/transaction.php';
require __DIR__ . '/receipt.php';
require __DIR__ . '/receipt.php';
require __DIR__ . '/order.php';
require __DIR__ . '/order.php';
require __DIR__ . '/packing_list.php';
require __DIR__ . '/packing_list.php';
require __DIR__ . '/remark.php';
require __DIR__ . '/remark.php';
require __DIR__ . '/transport.php';
require __DIR__ . '/transport.php';
require __DIR__ . '/schedule.php';
require __DIR__ . '/schedule.php';
require __DIR__ . '/segment.php';
require __DIR__ . '/segment.php';
require __DIR__ . '/announcement.php';
require __DIR__ . '/announcement.php';
require __DIR__ . '/report.php';
require __DIR__ . '/report.php';
require __DIR__ . '/wallet.php';
require __DIR__ . '/wallet.php';
require __DIR__ . '/contact.php';
require __DIR__ . '/contact.php';
require __DIR__ . '/help_menu.php';
require __DIR__ . '/help_menu.php';
require __DIR__ . '/permits_reminder.php';
require __DIR__ . '/job.php';
require __DIR__ . '/permits_reminder.php';
require __DIR__ . '/job.php';
require __DIR__ . '/rule.php';
});
});
require __DIR__ . '/announcement.php';
+8
View File
@@ -1,6 +1,9 @@
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\Companies\UpdateCompanyEInvoiceInfoController;
use App\Http\Controllers\Companies\FetchCompanyEInvoiceInfoController;
use App\Http\Controllers\Companies\UpdateCompanyDetailsController;
Route::group(['prefix' => 'company', 'as' => 'company.', 'namespace' => 'Companies'], function () {
Route::get('/{id}/show', 'FetchCompanyController@fetch')->name('show');
@@ -39,4 +42,9 @@ Route::group(['prefix' => 'company', 'as' => 'company.', 'namespace' => 'Compani
});
Route::get('/module/list', 'ListCompanyModulesController@list')->name('module.list');
Route::put('/details/update/{id}', [UpdateCompanyDetailsController::class, 'update'])->name('update.details');
Route::get('/e-invoice/info/{id}', [FetchCompanyEInvoiceInfoController::class, 'fetch'])->name('einvoice.info');
Route::post('/e-invoice/info/update', [UpdateCompanyEInvoiceInfoController::class, 'updateInfo'])->name('einvoice.info.update');
Route::post('/e-invoice/request/update', [UpdateCompanyEInvoiceInfoController::class, 'updateRequest'])->name('einvoice.request.update');
});
+10
View File
@@ -0,0 +1,10 @@
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\Rules\CheckRuleController;
Route::prefix('rule')
->as('rule.')
->group(function () {
Route::post('/check/eInvoice', [CheckRuleController::class, 'checkEInvoiceRule'])->name('check.einvoice');
});
+18
View File
@@ -215,6 +215,12 @@ Route::get('/orders-table', function () {
Route::get('/order/show/{order_number}', function (Illuminate\Http\Request $request, $orderNumber) {
// return view('pages.orders.profile', ['id' => $orderNumber]);
// $order = Order::where('reference', $orderNumber)->first();
// $isValid = $order->companyModule->company->e_invoice !== null;
// if (!$isValid) {
// return redirect()->route('dashboard');
// }
return view('pages.orders.profile_v2', [
'id' => $orderNumber,
'q' => $request->query('q', null)
@@ -274,6 +280,13 @@ Route::get('/customer/{marking}/payment-and-billing', function ($marking) {
Route::get('/customer-invoices/{company_module_id}/payment-and-billing', function ($company_module_id) {
// todo-new: check company_module_id
// $companyModule = CompanyModule::where('id', $company_module_id)->first();
// $isValid = $companyModule->company->e_invoice !== null;
// if (!$isValid) {
// return redirect()->route('dashboard');
// }
return view('pages.customers.paymentsBilling', ['company_module_id' => $company_module_id]);
})->name('customer.payment-and-billing-by-company-module-id');
@@ -1420,3 +1433,8 @@ Route::get('/group-transaction-with-completed-payments', function () {
Route::get('/downloads', function () {
return view('pages.downloads.index');
})->name('admin.downloads');
Route::get('/maintenance', function () {
return response()->view('errors.503', [], 503);
});