Compare commits
258 Commits
Author | SHA1 | Date | |
---|---|---|---|
3fc676fa26 | |||
a65c81871b | |||
7ec28218fa | |||
2627cea3b5 | |||
b877a2b673 | |||
89fb347806 | |||
e39dde05d8 | |||
2c3665650c | |||
5139b26a05 | |||
283ae06a5c | |||
23f23dfe40 | |||
7e784c3e81 | |||
a41a69676e | |||
d5b5de3086 | |||
6ac1b11864 | |||
7a41dd803f | |||
3b40e92c48 | |||
5f66987a3e | |||
b4c7c3ad20 | |||
8179ad60e1 | |||
e7f1ab638f | |||
33ba7903f2 | |||
f1031beff6 | |||
1b581e9feb | |||
bab1f45234 | |||
5abc07b712 | |||
4c273364c7 | |||
ef0d4dc773 | |||
f60727f5fb | |||
222fd5092e | |||
f1dd68a737 | |||
efbb3d091f | |||
06f25d5d4d | |||
c54b0fdc79 | |||
2e9f87550c | |||
78a8f63ac9 | |||
df3f7e31be | |||
0469d64577 | |||
f8453ae391 | |||
078dc6ab39 | |||
7e383511ab | |||
725b6f317d | |||
f43748e20a | |||
0b5bc9e012 | |||
5f10175b35 | |||
1c4cb6f38c | |||
667109150d | |||
9380850395 | |||
756f550b43 | |||
9277d42196 | |||
743374cb17 | |||
ddd44b643f | |||
79237868cb | |||
14609fb377 | |||
1bae121481 | |||
d6a2c70146 | |||
46075745d2 | |||
b145856ce9 | |||
45794ff109 | |||
c91a2fa8e5 | |||
b486a0eac4 | |||
28aa1f9dc8 | |||
f561139d45 | |||
29bccbf72f | |||
2dc56d0321 | |||
09f2eb8d9d | |||
76889728cd | |||
0d9dbafcf1 | |||
b4f3db04fc | |||
70e94bf6e6 | |||
61fe84498a | |||
3c7e2bbbc9 | |||
844d509834 | |||
f458bb19c5 | |||
76d43a81c8 | |||
b3d5bf05a9 | |||
f0ec35f463 | |||
326b1dcfc5 | |||
b6b036e06d | |||
e7ac329d24 | |||
648d941893 | |||
59dc825bf7 | |||
1b4504cee2 | |||
74864e66cb | |||
c0cffc3e2c | |||
4e450d4efc | |||
1374d38545 | |||
7c91082ca8 | |||
27720ee882 | |||
8f283f83f2 | |||
c1bb20dec0 | |||
12b63a506f | |||
a195e4b55b | |||
8ad9e73abb | |||
|
a518158ccf | ||
|
ad2f6f3a7f | ||
|
e2d8f8a096 | ||
|
11b554daad | ||
|
17ebbb71e8 | ||
|
dde11f73f5 | ||
|
790ece14d1 | ||
|
45dd74aad4 | ||
|
b3539e6c7e | ||
|
f3ecc12494 | ||
|
fe4bc3acef | ||
a32e8e9d05 | |||
013bb632d3 | |||
691180b3f0 | |||
dc74a064ba | |||
820ff2be00 | |||
96f799f535 | |||
0f91ce4940 | |||
95bb55aad8 | |||
0ac35c3d43 | |||
a5238bfbdc | |||
25dab73a83 | |||
72648ea14d | |||
4f19da5987 | |||
fd110f5c6f | |||
8fb888a395 | |||
10931bd156 | |||
a6f01d0864 | |||
|
b719efb58c | ||
|
bfd17b0686 | ||
|
a87560ff96 | ||
|
c96d264c8f | ||
|
0b4e3a9341 | ||
|
6aa30f537b | ||
|
ffcab790fc | ||
|
b065d15f60 | ||
|
319fa32754 | ||
|
15a3b11d2e | ||
|
ec99a5ff75 | ||
|
2a19f14adb | ||
|
1667b8c1df | ||
|
5b4aa5c73e | ||
|
3cae12b256 | ||
|
39db6303c2 | ||
|
8955df84cd | ||
|
8d920e1ba1 | ||
|
71b252843c | ||
|
1deda523b4 | ||
|
73d92f25c1 | ||
|
798608cebd | ||
|
4b85e01e93 | ||
|
c1a64e2094 | ||
|
8fd79ce23e | ||
|
70571cb6ac | ||
|
f5d535daa7 | ||
|
d358620b46 | ||
|
e4c1305da5 | ||
|
53c665787e | ||
|
2722c92bcf | ||
|
a1fd36aa6f | ||
|
ae3f97d890 | ||
|
17f07dafc0 | ||
|
20c91e8e31 | ||
|
a52c20993b | ||
|
dd76fda274 | ||
|
2bac177618 | ||
|
06b1eca306 | ||
|
360182b6bb | ||
|
7feec266b8 | ||
|
de3f1a534b | ||
|
97f5c84f23 | ||
|
7f6df8d032 | ||
|
39ded93a42 | ||
|
4f7a27dd8d | ||
|
cc906e9b22 | ||
|
bb44c1a216 | ||
|
3ff7bf1571 | ||
|
5297ae8a62 | ||
|
fb416306e7 | ||
|
464407e7ee | ||
|
3723d644e6 | ||
|
f6f502618d | ||
|
b0a317d709 | ||
|
8ba6a93214 | ||
|
768744ad27 | ||
|
606f357839 | ||
|
8777024cd8 | ||
|
642446e592 | ||
|
d1fbb4b42b | ||
|
5e82f091c0 | ||
|
28438c6423 | ||
|
49a4830d89 | ||
|
9e889008bf | ||
|
2590997b1a | ||
|
c1080481ec | ||
|
c8162b8eb9 | ||
|
849fd8d56b | ||
|
cc94426902 | ||
|
360c1e46a1 | ||
|
b8f85960aa | ||
|
b9ec64fd4f | ||
|
69e5a5f12c | ||
|
2d7437fc0d | ||
|
03f37f33ff | ||
|
16cc0c9f8d | ||
|
e1a4db700f | ||
|
a16277d9bb | ||
|
8ed9e38290 | ||
|
d53643ef55 | ||
|
796c72dd09 | ||
|
40d12b906b | ||
|
3fb6c0a052 | ||
|
16b7e0b493 | ||
|
621a132e35 | ||
|
ebf08ea414 | ||
|
9659621ba0 | ||
|
edc06e51fb | ||
|
a4ed29b560 | ||
|
7775105da6 | ||
|
d7b5d9a272 | ||
|
62f587d7e6 | ||
|
6dab5bded8 | ||
|
e9ada2468e | ||
|
db0ded44e0 | ||
|
d1a7e399dc | ||
|
b9b4416737 | ||
|
1e9f15b40f | ||
|
8f5293662e | ||
|
d0a56de07e | ||
|
bdcfe07fb0 | ||
|
0aa7ff3b2c | ||
|
b7b6a575bc | ||
|
8d194c5523 | ||
|
05c5d35dbf | ||
|
99a62828f5 | ||
|
b4e569ccc8 | ||
|
48a76bacb6 | ||
|
8a8e299c7b | ||
|
7908676063 | ||
|
6fa88daeb0 | ||
|
17e7b47cdc | ||
|
cc49692545 | ||
|
1a92d89911 | ||
|
7c5369203c | ||
|
c0ad46ba65 | ||
|
5be4fe6784 | ||
|
7acb9e964b | ||
|
4243da9c32 | ||
|
f7439172b6 | ||
|
b2e45fcaee | ||
|
eae1b16797 | ||
|
4cbe990ec1 | ||
|
7277d7407a | ||
|
ccd6a11c8a | ||
|
00f215b780 | ||
|
10e6c73b2b | ||
|
7a963c8461 | ||
|
d463239b17 | ||
|
fa62a47680 | ||
|
f22813bb5b | ||
|
8b08f79877 | ||
|
9515e67493 | ||
|
53fc25612b | ||
|
71d2faedb1 |
37
.env.example
37
.env.example
@ -1,32 +1,37 @@
|
||||
APP_ADMIN=
|
||||
APP_DEBUG=false
|
||||
APP_NAME=OSB
|
||||
APP_NAME_HTML_LONG="<b>Graytech</b>Hosting"
|
||||
APP_NAME_HTML_SHORT="<b>G</b>H"
|
||||
APP_ENV=production
|
||||
APP_KEY=
|
||||
APP_DEBUG=false
|
||||
APP_TIMEZONE=Australia/Melbourne
|
||||
APP_URL=https://www.graytech.net.au
|
||||
|
||||
LOG_CHANNEL=stack
|
||||
AUTH_PASSWORD_RESET_TOKEN_TABLE=password_resets
|
||||
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=database
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=database
|
||||
DB_USERNAME=homestead
|
||||
DB_PASSWORD=secret
|
||||
LOG_CHANNEL=daily
|
||||
|
||||
DB_CONNECTION=pgsql
|
||||
DB_HOST=postgres
|
||||
DB_PORT=5432
|
||||
DB_DATABASE=graytech
|
||||
DB_USERNAME=graytech
|
||||
DB_PASSWORD=
|
||||
DB_SCHEMA=billing
|
||||
|
||||
BROADCAST_DRIVER=log
|
||||
CACHE_DRIVER=file
|
||||
CACHE_STORE=file
|
||||
SESSION_DRIVER=file
|
||||
SESSION_LIFETIME=120
|
||||
QUEUE_DRIVER=database
|
||||
QUEUE_CONNECTION=database
|
||||
|
||||
REDIS_HOST=127.0.0.1
|
||||
REDIS_PASSWORD=null
|
||||
REDIS_PORT=6379
|
||||
|
||||
MAIL_DRIVER=smtp
|
||||
MAIL_HOST=MAIL
|
||||
MAIL_MAILER=smtp
|
||||
MAIL_HOST=smtp
|
||||
MAIL_PORT=25
|
||||
MAIL_USERNAME=null
|
||||
MAIL_PASSWORD=null
|
||||
@ -43,13 +48,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=
|
||||
|
147
.gitea/workflows/build_docker.yaml
Normal file
147
.gitea/workflows/build_docker.yaml
Normal file
@ -0,0 +1,147 @@
|
||||
name: Create Docker Image
|
||||
run-name: ${{ gitea.actor }} Building Docker Image 🐳
|
||||
on: [push]
|
||||
env:
|
||||
VERSION: latest
|
||||
DOCKER_HOST: tcp://127.0.0.1:2375
|
||||
|
||||
jobs:
|
||||
# test:
|
||||
# strategy:
|
||||
# matrix:
|
||||
# arch:
|
||||
# - x86_64
|
||||
# # arm64
|
||||
#
|
||||
# name: Test Application
|
||||
# runs-on: docker-${{ matrix.arch }}
|
||||
# container:
|
||||
# image: gitea.dege.au/docker/php:8.3-fpm-pgsql-server-test
|
||||
#
|
||||
# steps:
|
||||
# - name: Environment Setup
|
||||
# run: |
|
||||
# # If we have a proxy use it
|
||||
# if [ -n "${HTTP_PROXY}" ]; then echo "HTTP PROXY [${HTTP_PROXY}]"; sed -i -e s'/https/http/' /etc/apk/repositories; fi
|
||||
# # Some pre-reqs
|
||||
# apk add git nodejs
|
||||
# ## Some debugging info
|
||||
# # env|sort
|
||||
#
|
||||
# - name: Code Checkout
|
||||
# uses: actions/checkout@v4
|
||||
#
|
||||
# - name: Run Tests
|
||||
# run: |
|
||||
# mv .env.testing .env
|
||||
# # Install Composer and project dependencies.
|
||||
# mkdir -p ${COMPOSER_HOME}
|
||||
# if [ -n "${{ secrets.COMPOSER_GITHUB_TOKEN }}" ]; then echo ${{ secrets.COMPOSER_GITHUB_TOKEN }} > ${COMPOSER_HOME}/auth.json; fi
|
||||
# composer install
|
||||
# # Generate an application key. Re-cache.
|
||||
# php artisan key:generate
|
||||
# php artisan migrate
|
||||
# php artisan db:seed
|
||||
# # run laravel tests
|
||||
# touch storage/app/test/*ZIP storage/app/test/file/*
|
||||
# XDEBUG_MODE=coverage php vendor/bin/phpunit --coverage-text --colors=never
|
||||
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
arch:
|
||||
- x86_64
|
||||
# - arm64
|
||||
# needs: [test]
|
||||
|
||||
name: Build Docker Image
|
||||
runs-on: docker-${{ matrix.arch }}
|
||||
container:
|
||||
image: docker:dind
|
||||
privileged: true
|
||||
env:
|
||||
ARCH: ${{ matrix.arch }}
|
||||
VERSIONARCH: ${{ env.VERSION }}-${{ env.ARCH }}
|
||||
|
||||
steps:
|
||||
- name: Environment Setup
|
||||
run: |
|
||||
# If we have a proxy use it
|
||||
if [ -n "${HTTP_PROXY}" ]; then echo "HTTP PROXY [${HTTP_PROXY}]"; sed -i -e s'/https/http/' /etc/apk/repositories; fi
|
||||
# Some pre-reqs
|
||||
apk add git curl nodejs
|
||||
# Start docker
|
||||
( dockerd --host=tcp://0.0.0.0:2375 --tls=false & ) && sleep 3
|
||||
## Some debugging info
|
||||
# docker info && docker version
|
||||
env|sort
|
||||
echo "PRT: ${{ secrets.PKG_WRITE_TOKEN }}"
|
||||
|
||||
- name: Registry FQDN Setup
|
||||
id: registry
|
||||
run: |
|
||||
registry=${{ github.server_url }}
|
||||
echo "registry=${registry##http*://}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Container Registry Login
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ${{ steps.registry.outputs.registry }}
|
||||
username: ${{ gitea.actor }}
|
||||
password: ${{ secrets.PKG_WRITE_TOKEN }}
|
||||
|
||||
- name: Code Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Record version
|
||||
run: |
|
||||
pwd
|
||||
ls -al
|
||||
echo ${GITHUB_SHA::8} > VERSION
|
||||
cat VERSION
|
||||
|
||||
- name: Build and Push Docker Image
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: docker/Dockerfile
|
||||
push: true
|
||||
tags: "${{ steps.registry.outputs.registry }}/${{ env.GITHUB_REPOSITORY }}:${{ env.VERSIONARCH }}"
|
||||
|
||||
manifest:
|
||||
name: Final Docker Image Manifest
|
||||
runs-on: docker-x86_64
|
||||
container:
|
||||
image: docker:dind
|
||||
privileged: true
|
||||
needs: [build]
|
||||
|
||||
steps:
|
||||
- name: Environment Setup
|
||||
run: |
|
||||
# If we have a proxy use it
|
||||
if [ -n "${HTTP_PROXY}" ]; then echo "HTTP PROXY [${HTTP_PROXY}]"; sed -i -e s'/https/http/' /etc/apk/repositories; fi
|
||||
# Some pre-reqs
|
||||
apk add git curl nodejs
|
||||
# Start docker
|
||||
( dockerd --host=tcp://0.0.0.0:2375 --tls=false & ) && sleep 3
|
||||
|
||||
- name: Registry FQDN Setup
|
||||
id: registry
|
||||
run: |
|
||||
registry=${{ github.server_url }}
|
||||
echo "registry=${registry##http*://}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Container Registry Login
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ${{ steps.registry.outputs.registry }}
|
||||
username: ${{ gitea.actor }}
|
||||
password: ${{ secrets.PKG_WRITE_TOKEN }}
|
||||
|
||||
- name: Build Docker Manifest
|
||||
run: |
|
||||
docker manifest create ${{ steps.registry.outputs.registry }}/${{ env.GITHUB_REPOSITORY }}:${{ env.VERSION }} \
|
||||
${{ steps.registry.outputs.registry }}/${{ env.GITHUB_REPOSITORY }}:${{ env.VERSION }}-x86_64
|
||||
# ${{ steps.registry.outputs.registry }}/${{ env.GITHUB_REPOSITORY }}:${{ env.VERSION }}-arm64
|
||||
docker manifest push --purge ${{ steps.registry.outputs.registry }}/${{ env.GITHUB_REPOSITORY }}:${{ env.VERSION }}
|
@ -1,14 +0,0 @@
|
||||
stages:
|
||||
- test
|
||||
- build
|
||||
|
||||
# This folder is cached between builds
|
||||
# http://docs.gitlab.com/ce/ci/yaml/README.html#cache
|
||||
cache:
|
||||
key: ${CI_COMMIT_REF_SLUG}
|
||||
paths:
|
||||
- vendor/
|
||||
|
||||
include:
|
||||
- .gitlab-test.yml
|
||||
- .gitlab-docker-x86_64.yml
|
@ -1,33 +0,0 @@
|
||||
docker:
|
||||
image: docker:latest
|
||||
|
||||
stage: build
|
||||
|
||||
services:
|
||||
- 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
|
||||
|
||||
script:
|
||||
- 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,45 +0,0 @@
|
||||
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
|
||||
|
||||
variables:
|
||||
MYSQL_DATABASE: testing
|
||||
MYSQL_ROOT_PASSWORD: test
|
||||
MYSQL_USER: test
|
||||
MYSQL_PASSWORD: test
|
||||
|
||||
tags:
|
||||
- php
|
||||
only:
|
||||
- master
|
||||
- test
|
||||
|
||||
before_script:
|
||||
- mv .env.testing .env
|
||||
|
||||
# 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
|
||||
|
||||
# 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 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
|
13
Dockerfile
13
Dockerfile
@ -1,13 +0,0 @@
|
||||
FROM registry.leenooks.net/leenooks/php:8.0-fpm-image
|
||||
|
||||
COPY . /var/www/html/
|
||||
|
||||
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 /var/www/.composer
|
29
app/Casts/CollectionOrNull.php
Normal file
29
app/Casts/CollectionOrNull.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Casts;
|
||||
|
||||
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class CollectionOrNull implements CastsAttributes
|
||||
{
|
||||
/**
|
||||
* Cast the given value.
|
||||
*
|
||||
* @param array<string, mixed> $attributes
|
||||
*/
|
||||
public function get(Model $model, string $key, mixed $value, array $attributes): mixed
|
||||
{
|
||||
return collect(json_decode($value, true));
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the given value for storage.
|
||||
*
|
||||
* @param array<string, mixed> $attributes
|
||||
*/
|
||||
public function set(Model $model, string $key, mixed $value, array $attributes): mixed
|
||||
{
|
||||
return count($value) ? json_encode($value) : NULL;
|
||||
}
|
||||
}
|
7
app/Classes/External/Accounting.php
vendored
7
app/Classes/External/Accounting.php
vendored
@ -1,7 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\External;
|
||||
|
||||
abstract class Accounting
|
||||
{
|
||||
}
|
68
app/Classes/External/Accounting/Quickbooks.php
vendored
68
app/Classes/External/Accounting/Quickbooks.php
vendored
@ -1,68 +0,0 @@
|
||||
<?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);
|
||||
}
|
||||
}
|
79
app/Classes/External/Payments/Ezypay.php
vendored
79
app/Classes/External/Payments/Ezypay.php
vendored
@ -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__]);
|
||||
if ($api_remain === 0) {
|
||||
Log::error('API Throttle.',['m'=>__METHOD__,'api_reset'=>$api_reset]);
|
||||
Cache::put('api_throttle',$api_reset,now()->addSeconds($api_reset));
|
||||
}
|
||||
|
||||
@ -45,6 +45,56 @@ 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() {
|
||||
@ -52,6 +102,29 @@ 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) {
|
||||
@ -65,4 +138,4 @@ class Ezypay extends Payments
|
||||
return Collect($this->connect('settlements/'.config('services.ezypay.guid').($opt ? '?'.http_build_query($opt) : '')));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
26
app/Classes/External/Supplier.php
vendored
26
app/Classes/External/Supplier.php
vendored
@ -17,6 +17,8 @@ abstract class Supplier
|
||||
protected $o = NULL;
|
||||
protected $_columns = [];
|
||||
|
||||
public const traffic_connection_keys = ['user','pass','url'];
|
||||
|
||||
public function __construct(Model $o)
|
||||
{
|
||||
$this->o = $o;
|
||||
@ -26,24 +28,29 @@ abstract class Supplier
|
||||
/**
|
||||
* Connect and pull down traffic data
|
||||
*
|
||||
* @param array $connection
|
||||
* @param string $type
|
||||
* @return Collection
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function fetch(): Collection
|
||||
public function fetch(array $connection,string $type): 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,$this->o->stats_lastupdate),['m'=>__METHOD__]);
|
||||
$key = 'Supplier:'.$this->o->id.$this->o->stats_lastupdate;
|
||||
$result = Cache::remember($key,86400,function() {
|
||||
$client = $this->getClient();
|
||||
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');
|
||||
|
||||
$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'),
|
||||
$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'),
|
||||
]);
|
||||
|
||||
// @todo These API rate limiting is untested.
|
||||
@ -55,7 +62,6 @@ 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();
|
||||
|
@ -3,9 +3,10 @@
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
|
||||
use App\Jobs\BroadbandTraffic as Job;
|
||||
use App\Models\AdslSupplier;
|
||||
use App\Models\Supplier;
|
||||
|
||||
class BroadbandTraffic extends Command
|
||||
{
|
||||
@ -14,7 +15,8 @@ class BroadbandTraffic extends Command
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'broadband:traffic:import';
|
||||
protected $signature = 'broadband:traffic:import'.
|
||||
' {supplier? : Supplier Name}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
@ -30,7 +32,26 @@ class BroadbandTraffic extends Command
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
foreach (AdslSupplier::active()->get() as $o)
|
||||
Job::dispatch($o);
|
||||
if ($this->argument('supplier')) {
|
||||
try {
|
||||
$o = Supplier::active()
|
||||
->where('name','ilike',$this->argument('supplier'))
|
||||
->sole();
|
||||
|
||||
} catch (ModelNotFoundException $e) {
|
||||
$this->error(sprintf('Supplier [%s] not found',$this->argument('supplier')));
|
||||
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
Job::dispatchSync($o->name);
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
foreach (Supplier::active()->get() as $o)
|
||||
Job::dispatchSync($o->name);
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
}
|
54
app/Console/Commands/EmailTest.php
Normal file
54
app/Console/Commands/EmailTest.php
Normal file
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
|
||||
use App\Mail\Test;
|
||||
use App\Models\{Site,User};
|
||||
|
||||
class EmailTest extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'test-email'
|
||||
.' {--s|site : Site ID}'
|
||||
.' {id : User ID}'
|
||||
.' {email? : Alternative Email}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Send a test email';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
Config::set(
|
||||
'site',
|
||||
$this->option('site')
|
||||
? Site::findOrFail($this->option('site'))
|
||||
: Site::where('url',config('app.url'))->sole()
|
||||
);
|
||||
|
||||
$uo = User::find($this->argument('id'));
|
||||
|
||||
$result = Mail::to($this->argument('email') ?? $uo->email)
|
||||
->send(new Test($uo));
|
||||
|
||||
$this->info($result->getMessageId());
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
}
|
95
app/Console/Commands/Ezypay/PaymentNext.php
Normal file
95
app/Console/Commands/Ezypay/PaymentNext.php
Normal file
@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands\Ezypay;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
use App\Classes\External\Payments\Ezypay;
|
||||
use App\Models\Account;
|
||||
|
||||
class PaymentNext extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'ezypay:payment:next';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Load next payments, and ensure they cover the next invoice';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$poo = new Ezypay;
|
||||
|
||||
foreach ($poo->getCustomers() as $c) {
|
||||
if ($c->BillingStatus == 'Inactive') {
|
||||
$this->comment(sprintf('Ignoring INACTIVE: [%s] %s %s',$c->EzypayReferenceNumber,$c->Firstname,$c->Surname));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Load Account Details from ReferenceId
|
||||
$ao = Account::find((int)substr($c->ReferenceId,2,4));
|
||||
|
||||
if (! $ao) {
|
||||
$this->warn(sprintf('Missing: [%s] %s %s (%s)',$c->EzypayReferenceNumber,$c->Firstname,$c->Surname,$c->ReferenceId));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get Due Invoices
|
||||
$invoice_due = $ao->invoiceSummaryDue()->get();
|
||||
|
||||
$this->info(sprintf('Account [%s] (%s) has [%d] invoices due, totalling [%3.2f]',
|
||||
$ao->lid,
|
||||
$ao->name,
|
||||
$invoice_due->count(),
|
||||
($due=$invoice_due->sum('_balance')),
|
||||
));
|
||||
|
||||
$next_pay = $poo->getDebits([
|
||||
'customerId'=>$c->Id,
|
||||
'dateFrom'=>now()->format('Y-m-d'),
|
||||
'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 < $due)
|
||||
$this->error(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($due,2)));
|
||||
|
||||
elseif ($next_pay->Amount > $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($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($due,2)));
|
||||
}
|
||||
}
|
||||
}
|
35
app/Console/Commands/Ezypay/PaymentsImport.php
Normal file
35
app/Console/Commands/Ezypay/PaymentsImport.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands\Ezypay;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
use App\Classes\External\Payments\Ezypay;
|
||||
use App\Jobs\PaymentsImport as Job;
|
||||
|
||||
class PaymentsImport extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'ezypay:payment:import';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Retrieve payments from Ezypay';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
Job::dispatchSync(new Ezypay);
|
||||
}
|
||||
}
|
44
app/Console/Commands/ImportCosts.php
Normal file
44
app/Console/Commands/ImportCosts.php
Normal file
@ -0,0 +1,44 @@
|
||||
<?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'),
|
||||
);
|
||||
}
|
||||
}
|
58
app/Console/Commands/Intuit/AccountAdd.php
Normal file
58
app/Console/Commands/Intuit/AccountAdd.php
Normal file
@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands\Intuit;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Intuit\Exceptions\NotTokenException;
|
||||
use Intuit\Jobs\AccountingCustomerUpdate;
|
||||
use Intuit\Models\Customer as AccAccount;
|
||||
use Intuit\Traits\ProviderTokenTrait;
|
||||
|
||||
use App\Models\Account;
|
||||
|
||||
class AccountAdd extends Command
|
||||
{
|
||||
use ProviderTokenTrait;
|
||||
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'intuit:account:add'
|
||||
.' {id : Account ID}'
|
||||
.' {user? : User Email}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Add an account to quickbooks';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return int
|
||||
* @throws NotTokenException
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$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(
|
||||
$this->providerToken($this->argument('user')),
|
||||
$acc
|
||||
);
|
||||
}
|
||||
}
|
45
app/Console/Commands/Intuit/AccountSync.php
Normal file
45
app/Console/Commands/Intuit/AccountSync.php
Normal file
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands\Intuit;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Intuit\Exceptions\NotTokenException;
|
||||
use Intuit\Traits\ProviderTokenTrait;
|
||||
|
||||
use App\Jobs\AccountingAccountSync;
|
||||
|
||||
/**
|
||||
* Synchronise Customers with Accounts
|
||||
*/
|
||||
class AccountSync extends Command
|
||||
{
|
||||
use ProviderTokenTrait;
|
||||
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'intuit:account:sync'
|
||||
.' {user? : User Email}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Synchronise accounts with quickbooks';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return int
|
||||
* @throws NotTokenException
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
AccountingAccountSync::dispatchSync($this->providerToken($this->argument('user')));
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
}
|
132
app/Console/Commands/Intuit/InvoiceAdd.php
Normal file
132
app/Console/Commands/Intuit/InvoiceAdd.php
Normal file
@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands\Intuit;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Intuit\Jobs\AccountingInvoiceUpdate;
|
||||
use Intuit\Models\Invoice as AccInvoice;
|
||||
use Intuit\Traits\ProviderTokenTrait;
|
||||
|
||||
use App\Models\Invoice;
|
||||
|
||||
class InvoiceAdd extends Command
|
||||
{
|
||||
use ProviderTokenTrait;
|
||||
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'intuit:invoice:add'
|
||||
.' {id : Invoice ID}'
|
||||
.' {user? : User Email}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Add an invoice to the accounting provider';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return int
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$to = $this->providerToken($this->argument('user'));
|
||||
|
||||
$io = Invoice::findOrFail($this->argument('id'));
|
||||
|
||||
// Check the customer exists
|
||||
if ($io->account->providers->where('pivot.provider_oauth_id',$to->provider->id)->count() !== 1)
|
||||
throw new \Exception(sprintf('Account [%d] for Invoice [%d] not defined',$io->account_id,$io->id));
|
||||
|
||||
$ao = $io->account->providers->where('pivot.provider_oauth_id',$to->provider->id)->pop();
|
||||
|
||||
// Some validation
|
||||
if (! $ao->pivot->ref) {
|
||||
$this->error(sprintf('Accounting not defined for account [%d]',$io->account_id));
|
||||
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
$acc = new AccInvoice;
|
||||
$acc->CustomerRef = (object)['value'=>$ao->pivot->ref];
|
||||
$acc->DocNumber = $io->lid;
|
||||
$acc->TxnDate = $io->created_at->format('Y-m-d');
|
||||
$acc->DueDate = $io->due_at->format('Y-m-d');
|
||||
|
||||
$lines = collect();
|
||||
$c = 0;
|
||||
$subtotal = 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 ($io->items->groupBy(
|
||||
fn($item)=>
|
||||
sprintf('%s.%s.%s.%s',
|
||||
$item->item_type_name,
|
||||
$item->price_base,
|
||||
$item->product?->provider_ref($to->provider),
|
||||
$item->taxes->pluck('description')->join('|'))) as $os)
|
||||
{
|
||||
$key = $os->first();
|
||||
|
||||
// Some validation
|
||||
if (! ($ref=$key->product?->provider_ref($to->provider))) {
|
||||
$this->error(sprintf('Accounting not defined in product [%d]',$key->product_id));
|
||||
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
if ($key->taxes->count() !== 1) {
|
||||
$this->error(sprintf('Cannot handle when there is not just 1 tax line [%d]',$key->id));
|
||||
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
$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'=>$tcf=$key->taxes->first()->tax->provider_ref($to->provider)],
|
||||
];
|
||||
$line->Amount = round($os->sum('quantity')*$key->price_base,2);
|
||||
|
||||
$subtotal += $line->Amount;
|
||||
|
||||
$lines->push($line);
|
||||
}
|
||||
|
||||
$acc->Line = $lines;
|
||||
|
||||
// If our subtotal doesnt match, we need to add a tax line
|
||||
if ($io->subtotal !== $subtotal) {
|
||||
$acc->TxnTaxDetail = (object)[
|
||||
'TotalTax' => $x=$io->total-$subtotal,
|
||||
'TaxLine' => [
|
||||
(object) [
|
||||
'Amount' => $x,
|
||||
'DetailType' => 'TaxLineDetail',
|
||||
'TaxLineDetail' => (object)[
|
||||
// @todo It is assumed there is only 1 tax category
|
||||
'TaxRateRef' => (object)['value'=>$to->API()->getTaxCodeQuery($tcf)->getTaxRateRef()->first()],
|
||||
'NetAmountTaxable' => $io->subtotal,
|
||||
]
|
||||
]
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
return AccountingInvoiceUpdate::dispatchSync($to,$acc);
|
||||
}
|
||||
}
|
41
app/Console/Commands/Intuit/InvoiceSync.php
Normal file
41
app/Console/Commands/Intuit/InvoiceSync.php
Normal file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands\Intuit;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Intuit\Traits\ProviderTokenTrait;
|
||||
|
||||
use App\Jobs\AccountingInvoiceSync as Job;
|
||||
|
||||
class InvoiceSync extends Command
|
||||
{
|
||||
use ProviderTokenTrait;
|
||||
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'intuit:invoice:sync'
|
||||
.' {user? : User Email}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Synchronise invoices with accounting system';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return int
|
||||
* @throws \Intuit\Exceptions\NotTokenException
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
Job::dispatchSync($this->providerToken($this->argument('user')));
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
}
|
60
app/Console/Commands/Intuit/ItemList.php
Normal file
60
app/Console/Commands/Intuit/ItemList.php
Normal file
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands\Intuit;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Intuit\Exceptions\NotTokenException;
|
||||
use Intuit\Traits\ProviderTokenTrait;
|
||||
|
||||
use App\Models\Product;
|
||||
|
||||
/**
|
||||
* Return a list of products and their accounting id
|
||||
*/
|
||||
class ItemList extends Command
|
||||
{
|
||||
use ProviderTokenTrait;
|
||||
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'accounting:item:list'
|
||||
.' {user? : User Email}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Synchronise items with accounting system';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return int
|
||||
* @throws NotTokenException
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$to = $this->providerToken($this->argument('user'));
|
||||
|
||||
// Current Products used by services
|
||||
$products = Product::select(['products.*'])
|
||||
->distinct('products.id')
|
||||
->join('services',['services.product_id'=>'products.id'])
|
||||
->where('services.active',TRUE)
|
||||
->get();
|
||||
|
||||
foreach ($products as $po) {
|
||||
if (! $x=$po->provider_ref($to->provider))
|
||||
$this->error(sprintf('Product [%03d](%s) doesnt have accounting set',$po->id,$po->name));
|
||||
|
||||
else
|
||||
$this->info(sprintf('Product [%03d](%s) set to accounting [%s]',$po->id,$po->name,$x));
|
||||
}
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
}
|
44
app/Console/Commands/Intuit/PaymentSync.php
Normal file
44
app/Console/Commands/Intuit/PaymentSync.php
Normal file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands\Intuit;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Intuit\Traits\ProviderTokenTrait;
|
||||
|
||||
use App\Jobs\AccountingPaymentSync as Job;
|
||||
|
||||
class PaymentSync extends Command
|
||||
{
|
||||
use ProviderTokenTrait;
|
||||
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'intuit:payment:sync'
|
||||
.' {user? : User Email}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Synchronise payments with accounting system';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return int
|
||||
* @throws \Intuit\Exceptions\NotTokenException
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$to = $this->providerToken($this->argument('user'));
|
||||
|
||||
foreach ($to->API()->getPayments() as $acc)
|
||||
Job::dispatchSync($to,$acc);
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
}
|
44
app/Console/Commands/Intuit/TaxSync.php
Normal file
44
app/Console/Commands/Intuit/TaxSync.php
Normal file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands\Intuit;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Intuit\Traits\ProviderTokenTrait;
|
||||
|
||||
use App\Jobs\AccountingTaxSync as Job;
|
||||
|
||||
/**
|
||||
* Synchronise TAX ids with our taxes.
|
||||
*/
|
||||
class TaxSync extends Command
|
||||
{
|
||||
use ProviderTokenTrait;
|
||||
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'intuit:tax:sync'
|
||||
.' {user? : User Email}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Synchronise taxes with accounting system';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return int
|
||||
* @throws \Intuit\Exceptions\NotTokenException
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
Job::dispatchSync($this->providerToken($this->argument('user')));
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
}
|
@ -2,10 +2,10 @@
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
use App\Models\Invoice;
|
||||
use App\Models\{Invoice,Site};
|
||||
|
||||
class InvoiceEmail extends Command
|
||||
{
|
||||
@ -14,7 +14,9 @@ class InvoiceEmail extends Command
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'invoice:email {id}';
|
||||
protected $signature = 'invoice:email'
|
||||
.' {--s|site : Site ID}'
|
||||
.' {id?}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
@ -23,16 +25,6 @@ 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.
|
||||
*
|
||||
@ -40,19 +32,23 @@ class InvoiceEmail extends Command
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
Config::set(
|
||||
'site',
|
||||
$this->option('site')
|
||||
? Site::findOrFail($this->option('site'))
|
||||
: Site::where('url',config('app.url'))->sole()
|
||||
);
|
||||
|
||||
$o = Invoice::findOrFail($this->argument('id'));
|
||||
|
||||
Mail::to($o->account->user->email)->send(new \App\Mail\InvoiceEmail($o));
|
||||
|
||||
if (Mail::failures()) {
|
||||
dump('Failure?');
|
||||
|
||||
dump(Mail::failures());
|
||||
|
||||
} else {
|
||||
$o->print_status = TRUE;
|
||||
$o->reminders = $o->reminders('send');
|
||||
try {
|
||||
$o->send();
|
||||
$o->save();
|
||||
|
||||
} catch (\Exception $e) {
|
||||
dd($e);
|
||||
}
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
}
|
@ -2,10 +2,11 @@
|
||||
|
||||
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 +15,11 @@ class InvoiceGenerate extends Command
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'invoice:generate {account?} {--p|preview : Preview} {--l|list : List Items}';
|
||||
protected $signature = 'invoice:generate'
|
||||
.' {--l|list : List Items}'
|
||||
.' {--p|preview : Preview}'
|
||||
.' {--s|site : Site ID}'
|
||||
.' {id?}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
@ -23,16 +28,6 @@ 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.
|
||||
*
|
||||
@ -40,35 +35,50 @@ class InvoiceGenerate extends Command
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
if ($this->argument('account'))
|
||||
$accounts = collect()->push(Account::find($this->argument('account')));
|
||||
Config::set(
|
||||
'site',
|
||||
$this->option('site')
|
||||
? Site::findOrFail($this->option('site'))
|
||||
: Site::where('url',config('app.url'))->sole()
|
||||
);
|
||||
|
||||
if ($this->argument('id'))
|
||||
$accounts = collect()->push(Account::find($this->argument('id')));
|
||||
else
|
||||
$accounts = Account::active()->get();
|
||||
|
||||
foreach ($accounts as $o) {
|
||||
$items = $o->invoice_next(Carbon::now());
|
||||
|
||||
if (! $items->count()) {
|
||||
$this->warn(sprintf('No items for account (%s) [%d]',$o->name,$o->id));
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->info(sprintf('Account: %s [%d]',$o->name,$o->lid));
|
||||
$io = new Invoice;
|
||||
$io->account_id = $o->id;
|
||||
|
||||
foreach ($o->services(TRUE)->get() as $so) {
|
||||
foreach ($so->next_invoice_items(FALSE) as $ooo)
|
||||
$io->items->push($ooo);
|
||||
}
|
||||
foreach ($items as $oo)
|
||||
$io->items_active->push($oo);
|
||||
|
||||
// If there are no items, no reason to do anything
|
||||
if (! $io->items->count() OR $io->total < 0)
|
||||
if ($io->total < 0) {
|
||||
$this->warn(sprintf(' - Invoice totals [%3.2f] - skipping',$io->total));
|
||||
continue;
|
||||
}
|
||||
|
||||
$io->account_id = $o->id;
|
||||
|
||||
if ($this->option('list')) {
|
||||
$this->warn(sprintf('|%4s|%4s|%-50s|%8s|',
|
||||
$this->line(sprintf('|%4s|%4s|%-50s|%8s|',
|
||||
'SID',
|
||||
'PID',
|
||||
'Name',
|
||||
'Amount',
|
||||
));
|
||||
|
||||
foreach ($io->items as $oo) {
|
||||
foreach ($io->items_active as $oo) {
|
||||
$this->info(sprintf('|%4s|%4s|%-50s|%8.2f|',
|
||||
$oo->service_id,
|
||||
$oo->product_id,
|
||||
@ -78,8 +88,9 @@ class InvoiceGenerate extends Command
|
||||
}
|
||||
}
|
||||
|
||||
//dump($io);
|
||||
if ($this->option('preview')) {
|
||||
$this->info(sprintf('Invoice for Account [%d] - [%d] items totalling [%3.2f]',$o->id,$io->items->count(),$io->total));
|
||||
$this->info(sprintf('=> Invoice for Account [%d] - [%d] items totalling [%3.2f]',$o->id,$io->items_active->count(),$io->total));
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -89,5 +100,7 @@ class InvoiceGenerate extends Command
|
||||
|
||||
$io->pushNew();
|
||||
}
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
}
|
@ -43,8 +43,8 @@ class OrderSend extends Command
|
||||
{
|
||||
$so = Service::findOrFail($this->argument('service'));
|
||||
|
||||
// @todo TO get from DB
|
||||
Mail::to('help@graytech.net.au')->sendNow(new OrderRequestApprove($so));
|
||||
Mail::to(config('osb.ticket_admin'))
|
||||
->sendNow(new OrderRequestApprove($so));
|
||||
|
||||
if (Mail::failures()) {
|
||||
dump('Failure?');
|
||||
|
@ -1,107 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
use App\Classes\External\Payments\Ezypay;
|
||||
use App\Models\{Account,Checkout,Payment};
|
||||
|
||||
class PaymentsEzypayImport extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'payments:ezypay:import';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Retrieve payments from Ezypay';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,81 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
use App\Classes\External\Payments\Ezypay;
|
||||
use App\Models\Account;
|
||||
|
||||
class PaymentsEzypayNext extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'payments:ezypay:next';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$poo = new Ezypay();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// Get Due Invoices
|
||||
$account_due = $ao->dueInvoices()->sum('due');
|
||||
|
||||
$next_pay = $poo->getDebits([
|
||||
'customerId'=>$c->Id,
|
||||
'dateFrom'=>now()->format('Y-m-d'),
|
||||
'dateTo'=>now()->addQuarter()->format('Y-m-d'),
|
||||
])->reverse()->first();
|
||||
|
||||
if ($next_pay->Amount < $account_due)
|
||||
$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 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 for (%s) [%s] will cover outstanding balance [%s]',$ao->name,number_format($next_pay->Amount,2),number_format($account_due,2)));
|
||||
}
|
||||
}
|
||||
}
|
46
app/Console/Commands/ProviderTokenRefresh.php
Normal file
46
app/Console/Commands/ProviderTokenRefresh.php
Normal file
@ -0,0 +1,46 @@
|
||||
<?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'
|
||||
.' {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()
|
||||
{
|
||||
$uo = User::where('email',$this->argument('user') ?: config('osb.admin'))->singleOrFail();
|
||||
|
||||
$so = ProviderOauth::where('name',$this->argument('provider'))->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());
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
}
|
@ -1,261 +0,0 @@
|
||||
<?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,8 +3,6 @@
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
use App\Models\Service;
|
||||
|
||||
@ -15,10 +13,10 @@ class ServiceList extends Command
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'service:list '.
|
||||
'{--a|active : Active Only}'.
|
||||
'{--category= : Category}'.
|
||||
'{--f|fix : Fix start_date}';
|
||||
protected $signature = 'service:list'.
|
||||
' {--i|inactive : Include Inactive}'.
|
||||
' {--t|type= : Type}'.
|
||||
' {--f|fix : Fix start_date}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
@ -27,16 +25,6 @@ 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.
|
||||
*
|
||||
@ -44,50 +32,51 @@ class ServiceList extends Command
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
DB::listen(function($query) {
|
||||
Log::debug('- SQL',['sql'=>$query->sql,'binding'=>$query->bindings]);
|
||||
});
|
||||
$header = '|%5s|%-9s|%-30s|%-30s|%7s|%7s|%10s|%10s|%10s|%10s|%10s|';
|
||||
|
||||
$this->warn(sprintf('|%10s|%-6s|%-20s|%-50s|%8s|%14s|%10s|%10s|%10s|%10s|%10s|',
|
||||
$this->warn(sprintf($header,
|
||||
'ID',
|
||||
'CAT',
|
||||
'Type',
|
||||
'Product',
|
||||
'Name',
|
||||
'active',
|
||||
'status',
|
||||
'invoice next',
|
||||
'start date',
|
||||
'stop date',
|
||||
'connect date',
|
||||
'first invoice'
|
||||
));
|
||||
'Active',
|
||||
'Status',
|
||||
'Start',
|
||||
'Stop',
|
||||
'Connect',
|
||||
'First',
|
||||
'Next',
|
||||
));
|
||||
|
||||
foreach (Service::all() as $o) {
|
||||
if ($this->option('active') AND ! $o->isActive())
|
||||
foreach (Service::cursor() as $o) {
|
||||
if ((! $this->option('inactive')) && (! $o->isActive()))
|
||||
continue;
|
||||
|
||||
if ($this->option('category') AND $o->product->category !== $this->option('category'))
|
||||
if ($this->option('type') && ($o->product->getCategoryAttribute() !== $this->option('type')))
|
||||
continue;
|
||||
|
||||
$c = $o->invoice_items->filter(function($item) {return $item->item_type === 0; })->sortby('date_start')->first();
|
||||
$c = $o->invoiced_items
|
||||
->filter(fn($item)=>$item->item_type === 0)
|
||||
->sortby('start_at')
|
||||
->first();
|
||||
|
||||
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;
|
||||
if ($this->option('fix') && (! $o->start_at) && $c && $c->start_at && $o->type && $o->type->connect_at && $c->start_at->format('Y-m-d') == $o->type->connect_at->format('Y-m-d')) {
|
||||
$o->start_at = $o->type->connect_at;
|
||||
$o->save();
|
||||
}
|
||||
|
||||
$this->info(sprintf('|%10s|%-6s|%-20s|%-50s|%8s|%14s|%10s|%10s|%10s|%10s|%10s|',
|
||||
$o->sid,
|
||||
$o->product->category,
|
||||
$o->product_name,
|
||||
$o->name_short,
|
||||
$this->info(sprintf($header,
|
||||
$o->lid,
|
||||
$o->product->getCategoryNameAttribute(),
|
||||
substr($o->product->getNameAttribute(),0,35),
|
||||
substr($o->name_short,0,40),
|
||||
$o->active ? 'active' : 'inactive',
|
||||
$o->status,
|
||||
$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,
|
||||
$o->start_at?->format('Y-m-d'),
|
||||
$o->stop_at?->format('Y-m-d'),
|
||||
($o->type && $o->type->connect_at) ? $o->type->connect_at->format('Y-m-d') : NULL,
|
||||
($c && $c->start_at) ? $c->start_at->format('Y-m-d') : NULL,
|
||||
$o->invoice_next?->format('Y-m-d'),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
67
app/Console/Commands/SupplierAccountSync.php
Normal file
67
app/Console/Commands/SupplierAccountSync.php
Normal file
@ -0,0 +1,67 @@
|
||||
<?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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
40
app/Console/Commands/SupplierDomainSync.php
Normal file
40
app/Console/Commands/SupplierDomainSync.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?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'));
|
||||
}
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
|
||||
use App\Mail\TestEmail as MailTest;
|
||||
use App\Models\User;
|
||||
|
||||
class TestEmail extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'test:email {id}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Send a test email';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$uo = User::find($this->argument('id'));
|
||||
|
||||
Mail::to($uo->email)
|
||||
->send(new MailTest($uo));
|
||||
}
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console;
|
||||
|
||||
use Illuminate\Console\Scheduling\Schedule;
|
||||
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
||||
|
||||
use App\Models\AdslSupplier;
|
||||
use App\Jobs\BroadbandTraffic;
|
||||
|
||||
class Kernel extends ConsoleKernel
|
||||
{
|
||||
/**
|
||||
* The Artisan commands provided by your application.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $commands = [
|
||||
//
|
||||
];
|
||||
|
||||
/**
|
||||
* Define the application's command schedule.
|
||||
*
|
||||
* @param \Illuminate\Console\Scheduling\Schedule $schedule
|
||||
* @return void
|
||||
*/
|
||||
protected function schedule(Schedule $schedule)
|
||||
{
|
||||
// @todo This needs to be more generic and dynamic
|
||||
// Exetel Traffic
|
||||
$schedule->job(new BroadbandTraffic(AdslSupplier::find(1)))->timezone('Australia/Melbourne')->dailyAt('10:00');
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the commands for the application.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function commands()
|
||||
{
|
||||
$this->load(__DIR__.'/Commands');
|
||||
|
||||
require base_path('routes/console.php');
|
||||
}
|
||||
}
|
40
app/Events/ProviderPaymentCreated.php
Normal file
40
app/Events/ProviderPaymentCreated.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?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,6 +22,7 @@ class Handler extends ExceptionHandler
|
||||
* @var array
|
||||
*/
|
||||
protected $dontFlash = [
|
||||
'current_password',
|
||||
'password',
|
||||
'password_confirmation',
|
||||
];
|
||||
|
@ -2,138 +2,59 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
|
||||
use App\Models\{Account,Payment,PaymentItem,Service,SiteDetail};
|
||||
use App\Http\Requests\SiteEdit;
|
||||
use App\Models\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
|
||||
{
|
||||
public function service(Service $o)
|
||||
{
|
||||
return View('a.service',['o'=>$o]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Record payments on an account.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Payment $o
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function pay_add(Request $request,Payment $o)
|
||||
{
|
||||
if ($request->post()) {
|
||||
$validation = $request->validate([
|
||||
'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:ab_account,id',
|
||||
'pending' => 'nullable|boolean',
|
||||
'notes' => 'nullable|string',
|
||||
'ip' => 'nullable|ip',
|
||||
'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' => 'nullable|exists:ab_invoice,id',
|
||||
]);
|
||||
|
||||
$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) {
|
||||
$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');
|
||||
}
|
||||
|
||||
return view('a.payment.add')
|
||||
->with('o',$o);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a list of invoices to apply payments to
|
||||
*
|
||||
* @param Account $o
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function pay_invoices(Account $o)
|
||||
{
|
||||
return view('a.payment.widgets.invoices')
|
||||
->with('o',$o);
|
||||
}
|
||||
|
||||
/**
|
||||
* Site setup
|
||||
*
|
||||
* @note This method is protected by the routes
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Http\RedirectResponse
|
||||
* @param SiteEdit $request
|
||||
* @return RedirectResponse
|
||||
*/
|
||||
public function setup(Request $request)
|
||||
public function setup(SiteEdit $request)
|
||||
{
|
||||
if ($request->post()) {
|
||||
$validated = $request->validate([
|
||||
'site_name' => 'required|string|max:255',
|
||||
'site_email' => 'required|string|email|max:255',
|
||||
'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',
|
||||
'site_tax' => 'required|regex:/[0-9 ]+/|size:14',
|
||||
'social' => 'nullable|array',
|
||||
'top_menu' => 'nullable|array',
|
||||
'site_logo' => 'nullable|image',
|
||||
'email_logo' => 'nullable|image',
|
||||
]);
|
||||
$site = config('site');
|
||||
$images = ['site_logo','email_logo'];
|
||||
$validated = collect($request->validated());
|
||||
|
||||
$site = config('SITE');
|
||||
// Handle the images
|
||||
foreach($images as $key)
|
||||
if ($x=$request->validated($key))
|
||||
$validated->put($key,$x->storeAs('site/'.$site->site_id,$x->getClientOriginalName(),'public'));
|
||||
|
||||
// @todo - not currently rendered in the home page
|
||||
$validated['social'] = [];
|
||||
$validated['top_menu'] = [];
|
||||
foreach ($site->details as $oo)
|
||||
if ($validated->has($oo->key)) {
|
||||
// Dont set the following keys to null if they are null
|
||||
if (in_array($oo->key,$images) && is_null($validated->get($oo->key)))
|
||||
continue;
|
||||
|
||||
// Handle the images
|
||||
foreach(['site_logo','email_logo'] as $key)
|
||||
if (array_key_exists($key,$validated))
|
||||
$validated[$key] = ($x=$validated[$key])->storeAs('site/'.$site->site_id,$x->getClientOriginalName(),'public');
|
||||
$oo->value = $validated->get($oo->key) ?: '';
|
||||
$oo->save();
|
||||
|
||||
foreach ($site->details as $oo)
|
||||
if (array_key_exists($oo->key,$validated)) {
|
||||
$oo->value = Arr::get($validated,$oo->key);
|
||||
$oo->save();
|
||||
|
||||
unset($validated[$oo->key]);
|
||||
}
|
||||
|
||||
// Left over values to be created.
|
||||
foreach ($validated as $k=>$v) {
|
||||
$oo = new SiteDetail;
|
||||
$oo->key = $k;
|
||||
$oo->value = $v ?: '';
|
||||
|
||||
$site->details()->save($oo);
|
||||
$validated->forget($oo->key);
|
||||
}
|
||||
|
||||
return redirect()->back()
|
||||
->with('success','Settings saved');
|
||||
// Left over values to be created.
|
||||
foreach ($validated as $k=>$v) {
|
||||
$oo = new SiteDetail;
|
||||
$oo->key = $k;
|
||||
$oo->value = $v ?: '';
|
||||
|
||||
$site->details()->save($oo);
|
||||
}
|
||||
|
||||
return view('a.setup');
|
||||
return redirect()
|
||||
->back()
|
||||
->with('success','Settings saved');
|
||||
}
|
||||
}
|
@ -4,46 +4,29 @@ namespace App\Http\Controllers\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Password;
|
||||
|
||||
class ForgotPasswordController extends Controller
|
||||
{
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Password Reset Controller
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This controller is responsible for handling password reset emails and
|
||||
| includes a trait which assists in sending these notifications from
|
||||
| your application to your users. Feel free to explore this trait.
|
||||
|
|
||||
*/
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Password Reset Controller
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This controller is responsible for handling password reset emails and
|
||||
| includes a trait which assists in sending these notifications from
|
||||
| your application to your users. Feel free to explore this trait.
|
||||
|
|
||||
*/
|
||||
|
||||
use SendsPasswordResetEmails;
|
||||
use SendsPasswordResetEmails;
|
||||
|
||||
/**
|
||||
* Display the form to request a password reset link.
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function showLinkRequestForm()
|
||||
{
|
||||
return view('adminlte::auth.passwords.email');
|
||||
}
|
||||
|
||||
public function sendResetLinkEmail(Request $request)
|
||||
{
|
||||
$this->validateEmail($request);
|
||||
|
||||
// If the account is not active, or doesnt exist, we'll send a fake "sent" message.
|
||||
if (! ($x=$this->broker()->getUser($this->credentials($request))) || (! $x->active))
|
||||
return $this->sendResetLinkResponse($request, Password::RESET_LINK_SENT);
|
||||
|
||||
// We will send the password reset link to this user. Once we have attempted
|
||||
// to send the link, we will examine the response then see the message we
|
||||
// need to show to the user. Finally, we'll send out a proper response.
|
||||
$response = $this->broker()->sendResetLink(
|
||||
$this->credentials($request)
|
||||
);
|
||||
|
||||
return $response == Password::RESET_LINK_SENT
|
||||
? $this->sendResetLinkResponse($request, $response)
|
||||
: $this->sendResetLinkFailedResponse($request, $response);
|
||||
}
|
||||
}
|
||||
|
@ -3,8 +3,6 @@
|
||||
namespace App\Http\Controllers\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Providers\RouteServiceProvider;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Foundation\Auth\AuthenticatesUsers;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
@ -12,35 +10,36 @@ use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class LoginController extends Controller
|
||||
{
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Login Controller
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This controller handles authenticating users for the application and
|
||||
| redirecting them to your home screen. The controller uses a trait
|
||||
| to conveniently provide its functionality to your applications.
|
||||
|
|
||||
*/
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Login Controller
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This controller handles authenticating users for the application and
|
||||
| redirecting them to your home screen. The controller uses a trait
|
||||
| to conveniently provide its functionality to your applications.
|
||||
|
|
||||
*/
|
||||
|
||||
use AuthenticatesUsers;
|
||||
use AuthenticatesUsers;
|
||||
|
||||
/**
|
||||
* Where to redirect users after login.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $redirectTo = RouteServiceProvider::HOME;
|
||||
/**
|
||||
* Where to redirect users after login.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $redirectTo = '/home';
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('guest')->except('logout');
|
||||
}
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('auth')
|
||||
->only('logout');
|
||||
}
|
||||
|
||||
public function login(Request $request)
|
||||
{
|
||||
@ -73,6 +72,7 @@ class LoginController extends Controller
|
||||
if (file_exists('login_note.txt'))
|
||||
$login_note = file_get_contents('login_note.txt');
|
||||
|
||||
return view('adminlte::auth.login')->with('login_note',$login_note);
|
||||
return view('adminlte::auth.login')
|
||||
->with('login_note',$login_note);
|
||||
}
|
||||
}
|
||||
|
@ -1,89 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Providers\RouteServiceProvider;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Auth\RegistersUsers;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
|
||||
class RegisterController extends Controller
|
||||
{
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Register Controller
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This controller handles the registration of new users as well as their
|
||||
| validation and creation. By default this controller uses a trait to
|
||||
| provide this functionality without requiring any additional code.
|
||||
|
|
||||
*/
|
||||
|
||||
use RegistersUsers;
|
||||
|
||||
/**
|
||||
* Where to redirect users after registration.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $redirectTo = RouteServiceProvider::HOME;
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('guest');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a validator for an incoming registration request.
|
||||
*
|
||||
* @param array $data
|
||||
* @return \Illuminate\Contracts\Validation\Validator
|
||||
*/
|
||||
protected function validator(array $data)
|
||||
{
|
||||
return Validator::make($data, [
|
||||
'name' => ['required', 'string', 'min:3', 'max:255'],
|
||||
'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
|
||||
'password' => ['required', 'string', 'min:8', 'confirmed'],
|
||||
'token' => 'required|doorman:email',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new user instance after a valid registration.
|
||||
*
|
||||
* @param array $data
|
||||
* @return User
|
||||
*/
|
||||
protected function create(array $data): User
|
||||
{
|
||||
$fields = [
|
||||
'name' => $data['name'],
|
||||
'email' => $data['email'],
|
||||
'password' => Hash::make($data['password']),
|
||||
];
|
||||
|
||||
if (config('auth.providers.users.field','email') === 'username' && isset($data['username'])) {
|
||||
$fields['username'] = $data['username'];
|
||||
}
|
||||
|
||||
try {
|
||||
Doorman::redeem($data['token'],$data['email']);
|
||||
|
||||
// @todo Want to direct or display an appropriate error message (although the form validation does it anyway).
|
||||
} catch (DoormanException $e) {
|
||||
redirect('/error');
|
||||
abort(403);
|
||||
}
|
||||
|
||||
return User::create($fields);
|
||||
}
|
||||
}
|
@ -3,46 +3,47 @@
|
||||
namespace App\Http\Controllers\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Providers\RouteServiceProvider;
|
||||
use Illuminate\Foundation\Auth\ResetsPasswords;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ResetPasswordController extends Controller
|
||||
{
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Password Reset Controller
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This controller is responsible for handling password reset requests
|
||||
| and uses a simple trait to include this behavior. You're free to
|
||||
| explore this trait and override any methods you wish to tweak.
|
||||
|
|
||||
*/
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Password Reset Controller
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This controller is responsible for handling password reset requests
|
||||
| and uses a simple trait to include this behavior. You're free to
|
||||
| explore this trait and override any methods you wish to tweak.
|
||||
|
|
||||
*/
|
||||
|
||||
use ResetsPasswords;
|
||||
|
||||
/**
|
||||
* Where to redirect users after resetting their password.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $redirectTo = RouteServiceProvider::HOME;
|
||||
use ResetsPasswords;
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
* Where to redirect users after resetting their password.
|
||||
*
|
||||
* @return void
|
||||
* @var string
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('guest');
|
||||
}
|
||||
protected $redirectTo = '/home';
|
||||
|
||||
public function showResetForm(Request $request, $token = null)
|
||||
/**
|
||||
* Display the password reset view for the given token.
|
||||
*
|
||||
* If no token is present, display the link request form.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function showResetForm(Request $request)
|
||||
{
|
||||
return view('adminlte::auth.passwords.reset')->with(
|
||||
['token' => $token, 'email' => $request->email]
|
||||
);
|
||||
$token = $request->route()->parameter('token');
|
||||
|
||||
return view('adminlte::auth.passwords.reset')
|
||||
->with([
|
||||
'token' => $token,
|
||||
'email' => $request->email
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
namespace App\Http\Controllers\Auth;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
@ -10,86 +12,120 @@ use Laravel\Socialite\Facades\Socialite;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Mail\SocialLink;
|
||||
use App\Models\Oauth;
|
||||
use App\Models\AccountOauth;
|
||||
use App\Models\User;
|
||||
use App\Providers\RouteServiceProvider;
|
||||
use App\Models\{ProviderOauth,ProviderToken,User,UserOauth};
|
||||
|
||||
class SocialLoginController extends Controller
|
||||
{
|
||||
public function redirectToProvider($provider)
|
||||
{
|
||||
return Socialite::with($provider)->redirect();
|
||||
return Socialite::with($provider)
|
||||
->redirect();
|
||||
}
|
||||
|
||||
public function handleProviderCallback($provider)
|
||||
{
|
||||
$openiduser = Socialite::with($provider)->user();
|
||||
|
||||
$oo = Oauth::firstOrCreate(['name'=>$provider,'active'=>TRUE]);
|
||||
if (! $openiduser)
|
||||
return redirect('/home')
|
||||
->with('error','No user details obtained.');
|
||||
|
||||
$oo = ProviderOauth::firstOrCreate(['name'=>$provider,'active'=>TRUE]);
|
||||
|
||||
// See if this user has connected and linked previously
|
||||
$aoo = $oo->accounts->where('userid',$openiduser->id);
|
||||
$aoo = $oo->users->where('userid',$openiduser->id);
|
||||
|
||||
if ($aoo->count() == 1) {
|
||||
if ($aoo->count() === 1) {
|
||||
$aoo = $aoo->first();
|
||||
|
||||
if ((is_null($user=$aoo->user) AND (is_null($aoo->account) OR is_null($user=$aoo->account->user))) OR ! $user->active) {
|
||||
if (! $user) {
|
||||
if ((is_null($user=$aoo->user) && (is_null($aoo->account) || is_null($user=$aoo->account->user))) || ! $user->active) {
|
||||
if (! $user)
|
||||
$user = User::where('email',$openiduser->email)->first();
|
||||
}
|
||||
|
||||
if (! $user OR ! $user->active) {
|
||||
return redirect('/login')->with('error','Invalid account, or account inactive, please contact an admin.');
|
||||
}
|
||||
if ((! $user) || (! $user->active))
|
||||
return redirect('/login')
|
||||
->with('error','Invalid account, or account inactive, please contact an admin.');
|
||||
|
||||
return $this->link($provider,$aoo,$user);
|
||||
}
|
||||
|
||||
// All Set to login
|
||||
Auth::login($user,FALSE);
|
||||
Auth::login($user);
|
||||
|
||||
// If there are too many users, then we have a problem
|
||||
} elseif ($aoo->count() > 1) {
|
||||
return redirect('/login')->with('error','Seems you have multiple oauth IDs, please contact an admin.');
|
||||
return redirect('/login')
|
||||
->with('error','Seems you have multiple oauth IDs, please contact an admin.');
|
||||
|
||||
// User is using OAUTH for the first time.
|
||||
} else {
|
||||
$uo = User::active()->where('email',$openiduser->email);
|
||||
|
||||
// See if their is an account with this email address
|
||||
if ($uo->count() == 1) {
|
||||
$aoo = new AccountOauth;
|
||||
if ($uo->count() === 1) {
|
||||
$aoo = new UserOauth;
|
||||
$aoo->userid = $openiduser->id;
|
||||
$aoo->oauth_data = $openiduser->user;
|
||||
$oo->accounts()->save($aoo);
|
||||
|
||||
$oo->users()->save($aoo);
|
||||
|
||||
return $this->link($provider,$aoo,$uo->first());
|
||||
|
||||
// If there are too many users, then we have a problem
|
||||
} elseif ($uo->count() > 1) {
|
||||
return redirect('/login')->with('error','Seems you have multiple accounts, please contact an admin.');
|
||||
return redirect('/login')
|
||||
->with('error','Seems you have multiple accounts, please contact an admin.');
|
||||
|
||||
} else {
|
||||
return redirect('/login')->with('error','Seems you dont have an account with that email, please contact an admin.');
|
||||
return redirect('/login')
|
||||
->with('error','Seems you dont have an account with that email, please contact an admin.');
|
||||
}
|
||||
}
|
||||
|
||||
return redirect()->intended(RouteServiceProvider::HOME);
|
||||
return redirect()
|
||||
->intended('/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('/home')
|
||||
->with('success','Token refreshed.');
|
||||
}
|
||||
|
||||
/**
|
||||
* We have identified the user and oauth, just need them to confirm the link
|
||||
*
|
||||
* @param $provider
|
||||
* @param $provider
|
||||
* @param UserOauth $ao
|
||||
* @param User $uo
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
* @return View
|
||||
*/
|
||||
public function link($provider,AccountOauth $ao,User $uo)
|
||||
public function link($provider,UserOauth $ao,User $uo): View
|
||||
{
|
||||
Mail::to($uo->email)->send(new SocialLink($ao));
|
||||
// @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));
|
||||
|
||||
return view('auth.social_link')
|
||||
return view('theme.backend.adminlte.auth.social_link')
|
||||
->with('oauthid',$ao->id)
|
||||
->with('provider',$provider);
|
||||
}
|
||||
@ -97,23 +133,29 @@ class SocialLoginController extends Controller
|
||||
public function linkcomplete(Request $request,$provider)
|
||||
{
|
||||
// Load our oauth id
|
||||
$aoo = AccountOauth::findOrFail($request->post('oauthid'));
|
||||
$aoo = UserOauth::findOrFail($request->post('oauthid'));
|
||||
|
||||
// Check our email matches
|
||||
if (Arr::get($aoo->oauth_data,'email','invalid') !== $request->post('email'))
|
||||
return redirect('/login')->with('error','Account details didnt match to make link.');
|
||||
return redirect('/login')
|
||||
->with('error','Account details didnt match to make link.');
|
||||
|
||||
// Check our token matches
|
||||
if ($aoo->link_token !== $request->post('token'))
|
||||
return redirect('/login')->with('error','Token details didnt match to make link.');
|
||||
return redirect('/login')
|
||||
->with('error','Token details didnt match to make link.');
|
||||
|
||||
// Load our email.
|
||||
$uo = User::where('email',$request->post('email'))->firstOrFail();
|
||||
|
||||
// Incase we have an existing record with a different oauthid
|
||||
UserOauth::where('user_id',$uo->id)->delete();
|
||||
|
||||
$aoo->user_id = $uo->id;
|
||||
$aoo->save();
|
||||
Auth::login($uo,FALSE);
|
||||
Auth::login($uo);
|
||||
|
||||
return redirect()->intended(RouteServiceProvider::HOME);
|
||||
return redirect()
|
||||
->intended('/home');
|
||||
}
|
||||
}
|
70
app/Http/Controllers/ChargeController.php
Normal file
70
app/Http/Controllers/ChargeController.php
Normal file
@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Requests\ChargeAdd;
|
||||
use App\Models\Charge;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\View\View;
|
||||
|
||||
class ChargeController extends Controller
|
||||
{
|
||||
/**
|
||||
* Add a charge to a service/account
|
||||
*
|
||||
* @param ChargeAdd $request
|
||||
* @return RedirectResponse
|
||||
*/
|
||||
public function addedit(ChargeAdd $request): RedirectResponse
|
||||
{
|
||||
$o = Charge::findOrNew(Arr::get($request->validated(),'id'));
|
||||
|
||||
// Dont update processed charges
|
||||
if ($o->processed)
|
||||
abort(403);
|
||||
|
||||
$o->forceFill(array_merge(Arr::except($request->validated(),['id']),['active'=>TRUE]));
|
||||
$o->save();
|
||||
|
||||
return redirect()
|
||||
->back()
|
||||
->with('success',sprintf('Charge %s #%d',$o->wasRecentlyCreated ? 'Created' : 'Updated',$o->id));
|
||||
}
|
||||
|
||||
public function delete(Charge $o): array
|
||||
{
|
||||
if (Gate::allows('delete',$o)) {
|
||||
$o->active = FALSE;
|
||||
$o->save();
|
||||
|
||||
return ['ok'];
|
||||
|
||||
} else {
|
||||
abort(401,'Not Allowed');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a charge to a service/account
|
||||
*
|
||||
* @param Request $request
|
||||
* @return View
|
||||
*/
|
||||
public function edit(Request $request): View
|
||||
{
|
||||
$o = Charge::where('processed',FALSE)
|
||||
->where('id',$request->id)
|
||||
->firstOrFail();
|
||||
|
||||
if (Gate::allows('update',$o)) {
|
||||
return view('theme.backend.adminlte.charge.widget.addedit')
|
||||
->with('o',$o)
|
||||
->with('so',$o->service);
|
||||
}
|
||||
|
||||
abort(403);
|
||||
}
|
||||
}
|
@ -2,33 +2,93 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Invoice;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
use App\Models\Checkout;
|
||||
use App\Http\Requests\CheckoutAddEdit;
|
||||
use App\Models\{Checkout,Invoice};
|
||||
|
||||
class CheckoutController extends Controller
|
||||
{
|
||||
public function cart_invoice(Request $request,Invoice $o=NULL)
|
||||
/**
|
||||
* Update a checkout details
|
||||
*
|
||||
* @param CheckoutAddEdit $request
|
||||
* @param Checkout $o
|
||||
* @return RedirectResponse
|
||||
*/
|
||||
public function addedit(CheckoutAddEdit $request,Checkout $o): RedirectResponse
|
||||
{
|
||||
if ($o) {
|
||||
$request->session()->put('invoice.cart.'.$o->id,$o->id);
|
||||
foreach ($request->validated() as $key => $item)
|
||||
$o->{$key} = $item;
|
||||
|
||||
$o->active = (bool)$request->validated('active',FALSE);
|
||||
|
||||
try {
|
||||
$o->save();
|
||||
|
||||
} catch (\Exception $e) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withErrors($e->getMessage())->withInput();
|
||||
}
|
||||
|
||||
if (! $request->session()->get('invoice.cart'))
|
||||
return redirect()->to('u/home');
|
||||
|
||||
return View('u.invoice.cart')
|
||||
->with('invoices',Invoice::find(array_values($request->session()->get('invoice.cart'))));
|
||||
return $o->wasRecentlyCreated
|
||||
? redirect()
|
||||
->to('a/checkout/'.$o->id)
|
||||
->with('success','Checkout added')
|
||||
: redirect()
|
||||
->back()
|
||||
->with('success','Checkout saved');
|
||||
}
|
||||
|
||||
public function fee(Request $request,Checkout $o): float
|
||||
/**
|
||||
* Add an invoice to the cart
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Invoice $o
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Foundation\Application
|
||||
* @note The route validates that the user can see the invoice
|
||||
*/
|
||||
public function cart_invoice(Request $request,Invoice $o)
|
||||
{
|
||||
return $o->fee($request->post('total',0));
|
||||
$request->session()->put('invoice.cart.'.$o->id,$o->id);
|
||||
|
||||
return view('theme.backend.adminlte.checkout.cart');
|
||||
}
|
||||
|
||||
public function pay(Request $request,Checkout $o)
|
||||
/**
|
||||
* Remove an item from the cart
|
||||
*
|
||||
* @param Request $request
|
||||
* @return string
|
||||
*/
|
||||
public function cart_remove(Request $request): string
|
||||
{
|
||||
return redirect('pay/paypal/authorise');
|
||||
if ($id=$request->post('id')) {
|
||||
$cart = $request->session()->pull('invoice.cart');
|
||||
unset($cart[$id]);
|
||||
|
||||
$request->session()->put('invoice.cart',$cart);
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
public function fee(Request $request): float
|
||||
{
|
||||
if ((! $request->post('checkout_id') || (! $request->post('total'))))
|
||||
return 0;
|
||||
|
||||
$co = Checkout::findOrFail($request->post('checkout_id'));
|
||||
|
||||
return $co->fee($request->post('total'));
|
||||
}
|
||||
|
||||
public function pay()
|
||||
{
|
||||
// @todo Currently sending all payments to paypal
|
||||
return redirect()
|
||||
->action([PaypalController::class,'authorise']);
|
||||
}
|
||||
}
|
@ -2,12 +2,10 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||
use Illuminate\Routing\Controller as BaseController;
|
||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||
|
||||
class Controller extends BaseController
|
||||
abstract class Controller extends \Illuminate\Routing\Controller
|
||||
{
|
||||
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
|
||||
}
|
||||
use AuthorizesRequests, ValidatesRequests;
|
||||
}
|
@ -4,11 +4,9 @@ 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};
|
||||
|
||||
@ -22,60 +20,19 @@ use App\Models\{Invoice,Service,User};
|
||||
*/
|
||||
class HomeController extends Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('auth');
|
||||
}
|
||||
|
||||
/**
|
||||
* Logged in users home page
|
||||
*
|
||||
* @return Factory|View
|
||||
* @param User $o
|
||||
* @return View
|
||||
*/
|
||||
public function home(User $o): View
|
||||
{
|
||||
// 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]);
|
||||
}
|
||||
if (! $o->exists)
|
||||
$o = Auth::user();
|
||||
|
||||
// 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));
|
||||
return view('theme.backend.adminlte.home')
|
||||
->with(['o'=>$o]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -101,18 +58,7 @@ class HomeController extends Controller
|
||||
abort(404);
|
||||
}
|
||||
|
||||
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]);
|
||||
return $this->invoice($o);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -122,6 +68,7 @@ class HomeController extends Controller
|
||||
* @param Service $o
|
||||
* @param string $status
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @deprecated
|
||||
*/
|
||||
public function service_progress(Service $o,string $status)
|
||||
{
|
||||
|
71
app/Http/Controllers/InvoiceController.php
Normal file
71
app/Http/Controllers/InvoiceController.php
Normal file
@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Clarkeash\Doorman\Exceptions\{ExpiredInviteCode,InvalidInviteCode,NotYourInviteCode};
|
||||
use Clarkeash\Doorman\Facades\Doorman;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\View\View;
|
||||
use Barryvdh\Snappy\Facades\SnappyPdf as PDF;
|
||||
|
||||
use App\Models\{Account,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
|
||||
{
|
||||
/**
|
||||
* Show a list of invoices to apply payments to
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function api_account_invoices(Request $request): \Illuminate\Contracts\View\View
|
||||
{
|
||||
session()->flashInput($request->post('old',[]));
|
||||
|
||||
return view('theme.backend.adminlte.payment.widget.invoices')
|
||||
->with('pid',$request->post('pid'))
|
||||
->with('o',Account::findOrFail($request->post('aid')));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the invoice in PDF format, ready to download
|
||||
*
|
||||
* @param Invoice $o
|
||||
* @return mixed
|
||||
*/
|
||||
public function pdf(Invoice $o)
|
||||
{
|
||||
return PDF::loadView('theme.backend.adminlte.u.invoice.home',['o'=>$o])
|
||||
->stream(sprintf('%s.pdf',$o->sid));
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a specific invoice for the user
|
||||
*
|
||||
* @param Invoice $o
|
||||
* @param string|null $code
|
||||
* @return View
|
||||
*/
|
||||
public function view(Invoice $o,string $code=NULL): View
|
||||
{
|
||||
if ($code) {
|
||||
try {
|
||||
Doorman::redeem($code,$o->account->user->email);
|
||||
|
||||
} catch (ExpiredInviteCode|InvalidInviteCode|NotYourInviteCode $e) {
|
||||
abort(404);
|
||||
}
|
||||
}
|
||||
|
||||
return view('theme.backend.adminlte.invoice.view')
|
||||
->with('o',$o);
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Image;
|
||||
|
||||
class MediaController extends Controller
|
||||
{
|
||||
/**
|
||||
* Create a generic image
|
||||
*
|
||||
* @param $width
|
||||
* @param $height
|
||||
* @param string $color
|
||||
* @return mixed
|
||||
*/
|
||||
public function image($width,$height,$color='#ccc') {
|
||||
$io = Image::canvas($width,$height,$color);
|
||||
$io->text(sprintf('IMAGE-%sx%s',$width,$height),$width/2,$height/2,function($font) {
|
||||
$font->file(5);
|
||||
$font->align('center');
|
||||
$font->valign('middle');
|
||||
});
|
||||
|
||||
return $io->response();
|
||||
}
|
||||
}
|
@ -3,63 +3,49 @@
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Igaster\LaravelTheme\Facades\Theme;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
use App\Mail\OrderRequest;
|
||||
use App\Models\{Account,Product,Service,User};
|
||||
use App\Models\{Account,Product,Rtm,Service,User};
|
||||
|
||||
class OrderController extends Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('auth');
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
return view('order');
|
||||
}
|
||||
|
||||
public function product_order(Product $o)
|
||||
{
|
||||
Theme::set('metronic-fe');
|
||||
|
||||
return view('widgets.product_order',['o'=>$o]);
|
||||
}
|
||||
|
||||
public function product_info(Product $o)
|
||||
{
|
||||
Theme::set('metronic-fe');
|
||||
|
||||
return view('widgets.product_description',['o'=>$o]);
|
||||
}
|
||||
|
||||
// @todo To check
|
||||
public function submit(Request $request)
|
||||
{
|
||||
Validator::make($request->all(),['product_id'=>'required|exists:ab_product,id'])
|
||||
Validator::make($request->all(),
|
||||
[
|
||||
'product_id'=>'required|exists:products,id'
|
||||
]
|
||||
)
|
||||
// Reseller
|
||||
->sometimes('account_id','required|email',function($input) use ($request) {
|
||||
return is_null($input->account_id) AND is_null($input->order_email_manual);
|
||||
})
|
||||
->sometimes(
|
||||
'account_id',
|
||||
'required|email',
|
||||
fn($input)=>is_null($input->account_id) && is_null($input->order_email_manual)
|
||||
)
|
||||
// Un-Authed User
|
||||
->sometimes('order_email_manual','required|email|unique:users,email,NULL,id',function($input) use ($request) {
|
||||
return (is_null($input->order_email_manual) AND ! isset($input->account_id)) OR $input->order_email_manual;
|
||||
})
|
||||
->sometimes(
|
||||
'order_email_manual',
|
||||
'required|email|unique:users,email,NULL,id',
|
||||
fn($input)=>(is_null($input->order_email_manual) && (! isset($input->account_id))) || $input->order_email_manual
|
||||
)
|
||||
// Authed User
|
||||
->sometimes('account_id','required|email',function($input) use ($request) {
|
||||
return is_null($input->account_id) AND ! isset($input->order_email_manual);
|
||||
})
|
||||
->sometimes(
|
||||
'account_id',
|
||||
'required|email',
|
||||
fn($input)=>is_null($input->account_id) && (! isset($input->order_email_manual))
|
||||
)
|
||||
->validate();
|
||||
|
||||
// Check the plugin details.
|
||||
$po = Product::findOrFail($request->input('product_id'));
|
||||
|
||||
// Check we have the custom attributes for the product
|
||||
$options = $po->orderValidation($request);
|
||||
$order = $po->orderValidation($request);
|
||||
|
||||
if ($request->input('order_email_manual')) {
|
||||
$uo = User::firstOrNew(['email'=>$request->input('order_email_manual')]);
|
||||
@ -67,12 +53,13 @@ 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();
|
||||
}
|
||||
@ -81,12 +68,9 @@ class OrderController extends Controller
|
||||
// If we have a new account.
|
||||
if (is_null($request->input('account_id'))) {
|
||||
$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->language_id = config('SITE')->language_id; // @todo This might be wrong
|
||||
$ao->currency_id = config('SITE')->currency_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->active = 1;
|
||||
$uo->accounts()->save($ao);
|
||||
|
||||
@ -97,28 +81,33 @@ class OrderController extends Controller
|
||||
$so = new Service;
|
||||
|
||||
// @todo Make this automatic
|
||||
$so->site_id = config('SITE')->site_id;
|
||||
$so->product_id = $request->input('product_id');
|
||||
$so->site_id = config('site')->site_id;
|
||||
$so->product_id = $po->id;
|
||||
$so->order_status = 'ORDER-SUBMIT';
|
||||
$so->orderby_id = Auth::id();
|
||||
$so->model = get_class($options);
|
||||
$so->ordered_by = Auth::id();
|
||||
$so->active = FALSE;
|
||||
$so->model = $order ? get_class($order) : NULL;
|
||||
$so->recur_schedule = $po->billing_interval;
|
||||
|
||||
if ($options->order_info) {
|
||||
$so->order_info = $options->order_info;
|
||||
if ($order && $order->order_info) {
|
||||
$so->order_info = $order->order_info;
|
||||
|
||||
unset($options->order_info);
|
||||
unset($order->order_info);
|
||||
}
|
||||
|
||||
$so = $ao->services()->save($so);
|
||||
|
||||
if ($options instanceOf Model) {
|
||||
$options->service_id = $so->id;
|
||||
$options->save();
|
||||
if ($order instanceOf Model) {
|
||||
$order->service_id = $so->id;
|
||||
$order->save();
|
||||
}
|
||||
|
||||
Mail::to('help@graytech.net.au')
|
||||
->queue((new OrderRequest($so,$request->input('options.notes')))->onQueue('email')); //@todo Get email from DB.
|
||||
$ro = Rtm::where('parent_id',NULL)->sole();
|
||||
|
||||
return view('order_received',['o'=>$so]);
|
||||
Mail::to(config('osb.ticket_admin'))
|
||||
->queue((new OrderRequest($so,$request->input('options.notes') ?: ''))->onQueue('email')); //@todo Get email from DB.
|
||||
|
||||
return view('theme.frontend.metronic.order_received')
|
||||
->with('o',$so);
|
||||
}
|
||||
}
|
||||
}
|
73
app/Http/Controllers/PaymentController.php
Normal file
73
app/Http/Controllers/PaymentController.php
Normal file
@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
use App\Http\Requests\PaymentAddEdit;
|
||||
use App\Models\{Payment,PaymentItem};
|
||||
|
||||
class PaymentController extends Controller
|
||||
{
|
||||
/**
|
||||
* Record payments on an account.
|
||||
*
|
||||
* @param PaymentAddEdit $request
|
||||
* @param Payment $o
|
||||
* @return RedirectResponse
|
||||
*/
|
||||
public function addedit(PaymentAddEdit $request,Payment $o): RedirectResponse
|
||||
{
|
||||
foreach (Arr::except($request->validated(),'invoices') as $k=>$v)
|
||||
$o->{$k} = $v;
|
||||
|
||||
foreach ($request->validated('invoices',[]) as $id => $amount) {
|
||||
// See if we already have a payment item that we need to update
|
||||
$items = $o->items
|
||||
->filter(fn($item)=>$item->invoice_id == $id);
|
||||
|
||||
if ($items->count() === 1) {
|
||||
$oo = $items->pop();
|
||||
|
||||
if ($amount == 0) {
|
||||
$oo->delete();
|
||||
continue;
|
||||
}
|
||||
|
||||
} else {
|
||||
$oo = new PaymentItem;
|
||||
$oo->invoice_id = $id;
|
||||
}
|
||||
|
||||
$oo->amount = ($oo->invoice->due >= 0) && ($oo->invoice->due-$amount >= 0)
|
||||
? $amount
|
||||
: 0;
|
||||
|
||||
// If the amount is empty, ignore it.
|
||||
if (! $oo->amount)
|
||||
continue;
|
||||
|
||||
$oo->site_id = config('site')->site_id;
|
||||
$oo->active = TRUE;
|
||||
$o->items->push($oo);
|
||||
}
|
||||
|
||||
try {
|
||||
$o->pushNew();
|
||||
|
||||
} catch (\Exception $e) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withErrors($e->getMessage())->withInput();
|
||||
}
|
||||
|
||||
return $o->wasRecentlyCreated
|
||||
? redirect()
|
||||
->to('r/payment/'.$o->id)
|
||||
->with('success','Payment added')
|
||||
: redirect()
|
||||
->back()
|
||||
->with('success','Payment saved');
|
||||
}
|
||||
}
|
@ -2,8 +2,8 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\PaymentItem;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use PayPalCheckoutSdk\Core\PayPalHttpClient;
|
||||
@ -13,14 +13,13 @@ use PayPalCheckoutSdk\Orders\OrdersCreateRequest;
|
||||
use PayPalCheckoutSdk\Orders\OrdersCaptureRequest;
|
||||
use PayPalHttp\HttpException;
|
||||
|
||||
use App\Models\Checkout;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
use App\Models\{Checkout,Invoice,Payment,PaymentItem};
|
||||
|
||||
class PaypalController extends Controller
|
||||
{
|
||||
private $client;
|
||||
private $o = NULL;
|
||||
private PayPalHttpClient $client;
|
||||
|
||||
protected const cart_url = 'u/checkout/cart';
|
||||
|
||||
// Create a new instance with our paypal credentials
|
||||
public function __construct()
|
||||
@ -31,27 +30,30 @@ class PaypalController extends Controller
|
||||
$environment = new ProductionEnvironment(config('paypal.live_client_id'),config('paypal.live_secret'));
|
||||
|
||||
$this->client = new PayPalHttpClient($environment);
|
||||
$this->o = Checkout::where('name','paypal')->firstOrFail();
|
||||
}
|
||||
|
||||
public function cancel(Request $request)
|
||||
public function cancel()
|
||||
{
|
||||
return redirect()->to('u/invoice/cart');
|
||||
return redirect()
|
||||
->to(self::cart_url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Authorize a paypal payment, and redirect the user to pay.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @return RedirectResponse
|
||||
* @throws \PayPalHttp\IOException
|
||||
*/
|
||||
public function authorise(Request $request)
|
||||
public function authorise()
|
||||
{
|
||||
$co = Checkout::where('name','ilike','paypal')->firstOrFail();
|
||||
|
||||
$currency = 'AUD'; // @todo TO determine from DB.;
|
||||
$cart = $request->session()->get('invoice.cart');
|
||||
$cart = request()->session()->get('invoice.cart');
|
||||
|
||||
if (! $cart)
|
||||
return redirect()->to('u/home');
|
||||
return redirect()
|
||||
->to('u/home');
|
||||
|
||||
$invoices = Invoice::find($cart);
|
||||
|
||||
@ -61,7 +63,7 @@ class PaypalController extends Controller
|
||||
// Paypal Purchase Units
|
||||
$items = collect();
|
||||
foreach ($invoices as $io) {
|
||||
$fee = $this->o->fee($io->due,count($cart));
|
||||
$fee = $co->fee($io->due,count($cart));
|
||||
$total = round($io->due+$fee,2);
|
||||
|
||||
$items->push([
|
||||
@ -100,7 +102,7 @@ class PaypalController extends Controller
|
||||
|
||||
$data->put('application_context',[
|
||||
'return_url' => url('pay/paypal/capture'),
|
||||
'cancel_url' => url('u/invoice/cart'),
|
||||
'cancel_url' => url(self::cart_url),
|
||||
]);
|
||||
|
||||
$paypal->body = $data->toArray();
|
||||
@ -111,12 +113,16 @@ class PaypalController extends Controller
|
||||
} catch (HttpException $e) {
|
||||
Log::error('Paypal Exception',['request'=>$paypal,'response'=>$e->getMessage()]);
|
||||
|
||||
return redirect()->to('u/invoice/cart')->withErrors('Paypal Exception: '.$e->getCode());
|
||||
return redirect()
|
||||
->to(self::cart_url)
|
||||
->withErrors('Paypal Exception: '.$e->getCode());
|
||||
|
||||
} catch (\HttpException $e) {
|
||||
Log::error('HTTP Exception',['request'=>$request,'response'=>$e->getMessage()]);
|
||||
Log::error('HTTP Exception',['request'=>$this->client,'response'=>$e->getMessage()]);
|
||||
|
||||
return redirect()->to('u/invoice/cart')->withErrors('HTTP Exception: '.$e->getCode());
|
||||
return redirect()
|
||||
->to(self::cart_url)
|
||||
->withErrors('HTTP Exception: '.$e->getCode());
|
||||
}
|
||||
|
||||
// Get the approval link
|
||||
@ -128,18 +134,21 @@ class PaypalController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
if ($redirect_url) {
|
||||
return redirect()->away($redirect_url);
|
||||
}
|
||||
if ($redirect_url)
|
||||
return redirect()
|
||||
->away($redirect_url);
|
||||
|
||||
return redirect()->to('u/invoice/cart')->withErrors('An error occurred with Paypal?');
|
||||
return redirect()
|
||||
->to(self::cart_url)
|
||||
->withErrors('An error occurred with Paypal?');
|
||||
}
|
||||
|
||||
/**
|
||||
* Capture a paypal payment
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @return RedirectResponse
|
||||
* @throws \PayPalHttp\IOException
|
||||
*/
|
||||
public function capture(Request $request)
|
||||
{
|
||||
@ -179,27 +188,37 @@ class PaypalController extends Controller
|
||||
if ($redirect_url) {
|
||||
Log::error('Paypal Capture: Redirect back to Paypal.');
|
||||
|
||||
return redirect()->away($redirect_url);
|
||||
return redirect()
|
||||
->away($redirect_url);
|
||||
}
|
||||
|
||||
return redirect()->to('u/invoice/cart')->withErrors('An error occurred with Paypal?');
|
||||
return redirect()
|
||||
->to(self::cart_url)
|
||||
->withErrors('An error occurred with Paypal?');
|
||||
|
||||
} catch (\HttpException $e) {
|
||||
Log::error('HTTP Exception',['request'=>$paypal,'response'=>$e->getMessage()]);
|
||||
|
||||
return redirect()->to('u/invoice/cart')->withErrors('HTTP Exception: '.$e->getCode());
|
||||
return redirect()
|
||||
->to(self::cart_url)
|
||||
->withErrors('HTTP Exception: '.$e->getCode());
|
||||
}
|
||||
|
||||
if (! $response OR ! $response->result->purchase_units) {
|
||||
if ((! $response) || (! $response->result->purchase_units)) {
|
||||
Log::error('Paypal Capture: No Purchase Units?');
|
||||
|
||||
return redirect()->to('u/invoice/cart')->withErrors('Paypal Exception: NPU');
|
||||
return redirect()
|
||||
->to(self::cart_url)
|
||||
->withErrors('Paypal Exception: NPU');
|
||||
}
|
||||
|
||||
$co = Checkout::where('name','ilike','paypal')->firstOrFail();
|
||||
|
||||
// If we got here, we got a payment
|
||||
foreach ($response->result->purchase_units as $pu) {
|
||||
foreach ($pu->payments->captures as $cap) {
|
||||
$po = new Payment;
|
||||
$po->active = TRUE;
|
||||
|
||||
switch ($cap->status) {
|
||||
case 'PENDING':
|
||||
@ -217,8 +236,8 @@ class PaypalController extends Controller
|
||||
break;
|
||||
}
|
||||
|
||||
$po->date_payment = Carbon::parse($cap->create_time);
|
||||
$po->checkout_id = $this->o->id;
|
||||
$po->paid_at = Carbon::parse($cap->create_time);
|
||||
$po->checkout_id = $co->id;
|
||||
$po->checkout_data = $cap->id;
|
||||
|
||||
list($account_id,$fee) = explode(':',$cap->custom_id);
|
||||
@ -229,7 +248,7 @@ class PaypalController extends Controller
|
||||
$pio = new PaymentItem;
|
||||
$pio->site_id = 1; // @todo To implement
|
||||
$pio->invoice_id = $cap->invoice_id;
|
||||
$pio->alloc_amt = $cap->amount->value-$po->fees_amt;
|
||||
$pio->amount = $cap->amount->value-$po->fees_amt;
|
||||
|
||||
$po->items->push($pio);
|
||||
|
||||
@ -245,7 +264,11 @@ class PaypalController extends Controller
|
||||
}
|
||||
|
||||
$request->session()->forget('invoice.cart');
|
||||
|
||||
Log::info('Paypal Payment Recorded',['po'=>$po->id]);
|
||||
return redirect()->to('u/home')->with('success','Payment recorded thank you.');
|
||||
|
||||
return redirect()
|
||||
->to('u/home')
|
||||
->with('success','Payment recorded thank you.');
|
||||
}
|
||||
}
|
127
app/Http/Controllers/ProductController.php
Normal file
127
app/Http/Controllers/ProductController.php
Normal file
@ -0,0 +1,127 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Arr;
|
||||
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_supplied_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(fn($item)=>['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(fn($item)=>['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(fn($item)=>['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(fn($item)=>['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(fn($item)=>['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(fn($item)=>['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);
|
||||
}
|
||||
}
|
||||
|
||||
public function addedit(ProductAddEdit $request,Product $o)
|
||||
{
|
||||
foreach (Arr::except($request->validated(),['translate','accounting','pricing','active']) as $key => $item)
|
||||
$o->{$key} = $item;
|
||||
|
||||
$o->active = (bool)$request->active;
|
||||
|
||||
// Trim down the pricing array, remove null values
|
||||
$o->pricing = collect($request->validated('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->validated('translate',[]) as $key => $item)
|
||||
$oo->{$key} = $item;
|
||||
|
||||
$o->translate()->save($oo);
|
||||
|
||||
foreach ($request->validated('accounting',[]) as $k=>$v) {
|
||||
$o->providers()->syncWithoutDetaching([
|
||||
$k => [
|
||||
'ref' => $v,
|
||||
'site_id'=>$o->site_id,
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
return redirect()
|
||||
->back()
|
||||
->with('success','Product saved');
|
||||
}
|
||||
}
|
@ -2,27 +2,18 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Auth;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
use App\Models\Account;
|
||||
|
||||
class ResellerServicesController extends Controller
|
||||
{
|
||||
public function accounts()
|
||||
public function services(Request $request,Account $o)
|
||||
{
|
||||
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()];
|
||||
return $o->services
|
||||
->filter(function($item) use ($request) {
|
||||
return $item->active || ($item->id == $request->include);
|
||||
});
|
||||
}
|
||||
}
|
@ -3,10 +3,11 @@
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
use App\Models\{Account,Invoice,Service,Service\Adsl,User};
|
||||
use App\Models\{Account,Invoice,Payment,Service,User};
|
||||
|
||||
class SearchController extends Controller
|
||||
{
|
||||
@ -14,73 +15,87 @@ class SearchController extends Controller
|
||||
* Search from the Application Dashboard.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
* @return Collection
|
||||
*/
|
||||
public function search(Request $request)
|
||||
public function search(Request $request): Collection
|
||||
{
|
||||
$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 [];
|
||||
return $result;
|
||||
|
||||
$result = collect();
|
||||
$accounts = ($x=Auth::user()->all_accounts())->pluck('id');
|
||||
$users = $x->transform(function($item) { return $item->user;});
|
||||
$account_ids = ($x=Auth::user()->accounts_all)->pluck('id');
|
||||
$user_ids = $x->pluck('user_id')->unique();
|
||||
|
||||
# Look for User
|
||||
// Look for User
|
||||
foreach (User::Search($request->input('term'))
|
||||
->whereIN('id',$users->pluck('id'))
|
||||
->whereIN('id',$user_ids)
|
||||
->orderBy('lastname')
|
||||
->orderBy('firstname')
|
||||
->limit(10)->get() as $o)
|
||||
{
|
||||
$result->push(['name'=>sprintf('%s %s',$o->aid,$o->name),'value'=>'/u/home/'.$o->id,'category'=>'Users']);
|
||||
$result->push(['name'=>sprintf('%s (%s) - %s',$o->name,$o->lid,$o->email),'value'=>'/u/home/'.$o->id,'category'=>'Users']);
|
||||
}
|
||||
|
||||
# Look for Account
|
||||
// Look for User by their Supplier ID with some suppliers
|
||||
if (is_numeric($request->input('term')))
|
||||
foreach (Account::select(['user_id','suppliers.name AS supplier_name','account_supplier.supplier_ref AS pivot_id'])
|
||||
->join('account_supplier',['account_supplier.account_id'=>'accounts.id'])
|
||||
->join('suppliers',['suppliers.id'=>'account_supplier.supplier_id'])
|
||||
->whereIN('accounts.id',$account_ids)
|
||||
->where('account_supplier.supplier_ref','like','%'.$request->input('term').'%')
|
||||
->orderBy('company')
|
||||
->limit(10)->get() as $o)
|
||||
{
|
||||
$result->push(['name'=>sprintf('%s (%s:%s)',$o->company,$o->supplier_name,$o->supplier_ref),'value'=>'/u/home/'.$o->user_id,'category'=>'Suppliers']);
|
||||
}
|
||||
|
||||
// Look for Account
|
||||
foreach (Account::Search($request->input('term'))
|
||||
->whereIN('user_id',$users->pluck('id'))
|
||||
->orderBy('company')
|
||||
->limit(10)->get() as $o)
|
||||
->whereIN('id',$account_ids)
|
||||
->orderBy('company')
|
||||
->limit(10)->get() as $o)
|
||||
{
|
||||
$result->push(['name'=>sprintf('%s %s',$o->aid,$o->company),'value'=>'/u/home/'.$o->user_id,'category'=>'Accounts']);
|
||||
$result->push(['name'=>sprintf('%s (%s)',$o->name,$o->lid),'value'=>'/u/home/'.$o->user_id,'category'=>'Accounts']);
|
||||
}
|
||||
|
||||
# Look for a Service
|
||||
// Look for a Service
|
||||
foreach (Service::Search($request->input('term'))
|
||||
->whereIN('account_id',$accounts)
|
||||
->orderBy('id')
|
||||
->limit(10)->get() as $o)
|
||||
->whereIN('account_id',$account_ids)
|
||||
->orderBy('id')
|
||||
->limit(20)
|
||||
->with(['product'])
|
||||
->get() as $o)
|
||||
{
|
||||
$result->push(['name'=>sprintf('%s (%s)',$o->name,$o->sid),'value'=>'/u/service/'.$o->id,'category'=>'Services']);
|
||||
$result->push(['name'=>sprintf('%s (%s) %s',$o->name,$o->lid,$o->active ? '' : '<small>INACT</small>'),'value'=>'/u/service/'.$o->id,'category'=>$o->product->category_name]);
|
||||
}
|
||||
|
||||
# Look for an Invoice
|
||||
// Look for an Invoice
|
||||
foreach (Invoice::Search($request->input('term'))
|
||||
->whereIN('account_id',$accounts)
|
||||
->orderBy('id')
|
||||
->limit(10)->get() as $o)
|
||||
->whereIN('account_id',$account_ids)
|
||||
->orderBy('id')
|
||||
->limit(10)->get() as $o)
|
||||
{
|
||||
$result->push(['name'=>sprintf('%s: %s',$o->sid,$o->account->name),'value'=>'/u/invoice/'.$o->id,'category'=>'Invoices']);
|
||||
$result->push(['name'=>sprintf('%s: %s',$o->lid,$o->account->name),'value'=>'/u/invoice/'.$o->id,'category'=>'Invoices']);
|
||||
}
|
||||
|
||||
# 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']);
|
||||
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'=>'/r/payment/addedit/'.$o->id,'category'=>'Payments']);
|
||||
}
|
||||
}
|
||||
|
||||
# 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;
|
||||
return $result
|
||||
->sortBy(fn($item)=>$item['category'].$item['name'])
|
||||
->values();
|
||||
}
|
||||
}
|
@ -2,146 +2,479 @@
|
||||
|
||||
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\Rule;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Illuminate\View\View;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
|
||||
use App\Models\Service;
|
||||
use App\Http\Requests\{ServiceCancel,ServiceChange,ServiceChangeRequest};
|
||||
use App\Mail\{CancelRequest,ChangeRequest};
|
||||
use App\Models\{Charge,Invoice,Product,Service};
|
||||
|
||||
class ServiceController extends Controller
|
||||
{
|
||||
/* SERVICE WORKFLOW METHODS */
|
||||
|
||||
/**
|
||||
* Edit a domain service details
|
||||
* Cancel a request to cancel a service
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Service $o
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @return bool
|
||||
*/
|
||||
public function domain_edit(Request $request,Service $o)
|
||||
private function action_cancel_cancel(Service $o): bool
|
||||
{
|
||||
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->order_info->put('cancel_cancel',Carbon::now()->format('Y-m-d H:i:s'));
|
||||
$o->order_status = 'ACTIVE';
|
||||
$o->stop_at = NULL;
|
||||
|
||||
$o->type->forceFill($validation['service'])->save();
|
||||
return $o->save();
|
||||
}
|
||||
|
||||
return redirect()->back()->with('success','Record updated.');
|
||||
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('theme.backend.adminlte.service.change_pending')
|
||||
->with('breadcrumb',collect()->merge($o->account->breadcrumb))
|
||||
->with('o',$o)
|
||||
->with('np',$np);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a request to cancel a service
|
||||
*
|
||||
* @param ServiceCancel $request
|
||||
* @param Service $o
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|RedirectResponse|\Illuminate\Routing\Redirector
|
||||
*/
|
||||
public function cancel_request(ServiceCancel $request,Service $o)
|
||||
{
|
||||
if (! $o->order_info)
|
||||
$o->order_info = collect();
|
||||
|
||||
$o->stop_at = $request->stop_at;
|
||||
$o->order_info->put('cancel_note',$request->validated('notes'));
|
||||
|
||||
if ($request->validated('extra_charges'))
|
||||
$o->order_info->put('cancel_extra_charges_accepted',$request->extra_charges_amount);
|
||||
|
||||
$o->order_status = 'CANCEL-REQUEST';
|
||||
$o->save();
|
||||
|
||||
Mail::to(config('osb.ticket_admin'))
|
||||
->queue((new CancelRequest($o,$request->notes))->onQueue('email'));
|
||||
|
||||
return redirect('u/service/'.$o->id)
|
||||
->with('success','Cancellation lodged');
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 ServiceChange $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(ServiceChange $request,Service $o)
|
||||
{
|
||||
$o->changes()->attach([$o->id=>[
|
||||
'site_id'=> $o->site_id,
|
||||
'ordered_by' => Auth::id(),
|
||||
'ordered_at' => Carbon::now(),
|
||||
'effective_at' => $request->validated('change_date'),
|
||||
'product_id' => $request->validated('product_id'),
|
||||
'notes' => $request->validated('notes'),
|
||||
'active' => TRUE,
|
||||
'complete' => FALSE,
|
||||
]]);
|
||||
|
||||
$o->order_status = 'CHANGE-REQUEST';
|
||||
$o->save();
|
||||
|
||||
Mail::to(config('osb.ticket_admin'))
|
||||
->queue((new ChangeRequest($o,$request->validated('notes')))->onQueue('email'));
|
||||
|
||||
return redirect('u/service/'.$o->id)
|
||||
->with('success','Upgrade requested');
|
||||
}
|
||||
|
||||
/**
|
||||
* 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_domains.*')
|
||||
->join('ab_service',['ab_service.id'=>'service_domains.service_id'])
|
||||
$o = Service\Domain::ServiceActive()
|
||||
->AccountUserAuthorised('services')
|
||||
->select('service_domain.*')
|
||||
->join('services',['services.id'=>'service_domain.service_id'])
|
||||
->with(['service.account','registrar'])
|
||||
->get();
|
||||
|
||||
return view('r.service.domain.list')
|
||||
return view('theme.backend.adminlte.service.domain.list')
|
||||
->with('o',$o);
|
||||
}
|
||||
|
||||
public function email_list(): View
|
||||
{
|
||||
$o = Service\Email::ServiceActive()
|
||||
->AccountUserAuthorised('services')
|
||||
->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('theme.backend.adminlte.service.email.list')
|
||||
->with('o',$o);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a service
|
||||
* Return details on the users service
|
||||
*
|
||||
* @param Service $o
|
||||
* @return View
|
||||
*/
|
||||
public function home(Service $o): View
|
||||
{
|
||||
return view('theme.backend.adminlte.service.home')
|
||||
->with('breadcrumb',collect()->merge($o->account->breadcrumb))
|
||||
->with('o',$o);
|
||||
}
|
||||
|
||||
public function hosting_list(): View
|
||||
{
|
||||
$o = Service\Host::ServiceActive()
|
||||
->AccountUserAuthorised('services')
|
||||
->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('theme.backend.adminlte.service.hosting.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->invoiced_items
|
||||
->filter(fn($item)=>($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->diffInDays($iio->stop_at)/$iio->start_at->diffInDays($iio->stop_at);
|
||||
$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->diffInDays($iio->stop_at)/$iio->start_at->diffInDays($iio->stop_at);
|
||||
$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
|
||||
*
|
||||
* @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|\Illuminate\Http\RedirectResponse
|
||||
* @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('theme.backend.adminlte.service.change_charge')
|
||||
->with('charges',$this->service_change_charges($request,$o));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update details about a service
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Service $o
|
||||
* @return RedirectResponse
|
||||
* @throws ValidationException
|
||||
*/
|
||||
public function update(Request $request,Service $o)
|
||||
{
|
||||
switch ($o->order_status) {
|
||||
case 'CANCEL-REQUEST':
|
||||
if ($request->post()) {
|
||||
if (! $request->post('date_end'))
|
||||
return redirect()->back()->withErrors('Cancellation Date not provided');
|
||||
Session::put('service_update',true);
|
||||
|
||||
$o->date_end = $request->post('date_end');
|
||||
// We dynamically create our validation
|
||||
$validator = Validator::make(
|
||||
$request->post(),
|
||||
collect($o->type->validation())
|
||||
->keys()
|
||||
->map(fn($item)=>sprintf('%s.%s',$o->product->category,$item))
|
||||
->combine(array_values($o->type->validation()))
|
||||
->map(fn($item)=>is_string($item)
|
||||
? preg_replace('/^exclude_without:/',sprintf('exclude_without:%s.',$o->product->category),$item)
|
||||
: $item)
|
||||
->merge(
|
||||
[
|
||||
'external_billing' => 'nullable|in:on',
|
||||
'suspend_billing' => 'nullable|in:on',
|
||||
'recur_schedule' => ['required',Rule::in(collect(Invoice::billing_periods)->keys())],
|
||||
'invoice_next_at' => 'nullable|date',
|
||||
'price' => 'nullable|numeric',
|
||||
$o->product->category => 'array|min:1',
|
||||
]
|
||||
)
|
||||
->toArray()
|
||||
);
|
||||
|
||||
foreach (['cancel_notes'] as $key) {
|
||||
if ($request->post($key))
|
||||
$o->setOrderInfo($key,$request->post($key));
|
||||
}
|
||||
|
||||
$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');
|
||||
if ($validator->fails()) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withErrors($validator)
|
||||
->withInput();
|
||||
}
|
||||
}
|
||||
|
||||
private function update_order_status(Service $o)
|
||||
{
|
||||
return View('r.service.order.sent',['o'=>$o]);
|
||||
}
|
||||
$validated = collect($validator->validated());
|
||||
|
||||
private function update_request_cancel(Service $o)
|
||||
{
|
||||
return View('u.service.order.cancel',['o'=>$o]);
|
||||
}
|
||||
// Store our service type values
|
||||
$o->type->forceFill($validated->get($o->product->category));
|
||||
|
||||
private function update_provision_planned(Service $o)
|
||||
{
|
||||
return View('r.service.order.provision_plan',['o'=>$o]);
|
||||
// Some special handling
|
||||
switch ($o->product->category) {
|
||||
case 'broadband':
|
||||
// If pppoe is not set, then we dont need username/password
|
||||
$o->type->pppoe = ($x=data_get($validated,$o->product->category.'.pppoe',FALSE));
|
||||
|
||||
if (! $x) {
|
||||
$o->type->service_username = NULL;
|
||||
$o->type->service_password = NULL;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
$o->type->save();
|
||||
|
||||
if ($validated->has('invoice_next_at'))
|
||||
$o->invoice_next_at = $validated?->get('invoice_next_at');
|
||||
|
||||
if ($validated->has('recur_schedule'))
|
||||
$o->recur_schedule = $validated->get('recur_schedule');
|
||||
|
||||
$o->suspend_billing = ($validated->get('suspend_billing') == 'on');
|
||||
$o->external_billing = ($validated->get('external_billing') == 'on');
|
||||
$o->price = $validated->get('price');
|
||||
|
||||
// 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 ($validated->has('start_at'))
|
||||
$o->start_at = $validated->get('start_at');
|
||||
|
||||
else {
|
||||
// For broadband, start_at is connect_at in the type record
|
||||
switch ($o->product->category) {
|
||||
case 'broadband':
|
||||
$o->start_at = $o->type->connect_at;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$o->save();
|
||||
|
||||
return redirect()
|
||||
->back()
|
||||
->with('success','Record Updated');
|
||||
}
|
||||
}
|
149
app/Http/Controllers/SupplierController.php
Normal file
149
app/Http/Controllers/SupplierController.php
Normal file
@ -0,0 +1,149 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
use App\Http\Requests\{SupplierAddEdit,SupplierProductAddEdit};
|
||||
use App\Jobs\ImportCosts;
|
||||
use App\Models\{Supplier,SupplierDetail};
|
||||
|
||||
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)
|
||||
{
|
||||
foreach (Arr::except($request->validated(),['supplier_details','api_key','api_secret','submit']) as $key => $item)
|
||||
$o->{$key} = $item;
|
||||
|
||||
$o->active = (bool)$request->validated('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');
|
||||
}
|
||||
|
||||
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');
|
||||
}
|
||||
|
||||
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 (Arr::only($request->validated(),[
|
||||
'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 (Arr::only($request->validated(),['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');
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.products.services']);
|
||||
|
||||
return view('theme.backend.adminlte.supplier.product.widget.'.$type)
|
||||
->with('o',$id ? $o : NULL)
|
||||
->withErrors($request->errors);
|
||||
}
|
||||
}
|
@ -1,102 +0,0 @@
|
||||
<?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)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\User;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\{Account,Invoice};
|
||||
|
||||
class AccountController extends Controller
|
||||
{
|
||||
/**
|
||||
* Show the users next invoice
|
||||
*/
|
||||
public function view_invoice_next(Account $o)
|
||||
{
|
||||
$io = new Invoice;
|
||||
$io->account = $o;
|
||||
|
||||
// Get the account services
|
||||
$s = $o->services(TRUE)
|
||||
->with(['invoice_items','charges'])
|
||||
->get()
|
||||
->filter(function($item) {
|
||||
return ! $item->suspend_billing AND ! $item->external_billing;
|
||||
});
|
||||
|
||||
// Get our invoice due date for this invoice
|
||||
$io->due_date = $s->min(function($item) { return $item->invoice_next; });
|
||||
|
||||
// @todo The days in advance is an application parameter
|
||||
$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_date)+1+7;
|
||||
foreach ($s as $so)
|
||||
{
|
||||
if ($so->isInvoiceDueSoon($days))
|
||||
foreach ($so->next_invoice_items() as $o)
|
||||
$io->items->push($o);
|
||||
}
|
||||
|
||||
return View('u.invoice.home',['o'=>$io]);
|
||||
}
|
||||
}
|
74
app/Http/Controllers/UserController.php
Normal file
74
app/Http/Controllers/UserController.php
Normal file
@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
|
||||
use App\Http\Requests\{AccountSupplierAdd,UserEdit};
|
||||
use App\Models\{Account,Supplier,User};
|
||||
|
||||
class UserController extends Controller
|
||||
{
|
||||
/**
|
||||
* Update user settings
|
||||
*
|
||||
* @param UserEdit $request
|
||||
* @param User $o
|
||||
* @return RedirectResponse
|
||||
*/
|
||||
public function edit(UserEdit $request,User $o): RedirectResponse
|
||||
{
|
||||
foreach (Arr::except($request->validated(),['password']) as $field => $value)
|
||||
$o->{$field} = $value;
|
||||
|
||||
if ($x=$request->validated('password'))
|
||||
$o->password = Hash::make($x);
|
||||
|
||||
return redirect()
|
||||
->back()
|
||||
->with('success',($o->isDirty() && $o->save()) ? 'User Updated' : 'No Changes');
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a supplier to a user's profile
|
||||
*
|
||||
* @param AccountSupplierAdd $request
|
||||
* @param Account $o
|
||||
* @return RedirectResponse
|
||||
*/
|
||||
public function supplier_addedit(AccountSupplierAdd $request,Account $o): RedirectResponse
|
||||
{
|
||||
$o->suppliers()->attach([
|
||||
$request->validated('supplier_id') => [
|
||||
'supplier_ref'=>$request->validated('supplier_ref'),
|
||||
'created_at'=>Carbon::now(),
|
||||
]
|
||||
]);
|
||||
|
||||
return redirect()
|
||||
->back()
|
||||
->with('success','Supplier Added');
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a supplier from a user's profile
|
||||
*
|
||||
* @param Account $o
|
||||
* @param Supplier $so
|
||||
* @return RedirectResponse
|
||||
*/
|
||||
public function supplier_delete(Account $o,Supplier $so): RedirectResponse
|
||||
{
|
||||
Session::put('supplier_update',TRUE);
|
||||
|
||||
$o->suppliers()->detach([$so->id]);
|
||||
|
||||
return redirect()
|
||||
->back()
|
||||
->with('success','Supplier Deleted');
|
||||
}
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
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');
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Wholesale;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class ReportController extends Controller
|
||||
{
|
||||
public function products()
|
||||
{
|
||||
return view('a/product/report');
|
||||
}
|
||||
}
|
@ -1,86 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http;
|
||||
|
||||
use Illuminate\Foundation\Http\Kernel as HttpKernel;
|
||||
|
||||
class Kernel extends HttpKernel
|
||||
{
|
||||
/**
|
||||
* The application's global HTTP middleware stack.
|
||||
*
|
||||
* These middleware are run during every request to your application.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $middleware = [
|
||||
\App\Http\Middleware\CheckForMaintenanceMode::class,
|
||||
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
|
||||
\App\Http\Middleware\TrimStrings::class,
|
||||
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
|
||||
\App\Http\Middleware\TrustProxies::class,
|
||||
\App\Http\Middleware\SetSite::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* The application's route middleware groups.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $middlewareGroups = [
|
||||
'web' => [
|
||||
\App\Http\Middleware\EncryptCookies::class,
|
||||
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
|
||||
\Illuminate\Session\Middleware\StartSession::class,
|
||||
// \Illuminate\Session\Middleware\AuthenticateSession::class,
|
||||
\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,
|
||||
],
|
||||
|
||||
'api' => [
|
||||
'throttle:60,1',
|
||||
'bindings',
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* The application's route middleware.
|
||||
*
|
||||
* These middleware may be assigned to groups or used individually.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $routeMiddleware = [
|
||||
'auth' => \App\Http\Middleware\Authenticate::class,
|
||||
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
|
||||
'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,
|
||||
'theme' => \Igaster\LaravelTheme\Middleware\setTheme::class,
|
||||
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
||||
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* The priority-sorted list of middleware.
|
||||
*
|
||||
* This forces non-global middleware to always be in the given order.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $middlewarePriority = [
|
||||
\Illuminate\Session\Middleware\StartSession::class,
|
||||
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
|
||||
\App\Http\Middleware\Authenticate::class,
|
||||
\Illuminate\Session\Middleware\AuthenticateSession::class,
|
||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
\Illuminate\Auth\Middleware\Authorize::class,
|
||||
];
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Illuminate\Auth\Middleware\Authenticate as Middleware;
|
||||
|
||||
class Authenticate extends Middleware
|
||||
{
|
||||
/**
|
||||
* Get the path the user should be redirected to when they are not authenticated.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return string
|
||||
*/
|
||||
protected function redirectTo($request)
|
||||
{
|
||||
if (! $request->expectsJson()) {
|
||||
return route('login');
|
||||
}
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode as Middleware;
|
||||
|
||||
class CheckForMaintenanceMode extends Middleware
|
||||
{
|
||||
/**
|
||||
* The URIs that should be reachable while maintenance mode is enabled.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $except = [
|
||||
//
|
||||
];
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Illuminate\Cookie\Middleware\EncryptCookies as Middleware;
|
||||
|
||||
class EncryptCookies extends Middleware
|
||||
{
|
||||
/**
|
||||
* The names of the cookies that should not be encrypted.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $except = [
|
||||
'toggleState',
|
||||
];
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class RedirectIfAuthenticated
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @param string|null $guard
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $next, $guard = null)
|
||||
{
|
||||
if (Auth::guard($guard)->check()) {
|
||||
return redirect('/home');
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
@ -2,15 +2,19 @@
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
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)
|
||||
public function handle(Request $request, Closure $next, string $role)
|
||||
{
|
||||
if ($role AND ! Auth::user())
|
||||
return abort(303,'Not Authenticated');
|
||||
abort(403,'Not Authenticated');
|
||||
|
||||
switch ($role) {
|
||||
case 'wholesaler':
|
||||
|
@ -2,10 +2,10 @@
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Support\Facades\View;
|
||||
use Closure;
|
||||
|
||||
use App\Models\Site;
|
||||
|
||||
@ -20,11 +20,11 @@ class SetSite
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
public function handle(Request $request,\Closure $next): mixed
|
||||
{
|
||||
$so = new Site;
|
||||
|
||||
@ -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);
|
||||
|
||||
|
@ -1,18 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Illuminate\Foundation\Http\Middleware\TrimStrings as Middleware;
|
||||
|
||||
class TrimStrings extends Middleware
|
||||
{
|
||||
/**
|
||||
* The names of the attributes that should not be trimmed.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $except = [
|
||||
'password',
|
||||
'password_confirmation',
|
||||
];
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Fideloper\Proxy\TrustProxies as Middleware;
|
||||
|
||||
class TrustProxies extends Middleware
|
||||
{
|
||||
/**
|
||||
* The trusted proxies for this application.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $proxies;
|
||||
|
||||
/**
|
||||
* The headers that should be used to detect proxies.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $headers = Request::HEADER_X_FORWARDED_ALL;
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
|
||||
|
||||
class VerifyCsrfToken extends Middleware
|
||||
{
|
||||
/**
|
||||
* Indicates whether the XSRF-TOKEN cookie should be set on the response.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $addHttpCookie = true;
|
||||
|
||||
/**
|
||||
* The URIs that should be excluded from CSRF verification.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $except = [
|
||||
//
|
||||
];
|
||||
}
|
42
app/Http/Requests/AccountSupplierAdd.php
Normal file
42
app/Http/Requests/AccountSupplierAdd.php
Normal file
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class AccountSupplierAdd extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return Gate::allows('wholesaler');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
Session::put('supplier_update',true);
|
||||
|
||||
return [
|
||||
'supplier_ref'=> [
|
||||
'required',
|
||||
'string',
|
||||
'min:2',
|
||||
Rule::unique('account_supplier')
|
||||
->where(fn($query)=>$query
|
||||
->where('account_id',request()->get('account_id')))
|
||||
->where('supplier_id',request()->get('supplier_id')),
|
||||
],
|
||||
'supplier_id'=>'required|exists:suppliers,id',
|
||||
];
|
||||
}
|
||||
}
|
46
app/Http/Requests/ChargeAdd.php
Normal file
46
app/Http/Requests/ChargeAdd.php
Normal file
@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
|
||||
use App\Models\{Charge,InvoiceItem};
|
||||
|
||||
class ChargeAdd extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return Auth::user()
|
||||
->accounts_all
|
||||
->contains(request()->post('account_id'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
Session::put('charge_add',true);
|
||||
|
||||
return [
|
||||
'id' => 'sometimes|exists:charges,id',
|
||||
'account_id' => 'required|exists:accounts,id',
|
||||
'charge_at' => 'required|date',
|
||||
'service_id' => 'required|exists:services,id',
|
||||
'site_id' => 'required|exists:sites,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|min:5|max:128',
|
||||
];
|
||||
}
|
||||
}
|
43
app/Http/Requests/CheckoutAddEdit.php
Normal file
43
app/Http/Requests/CheckoutAddEdit.php
Normal file
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
/**
|
||||
* Editing Suppliers
|
||||
*/
|
||||
class CheckoutAddEdit extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return Gate::allows('wholesaler');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'name' => [
|
||||
'required',
|
||||
'string',
|
||||
'min:2',
|
||||
'max:255',
|
||||
Rule::unique('checkouts','name')->ignore($this->route('o')?->id),
|
||||
],
|
||||
'active' => 'sometimes|accepted',
|
||||
'description' => 'nullable|string|min:2|max:255',
|
||||
];
|
||||
}
|
||||
}
|
62
app/Http/Requests/PaymentAddEdit.php
Normal file
62
app/Http/Requests/PaymentAddEdit.php
Normal file
@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
use App\Models\Invoice;
|
||||
|
||||
/**
|
||||
* Editing Suppliers
|
||||
*/
|
||||
class PaymentAddEdit extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return Gate::allows('wholesaler');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'account_id' => 'required|exists:accounts,id',
|
||||
'paid_at' => 'required|date',
|
||||
'checkout_id' => 'required|exists:checkouts,id',
|
||||
'total_amt' => 'required|numeric|min:0.01',
|
||||
'fees_amt' => 'nullable|numeric|lt:total_amt',
|
||||
'source_id' => 'nullable|exists:accounts,id',
|
||||
'pending' => 'nullable|boolean',
|
||||
'notes' => 'nullable|string',
|
||||
'ip' => 'nullable|ip',
|
||||
'invoices' => [
|
||||
'nullable',
|
||||
'array',
|
||||
function($attribute,$value,$fail) {
|
||||
if (($x=collect($value)->sum()) > request()->post('total_amt'))
|
||||
$fail(sprintf('Allocation %3.2f is greater than payment total %3.2f.',$x,request()->post('total_amt')));
|
||||
}
|
||||
],
|
||||
'invoices.*' => [
|
||||
'nullable',
|
||||
function($attribute,$value,$fail) {
|
||||
if (! ($x=Invoice::where('id',$xx=str_replace('invoices.','',$attribute))->first()))
|
||||
$fail(sprintf('Invoice [%d] doesnt exist in DB',$xx));
|
||||
// @todo The due amount may be influenced by this payment (ie: payment edit)
|
||||
elseif($x->due < $value)
|
||||
$fail(sprintf('Invoice [%d] is over allocated by %3.2f',$x->id,$value-$x->due));
|
||||
}
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
57
app/Http/Requests/ProductAddEdit.php
Normal file
57
app/Http/Requests/ProductAddEdit.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
use App\Models\ProviderOauth;
|
||||
|
||||
/**
|
||||
* Editing Suppliers
|
||||
*/
|
||||
class ProductAddEdit extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return Gate::allows('wholesaler');
|
||||
}
|
||||
|
||||
/**
|
||||
* 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',
|
||||
function (string $attribute,mixed $value,\Closure $fail) {
|
||||
if (! is_array($value))
|
||||
$fail("Invalid format for {$attribute}");
|
||||
|
||||
foreach ($value as $k=>$v) {
|
||||
if (! ProviderOauth::where('id',$k)->exists())
|
||||
$fail("Provider doesnt exist [$k]");
|
||||
|
||||
// @todo Validate that the value is in the accounting system
|
||||
}
|
||||
},
|
||||
],
|
||||
'pricing' => 'required|array', // @todo Validate the elements in the pricing
|
||||
];
|
||||
}
|
||||
}
|
54
app/Http/Requests/ServiceCancel.php
Normal file
54
app/Http/Requests/ServiceCancel.php
Normal file
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
/**
|
||||
* Editing Suppliers
|
||||
*/
|
||||
class ServiceCancel extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return Gate::allows('view',$this->route('o'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
//dd(request()->post());
|
||||
return [
|
||||
'stop_at'=> [
|
||||
'required',
|
||||
'date',
|
||||
'after:today',
|
||||
'exclude_unless:extra_charges,null',
|
||||
function($attribute,$value,$fail) {
|
||||
if ($this->route('o')->cancel_date->greaterThan($value))
|
||||
$fail(sprintf('Service cannot be cancelled before: %s',$this->route('o')->cancel_date->format('Y-m-d')));
|
||||
}
|
||||
],
|
||||
'extra_charges_amount' => [
|
||||
'nullable',
|
||||
'exclude_unless:extra_charges,null',
|
||||
function($attribute,$value,$fail) {
|
||||
if ($this->route('o')->cancel_date->greaterThan(request('stop_at')) && (request('extra_charges') !== 1))
|
||||
$fail('Extra charges must be accepted if cancelling before contract end');
|
||||
},
|
||||
],
|
||||
'extra_charges' => 'sometimes|required|accepted',
|
||||
'notes' => 'nullable|min:5',
|
||||
];
|
||||
}
|
||||
}
|
45
app/Http/Requests/ServiceChange.php
Normal file
45
app/Http/Requests/ServiceChange.php
Normal file
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
/**
|
||||
* Editing Suppliers
|
||||
*/
|
||||
class ServiceChange extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return Gate::allows('view',$this->route('o'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'change_date'=> [
|
||||
'required',
|
||||
'date',
|
||||
'after:today',
|
||||
],
|
||||
'product_id' => [
|
||||
'required',
|
||||
'exists:products,id',
|
||||
Rule::notIn([request()->route('o')->product_id]),
|
||||
],
|
||||
'notes' => 'nullable|min:5',
|
||||
];
|
||||
}
|
||||
}
|
41
app/Http/Requests/ServiceChangeRequest.php
Normal file
41
app/Http/Requests/ServiceChangeRequest.php
Normal file
@ -0,0 +1,41 @@
|
||||
<?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')
|
||||
->AccountUserAuthorised();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
];
|
||||
}
|
||||
}
|
43
app/Http/Requests/SiteEdit.php
Normal file
43
app/Http/Requests/SiteEdit.php
Normal file
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
class SiteEdit extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return Gate::allows('wholesaler');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'site_name' => 'required|string|min:2|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_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',
|
||||
'site_tax' => 'required|regex:/[0-9 ]+/|size:14',
|
||||
'social' => 'nullable|array',
|
||||
'top_menu' => 'nullable|array',
|
||||
'site_logo' => 'nullable|image',
|
||||
'email_logo' => 'nullable|image',
|
||||
];
|
||||
}
|
||||
}
|
46
app/Http/Requests/SupplierAddEdit.php
Normal file
46
app/Http/Requests/SupplierAddEdit.php
Normal file
@ -0,0 +1,46 @@
|
||||
<?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',
|
||||
];
|
||||
}
|
||||
}
|
60
app/Http/Requests/SupplierProductAddEdit.php
Normal file
60
app/Http/Requests/SupplierProductAddEdit.php
Normal file
@ -0,0 +1,60 @@
|
||||
<?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',
|
||||
];
|
||||
}
|
||||
}
|
39
app/Http/Requests/UserEdit.php
Normal file
39
app/Http/Requests/UserEdit.php
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Validation\Rules\Password;
|
||||
|
||||
class UserEdit extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return Auth::id() === $this->route('o')->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'email'=>'required|email|min:5',
|
||||
'password'=>['nullable','confirmed',Password::min(8)],
|
||||
'firstname'=>'required|min:2',
|
||||
'lastname'=>'required|min:2',
|
||||
'address1'=>'required|min:8',
|
||||
'address2'=>'nullable|min:8',
|
||||
'city'=>'required|min:4',
|
||||
'state'=>'required|min:3|max:3',
|
||||
'postcode'=>'required|min:4|max:4',
|
||||
'country_id'=>'required|exists:countries,id'
|
||||
];
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
29
app/Interfaces/ProductItem.php
Normal file
29
app/Interfaces/ProductItem.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?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;
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
<?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,6 +6,13 @@ use Carbon\Carbon;
|
||||
|
||||
interface ServiceItem
|
||||
{
|
||||
/**
|
||||
* Months the service is contracted for.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getContractTermAttribute(): int;
|
||||
|
||||
/**
|
||||
* Return the Service Description.
|
||||
*
|
||||
@ -16,7 +23,7 @@ interface ServiceItem
|
||||
/**
|
||||
* Date the service expires
|
||||
*/
|
||||
public function getServiceExpireAttribute(): Carbon;
|
||||
public function getServiceExpireAttribute(): ?Carbon;
|
||||
|
||||
/**
|
||||
* Return the Service Name.
|
||||
@ -25,6 +32,13 @@ interface ServiceItem
|
||||
*/
|
||||
public function getServiceNameAttribute(): string;
|
||||
|
||||
/**
|
||||
* Has this service expired
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasExpired(): bool;
|
||||
|
||||
/**
|
||||
* Is this service in a contract
|
||||
*
|
||||
|
@ -6,6 +6,13 @@ use Illuminate\Support\Collection;
|
||||
|
||||
interface ServiceUsage
|
||||
{
|
||||
/**
|
||||
* Our model that holds traffic information
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function traffic();
|
||||
|
||||
/**
|
||||
* This service provides usage information
|
||||
*
|
||||
|
107
app/Jobs/AccountingAccountSync.php
Normal file
107
app/Jobs/AccountingAccountSync.php
Normal file
@ -0,0 +1,107 @@
|
||||
<?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
|
||||
}
|
||||
}
|
||||
}
|
79
app/Jobs/AccountingInvoiceSync.php
Normal file
79
app/Jobs/AccountingInvoiceSync.php
Normal file
@ -0,0 +1,79 @@
|
||||
<?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\{Invoice,ProviderToken};
|
||||
|
||||
/**
|
||||
* Synchronise invoices ref numbers with our database
|
||||
*/
|
||||
class AccountingInvoiceSync implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
private const LOGKEY = 'JIS';
|
||||
|
||||
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 = Invoice::select('id')->get();
|
||||
|
||||
foreach ($api->getInvoices() 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(fn($item)=>$item->lid == $acc->DocNumber))->count() === 1) {
|
||||
$o = $x->pop();
|
||||
|
||||
} else {
|
||||
// Log not found
|
||||
Log::alert(sprintf('%s:Invoice not found [%s:%s]',self::LOGKEY,$acc->id,$acc->DocNumber));
|
||||
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:Invoice updated [%s:%s]',self::LOGKEY,$o->id,$acc->DocNumber));
|
||||
}
|
||||
}
|
||||
}
|
142
app/Jobs/AccountingPaymentSync.php
Normal file
142
app/Jobs/AccountingPaymentSync.php
Normal file
@ -0,0 +1,142 @@
|
||||
<?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));
|
||||
}
|
||||
}
|
86
app/Jobs/AccountingTaxSync.php
Normal file
86
app/Jobs/AccountingTaxSync.php
Normal file
@ -0,0 +1,86 @@
|
||||
<?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(fn($item)=>$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));
|
||||
}
|
||||
}
|
||||
}
|
@ -8,70 +8,81 @@ 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\DB;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
use App\Mail\TrafficMismatch;
|
||||
use App\Models\Service\Adsl;
|
||||
use App\Models\Service\AdslTraffic;
|
||||
use App\Models\AdslSupplier;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
|
||||
use App\Classes\External\Supplier as ExternalSupplier;
|
||||
use App\Mail\TrafficMismatch;
|
||||
use App\Models\{Rtm,Supplier};
|
||||
use App\Models\Service\Broadband as ServiceBroadband;
|
||||
use App\Models\Usage\Broadband as UsageBroadband;
|
||||
|
||||
/**
|
||||
* Class BroadbandTraffic
|
||||
* Read and update the traffic for an Broadband supplier
|
||||
* Read and update the traffic for a Broadband supplier
|
||||
*
|
||||
* @package App\Jobs
|
||||
*/
|
||||
class BroadbandTraffic implements ShouldQueue
|
||||
final class BroadbandTraffic implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
private const LOGKEY = 'JBT';
|
||||
|
||||
protected $aso = NULL; // The supplier we are updating from
|
||||
private $class_prefix = 'App\Classes\External\Supplier\\';
|
||||
private const class_prefix = 'App\Classes\External\Supplier\\';
|
||||
|
||||
public function __construct(AdslSupplier $o)
|
||||
{
|
||||
$this->aso = $o;
|
||||
}
|
||||
private const traffic = 'broadband';
|
||||
|
||||
public function __construct(private string $supplier) {}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
* @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->aso->name),['m'=>__METHOD__]);
|
||||
$so = Supplier::active()
|
||||
->where('name','ilike',$this->supplier)
|
||||
->sole();
|
||||
|
||||
// Wholesaler email
|
||||
$ro = Rtm::where('parent_id',NULL)->sole();
|
||||
|
||||
Log::info(sprintf('%s:Importing Broadband Traffic from [%s]',self::LOGKEY,$so->name));
|
||||
|
||||
if ((! $connection=$so->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);
|
||||
|
||||
// Count of updated records
|
||||
$u = 0;
|
||||
|
||||
// Load our class for this supplier
|
||||
$class = $this->class_prefix.$this->aso->name;
|
||||
$class = self::class_prefix.$so->name;
|
||||
if (class_exists($class)) {
|
||||
$o = new $class($this->aso);
|
||||
$o = new $class($so);
|
||||
|
||||
} else {
|
||||
Log::error(sprintf('%s: Class doesnt exist: %d',get_class($this),$class));
|
||||
Log::error(sprintf('%s: Class doesnt exist: %s',self::LOGKEY,$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 ($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__]);
|
||||
while ($last_update < Carbon::now()->subDay()) {
|
||||
Log::notice(sprintf('%s:Next update is [%s]',self::LOGKEY,$last_update->format('Y-m-d')));
|
||||
|
||||
// Delete traffic, since we'll refresh it.
|
||||
AdslTraffic::where('supplier_id',$this->aso->id)
|
||||
->where('date',$this->aso->stats_lastupdate)
|
||||
UsageBroadband::where('supplier_id',$so->id)
|
||||
->where('date',$last_update->format('Y-m-d'))
|
||||
->delete();
|
||||
|
||||
$c = 0;
|
||||
foreach ($o->fetch() as $line) {
|
||||
foreach ($o->fetch($connection,self::traffic) as $line) {
|
||||
// The first row is our header
|
||||
if (! $c++) {
|
||||
$fields = $o->getColumns(preg_replace('/,\s+/',',',$line),collect($o->header()));
|
||||
@ -79,29 +90,27 @@ class BroadbandTraffic implements ShouldQueue
|
||||
}
|
||||
|
||||
if (! $fields->count())
|
||||
abort(500,'? No fields in data exportupda');
|
||||
abort(500,'? No fields in data export');
|
||||
|
||||
$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 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();
|
||||
// Find the right service dependent on the dates we supplied the service
|
||||
$oo = ServiceBroadband::where('service_username',$row[$o->getColumnKey('Login')])
|
||||
->select('service_broadband.*')
|
||||
->join('services',['service_broadband.service_id'=>'services.id'])
|
||||
->where('services.start_at','<=',$date)
|
||||
->where(fn($query)=>
|
||||
$query->whereNULL('services.stop_at')
|
||||
->orWhere('services.stop_at','>=',$date)
|
||||
)
|
||||
->single();
|
||||
|
||||
$to = new AdslTraffic;
|
||||
$to->site_id = 1; // @todo TO ADDRESS
|
||||
$to->date = $this->aso->stats_lastupdate;
|
||||
$to->supplier_id = $this->aso->id;
|
||||
$to = new UsageBroadband;
|
||||
$to->date = $last_update;
|
||||
$to->supplier_id = $so->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')];
|
||||
@ -111,33 +120,39 @@ class BroadbandTraffic implements ShouldQueue
|
||||
$to->time = '24:00'; // @todo
|
||||
|
||||
// If we have no records
|
||||
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()]);
|
||||
if (! $oo) {
|
||||
Log::error(sprintf('%s:None or too many services return for [%s]',self::LOGKEY,$row[$o->getColumnKey('Login')]),['date'=>$date]);
|
||||
|
||||
$to->service = $row[$o->getColumnKey('Login')];
|
||||
$to->save();
|
||||
$to->site_id = 1; // @todo This needs to be worked out a better way
|
||||
|
||||
} else {
|
||||
$oo->first()->traffic()->save($to);
|
||||
$to->site_id = $oo->site_id;
|
||||
$to->service_item_id = $oo->id;
|
||||
}
|
||||
|
||||
$u++;
|
||||
if ($to->save())
|
||||
$u++;
|
||||
|
||||
} catch (\Exception $e) {
|
||||
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::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::info(sprintf('%s: Records Imported [%d] for [%s]',self::LOGKEY,$u,$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__]);
|
||||
// Save our current progress.
|
||||
$so->detail->connections = $so->detail->connections->put(self::traffic,array_merge($connection,['last'=>$last_update->format('Y-m-d')]));
|
||||
$so->detail->save();
|
||||
|
||||
// Update our details for the next iteration.
|
||||
$last_update = $last_update->addDay();
|
||||
Arr::set($connection,'last',$last_update->format('Y-m-d'));
|
||||
|
||||
if ($u) {
|
||||
$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->aso,$date));
|
||||
if ($so->trafficMismatch($date)->count())
|
||||
Mail::to($ro->owner->email)
|
||||
->send(new TrafficMismatch($so,$date));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
232
app/Jobs/ImportCosts.php
Normal file
232
app/Jobs/ImportCosts.php
Normal file
@ -0,0 +1,232 @@
|
||||
<?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)->map(fn($item)=>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])->ServiceActive()->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->product->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->product->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->product->category,$c));
|
||||
}
|
||||
|
||||
} else {
|
||||
dump(['line'=>$line,'sql'=>Service::search($m[1])->ServiceActive()->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);
|
||||
}
|
||||
}
|
104
app/Jobs/PaymentsImport.php
Normal file
104
app/Jobs/PaymentsImport.php
Normal file
@ -0,0 +1,104 @@
|
||||
<?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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
39
app/Jobs/ProviderTokenRefresh.php
Normal file
39
app/Jobs/ProviderTokenRefresh.php
Normal file
@ -0,0 +1,39 @@
|
||||
<?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();
|
||||
}
|
||||
}
|
81
app/Jobs/SupplierDomainSync.php
Normal file
81
app/Jobs/SupplierDomainSync.php
Normal file
@ -0,0 +1,81 @@
|
||||
<?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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
31
app/Listeners/LogSentMessage.php
Normal file
31
app/Listeners/LogSentMessage.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?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()]);
|
||||
}
|
||||
}
|
40
app/Listeners/ProviderPaymentCreated.php
Normal file
40
app/Listeners/ProviderPaymentCreated.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?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);
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user