Compare commits
2 Commits
Author | SHA1 | Date |
---|---|---|
|
6707790943 | |
|
6e4c332dea |
12
.env.example
12
.env.example
|
@ -19,14 +19,14 @@ BROADCAST_DRIVER=log
|
|||
CACHE_DRIVER=file
|
||||
SESSION_DRIVER=file
|
||||
SESSION_LIFETIME=120
|
||||
QUEUE_CONNECTION=database
|
||||
QUEUE_DRIVER=database
|
||||
|
||||
REDIS_HOST=127.0.0.1
|
||||
REDIS_PASSWORD=null
|
||||
REDIS_PORT=6379
|
||||
|
||||
MAIL_DRIVER=smtp
|
||||
MAIL_HOST=smtp
|
||||
MAIL_HOST=MAIL
|
||||
MAIL_PORT=25
|
||||
MAIL_USERNAME=null
|
||||
MAIL_PASSWORD=null
|
||||
|
@ -43,13 +43,13 @@ MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
|
|||
EZYPAY_TOKEN=
|
||||
EZYPAY_GUID=
|
||||
|
||||
QUICKBOOKS_CLIENT_ID=
|
||||
QUICKBOOKS_CLIENT_SECRET=
|
||||
QUICKBOOKS_API_URL=Production
|
||||
|
||||
AUTH_GOOGLE_CLIENT_ID=
|
||||
AUTH_GOOGLE_SECRET=
|
||||
|
||||
AUTH_INTUIT_CLIENT_ID=
|
||||
AUTH_INTUIT_SECRET_KEY=
|
||||
INTUIT_VERIFYTOKEN=
|
||||
|
||||
PAYPAL_MODE=sandbox
|
||||
PAYPAL_SANDBOX_CLIENT_ID=
|
||||
PAYPAL_SANDBOX_SECRET=
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
stages:
|
||||
- test
|
||||
- build
|
||||
- test
|
||||
- build
|
||||
|
||||
# This folder is cached between builds
|
||||
# http://docs.gitlab.com/ce/ci/yaml/README.html#cache
|
||||
cache:
|
||||
key: ${CI_JOB_NAME_SLUG}-${CI_COMMIT_REF_SLUG}
|
||||
key: ${CI_COMMIT_REF_SLUG}
|
||||
paths:
|
||||
- vendor/
|
||||
- vendor/
|
||||
|
||||
include:
|
||||
- .gitlab-test.yml
|
||||
- .gitlab-docker-x86_64.yml
|
||||
- .gitlab-test.yml
|
||||
- .gitlab-docker-x86_64.yml
|
||||
|
|
|
@ -1,27 +1,33 @@
|
|||
docker:
|
||||
variables:
|
||||
VERSION: latest
|
||||
DOCKER_HOST: tcp://docker:2375
|
||||
image: docker:latest
|
||||
|
||||
stage: build
|
||||
|
||||
image: docker:latest
|
||||
services:
|
||||
- docker:dind
|
||||
- docker:dind
|
||||
|
||||
variables:
|
||||
VERSION: latest
|
||||
CACHETAG: build-${VERSION}
|
||||
DOCKER_HOST: tcp://docker:2375
|
||||
|
||||
tags:
|
||||
- docker
|
||||
- x86_64
|
||||
only:
|
||||
- master
|
||||
|
||||
before_script:
|
||||
- docker info && docker version
|
||||
- echo "$CI_JOB_TOKEN" | docker login -u "$CI_REGISTRY_USER" "$CI_REGISTRY" --password-stdin
|
||||
- if [ -n "$GITHUB_TOKEN" ]; then cat $GITHUB_TOKEN |base64 -d > auth.json; fi
|
||||
- docker info
|
||||
- docker version
|
||||
- echo "$CI_JOB_TOKEN" | docker login -u "$CI_REGISTRY_USER" "$CI_REGISTRY" --password-stdin
|
||||
- if [ -n "$GITHUB_TOKEN" ]; then cat $GITHUB_TOKEN |base64 -d > auth.json; fi
|
||||
|
||||
script:
|
||||
- if [ -f init ]; then chmod 500 init; fi
|
||||
- echo -n ${CI_COMMIT_SHORT_SHA} > VERSION
|
||||
- rm -rf vendor/ database/schema database/seeders database/factories/*
|
||||
- docker build -t ${CI_REGISTRY_IMAGE}:${VERSION} .
|
||||
- docker push ${CI_REGISTRY_IMAGE}:${VERSION}
|
||||
tags:
|
||||
- docker
|
||||
- x86_64
|
||||
only:
|
||||
- master
|
||||
- if [ -f init ]; then chmod 500 init; fi
|
||||
- ([ -z "$REFRESH" ] && docker pull ${CI_REGISTRY_IMAGE}:${CACHETAG}) || echo "true"
|
||||
- echo -n ${CI_COMMIT_SHORT_SHA} > VERSION
|
||||
- rm -rf vendor/
|
||||
- docker build --cache-from ${CI_REGISTRY_IMAGE}:${CACHETAG} -t ${CI_REGISTRY_IMAGE}:${VERSION} -t ${CI_REGISTRY_IMAGE}:${CACHETAG} .
|
||||
- docker push ${CI_REGISTRY_IMAGE}:${VERSION}
|
||||
- docker push ${CI_REGISTRY_IMAGE}:${CACHETAG}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
test:
|
||||
image: ${CI_REGISTRY}/leenooks/php:8.1-fpm-alpine-mysql-test
|
||||
image: registry.leenooks.net/leenooks/php:8.0-fpm-ext-test
|
||||
|
||||
stage: test
|
||||
|
||||
# NOTE: This service is dependant on project file configuration, which is not there if the cache was deleted
|
||||
# resulting in the testing to fail on the first run.
|
||||
services:
|
||||
- mariadb:10.5
|
||||
- mariadb:10.5
|
||||
|
||||
variables:
|
||||
MYSQL_DATABASE: testing
|
||||
|
@ -15,34 +15,34 @@ test:
|
|||
MYSQL_PASSWORD: test
|
||||
|
||||
tags:
|
||||
- php
|
||||
- php
|
||||
only:
|
||||
- master
|
||||
- test
|
||||
- master
|
||||
- test
|
||||
|
||||
before_script:
|
||||
- mv .env.testing .env
|
||||
- mv .env.testing .env
|
||||
|
||||
# Install Composer and project dependencies.
|
||||
- mkdir -p ${COMPOSER_HOME}
|
||||
- if [ -n "$GITHUB_TOKEN" ]; then cat $GITHUB_TOKEN |base64 -d > ${COMPOSER_HOME}/auth.json; fi
|
||||
- composer install
|
||||
# Install Composer and project dependencies.
|
||||
- mkdir -p /root/.config/composer
|
||||
- if [ -n "$GITHUB_TOKEN" ]; then cat $GITHUB_TOKEN |base64 -d > /root/.config/composer/auth.json ; fi
|
||||
- composer install
|
||||
|
||||
# Add mysql client for schema pre-load
|
||||
- apt update -o Acquire::ForceIPv4=true && apt install -o Acquire::ForceIPv4=true -y mariadb-client
|
||||
# Add mysql client for schema pre-load
|
||||
- apt update && apt install -f mariadb-client
|
||||
|
||||
# Generate an application key. Re-cache.
|
||||
- php artisan key:generate --env=testing
|
||||
- php artisan config:cache --env=testing
|
||||
- php artisan migrate
|
||||
- php artisan db:seed
|
||||
# Generate an application key. Re-cache.
|
||||
- php artisan key:generate --env=testing
|
||||
- php artisan config:cache --env=testing
|
||||
- php artisan migrate
|
||||
- php artisan db:seed
|
||||
|
||||
script:
|
||||
# run laravel tests
|
||||
- XDEBUG_MODE=coverage php vendor/bin/phpunit --coverage-text --colors=never
|
||||
# run laravel tests
|
||||
- XDEBUG_MODE=coverage php vendor/bin/phpunit --coverage-text --colors=never
|
||||
|
||||
# run frontend tests
|
||||
# if you have any task for testing frontend
|
||||
# set it in your package.json script
|
||||
# comment this out if you don't have a frontend test
|
||||
# npm test
|
||||
# run frontend tests
|
||||
# if you have any task for testing frontend
|
||||
# set it in your package.json script
|
||||
# comment this out if you don't have a frontend test
|
||||
# npm test
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
FROM registry.dege.au/leenooks/php:8.1-fpm-alpine-mysql
|
||||
FROM registry.leenooks.net/leenooks/php:8.0-fpm-image
|
||||
|
||||
COPY . /var/www/html/
|
||||
|
||||
RUN mkdir -p ${COMPOSER_HOME} \
|
||||
&& ([ -r auth.json ] && mv auth.json ${COMPOSER_HOME}) || true \
|
||||
RUN export COMPOSER_HOME=/var/www/.composer \
|
||||
&& mkdir -p /var/www/.composer \
|
||||
&& ([ -r auth.json ] && mv auth.json /var/www/.composer/) || true \
|
||||
&& touch .composer.refresh \
|
||||
&& mv .env.example .env \
|
||||
&& FORCE_PERMS=1 NGINX_START=FALSE /sbin/init \
|
||||
&& chmod +x /var/www/html/artisan \
|
||||
&& /var/www/html/artisan storage:link \
|
||||
&& rm -rf ${COMPOSER_HOME}/* .git* composer.lock
|
||||
&& rm -rf /var/www/.composer
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
|
||||
namespace App\Classes\External;
|
||||
|
||||
abstract class Accounting
|
||||
{
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
|
||||
namespace App\Classes\External\Accounting;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use QuickBooksOnline\API\Data\IPPCustomer;
|
||||
|
||||
use App\Classes\External\Accounting as Base;
|
||||
use App\Models\User;
|
||||
|
||||
class Quickbooks extends Base
|
||||
{
|
||||
private $api = NULL;
|
||||
|
||||
public function __construct(User $uo)
|
||||
{
|
||||
if (Auth::user())
|
||||
throw new \Exception('User logged in - *TODO* handle this');
|
||||
|
||||
Auth::loginUsingId($uo->id);
|
||||
|
||||
$this->api = app('Spinen\QuickBooks\Client');
|
||||
}
|
||||
|
||||
public function getCustomers($refresh=FALSE): Collection
|
||||
{
|
||||
if ($refresh)
|
||||
Cache::forget(__METHOD__);
|
||||
|
||||
return Cache::remember(__METHOD__,86400,function() {
|
||||
return collect($this->api->getDataService()->Query('SELECT * FROM Customer'));
|
||||
});
|
||||
}
|
||||
|
||||
public function getInvoice(int $id,$refresh=FALSE)
|
||||
{
|
||||
if ($refresh)
|
||||
Cache::forget(__METHOD__.$id);
|
||||
|
||||
return Cache::remember(__METHOD__.$id,86400,function() use ($id) {
|
||||
return $this->api->getDataService()->Query(sprintf("SELECT * FROM Invoice where id = '%s'",$id));
|
||||
});
|
||||
}
|
||||
|
||||
public function getInvoices($refresh=FALSE): Collection
|
||||
{
|
||||
if ($refresh)
|
||||
Cache::forget(__METHOD__);
|
||||
|
||||
return Cache::remember(__METHOD__,86400,function() {
|
||||
return collect($this->api->getDataService()->Query('SELECT * FROM Invoice'));
|
||||
});
|
||||
}
|
||||
|
||||
public function updateCustomer(IPPCustomer $r,array $args)
|
||||
{
|
||||
$r->sparse = TRUE;
|
||||
|
||||
foreach ($args as $k=>$v)
|
||||
{
|
||||
$r->{$k} = $v;
|
||||
}
|
||||
|
||||
return $this->api->getDataService()->Update($r);
|
||||
}
|
||||
}
|
|
@ -30,8 +30,8 @@ class Ezypay extends Payments
|
|||
$api_remain = Arr::get($result->getHeader('X-RateLimit-Remaining'),0);
|
||||
$api_reset = Arr::get($result->getHeader('X-RateLimit-Reset'),0);
|
||||
|
||||
if ($api_remain === 0) {
|
||||
Log::error('API Throttle.',['m'=>__METHOD__,'api_reset'=>$api_reset]);
|
||||
if ($api_remain == 0) {
|
||||
Log::error('API Throttle.',['m'=>__METHOD__]);
|
||||
Cache::put('api_throttle',$api_reset,now()->addSeconds($api_reset));
|
||||
}
|
||||
|
||||
|
@ -45,56 +45,6 @@ class Ezypay extends Payments
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of configured customers
|
||||
*
|
||||
* @return Collection
|
||||
* @todo Hard coded at 100 clients - need to make this more dynamic
|
||||
*
|
||||
* {#1079
|
||||
* +"TermsAndConditions": true
|
||||
* +"Account": {#1082
|
||||
* +"PaymentMethodId": 0
|
||||
* }
|
||||
* +"Address1": "1 Road Street "
|
||||
* +"BillingStatus": "Active"
|
||||
* +"BusinessAccountReference": "12345"
|
||||
* +"CountryCode": "AU"
|
||||
* +"Email": "user@example.com"
|
||||
* +"EzypayReferenceNumber": 12345678
|
||||
* +"Firstname": "Bart"
|
||||
* +"Id": "6219c42b-8e56-4e4e-af3a-76ddf4b0e4e1"
|
||||
* +"MobilePhone": ""
|
||||
* +"Postcode": "1234"
|
||||
* +"ReferenceId": "01nnnn"
|
||||
* +"State": "VIC"
|
||||
* +"Suburb": "TOWN"
|
||||
* +"Towncity": ""
|
||||
* +"Surname": "Simpson "
|
||||
* +"PaymentPlanId": "00000000-0000-0000-0000-000000000000"
|
||||
* +"DateOfBirth": "1970-01-01T00:00:00.000"
|
||||
* +"Gender": "M"
|
||||
* +"DebitType": 0
|
||||
* +"RecurringAmount": 0.0
|
||||
* +"Frequency": 0
|
||||
* +"FrequencyType": 0
|
||||
* +"StartDate": "0001-01-01T00:00:00.000"
|
||||
* +"RecurringDebitEndType": 0
|
||||
* +"TotalAmountCollected": 0.0
|
||||
* +"MinimumNumberOfPayment": 0
|
||||
* +"RecurringWithDifferentFirstDebitAmount": 0.0
|
||||
* +"RecurringDebitFirstDebitDate": "0001-01-01T00:00:00.000"
|
||||
* +"RecurringDebitAmount": 0.0
|
||||
* +"RecurringDebitFrequency": 0
|
||||
* +"RecurringDebitFrequencyType": 0
|
||||
* +"RecurringDebitStartDate": "0001-01-01T00:00:00.000"
|
||||
* +"RecurringDebitDifferentFirstAmountEndType": 0
|
||||
* +"RecurringDebitTotalAmountCollected": 0.0
|
||||
* +"RecurringDebitMinimumNumberOfPayment": 0
|
||||
* +"OnceOffAmount": 0.0
|
||||
* +"OnceOffStartDate": "0001-01-01T00:00:00.000"
|
||||
* }
|
||||
*/
|
||||
public function getCustomers(): Collection
|
||||
{
|
||||
return Cache::remember(__METHOD__,86400,function() {
|
||||
|
@ -102,29 +52,6 @@ class Ezypay extends Payments
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Specific debits for a client.
|
||||
*
|
||||
* @param array $opt
|
||||
* @return Collection
|
||||
*
|
||||
* Illuminate\Support\Collection^ {#1077
|
||||
* #items: array:4 [
|
||||
* 0 => {#1826
|
||||
* +"Amount": 99.99
|
||||
* +"Id": "76666ef1-106c-458c-9162-e77fe746517c"
|
||||
* +"CustomerId": "6219c42b-8e56-4e4e-af3a-76ddf4b0e4e1"
|
||||
* +"Date": "2021-10-01T00:00:00.000"
|
||||
* +"Status": "Pending"
|
||||
* }
|
||||
* 1 => {#2075
|
||||
* +"Amount": 99.99
|
||||
* +"Id": "80ba201d-fb6f-4700-b1b7-2b13fbfa91d5"
|
||||
* +"CustomerId": "6219c42b-8e56-4e4e-af3a-76ddf4b0e4e1"
|
||||
* +"Date": "2021-09-01T00:00:00.000"
|
||||
* +"Status": "Pending"
|
||||
* }
|
||||
*/
|
||||
public function getDebits($opt=[]): Collection
|
||||
{
|
||||
return Cache::remember(__METHOD__.http_build_query($opt),86400,function() use ($opt) {
|
||||
|
|
|
@ -17,8 +17,6 @@ abstract class Supplier
|
|||
protected $o = NULL;
|
||||
protected $_columns = [];
|
||||
|
||||
public const traffic_connection_keys = ['user','pass','url'];
|
||||
|
||||
public function __construct(Model $o)
|
||||
{
|
||||
$this->o = $o;
|
||||
|
@ -28,29 +26,24 @@ abstract class Supplier
|
|||
/**
|
||||
* Connect and pull down traffic data
|
||||
*
|
||||
* @param array $connection
|
||||
* @param string $type
|
||||
* @return Collection
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function fetch(array $connection,string $type): Collection
|
||||
public function fetch(): Collection
|
||||
{
|
||||
if (count(array_intersect(array_keys($connection),self::traffic_connection_keys)) !== 3)
|
||||
throw new \Exception('No or missing connection details for:'.$type);
|
||||
|
||||
if ($x=$this->mustPause()) {
|
||||
Log::notice(sprintf('%s:API Throttle, waiting [%s]...',self::LOGKEY,$x),['m'=>__METHOD__]);
|
||||
sleep($x);
|
||||
}
|
||||
|
||||
Log::debug(sprintf('%s:Supplier [%d], fetch data for [%s]...',self::LOGKEY,$this->o->id,Arr::get($connection,'last')),['m'=>__METHOD__]);
|
||||
$key = 'Supplier:'.$this->o->id.Arr::get($connection,'last');
|
||||
Log::debug(sprintf('%s:Supplier [%d], fetch data for [%s]...',self::LOGKEY,$this->o->id,$this->o->stats_lastupdate),['m'=>__METHOD__]);
|
||||
$key = 'Supplier:'.$this->o->id.$this->o->stats_lastupdate;
|
||||
$result = Cache::remember($key,86400,function() {
|
||||
$client = $this->getClient();
|
||||
|
||||
$result = Cache::remember($key,86400,function() use ($connection) {
|
||||
$response = Http::get(Arr::get($connection,'url'),[
|
||||
$this->login_user_field => Arr::get($connection,'user'),
|
||||
$this->login_pass_field => Arr::get($connection,'pass'),
|
||||
$this->date_field => Arr::get($connection,'last'),
|
||||
$response = Http::get($this->o->stats_url,[
|
||||
$this->login_user_field => $this->o->stats_username,
|
||||
$this->login_pass_field => $this->o->stats_password,
|
||||
$this->date_field => $this->o->stats_lastupdate->format('Y-m-d'),
|
||||
]);
|
||||
|
||||
// @todo These API rate limiting is untested.
|
||||
|
@ -62,6 +55,7 @@ abstract class Supplier
|
|||
Cache::put('api_throttle',$api_reset,now()->addSeconds($api_reset));
|
||||
}
|
||||
|
||||
//dd($response->header('Content-Type'),$response->headers());
|
||||
// Assume the supplier provides an ASCII output for text/html
|
||||
if (preg_match('#^text/html;#',$x=$response->header('Content-Type'))) {
|
||||
return collect(explode("\n",$response->body()))->filter();
|
||||
|
|
|
@ -1,62 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Intuit\Jobs\AccountingCustomerUpdate;
|
||||
use Intuit\Models\Customer as AccAccount;
|
||||
|
||||
use App\Models\{Account,ProviderOauth,Site,User};
|
||||
|
||||
class AccountingAccountAdd extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'accounting:account:add'
|
||||
.' {siteid : Site ID}'
|
||||
.' {provider : Provider Name}'
|
||||
.' {user : User Email}'
|
||||
.' {id : Account ID}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Add an account to the accounting provider';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$site = Site::findOrFail($this->argument('siteid'));
|
||||
Config::set('site',$site);
|
||||
|
||||
$uo = User::where('email',$this->argument('user'))->singleOrFail();
|
||||
|
||||
$so = ProviderOauth::where('name',$this->argument('provider'))->singleOrFail();
|
||||
if (! ($to=$so->token($uo)))
|
||||
abort(500,sprintf('Unknown Tokens for [%s]',$uo->email));
|
||||
|
||||
$o = Account::findOrFail($this->argument('id'));
|
||||
|
||||
$acc = new AccAccount;
|
||||
$acc->PrimaryEmailAddr = (object)['Address'=>$o->user->email];
|
||||
$acc->ResaleNum = $o->sid;
|
||||
$acc->GivenName = $o->user->firstname;
|
||||
$acc->FamilyName = $o->user->lastname;
|
||||
$acc->CompanyName = $o->name;
|
||||
$acc->DisplayName = $o->name;
|
||||
$acc->FullyQualifiedName = $o->name;
|
||||
$acc->Active = (bool)$o->active;
|
||||
|
||||
return AccountingCustomerUpdate::dispatchSync($to,$acc);
|
||||
}
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use GuzzleHttp\Exception\ConnectException;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Intuit\Exceptions\ConnectionIssueException;
|
||||
|
||||
use App\Models\{ProviderOauth,Site,User};
|
||||
|
||||
class AccountingAccountGet extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'accounting:account:get'
|
||||
.' {siteid : Site ID}'
|
||||
.' {provider : Provider Name}'
|
||||
.' {user : User Email}'
|
||||
.' {id : Account ID}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Get an account from the accounting provider';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$site = Site::findOrFail($this->argument('siteid'));
|
||||
Config::set('site',$site);
|
||||
|
||||
$uo = User::where('email',$this->argument('user'))->singleOrFail();
|
||||
|
||||
$so = ProviderOauth::where('name',$this->argument('provider'))->singleOrFail();
|
||||
if (! ($to=$so->token($uo)))
|
||||
abort(500,sprintf('Unknown Tokens for [%s]',$uo->email));
|
||||
|
||||
try {
|
||||
$api = $to->API();
|
||||
dump($api->getAccountQuery($this->argument('id')));
|
||||
|
||||
} catch (ConnectException|ConnectionIssueException $e) {
|
||||
$this->error($e->getMessage());
|
||||
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
|
||||
use App\Models\{ProviderOauth,Site,User};
|
||||
use App\Jobs\AccountingAccountSync as Job;
|
||||
|
||||
/**
|
||||
* Synchronise Customers with Accounts
|
||||
*/
|
||||
class AccountingAccountSync extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'accounting:account:sync'
|
||||
.' {siteid : Site ID}'
|
||||
.' {provider : Provider Name}'
|
||||
.' {user : User Email}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Synchronise accounts with accounting system';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$site = Site::findOrFail($this->argument('siteid'));
|
||||
Config::set('site',$site);
|
||||
|
||||
$uo = User::where('email',$this->argument('user'))->singleOrFail();
|
||||
|
||||
$so = ProviderOauth::where('name',$this->argument('provider'))->singleOrFail();
|
||||
if (! ($to=$so->token($uo)))
|
||||
abort(500,sprintf('Unknown Tokens for [%s]',$uo->email));
|
||||
|
||||
Job::dispatchSync($to);
|
||||
}
|
||||
}
|
|
@ -1,110 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Intuit\Jobs\AccountingInvoiceUpdate;
|
||||
use Intuit\Models\Invoice as AccInvoice;
|
||||
|
||||
use App\Models\{Invoice,ProviderOauth,Site,User};
|
||||
|
||||
class AccountingInvoiceAdd extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'accounting:invoice:add'
|
||||
.' {siteid : Site ID}'
|
||||
.' {provider : Provider Name}'
|
||||
.' {user : User Email}'
|
||||
.' {id : Invoice ID}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Add an invoice to the accounting provider';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$site = Site::findOrFail($this->argument('siteid'));
|
||||
Config::set('site',$site);
|
||||
|
||||
$uo = User::where('email',$this->argument('user'))->singleOrFail();
|
||||
|
||||
$so = ProviderOauth::where('name',$this->argument('provider'))->singleOrFail();
|
||||
if (! ($to=$so->token($uo)))
|
||||
abort(500,sprintf('Unknown Tokens for [%s]',$uo->email));
|
||||
|
||||
$o = Invoice::findOrFail($this->argument('id'));
|
||||
|
||||
// Check the customer exists
|
||||
if ($o->account->providers->where('pivot.provider_oauth_id',$so->id)->count() !== 1)
|
||||
throw new \Exception(sprintf('Account [%d] for Invoice [%d] not defined',$o->account_id,$o->id));
|
||||
|
||||
$ao = $o->account->providers->where('pivot.provider_oauth_id',$so->id)->pop();
|
||||
|
||||
// Some validation
|
||||
if (! $ao->pivot->ref) {
|
||||
$this->error(sprintf('Accounting not defined for account [%d]',$o->account_id));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$acc = new AccInvoice;
|
||||
$acc->CustomerRef = (object)['value'=>$ao->pivot->ref];
|
||||
$acc->DocNumber = $o->lid;
|
||||
$acc->TxnDate = $o->created_at->format('Y-m-d');
|
||||
$acc->DueDate = $o->due_at->format('Y-m-d');
|
||||
|
||||
$lines = collect();
|
||||
$c = 0;
|
||||
|
||||
// @todo Group these by ItemRef and the Same Unit Price and Description, so that we can then use quantity to represent the number of them.
|
||||
foreach ($o->items->groupBy(function($item) use ($so) {
|
||||
return sprintf('%s.%s.%s.%s',$item->item_type_name,$item->price_base,$item->product->provider_ref($so),$item->taxes->pluck('description')->join('|'));
|
||||
}) as $os)
|
||||
{
|
||||
$key = $os->first();
|
||||
|
||||
// Some validation
|
||||
if (! ($ref=$key->product->provider_ref($so))) {
|
||||
$this->error(sprintf('Accounting not defined in product [%d]',$key->product_id));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ($key->taxes->count() !== 1) {
|
||||
$this->error(sprintf('Cannot handle when there is not just 1 tax line [%d]',$key->id));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$c++;
|
||||
$line = new \stdClass;
|
||||
$line->Id = $c;
|
||||
$line->DetailType = 'SalesItemLineDetail';
|
||||
$line->Description = $key->item_type_name;
|
||||
$line->SalesItemLineDetail = (object)[
|
||||
'Qty' => $os->sum('quantity'),
|
||||
'UnitPrice' => $key->price_base,
|
||||
'ItemRef' => ['value'=>$ref],
|
||||
// @todo It is assumed there is only 1 tax category
|
||||
'TaxCodeRef' => ['value'=>$key->taxes->first()->tax->provider_ref($so)],
|
||||
];
|
||||
$line->Amount = $os->sum('quantity')*$key->price_base;
|
||||
|
||||
$lines->push($line);
|
||||
}
|
||||
|
||||
$acc->Line = $lines;
|
||||
|
||||
return AccountingInvoiceUpdate::dispatchSync($to,$acc);
|
||||
}
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use GuzzleHttp\Exception\ConnectException;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Intuit\Exceptions\ConnectionIssueException;
|
||||
|
||||
use App\Models\{ProviderOauth,Site,User};
|
||||
|
||||
class AccountingInvoiceGet extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'accounting:invoice:get'
|
||||
.' {siteid : Site ID}'
|
||||
.' {provider : Provider Name}'
|
||||
.' {user : User Email}'
|
||||
.' {id : Invoice ID}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Get an invoice from the accounting provider';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$site = Site::findOrFail($this->argument('siteid'));
|
||||
Config::set('site',$site);
|
||||
|
||||
$uo = User::where('email',$this->argument('user'))->singleOrFail();
|
||||
|
||||
$so = ProviderOauth::where('name',$this->argument('provider'))->singleOrFail();
|
||||
if (! ($to=$so->token($uo)))
|
||||
abort(500,sprintf('Unknown Tokens for [%s]',$uo->email));
|
||||
|
||||
try {
|
||||
$api = $to->API();
|
||||
dump($api->getInvoiceQuery($this->argument('id')));
|
||||
|
||||
} catch (ConnectException|ConnectionIssueException $e) {
|
||||
$this->error($e->getMessage());
|
||||
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use App\Models\{Product, ProviderOauth, Site, User};
|
||||
use App\Jobs\AccountingItemSync as Job;
|
||||
|
||||
class AccountingItemList extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'accounting:item:list'
|
||||
.' {siteid : Site ID}'
|
||||
.' {provider : Provider Name}'
|
||||
.' {user : User Email}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Synchronise items with accounting system';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$site = Site::findOrFail($this->argument('siteid'));
|
||||
Config::set('site',$site);
|
||||
|
||||
$so = ProviderOauth::where('name',$this->argument('provider'))->singleOrFail();
|
||||
$uo = User::where('email',$this->argument('user'))->singleOrFail();
|
||||
|
||||
if (($x=$so->tokens->where('user_id',$uo->id))->count() !== 1)
|
||||
abort(500,sprintf('Unknown Tokens for [%s]',$uo->email));
|
||||
|
||||
$to = $x->pop();
|
||||
|
||||
// Current Products used by services
|
||||
$products = Product::select(['products.*'])
|
||||
->distinct('products.id')
|
||||
->join('services',['services.product_id'=>'products.id'])
|
||||
->where('services.active',TRUE)
|
||||
->get();
|
||||
|
||||
$api = $so->API($to,TRUE); // @todo Remove TRUE
|
||||
|
||||
$acc = $api->getItems()->pluck('pid','FullyQualifiedName');
|
||||
|
||||
foreach ($products as $po) {
|
||||
if (! $po->accounting)
|
||||
$this->error(sprintf('Product [%d](%s) doesnt have accounting set',$po->id,$po->name));
|
||||
|
||||
elseif ($acc->has($po->accounting) === FALSE)
|
||||
$this->error(sprintf('Product [%d](%s) accounting [%s] doesnt exist?',$po->id,$po->name,$po->accounting));
|
||||
|
||||
else
|
||||
$this->info(sprintf('Product [%d](%s) set to accounting [%s]',$po->id,$po->name,$po->accounting));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use GuzzleHttp\Exception\ConnectException;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Intuit\Exceptions\ConnectionIssueException;
|
||||
|
||||
use App\Jobs\AccountingPaymentSync as Job;
|
||||
use App\Models\{ProviderOauth,Site,User};
|
||||
|
||||
class AccountingPaymentGet extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'accounting:payment:get'
|
||||
.' {siteid : Site ID}'
|
||||
.' {provider : Provider Name}'
|
||||
.' {user : User Email}'
|
||||
.' {id : Payment ID}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Get a payment from the accounting provider';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$site = Site::findOrFail($this->argument('siteid'));
|
||||
Config::set('site',$site);
|
||||
|
||||
$uo = User::where('email',$this->argument('user'))->singleOrFail();
|
||||
|
||||
$so = ProviderOauth::where('name',$this->argument('provider'))->singleOrFail();
|
||||
if (! ($to=$so->token($uo)))
|
||||
abort(500,sprintf('Unknown Tokens for [%s]',$uo->email));
|
||||
|
||||
try {
|
||||
$api = $to->API();
|
||||
$acc = $api->getPayment($this->argument('id'));
|
||||
dump($acc);
|
||||
|
||||
} catch (ConnectException|ConnectionIssueException $e) {
|
||||
$this->error($e->getMessage());
|
||||
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
if ($acc)
|
||||
Job::dispatchSync($to,$acc);
|
||||
}
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
|
||||
use App\Models\{ProviderOauth,Site,User};
|
||||
use App\Jobs\AccountingPaymentSync as Job;
|
||||
|
||||
class AccountingPaymentSync extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'accounting:payment:sync'
|
||||
.' {siteid : Site ID}'
|
||||
.' {provider : Provider Name}'
|
||||
.' {user : User Email}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Synchronise payments with accounting system';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$site = Site::findOrFail($this->argument('siteid'));
|
||||
Config::set('site',$site);
|
||||
|
||||
$uo = User::where('email',$this->argument('user'))->singleOrFail();
|
||||
|
||||
$so = ProviderOauth::where('name',$this->argument('provider'))->singleOrFail();
|
||||
if (! ($to=$so->token($uo)))
|
||||
abort(500,sprintf('Unknown Tokens for [%s]',$uo->email));
|
||||
|
||||
$api = $to->API();
|
||||
foreach ($api->getPayments() as $acc)
|
||||
Job::dispatchSync($to,$acc);
|
||||
}
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
|
||||
use App\Models\{ProviderOauth,Site,User};
|
||||
use App\Jobs\AccountingTaxSync as Job;
|
||||
|
||||
/**
|
||||
* Synchronise TAX ids with our taxes.
|
||||
*/
|
||||
class AccountingTaxSync extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'accounting:tax:sync'
|
||||
.' {siteid : Site ID}'
|
||||
.' {provider : Provider Name}'
|
||||
.' {user : User Email}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Synchronise taxes with accounting system';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$site = Site::findOrFail($this->argument('siteid'));
|
||||
Config::set('site',$site);
|
||||
|
||||
$uo = User::where('email',$this->argument('user'))->singleOrFail();
|
||||
|
||||
$so = ProviderOauth::where('name',$this->argument('provider'))->singleOrFail();
|
||||
if (! ($to=$so->token($uo)))
|
||||
abort(500,sprintf('Unknown Tokens for [%s]',$uo->email));
|
||||
|
||||
Job::dispatchSync($to);
|
||||
}
|
||||
}
|
|
@ -5,7 +5,7 @@ namespace App\Console\Commands;
|
|||
use Illuminate\Console\Command;
|
||||
|
||||
use App\Jobs\BroadbandTraffic as Job;
|
||||
use App\Models\Supplier;
|
||||
use App\Models\AdslSupplier;
|
||||
|
||||
class BroadbandTraffic extends Command
|
||||
{
|
||||
|
@ -14,8 +14,7 @@ class BroadbandTraffic extends Command
|
|||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'broadband:traffic:import'.
|
||||
' {--s|supplier= : Supplier Name}';
|
||||
protected $signature = 'broadband:traffic:import';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
|
@ -31,14 +30,7 @@ class BroadbandTraffic extends Command
|
|||
*/
|
||||
public function handle()
|
||||
{
|
||||
if ($this->option('supplier')) {
|
||||
$o = Supplier::where('name','like',$this->option('supplier'))->singleOrFail();
|
||||
|
||||
Job::dispatchSync($o);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (Supplier::active()->get() as $o)
|
||||
Job::dispatchSync($o);
|
||||
foreach (AdslSupplier::active()->get() as $o)
|
||||
Job::dispatch($o);
|
||||
}
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
use App\Jobs\ImportCosts as Job;
|
||||
use App\Models\{Site,Supplier};
|
||||
|
||||
class ImportCosts extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'costs:import {siteid : Site ID} {supplier : Supplier Name} {file : Filename} {date : Date}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Import Costs from file';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
if (! str_starts_with($this->argument('file'),'files/'))
|
||||
throw new \Exception('Filename must start with files/');
|
||||
|
||||
Job::dispatchSync(
|
||||
Site::findOrFail($this->argument('siteid')),
|
||||
Supplier::where('name',$this->argument('supplier'))->singleOrFail(),
|
||||
Carbon::create($this->argument('date')),
|
||||
$this->argument('file'),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -2,11 +2,10 @@
|
|||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
use App\Models\{Invoice,Site};
|
||||
use App\Models\Invoice;
|
||||
|
||||
class InvoiceEmail extends Command
|
||||
{
|
||||
|
@ -15,7 +14,7 @@ class InvoiceEmail extends Command
|
|||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'invoice:email {site} {id}';
|
||||
protected $signature = 'invoice:email {id}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
|
@ -24,6 +23,16 @@ class InvoiceEmail extends Command
|
|||
*/
|
||||
protected $description = 'Email Invoices to be client';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
|
@ -31,19 +40,19 @@ class InvoiceEmail extends Command
|
|||
*/
|
||||
public function handle()
|
||||
{
|
||||
Config::set('site',Site::findOrFail($this->argument('site')));
|
||||
|
||||
$o = Invoice::findOrFail($this->argument('id'));
|
||||
|
||||
Mail::to($o->account->user->email)->send(new \App\Mail\InvoiceEmail($o));
|
||||
|
||||
try {
|
||||
if (Mail::failures()) {
|
||||
dump('Failure?');
|
||||
|
||||
dump(Mail::failures());
|
||||
|
||||
} else {
|
||||
$o->print_status = TRUE;
|
||||
$o->reminders = $o->reminders('send');
|
||||
$o->save();
|
||||
|
||||
} catch (\Exception $e) {
|
||||
dd($e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\Account;
|
||||
use App\Models\Invoice;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
|
||||
use App\Models\{Account,Invoice,Site};
|
||||
|
||||
class InvoiceGenerate extends Command
|
||||
{
|
||||
|
@ -14,7 +14,7 @@ class InvoiceGenerate extends Command
|
|||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'invoice:generate {site} {account?} {--p|preview : Preview} {--l|list : List Items}';
|
||||
protected $signature = 'invoice:generate {account?} {--p|preview : Preview} {--l|list : List Items}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
|
@ -23,6 +23,16 @@ class InvoiceGenerate extends Command
|
|||
*/
|
||||
protected $description = 'Generate Invoices to be Sent';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
|
@ -30,8 +40,6 @@ class InvoiceGenerate extends Command
|
|||
*/
|
||||
public function handle()
|
||||
{
|
||||
Config::set('site',Site::findOrFail($this->argument('site')));
|
||||
|
||||
if ($this->argument('account'))
|
||||
$accounts = collect()->push(Account::find($this->argument('account')));
|
||||
else
|
||||
|
|
|
@ -2,10 +2,11 @@
|
|||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
use App\Classes\External\Payments\Ezypay;
|
||||
use App\Jobs\PaymentsImport as Job;
|
||||
use App\Models\{Account,Checkout,Payment};
|
||||
|
||||
class PaymentsEzypayImport extends Command
|
||||
{
|
||||
|
@ -23,6 +24,16 @@ class PaymentsEzypayImport extends Command
|
|||
*/
|
||||
protected $description = 'Retrieve payments from Ezypay';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
|
@ -30,6 +41,67 @@ class PaymentsEzypayImport extends Command
|
|||
*/
|
||||
public function handle()
|
||||
{
|
||||
Job::dispatchSync(new Ezypay);
|
||||
$poo = new Ezypay();
|
||||
|
||||
// Get our checkout IDs for this plugin
|
||||
$cos = Checkout::where('plugin',config('services.ezypay.plugin'))->pluck('id');
|
||||
|
||||
foreach ($poo->getCustomers() as $c)
|
||||
{
|
||||
if ($c->BillingStatus == 'Inactive')
|
||||
{
|
||||
$this->info(sprintf('Ignoring INACTIVE: [%s] %s %s',$c->EzypayReferenceNumber,$c->Firstname,$c->Surname));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Load Account Details from ReferenceId
|
||||
$ao = Account::where('site_id',(int)substr($c->ReferenceId,0,2))
|
||||
->where('id',(int)substr($c->ReferenceId,2,4))
|
||||
->first();
|
||||
|
||||
if (! $ao)
|
||||
{
|
||||
$this->warn(sprintf('Missing: [%s] %s %s (%s)',$c->EzypayReferenceNumber,$c->Firstname,$c->Surname,$c->ReferenceId));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Find the last payment logged
|
||||
$last = Carbon::createFromTimestamp(Payment::whereIN('checkout_id',$cos)->where('account_id',$ao->id)->max('date_payment'));
|
||||
|
||||
$o = $poo->getDebits([
|
||||
'customerId'=>$c->Id,
|
||||
'dateFrom'=>$last->format('Y-m-d'),
|
||||
'dateTo'=>$last->addQuarter()->format('Y-m-d'),
|
||||
'pageSize'=>100,
|
||||
]);
|
||||
|
||||
// Load the payments
|
||||
if ($o->count())
|
||||
{
|
||||
foreach ($o->reverse() as $p)
|
||||
{
|
||||
// If not success, ignore it.
|
||||
if ($p->Status != 'Success')
|
||||
continue;
|
||||
|
||||
$pd = Carbon::createFromFormat('Y-m-d?H:i:s.u',$p->Date);
|
||||
$lp = $ao->payments->last();
|
||||
|
||||
if ($lp AND (($pd == $lp->date_payment) OR ($p->Id == $lp->checkout_data)))
|
||||
continue;
|
||||
|
||||
// New Payment
|
||||
$po = new Payment;
|
||||
$po->site_id = 1; // @todo
|
||||
$po->date_payment = $pd;
|
||||
$po->checkout_id = '999'; // @todo
|
||||
$po->checkout_data = $p->Id;
|
||||
$po->total_amt = $p->Amount;
|
||||
$ao->payments()->save($po);
|
||||
|
||||
$this->info(sprintf('Recorded: Payment for [%s] %s %s (%s) on %s',$c->EzypayReferenceNumber,$c->Firstname,$c->Surname,$po->id,$pd));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
use App\Classes\External\Payments\Ezypay;
|
||||
|
@ -24,6 +23,16 @@ class PaymentsEzypayNext extends Command
|
|||
*/
|
||||
protected $description = 'Load next payments, and ensure they cover the next invoice';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
|
@ -31,10 +40,12 @@ class PaymentsEzypayNext extends Command
|
|||
*/
|
||||
public function handle()
|
||||
{
|
||||
$poo = new Ezypay;
|
||||
$poo = new Ezypay();
|
||||
|
||||
foreach ($poo->getCustomers() as $c) {
|
||||
if ($c->BillingStatus == 'Inactive') {
|
||||
foreach ($poo->getCustomers() as $c)
|
||||
{
|
||||
if ($c->BillingStatus == 'Inactive')
|
||||
{
|
||||
$this->info(sprintf('Ignoring INACTIVE: [%s] %s %s',$c->EzypayReferenceNumber,$c->Firstname,$c->Surname));
|
||||
continue;
|
||||
}
|
||||
|
@ -42,9 +53,10 @@ class PaymentsEzypayNext extends Command
|
|||
// Load Account Details from ReferenceId
|
||||
$ao = Account::where('site_id',(int)substr($c->ReferenceId,0,2))
|
||||
->where('id',(int)substr($c->ReferenceId,2,4))
|
||||
->single();
|
||||
->first();
|
||||
|
||||
if (! $ao) {
|
||||
if (! $ao)
|
||||
{
|
||||
$this->warn(sprintf('Missing: [%s] %s %s (%s)',$c->EzypayReferenceNumber,$c->Firstname,$c->Surname,$c->ReferenceId));
|
||||
continue;
|
||||
}
|
||||
|
@ -58,33 +70,12 @@ class PaymentsEzypayNext extends Command
|
|||
'dateTo'=>now()->addQuarter()->format('Y-m-d'),
|
||||
])->reverse()->first();
|
||||
|
||||
if ($next_pay->Status !== 'Pending') {
|
||||
$this->warn(sprintf('Next payment is not pending for (%s)',$ao->name));
|
||||
continue;
|
||||
}
|
||||
|
||||
$next_paydate = Carbon::createFromTimeString($next_pay->Date);
|
||||
|
||||
if ($next_pay->Amount < $account_due)
|
||||
$this->warn(sprintf('Next payment on [%s] for (%s) [%s] not sufficient for outstanding balance [%s]',
|
||||
$next_paydate->format('Y-m-d'),
|
||||
$ao->name,
|
||||
number_format($next_pay->Amount,2),
|
||||
number_format($account_due,2)));
|
||||
|
||||
$this->warn(sprintf('Next payment for (%s) [%s] not sufficient for outstanding balance [%s]',$ao->name,number_format($next_pay->Amount,2),number_format($account_due,2)));
|
||||
elseif ($next_pay->Amount > $account_due)
|
||||
$this->warn(sprintf('Next payment on [%s] for (%s) [%s] is too much for outstanding balance [%s]',
|
||||
$next_paydate->format('Y-m-d'),
|
||||
$ao->name,
|
||||
number_format($next_pay->Amount,2),
|
||||
number_format($account_due,2)));
|
||||
|
||||
$this->warn(sprintf('Next payment for (%s) [%s] is too much for outstanding balance [%s]',$ao->name,number_format($next_pay->Amount,2),number_format($account_due,2)));
|
||||
else
|
||||
$this->info(sprintf('Next payment on [%s] for (%s) [%s] will cover outstanding balance [%s]',
|
||||
$next_paydate->format('Y-m-d'),
|
||||
$ao->name,
|
||||
number_format($next_pay->Amount,2),
|
||||
number_format($account_due,2)));
|
||||
$this->info(sprintf('Next payment for (%s) [%s] will cover outstanding balance [%s]',$ao->name,number_format($next_pay->Amount,2),number_format($account_due,2)));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
|
||||
use App\Models\{ProviderOauth,Site,User};
|
||||
use App\Jobs\ProviderTokenRefresh as Job;
|
||||
|
||||
class ProviderTokenRefresh extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'provider:token:refresh'
|
||||
.' {siteid : Site ID}'
|
||||
.' {provider : Supplier Name}'
|
||||
.' {user : User Email}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Refresh users access/refresh token';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$site = Site::findOrFail($this->argument('siteid'));
|
||||
Config::set('site',$site);
|
||||
|
||||
$so = ProviderOauth::where('name',$this->argument('provider'))->singleOrFail();
|
||||
$uo = User::where('email',$this->argument('user'))->singleOrFail();
|
||||
|
||||
if (($x=$so->tokens->where('user_id',$uo->id))->count() !== 1)
|
||||
abort(500,sprintf('Unknown Tokens for [%s]',$uo->email));
|
||||
|
||||
Job::dispatchSync($x->pop());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,261 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use QuickBooksOnline\API\Data\IPPEmailAddress;
|
||||
use QuickBooksOnline\API\Data\IPPPhysicalAddress;
|
||||
|
||||
use App\Classes\External\Accounting\Quickbooks;
|
||||
use App\Models\{Account,External\Integrations,User};
|
||||
|
||||
class QuickAccounts extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'external:sync:accounts {--m|match : Match Display Name}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Sync Account numbers with External Sources';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
foreach (Integrations::active()->type('ACCOUNTING')->get() as $into)
|
||||
{
|
||||
switch ($into->name)
|
||||
{
|
||||
case 'quickbooks':
|
||||
$api = new Quickbooks($into->user);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new \Exception('No handler for: ',$into-name);
|
||||
}
|
||||
|
||||
foreach ($api->getCustomers(TRUE) as $r)
|
||||
{
|
||||
$this->info(sprintf('Checking [%s] (%s)',$r->Id,$r->DisplayName));
|
||||
|
||||
if ($r->Notes == 'Cash Only')
|
||||
{
|
||||
$this->warn(sprintf('Skipping [%s] (%s)',$r->Id,$r->DisplayName));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! $this->option('match') AND (! $r->CompanyName AND (! $r->FamilyName AND ! $r->GivenName)))
|
||||
{
|
||||
$this->error(sprintf('No COMPANY or PERSONAL details for [%s] (%s)',$r->Id,$r->DisplayName));
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($this->option('match')) {
|
||||
$ao = Account::where('company',$r->DisplayName);
|
||||
|
||||
if (! $ao->count()) {
|
||||
$uo = User::where('lastname',$r->FamilyName);
|
||||
|
||||
if ($r->GivenName)
|
||||
$uo->where('firstname',$r->GivenName);
|
||||
|
||||
if ($uo->count() > 1 OR (! $uo->count()))
|
||||
{
|
||||
$this->error(sprintf('No SINGLE Users matched for [%s] (%s)',$r->Id,$r->DisplayName));
|
||||
continue;
|
||||
}
|
||||
|
||||
$uo = $uo->first();
|
||||
$ao = $uo->accounts->where('active',TRUE);
|
||||
}
|
||||
|
||||
} else {
|
||||
if ($r->CompanyName) {
|
||||
$ao = Account::where('company',$this->option('match') ? $r->DisplayName : $r->CompanyName);
|
||||
} else {
|
||||
$uo = User::where('lastname',$r->FamilyName);
|
||||
|
||||
if ($r->GivenName)
|
||||
$uo->where('firstname',$r->GivenName);
|
||||
|
||||
if ($uo->count() > 1 OR (! $uo->count()))
|
||||
{
|
||||
$this->error(sprintf('No SINGLE matched for [%s] (%s)',$r->Id,$r->DisplayName));
|
||||
continue;
|
||||
}
|
||||
|
||||
$uo = $uo->first();
|
||||
$ao = $uo->accounts->where('active',TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
if (! $ao->count())
|
||||
{
|
||||
$this->error(sprintf('No Accounts matched for [%s] (%s)',$r->Id,$r->DisplayName));
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($ao->count() > 1)
|
||||
{
|
||||
$this->error(sprintf('Too Many Accounts (%s) matched for [%s] (%s)',$ao->count(),$r->Id,$r->DisplayName));
|
||||
continue;
|
||||
}
|
||||
|
||||
$ao = $ao->first();
|
||||
|
||||
// If we are matching on DisplayName, make sure the account is updated correct for Business or Personal Accounts
|
||||
$oldr = clone $r;
|
||||
|
||||
// @NOTE: This overwrites the ABN if it exists.
|
||||
if ($r->PrimaryTaxIdentifier)
|
||||
{
|
||||
$this->warn(sprintf('ABN Overwrite for (%s)',$r->DisplayName));
|
||||
}
|
||||
|
||||
switch ($ao->type)
|
||||
{
|
||||
case 'Business':
|
||||
$r->CompanyName = $ao->company;
|
||||
$r->ResaleNum = $ao->AccountId;
|
||||
$r->SalesTermRef = '7'; // @todo
|
||||
|
||||
if ($ao->first_name)
|
||||
$r->GivenName = chop($ao->user->firstname); // @todo shouldnt be required
|
||||
if ($ao->last_name)
|
||||
$r->FamilyName = $ao->user->lastname;
|
||||
|
||||
if ($ao->address1)
|
||||
{
|
||||
if (! $r->BillAddr)
|
||||
$r->BillAddr = new IPPPhysicalAddress;
|
||||
|
||||
$r->BillAddr->Line1 = $ao->user->address1;
|
||||
$r->BillAddr->Line2 = $ao->user->address2;
|
||||
$r->BillAddr->City = $ao->user->city;
|
||||
$r->BillAddr->CountrySubDivisionCode = strtoupper($ao->user->state);
|
||||
$r->BillAddr->PostalCode = $ao->user->postcode;
|
||||
$r->BillAddr->Country = 'Australia'; // @todo
|
||||
|
||||
//$r->ShipAddr = $r->BillAddr;
|
||||
}
|
||||
|
||||
if ($ao->email) {
|
||||
if (! $r->PrimaryEmailAddr)
|
||||
$r->PrimaryEmailAddr = new IPPEmailAddress;
|
||||
|
||||
$r->PrimaryEmailAddr->Address = $ao->user->email;
|
||||
$r->PreferredDeliveryMethod = 'Email';
|
||||
}
|
||||
|
||||
if (! $r->Balance)
|
||||
$r->Active = $ao->active ? 'true' : 'false';
|
||||
|
||||
break;
|
||||
|
||||
case 'Private':
|
||||
$r->CompanyName = NULL;
|
||||
$r->DisplayName = sprintf('%s %s',$ao->user->lastname,$ao->user->firstname);
|
||||
$r->ResaleNum = $ao->AccountId;
|
||||
$r->SalesTermRef = '7'; // @todo
|
||||
|
||||
if ($ao->first_name)
|
||||
$r->GivenName = chop($ao->user->firstname); // @todo shouldnt be required
|
||||
if ($ao->last_name)
|
||||
$r->FamilyName = $ao->user->lastname;
|
||||
|
||||
if ($ao->address1)
|
||||
{
|
||||
if (! $r->BillAddr)
|
||||
$r->BillAddr = new IPPPhysicalAddress;
|
||||
|
||||
$r->BillAddr->Line1 = $ao->user->address1;
|
||||
$r->BillAddr->Line2 = $ao->user->address2;
|
||||
$r->BillAddr->City = $ao->user->city;
|
||||
$r->BillAddr->CountrySubDivisionCode = strtoupper($ao->user->state);
|
||||
$r->BillAddr->PostalCode = $ao->user->postcode;
|
||||
$r->BillAddr->Country = 'Australia'; // @todo
|
||||
|
||||
//$r->ShipAddr = $r->BillAddr;
|
||||
}
|
||||
|
||||
if ($ao->email) {
|
||||
if (! $r->PrimaryEmailAddr)
|
||||
$r->PrimaryEmailAddr = new IPPEmailAddress;
|
||||
|
||||
$r->PrimaryEmailAddr->Address = $ao->user->email;
|
||||
$r->PreferredDeliveryMethod = 'Email';
|
||||
}
|
||||
|
||||
if (! $r->Balance)
|
||||
$r->Active = $ao->active ? 'true' : 'false';
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new \Exception('Unhandled account type: '.$ao->type);
|
||||
|
||||
}
|
||||
|
||||
// If something changed, lets update it.
|
||||
if (count(array_diff_assoc(object_to_array($r,FALSE),object_to_array($oldr,FALSE))))
|
||||
{
|
||||
$api->updateCustomer($r,[]);
|
||||
}
|
||||
|
||||
// If external integration doesnt exist, lets create it.
|
||||
if (! $ao->ExternalAccounting($into))
|
||||
{
|
||||
$ao->external()->attach([$into->id=>['site_id'=>1,'link'=>$r->Id]]); // @todo site_id
|
||||
}
|
||||
|
||||
// If the integration ID doesnt exist in the integration source, add it.
|
||||
if (! $r->ResaleNum)
|
||||
{
|
||||
$api->updateCustomer($r,['ResaleNum'=>$ao->AccountId]);
|
||||
}
|
||||
|
||||
// If integration exist, double check the numbers match
|
||||
if ($r->ResaleNum != $ao->AccountId) {
|
||||
$this->warn(sprintf('Integration ID Mismatch AID [%s] ID [%s]',$ao->id,$r->Id));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function object_to_array($object,$encode=TRUE)
|
||||
{
|
||||
// For child arrays, we just encode
|
||||
if ($encode)
|
||||
return json_encode($object);
|
||||
|
||||
if (is_object($object)) {
|
||||
return array_map(__FUNCTION__,get_object_vars($object));
|
||||
} else if (is_array($object)) {
|
||||
return array_map(__FUNCTION__,$object);
|
||||
} else {
|
||||
return $object;
|
||||
}
|
||||
}
|
|
@ -3,9 +3,10 @@
|
|||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
use App\Models\{Service,Site};
|
||||
use App\Models\Service;
|
||||
|
||||
class ServiceList extends Command
|
||||
{
|
||||
|
@ -14,10 +15,10 @@ class ServiceList extends Command
|
|||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'service:list'.
|
||||
' {--i|inactive : Include Inactive}'.
|
||||
' {--t|type= : Type}'.
|
||||
' {--f|fix : Fix start_date}';
|
||||
protected $signature = 'service:list '.
|
||||
'{--a|active : Active Only}'.
|
||||
'{--category= : Category}'.
|
||||
'{--f|fix : Fix start_date}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
|
@ -26,6 +27,16 @@ class ServiceList extends Command
|
|||
*/
|
||||
protected $description = 'List all services';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
|
@ -33,50 +44,50 @@ class ServiceList extends Command
|
|||
*/
|
||||
public function handle()
|
||||
{
|
||||
$header = '|%13s|%-14s|%-35s|%-40s|%8s|%17s|%12s|%12s|%12s|%12s|%14s|';
|
||||
DB::listen(function($query) {
|
||||
Log::debug('- SQL',['sql'=>$query->sql,'binding'=>$query->bindings]);
|
||||
});
|
||||
|
||||
$this->warn(sprintf($header,
|
||||
$this->warn(sprintf('|%10s|%-6s|%-20s|%-50s|%8s|%14s|%10s|%10s|%10s|%10s|%10s|',
|
||||
'ID',
|
||||
'Type',
|
||||
'CAT',
|
||||
'Product',
|
||||
'Name',
|
||||
'Active',
|
||||
'Status',
|
||||
'Next Invoice',
|
||||
'Start Date',
|
||||
'Stop Date',
|
||||
'Connect Date',
|
||||
'First Invoice'
|
||||
));
|
||||
'active',
|
||||
'status',
|
||||
'invoice next',
|
||||
'start date',
|
||||
'stop date',
|
||||
'connect date',
|
||||
'first invoice'
|
||||
));
|
||||
|
||||
foreach (Service::withoutGlobalScope(\App\Models\Scopes\SiteScope::class)->with(['site'])->cursor() as $o) {
|
||||
if ((! $this->option('inactive')) AND ! $o->isActive())
|
||||
foreach (Service::all() as $o) {
|
||||
if ($this->option('active') AND ! $o->isActive())
|
||||
continue;
|
||||
|
||||
Config::set('site',$o->site);
|
||||
|
||||
if ($this->option('type') AND ($o->product->getCategoryAttribute() !== $this->option('type')))
|
||||
if ($this->option('category') AND $o->product->category !== $this->option('category'))
|
||||
continue;
|
||||
|
||||
$c = $o->invoice_items->filter(function($item) {return $item->item_type === 0; })->sortby('start_at')->first();
|
||||
$c = $o->invoice_items->filter(function($item) {return $item->item_type === 0; })->sortby('date_start')->first();
|
||||
|
||||
if ($this->option('fix') AND ! $o->start_at AND $c AND $c->start_at AND $o->type AND $o->type->connect_at AND $c->start_at->format('Y-m-d') == $o->type->connect_at->format('Y-m-d')) {
|
||||
$o->start_at = $o->type->connect_at;
|
||||
if ($this->option('fix') AND ! $o->date_start AND $c AND $c->date_start AND $o->type AND $o->type->service_connect_date AND $c->date_start->format('Y-m-d') == $o->type->service_connect_date->format('Y-m-d')) {
|
||||
$o->date_start = $o->type->service_connect_date;
|
||||
$o->save();
|
||||
}
|
||||
|
||||
$this->info(sprintf($header,
|
||||
$this->info(sprintf('|%10s|%-6s|%-20s|%-50s|%8s|%14s|%10s|%10s|%10s|%10s|%10s|',
|
||||
$o->sid,
|
||||
$o->product->getCategoryNameAttribute(),
|
||||
substr($o->product->getNameAttribute(),0,35),
|
||||
substr($o->name_short,0,40),
|
||||
$o->product->category,
|
||||
$o->product_name,
|
||||
$o->name_short,
|
||||
$o->active ? 'active' : 'inactive',
|
||||
$o->status,
|
||||
$o->invoice_next?->format('Y-m-d'),
|
||||
$o->start_at?->format('Y-m-d'),
|
||||
$o->stop_at?->format('Y-m-d'),
|
||||
($o->type AND $o->type->connect_at) ? $o->type->connect_at->format('Y-m-d') : NULL,
|
||||
($c && $c->date_start) ? $c->date_start->format('Y-m-d') : NULL,
|
||||
$o->invoice_next ? $o->invoice_next->format('Y-m-d') : NULL,
|
||||
$o->date_start ? $o->date_start->format('Y-m-d') : NULL,
|
||||
$o->date_end ? $o->date_end->format('Y-m-d') : NULL,
|
||||
($o->type AND $o->type->service_connect_date) ? $o->type->service_connect_date->format('Y-m-d') : NULL,
|
||||
$c ? $c->date_start->format('Y-m-d') : NULL,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,67 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
|
||||
use App\Models\{Site,Supplier,User};
|
||||
|
||||
class SupplierAccountSync extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'supplier:account:sync'
|
||||
.' {siteid : Site ID}'
|
||||
.' {supplier : Supplier Name}'
|
||||
.' {--f|forceprod : Force Prod API on dev environment}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Sync accounts with a supplier';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
Config::set('site',Site::findOrFail($this->argument('siteid')));
|
||||
$so = Supplier::where('name',$this->argument('supplier'))->singleOrFail();
|
||||
|
||||
foreach ($so->API($this->option('forceprod'))->getCustomers(['fetchall'=>true]) as $customer) {
|
||||
// Check if we have this customer already (by ID)
|
||||
if ($so->users->where('pivot.id',$customer->id)->count()) {
|
||||
$this->info(sprintf('User already linked (%s:%s)',$customer->id,$customer->email));
|
||||
|
||||
} elseif ($x=User::where('email',$customer->email)->single()) {
|
||||
//dump($x->suppliers->first());
|
||||
if ($x->suppliers->count()) {
|
||||
$this->alert(sprintf('User [%d:%s] already linked to this supplier with ID (%s)',$customer->id,$customer->email,$x->suppliers->first()->pivot->id));
|
||||
|
||||
} else {
|
||||
$this->warn(sprintf('User [%d:%s] has same email (%s:%s) - Linked',$x->id,$x->email,$customer->id,$customer->email));
|
||||
|
||||
$so->users()->syncWithoutDetaching([
|
||||
$x->id => [
|
||||
'id'=>$customer->id,
|
||||
'site_id'=>$x->site_id, // @todo See if we can have this handled automatically
|
||||
'created_at'=>Carbon::create($customer->date_added),
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
} else {
|
||||
$this->error(sprintf('User doesnt exist with email (%s:%s)',$customer->id,$customer->email));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
use App\Models\{Site,Supplier};
|
||||
use App\Jobs\SupplierDomainSync as Job;
|
||||
|
||||
class SupplierDomainSync extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'supplier:domain:sync'
|
||||
.' {siteid : Site ID}'
|
||||
.' {supplier : Supplier Name}'
|
||||
.' {--f|forceprod : Force Prod API on dev environment}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Sync domains from a supplier';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$so = Supplier::where('name',$this->argument('supplier'))->singleOrFail();
|
||||
|
||||
Job::dispatchSync(Site::findOrFail($this->argument('siteid')),$so,$this->option('forceprod'));
|
||||
}
|
||||
}
|
|
@ -3,11 +3,10 @@
|
|||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
|
||||
use App\Mail\TestEmail as MailTest;
|
||||
use App\Models\{Site,User};
|
||||
use App\Models\User;
|
||||
|
||||
class TestEmail extends Command
|
||||
{
|
||||
|
@ -16,7 +15,7 @@ class TestEmail extends Command
|
|||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'test:email {site : Site ID} {id : User ID} {email? : Alternative Email}';
|
||||
protected $signature = 'test:email {id}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
|
@ -42,11 +41,9 @@ class TestEmail extends Command
|
|||
*/
|
||||
public function handle()
|
||||
{
|
||||
Config::set('site',Site::findOrFail($this->argument('site')));
|
||||
|
||||
$uo = User::find($this->argument('id'));
|
||||
|
||||
Mail::to($this->argument('email') ?? $uo->email)
|
||||
Mail::to($uo->email)
|
||||
->send(new MailTest($uo));
|
||||
}
|
||||
}
|
|
@ -5,8 +5,8 @@ namespace App\Console;
|
|||
use Illuminate\Console\Scheduling\Schedule;
|
||||
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
||||
|
||||
use App\Models\AdslSupplier;
|
||||
use App\Jobs\BroadbandTraffic;
|
||||
use App\Models\Supplier;
|
||||
|
||||
class Kernel extends ConsoleKernel
|
||||
{
|
||||
|
@ -29,7 +29,7 @@ class Kernel extends ConsoleKernel
|
|||
{
|
||||
// @todo This needs to be more generic and dynamic
|
||||
// Exetel Traffic
|
||||
$schedule->job(new BroadbandTraffic(Supplier::find(1)))->timezone('Australia/Melbourne')->dailyAt('10:00');
|
||||
$schedule->job(new BroadbandTraffic(AdslSupplier::find(1)))->timezone('Australia/Melbourne')->dailyAt('10:00');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use Illuminate\Broadcasting\Channel;
|
||||
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||
use Illuminate\Broadcasting\PresenceChannel;
|
||||
use Illuminate\Broadcasting\PrivateChannel;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||
use Illuminate\Foundation\Events\Dispatchable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class ProviderPaymentCreated
|
||||
{
|
||||
use Dispatchable, InteractsWithSockets, SerializesModels;
|
||||
|
||||
public array $paymentData;
|
||||
public string $provider;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(string $provider,array $paymentData)
|
||||
{
|
||||
$this->provider = $provider;
|
||||
$this->paymentData = $paymentData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the channels the event should broadcast on.
|
||||
*
|
||||
* @return \Illuminate\Broadcasting\Channel|array
|
||||
*/
|
||||
public function broadcastOn()
|
||||
{
|
||||
return new PrivateChannel('channel-name');
|
||||
}
|
||||
}
|
|
@ -22,7 +22,6 @@ class Handler extends ExceptionHandler
|
|||
* @var array
|
||||
*/
|
||||
protected $dontFlash = [
|
||||
'current_password',
|
||||
'password',
|
||||
'password_confirmation',
|
||||
];
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
use App\Models\ProviderOauth;
|
||||
use App\Models\User;
|
||||
|
||||
class AccountingController extends Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('auth');
|
||||
}
|
||||
|
||||
/**
|
||||
* Query the accounting system and get a valid list of accounting codes
|
||||
*
|
||||
* @param string $provider
|
||||
* @return Collection
|
||||
*/
|
||||
public static function list(string $provider): Collection
|
||||
{
|
||||
// @todo This should be a variable
|
||||
$uo = User::findOrFail(1);
|
||||
|
||||
$so = ProviderOauth::where('name',$provider)->singleOrFail();
|
||||
if (! ($to=$so->token($uo)))
|
||||
abort(500,sprintf('Unknown Tokens for [%s]',$uo->email));
|
||||
|
||||
$api = $to->API();
|
||||
|
||||
return $api->getItems()
|
||||
->pluck('pid','Id')
|
||||
->transform(function($item,$value) { return ['id'=>$value,'value'=>$item]; })
|
||||
->values();
|
||||
}
|
||||
}
|
|
@ -4,83 +4,16 @@ namespace App\Http\Controllers;
|
|||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
use App\Models\{Account,
|
||||
Charge,
|
||||
Invoice,
|
||||
InvoiceItem,
|
||||
Payment,
|
||||
PaymentItem,
|
||||
Service,
|
||||
SiteDetail,
|
||||
Supplier,
|
||||
SupplierDetail};
|
||||
use App\Models\{Account,Payment,PaymentItem,Service,SiteDetail};
|
||||
|
||||
/**
|
||||
* The AdminController governs all routes that are prefixed with 'a/'.
|
||||
*
|
||||
* This is everything about the configuration of the application as a whole, or administration of a site.
|
||||
*/
|
||||
class AdminController extends Controller
|
||||
{
|
||||
// @todo Move to reseller
|
||||
public function service(Service $o)
|
||||
{
|
||||
return View('a.service',['o'=>$o]);
|
||||
}
|
||||
|
||||
// @todo Move to reseller
|
||||
public function charge_addedit(Request $request,Charge $o)
|
||||
{
|
||||
if ($request->post()) {
|
||||
$request->validate([
|
||||
'account_id' => 'required|exists:accounts,id',
|
||||
'charge_at' => 'required|date',
|
||||
'service_id' => 'required|exists:services,id',
|
||||
'quantity' => 'required|numeric|not_in:0',
|
||||
'amount' => 'required|numeric|min:0.01',
|
||||
'sweep_type' => 'required|numeric|in:'.implode(',',array_keys(Charge::sweep)),
|
||||
'type' => 'required|numeric|in:'.implode(',',array_keys(InvoiceItem::type)),
|
||||
'taxable' => 'nullable|boolean',
|
||||
'description' => 'nullable|string|max:128',
|
||||
]);
|
||||
|
||||
if (! $o->exists) {
|
||||
$o->site_id = config('site')->site_id;
|
||||
$o->user_id = Auth::id();
|
||||
$o->active = TRUE;
|
||||
}
|
||||
|
||||
$o->forceFill($request->only(['account_id','charge_at','service_id','quantity','amount','sweep_type','type','taxable','description']));
|
||||
$o->save();
|
||||
|
||||
return redirect()->back()
|
||||
->with('success','Charge recorded: '.$o->id);
|
||||
}
|
||||
|
||||
return view('a.charge.addedit')
|
||||
->with('o',$o);
|
||||
}
|
||||
|
||||
// @todo Move to reseller
|
||||
public function charge_pending_account(Request $request,Account $o)
|
||||
{
|
||||
return view('a.charge.widgets.pending')
|
||||
->with('list',$o->charges->where('active',TRUE)->where('processed',NULL)->except($request->exclude));
|
||||
}
|
||||
|
||||
/**
|
||||
* List unprocessed charges
|
||||
*
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
|
||||
*/
|
||||
// @todo Move to reseller
|
||||
public function charge_unprocessed()
|
||||
{
|
||||
return view('a.charge.unprocessed');
|
||||
}
|
||||
|
||||
/**
|
||||
* Record payments on an account.
|
||||
*
|
||||
|
@ -88,97 +21,56 @@ class AdminController extends Controller
|
|||
* @param Payment $o
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
// @todo Move to reseller
|
||||
public function pay_addedit(Request $request,Payment $o)
|
||||
public function pay_add(Request $request,Payment $o)
|
||||
{
|
||||
if ($request->post()) {
|
||||
|
||||
$validation = $request->validate([
|
||||
'account_id' => 'required|exists:accounts,id',
|
||||
'paid_at' => 'required|date',
|
||||
'checkout_id' => 'required|exists:checkouts,id',
|
||||
'account_id' => 'required|exists:ab_account,id',
|
||||
'date_payment' => 'required|date',
|
||||
'checkout_id' => 'required|exists:ab_checkout,id',
|
||||
'total_amt' => 'required|numeric|min:0.01',
|
||||
'fees_amt' => 'nullable|numeric|lt:total_amt',
|
||||
'source_id' => 'nullable|exists:accounts,id',
|
||||
'source_id' => 'nullable|exists:ab_account,id',
|
||||
'pending' => 'nullable|boolean',
|
||||
'notes' => 'nullable|string',
|
||||
'ip' => 'nullable|ip',
|
||||
'invoices' => ['required','array',function ($attribute,$value,$fail) use ($request) {
|
||||
if (collect($value)->sum('id') > $request->post('total_amt'))
|
||||
'invoices' => ['nullable','array',function ($attribute,$value,$fail) use ($request) {
|
||||
if (collect($value)->sum() > $request->post('total_amt'))
|
||||
$fail('Allocation is greater than payment total.');
|
||||
}],
|
||||
'invoices.*.id' => ['required',function ($attribute,$value,$fail) {
|
||||
if (! Invoice::exists(str_replace(str_replace($attribute,'invoice\.','',),'.id','')))
|
||||
$fail('Invoice doesnt exist in DB');
|
||||
}],
|
||||
'invoices.*.id' => 'nullable|exists:ab_invoice,id',
|
||||
]);
|
||||
|
||||
if (! $o->exists) {
|
||||
$o->site_id = config('site')->site_id;
|
||||
$o->active = TRUE;
|
||||
}
|
||||
|
||||
$o->forceFill($request->only(['account_id','paid_at','checkout_id','total_amt','fees_amt','source_id','pending','notes','ip']));
|
||||
$o->save();
|
||||
$oo = new Payment;
|
||||
$oo->forceFill($request->only(['account_id','date_payment','checkout_id','checkout_id','total_amt','fees_amt','source_id','pending','notes','ip']));
|
||||
$oo->site_id = config('SITE')->site_id;
|
||||
$oo->save();
|
||||
|
||||
foreach ($validation['invoices'] as $id => $amount) {
|
||||
// See if we already have a payment item that we need to update
|
||||
$items = $o->items->filter(function($item) use ($id) { return $item->invoice_id == $id; });
|
||||
|
||||
if ($items->count() == 1) {
|
||||
$oo = $items->pop();
|
||||
if ($amount['id'] == 0) {
|
||||
$oo->delete();
|
||||
continue;
|
||||
}
|
||||
|
||||
} else {
|
||||
$oo = new PaymentItem;
|
||||
$oo->invoice_id = $id;
|
||||
}
|
||||
|
||||
$oo->amount = ($oo->invoice->due >= 0) && ($oo->invoice->due-$amount['id'] >= 0) ? $amount['id'] : 0;
|
||||
|
||||
// If the amount is empty, ignore it.
|
||||
if (! $oo->amount)
|
||||
continue;
|
||||
|
||||
$oo->site_id = config('site')->site_id;
|
||||
$oo->active = TRUE;
|
||||
$o->items()->save($oo);
|
||||
$ooo = new PaymentItem;
|
||||
$ooo->invoice_id = $id;
|
||||
$ooo->alloc_amt = $amount;
|
||||
$ooo->site_id = config('SITE')->site_id;
|
||||
$oo->items()->save($ooo);
|
||||
}
|
||||
|
||||
return redirect()->back()
|
||||
->with('success','Payment recorded: '.$o->id);
|
||||
->with('success','Payment recorded');
|
||||
}
|
||||
|
||||
return view('a.payment.addedit')
|
||||
return view('a.payment.add')
|
||||
->with('o',$o);
|
||||
}
|
||||
|
||||
/**
|
||||
* List unapplied payments
|
||||
*
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
|
||||
*/
|
||||
// @todo Move to reseller
|
||||
public function pay_unapplied()
|
||||
{
|
||||
return view('a.payment.unapplied');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a list of invoices to apply payments to
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Account $o
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
|
||||
*/
|
||||
// @todo Move to reseller
|
||||
public function pay_invoices(Request $request,Account $o)
|
||||
public function pay_invoices(Account $o)
|
||||
{
|
||||
return view('a.payment.widgets.invoices')
|
||||
->with('pid',$request->pid)
|
||||
->with('o',$o);
|
||||
}
|
||||
|
||||
|
@ -193,13 +85,13 @@ class AdminController extends Controller
|
|||
{
|
||||
if ($request->post()) {
|
||||
$validated = $request->validate([
|
||||
'site_name' => 'required|string|min:2|max:255',
|
||||
'site_name' => 'required|string|max:255',
|
||||
'site_email' => 'required|string|email|max:255',
|
||||
'site_address1' => 'required|string|min:2|max:255',
|
||||
'site_address2' => 'nullable|string|min:2|max:255',
|
||||
'site_city' => 'required|string|min:2|max:64',
|
||||
'site_state' => 'required|string|min:2|max:32',
|
||||
'site_postcode' => 'required|string|min:2|max:8',
|
||||
'site_address1' => 'required|string|max:255',
|
||||
'site_address2' => 'nullable|string|max:255',
|
||||
'site_city' => 'required|string|max:64',
|
||||
'site_state' => 'required|string|max:32',
|
||||
'site_postcode' => 'required|string|max:8',
|
||||
'site_description' => 'nullable|string|min:5',
|
||||
'site_phone' => 'nullable|regex:/[0-9 ]+/|min:6|max:12',
|
||||
'site_fax' => 'nullable|regex:/[0-9 ]+/|min:6|max:12',
|
||||
|
@ -210,7 +102,7 @@ class AdminController extends Controller
|
|||
'email_logo' => 'nullable|image',
|
||||
]);
|
||||
|
||||
$site = config('site');
|
||||
$site = config('SITE');
|
||||
|
||||
// @todo - not currently rendered in the home page
|
||||
$validated['social'] = [];
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
namespace App\Http\Controllers\Auth;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
@ -11,7 +10,9 @@ use Laravel\Socialite\Facades\Socialite;
|
|||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Mail\SocialLink;
|
||||
use App\Models\{ProviderOauth,ProviderToken,User,UserOauth};
|
||||
use App\Models\Oauth;
|
||||
use App\Models\AccountOauth;
|
||||
use App\Models\User;
|
||||
use App\Providers\RouteServiceProvider;
|
||||
|
||||
class SocialLoginController extends Controller
|
||||
|
@ -25,13 +26,10 @@ class SocialLoginController extends Controller
|
|||
{
|
||||
$openiduser = Socialite::with($provider)->user();
|
||||
|
||||
if (! $openiduser)
|
||||
return redirect('/home')->with('error','No user details obtained.');
|
||||
|
||||
$oo = ProviderOauth::firstOrCreate(['name'=>$provider,'active'=>TRUE]);
|
||||
$oo = Oauth::firstOrCreate(['name'=>$provider,'active'=>TRUE]);
|
||||
|
||||
// See if this user has connected and linked previously
|
||||
$aoo = $oo->users->where('userid',$openiduser->id);
|
||||
$aoo = $oo->accounts->where('userid',$openiduser->id);
|
||||
|
||||
if ($aoo->count() == 1) {
|
||||
$aoo = $aoo->first();
|
||||
|
@ -61,10 +59,10 @@ class SocialLoginController extends Controller
|
|||
|
||||
// See if their is an account with this email address
|
||||
if ($uo->count() == 1) {
|
||||
$aoo = new UserOauth;
|
||||
$aoo = new AccountOauth;
|
||||
$aoo->userid = $openiduser->id;
|
||||
$aoo->oauth_data = $openiduser->user;
|
||||
$oo->users()->save($aoo);
|
||||
$oo->accounts()->save($aoo);
|
||||
|
||||
return $this->link($provider,$aoo,$uo->first());
|
||||
|
||||
|
@ -80,43 +78,16 @@ class SocialLoginController extends Controller
|
|||
return redirect()->intended(RouteServiceProvider::HOME);
|
||||
}
|
||||
|
||||
public function handleBearerTokenCallback($provider)
|
||||
{
|
||||
$openiduser = Socialite::with($provider)->user();
|
||||
|
||||
if (! $openiduser)
|
||||
return redirect('/home')->with('error','No user details obtained.');
|
||||
|
||||
$po = ProviderOauth::where('name',$provider)->singleOrFail();
|
||||
|
||||
$uoo = ProviderToken::where('user_id',Auth::id())->where('provider_oauth_id',$po->id)->firstOrNew();
|
||||
|
||||
$uoo->user_id = Auth::id();
|
||||
$uoo->access_token = $openiduser->token;
|
||||
$uoo->access_token_expires_at = Carbon::now()->addSeconds($openiduser->expiresIn);
|
||||
$uoo->refresh_token = $openiduser->refreshToken;
|
||||
$uoo->refresh_token_expires_at = Carbon::now()->addSeconds($openiduser->refresh_token_expires_in);
|
||||
$uoo->realm_id = $openiduser->realmid;
|
||||
|
||||
$po->tokens()->save($uoo);
|
||||
|
||||
return redirect()
|
||||
->intended(RouteServiceProvider::HOME)
|
||||
->with('success','Token refreshed.');
|
||||
}
|
||||
|
||||
/**
|
||||
* We have identified the user and oauth, just need them to confirm the link
|
||||
*
|
||||
* @param $provider
|
||||
* @param UserOauth $ao
|
||||
* @param $provider
|
||||
* @param User $uo
|
||||
* @return \Illuminate\View\View
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function link($provider,UserOauth $ao,User $uo): \Illuminate\View\View
|
||||
public function link($provider,AccountOauth $ao,User $uo)
|
||||
{
|
||||
// @note If this is sent now (send()), it results in the caller to be executed a second time (handleProviderCallback()).
|
||||
Mail::to($uo->email)->queue(new SocialLink($ao));
|
||||
Mail::to($uo->email)->send(new SocialLink($ao));
|
||||
|
||||
return view('auth.social_link')
|
||||
->with('oauthid',$ao->id)
|
||||
|
@ -126,7 +97,7 @@ class SocialLoginController extends Controller
|
|||
public function linkcomplete(Request $request,$provider)
|
||||
{
|
||||
// Load our oauth id
|
||||
$aoo = UserOauth::findOrFail($request->post('oauthid'));
|
||||
$aoo = AccountOauth::findOrFail($request->post('oauthid'));
|
||||
|
||||
// Check our email matches
|
||||
if (Arr::get($aoo->oauth_data,'email','invalid') !== $request->post('email'))
|
||||
|
|
|
@ -2,41 +2,13 @@
|
|||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Invoice;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\View\View;
|
||||
|
||||
use App\Http\Requests\CheckoutAddEdit;
|
||||
use App\Models\{Checkout,Invoice};
|
||||
use App\Models\Checkout;
|
||||
|
||||
class CheckoutController extends Controller
|
||||
{
|
||||
/**
|
||||
* Update a suppliers details
|
||||
*
|
||||
* @param CheckoutAddEdit $request
|
||||
* @param Checkout $o
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function addedit(CheckoutAddEdit $request,Checkout $o)
|
||||
{
|
||||
$this->middleware(['auth','wholesaler']);
|
||||
|
||||
foreach ($request->except(['_token','active','submit']) as $key => $item)
|
||||
$o->{$key} = $item;
|
||||
|
||||
$o->active = (bool)$request->active;
|
||||
|
||||
try {
|
||||
$o->save();
|
||||
|
||||
} catch (\Exception $e) {
|
||||
return redirect()->back()->withErrors($e->getMessage())->withInput();
|
||||
}
|
||||
|
||||
return redirect()->back()
|
||||
->with('success','Payment saved');
|
||||
}
|
||||
|
||||
public function cart_invoice(Request $request,Invoice $o=NULL)
|
||||
{
|
||||
if ($o) {
|
||||
|
@ -55,29 +27,8 @@ class CheckoutController extends Controller
|
|||
return $o->fee($request->post('total',0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a specific invoice for the user
|
||||
*
|
||||
* @return View
|
||||
*/
|
||||
public function home(): View
|
||||
{
|
||||
return View('payment.home');
|
||||
}
|
||||
|
||||
public function pay(Request $request,Checkout $o)
|
||||
{
|
||||
return redirect('pay/paypal/authorise');
|
||||
}
|
||||
|
||||
/**
|
||||
* View details on a specific payment method
|
||||
*
|
||||
* @param Checkout $o
|
||||
* @return View
|
||||
*/
|
||||
public function view(Checkout $o): View
|
||||
{
|
||||
return View('payment.view',['o'=>$o]);
|
||||
}
|
||||
}
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||
use Illuminate\Routing\Controller as BaseController;
|
||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
|
||||
class Controller extends BaseController
|
||||
{
|
||||
|
|
|
@ -4,9 +4,11 @@ namespace App\Http\Controllers;
|
|||
|
||||
use Clarkeash\Doorman\Exceptions\{DoormanException,ExpiredInviteCode};
|
||||
use Clarkeash\Doorman\Facades\Doorman;
|
||||
use Illuminate\Contracts\View\Factory;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\View\View;
|
||||
use Barryvdh\Snappy\Facades\SnappyPdf as PDF;
|
||||
|
||||
use App\Models\{Invoice,Service,User};
|
||||
|
||||
|
@ -20,18 +22,60 @@ use App\Models\{Invoice,Service,User};
|
|||
*/
|
||||
class HomeController extends Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('auth');
|
||||
}
|
||||
|
||||
/**
|
||||
* Logged in users home page
|
||||
*
|
||||
* @param User $o
|
||||
* @return View
|
||||
* @return Factory|View
|
||||
*/
|
||||
public function home(User $o): View
|
||||
{
|
||||
if (! $o->exists)
|
||||
$o = Auth::user();
|
||||
// If we are passed a user to view, we'll open up their home page.
|
||||
if ($o->exists) {
|
||||
$o->load(['accounts','services']);
|
||||
return View('u.home',['o'=>$o]);
|
||||
}
|
||||
|
||||
return View('home',['o'=>$o]);
|
||||
// If User was null, then test and see what type of logged on user we have
|
||||
$o = Auth::user();
|
||||
|
||||
switch (Auth::user()->role()) {
|
||||
case 'customer':
|
||||
return View('u.home',['o'=>$o]);
|
||||
|
||||
case 'reseller':
|
||||
case 'wholesaler':
|
||||
return View('r.home',['o'=>$o]);
|
||||
|
||||
default:
|
||||
abort(404,'Unknown role: '.$o->role());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a specific invoice for the user
|
||||
*
|
||||
* @param Invoice $o
|
||||
* @return View
|
||||
*/
|
||||
public function invoice(Invoice $o): View
|
||||
{
|
||||
return View('u.invoice.home',['o'=>$o]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the invoice in PDF format, ready to download
|
||||
*
|
||||
* @param Invoice $o
|
||||
* @return mixed
|
||||
*/
|
||||
public function invoice_pdf(Invoice $o)
|
||||
{
|
||||
return PDF::loadView('u.invoice.home',['o'=>$o])->stream(sprintf('%s.pdf',$o->invoice_account_id));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -57,7 +101,18 @@ class HomeController extends Controller
|
|||
abort(404);
|
||||
}
|
||||
|
||||
return $this->invoice($o);
|
||||
return $this->invoice_pdf($o);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return details on the users service
|
||||
*
|
||||
* @param Service $o
|
||||
* @return View
|
||||
*/
|
||||
public function service(Service $o): View
|
||||
{
|
||||
return View('u.service.home',['o'=>$o]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -67,7 +122,6 @@ class HomeController extends Controller
|
|||
* @param Service $o
|
||||
* @param string $status
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @deprecated
|
||||
*/
|
||||
public function service_progress(Service $o,string $status)
|
||||
{
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\View\View;
|
||||
use Barryvdh\Snappy\Facades\SnappyPdf as PDF;
|
||||
|
||||
use App\Models\Invoice;
|
||||
|
||||
/**
|
||||
* Class InvoiceController
|
||||
* This controller manages invoices
|
||||
*
|
||||
* The methods to this controller should be projected by the route
|
||||
*
|
||||
* @package App\Http\Controllers
|
||||
*/
|
||||
class InvoiceController extends Controller
|
||||
{
|
||||
/**
|
||||
* Return the invoice in PDF format, ready to download
|
||||
*
|
||||
* @param Invoice $o
|
||||
* @return mixed
|
||||
*/
|
||||
public function pdf(Invoice $o)
|
||||
{
|
||||
return PDF::loadView('u.invoice.home',['o'=>$o])->stream(sprintf('%s.pdf',$o->sid));
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a specific invoice for the user
|
||||
*
|
||||
* @param Invoice $o
|
||||
* @return View
|
||||
*/
|
||||
public function view(Invoice $o): View
|
||||
{
|
||||
return View('invoice.view',['o'=>$o]);
|
||||
}
|
||||
}
|
|
@ -14,38 +14,33 @@ use App\Models\{Account,Product,Service,User};
|
|||
|
||||
class OrderController extends Controller
|
||||
{
|
||||
// @todo To check
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('auth');
|
||||
}
|
||||
|
||||
// @todo To check
|
||||
public function index()
|
||||
{
|
||||
return view('order.home');
|
||||
return view('order');
|
||||
}
|
||||
|
||||
// @todo To check
|
||||
public function product_order(Product $o)
|
||||
{
|
||||
Theme::set('metronic-fe');
|
||||
|
||||
return view('order.widget.order',['o'=>$o]);
|
||||
return view('widgets.product_order',['o'=>$o]);
|
||||
}
|
||||
|
||||
// @todo To check
|
||||
public function product_info(Product $o)
|
||||
{
|
||||
Theme::set('metronic-fe');
|
||||
|
||||
return view('order.widget.info',['o'=>$o]);
|
||||
return view('widgets.product_description',['o'=>$o]);
|
||||
}
|
||||
|
||||
// @todo To check
|
||||
public function submit(Request $request)
|
||||
{
|
||||
Validator::make($request->all(),['product_id'=>'required|exists:products,id'])
|
||||
Validator::make($request->all(),['product_id'=>'required|exists:ab_product,id'])
|
||||
// Reseller
|
||||
->sometimes('account_id','required|email',function($input) use ($request) {
|
||||
return is_null($input->account_id) AND is_null($input->order_email_manual);
|
||||
|
@ -64,7 +59,7 @@ class OrderController extends Controller
|
|||
$po = Product::findOrFail($request->input('product_id'));
|
||||
|
||||
// Check we have the custom attributes for the product
|
||||
$order = $po->orderValidation($request);
|
||||
$options = $po->orderValidation($request);
|
||||
|
||||
if ($request->input('order_email_manual')) {
|
||||
$uo = User::firstOrNew(['email'=>$request->input('order_email_manual')]);
|
||||
|
@ -72,13 +67,12 @@ class OrderController extends Controller
|
|||
// If this is a new client
|
||||
if (! $uo->exists) {
|
||||
// @todo Make this automatic
|
||||
$uo->site_id = config('site')->site_id;
|
||||
$uo->site_id = config('SITE')->site_id;
|
||||
$uo->active = FALSE;
|
||||
$uo->firstname = '';
|
||||
$uo->lastname = '';
|
||||
$uo->country_id = config('site')->country_id; // @todo This might be wrong
|
||||
$uo->country_id = config('SITE')->country_id; // @todo This might be wrong
|
||||
$uo->parent_id = Auth::id() ?: 1; // @todo This should be configured to a default user
|
||||
$uo->language_id = config('site')->language_id; // @todo This might be wrong
|
||||
$uo->active = 1;
|
||||
$uo->save();
|
||||
}
|
||||
|
@ -89,8 +83,10 @@ class OrderController extends Controller
|
|||
$ao = new Account;
|
||||
//$ao->id = Account::NextId();
|
||||
// @todo Make this automatic
|
||||
$ao->site_id = config('site')->site_id;
|
||||
$ao->country_id = config('site')->country_id; // @todo This might be wrong
|
||||
$ao->site_id = config('SITE')->site_id;
|
||||
$ao->country_id = config('SITE')->country_id; // @todo This might be wrong
|
||||
$ao->language_id = config('SITE')->language_id; // @todo This might be wrong
|
||||
$ao->currency_id = config('SITE')->currency_id; // @todo This might be wrong
|
||||
$ao->active = 1;
|
||||
$uo->accounts()->save($ao);
|
||||
|
||||
|
@ -101,29 +97,27 @@ class OrderController extends Controller
|
|||
$so = new Service;
|
||||
|
||||
// @todo Make this automatic
|
||||
$so->site_id = config('site')->site_id;
|
||||
$so->product_id = $po->id;
|
||||
$so->site_id = config('SITE')->site_id;
|
||||
$so->product_id = $request->input('product_id');
|
||||
$so->order_status = 'ORDER-SUBMIT';
|
||||
$so->ordered_by = Auth::id();
|
||||
$so->active = FALSE;
|
||||
$so->model = $order ? get_class($order) : NULL;
|
||||
$so->recur_schedule = $po->billing_interval;
|
||||
$so->orderby_id = Auth::id();
|
||||
$so->model = get_class($options);
|
||||
|
||||
if ($order && $order->order_info) {
|
||||
$so->order_info = $order->order_info;
|
||||
if ($options->order_info) {
|
||||
$so->order_info = $options->order_info;
|
||||
|
||||
unset($order->order_info);
|
||||
unset($options->order_info);
|
||||
}
|
||||
|
||||
$so = $ao->services()->save($so);
|
||||
|
||||
if ($order instanceOf Model) {
|
||||
$order->service_id = $so->id;
|
||||
$order->save();
|
||||
if ($options instanceOf Model) {
|
||||
$options->service_id = $so->id;
|
||||
$options->save();
|
||||
}
|
||||
|
||||
Mail::to('help@graytech.net.au')
|
||||
->queue((new OrderRequest($so,$request->input('options.notes') ?: ''))->onQueue('email')); //@todo Get email from DB.
|
||||
->queue((new OrderRequest($so,$request->input('options.notes')))->onQueue('email')); //@todo Get email from DB.
|
||||
|
||||
return view('order_received',['o'=>$so]);
|
||||
}
|
||||
|
|
|
@ -200,7 +200,6 @@ class PaypalController extends Controller
|
|||
foreach ($response->result->purchase_units as $pu) {
|
||||
foreach ($pu->payments->captures as $cap) {
|
||||
$po = new Payment;
|
||||
$po->active = TRUE;
|
||||
|
||||
switch ($cap->status) {
|
||||
case 'PENDING':
|
||||
|
@ -218,7 +217,7 @@ class PaypalController extends Controller
|
|||
break;
|
||||
}
|
||||
|
||||
$po->paid_at = Carbon::parse($cap->create_time);
|
||||
$po->date_payment = Carbon::parse($cap->create_time);
|
||||
$po->checkout_id = $this->o->id;
|
||||
$po->checkout_data = $cap->id;
|
||||
|
||||
|
@ -230,7 +229,7 @@ class PaypalController extends Controller
|
|||
$pio = new PaymentItem;
|
||||
$pio->site_id = 1; // @todo To implement
|
||||
$pio->invoice_id = $cap->invoice_id;
|
||||
$pio->amount = $cap->amount->value-$po->fees_amt;
|
||||
$pio->alloc_amt = $cap->amount->value-$po->fees_amt;
|
||||
|
||||
$po->items->push($pio);
|
||||
|
||||
|
|
|
@ -1,148 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
use App\Http\Requests\ProductAddEdit;
|
||||
use App\Models\{Product,ProductTranslate};
|
||||
|
||||
class ProductController extends Controller
|
||||
{
|
||||
/**
|
||||
* Get a list of products that meet a type
|
||||
*
|
||||
* @param Request $request
|
||||
* @return Collection
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function api_supplier_products(Request $request): Collection
|
||||
{
|
||||
switch ($request->type) {
|
||||
case Product\Broadband::class:
|
||||
return Product\Broadband::select(['id','supplier_item_id'])
|
||||
->with(['supplied.supplier_detail.supplier'])
|
||||
->get()
|
||||
->map(function($item) { return ['id'=>$item->id,'name'=>sprintf('%s: %s',$item->supplied->supplier->name,$item->supplied->name)]; })
|
||||
->sortBy('name')
|
||||
->values();
|
||||
|
||||
case Product\Domain::class:
|
||||
return Product\Domain::select(['id','supplier_item_id'])
|
||||
->with(['supplied.supplier_detail.supplier'])
|
||||
->get()
|
||||
->map(function($item) { return ['id'=>$item->id,'name'=>sprintf('%s: %s',$item->supplied->supplier->name,$item->supplied->name)]; })
|
||||
->sortBy('name')
|
||||
->values();
|
||||
|
||||
case Product\Email::class:
|
||||
return Product\Email::select(['id','supplier_item_id'])
|
||||
->with(['supplied.supplier_detail.supplier'])
|
||||
->get()
|
||||
->map(function($item) { return ['id'=>$item->id,'name'=>sprintf('%s: %s',$item->supplied->supplier->name,$item->supplied->name)]; })
|
||||
->sortBy('name')
|
||||
->values();
|
||||
|
||||
case Product\Generic::class:
|
||||
return Product\Generic::select(['id','supplier_item_id'])
|
||||
->with(['supplied.supplier_detail.supplier'])
|
||||
->get()
|
||||
->map(function($item) { return ['id'=>$item->id,'name'=>sprintf('%s: %s',$item->supplied->supplier->name,$item->supplied->name)]; })
|
||||
->sortBy('name')
|
||||
->values();
|
||||
|
||||
case Product\Host::class:
|
||||
return Product\Host::select(['id','supplier_item_id'])
|
||||
->with(['supplied.supplier_detail.supplier'])
|
||||
->get()
|
||||
->map(function($item) { return ['id'=>$item->id,'name'=>sprintf('%s: %s',$item->supplied->supplier->name,$item->supplied->name)]; })
|
||||
->sortBy('name')
|
||||
->values();
|
||||
|
||||
case Product\Phone::class:
|
||||
return Product\Phone::select(['id','supplier_item_id'])
|
||||
->with(['supplied.supplier_detail.supplier'])
|
||||
->get()
|
||||
->map(function($item) { return ['id'=>$item->id,'name'=>sprintf('%s: %s',$item->supplied->supplier->name,$item->supplied->name)]; })
|
||||
->sortBy('name')
|
||||
->values();
|
||||
|
||||
default:
|
||||
throw new \Exception('Unknown type: '.$request->type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a suppliers details
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Product $o
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function details(Request $request,Product $o)
|
||||
{
|
||||
if (! $o->exists && $request->name)
|
||||
$o = Product::where('name',$request->name)->firstOrNew();
|
||||
|
||||
return view('product.details')
|
||||
->with('breadcrumb',collect(['Products'=>url('a/product')]))
|
||||
->with('o',$o);
|
||||
}
|
||||
|
||||
public function details_addedit(ProductAddEdit $request,Product $o)
|
||||
{
|
||||
foreach ($request->except(['_token','submit','translate','accounting']) as $key => $item)
|
||||
$o->{$key} = $item;
|
||||
|
||||
$o->active = (bool)$request->active;
|
||||
|
||||
// Trim down the pricing array, remove null values
|
||||
$o->pricing = $o->pricing->map(function($item) {
|
||||
foreach ($item as $k=>$v) {
|
||||
if (is_array($v)) {
|
||||
$v = array_filter($v);
|
||||
$item[$k] = $v;
|
||||
}
|
||||
}
|
||||
|
||||
return $item;
|
||||
});
|
||||
|
||||
try {
|
||||
$o->save();
|
||||
} catch (\Exception $e) {
|
||||
return redirect()->back()->withErrors($e->getMessage())->withInput();
|
||||
}
|
||||
|
||||
$o->load(['translate']);
|
||||
$oo = $o->translate ?: new ProductTranslate;
|
||||
foreach ($request->get('translate',[]) as $key => $item)
|
||||
$oo->{$key} = $item;
|
||||
|
||||
$o->translate()->save($oo);
|
||||
|
||||
if ($request->accounting)
|
||||
foreach ($request->accounting as $k=>$v)
|
||||
$o->providers()->syncWithoutDetaching([
|
||||
$k => [
|
||||
'ref' => $v,
|
||||
'site_id'=>$o->site_id,
|
||||
],
|
||||
]);
|
||||
|
||||
return redirect()->back()
|
||||
->with('success','Product saved');
|
||||
}
|
||||
|
||||
/**
|
||||
* Manage products for a site
|
||||
*
|
||||
* @note This method is protected by the routes
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function home()
|
||||
{
|
||||
return view('product.home');
|
||||
}
|
||||
}
|
|
@ -2,18 +2,27 @@
|
|||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
use App\Models\Account;
|
||||
use Auth;
|
||||
|
||||
class ResellerServicesController extends Controller
|
||||
{
|
||||
public function services(Request $request,Account $o)
|
||||
public function accounts()
|
||||
{
|
||||
return $o->services
|
||||
->filter(function($item) use ($request) {
|
||||
return $item->active || ($item->id == $request->include);
|
||||
});
|
||||
return ['data'=>Auth::user()->all_accounts()->values()];
|
||||
}
|
||||
|
||||
public function agents()
|
||||
{
|
||||
return ['data'=>Auth::user()->all_agents()->values()];
|
||||
}
|
||||
|
||||
public function clients()
|
||||
{
|
||||
return ['data'=>Auth::user()->all_clients()->values()];
|
||||
}
|
||||
|
||||
public function service_inactive()
|
||||
{
|
||||
return ['data'=>Auth::user()->all_client_service_inactive()->values()];
|
||||
}
|
||||
}
|
|
@ -3,11 +3,10 @@
|
|||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
use App\Models\{Account,Invoice,Payment,Service,Supplier,User};
|
||||
use App\Models\{Account,Invoice,Service,Service\Adsl,User};
|
||||
|
||||
class SearchController extends Controller
|
||||
{
|
||||
|
@ -15,84 +14,73 @@ class SearchController extends Controller
|
|||
* Search from the Application Dashboard.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return Collection
|
||||
* @return Response
|
||||
*/
|
||||
public function search(Request $request): Collection
|
||||
public function search(Request $request)
|
||||
{
|
||||
$result = collect();
|
||||
|
||||
// If the user isnt logged in
|
||||
if (! Auth::user())
|
||||
abort(401,'Need to login');
|
||||
|
||||
// If there isnt a term value, return null
|
||||
if (! $request->input('term'))
|
||||
return $result;
|
||||
return [];
|
||||
|
||||
$account_ids = ($x=Auth::user()->accounts)->pluck('id');
|
||||
$user_ids = $x->transform(function($item) { return $item->user;})->pluck('id');
|
||||
$result = collect();
|
||||
$accounts = ($x=Auth::user()->all_accounts())->pluck('id');
|
||||
$users = $x->transform(function($item) { return $item->user;});
|
||||
|
||||
# Look for User
|
||||
foreach (User::Search($request->input('term'))
|
||||
->whereIN('id',$user_ids)
|
||||
->whereIN('id',$users->pluck('id'))
|
||||
->orderBy('lastname')
|
||||
->orderBy('firstname')
|
||||
->limit(10)->get() as $o)
|
||||
{
|
||||
$result->push(['name'=>sprintf('%s (%s) - %s',$o->name,$o->lid,$o->email),'value'=>'/u/home/'.$o->id,'category'=>'Users']);
|
||||
$result->push(['name'=>sprintf('%s %s',$o->aid,$o->name),'value'=>'/u/home/'.$o->id,'category'=>'Users']);
|
||||
}
|
||||
|
||||
# Look for User by Supplier
|
||||
if (is_numeric($request->input('term')))
|
||||
foreach (User::select(['users.*','suppliers.name AS supplier_name','supplier_user.id AS pivot_id'])
|
||||
->join('supplier_user',['supplier_user.user_id'=>'users.id'])
|
||||
->join('suppliers',['suppliers.id'=>'supplier_user.supplier_id'])
|
||||
->whereIN('user_id',$user_ids)
|
||||
->where('supplier_user.id','like','%'.$request->input('term').'%')
|
||||
->orderBy('lastname')
|
||||
->orderBy('firstname')
|
||||
->limit(10)->get() as $o)
|
||||
{
|
||||
$result->push(['name'=>sprintf('%s (%s:%s)',$o->name,$o->supplier_name,$o->pivot_id),'value'=>'/u/home/'.$o->id,'category'=>'Suppliers']);
|
||||
}
|
||||
|
||||
# Look for Account
|
||||
foreach (Account::Search($request->input('term'))
|
||||
->whereIN('user_id',$user_ids)
|
||||
->orderBy('company')
|
||||
->limit(10)->get() as $o)
|
||||
->whereIN('user_id',$users->pluck('id'))
|
||||
->orderBy('company')
|
||||
->limit(10)->get() as $o)
|
||||
{
|
||||
$result->push(['name'=>sprintf('%s (%s)',$o->company,$o->lid),'value'=>'/u/home/'.$o->user_id,'category'=>'Accounts']);
|
||||
$result->push(['name'=>sprintf('%s %s',$o->aid,$o->company),'value'=>'/u/home/'.$o->user_id,'category'=>'Accounts']);
|
||||
}
|
||||
|
||||
# Look for a Service
|
||||
foreach (Service::Search($request->input('term'))
|
||||
->whereIN('account_id',$account_ids)
|
||||
->orderBy('id')
|
||||
->limit(20)->get() as $o)
|
||||
->whereIN('account_id',$accounts)
|
||||
->orderBy('id')
|
||||
->limit(10)->get() as $o)
|
||||
{
|
||||
$result->push(['name'=>sprintf('%s (%s) %s',$o->name,$o->lid,$o->active ? '' : '<small>INACT</small>'),'value'=>'/u/service/'.$o->id,'category'=>$o->category_name]);
|
||||
$result->push(['name'=>sprintf('%s (%s)',$o->name,$o->sid),'value'=>'/u/service/'.$o->id,'category'=>'Services']);
|
||||
}
|
||||
|
||||
# Look for an Invoice
|
||||
foreach (Invoice::Search($request->input('term'))
|
||||
->whereIN('account_id',$account_ids)
|
||||
->orderBy('id')
|
||||
->limit(10)->get() as $o)
|
||||
->whereIN('account_id',$accounts)
|
||||
->orderBy('id')
|
||||
->limit(10)->get() as $o)
|
||||
{
|
||||
$result->push(['name'=>sprintf('%s: %s',$o->lid,$o->account->name),'value'=>'/u/invoice/'.$o->id,'category'=>'Invoices']);
|
||||
$result->push(['name'=>sprintf('%s: %s',$o->sid,$o->account->name),'value'=>'/u/invoice/'.$o->id,'category'=>'Invoices']);
|
||||
}
|
||||
|
||||
if (Gate::any(['wholesaler'],new Payment)) {
|
||||
# Look for Payments
|
||||
foreach (Payment::Search($request->input('term'))
|
||||
->whereIN('account_id',$account_ids)
|
||||
->limit(10)->get() as $o)
|
||||
{
|
||||
$result->push(['name'=>sprintf('%s: %s $%s',$o->lid,$o->account->name,number_format($o->total,2)),'value'=>'/a/payment/addedit/'.$o->id,'category'=>'Payments']);
|
||||
}
|
||||
# Look for an ADSL/NBN Service
|
||||
foreach (Adsl::Search($request->input('term'))
|
||||
->whereIN('account_id',$accounts)
|
||||
->orderBy('service_number')
|
||||
->limit(10)->get() as $o)
|
||||
{
|
||||
$result->push(['name'=>sprintf('%s (%s)',$o->name,$o->service->sid),'value'=>'/u/service/'.$o->id,'category'=>'Broadband']);
|
||||
}
|
||||
|
||||
return $result->sortBy(function($item) { return $item['category'].$item['name']; })->values();
|
||||
# Look for Domain Name
|
||||
foreach (Service\Domain::Search($request->input('term'))
|
||||
->whereIN('account_id',$accounts)
|
||||
->orderBy('domain_name')
|
||||
->limit(10)->get() as $o)
|
||||
{
|
||||
$result->push(['name'=>sprintf('%s (%s)',$o->service_name,$o->service->sid),'value'=>'/u/service/'.$o->id,'category'=>'Domains']);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
|
@ -2,463 +2,146 @@
|
|||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Illuminate\View\View;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
|
||||
use App\Http\Requests\ServiceChangeRequest;
|
||||
use App\Mail\{CancelRequest,ChangeRequest};
|
||||
use App\Models\{Charge,Product,Service};
|
||||
use App\Models\Service;
|
||||
|
||||
class ServiceController extends Controller
|
||||
{
|
||||
/* SERVICE WORKFLOW METHODS */
|
||||
|
||||
/**
|
||||
* Cancel a request to cancel a service
|
||||
*
|
||||
* @param Service $o
|
||||
* @return bool
|
||||
*/
|
||||
private function action_cancel_cancel(Service $o): bool
|
||||
{
|
||||
if (! $o->order_info)
|
||||
$o->order_info = collect();
|
||||
|
||||
$o->order_info->put('cancel_cancel',Carbon::now()->format('Y-m-d H:i:s'));
|
||||
$o->order_status = 'ACTIVE';
|
||||
|
||||
return $o->save();
|
||||
}
|
||||
|
||||
private function action_cancel_pending_enter(Service $o): bool
|
||||
{
|
||||
$o->order_status = 'CANCEL-PENDING';
|
||||
|
||||
return $o->save();
|
||||
}
|
||||
|
||||
private function action_cancelled(Service $o): bool
|
||||
{
|
||||
$o->order_status = 'CANCELLED';
|
||||
$o->active = FALSE;
|
||||
|
||||
return $o->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel a request to change a service
|
||||
*
|
||||
* @param Service $o
|
||||
* @return bool
|
||||
*/
|
||||
private function action_change_cancel(Service $o): bool
|
||||
{
|
||||
if (! $o->order_info)
|
||||
$o->order_info = collect();
|
||||
|
||||
// @todo add some validation if this doesnt return a result
|
||||
$np = $o->changes()->where('service__change.active',TRUE)->where('complete',FALSE)->get()->pop();
|
||||
$np->pivot->active = FALSE;
|
||||
$np->pivot->save();
|
||||
|
||||
$o->order_status = 'ACTIVE';
|
||||
|
||||
return $o->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Action to change a service order_status to another stage
|
||||
* This is a generic function that can redirect the user to a page that is required to completed to enter
|
||||
* the new stage
|
||||
*
|
||||
* @param Service $o
|
||||
* @param string $stage
|
||||
* @return \Illuminate\Contracts\Foundation\Application|RedirectResponse|\Illuminate\Routing\Redirector
|
||||
*/
|
||||
private function action_request_enter_redirect(Service $o,string $stage)
|
||||
{
|
||||
return redirect(sprintf('u/service/%d/%s',$o->id,strtolower($stage)));
|
||||
}
|
||||
|
||||
/* OTHER METHODS */
|
||||
|
||||
public function change_pending(ServiceChangeRequest $request,Service $o)
|
||||
{
|
||||
// @todo add some validation if this doesnt return a result
|
||||
$np = $o->changes()->where('service__change.active',TRUE)->where('complete',FALSE)->get()->pop();
|
||||
|
||||
if ($request->post()) {
|
||||
foreach ($this->service_change_charges($request,$o) as $co)
|
||||
$co->save();
|
||||
|
||||
$o->product_id = Arr::get($request->broadband,'product_id');
|
||||
$o->price = Arr::get($request->broadband,'price');
|
||||
$o->order_status = 'ACTIVE';
|
||||
$o->save();
|
||||
|
||||
$np->pivot->complete = TRUE;
|
||||
$np->pivot->effective_at = Carbon::now();
|
||||
$np->pivot->save();
|
||||
|
||||
return redirect()->to(url('u/service',[$o->id]));
|
||||
}
|
||||
|
||||
return view('service.change_pending')
|
||||
->with('breadcrumb',collect()->merge($o->account->breadcrumb))
|
||||
->with('o',$o)
|
||||
->with('np',$np);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a request to cancel a service
|
||||
* Edit a domain service details
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Service $o
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|RedirectResponse|\Illuminate\Routing\Redirector
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function cancel_request(Request $request,Service $o)
|
||||
public function domain_edit(Request $request,Service $o)
|
||||
{
|
||||
if ($request->post()) {
|
||||
$request->validate([
|
||||
'stop_at'=>'required|date',
|
||||
]);
|
||||
session()->flash('service_update',TRUE);
|
||||
|
||||
if (! $o->order_info)
|
||||
$o->order_info = collect();
|
||||
$validation = $request->validate([
|
||||
'service.domain_name' => sprintf('required|unique:%s,domain_name,%d',$o->type->getTable(),$o->type->id),
|
||||
'service.domain_expire' => 'required|date',
|
||||
'service.domain_tld_id' => 'required|exists:ab_domain_tld,id',
|
||||
'service.domain_registrar_id' => 'required|exists:ab_domain_registrar,id',
|
||||
'service.registrar_account' => 'required',
|
||||
'service.registrar_username' => 'required|string|min:5',
|
||||
'service.registrar_ns' => 'required|string|min:5',
|
||||
]);
|
||||
|
||||
$o->stop_at = $request->stop_at;
|
||||
$o->order_info->put('cancel_note',$request->notes);
|
||||
$o->order_status = 'CANCEL-REQUEST';
|
||||
$o->save();
|
||||
$o->type->forceFill($validation['service'])->save();
|
||||
|
||||
//@todo Get email from DB.
|
||||
Mail::to('help@graytech.net.au')
|
||||
->queue((new CancelRequest($o,$request->notes))->onQueue('email'));
|
||||
|
||||
return redirect('u/service/'.$o->id)->with('success','Cancellation lodged');
|
||||
}
|
||||
|
||||
return view('service.cancel_request')
|
||||
->with('o',$o);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the status of a service
|
||||
* @todo This needs to be optimized
|
||||
*
|
||||
* @note This route is protected by middleware @see ServicePolicy::progress()
|
||||
* It is assumed that the next stage is valid for the services current stage - validated in ServicePolicy::progress()
|
||||
* @param Service $o
|
||||
* @param string $stage
|
||||
* @return RedirectResponse
|
||||
*/
|
||||
public function change(Service $o,string $stage): RedirectResponse
|
||||
{
|
||||
// While stage has a string value, that indicates the next stage we want to go to
|
||||
// If stage is NULL, the current stage hasnt been completed
|
||||
// If stage is FALSE, then the current stage failed, and may optionally be directed to another stage.
|
||||
|
||||
while ($stage) {
|
||||
// Check that stage is a valid next action for the user currently performing it
|
||||
//$current = $this->getStageParameters($this->order_status);
|
||||
$next = $o->getStageParameters($stage);
|
||||
|
||||
// If valid, call the method to confirm that the current stage is complete
|
||||
if ($x=$next->get('enter_method')) {
|
||||
if (! method_exists($this,$x))
|
||||
abort(500,sprintf('ENTER_METHOD [%s]defined doesnt exist',$x));
|
||||
|
||||
Log::debug(sprintf('Running ENTER_METHOD [%s] on Service [%d] to go to stage [%s]',$x,$o->id,$stage));
|
||||
|
||||
// @todo Should call exit_method of the current stage first, to be sure we can change
|
||||
|
||||
try {
|
||||
$result = $this->{$x}($o,$stage);
|
||||
|
||||
// If we have a form to complete, we need to return with a URL, so we can catch that with an Exception
|
||||
} catch (HttpException $e) {
|
||||
if ($e->getStatusCode() == 301)
|
||||
return ($e->getMessage());
|
||||
}
|
||||
|
||||
// An Error Condition
|
||||
if (is_null($result))
|
||||
return redirect()->to('u/service/'.$o->id);
|
||||
|
||||
elseif ($result instanceof RedirectResponse)
|
||||
return $result;
|
||||
|
||||
// The service cannot enter the next stage
|
||||
elseif (! $result)
|
||||
abort(500,'Current Method FAILED: '.$result);
|
||||
|
||||
} else {
|
||||
$o->order_status = $stage;
|
||||
|
||||
if ($stage == 'ACTIVE')
|
||||
$o->active = TRUE;
|
||||
|
||||
$o->save();
|
||||
}
|
||||
|
||||
// If valid, call the method to start the next stage
|
||||
$stage = ''; // @todo this is temporary, we havent written the code to automatically jump to the next stage if wecan
|
||||
}
|
||||
|
||||
return redirect()->to('u/service/'.$o->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a request to cancel a service
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Service $o
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|RedirectResponse|\Illuminate\Routing\Redirector
|
||||
*/
|
||||
public function change_request(Request $request,Service $o)
|
||||
{
|
||||
if ($request->post()) {
|
||||
$request->validate([
|
||||
'product_id'=>'required|exists:products,id',
|
||||
'change_date'=>'required|date',
|
||||
'notes'=>'nullable|min:10',
|
||||
]);
|
||||
|
||||
$o->changes()->attach([$o->id=>[
|
||||
'site_id'=> $o->site_id,
|
||||
'ordered_by' => Auth::id(),
|
||||
'ordered_at' => Carbon::now(),
|
||||
'effective_at' => $request->change_date,
|
||||
'product_id' => $request->product_id,
|
||||
'notes' => $request->notes,
|
||||
'active' => TRUE,
|
||||
'complete' => FALSE,
|
||||
]]);
|
||||
|
||||
$o->order_status = 'CHANGE-REQUEST';
|
||||
$o->save();
|
||||
|
||||
//@todo Get email from DB.
|
||||
Mail::to('help@graytech.net.au')
|
||||
->queue((new ChangeRequest($o,$request->notes))->onQueue('email'));
|
||||
|
||||
return redirect('u/service/'.$o->id)->with('success','Upgrade requested');
|
||||
}
|
||||
|
||||
switch (get_class($o->type)) {
|
||||
default:
|
||||
return view('service.change_request')
|
||||
->with('breadcrumb',collect()->merge($o->account->breadcrumb))
|
||||
->with('o',$o);
|
||||
}
|
||||
return redirect()->back()->with('success','Record updated.');
|
||||
}
|
||||
|
||||
/**
|
||||
* List all the domains managed by the user
|
||||
*
|
||||
* @return View
|
||||
* @todo revalidate
|
||||
*/
|
||||
public function domain_list(): View
|
||||
{
|
||||
$o = Service\Domain::serviceActive()
|
||||
->serviceUserAuthorised(Auth::user())
|
||||
->select('service_domain.*')
|
||||
->join('services',['services.id'=>'service_domain.service_id'])
|
||||
->select('service_domains.*')
|
||||
->join('ab_service',['ab_service.id'=>'service_domains.service_id'])
|
||||
->with(['service.account','registrar'])
|
||||
->get();
|
||||
|
||||
return view('service.domain.list')
|
||||
->with('o',$o);
|
||||
}
|
||||
|
||||
public function email_list(): View
|
||||
{
|
||||
// @todo Need to add the with path when calculating next_billed and price
|
||||
$o = Service\Email::serviceActive()
|
||||
->serviceUserAuthorised(Auth::user())
|
||||
->select('service_email.*')
|
||||
->join('services',['services.id'=>'service_email.service_id'])
|
||||
->with(['service.account','service.product.type.supplied.supplier_detail.supplier','tld'])
|
||||
->get();
|
||||
|
||||
return view('service.email.list')
|
||||
return view('r.service.domain.list')
|
||||
->with('o',$o);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return details on the users service
|
||||
*
|
||||
* @param Service $o
|
||||
* @return View
|
||||
*/
|
||||
public function home(Service $o): View
|
||||
{
|
||||
return View('service.home')
|
||||
->with('breadcrumb',collect()->merge($o->account->breadcrumb))
|
||||
->with('o',$o);
|
||||
}
|
||||
|
||||
public function hosting_list(): View
|
||||
{
|
||||
// @todo Need to add the with path when calculating next_billed and price
|
||||
$o = Service\Host::serviceActive()
|
||||
->serviceUserAuthorised(Auth::user())
|
||||
->select('service_host.*')
|
||||
->join('services',['services.id'=>'service_host.service_id'])
|
||||
->with(['service.account','service.product.type.supplied.supplier_detail.supplier','tld'])
|
||||
->get();
|
||||
|
||||
return view('service.host.list')
|
||||
->with('o',$o);
|
||||
}
|
||||
|
||||
private function service_change_charges(Request $request,Service $o): Collection
|
||||
{
|
||||
$charges = collect();
|
||||
$po = Product::findOrFail(Arr::get($request->broadband,'product_id'));
|
||||
$start_at = Carbon::create(Arr::get($request->broadband,'start_at'));
|
||||
|
||||
// Get the invoiced items covering the start_at date
|
||||
foreach ($o->invoice_items->filter(function($item) use ($start_at) {
|
||||
return ($item->start_at < $start_at) && ($item->stop_at > $start_at) && ($item->item_type === 0);
|
||||
}) as $iio)
|
||||
{
|
||||
// Reverse the original charge
|
||||
$co = new Charge;
|
||||
$co->active = TRUE;
|
||||
$co->service_id = $o->id;
|
||||
$co->account_id = $o->account_id;
|
||||
$co->sweep_type = 6;
|
||||
$co->product_id = $iio->product_id;
|
||||
$co->description = 'Plan Upgrade Adjustment';
|
||||
$co->user_id = Auth::id();
|
||||
$co->type = $iio->item_type;
|
||||
$co->start_at = $start_at;
|
||||
$co->stop_at = $iio->stop_at;
|
||||
$co->amount = $iio->price_base;
|
||||
$co->taxable = TRUE; // @todo this should be determined
|
||||
$co->quantity = -1*$start_at->diff($iio->stop_at)->days/$iio->start_at->diff($iio->stop_at)->days;
|
||||
$charges->push($co);
|
||||
|
||||
// Add the new charge
|
||||
$co = new Charge;
|
||||
$co->active = TRUE;
|
||||
$co->service_id = $o->id;
|
||||
$co->account_id = $o->account_id;
|
||||
$co->sweep_type = 6;
|
||||
$co->product_id = $po->id;
|
||||
$co->description = 'Plan Upgrade Adjustment';
|
||||
$co->user_id = Auth::id();
|
||||
$co->type = $iio->item_type;
|
||||
$co->start_at = $start_at;
|
||||
$co->stop_at = $iio->stop_at;
|
||||
$co->amount = Arr::get($request->broadband,'price') ?: $po->base_charge;
|
||||
$co->taxable = TRUE; // @todo this should be determined
|
||||
$co->quantity = $start_at->diff($iio->stop_at)->days/$iio->start_at->diff($iio->stop_at)->days;
|
||||
$charges->push($co);
|
||||
}
|
||||
|
||||
// Add any fee
|
||||
if (Arr::get($request->broadband,'change_fee')) {
|
||||
$co = new Charge;
|
||||
$co->active = TRUE;
|
||||
$co->service_id = $o->id;
|
||||
$co->account_id = $o->account_id;
|
||||
$co->sweep_type = 6;
|
||||
$co->product_id = $po->id;
|
||||
$co->description = 'Plan Upgrade Fee';
|
||||
$co->user_id = Auth::id();
|
||||
$co->type = 3;
|
||||
$co->start_at = $start_at;
|
||||
$co->stop_at = $start_at;
|
||||
$co->amount = Arr::get($request->broadband,'change_fee');
|
||||
$co->taxable = TRUE; // @todo this should be determined
|
||||
$co->quantity = 1;
|
||||
$charges->push($co);
|
||||
}
|
||||
|
||||
return $charges;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is an API method, that works with service change - to return the new charges as a result of changing a service
|
||||
* Update a service
|
||||
*
|
||||
* @note: Route Middleware protects this path
|
||||
* @param Request $request
|
||||
* @param Service $o
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function service_change_charges_display(Request $request,Service $o)
|
||||
{
|
||||
return view('a.charge.service_change')
|
||||
->with('charges',$this->service_change_charges($request,$o));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update details about a service
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Service $o
|
||||
* @return RedirectResponse
|
||||
* @throws ValidationException
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function update(Request $request,Service $o)
|
||||
{
|
||||
if ($o->type->validation()) {
|
||||
Session::put('service_update',true);
|
||||
$validator = Validator::make($x=$request->post($o->category),$o->type->validation());
|
||||
switch ($o->order_status) {
|
||||
case 'CANCEL-REQUEST':
|
||||
if ($request->post()) {
|
||||
if (! $request->post('date_end'))
|
||||
return redirect()->back()->withErrors('Cancellation Date not provided');
|
||||
|
||||
if ($validator->fails()) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withErrors($validator)
|
||||
->withInput();
|
||||
}
|
||||
$o->date_end = $request->post('date_end');
|
||||
|
||||
$o->type->forceFill($validator->validated());
|
||||
foreach (['cancel_notes'] as $key) {
|
||||
if ($request->post($key))
|
||||
$o->setOrderInfo($key,$request->post($key));
|
||||
}
|
||||
|
||||
} elseif ($request->post($o->product->category)) {
|
||||
$o->type->forceFill($request->post($o->product->category));
|
||||
$o->order_status='CANCEL-PENDING';
|
||||
$o->save();
|
||||
|
||||
return redirect()->to(url('u/service',$o->id))->with('updated','Service cancellation submitted.');
|
||||
}
|
||||
|
||||
return $this->update_request_cancel($o);
|
||||
|
||||
case 'ORDER-SENT':
|
||||
if ($request->post()) {
|
||||
foreach (['reference','notes'] as $key) {
|
||||
$o->setOrderInfo($key,$request->post($key));
|
||||
}
|
||||
|
||||
$o->save();
|
||||
|
||||
foreach ($request->post($o->stype) as $k=>$v) {
|
||||
$o->type->{$k} = $v;
|
||||
}
|
||||
|
||||
$o->type->save();
|
||||
|
||||
return redirect()->to(url('u/service',$o->id))->with('updated','Order sent notes updated.');
|
||||
}
|
||||
|
||||
return $this->update_order_status($o);
|
||||
|
||||
case 'PROVISION-PLANNED':
|
||||
if ($request->post()) {
|
||||
foreach (['provision_notes'] as $key) {
|
||||
$o->setOrderInfo($key,$request->post($key));
|
||||
}
|
||||
|
||||
$o->date_start = $request->post('date_start');
|
||||
|
||||
$o->save();
|
||||
|
||||
foreach ($request->post($o->stype) as $k=>$v) {
|
||||
$o->type->{$k} = $v;
|
||||
}
|
||||
|
||||
$o->type->save();
|
||||
|
||||
return redirect()->to(url('u/service',$o->id))->with('updated','Order sent notes updated.');
|
||||
}
|
||||
|
||||
return $this->update_provision_planned($o);
|
||||
|
||||
default:
|
||||
abort(499,'Not yet implemented');
|
||||
}
|
||||
}
|
||||
|
||||
$o->type->save();
|
||||
private function update_order_status(Service $o)
|
||||
{
|
||||
return View('r.service.order.sent',['o'=>$o]);
|
||||
}
|
||||
|
||||
if ($request->post('invoice_next_at'))
|
||||
$o->invoice_next_at = $request->invoice_next_at;
|
||||
private function update_request_cancel(Service $o)
|
||||
{
|
||||
return View('u.service.order.cancel',['o'=>$o]);
|
||||
}
|
||||
|
||||
if ($request->post('recur_schedule'))
|
||||
$o->recur_schedule = $request->recur_schedule;
|
||||
|
||||
$o->suspend_billing = ($request->suspend_billing == 'on');
|
||||
$o->external_billing = ($request->external_billing == 'on');
|
||||
$o->price = $request->price ?: NULL;
|
||||
|
||||
// Also update our service start_at date.
|
||||
// @todo We may want to make start_at/stop_at dynamic values calculated by the type records
|
||||
if ($request->post('start_at'))
|
||||
$o->start_at = $request->start_at;
|
||||
else {
|
||||
// For broadband, start_at is connect_at in the type record
|
||||
switch ($o->category) {
|
||||
case 'broadband':
|
||||
$o->start_at = $o->type->connect_at;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$o->save();
|
||||
|
||||
return redirect()->back()->with('success','Record Updated');
|
||||
private function update_provision_planned(Service $o)
|
||||
{
|
||||
return View('r.service.order.provision_plan',['o'=>$o]);
|
||||
}
|
||||
}
|
|
@ -1,220 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
use App\Http\Requests\{SupplierAddEdit,SupplierProductAddEdit};
|
||||
use App\Models\{Cost,Supplier,SupplierDetail};
|
||||
use App\Jobs\ImportCosts;
|
||||
|
||||
class SupplierController extends Controller
|
||||
{
|
||||
/**
|
||||
* Update a suppliers details
|
||||
*
|
||||
* @param SupplierAddEdit $request
|
||||
* @param Supplier $o
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function addedit(SupplierAddEdit $request,Supplier $o)
|
||||
{
|
||||
$this->middleware(['auth','wholesaler']);
|
||||
|
||||
foreach ($request->except(['_token','supplier_details','api_key','api_secret','submit']) as $key => $item)
|
||||
$o->{$key} = $item;
|
||||
|
||||
$o->active = (bool)$request->active;
|
||||
|
||||
try {
|
||||
$o->save();
|
||||
|
||||
} catch (\Exception $e) {
|
||||
return redirect()->back()->withErrors($e->getMessage())->withInput();
|
||||
}
|
||||
|
||||
$o->load(['detail']);
|
||||
$oo = $o->detail ?: new SupplierDetail;
|
||||
|
||||
foreach ($request->get('supplier_details',[]) as $key => $item)
|
||||
$oo->{$key} = $item;
|
||||
|
||||
$oo->connections = $oo->connections->merge([
|
||||
'api_key'=>$request->get('api_key'),
|
||||
'api_secret'=>$request->get('api_secret'),
|
||||
])->filter();
|
||||
$o->detail()->save($oo);
|
||||
|
||||
return redirect()->back()
|
||||
->with('success','Supplier Saved');
|
||||
}
|
||||
|
||||
/**
|
||||
* Site up site wide suppliers, or a site's supplier details
|
||||
*
|
||||
* @note This method is protected by the routes
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function admin_home()
|
||||
{
|
||||
$this->middleware(['auth','wholesaler']);
|
||||
|
||||
return view('supplier.home');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the suppliers invoice
|
||||
*
|
||||
* @param Cost $o
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function cost(Cost $o)
|
||||
{
|
||||
// @todo Need to add the services that are active that are not on the bill for the supplier.
|
||||
return view('supplier.cost.view',['o'=>$o]);
|
||||
}
|
||||
|
||||
public function cost_add(Supplier $o)
|
||||
{
|
||||
return view('supplier.cost.add',['o'=>$o]);
|
||||
}
|
||||
|
||||
public function cost_submit(Request $request,Supplier $o)
|
||||
{
|
||||
$request->validate([
|
||||
'file' => 'required|filled',
|
||||
'billed_at' => 'required|date',
|
||||
]);
|
||||
|
||||
$filename = $request->file('file')->store('cost_import');
|
||||
|
||||
ImportCosts::dispatch(
|
||||
config('site'),
|
||||
$o,
|
||||
Carbon::create($request->billed_at),
|
||||
$filename,
|
||||
)->onQueue('low');
|
||||
|
||||
return redirect()->back()->with('success','File uploaded');
|
||||
}
|
||||
|
||||
/**
|
||||
* New Product from a supplier
|
||||
*
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function product_add()
|
||||
{
|
||||
return view('supplier.product.addedit')
|
||||
->with('o',new Supplier)
|
||||
->with('oo',NULL);
|
||||
}
|
||||
|
||||
public function product_addedit(SupplierProductAddEdit $request,Supplier $o,int $id,string $type)
|
||||
{
|
||||
// Quick validation
|
||||
if ($type !== $request->offering_type)
|
||||
abort(500,'Type and offering type do not match');
|
||||
if ($o->exists && ($o->detail->id !== (int)$request->supplier_detail_id))
|
||||
abort(500,sprintf('Supplier [%d] and supplier_detail_id [%d] do not match',$o->detail->id,$request->supplier_detail_id));
|
||||
|
||||
switch ($request->offering_type) {
|
||||
case 'broadband':
|
||||
$oo = Supplier\Broadband::findOrNew($id);
|
||||
|
||||
// @todo these are broadband requirements - get them from the broadband class.
|
||||
foreach ($request->only([
|
||||
'supplier_detail_id',
|
||||
'product_id'.
|
||||
'product_desc',
|
||||
'base_cost',
|
||||
'setup_cost',
|
||||
'contract_term',
|
||||
'metric',
|
||||
'speed',
|
||||
'technology',
|
||||
'offpeak_start',
|
||||
'offpeak_end',
|
||||
'base_down_peak',
|
||||
'base_up_peak',
|
||||
'base_down_offpeak',
|
||||
'base_up_offpeak',
|
||||
'extra_down_peak',
|
||||
'extra_up_peak',
|
||||
'extra_down_offpeak',
|
||||
'extra_up_offpeak',
|
||||
]) as $key => $value)
|
||||
$oo->$key = $value;
|
||||
|
||||
// Our boolean values
|
||||
foreach ($request->only(['active','extra_shaped','extra_charged']) as $key => $value)
|
||||
$oo->$key = ($value == 'on' ? 1 : 0);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new \Exception('Unknown offering type:'.$request->offering_type);
|
||||
}
|
||||
|
||||
$oo->save();
|
||||
|
||||
return redirect()->back()
|
||||
->with('success','Saved');
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit a supplier product
|
||||
*
|
||||
* @param Supplier $o
|
||||
* @param int $id
|
||||
* @param string $type
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function product_view(Supplier $o,int $id,string $type)
|
||||
{
|
||||
$oo = $o->detail->find($type,$id);
|
||||
$oo->load(['products.product.services.product.type']);
|
||||
|
||||
return view('supplier.product.addedit')
|
||||
->with('o',$o)
|
||||
->with('oo',$oo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the form for a specific product type
|
||||
*
|
||||
* @param Request $request
|
||||
* @param string $type
|
||||
* @param int|null $id
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function product_view_type(Request $request,string $type,int $id=NULL)
|
||||
{
|
||||
$o = $id ? Supplier::offeringTypeClass($type)->findOrFail($id) : NULL;
|
||||
|
||||
if ($request->old)
|
||||
$request->session()->flashInput($request->old);
|
||||
|
||||
if ($o)
|
||||
$o->load(['products.product.services']);
|
||||
|
||||
return view('supplier.product.widget.'.$type)
|
||||
->with('o',$id ? $o : NULL)
|
||||
->withErrors($request->errors);
|
||||
}
|
||||
|
||||
/**
|
||||
* View a supplier.
|
||||
*
|
||||
* @param Supplier|null $o
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function view(?Supplier $o)
|
||||
{
|
||||
$this->middleware(['auth','wholesaler']);
|
||||
|
||||
return view('supplier.details')
|
||||
->with('o',$o);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Supplier;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class SuppliersController extends Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('auth ');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return view('r/supplier/index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
return view('r/supplier/create');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
// @todo Insure site index is included.
|
||||
$o = new Supplier;
|
||||
$o->name = $request->input('name');
|
||||
$o->active = 1;
|
||||
$o->account_mgr = '';
|
||||
$o->account_email = '';
|
||||
$o->email_provision = '';
|
||||
$o->email_support = '';
|
||||
$o->phone_provision = '';
|
||||
$o->phone_support = '';
|
||||
$o->save();
|
||||
|
||||
echo 'REDIRECT TO <a href="'.url('r/supplier/index').'">here</a>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @param \App\suppliers $suppliers
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function show(suppliers $suppliers)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param \App\suppliers $suppliers
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function edit(suppliers $suppliers)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \App\suppliers $suppliers
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(Request $request, suppliers $suppliers)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param \App\suppliers $suppliers
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(suppliers $suppliers)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
|
@ -24,13 +24,13 @@ class AccountController extends Controller
|
|||
});
|
||||
|
||||
// Get our invoice due date for this invoice
|
||||
$io->due_at = $s->min(function($item) { return $item->invoice_next; });
|
||||
$io->due_date = $s->min(function($item) { return $item->invoice_next; });
|
||||
|
||||
// @todo The days in advance is an application parameter
|
||||
$io->created_at = $io->due_at->subDays(30);
|
||||
$io->date_orig = $io->due_date->subDays(30);
|
||||
|
||||
// Work out items to add to this invoice, plus any in the next additional days
|
||||
$days = now()->diffInDays($io->due_at)+1+7;
|
||||
$days = now()->diffInDays($io->due_date)+1+7;
|
||||
foreach ($s as $so)
|
||||
{
|
||||
if ($so->isInvoiceDueSoon($days))
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
use App\Models\{Supplier,User};
|
||||
|
||||
class UserController extends Controller
|
||||
{
|
||||
/**
|
||||
* Add a supplier to a user's profile
|
||||
*
|
||||
* @param Request $request
|
||||
* @param User $o
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function supplier_addedit(Request $request,User $o)
|
||||
{
|
||||
Session::put('supplier_update',true);
|
||||
|
||||
$validated = $request->validate([
|
||||
'id'=> ['required','string',Rule::unique('supplier_user')->where(fn ($query) => $query->where('supplier_id',$request->supplier_id)->where('user_id','<>',$o->id))],
|
||||
'supplier_id'=>'required|exists:suppliers,id',
|
||||
]);
|
||||
|
||||
$o->suppliers()->attach([
|
||||
$validated['supplier_id'] => [
|
||||
'id'=>$validated['id'],
|
||||
'site_id'=>$o->site_id,
|
||||
'created_at'=>Carbon::now(),
|
||||
]
|
||||
]);
|
||||
|
||||
return redirect()->back()->with('success','Supplier Added');
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a supplier from a user's profile
|
||||
*
|
||||
* @param User $o
|
||||
* @param Supplier $so
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function supplier_delete(User $o,Supplier $so)
|
||||
{
|
||||
Session::put('supplier_update',true);
|
||||
|
||||
$o->suppliers()->detach([$so->id]);
|
||||
|
||||
return redirect()->back()->with('success','Supplier Deleted');
|
||||
}
|
||||
}
|
|
@ -2,12 +2,18 @@
|
|||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class WelcomeController extends Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('demoMode');
|
||||
}
|
||||
|
||||
public function home() {
|
||||
return view('welcome.home');
|
||||
}
|
||||
|
||||
public function under_construction() {
|
||||
abort(499,'Under Construction');
|
||||
}
|
||||
}
|
|
@ -6,18 +6,8 @@ use App\Http\Controllers\Controller;
|
|||
|
||||
class ReportController extends Controller
|
||||
{
|
||||
public function accounts()
|
||||
{
|
||||
return view('account/report');
|
||||
}
|
||||
|
||||
public function products()
|
||||
{
|
||||
return view('product/report');
|
||||
}
|
||||
|
||||
public function services()
|
||||
{
|
||||
return view('service/report');
|
||||
return view('a/product/report');
|
||||
}
|
||||
}
|
|
@ -36,6 +36,7 @@ class Kernel extends HttpKernel
|
|||
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
|
||||
\App\Http\Middleware\VerifyCsrfToken::class,
|
||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
// \App\Http\Middleware\SetSite::class,
|
||||
\Laravel\Passport\Http\Middleware\CreateFreshApiToken::class,
|
||||
],
|
||||
|
||||
|
@ -58,6 +59,7 @@ class Kernel extends HttpKernel
|
|||
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
|
||||
'can' => \Illuminate\Auth\Middleware\Authorize::class,
|
||||
'demoMode' => \Spatie\DemoMode\DemoMode::class,
|
||||
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
|
||||
'role' => \App\Http\Middleware\Role::class,
|
||||
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
|
||||
|
|
|
@ -5,15 +5,12 @@ namespace App\Http\Middleware;
|
|||
use Illuminate\Support\Facades\Auth;
|
||||
use Closure;
|
||||
|
||||
/**
|
||||
* Enable us to use the role during middleware authorisation
|
||||
*/
|
||||
class Role
|
||||
{
|
||||
public function handle($request, Closure $next, $role)
|
||||
{
|
||||
if ($role AND ! Auth::user())
|
||||
abort(403,'Not Authenticated');
|
||||
return abort(303,'Not Authenticated');
|
||||
|
||||
switch ($role) {
|
||||
case 'wholesaler':
|
||||
|
|
|
@ -43,7 +43,7 @@ class SetSite
|
|||
}
|
||||
|
||||
// Set who we are in SETUP.
|
||||
Config::set('site',$so);
|
||||
Config::set('SITE',$so);
|
||||
if (! $request->ajax())
|
||||
View::share('site',$so);
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
namespace App\Http\Middleware;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Middleware\TrustProxies as Middleware;
|
||||
use Fideloper\Proxy\TrustProxies as Middleware;
|
||||
|
||||
class TrustProxies extends Middleware
|
||||
{
|
||||
|
@ -19,10 +19,5 @@ class TrustProxies extends Middleware
|
|||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $headers =
|
||||
Request::HEADER_X_FORWARDED_FOR |
|
||||
Request::HEADER_X_FORWARDED_HOST |
|
||||
Request::HEADER_X_FORWARDED_PORT |
|
||||
Request::HEADER_X_FORWARDED_PROTO |
|
||||
Request::HEADER_X_FORWARDED_AWS_ELB;
|
||||
protected $headers = Request::HEADER_X_FORWARDED_ALL;
|
||||
}
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
/**
|
||||
* Editing Suppliers
|
||||
*/
|
||||
class CheckoutAddEdit extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return Auth::user()->isWholesaler();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'name' => 'required|string|min:2|max:255',
|
||||
'active' => 'sometimes|accepted',
|
||||
'description' => 'nullable|string|min:2|max:255',
|
||||
];
|
||||
}
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
/**
|
||||
* Editing Suppliers
|
||||
*/
|
||||
class ProductAddEdit extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return Auth::user()->isWholesaler();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'translate.name_short' => 'required|string|min:2|max:100',
|
||||
'translate.name_detail' => 'required|string|min:2|max:100',
|
||||
'translate.description' => 'required|string|min:2|max:65535',
|
||||
'active' => 'sometimes|accepted',
|
||||
'model' => 'sometimes|string', // @todo Check that it is a valid model type
|
||||
'model_id' => 'sometimes|int', // @todo Check that it is a valid model type
|
||||
'accounting' => 'nullable|array', // @todo Validate that the value is in the accounting system
|
||||
'pricing' => 'required|array', // @todo Validate the elements in the pricing
|
||||
];
|
||||
}
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class ServiceChangeRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return $this->route('o')->serviceUserAuthorised(Auth::user());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
* @todo This is specific to broadband - this needs to be more generic.
|
||||
*/
|
||||
public function rules(Request $request)
|
||||
{
|
||||
if (! $request->isMethod('post'))
|
||||
return [];
|
||||
|
||||
return [
|
||||
'broadband.product_id' => 'required|exists:products,id',
|
||||
'broadband.change_fee' => 'nullable|numeric',
|
||||
'broadband.price' => 'nullable|numeric',
|
||||
'broadband.start_at' => 'required|date', // @todo Check that it is not more than 1 billing cycle ago, and not future.
|
||||
];
|
||||
}
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
/**
|
||||
* Editing Suppliers
|
||||
*/
|
||||
class SupplierAddEdit extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return Auth::user()->isWholesaler();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'name' => 'required|string|min:2|max:255',
|
||||
'active' => 'sometimes|accepted',
|
||||
'address1' => 'nullable|string|min:2|max:255',
|
||||
'address2' => 'nullable|string|min:2|max:255',
|
||||
'city' => 'nullable|string|min:2|max:64',
|
||||
'state' => 'nullable|string|min:2|max:32',
|
||||
'postcode' => 'nullable|string|min:2|max:8',
|
||||
'supplier_details.notes' => 'nullable|string|min:3',
|
||||
'supplier_details.accounts' => 'nullable|email',
|
||||
'supplier_details.support' => 'nullable|email',
|
||||
'supplier_details.payments' => 'nullable|string|min:3',
|
||||
'api_key' => 'nullable|string|min:3',
|
||||
'api_secret' => 'nullable|string|min:3',
|
||||
];
|
||||
}
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
use App\Models\Supplier;
|
||||
|
||||
class SupplierProductAddEdit extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return Auth::user()->isWholesaler();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function rules(Request $request)
|
||||
{
|
||||
// @todo these are broadband requirements - perhaps move them to the broadband class.
|
||||
// @todo Enhance the validation so that extra_* values are not accepted if base_* values are not included.
|
||||
return [
|
||||
'id' => 'required|nullable',
|
||||
'offering_type' => ['required',Rule::in(Supplier::offeringTypeKeys()->toArray())],
|
||||
'supplier_detail_id' => 'required|exists:supplier_details,id',
|
||||
'active' => 'sometimes|accepted',
|
||||
'extra_shaped' => 'sometimes|accepted',
|
||||
'extra_charged' => 'sometimes|accepted',
|
||||
'product_id' => 'required|string|min:2',
|
||||
'product_desc' => 'required|string|min:2',
|
||||
'base_cost' => 'required|numeric|min:.01',
|
||||
'setup_cost' => 'nullable|numeric',
|
||||
'contract_term' => 'nullable|numeric|min:1',
|
||||
'metric' => 'nullable|numeric|min:1',
|
||||
'speed' => 'nullable|string|max:64',
|
||||
'technology' => 'nullable|string|max:255',
|
||||
'offpeak_start' => 'nullable|date_format:H:i',
|
||||
'offpeak_end' => 'nullable|date_format:H:i',
|
||||
'base_down_peak' => 'nullable|numeric',
|
||||
'base_up_peak' => 'nullable|numeric',
|
||||
'base_down_offpeak' => 'nullable|numeric',
|
||||
'base_up_offpeak' => 'nullable|numeric',
|
||||
'extra_down_peak' => 'nullable|numeric',
|
||||
'extra_up_peak' => 'nullable|numeric',
|
||||
'extra_down_offpeak' => 'nullable|numeric',
|
||||
'extra_up_offpeak' => 'nullable|numeric',
|
||||
];
|
||||
}
|
||||
}
|
|
@ -9,12 +9,12 @@ interface IDs
|
|||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getLIDAttribute(): string;
|
||||
public function getLIDattribute(): string;
|
||||
|
||||
/**
|
||||
* Return the system ID of the item
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getSIDAttribute(): string;
|
||||
public function getSIDattribute(): string;
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Interfaces;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
interface ProductItem
|
||||
{
|
||||
/**
|
||||
* Return the traffic inclusion with the service
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function allowance(): Collection;
|
||||
|
||||
/**
|
||||
* Render the traffic inclusion as a string
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function allowance_string(): string;
|
||||
|
||||
/**
|
||||
* Does this offering capture usage information
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasUsage(): bool;
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
namespace App\Interfaces;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
interface ProductSupplier
|
||||
{
|
||||
/**
|
||||
* Return the traffic inclusion with the service
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function allowance(): Collection;
|
||||
|
||||
/**
|
||||
* Render the traffic inclusion as a string
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function allowance_string(): string;
|
||||
|
||||
/**
|
||||
* Return the product cost
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function getCostAttribute(): float;
|
||||
|
||||
/**
|
||||
* Return the supplier class
|
||||
* If there is a model relationship return:
|
||||
* return $this->getRelationValue('supplier');
|
||||
* otherwise return a stdClass with name
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getSupplierAttribute();
|
||||
}
|
|
@ -6,13 +6,6 @@ use Carbon\Carbon;
|
|||
|
||||
interface ServiceItem
|
||||
{
|
||||
/**
|
||||
* Months the service is contracted for.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getContractTermAttribute(): int;
|
||||
|
||||
/**
|
||||
* Return the Service Description.
|
||||
*
|
||||
|
@ -23,7 +16,7 @@ interface ServiceItem
|
|||
/**
|
||||
* Date the service expires
|
||||
*/
|
||||
public function getServiceExpireAttribute(): ?Carbon;
|
||||
public function getServiceExpireAttribute(): Carbon;
|
||||
|
||||
/**
|
||||
* Return the Service Name.
|
||||
|
@ -32,13 +25,6 @@ interface ServiceItem
|
|||
*/
|
||||
public function getServiceNameAttribute(): string;
|
||||
|
||||
/**
|
||||
* Has this service expired
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasExpired(): bool;
|
||||
|
||||
/**
|
||||
* Is this service in a contract
|
||||
*
|
||||
|
|
|
@ -6,13 +6,6 @@ use Illuminate\Support\Collection;
|
|||
|
||||
interface ServiceUsage
|
||||
{
|
||||
/**
|
||||
* Our model that holds traffic information
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function traffic();
|
||||
|
||||
/**
|
||||
* This service provides usage information
|
||||
*
|
||||
|
|
|
@ -1,107 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldBeUnique;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Intuit\Jobs\AccountingCustomerUpdate;
|
||||
|
||||
use App\Models\{Account,ProviderToken};
|
||||
|
||||
/**
|
||||
* Synchronise customers with our accounts.
|
||||
*
|
||||
* This will:
|
||||
* + Create the account in the accounting system
|
||||
* + Update the account in the accounting system with our data (we are master)
|
||||
*/
|
||||
class AccountingAccountSync implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
private const LOGKEY = 'JAS';
|
||||
|
||||
private ProviderToken $to;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
* @param ProviderToken $to
|
||||
*/
|
||||
public function __construct(ProviderToken $to)
|
||||
{
|
||||
$this->to = $to;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
* @return void
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$api = $this->to->API();
|
||||
$ref = Account::select('id','site_id','company','user_id')->with(['user'])->get();
|
||||
|
||||
foreach ($api->getCustomers() as $acc) {
|
||||
$o = NULL;
|
||||
|
||||
// See if we are already linked
|
||||
if (($x=$this->to->provider->accounts->where('pivot.ref',$acc->id))->count() === 1) {
|
||||
$o = $x->pop();
|
||||
|
||||
// If not, see if our reference matches
|
||||
} elseif (($x=$ref->filter(function($item) use ($acc) { return $item->sid == $acc->ref; }))->count() === 1) {
|
||||
$o = $x->pop();
|
||||
|
||||
// Look based on Name
|
||||
} elseif (($x=$ref->filter(function($item) use ($acc) { return $item->company == $acc->companyname || $item->name == $acc->fullname || $item->user->email == $acc->email; }))->count() === 1) {
|
||||
$o = $x->pop();
|
||||
|
||||
} else {
|
||||
// Log not found
|
||||
Log::alert(sprintf('%s:Customer not found [%s:%s]',self::LOGKEY,$acc->id,$acc->DisplayName));
|
||||
continue;
|
||||
}
|
||||
|
||||
$o->providers()->syncWithoutDetaching([
|
||||
$this->to->provider->id => [
|
||||
'ref' => $acc->id,
|
||||
'synctoken' => $acc->synctoken,
|
||||
'created_at'=>Carbon::create($acc->created_at),
|
||||
'updated_at'=>Carbon::create($acc->updated_at),
|
||||
'site_id'=>$this->to->site_id,
|
||||
],
|
||||
]);
|
||||
|
||||
Log::alert(sprintf('%s:Customer updated [%s:%s]',self::LOGKEY,$o->id,$acc->id));
|
||||
|
||||
// Check if QB is out of Sync and update it.
|
||||
$acc->syncOriginal();
|
||||
$acc->PrimaryEmailAddr = (object)['Address'=>$o->user->email];
|
||||
$acc->ResaleNum = $o->sid;
|
||||
$acc->GivenName = $o->user->firstname;
|
||||
$acc->FamilyName = $o->user->lastname;
|
||||
$acc->CompanyName = $o->name;
|
||||
$acc->DisplayName = $o->name;
|
||||
$acc->FullyQualifiedName = $o->name;
|
||||
//$acc->Active = (bool)$o->active; // @todo implement in-activity, but only if all invoices are paid and services cancelled
|
||||
|
||||
if ($acc->getDirty()) {
|
||||
Log::info(sprintf('%s:Customer [%s] (%s:%s) has changed',self::LOGKEY,$o->sid,$acc->id,$acc->DisplayName),['dirty'=>$acc->getDirty()]);
|
||||
$acc->sparse = 'true';
|
||||
|
||||
AccountingCustomerUpdate::dispatch($this->to,$acc);
|
||||
}
|
||||
|
||||
// @todo Identify accounts in our DB that are not in accounting
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,142 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldBeUnique;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
use App\Models\{Account,Invoice,Payment,PaymentItem,ProviderToken,Site};
|
||||
use Intuit\Models\Payment as PaymentModel;
|
||||
|
||||
/**
|
||||
* Synchronise payments with our payments.
|
||||
*
|
||||
* This will:
|
||||
* + Create/Update the payment in our system
|
||||
* + Associate the payment to the same invoice in our system
|
||||
*/
|
||||
class AccountingPaymentSync implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
private const LOGKEY = 'JPS';
|
||||
|
||||
private PaymentModel $pmi;
|
||||
private ProviderToken $to;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(ProviderToken $to,PaymentModel $pmi)
|
||||
{
|
||||
$this->pmi = $pmi;
|
||||
$this->to = $to;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
* @return void
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
// @todo Can this be automatically determined?
|
||||
$site = Site::findOrFail($this->to->site_id);
|
||||
Config::set('site',$site);
|
||||
|
||||
// See if we are already linked
|
||||
if (($x=$this->to->provider->payments->where('pivot.ref',$this->pmi->id))->count() === 1) {
|
||||
$o = $x->pop();
|
||||
|
||||
} else {
|
||||
// Find the account
|
||||
$ao = Account::select('accounts.*')
|
||||
->join('account__provider',['account__provider.account_id'=>'accounts.id'])
|
||||
->where('provider_oauth_id',$this->to->provider_oauth_id)
|
||||
->where('ref',$this->pmi->account_ref)
|
||||
->single();
|
||||
|
||||
if (! $ao) {
|
||||
Log::alert(sprintf('%s:Account not found for payment [%s:%d]',self::LOGKEY,$this->pmi->id,$this->pmi->account_ref));
|
||||
return;
|
||||
}
|
||||
|
||||
// Create the payment
|
||||
$o = new Payment;
|
||||
$o->account_id = $ao->id;
|
||||
$o->site_id = $ao->site_id; // @todo Automatically determine
|
||||
}
|
||||
|
||||
// Update the payment details
|
||||
$o->paid_at = $this->pmi->date_paid;
|
||||
$o->active = TRUE;
|
||||
$o->checkout_id = 2; // @todo
|
||||
$o->total_amt = $this->pmi->total_amt;
|
||||
$o->notes = 'Imported from Intuit';
|
||||
$o->save();
|
||||
|
||||
Log::info(sprintf('%s:Recording payment [%s:%3.2f]',self::LOGKEY,$this->pmi->id,$this->pmi->total_amt));
|
||||
|
||||
$o->providers()->syncWithoutDetaching([
|
||||
$this->to->provider->id => [
|
||||
'ref' => $this->pmi->id,
|
||||
'synctoken' => $this->pmi->synctoken,
|
||||
'created_at'=>Carbon::create($this->pmi->created_at),
|
||||
'updated_at'=>Carbon::create($this->pmi->updated_at),
|
||||
'site_id'=>$this->to->site_id,
|
||||
],
|
||||
]);
|
||||
|
||||
// Load the invoice that this payment pays
|
||||
$invoices = collect();
|
||||
foreach ($this->pmi->lines() as $item => $amount) {
|
||||
$invoice = Invoice::select('invoices.*')
|
||||
->join('invoice__provider',['invoice__provider.invoice_id'=>'invoices.id'])
|
||||
->where('provider_oauth_id',$this->to->provider_oauth_id)
|
||||
->where('ref',$item)
|
||||
->single();
|
||||
|
||||
$invoices->put($item,$invoice);
|
||||
}
|
||||
|
||||
// Delete existing paid invoices that are no longer paid
|
||||
foreach ($o->items as $pio)
|
||||
if ($invoices->pluck('id')->search($pio->invoice_id) === FALSE)
|
||||
$pio->delete();
|
||||
|
||||
// Update payment items
|
||||
foreach ($this->pmi->lines() as $item => $amount) {
|
||||
if (! $invoices->has($item)) {
|
||||
Log::alert(sprintf('%s:Invoice [%s] not recorded, payment not assigned',self::LOGKEY,$item));
|
||||
continue;
|
||||
}
|
||||
|
||||
$io = $invoices->get($item);
|
||||
|
||||
// If the payment item already exists
|
||||
if (($x=$o->items->where('invoice_id',$io->id))->count()) {
|
||||
$pio = $x->pop();
|
||||
|
||||
} else {
|
||||
$pio = new PaymentItem;
|
||||
$pio->invoice_id = $io->id;
|
||||
$pio->site_id = $io->site_id;
|
||||
}
|
||||
|
||||
$pio->amount = $amount;
|
||||
$o->items()->save($pio);
|
||||
}
|
||||
|
||||
Log::alert(sprintf('%s:Payment updated [%s:%s]',self::LOGKEY,$o->id,$this->pmi->id));
|
||||
}
|
||||
}
|
|
@ -1,86 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldBeUnique;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
use App\Models\{Tax,ProviderToken};
|
||||
|
||||
/**
|
||||
* Synchronise TAX ids with our taxes.
|
||||
*
|
||||
* This will only update our records, it wont create new records in the account system, nor in our DB
|
||||
*/
|
||||
class AccountingTaxSync implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
private const LOGKEY = 'JTS';
|
||||
|
||||
private ProviderToken $to;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
* @param ProviderToken $to
|
||||
*/
|
||||
public function __construct(ProviderToken $to)
|
||||
{
|
||||
$this->to = $to;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
* @return void
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$api = $this->to->API();
|
||||
$ref = Tax::select(['id','description'])->get();
|
||||
|
||||
foreach ($api->getTaxCodes() as $acc) {
|
||||
$o = NULL;
|
||||
|
||||
// See if we are already linked
|
||||
if (($x=$this->to->provider->taxes->where('pivot.ref',$acc->id))->count() === 1) {
|
||||
$o = $x->pop();
|
||||
|
||||
/*
|
||||
// If not, see if our reference matches
|
||||
} elseif (($x=$ref->filter(function($item) use ($acc) { return $item->sid == $acc->ref; }))->count() === 1) {
|
||||
$o = $x->pop();
|
||||
*/
|
||||
|
||||
// Look based on Name
|
||||
} elseif (($x=$ref->filter(function($item) use ($acc) { return $item->description === $acc->name; }))->count() === 1) {
|
||||
$o = $x->pop();
|
||||
|
||||
} else {
|
||||
// Log not found
|
||||
Log::alert(sprintf('%s:Tax not found [%s:%s]',self::LOGKEY,$acc->id,$acc->name));
|
||||
continue;
|
||||
}
|
||||
|
||||
$o->providers()->syncWithoutDetaching([
|
||||
$this->to->provider->id => [
|
||||
'ref' => $acc->id,
|
||||
'synctoken' => $acc->synctoken,
|
||||
'created_at'=>Carbon::create($acc->created_at),
|
||||
'updated_at'=>Carbon::create($acc->updated_at),
|
||||
'site_id'=>$this->to->site_id,
|
||||
],
|
||||
]);
|
||||
|
||||
Log::alert(sprintf('%s:Tax updated [%s:%s]',self::LOGKEY,$o->id,$acc->id));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,20 +5,18 @@ namespace App\Jobs;
|
|||
use Carbon\Carbon;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
|
||||
use App\Classes\External\Supplier as ExternalSupplier;
|
||||
use App\Mail\TrafficMismatch;
|
||||
use App\Models\Supplier;
|
||||
use App\Models\Service\Broadband as ServiceBroadband;
|
||||
use App\Models\Usage\Broadband as UsageBroadband;
|
||||
use App\Models\Service\Adsl;
|
||||
use App\Models\Service\AdslTraffic;
|
||||
use App\Models\AdslSupplier;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
|
||||
/**
|
||||
* Class BroadbandTraffic
|
||||
|
@ -26,20 +24,18 @@ use App\Models\Usage\Broadband as UsageBroadband;
|
|||
*
|
||||
* @package App\Jobs
|
||||
*/
|
||||
final class BroadbandTraffic implements ShouldQueue
|
||||
class BroadbandTraffic implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
private const LOGKEY = 'JBT';
|
||||
|
||||
protected Model $o; // The supplier we are updating from
|
||||
private const class_prefix = 'App\Classes\External\Supplier\\';
|
||||
protected $aso = NULL; // The supplier we are updating from
|
||||
private $class_prefix = 'App\Classes\External\Supplier\\';
|
||||
|
||||
private const traffic = 'broadband';
|
||||
|
||||
public function __construct(Supplier $o)
|
||||
public function __construct(AdslSupplier $o)
|
||||
{
|
||||
$this->o = $o;
|
||||
$this->aso = $o;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -47,40 +43,35 @@ final class BroadbandTraffic implements ShouldQueue
|
|||
*
|
||||
* @return void
|
||||
* @throws \Exception
|
||||
* @todo The column stats_lastupdate is actually the "next" date that stats should be retrieved. Rename it.
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
Log::info(sprintf('%s:Importing Broadband Traffic from [%s]',self::LOGKEY,$this->o->name));
|
||||
|
||||
if ((! $connection=$this->o->detail->connections->get('broadband')) || (count(array_intersect(array_keys($connection),ExternalSupplier::traffic_connection_keys)) !== 3))
|
||||
throw new \Exception('No or missing connection details for:'.self::traffic);
|
||||
Log::info(sprintf('%s:Importing Broadband Traffic from [%s]',self::LOGKEY,$this->aso->name),['m'=>__METHOD__]);
|
||||
|
||||
$u = 0;
|
||||
|
||||
// Load our class for this supplier
|
||||
$class = self::class_prefix.$this->o->name;
|
||||
$class = $this->class_prefix.$this->aso->name;
|
||||
if (class_exists($class)) {
|
||||
$o = new $class($this->o);
|
||||
$o = new $class($this->aso);
|
||||
|
||||
} else {
|
||||
Log::error(sprintf('%s: Class doesnt exist: %s',self::LOGKEY,$class));
|
||||
Log::error(sprintf('%s: Class doesnt exist: %d',get_class($this),$class));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$last_update = Carbon::create(Arr::get($connection,'last'))->addDay();
|
||||
Arr::set($connection,'last',$last_update->format('Y-m-d'));
|
||||
|
||||
// Repeat pull traffic data until yesterday
|
||||
while ($last_update < Carbon::now()->subDay()) {
|
||||
Log::notice(sprintf('%s:Next update is [%s]',self::LOGKEY,$last_update->format('Y-m-d')));
|
||||
while ($this->aso->stats_lastupdate < Carbon::now()->subDay()) {
|
||||
Log::notice(sprintf('%s:Next update is [%s]',self::LOGKEY,$this->aso->stats_lastupdate->format('Y-m-d')),['m'=>__METHOD__]);
|
||||
|
||||
// Delete traffic, since we'll refresh it.
|
||||
UsageBroadband::where('supplier_id',$this->o->id)
|
||||
->where('date',$last_update->format('Y-m-d'))
|
||||
AdslTraffic::where('supplier_id',$this->aso->id)
|
||||
->where('date',$this->aso->stats_lastupdate)
|
||||
->delete();
|
||||
|
||||
$c = 0;
|
||||
foreach ($o->fetch($connection,self::traffic) as $line) {
|
||||
foreach ($o->fetch() as $line) {
|
||||
// The first row is our header
|
||||
if (! $c++) {
|
||||
$fields = $o->getColumns(preg_replace('/,\s+/',',',$line),collect($o->header()));
|
||||
|
@ -88,26 +79,29 @@ final class BroadbandTraffic implements ShouldQueue
|
|||
}
|
||||
|
||||
if (! $fields->count())
|
||||
abort(500,'? No fields in data export');
|
||||
abort(500,'? No fields in data exportupda');
|
||||
|
||||
$row = str_getcsv(trim($line));
|
||||
|
||||
try {
|
||||
// @todo Put the date format in the DB.
|
||||
$date = Carbon::createFromFormat('Y-m-d',$row[$o->getColumnKey('Date')]);
|
||||
// Find the right service dependent on the dates we supplied the service
|
||||
$oo = ServiceBroadband::where('service_username',$row[$o->getColumnKey('Login')])
|
||||
->select(DB::raw('service_broadband.*'))
|
||||
->join('services','services.id','=','service_id')
|
||||
->where('services.start_at','<=',$date)
|
||||
->where(function($query) use ($date) {
|
||||
$query->whereNULL('services.stop_at')
|
||||
->orWhere('services.stop_at','<=',$date);
|
||||
})
|
||||
->single();
|
||||
|
||||
$to = new UsageBroadband;
|
||||
$to->date = $last_update;
|
||||
$to->supplier_id = $this->o->id;
|
||||
// Find the right service dependant on the dates we supplied the service
|
||||
$oo = Adsl::where('service_username',$row[$o->getColumnKey('Login')])
|
||||
->select(DB::raw('ab_service__adsl.*'))
|
||||
->join('ab_service','ab_service.id','=','service_id')
|
||||
->where('ab_service.date_start','<=',$date->format('U'))
|
||||
->where(function($query) use ($date) {
|
||||
$query->whereNULL('ab_service.date_end')
|
||||
->orWhere('ab_service.date_end','<=',$date->format('U'));
|
||||
})
|
||||
->get();
|
||||
|
||||
$to = new AdslTraffic;
|
||||
$to->site_id = 1; // @todo TO ADDRESS
|
||||
$to->date = $this->aso->stats_lastupdate;
|
||||
$to->supplier_id = $this->aso->id;
|
||||
$to->up_peak = $row[$o->getColumnKey('Peak upload')];
|
||||
$to->up_offpeak = $row[$o->getColumnKey('Off peak upload')];
|
||||
$to->down_peak = $row[$o->getColumnKey('Peak download')];
|
||||
|
@ -117,39 +111,33 @@ final class BroadbandTraffic implements ShouldQueue
|
|||
$to->time = '24:00'; // @todo
|
||||
|
||||
// If we have no records
|
||||
if (! $oo) {
|
||||
Log::error(sprintf('%s:None or too many services return for [%s]',self::LOGKEY,$row[$o->getColumnKey('Login')]),['date'=>$date]);
|
||||
if ($oo->count() != 1) {
|
||||
Log::error(sprintf('%s:Too many services return for [%s]',self::LOGKEY,$row[$o->getColumnKey('Login')]),['m'=>__METHOD__,'date'=>$date,'count'=>$oo->count()]);
|
||||
|
||||
$to->service = $row[$o->getColumnKey('Login')];
|
||||
$to->site_id = 1; // @todo This needs to be worked out a better way
|
||||
$to->save();
|
||||
|
||||
} else {
|
||||
$to->site_id = $oo->site_id;
|
||||
$to->service_item_id = $oo->id;
|
||||
$oo->first()->traffic()->save($to);
|
||||
}
|
||||
|
||||
if ($to->save())
|
||||
$u++;
|
||||
$u++;
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error(sprintf('%s:Exception occurred when storing traffic record for [%s].',self::LOGKEY,$row[$o->getColumnKey('Login')]),['row'=>$row,'line'=>$line]);
|
||||
throw new \Exception('Error while storing traffic data: '.$e->getMessage());
|
||||
Log::error(sprintf('%s:Exception occurred when storing traffic record for [%s].',self::LOGKEY,$row[$o->getColumnKey('Login')]),['m'=>__METHOD__,'row'=>$row,'line'=>$line]);
|
||||
throw new \Exception('Error while storing traffic date');
|
||||
}
|
||||
}
|
||||
Log::info(sprintf('%s: Records Imported [%d] for [%s]',self::LOGKEY,$u,$last_update->format('Y-m-d')));
|
||||
|
||||
// Save our current progress.
|
||||
$this->o->detail->connections = $this->o->detail->connections->put(self::traffic,array_merge($connection,['last'=>$last_update->format('Y-m-d')]));
|
||||
$this->o->detail->save();
|
||||
|
||||
// Update our details for the next iteration.
|
||||
$last_update = $last_update->addDay();
|
||||
Arr::set($connection,'last',$last_update->format('Y-m-d'));
|
||||
Log::info(sprintf('%s: Records Imported [%d] for [%s]',self::LOGKEY,$u,$this->aso->stats_lastupdate->format('Y-m-d')),['m'=>__METHOD__]);
|
||||
|
||||
if ($u) {
|
||||
if ($this->o->trafficMismatch($date)->count())
|
||||
$this->aso->stats_lastupdate = $this->aso->stats_lastupdate->addDay();
|
||||
$this->aso->save();
|
||||
|
||||
if ($this->aso->trafficMismatch($date)->count())
|
||||
Mail::to('deon@graytech.net.au') // @todo To change
|
||||
->send(new TrafficMismatch($this->o,$date));
|
||||
->send(new TrafficMismatch($this->aso,$date));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,232 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldBeUnique;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
use App\Models\{Cost,Service,Site,Supplier};
|
||||
use App\Traits\Import;
|
||||
|
||||
class ImportCosts implements ShouldQueue
|
||||
{
|
||||
use Dispatchable,InteractsWithQueue,Queueable,SerializesModels,Import;
|
||||
|
||||
private const LOGKEY = 'JIC';
|
||||
private Cost $co;
|
||||
private Site $site;
|
||||
private string $file;
|
||||
protected Collection $columns;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Site $site,Supplier $so,Carbon $invoice_date,string $file)
|
||||
{
|
||||
$this->file = $file;
|
||||
$this->site = $site;
|
||||
|
||||
$this->co = Cost::where('site_id',$site->site_id)
|
||||
->where('supplier_id',$so->id)
|
||||
->where('billed_at',$invoice_date)
|
||||
->firstOrNew();
|
||||
$this->co->active = TRUE;
|
||||
$this->co->site_id = $site->site_id;
|
||||
$this->co->billed_at = $invoice_date;
|
||||
$this->co->supplier_id = $so->id;
|
||||
$this->co->save();
|
||||
|
||||
Cost\Broadband::where('cost_id',$this->co->id)->where('site_id',$site->site_id)->delete();
|
||||
Cost\Phone::where('cost_id',$this->co->id)->where('site_id',$site->site_id)->delete();
|
||||
Cost\Generic::where('cost_id',$this->co->id)->where('site_id',$site->site_id)->delete();
|
||||
|
||||
// @todo to be stored in supplier config
|
||||
$headers = [
|
||||
'INVOICEID'=>'Item ID',
|
||||
'REF'=>'Reference No',
|
||||
'IDTAG'=>'ID Tag',
|
||||
'CATEGORY'=>'Category',
|
||||
'DESC'=>'Item Description',
|
||||
'QUANTITY'=>'Quantity',
|
||||
'PRICEUNIT'=>'Unit Price (inc-GST)',
|
||||
'PRICETOTAL'=>'Total (inc-GST)'
|
||||
];
|
||||
|
||||
$this->columns = collect($headers)->transform(function($item) { return strtolower($item); });
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
* @return void
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
Config::set('site',$this->site);
|
||||
$skip = 7; // @todo to be stored in supplier config
|
||||
|
||||
$file = fopen('storage/app/'.$this->file,'r');
|
||||
$haveHeader = FALSE;
|
||||
|
||||
$c = 0;
|
||||
while (! feof($file)) {
|
||||
$line = stream_get_line($file,0,"\r\n");
|
||||
if (str_starts_with($line,'#'))
|
||||
continue;
|
||||
|
||||
// Remove any embedded CR and BOM
|
||||
$line = str_replace("\r",'',$line);
|
||||
$line = preg_replace('/^\x{feff}/u','',$line);
|
||||
if (($c++ < $skip) || (! $line))
|
||||
continue;
|
||||
|
||||
// The first line is a header.
|
||||
if (! $haveHeader) {
|
||||
Log::debug(sprintf('%s: Input File: %s',get_class($this),$this->file));
|
||||
Log::debug(sprintf('%s: Processing columns: %s',get_class($this),join('|',$this->setColumns($line)->toArray())));
|
||||
$haveHeader = TRUE;
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the line has a , between two (), then convert the comma to a space.
|
||||
$x = [];
|
||||
if (preg_match('#\(.+,.+\)#i',$line,$x)) {
|
||||
$replace = str_replace(',','_',$x[0]);
|
||||
$line = str_replace($x[0],$replace,$line);
|
||||
//dd($line,$x);
|
||||
}
|
||||
|
||||
$fields = str_getcsv(trim($line));
|
||||
if (is_null($x=$this->getColumnKey('DESC')) OR empty($fields[$x]))
|
||||
continue;
|
||||
|
||||
// The first part of our item description is the service number.
|
||||
// This should go to a "supplier" function, since all suppliers may show different values in description.
|
||||
$m = [];
|
||||
$desc = $fields[$x];
|
||||
// m[1] = Service, m[2] = Desc, m[3] = From Date, m[4] = To Date
|
||||
preg_match('#^([0-9]{10})\s+-\s+(.*)\(([0-9]+\s+[JFMASOND].*\s+[0-9]+)+\s+-\s+([0-9]+\s+[JFMASOND].*\s+[0-9]+)+\)$#',$fields[$x],$m);
|
||||
|
||||
if (count($m) !== 5) {
|
||||
dump(sprintf('ERROR: Description didnt parse [%s] on line [%d]',$fields[$x],$c));
|
||||
continue;
|
||||
}
|
||||
|
||||
$cost = ($x=$this->getColumnKey('PRICETOTAL')) ? str_replace([',','$'],'',$fields[$x]) : NULL;
|
||||
$start_at = Carbon::createFromFormat('d M Y',$m[3]);
|
||||
$stop_at = Carbon::createFromFormat('d M Y',$m[4]);
|
||||
$so = Service::search($m[1])->active()->with(['type','product.type.supplied'])->single();
|
||||
|
||||
if ($so) {
|
||||
// r[1] = Monthly Charge or Extra Charge,r[2] = "On Plan", r[3] = Plan Info
|
||||
$r = [];
|
||||
switch ($so->category) {
|
||||
case 'broadband':
|
||||
$to = Cost\Broadband::where('site_id',$this->co->site_id)
|
||||
->where('cost_id',$this->co->id)
|
||||
->where('service_broadband_id',$so->type->id)
|
||||
->where('start_at',$start_at)
|
||||
->where('end_at',$stop_at)
|
||||
->firstOrNew();
|
||||
$to->service_broadband_id = $so->type->id;
|
||||
|
||||
preg_match('#^(Monthly Internet Charge|Plan Change Fee|Change billing date refund for Monthly Internet Charge On Plan|First 12 Month VISP broadband plan discount|.*)\s?(On Plan)?\s?(.*)#',$m[2],$r);
|
||||
|
||||
switch ($r[1]) {
|
||||
case 'Monthly Internet Charge':
|
||||
case 'First 12 Month VISP broadband plan discount':
|
||||
case 'Change billing date refund for Monthly Internet Charge On Plan':
|
||||
$to->base =+ $cost;
|
||||
break;
|
||||
|
||||
case 'Plan Change Fee':
|
||||
$to->excess =+ $cost;
|
||||
break;
|
||||
|
||||
default:
|
||||
dump(['extra charge'=>$r]);
|
||||
$to->excess =+ $cost;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'phone':
|
||||
$to = Cost\Phone::where('site_id',$this->co->site_id)
|
||||
->where('cost_id',$this->co->id)
|
||||
->where('service_phone_id',$so->type->id)
|
||||
->where('start_at',$start_at)
|
||||
->where('end_at',$stop_at)
|
||||
->firstOrNew();
|
||||
$to->service_phone_id = $so->type->id;
|
||||
|
||||
preg_match('#^(Residential VOIP Plan Excess Usage|Virtual FAX Number Monthly Rental|Corporate VOIP Plan Monthly Rental|Residential VOIP Plan Monthly Rental|.*)\s?(.*)#',$m[2],$r);
|
||||
|
||||
switch ($r[1]) {
|
||||
case 'Residential VOIP Plan Monthly Rental':
|
||||
case 'Virtual FAX Number Monthly Rental':
|
||||
case 'Corporate VOIP Plan Monthly Rental':
|
||||
$to->base =+ $cost;
|
||||
break;
|
||||
|
||||
case 'Residential VOIP Plan Excess Usage':
|
||||
$to->excess =+ $cost;
|
||||
$to->notes = $r[2];
|
||||
break;
|
||||
|
||||
default:
|
||||
dump(['extra charge'=>$r]);
|
||||
$to->excess =+ $cost;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
dump(['so'=>$so,'category'=>$so->category,'line'=>$line,'m'=>$m,'r'=>$r]);
|
||||
throw new \Exception(sprintf('ERROR: Service type not handled for service [%s] (%s) on line [%d]',$m[1],$so->category,$c));
|
||||
}
|
||||
|
||||
} else {
|
||||
dump(['line'=>$line,'sql'=>Service::search($m[1])->active()->with(['type','product.type.supplied'])->toSql()]);
|
||||
|
||||
$to = Cost\Generic::where('site_id',$this->co->site_id)
|
||||
->where('cost_id',$this->co->id)
|
||||
->where('notes',sprintf('%s:%s',$m[1],$m[2]))
|
||||
->where('start_at',$start_at)
|
||||
->where('end_at',$stop_at)
|
||||
->firstOrNew();
|
||||
|
||||
$to->excess =+ $cost;
|
||||
$to->notes = $line;
|
||||
}
|
||||
|
||||
$to->site_id = $this->co->site_id;
|
||||
$to->cost_id = $this->co->id;
|
||||
$to->active = TRUE;
|
||||
$to->start_at = $start_at;
|
||||
$to->end_at = $stop_at;
|
||||
|
||||
// Work out supplier product number
|
||||
Log::warning(sprintf('%s:Supplier product ID not matched',self::LOGKEY),['r'=>$r]);
|
||||
|
||||
//dd($m[2],$cost,$so->product->type->supplied);
|
||||
|
||||
// Work out if this base charge, or extra charge
|
||||
|
||||
//dd(['M'=>__METHOD__,'fields'=>$fields,'DESC'=>$this->getColumnKey('DESC'),'desc'=>$desc,'m'=>$m,'sql'=>$so->toSql(),'bindings'=>$so->getBindings(),'so'=>$so]);
|
||||
$to->save();
|
||||
}
|
||||
|
||||
fclose($file);
|
||||
}
|
||||
}
|
|
@ -1,104 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
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;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
use App\Classes\External\Payments;
|
||||
use App\Models\{Account,Checkout,Payment};
|
||||
|
||||
/**
|
||||
* Import payments from payment providers
|
||||
*
|
||||
* @package App\Jobs
|
||||
*/
|
||||
final class PaymentsImport implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
private const LOGKEY = 'JPI';
|
||||
|
||||
protected Payments $o; // The payment provider we are updating from
|
||||
private $class_prefix = 'App\Classes\External\Payments\\';
|
||||
|
||||
public function __construct(Payments $o)
|
||||
{
|
||||
$this->o = $o;
|
||||
}
|
||||
|
||||
public function handle()
|
||||
{
|
||||
Log::info(sprintf('%s:Importing Payment Date from [%s]',self::LOGKEY,get_class($this->o)));
|
||||
|
||||
// Get our checkout IDs for this plugin
|
||||
$cos = Checkout::where('plugin',config('services.ezypay.plugin'))->pluck('id');
|
||||
|
||||
foreach ($this->o->getCustomers() as $c) {
|
||||
if ($c->BillingStatus == 'Inactive') {
|
||||
Log::debug(sprintf('%s:Ignoring INACTIVE: [%s] %s %s',self::LOGKEY,$c->EzypayReferenceNumber,$c->Firstname,$c->Surname));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Load Account Details from ReferenceId
|
||||
$ao = Account::where('site_id',(int)substr($c->ReferenceId,0,2))
|
||||
->where('id',(int)substr($c->ReferenceId,2,4))
|
||||
->first();
|
||||
|
||||
if (! $ao) {
|
||||
Log::error(sprintf('%s:Missing: [%s] %s %s (%s)',self::LOGKEY,$c->EzypayReferenceNumber,$c->Firstname,$c->Surname,$c->ReferenceId));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Find the last payment logged
|
||||
$last = Carbon::create(Payment::whereIN('checkout_id',$cos)->where('account_id',$ao->id)->max('paid_at'));
|
||||
|
||||
$o = $this->o->getDebits([
|
||||
'customerId'=>$c->Id,
|
||||
'dateFrom'=>$last->format('Y-m-d'),
|
||||
'dateTo'=>$last->addQuarter()->format('Y-m-d'),
|
||||
'pageSize'=>100,
|
||||
]);
|
||||
|
||||
Log::info(sprintf('%s:Loaded [%d] payments for account: [%s]',self::LOGKEY,$o->count(),$ao->id));
|
||||
|
||||
// Load the payments
|
||||
if ($o->count()) {
|
||||
foreach ($o->reverse() as $p) {
|
||||
$pd = Carbon::createFromTimeString($p->Date);
|
||||
|
||||
// If not success, ignore it.
|
||||
if ($p->Status != 'Success') {
|
||||
Log::alert(sprintf('%s:Payment not successful: [%s] %s %s (%s) [%s]',self::LOGKEY,$pd->format('Y-m-d'),$ao->id,$p->Id,$p->Amount,$p->Status));
|
||||
continue;
|
||||
}
|
||||
|
||||
$lp = $ao->payments->last();
|
||||
|
||||
if ($lp AND (($pd == $lp->paid_at) OR ($p->Id == $lp->checkout_data))) {
|
||||
Log::alert(sprintf('%s:Payment Already Recorded: [%s] %s %s (%s)',self::LOGKEY,$pd->format('Y-m-d'),$ao->id,$p->Id,$p->Amount));
|
||||
continue;
|
||||
}
|
||||
|
||||
// New Payment
|
||||
$po = new Payment;
|
||||
$po->active = TRUE;
|
||||
$po->site_id = 1; // @todo
|
||||
$po->paid_at = $pd;
|
||||
$po->checkout_id = '999'; // @todo
|
||||
$po->checkout_data = $p->Id;
|
||||
$po->total_amt = $p->Amount;
|
||||
$ao->payments()->save($po);
|
||||
|
||||
Log::info(sprintf('%s:Recorded: Payment for [%s] %s %s (%s) on %s',self::LOGKEY,$c->EzypayReferenceNumber,$c->Firstname,$c->Surname,$po->id,$pd));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldBeUnique;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
use App\Models\ProviderToken;
|
||||
|
||||
class ProviderTokenRefresh implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
private ProviderToken $to;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(ProviderToken $to)
|
||||
{
|
||||
$this->to = $to;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$this->to->refreshToken();
|
||||
}
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldBeUnique;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
use App\Models\{Site,Supplier,TLD};
|
||||
|
||||
class SupplierDomainSync implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
private const LOGKEY = 'JSD';
|
||||
|
||||
protected Site $site;
|
||||
protected Supplier $supplier;
|
||||
protected bool $forceprod;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Site $site,Supplier $supplier,bool $forceprod=FALSE)
|
||||
{
|
||||
$this->site = $site;
|
||||
$this->supplier = $supplier;
|
||||
$this->forceprod = $forceprod;
|
||||
|
||||
Config::set('site',$site);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$registrar_id = ($x=$this->supplier->registrar()) ? $x->id : NULL;
|
||||
|
||||
foreach ($this->supplier->API($this->forceprod)->getDomains(['fetchall'=>true]) as $domain) {
|
||||
// @todo See if we can find this domain by its ID
|
||||
|
||||
// Find this domain by it's name
|
||||
if (! $to=TLD::domaintld($domain->domain_name)) {
|
||||
Log::alert(sprintf('%s:Domain [%s] from (%s) is not in a TLD that we manage',self::LOGKEY,$this->supplier->name,$domain->domain_name));
|
||||
|
||||
} elseif (($domainpart=strtolower($to->domain_part($domain->domain_name))) && (($x=$to->domains->where('domain_name',$domainpart))->count() === 1)) {
|
||||
$o = $x->pop();
|
||||
$o->registrar_auth_password = $domain->auth_key;
|
||||
$o->expire_at = Carbon::create($domain->expiry_date);
|
||||
$o->registrar_account = $domain->account;
|
||||
$o->registrar_username = '';
|
||||
$o->registrar_ns = Supplier\Domain::nameserver_name($domain->nameservers());
|
||||
if ($registrar_id)
|
||||
$o->domain_registrar_id = $registrar_id;
|
||||
|
||||
if ($o->getDirty()) {
|
||||
Log::info(sprintf('%s:Updating Domain [%s] from (%s)',self::LOGKEY,$domain->domain_name,$this->supplier->name));
|
||||
$o->save();
|
||||
|
||||
} else {
|
||||
Log::info(sprintf('%s:No Change to Domain [%s] from (%s)',self::LOGKEY,$domain->domain_name,$this->supplier->name));
|
||||
}
|
||||
|
||||
// Alert an unmanaged name.
|
||||
} else {
|
||||
Log::alert(sprintf('%s:Domain [%s] from (%s) is not one managed in OSB',self::LOGKEY,$this->supplier->name,$domain->domain_name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Listeners;
|
||||
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Mail\Events\MessageSent;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class LogSentMessage
|
||||
{
|
||||
private const LOGKEY = 'LSM';
|
||||
|
||||
/**
|
||||
* Handle the event.
|
||||
*
|
||||
* @param MessageSent $event
|
||||
* @return void
|
||||
*/
|
||||
public function handle(MessageSent $event)
|
||||
{
|
||||
Log::debug(
|
||||
sprintf('%s:Email to [%s] with subject [%s] sent [%s]',
|
||||
self::LOGKEY,
|
||||
collect($event->data['message']->getTo())->transform(function($item) { return $item->getAddress(); })->join(','),
|
||||
$event->data['message']->getSubject(),
|
||||
$event->sent->getMessageId(),
|
||||
),
|
||||
['debug'=>$event->sent->getDebug()]);
|
||||
}
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Listeners;
|
||||
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
use App\Events\ProviderPaymentCreated as Event;
|
||||
use App\Jobs\AccountingPaymentSync as Job;
|
||||
use App\Models\{ProviderOauth,Site,User};
|
||||
|
||||
class ProviderPaymentCreated
|
||||
{
|
||||
private const LOGKEY = 'LPC';
|
||||
|
||||
/**
|
||||
* Handle the event.
|
||||
*
|
||||
* @param Event $event
|
||||
* @return void
|
||||
*/
|
||||
public function handle(Event $event)
|
||||
{
|
||||
$site = Site::findOrFail(1); // @todo This shouldnt be hard coded
|
||||
Config::set('site',$site);
|
||||
|
||||
$uo = User::findOrFail(1); // @todo This shouldnt be hard coded
|
||||
|
||||
$so = ProviderOauth::where('name',$event->provider)->singleOrFail();
|
||||
if (! ($to=$so->token($uo)))
|
||||
abort(500,sprintf('Unknown Tokens for [%s]',$uo->email));
|
||||
|
||||
$api = $to->API();
|
||||
$acc = $api->getPayment($event->paymentData['id']);
|
||||
|
||||
Job::dispatch($to,$acc);
|
||||
}
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Mail;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
|
||||
use App\Models\Service;
|
||||
|
||||
class CancelRequest extends Mailable
|
||||
{
|
||||
use Queueable, SerializesModels;
|
||||
|
||||
public Service $service;
|
||||
public string $notes;
|
||||
|
||||
/**
|
||||
* Create a new message instance.
|
||||
*
|
||||
* @param Service $o
|
||||
* @param string $notes
|
||||
*/
|
||||
public function __construct(Service $o,string $notes='')
|
||||
{
|
||||
$this->service = $o;
|
||||
$this->notes = $notes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the message.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function build()
|
||||
{
|
||||
Config::set('site',$this->service->site);
|
||||
|
||||
switch (get_class($this->service->type)) {
|
||||
case Service\Broadband::class:
|
||||
$subject = sprintf('Cancel BROADBAND: %s',$this->service->type->service_address);
|
||||
break;
|
||||
|
||||
case Service\Phone::class:
|
||||
$subject = sprintf('Cancel PHONE: %s',$this->service->type->service_number);
|
||||
break;
|
||||
|
||||
default:
|
||||
$subject = 'Cancel Service Request';
|
||||
}
|
||||
|
||||
return $this
|
||||
->markdown('email.admin.service.cancel')
|
||||
->subject($subject)
|
||||
->with(['site'=>$this->service->site]);
|
||||
}
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Mail;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
|
||||
use App\Models\Service;
|
||||
|
||||
class ChangeRequest extends Mailable
|
||||
{
|
||||
use Queueable, SerializesModels;
|
||||
|
||||
public Service $service;
|
||||
public string $notes;
|
||||
|
||||
/**
|
||||
* Create a new message instance.
|
||||
*
|
||||
* @param Service $o
|
||||
* @param string $notes
|
||||
*/
|
||||
public function __construct(Service $o,string $notes='')
|
||||
{
|
||||
$this->service = $o;
|
||||
$this->notes = $notes ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the message.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function build()
|
||||
{
|
||||
Config::set('site',$this->service->site);
|
||||
|
||||
switch (get_class($this->service->type)) {
|
||||
case Service\Broadband::class:
|
||||
$subject = sprintf('Change BROADBAND: %s',$this->service->type->service_address);
|
||||
break;
|
||||
|
||||
case Service\Phone::class:
|
||||
$subject = sprintf('Change PHONE: %s',$this->service->type->service_number);
|
||||
break;
|
||||
|
||||
default:
|
||||
$subject = 'Change Service Request';
|
||||
}
|
||||
|
||||
return $this
|
||||
->markdown('email.admin.service.change')
|
||||
->subject($subject)
|
||||
->with(['site'=>$this->service->site]);
|
||||
}
|
||||
}
|
|
@ -3,10 +3,9 @@
|
|||
namespace App\Mail;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
|
||||
use App\Models\Invoice;
|
||||
|
||||
|
@ -20,6 +19,7 @@ class InvoiceEmail extends Mailable
|
|||
* Create a new message instance.
|
||||
*
|
||||
* @param Invoice $o
|
||||
* @param string $notes
|
||||
*/
|
||||
public function __construct(Invoice $o)
|
||||
{
|
||||
|
@ -33,14 +33,12 @@ class InvoiceEmail extends Mailable
|
|||
*/
|
||||
public function build()
|
||||
{
|
||||
Config::set('site',$this->invoice->site);
|
||||
|
||||
return $this
|
||||
->markdown('email.user.invoice')
|
||||
->subject(sprintf( 'Invoice: %s - Total: $%s - Due: %s',
|
||||
$this->invoice->id,
|
||||
number_format($this->invoice->total,2),
|
||||
$this->invoice->due_at->format('Y-m-d')))
|
||||
$this->invoice->date_due))
|
||||
->with([
|
||||
'user'=>$this->invoice->account->user,
|
||||
'site'=>$this->invoice->account->user->site,
|
||||
|
|
|
@ -3,10 +3,9 @@
|
|||
namespace App\Mail;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
|
||||
use App\Models\Service;
|
||||
|
||||
|
@ -14,8 +13,8 @@ class OrderRequest extends Mailable
|
|||
{
|
||||
use Queueable, SerializesModels;
|
||||
|
||||
public Service $service;
|
||||
public string $notes;
|
||||
public $service;
|
||||
public $notes;
|
||||
|
||||
/**
|
||||
* Create a new message instance.
|
||||
|
@ -23,7 +22,7 @@ class OrderRequest extends Mailable
|
|||
* @param Service $o
|
||||
* @param string $notes
|
||||
*/
|
||||
public function __construct(Service $o,string $notes='')
|
||||
public function __construct(Service $o,$notes='')
|
||||
{
|
||||
$this->service = $o;
|
||||
$this->notes = $notes;
|
||||
|
@ -36,15 +35,14 @@ class OrderRequest extends Mailable
|
|||
*/
|
||||
public function build()
|
||||
{
|
||||
Config::set('site',$this->service->site);
|
||||
|
||||
switch (get_class($this->service->type)) {
|
||||
case Service\Broadband::class:
|
||||
$subject = sprintf('Order BROADBAND: %s',$this->service->type->service_address);
|
||||
switch (get_class($this->service->type))
|
||||
{
|
||||
case 'App\Models\Service\Adsl':
|
||||
$subject = sprintf('NBN: %s',$this->service->type->service_address);
|
||||
break;
|
||||
|
||||
case Service\Phone::class:
|
||||
$subject = sprintf('Order PHONE: %s',$this->service->type->service_number);
|
||||
case 'App\Models\Service\Voip':
|
||||
$subject = sprintf('VOIP: %s',$this->service->type->service_number);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
@ -6,7 +6,6 @@ use Illuminate\Bus\Queueable;
|
|||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
|
||||
use App\Models\Service;
|
||||
|
||||
|
@ -14,8 +13,8 @@ class OrderRequestApprove extends Mailable
|
|||
{
|
||||
use Queueable, SerializesModels;
|
||||
|
||||
public Service $service;
|
||||
public string $notes;
|
||||
public $service;
|
||||
public $notes;
|
||||
|
||||
/**
|
||||
* Create a new message instance.
|
||||
|
@ -23,7 +22,7 @@ class OrderRequestApprove extends Mailable
|
|||
* @param Service $o
|
||||
* @param string $notes
|
||||
*/
|
||||
public function __construct(Service $o,string $notes='')
|
||||
public function __construct(Service $o,$notes='')
|
||||
{
|
||||
$this->service = $o;
|
||||
$this->notes = $notes;
|
||||
|
@ -36,14 +35,12 @@ class OrderRequestApprove extends Mailable
|
|||
*/
|
||||
public function build()
|
||||
{
|
||||
Config::set('site',$this->service->site);
|
||||
|
||||
// @todo This is not consistent with Cancel/Change Request
|
||||
switch ($this->service->category) {
|
||||
case 'broadband': $subject = sprintf('%s: %s',$this->service->category,$this->service->type->service_address);
|
||||
switch ($this->service->category)
|
||||
{
|
||||
case 'ADSL': $subject = sprintf('%s: %s',$this->service->category,$this->service->service_adsl->service_address);
|
||||
break;
|
||||
|
||||
case 'phone': $subject = sprintf('%s: %s',$this->service->category,$this->service->type->service_number);
|
||||
case 'VOIP': $subject = sprintf('%s: %s',$this->service->category,$this->service->service_voip->service_number);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
@ -6,7 +6,6 @@ use Illuminate\Bus\Queueable;
|
|||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
|
||||
use App\Models\Service;
|
||||
|
||||
|
@ -14,15 +13,15 @@ class OrderRequestReject extends Mailable
|
|||
{
|
||||
use Queueable, SerializesModels;
|
||||
|
||||
public Service $service;
|
||||
public string $reason;
|
||||
public $service;
|
||||
public $reason;
|
||||
|
||||
/**
|
||||
* Create a new message instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Service $o,string $reason)
|
||||
public function __construct(Service $o,$reason)
|
||||
{
|
||||
$this->service = $o;
|
||||
$this->reason = $reason;
|
||||
|
@ -35,8 +34,6 @@ class OrderRequestReject extends Mailable
|
|||
*/
|
||||
public function build()
|
||||
{
|
||||
Config::set('site',$this->service->site);
|
||||
|
||||
return $this
|
||||
->markdown('email.admin.order.reject')
|
||||
->subject(sprintf('Your order: #%s was rejected',$this->service->id))
|
||||
|
|
|
@ -5,28 +5,26 @@ namespace App\Mail;
|
|||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
|
||||
use App\Models\{Site,User,UserOauth};
|
||||
use App\Models\{AccountOauth,User};
|
||||
|
||||
class SocialLink extends Mailable
|
||||
{
|
||||
use Queueable, SerializesModels;
|
||||
|
||||
public string $token;
|
||||
public Site $site;
|
||||
public ?User $user;
|
||||
public $token;
|
||||
public $user;
|
||||
|
||||
/**
|
||||
* Create a new message instance.
|
||||
*
|
||||
* @param UserOauth $o
|
||||
* @param User $o
|
||||
* @param string $token
|
||||
*/
|
||||
public function __construct(UserOauth $o)
|
||||
public function __construct(AccountOauth $o)
|
||||
{
|
||||
$this->site = $o->site;
|
||||
$this->token = $o->link_token;
|
||||
$this->user = $o->user;
|
||||
$this->user = $o->account->user;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -36,13 +34,11 @@ class SocialLink extends Mailable
|
|||
*/
|
||||
public function build()
|
||||
{
|
||||
Config::set('site',$this->site);
|
||||
|
||||
return $this
|
||||
->markdown('email.system.social_link')
|
||||
->subject('Link your Account')
|
||||
->with([
|
||||
'site'=>$this->site,
|
||||
]);
|
||||
'site'=>$this->user->site,
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -6,41 +6,36 @@ use Illuminate\Bus\Queueable;
|
|||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
|
||||
use App\Models\User;
|
||||
|
||||
class TestEmail extends Mailable
|
||||
{
|
||||
use Queueable, SerializesModels;
|
||||
use Queueable, SerializesModels;
|
||||
|
||||
public User $user;
|
||||
/**
|
||||
* Create a new message instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(User $o)
|
||||
{
|
||||
$this->user = $o;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new message instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(User $o)
|
||||
{
|
||||
$this->user = $o;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the message.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function build()
|
||||
{
|
||||
Config::set('site',$this->user->site);
|
||||
|
||||
return $this
|
||||
->markdown('email.system.test_email')
|
||||
->subject('Just a test...')
|
||||
->with([
|
||||
'site'=>$this->user->site,
|
||||
'user'=>$this->user,
|
||||
]);
|
||||
}
|
||||
/**
|
||||
* Build the message.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function build()
|
||||
{
|
||||
return $this
|
||||
->markdown('email.system.test_email')
|
||||
->subject('Just a test...')
|
||||
->with([
|
||||
'site'=>$this->user->site,
|
||||
'user'=>$this->user,
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -2,28 +2,25 @@
|
|||
|
||||
namespace App\Mail;
|
||||
|
||||
use App\Models\Site;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
|
||||
use App\Models\{Supplier,Site};
|
||||
use App\Models\AdslSupplier;
|
||||
|
||||
class TrafficMismatch extends Mailable
|
||||
{
|
||||
use Queueable, SerializesModels;
|
||||
|
||||
public Supplier $aso;
|
||||
public Carbon $date;
|
||||
|
||||
/**
|
||||
* Create a new message instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Supplier $o,Carbon $date)
|
||||
public function __construct(AdslSupplier $o,Carbon $date)
|
||||
{
|
||||
$this->aso = $o;
|
||||
$this->date = $date;
|
||||
|
@ -36,13 +33,11 @@ class TrafficMismatch extends Mailable
|
|||
*/
|
||||
public function build()
|
||||
{
|
||||
Config::set('site',$x=Site::find(1)); // @todo To auto determine;
|
||||
|
||||
return $this
|
||||
->markdown('email.system.broadband_traffic_mismatch')
|
||||
->subject('Traffic Mismatch for '.$this->date)
|
||||
->with([
|
||||
'site'=>$x,
|
||||
'site'=>Site::find(1), // @todo To auto determine
|
||||
'date'=>$this->date,
|
||||
'aso'=>$this->aso,
|
||||
]);
|
||||
|
|
|
@ -2,50 +2,52 @@
|
|||
|
||||
namespace App\Models;
|
||||
|
||||
use Awobaz\Compoships\Compoships;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Leenooks\Traits\ScopeActive;
|
||||
|
||||
use App\Models\Scopes\SiteScope;
|
||||
use App\Interfaces\IDs;
|
||||
use App\Traits\SiteID;
|
||||
use App\Traits\NextKey;
|
||||
|
||||
/**
|
||||
* Class Account
|
||||
* Service Accounts
|
||||
*
|
||||
* Attributes for accounts:
|
||||
* + lid : Local ID for account
|
||||
* + sid : System ID for account
|
||||
* + name : Account Name
|
||||
* + taxes : Taxes Applicable to this account
|
||||
* + lid: : Local ID for account
|
||||
* + sid: : System ID for account
|
||||
*
|
||||
* @package App\Models
|
||||
*/
|
||||
class Account extends Model implements IDs
|
||||
{
|
||||
use Compoships,HasFactory,ScopeActive,SiteID;
|
||||
use HasFactory,NextKey,ScopeActive;
|
||||
|
||||
/* INTERFACES */
|
||||
const RECORD_ID = 'account';
|
||||
public $incrementing = FALSE;
|
||||
|
||||
public function getLIDAttribute(): string
|
||||
{
|
||||
return sprintf('%04s',$this->id);
|
||||
}
|
||||
const CREATED_AT = 'date_orig';
|
||||
const UPDATED_AT = 'date_last';
|
||||
|
||||
public function getSIDAttribute(): string
|
||||
{
|
||||
return sprintf('%02s-%s',$this->site_id,$this->getLIDAttribute());
|
||||
}
|
||||
protected $appends = [
|
||||
'active_display',
|
||||
'name',
|
||||
'services_count_html',
|
||||
'switch_url',
|
||||
];
|
||||
|
||||
public $dateFormat = 'U';
|
||||
|
||||
protected $visible = [
|
||||
'id',
|
||||
'active_display',
|
||||
'name',
|
||||
'services_count_html',
|
||||
'switch_url',
|
||||
];
|
||||
|
||||
/* RELATIONS */
|
||||
|
||||
public function charges()
|
||||
{
|
||||
return $this->hasMany(Charge::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the country the user belongs to
|
||||
*/
|
||||
|
@ -59,20 +61,9 @@ class Account extends Model implements IDs
|
|||
return $this->belongsToMany(External\Integrations::class,'external_account',NULL,'external_integration_id');
|
||||
}
|
||||
|
||||
public function group()
|
||||
{
|
||||
return $this->hasOneThrough(Group::class,AccountGroup::class,'account_id','id','id','group_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
* @todo This needs to be optimised, to only return outstanding invoices and invoices for a specific age (eg: 2 years worth)
|
||||
*/
|
||||
public function invoices()
|
||||
{
|
||||
return $this->hasMany(Invoice::class)
|
||||
->active()
|
||||
->with(['items.taxes','paymentitems.payment']);
|
||||
return $this->hasMany(Invoice::class);
|
||||
}
|
||||
|
||||
public function language()
|
||||
|
@ -82,37 +73,16 @@ class Account extends Model implements IDs
|
|||
|
||||
public function payments()
|
||||
{
|
||||
return $this->hasMany(Payment::class)
|
||||
->active()
|
||||
->with(['items']);
|
||||
}
|
||||
|
||||
public function providers()
|
||||
{
|
||||
return $this->belongsToMany(ProviderOauth::class,'account__provider')
|
||||
->where('account__provider.site_id',$this->site_id)
|
||||
->withPivot('ref','synctoken','created_at','updated_at');
|
||||
return $this->hasMany(Payment::class);
|
||||
}
|
||||
|
||||
public function services($active=FALSE)
|
||||
{
|
||||
$query = $this->hasMany(Service::class,['account_id','site_id'],['id','site_id'])
|
||||
->withoutGlobalScope(SiteScope::class)
|
||||
->with(['product.translate','invoice_items']);
|
||||
$query = $this->hasMany(Service::class);
|
||||
|
||||
return $active ? $query->active() : $query;
|
||||
}
|
||||
|
||||
public function site()
|
||||
{
|
||||
return $this->belongsTo(Site::class);
|
||||
}
|
||||
|
||||
public function taxes()
|
||||
{
|
||||
return $this->hasMany(Tax::class,'country_id','country_id');
|
||||
}
|
||||
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
|
@ -125,7 +95,7 @@ class Account extends Model implements IDs
|
|||
*
|
||||
* @param $query
|
||||
* @param string $term
|
||||
* @return mixed
|
||||
* @return
|
||||
*/
|
||||
public function scopeSearch($query,string $term)
|
||||
{
|
||||
|
@ -145,6 +115,27 @@ class Account extends Model implements IDs
|
|||
|
||||
/* ATTRIBUTES */
|
||||
|
||||
public function getActiveDisplayAttribute($value)
|
||||
{
|
||||
return sprintf('<span class="btn-sm btn-block btn-%s text-center">%s</span>',$this->active ? 'success' : 'danger',$this->active ? 'Active' : 'Inactive');
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use getAIDAttribute()
|
||||
*/
|
||||
public function getAccountIdAttribute()
|
||||
{
|
||||
return $this->getAIDAttribute();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use getUrlAdminAttribute()
|
||||
*/
|
||||
public function getAccountIdUrlAttribute()
|
||||
{
|
||||
return $this->getUrlAdminAttribute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the address for the account
|
||||
*
|
||||
|
@ -160,36 +151,76 @@ class Account extends Model implements IDs
|
|||
}
|
||||
|
||||
/**
|
||||
* Account breadcrumb to render on pages
|
||||
*
|
||||
* @return array
|
||||
* Return the Account Unique Identifier
|
||||
* @return string
|
||||
* @deprecated use getSIDAttribute()
|
||||
*/
|
||||
public function getBreadcrumbAttribute(): array
|
||||
public function getAIDAttribute()
|
||||
{
|
||||
return [$this->name => url('u/home',$this->user_id)];
|
||||
return $this->getSIDAttribute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the account name
|
||||
*
|
||||
* @return mixed|string
|
||||
*/
|
||||
public function getNameAttribute(): string
|
||||
{
|
||||
return $this->company ?: ($this->user_id ? $this->user->getSurFirstNameAttribute() : 'LID:'.$this->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type of account this is - if it has a company name, then its a business account.
|
||||
* Account Local ID
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getLIDAttribute(): string
|
||||
{
|
||||
return sprintf('%04s',$this->id);
|
||||
}
|
||||
|
||||
public function getNameAttribute()
|
||||
{
|
||||
return $this->company ?: ($this->user_id ? $this->user->SurFirstName : 'AID:'.$this->id);
|
||||
}
|
||||
|
||||
public function getServicesCountHtmlAttribute()
|
||||
{
|
||||
return sprintf('%s <small>/%s</small>',$this->services()->noEagerLoads()->where('active',TRUE)->count(),$this->services()->noEagerLoads()->count());
|
||||
}
|
||||
|
||||
/**
|
||||
* Account System ID
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getSIDAttribute(): string
|
||||
{
|
||||
return sprintf('%02s-%s',$this->site_id,$this->getLIDAttribute());
|
||||
}
|
||||
|
||||
public function getSwitchUrlAttribute()
|
||||
{
|
||||
return sprintf('<a href="/r/switch/start/%s"><i class="fas fa-external-link-alt"></i></a>',$this->user_id);
|
||||
}
|
||||
|
||||
public function getTypeAttribute()
|
||||
{
|
||||
return $this->company ? 'Business' : 'Private';
|
||||
}
|
||||
|
||||
/* METHODS */
|
||||
/**
|
||||
* Return the Admin URL to manage the account
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUrlAdminAttribute(): string
|
||||
{
|
||||
return sprintf('<a href="/r/account/view/%s">%s</a>',$this->id,$this->account_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the User URL to manage the account
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUrlUserAttribute(): string
|
||||
{
|
||||
return sprintf('<a href="/u/account/view/%s">%s</a>',$this->id,$this->account_id);
|
||||
}
|
||||
|
||||
/* GENERAL METHODS */
|
||||
|
||||
/**
|
||||
* Get the due invoices on an account
|
||||
|
@ -204,13 +235,17 @@ class Account extends Model implements IDs
|
|||
}
|
||||
|
||||
/**
|
||||
* Return the taxed value of a value
|
||||
* Get the external account ID for a specific integration
|
||||
*
|
||||
* @param float $value
|
||||
* @return float
|
||||
* @param External\Integrations $o
|
||||
* @return mixed
|
||||
*/
|
||||
public function taxed(float $value): float
|
||||
public function ExternalAccounting(External\Integrations $o)
|
||||
{
|
||||
return Tax::calc($value,$this->taxes);
|
||||
return $this
|
||||
->external()
|
||||
->where('id','=',$o->id)
|
||||
->where('site_id','=',$this->site_id)
|
||||
->first();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
use App\Traits\NextKey;
|
||||
|
||||
class AccountOauth extends Model
|
||||
{
|
||||
use NextKey;
|
||||
const RECORD_ID = 'account_oauth';
|
||||
public $incrementing = FALSE;
|
||||
|
||||
protected $table = 'ab_account_oauth';
|
||||
const CREATED_AT = 'date_orig';
|
||||
const UPDATED_AT = 'date_last';
|
||||
public $dateFormat = 'U';
|
||||
|
||||
protected $casts = [
|
||||
'oauth_data'=>'array',
|
||||
];
|
||||
|
||||
public function account()
|
||||
{
|
||||
return $this->belongsTo(Account::class);
|
||||
}
|
||||
|
||||
public function site()
|
||||
{
|
||||
return $this->belongsTo(Site::class);
|
||||
}
|
||||
|
||||
public function User()
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a link token to use when validating account.
|
||||
*/
|
||||
public function getLinkTokenAttribute()
|
||||
{
|
||||
return strtoupper(substr(md5($this->id.$this->date_last),0,8));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
use App\Traits\OrderServiceOptions;
|
||||
|
||||
class AdslPlan extends Model
|
||||
{
|
||||
use OrderServiceOptions;
|
||||
|
||||
protected $table = 'ab_adsl_plan';
|
||||
|
||||
protected $order_attributes = [
|
||||
'options.address'=>[
|
||||
'request'=>'options.address',
|
||||
'key'=>'service_address',
|
||||
'validation'=>'required|string:10',
|
||||
'validation_message'=>'Address is a required field.',
|
||||
],
|
||||
'options.notes'=>[
|
||||
'request'=>'options.notes',
|
||||
'key'=>'order_info.notes',
|
||||
'validation'=>'present',
|
||||
'validation_message'=>'Special Instructions here.',
|
||||
],
|
||||
];
|
||||
|
||||
protected $order_model = Service\Adsl::class;
|
||||
|
||||
public function product()
|
||||
{
|
||||
return $this->hasOne(AdslSupplierPlan::class,'id','adsl_supplier_plan_id');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Models\Service\AdslTraffic;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class AdslSupplier extends Model
|
||||
{
|
||||
protected $table = 'ab_adsl_supplier';
|
||||
|
||||
protected $dates = [
|
||||
'stats_lastupdate',
|
||||
];
|
||||
|
||||
public $timestamps = FALSE;
|
||||
|
||||
/** SCOPES */
|
||||
|
||||
/**
|
||||
* Only query active categories
|
||||
*/
|
||||
public function scopeActive($query)
|
||||
{
|
||||
return $query->where('active',TRUE);
|
||||
}
|
||||
|
||||
/** METHODS **/
|
||||
|
||||
/**
|
||||
* Return the traffic records, that were not matched to a service.
|
||||
*
|
||||
* @param Carbon $date
|
||||
* @return Collection
|
||||
*/
|
||||
public function trafficMismatch(Carbon $date): Collection
|
||||
{
|
||||
return AdslTraffic::where('date',$date->format('Y-m-d'))
|
||||
->where('supplier_id',$this->id)
|
||||
->whereNULL('ab_service_adsl_id')
|
||||
->get();
|
||||
}
|
||||
}
|
|
@ -1,43 +1,14 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models\Supplier;
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
use App\Models\Product\Broadband as ProductBroadband;
|
||||
|
||||
class Broadband extends Type
|
||||
class AdslSupplierPlan extends Model
|
||||
{
|
||||
protected const category_name = 'Broadband';
|
||||
|
||||
protected $table = 'supplier_broadband';
|
||||
|
||||
// The model of the product that is supplied by this model
|
||||
const ProductModel = ProductBroadband::class;
|
||||
|
||||
protected $casts = [
|
||||
'offpeak_start' => 'datetime:H:i',
|
||||
'offpeak_end' => 'datetime:H:i',
|
||||
];
|
||||
|
||||
// Map the table fields, with the extra fields
|
||||
public const traffic_map = [
|
||||
'base_up_offpeak' => 'extra_up_offpeak',
|
||||
'base_down_offpeak' => 'extra_down_offpeak',
|
||||
'base_up_peak' => 'extra_up_peak',
|
||||
'base_down_peak' => 'extra_down_peak',
|
||||
];
|
||||
|
||||
// Map the NULL relationships - and where traffic gets applied if NULL
|
||||
public const traffic_merge = [
|
||||
'extra_up_offpeak' => 'base_down_offpeak',
|
||||
'extra_down_offpeak' => 'base_down_peak',
|
||||
'extra_up_peak' => 'base_down_peak',
|
||||
'extra_down_peak' => 'base_down_peak',
|
||||
];
|
||||
|
||||
/* METHODS */
|
||||
protected $table = 'ab_adsl_supplier_plan';
|
||||
|
||||
/**
|
||||
* Determine how traffic is counted for Broadband links.
|
||||
|
@ -46,7 +17,7 @@ class Broadband extends Type
|
|||
* + down_peak, when not NULL, traffic is included to value of this metric, extra traffic is charged per extra_peak
|
||||
* + down_offpeak, when not NULL, traffic is included to the value of metric, extra traffic is charged per extra_offpeak
|
||||
*
|
||||
* If:
|
||||
* If:
|
||||
* + UPLOADS are charged and there are no PEAK/OFFPEAK periods (therefore all
|
||||
* traffic is charged), the allowance will be shown as 1 metric - TRAFFIC.
|
||||
* + UPLOADS are charged and there are PEAK/OFFPEAK periods the allowance
|
||||
|
@ -68,15 +39,29 @@ class Broadband extends Type
|
|||
* + If extra_up_peak is NULL add traffic_up_peak to traffic_down_peak
|
||||
* + If extra_up_offpeak is NULL add traffic_up_offpeak to traffic_down_offpeak
|
||||
*
|
||||
* @param Collection|null $config The configuration of the link, if NULL assume the supplieres configuration
|
||||
* @param array $data The traffic used on this link, determine whats left or over
|
||||
* @param bool $ceil Round the numbers to integers
|
||||
* @param array $config The configuration of the link, if NULL assume the supplieres configuration
|
||||
* @param array $data The traffic used on this link, determine whats left or over
|
||||
* @param bool $format @deprecate
|
||||
* @param bool $over @deprecate
|
||||
* @param bool $ceil Round the numbers to integers
|
||||
* @return array|string
|
||||
*/
|
||||
public function allowance(Collection $config=NULL,array $data=[],bool $ceil=TRUE)
|
||||
{
|
||||
$map = collect(self::traffic_map);
|
||||
$merge = collect(self::traffic_merge);
|
||||
public function allowance(Collection $config=NULL,array $data=[],$ceil=TRUE) {
|
||||
// Map the table fields, with the extra fields
|
||||
$map = collect([
|
||||
'base_up_offpeak'=>'extra_up_offpeak',
|
||||
'base_down_offpeak'=>'extra_down_offpeak',
|
||||
'base_up_peak'=>'extra_up_peak',
|
||||
'base_down_peak'=>'extra_down_peak',
|
||||
]);
|
||||
|
||||
// Map the NULL relationships - and where traffic gets applied if NULL
|
||||
$merge = collect([
|
||||
'extra_up_offpeak'=>'base_down_offpeak',
|
||||
'extra_down_offpeak'=>'base_down_peak',
|
||||
'extra_up_peak'=>'base_down_peak',
|
||||
'extra_down_peak'=>'base_down_peak',
|
||||
]);
|
||||
|
||||
if (is_null($config))
|
||||
$config = collect($config);
|
||||
|
@ -84,12 +69,14 @@ class Broadband extends Type
|
|||
// If config is null, use the configuration from this Model
|
||||
if (! $config->count()) {
|
||||
// Base Config
|
||||
foreach ($map->keys() as $k)
|
||||
foreach ($map->keys() as $k) {
|
||||
$config->put($k,$this->{$k});
|
||||
}
|
||||
|
||||
// Excess Config
|
||||
foreach ($map->values() as $k)
|
||||
foreach ($map->values() as $k) {
|
||||
$config->put($k,$this->{$k});
|
||||
}
|
||||
|
||||
// Shaped or Charge
|
||||
$config->put('shaped',$this->extra_shaped);
|
||||
|
@ -102,7 +89,7 @@ class Broadband extends Type
|
|||
$result = collect();
|
||||
|
||||
// If data is empty, we'll report on allowance, otherwise we'll report on consumption
|
||||
$report = ! $data;
|
||||
$report = $data ? FALSE : TRUE;
|
||||
|
||||
// Work out if we charge each period
|
||||
foreach ($map as $k => $v) {
|
||||
|
@ -148,4 +135,9 @@ class Broadband extends Type
|
|||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getNameAttribute()
|
||||
{
|
||||
return $this->speed;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models\Base;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
use App\Models\Product;
|
||||
|
||||
//@todo column prod_plugin_file should no longer be required
|
||||
abstract class ProductType extends Model
|
||||
{
|
||||
public $timestamps = FALSE;
|
||||
public $dateFormat = 'U';
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models\Base;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
use App\Models\Service;
|
||||
|
||||
abstract class ServiceType extends Model
|
||||
{
|
||||
public $timestamps = FALSE;
|
||||
public $dateFormat = 'U';
|
||||
|
||||
/**
|
||||
* @NOTE: The service_id column could be discarded, if the id column=service_id
|
||||
* @return \Illuminate\Database\Eloquent\Relations\MorphOne
|
||||
*/
|
||||
public function service()
|
||||
{
|
||||
return $this->morphOne(Service::class,'type','model','id','service_id');
|
||||
}
|
||||
|
||||
/** SCOPES */
|
||||
|
||||
/**
|
||||
* Search for a record
|
||||
*
|
||||
* @param $query
|
||||
* @param string $term
|
||||
* @return
|
||||
*/
|
||||
public function scopeSearch($query,string $term)
|
||||
{
|
||||
return $query
|
||||
->with(['service'])
|
||||
->join('ab_service','ab_service.id','=',$this->getTable().'.service_id')
|
||||
->Where('ab_service.id','like','%'.$term.'%');
|
||||
}
|
||||
|
||||
/** ATTRIBUTES **/
|
||||
|
||||
public function getTypeAttribute()
|
||||
{
|
||||
return strtolower((new \ReflectionClass($this))->getShortName());
|
||||
}
|
||||
}
|
|
@ -2,83 +2,16 @@
|
|||
|
||||
namespace App\Models;
|
||||
|
||||
use Awobaz\Compoships\Compoships;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
use App\Traits\SiteID;
|
||||
|
||||
/**
|
||||
* CLEANUP NOTES:
|
||||
* + Charge Date should not be null
|
||||
* + Attributes should be a collection array
|
||||
* + type should not be null
|
||||
* + It would be useful, given an array of Charges to call a function that renders them into invoice format. This may provide consistence and be the single view of how charges do look on an invoice.
|
||||
*/
|
||||
class Charge extends Model
|
||||
{
|
||||
use Compoships,SiteID;
|
||||
|
||||
protected $casts = [
|
||||
'attributes' => 'json',
|
||||
];
|
||||
|
||||
protected $dates = [
|
||||
'start_at',
|
||||
'stop_at',
|
||||
'charge_at', // The date the charge applies - since it can be different to created_at
|
||||
];
|
||||
|
||||
public const sweep = [
|
||||
// 0 => 'Daily',
|
||||
// 1 => 'Weekly',
|
||||
// 2 => 'Monthly',
|
||||
// 3 => 'Quarterly',
|
||||
// 4 => 'Semi-Annually',
|
||||
// 5 => 'Annually',
|
||||
6 => 'Service Rebill',
|
||||
];
|
||||
|
||||
/* RELATIONS */
|
||||
|
||||
public function account()
|
||||
{
|
||||
return $this->belongsTo(Account::class);
|
||||
}
|
||||
|
||||
public function product()
|
||||
{
|
||||
return $this->belongsTo(Product::class);
|
||||
}
|
||||
|
||||
public function service()
|
||||
{
|
||||
return $this->belongsTo(Service::class);
|
||||
}
|
||||
|
||||
/* SCOPES */
|
||||
|
||||
public function scopeUnprocessed($query)
|
||||
{
|
||||
return $query
|
||||
->where('active',TRUE)
|
||||
->whereNotNull('charge_at')
|
||||
->whereNotNull('type')
|
||||
->where(function($q) {
|
||||
return $q->where('processed',FALSE)
|
||||
->orWhereNull('processed');
|
||||
});
|
||||
}
|
||||
|
||||
/* ATTRIBUTES */
|
||||
protected $table = 'ab_charge';
|
||||
protected $dates = ['date_charge'];
|
||||
public $dateFormat = 'U';
|
||||
|
||||
public function getNameAttribute()
|
||||
{
|
||||
return sprintf('%s %s',$this->description,$this->getAttribute('attributes') ? join('|',unserialize($this->getAttribute('attributes'))) : '');
|
||||
}
|
||||
|
||||
public function getTypeNameAttribute(): string
|
||||
{
|
||||
return Arr::get(InvoiceItem::type,$this->type);
|
||||
return sprintf('%s %s',$this->description,join('|',unserialize($this->getAttribute('attributes'))));
|
||||
}
|
||||
}
|
|
@ -2,43 +2,33 @@
|
|||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Leenooks\Traits\ScopeActive;
|
||||
|
||||
class Checkout extends Model
|
||||
{
|
||||
use ScopeActive;
|
||||
|
||||
protected $casts = [
|
||||
'plugin_data'=>'json',
|
||||
];
|
||||
|
||||
/* RELATIONS */
|
||||
protected $table = 'ab_checkout';
|
||||
public $timestamps = FALSE;
|
||||
|
||||
public function payments()
|
||||
{
|
||||
return $this->hasMany(Payment::class);
|
||||
}
|
||||
|
||||
/* STATIC METHODS */
|
||||
/** SCOPES **/
|
||||
|
||||
public static function available(): Collection
|
||||
/**
|
||||
* Search for a record
|
||||
*
|
||||
* @param $query
|
||||
* @param string $term
|
||||
* @return
|
||||
*/
|
||||
public function scopeActive($query)
|
||||
{
|
||||
return self::active()->get();
|
||||
return $query->where('active',TRUE);
|
||||
}
|
||||
|
||||
/* ATTRIBUTES */
|
||||
|
||||
public function getIconAttribute(): string
|
||||
{
|
||||
switch(strtolower($this->name)) {
|
||||
case 'paypal': return 'fab fa-cc-paypal';
|
||||
default: return 'fas fa-money-bill-alt';
|
||||
}
|
||||
}
|
||||
|
||||
/* METHODS */
|
||||
/** FUNCTIONS **/
|
||||
|
||||
public function fee(float $amt,int $items=1): float
|
||||
{
|
||||
|
|
|
@ -1,66 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
use App\Models\Cost\{Broadband,Generic,Phone};
|
||||
|
||||
class Cost extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $dates = [
|
||||
'billed_at',
|
||||
];
|
||||
|
||||
protected $with = [
|
||||
'broadbands',
|
||||
'generics',
|
||||
'phones',
|
||||
];
|
||||
|
||||
/* RELATIONS */
|
||||
|
||||
public function broadbands()
|
||||
{
|
||||
return $this->hasMany(Broadband::class)
|
||||
->where('active',TRUE);
|
||||
}
|
||||
|
||||
public function generics()
|
||||
{
|
||||
return $this->hasMany(Generic::class)
|
||||
->where('active',TRUE);
|
||||
}
|
||||
|
||||
public function phones()
|
||||
{
|
||||
return $this->hasMany(Phone::class)
|
||||
->where('active',TRUE);
|
||||
}
|
||||
|
||||
/* ATTRIBUTES */
|
||||
|
||||
public function getTotalBroadbandAttribute(): float
|
||||
{
|
||||
return $this->broadbands->sum('base')+$this->broadbands->sum('excess');
|
||||
}
|
||||
|
||||
public function getTotalGenericAttribute(): float
|
||||
{
|
||||
return $this->generics->sum('base')+$this->generics->sum('excess');
|
||||
}
|
||||
|
||||
public function getTotalPhoneAttribute(): float
|
||||
{
|
||||
return $this->phones->sum('base')+$this->phones->sum('excess');
|
||||
}
|
||||
|
||||
public function getTotalAttribute(): float
|
||||
{
|
||||
|
||||
return $this->getTotalBroadbandAttribute()+$this->getTotalGenericAttribute()+$this->getTotalPhoneAttribute();
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models\Cost;
|
||||
|
||||
use App\Models\Service;
|
||||
use App\Models\Service\Broadband as BroadbandService;
|
||||
|
||||
class Broadband extends Type
|
||||
{
|
||||
protected $table = 'cost_broadband';
|
||||
|
||||
/* RELATIONS */
|
||||
|
||||
public function service()
|
||||
{
|
||||
return $this->hasOneThrough(Service::class,BroadbandService::class,'id','id','service_broadband_id','service_id');
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models\Cost;
|
||||
|
||||
use App\Models\Service;
|
||||
use App\Models\Service\Generic as GenericService;
|
||||
|
||||
class Generic extends Type
|
||||
{
|
||||
protected $table = 'cost_generic';
|
||||
|
||||
/* RELATIONS */
|
||||
|
||||
public function service()
|
||||
{
|
||||
return $this->hasOneThrough(Service::class,GenericService::class,'id','id','service_generic_id','service_id');
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models\Cost;
|
||||
|
||||
use App\Models\Service;
|
||||
use App\Models\Service\Phone as PhoneService;
|
||||
|
||||
class Phone extends Type
|
||||
{
|
||||
protected $table = 'cost_phone';
|
||||
|
||||
/* RELATIONS */
|
||||
|
||||
public function service()
|
||||
{
|
||||
return $this->hasOneThrough(Service::class,PhoneService::class,'id','id','service_phone_id','service_id');
|
||||
}
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models\Cost;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
abstract class Type extends Model
|
||||
{
|
||||
public $timestamps = FALSE;
|
||||
|
||||
protected $dates = [
|
||||
'start_at',
|
||||
'end_at',
|
||||
];
|
||||
|
||||
/* RELATIONS */
|
||||
|
||||
abstract public function service();
|
||||
|
||||
/* ATTRIBUTES */
|
||||
|
||||
public function getCostAttribute(): float
|
||||
{
|
||||
return $this->base+$this->excess;
|
||||
}
|
||||
}
|
|
@ -6,10 +6,9 @@ use Illuminate\Database\Eloquent\Model;
|
|||
|
||||
class Country extends Model
|
||||
{
|
||||
protected $table = 'ab_country';
|
||||
public $timestamps = FALSE;
|
||||
|
||||
/* RELATIONS */
|
||||
|
||||
/**
|
||||
* The currency this country belongs to
|
||||
*/
|
||||
|
@ -22,4 +21,12 @@ class Country extends Model
|
|||
{
|
||||
return $this->hasMany(Tax::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* The accounts in this country
|
||||
*/
|
||||
public function users()
|
||||
{
|
||||
return $this->hasMany(User::class);
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue